diff --git a/.gitignore b/.gitignore index 3e206b4a4..f238dcea6 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,7 @@ src/glfw_config.h src/glfw3.pc src/glfwConfig.cmake src/glfwConfigVersion.cmake +install_manifest.txt # Compiled binaries src/libglfw.so diff --git a/include/GLFW/glfw3native.h b/include/GLFW/glfw3native.h index 35d6f49b3..24ad436c8 100644 --- a/include/GLFW/glfw3native.h +++ b/include/GLFW/glfw3native.h @@ -55,7 +55,8 @@ extern "C" { * * The available context API macros are: * * `GLFW_EXPOSE_NATIVE_WGL` - * * `GLFW_EXPOSE_NATIVE_NSGL` + * * `GLFW_EXPOSE_NATIVE_NSGL` (OSX, ObjC required to do anything useful) + * * `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) @@ -151,6 +154,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. * @return The `Display` used by GLFW. diff --git a/src/cocoa_monitor.m b/src/cocoa_monitor.m index abf66654f..65e12a317 100644 --- a/src/cocoa_monitor.m +++ b/src/cocoa_monitor.m @@ -38,6 +38,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 char* getDisplayName(CGDirectDisplayID displayID) @@ -46,31 +108,40 @@ static 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) diff --git a/src/nsgl_context.m b/src/nsgl_context.m index cbdf284d8..76b15e964 100644 --- a/src/nsgl_context.m +++ b/src/nsgl_context.m @@ -299,3 +299,9 @@ GLFWAPI id glfwGetNSGLContext(GLFWwindow* handle) return window->nsgl.context; } +GLFWAPI CGLContextObj glfwGetCGLContext(GLFWwindow* handle) +{ + NSOpenGLContext* ctx = glfwGetNSGLContext(handle); + return [ctx CGLContextObj]; +} +