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
1=== modified file 'libdbusmenu-gtk/parser.c'
2--- libdbusmenu-gtk/parser.c 2011-02-03 13:43:56 +0000
3+++ libdbusmenu-gtk/parser.c 2011-02-04 19:14:16 +0000
4@@ -38,6 +38,7 @@
5 GtkWidget *label;
6 GtkAction *action;
7 GtkWidget *widget;
8+ GtkWidget *shell;
9 } ParserData;
10
11 typedef struct _RecurseContext
12@@ -63,6 +64,9 @@
13 static void action_notify_cb (GtkAction * action,
14 GParamSpec * pspec,
15 gpointer data);
16+static void child_added_cb (GtkContainer * menu,
17+ GtkWidget * widget,
18+ gpointer data);
19 static void item_activated (DbusmenuMenuitem * item,
20 guint timestamp,
21 gpointer user_data);
22@@ -109,7 +113,6 @@
23 /* If the dbusmenu item is killed we don't need to remove
24 the weak ref as well. */
25 g_object_steal_data(G_OBJECT(data), CACHED_MENUITEM);
26- g_signal_handlers_disconnect_by_func(data, G_CALLBACK(widget_notify_cb), obj);
27
28 ParserData *pdata = (ParserData *)g_object_get_data(G_OBJECT(obj), PARSER_DATA);
29
30@@ -128,6 +131,11 @@
31 g_object_remove_weak_pointer(G_OBJECT(pdata->widget), (gpointer*)&pdata->widget);
32 }
33
34+ if (pdata != NULL && pdata->shell != NULL) {
35+ g_signal_handlers_disconnect_by_func(pdata->shell, G_CALLBACK(child_added_cb), obj);
36+ g_object_remove_weak_pointer(G_OBJECT(pdata->shell), (gpointer*)&pdata->shell);
37+ }
38+
39 return;
40 }
41
42@@ -143,6 +151,45 @@
43 return;
44 }
45
46+static gint
47+get_child_position (GtkWidget * child)
48+{
49+ GtkWidget * parent = gtk_widget_get_parent (child);
50+ if (parent == NULL || !GTK_IS_CONTAINER (parent))
51+ return -1;
52+
53+ GList * children = gtk_container_get_children (GTK_CONTAINER (parent));
54+ GList * iter;
55+ gint position = 0;
56+
57+ for (iter = children; iter != NULL; iter = iter->next) {
58+ if (iter->data == child)
59+ break;
60+ ++position;
61+ }
62+
63+ g_list_free (children);
64+
65+ if (iter == NULL)
66+ return -1;
67+ else
68+ return position;
69+}
70+
71+static DbusmenuMenuitem *
72+new_menuitem (GtkWidget * widget)
73+{
74+ DbusmenuMenuitem * item = dbusmenu_menuitem_new();
75+
76+ ParserData *pdata = g_new0 (ParserData, 1);
77+ g_object_set_data_full(G_OBJECT(item), PARSER_DATA, pdata, g_free);
78+
79+ g_object_set_data_full(G_OBJECT(widget), CACHED_MENUITEM, item, object_cache_freed);
80+ g_object_weak_ref(G_OBJECT(item), dbusmenu_cache_freed, widget);
81+
82+ return item;
83+}
84+
85 static void
86 parse_menu_structure_helper (GtkWidget * widget, RecurseContext * recurse)
87 {
88@@ -161,10 +208,11 @@
89 */
90 if (recurse->parent == NULL && GTK_IS_MENU_BAR(widget)) {
91 GList *children = gtk_container_get_children (GTK_CONTAINER (widget));
92+ GList *iter;
93
94- for (; children != NULL; children = children->next) {
95+ for (iter = children; iter != NULL; iter = iter->next) {
96 gtk_menu_shell_activate_item (GTK_MENU_SHELL (widget),
97- children->data,
98+ iter->data,
99 TRUE);
100 }
101
102@@ -172,9 +220,18 @@
103 }
104
105 if (recurse->parent == NULL) {
106- recurse->parent = dbusmenu_menuitem_new();
107+ recurse->parent = new_menuitem(widget);
108 }
109
110+ ParserData *pdata = (ParserData *)g_object_get_data(G_OBJECT(recurse->parent), PARSER_DATA);
111+
112+ pdata->shell = widget;
113+ g_signal_connect (G_OBJECT (widget),
114+ "child-added",
115+ G_CALLBACK (child_added_cb),
116+ recurse->parent);
117+ g_object_add_weak_pointer(G_OBJECT (widget), (gpointer*)&pdata->shell);
118+
119 gtk_container_foreach (GTK_CONTAINER (widget),
120 (GtkCallback)parse_menu_structure_helper,
121 recurse);
122@@ -194,8 +251,6 @@
123 /* We don't have one, so we'll need to build it */
124 if (thisitem == NULL) {
125 thisitem = construct_dbusmenu_for_widget (widget);
126- g_object_set_data_full(G_OBJECT(widget), CACHED_MENUITEM, thisitem, object_cache_freed);
127- g_object_weak_ref(G_OBJECT(thisitem), dbusmenu_cache_freed, widget);
128
129 if (!gtk_widget_get_visible (widget)) {
130 g_signal_connect (G_OBJECT (widget),
131@@ -227,8 +282,14 @@
132 g_object_set_data (G_OBJECT (thisitem),
133 "dbusmenu-parent",
134 recurse->parent);
135- dbusmenu_menuitem_child_append (recurse->parent,
136- thisitem);
137+ gint pos = get_child_position (widget);
138+ if (pos >= 0)
139+ dbusmenu_menuitem_child_add_position (recurse->parent,
140+ thisitem,
141+ pos);
142+ else
143+ dbusmenu_menuitem_child_append (recurse->parent,
144+ thisitem);
145 }
146 }
147
148@@ -265,10 +326,9 @@
149 /* If it's a standard GTK Menu Item we need to do some of our own work */
150 if (GTK_IS_MENU_ITEM (widget))
151 {
152- DbusmenuMenuitem *mi = dbusmenu_menuitem_new ();
153+ DbusmenuMenuitem *mi = new_menuitem(widget);
154
155- ParserData *pdata = g_new0 (ParserData, 1);
156- g_object_set_data_full (G_OBJECT (mi), PARSER_DATA, pdata, g_free);
157+ ParserData *pdata = (ParserData *)g_object_get_data(G_OBJECT(mi), PARSER_DATA);
158
159 gboolean visible = FALSE;
160 gboolean sensitive = FALSE;
161@@ -414,7 +474,7 @@
162
163 /* If it's none of those we're going to just create a
164 generic menuitem as a place holder for it. */
165- return dbusmenu_menuitem_new();
166+ return new_menuitem(widget);
167 }
168
169 static void
170@@ -720,6 +780,19 @@
171 }
172 }
173
174+/* A child item was added to a menu we're watching. Let's try to integrate it. */
175+static void
176+child_added_cb (GtkContainer *menu, GtkWidget *widget, gpointer data)
177+{
178+ DbusmenuMenuitem *menuitem = (DbusmenuMenuitem *)data;
179+
180+ RecurseContext recurse = {0};
181+ recurse.toplevel = gtk_widget_get_toplevel(GTK_WIDGET(menu));
182+ recurse.parent = menuitem;
183+
184+ parse_menu_structure_helper(widget, &recurse);
185+}
186+
187 static gboolean
188 should_show_image (GtkImage *image)
189 {

Subscribers

People subscribed via source and target branches