Merge pull request #58 from kainjow/osx-mapTable-leak-crash
Fix crash when closing program on OS X
This commit is contained in:
commit
ea6bef5146
|
@ -2,6 +2,7 @@
|
||||||
#import "uipriv_darwin.h"
|
#import "uipriv_darwin.h"
|
||||||
|
|
||||||
static BOOL canQuit = NO;
|
static BOOL canQuit = NO;
|
||||||
|
static NSAutoreleasePool *globalPool;
|
||||||
|
|
||||||
@implementation applicationClass
|
@implementation applicationClass
|
||||||
|
|
||||||
|
@ -72,7 +73,8 @@ static BOOL canQuit = NO;
|
||||||
|
|
||||||
- (void)dealloc
|
- (void)dealloc
|
||||||
{
|
{
|
||||||
[self.menuManager release];
|
// Apple docs: "Don't Use Accessor Methods in Initializer Methods and dealloc"
|
||||||
|
[_menuManager release];
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,6 +101,10 @@ uiInitOptions options;
|
||||||
|
|
||||||
const char *uiInit(uiInitOptions *o)
|
const char *uiInit(uiInitOptions *o)
|
||||||
{
|
{
|
||||||
|
globalPool = [[NSAutoreleasePool alloc] init];
|
||||||
|
|
||||||
|
@autoreleasepool {
|
||||||
|
|
||||||
options = *o;
|
options = *o;
|
||||||
[applicationClass sharedApplication];
|
[applicationClass sharedApplication];
|
||||||
// don't check for a NO return; something (launch services?) causes running from application bundles to always return NO when asking to change activation policy, even if the change is to the same activation policy!
|
// don't check for a NO return; something (launch services?) causes running from application bundles to always return NO when asking to change activation policy, even if the change is to the same activation policy!
|
||||||
|
@ -109,21 +115,28 @@ const char *uiInit(uiInitOptions *o)
|
||||||
initAlloc();
|
initAlloc();
|
||||||
|
|
||||||
// always do this so we always have an application menu
|
// always do this so we always have an application menu
|
||||||
appDelegate().menuManager = [menuManager new];
|
appDelegate().menuManager = [[menuManager new] autorelease];
|
||||||
[realNSApp() setMainMenu:[appDelegate().menuManager makeMenubar]];
|
[realNSApp() setMainMenu:[appDelegate().menuManager makeMenubar]];
|
||||||
|
|
||||||
setupFontPanel();
|
setupFontPanel();
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
} // @autoreleasepool
|
||||||
}
|
}
|
||||||
|
|
||||||
void uiUninit(void)
|
void uiUninit(void)
|
||||||
{
|
{
|
||||||
uninitMenus();
|
@autoreleasepool {
|
||||||
[realNSApp() setDelegate:nil];
|
|
||||||
[appDelegate() release];
|
[appDelegate() release];
|
||||||
|
[realNSApp() setDelegate:nil];
|
||||||
[realNSApp() release];
|
[realNSApp() release];
|
||||||
uninitAlloc();
|
uninitAlloc();
|
||||||
|
|
||||||
|
} // @autoreleasepool
|
||||||
|
|
||||||
|
[globalPool release];
|
||||||
}
|
}
|
||||||
|
|
||||||
void uiFreeInitError(const char *err)
|
void uiFreeInitError(const char *err)
|
||||||
|
|
16
darwin/map.m
16
darwin/map.m
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -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];
|
||||||
}
|
}
|
||||||
|
@ -116,14 +127,14 @@ enum {
|
||||||
NSMenu *servicesMenu;
|
NSMenu *servicesMenu;
|
||||||
|
|
||||||
appName = [[NSProcessInfo processInfo] processName];
|
appName = [[NSProcessInfo processInfo] processName];
|
||||||
appMenuItem = [[NSMenuItem alloc] initWithTitle:appName action:NULL keyEquivalent:@""];
|
appMenuItem = [[[NSMenuItem alloc] initWithTitle:appName action:NULL keyEquivalent:@""] autorelease];
|
||||||
appMenu = [[NSMenu alloc] initWithTitle:appName];
|
appMenu = [[[NSMenu alloc] initWithTitle:appName] autorelease];
|
||||||
[appMenuItem setSubmenu:appMenu];
|
[appMenuItem setSubmenu:appMenu];
|
||||||
[menubar addItem:appMenuItem];
|
[menubar addItem:appMenuItem];
|
||||||
|
|
||||||
// first is About
|
// first is About
|
||||||
title = [@"About " stringByAppendingString:appName];
|
title = [@"About " stringByAppendingString:appName];
|
||||||
item = [[NSMenuItem alloc] initWithTitle:title action:@selector(onClicked:) keyEquivalent:@""];
|
item = [[[NSMenuItem alloc] initWithTitle:title action:@selector(onClicked:) keyEquivalent:@""] autorelease];
|
||||||
[item setTarget:self];
|
[item setTarget:self];
|
||||||
[appMenu addItem:item];
|
[appMenu addItem:item];
|
||||||
self.aboutItem = item;
|
self.aboutItem = item;
|
||||||
|
@ -131,7 +142,7 @@ enum {
|
||||||
[appMenu addItem:[NSMenuItem separatorItem]];
|
[appMenu addItem:[NSMenuItem separatorItem]];
|
||||||
|
|
||||||
// next is Preferences
|
// next is Preferences
|
||||||
item = [[NSMenuItem alloc] initWithTitle:@"Preferences…" action:@selector(onClicked:) keyEquivalent:@","];
|
item = [[[NSMenuItem alloc] initWithTitle:@"Preferences…" action:@selector(onClicked:) keyEquivalent:@","] autorelease];
|
||||||
[item setTarget:self];
|
[item setTarget:self];
|
||||||
[appMenu addItem:item];
|
[appMenu addItem:item];
|
||||||
self.preferencesItem = item;
|
self.preferencesItem = item;
|
||||||
|
@ -139,8 +150,8 @@ enum {
|
||||||
[appMenu addItem:[NSMenuItem separatorItem]];
|
[appMenu addItem:[NSMenuItem separatorItem]];
|
||||||
|
|
||||||
// next is Services
|
// next is Services
|
||||||
item = [[NSMenuItem alloc] initWithTitle:@"Services" action:NULL keyEquivalent:@""];
|
item = [[[NSMenuItem alloc] initWithTitle:@"Services" action:NULL keyEquivalent:@""] autorelease];
|
||||||
servicesMenu = [[NSMenu alloc] initWithTitle:@"Services"];
|
servicesMenu = [[[NSMenu alloc] initWithTitle:@"Services"] autorelease];
|
||||||
[item setSubmenu:servicesMenu];
|
[item setSubmenu:servicesMenu];
|
||||||
[realNSApp() setServicesMenu:servicesMenu];
|
[realNSApp() setServicesMenu:servicesMenu];
|
||||||
[appMenu addItem:item];
|
[appMenu addItem:item];
|
||||||
|
@ -149,14 +160,14 @@ enum {
|
||||||
|
|
||||||
// next are the three hiding options
|
// next are the three hiding options
|
||||||
title = [@"Hide " stringByAppendingString:appName];
|
title = [@"Hide " stringByAppendingString:appName];
|
||||||
item = [[NSMenuItem alloc] initWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
|
item = [[[NSMenuItem alloc] initWithTitle:title action:@selector(hide:) keyEquivalent:@"h"] autorelease];
|
||||||
// the .xib file says they go to -1 ("First Responder", which sounds wrong...)
|
// the .xib file says they go to -1 ("First Responder", which sounds wrong...)
|
||||||
// to do that, we simply leave the target as nil
|
// to do that, we simply leave the target as nil
|
||||||
[appMenu addItem:item];
|
[appMenu addItem:item];
|
||||||
item = [[NSMenuItem alloc] initWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
|
item = [[[NSMenuItem alloc] initWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"] autorelease];
|
||||||
[item setKeyEquivalentModifierMask:(NSAlternateKeyMask | NSCommandKeyMask)];
|
[item setKeyEquivalentModifierMask:(NSAlternateKeyMask | NSCommandKeyMask)];
|
||||||
[appMenu addItem:item];
|
[appMenu addItem:item];
|
||||||
item = [[NSMenuItem alloc] initWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
|
item = [[[NSMenuItem alloc] initWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""] autorelease];
|
||||||
[appMenu addItem:item];
|
[appMenu addItem:item];
|
||||||
|
|
||||||
[appMenu addItem:[NSMenuItem separatorItem]];
|
[appMenu addItem:[NSMenuItem separatorItem]];
|
||||||
|
@ -164,7 +175,7 @@ enum {
|
||||||
// and finally Quit
|
// and finally Quit
|
||||||
// DON'T use @selector(terminate:) as the action; we handle termination ourselves
|
// DON'T use @selector(terminate:) as the action; we handle termination ourselves
|
||||||
title = [@"Quit " stringByAppendingString:appName];
|
title = [@"Quit " stringByAppendingString:appName];
|
||||||
item = [[NSMenuItem alloc] initWithTitle:title action:@selector(onQuitClicked:) keyEquivalent:@"q"];
|
item = [[[NSMenuItem alloc] initWithTitle:title action:@selector(onQuitClicked:) keyEquivalent:@"q"] autorelease];
|
||||||
[item setTarget:self];
|
[item setTarget:self];
|
||||||
[appMenu addItem:item];
|
[appMenu addItem:item];
|
||||||
self.quitItem = item;
|
self.quitItem = item;
|
||||||
|
@ -174,7 +185,7 @@ enum {
|
||||||
{
|
{
|
||||||
NSMenu *menubar;
|
NSMenu *menubar;
|
||||||
|
|
||||||
menubar = [[NSMenu alloc] initWithTitle:@""];
|
menubar = [[[NSMenu alloc] initWithTitle:@""] autorelease];
|
||||||
[self buildApplicationMenu:menubar];
|
[self buildApplicationMenu:menubar];
|
||||||
return menubar;
|
return menubar;
|
||||||
}
|
}
|
||||||
|
@ -222,6 +233,8 @@ void uiMenuItemSetChecked(uiMenuItem *item, int checked)
|
||||||
|
|
||||||
static uiMenuItem *newItem(uiMenu *m, int type, const char *name)
|
static uiMenuItem *newItem(uiMenu *m, int type, const char *name)
|
||||||
{
|
{
|
||||||
|
@autoreleasepool {
|
||||||
|
|
||||||
uiMenuItem *item;
|
uiMenuItem *item;
|
||||||
|
|
||||||
if (menusFinalized)
|
if (menusFinalized)
|
||||||
|
@ -232,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:
|
||||||
|
@ -257,6 +270,8 @@ static uiMenuItem *newItem(uiMenu *m, int type, const char *name)
|
||||||
[m->items addObject:[NSValue valueWithPointer:item]];
|
[m->items addObject:[NSValue valueWithPointer:item]];
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
|
|
||||||
|
} // @autoreleasepool
|
||||||
}
|
}
|
||||||
|
|
||||||
uiMenuItem *uiMenuAppendItem(uiMenu *m, const char *name)
|
uiMenuItem *uiMenuAppendItem(uiMenu *m, const char *name)
|
||||||
|
@ -294,6 +309,8 @@ void uiMenuAppendSeparator(uiMenu *m)
|
||||||
|
|
||||||
uiMenu *uiNewMenu(const char *name)
|
uiMenu *uiNewMenu(const char *name)
|
||||||
{
|
{
|
||||||
|
@autoreleasepool {
|
||||||
|
|
||||||
uiMenu *m;
|
uiMenu *m;
|
||||||
|
|
||||||
if (menusFinalized)
|
if (menusFinalized)
|
||||||
|
@ -316,6 +333,8 @@ uiMenu *uiNewMenu(const char *name)
|
||||||
[menus addObject:[NSValue valueWithPointer:m]];
|
[menus addObject:[NSValue valueWithPointer:m]];
|
||||||
|
|
||||||
return m;
|
return m;
|
||||||
|
|
||||||
|
} // @autoreleasepool
|
||||||
}
|
}
|
||||||
|
|
||||||
void finalizeMenus(void)
|
void finalizeMenus(void)
|
||||||
|
@ -327,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;
|
||||||
|
|
|
@ -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 *);
|
||||||
|
|
Loading…
Reference in New Issue