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