cocoa: Implement Cocoa popup windows
diff --git a/src/video/cocoa/SDL_cocoawindow.m b/src/video/cocoa/SDL_cocoawindow.m index b14cd3b..0f159a6 100644 --- a/src/video/cocoa/SDL_cocoawindow.m +++ b/src/video/cocoa/SDL_cocoawindow.m
@@ -119,7 +119,12 @@ - (BOOL)canBecomeMainWindow { - return YES; + SDL_Window *window = [self findSDLWindow]; + if (window && !SDL_WINDOW_IS_POPUP(window)) { + return YES; + } else { + return NO; + } } - (void)sendEvent:(NSEvent *)event @@ -308,13 +313,17 @@ minimize the window, whether there's a title bar or not */ NSUInteger style = NSWindowStyleMaskMiniaturizable; - if (window->flags & SDL_WINDOW_BORDERLESS) { - style |= NSWindowStyleMaskBorderless; + if (!SDL_WINDOW_IS_POPUP(window)) { + if (window->flags & SDL_WINDOW_BORDERLESS) { + style |= NSWindowStyleMaskBorderless; + } else { + style |= (NSWindowStyleMaskTitled | NSWindowStyleMaskClosable); + } + if (window->flags & SDL_WINDOW_RESIZABLE) { + style |= NSWindowStyleMaskResizable; + } } else { - style |= (NSWindowStyleMaskTitled | NSWindowStyleMaskClosable); - } - if (window->flags & SDL_WINDOW_RESIZABLE) { - style |= NSWindowStyleMaskResizable; + style |= NSWindowStyleMaskBorderless; } return style; } @@ -461,6 +470,26 @@ } } +static void Cocoa_RestoreChildParameters(SDL_Window *window) +{ + if (SDL_WINDOW_IS_POPUP(window)) { + SDL_CocoaWindowData *windowData, *parentData; + SDL_Window *w; + + windowData = (__bridge SDL_CocoaWindowData *)window->driverdata; + parentData = (__bridge SDL_CocoaWindowData *)window->parent->driverdata; + [parentData.nswindow addChildWindow:windowData.nswindow ordered:NSWindowAbove]; + + if (window->flags & SDL_WINDOW_TOOLTIP) { + [windowData.nswindow setIgnoresMouseEvents:YES]; + } + + for (w = window->first_child; w != NULL; w = w->next_sibling) { + Cocoa_RestoreChildParameters(w); + } + } +} + @implementation Cocoa_WindowListener - (void)listen:(SDL_CocoaWindowData *)data @@ -738,6 +767,7 @@ - (void)windowDidMove:(NSNotification *)aNotification { int x, y; + SDL_Window *w; SDL_Window *window = _data.window; NSWindow *nswindow = _data.nswindow; BOOL fullscreen = (window->flags & SDL_WINDOW_FULLSCREEN) ? YES : NO; @@ -766,6 +796,12 @@ x = (int)rect.origin.x; y = (int)rect.origin.y; + + /* Get the parent-relative coordinates for child windows. */ + for (w = window->parent; w != NULL; w = w->parent) { + x -= w->x; + y -= w->y; + } ScheduleContextUpdates(_data); @@ -1700,6 +1736,8 @@ { @autoreleasepool { SDL_CocoaVideoData *videodata = (__bridge SDL_CocoaVideoData *)_this->driverdata; + SDL_CocoaWindowData *windata; + SDL_Window *w; NSWindow *nswindow; SDL_VideoDisplay *display = SDL_GetVideoDisplayForWindow(window); NSRect rect; @@ -1717,6 +1755,13 @@ rect.size.width = window->w; rect.size.height = window->h; fullscreen = (window->flags & SDL_WINDOW_FULLSCREEN) ? YES : NO; + + if (window->parent) { + w = window->parent; + rect.origin.x += w->x; + rect.origin.y += w->y; + } + ConvertNSRect([screens objectAtIndex:0], fullscreen, &rect); style = GetWindowStyle(window); @@ -1740,6 +1785,18 @@ @catch (NSException *e) { return SDL_SetError("%s", [[e reason] UTF8String]); } + + if (SDL_WINDOW_IS_POPUP(window)) { + windata = (__bridge SDL_CocoaWindowData *)window->parent->driverdata; + + [windata.nswindow addChildWindow:nswindow ordered:NSWindowAbove]; + + if (window->flags & SDL_WINDOW_TOOLTIP) { + [nswindow setIgnoresMouseEvents:YES]; + } else { + [nswindow makeKeyWindow]; + } + } [nswindow setColorSpace:[NSColorSpace sRGBColorSpace]]; @@ -1893,7 +1950,9 @@ { @autoreleasepool { SDL_CocoaWindowData *windata = (__bridge SDL_CocoaWindowData *)window->driverdata; + NSRect bounds; NSWindow *nswindow = windata.nswindow; + SDL_Window *w; NSRect rect; BOOL fullscreen; Uint64 moveHack; @@ -1903,6 +1962,26 @@ rect.size.width = window->w; rect.size.height = window->h; fullscreen = (window->flags & SDL_WINDOW_FULLSCREEN) ? YES : NO; + + /* Position and constrain the popup */ + if (SDL_WINDOW_IS_POPUP(window)) { + for (w = window->parent; w != NULL; w = w->parent) { + rect.origin.x += w->x; + rect.origin.y += w->y; + } + + bounds = [[nswindow screen] frame]; + + if (rect.origin.x + rect.size.width > bounds.origin.x + bounds.size.width) { + rect.origin.x -= (rect.origin.x + rect.size.width) - (bounds.origin.x + bounds.size.width); + } + if (rect.origin.y + rect.size.height > bounds.origin.y + bounds.size.height) { + rect.origin.y -= (rect.origin.y + rect.size.height) - (bounds.origin.y + bounds.size.height); + } + rect.origin.x = SDL_max(rect.origin.x, bounds.origin.x); + rect.origin.y = SDL_max(rect.origin.y, bounds.origin.y); + } + ConvertNSRect([nswindow screen], fullscreen, &rect); moveHack = s_moveHack; @@ -1997,6 +2076,28 @@ [nswindow makeKeyAndOrderFront:nil]; [windowData.listener resumeVisibleObservation]; } + + if (SDL_WINDOW_IS_POPUP(window)) { + SDL_Window *w; + + windowData = ((__bridge SDL_CocoaWindowData *)window->parent->driverdata); + [windowData.nswindow addChildWindow:nswindow ordered:NSWindowAbove]; + + if (window->flags & SDL_WINDOW_TOOLTIP) { + [nswindow setIgnoresMouseEvents:YES]; + + for (w = window->parent; w->parent != NULL; w = w->parent) { + if (!(w->flags & SDL_WINDOW_TOOLTIP)) { + break; + } + } + + windowData = ((__bridge SDL_CocoaWindowData *)w->driverdata); + [windowData.nswindow makeKeyWindow]; + } else { + [nswindow makeKeyWindow]; + } + } } }