Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CGDirectDisplayID, multiple GPUs, deprecated CGDisplayIOServicePort and uniquely identifying displays

I need to uniquely identify a display to the extent that the displays are indeed characteristically different. Thus, the same models of displays, plugged into the same physical port would not be treated as different, but basically everything else would be.

When the system GPU changes, the CGDirectDisplayID also changes, but not in a documented way. Experimentation indicates the same screen ID will differ by 2 depending on which GPU is used.

CGDisplayID changing issues

A way to overcome this has been to get an IO registry string for the display:

io_service_t  servicePort = CGDisplayIOServicePort (cgDisplayID);
io_service_t  root = IODisplayForFramebuffer (servicePort, kNilOptions);
NSDictionary* ioRegistryDict = nil;
NSString*     displayKey = nil;

IORegistryEntryCreateCFProperties (root, (CFMutableDictionaryRef *)&ioRegistryDict, kCFAllocatorDefault, kNilOptions);

if (ioRegistryDict)
    displayKey = [ioRegistryDict objectForKey:@"IODisplayPrefsKey"];

This works well, except in 10.9, CGDisplayIOServicePort is deprecated.

Given all of this, and Apple's advice not to cache NSScreens (which don't really work for this purpose anyway), what is the best way to reliably identify screens so that I can tell (for example) the difference between a screen at home and one at work?

I don't want to have to rely on screen resolution because the user changing resolution should not be considered a different display. Nor should the same screen on different GPUs be considered different.

A secondary goal is to find a way that given a CGDirectDisplayID, how can I determine what the CGDirectDisplayID would be for the same screen if a GPU switch were to occur? This would at least allow me to track displays by CGDirectDisplayID as long as I could match the two results from the two GPU controllers.

like image 804
Trygve Avatar asked Jun 22 '14 04:06

Trygve


1 Answers

Use CFUUIDRef which can be obtained using:

CGDisplayCreateUUIDFromDisplayID(CGDirectDisplayID displayID) and you can get the display ID back using:

CGDisplayGetDisplayIDFromUUID(CFUUIDRef uuid)

This is what I'm using to uniquely identify displays even when their CGDirectDisplayID changes, for example was plugged into a different port. These functions aren't properly documented by Apple unfortunately, but my testing on multiple Macs with multiple displays shown that the CFUUIDRef obtained is unique and consistent -even after a reboot-, regardless of whether CGDirectDisplayID changed for whatever reason.

To check if a display is new/unique, take its CGDirectDisplayID and convert it to CFUUIDRef, and then compare the UUID, it is a many-to-one relationship, many CGDirectDisplayIDs will map to a single CFUUIDRef.

These API calls are available in ApplicationServices in 10.7 - 10.12, and ColorSync since 10.13.

like image 122
H. Al-Amri Avatar answered Sep 27 '22 21:09

H. Al-Amri