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