summaryrefslogtreecommitdiff
path: root/apps/plugins/sdl/src/video/quartz/SDL_QuartzVideo.m
diff options
context:
space:
mode:
authorFranklin Wei <git@fwei.tk>2018-02-07 20:04:46 -0500
committerFranklin Wei <git@fwei.tk>2018-03-12 20:52:01 -0400
commit6039eb05ba6d82ef56f2868c96654c552d117bf9 (patch)
tree9db7016bcbf66cfdf7b9bc998d84c6eaff9c8378 /apps/plugins/sdl/src/video/quartz/SDL_QuartzVideo.m
parentef373c03b96b0be08babca581d9f10bccfd4931f (diff)
downloadrockbox-6039eb05ba6d82ef56f2868c96654c552d117bf9.tar.gz
rockbox-6039eb05ba6d82ef56f2868c96654c552d117bf9.zip
sdl: remove non-rockbox drivers
We never use any of these other drivers, so having them around just takes up space. Change-Id: Iced812162df1fef3fd55522b7e700acb6c3bcd41
Diffstat (limited to 'apps/plugins/sdl/src/video/quartz/SDL_QuartzVideo.m')
-rw-r--r--apps/plugins/sdl/src/video/quartz/SDL_QuartzVideo.m1689
1 files changed, 0 insertions, 1689 deletions
diff --git a/apps/plugins/sdl/src/video/quartz/SDL_QuartzVideo.m b/apps/plugins/sdl/src/video/quartz/SDL_QuartzVideo.m
deleted file mode 100644
index fa04e9d107..0000000000
--- a/apps/plugins/sdl/src/video/quartz/SDL_QuartzVideo.m
+++ /dev/null
@@ -1,1689 +0,0 @@
1/*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2012 Sam Lantinga
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19 Sam Lantinga
20 slouken@libsdl.org
21*/
22#include "SDL_config.h"
23
24#include "SDL_QuartzVideo.h"
25#include "SDL_QuartzWindow.h"
26
27/* These APIs aren't just deprecated; they're gone from the headers in the
28 10.7 SDK. If we're using a >= 10.7 SDK, but targeting < 10.7, then we
29 force these function declarations. */
30#if ((MAC_OS_X_VERSION_MIN_REQUIRED < 1070) && (MAC_OS_X_VERSION_MAX_ALLOWED >= 1070))
31CG_EXTERN void *CGDisplayBaseAddress(CGDirectDisplayID display)
32 CG_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_6,
33 __IPHONE_NA, __IPHONE_NA);
34CG_EXTERN size_t CGDisplayBytesPerRow(CGDirectDisplayID display)
35 CG_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_6,
36 __IPHONE_NA, __IPHONE_NA);
37#endif
38
39
40static inline BOOL IS_LION_OR_LATER(_THIS)
41{
42 return (system_version >= 0x1070);
43}
44
45static inline BOOL IS_SNOW_LEOPARD_OR_LATER(_THIS)
46{
47 return (system_version >= 0x1060);
48}
49
50#if (MAC_OS_X_VERSION_MAX_ALLOWED < 1060) && !defined(__LP64__) /* Fixed in Snow Leopard */
51/*
52 Add methods to get at private members of NSScreen.
53 Since there is a bug in Apple's screen switching code
54 that does not update this variable when switching
55 to fullscreen, we'll set it manually (but only for the
56 main screen).
57*/
58@interface NSScreen (NSScreenAccess)
59- (void) setFrame:(NSRect)frame;
60@end
61
62@implementation NSScreen (NSScreenAccess)
63- (void) setFrame:(NSRect)frame;
64{
65 _frame = frame;
66}
67@end
68static inline void QZ_SetFrame(_THIS, NSScreen *nsscreen, NSRect frame)
69{
70 if (!IS_SNOW_LEOPARD_OR_LATER(this)) {
71 [nsscreen setFrame:frame];
72 }
73}
74#else
75static inline void QZ_SetFrame(_THIS, NSScreen *nsscreen, NSRect frame)
76{
77}
78#endif
79
80@interface SDLTranslatorResponder : NSTextView
81{
82}
83- (void) doCommandBySelector:(SEL)myselector;
84@end
85
86@implementation SDLTranslatorResponder
87- (void) doCommandBySelector:(SEL) myselector {}
88@end
89
90/* absent in 10.3.9. */
91CG_EXTERN CGImageRef CGBitmapContextCreateImage (CGContextRef);
92
93/* Bootstrap functions */
94static int QZ_Available ();
95static SDL_VideoDevice* QZ_CreateDevice (int device_index);
96static void QZ_DeleteDevice (SDL_VideoDevice *device);
97
98/* Initialization, Query, Setup, and Redrawing functions */
99static int QZ_VideoInit (_THIS, SDL_PixelFormat *video_format);
100
101static SDL_Rect** QZ_ListModes (_THIS, SDL_PixelFormat *format,
102 Uint32 flags);
103static void QZ_UnsetVideoMode (_THIS, BOOL to_desktop, BOOL save_gl);
104
105static SDL_Surface* QZ_SetVideoMode (_THIS, SDL_Surface *current,
106 int width, int height, int bpp,
107 Uint32 flags);
108static int QZ_ToggleFullScreen (_THIS, int on);
109static int QZ_SetColors (_THIS, int first_color,
110 int num_colors, SDL_Color *colors);
111
112#if (MAC_OS_X_VERSION_MIN_REQUIRED < 1070)
113static int QZ_LockDoubleBuffer (_THIS, SDL_Surface *surface);
114static void QZ_UnlockDoubleBuffer (_THIS, SDL_Surface *surface);
115static int QZ_ThreadFlip (_THIS);
116static int QZ_FlipDoubleBuffer (_THIS, SDL_Surface *surface);
117static void QZ_DoubleBufferUpdate (_THIS, int num_rects, SDL_Rect *rects);
118static void QZ_DirectUpdate (_THIS, int num_rects, SDL_Rect *rects);
119#endif
120
121static void QZ_UpdateRects (_THIS, int num_rects, SDL_Rect *rects);
122static void QZ_VideoQuit (_THIS);
123
124static int QZ_LockHWSurface(_THIS, SDL_Surface *surface);
125static void QZ_UnlockHWSurface(_THIS, SDL_Surface *surface);
126static int QZ_AllocHWSurface(_THIS, SDL_Surface *surface);
127static void QZ_FreeHWSurface (_THIS, SDL_Surface *surface);
128
129/* Bootstrap binding, enables entry point into the driver */
130VideoBootStrap QZ_bootstrap = {
131 "Quartz", "Mac OS X CoreGraphics", QZ_Available, QZ_CreateDevice
132};
133
134/* Disable compiler warnings we can't avoid. */
135#if (defined(__GNUC__) && (__GNUC__ >= 4))
136# if (MAC_OS_X_VERSION_MAX_ALLOWED <= 1070)
137# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
138# endif
139#endif
140
141static void QZ_ReleaseDisplayMode(_THIS, const void *moderef)
142{
143 /* we only own these references in the 10.6+ API. */
144#if (MAC_OS_X_VERSION_MAX_ALLOWED >= 1060)
145 if (use_new_mode_apis) {
146 CGDisplayModeRelease((CGDisplayModeRef) moderef);
147 }
148#endif
149}
150
151static void QZ_ReleaseDisplayModeList(_THIS, CFArrayRef mode_list)
152{
153 /* we only own these references in the 10.6+ API. */
154#if (MAC_OS_X_VERSION_MAX_ALLOWED >= 1060)
155 if (use_new_mode_apis) {
156 CFRelease(mode_list);
157 }
158#endif
159}
160
161
162/* Bootstrap functions */
163static int QZ_Available ()
164{
165 return 1;
166}
167
168static SDL_VideoDevice* QZ_CreateDevice (int device_index)
169{
170#pragma unused (device_index)
171
172 SDL_VideoDevice *device;
173 SDL_PrivateVideoData *hidden;
174
175 device = (SDL_VideoDevice*) SDL_malloc (sizeof (*device) );
176 hidden = (SDL_PrivateVideoData*) SDL_malloc (sizeof (*hidden) );
177
178 if (device == NULL || hidden == NULL)
179 SDL_OutOfMemory ();
180
181 SDL_memset (device, 0, sizeof (*device) );
182 SDL_memset (hidden, 0, sizeof (*hidden) );
183
184 device->hidden = hidden;
185
186 device->VideoInit = QZ_VideoInit;
187 device->ListModes = QZ_ListModes;
188 device->SetVideoMode = QZ_SetVideoMode;
189 device->ToggleFullScreen = QZ_ToggleFullScreen;
190 device->UpdateMouse = QZ_UpdateMouse;
191 device->SetColors = QZ_SetColors;
192 /* device->UpdateRects = QZ_UpdateRects; this is determined by SetVideoMode() */
193 device->VideoQuit = QZ_VideoQuit;
194
195 device->LockHWSurface = QZ_LockHWSurface;
196 device->UnlockHWSurface = QZ_UnlockHWSurface;
197 device->AllocHWSurface = QZ_AllocHWSurface;
198 device->FreeHWSurface = QZ_FreeHWSurface;
199
200 device->SetGamma = QZ_SetGamma;
201 device->GetGamma = QZ_GetGamma;
202 device->SetGammaRamp = QZ_SetGammaRamp;
203 device->GetGammaRamp = QZ_GetGammaRamp;
204
205 device->GL_GetProcAddress = QZ_GL_GetProcAddress;
206 device->GL_GetAttribute = QZ_GL_GetAttribute;
207 device->GL_MakeCurrent = QZ_GL_MakeCurrent;
208 device->GL_SwapBuffers = QZ_GL_SwapBuffers;
209 device->GL_LoadLibrary = QZ_GL_LoadLibrary;
210
211 device->FreeWMCursor = QZ_FreeWMCursor;
212 device->CreateWMCursor = QZ_CreateWMCursor;
213 device->ShowWMCursor = QZ_ShowWMCursor;
214 device->WarpWMCursor = QZ_WarpWMCursor;
215 device->MoveWMCursor = QZ_MoveWMCursor;
216 device->CheckMouseMode = QZ_CheckMouseMode;
217 device->InitOSKeymap = QZ_InitOSKeymap;
218 device->PumpEvents = QZ_PumpEvents;
219
220 device->SetCaption = QZ_SetCaption;
221 device->SetIcon = QZ_SetIcon;
222 device->IconifyWindow = QZ_IconifyWindow;
223 /*device->GetWMInfo = QZ_GetWMInfo;*/
224 device->GrabInput = QZ_GrabInput;
225
226 /*
227 * This is a big hassle, needing QuickDraw and QuickTime on older
228 * systems, and god knows what on 10.6, so we immediately fail here,
229 * which causes SDL to make an RGB surface and manage the YUV overlay
230 * in software. Sorry. Use SDL 1.3 if you want YUV rendering in a pixel
231 * shader. :)
232 */
233 /*device->CreateYUVOverlay = QZ_CreateYUVOverlay;*/
234
235 device->free = QZ_DeleteDevice;
236
237 return device;
238}
239
240static void QZ_DeleteDevice (SDL_VideoDevice *device)
241{
242 _THIS = device;
243 QZ_ReleaseDisplayMode(this, save_mode);
244 QZ_ReleaseDisplayMode(this, mode);
245 SDL_free (device->hidden);
246 SDL_free (device);
247}
248
249static void QZ_GetModeInfo(_THIS, const void *_mode, Uint32 *w, Uint32 *h, Uint32 *bpp)
250{
251 *w = *h = *bpp = 0;
252 if (_mode == NULL) {
253 return;
254 }
255
256#if (MAC_OS_X_VERSION_MAX_ALLOWED >= 1060)
257 if (use_new_mode_apis) {
258 CGDisplayModeRef vidmode = (CGDisplayModeRef) _mode;
259 CFStringRef fmt = CGDisplayModeCopyPixelEncoding(vidmode);
260
261 *w = (Uint32) CGDisplayModeGetWidth(vidmode);
262 *h = (Uint32) CGDisplayModeGetHeight(vidmode);
263
264 /* we only care about the 32-bit modes... */
265 if (CFStringCompare(fmt, CFSTR(IO32BitDirectPixels),
266 kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
267 *bpp = 32;
268 }
269
270 CFRelease(fmt);
271 }
272#endif
273
274#if (MAC_OS_X_VERSION_MIN_REQUIRED < 1060)
275 if (!use_new_mode_apis) {
276 CFDictionaryRef vidmode = (CFDictionaryRef) _mode;
277 CFNumberGetValue (
278 CFDictionaryGetValue (vidmode, kCGDisplayBitsPerPixel),
279 kCFNumberSInt32Type, bpp);
280
281 CFNumberGetValue (
282 CFDictionaryGetValue (vidmode, kCGDisplayWidth),
283 kCFNumberSInt32Type, w);
284
285 CFNumberGetValue (
286 CFDictionaryGetValue (vidmode, kCGDisplayHeight),
287 kCFNumberSInt32Type, h);
288 }
289#endif
290
291 /* we only care about the 32-bit modes... */
292 if (*bpp != 32) {
293 *bpp = 0;
294 }
295}
296
297static int QZ_VideoInit (_THIS, SDL_PixelFormat *video_format)
298{
299 NSRect r = NSMakeRect(0.0, 0.0, 0.0, 0.0);
300 const char *env = NULL;
301
302 if ( Gestalt(gestaltSystemVersion, &system_version) != noErr )
303 system_version = 0;
304
305 use_new_mode_apis = NO;
306
307#if (MAC_OS_X_VERSION_MAX_ALLOWED >= 1060)
308 use_new_mode_apis = IS_SNOW_LEOPARD_OR_LATER(this);
309#endif
310
311 /* Initialize the video settings; this data persists between mode switches */
312 display_id = kCGDirectMainDisplay;
313
314#if 0 /* The mouse event code needs to take this into account... */
315 env = getenv("SDL_VIDEO_FULLSCREEN_DISPLAY");
316 if ( env ) {
317 int monitor = SDL_atoi(env);
318 CGDirectDisplayID activeDspys [3];
319 CGDisplayCount dspyCnt;
320 CGGetActiveDisplayList (3, activeDspys, &dspyCnt);
321 if ( monitor >= 0 && monitor < dspyCnt ) {
322 display_id = activeDspys[monitor];
323 }
324 }
325#endif
326
327#if (MAC_OS_X_VERSION_MAX_ALLOWED >= 1060)
328 if (use_new_mode_apis) {
329 save_mode = CGDisplayCopyDisplayMode(display_id);
330 }
331#endif
332
333#if (MAC_OS_X_VERSION_MIN_REQUIRED < 1060)
334 if (!use_new_mode_apis) {
335 save_mode = CGDisplayCurrentMode(display_id);
336 }
337#endif
338
339#if (MAC_OS_X_VERSION_MIN_REQUIRED < 1070)
340 if (!IS_LION_OR_LATER(this)) {
341 palette = CGPaletteCreateDefaultColorPalette();
342 }
343#endif
344
345 if (save_mode == NULL) {
346 SDL_SetError("Couldn't figure out current display mode.");
347 return -1;
348 }
349
350 /* Allow environment override of screensaver disable. */
351 env = SDL_getenv("SDL_VIDEO_ALLOW_SCREENSAVER");
352 if ( env ) {
353 allow_screensaver = SDL_atoi(env);
354 } else {
355#ifdef SDL_VIDEO_DISABLE_SCREENSAVER
356 allow_screensaver = 0;
357#else
358 allow_screensaver = 1;
359#endif
360 }
361
362 /* Gather some information that is useful to know about the display */
363 QZ_GetModeInfo(this, save_mode, &device_width, &device_height, &device_bpp);
364 if (device_bpp == 0) {
365 QZ_ReleaseDisplayMode(this, save_mode);
366 save_mode = NULL;
367 SDL_SetError("Unsupported display mode");
368 return -1;
369 }
370
371 /* Determine the current screen size */
372 this->info.current_w = device_width;
373 this->info.current_h = device_height;
374
375 /* Determine the default screen depth */
376 video_format->BitsPerPixel = device_bpp;
377
378 /* Set misc globals */
379 current_grab_mode = SDL_GRAB_OFF;
380 cursor_should_be_visible = YES;
381 cursor_visible = YES;
382 current_mods = 0;
383 field_edit = [[SDLTranslatorResponder alloc] initWithFrame:r];
384
385 /* register for sleep notifications so wake from sleep generates SDL_VIDEOEXPOSE */
386 QZ_RegisterForSleepNotifications (this);
387
388 /* Fill in some window manager capabilities */
389 this->info.wm_available = 1;
390
391 return 0;
392}
393
394static SDL_Rect** QZ_ListModes (_THIS, SDL_PixelFormat *format, Uint32 flags)
395{
396 CFArrayRef mode_list = NULL; /* list of available fullscreen modes */
397 CFIndex num_modes;
398 CFIndex i;
399
400 int list_size = 0;
401
402 /* Any windowed mode is acceptable */
403 if ( (flags & SDL_FULLSCREEN) == 0 )
404 return (SDL_Rect**)-1;
405
406 /* Free memory from previous call, if any */
407 if ( client_mode_list != NULL ) {
408 int i;
409
410 for (i = 0; client_mode_list[i] != NULL; i++)
411 SDL_free (client_mode_list[i]);
412
413 SDL_free (client_mode_list);
414 client_mode_list = NULL;
415 }
416
417#if (MAC_OS_X_VERSION_MAX_ALLOWED >= 1060)
418 if (use_new_mode_apis) {
419 mode_list = CGDisplayCopyAllDisplayModes(display_id, NULL);
420 }
421#endif
422
423#if (MAC_OS_X_VERSION_MIN_REQUIRED < 1060)
424 if (!use_new_mode_apis) {
425 mode_list = CGDisplayAvailableModes(display_id);
426 }
427#endif
428
429 num_modes = CFArrayGetCount (mode_list);
430
431 /* Build list of modes with the requested bpp */
432 for (i = 0; i < num_modes; i++) {
433 Uint32 width, height, bpp;
434 const void *onemode = CFArrayGetValueAtIndex(mode_list, i);
435
436 QZ_GetModeInfo(this, onemode, &width, &height, &bpp);
437
438 if (bpp && (bpp == format->BitsPerPixel)) {
439 int hasMode = SDL_FALSE;
440 int i;
441
442 /* Check if mode is already in the list */
443 for (i = 0; i < list_size; i++) {
444 if (client_mode_list[i]->w == width &&
445 client_mode_list[i]->h == height) {
446 hasMode = SDL_TRUE;
447 break;
448 }
449 }
450
451 /* Grow the list and add mode to the list */
452 if ( ! hasMode ) {
453 SDL_Rect *rect;
454
455 list_size++;
456
457 if (client_mode_list == NULL)
458 client_mode_list = (SDL_Rect**)
459 SDL_malloc (sizeof(*client_mode_list) * (list_size+1) );
460 else {
461 /* !!! FIXME: this leaks memory if SDL_realloc() fails! */
462 client_mode_list = (SDL_Rect**)
463 SDL_realloc (client_mode_list, sizeof(*client_mode_list) * (list_size+1));
464 }
465
466 rect = (SDL_Rect*) SDL_malloc (sizeof(**client_mode_list));
467
468 if (client_mode_list == NULL || rect == NULL) {
469 QZ_ReleaseDisplayModeList(this, mode_list);
470 SDL_OutOfMemory ();
471 return NULL;
472 }
473
474 rect->x = rect->y = 0;
475 rect->w = width;
476 rect->h = height;
477
478 client_mode_list[list_size-1] = rect;
479 client_mode_list[list_size] = NULL;
480 }
481 }
482 }
483
484 QZ_ReleaseDisplayModeList(this, mode_list);
485
486 /* Sort list largest to smallest (by area) */
487 {
488 int i, j;
489 for (i = 0; i < list_size; i++) {
490 for (j = 0; j < list_size-1; j++) {
491
492 int area1, area2;
493 area1 = client_mode_list[j]->w * client_mode_list[j]->h;
494 area2 = client_mode_list[j+1]->w * client_mode_list[j+1]->h;
495
496 if (area1 < area2) {
497 SDL_Rect *tmp = client_mode_list[j];
498 client_mode_list[j] = client_mode_list[j+1];
499 client_mode_list[j+1] = tmp;
500 }
501 }
502 }
503 }
504
505 return client_mode_list;
506}
507
508static SDL_bool QZ_WindowPosition(_THIS, int *x, int *y)
509{
510 const char *window = getenv("SDL_VIDEO_WINDOW_POS");
511 if ( window ) {
512 if ( sscanf(window, "%d,%d", x, y) == 2 ) {
513 return SDL_TRUE;
514 }
515 }
516 return SDL_FALSE;
517}
518
519static CGError QZ_SetDisplayMode(_THIS, const void *vidmode)
520{
521#if (MAC_OS_X_VERSION_MAX_ALLOWED >= 1060)
522 if (use_new_mode_apis) {
523 return CGDisplaySetDisplayMode(display_id, (CGDisplayModeRef) vidmode, NULL);
524 }
525#endif
526
527#if (MAC_OS_X_VERSION_MIN_REQUIRED < 1060)
528 if (!use_new_mode_apis) {
529 return CGDisplaySwitchToMode(display_id, (CFDictionaryRef) vidmode);
530 }
531#endif
532
533 return kCGErrorFailure;
534}
535
536static inline CGError QZ_RestoreDisplayMode(_THIS)
537{
538 return QZ_SetDisplayMode(this, save_mode);
539}
540
541static void QZ_UnsetVideoMode (_THIS, BOOL to_desktop, BOOL save_gl)
542{
543 /* Reset values that may change between switches */
544 this->info.blit_fill = 0;
545 this->FillHWRect = NULL;
546 this->UpdateRects = NULL;
547 this->LockHWSurface = NULL;
548 this->UnlockHWSurface = NULL;
549
550 if (cg_context) {
551 CGContextFlush (cg_context);
552 CGContextRelease (cg_context);
553 cg_context = nil;
554 }
555
556 /* Release fullscreen resources */
557 if ( mode_flags & SDL_FULLSCREEN ) {
558
559 NSRect screen_rect;
560
561 /* Release double buffer stuff */
562#if (MAC_OS_X_VERSION_MIN_REQUIRED < 1070)
563 if ( !IS_LION_OR_LATER(this) && (mode_flags & SDL_DOUBLEBUF) ) {
564 quit_thread = YES;
565 SDL_SemPost (sem1);
566 SDL_WaitThread (thread, NULL);
567 SDL_DestroySemaphore (sem1);
568 SDL_DestroySemaphore (sem2);
569 SDL_free (sw_buffers[0]);
570 }
571#endif
572
573 /* If we still have a valid window, close it. */
574 if ( qz_window ) {
575 NSCAssert([ qz_window delegate ] == nil, @"full screen window shouldn't have a delegate"); /* if that should ever change, we'd have to release it here */
576 [ qz_window close ]; /* includes release because [qz_window isReleasedWhenClosed] */
577 qz_window = nil;
578 window_view = nil;
579 }
580 /*
581 Release the OpenGL context
582 Do this first to avoid trash on the display before fade
583 */
584 if ( mode_flags & SDL_OPENGL ) {
585 if (!save_gl) {
586 QZ_TearDownOpenGL (this);
587 }
588
589 #ifdef __powerpc__ /* we only use this for pre-10.3 compatibility. */
590 CGLSetFullScreen (NULL);
591 #endif
592 }
593 if (to_desktop) {
594 /* !!! FIXME: keep an eye on this.
595 * This API is officially unavailable for 64-bit binaries.
596 * It happens to work, as of 10.7, but we're going to see if
597 * we can just simply do without it on newer OSes...
598 */
599 #if (MAC_OS_X_VERSION_MIN_REQUIRED < 1070) && !defined(__LP64__)
600 if ( !IS_LION_OR_LATER(this) ) {
601 ShowMenuBar ();
602 }
603 #endif
604
605 /* Restore original screen resolution/bpp */
606 QZ_RestoreDisplayMode (this);
607 CGReleaseAllDisplays ();
608 /*
609 Reset the main screen's rectangle
610 See comment in QZ_SetVideoFullscreen for why we do this
611 */
612 screen_rect = NSMakeRect(0,0,device_width,device_height);
613 QZ_SetFrame(this, [ NSScreen mainScreen ], screen_rect);
614 }
615 }
616 /* Release window mode resources */
617 else {
618 id delegate = [ qz_window delegate ];
619 [ qz_window close ]; /* includes release because [qz_window isReleasedWhenClosed] */
620 if (delegate != nil) [ delegate release ];
621 qz_window = nil;
622 window_view = nil;
623
624 /* Release the OpenGL context */
625 if ( mode_flags & SDL_OPENGL ) {
626 if (!save_gl) {
627 QZ_TearDownOpenGL (this);
628 }
629 }
630 }
631
632 /* Signal successful teardown */
633 video_set = SDL_FALSE;
634}
635
636static const void *QZ_BestMode(_THIS, const int bpp, const int w, const int h)
637{
638 const void *best = NULL;
639
640 if (bpp == 0) {
641 return NULL;
642 }
643
644#if (MAC_OS_X_VERSION_MAX_ALLOWED >= 1060)
645 if (use_new_mode_apis) {
646 /* apparently, we have to roll our own now. :/ */
647 CFArrayRef mode_list = CGDisplayCopyAllDisplayModes(display_id, NULL);
648 if (mode_list != NULL) {
649 const CFIndex num_modes = CFArrayGetCount(mode_list);
650 CFIndex i;
651 for (i = 0; i < num_modes; i++) {
652 const void *vidmode = CFArrayGetValueAtIndex(mode_list, i);
653 Uint32 thisw, thish, thisbpp;
654 QZ_GetModeInfo(this, vidmode, &thisw, &thish, &thisbpp);
655
656 /* We only care about exact matches, apparently. */
657 if ((thisbpp == bpp) && (thisw == w) && (thish == h)) {
658 best = vidmode;
659 break; /* got it! */
660 }
661 }
662 CGDisplayModeRetain((CGDisplayModeRef) best); /* NULL is ok */
663 CFRelease(mode_list);
664 }
665 }
666#endif
667
668#if (MAC_OS_X_VERSION_MIN_REQUIRED < 1060)
669 if (!use_new_mode_apis) {
670 boolean_t exact = 0;
671 best = CGDisplayBestModeForParameters(display_id, bpp, w, h, &exact);
672 if (!exact) {
673 best = NULL;
674 }
675 }
676#endif
677
678 return best;
679}
680
681static SDL_Surface* QZ_SetVideoFullScreen (_THIS, SDL_Surface *current, int width,
682 int height, int bpp, Uint32 flags,
683 const BOOL save_gl)
684{
685 const BOOL isLion = IS_LION_OR_LATER(this);
686 NSRect screen_rect;
687 CGError error;
688 NSRect contentRect;
689 CGDisplayFadeReservationToken fade_token = kCGDisplayFadeReservationInvalidToken;
690
691 current->flags = SDL_FULLSCREEN;
692 current->w = width;
693 current->h = height;
694
695 contentRect = NSMakeRect (0, 0, width, height);
696
697 /* Fade to black to hide resolution-switching flicker (and garbage
698 that is displayed by a destroyed OpenGL context, if applicable) */
699 if ( CGAcquireDisplayFadeReservation (5, &fade_token) == kCGErrorSuccess ) {
700 CGDisplayFade (fade_token, 0.3, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0, TRUE);
701 }
702
703 /* Destroy any previous mode */
704 if (video_set == SDL_TRUE)
705 QZ_UnsetVideoMode (this, FALSE, save_gl);
706
707 /* Sorry, QuickDraw was ripped out. */
708 if (getenv("SDL_NSWindowPointer") || getenv("SDL_NSQuickDrawViewPointer")) {
709 SDL_SetError ("Embedded QuickDraw windows are no longer supported");
710 goto ERR_NO_MATCH;
711 }
712
713 QZ_ReleaseDisplayMode(this, mode); /* NULL is okay. */
714
715 /* See if requested mode exists */
716 mode = QZ_BestMode(this, bpp, width, height);
717
718 /* Require an exact match to the requested mode */
719 if ( mode == NULL ) {
720 SDL_SetError ("Failed to find display resolution: %dx%dx%d", width, height, bpp);
721 goto ERR_NO_MATCH;
722 }
723
724 /* Put up the blanking window (a window above all other windows) */
725 if (getenv ("SDL_SINGLEDISPLAY"))
726 error = CGDisplayCapture (display_id);
727 else
728 error = CGCaptureAllDisplays ();
729
730 if ( CGDisplayNoErr != error ) {
731 SDL_SetError ("Failed capturing display");
732 goto ERR_NO_CAPTURE;
733 }
734
735 /* Do the physical switch */
736 if ( CGDisplayNoErr != QZ_SetDisplayMode(this, mode) ) {
737 SDL_SetError ("Failed switching display resolution");
738 goto ERR_NO_SWITCH;
739 }
740
741#if (MAC_OS_X_VERSION_MIN_REQUIRED < 1070)
742 if ( !isLion ) {
743 current->pixels = (Uint32*) CGDisplayBaseAddress (display_id);
744 current->pitch = CGDisplayBytesPerRow (display_id);
745
746 current->flags |= SDL_HWSURFACE;
747 current->flags |= SDL_PREALLOC;
748 /* current->hwdata = (void *) CGDisplayGetDrawingContext (display_id); */
749
750 this->UpdateRects = QZ_DirectUpdate;
751 this->LockHWSurface = QZ_LockHWSurface;
752 this->UnlockHWSurface = QZ_UnlockHWSurface;
753
754 /* Setup double-buffer emulation */
755 if ( flags & SDL_DOUBLEBUF ) {
756
757 /*
758 Setup a software backing store for reasonable results when
759 double buffering is requested (since a single-buffered hardware
760 surface looks hideous).
761
762 The actual screen blit occurs in a separate thread to allow
763 other blitting while waiting on the VBL (and hence results in higher framerates).
764 */
765 this->LockHWSurface = NULL;
766 this->UnlockHWSurface = NULL;
767 this->UpdateRects = NULL;
768
769 current->flags |= (SDL_HWSURFACE|SDL_DOUBLEBUF);
770 this->UpdateRects = QZ_DoubleBufferUpdate;
771 this->LockHWSurface = QZ_LockDoubleBuffer;
772 this->UnlockHWSurface = QZ_UnlockDoubleBuffer;
773 this->FlipHWSurface = QZ_FlipDoubleBuffer;
774
775 current->pixels = SDL_malloc (current->pitch * current->h * 2);
776 if (current->pixels == NULL) {
777 SDL_OutOfMemory ();
778 goto ERR_DOUBLEBUF;
779 }
780
781 sw_buffers[0] = current->pixels;
782 sw_buffers[1] = (Uint8*)current->pixels + current->pitch * current->h;
783
784 quit_thread = NO;
785 sem1 = SDL_CreateSemaphore (0);
786 sem2 = SDL_CreateSemaphore (1);
787 thread = SDL_CreateThread ((int (*)(void *))QZ_ThreadFlip, this);
788 }
789
790 if ( CGDisplayCanSetPalette (display_id) )
791 current->flags |= SDL_HWPALETTE;
792 }
793#endif
794
795 /* Check if we should recreate the window */
796 if (qz_window == nil) {
797 /* Manually create a window, avoids having a nib file resource */
798 qz_window = [ [ SDL_QuartzWindow alloc ]
799 initWithContentRect:contentRect
800 styleMask:(isLion ? NSBorderlessWindowMask : 0)
801 backing:NSBackingStoreBuffered
802 defer:NO ];
803
804 if (qz_window != nil) {
805 [ qz_window setAcceptsMouseMovedEvents:YES ];
806 [ qz_window setViewsNeedDisplay:NO ];
807 if (isLion) {
808 [ qz_window setContentView: [ [ [ SDL_QuartzView alloc ] init ] autorelease ] ];
809 }
810 }
811 }
812 /* We already have a window, just change its size */
813 else {
814 [ qz_window setContentSize:contentRect.size ];
815 current->flags |= (SDL_NOFRAME|SDL_RESIZABLE) & mode_flags;
816 [ window_view setFrameSize:contentRect.size ];
817 }
818
819 /* Setup OpenGL for a fullscreen context */
820 if (flags & SDL_OPENGL) {
821
822 if ( ! save_gl ) {
823 if ( ! QZ_SetupOpenGL (this, bpp, flags) ) {
824 goto ERR_NO_GL;
825 }
826 }
827
828 /* Initialize the NSView and add it to our window. The presence of a valid window and
829 view allow the cursor to be changed whilst in fullscreen.*/
830 window_view = [ [ NSView alloc ] initWithFrame:contentRect ];
831
832 if ( isLion ) {
833 [ window_view setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable ];
834 }
835
836 [ [ qz_window contentView ] addSubview:window_view ];
837
838 /* Apparently Lion checks some version flag set by the linker
839 and changes API behavior. Annoying. */
840 if ( isLion ) {
841 [ qz_window setLevel:CGShieldingWindowLevel() ];
842 [ gl_context setView: window_view ];
843 //[ gl_context setFullScreen ];
844 [ gl_context update ];
845 }
846
847#if (MAC_OS_X_VERSION_MIN_REQUIRED < 1070)
848 if ( !isLion ) {
849 CGLError err;
850 CGLContextObj ctx;
851
852 [ qz_window setLevel:NSNormalWindowLevel ];
853 ctx = QZ_GetCGLContextObj (gl_context);
854 err = CGLSetFullScreen (ctx);
855
856 if (err) {
857 SDL_SetError ("Error setting OpenGL fullscreen: %s", CGLErrorString(err));
858 goto ERR_NO_GL;
859 }
860 }
861#endif
862
863 [ window_view release ];
864 [ gl_context makeCurrentContext];
865
866 glClear (GL_COLOR_BUFFER_BIT);
867
868 [ gl_context flushBuffer ];
869
870 current->flags |= SDL_OPENGL;
871 } else if (isLion) { /* For 2D, we build a CGBitmapContext */
872 CGColorSpaceRef cgColorspace;
873
874 /* Only recreate the view if it doesn't already exist */
875 if (window_view == nil) {
876 window_view = [ [ NSView alloc ] initWithFrame:contentRect ];
877 [ window_view setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable ];
878 [ [ qz_window contentView ] addSubview:window_view ];
879 [ window_view release ];
880 }
881
882 cgColorspace = CGColorSpaceCreateDeviceRGB();
883 current->pitch = 4 * current->w;
884 current->pixels = SDL_malloc (current->h * current->pitch);
885
886 cg_context = CGBitmapContextCreate (current->pixels, current->w, current->h,
887 8, current->pitch, cgColorspace,
888 kCGImageAlphaNoneSkipFirst);
889 CGColorSpaceRelease (cgColorspace);
890
891 current->flags |= SDL_SWSURFACE;
892 current->flags |= SDL_ASYNCBLIT;
893 current->hwdata = (void *) cg_context;
894
895 /* Force this window to draw above _everything_. */
896 [ qz_window setLevel:CGShieldingWindowLevel() ];
897
898 this->UpdateRects = QZ_UpdateRects;
899 this->LockHWSurface = QZ_LockHWSurface;
900 this->UnlockHWSurface = QZ_UnlockHWSurface;
901 }
902
903 if (isLion) {
904 [ qz_window setHasShadow:NO];
905 [ qz_window setOpaque:YES];
906 [ qz_window makeKeyAndOrderFront:nil ];
907 }
908
909 /* !!! FIXME: keep an eye on this.
910 * This API is officially unavailable for 64-bit binaries.
911 * It happens to work, as of 10.7, but we're going to see if
912 * we can just simply do without it on newer OSes...
913 */
914 #if (MAC_OS_X_VERSION_MIN_REQUIRED < 1070) && !defined(__LP64__)
915 if ( !isLion ) {
916 /* If we don't hide menu bar, it will get events and interrupt the program */
917 HideMenuBar ();
918 }
919 #endif
920
921 /* Fade in again (asynchronously) */
922 if ( fade_token != kCGDisplayFadeReservationInvalidToken ) {
923 CGDisplayFade (fade_token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE);
924 CGReleaseDisplayFadeReservation(fade_token);
925 }
926
927 /*
928 There is a bug in Cocoa where NSScreen doesn't synchronize
929 with CGDirectDisplay, so the main screen's frame is wrong.
930 As a result, coordinate translation produces incorrect results.
931 We can hack around this bug by setting the screen rect
932 ourselves. This hack should be removed if/when the bug is fixed.
933 */
934 screen_rect = NSMakeRect(0,0,width,height);
935 QZ_SetFrame(this, [ NSScreen mainScreen ], screen_rect);
936
937 /* Save the flags to ensure correct tear-down */
938 mode_flags = current->flags;
939
940 /* Set app state, hide cursor if necessary, ... */
941 QZ_DoActivate(this);
942
943 return current;
944
945 /* Since the blanking window covers *all* windows (even force quit) correct recovery is crucial */
946ERR_NO_GL: goto ERR_DOUBLEBUF; /* this goto is to stop a compiler warning on newer SDKs. */
947ERR_DOUBLEBUF: QZ_RestoreDisplayMode(this);
948ERR_NO_SWITCH: CGReleaseAllDisplays ();
949ERR_NO_CAPTURE:
950ERR_NO_MATCH: if ( fade_token != kCGDisplayFadeReservationInvalidToken ) {
951 CGDisplayFade (fade_token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE);
952 CGReleaseDisplayFadeReservation (fade_token);
953 }
954 return NULL;
955}
956
957static SDL_Surface* QZ_SetVideoWindowed (_THIS, SDL_Surface *current, int width,
958 int height, int *bpp, Uint32 flags,
959 const BOOL save_gl)
960{
961 unsigned int style;
962 NSRect contentRect;
963 int center_window = 1;
964 int origin_x, origin_y;
965 CGDisplayFadeReservationToken fade_token = kCGDisplayFadeReservationInvalidToken;
966
967 current->flags = 0;
968 current->w = width;
969 current->h = height;
970
971 contentRect = NSMakeRect (0, 0, width, height);
972
973 /*
974 Check if we should completely destroy the previous mode
975 - If it is fullscreen
976 - If it has different noframe or resizable attribute
977 - If it is OpenGL (since gl attributes could be different)
978 - If new mode is OpenGL, but previous mode wasn't
979 */
980 if (video_set == SDL_TRUE) {
981 if (mode_flags & SDL_FULLSCREEN) {
982 /* Fade to black to hide resolution-switching flicker (and garbage
983 that is displayed by a destroyed OpenGL context, if applicable) */
984 if (CGAcquireDisplayFadeReservation (5, &fade_token) == kCGErrorSuccess) {
985 CGDisplayFade (fade_token, 0.3, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0, TRUE);
986 }
987 QZ_UnsetVideoMode (this, TRUE, save_gl);
988 }
989 else if ( ((mode_flags ^ flags) & (SDL_NOFRAME|SDL_RESIZABLE)) ||
990 (mode_flags & SDL_OPENGL) ||
991 (flags & SDL_OPENGL) ) {
992 QZ_UnsetVideoMode (this, TRUE, save_gl);
993 }
994 }
995
996 /* Sorry, QuickDraw was ripped out. */
997 if (getenv("SDL_NSWindowPointer") || getenv("SDL_NSQuickDrawViewPointer")) {
998 SDL_SetError ("Embedded QuickDraw windows are no longer supported");
999 if (fade_token != kCGDisplayFadeReservationInvalidToken) {
1000 CGDisplayFade (fade_token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE);
1001 CGReleaseDisplayFadeReservation (fade_token);
1002 }
1003 return NULL;
1004 }
1005
1006 /* Check if we should recreate the window */
1007 if (qz_window == nil) {
1008
1009 /* Set the window style based on input flags */
1010 if ( flags & SDL_NOFRAME ) {
1011 style = NSBorderlessWindowMask;
1012 current->flags |= SDL_NOFRAME;
1013 } else {
1014 style = NSTitledWindowMask;
1015 style |= (NSMiniaturizableWindowMask | NSClosableWindowMask);
1016 if ( flags & SDL_RESIZABLE ) {
1017 style |= NSResizableWindowMask;
1018 current->flags |= SDL_RESIZABLE;
1019 }
1020 }
1021
1022 /* Manually create a window, avoids having a nib file resource */
1023 qz_window = [ [ SDL_QuartzWindow alloc ]
1024 initWithContentRect:contentRect
1025 styleMask:style
1026 backing:NSBackingStoreBuffered
1027 defer:NO ];
1028
1029 if (qz_window == nil) {
1030 SDL_SetError ("Could not create the Cocoa window");
1031 if (fade_token != kCGDisplayFadeReservationInvalidToken) {
1032 CGDisplayFade (fade_token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE);
1033 CGReleaseDisplayFadeReservation (fade_token);
1034 }
1035 return NULL;
1036 }
1037
1038 /*[ qz_window setReleasedWhenClosed:YES ];*/ /* no need to set this as it's the default for NSWindows */
1039 QZ_SetCaption(this, this->wm_title, this->wm_icon);
1040 [ qz_window setAcceptsMouseMovedEvents:YES ];
1041 [ qz_window setViewsNeedDisplay:NO ];
1042
1043 if ( QZ_WindowPosition(this, &origin_x, &origin_y) ) {
1044 /* have to flip the Y value (NSPoint is lower left corner origin) */
1045 [ qz_window setFrameTopLeftPoint:NSMakePoint((float) origin_x, (float) (this->info.current_h - origin_y))];
1046 center_window = 0;
1047 } else if ( center_window ) {
1048 [ qz_window center ];
1049 }
1050
1051 [ qz_window setDelegate:
1052 [ [ SDL_QuartzWindowDelegate alloc ] init ] ];
1053 [ qz_window setContentView: [ [ [ SDL_QuartzView alloc ] init ] autorelease ] ];
1054 }
1055 /* We already have a window, just change its size */
1056 else {
1057 [ qz_window setContentSize:contentRect.size ];
1058 current->flags |= (SDL_NOFRAME|SDL_RESIZABLE) & mode_flags;
1059 [ window_view setFrameSize:contentRect.size ];
1060 }
1061
1062 /* For OpenGL, we bind the context to a subview */
1063 if ( flags & SDL_OPENGL ) {
1064
1065 if ( ! save_gl ) {
1066 if ( ! QZ_SetupOpenGL (this, *bpp, flags) ) {
1067 if (fade_token != kCGDisplayFadeReservationInvalidToken) {
1068 CGDisplayFade (fade_token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE);
1069 CGReleaseDisplayFadeReservation (fade_token);
1070 }
1071 return NULL;
1072 }
1073 }
1074
1075 window_view = [ [ NSView alloc ] initWithFrame:contentRect ];
1076 [ window_view setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable ];
1077 [ [ qz_window contentView ] addSubview:window_view ];
1078 [ gl_context setView: window_view ];
1079 [ window_view release ];
1080 [ gl_context makeCurrentContext];
1081 [ qz_window makeKeyAndOrderFront:nil ];
1082 current->flags |= SDL_OPENGL;
1083 }
1084 /* For 2D, we build a CGBitmapContext */
1085 else {
1086 CGColorSpaceRef cgColorspace;
1087
1088 /* Only recreate the view if it doesn't already exist */
1089 if (window_view == nil) {
1090
1091 window_view = [ [ NSView alloc ] initWithFrame:contentRect ];
1092 [ window_view setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable ];
1093 [ [ qz_window contentView ] addSubview:window_view ];
1094 [ window_view release ];
1095 [ qz_window makeKeyAndOrderFront:nil ];
1096 }
1097
1098 cgColorspace = CGColorSpaceCreateDeviceRGB();
1099 current->pitch = 4 * current->w;
1100 current->pixels = SDL_malloc (current->h * current->pitch);
1101
1102 cg_context = CGBitmapContextCreate (current->pixels, current->w, current->h,
1103 8, current->pitch, cgColorspace,
1104 kCGImageAlphaNoneSkipFirst);
1105 CGColorSpaceRelease (cgColorspace);
1106
1107 current->flags |= SDL_SWSURFACE;
1108 current->flags |= SDL_ASYNCBLIT;
1109 current->hwdata = (void *) cg_context;
1110
1111 this->UpdateRects = QZ_UpdateRects;
1112 this->LockHWSurface = QZ_LockHWSurface;
1113 this->UnlockHWSurface = QZ_UnlockHWSurface;
1114 }
1115
1116 /* Save flags to ensure correct teardown */
1117 mode_flags = current->flags;
1118
1119 /* Fade in again (asynchronously) if we came from a fullscreen mode and faded to black */
1120 if (fade_token != kCGDisplayFadeReservationInvalidToken) {
1121 CGDisplayFade (fade_token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE);
1122 CGReleaseDisplayFadeReservation (fade_token);
1123 }
1124
1125 return current;
1126}
1127
1128
1129static SDL_Surface* QZ_SetVideoModeInternal (_THIS, SDL_Surface *current,
1130 int width, int height, int bpp,
1131 Uint32 flags, BOOL save_gl)
1132{
1133 const BOOL isLion = IS_LION_OR_LATER(this);
1134
1135 current->flags = 0;
1136 current->pixels = NULL;
1137
1138 /* Setup full screen video */
1139 if ( flags & SDL_FULLSCREEN ) {
1140 if ( isLion ) {
1141 bpp = 32;
1142 }
1143 current = QZ_SetVideoFullScreen (this, current, width, height, bpp, flags, save_gl );
1144 if (current == NULL)
1145 return NULL;
1146 }
1147 /* Setup windowed video */
1148 else {
1149 /* Force bpp to 32 */
1150 bpp = 32;
1151 current = QZ_SetVideoWindowed (this, current, width, height, &bpp, flags, save_gl );
1152 if (current == NULL)
1153 return NULL;
1154 }
1155
1156 if (qz_window != nil) {
1157 nsgfx_context = [NSGraphicsContext graphicsContextWithWindow:qz_window];
1158 [NSGraphicsContext setCurrentContext:nsgfx_context];
1159 }
1160
1161 /* Setup the new pixel format */
1162 {
1163 int amask = 0,
1164 rmask = 0,
1165 gmask = 0,
1166 bmask = 0;
1167
1168 switch (bpp) {
1169 case 16: /* (1)-5-5-5 RGB */
1170 amask = 0;
1171 rmask = 0x7C00;
1172 gmask = 0x03E0;
1173 bmask = 0x001F;
1174 break;
1175 case 24:
1176 SDL_SetError ("24bpp is not available");
1177 return NULL;
1178 case 32: /* (8)-8-8-8 ARGB */
1179 amask = 0x00000000;
1180 if ( (!isLion) && (flags & SDL_FULLSCREEN) ) {
1181 rmask = 0x00FF0000;
1182 gmask = 0x0000FF00;
1183 bmask = 0x000000FF;
1184 } else {
1185#if SDL_BYTEORDER == SDL_LIL_ENDIAN
1186 rmask = 0x0000FF00;
1187 gmask = 0x00FF0000;
1188 bmask = 0xFF000000;
1189#else
1190 rmask = 0x00FF0000;
1191 gmask = 0x0000FF00;
1192 bmask = 0x000000FF;
1193#endif
1194 break;
1195 }
1196 }
1197
1198 if ( ! SDL_ReallocFormat (current, bpp,
1199 rmask, gmask, bmask, amask ) ) {
1200 SDL_SetError ("Couldn't reallocate pixel format");
1201 return NULL;
1202 }
1203 }
1204
1205 /* Signal successful completion (used internally) */
1206 video_set = SDL_TRUE;
1207
1208 return current;
1209}
1210
1211static SDL_Surface* QZ_SetVideoMode(_THIS, SDL_Surface *current,
1212 int width, int height, int bpp,
1213 Uint32 flags)
1214{
1215 /* Don't throw away the GL context if we can just resize the current one. */
1216#if 0 /* !!! FIXME: half-finished side project. Reenable this if you ever debug the corner cases. */
1217 const BOOL save_gl = ( (video_set == SDL_TRUE) && ((flags & SDL_OPENGL) == (current->flags & SDL_OPENGL)) && (bpp == current->format->BitsPerPixel) );
1218#else
1219 const BOOL save_gl = NO;
1220#endif
1221
1222 NSOpenGLContext *glctx = gl_context;
1223 SDL_Surface* retval = NULL;
1224
1225 if (save_gl) {
1226 [glctx retain]; /* just so we don't lose this when killing old views, etc */
1227 }
1228
1229 retval = QZ_SetVideoModeInternal (this, current, width, height, bpp, flags, save_gl);
1230
1231 if (save_gl) {
1232 [glctx release]; /* something else should own this now, or we legitimately release it. */
1233 }
1234
1235 return retval;
1236}
1237
1238
1239static int QZ_ToggleFullScreen (_THIS, int on)
1240{
1241 return 0;
1242}
1243
1244static int QZ_SetColors (_THIS, int first_color, int num_colors,
1245 SDL_Color *colors)
1246{
1247#if (MAC_OS_X_VERSION_MIN_REQUIRED < 1070)
1248 /* we shouldn't have an 8-bit mode on Lion! */
1249 if (!IS_LION_OR_LATER(this)) {
1250 CGTableCount index;
1251 CGDeviceColor color;
1252
1253 for (index = first_color; index < first_color+num_colors; index++) {
1254
1255 /* Clamp colors between 0.0 and 1.0 */
1256 color.red = colors->r / 255.0;
1257 color.blue = colors->b / 255.0;
1258 color.green = colors->g / 255.0;
1259
1260 colors++;
1261
1262 CGPaletteSetColorAtIndex (palette, color, index);
1263 }
1264
1265 return ( CGDisplayNoErr == CGDisplaySetPalette (display_id, palette) );
1266 }
1267#endif
1268
1269 return 0;
1270}
1271
1272#if (MAC_OS_X_VERSION_MIN_REQUIRED < 1070)
1273static int QZ_LockDoubleBuffer (_THIS, SDL_Surface *surface)
1274{
1275 return 1;
1276}
1277
1278static void QZ_UnlockDoubleBuffer (_THIS, SDL_Surface *surface)
1279{
1280}
1281
1282/* The VBL delay is based on code by Ian R Ollmann's RezLib <iano@cco.caltech.edu> */
1283static AbsoluteTime QZ_SecondsToAbsolute ( double seconds )
1284{
1285 union
1286 {
1287 UInt64 i;
1288 Nanoseconds ns;
1289 } temp;
1290
1291 temp.i = seconds * 1000000000.0;
1292
1293 return NanosecondsToAbsolute ( temp.ns );
1294}
1295
1296static int QZ_ThreadFlip (_THIS)
1297{
1298 Uint8 *src, *dst;
1299 int skip, len, h;
1300
1301 /*
1302 Give this thread the highest scheduling priority possible,
1303 in the hopes that it will immediately run after the VBL delay
1304 */
1305 {
1306 pthread_t current_thread;
1307 int policy;
1308 struct sched_param param;
1309
1310 current_thread = pthread_self ();
1311 pthread_getschedparam (current_thread, &policy, &param);
1312 policy = SCHED_RR;
1313 param.sched_priority = sched_get_priority_max (policy);
1314 pthread_setschedparam (current_thread, policy, &param);
1315 }
1316
1317 while (1) {
1318
1319 SDL_SemWait (sem1);
1320 if (quit_thread)
1321 return 0;
1322
1323 /*
1324 * We have to add SDL_VideoSurface->offset here, since we might be a
1325 * smaller surface in the center of the framebuffer (you asked for
1326 * a fullscreen resolution smaller than the hardware could supply
1327 * so SDL is centering it in a bigger resolution)...
1328 */
1329 dst = ((Uint8 *)((size_t)CGDisplayBaseAddress (display_id))) + SDL_VideoSurface->offset;
1330 src = current_buffer + SDL_VideoSurface->offset;
1331 len = SDL_VideoSurface->w * SDL_VideoSurface->format->BytesPerPixel;
1332 h = SDL_VideoSurface->h;
1333 skip = SDL_VideoSurface->pitch;
1334
1335 /* Wait for the VBL to occur (estimated since we don't have a hardware interrupt) */
1336 {
1337
1338 /* The VBL delay is based on Ian Ollmann's RezLib <iano@cco.caltech.edu> */
1339 double refreshRate;
1340 double linesPerSecond;
1341 double target;
1342 double position;
1343 double adjustment;
1344 AbsoluteTime nextTime;
1345 CFNumberRef refreshRateCFNumber;
1346
1347 refreshRateCFNumber = CFDictionaryGetValue (mode, kCGDisplayRefreshRate);
1348 if ( NULL == refreshRateCFNumber ) {
1349 SDL_SetError ("Mode has no refresh rate");
1350 goto ERROR;
1351 }
1352
1353 if ( 0 == CFNumberGetValue (refreshRateCFNumber, kCFNumberDoubleType, &refreshRate) ) {
1354 SDL_SetError ("Error getting refresh rate");
1355 goto ERROR;
1356 }
1357
1358 if ( 0 == refreshRate ) {
1359
1360 SDL_SetError ("Display has no refresh rate, using 60hz");
1361
1362 /* ok, for LCD's we'll emulate a 60hz refresh, which may or may not look right */
1363 refreshRate = 60.0;
1364 }
1365
1366 linesPerSecond = refreshRate * h;
1367 target = h;
1368
1369 /* Figure out the first delay so we start off about right */
1370 position = CGDisplayBeamPosition (display_id);
1371 if (position > target)
1372 position = 0;
1373
1374 adjustment = (target - position) / linesPerSecond;
1375
1376 nextTime = AddAbsoluteToAbsolute (UpTime (), QZ_SecondsToAbsolute (adjustment));
1377
1378 MPDelayUntil (&nextTime);
1379 }
1380
1381
1382 /* On error, skip VBL delay */
1383 ERROR:
1384
1385 /* TODO: use CGContextDrawImage here too! Create two CGContextRefs the same way we
1386 create two buffers, replace current_buffer with current_context and set it
1387 appropriately in QZ_FlipDoubleBuffer. */
1388 while ( h-- ) {
1389
1390 SDL_memcpy (dst, src, len);
1391 src += skip;
1392 dst += skip;
1393 }
1394
1395 /* signal flip completion */
1396 SDL_SemPost (sem2);
1397 }
1398
1399 return 0;
1400}
1401
1402static int QZ_FlipDoubleBuffer (_THIS, SDL_Surface *surface)
1403{
1404 /* wait for previous flip to complete */
1405 SDL_SemWait (sem2);
1406
1407 current_buffer = surface->pixels;
1408
1409 if (surface->pixels == sw_buffers[0])
1410 surface->pixels = sw_buffers[1];
1411 else
1412 surface->pixels = sw_buffers[0];
1413
1414 /* signal worker thread to do the flip */
1415 SDL_SemPost (sem1);
1416
1417 return 0;
1418}
1419
1420static void QZ_DoubleBufferUpdate (_THIS, int num_rects, SDL_Rect *rects)
1421{
1422 /* perform a flip if someone calls updaterects on a doublebuferred surface */
1423 this->FlipHWSurface (this, SDL_VideoSurface);
1424}
1425
1426static void QZ_DirectUpdate (_THIS, int num_rects, SDL_Rect *rects)
1427{
1428#pragma unused(this,num_rects,rects)
1429}
1430#endif
1431
1432/* Resize icon, BMP format */
1433static const unsigned char QZ_ResizeIcon[] = {
1434 0x42,0x4d,0x31,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x36,0x00,0x00,0x00,0x28,0x00,
1435 0x00,0x00,0x0d,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x01,0x00,0x18,0x00,0x00,0x00,
1436 0x00,0x00,0xfb,0x01,0x00,0x00,0x13,0x0b,0x00,0x00,0x13,0x0b,0x00,0x00,0x00,0x00,
1437 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
1438 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
1439 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0b,0xff,0xff,
1440 0xff,0xda,0xda,0xda,0x87,0x87,0x87,0xe8,0xe8,0xe8,0xff,0xff,0xff,0xda,0xda,0xda,
1441 0x87,0x87,0x87,0xe8,0xe8,0xe8,0xff,0xff,0xff,0xda,0xda,0xda,0x87,0x87,0x87,0xe8,
1442 0xe8,0xe8,0xff,0xff,0xff,0x0b,0xff,0xff,0xff,0xff,0xff,0xff,0xda,0xda,0xda,0x87,
1443 0x87,0x87,0xe8,0xe8,0xe8,0xff,0xff,0xff,0xda,0xda,0xda,0x87,0x87,0x87,0xe8,0xe8,
1444 0xe8,0xff,0xff,0xff,0xda,0xda,0xda,0x87,0x87,0x87,0xff,0xff,0xff,0x0b,0xff,0xff,
1445 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xd5,0xd5,0xd5,0x87,0x87,0x87,0xe8,0xe8,0xe8,
1446 0xff,0xff,0xff,0xda,0xda,0xda,0x87,0x87,0x87,0xe8,0xe8,0xe8,0xff,0xff,0xff,0xda,
1447 0xda,0xda,0xff,0xff,0xff,0x0b,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
1448 0xff,0xff,0xd7,0xd7,0xd7,0x87,0x87,0x87,0xe8,0xe8,0xe8,0xff,0xff,0xff,0xda,0xda,
1449 0xda,0x87,0x87,0x87,0xe8,0xe8,0xe8,0xff,0xff,0xff,0xff,0xff,0xff,0x0b,0xff,0xff,
1450 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xd7,0xd7,0xd7,
1451 0x87,0x87,0x87,0xe8,0xe8,0xe8,0xff,0xff,0xff,0xda,0xda,0xda,0x87,0x87,0x87,0xe8,
1452 0xe8,0xe8,0xff,0xff,0xff,0x0b,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
1453 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xd7,0xd7,0xd7,0x87,0x87,0x87,0xe8,0xe8,
1454 0xe8,0xff,0xff,0xff,0xdc,0xdc,0xdc,0x87,0x87,0x87,0xff,0xff,0xff,0x0b,0xff,0xff,
1455 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
1456 0xff,0xff,0xff,0xd9,0xd9,0xd9,0x87,0x87,0x87,0xe8,0xe8,0xe8,0xff,0xff,0xff,0xdc,
1457 0xdc,0xdc,0xff,0xff,0xff,0x0b,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
1458 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdb,0xdb,
1459 0xdb,0x87,0x87,0x87,0xe8,0xe8,0xe8,0xff,0xff,0xff,0xff,0xff,0xff,0x0b,0xff,0xff,
1460 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
1461 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdb,0xdb,0xdb,0x87,0x87,0x87,0xe8,
1462 0xe8,0xe8,0xff,0xff,0xff,0x0b,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
1463 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
1464 0xff,0xff,0xff,0xff,0xdc,0xdc,0xdc,0x87,0x87,0x87,0xff,0xff,0xff,0x0b,0xff,0xff,
1465 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
1466 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdc,
1467 0xdc,0xdc,0xff,0xff,0xff,0x0b,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
1468 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
1469 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0b
1470};
1471
1472static void QZ_DrawResizeIcon (_THIS)
1473{
1474 /* Check if we should draw the resize icon */
1475 if (SDL_VideoSurface->flags & SDL_RESIZABLE) {
1476
1477 SDL_Rect icon_rect;
1478
1479 /* Create the icon image */
1480 if (resize_icon == NULL) {
1481
1482 SDL_RWops *rw;
1483 SDL_Surface *tmp;
1484
1485 rw = SDL_RWFromConstMem (QZ_ResizeIcon, sizeof(QZ_ResizeIcon));
1486 tmp = SDL_LoadBMP_RW (rw, SDL_TRUE);
1487
1488 resize_icon = SDL_ConvertSurface (tmp, SDL_VideoSurface->format, SDL_SRCCOLORKEY);
1489 SDL_SetColorKey (resize_icon, SDL_SRCCOLORKEY, 0xFFFFFF);
1490
1491 SDL_FreeSurface (tmp);
1492 }
1493
1494 icon_rect.x = SDL_VideoSurface->w - 13;
1495 icon_rect.y = SDL_VideoSurface->h - 13;
1496 icon_rect.w = 13;
1497 icon_rect.h = 13;
1498
1499 SDL_BlitSurface (resize_icon, NULL, SDL_VideoSurface, &icon_rect);
1500 }
1501}
1502
1503static void QZ_UpdateRects (_THIS, int numRects, SDL_Rect *rects)
1504{
1505 if (SDL_VideoSurface->flags & SDL_OPENGLBLIT) {
1506 QZ_GL_SwapBuffers (this);
1507 }
1508 else if ( [ qz_window isMiniaturized ] ) {
1509
1510 /* Do nothing if miniaturized */
1511 }
1512
1513 else {
1514 NSGraphicsContext *ctx = [NSGraphicsContext currentContext];
1515 if (ctx != nsgfx_context) { /* uhoh, you might be rendering from another thread... */
1516 [NSGraphicsContext setCurrentContext:nsgfx_context];
1517 ctx = nsgfx_context;
1518 }
1519 CGContextRef cgc = (CGContextRef) [ctx graphicsPort];
1520 QZ_DrawResizeIcon (this);
1521 CGContextFlush (cg_context);
1522 CGImageRef image = CGBitmapContextCreateImage (cg_context);
1523 CGRect rectangle = CGRectMake (0,0,[window_view frame].size.width,[window_view frame].size.height);
1524
1525 CGContextDrawImage (cgc, rectangle, image);
1526 CGImageRelease(image);
1527 CGContextFlush (cgc);
1528 }
1529}
1530
1531static void QZ_VideoQuit (_THIS)
1532{
1533 CGDisplayFadeReservationToken fade_token = kCGDisplayFadeReservationInvalidToken;
1534
1535 /* Restore gamma settings */
1536 CGDisplayRestoreColorSyncSettings ();
1537
1538 /* Ensure the cursor will be visible and working when we quit */
1539 CGDisplayShowCursor (display_id);
1540 CGAssociateMouseAndMouseCursorPosition (1);
1541
1542 if (mode_flags & SDL_FULLSCREEN) {
1543 /* Fade to black to hide resolution-switching flicker (and garbage
1544 that is displayed by a destroyed OpenGL context, if applicable) */
1545 if (CGAcquireDisplayFadeReservation (5, &fade_token) == kCGErrorSuccess) {
1546 CGDisplayFade (fade_token, 0.3, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0, TRUE);
1547 }
1548 QZ_UnsetVideoMode (this, TRUE, FALSE);
1549 if (fade_token != kCGDisplayFadeReservationInvalidToken) {
1550 CGDisplayFade (fade_token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE);
1551 CGReleaseDisplayFadeReservation (fade_token);
1552 }
1553 }
1554 else
1555 QZ_UnsetVideoMode (this, TRUE, FALSE);
1556
1557#if (MAC_OS_X_VERSION_MIN_REQUIRED < 1070)
1558 if (!IS_LION_OR_LATER(this)) {
1559 CGPaletteRelease(palette);
1560 }
1561#endif
1562
1563 if (opengl_library) {
1564 SDL_UnloadObject(opengl_library);
1565 opengl_library = NULL;
1566 }
1567 this->gl_config.driver_loaded = 0;
1568
1569 if (field_edit) {
1570 [field_edit release];
1571 field_edit = NULL;
1572 }
1573}
1574
1575static int QZ_LockHWSurface(_THIS, SDL_Surface *surface)
1576{
1577 return 1;
1578}
1579
1580static void QZ_UnlockHWSurface(_THIS, SDL_Surface *surface)
1581{
1582}
1583
1584static int QZ_AllocHWSurface(_THIS, SDL_Surface *surface)
1585{
1586 return(-1); /* unallowed (no HWSURFACE support here). */
1587}
1588
1589static void QZ_FreeHWSurface (_THIS, SDL_Surface *surface)
1590{
1591}
1592
1593/* Gamma functions */
1594int QZ_SetGamma (_THIS, float red, float green, float blue)
1595{
1596 const CGGammaValue min = 0.0, max = 1.0;
1597
1598 if (red == 0.0)
1599 red = FLT_MAX;
1600 else
1601 red = 1.0 / red;
1602
1603 if (green == 0.0)
1604 green = FLT_MAX;
1605 else
1606 green = 1.0 / green;
1607
1608 if (blue == 0.0)
1609 blue = FLT_MAX;
1610 else
1611 blue = 1.0 / blue;
1612
1613 if ( CGDisplayNoErr == CGSetDisplayTransferByFormula
1614 (display_id, min, max, red, min, max, green, min, max, blue) ) {
1615
1616 return 0;
1617 }
1618 else {
1619
1620 return -1;
1621 }
1622}
1623
1624int QZ_GetGamma (_THIS, float *red, float *green, float *blue)
1625{
1626 CGGammaValue dummy;
1627 if ( CGDisplayNoErr == CGGetDisplayTransferByFormula
1628 (display_id, &dummy, &dummy, red,
1629 &dummy, &dummy, green, &dummy, &dummy, blue) )
1630
1631 return 0;
1632 else
1633 return -1;
1634}
1635
1636int QZ_SetGammaRamp (_THIS, Uint16 *ramp)
1637{
1638 const uint32_t tableSize = 255;
1639 CGGammaValue redTable[tableSize];
1640 CGGammaValue greenTable[tableSize];
1641 CGGammaValue blueTable[tableSize];
1642
1643 int i;
1644
1645 /* Extract gamma values into separate tables, convert to floats between 0.0 and 1.0 */
1646 for (i = 0; i < 256; i++)
1647 redTable[i % 256] = ramp[i] / 65535.0;
1648
1649 for (i=256; i < 512; i++)
1650 greenTable[i % 256] = ramp[i] / 65535.0;
1651
1652 for (i=512; i < 768; i++)
1653 blueTable[i % 256] = ramp[i] / 65535.0;
1654
1655 if ( CGDisplayNoErr == CGSetDisplayTransferByTable
1656 (display_id, tableSize, redTable, greenTable, blueTable) )
1657 return 0;
1658 else
1659 return -1;
1660}
1661
1662int QZ_GetGammaRamp (_THIS, Uint16 *ramp)
1663{
1664 const uint32_t tableSize = 255;
1665 CGGammaValue redTable[tableSize];
1666 CGGammaValue greenTable[tableSize];
1667 CGGammaValue blueTable[tableSize];
1668 uint32_t actual;
1669 int i;
1670
1671 if ( CGDisplayNoErr != CGGetDisplayTransferByTable
1672 (display_id, tableSize, redTable, greenTable, blueTable, &actual) ||
1673 actual != tableSize)
1674
1675 return -1;
1676
1677 /* Pack tables into one array, with values from 0 to 65535 */
1678 for (i = 0; i < 256; i++)
1679 ramp[i] = redTable[i % 256] * 65535.0;
1680
1681 for (i=256; i < 512; i++)
1682 ramp[i] = greenTable[i % 256] * 65535.0;
1683
1684 for (i=512; i < 768; i++)
1685 ramp[i] = blueTable[i % 256] * 65535.0;
1686
1687 return 0;
1688}
1689