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

Subscribers

People subscribed via source and target branches

to all changes: