diff options
Diffstat (limited to 'apps/plugins/sdl/src/video/quartz/SDL_QuartzVideo.m')
-rw-r--r-- | apps/plugins/sdl/src/video/quartz/SDL_QuartzVideo.m | 1689 |
1 files changed, 1689 insertions, 0 deletions
diff --git a/apps/plugins/sdl/src/video/quartz/SDL_QuartzVideo.m b/apps/plugins/sdl/src/video/quartz/SDL_QuartzVideo.m new file mode 100644 index 0000000000..fa04e9d107 --- /dev/null +++ b/apps/plugins/sdl/src/video/quartz/SDL_QuartzVideo.m | |||
@@ -0,0 +1,1689 @@ | |||
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)) | ||
31 | CG_EXTERN void *CGDisplayBaseAddress(CGDirectDisplayID display) | ||
32 | CG_AVAILABLE_BUT_DEPRECATED(__MAC_10_0, __MAC_10_6, | ||
33 | __IPHONE_NA, __IPHONE_NA); | ||
34 | CG_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 | |||
40 | static inline BOOL IS_LION_OR_LATER(_THIS) | ||
41 | { | ||
42 | return (system_version >= 0x1070); | ||
43 | } | ||
44 | |||
45 | static 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 | ||
68 | static 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 | ||
75 | static 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. */ | ||
91 | CG_EXTERN CGImageRef CGBitmapContextCreateImage (CGContextRef); | ||
92 | |||
93 | /* Bootstrap functions */ | ||
94 | static int QZ_Available (); | ||
95 | static SDL_VideoDevice* QZ_CreateDevice (int device_index); | ||
96 | static void QZ_DeleteDevice (SDL_VideoDevice *device); | ||
97 | |||
98 | /* Initialization, Query, Setup, and Redrawing functions */ | ||
99 | static int QZ_VideoInit (_THIS, SDL_PixelFormat *video_format); | ||
100 | |||
101 | static SDL_Rect** QZ_ListModes (_THIS, SDL_PixelFormat *format, | ||
102 | Uint32 flags); | ||
103 | static void QZ_UnsetVideoMode (_THIS, BOOL to_desktop, BOOL save_gl); | ||
104 | |||
105 | static SDL_Surface* QZ_SetVideoMode (_THIS, SDL_Surface *current, | ||
106 | int width, int height, int bpp, | ||
107 | Uint32 flags); | ||
108 | static int QZ_ToggleFullScreen (_THIS, int on); | ||
109 | static int QZ_SetColors (_THIS, int first_color, | ||
110 | int num_colors, SDL_Color *colors); | ||
111 | |||
112 | #if (MAC_OS_X_VERSION_MIN_REQUIRED < 1070) | ||
113 | static int QZ_LockDoubleBuffer (_THIS, SDL_Surface *surface); | ||
114 | static void QZ_UnlockDoubleBuffer (_THIS, SDL_Surface *surface); | ||
115 | static int QZ_ThreadFlip (_THIS); | ||
116 | static int QZ_FlipDoubleBuffer (_THIS, SDL_Surface *surface); | ||
117 | static void QZ_DoubleBufferUpdate (_THIS, int num_rects, SDL_Rect *rects); | ||
118 | static void QZ_DirectUpdate (_THIS, int num_rects, SDL_Rect *rects); | ||
119 | #endif | ||
120 | |||
121 | static void QZ_UpdateRects (_THIS, int num_rects, SDL_Rect *rects); | ||
122 | static void QZ_VideoQuit (_THIS); | ||
123 | |||
124 | static int QZ_LockHWSurface(_THIS, SDL_Surface *surface); | ||
125 | static void QZ_UnlockHWSurface(_THIS, SDL_Surface *surface); | ||
126 | static int QZ_AllocHWSurface(_THIS, SDL_Surface *surface); | ||
127 | static void QZ_FreeHWSurface (_THIS, SDL_Surface *surface); | ||
128 | |||
129 | /* Bootstrap binding, enables entry point into the driver */ | ||
130 | VideoBootStrap 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 | |||
141 | static 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 | |||
151 | static 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 */ | ||
163 | static int QZ_Available () | ||
164 | { | ||
165 | return 1; | ||
166 | } | ||
167 | |||
168 | static 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 | |||
240 | static 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 | |||
249 | static 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 | |||
297 | static 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 | |||
394 | static 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 | |||
508 | static 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 | |||
519 | static 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 | |||
536 | static inline CGError QZ_RestoreDisplayMode(_THIS) | ||
537 | { | ||
538 | return QZ_SetDisplayMode(this, save_mode); | ||
539 | } | ||
540 | |||
541 | static 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 | |||
636 | static 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 | |||
681 | static 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 */ | ||
946 | ERR_NO_GL: goto ERR_DOUBLEBUF; /* this goto is to stop a compiler warning on newer SDKs. */ | ||
947 | ERR_DOUBLEBUF: QZ_RestoreDisplayMode(this); | ||
948 | ERR_NO_SWITCH: CGReleaseAllDisplays (); | ||
949 | ERR_NO_CAPTURE: | ||
950 | ERR_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 | |||
957 | static 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 | |||
1129 | static 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 | |||
1211 | static 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 | |||
1239 | static int QZ_ToggleFullScreen (_THIS, int on) | ||
1240 | { | ||
1241 | return 0; | ||
1242 | } | ||
1243 | |||
1244 | static 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) | ||
1273 | static int QZ_LockDoubleBuffer (_THIS, SDL_Surface *surface) | ||
1274 | { | ||
1275 | return 1; | ||
1276 | } | ||
1277 | |||
1278 | static 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> */ | ||
1283 | static 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 | |||
1296 | static 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, ¶m); | ||
1312 | policy = SCHED_RR; | ||
1313 | param.sched_priority = sched_get_priority_max (policy); | ||
1314 | pthread_setschedparam (current_thread, policy, ¶m); | ||
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 | |||
1402 | static 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 | |||
1420 | static 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 | |||
1426 | static 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 */ | ||
1433 | static 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 | |||
1472 | static 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 | |||
1503 | static 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 | |||
1531 | static 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 | |||
1575 | static int QZ_LockHWSurface(_THIS, SDL_Surface *surface) | ||
1576 | { | ||
1577 | return 1; | ||
1578 | } | ||
1579 | |||
1580 | static void QZ_UnlockHWSurface(_THIS, SDL_Surface *surface) | ||
1581 | { | ||
1582 | } | ||
1583 | |||
1584 | static int QZ_AllocHWSurface(_THIS, SDL_Surface *surface) | ||
1585 | { | ||
1586 | return(-1); /* unallowed (no HWSURFACE support here). */ | ||
1587 | } | ||
1588 | |||
1589 | static void QZ_FreeHWSurface (_THIS, SDL_Surface *surface) | ||
1590 | { | ||
1591 | } | ||
1592 | |||
1593 | /* Gamma functions */ | ||
1594 | int 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 | |||
1624 | int 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 | |||
1636 | int 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 | |||
1662 | int 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 | |||