src/video/cocoa/SDL_cocoawindow.m
author Sam Lantinga
Mon, 21 Feb 2011 21:32:11 -0800
changeset 5379 78c071fe4c37
parent 5378 738a96883fa6
child 5380 2de85077eb0b
permissions -rw-r--r--
We can defer window creation.
Added documentation for why we need an SDLView
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2011 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 #include "SDL_syswm.h"
    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 static __inline__ void ConvertNSRect(NSRect *r)
    35 {
    36     r->origin.y = CGDisplayPixelsHigh(kCGDirectMainDisplay) - r->origin.y - r->size.height;
    37 }
    38 
    39 @implementation Cocoa_WindowListener
    40 
    41 - (void)listen:(SDL_WindowData *)data
    42 {
    43     NSNotificationCenter *center;
    44     NSWindow *window = data->nswindow;
    45     NSView *view = [window contentView];
    46 
    47     _data = data;
    48 
    49     center = [NSNotificationCenter defaultCenter];
    50 
    51     if ([window delegate] != nil) {
    52         [center addObserver:self selector:@selector(windowDidExpose:) name:NSWindowDidExposeNotification object:window];
    53         [center addObserver:self selector:@selector(windowDidMove:) name:NSWindowDidMoveNotification object:window];
    54         [center addObserver:self selector:@selector(windowDidResize:) name:NSWindowDidResizeNotification object:window];
    55         [center addObserver:self selector:@selector(windowDidMiniaturize:) name:NSWindowDidMiniaturizeNotification object:window];
    56         [center addObserver:self selector:@selector(windowDidDeminiaturize:) name:NSWindowDidDeminiaturizeNotification object:window];
    57         [center addObserver:self selector:@selector(windowDidBecomeKey:) name:NSWindowDidBecomeKeyNotification object:window];
    58         [center addObserver:self selector:@selector(windowDidResignKey:) name:NSWindowDidResignKeyNotification object:window];
    59     } else {
    60         [window setDelegate:self];
    61     }
    62     [center addObserver:self selector:@selector(windowDidHide:) name:NSApplicationDidHideNotification object:NSApp];
    63     [center addObserver:self selector:@selector(windowDidUnhide:) name:NSApplicationDidUnhideNotification object:NSApp];
    64 
    65     [window setNextResponder:self];
    66     [window setAcceptsMouseMovedEvents:YES];
    67 
    68     [view setNextResponder:self];
    69     [view addTrackingRect:[view visibleRect] owner:self userData:nil assumeInside:NO];
    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     [center removeObserver:self name:NSApplicationDidHideNotification object:NSApp];
    95     [center removeObserver:self name:NSApplicationDidUnhideNotification object:NSApp];
    96 
    97     if ([window nextResponder] == self) {
    98         [window setNextResponder:nil];
    99     }
   100     if ([view nextResponder] == self) {
   101         [view setNextResponder:nil];
   102     }
   103 }
   104 
   105 - (BOOL)windowShouldClose:(id)sender
   106 {
   107     SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_CLOSE, 0, 0);
   108     return NO;
   109 }
   110 
   111 - (void)windowDidExpose:(NSNotification *)aNotification
   112 {
   113     SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_EXPOSED, 0, 0);
   114 }
   115 
   116 - (void)windowDidMove:(NSNotification *)aNotification
   117 {
   118     int x, y;
   119     NSRect rect = [_data->nswindow contentRectForFrameRect:[_data->nswindow frame]];
   120     ConvertNSRect(&rect);
   121     x = (int)rect.origin.x;
   122     y = (int)rect.origin.y;
   123     SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_MOVED, x, y);
   124 }
   125 
   126 - (void)windowDidResize:(NSNotification *)aNotification
   127 {
   128     int w, h;
   129     NSRect rect = [_data->nswindow contentRectForFrameRect:[_data->nswindow frame]];
   130     w = (int)rect.size.width;
   131     h = (int)rect.size.height;
   132     if (SDL_IsShapedWindow(_data->window))
   133         Cocoa_ResizeWindowShape(_data->window);
   134     SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_RESIZED, w, h);
   135 }
   136 
   137 - (void)windowDidMiniaturize:(NSNotification *)aNotification
   138 {
   139     SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
   140 }
   141 
   142 - (void)windowDidDeminiaturize:(NSNotification *)aNotification
   143 {
   144     SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_RESTORED, 0, 0);
   145 }
   146 
   147 - (void)windowDidBecomeKey:(NSNotification *)aNotification
   148 {
   149     SDL_Window *window = _data->window;
   150 
   151     /* We're going to get keyboard events, since we're key. */
   152     SDL_SetKeyboardFocus(window);
   153 
   154     /* If we just gained focus we need the updated mouse position */
   155     if (SDL_GetMouseFocus() == window) {
   156         NSPoint point;
   157         point = [NSEvent mouseLocation];
   158         point = [_data->nswindow convertScreenToBase:point];
   159         point.y = window->h - point.y;
   160         SDL_SendMouseMotion(window, 0, (int)point.x, (int)point.y);
   161     }
   162 
   163     /* Check to see if someone updated the clipboard */
   164     Cocoa_CheckClipboardUpdate(_data->videodata);
   165 }
   166 
   167 - (void)windowDidResignKey:(NSNotification *)aNotification
   168 {
   169     /* Some other window will get mouse events, since we're not key. */
   170     if (SDL_GetMouseFocus() == _data->window) {
   171         SDL_SetMouseFocus(NULL);
   172     }
   173 
   174     /* Some other window will get keyboard events, since we're not key. */
   175     if (SDL_GetKeyboardFocus() == _data->window) {
   176         SDL_SetKeyboardFocus(NULL);
   177     }
   178 }
   179 
   180 - (void)windowDidHide:(NSNotification *)aNotification
   181 {
   182     SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
   183 }
   184 
   185 - (void)windowDidUnhide:(NSNotification *)aNotification
   186 {
   187     SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
   188 }
   189 
   190 - (void)mouseDown:(NSEvent *)theEvent
   191 {
   192     int button;
   193 
   194     switch ([theEvent buttonNumber]) {
   195     case 0:
   196         button = SDL_BUTTON_LEFT;
   197         break;
   198     case 1:
   199         button = SDL_BUTTON_RIGHT;
   200         break;
   201     case 2:
   202         button = SDL_BUTTON_MIDDLE;
   203         break;
   204     default:
   205         button = [theEvent buttonNumber] + 1;
   206         break;
   207     }
   208     SDL_SendMouseButton(_data->window, SDL_PRESSED, button);
   209 }
   210 
   211 - (void)rightMouseDown:(NSEvent *)theEvent
   212 {
   213     [self mouseDown:theEvent];
   214 }
   215 
   216 - (void)otherMouseDown:(NSEvent *)theEvent
   217 {
   218     [self mouseDown:theEvent];
   219 }
   220 
   221 - (void)mouseUp:(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_RELEASED, button);
   240 }
   241 
   242 - (void)rightMouseUp:(NSEvent *)theEvent
   243 {
   244     [self mouseUp:theEvent];
   245 }
   246 
   247 - (void)otherMouseUp:(NSEvent *)theEvent
   248 {
   249     [self mouseUp:theEvent];
   250 }
   251 
   252 - (void)mouseEntered:(NSEvent *)theEvent
   253 {
   254     SDL_Mouse *mouse = SDL_GetMouse();
   255 
   256     SDL_SetMouseFocus(_data->window);
   257 
   258     if (!mouse->cursor_shown) {
   259         [NSCursor hide];
   260     }
   261 }
   262 
   263 - (void)mouseExited:(NSEvent *)theEvent
   264 {
   265     SDL_Window *window = _data->window;
   266     SDL_Mouse *mouse = SDL_GetMouse();
   267 
   268     if (SDL_GetMouseFocus() == window) {
   269         if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
   270             int x, y;
   271             NSPoint point;
   272             CGPoint cgpoint;
   273 
   274             point = [theEvent locationInWindow];
   275             point.y = window->h - point.y;
   276 
   277             SDL_SendMouseMotion(window, 0, (int)point.x, (int)point.y);
   278             SDL_GetMouseState(&x, &y);
   279             cgpoint.x = window->x + x;
   280             cgpoint.y = window->y + y;
   281             CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
   282         } else {
   283             SDL_SetMouseFocus(NULL);
   284         }
   285     }
   286 
   287     if (!mouse->cursor_shown) {
   288         [NSCursor unhide];
   289     }
   290 }
   291 
   292 - (void)mouseMoved:(NSEvent *)theEvent
   293 {
   294     SDL_Window *window = _data->window;
   295 
   296 #ifdef RELATIVE_MOTION
   297     if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
   298         return;
   299     }
   300 #endif
   301 
   302     if (SDL_GetMouseFocus() == window) {
   303         NSPoint point;
   304 
   305         point = [theEvent locationInWindow];
   306         point.y = window->h - point.y;
   307 
   308         SDL_SendMouseMotion(window, 0, (int)point.x, (int)point.y);
   309     }
   310 }
   311 
   312 - (void)mouseDragged:(NSEvent *)theEvent
   313 {
   314     [self mouseMoved:theEvent];
   315 }
   316 
   317 - (void)rightMouseDragged:(NSEvent *)theEvent
   318 {
   319     [self mouseMoved:theEvent];
   320 }
   321 
   322 - (void)otherMouseDragged:(NSEvent *)theEvent
   323 {
   324     [self mouseMoved:theEvent];
   325 }
   326 
   327 - (void)scrollWheel:(NSEvent *)theEvent
   328 {
   329     Cocoa_HandleMouseWheel(_data->window, theEvent);
   330 }
   331 
   332 - (void)touchesBeganWithEvent:(NSEvent *) theEvent
   333 {
   334     [self handleTouches:COCOA_TOUCH_DOWN withEvent:theEvent];
   335 }
   336 
   337 - (void)touchesMovedWithEvent:(NSEvent *) theEvent
   338 {
   339     [self handleTouches:COCOA_TOUCH_MOVE withEvent:theEvent];
   340 }
   341 
   342 - (void)touchesEndedWithEvent:(NSEvent *) theEvent
   343 {
   344     [self handleTouches:COCOA_TOUCH_UP withEvent:theEvent];
   345 }
   346 
   347 - (void)touchesCancelledWithEvent:(NSEvent *) theEvent
   348 {
   349     [self handleTouches:COCOA_TOUCH_CANCELLED withEvent:theEvent];
   350 }
   351 
   352 - (void)handleTouches:(cocoaTouchType)type withEvent:(NSEvent *)event
   353 {
   354 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
   355     NSSet *touches = 0;
   356     NSEnumerator *enumerator;
   357     NSTouch *touch;
   358 
   359     switch (type) {
   360         case COCOA_TOUCH_DOWN:
   361             touches = [event touchesMatchingPhase:NSTouchPhaseBegan inView:nil];
   362             break;
   363         case COCOA_TOUCH_UP:
   364         case COCOA_TOUCH_CANCELLED:
   365             touches = [event touchesMatchingPhase:NSTouchPhaseEnded inView:nil];
   366             break;
   367         case COCOA_TOUCH_MOVE:
   368             touches = [event touchesMatchingPhase:NSTouchPhaseMoved inView:nil];
   369             break;
   370     }
   371 
   372     enumerator = [touches objectEnumerator];
   373     touch = (NSTouch*)[enumerator nextObject];
   374     while (touch) {
   375         SDL_TouchID touchId = (SDL_TouchID)[touch device];
   376         if (!SDL_GetTouch(touchId)) {
   377             SDL_Touch touch;
   378 
   379             touch.id = touchId;
   380             touch.x_min = 0;
   381             touch.x_max = 1;
   382             touch.native_xres = touch.x_max - touch.x_min;
   383             touch.y_min = 0;
   384             touch.y_max = 1;
   385             touch.native_yres = touch.y_max - touch.y_min;
   386             touch.pressure_min = 0;
   387             touch.pressure_max = 1;
   388             touch.native_pressureres = touch.pressure_max - touch.pressure_min;
   389             
   390             if (SDL_AddTouch(&touch, "") < 0) {
   391                 return;
   392             }
   393         } 
   394 
   395         SDL_FingerID fingerId = (SDL_FingerID)[touch identity];
   396         float x = [touch normalizedPosition].x;
   397         float y = [touch normalizedPosition].y;
   398         /* Make the origin the upper left instead of the lower left */
   399         y = 1.0f - y;
   400 
   401         switch (type) {
   402         case COCOA_TOUCH_DOWN:
   403             SDL_SendFingerDown(touchId, fingerId, SDL_TRUE, x, y, 1);
   404             break;
   405         case COCOA_TOUCH_UP:
   406         case COCOA_TOUCH_CANCELLED:
   407             SDL_SendFingerDown(touchId, fingerId, SDL_FALSE, x, y, 1);
   408             break;
   409         case COCOA_TOUCH_MOVE:
   410             SDL_SendTouchMotion(touchId, fingerId, SDL_FALSE, x, y, 1);
   411             break;
   412         }
   413         
   414         touch = (NSTouch*)[enumerator nextObject];
   415     }
   416 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 */
   417 }
   418 
   419 @end
   420 
   421 @interface SDLWindow : NSWindow
   422 /* These are needed for borderless/fullscreen windows */
   423 - (BOOL)canBecomeKeyWindow;
   424 - (BOOL)canBecomeMainWindow;
   425 @end
   426 
   427 @implementation SDLWindow
   428 - (BOOL)canBecomeKeyWindow
   429 {
   430     return YES;
   431 }
   432 
   433 - (BOOL)canBecomeMainWindow
   434 {
   435     return YES;
   436 }
   437 @end
   438 
   439 @interface SDLView : NSView
   440 /* The default implementation doesn't pass rightMouseDown to responder chain */
   441 - (void)rightMouseDown:(NSEvent *)theEvent;
   442 @end
   443 
   444 @implementation SDLView
   445 - (void)rightMouseDown:(NSEvent *)theEvent
   446 {
   447     [[self nextResponder] rightMouseDown:theEvent];
   448 }
   449 @end
   450 
   451 static unsigned int
   452 GetWindowStyle(SDL_Window * window)
   453 {
   454     unsigned int style;
   455 
   456 	if (window->flags & SDL_WINDOW_FULLSCREEN) {
   457         style = NSBorderlessWindowMask;
   458 	} else {
   459 		if (window->flags & SDL_WINDOW_BORDERLESS) {
   460 			style = NSBorderlessWindowMask;
   461 		} else {
   462 			style = (NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask);
   463 		}
   464 		if (window->flags & SDL_WINDOW_RESIZABLE) {
   465 			style |= NSResizableWindowMask;
   466 		}
   467 	}
   468     return style;
   469 }
   470 
   471 static int
   472 SetupWindowData(_THIS, SDL_Window * window, NSWindow *nswindow, SDL_bool created)
   473 {
   474     NSAutoreleasePool *pool;
   475     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
   476     SDL_WindowData *data;
   477 
   478     /* Allocate the window data */
   479     data = (SDL_WindowData *) SDL_calloc(1, sizeof(*data));
   480     if (!data) {
   481         SDL_OutOfMemory();
   482         return -1;
   483     }
   484     data->window = window;
   485     data->nswindow = nswindow;
   486     data->created = created;
   487     data->videodata = videodata;
   488 
   489     pool = [[NSAutoreleasePool alloc] init];
   490 
   491     /* Create an event listener for the window */
   492     data->listener = [[Cocoa_WindowListener alloc] init];
   493 
   494     /* Fill in the SDL window with the window data */
   495     {
   496         NSRect rect = [nswindow contentRectForFrameRect:[nswindow frame]];
   497         NSView *contentView = [[SDLView alloc] initWithFrame:rect];
   498         [nswindow setContentView: contentView];
   499         [contentView release];
   500 
   501         ConvertNSRect(&rect);
   502         window->x = (int)rect.origin.x;
   503         window->y = (int)rect.origin.y;
   504         window->w = (int)rect.size.width;
   505         window->h = (int)rect.size.height;
   506     }
   507 
   508     /* Set up the listener after we create the view */
   509     [data->listener listen:data];
   510 
   511     if ([nswindow isVisible]) {
   512         window->flags |= SDL_WINDOW_SHOWN;
   513     } else {
   514         window->flags &= ~SDL_WINDOW_SHOWN;
   515     }
   516     {
   517         unsigned int style = [nswindow styleMask];
   518 
   519         if ((style & ~NSResizableWindowMask) == NSBorderlessWindowMask) {
   520             window->flags |= SDL_WINDOW_BORDERLESS;
   521         } else {
   522             window->flags &= ~SDL_WINDOW_BORDERLESS;
   523         }
   524         if (style & NSResizableWindowMask) {
   525             window->flags |= SDL_WINDOW_RESIZABLE;
   526         } else {
   527             window->flags &= ~SDL_WINDOW_RESIZABLE;
   528         }
   529     }
   530     if ([nswindow isZoomed]) {
   531         window->flags |= SDL_WINDOW_MAXIMIZED;
   532     } else {
   533         window->flags &= ~SDL_WINDOW_MAXIMIZED;
   534     }
   535     if ([nswindow isMiniaturized]) {
   536         window->flags |= SDL_WINDOW_MINIMIZED;
   537     } else {
   538         window->flags &= ~SDL_WINDOW_MINIMIZED;
   539     }
   540     if ([nswindow isKeyWindow]) {
   541         window->flags |= SDL_WINDOW_INPUT_FOCUS;
   542         SDL_SetKeyboardFocus(data->window);
   543 
   544         if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
   545             /* FIXME */
   546         }
   547     }
   548 
   549     /* All done! */
   550     [pool release];
   551     window->driverdata = data;
   552     return 0;
   553 }
   554 
   555 int
   556 Cocoa_CreateWindow(_THIS, SDL_Window * window)
   557 {
   558     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   559     NSWindow *nswindow;
   560     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
   561     NSRect rect;
   562     SDL_Rect bounds;
   563     unsigned int style;
   564 
   565     Cocoa_GetDisplayBounds(_this, display, &bounds);
   566     if (SDL_WINDOWPOS_ISCENTERED(window->x)) {
   567         rect.origin.x = bounds.x + (bounds.w - window->w) / 2;
   568     } else if (SDL_WINDOWPOS_ISUNDEFINED(window->x)) {
   569         rect.origin.x = bounds.x;
   570     } else {
   571         rect.origin.x = window->x;
   572     }
   573     if (SDL_WINDOWPOS_ISCENTERED(window->y)) {
   574         rect.origin.y = bounds.y + (bounds.h - window->h) / 2;
   575     } else if (SDL_WINDOWPOS_ISUNDEFINED(window->y)) {
   576         rect.origin.y = bounds.y;
   577     } else {
   578         rect.origin.y = window->y;
   579     }
   580     rect.size.width = window->w;
   581     rect.size.height = window->h;
   582     ConvertNSRect(&rect);
   583 
   584     style = GetWindowStyle(window);
   585 
   586     /* Figure out which screen to place this window */
   587     NSArray *screens = [NSScreen screens];
   588     NSScreen *screen = nil;
   589     NSScreen *candidate;
   590     int i, count = [screens count];
   591     for (i = 0; i < count; ++i) {
   592         candidate = [screens objectAtIndex:i];
   593         NSRect screenRect = [candidate frame];
   594         if (rect.origin.x >= screenRect.origin.x &&
   595             rect.origin.x < screenRect.origin.x + screenRect.size.width &&
   596             rect.origin.y >= screenRect.origin.y &&
   597             rect.origin.y < screenRect.origin.y + screenRect.size.height) {
   598             screen = candidate;
   599             rect.origin.x -= screenRect.origin.x;
   600             rect.origin.y -= screenRect.origin.y;
   601         }
   602     }
   603     nswindow = [[SDLWindow alloc] initWithContentRect:rect styleMask:style backing:NSBackingStoreBuffered defer:YES screen:screen];
   604 
   605     [pool release];
   606 
   607     if (SetupWindowData(_this, window, nswindow, SDL_TRUE) < 0) {
   608         [nswindow release];
   609         return -1;
   610     }
   611     return 0;
   612 }
   613 
   614 int
   615 Cocoa_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
   616 {
   617     NSAutoreleasePool *pool;
   618     NSWindow *nswindow = (NSWindow *) data;
   619     NSString *title;
   620 
   621     pool = [[NSAutoreleasePool alloc] init];
   622 
   623     /* Query the title from the existing window */
   624     title = [nswindow title];
   625     if (title) {
   626         window->title = SDL_strdup([title UTF8String]);
   627     }
   628 
   629     [pool release];
   630 
   631     return SetupWindowData(_this, window, nswindow, SDL_FALSE);
   632 }
   633 
   634 void
   635 Cocoa_SetWindowTitle(_THIS, SDL_Window * window)
   636 {
   637     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   638     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
   639     NSString *string;
   640 
   641     if(window->title) {
   642         string = [[NSString alloc] initWithUTF8String:window->title];
   643     } else {
   644         string = [[NSString alloc] init];
   645     }
   646     [nswindow setTitle:string];
   647     [string release];
   648 
   649     [pool release];
   650 }
   651 
   652 void
   653 Cocoa_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
   654 {
   655     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   656     NSImage *nsimage = Cocoa_CreateImage(icon);
   657 
   658     if (nsimage) {
   659         [NSApp setApplicationIconImage:nsimage];
   660     }
   661 
   662     [pool release];
   663 }
   664 
   665 void
   666 Cocoa_SetWindowPosition(_THIS, SDL_Window * window)
   667 {
   668     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   669     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
   670     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
   671     NSRect rect;
   672     SDL_Rect bounds;
   673 
   674     Cocoa_GetDisplayBounds(_this, display, &bounds);
   675     if (SDL_WINDOWPOS_ISCENTERED(window->x)) {
   676         rect.origin.x = bounds.x + (bounds.w - window->w) / 2;
   677     } else {
   678         rect.origin.x = window->x;
   679     }
   680     if (SDL_WINDOWPOS_ISCENTERED(window->y)) {
   681         rect.origin.y = bounds.y + (bounds.h - window->h) / 2;
   682     } else {
   683         rect.origin.y = window->y;
   684     }
   685     rect.size.width = window->w;
   686     rect.size.height = window->h;
   687     ConvertNSRect(&rect);
   688     rect = [nswindow frameRectForContentRect:rect];
   689     [nswindow setFrameOrigin:rect.origin];
   690     [pool release];
   691 }
   692 
   693 void
   694 Cocoa_SetWindowSize(_THIS, SDL_Window * window)
   695 {
   696     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   697     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
   698     NSSize size;
   699 
   700     size.width = window->w;
   701     size.height = window->h;
   702     [nswindow setContentSize:size];
   703     [pool release];
   704 }
   705 
   706 void
   707 Cocoa_ShowWindow(_THIS, SDL_Window * window)
   708 {
   709     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   710     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
   711 
   712     if (![nswindow isMiniaturized]) {
   713         [nswindow makeKeyAndOrderFront:nil];
   714     }
   715     [pool release];
   716 }
   717 
   718 void
   719 Cocoa_HideWindow(_THIS, SDL_Window * window)
   720 {
   721     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   722     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
   723 
   724     [nswindow orderOut:nil];
   725     [pool release];
   726 }
   727 
   728 void
   729 Cocoa_RaiseWindow(_THIS, SDL_Window * window)
   730 {
   731     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   732     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
   733 
   734     [nswindow makeKeyAndOrderFront:nil];
   735     [pool release];
   736 }
   737 
   738 void
   739 Cocoa_MaximizeWindow(_THIS, SDL_Window * window)
   740 {
   741     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   742     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
   743 
   744     [nswindow zoom:nil];
   745     [pool release];
   746 }
   747 
   748 void
   749 Cocoa_MinimizeWindow(_THIS, SDL_Window * window)
   750 {
   751     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   752     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
   753 
   754     [nswindow miniaturize:nil];
   755     [pool release];
   756 }
   757 
   758 void
   759 Cocoa_RestoreWindow(_THIS, SDL_Window * window)
   760 {
   761     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   762     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
   763 
   764     if ([nswindow isMiniaturized]) {
   765         [nswindow deminiaturize:nil];
   766     } else if ([nswindow isZoomed]) {
   767         [nswindow zoom:nil];
   768     }
   769     [pool release];
   770 }
   771 
   772 void
   773 Cocoa_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
   774 {
   775     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   776     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   777     NSWindow *nswindow = data->nswindow;
   778     NSRect rect;
   779 
   780     if (fullscreen) {
   781         SDL_Rect bounds;
   782 
   783         Cocoa_GetDisplayBounds(_this, display, &bounds);
   784         rect.origin.x = bounds.x;
   785         rect.origin.y = bounds.y;
   786         rect.size.width = bounds.w;
   787         rect.size.height = bounds.h;
   788         ConvertNSRect(&rect);
   789 
   790         if ([nswindow respondsToSelector: @selector(setStyleMask:)]) {
   791             [nswindow performSelector: @selector(setStyleMask:) withObject: (id)NSBorderlessWindowMask];
   792         }
   793         [nswindow setFrameOrigin:rect.origin];
   794         [nswindow setContentSize:rect.size];
   795     } else {
   796         if ([nswindow respondsToSelector: @selector(setStyleMask:)]) {
   797             [nswindow performSelector: @selector(setStyleMask:) withObject: (id)(uintptr_t)GetWindowStyle(window)];
   798         }
   799 
   800         // This doesn't seem to do anything...
   801         //[nswindow setFrameOrigin:origin];
   802     }
   803 
   804 #ifdef FULLSCREEN_TOGGLEABLE
   805     if (fullscreen) {
   806         /* OpenGL is rendering to the window, so make it visible! */
   807         [nswindow setLevel:CGShieldingWindowLevel()];
   808     } else {
   809         [nswindow setLevel:kCGNormalWindowLevel];
   810     }
   811 #endif
   812     [nswindow makeKeyAndOrderFront:nil];
   813 
   814     [pool release];
   815 }
   816 
   817 NSPoint origin;
   818 void
   819 Cocoa_SetWindowGrab(_THIS, SDL_Window * window)
   820 {
   821 #ifdef RELATIVE_MOTION
   822     /* FIXME: work in progress
   823         You set relative mode by using the following code in conjunction with
   824         CGDisplayHideCursor(kCGDirectMainDisplay) and
   825         CGDisplayShowCursor(kCGDirectMainDisplay)
   826     */
   827     if ((window->flags & SDL_WINDOW_INPUT_GRABBED) &&
   828         (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
   829         CGAssociateMouseAndMouseCursorPosition(NO);
   830     } else {
   831         CGAssociateMouseAndMouseCursorPosition(YES);
   832     }
   833 #else
   834     /* Move the cursor to the nearest point in the window */
   835     if ((window->flags & SDL_WINDOW_INPUT_GRABBED) &&
   836         (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
   837         int x, y;
   838         CGPoint cgpoint;
   839 
   840         SDL_GetMouseState(&x, &y);
   841         cgpoint.x = window->x + x;
   842         cgpoint.y = window->y + y;
   843         CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
   844     }
   845 #endif
   846 }
   847 
   848 void
   849 Cocoa_DestroyWindow(_THIS, SDL_Window * window)
   850 {
   851     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   852     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   853 
   854     if (data) {
   855         [data->listener close];
   856         [data->listener release];
   857         if (data->created) {
   858             [data->nswindow close];
   859         }
   860         SDL_free(data);
   861     }
   862     [pool release];
   863 }
   864 
   865 SDL_bool
   866 Cocoa_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
   867 {
   868     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
   869 
   870     if (info->version.major <= SDL_MAJOR_VERSION) {
   871         info->subsystem = SDL_SYSWM_COCOA;
   872         info->info.cocoa.window = nswindow;
   873         return SDL_TRUE;
   874     } else {
   875         SDL_SetError("Application not compiled with SDL %d.%d\n",
   876                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
   877         return SDL_FALSE;
   878     }
   879 }
   880 
   881 /* vi: set ts=4 sw=4 expandtab: */