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