Windows QPA: Use less magic number

The correct calculation of the invisible frame margin and the window
border width (they are the same thing actually) is the thickness
of the size frame plus the thickness of the padded border. When
DPI is 96, both of them is 4px and thus the invisible frame margin
and window border width is 8px. So previously the empirical
magic number can work normally is because the error is very small.
It's not a big thing because even on a high DPI screen the error
is still very small. For example, on my 4K monitor with 200%
scaling, the error is only 2px, human eyes almost can't find the
visual difference. But since we now know how to calculate these
values correctly, let's use the correct calculation instead. The
magic numbers and empirical expressions just make people confused.

Change-Id: Ieda4796231935f2ad1b6f28e4aa4af5b5bce2256
Reviewed-by: André de la Rocha <andre.rocha@qt.io>
(cherry picked from commit 770ea68588f954b8465276908bdfeeb6bcf550e8)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Yuhang Zhao 2021-12-04 20:19:03 +08:00 committed by Qt Cherry-pick Bot
parent eaa3faeacd
commit 33f8df80f9

View File

@ -478,10 +478,18 @@ static inline void updateGLWindowSettings(const QWindow *w, HWND hwnd, Qt::Windo
setWindowOpacity(hwnd, flags, hasAlpha, isAccelerated, opacity); setWindowOpacity(hwnd, flags, hasAlpha, isAccelerated, opacity);
} }
[[nodiscard]] static inline int getResizeBorderThickness(const UINT dpi)
{
// The width of the padded border will always be 0 if DWM composition is
// disabled, but since it will always be enabled and can't be programtically
// disabled from Windows 8, we are safe to go.
return GetSystemMetricsForDpi(SM_CXSIZEFRAME, dpi)
+ GetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi);
}
/*! /*!
Calculates the dimensions of the invisible borders within the Calculates the dimensions of the invisible borders within the
window frames in Windows 10, using an empirical expression that window frames which only exist on Windows 10 and onwards.
reproduces the measured values for standard DPI settings.
*/ */
static QMargins invisibleMargins(QPoint screenPoint) static QMargins invisibleMargins(QPoint screenPoint)
@ -491,14 +499,20 @@ static QMargins invisibleMargins(QPoint screenPoint)
UINT dpiX; UINT dpiX;
UINT dpiY; UINT dpiY;
if (SUCCEEDED(GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY))) { if (SUCCEEDED(GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY))) {
const qreal sc = (dpiX - 96) / 96.0; const int gap = getResizeBorderThickness(dpiX);
const int gap = 7 + qRound(5*sc) - int(sc);
return QMargins(gap, 0, gap, gap); return QMargins(gap, 0, gap, gap);
} }
} }
return QMargins(); return QMargins();
} }
[[nodiscard]] static inline QMargins invisibleMargins(const HWND hwnd)
{
const UINT dpi = GetDpiForWindow(hwnd);
const int gap = getResizeBorderThickness(dpi);
return QMargins(gap, 0, gap, gap);
}
/*! /*!
\class WindowCreationData \class WindowCreationData
\brief Window creation code. \brief Window creation code.
@ -2601,7 +2615,7 @@ QMargins QWindowsWindow::frameMargins() const
{ {
QMargins result = fullFrameMargins(); QMargins result = fullFrameMargins();
if (isTopLevel() && m_data.hasFrame) if (isTopLevel() && m_data.hasFrame)
result -= invisibleMargins(geometry().topLeft()); result -= invisibleMargins(m_data.hwnd);
return result; return result;
} }
@ -2801,13 +2815,6 @@ void QWindowsWindow::setFrameStrutEventsEnabled(bool enabled)
} }
} }
static int getBorderWidth(const QPlatformScreen *screen)
{
NONCLIENTMETRICS ncm;
QWindowsContext::nonClientMetricsForScreen(&ncm, screen);
return ncm.iBorderWidth + ncm.iPaddedBorderWidth + 2;
}
void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const
{ {
QWindowsGeometryHint::applyToMinMaxInfo(window(), fullFrameMargins(), mmi); QWindowsGeometryHint::applyToMinMaxInfo(window(), fullFrameMargins(), mmi);
@ -2829,7 +2836,7 @@ void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const
mmi->ptMaxPosition.x = availablePositionDiff.x(); mmi->ptMaxPosition.x = availablePositionDiff.x();
mmi->ptMaxPosition.y = availablePositionDiff.y(); mmi->ptMaxPosition.y = availablePositionDiff.y();
if (!m_data.flags.testFlag(Qt::FramelessWindowHint)) { if (!m_data.flags.testFlag(Qt::FramelessWindowHint)) {
const int borderWidth = getBorderWidth(currentScreen); const int borderWidth = invisibleMargins(m_data.hwnd).left();
mmi->ptMaxSize.x += borderWidth * 2; mmi->ptMaxSize.x += borderWidth * 2;
mmi->ptMaxSize.y += borderWidth * 2; mmi->ptMaxSize.y += borderWidth * 2;
mmi->ptMaxTrackSize = mmi->ptMaxSize; mmi->ptMaxTrackSize = mmi->ptMaxSize;
@ -2870,12 +2877,7 @@ bool QWindowsWindow::handleNonClientHitTest(const QPoint &globalPos, LRESULT *re
return true; return true;
} }
if (localPos.y() < 0) { if (localPos.y() < 0) {
// We want to return HTCAPTION/true only over the outer sizing frame, not the entire title bar, const int topResizeBarPos = invisibleMargins(m_data.hwnd).left() - frameMargins().top();
// otherwise the title bar buttons (close, etc.) become unresponsive on Windows 7 (QTBUG-78262).
// However, neither frameMargins() nor GetSystemMetrics(SM_CYSIZEFRAME), etc., give the correct
// sizing frame height in all Windows versions/scales. This empirical constant seems to work, though.
const int sizingHeight = 9;
const int topResizeBarPos = sizingHeight - frameMargins().top();
if (localPos.y() < topResizeBarPos) { if (localPos.y() < topResizeBarPos) {
*result = HTCAPTION; // Extend caption over top resize bar, let's user move the window. *result = HTCAPTION; // Extend caption over top resize bar, let's user move the window.
return true; return true;