Merge lp:~ted/libdbusmenu/types into lp:libdbusmenu/0.5

Proposed by Ted Gould
Status: Merged
Merged at revision: not available
Proposed branch: lp:~ted/libdbusmenu/types
Merge into: lp:libdbusmenu/0.5
Diff against target: None lines
To merge this branch: bzr merge lp:~ted/libdbusmenu/types
Reviewer Review Type Date Requested Status
Neil J. Patel (community) Approve
Review via email: mp+10772@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Ted Gould (ted) wrote :

Adds a simple system for extending the menu items to the point where it can say "I handle these types." Then use this in the gtk version of the library to add separators and a shell for images in the future. Also now we handle visibility.

lp:~ted/libdbusmenu/types updated
32. By Ted Gould

Promoting the base function up to an API function so that it can be used else where.

33. By Ted Gould

Adding a public accessor for getting the gtk client

Revision history for this message
Neil J. Patel (njpatel) wrote :

Looks good. I had some suggestions/questions:

menuitem_get_properties_new_cb:
  - I'd normally check that data != NULL before accessing its members

menuitem_call_cb:
  - I'd, normally check that returned pointer from g_new0 != NULL

dbusmenu_client_add_type_handler:
  - Would a check for type!= NULL make sense here, as you use it to lookup in the hashtable?
  - Does newfunc need to also be checked? Or is is okay to add a NULL func (i.e. to unset a previously set function)?

new_item_seperator & new_item_normal:
  - Are arg checks required for newitem, parent and client?

child_realized:
  - I'd have g_return_if_fail (DBUS_MENU_GTKMENU (userdata)) before casting it as its a signal callback

review: Needs Information
Revision history for this message
Ted Gould (ted) wrote :

On Thu, 2009-08-27 at 11:33 +0000, Neil J. Patel wrote:
> menuitem_get_properties_new_cb:
> - I'd normally check that data != NULL before accessing its members

Fixed. (r34)

> menuitem_call_cb:
> - I'd, normally check that returned pointer from g_new0 != NULL

Do you mean "parse_layout_xml"? I believe that is the only call to
g_new0 in client.c, fixed :) (r35)

> dbusmenu_client_add_type_handler:
> - Would a check for type!= NULL make sense here, as you use it to lookup in the hashtable?

Fixed. (r36)

> - Does newfunc need to also be checked? Or is is okay to add a NULL func (i.e. to unset a previously set function)?

No, I think it's okay to have a NULL function. We check when it's
pulled out, so there's no risk. I'm not sure why you'd WANT to do that,
but I don't see any reason to restrict it.

> new_item_seperator & new_item_normal:
> - Are arg checks required for newitem, parent and client?

They're basically internal functions... but since people will probably
steal that code as examples when they make their own external ones it
makes sense to have it there, so they include it. (r37)

> child_realized:
> - I'd have g_return_if_fail (DBUS_MENU_GTKMENU (userdata)) before casting it as its a signal callback

I used DBUSMENU_IS_GTKMENU, but yeah. (r38)

lp:~ted/libdbusmenu/types updated
34. By Ted Gould

Comment for Neil. Checking data.

35. By Ted Gould

Check the return of g_new0 for NULL. Comment by Neil.

36. By Ted Gould

Making sure that type is not NULL. Comment from Neil.

37. By Ted Gould

Adding checks to the type handling functions in GTK+ version of the lib. Comments by Neil.

38. By Ted Gould

Checking the menu is a GTK menu before casting it. Comments by Neil.

Revision history for this message
Neil J. Patel (njpatel) wrote :

> > menuitem_call_cb:
> > - I'd, normally check that returned pointer from g_new0 != NULL
>
> Do you mean "parse_layout_xml"? I believe that is the only call to
> g_new0 in client.c, fixed :) (r35)
>

yes :)

> > child_realized:
> > - I'd have g_return_if_fail (DBUS_MENU_GTKMENU (userdata)) before casting
> it as its a signal callback
>
> I used DBUSMENU_IS_GTKMENU, but yeah. (r38)

Thankfully one of us woke up this morning :)

Approved.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'configure.ac'
2--- configure.ac 2009-06-24 17:35:35 +0000
3+++ configure.ac 2009-08-26 21:31:40 +0000
4@@ -5,7 +5,7 @@
5 AC_PREREQ(2.53)
6
7 AM_CONFIG_HEADER(config.h)
8-AM_INIT_AUTOMAKE(libdbusmenu, 0.0.1)
9+AM_INIT_AUTOMAKE(libdbusmenu, 0.0.2)
10
11 AM_MAINTAINER_MODE
12
13@@ -19,6 +19,8 @@
14 AC_SUBST(VERSION)
15 AC_CONFIG_MACRO_DIR([m4])
16
17+m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
18+
19 ###########################
20 # Dependencies - GLib
21 ###########################
22
23=== modified file 'libdbusmenu-glib/client.c'
24--- libdbusmenu-glib/client.c 2009-07-20 21:34:39 +0000
25+++ libdbusmenu-glib/client.c 2009-08-26 20:42:27 +0000
26@@ -68,6 +68,16 @@
27 DBusGProxyCall * layoutcall;
28
29 DBusGProxy * dbusproxy;
30+
31+ GHashTable * type_handlers;
32+};
33+
34+typedef struct _newItemPropData newItemPropData;
35+struct _newItemPropData
36+{
37+ DbusmenuClient * client;
38+ DbusmenuMenuitem * item;
39+ DbusmenuMenuitem * parent;
40 };
41
42 #define DBUSMENU_CLIENT_GET_PRIVATE(o) \
43@@ -187,6 +197,9 @@
44
45 priv->dbusproxy = NULL;
46
47+ priv->type_handlers = g_hash_table_new_full(g_str_hash, g_str_equal,
48+ g_free, NULL);
49+
50 return;
51 }
52
53@@ -230,6 +243,10 @@
54 g_free(priv->dbus_name);
55 g_free(priv->dbus_object);
56
57+ if (priv->type_handlers != NULL) {
58+ g_hash_table_destroy(priv->type_handlers);
59+ }
60+
61 G_OBJECT_CLASS (dbusmenu_client_parent_class)->finalize (object);
62 return;
63 }
64@@ -515,6 +532,43 @@
65 return;
66 }
67
68+/* This is a different get properites call back that also sends
69+ new signals. It basically is a small wrapper around the original. */
70+static void
71+menuitem_get_properties_new_cb (DBusGProxy * proxy, GHashTable * properties, GError * error, gpointer data)
72+{
73+ newItemPropData * propdata = (newItemPropData *)data;
74+ DbusmenuClientPrivate * priv = DBUSMENU_CLIENT_GET_PRIVATE(propdata->client);
75+
76+ menuitem_get_properties_cb (proxy, properties, error, propdata->item);
77+
78+ gboolean handled = FALSE;
79+
80+ const gchar * type;
81+ DbusmenuClientTypeHandler newfunc = NULL;
82+
83+ type = dbusmenu_menuitem_property_get(propdata->item, "type");
84+ if (type != NULL) {
85+ newfunc = g_hash_table_lookup(priv->type_handlers, type);
86+ } else {
87+ newfunc = g_hash_table_lookup(priv->type_handlers, DBUSMENU_CLIENT_TYPES_DEFAULT);
88+ }
89+
90+ if (newfunc != NULL) {
91+ handled = newfunc(propdata->item, propdata->parent, propdata->client);
92+ }
93+
94+ g_signal_emit(G_OBJECT(propdata->item), DBUSMENU_MENUITEM_SIGNAL_REALIZED_ID, 0, TRUE);
95+
96+ if (!handled) {
97+ g_signal_emit(G_OBJECT(propdata->client), signals[NEW_MENUITEM], 0, propdata->item, TRUE);
98+ }
99+
100+ g_free(propdata);
101+
102+ return;
103+}
104+
105 static void
106 menuitem_call_cb (DBusGProxy * proxy, GError * error, gpointer userdata)
107 {
108@@ -562,9 +616,15 @@
109 dbusmenu_menuitem_set_root(item, TRUE);
110 }
111 g_signal_connect(G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(menuitem_activate), client);
112- g_signal_emit(G_OBJECT(client), signals[NEW_MENUITEM], 0, item, TRUE);
113+
114 /* Get the properties queued up for this item */
115- org_freedesktop_dbusmenu_get_properties_async(proxy, id, menuitem_get_properties_cb, item);
116+ /* Not happy about this, but I need these :( */
117+ newItemPropData * propdata = g_new0(newItemPropData, 1);
118+ propdata->client = client;
119+ propdata->item = item;
120+ propdata->parent = parent;
121+
122+ org_freedesktop_dbusmenu_get_properties_async(proxy, id, menuitem_get_properties_new_cb, propdata);
123 }
124
125 xmlNodePtr children;
126@@ -744,3 +804,46 @@
127
128 return priv->root;
129 }
130+
131+/**
132+ dbusmenu_client_add_type_handler:
133+ @client: Client where we're getting types coming in
134+ @type: A text string that will be matched with the 'type'
135+ property on incoming menu items
136+ @newfunc: The function that will be executed with those new
137+ items when they come in.
138+
139+ This function connects into the type handling of the #DbusmenuClient.
140+ Every new menuitem that comes in immediately gets asked for it's
141+ properties. When we get those properties we check the 'type'
142+ property and look to see if it matches a handler that is known
143+ by the client. If so, the @newfunc function is executed on that
144+ #DbusmenuMenuitem. If not, then the DbusmenuClient::new-menuitem
145+ signal is sent.
146+
147+ In the future the known types will be sent to the server so that it
148+ can make choices about the menu item types availble.
149+
150+ Return value: If registering the new type was successful.
151+*/
152+gboolean
153+dbusmenu_client_add_type_handler (DbusmenuClient * client, const gchar * type, DbusmenuClientTypeHandler newfunc)
154+{
155+ g_return_val_if_fail(DBUSMENU_IS_CLIENT(client), FALSE);
156+
157+ DbusmenuClientPrivate * priv = DBUSMENU_CLIENT_GET_PRIVATE(client);
158+
159+ if (priv->type_handlers == NULL) {
160+ g_warning("Type handlers hashtable not built");
161+ return FALSE;
162+ }
163+
164+ gpointer value = g_hash_table_lookup(priv->type_handlers, type);
165+ if (value != NULL) {
166+ g_warning("Type '%s' already had a registered handler.", type);
167+ return FALSE;
168+ }
169+
170+ g_hash_table_insert(priv->type_handlers, g_strdup(type), newfunc);
171+ return TRUE;
172+}
173
174=== modified file 'libdbusmenu-glib/client.h'
175--- libdbusmenu-glib/client.h 2009-06-23 20:44:29 +0000
176+++ libdbusmenu-glib/client.h 2009-08-26 20:15:13 +0000
177@@ -50,10 +50,15 @@
178 #define DBUSMENU_CLIENT_PROP_DBUS_NAME "dbus-name"
179 #define DBUSMENU_CLIENT_PROP_DBUS_OBJECT "dbus-object"
180
181+#define DBUSMENU_CLIENT_TYPES_DEFAULT "menuitem"
182+#define DBUSMENU_CLIENT_TYPES_SEPARATOR "separator"
183+#define DBUSMENU_CLIENT_TYPES_IMAGE "imageitem"
184+
185 /**
186 DbusmenuClientClass:
187 @parent_class: #GObjectClass
188 @layout_updated: Slot for #DbusmenuClient::layout-updated.
189+ @new_menuitem: Slot for #DbusmenuClient::new-menuitem.
190 @reserved1: Reserved for future use.
191 @reserved2: Reserved for future use.
192 @reserved3: Reserved for future use.
193@@ -90,9 +95,15 @@
194 GObject parent;
195 };
196
197-GType dbusmenu_client_get_type (void);
198-DbusmenuClient * dbusmenu_client_new (const gchar * name, const gchar * object);
199-DbusmenuMenuitem * dbusmenu_client_get_root (DbusmenuClient * client);
200+typedef gboolean (*DbusmenuClientTypeHandler) (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client);
201+
202+GType dbusmenu_client_get_type (void);
203+DbusmenuClient * dbusmenu_client_new (const gchar * name,
204+ const gchar * object);
205+DbusmenuMenuitem * dbusmenu_client_get_root (DbusmenuClient * client);
206+gboolean dbusmenu_client_add_type_handler (DbusmenuClient * client,
207+ const gchar * type,
208+ DbusmenuClientTypeHandler newfunc);
209
210 /**
211 SECTION:client
212
213=== modified file 'libdbusmenu-glib/menuitem.c'
214--- libdbusmenu-glib/menuitem.c 2009-06-26 18:57:59 +0000
215+++ libdbusmenu-glib/menuitem.c 2009-08-25 16:16:26 +0000
216@@ -61,6 +61,7 @@
217 CHILD_ADDED,
218 CHILD_REMOVED,
219 CHILD_MOVED,
220+ REALIZED,
221 LAST_SIGNAL
222 };
223
224@@ -178,6 +179,22 @@
225 NULL, NULL,
226 _dbusmenu_menuitem_marshal_VOID__OBJECT_UINT_UINT,
227 G_TYPE_NONE, 3, G_TYPE_OBJECT, G_TYPE_UINT, G_TYPE_UINT);
228+ /**
229+ DbusmenuMenuitem::realized:
230+ @arg0: The #DbusmenuMenuitem object.
231+
232+ Emitted when the initial request for properties
233+ is complete on the item. If there is a type
234+ handler configured for the "type" parameter
235+ that will be executed before this is signaled.
236+ */
237+ signals[REALIZED] = g_signal_new(DBUSMENU_MENUITEM_SIGNAL_REALIZED,
238+ G_TYPE_FROM_CLASS(klass),
239+ G_SIGNAL_RUN_LAST,
240+ G_STRUCT_OFFSET(DbusmenuMenuitemClass, realized),
241+ NULL, NULL,
242+ _dbusmenu_menuitem_marshal_VOID__VOID,
243+ G_TYPE_NONE, 0, G_TYPE_NONE);
244
245 g_object_class_install_property (object_class, PROP_ID,
246 g_param_spec_uint("id", "ID for the menu item",
247
248=== modified file 'libdbusmenu-glib/menuitem.h'
249--- libdbusmenu-glib/menuitem.h 2009-06-26 17:49:52 +0000
250+++ libdbusmenu-glib/menuitem.h 2009-08-26 20:18:50 +0000
251@@ -47,6 +47,13 @@
252 #define DBUSMENU_MENUITEM_SIGNAL_CHILD_ADDED "child-added"
253 #define DBUSMENU_MENUITEM_SIGNAL_CHILD_REMOVED "child-removed"
254 #define DBUSMENU_MENUITEM_SIGNAL_CHILD_MOVED "child-moved"
255+#define DBUSMENU_MENUITEM_SIGNAL_REALIZED "realized"
256+#define DBUSMENU_MENUITEM_SIGNAL_REALIZED_ID (g_signal_lookup(DBUSMENU_MENUITEM_SIGNAL_REALIZED, DBUSMENU_TYPE_MENUITEM))
257+
258+#define DBUSMENU_MENUITEM_PROP_VISIBLE "visible"
259+#define DBUSMENU_MENUITEM_PROP_LABEL "label"
260+#define DBUSMENU_MENUITEM_PROP_ICON "icon"
261+#define DBUSMENU_MENUITEM_PROP_ICON_DATA "icon-data"
262
263 /**
264 DbusmenuMenuitem:
265@@ -71,6 +78,7 @@
266 @child_added: Slot for #DbusmenuMenuitem::child-added.
267 @child_removed: Slot for #DbusmenuMenuitem::child-removed.
268 @child_moved: Slot for #DbusmenuMenuitem::child-moved.
269+ @realized: Slot for #DbusmenuMenuitem::realized.
270 @buildxml: Virtual function that appends the strings required
271 to represent this menu item in the menu XML file.
272 @reserved1: Reserved for future use.
273@@ -89,6 +97,7 @@
274 void (*child_added) (DbusmenuMenuitem * child, guint position);
275 void (*child_removed) (DbusmenuMenuitem * child);
276 void (*child_moved) (DbusmenuMenuitem * child, guint newpos, guint oldpos);
277+ void (*realized) (void);
278
279 /* Virtual functions */
280 void (*buildxml) (GPtrArray * stringarray);
281@@ -96,7 +105,7 @@
282 void (*reserved1) (void);
283 void (*reserved2) (void);
284 void (*reserved3) (void);
285- void (*reserved4) (void);
286+ /* void (*reserved4) (void); -- realized, realloc when bumping lib version */
287 };
288
289 GType dbusmenu_menuitem_get_type (void);
290
291=== modified file 'libdbusmenu-gtk/client.c'
292--- libdbusmenu-gtk/client.c 2009-06-26 17:53:15 +0000
293+++ libdbusmenu-gtk/client.c 2009-08-26 20:25:37 +0000
294@@ -44,6 +44,10 @@
295 static void delete_child (DbusmenuMenuitem * mi, DbusmenuMenuitem * child, DbusmenuGtkClient * gtkclient);
296 static void move_child (DbusmenuMenuitem * mi, DbusmenuMenuitem * child, guint new, guint old, DbusmenuGtkClient * gtkclient);
297
298+static gboolean new_item_normal (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client);
299+static gboolean new_item_seperator (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client);
300+static gboolean new_item_image (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client);
301+
302 /* GObject Stuff */
303 G_DEFINE_TYPE (DbusmenuGtkClient, dbusmenu_gtkclient, DBUSMENU_TYPE_CLIENT);
304
305@@ -61,7 +65,12 @@
306 static void
307 dbusmenu_gtkclient_init (DbusmenuGtkClient *self)
308 {
309+ dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(self), DBUSMENU_CLIENT_TYPES_DEFAULT, new_item_normal);
310+ dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(self), DBUSMENU_CLIENT_TYPES_SEPARATOR, new_item_seperator);
311+ dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(self), DBUSMENU_CLIENT_TYPES_IMAGE, new_item_image);
312+
313 g_signal_connect(G_OBJECT(self), DBUSMENU_CLIENT_SIGNAL_NEW_MENUITEM, G_CALLBACK(new_menuitem), NULL);
314+
315 return;
316 }
317
318@@ -95,14 +104,27 @@
319 return TRUE;
320 }
321
322+/* Process the visible property */
323+static void
324+process_visible (GtkMenuItem * gmi, const gchar * value)
325+{
326+ if (value == NULL || !g_strcmp0(value, "true")) {
327+ gtk_widget_show(GTK_WIDGET(gmi));
328+ } else {
329+ gtk_widget_hide(GTK_WIDGET(gmi));
330+ }
331+ return;
332+}
333+
334 /* Whenever we have a property change on a DbusmenuMenuitem
335 we need to be responsive to that. */
336 static void
337 menu_prop_change_cb (DbusmenuMenuitem * mi, gchar * prop, gchar * value, GtkMenuItem * gmi)
338 {
339- if (!g_strcmp0(prop, "label")) {
340+ if (!g_strcmp0(prop, DBUSMENU_MENUITEM_PROP_LABEL)) {
341 gtk_menu_item_set_label(gmi, value);
342- gtk_widget_show(GTK_WIDGET(gmi));
343+ } else if (!g_strcmp0(prop, DBUSMENU_MENUITEM_PROP_VISIBLE)) {
344+ process_visible(gmi, value);
345 }
346
347 return;
348@@ -125,23 +147,20 @@
349 static void
350 new_menuitem (DbusmenuClient * client, DbusmenuMenuitem * mi, gpointer userdata)
351 {
352- gpointer ann_mi = g_object_get_data(G_OBJECT(mi), data_menuitem);
353- GtkMenuItem * gmi = GTK_MENU_ITEM(ann_mi);
354-
355- if (gmi != NULL) {
356- /* It's possible we've already been looked at, that's
357- okay, but we can just ignore this signal then. */
358- return;
359- }
360-
361- gmi = GTK_MENU_ITEM(gtk_menu_item_new());
362-
363+ g_warning("Got new menuitem signal, which means they want something");
364+ g_warning(" that I simply don't have.");
365+
366+ return;
367+}
368+
369+static void
370+base_new_menuitem (DbusmenuMenuitem * mi, GtkMenuItem * gmi, DbusmenuGtkClient * client)
371+{
372 /* Attach these two */
373 g_object_set_data(G_OBJECT(mi), data_menuitem, gmi);
374
375 /* DbusmenuMenuitem signals */
376 g_signal_connect(G_OBJECT(mi), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(menu_prop_change_cb), gmi);
377- g_signal_connect(G_OBJECT(mi), DBUSMENU_MENUITEM_SIGNAL_CHILD_ADDED, G_CALLBACK(new_child), client);
378 g_signal_connect(G_OBJECT(mi), DBUSMENU_MENUITEM_SIGNAL_CHILD_REMOVED, G_CALLBACK(delete_child), client);
379 g_signal_connect(G_OBJECT(mi), DBUSMENU_MENUITEM_SIGNAL_CHILD_MOVED, G_CALLBACK(move_child), client);
380
381@@ -151,6 +170,8 @@
382 /* Life insurance */
383 g_object_weak_ref(G_OBJECT(mi), destoryed_dbusmenuitem_cb, gmi);
384
385+ process_visible(gmi, dbusmenu_menuitem_property_get(mi, DBUSMENU_MENUITEM_PROP_VISIBLE));
386+
387 return;
388 }
389
390@@ -251,10 +272,47 @@
391
392 GtkMenuItem * mi = GTK_MENU_ITEM(g_object_get_data(G_OBJECT(item), data_menuitem));
393 if (mi == NULL) {
394- new_menuitem(DBUSMENU_CLIENT(client), item, NULL);
395+ // new_menuitem(DBUSMENU_CLIENT(client), item, NULL);
396+ g_warning("GTK not updated");
397 mi = GTK_MENU_ITEM(g_object_get_data(G_OBJECT(item), data_menuitem));
398 }
399
400 return mi;
401 }
402
403+static gboolean
404+new_item_normal (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client)
405+{
406+ GtkMenuItem * gmi;
407+
408+ gmi = GTK_MENU_ITEM(gtk_menu_item_new_with_label(dbusmenu_menuitem_property_get(newitem, "label")));
409+
410+ base_new_menuitem(newitem, gmi, DBUSMENU_GTKCLIENT(client));
411+ if (parent != NULL) {
412+ new_child(parent, newitem, dbusmenu_menuitem_get_position(newitem, parent), DBUSMENU_GTKCLIENT(client));
413+ }
414+
415+ return TRUE;
416+}
417+
418+static gboolean
419+new_item_seperator (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client)
420+{
421+ GtkMenuItem * gmi;
422+
423+ gmi = GTK_MENU_ITEM(gtk_separator_menu_item_new());
424+
425+ base_new_menuitem(newitem, gmi, DBUSMENU_GTKCLIENT(client));
426+ if (parent != NULL) {
427+ new_child(parent, newitem, dbusmenu_menuitem_get_position(newitem, parent), DBUSMENU_GTKCLIENT(client));
428+ }
429+
430+ return TRUE;
431+}
432+
433+static gboolean
434+new_item_image (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client)
435+{
436+
437+ return TRUE;
438+}
439
440=== modified file 'libdbusmenu-gtk/menu.c'
441--- libdbusmenu-gtk/menu.c 2009-06-26 18:40:04 +0000
442+++ libdbusmenu-gtk/menu.c 2009-08-26 21:24:58 +0000
443@@ -64,6 +64,7 @@
444 static void get_property (GObject * obj, guint id, GValue * value, GParamSpec * pspec);
445 /* Internal */
446 static void build_client (DbusmenuGtkMenu * self);
447+static void child_realized (DbusmenuMenuitem * child, gpointer userdata);
448
449 /* GObject Stuff */
450 G_DEFINE_TYPE (DbusmenuGtkMenu, dbusmenu_gtkmenu, GTK_TYPE_MENU);
451@@ -188,9 +189,7 @@
452 root_child_added (DbusmenuMenuitem * root, DbusmenuMenuitem * child, guint position, DbusmenuGtkMenu * menu)
453 {
454 g_debug("Root new child");
455- DbusmenuGtkMenuPrivate * priv = DBUSMENU_GTKMENU_GET_PRIVATE(menu);
456- gtk_menu_shell_insert(GTK_MENU_SHELL(menu), GTK_WIDGET(dbusmenu_gtkclient_menuitem_get(priv->client, child)), position);
457- gtk_widget_show(GTK_WIDGET(menu));
458+ g_signal_connect(G_OBJECT(child), DBUSMENU_MENUITEM_SIGNAL_REALIZED, G_CALLBACK(child_realized), menu);
459 return;
460 }
461
462@@ -214,6 +213,16 @@
463 }
464
465 static void
466+child_realized (DbusmenuMenuitem * child, gpointer userdata)
467+{
468+ DbusmenuGtkMenu * menu = DBUSMENU_GTKMENU(userdata);
469+ DbusmenuGtkMenuPrivate * priv = DBUSMENU_GTKMENU_GET_PRIVATE(menu);
470+
471+ gtk_menu_append(menu, GTK_WIDGET(dbusmenu_gtkclient_menuitem_get(priv->client, child)));
472+ return;
473+}
474+
475+static void
476 root_changed (DbusmenuGtkClient * client, DbusmenuMenuitem * newroot, DbusmenuGtkMenu * menu) {
477 if (newroot == NULL) {
478 gtk_widget_hide(GTK_WIDGET(menu));
479@@ -227,7 +236,8 @@
480 GList * child = NULL;
481 guint count = 0;
482 for (child = dbusmenu_menuitem_get_children(newroot); child != NULL; child = g_list_next(child)) {
483- gtk_menu_append(menu, GTK_WIDGET(dbusmenu_gtkclient_menuitem_get(client, child->data)));
484+ /* gtk_menu_append(menu, GTK_WIDGET(dbusmenu_gtkclient_menuitem_get(client, child->data))); */
485+ g_signal_connect(G_OBJECT(child->data), DBUSMENU_MENUITEM_SIGNAL_REALIZED, G_CALLBACK(child_realized), menu);
486 count++;
487 }
488
489
490=== modified file 'po/Makefile.in.in'
491--- po/Makefile.in.in 2009-03-25 17:33:11 +0000
492+++ po/Makefile.in.in 2009-08-20 17:55:36 +0000
493@@ -56,7 +56,7 @@
494
495 PO_LINGUAS=$(shell if test -r $(srcdir)/LINGUAS; then grep -v "^\#" $(srcdir)/LINGUAS; else echo "$(ALL_LINGUAS)"; fi)
496
497-USER_LINGUAS=$(shell if test -n "$(LINGUAS)"; then LLINGUAS="$(LINGUAS)"; ALINGUAS="$(ALL_LINGUAS)"; for lang in $$LLINGUAS; do if test -n "`grep '^$$lang$$' $(srcdir)/LINGUAS 2>/dev/null`" -o -n "`echo $$ALINGUAS|tr ' ' '\n'|grep '^$$lang$$'`"; then printf "$$lang "; fi; done; fi)
498+USER_LINGUAS=$(shell if test -n "$(LINGUAS)"; then LLINGUAS="$(LINGUAS)"; ALINGUAS="$(ALL_LINGUAS)"; for lang in $$LLINGUAS; do if test -n "`grep \^$$lang$$ $(srcdir)/LINGUAS 2>/dev/null`" -o -n "`echo $$ALINGUAS|tr ' ' '\n'|grep \^$$lang$$`"; then printf "$$lang "; fi; done; fi)
499
500 USE_LINGUAS=$(shell if test -n "$(USER_LINGUAS)" -o -n "$(LINGUAS)"; then LLINGUAS="$(USER_LINGUAS)"; else if test -n "$(PO_LINGUAS)"; then LLINGUAS="$(PO_LINGUAS)"; else LLINGUAS="$(ALL_LINGUAS)"; fi; fi; for lang in $$LLINGUAS; do printf "$$lang "; done)
501
502
503=== modified file 'tests/test-gtk-label.json'
504--- tests/test-gtk-label.json 2009-06-17 19:59:57 +0000
505+++ tests/test-gtk-label.json 2009-08-26 20:32:37 +0000
506@@ -1,155 +1,155 @@
507 [
508- {"id": 1,
509+ {"id": 1, "type": "menuitem",
510 "label": "value1",
511 "submenu": [
512- {"id": 30,
513+ {"id": 30, "type": "menuitem",
514 "label": "value30"},
515- {"id": 31,
516+ {"id": 31, "type": "menuitem",
517 "label": "value31"},
518- {"id": 32,
519+ {"id": 32, "type": "menuitem",
520 "label": "value32"},
521- {"id": 33,
522+ {"id": 33, "type": "menuitem",
523 "label": "value33"},
524- {"id": 34,
525+ {"id": 34, "type": "menuitem",
526 "label": "value34"},
527- {"id": 35,
528+ {"id": 35, "type": "menuitem",
529 "label": "value35"},
530- {"id": 36,
531+ {"id": 36, "type": "menuitem",
532 "label": "value36"},
533- {"id": 37,
534+ {"id": 37, "type": "menuitem",
535 "label": "value37"},
536- {"id": 38,
537+ {"id": 38, "type": "menuitem",
538 "label": "value38"},
539- {"id": 39,
540+ {"id": 39, "type": "menuitem",
541 "label": "value39"}
542 ]
543 },
544- {"id": 2,
545+ {"id": 2, "type": "menuitem",
546 "label": "value2",
547 "submenu": [
548- {"id": 20,
549+ {"id": 20, "type": "menuitem",
550 "label": "value20"},
551- {"id": 21,
552+ {"id": 21, "type": "separator",
553 "label": "value21"},
554- {"id": 22,
555+ {"id": 22, "type": "menuitem",
556 "label": "value22"},
557- {"id": 23,
558+ {"id": 23, "type": "separator",
559 "label": "value23"},
560- {"id": 24,
561+ {"id": 24, "type": "menuitem",
562 "label": "value24"},
563- {"id": 25,
564+ {"id": 25, "type": "separator",
565 "label": "value25"},
566- {"id": 26,
567+ {"id": 26, "type": "menuitem",
568 "label": "value26"},
569- {"id": 27,
570+ {"id": 27, "type": "separator",
571 "label": "value27"},
572- {"id": 28,
573+ {"id": 28, "type": "menuitem",
574 "label": "value28"},
575- {"id": 29,
576+ {"id": 29, "type": "menuitem", "visible": "false",
577 "label": "value29"}
578 ]
579 },
580- {"id": 3,
581+ {"id": 3, "type": "menuitem",
582 "label": "a super long label that is really of unreasonable length but we should make sure it makes it across the bus",
583 "not.a.value": "A useless value",
584 "submenu": [
585- {"id": 10,
586+ {"id": 10, "type": "menuitem",
587 "label": "value10"},
588- {"id": 11,
589+ {"id": 11, "type": "menuitem",
590 "label": "value11"},
591- {"id": 12,
592+ {"id": 12, "type": "menuitem",
593 "label": "value12"},
594- {"id": 13,
595+ {"id": 13, "type": "menuitem",
596 "label": "value13"},
597- {"id": 14,
598+ {"id": 14, "type": "menuitem",
599 "label": "value14"},
600- {"id": 15,
601+ {"id": 15, "type": "menuitem",
602 "label": "value15"},
603- {"id": 16,
604+ {"id": 16, "type": "menuitem",
605 "label": "value16"},
606- {"id": 17,
607+ {"id": 17, "type": "menuitem",
608 "label": "value17"},
609- {"id": 18,
610+ {"id": 18, "type": "menuitem",
611 "label": "value18"},
612- {"id": 19,
613+ {"id": 19, "type": "menuitem",
614 "label": "value19"}
615 ]
616 },
617- {"id": 4,
618+ {"id": 4, "type": "menuitem",
619 "label": "value2",
620 "submenu": [
621- {"id": 5,
622+ {"id": 5, "type": "menuitem",
623 "label": "value5",
624 "submenu": [
625- {"id": 10,
626+ {"id": 10, "type": "menuitem",
627 "label": "value10"},
628- {"id": 11,
629+ {"id": 11, "type": "menuitem",
630 "label": "value11"},
631- {"id": 12,
632+ {"id": 12, "type": "menuitem",
633 "label": "value12"},
634- {"id": 13,
635+ {"id": 13, "type": "menuitem",
636 "label": "value13"},
637- {"id": 14,
638+ {"id": 14, "type": "menuitem",
639 "label": "value14"},
640- {"id": 15,
641+ {"id": 15, "type": "menuitem",
642 "label": "value15"},
643- {"id": 16,
644+ {"id": 16, "type": "menuitem",
645 "label": "value16"},
646- {"id": 17,
647+ {"id": 17, "type": "menuitem",
648 "label": "value17"},
649- {"id": 18,
650+ {"id": 18, "type": "menuitem",
651 "label": "value18"},
652- {"id": 19,
653+ {"id": 19, "type": "menuitem",
654 "label": "value19"}
655 ]
656 },
657- {"id": 6,
658+ {"id": 6, "type": "menuitem",
659 "label": "value6",
660 "submenu": [
661- {"id": 20,
662+ {"id": 20, "type": "menuitem",
663 "label": "value20"},
664- {"id": 21,
665+ {"id": 21, "type": "menuitem",
666 "label": "value21"},
667- {"id": 22,
668+ {"id": 22, "type": "menuitem",
669 "label": "value22"},
670- {"id": 23,
671+ {"id": 23, "type": "menuitem",
672 "label": "value23"},
673- {"id": 24,
674+ {"id": 24, "type": "menuitem",
675 "label": "value24"},
676- {"id": 25,
677+ {"id": 25, "type": "menuitem",
678 "label": "value25"},
679- {"id": 26,
680+ {"id": 26, "type": "menuitem",
681 "label": "value26"},
682- {"id": 27,
683+ {"id": 27, "type": "menuitem",
684 "label": "value27"},
685- {"id": 28,
686+ {"id": 28, "type": "menuitem",
687 "label": "value28"},
688- {"id": 29,
689+ {"id": 29, "type": "menuitem",
690 "label": "value29"}
691 ]
692 },
693- {"id": 7,
694+ {"id": 7, "type": "menuitem",
695 "label": "value7",
696 "submenu": [
697- {"id": 30,
698+ {"id": 30, "type": "menuitem",
699 "label": "value30"},
700- {"id": 31,
701+ {"id": 31, "type": "menuitem",
702 "label": "value31"},
703- {"id": 32,
704+ {"id": 32, "type": "menuitem",
705 "label": "value32"},
706- {"id": 33,
707+ {"id": 33, "type": "menuitem",
708 "label": "value33"},
709- {"id": 34,
710+ {"id": 34, "type": "menuitem",
711 "label": "value34"},
712- {"id": 35,
713+ {"id": 35, "type": "menuitem",
714 "label": "value35"},
715- {"id": 36,
716+ {"id": 36, "type": "menuitem",
717 "label": "value36"},
718- {"id": 37,
719+ {"id": 37, "type": "menuitem",
720 "label": "value37"},
721- {"id": 38,
722+ {"id": 38, "type": "menuitem",
723 "label": "value38"},
724- {"id": 39,
725+ {"id": 39, "type": "menuitem",
726 "label": "value39"}
727 ]
728 },

Subscribers

People subscribed via source and target branches