Mercurial > sdl-ios-xcode
comparison src/video/quartz/SDL_QuartzVideo.m @ 501:74262d2647ca
Lots of cleanups by Darrell, added the ability to resize Cocoa windows.
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Sat, 05 Oct 2002 05:07:57 +0000 |
parents | c335456c421d |
children | 2536446a92de |
comparison
equal
deleted
inserted
replaced
500:c335456c421d | 501:74262d2647ca |
---|---|
19 Sam Lantinga | 19 Sam Lantinga |
20 slouken@libsdl.org | 20 slouken@libsdl.org |
21 */ | 21 */ |
22 | 22 |
23 #include "SDL_QuartzVideo.h" | 23 #include "SDL_QuartzVideo.h" |
24 | |
25 /* Some variables to share among files, put in device structure eventually */ | |
26 static SDL_GrabMode currentGrabMode = SDL_GRAB_OFF; | |
27 static BOOL inForeground = YES; | |
28 static char QZ_Error[255]; /* Global error buffer to temporarily store more informative error messages */ | |
29 | 24 |
30 /* Include files into one compile unit...break apart eventually */ | 25 /* Include files into one compile unit...break apart eventually */ |
31 #include "SDL_QuartzWM.m" | 26 #include "SDL_QuartzWM.m" |
32 #include "SDL_QuartzEvents.m" | 27 #include "SDL_QuartzEvents.m" |
33 #include "SDL_QuartzWindow.m" | 28 #include "SDL_QuartzWindow.m" |
130 CFNumberGetValue (CFDictionaryGetValue (save_mode, kCGDisplayHeight), | 125 CFNumberGetValue (CFDictionaryGetValue (save_mode, kCGDisplayHeight), |
131 kCFNumberSInt32Type, &device_height); | 126 kCFNumberSInt32Type, &device_height); |
132 | 127 |
133 video_format->BitsPerPixel = device_bpp; | 128 video_format->BitsPerPixel = device_bpp; |
134 | 129 |
130 /* Set misc globals */ | |
131 current_grab_mode = SDL_GRAB_OFF; | |
132 in_foreground = YES; | |
133 | |
135 return 0; | 134 return 0; |
136 } | 135 } |
137 | 136 |
138 static SDL_Rect** QZ_ListModes (_THIS, SDL_PixelFormat *format, Uint32 flags) { | 137 static SDL_Rect** QZ_ListModes (_THIS, SDL_PixelFormat *format, Uint32 flags) { |
139 | 138 |
140 CFIndex num_modes; | 139 CFIndex num_modes; |
141 CFIndex i; | 140 CFIndex i; |
142 | 141 |
143 static SDL_Rect **list = NULL; | |
144 int list_size = 0; | 142 int list_size = 0; |
145 | 143 |
146 /* Any windowed mode is acceptable */ | 144 /* Any windowed mode is acceptable */ |
147 if ( (flags & SDL_FULLSCREEN) == 0 ) | 145 if ( (flags & SDL_FULLSCREEN) == 0 ) |
148 return (SDL_Rect**)-1; | 146 return (SDL_Rect**)-1; |
149 | 147 |
150 /* Free memory from previous call, if any */ | 148 /* Free memory from previous call, if any */ |
151 if ( list != NULL ) { | 149 if ( client_mode_list != NULL ) { |
152 | 150 |
153 int i; | 151 int i; |
154 | 152 |
155 for (i = 0; list[i] != NULL; i++) | 153 for (i = 0; client_mode_list[i] != NULL; i++) |
156 free (list[i]); | 154 free (client_mode_list[i]); |
157 | 155 |
158 free (list); | 156 free (client_mode_list); |
159 list = NULL; | 157 client_mode_list = NULL; |
160 } | 158 } |
161 | 159 |
162 num_modes = CFArrayGetCount (mode_list); | 160 num_modes = CFArrayGetCount (mode_list); |
163 | 161 |
164 /* Build list of modes with the requested bpp */ | 162 /* Build list of modes with the requested bpp */ |
189 /* Check if mode is already in the list */ | 187 /* Check if mode is already in the list */ |
190 { | 188 { |
191 int i; | 189 int i; |
192 hasMode = SDL_FALSE; | 190 hasMode = SDL_FALSE; |
193 for (i = 0; i < list_size; i++) { | 191 for (i = 0; i < list_size; i++) { |
194 if (list[i]->w == width && list[i]->h == height) { | 192 if (client_mode_list[i]->w == width && |
193 client_mode_list[i]->h == height) { | |
195 hasMode = SDL_TRUE; | 194 hasMode = SDL_TRUE; |
196 break; | 195 break; |
197 } | 196 } |
198 } | 197 } |
199 } | 198 } |
203 | 202 |
204 SDL_Rect *rect; | 203 SDL_Rect *rect; |
205 | 204 |
206 list_size++; | 205 list_size++; |
207 | 206 |
208 if (list == NULL) | 207 if (client_mode_list == NULL) |
209 list = (SDL_Rect**) malloc (sizeof(*list) * (list_size+1) ); | 208 client_mode_list = (SDL_Rect**) |
209 malloc (sizeof(*client_mode_list) * (list_size+1) ); | |
210 else | 210 else |
211 list = (SDL_Rect**) realloc (list, sizeof(*list) * (list_size+1)); | 211 client_mode_list = (SDL_Rect**) |
212 | 212 realloc (client_mode_list, sizeof(*client_mode_list) * (list_size+1)); |
213 rect = (SDL_Rect*) malloc (sizeof(**list)); | 213 |
214 | 214 rect = (SDL_Rect*) malloc (sizeof(**client_mode_list)); |
215 if (list == NULL || rect == NULL) { | 215 |
216 if (client_mode_list == NULL || rect == NULL) { | |
216 SDL_OutOfMemory (); | 217 SDL_OutOfMemory (); |
217 return NULL; | 218 return NULL; |
218 } | 219 } |
219 | 220 |
220 rect->w = width; | 221 rect->w = width; |
221 rect->h = height; | 222 rect->h = height; |
222 | 223 |
223 list[list_size-1] = rect; | 224 client_mode_list[list_size-1] = rect; |
224 list[list_size] = NULL; | 225 client_mode_list[list_size] = NULL; |
225 } | 226 } |
226 } | 227 } |
227 } | 228 } |
228 | 229 |
229 /* Sort list largest to smallest (by area) */ | 230 /* Sort list largest to smallest (by area) */ |
231 int i, j; | 232 int i, j; |
232 for (i = 0; i < list_size; i++) { | 233 for (i = 0; i < list_size; i++) { |
233 for (j = 0; j < list_size-1; j++) { | 234 for (j = 0; j < list_size-1; j++) { |
234 | 235 |
235 int area1, area2; | 236 int area1, area2; |
236 area1 = list[j]->w * list[j]->h; | 237 area1 = client_mode_list[j]->w * client_mode_list[j]->h; |
237 area2 = list[j+1]->w * list[j+1]->h; | 238 area2 = client_mode_list[j+1]->w * client_mode_list[j+1]->h; |
238 | 239 |
239 if (area1 < area2) { | 240 if (area1 < area2) { |
240 SDL_Rect *tmp = list[j]; | 241 SDL_Rect *tmp = client_mode_list[j]; |
241 list[j] = list[j+1]; | 242 client_mode_list[j] = client_mode_list[j+1]; |
242 list[j+1] = tmp; | 243 client_mode_list[j+1] = tmp; |
243 } | 244 } |
244 } | 245 } |
245 } | 246 } |
246 } | 247 } |
247 return list; | 248 return client_mode_list; |
248 } | 249 } |
249 | 250 |
250 /* Gamma functions to try to hide the flash from a rez switch */ | 251 /* |
251 /* Fade the display from normal to black */ | 252 Gamma functions to try to hide the flash from a rez switch |
252 /* Save gamma tables for fade back to normal */ | 253 Fade the display from normal to black |
254 Save gamma tables for fade back to normal | |
255 */ | |
253 static UInt32 QZ_FadeGammaOut (_THIS, SDL_QuartzGammaTable *table) { | 256 static UInt32 QZ_FadeGammaOut (_THIS, SDL_QuartzGammaTable *table) { |
254 | 257 |
255 CGGammaValue redTable[QZ_GAMMA_TABLE_SIZE], | 258 CGGammaValue redTable[QZ_GAMMA_TABLE_SIZE], |
256 greenTable[QZ_GAMMA_TABLE_SIZE], | 259 greenTable[QZ_GAMMA_TABLE_SIZE], |
257 blueTable[QZ_GAMMA_TABLE_SIZE]; | 260 blueTable[QZ_GAMMA_TABLE_SIZE]; |
293 } | 296 } |
294 | 297 |
295 return 0; | 298 return 0; |
296 } | 299 } |
297 | 300 |
298 /* Fade the display from black to normal */ | 301 /* |
299 /* Restore previously saved gamma values */ | 302 Fade the display from black to normal |
303 Restore previously saved gamma values | |
304 */ | |
300 static UInt32 QZ_FadeGammaIn (_THIS, SDL_QuartzGammaTable *table) { | 305 static UInt32 QZ_FadeGammaIn (_THIS, SDL_QuartzGammaTable *table) { |
301 | 306 |
302 CGGammaValue redTable[QZ_GAMMA_TABLE_SIZE], | 307 CGGammaValue redTable[QZ_GAMMA_TABLE_SIZE], |
303 greenTable[QZ_GAMMA_TABLE_SIZE], | 308 greenTable[QZ_GAMMA_TABLE_SIZE], |
304 blueTable[QZ_GAMMA_TABLE_SIZE]; | 309 blueTable[QZ_GAMMA_TABLE_SIZE]; |
334 } | 339 } |
335 | 340 |
336 static void QZ_UnsetVideoMode (_THIS) { | 341 static void QZ_UnsetVideoMode (_THIS) { |
337 | 342 |
338 /* Reset values that may change between switches */ | 343 /* Reset values that may change between switches */ |
339 this->info.blit_fill = 0; | 344 this->info.blit_fill = 0; |
340 this->FillHWRect = NULL; | 345 this->FillHWRect = NULL; |
341 this->UpdateRects = NULL; | 346 this->UpdateRects = NULL; |
342 | 347 this->LockHWSurface = NULL; |
348 this->UnlockHWSurface = NULL; | |
349 | |
343 /* Release fullscreen resources */ | 350 /* Release fullscreen resources */ |
344 if ( mode_flags & SDL_FULLSCREEN ) { | 351 if ( mode_flags & SDL_FULLSCREEN ) { |
345 | 352 |
346 SDL_QuartzGammaTable gamma_table; | 353 SDL_QuartzGammaTable gamma_table; |
347 int gamma_error; | 354 int gamma_error; |
348 NSRect screen_rect; | 355 NSRect screen_rect; |
349 | 356 |
350 gamma_error = QZ_FadeGammaOut (this, &gamma_table); | 357 gamma_error = QZ_FadeGammaOut (this, &gamma_table); |
351 | 358 |
352 /* Release the OpenGL context */ | 359 /* |
353 /* Do this first to avoid trash on the display before fade */ | 360 Release the OpenGL context |
354 if ( mode_flags & SDL_OPENGL ) | 361 Do this first to avoid trash on the display before fade |
362 */ | |
363 if ( mode_flags & SDL_OPENGL ) { | |
364 | |
355 QZ_TearDownOpenGL (this); | 365 QZ_TearDownOpenGL (this); |
356 | 366 CGLSetFullScreen (NULL); |
357 if (mode_flags & SDL_OPENGL) | 367 } |
358 CGLSetFullScreen(NULL); | 368 |
359 | |
360 /* Restore original screen resolution/bpp */ | 369 /* Restore original screen resolution/bpp */ |
361 CGDisplaySwitchToMode (display_id, save_mode); | 370 CGDisplaySwitchToMode (display_id, save_mode); |
362 CGDisplayRelease (display_id); | 371 CGDisplayRelease (display_id); |
363 ShowMenuBar (); | 372 ShowMenuBar (); |
364 | 373 |
365 /* | 374 /* |
366 reset the main screen's rectangle, see comment | 375 Reset the main screen's rectangle |
367 in QZ_SetVideoFullscreen | 376 See comment in QZ_SetVideoFullscreen for why we do this |
368 */ | 377 */ |
369 screen_rect = NSMakeRect(0,0,device_width,device_height); | 378 screen_rect = NSMakeRect(0,0,device_width,device_height); |
370 [ [ NSScreen mainScreen ] setFrame:screen_rect ]; | 379 [ [ NSScreen mainScreen ] setFrame:screen_rect ]; |
371 | 380 |
372 if (! gamma_error) | 381 if (! gamma_error) |
373 QZ_FadeGammaIn (this, &gamma_table); | 382 QZ_FadeGammaIn (this, &gamma_table); |
374 } | 383 } |
375 /* Release window mode resources */ | 384 /* Release window mode resources */ |
376 else { | 385 else { |
377 if ( (mode_flags & SDL_OPENGL) == 0 ) { | 386 |
378 UnlockPortBits ( [ window_view qdPort ] ); | |
379 [ window_view release ]; | |
380 } | |
381 [ qz_window setContentView:nil ]; | |
382 [ qz_window setDelegate:nil ]; | |
383 [ qz_window close ]; | 387 [ qz_window close ]; |
384 [ qz_window release ]; | 388 [ qz_window release ]; |
385 qz_window = nil; | 389 qz_window = nil; |
386 | 390 window_view = nil; |
391 | |
387 /* Release the OpenGL context */ | 392 /* Release the OpenGL context */ |
388 if ( mode_flags & SDL_OPENGL ) | 393 if ( mode_flags & SDL_OPENGL ) |
389 QZ_TearDownOpenGL (this); | 394 QZ_TearDownOpenGL (this); |
390 } | 395 } |
391 | 396 |
392 /* Restore gamma settings */ | 397 /* Restore gamma settings */ |
393 CGDisplayRestoreColorSyncSettings (); | 398 CGDisplayRestoreColorSyncSettings (); |
394 | |
395 /* Set pixels to null (so other code doesn't try to free it) */ | |
396 if (this->screen != NULL) | |
397 this->screen->pixels = NULL; | |
398 | 399 |
399 /* Ensure the cursor will be visible and working when we quit */ | 400 /* Ensure the cursor will be visible and working when we quit */ |
400 CGDisplayShowCursor (display_id); | 401 CGDisplayShowCursor (display_id); |
401 CGAssociateMouseAndMouseCursorPosition (1); | 402 CGAssociateMouseAndMouseCursorPosition (1); |
402 | 403 |
409 int exact_match; | 410 int exact_match; |
410 int gamma_error; | 411 int gamma_error; |
411 SDL_QuartzGammaTable gamma_table; | 412 SDL_QuartzGammaTable gamma_table; |
412 NSRect screen_rect; | 413 NSRect screen_rect; |
413 | 414 |
415 /* Destroy any previous mode */ | |
416 if (video_set == SDL_TRUE) | |
417 QZ_UnsetVideoMode (this); | |
418 | |
414 /* See if requested mode exists */ | 419 /* See if requested mode exists */ |
415 mode = CGDisplayBestModeForParameters (display_id, bpp, width, | 420 mode = CGDisplayBestModeForParameters (display_id, bpp, width, |
416 height, &exact_match); | 421 height, &exact_match); |
417 | 422 |
418 /* Require an exact match to the requested mode */ | 423 /* Require an exact match to the requested mode */ |
419 if ( ! exact_match ) { | 424 if ( ! exact_match ) { |
420 sprintf (QZ_Error, "Failed to find display resolution: %dx%dx%d", width, height, bpp); | 425 SDL_SetError ("Failed to find display resolution: %dx%dx%d", width, height, bpp); |
421 SDL_SetError (QZ_Error); | |
422 goto ERR_NO_MATCH; | 426 goto ERR_NO_MATCH; |
423 } | 427 } |
424 | 428 |
425 /* Fade display to zero gamma */ | 429 /* Fade display to zero gamma */ |
426 gamma_error = QZ_FadeGammaOut (this, &gamma_table); | 430 gamma_error = QZ_FadeGammaOut (this, &gamma_table); |
428 /* Put up the blanking window (a window above all other windows) */ | 432 /* Put up the blanking window (a window above all other windows) */ |
429 if ( CGDisplayNoErr != CGDisplayCapture (display_id) ) { | 433 if ( CGDisplayNoErr != CGDisplayCapture (display_id) ) { |
430 SDL_SetError ("Failed capturing display"); | 434 SDL_SetError ("Failed capturing display"); |
431 goto ERR_NO_CAPTURE; | 435 goto ERR_NO_CAPTURE; |
432 } | 436 } |
433 | |
434 | 437 |
435 /* Do the physical switch */ | 438 /* Do the physical switch */ |
436 if ( CGDisplayNoErr != CGDisplaySwitchToMode (display_id, mode) ) { | 439 if ( CGDisplayNoErr != CGDisplaySwitchToMode (display_id, mode) ) { |
437 SDL_SetError ("Failed switching display resolution"); | 440 SDL_SetError ("Failed switching display resolution"); |
438 goto ERR_NO_SWITCH; | 441 goto ERR_NO_SWITCH; |
444 current->flags = 0; | 447 current->flags = 0; |
445 current->w = width; | 448 current->w = width; |
446 current->h = height; | 449 current->h = height; |
447 current->flags |= SDL_FULLSCREEN; | 450 current->flags |= SDL_FULLSCREEN; |
448 current->flags |= SDL_HWSURFACE; | 451 current->flags |= SDL_HWSURFACE; |
449 | 452 current->flags |= SDL_PREALLOC; |
450 this->UpdateRects = QZ_DirectUpdate; | 453 |
451 | 454 this->UpdateRects = QZ_DirectUpdate; |
455 this->LockHWSurface = QZ_LockHWSurface; | |
456 this->UnlockHWSurface = QZ_UnlockHWSurface; | |
457 | |
452 /* Setup some mode-dependant info */ | 458 /* Setup some mode-dependant info */ |
453 if ( CGSDisplayCanHWFill (display_id) ) { | 459 if ( CGSDisplayCanHWFill (display_id) ) { |
454 this->info.blit_fill = 1; | 460 this->info.blit_fill = 1; |
455 this->FillHWRect = QZ_FillHWRect; | 461 this->FillHWRect = QZ_FillHWRect; |
456 } | 462 } |
470 | 476 |
471 ctx = [ gl_context cglContext ]; | 477 ctx = [ gl_context cglContext ]; |
472 err = CGLSetFullScreen (ctx); | 478 err = CGLSetFullScreen (ctx); |
473 | 479 |
474 if (err) { | 480 if (err) { |
475 sprintf (QZ_Error, "Error setting OpenGL fullscreen: %s", CGLErrorString(err)); | 481 SDL_SetError ("Error setting OpenGL fullscreen: %s", CGLErrorString(err)); |
476 SDL_SetError (QZ_Error); | |
477 goto ERR_NO_GL; | 482 goto ERR_NO_GL; |
478 } | 483 } |
479 | 484 |
480 [ gl_context makeCurrentContext]; | 485 [ gl_context makeCurrentContext]; |
481 | 486 |
492 /* Fade the display to original gamma */ | 497 /* Fade the display to original gamma */ |
493 if (! gamma_error ) | 498 if (! gamma_error ) |
494 QZ_FadeGammaIn (this, &gamma_table); | 499 QZ_FadeGammaIn (this, &gamma_table); |
495 | 500 |
496 /* | 501 /* |
497 There is a bug in Cocoa where NSScreen doesn't synchronize | 502 There is a bug in Cocoa where NSScreen doesn't synchronize |
498 with CGDirectDisplay, so the main screen's frame is wrong. | 503 with CGDirectDisplay, so the main screen's frame is wrong. |
499 As a result, coordinate translation produces wrong results. | 504 As a result, coordinate translation produces incorrect results. |
500 We can hack around this bug by setting the screen rect | 505 We can hack around this bug by setting the screen rect |
501 ourselves. This hack should be removed if/when the bug is fixed. | 506 ourselves. This hack should be removed if/when the bug is fixed. |
502 */ | 507 */ |
503 screen_rect = NSMakeRect(0,0,width,height); | 508 screen_rect = NSMakeRect(0,0,width,height); |
504 [ [ NSScreen mainScreen ] setFrame:screen_rect ]; | 509 [ [ NSScreen mainScreen ] setFrame:screen_rect ]; |
505 | 510 |
506 /* Save the flags to ensure correct tear-down */ | 511 /* Save the flags to ensure correct tear-down */ |
516 } | 521 } |
517 | 522 |
518 static SDL_Surface* QZ_SetVideoWindowed (_THIS, SDL_Surface *current, int width, | 523 static SDL_Surface* QZ_SetVideoWindowed (_THIS, SDL_Surface *current, int width, |
519 int height, int bpp, Uint32 flags) { | 524 int height, int bpp, Uint32 flags) { |
520 unsigned int style; | 525 unsigned int style; |
521 NSRect rect; | 526 NSRect contentRect; |
522 rect = NSMakeRect (0, 0, width, height); | |
523 | |
524 #if 1 // FIXME - the resize button doesn't show? Also need resize events... | |
525 flags &= ~SDL_RESIZABLE; | |
526 #endif | |
527 /* Set the window style based on input flags */ | |
528 if ( flags & SDL_NOFRAME ) { | |
529 style = NSBorderlessWindowMask; | |
530 } else { | |
531 style = NSTitledWindowMask; | |
532 style |= (NSMiniaturizableWindowMask | NSClosableWindowMask); | |
533 if ( flags & SDL_RESIZABLE ) | |
534 style |= NSResizableWindowMask; | |
535 } | |
536 | |
537 /* Manually create a window, avoids having a nib file resource */ | |
538 qz_window = [ [ SDL_QuartzWindow alloc ] initWithContentRect:rect | |
539 styleMask:style backing:NSBackingStoreBuffered defer:NO ]; | |
540 if (qz_window == nil) { | |
541 SDL_SetError ("Could not create the Cocoa window"); | |
542 return NULL; | |
543 } | |
544 | 527 |
545 current->flags = 0; | 528 current->flags = 0; |
546 current->w = width; | 529 current->w = width; |
547 current->h = height; | 530 current->h = height; |
548 | 531 |
549 [ qz_window setReleasedWhenClosed:YES ]; | 532 contentRect = NSMakeRect (0, 0, width, height); |
550 QZ_SetCaption(this, this->wm_title, this->wm_icon); | 533 |
551 [ qz_window setAcceptsMouseMovedEvents:YES ]; | 534 /* |
552 [ qz_window setViewsNeedDisplay:NO ]; | 535 Check if we should completely destroy the previous mode |
553 [ qz_window center ]; | 536 - If it is fullscreen |
554 [ qz_window setDelegate: | 537 - If it has different noframe or resizable attribute |
555 [ [ [ SDL_QuartzWindowDelegate alloc ] init ] autorelease ] ]; | 538 - If it is OpenGL (since gl attributes could be different) |
556 | 539 - If new mode is OpenGL, but previous mode wasn't |
557 /* For OpenGL, we set the content view to a NSOpenGLView */ | 540 */ |
541 if (video_set == SDL_TRUE) | |
542 if ( (mode_flags & SDL_FULLSCREEN) || | |
543 ((mode_flags ^ flags) & (SDL_NOFRAME|SDL_RESIZABLE)) || | |
544 (mode_flags & SDL_OPENGL) || | |
545 (flags & SDL_OPENGL) ) | |
546 QZ_UnsetVideoMode (this); | |
547 | |
548 /* Check if we should recreate the window */ | |
549 if (qz_window == nil) { | |
550 | |
551 /* Set the window style based on input flags */ | |
552 if ( flags & SDL_NOFRAME ) { | |
553 style = NSBorderlessWindowMask; | |
554 current->flags |= SDL_NOFRAME; | |
555 } else { | |
556 style = NSTitledWindowMask; | |
557 style |= (NSMiniaturizableWindowMask | NSClosableWindowMask); | |
558 if ( flags & SDL_RESIZABLE ) { | |
559 style |= NSResizableWindowMask; | |
560 current->flags |= SDL_RESIZABLE; | |
561 } | |
562 } | |
563 | |
564 /* Manually create a window, avoids having a nib file resource */ | |
565 qz_window = [ [ SDL_QuartzWindow alloc ] | |
566 initWithContentRect:contentRect | |
567 styleMask:style | |
568 backing:NSBackingStoreBuffered | |
569 defer:NO ]; | |
570 | |
571 if (qz_window == nil) { | |
572 SDL_SetError ("Could not create the Cocoa window"); | |
573 return NULL; | |
574 } | |
575 | |
576 [ qz_window setReleasedWhenClosed:YES ]; | |
577 QZ_SetCaption(this, this->wm_title, this->wm_icon); | |
578 [ qz_window setAcceptsMouseMovedEvents:YES ]; | |
579 [ qz_window setViewsNeedDisplay:NO ]; | |
580 [ qz_window center ]; | |
581 [ qz_window setDelegate: | |
582 [ [ [ SDL_QuartzWindowDelegate alloc ] init ] autorelease ] ]; | |
583 } | |
584 /* We already have a window, just change its size */ | |
585 else { | |
586 | |
587 [ qz_window setContentSize:contentRect.size ]; | |
588 current->flags |= (SDL_NOFRAME|SDL_RESIZABLE) & mode_flags; | |
589 } | |
590 | |
591 /* For OpenGL, we bind the context to a subview */ | |
558 if ( flags & SDL_OPENGL ) { | 592 if ( flags & SDL_OPENGL ) { |
559 | 593 |
560 if ( ! QZ_SetupOpenGL (this, bpp, flags) ) { | 594 if ( ! QZ_SetupOpenGL (this, bpp, flags) ) { |
561 return NULL; | 595 return NULL; |
562 } | 596 } |
563 | 597 |
564 [ gl_context setView: [ qz_window contentView ] ]; | 598 window_view = [ [ NSView alloc ] initWithFrame:contentRect ]; |
599 [ window_view setAutoresizingMask: NSViewMinYMargin ]; | |
600 [ [ qz_window contentView ] addSubview:window_view ]; | |
601 [ gl_context setView: window_view ]; | |
602 [ window_view release ]; | |
565 [ gl_context makeCurrentContext]; | 603 [ gl_context makeCurrentContext]; |
566 [ qz_window makeKeyAndOrderFront:nil ]; | 604 [ qz_window makeKeyAndOrderFront:nil ]; |
567 current->flags |= SDL_OPENGL; | 605 current->flags |= SDL_OPENGL; |
568 } | 606 } |
569 /* For 2D, we set the content view to a NSQuickDrawView */ | 607 /* For 2D, we set the subview to an NSQuickDrawView */ |
570 else { | 608 else { |
571 | 609 |
572 window_view = [ [ SDL_QuartzWindowView alloc ] init ]; | 610 /* Only recreate the view if it doesn't already exist */ |
573 [ qz_window setContentView:window_view ]; | 611 if (window_view == nil) { |
574 [ qz_window makeKeyAndOrderFront:nil ]; | 612 |
575 | 613 window_view = [ [ SDL_QuartzWindowView alloc ] initWithFrame:contentRect ]; |
614 [ window_view setAutoresizingMask: NSViewMinYMargin ]; | |
615 [ [ qz_window contentView ] addSubview:window_view ]; | |
616 [ window_view release ]; | |
617 [ qz_window makeKeyAndOrderFront:nil ]; | |
618 } | |
619 | |
576 LockPortBits ( [ window_view qdPort ] ); | 620 LockPortBits ( [ window_view qdPort ] ); |
577 current->pixels = GetPixBaseAddr ( GetPortPixMap ( [ window_view qdPort ] ) ); | 621 current->pixels = GetPixBaseAddr ( GetPortPixMap ( [ window_view qdPort ] ) ); |
578 current->pitch = GetPixRowBytes ( GetPortPixMap ( [ window_view qdPort ] ) ); | 622 current->pitch = GetPixRowBytes ( GetPortPixMap ( [ window_view qdPort ] ) ); |
579 UnlockPortBits ( [ window_view qdPort ] ); | 623 UnlockPortBits ( [ window_view qdPort ] ); |
580 | 624 |
581 current->flags |= SDL_SWSURFACE; | 625 current->flags |= SDL_SWSURFACE; |
582 current->flags |= SDL_PREALLOC; | 626 current->flags |= SDL_PREALLOC; |
583 current->flags |= SDL_ASYNCBLIT; | 627 current->flags |= SDL_ASYNCBLIT; |
584 | 628 |
585 if ( flags & SDL_NOFRAME ) | 629 /* Offset below the title bar to fill the full content region */ |
586 current->flags |= SDL_NOFRAME; | 630 current->pixels += ((int)([ qz_window frame ].size.height) - height) * current->pitch; |
587 if ( flags & SDL_RESIZABLE ) | |
588 current->flags |= SDL_RESIZABLE; | |
589 | |
590 /* Offset 22 pixels down to fill the full content region */ | |
591 if ( ! (current->flags & SDL_NOFRAME) ) { | |
592 current->pixels += 22 * current->pitch; | |
593 } | |
594 | 631 |
595 this->UpdateRects = QZ_UpdateRects; | 632 this->UpdateRects = QZ_UpdateRects; |
596 this->LockHWSurface = QZ_LockWindow; | 633 this->LockHWSurface = QZ_LockWindow; |
597 this->UnlockHWSurface = QZ_UnlockWindow; | 634 this->UnlockHWSurface = QZ_UnlockWindow; |
598 } | 635 } |
603 return current; | 640 return current; |
604 } | 641 } |
605 | 642 |
606 static SDL_Surface* QZ_SetVideoMode (_THIS, SDL_Surface *current, int width, | 643 static SDL_Surface* QZ_SetVideoMode (_THIS, SDL_Surface *current, int width, |
607 int height, int bpp, Uint32 flags) { | 644 int height, int bpp, Uint32 flags) { |
608 | |
609 if (video_set == SDL_TRUE) | |
610 QZ_UnsetVideoMode (this); | |
611 | 645 |
612 current->flags = 0; | 646 current->flags = 0; |
613 | 647 |
614 /* Setup full screen video */ | 648 /* Setup full screen video */ |
615 if ( flags & SDL_FULLSCREEN ) { | 649 if ( flags & SDL_FULLSCREEN ) { |
694 | 728 |
695 static void QZ_DirectUpdate (_THIS, int num_rects, SDL_Rect *rects) { | 729 static void QZ_DirectUpdate (_THIS, int num_rects, SDL_Rect *rects) { |
696 #pragma unused(this,num_rects,rects) | 730 #pragma unused(this,num_rects,rects) |
697 } | 731 } |
698 | 732 |
699 /** | 733 /* |
700 * The obscured code is based on work by Matt Slot fprefect@ambrosiasw.com, | 734 The obscured code is based on work by Matt Slot fprefect@ambrosiasw.com, |
701 * who supplied sample code for Carbon. | 735 who supplied sample code for Carbon. |
702 **/ | 736 */ |
703 static int QZ_IsWindowObscured (NSWindow *window) { | 737 static int QZ_IsWindowObscured (NSWindow *window) { |
704 | 738 |
705 //#define TEST_OBSCURED 1 | 739 //#define TEST_OBSCURED 1 |
706 | 740 |
707 #if TEST_OBSCURED | 741 #if TEST_OBSCURED |
708 | 742 |
709 /* In order to determine if a direct copy to the screen is possible, | 743 /* |
744 In order to determine if a direct copy to the screen is possible, | |
710 we must figure out if there are any windows covering ours (including shadows). | 745 we must figure out if there are any windows covering ours (including shadows). |
711 This can be done by querying the window server about the on screen | 746 This can be done by querying the window server about the on screen |
712 windows for their screen rectangle and window level. | 747 windows for their screen rectangle and window level. |
713 The procedure used below is puts accuracy before speed; however, it aims to call | 748 The procedure used below is puts accuracy before speed; however, it aims to call |
714 the window server the fewest number of times possible to keep things reasonable. | 749 the window server the fewest number of times possible to keep things reasonable. |
751 | 786 |
752 int obscured = SDL_TRUE; | 787 int obscured = SDL_TRUE; |
753 | 788 |
754 if ( [ window isVisible ] ) { | 789 if ( [ window isVisible ] ) { |
755 | 790 |
756 /* walk the window list looking for windows over top of | 791 /* |
757 (or casting a shadow on) ours */ | 792 walk the window list looking for windows over top of |
758 | 793 (or casting a shadow on) ours |
759 /* Get a connection to the window server */ | 794 */ |
760 /* Should probably be moved out into SetVideoMode() or InitVideo() */ | 795 |
796 /* | |
797 Get a connection to the window server | |
798 Should probably be moved out into SetVideoMode() or InitVideo() | |
799 */ | |
761 if (cgsConnection == (CGSConnectionID) -1) { | 800 if (cgsConnection == (CGSConnectionID) -1) { |
762 cgsConnection = (CGSConnectionID) 0; | 801 cgsConnection = (CGSConnectionID) 0; |
763 cgsConnection = _CGSDefaultConnection (); | 802 cgsConnection = _CGSDefaultConnection (); |
764 } | 803 } |
765 | 804 |
783 contentRect.size.height -= windowContentOffset; | 822 contentRect.size.height -= windowContentOffset; |
784 | 823 |
785 firstDockIcon = -1; | 824 firstDockIcon = -1; |
786 dockIconCacheMiss = SDL_FALSE; | 825 dockIconCacheMiss = SDL_FALSE; |
787 | 826 |
788 /* The first window is always an empty window with level kCGSWindowLevelTop | 827 /* |
789 so start at index 1 */ | 828 The first window is always an empty window with level kCGSWindowLevelTop |
829 so start at index 1 | |
830 */ | |
790 for (i = 1; i < count; i++) { | 831 for (i = 1; i < count; i++) { |
791 | 832 |
792 /* If we reach our window in the list, it cannot be obscured */ | 833 /* If we reach our window in the list, it cannot be obscured */ |
793 if (windows[i] == windowNumber) { | 834 if (windows[i] == windowNumber) { |
794 | 835 |
854 shadowTop = 4; | 895 shadowTop = 4; |
855 shadowBottom = 12; | 896 shadowBottom = 12; |
856 } | 897 } |
857 else if (winLevel == kCGSWindowLevelNormal) { | 898 else if (winLevel == kCGSWindowLevelNormal) { |
858 | 899 |
859 /* These numbers are for foreground windows, | 900 /* |
860 they are too big (but will work) for background windows */ | 901 These numbers are for foreground windows, |
902 they are too big (but will work) for background windows | |
903 */ | |
861 shadowSide = 20; | 904 shadowSide = 20; |
862 shadowTop = 10; | 905 shadowTop = 10; |
863 shadowBottom = 24; | 906 shadowBottom = 24; |
864 } | 907 } |
865 else if (winLevel == kCGSWindowLevelDock) { | 908 else if (winLevel == kCGSWindowLevelDock) { |
878 shadowTop = 0; | 921 shadowTop = 0; |
879 shadowBottom = 0; | 922 shadowBottom = 0; |
880 } | 923 } |
881 else { | 924 else { |
882 | 925 |
883 /* kCGSWindowLevelDockLabel, | 926 /* |
884 kCGSWindowLevelDock, | 927 kCGSWindowLevelDockLabel, |
885 kOther??? */ | 928 kCGSWindowLevelDock, |
929 kOther??? | |
930 */ | |
886 | 931 |
887 /* no shadow */ | 932 /* no shadow */ |
888 shadowSide = 0; | 933 shadowSide = 0; |
889 shadowTop = 0; | 934 shadowTop = 0; |
890 shadowBottom = 0; | 935 shadowBottom = 0; |
915 #else | 960 #else |
916 return SDL_TRUE; | 961 return SDL_TRUE; |
917 #endif | 962 #endif |
918 } | 963 } |
919 | 964 |
965 | |
920 /* Locking functions for the software window buffer */ | 966 /* Locking functions for the software window buffer */ |
921 static int QZ_LockWindow (_THIS, SDL_Surface *surface) { | 967 static int QZ_LockWindow (_THIS, SDL_Surface *surface) { |
922 | 968 |
923 return LockPortBits ( [ window_view qdPort ] ); | 969 return LockPortBits ( [ window_view qdPort ] ); |
924 } | 970 } |
931 static void QZ_UpdateRects (_THIS, int numRects, SDL_Rect *rects) { | 977 static void QZ_UpdateRects (_THIS, int numRects, SDL_Rect *rects) { |
932 | 978 |
933 if (SDL_VideoSurface->flags & SDL_OPENGLBLIT) { | 979 if (SDL_VideoSurface->flags & SDL_OPENGLBLIT) { |
934 QZ_GL_SwapBuffers (this); | 980 QZ_GL_SwapBuffers (this); |
935 } | 981 } |
936 else if ( [ qz_window isMiniaturized ] && | 982 else if ( [ qz_window isMiniaturized ] ) { |
937 ! (SDL_VideoSurface->flags & SDL_OPENGL)) { | 983 |
938 | 984 /* Do nothing if miniaturized */ |
939 /** | 985 } |
940 * Set port alpha opaque so deminiaturize looks right | 986 |
941 * This isn't so nice, but there is no | |
942 * initial deminatureize notification (before demini starts) | |
943 **/ | |
944 QZ_SetPortAlphaOpaque ([ [ qz_window contentView ] qdPort], | |
945 [ qz_window styleMask ] & NSBorderlessWindowMask); | |
946 } | |
947 else if ( ! QZ_IsWindowObscured (qz_window) ) { | 987 else if ( ! QZ_IsWindowObscured (qz_window) ) { |
948 | 988 |
949 /* Use direct copy to flush contents to the display */ | 989 /* Use direct copy to flush contents to the display */ |
950 CGrafPtr savePort; | 990 CGrafPtr savePort; |
951 CGrafPtr dstPort, srcPort; | 991 CGrafPtr dstPort, srcPort; |
990 } | 1030 } |
991 | 1031 |
992 SetPort (savePort); | 1032 SetPort (savePort); |
993 } | 1033 } |
994 else { | 1034 else { |
995 | |
996 /* Use QDFlushPortBuffer() to flush content to display */ | 1035 /* Use QDFlushPortBuffer() to flush content to display */ |
997 int i; | 1036 int i; |
998 RgnHandle dirty = NewRgn (); | 1037 RgnHandle dirty = NewRgn (); |
999 RgnHandle temp = NewRgn (); | 1038 RgnHandle temp = NewRgn (); |
1000 | 1039 |
1002 | 1041 |
1003 /* Build the region of dirty rectangles */ | 1042 /* Build the region of dirty rectangles */ |
1004 for (i = 0; i < numRects; i++) { | 1043 for (i = 0; i < numRects; i++) { |
1005 | 1044 |
1006 MacSetRectRgn (temp, rects[i].x, rects[i].y, | 1045 MacSetRectRgn (temp, rects[i].x, rects[i].y, |
1007 rects[i].x + rects[i].w, rects[i].y + rects[i].h); | 1046 rects[i].x + rects[i].w, rects[i].y + rects[i].h); |
1008 MacUnionRgn (dirty, temp, dirty); | 1047 MacUnionRgn (dirty, temp, dirty); |
1009 } | 1048 } |
1010 | 1049 |
1050 QZ_DrawResizeIcon (this, dirty); | |
1051 | |
1011 /* Flush the dirty region */ | 1052 /* Flush the dirty region */ |
1012 QDFlushPortBuffer ( [ window_view qdPort ], dirty ); | 1053 QDFlushPortBuffer ( [ window_view qdPort ], dirty ); |
1013 DisposeRgn (dirty); | 1054 DisposeRgn (dirty); |
1014 DisposeRgn (temp); | 1055 DisposeRgn (temp); |
1015 } | 1056 } |
1361 DisposeHandle ((Handle)yuv_idh); | 1402 DisposeHandle ((Handle)yuv_idh); |
1362 } | 1403 } |
1363 | 1404 |
1364 #include "SDL_yuvfuncs.h" | 1405 #include "SDL_yuvfuncs.h" |
1365 | 1406 |
1366 /** | 1407 /* check for 16 byte alignment, bail otherwise */ |
1367 * check for 16 byte alignment, bail otherwise | |
1368 **/ | |
1369 #define CHECK_ALIGN(x) do { if ((Uint32)x & 15) { SDL_SetError("Alignment error"); return NULL; } } while(0) | 1408 #define CHECK_ALIGN(x) do { if ((Uint32)x & 15) { SDL_SetError("Alignment error"); return NULL; } } while(0) |
1370 | 1409 |
1371 /** | 1410 /* align a byte offset, return how much to add to make it a multiple of 16 */ |
1372 * align a byte offset, return how much to add to make it | |
1373 * a multiple of 16 | |
1374 **/ | |
1375 #define ALIGN(x) ((16 - (x & 15)) & 15) | 1411 #define ALIGN(x) ((16 - (x & 15)) & 15) |
1376 | 1412 |
1377 static SDL_Overlay* QZ_CreateYUVOverlay (_THIS, int width, int height, | 1413 static SDL_Overlay* QZ_CreateYUVOverlay (_THIS, int width, int height, |
1378 Uint32 format, SDL_Surface *display) { | 1414 Uint32 format, SDL_Surface *display) { |
1379 | 1415 |
1415 return NULL; | 1451 return NULL; |
1416 } | 1452 } |
1417 | 1453 |
1418 if (SDL_VideoSurface->flags & SDL_FULLSCREEN) { | 1454 if (SDL_VideoSurface->flags & SDL_FULLSCREEN) { |
1419 | 1455 |
1420 /** | 1456 /* |
1421 * Good acceleration requires a window to be present. | 1457 Acceleration requires a window to be present. |
1422 * A CGrafPtr that points to the screen isn't good enough | 1458 A CGrafPtr that points to the screen isn't good enough |
1423 **/ | 1459 */ |
1424 NSRect content = NSMakeRect (0, 0, SDL_VideoSurface->w, SDL_VideoSurface->h); | 1460 NSRect content = NSMakeRect (0, 0, SDL_VideoSurface->w, SDL_VideoSurface->h); |
1425 | 1461 |
1426 qz_window = [ [ SDL_QuartzWindow alloc ] | 1462 qz_window = [ [ SDL_QuartzWindow alloc ] |
1427 initWithContentRect:content | 1463 initWithContentRect:content |
1428 styleMask:NSBorderlessWindowMask | 1464 styleMask:NSBorderlessWindowMask |
1440 [ qz_window setLevel:CGShieldingWindowLevel() ]; | 1476 [ qz_window setLevel:CGShieldingWindowLevel() ]; |
1441 [ qz_window makeKeyAndOrderFront:nil ]; | 1477 [ qz_window makeKeyAndOrderFront:nil ]; |
1442 | 1478 |
1443 port = [ [ qz_window contentView ] qdPort ]; | 1479 port = [ [ qz_window contentView ] qdPort ]; |
1444 SetPort (port); | 1480 SetPort (port); |
1445 // BUG: would like to remove white flash when window kicks in | 1481 |
1446 //{ | 1482 /* |
1447 // Rect r; | 1483 BUG: would like to remove white flash when window kicks in |
1448 // SetRect (&r, 0, 0, SDL_VideoSurface->w, SDL_VideoSurface->h); | 1484 { |
1449 // PaintRect (&r); | 1485 Rect r; |
1450 // QDFlushPortBuffer (port, nil); | 1486 SetRect (&r, 0, 0, SDL_VideoSurface->w, SDL_VideoSurface->h); |
1451 //} | 1487 PaintRect (&r); |
1488 QDFlushPortBuffer (port, nil); | |
1489 } | |
1490 */ | |
1452 | 1491 |
1453 } | 1492 } |
1454 else { | 1493 else { |
1455 port = [ [ qz_window contentView ] qdPort ]; | 1494 port = [ window_view qdPort ]; |
1456 SetPort (port); | 1495 SetPort (port); |
1457 } | 1496 } |
1458 | 1497 |
1459 SetIdentityMatrix (yuv_matrix); | 1498 SetIdentityMatrix (yuv_matrix); |
1460 | 1499 |
1542 if (yuv_pixmap == NULL) { | 1581 if (yuv_pixmap == NULL) { |
1543 SDL_OutOfMemory (); | 1582 SDL_OutOfMemory (); |
1544 return NULL; | 1583 return NULL; |
1545 } | 1584 } |
1546 | 1585 |
1547 //CHECK_ALIGN(yuv_pixmap); | 1586 /* CHECK_ALIGN(yuv_pixmap); */ |
1548 offset = sizeof(PlanarPixmapInfoYUV420); | 1587 offset = sizeof(PlanarPixmapInfoYUV420); |
1549 //offset += ALIGN(offset); | 1588 /* offset += ALIGN(offset); */ |
1550 //CHECK_ALIGN(offset); | 1589 /* CHECK_ALIGN(offset); */ |
1551 | 1590 |
1552 pixels[0] = (Uint8*)yuv_pixmap + offset; | 1591 pixels[0] = (Uint8*)yuv_pixmap + offset; |
1553 //CHECK_ALIGN(pixels[0]); | 1592 /* CHECK_ALIGN(pixels[0]); */ |
1554 | 1593 |
1555 pitches[0] = width; | 1594 pitches[0] = width; |
1556 yuv_pixmap->componentInfoY.offset = offset; | 1595 yuv_pixmap->componentInfoY.offset = offset; |
1557 yuv_pixmap->componentInfoY.rowBytes = width; | 1596 yuv_pixmap->componentInfoY.rowBytes = width; |
1558 | 1597 |
1586 yuv_width = overlay->w; | 1625 yuv_width = overlay->w; |
1587 yuv_height = overlay->h; | 1626 yuv_height = overlay->h; |
1588 | 1627 |
1589 return overlay; | 1628 return overlay; |
1590 } | 1629 } |
1591 |