13#include <QtCore/qt_windows.h>
15#include <QtCore/qsettings.h>
16#include <QtGui/qpixmap.h>
17#include <QtGui/qguiapplication.h>
18#include <qpa/qwindowsysteminterface.h>
19#include <QtCore/private/qsystemerror_p.h>
20#include <QtGui/private/qedidparser_p.h>
21#include <private/qhighdpiscaling_p.h>
22#include <private/qwindowsfontdatabasebase_p.h>
23#include <private/qpixmap_win_p.h>
24#include <private/quniquehandle_p.h>
26#include <QtGui/qscreen.h>
28#include <QtCore/qdebug.h>
35#include <shellscalingapi.h>
39using namespace Qt::StringLiterals;
43 return QDpi(GetDeviceCaps(hdc, LOGPIXELSX), GetDeviceCaps(hdc, LOGPIXELSY));
50 if (SUCCEEDED(GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY)))
51 return QDpi(dpiX, dpiY);
58 std::vector<DISPLAYCONFIG_PATH_INFO> pathInfos;
59 std::vector<DISPLAYCONFIG_MODE_INFO> modeInfos;
63 UINT32 numPathArrayElements;
64 UINT32 numModeInfoArrayElements;
69 if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &numPathArrayElements,
70 &numModeInfoArrayElements) != ERROR_SUCCESS) {
73 pathInfos.resize(numPathArrayElements);
74 modeInfos.resize(numModeInfoArrayElements);
75 result = QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &numPathArrayElements, pathInfos.data(),
76 &numModeInfoArrayElements, modeInfos.data(),
nullptr);
77 }
while (result == ERROR_INSUFFICIENT_BUFFER);
79 if (result != ERROR_SUCCESS)
84 std::remove_if(pathInfos.begin(), pathInfos.end(), [&](
const auto &path) ->
bool {
85 DISPLAYCONFIG_SOURCE_DEVICE_NAME deviceName;
86 deviceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
87 deviceName.header.size =
sizeof(DISPLAYCONFIG_SOURCE_DEVICE_NAME);
88 deviceName.header.adapterId = path.sourceInfo.adapterId;
89 deviceName.header.id = path.sourceInfo.id;
90 if (DisplayConfigGetDeviceInfo(&deviceName.header) == ERROR_SUCCESS) {
91 return wcscmp(viewInfo.szDevice, deviceName.viewGdiDeviceName) != 0;
96 pathInfos.erase(discardThese, pathInfos.end());
103static float getMonitorSDRWhiteLevel(DISPLAYCONFIG_PATH_TARGET_INFO *targetInfo)
105 const float defaultSdrWhiteLevel = 200.0;
107 return defaultSdrWhiteLevel;
109 DISPLAYCONFIG_SDR_WHITE_LEVEL whiteLevel = {};
110 whiteLevel.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL;
111 whiteLevel.header.size =
sizeof(DISPLAYCONFIG_SDR_WHITE_LEVEL);
112 whiteLevel.header.adapterId = targetInfo->adapterId;
113 whiteLevel.header.id = targetInfo->id;
114 if (DisplayConfigGetDeviceInfo(&whiteLevel.header) != ERROR_SUCCESS)
115 return defaultSdrWhiteLevel;
116 return whiteLevel.SDRWhiteLevel * 80.0 / 1000.0;
120using WindowsScreenDataList = QList<QWindowsScreenData>;
124struct DiRegKeyHandleTraits
127 static Type invalidValue()
noexcept
130 return reinterpret_cast<HKEY>(INVALID_HANDLE_VALUE);
132 static bool close(Type handle)
noexcept {
return RegCloseKey(handle) == ERROR_SUCCESS; }
135using DiRegKeyHandle = QUniqueHandle<DiRegKeyHandleTraits>;
137struct DevInfoHandleTraits
139 using Type = HDEVINFO;
140 static Type invalidValue()
noexcept
142 return reinterpret_cast<HDEVINFO>(INVALID_HANDLE_VALUE);
144 static bool close(Type handle)
noexcept {
return SetupDiDestroyDeviceInfoList(handle) == TRUE; }
147using DevInfoHandle = QUniqueHandle<DevInfoHandleTraits>;
152 const std::vector<DISPLAYCONFIG_PATH_INFO> &pathGroup)
154 if (pathGroup.empty()) {
160 DISPLAYCONFIG_TARGET_DEVICE_NAME deviceName = {};
161 deviceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
162 deviceName.header.size =
sizeof(DISPLAYCONFIG_TARGET_DEVICE_NAME);
164 deviceName.header.adapterId = pathGroup[0].targetInfo.adapterId;
165 deviceName.header.id = pathGroup[0].targetInfo.id;
166 if (DisplayConfigGetDeviceInfo(&deviceName.header) == ERROR_SUCCESS) {
167 data.devicePath = QString::fromWCharArray(deviceName.monitorDevicePath);
169 qCWarning(lcQpaScreen)
170 << u"Unable to get device information for %1:"_s.arg(pathGroup[0].targetInfo.id)
171 << QSystemError::windowsString();
177 QStringList manufacturers;
179 QStringList serialNumbers;
181 for (
const auto &path : pathGroup) {
182 DISPLAYCONFIG_TARGET_DEVICE_NAME deviceName = {};
183 deviceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
184 deviceName.header.size =
sizeof(DISPLAYCONFIG_TARGET_DEVICE_NAME);
185 deviceName.header.adapterId = path.targetInfo.adapterId;
186 deviceName.header.id = path.targetInfo.id;
187 if (DisplayConfigGetDeviceInfo(&deviceName.header) != ERROR_SUCCESS) {
188 qCWarning(lcQpaScreen)
189 << u"Unable to get device information for %1:"_s.arg(path.targetInfo.id)
190 << QSystemError::windowsString();
195 constexpr GUID GUID_DEVINTERFACE_MONITOR = {
196 0xe6f07b5f, 0xee97, 0x4a90, { 0xb0, 0x76, 0x33, 0xf5, 0x7b, 0xf4, 0xea, 0xa7 }
198 const DevInfoHandle devInfo{ SetupDiGetClassDevs(
199 &GUID_DEVINTERFACE_MONITOR,
nullptr,
nullptr, DIGCF_DEVICEINTERFACE) };
201 if (!devInfo.isValid())
204 SP_DEVICE_INTERFACE_DATA deviceInterfaceData{};
205 deviceInterfaceData.cbSize =
sizeof(deviceInterfaceData);
207 if (!SetupDiOpenDeviceInterfaceW(devInfo.get(), deviceName.monitorDevicePath, DIODI_NO_ADD,
208 &deviceInterfaceData)) {
209 qCWarning(lcQpaScreen)
210 << u"Unable to open monitor interface to %1:"_s.arg(data.deviceName)
211 << QSystemError::windowsString();
215 DWORD requiredSize{ 0 };
216 if (SetupDiGetDeviceInterfaceDetailW(devInfo.get(), &deviceInterfaceData,
nullptr, 0,
217 &requiredSize,
nullptr)
218 || GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
222 const std::unique_ptr<std::byte[]> storage(
new std::byte[requiredSize]);
223 auto *devicePath =
reinterpret_cast<SP_DEVICE_INTERFACE_DETAIL_DATA_W *>(storage.get());
224 devicePath->cbSize =
sizeof(std::remove_pointer_t<
decltype(devicePath)>);
225 SP_DEVINFO_DATA deviceInfoData{};
226 deviceInfoData.cbSize =
sizeof(deviceInfoData);
227 if (!SetupDiGetDeviceInterfaceDetailW(devInfo.get(), &deviceInterfaceData, devicePath,
228 requiredSize,
nullptr, &deviceInfoData)) {
229 qCDebug(lcQpaScreen) << u"Unable to get monitor metadata for %1:"_s.arg(data.deviceName)
230 << QSystemError::windowsString();
234 const DiRegKeyHandle edidRegistryKey{ SetupDiOpenDevRegKey(
235 devInfo.get(), &deviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ) };
237 if (!edidRegistryKey.isValid())
240 DWORD edidDataSize{ 0 };
241 if (RegQueryValueExW(edidRegistryKey.get(), L"EDID",
nullptr,
nullptr,
nullptr,
248 edidData.resize(edidDataSize);
250 if (RegQueryValueExW(edidRegistryKey.get(), L"EDID",
nullptr,
nullptr,
251 reinterpret_cast<
unsigned char *>(edidData.data()), &edidDataSize)
253 qCDebug(lcQpaScreen) << u"Unable to get EDID from the Registry for %1:"_s.arg(
255 << QSystemError::windowsString();
261 if (!edid.parse(edidData)) {
262 qCDebug(lcQpaScreen) <<
"Invalid EDID blob for" << data.deviceName;
268 names << QString::fromWCharArray(deviceName.monitorFriendlyDeviceName);
269 manufacturers << edid.manufacturer;
270 models << edid.model;
271 serialNumbers << edid.serialNumber;
274 data.name = names.join(u"|"_s);
275 data.manufacturer = manufacturers.join(u"|"_s);
276 data.model = models.join(u"|"_s);
277 data.serialNumber = serialNumbers.join(u"|"_s);
280static bool monitorData(HMONITOR hMonitor, QWindowsScreenData *data)
283 memset(&info, 0,
sizeof(MONITORINFOEX));
284 info.cbSize =
sizeof(MONITORINFOEX);
285 if (GetMonitorInfo(hMonitor, &info) == FALSE)
288 data->hMonitor = hMonitor;
289 data->geometry = QRect(
QPoint(info.rcMonitor.left, info.rcMonitor.top),
QPoint(info.rcMonitor.right - 1, info.rcMonitor.bottom - 1));
290 data->availableGeometry = QRect(
QPoint(info.rcWork.left, info.rcWork.top),
QPoint(info.rcWork.right - 1, info.rcWork.bottom - 1));
291 data->deviceName = QString::fromWCharArray(info.szDevice);
292 const auto pathGroup = getPathInfo(info);
293 if (!pathGroup.empty()) {
294 setMonitorDataFromSetupApi(*data, pathGroup);
296 if (data->name.isEmpty())
297 data->name = data->deviceName;
298 if (data->deviceName == u"WinDisc") {
299 data->flags |= QWindowsScreenData::LockScreen;
301 if (
const HDC hdc = CreateDC(info.szDevice,
nullptr,
nullptr,
nullptr)) {
302 const QDpi dpi = monitorDPI(hMonitor);
303 data->dpi = dpi.first > 0 ? dpi : deviceDPI(hdc);
304 data->depth = GetDeviceCaps(hdc, BITSPIXEL);
305 data->format = data->depth == 16 ? QImage::Format_RGB16 : QImage::Format_RGB32;
306 data->physicalSizeMM = QSizeF(GetDeviceCaps(hdc, HORZSIZE), GetDeviceCaps(hdc, VERTSIZE));
307 const int refreshRate = GetDeviceCaps(hdc, VREFRESH);
309 data->refreshRateHz = refreshRate;
312 qWarning(
"%s: Unable to obtain handle for monitor '%s', defaulting to %g DPI.",
313 __FUNCTION__, qPrintable(data->deviceName),
320 if (!pathGroup.empty()) {
322 const auto &pathInfo = pathGroup[0];
323 switch (pathInfo.targetInfo.rotation) {
324 case DISPLAYCONFIG_ROTATION_IDENTITY:
325 data->orientation = Qt::LandscapeOrientation;
327 case DISPLAYCONFIG_ROTATION_ROTATE90:
328 data->orientation = Qt::PortraitOrientation;
330 case DISPLAYCONFIG_ROTATION_ROTATE180:
331 data->orientation = Qt::InvertedLandscapeOrientation;
333 case DISPLAYCONFIG_ROTATION_ROTATE270:
334 data->orientation = Qt::InvertedPortraitOrientation;
336 case DISPLAYCONFIG_ROTATION_FORCE_UINT32:
340 if (pathInfo.targetInfo.refreshRate.Numerator && pathInfo.targetInfo.refreshRate.Denominator)
341 data->refreshRateHz =
static_cast<qreal>(pathInfo.targetInfo.refreshRate.Numerator)
342 / pathInfo.targetInfo.refreshRate.Denominator;
344 data->orientation = data->geometry.height() > data->geometry.width()
345 ? Qt::PortraitOrientation
346 : Qt::LandscapeOrientation;
350 data->flags |= QWindowsScreenData::VirtualDesktop;
351 if (info.dwFlags & MONITORINFOF_PRIMARY)
352 data->flags |= QWindowsScreenData::PrimaryScreen;
357BOOL QT_WIN_CALLBACK monitorEnumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM p)
359 QWindowsScreenData data;
360 if (monitorData(hMonitor, &data)) {
361 auto *result =
reinterpret_cast<WindowsScreenDataList *>(p);
362 auto it = std::find_if(result->rbegin(), result->rend(),
363 [&data](QWindowsScreenData i){
return i.name == data.name; });
364 if (it != result->rend()) {
365 int previousIndex = 1;
366 if (it->deviceIndex.has_value())
367 previousIndex = it->deviceIndex.value();
369 (*it).deviceIndex = 1;
370 data.deviceIndex = previousIndex + 1;
377 if (data.flags & QWindowsScreenData::PrimaryScreen)
378 result->prepend(data);
380 result->append(data);
387 WindowsScreenDataList result;
388 EnumDisplayMonitors(
nullptr,
nullptr, monitorEnumCallback,
reinterpret_cast<LPARAM>(&result));
392#ifndef QT_NO_DEBUG_STREAM
393static QDebug operator<<(QDebug dbg,
const QWindowsScreenData &d)
395 QDebugStateSaver saver(dbg);
398 dbg <<
"Screen \"" << d.name <<
"\" " << d.geometry.width() <<
'x' << d.geometry.height() <<
'+'
399 << d.geometry.x() <<
'+' << d.geometry.y() <<
" avail: " << d.availableGeometry.width()
400 <<
'x' << d.availableGeometry.height() <<
'+' << d.availableGeometry.x() <<
'+'
401 << d.availableGeometry.y() <<
" physical: " << d.physicalSizeMM.width() <<
'x'
402 << d.physicalSizeMM.height() <<
" DPI: " << d.dpi.first <<
'x' << d.dpi.second
403 <<
" Depth: " << d.depth <<
" Format: " << d.format <<
" hMonitor: " << d.hMonitor
404 <<
" device name: " << d.deviceName <<
" manufacturer: " << d.manufacturer
405 <<
" model: " << d.model <<
" serial number: " << d.serialNumber;
406 if (d.flags & QWindowsScreenData::PrimaryScreen)
408 if (d.flags & QWindowsScreenData::VirtualDesktop)
409 dbg <<
" virtual desktop";
410 if (d.flags & QWindowsScreenData::LockScreen)
411 dbg <<
" lock screen";
417
418
419
420
421
426 , m_cursor(
new QWindowsCursor(
this))
433 return m_data.deviceIndex.has_value()
434 ? (u"%1 (%2)"_s).arg(m_data.name, QString::number(m_data.deviceIndex.value()))
443 HWND hwnd =
reinterpret_cast<HWND>(window);
446 GetClientRect(hwnd, &r);
447 windowSize = QSize(r.right - r.left, r.bottom - r.top);
451 hwnd = GetDesktopWindow();
452 const QRect screenGeometry = geometry();
453 windowSize = screenGeometry.size();
461 MONITORINFOEX info = {};
462 info.cbSize =
sizeof(MONITORINFOEX);
463 if (GetMonitorInfo(handle(), &info)) {
465 dm.dmSize =
sizeof(dm);
466 if (EnumDisplaySettings(info.szDevice, ENUM_CURRENT_SETTINGS, &dm)) {
467 qreal scale =
static_cast<qreal>(dm.dmPelsWidth) / windowSize.width();
468 x =
static_cast<
int>(
static_cast<qreal>(x) * scale);
469 y =
static_cast<
int>(
static_cast<qreal>(y) * scale);
470 windowSize = QSize(dm.dmPelsWidth, dm.dmPelsHeight);
474 x += screenGeometry.x();
475 y += screenGeometry.y();
479 width = windowSize.width() - xIn;
481 height = windowSize.height() - yIn;
484 HDC display_dc = GetDC(
nullptr);
485 HDC bitmap_dc = CreateCompatibleDC(display_dc);
486 HBITMAP bitmap = CreateCompatibleBitmap(display_dc, width, height);
487 HGDIOBJ null_bitmap = SelectObject(bitmap_dc, bitmap);
490 HDC window_dc = GetDC(hwnd);
491 BitBlt(bitmap_dc, 0, 0, width, height, window_dc, x, y, SRCCOPY | CAPTUREBLT);
494 ReleaseDC(hwnd, window_dc);
495 SelectObject(bitmap_dc, null_bitmap);
498 const QPixmap pixmap = qt_pixmapFromWinHBITMAP(bitmap);
500 DeleteObject(bitmap);
501 ReleaseDC(
nullptr, display_dc);
507
508
512 QWindow *result =
nullptr;
513 if (QWindow *child = QWindowsScreen::windowAt(point, CWP_SKIPINVISIBLE))
514 result = QWindowsWindow::topLevelOf(child);
516 qCDebug(lcQpaScreen) <<
__FUNCTION__ << point << result;
522 QWindow* result =
nullptr;
524 findPlatformWindowAt(GetDesktopWindow(), screenPoint, flags))
525 result = bw->window();
527 qCDebug(lcQpaScreen) <<
__FUNCTION__ << screenPoint <<
" returns " << result;
532
533
534
535
536
540 QList<QPlatformScreen *> result;
541 if (m_data.flags & QWindowsScreenData::VirtualDesktop) {
542 const QWindowsScreenManager::WindowsScreenList screens
544 for (QWindowsScreen *screen : screens) {
545 if (screen->data().flags & QWindowsScreenData::VirtualDesktop)
546 result.push_back(screen);
555
556
560 m_data.physicalSizeMM = newData.physicalSizeMM;
562 if (m_data.hMonitor != newData.hMonitor) {
563 qCDebug(lcQpaScreen) <<
"Monitor" << m_data.name
564 <<
"has had its hMonitor handle changed from"
565 << m_data.hMonitor <<
"to" << newData.hMonitor;
566 m_data.hMonitor = newData.hMonitor;
571 const bool geometryChanged = m_data.geometry != newData.geometry
572 || m_data.availableGeometry != newData.availableGeometry;
573 const bool dpiChanged = !qFuzzyCompare(m_data.dpi.first, newData.dpi.first)
574 || !qFuzzyCompare(m_data.dpi.second, newData.dpi.second);
575 const bool orientationChanged = m_data.orientation != newData.orientation;
576 const bool primaryChanged = (newData.flags & QWindowsScreenData::PrimaryScreen)
577 && !(m_data.flags & QWindowsScreenData::PrimaryScreen);
578 const bool refreshRateChanged = m_data.refreshRateHz != newData.refreshRateHz;
579 m_data.dpi = newData.dpi;
580 m_data.orientation = newData.orientation;
581 m_data.geometry = newData.geometry;
582 m_data.availableGeometry = newData.availableGeometry;
583 m_data.flags = (m_data.flags & ~QWindowsScreenData::PrimaryScreen)
584 | (newData.flags & QWindowsScreenData::PrimaryScreen);
585 m_data.refreshRateHz = newData.refreshRateHz;
588 QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(screen(),
592 if (orientationChanged)
593 QWindowSystemInterface::handleScreenOrientationChange(screen(), newData.orientation);
594 if (geometryChanged) {
595 QWindowSystemInterface::handleScreenGeometryChange(screen(),
596 newData.geometry, newData.availableGeometry);
599 QWindowSystemInterface::handlePrimaryScreenChanged(
this);
601 if (refreshRateChanged)
602 QWindowSystemInterface::handleScreenRefreshRateChange(screen(), newData.refreshRateHz);
607 return m_data.hMonitor;
613 const auto siblings = screen->virtualSiblings();
614 for (
const QPlatformScreen *sibling : siblings)
615 result |= sibling->geometry();
622 ORIENTATION_PREFERENCE orientationPreference = ORIENTATION_PREFERENCE_NONE;
624 case Qt::PrimaryOrientation:
626 case Qt::PortraitOrientation:
627 orientationPreference = ORIENTATION_PREFERENCE_PORTRAIT;
629 case Qt::LandscapeOrientation:
630 orientationPreference = ORIENTATION_PREFERENCE_LANDSCAPE;
632 case Qt::InvertedPortraitOrientation:
633 orientationPreference = ORIENTATION_PREFERENCE_PORTRAIT_FLIPPED;
635 case Qt::InvertedLandscapeOrientation:
636 orientationPreference = ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED;
639 result = SetDisplayAutoRotationPreferences(orientationPreference);
645 Qt::ScreenOrientation result = Qt::PrimaryOrientation;
646 ORIENTATION_PREFERENCE orientationPreference = ORIENTATION_PREFERENCE_NONE;
647 if (GetDisplayAutoRotationPreferences(&orientationPreference)) {
648 switch (orientationPreference) {
649 case ORIENTATION_PREFERENCE_NONE:
651 case ORIENTATION_PREFERENCE_LANDSCAPE:
652 result = Qt::LandscapeOrientation;
654 case ORIENTATION_PREFERENCE_PORTRAIT:
655 result = Qt::PortraitOrientation;
657 case ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED:
658 result = Qt::InvertedLandscapeOrientation;
660 case ORIENTATION_PREFERENCE_PORTRAIT_FLIPPED:
661 result = Qt::InvertedPortraitOrientation;
669
670
673 QPlatformScreen::SubpixelAntialiasingType type = QPlatformScreen::subpixelAntialiasingTypeHint();
674 if (type == QPlatformScreen::Subpixel_None) {
675 QSettings settings(R"(HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Avalon.Graphics\DISPLAY1)"_L1,
676 QSettings::NativeFormat);
677 int registryValue = settings.value(
"PixelStructure"_L1, -1).toInt();
678 switch (registryValue) {
680 type = QPlatformScreen::Subpixel_None;
683 type = QPlatformScreen::Subpixel_RGB;
686 type = QPlatformScreen::Subpixel_BGR;
689 type = QPlatformScreen::Subpixel_None;
697
698
699
700
701
702
703
704
705
707LRESULT QT_WIN_CALLBACK qDisplayChangeObserverWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
709 if (message == WM_DISPLAYCHANGE) {
710 qCDebug(lcQpaScreen) <<
"Handling WM_DISPLAYCHANGE";
711 if (QWindowsTheme *t = QWindowsTheme::instance())
713 QWindowsWindow::displayChanged();
714 if (
auto *context = QWindowsContext::instance())
715 context->screenManager().handleScreenChanges();
718 return DefWindowProc(hwnd, message, wParam, lParam);
725 qCDebug(lcQpaScreen) <<
"Initializing screen manager";
728 "ScreenChangeObserverWindow"_L1,
729 qDisplayChangeObserverWndProc);
733 m_displayChangeObserver = CreateWindowEx(0,
reinterpret_cast<LPCWSTR>(className.utf16()),
734 nullptr, WS_TILED, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
735 nullptr,
nullptr, GetModuleHandle(
nullptr),
nullptr);
736 Q_ASSERT(m_displayChangeObserver);
738 qCDebug(lcQpaScreen) <<
"Created display change observer" << m_displayChangeObserver;
745 qCDebug(lcQpaScreen) <<
"Destroying display change observer" << m_displayChangeObserver;
746 DestroyWindow(m_displayChangeObserver);
747 m_displayChangeObserver =
nullptr;
757static inline int indexOfMonitor(
const QWindowsScreenManager::WindowsScreenList &screens,
758 const QString &deviceName)
760 for (
int i= 0; i < screens.size(); ++i)
761 if (screens.at(i)->data().deviceName == deviceName)
767 const QString &deviceName)
769 for (
int i = 0; i < screenData.size(); ++i)
770 if (screenData.at(i).deviceName == deviceName)
778 QRect geometry = w->geometry();
779 const QRect oldScreenGeometry = w->screen()->geometry();
780 const QRect newScreenGeometry = newScreen->geometry();
781 QPoint relativePosition = geometry.topLeft() - oldScreenGeometry.topLeft();
782 if (oldScreenGeometry.size() != newScreenGeometry.size()) {
784 qreal(
QPoint(newScreenGeometry.width(), newScreenGeometry.height()).manhattanLength()) /
785 qreal(
QPoint(oldScreenGeometry.width(), oldScreenGeometry.height()).manhattanLength());
786 relativePosition = (QPointF(relativePosition) * factor).toPoint();
788 geometry.moveTopLeft(relativePosition);
789 w->setGeometry(geometry);
795 m_screens.push_back(newScreen);
796 QWindowSystemInterface::handleScreenAdded(newScreen,
797 screenData.flags & QWindowsScreenData::PrimaryScreen);
798 qCDebug(lcQpaScreen) <<
"New Monitor: " << screenData;
805 const auto allWindows = QGuiApplication::allWindows();
806 for (QWindow *w : allWindows) {
807 if (w->isVisible() && w->handle()) {
808 if (QWindowsWindow *window = QWindowsWindow::windowsWindowOf(w))
809 window->checkForScreenChanged(QWindowsWindow::ScreenChangeMode::FromScreenAdded);
816 qCDebug(lcQpaScreen) <<
"Removing Monitor:" << m_screens.at(index)->data();
817 QPlatformScreen *platformScreen = m_screens.takeAt(index);
818 QScreen *screen = platformScreen->screen();
819 QScreen *primaryScreen = QGuiApplication::primaryScreen();
827 if (screen != primaryScreen) {
828 unsigned movedWindowCount = 0;
829 const QWindowList tlws = QGuiApplication::topLevelWindows();
830 for (QWindow *w : tlws) {
831 if (w->screen() == screen && w->handle()) {
832 if (w->isVisible() && w->windowState() != Qt::WindowMinimized
833 && (QWindowsWindow::baseWindowOf(w)->exStyle() & WS_EX_TOOLWINDOW)) {
834 moveToVirtualScreen(w, primaryScreen);
836 QWindowSystemInterface::handleWindowScreenChanged<QWindowSystemInterface::SynchronousDelivery>(w, primaryScreen);
841 if (movedWindowCount)
842 QWindowSystemInterface::flushWindowSystemEvents();
844 QWindowSystemInterface::handleScreenRemoved(platformScreen);
848
849
850
855 const WindowsScreenDataList newDataList = monitorData();
856 const bool lockScreen = newDataList.size() == 1 && (newDataList.front().flags & QWindowsScreenData::LockScreen);
857 bool primaryScreenChanged =
false;
858 for (
const QWindowsScreenData &newData : newDataList) {
859 const int existingIndex = indexOfMonitor(m_screens, newData.deviceName);
860 if (existingIndex != -1) {
861 m_screens.at(existingIndex)->handleChanges(newData);
862 if (existingIndex == 0)
863 primaryScreenChanged =
true;
871 for (
int i = m_screens.size() - 1; i >= 0; --i) {
872 if (indexOfMonitor(newDataList, m_screens.at(i)->data().deviceName) == -1)
876 if (primaryScreenChanged) {
886 while (!m_screens.isEmpty())
887 QWindowSystemInterface::handleScreenRemoved(m_screens.takeLast());
892 for (QWindowsScreen *scr : m_screens) {
893 if (scr->geometry().contains(p))
901 if (hMonitor ==
nullptr)
904 std::find_if(m_screens.cbegin(), m_screens.cend(),
905 [hMonitor](
const QWindowsScreen *s)
907 return s->data().hMonitor == hMonitor
908 && (s->data().flags & QWindowsScreenData::VirtualDesktop) != 0;
910 return it != m_screens.cend() ? *it :
nullptr;
915 HMONITOR hMonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONULL);
916 return screenForMonitor(hMonitor);
923 HMONITOR hMonitor = MonitorFromRect(rect, MONITOR_DEFAULTTONULL);
924 return screenForMonitor(hMonitor);
\inmodule QtCore\reentrant
Singleton container for all relevant information.
QWindowsScreenManager & screenManager()
static QtWindows::DpiAwareness processDpiAwareness()
static QWindowsContext * instance()
Manages a list of QWindowsScreen.
bool handleScreenChanges()
Synchronizes the screen list, adds new screens, removes deleted ones and propagates resolution change...
const QWindowsScreen * screenForHwnd(HWND hwnd) const
const QWindowsScreen * screenAtDp(const QPoint &p) const
static bool isSingleScreen()
const QWindowsScreen * screenForRect(const RECT *rect) const
QList< QPlatformScreen * > virtualSiblings() const override
Determine siblings in a virtual desktop system.
QPixmap grabWindow(WId window, int qX, int qY, int qWidth, int qHeight) const override
This function is called when Qt needs to be able to grab the content of a window.
QPlatformScreen::SubpixelAntialiasingType subpixelAntialiasingTypeHint() const override
Queries ClearType settings to check the pixel layout.
QString name() const override
QWindow * topLevelAt(const QPoint &point) const override
Find a top level window taking the flags of ChildWindowFromPointEx.
HMONITOR handle() const override
static QWindowsTheme * instance()
static QWindowsWindowClassRegistry * instance()
static QDpi deviceDPI(HDC hdc)
static WindowsScreenDataList monitorData()
static std::vector< DISPLAYCONFIG_PATH_INFO > getPathInfo(const MONITORINFOEX &viewInfo)
static void moveToVirtualScreen(QWindow *w, const QScreen *newScreen)
static void setMonitorDataFromSetupApi(QWindowsScreenData &data, const std::vector< DISPLAYCONFIG_PATH_INFO > &pathGroup)
static int indexOfMonitor(const QWindowsScreenManager::WindowsScreenList &screens, const QString &deviceName)
static bool monitorData(HMONITOR hMonitor, QWindowsScreenData *data)
static QDpi monitorDPI(HMONITOR hMonitor)