Merge lp://qastaging/~indicator-applet-developers/libindicator/ubuntu into lp://qastaging/~ubuntu-desktop/libindicator/ubuntu
- ubuntu
- Merge into ubuntu
Proposed by
Ted Gould
Status: | Merged | ||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Merged at revision: | not available | ||||||||||||||||||||||||||||
Proposed branch: | lp://qastaging/~indicator-applet-developers/libindicator/ubuntu | ||||||||||||||||||||||||||||
Merge into: | lp://qastaging/~ubuntu-desktop/libindicator/ubuntu | ||||||||||||||||||||||||||||
Diff against target: |
899 lines (+811/-2) 9 files modified
.bzrignore (+4/-0) configure.ac (+4/-2) debian/changelog (+7/-0) libindicator/Makefile.am (+2/-0) libindicator/indicator-desktop-shortcuts.c (+523/-0) libindicator/indicator-desktop-shortcuts.h (+74/-0) tests/Makefile.am (+36/-0) tests/test-desktop-shortcuts.c (+137/-0) tests/test-well-formed.desktop (+24/-0) |
||||||||||||||||||||||||||||
To merge this branch: | bzr merge lp://qastaging/~indicator-applet-developers/libindicator/ubuntu | ||||||||||||||||||||||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Sebastien Bacher | Pending | ||
Review via email: mp+19626@code.qastaging.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Revision history for this message
Ted Gould (ted) wrote : | # |
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file '.bzrignore' |
2 | --- .bzrignore 2010-01-15 21:16:30 +0000 |
3 | +++ .bzrignore 2010-02-18 16:14:13 +0000 |
4 | @@ -147,3 +147,7 @@ |
5 | libindicator/indicator-object-marshal.h |
6 | libindicator/libindicator_la-indicator-object-marshal.lo |
7 | libindicator/stamp-marshal |
8 | +libindicator/libindicator_la-indicator-desktop-shortcuts.lo |
9 | +tests/test-desktop-shortcuts |
10 | +tests/test-desktop-shortcuts-tester |
11 | +tests/test-desktop-shortcuts-touch-test |
12 | |
13 | === modified file 'configure.ac' |
14 | --- configure.ac 2010-02-05 01:37:47 +0000 |
15 | +++ configure.ac 2010-02-18 16:14:13 +0000 |
16 | @@ -1,10 +1,10 @@ |
17 | |
18 | -AC_INIT(libindicator, 0.3.2, ted@canonical.com) |
19 | +AC_INIT(libindicator, 0.3.3, ted@canonical.com) |
20 | |
21 | AC_PREREQ(2.53) |
22 | |
23 | AM_CONFIG_HEADER(config.h) |
24 | -AM_INIT_AUTOMAKE(libindicator, 0.3.2) |
25 | +AM_INIT_AUTOMAKE(libindicator, 0.3.3) |
26 | |
27 | AM_MAINTAINER_MODE |
28 | m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES]) |
29 | @@ -28,8 +28,10 @@ |
30 | |
31 | GTK_REQUIRED_VERSION=2.18 |
32 | DBUS_REQUIRED_VERSION=0.76 |
33 | +GIO_UNIX_REQUIRED_VERSION=2.23 |
34 | |
35 | PKG_CHECK_MODULES(LIBINDICATOR, gtk+-2.0 >= $GTK_REQUIRED_VERSION |
36 | + gio-unix-2.0 >= $GIO_UNIX_REQUIRED_VERSION |
37 | dbus-glib-1 >= $DBUS_REQUIRED_VERSION) |
38 | |
39 | AC_SUBST(LIBINDICATOR_CFLAGS) |
40 | |
41 | === modified file 'debian/changelog' |
42 | --- debian/changelog 2010-02-05 03:00:38 +0000 |
43 | +++ debian/changelog 2010-02-18 16:14:13 +0000 |
44 | @@ -1,3 +1,10 @@ |
45 | +libindicator (0.3.3-0ubuntu1~ppa1) lucid; urgency=low |
46 | + |
47 | + * Upstream release 0.3.3 |
48 | + * Adding new object for parsing desktop files for Shortcuts |
49 | + |
50 | + -- Ted Gould <ted@ubuntu.com> Thu, 18 Feb 2010 10:11:21 -0600 |
51 | + |
52 | libindicator (0.3.2-0ubuntu1) lucid; urgency=low |
53 | |
54 | * Upstream release 0.3.2 |
55 | |
56 | === modified file 'libindicator/Makefile.am' |
57 | --- libindicator/Makefile.am 2010-01-15 21:16:30 +0000 |
58 | +++ libindicator/Makefile.am 2010-02-18 16:14:13 +0000 |
59 | @@ -10,6 +10,7 @@ |
60 | |
61 | indicator_headers = \ |
62 | indicator.h \ |
63 | + indicator-desktop-shortcuts.h \ |
64 | indicator-object.h \ |
65 | indicator-service.h \ |
66 | indicator-service-manager.h |
67 | @@ -24,6 +25,7 @@ |
68 | $(indicator_headers) \ |
69 | dbus-shared.h \ |
70 | indicator-object.c \ |
71 | + indicator-desktop-shortcuts.c \ |
72 | indicator-object-marshal.h \ |
73 | indicator-object-marshal.c \ |
74 | indicator-service.c \ |
75 | |
76 | === added file 'libindicator/indicator-desktop-shortcuts.c' |
77 | --- libindicator/indicator-desktop-shortcuts.c 1970-01-01 00:00:00 +0000 |
78 | +++ libindicator/indicator-desktop-shortcuts.c 2010-02-18 16:14:13 +0000 |
79 | @@ -0,0 +1,523 @@ |
80 | +/* |
81 | +A small file to parse through the actions that are available |
82 | +in the desktop file and making those easily usable. |
83 | + |
84 | +Copyright 2010 Canonical Ltd. |
85 | + |
86 | +Authors: |
87 | + Ted Gould <ted@canonical.com> |
88 | + |
89 | +This library is free software; you can redistribute it and/or |
90 | +modify it under the terms of the GNU General Public License |
91 | +version 3.0 as published by the Free Software Foundation. |
92 | + |
93 | +This library is distributed in the hope that it will be useful, |
94 | +but WITHOUT ANY WARRANTY; without even the implied warranty of |
95 | +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
96 | +GNU General Public License version 3.0 for more details. |
97 | + |
98 | +You should have received a copy of the GNU General Public |
99 | +License along with this library. If not, see |
100 | +<http://www.gnu.org/licenses/>. |
101 | +*/ |
102 | + |
103 | +#ifdef HAVE_CONFIG_H |
104 | +#include "config.h" |
105 | +#endif |
106 | + |
107 | +#include <gio/gdesktopappinfo.h> |
108 | +#include "indicator-desktop-shortcuts.h" |
109 | + |
110 | +#define GROUP_SUFFIX "Shortcut Group" |
111 | +#define SHORTCUTS_KEY "X-Ayatana-Desktop-Shortcuts" |
112 | + |
113 | +#define PROP_DESKTOP_FILE_S "desktop-file" |
114 | +#define PROP_IDENTITY_S "identity" |
115 | + |
116 | +typedef struct _IndicatorDesktopShortcutsPrivate IndicatorDesktopShortcutsPrivate; |
117 | +struct _IndicatorDesktopShortcutsPrivate { |
118 | + GKeyFile * keyfile; |
119 | + gchar * identity; |
120 | + GArray * nicks; |
121 | +}; |
122 | + |
123 | +enum { |
124 | + PROP_0, |
125 | + PROP_DESKTOP_FILE, |
126 | + PROP_IDENTITY |
127 | +}; |
128 | + |
129 | +#define INDICATOR_DESKTOP_SHORTCUTS_GET_PRIVATE(o) \ |
130 | + (G_TYPE_INSTANCE_GET_PRIVATE ((o), INDICATOR_TYPE_DESKTOP_SHORTCUTS, IndicatorDesktopShortcutsPrivate)) |
131 | + |
132 | +static void indicator_desktop_shortcuts_class_init (IndicatorDesktopShortcutsClass *klass); |
133 | +static void indicator_desktop_shortcuts_init (IndicatorDesktopShortcuts *self); |
134 | +static void indicator_desktop_shortcuts_dispose (GObject *object); |
135 | +static void indicator_desktop_shortcuts_finalize (GObject *object); |
136 | +static void set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); |
137 | +static void get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); |
138 | +static void parse_keyfile (IndicatorDesktopShortcuts * ids); |
139 | +static gboolean should_show (GKeyFile * keyfile, const gchar * group, const gchar * identity); |
140 | + |
141 | +G_DEFINE_TYPE (IndicatorDesktopShortcuts, indicator_desktop_shortcuts, G_TYPE_OBJECT); |
142 | + |
143 | +/* Build up the class */ |
144 | +static void |
145 | +indicator_desktop_shortcuts_class_init (IndicatorDesktopShortcutsClass *klass) |
146 | +{ |
147 | + GObjectClass *object_class = G_OBJECT_CLASS (klass); |
148 | + |
149 | + g_type_class_add_private (klass, sizeof (IndicatorDesktopShortcutsPrivate)); |
150 | + |
151 | + object_class->dispose = indicator_desktop_shortcuts_dispose; |
152 | + object_class->finalize = indicator_desktop_shortcuts_finalize; |
153 | + |
154 | + /* Property funcs */ |
155 | + object_class->set_property = set_property; |
156 | + object_class->get_property = get_property; |
157 | + |
158 | + g_object_class_install_property(object_class, PROP_DESKTOP_FILE, |
159 | + g_param_spec_string(PROP_DESKTOP_FILE_S, |
160 | + "The path of the desktop file to read", |
161 | + "A path to a desktop file that we'll look for shortcuts in.", |
162 | + NULL, |
163 | + G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY)); |
164 | + g_object_class_install_property(object_class, PROP_IDENTITY, |
165 | + g_param_spec_string(PROP_IDENTITY_S, |
166 | + "The string that represents the identity that we're acting as.", |
167 | + "Used to process ShowIn and NotShownIn fields of the desktop shortcust to get the proper list.", |
168 | + NULL, |
169 | + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY)); |
170 | + |
171 | + return; |
172 | +} |
173 | + |
174 | +/* Initialize instance data */ |
175 | +static void |
176 | +indicator_desktop_shortcuts_init (IndicatorDesktopShortcuts *self) |
177 | +{ |
178 | + IndicatorDesktopShortcutsPrivate * priv = INDICATOR_DESKTOP_SHORTCUTS_GET_PRIVATE(self); |
179 | + |
180 | + priv->keyfile = NULL; |
181 | + priv->identity = NULL; |
182 | + priv->nicks = g_array_new(TRUE, TRUE, sizeof(gchar *)); |
183 | + |
184 | + return; |
185 | +} |
186 | + |
187 | +/* Clear object references */ |
188 | +static void |
189 | +indicator_desktop_shortcuts_dispose (GObject *object) |
190 | +{ |
191 | + IndicatorDesktopShortcutsPrivate * priv = INDICATOR_DESKTOP_SHORTCUTS_GET_PRIVATE(object); |
192 | + |
193 | + if (priv->keyfile) { |
194 | + g_key_file_free(priv->keyfile); |
195 | + priv->keyfile = NULL; |
196 | + } |
197 | + |
198 | + G_OBJECT_CLASS (indicator_desktop_shortcuts_parent_class)->dispose (object); |
199 | + return; |
200 | +} |
201 | + |
202 | +/* Free all memory */ |
203 | +static void |
204 | +indicator_desktop_shortcuts_finalize (GObject *object) |
205 | +{ |
206 | + IndicatorDesktopShortcutsPrivate * priv = INDICATOR_DESKTOP_SHORTCUTS_GET_PRIVATE(object); |
207 | + |
208 | + if (priv->identity != NULL) { |
209 | + g_free(priv->identity); |
210 | + priv->identity = NULL; |
211 | + } |
212 | + |
213 | + if (priv->nicks != NULL) { |
214 | + gint i; |
215 | + for (i = 0; i < priv->nicks->len; i++) { |
216 | + gchar * nick = g_array_index(priv->nicks, gchar *, i); |
217 | + g_free(nick); |
218 | + } |
219 | + g_array_free(priv->nicks, TRUE); |
220 | + priv->nicks = NULL; |
221 | + } |
222 | + |
223 | + G_OBJECT_CLASS (indicator_desktop_shortcuts_parent_class)->finalize (object); |
224 | + return; |
225 | +} |
226 | + |
227 | +/* Sets one of the two properties we have, only at construction though */ |
228 | +static void |
229 | +set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) |
230 | +{ |
231 | + g_return_if_fail(INDICATOR_IS_DESKTOP_SHORTCUTS(object)); |
232 | + IndicatorDesktopShortcutsPrivate * priv = INDICATOR_DESKTOP_SHORTCUTS_GET_PRIVATE(object); |
233 | + |
234 | + switch(prop_id) { |
235 | + case PROP_DESKTOP_FILE: { |
236 | + GError * error = NULL; |
237 | + GKeyFile * keyfile = g_key_file_new(); |
238 | + g_key_file_load_from_file(keyfile, g_value_get_string(value), G_KEY_FILE_NONE, &error); |
239 | + |
240 | + if (error != NULL) { |
241 | + g_warning("Unable to load keyfile from file '%s': %s", g_value_get_string(value), error->message); |
242 | + g_error_free(error); |
243 | + g_key_file_free(keyfile); |
244 | + break; |
245 | + } |
246 | + |
247 | + if (!g_key_file_has_key(keyfile, G_KEY_FILE_DESKTOP_GROUP, SHORTCUTS_KEY, NULL)) { |
248 | + g_warning("Keyfile from file '%s' does not have '" SHORTCUTS_KEY "' key", g_value_get_string(value)); |
249 | + g_key_file_free(keyfile); |
250 | + break; |
251 | + } |
252 | + |
253 | + priv->keyfile = keyfile; |
254 | + parse_keyfile(INDICATOR_DESKTOP_SHORTCUTS(object)); |
255 | + break; |
256 | + } |
257 | + case PROP_IDENTITY: |
258 | + if (priv->identity != NULL) { |
259 | + g_warning("Identity already set to '%s' and trying to set it to '%s'.", priv->identity, g_value_get_string(value)); |
260 | + return; |
261 | + } |
262 | + priv->identity = g_value_dup_string(value); |
263 | + parse_keyfile(INDICATOR_DESKTOP_SHORTCUTS(object)); |
264 | + break; |
265 | + /* *********************** */ |
266 | + default: |
267 | + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
268 | + break; |
269 | + } |
270 | + |
271 | + return; |
272 | +} |
273 | + |
274 | +/* Gets either the desktop file our the identity. */ |
275 | +static void |
276 | +get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) |
277 | +{ |
278 | + g_return_if_fail(INDICATOR_IS_DESKTOP_SHORTCUTS(object)); |
279 | + IndicatorDesktopShortcutsPrivate * priv = INDICATOR_DESKTOP_SHORTCUTS_GET_PRIVATE(object); |
280 | + |
281 | + switch(prop_id) { |
282 | + case PROP_IDENTITY: |
283 | + g_value_set_string(value, priv->identity); |
284 | + break; |
285 | + /* *********************** */ |
286 | + default: |
287 | + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
288 | + break; |
289 | + } |
290 | + |
291 | + return; |
292 | +} |
293 | + |
294 | +/* Checks to see if we can, and if we can it goes through |
295 | + and parses the keyfile entries. */ |
296 | +static void |
297 | +parse_keyfile (IndicatorDesktopShortcuts * ids) |
298 | +{ |
299 | + IndicatorDesktopShortcutsPrivate * priv = INDICATOR_DESKTOP_SHORTCUTS_GET_PRIVATE(ids); |
300 | + |
301 | + if (priv->keyfile == NULL) { |
302 | + return; |
303 | + } |
304 | + |
305 | + if (priv->identity == NULL) { |
306 | + return; |
307 | + } |
308 | + |
309 | + /* Okay, we've got everything we need. Let's get it on! */ |
310 | + gint i; |
311 | + gsize num_nicks = 0; |
312 | + gchar ** nicks = g_key_file_get_string_list(priv->keyfile, G_KEY_FILE_DESKTOP_GROUP, SHORTCUTS_KEY, &num_nicks, NULL); |
313 | + |
314 | + /* If there is an error from get_string_list num_nicks should still |
315 | + be zero, so this loop will drop out. */ |
316 | + for (i = 0; i < num_nicks; i++) { |
317 | + /* g_debug("Looking at group nick %s", nicks[i]); */ |
318 | + gchar * groupname = g_strdup_printf("%s " GROUP_SUFFIX, nicks[i]); |
319 | + if (!g_key_file_has_group(priv->keyfile, groupname)) { |
320 | + g_warning("Unable to find group '%s'", groupname); |
321 | + g_free(groupname); |
322 | + continue; |
323 | + } |
324 | + |
325 | + if (!should_show(priv->keyfile, G_KEY_FILE_DESKTOP_GROUP, priv->identity)) { |
326 | + g_free(groupname); |
327 | + continue; |
328 | + } |
329 | + |
330 | + if (!should_show(priv->keyfile, groupname, priv->identity)) { |
331 | + g_free(groupname); |
332 | + continue; |
333 | + } |
334 | + |
335 | + gchar * nickalloc = g_strdup(nicks[i]); |
336 | + g_array_append_val(priv->nicks, nickalloc); |
337 | + } |
338 | + |
339 | + if (nicks != NULL) { |
340 | + g_strfreev(nicks); |
341 | + } |
342 | + |
343 | + return; |
344 | +} |
345 | + |
346 | +/* Checks the ONLY_SHOW_IN and NOT_SHOW_IN keys for a group to |
347 | + see if we should be showing ourselves. */ |
348 | +static gboolean |
349 | +should_show (GKeyFile * keyfile, const gchar * group, const gchar * identity) |
350 | +{ |
351 | + /* If there is a list of OnlyShowIn entries we need to check |
352 | + to see if we're in that list. If not, we drop this nick */ |
353 | + if (g_key_file_has_key(keyfile, group, G_KEY_FILE_DESKTOP_KEY_ONLY_SHOW_IN, NULL)) { |
354 | + gint j; |
355 | + gsize num_only = 0; |
356 | + gchar ** onlies = g_key_file_get_string_list(keyfile, group, G_KEY_FILE_DESKTOP_KEY_ONLY_SHOW_IN, &num_only, NULL); |
357 | + |
358 | + for (j = 0; j < num_only; j++) { |
359 | + if (g_strcmp0(onlies[j], identity) == 0) { |
360 | + break; |
361 | + } |
362 | + } |
363 | + |
364 | + if (onlies != NULL) { |
365 | + g_strfreev(onlies); |
366 | + } |
367 | + |
368 | + if (j == num_only) { |
369 | + return FALSE; |
370 | + } |
371 | + } |
372 | + |
373 | + /* If there is a NotShowIn entry we need to make sure that we're |
374 | + not in that list. If we are, we need to drop out. */ |
375 | + if (g_key_file_has_key(keyfile, group, G_KEY_FILE_DESKTOP_KEY_NOT_SHOW_IN, NULL)) { |
376 | + gint j; |
377 | + gsize num_not = 0; |
378 | + gchar ** nots = g_key_file_get_string_list(keyfile, group, G_KEY_FILE_DESKTOP_KEY_NOT_SHOW_IN, &num_not, NULL); |
379 | + |
380 | + for (j = 0; j < num_not; j++) { |
381 | + if (g_strcmp0(nots[j], identity) == 0) { |
382 | + break; |
383 | + } |
384 | + } |
385 | + |
386 | + if (nots != NULL) { |
387 | + g_strfreev(nots); |
388 | + } |
389 | + |
390 | + if (j != num_not) { |
391 | + return FALSE; |
392 | + } |
393 | + } |
394 | + |
395 | + return TRUE; |
396 | +} |
397 | + |
398 | +/* Looks through the nicks ot see if this one is in the list, |
399 | + and thus valid to use. */ |
400 | +static gboolean |
401 | +is_valid_nick (gchar ** list, const gchar * nick) |
402 | +{ |
403 | + if (*list == NULL) |
404 | + return FALSE; |
405 | + /* g_debug("Checking Nick: %s", list[0]); */ |
406 | + if (g_strcmp0(list[0], nick) == 0) |
407 | + return TRUE; |
408 | + return is_valid_nick(&list[1], nick); |
409 | +} |
410 | + |
411 | +/* API */ |
412 | + |
413 | +/** |
414 | + indicator_desktop_shortcuts_new: |
415 | + @file: The desktop file that would be opened to |
416 | + find the actions. |
417 | + @identity: This is a string that represents the identity |
418 | + that should be used in searching those actions. It |
419 | + relates to the ShowIn and NotShownIn properties. |
420 | + |
421 | + This function creates the basic object. It involves opening |
422 | + the file and parsing it. It could potentially block on IO. At |
423 | + the end of the day you'll have a fully functional object. |
424 | + |
425 | + Return value: A new #IndicatorDesktopShortcuts object. |
426 | +*/ |
427 | +IndicatorDesktopShortcuts * |
428 | +indicator_desktop_shortcuts_new (const gchar * file, const gchar * identity) |
429 | +{ |
430 | + GObject * obj = g_object_new(INDICATOR_TYPE_DESKTOP_SHORTCUTS, |
431 | + PROP_DESKTOP_FILE_S, file, |
432 | + PROP_IDENTITY_S, identity, |
433 | + NULL); |
434 | + return INDICATOR_DESKTOP_SHORTCUTS(obj); |
435 | +} |
436 | + |
437 | +/** |
438 | + indicator_desktop_shortcuts_get_nicks: |
439 | + @ids: The #IndicatorDesktopShortcuts object to look in |
440 | + |
441 | + Give you the list of commands that are available for this desktop |
442 | + file given the identity that was passed in at creation. This will |
443 | + filter out the various items in the desktop file. These nicks can |
444 | + then be used as keys for working with the desktop file. |
445 | + |
446 | + Return value: A #NULL terminated list of strings. This memory |
447 | + is managed by the @ids object. |
448 | +*/ |
449 | +const gchar ** |
450 | +indicator_desktop_shortcuts_get_nicks (IndicatorDesktopShortcuts * ids) |
451 | +{ |
452 | + g_return_val_if_fail(INDICATOR_IS_DESKTOP_SHORTCUTS(ids), NULL); |
453 | + IndicatorDesktopShortcutsPrivate * priv = INDICATOR_DESKTOP_SHORTCUTS_GET_PRIVATE(ids); |
454 | + return (const gchar **)priv->nicks->data; |
455 | +} |
456 | + |
457 | +/** |
458 | + indicator_desktop_shortcuts_nick_get_name: |
459 | + @ids: The #IndicatorDesktopShortcuts object to look in |
460 | + @nick: Which command that we're referencing. |
461 | + |
462 | + This function looks in a desktop file for a nick to find the |
463 | + user visible name for that shortcut. The @nick parameter |
464 | + should be gotten from #indicator_desktop_shortcuts_get_nicks |
465 | + though it's not required that the exact memory location |
466 | + be the same. |
467 | + |
468 | + Return value: A user visible string for the shortcut or |
469 | + #NULL on error. |
470 | +*/ |
471 | +gchar * |
472 | +indicator_desktop_shortcuts_nick_get_name (IndicatorDesktopShortcuts * ids, const gchar * nick) |
473 | +{ |
474 | + g_return_val_if_fail(INDICATOR_IS_DESKTOP_SHORTCUTS(ids), NULL); |
475 | + IndicatorDesktopShortcutsPrivate * priv = INDICATOR_DESKTOP_SHORTCUTS_GET_PRIVATE(ids); |
476 | + |
477 | + g_return_val_if_fail(priv->keyfile != NULL, NULL); |
478 | + g_return_val_if_fail(is_valid_nick((gchar **)priv->nicks->data, nick), NULL); |
479 | + |
480 | + gchar * groupheader = g_strdup_printf("%s " GROUP_SUFFIX, nick); |
481 | + if (!g_key_file_has_group(priv->keyfile, groupheader)) { |
482 | + g_warning("The group for nick '%s' doesn't exist anymore.", nick); |
483 | + g_free(groupheader); |
484 | + return NULL; |
485 | + } |
486 | + |
487 | + if (!g_key_file_has_key(priv->keyfile, groupheader, G_KEY_FILE_DESKTOP_KEY_NAME, NULL)) { |
488 | + g_warning("No name available for nick '%s'", nick); |
489 | + g_free(groupheader); |
490 | + return NULL; |
491 | + } |
492 | + |
493 | + gchar * name = g_key_file_get_locale_string(priv->keyfile, |
494 | + groupheader, |
495 | + G_KEY_FILE_DESKTOP_KEY_NAME, |
496 | + NULL, |
497 | + NULL); |
498 | + |
499 | + g_free(groupheader); |
500 | + |
501 | + return name; |
502 | +} |
503 | + |
504 | +/** |
505 | + indicator_desktop_shortcuts_nick_exec: |
506 | + @ids: The #IndicatorDesktopShortcuts object to look in |
507 | + @nick: Which command that we're referencing. |
508 | + |
509 | + Here we take a @nick and try and execute the action that is |
510 | + associated with it. The @nick parameter should be gotten |
511 | + from #indicator_desktop_shortcuts_get_nicks though it's not |
512 | + required that the exact memory location be the same. |
513 | + |
514 | + Return value: #TRUE on success or #FALSE on error. |
515 | +*/ |
516 | +gboolean |
517 | +indicator_desktop_shortcuts_nick_exec (IndicatorDesktopShortcuts * ids, const gchar * nick) |
518 | +{ |
519 | + GError * error = NULL; |
520 | + |
521 | + g_return_val_if_fail(INDICATOR_IS_DESKTOP_SHORTCUTS(ids), FALSE); |
522 | + IndicatorDesktopShortcutsPrivate * priv = INDICATOR_DESKTOP_SHORTCUTS_GET_PRIVATE(ids); |
523 | + |
524 | + g_return_val_if_fail(priv->keyfile != NULL, FALSE); |
525 | + g_return_val_if_fail(is_valid_nick((gchar **)priv->nicks->data, nick), FALSE); |
526 | + |
527 | + gchar * groupheader = g_strdup_printf("%s " GROUP_SUFFIX, nick); |
528 | + if (!g_key_file_has_group(priv->keyfile, groupheader)) { |
529 | + g_warning("The group for nick '%s' doesn't exist anymore.", nick); |
530 | + g_free(groupheader); |
531 | + return FALSE; |
532 | + } |
533 | + |
534 | + if (!g_key_file_has_key(priv->keyfile, groupheader, G_KEY_FILE_DESKTOP_KEY_NAME, NULL)) { |
535 | + g_warning("No name available for nick '%s'", nick); |
536 | + g_free(groupheader); |
537 | + return FALSE; |
538 | + } |
539 | + |
540 | + if (!g_key_file_has_key(priv->keyfile, groupheader, G_KEY_FILE_DESKTOP_KEY_EXEC, NULL)) { |
541 | + g_warning("No exec available for nick '%s'", nick); |
542 | + g_free(groupheader); |
543 | + return FALSE; |
544 | + } |
545 | + |
546 | + /* Grab the name and the exec entries out of our current group */ |
547 | + gchar * name = g_key_file_get_locale_string(priv->keyfile, |
548 | + groupheader, |
549 | + G_KEY_FILE_DESKTOP_KEY_NAME, |
550 | + NULL, |
551 | + NULL); |
552 | + |
553 | + gchar * exec = g_key_file_get_locale_string(priv->keyfile, |
554 | + groupheader, |
555 | + G_KEY_FILE_DESKTOP_KEY_EXEC, |
556 | + NULL, |
557 | + NULL); |
558 | + |
559 | + /* Build a new desktop file with the name and exec in the desktop |
560 | + group. We have to do this with data as apparently there isn't |
561 | + and add_group function in g_key_file. Go figure. */ |
562 | + gchar * desktopdata = g_strdup_printf("[" G_KEY_FILE_DESKTOP_GROUP "]\n" |
563 | + G_KEY_FILE_DESKTOP_KEY_TYPE "=" G_KEY_FILE_DESKTOP_TYPE_APPLICATION "\n" |
564 | + G_KEY_FILE_DESKTOP_KEY_NAME "=%s\n" |
565 | + G_KEY_FILE_DESKTOP_KEY_EXEC "=%s\n", |
566 | + name, exec); |
567 | + |
568 | + |
569 | + g_free(name); g_free(exec); |
570 | + /* g_debug("Desktop file: \n%s", desktopdata); */ |
571 | + |
572 | + GKeyFile * launcher = g_key_file_new(); |
573 | + g_key_file_load_from_data(launcher, desktopdata, -1, G_KEY_FILE_NONE, &error); |
574 | + g_free(desktopdata); |
575 | + |
576 | + if (error != NULL) { |
577 | + g_warning("Unable to build desktop keyfile for executing shortcut '%s': %s", nick, error->message); |
578 | + g_error_free(error); |
579 | + return FALSE; |
580 | + } |
581 | + |
582 | + GDesktopAppInfo * appinfo = g_desktop_app_info_new_from_keyfile(launcher); |
583 | + if (appinfo == NULL) { |
584 | + g_warning("Unable to build Desktop App info (unknown)"); |
585 | + g_key_file_free(launcher); |
586 | + return FALSE; |
587 | + } |
588 | + |
589 | + gboolean launched = g_app_info_launch(G_APP_INFO(appinfo), NULL, NULL, &error); |
590 | + |
591 | + if (error != NULL) { |
592 | + g_warning("Unable to launch file from nick '%s': %s", nick, error->message); |
593 | + g_error_free(error); |
594 | + g_key_file_free(launcher); |
595 | + return FALSE; |
596 | + } |
597 | + |
598 | + g_object_unref(appinfo); |
599 | + g_key_file_free(launcher); |
600 | + |
601 | + return launched; |
602 | +} |
603 | |
604 | === added file 'libindicator/indicator-desktop-shortcuts.h' |
605 | --- libindicator/indicator-desktop-shortcuts.h 1970-01-01 00:00:00 +0000 |
606 | +++ libindicator/indicator-desktop-shortcuts.h 2010-02-18 16:14:13 +0000 |
607 | @@ -0,0 +1,74 @@ |
608 | +/* |
609 | +A small file to parse through the actions that are available |
610 | +in the desktop file and making those easily usable. |
611 | + |
612 | +Copyright 2010 Canonical Ltd. |
613 | + |
614 | +Authors: |
615 | + Ted Gould <ted@canonical.com> |
616 | + |
617 | +This library is free software; you can redistribute it and/or |
618 | +modify it under the terms of the GNU General Public License |
619 | +version 3.0 as published by the Free Software Foundation. |
620 | + |
621 | +This library is distributed in the hope that it will be useful, |
622 | +but WITHOUT ANY WARRANTY; without even the implied warranty of |
623 | +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
624 | +GNU General Public License version 3.0 for more details. |
625 | + |
626 | +You should have received a copy of the GNU General Public |
627 | +License along with this library. If not, see |
628 | +<http://www.gnu.org/licenses/>. |
629 | +*/ |
630 | + |
631 | +#ifndef __INDICATOR_DESKTOP_SHORTCUTS_H__ |
632 | +#define __INDICATOR_DESKTOP_SHORTCUTS_H__ |
633 | + |
634 | +#include <glib.h> |
635 | +#include <glib-object.h> |
636 | + |
637 | +G_BEGIN_DECLS |
638 | + |
639 | +#define INDICATOR_TYPE_DESKTOP_SHORTCUTS (indicator_desktop_shortcuts_get_type ()) |
640 | +#define INDICATOR_DESKTOP_SHORTCUTS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), INDICATOR_TYPE_DESKTOP_SHORTCUTS, IndicatorDesktopShortcuts)) |
641 | +#define INDICATOR_DESKTOP_SHORTCUTS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), INDICATOR_TYPE_DESKTOP_SHORTCUTS, IndicatorDesktopShortcutsClass)) |
642 | +#define INDICATOR_IS_DESKTOP_SHORTCUTS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), INDICATOR_TYPE_DESKTOP_SHORTCUTS)) |
643 | +#define INDICATOR_IS_DESKTOP_SHORTCUTS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), INDICATOR_TYPE_DESKTOP_SHORTCUTS)) |
644 | +#define INDICATOR_DESKTOP_SHORTCUTS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), INDICATOR_TYPE_DESKTOP_SHORTCUTS, IndicatorDesktopShortcutsClass)) |
645 | + |
646 | +typedef struct _IndicatorDesktopShortcuts IndicatorDesktopShortcuts; |
647 | +typedef struct _IndicatorDesktopShortcutsClass IndicatorDesktopShortcutsClass; |
648 | + |
649 | +/** |
650 | + IndicatorDesktopShortcutsClass: |
651 | + @parent_class: Space for #GObjectClass |
652 | + |
653 | + The vtable for our precious #IndicatorDesktopShortcutsClass. |
654 | +*/ |
655 | +struct _IndicatorDesktopShortcutsClass { |
656 | + GObjectClass parent_class; |
657 | +}; |
658 | + |
659 | +/** |
660 | + IndicatorDesktopShortcuts: |
661 | + @parent: The parent data from #GObject |
662 | + |
663 | + The public data for an instance of the class |
664 | + #IndicatorDesktopShortcuts. |
665 | +*/ |
666 | +struct _IndicatorDesktopShortcuts { |
667 | + GObject parent; |
668 | +}; |
669 | + |
670 | +GType indicator_desktop_shortcuts_get_type (void); |
671 | +IndicatorDesktopShortcuts * indicator_desktop_shortcuts_new (const gchar * file, |
672 | + const gchar * identity); |
673 | +const gchar ** indicator_desktop_shortcuts_get_nicks (IndicatorDesktopShortcuts * ids); |
674 | +gchar * indicator_desktop_shortcuts_nick_get_name (IndicatorDesktopShortcuts * ids, |
675 | + const gchar * nick); |
676 | +gboolean indicator_desktop_shortcuts_nick_exec (IndicatorDesktopShortcuts * ids, |
677 | + const gchar * nick); |
678 | + |
679 | +G_END_DECLS |
680 | + |
681 | +#endif |
682 | |
683 | === modified file 'tests/Makefile.am' |
684 | --- tests/Makefile.am 2010-02-02 20:10:23 +0000 |
685 | +++ tests/Makefile.am 2010-02-18 16:14:13 +0000 |
686 | @@ -34,6 +34,42 @@ |
687 | -lindicator |
688 | |
689 | ############################# |
690 | +# Test Desktop Shortcuts |
691 | +############################# |
692 | + |
693 | +check_PROGRAMS += test-desktop-shortcuts |
694 | + |
695 | +test_desktop_shortcuts_SOURCES = \ |
696 | + test-desktop-shortcuts.c |
697 | + |
698 | +test_desktop_shortcuts_CFLAGS = \ |
699 | + -Wall -Werror \ |
700 | + -DSRCDIR="\"$(srcdir)\"" \ |
701 | + $(LIBINDICATOR_CFLAGS) -I$(top_srcdir) \ |
702 | + -DBUILD_DIR="\"$(builddir)\"" |
703 | + |
704 | +test_desktop_shortcuts_LDADD = \ |
705 | + $(LIBINDICATOR_LIBS) \ |
706 | + -L$(top_builddir)/libindicator/.libs \ |
707 | + -lindicator |
708 | + |
709 | +DS_XML_REPORT = desktop-shortcuts-check-results.xml |
710 | +DS_HTML_REPORT = desktop-shortcuts-check-results.html |
711 | + |
712 | +test-desktop-shortcuts-tester: test-desktop-shortcuts Makefile.am |
713 | + @echo "#!/bin/bash" > $@ |
714 | + @echo $(XVFB_RUN) >> $@ |
715 | + @echo gtester -k --verbose -o=$(XML_REPORT) ./test-desktop-shortcuts >> $@ |
716 | + @chmod +x $@ |
717 | + |
718 | +TESTS += test-desktop-shortcuts-tester |
719 | +DISTCLEANFILES += test-desktop-shortcuts-tester \ |
720 | + test-desktop-shortcuts-touch-test \ |
721 | + $(DS_XML_REPORT) \ |
722 | + $(DS_HTML_REPORT) |
723 | +EXTRA_DIST += test-well-formed.desktop |
724 | + |
725 | +############################# |
726 | # Dummy Indicator Blank |
727 | ############################# |
728 | |
729 | |
730 | === added file 'tests/test-desktop-shortcuts.c' |
731 | --- tests/test-desktop-shortcuts.c 1970-01-01 00:00:00 +0000 |
732 | +++ tests/test-desktop-shortcuts.c 2010-02-18 16:14:13 +0000 |
733 | @@ -0,0 +1,137 @@ |
734 | +#include <gtk/gtk.h> |
735 | +#include "libindicator/indicator-desktop-shortcuts.h" |
736 | + |
737 | +/* Basic object creation and destruction. Stop big |
738 | + f*** ups here. */ |
739 | +void |
740 | +test_desktop_shortcuts_creation (void) |
741 | +{ |
742 | + |
743 | + IndicatorDesktopShortcuts * ids = indicator_desktop_shortcuts_new(SRCDIR "/test-well-formed.desktop", "France"); |
744 | + g_assert(ids != NULL); |
745 | + |
746 | + g_object_add_weak_pointer(G_OBJECT(ids), (gpointer *)&ids); |
747 | + g_object_unref(G_OBJECT(ids)); |
748 | + |
749 | + g_assert(ids == NULL); |
750 | + return; |
751 | +} |
752 | + |
753 | +/* Tests that the NotShowIn the desktop group is watched |
754 | + for */ |
755 | +void |
756 | +test_desktop_shortcuts_globalnoshow (void) |
757 | +{ |
758 | + |
759 | + IndicatorDesktopShortcuts * ids = indicator_desktop_shortcuts_new(SRCDIR "/test-well-formed.desktop", "Germany"); |
760 | + g_assert(ids != NULL); |
761 | + |
762 | + const gchar ** nicks = indicator_desktop_shortcuts_get_nicks(ids); |
763 | + g_assert(nicks[0] == NULL); |
764 | + |
765 | + g_object_unref(ids); |
766 | + |
767 | + return; |
768 | +} |
769 | + |
770 | +gboolean |
771 | +nicks_contains (const gchar ** nicks, const gchar * search) |
772 | +{ |
773 | + if (nicks[0] == NULL) |
774 | + return FALSE; |
775 | + if (g_strcmp0(nicks[0], search) == 0) |
776 | + return TRUE; |
777 | + return nicks_contains(&nicks[1], search); |
778 | +} |
779 | + |
780 | +/* Checking that the local show OnlyIn works. */ |
781 | +void |
782 | +test_desktop_shortcuts_localfilter (void) |
783 | +{ |
784 | + IndicatorDesktopShortcuts * ids = indicator_desktop_shortcuts_new(SRCDIR "/test-well-formed.desktop", "France"); |
785 | + g_assert(ids != NULL); |
786 | + |
787 | + const gchar ** nicks = indicator_desktop_shortcuts_get_nicks(ids); |
788 | + |
789 | + g_assert(nicks_contains(nicks, "bob")); |
790 | + g_assert(nicks_contains(nicks, "alvin")); |
791 | + g_assert(!nicks_contains(nicks, "jim")); |
792 | + |
793 | + g_object_unref(ids); |
794 | + |
795 | + return; |
796 | +} |
797 | + |
798 | +/* Nick names -- checks to see they all have names */ |
799 | +void |
800 | +test_desktop_shortcuts_nicknames (void) |
801 | +{ |
802 | + IndicatorDesktopShortcuts * ids = indicator_desktop_shortcuts_new(SRCDIR "/test-well-formed.desktop", "France"); |
803 | + g_assert(ids != NULL); |
804 | + |
805 | + const gchar ** nicks = indicator_desktop_shortcuts_get_nicks(ids); |
806 | + gint i = 0; |
807 | + while (nicks[i] != NULL) { |
808 | + gchar * expectedstr = g_strdup_printf("%s's shortcut", nicks[i]); |
809 | + gchar * name = indicator_desktop_shortcuts_nick_get_name(ids, nicks[i]); |
810 | + g_assert(name != NULL); |
811 | + |
812 | + gboolean same = (g_strcmp0(expectedstr, name) == 0); |
813 | + |
814 | + g_free(name); |
815 | + g_free(expectedstr); |
816 | + |
817 | + g_assert(same); |
818 | + |
819 | + i++; |
820 | + } |
821 | + |
822 | + |
823 | + g_object_unref(ids); |
824 | + |
825 | + return; |
826 | +} |
827 | + |
828 | +/* Try executing a shortcut which will touch a file */ |
829 | +void |
830 | +test_desktop_shortcuts_launch (void) |
831 | +{ |
832 | + IndicatorDesktopShortcuts * ids = indicator_desktop_shortcuts_new(SRCDIR "/test-well-formed.desktop", "TouchTest"); |
833 | + g_assert(ids != NULL); |
834 | + |
835 | + const gchar ** nicks = indicator_desktop_shortcuts_get_nicks(ids); |
836 | + g_assert(nicks_contains(nicks, "touch")); |
837 | + |
838 | + g_assert(indicator_desktop_shortcuts_nick_exec(ids, "touch")); |
839 | + g_assert(g_file_test(BUILD_DIR "/test-desktop-shortcuts-touch-test", G_FILE_TEST_EXISTS)); |
840 | + |
841 | + g_object_unref(ids); |
842 | + |
843 | + return; |
844 | +} |
845 | + |
846 | +/* Build our test suite */ |
847 | +void |
848 | +test_desktop_shortcuts_suite (void) |
849 | +{ |
850 | + g_test_add_func ("/libindicator/desktopshortcuts/creation", test_desktop_shortcuts_creation); |
851 | + g_test_add_func ("/libindicator/desktopshortcuts/globalnosho", test_desktop_shortcuts_globalnoshow); |
852 | + g_test_add_func ("/libindicator/desktopshortcuts/nicknames", test_desktop_shortcuts_nicknames); |
853 | + g_test_add_func ("/libindicator/desktopshortcuts/launch", test_desktop_shortcuts_launch); |
854 | + |
855 | + return; |
856 | +} |
857 | + |
858 | +int |
859 | +main (int argc, char ** argv) |
860 | +{ |
861 | + g_type_init (); |
862 | + g_test_init (&argc, &argv, NULL); |
863 | + gtk_init(&argc, &argv); |
864 | + |
865 | + test_desktop_shortcuts_suite(); |
866 | + |
867 | + g_log_set_always_fatal(G_LOG_LEVEL_CRITICAL); |
868 | + |
869 | + return g_test_run(); |
870 | +} |
871 | |
872 | === added file 'tests/test-well-formed.desktop' |
873 | --- tests/test-well-formed.desktop 1970-01-01 00:00:00 +0000 |
874 | +++ tests/test-well-formed.desktop 2010-02-18 16:14:13 +0000 |
875 | @@ -0,0 +1,24 @@ |
876 | +[Desktop Entry] |
877 | +Name=My Application |
878 | +Exec=ls |
879 | +NotShowIn=Germany |
880 | +X-Ayatana-Desktop-Shortcuts=bob;alvin;jim;touch |
881 | + |
882 | +[bob Shortcut Group] |
883 | +Name=bob's shortcut |
884 | +Exec=ls bob |
885 | + |
886 | +[alvin Shortcut Group] |
887 | +Name=alvin's shortcut |
888 | +Exec=ls alvin |
889 | +OnlyShowIn=France |
890 | + |
891 | +[jim Shortcut Group] |
892 | +Name=Jim's shortcut |
893 | +Exec=ls jim |
894 | +NotShowIn=France |
895 | + |
896 | +[touch Shortcut Group] |
897 | +Name=Touch Test |
898 | +Exec=touch test-desktop-shortcuts-touch-test |
899 | +OnlyShowIn=TouchTest |
0.3.3