From bebae1422386691c48729644d515fa2eaa497222 Mon Sep 17 00:00:00 2001 From: Matthew Henry Date: Sat, 14 Dec 2013 01:03:39 +1000 Subject: [PATCH] Replace CGDisplayIOServicePort with a workaround This could be cleaned up and refined a bit by comparing more display attributes when available, but it gets the job done. Closes #192. --- src/cocoa_monitor.m | 91 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 81 insertions(+), 10 deletions(-) diff --git a/src/cocoa_monitor.m b/src/cocoa_monitor.m index 88cae085..a2f9a7f1 100644 --- a/src/cocoa_monitor.m +++ b/src/cocoa_monitor.m @@ -36,6 +36,68 @@ #include +// Returns the io_service_t corresponding to a CG display ID, or 0 on failure. +// The io_service_t should be released with IOObjectRelease when not needed. +// +static io_service_t IOServicePortFromCGDisplayID(CGDirectDisplayID displayID) +{ + io_iterator_t iter; + io_service_t serv, servicePort = 0; + + CFMutableDictionaryRef matching = IOServiceMatching("IODisplayConnect"); + + // releases matching for us + kern_return_t err = IOServiceGetMatchingServices(kIOMasterPortDefault, + matching, + &iter); + if (err) + { + return 0; + } + + while ((serv = IOIteratorNext(iter)) != 0) + { + CFDictionaryRef info; + CFIndex vendorID, productID; + CFNumberRef vendorIDRef, productIDRef; + Boolean success; + + info = IODisplayCreateInfoDictionary(serv, + kIODisplayOnlyPreferredName); + + vendorIDRef = CFDictionaryGetValue(info, + CFSTR(kDisplayVendorID)); + productIDRef = CFDictionaryGetValue(info, + CFSTR(kDisplayProductID)); + + success = CFNumberGetValue(vendorIDRef, kCFNumberCFIndexType, + &vendorID); + success &= CFNumberGetValue(productIDRef, kCFNumberCFIndexType, + &productID); + + if (!success) + { + CFRelease(info); + continue; + } + + if (CGDisplayVendorNumber(displayID) != vendorID || + CGDisplayModelNumber(displayID) != productID) + { + CFRelease(info); + continue; + } + + // we're a match + servicePort = serv; + CFRelease(info); + break; + } + + IOObjectRelease(iter); + return servicePort; +} + // Get the name of the specified display // static const char* getDisplayName(CGDirectDisplayID displayID) @@ -44,31 +106,40 @@ static const char* getDisplayName(CGDirectDisplayID displayID) CFDictionaryRef info, names; CFStringRef value; CFIndex size; - - info = IODisplayCreateInfoDictionary(CGDisplayIOServicePort(displayID), - kIODisplayOnlyPreferredName); + + io_service_t serv = IOServicePortFromCGDisplayID(displayID); + if (!serv) + { + return strdup("Unknown"); + } + + info = IODisplayCreateInfoDictionary(serv, + kIODisplayOnlyPreferredName); + + IOObjectRelease(serv); + names = CFDictionaryGetValue(info, CFSTR(kDisplayProductName)); - + if (!names || !CFDictionaryGetValueIfPresent(names, CFSTR("en_US"), - (const void**) &value)) + (const void**) &value)) { // This may happen if a desktop Mac is running headless _glfwInputError(GLFW_PLATFORM_ERROR, "Failed to retrieve display name"); - CFRelease(info); return strdup("Unknown"); } - + size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(value), - kCFStringEncodingUTF8); + kCFStringEncodingUTF8); name = calloc(size + 1, sizeof(char)); CFStringGetCString(value, name, size, kCFStringEncodingUTF8); - + CFRelease(info); - + return name; } + // Check whether the display mode should be included in enumeration // static GLboolean modeIsGood(CGDisplayModeRef mode)