src/video/cocoa/SDL_cocoawindow.m
author Jørgen P. Tjernø <jorgen@valvesoftware.com>
Mon, 22 Apr 2013 12:07:13 -0700
changeset 7084 9d43403e9fc5
parent 7037 3fedf1f25b94
child 7085 152cc7ddfa57
permissions -rw-r--r--
Properly reflect hidden/shown windows on OSX.

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