В Mac OS X каждому дисплею присваивается уникальный номер CGDirectDisplayID
. Вы можете использовать CGGetActiveDisplayList(
) или [NSScreen screens]
для доступа к ним, среди прочего. Согласно Документам Apple :
Идентификатор дисплея может сохраняться при всех процессах и перезагрузке системы и, как правило, остается постоянным до тех пор, пока некоторые параметры дисплея не изменятся.
На новых MacBook Pro середины 2010 года Apple начала использовать автоматическое переключение графики Intel / nVidia. Ноутбуки имеют два графических процессора, маломощный Intel и мощный nVidia. Предыдущие ноутбуки с двумя графическими процессорами (модели 2009 года) не имели автоматического переключения графических процессоров и требовали от пользователя изменения настроек, выхода из системы и повторного входа в систему для переключения графического процессора. Даже в старых системах был только один графический процессор.
Существует проблема с моделями середины 2010 года, когда CGDirectDisplayID не остаются прежними, когда дисплей переключается с одного графического процессора на другое. Например:
У меня вопрос: как сопоставить старый идентификатор дисплея новому идентификатору дисплея, если они меняются из-за Смена графического процессора?
Мысль о:
Я заметил, что идентификатор дисплея меняется только на 2, но мне не хватает протестируйте Mac, чтобы определить, является ли это общим для всех новых MacBook Pro или только для меня. В любом случае, это своего рода клочок, если "просто проверьте идентификаторы дисплея, которые находятся +/- 2 друг от друга".
Пробовал:
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");
То, что происходит выше, это:
IODisplayMatchDictionaries()
IODisplayMatchDictionaries()
возвращает BOOL, либо ДА, они одинаковы, либо НЕТ, они разные. К сожалению, IODisplayMatchDictionaries()
не возвращает YES, если тот же дисплей изменил GPU. Вот пример сравнения словаря (посмотрите на клавишу 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
изменяется при переключении графических процессоров, поэтому IODisplayMatchDictionaries()
не работа.
Теоретически я могу сравнить только клавиши DisplayProductID
и DisplayVendorID
, но я пишу программное обеспечение для конечного пользователя, и меня беспокоит ситуация, когда у пользователя есть два или более одинаковых монитора, то есть будут ли оба одинаковых DisplayProductID / DisplayVendorID). Другими словами, это не идеальное решение, открытое для потенциальных сбоев.
Любая помощь очень ценится! :) [+1143]
Хотя я не профессионал, я считаю, что ответ заключается в том, чтобы позволить Apple уведомлять вас, когда пользователь меняет дисплеи. Информация в обратном вызове содержит флаги для добавления и удаления CGDirectDisplayID
ов.
Пользователь не должен добавлять или удалять видеокарты во время работы, поэтому я бы поигрался с составлением списка при запуске, и всякий раз, когда вы получаете флаг "remove", установите следующую операцию "add" для замены этого ID в списке.
Я бы попробовал просто печатать информацию, которую вы получаете каждый раз, когда CGDisplayRegisterReconfigurationCallback
вызывает вашу функцию. Посмотрите, получаете ли вы один DeviceUID с флагом 'remove', а затем при последующем вызове другой с флагом 'add'. Проверка этих идентификаторов по CGGetActiveDisplayList
также поможет понять, что происходит.
Это мой лучший вариант, надеюсь, он поможет!