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.
37 gchar *name; /*!< Specific name for the object (eg Firefox) */
38 gchar *collate_key; /*!< Internal key for sorting by name. */
39 gboolean display; /*<! When false, do not display this link in menus or
41 gboolean deleted; /*<! When true, the Link could exist but is deleted
42 for the current user */
43 gchar *generic; /*!< Generic name for the object (eg Web Browser) */
44 gchar *comment; /*!< Comment/description to display for the object */
45 gchar *icon; /*!< Name/path for an icon for the object */
46 guint env_required; /*!< The environments that must be present to use this
48 guint env_restricted; /*!< The environments that must _not_ be present to
53 gchar *exec; /*!< Executable to run for the app.
55 gchar *wdir; /*!< Working dir to run the app in.
57 gboolean term; /*!< Run the app in a terminal or not */
60 gchar **mime; /*!< Mime types the app can open */
62 GQuark *categories; /*!< Array of quarks representing the
63 application's categories */
64 gulong n_categories; /*!< Number of categories for the app */
66 ObtLinkAppStartup startup;
67 gchar *startup_wmclass;
77 ObtLink* obt_link_from_ddfile(const gchar *path, ObtPaths *p,
78 const gchar *language,
80 const gchar *modifier)
83 GHashTable *groups, *keys;
87 /* parse the file, and get a hash table of the groups */
88 groups = obt_ddparse_file(path, language, country, modifier);
89 if (!groups) return NULL; /* parsing failed */
91 /* grab the Desktop Entry group */
92 g = g_hash_table_lookup(groups, "Desktop Entry");
94 /* grab the keys that appeared in the Desktop Entry group */
95 keys = obt_ddparse_group_keys(g);
97 /* build the ObtLink (we steal all strings from the parser) */
98 link = g_slice_new0(ObtLink);
100 link->path = g_strdup(path);
101 link->display = TRUE;
103 v = g_hash_table_lookup(keys, "Type");
105 link->type = v->value.enumerable;
107 v = g_hash_table_lookup(keys, "Name");
109 link->name = v->value.string, v->value.string = NULL; /* steal it */
110 link->collate_key = g_utf8_collate_key(link->name, -1);
112 if ((v = g_hash_table_lookup(keys, "Hidden")))
113 link->deleted = v->value.boolean;
115 if ((v = g_hash_table_lookup(keys, "NoDisplay")))
116 link->display = !v->value.boolean;
118 if ((v = g_hash_table_lookup(keys, "GenericName")))
119 link->generic = v->value.string, v->value.string = NULL;
121 if ((v = g_hash_table_lookup(keys, "Comment")))
122 link->comment = v->value.string, v->value.string = NULL;
124 if ((v = g_hash_table_lookup(keys, "Icon")))
125 link->icon = v->value.string, v->value.string = NULL;
127 if ((v = g_hash_table_lookup(keys, "OnlyShowIn")))
128 link->env_required = v->value.environments;
130 link->env_required = 0;
132 if ((v = g_hash_table_lookup(keys, "NotShowIn")))
133 link->env_restricted = v->value.environments;
135 link->env_restricted = 0;
137 /* type-specific keys */
139 if (link->type == OBT_LINK_TYPE_APPLICATION) {
143 v = g_hash_table_lookup(keys, "Exec");
145 link->d.app.exec = v->value.string;
146 v->value.string = NULL;
148 /* parse link->d.app.exec to determine link->d.app.open */
150 for (c = link->d.app.exec; *c; ++c) {
153 case 'f': link->d.app.open = OBT_LINK_APP_SINGLE_LOCAL; break;
154 case 'F': link->d.app.open = OBT_LINK_APP_MULTI_LOCAL; break;
155 case 'u': link->d.app.open = OBT_LINK_APP_SINGLE_URL; break;
156 case 'U': link->d.app.open = OBT_LINK_APP_MULTI_URL; break;
157 default: percent = FALSE;
159 if (percent) break; /* found f/F/u/U */
161 else if (*c == '%') percent = TRUE;
164 if ((v = g_hash_table_lookup(keys, "TryExec"))) {
165 /* XXX spawn a thread to check TryExec? */
166 link->display = link->display &&
167 obt_paths_try_exec(p, v->value.string);
170 if ((v = g_hash_table_lookup(keys, "Path"))) {
171 /* steal the string */
172 link->d.app.wdir = v->value.string;
173 v->value.string = NULL;
176 if ((v = g_hash_table_lookup(keys, "Terminal")))
177 link->d.app.term = v->value.boolean;
179 if ((v = g_hash_table_lookup(keys, "StartupNotify")))
180 link->d.app.startup = v->value.boolean ?
181 OBT_LINK_APP_STARTUP_PROTOCOL_SUPPORT :
182 OBT_LINK_APP_STARTUP_NO_SUPPORT;
184 link->d.app.startup = OBT_LINK_APP_STARTUP_LEGACY_SUPPORT;
185 if ((v = g_hash_table_lookup(keys, "StartupWMClass"))) {
186 /* steal the string */
187 link->d.app.startup_wmclass = v->value.string;
188 v->value.string = NULL;
192 if ((v = g_hash_table_lookup(keys, "Categories"))) {
195 link->d.app.categories = g_new(GQuark, v->value.strings.n);
196 link->d.app.n_categories = v->value.strings.n;
198 for (i = 0; i < v->value.strings.n; ++i) {
199 link->d.app.categories[i] =
200 g_quark_from_string(v->value.strings.a[i]);
204 if ((v = g_hash_table_lookup(keys, "MimeType"))) {
205 /* steal the string array */
206 link->d.app.mime = v->value.strings.a;
207 v->value.strings.a = NULL;
208 v->value.strings.n = 0;
211 else if (link->type == OBT_LINK_TYPE_URL) {
212 v = g_hash_table_lookup(keys, "URL");
214 link->d.url.addr = v->value.string;
215 v->value.string = NULL;
218 /* destroy the parsing info */
219 g_hash_table_destroy(groups);
224 void obt_link_ref(ObtLink *dd)
229 void obt_link_unref(ObtLink *dd)
233 g_free(dd->collate_key);
237 if (dd->type == OBT_LINK_TYPE_APPLICATION) {
238 g_free(dd->d.app.exec);
239 g_free(dd->d.app.wdir);
240 g_strfreev(dd->d.app.mime);
241 g_free(dd->d.app.categories);
242 g_free(dd->d.app.startup_wmclass);
244 else if (dd->type == OBT_LINK_TYPE_URL)
245 g_free(dd->d.url.addr);
246 g_slice_free(ObtLink, dd);
250 ObtLinkType obt_link_type (ObtLink *e)
252 g_return_val_if_fail(e != NULL, 0);
257 const GQuark* obt_link_app_categories(ObtLink *e, gulong *n)
259 g_return_val_if_fail(e != NULL, NULL);
260 g_return_val_if_fail(e->type == OBT_LINK_TYPE_APPLICATION, NULL);
261 g_return_val_if_fail(n != NULL, NULL);
263 *n = e->d.app.n_categories;
264 return e->d.app.categories;
267 const gchar *obt_link_source_file(ObtLink *e)
272 gchar* obt_link_id_from_ddfile(const gchar *filename)
274 return obt_ddparse_file_to_id(filename);
277 const gchar* obt_link_name(ObtLink *e)
282 const gchar* obt_link_generic_name(ObtLink *e)
287 const gchar* obt_link_comment(ObtLink *e)
292 gboolean obt_link_display(ObtLink *e, const guint environments)
295 /* display if the link wants to be displayed and TryExec passed */
297 /* display if no environment is required, or we match at least one of
299 (!e->env_required || (e->env_required & environments)) &&
300 /* display if no environment is restricted, or we do not match any of
302 (!e->env_restricted || !(e->env_restricted & environments));
305 int obt_link_cmp_by_name(const void *a, const void *b)
307 const ObtLink *const la = *(ObtLink**)a, *const lb = *(ObtLink**)b;
308 int r = strcmp(la->collate_key, lb->collate_key);
310 /* fallback to differentiating on the path */
311 return strcmp(la->path, lb->path);