src/video/cocoa/SDL_cocoawindow.m
author Jørgen P. Tjernø <jorgen@valvesoftware.com>
Wed, 26 Feb 2014 11:35:02 -0800
changeset 8261 841b66e4397a
parent 8260 028ed8da2524
child 8284 a2910aa6c056
permissions -rw-r--r--
Mac: Redo cursor warp handling.

This fixes bugs related to getting unnaturally large xrel/yrel for
SDL_MOUSEMOTION after warps and enabling / disabling relative mode.

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