Merge lp:~mterry/libdbusmenu/watch-for-new-items into lp:libdbusmenu/0.5

Proposed by Michael Terry
Status: Merged
Merged at revision: 206
Proposed branch: lp:~mterry/libdbusmenu/watch-for-new-items
Merge into: lp:libdbusmenu/0.5
Diff against target: 189 lines (+85/-12)
1 file modified
libdbusmenu-gtk/parser.c (+85/-12)
To merge this branch: bzr merge lp:~mterry/libdbusmenu/watch-for-new-items
Reviewer Review Type Date Requested Status
Ted Gould (community) Approve
Review via email: mp+48644@code.launchpad.net

Description of the change

This branch does a few things, but most importantly, it watches GtkMenuShells for the addition of new items, fixing bugs where menu items don't appear but should, such as bug 709839.

So, here's what it does:
 * Consolidates the creation of new dbusmenu_items into a helper function. There are several things we want to do for each menu item, no matter who creates it, like adding a ParserData object or connecting to its destruction.

 * Connect to a new callback to GtkMenuShells ("child-added"). This involves adding a new entry, 'shell' to the ParserData blob.

 * Remove a duplicate line from dbusmenu_cache_freed that was leftover from my addition of ParserData. The line disconnected from widget_notify_cb, but there's already a block that does.

 * Fix a memory leak when iterating over the children of the topmost GtkMenuShell. It tried to free the list iterator instead of the list itself.

 * When adding a new child to a dbusmenu_item, make sure to add it at the right position. This never mattered before, since we did one iteration and were done, but now that we pay attention to insertions, we need to make sure we insert at the correct place.

To post a comment you must log in.
Revision history for this message
Ted Gould (ted) wrote :

  review approve

Very cool!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'libdbusmenu-gtk/parser.c'
--- libdbusmenu-gtk/parser.c 2011-02-03 13:43:56 +0000
+++ libdbusmenu-gtk/parser.c 2011-02-04 19:14:16 +0000
@@ -38,6 +38,7 @@
38 GtkWidget *label;38 GtkWidget *label;
39 GtkAction *action;39 GtkAction *action;
40 GtkWidget *widget;40 GtkWidget *widget;
41 GtkWidget *shell;
41} ParserData;42} ParserData;
4243
43typedef struct _RecurseContext44typedef struct _RecurseContext
@@ -63,6 +64,9 @@
63static void action_notify_cb (GtkAction * action,64static void action_notify_cb (GtkAction * action,
64 GParamSpec * pspec,65 GParamSpec * pspec,
65 gpointer data);66 gpointer data);
67static void child_added_cb (GtkContainer * menu,
68 GtkWidget * widget,
69 gpointer data);
66static void item_activated (DbusmenuMenuitem * item,70static void item_activated (DbusmenuMenuitem * item,
67 guint timestamp,71 guint timestamp,
68 gpointer user_data);72 gpointer user_data);
@@ -109,7 +113,6 @@
109 /* If the dbusmenu item is killed we don't need to remove113 /* If the dbusmenu item is killed we don't need to remove
110 the weak ref as well. */114 the weak ref as well. */
111 g_object_steal_data(G_OBJECT(data), CACHED_MENUITEM);115 g_object_steal_data(G_OBJECT(data), CACHED_MENUITEM);
112 g_signal_handlers_disconnect_by_func(data, G_CALLBACK(widget_notify_cb), obj);
113116
114 ParserData *pdata = (ParserData *)g_object_get_data(G_OBJECT(obj), PARSER_DATA);117 ParserData *pdata = (ParserData *)g_object_get_data(G_OBJECT(obj), PARSER_DATA);
115118
@@ -128,6 +131,11 @@
128 g_object_remove_weak_pointer(G_OBJECT(pdata->widget), (gpointer*)&pdata->widget);131 g_object_remove_weak_pointer(G_OBJECT(pdata->widget), (gpointer*)&pdata->widget);
129 }132 }
130133
134 if (pdata != NULL && pdata->shell != NULL) {
135 g_signal_handlers_disconnect_by_func(pdata->shell, G_CALLBACK(child_added_cb), obj);
136 g_object_remove_weak_pointer(G_OBJECT(pdata->shell), (gpointer*)&pdata->shell);
137 }
138
131 return;139 return;
132}140}
133141
@@ -143,6 +151,45 @@
143 return;151 return;
144}152}
145153
154static gint
155get_child_position (GtkWidget * child)
156{
157 GtkWidget * parent = gtk_widget_get_parent (child);
158 if (parent == NULL || !GTK_IS_CONTAINER (parent))
159 return -1;
160
161 GList * children = gtk_container_get_children (GTK_CONTAINER (parent));
162 GList * iter;
163 gint position = 0;
164
165 for (iter = children; iter != NULL; iter = iter->next) {
166 if (iter->data == child)
167 break;
168 ++position;
169 }
170
171 g_list_free (children);
172
173 if (iter == NULL)
174 return -1;
175 else
176 return position;
177}
178
179static DbusmenuMenuitem *
180new_menuitem (GtkWidget * widget)
181{
182 DbusmenuMenuitem * item = dbusmenu_menuitem_new();
183
184 ParserData *pdata = g_new0 (ParserData, 1);
185 g_object_set_data_full(G_OBJECT(item), PARSER_DATA, pdata, g_free);
186
187 g_object_set_data_full(G_OBJECT(widget), CACHED_MENUITEM, item, object_cache_freed);
188 g_object_weak_ref(G_OBJECT(item), dbusmenu_cache_freed, widget);
189
190 return item;
191}
192
146static void193static void
147parse_menu_structure_helper (GtkWidget * widget, RecurseContext * recurse)194parse_menu_structure_helper (GtkWidget * widget, RecurseContext * recurse)
148{195{
@@ -161,10 +208,11 @@
161 */208 */
162 if (recurse->parent == NULL && GTK_IS_MENU_BAR(widget)) {209 if (recurse->parent == NULL && GTK_IS_MENU_BAR(widget)) {
163 GList *children = gtk_container_get_children (GTK_CONTAINER (widget));210 GList *children = gtk_container_get_children (GTK_CONTAINER (widget));
211 GList *iter;
164212
165 for (; children != NULL; children = children->next) {213 for (iter = children; iter != NULL; iter = iter->next) {
166 gtk_menu_shell_activate_item (GTK_MENU_SHELL (widget),214 gtk_menu_shell_activate_item (GTK_MENU_SHELL (widget),
167 children->data,215 iter->data,
168 TRUE);216 TRUE);
169 }217 }
170218
@@ -172,9 +220,18 @@
172 }220 }
173221
174 if (recurse->parent == NULL) {222 if (recurse->parent == NULL) {
175 recurse->parent = dbusmenu_menuitem_new();223 recurse->parent = new_menuitem(widget);
176 }224 }
177225
226 ParserData *pdata = (ParserData *)g_object_get_data(G_OBJECT(recurse->parent), PARSER_DATA);
227
228 pdata->shell = widget;
229 g_signal_connect (G_OBJECT (widget),
230 "child-added",
231 G_CALLBACK (child_added_cb),
232 recurse->parent);
233 g_object_add_weak_pointer(G_OBJECT (widget), (gpointer*)&pdata->shell);
234
178 gtk_container_foreach (GTK_CONTAINER (widget),235 gtk_container_foreach (GTK_CONTAINER (widget),
179 (GtkCallback)parse_menu_structure_helper,236 (GtkCallback)parse_menu_structure_helper,
180 recurse);237 recurse);
@@ -194,8 +251,6 @@
194 /* We don't have one, so we'll need to build it */251 /* We don't have one, so we'll need to build it */
195 if (thisitem == NULL) {252 if (thisitem == NULL) {
196 thisitem = construct_dbusmenu_for_widget (widget);253 thisitem = construct_dbusmenu_for_widget (widget);
197 g_object_set_data_full(G_OBJECT(widget), CACHED_MENUITEM, thisitem, object_cache_freed);
198 g_object_weak_ref(G_OBJECT(thisitem), dbusmenu_cache_freed, widget);
199254
200 if (!gtk_widget_get_visible (widget)) {255 if (!gtk_widget_get_visible (widget)) {
201 g_signal_connect (G_OBJECT (widget),256 g_signal_connect (G_OBJECT (widget),
@@ -227,8 +282,14 @@
227 g_object_set_data (G_OBJECT (thisitem),282 g_object_set_data (G_OBJECT (thisitem),
228 "dbusmenu-parent",283 "dbusmenu-parent",
229 recurse->parent);284 recurse->parent);
230 dbusmenu_menuitem_child_append (recurse->parent,285 gint pos = get_child_position (widget);
231 thisitem);286 if (pos >= 0)
287 dbusmenu_menuitem_child_add_position (recurse->parent,
288 thisitem,
289 pos);
290 else
291 dbusmenu_menuitem_child_append (recurse->parent,
292 thisitem);
232 }293 }
233 }294 }
234295
@@ -265,10 +326,9 @@
265 /* If it's a standard GTK Menu Item we need to do some of our own work */326 /* If it's a standard GTK Menu Item we need to do some of our own work */
266 if (GTK_IS_MENU_ITEM (widget))327 if (GTK_IS_MENU_ITEM (widget))
267 {328 {
268 DbusmenuMenuitem *mi = dbusmenu_menuitem_new ();329 DbusmenuMenuitem *mi = new_menuitem(widget);
269330
270 ParserData *pdata = g_new0 (ParserData, 1);331 ParserData *pdata = (ParserData *)g_object_get_data(G_OBJECT(mi), PARSER_DATA);
271 g_object_set_data_full (G_OBJECT (mi), PARSER_DATA, pdata, g_free);
272332
273 gboolean visible = FALSE;333 gboolean visible = FALSE;
274 gboolean sensitive = FALSE;334 gboolean sensitive = FALSE;
@@ -414,7 +474,7 @@
414474
415 /* If it's none of those we're going to just create a475 /* If it's none of those we're going to just create a
416 generic menuitem as a place holder for it. */476 generic menuitem as a place holder for it. */
417 return dbusmenu_menuitem_new();477 return new_menuitem(widget);
418}478}
419479
420static void480static void
@@ -720,6 +780,19 @@
720 }780 }
721}781}
722782
783/* A child item was added to a menu we're watching. Let's try to integrate it. */
784static void
785child_added_cb (GtkContainer *menu, GtkWidget *widget, gpointer data)
786{
787 DbusmenuMenuitem *menuitem = (DbusmenuMenuitem *)data;
788
789 RecurseContext recurse = {0};
790 recurse.toplevel = gtk_widget_get_toplevel(GTK_WIDGET(menu));
791 recurse.parent = menuitem;
792
793 parse_menu_structure_helper(widget, &recurse);
794}
795
723static gboolean796static gboolean
724should_show_image (GtkImage *image)797should_show_image (GtkImage *image)
725{798{

Subscribers

People subscribed via source and target branches