Cocoa: Make the next-highest window gain focus when a window is closing.
(if the closed window wasn't the foreground, this is effectively a no-op.)
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
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.
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:
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.
21 #include "SDL_config.h"
23 #if SDL_VIDEO_DRIVER_COCOA
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"
37 static Uint32 s_moveHack;
39 static __inline__ void ConvertNSRect(NSRect *r)
41 r->origin.y = CGDisplayPixelsHigh(kCGDirectMainDisplay) - r->origin.y - r->size.height;
44 @implementation Cocoa_WindowListener
46 - (void)listen:(SDL_WindowData *)data
48 NSNotificationCenter *center;
49 NSWindow *window = data->nswindow;
50 NSView *view = [window contentView];
53 observingVisible = YES;
54 wasVisible = [window isVisible];
56 center = [NSNotificationCenter defaultCenter];
58 if ([window delegate] != nil) {
59 [center addObserver:self selector:@selector(windowDidExpose:) name:NSWindowDidExposeNotification object:window];
60 [center addObserver:self selector:@selector(windowDidMove:) name:NSWindowDidMoveNotification object:window];
61 [center addObserver:self selector:@selector(windowDidResize:) name:NSWindowDidResizeNotification object:window];
62 [center addObserver:self selector:@selector(windowDidMiniaturize:) name:NSWindowDidMiniaturizeNotification object:window];
63 [center addObserver:self selector:@selector(windowDidDeminiaturize:) name:NSWindowDidDeminiaturizeNotification object:window];
64 [center addObserver:self selector:@selector(windowDidBecomeKey:) name:NSWindowDidBecomeKeyNotification object:window];
65 [center addObserver:self selector:@selector(windowDidResignKey:) name:NSWindowDidResignKeyNotification object:window];
67 [window setDelegate:self];
70 /* Haven't found a delegate / notification that triggers when the window is
71 * ordered out (is not visible any more). You can be ordered out without
72 * minimizing, so DidMiniaturize doesn't work. (e.g. -[NSWindow orderOut:])
74 [window addObserver:self
76 options:NSKeyValueObservingOptionNew
79 [window setNextResponder:self];
80 [window setAcceptsMouseMovedEvents:YES];
82 [view setNextResponder:self];
84 if ([view respondsToSelector:@selector(setAcceptsTouchEvents:)]) {
85 [view setAcceptsTouchEvents:YES];
89 - (void)observeValueForKeyPath:(NSString *)keyPath
91 change:(NSDictionary *)change
92 context:(void *)context
94 if (!observingVisible) {
98 if (object == _data->nswindow && [keyPath isEqualToString:@"visible"]) {
99 int newVisibility = [[change objectForKey:@"new"] intValue];
101 SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
103 SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
108 -(void) pauseVisibleObservation
110 observingVisible = NO;
111 wasVisible = [_data->nswindow isVisible];
114 -(void) resumeVisibleObservation
116 BOOL isVisible = [_data->nswindow isVisible];
117 observingVisible = YES;
118 if (wasVisible != isVisible) {
120 SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
122 SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
125 wasVisible = isVisible;
131 NSNotificationCenter *center;
132 NSWindow *window = _data->nswindow;
133 NSView *view = [window contentView];
134 NSArray *windows = nil;
136 center = [NSNotificationCenter defaultCenter];
138 if ([window delegate] != self) {
139 [center removeObserver:self name:NSWindowDidExposeNotification object:window];
140 [center removeObserver:self name:NSWindowDidMoveNotification object:window];
141 [center removeObserver:self name:NSWindowDidResizeNotification object:window];
142 [center removeObserver:self name:NSWindowDidMiniaturizeNotification object:window];
143 [center removeObserver:self name:NSWindowDidDeminiaturizeNotification object:window];
144 [center removeObserver:self name:NSWindowDidBecomeKeyNotification object:window];
145 [center removeObserver:self name:NSWindowDidResignKeyNotification object:window];
147 [window setDelegate:nil];
150 [window removeObserver:self
151 forKeyPath:@"visible"];
153 if ([window nextResponder] == self) {
154 [window setNextResponder:nil];
156 if ([view nextResponder] == self) {
157 [view setNextResponder:nil];
160 /* Make the next window in the z-order Key. If we weren't the foreground
161 when closed, this is a no-op. */
162 windows = [NSApp orderedWindows];
163 if ([windows count] > 0) {
164 NSWindow *win = (NSWindow *) [windows objectAtIndex:0];
165 [win makeKeyAndOrderFront:self];
169 - (BOOL)windowShouldClose:(id)sender
171 SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_CLOSE, 0, 0);
175 - (void)windowDidExpose:(NSNotification *)aNotification
177 SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_EXPOSED, 0, 0);
180 - (void)windowDidMove:(NSNotification *)aNotification
183 SDL_VideoDevice *device = SDL_GetVideoDevice();
184 SDL_Window *window = _data->window;
185 NSWindow *nswindow = _data->nswindow;
186 NSRect rect = [nswindow contentRectForFrameRect:[nswindow frame]];
187 ConvertNSRect(&rect);
190 SDL_bool blockMove = ((SDL_GetTicks() - s_moveHack) < 500);
195 /* Cocoa is adjusting the window in response to a mode change */
196 rect.origin.x = window->x;
197 rect.origin.y = window->y;
198 ConvertNSRect(&rect);
199 [nswindow setFrameOrigin:rect.origin];
204 x = (int)rect.origin.x;
205 y = (int)rect.origin.y;
207 if (window == device->current_glwin) {
208 [((NSOpenGLContext *) device->current_glctx) update];
211 SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, x, y);
214 - (void)windowDidResize:(NSNotification *)aNotification
216 SDL_VideoDevice *device = SDL_GetVideoDevice();
218 NSRect rect = [_data->nswindow contentRectForFrameRect:[_data->nswindow frame]];
219 ConvertNSRect(&rect);
220 x = (int)rect.origin.x;
221 y = (int)rect.origin.y;
222 w = (int)rect.size.width;
223 h = (int)rect.size.height;
224 if (SDL_IsShapedWindow(_data->window))
225 Cocoa_ResizeWindowShape(_data->window);
227 if (_data->window == device->current_glwin) {
228 [((NSOpenGLContext *) device->current_glctx) update];
231 /* The window can move during a resize event, such as when maximizing
232 or resizing from a corner */
233 SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_MOVED, x, y);
234 SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_RESIZED, w, h);
237 - (void)windowDidMiniaturize:(NSNotification *)aNotification
239 SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
242 - (void)windowDidDeminiaturize:(NSNotification *)aNotification
244 SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_RESTORED, 0, 0);
247 - (void)windowDidBecomeKey:(NSNotification *)aNotification
249 SDL_Window *window = _data->window;
250 SDL_Mouse *mouse = SDL_GetMouse();
252 /* We're going to get keyboard events, since we're key. */
253 SDL_SetKeyboardFocus(window);
255 /* If we just gained focus we need the updated mouse position */
256 if (!mouse->relative_mode) {
260 point = [_data->nswindow mouseLocationOutsideOfEventStream];
262 y = (int)(window->h - point.y);
264 if (x >= 0 && x < window->w && y >= 0 && y < window->h) {
265 SDL_SendMouseMotion(window, 0, 0, x, y);
269 /* Check to see if someone updated the clipboard */
270 Cocoa_CheckClipboardUpdate(_data->videodata);
273 - (void)windowDidResignKey:(NSNotification *)aNotification
275 /* Some other window will get mouse events, since we're not key. */
276 if (SDL_GetMouseFocus() == _data->window) {
277 SDL_SetMouseFocus(NULL);
280 /* Some other window will get keyboard events, since we're not key. */
281 if (SDL_GetKeyboardFocus() == _data->window) {
282 SDL_SetKeyboardFocus(NULL);
286 /* We'll respond to key events by doing nothing so we don't beep.
287 * We could handle key messages here, but we lose some in the NSApp dispatch,
288 * where they get converted to action messages, etc.
290 - (void)flagsChanged:(NSEvent *)theEvent
292 /*Cocoa_HandleKeyEvent(SDL_GetVideoDevice(), theEvent);*/
294 - (void)keyDown:(NSEvent *)theEvent
296 /*Cocoa_HandleKeyEvent(SDL_GetVideoDevice(), theEvent);*/
298 - (void)keyUp:(NSEvent *)theEvent
300 /*Cocoa_HandleKeyEvent(SDL_GetVideoDevice(), theEvent);*/
303 /* We'll respond to selectors by doing nothing so we don't beep.
304 * The escape key gets converted to a "cancel" selector, etc.
306 - (void)doCommandBySelector:(SEL)aSelector
308 /*NSLog(@"doCommandBySelector: %@\n", NSStringFromSelector(aSelector));*/
311 - (void)mouseDown:(NSEvent *)theEvent
315 switch ([theEvent buttonNumber]) {
317 button = SDL_BUTTON_LEFT;
320 button = SDL_BUTTON_RIGHT;
323 button = SDL_BUTTON_MIDDLE;
326 button = [theEvent buttonNumber] + 1;
329 SDL_SendMouseButton(_data->window, 0, SDL_PRESSED, button);
332 - (void)rightMouseDown:(NSEvent *)theEvent
334 [self mouseDown:theEvent];
337 - (void)otherMouseDown:(NSEvent *)theEvent
339 [self mouseDown:theEvent];
342 - (void)mouseUp:(NSEvent *)theEvent
346 switch ([theEvent buttonNumber]) {
348 button = SDL_BUTTON_LEFT;
351 button = SDL_BUTTON_RIGHT;
354 button = SDL_BUTTON_MIDDLE;
357 button = [theEvent buttonNumber] + 1;
360 SDL_SendMouseButton(_data->window, 0, SDL_RELEASED, button);
363 - (void)rightMouseUp:(NSEvent *)theEvent
365 [self mouseUp:theEvent];
368 - (void)otherMouseUp:(NSEvent *)theEvent
370 [self mouseUp:theEvent];
373 - (void)mouseMoved:(NSEvent *)theEvent
375 SDL_Mouse *mouse = SDL_GetMouse();
376 SDL_Window *window = _data->window;
380 if (mouse->relative_mode) {
384 point = [theEvent locationInWindow];
386 y = (int)(window->h - point.y);
388 if (x < 0 || x >= window->w || y < 0 || y >= window->h) {
389 if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
394 } else if (x >= window->w) {
399 } else if (y >= window->h) {
403 cgpoint.x = window->x + x;
404 cgpoint.y = window->y + y;
406 /* According to the docs, this was deprecated in 10.6, but it's still
407 * around. The substitute requires a CGEventSource, but I'm not entirely
408 * sure how we'd procure the right one for this event.
410 CGSetLocalEventsSuppressionInterval(0.0);
411 CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
412 CGSetLocalEventsSuppressionInterval(0.25);
415 SDL_SendMouseMotion(window, 0, 0, x, y);
418 - (void)mouseDragged:(NSEvent *)theEvent
420 [self mouseMoved:theEvent];
423 - (void)rightMouseDragged:(NSEvent *)theEvent
425 [self mouseMoved:theEvent];
428 - (void)otherMouseDragged:(NSEvent *)theEvent
430 [self mouseMoved:theEvent];
433 - (void)scrollWheel:(NSEvent *)theEvent
435 Cocoa_HandleMouseWheel(_data->window, theEvent);
438 - (void)touchesBeganWithEvent:(NSEvent *) theEvent
440 [self handleTouches:COCOA_TOUCH_DOWN withEvent:theEvent];
443 - (void)touchesMovedWithEvent:(NSEvent *) theEvent
445 [self handleTouches:COCOA_TOUCH_MOVE withEvent:theEvent];
448 - (void)touchesEndedWithEvent:(NSEvent *) theEvent
450 [self handleTouches:COCOA_TOUCH_UP withEvent:theEvent];
453 - (void)touchesCancelledWithEvent:(NSEvent *) theEvent
455 [self handleTouches:COCOA_TOUCH_CANCELLED withEvent:theEvent];
458 - (void)handleTouches:(cocoaTouchType)type withEvent:(NSEvent *)event
461 NSEnumerator *enumerator;
465 case COCOA_TOUCH_DOWN:
466 touches = [event touchesMatchingPhase:NSTouchPhaseBegan inView:nil];
469 case COCOA_TOUCH_CANCELLED:
470 touches = [event touchesMatchingPhase:NSTouchPhaseEnded inView:nil];
472 case COCOA_TOUCH_MOVE:
473 touches = [event touchesMatchingPhase:NSTouchPhaseMoved inView:nil];
477 enumerator = [touches objectEnumerator];
478 touch = (NSTouch*)[enumerator nextObject];
480 const SDL_TouchID touchId = (SDL_TouchID)(intptr_t)[touch device];
481 if (!SDL_GetTouch(touchId)) {
482 if (SDL_AddTouch(touchId, "") < 0) {
487 const SDL_FingerID fingerId = (SDL_FingerID)(intptr_t)[touch identity];
488 float x = [touch normalizedPosition].x;
489 float y = [touch normalizedPosition].y;
490 /* Make the origin the upper left instead of the lower left */
494 case COCOA_TOUCH_DOWN:
495 SDL_SendTouch(touchId, fingerId, SDL_TRUE, x, y, 1.0f);
498 case COCOA_TOUCH_CANCELLED:
499 SDL_SendTouch(touchId, fingerId, SDL_FALSE, x, y, 1.0f);
501 case COCOA_TOUCH_MOVE:
502 SDL_SendTouchMotion(touchId, fingerId, x, y, 1.0f);
506 touch = (NSTouch*)[enumerator nextObject];
512 @interface SDLWindow : NSWindow
513 /* These are needed for borderless/fullscreen windows */
514 - (BOOL)canBecomeKeyWindow;
515 - (BOOL)canBecomeMainWindow;
518 @implementation SDLWindow
519 - (BOOL)canBecomeKeyWindow
524 - (BOOL)canBecomeMainWindow
530 @interface SDLView : NSView
532 /* The default implementation doesn't pass rightMouseDown to responder chain */
533 - (void)rightMouseDown:(NSEvent *)theEvent;
536 @implementation SDLView
537 - (void)rightMouseDown:(NSEvent *)theEvent
539 [[self nextResponder] rightMouseDown:theEvent];
542 - (void)resetCursorRects
544 [super resetCursorRects];
545 SDL_Mouse *mouse = SDL_GetMouse();
547 if (mouse->cursor_shown && mouse->cur_cursor && !mouse->relative_mode) {
548 [self addCursorRect:[self bounds]
549 cursor:mouse->cur_cursor->driverdata];
551 [self addCursorRect:[self bounds]
552 cursor:[NSCursor invisibleCursor]];
558 GetWindowStyle(SDL_Window * window)
562 if (window->flags & SDL_WINDOW_FULLSCREEN) {
563 style = NSBorderlessWindowMask;
565 if (window->flags & SDL_WINDOW_BORDERLESS) {
566 style = NSBorderlessWindowMask;
568 style = (NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask);
570 if (window->flags & SDL_WINDOW_RESIZABLE) {
571 style |= NSResizableWindowMask;
578 SetupWindowData(_THIS, SDL_Window * window, NSWindow *nswindow, SDL_bool created)
580 NSAutoreleasePool *pool;
581 SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
582 SDL_WindowData *data;
584 /* Allocate the window data */
585 data = (SDL_WindowData *) SDL_calloc(1, sizeof(*data));
587 return SDL_OutOfMemory();
589 data->window = window;
590 data->nswindow = nswindow;
591 data->created = created;
592 data->videodata = videodata;
594 pool = [[NSAutoreleasePool alloc] init];
596 /* Create an event listener for the window */
597 data->listener = [[Cocoa_WindowListener alloc] init];
599 /* Fill in the SDL window with the window data */
601 NSRect rect = [nswindow contentRectForFrameRect:[nswindow frame]];
602 ConvertNSRect(&rect);
603 window->x = (int)rect.origin.x;
604 window->y = (int)rect.origin.y;
605 window->w = (int)rect.size.width;
606 window->h = (int)rect.size.height;
609 /* Set up the listener after we create the view */
610 [data->listener listen:data];
612 if ([nswindow isVisible]) {
613 window->flags |= SDL_WINDOW_SHOWN;
615 window->flags &= ~SDL_WINDOW_SHOWN;
619 unsigned int style = [nswindow styleMask];
621 if (style == NSBorderlessWindowMask) {
622 window->flags |= SDL_WINDOW_BORDERLESS;
624 window->flags &= ~SDL_WINDOW_BORDERLESS;
626 if (style & NSResizableWindowMask) {
627 window->flags |= SDL_WINDOW_RESIZABLE;
629 window->flags &= ~SDL_WINDOW_RESIZABLE;
633 /* isZoomed always returns true if the window is not resizable */
634 if ((window->flags & SDL_WINDOW_RESIZABLE) && [nswindow isZoomed]) {
635 window->flags |= SDL_WINDOW_MAXIMIZED;
637 window->flags &= ~SDL_WINDOW_MAXIMIZED;
640 if ([nswindow isMiniaturized]) {
641 window->flags |= SDL_WINDOW_MINIMIZED;
643 window->flags &= ~SDL_WINDOW_MINIMIZED;
646 if ([nswindow isKeyWindow]) {
647 window->flags |= SDL_WINDOW_INPUT_FOCUS;
648 SDL_SetKeyboardFocus(data->window);
651 /* Prevents the window's "window device" from being destroyed when it is
652 * hidden. See http://www.mikeash.com/pyblog/nsopenglcontext-and-one-shot.html
654 [nswindow setOneShot:NO];
658 window->driverdata = data;
663 Cocoa_CreateWindow(_THIS, SDL_Window * window)
665 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
667 SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
672 Cocoa_GetDisplayBounds(_this, display, &bounds);
673 rect.origin.x = window->x;
674 rect.origin.y = window->y;
675 rect.size.width = window->w;
676 rect.size.height = window->h;
677 ConvertNSRect(&rect);
679 style = GetWindowStyle(window);
681 /* Figure out which screen to place this window */
682 NSArray *screens = [NSScreen screens];
683 NSScreen *screen = nil;
685 int i, count = [screens count];
686 for (i = 0; i < count; ++i) {
687 candidate = [screens objectAtIndex:i];
688 NSRect screenRect = [candidate frame];
689 if (rect.origin.x >= screenRect.origin.x &&
690 rect.origin.x < screenRect.origin.x + screenRect.size.width &&
691 rect.origin.y >= screenRect.origin.y &&
692 rect.origin.y < screenRect.origin.y + screenRect.size.height) {
694 rect.origin.x -= screenRect.origin.x;
695 rect.origin.y -= screenRect.origin.y;
698 nswindow = [[SDLWindow alloc] initWithContentRect:rect styleMask:style backing:NSBackingStoreBuffered defer:NO screen:screen];
699 [nswindow setBackgroundColor:[NSColor blackColor]];
701 /* Create a default view for this window */
702 rect = [nswindow contentRectForFrameRect:[nswindow frame]];
703 NSView *contentView = [[SDLView alloc] initWithFrame:rect];
704 [nswindow setContentView: contentView];
705 [contentView release];
709 if (SetupWindowData(_this, window, nswindow, SDL_TRUE) < 0) {
717 Cocoa_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
719 NSAutoreleasePool *pool;
720 NSWindow *nswindow = (NSWindow *) data;
723 pool = [[NSAutoreleasePool alloc] init];
725 /* Query the title from the existing window */
726 title = [nswindow title];
728 window->title = SDL_strdup([title UTF8String]);
733 return SetupWindowData(_this, window, nswindow, SDL_FALSE);
737 Cocoa_SetWindowTitle(_THIS, SDL_Window * window)
739 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
740 NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
744 string = [[NSString alloc] initWithUTF8String:window->title];
746 string = [[NSString alloc] init];
748 [nswindow setTitle:string];
755 Cocoa_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
757 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
758 NSImage *nsimage = Cocoa_CreateImage(icon);
761 [NSApp setApplicationIconImage:nsimage];
768 Cocoa_SetWindowPosition(_THIS, SDL_Window * window)
770 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
771 NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
775 rect.origin.x = window->x;
776 rect.origin.y = window->y;
777 rect.size.width = window->w;
778 rect.size.height = window->h;
779 ConvertNSRect(&rect);
781 moveHack = s_moveHack;
783 [nswindow setFrameOrigin:rect.origin];
784 s_moveHack = moveHack;
786 if (window == _this->current_glwin) {
787 [((NSOpenGLContext *) _this->current_glctx) update];
794 Cocoa_SetWindowSize(_THIS, SDL_Window * window)
796 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
797 SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
798 NSWindow *nswindow = windata->nswindow;
801 size.width = window->w;
802 size.height = window->h;
803 [nswindow setContentSize:size];
805 if (window == _this->current_glwin) {
806 [((NSOpenGLContext *) _this->current_glctx) update];
813 Cocoa_SetWindowMinimumSize(_THIS, SDL_Window * window)
815 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
816 SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
819 minSize.width = window->min_w;
820 minSize.height = window->min_h;
822 [windata->nswindow setContentMinSize:minSize];
828 Cocoa_SetWindowMaximumSize(_THIS, SDL_Window * window)
830 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
831 SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
834 maxSize.width = window->max_w;
835 maxSize.height = window->max_h;
837 [windata->nswindow setContentMaxSize:maxSize];
843 Cocoa_ShowWindow(_THIS, SDL_Window * window)
845 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
846 SDL_WindowData *windowData = ((SDL_WindowData *) window->driverdata);
847 NSWindow *nswindow = windowData->nswindow;
849 if (![nswindow isMiniaturized]) {
850 [windowData->listener pauseVisibleObservation];
851 [nswindow makeKeyAndOrderFront:nil];
852 [windowData->listener resumeVisibleObservation];
858 Cocoa_HideWindow(_THIS, SDL_Window * window)
860 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
861 NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
863 [nswindow orderOut:nil];
868 Cocoa_RaiseWindow(_THIS, SDL_Window * window)
870 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
871 SDL_WindowData *windowData = ((SDL_WindowData *) window->driverdata);
872 NSWindow *nswindow = windowData->nswindow;
874 // makeKeyAndOrderFront: has the side-effect of deminiaturizing and showing
875 // a minimized or hidden window, so check for that before showing it.
876 [windowData->listener pauseVisibleObservation];
877 if (![nswindow isMiniaturized] && [nswindow isVisible]) {
878 [nswindow makeKeyAndOrderFront:nil];
880 [windowData->listener resumeVisibleObservation];
886 Cocoa_MaximizeWindow(_THIS, SDL_Window * window)
888 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
889 NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
893 if (window == _this->current_glwin) {
894 [((NSOpenGLContext *) _this->current_glctx) update];
901 Cocoa_MinimizeWindow(_THIS, SDL_Window * window)
903 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
904 NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
906 [nswindow miniaturize:nil];
911 Cocoa_RestoreWindow(_THIS, SDL_Window * window)
913 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
914 NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
916 if ([nswindow isMiniaturized]) {
917 [nswindow deminiaturize:nil];
918 } else if ((window->flags & SDL_WINDOW_RESIZABLE) && [nswindow isZoomed]) {
925 Cocoa_RebuildWindow(SDL_WindowData * data, NSWindow * nswindow, unsigned style)
927 if (!data->created) {
928 /* Don't mess with other people's windows... */
932 [data->listener close];
933 data->nswindow = [[SDLWindow alloc] initWithContentRect:[[nswindow contentView] frame] styleMask:style backing:NSBackingStoreBuffered defer:NO screen:[nswindow screen]];
934 [data->nswindow setContentView:[nswindow contentView]];
935 /* See comment in SetupWindowData. */
936 [data->nswindow setOneShot:NO];
937 [data->listener listen:data];
941 return data->nswindow;
945 Cocoa_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
947 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
948 NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
949 if ([nswindow respondsToSelector:@selector(setStyleMask:)]) {
950 [nswindow setStyleMask:GetWindowStyle(window)];
952 Cocoa_SetWindowTitle(_this, window); /* this got blanked out. */
959 Cocoa_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
961 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
962 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
963 NSWindow *nswindow = data->nswindow;
966 /* The view responder chain gets messed with during setStyleMask */
967 if ([[nswindow contentView] nextResponder] == data->listener) {
968 [[nswindow contentView] setNextResponder:nil];
974 Cocoa_GetDisplayBounds(_this, display, &bounds);
975 rect.origin.x = bounds.x;
976 rect.origin.y = bounds.y;
977 rect.size.width = bounds.w;
978 rect.size.height = bounds.h;
979 ConvertNSRect(&rect);
981 /* Hack to fix origin on Mac OS X 10.4 */
982 NSRect screenRect = [[nswindow screen] frame];
983 if (screenRect.size.height >= 1.0f) {
984 rect.origin.y += (screenRect.size.height - rect.size.height);
987 if ([nswindow respondsToSelector: @selector(setStyleMask:)]) {
988 [nswindow performSelector: @selector(setStyleMask:) withObject: (id)NSBorderlessWindowMask];
990 nswindow = Cocoa_RebuildWindow(data, nswindow, NSBorderlessWindowMask);
993 rect.origin.x = window->windowed.x;
994 rect.origin.y = window->windowed.y;
995 rect.size.width = window->windowed.w;
996 rect.size.height = window->windowed.h;
997 ConvertNSRect(&rect);
999 if ([nswindow respondsToSelector: @selector(setStyleMask:)]) {
1000 [nswindow performSelector: @selector(setStyleMask:) withObject: (id)(uintptr_t)GetWindowStyle(window)];
1002 nswindow = Cocoa_RebuildWindow(data, nswindow, GetWindowStyle(window));
1006 /* The view responder chain gets messed with during setStyleMask */
1007 if ([[nswindow contentView] nextResponder] != data->listener) {
1008 [[nswindow contentView] setNextResponder:data->listener];
1012 [nswindow setFrameOrigin:rect.origin];
1013 [nswindow setContentSize:rect.size];
1014 s_moveHack = SDL_GetTicks();
1016 /* When the window style changes the title is cleared */
1018 Cocoa_SetWindowTitle(_this, window);
1021 if (SDL_ShouldAllowTopmost() && fullscreen) {
1022 /* OpenGL is rendering to the window, so make it visible! */
1023 [nswindow setLevel:CGShieldingWindowLevel()];
1025 [nswindow setLevel:kCGNormalWindowLevel];
1028 [data->listener pauseVisibleObservation];
1029 [nswindow makeKeyAndOrderFront:nil];
1030 [data->listener resumeVisibleObservation];
1032 if (window == _this->current_glwin) {
1033 [((NSOpenGLContext *) _this->current_glctx) update];
1040 Cocoa_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
1042 SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
1043 CGDirectDisplayID display_id = ((SDL_DisplayData *)display->driverdata)->display;
1044 const uint32_t tableSize = 256;
1045 CGGammaValue redTable[tableSize];
1046 CGGammaValue greenTable[tableSize];
1047 CGGammaValue blueTable[tableSize];
1049 float inv65535 = 1.0f / 65535.0f;
1051 /* Extract gamma values into separate tables, convert to floats between 0.0 and 1.0 */
1052 for (i = 0; i < 256; i++) {
1053 redTable[i] = ramp[0*256+i] * inv65535;
1054 greenTable[i] = ramp[1*256+i] * inv65535;
1055 blueTable[i] = ramp[2*256+i] * inv65535;
1058 if (CGSetDisplayTransferByTable(display_id, tableSize,
1059 redTable, greenTable, blueTable) != CGDisplayNoErr) {
1060 return SDL_SetError("CGSetDisplayTransferByTable()");
1066 Cocoa_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp)
1068 SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
1069 CGDirectDisplayID display_id = ((SDL_DisplayData *)display->driverdata)->display;
1070 const uint32_t tableSize = 256;
1071 CGGammaValue redTable[tableSize];
1072 CGGammaValue greenTable[tableSize];
1073 CGGammaValue blueTable[tableSize];
1074 uint32_t i, tableCopied;
1076 if (CGGetDisplayTransferByTable(display_id, tableSize,
1077 redTable, greenTable, blueTable, &tableCopied) != CGDisplayNoErr) {
1078 return SDL_SetError("CGGetDisplayTransferByTable()");
1081 for (i = 0; i < tableCopied; i++) {
1082 ramp[0*256+i] = (Uint16)(redTable[i] * 65535.0f);
1083 ramp[1*256+i] = (Uint16)(greenTable[i] * 65535.0f);
1084 ramp[2*256+i] = (Uint16)(blueTable[i] * 65535.0f);
1090 Cocoa_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
1092 /* Move the cursor to the nearest point in the window */
1097 SDL_GetMouseState(&x, &y);
1098 cgpoint.x = window->x + x;
1099 cgpoint.y = window->y + y;
1100 CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
1103 if ( window->flags & SDL_WINDOW_FULLSCREEN ) {
1104 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1106 if (SDL_ShouldAllowTopmost() && (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
1107 /* OpenGL is rendering to the window, so make it visible! */
1108 [data->nswindow setLevel:CGShieldingWindowLevel()];
1110 [data->nswindow setLevel:kCGNormalWindowLevel];
1116 Cocoa_DestroyWindow(_THIS, SDL_Window * window)
1118 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1119 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1122 [data->listener close];
1123 [data->listener release];
1124 if (data->created) {
1125 [data->nswindow close];
1133 Cocoa_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
1135 NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
1137 if (info->version.major <= SDL_MAJOR_VERSION) {
1138 info->subsystem = SDL_SYSWM_COCOA;
1139 info->info.cocoa.window = nswindow;
1142 SDL_SetError("Application not compiled with SDL %d.%d\n",
1143 SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
1148 #endif /* SDL_VIDEO_DRIVER_COCOA */
1150 /* vi: set ts=4 sw=4 expandtab: */