From d64b38a8dbd50630149c0487d086368ca9e79f39 Mon Sep 17 00:00:00 2001 From: Yuhang Zhao <2546789017@qq.com> Date: Sun, 5 Sep 2021 12:27:16 +0800 Subject: [PATCH] Improve the widget example Signed-off-by: Yuhang Zhao <2546789017@qq.com> --- examples/widget/widget.cpp | 267 +++++++++++++++++++++++++++---------- examples/widget/widget.h | 12 +- utilities.h | 15 ++- utilities_win32.cpp | 149 +++++++++++++++++++-- 4 files changed, 360 insertions(+), 83 deletions(-) diff --git a/examples/widget/widget.cpp b/examples/widget/widget.cpp index c9809eb..2aed980 100644 --- a/examples/widget/widget.cpp +++ b/examples/widget/widget.cpp @@ -27,13 +27,54 @@ #include #include #include -#include #include #include "../../utilities.h" #include "../../framelesswindowsmanager.h" FRAMELESSHELPER_USE_NAMESPACE +static const QColor systemLightColor = QStringLiteral("#f0f0f0"); +static const QColor systemDarkColor = QColor::fromRgb(32, 32, 32); + +static constexpr char mainStyleSheet[] = R"( +#MainWidget { + background-color: %1; +} + +#TitleBarWidget { + background-color: %2; +} + +#WindowTitleLabel { + color: %3; +} + +#MinimizeButton, #MaximizeButton, #CloseButton { + border-style: none; + background-color: transparent; +} + +#MinimizeButton:hover, #MaximizeButton:hover { + background-color: #c7c7c7; +} + +#MinimizeButton:pressed, #MaximizeButton:pressed { + background-color: #808080; +} + +#CloseButton:hover { + background-color: #e81123; +} + +#CloseButton:pressed { + background-color: #8c0a15; +} + +#ClockLabel { + color: %4; +} +)"; + Widget::Widget(QWidget *parent) : QWidget(parent) { setAttribute(Qt::WA_DontCreateNativeAncestors); @@ -49,20 +90,28 @@ void Widget::showEvent(QShowEvent *event) QWidget::showEvent(event); static bool inited = false; if (!inited) { + inited = true; QWindow *win = windowHandle(); + Q_ASSERT(win); + if (!win) { + qFatal("Failed to retrieve the window handle."); + return; + } FramelessWindowsManager::addWindow(win); FramelessWindowsManager::setHitTestVisibleInChrome(win, m_minimizeButton, true); FramelessWindowsManager::setHitTestVisibleInChrome(win, m_maximizeButton, true); FramelessWindowsManager::setHitTestVisibleInChrome(win, m_closeButton, true); - setContentsMargins(1, 1, 1, 1); - inited = true; + const int margin = Utilities::getWindowVisibleFrameBorderThickness(winId()); + setContentsMargins(margin, margin, margin, margin); } } void Widget::timerEvent(QTimerEvent *event) { QWidget::timerEvent(event); - m_label->setText(QTime::currentTime().toString(QStringLiteral("hh:mm:ss"))); + if (m_clockLabel) { + m_clockLabel->setText(QTime::currentTime().toString(QStringLiteral("hh:mm:ss"))); + } } void Widget::changeEvent(QEvent *event) @@ -70,42 +119,45 @@ void Widget::changeEvent(QEvent *event) QWidget::changeEvent(event); bool shouldUpdate = false; if (event->type() == QEvent::WindowStateChange) { - if (isMaximized() || isFullScreen()) { - setContentsMargins(0, 0, 0, 0); - m_maximizeButton->setIcon(QIcon{QStringLiteral(":/images/button_restore_black.svg")}); - } else if (!isMinimized()) { - setContentsMargins(1, 1, 1, 1); - m_maximizeButton->setIcon(QIcon{QStringLiteral(":/images/button_maximize_black.svg")}); - } + const int margin = ((isMaximized() || isFullScreen()) ? 0 : Utilities::getWindowVisibleFrameBorderThickness(winId())); + setContentsMargins(margin, margin, margin, margin); + updateSystemButtonIcons(); + updateTitleBarSize(); shouldUpdate = true; } else if (event->type() == QEvent::ActivationChange) { shouldUpdate = true; } if (shouldUpdate) { - update(); + updateStyleSheet(); } } void Widget::paintEvent(QPaintEvent *event) { QWidget::paintEvent(event); - if (windowState() == Qt::WindowNoState) { + if (!isMaximized() && !isFullScreen()) { QPainter painter(this); - const int w = width(); - const int h = height(); + painter.save(); + painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform); + const auto w = static_cast(width()); + const auto h = static_cast(height()); #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) - using BorderLines = QList; + using BorderLines = QList; #else - using BorderLines = QVector; + using BorderLines = QVector; #endif const BorderLines lines = { {0, 0, w, 0}, - {w - 1, 0, w - 1, h}, - {w, h - 1, 0, h - 1}, + {w, 0, w , h}, + {w, h, 0, h}, {0, h, 0, 0} }; - painter.save(); - painter.setPen({isActiveWindow() ? Qt::black : Qt::darkGray, 1}); + const ColorizationArea area = Utilities::getColorizationArea(); + const bool colorizedBorder = ((area == ColorizationArea::TitleBar_WindowBorder) + || (area == ColorizationArea::All)); + const QColor borderColor = (isActiveWindow() ? (colorizedBorder ? Utilities::getColorizationColor() : Qt::black) : Qt::darkGray); + const auto borderThickness = static_cast(Utilities::getWindowVisibleFrameBorderThickness(winId())); + painter.setPen({borderColor, qMax(borderThickness, devicePixelRatioF())}); painter.drawLines(lines); painter.restore(); } @@ -113,82 +165,163 @@ void Widget::paintEvent(QPaintEvent *event) void Widget::setupUi() { + setObjectName(QStringLiteral("MainWidget")); setWindowTitle(tr("Hello, World!")); resize(800, 600); - const QWindow *win = windowHandle(); - const int titleBarHeight = Utilities::getSystemMetric(win, SystemMetric::TitleBarHeight, false); - const QSize systemButtonSize = {qRound(static_cast(titleBarHeight) * 1.5), titleBarHeight}; - m_minimizeButton = new QPushButton(this); + m_titleBarWidget = new QWidget(this); + m_titleBarWidget->setObjectName(QStringLiteral("TitleBarWidget")); + m_titleBarWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + m_windowTitleLabel = new QLabel(m_titleBarWidget); + m_windowTitleLabel->setObjectName(QStringLiteral("WindowTitleLabel")); + m_windowTitleLabel->setFrameShape(QFrame::NoFrame); + QFont titleFont = font(); + titleFont.setPointSize(11); + m_windowTitleLabel->setFont(titleFont); + m_windowTitleLabel->setText(windowTitle()); + connect(this, &Widget::windowTitleChanged, m_windowTitleLabel, &QLabel::setText); + m_minimizeButton = new QPushButton(m_titleBarWidget); m_minimizeButton->setObjectName(QStringLiteral("MinimizeButton")); - m_minimizeButton->setFixedSize(systemButtonSize); - m_minimizeButton->setIcon(QIcon{QStringLiteral(":/images/button_minimize_black.svg")}); - m_minimizeButton->setIconSize(systemButtonSize); connect(m_minimizeButton, &QPushButton::clicked, this, &Widget::showMinimized); - m_maximizeButton = new QPushButton(this); + m_maximizeButton = new QPushButton(m_titleBarWidget); m_maximizeButton->setObjectName(QStringLiteral("MaximizeButton")); - m_maximizeButton->setFixedSize(systemButtonSize); - m_maximizeButton->setIcon(QIcon{QStringLiteral(":/images/button_maximize_black.svg")}); - m_maximizeButton->setIconSize(systemButtonSize); connect(m_maximizeButton, &QPushButton::clicked, this, [this](){ if (isMaximized() || isFullScreen()) { showNormal(); - m_maximizeButton->setIcon(QIcon{QStringLiteral(":/images/button_maximize_black.svg")}); } else { showMaximized(); - m_maximizeButton->setIcon(QIcon{QStringLiteral(":/images/button_restore_black.svg")}); } + updateSystemButtonIcons(); }); - m_closeButton = new QPushButton(this); + m_closeButton = new QPushButton(m_titleBarWidget); m_closeButton->setObjectName(QStringLiteral("CloseButton")); - m_closeButton->setFixedSize(systemButtonSize); - m_closeButton->setIcon(QIcon{QStringLiteral(":/images/button_close_black.svg")}); - m_closeButton->setIconSize(systemButtonSize); connect(m_closeButton, &QPushButton::clicked, this, &Widget::close); - const auto systemButtonLayout = new QHBoxLayout; - systemButtonLayout->setContentsMargins(0, 0, 0, 0); - systemButtonLayout->setSpacing(0); - systemButtonLayout->addStretch(); - systemButtonLayout->addWidget(m_minimizeButton); - systemButtonLayout->addWidget(m_maximizeButton); - systemButtonLayout->addWidget(m_closeButton); - m_label = new QLabel(this); - QFont font = QGuiApplication::font(); - font.setBold(true); - font.setPointSize(70); - m_label->setFont(font); - m_label->setFrameShape(QFrame::NoFrame); + updateSystemButtonIcons(); + updateTitleBarSize(); + const auto titleBarLayout = new QHBoxLayout(m_titleBarWidget); + titleBarLayout->setContentsMargins(0, 0, 0, 0); + titleBarLayout->setSpacing(0); + titleBarLayout->addSpacerItem(new QSpacerItem(10, 10)); + titleBarLayout->addWidget(m_windowTitleLabel); + titleBarLayout->addStretch(); + titleBarLayout->addWidget(m_minimizeButton); + titleBarLayout->addWidget(m_maximizeButton); + titleBarLayout->addWidget(m_closeButton); + m_titleBarWidget->setLayout(titleBarLayout); + m_clockLabel = new QLabel(this); + m_clockLabel->setObjectName(QStringLiteral("ClockLabel")); + m_clockLabel->setFrameShape(QFrame::NoFrame); + QFont clockFont = font(); + clockFont.setBold(true); + clockFont.setPointSize(70); + m_clockLabel->setFont(clockFont); const auto contentLayout = new QHBoxLayout; + contentLayout->setContentsMargins(0, 0, 0, 0); + contentLayout->setSpacing(0); contentLayout->addStretch(); - contentLayout->addWidget(m_label); + contentLayout->addWidget(m_clockLabel); contentLayout->addStretch(); const auto mainLayout = new QVBoxLayout(this); mainLayout->setContentsMargins(0, 0, 0, 0); mainLayout->setSpacing(0); - mainLayout->addLayout(systemButtonLayout); + mainLayout->addWidget(m_titleBarWidget); mainLayout->addStretch(); mainLayout->addLayout(contentLayout); mainLayout->addStretch(); setLayout(mainLayout); - setStyleSheet(QStringLiteral(R"( -#MinimizeButton, #MaximizeButton, #CloseButton { - border-style: none; - background-color: transparent; + updateStyleSheet(); } -#MinimizeButton:hover, #MaximizeButton:hover { - background-color: #80c7c7c7; +void Widget::updateStyleSheet() +{ + const bool active = isActiveWindow(); + const bool dark = Utilities::shouldAppsUseDarkMode(); + const ColorizationArea area = Utilities::getColorizationArea(); + const bool colorizedTitleBar = ((area == ColorizationArea::TitleBar_WindowBorder) + || (area == ColorizationArea::All)); + const QColor colorizationColor = Utilities::getColorizationColor(); + const QColor mainWidgetBackgroundColor = (dark ? systemDarkColor : systemLightColor); + const QColor titleBarWidgetBackgroundColor = [active, colorizedTitleBar, &colorizationColor, dark]{ + if (active) { + if (colorizedTitleBar) { + return colorizationColor; + } else { + if (dark) { + return QColor(Qt::black); + } else { + return QColor(Qt::white); + } + } + } else { + if (dark) { + return systemDarkColor; + } else { + return QColor(Qt::white); + } + } + }(); + const QColor windowTitleLabelTextColor = (active ? (dark ? Qt::white : Qt::black) : Qt::darkGray); + const QColor clockLabelTextColor = (dark ? Qt::white : Qt::black); + setStyleSheet(QString::fromUtf8(mainStyleSheet) + .arg(mainWidgetBackgroundColor.name(), + titleBarWidgetBackgroundColor.name(), + windowTitleLabelTextColor.name(), + clockLabelTextColor.name())); + update(); } -#MinimizeButton:pressed, #MaximizeButton:pressed { - background-color: #80808080; +void Widget::updateTitleBarSize() +{ + const QWindow *win = windowHandle(); + Q_ASSERT(win); + if (!win) { + return; + } + const int titleBarHeight = Utilities::getSystemMetric(win, SystemMetric::TitleBarHeight, false); + const QSize systemButtonSize = {qRound(static_cast(titleBarHeight) * 1.5), titleBarHeight}; + m_minimizeButton->setFixedSize(systemButtonSize); + m_minimizeButton->setIconSize(systemButtonSize); + m_maximizeButton->setFixedSize(systemButtonSize); + m_maximizeButton->setIconSize(systemButtonSize); + m_closeButton->setFixedSize(systemButtonSize); + m_closeButton->setIconSize(systemButtonSize); + m_titleBarWidget->setFixedHeight(titleBarHeight); } -#CloseButton:hover { - background-color: #e81123; +void Widget::updateSystemButtonIcons() +{ + Q_ASSERT(m_minimizeButton); + Q_ASSERT(m_maximizeButton); + Q_ASSERT(m_closeButton); + if (!m_minimizeButton || !m_maximizeButton || !m_closeButton) { + return; + } + const QString suffix = (Utilities::shouldAppsUseDarkMode() ? QStringLiteral("white") : QStringLiteral("black")); + m_minimizeButton->setIcon(QIcon(QStringLiteral(":/images/button_minimize_%1.svg").arg(suffix))); + if (isMaximized() || isFullScreen()) { + m_maximizeButton->setIcon(QIcon(QStringLiteral(":/images/button_restore_%1.svg").arg(suffix))); + } else { + m_maximizeButton->setIcon(QIcon(QStringLiteral(":/images/button_maximize_%1.svg").arg(suffix))); + } + m_closeButton->setIcon(QIcon(QStringLiteral(":/images/button_close_%1.svg").arg(suffix))); } -#CloseButton:pressed { - background-color: #8c0a15; -} -)")); +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) +bool Widget::nativeEvent(const QByteArray &eventType, void *message, qintptr *result) +#else +bool Widget::nativeEvent(const QByteArray &eventType, void *message, long *result) +#endif +{ + if (message) { + if (Utilities::isThemeChanged(message)) { + updateStyleSheet(); + updateSystemButtonIcons(); + } + QPointF pos = {}; + if (Utilities::isSystemMenuRequested(message, &pos)) { + if (!Utilities::showSystemMenu(winId(), pos)) { + qWarning() << "Failed to display the system menu."; + } + } + } + return QWidget::nativeEvent(eventType, message, result); } diff --git a/examples/widget/widget.h b/examples/widget/widget.h index c07b00b..071c9cc 100644 --- a/examples/widget/widget.h +++ b/examples/widget/widget.h @@ -44,13 +44,23 @@ protected: void timerEvent(QTimerEvent *event) override; void changeEvent(QEvent *event) override; void paintEvent(QPaintEvent *event) override; +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + bool nativeEvent(const QByteArray &eventType, void *message, qintptr *result) override; +#else + bool nativeEvent(const QByteArray &eventType, void *message, long *result) override; +#endif private: void setupUi(); + void updateStyleSheet(); + void updateTitleBarSize(); + void updateSystemButtonIcons(); private: - QLabel *m_label = nullptr; + QWidget *m_titleBarWidget = nullptr; + QLabel *m_windowTitleLabel = nullptr; QPushButton *m_minimizeButton = nullptr; QPushButton *m_maximizeButton = nullptr; QPushButton *m_closeButton = nullptr; + QLabel *m_clockLabel = nullptr; }; diff --git a/utilities.h b/utilities.h index e2d5dc0..4b4e26d 100644 --- a/utilities.h +++ b/utilities.h @@ -38,6 +38,15 @@ namespace Utilities [[nodiscard]] FRAMELESSHELPER_API bool isWindowFixedSize(const QWindow *window); [[nodiscard]] FRAMELESSHELPER_API bool isHitTestVisibleInChrome(const QWindow *window); [[nodiscard]] FRAMELESSHELPER_API QPointF mapOriginPointToWindow(const QObject *object); +[[nodiscard]] FRAMELESSHELPER_API QColor getColorizationColor(); +[[nodiscard]] FRAMELESSHELPER_API int getWindowVisibleFrameBorderThickness(const WId winId); +[[nodiscard]] FRAMELESSHELPER_API bool shouldAppsUseDarkMode(); +[[nodiscard]] FRAMELESSHELPER_API bool isHighContrastModeEnabled(); +[[nodiscard]] FRAMELESSHELPER_API ColorizationArea getColorizationArea(); +[[nodiscard]] FRAMELESSHELPER_API bool isWindowDarkFrameBorderEnabled(const WId winId); +[[nodiscard]] FRAMELESSHELPER_API bool isThemeChanged(const void *data); +[[nodiscard]] FRAMELESSHELPER_API bool isSystemMenuRequested(const void *data, QPointF *pos); +[[nodiscard]] FRAMELESSHELPER_API bool showSystemMenu(const WId winId, const QPointF &pos); #ifdef Q_OS_WINDOWS [[nodiscard]] FRAMELESSHELPER_API bool isWin8OrGreater(); @@ -48,12 +57,6 @@ FRAMELESSHELPER_API void triggerFrameChange(const WId winId); FRAMELESSHELPER_API void updateFrameMargins(const WId winId, const bool reset); FRAMELESSHELPER_API void updateQtFrameMargins(QWindow *window, const bool enable); [[nodiscard]] FRAMELESSHELPER_API QString getSystemErrorMessage(const QString &function, const HRESULT hr); -[[nodiscard]] FRAMELESSHELPER_API QColor getColorizationColor(); -[[nodiscard]] FRAMELESSHELPER_API int getWindowVisibleFrameBorderThickness(const QWindow *window); -[[nodiscard]] FRAMELESSHELPER_API bool shouldAppsUseDarkMode(); -[[nodiscard]] FRAMELESSHELPER_API bool isHighContrastModeEnabled(); -[[nodiscard]] FRAMELESSHELPER_API ColorizationArea getColorizationArea(); -[[nodiscard]] FRAMELESSHELPER_API bool isWindowDarkFrameBorderEnabled(const WId winId); #endif } diff --git a/utilities_win32.cpp b/utilities_win32.cpp index ea1f0a2..d5146f1 100644 --- a/utilities_win32.cpp +++ b/utilities_win32.cpp @@ -42,11 +42,31 @@ Q_DECLARE_METATYPE(QMargins) +#ifndef GET_X_LPARAM +// Only available since Windows 2000 +#define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp)) +#endif + +#ifndef GET_Y_LPARAM +// Only available since Windows 2000 +#define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp)) +#endif + +#ifndef IsMaximized +// Only available since Windows 2000 +#define IsMaximized(window) (IsZoomed(window) != FALSE) +#endif + #ifndef SM_CXPADDEDBORDER // Only available since Windows Vista #define SM_CXPADDEDBORDER (92) #endif +#ifndef WM_DWMCOLORIZATIONCOLORCHANGED +// Only available since Windows Vista +#define WM_DWMCOLORIZATIONCOLORCHANGED (0x0320) +#endif + FRAMELESSHELPER_BEGIN_NAMESPACE static constexpr char kDwmRegistryKey[] = R"(HKEY_CURRENT_USER\Software\Microsoft\Windows\DWM)"; @@ -310,16 +330,16 @@ QColor Utilities::getColorizationColor() return QColor::fromRgba(color); } -int Utilities::getWindowVisibleFrameBorderThickness(const QWindow *window) +int Utilities::getWindowVisibleFrameBorderThickness(const WId winId) { - Q_ASSERT(window); - if (!window) { - return 0; + Q_ASSERT(winId); + if (!winId) { + return 1; } if (!isWin10OrGreater()) { - return 0; + return 1; } - const auto hWnd = reinterpret_cast(window->winId()); + const auto hWnd = reinterpret_cast(winId); UINT value = 0; const HRESULT hr = DwmGetWindowAttribute(hWnd, _DWMWA_VISIBLE_FRAME_BORDER_THICKNESS, &value, sizeof(value)); if (SUCCEEDED(hr)) { @@ -329,9 +349,7 @@ int Utilities::getWindowVisibleFrameBorderThickness(const QWindow *window) // late Windows 10 version, so querying it's value will always result in // a "parameter error" (code: 87) on systems before that value was introduced. } - const bool max = (window->windowState() == Qt::WindowMaximized); - const bool full = (window->windowState() == Qt::WindowFullScreen); - return ((max || full) ? 0 : qRound(1.0 * window->devicePixelRatio())); + return 1; } bool Utilities::shouldAppsUseDarkMode() @@ -443,4 +461,117 @@ bool Utilities::isWindowDarkFrameBorderEnabled(const WId winId) return false; } +bool Utilities::isThemeChanged(const void *data) +{ + Q_ASSERT(data); + if (!data) { + return false; + } + const auto msg = static_cast(data); + if (msg->message == WM_THEMECHANGED) { + return true; + } else if (msg->message == WM_DWMCOLORIZATIONCOLORCHANGED) { + return true; + } else if (msg->message == WM_SETTINGCHANGE) { + if ((msg->wParam == 0) && (_wcsicmp(reinterpret_cast(msg->lParam), L"ImmersiveColorSet") == 0)) { + return true; + } + } + return false; +} + +bool Utilities::isSystemMenuRequested(const void *data, QPointF *pos) +{ + Q_ASSERT(data); + if (!data) { + return false; + } + const auto msg = static_cast(data); + if (msg->message == WM_NCRBUTTONUP) { + if (msg->wParam == HTCAPTION) { + if (pos) { + const POINT nativePos = {GET_X_LPARAM(msg->lParam), GET_Y_LPARAM(msg->lParam)}; + *pos = QPointF(static_cast(nativePos.x), static_cast(nativePos.y)); + } + return true; + } + } + return false; +} + +bool Utilities::showSystemMenu(const WId winId, const QPointF &pos) +{ + Q_ASSERT(winId); + if (!winId) { + return false; + } + const auto hWnd = reinterpret_cast(winId); + const HMENU menu = GetSystemMenu(hWnd, FALSE); + if (!menu) { + const HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); + qWarning() << getSystemErrorMessage(QStringLiteral("GetSystemMenu"), hr); + return false; + } + // Update the options based on window state. + MENUITEMINFOW mii; + SecureZeroMemory(&mii, sizeof(mii)); + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_STATE; + mii.fType = MFT_STRING; + const auto setState = [&mii, menu](const UINT item, const bool enabled) -> bool { + mii.fState = (enabled ? MF_ENABLED : MF_DISABLED); + return (SetMenuItemInfoW(menu, item, FALSE, &mii) != FALSE); + }; + const bool max = IsMaximized(hWnd); + if (!setState(SC_RESTORE, max)) { + const HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); + qWarning() << getSystemErrorMessage(QStringLiteral("SetMenuItemInfoW"), hr); + return false; + } + if (!setState(SC_MOVE, !max)) { + const HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); + qWarning() << getSystemErrorMessage(QStringLiteral("SetMenuItemInfoW"), hr); + return false; + } + if (!setState(SC_SIZE, !max)) { + const HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); + qWarning() << getSystemErrorMessage(QStringLiteral("SetMenuItemInfoW"), hr); + return false; + } + if (!setState(SC_MINIMIZE, true)) { + const HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); + qWarning() << getSystemErrorMessage(QStringLiteral("SetMenuItemInfoW"), hr); + return false; + } + if (!setState(SC_MAXIMIZE, !max)) { + const HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); + qWarning() << getSystemErrorMessage(QStringLiteral("SetMenuItemInfoW"), hr); + return false; + } + if (!setState(SC_CLOSE, true)) { + const HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); + qWarning() << getSystemErrorMessage(QStringLiteral("SetMenuItemInfoW"), hr); + return false; + } + if (SetMenuDefaultItem(menu, UINT_MAX, FALSE) == FALSE) { + const HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); + qWarning() << getSystemErrorMessage(QStringLiteral("SetMenuDefaultItem"), hr); + return false; + } + const QPoint roundedPos = pos.toPoint(); + UINT flags = TPM_RETURNCMD; + if (QGuiApplication::isRightToLeft()) { + flags |= TPM_LAYOUTRTL; + } + const auto ret = TrackPopupMenu(menu, flags, roundedPos.x(), roundedPos.y(), 0, hWnd, nullptr); + if (ret != 0) { + if (PostMessageW(hWnd, WM_SYSCOMMAND, ret, 0) == FALSE) { + const HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); + qWarning() << getSystemErrorMessage(QStringLiteral("PostMessageW"), hr); + return false; + } + } + return true; +} + FRAMELESSHELPER_END_NAMESPACE