Skip to content
This repository has been archived by the owner. It is now read-only.
Permalink
Browse files

Implemented Mac OS X video mode selection.

  • Loading branch information
slouken committed Jul 24, 2006
1 parent 952e9c8 commit 4c46dad8bdd942f945aaebb473ebbe30ba0fd8f5
Showing with 220 additions and 6 deletions.
  1. +10 −0 src/video/cocoa/SDL_cocoamodes.h
  2. +209 −6 src/video/cocoa/SDL_cocoamodes.m
  3. +1 −0 src/video/cocoa/SDL_cocoavideo.h
@@ -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"

0 comments on commit 4c46dad

Please sign in to comment.