src/video/cocoa/SDL_cocoamodes.m
author Sam Lantinga <slouken@libsdl.org>
Sat, 29 Jul 2006 21:51:00 +0000
changeset 1956 ba0d62354872
parent 1934 70139af5ac27
child 1969 5d3724f64f2b
permissions -rw-r--r--
Simplified driver window creation code.
Implemented several Cocoa window functions
slouken@1931
     1
/*
slouken@1931
     2
    SDL - Simple DirectMedia Layer
slouken@1931
     3
    Copyright (C) 1997-2006 Sam Lantinga
slouken@1931
     4
slouken@1931
     5
    This library is free software; you can redistribute it and/or
slouken@1931
     6
    modify it under the terms of the GNU Lesser General Public
slouken@1931
     7
    License as published by the Free Software Foundation; either
slouken@1931
     8
    version 2.1 of the License, or (at your option) any later version.
slouken@1931
     9
slouken@1931
    10
    This library is distributed in the hope that it will be useful,
slouken@1931
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@1931
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@1931
    13
    Lesser General Public License for more details.
slouken@1931
    14
slouken@1931
    15
    You should have received a copy of the GNU Lesser General Public
slouken@1931
    16
    License along with this library; if not, write to the Free Software
slouken@1931
    17
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
slouken@1931
    18
slouken@1931
    19
    Sam Lantinga
slouken@1931
    20
    slouken@libsdl.org
slouken@1931
    21
*/
slouken@1931
    22
#include "SDL_config.h"
slouken@1931
    23
slouken@1931
    24
#include "SDL_cocoavideo.h"
slouken@1931
    25
slouken@1934
    26
static void
slouken@1934
    27
CG_SetError(const char *prefix, CGDisplayErr result)
slouken@1934
    28
{
slouken@1934
    29
    const char *error;
slouken@1934
    30
slouken@1934
    31
    switch (result) {
slouken@1934
    32
    case kCGErrorFailure:
slouken@1934
    33
        error = "kCGErrorFailure";
slouken@1934
    34
        break;
slouken@1934
    35
    case kCGErrorIllegalArgument:
slouken@1934
    36
        error = "kCGErrorIllegalArgument";
slouken@1934
    37
        break;
slouken@1934
    38
    case kCGErrorInvalidConnection:
slouken@1934
    39
        error = "kCGErrorInvalidConnection";
slouken@1934
    40
        break;
slouken@1934
    41
    case kCGErrorInvalidContext:
slouken@1934
    42
        error = "kCGErrorInvalidContext";
slouken@1934
    43
        break;
slouken@1934
    44
    case kCGErrorCannotComplete:
slouken@1934
    45
        error = "kCGErrorCannotComplete";
slouken@1934
    46
        break;
slouken@1934
    47
    case kCGErrorNameTooLong:
slouken@1934
    48
        error = "kCGErrorNameTooLong";
slouken@1934
    49
        break;
slouken@1934
    50
    case kCGErrorNotImplemented:
slouken@1934
    51
        error = "kCGErrorNotImplemented";
slouken@1934
    52
        break;
slouken@1934
    53
    case kCGErrorRangeCheck:
slouken@1934
    54
        error = "kCGErrorRangeCheck";
slouken@1934
    55
        break;
slouken@1934
    56
    case kCGErrorTypeCheck:
slouken@1934
    57
        error = "kCGErrorTypeCheck";
slouken@1934
    58
        break;
slouken@1934
    59
    case kCGErrorNoCurrentPoint:
slouken@1934
    60
        error = "kCGErrorNoCurrentPoint";
slouken@1934
    61
        break;
slouken@1934
    62
    case kCGErrorInvalidOperation:
slouken@1934
    63
        error = "kCGErrorInvalidOperation";
slouken@1934
    64
        break;
slouken@1934
    65
    case kCGErrorNoneAvailable:
slouken@1934
    66
        error = "kCGErrorNoneAvailable";
slouken@1934
    67
        break;
slouken@1934
    68
    default:
slouken@1934
    69
        error = "Unknown Error";
slouken@1934
    70
        break;
slouken@1934
    71
    }
slouken@1934
    72
    SDL_SetError("%s: %s", prefix, error);
slouken@1934
    73
}
slouken@1934
    74
slouken@1934
    75
static SDL_bool
slouken@1934
    76
GetDisplayMode(CFDictionaryRef moderef, SDL_DisplayMode *mode)
slouken@1934
    77
{
slouken@1934
    78
    SDL_DisplayModeData *data;
slouken@1934
    79
    CFNumberRef number;
slouken@1934
    80
    long width, height, bpp, refreshRate;
slouken@1934
    81
slouken@1934
    82
    data = (SDL_DisplayModeData *) SDL_malloc(sizeof(*data));
slouken@1934
    83
    if (!data) {
slouken@1934
    84
        return SDL_FALSE;
slouken@1934
    85
    }
slouken@1934
    86
    data->moderef = moderef;
slouken@1934
    87
slouken@1934
    88
    number = CFDictionaryGetValue(moderef, kCGDisplayWidth);
slouken@1934
    89
    CFNumberGetValue(number, kCFNumberLongType, &width);
slouken@1934
    90
    number = CFDictionaryGetValue(moderef, kCGDisplayHeight);
slouken@1934
    91
    CFNumberGetValue(number, kCFNumberLongType, &height);
slouken@1934
    92
    number = CFDictionaryGetValue(moderef, kCGDisplayBitsPerPixel);
slouken@1934
    93
    CFNumberGetValue(number, kCFNumberLongType, &bpp);
slouken@1934
    94
    number = CFDictionaryGetValue(moderef, kCGDisplayRefreshRate);
slouken@1934
    95
    CFNumberGetValue(number, kCFNumberLongType, &refreshRate);
slouken@1934
    96
slouken@1934
    97
    mode->format = SDL_PixelFormat_Unknown;
slouken@1934
    98
    switch (bpp) {
slouken@1934
    99
    case 8:
slouken@1934
   100
        mode->format = SDL_PixelFormat_Index8;
slouken@1934
   101
        break;
slouken@1934
   102
    case 16:
slouken@1934
   103
        mode->format = SDL_PixelFormat_RGB555;
slouken@1934
   104
        break;
slouken@1934
   105
    case 32:
slouken@1934
   106
        mode->format = SDL_PixelFormat_RGB888;
slouken@1934
   107
        break;
slouken@1934
   108
    }
slouken@1934
   109
    mode->w = width;
slouken@1934
   110
    mode->h = height;
slouken@1934
   111
    mode->refresh_rate = refreshRate;
slouken@1934
   112
    mode->driverdata = data;
slouken@1934
   113
    return SDL_TRUE;
slouken@1934
   114
}
slouken@1931
   115
slouken@1931
   116
void
slouken@1931
   117
Cocoa_InitModes(_THIS)
slouken@1931
   118
{
slouken@1934
   119
    CGDisplayErr result;
slouken@1934
   120
    CGDirectDisplayID *displays;
slouken@1934
   121
    CGDisplayCount numDisplays;
slouken@1934
   122
    int i;
slouken@1934
   123
slouken@1934
   124
    result = CGGetOnlineDisplayList(0, NULL, &numDisplays);
slouken@1934
   125
    if (result != kCGErrorSuccess) {
slouken@1934
   126
        CG_SetError("CGGetOnlineDisplayList()", result);
slouken@1934
   127
        return;
slouken@1934
   128
    }
slouken@1934
   129
    displays = SDL_stack_alloc(CGDirectDisplayID, numDisplays);
slouken@1934
   130
    result = CGGetOnlineDisplayList(numDisplays, displays, &numDisplays);
slouken@1934
   131
    if (result != kCGErrorSuccess) {
slouken@1934
   132
        CG_SetError("CGGetOnlineDisplayList()", result);
slouken@1934
   133
        SDL_stack_free(displays);
slouken@1934
   134
        return;
slouken@1934
   135
    }
slouken@1934
   136
slouken@1934
   137
    for (i = 0; i < numDisplays; ++i) {
slouken@1934
   138
        SDL_VideoDisplay display;
slouken@1934
   139
        SDL_DisplayData *displaydata;
slouken@1934
   140
        SDL_DisplayMode mode;
slouken@1934
   141
        CFDictionaryRef moderef;
slouken@1934
   142
slouken@1934
   143
        if (CGDisplayIsInMirrorSet(displays[i])) {
slouken@1934
   144
            continue;
slouken@1934
   145
        }
slouken@1934
   146
        moderef = CGDisplayCurrentMode(displays[i]);
slouken@1934
   147
        if (!moderef) {
slouken@1934
   148
            continue;
slouken@1934
   149
        }
slouken@1934
   150
slouken@1934
   151
        displaydata = (SDL_DisplayData *) SDL_malloc(sizeof(*displaydata));
slouken@1934
   152
        if (!displaydata) {
slouken@1934
   153
            continue;
slouken@1934
   154
        }
slouken@1934
   155
        displaydata->display = displays[i];
slouken@1934
   156
slouken@1934
   157
        SDL_zero(display);
slouken@1934
   158
        if (!GetDisplayMode (moderef, &mode)) {
slouken@1934
   159
            SDL_free(displaydata);
slouken@1934
   160
            continue;
slouken@1934
   161
        }
slouken@1934
   162
        display.desktop_mode = mode;
slouken@1934
   163
        display.current_mode = mode;
slouken@1934
   164
        display.driverdata = displaydata;
slouken@1934
   165
        SDL_AddVideoDisplay(&display);
slouken@1934
   166
    }
slouken@1934
   167
}
slouken@1934
   168
slouken@1934
   169
static void
slouken@1934
   170
AddDisplayMode(const void *moderef, void *context)
slouken@1934
   171
{
slouken@1934
   172
    SDL_VideoDevice *_this = (SDL_VideoDevice *) context;
slouken@1931
   173
    SDL_DisplayMode mode;
slouken@1931
   174
slouken@1934
   175
    if (GetDisplayMode(moderef, &mode)) {
slouken@1934
   176
        SDL_AddDisplayMode(_this->current_display, &mode);
slouken@1934
   177
    }
slouken@1931
   178
}
slouken@1931
   179
slouken@1931
   180
void
slouken@1931
   181
Cocoa_GetDisplayModes(_THIS)
slouken@1931
   182
{
slouken@1934
   183
    SDL_DisplayData *data = (SDL_DisplayData *) SDL_CurrentDisplay.driverdata;
slouken@1934
   184
    CFArrayRef modes;
slouken@1934
   185
    CFRange range;
slouken@1934
   186
slouken@1934
   187
    modes = CGDisplayAvailableModes(data->display);
slouken@1934
   188
    if (!modes) {
slouken@1934
   189
        return;
slouken@1934
   190
    }
slouken@1934
   191
    range.location = 0;
slouken@1934
   192
    range.length = CFArrayGetCount(modes);
slouken@1934
   193
    CFArrayApplyFunction(modes, range, AddDisplayMode, _this);
slouken@1931
   194
}
slouken@1931
   195
slouken@1931
   196
int
slouken@1931
   197
Cocoa_SetDisplayMode(_THIS, SDL_DisplayMode * mode)
slouken@1931
   198
{
slouken@1934
   199
    SDL_DisplayData *displaydata = (SDL_DisplayData *) SDL_CurrentDisplay.driverdata;
slouken@1934
   200
    SDL_DisplayModeData *data = (SDL_DisplayModeData *) mode->driverdata;
slouken@1934
   201
    CGDisplayFadeReservationToken fade_token = kCGDisplayFadeReservationInvalidToken;
slouken@1934
   202
    CGError result;
slouken@1934
   203
    
slouken@1934
   204
    /* Fade to black to hide resolution-switching flicker */
slouken@1934
   205
    if (CGAcquireDisplayFadeReservation(5, &fade_token) == kCGErrorSuccess) {
slouken@1934
   206
        CGDisplayFade(fade_token, 0.3, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0, TRUE);
slouken@1934
   207
    }
slouken@1934
   208
slouken@1934
   209
    /* Put up the blanking window (a window above all other windows) */
slouken@1934
   210
    result = CGDisplayCapture(displaydata->display);
slouken@1934
   211
    if (result != kCGErrorSuccess) {
slouken@1934
   212
        CG_SetError("CGDisplayCapture()", result);
slouken@1934
   213
        goto ERR_NO_CAPTURE;
slouken@1934
   214
    }
slouken@1934
   215
slouken@1934
   216
    /* Do the physical switch */
slouken@1934
   217
    result = CGDisplaySwitchToMode(displaydata->display, data->moderef);
slouken@1934
   218
    if (result != kCGErrorSuccess) {
slouken@1934
   219
        CG_SetError("CGDisplaySwitchToMode()", result);
slouken@1934
   220
        goto ERR_NO_SWITCH;
slouken@1934
   221
    }
slouken@1934
   222
slouken@1934
   223
    /* Fade in again (asynchronously) */
slouken@1934
   224
    if (fade_token != kCGDisplayFadeReservationInvalidToken) {
slouken@1934
   225
        CGDisplayFade(fade_token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE);
slouken@1934
   226
        CGReleaseDisplayFadeReservation(fade_token);
slouken@1934
   227
    }
slouken@1934
   228
    return 0;
slouken@1934
   229
slouken@1934
   230
    /* Since the blanking window covers *all* windows (even force quit) correct recovery is crucial */
slouken@1934
   231
ERR_NO_SWITCH:
slouken@1934
   232
    CGDisplayRelease(displaydata->display);
slouken@1934
   233
ERR_NO_CAPTURE:
slouken@1934
   234
    if (fade_token != kCGDisplayFadeReservationInvalidToken) {
slouken@1934
   235
        CGDisplayFade (fade_token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE);
slouken@1934
   236
        CGReleaseDisplayFadeReservation(fade_token);
slouken@1934
   237
    }
slouken@1931
   238
    return -1;
slouken@1931
   239
}
slouken@1931
   240
slouken@1931
   241
void
slouken@1931
   242
Cocoa_QuitModes(_THIS)
slouken@1931
   243
{
slouken@1934
   244
    int i, saved_display;
slouken@1934
   245
slouken@1934
   246
    saved_display = _this->current_display;
slouken@1934
   247
    for (i = 0; i < _this->num_displays; ++i) {
slouken@1934
   248
        SDL_VideoDisplay *display = &_this->displays[i];
slouken@1934
   249
slouken@1934
   250
        if (display->current_mode.driverdata != display->desktop_mode.driverdata) {
slouken@1934
   251
            _this->current_display = i;
slouken@1934
   252
            Cocoa_SetDisplayMode(_this, &display->desktop_mode);
slouken@1934
   253
        }
slouken@1934
   254
    }
slouken@1934
   255
    CGReleaseAllDisplays();
slouken@1934
   256
    _this->current_display = saved_display;
slouken@1931
   257
}
slouken@1931
   258
slouken@1931
   259
/* vi: set ts=4 sw=4 expandtab: */