zenilib  0.5.3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
SDL_cocoamodes.m
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
4 
5  This software is provided 'as-is', without any express or implied
6  warranty. In no event will the authors be held liable for any damages
7  arising from the use of this software.
8 
9  Permission is granted to anyone to use this software for any purpose,
10  including commercial applications, and to alter it and redistribute it
11  freely, subject to the following restrictions:
12 
13  1. The origin of this software must not be misrepresented; you must not
14  claim that you wrote the original software. If you use this software
15  in a product, an acknowledgment in the product documentation would be
16  appreciated but is not required.
17  2. Altered source versions must be plainly marked as such, and must not be
18  misrepresented as being the original software.
19  3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "SDL_config.h"
22 
23 #if SDL_VIDEO_DRIVER_COCOA
24 
25 #include "SDL_cocoavideo.h"
26 
27 /* We need this for IODisplayCreateInfoDictionary and kIODisplayOnlyPreferredName */
28 #include <IOKit/graphics/IOGraphicsLib.h>
29 
30 /* we need this for ShowMenuBar() and HideMenuBar(). */
31 #include <Carbon/Carbon.h>
32 
33 /* This gets us MAC_OS_X_VERSION_MIN_REQUIRED... */
34 #include <AvailabilityMacros.h>
35 
36 static inline void Cocoa_ToggleMenuBar(const BOOL show)
37 {
38  /* !!! FIXME: keep an eye on this.
39  * ShowMenuBar/HideMenuBar is officially unavailable for 64-bit binaries.
40  * It happens to work, as of 10.7, but we're going to see if
41  * we can just simply do without it on newer OSes...
42  */
43 #if (MAC_OS_X_VERSION_MIN_REQUIRED < 1070) && !defined(__LP64__)
44  if (show)
45  ShowMenuBar();
46  else
47  HideMenuBar();
48 #endif
49 }
50 
51 
52 /* !!! FIXME: clean out the pre-10.6 code when it makes sense to do so. */
53 #define FORCE_OLD_API 0
54 
55 #if FORCE_OLD_API
56 #undef MAC_OS_X_VERSION_MIN_REQUIRED
57 #define MAC_OS_X_VERSION_MIN_REQUIRED 1050
58 #endif
59 
60 static inline BOOL
61 IS_SNOW_LEOPARD_OR_LATER(_THIS)
62 {
63 #if FORCE_OLD_API
64  return NO;
65 #else
66  return ((((SDL_VideoData *) _this->driverdata))->osversion >= 0x1060);
67 #endif
68 }
69 
70 static int
71 CG_SetError(const char *prefix, CGDisplayErr result)
72 {
73  const char *error;
74 
75  switch (result) {
76  case kCGErrorFailure:
77  error = "kCGErrorFailure";
78  break;
79  case kCGErrorIllegalArgument:
80  error = "kCGErrorIllegalArgument";
81  break;
82  case kCGErrorInvalidConnection:
83  error = "kCGErrorInvalidConnection";
84  break;
85  case kCGErrorInvalidContext:
86  error = "kCGErrorInvalidContext";
87  break;
88  case kCGErrorCannotComplete:
89  error = "kCGErrorCannotComplete";
90  break;
91  case kCGErrorNotImplemented:
92  error = "kCGErrorNotImplemented";
93  break;
94  case kCGErrorRangeCheck:
95  error = "kCGErrorRangeCheck";
96  break;
97  case kCGErrorTypeCheck:
98  error = "kCGErrorTypeCheck";
99  break;
100  case kCGErrorInvalidOperation:
101  error = "kCGErrorInvalidOperation";
102  break;
103  case kCGErrorNoneAvailable:
104  error = "kCGErrorNoneAvailable";
105  break;
106  default:
107  error = "Unknown Error";
108  break;
109  }
110  return SDL_SetError("%s: %s", prefix, error);
111 }
112 
113 static SDL_bool
114 GetDisplayMode(_THIS, const void *moderef, SDL_DisplayMode *mode)
115 {
117  long width = 0;
118  long height = 0;
119  long bpp = 0;
120  long refreshRate = 0;
121 
122  data = (SDL_DisplayModeData *) SDL_malloc(sizeof(*data));
123  if (!data) {
124  return SDL_FALSE;
125  }
126  data->moderef = moderef;
127 
128  if (IS_SNOW_LEOPARD_OR_LATER(_this)) {
129  CGDisplayModeRef vidmode = (CGDisplayModeRef) moderef;
130  CFStringRef fmt = CGDisplayModeCopyPixelEncoding(vidmode);
131  width = (long) CGDisplayModeGetWidth(vidmode);
132  height = (long) CGDisplayModeGetHeight(vidmode);
133  refreshRate = (long) CGDisplayModeGetRefreshRate(vidmode);
134 
135  if (CFStringCompare(fmt, CFSTR(IO32BitDirectPixels),
136  kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
137  bpp = 32;
138  } else if (CFStringCompare(fmt, CFSTR(IO16BitDirectPixels),
139  kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
140  bpp = 16;
141  } else {
142  bpp = 0; /* ignore 8-bit and such for now. */
143  }
144 
145  CFRelease(fmt);
146  }
147 
148  #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
149  if (!IS_SNOW_LEOPARD_OR_LATER(_this)) {
150  CFNumberRef number;
151  CFDictionaryRef vidmode = (CFDictionaryRef) moderef;
152  number = CFDictionaryGetValue(vidmode, kCGDisplayWidth);
153  CFNumberGetValue(number, kCFNumberLongType, &width);
154  number = CFDictionaryGetValue(vidmode, kCGDisplayHeight);
155  CFNumberGetValue(number, kCFNumberLongType, &height);
156  number = CFDictionaryGetValue(vidmode, kCGDisplayBitsPerPixel);
157  CFNumberGetValue(number, kCFNumberLongType, &bpp);
158  number = CFDictionaryGetValue(vidmode, kCGDisplayRefreshRate);
159  CFNumberGetValue(number, kCFNumberLongType, &refreshRate);
160  }
161  #endif
162 
164  switch (bpp) {
165  case 16:
167  break;
168  case 32:
170  break;
171  case 8: /* We don't support palettized modes now */
172  default: /* Totally unrecognizable bit depth. */
173  return SDL_FALSE;
174  }
175  mode->w = width;
176  mode->h = height;
177  mode->refresh_rate = refreshRate;
178  mode->driverdata = data;
179  return SDL_TRUE;
180 }
181 
182 static inline void
183 Cocoa_ReleaseDisplayMode(_THIS, const void *moderef)
184 {
185  if (IS_SNOW_LEOPARD_OR_LATER(_this)) {
186  CGDisplayModeRelease((CGDisplayModeRef) moderef); /* NULL is ok */
187  }
188 }
189 
190 static inline void
191 Cocoa_ReleaseDisplayModeList(_THIS, CFArrayRef modelist)
192 {
193  if (IS_SNOW_LEOPARD_OR_LATER(_this)) {
194  CFRelease(modelist); /* NULL is ok */
195  }
196 }
197 
198 static const char *
199 Cocoa_GetDisplayName(CGDirectDisplayID displayID)
200 {
201  NSDictionary *deviceInfo = (NSDictionary *)IODisplayCreateInfoDictionary(CGDisplayIOServicePort(displayID), kIODisplayOnlyPreferredName);
202  NSDictionary *localizedNames = [deviceInfo objectForKey:[NSString stringWithUTF8String:kDisplayProductName]];
203  const char* displayName = NULL;
204 
205  if ([localizedNames count] > 0) {
206  displayName = SDL_strdup([[localizedNames objectForKey:[[localizedNames allKeys] objectAtIndex:0]] UTF8String]);
207  }
208  [deviceInfo release];
209  return displayName;
210 }
211 
212 void
214 {
215  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
216  CGDisplayErr result;
217  CGDirectDisplayID *displays;
218  CGDisplayCount numDisplays;
219  int pass, i;
220 
221  result = CGGetOnlineDisplayList(0, NULL, &numDisplays);
222  if (result != kCGErrorSuccess) {
223  CG_SetError("CGGetOnlineDisplayList()", result);
224  [pool release];
225  return;
226  }
227  displays = SDL_stack_alloc(CGDirectDisplayID, numDisplays);
228  result = CGGetOnlineDisplayList(numDisplays, displays, &numDisplays);
229  if (result != kCGErrorSuccess) {
230  CG_SetError("CGGetOnlineDisplayList()", result);
231  SDL_stack_free(displays);
232  [pool release];
233  return;
234  }
235 
236  /* Pick up the primary display in the first pass, then get the rest */
237  for (pass = 0; pass < 2; ++pass) {
238  for (i = 0; i < numDisplays; ++i) {
240  SDL_DisplayData *displaydata;
242  const void *moderef = NULL;
243 
244  if (pass == 0) {
245  if (!CGDisplayIsMain(displays[i])) {
246  continue;
247  }
248  } else {
249  if (CGDisplayIsMain(displays[i])) {
250  continue;
251  }
252  }
253 
254  if (CGDisplayMirrorsDisplay(displays[i]) != kCGNullDirectDisplay) {
255  continue;
256  }
257 
258  if (IS_SNOW_LEOPARD_OR_LATER(_this)) {
259  moderef = CGDisplayCopyDisplayMode(displays[i]);
260  }
261 
262  #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
263  if (!IS_SNOW_LEOPARD_OR_LATER(_this)) {
264  moderef = CGDisplayCurrentMode(displays[i]);
265  }
266  #endif
267 
268  if (!moderef) {
269  continue;
270  }
271 
272  displaydata = (SDL_DisplayData *) SDL_malloc(sizeof(*displaydata));
273  if (!displaydata) {
274  Cocoa_ReleaseDisplayMode(_this, moderef);
275  continue;
276  }
277  displaydata->display = displays[i];
278 
279  SDL_zero(display);
280  /* this returns a stddup'ed string */
281  display.name = (char *)Cocoa_GetDisplayName(displays[i]);
282  if (!GetDisplayMode (_this, moderef, &mode)) {
283  Cocoa_ReleaseDisplayMode(_this, moderef);
284  SDL_free(display.name);
285  SDL_free(displaydata);
286  continue;
287  }
288 
289  display.desktop_mode = mode;
290  display.current_mode = mode;
291  display.driverdata = displaydata;
292  SDL_AddVideoDisplay(&display);
293  SDL_free(display.name);
294  }
295  }
296  SDL_stack_free(displays);
297  [pool release];
298 }
299 
300 int
302 {
303  SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata;
304  CGRect cgrect;
305 
306  cgrect = CGDisplayBounds(displaydata->display);
307  rect->x = (int)cgrect.origin.x;
308  rect->y = (int)cgrect.origin.y;
309  rect->w = (int)cgrect.size.width;
310  rect->h = (int)cgrect.size.height;
311  return 0;
312 }
313 
314 void
316 {
317  SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
318  CFArrayRef modes = NULL;
319 
320  if (IS_SNOW_LEOPARD_OR_LATER(_this)) {
321  modes = CGDisplayCopyAllDisplayModes(data->display, NULL);
322  }
323 
324  #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
325  if (!IS_SNOW_LEOPARD_OR_LATER(_this)) {
326  modes = CGDisplayAvailableModes(data->display);
327  }
328  #endif
329 
330  if (modes) {
331  const CFIndex count = CFArrayGetCount(modes);
332  CFIndex i;
333 
334  for (i = 0; i < count; i++) {
335  const void *moderef = CFArrayGetValueAtIndex(modes, i);
337  if (GetDisplayMode(_this, moderef, &mode)) {
338  if (IS_SNOW_LEOPARD_OR_LATER(_this)) {
339  CGDisplayModeRetain((CGDisplayModeRef) moderef);
340  }
341  SDL_AddDisplayMode(display, &mode);
342  }
343  }
344 
345  Cocoa_ReleaseDisplayModeList(_this, modes);
346  }
347 }
348 
349 static CGError
350 Cocoa_SwitchMode(_THIS, CGDirectDisplayID display, const void *mode)
351 {
352  if (IS_SNOW_LEOPARD_OR_LATER(_this)) {
353  return CGDisplaySetDisplayMode(display, (CGDisplayModeRef) mode, NULL);
354  }
355 
356  #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
357  if (!IS_SNOW_LEOPARD_OR_LATER(_this)) {
358  return CGDisplaySwitchToMode(display, (CFDictionaryRef) mode);
359  }
360  #endif
361 
362  return kCGErrorFailure;
363 }
364 
365 int
367 {
368  SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata;
370  CGDisplayFadeReservationToken fade_token = kCGDisplayFadeReservationInvalidToken;
371  CGError result;
372 
373  /* Fade to black to hide resolution-switching flicker */
374  if (CGAcquireDisplayFadeReservation(5, &fade_token) == kCGErrorSuccess) {
375  CGDisplayFade(fade_token, 0.3, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0, TRUE);
376  }
377 
378  if (data == display->desktop_mode.driverdata) {
379  /* Restoring desktop mode */
380  Cocoa_SwitchMode(_this, displaydata->display, data->moderef);
381 
382  if (CGDisplayIsMain(displaydata->display)) {
383  CGReleaseAllDisplays();
384  } else {
385  CGDisplayRelease(displaydata->display);
386  }
387 
388  if (CGDisplayIsMain(displaydata->display)) {
389  Cocoa_ToggleMenuBar(YES);
390  }
391  } else {
392  /* Put up the blanking window (a window above all other windows) */
393  if (CGDisplayIsMain(displaydata->display)) {
394  /* If we don't capture all displays, Cocoa tries to rearrange windows... *sigh* */
395  result = CGCaptureAllDisplays();
396  } else {
397  result = CGDisplayCapture(displaydata->display);
398  }
399  if (result != kCGErrorSuccess) {
400  CG_SetError("CGDisplayCapture()", result);
401  goto ERR_NO_CAPTURE;
402  }
403 
404  /* Do the physical switch */
405  result = Cocoa_SwitchMode(_this, displaydata->display, data->moderef);
406  if (result != kCGErrorSuccess) {
407  CG_SetError("CGDisplaySwitchToMode()", result);
408  goto ERR_NO_SWITCH;
409  }
410 
411  /* Hide the menu bar so it doesn't intercept events */
412  if (CGDisplayIsMain(displaydata->display)) {
413  Cocoa_ToggleMenuBar(NO);
414  }
415  }
416 
417  /* Fade in again (asynchronously) */
418  if (fade_token != kCGDisplayFadeReservationInvalidToken) {
419  CGDisplayFade(fade_token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE);
420  CGReleaseDisplayFadeReservation(fade_token);
421  }
422 
423  return 0;
424 
425  /* Since the blanking window covers *all* windows (even force quit) correct recovery is crucial */
426 ERR_NO_SWITCH:
427  CGDisplayRelease(displaydata->display);
428 ERR_NO_CAPTURE:
429  if (fade_token != kCGDisplayFadeReservationInvalidToken) {
430  CGDisplayFade (fade_token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE);
431  CGReleaseDisplayFadeReservation(fade_token);
432  }
433  return -1;
434 }
435 
436 void
438 {
439  int i, j;
440 
441  for (i = 0; i < _this->num_displays; ++i) {
442  SDL_VideoDisplay *display = &_this->displays[i];
444 
445  if (display->current_mode.driverdata != display->desktop_mode.driverdata) {
446  Cocoa_SetDisplayMode(_this, display, &display->desktop_mode);
447  }
448 
449  mode = (SDL_DisplayModeData *) display->desktop_mode.driverdata;
450  Cocoa_ReleaseDisplayMode(_this, mode->moderef);
451 
452  for (j = 0; j < display->num_display_modes; j++) {
453  mode = (SDL_DisplayModeData*) display->display_modes[j].driverdata;
454  Cocoa_ReleaseDisplayMode(_this, mode->moderef);
455  }
456 
457  }
458  Cocoa_ToggleMenuBar(YES);
459 }
460 
461 #endif /* SDL_VIDEO_DRIVER_COCOA */
462 
463 /* vi: set ts=4 sw=4 expandtab: */
void Cocoa_GetDisplayModes(_THIS, SDL_VideoDisplay *display)
const void * moderef
#define NULL
Definition: ftobjs.h:61
#define SDL_stack_free(data)
Definition: SDL_stdinc.h:227
SDL_bool
Definition: SDL_stdinc.h:116
DECLSPEC void SDLCALL SDL_free(void *mem)
The structure that defines a display mode.
Definition: SDL_video.h:53
int32_t j
Definition: e_log.c:102
EGLSurface EGLint EGLint EGLint EGLint height
Definition: eglext.h:293
char * display
Definition: visualinfo.c:85
CGDirectDisplayID display
if(!yyg->yy_init)
int SDL_AddVideoDisplay(const SDL_VideoDisplay *display)
Definition: SDL_video.c:568
static SDL_VideoDevice * _this
Definition: SDL_video.c:92
GLuint64EXT * result
Definition: glew.h:12708
int Cocoa_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
int
Definition: SDL_systhread.c:37
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl2ext.h:848
FT_Error error
Definition: cffdrivr.c:407
EGLSurface EGLint EGLint EGLint width
Definition: eglext.h:293
#define _THIS
DECLSPEC char *SDLCALL SDL_strdup(const char *str)
Definition: SDL_string.c:511
void * driverdata
Definition: SDL_video.h:59
GLint GLsizei count
Definition: gl2ext.h:1011
SDL_DisplayMode * display_modes
Definition: SDL_sysvideo.h:118
SDL_DisplayMode current_mode
Definition: SDL_sysvideo.h:120
SDL_VideoDisplay * displays
Definition: SDL_sysvideo.h:265
DECLSPEC int SDLCALL SDL_SetError(const char *fmt,...)
Definition: SDL_error.c:53
DECLSPEC void *SDLCALL SDL_malloc(size_t size)
int x
Definition: SDL_rect.h:65
#define FALSE
Definition: ftobjs.h:57
int w
Definition: SDL_rect.h:66
SDL_DisplayMode desktop_mode
Definition: SDL_sysvideo.h:119
int h
Definition: SDL_rect.h:66
SDL_bool SDL_AddDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode)
Definition: SDL_video.c:666
#define SDL_stack_alloc(type, count)
Definition: SDL_stdinc.h:226
#define SDL_zero(x)
Definition: SDL_stdinc.h:254
int Cocoa_GetDisplayBounds(_THIS, SDL_VideoDisplay *display, SDL_Rect *rect)
Uint32 format
Definition: SDL_video.h:55
int i
Definition: pngrutil.c:1377
void Cocoa_QuitModes(_THIS)
void Cocoa_InitModes(_THIS)
int y
Definition: SDL_rect.h:65
GLenum mode
Definition: glew.h:2394
#define TRUE
Definition: ftobjs.h:53
A rectangle, with the origin at the upper left.
Definition: SDL_rect.h:63
typedef BOOL(WINAPI *PFNWGLSETSTEREOEMITTERSTATE3DLPROC)(HDC hDC