12#include <QtCore/qt_windows.h>
14#include <QtCore/qsettings.h>
15#include <QtGui/qpixmap.h>
16#include <QtGui/qguiapplication.h>
17#include <qpa/qwindowsysteminterface.h>
18#include <QtCore/private/qsystemerror_p.h>
19#include <QtGui/private/qedidparser_p.h>
20#include <private/qhighdpiscaling_p.h>
21#include <private/qwindowsfontdatabasebase_p.h>
22#include <private/qpixmap_win_p.h>
23#include <private/quniquehandle_p.h>
25#include <QtGui/qscreen.h>
27#include <QtCore/qdebug.h>
34#include <shellscalingapi.h>
38using namespace Qt::StringLiterals;
42 return QDpi(GetDeviceCaps(hdc, LOGPIXELSX), GetDeviceCaps(hdc, LOGPIXELSY));
49 if (SUCCEEDED(GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY)))
50 return QDpi(dpiX, dpiY);
57 std::vector<DISPLAYCONFIG_PATH_INFO> pathInfos;
58 std::vector<DISPLAYCONFIG_MODE_INFO> modeInfos;
62 UINT32 numPathArrayElements;
63 UINT32 numModeInfoArrayElements;
68 if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &numPathArrayElements,
69 &numModeInfoArrayElements) != ERROR_SUCCESS) {
72 pathInfos.resize(numPathArrayElements);
73 modeInfos.resize(numModeInfoArrayElements);
74 result = QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &numPathArrayElements, pathInfos.data(),
75 &numModeInfoArrayElements, modeInfos.data(),
nullptr);
76 }
while (result == ERROR_INSUFFICIENT_BUFFER);
78 if (result != ERROR_SUCCESS)
83 std::remove_if(pathInfos.begin(), pathInfos.end(), [&](
const auto &path) ->
bool {
84 DISPLAYCONFIG_SOURCE_DEVICE_NAME deviceName;
85 deviceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
86 deviceName.header.size =
sizeof(DISPLAYCONFIG_SOURCE_DEVICE_NAME);
87 deviceName.header.adapterId = path.sourceInfo.adapterId;
88 deviceName.header.id = path.sourceInfo.id;
89 if (DisplayConfigGetDeviceInfo(&deviceName.header) == ERROR_SUCCESS) {
90 return wcscmp(viewInfo.szDevice, deviceName.viewGdiDeviceName) != 0;
95 pathInfos.erase(discardThese, pathInfos.end());
102static float getMonitorSDRWhiteLevel(DISPLAYCONFIG_PATH_TARGET_INFO *targetInfo)
104 const float defaultSdrWhiteLevel = 200.0;
106 return defaultSdrWhiteLevel;
108 DISPLAYCONFIG_SDR_WHITE_LEVEL whiteLevel = {};
109 whiteLevel.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL;
110 whiteLevel.header.size =
sizeof(DISPLAYCONFIG_SDR_WHITE_LEVEL);
111 whiteLevel.header.adapterId = targetInfo->adapterId;
112 whiteLevel.header.id = targetInfo->id;
113 if (DisplayConfigGetDeviceInfo(&whiteLevel.header) != ERROR_SUCCESS)
114 return defaultSdrWhiteLevel;
115 return whiteLevel.SDRWhiteLevel * 80.0 / 1000.0;
119using WindowsScreenDataList = QList<QWindowsScreenData>;
123struct DiRegKeyHandleTraits
126 static Type invalidValue()
noexcept
129 return reinterpret_cast<HKEY>(INVALID_HANDLE_VALUE);
131 static bool close(Type handle)
noexcept {
return RegCloseKey(handle) == ERROR_SUCCESS; }
134using DiRegKeyHandle = QUniqueHandle<DiRegKeyHandleTraits>;
136struct DevInfoHandleTraits
138 using Type = HDEVINFO;
139 static Type invalidValue()
noexcept
141 return reinterpret_cast<HDEVINFO>(INVALID_HANDLE_VALUE);
143 static bool close(Type handle)
noexcept {
return SetupDiDestroyDeviceInfoList(handle) == TRUE; }
146using DevInfoHandle = QUniqueHandle<DevInfoHandleTraits>;
151 const std::vector<DISPLAYCONFIG_PATH_INFO> &pathGroup)
153 if (pathGroup.empty()) {
159 DISPLAYCONFIG_TARGET_DEVICE_NAME deviceName = {};
160 deviceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
161 deviceName.header.size =
sizeof(DISPLAYCONFIG_TARGET_DEVICE_NAME);
163 deviceName.header.adapterId = pathGroup[0].targetInfo.adapterId;
164 deviceName.header.id = pathGroup[0].targetInfo.id;
165 if (DisplayConfigGetDeviceInfo(&deviceName.header) == ERROR_SUCCESS) {
166 data.devicePath = QString::fromWCharArray(deviceName.monitorDevicePath);
168 qCWarning(lcQpaScreen)
169 << u"Unable to get device information for %1:"_s.arg(pathGroup[0].targetInfo.id)
170 << QSystemError::windowsString();
176 QStringList manufacturers;
178 QStringList serialNumbers;
180 for (
const auto &path : pathGroup) {
181 DISPLAYCONFIG_TARGET_DEVICE_NAME deviceName = {};
182 deviceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
183 deviceName.header.size =
sizeof(DISPLAYCONFIG_TARGET_DEVICE_NAME);
184 deviceName.header.adapterId = path.targetInfo.adapterId;
185 deviceName.header.id = path.targetInfo.id;
186 if (DisplayConfigGetDeviceInfo(&deviceName.header) != ERROR_SUCCESS) {
187 qCWarning(lcQpaScreen)
188 << u"Unable to get device information for %1:"_s.arg(path.targetInfo.id)
189 << QSystemError::windowsString();
194 constexpr GUID GUID_DEVINTERFACE_MONITOR = {
195 0xe6f07b5f, 0xee97, 0x4a90, { 0xb0, 0x76, 0x33, 0xf5, 0x7b, 0xf4, 0xea, 0xa7 }
197 const DevInfoHandle devInfo{ SetupDiGetClassDevs(
198 &GUID_DEVINTERFACE_MONITOR,
nullptr,
nullptr, DIGCF_DEVICEINTERFACE) };
200 if (!devInfo.isValid())
203 SP_DEVICE_INTERFACE_DATA deviceInterfaceData{};
204 deviceInterfaceData.cbSize =
sizeof(deviceInterfaceData);
206 if (!SetupDiOpenDeviceInterfaceW(devInfo.get(), deviceName.monitorDevicePath, DIODI_NO_ADD,
207 &deviceInterfaceData)) {
208 qCWarning(lcQpaScreen)
209 << u"Unable to open monitor interface to %1:"_s.arg(data.deviceName)
210 << QSystemError::windowsString();
214 DWORD requiredSize{ 0 };
215 if (SetupDiGetDeviceInterfaceDetailW(devInfo.get(), &deviceInterfaceData,
nullptr, 0,
216 &requiredSize,
nullptr)
217 || GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
221 const std::unique_ptr<std::byte[]> storage(
new std::byte[requiredSize]);
222 auto *devicePath =
reinterpret_cast<SP_DEVICE_INTERFACE_DETAIL_DATA_W *>(storage.get());
223 devicePath->cbSize =
sizeof(std::remove_pointer_t<
decltype(devicePath)>);
224 SP_DEVINFO_DATA deviceInfoData{};
225 deviceInfoData.cbSize =
sizeof(deviceInfoData);
226 if (!SetupDiGetDeviceInterfaceDetailW(devInfo.get(), &deviceInterfaceData, devicePath,
227 requiredSize,
nullptr, &deviceInfoData)) {
228 qCDebug(lcQpaScreen) << u"Unable to get monitor metadata for %1:"_s.arg(data.deviceName)
229 << QSystemError::windowsString();
233 const DiRegKeyHandle edidRegistryKey{ SetupDiOpenDevRegKey(
234 devInfo.get(), &deviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ) };
236 if (!edidRegistryKey.isValid())
239 DWORD edidDataSize{ 0 };
240 if (RegQueryValueExW(edidRegistryKey.get(), L"EDID",
nullptr,
nullptr,
nullptr,
247 edidData.resize(edidDataSize);
249 if (RegQueryValueExW(edidRegistryKey.get(), L"EDID",
nullptr,
nullptr,
250 reinterpret_cast<
unsigned char *>(edidData.data()), &edidDataSize)
252 qCDebug(lcQpaScreen) << u"Unable to get EDID from the Registry for %1:"_s.arg(
254 << QSystemError::windowsString();
260 if (!edid.parse(edidData)) {
261 qCDebug(lcQpaScreen) <<
"Invalid EDID blob for" << data.deviceName;
267 names << QString::fromWCharArray(deviceName.monitorFriendlyDeviceName);
268 manufacturers << edid.manufacturer;
269 models << edid.model;
270 serialNumbers << edid.serialNumber;
273 data.name = names.join(u"|"_s);
274 data.manufacturer = manufacturers.join(u"|"_s);
275 data.model = models.join(u"|"_s);
276 data.serialNumber = serialNumbers.join(u"|"_s);
279static bool monitorData(HMONITOR hMonitor, QWindowsScreenData *data)
282 memset(&info, 0,
sizeof(MONITORINFOEX));
283 info.cbSize =
sizeof(MONITORINFOEX);
284 if (GetMonitorInfo(hMonitor, &info) == FALSE)
287 data->hMonitor = hMonitor;
288 data->geometry = QRect(
QPoint(info.rcMonitor.left, info.rcMonitor.top),
QPoint(info.rcMonitor.right - 1, info.rcMonitor.bottom - 1));
289 data->availableGeometry = QRect(
QPoint(info.rcWork.left, info.rcWork.top),
QPoint(info.rcWork.right - 1, info.rcWork.bottom - 1));
290 data->deviceName = QString::fromWCharArray(info.szDevice);
291 const auto pathGroup = getPathInfo(info);
292 if (!pathGroup.empty()) {
293 setMonitorDataFromSetupApi(*data, pathGroup);
295 if (data->name.isEmpty())
296 data->name = data->deviceName;
297 if (data->deviceName == u"WinDisc") {
298 data->flags |= QWindowsScreenData::LockScreen;
300 if (
const HDC hdc = CreateDC(info.szDevice,
nullptr,
nullptr,
nullptr)) {
301 const QDpi dpi = monitorDPI(hMonitor);
302 data->dpi = dpi.first > 0 ? dpi : deviceDPI(hdc);
303 data->depth = GetDeviceCaps(hdc, BITSPIXEL);
304 data->format = data->depth == 16 ? QImage::Format_RGB16 : QImage::Format_RGB32;
305 data->physicalSizeMM = QSizeF(GetDeviceCaps(hdc, HORZSIZE), GetDeviceCaps(hdc, VERTSIZE));
306 const int refreshRate = GetDeviceCaps(hdc, VREFRESH);
308 data->refreshRateHz = refreshRate;
311 qWarning(
"%s: Unable to obtain handle for monitor '%s', defaulting to %g DPI.",
312 __FUNCTION__, qPrintable(data->deviceName),
319 if (!pathGroup.empty()) {
321 const auto &pathInfo = pathGroup[0];
322 switch (pathInfo.targetInfo.rotation) {
323 case DISPLAYCONFIG_ROTATION_IDENTITY:
324 data->orientation = Qt::LandscapeOrientation;
326 case DISPLAYCONFIG_ROTATION_ROTATE90:
327 data->orientation = Qt::PortraitOrientation;
329 case DISPLAYCONFIG_ROTATION_ROTATE180:
330 data->orientation = Qt::InvertedLandscapeOrientation;
332 case DISPLAYCONFIG_ROTATION_ROTATE270:
333 data->orientation = Qt::InvertedPortraitOrientation;
335 case DISPLAYCONFIG_ROTATION_FORCE_UINT32:
339 if (pathInfo.targetInfo.refreshRate.Numerator && pathInfo.targetInfo.refreshRate.Denominator)
340 data->refreshRateHz =
static_cast<qreal>(pathInfo.targetInfo.refreshRate.Numerator)
341 / pathInfo.targetInfo.refreshRate.Denominator;
343 data->orientation = data->geometry.height() > data->geometry.width()
344 ? Qt::PortraitOrientation
345 : Qt::LandscapeOrientation;
349 data->flags |= QWindowsScreenData::VirtualDesktop;
350 if (info.dwFlags & MONITORINFOF_PRIMARY)
351 data->flags |= QWindowsScreenData::PrimaryScreen;
356BOOL QT_WIN_CALLBACK monitorEnumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM p)
358 QWindowsScreenData data;
359 if (monitorData(hMonitor, &data)) {
360 auto *result =
reinterpret_cast<WindowsScreenDataList *>(p);
361 auto it = std::find_if(result->rbegin(), result->rend(),
362 [&data](QWindowsScreenData i){
return i.name == data.name; });
363 if (it != result->rend()) {
364 int previousIndex = 1;
365 if (it->deviceIndex.has_value())
366 previousIndex = it->deviceIndex.value();
368 (*it).deviceIndex = 1;
369 data.deviceIndex = previousIndex + 1;
376 if (data.flags & QWindowsScreenData::PrimaryScreen)
377 result->prepend(data);
379 result->append(data);
386 WindowsScreenDataList result;
387 EnumDisplayMonitors(
nullptr,
nullptr, monitorEnumCallback,
reinterpret_cast<LPARAM>(&result));
391#ifndef QT_NO_DEBUG_STREAM
392static QDebug operator<<(QDebug dbg,
const QWindowsScreenData &d)
394 QDebugStateSaver saver(dbg);
397 dbg <<
"Screen \"" << d.name <<
"\" " << d.geometry.width() <<
'x' << d.geometry.height() <<
'+'
398 << d.geometry.x() <<
'+' << d.geometry.y() <<
" avail: " << d.availableGeometry.width()
399 <<
'x' << d.availableGeometry.height() <<
'+' << d.availableGeometry.x() <<
'+'
400 << d.availableGeometry.y() <<
" physical: " << d.physicalSizeMM.width() <<
'x'
401 << d.physicalSizeMM.height() <<
" DPI: " << d.dpi.first <<
'x' << d.dpi.second
402 <<
" Depth: " << d.depth <<
" Format: " << d.format <<
" hMonitor: " << d.hMonitor
403 <<
" device name: " << d.deviceName <<
" manufacturer: " << d.manufacturer
404 <<
" model: " << d.model <<
" serial number: " << d.serialNumber;
405 if (d.flags & QWindowsScreenData::PrimaryScreen)
407 if (d.flags & QWindowsScreenData::VirtualDesktop)
408 dbg <<
" virtual desktop";
409 if (d.flags & QWindowsScreenData::LockScreen)
410 dbg <<
" lock screen";
416
417
418
419
420
425 , m_cursor(
new QWindowsCursor(
this))
432 return m_data.deviceIndex.has_value()
433 ? (u"%1 (%2)"_s).arg(m_data.name, QString::number(m_data.deviceIndex.value()))
442 HWND hwnd =
reinterpret_cast<HWND>(window);
445 GetClientRect(hwnd, &r);
446 windowSize = QSize(r.right - r.left, r.bottom - r.top);
450 hwnd = GetDesktopWindow();
451 const QRect screenGeometry = geometry();
452 windowSize = screenGeometry.size();
460 MONITORINFOEX info = {};
461 info.cbSize =
sizeof(MONITORINFOEX);
462 if (GetMonitorInfo(handle(), &info)) {
464 dm.dmSize =
sizeof(dm);
465 if (EnumDisplaySettings(info.szDevice, ENUM_CURRENT_SETTINGS, &dm)) {
466 qreal scale =
static_cast<qreal>(dm.dmPelsWidth) / windowSize.width();
467 x =
static_cast<
int>(
static_cast<qreal>(x) * scale);
468 y =
static_cast<
int>(
static_cast<qreal>(y) * scale);
469 windowSize = QSize(dm.dmPelsWidth, dm.dmPelsHeight);
473 x += screenGeometry.x();
474 y += screenGeometry.y();
478 width = windowSize.width() - xIn;
480 height = windowSize.height() - yIn;
483 HDC display_dc = GetDC(
nullptr);
484 HDC bitmap_dc = CreateCompatibleDC(display_dc);
485 HBITMAP bitmap = CreateCompatibleBitmap(display_dc, width, height);
486 HGDIOBJ null_bitmap = SelectObject(bitmap_dc, bitmap);
489 HDC window_dc = GetDC(hwnd);
490 BitBlt(bitmap_dc, 0, 0, width, height, window_dc, x, y, SRCCOPY | CAPTUREBLT);
493 ReleaseDC(hwnd, window_dc);
494 SelectObject(bitmap_dc, null_bitmap);
497 const QPixmap pixmap = qt_pixmapFromWinHBITMAP(bitmap);
499 DeleteObject(bitmap);
500 ReleaseDC(
nullptr, display_dc);
506
507
511 QWindow *result =
nullptr;
512 if (QWindow *child = QWindowsScreen::windowAt(point, CWP_SKIPINVISIBLE))
513 result = QWindowsWindow::topLevelOf(child);
515 qCDebug(lcQpaScreen) <<
__FUNCTION__ << point << result;
521 QWindow* result =
nullptr;
523 findPlatformWindowAt(GetDesktopWindow(), screenPoint, flags))
524 result = bw->window();
526 qCDebug(lcQpaScreen) <<
__FUNCTION__ << screenPoint <<
" returns " << result;
531
532
533
534
535
539 QList<QPlatformScreen *> result;
540 if (m_data.flags & QWindowsScreenData::VirtualDesktop) {
541 const QWindowsScreenManager::WindowsScreenList screens
543 for (QWindowsScreen *screen : screens) {
544 if (screen->data().flags & QWindowsScreenData::VirtualDesktop)
545 result.push_back(screen);
554
555
559 m_data.physicalSizeMM = newData.physicalSizeMM;
561 if (m_data.hMonitor != newData.hMonitor) {
562 qCDebug(lcQpaScreen) <<
"Monitor" << m_data.name
563 <<
"has had its hMonitor handle changed from"
564 << m_data.hMonitor <<
"to" << newData.hMonitor;
565 m_data.hMonitor = newData.hMonitor;
570 const bool geometryChanged = m_data.geometry != newData.geometry
571 || m_data.availableGeometry != newData.availableGeometry;
572 const bool dpiChanged = !qFuzzyCompare(m_data.dpi.first, newData.dpi.first)
573 || !qFuzzyCompare(m_data.dpi.second, newData.dpi.second);
574 const bool orientationChanged = m_data.orientation != newData.orientation;
575 const bool primaryChanged = (newData.flags & QWindowsScreenData::PrimaryScreen)
576 && !(m_data.flags & QWindowsScreenData::PrimaryScreen);
577 const bool refreshRateChanged = m_data.refreshRateHz != newData.refreshRateHz;
578 m_data.dpi = newData.dpi;
579 m_data.orientation = newData.orientation;
580 m_data.geometry = newData.geometry;
581 m_data.availableGeometry = newData.availableGeometry;
582 m_data.flags = (m_data.flags & ~QWindowsScreenData::PrimaryScreen)
583 | (newData.flags & QWindowsScreenData::PrimaryScreen);
584 m_data.refreshRateHz = newData.refreshRateHz;
587 QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(screen(),
591 if (orientationChanged)
592 QWindowSystemInterface::handleScreenOrientationChange(screen(), newData.orientation);
593 if (geometryChanged) {
594 QWindowSystemInterface::handleScreenGeometryChange(screen(),
595 newData.geometry, newData.availableGeometry);
598 QWindowSystemInterface::handlePrimaryScreenChanged(
this);
600 if (refreshRateChanged)
601 QWindowSystemInterface::handleScreenRefreshRateChange(screen(), newData.refreshRateHz);
606 return m_data.hMonitor;
612 const auto siblings = screen->virtualSiblings();
613 for (
const QPlatformScreen *sibling : siblings)
614 result |= sibling->geometry();
621 ORIENTATION_PREFERENCE orientationPreference = ORIENTATION_PREFERENCE_NONE;
623 case Qt::PrimaryOrientation:
625 case Qt::PortraitOrientation:
626 orientationPreference = ORIENTATION_PREFERENCE_PORTRAIT;
628 case Qt::LandscapeOrientation:
629 orientationPreference = ORIENTATION_PREFERENCE_LANDSCAPE;
631 case Qt::InvertedPortraitOrientation:
632 orientationPreference = ORIENTATION_PREFERENCE_PORTRAIT_FLIPPED;
634 case Qt::InvertedLandscapeOrientation:
635 orientationPreference = ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED;
638 result = SetDisplayAutoRotationPreferences(orientationPreference);
644 Qt::ScreenOrientation result = Qt::PrimaryOrientation;
645 ORIENTATION_PREFERENCE orientationPreference = ORIENTATION_PREFERENCE_NONE;
646 if (GetDisplayAutoRotationPreferences(&orientationPreference)) {
647 switch (orientationPreference) {
648 case ORIENTATION_PREFERENCE_NONE:
650 case ORIENTATION_PREFERENCE_LANDSCAPE:
651 result = Qt::LandscapeOrientation;
653 case ORIENTATION_PREFERENCE_PORTRAIT:
654 result = Qt::PortraitOrientation;
656 case ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED:
657 result = Qt::InvertedLandscapeOrientation;
659 case ORIENTATION_PREFERENCE_PORTRAIT_FLIPPED:
660 result = Qt::InvertedPortraitOrientation;
668
669
672 QPlatformScreen::SubpixelAntialiasingType type = QPlatformScreen::subpixelAntialiasingTypeHint();
673 if (type == QPlatformScreen::Subpixel_None) {
674 QSettings settings(R"(HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Avalon.Graphics\DISPLAY1)"_L1,
675 QSettings::NativeFormat);
676 int registryValue = settings.value(
"PixelStructure"_L1, -1).toInt();
677 switch (registryValue) {
679 type = QPlatformScreen::Subpixel_None;
682 type = QPlatformScreen::Subpixel_RGB;
685 type = QPlatformScreen::Subpixel_BGR;
688 type = QPlatformScreen::Subpixel_None;
696
697
698
699
700
701
702
703
704
706LRESULT QT_WIN_CALLBACK qDisplayChangeObserverWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
708 if (message == WM_DISPLAYCHANGE) {
709 qCDebug(lcQpaScreen) <<
"Handling WM_DISPLAYCHANGE";
710 if (QWindowsTheme *t = QWindowsTheme::instance())
712 QWindowsWindow::displayChanged();
713 if (
auto *context = QWindowsContext::instance())
714 context->screenManager().handleScreenChanges();
717 return DefWindowProc(hwnd, message, wParam, lParam);
724 qCDebug(lcQpaScreen) <<
"Initializing screen manager";
727 "ScreenChangeObserverWindow"_L1,
728 qDisplayChangeObserverWndProc);
732 m_displayChangeObserver = CreateWindowEx(0,
reinterpret_cast<LPCWSTR>(className.utf16()),
733 nullptr, WS_TILED, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
734 nullptr,
nullptr, GetModuleHandle(
nullptr),
nullptr);
735 Q_ASSERT(m_displayChangeObserver);
737 qCDebug(lcQpaScreen) <<
"Created display change observer" << m_displayChangeObserver;
744 qCDebug(lcQpaScreen) <<
"Destroying display change observer" << m_displayChangeObserver;
745 DestroyWindow(m_displayChangeObserver);
746 m_displayChangeObserver =
nullptr;
756static inline int indexOfMonitor(
const QWindowsScreenManager::WindowsScreenList &screens,
757 const QString &deviceName)
759 for (
int i= 0; i < screens.size(); ++i)
760 if (screens.at(i)->data().deviceName == deviceName)
766 const QString &deviceName)
768 for (
int i = 0; i < screenData.size(); ++i)
769 if (screenData.at(i).deviceName == deviceName)
777 QRect geometry = w->geometry();
778 const QRect oldScreenGeometry = w->screen()->geometry();
779 const QRect newScreenGeometry = newScreen->geometry();
780 QPoint relativePosition = geometry.topLeft() - oldScreenGeometry.topLeft();
781 if (oldScreenGeometry.size() != newScreenGeometry.size()) {
783 qreal(
QPoint(newScreenGeometry.width(), newScreenGeometry.height()).manhattanLength()) /
784 qreal(
QPoint(oldScreenGeometry.width(), oldScreenGeometry.height()).manhattanLength());
785 relativePosition = (QPointF(relativePosition) * factor).toPoint();
787 geometry.moveTopLeft(relativePosition);
788 w->setGeometry(geometry);
794 m_screens.push_back(newScreen);
795 QWindowSystemInterface::handleScreenAdded(newScreen,
796 screenData.flags & QWindowsScreenData::PrimaryScreen);
797 qCDebug(lcQpaScreen) <<
"New Monitor: " << screenData;
804 const auto allWindows = QGuiApplication::allWindows();
805 for (QWindow *w : allWindows) {
806 if (w->isVisible() && w->handle()) {
807 if (QWindowsWindow *window = QWindowsWindow::windowsWindowOf(w))
808 window->checkForScreenChanged(QWindowsWindow::ScreenChangeMode::FromScreenAdded);
815 qCDebug(lcQpaScreen) <<
"Removing Monitor:" << m_screens.at(index)->data();
816 QPlatformScreen *platformScreen = m_screens.takeAt(index);
817 QScreen *screen = platformScreen->screen();
818 QScreen *primaryScreen = QGuiApplication::primaryScreen();
826 if (screen != primaryScreen) {
827 unsigned movedWindowCount = 0;
828 const QWindowList tlws = QGuiApplication::topLevelWindows();
829 for (QWindow *w : tlws) {
830 if (w->screen() == screen && w->handle()) {
831 if (w->isVisible() && w->windowState() != Qt::WindowMinimized
832 && (QWindowsWindow::baseWindowOf(w)->exStyle() & WS_EX_TOOLWINDOW)) {
833 moveToVirtualScreen(w, primaryScreen);
835 QWindowSystemInterface::handleWindowScreenChanged<QWindowSystemInterface::SynchronousDelivery>(w, primaryScreen);
840 if (movedWindowCount)
841 QWindowSystemInterface::flushWindowSystemEvents();
843 QWindowSystemInterface::handleScreenRemoved(platformScreen);
847
848
849
854 const WindowsScreenDataList newDataList = monitorData();
855 const bool lockScreen = newDataList.size() == 1 && (newDataList.front().flags & QWindowsScreenData::LockScreen);
856 bool primaryScreenChanged =
false;
857 for (
const QWindowsScreenData &newData : newDataList) {
858 const int existingIndex = indexOfMonitor(m_screens, newData.deviceName);
859 if (existingIndex != -1) {
860 m_screens.at(existingIndex)->handleChanges(newData);
861 if (existingIndex == 0)
862 primaryScreenChanged =
true;
870 for (
int i = m_screens.size() - 1; i >= 0; --i) {
871 if (indexOfMonitor(newDataList, m_screens.at(i)->data().deviceName) == -1)
875 if (primaryScreenChanged) {
885 while (!m_screens.isEmpty())
886 QWindowSystemInterface::handleScreenRemoved(m_screens.takeLast());
891 for (QWindowsScreen *scr : m_screens) {
892 if (scr->geometry().contains(p))
900 if (hMonitor ==
nullptr)
903 std::find_if(m_screens.cbegin(), m_screens.cend(),
904 [hMonitor](
const QWindowsScreen *s)
906 return s->data().hMonitor == hMonitor
907 && (s->data().flags & QWindowsScreenData::VirtualDesktop) != 0;
909 return it != m_screens.cend() ? *it :
nullptr;
914 HMONITOR hMonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONULL);
915 return screenForMonitor(hMonitor);
922 HMONITOR hMonitor = MonitorFromRect(rect, MONITOR_DEFAULTTONULL);
923 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)