diff --git a/TODO.md b/TODO.md index 9c65997b..e9725698 100644 --- a/TODO.md +++ b/TODO.md @@ -20,7 +20,7 @@ - verify that uiParentSetMainControl() does indeed not update - settle differences between intmax_t and uintmax_t - settle onDestroy/destroy naming -- clean up Unix lifetiming code +- clean up Windows lifetiming code ultimately: - make everything vtable-based diff --git a/unix/newcontrol.c b/unix/newcontrol.c index 1a9006f8..d7a39d5c 100644 --- a/unix/newcontrol.c +++ b/unix/newcontrol.c @@ -25,8 +25,10 @@ static void singleDestroy(uiControl *c) (*(s->onDestroy))(s->onDestroyData); // then mark that we are ready to be destroyed g_signal_handler_disconnect(s->immediate, s->destroyBlocker); - // then actually destroy + // then actually destroy (TODO sync these comments) gtk_widget_destroy(s->immediate); + // and free ourselves + uiFree(s); } static uintptr_t singleHandle(uiControl *c) diff --git a/unix/parent.c b/unix/parent.c index a279c814..9e934484 100644 --- a/unix/parent.c +++ b/unix/parent.c @@ -46,6 +46,8 @@ static void uipParent_dispose(GObject *obj) if (!p->canDestroy) complain("attempt to dispose uiParent with uipParent at %p before uiParentDestroy()", p); if (p->children != NULL) { + if (p->children->len != 0) + complain("disposing uiParent with uipParent at %p while there are still children", p); g_ptr_array_unref(p->children); p->children = NULL; } @@ -150,6 +152,8 @@ static void parentDestroy(uiParent *pp) p->canDestroy = TRUE; // finally, destroy the parent gtk_widget_destroy(GTK_WIDGET(p)); + // and free ourselves + uiFree(pp); } static uintptr_t parentHandle(uiParent *p) diff --git a/unix/window.c b/unix/window.c index a64cd189..a49c6b82 100644 --- a/unix/window.c +++ b/unix/window.c @@ -10,7 +10,7 @@ struct window { int (*onClosing)(uiWindow *, void *); void *onClosingData; int margined; - gboolean canDestroy; + gulong destroyBlocker; }; static gboolean onClosing(GtkWidget *win, GdkEvent *e, gpointer data) @@ -28,13 +28,9 @@ static int defaultOnClosing(uiWindow *w, void *data) return 1; } -static void onDestroy(GtkWidget *widget, gpointer data) +static void destroyBlocker(GtkWidget *widget, gpointer data) { - struct window *w = (struct window *) data; - - if (!w->canDestroy) - complain("attempt to dispose uiWindow at %p before uiWindowDestroy()", w); - uiFree(w); + complain("attempt to dispose uiWindow at %p before uiWindowDestroy()", data); } // TODO should we change the GtkWindow's child first? @@ -47,9 +43,11 @@ static void windowDestroy(uiWindow *ww) // next, destroy the content uiParent uiParentDestroy(w->content); // now that we cleaned up properly, we can mark our window as ready to be destroyed - w->canDestroy = TRUE; + g_signal_handler_disconnect(w->widget, w->destroyBlocker); // finally, destroy the window gtk_widget_destroy(w->widget); + // and free ourselves + uiFree(w); } static uintptr_t windowHandle(uiWindow *ww) @@ -136,7 +134,7 @@ uiWindow *uiNewWindow(const char *title, int width, int height) gtk_window_resize(w->window, width, height); g_signal_connect(w->widget, "delete-event", G_CALLBACK(onClosing), w); - g_signal_connect(w->widget, "destroy", G_CALLBACK(onDestroy), w); + w->destroyBlocker = g_signal_connect(w->widget, "destroy", G_CALLBACK(destroyBlocker), w); w->content = uiNewParent((uintptr_t) (w->container)); w->onClosing = defaultOnClosing;