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"
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);
}