src/video/cocoa/SDL_cocoawindow.m
author Ryan C. Gordon <icculus@icculus.org>
Sun, 27 Dec 2015 23:39:43 -0500
changeset 9972 734c90ea9990
parent 9933 16e85b80177f
child 9973 4d8a561cf978
permissions -rw-r--r--
Mac: Fix keyboard state if capslock was toggled while app wasn't in foreground.
     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. */
   593     if (floor(NSAppKitVersionNumber) >= NSAppKitVersionNumber10_6) {
   594         const unsigned int oldflags = _data->videodata->modifierFlags & NSAlphaShiftKeyMask;
   595         const unsigned int newflags = [NSEvent modifierFlags] & NSAlphaShiftKeyMask;
   596         if (oldflags != newflags) {
   597             _data->videodata->modifierFlags = (_data->videodata->modifierFlags & ~NSAlphaShiftKeyMask) | newflags;
   598             SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_CAPSLOCK);
   599             SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_CAPSLOCK);
   600         }
   601     }
   602 }
   603 
   604 - (void)windowDidResignKey:(NSNotification *)aNotification
   605 {
   606     SDL_Mouse *mouse = SDL_GetMouse();
   607     if (mouse->relative_mode && !mouse->relative_mode_warp) {
   608         mouse->SetRelativeMouseMode(SDL_FALSE);
   609     }
   610 
   611     /* Some other window will get mouse events, since we're not key. */
   612     if (SDL_GetMouseFocus() == _data->window) {
   613         SDL_SetMouseFocus(NULL);
   614     }
   615 
   616     /* Some other window will get keyboard events, since we're not key. */
   617     if (SDL_GetKeyboardFocus() == _data->window) {
   618         SDL_SetKeyboardFocus(NULL);
   619     }
   620 
   621     if (isFullscreenSpace) {
   622         [NSMenu setMenuBarVisible:YES];
   623     }
   624 }
   625 
   626 - (void)windowDidChangeBackingProperties:(NSNotification *)aNotification
   627 {
   628     NSNumber *oldscale = [[aNotification userInfo] objectForKey:NSBackingPropertyOldScaleFactorKey];
   629 
   630     if (inFullscreenTransition) {
   631         return;
   632     }
   633 
   634     if ([oldscale doubleValue] != [_data->nswindow backingScaleFactor]) {
   635         /* Force a resize event when the backing scale factor changes. */
   636         _data->window->w = 0;
   637         _data->window->h = 0;
   638         [self windowDidResize:aNotification];
   639     }
   640 }
   641 
   642 - (void)windowWillEnterFullScreen:(NSNotification *)aNotification
   643 {
   644     SDL_Window *window = _data->window;
   645 
   646     SetWindowStyle(window, (NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask));
   647 
   648     isFullscreenSpace = YES;
   649     inFullscreenTransition = YES;
   650 }
   651 
   652 - (void)windowDidFailToEnterFullScreen:(NSNotification *)aNotification
   653 {
   654     SDL_Window *window = _data->window;
   655 
   656     if (window->is_destroying) {
   657         return;
   658     }
   659 
   660     SetWindowStyle(window, GetWindowStyle(window));
   661 
   662     isFullscreenSpace = NO;
   663     inFullscreenTransition = NO;
   664     
   665     [self windowDidExitFullScreen:nil];
   666 }
   667 
   668 - (void)windowDidEnterFullScreen:(NSNotification *)aNotification
   669 {
   670     SDL_Window *window = _data->window;
   671 
   672     inFullscreenTransition = NO;
   673 
   674     if (pendingWindowOperation == PENDING_OPERATION_LEAVE_FULLSCREEN) {
   675         pendingWindowOperation = PENDING_OPERATION_NONE;
   676         [self setFullscreenSpace:NO];
   677     } else {
   678         if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) {
   679             [NSMenu setMenuBarVisible:NO];
   680         }
   681 
   682         pendingWindowOperation = PENDING_OPERATION_NONE;
   683         /* Force the size change event in case it was delivered earlier
   684            while the window was still animating into place.
   685          */
   686         window->w = 0;
   687         window->h = 0;
   688         [self windowDidResize:aNotification];
   689     }
   690 }
   691 
   692 - (void)windowWillExitFullScreen:(NSNotification *)aNotification
   693 {
   694     SDL_Window *window = _data->window;
   695 
   696     /* As of OS X 10.11, the window seems to need to be resizable when exiting
   697        a Space, in order for it to resize back to its windowed-mode size.
   698      */
   699     SetWindowStyle(window, GetWindowStyle(window) | NSResizableWindowMask);
   700 
   701     isFullscreenSpace = NO;
   702     inFullscreenTransition = YES;
   703 }
   704 
   705 - (void)windowDidFailToExitFullScreen:(NSNotification *)aNotification
   706 {
   707     SDL_Window *window = _data->window;
   708     
   709     if (window->is_destroying) {
   710         return;
   711     }
   712 
   713     SetWindowStyle(window, (NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask));
   714     
   715     isFullscreenSpace = YES;
   716     inFullscreenTransition = NO;
   717     
   718     [self windowDidEnterFullScreen:nil];
   719 }
   720 
   721 - (void)windowDidExitFullScreen:(NSNotification *)aNotification
   722 {
   723     SDL_Window *window = _data->window;
   724     NSWindow *nswindow = _data->nswindow;
   725 
   726     inFullscreenTransition = NO;
   727 
   728     SetWindowStyle(window, GetWindowStyle(window));
   729 
   730     [nswindow setLevel:kCGNormalWindowLevel];
   731 
   732     if (pendingWindowOperation == PENDING_OPERATION_ENTER_FULLSCREEN) {
   733         pendingWindowOperation = PENDING_OPERATION_NONE;
   734         [self setFullscreenSpace:YES];
   735     } else if (pendingWindowOperation == PENDING_OPERATION_MINIMIZE) {
   736         pendingWindowOperation = PENDING_OPERATION_NONE;
   737         [nswindow miniaturize:nil];
   738     } else {
   739         /* Adjust the fullscreen toggle button and readd menu now that we're here. */
   740         if (window->flags & SDL_WINDOW_RESIZABLE) {
   741             /* resizable windows are Spaces-friendly: they get the "go fullscreen" toggle button on their titlebar. */
   742             [nswindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
   743         } else {
   744             [nswindow setCollectionBehavior:NSWindowCollectionBehaviorManaged];
   745         }
   746         [NSMenu setMenuBarVisible:YES];
   747 
   748         pendingWindowOperation = PENDING_OPERATION_NONE;
   749         /* Force the size change event in case it was delivered earlier
   750            while the window was still animating into place.
   751          */
   752         window->w = 0;
   753         window->h = 0;
   754         [self windowDidResize:aNotification];
   755 
   756         /* FIXME: Why does the window get hidden? */
   757         if (window->flags & SDL_WINDOW_SHOWN) {
   758             Cocoa_ShowWindow(SDL_GetVideoDevice(), window);
   759         }
   760     }
   761 }
   762 
   763 -(NSApplicationPresentationOptions)window:(NSWindow *)window willUseFullScreenPresentationOptions:(NSApplicationPresentationOptions)proposedOptions
   764 {
   765     if ((_data->window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) {
   766         return NSApplicationPresentationFullScreen | NSApplicationPresentationHideDock | NSApplicationPresentationHideMenuBar;
   767     } else {
   768         return proposedOptions;
   769     }
   770 }
   771 
   772 
   773 /* We'll respond to key events by doing nothing so we don't beep.
   774  * We could handle key messages here, but we lose some in the NSApp dispatch,
   775  * where they get converted to action messages, etc.
   776  */
   777 - (void)flagsChanged:(NSEvent *)theEvent
   778 {
   779     /*Cocoa_HandleKeyEvent(SDL_GetVideoDevice(), theEvent);*/
   780 }
   781 - (void)keyDown:(NSEvent *)theEvent
   782 {
   783     /*Cocoa_HandleKeyEvent(SDL_GetVideoDevice(), theEvent);*/
   784 }
   785 - (void)keyUp:(NSEvent *)theEvent
   786 {
   787     /*Cocoa_HandleKeyEvent(SDL_GetVideoDevice(), theEvent);*/
   788 }
   789 
   790 /* We'll respond to selectors by doing nothing so we don't beep.
   791  * The escape key gets converted to a "cancel" selector, etc.
   792  */
   793 - (void)doCommandBySelector:(SEL)aSelector
   794 {
   795     /*NSLog(@"doCommandBySelector: %@\n", NSStringFromSelector(aSelector));*/
   796 }
   797 
   798 - (BOOL)processHitTest:(NSEvent *)theEvent
   799 {
   800     SDL_assert(isDragAreaRunning == [_data->nswindow isMovableByWindowBackground]);
   801 
   802     if (_data->window->hit_test) {  /* if no hit-test, skip this. */
   803         const NSPoint location = [theEvent locationInWindow];
   804         const SDL_Point point = { (int) location.x, _data->window->h - (((int) location.y)-1) };
   805         const SDL_HitTestResult rc = _data->window->hit_test(_data->window, &point, _data->window->hit_test_data);
   806         if (rc == SDL_HITTEST_DRAGGABLE) {
   807             if (!isDragAreaRunning) {
   808                 isDragAreaRunning = YES;
   809                 [_data->nswindow setMovableByWindowBackground:YES];
   810             }
   811             return YES;  /* dragging! */
   812         }
   813     }
   814 
   815     if (isDragAreaRunning) {
   816         isDragAreaRunning = NO;
   817         [_data->nswindow setMovableByWindowBackground:NO];
   818         return YES;  /* was dragging, drop event. */
   819     }
   820 
   821     return NO;  /* not a special area, carry on. */
   822 }
   823 
   824 - (void)mouseDown:(NSEvent *)theEvent
   825 {
   826     int button;
   827 
   828     /* Ignore events that aren't inside the client area (i.e. title bar.) */
   829     if ([theEvent window]) {
   830         const NSRect windowRect = [[[theEvent window] contentView] frame];
   831         if (!NSPointInRect([theEvent locationInWindow], windowRect)) {
   832             return;
   833         }
   834     }
   835 
   836     if ([self processHitTest:theEvent]) {
   837         return;  /* dragging, drop event. */
   838     }
   839 
   840     switch ([theEvent buttonNumber]) {
   841     case 0:
   842         if (([theEvent modifierFlags] & NSControlKeyMask) &&
   843 		    GetHintCtrlClickEmulateRightClick()) {
   844             wasCtrlLeft = YES;
   845             button = SDL_BUTTON_RIGHT;
   846         } else {
   847             wasCtrlLeft = NO;
   848             button = SDL_BUTTON_LEFT;
   849         }
   850         break;
   851     case 1:
   852         button = SDL_BUTTON_RIGHT;
   853         break;
   854     case 2:
   855         button = SDL_BUTTON_MIDDLE;
   856         break;
   857     default:
   858         button = [theEvent buttonNumber] + 1;
   859         break;
   860     }
   861     SDL_SendMouseButton(_data->window, 0, SDL_PRESSED, button);
   862 }
   863 
   864 - (void)rightMouseDown:(NSEvent *)theEvent
   865 {
   866     [self mouseDown:theEvent];
   867 }
   868 
   869 - (void)otherMouseDown:(NSEvent *)theEvent
   870 {
   871     [self mouseDown:theEvent];
   872 }
   873 
   874 - (void)mouseUp:(NSEvent *)theEvent
   875 {
   876     int button;
   877 
   878     if ([self processHitTest:theEvent]) {
   879         return;  /* stopped dragging, drop event. */
   880     }
   881 
   882     switch ([theEvent buttonNumber]) {
   883     case 0:
   884         if (wasCtrlLeft) {
   885             button = SDL_BUTTON_RIGHT;
   886             wasCtrlLeft = NO;
   887         } else {
   888             button = SDL_BUTTON_LEFT;
   889         }
   890         break;
   891     case 1:
   892         button = SDL_BUTTON_RIGHT;
   893         break;
   894     case 2:
   895         button = SDL_BUTTON_MIDDLE;
   896         break;
   897     default:
   898         button = [theEvent buttonNumber] + 1;
   899         break;
   900     }
   901     SDL_SendMouseButton(_data->window, 0, SDL_RELEASED, button);
   902 }
   903 
   904 - (void)rightMouseUp:(NSEvent *)theEvent
   905 {
   906     [self mouseUp:theEvent];
   907 }
   908 
   909 - (void)otherMouseUp:(NSEvent *)theEvent
   910 {
   911     [self mouseUp:theEvent];
   912 }
   913 
   914 - (void)mouseMoved:(NSEvent *)theEvent
   915 {
   916     SDL_Mouse *mouse = SDL_GetMouse();
   917     SDL_Window *window = _data->window;
   918     NSPoint point;
   919     int x, y;
   920 
   921     if ([self processHitTest:theEvent]) {
   922         return;  /* dragging, drop event. */
   923     }
   924 
   925     if (mouse->relative_mode) {
   926         return;
   927     }
   928 
   929     point = [theEvent locationInWindow];
   930     x = (int)point.x;
   931     y = (int)(window->h - point.y);
   932 
   933     if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
   934         if (x < 0 || x >= window->w || y < 0 || y >= window->h) {
   935             if (x < 0) {
   936                 x = 0;
   937             } else if (x >= window->w) {
   938                 x = window->w - 1;
   939             }
   940             if (y < 0) {
   941                 y = 0;
   942             } else if (y >= window->h) {
   943                 y = window->h - 1;
   944             }
   945 
   946 #if !SDL_MAC_NO_SANDBOX
   947             CGPoint cgpoint;
   948 
   949             /* When SDL_MAC_NO_SANDBOX is set, this is handled by
   950              * SDL_cocoamousetap.m.
   951              */
   952 
   953             cgpoint.x = window->x + x;
   954             cgpoint.y = window->y + y;
   955 
   956             /* According to the docs, this was deprecated in 10.6, but it's still
   957              * around. The substitute requires a CGEventSource, but I'm not entirely
   958              * sure how we'd procure the right one for this event.
   959              */
   960             CGSetLocalEventsSuppressionInterval(0.0);
   961             CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
   962             CGSetLocalEventsSuppressionInterval(0.25);
   963 
   964             Cocoa_HandleMouseWarp(cgpoint.x, cgpoint.y);
   965 #endif
   966         }
   967     }
   968     SDL_SendMouseMotion(window, 0, 0, x, y);
   969 }
   970 
   971 - (void)mouseDragged:(NSEvent *)theEvent
   972 {
   973     [self mouseMoved:theEvent];
   974 }
   975 
   976 - (void)rightMouseDragged:(NSEvent *)theEvent
   977 {
   978     [self mouseMoved:theEvent];
   979 }
   980 
   981 - (void)otherMouseDragged:(NSEvent *)theEvent
   982 {
   983     [self mouseMoved:theEvent];
   984 }
   985 
   986 - (void)scrollWheel:(NSEvent *)theEvent
   987 {
   988     Cocoa_HandleMouseWheel(_data->window, theEvent);
   989 }
   990 
   991 - (void)touchesBeganWithEvent:(NSEvent *) theEvent
   992 {
   993     NSSet *touches = [theEvent touchesMatchingPhase:NSTouchPhaseAny inView:nil];
   994     int existingTouchCount = 0;
   995 
   996     for (NSTouch* touch in touches) {
   997         if ([touch phase] != NSTouchPhaseBegan) {
   998             existingTouchCount++;
   999         }
  1000     }
  1001     if (existingTouchCount == 0) {
  1002         SDL_TouchID touchID = (SDL_TouchID)(intptr_t)[[touches anyObject] device];
  1003         int numFingers = SDL_GetNumTouchFingers(touchID);
  1004         DLog("Reset Lost Fingers: %d", numFingers);
  1005         for (--numFingers; numFingers >= 0; --numFingers) {
  1006             SDL_Finger* finger = SDL_GetTouchFinger(touchID, numFingers);
  1007             SDL_SendTouch(touchID, finger->id, SDL_FALSE, 0, 0, 0);
  1008         }
  1009     }
  1010 
  1011     DLog("Began Fingers: %lu .. existing: %d", (unsigned long)[touches count], existingTouchCount);
  1012     [self handleTouches:NSTouchPhaseBegan withEvent:theEvent];
  1013 }
  1014 
  1015 - (void)touchesMovedWithEvent:(NSEvent *) theEvent
  1016 {
  1017     [self handleTouches:NSTouchPhaseMoved withEvent:theEvent];
  1018 }
  1019 
  1020 - (void)touchesEndedWithEvent:(NSEvent *) theEvent
  1021 {
  1022     [self handleTouches:NSTouchPhaseEnded withEvent:theEvent];
  1023 }
  1024 
  1025 - (void)touchesCancelledWithEvent:(NSEvent *) theEvent
  1026 {
  1027     [self handleTouches:NSTouchPhaseCancelled withEvent:theEvent];
  1028 }
  1029 
  1030 - (void)handleTouches:(NSTouchPhase) phase withEvent:(NSEvent *) theEvent
  1031 {
  1032     NSSet *touches = [theEvent touchesMatchingPhase:phase inView:nil];
  1033 
  1034     for (NSTouch *touch in touches) {
  1035         const SDL_TouchID touchId = (SDL_TouchID)(intptr_t)[touch device];
  1036         if (SDL_AddTouch(touchId, "") < 0) {
  1037             return;
  1038         }
  1039 
  1040         const SDL_FingerID fingerId = (SDL_FingerID)(intptr_t)[touch identity];
  1041         float x = [touch normalizedPosition].x;
  1042         float y = [touch normalizedPosition].y;
  1043         /* Make the origin the upper left instead of the lower left */
  1044         y = 1.0f - y;
  1045 
  1046         switch (phase) {
  1047         case NSTouchPhaseBegan:
  1048             SDL_SendTouch(touchId, fingerId, SDL_TRUE, x, y, 1.0f);
  1049             break;
  1050         case NSTouchPhaseEnded:
  1051         case NSTouchPhaseCancelled:
  1052             SDL_SendTouch(touchId, fingerId, SDL_FALSE, x, y, 1.0f);
  1053             break;
  1054         case NSTouchPhaseMoved:
  1055             SDL_SendTouchMotion(touchId, fingerId, x, y, 1.0f);
  1056             break;
  1057         default:
  1058             break;
  1059         }
  1060     }
  1061 }
  1062 
  1063 @end
  1064 
  1065 @interface SDLView : NSView {
  1066     SDL_Window *_sdlWindow;
  1067 }
  1068 
  1069 - (void)setSDLWindow:(SDL_Window*)window;
  1070 
  1071 /* The default implementation doesn't pass rightMouseDown to responder chain */
  1072 - (void)rightMouseDown:(NSEvent *)theEvent;
  1073 - (BOOL)mouseDownCanMoveWindow;
  1074 - (void)drawRect:(NSRect)dirtyRect;
  1075 @end
  1076 
  1077 @implementation SDLView
  1078 - (void)setSDLWindow:(SDL_Window*)window
  1079 {
  1080     _sdlWindow = window;
  1081 }
  1082 
  1083 - (void)drawRect:(NSRect)dirtyRect
  1084 {
  1085     SDL_SendWindowEvent(_sdlWindow, SDL_WINDOWEVENT_EXPOSED, 0, 0);
  1086 }
  1087 
  1088 - (void)rightMouseDown:(NSEvent *)theEvent
  1089 {
  1090     [[self nextResponder] rightMouseDown:theEvent];
  1091 }
  1092 
  1093 - (BOOL)mouseDownCanMoveWindow
  1094 {
  1095     /* Always say YES, but this doesn't do anything until we call
  1096        -[NSWindow setMovableByWindowBackground:YES], which we ninja-toggle
  1097        during mouse events when we're using a drag area. */
  1098     return YES;
  1099 }
  1100 
  1101 - (void)resetCursorRects
  1102 {
  1103     [super resetCursorRects];
  1104     SDL_Mouse *mouse = SDL_GetMouse();
  1105 
  1106     if (mouse->cursor_shown && mouse->cur_cursor && !mouse->relative_mode) {
  1107         [self addCursorRect:[self bounds]
  1108                      cursor:mouse->cur_cursor->driverdata];
  1109     } else {
  1110         [self addCursorRect:[self bounds]
  1111                      cursor:[NSCursor invisibleCursor]];
  1112     }
  1113 }
  1114 @end
  1115 
  1116 static int
  1117 SetupWindowData(_THIS, SDL_Window * window, NSWindow *nswindow, SDL_bool created)
  1118 { @autoreleasepool
  1119 {
  1120     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
  1121     SDL_WindowData *data;
  1122 
  1123     /* Allocate the window data */
  1124     window->driverdata = data = (SDL_WindowData *) SDL_calloc(1, sizeof(*data));
  1125     if (!data) {
  1126         return SDL_OutOfMemory();
  1127     }
  1128     data->window = window;
  1129     data->nswindow = nswindow;
  1130     data->created = created;
  1131     data->videodata = videodata;
  1132     data->nscontexts = [[NSMutableArray alloc] init];
  1133 
  1134     /* Create an event listener for the window */
  1135     data->listener = [[Cocoa_WindowListener alloc] init];
  1136 
  1137     /* Fill in the SDL window with the window data */
  1138     {
  1139         NSRect rect = [nswindow contentRectForFrameRect:[nswindow frame]];
  1140         ConvertNSRect([nswindow screen], (window->flags & FULLSCREEN_MASK), &rect);
  1141         window->x = (int)rect.origin.x;
  1142         window->y = (int)rect.origin.y;
  1143         window->w = (int)rect.size.width;
  1144         window->h = (int)rect.size.height;
  1145     }
  1146 
  1147     /* Set up the listener after we create the view */
  1148     [data->listener listen:data];
  1149 
  1150     if ([nswindow isVisible]) {
  1151         window->flags |= SDL_WINDOW_SHOWN;
  1152     } else {
  1153         window->flags &= ~SDL_WINDOW_SHOWN;
  1154     }
  1155 
  1156     {
  1157         unsigned int style = [nswindow styleMask];
  1158 
  1159         if (style == NSBorderlessWindowMask) {
  1160             window->flags |= SDL_WINDOW_BORDERLESS;
  1161         } else {
  1162             window->flags &= ~SDL_WINDOW_BORDERLESS;
  1163         }
  1164         if (style & NSResizableWindowMask) {
  1165             window->flags |= SDL_WINDOW_RESIZABLE;
  1166         } else {
  1167             window->flags &= ~SDL_WINDOW_RESIZABLE;
  1168         }
  1169     }
  1170 
  1171     /* isZoomed always returns true if the window is not resizable */
  1172     if ((window->flags & SDL_WINDOW_RESIZABLE) && [nswindow isZoomed]) {
  1173         window->flags |= SDL_WINDOW_MAXIMIZED;
  1174     } else {
  1175         window->flags &= ~SDL_WINDOW_MAXIMIZED;
  1176     }
  1177 
  1178     if ([nswindow isMiniaturized]) {
  1179         window->flags |= SDL_WINDOW_MINIMIZED;
  1180     } else {
  1181         window->flags &= ~SDL_WINDOW_MINIMIZED;
  1182     }
  1183 
  1184     if ([nswindow isKeyWindow]) {
  1185         window->flags |= SDL_WINDOW_INPUT_FOCUS;
  1186         SDL_SetKeyboardFocus(data->window);
  1187     }
  1188 
  1189     /* Prevents the window's "window device" from being destroyed when it is
  1190      * hidden. See http://www.mikeash.com/pyblog/nsopenglcontext-and-one-shot.html
  1191      */
  1192     [nswindow setOneShot:NO];
  1193 
  1194     /* All done! */
  1195     window->driverdata = data;
  1196     return 0;
  1197 }}
  1198 
  1199 int
  1200 Cocoa_CreateWindow(_THIS, SDL_Window * window)
  1201 { @autoreleasepool
  1202 {
  1203     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
  1204     NSWindow *nswindow;
  1205     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  1206     NSRect rect;
  1207     SDL_Rect bounds;
  1208     unsigned int style;
  1209     NSArray *screens = [NSScreen screens];
  1210 
  1211     Cocoa_GetDisplayBounds(_this, display, &bounds);
  1212     rect.origin.x = window->x;
  1213     rect.origin.y = window->y;
  1214     rect.size.width = window->w;
  1215     rect.size.height = window->h;
  1216     ConvertNSRect([screens objectAtIndex:0], (window->flags & FULLSCREEN_MASK), &rect);
  1217 
  1218     style = GetWindowStyle(window);
  1219 
  1220     /* Figure out which screen to place this window */
  1221     NSScreen *screen = nil;
  1222     for (NSScreen *candidate in screens) {
  1223         NSRect screenRect = [candidate frame];
  1224         if (rect.origin.x >= screenRect.origin.x &&
  1225             rect.origin.x < screenRect.origin.x + screenRect.size.width &&
  1226             rect.origin.y >= screenRect.origin.y &&
  1227             rect.origin.y < screenRect.origin.y + screenRect.size.height) {
  1228             screen = candidate;
  1229             rect.origin.x -= screenRect.origin.x;
  1230             rect.origin.y -= screenRect.origin.y;
  1231         }
  1232     }
  1233 
  1234     @try {
  1235         nswindow = [[SDLWindow alloc] initWithContentRect:rect styleMask:style backing:NSBackingStoreBuffered defer:NO screen:screen];
  1236     }
  1237     @catch (NSException *e) {
  1238         return SDL_SetError("%s", [[e reason] UTF8String]);
  1239     }
  1240     [nswindow setBackgroundColor:[NSColor blackColor]];
  1241 
  1242     if (videodata->allow_spaces) {
  1243         SDL_assert(floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6);
  1244         SDL_assert([nswindow respondsToSelector:@selector(toggleFullScreen:)]);
  1245         /* we put FULLSCREEN_DESKTOP windows in their own Space, without a toggle button or menubar, later */
  1246         if (window->flags & SDL_WINDOW_RESIZABLE) {
  1247             /* resizable windows are Spaces-friendly: they get the "go fullscreen" toggle button on their titlebar. */
  1248             [nswindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
  1249         }
  1250     }
  1251 
  1252     /* Create a default view for this window */
  1253     rect = [nswindow contentRectForFrameRect:[nswindow frame]];
  1254     SDLView *contentView = [[SDLView alloc] initWithFrame:rect];
  1255     [contentView setSDLWindow:window];
  1256 
  1257     if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
  1258         if ([contentView respondsToSelector:@selector(setWantsBestResolutionOpenGLSurface:)]) {
  1259             [contentView setWantsBestResolutionOpenGLSurface:YES];
  1260         }
  1261     }
  1262 
  1263     [nswindow setContentView: contentView];
  1264     [contentView release];
  1265 
  1266     /* Allow files and folders to be dragged onto the window by users */
  1267     [nswindow registerForDraggedTypes:[NSArray arrayWithObject:(NSString *)kUTTypeFileURL]];
  1268 
  1269     if (SetupWindowData(_this, window, nswindow, SDL_TRUE) < 0) {
  1270         [nswindow release];
  1271         return -1;
  1272     }
  1273     return 0;
  1274 }}
  1275 
  1276 int
  1277 Cocoa_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
  1278 { @autoreleasepool
  1279 {
  1280     NSWindow *nswindow = (NSWindow *) data;
  1281     NSString *title;
  1282 
  1283     /* Query the title from the existing window */
  1284     title = [nswindow title];
  1285     if (title) {
  1286         window->title = SDL_strdup([title UTF8String]);
  1287     }
  1288 
  1289     return SetupWindowData(_this, window, nswindow, SDL_FALSE);
  1290 }}
  1291 
  1292 void
  1293 Cocoa_SetWindowTitle(_THIS, SDL_Window * window)
  1294 { @autoreleasepool
  1295 {
  1296     const char *title = window->title ? window->title : "";
  1297     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
  1298     NSString *string = [[NSString alloc] initWithUTF8String:title];
  1299     [nswindow setTitle:string];
  1300     [string release];
  1301 }}
  1302 
  1303 void
  1304 Cocoa_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
  1305 { @autoreleasepool
  1306 {
  1307     NSImage *nsimage = Cocoa_CreateImage(icon);
  1308 
  1309     if (nsimage) {
  1310         [NSApp setApplicationIconImage:nsimage];
  1311     }
  1312 }}
  1313 
  1314 void
  1315 Cocoa_SetWindowPosition(_THIS, SDL_Window * window)
  1316 { @autoreleasepool
  1317 {
  1318     SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
  1319     NSWindow *nswindow = windata->nswindow;
  1320     NSRect rect;
  1321     Uint32 moveHack;
  1322 
  1323     rect.origin.x = window->x;
  1324     rect.origin.y = window->y;
  1325     rect.size.width = window->w;
  1326     rect.size.height = window->h;
  1327     ConvertNSRect([nswindow screen], (window->flags & FULLSCREEN_MASK), &rect);
  1328 
  1329     moveHack = s_moveHack;
  1330     s_moveHack = 0;
  1331     [nswindow setFrameOrigin:rect.origin];
  1332     s_moveHack = moveHack;
  1333 
  1334     ScheduleContextUpdates(windata);
  1335 }}
  1336 
  1337 void
  1338 Cocoa_SetWindowSize(_THIS, SDL_Window * window)
  1339 { @autoreleasepool
  1340 {
  1341     SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
  1342     NSWindow *nswindow = windata->nswindow;
  1343     NSRect rect;
  1344     Uint32 moveHack;
  1345 
  1346     /* Cocoa will resize the window from the bottom-left rather than the
  1347      * top-left when -[nswindow setContentSize:] is used, so we must set the
  1348      * entire frame based on the new size, in order to preserve the position.
  1349      */
  1350     rect.origin.x = window->x;
  1351     rect.origin.y = window->y;
  1352     rect.size.width = window->w;
  1353     rect.size.height = window->h;
  1354     ConvertNSRect([nswindow screen], (window->flags & FULLSCREEN_MASK), &rect);
  1355 
  1356     moveHack = s_moveHack;
  1357     s_moveHack = 0;
  1358     [nswindow setFrame:[nswindow frameRectForContentRect:rect] display:YES];
  1359     s_moveHack = moveHack;
  1360 
  1361     ScheduleContextUpdates(windata);
  1362 }}
  1363 
  1364 void
  1365 Cocoa_SetWindowMinimumSize(_THIS, SDL_Window * window)
  1366 { @autoreleasepool
  1367 {
  1368     SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
  1369 
  1370     NSSize minSize;
  1371     minSize.width = window->min_w;
  1372     minSize.height = window->min_h;
  1373 
  1374     [windata->nswindow setContentMinSize:minSize];
  1375 }}
  1376 
  1377 void
  1378 Cocoa_SetWindowMaximumSize(_THIS, SDL_Window * window)
  1379 { @autoreleasepool
  1380 {
  1381     SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
  1382 
  1383     NSSize maxSize;
  1384     maxSize.width = window->max_w;
  1385     maxSize.height = window->max_h;
  1386 
  1387     [windata->nswindow setContentMaxSize:maxSize];
  1388 }}
  1389 
  1390 void
  1391 Cocoa_ShowWindow(_THIS, SDL_Window * window)
  1392 { @autoreleasepool
  1393 {
  1394     SDL_WindowData *windowData = ((SDL_WindowData *) window->driverdata);
  1395     NSWindow *nswindow = windowData->nswindow;
  1396 
  1397     if (![nswindow isMiniaturized]) {
  1398         [windowData->listener pauseVisibleObservation];
  1399         [nswindow makeKeyAndOrderFront:nil];
  1400         [windowData->listener resumeVisibleObservation];
  1401     }
  1402 }}
  1403 
  1404 void
  1405 Cocoa_HideWindow(_THIS, SDL_Window * window)
  1406 { @autoreleasepool
  1407 {
  1408     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
  1409 
  1410     [nswindow orderOut:nil];
  1411 }}
  1412 
  1413 void
  1414 Cocoa_RaiseWindow(_THIS, SDL_Window * window)
  1415 { @autoreleasepool
  1416 {
  1417     SDL_WindowData *windowData = ((SDL_WindowData *) window->driverdata);
  1418     NSWindow *nswindow = windowData->nswindow;
  1419 
  1420     /* makeKeyAndOrderFront: has the side-effect of deminiaturizing and showing
  1421        a minimized or hidden window, so check for that before showing it.
  1422      */
  1423     [windowData->listener pauseVisibleObservation];
  1424     if (![nswindow isMiniaturized] && [nswindow isVisible]) {
  1425         [NSApp activateIgnoringOtherApps:YES];
  1426         [nswindow makeKeyAndOrderFront:nil];
  1427     }
  1428     [windowData->listener resumeVisibleObservation];
  1429 }}
  1430 
  1431 void
  1432 Cocoa_MaximizeWindow(_THIS, SDL_Window * window)
  1433 { @autoreleasepool
  1434 {
  1435     SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
  1436     NSWindow *nswindow = windata->nswindow;
  1437 
  1438     [nswindow zoom:nil];
  1439 
  1440     ScheduleContextUpdates(windata);
  1441 }}
  1442 
  1443 void
  1444 Cocoa_MinimizeWindow(_THIS, SDL_Window * window)
  1445 { @autoreleasepool
  1446 {
  1447     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1448     NSWindow *nswindow = data->nswindow;
  1449 
  1450     if ([data->listener isInFullscreenSpaceTransition]) {
  1451         [data->listener addPendingWindowOperation:PENDING_OPERATION_MINIMIZE];
  1452     } else {
  1453         [nswindow miniaturize:nil];
  1454     }
  1455 }}
  1456 
  1457 void
  1458 Cocoa_RestoreWindow(_THIS, SDL_Window * window)
  1459 { @autoreleasepool
  1460 {
  1461     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
  1462 
  1463     if ([nswindow isMiniaturized]) {
  1464         [nswindow deminiaturize:nil];
  1465     } else if ((window->flags & SDL_WINDOW_RESIZABLE) && [nswindow isZoomed]) {
  1466         [nswindow zoom:nil];
  1467     }
  1468 }}
  1469 
  1470 static NSWindow *
  1471 Cocoa_RebuildWindow(SDL_WindowData * data, NSWindow * nswindow, unsigned style)
  1472 {
  1473     if (!data->created) {
  1474         /* Don't mess with other people's windows... */
  1475         return nswindow;
  1476     }
  1477 
  1478     [data->listener close];
  1479     data->nswindow = [[SDLWindow alloc] initWithContentRect:[[nswindow contentView] frame] styleMask:style backing:NSBackingStoreBuffered defer:NO screen:[nswindow screen]];
  1480     [data->nswindow setContentView:[nswindow contentView]];
  1481     [data->nswindow registerForDraggedTypes:[NSArray arrayWithObject:(NSString *)kUTTypeFileURL]];
  1482     /* See comment in SetupWindowData. */
  1483     [data->nswindow setOneShot:NO];
  1484     [data->listener listen:data];
  1485 
  1486     [nswindow close];
  1487 
  1488     return data->nswindow;
  1489 }
  1490 
  1491 void
  1492 Cocoa_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
  1493 { @autoreleasepool
  1494 {
  1495     if (SetWindowStyle(window, GetWindowStyle(window))) {
  1496         if (bordered) {
  1497             Cocoa_SetWindowTitle(_this, window);  /* this got blanked out. */
  1498         }
  1499     }
  1500 }}
  1501 
  1502 
  1503 void
  1504 Cocoa_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
  1505 { @autoreleasepool
  1506 {
  1507     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1508     NSWindow *nswindow = data->nswindow;
  1509     NSRect rect;
  1510 
  1511     /* The view responder chain gets messed with during setStyleMask */
  1512     if ([[nswindow contentView] nextResponder] == data->listener) {
  1513         [[nswindow contentView] setNextResponder:nil];
  1514     }
  1515 
  1516     if (fullscreen) {
  1517         SDL_Rect bounds;
  1518 
  1519         Cocoa_GetDisplayBounds(_this, display, &bounds);
  1520         rect.origin.x = bounds.x;
  1521         rect.origin.y = bounds.y;
  1522         rect.size.width = bounds.w;
  1523         rect.size.height = bounds.h;
  1524         ConvertNSRect([nswindow screen], fullscreen, &rect);
  1525 
  1526         /* Hack to fix origin on Mac OS X 10.4 */
  1527         NSRect screenRect = [[nswindow screen] frame];
  1528         if (screenRect.size.height >= 1.0f) {
  1529             rect.origin.y += (screenRect.size.height - rect.size.height);
  1530         }
  1531 
  1532         if ([nswindow respondsToSelector: @selector(setStyleMask:)]) {
  1533             [nswindow performSelector: @selector(setStyleMask:) withObject: (id)NSBorderlessWindowMask];
  1534         } else {
  1535             nswindow = Cocoa_RebuildWindow(data, nswindow, NSBorderlessWindowMask);
  1536         }
  1537     } else {
  1538         rect.origin.x = window->windowed.x;
  1539         rect.origin.y = window->windowed.y;
  1540         rect.size.width = window->windowed.w;
  1541         rect.size.height = window->windowed.h;
  1542         ConvertNSRect([nswindow screen], fullscreen, &rect);
  1543 
  1544         if ([nswindow respondsToSelector: @selector(setStyleMask:)]) {
  1545             [nswindow performSelector: @selector(setStyleMask:) withObject: (id)(uintptr_t)GetWindowStyle(window)];
  1546 
  1547             /* Hack to restore window decorations on Mac OS X 10.10 */
  1548             NSRect frameRect = [nswindow frame];
  1549             [nswindow setFrame:NSMakeRect(frameRect.origin.x, frameRect.origin.y, frameRect.size.width + 1, frameRect.size.height) display:NO];
  1550             [nswindow setFrame:frameRect display:NO];
  1551         } else {
  1552             nswindow = Cocoa_RebuildWindow(data, nswindow, GetWindowStyle(window));
  1553         }
  1554     }
  1555 
  1556     /* The view responder chain gets messed with during setStyleMask */
  1557     if ([[nswindow contentView] nextResponder] != data->listener) {
  1558         [[nswindow contentView] setNextResponder:data->listener];
  1559     }
  1560 
  1561     s_moveHack = 0;
  1562     [nswindow setContentSize:rect.size];
  1563     [nswindow setFrameOrigin:rect.origin];
  1564     s_moveHack = SDL_GetTicks();
  1565 
  1566     /* When the window style changes the title is cleared */
  1567     if (!fullscreen) {
  1568         Cocoa_SetWindowTitle(_this, window);
  1569     }
  1570 
  1571     if (SDL_ShouldAllowTopmost() && fullscreen) {
  1572         /* OpenGL is rendering to the window, so make it visible! */
  1573         [nswindow setLevel:CGShieldingWindowLevel()];
  1574     } else {
  1575         [nswindow setLevel:kCGNormalWindowLevel];
  1576     }
  1577 
  1578     if ([nswindow isVisible] || fullscreen) {
  1579         [data->listener pauseVisibleObservation];
  1580         [nswindow makeKeyAndOrderFront:nil];
  1581         [data->listener resumeVisibleObservation];
  1582     }
  1583 
  1584     ScheduleContextUpdates(data);
  1585 }}
  1586 
  1587 int
  1588 Cocoa_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
  1589 {
  1590     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  1591     CGDirectDisplayID display_id = ((SDL_DisplayData *)display->driverdata)->display;
  1592     const uint32_t tableSize = 256;
  1593     CGGammaValue redTable[tableSize];
  1594     CGGammaValue greenTable[tableSize];
  1595     CGGammaValue blueTable[tableSize];
  1596     uint32_t i;
  1597     float inv65535 = 1.0f / 65535.0f;
  1598 
  1599     /* Extract gamma values into separate tables, convert to floats between 0.0 and 1.0 */
  1600     for (i = 0; i < 256; i++) {
  1601         redTable[i] = ramp[0*256+i] * inv65535;
  1602         greenTable[i] = ramp[1*256+i] * inv65535;
  1603         blueTable[i] = ramp[2*256+i] * inv65535;
  1604     }
  1605 
  1606     if (CGSetDisplayTransferByTable(display_id, tableSize,
  1607                                     redTable, greenTable, blueTable) != CGDisplayNoErr) {
  1608         return SDL_SetError("CGSetDisplayTransferByTable()");
  1609     }
  1610     return 0;
  1611 }
  1612 
  1613 int
  1614 Cocoa_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp)
  1615 {
  1616     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
  1617     CGDirectDisplayID display_id = ((SDL_DisplayData *)display->driverdata)->display;
  1618     const uint32_t tableSize = 256;
  1619     CGGammaValue redTable[tableSize];
  1620     CGGammaValue greenTable[tableSize];
  1621     CGGammaValue blueTable[tableSize];
  1622     uint32_t i, tableCopied;
  1623 
  1624     if (CGGetDisplayTransferByTable(display_id, tableSize,
  1625                                     redTable, greenTable, blueTable, &tableCopied) != CGDisplayNoErr) {
  1626         return SDL_SetError("CGGetDisplayTransferByTable()");
  1627     }
  1628 
  1629     for (i = 0; i < tableCopied; i++) {
  1630         ramp[0*256+i] = (Uint16)(redTable[i] * 65535.0f);
  1631         ramp[1*256+i] = (Uint16)(greenTable[i] * 65535.0f);
  1632         ramp[2*256+i] = (Uint16)(blueTable[i] * 65535.0f);
  1633     }
  1634     return 0;
  1635 }
  1636 
  1637 void
  1638 Cocoa_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
  1639 {
  1640     /* Move the cursor to the nearest point in the window */
  1641     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1642     if (grabbed && data && ![data->listener isMoving]) {
  1643         int x, y;
  1644         CGPoint cgpoint;
  1645 
  1646         SDL_GetMouseState(&x, &y);
  1647         cgpoint.x = window->x + x;
  1648         cgpoint.y = window->y + y;
  1649 
  1650         Cocoa_HandleMouseWarp(cgpoint.x, cgpoint.y);
  1651 
  1652         DLog("Returning cursor to (%g, %g)", cgpoint.x, cgpoint.y);
  1653         CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
  1654     }
  1655 
  1656     if ( data && (window->flags & SDL_WINDOW_FULLSCREEN) ) {
  1657         if (SDL_ShouldAllowTopmost() && (window->flags & SDL_WINDOW_INPUT_FOCUS)
  1658             && ![data->listener isInFullscreenSpace]) {
  1659             /* OpenGL is rendering to the window, so make it visible! */
  1660             /* Doing this in 10.11 while in a Space breaks things (bug #3152) */
  1661             [data->nswindow setLevel:CGShieldingWindowLevel()];
  1662         } else {
  1663             [data->nswindow setLevel:kCGNormalWindowLevel];
  1664         }
  1665     }
  1666 }
  1667 
  1668 void
  1669 Cocoa_DestroyWindow(_THIS, SDL_Window * window)
  1670 { @autoreleasepool
  1671 {
  1672     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1673 
  1674     if (data) {
  1675         if ([data->listener isInFullscreenSpace]) {
  1676             [NSMenu setMenuBarVisible:YES];
  1677         }
  1678         [data->listener close];
  1679         [data->listener release];
  1680         if (data->created) {
  1681             [data->nswindow close];
  1682         }
  1683 
  1684         NSArray *contexts = [[data->nscontexts copy] autorelease];
  1685         for (SDLOpenGLContext *context in contexts) {
  1686             /* Calling setWindow:NULL causes the context to remove itself from the context list. */            
  1687             [context setWindow:NULL];
  1688         }
  1689         [data->nscontexts release];
  1690 
  1691         SDL_free(data);
  1692     }
  1693     window->driverdata = NULL;
  1694 }}
  1695 
  1696 SDL_bool
  1697 Cocoa_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
  1698 {
  1699     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
  1700 
  1701     if (info->version.major <= SDL_MAJOR_VERSION) {
  1702         info->subsystem = SDL_SYSWM_COCOA;
  1703         info->info.cocoa.window = nswindow;
  1704         return SDL_TRUE;
  1705     } else {
  1706         SDL_SetError("Application not compiled with SDL %d.%d\n",
  1707                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
  1708         return SDL_FALSE;
  1709     }
  1710 }
  1711 
  1712 SDL_bool
  1713 Cocoa_IsWindowInFullscreenSpace(SDL_Window * window)
  1714 {
  1715     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1716 
  1717     if ([data->listener isInFullscreenSpace]) {
  1718         return SDL_TRUE;
  1719     } else {
  1720         return SDL_FALSE;
  1721     }
  1722 }
  1723 
  1724 SDL_bool
  1725 Cocoa_SetWindowFullscreenSpace(SDL_Window * window, SDL_bool state)
  1726 { @autoreleasepool
  1727 {
  1728     SDL_bool succeeded = SDL_FALSE;
  1729     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1730 
  1731     if ([data->listener setFullscreenSpace:(state ? YES : NO)]) {
  1732         const int maxattempts = 3;
  1733         int attempt = 0;
  1734         while (++attempt <= maxattempts) {
  1735             /* Wait for the transition to complete, so application changes
  1736              take effect properly (e.g. setting the window size, etc.)
  1737              */
  1738             const int limit = 10000;
  1739             int count = 0;
  1740             while ([data->listener isInFullscreenSpaceTransition]) {
  1741                 if ( ++count == limit ) {
  1742                     /* Uh oh, transition isn't completing. Should we assert? */
  1743                     break;
  1744                 }
  1745                 SDL_Delay(1);
  1746                 SDL_PumpEvents();
  1747             }
  1748             if ([data->listener isInFullscreenSpace] == (state ? YES : NO))
  1749                 break;
  1750             /* Try again, the last attempt was interrupted by user gestures */
  1751             if (![data->listener setFullscreenSpace:(state ? YES : NO)])
  1752                 break; /* ??? */
  1753         }
  1754         /* Return TRUE to prevent non-space fullscreen logic from running */
  1755         succeeded = SDL_TRUE;
  1756     }
  1757 
  1758     return succeeded;
  1759 }}
  1760 
  1761 int
  1762 Cocoa_SetWindowHitTest(SDL_Window * window, SDL_bool enabled)
  1763 {
  1764     return 0;  /* just succeed, the real work is done elsewhere. */
  1765 }
  1766 
  1767 #endif /* SDL_VIDEO_DRIVER_COCOA */
  1768 
  1769 /* vi: set ts=4 sw=4 expandtab: */