src/video/cocoa/SDL_cocoawindow.m
author Sam Lantinga <slouken@libsdl.org>
Wed, 18 Jan 2012 22:22:54 -0500
changeset 6231 5eecf59b698f
parent 6185 b91e7565e877
child 6301 e8a69c5378e7
permissions -rwxr-xr-x
Fixed bug 1372 - OSX Window Maximize/Resize Doesn't Update Window Position

Alex Nankervis 2012-01-15 14:20:01 PST

SDL_cocoawindow.m, windowDidResize needs to also send a window move event.
Depending on the corner you resize a window from, or when maximizing a window,
the window position will change. Discovered this when creating a maximized
window and found that the window position was stuck at the un-maximized
window's value.

Diff with fix attached.
     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 - (void)mouseDown:(NSEvent *)theEvent
   228 {
   229     int button;
   230 
   231     switch ([theEvent buttonNumber]) {
   232     case 0:
   233         button = SDL_BUTTON_LEFT;
   234         break;
   235     case 1:
   236         button = SDL_BUTTON_RIGHT;
   237         break;
   238     case 2:
   239         button = SDL_BUTTON_MIDDLE;
   240         break;
   241     default:
   242         button = [theEvent buttonNumber] + 1;
   243         break;
   244     }
   245     SDL_SendMouseButton(_data->window, SDL_PRESSED, button);
   246 }
   247 
   248 - (void)rightMouseDown:(NSEvent *)theEvent
   249 {
   250     [self mouseDown:theEvent];
   251 }
   252 
   253 - (void)otherMouseDown:(NSEvent *)theEvent
   254 {
   255     [self mouseDown:theEvent];
   256 }
   257 
   258 - (void)mouseUp:(NSEvent *)theEvent
   259 {
   260     int button;
   261 
   262     switch ([theEvent buttonNumber]) {
   263     case 0:
   264         button = SDL_BUTTON_LEFT;
   265         break;
   266     case 1:
   267         button = SDL_BUTTON_RIGHT;
   268         break;
   269     case 2:
   270         button = SDL_BUTTON_MIDDLE;
   271         break;
   272     default:
   273         button = [theEvent buttonNumber] + 1;
   274         break;
   275     }
   276     SDL_SendMouseButton(_data->window, SDL_RELEASED, button);
   277 }
   278 
   279 - (void)rightMouseUp:(NSEvent *)theEvent
   280 {
   281     [self mouseUp:theEvent];
   282 }
   283 
   284 - (void)otherMouseUp:(NSEvent *)theEvent
   285 {
   286     [self mouseUp:theEvent];
   287 }
   288 
   289 - (void)mouseEntered:(NSEvent *)theEvent
   290 {
   291     SDL_SetMouseFocus(_data->window);
   292 
   293     SDL_SetCursor(NULL);
   294 }
   295 
   296 - (void)mouseExited:(NSEvent *)theEvent
   297 {
   298     SDL_Window *window = _data->window;
   299 
   300     if (SDL_GetMouseFocus() == window) {
   301         if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
   302             int x, y;
   303             NSPoint point;
   304             CGPoint cgpoint;
   305 
   306             point = [theEvent locationInWindow];
   307             point.y = window->h - point.y;
   308 
   309             SDL_SendMouseMotion(window, 0, (int)point.x, (int)point.y);
   310             SDL_GetMouseState(&x, &y);
   311             cgpoint.x = window->x + x;
   312             cgpoint.y = window->y + y;
   313             CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
   314         } else {
   315             SDL_SetMouseFocus(NULL);
   316 
   317             [[NSCursor arrowCursor] set];
   318             [NSCursor unhide];
   319         }
   320     }
   321 }
   322 
   323 - (void)mouseMoved:(NSEvent *)theEvent
   324 {
   325     SDL_Mouse *mouse = SDL_GetMouse();
   326     SDL_Window *window = _data->window;
   327     NSPoint point;
   328     int x, y;
   329 
   330     if (mouse->relative_mode) {
   331         return;
   332     }
   333 
   334     point = [theEvent locationInWindow];
   335     x = (int)point.x;
   336     y = (int)(window->h - point.y);
   337 
   338     if (x < 0 || x >= window->w || y < 0 || y >= window->h) {
   339         if (SDL_GetMouseFocus() == window) {
   340             [self mouseExited:theEvent];
   341         }
   342     } else {
   343         if (SDL_GetMouseFocus() != window) {
   344             [self mouseEntered:theEvent];
   345         }
   346         SDL_SendMouseMotion(window, 0, x, y);
   347     }
   348 }
   349 
   350 - (void)mouseDragged:(NSEvent *)theEvent
   351 {
   352     [self mouseMoved:theEvent];
   353 }
   354 
   355 - (void)rightMouseDragged:(NSEvent *)theEvent
   356 {
   357     [self mouseMoved:theEvent];
   358 }
   359 
   360 - (void)otherMouseDragged:(NSEvent *)theEvent
   361 {
   362     [self mouseMoved:theEvent];
   363 }
   364 
   365 - (void)scrollWheel:(NSEvent *)theEvent
   366 {
   367     Cocoa_HandleMouseWheel(_data->window, theEvent);
   368 }
   369 
   370 - (void)touchesBeganWithEvent:(NSEvent *) theEvent
   371 {
   372     [self handleTouches:COCOA_TOUCH_DOWN withEvent:theEvent];
   373 }
   374 
   375 - (void)touchesMovedWithEvent:(NSEvent *) theEvent
   376 {
   377     [self handleTouches:COCOA_TOUCH_MOVE withEvent:theEvent];
   378 }
   379 
   380 - (void)touchesEndedWithEvent:(NSEvent *) theEvent
   381 {
   382     [self handleTouches:COCOA_TOUCH_UP withEvent:theEvent];
   383 }
   384 
   385 - (void)touchesCancelledWithEvent:(NSEvent *) theEvent
   386 {
   387     [self handleTouches:COCOA_TOUCH_CANCELLED withEvent:theEvent];
   388 }
   389 
   390 - (void)handleTouches:(cocoaTouchType)type withEvent:(NSEvent *)event
   391 {
   392 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
   393     NSSet *touches = 0;
   394     NSEnumerator *enumerator;
   395     NSTouch *touch;
   396 
   397     switch (type) {
   398         case COCOA_TOUCH_DOWN:
   399             touches = [event touchesMatchingPhase:NSTouchPhaseBegan inView:nil];
   400             break;
   401         case COCOA_TOUCH_UP:
   402         case COCOA_TOUCH_CANCELLED:
   403             touches = [event touchesMatchingPhase:NSTouchPhaseEnded inView:nil];
   404             break;
   405         case COCOA_TOUCH_MOVE:
   406             touches = [event touchesMatchingPhase:NSTouchPhaseMoved inView:nil];
   407             break;
   408     }
   409 
   410     enumerator = [touches objectEnumerator];
   411     touch = (NSTouch*)[enumerator nextObject];
   412     while (touch) {
   413         const SDL_TouchID touchId = (SDL_TouchID) ((size_t) [touch device]);
   414         if (!SDL_GetTouch(touchId)) {
   415             SDL_Touch touch;
   416 
   417             touch.id = touchId;
   418             touch.x_min = 0;
   419             touch.x_max = 1;
   420             touch.native_xres = touch.x_max - touch.x_min;
   421             touch.y_min = 0;
   422             touch.y_max = 1;
   423             touch.native_yres = touch.y_max - touch.y_min;
   424             touch.pressure_min = 0;
   425             touch.pressure_max = 1;
   426             touch.native_pressureres = touch.pressure_max - touch.pressure_min;
   427             
   428             if (SDL_AddTouch(&touch, "") < 0) {
   429                 return;
   430             }
   431         } 
   432 
   433         const SDL_FingerID fingerId = (SDL_FingerID) ((size_t) [touch identity]);
   434         float x = [touch normalizedPosition].x;
   435         float y = [touch normalizedPosition].y;
   436         /* Make the origin the upper left instead of the lower left */
   437         y = 1.0f - y;
   438 
   439         switch (type) {
   440         case COCOA_TOUCH_DOWN:
   441             SDL_SendFingerDown(touchId, fingerId, SDL_TRUE, x, y, 1);
   442             break;
   443         case COCOA_TOUCH_UP:
   444         case COCOA_TOUCH_CANCELLED:
   445             SDL_SendFingerDown(touchId, fingerId, SDL_FALSE, x, y, 1);
   446             break;
   447         case COCOA_TOUCH_MOVE:
   448             SDL_SendTouchMotion(touchId, fingerId, SDL_FALSE, x, y, 1);
   449             break;
   450         }
   451         
   452         touch = (NSTouch*)[enumerator nextObject];
   453     }
   454 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 */
   455 }
   456 
   457 @end
   458 
   459 @interface SDLWindow : NSWindow
   460 /* These are needed for borderless/fullscreen windows */
   461 - (BOOL)canBecomeKeyWindow;
   462 - (BOOL)canBecomeMainWindow;
   463 @end
   464 
   465 @implementation SDLWindow
   466 - (BOOL)canBecomeKeyWindow
   467 {
   468     return YES;
   469 }
   470 
   471 - (BOOL)canBecomeMainWindow
   472 {
   473     return YES;
   474 }
   475 @end
   476 
   477 @interface SDLView : NSView
   478 /* The default implementation doesn't pass rightMouseDown to responder chain */
   479 - (void)rightMouseDown:(NSEvent *)theEvent;
   480 @end
   481 
   482 @implementation SDLView
   483 - (void)rightMouseDown:(NSEvent *)theEvent
   484 {
   485     [[self nextResponder] rightMouseDown:theEvent];
   486 }
   487 @end
   488 
   489 static unsigned int
   490 GetWindowStyle(SDL_Window * window)
   491 {
   492     unsigned int style;
   493 
   494 	if (window->flags & SDL_WINDOW_FULLSCREEN) {
   495         style = NSBorderlessWindowMask;
   496 	} else {
   497 		if (window->flags & SDL_WINDOW_BORDERLESS) {
   498 			style = NSBorderlessWindowMask;
   499 		} else {
   500 			style = (NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask);
   501 		}
   502 		if (window->flags & SDL_WINDOW_RESIZABLE) {
   503 			style |= NSResizableWindowMask;
   504 		}
   505 	}
   506     return style;
   507 }
   508 
   509 static int
   510 SetupWindowData(_THIS, SDL_Window * window, NSWindow *nswindow, SDL_bool created)
   511 {
   512     NSAutoreleasePool *pool;
   513     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
   514     SDL_WindowData *data;
   515 
   516     /* Allocate the window data */
   517     data = (SDL_WindowData *) SDL_calloc(1, sizeof(*data));
   518     if (!data) {
   519         SDL_OutOfMemory();
   520         return -1;
   521     }
   522     data->window = window;
   523     data->nswindow = nswindow;
   524     data->created = created;
   525     data->videodata = videodata;
   526 
   527     pool = [[NSAutoreleasePool alloc] init];
   528 
   529     /* Create an event listener for the window */
   530     data->listener = [[Cocoa_WindowListener alloc] init];
   531 
   532     /* Fill in the SDL window with the window data */
   533     {
   534         NSRect rect = [nswindow contentRectForFrameRect:[nswindow frame]];
   535         NSView *contentView = [ nswindow contentView ];
   536         /* Create view if not already exists */
   537         if (!contentView) {
   538             contentView = [[SDLView alloc] initWithFrame:rect];
   539             [nswindow setContentView: contentView];
   540             [contentView release];
   541         }
   542 
   543         ConvertNSRect(&rect);
   544         window->x = (int)rect.origin.x;
   545         window->y = (int)rect.origin.y;
   546         window->w = (int)rect.size.width;
   547         window->h = (int)rect.size.height;
   548     }
   549 
   550     /* Set up the listener after we create the view */
   551     [data->listener listen:data];
   552 
   553     if ([nswindow isVisible]) {
   554         window->flags |= SDL_WINDOW_SHOWN;
   555     } else {
   556         window->flags &= ~SDL_WINDOW_SHOWN;
   557     }
   558     {
   559         unsigned int style = [nswindow styleMask];
   560 
   561         if (style == NSBorderlessWindowMask) {
   562             window->flags |= SDL_WINDOW_BORDERLESS;
   563         } else {
   564             window->flags &= ~SDL_WINDOW_BORDERLESS;
   565         }
   566         if (style & NSResizableWindowMask) {
   567             window->flags |= SDL_WINDOW_RESIZABLE;
   568         } else {
   569             window->flags &= ~SDL_WINDOW_RESIZABLE;
   570         }
   571     }
   572     /* isZoomed always returns true if the window is not resizable */
   573     if ((window->flags & SDL_WINDOW_RESIZABLE) && [nswindow isZoomed]) {
   574         window->flags |= SDL_WINDOW_MAXIMIZED;
   575     } else {
   576         window->flags &= ~SDL_WINDOW_MAXIMIZED;
   577     }
   578     if ([nswindow isMiniaturized]) {
   579         window->flags |= SDL_WINDOW_MINIMIZED;
   580     } else {
   581         window->flags &= ~SDL_WINDOW_MINIMIZED;
   582     }
   583     if ([nswindow isKeyWindow]) {
   584         window->flags |= SDL_WINDOW_INPUT_FOCUS;
   585         SDL_SetKeyboardFocus(data->window);
   586     }
   587 
   588     /* All done! */
   589     [pool release];
   590     window->driverdata = data;
   591     return 0;
   592 }
   593 
   594 int
   595 Cocoa_CreateWindow(_THIS, SDL_Window * window)
   596 {
   597     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   598     NSWindow *nswindow;
   599     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
   600     NSRect rect;
   601     SDL_Rect bounds;
   602     unsigned int style;
   603 
   604     Cocoa_GetDisplayBounds(_this, display, &bounds);
   605     rect.origin.x = window->x;
   606     rect.origin.y = window->y;
   607     rect.size.width = window->w;
   608     rect.size.height = window->h;
   609     ConvertNSRect(&rect);
   610 
   611     style = GetWindowStyle(window);
   612 
   613     /* Figure out which screen to place this window */
   614     NSArray *screens = [NSScreen screens];
   615     NSScreen *screen = nil;
   616     NSScreen *candidate;
   617     int i, count = [screens count];
   618     for (i = 0; i < count; ++i) {
   619         candidate = [screens objectAtIndex:i];
   620         NSRect screenRect = [candidate frame];
   621         if (rect.origin.x >= screenRect.origin.x &&
   622             rect.origin.x < screenRect.origin.x + screenRect.size.width &&
   623             rect.origin.y >= screenRect.origin.y &&
   624             rect.origin.y < screenRect.origin.y + screenRect.size.height) {
   625             screen = candidate;
   626             rect.origin.x -= screenRect.origin.x;
   627             rect.origin.y -= screenRect.origin.y;
   628         }
   629     }
   630     nswindow = [[SDLWindow alloc] initWithContentRect:rect styleMask:style backing:NSBackingStoreBuffered defer:YES screen:screen];
   631 
   632     [pool release];
   633 
   634     if (SetupWindowData(_this, window, nswindow, SDL_TRUE) < 0) {
   635         [nswindow release];
   636         return -1;
   637     }
   638     return 0;
   639 }
   640 
   641 int
   642 Cocoa_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
   643 {
   644     NSAutoreleasePool *pool;
   645     NSWindow *nswindow = (NSWindow *) data;
   646     NSString *title;
   647 
   648     pool = [[NSAutoreleasePool alloc] init];
   649 
   650     /* Query the title from the existing window */
   651     title = [nswindow title];
   652     if (title) {
   653         window->title = SDL_strdup([title UTF8String]);
   654     }
   655 
   656     [pool release];
   657 
   658     return SetupWindowData(_this, window, nswindow, SDL_FALSE);
   659 }
   660 
   661 void
   662 Cocoa_SetWindowTitle(_THIS, SDL_Window * window)
   663 {
   664     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   665     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
   666     NSString *string;
   667 
   668     if(window->title) {
   669         string = [[NSString alloc] initWithUTF8String:window->title];
   670     } else {
   671         string = [[NSString alloc] init];
   672     }
   673     [nswindow setTitle:string];
   674     [string release];
   675 
   676     [pool release];
   677 }
   678 
   679 void
   680 Cocoa_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
   681 {
   682     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   683     NSImage *nsimage = Cocoa_CreateImage(icon);
   684 
   685     if (nsimage) {
   686         [NSApp setApplicationIconImage:nsimage];
   687     }
   688 
   689     [pool release];
   690 }
   691 
   692 void
   693 Cocoa_SetWindowPosition(_THIS, SDL_Window * window)
   694 {
   695     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   696     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
   697     NSRect rect;
   698     Uint32 moveHack;
   699 
   700     rect.origin.x = window->x;
   701     rect.origin.y = window->y;
   702     rect.size.width = window->w;
   703     rect.size.height = window->h;
   704     ConvertNSRect(&rect);
   705 
   706     moveHack = s_moveHack;
   707     s_moveHack = 0;
   708     [nswindow setFrameOrigin:rect.origin];
   709     s_moveHack = moveHack;
   710 
   711     if (window == _this->current_glwin) {
   712         [((NSOpenGLContext *) _this->current_glctx) update];
   713     }
   714 
   715     [pool release];
   716 }
   717 
   718 void
   719 Cocoa_SetWindowSize(_THIS, SDL_Window * window)
   720 {
   721     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   722     SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
   723     NSWindow *nswindow = windata->nswindow;
   724     NSSize size;
   725 
   726     size.width = window->w;
   727     size.height = window->h;
   728     [nswindow setContentSize:size];
   729 
   730     if (window == _this->current_glwin) {
   731         [((NSOpenGLContext *) _this->current_glctx) update];
   732     }
   733 
   734     [pool release];
   735 }
   736 
   737 void
   738 Cocoa_ShowWindow(_THIS, SDL_Window * window)
   739 {
   740     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   741     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
   742 
   743     if (![nswindow isMiniaturized]) {
   744         [nswindow makeKeyAndOrderFront:nil];
   745     }
   746     [pool release];
   747 }
   748 
   749 void
   750 Cocoa_HideWindow(_THIS, SDL_Window * window)
   751 {
   752     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   753     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
   754 
   755     [nswindow orderOut:nil];
   756     [pool release];
   757 }
   758 
   759 void
   760 Cocoa_RaiseWindow(_THIS, SDL_Window * window)
   761 {
   762     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   763     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
   764 
   765     [nswindow makeKeyAndOrderFront:nil];
   766     [pool release];
   767 }
   768 
   769 void
   770 Cocoa_MaximizeWindow(_THIS, SDL_Window * window)
   771 {
   772     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   773     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
   774 
   775     [nswindow zoom:nil];
   776 
   777     if (window == _this->current_glwin) {
   778         [((NSOpenGLContext *) _this->current_glctx) update];
   779     }
   780 
   781     [pool release];
   782 }
   783 
   784 void
   785 Cocoa_MinimizeWindow(_THIS, SDL_Window * window)
   786 {
   787     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   788     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
   789 
   790     [nswindow miniaturize:nil];
   791     [pool release];
   792 }
   793 
   794 void
   795 Cocoa_RestoreWindow(_THIS, SDL_Window * window)
   796 {
   797     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   798     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
   799 
   800     if ([nswindow isMiniaturized]) {
   801         [nswindow deminiaturize:nil];
   802     } else if ((window->flags & SDL_WINDOW_RESIZABLE) && [nswindow isZoomed]) {
   803         [nswindow zoom:nil];
   804     }
   805     [pool release];
   806 }
   807 
   808 static NSWindow *
   809 Cocoa_RebuildWindow(SDL_WindowData * data, NSWindow * nswindow, unsigned style)
   810 {
   811     if (!data->created) {
   812         /* Don't mess with other people's windows... */
   813         return nswindow;
   814     }
   815 
   816     [data->listener close];
   817     data->nswindow = [[SDLWindow alloc] initWithContentRect:[[nswindow contentView] frame] styleMask:style backing:NSBackingStoreBuffered defer:YES screen:[nswindow screen]];
   818     [data->nswindow setContentView:[nswindow contentView]];
   819     [data->listener listen:data];
   820 
   821     [nswindow close];
   822 
   823     return data->nswindow;
   824 }
   825 
   826 void
   827 Cocoa_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
   828 {
   829     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   830     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   831     NSWindow *nswindow = data->nswindow;
   832     NSRect rect;
   833 
   834     /* The view responder chain gets messed with during setStyleMask */
   835     if ([[nswindow contentView] nextResponder] == data->listener) {
   836         [[nswindow contentView] setNextResponder:nil];
   837     }
   838 
   839     if (fullscreen) {
   840         SDL_Rect bounds;
   841 
   842         Cocoa_GetDisplayBounds(_this, display, &bounds);
   843         rect.origin.x = bounds.x;
   844         rect.origin.y = bounds.y;
   845         rect.size.width = bounds.w;
   846         rect.size.height = bounds.h;
   847         ConvertNSRect(&rect);
   848 
   849         /* Hack to fix origin on Mac OS X 10.4 */
   850         NSRect screenRect = [[nswindow screen] frame];
   851         if (screenRect.size.height >= 1.0f) {
   852             rect.origin.y += (screenRect.size.height - rect.size.height);
   853         }
   854 
   855         if ([nswindow respondsToSelector: @selector(setStyleMask:)]) {
   856             [nswindow performSelector: @selector(setStyleMask:) withObject: (id)NSBorderlessWindowMask];
   857         } else {
   858             nswindow = Cocoa_RebuildWindow(data, nswindow, NSBorderlessWindowMask);
   859         }
   860     } else {
   861         rect.origin.x = window->windowed.x;
   862         rect.origin.y = window->windowed.y;
   863         rect.size.width = window->windowed.w;
   864         rect.size.height = window->windowed.h;
   865         ConvertNSRect(&rect);
   866 
   867         if ([nswindow respondsToSelector: @selector(setStyleMask:)]) {
   868             [nswindow performSelector: @selector(setStyleMask:) withObject: (id)(uintptr_t)GetWindowStyle(window)];
   869         } else {
   870             nswindow = Cocoa_RebuildWindow(data, nswindow, GetWindowStyle(window));
   871         }
   872     }
   873 
   874     /* The view responder chain gets messed with during setStyleMask */
   875     if ([[nswindow contentView] nextResponder] != data->listener) {
   876         [[nswindow contentView] setNextResponder:data->listener];
   877     }
   878 
   879     s_moveHack = 0;
   880     [nswindow setFrameOrigin:rect.origin];
   881     [nswindow setContentSize:rect.size];
   882     s_moveHack = SDL_GetTicks();
   883 
   884     /* When the window style changes the title is cleared */
   885     if (!fullscreen) {
   886         Cocoa_SetWindowTitle(_this, window);
   887     }
   888 
   889 #ifdef FULLSCREEN_TOGGLEABLE
   890     if (fullscreen) {
   891         /* OpenGL is rendering to the window, so make it visible! */
   892         [nswindow setLevel:CGShieldingWindowLevel()];
   893     } else {
   894         [nswindow setLevel:kCGNormalWindowLevel];
   895     }
   896 #endif
   897     [nswindow makeKeyAndOrderFront:nil];
   898 
   899     if (window == _this->current_glwin) {
   900         [((NSOpenGLContext *) _this->current_glctx) update];
   901     }
   902 
   903     [pool release];
   904 }
   905 
   906 int
   907 Cocoa_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
   908 {
   909     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
   910     CGDirectDisplayID display_id = ((SDL_DisplayData *)display->driverdata)->display;
   911     const uint32_t tableSize = 256;
   912     CGGammaValue redTable[tableSize];
   913     CGGammaValue greenTable[tableSize];
   914     CGGammaValue blueTable[tableSize];
   915     uint32_t i;
   916     float inv65535 = 1.0f / 65535.0f;
   917 
   918     /* Extract gamma values into separate tables, convert to floats between 0.0 and 1.0 */
   919     for (i = 0; i < 256; i++) {
   920         redTable[i] = ramp[0*256+i] * inv65535;
   921         greenTable[i] = ramp[1*256+i] * inv65535;
   922         blueTable[i] = ramp[2*256+i] * inv65535;
   923     }
   924 
   925     if (CGSetDisplayTransferByTable(display_id, tableSize,
   926                                     redTable, greenTable, blueTable) != CGDisplayNoErr) {
   927         SDL_SetError("CGSetDisplayTransferByTable()");
   928         return -1;
   929     }
   930     return 0;
   931 }
   932 
   933 int
   934 Cocoa_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp)
   935 {
   936     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
   937     CGDirectDisplayID display_id = ((SDL_DisplayData *)display->driverdata)->display;
   938     const uint32_t tableSize = 256;
   939     CGGammaValue redTable[tableSize];
   940     CGGammaValue greenTable[tableSize];
   941     CGGammaValue blueTable[tableSize];
   942     uint32_t i, tableCopied;
   943 
   944     if (CGGetDisplayTransferByTable(display_id, tableSize,
   945                                     redTable, greenTable, blueTable, &tableCopied) != CGDisplayNoErr) {
   946         SDL_SetError("CGGetDisplayTransferByTable()");
   947         return -1;
   948     }
   949 
   950     for (i = 0; i < tableCopied; i++) {
   951         ramp[0*256+i] = (Uint16)(redTable[i] * 65535.0f);
   952         ramp[1*256+i] = (Uint16)(greenTable[i] * 65535.0f);
   953         ramp[2*256+i] = (Uint16)(blueTable[i] * 65535.0f);
   954     }
   955     return 0;
   956 }
   957 
   958 void
   959 Cocoa_SetWindowGrab(_THIS, SDL_Window * window)
   960 {
   961     /* Move the cursor to the nearest point in the window */
   962     if ((window->flags & SDL_WINDOW_INPUT_GRABBED) &&
   963         (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
   964         int x, y;
   965         CGPoint cgpoint;
   966 
   967         SDL_GetMouseState(&x, &y);
   968         cgpoint.x = window->x + x;
   969         cgpoint.y = window->y + y;
   970         CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
   971     }
   972 }
   973 
   974 void
   975 Cocoa_DestroyWindow(_THIS, SDL_Window * window)
   976 {
   977     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   978     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   979 
   980     if (data) {
   981         [data->listener close];
   982         [data->listener release];
   983         if (data->created) {
   984             [data->nswindow close];
   985         }
   986         SDL_free(data);
   987     }
   988     [pool release];
   989 }
   990 
   991 SDL_bool
   992 Cocoa_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
   993 {
   994     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
   995 
   996     if (info->version.major <= SDL_MAJOR_VERSION) {
   997         info->subsystem = SDL_SYSWM_COCOA;
   998         info->info.cocoa.window = nswindow;
   999         return SDL_TRUE;
  1000     } else {
  1001         SDL_SetError("Application not compiled with SDL %d.%d\n",
  1002                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
  1003         return SDL_FALSE;
  1004     }
  1005 }
  1006 
  1007 #endif /* SDL_VIDEO_DRIVER_COCOA */
  1008 
  1009 /* vi: set ts=4 sw=4 expandtab: */