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