在 Mac OS X 中,每个显示器都CGDirectDisplayID
分配有一个唯一的编号。您可以使用CGGetActiveDisplayList(
) 或[NSScreen screens]
访问它们等。根据Apple 的文档:
显示 ID 可以跨进程和系统重新启动持续存在,并且只要某些显示参数不更改,通常保持不变。
在 2010 年中期更新的 MacBook Pro 上,Apple 开始使用自动切换 Intel/nVidia 显卡。笔记本电脑有两个 GPU,一个低功耗的 Intel 和一个高性能的 nVidia。以前的双 GPU 笔记本电脑(2009 年型号)没有自动 GPU 切换功能,并且需要用户进行设置更改、注销,然后再次登录才能进行 GPU 切换。即使是较旧的系统也只有一个 GPU。
2010 年中期的型号存在一个问题,当显示器从一个 GPU 切换到下一个 GPU 时,CGDirectDisplayID 不会保持不变。例如:
- 笔记本电脑开机。
- 内置LCD 屏幕由 Intel 芯片组驱动。显示 ID: 30002
- 外接显示器已插入。
- 内置 LCD 屏幕切换到 nVidia 芯片组。它的显示ID更改: 30004
- 外接显示器由 nVidia 芯片组驱动。
- ...此时,英特尔芯片组处于休眠状态...
- 用户拔下外接显示器。
- 内置LCD 屏幕切换回 Intel 芯片组。它的显示ID变回原来的:30002
我的问题是,当旧的显示 ID 由于 GPU 更改而改变时,如何将旧显示 ID 与新显示 ID 匹配?
想过:
我注意到显示 ID 仅更改 2,但我没有足够的测试 Mac 可用来确定这是否适用于所有新的 MacBook Pro,或者只是我的。无论如何,如果“只检查彼此相差 +/-2 的显示 ID”,那是一种混搭。
试过:
CGDisplayRegisterReconfigurationCallback()
,它在显示将要更改时通知前后,没有匹配的逻辑。将这样的东西放在用它注册的方法中是行不通的:
// Run before display settings change:
CGDirectDisplayID directDisplayID = ...;
io_service_t servicePort = CGDisplayIOServicePort(directDisplayID);
CFDictionaryRef oldInfoDict = IODisplayCreateInfoDictionary(servicePort, kIODisplayMatchingInfo);
// ...display settings change...
// Run after display settings change:
CGDirectDisplayID directDisplayID = ...;
io_service_t servicePort = CGDisplayIOServicePort(directDisplayID);
CFDictionaryRef newInfoDict = IODisplayCreateInfoDictionary(servicePort, kIODisplayMatchingInfo);
BOOL match = IODisplayMatchDictionaries(oldInfoDict, newInfoDict, 0);
if (match)
NSLog(@"Displays are a match");
else
NSLog(@"Displays are not a match");
上面发生的事情是:
- 在显示设置更改之前,我正在缓存oldInfoDict 。
- 等待显示设置更改
- 然后使用比较oldInfoDict和newInfoDict
IODisplayMatchDictionaries()
IODisplayMatchDictionaries()
返回一个 BOOL,要么是它们相同,要么不它们不同。
不幸的是,IODisplayMatchDictionaries()
如果相同的显示器更改了 GPU,则不会返回 YES。这是它正在比较的字典的示例(查看IODisplayLocation
键):
// oldInfoDict (Display ID: 30002)
oldInfoDict: {
DisplayProductID = 40144;
DisplayVendorID = 1552;
IODisplayLocation = "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/IGPU@2/AppleIntelFramebuffer/display0/AppleBacklightDisplay";
}
// newInfoDict (Display ID: 30004)
newInfoDict: {
DisplayProductID = 40144;
DisplayVendorID = 1552;
IODisplayLocation = "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/P0P2@1/IOPCI2PCIBridge/GFX0@0/NVDA,Display-A@0/NVDA/display0/AppleBacklightDisplay";
}
如您所见,IODisplayLocation
切换 GPU 时键会发生变化,因此IODisplayMatchDictionaries()
不起作用。
从理论上讲,我可以只比较DisplayProductID
和DisplayVendorID
键,但我正在编写最终用户软件,并且担心用户插入两个或多个相同显示器的情况(这意味着它们都将具有相同的 DisplayProductID/DisplayVendorID) . 换句话说,这是一个不太完美的解决方案,可能会出现潜在故障。
任何帮助是极大的赞赏!:)