src/video/cocoa/SDL_cocoawindow.m
author Sam Lantinga <slouken@libsdl.org>
Sun, 08 Jan 2012 00:39:41 -0500
changeset 6185 b91e7565e877
parent 6138 4c64952a58fb
child 6231 5eecf59b698f
permissions -rwxr-xr-x
Fixed bug 1303 - SDL_CreateFromWindow duplicates window (Cocoa only)

Jens Köhler 2011-09-09 04:47:40 PDT

When calling SDL_CreateWindowFrom with a NSWindow which already contains a
NSView, the window will be duplicated because another NSView is added. I
attached a possible fix that prevents the creation of a second NSView.
     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 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 = [ nswindow contentView ];
   530         /* Create view if not already exists */
   531         if (!contentView) {
   532             contentView = [[SDLView alloc] initWithFrame:rect];
   533             [nswindow setContentView: contentView];
   534             [contentView release];
   535         }
   536 
   537         ConvertNSRect(&rect);
   538         window->x = (int)rect.origin.x;
   539         window->y = (int)rect.origin.y;
   540         window->w = (int)rect.size.width;
   541         window->h = (int)rect.size.height;
   542     }
   543 
   544     /* Set up the listener after we create the view */
   545     [data->listener listen:data];
   546 
   547     if ([nswindow isVisible]) {
   548         window->flags |= SDL_WINDOW_SHOWN;
   549     } else {
   550         window->flags &= ~SDL_WINDOW_SHOWN;
   551     }
   552     {
   553         unsigned int style = [nswindow styleMask];
   554 
   555         if (style == NSBorderlessWindowMask) {
   556             window->flags |= SDL_WINDOW_BORDERLESS;
   557         } else {
   558             window->flags &= ~SDL_WINDOW_BORDERLESS;
   559         }
   560         if (style & NSResizableWindowMask) {
   561             window->flags |= SDL_WINDOW_RESIZABLE;
   562         } else {
   563             window->flags &= ~SDL_WINDOW_RESIZABLE;
   564         }
   565     }
   566     /* isZoomed always returns true if the window is not resizable */
   567     if ((window->flags & SDL_WINDOW_RESIZABLE) && [nswindow isZoomed]) {
   568         window->flags |= SDL_WINDOW_MAXIMIZED;
   569     } else {
   570         window->flags &= ~SDL_WINDOW_MAXIMIZED;
   571     }
   572     if ([nswindow isMiniaturized]) {
   573         window->flags |= SDL_WINDOW_MINIMIZED;
   574     } else {
   575         window->flags &= ~SDL_WINDOW_MINIMIZED;
   576     }
   577     if ([nswindow isKeyWindow]) {
   578         window->flags |= SDL_WINDOW_INPUT_FOCUS;
   579         SDL_SetKeyboardFocus(data->window);
   580     }
   581 
   582     /* All done! */
   583     [pool release];
   584     window->driverdata = data;
   585     return 0;
   586 }
   587 
   588 int
   589 Cocoa_CreateWindow(_THIS, SDL_Window * window)
   590 {
   591     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   592     NSWindow *nswindow;
   593     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
   594     NSRect rect;
   595     SDL_Rect bounds;
   596     unsigned int style;
   597 
   598     Cocoa_GetDisplayBounds(_this, display, &bounds);
   599     rect.origin.x = window->x;
   600     rect.origin.y = window->y;
   601     rect.size.width = window->w;
   602     rect.size.height = window->h;
   603     ConvertNSRect(&rect);
   604 
   605     style = GetWindowStyle(window);
   606 
   607     /* Figure out which screen to place this window */
   608     NSArray *screens = [NSScreen screens];
   609     NSScreen *screen = nil;
   610     NSScreen *candidate;
   611     int i, count = [screens count];
   612     for (i = 0; i < count; ++i) {
   613         candidate = [screens objectAtIndex:i];
   614         NSRect screenRect = [candidate frame];
   615         if (rect.origin.x >= screenRect.origin.x &&
   616             rect.origin.x < screenRect.origin.x + screenRect.size.width &&
   617             rect.origin.y >= screenRect.origin.y &&
   618             rect.origin.y < screenRect.origin.y + screenRect.size.height) {
   619             screen = candidate;
   620             rect.origin.x -= screenRect.origin.x;
   621             rect.origin.y -= screenRect.origin.y;
   622         }
   623     }
   624     nswindow = [[SDLWindow alloc] initWithContentRect:rect styleMask:style backing:NSBackingStoreBuffered defer:YES screen:screen];
   625 
   626     [pool release];
   627 
   628     if (SetupWindowData(_this, window, nswindow, SDL_TRUE) < 0) {
   629         [nswindow release];
   630         return -1;
   631     }
   632     return 0;
   633 }
   634 
   635 int
   636 Cocoa_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
   637 {
   638     NSAutoreleasePool *pool;
   639     NSWindow *nswindow = (NSWindow *) data;
   640     NSString *title;
   641 
   642     pool = [[NSAutoreleasePool alloc] init];
   643 
   644     /* Query the title from the existing window */
   645     title = [nswindow title];
   646     if (title) {
   647         window->title = SDL_strdup([title UTF8String]);
   648     }
   649 
   650     [pool release];
   651 
   652     return SetupWindowData(_this, window, nswindow, SDL_FALSE);
   653 }
   654 
   655 void
   656 Cocoa_SetWindowTitle(_THIS, SDL_Window * window)
   657 {
   658     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   659     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
   660     NSString *string;
   661 
   662     if(window->title) {
   663         string = [[NSString alloc] initWithUTF8String:window->title];
   664     } else {
   665         string = [[NSString alloc] init];
   666     }
   667     [nswindow setTitle:string];
   668     [string release];
   669 
   670     [pool release];
   671 }
   672 
   673 void
   674 Cocoa_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
   675 {
   676     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   677     NSImage *nsimage = Cocoa_CreateImage(icon);
   678 
   679     if (nsimage) {
   680         [NSApp setApplicationIconImage:nsimage];
   681     }
   682 
   683     [pool release];
   684 }
   685 
   686 void
   687 Cocoa_SetWindowPosition(_THIS, SDL_Window * window)
   688 {
   689     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   690     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
   691     NSRect rect;
   692     Uint32 moveHack;
   693 
   694     rect.origin.x = window->x;
   695     rect.origin.y = window->y;
   696     rect.size.width = window->w;
   697     rect.size.height = window->h;
   698     ConvertNSRect(&rect);
   699 
   700     moveHack = s_moveHack;
   701     s_moveHack = 0;
   702     [nswindow setFrameOrigin:rect.origin];
   703     s_moveHack = moveHack;
   704 
   705     if (window == _this->current_glwin) {
   706         [((NSOpenGLContext *) _this->current_glctx) update];
   707     }
   708 
   709     [pool release];
   710 }
   711 
   712 void
   713 Cocoa_SetWindowSize(_THIS, SDL_Window * window)
   714 {
   715     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   716     SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
   717     NSWindow *nswindow = windata->nswindow;
   718     NSSize size;
   719 
   720     size.width = window->w;
   721     size.height = window->h;
   722     [nswindow setContentSize:size];
   723 
   724     if (window == _this->current_glwin) {
   725         [((NSOpenGLContext *) _this->current_glctx) update];
   726     }
   727 
   728     [pool release];
   729 }
   730 
   731 void
   732 Cocoa_ShowWindow(_THIS, SDL_Window * window)
   733 {
   734     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   735     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
   736 
   737     if (![nswindow isMiniaturized]) {
   738         [nswindow makeKeyAndOrderFront:nil];
   739     }
   740     [pool release];
   741 }
   742 
   743 void
   744 Cocoa_HideWindow(_THIS, SDL_Window * window)
   745 {
   746     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   747     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
   748 
   749     [nswindow orderOut:nil];
   750     [pool release];
   751 }
   752 
   753 void
   754 Cocoa_RaiseWindow(_THIS, SDL_Window * window)
   755 {
   756     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   757     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
   758 
   759     [nswindow makeKeyAndOrderFront:nil];
   760     [pool release];
   761 }
   762 
   763 void
   764 Cocoa_MaximizeWindow(_THIS, SDL_Window * window)
   765 {
   766     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   767     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
   768 
   769     [nswindow zoom:nil];
   770 
   771     if (window == _this->current_glwin) {
   772         [((NSOpenGLContext *) _this->current_glctx) update];
   773     }
   774 
   775     [pool release];
   776 }
   777 
   778 void
   779 Cocoa_MinimizeWindow(_THIS, SDL_Window * window)
   780 {
   781     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   782     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
   783 
   784     [nswindow miniaturize:nil];
   785     [pool release];
   786 }
   787 
   788 void
   789 Cocoa_RestoreWindow(_THIS, SDL_Window * window)
   790 {
   791     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   792     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
   793 
   794     if ([nswindow isMiniaturized]) {
   795         [nswindow deminiaturize:nil];
   796     } else if ((window->flags & SDL_WINDOW_RESIZABLE) && [nswindow isZoomed]) {
   797         [nswindow zoom:nil];
   798     }
   799     [pool release];
   800 }
   801 
   802 static NSWindow *
   803 Cocoa_RebuildWindow(SDL_WindowData * data, NSWindow * nswindow, unsigned style)
   804 {
   805     if (!data->created) {
   806         /* Don't mess with other people's windows... */
   807         return nswindow;
   808     }
   809 
   810     [data->listener close];
   811     data->nswindow = [[SDLWindow alloc] initWithContentRect:[[nswindow contentView] frame] styleMask:style backing:NSBackingStoreBuffered defer:YES screen:[nswindow screen]];
   812     [data->nswindow setContentView:[nswindow contentView]];
   813     [data->listener listen:data];
   814 
   815     [nswindow close];
   816 
   817     return data->nswindow;
   818 }
   819 
   820 void
   821 Cocoa_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
   822 {
   823     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   824     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   825     NSWindow *nswindow = data->nswindow;
   826     NSRect rect;
   827 
   828     /* The view responder chain gets messed with during setStyleMask */
   829     if ([[nswindow contentView] nextResponder] == data->listener) {
   830         [[nswindow contentView] setNextResponder:nil];
   831     }
   832 
   833     if (fullscreen) {
   834         SDL_Rect bounds;
   835 
   836         Cocoa_GetDisplayBounds(_this, display, &bounds);
   837         rect.origin.x = bounds.x;
   838         rect.origin.y = bounds.y;
   839         rect.size.width = bounds.w;
   840         rect.size.height = bounds.h;
   841         ConvertNSRect(&rect);
   842 
   843         /* Hack to fix origin on Mac OS X 10.4 */
   844         NSRect screenRect = [[nswindow screen] frame];
   845         if (screenRect.size.height >= 1.0f) {
   846             rect.origin.y += (screenRect.size.height - rect.size.height);
   847         }
   848 
   849         if ([nswindow respondsToSelector: @selector(setStyleMask:)]) {
   850             [nswindow performSelector: @selector(setStyleMask:) withObject: (id)NSBorderlessWindowMask];
   851         } else {
   852             nswindow = Cocoa_RebuildWindow(data, nswindow, NSBorderlessWindowMask);
   853         }
   854     } else {
   855         rect.origin.x = window->windowed.x;
   856         rect.origin.y = window->windowed.y;
   857         rect.size.width = window->windowed.w;
   858         rect.size.height = window->windowed.h;
   859         ConvertNSRect(&rect);
   860 
   861         if ([nswindow respondsToSelector: @selector(setStyleMask:)]) {
   862             [nswindow performSelector: @selector(setStyleMask:) withObject: (id)(uintptr_t)GetWindowStyle(window)];
   863         } else {
   864             nswindow = Cocoa_RebuildWindow(data, nswindow, GetWindowStyle(window));
   865         }
   866     }
   867 
   868     /* The view responder chain gets messed with during setStyleMask */
   869     if ([[nswindow contentView] nextResponder] != data->listener) {
   870         [[nswindow contentView] setNextResponder:data->listener];
   871     }
   872 
   873     s_moveHack = 0;
   874     [nswindow setFrameOrigin:rect.origin];
   875     [nswindow setContentSize:rect.size];
   876     s_moveHack = SDL_GetTicks();
   877 
   878     /* When the window style changes the title is cleared */
   879     if (!fullscreen) {
   880         Cocoa_SetWindowTitle(_this, window);
   881     }
   882 
   883 #ifdef FULLSCREEN_TOGGLEABLE
   884     if (fullscreen) {
   885         /* OpenGL is rendering to the window, so make it visible! */
   886         [nswindow setLevel:CGShieldingWindowLevel()];
   887     } else {
   888         [nswindow setLevel:kCGNormalWindowLevel];
   889     }
   890 #endif
   891     [nswindow makeKeyAndOrderFront:nil];
   892 
   893     if (window == _this->current_glwin) {
   894         [((NSOpenGLContext *) _this->current_glctx) update];
   895     }
   896 
   897     [pool release];
   898 }
   899 
   900 int
   901 Cocoa_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
   902 {
   903     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
   904     CGDirectDisplayID display_id = ((SDL_DisplayData *)display->driverdata)->display;
   905     const uint32_t tableSize = 256;
   906     CGGammaValue redTable[tableSize];
   907     CGGammaValue greenTable[tableSize];
   908     CGGammaValue blueTable[tableSize];
   909     uint32_t i;
   910     float inv65535 = 1.0f / 65535.0f;
   911 
   912     /* Extract gamma values into separate tables, convert to floats between 0.0 and 1.0 */
   913     for (i = 0; i < 256; i++) {
   914         redTable[i] = ramp[0*256+i] * inv65535;
   915         greenTable[i] = ramp[1*256+i] * inv65535;
   916         blueTable[i] = ramp[2*256+i] * inv65535;
   917     }
   918 
   919     if (CGSetDisplayTransferByTable(display_id, tableSize,
   920                                     redTable, greenTable, blueTable) != CGDisplayNoErr) {
   921         SDL_SetError("CGSetDisplayTransferByTable()");
   922         return -1;
   923     }
   924     return 0;
   925 }
   926 
   927 int
   928 Cocoa_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp)
   929 {
   930     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
   931     CGDirectDisplayID display_id = ((SDL_DisplayData *)display->driverdata)->display;
   932     const uint32_t tableSize = 256;
   933     CGGammaValue redTable[tableSize];
   934     CGGammaValue greenTable[tableSize];
   935     CGGammaValue blueTable[tableSize];
   936     uint32_t i, tableCopied;
   937 
   938     if (CGGetDisplayTransferByTable(display_id, tableSize,
   939                                     redTable, greenTable, blueTable, &tableCopied) != CGDisplayNoErr) {
   940         SDL_SetError("CGGetDisplayTransferByTable()");
   941         return -1;
   942     }
   943 
   944     for (i = 0; i < tableCopied; i++) {
   945         ramp[0*256+i] = (Uint16)(redTable[i] * 65535.0f);
   946         ramp[1*256+i] = (Uint16)(greenTable[i] * 65535.0f);
   947         ramp[2*256+i] = (Uint16)(blueTable[i] * 65535.0f);
   948     }
   949     return 0;
   950 }
   951 
   952 void
   953 Cocoa_SetWindowGrab(_THIS, SDL_Window * window)
   954 {
   955     /* Move the cursor to the nearest point in the window */
   956     if ((window->flags & SDL_WINDOW_INPUT_GRABBED) &&
   957         (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
   958         int x, y;
   959         CGPoint cgpoint;
   960 
   961         SDL_GetMouseState(&x, &y);
   962         cgpoint.x = window->x + x;
   963         cgpoint.y = window->y + y;
   964         CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
   965     }
   966 }
   967 
   968 void
   969 Cocoa_DestroyWindow(_THIS, SDL_Window * window)
   970 {
   971     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   972     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   973 
   974     if (data) {
   975         [data->listener close];
   976         [data->listener release];
   977         if (data->created) {
   978             [data->nswindow close];
   979         }
   980         SDL_free(data);
   981     }
   982     [pool release];
   983 }
   984 
   985 SDL_bool
   986 Cocoa_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
   987 {
   988     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
   989 
   990     if (info->version.major <= SDL_MAJOR_VERSION) {
   991         info->subsystem = SDL_SYSWM_COCOA;
   992         info->info.cocoa.window = nswindow;
   993         return SDL_TRUE;
   994     } else {
   995         SDL_SetError("Application not compiled with SDL %d.%d\n",
   996                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
   997         return SDL_FALSE;
   998     }
   999 }
  1000 
  1001 #endif /* SDL_VIDEO_DRIVER_COCOA */
  1002 
  1003 /* vi: set ts=4 sw=4 expandtab: */