| | |
| | | /* |
| | | Simple DirectMedia Layer |
| | | Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org> |
| | | Copyright (C) 1997-2014 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 |
| | |
| | | misrepresented as being the original software. |
| | | 3. This notice may not be removed or altered from any source distribution. |
| | | */ |
| | | #include "SDL_config.h" |
| | | #include "../../SDL_internal.h" |
| | | |
| | | #if SDL_VIDEO_DRIVER_COCOA |
| | | |
| | | #if MAC_OS_X_VERSION_MAX_ALLOWED < 1070 |
| | | # error SDL for Mac OS X must be built with a 10.7 SDK or above. |
| | | #endif /* MAC_OS_X_VERSION_MAX_ALLOWED < 1070 */ |
| | | |
| | | #include "SDL_syswm.h" |
| | | #include "SDL_timer.h" /* For SDL_GetTicks() */ |
| | | #include "SDL_hints.h" |
| | | #include "../SDL_sysvideo.h" |
| | | #include "../../events/SDL_keyboard_c.h" |
| | | #include "../../events/SDL_mouse_c.h" |
| | |
| | | #include "SDL_cocoashape.h" |
| | | #include "SDL_cocoamouse.h" |
| | | #include "SDL_cocoaopengl.h" |
| | | #include "SDL_assert.h" |
| | | |
| | | #if MAC_OS_X_VERSION_MAX_ALLOWED < 1070 |
| | | /* Taken from AppKit/NSOpenGLView.h in 10.8 SDK. */ |
| | | @interface NSView (NSOpenGLSurfaceResolution) |
| | | - (BOOL)wantsBestResolutionOpenGLSurface; |
| | | - (void)setWantsBestResolutionOpenGLSurface:(BOOL)flag; |
| | | @end |
| | | /* #define DEBUG_COCOAWINDOW */ |
| | | |
| | | #ifdef DEBUG_COCOAWINDOW |
| | | #define DLog(fmt, ...) printf("%s: " fmt "\n", __func__, ##__VA_ARGS__) |
| | | #else |
| | | #define DLog(...) do { } while (0) |
| | | #endif |
| | | |
| | | |
| | | @interface SDLWindow : NSWindow |
| | | /* These are needed for borderless/fullscreen windows */ |
| | | - (BOOL)canBecomeKeyWindow; |
| | | - (BOOL)canBecomeMainWindow; |
| | | - (void)sendEvent:(NSEvent *)event; |
| | | @end |
| | | |
| | | @implementation SDLWindow |
| | | - (BOOL)canBecomeKeyWindow |
| | | { |
| | | return YES; |
| | | } |
| | | |
| | | - (BOOL)canBecomeMainWindow |
| | | { |
| | | return YES; |
| | | } |
| | | |
| | | - (void)sendEvent:(NSEvent *)event |
| | | { |
| | | [super sendEvent:event]; |
| | | |
| | | if ([event type] != NSLeftMouseUp) { |
| | | return; |
| | | } |
| | | |
| | | id delegate = [self delegate]; |
| | | if (![delegate isKindOfClass:[Cocoa_WindowListener class]]) { |
| | | return; |
| | | } |
| | | |
| | | if ([delegate isMoving]) { |
| | | [delegate windowDidFinishMoving]; |
| | | } |
| | | } |
| | | @end |
| | | |
| | | |
| | | static Uint32 s_moveHack; |
| | | |
| | |
| | | r->origin.y = CGDisplayPixelsHigh(kCGDirectMainDisplay) - r->origin.y - r->size.height; |
| | | } |
| | | |
| | | static void ScheduleContextUpdates(SDL_WindowData *data) |
| | | static void |
| | | ScheduleContextUpdates(SDL_WindowData *data) |
| | | { |
| | | NSOpenGLContext *currentContext = [NSOpenGLContext currentContext]; |
| | | NSMutableArray *contexts = data->nscontexts; |
| | | @synchronized (contexts) { |
| | | for (SDLOpenGLContext *context in contexts) { |
| | | [context scheduleUpdate]; |
| | | if (context == currentContext) { |
| | | [context update]; |
| | | } else { |
| | | [context scheduleUpdate]; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | static int |
| | | GetHintCtrlClickEmulateRightClick() |
| | | { |
| | | const char *hint = SDL_GetHint( SDL_HINT_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK ); |
| | | return hint != NULL && *hint != '0'; |
| | | } |
| | | |
| | | static unsigned int |
| | | GetWindowStyle(SDL_Window * window) |
| | | { |
| | | unsigned int style; |
| | | |
| | | if (window->flags & SDL_WINDOW_FULLSCREEN) { |
| | | style = NSBorderlessWindowMask; |
| | | } else { |
| | | if (window->flags & SDL_WINDOW_BORDERLESS) { |
| | | style = NSBorderlessWindowMask; |
| | | } else { |
| | | style = (NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask); |
| | | } |
| | | if (window->flags & SDL_WINDOW_RESIZABLE) { |
| | | style |= NSResizableWindowMask; |
| | | } |
| | | } |
| | | return style; |
| | | } |
| | | |
| | | static SDL_bool |
| | | SetWindowStyle(SDL_Window * window, unsigned int style) |
| | | { |
| | | SDL_WindowData *data = (SDL_WindowData *) window->driverdata; |
| | | NSWindow *nswindow = data->nswindow; |
| | | |
| | | if (![nswindow respondsToSelector: @selector(setStyleMask:)]) { |
| | | return SDL_FALSE; |
| | | } |
| | | |
| | | /* The view responder chain gets messed with during setStyleMask */ |
| | | if ([[nswindow contentView] nextResponder] == data->listener) { |
| | | [[nswindow contentView] setNextResponder:nil]; |
| | | } |
| | | |
| | | [nswindow performSelector: @selector(setStyleMask:) withObject: (id)(uintptr_t)style]; |
| | | |
| | | /* The view responder chain gets messed with during setStyleMask */ |
| | | if ([[nswindow contentView] nextResponder] != data->listener) { |
| | | [[nswindow contentView] setNextResponder:data->listener]; |
| | | } |
| | | |
| | | return SDL_TRUE; |
| | | } |
| | | |
| | | |
| | | @implementation Cocoa_WindowListener |
| | | |
| | |
| | | observingVisible = YES; |
| | | wasCtrlLeft = NO; |
| | | wasVisible = [window isVisible]; |
| | | isFullscreenSpace = NO; |
| | | inFullscreenTransition = NO; |
| | | pendingWindowOperation = PENDING_OPERATION_NONE; |
| | | isMoving = NO; |
| | | |
| | | center = [NSNotificationCenter defaultCenter]; |
| | | |
| | |
| | | [center addObserver:self selector:@selector(windowDidDeminiaturize:) name:NSWindowDidDeminiaturizeNotification object:window]; |
| | | [center addObserver:self selector:@selector(windowDidBecomeKey:) name:NSWindowDidBecomeKeyNotification object:window]; |
| | | [center addObserver:self selector:@selector(windowDidResignKey:) name:NSWindowDidResignKeyNotification object:window]; |
| | | [center addObserver:self selector:@selector(windowWillEnterFullScreen:) name:NSWindowWillEnterFullScreenNotification object:window]; |
| | | [center addObserver:self selector:@selector(windowDidEnterFullScreen:) name:NSWindowDidEnterFullScreenNotification object:window]; |
| | | [center addObserver:self selector:@selector(windowWillExitFullScreen:) name:NSWindowWillExitFullScreenNotification object:window]; |
| | | [center addObserver:self selector:@selector(windowDidExitFullScreen:) name:NSWindowDidExitFullScreenNotification object:window]; |
| | | } else { |
| | | [window setDelegate:self]; |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | -(BOOL) setFullscreenSpace:(BOOL) state |
| | | { |
| | | SDL_Window *window = _data->window; |
| | | NSWindow *nswindow = _data->nswindow; |
| | | SDL_VideoData *videodata = ((SDL_WindowData *) window->driverdata)->videodata; |
| | | |
| | | if (!videodata->allow_spaces) { |
| | | return NO; /* Spaces are forcibly disabled. */ |
| | | } else if (state && ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP)) { |
| | | return NO; /* we only allow you to make a Space on FULLSCREEN_DESKTOP windows. */ |
| | | } else if (state == isFullscreenSpace) { |
| | | return YES; /* already there. */ |
| | | } |
| | | |
| | | if (inFullscreenTransition) { |
| | | if (state) { |
| | | [self addPendingWindowOperation:PENDING_OPERATION_ENTER_FULLSCREEN]; |
| | | } else { |
| | | [self addPendingWindowOperation:PENDING_OPERATION_LEAVE_FULLSCREEN]; |
| | | } |
| | | return YES; |
| | | } |
| | | inFullscreenTransition = YES; |
| | | |
| | | /* you need to be FullScreenPrimary, or toggleFullScreen doesn't work. Unset it again in windowDidExitFullScreen. */ |
| | | [nswindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; |
| | | [nswindow performSelectorOnMainThread: @selector(toggleFullScreen:) withObject:nswindow waitUntilDone:NO]; |
| | | return YES; |
| | | } |
| | | |
| | | -(BOOL) isInFullscreenSpace |
| | | { |
| | | return isFullscreenSpace; |
| | | } |
| | | |
| | | -(BOOL) isInFullscreenSpaceTransition |
| | | { |
| | | return inFullscreenTransition; |
| | | } |
| | | |
| | | -(void) addPendingWindowOperation:(PendingWindowOperation) operation |
| | | { |
| | | pendingWindowOperation = operation; |
| | | } |
| | | |
| | | - (void)close |
| | | { |
| | | NSNotificationCenter *center; |
| | |
| | | [center removeObserver:self name:NSWindowDidDeminiaturizeNotification object:window]; |
| | | [center removeObserver:self name:NSWindowDidBecomeKeyNotification object:window]; |
| | | [center removeObserver:self name:NSWindowDidResignKeyNotification object:window]; |
| | | [center removeObserver:self name:NSWindowWillEnterFullScreenNotification object:window]; |
| | | [center removeObserver:self name:NSWindowDidEnterFullScreenNotification object:window]; |
| | | [center removeObserver:self name:NSWindowWillExitFullScreenNotification object:window]; |
| | | [center removeObserver:self name:NSWindowDidExitFullScreenNotification object:window]; |
| | | } else { |
| | | [window setDelegate:nil]; |
| | | } |
| | | |
| | | [window removeObserver:self |
| | | forKeyPath:@"visible"]; |
| | | [window removeObserver:self forKeyPath:@"visible"]; |
| | | |
| | | if ([window nextResponder] == self) { |
| | | [window setNextResponder:nil]; |
| | |
| | | !!! FIXME: http://bugzilla.libsdl.org/show_bug.cgi?id=1825 |
| | | */ |
| | | windows = [NSApp orderedWindows]; |
| | | if ([windows count] > 0) { |
| | | NSWindow *win = (NSWindow *) [windows objectAtIndex:0]; |
| | | for (NSWindow *win in windows) |
| | | { |
| | | if (win == window) { |
| | | continue; |
| | | } |
| | | |
| | | [win makeKeyAndOrderFront:self]; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | - (BOOL)isMoving |
| | | { |
| | | return isMoving; |
| | | } |
| | | |
| | | -(void) setPendingMoveX:(int)x Y:(int)y |
| | | { |
| | | pendingWindowWarpX = x; |
| | | pendingWindowWarpY = y; |
| | | } |
| | | |
| | | - (void)windowDidFinishMoving |
| | | { |
| | | if ([self isMoving]) |
| | | { |
| | | isMoving = NO; |
| | | |
| | | SDL_Mouse *mouse = SDL_GetMouse(); |
| | | if (pendingWindowWarpX >= 0 && pendingWindowWarpY >= 0) { |
| | | mouse->WarpMouse(_data->window, pendingWindowWarpX, pendingWindowWarpY); |
| | | pendingWindowWarpX = pendingWindowWarpY = -1; |
| | | } |
| | | if (mouse->relative_mode && SDL_GetMouseFocus() == _data->window) { |
| | | mouse->SetRelativeMouseMode(SDL_TRUE); |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | - (void)windowDidExpose:(NSNotification *)aNotification |
| | | { |
| | | SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_EXPOSED, 0, 0); |
| | | } |
| | | |
| | | - (void)windowWillMove:(NSNotification *)aNotification |
| | | { |
| | | if ([_data->nswindow isKindOfClass:[SDLWindow class]]) { |
| | | pendingWindowWarpX = pendingWindowWarpY = -1; |
| | | isMoving = YES; |
| | | } |
| | | } |
| | | |
| | | - (void)windowDidMove:(NSNotification *)aNotification |
| | |
| | | |
| | | - (void)windowDidResize:(NSNotification *)aNotification |
| | | { |
| | | if (inFullscreenTransition) { |
| | | /* We'll take care of this at the end of the transition */ |
| | | return; |
| | | } |
| | | |
| | | SDL_Window *window = _data->window; |
| | | NSWindow *nswindow = _data->nswindow; |
| | | int x, y, w, h; |
| | | NSRect rect = [_data->nswindow contentRectForFrameRect:[_data->nswindow frame]]; |
| | | NSRect rect = [nswindow contentRectForFrameRect:[nswindow frame]]; |
| | | ConvertNSRect(&rect); |
| | | x = (int)rect.origin.x; |
| | | y = (int)rect.origin.y; |
| | | w = (int)rect.size.width; |
| | | h = (int)rect.size.height; |
| | | if (SDL_IsShapedWindow(_data->window)) |
| | | Cocoa_ResizeWindowShape(_data->window); |
| | | |
| | | if (SDL_IsShapedWindow(window)) { |
| | | Cocoa_ResizeWindowShape(window); |
| | | } |
| | | |
| | | ScheduleContextUpdates(_data); |
| | | |
| | | /* The window can move during a resize event, such as when maximizing |
| | | or resizing from a corner */ |
| | | SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_MOVED, x, y); |
| | | SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_RESIZED, w, h); |
| | | SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, x, y); |
| | | SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, w, h); |
| | | |
| | | const BOOL zoomed = [_data->nswindow isZoomed]; |
| | | const BOOL zoomed = [nswindow isZoomed]; |
| | | if (!zoomed) { |
| | | SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_RESTORED, 0, 0); |
| | | SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESTORED, 0, 0); |
| | | } else if (zoomed) { |
| | | SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_MAXIMIZED, 0, 0); |
| | | SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MAXIMIZED, 0, 0); |
| | | } |
| | | } |
| | | |
| | |
| | | { |
| | | SDL_Window *window = _data->window; |
| | | SDL_Mouse *mouse = SDL_GetMouse(); |
| | | if (mouse->relative_mode && ![self isMoving]) { |
| | | mouse->SetRelativeMouseMode(SDL_TRUE); |
| | | } |
| | | |
| | | /* We're going to get keyboard events, since we're key. */ |
| | | SDL_SetKeyboardFocus(window); |
| | |
| | | |
| | | /* Check to see if someone updated the clipboard */ |
| | | Cocoa_CheckClipboardUpdate(_data->videodata); |
| | | |
| | | if ((isFullscreenSpace) && ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP)) { |
| | | [NSMenu setMenuBarVisible:NO]; |
| | | } |
| | | } |
| | | |
| | | - (void)windowDidResignKey:(NSNotification *)aNotification |
| | | { |
| | | SDL_Mouse *mouse = SDL_GetMouse(); |
| | | if (mouse->relative_mode) { |
| | | mouse->SetRelativeMouseMode(SDL_FALSE); |
| | | } |
| | | |
| | | /* Some other window will get mouse events, since we're not key. */ |
| | | if (SDL_GetMouseFocus() == _data->window) { |
| | | SDL_SetMouseFocus(NULL); |
| | |
| | | if (SDL_GetKeyboardFocus() == _data->window) { |
| | | SDL_SetKeyboardFocus(NULL); |
| | | } |
| | | |
| | | if (isFullscreenSpace) { |
| | | [NSMenu setMenuBarVisible:YES]; |
| | | } |
| | | } |
| | | |
| | | - (void)windowWillEnterFullScreen:(NSNotification *)aNotification |
| | | { |
| | | SDL_Window *window = _data->window; |
| | | |
| | | SetWindowStyle(window, (NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask)); |
| | | |
| | | isFullscreenSpace = YES; |
| | | inFullscreenTransition = YES; |
| | | } |
| | | |
| | | - (void)windowDidEnterFullScreen:(NSNotification *)aNotification |
| | | { |
| | | SDL_Window *window = _data->window; |
| | | |
| | | inFullscreenTransition = NO; |
| | | |
| | | if (pendingWindowOperation == PENDING_OPERATION_LEAVE_FULLSCREEN) { |
| | | pendingWindowOperation = PENDING_OPERATION_NONE; |
| | | [self setFullscreenSpace:NO]; |
| | | } else { |
| | | if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) { |
| | | [NSMenu setMenuBarVisible:NO]; |
| | | } |
| | | |
| | | pendingWindowOperation = PENDING_OPERATION_NONE; |
| | | /* Force the size change event in case it was delivered earlier |
| | | while the window was still animating into place. |
| | | */ |
| | | window->w = 0; |
| | | window->h = 0; |
| | | [self windowDidResize:aNotification]; |
| | | } |
| | | } |
| | | |
| | | - (void)windowWillExitFullScreen:(NSNotification *)aNotification |
| | | { |
| | | SDL_Window *window = _data->window; |
| | | |
| | | SetWindowStyle(window, GetWindowStyle(window)); |
| | | |
| | | isFullscreenSpace = NO; |
| | | inFullscreenTransition = YES; |
| | | } |
| | | |
| | | - (void)windowDidExitFullScreen:(NSNotification *)aNotification |
| | | { |
| | | SDL_Window *window = _data->window; |
| | | NSWindow *nswindow = _data->nswindow; |
| | | |
| | | inFullscreenTransition = NO; |
| | | |
| | | if (pendingWindowOperation == PENDING_OPERATION_ENTER_FULLSCREEN) { |
| | | pendingWindowOperation = PENDING_OPERATION_NONE; |
| | | [self setFullscreenSpace:YES]; |
| | | } else if (pendingWindowOperation == PENDING_OPERATION_MINIMIZE) { |
| | | pendingWindowOperation = PENDING_OPERATION_NONE; |
| | | [nswindow miniaturize:nil]; |
| | | } else { |
| | | /* Adjust the fullscreen toggle button and readd menu now that we're here. */ |
| | | if (window->flags & SDL_WINDOW_RESIZABLE) { |
| | | /* resizable windows are Spaces-friendly: they get the "go fullscreen" toggle button on their titlebar. */ |
| | | [nswindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; |
| | | } else { |
| | | [nswindow setCollectionBehavior:NSWindowCollectionBehaviorManaged]; |
| | | } |
| | | [NSMenu setMenuBarVisible:YES]; |
| | | |
| | | pendingWindowOperation = PENDING_OPERATION_NONE; |
| | | /* Force the size change event in case it was delivered earlier |
| | | while the window was still animating into place. |
| | | */ |
| | | window->w = 0; |
| | | window->h = 0; |
| | | [self windowDidResize:aNotification]; |
| | | } |
| | | } |
| | | |
| | | -(NSApplicationPresentationOptions)window:(NSWindow *)window willUseFullScreenPresentationOptions:(NSApplicationPresentationOptions)proposedOptions |
| | | { |
| | | if ((_data->window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) { |
| | | return NSApplicationPresentationFullScreen | NSApplicationPresentationHideDock | NSApplicationPresentationHideMenuBar; |
| | | } else { |
| | | return proposedOptions; |
| | | } |
| | | } |
| | | |
| | | |
| | | /* We'll respond to key events by doing nothing so we don't beep. |
| | | * We could handle key messages here, but we lose some in the NSApp dispatch, |
| | |
| | | |
| | | switch ([theEvent buttonNumber]) { |
| | | case 0: |
| | | if ([theEvent modifierFlags] & NSControlKeyMask) { |
| | | if (([theEvent modifierFlags] & NSControlKeyMask) && |
| | | GetHintCtrlClickEmulateRightClick()) { |
| | | wasCtrlLeft = YES; |
| | | button = SDL_BUTTON_RIGHT; |
| | | } else { |
| | |
| | | |
| | | if (x < 0 || x >= window->w || y < 0 || y >= window->h) { |
| | | if (window->flags & SDL_WINDOW_INPUT_GRABBED) { |
| | | CGPoint cgpoint; |
| | | |
| | | if (x < 0) { |
| | | x = 0; |
| | | } else if (x >= window->w) { |
| | |
| | | } |
| | | |
| | | #if !SDL_MAC_NO_SANDBOX |
| | | CGPoint cgpoint; |
| | | |
| | | /* When SDL_MAC_NO_SANDBOX is set, this is handled by |
| | | * SDL_cocoamousetap.m. |
| | | */ |
| | |
| | | CGSetLocalEventsSuppressionInterval(0.0); |
| | | CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint); |
| | | CGSetLocalEventsSuppressionInterval(0.25); |
| | | |
| | | Cocoa_HandleMouseWarp(cgpoint.x, cgpoint.y); |
| | | #endif |
| | | } |
| | | } |
| | |
| | | touches = [event touchesMatchingPhase:NSTouchPhaseBegan inView:nil]; |
| | | break; |
| | | case COCOA_TOUCH_UP: |
| | | case COCOA_TOUCH_CANCELLED: |
| | | touches = [event touchesMatchingPhase:NSTouchPhaseEnded inView:nil]; |
| | | break; |
| | | case COCOA_TOUCH_CANCELLED: |
| | | touches = [event touchesMatchingPhase:NSTouchPhaseCancelled inView:nil]; |
| | | break; |
| | | case COCOA_TOUCH_MOVE: |
| | | touches = [event touchesMatchingPhase:NSTouchPhaseMoved inView:nil]; |
| | |
| | | |
| | | @end |
| | | |
| | | @interface SDLWindow : NSWindow |
| | | /* These are needed for borderless/fullscreen windows */ |
| | | - (BOOL)canBecomeKeyWindow; |
| | | - (BOOL)canBecomeMainWindow; |
| | | @end |
| | | |
| | | @implementation SDLWindow |
| | | - (BOOL)canBecomeKeyWindow |
| | | { |
| | | return YES; |
| | | } |
| | | |
| | | - (BOOL)canBecomeMainWindow |
| | | { |
| | | return YES; |
| | | } |
| | | @end |
| | | |
| | | @interface SDLView : NSView |
| | | |
| | | /* The default implementation doesn't pass rightMouseDown to responder chain */ |
| | |
| | | } |
| | | } |
| | | @end |
| | | |
| | | static unsigned int |
| | | GetWindowStyle(SDL_Window * window) |
| | | { |
| | | unsigned int style; |
| | | |
| | | if (window->flags & SDL_WINDOW_FULLSCREEN) { |
| | | style = NSBorderlessWindowMask; |
| | | } else { |
| | | if (window->flags & SDL_WINDOW_BORDERLESS) { |
| | | style = NSBorderlessWindowMask; |
| | | } else { |
| | | style = (NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask); |
| | | } |
| | | if (window->flags & SDL_WINDOW_RESIZABLE) { |
| | | style |= NSResizableWindowMask; |
| | | } |
| | | } |
| | | return style; |
| | | } |
| | | |
| | | static int |
| | | SetupWindowData(_THIS, SDL_Window * window, NSWindow *nswindow, SDL_bool created) |
| | |
| | | int |
| | | Cocoa_CreateWindow(_THIS, SDL_Window * window) |
| | | { |
| | | SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata; |
| | | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; |
| | | NSWindow *nswindow; |
| | | SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window); |
| | |
| | | rect.origin.y -= screenRect.origin.y; |
| | | } |
| | | } |
| | | nswindow = [[SDLWindow alloc] initWithContentRect:rect styleMask:style backing:NSBackingStoreBuffered defer:NO screen:screen]; |
| | | |
| | | @try { |
| | | nswindow = [[SDLWindow alloc] initWithContentRect:rect styleMask:style backing:NSBackingStoreBuffered defer:NO screen:screen]; |
| | | } |
| | | @catch (NSException *e) { |
| | | SDL_SetError("%s", [[e reason] UTF8String]); |
| | | [pool release]; |
| | | return -1; |
| | | } |
| | | [nswindow setBackgroundColor:[NSColor blackColor]]; |
| | | |
| | | if (videodata->allow_spaces) { |
| | | SDL_assert(videodata->osversion >= 0x1070); |
| | | SDL_assert([nswindow respondsToSelector:@selector(toggleFullScreen:)]); |
| | | /* we put FULLSCREEN_DESKTOP windows in their own Space, without a toggle button or menubar, later */ |
| | | if (window->flags & SDL_WINDOW_RESIZABLE) { |
| | | /* resizable windows are Spaces-friendly: they get the "go fullscreen" toggle button on their titlebar. */ |
| | | [nswindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; |
| | | } |
| | | } |
| | | |
| | | /* Create a default view for this window */ |
| | | rect = [nswindow contentRectForFrameRect:[nswindow frame]]; |
| | | NSView *contentView = [[SDLView alloc] initWithFrame:rect]; |
| | | |
| | | if ((window->flags & SDL_WINDOW_ALLOW_HIGHDPI) > 0) { |
| | | if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) { |
| | | if ([contentView respondsToSelector:@selector(setWantsBestResolutionOpenGLSurface:)]) { |
| | | [contentView setWantsBestResolutionOpenGLSurface:YES]; |
| | | } |
| | |
| | | Cocoa_MinimizeWindow(_THIS, SDL_Window * window) |
| | | { |
| | | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; |
| | | NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow; |
| | | SDL_WindowData *data = (SDL_WindowData *) window->driverdata; |
| | | NSWindow *nswindow = data->nswindow; |
| | | |
| | | [nswindow miniaturize:nil]; |
| | | if ([data->listener isInFullscreenSpaceTransition]) { |
| | | [data->listener addPendingWindowOperation:PENDING_OPERATION_MINIMIZE]; |
| | | } else { |
| | | [nswindow miniaturize:nil]; |
| | | } |
| | | [pool release]; |
| | | } |
| | | |
| | |
| | | Cocoa_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered) |
| | | { |
| | | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; |
| | | NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow; |
| | | if ([nswindow respondsToSelector:@selector(setStyleMask:)]) { |
| | | [nswindow setStyleMask:GetWindowStyle(window)]; |
| | | if (SetWindowStyle(window, GetWindowStyle(window))) { |
| | | if (bordered) { |
| | | Cocoa_SetWindowTitle(_this, window); /* this got blanked out. */ |
| | | } |
| | | } |
| | | [pool release]; |
| | | } |
| | | |
| | | |
| | | void |
| | | Cocoa_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen) |
| | |
| | | Cocoa_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed) |
| | | { |
| | | /* Move the cursor to the nearest point in the window */ |
| | | if (grabbed) { |
| | | SDL_WindowData *data = (SDL_WindowData *) window->driverdata; |
| | | if (grabbed && data && ![data->listener isMoving]) { |
| | | int x, y; |
| | | CGPoint cgpoint; |
| | | |
| | | SDL_GetMouseState(&x, &y); |
| | | cgpoint.x = window->x + x; |
| | | cgpoint.y = window->y + y; |
| | | |
| | | Cocoa_HandleMouseWarp(cgpoint.x, cgpoint.y); |
| | | |
| | | DLog("Returning cursor to (%g, %g)", cgpoint.x, cgpoint.y); |
| | | CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint); |
| | | } |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | SDL_bool |
| | | Cocoa_IsWindowInFullscreenSpace(SDL_Window * window) |
| | | { |
| | | SDL_WindowData *data = (SDL_WindowData *) window->driverdata; |
| | | |
| | | if ([data->listener isInFullscreenSpace]) { |
| | | return SDL_TRUE; |
| | | } else { |
| | | return SDL_FALSE; |
| | | } |
| | | } |
| | | |
| | | SDL_bool |
| | | Cocoa_SetWindowFullscreenSpace(SDL_Window * window, SDL_bool state) |
| | | { |
| | | SDL_bool succeeded = SDL_FALSE; |
| | | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; |
| | | SDL_WindowData *data = (SDL_WindowData *) window->driverdata; |
| | | |
| | | if ([data->listener setFullscreenSpace:(state ? YES : NO)]) { |
| | | succeeded = SDL_TRUE; |
| | | } |
| | | |
| | | [pool release]; |
| | | |
| | | return succeeded; |
| | | } |
| | | |
| | | #endif /* SDL_VIDEO_DRIVER_COCOA */ |
| | | |
| | | /* vi: set ts=4 sw=4 expandtab: */ |