From 4c6c0948955988ad93d2960ac8b7f64eaca42b58 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 2 Jul 2019 12:44:58 +0200 Subject: Windows QPA: Lookup DISPLAYCONFIG data for monitors Gives more accurate orientation and refresh-rate. Change-Id: I90b0b7563efc35c9bace07ccb3996350a957e8e5 Reviewed-by: Oliver Wolff --- src/plugins/platforms/windows/qwindowsscreen.cpp | 96 +++++++++++++++++++++++- 1 file changed, 94 insertions(+), 2 deletions(-) diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp index a15a39c2a4..cddc384418 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.cpp +++ b/src/plugins/platforms/windows/qwindowsscreen.cpp @@ -74,6 +74,70 @@ static inline QDpi monitorDPI(HMONITOR hMonitor) return {0, 0}; } +static bool getPathInfo(const MONITORINFOEX &viewInfo, DISPLAYCONFIG_PATH_INFO *pathInfo) +{ + // We might want to consider storing adapterId/id from DISPLAYCONFIG_PATH_TARGET_INFO. + std::vector pathInfos; + std::vector modeInfos; + + // Fetch paths + LONG result; + UINT32 numPathArrayElements; + UINT32 numModeInfoArrayElements; + do { + // QueryDisplayConfig documentation doesn't say the number of needed elements is updated + // when the call fails with ERROR_INSUFFICIENT_BUFFER, so we need a separate call to + // look up the needed buffer sizes. + if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &numPathArrayElements, + &numModeInfoArrayElements) != ERROR_SUCCESS) { + return false; + } + pathInfos.resize(numPathArrayElements); + modeInfos.resize(numModeInfoArrayElements); + result = QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &numPathArrayElements, pathInfos.data(), + &numModeInfoArrayElements, modeInfos.data(), nullptr); + } while (result == ERROR_INSUFFICIENT_BUFFER); + + if (result != ERROR_SUCCESS) + return false; + + // Find path matching monitor name + for (uint32_t p = 0; p < numPathArrayElements; p++) { + DISPLAYCONFIG_SOURCE_DEVICE_NAME deviceName; + deviceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME; + deviceName.header.size = sizeof(DISPLAYCONFIG_SOURCE_DEVICE_NAME); + deviceName.header.adapterId = pathInfos[p].sourceInfo.adapterId; + deviceName.header.id = pathInfos[p].sourceInfo.id; + if (DisplayConfigGetDeviceInfo(&deviceName.header) == ERROR_SUCCESS) { + if (wcscmp(viewInfo.szDevice, deviceName.viewGdiDeviceName) == 0) { + *pathInfo = pathInfos[p]; + return true; + } + } + } + + return false; +} + +#if 0 +// Needed later for HDR support +static float getMonitorSDRWhiteLevel(DISPLAYCONFIG_PATH_TARGET_INFO *targetInfo) +{ + const float defaultSdrWhiteLevel = 200.0; + if (!targetInfo) + return defaultSdrWhiteLevel; + + DISPLAYCONFIG_SDR_WHITE_LEVEL whiteLevel = {}; + whiteLevel.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL; + whiteLevel.header.size = sizeof(DISPLAYCONFIG_SDR_WHITE_LEVEL); + whiteLevel.header.adapterId = targetInfo->adapterId; + whiteLevel.header.id = targetInfo->id; + if (DisplayConfigGetDeviceInfo(&whiteLevel.header) != ERROR_SUCCESS) + return defaultSdrWhiteLevel; + return whiteLevel.SDRWhiteLevel * 80.0 / 1000.0; +} +#endif + using WindowsScreenDataList = QList; static bool monitorData(HMONITOR hMonitor, QWindowsScreenData *data) @@ -107,8 +171,36 @@ static bool monitorData(HMONITOR hMonitor, QWindowsScreenData *data) data->dpi.first); } // CreateDC() failed } // not lock screen - data->orientation = data->geometry.height() > data->geometry.width() ? - Qt::PortraitOrientation : Qt::LandscapeOrientation; + + // ### We might want to consider storing adapterId/id from DISPLAYCONFIG_PATH_TARGET_INFO, + // if we are going to use DISPLAYCONFIG lookups more. + DISPLAYCONFIG_PATH_INFO pathInfo = {}; + if (getPathInfo(info, &pathInfo)) { + switch (pathInfo.targetInfo.rotation) { + case DISPLAYCONFIG_ROTATION_IDENTITY: + data->orientation = Qt::LandscapeOrientation; + break; + case DISPLAYCONFIG_ROTATION_ROTATE90: + data->orientation = Qt::PortraitOrientation; + break; + case DISPLAYCONFIG_ROTATION_ROTATE180: + data->orientation = Qt::InvertedLandscapeOrientation; + break; + case DISPLAYCONFIG_ROTATION_ROTATE270: + data->orientation = Qt::InvertedPortraitOrientation; + break; + case DISPLAYCONFIG_ROTATION_FORCE_UINT32: + Q_UNREACHABLE(); + break; + } + if (pathInfo.targetInfo.refreshRate.Numerator && pathInfo.targetInfo.refreshRate.Denominator) + data->refreshRateHz = static_cast(pathInfo.targetInfo.refreshRate.Numerator) + / pathInfo.targetInfo.refreshRate.Denominator; + } else { + data->orientation = data->geometry.height() > data->geometry.width() + ? Qt::PortraitOrientation + : Qt::LandscapeOrientation; + } // EnumDisplayMonitors (as opposed to EnumDisplayDevices) enumerates only // virtual desktop screens. data->flags |= QWindowsScreenData::VirtualDesktop; -- cgit v1.2.3