21 #include "../../SDL_internal.h"
24 #if SDL_VIDEO_DRIVER_COCOA
29 #include <IOKit/graphics/IOGraphicsLib.h>
32 #include <CoreVideo/CVBase.h>
33 #include <CoreVideo/CVDisplayLink.h>
36 #include <Carbon/Carbon.h>
39 #include <AvailabilityMacros.h>
41 #ifndef MAC_OS_X_VERSION_10_13
42 #define NSAppKitVersionNumber10_12 1504
47 Cocoa_ToggleMenuBar(
const BOOL show)
54 #if (MAC_OS_X_VERSION_MIN_REQUIRED < 1070) && !defined(__LP64__)
64 CG_SetError(
const char *prefix, CGDisplayErr
result)
70 error =
"kCGErrorFailure";
72 case kCGErrorIllegalArgument:
73 error =
"kCGErrorIllegalArgument";
75 case kCGErrorInvalidConnection:
76 error =
"kCGErrorInvalidConnection";
78 case kCGErrorInvalidContext:
79 error =
"kCGErrorInvalidContext";
81 case kCGErrorCannotComplete:
82 error =
"kCGErrorCannotComplete";
84 case kCGErrorNotImplemented:
85 error =
"kCGErrorNotImplemented";
87 case kCGErrorRangeCheck:
88 error =
"kCGErrorRangeCheck";
90 case kCGErrorTypeCheck:
91 error =
"kCGErrorTypeCheck";
93 case kCGErrorInvalidOperation:
94 error =
"kCGErrorInvalidOperation";
96 case kCGErrorNoneAvailable:
97 error =
"kCGErrorNoneAvailable";
100 error =
"Unknown Error";
107 GetDisplayModeRefreshRate(CGDisplayModeRef vidmode, CVDisplayLinkRef link)
109 int refreshRate = (int) (CGDisplayModeGetRefreshRate(vidmode) + 0.5);
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);
123 HasValidDisplayModeFlags(CGDisplayModeRef vidmode)
125 uint32_t ioflags = CGDisplayModeGetIOFlags(vidmode);
128 if (ioflags & (kDisplayModeNeverShowFlag | kDisplayModeNotGraphicsQualityFlag)) {
133 if (!(ioflags & kDisplayModeValidFlag) || !(ioflags & kDisplayModeSafeFlag)) {
141 GetDisplayModePixelFormat(CGDisplayModeRef vidmode)
144 CFStringRef fmt = CGDisplayModeCopyPixelEncoding(vidmode);
147 if (CFStringCompare(fmt, CFSTR(IO32BitDirectPixels),
148 kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
150 }
else if (CFStringCompare(fmt, CFSTR(IO16BitDirectPixels),
151 kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
153 }
else if (CFStringCompare(fmt, CFSTR(kIO30BitDirectPixels),
154 kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
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);
175 bool interlaced = (ioflags & kDisplayModeInterlacedFlag) != 0;
176 CFMutableArrayRef modes;
182 if (!HasValidDisplayModeFlags(vidmode)) {
186 modes = CFArrayCreateMutable(
NULL, 0, &kCFTypeArrayCallBacks);
187 CFArrayAppendValue(modes, vidmode);
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);
200 CFIndex modescount = CFArrayGetCount(modelist);
202 for (
int i = 0;
i < modescount;
i++) {
203 CGDisplayModeRef othermode = (CGDisplayModeRef) CFArrayGetValueAtIndex(modelist,
i);
204 uint32_t otherioflags = CGDisplayModeGetIOFlags(othermode);
206 if (CFEqual(vidmode, othermode)) {
210 if (!HasValidDisplayModeFlags(othermode)) {
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);
227 && refreshrate == otherrefresh &&
format == otherformat
228 && (otherpixelW != otherW || otherpixelH != otherH)) {
236 if (interlaced && ((otherioflags & kDisplayModeInterlacedFlag) == 0)
237 &&
width == otherW &&
height == otherH && pixelW == otherpixelW
238 && pixelH == otherpixelH && refreshrate == otherrefresh
239 &&
format == otherformat && usableForGUI == otherGUI) {
247 if (
width == otherW &&
height == otherH && pixelW == otherpixelW
248 && pixelH == otherpixelH && !usableForGUI && otherGUI
249 && refreshrate == otherrefresh &&
format == otherformat) {
275 if (
width == otherW &&
height == otherH && pixelW == otherpixelW
276 && pixelH == otherpixelH && usableForGUI == otherGUI
277 && refreshrate == otherrefresh &&
format == otherformat) {
278 CFArrayAppendValue(modes, othermode);
293 mode->refresh_rate = refreshrate;
299 Cocoa_GetDisplayName(CGDirectDisplayID displayID)
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;
307 if ([localizedNames
count] > 0) {
308 displayName =
SDL_strdup([[localizedNames objectForKey:[[localizedNames allKeys] objectAtIndex:0]] UTF8String]);
310 CFRelease(deviceInfo);
319 CGDirectDisplayID *displays;
320 CGDisplayCount numDisplays;
324 result = CGGetOnlineDisplayList(0,
NULL, &numDisplays);
325 if (
result != kCGErrorSuccess) {
326 CG_SetError(
"CGGetOnlineDisplayList()",
result);
330 result = CGGetOnlineDisplayList(numDisplays, displays, &numDisplays);
331 if (
result != kCGErrorSuccess) {
332 CG_SetError(
"CGGetOnlineDisplayList()",
result);
338 for (pass = 0; pass < 2; ++pass) {
339 for (
i = 0;
i < numDisplays; ++
i) {
343 CGDisplayModeRef moderef =
NULL;
344 CVDisplayLinkRef link =
NULL;
347 if (!CGDisplayIsMain(displays[
i])) {
351 if (CGDisplayIsMain(displays[
i])) {
356 if (CGDisplayMirrorsDisplay(displays[
i]) != kCGNullDirectDisplay) {
360 moderef = CGDisplayCopyDisplayMode(displays[
i]);
368 CGDisplayModeRelease(moderef);
371 displaydata->
display = displays[i];
373 CVDisplayLinkCreateWithCGDisplay(displays[
i], &link);
377 display.
name = (
char *)Cocoa_GetDisplayName(displays[
i]);
379 CVDisplayLinkRelease(link);
380 CGDisplayModeRelease(moderef);
386 CVDisplayLinkRelease(link);
387 CGDisplayModeRelease(moderef);
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;
417 const CGDirectDisplayID cgdisplay = displaydata->
display;
418 NSArray *screens = [NSScreen screens];
422 for (NSScreen *
i in screens) {
423 const CGDirectDisplayID thisDisplay = (CGDirectDisplayID) [[[
i deviceDescription] objectForKey:
@"NSScreenNumber"] unsignedIntValue];
424 if (thisDisplay == cgdisplay) {
435 const NSRect
frame = [screen visibleFrame];
448 const float MM_IN_INCH = 25.4f;
453 CGFloat scaleFactor = 1.0f;
454 NSArray *screens = [NSScreen screens];
456 const CGDirectDisplayID dpyid = (
const CGDirectDisplayID ) [[[
screen deviceDescription] objectForKey:
@"NSScreenNumber"] unsignedIntValue];
457 if (dpyid ==
data->display) {
458 if ([
screen respondsToSelector:
@selector(backingScaleFactor)]) {
459 scaleFactor = [screen backingScaleFactor];
465 const CGSize displaySize = CGDisplayScreenSize(
data->display);
466 const int pixelWidth = (int) CGDisplayPixelsWide(
data->display);
467 const int pixelHeight = (int) CGDisplayPixelsHigh(
data->display);
470 *ddpi = (
SDL_ComputeDiagonalDPI(pixelWidth, pixelHeight, displaySize.width / MM_IN_INCH, displaySize.height / MM_IN_INCH)) * scaleFactor;
473 *hdpi = (pixelWidth * MM_IN_INCH / displaySize.width) * scaleFactor;
476 *vdpi = (pixelHeight * MM_IN_INCH / displaySize.height) * scaleFactor;
486 CVDisplayLinkRef link =
NULL;
487 CGDisplayModeRef desktopmoderef;
490 CFDictionaryRef dict =
NULL;
492 CVDisplayLinkCreateWithCGDisplay(
data->display, &link);
494 desktopmoderef = CGDisplayCopyDisplayMode(
data->display);
502 if (desktopmoderef && GetDisplayMode(
_this, desktopmoderef,
NULL, link, &desktopmode)) {
509 CGDisplayModeRelease(desktopmoderef);
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,
530 &kCFCopyStringDictionaryKeyCallBacks,
531 &kCFTypeDictionaryValueCallBacks);
535 modes = CGDisplayCopyAllDisplayModes(
data->display, dict);
543 const CFIndex
count = CFArrayGetCount(modes);
546 CGDisplayModeRef moderef = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes,
i);
549 if (GetDisplayMode(
_this, moderef, modes, link, &
mode)) {
560 CVDisplayLinkRelease(link);
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) {
575 CFArrayExchangeValuesAtIndices(
data->modes,
i, 0);
587 CGDisplayFadeReservationToken fade_token = kCGDisplayFadeReservationInvalidToken;
591 if (CGAcquireDisplayFadeReservation(5, &fade_token) == kCGErrorSuccess) {
592 CGDisplayFade(fade_token, 0.3, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0,
TRUE);
597 SetDisplayModeForDisplay(displaydata->
display,
data);
599 if (CGDisplayIsMain(displaydata->
display)) {
600 CGReleaseAllDisplays();
602 CGDisplayRelease(displaydata->
display);
605 if (CGDisplayIsMain(displaydata->
display)) {
606 Cocoa_ToggleMenuBar(YES);
610 if (CGDisplayIsMain(displaydata->
display)) {
612 result = CGCaptureAllDisplays();
616 if (
result != kCGErrorSuccess) {
617 CG_SetError(
"CGDisplayCapture()",
result);
623 if (
result != kCGErrorSuccess) {
624 CG_SetError(
"CGDisplaySwitchToMode()",
result);
629 if (CGDisplayIsMain(displaydata->
display)) {
630 Cocoa_ToggleMenuBar(NO);
635 if (fade_token != kCGDisplayFadeReservationInvalidToken) {
636 CGDisplayFade(fade_token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0,
FALSE);
637 CGReleaseDisplayFadeReservation(fade_token);
644 if (CGDisplayIsMain(displaydata->
display)) {
645 CGReleaseAllDisplays();
647 CGDisplayRelease(displaydata->
display);
650 if (fade_token != kCGDisplayFadeReservationInvalidToken) {
651 CGDisplayFade (fade_token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0,
FALSE);
652 CGReleaseDisplayFadeReservation(fade_token);
667 Cocoa_SetDisplayMode(_this, display, &display->desktop_mode);
671 CFRelease(
mode->modes);
675 CFRelease(
mode->modes);
678 Cocoa_ToggleMenuBar(YES);