From 5abc6e9ccb2907c98995741ab38e728753a83bd9 Mon Sep 17 00:00:00 2001 From: Axel Spoerl Date: Thu, 3 Oct 2024 18:52:45 +0200 Subject: [PATCH] QWindowsWindow: Refactor corrections related to task bar on top / left 33874a9424cd03c21ca9986a39c383b3689f03d2 corrected a size-contrained window's position when maximized. Restoring such a window's size moved the window downwards as well, if the task bar was on top. With the task bar on the left, such maximizing the window caused parts of it to be off screen to the right. These bugs affect only Windows 10, because Windows 11 only allows the task bar to be at the bottom. Factor out all corrections to QWindowsWindow::correctWindowPlacement(). Correct placement when restoring size of a maximized, size-constrained window. Correct width of a height-constrained, maximized window. Correct height of a width-constrained, maximized window. Change-Id: I9a1e0cf4708e8c579595fdbdc7f16b927be53b05 Done-with: Johannes Grunenberg Fixes: QTBUG-129405 Fixes: QTBUG-129679 Task-number: QTBUG-123752 Pick-to: 6.5 Reviewed-by: Oliver Wolff (cherry picked from commit 06fcb3dfe69e175f94d112ecef45b091598f5ae5) Reviewed-by: Qt Cherry-pick Bot --- .../platforms/windows/qwindowswindow.cpp | 80 ++++++++++++++----- .../platforms/windows/qwindowswindow.h | 3 + 2 files changed, 63 insertions(+), 20 deletions(-) diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 925b70ffb25..2b48e920033 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -2485,12 +2485,6 @@ QWindowsWindowData QWindowsWindow::setWindowFlags_sys(Qt::WindowFlags wt, return result; } -inline bool QWindowsBaseWindow::hasMaximumSize() const -{ - const auto maximumSize = window()->maximumSize(); - return maximumSize.width() != QWINDOWSIZE_MAX || maximumSize.height() != QWINDOWSIZE_MAX; -} - void QWindowsWindow::handleWindowStateChange(Qt::WindowStates state) { qCDebug(lcQpaWindow) << __FUNCTION__ << this << window() @@ -2507,20 +2501,7 @@ void QWindowsWindow::handleWindowStateChange(Qt::WindowStates state) GetWindowPlacement(m_data.hwnd, &windowPlacement); const RECT geometry = RECTfromQRect(m_data.restoreGeometry); windowPlacement.rcNormalPosition = geometry; - - // A bug in windows 10 grows - // - ptMaxPosition.x by the task bar's width, if it's on the left - // - ptMaxPosition.y by the task bar's height, if it's on the top - // each time GetWindowPlacement() is called. - // The offset of the screen's left edge (as per frameMargins_sys().left()) is ignored. - // => Check for windows 10 and correct. - static const auto windows11 = QOperatingSystemVersion::Windows11_21H2; - static const bool isWindows10 = QOperatingSystemVersion::current() < windows11; - if (isWindows10 && hasMaximumSize()) { - const QMargins margins = frameMargins_sys(); - const QPoint topLeft = window()->screen()->geometry().topLeft(); - windowPlacement.ptMaxPosition = POINT{ topLeft.x() - margins.left(), topLeft.y() }; - } + correctWindowPlacement(windowPlacement); // Even if the window is hidden, windowPlacement's showCmd is not SW_HIDE, so change it // manually to avoid unhiding a hidden window with the subsequent call to @@ -2552,6 +2533,65 @@ void QWindowsWindow::handleWindowStateChange(Qt::WindowStates state) } } +// Apply corrections to window placement in Windows 10 +// Related to task bar on top or left. + +inline bool QWindowsBaseWindow::hasMaximumHeight() const +{ + return window()->maximumHeight() != QWINDOWSIZE_MAX; +} + +inline bool QWindowsBaseWindow::hasMaximumWidth() const +{ + return window()->maximumWidth() != QWINDOWSIZE_MAX; +} + +inline bool QWindowsBaseWindow::hasMaximumSize() const +{ + return hasMaximumHeight() || hasMaximumWidth(); +} + +void QWindowsWindow::correctWindowPlacement(WINDOWPLACEMENT &windowPlacement) +{ + static const auto windows11 = QOperatingSystemVersion::Windows11_21H2; + static const bool isWindows10 = QOperatingSystemVersion::current() < windows11; + if (!isWindows10) + return; + + // Correct normal position by placement offset on Windows 10 + // (where task bar can be on any side of the screen) + const QPoint offset = windowPlacementOffset(m_data.hwnd, m_data.restoreGeometry.topLeft()); + windowPlacement.rcNormalPosition = RECTfromQRect(m_data.restoreGeometry.translated(-offset)); + qCDebug(lcQpaWindow) << "Corrected normal position by" << -offset; + + // A bug in windows 10 grows + // - ptMaxPosition.x by the task bar's width, if it's on the left + // - ptMaxPosition.y by the task bar's height, if it's on the top + // each time GetWindowPlacement() is called. + // The offset of the screen's left edge (as per frameMargins_sys().left()) is ignored. + // => Check for windows 10 and correct. + if (hasMaximumSize()) { + const QMargins margins = frameMargins_sys(); + const QPoint topLeft = window()->screen()->geometry().topLeft(); + windowPlacement.ptMaxPosition = POINT{ topLeft.x() - margins.left(), topLeft.y() }; + qCDebug(lcQpaWindow) << "Window has maximum size. Corrected topLeft by" + << -margins.left(); + + // If there is a placement offset correct width/height unless restricted, + // in order to fit window onto the screen. + if (offset.x() > 0 && !hasMaximumWidth()) { + const int adjust = offset.x() / window()->devicePixelRatio(); + window()->setWidth(window()->width() - adjust); + qCDebug(lcQpaWindow) << "Width shortened by" << adjust << "logical pixels."; + } + if (offset.y() > 0 && !hasMaximumHeight()) { + const int adjust = offset.y() / window()->devicePixelRatio(); + window()->setHeight(window()->height() - adjust); + qCDebug(lcQpaWindow) << "Height shortened by" << adjust << "logical pixels."; + } + } +} + void QWindowsWindow::updateRestoreGeometry() { m_data.restoreGeometry = normalFrameGeometry(m_data.hwnd); diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index 687ade1d921..bebd068f1a5 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -128,6 +128,8 @@ public: protected: HWND parentHwnd() const { return GetAncestor(handle(), GA_PARENT); } bool isTopLevel_sys() const; + inline bool hasMaximumHeight() const; + inline bool hasMaximumWidth() const; inline bool hasMaximumSize() const; QRect frameGeometry_sys() const; QRect geometry_sys() const; @@ -368,6 +370,7 @@ private: void fireExpose(const QRegion ®ion, bool force=false); void fireFullExpose(bool force=false); void calculateFullFrameMargins(); + void correctWindowPlacement(WINDOWPLACEMENT &windowPlacement); mutable QWindowsWindowData m_data; QPointer m_menuBar;