Commit 14744935 authored by Sam Lantinga's avatar Sam Lantinga

Implemented Mac OS X video mode selection.

--HG--
extra : convert_revision : svn%3Ac70aab31-4412-0410-b14c-859654838e24/trunk%401979
parent 56c1ba80
......@@ -24,6 +24,16 @@
#ifndef _SDL_cocoamodes_h
#define _SDL_cocoamodes_h
typedef struct
{
CGDirectDisplayID display;
} SDL_DisplayData;
typedef struct
{
CFDictionaryRef moderef;
} SDL_DisplayModeData;
extern void Cocoa_InitModes(_THIS);
extern void Cocoa_GetDisplayModes(_THIS);
extern int Cocoa_SetDisplayMode(_THIS, SDL_DisplayMode * mode);
......
......@@ -23,34 +23,237 @@
#include "SDL_cocoavideo.h"
static void
CG_SetError(const char *prefix, CGDisplayErr result)
{
const char *error;
switch (result) {
case kCGErrorFailure:
error = "kCGErrorFailure";
break;
case kCGErrorIllegalArgument:
error = "kCGErrorIllegalArgument";
break;
case kCGErrorInvalidConnection:
error = "kCGErrorInvalidConnection";
break;
case kCGErrorInvalidContext:
error = "kCGErrorInvalidContext";
break;
case kCGErrorCannotComplete:
error = "kCGErrorCannotComplete";
break;
case kCGErrorNameTooLong:
error = "kCGErrorNameTooLong";
break;
case kCGErrorNotImplemented:
error = "kCGErrorNotImplemented";
break;
case kCGErrorRangeCheck:
error = "kCGErrorRangeCheck";
break;
case kCGErrorTypeCheck:
error = "kCGErrorTypeCheck";
break;
case kCGErrorNoCurrentPoint:
error = "kCGErrorNoCurrentPoint";
break;
case kCGErrorInvalidOperation:
error = "kCGErrorInvalidOperation";
break;
case kCGErrorNoneAvailable:
error = "kCGErrorNoneAvailable";
break;
default:
error = "Unknown Error";
break;
}
SDL_SetError("%s: %s", prefix, error);
}
static SDL_bool
GetDisplayMode(CFDictionaryRef moderef, SDL_DisplayMode *mode)
{
SDL_DisplayModeData *data;
CFNumberRef number;
long width, height, bpp, refreshRate;
data = (SDL_DisplayModeData *) SDL_malloc(sizeof(*data));
if (!data) {
return SDL_FALSE;
}
data->moderef = moderef;
number = CFDictionaryGetValue(moderef, kCGDisplayWidth);
CFNumberGetValue(number, kCFNumberLongType, &width);
number = CFDictionaryGetValue(moderef, kCGDisplayHeight);
CFNumberGetValue(number, kCFNumberLongType, &height);
number = CFDictionaryGetValue(moderef, kCGDisplayBitsPerPixel);
CFNumberGetValue(number, kCFNumberLongType, &bpp);
number = CFDictionaryGetValue(moderef, kCGDisplayRefreshRate);
CFNumberGetValue(number, kCFNumberLongType, &refreshRate);
mode->format = SDL_PixelFormat_Unknown;
switch (bpp) {
case 8:
mode->format = SDL_PixelFormat_Index8;
break;
case 16:
mode->format = SDL_PixelFormat_RGB555;
break;
case 32:
mode->format = SDL_PixelFormat_RGB888;
break;
}
mode->w = width;
mode->h = height;
mode->refresh_rate = refreshRate;
mode->driverdata = data;
return SDL_TRUE;
}
void
Cocoa_InitModes(_THIS)
{
SDL_VideoDisplay display;
CGDisplayErr result;
CGDirectDisplayID *displays;
CGDisplayCount numDisplays;
int i;
result = CGGetOnlineDisplayList(0, NULL, &numDisplays);
if (result != kCGErrorSuccess) {
CG_SetError("CGGetOnlineDisplayList()", result);
return;
}
displays = SDL_stack_alloc(CGDirectDisplayID, numDisplays);
result = CGGetOnlineDisplayList(numDisplays, displays, &numDisplays);
if (result != kCGErrorSuccess) {
CG_SetError("CGGetOnlineDisplayList()", result);
SDL_stack_free(displays);
return;
}
for (i = 0; i < numDisplays; ++i) {
SDL_VideoDisplay display;
SDL_DisplayData *displaydata;
SDL_DisplayMode mode;
CFDictionaryRef moderef;
if (CGDisplayIsInMirrorSet(displays[i])) {
continue;
}
moderef = CGDisplayCurrentMode(displays[i]);
if (!moderef) {
continue;
}
displaydata = (SDL_DisplayData *) SDL_malloc(sizeof(*displaydata));
if (!displaydata) {
continue;
}
displaydata->display = displays[i];
SDL_zero(display);
if (!GetDisplayMode (moderef, &mode)) {
SDL_free(displaydata);
continue;
}
display.desktop_mode = mode;
display.current_mode = mode;
display.driverdata = displaydata;
SDL_AddVideoDisplay(&display);
}
}
static void
AddDisplayMode(const void *moderef, void *context)
{
SDL_VideoDevice *_this = (SDL_VideoDevice *) context;
SDL_DisplayMode mode;
SDL_zero(display);
SDL_zero(mode);
display.desktop_mode = mode;
display.current_mode = mode;
SDL_AddVideoDisplay(&display);
if (GetDisplayMode(moderef, &mode)) {
SDL_AddDisplayMode(_this->current_display, &mode);
}
}
void
Cocoa_GetDisplayModes(_THIS)
{
SDL_DisplayData *data = (SDL_DisplayData *) SDL_CurrentDisplay.driverdata;
CFArrayRef modes;
CFRange range;
modes = CGDisplayAvailableModes(data->display);
if (!modes) {
return;
}
range.location = 0;
range.length = CFArrayGetCount(modes);
CFArrayApplyFunction(modes, range, AddDisplayMode, _this);
}
int
Cocoa_SetDisplayMode(_THIS, SDL_DisplayMode * mode)
{
SDL_DisplayData *displaydata = (SDL_DisplayData *) SDL_CurrentDisplay.driverdata;
SDL_DisplayModeData *data = (SDL_DisplayModeData *) mode->driverdata;
CGDisplayFadeReservationToken fade_token = kCGDisplayFadeReservationInvalidToken;
CGError result;
/* Fade to black to hide resolution-switching flicker */
if (CGAcquireDisplayFadeReservation(5, &fade_token) == kCGErrorSuccess) {
CGDisplayFade(fade_token, 0.3, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0, TRUE);
}
/* Put up the blanking window (a window above all other windows) */
result = CGDisplayCapture(displaydata->display);
if (result != kCGErrorSuccess) {
CG_SetError("CGDisplayCapture()", result);
goto ERR_NO_CAPTURE;
}
/* Do the physical switch */
result = CGDisplaySwitchToMode(displaydata->display, data->moderef);
if (result != kCGErrorSuccess) {
CG_SetError("CGDisplaySwitchToMode()", result);
goto ERR_NO_SWITCH;
}
/* Fade in again (asynchronously) */
if (fade_token != kCGDisplayFadeReservationInvalidToken) {
CGDisplayFade(fade_token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE);
CGReleaseDisplayFadeReservation(fade_token);
}
return 0;
/* Since the blanking window covers *all* windows (even force quit) correct recovery is crucial */
ERR_NO_SWITCH:
CGDisplayRelease(displaydata->display);
ERR_NO_CAPTURE:
if (fade_token != kCGDisplayFadeReservationInvalidToken) {
CGDisplayFade (fade_token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE);
CGReleaseDisplayFadeReservation(fade_token);
}
return -1;
}
void
Cocoa_QuitModes(_THIS)
{
int i, saved_display;
saved_display = _this->current_display;
for (i = 0; i < _this->num_displays; ++i) {
SDL_VideoDisplay *display = &_this->displays[i];
if (display->current_mode.driverdata != display->desktop_mode.driverdata) {
_this->current_display = i;
Cocoa_SetDisplayMode(_this, &display->desktop_mode);
}
}
CGReleaseAllDisplays();
_this->current_display = saved_display;
}
/* vi: set ts=4 sw=4 expandtab: */
......@@ -24,6 +24,7 @@
#ifndef _SDL_cocoavideo_h
#define _SDL_cocoavideo_h
#include <ApplicationServices/ApplicationServices.h>
#include <Cocoa/Cocoa.h>
#include "../SDL_sysvideo.h"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment