slouken@47
|
1 |
/*
|
slouken@47
|
2 |
SDL - Simple DirectMedia Layer
|
slouken@761
|
3 |
Copyright (C) 1997-2003 Sam Lantinga
|
slouken@47
|
4 |
|
slouken@47
|
5 |
This library is free software; you can redistribute it and/or
|
slouken@47
|
6 |
modify it under the terms of the GNU Library General Public
|
slouken@47
|
7 |
License as published by the Free Software Foundation; either
|
slouken@47
|
8 |
version 2 of the License, or (at your option) any later version.
|
slouken@47
|
9 |
|
slouken@47
|
10 |
This library is distributed in the hope that it will be useful,
|
slouken@47
|
11 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
slouken@47
|
12 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
slouken@47
|
13 |
Library General Public License for more details.
|
slouken@47
|
14 |
|
slouken@47
|
15 |
You should have received a copy of the GNU Library General Public
|
slouken@47
|
16 |
License along with this library; if not, write to the Free
|
slouken@47
|
17 |
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
slouken@47
|
18 |
|
slouken@47
|
19 |
Sam Lantinga
|
slouken@252
|
20 |
slouken@libsdl.org
|
slouken@47
|
21 |
*/
|
slouken@47
|
22 |
|
slouken@47
|
23 |
#include "SDL_QuartzVideo.h"
|
slouken@761
|
24 |
#include "SDL_QuartzWindow.h"
|
slouken@47
|
25 |
|
slouken@761
|
26 |
|
slouken@761
|
27 |
/*
|
slouken@761
|
28 |
Add methods to get at private members of NSScreen.
|
slouken@761
|
29 |
Since there is a bug in Apple's screen switching code
|
slouken@761
|
30 |
that does not update this variable when switching
|
slouken@761
|
31 |
to fullscreen, we'll set it manually (but only for the
|
slouken@761
|
32 |
main screen).
|
slouken@761
|
33 |
*/
|
slouken@761
|
34 |
@interface NSScreen (NSScreenAccess)
|
slouken@761
|
35 |
- (void) setFrame:(NSRect)frame;
|
slouken@761
|
36 |
@end
|
slouken@761
|
37 |
|
slouken@761
|
38 |
@implementation NSScreen (NSScreenAccess)
|
slouken@761
|
39 |
- (void) setFrame:(NSRect)frame;
|
slouken@761
|
40 |
{
|
slouken@761
|
41 |
_frame = frame;
|
slouken@761
|
42 |
}
|
slouken@761
|
43 |
@end
|
slouken@761
|
44 |
|
slouken@761
|
45 |
|
slouken@761
|
46 |
/*
|
slouken@761
|
47 |
Structure for rez switch gamma fades
|
slouken@761
|
48 |
We can hide the monitor flicker by setting the gamma tables to 0
|
slouken@761
|
49 |
*/
|
slouken@761
|
50 |
#define QZ_GAMMA_TABLE_SIZE 256
|
slouken@761
|
51 |
|
slouken@761
|
52 |
typedef struct {
|
slouken@761
|
53 |
|
slouken@761
|
54 |
CGGammaValue red[QZ_GAMMA_TABLE_SIZE];
|
slouken@761
|
55 |
CGGammaValue green[QZ_GAMMA_TABLE_SIZE];
|
slouken@761
|
56 |
CGGammaValue blue[QZ_GAMMA_TABLE_SIZE];
|
slouken@761
|
57 |
|
slouken@761
|
58 |
} SDL_QuartzGammaTable;
|
slouken@761
|
59 |
|
slouken@761
|
60 |
|
slouken@761
|
61 |
/* Bootstrap functions */
|
slouken@761
|
62 |
static int QZ_Available ();
|
slouken@761
|
63 |
static SDL_VideoDevice* QZ_CreateDevice (int device_index);
|
slouken@761
|
64 |
static void QZ_DeleteDevice (SDL_VideoDevice *device);
|
slouken@761
|
65 |
|
slouken@761
|
66 |
/* Initialization, Query, Setup, and Redrawing functions */
|
slouken@761
|
67 |
static int QZ_VideoInit (_THIS, SDL_PixelFormat *video_format);
|
slouken@761
|
68 |
|
slouken@761
|
69 |
static SDL_Rect** QZ_ListModes (_THIS, SDL_PixelFormat *format,
|
slouken@761
|
70 |
Uint32 flags);
|
slouken@761
|
71 |
static void QZ_UnsetVideoMode (_THIS);
|
slouken@761
|
72 |
|
slouken@761
|
73 |
static SDL_Surface* QZ_SetVideoMode (_THIS, SDL_Surface *current,
|
slouken@761
|
74 |
int width, int height, int bpp,
|
slouken@761
|
75 |
Uint32 flags);
|
slouken@761
|
76 |
static int QZ_ToggleFullScreen (_THIS, int on);
|
slouken@761
|
77 |
static int QZ_SetColors (_THIS, int first_color,
|
slouken@761
|
78 |
int num_colors, SDL_Color *colors);
|
slouken@761
|
79 |
|
slouken@761
|
80 |
static int QZ_LockDoubleBuffer (_THIS, SDL_Surface *surface);
|
slouken@761
|
81 |
static void QZ_UnlockDoubleBuffer (_THIS, SDL_Surface *surface);
|
slouken@761
|
82 |
static int QZ_ThreadFlip (_THIS);
|
slouken@761
|
83 |
static int QZ_FlipDoubleBuffer (_THIS, SDL_Surface *surface);
|
slouken@761
|
84 |
static void QZ_DoubleBufferUpdate (_THIS, int num_rects, SDL_Rect *rects);
|
slouken@761
|
85 |
|
slouken@761
|
86 |
static void QZ_DirectUpdate (_THIS, int num_rects, SDL_Rect *rects);
|
slouken@761
|
87 |
static int QZ_LockWindow (_THIS, SDL_Surface *surface);
|
slouken@761
|
88 |
static void QZ_UnlockWindow (_THIS, SDL_Surface *surface);
|
slouken@761
|
89 |
static void QZ_UpdateRects (_THIS, int num_rects, SDL_Rect *rects);
|
slouken@761
|
90 |
static void QZ_VideoQuit (_THIS);
|
slouken@761
|
91 |
|
slouken@761
|
92 |
/* Hardware surface functions (for fullscreen mode only) */
|
slouken@761
|
93 |
#if 0 /* Not used (apparently, it's really slow) */
|
slouken@761
|
94 |
static int QZ_FillHWRect (_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color);
|
slouken@761
|
95 |
#endif
|
slouken@761
|
96 |
static int QZ_LockHWSurface(_THIS, SDL_Surface *surface);
|
slouken@761
|
97 |
static void QZ_UnlockHWSurface(_THIS, SDL_Surface *surface);
|
slouken@761
|
98 |
static void QZ_FreeHWSurface (_THIS, SDL_Surface *surface);
|
slouken@761
|
99 |
/* static int QZ_FlipHWSurface (_THIS, SDL_Surface *surface); */
|
slouken@47
|
100 |
|
slouken@47
|
101 |
/* Bootstrap binding, enables entry point into the driver */
|
slouken@47
|
102 |
VideoBootStrap QZ_bootstrap = {
|
slouken@272
|
103 |
"Quartz", "Mac OS X CoreGraphics", QZ_Available, QZ_CreateDevice
|
slouken@47
|
104 |
};
|
slouken@47
|
105 |
|
slouken@588
|
106 |
|
slouken@47
|
107 |
/* Bootstrap functions */
|
slouken@47
|
108 |
static int QZ_Available () {
|
slouken@47
|
109 |
return 1;
|
slouken@47
|
110 |
}
|
slouken@47
|
111 |
|
slouken@47
|
112 |
static SDL_VideoDevice* QZ_CreateDevice (int device_index) {
|
slouken@47
|
113 |
|
slouken@272
|
114 |
#pragma unused (device_index)
|
slouken@47
|
115 |
|
slouken@47
|
116 |
SDL_VideoDevice *device;
|
slouken@47
|
117 |
SDL_PrivateVideoData *hidden;
|
slouken@47
|
118 |
|
slouken@47
|
119 |
device = (SDL_VideoDevice*) malloc (sizeof (*device) );
|
slouken@47
|
120 |
hidden = (SDL_PrivateVideoData*) malloc (sizeof (*hidden) );
|
slouken@47
|
121 |
|
slouken@47
|
122 |
if (device == NULL || hidden == NULL)
|
slouken@47
|
123 |
SDL_OutOfMemory ();
|
slouken@47
|
124 |
|
slouken@47
|
125 |
memset (device, 0, sizeof (*device) );
|
slouken@47
|
126 |
memset (hidden, 0, sizeof (*hidden) );
|
slouken@272
|
127 |
|
slouken@47
|
128 |
device->hidden = hidden;
|
slouken@47
|
129 |
|
slouken@47
|
130 |
device->VideoInit = QZ_VideoInit;
|
slouken@47
|
131 |
device->ListModes = QZ_ListModes;
|
slouken@47
|
132 |
device->SetVideoMode = QZ_SetVideoMode;
|
slouken@47
|
133 |
device->ToggleFullScreen = QZ_ToggleFullScreen;
|
slouken@47
|
134 |
device->SetColors = QZ_SetColors;
|
slouken@47
|
135 |
/* device->UpdateRects = QZ_UpdateRects; this is determined by SetVideoMode() */
|
slouken@47
|
136 |
device->VideoQuit = QZ_VideoQuit;
|
slouken@272
|
137 |
|
slouken@47
|
138 |
device->LockHWSurface = QZ_LockHWSurface;
|
slouken@47
|
139 |
device->UnlockHWSurface = QZ_UnlockHWSurface;
|
slouken@47
|
140 |
device->FreeHWSurface = QZ_FreeHWSurface;
|
slouken@47
|
141 |
/* device->FlipHWSurface = QZ_FlipHWSurface */;
|
slouken@47
|
142 |
|
slouken@47
|
143 |
device->SetGamma = QZ_SetGamma;
|
slouken@47
|
144 |
device->GetGamma = QZ_GetGamma;
|
slouken@47
|
145 |
device->SetGammaRamp = QZ_SetGammaRamp;
|
slouken@47
|
146 |
device->GetGammaRamp = QZ_GetGammaRamp;
|
slouken@47
|
147 |
|
slouken@47
|
148 |
device->GL_GetProcAddress = QZ_GL_GetProcAddress;
|
slouken@47
|
149 |
device->GL_GetAttribute = QZ_GL_GetAttribute;
|
slouken@47
|
150 |
device->GL_MakeCurrent = QZ_GL_MakeCurrent;
|
slouken@47
|
151 |
device->GL_SwapBuffers = QZ_GL_SwapBuffers;
|
slouken@47
|
152 |
device->GL_LoadLibrary = QZ_GL_LoadLibrary;
|
slouken@272
|
153 |
|
slouken@47
|
154 |
device->FreeWMCursor = QZ_FreeWMCursor;
|
slouken@47
|
155 |
device->CreateWMCursor = QZ_CreateWMCursor;
|
slouken@47
|
156 |
device->ShowWMCursor = QZ_ShowWMCursor;
|
slouken@47
|
157 |
device->WarpWMCursor = QZ_WarpWMCursor;
|
slouken@47
|
158 |
device->MoveWMCursor = QZ_MoveWMCursor;
|
slouken@47
|
159 |
device->CheckMouseMode = QZ_CheckMouseMode;
|
slouken@47
|
160 |
device->InitOSKeymap = QZ_InitOSKeymap;
|
slouken@47
|
161 |
device->PumpEvents = QZ_PumpEvents;
|
slouken@47
|
162 |
|
slouken@47
|
163 |
device->SetCaption = QZ_SetCaption;
|
slouken@47
|
164 |
device->SetIcon = QZ_SetIcon;
|
slouken@47
|
165 |
device->IconifyWindow = QZ_IconifyWindow;
|
slouken@47
|
166 |
/*device->GetWMInfo = QZ_GetWMInfo;*/
|
slouken@47
|
167 |
device->GrabInput = QZ_GrabInput;
|
slouken@272
|
168 |
|
slouken@390
|
169 |
device->CreateYUVOverlay = QZ_CreateYUVOverlay;
|
slouken@390
|
170 |
|
slouken@390
|
171 |
device->free = QZ_DeleteDevice;
|
slouken@272
|
172 |
|
slouken@47
|
173 |
return device;
|
slouken@47
|
174 |
}
|
slouken@47
|
175 |
|
slouken@47
|
176 |
static void QZ_DeleteDevice (SDL_VideoDevice *device) {
|
slouken@47
|
177 |
|
slouken@47
|
178 |
free (device->hidden);
|
slouken@47
|
179 |
free (device);
|
slouken@47
|
180 |
}
|
slouken@47
|
181 |
|
slouken@47
|
182 |
static int QZ_VideoInit (_THIS, SDL_PixelFormat *video_format) {
|
slouken@47
|
183 |
|
slouken@272
|
184 |
/* Initialize the video settings; this data persists between mode switches */
|
slouken@272
|
185 |
display_id = kCGDirectMainDisplay;
|
slouken@272
|
186 |
save_mode = CGDisplayCurrentMode (display_id);
|
slouken@272
|
187 |
mode_list = CGDisplayAvailableModes (display_id);
|
slouken@272
|
188 |
palette = CGPaletteCreateDefaultColorPalette ();
|
slouken@272
|
189 |
|
slouken@272
|
190 |
/* Gather some information that is useful to know about the display */
|
slouken@272
|
191 |
CFNumberGetValue (CFDictionaryGetValue (save_mode, kCGDisplayBitsPerPixel),
|
slouken@272
|
192 |
kCFNumberSInt32Type, &device_bpp);
|
slouken@47
|
193 |
|
slouken@272
|
194 |
CFNumberGetValue (CFDictionaryGetValue (save_mode, kCGDisplayWidth),
|
slouken@272
|
195 |
kCFNumberSInt32Type, &device_width);
|
slouken@47
|
196 |
|
slouken@272
|
197 |
CFNumberGetValue (CFDictionaryGetValue (save_mode, kCGDisplayHeight),
|
slouken@272
|
198 |
kCFNumberSInt32Type, &device_height);
|
slouken@272
|
199 |
|
slouken@272
|
200 |
video_format->BitsPerPixel = device_bpp;
|
slouken@272
|
201 |
|
slouken@501
|
202 |
/* Set misc globals */
|
slouken@501
|
203 |
current_grab_mode = SDL_GRAB_OFF;
|
slouken@761
|
204 |
cursor_should_be_visible = YES;
|
slouken@779
|
205 |
cursor_visible = YES;
|
slouken@823
|
206 |
current_mods = 0;
|
slouken@501
|
207 |
|
icculus@876
|
208 |
if ( Gestalt(gestaltSystemVersion, &system_version) != noErr )
|
icculus@876
|
209 |
system_version = 0;
|
slouken@934
|
210 |
|
slouken@555
|
211 |
/* register for sleep notifications so wake from sleep generates SDL_VIDEOEXPOSE */
|
slouken@555
|
212 |
QZ_RegisterForSleepNotifications (this);
|
slouken@555
|
213 |
|
slouken@272
|
214 |
return 0;
|
slouken@47
|
215 |
}
|
slouken@47
|
216 |
|
slouken@47
|
217 |
static SDL_Rect** QZ_ListModes (_THIS, SDL_PixelFormat *format, Uint32 flags) {
|
slouken@390
|
218 |
|
slouken@272
|
219 |
CFIndex num_modes;
|
slouken@47
|
220 |
CFIndex i;
|
slouken@47
|
221 |
|
slouken@47
|
222 |
int list_size = 0;
|
slouken@390
|
223 |
|
slouken@47
|
224 |
/* Any windowed mode is acceptable */
|
slouken@47
|
225 |
if ( (flags & SDL_FULLSCREEN) == 0 )
|
slouken@47
|
226 |
return (SDL_Rect**)-1;
|
slouken@390
|
227 |
|
slouken@47
|
228 |
/* Free memory from previous call, if any */
|
slouken@501
|
229 |
if ( client_mode_list != NULL ) {
|
slouken@47
|
230 |
|
slouken@390
|
231 |
int i;
|
slouken@47
|
232 |
|
slouken@501
|
233 |
for (i = 0; client_mode_list[i] != NULL; i++)
|
slouken@501
|
234 |
free (client_mode_list[i]);
|
slouken@47
|
235 |
|
slouken@501
|
236 |
free (client_mode_list);
|
slouken@501
|
237 |
client_mode_list = NULL;
|
slouken@47
|
238 |
}
|
slouken@390
|
239 |
|
slouken@272
|
240 |
num_modes = CFArrayGetCount (mode_list);
|
slouken@272
|
241 |
|
slouken@47
|
242 |
/* Build list of modes with the requested bpp */
|
slouken@155
|
243 |
for (i = 0; i < num_modes; i++) {
|
slouken@390
|
244 |
|
slouken@155
|
245 |
CFDictionaryRef onemode;
|
slouken@155
|
246 |
CFNumberRef number;
|
slouken@390
|
247 |
int bpp;
|
slouken@390
|
248 |
|
slouken@390
|
249 |
onemode = CFArrayGetValueAtIndex (mode_list, i);
|
slouken@390
|
250 |
number = CFDictionaryGetValue (onemode, kCGDisplayBitsPerPixel);
|
slouken@390
|
251 |
CFNumberGetValue (number, kCFNumberSInt32Type, &bpp);
|
slouken@390
|
252 |
|
slouken@390
|
253 |
if (bpp == format->BitsPerPixel) {
|
slouken@390
|
254 |
|
slouken@390
|
255 |
int intvalue;
|
slouken@390
|
256 |
int hasMode;
|
slouken@390
|
257 |
int width, height;
|
slouken@47
|
258 |
|
slouken@390
|
259 |
number = CFDictionaryGetValue (onemode, kCGDisplayWidth);
|
slouken@390
|
260 |
CFNumberGetValue (number, kCFNumberSInt32Type, &intvalue);
|
slouken@390
|
261 |
width = (Uint16) intvalue;
|
slouken@390
|
262 |
|
slouken@390
|
263 |
number = CFDictionaryGetValue (onemode, kCGDisplayHeight);
|
slouken@390
|
264 |
CFNumberGetValue (number, kCFNumberSInt32Type, &intvalue);
|
slouken@390
|
265 |
height = (Uint16) intvalue;
|
slouken@390
|
266 |
|
slouken@390
|
267 |
/* Check if mode is already in the list */
|
slouken@390
|
268 |
{
|
slouken@390
|
269 |
int i;
|
slouken@390
|
270 |
hasMode = SDL_FALSE;
|
slouken@390
|
271 |
for (i = 0; i < list_size; i++) {
|
slouken@501
|
272 |
if (client_mode_list[i]->w == width &&
|
slouken@501
|
273 |
client_mode_list[i]->h == height) {
|
slouken@390
|
274 |
hasMode = SDL_TRUE;
|
slouken@390
|
275 |
break;
|
slouken@390
|
276 |
}
|
slouken@155
|
277 |
}
|
slouken@155
|
278 |
}
|
slouken@390
|
279 |
|
slouken@390
|
280 |
/* Grow the list and add mode to the list */
|
slouken@390
|
281 |
if ( ! hasMode ) {
|
slouken@390
|
282 |
|
slouken@390
|
283 |
SDL_Rect *rect;
|
slouken@390
|
284 |
|
slouken@390
|
285 |
list_size++;
|
slouken@390
|
286 |
|
slouken@501
|
287 |
if (client_mode_list == NULL)
|
slouken@501
|
288 |
client_mode_list = (SDL_Rect**)
|
slouken@501
|
289 |
malloc (sizeof(*client_mode_list) * (list_size+1) );
|
slouken@390
|
290 |
else
|
slouken@501
|
291 |
client_mode_list = (SDL_Rect**)
|
slouken@501
|
292 |
realloc (client_mode_list, sizeof(*client_mode_list) * (list_size+1));
|
slouken@390
|
293 |
|
slouken@501
|
294 |
rect = (SDL_Rect*) malloc (sizeof(**client_mode_list));
|
slouken@47
|
295 |
|
slouken@501
|
296 |
if (client_mode_list == NULL || rect == NULL) {
|
slouken@390
|
297 |
SDL_OutOfMemory ();
|
slouken@390
|
298 |
return NULL;
|
slouken@390
|
299 |
}
|
slouken@390
|
300 |
|
slouken@390
|
301 |
rect->w = width;
|
slouken@390
|
302 |
rect->h = height;
|
slouken@390
|
303 |
|
slouken@501
|
304 |
client_mode_list[list_size-1] = rect;
|
slouken@501
|
305 |
client_mode_list[list_size] = NULL;
|
slouken@272
|
306 |
}
|
slouken@47
|
307 |
}
|
slouken@47
|
308 |
}
|
slouken@390
|
309 |
|
slouken@155
|
310 |
/* Sort list largest to smallest (by area) */
|
slouken@155
|
311 |
{
|
slouken@155
|
312 |
int i, j;
|
slouken@155
|
313 |
for (i = 0; i < list_size; i++) {
|
slouken@155
|
314 |
for (j = 0; j < list_size-1; j++) {
|
slouken@390
|
315 |
|
slouken@155
|
316 |
int area1, area2;
|
slouken@501
|
317 |
area1 = client_mode_list[j]->w * client_mode_list[j]->h;
|
slouken@501
|
318 |
area2 = client_mode_list[j+1]->w * client_mode_list[j+1]->h;
|
slouken@390
|
319 |
|
slouken@155
|
320 |
if (area1 < area2) {
|
slouken@501
|
321 |
SDL_Rect *tmp = client_mode_list[j];
|
slouken@501
|
322 |
client_mode_list[j] = client_mode_list[j+1];
|
slouken@501
|
323 |
client_mode_list[j+1] = tmp;
|
slouken@155
|
324 |
}
|
slouken@155
|
325 |
}
|
slouken@155
|
326 |
}
|
slouken@155
|
327 |
}
|
slouken@501
|
328 |
return client_mode_list;
|
slouken@47
|
329 |
}
|
slouken@47
|
330 |
|
slouken@657
|
331 |
static SDL_bool QZ_WindowPosition(_THIS, int *x, int *y)
|
slouken@657
|
332 |
{
|
slouken@657
|
333 |
const char *window = getenv("SDL_VIDEO_WINDOW_POS");
|
slouken@657
|
334 |
if ( window ) {
|
slouken@657
|
335 |
if ( sscanf(window, "%d,%d", x, y) == 2 ) {
|
slouken@657
|
336 |
return SDL_TRUE;
|
slouken@657
|
337 |
}
|
slouken@657
|
338 |
}
|
slouken@657
|
339 |
return SDL_FALSE;
|
slouken@657
|
340 |
}
|
slouken@657
|
341 |
|
slouken@501
|
342 |
/*
|
slouken@501
|
343 |
Gamma functions to try to hide the flash from a rez switch
|
slouken@501
|
344 |
Fade the display from normal to black
|
slouken@501
|
345 |
Save gamma tables for fade back to normal
|
slouken@501
|
346 |
*/
|
slouken@272
|
347 |
static UInt32 QZ_FadeGammaOut (_THIS, SDL_QuartzGammaTable *table) {
|
slouken@272
|
348 |
|
slouken@272
|
349 |
CGGammaValue redTable[QZ_GAMMA_TABLE_SIZE],
|
slouken@272
|
350 |
greenTable[QZ_GAMMA_TABLE_SIZE],
|
slouken@272
|
351 |
blueTable[QZ_GAMMA_TABLE_SIZE];
|
slouken@272
|
352 |
|
slouken@272
|
353 |
float percent;
|
slouken@272
|
354 |
int j;
|
slouken@272
|
355 |
int actual;
|
slouken@272
|
356 |
|
slouken@272
|
357 |
if ( (CGDisplayNoErr != CGGetDisplayTransferByTable
|
slouken@272
|
358 |
(display_id, QZ_GAMMA_TABLE_SIZE,
|
slouken@272
|
359 |
table->red, table->green, table->blue, &actual)) ||
|
slouken@272
|
360 |
actual != QZ_GAMMA_TABLE_SIZE) {
|
slouken@272
|
361 |
|
slouken@272
|
362 |
return 1;
|
slouken@272
|
363 |
}
|
slouken@272
|
364 |
|
slouken@272
|
365 |
memcpy (redTable, table->red, sizeof(redTable));
|
slouken@272
|
366 |
memcpy (greenTable, table->green, sizeof(greenTable));
|
slouken@272
|
367 |
memcpy (blueTable, table->blue, sizeof(greenTable));
|
slouken@272
|
368 |
|
slouken@272
|
369 |
for (percent = 1.0; percent >= 0.0; percent -= 0.01) {
|
slouken@272
|
370 |
|
slouken@272
|
371 |
for (j = 0; j < QZ_GAMMA_TABLE_SIZE; j++) {
|
slouken@272
|
372 |
|
slouken@272
|
373 |
redTable[j] = redTable[j] * percent;
|
slouken@272
|
374 |
greenTable[j] = greenTable[j] * percent;
|
slouken@272
|
375 |
blueTable[j] = blueTable[j] * percent;
|
slouken@272
|
376 |
}
|
slouken@272
|
377 |
|
slouken@272
|
378 |
if (CGDisplayNoErr != CGSetDisplayTransferByTable
|
slouken@272
|
379 |
(display_id, QZ_GAMMA_TABLE_SIZE,
|
slouken@272
|
380 |
redTable, greenTable, blueTable)) {
|
slouken@272
|
381 |
|
slouken@272
|
382 |
CGDisplayRestoreColorSyncSettings();
|
slouken@272
|
383 |
return 1;
|
slouken@272
|
384 |
}
|
slouken@272
|
385 |
|
slouken@272
|
386 |
SDL_Delay (10);
|
slouken@272
|
387 |
}
|
slouken@272
|
388 |
|
slouken@272
|
389 |
return 0;
|
slouken@272
|
390 |
}
|
slouken@272
|
391 |
|
slouken@501
|
392 |
/*
|
slouken@501
|
393 |
Fade the display from black to normal
|
slouken@501
|
394 |
Restore previously saved gamma values
|
slouken@501
|
395 |
*/
|
slouken@272
|
396 |
static UInt32 QZ_FadeGammaIn (_THIS, SDL_QuartzGammaTable *table) {
|
slouken@272
|
397 |
|
slouken@272
|
398 |
CGGammaValue redTable[QZ_GAMMA_TABLE_SIZE],
|
slouken@390
|
399 |
greenTable[QZ_GAMMA_TABLE_SIZE],
|
slouken@390
|
400 |
blueTable[QZ_GAMMA_TABLE_SIZE];
|
slouken@272
|
401 |
|
slouken@272
|
402 |
float percent;
|
slouken@272
|
403 |
int j;
|
slouken@272
|
404 |
|
slouken@272
|
405 |
memset (redTable, 0, sizeof(redTable));
|
slouken@272
|
406 |
memset (greenTable, 0, sizeof(greenTable));
|
slouken@272
|
407 |
memset (blueTable, 0, sizeof(greenTable));
|
slouken@390
|
408 |
|
slouken@272
|
409 |
for (percent = 0.0; percent <= 1.0; percent += 0.01) {
|
slouken@272
|
410 |
|
slouken@272
|
411 |
for (j = 0; j < QZ_GAMMA_TABLE_SIZE; j++) {
|
slouken@272
|
412 |
|
slouken@272
|
413 |
redTable[j] = table->red[j] * percent;
|
slouken@272
|
414 |
greenTable[j] = table->green[j] * percent;
|
slouken@272
|
415 |
blueTable[j] = table->blue[j] * percent;
|
slouken@272
|
416 |
}
|
slouken@272
|
417 |
|
slouken@272
|
418 |
if (CGDisplayNoErr != CGSetDisplayTransferByTable
|
slouken@272
|
419 |
(display_id, QZ_GAMMA_TABLE_SIZE,
|
slouken@272
|
420 |
redTable, greenTable, blueTable)) {
|
slouken@272
|
421 |
|
slouken@272
|
422 |
CGDisplayRestoreColorSyncSettings();
|
slouken@272
|
423 |
return 1;
|
slouken@272
|
424 |
}
|
slouken@272
|
425 |
|
slouken@272
|
426 |
SDL_Delay (10);
|
slouken@272
|
427 |
}
|
slouken@272
|
428 |
|
slouken@272
|
429 |
return 0;
|
slouken@272
|
430 |
}
|
slouken@272
|
431 |
|
slouken@47
|
432 |
static void QZ_UnsetVideoMode (_THIS) {
|
slouken@47
|
433 |
|
slouken@47
|
434 |
/* Reset values that may change between switches */
|
slouken@501
|
435 |
this->info.blit_fill = 0;
|
slouken@501
|
436 |
this->FillHWRect = NULL;
|
slouken@501
|
437 |
this->UpdateRects = NULL;
|
slouken@501
|
438 |
this->LockHWSurface = NULL;
|
slouken@501
|
439 |
this->UnlockHWSurface = NULL;
|
slouken@501
|
440 |
|
slouken@272
|
441 |
/* Release fullscreen resources */
|
slouken@47
|
442 |
if ( mode_flags & SDL_FULLSCREEN ) {
|
slouken@272
|
443 |
|
slouken@272
|
444 |
SDL_QuartzGammaTable gamma_table;
|
slouken@272
|
445 |
int gamma_error;
|
slouken@435
|
446 |
NSRect screen_rect;
|
slouken@435
|
447 |
|
slouken@272
|
448 |
gamma_error = QZ_FadeGammaOut (this, &gamma_table);
|
slouken@272
|
449 |
|
slouken@588
|
450 |
/* Release double buffer stuff */
|
slouken@588
|
451 |
if ( mode_flags & (SDL_HWSURFACE|SDL_DOUBLEBUF)) {
|
slouken@588
|
452 |
quit_thread = YES;
|
slouken@588
|
453 |
SDL_SemPost (sem1);
|
slouken@588
|
454 |
SDL_WaitThread (thread, NULL);
|
slouken@588
|
455 |
SDL_DestroySemaphore (sem1);
|
slouken@588
|
456 |
SDL_DestroySemaphore (sem2);
|
slouken@588
|
457 |
free (sw_buffers[0]);
|
slouken@588
|
458 |
}
|
slouken@588
|
459 |
|
slouken@501
|
460 |
/*
|
slouken@501
|
461 |
Release the OpenGL context
|
slouken@501
|
462 |
Do this first to avoid trash on the display before fade
|
slouken@501
|
463 |
*/
|
slouken@501
|
464 |
if ( mode_flags & SDL_OPENGL ) {
|
slouken@501
|
465 |
|
slouken@272
|
466 |
QZ_TearDownOpenGL (this);
|
slouken@501
|
467 |
CGLSetFullScreen (NULL);
|
slouken@501
|
468 |
}
|
slouken@501
|
469 |
|
slouken@272
|
470 |
/* Restore original screen resolution/bpp */
|
slouken@47
|
471 |
CGDisplaySwitchToMode (display_id, save_mode);
|
slouken@588
|
472 |
CGReleaseAllDisplays ();
|
slouken@272
|
473 |
ShowMenuBar ();
|
slouken@435
|
474 |
/*
|
slouken@501
|
475 |
Reset the main screen's rectangle
|
slouken@501
|
476 |
See comment in QZ_SetVideoFullscreen for why we do this
|
slouken@435
|
477 |
*/
|
slouken@435
|
478 |
screen_rect = NSMakeRect(0,0,device_width,device_height);
|
slouken@435
|
479 |
[ [ NSScreen mainScreen ] setFrame:screen_rect ];
|
slouken@435
|
480 |
|
slouken@272
|
481 |
if (! gamma_error)
|
slouken@272
|
482 |
QZ_FadeGammaIn (this, &gamma_table);
|
slouken@47
|
483 |
}
|
slouken@272
|
484 |
/* Release window mode resources */
|
slouken@390
|
485 |
else {
|
slouken@501
|
486 |
|
slouken@158
|
487 |
[ qz_window close ];
|
slouken@390
|
488 |
qz_window = nil;
|
slouken@501
|
489 |
window_view = nil;
|
slouken@501
|
490 |
|
slouken@272
|
491 |
/* Release the OpenGL context */
|
slouken@272
|
492 |
if ( mode_flags & SDL_OPENGL )
|
slouken@272
|
493 |
QZ_TearDownOpenGL (this);
|
slouken@47
|
494 |
}
|
slouken@272
|
495 |
|
slouken@155
|
496 |
/* Signal successful teardown */
|
slouken@155
|
497 |
video_set = SDL_FALSE;
|
slouken@47
|
498 |
}
|
slouken@47
|
499 |
|
slouken@47
|
500 |
static SDL_Surface* QZ_SetVideoFullScreen (_THIS, SDL_Surface *current, int width,
|
slouken@47
|
501 |
int height, int bpp, Uint32 flags) {
|
slouken@47
|
502 |
int exact_match;
|
slouken@272
|
503 |
int gamma_error;
|
slouken@272
|
504 |
SDL_QuartzGammaTable gamma_table;
|
slouken@435
|
505 |
NSRect screen_rect;
|
slouken@588
|
506 |
CGError error;
|
slouken@435
|
507 |
|
slouken@501
|
508 |
/* Destroy any previous mode */
|
slouken@501
|
509 |
if (video_set == SDL_TRUE)
|
slouken@501
|
510 |
QZ_UnsetVideoMode (this);
|
slouken@501
|
511 |
|
slouken@47
|
512 |
/* See if requested mode exists */
|
slouken@390
|
513 |
mode = CGDisplayBestModeForParameters (display_id, bpp, width,
|
slouken@390
|
514 |
height, &exact_match);
|
slouken@390
|
515 |
|
slouken@47
|
516 |
/* Require an exact match to the requested mode */
|
slouken@47
|
517 |
if ( ! exact_match ) {
|
slouken@501
|
518 |
SDL_SetError ("Failed to find display resolution: %dx%dx%d", width, height, bpp);
|
slouken@47
|
519 |
goto ERR_NO_MATCH;
|
slouken@47
|
520 |
}
|
slouken@155
|
521 |
|
slouken@272
|
522 |
/* Fade display to zero gamma */
|
slouken@272
|
523 |
gamma_error = QZ_FadeGammaOut (this, &gamma_table);
|
slouken@272
|
524 |
|
slouken@47
|
525 |
/* Put up the blanking window (a window above all other windows) */
|
slouken@588
|
526 |
if (getenv ("SDL_SINGLEDISPLAY"))
|
slouken@588
|
527 |
error = CGDisplayCapture (display_id);
|
slouken@588
|
528 |
else
|
slouken@588
|
529 |
error = CGCaptureAllDisplays ();
|
slouken@588
|
530 |
|
slouken@588
|
531 |
if ( CGDisplayNoErr != error ) {
|
slouken@47
|
532 |
SDL_SetError ("Failed capturing display");
|
slouken@47
|
533 |
goto ERR_NO_CAPTURE;
|
slouken@47
|
534 |
}
|
slouken@272
|
535 |
|
slouken@47
|
536 |
/* Do the physical switch */
|
slouken@47
|
537 |
if ( CGDisplayNoErr != CGDisplaySwitchToMode (display_id, mode) ) {
|
slouken@47
|
538 |
SDL_SetError ("Failed switching display resolution");
|
slouken@47
|
539 |
goto ERR_NO_SWITCH;
|
slouken@47
|
540 |
}
|
slouken@272
|
541 |
|
slouken@47
|
542 |
current->pixels = (Uint32*) CGDisplayBaseAddress (display_id);
|
slouken@47
|
543 |
current->pitch = CGDisplayBytesPerRow (display_id);
|
slouken@47
|
544 |
|
slouken@58
|
545 |
current->flags = 0;
|
slouken@47
|
546 |
current->w = width;
|
slouken@47
|
547 |
current->h = height;
|
slouken@390
|
548 |
current->flags |= SDL_FULLSCREEN;
|
slouken@47
|
549 |
current->flags |= SDL_HWSURFACE;
|
slouken@501
|
550 |
current->flags |= SDL_PREALLOC;
|
slouken@501
|
551 |
|
slouken@501
|
552 |
this->UpdateRects = QZ_DirectUpdate;
|
slouken@501
|
553 |
this->LockHWSurface = QZ_LockHWSurface;
|
slouken@501
|
554 |
this->UnlockHWSurface = QZ_UnlockHWSurface;
|
slouken@588
|
555 |
|
slouken@588
|
556 |
/* Setup double-buffer emulation */
|
slouken@588
|
557 |
if ( flags & SDL_DOUBLEBUF ) {
|
slouken@588
|
558 |
|
slouken@588
|
559 |
/*
|
slouken@588
|
560 |
Setup a software backing store for reasonable results when
|
slouken@588
|
561 |
double buffering is requested (since a single-buffered hardware
|
slouken@588
|
562 |
surface looks hideous).
|
slouken@588
|
563 |
|
slouken@588
|
564 |
The actual screen blit occurs in a separate thread to allow
|
slouken@588
|
565 |
other blitting while waiting on the VBL (and hence results in higher framerates).
|
slouken@588
|
566 |
*/
|
slouken@588
|
567 |
this->LockHWSurface = NULL;
|
slouken@588
|
568 |
this->UnlockHWSurface = NULL;
|
slouken@588
|
569 |
this->UpdateRects = NULL;
|
slouken@588
|
570 |
|
slouken@588
|
571 |
current->flags |= (SDL_HWSURFACE|SDL_DOUBLEBUF);
|
slouken@588
|
572 |
this->UpdateRects = QZ_DoubleBufferUpdate;
|
slouken@588
|
573 |
this->LockHWSurface = QZ_LockDoubleBuffer;
|
slouken@588
|
574 |
this->UnlockHWSurface = QZ_UnlockDoubleBuffer;
|
slouken@588
|
575 |
this->FlipHWSurface = QZ_FlipDoubleBuffer;
|
slouken@588
|
576 |
|
slouken@588
|
577 |
current->pixels = malloc (current->pitch * current->h * 2);
|
slouken@588
|
578 |
if (current->pixels == NULL) {
|
slouken@588
|
579 |
SDL_OutOfMemory ();
|
slouken@588
|
580 |
goto ERR_DOUBLEBUF;
|
slouken@588
|
581 |
}
|
slouken@588
|
582 |
|
slouken@588
|
583 |
sw_buffers[0] = current->pixels;
|
slouken@588
|
584 |
sw_buffers[1] = (Uint8*)current->pixels + current->pitch * current->h;
|
slouken@588
|
585 |
|
slouken@588
|
586 |
quit_thread = NO;
|
slouken@588
|
587 |
sem1 = SDL_CreateSemaphore (0);
|
slouken@588
|
588 |
sem2 = SDL_CreateSemaphore (1);
|
slouken@588
|
589 |
thread = SDL_CreateThread ((int (*)(void *))QZ_ThreadFlip, this);
|
slouken@47
|
590 |
}
|
slouken@390
|
591 |
|
slouken@47
|
592 |
if ( CGDisplayCanSetPalette (display_id) )
|
slouken@47
|
593 |
current->flags |= SDL_HWPALETTE;
|
slouken@390
|
594 |
|
slouken@47
|
595 |
/* Setup OpenGL for a fullscreen context */
|
slouken@47
|
596 |
if (flags & SDL_OPENGL) {
|
slouken@47
|
597 |
|
slouken@47
|
598 |
CGLError err;
|
slouken@47
|
599 |
CGLContextObj ctx;
|
slouken@390
|
600 |
|
slouken@47
|
601 |
if ( ! QZ_SetupOpenGL (this, bpp, flags) ) {
|
slouken@272
|
602 |
goto ERR_NO_GL;
|
slouken@47
|
603 |
}
|
slouken@390
|
604 |
|
slouken@47
|
605 |
ctx = [ gl_context cglContext ];
|
slouken@47
|
606 |
err = CGLSetFullScreen (ctx);
|
slouken@390
|
607 |
|
slouken@47
|
608 |
if (err) {
|
slouken@501
|
609 |
SDL_SetError ("Error setting OpenGL fullscreen: %s", CGLErrorString(err));
|
slouken@47
|
610 |
goto ERR_NO_GL;
|
slouken@47
|
611 |
}
|
slouken@390
|
612 |
|
slouken@47
|
613 |
[ gl_context makeCurrentContext];
|
slouken@272
|
614 |
|
slouken@272
|
615 |
glClear (GL_COLOR_BUFFER_BIT);
|
slouken@272
|
616 |
|
slouken@272
|
617 |
[ gl_context flushBuffer ];
|
slouken@390
|
618 |
|
slouken@47
|
619 |
current->flags |= SDL_OPENGL;
|
slouken@47
|
620 |
}
|
slouken@47
|
621 |
|
slouken@47
|
622 |
/* If we don't hide menu bar, it will get events and interrupt the program */
|
slouken@47
|
623 |
HideMenuBar ();
|
slouken@272
|
624 |
|
slouken@272
|
625 |
/* Fade the display to original gamma */
|
slouken@272
|
626 |
if (! gamma_error )
|
slouken@272
|
627 |
QZ_FadeGammaIn (this, &gamma_table);
|
slouken@390
|
628 |
|
slouken@435
|
629 |
/*
|
slouken@501
|
630 |
There is a bug in Cocoa where NSScreen doesn't synchronize
|
slouken@501
|
631 |
with CGDirectDisplay, so the main screen's frame is wrong.
|
slouken@501
|
632 |
As a result, coordinate translation produces incorrect results.
|
slouken@501
|
633 |
We can hack around this bug by setting the screen rect
|
slouken@501
|
634 |
ourselves. This hack should be removed if/when the bug is fixed.
|
slouken@435
|
635 |
*/
|
slouken@435
|
636 |
screen_rect = NSMakeRect(0,0,width,height);
|
slouken@435
|
637 |
[ [ NSScreen mainScreen ] setFrame:screen_rect ];
|
slouken@435
|
638 |
|
slouken@47
|
639 |
/* Save the flags to ensure correct tear-down */
|
slouken@47
|
640 |
mode_flags = current->flags;
|
slouken@390
|
641 |
|
icculus@1119
|
642 |
/* we're fullscreen, so flag all input states... */
|
icculus@1119
|
643 |
SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS | SDL_APPINPUTFOCUS | SDL_APPACTIVE);
|
icculus@1119
|
644 |
|
slouken@47
|
645 |
return current;
|
slouken@47
|
646 |
|
slouken@390
|
647 |
/* Since the blanking window covers *all* windows (even force quit) correct recovery is crucial */
|
slouken@588
|
648 |
ERR_NO_GL:
|
slouken@588
|
649 |
ERR_DOUBLEBUF: CGDisplaySwitchToMode (display_id, save_mode);
|
slouken@588
|
650 |
ERR_NO_SWITCH: CGReleaseAllDisplays ();
|
slouken@390
|
651 |
ERR_NO_CAPTURE: if (!gamma_error) { QZ_FadeGammaIn (this, &gamma_table); }
|
slouken@588
|
652 |
ERR_NO_MATCH: return NULL;
|
slouken@47
|
653 |
}
|
slouken@47
|
654 |
|
slouken@47
|
655 |
static SDL_Surface* QZ_SetVideoWindowed (_THIS, SDL_Surface *current, int width,
|
slouken@390
|
656 |
int height, int bpp, Uint32 flags) {
|
slouken@58
|
657 |
unsigned int style;
|
slouken@501
|
658 |
NSRect contentRect;
|
slouken@683
|
659 |
BOOL isCustom = NO;
|
slouken@657
|
660 |
int center_window = 1;
|
slouken@657
|
661 |
int origin_x, origin_y;
|
slouken@390
|
662 |
|
slouken@58
|
663 |
current->flags = 0;
|
slouken@58
|
664 |
current->w = width;
|
slouken@47
|
665 |
current->h = height;
|
slouken@501
|
666 |
|
slouken@501
|
667 |
contentRect = NSMakeRect (0, 0, width, height);
|
slouken@501
|
668 |
|
slouken@501
|
669 |
/*
|
slouken@501
|
670 |
Check if we should completely destroy the previous mode
|
slouken@501
|
671 |
- If it is fullscreen
|
slouken@501
|
672 |
- If it has different noframe or resizable attribute
|
slouken@501
|
673 |
- If it is OpenGL (since gl attributes could be different)
|
slouken@501
|
674 |
- If new mode is OpenGL, but previous mode wasn't
|
slouken@501
|
675 |
*/
|
slouken@501
|
676 |
if (video_set == SDL_TRUE)
|
slouken@501
|
677 |
if ( (mode_flags & SDL_FULLSCREEN) ||
|
slouken@501
|
678 |
((mode_flags ^ flags) & (SDL_NOFRAME|SDL_RESIZABLE)) ||
|
slouken@501
|
679 |
(mode_flags & SDL_OPENGL) ||
|
slouken@501
|
680 |
(flags & SDL_OPENGL) )
|
slouken@501
|
681 |
QZ_UnsetVideoMode (this);
|
slouken@683
|
682 |
|
slouken@683
|
683 |
/* Check for user-specified window and view */
|
slouken@683
|
684 |
{
|
slouken@683
|
685 |
char *windowPtrString = getenv ("SDL_NSWindowPointer");
|
slouken@683
|
686 |
char *viewPtrString = getenv ("SDL_NSQuickDrawViewPointer");
|
slouken@683
|
687 |
|
slouken@683
|
688 |
if (windowPtrString && viewPtrString) {
|
slouken@683
|
689 |
|
slouken@683
|
690 |
/* Release any previous window */
|
slouken@683
|
691 |
if ( qz_window ) {
|
slouken@683
|
692 |
[ qz_window release ];
|
slouken@683
|
693 |
qz_window = nil;
|
slouken@683
|
694 |
}
|
slouken@683
|
695 |
|
slouken@683
|
696 |
qz_window = (NSWindow*)atoi(windowPtrString);
|
slouken@683
|
697 |
window_view = (NSQuickDrawView*)atoi(viewPtrString);
|
slouken@683
|
698 |
isCustom = YES;
|
slouken@683
|
699 |
|
slouken@683
|
700 |
/*
|
slouken@683
|
701 |
Retain reference to window because we
|
slouken@683
|
702 |
might release it in QZ_UnsetVideoMode
|
slouken@683
|
703 |
*/
|
slouken@683
|
704 |
[ qz_window retain ];
|
slouken@683
|
705 |
|
slouken@683
|
706 |
style = [ qz_window styleMask ];
|
slouken@683
|
707 |
/* Check resizability */
|
slouken@683
|
708 |
if ( style & NSResizableWindowMask )
|
slouken@683
|
709 |
current->flags |= SDL_RESIZABLE;
|
slouken@683
|
710 |
|
slouken@683
|
711 |
/* Check frame */
|
slouken@683
|
712 |
if ( style & NSBorderlessWindowMask )
|
slouken@683
|
713 |
current->flags |= SDL_NOFRAME;
|
slouken@683
|
714 |
}
|
slouken@683
|
715 |
}
|
slouken@683
|
716 |
|
slouken@501
|
717 |
/* Check if we should recreate the window */
|
slouken@501
|
718 |
if (qz_window == nil) {
|
slouken@501
|
719 |
|
slouken@501
|
720 |
/* Set the window style based on input flags */
|
slouken@501
|
721 |
if ( flags & SDL_NOFRAME ) {
|
slouken@501
|
722 |
style = NSBorderlessWindowMask;
|
slouken@501
|
723 |
current->flags |= SDL_NOFRAME;
|
slouken@501
|
724 |
} else {
|
slouken@501
|
725 |
style = NSTitledWindowMask;
|
slouken@501
|
726 |
style |= (NSMiniaturizableWindowMask | NSClosableWindowMask);
|
slouken@501
|
727 |
if ( flags & SDL_RESIZABLE ) {
|
slouken@501
|
728 |
style |= NSResizableWindowMask;
|
slouken@501
|
729 |
current->flags |= SDL_RESIZABLE;
|
slouken@501
|
730 |
}
|
slouken@501
|
731 |
}
|
slouken@501
|
732 |
|
slouken@657
|
733 |
if ( QZ_WindowPosition(this, &origin_x, &origin_y) ) {
|
slouken@657
|
734 |
center_window = 0;
|
slouken@657
|
735 |
contentRect.origin.x = (float)origin_x;
|
slouken@657
|
736 |
contentRect.origin.y = (float)origin_y;
|
slouken@657
|
737 |
}
|
slouken@657
|
738 |
|
slouken@501
|
739 |
/* Manually create a window, avoids having a nib file resource */
|
slouken@501
|
740 |
qz_window = [ [ SDL_QuartzWindow alloc ]
|
slouken@501
|
741 |
initWithContentRect:contentRect
|
slouken@501
|
742 |
styleMask:style
|
slouken@501
|
743 |
backing:NSBackingStoreBuffered
|
slouken@501
|
744 |
defer:NO ];
|
slouken@501
|
745 |
|
slouken@501
|
746 |
if (qz_window == nil) {
|
slouken@501
|
747 |
SDL_SetError ("Could not create the Cocoa window");
|
slouken@501
|
748 |
return NULL;
|
slouken@501
|
749 |
}
|
slouken@501
|
750 |
|
icculus@560
|
751 |
//[ qz_window setReleasedWhenClosed:YES ];
|
slouken@501
|
752 |
QZ_SetCaption(this, this->wm_title, this->wm_icon);
|
slouken@501
|
753 |
[ qz_window setAcceptsMouseMovedEvents:YES ];
|
slouken@501
|
754 |
[ qz_window setViewsNeedDisplay:NO ];
|
slouken@657
|
755 |
if ( center_window ) {
|
slouken@657
|
756 |
[ qz_window center ];
|
slouken@657
|
757 |
}
|
slouken@501
|
758 |
[ qz_window setDelegate:
|
slouken@501
|
759 |
[ [ [ SDL_QuartzWindowDelegate alloc ] init ] autorelease ] ];
|
slouken@501
|
760 |
}
|
slouken@501
|
761 |
/* We already have a window, just change its size */
|
slouken@501
|
762 |
else {
|
slouken@501
|
763 |
|
slouken@683
|
764 |
if (!isCustom) {
|
slouken@683
|
765 |
[ qz_window setContentSize:contentRect.size ];
|
slouken@683
|
766 |
current->flags |= (SDL_NOFRAME|SDL_RESIZABLE) & mode_flags;
|
slouken@832
|
767 |
[ window_view setFrameSize:contentRect.size ];
|
slouken@683
|
768 |
}
|
slouken@501
|
769 |
}
|
slouken@390
|
770 |
|
slouken@501
|
771 |
/* For OpenGL, we bind the context to a subview */
|
slouken@47
|
772 |
if ( flags & SDL_OPENGL ) {
|
slouken@390
|
773 |
|
slouken@47
|
774 |
if ( ! QZ_SetupOpenGL (this, bpp, flags) ) {
|
slouken@47
|
775 |
return NULL;
|
slouken@47
|
776 |
}
|
slouken@390
|
777 |
|
slouken@501
|
778 |
window_view = [ [ NSView alloc ] initWithFrame:contentRect ];
|
slouken@832
|
779 |
[ window_view setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable ];
|
slouken@501
|
780 |
[ [ qz_window contentView ] addSubview:window_view ];
|
slouken@501
|
781 |
[ gl_context setView: window_view ];
|
slouken@501
|
782 |
[ window_view release ];
|
slouken@47
|
783 |
[ gl_context makeCurrentContext];
|
slouken@158
|
784 |
[ qz_window makeKeyAndOrderFront:nil ];
|
slouken@47
|
785 |
current->flags |= SDL_OPENGL;
|
slouken@47
|
786 |
}
|
slouken@501
|
787 |
/* For 2D, we set the subview to an NSQuickDrawView */
|
slouken@47
|
788 |
else {
|
slouken@390
|
789 |
|
slouken@501
|
790 |
/* Only recreate the view if it doesn't already exist */
|
slouken@501
|
791 |
if (window_view == nil) {
|
slouken@501
|
792 |
|
slouken@761
|
793 |
window_view = [ [ NSQuickDrawView alloc ] initWithFrame:contentRect ];
|
slouken@832
|
794 |
[ window_view setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable ];
|
slouken@501
|
795 |
[ [ qz_window contentView ] addSubview:window_view ];
|
slouken@501
|
796 |
[ window_view release ];
|
slouken@501
|
797 |
[ qz_window makeKeyAndOrderFront:nil ];
|
slouken@501
|
798 |
}
|
slouken@501
|
799 |
|
slouken@272
|
800 |
LockPortBits ( [ window_view qdPort ] );
|
slouken@272
|
801 |
current->pixels = GetPixBaseAddr ( GetPortPixMap ( [ window_view qdPort ] ) );
|
slouken@272
|
802 |
current->pitch = GetPixRowBytes ( GetPortPixMap ( [ window_view qdPort ] ) );
|
slouken@498
|
803 |
UnlockPortBits ( [ window_view qdPort ] );
|
slouken@501
|
804 |
|
slouken@47
|
805 |
current->flags |= SDL_SWSURFACE;
|
slouken@47
|
806 |
current->flags |= SDL_PREALLOC;
|
slouken@498
|
807 |
current->flags |= SDL_ASYNCBLIT;
|
slouken@498
|
808 |
|
slouken@683
|
809 |
/*
|
slouken@683
|
810 |
current->pixels now points to the window's pixels
|
slouken@683
|
811 |
We want it to point to the *view's* pixels
|
slouken@683
|
812 |
*/
|
slouken@683
|
813 |
{
|
slouken@683
|
814 |
int vOffset = [ qz_window frame ].size.height -
|
slouken@683
|
815 |
[ window_view frame ].size.height - [ window_view frame ].origin.y;
|
slouken@683
|
816 |
|
slouken@683
|
817 |
int hOffset = [ window_view frame ].origin.x;
|
slouken@683
|
818 |
|
slouken@683
|
819 |
current->pixels += (vOffset * current->pitch) + hOffset * (device_bpp/8);
|
slouken@683
|
820 |
}
|
slouken@498
|
821 |
this->UpdateRects = QZ_UpdateRects;
|
slouken@498
|
822 |
this->LockHWSurface = QZ_LockWindow;
|
slouken@498
|
823 |
this->UnlockHWSurface = QZ_UnlockWindow;
|
slouken@47
|
824 |
}
|
slouken@390
|
825 |
|
slouken@272
|
826 |
/* Save flags to ensure correct teardown */
|
slouken@272
|
827 |
mode_flags = current->flags;
|
slouken@390
|
828 |
|
slouken@47
|
829 |
return current;
|
slouken@47
|
830 |
}
|
slouken@47
|
831 |
|
slouken@390
|
832 |
static SDL_Surface* QZ_SetVideoMode (_THIS, SDL_Surface *current, int width,
|
slouken@390
|
833 |
int height, int bpp, Uint32 flags) {
|
slouken@47
|
834 |
|
slouken@47
|
835 |
current->flags = 0;
|
icculus@852
|
836 |
current->pixels = NULL;
|
slouken@390
|
837 |
|
slouken@47
|
838 |
/* Setup full screen video */
|
slouken@47
|
839 |
if ( flags & SDL_FULLSCREEN ) {
|
slouken@47
|
840 |
current = QZ_SetVideoFullScreen (this, current, width, height, bpp, flags );
|
slouken@47
|
841 |
if (current == NULL)
|
slouken@47
|
842 |
return NULL;
|
slouken@47
|
843 |
}
|
slouken@47
|
844 |
/* Setup windowed video */
|
slouken@47
|
845 |
else {
|
slouken@47
|
846 |
/* Force bpp to the device's bpp */
|
slouken@272
|
847 |
bpp = device_bpp;
|
slouken@47
|
848 |
current = QZ_SetVideoWindowed (this, current, width, height, bpp, flags);
|
slouken@47
|
849 |
if (current == NULL)
|
slouken@47
|
850 |
return NULL;
|
slouken@47
|
851 |
}
|
slouken@390
|
852 |
|
slouken@47
|
853 |
/* Setup the new pixel format */
|
slouken@47
|
854 |
{
|
slouken@390
|
855 |
int amask = 0,
|
slouken@390
|
856 |
rmask = 0,
|
slouken@390
|
857 |
gmask = 0,
|
slouken@390
|
858 |
bmask = 0;
|
slouken@390
|
859 |
|
slouken@47
|
860 |
switch (bpp) {
|
slouken@47
|
861 |
case 16: /* (1)-5-5-5 RGB */
|
slouken@390
|
862 |
amask = 0;
|
slouken@58
|
863 |
rmask = 0x7C00;
|
slouken@58
|
864 |
gmask = 0x03E0;
|
slouken@58
|
865 |
bmask = 0x001F;
|
slouken@47
|
866 |
break;
|
slouken@47
|
867 |
case 24:
|
slouken@47
|
868 |
SDL_SetError ("24bpp is not available");
|
slouken@47
|
869 |
return NULL;
|
slouken@47
|
870 |
case 32: /* (8)-8-8-8 ARGB */
|
slouken@155
|
871 |
amask = 0x00000000;
|
slouken@47
|
872 |
rmask = 0x00FF0000;
|
slouken@47
|
873 |
gmask = 0x0000FF00;
|
slouken@47
|
874 |
bmask = 0x000000FF;
|
slouken@47
|
875 |
break;
|
slouken@47
|
876 |
}
|
slouken@390
|
877 |
|
slouken@47
|
878 |
if ( ! SDL_ReallocFormat (current, bpp,
|
slouken@47
|
879 |
rmask, gmask, bmask, amask ) ) {
|
slouken@390
|
880 |
SDL_SetError ("Couldn't reallocate pixel format");
|
slouken@390
|
881 |
return NULL;
|
slouken@390
|
882 |
}
|
slouken@47
|
883 |
}
|
slouken@390
|
884 |
|
slouken@272
|
885 |
/* Signal successful completion (used internally) */
|
slouken@155
|
886 |
video_set = SDL_TRUE;
|
slouken@390
|
887 |
|
slouken@47
|
888 |
return current;
|
slouken@47
|
889 |
}
|
slouken@47
|
890 |
|
slouken@390
|
891 |
static int QZ_ToggleFullScreen (_THIS, int on) {
|
slouken@576
|
892 |
return 0;
|
slouken@47
|
893 |
}
|
slouken@47
|
894 |
|
slouken@390
|
895 |
static int QZ_SetColors (_THIS, int first_color, int num_colors,
|
slouken@390
|
896 |
SDL_Color *colors) {
|
slouken@47
|
897 |
|
slouken@47
|
898 |
CGTableCount index;
|
slouken@47
|
899 |
CGDeviceColor color;
|
slouken@390
|
900 |
|
slouken@47
|
901 |
for (index = first_color; index < first_color+num_colors; index++) {
|
slouken@390
|
902 |
|
slouken@47
|
903 |
/* Clamp colors between 0.0 and 1.0 */
|
slouken@47
|
904 |
color.red = colors->r / 255.0;
|
slouken@47
|
905 |
color.blue = colors->b / 255.0;
|
slouken@47
|
906 |
color.green = colors->g / 255.0;
|
slouken@390
|
907 |
|
slouken@47
|
908 |
colors++;
|
slouken@390
|
909 |
|
slouken@47
|
910 |
CGPaletteSetColorAtIndex (palette, color, index);
|
slouken@47
|
911 |
}
|
slouken@390
|
912 |
|
slouken@47
|
913 |
if ( CGDisplayNoErr != CGDisplaySetPalette (display_id, palette) )
|
slouken@47
|
914 |
return 0;
|
slouken@390
|
915 |
|
slouken@47
|
916 |
return 1;
|
slouken@47
|
917 |
}
|
slouken@47
|
918 |
|
slouken@588
|
919 |
static int QZ_LockDoubleBuffer (_THIS, SDL_Surface *surface) {
|
slouken@588
|
920 |
|
slouken@588
|
921 |
return 1;
|
slouken@588
|
922 |
}
|
slouken@588
|
923 |
|
slouken@588
|
924 |
static void QZ_UnlockDoubleBuffer (_THIS, SDL_Surface *surface) {
|
slouken@588
|
925 |
|
slouken@588
|
926 |
}
|
slouken@588
|
927 |
|
slouken@588
|
928 |
/* The VBL delay is based on code by Ian R Ollmann's RezLib <iano@cco.caltech.edu> */
|
slouken@588
|
929 |
static AbsoluteTime QZ_SecondsToAbsolute ( double seconds ) {
|
slouken@588
|
930 |
|
slouken@588
|
931 |
union
|
slouken@588
|
932 |
{
|
slouken@761
|
933 |
UInt64 i;
|
slouken@588
|
934 |
Nanoseconds ns;
|
slouken@588
|
935 |
} temp;
|
slouken@588
|
936 |
|
slouken@588
|
937 |
temp.i = seconds * 1000000000.0;
|
slouken@588
|
938 |
|
slouken@588
|
939 |
return NanosecondsToAbsolute ( temp.ns );
|
slouken@588
|
940 |
}
|
slouken@588
|
941 |
|
slouken@588
|
942 |
static int QZ_ThreadFlip (_THIS) {
|
slouken@588
|
943 |
|
slouken@588
|
944 |
Uint8 *src, *dst;
|
slouken@588
|
945 |
int skip, len, h;
|
slouken@588
|
946 |
|
slouken@588
|
947 |
/*
|
slouken@588
|
948 |
Give this thread the highest scheduling priority possible,
|
slouken@588
|
949 |
in the hopes that it will immediately run after the VBL delay
|
slouken@588
|
950 |
*/
|
slouken@588
|
951 |
{
|
slouken@588
|
952 |
pthread_t current_thread;
|
slouken@588
|
953 |
int policy;
|
slouken@588
|
954 |
struct sched_param param;
|
slouken@588
|
955 |
|
slouken@588
|
956 |
current_thread = pthread_self ();
|
slouken@588
|
957 |
pthread_getschedparam (current_thread, &policy, ¶m);
|
slouken@588
|
958 |
policy = SCHED_RR;
|
slouken@588
|
959 |
param.sched_priority = sched_get_priority_max (policy);
|
slouken@588
|
960 |
pthread_setschedparam (current_thread, policy, ¶m);
|
slouken@588
|
961 |
}
|
slouken@588
|
962 |
|
slouken@588
|
963 |
while (1) {
|
slouken@588
|
964 |
|
slouken@588
|
965 |
SDL_SemWait (sem1);
|
slouken@588
|
966 |
if (quit_thread)
|
slouken@588
|
967 |
return 0;
|
slouken@588
|
968 |
|
slouken@588
|
969 |
dst = CGDisplayBaseAddress (display_id);
|
slouken@588
|
970 |
src = current_buffer;
|
slouken@588
|
971 |
len = SDL_VideoSurface->w * SDL_VideoSurface->format->BytesPerPixel;
|
slouken@588
|
972 |
h = SDL_VideoSurface->h;
|
slouken@588
|
973 |
skip = SDL_VideoSurface->pitch;
|
slouken@588
|
974 |
|
slouken@588
|
975 |
/* Wait for the VBL to occur (estimated since we don't have a hardware interrupt) */
|
slouken@588
|
976 |
{
|
slouken@588
|
977 |
|
slouken@588
|
978 |
/* The VBL delay is based on Ian Ollmann's RezLib <iano@cco.caltech.edu> */
|
slouken@588
|
979 |
double refreshRate;
|
slouken@588
|
980 |
double linesPerSecond;
|
slouken@588
|
981 |
double target;
|
slouken@588
|
982 |
double position;
|
slouken@588
|
983 |
double adjustment;
|
slouken@588
|
984 |
AbsoluteTime nextTime;
|
slouken@588
|
985 |
CFNumberRef refreshRateCFNumber;
|
slouken@588
|
986 |
|
slouken@588
|
987 |
refreshRateCFNumber = CFDictionaryGetValue (mode, kCGDisplayRefreshRate);
|
slouken@588
|
988 |
if ( NULL == refreshRateCFNumber ) {
|
slouken@588
|
989 |
SDL_SetError ("Mode has no refresh rate");
|
slouken@588
|
990 |
goto ERROR;
|
slouken@588
|
991 |
}
|
slouken@588
|
992 |
|
slouken@588
|
993 |
if ( 0 == CFNumberGetValue (refreshRateCFNumber, kCFNumberDoubleType, &refreshRate) ) {
|
slouken@588
|
994 |
SDL_SetError ("Error getting refresh rate");
|
slouken@588
|
995 |
goto ERROR;
|
slouken@588
|
996 |
}
|
slouken@588
|
997 |
|
slouken@588
|
998 |
if ( 0 == refreshRate ) {
|
slouken@588
|
999 |
|
slouken@588
|
1000 |
SDL_SetError ("Display has no refresh rate, using 60hz");
|
slouken@588
|
1001 |
|
slouken@588
|
1002 |
/* ok, for LCD's we'll emulate a 60hz refresh, which may or may not look right */
|
slouken@588
|
1003 |
refreshRate = 60.0;
|
slouken@588
|
1004 |
}
|
slouken@588
|
1005 |
|
slouken@588
|
1006 |
linesPerSecond = refreshRate * h;
|
slouken@588
|
1007 |
target = h;
|
slouken@588
|
1008 |
|
slouken@588
|
1009 |
/* Figure out the first delay so we start off about right */
|
slouken@588
|
1010 |
position = CGDisplayBeamPosition (display_id);
|
slouken@588
|
1011 |
if (position > target)
|
slouken@588
|
1012 |
position = 0;
|
slouken@588
|
1013 |
|
slouken@588
|
1014 |
adjustment = (target - position) / linesPerSecond;
|
slouken@588
|
1015 |
|
slouken@588
|
1016 |
nextTime = AddAbsoluteToAbsolute (UpTime (), QZ_SecondsToAbsolute (adjustment));
|
slouken@588
|
1017 |
|
slouken@588
|
1018 |
MPDelayUntil (&nextTime);
|
slouken@588
|
1019 |
}
|
slouken@588
|
1020 |
|
slouken@588
|
1021 |
|
slouken@588
|
1022 |
/* On error, skip VBL delay */
|
slouken@588
|
1023 |
ERROR:
|
slouken@588
|
1024 |
|
slouken@588
|
1025 |
while ( h-- ) {
|
slouken@588
|
1026 |
|
slouken@588
|
1027 |
memcpy (dst, src, len);
|
slouken@588
|
1028 |
src += skip;
|
slouken@588
|
1029 |
dst += skip;
|
slouken@588
|
1030 |
}
|
slouken@588
|
1031 |
|
slouken@588
|
1032 |
/* signal flip completion */
|
slouken@588
|
1033 |
SDL_SemPost (sem2);
|
slouken@588
|
1034 |
}
|
slouken@588
|
1035 |
|
slouken@588
|
1036 |
return 0;
|
slouken@588
|
1037 |
}
|
slouken@588
|
1038 |
|
slouken@588
|
1039 |
static int QZ_FlipDoubleBuffer (_THIS, SDL_Surface *surface) {
|
slouken@588
|
1040 |
|
slouken@588
|
1041 |
/* wait for previous flip to complete */
|
slouken@588
|
1042 |
SDL_SemWait (sem2);
|
slouken@588
|
1043 |
|
slouken@588
|
1044 |
current_buffer = surface->pixels;
|
slouken@588
|
1045 |
|
slouken@588
|
1046 |
if (surface->pixels == sw_buffers[0])
|
slouken@588
|
1047 |
surface->pixels = sw_buffers[1];
|
slouken@588
|
1048 |
else
|
slouken@588
|
1049 |
surface->pixels = sw_buffers[0];
|
slouken@588
|
1050 |
|
slouken@588
|
1051 |
/* signal worker thread to do the flip */
|
slouken@588
|
1052 |
SDL_SemPost (sem1);
|
slouken@588
|
1053 |
|
slouken@588
|
1054 |
return 0;
|
slouken@588
|
1055 |
}
|
slouken@588
|
1056 |
|
slouken@588
|
1057 |
|
slouken@588
|
1058 |
static void QZ_DoubleBufferUpdate (_THIS, int num_rects, SDL_Rect *rects) {
|
slouken@588
|
1059 |
|
slouken@588
|
1060 |
/* perform a flip if someone calls updaterects on a doublebuferred surface */
|
slouken@588
|
1061 |
this->FlipHWSurface (this, SDL_VideoSurface);
|
slouken@588
|
1062 |
}
|
slouken@588
|
1063 |
|
slouken@47
|
1064 |
static void QZ_DirectUpdate (_THIS, int num_rects, SDL_Rect *rects) {
|
slouken@390
|
1065 |
#pragma unused(this,num_rects,rects)
|
slouken@47
|
1066 |
}
|
slouken@47
|
1067 |
|
slouken@501
|
1068 |
/*
|
slouken@501
|
1069 |
The obscured code is based on work by Matt Slot fprefect@ambrosiasw.com,
|
slouken@501
|
1070 |
who supplied sample code for Carbon.
|
slouken@501
|
1071 |
*/
|
slouken@761
|
1072 |
|
slouken@761
|
1073 |
//#define TEST_OBSCURED 1
|
slouken@761
|
1074 |
|
slouken@761
|
1075 |
#if TEST_OBSCURED
|
slouken@761
|
1076 |
#include "CGS.h"
|
slouken@761
|
1077 |
#endif
|
slouken@761
|
1078 |
|
slouken@272
|
1079 |
static int QZ_IsWindowObscured (NSWindow *window) {
|
slouken@272
|
1080 |
|
slouken@272
|
1081 |
|
slouken@272
|
1082 |
#if TEST_OBSCURED
|
slouken@390
|
1083 |
|
slouken@501
|
1084 |
/*
|
slouken@501
|
1085 |
In order to determine if a direct copy to the screen is possible,
|
slouken@390
|
1086 |
we must figure out if there are any windows covering ours (including shadows).
|
slouken@390
|
1087 |
This can be done by querying the window server about the on screen
|
slouken@390
|
1088 |
windows for their screen rectangle and window level.
|
slouken@390
|
1089 |
The procedure used below is puts accuracy before speed; however, it aims to call
|
slouken@390
|
1090 |
the window server the fewest number of times possible to keep things reasonable.
|
slouken@390
|
1091 |
In my testing on a 300mhz G3, this routine typically takes < 2 ms. -DW
|
slouken@272
|
1092 |
|
slouken@390
|
1093 |
Notes:
|
slouken@390
|
1094 |
-Calls into the Window Server involve IPC which is slow.
|
slouken@390
|
1095 |
-Getting a rectangle seems slower than getting the window level
|
slouken@390
|
1096 |
-The window list we get back is in sorted order, top to bottom
|
slouken@390
|
1097 |
-On average, I suspect, most windows above ours are dock icon windows (hence optimization)
|
slouken@390
|
1098 |
-Some windows above ours are always there, and cannot move or obscure us (menu bar)
|
slouken@390
|
1099 |
|
slouken@390
|
1100 |
Bugs:
|
slouken@390
|
1101 |
-no way (yet) to deactivate direct drawing when a window is dragged,
|
slouken@390
|
1102 |
or suddenly obscured, so drawing continues and can produce garbage
|
slouken@390
|
1103 |
We need some kind of locking mechanism on window movement to prevent this
|
slouken@390
|
1104 |
|
slouken@390
|
1105 |
-deactivated normal windows use activated normal
|
slouken@390
|
1106 |
window shadows (slight inaccuraccy)
|
slouken@272
|
1107 |
*/
|
slouken@390
|
1108 |
|
slouken@272
|
1109 |
/* Cache the connection to the window server */
|
slouken@390
|
1110 |
static CGSConnectionID cgsConnection = (CGSConnectionID) -1;
|
slouken@390
|
1111 |
|
slouken@272
|
1112 |
/* Cache the dock icon windows */
|
slouken@272
|
1113 |
static CGSWindowID dockIcons[kMaxWindows];
|
slouken@272
|
1114 |
static int numCachedDockIcons = 0;
|
slouken@390
|
1115 |
|
slouken@390
|
1116 |
CGSWindowID windows[kMaxWindows];
|
slouken@390
|
1117 |
CGSWindowCount i, count;
|
slouken@390
|
1118 |
CGSWindowLevel winLevel;
|
slouken@390
|
1119 |
CGSRect winRect;
|
slouken@272
|
1120 |
|
slouken@272
|
1121 |
CGSRect contentRect;
|
slouken@272
|
1122 |
int windowNumber;
|
slouken@272
|
1123 |
//int isMainWindow;
|
slouken@390
|
1124 |
int firstDockIcon;
|
slouken@272
|
1125 |
int dockIconCacheMiss;
|
slouken@272
|
1126 |
int windowContentOffset;
|
slouken@390
|
1127 |
|
slouken@272
|
1128 |
int obscured = SDL_TRUE;
|
slouken@390
|
1129 |
|
slouken@272
|
1130 |
if ( [ window isVisible ] ) {
|
slouken@390
|
1131 |
|
slouken@501
|
1132 |
/*
|
slouken@501
|
1133 |
walk the window list looking for windows over top of
|
slouken@501
|
1134 |
(or casting a shadow on) ours
|
slouken@501
|
1135 |
*/
|
slouken@390
|
1136 |
|
slouken@501
|
1137 |
/*
|
slouken@501
|
1138 |
Get a connection to the window server
|
slouken@501
|
1139 |
Should probably be moved out into SetVideoMode() or InitVideo()
|
slouken@501
|
1140 |
*/
|
slouken@272
|
1141 |
if (cgsConnection == (CGSConnectionID) -1) {
|
slouken@272
|
1142 |
cgsConnection = (CGSConnectionID) 0;
|
slouken@272
|
1143 |
cgsConnection = _CGSDefaultConnection ();
|
slouken@272
|
1144 |
}
|
slouken@390
|
1145 |
|
slouken@390
|
1146 |
if (cgsConnection) {
|
slouken@390
|
1147 |
|
slouken@272
|
1148 |
if ( ! [ window styleMask ] & NSBorderlessWindowMask )
|
slouken@272
|
1149 |
windowContentOffset = 22;
|
slouken@272
|
1150 |
else
|
slouken@272
|
1151 |
windowContentOffset = 0;
|
slouken@390
|
1152 |
|
slouken@272
|
1153 |
windowNumber = [ window windowNumber ];
|
slouken@272
|
1154 |
//isMainWindow = [ window isMainWindow ];
|
slouken@390
|
1155 |
|
slouken@272
|
1156 |
/* The window list is sorted according to order on the screen */
|
slouken@272
|
1157 |
count = 0;
|
slouken@272
|
1158 |
CGSGetOnScreenWindowList (cgsConnection, 0, kMaxWindows, windows, &count);
|
slouken@272
|
1159 |
CGSGetScreenRectForWindow (cgsConnection, windowNumber, &contentRect);
|
slouken@390
|
1160 |
|
slouken@272
|
1161 |
/* adjust rect for window title bar (if present) */
|
slouken@272
|
1162 |
contentRect.origin.y += windowContentOffset;
|
slouken@272
|
1163 |
contentRect.size.height -= windowContentOffset;
|
slouken@390
|
1164 |
|
slouken@272
|
1165 |
firstDockIcon = -1;
|
slouken@272
|
1166 |
dockIconCacheMiss = SDL_FALSE;
|
slouken@390
|
1167 |
|
slouken@501
|
1168 |
/*
|
slouken@501
|
1169 |
The first window is always an empty window with level kCGSWindowLevelTop
|
slouken@501
|
1170 |
so start at index 1
|
slouken@501
|
1171 |
*/
|
slouken@272
|
1172 |
for (i = 1; i < count; i++) {
|
slouken@390
|
1173 |
|
slouken@272
|
1174 |
/* If we reach our window in the list, it cannot be obscured */
|
slouken@272
|
1175 |
if (windows[i] == windowNumber) {
|
slouken@390
|
1176 |
|
slouken@272
|
1177 |
obscured = SDL_FALSE;
|
slouken@272
|
1178 |
break;
|
slouken@272
|
1179 |
}
|
slouken@272
|
1180 |
else {
|
slouken@390
|
1181 |
|
slouken@272
|
1182 |
float shadowSide;
|
slouken@272
|
1183 |
float shadowTop;
|
slouken@272
|
1184 |
float shadowBottom;
|
slouken@272
|
1185 |
|
slouken@272
|
1186 |
CGSGetWindowLevel (cgsConnection, windows[i], &winLevel);
|
slouken@390
|
1187 |
|
slouken@272
|
1188 |
if (winLevel == kCGSWindowLevelDockIcon) {
|
slouken@390
|
1189 |
|
slouken@272
|
1190 |
int j;
|
slouken@390
|
1191 |
|
slouken@272
|
1192 |
if (firstDockIcon < 0) {
|
slouken@390
|
1193 |
|
slouken@272
|
1194 |
firstDockIcon = i;
|
slouken@390
|
1195 |
|
slouken@272
|
1196 |
if (numCachedDockIcons > 0) {
|
slouken@390
|
1197 |
|
slouken@272
|
1198 |
for (j = 0; j < numCachedDockIcons; j++) {
|
slouken@390
|
1199 |
|
slouken@272
|
1200 |
if (windows[i] == dockIcons[j])
|
slouken@272
|
1201 |
i++;
|
slouken@272
|
1202 |
else
|
slouken@272
|
1203 |
break;
|
slouken@272
|
1204 |
}
|
slouken@390
|
1205 |
|
slouken@272
|
1206 |
if (j != 0) {
|
slouken@390
|
1207 |
|
slouken@272
|
1208 |
i--;
|
slouken@390
|
1209 |
|
slouken@272
|
1210 |
if (j < numCachedDockIcons) {
|
slouken@390
|
1211 |
|
slouken@272
|
1212 |
dockIconCacheMiss = SDL_TRUE;
|
slouken@272
|
1213 |
}
|
slouken@272
|
1214 |
}
|
slouken@272
|
1215 |
|
slouken@272
|
1216 |
}
|
slouken@272
|
1217 |
}
|
slouken@390
|
1218 |
|
slouken@272
|
1219 |
continue;
|
slouken@272
|
1220 |
}
|
slouken@272
|
1221 |
else if (winLevel == kCGSWindowLevelMenuIgnore
|
slouken@272
|
1222 |
/* winLevel == kCGSWindowLevelTop */) {
|
slouken@390
|
1223 |
|
slouken@272
|
1224 |
continue; /* cannot obscure window */
|
slouken@272
|
1225 |
}
|
slouken@272
|
1226 |
else if (winLevel == kCGSWindowLevelDockMenu ||
|
slouken@272
|
1227 |
winLevel == kCGSWindowLevelMenu) {
|
slouken@390
|
1228 |
|
slouken@272
|
1229 |
shadowSide = 18;
|
slouken@272
|
1230 |
shadowTop = 4;
|
slouken@390
|
1231 |
shadowBottom = 22;
|
slouken@272
|
1232 |
}
|
slouken@272
|
1233 |
else if (winLevel == kCGSWindowLevelUtility) {
|
slouken@390
|
1234 |
|
slouken@272
|
1235 |
shadowSide = 8;
|
slouken@272
|
1236 |
shadowTop = 4;
|
slouken@272
|
1237 |
shadowBottom = 12;
|
slouken@272
|
1238 |
}
|
slouken@272
|
1239 |
else if (winLevel == kCGSWindowLevelNormal) {
|
slouken@390
|
1240 |
|
slouken@501
|
1241 |
/*
|
slouken@501
|
1242 |
These numbers are for foreground windows,
|
slouken@501
|
1243 |
they are too big (but will work) for background windows
|
slouken@501
|
1244 |
*/
|
slouken@272
|
1245 |
shadowSide = 20;
|
slouken@272
|
1246 |
shadowTop = 10;
|
slouken@272
|
1247 |
shadowBottom = 24;
|
slouken@272
|
1248 |
}
|
slouken@272
|
1249 |
else if (winLevel == kCGSWindowLevelDock) {
|
slouken@390
|
1250 |
|
slouken@272
|
1251 |
/* Create dock icon cache */
|
slouken@272
|
1252 |
if (numCachedDockIcons != (i-firstDockIcon) ||
|
slouken@272
|
1253 |
dockIconCacheMiss) {
|
slouken@390
|
1254 |
|
slouken@272
|
1255 |
numCachedDockIcons = i - firstDockIcon;
|
slouken@390
|
1256 |
memcpy (dockIcons, &(windows[firstDockIcon]),
|
slouken@272
|
1257 |
numCachedDockIcons * sizeof(*windows));
|
slouken@272
|
1258 |
}
|
slouken@390
|
1259 |
|
slouken@272
|
1260 |
/* no shadow */
|
slouken@272
|
1261 |
shadowSide = 0;
|
slouken@272
|
1262 |
shadowTop = 0;
|
slouken@272
|
1263 |
shadowBottom = 0;
|
slouken@272
|
1264 |
}
|
slouken@272
|
1265 |
else {
|
slouken@390
|
1266 |
|
slouken@501
|
1267 |
/*
|
slouken@501
|
1268 |
kCGSWindowLevelDockLabel,
|
slouken@501
|
1269 |
kCGSWindowLevelDock,
|
slouken@501
|
1270 |
kOther???
|
slouken@501
|
1271 |
*/
|
slouken@390
|
1272 |
|
slouken@272
|
1273 |
/* no shadow */
|
slouken@272
|
1274 |
shadowSide = 0;
|
slouken@272
|
1275 |
shadowTop = 0;
|
slouken@272
|
1276 |
shadowBottom = 0;
|
slouken@272
|
1277 |
}
|
slouken@390
|
1278 |
|
slouken@272
|
1279 |
CGSGetScreenRectForWindow (cgsConnection, windows[i], &winRect);
|
slouken@390
|
1280 |
|
slouken@272
|
1281 |
winRect.origin.x -= shadowSide;
|
slouken@272
|
1282 |
winRect.origin.y -= shadowTop;
|
slouken@272
|
1283 |
winRect.size.width += shadowSide;
|
slouken@272
|
1284 |
winRect.size.height += shadowBottom;
|
slouken@390
|
1285 |
|
slouken@272
|
1286 |
if (NSIntersectsRect (contentRect, winRect)) {
|
slouken@390
|
1287 |
|
slouken@272
|
1288 |
obscured = SDL_TRUE;
|
slouken@272
|
1289 |
break;
|
slouken@272
|
1290 |
}
|
slouken@390
|
1291 |
|
slouken@390
|
1292 |
} /* window was not our window */
|
slouken@390
|
1293 |
|
slouken@272
|
1294 |
} /* iterate over windows */
|
slouken@390
|
1295 |
|
slouken@272
|
1296 |
} /* get cgsConnection */
|
slouken@390
|
1297 |
|
slouken@272
|
1298 |
} /* window is visible */
|
slouken@272
|
1299 |
|
slouken@272
|
1300 |
return obscured;
|
slouken@272
|
1301 |
#else
|
slouken@272
|
1302 |
return SDL_TRUE;
|
slouken@272
|
1303 |
#endif
|
slouken@272
|
1304 |
}
|
slouken@272
|
1305 |
|
slouken@501
|
1306 |
|
slouken@498
|
1307 |
/* Locking functions for the software window buffer */
|
slouken@498
|
1308 |
static int QZ_LockWindow (_THIS, SDL_Surface *surface) {
|
slouken@498
|
1309 |
|
slouken@498
|
1310 |
return LockPortBits ( [ window_view qdPort ] );
|
slouken@498
|
1311 |
}
|
slouken@498
|
1312 |
|
slouken@498
|
1313 |
static void QZ_UnlockWindow (_THIS, SDL_Surface *surface) {
|
slouken@498
|
1314 |
|
slouken@498
|
1315 |
UnlockPortBits ( [ window_view qdPort ] );
|
slouken@498
|
1316 |
}
|
slouken@498
|
1317 |
|
slouken@761
|
1318 |
/* Resize icon, BMP format */
|
slouken@761
|
1319 |
static const unsigned char QZ_ResizeIcon[] = {
|
slouken@761
|
1320 |
0x42,0x4d,0x31,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x36,0x00,0x00,0x00,0x28,0x00,
|
slouken@761
|
1321 |
0x00,0x00,0x0d,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x01,0x00,0x18,0x00,0x00,0x00,
|
slouken@761
|
1322 |
0x00,0x00,0xfb,0x01,0x00,0x00,0x13,0x0b,0x00,0x00,0x13,0x0b,0x00,0x00,0x00,0x00,
|
slouken@761
|
1323 |
0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
slouken@761
|
1324 |
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
slouken@761
|
1325 |
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0b,0xff,0xff,
|
slouken@761
|
1326 |
0xff,0xda,0xda,0xda,0x87,0x87,0x87,0xe8,0xe8,0xe8,0xff,0xff,0xff,0xda,0xda,0xda,
|
slouken@761
|
1327 |
0x87,0x87,0x87,0xe8,0xe8,0xe8,0xff,0xff,0xff,0xda,0xda,0xda,0x87,0x87,0x87,0xe8,
|
slouken@761
|
1328 |
0xe8,0xe8,0xff,0xff,0xff,0x0b,0xff,0xff,0xff,0xff,0xff,0xff,0xda,0xda,0xda,0x87,
|
slouken@761
|
1329 |
0x87,0x87,0xe8,0xe8,0xe8,0xff,0xff,0xff,0xda,0xda,0xda,0x87,0x87,0x87,0xe8,0xe8,
|
slouken@761
|
1330 |
0xe8,0xff,0xff,0xff,0xda,0xda,0xda,0x87,0x87,0x87,0xff,0xff,0xff,0x0b,0xff,0xff,
|
slouken@761
|
1331 |
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xd5,0xd5,0xd5,0x87,0x87,0x87,0xe8,0xe8,0xe8,
|
slouken@761
|
1332 |
0xff,0xff,0xff,0xda,0xda,0xda,0x87,0x87,0x87,0xe8,0xe8,0xe8,0xff,0xff,0xff,0xda,
|
slouken@761
|
1333 |
0xda,0xda,0xff,0xff,0xff,0x0b,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
slouken@761
|
1334 |
0xff,0xff,0xd7,0xd7,0xd7,0x87,0x87,0x87,0xe8,0xe8,0xe8,0xff,0xff,0xff,0xda,0xda,
|
slouken@761
|
1335 |
0xda,0x87,0x87,0x87,0xe8,0xe8,0xe8,0xff,0xff,0xff,0xff,0xff,0xff,0x0b,0xff,0xff,
|
slouken@761
|
1336 |
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xd7,0xd7,0xd7,
|
slouken@761
|
1337 |
0x87,0x87,0x87,0xe8,0xe8,0xe8,0xff,0xff,0xff,0xda,0xda,0xda,0x87,0x87,0x87,0xe8,
|
slouken@761
|
1338 |
0xe8,0xe8,0xff,0xff,0xff,0x0b,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
slouken@761
|
1339 |
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xd7,0xd7,0xd7,0x87,0x87,0x87,0xe8,0xe8,
|
slouken@761
|
1340 |
0xe8,0xff,0xff,0xff,0xdc,0xdc,0xdc,0x87,0x87,0x87,0xff,0xff,0xff,0x0b,0xff,0xff,
|
slouken@761
|
1341 |
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
slouken@761
|
1342 |
0xff,0xff,0xff,0xd9,0xd9,0xd9,0x87,0x87,0x87,0xe8,0xe8,0xe8,0xff,0xff,0xff,0xdc,
|
slouken@761
|
1343 |
0xdc,0xdc,0xff,0xff,0xff,0x0b,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
slouken@761
|
1344 |
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdb,0xdb,
|
slouken@761
|
1345 |
0xdb,0x87,0x87,0x87,0xe8,0xe8,0xe8,0xff,0xff,0xff,0xff,0xff,0xff,0x0b,0xff,0xff,
|
slouken@761
|
1346 |
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
slouken@761
|
1347 |
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdb,0xdb,0xdb,0x87,0x87,0x87,0xe8,
|
slouken@761
|
1348 |
0xe8,0xe8,0xff,0xff,0xff,0x0b,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
slouken@761
|
1349 |
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
slouken@761
|
1350 |
0xff,0xff,0xff,0xff,0xdc,0xdc,0xdc,0x87,0x87,0x87,0xff,0xff,0xff,0x0b,0xff,0xff,
|
slouken@761
|
1351 |
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
slouken@761
|
1352 |
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdc,
|
slouken@761
|
1353 |
0xdc,0xdc,0xff,0xff,0xff,0x0b,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
slouken@761
|
1354 |
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
slouken@761
|
1355 |
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0b
|
slouken@761
|
1356 |
};
|
slouken@761
|
1357 |
|
slouken@761
|
1358 |
static void QZ_DrawResizeIcon (_THIS, RgnHandle dirtyRegion) {
|
slouken@761
|
1359 |
|
slouken@761
|
1360 |
/* Check if we should draw the resize icon */
|
slouken@761
|
1361 |
if (SDL_VideoSurface->flags & SDL_RESIZABLE) {
|
slouken@761
|
1362 |
|
slouken@761
|
1363 |
Rect icon;
|
slouken@761
|
1364 |
SetRect (&icon, SDL_VideoSurface->w - 13, SDL_VideoSurface->h - 13,
|
slouken@761
|
1365 |
SDL_VideoSurface->w, SDL_VideoSurface->h);
|
slouken@761
|
1366 |
|
slouken@761
|
1367 |
if (RectInRgn (&icon, dirtyRegion)) {
|
slouken@761
|
1368 |
|
slouken@761
|
1369 |
SDL_Rect icon_rect;
|
slouken@761
|
1370 |
|
slouken@761
|
1371 |
/* Create the icon image */
|
slouken@761
|
1372 |
if (resize_icon == NULL) {
|
slouken@761
|
1373 |
|
slouken@761
|
1374 |
SDL_RWops *rw;
|
slouken@761
|
1375 |
SDL_Surface *tmp;
|
slouken@761
|
1376 |
|
slouken@768
|
1377 |
rw = SDL_RWFromConstMem (QZ_ResizeIcon, sizeof(QZ_ResizeIcon));
|
slouken@761
|
1378 |
tmp = SDL_LoadBMP_RW (rw, SDL_TRUE);
|
slouken@761
|
1379 |
|
slouken@761
|
1380 |
resize_icon = SDL_ConvertSurface (tmp, SDL_VideoSurface->format, SDL_SRCCOLORKEY);
|
slouken@761
|
1381 |
SDL_SetColorKey (resize_icon, SDL_SRCCOLORKEY, 0xFFFFFF);
|
slouken@761
|
1382 |
|
slouken@761
|
1383 |
SDL_FreeSurface (tmp);
|
slouken@761
|
1384 |
}
|
slouken@761
|
1385 |
|
slouken@761
|
1386 |
icon_rect.x = SDL_VideoSurface->w - 13;
|
slouken@761
|
1387 |
icon_rect.y = SDL_VideoSurface->h - 13;
|
slouken@761
|
1388 |
icon_rect.w = 13;
|
slouken@761
|
1389 |
icon_rect.h = 13;
|
slouken@761
|
1390 |
|
slouken@761
|
1391 |
SDL_BlitSurface (resize_icon, NULL, SDL_VideoSurface, &icon_rect);
|
slouken@761
|
1392 |
}
|
slouken@761
|
1393 |
}
|
slouken@761
|
1394 |
}
|
slouken@761
|
1395 |
|
slouken@390
|
1396 |
static void QZ_UpdateRects (_THIS, int numRects, SDL_Rect *rects) {
|
slouken@272
|
1397 |
|
slouken@47
|
1398 |
if (SDL_VideoSurface->flags & SDL_OPENGLBLIT) {
|
slouken@47
|
1399 |
QZ_GL_SwapBuffers (this);
|
slouken@47
|
1400 |
}
|
slouken@501
|
1401 |
else if ( [ qz_window isMiniaturized ] ) {
|
slouken@501
|
1402 |
|
slouken@501
|
1403 |
/* Do nothing if miniaturized */
|
slouken@272
|
1404 |
}
|
slouken@501
|
1405 |
|
slouken@272
|
1406 |
else if ( ! QZ_IsWindowObscured (qz_window) ) {
|
slouken@390
|
1407 |
|
slouken@272
|
1408 |
/* Use direct copy to flush contents to the display */
|
slouken@272
|
1409 |
CGrafPtr savePort;
|
slouken@272
|
1410 |
CGrafPtr dstPort, srcPort;
|
slouken@272
|
1411 |
const BitMap *dstBits, *srcBits;
|
slouken@390
|
1412 |
Rect dstRect, srcRect;
|
slouken@272
|
1413 |
Point offset;
|
slouken@272
|
1414 |
int i;
|
slouken@390
|
1415 |
|
slouken@272
|
1416 |
GetPort (&savePort);
|
slouken@390
|
1417 |
|
slouken@272
|
1418 |
dstPort = CreateNewPortForCGDisplayID ((UInt32)display_id);
|
slouken@272
|
1419 |
srcPort = [ window_view qdPort ];
|
slouken@390
|
1420 |
|
slouken@272
|
1421 |
offset.h = 0;
|
slouken@272
|
1422 |
offset.v = 0;
|
slouken@272
|
1423 |
SetPort (srcPort);
|
slouken@272
|
1424 |
LocalToGlobal (&offset);
|
slouken@390
|
1425 |
|
slouken@272
|
1426 |
SetPort (dstPort);
|
slouken@390
|
1427 |
|
slouken@272
|
1428 |
LockPortBits (dstPort);
|
slouken@272
|
1429 |
LockPortBits (srcPort);
|
slouken@390
|
1430 |
|
slouken@272
|
1431 |
dstBits = GetPortBitMapForCopyBits (dstPort);
|
slouken@272
|
1432 |
srcBits = GetPortBitMapForCopyBits (srcPort);
|
slouken@390
|
1433 |
|
slouken@272
|
1434 |
for (i = 0; i < numRects; i++) {
|
slouken@390
|
1435 |
|
slouken@272
|
1436 |
SetRect (&srcRect, rects[i].x, rects[i].y,
|
slouken@272
|
1437 |
rects[i].x + rects[i].w,
|
slouken@272
|
1438 |
rects[i].y + rects[i].h);
|
slouken@390
|
1439 |
|
slouken@272
|
1440 |
SetRect (&dstRect,
|
slouken@390
|
1441 |
rects[i].x + offset.h,
|
slouken@272
|
1442 |
rects[i].y + offset.v,
|
slouken@272
|
1443 |
rects[i].x + rects[i].w + offset.h,
|
slouken@272
|
1444 |
rects[i].y + rects[i].h + offset.v);
|
slouken@390
|
1445 |
|
slouken@272
|
1446 |
CopyBits (srcBits, dstBits,
|
slouken@272
|
1447 |
&srcRect, &dstRect, srcCopy, NULL);
|
slouken@390
|
1448 |
|
slouken@272
|
1449 |
}
|
slouken@390
|
1450 |
|
slouken@272
|
1451 |
SetPort (savePort);
|
slouken@272
|
1452 |
}
|
slouken@47
|
1453 |
else {
|
slouken@272
|
1454 |
/* Use QDFlushPortBuffer() to flush content to display */
|
slouken@47
|
1455 |
int i;
|
slouken@47
|
1456 |
RgnHandle dirty = NewRgn ();
|
slouken@47
|
1457 |
RgnHandle temp = NewRgn ();
|
slouken@390
|
1458 |
|
slouken@47
|
1459 |
SetEmptyRgn (dirty);
|
slouken@390
|
1460 |
|
slouken@47
|
1461 |
/* Build the region of dirty rectangles */
|
slouken@47
|
1462 |
for (i = 0; i < numRects; i++) {
|
slouken@390
|
1463 |
|
slouken@390
|
1464 |
MacSetRectRgn (temp, rects[i].x, rects[i].y,
|
slouken@501
|
1465 |
rects[i].x + rects[i].w, rects[i].y + rects[i].h);
|
slouken@47
|
1466 |
MacUnionRgn (dirty, temp, dirty);
|
slouken@47
|
1467 |
}
|
slouken@390
|
1468 |
|
slouken@501
|
1469 |
QZ_DrawResizeIcon (this, dirty);
|
slouken@501
|
1470 |
|
slouken@47
|
1471 |
/* Flush the dirty region */
|
slouken@272
|
1472 |
QDFlushPortBuffer ( [ window_view qdPort ], dirty );
|
slouken@47
|
1473 |
DisposeRgn (dirty);
|
slouken@47
|
1474 |
DisposeRgn (temp);
|
slouken@47
|
1475 |
}
|
slouken@47
|
1476 |
}
|
slouken@47
|
1477 |
|
slouken@47
|
1478 |
static void QZ_VideoQuit (_THIS) {
|
slouken@47
|
1479 |
|
icculus@560
|
1480 |
/* Restore gamma settings */
|
icculus@560
|
1481 |
CGDisplayRestoreColorSyncSettings ();
|
icculus@560
|
1482 |
|
icculus@560
|
1483 |
/* Ensure the cursor will be visible and working when we quit */
|
icculus@560
|
1484 |
CGDisplayShowCursor (display_id);
|
icculus@560
|
1485 |
CGAssociateMouseAndMouseCursorPosition (1);
|
icculus@560
|
1486 |
|
slouken@47
|
1487 |
QZ_UnsetVideoMode (this);
|
slouken@47
|
1488 |
CGPaletteRelease (palette);
|
slouken@47
|
1489 |
}
|
slouken@47
|
1490 |
|
slouken@674
|
1491 |
#if 0 /* Not used (apparently, it's really slow) */
|
slouken@47
|
1492 |
static int QZ_FillHWRect (_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color) {
|
slouken@47
|
1493 |
|
slouken@47
|
1494 |
CGSDisplayHWFill (display_id, rect->x, rect->y, rect->w, rect->h, color);
|
slouken@272
|
1495 |
|
slouken@47
|
1496 |
return 0;
|
slouken@47
|
1497 |
}
|
slouken@674
|
1498 |
#endif
|
slouken@47
|
1499 |
|
slouken@390
|
1500 |
static int QZ_LockHWSurface(_THIS, SDL_Surface *surface) {
|
slouken@47
|
1501 |
|
slouken@47
|
1502 |
return 1;
|
slouken@47
|
1503 |
}
|
slouken@47
|
1504 |
|
slouken@272
|
1505 |
static void QZ_UnlockHWSurface(_THIS, SDL_Surface *surface) {
|
slouken@272
|
1506 |
|
slouken@47
|
1507 |
}
|
slouken@47
|
1508 |
|
slouken@47
|
1509 |
static void QZ_FreeHWSurface (_THIS, SDL_Surface *surface) {
|
slouken@47
|
1510 |
}
|
slouken@47
|
1511 |
|
slouken@47
|
1512 |
/*
|
slouken@390
|
1513 |
int QZ_FlipHWSurface (_THIS, SDL_Surface *surface) {
|
slouken@390
|
1514 |
return 0;
|
slouken@390
|
1515 |
}
|
slouken@390
|
1516 |
*/
|
slouken@47
|
1517 |
|
slouken@47
|
1518 |
/* Gamma functions */
|
slouken@761
|
1519 |
int QZ_SetGamma (_THIS, float red, float green, float blue) {
|
slouken@47
|
1520 |
|
slouken@47
|
1521 |
const CGGammaValue min = 0.0, max = 1.0;
|
slouken@272
|
1522 |
|
slouken@272
|
1523 |
if (red == 0.0)
|
slouken@272
|
1524 |
red = FLT_MAX;
|
slouken@272
|
1525 |
else
|
slouken@272
|
1526 |
red = 1.0 / red;
|
slouken@272
|
1527 |
|
slouken@272
|
1528 |
if (green == 0.0)
|
slouken@272
|
1529 |
green = FLT_MAX;
|
slouken@272
|
1530 |
else
|
slouken@272
|
1531 |
green = 1.0 / green;
|
slouken@272
|
1532 |
|
slouken@272
|
1533 |
if (blue == 0.0)
|
slouken@272
|
1534 |
blue = FLT_MAX;
|
slouken@272
|
1535 |
else
|
slouken@272
|
1536 |
blue = 1.0 / blue;
|
slouken@390
|
1537 |
|
slouken@390
|
1538 |
if ( CGDisplayNoErr == CGSetDisplayTransferByFormula
|
slouken@390
|
1539 |
(display_id, min, max, red, min, max, green, min, max, blue) ) {
|
slouken@390
|
1540 |
|
slouken@272
|
1541 |
return 0;
|
slouken@272
|
1542 |
}
|
slouken@272
|
1543 |
else {
|
slouken@390
|
1544 |
|
slouken@47
|
1545 |
return -1;
|
slouken@272
|
1546 |
}
|
slouken@47
|
1547 |
}
|
slouken@47
|
1548 |
|
slouken@761
|
1549 |
int QZ_GetGamma (_THIS, float *red, float *green, float *blue) {
|
slouken@47
|
1550 |
|
slouken@47
|
1551 |
CGGammaValue dummy;
|
slouken@272
|
1552 |
if ( CGDisplayNoErr == CGGetDisplayTransferByFormula
|
slouken@390
|
1553 |
(display_id, &dummy, &dummy, red,
|
slouken@390
|
1554 |
&dummy, &dummy, green, &dummy, &dummy, blue) )
|
slouken@390
|
1555 |
|
slouken@272
|
1556 |
return 0;
|
slouken@272
|
1557 |
else
|
slouken@47
|
1558 |
return -1;
|
slouken@47
|
1559 |
}
|
slouken@47
|
1560 |
|
slouken@761
|
1561 |
int QZ_SetGammaRamp (_THIS, Uint16 *ramp) {
|
slouken@390
|
1562 |
|
slouken@390
|
1563 |
const CGTableCount tableSize = 255;
|
slouken@390
|
1564 |
CGGammaValue redTable[tableSize];
|
slouken@390
|
1565 |
CGGammaValue greenTable[tableSize];
|
slouken@390
|
1566 |
CGGammaValue blueTable[tableSize];
|
slouken@390
|
1567 |
|
slouken@390
|
1568 |
int i;
|
slouken@390
|
1569 |
|
slouken@390
|
1570 |
/* Extract gamma values into separate tables, convert to floats between 0.0 and 1.0 */
|
slouken@390
|
1571 |
for (i = 0; i < 256; i++)
|
slouken@390
|
1572 |
redTable[i % 256] = ramp[i] / 65535.0;
|
slouken@390
|
1573 |
|
slouken@390
|
1574 |
for (i=256; i < 512; i++)
|
slouken@390
|
1575 |
greenTable[i % 256] = ramp[i] / 65535.0;
|
slouken@390
|
1576 |
|
slouken@390
|
1577 |
for (i=512; i < 768; i++)
|
slouken@390
|
1578 |
blueTable[i % 256] = ramp[i] / 65535.0;
|
slouken@390
|
1579 |
|
slouken@390
|
1580 |
if ( CGDisplayNoErr == CGSetDisplayTransferByTable
|
slouken@390
|
1581 |
(display_id, tableSize, redTable, greenTable, blueTable) )
|
slouken@272
|
1582 |
return 0;
|
slouken@272
|
1583 |
else
|
slouken@47
|
1584 |
return -1;
|
slouken@47
|
1585 |
}
|
slouken@47
|
1586 |
|
slouken@761
|
1587 |
int QZ_GetGammaRamp (_THIS, Uint16 *ramp) {
|
slouken@390
|
1588 |
|
slouken@47
|
1589 |
const CGTableCount tableSize = 255;
|
slouken@47
|
1590 |
CGGammaValue redTable[tableSize];
|
slouken@47
|
1591 |
CGGammaValue greenTable[tableSize];
|
slouken@47
|
1592 |
CGGammaValue blueTable[tableSize];
|
slouken@47
|
1593 |
CGTableCount actual;
|
slouken@47
|
1594 |
int i;
|
slouken@390
|
1595 |
|
slouken@390
|
1596 |
if ( CGDisplayNoErr != CGGetDisplayTransferByTable
|
slouken@390
|
1597 |
(display_id, tableSize, redTable, greenTable, blueTable, &actual) ||
|
slouken@390
|
1598 |
actual != tableSize)
|
slouken@390
|
1599 |
|
slouken@47
|
1600 |
return -1;
|
slouken@390
|
1601 |
|
slouken@47
|
1602 |
/* Pack tables into one array, with values from 0 to 65535 */
|
slouken@47
|
1603 |
for (i = 0; i < 256; i++)
|
slouken@47
|
1604 |
ramp[i] = redTable[i % 256] * 65535.0;
|
slouken@390
|
1605 |
|
slouken@47
|
1606 |
for (i=256; i < 512; i++)
|
slouken@47
|
1607 |
ramp[i] = greenTable[i % 256] * 65535.0;
|
slouken@390
|
1608 |
|
slouken@47
|
1609 |
for (i=512; i < 768; i++)
|
slouken@47
|
1610 |
ramp[i] = blueTable[i % 256] * 65535.0;
|
slouken@390
|
1611 |
|
slouken@390
|
1612 |
return 0;
|
slouken@47
|
1613 |
}
|
slouken@47
|
1614 |
|