From a398961e53145b17e2cabc751923f4e3fd840501 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Wed, 29 Sep 2021 11:42:43 +0200 Subject: Fix programatic geometry change to different DPI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The event flow for programatic window geometry change (e.g. from MoveWindow()) differs from user-interactive geometry change: We still get WM_DPICHANGED, but this event is not preceded by WM_GETDPISCALEDSIZE, so we don’t get to override the window size. However, Qt has already scaled the window size for the new DPI in this case (the scaled size is provided to QWindowsWindow::setGeometry()), so we can omit making second native set-geometry call. Change-Id: Ia7d42d7fee49adf757e7fe75d77f1731405ad519 Reviewed-by: Tor Arne Vestbø (cherry picked from commit 81707951fe251d9c9074a5b8ca6211900a23d235) Reviewed-by: Qt Cherry-pick Bot --- src/plugins/platforms/windows/qwindowswindow.cpp | 34 ++++++++++++++++++------ src/plugins/platforms/windows/qwindowswindow.h | 1 + 2 files changed, 27 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index bbe19e4fcc..f167847a59 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -1345,6 +1345,7 @@ void QWindowCreationContext::applyToMinMaxInfo(MINMAXINFO *mmi) const const char *QWindowsWindow::embeddedNativeParentHandleProperty = "_q_embedded_native_parent_handle"; const char *QWindowsWindow::hasBorderInFullScreenProperty = "_q_has_border_in_fullscreen"; bool QWindowsWindow::m_borderInFullScreenDefault = false; +bool QWindowsWindow::m_inSetgeometry = false; QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data) : QWindowsBaseWindow(aWindow), @@ -1842,14 +1843,29 @@ void QWindowsWindow::handleDpiChanged(HWND hwnd, WPARAM wParam, LPARAM lParam) // Send screen change first, so that the new sceen is set during any following resize checkForScreenChanged(QWindowsWindow::FromDpiChange); - // 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. - 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); + // We get WM_DPICHANGED in one of two situations: + // + // 1. The DPI change is a "spontaneous" DPI change as a result of e.g. + // the user dragging the window to a new screen. In this case Windows + // first sends WM_GETDPISCALEDSIZE, where we set the new window size, + // followed by this event where we 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. + // + // 2. The DPI change is a result of a setGeometry() call. In this case + // Qt has already scaled the window size for the new DPI. Further, Windows + // does not call WM_GETDPISCALEDSIZE, and also applies its own scaling + // to the already scaled window size. Since there is no need to set the + // window geometry again, and the provided geometry is incorrect, we omit + // making the SetWindowPos() call. + if (!m_inSetgeometry) { + 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 : window()->findChildren()) { @@ -1930,6 +1946,8 @@ static QString msgUnableToSetGeometry(const QWindowsWindow *platformWindow, void QWindowsWindow::setGeometry(const QRect &rectIn) { + QBoolBlocker b(m_inSetgeometry); + QRect rect = rectIn; // This means it is a call from QWindow::setFramePosition() and // the coordinates include the frame (size is still the contents rectangle). diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index 14c5f47853..205a02a30d 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -417,6 +417,7 @@ private: VkSurfaceKHR m_vkSurface = VK_NULL_HANDLE; #endif static bool m_borderInFullScreenDefault; + static bool m_inSetgeometry; }; #ifndef QT_NO_DEBUG_STREAM -- cgit v1.2.3