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 
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 CVDisplayLinkGetNominalOutputVideoRefreshPeriod */
31 #include <CoreVideo/CVBase.h>
32 #include <CoreVideo/CVDisplayLink.h>
33 
34 /* we need this for ShowMenuBar() and HideMenuBar(). */
35 #include <Carbon/Carbon.h>
36 
37 /* This gets us MAC_OS_X_VERSION_MIN_REQUIRED... */
38 #include <AvailabilityMacros.h>
39 
40 #ifndef MAC_OS_X_VERSION_10_13
41 #define NSAppKitVersionNumber10_12 1504
42 #endif
43 
44 
45 static void
46 Cocoa_ToggleMenuBar(const BOOL show)
47 {
48  /* !!! FIXME: keep an eye on this.
49  * ShowMenuBar/HideMenuBar is officially unavailable for 64-bit binaries.
50  * It happens to work, as of 10.7, but we're going to see if
51  * we can just simply do without it on newer OSes...
52  */
53 #if (MAC_OS_X_VERSION_MIN_REQUIRED < 1070) && !defined(__LP64__)
54  if (show) {
55  ShowMenuBar();
56  } else {
57  HideMenuBar();
58  }
59 #endif
60 }
61 
62 static int
63 CG_SetError(const char *prefix, CGDisplayErr result)
64 {
65  const char *error;
66 
67  switch (result) {
68  case kCGErrorFailure:
69  error = "kCGErrorFailure";
70  break;
71  case kCGErrorIllegalArgument:
72  error = "kCGErrorIllegalArgument";
73  break;
74  case kCGErrorInvalidConnection:
75  error = "kCGErrorInvalidConnection";
76  break;
77  case kCGErrorInvalidContext:
78  error = "kCGErrorInvalidContext";
79  break;
80  case kCGErrorCannotComplete:
81  error = "kCGErrorCannotComplete";
82  break;
83  case kCGErrorNotImplemented:
84  error = "kCGErrorNotImplemented";
85  break;
86  case kCGErrorRangeCheck:
87  error = "kCGErrorRangeCheck";
88  break;
89  case kCGErrorTypeCheck:
90  error = "kCGErrorTypeCheck";
91  break;
92  case kCGErrorInvalidOperation:
93  error = "kCGErrorInvalidOperation";
94  break;
95  case kCGErrorNoneAvailable:
96  error = "kCGErrorNoneAvailable";
97  break;
98  default:
99  error = "Unknown Error";
100  break;
101  }
102  return SDL_SetError("%s: %s", prefix, error);
103 }
104 
105 static int
106 GetDisplayModeRefreshRate(CGDisplayModeRef vidmode, CVDisplayLinkRef link)
107 {
108  int refreshRate = (int) (CGDisplayModeGetRefreshRate(vidmode) + 0.5);
109 
110  /* CGDisplayModeGetRefreshRate can return 0 (eg for built-in displays). */
111  if (refreshRate == 0 && link != NULL) {
112  CVTime time = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(link);
113  if ((time.flags & kCVTimeIsIndefinite) == 0 && time.timeValue != 0) {
114  refreshRate = (int) ((time.timeScale / (double) time.timeValue) + 0.5);
115  }
116  }
117 
118  return refreshRate;
119 }
120 
121 static SDL_bool
122 HasValidDisplayModeFlags(CGDisplayModeRef vidmode)
123 {
124  uint32_t ioflags = CGDisplayModeGetIOFlags(vidmode);
125 
126  /* Filter out modes which have flags that we don't want. */
127  if (ioflags & (kDisplayModeNeverShowFlag | kDisplayModeNotGraphicsQualityFlag)) {
128  return SDL_FALSE;
129  }
130 
131  /* Filter out modes which don't have flags that we want. */
132  if (!(ioflags & kDisplayModeValidFlag) || !(ioflags & kDisplayModeSafeFlag)) {
133  return SDL_FALSE;
134  }
135 
136  return SDL_TRUE;
137 }
138 
139 static Uint32
140 GetDisplayModePixelFormat(CGDisplayModeRef vidmode)
141 {
142  /* This API is deprecated in 10.11 with no good replacement (as of 10.15). */
143  CFStringRef fmt = CGDisplayModeCopyPixelEncoding(vidmode);
144  Uint32 pixelformat = SDL_PIXELFORMAT_UNKNOWN;
145 
146  if (CFStringCompare(fmt, CFSTR(IO32BitDirectPixels),
147  kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
148  pixelformat = SDL_PIXELFORMAT_ARGB8888;
149  } else if (CFStringCompare(fmt, CFSTR(IO16BitDirectPixels),
150  kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
151  pixelformat = SDL_PIXELFORMAT_ARGB1555;
152  } else if (CFStringCompare(fmt, CFSTR(kIO30BitDirectPixels),
153  kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
154  pixelformat = SDL_PIXELFORMAT_ARGB2101010;
155  } else {
156  /* ignore 8-bit and such for now. */
157  }
158 
159  CFRelease(fmt);
160 
161  return pixelformat;
162 }
163 
164 static SDL_bool
165 GetDisplayMode(_THIS, CGDisplayModeRef vidmode, CFArrayRef modelist, CVDisplayLinkRef link, SDL_DisplayMode *mode)
166 {
168  bool usableForGUI = CGDisplayModeIsUsableForDesktopGUI(vidmode);
169  int width = (int) CGDisplayModeGetWidth(vidmode);
170  int height = (int) CGDisplayModeGetHeight(vidmode);
171  uint32_t ioflags = CGDisplayModeGetIOFlags(vidmode);
172  int refreshrate = GetDisplayModeRefreshRate(vidmode, link);
173  Uint32 format = GetDisplayModePixelFormat(vidmode);
174  bool interlaced = (ioflags & kDisplayModeInterlacedFlag) != 0;
175  CFMutableArrayRef modes;
176 
178  return SDL_FALSE;
179  }
180 
181  if (!HasValidDisplayModeFlags(vidmode)) {
182  return SDL_FALSE;
183  }
184 
185  modes = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
186  CFArrayAppendValue(modes, vidmode);
187 
188  /* If a list of possible diplay modes is passed in, use it to filter out
189  * modes that have duplicate sizes. We don't just rely on SDL's higher level
190  * duplicate filtering because this code can choose what properties are
191  * prefered, and it can add CGDisplayModes to the DisplayModeData's list of
192  * modes to try (see comment below for why that's necessary).
193  * CGDisplayModeGetPixelWidth and friends are only available in 10.8+. */
194 #ifdef MAC_OS_X_VERSION_10_8
195  if (modelist != NULL && floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_7) {
196  int pixelW = (int) CGDisplayModeGetPixelWidth(vidmode);
197  int pixelH = (int) CGDisplayModeGetPixelHeight(vidmode);
198 
199  CFIndex modescount = CFArrayGetCount(modelist);
200  int i;
201 
202  for (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, SDL_FALSE);
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: */
#define _THIS
#define SDL_assert(condition)
Definition: SDL_assert.h:171
void Cocoa_QuitModes(_THIS)
int Cocoa_GetDisplayDPI(_THIS, SDL_VideoDisplay *display, float *ddpi, float *hpdi, float *vdpi)
int Cocoa_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
int Cocoa_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay *display, SDL_Rect *rect)
void Cocoa_GetDisplayModes(_THIS, SDL_VideoDisplay *display)
void Cocoa_InitModes(_THIS)
int Cocoa_GetDisplayBounds(_THIS, SDL_VideoDisplay *display, SDL_Rect *rect)
unsigned int uint32_t
#define SDL_SetError
#define SDL_malloc
#define SDL_free
#define SDL_strdup
#define SDL_small_alloc(type, count, pisstack)
Definition: SDL_internal.h:39
#define SDL_small_free(ptr, isstack)
Definition: SDL_internal.h:40
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1574
GLuint GLuint GLsizei count
Definition: SDL_opengl.h:1571
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
GLint GLint GLsizei width
Definition: SDL_opengl.h:1572
GLint GLint GLsizei GLsizei height
Definition: SDL_opengl.h:1572
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1572
GLenum mode
GLuint64EXT * result
GLuint in
GLsizeiptr size
@ SDL_PIXELFORMAT_ARGB1555
Definition: SDL_pixels.h:219
@ SDL_PIXELFORMAT_ARGB8888
Definition: SDL_pixels.h:257
@ SDL_PIXELFORMAT_ARGB2101010
Definition: SDL_pixels.h:269
@ SDL_PIXELFORMAT_UNKNOWN
Definition: SDL_pixels.h:173
#define SDL_zero(x)
Definition: SDL_stdinc.h:426
SDL_bool
Definition: SDL_stdinc.h:168
@ SDL_TRUE
Definition: SDL_stdinc.h:170
@ SDL_FALSE
Definition: SDL_stdinc.h:169
uint32_t Uint32
Definition: SDL_stdinc.h:209
int SDL_AddVideoDisplay(const SDL_VideoDisplay *display, SDL_bool send_event)
Definition: SDL_video.c:607
float SDL_ComputeDiagonalDPI(int hpix, int vpix, float hinches, float vinches)
Definition: SDL_video.c:4162
SDL_bool SDL_AddDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode)
Definition: SDL_video.c:792
static SDL_VideoDevice * _this
Definition: SDL_video.c:126
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
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
#define NULL
Definition: begin_code.h:163
#define TRUE
Definition: edid-parse.c:33
#define FALSE
Definition: edid-parse.c:34
EGLSurface EGLnsecsANDROID time
Definition: eglext.h:518
double floor(double x)
Definition: s_floor.c:33
CGDirectDisplayID display
The structure that defines a display mode.
Definition: SDL_video.h:54
void * driverdata
Definition: SDL_video.h:59
A rectangle, with the origin at the upper left (integer).
Definition: SDL_rect.h:78
int h
Definition: SDL_rect.h:80
int w
Definition: SDL_rect.h:80
int y
Definition: SDL_rect.h:79
int x
Definition: SDL_rect.h:79
SDL_VideoDisplay * displays
Definition: SDL_sysvideo.h:326
SDL_DisplayMode desktop_mode
Definition: SDL_sysvideo.h:132
SDL_DisplayMode * display_modes
Definition: SDL_sysvideo.h:131
SDL_DisplayMode current_mode
Definition: SDL_sysvideo.h:133
SDL_Renderer * screen
SDL_Rect rect
Definition: testrelative.c:27
int frame
Definition: teststreaming.c:60
typedef int(__stdcall *FARPROC)()