1 /* vi:set et ai sw=2 sts=2 ts=2: */
2 /*-
3 * Copyright (c) 2006-2009 Jannis Pohlmann <jannis@xfce.org>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General
16 * Public License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <locale.h>
26 #include <glib.h>
27 #include <libxfce4util/libxfce4util.h>
28
29 #include <garcon/garcon-environment.h>
30 #include <garcon/garcon-menu-directory.h>
31 #include <garcon/garcon-private.h>
32
33
34
35 /**
36 * SECTION: garcon-menu-directory
37 * @title: GarconMenuDirectory
38 * @short_description: Garcon element for .directory files.
39 * @include: garcon/garcon.h
40 *
41 * Element that represents a .directory file in the menu configurations.
42 * Each menu (except for the root menu) has a #GarconMenuDirectory,
43 * see garcon_menu_get_directory().
44 **/
45
46
47
48 /* Desktop entry keys */
49 #if 0
50 static const gchar *desktop_entry_keys[] =
51 {
52 "Name",
53 "Comment",
54 "Icon",
55 "Categories",
56 "OnlyShowIn",
57 "NotShowIn",
58 "NoDisplay",
59 "Hidden",
60 NULL
61 };
62 #endif
63
64
65
66 /* Property identifiers */
67 enum
68 {
69 PROP_0,
70 PROP_FILE,
71 PROP_NAME,
72 PROP_COMMENT,
73 PROP_NO_DISPLAY,
74 PROP_ICON_NAME,
75 };
76
77
78
79 static void garcon_menu_directory_finalize (GObject *object);
80 static void garcon_menu_directory_get_property (GObject *object,
81 guint prop_id,
82 GValue *value,
83 GParamSpec *pspec);
84 static void garcon_menu_directory_set_property (GObject *object,
85 guint prop_id,
86 const GValue *value,
87 GParamSpec *pspec);
88
89
90
91 struct _GarconMenuDirectoryPrivate
92 {
93 /* Directory file */
94 GFile *file;
95
96 /* Directory name */
97 gchar *name;
98
99 /* Directory description (comment) */
100 gchar *comment;
101
102 /* Icon */
103 gchar *icon_name;
104
105 /* Environments in which the menu should be displayed only */
106 gchar **only_show_in;
107
108 /* Environments in which the menu should be hidden */
109 gchar **not_show_in;
110
111 /* Whether the menu should be ignored completely */
112 guint hidden : 1;
113
114 /* Whether the menu should be hidden */
115 guint no_display : 1;
116 };
117
118
119
120 /* TODO, maybe implement the GarconMenuElement interface */
G_DEFINE_TYPE_WITH_PRIVATE(GarconMenuDirectory,garcon_menu_directory,G_TYPE_OBJECT)121 G_DEFINE_TYPE_WITH_PRIVATE (GarconMenuDirectory, garcon_menu_directory, G_TYPE_OBJECT)
122
123
124
125 static void
126 garcon_menu_directory_class_init (GarconMenuDirectoryClass *klass)
127 {
128 GObjectClass *gobject_class;
129
130 gobject_class = G_OBJECT_CLASS (klass);
131 gobject_class->finalize = garcon_menu_directory_finalize;
132 gobject_class->get_property = garcon_menu_directory_get_property;
133 gobject_class->set_property = garcon_menu_directory_set_property;
134
135 /**
136 * GarconMenuDirectory:filename:
137 *
138 * The @GFile of an %GarconMenuDirectory.
139 **/
140 g_object_class_install_property (gobject_class,
141 PROP_FILE,
142 g_param_spec_object ("file",
143 "File",
144 "File",
145 G_TYPE_FILE,
146 G_PARAM_READWRITE |
147 G_PARAM_STATIC_STRINGS |
148 G_PARAM_CONSTRUCT_ONLY));
149
150 /**
151 * GarconMenuDirectory:name:
152 *
153 * Name of the directory.
154 **/
155 g_object_class_install_property (gobject_class,
156 PROP_NAME,
157 g_param_spec_string ("name",
158 "Name",
159 "Directory name",
160 NULL,
161 G_PARAM_READWRITE |
162 G_PARAM_STATIC_STRINGS));
163
164 /**
165 * GarconMenuDirectory:comment:
166 *
167 * Directory description (comment).
168 **/
169 g_object_class_install_property (gobject_class,
170 PROP_COMMENT,
171 g_param_spec_string ("comment",
172 "Description",
173 "Directory description",
174 NULL,
175 G_PARAM_READWRITE |
176 G_PARAM_STATIC_STRINGS));
177
178 /**
179 * GarconMenuDirectory:icon-name:
180 *
181 * Icon associated with this directory.
182 **/
183 g_object_class_install_property (gobject_class,
184 PROP_ICON_NAME,
185 g_param_spec_string ("icon-name",
186 "Icon",
187 "Directory icon",
188 NULL,
189 G_PARAM_READWRITE |
190 G_PARAM_STATIC_STRINGS));
191
192 /**
193 * GarconMenuDirectory:no-display:
194 *
195 * Whether this menu item is hidden in menus.
196 **/
197 g_object_class_install_property (gobject_class,
198 PROP_NO_DISPLAY,
199 g_param_spec_boolean ("no-display",
200 "No Display",
201 "Visibility state of the related menu",
202 FALSE,
203 G_PARAM_READWRITE |
204 G_PARAM_STATIC_STRINGS));
205
206 }
207
208
209
210 static void
garcon_menu_directory_init(GarconMenuDirectory * directory)211 garcon_menu_directory_init (GarconMenuDirectory *directory)
212 {
213 directory->priv = garcon_menu_directory_get_instance_private (directory);
214 directory->priv->file = NULL;
215 directory->priv->name = NULL;
216 directory->priv->icon_name = NULL;
217 directory->priv->only_show_in = NULL;
218 directory->priv->not_show_in = NULL;
219 directory->priv->hidden = FALSE;
220 directory->priv->no_display = FALSE;
221 }
222
223
224
225 static void
garcon_menu_directory_finalize(GObject * object)226 garcon_menu_directory_finalize (GObject *object)
227 {
228 GarconMenuDirectory *directory = GARCON_MENU_DIRECTORY (object);
229
230 /* Free name */
231 g_free (directory->priv->name);
232
233 /* Free comment */
234 g_free (directory->priv->comment);
235
236 /* Free icon_name */
237 g_free (directory->priv->icon_name);
238
239 /* Free environment lists */
240 g_strfreev (directory->priv->only_show_in);
241 g_strfreev (directory->priv->not_show_in);
242
243 /* Free file */
244 if (directory->priv->file != NULL)
245 g_object_unref (directory->priv->file);
246
247 (*G_OBJECT_CLASS (garcon_menu_directory_parent_class)->finalize) (object);
248 }
249
250
251
252 static void
garcon_menu_directory_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)253 garcon_menu_directory_get_property (GObject *object,
254 guint prop_id,
255 GValue *value,
256 GParamSpec *pspec)
257 {
258 GarconMenuDirectory *directory = GARCON_MENU_DIRECTORY (object);
259
260 switch (prop_id)
261 {
262 case PROP_FILE:
263 g_value_set_object (value, directory->priv->file);
264 break;
265
266 case PROP_NAME:
267 g_value_set_string (value, garcon_menu_directory_get_name (directory));
268 break;
269
270 case PROP_COMMENT:
271 g_value_set_string (value, garcon_menu_directory_get_comment (directory));
272 break;
273
274 case PROP_ICON_NAME:
275 g_value_set_string (value, garcon_menu_directory_get_icon_name (directory));
276 break;
277
278 case PROP_NO_DISPLAY:
279 g_value_set_boolean (value, garcon_menu_directory_get_no_display (directory));
280 break;
281
282 default:
283 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
284 break;
285 }
286 }
287
288
289
290 static void
garcon_menu_directory_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)291 garcon_menu_directory_set_property (GObject *object,
292 guint prop_id,
293 const GValue *value,
294 GParamSpec *pspec)
295 {
296 GarconMenuDirectory *directory = GARCON_MENU_DIRECTORY (object);
297
298 switch (prop_id)
299 {
300 case PROP_FILE:
301 directory->priv->file = g_value_dup_object (value);
302 break;
303
304 case PROP_NAME:
305 garcon_menu_directory_set_name (directory, g_value_get_string (value));
306 break;
307
308 case PROP_COMMENT:
309 garcon_menu_directory_set_comment (directory, g_value_get_string (value));
310 break;
311
312 case PROP_ICON_NAME:
313 garcon_menu_directory_set_icon_name (directory, g_value_get_string (value));
314 break;
315
316 case PROP_NO_DISPLAY:
317 garcon_menu_directory_set_no_display (directory, g_value_get_boolean (value));
318 break;
319
320 default:
321 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
322 break;
323 }
324 }
325
326
327
328 /**
329 * garcon_menu_directory_new: (method)
330 * @file : a #GFile
331 *
332 * Create a new #GarconMenuDirectory for @file. You most likely never
333 * use this, but retrieve the info from garcon_menu_get_directory().
334 *
335 * Returns: a #GarconMenuDirectory.
336 **/
337 GarconMenuDirectory *
garcon_menu_directory_new(GFile * file)338 garcon_menu_directory_new (GFile *file)
339 {
340 GarconMenuDirectory *directory = NULL;
341 XfceRc *rc;
342 const gchar *name;
343 const gchar *comment;
344 const gchar *icon_name;
345 gboolean no_display;
346 gchar *filename;
347
348 g_return_val_if_fail (G_IS_FILE (file), NULL);
349 g_return_val_if_fail (g_file_is_native (file), NULL);
350
351 /* Open the rc file */
352 filename = g_file_get_path (file);
353 rc = xfce_rc_simple_open (filename, TRUE);
354 g_free (filename);
355 if (G_UNLIKELY (rc == NULL))
356 return NULL;
357
358 xfce_rc_set_group (rc, G_KEY_FILE_DESKTOP_GROUP);
359
360 /* Parse name, exec command and icon name */
361 name = xfce_rc_read_entry (rc, G_KEY_FILE_DESKTOP_KEY_NAME, NULL);
362
363 /* If there is no name we must bail out now or segfault later */
364 if (G_UNLIKELY (name == NULL))
365 return NULL;
366
367 comment = xfce_rc_read_entry (rc, G_KEY_FILE_DESKTOP_KEY_COMMENT, NULL);
368 icon_name = xfce_rc_read_entry_untranslated (rc, G_KEY_FILE_DESKTOP_KEY_ICON, NULL);
369 no_display = xfce_rc_read_bool_entry (rc, G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, FALSE);
370
371 /* Allocate a new directory instance */
372 directory = g_object_new (GARCON_TYPE_MENU_DIRECTORY,
373 "file", file,
374 "name", name,
375 "comment", comment,
376 "icon-name", icon_name,
377 "no-display", no_display,
378 NULL);
379
380 /* Set rest of the private data directly */
381 directory->priv->only_show_in = xfce_rc_read_list_entry (rc, G_KEY_FILE_DESKTOP_KEY_ONLY_SHOW_IN, ";");
382 directory->priv->not_show_in = xfce_rc_read_list_entry (rc, G_KEY_FILE_DESKTOP_KEY_NOT_SHOW_IN, ";");
383 directory->priv->hidden = xfce_rc_read_bool_entry (rc, G_KEY_FILE_DESKTOP_KEY_HIDDEN, FALSE);
384
385 /* Cleanup */
386 xfce_rc_close (rc);
387
388 return directory;
389 }
390
391
392
393 /**
394 * garcon_menu_directory_get_file:
395 * @directory: a #GarconMenuDirectory
396 *
397 * Get the #GFile for @directory. The returned object should be
398 * unreffed with g_object_unref() when no longer needed.
399 *
400 * Returns: (transfer full): a #GFile
401 */
402 GFile *
garcon_menu_directory_get_file(GarconMenuDirectory * directory)403 garcon_menu_directory_get_file (GarconMenuDirectory *directory)
404 {
405 g_return_val_if_fail (GARCON_IS_MENU_DIRECTORY (directory), NULL);
406 return g_object_ref (directory->priv->file);
407 }
408
409
410
411 /**
412 * garcon_menu_directory_get_name:
413 * @directory : a #GarconMenuDirectory
414 *
415 * Get the name of @directory.
416 *
417 * Returns: a the name for @directory.
418 */
419 const gchar*
garcon_menu_directory_get_name(GarconMenuDirectory * directory)420 garcon_menu_directory_get_name (GarconMenuDirectory *directory)
421 {
422 g_return_val_if_fail (GARCON_IS_MENU_DIRECTORY (directory), NULL);
423 return directory->priv->name;
424 }
425
426
427
428 /**
429 * garcon_menu_directory_set_name:
430 * @directory : a #GarconMenuDirectory
431 * @name : the new name for @directory.
432 *
433 * Set the name of @directory.
434 */
435 void
garcon_menu_directory_set_name(GarconMenuDirectory * directory,const gchar * name)436 garcon_menu_directory_set_name (GarconMenuDirectory *directory,
437 const gchar *name)
438 {
439 g_return_if_fail (GARCON_IS_MENU_DIRECTORY (directory));
440 g_return_if_fail (g_utf8_validate (name, -1, NULL));
441
442 if (g_strcmp0 (directory->priv->name, name) == 0)
443 return;
444
445 /* Free old name */
446 g_free (directory->priv->name);
447
448 /* Set the new filename */
449 directory->priv->name = g_strdup (name);
450
451 /* Notify listeners */
452 g_object_notify (G_OBJECT (directory), "name");
453 }
454
455
456
457 /**
458 * garcon_menu_directory_get_comment:
459 * @directory : a #GarconMenuDirectory
460 *
461 * Get the comment of @directory.
462 *
463 * Returns: a the description for @directory.
464 */
465 const gchar*
garcon_menu_directory_get_comment(GarconMenuDirectory * directory)466 garcon_menu_directory_get_comment (GarconMenuDirectory *directory)
467 {
468 g_return_val_if_fail (GARCON_IS_MENU_DIRECTORY (directory), NULL);
469 return directory->priv->comment;
470 }
471
472
473
474 /**
475 * garcon_menu_directory_set_comment:
476 * @directory : a #GarconMenuDirectory
477 * @comment : the new description for @directory.
478 *
479 * Set the comment of @directory.
480 */
481 void
garcon_menu_directory_set_comment(GarconMenuDirectory * directory,const gchar * comment)482 garcon_menu_directory_set_comment (GarconMenuDirectory *directory,
483 const gchar *comment)
484 {
485 g_return_if_fail (GARCON_IS_MENU_DIRECTORY (directory));
486 g_return_if_fail (comment == NULL || g_utf8_validate (comment, -1, NULL));
487
488 if (g_strcmp0 (directory->priv->comment, comment) == 0)
489 return;
490
491 /* Free old name */
492 g_free (directory->priv->comment);
493
494 /* Set the new filename */
495 directory->priv->comment = g_strdup (comment);
496
497 /* Notify listeners */
498 g_object_notify (G_OBJECT (directory), "comment");
499 }
500
501
502
503 /**
504 * garcon_menu_directory_get_icon_name:
505 * @directory : a #GarconMenuDirectory
506 *
507 * Get the icon name of @directory.
508 *
509 * Returns: a the icon-name key for @directory.
510 */
511 const gchar*
garcon_menu_directory_get_icon_name(GarconMenuDirectory * directory)512 garcon_menu_directory_get_icon_name (GarconMenuDirectory *directory)
513 {
514 g_return_val_if_fail (GARCON_IS_MENU_DIRECTORY (directory), NULL);
515 return directory->priv->icon_name;
516 }
517
518
519
520 /**
521 * garcon_menu_directory_set_icon_name:
522 * @directory : a #GarconMenuDirectory
523 * @icon_name : the new icon name for @directory.
524 *
525 * Set the icon name of @directory.
526 */
527 void
garcon_menu_directory_set_icon_name(GarconMenuDirectory * directory,const gchar * icon_name)528 garcon_menu_directory_set_icon_name (GarconMenuDirectory *directory,
529 const gchar *icon_name)
530 {
531 g_return_if_fail (GARCON_IS_MENU_DIRECTORY (directory));
532
533 if (g_strcmp0 (directory->priv->icon_name, icon_name) == 0)
534 return;
535
536 /* Free old name */
537 g_free (directory->priv->icon_name);
538
539 /* Set the new filename */
540 directory->priv->icon_name = g_strdup (icon_name);
541
542 /* Notify listeners */
543 g_object_notify (G_OBJECT (directory), "icon-name");
544 }
545
546
547
548 /**
549 * garcon_menu_directory_get_no_display:
550 * @directory : a #GarconMenuDirectory
551 *
552 * Whether @directory should be displayed.
553 * For applications you want to call garcon_menu_directory_get_visible().
554 *
555 * Returns: a the no-display key for @directory.
556 */
557 gboolean
garcon_menu_directory_get_no_display(GarconMenuDirectory * directory)558 garcon_menu_directory_get_no_display (GarconMenuDirectory *directory)
559 {
560 g_return_val_if_fail (GARCON_IS_MENU_DIRECTORY (directory), FALSE);
561 return directory->priv->no_display;
562 }
563
564
565
566 /**
567 * garcon_menu_directory_set_no_display:
568 * @directory : a #GarconMenuDirectory
569 * @no_display : whether @directory should be displayed.
570 *
571 * Set the NoDisplay key of @directory.
572 */
573 void
garcon_menu_directory_set_no_display(GarconMenuDirectory * directory,gboolean no_display)574 garcon_menu_directory_set_no_display (GarconMenuDirectory *directory,
575 gboolean no_display)
576 {
577 g_return_if_fail (GARCON_IS_MENU_DIRECTORY (directory));
578
579 /* Abort if old and new value are equal */
580 if (directory->priv->no_display == no_display)
581 return;
582
583 /* Assign new value */
584 directory->priv->no_display = no_display;
585
586 /* Notify listeners */
587 g_object_notify (G_OBJECT (directory), "no-display");
588 }
589
590
591
592 /**
593 * garcon_menu_directory_get_hidden:
594 * @directory : a #GarconMenuDirectory
595 *
596 * Whether @directory should be hidden.
597 * For applications you want to call garcon_menu_directory_get_visible().
598 *
599 * Returns: a the hidden key for @directory.
600 */
601 gboolean
garcon_menu_directory_get_hidden(GarconMenuDirectory * directory)602 garcon_menu_directory_get_hidden (GarconMenuDirectory *directory)
603 {
604 g_return_val_if_fail (GARCON_IS_MENU_DIRECTORY (directory), FALSE);
605 return directory->priv->hidden;
606 }
607
608
609
610 /**
611 * garcon_menu_directory_get_show_in_environment:
612 * @directory : a #GarconMenuDirectory
613 *
614 * Whether @directory is visible in the current environment
615 * which has been set by garcon_set_environment().
616 * For applications you want to call garcon_menu_directory_get_visible().
617 *
618 * Returns: %TRUE is visible in environment, else %FALSE.
619 */
620 gboolean
garcon_menu_directory_get_show_in_environment(GarconMenuDirectory * directory)621 garcon_menu_directory_get_show_in_environment (GarconMenuDirectory *directory)
622 {
623 const gchar *env;
624 guint i;
625 gboolean show = TRUE;
626
627 g_return_val_if_fail (GARCON_IS_MENU_DIRECTORY (directory), FALSE);
628
629 /* Determine current environment */
630 env = garcon_get_environment ();
631
632 /* If no environment has been set, the menu is displayed no matter what
633 * OnlyShowIn or NotShowIn contain */
634 if (G_UNLIKELY (env == NULL))
635 return TRUE;
636
637 /* According to the spec there is either a OnlyShowIn or a NotShowIn list */
638 if (G_UNLIKELY (directory->priv->only_show_in != NULL))
639 {
640 /* Check if your environemnt is in OnlyShowIn list */
641 for (i = 0, show = FALSE; !show && directory->priv->only_show_in[i] != NULL; i++)
642 if (g_strcmp0 (directory->priv->only_show_in[i], env) == 0)
643 show = TRUE;
644 }
645 else if (G_UNLIKELY (directory->priv->not_show_in != NULL))
646 {
647 /* Check if your environemnt is in NotShowIn list */
648 for (i = 0, show = TRUE; show && directory->priv->not_show_in[i] != NULL; i++)
649 if (g_strcmp0 (directory->priv->not_show_in[i], env) == 0)
650 show = FALSE;
651 }
652
653 return show;
654 }
655
656
657
658 /**
659 * garcon_menu_directory_get_visible:
660 * @directory : a #GarconMenuDirectory
661 *
662 * Check which runs the following checks:
663 * garcon_menu_directory_get_show_in_environment(),
664 * garcon_menu_directory_get_hidden() and
665 * garcon_menu_directory_get_no_display().
666 *
667 * Returns: if visible %TRUE, else %FALSE.
668 **/
669 gboolean
garcon_menu_directory_get_visible(GarconMenuDirectory * directory)670 garcon_menu_directory_get_visible (GarconMenuDirectory *directory)
671 {
672 g_return_val_if_fail (GARCON_IS_MENU_DIRECTORY (directory), FALSE);
673
674 if (!garcon_menu_directory_get_show_in_environment (directory))
675 return FALSE;
676 else if (garcon_menu_directory_get_hidden (directory))
677 return FALSE;
678 else if (garcon_menu_directory_get_no_display (directory))
679 return FALSE;
680
681 return TRUE;
682 }
683
684
685 /**
686 * garcon_menu_directory_equal:
687 * @directory : a #GarconMenuDirectory
688 * @other : a #GarconMenuDirectory
689 *
690 * Checks if both directories point to the same file.
691 *
692 * Returns: if files are equal %TRUE, else %FALSE.
693 **/
694 gboolean
garcon_menu_directory_equal(GarconMenuDirectory * directory,GarconMenuDirectory * other)695 garcon_menu_directory_equal (GarconMenuDirectory *directory,
696 GarconMenuDirectory *other)
697 {
698 g_return_val_if_fail (GARCON_IS_MENU_DIRECTORY (directory), FALSE);
699 g_return_val_if_fail (GARCON_IS_MENU_DIRECTORY (other), FALSE);
700 return g_file_equal (directory->priv->file, other->priv->file);
701 }
702