summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPietro Gagliardi <[email protected]>2015-04-08 01:16:22 -0400
committerPietro Gagliardi <[email protected]>2015-04-08 01:16:22 -0400
commitd37bc67158228e75dc4f47cf445c771a890fb35a (patch)
tree34d3dc791b7eb46eb1658b22c630105792ee8af1
parentf5c8bdd4b3fb089370f3cc41a742b3385289efe1 (diff)
Cleaned up memory leaks in the GTK+ backend.
-rw-r--r--new/button_unix.c9
-rw-r--r--new/container_unix.c4
-rw-r--r--new/newcontrol_unix.c25
-rw-r--r--new/window_unix.c2
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;