]> icculus.org git repositories - dana/openbox.git/blob - obt/link.c
Add linkbase which will keep track of available .desktop files for application launch...
[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             gchar **mime; /*!< Mime types the app can open */
49
50             GQuark *categories; /*!< Array of quarks representing the
51                                   application's categories */
52             gulong  n_categories; /*!< Number of categories for the app */
53
54             ObtLinkAppStartup startup;
55             gchar *startup_wmclass;
56         } app;
57         struct _ObtLinkLink {
58             gchar *addr;
59         } url;
60         struct _ObtLinkDir {
61         } dir;
62     } d;
63 };
64
65 ObtLink* obt_link_from_ddfile(const gchar *basepath, const gchar *filename,
66                               ObtPaths *p)
67 {
68     ObtLink *link;
69     GHashTable *groups, *keys;
70     ObtDDParseGroup *g;
71     ObtDDParseValue *v;
72     gchar *path;
73
74     /* parse the file, and get a hash table of the groups */
75     path = g_strconcat(basepath, filename, NULL);
76     groups = obt_ddparse_file(path);
77     g_free(path);
78     if (!groups) return NULL; /* parsing failed */
79
80     /* grab the Desktop Entry group */
81     g = g_hash_table_lookup(groups, "Desktop Entry");
82     g_assert(g != NULL);
83     /* grab the keys that appeared in the Desktop Entry group */
84     keys = obt_ddparse_group_keys(g);
85
86     /* build the ObtLink (we steal all strings from the parser) */
87     link = g_slice_new0(ObtLink);
88     link->ref = 1;
89     link->display = TRUE;
90
91     v = g_hash_table_lookup(keys, "Type");
92     g_assert(v);
93     link->type = v->value.enumerable;
94
95     if ((v = g_hash_table_lookup(keys, "Hidden")))
96         link->deleted = v->value.boolean;
97
98     if ((v = g_hash_table_lookup(keys, "NoDisplay")))
99         link->display = !v->value.boolean;
100
101     if ((v = g_hash_table_lookup(keys, "GenericName")))
102         link->generic = v->value.string, v->value.string = NULL;
103
104     if ((v = g_hash_table_lookup(keys, "Comment")))
105         link->comment = v->value.string, v->value.string = NULL;
106
107     if ((v = g_hash_table_lookup(keys, "Icon")))
108         link->icon = v->value.string, v->value.string = NULL;
109
110     if ((v = g_hash_table_lookup(keys, "OnlyShowIn")))
111         link->env_required = v->value.environments;
112     else
113         link->env_required = 0;
114
115     if ((v = g_hash_table_lookup(keys, "NotShowIn")))
116         link->env_restricted = v->value.environments;
117     else
118         link->env_restricted = 0;
119
120     /* type-specific keys */
121
122     if (link->type == OBT_LINK_TYPE_APPLICATION) {
123         gchar *c;
124         gboolean percent;
125
126         v = g_hash_table_lookup(keys, "Exec");
127         g_assert(v);
128         link->d.app.exec = v->value.string;
129         v->value.string = NULL;
130
131         /* parse link->d.app.exec to determine link->d.app.open */
132         percent = FALSE;
133         for (c = link->d.app.exec; *c; ++c) {
134             if (percent) {
135                 switch (*c) {
136                 case 'f': link->d.app.open = OBT_LINK_APP_SINGLE_LOCAL; break;
137                 case 'F': link->d.app.open = OBT_LINK_APP_MULTI_LOCAL; break;
138                 case 'u': link->d.app.open = OBT_LINK_APP_SINGLE_URL; break;
139                 case 'U': link->d.app.open = OBT_LINK_APP_MULTI_URL; break;
140                 default: percent = FALSE;
141                 }
142                 if (percent) break; /* found f/F/u/U */
143             }
144             else if (*c == '%') percent = TRUE;
145         }
146
147         if ((v = g_hash_table_lookup(keys, "TryExec"))) {
148             /* XXX spawn a thread to check TryExec? */
149             link->display = link->display &&
150                 obt_paths_try_exec(p, v->value.string);
151         }
152
153         if ((v = g_hash_table_lookup(keys, "Path"))) {
154             /* steal the string */
155             link->d.app.wdir = v->value.string;
156             v->value.string = NULL;
157         }
158
159         if ((v = g_hash_table_lookup(keys, "Terminal")))
160             link->d.app.term = v->value.boolean;
161
162         if ((v = g_hash_table_lookup(keys, "StartupNotify")))
163             link->d.app.startup = v->value.boolean ?
164                 OBT_LINK_APP_STARTUP_PROTOCOL_SUPPORT :
165                 OBT_LINK_APP_STARTUP_NO_SUPPORT;
166         else {
167             link->d.app.startup = OBT_LINK_APP_STARTUP_LEGACY_SUPPORT;
168             if ((v = g_hash_table_lookup(keys, "StartupWMClass"))) {
169                 /* steal the string */
170                 link->d.app.startup_wmclass = v->value.string;
171                 v->value.string = NULL;
172             }
173         }
174
175         if ((v = g_hash_table_lookup(keys, "Categories"))) {
176             gulong i;
177             gchar *end;
178
179             link->d.app.categories = g_new(GQuark, v->value.strings.n);
180             link->d.app.n_categories = v->value.strings.n;
181
182             for (i = 0; i < v->value.strings.n; ++i) {
183                 link->d.app.categories[i] =
184                     g_quark_from_string(v->value.strings.a[i]);
185                 c = end = end+1; /* next */
186             }
187         }
188
189         if ((v = g_hash_table_lookup(keys, "MimeType"))) {
190             /* steal the string array */
191             link->d.app.mime = v->value.strings.a;
192             v->value.strings.a = NULL;
193             v->value.strings.n = 0;
194         }
195     }
196     else if (link->type == OBT_LINK_TYPE_URL) {
197         v = g_hash_table_lookup(keys, "URL");
198         g_assert(v);
199         link->d.url.addr = v->value.string;
200         v->value.string = NULL;
201     }
202
203     /* destroy the parsing info */
204     g_hash_table_destroy(groups);
205
206     return link;
207 }
208
209 void obt_link_ref(ObtLink *dd)
210 {
211     ++dd->ref;
212 }
213
214 void obt_link_unref(ObtLink *dd)
215 {
216     if (--dd->ref < 1) {
217         g_free(dd->name);
218         g_free(dd->generic);
219         g_free(dd->comment);
220         g_free(dd->icon);
221         if (dd->type == OBT_LINK_TYPE_APPLICATION) {
222             g_free(dd->d.app.exec);
223             g_free(dd->d.app.wdir);
224             g_strfreev(dd->d.app.mime);
225             g_free(dd->d.app.categories);
226             g_free(dd->d.app.startup_wmclass);
227         }
228         else if (dd->type == OBT_LINK_TYPE_URL)
229             g_free(dd->d.url.addr);
230         g_slice_free(ObtLink, dd);
231     }
232 }
233
234 const GQuark* obt_link_app_categories(ObtLink *e, gulong *n)
235 {
236     g_return_val_if_fail(e != NULL, NULL);
237     g_return_val_if_fail(e->type == OBT_LINK_TYPE_APPLICATION, NULL);
238     g_return_val_if_fail(n != NULL, NULL);
239
240     *n = e->d.app.n_categories;
241     return e->d.app.categories;
242 }