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