From 59168f3c1a72f610b693cd1ed4cfa5fac281079a Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Wed, 6 Nov 2013 14:48:19 +0100 Subject: [PATCH] Add UbuntuMenuItemFactory UbuntuMenuItemFactory is an interface for creating widgets for menu items in a GMenuModel that have an 'x-canonical-type' attribute. It is needed by unity and should not be considered public API. --- gtk/Makefile.am | 3 ++ gtk/gtkmenushell.c | 69 ++++++++++++++++++++++++++++++++++++++++++++ gtk/gtkmenutrackeritem.c | 16 +++++++++++ gtk/gtkmenutrackeritem.h | 4 +++ gtk/ubuntu-private.h | 32 +++++++++++++++++++++ gtk/ubuntumenuitemfactory.c | 70 +++++++++++++++++++++++++++++++++++++++++++++ gtk/ubuntumenuitemfactory.h | 61 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 255 insertions(+) create mode 100644 gtk/ubuntu-private.h create mode 100644 gtk/ubuntumenuitemfactory.c create mode 100644 gtk/ubuntumenuitemfactory.h diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 51153e6..3c01638 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -108,6 +108,8 @@ include $(srcdir)/inspector/Makefile.inc gtk_public_h_sources = \ gtk.h \ gtk-autocleanups.h \ + ubuntu-private.h \ + ubuntumenuitemfactory.h \ gtkx.h \ gtkx-autocleanups.h \ gtk-a11y.h \ @@ -528,6 +530,7 @@ gtk_base_c_sources = \ $(a11y_c_sources) \ $(deprecated_c_sources) \ $(inspector_c_sources) \ + ubuntumenuitemfactory.c \ gtkactionmuxer.c \ gtkactionobserver.c \ gtkactionobservable.c \ diff --git a/gtk/gtkmenushell.c b/gtk/gtkmenushell.c index e1ba138..6d7a2f6 100644 --- a/gtk/gtkmenushell.c +++ b/gtk/gtkmenushell.c @@ -80,6 +80,8 @@ #include "a11y/gtkmenushellaccessible.h" +#include "ubuntu-private.h" + #define MENU_SHELL_TIMEOUT 500 #define MENU_POPUP_DELAY 225 @@ -2044,6 +2046,58 @@ gtk_menu_shell_tracker_remove_func (gint position, gtk_widget_destroy (child); } +static GtkWidget * +create_custom_menu_item (GMenuItem *item, + GtkWidget *parent, + const gchar *action_namespace) +{ + gchar *type; + GActionGroup *actions; + GtkMenuItem *widget = NULL; + GList *it; + + g_menu_item_get_attribute (item, "x-canonical-type", "s", &type); + + if (action_namespace) + { + gchar *action; + + /* Rewrite the menu item to include the fully qualified action + * name to make writing widgets easier. This won't break, as + * we don't use the tracker item for custom items. + */ + if (g_menu_item_get_attribute (item, "action", "s", &action)) + { + gchar *fullname; + + fullname = g_strconcat (action_namespace, ".", action, NULL); + g_menu_item_set_attribute (item, "action", "s", fullname); + + g_free (fullname); + g_free (action); + } + } + + /* Passing the parent muxer is wrong, but we'll only have access + * to the menuitem's muxer after the widget has been created. + * Thus we'd need some other form of passing the action group to + * the widget, which would complicate things for no practical + * reason: the panel service is the only consumer of this API and + * it will never call gtk_widget_insert_action_group() on the + * returned menu item. + */ + actions = G_ACTION_GROUP (_gtk_widget_get_action_muxer (parent, TRUE)); + + for (it = ubuntu_menu_item_factory_get_all (); it != NULL && widget == NULL; it = it->next) + widget = ubuntu_menu_item_factory_create_menu_item (it->data, type, item, actions); + + if (widget == NULL) + g_warning ("Cannot create custom menu item of type '%s'", type); + + g_free (type); + return GTK_WIDGET (widget); +} + static void gtk_menu_shell_tracker_insert_func (GtkMenuTrackerItem *item, gint position, @@ -2051,6 +2105,9 @@ gtk_menu_shell_tracker_insert_func (GtkMenuTrackerItem *item, { GtkMenuShell *menu_shell = user_data; GtkWidget *widget; + GMenuItem *menuitem; + + menuitem = gtk_menu_tracker_item_get_menu_item (item); if (gtk_menu_tracker_item_get_is_separator (item)) { @@ -2112,6 +2169,18 @@ gtk_menu_shell_tracker_insert_func (GtkMenuTrackerItem *item, gtk_widget_show (widget); } + else if (g_menu_item_get_attribute (menuitem, "x-canonical-type", "s", NULL)) + { + const gchar *namespace; + + namespace = gtk_menu_tracker_item_get_action_namespace (item); + widget = create_custom_menu_item (menuitem, GTK_WIDGET (menu_shell), namespace); + + if (widget == NULL) + return; + + gtk_widget_show (widget); + } else { widget = gtk_model_menu_item_new (); diff --git a/gtk/gtkmenutrackeritem.c b/gtk/gtkmenutrackeritem.c index c304b66..cd0c796 100644 --- a/gtk/gtkmenutrackeritem.c +++ b/gtk/gtkmenutrackeritem.c @@ -979,3 +979,19 @@ gtk_menu_tracker_item_may_disappear (GtkMenuTrackerItem *self) { return self->hidden_when != HIDDEN_NEVER; } + +GMenuItem * +gtk_menu_tracker_item_get_menu_item (GtkMenuTrackerItem *self) +{ + g_return_val_if_fail (GTK_IS_MENU_TRACKER_ITEM (self), NULL); + + return self->item; +} + +const gchar * +gtk_menu_tracker_item_get_action_namespace (GtkMenuTrackerItem *self) +{ + g_return_val_if_fail (GTK_IS_MENU_TRACKER_ITEM (self), NULL); + + return self->action_namespace; +} diff --git a/gtk/gtkmenutrackeritem.h b/gtk/gtkmenutrackeritem.h index 6b4fcb5..d74fe92 100644 --- a/gtk/gtkmenutrackeritem.h +++ b/gtk/gtkmenutrackeritem.h @@ -92,4 +92,8 @@ void gtk_menu_tracker_item_request_submenu_shown (GtkMenu gboolean gtk_menu_tracker_item_get_submenu_shown (GtkMenuTrackerItem *self); +GMenuItem * gtk_menu_tracker_item_get_menu_item (GtkMenuTrackerItem *self); + +const gchar * gtk_menu_tracker_item_get_action_namespace (GtkMenuTrackerItem *self); + #endif -- 2.1.4