src/video/cocoa/SDL_cocoawindow.m
author Ryan C. Gordon <icculus@icculus.org>
Fri, 09 Dec 2011 02:32:21 -0500
changeset 6108 f3c34d321289
parent 6044 35448a5ea044
child 6138 4c64952a58fb
permissions -rw-r--r--
Don't call -[NSView setAcceptsTouchEvents] if the OS doesn't provide it.

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