Fix "attempt to destroy map with items inside" when menuManager is deallocated

Fixes #58. The map needs to have its contents properly freed which requires releasing the properly retaining the NSMenuItem object.
This commit is contained in:
Kevin Wojniak 2016-05-23 21:41:52 -07:00
parent abb3c39c78
commit 49e17cbfd7
4 changed files with 33 additions and 6 deletions

View File

@ -129,7 +129,6 @@ void uiUninit(void)
{ {
@autoreleasepool { @autoreleasepool {
uninitMenus();
[appDelegate() release]; [appDelegate() release];
[realNSApp() setDelegate:nil]; [realNSApp() setDelegate:nil];
[realNSApp() release]; [realNSApp() release];

View File

@ -41,3 +41,19 @@ void mapDelete(struct mapTable *m, void *key)
{ {
NSMapRemove(m->m, key); NSMapRemove(m->m, key);
} }
void mapWalk(struct mapTable *m, void (*f)(void *key, void *value))
{
NSMapEnumerator e = NSEnumerateMapTable(m->m);
void *k = NULL;
void *v = NULL;
while (NSNextMapEnumeratorPair(&e, &k, &v)) {
f(k, v);
}
NSEndMapTableEnumeration(&e);
}
void mapReset(struct mapTable *m)
{
NSResetMapTable(m->m);
}

View File

@ -27,6 +27,14 @@ enum {
typeSeparator, typeSeparator,
}; };
static void mapItemReleaser(void *key, void *value)
{
uiMenuItem *item;
item = (uiMenuItem *)value;
[item->item release];
}
@implementation menuManager @implementation menuManager
- (id)init - (id)init
@ -43,6 +51,9 @@ enum {
- (void)dealloc - (void)dealloc
{ {
uninitMenus();
mapWalk(self->items, mapItemReleaser);
mapReset(self->items);
mapDestroy(self->items); mapDestroy(self->items);
[super dealloc]; [super dealloc];
} }
@ -234,16 +245,16 @@ static uiMenuItem *newItem(uiMenu *m, int type, const char *name)
item->type = type; item->type = type;
switch (item->type) { switch (item->type) {
case typeQuit: case typeQuit:
item->item = appDelegate().menuManager.quitItem; item->item = [appDelegate().menuManager.quitItem retain];
break; break;
case typePreferences: case typePreferences:
item->item = appDelegate().menuManager.preferencesItem; item->item = [appDelegate().menuManager.preferencesItem retain];
break; break;
case typeAbout: case typeAbout:
item->item = appDelegate().menuManager.aboutItem; item->item = [appDelegate().menuManager.aboutItem retain];
break; break;
case typeSeparator: case typeSeparator:
item->item = [NSMenuItem separatorItem]; item->item = [[NSMenuItem separatorItem] retain];
[m->menu addItem:item->item]; [m->menu addItem:item->item];
break; break;
default: default:
@ -335,7 +346,6 @@ void uninitMenus(void)
{ {
if (menus == NULL) if (menus == NULL)
return; return;
// don't worry about the actual NSMenus and NSMenuItems; they'll be freed when we clean up the NSApplication
[menus enumerateObjectsUsingBlock:^(id obj, NSUInteger index, BOOL *stop) { [menus enumerateObjectsUsingBlock:^(id obj, NSUInteger index, BOOL *stop) {
NSValue *v; NSValue *v;
uiMenu *m; uiMenu *m;

View File

@ -89,6 +89,8 @@ extern void mapDestroy(struct mapTable *m);
extern void *mapGet(struct mapTable *m, void *key); extern void *mapGet(struct mapTable *m, void *key);
extern void mapSet(struct mapTable *m, void *key, void *value); extern void mapSet(struct mapTable *m, void *key, void *value);
extern void mapDelete(struct mapTable *m, void *key); extern void mapDelete(struct mapTable *m, void *key);
extern void mapWalk(struct mapTable *m, void (*f)(void *key, void *value));
extern void mapReset(struct mapTable *m);
// area.m // area.m
extern int sendAreaEvents(NSEvent *); extern int sendAreaEvents(NSEvent *);