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