src/video/quartz/SDL_QuartzVideo.m
author Ryan C. Gordon
Mon, 02 Jan 2012 21:25:34 -0800
branchSDL-1.2
changeset 6157 8a1bc41db6bb
parent 6146 06ae169343e4
child 6158 6f3a2bb301d6
permissions -rw-r--r--
Quartz: Restore 1.2.14 behaviour of letting apps draw from background thread.

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