bdddcf547b12dc1e723a3839e9d9819472010a62
[dana/openbox.git] / obt / link.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
3    obt/link.c for the Openbox window manager
4    Copyright (c) 2009        Dana Jansens
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    See the COPYING file for a copy of the GNU General Public License.
17 */
18
19 #include "obt/link.h"
20 #include "obt/ddparse.h"
21 #include "obt/paths.h"
22 #include <glib.h>
23
24 struct _ObtLink {
25     guint ref;
26
27     ObtLinkType type;
28     gchar *name; /*!< Specific name for the object (eg Firefox) */
29     gboolean display; /*<! When false, do not display this link in menus or
30                            launchers, etc */
31     gboolean deleted; /*<! When true, the Link could exist but is deleted
32                            for the current user */
33     gchar *generic; /*!< Generic name for the object (eg Web Browser) */
34     gchar *comment; /*!< Comment/description to display for the object */
35     gchar *icon; /*!< Name/path for an icon for the object */
36     guint env_required; /*!< The environments that must be present to use this
37                           link. */
38     guint env_restricted; /*!< The environments that must _not_ be present to
39                             use this link. */
40
41     union _ObtLinkData {
42         struct _ObtLinkApp {
43             gchar *exec; /*!< Executable to run for the app */
44             gchar *wdir; /*!< Working dir to run the app in */
45             gboolean term; /*!< Run the app in a terminal or not */
46             ObtLinkAppOpen open;
47
48             /* XXX gchar**? or something better, a mime struct.. maybe
49                glib has something i can use. */
50             gchar **mime; /*!< Mime types the app can open */
51
52             ObtLinkAppStartup startup;
53             gchar *startup_wmclass;
54         } app;
55         struct _ObtLinkLink {
56             gchar *addr;
57         } url;
58         struct _ObtLinkDir {
59         } dir;
60     } d;
61 };
62
63 ObtLink* obt_link_from_ddfile(const gchar *ddname, GSList *paths,
64                               ObtPaths *p)
65 {
66     ObtLink *link;
67     GHashTable *groups, *keys;
68     ObtDDParseGroup *g;
69     ObtDDParseValue *v;
70
71     /* parse the file, and get a hash table of the groups */
72     groups = obt_ddparse_file(ddname, paths);
73     if (!groups) return NULL; /* parsing failed */
74     /* grab the Desktop Entry group */
75     g = g_hash_table_lookup(groups, "Desktop Entry");
76     g_assert(g != NULL);
77     /* grab the keys that appeared in the Desktop Entry group */
78     keys = obt_ddparse_group_keys(g);
79
80     /* build the ObtLink (we steal all strings from the parser) */
81     link = g_slice_new0(ObtLink);
82     link->ref = 1;
83     link->display = TRUE;
84
85     v = g_hash_table_lookup(keys, "Type");
86     g_assert(v);
87     link->type = v->value.enumerable;
88
89     if ((v = g_hash_table_lookup(keys, "Hidden")))
90         link->deleted = v->value.boolean;
91
92     if ((v = g_hash_table_lookup(keys, "NoDisplay")))
93         link->display = !v->value.boolean;
94
95     if ((v = g_hash_table_lookup(keys, "GenericName")))
96         link->generic = v->value.string, v->value.string = NULL;
97
98     if ((v = g_hash_table_lookup(keys, "Comment")))
99         link->comment = v->value.string, v->value.string = NULL;
100
101     if ((v = g_hash_table_lookup(keys, "Icon")))
102         link->icon = v->value.string, v->value.string = NULL;
103
104     if ((v = g_hash_table_lookup(keys, "OnlyShowIn")))
105         link->env_required = v->value.environments;
106     else
107         link->env_required = 0;
108
109     if ((v = g_hash_table_lookup(keys, "NotShowIn")))
110         link->env_restricted = v->value.environments;
111     else
112         link->env_restricted = 0;
113
114     /* type-specific keys */
115
116     if (link->type == OBT_LINK_TYPE_APPLICATION) {
117         gchar *c;
118         gboolean percent;
119
120         v = g_hash_table_lookup(keys, "Exec");
121         g_assert(v);
122         link->d.app.exec = v->value.string;
123         v->value.string = NULL;
124
125         /* parse link->d.app.exec to determine link->d.app.open */
126         percent = FALSE;
127         for (c = link->d.app.exec; *c; ++c) {
128             if (*c == '%') percent = !percent;
129             if (percent) {
130                 switch (*c) {
131                 case 'f': link->d.app.open = OBT_LINK_APP_SINGLE_LOCAL; break;
132                 case 'F': link->d.app.open = OBT_LINK_APP_MULTI_LOCAL; break;
133                 case 'u': link->d.app.open = OBT_LINK_APP_SINGLE_URL; break;
134                 case 'U': link->d.app.open = OBT_LINK_APP_MULTI_URL; break;
135                 }
136             }
137         }
138
139         if ((v = g_hash_table_lookup(keys, "TryExec"))) {
140             /* XXX spawn a thread to check TryExec? */
141             link->display = link->display &&
142                 obt_paths_try_exec(p, v->value.string);
143         }
144
145         if ((v = g_hash_table_lookup(keys, "Path"))) {
146             /* steal the string */
147             link->d.app.wdir = v->value.string;
148             v->value.string = NULL;
149         }
150
151         if ((v = g_hash_table_lookup(keys, "Terminal")))
152             link->d.app.term = v->value.boolean;
153
154         if ((v = g_hash_table_lookup(keys, "StartupNotify")))
155             link->d.app.startup = v->value.boolean ?
156                 OBT_LINK_APP_STARTUP_PROTOCOL_SUPPORT :
157                 OBT_LINK_APP_STARTUP_NO_SUPPORT;
158         else {
159             link->d.app.startup = OBT_LINK_APP_STARTUP_LEGACY_SUPPORT;
160             if ((v = g_hash_table_lookup(keys, "StartupWMClass"))) {
161                 /* steal the string */
162                 link->d.app.startup_wmclass = v->value.string;
163                 v->value.string = NULL;
164             }
165         }
166
167         /* XXX there's more app specific stuff */
168     }
169     else if (link->type == OBT_LINK_TYPE_URL) {
170         v = g_hash_table_lookup(keys, "URL");
171         g_assert(v);
172         link->d.url.addr = v->value.string;
173         v->value.string = NULL;
174     }
175
176     return link;
177 }
178
179 void obt_link_ref(ObtLink *dd)
180 {
181     ++dd->ref;
182 }
183
184 void obt_link_unref(ObtLink *dd)
185 {
186     if (--dd->ref < 1) {
187         g_slice_free(ObtLink, dd);
188     }
189 }