| | |
| | | /* |
| | | Simple DirectMedia Layer |
| | | Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> |
| | | Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org> |
| | | |
| | | This software is provided 'as-is', without any express or implied |
| | | warranty. In no event will the authors be held liable for any damages |
| | |
| | | |
| | | #define FULLSCREEN_MASK (SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_FULLSCREEN) |
| | | |
| | | #ifndef MAC_OS_X_VERSION_10_12 |
| | | #define NSEventModifierFlagCapsLock NSAlphaShiftKeyMask |
| | | #endif |
| | | |
| | | @interface SDLWindow : NSWindow <NSDraggingDestination> |
| | | /* These are needed for borderless/fullscreen windows */ |
| | |
| | | static void |
| | | ScheduleContextUpdates(SDL_WindowData *data) |
| | | { |
| | | if (!data || !data->nscontexts) { |
| | | return; |
| | | } |
| | | |
| | | /* We still support OpenGL as long as Apple offers it, deprecated or not, so disable deprecation warnings about it. */ |
| | | #ifdef __clang__ |
| | | #pragma clang diagnostic push |
| | | #pragma clang diagnostic ignored "-Wdeprecated-declarations" |
| | | #endif |
| | | |
| | | NSOpenGLContext *currentContext = [NSOpenGLContext currentContext]; |
| | | NSMutableArray *contexts = data->nscontexts; |
| | | @synchronized (contexts) { |
| | |
| | | } |
| | | } |
| | | } |
| | | |
| | | #ifdef __clang__ |
| | | #pragma clang diagnostic pop |
| | | #endif |
| | | } |
| | | |
| | | /* !!! FIXME: this should use a hint callback. */ |
| | |
| | | } |
| | | |
| | | static NSUInteger |
| | | GetWindowWindowedStyle(SDL_Window * window) |
| | | { |
| | | NSUInteger style = 0; |
| | | |
| | | if (window->flags & SDL_WINDOW_BORDERLESS) { |
| | | style = NSWindowStyleMaskBorderless; |
| | | } else { |
| | | style = (NSWindowStyleMaskTitled|NSWindowStyleMaskClosable|NSWindowStyleMaskMiniaturizable); |
| | | } |
| | | if (window->flags & SDL_WINDOW_RESIZABLE) { |
| | | style |= NSWindowStyleMaskResizable; |
| | | } |
| | | return style; |
| | | } |
| | | |
| | | static NSUInteger |
| | | GetWindowStyle(SDL_Window * window) |
| | | { |
| | | NSUInteger style = 0; |
| | |
| | | if (window->flags & SDL_WINDOW_FULLSCREEN) { |
| | | style = NSWindowStyleMaskBorderless; |
| | | } else { |
| | | if (window->flags & SDL_WINDOW_BORDERLESS) { |
| | | style = NSWindowStyleMaskBorderless; |
| | | } else { |
| | | style = (NSWindowStyleMaskTitled|NSWindowStyleMaskClosable|NSWindowStyleMaskMiniaturizable); |
| | | } |
| | | if (window->flags & SDL_WINDOW_RESIZABLE) { |
| | | style |= NSWindowStyleMaskResizable; |
| | | } |
| | | style = GetWindowWindowedStyle(window); |
| | | } |
| | | return style; |
| | | } |
| | |
| | | y = (int)(window->h - point.y); |
| | | |
| | | if (x >= 0 && x < window->w && y >= 0 && y < window->h) { |
| | | SDL_SendMouseMotion(window, 0, 0, x, y); |
| | | SDL_SendMouseMotion(window, mouse->mouseID, 0, x, y); |
| | | } |
| | | } |
| | | |
| | |
| | | isFullscreenSpace = NO; |
| | | inFullscreenTransition = YES; |
| | | |
| | | /* As of OS X 10.11, the window seems to need to be resizable when exiting |
| | | /* As of macOS 10.11, the window seems to need to be resizable when exiting |
| | | a Space, in order for it to resize back to its windowed-mode size. |
| | | As of macOS 10.15, the window decorations can go missing sometimes after |
| | | certain fullscreen-desktop->exlusive-fullscreen->windowed mode flows |
| | | sometimes. Making sure the style mask always uses the windowed mode style |
| | | when returning to windowed mode from a space (instead of using a pending |
| | | fullscreen mode style mask) seems to work around that issue. |
| | | */ |
| | | SetWindowStyle(window, GetWindowStyle(window) | NSWindowStyleMaskResizable); |
| | | SetWindowStyle(window, GetWindowWindowedStyle(window) | NSWindowStyleMaskResizable); |
| | | } |
| | | |
| | | - (void)windowDidFailToExitFullScreen:(NSNotification *)aNotification |
| | |
| | | { |
| | | SDL_Window *window = _data->window; |
| | | NSWindow *nswindow = _data->nswindow; |
| | | NSButton *button = nil; |
| | | |
| | | inFullscreenTransition = NO; |
| | | |
| | | SetWindowStyle(window, GetWindowStyle(window)); |
| | | /* As of macOS 10.15, the window decorations can go missing sometimes after |
| | | certain fullscreen-desktop->exlusive-fullscreen->windowed mode flows |
| | | sometimes. Making sure the style mask always uses the windowed mode style |
| | | when returning to windowed mode from a space (instead of using a pending |
| | | fullscreen mode style mask) seems to work around that issue. |
| | | */ |
| | | SetWindowStyle(window, GetWindowWindowedStyle(window)); |
| | | |
| | | [nswindow setLevel:kCGNormalWindowLevel]; |
| | | if (window->flags & SDL_WINDOW_ALWAYS_ON_TOP) { |
| | | [nswindow setLevel:NSFloatingWindowLevel]; |
| | | } else { |
| | | [nswindow setLevel:kCGNormalWindowLevel]; |
| | | } |
| | | |
| | | if (pendingWindowOperation == PENDING_OPERATION_ENTER_FULLSCREEN) { |
| | | pendingWindowOperation = PENDING_OPERATION_NONE; |
| | |
| | | Cocoa_ShowWindow(SDL_GetVideoDevice(), window); |
| | | } |
| | | } |
| | | |
| | | /* There's some state that isn't quite back to normal when |
| | | windowDidExitFullScreen triggers. For example, the minimize button on |
| | | the titlebar doesn't actually enable for another 200 milliseconds or |
| | | so on this MacBook. Camp here and wait for that to happen before |
| | | going on, in case we're exiting fullscreen to minimize, which need |
| | | that window state to be normal before it will work. */ |
| | | button = [nswindow standardWindowButton:NSWindowMiniaturizeButton]; |
| | | if (button) { |
| | | int iterations = 0; |
| | | while (![button isEnabled] && (iterations < 100)) { |
| | | SDL_Delay(10); |
| | | SDL_PumpEvents(); |
| | | iterations++; |
| | | } |
| | | } |
| | | } |
| | | |
| | | -(NSApplicationPresentationOptions)window:(NSWindow *)window willUseFullScreenPresentationOptions:(NSApplicationPresentationOptions)proposedOptions |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | /* We'll respond to key events by doing nothing so we don't beep. |
| | | /* We'll respond to key events by mostly doing nothing so we don't beep. |
| | | * We could handle key messages here, but we lose some in the NSApp dispatch, |
| | | * where they get converted to action messages, etc. |
| | | */ |
| | | - (void)flagsChanged:(NSEvent *)theEvent |
| | | { |
| | | /*Cocoa_HandleKeyEvent(SDL_GetVideoDevice(), theEvent);*/ |
| | | |
| | | /* Catch capslock in here as a special case: |
| | | https://developer.apple.com/library/archive/qa/qa1519/_index.html |
| | | Note that technote's check of keyCode doesn't work. At least on the |
| | | 10.15 beta, capslock comes through here as keycode 255, but it's safe |
| | | to send duplicate key events; SDL filters them out quickly in |
| | | SDL_SendKeyboardKey(). */ |
| | | |
| | | /* Also note that SDL_SendKeyboardKey expects all capslock events to be |
| | | keypresses; it won't toggle the mod state if you send a keyrelease. */ |
| | | const SDL_bool osenabled = ([theEvent modifierFlags] & NSEventModifierFlagCapsLock) ? SDL_TRUE : SDL_FALSE; |
| | | const SDL_bool sdlenabled = (SDL_GetModState() & KMOD_CAPS) ? SDL_TRUE : SDL_FALSE; |
| | | if (!osenabled && sdlenabled) { |
| | | SDL_ToggleModState(KMOD_CAPS, SDL_FALSE); |
| | | SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_CAPSLOCK); |
| | | } else if (osenabled && !sdlenabled) { |
| | | SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_CAPSLOCK); |
| | | } |
| | | } |
| | | - (void)keyDown:(NSEvent *)theEvent |
| | | { |
| | |
| | | |
| | | - (void)mouseDown:(NSEvent *)theEvent |
| | | { |
| | | const SDL_Mouse *mouse = SDL_GetMouse(); |
| | | if (!mouse) { |
| | | return; |
| | | } |
| | | |
| | | const SDL_MouseID mouseID = mouse->mouseID; |
| | | int button; |
| | | int clicks; |
| | | |
| | |
| | | } |
| | | |
| | | clicks = (int) [theEvent clickCount]; |
| | | SDL_SendMouseButtonClicks(_data->window, 0, SDL_PRESSED, button, clicks); |
| | | |
| | | SDL_SendMouseButtonClicks(_data->window, mouseID, SDL_PRESSED, button, clicks); |
| | | } |
| | | |
| | | - (void)rightMouseDown:(NSEvent *)theEvent |
| | |
| | | |
| | | - (void)mouseUp:(NSEvent *)theEvent |
| | | { |
| | | const SDL_Mouse *mouse = SDL_GetMouse(); |
| | | if (!mouse) { |
| | | return; |
| | | } |
| | | |
| | | const SDL_MouseID mouseID = mouse->mouseID; |
| | | int button; |
| | | int clicks; |
| | | |
| | |
| | | } |
| | | |
| | | clicks = (int) [theEvent clickCount]; |
| | | SDL_SendMouseButtonClicks(_data->window, 0, SDL_RELEASED, button, clicks); |
| | | |
| | | SDL_SendMouseButtonClicks(_data->window, mouseID, SDL_RELEASED, button, clicks); |
| | | } |
| | | |
| | | - (void)rightMouseUp:(NSEvent *)theEvent |
| | |
| | | - (void)mouseMoved:(NSEvent *)theEvent |
| | | { |
| | | SDL_Mouse *mouse = SDL_GetMouse(); |
| | | if (!mouse) { |
| | | return; |
| | | } |
| | | |
| | | const SDL_MouseID mouseID = mouse->mouseID; |
| | | SDL_Window *window = _data->window; |
| | | NSPoint point; |
| | | int x, y; |
| | |
| | | #endif |
| | | } |
| | | } |
| | | SDL_SendMouseMotion(window, 0, 0, x, y); |
| | | |
| | | SDL_SendMouseMotion(window, mouseID, 0, x, y); |
| | | } |
| | | |
| | | - (void)mouseDragged:(NSEvent *)theEvent |
| | |
| | | |
| | | - (void)touchesBeganWithEvent:(NSEvent *) theEvent |
| | | { |
| | | /* probably a MacBook trackpad; make this look like a synthesized event. |
| | | This is backwards from reality, but better matches user expectations. */ |
| | | const BOOL istrackpad = ([theEvent subtype] == NSEventSubtypeMouseEvent); |
| | | |
| | | NSSet *touches = [theEvent touchesMatchingPhase:NSTouchPhaseAny inView:nil]; |
| | | const SDL_TouchID touchID = istrackpad ? SDL_MOUSE_TOUCHID : (SDL_TouchID)(intptr_t)[[touches anyObject] device]; |
| | | int existingTouchCount = 0; |
| | | |
| | | for (NSTouch* touch in touches) { |
| | |
| | | } |
| | | } |
| | | if (existingTouchCount == 0) { |
| | | SDL_TouchID touchID = (SDL_TouchID)(intptr_t)[[touches anyObject] device]; |
| | | int numFingers = SDL_GetNumTouchFingers(touchID); |
| | | DLog("Reset Lost Fingers: %d", numFingers); |
| | | for (--numFingers; numFingers >= 0; --numFingers) { |
| | | SDL_Finger* finger = SDL_GetTouchFinger(touchID, numFingers); |
| | | SDL_SendTouch(touchID, finger->id, SDL_FALSE, 0, 0, 0); |
| | | /* trackpad touches have no window. If we really wanted one we could |
| | | * use the window that has mouse or keyboard focus. |
| | | * Sending a null window currently also prevents synthetic mouse |
| | | * events from being generated from touch events. |
| | | */ |
| | | SDL_Window *window = NULL; |
| | | SDL_SendTouch(touchID, finger->id, window, SDL_FALSE, 0, 0, 0); |
| | | } |
| | | } |
| | | |
| | |
| | | { |
| | | NSSet *touches = [theEvent touchesMatchingPhase:phase inView:nil]; |
| | | |
| | | /* probably a MacBook trackpad; make this look like a synthesized event. |
| | | This is backwards from reality, but better matches user expectations. */ |
| | | const BOOL istrackpad = ([theEvent subtype] == NSEventSubtypeMouseEvent); |
| | | |
| | | for (NSTouch *touch in touches) { |
| | | const SDL_TouchID touchId = (SDL_TouchID)(intptr_t)[touch device]; |
| | | if (SDL_AddTouch(touchId, "") < 0) { |
| | | const SDL_TouchID touchId = istrackpad ? SDL_MOUSE_TOUCHID : (SDL_TouchID)(intptr_t)[touch device]; |
| | | SDL_TouchDeviceType devtype = SDL_TOUCH_DEVICE_INDIRECT_ABSOLUTE; |
| | | |
| | | /* trackpad touches have no window. If we really wanted one we could |
| | | * use the window that has mouse or keyboard focus. |
| | | * Sending a null window currently also prevents synthetic mouse events |
| | | * from being generated from touch events. |
| | | */ |
| | | SDL_Window *window = NULL; |
| | | |
| | | #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101202 /* Added in the 10.12.2 SDK. */ |
| | | if ([touch respondsToSelector:@selector(type)]) { |
| | | /* TODO: Before implementing direct touch support here, we need to |
| | | * figure out whether the OS generates mouse events from them on its |
| | | * own. If it does, we should prevent SendTouch from generating |
| | | * synthetic mouse events for these touches itself (while also |
| | | * sending a window.) It will also need to use normalized window- |
| | | * relative coordinates via [touch locationInView:]. |
| | | */ |
| | | if ([touch type] == NSTouchTypeDirect) { |
| | | continue; |
| | | } |
| | | } |
| | | #endif |
| | | |
| | | if (SDL_AddTouch(touchId, devtype, "") < 0) { |
| | | return; |
| | | } |
| | | |
| | |
| | | |
| | | switch (phase) { |
| | | case NSTouchPhaseBegan: |
| | | SDL_SendTouch(touchId, fingerId, SDL_TRUE, x, y, 1.0f); |
| | | SDL_SendTouch(touchId, fingerId, window, SDL_TRUE, x, y, 1.0f); |
| | | break; |
| | | case NSTouchPhaseEnded: |
| | | case NSTouchPhaseCancelled: |
| | | SDL_SendTouch(touchId, fingerId, SDL_FALSE, x, y, 1.0f); |
| | | SDL_SendTouch(touchId, fingerId, window, SDL_FALSE, x, y, 1.0f); |
| | | break; |
| | | case NSTouchPhaseMoved: |
| | | SDL_SendTouchMotion(touchId, fingerId, x, y, 1.0f); |
| | | SDL_SendTouchMotion(touchId, fingerId, window, x, y, 1.0f); |
| | | break; |
| | | default: |
| | | break; |
| | |
| | | _sdlWindow = window; |
| | | } |
| | | |
| | | /* this is used on older macOS revisions. 10.8 and later use updateLayer. */ |
| | | /* this is used on older macOS revisions, and newer ones which emulate old |
| | | NSOpenGLContext behaviour while still using a layer under the hood. 10.8 and |
| | | later use updateLayer, up until 10.14.2 or so, which uses drawRect without |
| | | a GraphicsContext and with a layer active instead (for OpenGL contexts). */ |
| | | - (void)drawRect:(NSRect)dirtyRect |
| | | { |
| | | /* Force the graphics context to clear to black so we don't get a flash of |
| | | white until the app is ready to draw. In practice on modern macOS, this |
| | | only gets called for window creation and other extraordinary events. */ |
| | | [[NSColor blackColor] setFill]; |
| | | NSRectFill(dirtyRect); |
| | | if ([NSGraphicsContext currentContext]) { |
| | | [[NSColor blackColor] setFill]; |
| | | NSRectFill(dirtyRect); |
| | | } else if (self.layer) { |
| | | self.layer.backgroundColor = CGColorGetConstantColor(kCGColorBlack); |
| | | } |
| | | |
| | | SDL_SendWindowEvent(_sdlWindow, SDL_WINDOWEVENT_EXPOSED, 0, 0); |
| | | } |
| | | |
| | | -(BOOL) wantsUpdateLayer |
| | | - (BOOL)wantsUpdateLayer |
| | | { |
| | | return YES; |
| | | } |
| | | |
| | | -(void) updateLayer |
| | | /* This is also called when a Metal layer is active. */ |
| | | - (void)updateLayer |
| | | { |
| | | /* Force the graphics context to clear to black so we don't get a flash of |
| | | white until the app is ready to draw. In practice on modern macOS, this |
| | | only gets called for window creation and other extraordinary events. */ |
| | | self.layer.backgroundColor = NSColor.blackColor.CGColor; |
| | | self.layer.backgroundColor = CGColorGetConstantColor(kCGColorBlack); |
| | | ScheduleContextUpdates((SDL_WindowData *) _sdlWindow->driverdata); |
| | | SDL_SendWindowEvent(_sdlWindow, SDL_WINDOWEVENT_EXPOSED, 0, 0); |
| | | } |
| | |
| | | data->created = created; |
| | | data->videodata = videodata; |
| | | data->nscontexts = [[NSMutableArray alloc] init]; |
| | | |
| | | /* Only store this for windows created by us since the content view might |
| | | * get replaced from under us otherwise, and we only need it when the |
| | | * window is guaranteed to be created by us (OpenGL contexts). */ |
| | | data->sdlContentView = created ? [nswindow contentView] : nil; |
| | | |
| | | /* Create an event listener for the window */ |
| | | data->listener = [[Cocoa_WindowListener alloc] init]; |
| | |
| | | return SDL_SetError("%s", [[e reason] UTF8String]); |
| | | } |
| | | |
| | | #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101200 /* Added in the 10.12.0 SDK. */ |
| | | /* By default, don't allow users to make our window tabbed in 10.12 or later */ |
| | | if ([nswindow respondsToSelector:@selector(setTabbingMode:)]) { |
| | | [nswindow setTabbingMode:NSWindowTabbingModeDisallowed]; |
| | | } |
| | | #endif |
| | | |
| | | if (videodata->allow_spaces) { |
| | | SDL_assert(floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6); |
| | | SDL_assert([nswindow respondsToSelector:@selector(toggleFullScreen:)]); |
| | |
| | | } |
| | | } |
| | | |
| | | if (window->flags & SDL_WINDOW_ALWAYS_ON_TOP) { |
| | | [nswindow setLevel:NSFloatingWindowLevel]; |
| | | } |
| | | |
| | | /* Create a default view for this window */ |
| | | rect = [nswindow contentRectForFrameRect:[nswindow frame]]; |
| | | SDLView *contentView = [[SDLView alloc] initWithFrame:rect]; |
| | | [contentView setSDLWindow:window]; |
| | | |
| | | if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) { |
| | | if ([contentView respondsToSelector:@selector(setWantsBestResolutionOpenGLSurface:)]) { |
| | | [contentView setWantsBestResolutionOpenGLSurface:YES]; |
| | | } |
| | | /* We still support OpenGL as long as Apple offers it, deprecated or not, so disable deprecation warnings about it. */ |
| | | #ifdef __clang__ |
| | | #pragma clang diagnostic push |
| | | #pragma clang diagnostic ignored "-Wdeprecated-declarations" |
| | | #endif |
| | | /* Note: as of the macOS 10.15 SDK, this defaults to YES instead of NO when |
| | | * the NSHighResolutionCapable boolean is set in Info.plist. */ |
| | | if ([contentView respondsToSelector:@selector(setWantsBestResolutionOpenGLSurface:)]) { |
| | | BOOL highdpi = (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) != 0; |
| | | [contentView setWantsBestResolutionOpenGLSurface:highdpi]; |
| | | } |
| | | #ifdef __clang__ |
| | | #pragma clang diagnostic pop |
| | | #endif |
| | | |
| | | #if SDL_VIDEO_OPENGL_ES2 |
| | | #if SDL_VIDEO_OPENGL_EGL |
| | |
| | | { |
| | | SDL_WindowData *data = (SDL_WindowData *) window->driverdata; |
| | | NSWindow *nswindow = data->nswindow; |
| | | |
| | | if ([data->listener isInFullscreenSpaceTransition]) { |
| | | [data->listener addPendingWindowOperation:PENDING_OPERATION_MINIMIZE]; |
| | | } else { |
| | |
| | | rect.size.height = bounds.h; |
| | | ConvertNSRect([nswindow screen], fullscreen, &rect); |
| | | |
| | | /* Hack to fix origin on Mac OS X 10.4 */ |
| | | NSRect screenRect = [[nswindow screen] frame]; |
| | | if (screenRect.size.height >= 1.0f) { |
| | | rect.origin.y += (screenRect.size.height - rect.size.height); |
| | | /* Hack to fix origin on Mac OS X 10.4 |
| | | This is no longer needed as of Mac OS X 10.15, according to bug 4822. |
| | | */ |
| | | NSProcessInfo *processInfo = [NSProcessInfo processInfo]; |
| | | NSOperatingSystemVersion version = { 10, 15, 0 }; |
| | | if (![processInfo respondsToSelector:@selector(isOperatingSystemAtLeastVersion:)] || |
| | | ![processInfo isOperatingSystemAtLeastVersion:version]) { |
| | | NSRect screenRect = [[nswindow screen] frame]; |
| | | if (screenRect.size.height >= 1.0f) { |
| | | rect.origin.y += (screenRect.size.height - rect.size.height); |
| | | } |
| | | } |
| | | |
| | | [nswindow setStyleMask:NSWindowStyleMaskBorderless]; |
| | |
| | | rect.size.height = window->windowed.h; |
| | | ConvertNSRect([nswindow screen], fullscreen, &rect); |
| | | |
| | | [nswindow setStyleMask:GetWindowStyle(window)]; |
| | | /* The window is not meant to be fullscreen, but its flags might have a |
| | | * fullscreen bit set if it's scheduled to go fullscreen immediately |
| | | * after. Always using the windowed mode style here works around bugs in |
| | | * macOS 10.15 where the window doesn't properly restore the windowed |
| | | * mode decorations after exiting fullscreen-desktop, when the window |
| | | * was created as fullscreen-desktop. */ |
| | | [nswindow setStyleMask:GetWindowWindowedStyle(window)]; |
| | | |
| | | /* Hack to restore window decorations on Mac OS X 10.10 */ |
| | | NSRect frameRect = [nswindow frame]; |
| | |
| | | if (SDL_ShouldAllowTopmost() && fullscreen) { |
| | | /* OpenGL is rendering to the window, so make it visible! */ |
| | | [nswindow setLevel:CGShieldingWindowLevel()]; |
| | | } else if (window->flags & SDL_WINDOW_ALWAYS_ON_TOP) { |
| | | [nswindow setLevel:NSFloatingWindowLevel]; |
| | | } else { |
| | | [nswindow setLevel:kCGNormalWindowLevel]; |
| | | } |
| | |
| | | /* OpenGL is rendering to the window, so make it visible! */ |
| | | /* Doing this in 10.11 while in a Space breaks things (bug #3152) */ |
| | | [data->nswindow setLevel:CGShieldingWindowLevel()]; |
| | | } else if (window->flags & SDL_WINDOW_ALWAYS_ON_TOP) { |
| | | [data->nswindow setLevel:NSFloatingWindowLevel]; |
| | | } else { |
| | | [data->nswindow setLevel:kCGNormalWindowLevel]; |
| | | } |
| | |
| | | [data->listener close]; |
| | | [data->listener release]; |
| | | if (data->created) { |
| | | /* Release the content view to avoid further updateLayer callbacks */ |
| | | [data->nswindow setContentView:nil]; |
| | | [data->nswindow close]; |
| | | } |
| | | |
| | |
| | | SDL_bool succeeded = SDL_FALSE; |
| | | SDL_WindowData *data = (SDL_WindowData *) window->driverdata; |
| | | |
| | | if (data->inWindowFullscreenTransition) { |
| | | return SDL_FALSE; |
| | | } |
| | | |
| | | data->inWindowFullscreenTransition = SDL_TRUE; |
| | | if ([data->listener setFullscreenSpace:(state ? YES : NO)]) { |
| | | const int maxattempts = 3; |
| | | int attempt = 0; |
| | |
| | | /* Return TRUE to prevent non-space fullscreen logic from running */ |
| | | succeeded = SDL_TRUE; |
| | | } |
| | | data->inWindowFullscreenTransition = SDL_FALSE; |
| | | |
| | | return succeeded; |
| | | }} |