From d37bc67158228e75dc4f47cf445c771a890fb35a Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Wed, 8 Apr 2015 01:16:22 -0400 Subject: [PATCH] Cleaned up memory leaks in the GTK+ backend. --- new/button_unix.c | 9 ++++++++- new/container_unix.c | 4 ++++ new/newcontrol_unix.c | 25 ++++++++++++++++++++++++- new/window_unix.c | 2 +- 4 files changed, 37 insertions(+), 3 deletions(-) diff --git a/new/button_unix.c b/new/button_unix.c index 986e81d..8ab9aa6 100644 --- a/new/button_unix.c +++ b/new/button_unix.c @@ -19,7 +19,13 @@ static void defaultOnClicked(uiControl *c, void *data) // do nothing } -// TODO destruction +static void onDestroy(GtkWidget *widget, gpointer data) +{ + struct button *b = (struct button *) data; + + uiFree(b); +} + uiControl *uiNewButton(const char *text) { struct button *b; @@ -33,6 +39,7 @@ uiControl *uiNewButton(const char *text) NULL); widget = GTK_WIDGET(uiControlHandle(b->c)); + g_signal_connect(widget, "destroy", G_CALLBACK(onDestroy), b); g_signal_connect(widget, "clicked", G_CALLBACK(onClicked), b); b->onClicked = defaultOnClicked; diff --git a/new/container_unix.c b/new/container_unix.c index 5192639..3a0b517 100644 --- a/new/container_unix.c +++ b/new/container_unix.c @@ -15,6 +15,10 @@ static void uiContainer_init(uiContainer *c) static void uiContainer_dispose(GObject *obj) { g_ptr_array_unref(uiContainer(obj)->children); + if (uiContainer(obj)->child != NULL) { + uiControlDestroy(uiContainer(obj)->child); + uiContainer(obj)->child = NULL; + } G_OBJECT_CLASS(uiContainer_parent_class)->dispose(obj); } diff --git a/new/newcontrol_unix.c b/new/newcontrol_unix.c index 673bb81..b424aa6 100644 --- a/new/newcontrol_unix.c +++ b/new/newcontrol_unix.c @@ -13,6 +13,11 @@ struct uiSingleWidgetControl { #define S(c) ((uiSingleWidgetControl *) (c)) +static void singleDestroy(uiControl *c) +{ + gtk_widget_destroy(S(c)->immediate); +} + static uintptr_t singleHandle(uiControl *c) { return (uintptr_t) (S(c)->widget); @@ -48,7 +53,12 @@ static void singleResize(uiControl *c, intmax_t x, intmax_t y, intmax_t width, i gtk_widget_size_allocate(S(c)->immediate, &a); } -// TODO connect free function +static void onDestroy(GtkWidget *widget, gpointer data) +{ + uiSingleWidgetControl *c = (uiSingleWidgetControl *) data; + + uiFree(c); +} uiControl *uiUnixNewControl(GType type, gboolean inScrolledWindow, gboolean needsViewport, gboolean scrolledWindowHasBorder, void *data, const char *firstProperty, ...) { @@ -75,6 +85,19 @@ uiControl *uiUnixNewControl(GType type, gboolean inScrolledWindow, gboolean need c->immediate = c->scrolledWindow; } + // we need to keep an extra reference on the immediate widget + // this is so uiControlDestroy() can work regardless of when it is called and who calls it + // without this: + // - end user call works (only one ref) + // - call in uiContainer destructor fails (uiContainer ref freed) + // with this: + // - end user call works (shoudn't be in any container) + // - call in uiContainer works (both refs freed) + g_object_ref_sink(c->immediate); + // and let's free the uiSingleWidgetControl with it + g_signal_connect(c->immediate, "destroy", G_CALLBACK(onDestroy), c); + + c->control.destroy = singleDestroy; c->control.handle = singleHandle; c->control.setParent = singleSetParent; c->control.preferredSize = singlePreferredSize; diff --git a/new/window_unix.c b/new/window_unix.c index 3d6f8e7..293fa51 100644 --- a/new/window_unix.c +++ b/new/window_unix.c @@ -8,7 +8,7 @@ struct uiWindow { void *onClosingData; }; -static void onDestroy(GtkWindow *window, gpointer data) +static void onDestroy(GtkWidget *widget, gpointer data) { uiWindow *w = (uiWindow *) data;