comparison src/video/quartz/SDL_QuartzVideo.m @ 272:d1447a846d80

Date: Sat, 19 Jan 2002 17:24:32 -0500 (EST) From: Darrell Walisser <dwaliss1@purdue.edu> Subject: SDL Quartz video update -better mouse motion events -fixed minification bugs (except OpenGL) -fixed QZ_SetGamma for correct semantics -fade/unfade display before/after rez switch -experimental obscured-check/blind-copy code The obscured code, while it speeds up window drawing substantially, isn't ready yet. The reason is that there doesn't (yet) seem to be a way to know when the window is dragged or when the window suddenly comes to the foreground. Since Carbon windows seem to allow detection of such things, I suspect it is possible through some window server API. Cocoa(NSWindow) has no functions for such things, AFAIK.
author Sam Lantinga <slouken@libsdl.org>
date Tue, 22 Jan 2002 18:46:28 +0000
parents e8157fcb3114
children f6ffac90895c
comparison
equal deleted inserted replaced
271:9631db4d9ee1 272:d1447a846d80
30 /* Include files into one compile unit...break apart eventually */ 30 /* Include files into one compile unit...break apart eventually */
31 #include "SDL_QuartzWM.m" 31 #include "SDL_QuartzWM.m"
32 #include "SDL_QuartzEvents.m" 32 #include "SDL_QuartzEvents.m"
33 #include "SDL_QuartzWindow.m" 33 #include "SDL_QuartzWindow.m"
34 34
35
35 /* Bootstrap binding, enables entry point into the driver */ 36 /* Bootstrap binding, enables entry point into the driver */
36 VideoBootStrap QZ_bootstrap = { 37 VideoBootStrap QZ_bootstrap = {
37 "Quartz", "MacOS X CoreGraphics", QZ_Available, QZ_CreateDevice 38 "Quartz", "Mac OS X CoreGraphics", QZ_Available, QZ_CreateDevice
38 }; 39 };
39 40
40 /* Bootstrap functions */ 41 /* Bootstrap functions */
41 static int QZ_Available () { 42 static int QZ_Available () {
42 return 1; 43 return 1;
43 } 44 }
44 45
45 static SDL_VideoDevice* QZ_CreateDevice (int device_index) { 46 static SDL_VideoDevice* QZ_CreateDevice (int device_index) {
46 47
47 #pragma unused (device_index) 48 #pragma unused (device_index)
48 49
49 SDL_VideoDevice *device; 50 SDL_VideoDevice *device;
50 SDL_PrivateVideoData *hidden; 51 SDL_PrivateVideoData *hidden;
51 52
52 device = (SDL_VideoDevice*) malloc (sizeof (*device) ); 53 device = (SDL_VideoDevice*) malloc (sizeof (*device) );
55 if (device == NULL || hidden == NULL) 56 if (device == NULL || hidden == NULL)
56 SDL_OutOfMemory (); 57 SDL_OutOfMemory ();
57 58
58 memset (device, 0, sizeof (*device) ); 59 memset (device, 0, sizeof (*device) );
59 memset (hidden, 0, sizeof (*hidden) ); 60 memset (hidden, 0, sizeof (*hidden) );
60 61
61 device->hidden = hidden; 62 device->hidden = hidden;
62 63
63 device->VideoInit = QZ_VideoInit; 64 device->VideoInit = QZ_VideoInit;
64 device->ListModes = QZ_ListModes; 65 device->ListModes = QZ_ListModes;
65 device->SetVideoMode = QZ_SetVideoMode; 66 device->SetVideoMode = QZ_SetVideoMode;
66 device->ToggleFullScreen = QZ_ToggleFullScreen; 67 device->ToggleFullScreen = QZ_ToggleFullScreen;
67 device->SetColors = QZ_SetColors; 68 device->SetColors = QZ_SetColors;
68 /* device->UpdateRects = QZ_UpdateRects; this is determined by SetVideoMode() */ 69 /* device->UpdateRects = QZ_UpdateRects; this is determined by SetVideoMode() */
69 device->VideoQuit = QZ_VideoQuit; 70 device->VideoQuit = QZ_VideoQuit;
70 71
71 device->LockHWSurface = QZ_LockHWSurface; 72 device->LockHWSurface = QZ_LockHWSurface;
72 device->UnlockHWSurface = QZ_UnlockHWSurface; 73 device->UnlockHWSurface = QZ_UnlockHWSurface;
73 device->FreeHWSurface = QZ_FreeHWSurface; 74 device->FreeHWSurface = QZ_FreeHWSurface;
74 /* device->FlipHWSurface = QZ_FlipHWSurface */; 75 /* device->FlipHWSurface = QZ_FlipHWSurface */;
75 76
81 device->GL_GetProcAddress = QZ_GL_GetProcAddress; 82 device->GL_GetProcAddress = QZ_GL_GetProcAddress;
82 device->GL_GetAttribute = QZ_GL_GetAttribute; 83 device->GL_GetAttribute = QZ_GL_GetAttribute;
83 device->GL_MakeCurrent = QZ_GL_MakeCurrent; 84 device->GL_MakeCurrent = QZ_GL_MakeCurrent;
84 device->GL_SwapBuffers = QZ_GL_SwapBuffers; 85 device->GL_SwapBuffers = QZ_GL_SwapBuffers;
85 device->GL_LoadLibrary = QZ_GL_LoadLibrary; 86 device->GL_LoadLibrary = QZ_GL_LoadLibrary;
86 87
87 device->FreeWMCursor = QZ_FreeWMCursor; 88 device->FreeWMCursor = QZ_FreeWMCursor;
88 device->CreateWMCursor = QZ_CreateWMCursor; 89 device->CreateWMCursor = QZ_CreateWMCursor;
89 device->ShowWMCursor = QZ_ShowWMCursor; 90 device->ShowWMCursor = QZ_ShowWMCursor;
90 device->WarpWMCursor = QZ_WarpWMCursor; 91 device->WarpWMCursor = QZ_WarpWMCursor;
91 device->MoveWMCursor = QZ_MoveWMCursor; 92 device->MoveWMCursor = QZ_MoveWMCursor;
96 device->SetCaption = QZ_SetCaption; 97 device->SetCaption = QZ_SetCaption;
97 device->SetIcon = QZ_SetIcon; 98 device->SetIcon = QZ_SetIcon;
98 device->IconifyWindow = QZ_IconifyWindow; 99 device->IconifyWindow = QZ_IconifyWindow;
99 /*device->GetWMInfo = QZ_GetWMInfo;*/ 100 /*device->GetWMInfo = QZ_GetWMInfo;*/
100 device->GrabInput = QZ_GrabInput; 101 device->GrabInput = QZ_GrabInput;
101 102
102 device->free = QZ_DeleteDevice; 103 device->free = QZ_DeleteDevice;
103 104
104 return device; 105 return device;
105 } 106 }
106 107
107 static void QZ_DeleteDevice (SDL_VideoDevice *device) { 108 static void QZ_DeleteDevice (SDL_VideoDevice *device) {
108 109
110 free (device); 111 free (device);
111 } 112 }
112 113
113 static int QZ_VideoInit (_THIS, SDL_PixelFormat *video_format) { 114 static int QZ_VideoInit (_THIS, SDL_PixelFormat *video_format) {
114 115
115 /* Initialize the video settings; this data persists between mode switches */ 116 /* Initialize the video settings; this data persists between mode switches */
116 display_id = kCGDirectMainDisplay; 117 display_id = kCGDirectMainDisplay;
117 save_mode = CGDisplayCurrentMode (display_id); 118 save_mode = CGDisplayCurrentMode (display_id);
118 mode_list = CGDisplayAvailableModes (display_id); 119 mode_list = CGDisplayAvailableModes (display_id);
119 palette = CGPaletteCreateDefaultColorPalette (); 120 palette = CGPaletteCreateDefaultColorPalette ();
120 121
121 /* Gather some information that is useful to know about the display */ 122 /* Gather some information that is useful to know about the display */
122 CFNumberGetValue (CFDictionaryGetValue (save_mode, kCGDisplayBitsPerPixel), 123 CFNumberGetValue (CFDictionaryGetValue (save_mode, kCGDisplayBitsPerPixel),
123 kCFNumberSInt32Type, &device_bpp); 124 kCFNumberSInt32Type, &device_bpp);
124 125
125 CFNumberGetValue (CFDictionaryGetValue (save_mode, kCGDisplayWidth), 126 CFNumberGetValue (CFDictionaryGetValue (save_mode, kCGDisplayWidth),
126 kCFNumberSInt32Type, &device_width); 127 kCFNumberSInt32Type, &device_width);
127 128
128 CFNumberGetValue (CFDictionaryGetValue (save_mode, kCGDisplayHeight), 129 CFNumberGetValue (CFDictionaryGetValue (save_mode, kCGDisplayHeight),
129 kCFNumberSInt32Type, &device_height); 130 kCFNumberSInt32Type, &device_height);
130 131
131 video_format->BitsPerPixel = device_bpp; 132 video_format->BitsPerPixel = device_bpp;
132 133
133 return 0; 134 return 0;
134 } 135 }
135 136
136 static SDL_Rect** QZ_ListModes (_THIS, SDL_PixelFormat *format, Uint32 flags) { 137 static SDL_Rect** QZ_ListModes (_THIS, SDL_PixelFormat *format, Uint32 flags) {
137 138
138 CFIndex num_modes = CFArrayGetCount (mode_list); 139 CFIndex num_modes;
139 CFIndex i; 140 CFIndex i;
140 141
141 static SDL_Rect **list = NULL; 142 static SDL_Rect **list = NULL;
142 int list_size = 0; 143 int list_size = 0;
143 144
155 156
156 free (list); 157 free (list);
157 list = NULL; 158 list = NULL;
158 } 159 }
159 160
161 num_modes = CFArrayGetCount (mode_list);
162
160 /* Build list of modes with the requested bpp */ 163 /* Build list of modes with the requested bpp */
161 for (i = 0; i < num_modes; i++) { 164 for (i = 0; i < num_modes; i++) {
162 165
163 CFDictionaryRef onemode; 166 CFDictionaryRef onemode;
164 CFNumberRef number; 167 CFNumberRef number;
199 202
200 SDL_Rect *rect; 203 SDL_Rect *rect;
201 204
202 list_size++; 205 list_size++;
203 206
204 if ( list == NULL) 207 if (list == NULL)
205 list = (SDL_Rect**) malloc (sizeof(*list) * list_size+1); 208 list = (SDL_Rect**) malloc (sizeof(*list) * (list_size+1) );
206 else 209 else
207 list = (SDL_Rect**) realloc (list, sizeof(*list) * list_size+1); 210 list = (SDL_Rect**) realloc (list, sizeof(*list) * (list_size+1));
208 211
209 rect = (SDL_Rect*) malloc (sizeof(**list)); 212 rect = (SDL_Rect*) malloc (sizeof(**list));
210 213
211 if (list == NULL || rect == NULL) 214 if (list == NULL || rect == NULL) {
212 SDL_OutOfMemory (); 215 SDL_OutOfMemory ();
213 216 return NULL;
217 }
218
214 rect->w = width; 219 rect->w = width;
215 rect->h = height; 220 rect->h = height;
216 221
217 list[list_size-1] = rect; 222 list[list_size-1] = rect;
218 list[list_size] = NULL; 223 list[list_size] = NULL;
239 } 244 }
240 } 245 }
241 return list; 246 return list;
242 } 247 }
243 248
249 /* Gamma functions to try to hide the flash from a rez switch */
250 /* Fade the display from normal to black */
251 /* Save gamma tables for fade back to normal */
252 static UInt32 QZ_FadeGammaOut (_THIS, SDL_QuartzGammaTable *table) {
253
254 CGGammaValue redTable[QZ_GAMMA_TABLE_SIZE],
255 greenTable[QZ_GAMMA_TABLE_SIZE],
256 blueTable[QZ_GAMMA_TABLE_SIZE];
257
258 float percent;
259 int j;
260 int actual;
261
262 if ( (CGDisplayNoErr != CGGetDisplayTransferByTable
263 (display_id, QZ_GAMMA_TABLE_SIZE,
264 table->red, table->green, table->blue, &actual)) ||
265 actual != QZ_GAMMA_TABLE_SIZE) {
266
267 return 1;
268 }
269
270 memcpy (redTable, table->red, sizeof(redTable));
271 memcpy (greenTable, table->green, sizeof(greenTable));
272 memcpy (blueTable, table->blue, sizeof(greenTable));
273
274 for (percent = 1.0; percent >= 0.0; percent -= 0.01) {
275
276 for (j = 0; j < QZ_GAMMA_TABLE_SIZE; j++) {
277
278 redTable[j] = redTable[j] * percent;
279 greenTable[j] = greenTable[j] * percent;
280 blueTable[j] = blueTable[j] * percent;
281 }
282
283 if (CGDisplayNoErr != CGSetDisplayTransferByTable
284 (display_id, QZ_GAMMA_TABLE_SIZE,
285 redTable, greenTable, blueTable)) {
286
287 CGDisplayRestoreColorSyncSettings();
288 return 1;
289 }
290
291 SDL_Delay (10);
292 }
293
294 return 0;
295 }
296
297 /* Fade the display from black to normal */
298 /* Restore previously saved gamma values */
299 static UInt32 QZ_FadeGammaIn (_THIS, SDL_QuartzGammaTable *table) {
300
301 CGGammaValue redTable[QZ_GAMMA_TABLE_SIZE],
302 greenTable[QZ_GAMMA_TABLE_SIZE],
303 blueTable[QZ_GAMMA_TABLE_SIZE];
304
305 float percent;
306 int j;
307
308 memset (redTable, 0, sizeof(redTable));
309 memset (greenTable, 0, sizeof(greenTable));
310 memset (blueTable, 0, sizeof(greenTable));
311
312 for (percent = 0.0; percent <= 1.0; percent += 0.01) {
313
314 for (j = 0; j < QZ_GAMMA_TABLE_SIZE; j++) {
315
316 redTable[j] = table->red[j] * percent;
317 greenTable[j] = table->green[j] * percent;
318 blueTable[j] = table->blue[j] * percent;
319 }
320
321 if (CGDisplayNoErr != CGSetDisplayTransferByTable
322 (display_id, QZ_GAMMA_TABLE_SIZE,
323 redTable, greenTable, blueTable)) {
324
325 CGDisplayRestoreColorSyncSettings();
326 return 1;
327 }
328
329 SDL_Delay (10);
330 }
331
332 return 0;
333 }
334
244 static void QZ_UnsetVideoMode (_THIS) { 335 static void QZ_UnsetVideoMode (_THIS) {
245 336
246 /* Reset values that may change between switches */ 337 /* Reset values that may change between switches */
247 this->info.blit_fill = 0; 338 this->info.blit_fill = 0;
248 this->FillHWRect = NULL; 339 this->FillHWRect = NULL;
249 this->UpdateRects = NULL; 340 this->UpdateRects = NULL;
250
251 /* Restore gamma settings */
252 CGDisplayRestoreColorSyncSettings ();
253 341
254 /* Restore original screen resolution */ 342 /* Release fullscreen resources */
255 if ( mode_flags & SDL_FULLSCREEN ) { 343 if ( mode_flags & SDL_FULLSCREEN ) {
344
345 SDL_QuartzGammaTable gamma_table;
346 int gamma_error;
347
348 gamma_error = QZ_FadeGammaOut (this, &gamma_table);
349
350 /* Release the OpenGL context */
351 /* Do this first to avoid trash on the display before fade */
352 if ( mode_flags & SDL_OPENGL )
353 QZ_TearDownOpenGL (this);
354
256 if (mode_flags & SDL_OPENGL) 355 if (mode_flags & SDL_OPENGL)
257 CGLSetFullScreen(NULL); 356 CGLSetFullScreen(NULL);
258 357
358 /* Restore original screen resolution/bpp */
259 CGDisplaySwitchToMode (display_id, save_mode); 359 CGDisplaySwitchToMode (display_id, save_mode);
260 CGDisplayRelease (display_id); 360 CGDisplayRelease (display_id);
261 } 361 ShowMenuBar ();
262 /* Release window mode data structures */ 362
363 if (! gamma_error)
364 QZ_FadeGammaIn (this, &gamma_table);
365 }
366 /* Release window mode resources */
263 else { 367 else {
264 if ( (mode_flags & SDL_OPENGL) == 0 ) { 368 if ( (mode_flags & SDL_OPENGL) == 0 ) {
265 UnlockPortBits ( [ windowView qdPort ] ); 369 UnlockPortBits ( [ window_view qdPort ] );
266 [ windowView release ]; 370 [ window_view release ];
267 } 371 }
268 [ qz_window setContentView:nil ]; 372 [ qz_window setContentView:nil ];
269 [ qz_window setDelegate:nil ]; 373 [ qz_window setDelegate:nil ];
270 [ qz_window close ]; 374 [ qz_window close ];
271 } 375 [ qz_window release ];
376
377 /* Release the OpenGL context */
378 if ( mode_flags & SDL_OPENGL )
379 QZ_TearDownOpenGL (this);
380 }
381
382 /* Restore gamma settings */
383 CGDisplayRestoreColorSyncSettings ();
272 384
273 /* Set pixels to null (so other code doesn't try to free it) */ 385 /* Set pixels to null (so other code doesn't try to free it) */
274 if (this->screen != NULL) 386 if (this->screen != NULL)
275 this->screen->pixels = NULL; 387 this->screen->pixels = NULL;
276 388
277 /* Release the OpenGL context */
278 if ( mode_flags & SDL_OPENGL )
279 QZ_TearDownOpenGL (this);
280
281 /* Ensure the cursor will be visible and working when we quit */ 389 /* Ensure the cursor will be visible and working when we quit */
282 CGDisplayShowCursor (display_id); 390 CGDisplayShowCursor (display_id);
283 CGAssociateMouseAndMouseCursorPosition (1); 391 CGAssociateMouseAndMouseCursorPosition (1);
284 392
285 /* Signal successful teardown */ 393 /* Signal successful teardown */
287 } 395 }
288 396
289 static SDL_Surface* QZ_SetVideoFullScreen (_THIS, SDL_Surface *current, int width, 397 static SDL_Surface* QZ_SetVideoFullScreen (_THIS, SDL_Surface *current, int width,
290 int height, int bpp, Uint32 flags) { 398 int height, int bpp, Uint32 flags) {
291 int exact_match; 399 int exact_match;
292 400 int gamma_error;
401 SDL_QuartzGammaTable gamma_table;
402
293 /* See if requested mode exists */ 403 /* See if requested mode exists */
294 mode = CGDisplayBestModeForParameters (display_id, bpp, width, 404 mode = CGDisplayBestModeForParameters (display_id, bpp, width,
295 height, &exact_match); 405 height, &exact_match);
296 406
297 /* Require an exact match to the requested mode */ 407 /* Require an exact match to the requested mode */
299 sprintf (QZ_Error, "Failed to find display resolution: %dx%dx%d", width, height, bpp); 409 sprintf (QZ_Error, "Failed to find display resolution: %dx%dx%d", width, height, bpp);
300 SDL_SetError (QZ_Error); 410 SDL_SetError (QZ_Error);
301 goto ERR_NO_MATCH; 411 goto ERR_NO_MATCH;
302 } 412 }
303 413
414 /* Fade display to zero gamma */
415 gamma_error = QZ_FadeGammaOut (this, &gamma_table);
416
304 /* Put up the blanking window (a window above all other windows) */ 417 /* Put up the blanking window (a window above all other windows) */
305 if ( CGDisplayNoErr != CGDisplayCapture (display_id) ) { 418 if ( CGDisplayNoErr != CGDisplayCapture (display_id) ) {
306 SDL_SetError ("Failed capturing display"); 419 SDL_SetError ("Failed capturing display");
307 goto ERR_NO_CAPTURE; 420 goto ERR_NO_CAPTURE;
308 } 421 }
422
309 423
310 /* Do the physical switch */ 424 /* Do the physical switch */
311 if ( CGDisplayNoErr != CGDisplaySwitchToMode (display_id, mode) ) { 425 if ( CGDisplayNoErr != CGDisplaySwitchToMode (display_id, mode) ) {
312 SDL_SetError ("Failed switching display resolution"); 426 SDL_SetError ("Failed switching display resolution");
313 goto ERR_NO_SWITCH; 427 goto ERR_NO_SWITCH;
314 } 428 }
315 429
316 /* None of these methods seem to fix the fullscreen artifacts bug(s) */
317 #if USE_GDHANDLE
318 SetGDevice(GetMainDevice());
319 current->pitch = (**(** GetMainDevice() ).gdPMap).rowBytes & 0x3FFF;
320 current->pixels = (**(** GetMainDevice() ).gdPMap).baseAddr;
321 #elif USE_CREATEPORT
322 device_port = CreateNewPortForCGDisplayID((Uint32*)display_id);
323 SetPort (device_port);
324 LockPortBits ( device_port );
325 current->pixels = GetPixBaseAddr ( GetPortPixMap ( device_port ) );
326 current->pitch = GetPixRowBytes ( GetPortPixMap ( device_port ) );
327 UnlockPortBits ( device_port );
328 #else
329 current->pixels = (Uint32*) CGDisplayBaseAddress (display_id); 430 current->pixels = (Uint32*) CGDisplayBaseAddress (display_id);
330 current->pitch = CGDisplayBytesPerRow (display_id); 431 current->pitch = CGDisplayBytesPerRow (display_id);
331 #endif
332 432
333 current->flags = 0; 433 current->flags = 0;
334 current->w = width; 434 current->w = width;
335 current->h = height; 435 current->h = height;
336 current->flags |= SDL_FULLSCREEN; 436 current->flags |= SDL_FULLSCREEN;
352 452
353 CGLError err; 453 CGLError err;
354 CGLContextObj ctx; 454 CGLContextObj ctx;
355 455
356 if ( ! QZ_SetupOpenGL (this, bpp, flags) ) { 456 if ( ! QZ_SetupOpenGL (this, bpp, flags) ) {
357 return NULL; 457 goto ERR_NO_GL;
358 } 458 }
359 459
360 ctx = [ gl_context cglContext ]; 460 ctx = [ gl_context cglContext ];
361 err = CGLSetFullScreen (ctx); 461 err = CGLSetFullScreen (ctx);
362 462
365 SDL_SetError (QZ_Error); 465 SDL_SetError (QZ_Error);
366 goto ERR_NO_GL; 466 goto ERR_NO_GL;
367 } 467 }
368 468
369 [ gl_context makeCurrentContext]; 469 [ gl_context makeCurrentContext];
470
471 glClear (GL_COLOR_BUFFER_BIT);
472
473 [ gl_context flushBuffer ];
370 474
371 current->flags |= SDL_OPENGL; 475 current->flags |= SDL_OPENGL;
372 } 476 }
373 477
374 /* If we don't hide menu bar, it will get events and interrupt the program */ 478 /* If we don't hide menu bar, it will get events and interrupt the program */
375 HideMenuBar (); 479 HideMenuBar ();
480
481 /* Fade the display to original gamma */
482 if (! gamma_error )
483 QZ_FadeGammaIn (this, &gamma_table);
376 484
377 /* Save the flags to ensure correct tear-down */ 485 /* Save the flags to ensure correct tear-down */
378 mode_flags = current->flags; 486 mode_flags = current->flags;
379 487
380 return current; 488 return current;
381 489
382 /* Since the blanking window covers *all* windows (even force quit) correct recovery is crutial */ 490 /* Since the blanking window covers *all* windows (even force quit) correct recovery is crucial */
383 ERR_NO_GL: CGDisplaySwitchToMode (display_id, save_mode); 491 ERR_NO_GL: CGDisplaySwitchToMode (display_id, save_mode);
384 ERR_NO_SWITCH: CGDisplayRelease (display_id); 492 ERR_NO_SWITCH: CGDisplayRelease (display_id);
385 ERR_NO_CAPTURE: 493 ERR_NO_CAPTURE: if (!gamma_error) { QZ_FadeGammaIn (this, &gamma_table); }
386 ERR_NO_MATCH: return NULL; 494 ERR_NO_MATCH: return NULL;
387 } 495 }
388 496
389 static SDL_Surface* QZ_SetVideoWindowed (_THIS, SDL_Surface *current, int width, 497 static SDL_Surface* QZ_SetVideoWindowed (_THIS, SDL_Surface *current, int width,
390 int height, int bpp, Uint32 flags) { 498 int height, int bpp, Uint32 flags) {
438 current->flags |= SDL_OPENGL; 546 current->flags |= SDL_OPENGL;
439 } 547 }
440 /* For 2D, we set the content view to a NSQuickDrawView */ 548 /* For 2D, we set the content view to a NSQuickDrawView */
441 else { 549 else {
442 550
443 windowView = [ [ NSQuickDrawView alloc ] init ]; 551 window_view = [ [ SDL_QuartzWindowView alloc ] init ];
444 [ qz_window setContentView:windowView ]; 552 [ qz_window setContentView:window_view ];
445 [ qz_window makeKeyAndOrderFront:nil ]; 553 [ qz_window makeKeyAndOrderFront:nil ];
446 554
447 LockPortBits ( [ windowView qdPort ] ); 555 LockPortBits ( [ window_view qdPort ] );
448 current->pixels = GetPixBaseAddr ( GetPortPixMap ( [ windowView qdPort ] ) ); 556 current->pixels = GetPixBaseAddr ( GetPortPixMap ( [ window_view qdPort ] ) );
449 current->pitch = GetPixRowBytes ( GetPortPixMap ( [ windowView qdPort ] ) ); 557 current->pitch = GetPixRowBytes ( GetPortPixMap ( [ window_view qdPort ] ) );
450 558
451 current->flags |= SDL_SWSURFACE; 559 current->flags |= SDL_SWSURFACE;
452 current->flags |= SDL_PREALLOC; 560 current->flags |= SDL_PREALLOC;
561
453 if ( flags & SDL_NOFRAME ) 562 if ( flags & SDL_NOFRAME )
454 current->flags |= SDL_NOFRAME; 563 current->flags |= SDL_NOFRAME;
455 if ( flags & SDL_RESIZABLE ) 564 if ( flags & SDL_RESIZABLE )
456 current->flags |= SDL_RESIZABLE; 565 current->flags |= SDL_RESIZABLE;
457 566
460 current->pixels += 22 * current->pitch; 569 current->pixels += 22 * current->pitch;
461 } 570 }
462 571
463 this->UpdateRects = QZ_UpdateRects; 572 this->UpdateRects = QZ_UpdateRects;
464 } 573 }
574
575 /* Save flags to ensure correct teardown */
576 mode_flags = current->flags;
577
465 return current; 578 return current;
466 } 579 }
467 580
468 static SDL_Surface* QZ_SetVideoMode (_THIS, SDL_Surface *current, int width, 581 static SDL_Surface* QZ_SetVideoMode (_THIS, SDL_Surface *current, int width,
469 int height, int bpp, Uint32 flags) { 582 int height, int bpp, Uint32 flags) {
480 return NULL; 593 return NULL;
481 } 594 }
482 /* Setup windowed video */ 595 /* Setup windowed video */
483 else { 596 else {
484 /* Force bpp to the device's bpp */ 597 /* Force bpp to the device's bpp */
485 bpp = current->format->BitsPerPixel; 598 bpp = device_bpp;
486 current = QZ_SetVideoWindowed (this, current, width, height, bpp, flags); 599 current = QZ_SetVideoWindowed (this, current, width, height, bpp, flags);
487 if (current == NULL) 600 if (current == NULL)
488 return NULL; 601 return NULL;
489 } 602 }
490 603
518 SDL_SetError ("Couldn't reallocate pixel format"); 631 SDL_SetError ("Couldn't reallocate pixel format");
519 return NULL; 632 return NULL;
520 } 633 }
521 } 634 }
522 635
523 /* Warp mouse to origin in order to get passive mouse motion events started correctly */ 636 /* Signal successful completion (used internally) */
524 QZ_PrivateWarpCursor (this, current->flags & SDL_FULLSCREEN, height, 0, 0);
525
526 /* Signal successful completion */
527 video_set = SDL_TRUE; 637 video_set = SDL_TRUE;
528 638
529 return current; 639 return current;
530 } 640 }
531 641
559 669
560 static void QZ_DirectUpdate (_THIS, int num_rects, SDL_Rect *rects) { 670 static void QZ_DirectUpdate (_THIS, int num_rects, SDL_Rect *rects) {
561 #pragma unused(this,num_rects,rects) 671 #pragma unused(this,num_rects,rects)
562 } 672 }
563 673
674 /**
675 * The obscured code is based on work by Matt Slot fprefect@ambrosiasw.com,
676 * who supplied sample code for Carbon.
677 **/
678 static int QZ_IsWindowObscured (NSWindow *window) {
679
680 //#define TEST_OBSCURED 1
681
682 #if TEST_OBSCURED
683
684 /* In order to determine if a direct copy to the screen is possible,
685 we must figure out if there are any windows covering ours (including shadows).
686 This can be done by querying the window server about the on screen
687 windows for their screen rectangle and window level.
688 The procedure used below is puts accuracy before speed; however, it aims to call
689 the window server the fewest number of times possible to keep things reasonable.
690 In my testing on a 300mhz G3, this routine typically takes < 2 ms. -DW
691
692 Notes:
693 -Calls into the Window Server involve IPC which is slow.
694 -Getting a rectangle seems slower than getting the window level
695 -The window list we get back is in sorted order, top to bottom
696 -On average, I suspect, most windows above ours are dock icon windows (hence optimization)
697 -Some windows above ours are always there, and cannot move or obscure us (menu bar)
698
699 Bugs:
700 -no way (yet) to deactivate direct drawing when a window is dragged,
701 or suddenly obscured, so drawing continues and can produce garbage
702 We need some kind of locking mechanism on window movement to prevent this
703
704 -deactivated normal windows use activated normal
705 window shadows (slight inaccuraccy)
706 */
707
708 /* Cache the connection to the window server */
709 static CGSConnectionID cgsConnection = (CGSConnectionID) -1;
710
711 /* Cache the dock icon windows */
712 static CGSWindowID dockIcons[kMaxWindows];
713 static int numCachedDockIcons = 0;
714
715 CGSWindowID windows[kMaxWindows];
716 CGSWindowCount i, count;
717 CGSWindowLevel winLevel;
718 CGSRect winRect;
719
720 CGSRect contentRect;
721 int windowNumber;
722 //int isMainWindow;
723 int firstDockIcon;
724 int dockIconCacheMiss;
725 int windowContentOffset;
726
727 int obscured = SDL_TRUE;
728
729 if ( [ window isVisible ] ) {
730
731 /* walk the window list looking for windows over top of
732 (or casting a shadow on) ours */
733
734 /* Get a connection to the window server */
735 /* Should probably be moved out into SetVideoMode() or InitVideo() */
736 if (cgsConnection == (CGSConnectionID) -1) {
737 cgsConnection = (CGSConnectionID) 0;
738 cgsConnection = _CGSDefaultConnection ();
739 }
740
741 if (cgsConnection) {
742
743 if ( ! [ window styleMask ] & NSBorderlessWindowMask )
744 windowContentOffset = 22;
745 else
746 windowContentOffset = 0;
747
748 windowNumber = [ window windowNumber ];
749 //isMainWindow = [ window isMainWindow ];
750
751 /* The window list is sorted according to order on the screen */
752 count = 0;
753 CGSGetOnScreenWindowList (cgsConnection, 0, kMaxWindows, windows, &count);
754 CGSGetScreenRectForWindow (cgsConnection, windowNumber, &contentRect);
755
756 /* adjust rect for window title bar (if present) */
757 contentRect.origin.y += windowContentOffset;
758 contentRect.size.height -= windowContentOffset;
759
760 firstDockIcon = -1;
761 dockIconCacheMiss = SDL_FALSE;
762
763 /* The first window is always an empty window with level kCGSWindowLevelTop
764 so start at index 1 */
765 for (i = 1; i < count; i++) {
766
767 /* If we reach our window in the list, it cannot be obscured */
768 if (windows[i] == windowNumber) {
769
770 obscured = SDL_FALSE;
771 break;
772 }
773 else {
774
775 float shadowSide;
776 float shadowTop;
777 float shadowBottom;
778
779 CGSGetWindowLevel (cgsConnection, windows[i], &winLevel);
780
781 if (winLevel == kCGSWindowLevelDockIcon) {
782
783 int j;
784
785 if (firstDockIcon < 0) {
786
787 firstDockIcon = i;
788
789 if (numCachedDockIcons > 0) {
790
791 for (j = 0; j < numCachedDockIcons; j++) {
792
793 if (windows[i] == dockIcons[j])
794 i++;
795 else
796 break;
797 }
798
799 if (j != 0) {
800
801 i--;
802
803 if (j < numCachedDockIcons) {
804
805 dockIconCacheMiss = SDL_TRUE;
806 }
807 }
808
809 }
810 }
811
812 continue;
813 }
814 else if (winLevel == kCGSWindowLevelMenuIgnore
815 /* winLevel == kCGSWindowLevelTop */) {
816
817 continue; /* cannot obscure window */
818 }
819 else if (winLevel == kCGSWindowLevelDockMenu ||
820 winLevel == kCGSWindowLevelMenu) {
821
822 shadowSide = 18;
823 shadowTop = 4;
824 shadowBottom = 22;
825 }
826 else if (winLevel == kCGSWindowLevelUtility) {
827
828 shadowSide = 8;
829 shadowTop = 4;
830 shadowBottom = 12;
831 }
832 else if (winLevel == kCGSWindowLevelNormal) {
833
834 /* These numbers are for foreground windows,
835 they are too big (but will work) for background windows */
836 shadowSide = 20;
837 shadowTop = 10;
838 shadowBottom = 24;
839 }
840 else if (winLevel == kCGSWindowLevelDock) {
841
842 /* Create dock icon cache */
843 if (numCachedDockIcons != (i-firstDockIcon) ||
844 dockIconCacheMiss) {
845
846 numCachedDockIcons = i - firstDockIcon;
847 memcpy (dockIcons, &(windows[firstDockIcon]),
848 numCachedDockIcons * sizeof(*windows));
849 }
850
851 /* no shadow */
852 shadowSide = 0;
853 shadowTop = 0;
854 shadowBottom = 0;
855 }
856 else {
857
858 /* kCGSWindowLevelDockLabel,
859 kCGSWindowLevelDock,
860 kOther??? */
861
862 /* no shadow */
863 shadowSide = 0;
864 shadowTop = 0;
865 shadowBottom = 0;
866 }
867
868 CGSGetScreenRectForWindow (cgsConnection, windows[i], &winRect);
869
870 winRect.origin.x -= shadowSide;
871 winRect.origin.y -= shadowTop;
872 winRect.size.width += shadowSide;
873 winRect.size.height += shadowBottom;
874
875 if (NSIntersectsRect (contentRect, winRect)) {
876
877 obscured = SDL_TRUE;
878 break;
879 }
880
881 } /* window was not our window */
882
883 } /* iterate over windows */
884
885 } /* get cgsConnection */
886
887 } /* window is visible */
888
889 return obscured;
890 #else
891 return SDL_TRUE;
892 #endif
893 }
894
564 static void QZ_UpdateRects (_THIS, int numRects, SDL_Rect *rects) { 895 static void QZ_UpdateRects (_THIS, int numRects, SDL_Rect *rects) {
565 896
566 if (SDL_VideoSurface->flags & SDL_OPENGLBLIT) { 897 if (SDL_VideoSurface->flags & SDL_OPENGLBLIT) {
567 QZ_GL_SwapBuffers (this); 898 QZ_GL_SwapBuffers (this);
568 } 899 }
900 else if ( [ qz_window isMiniaturized ] &&
901 ! (SDL_VideoSurface->flags & SDL_OPENGL)) {
902
903 /**
904 * Set port alpha opaque so deminiaturize looks right
905 * This isn't so nice, but there is no
906 * initial deminatureize notification (before demini starts)
907 **/
908 QZ_SetPortAlphaOpaque ([ [ qz_window contentView ] qdPort],
909 [ qz_window styleMask ] & NSBorderlessWindowMask);
910 }
911 else if ( ! QZ_IsWindowObscured (qz_window) ) {
912
913 /* Use direct copy to flush contents to the display */
914 CGrafPtr savePort;
915 CGrafPtr dstPort, srcPort;
916 const BitMap *dstBits, *srcBits;
917 Rect dstRect, srcRect;
918 Point offset;
919 int i;
920
921 GetPort (&savePort);
922
923 dstPort = CreateNewPortForCGDisplayID ((UInt32)display_id);
924 srcPort = [ window_view qdPort ];
925
926 offset.h = 0;
927 offset.v = 0;
928 SetPort (srcPort);
929 LocalToGlobal (&offset);
930
931 SetPort (dstPort);
932
933 LockPortBits (dstPort);
934 LockPortBits (srcPort);
935
936 dstBits = GetPortBitMapForCopyBits (dstPort);
937 srcBits = GetPortBitMapForCopyBits (srcPort);
938
939 for (i = 0; i < numRects; i++) {
940
941 SetRect (&srcRect, rects[i].x, rects[i].y,
942 rects[i].x + rects[i].w,
943 rects[i].y + rects[i].h);
944
945 SetRect (&dstRect,
946 rects[i].x + offset.h,
947 rects[i].y + offset.v,
948 rects[i].x + rects[i].w + offset.h,
949 rects[i].y + rects[i].h + offset.v);
950
951 CopyBits (srcBits, dstBits,
952 &srcRect, &dstRect, srcCopy, NULL);
953
954 }
955
956 SetPort (savePort);
957 }
569 else { 958 else {
959
960 /* Use QDFlushPortBuffer() to flush content to display */
570 int i; 961 int i;
571 RgnHandle dirty = NewRgn (); 962 RgnHandle dirty = NewRgn ();
572 RgnHandle temp = NewRgn (); 963 RgnHandle temp = NewRgn ();
573 964
574 SetEmptyRgn (dirty); 965 SetEmptyRgn (dirty);
580 rects[i].x + rects[i].w, rects[i].y + rects[i].h); 971 rects[i].x + rects[i].w, rects[i].y + rects[i].h);
581 MacUnionRgn (dirty, temp, dirty); 972 MacUnionRgn (dirty, temp, dirty);
582 } 973 }
583 974
584 /* Flush the dirty region */ 975 /* Flush the dirty region */
585 QDFlushPortBuffer ( [ windowView qdPort ], dirty ); 976 QDFlushPortBuffer ( [ window_view qdPort ], dirty );
586 DisposeRgn (dirty); 977 DisposeRgn (dirty);
587 DisposeRgn (temp); 978 DisposeRgn (temp);
588 } 979 }
589 } 980 }
590 981
595 } 986 }
596 987
597 static int QZ_FillHWRect (_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color) { 988 static int QZ_FillHWRect (_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color) {
598 989
599 CGSDisplayHWFill (display_id, rect->x, rect->y, rect->w, rect->h, color); 990 CGSDisplayHWFill (display_id, rect->x, rect->y, rect->w, rect->h, color);
991
600 return 0; 992 return 0;
601 } 993 }
602 994
603 static int QZ_LockHWSurface(_THIS, SDL_Surface *surface) { 995 static int QZ_LockHWSurface(_THIS, SDL_Surface *surface) {
604 996
605 return 1; 997 return 1;
606 } 998 }
607 999
608 static void QZ_UnlockHWSurface(_THIS, SDL_Surface *surface) { 1000 static void QZ_UnlockHWSurface(_THIS, SDL_Surface *surface) {
1001
609 } 1002 }
610 1003
611 static void QZ_FreeHWSurface (_THIS, SDL_Surface *surface) { 1004 static void QZ_FreeHWSurface (_THIS, SDL_Surface *surface) {
612 } 1005 }
613 1006
619 1012
620 /* Gamma functions */ 1013 /* Gamma functions */
621 static int QZ_SetGamma (_THIS, float red, float green, float blue) { 1014 static int QZ_SetGamma (_THIS, float red, float green, float blue) {
622 1015
623 const CGGammaValue min = 0.0, max = 1.0; 1016 const CGGammaValue min = 0.0, max = 1.0;
624 1017
625 if ( CGDisplayNoErr != CGSetDisplayTransferByFormula 1018 if (red == 0.0)
626 (display_id, min, max, red, min, max, green, min, max, blue) ) 1019 red = FLT_MAX;
1020 else
1021 red = 1.0 / red;
1022
1023 if (green == 0.0)
1024 green = FLT_MAX;
1025 else
1026 green = 1.0 / green;
1027
1028 if (blue == 0.0)
1029 blue = FLT_MAX;
1030 else
1031 blue = 1.0 / blue;
1032
1033 if ( CGDisplayNoErr == CGSetDisplayTransferByFormula
1034 (display_id, min, max, red, min, max, green, min, max, blue) ) {
1035
1036 return 0;
1037 }
1038 else {
1039
627 return -1; 1040 return -1;
628 1041 }
629 return 0;
630 } 1042 }
631 1043
632 static int QZ_GetGamma (_THIS, float *red, float *green, float *blue) { 1044 static int QZ_GetGamma (_THIS, float *red, float *green, float *blue) {
633 1045
634 CGGammaValue dummy; 1046 CGGammaValue dummy;
635 if ( CGDisplayNoErr != CGGetDisplayTransferByFormula 1047 if ( CGDisplayNoErr == CGGetDisplayTransferByFormula
636 (display_id, &dummy, &dummy, red, 1048 (display_id, &dummy, &dummy, red,
637 &dummy, &dummy, green, &dummy, &dummy, blue) ) 1049 &dummy, &dummy, green, &dummy, &dummy, blue) )
638 1050
1051 return 0;
1052 else
639 return -1; 1053 return -1;
640
641 return 0;
642 } 1054 }
643 1055
644 static int QZ_SetGammaRamp (_THIS, Uint16 *ramp) { 1056 static int QZ_SetGammaRamp (_THIS, Uint16 *ramp) {
645 1057
646 const CGTableCount tableSize = 255; 1058 const CGTableCount tableSize = 255;
658 greenTable[i % 256] = ramp[i] / 65535.0; 1070 greenTable[i % 256] = ramp[i] / 65535.0;
659 1071
660 for (i=512; i < 768; i++) 1072 for (i=512; i < 768; i++)
661 blueTable[i % 256] = ramp[i] / 65535.0; 1073 blueTable[i % 256] = ramp[i] / 65535.0;
662 1074
663 if ( CGDisplayNoErr != CGSetDisplayTransferByTable 1075 if ( CGDisplayNoErr == CGSetDisplayTransferByTable
664 (display_id, tableSize, redTable, greenTable, blueTable) ) 1076 (display_id, tableSize, redTable, greenTable, blueTable) )
1077 return 0;
1078 else
665 return -1; 1079 return -1;
666
667 return 0;
668 } 1080 }
669 1081
670 static int QZ_GetGammaRamp (_THIS, Uint16 *ramp) { 1082 static int QZ_GetGammaRamp (_THIS, Uint16 *ramp) {
671 1083
672 const CGTableCount tableSize = 255; 1084 const CGTableCount tableSize = 255;
693 ramp[i] = blueTable[i % 256] * 65535.0; 1105 ramp[i] = blueTable[i % 256] * 65535.0;
694 1106
695 return 0; 1107 return 0;
696 } 1108 }
697 1109
698 /* OpenGL helper functions */ 1110 /* OpenGL helper functions (used internally) */
1111
699 static int QZ_SetupOpenGL (_THIS, int bpp, Uint32 flags) { 1112 static int QZ_SetupOpenGL (_THIS, int bpp, Uint32 flags) {
700 1113
701 NSOpenGLPixelFormatAttribute attr[32]; 1114 NSOpenGLPixelFormatAttribute attr[32];
702 NSOpenGLPixelFormat *fmt; 1115 NSOpenGLPixelFormat *fmt;
703 int i = 0; 1116 int i = 0;
759 [ NSOpenGLContext clearCurrentContext ]; 1172 [ NSOpenGLContext clearCurrentContext ];
760 [ gl_context clearDrawable ]; 1173 [ gl_context clearDrawable ];
761 [ gl_context release ]; 1174 [ gl_context release ];
762 } 1175 }
763 1176
1177
764 /* SDL OpenGL functions */ 1178 /* SDL OpenGL functions */
765 1179
766 static int QZ_GL_LoadLibrary (_THIS, const char *location) { 1180 static int QZ_GL_LoadLibrary (_THIS, const char *location) {
767 this->gl_config.driver_loaded = 1; 1181 this->gl_config.driver_loaded = 1;
768 return 1; 1182 return 1;
803 1217
804 } 1218 }
805 1219
806 CGLGetParameter (ctx, param, (long*)value); 1220 CGLGetParameter (ctx, param, (long*)value);
807 */ 1221 */
1222
808 *value = -1; 1223 *value = -1;
809 return -1; 1224 return -1;
810 } 1225 }
811 1226
812 static int QZ_GL_MakeCurrent (_THIS) { 1227 static int QZ_GL_MakeCurrent (_THIS) {
815 } 1230 }
816 1231
817 static void QZ_GL_SwapBuffers (_THIS) { 1232 static void QZ_GL_SwapBuffers (_THIS) {
818 [ gl_context flushBuffer ]; 1233 [ gl_context flushBuffer ];
819 } 1234 }
1235
1236