src/video/cocoa/SDL_cocoawindow.m
author Sam Lantinga <slouken@libsdl.org>
Thu, 14 Nov 2013 22:26:49 -0800
changeset 7990 a05a48e493c0
parent 7970 6dc794be47aa
child 8083 3782a12331d6
permissions -rw-r--r--
Fixed bug 2240 - On OS/X after calling SDL_SetWindowBordered right mouse clicks no longer register

philhassey

On OS/X after calling SDL_SetWindowBordered right mouse clicks no longer register.

Steps to Reproduce:

1. Open a windowed window on OS/X. (With the border on.)

2. e.button.button will give values 1,2,3 depending on which mouse button I click.

3. Call SDL_SetWindowBordered to disable the border.

4. e.button.button will only give values 1,2. 3 (right mouse button) stops coming through.

Expected result:

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