Completely rewrote the OS X map system to use NSMapTable correctly and hide the details behind more wrapper functions to prevent further mass rewrites; this fixes most of the crashing issues on OS X. The one with package ui still stands...

This commit is contained in:
Pietro Gagliardi 2016-01-07 14:41:20 -05:00
parent f9b940f698
commit 499a93e32e
9 changed files with 58 additions and 54 deletions

View File

@ -9,7 +9,7 @@ struct uiButton {
}; };
@interface buttonDelegateClass : NSObject { @interface buttonDelegateClass : NSObject {
NSMapTable *buttons; struct mapTable *buttons;
} }
- (IBAction)onClicked:(id)sender; - (IBAction)onClicked:(id)sender;
- (void)registerButton:(uiButton *)b; - (void)registerButton:(uiButton *)b;
@ -28,9 +28,7 @@ struct uiButton {
- (void)dealloc - (void)dealloc
{ {
if ([self->buttons count] != 0) mapDestroy(self->buttons);
complain("attempt to destroy shared button delegate but buttons are still registered to it");
[self->buttons release];
[super dealloc]; [super dealloc];
} }
@ -52,7 +50,7 @@ struct uiButton {
- (void)unregisterButton:(uiButton *)b - (void)unregisterButton:(uiButton *)b
{ {
[b->button setTarget:nil]; [b->button setTarget:nil];
[self->buttons removeObjectForKey:b->button]; mapDelete(self->buttons, b->button);
} }
@end @end

View File

@ -9,7 +9,7 @@ struct uiCheckbox {
}; };
@interface checkboxDelegateClass : NSObject { @interface checkboxDelegateClass : NSObject {
NSMapTable *buttons; struct mapTable *buttons;
} }
- (IBAction)onToggled:(id)sender; - (IBAction)onToggled:(id)sender;
- (void)registerCheckbox:(uiCheckbox *)c; - (void)registerCheckbox:(uiCheckbox *)c;
@ -28,9 +28,7 @@ struct uiCheckbox {
- (void)dealloc - (void)dealloc
{ {
if ([self->buttons count] != 0) mapDestroy(self->buttons);
complain("attempt to destroy shared checkbox delegate but checkboxes are still registered to it");
[self->buttons release];
[super dealloc]; [super dealloc];
} }
@ -52,7 +50,7 @@ struct uiCheckbox {
- (void)unregisterCheckbox:(uiCheckbox *)c - (void)unregisterCheckbox:(uiCheckbox *)c
{ {
[c->button setTarget:nil]; [c->button setTarget:nil];
[self->buttons removeObjectForKey:c->button]; mapDelete(self->buttons, c->button);
} }
@end @end

View File

@ -33,7 +33,7 @@ struct uiCombobox {
}; };
@interface comboboxDelegateClass : NSObject<NSComboBoxDelegate> { @interface comboboxDelegateClass : NSObject<NSComboBoxDelegate> {
NSMapTable *comboboxes; struct mapTable *comboboxes;
} }
- (void)comboBoxSelectionDidChange:(NSNotification *)note; - (void)comboBoxSelectionDidChange:(NSNotification *)note;
- (IBAction)onSelected:(id)sender; - (IBAction)onSelected:(id)sender;
@ -53,9 +53,7 @@ struct uiCombobox {
- (void)dealloc - (void)dealloc
{ {
if ([self->comboboxes count] != 0) mapDestroy(self->comboboxes);
complain("attempt to destroy shared combobox delegate but comboboxes are still registered to it");
[self->comboboxes release];
[super dealloc]; [super dealloc];
} }
@ -93,7 +91,7 @@ struct uiCombobox {
[c->cb setDelegate:nil]; [c->cb setDelegate:nil];
else else
[c->pb setTarget:nil]; [c->pb setTarget:nil];
[self->comboboxes removeObjectForKey:c->handle]; mapDelete(self->comboboxes, c->handle);
} }
@end @end

View File

@ -28,7 +28,7 @@ struct uiEntry {
}; };
@interface entryDelegateClass : NSObject<NSTextFieldDelegate> { @interface entryDelegateClass : NSObject<NSTextFieldDelegate> {
NSMapTable *entries; struct mapTable *entries;
} }
- (void)controlTextDidChange:(NSNotification *)note; - (void)controlTextDidChange:(NSNotification *)note;
- (void)registerEntry:(uiEntry *)e; - (void)registerEntry:(uiEntry *)e;
@ -47,9 +47,7 @@ struct uiEntry {
- (void)dealloc - (void)dealloc
{ {
if ([self->entries count] != 0) mapDestroy(self->entries);
complain("attempt to destroy shared entry delegate but entries are still registered to it");
[self->entries release];
[super dealloc]; [super dealloc];
} }
@ -70,7 +68,7 @@ struct uiEntry {
- (void)unregisterEntry:(uiEntry *)e - (void)unregisterEntry:(uiEntry *)e
{ {
[e->textfield setDelegate:nil]; [e->textfield setDelegate:nil];
[self->entries removeObjectForKey:e->textfield]; mapDelete(self->entries, e->textfield);
} }
@end @end

View File

@ -1,29 +1,44 @@
// 17 august 2015 // 17 august 2015
#import "uipriv_darwin.h" #import "uipriv_darwin.h"
// TODO are the NSValues (or worse, the NSMapTable) being garbage collected underfoot? open menuless window and check the checkbox; crash the package ui test when closing the main window; etc. // TODO are the NSValues (or worse, the NSMapTable) being garbage collected underfoot? crash the package ui test when closing the main window; etc.
// unfortunately NSMutableDictionary copies its keys, meaning we can't use it for pointers // unfortunately NSMutableDictionary copies its keys, meaning we can't use it for pointers
// hence, this file // hence, this file
// we could expose a NSMapTable directly, but let's treat all pointers as opaque and hide the implementation, just to be safe and prevent even more rewrites later
struct mapTable {
NSMapTable *m;
};
NSMapTable *newMap(void) struct mapTable *newMap(void)
{ {
return [NSMapTable mapTableWithKeyOptions:(NSPointerFunctionsOpaqueMemory | NSPointerFunctionsOpaquePersonality) struct mapTable *m;
valueOptions:NSPointerFunctionsOpaqueMemory];
m = uiNew(struct mapTable);
m->m = [NSMapTable mapTableWithKeyOptions:(NSPointerFunctionsOpaqueMemory | NSPointerFunctionsOpaquePersonality)
valueOptions:(NSPointerFunctionsOpaqueMemory | NSPointerFunctionsOpaquePersonality)];
return m;
} }
void *mapGet(NSMapTable *map, id key) void mapDestroy(struct mapTable *m)
{ {
NSValue *v; if ([m->m count] != 0)
complain("attempt to destroy map with items inside; did you forget to deallocate something?");
v = (NSValue *) [map objectForKey:key]; [m->m release];
return [v pointerValue]; uiFree(m);
} }
void mapSet(NSMapTable *map, id key, void *value) void *mapGet(struct mapTable *m, void *key)
{ {
NSValue *v; return NSMapGet(m->m, key);
}
v = [NSValue valueWithPointer:value];
[map setObject:v forKey:key]; void mapSet(struct mapTable *m, void *key, void *value)
{
NSMapInsert(m->m, key, value);
}
void mapDelete(struct mapTable *m, void *key)
{
NSMapRemove(m->m, key);
} }

View File

@ -45,7 +45,7 @@ enum {
- (void)dealloc - (void)dealloc
{ {
[self->items release]; mapDestroy(self->items);
[super dealloc]; [super dealloc];
} }

View File

@ -29,7 +29,7 @@ struct uiSlider {
}; };
@interface sliderDelegateClass : NSObject { @interface sliderDelegateClass : NSObject {
NSMapTable *sliders; struct mapTable *sliders;
} }
- (IBAction)onChanged:(id)sender; - (IBAction)onChanged:(id)sender;
- (void)registerSlider:(uiSlider *)b; - (void)registerSlider:(uiSlider *)b;
@ -48,9 +48,7 @@ struct uiSlider {
- (void)dealloc - (void)dealloc
{ {
if ([self->sliders count] != 0) mapDestroy(self->sliders);
complain("attempt to destroy shared slider delegate but sliders are still registered to it");
[self->sliders release];
[super dealloc]; [super dealloc];
} }
@ -72,7 +70,7 @@ struct uiSlider {
- (void)unregisterSlider:(uiSlider *)s - (void)unregisterSlider:(uiSlider *)s
{ {
[s->slider setTarget:nil]; [s->slider setTarget:nil];
[self->sliders removeObjectForKey:s->slider]; mapDelete(self->sliders, s->slider);
} }
@end @end

View File

@ -15,7 +15,7 @@
// menu.m // menu.m
@interface menuManager : NSObject { @interface menuManager : NSObject {
NSMapTable *items; struct mapTable *items;
BOOL hasQuit; BOOL hasQuit;
BOOL hasPreferences; BOOL hasPreferences;
BOOL hasAbout; BOOL hasAbout;
@ -64,9 +64,11 @@ extern void layoutSingleView(NSView *, NSView *, int);
extern NSSize fittingAlignmentSize(NSView *); extern NSSize fittingAlignmentSize(NSView *);
// map.m // map.m
extern NSMapTable *newMap(void); extern struct mapTable *newMap(void);
extern void *mapGet(NSMapTable *map, id key); extern void mapDestroy(struct mapTable *m);
extern void mapSet(NSMapTable *map, id key, void *value); extern void *mapGet(struct mapTable *m, void *key);
extern void mapSet(struct mapTable *m, void *key, void *value);
extern void mapDelete(struct mapTable *m, void *key);
// area.m // area.m
extern int sendAreaEvents(NSEvent *); extern int sendAreaEvents(NSEvent *);

View File

@ -11,7 +11,7 @@ struct uiWindow {
}; };
@interface windowDelegateClass : NSObject<NSWindowDelegate> { @interface windowDelegateClass : NSObject<NSWindowDelegate> {
NSMapTable *windows; struct mapTable *windows;
} }
- (BOOL)windowShouldClose:(id)sender; - (BOOL)windowShouldClose:(id)sender;
- (void)registerWindow:(uiWindow *)w; - (void)registerWindow:(uiWindow *)w;
@ -31,9 +31,7 @@ struct uiWindow {
- (void)dealloc - (void)dealloc
{ {
if ([self->windows count] != 0) mapDestroy(self->windows);
complain("attempt to destroy shared window delegate but windows are still registered to it");
[self->windows release];
[super dealloc]; [super dealloc];
} }
@ -57,17 +55,16 @@ struct uiWindow {
- (void)unregisterWindow:(uiWindow *)w - (void)unregisterWindow:(uiWindow *)w
{ {
[w->window setDelegate:nil]; [w->window setDelegate:nil];
[self->windows removeObjectForKey:w->window]; mapDelete(self->windows, w->window);
} }
- (uiWindow *)lookupWindow:(NSWindow *)w - (uiWindow *)lookupWindow:(NSWindow *)w
{ {
NSValue *v; uiWindow *v;
v = (NSValue *) [self->windows objectForKey:w]; v = (uiWindow *) mapGet(self->windows, w);
if (v == nil) // just in case we're called with some OS X-provided window as the key window // this CAN (and IS ALLOWED TO) return NULL, just in case we're called with some OS X-provided window as the key window
return NULL; return v;
return (uiWindow *) [v pointerValue];
} }
@end @end