src/video/cocoa/SDL_cocoawindow.m
author Sam Lantinga <slouken@libsdl.org>
Mon, 11 Nov 2013 23:42:43 -0800
changeset 7966 ef27c2dbeb8f
parent 7965 d3cbe8ecb1af
child 7967 75f04553360a
permissions -rw-r--r--
Made sure the window had the correct border when manually being brought back from fullscreen mode.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "SDL_config.h"
    22 
    23 #if SDL_VIDEO_DRIVER_COCOA
    24 
    25 #include "SDL_syswm.h"
    26 #include "SDL_timer.h"  /* For SDL_GetTicks() */
    27 #include "SDL_hints.h"
    28 #include "../SDL_sysvideo.h"
    29 #include "../../events/SDL_keyboard_c.h"
    30 #include "../../events/SDL_mouse_c.h"
    31 #include "../../events/SDL_touch_c.h"
    32 #include "../../events/SDL_windowevents_c.h"
    33 #include "SDL_cocoavideo.h"
    34 #include "SDL_cocoashape.h"
    35 #include "SDL_cocoamouse.h"
    36 #include "SDL_cocoaopengl.h"
    37 
    38 #if MAC_OS_X_VERSION_MAX_ALLOWED < 1070
    39 /* Taken from AppKit/NSOpenGLView.h in 10.8 SDK. */
    40 @interface NSView (NSOpenGLSurfaceResolution)
    41 - (BOOL)wantsBestResolutionOpenGLSurface;
    42 - (void)setWantsBestResolutionOpenGLSurface:(BOOL)flag;
    43 @end
    44 #endif
    45 
    46 static Uint32 s_moveHack;
    47 
    48 static void ConvertNSRect(NSRect *r)
    49 {
    50     r->origin.y = CGDisplayPixelsHigh(kCGDirectMainDisplay) - r->origin.y - r->size.height;
    51 }
    52 
    53 static void
    54 ScheduleContextUpdates(SDL_WindowData *data)
    55 {
    56     NSMutableArray *contexts = data->nscontexts;
    57     @synchronized (contexts) {
    58         for (SDLOpenGLContext *context in contexts) {
    59             [context scheduleUpdate];
    60         }
    61     }
    62 }
    63 
    64 static int
    65 GetHintCtrlClickEmulateRightClick()
    66 {
    67 	const char *hint = SDL_GetHint( SDL_HINT_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK );
    68 	return hint != NULL && *hint != '0';
    69 }
    70 
    71 static unsigned int
    72 GetWindowStyle(SDL_Window * window)
    73 {
    74     unsigned int style;
    75 
    76     if (window->flags & SDL_WINDOW_FULLSCREEN) {
    77         style = NSBorderlessWindowMask;
    78     } else {
    79         if (window->flags & SDL_WINDOW_BORDERLESS) {
    80             style = NSBorderlessWindowMask;
    81         } else {
    82             style = (NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask);
    83         }
    84         if (window->flags & SDL_WINDOW_RESIZABLE) {
    85             style |= NSResizableWindowMask;
    86         }
    87     }
    88     return style;
    89 }
    90 
    91 
    92 @implementation Cocoa_WindowListener
    93 
    94 - (void)listen:(SDL_WindowData *)data
    95 {
    96     NSNotificationCenter *center;
    97     NSWindow *window = data->nswindow;
    98     NSView *view = [window contentView];
    99 
   100     _data = data;
   101     observingVisible = YES;
   102     wasCtrlLeft = NO;
   103     wasVisible = [window isVisible];
   104     isFullscreen = NO;
   105     inFullscreenTransition = NO;
   106     pendingWindowOperation = PENDING_OPERATION_NONE;
   107 
   108     center = [NSNotificationCenter defaultCenter];
   109 
   110     if ([window delegate] != nil) {
   111         [center addObserver:self selector:@selector(windowDidExpose:) name:NSWindowDidExposeNotification object:window];
   112         [center addObserver:self selector:@selector(windowDidMove:) name:NSWindowDidMoveNotification object:window];
   113         [center addObserver:self selector:@selector(windowDidResize:) name:NSWindowDidResizeNotification object:window];
   114         [center addObserver:self selector:@selector(windowDidMiniaturize:) name:NSWindowDidMiniaturizeNotification object:window];
   115         [center addObserver:self selector:@selector(windowDidDeminiaturize:) name:NSWindowDidDeminiaturizeNotification object:window];
   116         [center addObserver:self selector:@selector(windowDidBecomeKey:) name:NSWindowDidBecomeKeyNotification object:window];
   117         [center addObserver:self selector:@selector(windowDidResignKey:) name:NSWindowDidResignKeyNotification object:window];
   118 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
   119         [center addObserver:self selector:@selector(windowWillEnterFullScreen:) name:NSWindowWillEnterFullScreenNotification object:window];
   120         [center addObserver:self selector:@selector(windowDidEnterFullScreen:) name:NSWindowDidEnterFullScreenNotification object:window];
   121         [center addObserver:self selector:@selector(windowWillExitFullScreen:) name:NSWindowWillExitFullScreenNotification object:window];
   122         [center addObserver:self selector:@selector(windowDidExitFullScreen:) name:NSWindowDidExitFullScreenNotification object:window];
   123 #endif /* Mac OS X 10.7+ */
   124     } else {
   125         [window setDelegate:self];
   126     }
   127 
   128     /* Haven't found a delegate / notification that triggers when the window is
   129      * ordered out (is not visible any more). You can be ordered out without
   130      * minimizing, so DidMiniaturize doesn't work. (e.g. -[NSWindow orderOut:])
   131      */
   132     [window addObserver:self
   133              forKeyPath:@"visible"
   134                 options:NSKeyValueObservingOptionNew
   135                 context:NULL];
   136 
   137     [window setNextResponder:self];
   138     [window setAcceptsMouseMovedEvents:YES];
   139 
   140     [view setNextResponder:self];
   141 
   142     if ([view respondsToSelector:@selector(setAcceptsTouchEvents:)]) {
   143         [view setAcceptsTouchEvents:YES];
   144     }
   145 }
   146 
   147 - (void)observeValueForKeyPath:(NSString *)keyPath
   148                       ofObject:(id)object
   149                         change:(NSDictionary *)change
   150                        context:(void *)context
   151 {
   152     if (!observingVisible) {
   153         return;
   154     }
   155 
   156     if (object == _data->nswindow && [keyPath isEqualToString:@"visible"]) {
   157         int newVisibility = [[change objectForKey:@"new"] intValue];
   158         if (newVisibility) {
   159             SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
   160         } else {
   161             SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
   162         }
   163     }
   164 }
   165 
   166 -(void) pauseVisibleObservation
   167 {
   168     observingVisible = NO;
   169     wasVisible = [_data->nswindow isVisible];
   170 }
   171 
   172 -(void) resumeVisibleObservation
   173 {
   174     BOOL isVisible = [_data->nswindow isVisible];
   175     observingVisible = YES;
   176     if (wasVisible != isVisible) {
   177         if (isVisible) {
   178             SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
   179         } else {
   180             SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
   181         }
   182 
   183         wasVisible = isVisible;
   184     }
   185 }
   186 
   187 -(BOOL) setFullscreenState:(BOOL) state;
   188 {
   189     SDL_Window *window = _data->window;
   190     NSWindow *nswindow = _data->nswindow;
   191     BOOL canSetState = NO;
   192 
   193     /* Make sure we can support this fullscreen style */
   194     if (![nswindow respondsToSelector: @selector(toggleFullScreen:)]) {
   195         return NO;
   196     }
   197 
   198     pendingWindowOperation = PENDING_OPERATION_NONE;
   199 
   200     /* We can enter new style fullscreen mode for "fullscreen desktop" */
   201     if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) {
   202         canSetState = YES;
   203     }
   204 
   205     /* We can always leave new style fullscreen mode */
   206     if (!state && isFullscreen) {
   207         canSetState = YES;
   208     }
   209 
   210     if (!canSetState) {
   211         return NO;
   212     }
   213 
   214     if (state == isFullscreen) {
   215         return YES;
   216     }
   217 
   218     if (inFullscreenTransition) {
   219         if (state) {
   220             [self addPendingWindowOperation:PENDING_OPERATION_ENTER_FULLSCREEN];
   221         } else {
   222             [self addPendingWindowOperation:PENDING_OPERATION_LEAVE_FULLSCREEN];
   223         }
   224         return YES;
   225     }
   226 
   227     [nswindow performSelectorOnMainThread: @selector(toggleFullScreen:) withObject:nswindow waitUntilDone:NO];
   228     return YES;
   229 }
   230 
   231 -(BOOL) isInFullscreenTransition
   232 {
   233     return inFullscreenTransition;
   234 }
   235 
   236 -(void) addPendingWindowOperation:(PendingWindowOperation) operation
   237 {
   238     pendingWindowOperation = operation;
   239 }
   240 
   241 - (void)close
   242 {
   243     NSNotificationCenter *center;
   244     NSWindow *window = _data->nswindow;
   245     NSView *view = [window contentView];
   246     NSArray *windows = nil;
   247 
   248     center = [NSNotificationCenter defaultCenter];
   249 
   250     if ([window delegate] != self) {
   251         [center removeObserver:self name:NSWindowDidExposeNotification object:window];
   252         [center removeObserver:self name:NSWindowDidMoveNotification object:window];
   253         [center removeObserver:self name:NSWindowDidResizeNotification object:window];
   254         [center removeObserver:self name:NSWindowDidMiniaturizeNotification object:window];
   255         [center removeObserver:self name:NSWindowDidDeminiaturizeNotification object:window];
   256         [center removeObserver:self name:NSWindowDidBecomeKeyNotification object:window];
   257         [center removeObserver:self name:NSWindowDidResignKeyNotification object:window];
   258 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
   259         [center removeObserver:self name:NSWindowWillEnterFullScreenNotification object:window];
   260         [center removeObserver:self name:NSWindowDidEnterFullScreenNotification object:window];
   261         [center removeObserver:self name:NSWindowWillExitFullScreenNotification object:window];
   262         [center removeObserver:self name:NSWindowDidExitFullScreenNotification object:window];
   263 #endif /* Mac OS X 10.7+ */
   264     } else {
   265         [window setDelegate:nil];
   266     }
   267 
   268     [window removeObserver:self forKeyPath:@"visible"];
   269 
   270     if ([window nextResponder] == self) {
   271         [window setNextResponder:nil];
   272     }
   273     if ([view nextResponder] == self) {
   274         [view setNextResponder:nil];
   275     }
   276 
   277     /* Make the next window in the z-order Key. If we weren't the foreground
   278        when closed, this is a no-op.
   279        !!! FIXME: Note that this is a hack, and there are corner cases where
   280        !!! FIXME:  this fails (such as the About box). The typical nib+RunLoop
   281        !!! FIXME:  handles this for Cocoa apps, but we bypass all that in SDL.
   282        !!! FIXME:  We should remove this code when we find a better way to
   283        !!! FIXME:  have the system do this for us. See discussion in
   284        !!! FIXME:   http://bugzilla.libsdl.org/show_bug.cgi?id=1825
   285     */
   286     windows = [NSApp orderedWindows];
   287     if ([windows count] > 0) {
   288         NSWindow *win = (NSWindow *) [windows objectAtIndex:0];
   289         [win makeKeyAndOrderFront:self];
   290     }
   291 }
   292 
   293 - (BOOL)windowShouldClose:(id)sender
   294 {
   295     SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_CLOSE, 0, 0);
   296     return NO;
   297 }
   298 
   299 - (void)windowDidExpose:(NSNotification *)aNotification
   300 {
   301     SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_EXPOSED, 0, 0);
   302 }
   303 
   304 - (void)windowDidMove:(NSNotification *)aNotification
   305 {
   306     int x, y;
   307     SDL_Window *window = _data->window;
   308     NSWindow *nswindow = _data->nswindow;
   309     NSRect rect = [nswindow contentRectForFrameRect:[nswindow frame]];
   310     ConvertNSRect(&rect);
   311 
   312     if (s_moveHack) {
   313         SDL_bool blockMove = ((SDL_GetTicks() - s_moveHack) < 500);
   314 
   315         s_moveHack = 0;
   316 
   317         if (blockMove) {
   318             /* Cocoa is adjusting the window in response to a mode change */
   319             rect.origin.x = window->x;
   320             rect.origin.y = window->y;
   321             ConvertNSRect(&rect);
   322             [nswindow setFrameOrigin:rect.origin];
   323             return;
   324         }
   325     }
   326 
   327     x = (int)rect.origin.x;
   328     y = (int)rect.origin.y;
   329 
   330     ScheduleContextUpdates(_data);
   331 
   332     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, x, y);
   333 }
   334 
   335 - (void)windowDidResize:(NSNotification *)aNotification
   336 {
   337     SDL_Window *window = _data->window;
   338     NSWindow *nswindow = _data->nswindow;
   339     int x, y, w, h;
   340     NSRect rect = [nswindow contentRectForFrameRect:[nswindow frame]];
   341     ConvertNSRect(&rect);
   342     x = (int)rect.origin.x;
   343     y = (int)rect.origin.y;
   344     w = (int)rect.size.width;
   345     h = (int)rect.size.height;
   346 
   347     if (inFullscreenTransition) {
   348         /* We'll take care of this at the end of the transition */
   349         return;
   350     }
   351 
   352     if (SDL_IsShapedWindow(window)) {
   353         Cocoa_ResizeWindowShape(window);
   354     }
   355 
   356     ScheduleContextUpdates(_data);
   357 
   358     /* The window can move during a resize event, such as when maximizing
   359        or resizing from a corner */
   360     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, x, y);
   361     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, w, h);
   362 
   363     const BOOL zoomed = [nswindow isZoomed];
   364     if (!zoomed) {
   365         SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESTORED, 0, 0);
   366     } else if (zoomed) {
   367         SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MAXIMIZED, 0, 0);
   368     }
   369 }
   370 
   371 - (void)windowDidMiniaturize:(NSNotification *)aNotification
   372 {
   373     SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
   374 }
   375 
   376 - (void)windowDidDeminiaturize:(NSNotification *)aNotification
   377 {
   378     SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_RESTORED, 0, 0);
   379 }
   380 
   381 - (void)windowDidBecomeKey:(NSNotification *)aNotification
   382 {
   383     SDL_Window *window = _data->window;
   384     SDL_Mouse *mouse = SDL_GetMouse();
   385 
   386     /* We're going to get keyboard events, since we're key. */
   387     SDL_SetKeyboardFocus(window);
   388 
   389     /* If we just gained focus we need the updated mouse position */
   390     if (!mouse->relative_mode) {
   391         NSPoint point;
   392         int x, y;
   393 
   394         point = [_data->nswindow mouseLocationOutsideOfEventStream];
   395         x = (int)point.x;
   396         y = (int)(window->h - point.y);
   397 
   398         if (x >= 0 && x < window->w && y >= 0 && y < window->h) {
   399             SDL_SendMouseMotion(window, 0, 0, x, y);
   400         }
   401     }
   402 
   403     /* Check to see if someone updated the clipboard */
   404     Cocoa_CheckClipboardUpdate(_data->videodata);
   405 }
   406 
   407 - (void)windowDidResignKey:(NSNotification *)aNotification
   408 {
   409     /* Some other window will get mouse events, since we're not key. */
   410     if (SDL_GetMouseFocus() == _data->window) {
   411         SDL_SetMouseFocus(NULL);
   412     }
   413 
   414     /* Some other window will get keyboard events, since we're not key. */
   415     if (SDL_GetKeyboardFocus() == _data->window) {
   416         SDL_SetKeyboardFocus(NULL);
   417     }
   418 }
   419 
   420 - (void)windowWillEnterFullScreen:(NSNotification *)aNotification
   421 {
   422     SDL_Window *window = _data->window;
   423     NSWindow *nswindow = _data->nswindow;
   424 
   425     if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
   426         if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) {
   427             [nswindow setStyleMask:(NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask)];
   428         } else {
   429             [nswindow setStyleMask:NSBorderlessWindowMask];
   430         }
   431     }
   432 
   433     isFullscreen = YES;
   434     inFullscreenTransition = YES;
   435 }
   436 
   437 - (void)windowDidEnterFullScreen:(NSNotification *)aNotification
   438 {
   439     SDL_Window *window = _data->window;
   440 
   441     inFullscreenTransition = NO;
   442 
   443     if (pendingWindowOperation == PENDING_OPERATION_LEAVE_FULLSCREEN) {
   444         pendingWindowOperation = PENDING_OPERATION_NONE;
   445         [self setFullscreenState:NO];
   446     } else {
   447         pendingWindowOperation = PENDING_OPERATION_NONE;
   448         /* Force the size change event in case it was delivered earlier
   449            while the window was still animating into place.
   450          */
   451         window->w = 0;
   452         window->h = 0;
   453         [self windowDidResize:aNotification];
   454     }
   455 }
   456 
   457 - (void)windowWillExitFullScreen:(NSNotification *)aNotification
   458 {
   459     SDL_Window *window = _data->window;
   460     NSWindow *nswindow = _data->nswindow;
   461 
   462     if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
   463         Uint32 flags = window->flags;
   464         window->flags &= ~SDL_WINDOW_FULLSCREEN_DESKTOP;
   465         [nswindow setStyleMask:GetWindowStyle(window)];
   466         window->flags = flags;
   467     }
   468 
   469     isFullscreen = NO;
   470     inFullscreenTransition = YES;
   471 }
   472 
   473 - (void)windowDidExitFullScreen:(NSNotification *)aNotification
   474 {
   475     SDL_Window *window = _data->window;
   476     NSWindow *nswindow = _data->nswindow;
   477 
   478     inFullscreenTransition = NO;
   479 
   480     if (pendingWindowOperation == PENDING_OPERATION_ENTER_FULLSCREEN) {
   481         pendingWindowOperation = PENDING_OPERATION_NONE;
   482         [self setFullscreenState:YES];
   483     } else if (pendingWindowOperation == PENDING_OPERATION_MINIMIZE) {
   484         pendingWindowOperation = PENDING_OPERATION_NONE;
   485         [nswindow miniaturize:nil];
   486     } else {
   487         pendingWindowOperation = PENDING_OPERATION_NONE;
   488         /* Force the size change event in case it was delivered earlier
   489            while the window was still animating into place.
   490          */
   491         window->w = 0;
   492         window->h = 0;
   493         [self windowDidResize:aNotification];
   494     }
   495 }
   496 
   497 /* We'll respond to key events by doing nothing so we don't beep.
   498  * We could handle key messages here, but we lose some in the NSApp dispatch,
   499  * where they get converted to action messages, etc.
   500  */
   501 - (void)flagsChanged:(NSEvent *)theEvent
   502 {
   503     /*Cocoa_HandleKeyEvent(SDL_GetVideoDevice(), theEvent);*/
   504 }
   505 - (void)keyDown:(NSEvent *)theEvent
   506 {
   507     /*Cocoa_HandleKeyEvent(SDL_GetVideoDevice(), theEvent);*/
   508 }
   509 - (void)keyUp:(NSEvent *)theEvent
   510 {
   511     /*Cocoa_HandleKeyEvent(SDL_GetVideoDevice(), theEvent);*/
   512 }
   513 
   514 /* We'll respond to selectors by doing nothing so we don't beep.
   515  * The escape key gets converted to a "cancel" selector, etc.
   516  */
   517 - (void)doCommandBySelector:(SEL)aSelector
   518 {
   519     /*NSLog(@"doCommandBySelector: %@\n", NSStringFromSelector(aSelector));*/
   520 }
   521 
   522 - (void)mouseDown:(NSEvent *)theEvent
   523 {
   524     int button;
   525 
   526     switch ([theEvent buttonNumber]) {
   527     case 0:
   528         if (([theEvent modifierFlags] & NSControlKeyMask) &&
   529 		    GetHintCtrlClickEmulateRightClick()) {
   530             wasCtrlLeft = YES;
   531             button = SDL_BUTTON_RIGHT;
   532         } else {
   533             wasCtrlLeft = NO;
   534             button = SDL_BUTTON_LEFT;
   535         }
   536         break;
   537     case 1:
   538         button = SDL_BUTTON_RIGHT;
   539         break;
   540     case 2:
   541         button = SDL_BUTTON_MIDDLE;
   542         break;
   543     default:
   544         button = [theEvent buttonNumber] + 1;
   545         break;
   546     }
   547     SDL_SendMouseButton(_data->window, 0, SDL_PRESSED, button);
   548 }
   549 
   550 - (void)rightMouseDown:(NSEvent *)theEvent
   551 {
   552     [self mouseDown:theEvent];
   553 }
   554 
   555 - (void)otherMouseDown:(NSEvent *)theEvent
   556 {
   557     [self mouseDown:theEvent];
   558 }
   559 
   560 - (void)mouseUp:(NSEvent *)theEvent
   561 {
   562     int button;
   563 
   564     switch ([theEvent buttonNumber]) {
   565     case 0:
   566         if (wasCtrlLeft) {
   567             button = SDL_BUTTON_RIGHT;
   568             wasCtrlLeft = NO;
   569         } else {
   570             button = SDL_BUTTON_LEFT;
   571         }
   572         break;
   573     case 1:
   574         button = SDL_BUTTON_RIGHT;
   575         break;
   576     case 2:
   577         button = SDL_BUTTON_MIDDLE;
   578         break;
   579     default:
   580         button = [theEvent buttonNumber] + 1;
   581         break;
   582     }
   583     SDL_SendMouseButton(_data->window, 0, SDL_RELEASED, button);
   584 }
   585 
   586 - (void)rightMouseUp:(NSEvent *)theEvent
   587 {
   588     [self mouseUp:theEvent];
   589 }
   590 
   591 - (void)otherMouseUp:(NSEvent *)theEvent
   592 {
   593     [self mouseUp:theEvent];
   594 }
   595 
   596 - (void)mouseMoved:(NSEvent *)theEvent
   597 {
   598     SDL_Mouse *mouse = SDL_GetMouse();
   599     SDL_Window *window = _data->window;
   600     NSPoint point;
   601     int x, y;
   602 
   603     if (mouse->relative_mode) {
   604         return;
   605     }
   606 
   607     point = [theEvent locationInWindow];
   608     x = (int)point.x;
   609     y = (int)(window->h - point.y);
   610 
   611     if (x < 0 || x >= window->w || y < 0 || y >= window->h) {
   612         if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
   613             CGPoint cgpoint;
   614 
   615             if (x < 0) {
   616                 x = 0;
   617             } else if (x >= window->w) {
   618                 x = window->w - 1;
   619             }
   620             if (y < 0) {
   621                 y = 0;
   622             } else if (y >= window->h) {
   623                 y = window->h - 1;
   624             }
   625 
   626 #if !SDL_MAC_NO_SANDBOX
   627             /* When SDL_MAC_NO_SANDBOX is set, this is handled by
   628              * SDL_cocoamousetap.m.
   629              */
   630 
   631             cgpoint.x = window->x + x;
   632             cgpoint.y = window->y + y;
   633 
   634             /* According to the docs, this was deprecated in 10.6, but it's still
   635              * around. The substitute requires a CGEventSource, but I'm not entirely
   636              * sure how we'd procure the right one for this event.
   637              */
   638             CGSetLocalEventsSuppressionInterval(0.0);
   639             CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
   640             CGSetLocalEventsSuppressionInterval(0.25);
   641 #endif
   642         }
   643     }
   644     SDL_SendMouseMotion(window, 0, 0, x, y);
   645 }
   646 
   647 - (void)mouseDragged:(NSEvent *)theEvent
   648 {
   649     [self mouseMoved:theEvent];
   650 }
   651 
   652 - (void)rightMouseDragged:(NSEvent *)theEvent
   653 {
   654     [self mouseMoved:theEvent];
   655 }
   656 
   657 - (void)otherMouseDragged:(NSEvent *)theEvent
   658 {
   659     [self mouseMoved:theEvent];
   660 }
   661 
   662 - (void)scrollWheel:(NSEvent *)theEvent
   663 {
   664     Cocoa_HandleMouseWheel(_data->window, theEvent);
   665 }
   666 
   667 - (void)touchesBeganWithEvent:(NSEvent *) theEvent
   668 {
   669     [self handleTouches:COCOA_TOUCH_DOWN withEvent:theEvent];
   670 }
   671 
   672 - (void)touchesMovedWithEvent:(NSEvent *) theEvent
   673 {
   674     [self handleTouches:COCOA_TOUCH_MOVE withEvent:theEvent];
   675 }
   676 
   677 - (void)touchesEndedWithEvent:(NSEvent *) theEvent
   678 {
   679     [self handleTouches:COCOA_TOUCH_UP withEvent:theEvent];
   680 }
   681 
   682 - (void)touchesCancelledWithEvent:(NSEvent *) theEvent
   683 {
   684     [self handleTouches:COCOA_TOUCH_CANCELLED withEvent:theEvent];
   685 }
   686 
   687 - (void)handleTouches:(cocoaTouchType)type withEvent:(NSEvent *)event
   688 {
   689     NSSet *touches = 0;
   690     NSEnumerator *enumerator;
   691     NSTouch *touch;
   692 
   693     switch (type) {
   694         case COCOA_TOUCH_DOWN:
   695             touches = [event touchesMatchingPhase:NSTouchPhaseBegan inView:nil];
   696             break;
   697         case COCOA_TOUCH_UP:
   698         case COCOA_TOUCH_CANCELLED:
   699             touches = [event touchesMatchingPhase:NSTouchPhaseEnded inView:nil];
   700             break;
   701         case COCOA_TOUCH_MOVE:
   702             touches = [event touchesMatchingPhase:NSTouchPhaseMoved inView:nil];
   703             break;
   704     }
   705 
   706     enumerator = [touches objectEnumerator];
   707     touch = (NSTouch*)[enumerator nextObject];
   708     while (touch) {
   709         const SDL_TouchID touchId = (SDL_TouchID)(intptr_t)[touch device];
   710         if (!SDL_GetTouch(touchId)) {
   711             if (SDL_AddTouch(touchId, "") < 0) {
   712                 return;
   713             }
   714         }
   715 
   716         const SDL_FingerID fingerId = (SDL_FingerID)(intptr_t)[touch identity];
   717         float x = [touch normalizedPosition].x;
   718         float y = [touch normalizedPosition].y;
   719         /* Make the origin the upper left instead of the lower left */
   720         y = 1.0f - y;
   721 
   722         switch (type) {
   723         case COCOA_TOUCH_DOWN:
   724             SDL_SendTouch(touchId, fingerId, SDL_TRUE, x, y, 1.0f);
   725             break;
   726         case COCOA_TOUCH_UP:
   727         case COCOA_TOUCH_CANCELLED:
   728             SDL_SendTouch(touchId, fingerId, SDL_FALSE, x, y, 1.0f);
   729             break;
   730         case COCOA_TOUCH_MOVE:
   731             SDL_SendTouchMotion(touchId, fingerId, x, y, 1.0f);
   732             break;
   733         }
   734 
   735         touch = (NSTouch*)[enumerator nextObject];
   736     }
   737 }
   738 
   739 @end
   740 
   741 @interface SDLWindow : NSWindow
   742 /* These are needed for borderless/fullscreen windows */
   743 - (BOOL)canBecomeKeyWindow;
   744 - (BOOL)canBecomeMainWindow;
   745 @end
   746 
   747 @implementation SDLWindow
   748 - (BOOL)canBecomeKeyWindow
   749 {
   750     return YES;
   751 }
   752 
   753 - (BOOL)canBecomeMainWindow
   754 {
   755     return YES;
   756 }
   757 @end
   758 
   759 @interface SDLView : NSView
   760 
   761 /* The default implementation doesn't pass rightMouseDown to responder chain */
   762 - (void)rightMouseDown:(NSEvent *)theEvent;
   763 @end
   764 
   765 @implementation SDLView
   766 - (void)rightMouseDown:(NSEvent *)theEvent
   767 {
   768     [[self nextResponder] rightMouseDown:theEvent];
   769 }
   770 
   771 - (void)resetCursorRects
   772 {
   773     [super resetCursorRects];
   774     SDL_Mouse *mouse = SDL_GetMouse();
   775 
   776     if (mouse->cursor_shown && mouse->cur_cursor && !mouse->relative_mode) {
   777         [self addCursorRect:[self bounds]
   778                      cursor:mouse->cur_cursor->driverdata];
   779     } else {
   780         [self addCursorRect:[self bounds]
   781                      cursor:[NSCursor invisibleCursor]];
   782     }
   783 }
   784 @end
   785 
   786 static int
   787 SetupWindowData(_THIS, SDL_Window * window, NSWindow *nswindow, SDL_bool created)
   788 {
   789     NSAutoreleasePool *pool;
   790     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
   791     SDL_WindowData *data;
   792 
   793     /* Allocate the window data */
   794     data = (SDL_WindowData *) SDL_calloc(1, sizeof(*data));
   795     if (!data) {
   796         return SDL_OutOfMemory();
   797     }
   798     data->window = window;
   799     data->nswindow = nswindow;
   800     data->created = created;
   801     data->videodata = videodata;
   802     data->nscontexts = [[NSMutableArray alloc] init];
   803 
   804     pool = [[NSAutoreleasePool alloc] init];
   805 
   806     /* Create an event listener for the window */
   807     data->listener = [[Cocoa_WindowListener alloc] init];
   808 
   809     /* Fill in the SDL window with the window data */
   810     {
   811         NSRect rect = [nswindow contentRectForFrameRect:[nswindow frame]];
   812         ConvertNSRect(&rect);
   813         window->x = (int)rect.origin.x;
   814         window->y = (int)rect.origin.y;
   815         window->w = (int)rect.size.width;
   816         window->h = (int)rect.size.height;
   817     }
   818 
   819     /* Set up the listener after we create the view */
   820     [data->listener listen:data];
   821 
   822     if ([nswindow isVisible]) {
   823         window->flags |= SDL_WINDOW_SHOWN;
   824     } else {
   825         window->flags &= ~SDL_WINDOW_SHOWN;
   826     }
   827 
   828     {
   829         unsigned int style = [nswindow styleMask];
   830 
   831         if (style == NSBorderlessWindowMask) {
   832             window->flags |= SDL_WINDOW_BORDERLESS;
   833         } else {
   834             window->flags &= ~SDL_WINDOW_BORDERLESS;
   835         }
   836         if (style & NSResizableWindowMask) {
   837             window->flags |= SDL_WINDOW_RESIZABLE;
   838         } else {
   839             window->flags &= ~SDL_WINDOW_RESIZABLE;
   840         }
   841     }
   842 
   843     /* isZoomed always returns true if the window is not resizable */
   844     if ((window->flags & SDL_WINDOW_RESIZABLE) && [nswindow isZoomed]) {
   845         window->flags |= SDL_WINDOW_MAXIMIZED;
   846     } else {
   847         window->flags &= ~SDL_WINDOW_MAXIMIZED;
   848     }
   849 
   850     if ([nswindow isMiniaturized]) {
   851         window->flags |= SDL_WINDOW_MINIMIZED;
   852     } else {
   853         window->flags &= ~SDL_WINDOW_MINIMIZED;
   854     }
   855 
   856     if ([nswindow isKeyWindow]) {
   857         window->flags |= SDL_WINDOW_INPUT_FOCUS;
   858         SDL_SetKeyboardFocus(data->window);
   859     }
   860 
   861     /* Prevents the window's "window device" from being destroyed when it is
   862      * hidden. See http://www.mikeash.com/pyblog/nsopenglcontext-and-one-shot.html
   863      */
   864     [nswindow setOneShot:NO];
   865 
   866     /* All done! */
   867     [pool release];
   868     window->driverdata = data;
   869     return 0;
   870 }
   871 
   872 int
   873 Cocoa_CreateWindow(_THIS, SDL_Window * window)
   874 {
   875     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   876     NSWindow *nswindow;
   877     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
   878     NSRect rect;
   879     SDL_Rect bounds;
   880     unsigned int style;
   881 
   882     Cocoa_GetDisplayBounds(_this, display, &bounds);
   883     rect.origin.x = window->x;
   884     rect.origin.y = window->y;
   885     rect.size.width = window->w;
   886     rect.size.height = window->h;
   887     ConvertNSRect(&rect);
   888 
   889     style = GetWindowStyle(window);
   890 
   891     /* Figure out which screen to place this window */
   892     NSArray *screens = [NSScreen screens];
   893     NSScreen *screen = nil;
   894     NSScreen *candidate;
   895     int i, count = [screens count];
   896     for (i = 0; i < count; ++i) {
   897         candidate = [screens objectAtIndex:i];
   898         NSRect screenRect = [candidate frame];
   899         if (rect.origin.x >= screenRect.origin.x &&
   900             rect.origin.x < screenRect.origin.x + screenRect.size.width &&
   901             rect.origin.y >= screenRect.origin.y &&
   902             rect.origin.y < screenRect.origin.y + screenRect.size.height) {
   903             screen = candidate;
   904             rect.origin.x -= screenRect.origin.x;
   905             rect.origin.y -= screenRect.origin.y;
   906         }
   907     }
   908 
   909     @try {
   910         nswindow = [[SDLWindow alloc] initWithContentRect:rect styleMask:style backing:NSBackingStoreBuffered defer:NO screen:screen];
   911     }
   912     @catch (NSException *e) {
   913         SDL_SetError("%s", [[e reason] UTF8String]);
   914         [pool release];
   915         return -1;
   916     }
   917     [nswindow setBackgroundColor:[NSColor blackColor]];
   918 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
   919     if ([nswindow respondsToSelector:@selector(setCollectionBehavior:)]) {
   920         [nswindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
   921     }
   922 #endif
   923 
   924     /* Create a default view for this window */
   925     rect = [nswindow contentRectForFrameRect:[nswindow frame]];
   926     NSView *contentView = [[SDLView alloc] initWithFrame:rect];
   927 
   928     if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
   929         if ([contentView respondsToSelector:@selector(setWantsBestResolutionOpenGLSurface:)]) {
   930             [contentView setWantsBestResolutionOpenGLSurface:YES];
   931         }
   932     }
   933 
   934     [nswindow setContentView: contentView];
   935     [contentView release];
   936 
   937     [pool release];
   938 
   939     if (SetupWindowData(_this, window, nswindow, SDL_TRUE) < 0) {
   940         [nswindow release];
   941         return -1;
   942     }
   943     return 0;
   944 }
   945 
   946 int
   947 Cocoa_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
   948 {
   949     NSAutoreleasePool *pool;
   950     NSWindow *nswindow = (NSWindow *) data;
   951     NSString *title;
   952 
   953     pool = [[NSAutoreleasePool alloc] init];
   954 
   955     /* Query the title from the existing window */
   956     title = [nswindow title];
   957     if (title) {
   958         window->title = SDL_strdup([title UTF8String]);
   959     }
   960 
   961     [pool release];
   962 
   963     return SetupWindowData(_this, window, nswindow, SDL_FALSE);
   964 }
   965 
   966 void
   967 Cocoa_SetWindowTitle(_THIS, SDL_Window * window)
   968 {
   969     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   970     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
   971     NSString *string;
   972 
   973     if(window->title) {
   974         string = [[NSString alloc] initWithUTF8String:window->title];
   975     } else {
   976         string = [[NSString alloc] init];
   977     }
   978     [nswindow setTitle:string];
   979     [string release];
   980 
   981     [pool release];
   982 }
   983 
   984 void
   985 Cocoa_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
   986 {
   987     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   988     NSImage *nsimage = Cocoa_CreateImage(icon);
   989 
   990     if (nsimage) {
   991         [NSApp setApplicationIconImage:nsimage];
   992     }
   993 
   994     [pool release];
   995 }
   996 
   997 void
   998 Cocoa_SetWindowPosition(_THIS, SDL_Window * window)
   999 {
  1000     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  1001     SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
  1002     NSWindow *nswindow = windata->nswindow;
  1003     NSRect rect;
  1004     Uint32 moveHack;
  1005 
  1006     rect.origin.x = window->x;
  1007     rect.origin.y = window->y;
  1008     rect.size.width = window->w;
  1009     rect.size.height = window->h;
  1010     ConvertNSRect(&rect);
  1011 
  1012     moveHack = s_moveHack;
  1013     s_moveHack = 0;
  1014     [nswindow setFrameOrigin:rect.origin];
  1015     s_moveHack = moveHack;
  1016 
  1017     ScheduleContextUpdates(windata);
  1018 
  1019     [pool release];
  1020 }
  1021 
  1022 void
  1023 Cocoa_SetWindowSize(_THIS, SDL_Window * window)
  1024 {
  1025     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  1026     SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
  1027     NSWindow *nswindow = windata->nswindow;
  1028     NSSize size;
  1029 
  1030     size.width = window->w;
  1031     size.height = window->h;
  1032     [nswindow setContentSize:size];
  1033 
  1034     ScheduleContextUpdates(windata);
  1035 
  1036     [pool release];
  1037 }
  1038 
  1039 void
  1040 Cocoa_SetWindowMinimumSize(_THIS, SDL_Window * window)
  1041 {
  1042     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  1043     SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
  1044 
  1045     NSSize minSize;
  1046     minSize.width = window->min_w;
  1047     minSize.height = window->min_h;
  1048 
  1049     [windata->nswindow setContentMinSize:minSize];
  1050 
  1051     [pool release];
  1052 }
  1053 
  1054 void
  1055 Cocoa_SetWindowMaximumSize(_THIS, SDL_Window * window)
  1056 {
  1057     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  1058     SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
  1059 
  1060     NSSize maxSize;
  1061     maxSize.width = window->max_w;
  1062     maxSize.height = window->max_h;
  1063 
  1064     [windata->nswindow setContentMaxSize:maxSize];
  1065 
  1066     [pool release];
  1067 }
  1068 
  1069 void
  1070 Cocoa_ShowWindow(_THIS, SDL_Window * window)
  1071 {
  1072     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  1073     SDL_WindowData *windowData = ((SDL_WindowData *) window->driverdata);
  1074     NSWindow *nswindow = windowData->nswindow;
  1075 
  1076     if (![nswindow isMiniaturized]) {
  1077         [windowData->listener pauseVisibleObservation];
  1078         [nswindow makeKeyAndOrderFront:nil];
  1079         [windowData->listener resumeVisibleObservation];
  1080     }
  1081     [pool release];
  1082 }
  1083 
  1084 void
  1085 Cocoa_HideWindow(_THIS, SDL_Window * window)
  1086 {
  1087     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  1088     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
  1089 
  1090     [nswindow orderOut:nil];
  1091     [pool release];
  1092 }
  1093 
  1094 void
  1095 Cocoa_RaiseWindow(_THIS, SDL_Window * window)
  1096 {
  1097     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  1098     SDL_WindowData *windowData = ((SDL_WindowData *) window->driverdata);
  1099     NSWindow *nswindow = windowData->nswindow;
  1100 
  1101     /* makeKeyAndOrderFront: has the side-effect of deminiaturizing and showing
  1102        a minimized or hidden window, so check for that before showing it.
  1103      */
  1104     [windowData->listener pauseVisibleObservation];
  1105     if (![nswindow isMiniaturized] && [nswindow isVisible]) {
  1106         [nswindow makeKeyAndOrderFront:nil];
  1107     }
  1108     [windowData->listener resumeVisibleObservation];
  1109 
  1110     [pool release];
  1111 }
  1112 
  1113 void
  1114 Cocoa_MaximizeWindow(_THIS, SDL_Window * window)
  1115 {
  1116     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  1117     SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
  1118     NSWindow *nswindow = windata->nswindow;
  1119 
  1120     [nswindow zoom:nil];
  1121 
  1122     ScheduleContextUpdates(windata);
  1123 
  1124     [pool release];
  1125 }
  1126 
  1127 void
  1128 Cocoa_MinimizeWindow(_THIS, SDL_Window * window)
  1129 {
  1130     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  1131     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1132     NSWindow *nswindow = data->nswindow;
  1133 
  1134     if ([data->listener isInFullscreenTransition]) {
  1135         [data->listener addPendingWindowOperation:PENDING_OPERATION_MINIMIZE];
  1136     } else {
  1137         [nswindow miniaturize:nil];
  1138     }
  1139     [pool release];
  1140 }
  1141 
  1142 void
  1143 Cocoa_RestoreWindow(_THIS, SDL_Window * window)
  1144 {
  1145     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  1146     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
  1147 
  1148     if ([nswindow isMiniaturized]) {
  1149         [nswindow deminiaturize:nil];
  1150     } else if ((window->flags & SDL_WINDOW_RESIZABLE) && [nswindow isZoomed]) {
  1151         [nswindow zoom:nil];
  1152     }
  1153     [pool release];
  1154 }
  1155 
  1156 static NSWindow *
  1157 Cocoa_RebuildWindow(SDL_WindowData * data, NSWindow * nswindow, unsigned style)
  1158 {
  1159     if (!data->created) {
  1160         /* Don't mess with other people's windows... */
  1161         return nswindow;
  1162     }
  1163 
  1164     [data->listener close];
  1165     data->nswindow = [[SDLWindow alloc] initWithContentRect:[[nswindow contentView] frame] styleMask:style backing:NSBackingStoreBuffered defer:NO screen:[nswindow screen]];
  1166     [data->nswindow setContentView:[nswindow contentView]];
  1167     /* See comment in SetupWindowData. */
  1168     [data->nswindow setOneShot:NO];
  1169     [data->listener listen:data];
  1170 
  1171     [nswindow close];
  1172 
  1173     return data->nswindow;
  1174 }
  1175 
  1176 void
  1177 Cocoa_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
  1178 {
  1179     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  1180     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
  1181     if ([nswindow respondsToSelector:@selector(setStyleMask:)]) {
  1182         [nswindow setStyleMask:GetWindowStyle(window)];
  1183         if (bordered) {
  1184             Cocoa_SetWindowTitle(_this, window);  /* this got blanked out. */
  1185         }
  1186     }
  1187     [pool release];
  1188 }
  1189 
  1190 
  1191 static void
  1192 Cocoa_SetWindowFullscreen_OldStyle(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
  1193 {
  1194     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1195     NSWindow *nswindow = data->nswindow;
  1196     NSRect rect;
  1197 
  1198     /* The view responder chain gets messed with during setStyleMask */
  1199     if ([[nswindow contentView] nextResponder] == data->listener) {
  1200         [[nswindow contentView] setNextResponder:nil];
  1201     }
  1202 
  1203     if (fullscreen) {
  1204         SDL_Rect bounds;
  1205 
  1206         Cocoa_GetDisplayBounds(_this, display, &bounds);
  1207         rect.origin.x = bounds.x;
  1208         rect.origin.y = bounds.y;
  1209         rect.size.width = bounds.w;
  1210         rect.size.height = bounds.h;
  1211         ConvertNSRect(&rect);
  1212 
  1213         /* Hack to fix origin on Mac OS X 10.4 */
  1214         NSRect screenRect = [[nswindow screen] frame];
  1215         if (screenRect.size.height >= 1.0f) {
  1216             rect.origin.y += (screenRect.size.height - rect.size.height);
  1217         }
  1218 
  1219         if ([nswindow respondsToSelector: @selector(setStyleMask:)]) {
  1220             [nswindow performSelector: @selector(setStyleMask:) withObject: (id)NSBorderlessWindowMask];
  1221         } else {
  1222             nswindow = Cocoa_RebuildWindow(data, nswindow, NSBorderlessWindowMask);
  1223         }
  1224     } else {
  1225         rect.origin.x = window->windowed.x;
  1226         rect.origin.y = window->windowed.y;
  1227         rect.size.width = window->windowed.w;
  1228         rect.size.height = window->windowed.h;
  1229         ConvertNSRect(&rect);
  1230 
  1231         if ([nswindow respondsToSelector: @selector(setStyleMask:)]) {
  1232             [nswindow performSelector: @selector(setStyleMask:) withObject: (id)(uintptr_t)GetWindowStyle(window)];
  1233         } else {
  1234             nswindow = Cocoa_RebuildWindow(data, nswindow, GetWindowStyle(window));
  1235         }
  1236     }
  1237 
  1238     /* The view responder chain gets messed with during setStyleMask */
  1239     if ([[nswindow contentView] nextResponder] != data->listener) {
  1240         [[nswindow contentView] setNextResponder:data->listener];
  1241     }
  1242 
  1243     s_moveHack = 0;
  1244     [nswindow setContentSize:rect.size];
  1245     [nswindow setFrameOrigin:rect.origin];
  1246     s_moveHack = SDL_GetTicks();
  1247 
  1248     /* When the window style changes the title is cleared */
  1249     if (!fullscreen) {
  1250         Cocoa_SetWindowTitle(_this, window);
  1251     }
  1252 
  1253     if (SDL_ShouldAllowTopmost() && fullscreen) {
  1254         /* OpenGL is rendering to the window, so make it visible! */
  1255         [nswindow setLevel:CGShieldingWindowLevel()];
  1256     } else {
  1257         [nswindow setLevel:kCGNormalWindowLevel];
  1258     }
  1259 
  1260     if ([nswindow isVisible] || fullscreen) {
  1261         [data->listener pauseVisibleObservation];
  1262         [nswindow makeKeyAndOrderFront:nil];
  1263         [data->listener resumeVisibleObservation];
  1264     }
  1265 
  1266     ScheduleContextUpdates(data);
  1267 }
  1268 
  1269 void
  1270 Cocoa_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
  1271 {
  1272     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  1273     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1274 
  1275     if (![data->listener setFullscreenState:(fullscreen ? YES : NO)]) {
  1276         Cocoa_SetWindowFullscreen_OldStyle(_this, window, display, fullscreen);
  1277     }
  1278 
  1279     [pool release];
  1280 }
  1281 
  1282 int
  1283 Cocoa_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
  1284 {
  1285     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  1286     CGDirectDisplayID display_id = ((SDL_DisplayData *)display->driverdata)->display;
  1287     const uint32_t tableSize = 256;
  1288     CGGammaValue redTable[tableSize];
  1289     CGGammaValue greenTable[tableSize];
  1290     CGGammaValue blueTable[tableSize];
  1291     uint32_t i;
  1292     float inv65535 = 1.0f / 65535.0f;
  1293 
  1294     /* Extract gamma values into separate tables, convert to floats between 0.0 and 1.0 */
  1295     for (i = 0; i < 256; i++) {
  1296         redTable[i] = ramp[0*256+i] * inv65535;
  1297         greenTable[i] = ramp[1*256+i] * inv65535;
  1298         blueTable[i] = ramp[2*256+i] * inv65535;
  1299     }
  1300 
  1301     if (CGSetDisplayTransferByTable(display_id, tableSize,
  1302                                     redTable, greenTable, blueTable) != CGDisplayNoErr) {
  1303         return SDL_SetError("CGSetDisplayTransferByTable()");
  1304     }
  1305     return 0;
  1306 }
  1307 
  1308 int
  1309 Cocoa_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp)
  1310 {
  1311     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  1312     CGDirectDisplayID display_id = ((SDL_DisplayData *)display->driverdata)->display;
  1313     const uint32_t tableSize = 256;
  1314     CGGammaValue redTable[tableSize];
  1315     CGGammaValue greenTable[tableSize];
  1316     CGGammaValue blueTable[tableSize];
  1317     uint32_t i, tableCopied;
  1318 
  1319     if (CGGetDisplayTransferByTable(display_id, tableSize,
  1320                                     redTable, greenTable, blueTable, &tableCopied) != CGDisplayNoErr) {
  1321         return SDL_SetError("CGGetDisplayTransferByTable()");
  1322     }
  1323 
  1324     for (i = 0; i < tableCopied; i++) {
  1325         ramp[0*256+i] = (Uint16)(redTable[i] * 65535.0f);
  1326         ramp[1*256+i] = (Uint16)(greenTable[i] * 65535.0f);
  1327         ramp[2*256+i] = (Uint16)(blueTable[i] * 65535.0f);
  1328     }
  1329     return 0;
  1330 }
  1331 
  1332 void
  1333 Cocoa_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
  1334 {
  1335     /* Move the cursor to the nearest point in the window */
  1336     if (grabbed) {
  1337         int x, y;
  1338         CGPoint cgpoint;
  1339 
  1340         SDL_GetMouseState(&x, &y);
  1341         cgpoint.x = window->x + x;
  1342         cgpoint.y = window->y + y;
  1343         CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
  1344     }
  1345 
  1346     if ( window->flags & SDL_WINDOW_FULLSCREEN ) {
  1347         SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1348 
  1349         if (SDL_ShouldAllowTopmost() && (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
  1350             /* OpenGL is rendering to the window, so make it visible! */
  1351             [data->nswindow setLevel:CGShieldingWindowLevel()];
  1352         } else {
  1353             [data->nswindow setLevel:kCGNormalWindowLevel];
  1354         }
  1355     }
  1356 }
  1357 
  1358 void
  1359 Cocoa_DestroyWindow(_THIS, SDL_Window * window)
  1360 {
  1361     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  1362     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1363 
  1364     if (data) {
  1365         [data->listener close];
  1366         [data->listener release];
  1367         if (data->created) {
  1368             [data->nswindow close];
  1369         }
  1370 
  1371         NSArray *contexts = [[data->nscontexts copy] autorelease];
  1372         for (SDLOpenGLContext *context in contexts) {
  1373             /* Calling setWindow:NULL causes the context to remove itself from the context list. */            
  1374             [context setWindow:NULL];
  1375         }
  1376         [data->nscontexts release];
  1377 
  1378         SDL_free(data);
  1379     }
  1380     [pool release];
  1381 }
  1382 
  1383 SDL_bool
  1384 Cocoa_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
  1385 {
  1386     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
  1387 
  1388     if (info->version.major <= SDL_MAJOR_VERSION) {
  1389         info->subsystem = SDL_SYSWM_COCOA;
  1390         info->info.cocoa.window = nswindow;
  1391         return SDL_TRUE;
  1392     } else {
  1393         SDL_SetError("Application not compiled with SDL %d.%d\n",
  1394                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
  1395         return SDL_FALSE;
  1396     }
  1397 }
  1398 
  1399 #endif /* SDL_VIDEO_DRIVER_COCOA */
  1400 
  1401 /* vi: set ts=4 sw=4 expandtab: */