36#include <IOKit/graphics/IOGraphicsLib.h>
37#include <ApplicationServices/ApplicationServices.h>
42static char* getMonitorName(CGDirectDisplayID displayID, NSScreen* screen)
49 if ([screen respondsToSelector:
@selector(localizedName)])
51 NSString* name = [screen valueForKey:@"localizedName"];
61 if (IOServiceGetMatchingServices(kIOMasterPortDefault,
62 IOServiceMatching(
"IODisplayConnect"),
69 while ((service = IOIteratorNext(it)) != 0)
71 info = IODisplayCreateInfoDictionary(service,
72 kIODisplayOnlyPreferredName);
74 CFNumberRef vendorIDRef =
75 CFDictionaryGetValue(info, CFSTR(kDisplayVendorID));
76 CFNumberRef productIDRef =
77 CFDictionaryGetValue(info, CFSTR(kDisplayProductID));
78 if (!vendorIDRef || !productIDRef)
84 unsigned int vendorID, productID;
85 CFNumberGetValue(vendorIDRef, kCFNumberIntType, &vendorID);
86 CFNumberGetValue(productIDRef, kCFNumberIntType, &productID);
88 if (CGDisplayVendorNumber(displayID) == vendorID &&
89 CGDisplayModelNumber(displayID) == productID)
103 "Cocoa: Failed to find service port for display");
107 CFDictionaryRef names =
108 CFDictionaryGetValue(info, CFSTR(kDisplayProductName));
112 if (!names || !CFDictionaryGetValueIfPresent(names, CFSTR(
"en_US"),
113 (
const void**) &nameRef))
121 CFStringGetMaximumSizeForEncoding(CFStringGetLength(nameRef),
122 kCFStringEncodingUTF8);
123 char* name = calloc(size + 1, 1);
124 CFStringGetCString(nameRef, name, size, kCFStringEncodingUTF8);
132static GLFWbool modeIsGood(CGDisplayModeRef mode)
134 uint32_t flags = CGDisplayModeGetIOFlags(mode);
136 if (!(flags & kDisplayModeValidFlag) || !(flags & kDisplayModeSafeFlag))
138 if (flags & kDisplayModeInterlacedFlag)
140 if (flags & kDisplayModeStretchedFlag)
143#if MAC_OS_X_VERSION_MAX_ALLOWED <= 101100
144 CFStringRef format = CGDisplayModeCopyPixelEncoding(mode);
145 if (CFStringCompare(format, CFSTR(IO16BitDirectPixels), 0) &&
146 CFStringCompare(format, CFSTR(IO32BitDirectPixels), 0))
159static GLFWvidmode vidmodeFromCGDisplayMode(CGDisplayModeRef mode,
160 double fallbackRefreshRate)
163 result.
width = (int) CGDisplayModeGetWidth(mode);
164 result.
height = (int) CGDisplayModeGetHeight(mode);
165 result.
refreshRate = (int) round(CGDisplayModeGetRefreshRate(mode));
168 result.
refreshRate = (int) round(fallbackRefreshRate);
170#if MAC_OS_X_VERSION_MAX_ALLOWED <= 101100
171 CFStringRef format = CGDisplayModeCopyPixelEncoding(mode);
172 if (CFStringCompare(format, CFSTR(IO16BitDirectPixels), 0) == 0)
186#if MAC_OS_X_VERSION_MAX_ALLOWED <= 101100
194static CGDisplayFadeReservationToken beginFadeReservation(
void)
196 CGDisplayFadeReservationToken token = kCGDisplayFadeReservationInvalidToken;
198 if (CGAcquireDisplayFadeReservation(5, &token) == kCGErrorSuccess)
200 CGDisplayFade(token, 0.3,
201 kCGDisplayBlendNormal,
202 kCGDisplayBlendSolidColor,
212static void endFadeReservation(CGDisplayFadeReservationToken token)
214 if (token != kCGDisplayFadeReservationInvalidToken)
216 CGDisplayFade(token, 0.5,
217 kCGDisplayBlendSolidColor,
218 kCGDisplayBlendNormal,
221 CGReleaseDisplayFadeReservation(token);
227static double getFallbackRefreshRate(CGDirectDisplayID displayID)
229 double refreshRate = 60.0;
232 io_service_t service;
234 if (IOServiceGetMatchingServices(kIOMasterPortDefault,
235 IOServiceMatching(
"IOFramebuffer"),
241 while ((service = IOIteratorNext(it)) != 0)
243 const CFNumberRef indexRef =
244 IORegistryEntryCreateCFProperty(service,
245 CFSTR(
"IOFramebufferOpenGLIndex"),
252 CFNumberGetValue(indexRef, kCFNumberIntType, &index);
255 if (CGOpenGLDisplayMaskToDisplayID(1 << index) != displayID)
258 const CFNumberRef clockRef =
259 IORegistryEntryCreateCFProperty(service,
260 CFSTR(
"IOFBCurrentPixelClock"),
263 const CFNumberRef countRef =
264 IORegistryEntryCreateCFProperty(service,
265 CFSTR(
"IOFBCurrentPixelCount"),
273 CFNumberGetValue(clockRef, kCFNumberIntType, &clock);
279 CFNumberGetValue(countRef, kCFNumberIntType, &count);
283 if (clock > 0 && count > 0)
284 refreshRate = clock / (double) count;
303 CGGetOnlineDisplayList(0,
NULL, &displayCount);
304 CGDirectDisplayID* displays = calloc(displayCount,
sizeof(CGDirectDisplayID));
305 CGGetOnlineDisplayList(displayCount, displays, &displayCount);
312 if (disconnectedCount)
320 for (
uint32_t i = 0; i < displayCount; i++)
322 if (CGDisplayIsAsleep(displays[i]))
325 const uint32_t unitNumber = CGDisplayUnitNumber(displays[i]);
326 NSScreen* screen = nil;
328 for (screen in [NSScreen screens])
330 NSNumber* screenNumber = [screen deviceDescription][@"NSScreenNumber"];
335 if (CGDisplayUnitNumber([screenNumber unsignedIntValue]) == unitNumber)
343 for (j = 0; j < disconnectedCount; j++)
345 if (disconnected[j] && disconnected[j]->ns.unitNumber == unitNumber)
347 disconnected[j]->ns.screen = screen;
348 disconnected[j] =
NULL;
353 if (j < disconnectedCount)
356 const CGSize size = CGDisplayScreenSize(displays[i]);
357 char* name = getMonitorName(displays[i], screen);
362 monitor->ns.displayID = displays[i];
363 monitor->ns.unitNumber = unitNumber;
364 monitor->ns.screen = screen;
368 CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displays[i]);
369 if (CGDisplayModeGetRefreshRate(mode) == 0.0)
370 monitor->ns.fallbackRefreshRate = getFallbackRefreshRate(displays[i]);
371 CGDisplayModeRelease(mode);
376 for (
uint32_t i = 0; i < disconnectedCount; i++)
397 CFArrayRef modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID,
NULL);
398 const CFIndex count = CFArrayGetCount(modes);
399 CGDisplayModeRef native =
NULL;
401 for (CFIndex i = 0; i < count; i++)
403 CGDisplayModeRef dm = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i);
408 vidmodeFromCGDisplayMode(dm, monitor->ns.fallbackRefreshRate);
418 if (monitor->ns.previousMode ==
NULL)
419 monitor->ns.previousMode = CGDisplayCopyDisplayMode(monitor->ns.displayID);
421 CGDisplayFadeReservationToken token = beginFadeReservation();
422 CGDisplaySetDisplayMode(monitor->ns.displayID, native,
NULL);
423 endFadeReservation(token);
433 if (monitor->ns.previousMode)
435 CGDisplayFadeReservationToken token = beginFadeReservation();
436 CGDisplaySetDisplayMode(monitor->ns.displayID,
437 monitor->ns.previousMode,
NULL);
438 endFadeReservation(token);
440 CGDisplayModeRelease(monitor->ns.previousMode);
441 monitor->ns.previousMode =
NULL;
458 const CGRect bounds = CGDisplayBounds(monitor->ns.displayID);
461 *xpos = (int) bounds.origin.x;
463 *ypos = (int) bounds.origin.y;
469 float* xscale,
float* yscale)
473 if (!monitor->ns.screen)
476 "Cocoa: Cannot query content scale without screen");
479 const NSRect points = [monitor->ns.screen frame];
480 const NSRect pixels = [monitor->ns.screen convertRectToBacking:points];
483 *xscale = (float) (pixels.size.width / points.size.width);
485 *yscale = (float) (pixels.size.height / points.size.height);
491 int* xpos,
int* ypos,
492 int* width,
int* height)
496 if (!monitor->ns.screen)
499 "Cocoa: Cannot query workarea without screen");
502 const NSRect frameRect = [monitor->ns.screen visibleFrame];
505 *xpos = frameRect.origin.x;
509 *width = frameRect.size.width;
511 *height = frameRect.size.height;
522 CFArrayRef modes = CGDisplayCopyAllDisplayModes(monitor->ns.displayID,
NULL);
523 const CFIndex found = CFArrayGetCount(modes);
526 for (CFIndex i = 0; i < found; i++)
528 CGDisplayModeRef dm = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i);
533 vidmodeFromCGDisplayMode(dm, monitor->ns.fallbackRefreshRate);
536 for (j = 0; j < *count; j++)
547 result[*count - 1] = mode;
560 CGDisplayModeRef native = CGDisplayCopyDisplayMode(monitor->ns.displayID);
561 *mode = vidmodeFromCGDisplayMode(native, monitor->ns.fallbackRefreshRate);
562 CGDisplayModeRelease(native);
571 uint32_t size = CGDisplayGammaTableCapacity(monitor->ns.displayID);
572 CGGammaValue* values = calloc(size * 3,
sizeof(CGGammaValue));
574 CGGetDisplayTransferByTable(monitor->ns.displayID,
585 ramp->
red[i] = (
unsigned short) (values[i] * 65535);
586 ramp->
green[i] = (
unsigned short) (values[i + size] * 65535);
587 ramp->
blue[i] = (
unsigned short) (values[i + size * 2] * 65535);
600 CGGammaValue* values = calloc(ramp->
size * 3,
sizeof(CGGammaValue));
602 for (
unsigned int i = 0; i < ramp->
size; i++)
604 values[i] = ramp->
red[i] / 65535.f;
605 values[i + ramp->size] = ramp->
green[i] / 65535.f;
606 values[i + ramp->size * 2] = ramp->
blue[i] / 65535.f;
609 CGSetDisplayTransferByTable(monitor->ns.displayID,
613 values + ramp->
size * 2);
629 return monitor->ns.displayID;
void _glfwPlatformFreeMonitor(_GLFWmonitor *monitor)
void _glfwRestoreVideoModeNS(_GLFWmonitor *monitor)
GLFWvidmode * _glfwPlatformGetVideoModes(_GLFWmonitor *monitor, int *count)
GLFWAPI CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor *handle)
void _glfwPlatformGetVideoMode(_GLFWmonitor *monitor, GLFWvidmode *mode)
void _glfwSetVideoModeNS(_GLFWmonitor *monitor, const GLFWvidmode *desired)
void _glfwPlatformSetGammaRamp(_GLFWmonitor *monitor, const GLFWgammaramp *ramp)
void _glfwPlatformGetMonitorPos(_GLFWmonitor *monitor, int *xpos, int *ypos)
GLFWbool _glfwPlatformGetGammaRamp(_GLFWmonitor *monitor, GLFWgammaramp *ramp)
void _glfwPlatformGetMonitorContentScale(_GLFWmonitor *monitor, float *xscale, float *yscale)
void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor *monitor, int *xpos, int *ypos, int *width, int *height)
void _glfwPollMonitorsNS(void)
#define GLFW_DISCONNECTED
#define GLFW_PLATFORM_ERROR
A platform-specific error occurred that does not match any of the more specific categories.
struct GLFWmonitor GLFWmonitor
Opaque monitor object.
void _glfwInputError(int code, const char *format,...)
char * _glfw_strdup(const char *source)
void _glfwInputMonitor(_GLFWmonitor *monitor, int action, int placement)
const GLFWvidmode * _glfwChooseVideoMode(_GLFWmonitor *monitor, const GLFWvidmode *desired)
#define _GLFW_REQUIRE_INIT_OR_RETURN(x)
int _glfwCompareVideoModes(const GLFWvidmode *first, const GLFWvidmode *second)
_GLFWmonitor * _glfwAllocMonitor(const char *name, int widthMM, int heightMM)
#define _GLFW_INSERT_LAST
void _glfwAllocGammaArrays(GLFWgammaramp *ramp, unsigned int size)