comparison src/video/cocoa/SDL_cocoamodes.m @ 1934:70139af5ac27

Implemented Mac OS X video mode selection.
author Sam Lantinga <slouken@libsdl.org>
date Mon, 24 Jul 2006 07:21:16 +0000
parents 103c6fec2a60
children 5d3724f64f2b
comparison
equal deleted inserted replaced
1933:7ee5297340f7 1934:70139af5ac27
21 */ 21 */
22 #include "SDL_config.h" 22 #include "SDL_config.h"
23 23
24 #include "SDL_cocoavideo.h" 24 #include "SDL_cocoavideo.h"
25 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 }
26 115
27 void 116 void
28 Cocoa_InitModes(_THIS) 117 Cocoa_InitModes(_THIS)
29 { 118 {
30 SDL_VideoDisplay display; 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;
31 SDL_DisplayMode mode; 173 SDL_DisplayMode mode;
32 174
33 SDL_zero(display); 175 if (GetDisplayMode(moderef, &mode)) {
34 SDL_zero(mode); 176 SDL_AddDisplayMode(_this->current_display, &mode);
35 display.desktop_mode = mode; 177 }
36 display.current_mode = mode;
37 SDL_AddVideoDisplay(&display);
38 } 178 }
39 179
40 void 180 void
41 Cocoa_GetDisplayModes(_THIS) 181 Cocoa_GetDisplayModes(_THIS)
42 { 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);
43 } 194 }
44 195
45 int 196 int
46 Cocoa_SetDisplayMode(_THIS, SDL_DisplayMode * mode) 197 Cocoa_SetDisplayMode(_THIS, SDL_DisplayMode * mode)
47 { 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 }
48 return -1; 238 return -1;
49 } 239 }
50 240
51 void 241 void
52 Cocoa_QuitModes(_THIS) 242 Cocoa_QuitModes(_THIS)
53 { 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;
54 } 257 }
55 258
56 /* vi: set ts=4 sw=4 expandtab: */ 259 /* vi: set ts=4 sw=4 expandtab: */