Windows QPA: Add some offset to the system menu when appropriate

Before this patch, the system menu will always appear on
the top-left corner of the window if the window doesn't
have the standard window frame. However, this doesn't look
very good on most situations, especially when the window
has a homemade title bar. This patch adds an extra check
for this kind of situations. This patch will automatically
apply an appropriate offset for the system menu if the user
is trying to use a self-made title bar for their frameless
or customized windows.

Pick-to: 6.3 6.2
Change-Id: I55e1c4ac26a4051ca48928d4a2ac3456dce117d1
Reviewed-by: André de la Rocha <andre.rocha@qt.io>
bb10
Yuhang Zhao 2022-02-12 16:46:26 +08:00
parent 7261c81152
commit 77d0ad6657
1 changed files with 23 additions and 1 deletions

View File

@ -785,6 +785,27 @@ static inline QString messageKeyText(const MSG &msg)
return ch.isNull() ? QString() : QString(ch);
}
[[nodiscard]] static inline int getTitleBarHeight(const HWND hwnd)
{
const UINT dpi = GetDpiForWindow(hwnd);
const int captionHeight = GetSystemMetricsForDpi(SM_CYCAPTION, dpi);
if (IsZoomed(hwnd))
return captionHeight;
// The frame height should also be taken into account if the window
// is not maximized.
const int frameHeight = GetSystemMetricsForDpi(SM_CYSIZEFRAME, dpi)
+ GetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi);
return captionHeight + frameHeight;
}
[[nodiscard]] static inline bool isSystemMenuOffsetNeeded(const Qt::WindowFlags flags)
{
static constexpr const Qt::WindowFlags titleBarHints =
Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint | Qt::WindowContextHelpButtonHint;
return (flags & Qt::WindowSystemMenuHint) && (flags & Qt::WindowTitleHint) && !(flags & titleBarHints)
&& (flags & (Qt::FramelessWindowHint | Qt::CustomizeWindowHint));
}
static void showSystemMenu(QWindow* w)
{
QWindow *topLevel = QWindowsWindow::topLevelOf(w);
@ -826,9 +847,10 @@ static void showSystemMenu(QWindow* w)
#undef enabled
#undef disabled
const QPoint pos = QHighDpi::toNativePixels(topLevel->geometry().topLeft(), topLevel);
const int titleBarOffset = isSystemMenuOffsetNeeded(topLevel->flags()) ? getTitleBarHeight(topLevelHwnd) : 0;
const int ret = TrackPopupMenuEx(menu,
TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RETURNCMD,
pos.x(), pos.y(),
pos.x(), pos.y() + titleBarOffset,
topLevelHwnd,
nullptr);
if (ret)