1 /* vi:set et ai sw=2 sts=2 ts=2: */
2 /*-
3  * Copyright (c) 2006-2010 Jannis Pohlmann <jannis@xfce.org>
4  * Copyright (c) 2009-2010 Nick Schermer <nick@xfce.org>
5  * Copyright (c) 2015      Danila Poyarkov <dannotemail@gmail.com>
6  * Copyright (c) 2017      Gregor Santner <gsantner@mailbox.org>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General
19  * Public License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 
28 #include <gio/gio.h>
29 #include <libxfce4util/libxfce4util.h>
30 
31 #include <garcon/garcon-environment.h>
32 #include <garcon/garcon-menu-element.h>
33 #include <garcon/garcon-menu-item.h>
34 #include <garcon/garcon-menu-item-action.h>
35 #include <garcon/garcon-private.h>
36 
37 
38 
39 /* Property identifiers */
40 enum
41 {
42   PROP_0,
43   PROP_FILE,
44   PROP_DESKTOP_ID,
45   PROP_REQUIRES_TERMINAL,
46   PROP_NO_DISPLAY,
47   PROP_STARTUP_NOTIFICATION,
48   PROP_NAME,
49   PROP_GENERIC_NAME,
50   PROP_COMMENT,
51   PROP_ICON_NAME,
52   PROP_COMMAND,
53   PROP_TRY_EXEC,
54   PROP_HIDDEN,
55   PROP_PATH,
56 };
57 
58 /* Signal identifiers */
59 enum
60 {
61   CHANGED,
62   LAST_SIGNAL,
63 };
64 
65 
66 
67 static void         garcon_menu_item_element_init                    (GarconMenuElementIface *iface);
68 static void         garcon_menu_item_finalize                        (GObject                *object);
69 static void         garcon_menu_item_get_property                    (GObject                *object,
70                                                                       guint                   prop_id,
71                                                                       GValue                 *value,
72                                                                       GParamSpec             *pspec);
73 static void         garcon_menu_item_set_property                    (GObject                *object,
74                                                                       guint                   prop_id,
75                                                                       const GValue           *value,
76                                                                       GParamSpec             *pspec);
77 static const gchar *garcon_menu_item_get_element_name                (GarconMenuElement      *element);
78 static const gchar *garcon_menu_item_get_element_comment             (GarconMenuElement      *element);
79 static const gchar *garcon_menu_item_get_element_icon_name           (GarconMenuElement      *element);
80 static gboolean     garcon_menu_item_get_element_visible             (GarconMenuElement      *element);
81 static gboolean     garcon_menu_item_get_element_show_in_environment (GarconMenuElement      *element);
82 static gboolean     garcon_menu_item_get_element_no_display          (GarconMenuElement      *element);
83 static gboolean     garcon_menu_item_get_element_equal               (GarconMenuElement      *element,
84                                                                       GarconMenuElement      *other);
85 static gboolean     garcon_menu_item_lists_equal                     (GList                  *list1,
86                                                                       GList                  *list2);
87 
88 
89 
90 static guint item_signals[LAST_SIGNAL];
91 
92 
93 
94 struct _GarconMenuItemPrivate
95 {
96   /* Source file of the menu item */
97   GFile      *file;
98 
99   /* Desktop file id */
100   gchar      *desktop_id;
101 
102   /* List of categories */
103   GList      *categories;
104 
105   /* List of keywords */
106   GList      *keywords;
107 
108   /* Whether this application requires a terminal to be started in */
109   guint       requires_terminal : 1;
110 
111   /* Whether this menu item should be hidden */
112   guint       no_display : 1;
113 
114   /* Whether this application supports startup notification */
115   guint       supports_startup_notification : 1;
116 
117   /* Name to be displayed for the menu item */
118   gchar      *name;
119 
120   /* Generic name of the menu item */
121   gchar      *generic_name;
122 
123   /* Comment/description of the item */
124   gchar      *comment;
125 
126   /* Command to be executed when the menu item is clicked */
127   gchar      *command;
128 
129   /* TryExec value */
130   gchar      *try_exec;
131 
132   /* Menu item icon name */
133   gchar      *icon_name;
134 
135   /* Environments in which the menu item should be displayed only */
136   gchar     **only_show_in;
137 
138   /* Environments in which the menu item should be hidden */
139   gchar     **not_show_in;
140 
141   /* Working directory */
142   gchar      *path;
143 
144   /* List of application actions of type GarconMenuItemAction */
145   GList      *actions;
146 
147   /* Hidden value */
148   guint       hidden : 1;
149 
150   /* Counter keeping the number of menus which use this item. This works
151    * like a reference counter and should be increased / decreased by GarconMenu
152    * items whenever the item is added to or removed from the menu. */
153   guint       num_allocated;
154 };
155 
156 
157 
G_DEFINE_TYPE_WITH_CODE(GarconMenuItem,garcon_menu_item,G_TYPE_OBJECT,G_ADD_PRIVATE (GarconMenuItem)G_IMPLEMENT_INTERFACE (GARCON_TYPE_MENU_ELEMENT,garcon_menu_item_element_init))158 G_DEFINE_TYPE_WITH_CODE (GarconMenuItem, garcon_menu_item, G_TYPE_OBJECT,
159                          G_ADD_PRIVATE (GarconMenuItem)
160                          G_IMPLEMENT_INTERFACE (GARCON_TYPE_MENU_ELEMENT,
161                                                 garcon_menu_item_element_init))
162 
163 
164 
165 static void
166 garcon_menu_item_class_init (GarconMenuItemClass *klass)
167 {
168   GObjectClass *gobject_class;
169 
170   gobject_class = G_OBJECT_CLASS (klass);
171   gobject_class->finalize = garcon_menu_item_finalize;
172   gobject_class->get_property = garcon_menu_item_get_property;
173   gobject_class->set_property = garcon_menu_item_set_property;
174 
175   /**
176    * GarconMenuItem:file:
177    *
178    * The #GFile from which the %GarconMenuItem was loaded.
179    **/
180   g_object_class_install_property (gobject_class,
181                                    PROP_FILE,
182                                    g_param_spec_object ("file",
183                                                         "file",
184                                                         "file",
185                                                         G_TYPE_FILE,
186                                                         G_PARAM_READWRITE |
187                                                         G_PARAM_STATIC_STRINGS |
188                                                         G_PARAM_CONSTRUCT_ONLY));
189 
190   /**
191    * GarconMenuItem:desktop-id:
192    *
193    * The desktop-file id of this application.
194    **/
195   g_object_class_install_property (gobject_class,
196                                    PROP_DESKTOP_ID,
197                                    g_param_spec_string ("desktop-id",
198                                                         "Desktop-File Id",
199                                                         "Desktop-File Id of the application",
200                                                         NULL,
201                                                         G_PARAM_READWRITE |
202                                                         G_PARAM_STATIC_STRINGS));
203 
204   /**
205    * GarconMenuItem:requires-terminal:
206    *
207    * Whether this application requires a terinal to be started in.
208    **/
209   g_object_class_install_property (gobject_class,
210                                    PROP_REQUIRES_TERMINAL,
211                                    g_param_spec_boolean ("requires-terminal",
212                                                          "Requires a terminal",
213                                                          "Whether this application requires a terminal",
214                                                          FALSE,
215                                                          G_PARAM_READWRITE |
216                                                          G_PARAM_STATIC_STRINGS));
217 
218   /**
219    * GarconMenuItem:no-display:
220    *
221    * Whether this menu item is hidden in menus.
222    **/
223   g_object_class_install_property (gobject_class,
224                                    PROP_NO_DISPLAY,
225                                    g_param_spec_boolean ("no-display",
226                                                          "No Display",
227                                                          "Visibility state of the menu item",
228                                                          FALSE,
229                                                          G_PARAM_READWRITE |
230                                                          G_PARAM_STATIC_STRINGS));
231 
232   /**
233    * GarconMenuItem:startup-notification:
234    *
235    * Whether this application supports startup notification.
236    **/
237   g_object_class_install_property (gobject_class,
238                                    PROP_STARTUP_NOTIFICATION,
239                                    g_param_spec_boolean ("supports-startup-notification",
240                                                          "Startup notification",
241                                                          "Startup notification support",
242                                                          FALSE,
243                                                          G_PARAM_READWRITE |
244                                                          G_PARAM_STATIC_STRINGS));
245 
246   /**
247    * GarconMenuItem:name:
248    *
249    * Name of the application (will be displayed in menus etc.).
250    **/
251   g_object_class_install_property (gobject_class,
252                                    PROP_NAME,
253                                    g_param_spec_string ("name",
254                                                         "Name",
255                                                         "Name of the application",
256                                                         NULL,
257                                                         G_PARAM_READWRITE |
258                                                         G_PARAM_STATIC_STRINGS));
259 
260   /**
261    * GarconMenuItem:generic-name:
262    *
263    * GenericName of the application (will be displayed in menus etc.).
264    **/
265   g_object_class_install_property (gobject_class,
266                                    PROP_GENERIC_NAME,
267                                    g_param_spec_string ("generic-name",
268                                                         "Generic name",
269                                                         "Generic name of the application",
270                                                         NULL,
271                                                         G_PARAM_READWRITE |
272                                                         G_PARAM_STATIC_STRINGS));
273 
274   /**
275    * GarconMenuItem:comment:
276    *
277    * Comment/description for the application. To be displayed e.g. in tooltips of
278    * GtkMenuItems.
279    **/
280   g_object_class_install_property (gobject_class,
281                                    PROP_COMMENT,
282                                    g_param_spec_string ("comment",
283                                                         "Comment",
284                                                         "Comment/description for the application",
285                                                         NULL,
286                                                         G_PARAM_READWRITE |
287                                                         G_PARAM_STATIC_STRINGS));
288 
289   /**
290    * GarconMenuItem:command:
291    *
292    * Command to be executed when the menu item is clicked.
293    **/
294   g_object_class_install_property (gobject_class,
295                                    PROP_COMMAND,
296                                    g_param_spec_string ("command",
297                                                         "Command",
298                                                         "Application command",
299                                                         NULL,
300                                                         G_PARAM_READWRITE |
301                                                         G_PARAM_STATIC_STRINGS));
302 
303   /**
304    * GarconMenuItem:try-exec:
305    *
306    * Path to an executable file on disk used to determine if the program
307    * is actually installed. If the path is not an absolute path, the file
308    * is looked up in the $PATH environment variable. If the file is not
309    * present or if it is not executable, the entry may be ignored (not be
310    * used in menus, for example).
311    **/
312   g_object_class_install_property (gobject_class,
313                                    PROP_TRY_EXEC,
314                                    g_param_spec_string ("try-exec",
315                                                         "TryExec",
316                                                         "Command to check if application is installed",
317                                                         NULL,
318                                                         G_PARAM_READWRITE |
319                                                         G_PARAM_STATIC_STRINGS));
320 
321   /**
322    * GarconMenuItem:icon-name:
323    *
324    * Name of the icon to be displayed for this menu item.
325    **/
326   g_object_class_install_property (gobject_class,
327                                    PROP_ICON_NAME,
328                                    g_param_spec_string ("icon-name",
329                                                         "Icon name",
330                                                         "Name of the application icon",
331                                                         NULL,
332                                                         G_PARAM_READWRITE |
333                                                         G_PARAM_STATIC_STRINGS));
334 
335  /**
336    * GarconMenuItem:hidden:
337    *
338    * It means the user deleted (at his level) something that was present
339    * (at an upper level, e.g. in the system dirs). It's strictly equivalent
340    * to the .desktop file not existing at all, as far as that user is concerned.
341    **/
342   g_object_class_install_property (gobject_class,
343                                    PROP_HIDDEN,
344                                    g_param_spec_boolean ("hidden",
345                                                          "Hidden",
346                                                          "Whether the application has been deleted",
347                                                           FALSE,
348                                                           G_PARAM_READWRITE |
349                                                           G_PARAM_STATIC_STRINGS));
350 
351  /**
352    * GarconMenuItem:path:
353    *
354    * Working directory the application should be started in.
355    **/
356   g_object_class_install_property (gobject_class,
357                                    PROP_PATH,
358                                    g_param_spec_string ("path",
359                                                         "Path",
360                                                         "Working directory path",
361                                                         NULL,
362                                                         G_PARAM_READWRITE |
363                                                         G_PARAM_STATIC_STRINGS));
364 
365   /**
366    * GarconMenuItem::changed:
367    * @item : a #GarconMenuItem.
368    *
369    * Emitted when #GarconMenuItem has been reloaded.
370    **/
371   item_signals[CHANGED] =
372     g_signal_new (g_intern_static_string ("changed"),
373                   G_TYPE_FROM_CLASS (klass),
374                   G_SIGNAL_RUN_FIRST,
375                   G_STRUCT_OFFSET (GarconMenuItemClass, changed),
376                   NULL, NULL,
377                   g_cclosure_marshal_VOID__VOID,
378                   G_TYPE_NONE, 0);
379 }
380 
381 
382 
383 static void
garcon_menu_item_element_init(GarconMenuElementIface * iface)384 garcon_menu_item_element_init (GarconMenuElementIface *iface)
385 {
386   iface->get_name = garcon_menu_item_get_element_name;
387   iface->get_comment = garcon_menu_item_get_element_comment;
388   iface->get_icon_name = garcon_menu_item_get_element_icon_name;
389   iface->get_visible = garcon_menu_item_get_element_visible;
390   iface->get_show_in_environment = garcon_menu_item_get_element_show_in_environment;
391   iface->get_no_display = garcon_menu_item_get_element_no_display;
392   iface->equal = garcon_menu_item_get_element_equal;
393 }
394 
395 
396 
397 static void
garcon_menu_item_init(GarconMenuItem * item)398 garcon_menu_item_init (GarconMenuItem *item)
399 {
400   item->priv = garcon_menu_item_get_instance_private (item);
401 }
402 
403 
404 
405 static void
garcon_menu_item_finalize(GObject * object)406 garcon_menu_item_finalize (GObject *object)
407 {
408   GarconMenuItem *item = GARCON_MENU_ITEM (object);
409 
410   g_free (item->priv->desktop_id);
411   g_free (item->priv->name);
412   g_free (item->priv->generic_name);
413   g_free (item->priv->comment);
414   g_free (item->priv->command);
415   g_free (item->priv->try_exec);
416   g_free (item->priv->icon_name);
417   g_free (item->priv->path);
418 
419   g_strfreev (item->priv->only_show_in);
420   g_strfreev (item->priv->not_show_in);
421 
422   _garcon_g_list_free_full (item->priv->categories, g_free);
423   _garcon_g_list_free_full (item->priv->keywords, g_free);
424   _garcon_g_list_free_full (item->priv->actions, garcon_menu_item_action_unref);
425 
426   if (item->priv->file != NULL)
427     g_object_unref (G_OBJECT (item->priv->file));
428 
429   (*G_OBJECT_CLASS (garcon_menu_item_parent_class)->finalize) (object);
430 }
431 
432 
433 
434 static void
garcon_menu_item_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)435 garcon_menu_item_get_property (GObject    *object,
436                                guint       prop_id,
437                                GValue     *value,
438                                GParamSpec *pspec)
439 {
440   GarconMenuItem *item = GARCON_MENU_ITEM (object);
441 
442   switch (prop_id)
443     {
444     case PROP_FILE:
445       g_value_set_object (value, item->priv->file);
446       break;
447 
448     case PROP_DESKTOP_ID:
449       g_value_set_string (value, garcon_menu_item_get_desktop_id (item));
450       break;
451 
452     case PROP_COMMENT:
453       g_value_set_string (value, garcon_menu_item_get_comment (item));
454       break;
455 
456     case PROP_REQUIRES_TERMINAL:
457       g_value_set_boolean (value, garcon_menu_item_requires_terminal (item));
458       break;
459 
460     case PROP_NO_DISPLAY:
461       g_value_set_boolean (value, garcon_menu_item_get_no_display (item));
462       break;
463 
464     case PROP_STARTUP_NOTIFICATION:
465       g_value_set_boolean (value, garcon_menu_item_supports_startup_notification (item));
466       break;
467 
468     case PROP_NAME:
469       g_value_set_string (value, garcon_menu_item_get_name (item));
470       break;
471 
472     case PROP_GENERIC_NAME:
473       g_value_set_string (value, garcon_menu_item_get_generic_name (item));
474       break;
475 
476     case PROP_COMMAND:
477       g_value_set_string (value, garcon_menu_item_get_command (item));
478       break;
479 
480     case PROP_ICON_NAME:
481       g_value_set_string (value, garcon_menu_item_get_icon_name (item));
482       break;
483 
484     case PROP_TRY_EXEC:
485       g_value_set_string (value, garcon_menu_item_get_try_exec (item));
486       break;
487 
488     case PROP_HIDDEN:
489       g_value_set_boolean (value, garcon_menu_item_get_hidden (item));
490       break;
491 
492     case PROP_PATH:
493       g_value_set_string (value, garcon_menu_item_get_path (item));
494       break;
495 
496     default:
497       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
498       break;
499     }
500 }
501 
502 
503 
504 static void
garcon_menu_item_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)505 garcon_menu_item_set_property (GObject      *object,
506                                guint         prop_id,
507                                const GValue *value,
508                                GParamSpec   *pspec)
509 {
510   GarconMenuItem *item = GARCON_MENU_ITEM (object);
511 
512   switch (prop_id)
513     {
514     case PROP_FILE:
515       item->priv->file = g_value_dup_object (value);
516       break;
517 
518     case PROP_DESKTOP_ID:
519       garcon_menu_item_set_desktop_id (item, g_value_get_string (value));
520       break;
521 
522     case PROP_REQUIRES_TERMINAL:
523       garcon_menu_item_set_requires_terminal (item, g_value_get_boolean (value));
524       break;
525 
526     case PROP_NO_DISPLAY:
527       garcon_menu_item_set_no_display (item, g_value_get_boolean (value));
528       break;
529 
530     case PROP_STARTUP_NOTIFICATION:
531       garcon_menu_item_set_supports_startup_notification (item, g_value_get_boolean (value));
532       break;
533 
534     case PROP_NAME:
535       garcon_menu_item_set_name (item, g_value_get_string (value));
536       break;
537 
538     case PROP_GENERIC_NAME:
539       garcon_menu_item_set_generic_name (item, g_value_get_string (value));
540       break;
541 
542     case PROP_COMMENT:
543       garcon_menu_item_set_comment (item, g_value_get_string (value));
544       break;
545 
546     case PROP_COMMAND:
547       garcon_menu_item_set_command (item, g_value_get_string (value));
548       break;
549 
550     case PROP_TRY_EXEC:
551       garcon_menu_item_set_try_exec (item, g_value_get_string (value));
552       break;
553 
554     case PROP_ICON_NAME:
555       garcon_menu_item_set_icon_name (item, g_value_get_string (value));
556       break;
557 
558     case PROP_HIDDEN:
559       garcon_menu_item_set_hidden (item, g_value_get_boolean (value));
560       break;
561 
562     case PROP_PATH:
563       garcon_menu_item_set_path (item, g_value_get_string (value));
564       break;
565 
566     default:
567       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
568       break;
569     }
570 }
571 
572 
573 
574 static gboolean
garcon_menu_item_get_element_visible(GarconMenuElement * element)575 garcon_menu_item_get_element_visible (GarconMenuElement *element)
576 {
577   GarconMenuItem  *item;
578   const gchar     *try_exec;
579   gchar          **mt;
580   gboolean         result = TRUE;
581   gchar           *command;
582 
583   g_return_val_if_fail (GARCON_IS_MENU_ITEM (element), FALSE);
584 
585   item = GARCON_MENU_ITEM (element);
586 
587   if (garcon_menu_item_get_hidden (item)
588       || garcon_menu_item_get_no_display (item)
589       || !garcon_menu_item_get_show_in_environment (item))
590     return FALSE;
591 
592   /* Check the TryExec field */
593   try_exec = garcon_menu_item_get_try_exec (item);
594   if (try_exec != NULL && g_shell_parse_argv (try_exec, NULL, &mt, NULL))
595     {
596       /* Check if we have an absolute path to an existing file */
597       result = g_file_test (mt[0], G_FILE_TEST_EXISTS);
598 
599       /* Else, we may have a program in $PATH */
600       if (!result)
601         {
602           command = g_find_program_in_path (mt[0]);
603           result = (command != NULL);
604           g_free (command);
605         }
606 
607       /* Cleanup */
608       g_strfreev (mt);
609     }
610 
611   return result;
612 }
613 
614 
615 
616 static gboolean
garcon_menu_item_get_element_show_in_environment(GarconMenuElement * element)617 garcon_menu_item_get_element_show_in_environment (GarconMenuElement *element)
618 {
619   g_return_val_if_fail (GARCON_IS_MENU_ITEM (element), FALSE);
620   return garcon_menu_item_get_show_in_environment (GARCON_MENU_ITEM (element));
621 }
622 
623 
624 
625 static gboolean
garcon_menu_item_get_element_no_display(GarconMenuElement * element)626 garcon_menu_item_get_element_no_display (GarconMenuElement *element)
627 {
628   g_return_val_if_fail (GARCON_IS_MENU_ITEM (element), FALSE);
629   return garcon_menu_item_get_no_display (GARCON_MENU_ITEM (element));
630 }
631 
632 
633 
634 static gboolean
garcon_menu_item_get_element_equal(GarconMenuElement * element,GarconMenuElement * other)635 garcon_menu_item_get_element_equal (GarconMenuElement *element,
636                                     GarconMenuElement *other)
637 {
638   g_return_val_if_fail (GARCON_IS_MENU_ITEM (element), FALSE);
639   g_return_val_if_fail (GARCON_IS_MENU_ITEM (other), FALSE);
640 
641   return g_file_equal (GARCON_MENU_ITEM (element)->priv->file,
642                        GARCON_MENU_ITEM (other)->priv->file);
643 }
644 
645 
646 
647 static const gchar*
garcon_menu_item_get_element_name(GarconMenuElement * element)648 garcon_menu_item_get_element_name (GarconMenuElement *element)
649 {
650   g_return_val_if_fail (GARCON_IS_MENU_ITEM (element), NULL);
651   return GARCON_MENU_ITEM (element)->priv->name;
652 }
653 
654 
655 
656 static const gchar*
garcon_menu_item_get_element_comment(GarconMenuElement * element)657 garcon_menu_item_get_element_comment (GarconMenuElement *element)
658 {
659   g_return_val_if_fail (GARCON_IS_MENU_ITEM (element), NULL);
660   return GARCON_MENU_ITEM (element)->priv->comment;
661 }
662 
663 
664 
665 static const gchar*
garcon_menu_item_get_element_icon_name(GarconMenuElement * element)666 garcon_menu_item_get_element_icon_name (GarconMenuElement *element)
667 {
668   g_return_val_if_fail (GARCON_IS_MENU_ITEM (element), NULL);
669   return GARCON_MENU_ITEM (element)->priv->icon_name;
670 }
671 
672 
673 
674 static gboolean
garcon_menu_item_lists_equal(GList * list1,GList * list2)675 garcon_menu_item_lists_equal (GList *list1,
676                               GList *list2)
677 {
678   gboolean  element_missing = FALSE;
679   GList    *lp;
680 
681   if (g_list_length (list1) != g_list_length (list2))
682     return FALSE;
683 
684   for (lp = list1; !element_missing && lp != NULL; lp = lp->next)
685     {
686       if (g_list_find_custom (list2, lp->data, (GCompareFunc) g_strcmp0) == NULL)
687         element_missing = TRUE;
688     }
689 
690   return !element_missing;
691 }
692 
693 
694 
695 static gchar *
garcon_menu_item_url_exec(XfceRc * rc)696 garcon_menu_item_url_exec (XfceRc *rc)
697 {
698   const gchar *url;
699   gchar       *url_exec = NULL;
700 
701   /* Support Type=Link items */
702   url = xfce_rc_read_entry_untranslated (rc, G_KEY_FILE_DESKTOP_KEY_URL, NULL);
703   if (url != NULL)
704     url_exec = g_strdup_printf ("exo-open '%s'", url);
705 
706   return url_exec;
707 }
708 
709 
710 /**
711  * garcon_menu_item_new: (constructor)
712  * @file: a #GFile
713  *
714  * Returns (transfer full): a new #GarconMenuItem
715  */
716 GarconMenuItem *
garcon_menu_item_new(GFile * file)717 garcon_menu_item_new (GFile *file)
718 {
719   GarconMenuItem       *item = NULL;
720   GarconMenuItemAction *action = NULL;
721   XfceRc               *rc;
722   GList                *categories = NULL;
723   GList                *keywords = NULL;
724   gchar                *filename;
725   gboolean              terminal;
726   gboolean              no_display;
727   gboolean              startup_notify;
728   gboolean              hidden;
729   const gchar          *path;
730   const gchar          *name;
731   const gchar          *generic_name;
732   const gchar          *comment;
733   const gchar          *exec;
734   const gchar          *try_exec;
735   const gchar          *icon;
736   gchar                *action_group;
737   gchar               **mt;
738   gchar               **str_list;
739   gchar                *url_exec = NULL;
740 
741   g_return_val_if_fail (G_IS_FILE (file), NULL);
742   g_return_val_if_fail (g_file_is_native (file), NULL);
743 
744   /* Open the rc file */
745   filename = g_file_get_path (file);
746   rc = xfce_rc_simple_open (filename, TRUE);
747   g_free (filename);
748   if (G_UNLIKELY (rc == NULL))
749     return NULL;
750 
751   xfce_rc_set_group (rc, G_KEY_FILE_DESKTOP_GROUP);
752 
753   /* Parse name and exec command */
754   name = xfce_rc_read_entry (rc, G_KEY_FILE_DESKTOP_KEY_NAME, NULL);
755   exec = xfce_rc_read_entry_untranslated (rc, G_KEY_FILE_DESKTOP_KEY_EXEC, NULL);
756 
757   /* Support Type=Link items */
758   if (G_UNLIKELY (exec == NULL))
759     exec = url_exec = garcon_menu_item_url_exec (rc);
760 
761   /* Validate Name and Exec fields */
762   if (G_LIKELY (exec != NULL && name != NULL))
763     {
764       /* Determine other application properties */
765       generic_name = xfce_rc_read_entry (rc, G_KEY_FILE_DESKTOP_KEY_GENERIC_NAME, NULL);
766       comment = xfce_rc_read_entry (rc, G_KEY_FILE_DESKTOP_KEY_COMMENT, NULL);
767       try_exec = xfce_rc_read_entry_untranslated (rc, G_KEY_FILE_DESKTOP_KEY_TRY_EXEC, NULL);
768       icon = xfce_rc_read_entry_untranslated (rc, G_KEY_FILE_DESKTOP_KEY_ICON, NULL);
769       path = xfce_rc_read_entry_untranslated (rc, G_KEY_FILE_DESKTOP_KEY_PATH, NULL);
770       terminal = xfce_rc_read_bool_entry (rc, G_KEY_FILE_DESKTOP_KEY_TERMINAL, FALSE);
771       no_display = xfce_rc_read_bool_entry (rc, G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, FALSE);
772       startup_notify = xfce_rc_read_bool_entry (rc, G_KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY, FALSE)
773                        || xfce_rc_read_bool_entry (rc, "X-KDE-StartupNotify", FALSE);
774       hidden = xfce_rc_read_bool_entry (rc, G_KEY_FILE_DESKTOP_KEY_HIDDEN, FALSE);
775 
776       /* Allocate a new menu item instance */
777       item = g_object_new (GARCON_TYPE_MENU_ITEM,
778                            "file", file,
779                            "command", exec,
780                            "try-exec", try_exec,
781                            "name", name,
782                            "generic-name", generic_name,
783                            "comment", comment,
784                            "icon-name", icon,
785                            "requires-terminal", terminal,
786                            "no-display", no_display,
787                            "supports-startup-notification", startup_notify,
788                            "path", path,
789                            "hidden", hidden,
790                            NULL);
791 
792       /* Determine the categories this application should be shown in */
793       str_list = xfce_rc_read_list_entry (rc, G_KEY_FILE_DESKTOP_KEY_CATEGORIES, ";");
794       if (G_LIKELY (str_list != NULL))
795         {
796           for (mt = str_list; *mt != NULL; ++mt)
797             {
798               /* Try to steal the values */
799               if (**mt != '\0')
800                 categories = g_list_prepend (categories, *mt);
801               else
802                 g_free (*mt);
803             }
804 
805           /* Cleanup */
806           g_free (str_list);
807 
808           /* Assign categories list to the menu item */
809           garcon_menu_item_set_categories (item, categories);
810         }
811 
812       /* Determine the keywords this application should be shown in */
813       str_list = xfce_rc_read_list_entry (rc, G_KEY_FILE_DESKTOP_KEY_KEYWORDS, ";");
814       if (G_LIKELY (str_list != NULL))
815         {
816           for (mt = str_list; *mt != NULL; ++mt)
817             {
818               /* Try to steal the values */
819               if (**mt != '\0')
820                 keywords = g_list_prepend (keywords, *mt);
821               else
822                 g_free (*mt);
823             }
824 
825           /* Cleanup */
826           g_free (str_list);
827 
828           /* Assign keywords list to the menu item */
829           garcon_menu_item_set_keywords (item, keywords);
830         }
831 
832       /* Set the rest of the private data directly */
833       item->priv->only_show_in = xfce_rc_read_list_entry (rc, G_KEY_FILE_DESKTOP_KEY_ONLY_SHOW_IN, ";");
834       item->priv->not_show_in = xfce_rc_read_list_entry (rc, G_KEY_FILE_DESKTOP_KEY_NOT_SHOW_IN, ";");
835 
836       /* Determine this application actions */
837       str_list = xfce_rc_read_list_entry (rc, G_KEY_FILE_DESKTOP_KEY_ACTIONS, ";");
838       if (G_LIKELY (str_list != NULL))
839         {
840           for (mt = str_list; *mt != NULL; ++mt)
841             {
842               if (**mt != '\0')
843                 {
844                   /* Set current desktop action group */
845                   action_group = g_strdup_printf ("Desktop Action %s", *mt);
846                   xfce_rc_set_group (rc, action_group);
847 
848                   /* Parse name and exec command */
849                   name = xfce_rc_read_entry (rc, G_KEY_FILE_DESKTOP_KEY_NAME, NULL);
850                   exec = xfce_rc_read_entry_untranslated (rc, G_KEY_FILE_DESKTOP_KEY_EXEC, NULL);
851                   icon = xfce_rc_read_entry_untranslated (rc, G_KEY_FILE_DESKTOP_KEY_ICON, NULL);
852 
853                   /* Validate Name and Exec fields, icon is optional */
854                   if (G_LIKELY (exec != NULL && name != NULL))
855                     {
856                       /* Allocate a new action instance */
857                       action = g_object_new (GARCON_TYPE_MENU_ITEM_ACTION,
858                                              "name", name,
859                                              "command", exec,
860                                              "icon-name", icon,
861                                              NULL);
862 
863                       garcon_menu_item_set_action (item, *mt, action);
864                     }
865 
866                   g_free (action_group);
867                 }
868             }
869 
870           /* Cleanup */
871           g_strfreev (str_list);
872         }
873 
874       else
875         {
876           str_list = xfce_rc_read_list_entry (rc, "X-Ayatana-Desktop-Shortcuts", ";");
877           if (G_LIKELY (str_list != NULL))
878             {
879               for (mt = str_list; *mt != NULL; ++mt)
880                 {
881                   if (**mt != '\0')
882                     {
883                       action_group = g_strdup_printf ("%s Shortcut Group", *mt);
884                       xfce_rc_set_group (rc, action_group);
885 
886                       name = xfce_rc_read_entry (rc, G_KEY_FILE_DESKTOP_KEY_NAME, NULL);
887                       exec = xfce_rc_read_entry_untranslated (rc, G_KEY_FILE_DESKTOP_KEY_EXEC, NULL);
888                       icon = xfce_rc_read_entry_untranslated (rc, G_KEY_FILE_DESKTOP_KEY_ICON, NULL);
889 
890                       /* Validate Name and Exec fields, icon is optional */
891                       if (G_LIKELY (exec != NULL && name != NULL))
892                         {
893                           action = g_object_new (GARCON_TYPE_MENU_ITEM_ACTION,
894                                                  "name", name,
895                                                  "command", exec,
896                                                  "icon-name", icon,
897                                                  NULL);
898 
899                           garcon_menu_item_set_action (item, *mt, action);
900                         }
901 
902                       g_free (action_group);
903                     }
904                 }
905 
906               g_strfreev (str_list);
907             }
908         }
909     }
910 
911   /* Cleanup */
912   xfce_rc_close (rc);
913   g_free (url_exec);
914 
915   return item;
916 }
917 
918 
919 /**
920  * garcon_menu_item_new_for_path: (constructor)
921  * @filename: (type filename): name of a file
922  *
923  * Returns: (transfer full): a new #GarconMenuItem
924  */
925 GarconMenuItem *
garcon_menu_item_new_for_path(const gchar * filename)926 garcon_menu_item_new_for_path (const gchar *filename)
927 {
928   GFile          *file;
929   GarconMenuItem *item;
930 
931   g_return_val_if_fail (filename != NULL, NULL);
932 
933   file = g_file_new_for_path (filename);
934   item = garcon_menu_item_new (file);
935   g_object_unref (G_OBJECT (file));
936 
937   return item;
938 }
939 
940 
941 /**
942  * garcon_menu_item_new_for_uri: (constructor)
943  * @uri: a given URI
944  *
945  * Returns: (transfer full): a new #GarconMenuItem
946  */
947 GarconMenuItem *
garcon_menu_item_new_for_uri(const gchar * uri)948 garcon_menu_item_new_for_uri (const gchar *uri)
949 {
950   GFile          *file;
951   GarconMenuItem *item;
952 
953   g_return_val_if_fail (uri != NULL, NULL);
954 
955   file = g_file_new_for_uri (uri);
956   item = garcon_menu_item_new (file);
957   g_object_unref (G_OBJECT (file));
958 
959   return item;
960 }
961 
962 
963 
964 gboolean
garcon_menu_item_reload(GarconMenuItem * item,gboolean * affects_the_outside,GError ** error)965 garcon_menu_item_reload (GarconMenuItem  *item,
966                          gboolean        *affects_the_outside,
967                          GError         **error)
968 {
969   g_return_val_if_fail (GARCON_IS_MENU_ITEM (item), FALSE);
970   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
971 
972   return garcon_menu_item_reload_from_file (item, item->priv->file, affects_the_outside, error);
973 }
974 
975 
976 
977 gboolean
garcon_menu_item_reload_from_file(GarconMenuItem * item,GFile * file,gboolean * affects_the_outside,GError ** error)978 garcon_menu_item_reload_from_file (GarconMenuItem  *item,
979                                    GFile           *file,
980                                    gboolean        *affects_the_outside,
981                                    GError         **error)
982 {
983   XfceRc               *rc;
984   GarconMenuItemAction *action = NULL;
985   gboolean              boolean;
986   GList                *categories = NULL;
987   GList                *old_categories = NULL;
988   GList                *keywords = NULL;
989   GList                *old_keywords = NULL;
990   GList                *lp;
991   gchar               **mt;
992   gchar               **str_list;
993   const gchar          *string;
994   const gchar          *name;
995   const gchar          *exec;
996   const gchar          *icon;
997   gchar                *filename;
998   gchar                *action_group;
999   gchar                *url_exec = NULL;
1000 
1001   g_return_val_if_fail (GARCON_IS_MENU_ITEM (item), FALSE);
1002   g_return_val_if_fail (G_IS_FILE (file), FALSE);
1003   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1004   g_return_val_if_fail (g_file_is_native (file), FALSE);
1005 
1006   /* Open the rc file */
1007   filename = g_file_get_path (file);
1008   rc = xfce_rc_simple_open (filename, TRUE);
1009   g_free (filename);
1010   if (G_UNLIKELY (rc == NULL))
1011     return FALSE;
1012 
1013   xfce_rc_set_group (rc, G_KEY_FILE_DESKTOP_GROUP);
1014 
1015   /* Check if there is a name and exec key */
1016   name = xfce_rc_read_entry (rc, G_KEY_FILE_DESKTOP_KEY_NAME, NULL);
1017   exec = xfce_rc_read_entry_untranslated (rc, G_KEY_FILE_DESKTOP_KEY_EXEC, NULL);
1018 
1019   /* Support Type=Link items */
1020   if (G_UNLIKELY (exec == NULL))
1021     exec = url_exec = garcon_menu_item_url_exec (rc);
1022 
1023   if (G_UNLIKELY (name == NULL || exec == NULL))
1024     {
1025       g_set_error_literal (error, G_KEY_FILE_ERROR,
1026                            G_KEY_FILE_ERROR_KEY_NOT_FOUND,
1027                            "Either the name or exec key was not defined.");
1028       xfce_rc_close (rc);
1029 
1030       return FALSE;
1031     }
1032 
1033   /* Queue property notifications */
1034   g_object_freeze_notify (G_OBJECT (item));
1035 
1036   /* Set the new file if needed */
1037   if (!g_file_equal (file, item->priv->file))
1038     {
1039       if (G_LIKELY (item->priv->file != NULL))
1040         g_object_unref (G_OBJECT (item->priv->file));
1041       item->priv->file = G_FILE (g_object_ref (G_OBJECT (file)));
1042 
1043       g_object_notify (G_OBJECT (item), "file");
1044     }
1045 
1046   /* Update properties */
1047   garcon_menu_item_set_name (item, name);
1048 
1049   garcon_menu_item_set_command (item, exec);
1050 
1051   string = xfce_rc_read_entry (rc, G_KEY_FILE_DESKTOP_KEY_GENERIC_NAME, NULL);
1052   garcon_menu_item_set_generic_name (item, string);
1053 
1054   string = xfce_rc_read_entry (rc, G_KEY_FILE_DESKTOP_KEY_COMMENT, NULL);
1055   garcon_menu_item_set_comment (item, string);
1056 
1057   string = xfce_rc_read_entry_untranslated (rc, G_KEY_FILE_DESKTOP_KEY_TRY_EXEC, NULL);
1058   garcon_menu_item_set_try_exec (item, string);
1059 
1060   string = xfce_rc_read_entry_untranslated (rc, G_KEY_FILE_DESKTOP_KEY_ICON, NULL);
1061   garcon_menu_item_set_icon_name (item, string);
1062 
1063   string = xfce_rc_read_entry_untranslated (rc, G_KEY_FILE_DESKTOP_KEY_PATH, NULL);
1064   garcon_menu_item_set_path (item, string);
1065 
1066   boolean = xfce_rc_read_bool_entry (rc, G_KEY_FILE_DESKTOP_KEY_TERMINAL, FALSE);
1067   garcon_menu_item_set_requires_terminal (item, boolean);
1068 
1069   boolean = xfce_rc_read_bool_entry (rc, G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, FALSE);
1070   garcon_menu_item_set_no_display (item, boolean);
1071 
1072   boolean = xfce_rc_read_bool_entry (rc, G_KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY, FALSE)
1073             || xfce_rc_read_bool_entry (rc, "X-KDE-StartupNotify", FALSE);
1074   garcon_menu_item_set_supports_startup_notification (item, boolean);
1075 
1076   boolean = xfce_rc_read_bool_entry (rc, G_KEY_FILE_DESKTOP_KEY_HIDDEN, FALSE);
1077   garcon_menu_item_set_hidden (item, boolean);
1078 
1079   if (affects_the_outside != NULL)
1080     {
1081       /* create a deep copy the old categories list */
1082       old_categories = g_list_copy (item->priv->categories);
1083       for (lp = old_categories; lp != NULL; lp = lp->next)
1084         lp->data = g_strdup (lp->data);
1085     }
1086 
1087   /* Determine the categories this application should be shown in */
1088   str_list = xfce_rc_read_list_entry (rc, G_KEY_FILE_DESKTOP_KEY_CATEGORIES, ";");
1089   if (G_LIKELY (str_list != NULL))
1090     {
1091       for (mt = str_list; *mt != NULL; ++mt)
1092         {
1093           /* Try to steal the values */
1094           if (**mt != '\0')
1095             categories = g_list_prepend (categories, *mt);
1096           else
1097             g_free (*mt);
1098         }
1099 
1100       /* Cleanup */
1101       g_free (str_list);
1102 
1103       /* Assign categories list to the menu item */
1104       garcon_menu_item_set_categories (item, categories);
1105     }
1106   else
1107     {
1108       /* Assign empty categories list to the menu item */
1109       garcon_menu_item_set_categories (item, NULL);
1110     }
1111 
1112   if (affects_the_outside != NULL)
1113     {
1114       if (!garcon_menu_item_lists_equal (old_categories, categories))
1115         *affects_the_outside = TRUE;
1116 
1117       _garcon_g_list_free_full (old_categories, g_free);
1118     }
1119 
1120 
1121   if (affects_the_outside != NULL)
1122     {
1123       /* create a deep copy the old keywords list */
1124       old_keywords = g_list_copy (item->priv->keywords);
1125       for (lp = old_keywords; lp != NULL; lp = lp->next)
1126         lp->data = g_strdup (lp->data);
1127     }
1128 
1129   /* Determine the keywords this application should be shown in */
1130   str_list = xfce_rc_read_list_entry (rc, G_KEY_FILE_DESKTOP_KEY_KEYWORDS, ";");
1131   if (G_LIKELY (str_list != NULL))
1132     {
1133       for (mt = str_list; *mt != NULL; ++mt)
1134         {
1135           /* Try to steal the values */
1136           if (**mt != '\0')
1137             keywords = g_list_prepend (keywords, *mt);
1138           else
1139             g_free (*mt);
1140         }
1141 
1142       /* Cleanup */
1143       g_free (str_list);
1144 
1145       /* Assign keywords list to the menu item */
1146       garcon_menu_item_set_keywords (item, keywords);
1147     }
1148   else
1149     {
1150       /* Assign empty keywords list to the menu item */
1151       garcon_menu_item_set_keywords (item, NULL);
1152     }
1153 
1154   if (affects_the_outside != NULL)
1155     {
1156       if (!garcon_menu_item_lists_equal (old_keywords, keywords))
1157         *affects_the_outside = TRUE;
1158 
1159       _garcon_g_list_free_full (old_keywords, g_free);
1160     }
1161 
1162   /* Set the rest of the private data directly */
1163   item->priv->only_show_in = xfce_rc_read_list_entry (rc, G_KEY_FILE_DESKTOP_KEY_ONLY_SHOW_IN, ";");
1164   item->priv->not_show_in = xfce_rc_read_list_entry (rc, G_KEY_FILE_DESKTOP_KEY_NOT_SHOW_IN, ";");
1165 
1166   /* Update application actions */
1167   _garcon_g_list_free_full (item->priv->actions, garcon_menu_item_action_unref);
1168   item->priv->actions = NULL;
1169 
1170   str_list = xfce_rc_read_list_entry (rc, G_KEY_FILE_DESKTOP_KEY_ACTIONS, ";");
1171   if (G_LIKELY (str_list != NULL))
1172     {
1173       for (mt = str_list; *mt != NULL; ++mt)
1174         {
1175           if (**mt != '\0')
1176             {
1177               /* Set current desktop action group */
1178               action_group = g_strdup_printf ("Desktop Action %s", *mt);
1179               xfce_rc_set_group (rc, action_group);
1180 
1181               /* Parse name and exec command */
1182               name = xfce_rc_read_entry (rc, G_KEY_FILE_DESKTOP_KEY_NAME, NULL);
1183               exec = xfce_rc_read_entry_untranslated (rc, G_KEY_FILE_DESKTOP_KEY_EXEC, NULL);
1184               icon = xfce_rc_read_entry_untranslated (rc, G_KEY_FILE_DESKTOP_KEY_ICON, NULL);
1185 
1186               /* Validate Name and Exec fields, icon is optional */
1187               if (G_LIKELY (exec != NULL && name != NULL))
1188                 {
1189                   /* Allocate a new action instance */
1190                   action = g_object_new (GARCON_TYPE_MENU_ITEM_ACTION,
1191                                          "name", name,
1192                                          "command", exec,
1193                                          "icon-name", icon,
1194                                          NULL);
1195 
1196                   garcon_menu_item_set_action (item, *mt, action);
1197                 }
1198               g_free (action_group);
1199             }
1200           else
1201             g_free (*mt);
1202         }
1203 
1204       /* Cleanup */
1205       g_free (str_list);
1206     }
1207 
1208   else
1209     {
1210       str_list = xfce_rc_read_list_entry (rc, "X-Ayatana-Desktop-Shortcuts", ";");
1211       if (G_LIKELY (str_list != NULL))
1212         {
1213           for (mt = str_list; *mt != NULL; ++mt)
1214             {
1215               if (**mt != '\0')
1216                 {
1217                   action_group = g_strdup_printf ("%s Shortcut Group", *mt);
1218                   xfce_rc_set_group (rc, action_group);
1219 
1220                   name = xfce_rc_read_entry (rc, G_KEY_FILE_DESKTOP_KEY_NAME, NULL);
1221                   exec = xfce_rc_read_entry_untranslated (rc, G_KEY_FILE_DESKTOP_KEY_EXEC, NULL);
1222                   icon = xfce_rc_read_entry_untranslated (rc, G_KEY_FILE_DESKTOP_KEY_ICON, NULL);
1223 
1224                   /* Validate Name and Exec fields, icon is optional */
1225                   if (G_LIKELY (exec != NULL && name != NULL))
1226                     {
1227                       action = g_object_new (GARCON_TYPE_MENU_ITEM_ACTION,
1228                                              "name", name,
1229                                              "command", exec,
1230                                              "icon-name", icon,
1231                                              NULL);
1232 
1233                       garcon_menu_item_set_action (item, *mt, action);
1234                     }
1235 
1236                   g_free (action_group);
1237                 }
1238               else
1239                 g_free (*mt);
1240             }
1241 
1242           g_free (str_list);
1243         }
1244     }
1245 
1246   /* Flush property notifications */
1247   g_object_thaw_notify (G_OBJECT (item));
1248 
1249   /* Emit signal to everybody knows we reloaded the file */
1250   g_signal_emit (G_OBJECT (item), item_signals[CHANGED], 0);
1251 
1252   xfce_rc_close (rc);
1253   g_free (url_exec);
1254 
1255   return TRUE;
1256 }
1257 
1258 
1259 
1260 /**
1261  * garcon_menu_item_get_file:
1262  * @item: A #GarconMenuItem
1263  *
1264  * Get the #GFile for @item. The returned object should be
1265  * unreffed with g_object_unref() when no longer needed.
1266  *
1267  * Returns: (transfer full): a #GFile.
1268  */
1269 GFile *
garcon_menu_item_get_file(GarconMenuItem * item)1270 garcon_menu_item_get_file (GarconMenuItem *item)
1271 {
1272   g_return_val_if_fail (GARCON_IS_MENU_ITEM (item), NULL);
1273   return g_object_ref (item->priv->file);
1274 }
1275 
1276 
1277 gchar *
garcon_menu_item_get_uri(GarconMenuItem * item)1278 garcon_menu_item_get_uri (GarconMenuItem *item)
1279 {
1280   g_return_val_if_fail (GARCON_IS_MENU_ITEM (item), NULL);
1281   return g_file_get_uri (item->priv->file);
1282 }
1283 
1284 
1285 
1286 const gchar *
garcon_menu_item_get_desktop_id(GarconMenuItem * item)1287 garcon_menu_item_get_desktop_id (GarconMenuItem *item)
1288 {
1289   g_return_val_if_fail (GARCON_IS_MENU_ITEM (item), NULL);
1290   return item->priv->desktop_id;
1291 }
1292 
1293 
1294 
1295 void
garcon_menu_item_set_desktop_id(GarconMenuItem * item,const gchar * desktop_id)1296 garcon_menu_item_set_desktop_id (GarconMenuItem *item,
1297                                  const gchar    *desktop_id)
1298 {
1299   g_return_if_fail (GARCON_IS_MENU_ITEM (item));
1300   g_return_if_fail (desktop_id != NULL);
1301 
1302   /* Abort if old and new desktop_id are equal */
1303   if (g_strcmp0 (item->priv->desktop_id, desktop_id) == 0)
1304     return;
1305 
1306   /* Assign the new desktop_id */
1307   g_free (item->priv->desktop_id);
1308   item->priv->desktop_id = g_strdup (desktop_id);
1309 
1310   /* Notify listeners */
1311   g_object_notify (G_OBJECT (item), "desktop-id");
1312 }
1313 
1314 
1315 /**
1316  * garcon_menu_item_get_categories:
1317  * @item: a #GarconMenuItem
1318  *
1319  * Returns list of categories
1320  *
1321  * Returns: (element-type utf8) (transfer full):
1322  */
1323 GList*
garcon_menu_item_get_categories(GarconMenuItem * item)1324 garcon_menu_item_get_categories (GarconMenuItem *item)
1325 {
1326   g_return_val_if_fail (GARCON_IS_MENU_ITEM (item), NULL);
1327   return item->priv->categories;
1328 }
1329 
1330 
1331 /**
1332  * garcon_menu_item_set_categories:
1333  * @item: a #GarconMenuItem
1334  * @categories: (element-type utf8): list of categories
1335  */
1336 void
garcon_menu_item_set_categories(GarconMenuItem * item,GList * categories)1337 garcon_menu_item_set_categories (GarconMenuItem *item,
1338                                  GList          *categories)
1339 {
1340   g_return_if_fail (GARCON_IS_MENU_ITEM (item));
1341 
1342   /* Abort if lists are equal */
1343   if (G_UNLIKELY (item->priv->categories == categories))
1344     return;
1345 
1346   /* Free old list */
1347   _garcon_g_list_free_full (item->priv->categories, g_free);
1348 
1349   /* Assign new list */
1350   item->priv->categories = categories;
1351 }
1352 
1353 
1354 /**
1355  * garcon_menu_item_get_keywords:
1356  * @item: a #GarconMenuItem
1357  *
1358  * Returns: (element-type utf8) (transfer full):
1359  */
1360 GList*
garcon_menu_item_get_keywords(GarconMenuItem * item)1361 garcon_menu_item_get_keywords (GarconMenuItem *item)
1362 {
1363   g_return_val_if_fail (GARCON_IS_MENU_ITEM (item), NULL);
1364   return item->priv->keywords;
1365 }
1366 
1367 
1368 /**
1369  * garcon_menu_item_set_keywords:
1370  * @item: a #GarconMenuItem
1371  * @keywords: (element-type utf8): list of keywords
1372  */
1373 void
garcon_menu_item_set_keywords(GarconMenuItem * item,GList * keywords)1374 garcon_menu_item_set_keywords (GarconMenuItem *item,
1375                                GList          *keywords)
1376 {
1377   g_return_if_fail (GARCON_IS_MENU_ITEM (item));
1378 
1379   /* Abort if lists are equal */
1380   if (G_UNLIKELY (item->priv->keywords == keywords))
1381     return;
1382 
1383   /* Free old list */
1384   _garcon_g_list_free_full (item->priv->keywords, g_free);
1385 
1386   /* Assign new list */
1387   item->priv->keywords = keywords;
1388 }
1389 
1390 
1391 const gchar*
garcon_menu_item_get_command(GarconMenuItem * item)1392 garcon_menu_item_get_command (GarconMenuItem *item)
1393 {
1394   g_return_val_if_fail (GARCON_IS_MENU_ITEM (item), NULL);
1395   return item->priv->command;
1396 }
1397 
1398 
1399 void
garcon_menu_item_set_command(GarconMenuItem * item,const gchar * command)1400 garcon_menu_item_set_command (GarconMenuItem *item,
1401                               const gchar    *command)
1402 {
1403   g_return_if_fail (GARCON_IS_MENU_ITEM (item));
1404   g_return_if_fail (command != NULL);
1405 
1406   /* Abort if old and new command are equal */
1407   if (g_strcmp0 (item->priv->command, command) == 0)
1408     return;
1409 
1410   /* Assign new command */
1411   g_free (item->priv->command);
1412   item->priv->command = g_strdup (command);
1413 
1414   /* Notify listeners */
1415   g_object_notify (G_OBJECT (item), "command");
1416 }
1417 
1418 
1419 
1420 const gchar*
garcon_menu_item_get_try_exec(GarconMenuItem * item)1421 garcon_menu_item_get_try_exec (GarconMenuItem *item)
1422 {
1423   g_return_val_if_fail (GARCON_IS_MENU_ITEM (item), NULL);
1424   return item->priv->try_exec;
1425 }
1426 
1427 
1428 
1429 void
garcon_menu_item_set_try_exec(GarconMenuItem * item,const gchar * try_exec)1430 garcon_menu_item_set_try_exec (GarconMenuItem *item,
1431                                const gchar    *try_exec)
1432 {
1433   g_return_if_fail (GARCON_IS_MENU_ITEM (item));
1434 
1435   /* Abort if old and new try_exec are equal */
1436   if (g_strcmp0 (item->priv->try_exec, try_exec) == 0)
1437     return;
1438 
1439   /* Assign new try_exec */
1440   g_free (item->priv->try_exec);
1441   item->priv->try_exec = g_strdup (try_exec);
1442 
1443   /* Notify listeners */
1444   g_object_notify (G_OBJECT (item), "try-exec");
1445 }
1446 
1447 
1448 
1449 const gchar*
garcon_menu_item_get_name(GarconMenuItem * item)1450 garcon_menu_item_get_name (GarconMenuItem *item)
1451 {
1452   g_return_val_if_fail (GARCON_IS_MENU_ITEM (item), NULL);
1453   return item->priv->name;
1454 }
1455 
1456 
1457 
1458 void
garcon_menu_item_set_name(GarconMenuItem * item,const gchar * name)1459 garcon_menu_item_set_name (GarconMenuItem *item,
1460                            const gchar    *name)
1461 {
1462   g_return_if_fail (GARCON_IS_MENU_ITEM (item));
1463   g_return_if_fail (g_utf8_validate (name, -1, NULL));
1464 
1465   /* Abort if old and new name are equal */
1466   if (g_strcmp0 (item->priv->name, name) == 0)
1467     return;
1468 
1469   /* Assign new name */
1470   g_free (item->priv->name);
1471   item->priv->name = g_strdup (name);
1472 
1473   /* Notify listeners */
1474   g_object_notify (G_OBJECT (item), "name");
1475 }
1476 
1477 
1478 
1479 const gchar*
garcon_menu_item_get_generic_name(GarconMenuItem * item)1480 garcon_menu_item_get_generic_name (GarconMenuItem *item)
1481 {
1482   g_return_val_if_fail (GARCON_IS_MENU_ITEM (item), NULL);
1483   return item->priv->generic_name;
1484 }
1485 
1486 
1487 
1488 void
garcon_menu_item_set_generic_name(GarconMenuItem * item,const gchar * generic_name)1489 garcon_menu_item_set_generic_name (GarconMenuItem *item,
1490                                    const gchar    *generic_name)
1491 {
1492   g_return_if_fail (GARCON_IS_MENU_ITEM (item));
1493   g_return_if_fail (generic_name == NULL || g_utf8_validate (generic_name, -1, NULL));
1494 
1495   /* Abort if old and new generic name are equal */
1496   if (g_strcmp0 (item->priv->generic_name, generic_name) == 0)
1497     return;
1498 
1499   /* Assign new generic_name */
1500   g_free (item->priv->generic_name);
1501   item->priv->generic_name = g_strdup (generic_name);
1502 
1503   /* Notify listeners */
1504   g_object_notify (G_OBJECT (item), "generic-name");
1505 }
1506 
1507 
1508 
1509 const gchar*
garcon_menu_item_get_comment(GarconMenuItem * item)1510 garcon_menu_item_get_comment (GarconMenuItem *item)
1511 {
1512   g_return_val_if_fail (GARCON_IS_MENU_ITEM (item), NULL);
1513   return item->priv->comment;
1514 }
1515 
1516 
1517 
1518 void
garcon_menu_item_set_comment(GarconMenuItem * item,const gchar * comment)1519 garcon_menu_item_set_comment (GarconMenuItem *item,
1520                               const gchar    *comment)
1521 {
1522   g_return_if_fail (GARCON_IS_MENU_ITEM (item));
1523   g_return_if_fail (comment == NULL || g_utf8_validate (comment, -1, NULL));
1524 
1525   /* Abort if old and new comment are equal */
1526   if (g_strcmp0 (item->priv->comment, comment) == 0)
1527     return;
1528 
1529   /* Assign new comment */
1530   g_free (item->priv->comment);
1531   item->priv->comment = g_strdup (comment);
1532 
1533   /* Notify listeners */
1534   g_object_notify (G_OBJECT (item), "comment");
1535 }
1536 
1537 
1538 
1539 const gchar*
garcon_menu_item_get_icon_name(GarconMenuItem * item)1540 garcon_menu_item_get_icon_name (GarconMenuItem *item)
1541 {
1542   g_return_val_if_fail (GARCON_IS_MENU_ITEM (item), NULL);
1543   return item->priv->icon_name;
1544 }
1545 
1546 
1547 
1548 void
garcon_menu_item_set_icon_name(GarconMenuItem * item,const gchar * icon_name)1549 garcon_menu_item_set_icon_name (GarconMenuItem *item,
1550                                 const gchar    *icon_name)
1551 {
1552   g_return_if_fail (GARCON_IS_MENU_ITEM (item));
1553 
1554   /* Abort if old and new icon name are equal */
1555   if (g_strcmp0 (item->priv->icon_name, icon_name) == 0)
1556     return;
1557 
1558   /* Assign new icon name */
1559   g_free (item->priv->icon_name);
1560   item->priv->icon_name = g_strdup (icon_name);
1561 
1562   /* Notify listeners */
1563   g_object_notify (G_OBJECT (item), "icon-name");
1564 }
1565 
1566 
1567 
1568 const gchar*
garcon_menu_item_get_path(GarconMenuItem * item)1569 garcon_menu_item_get_path (GarconMenuItem *item)
1570 {
1571   g_return_val_if_fail (GARCON_IS_MENU_ITEM (item), NULL);
1572   return item->priv->path;
1573 }
1574 
1575 
1576 
1577 void
garcon_menu_item_set_path(GarconMenuItem * item,const gchar * path)1578 garcon_menu_item_set_path (GarconMenuItem *item,
1579                            const gchar    *path)
1580 {
1581   g_return_if_fail (GARCON_IS_MENU_ITEM (item));
1582 
1583   /* Abort if old and new path are equal */
1584   if (g_strcmp0 (item->priv->path, path) == 0)
1585     return;
1586 
1587   /* Assign new path */
1588   g_free (item->priv->path);
1589   item->priv->path = g_strdup (path);
1590 
1591   /* Notify listeners */
1592   g_object_notify (G_OBJECT (item), "path");
1593 }
1594 
1595 
1596 
1597 gboolean
garcon_menu_item_get_hidden(GarconMenuItem * item)1598 garcon_menu_item_get_hidden (GarconMenuItem *item)
1599 {
1600   g_return_val_if_fail (GARCON_IS_MENU_ITEM (item), TRUE);
1601   return item->priv->hidden;
1602 }
1603 
1604 
1605 
1606 void
garcon_menu_item_set_hidden(GarconMenuItem * item,gboolean hidden)1607 garcon_menu_item_set_hidden (GarconMenuItem *item,
1608                              gboolean        hidden)
1609 {
1610   g_return_if_fail (GARCON_IS_MENU_ITEM (item));
1611 
1612   /* Abort if old and new value are equal */
1613   if (item->priv->hidden == hidden)
1614     return;
1615 
1616   /* Assign new value */
1617   item->priv->hidden = !!hidden;
1618 
1619   /* Notify listeners */
1620   g_object_notify (G_OBJECT (item), "hidden");
1621 }
1622 
1623 
1624 
1625 gboolean
garcon_menu_item_requires_terminal(GarconMenuItem * item)1626 garcon_menu_item_requires_terminal (GarconMenuItem *item)
1627 {
1628   g_return_val_if_fail (GARCON_IS_MENU_ITEM (item), FALSE);
1629   return item->priv->requires_terminal;
1630 }
1631 
1632 
1633 
1634 void
garcon_menu_item_set_requires_terminal(GarconMenuItem * item,gboolean requires_terminal)1635 garcon_menu_item_set_requires_terminal (GarconMenuItem *item,
1636                                         gboolean        requires_terminal)
1637 {
1638   g_return_if_fail (GARCON_IS_MENU_ITEM (item));
1639 
1640   /* Abort if old and new value are equal */
1641   if (item->priv->requires_terminal == requires_terminal)
1642     return;
1643 
1644   /* Assign new value */
1645   item->priv->requires_terminal = !!requires_terminal;
1646 
1647   /* Notify listeners */
1648   g_object_notify (G_OBJECT (item), "requires-terminal");
1649 }
1650 
1651 
1652 
1653 gboolean
garcon_menu_item_get_no_display(GarconMenuItem * item)1654 garcon_menu_item_get_no_display (GarconMenuItem *item)
1655 {
1656   g_return_val_if_fail (GARCON_IS_MENU_ITEM (item), FALSE);
1657   return item->priv->no_display;
1658 }
1659 
1660 
1661 
1662 void
garcon_menu_item_set_no_display(GarconMenuItem * item,gboolean no_display)1663 garcon_menu_item_set_no_display (GarconMenuItem *item,
1664                                  gboolean        no_display)
1665 {
1666   g_return_if_fail (GARCON_IS_MENU_ITEM (item));
1667 
1668   /* Abort if old and new value are equal */
1669   if (item->priv->no_display == no_display)
1670     return;
1671 
1672   /* Assign new value */
1673   item->priv->no_display = !!no_display;
1674 
1675   /* Notify listeners */
1676   g_object_notify (G_OBJECT (item), "no-display");
1677 }
1678 
1679 
1680 
1681 gboolean
garcon_menu_item_supports_startup_notification(GarconMenuItem * item)1682 garcon_menu_item_supports_startup_notification (GarconMenuItem *item)
1683 {
1684   g_return_val_if_fail (GARCON_IS_MENU_ITEM (item), FALSE);
1685   return item->priv->supports_startup_notification;
1686 }
1687 
1688 
1689 
1690 void
garcon_menu_item_set_supports_startup_notification(GarconMenuItem * item,gboolean supports_startup_notification)1691 garcon_menu_item_set_supports_startup_notification (GarconMenuItem *item,
1692                                                     gboolean        supports_startup_notification)
1693 {
1694   g_return_if_fail (GARCON_IS_MENU_ITEM (item));
1695 
1696   /* Abort if old and new value are equal */
1697   if (item->priv->supports_startup_notification == supports_startup_notification)
1698     return;
1699 
1700   /* Assign new value */
1701   item->priv->supports_startup_notification = !!supports_startup_notification;
1702 
1703   /* Notify listeners */
1704   g_object_notify (G_OBJECT (item), "supports-startup-notification");
1705 }
1706 
1707 
1708 
1709 gboolean
garcon_menu_item_has_category(GarconMenuItem * item,const gchar * category)1710 garcon_menu_item_has_category (GarconMenuItem *item,
1711                                const gchar    *category)
1712 {
1713   GList   *iter;
1714   gboolean found = FALSE;
1715 
1716   g_return_val_if_fail (GARCON_IS_MENU_ITEM (item), FALSE);
1717   g_return_val_if_fail (category != NULL, FALSE);
1718 
1719   for (iter = item->priv->categories; !found && iter != NULL; iter = g_list_next (iter))
1720     if (g_strcmp0 (iter->data, category) == 0)
1721       found = TRUE;
1722 
1723   return found;
1724 }
1725 
1726 
1727 
1728 gboolean
garcon_menu_item_has_keyword(GarconMenuItem * item,const gchar * keyword)1729 garcon_menu_item_has_keyword (GarconMenuItem *item,
1730                               const gchar    *keyword)
1731 {
1732   GList   *iter;
1733   gboolean found = FALSE;
1734 
1735   g_return_val_if_fail (GARCON_IS_MENU_ITEM (item), FALSE);
1736   g_return_val_if_fail (keyword != NULL, FALSE);
1737 
1738   for (iter = item->priv->keywords; !found && iter != NULL; iter = g_list_next (iter))
1739     if (g_strcmp0 (iter->data, keyword) == 0)
1740       found = TRUE;
1741 
1742   return found;
1743 }
1744 
1745 
1746 /**
1747  * garcon_menu_item_get_actions:
1748  * @item: a #GarconMenuItem
1749  *
1750  * Returns: (element-type GarconMenuItemAction) (transfer full):
1751  */
1752 GList *
garcon_menu_item_get_actions(GarconMenuItem * item)1753 garcon_menu_item_get_actions (GarconMenuItem *item)
1754 {
1755   GList                *action_names = NULL;
1756   GList                *iter;
1757   GarconMenuItemAction *action;
1758 
1759   g_return_val_if_fail (GARCON_IS_MENU_ITEM (item), NULL);
1760 
1761   for (iter = item->priv->actions; iter != NULL ; iter = g_list_next (iter))
1762     {
1763       action = GARCON_MENU_ITEM_ACTION (iter->data);
1764       action_names = g_list_prepend (action_names, (gchar*)garcon_menu_item_action_get_name (action));
1765     }
1766   action_names = g_list_reverse (action_names);
1767 
1768   return action_names;
1769 }
1770 
1771 
1772 /**
1773  * garcon_menu_item_get_action:
1774  * @item: a #GarconMenuItem
1775  * @action_name:
1776  *
1777  * Returns: (nullable) (transfer full): a #GarconMenuItemAction
1778  */
1779 GarconMenuItemAction *
garcon_menu_item_get_action(GarconMenuItem * item,const gchar * action_name)1780 garcon_menu_item_get_action (GarconMenuItem *item,
1781                              const gchar    *action_name)
1782 {
1783   GList                *iter;
1784   GarconMenuItemAction *action;
1785 
1786   g_return_val_if_fail (GARCON_IS_MENU_ITEM (item), NULL);
1787   g_return_val_if_fail (action_name != NULL, NULL);
1788 
1789   for (iter = item->priv->actions; iter != NULL; iter = g_list_next (iter))
1790     {
1791       action = GARCON_MENU_ITEM_ACTION (iter->data);
1792       if (g_strcmp0 (garcon_menu_item_action_get_name (action), action_name) == 0)
1793         return (action);
1794     }
1795 
1796   return NULL;
1797 }
1798 
1799 
1800 
1801 
1802 void
garcon_menu_item_set_action(GarconMenuItem * item,const gchar * action_name,GarconMenuItemAction * action)1803 garcon_menu_item_set_action (GarconMenuItem       *item,
1804                              const gchar          *action_name,
1805                              GarconMenuItemAction *action)
1806 {
1807   GList                *iter;
1808   GarconMenuItemAction *old_action;
1809   gboolean             found = FALSE;
1810 
1811   g_return_if_fail (GARCON_IS_MENU_ITEM (item));
1812   g_return_if_fail (GARCON_IS_MENU_ITEM_ACTION (action));
1813 
1814   /* If action name is found in list, then insert new action into the list and
1815    * remove old action */
1816   for (iter = item->priv->actions; !found && iter != NULL; iter = g_list_next (iter))
1817     {
1818       old_action = GARCON_MENU_ITEM_ACTION (iter->data);
1819       if (g_strcmp0 (garcon_menu_item_action_get_name (old_action), action_name) == 0)
1820         {
1821            /* Release reference on action currently stored at action name */
1822            garcon_menu_item_action_unref (old_action);
1823 
1824            /* Replace action in list at action name and grab a reference */
1825            iter->data = action;
1826            garcon_menu_item_action_ref (action);
1827 
1828            /* Set flag that action was found */
1829            found = TRUE;
1830         }
1831     }
1832 
1833   /* If action name was not found in list, then simply add it to list */
1834   if (found == FALSE)
1835     {
1836       /* Add action to list and grab a reference */
1837       item->priv->actions=g_list_append (item->priv->actions, action);
1838       garcon_menu_item_action_ref (action);
1839     }
1840 }
1841 
1842 
1843 
1844 gboolean
garcon_menu_item_has_action(GarconMenuItem * item,const gchar * action_name)1845 garcon_menu_item_has_action (GarconMenuItem  *item,
1846                              const gchar     *action_name)
1847 {
1848   GList                *iter;
1849   GarconMenuItemAction *action;
1850   gboolean             found = FALSE;
1851 
1852   g_return_val_if_fail (GARCON_IS_MENU_ITEM (item), FALSE);
1853   g_return_val_if_fail (action_name != NULL, FALSE);
1854 
1855   for (iter = item->priv->actions; !found && iter != NULL; iter = g_list_next (iter))
1856     {
1857       action = GARCON_MENU_ITEM_ACTION (iter->data);
1858       if (g_strcmp0 (garcon_menu_item_action_get_name (action), action_name) == 0)
1859         found = TRUE;
1860     }
1861 
1862   return found;
1863 }
1864 
1865 
1866 
1867 gboolean
garcon_menu_item_get_show_in_environment(GarconMenuItem * item)1868 garcon_menu_item_get_show_in_environment (GarconMenuItem *item)
1869 {
1870   const gchar *env;
1871   guint        i, j;
1872   gboolean     show = TRUE;
1873   gchar**      path = NULL;
1874 
1875   g_return_val_if_fail (GARCON_IS_MENU_ITEM (item), FALSE);
1876 
1877   /* Determine current environment */
1878   env = garcon_get_environment ();
1879 
1880   /* If no environment has been set, the menu is displayed no matter what
1881    * OnlyShowIn or NotShowIn contain */
1882   if (G_UNLIKELY (env == NULL))
1883     return TRUE;
1884 
1885   /* According to the spec there is either a OnlyShowIn or a NotShowIn list
1886    * The environment can be multiple Desktop Names separated by a colons */
1887   if (G_UNLIKELY (item->priv->only_show_in != NULL))
1888     {
1889       /* Check if your environemnt is in OnlyShowIn list */
1890       show = FALSE;
1891       path = g_strsplit(env, ":", 0);
1892       for (j = 0; path[j] != NULL; j++)
1893         for (i = 0; !show && item->priv->only_show_in[i] != NULL; i++)
1894           if (g_strcmp0 (item->priv->only_show_in[i], path[j]) == 0)
1895             show = TRUE;
1896       g_strfreev(path);
1897     }
1898   else if (G_UNLIKELY (item->priv->not_show_in != NULL))
1899     {
1900       /* Check if your environemnt is in NotShowIn list */
1901       show = TRUE;
1902       path = g_strsplit(env, ":", 0);
1903       for (j = 0; path[j] != NULL; j++)
1904         for (i = 0; show && item->priv->not_show_in[i] != NULL; i++)
1905           if (g_strcmp0 (item->priv->not_show_in[i], path[j]) == 0)
1906             show = FALSE;
1907       g_strfreev(path);
1908     }
1909 
1910   return show;
1911 }
1912 
1913 
1914 
1915 gboolean
garcon_menu_item_only_show_in_environment(GarconMenuItem * item)1916 garcon_menu_item_only_show_in_environment (GarconMenuItem *item)
1917 {
1918   const gchar *env;
1919   guint        i, j;
1920   gboolean     show = FALSE;
1921   gchar**      path = NULL;
1922 
1923   g_return_val_if_fail (GARCON_IS_MENU_ITEM (item), FALSE);
1924 
1925   /* Determine current environment */
1926   env = garcon_get_environment ();
1927 
1928   /* If no environment has been set, the contents of OnlyShowIn don't matter */
1929   if (G_LIKELY (env == NULL))
1930     return FALSE;
1931 
1932   /* Check if we have an OnlyShowIn list */
1933   if (G_UNLIKELY (item->priv->only_show_in != NULL))
1934     {
1935       /* Check if your environemnt is in OnlyShowIn list */
1936       show = FALSE;
1937       path = g_strsplit(env, ":", 0);
1938       for (j= 0; path[j] != NULL; j++)
1939         for (i = 0; !show && item->priv->only_show_in[i] != NULL; i++)
1940           if (g_strcmp0 (item->priv->only_show_in[i], path[j]) == 0)
1941             show = TRUE;
1942     }
1943 
1944   return show;
1945 }
1946 
1947 
1948 
1949 void
garcon_menu_item_ref(GarconMenuItem * item)1950 garcon_menu_item_ref (GarconMenuItem *item)
1951 {
1952   g_return_if_fail (GARCON_IS_MENU_ITEM (item));
1953 
1954   /* Increment the allocation counter */
1955   garcon_menu_item_increment_allocated (item);
1956 
1957   /* Grab a reference on the object */
1958   g_object_ref (G_OBJECT (item));
1959 }
1960 
1961 
1962 
1963 void
garcon_menu_item_unref(GarconMenuItem * item)1964 garcon_menu_item_unref (GarconMenuItem *item)
1965 {
1966   g_return_if_fail (GARCON_IS_MENU_ITEM (item));
1967 
1968   garcon_menu_item_decrement_allocated (item);
1969 
1970   /* Decrement the reference counter */
1971   g_object_unref (G_OBJECT (item));
1972 }
1973 
1974 
1975 
1976 gint
garcon_menu_item_get_allocated(GarconMenuItem * item)1977 garcon_menu_item_get_allocated (GarconMenuItem *item)
1978 {
1979   g_return_val_if_fail (GARCON_IS_MENU_ITEM (item), FALSE);
1980   return item->priv->num_allocated;
1981 }
1982 
1983 
1984 
1985 void
garcon_menu_item_increment_allocated(GarconMenuItem * item)1986 garcon_menu_item_increment_allocated (GarconMenuItem *item)
1987 {
1988   g_return_if_fail (GARCON_IS_MENU_ITEM (item));
1989   item->priv->num_allocated++;
1990 }
1991 
1992 
1993 
1994 void
garcon_menu_item_decrement_allocated(GarconMenuItem * item)1995 garcon_menu_item_decrement_allocated (GarconMenuItem *item)
1996 {
1997   g_return_if_fail (GARCON_IS_MENU_ITEM (item));
1998 
1999   if (item->priv->num_allocated > 0)
2000     item->priv->num_allocated--;
2001 }
2002