diff --git a/redo/reredo/darwin/window.m b/redo/reredo/darwin/window.m new file mode 100644 index 00000000..acaca20e --- /dev/null +++ b/redo/reredo/darwin/window.m @@ -0,0 +1,215 @@ +// 15 august 2015 +#import "uipriv_darwin.h" + +struct uiWindow { + uiDarwinControl c; + NSWindow *window; + uiControl *child; + int margined; + int (*onClosing)(uiWindow *, void *); + void *onClosingData; +}; + +@interface windowDelegateClass : NSObject { + NSMutableDictionary *windows; +} +- (BOOL)windowShouldClose:(id)sender; +- (void)registerWindow:(uiWindow *)w; +- (void)unregisterWindow:(uiWindow *)w; +- (uiWindow *)lookupWindow:(NSWindow *)w; +@end + +@implementation windowDelegateClass + +- (id)init +{ + self = [super init]; + if (self) + self->windows = [NSMutableDictionary new]; + return self; +} + +// TODO have this called +- (void)dealloc +{ + if ([self->windows count] != 0) + complain("attempt to destroy shared window delegate but windows are still registered to it"); + [self->windows release]; + [super dealloc]; +} + +- (BOOL)windowShouldClose:(id)sender +{ + uiWindow *w; + + w = [self lookupWindow:((NSWindow *) sender)]; + // w should not be NULL; we are only the delegate of registered windows + if ((*(w->onClosing))(w, w->onClosingData)) + uiControlDestroy(uiControl(w)); + return NO; +} + +- (void)registerWindow:(uiWindow *)w +{ + [self->windows setObject:[NSValue valueWithPointer:w] + forKey:w->window]; + [w->window setDelegate:self]; +} + +- (void)unregisterWindow:(uiWindow *)w +{ + [w->window setDelegate:nil]; + [self->windows removeObjectForKey:w->window]; +} + +- (uiWindow *)lookupWindow:(NSWindow *)w +{ + NSValue *v; + + v = (NSValue *) [self->windows objectForKey:w]; + if (v == nil) // just in case we're called with some OS X-provided window as the key window + return NULL; + return (uiWindow *) [v pointerValue]; +} + +@end + +static windowDelegateClass *windowDelegate = nil; + +static void onDestroy(uiWindow *); + +uiDarwinDefineControl( + uiWindow, // type name + uiWindowType, // type function + window, // handle + onDestroy(this); // on destroy +) + +static void onDestroy(uiWindow *w) +{ + NSView *childView; + + // hide the window + [w->window orderOut:w->window]; + if (w->child != NULL) { + childView = (NSView *) uiControlHandle(w->child); + [childView removeFromSuperview]; + uiControlSetParent(w->child, NULL); + uiControlDestroy(w->child); + } + [windowDelegate unregisterWindow:w]; +} + +// TODO forbid setting a parent + +static void windowCommitShow(uiControl *c) +{ + uiWindow *w = (uiWindow *) c; + + [w->window makeKeyAndOrderFront:w->window]; +} + +static void windowCommitHide(uiControl *c) +{ + uiWindow *w = (uiWindow *) c; + + [w->window orderOut:w->window]; +} + +// TODO container update state + +char *uiWindowTitle(uiWindow *w) +{ + return uiDarwinNSStringToText([w->window title]); +} + +void uiWindowSetTitle(uiWindow *w, const char *title) +{ + [w->window setTitle:toNSString(title)]; +} + +void uiWindowOnClosing(uiWindow *w, int (*f)(uiWindow *, void *), void *data) +{ + w->onClosing = f; + w->onClosingData = data; +} + +void uiWindowSetChild(uiWindow *w, uiControl *child) +{ + NSView *childView; + + if (w->child != NULL) { + childView = (NSView *) uiControlHandle(w->child); + [childView removeFromSuperview]; + uiControlSetParent(w->child, NULL); + } + w->child = child; + if (w->child != NULL) { + uiControlSetParent(w->child, uiControl(w)); + childView = (NSView *) uiControlHandle(w->child); + [[w->window contentView] addSubview:childView]; + layoutSingleView([w->window contentView], childView, w->margined); + } +} + +int uiWindowMargined(uiWindow *w) +{ + return w->margined; +} + +void uiWindowSetMargined(uiWindow *w, int margined) +{ + NSView *childView; + + w->margined = margined; + if (w->child != NULL) { + childView = (NSView *) uiControlHandle(w->child); + [[w->window contentView] addSubview:childView]; + layoutSingleView([w->window contentView], childView, w->margined); + } +} + +static int defaultOnClosing(uiWindow *w, void *data) +{ + return 0; +} + +uiWindow *uiNewWindow(const char *title, int width, int height, int hasMenubar) +{ + uiWindow *w; + + finalizeMenus(); + + w = (uiWindow *) uiNewControl(uiWindowType()); + + w->window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, (CGFloat) width, (CGFloat) height) + styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask) + backing:NSBackingStoreBuffered + defer:YES]; + [w->window setTitle:toNSString(title)]; + + // explicitly release when closed + // the only thing that closes the window is us anyway + [w->window setReleasedWhenClosed:YES]; + + if (windowDelegate == nil) + windowDelegate = [windowDelegateClass new]; + [windowDelegate registerWindow:w]; + uiWindowOnClosing(w, defaultOnClosing, NULL); + + uiDarwinFinishNewControl(w, uiWindow); + uiControl(w)->CommitShow = windowCommitShow; + uiControl(w)->CommitHide = windowCommitHide; + + return w; +} + +// utility function for menus +uiWindow *windowFromNSWindow(NSWindow *w) +{ + if (w == nil) + return NULL; + if (windowDelegate == nil) // no windows were created yet; we're called with some OS X-provided window + return NULL; + return [windowDelegate lookupWindow:w]; +}