src/video/quartz/SDL_QuartzVideo.m
author Sam Lantinga <slouken@libsdl.org>
Sat, 29 Dec 2007 21:31:26 +0000
branchSDL-1.2
changeset 4123 9d90d7765fa7
parent 4090 fedb379bedd0
child 4139 568c9b3c0167
permissions -rw-r--r--
Guillaume Borios fixed bug #508

When unicode translation is ON, pressing the escape key raise an NSBeep()
because the NSTextView interprets the key as a special command (in that case
impossible to interpret)... The NSTextView instance should replaced by
something subclassed so that doCommandBySelector: does nothing.

Example code :

@interface SDLTranslatorResponder : NSTextView
{
}
- (void) doCommandBySelector:(SEL)myselector;
@end

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