This repository has been archived by the owner on Feb 11, 2021. It is now read-only.
/
SDL_QuartzVideo.m
1721 lines (1364 loc) · 52.5 KB
1
2
/*
SDL - Simple DirectMedia Layer
3
Copyright (C) 1997-2003 Sam Lantinga
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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
28
29
30
31
32
33
/*
Add methods to get at private members of NSScreen.
Since there is a bug in Apple's screen switching code
that does not update this variable when switching
to fullscreen, we'll set it manually (but only for the
main screen).
*/
34
35
36
@ interface NSScreen (NSScreenAccess) - (void) setFrame:(NSRect) frame;
@end @ implementation NSScreen (NSScreenAccess) - (void) setFrame:(NSRect)
frame;
37
38
39
40
{
_frame = frame;
}
41
@end
42
43
44
45
46
/*
Structure for rez switch gamma fades
We can hide the monitor flicker by setting the gamma tables to 0
*/
#define QZ_GAMMA_TABLE_SIZE 256
47
48
typedef struct
{
49
50
51
52
53
54
55
56
57
CGGammaValue red[QZ_GAMMA_TABLE_SIZE];
CGGammaValue green[QZ_GAMMA_TABLE_SIZE];
CGGammaValue blue[QZ_GAMMA_TABLE_SIZE];
} SDL_QuartzGammaTable;
/* Bootstrap functions */
58
59
60
static int QZ_Available ();
static SDL_VideoDevice *QZ_CreateDevice (int device_index);
static void QZ_DeleteDevice (SDL_VideoDevice * device);
61
62
/* Initialization, Query, Setup, and Redrawing functions */
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
static int QZ_VideoInit (_THIS, SDL_PixelFormat * video_format);
static SDL_Rect **QZ_ListModes (_THIS, SDL_PixelFormat * format,
Uint32 flags);
static void QZ_UnsetVideoMode (_THIS, BOOL to_desktop);
static SDL_Surface *QZ_SetVideoMode (_THIS, SDL_Surface * current,
int width, int height, int bpp,
Uint32 flags);
static int QZ_ToggleFullScreen (_THIS, int on);
static int QZ_SetColors (_THIS, int first_color,
int num_colors, SDL_Color * colors);
static int QZ_LockDoubleBuffer (_THIS, SDL_Surface * surface);
static void QZ_UnlockDoubleBuffer (_THIS, SDL_Surface * surface);
static int QZ_ThreadFlip (_THIS);
static int QZ_FlipDoubleBuffer (_THIS, SDL_Surface * surface);
static void QZ_DoubleBufferUpdate (_THIS, int num_rects, SDL_Rect * rects);
static void QZ_DirectUpdate (_THIS, int num_rects, SDL_Rect * rects);
static int QZ_LockWindow (_THIS, SDL_Surface * surface);
static void QZ_UnlockWindow (_THIS, SDL_Surface * surface);
static void QZ_UpdateRects (_THIS, int num_rects, SDL_Rect * rects);
static void QZ_VideoQuit (_THIS);
87
88
/* Hardware surface functions (for fullscreen mode only) */
89
90
91
#if 0 /* Not used (apparently, it's really slow) */
static int QZ_FillHWRect (_THIS, SDL_Surface * dst, SDL_Rect * rect,
Uint32 color);
92
#endif
93
94
95
96
static int QZ_LockHWSurface (_THIS, SDL_Surface * surface);
static void QZ_UnlockHWSurface (_THIS, SDL_Surface * surface);
static int QZ_AllocHWSurface (_THIS, SDL_Surface * surface);
static void QZ_FreeHWSurface (_THIS, SDL_Surface * surface);
97
/* static int QZ_FlipHWSurface (_THIS, SDL_Surface *surface); */
98
99
100
/* Bootstrap binding, enables entry point into the driver */
VideoBootStrap QZ_bootstrap = {
101
"Quartz", "Mac OS X CoreGraphics", QZ_Available, QZ_CreateDevice
102
103
};
104
105
/* Bootstrap functions */
106
107
108
static int
QZ_Available ()
{
109
110
111
return 1;
}
112
113
114
static SDL_VideoDevice *
QZ_CreateDevice (int device_index)
{
115
116
#pragma unused (device_index)
117
118
119
120
SDL_VideoDevice *device;
SDL_PrivateVideoData *hidden;
121
122
device = (SDL_VideoDevice *) SDL_malloc (sizeof (*device));
hidden = (SDL_PrivateVideoData *) SDL_malloc (sizeof (*hidden));
123
124
125
126
if (device == NULL || hidden == NULL)
SDL_OutOfMemory ();
127
128
SDL_memset (device, 0, sizeof (*device));
SDL_memset (hidden, 0, sizeof (*hidden));
129
130
131
device->hidden = hidden;
132
133
134
device->VideoInit = QZ_VideoInit;
device->ListModes = QZ_ListModes;
device->SetVideoMode = QZ_SetVideoMode;
135
device->ToggleFullScreen = QZ_ToggleFullScreen;
136
137
device->UpdateMouse = QZ_UpdateMouse;
device->SetColors = QZ_SetColors;
138
/* device->UpdateRects = QZ_UpdateRects; this is determined by SetVideoMode() */
139
device->VideoQuit = QZ_VideoQuit;
140
141
device->LockHWSurface = QZ_LockHWSurface;
142
device->UnlockHWSurface = QZ_UnlockHWSurface;
143
144
145
device->AllocHWSurface = QZ_AllocHWSurface;
device->FreeHWSurface = QZ_FreeHWSurface;
/* device->FlipHWSurface = QZ_FlipHWSurface */ ;
146
147
148
device->SetGamma = QZ_SetGamma;
device->GetGamma = QZ_GetGamma;
149
150
151
152
device->SetGammaRamp = QZ_SetGammaRamp;
device->GetGammaRamp = QZ_GetGammaRamp;
device->GL_GetProcAddress = QZ_GL_GetProcAddress;
153
154
155
156
device->GL_GetAttribute = QZ_GL_GetAttribute;
device->GL_MakeCurrent = QZ_GL_MakeCurrent;
device->GL_SwapBuffers = QZ_GL_SwapBuffers;
device->GL_LoadLibrary = QZ_GL_LoadLibrary;
157
158
device->FreeWMCursor = QZ_FreeWMCursor;
159
device->CreateWMCursor = QZ_CreateWMCursor;
160
161
162
device->ShowWMCursor = QZ_ShowWMCursor;
device->WarpWMCursor = QZ_WarpWMCursor;
device->MoveWMCursor = QZ_MoveWMCursor;
163
device->CheckMouseMode = QZ_CheckMouseMode;
164
165
device->InitOSKeymap = QZ_InitOSKeymap;
device->PumpEvents = QZ_PumpEvents;
166
167
168
device->SetCaption = QZ_SetCaption;
device->SetIcon = QZ_SetIcon;
169
device->IconifyWindow = QZ_IconifyWindow;
170
171
/*device->GetWMInfo = QZ_GetWMInfo; */
device->GrabInput = QZ_GrabInput;
172
173
device->CreateYUVOverlay = QZ_CreateYUVOverlay;
174
175
device->free = QZ_DeleteDevice;
176
177
178
179
return device;
}
180
181
182
static void
QZ_DeleteDevice (SDL_VideoDevice * device)
{
183
184
185
SDL_free (device->hidden);
SDL_free (device);
186
187
}
188
189
190
static int
QZ_VideoInit (_THIS, SDL_PixelFormat * video_format)
{
191
192
193
/* Initialize the video settings; this data persists between mode switches */
display_id = kCGDirectMainDisplay;
194
195
196
save_mode = CGDisplayCurrentMode (display_id);
mode_list = CGDisplayAvailableModes (display_id);
palette = CGPaletteCreateDefaultColorPalette ();
197
198
/* Gather some information that is useful to know about the display */
199
200
CFNumberGetValue (CFDictionaryGetValue
(save_mode, kCGDisplayBitsPerPixel),
201
kCFNumberSInt32Type, &device_bpp);
202
203
204
205
206
207
208
CFNumberGetValue (CFDictionaryGetValue (save_mode, kCGDisplayWidth),
kCFNumberSInt32Type, &device_width);
CFNumberGetValue (CFDictionaryGetValue (save_mode, kCGDisplayHeight),
kCFNumberSInt32Type, &device_height);
209
210
211
212
213
/* Determine the current screen size */
this->info.current_w = device_width;
this->info.current_h = device_height;
/* Determine the default screen depth */
214
215
video_format->BitsPerPixel = device_bpp;
216
217
/* Set misc globals */
current_grab_mode = SDL_GRAB_OFF;
218
219
cursor_should_be_visible = YES;
cursor_visible = YES;
220
current_mods = 0;
221
222
if (Gestalt (gestaltSystemVersion, &system_version) != noErr)
223
system_version = 0;
224
225
226
/* register for sleep notifications so wake from sleep generates SDL_VIDEOEXPOSE */
QZ_RegisterForSleepNotifications (this);
227
228
229
230
/* Fill in some window manager capabilities */
this->info.wm_available = 1;
231
return 0;
232
233
}
234
235
236
static SDL_Rect **
QZ_ListModes (_THIS, SDL_PixelFormat * format, Uint32 flags)
{
237
238
CFIndex num_modes;
239
240
241
CFIndex i;
int list_size = 0;
242
243
/* Any windowed mode is acceptable */
244
245
if ((flags & SDL_FULLSCREEN) == 0)
return (SDL_Rect **) - 1;
246
247
/* Free memory from previous call, if any */
248
if (client_mode_list != NULL) {
249
250
int i;
251
252
for (i = 0; client_mode_list[i] != NULL; i++)
253
SDL_free (client_mode_list[i]);
254
255
SDL_free (client_mode_list);
256
client_mode_list = NULL;
257
}
258
259
260
num_modes = CFArrayGetCount (mode_list);
261
/* Build list of modes with the requested bpp */
262
for (i = 0; i < num_modes; i++) {
263
264
CFDictionaryRef onemode;
265
CFNumberRef number;
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
int bpp;
onemode = CFArrayGetValueAtIndex (mode_list, i);
number = CFDictionaryGetValue (onemode, kCGDisplayBitsPerPixel);
CFNumberGetValue (number, kCFNumberSInt32Type, &bpp);
if (bpp == format->BitsPerPixel) {
int intvalue;
int hasMode;
int width, height;
number = CFDictionaryGetValue (onemode, kCGDisplayWidth);
CFNumberGetValue (number, kCFNumberSInt32Type, &intvalue);
width = (Uint16) intvalue;
number = CFDictionaryGetValue (onemode, kCGDisplayHeight);
CFNumberGetValue (number, kCFNumberSInt32Type, &intvalue);
height = (Uint16) intvalue;
/* Check if mode is already in the list */
{
int i;
hasMode = SDL_FALSE;
for (i = 0; i < list_size; i++) {
291
if (client_mode_list[i]->w == width &&
292
client_mode_list[i]->h == height) {
293
294
295
hasMode = SDL_TRUE;
break;
}
296
297
}
}
298
299
/* Grow the list and add mode to the list */
300
if (!hasMode) {
301
302
303
304
305
SDL_Rect *rect;
list_size++;
306
if (client_mode_list == NULL)
307
308
309
client_mode_list = (SDL_Rect **)
SDL_malloc (sizeof (*client_mode_list) *
(list_size + 1));
310
else
311
312
313
314
client_mode_list = (SDL_Rect **)
SDL_realloc (client_mode_list,
sizeof (*client_mode_list) *
(list_size + 1));
315
316
317
rect = (SDL_Rect *)
SDL_malloc (sizeof (**client_mode_list));
318
319
if (client_mode_list == NULL || rect == NULL) {
320
321
322
323
SDL_OutOfMemory ();
return NULL;
}
324
rect->x = rect->y = 0;
325
326
327
rect->w = width;
rect->h = height;
328
329
client_mode_list[list_size - 1] = rect;
client_mode_list[list_size] = NULL;
330
}
331
332
}
}
333
334
335
336
337
/* Sort list largest to smallest (by area) */
{
int i, j;
for (i = 0; i < list_size; i++) {
338
for (j = 0; j < list_size - 1; j++) {
339
340
int area1, area2;
341
area1 = client_mode_list[j]->w * client_mode_list[j]->h;
342
343
area2 =
client_mode_list[j + 1]->w * client_mode_list[j + 1]->h;
344
345
if (area1 < area2) {
346
SDL_Rect *tmp = client_mode_list[j];
347
348
client_mode_list[j] = client_mode_list[j + 1];
client_mode_list[j + 1] = tmp;
349
350
351
352
}
}
}
}
353
return client_mode_list;
354
355
}
356
357
static SDL_bool
QZ_WindowPosition (_THIS, int *x, int *y)
358
{
359
360
361
const char *window = getenv ("SDL_VIDEO_WINDOW_POS");
if (window) {
if (sscanf (window, "%d,%d", x, y) == 2) {
362
363
364
365
366
367
return SDL_TRUE;
}
}
return SDL_FALSE;
}
368
369
370
static void
QZ_UnsetVideoMode (_THIS, BOOL to_desktop)
{
371
372
/* Reset values that may change between switches */
373
374
375
376
this->info.blit_fill = 0;
this->FillHWRect = NULL;
this->UpdateRects = NULL;
this->LockHWSurface = NULL;
377
this->UnlockHWSurface = NULL;
378
379
/* Release fullscreen resources */
380
if (mode_flags & SDL_FULLSCREEN) {
381
382
NSRect screen_rect;
383
384
/* Release double buffer stuff */
385
if (mode_flags & SDL_DOUBLEBUF) {
386
387
388
389
390
quit_thread = YES;
SDL_SemPost (sem1);
SDL_WaitThread (thread, NULL);
SDL_DestroySemaphore (sem1);
SDL_DestroySemaphore (sem2);
391
SDL_free (sw_buffers[0]);
392
}
393
394
/*
395
396
397
398
399
Release the OpenGL context
Do this first to avoid trash on the display before fade
*/
if (mode_flags & SDL_INTERNALOPENGL) {
400
QZ_TearDownOpenGL (this);
401
402
CGLSetFullScreen (NULL);
}
403
404
405
406
407
408
if (to_desktop) {
/* Restore original screen resolution/bpp */
CGDisplaySwitchToMode (display_id, save_mode);
CGReleaseAllDisplays ();
ShowMenuBar ();
/*
409
410
411
412
413
Reset the main screen's rectangle
See comment in QZ_SetVideoFullscreen for why we do this
*/
screen_rect = NSMakeRect (0, 0, device_width, device_height);
[[NSScreen mainScreen] setFrame:screen_rect];
414
}
415
}
416
/* Release window mode resources */
417
else {
418
419
420
[qz_window close];
[qz_window release];
421
qz_window = nil;
422
window_view = nil;
423
424
/* Release the OpenGL context */
425
if (mode_flags & SDL_INTERNALOPENGL)
426
QZ_TearDownOpenGL (this);
427
}
428
429
430
/* Signal successful teardown */
video_set = SDL_FALSE;
431
432
}
433
434
435
436
static SDL_Surface *
QZ_SetVideoFullScreen (_THIS, SDL_Surface * current, int width,
int height, int bpp, Uint32 flags)
{
437
boolean_t exact_match = 0;
438
NSRect screen_rect;
439
CGError error;
440
441
442
CGDisplayFadeReservationToken fade_token =
kCGDisplayFadeReservationInvalidToken;
443
444
/* Fade to black to hide resolution-switching flicker (and garbage
that is displayed by a destroyed OpenGL context, if applicable) */
445
446
447
if (CGAcquireDisplayFadeReservation (5, &fade_token) == kCGErrorSuccess) {
CGDisplayFade (fade_token, 0.3, kCGDisplayBlendNormal,
kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0, TRUE);
448
}
449
450
451
/* Destroy any previous mode */
if (video_set == SDL_TRUE)
452
QZ_UnsetVideoMode (this, FALSE);
453
454
/* See if requested mode exists */
455
456
457
mode = CGDisplayBestModeForParameters (display_id, bpp, width,
height, &exact_match);
458
/* Require an exact match to the requested mode */
459
460
461
if (!exact_match) {
SDL_SetError ("Failed to find display resolution: %dx%dx%d", width,
height, bpp);
462
463
goto ERR_NO_MATCH;
}
464
465
/* Put up the blanking window (a window above all other windows) */
466
467
468
469
if (getenv ("SDL_SINGLEDISPLAY"))
error = CGDisplayCapture (display_id);
else
error = CGCaptureAllDisplays ();
470
471
if (CGDisplayNoErr != error) {
472
473
474
SDL_SetError ("Failed capturing display");
goto ERR_NO_CAPTURE;
}
475
476
/* Do the physical switch */
477
if (CGDisplayNoErr != CGDisplaySwitchToMode (display_id, mode)) {
478
479
480
SDL_SetError ("Failed switching display resolution");
goto ERR_NO_SWITCH;
}
481
482
483
current->pixels = (Uint32 *) CGDisplayBaseAddress (display_id);
current->pitch = CGDisplayBytesPerRow (display_id);
484
485
current->flags = 0;
486
487
current->w = width;
current->h = height;
488
current->flags |= SDL_FULLSCREEN;
489
current->flags |= SDL_HWSURFACE;
490
current->flags |= SDL_PREALLOC;
491
492
493
this->UpdateRects = QZ_DirectUpdate;
this->LockHWSurface = QZ_LockHWSurface;
494
this->UnlockHWSurface = QZ_UnlockHWSurface;
495
496
/* Setup double-buffer emulation */
497
498
if (flags & SDL_DOUBLEBUF) {
499
/*
500
501
502
503
504
505
506
Setup a software backing store for reasonable results when
double buffering is requested (since a single-buffered hardware
surface looks hideous).
The actual screen blit occurs in a separate thread to allow
other blitting while waiting on the VBL (and hence results in higher framerates).
*/
507
508
509
this->LockHWSurface = NULL;
this->UnlockHWSurface = NULL;
this->UpdateRects = NULL;
510
511
current->flags |= (SDL_HWSURFACE | SDL_DOUBLEBUF);
512
513
514
515
516
this->UpdateRects = QZ_DoubleBufferUpdate;
this->LockHWSurface = QZ_LockDoubleBuffer;
this->UnlockHWSurface = QZ_UnlockDoubleBuffer;
this->FlipHWSurface = QZ_FlipDoubleBuffer;
517
current->pixels = SDL_malloc (current->pitch * current->h * 2);
518
519
520
521
if (current->pixels == NULL) {
SDL_OutOfMemory ();
goto ERR_DOUBLEBUF;
}
522
523
sw_buffers[0] = current->pixels;
524
525
526
sw_buffers[1] =
(Uint8 *) current->pixels + current->pitch * current->h;
527
528
529
quit_thread = NO;
sem1 = SDL_CreateSemaphore (0);
sem2 = SDL_CreateSemaphore (1);
530
thread = SDL_CreateThread ((int (*)(void *)) QZ_ThreadFlip, this);
531
}
532
533
if (CGDisplayCanSetPalette (display_id))
534
current->flags |= SDL_HWPALETTE;
535
536
/* Setup OpenGL for a fullscreen context */
537
if (flags & SDL_INTERNALOPENGL) {
538
539
540
CGLError err;
CGLContextObj ctx;
541
542
if (!QZ_SetupOpenGL (this, bpp, flags)) {
543
goto ERR_NO_GL;
544
}
545
546
ctx =[gl_context cglContext];
547
err = CGLSetFullScreen (ctx);
548
549
if (err) {
550
551
SDL_SetError ("Error setting OpenGL fullscreen: %s",
CGLErrorString (err));
552
553
goto ERR_NO_GL;
}
554
555
[gl_context makeCurrentContext];
556
557
558
glClear (GL_COLOR_BUFFER_BIT);
559
[gl_context flushBuffer];
560
561
current->flags |= SDL_INTERNALOPENGL;
562
563
564
565
}
/* If we don't hide menu bar, it will get events and interrupt the program */
HideMenuBar ();
566
567
/* Fade in again (asynchronously) */
568
569
570
571
if (fade_token != kCGDisplayFadeReservationInvalidToken) {
CGDisplayFade (fade_token, 0.5, kCGDisplayBlendSolidColor,
kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE);
CGReleaseDisplayFadeReservation (fade_token);
572
}
573
574
/*
575
576
577
578
579
580
581
582
There is a bug in Cocoa where NSScreen doesn't synchronize
with CGDirectDisplay, so the main screen's frame is wrong.
As a result, coordinate translation produces incorrect results.
We can hack around this bug by setting the screen rect
ourselves. This hack should be removed if/when the bug is fixed.
*/
screen_rect = NSMakeRect (0, 0, width, height);
[[NSScreen mainScreen] setFrame:screen_rect];
583
584
585
/* Save the flags to ensure correct tear-down */
mode_flags = current->flags;
586
587
/* Set app state, hide cursor if necessary, ... */
588
QZ_DoActivate (this);
589
590
591
return current;
592
/* Since the blanking window covers *all* windows (even force quit) correct recovery is crucial */
593
594
595
596
597
598
599
600
601
602
ERR_NO_GL:
ERR_DOUBLEBUF:CGDisplaySwitchToMode (display_id, save_mode);
ERR_NO_SWITCH:CGReleaseAllDisplays ();
ERR_NO_CAPTURE:
ERR_NO_MATCH:if (fade_token != kCGDisplayFadeReservationInvalidToken) {
CGDisplayFade (fade_token, 0.5, kCGDisplayBlendSolidColor,
kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE);
CGReleaseDisplayFadeReservation (fade_token);
}
return NULL;
603
604
}
605
606
607
608
static SDL_Surface *
QZ_SetVideoWindowed (_THIS, SDL_Surface * current, int width,
int height, int *bpp, Uint32 flags)
{
609
unsigned int style;
610
NSRect contentRect;
611
BOOL isCustom = NO;
612
613
int center_window = 1;
int origin_x, origin_y;
614
615
CGDisplayFadeReservationToken fade_token =
kCGDisplayFadeReservationInvalidToken;
616
617
618
current->flags = 0;
current->w = width;
619
current->h = height;
620
621
contentRect = NSMakeRect (0, 0, width, height);
622
623
/*
624
625
626
627
628
629
Check if we should completely destroy the previous mode
- If it is fullscreen
- If it has different noframe or resizable attribute
- If it is OpenGL (since gl attributes could be different)
- If new mode is OpenGL, but previous mode wasn't
*/
630
631
632
633
if (video_set == SDL_TRUE) {
if (mode_flags & SDL_FULLSCREEN) {
/* Fade to black to hide resolution-switching flicker (and garbage
that is displayed by a destroyed OpenGL context, if applicable) */
634
635
636
637
638
if (CGAcquireDisplayFadeReservation (5, &fade_token) ==
kCGErrorSuccess) {
CGDisplayFade (fade_token, 0.3, kCGDisplayBlendNormal,
kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0,
TRUE);
639
640
}
QZ_UnsetVideoMode (this, TRUE);
641
642
643
} else if (((mode_flags ^ flags) & (SDL_NOFRAME | SDL_RESIZABLE)) ||
(mode_flags & SDL_INTERNALOPENGL) ||
(flags & SDL_INTERNALOPENGL)) {
644
645
646
QZ_UnsetVideoMode (this, TRUE);
}
}
647
648
649
650
651
/* Check for user-specified window and view */
{
char *windowPtrString = getenv ("SDL_NSWindowPointer");
char *viewPtrString = getenv ("SDL_NSQuickDrawViewPointer");
652
653
if (windowPtrString && viewPtrString) {
654
655
/* Release any previous window */
656
657
if (qz_window) {
[qz_window release];
658
659
qz_window = nil;
}
660
661
662
qz_window = (NSWindow *) atoi (windowPtrString);
window_view = (NSQuickDrawView *) atoi (viewPtrString);
663
isCustom = YES;
664
665
/*
666
667
668
669
670
671
Retain reference to window because we
might release it in QZ_UnsetVideoMode
*/
[qz_window retain];
style =[qz_window styleMask];
672
/* Check resizability */
673
if (style & NSResizableWindowMask)
674
current->flags |= SDL_RESIZABLE;
675
676
/* Check frame */
677
if (style & NSBorderlessWindowMask)
678
679
680
current->flags |= SDL_NOFRAME;
}
}
681
682
683
/* Check if we should recreate the window */
if (qz_window == nil) {
684
685
/* Set the window style based on input flags */
686
if (flags & SDL_NOFRAME) {
687
688
689
690
691
style = NSBorderlessWindowMask;
current->flags |= SDL_NOFRAME;
} else {
style = NSTitledWindowMask;
style |= (NSMiniaturizableWindowMask | NSClosableWindowMask);
692
if (flags & SDL_RESIZABLE) {
693
694
695
696
style |= NSResizableWindowMask;
current->flags |= SDL_RESIZABLE;
}
}
697
698
if (QZ_WindowPosition (this, &origin_x, &origin_y)) {
699
center_window = 0;
700
701
contentRect.origin.x = (float) origin_x;
contentRect.origin.y = (float) origin_y;
702
}
703
704
/* Manually create a window, avoids having a nib file resource */
705
706
qz_window =[[SDL_QuartzWindow alloc] initWithContentRect: contentRect styleMask: style backing: NSBackingStoreBuffered defer:NO];
707
708
if (qz_window == nil) {
SDL_SetError ("Could not create the Cocoa window");
709
if (fade_token != kCGDisplayFadeReservationInvalidToken) {
710
711
712
CGDisplayFade (fade_token, 0.5,
kCGDisplayBlendSolidColor,
kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE);
713
714
CGReleaseDisplayFadeReservation (fade_token);
}
715
716
return NULL;
}
717
718
719
720
721
722
723
/*[ qz_window setReleasedWhenClosed:YES ]; */
QZ_SetCaption (this, this->wm_title, this->wm_icon);
[qz_window setAcceptsMouseMovedEvents:YES];
[qz_window setViewsNeedDisplay:NO];
if (center_window) {
[qz_window center];
724
}
725
726
[qz_window setDelegate:
[[[SDL_QuartzWindowDelegate alloc] init] autorelease]];
727
728
729
}
/* We already have a window, just change its size */
else {
730
731
if (!isCustom) {
732
733
734
[qz_window setContentSize:contentRect.size];
current->flags |= (SDL_NOFRAME | SDL_RESIZABLE) & mode_flags;
[window_view setFrameSize:contentRect.size];
735
}
736
}
737
738
/* For OpenGL, we bind the context to a subview */
739
if (flags & SDL_INTERNALOPENGL) {
740
741
if (!QZ_SetupOpenGL (this, *bpp, flags)) {
742
if (fade_token != kCGDisplayFadeReservationInvalidToken) {
743
744
745
CGDisplayFade (fade_token, 0.5,
kCGDisplayBlendSolidColor,
kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE);
746
747
CGReleaseDisplayFadeReservation (fade_token);
}
748
749
return NULL;
}
750
751
752
753
754
755
756
757
758
window_view =[[NSView alloc] initWithFrame:contentRect];
[window_view setAutoresizingMask:NSViewWidthSizable |
NSViewHeightSizable];
[[qz_window contentView] addSubview:window_view];
[gl_context setView:window_view];
[window_view release];
[gl_context makeCurrentContext];
[qz_window makeKeyAndOrderFront:nil];
759
current->flags |= SDL_INTERNALOPENGL;
760
}
761
/* For 2D, we set the subview to an NSQuickDrawView */
762
else {
763
short qdbpp = 0;
764
765
766
/* Only recreate the view if it doesn't already exist */
if (window_view == nil) {
767
768
769
770
771
772
773
window_view =[[NSQuickDrawView alloc] initWithFrame:contentRect];
[window_view setAutoresizingMask:NSViewWidthSizable |
NSViewHeightSizable];
[[qz_window contentView] addSubview:window_view];
[window_view release];
[qz_window makeKeyAndOrderFront:nil];
774
}
775
776
777
778
779
780
781
782
LockPortBits ([window_view qdPort]);
current->pixels =
GetPixBaseAddr (GetPortPixMap ([window_view qdPort]));
current->pitch =
GetPixRowBytes (GetPortPixMap ([window_view qdPort]));
qdbpp = GetPixDepth (GetPortPixMap ([window_view qdPort]));
UnlockPortBits ([window_view qdPort]);
783
784
785
786
/* QuickDraw may give a 16-bit shadow surface on 8-bit displays! */
*bpp = qdbpp;
787
788
current->flags |= SDL_SWSURFACE;
current->flags |= SDL_PREALLOC;
789
current->flags |= SDL_ASYNCBLIT;
790
791
/*
792
793
794
795
796
797
798
799
800
801
802
803
current->pixels now points to the window's pixels
We want it to point to the *view's* pixels
*/
{
int vOffset =[qz_window frame].size.height -
[window_view frame].size.height -[window_view frame].origin.y;
int hOffset =[window_view frame].origin.x;
current->pixels =
(Uint8 *) current->pixels + (vOffset * current->pitch) +
hOffset * (qdbpp / 8);
804
}
805
806
this->UpdateRects = QZ_UpdateRects;
this->LockHWSurface = QZ_LockWindow;
807
this->UnlockHWSurface = QZ_UnlockWindow;
808
}
809
810
811
/* Save flags to ensure correct teardown */
mode_flags = current->flags;
812
813
814
/* Fade in again (asynchronously) if we came from a fullscreen mode and faded to black */
if (fade_token != kCGDisplayFadeReservationInvalidToken) {
815
816
CGDisplayFade (fade_token, 0.5, kCGDisplayBlendSolidColor,
kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE);
817
818
819
CGReleaseDisplayFadeReservation (fade_token);
}
820
821
822
return current;
}
823
824
825
826
static SDL_Surface *
QZ_SetVideoMode (_THIS, SDL_Surface * current, int width,
int height, int bpp, Uint32 flags)
{
827
828
current->flags = 0;
829
current->pixels = NULL;
830
831
/* Setup full screen video */
832
833
834
if (flags & SDL_FULLSCREEN) {
current =
QZ_SetVideoFullScreen (this, current, width, height, bpp, flags);
835
836
837
838
839
840
if (current == NULL)
return NULL;
}
/* Setup windowed video */
else {
/* Force bpp to the device's bpp */
841
bpp = device_bpp;
842
843
current =
QZ_SetVideoWindowed (this, current, width, height, &bpp, flags);
844
845
846
if (current == NULL)
return NULL;
}
847
848
849
/* Setup the new pixel format */
{
850
int amask = 0, rmask = 0, gmask = 0, bmask = 0;
851
852
switch (bpp) {
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
case 16: /* (1)-5-5-5 RGB */
amask = 0;
rmask = 0x7C00;
gmask = 0x03E0;
bmask = 0x001F;
break;
case 24:
SDL_SetError ("24bpp is not available");
return NULL;
case 32: /* (8)-8-8-8 ARGB */
amask = 0x00000000;
rmask = 0x00FF0000;
gmask = 0x0000FF00;
bmask = 0x000000FF;
break;
868
}
869
870
if (!SDL_ReallocFormat (current, bpp, rmask, gmask, bmask, amask)) {
871
872
SDL_SetError ("Couldn't reallocate pixel format");
return NULL;
873
}
874
}
875
876
/* Signal successful completion (used internally) */
877
video_set = SDL_TRUE;
878
879
880
881
return current;
}
882
883
884
static int
QZ_ToggleFullScreen (_THIS, int on)
{
885
return 0;
886
887
}
888
889
890
static int
QZ_SetColors (_THIS, int first_color, int num_colors, SDL_Color * colors)
{
891
892
CGTableCount index;
893
CGDeviceColor color;
894
895
for (index = first_color; index < first_color + num_colors; index++) {
896
897
/* Clamp colors between 0.0 and 1.0 */
898
899
color.red = colors->r / 255.0;
color.blue = colors->b / 255.0;
900
color.green = colors->g / 255.0;
901
902
colors++;
903
904
905
CGPaletteSetColorAtIndex (palette, color, index);
}
906
907
if (CGDisplayNoErr != CGDisplaySetPalette (display_id, palette))
908
return 0;
909
910
911
912
return 1;
}
913
914
915
static int
QZ_LockDoubleBuffer (_THIS, SDL_Surface * surface)
{
916
917
918
919
return 1;
}
920
921
922
static void
QZ_UnlockDoubleBuffer (_THIS, SDL_Surface * surface)
{
923
924
925
926
}
/* The VBL delay is based on code by Ian R Ollmann's RezLib <iano@cco.caltech.edu> */
927
928
929
930
static AbsoluteTime
QZ_SecondsToAbsolute (double seconds)
{
931
932
union
{
933
UInt64 i;
934
935
Nanoseconds ns;
} temp;
936
937
temp.i = seconds * 1000000000.0;
938
939
return NanosecondsToAbsolute (temp.ns);
940
941
}
942
943
944
static int
QZ_ThreadFlip (_THIS)
{
945
946
947
Uint8 *src, *dst;
int skip, len, h;
948
949
/*
950
951
952
Give this thread the highest scheduling priority possible,
in the hopes that it will immediately run after the VBL delay
*/
953
954
955
956
{
pthread_t current_thread;
int policy;
struct sched_param param;
957
958
959
960
961
962
963
current_thread = pthread_self ();
pthread_getschedparam (current_thread, &policy, ¶m);
policy = SCHED_RR;
param.sched_priority = sched_get_priority_max (policy);
pthread_setschedparam (current_thread, policy, ¶m);
}
964
965
while (1) {
966
967
968
969
SDL_SemWait (sem1);
if (quit_thread)
return 0;
970
971
972
973
974
975
976
/*
* We have to add SDL_VideoSurface->offset here, since we might be a
* smaller surface in the center of the framebuffer (you asked for
* a fullscreen resolution smaller than the hardware could supply
* so SDL is centering it in a bigger resolution)...
*/
977
978
979
dst =
(Uint8 *) CGDisplayBaseAddress (display_id) +
SDL_VideoSurface->offset;
980
src = current_buffer + SDL_VideoSurface->offset;
981
982
983
len = SDL_VideoSurface->w * SDL_VideoSurface->format->BytesPerPixel;
h = SDL_VideoSurface->h;
skip = SDL_VideoSurface->pitch;
984
985
986
/* Wait for the VBL to occur (estimated since we don't have a hardware interrupt) */
{
987
988
989
990
991
992
993
/* The VBL delay is based on Ian Ollmann's RezLib <iano@cco.caltech.edu> */
double refreshRate;
double linesPerSecond;
double target;
double position;
double adjustment;
994
AbsoluteTime nextTime;
995
CFNumberRef refreshRateCFNumber;
996
997
998
999
refreshRateCFNumber =
CFDictionaryGetValue (mode, kCGDisplayRefreshRate);
if (NULL == refreshRateCFNumber) {
1000
SDL_SetError ("Mode has no refresh rate");