src/video/cocoa/SDL_cocoawindow.m
author Sam Lantinga <slouken@libsdl.org>
Wed, 07 Nov 2012 15:55:43 -0800
changeset 6662 698c2e533a7e
parent 6514 e94c2eaaa1ab
child 6666 018f8019ce36
permissions -rw-r--r--
SDL no longer grabs the keyboard by default on X11.
You can re-enable that functionality by setting a new hint SDL_HINT_GRAB_KEYBOARD
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "SDL_config.h"
    22 
    23 #if SDL_VIDEO_DRIVER_COCOA
    24 
    25 #include "SDL_syswm.h"
    26 #include "SDL_timer.h"  /* For SDL_GetTicks() */
    27 #include "../SDL_sysvideo.h"
    28 #include "../../events/SDL_keyboard_c.h"
    29 #include "../../events/SDL_mouse_c.h"
    30 #include "../../events/SDL_touch_c.h"
    31 #include "../../events/SDL_windowevents_c.h"
    32 #include "SDL_cocoavideo.h"
    33 #include "SDL_cocoashape.h"
    34 #include "SDL_cocoamouse.h"
    35 
    36 
    37 static Uint32 s_moveHack;
    38 
    39 static __inline__ void ConvertNSRect(NSRect *r)
    40 {
    41     r->origin.y = CGDisplayPixelsHigh(kCGDirectMainDisplay) - r->origin.y - r->size.height;
    42 }
    43 
    44 @implementation Cocoa_WindowListener
    45 
    46 - (void)listen:(SDL_WindowData *)data
    47 {
    48     NSNotificationCenter *center;
    49     NSWindow *window = data->nswindow;
    50     NSView *view = [window contentView];
    51 
    52     _data = data;
    53 
    54     center = [NSNotificationCenter defaultCenter];
    55 
    56     if ([window delegate] != nil) {
    57         [center addObserver:self selector:@selector(windowDidExpose:) name:NSWindowDidExposeNotification object:window];
    58         [center addObserver:self selector:@selector(windowDidMove:) name:NSWindowDidMoveNotification object:window];
    59         [center addObserver:self selector:@selector(windowDidResize:) name:NSWindowDidResizeNotification object:window];
    60         [center addObserver:self selector:@selector(windowDidMiniaturize:) name:NSWindowDidMiniaturizeNotification object:window];
    61         [center addObserver:self selector:@selector(windowDidDeminiaturize:) name:NSWindowDidDeminiaturizeNotification object:window];
    62         [center addObserver:self selector:@selector(windowDidBecomeKey:) name:NSWindowDidBecomeKeyNotification object:window];
    63         [center addObserver:self selector:@selector(windowDidResignKey:) name:NSWindowDidResignKeyNotification object:window];
    64     } else {
    65         [window setDelegate:self];
    66     }
    67 
    68     [window setNextResponder:self];
    69     [window setAcceptsMouseMovedEvents:YES];
    70 
    71     [view setNextResponder:self];
    72 
    73 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
    74     if ([view respondsToSelector:@selector(setAcceptsTouchEvents:)]) {
    75         [view setAcceptsTouchEvents:YES];
    76     }
    77 #endif
    78 }
    79 
    80 - (void)close
    81 {
    82     NSNotificationCenter *center;
    83     NSWindow *window = _data->nswindow;
    84     NSView *view = [window contentView];
    85 
    86     center = [NSNotificationCenter defaultCenter];
    87 
    88     if ([window delegate] != self) {
    89         [center removeObserver:self name:NSWindowDidExposeNotification object:window];
    90         [center removeObserver:self name:NSWindowDidMoveNotification object:window];
    91         [center removeObserver:self name:NSWindowDidResizeNotification object:window];
    92         [center removeObserver:self name:NSWindowDidMiniaturizeNotification object:window];
    93         [center removeObserver:self name:NSWindowDidDeminiaturizeNotification object:window];
    94         [center removeObserver:self name:NSWindowDidBecomeKeyNotification object:window];
    95         [center removeObserver:self name:NSWindowDidResignKeyNotification object:window];
    96     } else {
    97         [window setDelegate:nil];
    98     }
    99 
   100     if ([window nextResponder] == self) {
   101         [window setNextResponder:nil];
   102     }
   103     if ([view nextResponder] == self) {
   104         [view setNextResponder:nil];
   105     }
   106 }
   107 
   108 - (BOOL)windowShouldClose:(id)sender
   109 {
   110     SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_CLOSE, 0, 0);
   111     return NO;
   112 }
   113 
   114 - (void)windowDidExpose:(NSNotification *)aNotification
   115 {
   116     SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_EXPOSED, 0, 0);
   117 }
   118 
   119 - (void)windowDidMove:(NSNotification *)aNotification
   120 {
   121     int x, y;
   122     SDL_VideoDevice *device = SDL_GetVideoDevice();
   123     SDL_Window *window = _data->window;
   124     NSWindow *nswindow = _data->nswindow;
   125     NSRect rect = [nswindow contentRectForFrameRect:[nswindow frame]];
   126     ConvertNSRect(&rect);
   127 
   128     if (s_moveHack) {
   129         SDL_bool blockMove = ((SDL_GetTicks() - s_moveHack) < 500);
   130 
   131         s_moveHack = 0;
   132 
   133         if (blockMove) {
   134             /* Cocoa is adjusting the window in response to a mode change */
   135             rect.origin.x = window->x;
   136             rect.origin.y = window->y;
   137             ConvertNSRect(&rect);
   138             [nswindow setFrameOrigin:rect.origin];
   139             return;
   140         }
   141     }
   142 
   143     x = (int)rect.origin.x;
   144     y = (int)rect.origin.y;
   145 
   146     if (window == device->current_glwin) {
   147         [((NSOpenGLContext *) device->current_glctx) update];
   148     }
   149 
   150     SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, x, y);
   151 }
   152 
   153 - (void)windowDidResize:(NSNotification *)aNotification
   154 {
   155     SDL_VideoDevice *device = SDL_GetVideoDevice();
   156     int x, y, w, h;
   157     NSRect rect = [_data->nswindow contentRectForFrameRect:[_data->nswindow frame]];
   158     ConvertNSRect(&rect);
   159     x = (int)rect.origin.x;
   160     y = (int)rect.origin.y;
   161     w = (int)rect.size.width;
   162     h = (int)rect.size.height;
   163     if (SDL_IsShapedWindow(_data->window))
   164         Cocoa_ResizeWindowShape(_data->window);
   165 
   166     if (_data->window == device->current_glwin) {
   167         [((NSOpenGLContext *) device->current_glctx) update];
   168     }
   169 
   170     /* The window can move during a resize event, such as when maximizing
   171        or resizing from a corner */
   172     SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_MOVED, x, y);
   173     SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_RESIZED, w, h);
   174 }
   175 
   176 - (void)windowDidMiniaturize:(NSNotification *)aNotification
   177 {
   178     SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
   179 }
   180 
   181 - (void)windowDidDeminiaturize:(NSNotification *)aNotification
   182 {
   183     SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_RESTORED, 0, 0);
   184 }
   185 
   186 - (void)windowDidBecomeKey:(NSNotification *)aNotification
   187 {
   188     SDL_Window *window = _data->window;
   189 
   190     /* We're going to get keyboard events, since we're key. */
   191     SDL_SetKeyboardFocus(window);
   192 
   193     /* If we just gained focus we need the updated mouse position */
   194     {
   195         NSPoint point;
   196         int x, y;
   197 
   198         point = [_data->nswindow mouseLocationOutsideOfEventStream];
   199         x = (int)point.x;
   200         y = (int)(window->h - point.y);
   201 
   202         if (x >= 0 && x < window->w && y >= 0 && y < window->h) {
   203             if (SDL_GetMouseFocus() != window) {
   204                 [self mouseEntered:nil];
   205             }
   206             SDL_SendMouseMotion(window, 0, x, y);
   207         }
   208     }
   209 
   210     /* Check to see if someone updated the clipboard */
   211     Cocoa_CheckClipboardUpdate(_data->videodata);
   212 }
   213 
   214 - (void)windowDidResignKey:(NSNotification *)aNotification
   215 {
   216     /* Some other window will get mouse events, since we're not key. */
   217     if (SDL_GetMouseFocus() == _data->window) {
   218         SDL_SetMouseFocus(NULL);
   219     }
   220 
   221     /* Some other window will get keyboard events, since we're not key. */
   222     if (SDL_GetKeyboardFocus() == _data->window) {
   223         SDL_SetKeyboardFocus(NULL);
   224     }
   225 }
   226 
   227 // We'll respond to key events by doing nothing so we don't beep.
   228 // We could handle key messages here, but we lose some in the NSApp dispatch,
   229 // where they get converted to action messages, etc.
   230 - (void)flagsChanged:(NSEvent *)theEvent
   231 {
   232     //Cocoa_HandleKeyEvent(SDL_GetVideoDevice(), theEvent);
   233 }
   234 - (void)keyDown:(NSEvent *)theEvent
   235 {
   236     //Cocoa_HandleKeyEvent(SDL_GetVideoDevice(), theEvent);
   237 }
   238 - (void)keyUp:(NSEvent *)theEvent
   239 {
   240     //Cocoa_HandleKeyEvent(SDL_GetVideoDevice(), theEvent);
   241 }
   242 
   243 // We'll respond to selectors by doing nothing so we don't beep.
   244 // The escape key gets converted to a "cancel" selector, etc.
   245 - (void)doCommandBySelector:(SEL)aSelector
   246 {
   247     //NSLog(@"doCommandBySelector: %@\n", NSStringFromSelector(aSelector));
   248 }
   249 
   250 - (void)mouseDown:(NSEvent *)theEvent
   251 {
   252     int button;
   253 
   254     switch ([theEvent buttonNumber]) {
   255     case 0:
   256         button = SDL_BUTTON_LEFT;
   257         break;
   258     case 1:
   259         button = SDL_BUTTON_RIGHT;
   260         break;
   261     case 2:
   262         button = SDL_BUTTON_MIDDLE;
   263         break;
   264     default:
   265         button = [theEvent buttonNumber] + 1;
   266         break;
   267     }
   268     SDL_SendMouseButton(_data->window, SDL_PRESSED, button);
   269 }
   270 
   271 - (void)rightMouseDown:(NSEvent *)theEvent
   272 {
   273     [self mouseDown:theEvent];
   274 }
   275 
   276 - (void)otherMouseDown:(NSEvent *)theEvent
   277 {
   278     [self mouseDown:theEvent];
   279 }
   280 
   281 - (void)mouseUp:(NSEvent *)theEvent
   282 {
   283     int button;
   284 
   285     switch ([theEvent buttonNumber]) {
   286     case 0:
   287         button = SDL_BUTTON_LEFT;
   288         break;
   289     case 1:
   290         button = SDL_BUTTON_RIGHT;
   291         break;
   292     case 2:
   293         button = SDL_BUTTON_MIDDLE;
   294         break;
   295     default:
   296         button = [theEvent buttonNumber] + 1;
   297         break;
   298     }
   299     SDL_SendMouseButton(_data->window, SDL_RELEASED, button);
   300 }
   301 
   302 - (void)rightMouseUp:(NSEvent *)theEvent
   303 {
   304     [self mouseUp:theEvent];
   305 }
   306 
   307 - (void)otherMouseUp:(NSEvent *)theEvent
   308 {
   309     [self mouseUp:theEvent];
   310 }
   311 
   312 - (void)mouseEntered:(NSEvent *)theEvent
   313 {
   314     SDL_SetMouseFocus(_data->window);
   315 
   316     SDL_SetCursor(NULL);
   317 }
   318 
   319 - (void)mouseExited:(NSEvent *)theEvent
   320 {
   321     SDL_Window *window = _data->window;
   322 
   323     if (SDL_GetMouseFocus() == window) {
   324         if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
   325             int x, y;
   326             NSPoint point;
   327             CGPoint cgpoint;
   328 
   329             point = [theEvent locationInWindow];
   330             point.y = window->h - point.y;
   331 
   332             SDL_SendMouseMotion(window, 0, (int)point.x, (int)point.y);
   333             SDL_GetMouseState(&x, &y);
   334             cgpoint.x = window->x + x;
   335             cgpoint.y = window->y + y;
   336             CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
   337         } else {
   338             SDL_SetMouseFocus(NULL);
   339             SDL_SetCursor(NULL);
   340         }
   341     }
   342 }
   343 
   344 - (void)mouseMoved:(NSEvent *)theEvent
   345 {
   346     SDL_Mouse *mouse = SDL_GetMouse();
   347     SDL_Window *window = _data->window;
   348     NSPoint point;
   349     int x, y;
   350 
   351     if (mouse->relative_mode) {
   352         return;
   353     }
   354 
   355     point = [theEvent locationInWindow];
   356     x = (int)point.x;
   357     y = (int)(window->h - point.y);
   358 
   359     if (x < 0 || x >= window->w || y < 0 || y >= window->h) {
   360         if (SDL_GetMouseFocus() == window) {
   361             [self mouseExited:theEvent];
   362         }
   363     } else {
   364         if (SDL_GetMouseFocus() != window) {
   365             [self mouseEntered:theEvent];
   366         }
   367         SDL_SendMouseMotion(window, 0, x, y);
   368     }
   369 }
   370 
   371 - (void)mouseDragged:(NSEvent *)theEvent
   372 {
   373     [self mouseMoved:theEvent];
   374 }
   375 
   376 - (void)rightMouseDragged:(NSEvent *)theEvent
   377 {
   378     [self mouseMoved:theEvent];
   379 }
   380 
   381 - (void)otherMouseDragged:(NSEvent *)theEvent
   382 {
   383     [self mouseMoved:theEvent];
   384 }
   385 
   386 - (void)scrollWheel:(NSEvent *)theEvent
   387 {
   388     Cocoa_HandleMouseWheel(_data->window, theEvent);
   389 }
   390 
   391 - (void)touchesBeganWithEvent:(NSEvent *) theEvent
   392 {
   393     [self handleTouches:COCOA_TOUCH_DOWN withEvent:theEvent];
   394 }
   395 
   396 - (void)touchesMovedWithEvent:(NSEvent *) theEvent
   397 {
   398     [self handleTouches:COCOA_TOUCH_MOVE withEvent:theEvent];
   399 }
   400 
   401 - (void)touchesEndedWithEvent:(NSEvent *) theEvent
   402 {
   403     [self handleTouches:COCOA_TOUCH_UP withEvent:theEvent];
   404 }
   405 
   406 - (void)touchesCancelledWithEvent:(NSEvent *) theEvent
   407 {
   408     [self handleTouches:COCOA_TOUCH_CANCELLED withEvent:theEvent];
   409 }
   410 
   411 - (void)handleTouches:(cocoaTouchType)type withEvent:(NSEvent *)event
   412 {
   413 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
   414     NSSet *touches = 0;
   415     NSEnumerator *enumerator;
   416     NSTouch *touch;
   417 
   418     switch (type) {
   419         case COCOA_TOUCH_DOWN:
   420             touches = [event touchesMatchingPhase:NSTouchPhaseBegan inView:nil];
   421             break;
   422         case COCOA_TOUCH_UP:
   423         case COCOA_TOUCH_CANCELLED:
   424             touches = [event touchesMatchingPhase:NSTouchPhaseEnded inView:nil];
   425             break;
   426         case COCOA_TOUCH_MOVE:
   427             touches = [event touchesMatchingPhase:NSTouchPhaseMoved inView:nil];
   428             break;
   429     }
   430 
   431     enumerator = [touches objectEnumerator];
   432     touch = (NSTouch*)[enumerator nextObject];
   433     while (touch) {
   434         const SDL_TouchID touchId = (SDL_TouchID) ((size_t) [touch device]);
   435         if (!SDL_GetTouch(touchId)) {
   436             SDL_Touch touch;
   437 
   438             touch.id = touchId;
   439             touch.x_min = 0;
   440             touch.x_max = 1;
   441             touch.native_xres = touch.x_max - touch.x_min;
   442             touch.y_min = 0;
   443             touch.y_max = 1;
   444             touch.native_yres = touch.y_max - touch.y_min;
   445             touch.pressure_min = 0;
   446             touch.pressure_max = 1;
   447             touch.native_pressureres = touch.pressure_max - touch.pressure_min;
   448             
   449             if (SDL_AddTouch(&touch, "") < 0) {
   450                 return;
   451             }
   452         } 
   453 
   454         const SDL_FingerID fingerId = (SDL_FingerID) ((size_t) [touch identity]);
   455         float x = [touch normalizedPosition].x;
   456         float y = [touch normalizedPosition].y;
   457         /* Make the origin the upper left instead of the lower left */
   458         y = 1.0f - y;
   459 
   460         switch (type) {
   461         case COCOA_TOUCH_DOWN:
   462             SDL_SendFingerDown(touchId, fingerId, SDL_TRUE, x, y, 1);
   463             break;
   464         case COCOA_TOUCH_UP:
   465         case COCOA_TOUCH_CANCELLED:
   466             SDL_SendFingerDown(touchId, fingerId, SDL_FALSE, x, y, 1);
   467             break;
   468         case COCOA_TOUCH_MOVE:
   469             SDL_SendTouchMotion(touchId, fingerId, SDL_FALSE, x, y, 1);
   470             break;
   471         }
   472         
   473         touch = (NSTouch*)[enumerator nextObject];
   474     }
   475 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 */
   476 }
   477 
   478 @end
   479 
   480 @interface SDLWindow : NSWindow
   481 /* These are needed for borderless/fullscreen windows */
   482 - (BOOL)canBecomeKeyWindow;
   483 - (BOOL)canBecomeMainWindow;
   484 @end
   485 
   486 @implementation SDLWindow
   487 - (BOOL)canBecomeKeyWindow
   488 {
   489     return YES;
   490 }
   491 
   492 - (BOOL)canBecomeMainWindow
   493 {
   494     return YES;
   495 }
   496 @end
   497 
   498 @interface SDLView : NSView
   499 /* The default implementation doesn't pass rightMouseDown to responder chain */
   500 - (void)rightMouseDown:(NSEvent *)theEvent;
   501 @end
   502 
   503 @implementation SDLView
   504 - (void)rightMouseDown:(NSEvent *)theEvent
   505 {
   506     [[self nextResponder] rightMouseDown:theEvent];
   507 }
   508 @end
   509 
   510 static unsigned int
   511 GetWindowStyle(SDL_Window * window)
   512 {
   513     unsigned int style;
   514 
   515 	if (window->flags & SDL_WINDOW_FULLSCREEN) {
   516         style = NSBorderlessWindowMask;
   517 	} else {
   518 		if (window->flags & SDL_WINDOW_BORDERLESS) {
   519 			style = NSBorderlessWindowMask;
   520 		} else {
   521 			style = (NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask);
   522 		}
   523 		if (window->flags & SDL_WINDOW_RESIZABLE) {
   524 			style |= NSResizableWindowMask;
   525 		}
   526 	}
   527     return style;
   528 }
   529 
   530 static int
   531 SetupWindowData(_THIS, SDL_Window * window, NSWindow *nswindow, SDL_bool created)
   532 {
   533     NSAutoreleasePool *pool;
   534     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
   535     SDL_WindowData *data;
   536 
   537     /* Allocate the window data */
   538     data = (SDL_WindowData *) SDL_calloc(1, sizeof(*data));
   539     if (!data) {
   540         SDL_OutOfMemory();
   541         return -1;
   542     }
   543     data->window = window;
   544     data->nswindow = nswindow;
   545     data->created = created;
   546     data->videodata = videodata;
   547 
   548     pool = [[NSAutoreleasePool alloc] init];
   549 
   550     /* Create an event listener for the window */
   551     data->listener = [[Cocoa_WindowListener alloc] init];
   552 
   553     /* Fill in the SDL window with the window data */
   554     {
   555         NSRect rect = [nswindow contentRectForFrameRect:[nswindow frame]];
   556         ConvertNSRect(&rect);
   557         window->x = (int)rect.origin.x;
   558         window->y = (int)rect.origin.y;
   559         window->w = (int)rect.size.width;
   560         window->h = (int)rect.size.height;
   561     }
   562 
   563     /* Set up the listener after we create the view */
   564     [data->listener listen:data];
   565 
   566     if ([nswindow isVisible]) {
   567         window->flags |= SDL_WINDOW_SHOWN;
   568     } else {
   569         window->flags &= ~SDL_WINDOW_SHOWN;
   570     }
   571     {
   572         unsigned int style = [nswindow styleMask];
   573 
   574         if (style == NSBorderlessWindowMask) {
   575             window->flags |= SDL_WINDOW_BORDERLESS;
   576         } else {
   577             window->flags &= ~SDL_WINDOW_BORDERLESS;
   578         }
   579         if (style & NSResizableWindowMask) {
   580             window->flags |= SDL_WINDOW_RESIZABLE;
   581         } else {
   582             window->flags &= ~SDL_WINDOW_RESIZABLE;
   583         }
   584     }
   585     /* isZoomed always returns true if the window is not resizable */
   586     if ((window->flags & SDL_WINDOW_RESIZABLE) && [nswindow isZoomed]) {
   587         window->flags |= SDL_WINDOW_MAXIMIZED;
   588     } else {
   589         window->flags &= ~SDL_WINDOW_MAXIMIZED;
   590     }
   591     if ([nswindow isMiniaturized]) {
   592         window->flags |= SDL_WINDOW_MINIMIZED;
   593     } else {
   594         window->flags &= ~SDL_WINDOW_MINIMIZED;
   595     }
   596     if ([nswindow isKeyWindow]) {
   597         window->flags |= SDL_WINDOW_INPUT_FOCUS;
   598         SDL_SetKeyboardFocus(data->window);
   599     }
   600 
   601     /* All done! */
   602     [pool release];
   603     window->driverdata = data;
   604     return 0;
   605 }
   606 
   607 int
   608 Cocoa_CreateWindow(_THIS, SDL_Window * window)
   609 {
   610     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   611     NSWindow *nswindow;
   612     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
   613     NSRect rect;
   614     SDL_Rect bounds;
   615     unsigned int style;
   616 
   617     Cocoa_GetDisplayBounds(_this, display, &bounds);
   618     rect.origin.x = window->x;
   619     rect.origin.y = window->y;
   620     rect.size.width = window->w;
   621     rect.size.height = window->h;
   622     ConvertNSRect(&rect);
   623 
   624     style = GetWindowStyle(window);
   625 
   626     /* Figure out which screen to place this window */
   627     NSArray *screens = [NSScreen screens];
   628     NSScreen *screen = nil;
   629     NSScreen *candidate;
   630     int i, count = [screens count];
   631     for (i = 0; i < count; ++i) {
   632         candidate = [screens objectAtIndex:i];
   633         NSRect screenRect = [candidate frame];
   634         if (rect.origin.x >= screenRect.origin.x &&
   635             rect.origin.x < screenRect.origin.x + screenRect.size.width &&
   636             rect.origin.y >= screenRect.origin.y &&
   637             rect.origin.y < screenRect.origin.y + screenRect.size.height) {
   638             screen = candidate;
   639             rect.origin.x -= screenRect.origin.x;
   640             rect.origin.y -= screenRect.origin.y;
   641         }
   642     }
   643     nswindow = [[SDLWindow alloc] initWithContentRect:rect styleMask:style backing:NSBackingStoreBuffered defer:YES screen:screen];
   644 
   645     // Create a default view for this window
   646     rect = [nswindow contentRectForFrameRect:[nswindow frame]];
   647     NSView *contentView = [[SDLView alloc] initWithFrame:rect];
   648     [nswindow setContentView: contentView];
   649     [contentView release];
   650 
   651     [pool release];
   652 
   653     if (SetupWindowData(_this, window, nswindow, SDL_TRUE) < 0) {
   654         [nswindow release];
   655         return -1;
   656     }
   657     return 0;
   658 }
   659 
   660 int
   661 Cocoa_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
   662 {
   663     NSAutoreleasePool *pool;
   664     NSWindow *nswindow = (NSWindow *) data;
   665     NSString *title;
   666 
   667     pool = [[NSAutoreleasePool alloc] init];
   668 
   669     /* Query the title from the existing window */
   670     title = [nswindow title];
   671     if (title) {
   672         window->title = SDL_strdup([title UTF8String]);
   673     }
   674 
   675     [pool release];
   676 
   677     return SetupWindowData(_this, window, nswindow, SDL_FALSE);
   678 }
   679 
   680 void
   681 Cocoa_SetWindowTitle(_THIS, SDL_Window * window)
   682 {
   683     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   684     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
   685     NSString *string;
   686 
   687     if(window->title) {
   688         string = [[NSString alloc] initWithUTF8String:window->title];
   689     } else {
   690         string = [[NSString alloc] init];
   691     }
   692     [nswindow setTitle:string];
   693     [string release];
   694 
   695     [pool release];
   696 }
   697 
   698 void
   699 Cocoa_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
   700 {
   701     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   702     NSImage *nsimage = Cocoa_CreateImage(icon);
   703 
   704     if (nsimage) {
   705         [NSApp setApplicationIconImage:nsimage];
   706     }
   707 
   708     [pool release];
   709 }
   710 
   711 void
   712 Cocoa_SetWindowPosition(_THIS, SDL_Window * window)
   713 {
   714     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   715     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
   716     NSRect rect;
   717     Uint32 moveHack;
   718 
   719     rect.origin.x = window->x;
   720     rect.origin.y = window->y;
   721     rect.size.width = window->w;
   722     rect.size.height = window->h;
   723     ConvertNSRect(&rect);
   724 
   725     moveHack = s_moveHack;
   726     s_moveHack = 0;
   727     [nswindow setFrameOrigin:rect.origin];
   728     s_moveHack = moveHack;
   729 
   730     if (window == _this->current_glwin) {
   731         [((NSOpenGLContext *) _this->current_glctx) update];
   732     }
   733 
   734     [pool release];
   735 }
   736 
   737 void
   738 Cocoa_SetWindowSize(_THIS, SDL_Window * window)
   739 {
   740     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   741     SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
   742     NSWindow *nswindow = windata->nswindow;
   743     NSSize size;
   744 
   745     size.width = window->w;
   746     size.height = window->h;
   747     [nswindow setContentSize:size];
   748 
   749     if (window == _this->current_glwin) {
   750         [((NSOpenGLContext *) _this->current_glctx) update];
   751     }
   752 
   753     [pool release];
   754 }
   755 
   756 void
   757 Cocoa_ShowWindow(_THIS, SDL_Window * window)
   758 {
   759     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   760     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
   761 
   762     if (![nswindow isMiniaturized]) {
   763         [nswindow makeKeyAndOrderFront:nil];
   764     }
   765     [pool release];
   766 }
   767 
   768 void
   769 Cocoa_HideWindow(_THIS, SDL_Window * window)
   770 {
   771     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   772     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
   773 
   774     [nswindow orderOut:nil];
   775     [pool release];
   776 }
   777 
   778 void
   779 Cocoa_RaiseWindow(_THIS, SDL_Window * window)
   780 {
   781     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   782     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
   783 
   784     [nswindow makeKeyAndOrderFront:nil];
   785     [pool release];
   786 }
   787 
   788 void
   789 Cocoa_MaximizeWindow(_THIS, SDL_Window * window)
   790 {
   791     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   792     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
   793 
   794     [nswindow zoom:nil];
   795 
   796     if (window == _this->current_glwin) {
   797         [((NSOpenGLContext *) _this->current_glctx) update];
   798     }
   799 
   800     [pool release];
   801 }
   802 
   803 void
   804 Cocoa_MinimizeWindow(_THIS, SDL_Window * window)
   805 {
   806     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   807     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
   808 
   809     [nswindow miniaturize:nil];
   810     [pool release];
   811 }
   812 
   813 void
   814 Cocoa_RestoreWindow(_THIS, SDL_Window * window)
   815 {
   816     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   817     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
   818 
   819     if ([nswindow isMiniaturized]) {
   820         [nswindow deminiaturize:nil];
   821     } else if ((window->flags & SDL_WINDOW_RESIZABLE) && [nswindow isZoomed]) {
   822         [nswindow zoom:nil];
   823     }
   824     [pool release];
   825 }
   826 
   827 static NSWindow *
   828 Cocoa_RebuildWindow(SDL_WindowData * data, NSWindow * nswindow, unsigned style)
   829 {
   830     if (!data->created) {
   831         /* Don't mess with other people's windows... */
   832         return nswindow;
   833     }
   834 
   835     [data->listener close];
   836     data->nswindow = [[SDLWindow alloc] initWithContentRect:[[nswindow contentView] frame] styleMask:style backing:NSBackingStoreBuffered defer:YES screen:[nswindow screen]];
   837     [data->nswindow setContentView:[nswindow contentView]];
   838     [data->listener listen:data];
   839 
   840     [nswindow close];
   841 
   842     return data->nswindow;
   843 }
   844 
   845 void
   846 Cocoa_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
   847 {
   848     /* this message arrived in 10.6. You're out of luck on older OSes. */
   849 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
   850     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   851     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
   852     if ([nswindow respondsToSelector:@selector(setStyleMask:)]) {
   853         [nswindow setStyleMask:GetWindowStyle(window)];
   854         if (bordered) {
   855             Cocoa_SetWindowTitle(_this, window);  // this got blanked out.
   856         }
   857     }
   858     [pool release];
   859 #endif
   860 }
   861 
   862 void
   863 Cocoa_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
   864 {
   865     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   866     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   867     NSWindow *nswindow = data->nswindow;
   868     NSRect rect;
   869 
   870     /* The view responder chain gets messed with during setStyleMask */
   871     if ([[nswindow contentView] nextResponder] == data->listener) {
   872         [[nswindow contentView] setNextResponder:nil];
   873     }
   874 
   875     if (fullscreen) {
   876         SDL_Rect bounds;
   877 
   878         Cocoa_GetDisplayBounds(_this, display, &bounds);
   879         rect.origin.x = bounds.x;
   880         rect.origin.y = bounds.y;
   881         rect.size.width = bounds.w;
   882         rect.size.height = bounds.h;
   883         ConvertNSRect(&rect);
   884 
   885         /* Hack to fix origin on Mac OS X 10.4 */
   886         NSRect screenRect = [[nswindow screen] frame];
   887         if (screenRect.size.height >= 1.0f) {
   888             rect.origin.y += (screenRect.size.height - rect.size.height);
   889         }
   890 
   891         if ([nswindow respondsToSelector: @selector(setStyleMask:)]) {
   892             [nswindow performSelector: @selector(setStyleMask:) withObject: (id)NSBorderlessWindowMask];
   893         } else {
   894             nswindow = Cocoa_RebuildWindow(data, nswindow, NSBorderlessWindowMask);
   895         }
   896     } else {
   897         rect.origin.x = window->windowed.x;
   898         rect.origin.y = window->windowed.y;
   899         rect.size.width = window->windowed.w;
   900         rect.size.height = window->windowed.h;
   901         ConvertNSRect(&rect);
   902 
   903         if ([nswindow respondsToSelector: @selector(setStyleMask:)]) {
   904             [nswindow performSelector: @selector(setStyleMask:) withObject: (id)(uintptr_t)GetWindowStyle(window)];
   905         } else {
   906             nswindow = Cocoa_RebuildWindow(data, nswindow, GetWindowStyle(window));
   907         }
   908     }
   909 
   910     /* The view responder chain gets messed with during setStyleMask */
   911     if ([[nswindow contentView] nextResponder] != data->listener) {
   912         [[nswindow contentView] setNextResponder:data->listener];
   913     }
   914 
   915     s_moveHack = 0;
   916     [nswindow setFrameOrigin:rect.origin];
   917     [nswindow setContentSize:rect.size];
   918     s_moveHack = SDL_GetTicks();
   919 
   920     /* When the window style changes the title is cleared */
   921     if (!fullscreen) {
   922         Cocoa_SetWindowTitle(_this, window);
   923     }
   924 
   925 #ifdef FULLSCREEN_TOGGLEABLE
   926     if (fullscreen) {
   927         /* OpenGL is rendering to the window, so make it visible! */
   928         [nswindow setLevel:CGShieldingWindowLevel()];
   929     } else {
   930         [nswindow setLevel:kCGNormalWindowLevel];
   931     }
   932 #endif
   933     [nswindow makeKeyAndOrderFront:nil];
   934 
   935     if (window == _this->current_glwin) {
   936         [((NSOpenGLContext *) _this->current_glctx) update];
   937     }
   938 
   939     [pool release];
   940 }
   941 
   942 int
   943 Cocoa_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
   944 {
   945     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
   946     CGDirectDisplayID display_id = ((SDL_DisplayData *)display->driverdata)->display;
   947     const uint32_t tableSize = 256;
   948     CGGammaValue redTable[tableSize];
   949     CGGammaValue greenTable[tableSize];
   950     CGGammaValue blueTable[tableSize];
   951     uint32_t i;
   952     float inv65535 = 1.0f / 65535.0f;
   953 
   954     /* Extract gamma values into separate tables, convert to floats between 0.0 and 1.0 */
   955     for (i = 0; i < 256; i++) {
   956         redTable[i] = ramp[0*256+i] * inv65535;
   957         greenTable[i] = ramp[1*256+i] * inv65535;
   958         blueTable[i] = ramp[2*256+i] * inv65535;
   959     }
   960 
   961     if (CGSetDisplayTransferByTable(display_id, tableSize,
   962                                     redTable, greenTable, blueTable) != CGDisplayNoErr) {
   963         SDL_SetError("CGSetDisplayTransferByTable()");
   964         return -1;
   965     }
   966     return 0;
   967 }
   968 
   969 int
   970 Cocoa_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp)
   971 {
   972     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
   973     CGDirectDisplayID display_id = ((SDL_DisplayData *)display->driverdata)->display;
   974     const uint32_t tableSize = 256;
   975     CGGammaValue redTable[tableSize];
   976     CGGammaValue greenTable[tableSize];
   977     CGGammaValue blueTable[tableSize];
   978     uint32_t i, tableCopied;
   979 
   980     if (CGGetDisplayTransferByTable(display_id, tableSize,
   981                                     redTable, greenTable, blueTable, &tableCopied) != CGDisplayNoErr) {
   982         SDL_SetError("CGGetDisplayTransferByTable()");
   983         return -1;
   984     }
   985 
   986     for (i = 0; i < tableCopied; i++) {
   987         ramp[0*256+i] = (Uint16)(redTable[i] * 65535.0f);
   988         ramp[1*256+i] = (Uint16)(greenTable[i] * 65535.0f);
   989         ramp[2*256+i] = (Uint16)(blueTable[i] * 65535.0f);
   990     }
   991     return 0;
   992 }
   993 
   994 void
   995 Cocoa_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
   996 {
   997     /* Move the cursor to the nearest point in the window */
   998     if (grabbed) {
   999         int x, y;
  1000         CGPoint cgpoint;
  1001 
  1002         SDL_GetMouseState(&x, &y);
  1003         cgpoint.x = window->x + x;
  1004         cgpoint.y = window->y + y;
  1005         CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
  1006     }
  1007 }
  1008 
  1009 void
  1010 Cocoa_DestroyWindow(_THIS, SDL_Window * window)
  1011 {
  1012     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  1013     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
  1014 
  1015     if (data) {
  1016         [data->listener close];
  1017         [data->listener release];
  1018         if (data->created) {
  1019             [data->nswindow close];
  1020         }
  1021         SDL_free(data);
  1022     }
  1023     [pool release];
  1024 }
  1025 
  1026 SDL_bool
  1027 Cocoa_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
  1028 {
  1029     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
  1030 
  1031     if (info->version.major <= SDL_MAJOR_VERSION) {
  1032         info->subsystem = SDL_SYSWM_COCOA;
  1033         info->info.cocoa.window = nswindow;
  1034         return SDL_TRUE;
  1035     } else {
  1036         SDL_SetError("Application not compiled with SDL %d.%d\n",
  1037                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
  1038         return SDL_FALSE;
  1039     }
  1040 }
  1041 
  1042 #endif /* SDL_VIDEO_DRIVER_COCOA */
  1043 
  1044 /* vi: set ts=4 sw=4 expandtab: */