Mac: Don't -[NSOpenGLContext update] on (potentially) the wrong thread.
If the user is using their context from a non-main thread, we could be
calling -[NSOpenGLContext update] on our thread, while they were
accessing it on their thread.
With this change, we schedule updates when the event comes in on the
main thread, and act on them when the user calls SDL_GL_MakeCurrent or
SDL_GL_SwapWindow.
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"
35 #include "SDL_cocoaopengl.h"
38 static Uint32 s_moveHack;
40 static __inline__ void ConvertNSRect(NSRect *r)
42 r->origin.y = CGDisplayPixelsHigh(kCGDirectMainDisplay) - r->origin.y - r->size.height;
45 @implementation Cocoa_WindowListener
47 - (void)listen:(SDL_WindowData *)data
49 NSNotificationCenter *center;
50 NSWindow *window = data->nswindow;
51 NSView *view = [window contentView];
54 observingVisible = YES;
55 wasVisible = [window isVisible];
57 center = [NSNotificationCenter defaultCenter];
59 if ([window delegate] != nil) {
60 [center addObserver:self selector:@selector(windowDidExpose:) name:NSWindowDidExposeNotification object:window];
61 [center addObserver:self selector:@selector(windowDidMove:) name:NSWindowDidMoveNotification object:window];
62 [center addObserver:self selector:@selector(windowDidResize:) name:NSWindowDidResizeNotification object:window];
63 [center addObserver:self selector:@selector(windowDidMiniaturize:) name:NSWindowDidMiniaturizeNotification object:window];
64 [center addObserver:self selector:@selector(windowDidDeminiaturize:) name:NSWindowDidDeminiaturizeNotification object:window];
65 [center addObserver:self selector:@selector(windowDidBecomeKey:) name:NSWindowDidBecomeKeyNotification object:window];
66 [center addObserver:self selector:@selector(windowDidResignKey:) name:NSWindowDidResignKeyNotification object:window];
68 [window setDelegate:self];
71 /* Haven't found a delegate / notification that triggers when the window is
72 * ordered out (is not visible any more). You can be ordered out without
73 * minimizing, so DidMiniaturize doesn't work. (e.g. -[NSWindow orderOut:])
75 [window addObserver:self
77 options:NSKeyValueObservingOptionNew
80 [window setNextResponder:self];
81 [window setAcceptsMouseMovedEvents:YES];
83 [view setNextResponder:self];
85 if ([view respondsToSelector:@selector(setAcceptsTouchEvents:)]) {
86 [view setAcceptsTouchEvents:YES];
90 - (void)observeValueForKeyPath:(NSString *)keyPath
92 change:(NSDictionary *)change
93 context:(void *)context
95 if (!observingVisible) {
99 if (object == _data->nswindow && [keyPath isEqualToString:@"visible"]) {
100 int newVisibility = [[change objectForKey:@"new"] intValue];
102 SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
104 SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
109 -(void) pauseVisibleObservation
111 observingVisible = NO;
112 wasVisible = [_data->nswindow isVisible];
115 -(void) resumeVisibleObservation
117 BOOL isVisible = [_data->nswindow isVisible];
118 observingVisible = YES;
119 if (wasVisible != isVisible) {
121 SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
123 SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
126 wasVisible = isVisible;
132 NSNotificationCenter *center;
133 NSWindow *window = _data->nswindow;
134 NSView *view = [window contentView];
135 NSArray *windows = nil;
137 center = [NSNotificationCenter defaultCenter];
139 if ([window delegate] != self) {
140 [center removeObserver:self name:NSWindowDidExposeNotification object:window];
141 [center removeObserver:self name:NSWindowDidMoveNotification object:window];
142 [center removeObserver:self name:NSWindowDidResizeNotification object:window];
143 [center removeObserver:self name:NSWindowDidMiniaturizeNotification object:window];
144 [center removeObserver:self name:NSWindowDidDeminiaturizeNotification object:window];
145 [center removeObserver:self name:NSWindowDidBecomeKeyNotification object:window];
146 [center removeObserver:self name:NSWindowDidResignKeyNotification object:window];
148 [window setDelegate:nil];
151 [window removeObserver:self
152 forKeyPath:@"visible"];
154 if ([window nextResponder] == self) {
155 [window setNextResponder:nil];
157 if ([view nextResponder] == self) {
158 [view setNextResponder:nil];
161 /* Make the next window in the z-order Key. If we weren't the foreground
162 when closed, this is a no-op.
163 !!! FIXME: Note that this is a hack, and there are corner cases where
164 !!! FIXME: this fails (such as the About box). The typical nib+RunLoop
165 !!! FIXME: handles this for Cocoa apps, but we bypass all that in SDL.
166 !!! FIXME: We should remove this code when we find a better way to
167 !!! FIXME: have the system do this for us. See discussion in
168 !!! FIXME: http://bugzilla.libsdl.org/show_bug.cgi?id=1825
170 windows = [NSApp orderedWindows];
171 if ([windows count] > 0) {
172 NSWindow *win = (NSWindow *) [windows objectAtIndex:0];
173 [win makeKeyAndOrderFront:self];
177 - (BOOL)windowShouldClose:(id)sender
179 SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_CLOSE, 0, 0);
183 - (void)windowDidExpose:(NSNotification *)aNotification
185 SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_EXPOSED, 0, 0);
188 - (void)windowDidMove:(NSNotification *)aNotification
191 SDL_Window *window = _data->window;
192 NSWindow *nswindow = _data->nswindow;
193 NSRect rect = [nswindow contentRectForFrameRect:[nswindow frame]];
194 ConvertNSRect(&rect);
197 SDL_bool blockMove = ((SDL_GetTicks() - s_moveHack) < 500);
202 /* Cocoa is adjusting the window in response to a mode change */
203 rect.origin.x = window->x;
204 rect.origin.y = window->y;
205 ConvertNSRect(&rect);
206 [nswindow setFrameOrigin:rect.origin];
211 x = (int)rect.origin.x;
212 y = (int)rect.origin.y;
214 [_data->nscontext scheduleUpdate];
216 SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, x, y);
219 - (void)windowDidResize:(NSNotification *)aNotification
222 NSRect rect = [_data->nswindow contentRectForFrameRect:[_data->nswindow frame]];
223 ConvertNSRect(&rect);
224 x = (int)rect.origin.x;
225 y = (int)rect.origin.y;
226 w = (int)rect.size.width;
227 h = (int)rect.size.height;
228 if (SDL_IsShapedWindow(_data->window))
229 Cocoa_ResizeWindowShape(_data->window);
231 [_data->nscontext scheduleUpdate];
233 /* The window can move during a resize event, such as when maximizing
234 or resizing from a corner */
235 SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_MOVED, x, y);
236 SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_RESIZED, w, h);
238 const BOOL zoomed = [_data->nswindow isZoomed];
240 SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_RESTORED, 0, 0);
242 SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_MAXIMIZED, 0, 0);
246 - (void)windowDidMiniaturize:(NSNotification *)aNotification
248 SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
251 - (void)windowDidDeminiaturize:(NSNotification *)aNotification
253 SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_RESTORED, 0, 0);
256 - (void)windowDidBecomeKey:(NSNotification *)aNotification
258 SDL_Window *window = _data->window;
259 SDL_Mouse *mouse = SDL_GetMouse();
261 /* We're going to get keyboard events, since we're key. */
262 SDL_SetKeyboardFocus(window);
264 /* If we just gained focus we need the updated mouse position */
265 if (!mouse->relative_mode) {
269 point = [_data->nswindow mouseLocationOutsideOfEventStream];
271 y = (int)(window->h - point.y);
273 if (x >= 0 && x < window->w && y >= 0 && y < window->h) {
274 SDL_SendMouseMotion(window, 0, 0, x, y);
278 /* Check to see if someone updated the clipboard */
279 Cocoa_CheckClipboardUpdate(_data->videodata);
282 - (void)windowDidResignKey:(NSNotification *)aNotification
284 /* Some other window will get mouse events, since we're not key. */
285 if (SDL_GetMouseFocus() == _data->window) {
286 SDL_SetMouseFocus(NULL);
289 /* Some other window will get keyboard events, since we're not key. */
290 if (SDL_GetKeyboardFocus() == _data->window) {
291 SDL_SetKeyboardFocus(NULL);
295 /* We'll respond to key events by doing nothing so we don't beep.
296 * We could handle key messages here, but we lose some in the NSApp dispatch,
297 * where they get converted to action messages, etc.
299 - (void)flagsChanged:(NSEvent *)theEvent
301 /*Cocoa_HandleKeyEvent(SDL_GetVideoDevice(), theEvent);*/
303 - (void)keyDown:(NSEvent *)theEvent
305 /*Cocoa_HandleKeyEvent(SDL_GetVideoDevice(), theEvent);*/
307 - (void)keyUp:(NSEvent *)theEvent
309 /*Cocoa_HandleKeyEvent(SDL_GetVideoDevice(), theEvent);*/
312 /* We'll respond to selectors by doing nothing so we don't beep.
313 * The escape key gets converted to a "cancel" selector, etc.
315 - (void)doCommandBySelector:(SEL)aSelector
317 /*NSLog(@"doCommandBySelector: %@\n", NSStringFromSelector(aSelector));*/
320 - (void)mouseDown:(NSEvent *)theEvent
324 switch ([theEvent buttonNumber]) {
326 button = SDL_BUTTON_LEFT;
329 button = SDL_BUTTON_RIGHT;
332 button = SDL_BUTTON_MIDDLE;
335 button = [theEvent buttonNumber] + 1;
338 SDL_SendMouseButton(_data->window, 0, SDL_PRESSED, button);
341 - (void)rightMouseDown:(NSEvent *)theEvent
343 [self mouseDown:theEvent];
346 - (void)otherMouseDown:(NSEvent *)theEvent
348 [self mouseDown:theEvent];
351 - (void)mouseUp:(NSEvent *)theEvent
355 switch ([theEvent buttonNumber]) {
357 button = SDL_BUTTON_LEFT;
360 button = SDL_BUTTON_RIGHT;
363 button = SDL_BUTTON_MIDDLE;
366 button = [theEvent buttonNumber] + 1;
369 SDL_SendMouseButton(_data->window, 0, SDL_RELEASED, button);
372 - (void)rightMouseUp:(NSEvent *)theEvent
374 [self mouseUp:theEvent];
377 - (void)otherMouseUp:(NSEvent *)theEvent
379 [self mouseUp:theEvent];
382 - (void)mouseMoved:(NSEvent *)theEvent
384 SDL_Mouse *mouse = SDL_GetMouse();
385 SDL_Window *window = _data->window;
389 if (mouse->relative_mode) {
393 point = [theEvent locationInWindow];
395 y = (int)(window->h - point.y);
397 if (x < 0 || x >= window->w || y < 0 || y >= window->h) {
398 if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
403 } else if (x >= window->w) {
408 } else if (y >= window->h) {
412 #if !SDL_MAC_NO_SANDBOX
413 /* When SDL_MAC_NO_SANDBOX is set, this is handled by
414 * SDL_cocoamousetap.m.
417 cgpoint.x = window->x + x;
418 cgpoint.y = window->y + y;
420 /* According to the docs, this was deprecated in 10.6, but it's still
421 * around. The substitute requires a CGEventSource, but I'm not entirely
422 * sure how we'd procure the right one for this event.
424 CGSetLocalEventsSuppressionInterval(0.0);
425 CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
426 CGSetLocalEventsSuppressionInterval(0.25);
430 SDL_SendMouseMotion(window, 0, 0, x, y);
433 - (void)mouseDragged:(NSEvent *)theEvent
435 [self mouseMoved:theEvent];
438 - (void)rightMouseDragged:(NSEvent *)theEvent
440 [self mouseMoved:theEvent];
443 - (void)otherMouseDragged:(NSEvent *)theEvent
445 [self mouseMoved:theEvent];
448 - (void)scrollWheel:(NSEvent *)theEvent
450 Cocoa_HandleMouseWheel(_data->window, theEvent);
453 - (void)touchesBeganWithEvent:(NSEvent *) theEvent
455 [self handleTouches:COCOA_TOUCH_DOWN withEvent:theEvent];
458 - (void)touchesMovedWithEvent:(NSEvent *) theEvent
460 [self handleTouches:COCOA_TOUCH_MOVE withEvent:theEvent];
463 - (void)touchesEndedWithEvent:(NSEvent *) theEvent
465 [self handleTouches:COCOA_TOUCH_UP withEvent:theEvent];
468 - (void)touchesCancelledWithEvent:(NSEvent *) theEvent
470 [self handleTouches:COCOA_TOUCH_CANCELLED withEvent:theEvent];
473 - (void)handleTouches:(cocoaTouchType)type withEvent:(NSEvent *)event
476 NSEnumerator *enumerator;
480 case COCOA_TOUCH_DOWN:
481 touches = [event touchesMatchingPhase:NSTouchPhaseBegan inView:nil];
484 case COCOA_TOUCH_CANCELLED:
485 touches = [event touchesMatchingPhase:NSTouchPhaseEnded inView:nil];
487 case COCOA_TOUCH_MOVE:
488 touches = [event touchesMatchingPhase:NSTouchPhaseMoved inView:nil];
492 enumerator = [touches objectEnumerator];
493 touch = (NSTouch*)[enumerator nextObject];
495 const SDL_TouchID touchId = (SDL_TouchID)(intptr_t)[touch device];
496 if (!SDL_GetTouch(touchId)) {
497 if (SDL_AddTouch(touchId, "") < 0) {
502 const SDL_FingerID fingerId = (SDL_FingerID)(intptr_t)[touch identity];
503 float x = [touch normalizedPosition].x;
504 float y = [touch normalizedPosition].y;
505 /* Make the origin the upper left instead of the lower left */
509 case COCOA_TOUCH_DOWN:
510 SDL_SendTouch(touchId, fingerId, SDL_TRUE, x, y, 1.0f);
513 case COCOA_TOUCH_CANCELLED:
514 SDL_SendTouch(touchId, fingerId, SDL_FALSE, x, y, 1.0f);
516 case COCOA_TOUCH_MOVE:
517 SDL_SendTouchMotion(touchId, fingerId, x, y, 1.0f);
521 touch = (NSTouch*)[enumerator nextObject];
527 @interface SDLWindow : NSWindow
528 /* These are needed for borderless/fullscreen windows */
529 - (BOOL)canBecomeKeyWindow;
530 - (BOOL)canBecomeMainWindow;
533 @implementation SDLWindow
534 - (BOOL)canBecomeKeyWindow
539 - (BOOL)canBecomeMainWindow
545 @interface SDLView : NSView
547 /* The default implementation doesn't pass rightMouseDown to responder chain */
548 - (void)rightMouseDown:(NSEvent *)theEvent;
551 @implementation SDLView
552 - (void)rightMouseDown:(NSEvent *)theEvent
554 [[self nextResponder] rightMouseDown:theEvent];
557 - (void)resetCursorRects
559 [super resetCursorRects];
560 SDL_Mouse *mouse = SDL_GetMouse();
562 if (mouse->cursor_shown && mouse->cur_cursor && !mouse->relative_mode) {
563 [self addCursorRect:[self bounds]
564 cursor:mouse->cur_cursor->driverdata];
566 [self addCursorRect:[self bounds]
567 cursor:[NSCursor invisibleCursor]];
573 GetWindowStyle(SDL_Window * window)
577 if (window->flags & SDL_WINDOW_FULLSCREEN) {
578 style = NSBorderlessWindowMask;
580 if (window->flags & SDL_WINDOW_BORDERLESS) {
581 style = NSBorderlessWindowMask;
583 style = (NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask);
585 if (window->flags & SDL_WINDOW_RESIZABLE) {
586 style |= NSResizableWindowMask;
593 SetupWindowData(_THIS, SDL_Window * window, NSWindow *nswindow, SDL_bool created)
595 NSAutoreleasePool *pool;
596 SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
597 SDL_WindowData *data;
599 /* Allocate the window data */
600 data = (SDL_WindowData *) SDL_calloc(1, sizeof(*data));
602 return SDL_OutOfMemory();
604 data->window = window;
605 data->nswindow = nswindow;
606 data->created = created;
607 data->videodata = videodata;
609 pool = [[NSAutoreleasePool alloc] init];
611 /* Create an event listener for the window */
612 data->listener = [[Cocoa_WindowListener alloc] init];
614 /* Fill in the SDL window with the window data */
616 NSRect rect = [nswindow contentRectForFrameRect:[nswindow frame]];
617 ConvertNSRect(&rect);
618 window->x = (int)rect.origin.x;
619 window->y = (int)rect.origin.y;
620 window->w = (int)rect.size.width;
621 window->h = (int)rect.size.height;
624 /* Set up the listener after we create the view */
625 [data->listener listen:data];
627 if ([nswindow isVisible]) {
628 window->flags |= SDL_WINDOW_SHOWN;
630 window->flags &= ~SDL_WINDOW_SHOWN;
634 unsigned int style = [nswindow styleMask];
636 if (style == NSBorderlessWindowMask) {
637 window->flags |= SDL_WINDOW_BORDERLESS;
639 window->flags &= ~SDL_WINDOW_BORDERLESS;
641 if (style & NSResizableWindowMask) {
642 window->flags |= SDL_WINDOW_RESIZABLE;
644 window->flags &= ~SDL_WINDOW_RESIZABLE;
648 /* isZoomed always returns true if the window is not resizable */
649 if ((window->flags & SDL_WINDOW_RESIZABLE) && [nswindow isZoomed]) {
650 window->flags |= SDL_WINDOW_MAXIMIZED;
652 window->flags &= ~SDL_WINDOW_MAXIMIZED;
655 if ([nswindow isMiniaturized]) {
656 window->flags |= SDL_WINDOW_MINIMIZED;
658 window->flags &= ~SDL_WINDOW_MINIMIZED;
661 if ([nswindow isKeyWindow]) {
662 window->flags |= SDL_WINDOW_INPUT_FOCUS;
663 SDL_SetKeyboardFocus(data->window);
666 /* Prevents the window's "window device" from being destroyed when it is
667 * hidden. See http://www.mikeash.com/pyblog/nsopenglcontext-and-one-shot.html
669 [nswindow setOneShot:NO];
673 window->driverdata = data;
678 Cocoa_CreateWindow(_THIS, SDL_Window * window)
680 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
682 SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
687 Cocoa_GetDisplayBounds(_this, display, &bounds);
688 rect.origin.x = window->x;
689 rect.origin.y = window->y;
690 rect.size.width = window->w;
691 rect.size.height = window->h;
692 ConvertNSRect(&rect);
694 style = GetWindowStyle(window);
696 /* Figure out which screen to place this window */
697 NSArray *screens = [NSScreen screens];
698 NSScreen *screen = nil;
700 int i, count = [screens count];
701 for (i = 0; i < count; ++i) {
702 candidate = [screens objectAtIndex:i];
703 NSRect screenRect = [candidate frame];
704 if (rect.origin.x >= screenRect.origin.x &&
705 rect.origin.x < screenRect.origin.x + screenRect.size.width &&
706 rect.origin.y >= screenRect.origin.y &&
707 rect.origin.y < screenRect.origin.y + screenRect.size.height) {
709 rect.origin.x -= screenRect.origin.x;
710 rect.origin.y -= screenRect.origin.y;
713 nswindow = [[SDLWindow alloc] initWithContentRect:rect styleMask:style backing:NSBackingStoreBuffered defer:NO screen:screen];
714 [nswindow setBackgroundColor:[NSColor blackColor]];
716 /* Create a default view for this window */
717 rect = [nswindow contentRectForFrameRect:[nswindow frame]];
718 NSView *contentView = [[SDLView alloc] initWithFrame:rect];
719 [nswindow setContentView: contentView];
720 [contentView release];
724 if (SetupWindowData(_this, window, nswindow, SDL_TRUE) < 0) {
732 Cocoa_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
734 NSAutoreleasePool *pool;
735 NSWindow *nswindow = (NSWindow *) data;
738 pool = [[NSAutoreleasePool alloc] init];
740 /* Query the title from the existing window */
741 title = [nswindow title];
743 window->title = SDL_strdup([title UTF8String]);
748 return SetupWindowData(_this, window, nswindow, SDL_FALSE);
752 Cocoa_SetWindowTitle(_THIS, SDL_Window * window)
754 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
755 NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
759 string = [[NSString alloc] initWithUTF8String:window->title];
761 string = [[NSString alloc] init];
763 [nswindow setTitle:string];
770 Cocoa_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
772 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
773 NSImage *nsimage = Cocoa_CreateImage(icon);
776 [NSApp setApplicationIconImage:nsimage];
783 Cocoa_SetWindowPosition(_THIS, SDL_Window * window)
785 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
786 SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
787 NSWindow *nswindow = windata->nswindow;
791 rect.origin.x = window->x;
792 rect.origin.y = window->y;
793 rect.size.width = window->w;
794 rect.size.height = window->h;
795 ConvertNSRect(&rect);
797 moveHack = s_moveHack;
799 [nswindow setFrameOrigin:rect.origin];
800 s_moveHack = moveHack;
802 [windata->nscontext scheduleUpdate];
808 Cocoa_SetWindowSize(_THIS, SDL_Window * window)
810 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
811 SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
812 NSWindow *nswindow = windata->nswindow;
815 size.width = window->w;
816 size.height = window->h;
817 [nswindow setContentSize:size];
819 [windata->nscontext scheduleUpdate];
825 Cocoa_SetWindowMinimumSize(_THIS, SDL_Window * window)
827 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
828 SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
831 minSize.width = window->min_w;
832 minSize.height = window->min_h;
834 [windata->nswindow setContentMinSize:minSize];
840 Cocoa_SetWindowMaximumSize(_THIS, SDL_Window * window)
842 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
843 SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
846 maxSize.width = window->max_w;
847 maxSize.height = window->max_h;
849 [windata->nswindow setContentMaxSize:maxSize];
855 Cocoa_ShowWindow(_THIS, SDL_Window * window)
857 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
858 SDL_WindowData *windowData = ((SDL_WindowData *) window->driverdata);
859 NSWindow *nswindow = windowData->nswindow;
861 if (![nswindow isMiniaturized]) {
862 [windowData->listener pauseVisibleObservation];
863 [nswindow makeKeyAndOrderFront:nil];
864 [windowData->listener resumeVisibleObservation];
870 Cocoa_HideWindow(_THIS, SDL_Window * window)
872 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
873 NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
875 [nswindow orderOut:nil];
880 Cocoa_RaiseWindow(_THIS, SDL_Window * window)
882 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
883 SDL_WindowData *windowData = ((SDL_WindowData *) window->driverdata);
884 NSWindow *nswindow = windowData->nswindow;
886 // makeKeyAndOrderFront: has the side-effect of deminiaturizing and showing
887 // a minimized or hidden window, so check for that before showing it.
888 [windowData->listener pauseVisibleObservation];
889 if (![nswindow isMiniaturized] && [nswindow isVisible]) {
890 [nswindow makeKeyAndOrderFront:nil];
892 [windowData->listener resumeVisibleObservation];
898 Cocoa_MaximizeWindow(_THIS, SDL_Window * window)
900 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
901 SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
902 NSWindow *nswindow = windata->nswindow;
906 [windata->nscontext scheduleUpdate];
912 Cocoa_MinimizeWindow(_THIS, SDL_Window * window)
914 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
915 NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
917 [nswindow miniaturize:nil];
922 Cocoa_RestoreWindow(_THIS, SDL_Window * window)
924 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
925 NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
927 if ([nswindow isMiniaturized]) {
928 [nswindow deminiaturize:nil];
929 } else if ((window->flags & SDL_WINDOW_RESIZABLE) && [nswindow isZoomed]) {
936 Cocoa_RebuildWindow(SDL_WindowData * data, NSWindow * nswindow, unsigned style)
938 if (!data->created) {
939 /* Don't mess with other people's windows... */
943 [data->listener close];
944 data->nswindow = [[SDLWindow alloc] initWithContentRect:[[nswindow contentView] frame] styleMask:style backing:NSBackingStoreBuffered defer:NO screen:[nswindow screen]];
945 [data->nswindow setContentView:[nswindow contentView]];
946 /* See comment in SetupWindowData. */
947 [data->nswindow setOneShot:NO];
948 [data->listener listen:data];
952 return data->nswindow;
956 Cocoa_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
958 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
959 NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
960 if ([nswindow respondsToSelector:@selector(setStyleMask:)]) {
961 [nswindow setStyleMask:GetWindowStyle(window)];
963 Cocoa_SetWindowTitle(_this, window); /* this got blanked out. */
970 Cocoa_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
972 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
973 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
974 NSWindow *nswindow = data->nswindow;
977 /* The view responder chain gets messed with during setStyleMask */
978 if ([[nswindow contentView] nextResponder] == data->listener) {
979 [[nswindow contentView] setNextResponder:nil];
985 Cocoa_GetDisplayBounds(_this, display, &bounds);
986 rect.origin.x = bounds.x;
987 rect.origin.y = bounds.y;
988 rect.size.width = bounds.w;
989 rect.size.height = bounds.h;
990 ConvertNSRect(&rect);
992 /* Hack to fix origin on Mac OS X 10.4 */
993 NSRect screenRect = [[nswindow screen] frame];
994 if (screenRect.size.height >= 1.0f) {
995 rect.origin.y += (screenRect.size.height - rect.size.height);
998 if ([nswindow respondsToSelector: @selector(setStyleMask:)]) {
999 [nswindow performSelector: @selector(setStyleMask:) withObject: (id)NSBorderlessWindowMask];
1001 nswindow = Cocoa_RebuildWindow(data, nswindow, NSBorderlessWindowMask);
1004 rect.origin.x = window->windowed.x;
1005 rect.origin.y = window->windowed.y;
1006 rect.size.width = window->windowed.w;
1007 rect.size.height = window->windowed.h;
1008 ConvertNSRect(&rect);
1010 if ([nswindow respondsToSelector: @selector(setStyleMask:)]) {
1011 [nswindow performSelector: @selector(setStyleMask:) withObject: (id)(uintptr_t)GetWindowStyle(window)];
1013 nswindow = Cocoa_RebuildWindow(data, nswindow, GetWindowStyle(window));
1017 /* The view responder chain gets messed with during setStyleMask */
1018 if ([[nswindow contentView] nextResponder] != data->listener) {
1019 [[nswindow contentView] setNextResponder:data->listener];
1023 [nswindow setFrameOrigin:rect.origin];
1024 [nswindow setContentSize:rect.size];
1025 s_moveHack = SDL_GetTicks();
1027 /* When the window style changes the title is cleared */
1029 Cocoa_SetWindowTitle(_this, window);
1032 if (SDL_ShouldAllowTopmost() && fullscreen) {
1033 /* OpenGL is rendering to the window, so make it visible! */
1034 [nswindow setLevel:CGShieldingWindowLevel()];
1036 [nswindow setLevel:kCGNormalWindowLevel];
1039 [data->listener pauseVisibleObservation];
1040 [nswindow makeKeyAndOrderFront:nil];
1041 [data->listener resumeVisibleObservation];
1043 [data->nscontext scheduleUpdate];
1049 Cocoa_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
1051 SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
1052 CGDirectDisplayID display_id = ((SDL_DisplayData *)display->driverdata)->display;
1053 const uint32_t tableSize = 256;
1054 CGGammaValue redTable[tableSize];
1055 CGGammaValue greenTable[tableSize];
1056 CGGammaValue blueTable[tableSize];
1058 float inv65535 = 1.0f / 65535.0f;
1060 /* Extract gamma values into separate tables, convert to floats between 0.0 and 1.0 */
1061 for (i = 0; i < 256; i++) {
1062 redTable[i] = ramp[0*256+i] * inv65535;
1063 greenTable[i] = ramp[1*256+i] * inv65535;
1064 blueTable[i] = ramp[2*256+i] * inv65535;
1067 if (CGSetDisplayTransferByTable(display_id, tableSize,
1068 redTable, greenTable, blueTable) != CGDisplayNoErr) {
1069 return SDL_SetError("CGSetDisplayTransferByTable()");
1075 Cocoa_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp)
1077 SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
1078 CGDirectDisplayID display_id = ((SDL_DisplayData *)display->driverdata)->display;
1079 const uint32_t tableSize = 256;
1080 CGGammaValue redTable[tableSize];
1081 CGGammaValue greenTable[tableSize];
1082 CGGammaValue blueTable[tableSize];
1083 uint32_t i, tableCopied;
1085 if (CGGetDisplayTransferByTable(display_id, tableSize,
1086 redTable, greenTable, blueTable, &tableCopied) != CGDisplayNoErr) {
1087 return SDL_SetError("CGGetDisplayTransferByTable()");
1090 for (i = 0; i < tableCopied; i++) {
1091 ramp[0*256+i] = (Uint16)(redTable[i] * 65535.0f);
1092 ramp[1*256+i] = (Uint16)(greenTable[i] * 65535.0f);
1093 ramp[2*256+i] = (Uint16)(blueTable[i] * 65535.0f);
1099 Cocoa_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
1101 /* Move the cursor to the nearest point in the window */
1106 SDL_GetMouseState(&x, &y);
1107 cgpoint.x = window->x + x;
1108 cgpoint.y = window->y + y;
1109 CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
1112 if ( window->flags & SDL_WINDOW_FULLSCREEN ) {
1113 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1115 if (SDL_ShouldAllowTopmost() && (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
1116 /* OpenGL is rendering to the window, so make it visible! */
1117 [data->nswindow setLevel:CGShieldingWindowLevel()];
1119 [data->nswindow setLevel:kCGNormalWindowLevel];
1125 Cocoa_DestroyWindow(_THIS, SDL_Window * window)
1127 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1128 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
1131 [data->listener close];
1132 [data->listener release];
1133 if (data->created) {
1134 [data->nswindow close];
1142 Cocoa_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
1144 NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
1146 if (info->version.major <= SDL_MAJOR_VERSION) {
1147 info->subsystem = SDL_SYSWM_COCOA;
1148 info->info.cocoa.window = nswindow;
1151 SDL_SetError("Application not compiled with SDL %d.%d\n",
1152 SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
1157 #endif /* SDL_VIDEO_DRIVER_COCOA */
1159 /* vi: set ts=4 sw=4 expandtab: */