Fix Maximized frameless window painting wrong with WS_THICKFRAME

In Qt versions greater than 6.4.2, when using Qt:FramelessWindowHint and
WS_THICKFRAME simultaneously, and handling the WM_NCCALCSIZE message to
draw a frameless window, the right and bottom sides may extend beyond
the drawable boundaries.

This is because in the previous commits, the calculation for margins was
skipped for windows with Qt:FramelessWindowHint set. This is correct for
non-maximized windows. However, when a window is maximized on Windows,
its actual size is slightly larger than the drawable area to avoid users
from dragging the border to resize the window. When window was maximized
, the code for calculating geometry should remove the margins instead of
skipping its calculation.

The fixed code determines whether to skip the calculation of margins and
frame by checking whether the window is maximized during the calculation
[ChangeLog][QPA][Windows] Adding a check for the maximized state of the
window during the calculation of margins. Margins calculation will not
be skipped for maximized windows.

Task-number: QTBUG-120196
Pick-to: 6.6 6.5
Change-Id: I63c8dbc8f65ff28cc581be261acfd3f675b027c4
Reviewed-by: Oliver Wolff <oliver.wolff@qt.io>
(cherry picked from commit 5f7b4c045f4347b9e47849d15d5932df45626c51)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Yansheng Zhu 2023-12-21 12:27:49 +08:00 committed by Qt Cherry-pick Bot
parent 56f4d1f0e9
commit 2b18f6c7b8

View File

@ -1019,6 +1019,21 @@ static QSize toNativeSizeConstrained(QSize dip, const QScreen *s)
return dip;
}
// Helper for checking if frame adjustment needs to be skipped
// NOTE: Unmaximized frameless windows will skip margins calculation
static bool shouldOmitFrameAdjustment(const Qt::WindowFlags flags, DWORD style)
{
return flags.testFlag(Qt::FramelessWindowHint) && !(style & WS_MAXIMIZE);
}
// Helper for checking if frame adjustment needs to be skipped
// NOTE: Unmaximized frameless windows will skip margins calculation
static bool shouldOmitFrameAdjustment(const Qt::WindowFlags flags, HWND hwnd)
{
DWORD style = hwnd != nullptr ? DWORD(GetWindowLongPtr(hwnd, GWL_STYLE)) : 0;
return flags.testFlag(Qt::FramelessWindowHint) && !(style & WS_MAXIMIZE);
}
/*!
\class QWindowsGeometryHint
\brief Stores geometry constraints and provides utility functions.
@ -1031,7 +1046,7 @@ static QSize toNativeSizeConstrained(QSize dip, const QScreen *s)
QMargins QWindowsGeometryHint::frameOnPrimaryScreen(const QWindow *w, DWORD style, DWORD exStyle)
{
if (!w->isTopLevel() || w->flags().testFlag(Qt::FramelessWindowHint))
if (!w->isTopLevel() || shouldOmitFrameAdjustment(w->flags(), style))
return {};
RECT rect = {0,0,0,0};
style &= ~DWORD(WS_OVERLAPPED); // Not permitted, see docs.
@ -1047,15 +1062,13 @@ QMargins QWindowsGeometryHint::frameOnPrimaryScreen(const QWindow *w, DWORD styl
QMargins QWindowsGeometryHint::frameOnPrimaryScreen(const QWindow *w, HWND hwnd)
{
if (!w->isTopLevel() || w->flags().testFlag(Qt::FramelessWindowHint))
return {};
return frameOnPrimaryScreen(w, DWORD(GetWindowLongPtr(hwnd, GWL_STYLE)),
DWORD(GetWindowLongPtr(hwnd, GWL_EXSTYLE)));
}
QMargins QWindowsGeometryHint::frame(const QWindow *w, DWORD style, DWORD exStyle, qreal dpi)
{
if (!w->isTopLevel() || w->flags().testFlag(Qt::FramelessWindowHint))
if (!w->isTopLevel() || shouldOmitFrameAdjustment(w->flags(), style))
return {};
RECT rect = {0,0,0,0};
style &= ~DWORD(WS_OVERLAPPED); // Not permitted, see docs.
@ -1073,7 +1086,7 @@ QMargins QWindowsGeometryHint::frame(const QWindow *w, DWORD style, DWORD exStyl
QMargins QWindowsGeometryHint::frame(const QWindow *w, HWND hwnd, DWORD style, DWORD exStyle)
{
if (!w->isTopLevel() || w->flags().testFlag(Qt::FramelessWindowHint))
if (!w->isTopLevel() || shouldOmitFrameAdjustment(w->flags(), style))
return {};
if (QWindowsScreenManager::isSingleScreen())
return frameOnPrimaryScreen(w, style, exStyle);
@ -1087,8 +1100,6 @@ QMargins QWindowsGeometryHint::frame(const QWindow *w, HWND hwnd, DWORD style, D
QMargins QWindowsGeometryHint::frame(const QWindow *w, HWND hwnd)
{
if (!w->isTopLevel() || w->flags().testFlag(Qt::FramelessWindowHint))
return {};
return frame(w, hwnd, DWORD(GetWindowLongPtr(hwnd, GWL_STYLE)),
DWORD(GetWindowLongPtr(hwnd, GWL_EXSTYLE)));
}
@ -1097,7 +1108,7 @@ QMargins QWindowsGeometryHint::frame(const QWindow *w, HWND hwnd)
QMargins QWindowsGeometryHint::frame(const QWindow *w, const QRect &geometry,
DWORD style, DWORD exStyle)
{
if (!w->isTopLevel() || w->flags().testFlag(Qt::FramelessWindowHint))
if (!w->isTopLevel() || shouldOmitFrameAdjustment(w->flags(), style))
return {};
if (QWindowsScreenManager::isSingleScreen()
|| !QWindowsContext::shouldHaveNonClientDpiScaling(w)) {
@ -2038,7 +2049,7 @@ void QWindowsWindow::handleDpiChanged(HWND hwnd, WPARAM wParam, LPARAM lParam)
// If the window does not have a frame, WM_MOVE and WM_SIZE won't be
// called which prevents the content from being scaled appropriately
// after a DPI change.
if (m_data.flags & Qt::FramelessWindowHint)
if (shouldOmitFrameAdjustment(m_data.flags, m_data.hwnd))
handleGeometryChange();
}
@ -2754,7 +2765,7 @@ bool QWindowsWindow::handleGeometryChanging(MSG *message) const
void QWindowsWindow::setFullFrameMargins(const QMargins &newMargins)
{
if (m_data.flags & Qt::FramelessWindowHint)
if (shouldOmitFrameAdjustment(m_data.flags, m_data.hwnd))
return;
if (m_data.fullFrameMargins != newMargins) {
qCDebug(lcQpaWindow) << __FUNCTION__ << window() << m_data.fullFrameMargins << "->" << newMargins;
@ -2773,7 +2784,7 @@ void QWindowsWindow::updateFullFrameMargins()
void QWindowsWindow::calculateFullFrameMargins()
{
if (m_data.flags & Qt::FramelessWindowHint)
if (shouldOmitFrameAdjustment(m_data.flags, m_data.hwnd))
return;
// QTBUG-113736: systemMargins depends on AdjustWindowRectExForDpi. This doesn't take into
@ -2824,7 +2835,7 @@ QMargins QWindowsWindow::frameMargins() const
QMargins QWindowsWindow::fullFrameMargins() const
{
if (m_data.flags & Qt::FramelessWindowHint)
if (shouldOmitFrameAdjustment(m_data.flags, m_data.hwnd))
return {};
return m_data.fullFrameMargins;
}