src/video/cocoa/SDL_cocoawindow.m
author Jørgen P. Tjernø <jorgen@valvesoftware.com>
Tue, 14 Jan 2014 17:33:24 -0800
changeset 8106 4e3e41b2cbfb
parent 8093 b43765095a6f
child 8111 426e78ce52e4
permissions -rw-r--r--
Mac: Trigger SDL_FINGERUP for all touches.

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