commit 2ac3bbb0acbe0d142e9f7980228210d171607151 Author: Danila Poyarkov Date: Wed Apr 1 01:17:50 2015 +0300 Added desktop actions support (bug #11268) diff --git a/garcon/Makefile.am b/garcon/Makefile.am index 6ead847..475cde1 100644 --- a/garcon/Makefile.am +++ b/garcon/Makefile.am @@ -42,6 +42,7 @@ libgarcon_headers = \ garcon-menu-element.h \ garcon-menu-separator.h \ garcon-menu-directory.h \ + garcon-menu-item-action.h \ garcon-menu-item-pool.h \ garcon-menu-item-cache.h \ garcon-environment.h \ @@ -58,6 +59,7 @@ libgarcon_sources = \ garcon-menu-element.c \ garcon-menu-separator.c \ garcon-menu-directory.c \ + garcon-menu-item-action.c \ garcon-menu-item-pool.c \ garcon-menu-item-cache.c \ garcon-environment.c \ diff --git a/garcon/garcon-menu-item-action.c b/garcon/garcon-menu-item-action.c new file mode 100644 index 0000000..b416895 --- /dev/null +++ b/garcon/garcon-menu-item-action.c @@ -0,0 +1,249 @@ +/* vi:set et ai sw=2 sts=2 ts=2: */ +/*- + * Copyright (c) 2015 Danila Poyarkov + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include +#include + +/* Property identifiers */ +enum +{ + PROP_0, + PROP_NAME, + PROP_COMMAND, +}; + +static void garcon_menu_item_action_finalize (GObject *object); +static void garcon_menu_item_action_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void garcon_menu_item_action_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); + +struct _GarconMenuItemActionPrivate +{ + /* Name to be displayed for the action */ + gchar *name; + + /* Command to be executed when the action is clicked */ + gchar *command; +}; + +G_DEFINE_TYPE (GarconMenuItemAction, garcon_menu_item_action, G_TYPE_OBJECT) + +static void +garcon_menu_item_action_class_init (GarconMenuItemActionClass *klass) +{ + GObjectClass *gobject_class; + + g_type_class_add_private (klass, sizeof (GarconMenuItemActionPrivate)); + + gobject_class = G_OBJECT_CLASS (klass); + gobject_class->finalize = garcon_menu_item_action_finalize; + gobject_class->get_property = garcon_menu_item_action_get_property; + gobject_class->set_property = garcon_menu_item_action_set_property; + + /** + * GarconMenuItemAction:name: + * + * Name of the application action (will be displayed in menus etc.). + **/ + g_object_class_install_property (gobject_class, + PROP_NAME, + g_param_spec_string ("name", + "Name", + "Name of the action", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * GarconMenuItemAction:command: + * + * Command to be executed when the application action is clicked. + **/ + g_object_class_install_property (gobject_class, + PROP_COMMAND, + g_param_spec_string ("command", + "Command", + "Application command", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); +} + +static void +garcon_menu_item_action_init (GarconMenuItemAction *action) +{ + action->priv = G_TYPE_INSTANCE_GET_PRIVATE (action, GARCON_TYPE_MENU_ITEM_ACTION, GarconMenuItemActionPrivate); +} + + + +static void +garcon_menu_item_action_finalize (GObject *object) +{ + GarconMenuItemAction *action = GARCON_MENU_ITEM_ACTION (object); + + g_free (action->priv->name); + g_free (action->priv->command); + + (*G_OBJECT_CLASS (garcon_menu_item_action_parent_class)->finalize) (object); +} + + + +static void +garcon_menu_item_action_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GarconMenuItemAction *action = GARCON_MENU_ITEM_ACTION (object); + + switch (prop_id) + { + case PROP_NAME: + g_value_set_string (value, garcon_menu_item_action_get_name (action)); + break; + + case PROP_COMMAND: + g_value_set_string (value, garcon_menu_item_action_get_command (action)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + + + +static void +garcon_menu_item_action_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GarconMenuItemAction *action = GARCON_MENU_ITEM_ACTION (object); + + switch (prop_id) + { + case PROP_NAME: + garcon_menu_item_action_set_name (action, g_value_get_string (value)); + break; + + case PROP_COMMAND: + garcon_menu_item_action_set_command (action, g_value_get_string (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + + +const gchar* +garcon_menu_item_action_get_name (GarconMenuItemAction *action) +{ + g_return_val_if_fail (GARCON_IS_MENU_ITEM_ACTION (action), NULL); + return action->priv->name; +} + + + +void +garcon_menu_item_action_set_name (GarconMenuItemAction *action, + const gchar *name) +{ + g_return_if_fail (GARCON_IS_MENU_ITEM_ACTION (action)); + g_return_if_fail (g_utf8_validate (name, -1, NULL)); + + /* Abort if old and new name are equal */ + if (g_strcmp0 (action->priv->name, name) == 0) + return; + + /* Assign new name */ + g_free (action->priv->name); + action->priv->name = g_strdup (name); + + /* Notify listeners */ + g_object_notify (G_OBJECT (action), "name"); +} + + +const gchar* +garcon_menu_item_action_get_command (GarconMenuItemAction *action) +{ + g_return_val_if_fail (GARCON_IS_MENU_ITEM_ACTION (action), NULL); + return action->priv->command; +} + + + +void +garcon_menu_item_action_set_command (GarconMenuItemAction *action, + const gchar *command) +{ + g_return_if_fail (GARCON_IS_MENU_ITEM_ACTION (action)); + g_return_if_fail (command != NULL); + + /* Abort if old and new command are equal */ + if (g_strcmp0 (action->priv->command, command) == 0) + return; + + /* Assign new command */ + g_free (action->priv->command); + action->priv->command = g_strdup (command); + + /* Notify listeners */ + g_object_notify (G_OBJECT (action), "command"); +} + +void +garcon_menu_item_action_ref (GarconMenuItemAction *action) +{ + g_return_if_fail (GARCON_IS_MENU_ITEM_ACTION (action)); + + /* Grab a reference on the object */ + g_object_ref (G_OBJECT (action)); +} + + + +void +garcon_menu_item_action_unref (GarconMenuItemAction *action) +{ + g_return_if_fail (GARCON_IS_MENU_ITEM_ACTION (action)); + + /* Decrement the reference counter */ + g_object_unref (G_OBJECT (action)); +} \ No newline at end of file diff --git a/garcon/garcon-menu-item-action.h b/garcon/garcon-menu-item-action.h new file mode 100644 index 0000000..2069aaa --- /dev/null +++ b/garcon/garcon-menu-item-action.h @@ -0,0 +1,74 @@ +/* vi:set et ai sw=2 sts=2 ts=2: */ +/*- + * Copyright (c) 2015 Danila Poyarkov + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + + #if !defined(GARCON_INSIDE_GARCON_H) && !defined(GARCON_COMPILATION) +#error "Only can be included directly. This file may disappear or change contents." +#endif + +#ifndef __GARCON_MENU_ITEM_ACTION_H__ +#define __GARCON_MENU_ITEM_ACTION_H__ + +#include +#include + +G_BEGIN_DECLS + +typedef struct _GarconMenuItemActionPrivate GarconMenuItemActionPrivate; +typedef struct _GarconMenuItemActionClass GarconMenuItemActionClass; +typedef struct _GarconMenuItemAction GarconMenuItemAction; + +#define GARCON_TYPE_MENU_ITEM_ACTION (garcon_menu_item_action_get_type()) +#define GARCON_MENU_ITEM_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GARCON_TYPE_MENU_ITEM_ACTION, GarconMenuItemAction)) +#define GARCON_MENU_ITEM_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GARCON_TYPE_MENU_ITEM_ACTION, GarconMenuItemActionClass)) +#define GARCON_IS_MENU_ITEM_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GARCON_TYPE_MENU_ITEM_ACTION)) +#define GARCON_IS_MENU_ITEM_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GARCON_TYPE_MENU_ITEM_ACTION)) +#define GARCON_MENU_ITEM_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GARCON_TYPE_MENU_ITEM_ACTION, GarconMenuItemActionClass)) + +struct _GarconMenuItemActionClass +{ + GObjectClass __parent__; + + /* signals */ + void (*changed) (GarconMenuItemAction *action); +}; + +struct _GarconMenuItemAction +{ + GObject __parent__; + + /* < private > */ + GarconMenuItemActionPrivate *priv; +}; + +GType garcon_menu_item_action_get_type (void) G_GNUC_CONST; +GarconMenuItemAction *garcon_menu_item_action_new (void) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT; + +const gchar *garcon_menu_item_action_get_command (GarconMenuItemAction *action); +void garcon_menu_item_action_set_command (GarconMenuItemAction *action, + const gchar *command); +const gchar *garcon_menu_item_action_get_name (GarconMenuItemAction *action); +void garcon_menu_item_action_set_name (GarconMenuItemAction *action, + const gchar *name); +void garcon_menu_item_action_ref (GarconMenuItemAction *action); +void garcon_menu_item_action_unref (GarconMenuItemAction *action); + +G_END_DECLS + +#endif /* !__GARCON_MENU_ITEM_ACTION_H__ */ \ No newline at end of file diff --git a/garcon/garcon-menu-item.c b/garcon/garcon-menu-item.c index 66a86bf..23a822f 100644 --- a/garcon/garcon-menu-item.c +++ b/garcon/garcon-menu-item.c @@ -2,6 +2,7 @@ /*- * Copyright (c) 2006-2010 Jannis Pohlmann * Copyright (c) 2009-2010 Nick Schermer + * Copyright (c) 2015 Danila Poyarkov * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -29,6 +30,7 @@ #include #include #include +#include #include @@ -91,57 +93,60 @@ static guint item_signals[LAST_SIGNAL]; struct _GarconMenuItemPrivate { /* Source file of the menu item */ - GFile *file; + GFile *file; /* Desktop file id */ - gchar *desktop_id; + gchar *desktop_id; /* List of categories */ - GList *categories; + GList *categories; /* Whether this application requires a terminal to be started in */ - guint requires_terminal : 1; + guint requires_terminal : 1; /* Whether this menu item should be hidden */ - guint no_display : 1; + guint no_display : 1; /* Whether this application supports startup notification */ - guint supports_startup_notification : 1; + guint supports_startup_notification : 1; /* Name to be displayed for the menu item */ - gchar *name; + gchar *name; /* Generic name of the menu item */ - gchar *generic_name; + gchar *generic_name; /* Comment/description of the item */ - gchar *comment; + gchar *comment; /* Command to be executed when the menu item is clicked */ - gchar *command; + gchar *command; /* TryExec value */ - gchar *try_exec; + gchar *try_exec; /* Menu item icon name */ - gchar *icon_name; + gchar *icon_name; /* Environments in which the menu item should be displayed only */ - gchar **only_show_in; + gchar **only_show_in; /* Environments in which the menu item should be hidden */ - gchar **not_show_in; + gchar **not_show_in; /* Working directory */ - gchar *path; + gchar *path; + + /* Hash table for mapping action names to GarconMenuItemAction's */ + GHashTable *actions; /* Hidden value */ - guint hidden : 1; + guint hidden : 1; /* Counter keeping the number of menus which use this item. This works * like a reference counter and should be increased / decreased by GarconMenu * items whenever the item is added to or removed from the menu. */ - guint num_allocated; + guint num_allocated; }; @@ -389,6 +394,8 @@ static void garcon_menu_item_init (GarconMenuItem *item) { item->priv = G_TYPE_INSTANCE_GET_PRIVATE (item, GARCON_TYPE_MENU_ITEM, GarconMenuItemPrivate); + item->priv->actions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, + (GDestroyNotify) garcon_menu_item_action_unref); } @@ -415,6 +422,8 @@ garcon_menu_item_finalize (GObject *object) if (item->priv->file != NULL) g_object_unref (G_OBJECT (item->priv->file)); + g_hash_table_unref (item->priv->actions); + (*G_OBJECT_CLASS (garcon_menu_item_parent_class)->finalize) (object); } @@ -700,24 +709,26 @@ garcon_menu_item_url_exec (XfceRc *rc) GarconMenuItem * garcon_menu_item_new (GFile *file) { - GarconMenuItem *item = NULL; - XfceRc *rc; - GList *categories = NULL; - gchar *filename; - gboolean terminal; - gboolean no_display; - gboolean startup_notify; - gboolean hidden; - const gchar *path; - const gchar *name; - const gchar *generic_name; - const gchar *comment; - const gchar *exec; - const gchar *try_exec; - const gchar *icon; - gchar **mt; - gchar **str_list; - gchar *url_exec = NULL; + GarconMenuItem *item = NULL; + GarconMenuItemAction *action = NULL; + XfceRc *rc; + GList *categories = NULL; + gchar *filename; + gboolean terminal; + gboolean no_display; + gboolean startup_notify; + gboolean hidden; + const gchar *path; + const gchar *name; + const gchar *generic_name; + const gchar *comment; + const gchar *exec; + const gchar *try_exec; + const gchar *icon; + gchar *action_group; + gchar **mt; + gchar **str_list; + gchar *url_exec = NULL; g_return_val_if_fail (G_IS_FILE (file), NULL); g_return_val_if_fail (g_file_is_native (file), NULL); @@ -793,6 +804,79 @@ garcon_menu_item_new (GFile *file) /* Set the rest of the private data directly */ item->priv->only_show_in = xfce_rc_read_list_entry (rc, G_KEY_FILE_DESKTOP_KEY_ONLY_SHOW_IN, ";"); item->priv->not_show_in = xfce_rc_read_list_entry (rc, G_KEY_FILE_DESKTOP_KEY_NOT_SHOW_IN, ";"); + + /* Determine this application actions */ + str_list = xfce_rc_read_list_entry (rc, G_KEY_FILE_DESKTOP_KEY_ACTIONS, ";"); + if (G_LIKELY (str_list != NULL)) + { + for (mt = str_list; *mt != NULL; ++mt) + { + if (**mt != '\0') + { + /* Set current desktop action group */ + action_group = g_strdup_printf ("Desktop Action %s", *mt); + xfce_rc_set_group (rc, action_group); + + /* Parse name and exec command */ + name = xfce_rc_read_entry (rc, G_KEY_FILE_DESKTOP_KEY_NAME, NULL); + exec = xfce_rc_read_entry_untranslated (rc, G_KEY_FILE_DESKTOP_KEY_EXEC, NULL); + + /* Validate Name and Exec fields */ + if (G_LIKELY (exec != NULL && name != NULL)) + { + /* Allocate a new action instance */ + action = g_object_new (GARCON_TYPE_MENU_ITEM_ACTION, + "name", name, + "command", exec, + NULL); + + garcon_menu_item_set_action (item, *mt, action); + } + + g_free (action_group); + } + else + g_free (*mt); + } + + /* Cleanup */ + g_free (str_list); + } + + else + { + str_list = xfce_rc_read_list_entry (rc, "X-Ayatana-Desktop-Shortcuts", ";"); + if (G_LIKELY (str_list != NULL)) + { + for (mt = str_list; *mt != NULL; ++mt) + { + if (**mt != '\0') + { + action_group = g_strdup_printf ("%s Shortcut Group", *mt); + xfce_rc_set_group (rc, action_group); + + name = xfce_rc_read_entry (rc, G_KEY_FILE_DESKTOP_KEY_NAME, NULL); + exec = xfce_rc_read_entry_untranslated (rc, G_KEY_FILE_DESKTOP_KEY_EXEC, NULL); + + if (G_LIKELY (exec != NULL && name != NULL)) + { + action = g_object_new (GARCON_TYPE_MENU_ITEM_ACTION, + "name", name, + "command", exec, + NULL); + + garcon_menu_item_set_action (item, *mt, action); + } + + g_free (action_group); + } + else + g_free (*mt); + } + + g_free (str_list); + } + } } /* Cleanup */ @@ -857,18 +941,20 @@ garcon_menu_item_reload_from_file (GarconMenuItem *item, gboolean *affects_the_outside, GError **error) { - XfceRc *rc; - gboolean boolean; - GList *categories = NULL; - GList *lp; - GList *old_categories = NULL; - gchar **mt; - gchar **str_list; - const gchar *string; - const gchar *name; - const gchar *exec; - gchar *filename; - gchar *url_exec = NULL; + XfceRc *rc; + GarconMenuItemAction *action = NULL; + gboolean boolean; + GList *categories = NULL; + GList *lp; + GList *old_categories = NULL; + gchar **mt; + gchar **str_list; + const gchar *string; + const gchar *name; + const gchar *exec; + gchar *filename; + gchar *action_group; + gchar *url_exec = NULL; g_return_val_if_fail (GARCON_IS_MENU_ITEM (item), FALSE); g_return_val_if_fail (G_IS_FILE (file), FALSE); @@ -994,6 +1080,78 @@ garcon_menu_item_reload_from_file (GarconMenuItem *item, item->priv->only_show_in = xfce_rc_read_list_entry (rc, G_KEY_FILE_DESKTOP_KEY_ONLY_SHOW_IN, ";"); item->priv->not_show_in = xfce_rc_read_list_entry (rc, G_KEY_FILE_DESKTOP_KEY_NOT_SHOW_IN, ";"); + /* Update application actions */ + str_list = xfce_rc_read_list_entry (rc, G_KEY_FILE_DESKTOP_KEY_ACTIONS, ";"); + if (G_LIKELY (str_list != NULL)) + { + for (mt = str_list; *mt != NULL; ++mt) + { + if (**mt != '\0') + { + /* Set current desktop action group */ + action_group = g_strdup_printf ("Desktop Action %s", *mt); + xfce_rc_set_group (rc, action_group); + + /* Parse name and exec command */ + name = xfce_rc_read_entry (rc, G_KEY_FILE_DESKTOP_KEY_NAME, NULL); + exec = xfce_rc_read_entry_untranslated (rc, G_KEY_FILE_DESKTOP_KEY_EXEC, NULL); + + /* Validate Name and Exec fields */ + if (G_LIKELY (exec != NULL && name != NULL)) + { + /* Allocate a new action instance */ + action = g_object_new (GARCON_TYPE_MENU_ITEM_ACTION, + "name", name, + "command", exec, + NULL); + + garcon_menu_item_set_action (item, *mt, action); + } + g_free (action_group); + } + else + g_free (*mt); + } + + /* Cleanup */ + g_free (str_list); + } + + else + { + str_list = xfce_rc_read_list_entry (rc, "X-Ayatana-Desktop-Shortcuts", ";"); + if (G_LIKELY (str_list != NULL)) + { + for (mt = str_list; *mt != NULL; ++mt) + { + if (**mt != '\0') + { + action_group = g_strdup_printf ("%s Shortcut Group", *mt); + xfce_rc_set_group (rc, action_group); + + name = xfce_rc_read_entry (rc, G_KEY_FILE_DESKTOP_KEY_NAME, NULL); + exec = xfce_rc_read_entry_untranslated (rc, G_KEY_FILE_DESKTOP_KEY_EXEC, NULL); + + if (G_LIKELY (exec != NULL && name != NULL)) + { + action = g_object_new (GARCON_TYPE_MENU_ITEM_ACTION, + "name", name, + "command", exec, + NULL); + + garcon_menu_item_set_action (item, *mt, action); + } + + g_free (action_group); + } + else + g_free (*mt); + } + + g_free (str_list); + } + } + /* Flush property notifications */ g_object_thaw_notify (G_OBJECT (item)); @@ -1429,6 +1587,56 @@ garcon_menu_item_has_category (GarconMenuItem *item, +GList * +garcon_menu_item_get_actions (GarconMenuItem *item) +{ + g_return_if_fail (GARCON_IS_MENU_ITEM (item)); + + return g_hash_table_get_keys (item->priv->actions); +} + + + +GarconMenuItemAction * +garcon_menu_item_get_action (GarconMenuItem *item, + const gchar *action_name) +{ + g_return_if_fail (GARCON_IS_MENU_ITEM (item)); + + return g_hash_table_lookup (item->priv->actions, action_name); +} + + + + +void +garcon_menu_item_set_action (GarconMenuItem *item, + const gchar *action_name, + GarconMenuItemAction *action) +{ + g_return_if_fail (GARCON_IS_MENU_ITEM (item)); + g_return_if_fail (GARCON_IS_MENU_ITEM_ACTION (action)); + + /* Insert into the hash table and remove old action (if any) */ + g_hash_table_replace (item->priv->actions, g_strdup (action_name), action); + + /* Grab a reference on the action */ + garcon_menu_item_action_ref (action); +} + + + +gboolean +garcon_menu_item_has_action (GarconMenuItem *item, + const gchar *action_name) +{ + g_return_if_fail (GARCON_IS_MENU_ITEM (item)); + + return g_hash_table_contains (item->priv->actions, action_name); +} + + + gboolean garcon_menu_item_get_show_in_environment (GarconMenuItem *item) { diff --git a/garcon/garcon-menu-item.h b/garcon/garcon-menu-item.h index ef17732..9b6b7b3 100644 --- a/garcon/garcon-menu-item.h +++ b/garcon/garcon-menu-item.h @@ -2,6 +2,7 @@ /*- * Copyright (c) 2006-2010 Jannis Pohlmann * Copyright (c) 2009 Nick Schermer + * Copyright (c) 2015 Danila Poyarkov * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -28,6 +29,7 @@ #include #include +#include G_BEGIN_DECLS @@ -60,74 +62,82 @@ struct _GarconMenuItem -GType garcon_menu_item_get_type (void) G_GNUC_CONST; +GType garcon_menu_item_get_type (void) G_GNUC_CONST; -GarconMenuItem *garcon_menu_item_new (GFile *file) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT; -GarconMenuItem *garcon_menu_item_new_for_path (const gchar *filename) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT; -GarconMenuItem *garcon_menu_item_new_for_uri (const gchar *uri) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT; +GarconMenuItem *garcon_menu_item_new (GFile *file) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT; +GarconMenuItem *garcon_menu_item_new_for_path (const gchar *filename) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT; +GarconMenuItem *garcon_menu_item_new_for_uri (const gchar *uri) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT; -gboolean garcon_menu_item_reload (GarconMenuItem *item, +gboolean garcon_menu_item_reload (GarconMenuItem *item, gboolean *affects_the_outside, GError **error); -gboolean garcon_menu_item_reload_from_file (GarconMenuItem *item, +gboolean garcon_menu_item_reload_from_file (GarconMenuItem *item, GFile *file, gboolean *affects_the_outside, GError **error); -GFile *garcon_menu_item_get_file (GarconMenuItem *item); - -gchar *garcon_menu_item_get_uri (GarconMenuItem *item) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT; - -const gchar *garcon_menu_item_get_desktop_id (GarconMenuItem *item); -void garcon_menu_item_set_desktop_id (GarconMenuItem *item, - const gchar *desktop_id); - -const gchar *garcon_menu_item_get_command (GarconMenuItem *item); -void garcon_menu_item_set_command (GarconMenuItem *item, - const gchar *command); -const gchar *garcon_menu_item_get_try_exec (GarconMenuItem *item); -void garcon_menu_item_set_try_exec (GarconMenuItem *item, - const gchar *try_exec); -const gchar *garcon_menu_item_get_name (GarconMenuItem *item); -void garcon_menu_item_set_name (GarconMenuItem *item, - const gchar *name); -const gchar *garcon_menu_item_get_generic_name (GarconMenuItem *item); -void garcon_menu_item_set_generic_name (GarconMenuItem *item, - const gchar *generic_name); -const gchar *garcon_menu_item_get_comment (GarconMenuItem *item); -void garcon_menu_item_set_comment (GarconMenuItem *item, - const gchar *comment); -const gchar *garcon_menu_item_get_icon_name (GarconMenuItem *item); -void garcon_menu_item_set_icon_name (GarconMenuItem *item, - const gchar *icon_name); -const gchar *garcon_menu_item_get_path (GarconMenuItem *item); -void garcon_menu_item_set_path (GarconMenuItem *item, - const gchar *path); -gboolean garcon_menu_item_get_hidden (GarconMenuItem *item); -void garcon_menu_item_set_hidden (GarconMenuItem *item, - gboolean hidden); -gboolean garcon_menu_item_requires_terminal (GarconMenuItem *item); -void garcon_menu_item_set_requires_terminal (GarconMenuItem *item, - gboolean requires_terminal); -gboolean garcon_menu_item_get_no_display (GarconMenuItem *item); -void garcon_menu_item_set_no_display (GarconMenuItem *item, - gboolean no_display); -gboolean garcon_menu_item_supports_startup_notification (GarconMenuItem *item); -void garcon_menu_item_set_supports_startup_notification (GarconMenuItem *item, - gboolean supports_startup_notification); -GList *garcon_menu_item_get_categories (GarconMenuItem *item); -void garcon_menu_item_set_categories (GarconMenuItem *item, - GList *categories); -gboolean garcon_menu_item_has_category (GarconMenuItem *item, - const gchar *category); -gboolean garcon_menu_item_get_show_in_environment (GarconMenuItem *item); -gboolean garcon_menu_item_only_show_in_environment (GarconMenuItem *item); -void garcon_menu_item_ref (GarconMenuItem *item); -void garcon_menu_item_unref (GarconMenuItem *item); -gint garcon_menu_item_get_allocated (GarconMenuItem *item); -void garcon_menu_item_increment_allocated (GarconMenuItem *item); -void garcon_menu_item_decrement_allocated (GarconMenuItem *item); +GFile *garcon_menu_item_get_file (GarconMenuItem *item); + +gchar *garcon_menu_item_get_uri (GarconMenuItem *item) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT; + +const gchar *garcon_menu_item_get_desktop_id (GarconMenuItem *item); +void garcon_menu_item_set_desktop_id (GarconMenuItem *item, + const gchar *desktop_id); + +const gchar *garcon_menu_item_get_command (GarconMenuItem *item); +void garcon_menu_item_set_command (GarconMenuItem *item, + const gchar *command); +const gchar *garcon_menu_item_get_try_exec (GarconMenuItem *item); +void garcon_menu_item_set_try_exec (GarconMenuItem *item, + const gchar *try_exec); +const gchar *garcon_menu_item_get_name (GarconMenuItem *item); +void garcon_menu_item_set_name (GarconMenuItem *item, + const gchar *name); +const gchar *garcon_menu_item_get_generic_name (GarconMenuItem *item); +void garcon_menu_item_set_generic_name (GarconMenuItem *item, + const gchar *generic_name); +const gchar *garcon_menu_item_get_comment (GarconMenuItem *item); +void garcon_menu_item_set_comment (GarconMenuItem *item, + const gchar *comment); +const gchar *garcon_menu_item_get_icon_name (GarconMenuItem *item); +void garcon_menu_item_set_icon_name (GarconMenuItem *item, + const gchar *icon_name); +const gchar *garcon_menu_item_get_path (GarconMenuItem *item); +void garcon_menu_item_set_path (GarconMenuItem *item, + const gchar *path); +gboolean garcon_menu_item_get_hidden (GarconMenuItem *item); +void garcon_menu_item_set_hidden (GarconMenuItem *item, + gboolean hidden); +gboolean garcon_menu_item_requires_terminal (GarconMenuItem *item); +void garcon_menu_item_set_requires_terminal (GarconMenuItem *item, + gboolean requires_terminal); +gboolean garcon_menu_item_get_no_display (GarconMenuItem *item); +void garcon_menu_item_set_no_display (GarconMenuItem *item, + gboolean no_display); +gboolean garcon_menu_item_supports_startup_notification (GarconMenuItem *item); +void garcon_menu_item_set_supports_startup_notification (GarconMenuItem *item, + gboolean supports_startup_notification); +GList *garcon_menu_item_get_categories (GarconMenuItem *item); +void garcon_menu_item_set_categories (GarconMenuItem *item, + GList *categories); +gboolean garcon_menu_item_has_category (GarconMenuItem *item, + const gchar *category); +GList *garcon_menu_item_get_actions (GarconMenuItem *item); +GarconMenuItemAction *garcon_menu_item_get_action (GarconMenuItem *item, + const gchar *action_name); +void garcon_menu_item_set_action (GarconMenuItem *item, + const gchar *action_name, + GarconMenuItemAction *action); +gboolean garcon_menu_item_has_action (GarconMenuItem *item, + const gchar *action_name); +gboolean garcon_menu_item_get_show_in_environment (GarconMenuItem *item); +gboolean garcon_menu_item_only_show_in_environment (GarconMenuItem *item); +void garcon_menu_item_ref (GarconMenuItem *item); +void garcon_menu_item_unref (GarconMenuItem *item); +gint garcon_menu_item_get_allocated (GarconMenuItem *item); +void garcon_menu_item_increment_allocated (GarconMenuItem *item); +void garcon_menu_item_decrement_allocated (GarconMenuItem *item); G_END_DECLS diff --git a/garcon/garcon.h b/garcon/garcon.h index 0a47778..098e694 100644 --- a/garcon/garcon.h +++ b/garcon/garcon.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include diff --git a/tests/test-display-menu.c b/tests/test-display-menu.c index cda576d..eead25d 100644 --- a/tests/test-display-menu.c +++ b/tests/test-display-menu.c @@ -71,6 +71,31 @@ execute_item_command (GtkWidget *widget, +static void +execute_action_command (GtkWidget *widget, + GarconMenuItemAction *action) +{ +#if 0 + GError *error = NULL; +#endif + const gchar *command; + + command = garcon_menu_item_action_get_command (action); + + if (G_UNLIKELY (command == NULL)) + return; + +#if 0 + if (!xfce_exec_on_screen (gdk_screen_get_default (), command, FALSE, FALSE, &error)) + { + xfce_err (error->message); + g_error_free (error); + } +#endif +} + + + static GdkPixbuf* create_item_icon (GarconMenuItem *item) { @@ -170,9 +195,13 @@ static void create_item_widgets (GarconMenuItem *item, GtkWidget *parent_menu) { - GtkWidget *gtk_item; - GtkWidget *image; - GdkPixbuf *icon; + GtkWidget *gtk_item; + GtkWidget *gtk_submenu; + GtkWidget *gtk_action; + GtkWidget *image; + GdkPixbuf *icon; + GList *actions; + GarconMenuItemAction *action; /* Try to load the icon */ icon = create_item_icon (item); @@ -194,6 +223,26 @@ create_item_widgets (GarconMenuItem *item, /* Execute command if item is clicked */ g_signal_connect (gtk_item, "activate", G_CALLBACK (execute_item_command), item); + + /* Create actions submenus */ + actions = garcon_menu_item_get_actions (item); + + if (G_LIKELY (actions != NULL)) + { + gtk_submenu = gtk_menu_new (); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (gtk_item), gtk_submenu); + for (; actions != NULL; actions = actions->next) + { + action = garcon_menu_item_get_action (item, actions->data); + gtk_action = gtk_menu_item_new_with_label (garcon_menu_item_action_get_name (action)); + gtk_menu_shell_append (GTK_MENU_SHELL (gtk_submenu), gtk_action); + gtk_widget_show (gtk_action); + + /* Execute command if action is clicked */ + g_signal_connect (gtk_action, "activate", G_CALLBACK (execute_action_command), action); + } + g_list_free (actions); + } }