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