libui/GTK: properly clean up menus, so it doesn't crash upon exit

This commit is contained in:
StapleButter 2017-12-05 05:21:11 +01:00
parent 746b4db382
commit 10b797e53d
1 changed files with 31 additions and 14 deletions

View File

@ -2,6 +2,7 @@
#include "uipriv_unix.h" #include "uipriv_unix.h"
static GArray *menus = NULL; static GArray *menus = NULL;
static guint nmenus = 0;
static gboolean menusFinalized = FALSE; static gboolean menusFinalized = FALSE;
static gboolean hasQuit = FALSE; static gboolean hasQuit = FALSE;
static gboolean hasPreferences = FALSE; static gboolean hasPreferences = FALSE;
@ -11,6 +12,7 @@ struct uiMenu {
char *name; char *name;
GArray *items; // []*uiMenuItem GArray *items; // []*uiMenuItem
gboolean ischild; gboolean ischild;
guint id;
}; };
struct uiMenuItem { struct uiMenuItem {
@ -267,6 +269,8 @@ uiMenu *uiNewMenu(const char *name)
m = uiNew(uiMenu); m = uiNew(uiMenu);
g_array_append_val(menus, m); g_array_append_val(menus, m);
m->id = nmenus;
nmenus++;
m->name = g_strdup(name); m->name = g_strdup(name);
m->items = g_array_new(FALSE, TRUE, sizeof (uiMenuItem *)); m->items = g_array_new(FALSE, TRUE, sizeof (uiMenuItem *));
@ -345,6 +349,8 @@ struct freeMenuItemData {
guint i; guint i;
}; };
static void freeMenu(GtkWidget *widget, gpointer data);
static void freeMenuItem(GtkWidget *widget, gpointer data) static void freeMenuItem(GtkWidget *widget, gpointer data)
{ {
struct freeMenuItemData *fmi = (struct freeMenuItemData *) data; struct freeMenuItemData *fmi = (struct freeMenuItemData *) data;
@ -352,6 +358,8 @@ static void freeMenuItem(GtkWidget *widget, gpointer data)
struct menuItemWindow *w; struct menuItemWindow *w;
item = g_array_index(fmi->items, uiMenuItem *, fmi->i); 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); w = (struct menuItemWindow *) g_hash_table_lookup(item->windows, widget);
if (g_hash_table_remove(item->windows, widget) == FALSE) if (g_hash_table_remove(item->windows, widget) == FALSE)
implbug("GtkMenuItem %p not in menu item's item/window map", widget); 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 // 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) void uninitMenus(void)
{ {
uiMenu *m; uiMenu *m;
uiMenuItem *item; guint i;
guint i, j;
if (menus == NULL) if (menus == NULL)
return; return;
for (i = 0; i < menus->len; i++) { for (i = 0; i < menus->len; i++) {
m = g_array_index(menus, uiMenu *, i); m = g_array_index(menus, uiMenu *, i);
g_free(m->name); if (m->ischild) continue;
for (j = 0; j < m->items->len; j++) { _freeMenu(m);
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);
} }
g_array_free(menus, TRUE); g_array_free(menus, TRUE);
} }