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