aboutsummaryrefslogtreecommitdiff
path: root/src/libui_sdl
diff options
context:
space:
mode:
authorStapleButter <thetotalworm@gmail.com>2017-12-05 05:21:11 +0100
committerStapleButter <thetotalworm@gmail.com>2017-12-05 05:21:11 +0100
commit10b797e53d4e6788fa30089de6242780af8c6db1 (patch)
treea05fb878862de26f925fb936099375fa62840838 /src/libui_sdl
parent746b4db3829d830813a2f79a958a645935eec51d (diff)
libui/GTK: properly clean up menus, so it doesn't crash upon exit
Diffstat (limited to 'src/libui_sdl')
-rw-r--r--src/libui_sdl/libui/unix/menu.c45
1 files changed, 31 insertions, 14 deletions
diff --git a/src/libui_sdl/libui/unix/menu.c b/src/libui_sdl/libui/unix/menu.c
index c4affd2..d6aa398 100644
--- a/src/libui_sdl/libui/unix/menu.c
+++ b/src/libui_sdl/libui/unix/menu.c
@@ -2,6 +2,7 @@
#include "uipriv_unix.h"
static GArray *menus = NULL;
+static guint nmenus = 0;
static gboolean menusFinalized = FALSE;
static gboolean hasQuit = FALSE;
static gboolean hasPreferences = FALSE;
@@ -11,6 +12,7 @@ struct uiMenu {
char *name;
GArray *items; // []*uiMenuItem
gboolean ischild;
+ guint id;
};
struct uiMenuItem {
@@ -267,6 +269,8 @@ uiMenu *uiNewMenu(const char *name)
m = uiNew(uiMenu);
g_array_append_val(menus, m);
+ m->id = nmenus;
+ nmenus++;
m->name = g_strdup(name);
m->items = g_array_new(FALSE, TRUE, sizeof (uiMenuItem *));
@@ -345,6 +349,8 @@ struct freeMenuItemData {
guint i;
};
+static void freeMenu(GtkWidget *widget, gpointer data);
+
static void freeMenuItem(GtkWidget *widget, gpointer data)
{
struct freeMenuItemData *fmi = (struct freeMenuItemData *) data;
@@ -352,6 +358,8 @@ static void freeMenuItem(GtkWidget *widget, gpointer data)
struct menuItemWindow *w;
item = g_array_index(fmi->items, uiMenuItem *, fmi->i);
+ if (item->popupchild != NULL)
+ freeMenu(widget, &item->popupchild->id);
w = (struct menuItemWindow *) g_hash_table_lookup(item->windows, widget);
if (g_hash_table_remove(item->windows, widget) == FALSE)
implbug("GtkMenuItem %p not in menu item's item/window map", widget);
@@ -385,28 +393,37 @@ void freeMenubar(GtkWidget *mb)
// no need to worry about destroying any widgets; destruction of the window they're in will do it for us
}
+void _freeMenu(uiMenu* m)
+{
+ uiMenuItem *item;
+ guint j;
+
+ g_free(m->name);
+ for (j = 0; j < m->items->len; j++) {
+ item = g_array_index(m->items, uiMenuItem *, j);
+ if (item->popupchild != NULL) _freeMenu(item->popupchild);
+ if (g_hash_table_size(item->windows) != 0)
+ // TODO is this really a userbug()?
+ implbug("menu item %p (%s) still has uiWindows attached; did you forget to destroy some windows?", item, item->name);
+ if (item->type != typeSubmenu) g_free(item->name);
+ g_hash_table_destroy(item->windows);
+ uiFree(item);
+ }
+ g_array_free(m->items, TRUE);
+ uiFree(m);
+}
+
void uninitMenus(void)
{
uiMenu *m;
- uiMenuItem *item;
- guint i, j;
+ guint i;
if (menus == NULL)
return;
for (i = 0; i < menus->len; i++) {
m = g_array_index(menus, uiMenu *, i);
- g_free(m->name);
- for (j = 0; j < m->items->len; j++) {
- item = g_array_index(m->items, uiMenuItem *, j);
- if (g_hash_table_size(item->windows) != 0)
- // TODO is this really a userbug()?
- implbug("menu item %p (%s) still has uiWindows attached; did you forget to destroy some windows?", item, item->name);
- g_free(item->name);
- g_hash_table_destroy(item->windows);
- uiFree(item);
- }
- g_array_free(m->items, TRUE);
- uiFree(m);
+ if (m->ischild) continue;
+ _freeMenu(m);
}
g_array_free(menus, TRUE);
}