1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 obt/link.c for the Openbox window manager
4 Copyright (c) 2009-2011 Dana Jansens
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.
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.
16 See the COPYING file for a copy of the GNU General Public License.
20 #include "obt/bsearch.h"
21 #include "obt/ddparse.h"
22 #include "obt/paths.h"
33 gchar *path; /*!< The path to the file where the link came from */
36 gchar *name; /*!< Specific name for the object (eg Firefox) */
37 gboolean display; /*<! When false, do not display this link in menus or
39 gboolean deleted; /*<! When true, the Link could exist but is deleted
40 for the current user */
41 gchar *generic; /*!< Generic name for the object (eg Web Browser) */
42 gchar *comment; /*!< Comment/description to display for the object */
43 gchar *icon; /*!< Name/path for an icon for the object */
44 guint env_required; /*!< The environments that must be present to use this
46 guint env_restricted; /*!< The environments that must _not_ be present to
51 gchar *exec; /*!< Executable to run for the app */
52 gchar *wdir; /*!< Working dir to run the app in */
53 gboolean term; /*!< Run the app in a terminal or not */
56 gchar **mime; /*!< Mime types the app can open */
58 GQuark main_category; /*!< The first main category listed */
59 GQuark *categories; /*!< Array of quarks representing the
60 application's categories */
61 gulong n_categories; /*!< Number of categories for the app */
63 ObtLinkAppStartup startup;
64 gchar *startup_wmclass;
74 #define NUM_MAIN_CATEGORIES 10
75 static GQuark MAIN_CATEGORIES[NUM_MAIN_CATEGORIES];
76 static gboolean setup = FALSE;
84 /* From http://standards.freedesktop.org/menu-spec/latest/apa.html */
85 MAIN_CATEGORIES[0] = g_quark_from_static_string("AudioVideo");
86 MAIN_CATEGORIES[1] = g_quark_from_static_string("Development");
87 MAIN_CATEGORIES[2] = g_quark_from_static_string("Education");
88 MAIN_CATEGORIES[3] = g_quark_from_static_string("Game");
89 MAIN_CATEGORIES[4] = g_quark_from_static_string("Graphics");
90 MAIN_CATEGORIES[5] = g_quark_from_static_string("Network");
91 MAIN_CATEGORIES[6] = g_quark_from_static_string("Office");
92 MAIN_CATEGORIES[7] = g_quark_from_static_string("Settings");
93 MAIN_CATEGORIES[8] = g_quark_from_static_string("System");
94 MAIN_CATEGORIES[9] = g_quark_from_static_string("Utility");
95 qsort(MAIN_CATEGORIES, NUM_MAIN_CATEGORIES, sizeof(guint), obt_guint_cmp);
98 ObtLink* obt_link_from_ddfile(const gchar *path, ObtPaths *p,
99 const gchar *language,
100 const gchar *country,
101 const gchar *modifier)
104 GHashTable *groups, *keys;
110 /* parse the file, and get a hash table of the groups */
111 groups = obt_ddparse_file(path, language, country, modifier);
112 if (!groups) return NULL; /* parsing failed */
114 /* grab the Desktop Entry group */
115 g = g_hash_table_lookup(groups, "Desktop Entry");
117 /* grab the keys that appeared in the Desktop Entry group */
118 keys = obt_ddparse_group_keys(g);
120 /* build the ObtLink (we steal all strings from the parser) */
121 link = g_slice_new0(ObtLink);
123 link->path = g_strdup(path);
124 link->display = TRUE;
126 v = g_hash_table_lookup(keys, "Type");
128 link->type = v->value.enumerable;
130 if ((v = g_hash_table_lookup(keys, "Hidden")))
131 link->deleted = v->value.boolean;
133 if ((v = g_hash_table_lookup(keys, "NoDisplay")))
134 link->display = !v->value.boolean;
136 if ((v = g_hash_table_lookup(keys, "GenericName")))
137 link->generic = v->value.string, v->value.string = NULL;
139 if ((v = g_hash_table_lookup(keys, "Comment")))
140 link->comment = v->value.string, v->value.string = NULL;
142 if ((v = g_hash_table_lookup(keys, "Icon")))
143 link->icon = v->value.string, v->value.string = NULL;
145 if ((v = g_hash_table_lookup(keys, "OnlyShowIn")))
146 link->env_required = v->value.environments;
148 link->env_required = 0;
150 if ((v = g_hash_table_lookup(keys, "NotShowIn")))
151 link->env_restricted = v->value.environments;
153 link->env_restricted = 0;
155 /* type-specific keys */
157 if (link->type == OBT_LINK_TYPE_APPLICATION) {
161 v = g_hash_table_lookup(keys, "Exec");
163 link->d.app.exec = v->value.string;
164 v->value.string = NULL;
166 /* parse link->d.app.exec to determine link->d.app.open */
168 for (c = link->d.app.exec; *c; ++c) {
171 case 'f': link->d.app.open = OBT_LINK_APP_SINGLE_LOCAL; break;
172 case 'F': link->d.app.open = OBT_LINK_APP_MULTI_LOCAL; break;
173 case 'u': link->d.app.open = OBT_LINK_APP_SINGLE_URL; break;
174 case 'U': link->d.app.open = OBT_LINK_APP_MULTI_URL; break;
175 default: percent = FALSE;
177 if (percent) break; /* found f/F/u/U */
179 else if (*c == '%') percent = TRUE;
182 if ((v = g_hash_table_lookup(keys, "TryExec"))) {
183 /* XXX spawn a thread to check TryExec? */
184 link->display = link->display &&
185 obt_paths_try_exec(p, v->value.string);
188 if ((v = g_hash_table_lookup(keys, "Path"))) {
189 /* steal the string */
190 link->d.app.wdir = v->value.string;
191 v->value.string = NULL;
194 if ((v = g_hash_table_lookup(keys, "Terminal")))
195 link->d.app.term = v->value.boolean;
197 if ((v = g_hash_table_lookup(keys, "StartupNotify")))
198 link->d.app.startup = v->value.boolean ?
199 OBT_LINK_APP_STARTUP_PROTOCOL_SUPPORT :
200 OBT_LINK_APP_STARTUP_NO_SUPPORT;
202 link->d.app.startup = OBT_LINK_APP_STARTUP_LEGACY_SUPPORT;
203 if ((v = g_hash_table_lookup(keys, "StartupWMClass"))) {
204 /* steal the string */
205 link->d.app.startup_wmclass = v->value.string;
206 v->value.string = NULL;
210 if ((v = g_hash_table_lookup(keys, "Categories"))) {
216 link->d.app.categories = g_new(GQuark, v->value.strings.n);
217 link->d.app.n_categories = v->value.strings.n;
220 for (i = 0; i < v->value.strings.n; ++i) {
221 cat = link->d.app.categories[i] =
222 g_quark_from_string(v->value.strings.a[i]);
225 BSEARCH_SETUP(guint);
226 BSEARCH(guint, MAIN_CATEGORIES, 0, NUM_MAIN_CATEGORIES,
228 if (BSEARCH_FOUND()) {
230 link->d.app.main_category = cat;
234 c = end = end+1; /* next */
238 if ((v = g_hash_table_lookup(keys, "MimeType"))) {
239 /* steal the string array */
240 link->d.app.mime = v->value.strings.a;
241 v->value.strings.a = NULL;
242 v->value.strings.n = 0;
245 else if (link->type == OBT_LINK_TYPE_URL) {
246 v = g_hash_table_lookup(keys, "URL");
248 link->d.url.addr = v->value.string;
249 v->value.string = NULL;
252 /* destroy the parsing info */
253 g_hash_table_destroy(groups);
258 void obt_link_ref(ObtLink *dd)
263 void obt_link_unref(ObtLink *dd)
270 if (dd->type == OBT_LINK_TYPE_APPLICATION) {
271 g_free(dd->d.app.exec);
272 g_free(dd->d.app.wdir);
273 g_strfreev(dd->d.app.mime);
274 g_free(dd->d.app.categories);
275 g_free(dd->d.app.startup_wmclass);
277 else if (dd->type == OBT_LINK_TYPE_URL)
278 g_free(dd->d.url.addr);
279 g_slice_free(ObtLink, dd);
283 ObtLinkType obt_link_type (ObtLink *e)
285 g_return_val_if_fail(e != NULL, 0);
290 GQuark obt_link_app_main_category (ObtLink *e)
292 g_return_val_if_fail(e != NULL, 0);
293 g_return_val_if_fail(e->type == OBT_LINK_TYPE_APPLICATION, 0);
295 return e->d.app.main_category;
298 const GQuark* obt_link_app_categories(ObtLink *e, gulong *n)
300 g_return_val_if_fail(e != NULL, NULL);
301 g_return_val_if_fail(e->type == OBT_LINK_TYPE_APPLICATION, NULL);
302 g_return_val_if_fail(n != NULL, NULL);
304 *n = e->d.app.n_categories;
305 return e->d.app.categories;
308 const gchar *obt_link_source_file(ObtLink *e)
313 gchar* obt_link_id_from_ddfile(const gchar *filename)
315 return obt_ddparse_file_to_id(filename);
318 gboolean obt_link_display(ObtLink *e, const guint environments)
321 /* display if the link wants to be displayed and TryExec passed */
323 /* display if no environment is required, or we match at least one of
325 (!e->env_required || (e->env_required & environments)) &&
326 /* display if no environment is restricted, or we do not match any of
328 (!e->env_restricted || !(e->env_restricted & environments));