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