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