11#include <QtCore/qt_windows.h>
13#include <QtCore/qsettings.h>
14#include <QtGui/qpixmap.h>
15#include <QtGui/qguiapplication.h>
16#include <qpa/qwindowsysteminterface.h>
17#include <QtCore/private/qsystemerror_p.h>
18#include <QtGui/private/qedidparser_p.h>
19#include <private/qhighdpiscaling_p.h>
20#include <private/qwindowsfontdatabasebase_p.h>
21#include <private/qpixmap_win_p.h>
22#include <private/quniquehandle_p.h>
24#include <QtGui/qscreen.h>
26#include <QtCore/qdebug.h>
33#include <shellscalingapi.h>
37using namespace Qt::StringLiterals;
41 return QDpi(GetDeviceCaps(hdc, LOGPIXELSX), GetDeviceCaps(hdc, LOGPIXELSY));
48 if (SUCCEEDED(GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY)))
49 return QDpi(dpiX, dpiY);
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());
101static float getMonitorSDRWhiteLevel(DISPLAYCONFIG_PATH_TARGET_INFO *targetInfo)
103 const float defaultSdrWhiteLevel = 200.0;
105 return defaultSdrWhiteLevel;
107 DISPLAYCONFIG_SDR_WHITE_LEVEL whiteLevel = {};
108 whiteLevel.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL;
109 whiteLevel.header.size =
sizeof(DISPLAYCONFIG_SDR_WHITE_LEVEL);
110 whiteLevel.header.adapterId = targetInfo->adapterId;
111 whiteLevel.header.id = targetInfo->id;
112 if (DisplayConfigGetDeviceInfo(&whiteLevel.header) != ERROR_SUCCESS)
113 return defaultSdrWhiteLevel;
114 return whiteLevel.SDRWhiteLevel * 80.0 / 1000.0;
118using WindowsScreenDataList = QList<QWindowsScreenData>;
122struct DiRegKeyHandleTraits
125 static Type invalidValue()
noexcept
128 return reinterpret_cast<HKEY>(INVALID_HANDLE_VALUE);
130 static bool close(Type handle)
noexcept {
return RegCloseKey(handle) == ERROR_SUCCESS; }
133using DiRegKeyHandle = QUniqueHandle<DiRegKeyHandleTraits>;
135struct DevInfoHandleTraits
137 using Type = HDEVINFO;
138 static Type invalidValue()
noexcept
140 return reinterpret_cast<HDEVINFO>(INVALID_HANDLE_VALUE);
142 static bool close(Type handle)
noexcept {
return SetupDiDestroyDeviceInfoList(handle) == TRUE; }
145using DevInfoHandle = QUniqueHandle<DevInfoHandleTraits>;
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);
385 WindowsScreenDataList result;
386 EnumDisplayMonitors(
nullptr,
nullptr, monitorEnumCallback,
reinterpret_cast<LPARAM>(&result));
390#ifndef QT_NO_DEBUG_STREAM
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";
415
416
417
418
419
424 , m_cursor(
new QWindowsCursor(
this))
431 return m_data.deviceIndex.has_value()
432 ? (u"%1 (%2)"_s).arg(m_data.name, QString::number(m_data.deviceIndex.value()))
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);
485
486
490 QWindow *result =
nullptr;
491 if (QWindow *child = QWindowsScreen::windowAt(point, CWP_SKIPINVISIBLE))
492 result = QWindowsWindow::topLevelOf(child);
493 if (QWindowsContext::verbose > 1)
494 qCDebug(lcQpaScreen) <<
__FUNCTION__ << point << result;
500 QWindow* result =
nullptr;
502 findPlatformWindowAt(GetDesktopWindow(), screenPoint, flags))
503 result = bw->window();
504 if (QWindowsContext::verbose > 1)
505 qCDebug(lcQpaScreen) <<
__FUNCTION__ << screenPoint <<
" returns " << result;
510
511
512
513
514
518 QList<QPlatformScreen *> result;
519 if (m_data.flags & QWindowsScreenData::VirtualDesktop) {
520 const QWindowsScreenManager::WindowsScreenList screens
522 for (QWindowsScreen *screen : screens) {
523 if (screen->data().flags & QWindowsScreenData::VirtualDesktop)
524 result.push_back(screen);
533
534
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 const bool refreshRateChanged = m_data.refreshRateHz != newData.refreshRateHz;
557 m_data.dpi = newData.dpi;
558 m_data.orientation = newData.orientation;
559 m_data.geometry = newData.geometry;
560 m_data.availableGeometry = newData.availableGeometry;
561 m_data.flags = (m_data.flags & ~QWindowsScreenData::PrimaryScreen)
562 | (newData.flags & QWindowsScreenData::PrimaryScreen);
563 m_data.refreshRateHz = newData.refreshRateHz;
566 QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(screen(),
570 if (orientationChanged)
571 QWindowSystemInterface::handleScreenOrientationChange(screen(), newData.orientation);
572 if (geometryChanged) {
573 QWindowSystemInterface::handleScreenGeometryChange(screen(),
574 newData.geometry, newData.availableGeometry);
577 QWindowSystemInterface::handlePrimaryScreenChanged(
this);
579 if (refreshRateChanged)
580 QWindowSystemInterface::handleScreenRefreshRateChange(screen(), newData.refreshRateHz);
585 return m_data.hMonitor;
591 const auto siblings = screen->virtualSiblings();
592 for (
const QPlatformScreen *sibling : siblings)
593 result |= sibling->geometry();
600 ORIENTATION_PREFERENCE orientationPreference = ORIENTATION_PREFERENCE_NONE;
602 case Qt::PrimaryOrientation:
604 case Qt::PortraitOrientation:
605 orientationPreference = ORIENTATION_PREFERENCE_PORTRAIT;
607 case Qt::LandscapeOrientation:
608 orientationPreference = ORIENTATION_PREFERENCE_LANDSCAPE;
610 case Qt::InvertedPortraitOrientation:
611 orientationPreference = ORIENTATION_PREFERENCE_PORTRAIT_FLIPPED;
613 case Qt::InvertedLandscapeOrientation:
614 orientationPreference = ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED;
617 result = SetDisplayAutoRotationPreferences(orientationPreference);
623 Qt::ScreenOrientation result = Qt::PrimaryOrientation;
624 ORIENTATION_PREFERENCE orientationPreference = ORIENTATION_PREFERENCE_NONE;
625 if (GetDisplayAutoRotationPreferences(&orientationPreference)) {
626 switch (orientationPreference) {
627 case ORIENTATION_PREFERENCE_NONE:
629 case ORIENTATION_PREFERENCE_LANDSCAPE:
630 result = Qt::LandscapeOrientation;
632 case ORIENTATION_PREFERENCE_PORTRAIT:
633 result = Qt::PortraitOrientation;
635 case ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED:
636 result = Qt::InvertedLandscapeOrientation;
638 case ORIENTATION_PREFERENCE_PORTRAIT_FLIPPED:
639 result = Qt::InvertedPortraitOrientation;
647
648
651 QPlatformScreen::SubpixelAntialiasingType type = QPlatformScreen::subpixelAntialiasingTypeHint();
652 if (type == QPlatformScreen::Subpixel_None) {
653 QSettings settings(R"(HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Avalon.Graphics\DISPLAY1)"_L1,
654 QSettings::NativeFormat);
655 int registryValue = settings.value(
"PixelStructure"_L1, -1).toInt();
656 switch (registryValue) {
658 type = QPlatformScreen::Subpixel_None;
661 type = QPlatformScreen::Subpixel_RGB;
664 type = QPlatformScreen::Subpixel_BGR;
667 type = QPlatformScreen::Subpixel_None;
675
676
677
678
679
680
681
682
683
685LRESULT QT_WIN_CALLBACK qDisplayChangeObserverWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
687 if (message == WM_DISPLAYCHANGE) {
688 qCDebug(lcQpaScreen) <<
"Handling WM_DISPLAYCHANGE";
689 if (QWindowsTheme *t = QWindowsTheme::instance())
691 QWindowsWindow::displayChanged();
692 if (
auto *context = QWindowsContext::instance())
693 context->screenManager().handleScreenChanges();
696 return DefWindowProc(hwnd, message, wParam, lParam);
703 qCDebug(lcQpaScreen) <<
"Initializing screen manager";
705 auto className = QWindowsContext::instance()->registerWindowClass(
706 QWindowsContext::classNamePrefix() + QLatin1String(
"ScreenChangeObserverWindow"),
707 qDisplayChangeObserverWndProc);
711 m_displayChangeObserver = CreateWindowEx(0,
reinterpret_cast<LPCWSTR>(className.utf16()),
712 nullptr, WS_TILED, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
713 nullptr,
nullptr, GetModuleHandle(
nullptr),
nullptr);
714 Q_ASSERT(m_displayChangeObserver);
716 qCDebug(lcQpaScreen) <<
"Created display change observer" << m_displayChangeObserver;
723 qCDebug(lcQpaScreen) <<
"Destroying display change observer" << m_displayChangeObserver;
724 DestroyWindow(m_displayChangeObserver);
725 m_displayChangeObserver =
nullptr;
735static inline int indexOfMonitor(
const QWindowsScreenManager::WindowsScreenList &screens,
736 const QString &deviceName)
738 for (
int i= 0; i < screens.size(); ++i)
739 if (screens.at(i)->data().deviceName == deviceName)
745 const QString &deviceName)
747 for (
int i = 0; i < screenData.size(); ++i)
748 if (screenData.at(i).deviceName == deviceName)
756 QRect geometry = w->geometry();
757 const QRect oldScreenGeometry = w->screen()->geometry();
758 const QRect newScreenGeometry = newScreen->geometry();
759 QPoint relativePosition = geometry.topLeft() - oldScreenGeometry.topLeft();
760 if (oldScreenGeometry.size() != newScreenGeometry.size()) {
762 qreal(
QPoint(newScreenGeometry.width(), newScreenGeometry.height()).manhattanLength()) /
763 qreal(
QPoint(oldScreenGeometry.width(), oldScreenGeometry.height()).manhattanLength());
764 relativePosition = (QPointF(relativePosition) * factor).toPoint();
766 geometry.moveTopLeft(relativePosition);
767 w->setGeometry(geometry);
773 m_screens.push_back(newScreen);
774 QWindowSystemInterface::handleScreenAdded(newScreen,
775 screenData.flags & QWindowsScreenData::PrimaryScreen);
776 qCDebug(lcQpaScreen) <<
"New Monitor: " << screenData;
783 const auto allWindows = QGuiApplication::allWindows();
784 for (QWindow *w : allWindows) {
785 if (w->isVisible() && w->handle()) {
786 if (QWindowsWindow *window = QWindowsWindow::windowsWindowOf(w))
787 window->checkForScreenChanged(QWindowsWindow::ScreenChangeMode::FromScreenAdded);
794 qCDebug(lcQpaScreen) <<
"Removing Monitor:" << m_screens.at(index)->data();
795 QPlatformScreen *platformScreen = m_screens.takeAt(index);
796 QScreen *screen = platformScreen->screen();
797 QScreen *primaryScreen = QGuiApplication::primaryScreen();
805 if (screen != primaryScreen) {
806 unsigned movedWindowCount = 0;
807 const QWindowList tlws = QGuiApplication::topLevelWindows();
808 for (QWindow *w : tlws) {
809 if (w->screen() == screen && w->handle()) {
810 if (w->isVisible() && w->windowState() != Qt::WindowMinimized
811 && (QWindowsWindow::baseWindowOf(w)->exStyle() & WS_EX_TOOLWINDOW)) {
812 moveToVirtualScreen(w, primaryScreen);
814 QWindowSystemInterface::handleWindowScreenChanged<QWindowSystemInterface::SynchronousDelivery>(w, primaryScreen);
819 if (movedWindowCount)
820 QWindowSystemInterface::flushWindowSystemEvents();
822 QWindowSystemInterface::handleScreenRemoved(platformScreen);
826
827
828
833 const WindowsScreenDataList newDataList = monitorData();
834 const bool lockScreen = newDataList.size() == 1 && (newDataList.front().flags & QWindowsScreenData::LockScreen);
835 bool primaryScreenChanged =
false;
836 for (
const QWindowsScreenData &newData : newDataList) {
837 const int existingIndex = indexOfMonitor(m_screens, newData.deviceName);
838 if (existingIndex != -1) {
839 m_screens.at(existingIndex)->handleChanges(newData);
840 if (existingIndex == 0)
841 primaryScreenChanged =
true;
849 for (
int i = m_screens.size() - 1; i >= 0; --i) {
850 if (indexOfMonitor(newDataList, m_screens.at(i)->data().deviceName) == -1)
854 if (primaryScreenChanged) {
864 while (!m_screens.isEmpty())
865 QWindowSystemInterface::handleScreenRemoved(m_screens.takeLast());
870 for (QWindowsScreen *scr : m_screens) {
871 if (scr->geometry().contains(p))
879 if (hMonitor ==
nullptr)
882 std::find_if(m_screens.cbegin(), m_screens.cend(),
883 [hMonitor](
const QWindowsScreen *s)
885 return s->data().hMonitor == hMonitor
886 && (s->data().flags & QWindowsScreenData::VirtualDesktop) != 0;
888 return it != m_screens.cend() ? *it :
nullptr;
893 HMONITOR hMonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONULL);
894 return screenForMonitor(hMonitor);
901 HMONITOR hMonitor = MonitorFromRect(rect, MONITOR_DEFAULTTONULL);
902 return screenForMonitor(hMonitor);
\inmodule QtCore\reentrant
Singleton container for all relevant information.
QWindowsScreenManager & screenManager()
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 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)