Merge lp:~charlesk/appmenu-gtk/lp-787736 into lp:appmenu-gtk/12.10

Proposed by Charles Kerr
Status: Merged
Merged at revision: 158
Proposed branch: lp:~charlesk/appmenu-gtk/lp-787736
Merge into: lp:appmenu-gtk/12.10
Diff against target: 218 lines (+90/-79)
1 file modified
src/bridge.c (+90/-79)
To merge this branch: bzr merge lp:~charlesk/appmenu-gtk/lp-787736
Reviewer Review Type Date Requested Status
jenkins (community) continuous-integration Needs Fixing
Lars Karlitski (community) Approve
Indicator Applet Developers Pending
Review via email: mp+103709@code.launchpad.net

Commit message

Fix a memory leak -- RebuildStructs were being leaked. (LP #787736)

Description of the change

Putting this fix in a standalone branch, without a half-dozen surrounding interwoven cleanup commits, to make it easier to cherry pick

To post a comment you must log in.
Revision history for this message
jenkins (martin-mrazik+qa) wrote :

PASSED: Continuous integration, rev:154
http://s-jenkins:8080/job/appmenu-gtk-ci/1/

review: Approve (continuous-integration)
Revision history for this message
jenkins (martin-mrazik+qa) wrote :
review: Approve (continuous-integration)
Revision history for this message
Lars Karlitski (larsu) wrote :

That's much cleaner, I like it.

* rebuild_list_clear is called in both dispose and in finalize

* rebuild_timer_func is the callback for the timer to rebuild widgets. It calls rebuild_list_clear, which removes the timer source with g_source_remove. Is removing sources in their callbacks allowed?

* you could be making life easier for this particular reviewer if you return G_SOURCE_REMOVE instead of FALSE in rebuild_timer_func (he has trouble remembering if TRUE or FALSE remove a source)

review: Needs Information
Revision history for this message
Charles Kerr (charlesk) wrote :

* wrt rebuild_list_clear being called twice, yes. I was continuing the double-clear behavior that's been in place since http://bazaar.launchpad.net/~canonical-dx-team/appmenu-gtk/trunk.12.10/revision/119.3.3 but it's not clear to me if the original behavior was necessary or accidental.

* removing sources in their callbacks works fine.

* Ah, G_SOURCE_REMOVE is a nice mnemonic device. I didn't know about that!

Revision history for this message
jenkins (martin-mrazik+qa) wrote :
review: Approve (continuous-integration)
Revision history for this message
Lars Karlitski (larsu) wrote :

Thanks for the info!

review: Approve
Revision history for this message
jenkins (martin-mrazik+qa) wrote :

FAILED: Autolanding.
No commit message was specified.
http://jenkins.qa.ubuntu.com/job/appmenu-gtk-autolanding/3/

review: Needs Fixing (continuous-integration)
Revision history for this message
Charles Kerr (charlesk) wrote :

(That failure message from jenkins looks like a false negative. Plus, the same code passed twelve hours ago.)

Revision history for this message
jenkins (martin-mrazik+qa) wrote :

FAILED: Autolanding.
No commit message was specified.
http://jenkins.qa.ubuntu.com/job/appmenu-gtk-autolanding/4/

review: Needs Fixing (continuous-integration)
Revision history for this message
Charles Kerr (charlesk) wrote :

:/

Revision history for this message
Allan LeSage (allanlesage) wrote :

Charles here's the link to that dput-failure: go ahead and post a commit message and I'll re-start the job: http://s-jenkins/job/generic-land/346/console

Revision history for this message
Charles Kerr (charlesk) wrote :

Landing this manually after talking over the CI problem with Allan.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/bridge.c'
--- src/bridge.c 2012-08-22 06:56:22 +0000
+++ src/bridge.c 2012-08-30 13:08:20 +0000
@@ -85,21 +85,13 @@
8585
86 GDBusProxy *appmenuproxy;86 GDBusProxy *appmenuproxy;
87 gboolean online;87 gboolean online;
88
89 GSList *rebuild_list;
90 guint rebuild_timer_id;
88};91};
8992
90typedef struct _RecurseContext
91{
92 AppMenuBridge *bridge;
93 AppWindowContext *context;
94
95 gint count;
96 gboolean previous;
97 DbusmenuMenuitem *stack[30];
98} RecurseContext;
99
100G_DEFINE_DYNAMIC_TYPE(AppMenuBridge, app_menu_bridge, UBUNTU_TYPE_MENU_PROXY)93G_DEFINE_DYNAMIC_TYPE(AppMenuBridge, app_menu_bridge, UBUNTU_TYPE_MENU_PROXY)
10194
102static GHashTable *rebuild_ids = NULL;
103static GDBusNodeInfo * registrar_node_info = NULL;95static GDBusNodeInfo * registrar_node_info = NULL;
104static GDBusInterfaceInfo * registrar_interface_info = NULL;96static GDBusInterfaceInfo * registrar_interface_info = NULL;
10597
@@ -213,28 +205,59 @@
213 g_free (context);205 g_free (context);
214}206}
215207
208
209/* a widget that was queued for rebuild has been destroyed,
210 so remove it from our queue */
211static void
212rebuild_list_widget_destroyed (gpointer gbridge, GObject * dead_object)
213{
214 AppMenuBridge * bridge = APP_MENU_BRIDGE (gbridge);
215 AppMenuBridgePrivate * p = bridge->priv;
216
217 p->rebuild_list = g_slist_remove (p->rebuild_list, dead_object);
218}
219
220static void
221rebuild_list_clear (AppMenuBridge * bridge)
222{
223 GSList * l;
224 AppMenuBridgePrivate * p = bridge->priv;
225 g_debug (G_STRLOC" clearing bridge %p's rebuild list", bridge);
226
227 /* unref the widgets and blow away the list */
228 for (l=p->rebuild_list; l!=NULL; l=l->next)
229 g_object_weak_unref (l->data, rebuild_list_widget_destroyed, bridge);
230 g_slist_free (p->rebuild_list);
231 p->rebuild_list = NULL;
232
233 /* remove the rebuild timer */
234 if (p->rebuild_timer_id > 0)
235 {
236 g_source_remove (p->rebuild_timer_id);
237 p->rebuild_timer_id = 0;
238 }
239}
240
216static void241static void
217app_menu_bridge_dispose (GObject *object)242app_menu_bridge_dispose (GObject *object)
218{243{
219 AppMenuBridge *bridge = APP_MENU_BRIDGE (object);244 AppMenuBridge *bridge = APP_MENU_BRIDGE (object);
220245 AppMenuBridgePrivate * p = bridge->priv;
221 g_list_foreach (bridge->priv->windows, (GFunc)context_dispose, NULL);246
222247 rebuild_list_clear (bridge);
223 if (bridge->priv->appmenuproxy)248 g_list_foreach (p->windows, (GFunc)context_dispose, NULL);
224 {249 g_clear_object (&p->appmenuproxy);
225 g_object_unref (bridge->priv->appmenuproxy);
226 bridge->priv->appmenuproxy = NULL;
227 }
228}250}
229251
230static void252static void
231app_menu_bridge_finalize (GObject *object)253app_menu_bridge_finalize (GObject *object)
232{254{
233 AppMenuBridge *bridge = APP_MENU_BRIDGE (object);255 AppMenuBridge *bridge = APP_MENU_BRIDGE (object);
256 AppMenuBridgePrivate * p = bridge->priv;
234257
235 g_list_foreach (bridge->priv->windows, (GFunc)context_free, NULL);258 g_list_foreach (p->windows, (GFunc)context_free, NULL);
236 g_list_free (bridge->priv->windows);259 g_list_free (p->windows);
237 bridge->priv->windows = NULL;260 p->windows = NULL;
238261
239 G_OBJECT_CLASS (app_menu_bridge_parent_class)->finalize (object);262 G_OBJECT_CLASS (app_menu_bridge_parent_class)->finalize (object);
240}263}
@@ -505,63 +528,56 @@
505 return;528 return;
506}529}
507530
508typedef struct _RebuildData {
509 AppMenuBridge *bridge;
510 GtkWidget *widget;
511} RebuildData;
512
513static gboolean531static gboolean
514do_rebuild (RebuildData *data)532rebuild_timer_func (gpointer gbridge)
515{533{
516 if (data->widget != NULL && gtk_widget_is_toplevel (data->widget))534 GSList * l;
517 {535 AppMenuBridge *bridge = APP_MENU_BRIDGE (gbridge);
518 rebuild_window_items (data->bridge,536 AppMenuBridgePrivate * p = bridge->priv;
519 data->widget);537
520 }538 /* call rebuild_window_items() for each toplevel in our list */
521539 for (l=p->rebuild_list; l!=NULL; l=l->next)
522 if (data->widget != NULL)540 {
523 {541 GtkWidget * w = GTK_WIDGET(l->data);
524 g_object_remove_weak_pointer (G_OBJECT (data->widget), (gpointer*)&data->widget);542
525 g_hash_table_remove (rebuild_ids, data->widget);543 if (gtk_widget_is_toplevel(w))
526 }
527
528 g_free (data);
529
530 return FALSE;
531}
532
533static void
534rebuild (AppMenuBridge *bridge,
535 GtkWidget *toplevel)
536{
537 guint id = 0;
538
539 if (rebuild_ids != NULL)
540 {
541 id = GPOINTER_TO_UINT (g_hash_table_lookup (rebuild_ids, toplevel));
542
543 if (id > 0)
544 {544 {
545 g_source_remove (id);545 g_debug (G_STRLOC" rebuilding bridge %p's toplevel %p", bridge, w);
546 g_hash_table_remove (rebuild_ids, toplevel);546 rebuild_window_items (bridge, w);
547 id = 0;
548 }547 }
549 }548 }
550549
551 RebuildData *data = g_new0 (RebuildData, 1);550 /* cleanup */
552 data->bridge = bridge;551 rebuild_list_clear (bridge);
553 data->widget = toplevel;552 return G_SOURCE_REMOVE;
554553}
555 id = gdk_threads_add_timeout (100, (GSourceFunc)do_rebuild, data);554
556555/* widgets tend to get a lot of changes all at once...
557 g_object_add_weak_pointer (G_OBJECT (data->widget), (gpointer*)&data->widget);556 + inserting a 100 msec delay here lets us batch up those changes */
558557static void
559 if (rebuild_ids == NULL)558rebuild (AppMenuBridge * bridge, GtkWidget * toplevel)
560 {559{
561 rebuild_ids = g_hash_table_new (g_direct_hash, g_direct_equal);560 AppMenuBridgePrivate * p = bridge->priv;
562 }561
563562 g_return_if_fail (toplevel != NULL);
564 g_hash_table_insert (rebuild_ids, toplevel, GUINT_TO_POINTER (id));563
564 /* ensure there's a rebuild timer ticking */
565 if (p->rebuild_timer_id == 0)
566 {
567 g_debug (G_STRLOC" creating rebuild timer");
568 p->rebuild_timer_id = gdk_threads_add_timeout (100,
569 rebuild_timer_func,
570 bridge);
571 }
572
573 /* ensure this widget is in our rebuild list */
574 if (g_slist_find (p->rebuild_list, toplevel) == NULL)
575 {
576 GObject * o = G_OBJECT(toplevel);
577 g_debug (G_STRLOC" adding widget %p to bridge %p's queue", o, bridge);
578 p->rebuild_list = g_slist_prepend (p->rebuild_list, o);
579 g_object_weak_ref (o, rebuild_list_widget_destroyed, bridge);
580 }
565}581}
566582
567static DbusmenuMenuitem * find_menu_bar (GtkWidget * widget);583static DbusmenuMenuitem * find_menu_bar (GtkWidget * widget);
@@ -989,9 +1005,4 @@
989G_MODULE_EXPORT void1005G_MODULE_EXPORT void
990menu_proxy_module_unload (UbuntuMenuProxyModule *module)1006menu_proxy_module_unload (UbuntuMenuProxyModule *module)
991{1007{
992 if (rebuild_ids)
993 {
994 g_hash_table_destroy (rebuild_ids);
995 rebuild_ids = NULL;
996 }
997}1008}

Subscribers

People subscribed via source and target branches