diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index e7bd2b8358..e966d7962f 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -2526,11 +2526,16 @@ void QGuiApplicationPrivate::processWindowScreenChangedEvent(QWindowSystemInterf else // Fall back to default behavior, and try to find some appropriate screen topLevelWindow->setScreen(nullptr); } - // we may have changed scaling, so trigger resize event if needed + + // We may have changed scaling; trigger resize event if needed, + // except on Windows, where we send resize events during WM_DPICHANGED + // event handling. FIXME: unify DPI change handling across all platforms. +#ifndef Q_OS_WIN if (window->handle()) { QWindowSystemInterfacePrivate::GeometryChangeEvent gce(window, QHighDpi::fromNativePixels(window->handle()->geometry(), window)); processGeometryChangeEvent(&gce); } +#endif } } diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index f24ab02b87..96abd046fb 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -1088,27 +1088,6 @@ static inline QWindowsInputContext *windowsInputContext() return qobject_cast(QWindowsIntegration::instance()->inputContext()); } - -// Child windows, fixed-size windows or pop-ups and similar should not be resized -static inline bool resizeOnDpiChanged(const QWindow *w) -{ - bool result = false; - if (w->isTopLevel()) { - switch (w->type()) { - case Qt::Window: - case Qt::Dialog: - case Qt::Sheet: - case Qt::Drawer: - case Qt::Tool: - result = !w->flags().testFlag(Qt::MSWindowsFixedSizeDialogHint); - break; - default: - break; - } - } - return result; -} - bool QWindowsContext::shouldHaveNonClientDpiScaling(const QWindow *window) { // DPI aware V2 processes always have NonClientDpiScaling enabled. @@ -1477,26 +1456,30 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, case QtWindows::DpiChangedEvent: { const UINT dpi = HIWORD(wParam); + const qreal scale = qreal(dpi) / qreal(platformWindow->savedDpi()); platformWindow->setSavedDpi(dpi); - // Try to apply the suggested size first and then notify ScreenChanged - // so that the resize event sent from QGuiApplication incorporates it - // WM_DPICHANGED is sent with a size that avoids resize loops (by - // snapping back to the previous screen, see QTBUG-65580). - const bool doResize = resizeOnDpiChanged(platformWindow->window()); - if (doResize) { - platformWindow->setFlag(QWindowsWindow::WithinDpiChanged); - platformWindow->updateFullFrameMargins(); - const auto prcNewWindow = reinterpret_cast(lParam); - qCDebug(lcQpaWindows) << __FUNCTION__ << "WM_DPICHANGED" - << platformWindow->window() << *prcNewWindow; - SetWindowPos(hwnd, nullptr, prcNewWindow->left, prcNewWindow->top, - prcNewWindow->right - prcNewWindow->left, - prcNewWindow->bottom - prcNewWindow->top, SWP_NOZORDER | SWP_NOACTIVATE); - platformWindow->clearFlag(QWindowsWindow::WithinDpiChanged); - } + // Send screen change first, so that the new sceen is set during any following resize platformWindow->checkForScreenChanged(QWindowsWindow::FromDpiChange); - return doResize; + + // Apply the suggested window geometry to the native window. This will make + // sure the window tracks the mouse cursor during screen change, and also + // that the window size is scaled according to the DPI change. + platformWindow->updateFullFrameMargins(); + const auto prcNewWindow = reinterpret_cast(lParam); + SetWindowPos(hwnd, nullptr, prcNewWindow->left, prcNewWindow->top, + prcNewWindow->right - prcNewWindow->left, + prcNewWindow->bottom - prcNewWindow->top, SWP_NOZORDER | SWP_NOACTIVATE); + + // Scale child QPlatformWindow size. Windows sends WM_DPICHANGE to top-level windows only. + for (QWindow *childWindow : platformWindow->window()->findChildren()) { + QWindowsWindow *platformChildWindow = static_cast(childWindow->handle()); + QRect currentGeometry = platformChildWindow->geometry(); + QRect scaledGeometry = QRect(currentGeometry.topLeft() * scale, currentGeometry.size() * scale); + platformChildWindow->setGeometry(scaledGeometry); + } + + return true; } #if QT_CONFIG(sessionmanager) case QtWindows::QueryEndSessionApplicationEvent: { diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index e16b3e7b5a..38e42a6282 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -1999,10 +1999,6 @@ void QWindowsWindow::handleGeometryChange() { const QRect previousGeometry = m_data.geometry; m_data.geometry = geometry_sys(); - if (testFlag(WithinDpiChanged) - && QWindowsContext::instance()->screenManager().screenForHwnd(m_data.hwnd) != screen()) { - return; // QGuiApplication will send resize when screen actually changes - } QWindowSystemInterface::handleGeometryChange(window(), m_data.geometry); // QTBUG-32121: OpenGL/normal windows (with exception of ANGLE // which we no longer support in Qt 6) do not receive expose @@ -2699,11 +2695,6 @@ static int getBorderWidth(const QPlatformScreen *screen) void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const { - // We don't apply the min/max size hint as we change the dpi, because we did not adjust the - // QScreen of the window yet so we don't have the min/max with the right ratio - if (!testFlag(QWindowsWindow::WithinDpiChanged)) - QWindowsGeometryHint::applyToMinMaxInfo(window(), fullFrameMargins(), mmi); - // This block fixes QTBUG-8361, QTBUG-4362: Frameless/title-less windows shouldn't cover the // taskbar when maximized if ((testFlag(WithinMaximize) || window()->windowStates().testFlag(Qt::WindowMinimized)) diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index 73b3b81f7f..ea170aeee1 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -235,11 +235,10 @@ public: MaximizeToFullScreen = 0x80000, Compositing = 0x100000, HasBorderInFullScreen = 0x200000, - WithinDpiChanged = 0x400000, - VulkanSurface = 0x800000, - ResizeMoveActive = 0x1000000, - DisableNonClientScaling = 0x2000000, - Direct3DSurface = 0x4000000 + VulkanSurface = 0x400000, + ResizeMoveActive = 0x800000, + DisableNonClientScaling = 0x1000000, + Direct3DSurface = 0x2000000 }; QWindowsWindow(QWindow *window, const QWindowsWindowData &data);