Merge lp:~ted/indicator-appmenu/lp743404 into lp:indicator-appmenu/0.3

Proposed by Ted Gould
Status: Merged
Merged at revision: 115
Proposed branch: lp:~ted/indicator-appmenu/lp743404
Merge into: lp:indicator-appmenu/0.3
Diff against target: 124 lines (+45/-8)
1 file modified
src/window-menus.c (+45/-8)
To merge this branch: bzr merge lp:~ted/indicator-appmenu/lp743404
Reviewer Review Type Date Requested Status
Conor Curran (community) Approve
Jay Taoko (community) Approve
Review via email: mp+56065@code.launchpad.net

Description of the change

This is bug about a signal, a signal that didn't have an object. And object that had abondoned it, and didn't bother to tell the signal. This is a sad story.

But it has a happy ending.

We've now protected that signal against objects that abondon it with further checks. We've now set up the situation so that the signals get removed when they're no longer needed. And we've delt with the reprocussions of having two places to remove the signal can cause. So in a nutshell:

We've earned the right to party.

To post a comment you must log in.
Revision history for this message
Jay Taoko (jaytaoko) :
review: Approve
Revision history for this message
Conor Curran (cjcurran) wrote :

Looks good to me Ted

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/window-menus.c'
2--- src/window-menus.c 2011-03-08 17:10:26 +0000
3+++ src/window-menus.c 2011-04-03 04:12:30 +0000
4@@ -226,8 +226,8 @@
5 }
6
7 if (priv->root != NULL) {
8- g_object_unref(G_OBJECT(priv->root));
9- priv->root = NULL;
10+ root_changed(DBUSMENU_CLIENT(priv->client), NULL, object);
11+ g_warn_if_fail(priv->root == NULL);
12 }
13
14 if (priv->client != NULL) {
15@@ -520,6 +520,18 @@
16 return;
17 }
18
19+/* Remove the various signals that we attach to menuitems to
20+ ensure they don't pop up later. */
21+static void
22+remove_menuitem_signals (DbusmenuMenuitem * mi, gpointer user_data)
23+{
24+ g_signal_handlers_disconnect_by_func(G_OBJECT(mi), G_CALLBACK(menu_entry_realized), user_data);
25+ g_signal_handlers_disconnect_matched (mi, G_SIGNAL_MATCH_FUNC, 0, 0, 0, menu_child_realized, NULL);
26+ g_signal_handlers_disconnect_matched (mi, G_SIGNAL_MATCH_FUNC, 0, 0, 0, menu_prop_changed, NULL);
27+
28+ return;
29+}
30+
31 /* Respond to the root menu item on our client changing */
32 static void
33 root_changed (DbusmenuClient * client, DbusmenuMenuitem * new_root, gpointer user_data)
34@@ -531,6 +543,8 @@
35 free_entries(G_OBJECT(user_data), TRUE);
36
37 if (priv->root != NULL) {
38+ dbusmenu_menuitem_foreach(priv->root, remove_menuitem_signals, client);
39+
40 g_signal_handlers_disconnect_by_func(G_OBJECT(priv->root), G_CALLBACK(menu_entry_added), user_data);
41 g_signal_handlers_disconnect_by_func(G_OBJECT(priv->root), G_CALLBACK(menu_entry_removed), user_data);
42 g_object_unref(priv->root);
43@@ -564,6 +578,7 @@
44 static void
45 menu_entry_added (DbusmenuMenuitem * root, DbusmenuMenuitem * newentry, guint position, gpointer user_data)
46 {
47+ g_return_if_fail(IS_WINDOW_MENUS(user_data));
48 WindowMenusPrivate * priv = WINDOW_MENUS_GET_PRIVATE(user_data);
49
50 g_signal_connect(G_OBJECT(newentry), DBUSMENU_MENUITEM_SIGNAL_REALIZED, G_CALLBACK(menu_entry_realized), user_data);
51@@ -575,11 +590,23 @@
52 return;
53 }
54
55+/* A small clean up function to ensure that the data
56+ gets free'd and the ref lost in all cases. */
57+static void
58+child_realized_data_cleanup (gpointer user_data, GClosure * closure)
59+{
60+ gpointer * data = (gpointer *)user_data;
61+ g_object_unref(data[1]);
62+ g_free(user_data);
63+ return;
64+}
65+
66 /* React to the menuitem when we know that it's got all the data
67 that we really need. */
68 static void
69 menu_entry_realized (DbusmenuMenuitem * newentry, gpointer user_data)
70 {
71+ g_return_if_fail(IS_WINDOW_MENUS(user_data));
72 WindowMenusPrivate * priv = WINDOW_MENUS_GET_PRIVATE(user_data);
73 GtkMenu * menu = dbusmenu_gtkclient_menuitem_get_submenu(priv->client, newentry);
74
75@@ -590,7 +617,7 @@
76 data[0] = user_data;
77 data[1] = g_object_ref(newentry);
78
79- g_signal_connect(G_OBJECT(children->data), DBUSMENU_MENUITEM_SIGNAL_REALIZED, G_CALLBACK(menu_child_realized), data);
80+ g_signal_connect_data(G_OBJECT(children->data), DBUSMENU_MENUITEM_SIGNAL_REALIZED, G_CALLBACK(menu_child_realized), data, child_realized_data_cleanup, 0);
81 } else {
82 g_warning("Entry has no children!");
83 }
84@@ -641,14 +668,25 @@
85 static void
86 menu_child_realized (DbusmenuMenuitem * child, gpointer user_data)
87 {
88- DbusmenuMenuitem * newentry = (DbusmenuMenuitem *)(((gpointer *)user_data)[1]);
89+ /* Grab our values out to stack variables */
90+ DbusmenuMenuitem * newentry = DBUSMENU_MENUITEM(((gpointer *)user_data)[1]);
91+ WindowMenus * wm = WINDOW_MENUS(((gpointer *)user_data)[0]);
92+
93+ g_return_if_fail(newentry != NULL);
94+ g_return_if_fail(wm != NULL);
95+
96+ /* Disconnection below will drop the ref for this signal
97+ handler, let's make sure that's not a problem */
98+ g_object_ref(G_OBJECT(newentry));
99
100 /* Only care about the first */
101+ /* This will cause the cleanup function attached to the signal
102+ handler to be run. */
103 g_signal_handlers_disconnect_by_func(G_OBJECT(child), menu_child_realized, user_data);
104
105- WindowMenusPrivate * priv = WINDOW_MENUS_GET_PRIVATE((((gpointer *)user_data)[0]));
106+ WindowMenusPrivate * priv = WINDOW_MENUS_GET_PRIVATE(wm);
107 WMEntry * wmentry = g_new0(WMEntry, 1);
108- wmentry->wm = WINDOW_MENUS((((gpointer *)user_data)[0]));
109+ wmentry->wm = wm;
110 IndicatorObjectEntry * entry = &wmentry->ioentry;
111
112 wmentry->mi = newentry;
113@@ -691,10 +729,9 @@
114
115 g_array_append_val(priv->entries, wmentry);
116
117- g_signal_emit(G_OBJECT((((gpointer *)user_data)[0])), signals[ENTRY_ADDED], 0, entry, TRUE);
118+ g_signal_emit(G_OBJECT(wm), signals[ENTRY_ADDED], 0, entry, TRUE);
119
120 g_object_unref(newentry);
121- g_free(user_data);
122
123 return;
124 }

Subscribers

People subscribed via source and target branches