From e336e062eff6a325ae3fa97886262b70ea5fd8bd Mon Sep 17 00:00:00 2001 From: Viktor Arvidsson Date: Mon, 31 Jan 2022 19:14:04 +0100 Subject: [PATCH] Windows QPA: Calculate window frame for frameless windows the same for all code paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we add the WS_THICKFRAME/WS_CAPTION window flags to a frameless window the return value of AdjustWindowRectEx is no longer 0. This works fine when creating the window since the version of QWindowsGeometryHint::frame used during creation checks the FramelessWindowHint, however later when the window changes screen, the screen change code checks the fullFrameMargins which uses a version of QWindowsGeometryHint::frame that does not early out, causing a missmatch in the geometries of the backing store and platform window. This fixes aero snapping shortcuts for frameless windows on multi monitor setups. Fixes: QTBUG-84466 Change-Id: I2357ea32669e4676645549996a3ac6073f3df15c Reviewed-by: André de la Rocha (cherry picked from commit cfe421cee2d4f56180280ecd9da8c3da6a980b84) Reviewed-by: Yuhang Zhao <2546789017@qq.com> --- .../platforms/windows/qwindowswindow.cpp | 34 +++++++++++-------- .../platforms/windows/qwindowswindow.h | 8 ++--- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index fb4d4ab1bcc..6e807360a3f 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -908,8 +908,10 @@ static QSize toNativeSizeConstrained(QSize dip, const QScreen *s) \internal */ -QMargins QWindowsGeometryHint::frameOnPrimaryScreen(DWORD style, DWORD exStyle) +QMargins QWindowsGeometryHint::frameOnPrimaryScreen(const QWindow *w, DWORD style, DWORD exStyle) { + if (!w->isTopLevel() || w->flags().testFlag(Qt::FramelessWindowHint)) + return {}; RECT rect = {0,0,0,0}; style &= ~DWORD(WS_OVERLAPPED); // Not permitted, see docs. if (AdjustWindowRectEx(&rect, style, FALSE, exStyle) == FALSE) @@ -922,16 +924,18 @@ QMargins QWindowsGeometryHint::frameOnPrimaryScreen(DWORD style, DWORD exStyle) return result; } -QMargins QWindowsGeometryHint::frameOnPrimaryScreen(HWND hwnd) +QMargins QWindowsGeometryHint::frameOnPrimaryScreen(const QWindow *w, HWND hwnd) { - return frameOnPrimaryScreen(DWORD(GetWindowLongPtr(hwnd, GWL_STYLE)), + return frameOnPrimaryScreen(w, DWORD(GetWindowLongPtr(hwnd, GWL_STYLE)), DWORD(GetWindowLongPtr(hwnd, GWL_EXSTYLE))); } -QMargins QWindowsGeometryHint::frame(DWORD style, DWORD exStyle, qreal dpi) +QMargins QWindowsGeometryHint::frame(const QWindow *w, DWORD style, DWORD exStyle, qreal dpi) { + if (!w->isTopLevel() || w->flags().testFlag(Qt::FramelessWindowHint)) + return {}; if (QWindowsContext::user32dll.adjustWindowRectExForDpi == nullptr) - return frameOnPrimaryScreen(style, exStyle); + return frameOnPrimaryScreen(w, style, exStyle); RECT rect = {0,0,0,0}; style &= ~DWORD(WS_OVERLAPPED); // Not permitted, see docs. if (QWindowsContext::user32dll.adjustWindowRectExForDpi(&rect, style, FALSE, exStyle, @@ -947,16 +951,18 @@ QMargins QWindowsGeometryHint::frame(DWORD style, DWORD exStyle, qreal dpi) return result; } -QMargins QWindowsGeometryHint::frame(HWND hwnd, DWORD style, DWORD exStyle) +QMargins QWindowsGeometryHint::frame(const QWindow *w, HWND hwnd, DWORD style, DWORD exStyle) { + if (!w->isTopLevel() || w->flags().testFlag(Qt::FramelessWindowHint)) + return {}; if (QWindowsScreenManager::isSingleScreen()) - return frameOnPrimaryScreen(style, exStyle); + return frameOnPrimaryScreen(w, style, exStyle); auto screenManager = QWindowsContext::instance()->screenManager(); auto screen = screenManager.screenForHwnd(hwnd); if (!screen) screen = screenManager.screens().value(0); const auto dpi = screen ? screen->logicalDpi().first : qreal(96); - return frame(style, exStyle, dpi); + return frame(w, style, exStyle, dpi); } // For newly created windows. @@ -968,7 +974,7 @@ QMargins QWindowsGeometryHint::frame(const QWindow *w, const QRect &geometry, if (!QWindowsContext::user32dll.adjustWindowRectExForDpi || QWindowsScreenManager::isSingleScreen() || !QWindowsContext::shouldHaveNonClientDpiScaling(w)) { - return frameOnPrimaryScreen(style, exStyle); + return frameOnPrimaryScreen(w, style, exStyle); } qreal dpi = 96; auto screenManager = QWindowsContext::instance()->screenManager(); @@ -977,7 +983,7 @@ QMargins QWindowsGeometryHint::frame(const QWindow *w, const QRect &geometry, screen = screenManager.screens().value(0); if (screen) dpi = screen->logicalDpi().first; - return QWindowsGeometryHint::frame(style, exStyle, dpi); + return QWindowsGeometryHint::frame(w, style, exStyle, dpi); } bool QWindowsGeometryHint::handleCalculateSize(const QMargins &customMargins, const MSG &msg, LRESULT *result) @@ -1115,7 +1121,7 @@ QRect QWindowsBaseWindow::geometry_sys() const QMargins QWindowsBaseWindow::frameMargins_sys() const { - return QWindowsGeometryHint::frame(handle(), style(), exStyle()); + return QWindowsGeometryHint::frame(window(), handle(), style(), exStyle()); } std::optional @@ -1841,7 +1847,7 @@ void QWindowsWindow::handleDpiScaledSize(WPARAM wParam, LPARAM lParam, LRESULT * const int dpi = int(wParam); const qreal scale = QHighDpiScaling::roundScaleFactor(qreal(dpi) / QWindowsScreen::baseDpi) / QHighDpiScaling::roundScaleFactor(qreal(savedDpi()) / QWindowsScreen::baseDpi); - const QMargins margins = QWindowsGeometryHint::frame(style(), exStyle(), dpi); + const QMargins margins = QWindowsGeometryHint::frame(window(), style(), exStyle(), dpi); const QSize windowSize = (geometry().size() * scale).grownBy(margins); SIZE *size = reinterpret_cast(lParam); size->cx = windowSize.width(); @@ -1911,7 +1917,7 @@ QRect QWindowsWindow::normalGeometry() const m_savedFrameGeometry.isValid() && (window()->windowStates() & Qt::WindowFullScreen); const QRect frame = fakeFullScreen ? m_savedFrameGeometry : normalFrameGeometry(m_data.hwnd); const QMargins margins = fakeFullScreen - ? QWindowsGeometryHint::frame(handle(), m_savedStyle, 0) + ? QWindowsGeometryHint::frame(window(), handle(), m_savedStyle, 0) : fullFrameMargins(); return frame.isValid() ? frame.marginsRemoved(margins) : frame; } @@ -2546,7 +2552,7 @@ void QWindowsWindow::calculateFullFrameMargins() // Normally obtained from WM_NCCALCSIZE. This calculation only works // when no native menu is present. const auto systemMargins = testFlag(DisableNonClientScaling) - ? QWindowsGeometryHint::frameOnPrimaryScreen(m_data.hwnd) + ? QWindowsGeometryHint::frameOnPrimaryScreen(window(), m_data.hwnd) : frameMargins_sys(); setFullFrameMargins(systemMargins + m_data.customMargins); } diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index 5e8478ca9cb..915254dbd80 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -62,10 +62,10 @@ class QDebug; struct QWindowsGeometryHint { - static QMargins frameOnPrimaryScreen(DWORD style, DWORD exStyle); - static QMargins frameOnPrimaryScreen(HWND hwnd); - static QMargins frame(DWORD style, DWORD exStyle, qreal dpi); - static QMargins frame(HWND hwnd, DWORD style, DWORD exStyle); + static QMargins frameOnPrimaryScreen(const QWindow *w, DWORD style, DWORD exStyle); + static QMargins frameOnPrimaryScreen(const QWindow *w, HWND hwnd); + static QMargins frame(const QWindow *w, DWORD style, DWORD exStyle, qreal dpi); + static QMargins frame(const QWindow *w, HWND hwnd, DWORD style, DWORD exStyle); static QMargins frame(const QWindow *w, const QRect &geometry, DWORD style, DWORD exStyle); static bool handleCalculateSize(const QMargins &customMargins, const MSG &msg, LRESULT *result);