From e0a6772e5e4c672179fc69a90bcda3369792ed1f Mon Sep 17 00:00:00 2001 From: "Jared P. Jones" Date: Sun, 10 May 2015 03:11:14 -0500 Subject: [PATCH] Fixed Deprecated CGDisplayIOServicePort *A function has manually been created that deals with grabbing the approriate service_io port. *This function adds support for collision detection against the VendorID, ProductID, and the SerialNumber. The serial number check is required incase a user has two types of identical monitors. *Supports OS X 10.4 (Tiger) and Newer (Untested, based on API Docs) I would like to give special thanks to mhernr18 for providing the initial code. Recloses #165 --- include/GLFW/glfw3native.h | 11 +++++ src/cocoa_monitor.m | 86 ++++++++++++++++++++++++++++++++++++-- src/nsgl_context.m | 5 +++ 3 files changed, 98 insertions(+), 4 deletions(-) diff --git a/include/GLFW/glfw3native.h b/include/GLFW/glfw3native.h index b3ce7482d..f37c92d0e 100644 --- a/include/GLFW/glfw3native.h +++ b/include/GLFW/glfw3native.h @@ -56,6 +56,7 @@ extern "C" { * The available context API macros are: * * `GLFW_EXPOSE_NATIVE_WGL` * * `GLFW_EXPOSE_NATIVE_NSGL` + * * `GLFW_EXPOSE_NATIVE_CGL` * * `GLFW_EXPOSE_NATIVE_GLX` * * `GLFW_EXPOSE_NATIVE_EGL` * @@ -94,6 +95,8 @@ extern "C" { /* WGL is declared by windows.h */ #elif defined(GLFW_EXPOSE_NATIVE_NSGL) /* NSGL is declared by Cocoa.h */ +#elif defined(GLFW_EXPOSE_NATIVE_CGL) + #include #elif defined(GLFW_EXPOSE_NATIVE_GLX) #include #elif defined(GLFW_EXPOSE_NATIVE_EGL) @@ -221,6 +224,14 @@ GLFWAPI id glfwGetCocoaWindow(GLFWwindow* window); */ GLFWAPI id glfwGetNSGLContext(GLFWwindow* window); #endif + +#if defined(GLFW_EXPOSE_NATIVE_CGL) + /*! @brief Returns the `CGLContextObj` of the specified window. + * @return The `CGLContextObj` of the specified window. + * @ingroup native + */ + GLFWAPI CGLContextObj glfwGetCGLContext(GLFWwindow* window); +#endif #if defined(GLFW_EXPOSE_NATIVE_X11) /*! @brief Returns the `Display` used by GLFW. diff --git a/src/cocoa_monitor.m b/src/cocoa_monitor.m index a99aa33f4..d05d287b8 100644 --- a/src/cocoa_monitor.m +++ b/src/cocoa_monitor.m @@ -38,6 +38,76 @@ #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, serialNumber; + CFNumberRef vendorIDRef, productIDRef, serialNumberRef; + Boolean success; + + info = IODisplayCreateInfoDictionary(serv, + kIODisplayOnlyPreferredName); + + vendorIDRef = CFDictionaryGetValue(info, + CFSTR(kDisplayVendorID)); + productIDRef = CFDictionaryGetValue(info, + CFSTR(kDisplayProductID)); + serialNumberRef = CFDictionaryGetValue(info, + CFSTR(kDisplaySerialNumber)); + + success = CFNumberGetValue(vendorIDRef, kCFNumberCFIndexType, + &vendorID); + success &= CFNumberGetValue(productIDRef, kCFNumberCFIndexType, + &productID); + success &= CFNumberGetValue(serialNumberRef, kCFNumberCFIndexType, + &serialNumber); + + if (!success) + { + CFRelease(info); + continue; + } + + // If the vendor and product id along with the serial don't match + // then we are not looking at the correct monitor. + // NOTE: The serial number is important in cases where two monitors + // are the exact same. + if (CGDisplayVendorNumber(displayID) != vendorID || + CGDisplayModelNumber(displayID) != productID || + CGDisplaySerialNumber(displayID) != serialNumber) + { + CFRelease(info); + continue; + } + + // The VendorID, Product ID, and the Serial Number all Match Up! + // Therefore we have found the appropriate display io_service + servicePort = serv; + CFRelease(info); + break; + } + + IOObjectRelease(iter); + return servicePort; +} + // Get the name of the specified display // static char* getDisplayName(CGDirectDisplayID displayID) @@ -47,10 +117,18 @@ static char* getDisplayName(CGDirectDisplayID displayID) CFStringRef value; CFIndex size; - // NOTE: This uses a deprecated function because Apple has - // (as of January 2015) not provided any alternative - info = IODisplayCreateInfoDictionary(CGDisplayIOServicePort(displayID), - kIODisplayOnlyPreferredName); + // Supports OS X 10.4 Tiger and Newer + io_service_t serv = IOServicePortFromCGDisplayID(displayID); + if (serv == 0) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Cocoa: IOServicePortFromCGDisplayID Returned an Invalid Port. (Port: 0)"); + return strdup("Unknown"); + } + + info = IODisplayCreateInfoDictionary(serv, kIODisplayOnlyPreferredName); + IOObjectRelease(serv); + names = CFDictionaryGetValue(info, CFSTR(kDisplayProductName)); if (!names || !CFDictionaryGetValueIfPresent(names, CFSTR("en_US"), diff --git a/src/nsgl_context.m b/src/nsgl_context.m index 28758060f..b614874a7 100644 --- a/src/nsgl_context.m +++ b/src/nsgl_context.m @@ -306,3 +306,8 @@ GLFWAPI id glfwGetNSGLContext(GLFWwindow* handle) return window->nsgl.context; } +GLFWAPI CGLContextObj glfwGetCGLContext(GLFWwindow* handle) +{ + NSOpenGLContext* ctx = glfwGetNSGLContext(handle); + return [ctx CGLContextObj]; +} \ No newline at end of file