Merge lp:~achiang/appmenu-gtk/memleaks-787736-780602 into lp:appmenu-gtk/0.4

Proposed by Alex Chiang
Status: Merged
Approved by: Charles Kerr
Approved revision: 154
Merged at revision: 153
Proposed branch: lp:~achiang/appmenu-gtk/memleaks-787736-780602
Merge into: lp:appmenu-gtk/0.4
Diff against target: 211 lines (+83/-78)
1 file modified
src/bridge.c (+83/-78)
To merge this branch: bzr merge lp:~achiang/appmenu-gtk/memleaks-787736-780602
Reviewer Review Type Date Requested Status
Charles Kerr (community) Approve
Review via email: mp+136550@code.launchpad.net

Description of the change

Cherrypick r158 from trunk to help fix nm-applet in Precise.

To post a comment you must log in.
Revision history for this message
Charles Kerr (charlesk) wrote :

Alex, you'll need to pull in r160 as well

154. By Alex Chiang

Backport r160 from trunk to eliminate noisy debug statements

Revision history for this message
Charles Kerr (charlesk) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/bridge.c'
2--- src/bridge.c 2012-04-02 19:12:37 +0000
3+++ src/bridge.c 2012-11-28 18:08:20 +0000
4@@ -85,21 +85,13 @@
5
6 GDBusProxy *appmenuproxy;
7 gboolean online;
8+
9+ GSList *rebuild_list;
10+ guint rebuild_timer_id;
11 };
12
13-typedef struct _RecurseContext
14-{
15- AppMenuBridge *bridge;
16- AppWindowContext *context;
17-
18- gint count;
19- gboolean previous;
20- DbusmenuMenuitem *stack[30];
21-} RecurseContext;
22-
23 G_DEFINE_DYNAMIC_TYPE(AppMenuBridge, app_menu_bridge, UBUNTU_TYPE_MENU_PROXY)
24
25-static GHashTable *rebuild_ids = NULL;
26 static GDBusNodeInfo * registrar_node_info = NULL;
27 static GDBusInterfaceInfo * registrar_interface_info = NULL;
28
29@@ -213,28 +205,58 @@
30 g_free (context);
31 }
32
33+
34+/* a widget that was queued for rebuild has been destroyed,
35+ so remove it from our queue */
36+static void
37+rebuild_list_widget_destroyed (gpointer gbridge, GObject * dead_object)
38+{
39+ AppMenuBridge * bridge = APP_MENU_BRIDGE (gbridge);
40+ AppMenuBridgePrivate * p = bridge->priv;
41+
42+ p->rebuild_list = g_slist_remove (p->rebuild_list, dead_object);
43+}
44+
45+static void
46+rebuild_list_clear (AppMenuBridge * bridge)
47+{
48+ GSList * l;
49+ AppMenuBridgePrivate * p = bridge->priv;
50+
51+ /* unref the widgets and blow away the list */
52+ for (l=p->rebuild_list; l!=NULL; l=l->next)
53+ g_object_weak_unref (l->data, rebuild_list_widget_destroyed, bridge);
54+ g_slist_free (p->rebuild_list);
55+ p->rebuild_list = NULL;
56+
57+ /* remove the rebuild timer */
58+ if (p->rebuild_timer_id > 0)
59+ {
60+ g_source_remove (p->rebuild_timer_id);
61+ p->rebuild_timer_id = 0;
62+ }
63+}
64+
65 static void
66 app_menu_bridge_dispose (GObject *object)
67 {
68 AppMenuBridge *bridge = APP_MENU_BRIDGE (object);
69-
70- g_list_foreach (bridge->priv->windows, (GFunc)context_dispose, NULL);
71-
72- if (bridge->priv->appmenuproxy)
73- {
74- g_object_unref (bridge->priv->appmenuproxy);
75- bridge->priv->appmenuproxy = NULL;
76- }
77+ AppMenuBridgePrivate * p = bridge->priv;
78+
79+ rebuild_list_clear (bridge);
80+ g_list_foreach (p->windows, (GFunc)context_dispose, NULL);
81+ g_clear_object (&p->appmenuproxy);
82 }
83
84 static void
85 app_menu_bridge_finalize (GObject *object)
86 {
87 AppMenuBridge *bridge = APP_MENU_BRIDGE (object);
88+ AppMenuBridgePrivate * p = bridge->priv;
89
90- g_list_foreach (bridge->priv->windows, (GFunc)context_free, NULL);
91- g_list_free (bridge->priv->windows);
92- bridge->priv->windows = NULL;
93+ g_list_foreach (p->windows, (GFunc)context_free, NULL);
94+ g_list_free (p->windows);
95+ p->windows = NULL;
96
97 G_OBJECT_CLASS (app_menu_bridge_parent_class)->finalize (object);
98 }
99@@ -505,63 +527,51 @@
100 return;
101 }
102
103-typedef struct _RebuildData {
104- AppMenuBridge *bridge;
105- GtkWidget *widget;
106-} RebuildData;
107-
108 static gboolean
109-do_rebuild (RebuildData *data)
110+rebuild_timer_func (gpointer gbridge)
111 {
112- if (data->widget != NULL && gtk_widget_is_toplevel (data->widget))
113- {
114- rebuild_window_items (data->bridge,
115- data->widget);
116- }
117-
118- if (data->widget != NULL)
119- {
120- g_object_remove_weak_pointer (G_OBJECT (data->widget), (gpointer*)&data->widget);
121- g_hash_table_remove (rebuild_ids, data->widget);
122- }
123-
124- g_free (data);
125-
126- return FALSE;
127+ GSList * l;
128+ AppMenuBridge *bridge = APP_MENU_BRIDGE (gbridge);
129+ AppMenuBridgePrivate * p = bridge->priv;
130+
131+ /* call rebuild_window_items() for each toplevel in our list */
132+ for (l=p->rebuild_list; l!=NULL; l=l->next)
133+ {
134+ GtkWidget * w = GTK_WIDGET(l->data);
135+
136+ if (gtk_widget_is_toplevel(w))
137+ rebuild_window_items (bridge, w);
138+ }
139+
140+ /* cleanup */
141+ rebuild_list_clear (bridge);
142+ return G_SOURCE_REMOVE;
143 }
144
145+/* widgets tend to get a lot of changes all at once...
146+ + inserting a 100 msec delay here lets us batch up those changes */
147 static void
148-rebuild (AppMenuBridge *bridge,
149- GtkWidget *toplevel)
150+rebuild (AppMenuBridge * bridge, GtkWidget * toplevel)
151 {
152- guint id = 0;
153-
154- if (rebuild_ids != NULL)
155- {
156- id = GPOINTER_TO_UINT (g_hash_table_lookup (rebuild_ids, toplevel));
157-
158- if (id > 0)
159- {
160- g_source_remove (id);
161- g_hash_table_remove (rebuild_ids, toplevel);
162- id = 0;
163- }
164- }
165-
166- RebuildData *data = g_new0 (RebuildData, 1);
167- data->bridge = bridge;
168- data->widget = toplevel;
169-
170- id = gdk_threads_add_timeout (100, (GSourceFunc)do_rebuild, data);
171-
172- g_object_add_weak_pointer (G_OBJECT (data->widget), (gpointer*)&data->widget);
173-
174- if (rebuild_ids == NULL)
175- {
176- rebuild_ids = g_hash_table_new (g_direct_hash, g_direct_equal);
177- }
178-
179- g_hash_table_insert (rebuild_ids, toplevel, GUINT_TO_POINTER (id));
180+ AppMenuBridgePrivate * p = bridge->priv;
181+
182+ g_return_if_fail (toplevel != NULL);
183+
184+ /* ensure there's a rebuild timer ticking */
185+ if (p->rebuild_timer_id == 0)
186+ {
187+ p->rebuild_timer_id = gdk_threads_add_timeout (100,
188+ rebuild_timer_func,
189+ bridge);
190+ }
191+
192+ /* ensure this widget is in our rebuild list */
193+ if (g_slist_find (p->rebuild_list, toplevel) == NULL)
194+ {
195+ GObject * o = G_OBJECT(toplevel);
196+ p->rebuild_list = g_slist_prepend (p->rebuild_list, o);
197+ g_object_weak_ref (o, rebuild_list_widget_destroyed, bridge);
198+ }
199 }
200
201 static DbusmenuMenuitem * find_menu_bar (GtkWidget * widget);
202@@ -985,9 +995,4 @@
203 G_MODULE_EXPORT void
204 menu_proxy_module_unload (UbuntuMenuProxyModule *module)
205 {
206- if (rebuild_ids)
207- {
208- g_hash_table_destroy (rebuild_ids);
209- rebuild_ids = NULL;
210- }
211 }

Subscribers

People subscribed via source and target branches