src/video/cocoa/SDL_cocoawindow.m
author Ryan C. Gordon <icculus@icculus.org>
Tue, 29 Dec 2015 01:09:58 -0500
changeset 9983 bbe9ef8c2ecb
parent 9973 4d8a561cf978
child 9998 f67cf37e9cd4
permissions -rw-r--r--
Mac: don't ignore mouse clicks on the top pixel of a window (thanks, Joshua!).

Fixes Bugzilla #3190.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2015 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 "../../events/SDL_dropevents_c.h"
    38 #include "SDL_cocoavideo.h"
    39 #include "SDL_cocoashape.h"
    40 #include "SDL_cocoamouse.h"
    41 #include "SDL_cocoaopengl.h"
    42 #include "SDL_assert.h"
    43 
    44 /* #define DEBUG_COCOAWINDOW */
    45 
    46 #ifdef DEBUG_COCOAWINDOW
    47 #define DLog(fmt, ...) printf("%s: " fmt "\n", __func__, ##__VA_ARGS__)
    48 #else
    49 #define DLog(...) do { } while (0)
    50 #endif
    51 
    52 
    53 #define FULLSCREEN_MASK (SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_FULLSCREEN)
    54 
    55 
    56 @interface SDLWindow : NSWindow <NSDraggingDestination>
    57 /* These are needed for borderless/fullscreen windows */
    58 - (BOOL)canBecomeKeyWindow;
    59 - (BOOL)canBecomeMainWindow;
    60 - (void)sendEvent:(NSEvent *)event;
    61 - (void)doCommandBySelector:(SEL)aSelector;
    62 
    63 /* Handle drag-and-drop of files onto the SDL window. */
    64 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender;
    65 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender;
    66 - (BOOL)wantsPeriodicDraggingUpdates;
    67 @end
    68 
    69 @implementation SDLWindow
    70 
    71 - (BOOL)canBecomeKeyWindow
    72 {
    73     return YES;
    74 }
    75 
    76 - (BOOL)canBecomeMainWindow
    77 {
    78     return YES;
    79 }
    80 
    81 - (void)sendEvent:(NSEvent *)event
    82 {
    83   [super sendEvent:event];
    84 
    85   if ([event type] != NSLeftMouseUp) {
    86       return;
    87   }
    88 
    89   id delegate = [self delegate];
    90   if (![delegate isKindOfClass:[Cocoa_WindowListener class]]) {
    91       return;
    92   }
    93 
    94   if ([delegate isMoving]) {
    95       [delegate windowDidFinishMoving];
    96   }
    97 }
    98 
    99 /* We'll respond to selectors by doing nothing so we don't beep.
   100  * The escape key gets converted to a "cancel" selector, etc.
   101  */
   102 - (void)doCommandBySelector:(SEL)aSelector
   103 {
   104     /*NSLog(@"doCommandBySelector: %@\n", NSStringFromSelector(aSelector));*/
   105 }
   106 
   107 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
   108 {
   109     if (([sender draggingSourceOperationMask] & NSDragOperationGeneric) == NSDragOperationGeneric) {
   110         return NSDragOperationGeneric;
   111     }
   112 
   113     return NSDragOperationNone; /* no idea what to do with this, reject it. */
   114 }
   115 
   116 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
   117 { @autoreleasepool
   118 {
   119     NSPasteboard *pasteboard = [sender draggingPasteboard];
   120     NSArray *types = [NSArray arrayWithObject:NSFilenamesPboardType];
   121     NSString *desiredType = [pasteboard availableTypeFromArray:types];
   122     if (desiredType == nil) {
   123         return NO;  /* can't accept anything that's being dropped here. */
   124     }
   125 
   126     NSData *data = [pasteboard dataForType:desiredType];
   127     if (data == nil) {
   128         return NO;
   129     }
   130 
   131     SDL_assert([desiredType isEqualToString:NSFilenamesPboardType]);
   132     NSArray *array = [pasteboard propertyListForType:@"NSFilenamesPboardType"];
   133 
   134     for (NSString *path in array) {
   135         NSURL *fileURL = [[NSURL fileURLWithPath:path] autorelease];
   136         NSNumber *isAlias = nil;
   137 
   138         /* Functionality for resolving URL aliases was added with OS X 10.6. */
   139         if ([fileURL respondsToSelector:@selector(getResourceValue:forKey:error:)]) {
   140             [fileURL getResourceValue:&isAlias forKey:NSURLIsAliasFileKey error:nil];
   141         }
   142 
   143         /* If the URL is an alias, resolve it. */
   144         if ([isAlias boolValue]) {
   145             NSURLBookmarkResolutionOptions opts = NSURLBookmarkResolutionWithoutMounting | NSURLBookmarkResolutionWithoutUI;
   146             NSData *bookmark = [NSURL bookmarkDataWithContentsOfURL:fileURL error:nil];
   147             if (bookmark != nil) {
   148                 NSURL *resolvedURL = [NSURL URLByResolvingBookmarkData:bookmark
   149                                                                options:opts
   150                                                          relativeToURL:nil
   151                                                    bookmarkDataIsStale:nil
   152                                                                  error:nil];
   153 
   154                 if (resolvedURL != nil) {
   155                     fileURL = resolvedURL;
   156                 }
   157             }
   158         }
   159 
   160         if (!SDL_SendDropFile([[fileURL path] UTF8String])) {
   161             return NO;
   162         }
   163     }
   164 
   165     return YES;
   166 }}
   167 
   168 - (BOOL)wantsPeriodicDraggingUpdates
   169 {
   170     return NO;
   171 }
   172 
   173 @end
   174 
   175 
   176 static Uint32 s_moveHack;
   177 
   178 static void ConvertNSRect(NSScreen *screen, BOOL fullscreen, NSRect *r)
   179 {
   180     r->origin.y = CGDisplayPixelsHigh(kCGDirectMainDisplay) - r->origin.y - r->size.height;
   181 }
   182 
   183 static void
   184 ScheduleContextUpdates(SDL_WindowData *data)
   185 {
   186     NSOpenGLContext *currentContext = [NSOpenGLContext currentContext];
   187     NSMutableArray *contexts = data->nscontexts;
   188     @synchronized (contexts) {
   189         for (SDLOpenGLContext *context in contexts) {
   190             if (context == currentContext) {
   191                 [context update];
   192             } else {
   193                 [context scheduleUpdate];
   194             }
   195         }
   196     }
   197 }
   198 
   199 static int
   200 GetHintCtrlClickEmulateRightClick()
   201 {
   202 	const char *hint = SDL_GetHint( SDL_HINT_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK );
   203 	return hint != NULL && *hint != '0';
   204 }
   205 
   206 static unsigned int
   207 GetWindowStyle(SDL_Window * window)
   208 {
   209     unsigned int style;
   210 
   211     if (window->flags & SDL_WINDOW_FULLSCREEN) {
   212         style = NSBorderlessWindowMask;
   213     } else {
   214         if (window->flags & SDL_WINDOW_BORDERLESS) {
   215             style = NSBorderlessWindowMask;
   216         } else {
   217             style = (NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask);
   218         }
   219         if (window->flags & SDL_WINDOW_RESIZABLE) {
   220             style |= NSResizableWindowMask;
   221         }
   222     }
   223     return style;
   224 }
   225 
   226 static SDL_bool
   227 SetWindowStyle(SDL_Window * window, unsigned int style)
   228 {
   229     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   230     NSWindow *nswindow = data->nswindow;
   231 
   232     if (![nswindow respondsToSelector: @selector(setStyleMask:)]) {
   233         return SDL_FALSE;
   234     }
   235 
   236     /* The view responder chain gets messed with during setStyleMask */
   237     if ([[nswindow contentView] nextResponder] == data->listener) {
   238         [[nswindow contentView] setNextResponder:nil];
   239     }
   240 
   241     [nswindow performSelector: @selector(setStyleMask:) withObject: (id)(uintptr_t)style];
   242 
   243     /* The view responder chain gets messed with during setStyleMask */
   244     if ([[nswindow contentView] nextResponder] != data->listener) {
   245         [[nswindow contentView] setNextResponder:data->listener];
   246     }
   247 
   248     return SDL_TRUE;
   249 }
   250 
   251 
   252 @implementation Cocoa_WindowListener
   253 
   254 - (void)listen:(SDL_WindowData *)data
   255 {
   256     NSNotificationCenter *center;
   257     NSWindow *window = data->nswindow;
   258     NSView *view = [window contentView];
   259 
   260     _data = data;
   261     observingVisible = YES;
   262     wasCtrlLeft = NO;
   263     wasVisible = [window isVisible];
   264     isFullscreenSpace = NO;
   265     inFullscreenTransition = NO;
   266     pendingWindowOperation = PENDING_OPERATION_NONE;
   267     isMoving = NO;
   268     isDragAreaRunning = NO;
   269 
   270     center = [NSNotificationCenter defaultCenter];
   271 
   272     if ([window delegate] != nil) {
   273         [center addObserver:self selector:@selector(windowDidExpose:) name:NSWindowDidExposeNotification object:window];
   274         [center addObserver:self selector:@selector(windowDidMove:) name:NSWindowDidMoveNotification object:window];
   275         [center addObserver:self selector:@selector(windowDidResize:) name:NSWindowDidResizeNotification object:window];
   276         [center addObserver:self selector:@selector(windowDidMiniaturize:) name:NSWindowDidMiniaturizeNotification object:window];
   277         [center addObserver:self selector:@selector(windowDidDeminiaturize:) name:NSWindowDidDeminiaturizeNotification object:window];
   278         [center addObserver:self selector:@selector(windowDidBecomeKey:) name:NSWindowDidBecomeKeyNotification object:window];
   279         [center addObserver:self selector:@selector(windowDidResignKey:) name:NSWindowDidResignKeyNotification object:window];
   280         [center addObserver:self selector:@selector(windowDidChangeBackingProperties:) name:NSWindowDidChangeBackingPropertiesNotification object:window];
   281         [center addObserver:self selector:@selector(windowWillEnterFullScreen:) name:NSWindowWillEnterFullScreenNotification object:window];
   282         [center addObserver:self selector:@selector(windowDidEnterFullScreen:) name:NSWindowDidEnterFullScreenNotification object:window];
   283         [center addObserver:self selector:@selector(windowWillExitFullScreen:) name:NSWindowWillExitFullScreenNotification object:window];
   284         [center addObserver:self selector:@selector(windowDidExitFullScreen:) name:NSWindowDidExitFullScreenNotification object:window];
   285         [center addObserver:self selector:@selector(windowDidFailToEnterFullScreen:) name:@"NSWindowDidFailToEnterFullScreenNotification" object:window];
   286         [center addObserver:self selector:@selector(windowDidFailToExitFullScreen:) name:@"NSWindowDidFailToExitFullScreenNotification" object:window];
   287     } else {
   288         [window setDelegate:self];
   289     }
   290 
   291     /* Haven't found a delegate / notification that triggers when the window is
   292      * ordered out (is not visible any more). You can be ordered out without
   293      * minimizing, so DidMiniaturize doesn't work. (e.g. -[NSWindow orderOut:])
   294      */
   295     [window addObserver:self
   296              forKeyPath:@"visible"
   297                 options:NSKeyValueObservingOptionNew
   298                 context:NULL];
   299 
   300     [window setNextResponder:self];
   301     [window setAcceptsMouseMovedEvents:YES];
   302 
   303     [view setNextResponder:self];
   304 
   305     if ([view respondsToSelector:@selector(setAcceptsTouchEvents:)]) {
   306         [view setAcceptsTouchEvents:YES];
   307     }
   308 }
   309 
   310 - (void)observeValueForKeyPath:(NSString *)keyPath
   311                       ofObject:(id)object
   312                         change:(NSDictionary *)change
   313                        context:(void *)context
   314 {
   315     if (!observingVisible) {
   316         return;
   317     }
   318 
   319     if (object == _data->nswindow && [keyPath isEqualToString:@"visible"]) {
   320         int newVisibility = [[change objectForKey:@"new"] intValue];
   321         if (newVisibility) {
   322             SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
   323         } else {
   324             SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
   325         }
   326     }
   327 }
   328 
   329 -(void) pauseVisibleObservation
   330 {
   331     observingVisible = NO;
   332     wasVisible = [_data->nswindow isVisible];
   333 }
   334 
   335 -(void) resumeVisibleObservation
   336 {
   337     BOOL isVisible = [_data->nswindow isVisible];
   338     observingVisible = YES;
   339     if (wasVisible != isVisible) {
   340         if (isVisible) {
   341             SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
   342         } else {
   343             SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
   344         }
   345 
   346         wasVisible = isVisible;
   347     }
   348 }
   349 
   350 -(BOOL) setFullscreenSpace:(BOOL) state
   351 {
   352     SDL_Window *window = _data->window;
   353     NSWindow *nswindow = _data->nswindow;
   354     SDL_VideoData *videodata = ((SDL_WindowData *) window->driverdata)->videodata;
   355 
   356     if (!videodata->allow_spaces) {
   357         return NO;  /* Spaces are forcibly disabled. */
   358     } else if (state && ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP)) {
   359         return NO;  /* we only allow you to make a Space on FULLSCREEN_DESKTOP windows. */
   360     } else if (!state && ((window->last_fullscreen_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP)) {
   361         return NO;  /* we only handle leaving the Space on windows that were previously FULLSCREEN_DESKTOP. */
   362     } else if (state == isFullscreenSpace) {
   363         return YES;  /* already there. */
   364     }
   365 
   366     if (inFullscreenTransition) {
   367         if (state) {
   368             [self addPendingWindowOperation:PENDING_OPERATION_ENTER_FULLSCREEN];
   369         } else {
   370             [self addPendingWindowOperation:PENDING_OPERATION_LEAVE_FULLSCREEN];
   371         }
   372         return YES;
   373     }
   374     inFullscreenTransition = YES;
   375 
   376     /* you need to be FullScreenPrimary, or toggleFullScreen doesn't work. Unset it again in windowDidExitFullScreen. */
   377     [nswindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
   378     [nswindow performSelectorOnMainThread: @selector(toggleFullScreen:) withObject:nswindow waitUntilDone:NO];
   379     return YES;
   380 }
   381 
   382 -(BOOL) isInFullscreenSpace
   383 {
   384     return isFullscreenSpace;
   385 }
   386 
   387 -(BOOL) isInFullscreenSpaceTransition
   388 {
   389     return inFullscreenTransition;
   390 }
   391 
   392 -(void) addPendingWindowOperation:(PendingWindowOperation) operation
   393 {
   394     pendingWindowOperation = operation;
   395 }
   396 
   397 - (void)close
   398 {
   399     NSNotificationCenter *center;
   400     NSWindow *window = _data->nswindow;
   401     NSView *view = [window contentView];
   402 
   403     center = [NSNotificationCenter defaultCenter];
   404 
   405     if ([window delegate] != self) {
   406         [center removeObserver:self name:NSWindowDidExposeNotification object:window];
   407         [center removeObserver:self name:NSWindowDidMoveNotification object:window];
   408         [center removeObserver:self name:NSWindowDidResizeNotification object:window];
   409         [center removeObserver:self name:NSWindowDidMiniaturizeNotification object:window];
   410         [center removeObserver:self name:NSWindowDidDeminiaturizeNotification object:window];
   411         [center removeObserver:self name:NSWindowDidBecomeKeyNotification object:window];
   412         [center removeObserver:self name:NSWindowDidResignKeyNotification object:window];
   413         [center removeObserver:self name:NSWindowDidChangeBackingPropertiesNotification object:window];
   414         [center removeObserver:self name:NSWindowWillEnterFullScreenNotification object:window];
   415         [center removeObserver:self name:NSWindowDidEnterFullScreenNotification object:window];
   416         [center removeObserver:self name:NSWindowWillExitFullScreenNotification object:window];
   417         [center removeObserver:self name:NSWindowDidExitFullScreenNotification object:window];
   418         [center removeObserver:self name:@"NSWindowDidFailToEnterFullScreenNotification" object:window];
   419         [center removeObserver:self name:@"NSWindowDidFailToExitFullScreenNotification" object:window];
   420     } else {
   421         [window setDelegate:nil];
   422     }
   423 
   424     [window removeObserver:self forKeyPath:@"visible"];
   425 
   426     if ([window nextResponder] == self) {
   427         [window setNextResponder:nil];
   428     }
   429     if ([view nextResponder] == self) {
   430         [view setNextResponder:nil];
   431     }
   432 }
   433 
   434 - (BOOL)isMoving
   435 {
   436     return isMoving;
   437 }
   438 
   439 -(void) setPendingMoveX:(int)x Y:(int)y
   440 {
   441     pendingWindowWarpX = x;
   442     pendingWindowWarpY = y;
   443 }
   444 
   445 - (void)windowDidFinishMoving
   446 {
   447     if ([self isMoving]) {
   448         isMoving = NO;
   449 
   450         SDL_Mouse *mouse = SDL_GetMouse();
   451         if (pendingWindowWarpX != INT_MAX && pendingWindowWarpY != INT_MAX) {
   452             mouse->WarpMouseGlobal(pendingWindowWarpX, pendingWindowWarpY);
   453             pendingWindowWarpX = pendingWindowWarpY = INT_MAX;
   454         }
   455         if (mouse->relative_mode && !mouse->relative_mode_warp && mouse->focus == _data->window) {
   456             mouse->SetRelativeMouseMode(SDL_TRUE);
   457         }
   458     }
   459 }
   460 
   461 - (BOOL)windowShouldClose:(id)sender
   462 {
   463     SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_CLOSE, 0, 0);
   464     return NO;
   465 }
   466 
   467 - (void)windowDidExpose:(NSNotification *)aNotification
   468 {
   469     SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_EXPOSED, 0, 0);
   470 }
   471 
   472 - (void)windowWillMove:(NSNotification *)aNotification
   473 {
   474     if ([_data->nswindow isKindOfClass:[SDLWindow class]]) {
   475         pendingWindowWarpX = pendingWindowWarpY = INT_MAX;
   476         isMoving = YES;
   477     }
   478 }
   479 
   480 - (void)windowDidMove:(NSNotification *)aNotification
   481 {
   482     int x, y;
   483     SDL_Window *window = _data->window;
   484     NSWindow *nswindow = _data->nswindow;
   485     BOOL fullscreen = window->flags & FULLSCREEN_MASK;
   486     NSRect rect = [nswindow contentRectForFrameRect:[nswindow frame]];
   487     ConvertNSRect([nswindow screen], fullscreen, &rect);
   488 
   489     if (s_moveHack) {
   490         SDL_bool blockMove = ((SDL_GetTicks() - s_moveHack) < 500);
   491 
   492         s_moveHack = 0;
   493 
   494         if (blockMove) {
   495             /* Cocoa is adjusting the window in response to a mode change */
   496             rect.origin.x = window->x;
   497             rect.origin.y = window->y;
   498             ConvertNSRect([nswindow screen], fullscreen, &rect);
   499             [nswindow setFrameOrigin:rect.origin];
   500             return;
   501         }
   502     }
   503 
   504     x = (int)rect.origin.x;
   505     y = (int)rect.origin.y;
   506 
   507     ScheduleContextUpdates(_data);
   508 
   509     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, x, y);
   510 }
   511 
   512 - (void)windowDidResize:(NSNotification *)aNotification
   513 {
   514     if (inFullscreenTransition) {
   515         /* We'll take care of this at the end of the transition */
   516         return;
   517     }
   518 
   519     SDL_Window *window = _data->window;
   520     NSWindow *nswindow = _data->nswindow;
   521     int x, y, w, h;
   522     NSRect rect = [nswindow contentRectForFrameRect:[nswindow frame]];
   523     ConvertNSRect([nswindow screen], (window->flags & FULLSCREEN_MASK), &rect);
   524     x = (int)rect.origin.x;
   525     y = (int)rect.origin.y;
   526     w = (int)rect.size.width;
   527     h = (int)rect.size.height;
   528 
   529     if (SDL_IsShapedWindow(window)) {
   530         Cocoa_ResizeWindowShape(window);
   531     }
   532 
   533     ScheduleContextUpdates(_data);
   534 
   535     /* The window can move during a resize event, such as when maximizing
   536        or resizing from a corner */
   537     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, x, y);
   538     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, w, h);
   539 
   540     const BOOL zoomed = [nswindow isZoomed];
   541     if (!zoomed) {
   542         SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESTORED, 0, 0);
   543     } else if (zoomed) {
   544         SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MAXIMIZED, 0, 0);
   545     }
   546 }
   547 
   548 - (void)windowDidMiniaturize:(NSNotification *)aNotification
   549 {
   550     SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
   551 }
   552 
   553 - (void)windowDidDeminiaturize:(NSNotification *)aNotification
   554 {
   555     SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_RESTORED, 0, 0);
   556 }
   557 
   558 - (void)windowDidBecomeKey:(NSNotification *)aNotification
   559 {
   560     SDL_Window *window = _data->window;
   561     SDL_Mouse *mouse = SDL_GetMouse();
   562 
   563     /* We're going to get keyboard events, since we're key. */
   564     /* This needs to be done before restoring the relative mouse mode. */
   565     SDL_SetKeyboardFocus(window);
   566 
   567     if (mouse->relative_mode && !mouse->relative_mode_warp && ![self isMoving]) {
   568         mouse->SetRelativeMouseMode(SDL_TRUE);
   569     }
   570 
   571     /* If we just gained focus we need the updated mouse position */
   572     if (!mouse->relative_mode) {
   573         NSPoint point;
   574         int x, y;
   575 
   576         point = [_data->nswindow mouseLocationOutsideOfEventStream];
   577         x = (int)point.x;
   578         y = (int)(window->h - point.y);
   579 
   580         if (x >= 0 && x < window->w && y >= 0 && y < window->h) {
   581             SDL_SendMouseMotion(window, 0, 0, x, y);
   582         }
   583     }
   584 
   585     /* Check to see if someone updated the clipboard */
   586     Cocoa_CheckClipboardUpdate(_data->videodata);
   587 
   588     if ((isFullscreenSpace) && ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP)) {
   589         [NSMenu setMenuBarVisible:NO];
   590     }
   591 
   592     /* On pre-10.6, you might have the capslock key state wrong now because we can't check here. */
   593     if (floor(NSAppKitVersionNumber) >= NSAppKitVersionNumber10_6) {
   594         const unsigned int newflags = [NSEvent modifierFlags] & NSAlphaShiftKeyMask;
   595         _data->videodata->modifierFlags = (_data->videodata->modifierFlags & ~NSAlphaShiftKeyMask) | newflags;
   596         SDL_ToggleModState(KMOD_CAPS, newflags != 0);
   597     }
   598 }
   599 
   600 - (void)windowDidResignKey:(NSNotification *)aNotification
   601 {
   602     SDL_Mouse *mouse = SDL_GetMouse();
   603     if (mouse->relative_mode && !mouse->relative_mode_warp) {
   604         mouse->SetRelativeMouseMode(SDL_FALSE);
   605     }
   606 
   607     /* Some other window will get mouse events, since we're not key. */
   608     if (SDL_GetMouseFocus() == _data->window) {
   609         SDL_SetMouseFocus(NULL);
   610     }
   611 
   612     /* Some other window will get keyboard events, since we're not key. */
   613     if (SDL_GetKeyboardFocus() == _data->window) {
   614         SDL_SetKeyboardFocus(NULL);
   615     }
   616 
   617     if (isFullscreenSpace) {
   618         [NSMenu setMenuBarVisible:YES];
   619     }
   620 }
   621 
   622 - (void)windowDidChangeBackingProperties:(NSNotification *)aNotification
   623 {
   624     NSNumber *oldscale = [[aNotification userInfo] objectForKey:NSBackingPropertyOldScaleFactorKey];
   625 
   626     if (inFullscreenTransition) {
   627         return;
   628     }
   629 
   630     if ([oldscale doubleValue] != [_data->nswindow backingScaleFactor]) {
   631         /* Force a resize event when the backing scale factor changes. */
   632         _data->window->w = 0;
   633         _data->window->h = 0;
   634         [self windowDidResize:aNotification];
   635     }
   636 }
   637 
   638 - (void)windowWillEnterFullScreen:(NSNotification *)aNotification
   639 {
   640     SDL_Window *window = _data->window;
   641 
   642     SetWindowStyle(window, (NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask));
   643 
   644     isFullscreenSpace = YES;
   645     inFullscreenTransition = YES;
   646 }
   647 
   648 - (void)windowDidFailToEnterFullScreen:(NSNotification *)aNotification
   649 {
   650     SDL_Window *window = _data->window;
   651 
   652     if (window->is_destroying) {
   653         return;
   654     }
   655 
   656     SetWindowStyle(window, GetWindowStyle(window));
   657 
   658     isFullscreenSpace = NO;
   659     inFullscreenTransition = NO;
   660     
   661     [self windowDidExitFullScreen:nil];
   662 }
   663 
   664 - (void)windowDidEnterFullScreen:(NSNotification *)aNotification
   665 {
   666     SDL_Window *window = _data->window;
   667 
   668     inFullscreenTransition = NO;
   669 
   670     if (pendingWindowOperation == PENDING_OPERATION_LEAVE_FULLSCREEN) {
   671         pendingWindowOperation = PENDING_OPERATION_NONE;
   672         [self setFullscreenSpace:NO];
   673     } else {
   674         if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) {
   675             [NSMenu setMenuBarVisible:NO];
   676         }
   677 
   678         pendingWindowOperation = PENDING_OPERATION_NONE;
   679         /* Force the size change event in case it was delivered earlier
   680            while the window was still animating into place.
   681          */
   682         window->w = 0;
   683         window->h = 0;
   684         [self windowDidResize:aNotification];
   685     }
   686 }
   687 
   688 - (void)windowWillExitFullScreen:(NSNotification *)aNotification
   689 {
   690     SDL_Window *window = _data->window;
   691 
   692     /* As of OS X 10.11, the window seems to need to be resizable when exiting
   693        a Space, in order for it to resize back to its windowed-mode size.
   694      */
   695     SetWindowStyle(window, GetWindowStyle(window) | NSResizableWindowMask);
   696 
   697     isFullscreenSpace = NO;
   698     inFullscreenTransition = YES;
   699 }
   700 
   701 - (void)windowDidFailToExitFullScreen:(NSNotification *)aNotification
   702 {
   703     SDL_Window *window = _data->window;
   704     
   705     if (window->is_destroying) {
   706         return;
   707     }
   708 
   709     SetWindowStyle(window, (NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask));
   710     
   711     isFullscreenSpace = YES;
   712     inFullscreenTransition = NO;
   713     
   714     [self windowDidEnterFullScreen:nil];
   715 }
   716 
   717 - (void)windowDidExitFullScreen:(NSNotification *)aNotification
   718 {
   719     SDL_Window *window = _data->window;
   720     NSWindow *nswindow = _data->nswindow;
   721 
   722     inFullscreenTransition = NO;
   723 
   724     SetWindowStyle(window, GetWindowStyle(window));
   725 
   726     [nswindow setLevel:kCGNormalWindowLevel];
   727 
   728     if (pendingWindowOperation == PENDING_OPERATION_ENTER_FULLSCREEN) {
   729         pendingWindowOperation = PENDING_OPERATION_NONE;
   730         [self setFullscreenSpace:YES];
   731     } else if (pendingWindowOperation == PENDING_OPERATION_MINIMIZE) {
   732         pendingWindowOperation = PENDING_OPERATION_NONE;
   733         [nswindow miniaturize:nil];
   734     } else {
   735         /* Adjust the fullscreen toggle button and readd menu now that we're here. */
   736         if (window->flags & SDL_WINDOW_RESIZABLE) {
   737             /* resizable windows are Spaces-friendly: they get the "go fullscreen" toggle button on their titlebar. */
   738             [nswindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
   739         } else {
   740             [nswindow setCollectionBehavior:NSWindowCollectionBehaviorManaged];
   741         }
   742         [NSMenu setMenuBarVisible:YES];
   743 
   744         pendingWindowOperation = PENDING_OPERATION_NONE;
   745         /* Force the size change event in case it was delivered earlier
   746            while the window was still animating into place.
   747          */
   748         window->w = 0;
   749         window->h = 0;
   750         [self windowDidResize:aNotification];
   751 
   752         /* FIXME: Why does the window get hidden? */
   753         if (window->flags & SDL_WINDOW_SHOWN) {
   754             Cocoa_ShowWindow(SDL_GetVideoDevice(), window);
   755         }
   756     }
   757 }
   758 
   759 -(NSApplicationPresentationOptions)window:(NSWindow *)window willUseFullScreenPresentationOptions:(NSApplicationPresentationOptions)proposedOptions
   760 {
   761     if ((_data->window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) {
   762         return NSApplicationPresentationFullScreen | NSApplicationPresentationHideDock | NSApplicationPresentationHideMenuBar;
   763     } else {
   764         return proposedOptions;
   765     }
   766 }
   767 
   768 
   769 /* We'll respond to key events by doing nothing so we don't beep.
   770  * We could handle key messages here, but we lose some in the NSApp dispatch,
   771  * where they get converted to action messages, etc.
   772  */
   773 - (void)flagsChanged:(NSEvent *)theEvent
   774 {
   775     /*Cocoa_HandleKeyEvent(SDL_GetVideoDevice(), theEvent);*/
   776 }
   777 - (void)keyDown:(NSEvent *)theEvent
   778 {
   779     /*Cocoa_HandleKeyEvent(SDL_GetVideoDevice(), theEvent);*/
   780 }
   781 - (void)keyUp:(NSEvent *)theEvent
   782 {
   783     /*Cocoa_HandleKeyEvent(SDL_GetVideoDevice(), theEvent);*/
   784 }
   785 
   786 /* We'll respond to selectors by doing nothing so we don't beep.
   787  * The escape key gets converted to a "cancel" selector, etc.
   788  */
   789 - (void)doCommandBySelector:(SEL)aSelector
   790 {
   791     /*NSLog(@"doCommandBySelector: %@\n", NSStringFromSelector(aSelector));*/
   792 }
   793 
   794 - (BOOL)processHitTest:(NSEvent *)theEvent
   795 {
   796     SDL_assert(isDragAreaRunning == [_data->nswindow isMovableByWindowBackground]);
   797 
   798     if (_data->window->hit_test) {  /* if no hit-test, skip this. */
   799         const NSPoint location = [theEvent locationInWindow];
   800         const SDL_Point point = { (int) location.x, _data->window->h - (((int) location.y)-1) };
   801         const SDL_HitTestResult rc = _data->window->hit_test(_data->window, &point, _data->window->hit_test_data);
   802         if (rc == SDL_HITTEST_DRAGGABLE) {
   803             if (!isDragAreaRunning) {
   804                 isDragAreaRunning = YES;
   805                 [_data->nswindow setMovableByWindowBackground:YES];
   806             }
   807             return YES;  /* dragging! */
   808         }
   809     }
   810 
   811     if (isDragAreaRunning) {
   812         isDragAreaRunning = NO;
   813         [_data->nswindow setMovableByWindowBackground:NO];
   814         return YES;  /* was dragging, drop event. */
   815     }
   816 
   817     return NO;  /* not a special area, carry on. */
   818 }
   819 
   820 - (void)mouseDown:(NSEvent *)theEvent
   821 {
   822     int button;
   823 
   824     /* Ignore events that aren't inside the client area (i.e. title bar.) */
   825     if ([theEvent window]) {
   826         NSRect windowRect = [[[theEvent window] contentView] frame];
   827 
   828         /* add one to size, since NSPointInRect is exclusive of the bottom
   829            edges, which mean it misses the top of the window by one pixel
   830            (as the origin is the bottom left). */
   831         windowRect.size.width += 1;
   832         windowRect.size.height += 1;
   833 
   834         if (!NSPointInRect([theEvent locationInWindow], windowRect)) {
   835             return;
   836         }
   837     }
   838 
   839     if ([self processHitTest:theEvent]) {
   840         return;  /* dragging, drop event. */
   841     }
   842 
   843     switch ([theEvent buttonNumber]) {
   844     case 0:
   845         if (([theEvent modifierFlags] & NSControlKeyMask) &&
   846 		    GetHintCtrlClickEmulateRightClick()) {
   847             wasCtrlLeft = YES;
   848             button = SDL_BUTTON_RIGHT;
   849         } else {
   850             wasCtrlLeft = NO;
   851             button = SDL_BUTTON_LEFT;
   852         }
   853         break;
   854     case 1:
   855         button = SDL_BUTTON_RIGHT;
   856         break;
   857     case 2:
   858         button = SDL_BUTTON_MIDDLE;
   859         break;
   860     default:
   861         button = [theEvent buttonNumber] + 1;
   862         break;
   863     }
   864     SDL_SendMouseButton(_data->window, 0, SDL_PRESSED, button);
   865 }
   866 
   867 - (void)rightMouseDown:(NSEvent *)theEvent
   868 {
   869     [self mouseDown:theEvent];
   870 }
   871 
   872 - (void)otherMouseDown:(NSEvent *)theEvent
   873 {
   874     [self mouseDown:theEvent];
   875 }
   876 
   877 - (void)mouseUp:(NSEvent *)theEvent
   878 {
   879     int button;
   880 
   881     if ([self processHitTest:theEvent]) {
   882         return;  /* stopped dragging, drop event. */
   883     }
   884 
   885     switch ([theEvent buttonNumber]) {
   886     case 0:
   887         if (wasCtrlLeft) {
   888             button = SDL_BUTTON_RIGHT;
   889             wasCtrlLeft = NO;
   890         } else {
   891             button = SDL_BUTTON_LEFT;
   892         }
   893         break;
   894     case 1:
   895         button = SDL_BUTTON_RIGHT;
   896         break;
   897     case 2:
   898         button = SDL_BUTTON_MIDDLE;
   899         break;
   900     default:
   901         button = [theEvent buttonNumber] + 1;
   902         break;
   903     }
   904     SDL_SendMouseButton(_data->window, 0, SDL_RELEASED, button);
   905 }
   906 
   907 - (void)rightMouseUp:(NSEvent *)theEvent
   908 {
   909     [self mouseUp:theEvent];
   910 }
   911 
   912 - (void)otherMouseUp:(NSEvent *)theEvent
   913 {
   914     [self mouseUp:theEvent];
   915 }
   916 
   917 - (void)mouseMoved:(NSEvent *)theEvent
   918 {
   919     SDL_Mouse *mouse = SDL_GetMouse();
   920     SDL_Window *window = _data->window;
   921     NSPoint point;
   922     int x, y;
   923 
   924     if ([self processHitTest:theEvent]) {
   925         return;  /* dragging, drop event. */
   926     }
   927 
   928     if (mouse->relative_mode) {
   929         return;
   930     }
   931 
   932     point = [theEvent locationInWindow];
   933     x = (int)point.x;
   934     y = (int)(window->h - point.y);
   935 
   936     if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
   937         if (x < 0 || x >= window->w || y < 0 || y >= window->h) {
   938             if (x < 0) {
   939                 x = 0;
   940             } else if (x >= window->w) {
   941                 x = window->w - 1;
   942             }
   943             if (y < 0) {
   944                 y = 0;
   945             } else if (y >= window->h) {
   946                 y = window->h - 1;
   947             }
   948 
   949 #if !SDL_MAC_NO_SANDBOX
   950             CGPoint cgpoint;
   951 
   952             /* When SDL_MAC_NO_SANDBOX is set, this is handled by
   953              * SDL_cocoamousetap.m.
   954              */
   955 
   956             cgpoint.x = window->x + x;
   957             cgpoint.y = window->y + y;
   958 
   959             /* According to the docs, this was deprecated in 10.6, but it's still
   960              * around. The substitute requires a CGEventSource, but I'm not entirely
   961              * sure how we'd procure the right one for this event.
   962              */
   963             CGSetLocalEventsSuppressionInterval(0.0);
   964             CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
   965             CGSetLocalEventsSuppressionInterval(0.25);
   966 
   967             Cocoa_HandleMouseWarp(cgpoint.x, cgpoint.y);
   968 #endif
   969         }
   970     }
   971     SDL_SendMouseMotion(window, 0, 0, x, y);
   972 }
   973 
   974 - (void)mouseDragged:(NSEvent *)theEvent
   975 {
   976     [self mouseMoved:theEvent];
   977 }
   978 
   979 - (void)rightMouseDragged:(NSEvent *)theEvent
   980 {
   981     [self mouseMoved:theEvent];
   982 }
   983 
   984 - (void)otherMouseDragged:(NSEvent *)theEvent
   985 {
   986     [self mouseMoved:theEvent];
   987 }
   988 
   989 - (void)scrollWheel:(NSEvent *)theEvent
   990 {
   991     Cocoa_HandleMouseWheel(_data->window, theEvent);
   992 }
   993 
   994 - (void)touchesBeganWithEvent:(NSEvent *) theEvent
   995 {
   996     NSSet *touches = [theEvent touchesMatchingPhase:NSTouchPhaseAny inView:nil];
   997     int existingTouchCount = 0;
   998 
   999     for (NSTouch* touch in touches) {
  1000         if ([touch phase] != NSTouchPhaseBegan) {
  1001             existingTouchCount++;
  1002         }
  1003     }
  1004     if (existingTouchCount == 0) {
  1005         SDL_TouchID touchID = (SDL_TouchID)(intptr_t)[[touches anyObject] device];
  1006         int numFingers = SDL_GetNumTouchFingers(touchID);
  1007         DLog("Reset Lost Fingers: %d", numFingers);
  1008         for (--numFingers; numFingers >= 0; --numFingers) {
  1009             SDL_Finger* finger = SDL_GetTouchFinger(touchID, numFingers);
  1010             SDL_SendTouch(touchID, finger->id, SDL_FALSE, 0, 0, 0);
  1011         }
  1012     }
  1013 
  1014     DLog("Began Fingers: %lu .. existing: %d", (unsigned long)[touches count], existingTouchCount);
  1015     [self handleTouches:NSTouchPhaseBegan withEvent:theEvent];
  1016 }
  1017 
  1018 - (void)touchesMovedWithEvent:(NSEvent *) theEvent
  1019 {
  1020     [self handleTouches:NSTouchPhaseMoved withEvent:theEvent];
  1021 }
  1022 
  1023 - (void)touchesEndedWithEvent:(NSEvent *) theEvent
  1024 {
  1025     [self handleTouches:NSTouchPhaseEnded withEvent:theEvent];
  1026 }
  1027 
  1028 - (void)touchesCancelledWithEvent:(NSEvent *) theEvent
  1029 {
  1030     [self handleTouches:NSTouchPhaseCancelled withEvent:theEvent];
  1031 }
  1032 
  1033 - (void)handleTouches:(NSTouchPhase) phase withEvent:(NSEvent *) theEvent
  1034 {
  1035     NSSet *touches = [theEvent touchesMatchingPhase:phase inView:nil];
  1036 
  1037     for (NSTouch *touch in touches) {
  1038         const SDL_TouchID touchId = (SDL_TouchID)(intptr_t)[touch device];
  1039         if (SDL_AddTouch(touchId, "") < 0) {
  1040             return;
  1041         }
  1042 
  1043         const SDL_FingerID fingerId = (SDL_FingerID)(intptr_t)[touch identity];
  1044         float x = [touch normalizedPosition].x;
  1045         float y = [touch normalizedPosition].y;
  1046         /* Make the origin the upper left instead of the lower left */
  1047         y = 1.0f - y;
  1048 
  1049         switch (phase) {
  1050         case NSTouchPhaseBegan:
  1051             SDL_SendTouch(touchId, fingerId, SDL_TRUE, x, y, 1.0f);
  1052             break;
  1053         case NSTouchPhaseEnded:
  1054         case NSTouchPhaseCancelled:
  1055             SDL_SendTouch(touchId, fingerId, SDL_FALSE, x, y, 1.0f);
  1056             break;
  1057         case NSTouchPhaseMoved:
  1058             SDL_SendTouchMotion(touchId, fingerId, x, y, 1.0f);
  1059             break;
  1060         default:
  1061             break;
  1062         }
  1063     }
  1064 }
  1065 
  1066 @end
  1067 
  1068 @interface SDLView : NSView {
  1069     SDL_Window *_sdlWindow;
  1070 }
  1071 
  1072 - (void)setSDLWindow:(SDL_Window*)window;
  1073 
  1074 /* The default implementation doesn't pass rightMouseDown to responder chain */
  1075 - (void)rightMouseDown:(NSEvent *)theEvent;
  1076 - (BOOL)mouseDownCanMoveWindow;
  1077 - (void)drawRect:(NSRect)dirtyRect;
  1078 @end
  1079 
  1080 @implementation SDLView
  1081 - (void)setSDLWindow:(SDL_Window*)window
  1082 {
  1083     _sdlWindow = window;
  1084 }
  1085 
  1086 - (void)drawRect:(NSRect)dirtyRect
  1087 {
  1088     SDL_SendWindowEvent(_sdlWindow, SDL_WINDOWEVENT_EXPOSED, 0, 0);
  1089 }
  1090 
  1091 - (void)rightMouseDown:(NSEvent *)theEvent
  1092 {
  1093     [[self nextResponder] rightMouseDown:theEvent];
  1094 }
  1095 
  1096 - (BOOL)mouseDownCanMoveWindow
  1097 {
  1098     /* Always say YES, but this doesn't do anything until we call
  1099        -[NSWindow setMovableByWindowBackground:YES], which we ninja-toggle
  1100        during mouse events when we're using a drag area. */
  1101     return YES;
  1102 }
  1103 
  1104 - (void)resetCursorRects
  1105 {
  1106     [super resetCursorRects];
  1107     SDL_Mouse *mouse = SDL_GetMouse();
  1108 
  1109     if (mouse->cursor_shown && mouse->cur_cursor && !mouse->relative_mode) {
  1110         [self addCursorRect:[self bounds]
  1111                      cursor:mouse->cur_cursor->driverdata];
  1112     } else {
  1113         [self addCursorRect:[self bounds]
  1114                      cursor:[NSCursor invisibleCursor]];
  1115     }
  1116 }
  1117 @end
  1118 
  1119 static int
  1120 SetupWindowData(_THIS, SDL_Window * window, NSWindow *nswindow, SDL_bool created)
  1121 { @autoreleasepool
  1122 {
  1123     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
  1124     SDL_WindowData *data;
  1125 
  1126     /* Allocate the window data */
  1127     window->driverdata = data = (SDL_WindowData *) SDL_calloc(1, sizeof(*data));
  1128     if (!data) {
  1129         return SDL_OutOfMemory();
  1130     }
  1131     data->window = window;
  1132     data->nswindow = nswindow;
  1133     data->created = created;
  1134     data->videodata = videodata;
  1135     data->nscontexts = [[NSMutableArray alloc] init];
  1136 
  1137     /* Create an event listener for the window */
  1138     data->listener = [[Cocoa_WindowListener alloc] init];
  1139 
  1140     /* Fill in the SDL window with the window data */
  1141     {
  1142         NSRect rect = [nswindow contentRectForFrameRect:[nswindow frame]];
  1143         ConvertNSRect([nswindow screen], (window->flags & FULLSCREEN_MASK), &rect);
  1144         window->x = (int)rect.origin.x;
  1145         window->y = (int)rect.origin.y;
  1146         window->w = (int)rect.size.width;
  1147         window->h = (int)rect.size.height;
  1148     }
  1149 
  1150     /* Set up the listener after we create the view */
  1151     [data->listener listen:data];
  1152 
  1153     if ([nswindow isVisible]) {
  1154         window->flags |= SDL_WINDOW_SHOWN;
  1155     } else {
  1156         window->flags &= ~SDL_WINDOW_SHOWN;
  1157     }
  1158 
  1159     {
  1160         unsigned int style = [nswindow styleMask];
  1161 
  1162         if (style == NSBorderlessWindowMask) {
  1163             window->flags |= SDL_WINDOW_BORDERLESS;
  1164         } else {
  1165             window->flags &= ~SDL_WINDOW_BORDERLESS;
  1166         }
  1167         if (style & NSResizableWindowMask) {
  1168             window->flags |= SDL_WINDOW_RESIZABLE;
  1169         } else {
  1170             window->flags &= ~SDL_WINDOW_RESIZABLE;
  1171         }
  1172     }
  1173 
  1174     /* isZoomed always returns true if the window is not resizable */
  1175     if ((window->flags & SDL_WINDOW_RESIZABLE) && [nswindow isZoomed]) {
  1176         window->flags |= SDL_WINDOW_MAXIMIZED;
  1177     } else {
  1178         window->flags &= ~SDL_WINDOW_MAXIMIZED;
  1179     }
  1180 
  1181     if ([nswindow isMiniaturized]) {
  1182         window->flags |= SDL_WINDOW_MINIMIZED;
  1183     } else {
  1184         window->flags &= ~SDL_WINDOW_MINIMIZED;
  1185     }
  1186 
  1187     if ([nswindow isKeyWindow]) {
  1188         window->flags |= SDL_WINDOW_INPUT_FOCUS;
  1189         SDL_SetKeyboardFocus(data->window);
  1190     }
  1191 
  1192     /* Prevents the window's "window device" from being destroyed when it is
  1193      * hidden. See http://www.mikeash.com/pyblog/nsopenglcontext-and-one-shot.html
  1194      */
  1195     [nswindow setOneShot:NO];
  1196 
  1197     /* All done! */
  1198     window->driverdata = data;
  1199     return 0;
  1200 }}
  1201 
  1202 int
  1203 Cocoa_CreateWindow(_THIS, SDL_Window * window)
  1204 { @autoreleasepool
  1205 {
  1206     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
  1207     NSWindow *nswindow;
  1208     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  1209     NSRect rect;
  1210     SDL_Rect bounds;
  1211     unsigned int style;
  1212     NSArray *screens = [NSScreen screens];
  1213 
  1214     Cocoa_GetDisplayBounds(_this, display, &bounds);
  1215     rect.origin.x = window->x;
  1216     rect.origin.y = window->y;
  1217     rect.size.width = window->w;
  1218     rect.size.height = window->h;
  1219     ConvertNSRect([screens objectAtIndex:0], (window->flags & FULLSCREEN_MASK), &rect);
  1220 
  1221     style = GetWindowStyle(window);
  1222 
  1223     /* Figure out which screen to place this window */
  1224     NSScreen *screen = nil;
  1225     for (NSScreen *candidate in screens) {
  1226         NSRect screenRect = [candidate frame];
  1227         if (rect.origin.x >= screenRect.origin.x &&
  1228             rect.origin.x < screenRect.origin.x + screenRect.size.width &&
  1229             rect.origin.y >= screenRect.origin.y &&
  1230             rect.origin.y < screenRect.origin.y + screenRect.size.height) {
  1231             screen = candidate;
  1232             rect.origin.x -= screenRect.origin.x;
  1233             rect.origin.y -= screenRect.origin.y;
  1234         }
  1235     }
  1236 
  1237     @try {
  1238         nswindow = [[SDLWindow alloc] initWithContentRect:rect styleMask:style backing:NSBackingStoreBuffered defer:NO screen:screen];
  1239     }
  1240     @catch (NSException *e) {
  1241         return SDL_SetError("%s", [[e reason] UTF8String]);
  1242     }
  1243     [nswindow setBackgroundColor:[NSColor blackColor]];
  1244 
  1245     if (videodata->allow_spaces) {
  1246         SDL_assert(floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6);
  1247         SDL_assert([nswindow respondsToSelector:@selector(toggleFullScreen:)]);
  1248         /* we put FULLSCREEN_DESKTOP windows in their own Space, without a toggle button or menubar, later */
  1249         if (window->flags & SDL_WINDOW_RESIZABLE) {
  1250             /* resizable windows are Spaces-friendly: they get the "go fullscreen" toggle button on their titlebar. */
  1251             [nswindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
  1252         }
  1253     }
  1254 
  1255     /* Create a default view for this window */
  1256     rect = [nswindow contentRectForFrameRect:[nswindow frame]];
  1257     SDLView *contentView = [[SDLView alloc] initWithFrame:rect];
  1258     [contentView setSDLWindow:window];
  1259 
  1260     if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
  1261         if ([contentView respondsToSelector:@selector(setWantsBestResolutionOpenGLSurface:)]) {
  1262             [contentView setWantsBestResolutionOpenGLSurface:YES];
  1263         }
  1264     }
  1265 
  1266     [nswindow setContentView: contentView];
  1267     [contentView release];
  1268 
  1269     /* Allow files and folders to be dragged onto the window by users */
  1270     [nswindow registerForDraggedTypes:[NSArray arrayWithObject:(NSString *)kUTTypeFileURL]];
  1271 
  1272     if (SetupWindowData(_this, window, nswindow, SDL_TRUE) < 0) {
  1273         [nswindow release];
  1274         return -1;
  1275     }
  1276     return 0;
  1277 }}
  1278 
  1279 int
  1280 Cocoa_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
  1281 { @autoreleasepool
  1282 {
  1283     NSWindow *nswindow = (NSWindow *) data;
  1284     NSString *title;
  1285 
  1286     /* Query the title from the existing window */
  1287     title = [nswindow title];
  1288     if (title) {
  1289         window->title = SDL_strdup([title UTF8String]);
  1290     }
  1291 
  1292     return SetupWindowData(_this, window, nswindow, SDL_FALSE);
  1293 }}
  1294 
  1295 void
  1296 Cocoa_SetWindowTitle(_THIS, SDL_Window * window)
  1297 { @autoreleasepool
  1298 {
  1299     const char *title = window->title ? window->title : "";
  1300     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
  1301     NSString *string = [[NSString alloc] initWithUTF8String:title];
  1302     [nswindow setTitle:string];
  1303     [string release];
  1304 }}
  1305 
  1306 void
  1307 Cocoa_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
  1308 { @autoreleasepool
  1309 {
  1310     NSImage *nsimage = Cocoa_CreateImage(icon);
  1311 
  1312     if (nsimage) {
  1313         [NSApp setApplicationIconImage:nsimage];
  1314     }
  1315 }}
  1316 
  1317 void
  1318 Cocoa_SetWindowPosition(_THIS, SDL_Window * window)
  1319 { @autoreleasepool
  1320 {
  1321     SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
  1322     NSWindow *nswindow = windata->nswindow;
  1323     NSRect rect;
  1324     Uint32 moveHack;
  1325 
  1326     rect.origin.x = window->x;
  1327     rect.origin.y = window->y;
  1328     rect.size.width = window->w;
  1329     rect.size.height = window->h;
  1330     ConvertNSRect([nswindow screen], (window->flags & FULLSCREEN_MASK), &rect);
  1331 
  1332     moveHack = s_moveHack;
  1333     s_moveHack = 0;
  1334     [nswindow setFrameOrigin:rect.origin];
  1335     s_moveHack = moveHack;
  1336 
  1337     ScheduleContextUpdates(windata);
  1338 }}
  1339 
  1340 void
  1341 Cocoa_SetWindowSize(_THIS, SDL_Window * window)
  1342 { @autoreleasepool
  1343 {
  1344     SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
  1345     NSWindow *nswindow = windata->nswindow;
  1346     NSRect rect;
  1347     Uint32 moveHack;
  1348 
  1349     /* Cocoa will resize the window from the bottom-left rather than the
  1350      * top-left when -[nswindow setContentSize:] is used, so we must set the
  1351      * entire frame based on the new size, in order to preserve the position.
  1352      */
  1353     rect.origin.x = window->x;
  1354     rect.origin.y = window->y;
  1355     rect.size.width = window->w;
  1356     rect.size.height = window->h;
  1357     ConvertNSRect([nswindow screen], (window->flags & FULLSCREEN_MASK), &rect);
  1358 
  1359     moveHack = s_moveHack;
  1360     s_moveHack = 0;
  1361     [nswindow setFrame:[nswindow frameRectForContentRect:rect] display:YES];
  1362     s_moveHack = moveHack;
  1363 
  1364     ScheduleContextUpdates(windata);
  1365 }}
  1366 
  1367 void
  1368 Cocoa_SetWindowMinimumSize(_THIS, SDL_Window * window)
  1369 { @autoreleasepool
  1370 {
  1371     SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
  1372 
  1373     NSSize minSize;
  1374     minSize.width = window->min_w;
  1375     minSize.height = window->min_h;
  1376 
  1377     [windata->nswindow setContentMinSize:minSize];
  1378 }}
  1379 
  1380 void
  1381 Cocoa_SetWindowMaximumSize(_THIS, SDL_Window * window)
  1382 { @autoreleasepool
  1383 {
  1384     SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
  1385 
  1386     NSSize maxSize;
  1387     maxSize.width = window->max_w;
  1388     maxSize.height = window->max_h;
  1389 
  1390     [windata->nswindow setContentMaxSize:maxSize];
  1391 }}
  1392 
  1393 void
  1394 Cocoa_ShowWindow(_THIS, SDL_Window * window)
  1395 { @autoreleasepool
  1396 {
  1397     SDL_WindowData *windowData = ((SDL_WindowData *) window->driverdata);
  1398     NSWindow *nswindow = windowData->nswindow;
  1399 
  1400     if (![nswindow isMiniaturized]) {
  1401         [windowData->listener pauseVisibleObservation];
  1402         [nswindow makeKeyAndOrderFront:nil];
  1403         [windowData->listener resumeVisibleObservation];
  1404     }
  1405 }}
  1406 
  1407 void
  1408 Cocoa_HideWindow(_THIS, SDL_Window * window)
  1409 { @autoreleasepool
  1410 {
  1411     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
  1412 
  1413     [nswindow orderOut:nil];
  1414 }}
  1415 
  1416 void
  1417 Cocoa_RaiseWindow(_THIS, SDL_Window * window)
  1418 { @autoreleasepool
  1419 {
  1420     SDL_WindowData *windowData = ((SDL_WindowData *) window->driverdata);
  1421     NSWindow *nswindow = windowData->nswindow;
  1422 
  1423     /* makeKeyAndOrderFront: has the side-effect of deminiaturizing and showing
  1424        a minimized or hidden window, so check for that before showing it.
  1425      */
  1426     [windowData->listener pauseVisibleObservation];
  1427     if (![nswindow isMiniaturized] && [nswindow isVisible]) {
  1428         [NSApp activateIgnoringOtherApps:YES];
  1429         [nswindow makeKeyAndOrderFront:nil];
  1430     }
  1431     [windowData->listener resumeVisibleObservation];
  1432 }}
  1433 
  1434 void
  1435 Cocoa_MaximizeWindow(_THIS, SDL_Window * window)
  1436 { @autoreleasepool
  1437 {
  1438     SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
  1439     NSWindow *nswindow = windata->nswindow;
  1440 
  1441     [nswindow zoom:nil];
  1442 
  1443     ScheduleContextUpdates(windata);
  1444 }}
  1445 
  1446 void
  1447 Cocoa_MinimizeWindow(_THIS, SDL_Window * window)
  1448 { @autoreleasepool
  1449 {
  1450     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1451     NSWindow *nswindow = data->nswindow;
  1452 
  1453     if ([data->listener isInFullscreenSpaceTransition]) {
  1454         [data->listener addPendingWindowOperation:PENDING_OPERATION_MINIMIZE];
  1455     } else {
  1456         [nswindow miniaturize:nil];
  1457     }
  1458 }}
  1459 
  1460 void
  1461 Cocoa_RestoreWindow(_THIS, SDL_Window * window)
  1462 { @autoreleasepool
  1463 {
  1464     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
  1465 
  1466     if ([nswindow isMiniaturized]) {
  1467         [nswindow deminiaturize:nil];
  1468     } else if ((window->flags & SDL_WINDOW_RESIZABLE) && [nswindow isZoomed]) {
  1469         [nswindow zoom:nil];
  1470     }
  1471 }}
  1472 
  1473 static NSWindow *
  1474 Cocoa_RebuildWindow(SDL_WindowData * data, NSWindow * nswindow, unsigned style)
  1475 {
  1476     if (!data->created) {
  1477         /* Don't mess with other people's windows... */
  1478         return nswindow;
  1479     }
  1480 
  1481     [data->listener close];
  1482     data->nswindow = [[SDLWindow alloc] initWithContentRect:[[nswindow contentView] frame] styleMask:style backing:NSBackingStoreBuffered defer:NO screen:[nswindow screen]];
  1483     [data->nswindow setContentView:[nswindow contentView]];
  1484     [data->nswindow registerForDraggedTypes:[NSArray arrayWithObject:(NSString *)kUTTypeFileURL]];
  1485     /* See comment in SetupWindowData. */
  1486     [data->nswindow setOneShot:NO];
  1487     [data->listener listen:data];
  1488 
  1489     [nswindow close];
  1490 
  1491     return data->nswindow;
  1492 }
  1493 
  1494 void
  1495 Cocoa_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
  1496 { @autoreleasepool
  1497 {
  1498     if (SetWindowStyle(window, GetWindowStyle(window))) {
  1499         if (bordered) {
  1500             Cocoa_SetWindowTitle(_this, window);  /* this got blanked out. */
  1501         }
  1502     }
  1503 }}
  1504 
  1505 
  1506 void
  1507 Cocoa_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
  1508 { @autoreleasepool
  1509 {
  1510     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1511     NSWindow *nswindow = data->nswindow;
  1512     NSRect rect;
  1513 
  1514     /* The view responder chain gets messed with during setStyleMask */
  1515     if ([[nswindow contentView] nextResponder] == data->listener) {
  1516         [[nswindow contentView] setNextResponder:nil];
  1517     }
  1518 
  1519     if (fullscreen) {
  1520         SDL_Rect bounds;
  1521 
  1522         Cocoa_GetDisplayBounds(_this, display, &bounds);
  1523         rect.origin.x = bounds.x;
  1524         rect.origin.y = bounds.y;
  1525         rect.size.width = bounds.w;
  1526         rect.size.height = bounds.h;
  1527         ConvertNSRect([nswindow screen], fullscreen, &rect);
  1528 
  1529         /* Hack to fix origin on Mac OS X 10.4 */
  1530         NSRect screenRect = [[nswindow screen] frame];
  1531         if (screenRect.size.height >= 1.0f) {
  1532             rect.origin.y += (screenRect.size.height - rect.size.height);
  1533         }
  1534 
  1535         if ([nswindow respondsToSelector: @selector(setStyleMask:)]) {
  1536             [nswindow performSelector: @selector(setStyleMask:) withObject: (id)NSBorderlessWindowMask];
  1537         } else {
  1538             nswindow = Cocoa_RebuildWindow(data, nswindow, NSBorderlessWindowMask);
  1539         }
  1540     } else {
  1541         rect.origin.x = window->windowed.x;
  1542         rect.origin.y = window->windowed.y;
  1543         rect.size.width = window->windowed.w;
  1544         rect.size.height = window->windowed.h;
  1545         ConvertNSRect([nswindow screen], fullscreen, &rect);
  1546 
  1547         if ([nswindow respondsToSelector: @selector(setStyleMask:)]) {
  1548             [nswindow performSelector: @selector(setStyleMask:) withObject: (id)(uintptr_t)GetWindowStyle(window)];
  1549 
  1550             /* Hack to restore window decorations on Mac OS X 10.10 */
  1551             NSRect frameRect = [nswindow frame];
  1552             [nswindow setFrame:NSMakeRect(frameRect.origin.x, frameRect.origin.y, frameRect.size.width + 1, frameRect.size.height) display:NO];
  1553             [nswindow setFrame:frameRect display:NO];
  1554         } else {
  1555             nswindow = Cocoa_RebuildWindow(data, nswindow, GetWindowStyle(window));
  1556         }
  1557     }
  1558 
  1559     /* The view responder chain gets messed with during setStyleMask */
  1560     if ([[nswindow contentView] nextResponder] != data->listener) {
  1561         [[nswindow contentView] setNextResponder:data->listener];
  1562     }
  1563 
  1564     s_moveHack = 0;
  1565     [nswindow setContentSize:rect.size];
  1566     [nswindow setFrameOrigin:rect.origin];
  1567     s_moveHack = SDL_GetTicks();
  1568 
  1569     /* When the window style changes the title is cleared */
  1570     if (!fullscreen) {
  1571         Cocoa_SetWindowTitle(_this, window);
  1572     }
  1573 
  1574     if (SDL_ShouldAllowTopmost() && fullscreen) {
  1575         /* OpenGL is rendering to the window, so make it visible! */
  1576         [nswindow setLevel:CGShieldingWindowLevel()];
  1577     } else {
  1578         [nswindow setLevel:kCGNormalWindowLevel];
  1579     }
  1580 
  1581     if ([nswindow isVisible] || fullscreen) {
  1582         [data->listener pauseVisibleObservation];
  1583         [nswindow makeKeyAndOrderFront:nil];
  1584         [data->listener resumeVisibleObservation];
  1585     }
  1586 
  1587     ScheduleContextUpdates(data);
  1588 }}
  1589 
  1590 int
  1591 Cocoa_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
  1592 {
  1593     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  1594     CGDirectDisplayID display_id = ((SDL_DisplayData *)display->driverdata)->display;
  1595     const uint32_t tableSize = 256;
  1596     CGGammaValue redTable[tableSize];
  1597     CGGammaValue greenTable[tableSize];
  1598     CGGammaValue blueTable[tableSize];
  1599     uint32_t i;
  1600     float inv65535 = 1.0f / 65535.0f;
  1601 
  1602     /* Extract gamma values into separate tables, convert to floats between 0.0 and 1.0 */
  1603     for (i = 0; i < 256; i++) {
  1604         redTable[i] = ramp[0*256+i] * inv65535;
  1605         greenTable[i] = ramp[1*256+i] * inv65535;
  1606         blueTable[i] = ramp[2*256+i] * inv65535;
  1607     }
  1608 
  1609     if (CGSetDisplayTransferByTable(display_id, tableSize,
  1610                                     redTable, greenTable, blueTable) != CGDisplayNoErr) {
  1611         return SDL_SetError("CGSetDisplayTransferByTable()");
  1612     }
  1613     return 0;
  1614 }
  1615 
  1616 int
  1617 Cocoa_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp)
  1618 {
  1619     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  1620     CGDirectDisplayID display_id = ((SDL_DisplayData *)display->driverdata)->display;
  1621     const uint32_t tableSize = 256;
  1622     CGGammaValue redTable[tableSize];
  1623     CGGammaValue greenTable[tableSize];
  1624     CGGammaValue blueTable[tableSize];
  1625     uint32_t i, tableCopied;
  1626 
  1627     if (CGGetDisplayTransferByTable(display_id, tableSize,
  1628                                     redTable, greenTable, blueTable, &tableCopied) != CGDisplayNoErr) {
  1629         return SDL_SetError("CGGetDisplayTransferByTable()");
  1630     }
  1631 
  1632     for (i = 0; i < tableCopied; i++) {
  1633         ramp[0*256+i] = (Uint16)(redTable[i] * 65535.0f);
  1634         ramp[1*256+i] = (Uint16)(greenTable[i] * 65535.0f);
  1635         ramp[2*256+i] = (Uint16)(blueTable[i] * 65535.0f);
  1636     }
  1637     return 0;
  1638 }
  1639 
  1640 void
  1641 Cocoa_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
  1642 {
  1643     /* Move the cursor to the nearest point in the window */
  1644     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1645     if (grabbed && data && ![data->listener isMoving]) {
  1646         int x, y;
  1647         CGPoint cgpoint;
  1648 
  1649         SDL_GetMouseState(&x, &y);
  1650         cgpoint.x = window->x + x;
  1651         cgpoint.y = window->y + y;
  1652 
  1653         Cocoa_HandleMouseWarp(cgpoint.x, cgpoint.y);
  1654 
  1655         DLog("Returning cursor to (%g, %g)", cgpoint.x, cgpoint.y);
  1656         CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
  1657     }
  1658 
  1659     if ( data && (window->flags & SDL_WINDOW_FULLSCREEN) ) {
  1660         if (SDL_ShouldAllowTopmost() && (window->flags & SDL_WINDOW_INPUT_FOCUS)
  1661             && ![data->listener isInFullscreenSpace]) {
  1662             /* OpenGL is rendering to the window, so make it visible! */
  1663             /* Doing this in 10.11 while in a Space breaks things (bug #3152) */
  1664             [data->nswindow setLevel:CGShieldingWindowLevel()];
  1665         } else {
  1666             [data->nswindow setLevel:kCGNormalWindowLevel];
  1667         }
  1668     }
  1669 }
  1670 
  1671 void
  1672 Cocoa_DestroyWindow(_THIS, SDL_Window * window)
  1673 { @autoreleasepool
  1674 {
  1675     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1676 
  1677     if (data) {
  1678         if ([data->listener isInFullscreenSpace]) {
  1679             [NSMenu setMenuBarVisible:YES];
  1680         }
  1681         [data->listener close];
  1682         [data->listener release];
  1683         if (data->created) {
  1684             [data->nswindow close];
  1685         }
  1686 
  1687         NSArray *contexts = [[data->nscontexts copy] autorelease];
  1688         for (SDLOpenGLContext *context in contexts) {
  1689             /* Calling setWindow:NULL causes the context to remove itself from the context list. */            
  1690             [context setWindow:NULL];
  1691         }
  1692         [data->nscontexts release];
  1693 
  1694         SDL_free(data);
  1695     }
  1696     window->driverdata = NULL;
  1697 }}
  1698 
  1699 SDL_bool
  1700 Cocoa_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
  1701 {
  1702     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
  1703 
  1704     if (info->version.major <= SDL_MAJOR_VERSION) {
  1705         info->subsystem = SDL_SYSWM_COCOA;
  1706         info->info.cocoa.window = nswindow;
  1707         return SDL_TRUE;
  1708     } else {
  1709         SDL_SetError("Application not compiled with SDL %d.%d\n",
  1710                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
  1711         return SDL_FALSE;
  1712     }
  1713 }
  1714 
  1715 SDL_bool
  1716 Cocoa_IsWindowInFullscreenSpace(SDL_Window * window)
  1717 {
  1718     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1719 
  1720     if ([data->listener isInFullscreenSpace]) {
  1721         return SDL_TRUE;
  1722     } else {
  1723         return SDL_FALSE;
  1724     }
  1725 }
  1726 
  1727 SDL_bool
  1728 Cocoa_SetWindowFullscreenSpace(SDL_Window * window, SDL_bool state)
  1729 { @autoreleasepool
  1730 {
  1731     SDL_bool succeeded = SDL_FALSE;
  1732     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1733 
  1734     if ([data->listener setFullscreenSpace:(state ? YES : NO)]) {
  1735         const int maxattempts = 3;
  1736         int attempt = 0;
  1737         while (++attempt <= maxattempts) {
  1738             /* Wait for the transition to complete, so application changes
  1739              take effect properly (e.g. setting the window size, etc.)
  1740              */
  1741             const int limit = 10000;
  1742             int count = 0;
  1743             while ([data->listener isInFullscreenSpaceTransition]) {
  1744                 if ( ++count == limit ) {
  1745                     /* Uh oh, transition isn't completing. Should we assert? */
  1746                     break;
  1747                 }
  1748                 SDL_Delay(1);
  1749                 SDL_PumpEvents();
  1750             }
  1751             if ([data->listener isInFullscreenSpace] == (state ? YES : NO))
  1752                 break;
  1753             /* Try again, the last attempt was interrupted by user gestures */
  1754             if (![data->listener setFullscreenSpace:(state ? YES : NO)])
  1755                 break; /* ??? */
  1756         }
  1757         /* Return TRUE to prevent non-space fullscreen logic from running */
  1758         succeeded = SDL_TRUE;
  1759     }
  1760 
  1761     return succeeded;
  1762 }}
  1763 
  1764 int
  1765 Cocoa_SetWindowHitTest(SDL_Window * window, SDL_bool enabled)
  1766 {
  1767     return 0;  /* just succeed, the real work is done elsewhere. */
  1768 }
  1769 
  1770 #endif /* SDL_VIDEO_DRIVER_COCOA */
  1771 
  1772 /* vi: set ts=4 sw=4 expandtab: */