2015-08-15 19:37:02 -05:00
|
|
|
// 15 august 2015
|
|
|
|
#import "uipriv_darwin.h"
|
|
|
|
|
2016-06-16 10:46:58 -05:00
|
|
|
#define defaultStyleMask (NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask)
|
|
|
|
|
2015-08-15 19:37:02 -05:00
|
|
|
struct uiWindow {
|
|
|
|
uiDarwinControl c;
|
2016-05-15 18:04:35 -05:00
|
|
|
NSWindow *window;
|
2015-08-15 19:37:02 -05:00
|
|
|
uiControl *child;
|
|
|
|
int margined;
|
|
|
|
int (*onClosing)(uiWindow *, void *);
|
|
|
|
void *onClosingData;
|
2016-05-11 17:06:29 -05:00
|
|
|
struct singleChildConstraints constraints;
|
2016-06-15 23:58:40 -05:00
|
|
|
void (*onContentSizeChanged)(uiWindow *, void *);
|
|
|
|
void *onContentSizeChangedData;
|
|
|
|
BOOL suppressSizeChanged;
|
2016-06-16 08:29:28 -05:00
|
|
|
int fullscreen;
|
2016-06-16 10:46:58 -05:00
|
|
|
int borderless;
|
2015-08-15 19:37:02 -05:00
|
|
|
};
|
|
|
|
|
2016-10-26 00:15:01 -05:00
|
|
|
@implementation libuiNSWindow
|
|
|
|
|
|
|
|
- (void)libui_doMove:(NSEvent *)initialEvent
|
|
|
|
{
|
2016-11-02 08:29:44 -05:00
|
|
|
doManualMove(self, initialEvent);
|
2016-10-26 00:15:01 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)libui_doResize:(NSEvent *)initialEvent on:(uiWindowResizeEdge)edge
|
|
|
|
{
|
2016-11-01 10:58:01 -05:00
|
|
|
doManualResize(self, initialEvent, edge);
|
2016-10-26 00:15:01 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
2015-08-15 19:37:02 -05:00
|
|
|
@interface windowDelegateClass : NSObject<NSWindowDelegate> {
|
2018-05-03 22:00:50 -05:00
|
|
|
uiprivMap *windows;
|
2015-08-15 19:37:02 -05:00
|
|
|
}
|
|
|
|
- (BOOL)windowShouldClose:(id)sender;
|
2016-06-15 23:58:40 -05:00
|
|
|
- (void)windowDidResize:(NSNotification *)note;
|
2016-06-16 08:29:28 -05:00
|
|
|
- (void)windowDidEnterFullScreen:(NSNotification *)note;
|
|
|
|
- (void)windowDidExitFullScreen:(NSNotification *)note;
|
2015-08-15 19:37:02 -05:00
|
|
|
- (void)registerWindow:(uiWindow *)w;
|
|
|
|
- (void)unregisterWindow:(uiWindow *)w;
|
|
|
|
- (uiWindow *)lookupWindow:(NSWindow *)w;
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation windowDelegateClass
|
|
|
|
|
|
|
|
- (id)init
|
|
|
|
{
|
|
|
|
self = [super init];
|
|
|
|
if (self)
|
2018-05-03 22:00:50 -05:00
|
|
|
self->windows = uiprivNewMap();
|
2015-08-15 19:37:02 -05:00
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)dealloc
|
|
|
|
{
|
2018-05-03 22:00:50 -05:00
|
|
|
uiprivMapDestroy(self->windows);
|
2015-08-15 19:37:02 -05:00
|
|
|
[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;
|
|
|
|
}
|
|
|
|
|
2016-06-15 23:58:40 -05:00
|
|
|
- (void)windowDidResize:(NSNotification *)note
|
|
|
|
{
|
|
|
|
uiWindow *w;
|
|
|
|
|
|
|
|
w = [self lookupWindow:((NSWindow *) [note object])];
|
|
|
|
if (!w->suppressSizeChanged)
|
|
|
|
(*(w->onContentSizeChanged))(w, w->onContentSizeChangedData);
|
|
|
|
}
|
|
|
|
|
2016-06-16 08:29:28 -05:00
|
|
|
- (void)windowDidEnterFullScreen:(NSNotification *)note
|
|
|
|
{
|
|
|
|
uiWindow *w;
|
|
|
|
|
|
|
|
w = [self lookupWindow:((NSWindow *) [note object])];
|
|
|
|
if (!w->suppressSizeChanged)
|
|
|
|
w->fullscreen = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)windowDidExitFullScreen:(NSNotification *)note
|
|
|
|
{
|
|
|
|
uiWindow *w;
|
|
|
|
|
|
|
|
w = [self lookupWindow:((NSWindow *) [note object])];
|
|
|
|
if (!w->suppressSizeChanged)
|
|
|
|
w->fullscreen = 0;
|
|
|
|
}
|
|
|
|
|
2015-08-15 19:37:02 -05:00
|
|
|
- (void)registerWindow:(uiWindow *)w
|
|
|
|
{
|
2018-05-03 22:00:50 -05:00
|
|
|
uiprivMapSet(self->windows, w->window, w);
|
2015-08-15 19:37:02 -05:00
|
|
|
[w->window setDelegate:self];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)unregisterWindow:(uiWindow *)w
|
|
|
|
{
|
|
|
|
[w->window setDelegate:nil];
|
2018-05-03 22:00:50 -05:00
|
|
|
uiprivMapDelete(self->windows, w->window);
|
2015-08-15 19:37:02 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
- (uiWindow *)lookupWindow:(NSWindow *)w
|
|
|
|
{
|
2016-01-07 13:41:20 -06:00
|
|
|
uiWindow *v;
|
2015-08-15 19:37:02 -05:00
|
|
|
|
2018-05-03 22:00:50 -05:00
|
|
|
v = uiWindow(uiprivMapGet(self->windows, w));
|
2016-01-07 13:41:20 -06:00
|
|
|
// 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 v;
|
2015-08-15 19:37:02 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
static windowDelegateClass *windowDelegate = nil;
|
|
|
|
|
2016-05-11 17:06:29 -05:00
|
|
|
static void removeConstraints(uiWindow *w)
|
|
|
|
{
|
|
|
|
NSView *cv;
|
|
|
|
|
|
|
|
cv = [w->window contentView];
|
|
|
|
singleChildConstraintsRemove(&(w->constraints), cv);
|
|
|
|
}
|
|
|
|
|
2016-04-25 11:28:36 -05:00
|
|
|
static void uiWindowDestroy(uiControl *c)
|
2015-08-15 19:37:02 -05:00
|
|
|
{
|
2016-04-25 11:28:36 -05:00
|
|
|
uiWindow *w = uiWindow(c);
|
2015-08-15 19:37:02 -05:00
|
|
|
|
|
|
|
// hide the window
|
|
|
|
[w->window orderOut:w->window];
|
2016-05-11 17:06:29 -05:00
|
|
|
removeConstraints(w);
|
2015-08-15 19:37:02 -05:00
|
|
|
if (w->child != NULL) {
|
|
|
|
uiControlSetParent(w->child, NULL);
|
2016-05-11 23:43:52 -05:00
|
|
|
uiDarwinControlSetSuperview(uiDarwinControl(w->child), nil);
|
2015-08-15 19:37:02 -05:00
|
|
|
uiControlDestroy(w->child);
|
|
|
|
}
|
|
|
|
[windowDelegate unregisterWindow:w];
|
2016-04-25 11:35:01 -05:00
|
|
|
[w->window release];
|
|
|
|
uiFreeControl(uiControl(w));
|
2015-08-15 19:37:02 -05:00
|
|
|
}
|
|
|
|
|
2016-04-25 11:28:36 -05:00
|
|
|
uiDarwinControlDefaultHandle(uiWindow, window)
|
2016-05-22 19:02:47 -05:00
|
|
|
|
|
|
|
uiControl *uiWindowParent(uiControl *c)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void uiWindowSetParent(uiControl *c, uiControl *parent)
|
|
|
|
{
|
|
|
|
uiUserBugCannotSetParentOnToplevel("uiWindow");
|
|
|
|
}
|
2016-04-25 11:28:36 -05:00
|
|
|
|
|
|
|
static int uiWindowToplevel(uiControl *c)
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int uiWindowVisible(uiControl *c)
|
|
|
|
{
|
|
|
|
uiWindow *w = uiWindow(c);
|
|
|
|
|
|
|
|
return [w->window isVisible];
|
|
|
|
}
|
|
|
|
|
|
|
|
static void uiWindowShow(uiControl *c)
|
2015-08-15 19:37:02 -05:00
|
|
|
{
|
|
|
|
uiWindow *w = (uiWindow *) c;
|
|
|
|
|
|
|
|
[w->window makeKeyAndOrderFront:w->window];
|
|
|
|
}
|
|
|
|
|
2016-04-25 11:28:36 -05:00
|
|
|
static void uiWindowHide(uiControl *c)
|
2015-08-15 19:37:02 -05:00
|
|
|
{
|
|
|
|
uiWindow *w = (uiWindow *) c;
|
|
|
|
|
|
|
|
[w->window orderOut:w->window];
|
|
|
|
}
|
|
|
|
|
2016-04-25 11:28:36 -05:00
|
|
|
uiDarwinControlDefaultEnabled(uiWindow, window)
|
|
|
|
uiDarwinControlDefaultEnable(uiWindow, window)
|
|
|
|
uiDarwinControlDefaultDisable(uiWindow, window)
|
|
|
|
|
2016-04-25 16:52:16 -05:00
|
|
|
static void uiWindowSyncEnableState(uiDarwinControl *c, int enabled)
|
2015-08-21 00:09:07 -05:00
|
|
|
{
|
|
|
|
uiWindow *w = uiWindow(c);
|
|
|
|
|
2016-04-25 17:07:29 -05:00
|
|
|
if (uiDarwinShouldStopSyncEnableState(uiDarwinControl(w), enabled))
|
|
|
|
return;
|
2015-08-21 00:09:07 -05:00
|
|
|
if (w->child != NULL)
|
2016-04-25 16:52:16 -05:00
|
|
|
uiDarwinControlSyncEnableState(uiDarwinControl(w->child), enabled);
|
2016-04-25 11:28:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static void uiWindowSetSuperview(uiDarwinControl *c, NSView *superview)
|
|
|
|
{
|
|
|
|
// TODO
|
2015-08-21 00:09:07 -05:00
|
|
|
}
|
2015-08-15 19:37:02 -05:00
|
|
|
|
2016-04-25 12:38:17 -05:00
|
|
|
static void windowRelayout(uiWindow *w)
|
2015-08-18 19:15:09 -05:00
|
|
|
{
|
|
|
|
NSView *childView;
|
2015-08-22 20:29:22 -05:00
|
|
|
NSView *contentView;
|
2015-08-18 19:15:09 -05:00
|
|
|
|
2016-05-11 17:06:29 -05:00
|
|
|
removeConstraints(w);
|
2015-08-18 19:15:09 -05:00
|
|
|
if (w->child == NULL)
|
|
|
|
return;
|
|
|
|
childView = (NSView *) uiControlHandle(w->child);
|
2015-08-22 20:29:22 -05:00
|
|
|
contentView = [w->window contentView];
|
2016-05-11 17:06:29 -05:00
|
|
|
singleChildConstraintsEstablish(&(w->constraints),
|
|
|
|
contentView, childView,
|
|
|
|
uiDarwinControlHugsTrailingEdge(uiDarwinControl(w->child)),
|
|
|
|
uiDarwinControlHugsBottom(uiDarwinControl(w->child)),
|
|
|
|
w->margined,
|
|
|
|
@"uiWindow");
|
|
|
|
}
|
|
|
|
|
|
|
|
uiDarwinControlDefaultHugsTrailingEdge(uiWindow, window)
|
|
|
|
uiDarwinControlDefaultHugsBottom(uiWindow, window)
|
|
|
|
|
|
|
|
static void uiWindowChildEdgeHuggingChanged(uiDarwinControl *c)
|
|
|
|
{
|
|
|
|
uiWindow *w = uiWindow(c);
|
|
|
|
|
|
|
|
windowRelayout(w);
|
2015-08-18 19:15:09 -05:00
|
|
|
}
|
|
|
|
|
2016-05-12 11:26:43 -05:00
|
|
|
// TODO
|
|
|
|
uiDarwinControlDefaultHuggingPriority(uiWindow, window)
|
|
|
|
uiDarwinControlDefaultSetHuggingPriority(uiWindow, window)
|
|
|
|
// end TODO
|
|
|
|
|
2016-06-14 09:37:19 -05:00
|
|
|
static void uiWindowChildVisibilityChanged(uiDarwinControl *c)
|
|
|
|
{
|
|
|
|
uiWindow *w = uiWindow(c);
|
|
|
|
|
|
|
|
windowRelayout(w);
|
|
|
|
}
|
|
|
|
|
2015-08-15 19:37:02 -05:00
|
|
|
char *uiWindowTitle(uiWindow *w)
|
|
|
|
{
|
|
|
|
return uiDarwinNSStringToText([w->window title]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void uiWindowSetTitle(uiWindow *w, const char *title)
|
|
|
|
{
|
2018-05-03 21:38:21 -05:00
|
|
|
[w->window setTitle:uiprivToNSString(title)];
|
2015-08-15 19:37:02 -05:00
|
|
|
}
|
|
|
|
|
2016-06-15 23:58:40 -05:00
|
|
|
void uiWindowContentSize(uiWindow *w, int *width, int *height)
|
|
|
|
{
|
|
|
|
NSRect r;
|
|
|
|
|
|
|
|
r = [w->window contentRectForFrameRect:[w->window frame]];
|
|
|
|
*width = r.size.width;
|
|
|
|
*height = r.size.height;
|
|
|
|
}
|
|
|
|
|
|
|
|
void uiWindowSetContentSize(uiWindow *w, int width, int height)
|
|
|
|
{
|
|
|
|
w->suppressSizeChanged = YES;
|
|
|
|
[w->window setContentSize:NSMakeSize(width, height)];
|
|
|
|
w->suppressSizeChanged = NO;
|
|
|
|
}
|
|
|
|
|
2016-06-16 08:29:28 -05:00
|
|
|
int uiWindowFullscreen(uiWindow *w)
|
|
|
|
{
|
|
|
|
return w->fullscreen;
|
|
|
|
}
|
|
|
|
|
|
|
|
void uiWindowSetFullscreen(uiWindow *w, int fullscreen)
|
|
|
|
{
|
|
|
|
if (w->fullscreen && fullscreen)
|
|
|
|
return;
|
|
|
|
if (!w->fullscreen && !fullscreen)
|
|
|
|
return;
|
|
|
|
w->fullscreen = fullscreen;
|
2016-06-16 10:46:58 -05:00
|
|
|
if (w->fullscreen && w->borderless) // borderless doesn't play nice with fullscreen; don't toggle while borderless
|
|
|
|
return;
|
2016-06-16 08:29:28 -05:00
|
|
|
w->suppressSizeChanged = YES;
|
|
|
|
[w->window toggleFullScreen:w->window];
|
|
|
|
w->suppressSizeChanged = NO;
|
2016-06-16 10:46:58 -05:00
|
|
|
if (!w->fullscreen && w->borderless) // borderless doesn't play nice with fullscreen; restore borderless after removing
|
|
|
|
[w->window setStyleMask:NSBorderlessWindowMask];
|
2016-06-16 08:29:28 -05:00
|
|
|
}
|
|
|
|
|
2016-06-15 23:58:40 -05:00
|
|
|
void uiWindowOnContentSizeChanged(uiWindow *w, void (*f)(uiWindow *, void *), void *data)
|
|
|
|
{
|
|
|
|
w->onContentSizeChanged = f;
|
|
|
|
w->onContentSizeChangedData = data;
|
|
|
|
}
|
|
|
|
|
2015-08-15 19:37:02 -05:00
|
|
|
void uiWindowOnClosing(uiWindow *w, int (*f)(uiWindow *, void *), void *data)
|
|
|
|
{
|
|
|
|
w->onClosing = f;
|
|
|
|
w->onClosingData = data;
|
|
|
|
}
|
|
|
|
|
2016-06-16 10:46:58 -05:00
|
|
|
int uiWindowBorderless(uiWindow *w)
|
|
|
|
{
|
|
|
|
return w->borderless;
|
|
|
|
}
|
|
|
|
|
|
|
|
void uiWindowSetBorderless(uiWindow *w, int borderless)
|
|
|
|
{
|
|
|
|
w->borderless = borderless;
|
|
|
|
if (w->borderless) {
|
|
|
|
// borderless doesn't play nice with fullscreen; wait for later
|
|
|
|
if (!w->fullscreen)
|
|
|
|
[w->window setStyleMask:NSBorderlessWindowMask];
|
|
|
|
} else {
|
|
|
|
[w->window setStyleMask:defaultStyleMask];
|
|
|
|
// borderless doesn't play nice with fullscreen; restore state
|
|
|
|
if (w->fullscreen) {
|
|
|
|
w->suppressSizeChanged = YES;
|
|
|
|
[w->window toggleFullScreen:w->window];
|
|
|
|
w->suppressSizeChanged = NO;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-15 19:37:02 -05:00
|
|
|
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);
|
2016-04-25 12:38:17 -05:00
|
|
|
uiDarwinControlSetSuperview(uiDarwinControl(w->child), [w->window contentView]);
|
2016-04-25 16:52:16 -05:00
|
|
|
uiDarwinControlSyncEnableState(uiDarwinControl(w->child), uiControlEnabledToUser(uiControl(w)));
|
2015-08-15 19:37:02 -05:00
|
|
|
}
|
2016-04-25 11:28:36 -05:00
|
|
|
windowRelayout(w);
|
2015-08-15 19:37:02 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
int uiWindowMargined(uiWindow *w)
|
|
|
|
{
|
|
|
|
return w->margined;
|
|
|
|
}
|
|
|
|
|
|
|
|
void uiWindowSetMargined(uiWindow *w, int margined)
|
|
|
|
{
|
|
|
|
w->margined = margined;
|
2016-05-11 17:06:29 -05:00
|
|
|
singleChildConstraintsSetMargined(&(w->constraints), w->margined);
|
2015-08-15 19:37:02 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static int defaultOnClosing(uiWindow *w, void *data)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-06-15 23:58:40 -05:00
|
|
|
static void defaultOnPositionContentSizeChanged(uiWindow *w, void *data)
|
2016-06-15 13:57:52 -05:00
|
|
|
{
|
|
|
|
// do nothing
|
|
|
|
}
|
|
|
|
|
2015-08-15 19:37:02 -05:00
|
|
|
uiWindow *uiNewWindow(const char *title, int width, int height, int hasMenubar)
|
|
|
|
{
|
|
|
|
uiWindow *w;
|
|
|
|
|
|
|
|
finalizeMenus();
|
|
|
|
|
2016-04-25 11:28:36 -05:00
|
|
|
uiDarwinNewControl(uiWindow, w);
|
2015-08-15 19:37:02 -05:00
|
|
|
|
2016-10-26 00:15:01 -05:00
|
|
|
w->window = [[libuiNSWindow alloc] initWithContentRect:NSMakeRect(0, 0, (CGFloat) width, (CGFloat) height)
|
2016-06-16 10:46:58 -05:00
|
|
|
styleMask:defaultStyleMask
|
2015-08-15 19:37:02 -05:00
|
|
|
backing:NSBackingStoreBuffered
|
|
|
|
defer:YES];
|
2018-05-03 21:38:21 -05:00
|
|
|
[w->window setTitle:uiprivToNSString(title)];
|
2015-08-15 19:37:02 -05:00
|
|
|
|
2016-05-22 11:15:50 -05:00
|
|
|
// do NOT release when closed
|
|
|
|
// we manually do this in uiWindowDestroy() above
|
|
|
|
[w->window setReleasedWhenClosed:NO];
|
2015-08-15 19:37:02 -05:00
|
|
|
|
2015-08-17 11:57:45 -05:00
|
|
|
if (windowDelegate == nil) {
|
2016-05-24 22:17:08 -05:00
|
|
|
windowDelegate = [[windowDelegateClass new] autorelease];
|
2015-08-17 11:57:45 -05:00
|
|
|
[delegates addObject:windowDelegate];
|
|
|
|
}
|
2015-08-15 19:37:02 -05:00
|
|
|
[windowDelegate registerWindow:w];
|
|
|
|
uiWindowOnClosing(w, defaultOnClosing, NULL);
|
2016-06-15 23:58:40 -05:00
|
|
|
uiWindowOnContentSizeChanged(w, defaultOnPositionContentSizeChanged, NULL);
|
2015-08-15 19:37:02 -05:00
|
|
|
|
|
|
|
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];
|
|
|
|
}
|