56 std::vector<DISPLAYCONFIG_PATH_INFO> pathInfos;
57 std::vector<DISPLAYCONFIG_MODE_INFO> modeInfos;
61 UINT32 numPathArrayElements;
62 UINT32 numModeInfoArrayElements;
67 if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &numPathArrayElements,
68 &numModeInfoArrayElements) != ERROR_SUCCESS) {
71 pathInfos.resize(numPathArrayElements);
72 modeInfos.resize(numModeInfoArrayElements);
73 result = QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &numPathArrayElements, pathInfos.data(),
74 &numModeInfoArrayElements, modeInfos.data(),
nullptr);
75 }
while (result == ERROR_INSUFFICIENT_BUFFER);
77 if (result != ERROR_SUCCESS)
82 std::remove_if(pathInfos.begin(), pathInfos.end(), [&](
const auto &path) ->
bool {
83 DISPLAYCONFIG_SOURCE_DEVICE_NAME deviceName;
84 deviceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
85 deviceName.header.size =
sizeof(DISPLAYCONFIG_SOURCE_DEVICE_NAME);
86 deviceName.header.adapterId = path.sourceInfo.adapterId;
87 deviceName.header.id = path.sourceInfo.id;
88 if (DisplayConfigGetDeviceInfo(&deviceName.header) == ERROR_SUCCESS) {
89 return wcscmp(viewInfo.szDevice, deviceName.viewGdiDeviceName) != 0;
94 pathInfos.erase(discardThese, pathInfos.end());
150 const std::vector<DISPLAYCONFIG_PATH_INFO> &pathGroup)
152 if (pathGroup.empty()) {
158 DISPLAYCONFIG_TARGET_DEVICE_NAME deviceName = {};
159 deviceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
160 deviceName.header.size =
sizeof(DISPLAYCONFIG_TARGET_DEVICE_NAME);
162 deviceName.header.adapterId = pathGroup[0].targetInfo.adapterId;
163 deviceName.header.id = pathGroup[0].targetInfo.id;
164 if (DisplayConfigGetDeviceInfo(&deviceName.header) == ERROR_SUCCESS) {
165 data.devicePath = QString::fromWCharArray(deviceName.monitorDevicePath);
167 qCWarning(lcQpaScreen)
168 << u"Unable to get device information for %1:"_s.arg(pathGroup[0].targetInfo.id)
169 << QSystemError::windowsString();
175 QStringList manufacturers;
177 QStringList serialNumbers;
179 for (
const auto &path : pathGroup) {
180 DISPLAYCONFIG_TARGET_DEVICE_NAME deviceName = {};
181 deviceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
182 deviceName.header.size =
sizeof(DISPLAYCONFIG_TARGET_DEVICE_NAME);
183 deviceName.header.adapterId = path.targetInfo.adapterId;
184 deviceName.header.id = path.targetInfo.id;
185 if (DisplayConfigGetDeviceInfo(&deviceName.header) != ERROR_SUCCESS) {
186 qCWarning(lcQpaScreen)
187 << u"Unable to get device information for %1:"_s.arg(path.targetInfo.id)
188 << QSystemError::windowsString();
193 constexpr GUID GUID_DEVINTERFACE_MONITOR = {
194 0xe6f07b5f, 0xee97, 0x4a90, { 0xb0, 0x76, 0x33, 0xf5, 0x7b, 0xf4, 0xea, 0xa7 }
196 const DevInfoHandle devInfo{ SetupDiGetClassDevs(
197 &GUID_DEVINTERFACE_MONITOR,
nullptr,
nullptr, DIGCF_DEVICEINTERFACE) };
199 if (!devInfo.isValid())
202 SP_DEVICE_INTERFACE_DATA deviceInterfaceData{};
203 deviceInterfaceData.cbSize =
sizeof(deviceInterfaceData);
205 if (!SetupDiOpenDeviceInterfaceW(devInfo.get(), deviceName.monitorDevicePath, DIODI_NO_ADD,
206 &deviceInterfaceData)) {
207 qCWarning(lcQpaScreen)
208 << u"Unable to open monitor interface to %1:"_s.arg(data.deviceName)
209 << QSystemError::windowsString();
213 DWORD requiredSize{ 0 };
214 if (SetupDiGetDeviceInterfaceDetailW(devInfo.get(), &deviceInterfaceData,
nullptr, 0,
215 &requiredSize,
nullptr)
216 || GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
220 const std::unique_ptr<std::byte[]> storage(
new std::byte[requiredSize]);
221 auto *devicePath =
reinterpret_cast<SP_DEVICE_INTERFACE_DETAIL_DATA_W *>(storage.get());
222 devicePath->cbSize =
sizeof(std::remove_pointer_t<
decltype(devicePath)>);
223 SP_DEVINFO_DATA deviceInfoData{};
224 deviceInfoData.cbSize =
sizeof(deviceInfoData);
225 if (!SetupDiGetDeviceInterfaceDetailW(devInfo.get(), &deviceInterfaceData, devicePath,
226 requiredSize,
nullptr, &deviceInfoData)) {
227 qCDebug(lcQpaScreen) << u"Unable to get monitor metadata for %1:"_s.arg(data.deviceName)
228 << QSystemError::windowsString();
232 const DiRegKeyHandle edidRegistryKey{ SetupDiOpenDevRegKey(
233 devInfo.get(), &deviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ) };
235 if (!edidRegistryKey.isValid())
238 DWORD edidDataSize{ 0 };
239 if (RegQueryValueExW(edidRegistryKey.get(), L"EDID",
nullptr,
nullptr,
nullptr,
246 edidData.resize(edidDataSize);
248 if (RegQueryValueExW(edidRegistryKey.get(), L"EDID",
nullptr,
nullptr,
249 reinterpret_cast<
unsigned char *>(edidData.data()), &edidDataSize)
251 qCDebug(lcQpaScreen) << u"Unable to get EDID from the Registry for %1:"_s.arg(
253 << QSystemError::windowsString();
259 if (!edid.parse(edidData)) {
260 qCDebug(lcQpaScreen) <<
"Invalid EDID blob for" << data.deviceName;
266 names << QString::fromWCharArray(deviceName.monitorFriendlyDeviceName);
267 manufacturers << edid.manufacturer;
268 models << edid.model;
269 serialNumbers << edid.serialNumber;
272 data.name = names.join(u"|"_s);
273 data.manufacturer = manufacturers.join(u"|"_s);
274 data.model = models.join(u"|"_s);
275 data.serialNumber = serialNumbers.join(u"|"_s);
278static bool monitorData(HMONITOR hMonitor, QWindowsScreenData *data)
281 memset(&info, 0,
sizeof(MONITORINFOEX));
282 info.cbSize =
sizeof(MONITORINFOEX);
283 if (GetMonitorInfo(hMonitor, &info) == FALSE)
286 data->hMonitor = hMonitor;
287 data->geometry = QRect(
QPoint(info.rcMonitor.left, info.rcMonitor.top),
QPoint(info.rcMonitor.right - 1, info.rcMonitor.bottom - 1));
288 data->availableGeometry = QRect(
QPoint(info.rcWork.left, info.rcWork.top),
QPoint(info.rcWork.right - 1, info.rcWork.bottom - 1));
289 data->deviceName = QString::fromWCharArray(info.szDevice);
290 const auto pathGroup = getPathInfo(info);
291 if (!pathGroup.empty()) {
292 setMonitorDataFromSetupApi(*data, pathGroup);
294 if (data->name.isEmpty())
295 data->name = data->deviceName;
296 if (data->deviceName == u"WinDisc") {
297 data->flags |= QWindowsScreenData::LockScreen;
299 if (
const HDC hdc = CreateDC(info.szDevice,
nullptr,
nullptr,
nullptr)) {
300 const QDpi dpi = monitorDPI(hMonitor);
301 data->dpi = dpi.first > 0 ? dpi : deviceDPI(hdc);
302 data->depth = GetDeviceCaps(hdc, BITSPIXEL);
303 data->format = data->depth == 16 ? QImage::Format_RGB16 : QImage::Format_RGB32;
304 data->physicalSizeMM = QSizeF(GetDeviceCaps(hdc, HORZSIZE), GetDeviceCaps(hdc, VERTSIZE));
305 const int refreshRate = GetDeviceCaps(hdc, VREFRESH);
307 data->refreshRateHz = refreshRate;
310 qWarning(
"%s: Unable to obtain handle for monitor '%s', defaulting to %g DPI.",
311 __FUNCTION__, qPrintable(data->deviceName),
318 if (!pathGroup.empty()) {
320 const auto &pathInfo = pathGroup[0];
321 switch (pathInfo.targetInfo.rotation) {
322 case DISPLAYCONFIG_ROTATION_IDENTITY:
323 data->orientation = Qt::LandscapeOrientation;
325 case DISPLAYCONFIG_ROTATION_ROTATE90:
326 data->orientation = Qt::PortraitOrientation;
328 case DISPLAYCONFIG_ROTATION_ROTATE180:
329 data->orientation = Qt::InvertedLandscapeOrientation;
331 case DISPLAYCONFIG_ROTATION_ROTATE270:
332 data->orientation = Qt::InvertedPortraitOrientation;
334 case DISPLAYCONFIG_ROTATION_FORCE_UINT32:
338 if (pathInfo.targetInfo.refreshRate.Numerator && pathInfo.targetInfo.refreshRate.Denominator)
339 data->refreshRateHz =
static_cast<qreal>(pathInfo.targetInfo.refreshRate.Numerator)
340 / pathInfo.targetInfo.refreshRate.Denominator;
342 data->orientation = data->geometry.height() > data->geometry.width()
343 ? Qt::PortraitOrientation
344 : Qt::LandscapeOrientation;
348 data->flags |= QWindowsScreenData::VirtualDesktop;
349 if (info.dwFlags & MONITORINFOF_PRIMARY)
350 data->flags |= QWindowsScreenData::PrimaryScreen;
355BOOL QT_WIN_CALLBACK monitorEnumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM p)
357 QWindowsScreenData data;
358 if (monitorData(hMonitor, &data)) {
359 auto *result =
reinterpret_cast<WindowsScreenDataList *>(p);
360 auto it = std::find_if(result->rbegin(), result->rend(),
361 [&data](QWindowsScreenData i){
return i.name == data.name; });
362 if (it != result->rend()) {
363 int previousIndex = 1;
364 if (it->deviceIndex.has_value())
365 previousIndex = it->deviceIndex.value();
367 (*it).deviceIndex = 1;
368 data.deviceIndex = previousIndex + 1;
375 if (data.flags & QWindowsScreenData::PrimaryScreen)
376 result->prepend(data);
378 result->append(data);
391static QDebug operator<<(QDebug dbg,
const QWindowsScreenData &d)
393 QDebugStateSaver saver(dbg);
396 dbg <<
"Screen \"" << d.name <<
"\" " << d.geometry.width() <<
'x' << d.geometry.height() <<
'+'
397 << d.geometry.x() <<
'+' << d.geometry.y() <<
" avail: " << d.availableGeometry.width()
398 <<
'x' << d.availableGeometry.height() <<
'+' << d.availableGeometry.x() <<
'+'
399 << d.availableGeometry.y() <<
" physical: " << d.physicalSizeMM.width() <<
'x'
400 << d.physicalSizeMM.height() <<
" DPI: " << d.dpi.first <<
'x' << d.dpi.second
401 <<
" Depth: " << d.depth <<
" Format: " << d.format <<
" hMonitor: " << d.hMonitor
402 <<
" device name: " << d.deviceName <<
" manufacturer: " << d.manufacturer
403 <<
" model: " << d.model <<
" serial number: " << d.serialNumber;
404 if (d.flags & QWindowsScreenData::PrimaryScreen)
406 if (d.flags & QWindowsScreenData::VirtualDesktop)
407 dbg <<
" virtual desktop";
408 if (d.flags & QWindowsScreenData::LockScreen)
409 dbg <<
" lock screen";
441 HWND hwnd =
reinterpret_cast<HWND>(window);
444 GetClientRect(hwnd, &r);
445 windowSize = QSize(r.right - r.left, r.bottom - r.top);
449 hwnd = GetDesktopWindow();
450 const QRect screenGeometry = geometry();
451 windowSize = screenGeometry.size();
452 x += screenGeometry.x();
453 y += screenGeometry.y();
457 width = windowSize.width() - xIn;
459 height = windowSize.height() - yIn;
462 HDC display_dc = GetDC(
nullptr);
463 HDC bitmap_dc = CreateCompatibleDC(display_dc);
464 HBITMAP bitmap = CreateCompatibleBitmap(display_dc, width, height);
465 HGDIOBJ null_bitmap = SelectObject(bitmap_dc, bitmap);
468 HDC window_dc = GetDC(hwnd);
469 BitBlt(bitmap_dc, 0, 0, width, height, window_dc, x, y, SRCCOPY | CAPTUREBLT);
472 ReleaseDC(hwnd, window_dc);
473 SelectObject(bitmap_dc, null_bitmap);
476 const QPixmap pixmap = qt_pixmapFromWinHBITMAP(bitmap);
478 DeleteObject(bitmap);
479 ReleaseDC(
nullptr, display_dc);
538 m_data.physicalSizeMM = newData.physicalSizeMM;
540 if (m_data.hMonitor != newData.hMonitor) {
541 qCDebug(lcQpaScreen) <<
"Monitor" << m_data.name
542 <<
"has had its hMonitor handle changed from"
543 << m_data.hMonitor <<
"to" << newData.hMonitor;
544 m_data.hMonitor = newData.hMonitor;
549 const bool geometryChanged = m_data.geometry != newData.geometry
550 || m_data.availableGeometry != newData.availableGeometry;
551 const bool dpiChanged = !qFuzzyCompare(m_data.dpi.first, newData.dpi.first)
552 || !qFuzzyCompare(m_data.dpi.second, newData.dpi.second);
553 const bool orientationChanged = m_data.orientation != newData.orientation;
554 const bool primaryChanged = (newData.flags & QWindowsScreenData::PrimaryScreen)
555 && !(m_data.flags & QWindowsScreenData::PrimaryScreen);
556 m_data.dpi = newData.dpi;
557 m_data.orientation = newData.orientation;
558 m_data.geometry = newData.geometry;
559 m_data.availableGeometry = newData.availableGeometry;
560 m_data.flags = (m_data.flags & ~QWindowsScreenData::PrimaryScreen)
561 | (newData.flags & QWindowsScreenData::PrimaryScreen);
564 QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(screen(),
568 if (orientationChanged)
569 QWindowSystemInterface::handleScreenOrientationChange(screen(), newData.orientation);
570 if (geometryChanged) {
571 QWindowSystemInterface::handleScreenGeometryChange(screen(),
572 newData.geometry, newData.availableGeometry);
575 QWindowSystemInterface::handlePrimaryScreenChanged(
this);
618 Qt::ScreenOrientation result = Qt::PrimaryOrientation;
619 ORIENTATION_PREFERENCE orientationPreference = ORIENTATION_PREFERENCE_NONE;
620 if (GetDisplayAutoRotationPreferences(&orientationPreference)) {
621 switch (orientationPreference) {
622 case ORIENTATION_PREFERENCE_NONE:
624 case ORIENTATION_PREFERENCE_LANDSCAPE:
625 result = Qt::LandscapeOrientation;
627 case ORIENTATION_PREFERENCE_PORTRAIT:
628 result = Qt::PortraitOrientation;
630 case ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED:
631 result = Qt::InvertedLandscapeOrientation;
633 case ORIENTATION_PREFERENCE_PORTRAIT_FLIPPED:
634 result = Qt::InvertedPortraitOrientation;
Singleton container for all relevant information.