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