SDL  2.0
SDL_cocoamodes.m
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2020 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_internal.h"
22 #include "SDL_assert.h"
23 
24 #if SDL_VIDEO_DRIVER_COCOA
25 
26 #include "SDL_cocoavideo.h"
27 
28 /* We need this for IODisplayCreateInfoDictionary and kIODisplayOnlyPreferredName */
29 #include <IOKit/graphics/IOGraphicsLib.h>
30 
31 /* We need this for CVDisplayLinkGetNominalOutputVideoRefreshPeriod */
32 #include <CoreVideo/CVBase.h>
33 #include <CoreVideo/CVDisplayLink.h>
34 
35 /* we need this for ShowMenuBar() and HideMenuBar(). */
36 #include <Carbon/Carbon.h>
37 
38 /* This gets us MAC_OS_X_VERSION_MIN_REQUIRED... */
39 #include <AvailabilityMacros.h>
40 
41 #ifndef MAC_OS_X_VERSION_10_13
42 #define NSAppKitVersionNumber10_12 1504
43 #endif
44 
45 
46 static void
47 Cocoa_ToggleMenuBar(const BOOL show)
48 {
49  /* !!! FIXME: keep an eye on this.
50  * ShowMenuBar/HideMenuBar is officially unavailable for 64-bit binaries.
51  * It happens to work, as of 10.7, but we're going to see if
52  * we can just simply do without it on newer OSes...
53  */
54 #if (MAC_OS_X_VERSION_MIN_REQUIRED < 1070) && !defined(__LP64__)
55  if (show) {
56  ShowMenuBar();
57  } else {
58  HideMenuBar();
59  }
60 #endif
61 }
62 
63 static int
64 CG_SetError(const char *prefix, CGDisplayErr result)
65 {
66  const char *error;
67 
68  switch (result) {
69  case kCGErrorFailure:
70  error = "kCGErrorFailure";
71  break;
72  case kCGErrorIllegalArgument:
73  error = "kCGErrorIllegalArgument";
74  break;
75  case kCGErrorInvalidConnection:
76  error = "kCGErrorInvalidConnection";
77  break;
78  case kCGErrorInvalidContext:
79  error = "kCGErrorInvalidContext";
80  break;
81  case kCGErrorCannotComplete:
82  error = "kCGErrorCannotComplete";
83  break;
84  case kCGErrorNotImplemented:
85  error = "kCGErrorNotImplemented";
86  break;
87  case kCGErrorRangeCheck:
88  error = "kCGErrorRangeCheck";
89  break;
90  case kCGErrorTypeCheck:
91  error = "kCGErrorTypeCheck";
92  break;
93  case kCGErrorInvalidOperation:
94  error = "kCGErrorInvalidOperation";
95  break;
96  case kCGErrorNoneAvailable:
97  error = "kCGErrorNoneAvailable";
98  break;
99  default:
100  error = "Unknown Error";
101  break;
102  }
103  return SDL_SetError("%s: %s", prefix, error);
104 }
105 
106 static int
107 GetDisplayModeRefreshRate(CGDisplayModeRef vidmode, CVDisplayLinkRef link)
108 {
109  int refreshRate = (int) (CGDisplayModeGetRefreshRate(vidmode) + 0.5);
110 
111  /* CGDisplayModeGetRefreshRate can return 0 (eg for built-in displays). */
112  if (refreshRate == 0 && link != NULL) {
113  CVTime time = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(link);
114  if ((time.flags & kCVTimeIsIndefinite) == 0 && time.timeValue != 0) {
115  refreshRate = (int) ((time.timeScale / (double) time.timeValue) + 0.5);
116  }
117  }
118 
119  return refreshRate;
120 }
121 
122 static SDL_bool
123 HasValidDisplayModeFlags(CGDisplayModeRef vidmode)
124 {
125  uint32_t ioflags = CGDisplayModeGetIOFlags(vidmode);
126 
127  /* Filter out modes which have flags that we don't want. */
128  if (ioflags & (kDisplayModeNeverShowFlag | kDisplayModeNotGraphicsQualityFlag)) {
129  return SDL_FALSE;
130  }
131 
132  /* Filter out modes which don't have flags that we want. */
133  if (!(ioflags & kDisplayModeValidFlag) || !(ioflags & kDisplayModeSafeFlag)) {
134  return SDL_FALSE;
135  }
136 
137  return SDL_TRUE;
138 }
139 
140 static Uint32
141 GetDisplayModePixelFormat(CGDisplayModeRef vidmode)
142 {
143  /* This API is deprecated in 10.11 with no good replacement (as of 10.15). */
144  CFStringRef fmt = CGDisplayModeCopyPixelEncoding(vidmode);
145  Uint32 pixelformat = SDL_PIXELFORMAT_UNKNOWN;
146 
147  if (CFStringCompare(fmt, CFSTR(IO32BitDirectPixels),
148  kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
149  pixelformat = SDL_PIXELFORMAT_ARGB8888;
150  } else if (CFStringCompare(fmt, CFSTR(IO16BitDirectPixels),
151  kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
152  pixelformat = SDL_PIXELFORMAT_ARGB1555;
153  } else if (CFStringCompare(fmt, CFSTR(kIO30BitDirectPixels),
154  kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
155  pixelformat = SDL_PIXELFORMAT_ARGB2101010;
156  } else {
157  /* ignore 8-bit and such for now. */
158  }
159 
160  CFRelease(fmt);
161 
162  return pixelformat;
163 }
164 
165 static SDL_bool
166 GetDisplayMode(_THIS, CGDisplayModeRef vidmode, CFArrayRef modelist, CVDisplayLinkRef link, SDL_DisplayMode *mode)
167 {
169  bool usableForGUI = CGDisplayModeIsUsableForDesktopGUI(vidmode);
170  int width = (int) CGDisplayModeGetWidth(vidmode);
171  int height = (int) CGDisplayModeGetHeight(vidmode);
172  uint32_t ioflags = CGDisplayModeGetIOFlags(vidmode);
173  int refreshrate = GetDisplayModeRefreshRate(vidmode, link);
174  Uint32 format = GetDisplayModePixelFormat(vidmode);
175  bool interlaced = (ioflags & kDisplayModeInterlacedFlag) != 0;
176  CFMutableArrayRef modes;
177 
179  return SDL_FALSE;
180  }
181 
182  if (!HasValidDisplayModeFlags(vidmode)) {
183  return SDL_FALSE;
184  }
185 
186  modes = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
187  CFArrayAppendValue(modes, vidmode);
188 
189  /* If a list of possible diplay modes is passed in, use it to filter out
190  * modes that have duplicate sizes. We don't just rely on SDL's higher level
191  * duplicate filtering because this code can choose what properties are
192  * prefered, and it can add CGDisplayModes to the DisplayModeData's list of
193  * modes to try (see comment below for why that's necessary).
194  * CGDisplayModeGetPixelWidth and friends are only available in 10.8+. */
195 #ifdef MAC_OS_X_VERSION_10_8
196  if (modelist != NULL && floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_7) {
197  int pixelW = (int) CGDisplayModeGetPixelWidth(vidmode);
198  int pixelH = (int) CGDisplayModeGetPixelHeight(vidmode);
199 
200  CFIndex modescount = CFArrayGetCount(modelist);
201 
202  for (int i = 0; i < modescount; i++) {
203  CGDisplayModeRef othermode = (CGDisplayModeRef) CFArrayGetValueAtIndex(modelist, i);
204  uint32_t otherioflags = CGDisplayModeGetIOFlags(othermode);
205 
206  if (CFEqual(vidmode, othermode)) {
207  continue;
208  }
209 
210  if (!HasValidDisplayModeFlags(othermode)) {
211  continue;
212  }
213 
214  int otherW = (int) CGDisplayModeGetWidth(othermode);
215  int otherH = (int) CGDisplayModeGetHeight(othermode);
216  int otherpixelW = (int) CGDisplayModeGetPixelWidth(othermode);
217  int otherpixelH = (int) CGDisplayModeGetPixelHeight(othermode);
218  int otherrefresh = GetDisplayModeRefreshRate(othermode, link);
219  Uint32 otherformat = GetDisplayModePixelFormat(othermode);
220  bool otherGUI = CGDisplayModeIsUsableForDesktopGUI(othermode);
221 
222  /* Ignore this mode if it's low-dpi (@1x) and we have a high-dpi
223  * mode in the list with the same size in points.
224  */
225  if (width == pixelW && height == pixelH
226  && width == otherW && height == otherH
227  && refreshrate == otherrefresh && format == otherformat
228  && (otherpixelW != otherW || otherpixelH != otherH)) {
229  CFRelease(modes);
230  return SDL_FALSE;
231  }
232 
233  /* Ignore this mode if it's interlaced and there's a non-interlaced
234  * mode in the list with the same properties.
235  */
236  if (interlaced && ((otherioflags & kDisplayModeInterlacedFlag) == 0)
237  && width == otherW && height == otherH && pixelW == otherpixelW
238  && pixelH == otherpixelH && refreshrate == otherrefresh
239  && format == otherformat && usableForGUI == otherGUI) {
240  CFRelease(modes);
241  return SDL_FALSE;
242  }
243 
244  /* Ignore this mode if it's not usable for desktop UI and its
245  * properties are equal to another GUI-capable mode in the list.
246  */
247  if (width == otherW && height == otherH && pixelW == otherpixelW
248  && pixelH == otherpixelH && !usableForGUI && otherGUI
249  && refreshrate == otherrefresh && format == otherformat) {
250  CFRelease(modes);
251  return SDL_FALSE;
252  }
253 
254  /* If multiple modes have the exact same properties, they'll all
255  * go in the list of modes to try when SetDisplayMode is called.
256  * This is needed because kCGDisplayShowDuplicateLowResolutionModes
257  * (which is used to expose highdpi display modes) can make the
258  * list of modes contain duplicates (according to their properties
259  * obtained via public APIs) which don't work with SetDisplayMode.
260  * Those duplicate non-functional modes *do* have different pixel
261  * formats according to their internal data structure viewed with
262  * NSLog, but currently no public API can detect that.
263  * https://bugzilla.libsdl.org/show_bug.cgi?id=4822
264  *
265  * As of macOS 10.15.0, those duplicates have the exact same
266  * properties via public APIs in every way (even their IO flags and
267  * CGDisplayModeGetIODisplayModeID is the same), so we could test
268  * those for equality here too, but I'm intentionally not doing that
269  * in case there are duplicate modes with different IO flags or IO
270  * display mode IDs in the future. In that case I think it's better
271  * to try them all in SetDisplayMode than to risk one of them being
272  * correct but it being filtered out by SDL_AddDisplayMode as being
273  * a duplicate.
274  */
275  if (width == otherW && height == otherH && pixelW == otherpixelW
276  && pixelH == otherpixelH && usableForGUI == otherGUI
277  && refreshrate == otherrefresh && format == otherformat) {
278  CFArrayAppendValue(modes, othermode);
279  }
280  }
281  }
282 #endif
283 
284  data = (SDL_DisplayModeData *) SDL_malloc(sizeof(*data));
285  if (!data) {
286  CFRelease(modes);
287  return SDL_FALSE;
288  }
289  data->modes = modes;
290  mode->format = format;
291  mode->w = width;
292  mode->h = height;
293  mode->refresh_rate = refreshrate;
294  mode->driverdata = data;
295  return SDL_TRUE;
296 }
297 
298 static const char *
299 Cocoa_GetDisplayName(CGDirectDisplayID displayID)
300 {
301  /* This API is deprecated in 10.9 with no good replacement (as of 10.15). */
302  io_service_t servicePort = CGDisplayIOServicePort(displayID);
303  CFDictionaryRef deviceInfo = IODisplayCreateInfoDictionary(servicePort, kIODisplayOnlyPreferredName);
304  NSDictionary *localizedNames = [(NSDictionary *)deviceInfo objectForKey:[NSString stringWithUTF8String:kDisplayProductName]];
305  const char* displayName = NULL;
306 
307  if ([localizedNames count] > 0) {
308  displayName = SDL_strdup([[localizedNames objectForKey:[[localizedNames allKeys] objectAtIndex:0]] UTF8String]);
309  }
310  CFRelease(deviceInfo);
311  return displayName;
312 }
313 
314 void
316 { @autoreleasepool
317 {
318  CGDisplayErr result;
319  CGDirectDisplayID *displays;
320  CGDisplayCount numDisplays;
321  SDL_bool isstack;
322  int pass, i;
323 
324  result = CGGetOnlineDisplayList(0, NULL, &numDisplays);
325  if (result != kCGErrorSuccess) {
326  CG_SetError("CGGetOnlineDisplayList()", result);
327  return;
328  }
329  displays = SDL_small_alloc(CGDirectDisplayID, numDisplays, &isstack);
330  result = CGGetOnlineDisplayList(numDisplays, displays, &numDisplays);
331  if (result != kCGErrorSuccess) {
332  CG_SetError("CGGetOnlineDisplayList()", result);
333  SDL_small_free(displays, isstack);
334  return;
335  }
336 
337  /* Pick up the primary display in the first pass, then get the rest */
338  for (pass = 0; pass < 2; ++pass) {
339  for (i = 0; i < numDisplays; ++i) {
340  SDL_VideoDisplay display;
341  SDL_DisplayData *displaydata;
343  CGDisplayModeRef moderef = NULL;
344  CVDisplayLinkRef link = NULL;
345 
346  if (pass == 0) {
347  if (!CGDisplayIsMain(displays[i])) {
348  continue;
349  }
350  } else {
351  if (CGDisplayIsMain(displays[i])) {
352  continue;
353  }
354  }
355 
356  if (CGDisplayMirrorsDisplay(displays[i]) != kCGNullDirectDisplay) {
357  continue;
358  }
359 
360  moderef = CGDisplayCopyDisplayMode(displays[i]);
361 
362  if (!moderef) {
363  continue;
364  }
365 
366  displaydata = (SDL_DisplayData *) SDL_malloc(sizeof(*displaydata));
367  if (!displaydata) {
368  CGDisplayModeRelease(moderef);
369  continue;
370  }
371  displaydata->display = displays[i];
372 
373  CVDisplayLinkCreateWithCGDisplay(displays[i], &link);
374 
375  SDL_zero(display);
376  /* this returns a stddup'ed string */
377  display.name = (char *)Cocoa_GetDisplayName(displays[i]);
378  if (!GetDisplayMode(_this, moderef, NULL, link, &mode)) {
379  CVDisplayLinkRelease(link);
380  CGDisplayModeRelease(moderef);
381  SDL_free(display.name);
382  SDL_free(displaydata);
383  continue;
384  }
385 
386  CVDisplayLinkRelease(link);
387  CGDisplayModeRelease(moderef);
388 
389  display.desktop_mode = mode;
390  display.current_mode = mode;
391  display.driverdata = displaydata;
392  SDL_AddVideoDisplay(&display);
393  SDL_free(display.name);
394  }
395  }
396  SDL_small_free(displays, isstack);
397 }}
398 
399 int
401 {
402  SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata;
403  CGRect cgrect;
404 
405  cgrect = CGDisplayBounds(displaydata->display);
406  rect->x = (int)cgrect.origin.x;
407  rect->y = (int)cgrect.origin.y;
408  rect->w = (int)cgrect.size.width;
409  rect->h = (int)cgrect.size.height;
410  return 0;
411 }
412 
413 int
415 {
416  SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata;
417  const CGDirectDisplayID cgdisplay = displaydata->display;
418  NSArray *screens = [NSScreen screens];
419  NSScreen *screen = nil;
420 
421  /* !!! FIXME: maybe track the NSScreen in SDL_DisplayData? */
422  for (NSScreen *i in screens) {
423  const CGDirectDisplayID thisDisplay = (CGDirectDisplayID) [[[i deviceDescription] objectForKey:@"NSScreenNumber"] unsignedIntValue];
424  if (thisDisplay == cgdisplay) {
425  screen = i;
426  break;
427  }
428  }
429 
430  SDL_assert(screen != nil); /* didn't find it?! */
431  if (screen == nil) {
432  return -1;
433  }
434 
435  const NSRect frame = [screen visibleFrame];
436  rect->x = (int)frame.origin.x;
437  rect->y = (int)(CGDisplayPixelsHigh(kCGDirectMainDisplay) - frame.origin.y - frame.size.height);
438  rect->w = (int)frame.size.width;
439  rect->h = (int)frame.size.height;
440 
441  return 0;
442 }
443 
444 int
445 Cocoa_GetDisplayDPI(_THIS, SDL_VideoDisplay * display, float * ddpi, float * hdpi, float * vdpi)
446 { @autoreleasepool
447 {
448  const float MM_IN_INCH = 25.4f;
449 
451 
452  /* we need the backingScaleFactor for Retina displays, which is only exposed through NSScreen, not CGDisplay, afaik, so find our screen... */
453  CGFloat scaleFactor = 1.0f;
454  NSArray *screens = [NSScreen screens];
455  for (NSScreen *screen in screens) {
456  const CGDirectDisplayID dpyid = (const CGDirectDisplayID ) [[[screen deviceDescription] objectForKey:@"NSScreenNumber"] unsignedIntValue];
457  if (dpyid == data->display) {
458  if ([screen respondsToSelector:@selector(backingScaleFactor)]) { // Mac OS X 10.7 and later
459  scaleFactor = [screen backingScaleFactor];
460  break;
461  }
462  }
463  }
464 
465  const CGSize displaySize = CGDisplayScreenSize(data->display);
466  const int pixelWidth = (int) CGDisplayPixelsWide(data->display);
467  const int pixelHeight = (int) CGDisplayPixelsHigh(data->display);
468 
469  if (ddpi) {
470  *ddpi = (SDL_ComputeDiagonalDPI(pixelWidth, pixelHeight, displaySize.width / MM_IN_INCH, displaySize.height / MM_IN_INCH)) * scaleFactor;
471  }
472  if (hdpi) {
473  *hdpi = (pixelWidth * MM_IN_INCH / displaySize.width) * scaleFactor;
474  }
475  if (vdpi) {
476  *vdpi = (pixelHeight * MM_IN_INCH / displaySize.height) * scaleFactor;
477  }
478 
479  return 0;
480 }}
481 
482 void
484 {
486  CVDisplayLinkRef link = NULL;
487  CGDisplayModeRef desktopmoderef;
488  SDL_DisplayMode desktopmode;
489  CFArrayRef modes;
490  CFDictionaryRef dict = NULL;
491 
492  CVDisplayLinkCreateWithCGDisplay(data->display, &link);
493 
494  desktopmoderef = CGDisplayCopyDisplayMode(data->display);
495 
496  /* CopyAllDisplayModes won't always contain the desktop display mode (if
497  * NULL is passed in) - for example on a retina 15" MBP, System Preferences
498  * allows choosing 1920x1200 but it's not in the list. AddDisplayMode makes
499  * sure there are no duplicates so it's safe to always add the desktop mode
500  * even in cases where it is in the CopyAllDisplayModes list.
501  */
502  if (desktopmoderef && GetDisplayMode(_this, desktopmoderef, NULL, link, &desktopmode)) {
503  if (!SDL_AddDisplayMode(display, &desktopmode)) {
504  CFRelease(((SDL_DisplayModeData*)desktopmode.driverdata)->modes);
505  SDL_free(desktopmode.driverdata);
506  }
507  }
508 
509  CGDisplayModeRelease(desktopmoderef);
510 
511  /* By default, CGDisplayCopyAllDisplayModes will only get a subset of the
512  * system's available modes. For example on a 15" 2016 MBP, users can
513  * choose 1920x1080@2x in System Preferences but it won't show up here,
514  * unless we specify the option below.
515  * The display modes returned by CGDisplayCopyAllDisplayModes are also not
516  * high dpi-capable unless this option is set.
517  * macOS 10.15 also seems to have a bug where entering, exiting, and
518  * re-entering exclusive fullscreen with a low dpi display mode can cause
519  * the content of the screen to move up, which this setting avoids:
520  * https://bugzilla.libsdl.org/show_bug.cgi?id=4822
521  */
522 #ifdef MAC_OS_X_VERSION_10_8
523  if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_7) {
524  const CFStringRef dictkeys[] = {kCGDisplayShowDuplicateLowResolutionModes};
525  const CFBooleanRef dictvalues[] = {kCFBooleanTrue};
526  dict = CFDictionaryCreate(NULL,
527  (const void **)dictkeys,
528  (const void **)dictvalues,
529  1,
530  &kCFCopyStringDictionaryKeyCallBacks,
531  &kCFTypeDictionaryValueCallBacks);
532  }
533 #endif
534 
535  modes = CGDisplayCopyAllDisplayModes(data->display, dict);
536 
537  if (dict) {
538  CFRelease(dict);
539  }
540 
541  if (modes) {
542  CFIndex i;
543  const CFIndex count = CFArrayGetCount(modes);
544 
545  for (i = 0; i < count; i++) {
546  CGDisplayModeRef moderef = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i);
548 
549  if (GetDisplayMode(_this, moderef, modes, link, &mode)) {
550  if (!SDL_AddDisplayMode(display, &mode)) {
551  CFRelease(((SDL_DisplayModeData*)mode.driverdata)->modes);
552  SDL_free(mode.driverdata);
553  }
554  }
555  }
556 
557  CFRelease(modes);
558  }
559 
560  CVDisplayLinkRelease(link);
561 }
562 
563 static CGError
564 SetDisplayModeForDisplay(CGDirectDisplayID display, SDL_DisplayModeData *data)
565 {
566  /* SDL_DisplayModeData can contain multiple CGDisplayModes to try (with
567  * identical properties), some of which might not work. See GetDisplayMode.
568  */
569  CGError result = kCGErrorFailure;
570  for (CFIndex i = 0; i < CFArrayGetCount(data->modes); i++) {
571  CGDisplayModeRef moderef = (CGDisplayModeRef)CFArrayGetValueAtIndex(data->modes, i);
572  result = CGDisplaySetDisplayMode(display, moderef, NULL);
573  if (result == kCGErrorSuccess) {
574  /* If this mode works, try it first next time. */
575  CFArrayExchangeValuesAtIndices(data->modes, i, 0);
576  break;
577  }
578  }
579  return result;
580 }
581 
582 int
584 {
585  SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata;
587  CGDisplayFadeReservationToken fade_token = kCGDisplayFadeReservationInvalidToken;
588  CGError result;
589 
590  /* Fade to black to hide resolution-switching flicker */
591  if (CGAcquireDisplayFadeReservation(5, &fade_token) == kCGErrorSuccess) {
592  CGDisplayFade(fade_token, 0.3, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0, TRUE);
593  }
594 
595  if (data == display->desktop_mode.driverdata) {
596  /* Restoring desktop mode */
597  SetDisplayModeForDisplay(displaydata->display, data);
598 
599  if (CGDisplayIsMain(displaydata->display)) {
600  CGReleaseAllDisplays();
601  } else {
602  CGDisplayRelease(displaydata->display);
603  }
604 
605  if (CGDisplayIsMain(displaydata->display)) {
606  Cocoa_ToggleMenuBar(YES);
607  }
608  } else {
609  /* Put up the blanking window (a window above all other windows) */
610  if (CGDisplayIsMain(displaydata->display)) {
611  /* If we don't capture all displays, Cocoa tries to rearrange windows... *sigh* */
612  result = CGCaptureAllDisplays();
613  } else {
614  result = CGDisplayCapture(displaydata->display);
615  }
616  if (result != kCGErrorSuccess) {
617  CG_SetError("CGDisplayCapture()", result);
618  goto ERR_NO_CAPTURE;
619  }
620 
621  /* Do the physical switch */
622  result = SetDisplayModeForDisplay(displaydata->display, data);
623  if (result != kCGErrorSuccess) {
624  CG_SetError("CGDisplaySwitchToMode()", result);
625  goto ERR_NO_SWITCH;
626  }
627 
628  /* Hide the menu bar so it doesn't intercept events */
629  if (CGDisplayIsMain(displaydata->display)) {
630  Cocoa_ToggleMenuBar(NO);
631  }
632  }
633 
634  /* Fade in again (asynchronously) */
635  if (fade_token != kCGDisplayFadeReservationInvalidToken) {
636  CGDisplayFade(fade_token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE);
637  CGReleaseDisplayFadeReservation(fade_token);
638  }
639 
640  return 0;
641 
642  /* Since the blanking window covers *all* windows (even force quit) correct recovery is crucial */
643 ERR_NO_SWITCH:
644  if (CGDisplayIsMain(displaydata->display)) {
645  CGReleaseAllDisplays();
646  } else {
647  CGDisplayRelease(displaydata->display);
648  }
649 ERR_NO_CAPTURE:
650  if (fade_token != kCGDisplayFadeReservationInvalidToken) {
651  CGDisplayFade (fade_token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE);
652  CGReleaseDisplayFadeReservation(fade_token);
653  }
654  return -1;
655 }
656 
657 void
659 {
660  int i, j;
661 
662  for (i = 0; i < _this->num_displays; ++i) {
663  SDL_VideoDisplay *display = &_this->displays[i];
665 
666  if (display->current_mode.driverdata != display->desktop_mode.driverdata) {
667  Cocoa_SetDisplayMode(_this, display, &display->desktop_mode);
668  }
669 
671  CFRelease(mode->modes);
672 
673  for (j = 0; j < display->num_display_modes; j++) {
675  CFRelease(mode->modes);
676  }
677  }
678  Cocoa_ToggleMenuBar(YES);
679 }
680 
681 #endif /* SDL_VIDEO_DRIVER_COCOA */
682 
683 /* vi: set ts=4 sw=4 expandtab: */
SDL_zero
#define SDL_zero(x)
Definition: SDL_stdinc.h:418
format
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1572
SDL_PIXELFORMAT_ARGB1555
@ SDL_PIXELFORMAT_ARGB1555
Definition: SDL_pixels.h:215
SDL_VideoDisplay::display_modes
SDL_DisplayMode * display_modes
Definition: SDL_sysvideo.h:131
screen
SDL_Renderer * screen
Definition: testgamecontroller.c:64
SDL_small_free
#define SDL_small_free(ptr, isstack)
Definition: SDL_internal.h:40
SDL_VideoDisplay::name
char * name
Definition: SDL_sysvideo.h:128
time
EGLSurface EGLnsecsANDROID time
Definition: eglext.h:518
in
GLuint in
Definition: SDL_opengl_glext.h:7943
NULL
#define NULL
Definition: begin_code.h:167
width
GLint GLint GLsizei width
Definition: SDL_opengl.h:1572
TRUE
#define TRUE
Definition: edid-parse.c:33
mode
GLenum mode
Definition: SDL_opengl_glext.h:1125
count
GLuint GLuint GLsizei count
Definition: SDL_opengl.h:1571
Cocoa_GetDisplayDPI
int Cocoa_GetDisplayDPI(_THIS, SDL_VideoDisplay *display, float *ddpi, float *hpdi, float *vdpi)
Uint32
uint32_t Uint32
Definition: SDL_stdinc.h:203
SDL_VideoDisplay::desktop_mode
SDL_DisplayMode desktop_mode
Definition: SDL_sysvideo.h:132
SDL_cocoavideo.h
Cocoa_GetDisplayBounds
int Cocoa_GetDisplayBounds(_THIS, SDL_VideoDisplay *display, SDL_Rect *rect)
SDL_small_alloc
#define SDL_small_alloc(type, count, pisstack)
Definition: SDL_internal.h:39
SDL_Rect::x
int x
Definition: SDL_rect.h:79
result
GLuint64EXT * result
Definition: SDL_opengl_glext.h:9435
data
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
SDL_Rect::w
int w
Definition: SDL_rect.h:80
SDL_DisplayMode
The structure that defines a display mode.
Definition: SDL_video.h:54
SDL_AddDisplayMode
SDL_bool SDL_AddDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode)
Definition: SDL_video.c:772
_this
static SDL_VideoDevice * _this
Definition: SDL_video.c:121
Cocoa_GetDisplayUsableBounds
int Cocoa_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay *display, SDL_Rect *rect)
SDL_VideoDevice::num_displays
int num_displays
Definition: SDL_sysvideo.h:323
Cocoa_SetDisplayMode
int Cocoa_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
SDL_Rect::y
int y
Definition: SDL_rect.h:79
SDL_Rect::h
int h
Definition: SDL_rect.h:80
SDL_free
#define SDL_free
Definition: SDL_dynapi_overrides.h:377
height
GLint GLint GLsizei GLsizei height
Definition: SDL_opengl.h:1572
SDL_PIXELFORMAT_ARGB2101010
@ SDL_PIXELFORMAT_ARGB2101010
Definition: SDL_pixels.h:263
SDL_VideoDevice::displays
SDL_VideoDisplay * displays
Definition: SDL_sysvideo.h:324
rect
SDL_Rect rect
Definition: testrelative.c:27
Cocoa_GetDisplayModes
void Cocoa_GetDisplayModes(_THIS, SDL_VideoDisplay *display)
frame
int frame
Definition: teststreaming.c:60
SDL_assert.h
Cocoa_QuitModes
void Cocoa_QuitModes(_THIS)
_THIS
#define _THIS
Definition: SDL_alsa_audio.h:31
SDL_TRUE
@ SDL_TRUE
Definition: SDL_stdinc.h:164
SDL_PIXELFORMAT_ARGB8888
@ SDL_PIXELFORMAT_ARGB8888
Definition: SDL_pixels.h:251
SDL_AddVideoDisplay
int SDL_AddVideoDisplay(const SDL_VideoDisplay *display)
Definition: SDL_video.c:606
SDL_assert
#define SDL_assert(condition)
Definition: SDL_assert.h:169
SDL_VideoDisplay::driverdata
void * driverdata
Definition: SDL_sysvideo.h:140
SDL_DisplayData
Definition: SDL_cocoamodes.h:27
size
GLsizeiptr size
Definition: SDL_opengl_glext.h:540
y
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1574
SDL_VideoDisplay::num_display_modes
int num_display_modes
Definition: SDL_sysvideo.h:130
uint32_t
unsigned int uint32_t
Definition: SDL_config_windows.h:63
SDL_VideoDisplay
Definition: SDL_sysvideo.h:127
SDL_SetError
#define SDL_SetError
Definition: SDL_dynapi_overrides.h:30
SDL_Rect
A rectangle, with the origin at the upper left (integer).
Definition: SDL_rect.h:78
SDL_PIXELFORMAT_UNKNOWN
@ SDL_PIXELFORMAT_UNKNOWN
Definition: SDL_pixels.h:173
SDL_strdup
#define SDL_strdup
Definition: SDL_dynapi_overrides.h:397
SDL_bool
SDL_bool
Definition: SDL_stdinc.h:162
SDL_ComputeDiagonalDPI
float SDL_ComputeDiagonalDPI(int hpix, int vpix, float hinches, float vinches)
Definition: SDL_video.c:4046
j
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int int in j)
Definition: SDL_x11sym.h:50
SDL_DisplayMode::driverdata
void * driverdata
Definition: SDL_video.h:59
Cocoa_InitModes
void Cocoa_InitModes(_THIS)
SDL_FALSE
@ SDL_FALSE
Definition: SDL_stdinc.h:163
SDL_VideoDisplay::current_mode
SDL_DisplayMode current_mode
Definition: SDL_sysvideo.h:133
SDL_malloc
#define SDL_malloc
Definition: SDL_dynapi_overrides.h:374
SDL_DisplayModeData
Definition: SDL_cocoamodes.h:32
floor
double floor(double x)
Definition: s_floor.c:33
i
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
SDL_DisplayData::display
CGDirectDisplayID display
Definition: SDL_cocoamodes.h:28
FALSE
#define FALSE
Definition: edid-parse.c:34