Merge lp:~larsu/gtk/custom-menu-items-v2 into lp:~ubuntu-desktop/gtk/ubuntugtk3

Proposed by Lars Karlitski
Status: Merged
Merged at revision: 269
Proposed branch: lp:~larsu/gtk/custom-menu-items-v2
Merge into: lp:~ubuntu-desktop/gtk/ubuntugtk3
Diff against target: 439 lines (+335/-62)
1 file modified
debian/patches/ubuntu_gtk_custom_menu_items.patch (+335/-62)
To merge this branch: bzr merge lp:~larsu/gtk/custom-menu-items-v2
Reviewer Review Type Date Requested Status
Sebastien Bacher Approve
Review via email: mp+165597@code.launchpad.net

Description of the change

Update custom menu items patch

The previous version simply interpreted the value of the "x-canonical-type"
attribute on a menu item as a GType string and instantiated an instance of
that. We need something more sophisticated now, because GMenuModel is used by
things that don't integrate with glib's type system. (In particular, the next
unity will be a consumer of the indicator services.)

This new patch adds an extension point to gtk. Libraries or programs can
register to implement this extension point and supply an object with the
GtkMenuItemFactory interface. Gtk will ask those factories to create menu items
whenever it stumbles on a "x-canonical-type" attribute.

To post a comment you must log in.
lp:~larsu/gtk/custom-menu-items-v2 updated
269. By Lars Karlitski

GtkMenuItemFactory -> UbuntuMenuItemFactory

Also moves the header from gtk.h to ubuntu-private.h, to make more explicit
that this should not be used from anyone except unity.

Revision history for this message
William Hua (attente) wrote :

The patch also needs to update gtk/gtk.symbols with the new functions in order to build the packaging properly.

See:

5935 --- expected-abi 2013-05-27 11:42:17.616520780 -0400
5936 +++ actual-abi 2013-05-27 11:42:17.652520780 -0400
5937 @@ -4022,6 +4022,8 @@
5938 gtk_wrap_mode_get_type
5939 ubuntu_gtk_menu_shell_activate_first
5940 ubuntu_gtk_menu_shell_activate_mnemonic
5941 +ubuntu_menu_item_factory_create_menu_item
5942 +ubuntu_menu_item_factory_get_type
5943 ubuntu_menu_proxy_activate_menu
5944 ubuntu_menu_proxy_get
5945 ubuntu_menu_proxy_get_type
5946 FAIL: abicheck.sh

lp:~larsu/gtk/custom-menu-items-v2 updated
270. By Lars Karlitski

Add UbuntuMenuItemFactory symbols to gtk/gtk.symbols

Revision history for this message
Sebastien Bacher (seb128) wrote :

Thanks Lars, I merged that with the corresponding packaging change and I'm upload to Ubuntu

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'debian/patches/ubuntu_gtk_custom_menu_items.patch'
--- debian/patches/ubuntu_gtk_custom_menu_items.patch 2012-09-19 01:20:28 +0000
+++ debian/patches/ubuntu_gtk_custom_menu_items.patch 2013-05-29 14:48:24 +0000
@@ -1,64 +1,171 @@
1# Description: gtk_menu_new_from_model doesn't support custom menu items1From 311cf9c2fd6bbc303c816585cfc4986cdee2db52 Mon Sep 17 00:00:00 2001
2# Ubuntu: https://bugs.launchpad.net/ubuntu/+source/gtk+3.0/+bug/10394762From: Lars Uebernickel <lars.uebernickel@canonical.com>
3#3Date: Wed, 8 May 2013 13:21:55 -0700
4Index: gtk+-3.5.18/gtk/gtkmodelmenu.c4Subject: [PATCH] Allow custom menu items from gtk_menu_new_from_model
5===================================================================5
6--- gtk+-3.5.18.orig/gtk/gtkmodelmenu.c 2012-09-19 03:34:42.000000000 +12006Provide UbuntuMenuItemFactory, an interface that can be implemented by
7+++ gtk+-3.5.18/gtk/gtkmodelmenu.c 2012-09-19 12:18:50.524724208 +12007extension points. It has one function: create a GtkMenuItem for a
8@@ -28,6 +28,7 @@8GMenuItem and a GActionGroup, keyed by the type given in the
9x-canonical-type attribute.
10
11This is not considered to be public API.
12---
13 gtk/Makefile.am | 3 +
14 gtk/gtk.symbols | 2 +
15 gtk/gtkmodelmenu.c | 147 +++++++++++++++++++++++++++++++++++++++++++-
16 gtk/ubuntu-private.h | 32 ++++++++++
17 gtk/ubuntumenuitemfactory.c | 38 ++++++++++++
18 gtk/ubuntumenuitemfactory.h | 57 +++++++++++++++++
19 6 files changed, 278 insertions(+), 1 deletion(-)
20 create mode 100644 gtk/ubuntu-private.h
21 create mode 100644 gtk/ubuntumenuitemfactory.c
22 create mode 100644 gtk/ubuntumenuitemfactory.h
23
24diff --git a/gtk/Makefile.am b/gtk/Makefile.am
25index e164c90..304e252 100644
26--- a/gtk/Makefile.am
27+++ b/gtk/Makefile.am
28@@ -175,6 +175,7 @@ deprecated_private_h_sources = \
29
30 gtk_public_h_sources = \
31 gtk.h \
32+ ubuntu-private.h \
33 gtkx.h \
34 gtk-a11y.h \
35 gtkaboutdialog.h \
36@@ -277,6 +278,7 @@ gtk_public_h_sources = \
37 gtklockbutton.h \
38 gtkmain.h \
39 gtkmenu.h \
40+ ubuntumenuitemfactory.h \
41 gtkmenubar.h \
42 gtkmenubutton.h \
43 gtkmenuitem.h \
44@@ -765,6 +767,7 @@ gtk_base_c_sources = \
45 gtkmisc.c \
46 gtkmnemonichash.c \
47 gtkmodelmenu.c \
48+ ubuntumenuitemfactory.c \
49 gtkmodelmenuitem.c \
50 gtkmodifierstyle.c \
51 gtkmodules.c \
52diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols
53index 030a06c..711b6ba 100644
54--- a/gtk/gtk.symbols
55+++ b/gtk/gtk.symbols
56@@ -4055,3 +4055,5 @@ gtk_window_unfullscreen
57 gtk_window_unmaximize
58 gtk_window_unstick
59 gtk_wrap_mode_get_type
60+ubuntu_menu_item_factory_get_type
61+ubuntu_menu_item_factory_create_menu_item
62diff --git a/gtk/gtkmodelmenu.c b/gtk/gtkmodelmenu.c
63index 0c3cc5e..2b6899b 100644
64--- a/gtk/gtkmodelmenu.c
65+++ b/gtk/gtkmodelmenu.c
66@@ -28,6 +28,8 @@
9 #include "gtkseparatormenuitem.h"67 #include "gtkseparatormenuitem.h"
10 #include "gtkmodelmenuitem.h"68 #include "gtkmodelmenuitem.h"
11 #include "gtkapplicationprivate.h"69 #include "gtkapplicationprivate.h"
12+#include "gtkwidgetprivate.h"70+#include "gtkwidgetprivate.h"
71+#include "ubuntumenuitemfactory.h"
13 72
14 #define MODEL_MENU_WIDGET_DATA "gtk-model-menu-widget-data"73 #define MODEL_MENU_WIDGET_DATA "gtk-model-menu-widget-data"
15 74
16@@ -72,6 +73,80 @@75@@ -72,6 +74,146 @@ gtk_model_menu_binding_free (gpointer data)
17 g_slice_free (GtkModelMenuBinding, binding);76 g_slice_free (GtkModelMenuBinding, binding);
18 }77 }
19 78
79+static gboolean
80+object_class_has_property (GObjectClass *class,
81+ const gchar *name,
82+ GType type)
83+{
84+ GParamSpec *pspec;
85+
86+ pspec = g_object_class_find_property (class, name);
87+ return pspec != NULL && G_PARAM_SPEC_VALUE_TYPE (pspec) == type;
88+}
89+
90+static GtkMenuItem *
91+gtk_model_menu_create_item_from_type (GType type,
92+ GMenuItem *menuitem)
93+{
94+ GObjectClass *class;
95+ GtkMenuItem *item = NULL;
96+
97+ class = g_type_class_ref (type);
98+
99+ if (g_type_is_a (type, GTK_TYPE_MENU_ITEM) &&
100+ object_class_has_property (class, "menu-item", G_TYPE_MENU_ITEM) &&
101+ object_class_has_property (class, "action-group", G_TYPE_ACTION_GROUP))
102+ {
103+ item = g_object_new (type,
104+ "menu-item", menuitem,
105+ NULL);
106+
107+ g_object_set (item,
108+ "action-group", _gtk_widget_get_action_muxer (GTK_WIDGET (item)),
109+ NULL);
110+ }
111+ else
112+ {
113+ g_warning ("gtk_menu_new_from_model: cannot create menu item from type '%s'.\n"
114+ " Does it derive from GtkMenuItem and have 'menu-item' and 'action-group' properties?",
115+ g_type_name (type));
116+ }
117+
118+ g_type_class_unref (class);
119+ return item;
120+}
121+
122+static GtkMenuItem *
123+gtk_model_menu_create_custom_item_from_factory (const gchar *typename,
124+ GMenuItem *menuitem,
125+ GActionGroup *actions)
126+{
127+ GList *it;
128+ static GList *factories = NULL;
129+
130+ if (factories == NULL)
131+ {
132+ GIOExtensionPoint *ep;
133+
134+ g_type_ensure (UBUNTU_TYPE_MENU_ITEM_FACTORY);
135+ ep = g_io_extension_point_lookup (UBUNTU_MENU_ITEM_FACTORY_EXTENSION_POINT_NAME);
136+ for (it = g_io_extension_point_get_extensions (ep); it != NULL; it = it->next)
137+ {
138+ GIOExtension *ext = it->data;
139+ UbuntuMenuItemFactory *factory;
140+
141+ factory = g_object_new (g_io_extension_get_type (ext), NULL);
142+ factories = g_list_prepend (factories, factory);
143+ }
144+ factories = g_list_reverse (factories);
145+ }
146+
147+ for (it = factories; it != NULL; it = it->next)
148+ {
149+ UbuntuMenuItemFactory *factory = it->data;
150+ GtkMenuItem *item;
151+
152+ item = ubuntu_menu_item_factory_create_menu_item (factory, typename, menuitem, actions);
153+ if (item)
154+ return item;
155+ }
156+
157+ return NULL;
158+}
159+
20+static GtkMenuItem *160+static GtkMenuItem *
21+gtk_model_menu_create_custom_item (GMenuModel *menu,161+gtk_model_menu_create_custom_item (GMenuModel *menu,
22+ gint item_index,162+ gint item_index,
23+ const gchar *action_namespace)163+ const gchar *action_namespace,
164+ GtkWidget *parent)
24+{165+{
166+ GMenuItem *menuitem;
167+ gchar *typename;
25+ GtkMenuItem *item = NULL;168+ GtkMenuItem *item = NULL;
26+ gchar *typename = NULL;
27+ GType type;
28+ GObjectClass *class = NULL;
29+ GParamSpec *pspec;
30+ GMenuItem *menuitem = NULL;
31+
32+ if (!g_menu_model_get_item_attribute (menu, item_index, "x-canonical-type", "s", &typename))
33+ return NULL;
34+
35+ type = g_type_from_name (typename);
36+ if (type == 0)
37+ {
38+ g_warning ("gtk_menu_new_from_model: cannot find type '%s'", typename);
39+ goto out;
40+ }
41+ if (!g_type_is_a (type, GTK_TYPE_MENU_ITEM))
42+ {
43+ g_warning ("gtk_menu_new_from_model: '%s' is not derived from GtkMenuItem", typename);
44+ goto out;
45+ }
46+
47+ class = g_type_class_ref (type);
48+
49+ pspec = g_object_class_find_property (class, "menu-item");
50+ if (pspec == NULL || G_PARAM_SPEC_VALUE_TYPE (pspec) != G_TYPE_MENU_ITEM)
51+ {
52+ g_warning ("gtk_menu_new_from_model: '%s' does not have a 'menu-item' property", typename);
53+ goto out;
54+ }
55+
56+ pspec = g_object_class_find_property (class, "action-group");
57+ if (pspec == NULL || G_PARAM_SPEC_VALUE_TYPE (pspec) != G_TYPE_ACTION_GROUP)
58+ {
59+ g_warning ("gtk_menu_new_from_model: '%s' does not have an 'action-group' property", typename);
60+ goto out;
61+ }
62+169+
63+ menuitem = g_menu_item_new_from_model (menu, item_index);170+ menuitem = g_menu_item_new_from_model (menu, item_index);
64+ if (action_namespace)171+ if (action_namespace)
@@ -74,35 +181,201 @@
74+ g_free (fullname);181+ g_free (fullname);
75+ }182+ }
76+183+
77+ item = g_object_new (type,184+ if (g_menu_model_get_item_attribute (menu, item_index, "x-canonical-type", "s", &typename))
78+ "menu-item", menuitem,185+ {
79+ NULL);186+ GActionGroup *actions;
80+187+
81+ g_object_set (item,188+ /* Passing the parent muxer is wrong, but we'll only have access
82+ "action-group", _gtk_widget_get_action_muxer (GTK_WIDGET (item)),189+ * to the menuitem's muxer after the widget has been created.
83+ NULL);190+ * Thus we'd need some other form of passing the action group to
84+191+ * the widget, which would complicate things for no practical
85+out:192+ * reason: the panel service is the only consumer of this API and
86+ if (menuitem)193+ * it will never call gtk_widget_insert_action_group() on the
87+ g_object_unref (menuitem);194+ * returned menu item.
88+ if (class)195+ */
89+ g_type_class_unref (class);196+ actions = G_ACTION_GROUP (_gtk_widget_get_action_muxer (parent));
90+ g_free (typename);197+ item = gtk_model_menu_create_custom_item_from_factory (typename, menuitem, actions);
198+
199+ /* continue supporting GTypes for now (the "old" behavior) */
200+ if (item == NULL)
201+ {
202+ GType type;
203+
204+ type = g_type_from_name (typename);
205+ if (type > 0)
206+ item = gtk_model_menu_create_item_from_type (type, menuitem);
207+ }
208+
209+ if (item == NULL)
210+ g_warning ("gtk_menu_new_from_model: cannot find type '%s'", typename);
211+
212+ g_free (typename);
213+ }
214+
215+ g_object_unref (menuitem);
91+ return item;216+ return item;
92+}217+}
93+218+
94 static void219 static void
95 gtk_model_menu_binding_append_item (GtkModelMenuBinding *binding,220 gtk_model_menu_binding_append_item (GtkModelMenuBinding *binding,
96 GMenuModel *model,221 GMenuModel *model,
97@@ -106,7 +181,10 @@222@@ -106,7 +248,10 @@ gtk_model_menu_binding_append_item (GtkModelMenuBinding *binding,
98 {223 {
99 GtkMenuItem *item;224 GtkMenuItem *item;
100 225
101- item = gtk_model_menu_item_new (model, item_index, action_namespace);226- item = gtk_model_menu_item_new (model, item_index, action_namespace);
102+ item = gtk_model_menu_create_custom_item (model, item_index, action_namespace);227+ item = gtk_model_menu_create_custom_item (model, item_index, action_namespace, GTK_WIDGET (binding->shell));
103+ if (item == NULL)228+ if (item == NULL)
104+ item = gtk_model_menu_item_new (model, item_index, action_namespace);229+ item = gtk_model_menu_item_new (model, item_index, action_namespace);
105+230+
106 gtk_menu_shell_append (binding->shell, GTK_WIDGET (item));231 gtk_menu_shell_append (binding->shell, GTK_WIDGET (item));
107 gtk_widget_show (GTK_WIDGET (item));232 gtk_widget_show (GTK_WIDGET (item));
108 binding->n_items++;233 binding->n_items++;
234diff --git a/gtk/ubuntu-private.h b/gtk/ubuntu-private.h
235new file mode 100644
236index 0000000..3ed366f
237--- /dev/null
238+++ b/gtk/ubuntu-private.h
239@@ -0,0 +1,32 @@
240+/*
241+* Copyright 2013 Canonical Ltd.
242+*
243+* This program is free software: you can redistribute it and/or modify it
244+* under the terms of the GNU General Public License version 3, as published
245+* by the Free Software Foundation.
246+*
247+* This program is distributed in the hope that it will be useful, but
248+* WITHOUT ANY WARRANTY; without even the implied warranties of
249+* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
250+* PURPOSE. See the GNU General Public License for more details.
251+*
252+* You should have received a copy of the GNU General Public License along
253+* with this program. If not, see <http://www.gnu.org/licenses/>.
254+*
255+* Authors:
256+* Lars Uebernickel <lars.uebernickel@canonical.com>
257+*/
258+
259+/*
260+ * Warning: this file is not part of gtk+, but an Ubuntu-specific extension.
261+ * The API provided here is meant to be used only from Unity.
262+ *
263+ * Applications should not use this.
264+ */
265+
266+#ifndef __UBUNTU_PRIVATE_H__
267+#define __UBUNTU_PRIVATE_H__
268+
269+#include "ubuntumenuitemfactory.h"
270+
271+#endif
272diff --git a/gtk/ubuntumenuitemfactory.c b/gtk/ubuntumenuitemfactory.c
273new file mode 100644
274index 0000000..65de84a
275--- /dev/null
276+++ b/gtk/ubuntumenuitemfactory.c
277@@ -0,0 +1,38 @@
278+/*
279+* Copyright 2013 Canonical Ltd.
280+*
281+* This program is free software: you can redistribute it and/or modify it
282+* under the terms of the GNU General Public License version 3, as published
283+* by the Free Software Foundation.
284+*
285+* This program is distributed in the hope that it will be useful, but
286+* WITHOUT ANY WARRANTY; without even the implied warranties of
287+* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
288+* PURPOSE. See the GNU General Public License for more details.
289+*
290+* You should have received a copy of the GNU General Public License along
291+* with this program. If not, see <http://www.gnu.org/licenses/>.
292+*
293+* Authors:
294+* Lars Uebernickel <lars.uebernickel@canonical.com>
295+*/
296+
297+#include "ubuntumenuitemfactory.h"
298+
299+G_DEFINE_INTERFACE_WITH_CODE (UbuntuMenuItemFactory, ubuntu_menu_item_factory, G_TYPE_OBJECT,
300+ GIOExtensionPoint *ep = g_io_extension_point_register (UBUNTU_MENU_ITEM_FACTORY_EXTENSION_POINT_NAME);
301+ g_io_extension_point_set_required_type (ep, g_define_type_id);)
302+
303+static void
304+ubuntu_menu_item_factory_default_init (UbuntuMenuItemFactoryInterface *iface)
305+{
306+}
307+
308+GtkMenuItem *
309+ubuntu_menu_item_factory_create_menu_item (UbuntuMenuItemFactory *factory,
310+ const gchar *type,
311+ GMenuItem *menuitem,
312+ GActionGroup *actions)
313+{
314+ return UBUNTU_MENU_ITEM_FACTORY_GET_IFACE (factory)->create_menu_item (factory, type, menuitem, actions);
315+}
316diff --git a/gtk/ubuntumenuitemfactory.h b/gtk/ubuntumenuitemfactory.h
317new file mode 100644
318index 0000000..e6f93c0
319--- /dev/null
320+++ b/gtk/ubuntumenuitemfactory.h
321@@ -0,0 +1,57 @@
322+/*
323+* Copyright 2013 Canonical Ltd.
324+*
325+* This program is free software: you can redistribute it and/or modify it
326+* under the terms of the GNU General Public License version 3, as published
327+* by the Free Software Foundation.
328+*
329+* This program is distributed in the hope that it will be useful, but
330+* WITHOUT ANY WARRANTY; without even the implied warranties of
331+* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
332+* PURPOSE. See the GNU General Public License for more details.
333+*
334+* You should have received a copy of the GNU General Public License along
335+* with this program. If not, see <http://www.gnu.org/licenses/>.
336+*
337+* Authors:
338+* Lars Uebernickel <lars.uebernickel@canonical.com>
339+*/
340+
341+#ifndef __UBUNTU_MENU_ITEM_FACTORY_H__
342+#define __UBUNTU_MENU_ITEM_FACTORY_H__
343+
344+#include <gio/gio.h>
345+#include "gtkmenuitem.h"
346+
347+G_BEGIN_DECLS
348+
349+#define UBUNTU_TYPE_MENU_ITEM_FACTORY (ubuntu_menu_item_factory_get_type ())
350+#define UBUNTU_MENU_ITEM_FACTORY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), UBUNTU_TYPE_MENU_ITEM_FACTORY, UbuntuMenuItemFactory))
351+#define UBUNTU_IS_MENU_ITEM_FACTORY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), UBUNTU_TYPE_MENU_ITEM_FACTORY))
352+#define UBUNTU_MENU_ITEM_FACTORY_GET_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), UBUNTU_TYPE_MENU_ITEM_FACTORY, UbuntuMenuItemFactoryInterface))
353+
354+#define UBUNTU_MENU_ITEM_FACTORY_EXTENSION_POINT_NAME "ubuntu-menu-item-factory"
355+
356+typedef struct _UbuntuMenuItemFactoryInterface UbuntuMenuItemFactoryInterface;
357+typedef struct _UbuntuMenuItemFactory UbuntuMenuItemFactory;
358+
359+struct _UbuntuMenuItemFactoryInterface
360+{
361+ GTypeInterface iface;
362+
363+ GtkMenuItem * (*create_menu_item) (UbuntuMenuItemFactory *factory,
364+ const gchar *type,
365+ GMenuItem *menuitem,
366+ GActionGroup *actions);
367+};
368+
369+GType ubuntu_menu_item_factory_get_type (void);
370+
371+GtkMenuItem * ubuntu_menu_item_factory_create_menu_item (UbuntuMenuItemFactory *factory,
372+ const gchar *type,
373+ GMenuItem *menuitem,
374+ GActionGroup *actions);
375+
376+G_END_DECLS
377+
378+#endif
379--
3801.8.1.2
381

Subscribers

People subscribed via source and target branches

to all changes: