From a9c357c40d29e9a7ea59ffa80214657ef58c7dbe Mon Sep 17 00:00:00 2001
From: Zhao Yuhang <2546789017@qq.com>
Date: 周一, 27 5月 2024 23:18:42 +0800
Subject: [PATCH] Fix typo

---
 src/core/contexts/win32windowcontext.cpp |  352 ++++++++++++++++++++++++++++++++++++++++++----------------
 1 files changed, 256 insertions(+), 96 deletions(-)

diff --git a/src/core/contexts/win32windowcontext.cpp b/src/core/contexts/win32windowcontext.cpp
index 4fda1eb..3fa910e 100644
--- a/src/core/contexts/win32windowcontext.cpp
+++ b/src/core/contexts/win32windowcontext.cpp
@@ -33,15 +33,13 @@
 #include "qwkglobal_p.h"
 #include "qwkwindowsextra_p.h"
 
-// https://github.com/qt/qtbase/blob/6.6.1/src/plugins/platforms/windows/qwindowswindow.cpp#L2791
-// https://github.com/qt/qtbase/blob/6.6.1/src/plugins/platforms/windows/qwindowswindow.cpp#L3321
-// This issue exists only in Qt 6.6.1, and was introduced by QTBUG-113736 patch and fixed by
-// QTBUG-117704 patch.
-#if !QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDERS) && QT_VERSION == QT_VERSION_CHECK(6, 6, 1)
-#  define QTBUG_113736_WORKAROUND
-#endif
-
 namespace QWK {
+
+    enum IconButtonClickLevelFlag {
+        IconButtonClicked = 1,
+        IconButtonDoubleClicked = 2,
+        IconButtonTriggersClose = 4,
+    };
 
     // The thickness of an auto-hide taskbar in pixels.
     static constexpr const quint8 kAutoHideTaskBarThickness = 2;
@@ -83,6 +81,8 @@
 
     static void setInternalWindowFrameMargins(QWindow *window, const QMargins &margins) {
         const QVariant marginsVar = QVariant::fromValue(margins);
+
+        // TODO: Add comments
         window->setProperty("_q_windowsCustomMargins", marginsVar);
 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
         if (QPlatformWindow *platformWindow = window->handle()) {
@@ -126,6 +126,36 @@
                        SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER);
     }
 
+    static inline bool isFullScreen(HWND hwnd) {
+        RECT windowRect{};
+        ::GetWindowRect(hwnd, &windowRect);
+        // Compare to the full area of the screen, not the work area.
+        return (windowRect == getMonitorForWindow(hwnd).rcMonitor);
+    }
+
+    static inline bool isMaximized(HWND hwnd) {
+        return ::IsZoomed(hwnd);
+    }
+
+    static inline bool isMinimized(HWND hwnd) {
+        return ::IsIconic(hwnd);
+    }
+
+    static inline bool isWindowNoState(HWND hwnd) {
+#if 0
+        WINDOWPLACEMENT wp{};
+        wp.length = sizeof(wp);
+        ::GetWindowPlacement(hwnd, &wp);
+        return ((wp.showCmd == SW_NORMAL) || (wp.showCmd == SW_RESTORE));
+#else
+        if (isFullScreen(hwnd)) {
+            return false;
+        }
+        const auto style = static_cast<DWORD>(::GetWindowLongPtrW(hwnd, GWL_STYLE));
+        return (!(style & (WS_MINIMIZE | WS_MAXIMIZE)));
+#endif
+    }
+
     static inline void bringWindowToFront(HWND hwnd) {
         HWND oldForegroundWindow = ::GetForegroundWindow();
         if (!oldForegroundWindow) {
@@ -137,7 +167,7 @@
         if (!::IsWindowVisible(hwnd)) {
             ::ShowWindow(hwnd, SW_SHOW);
         }
-        if (IsMinimized(hwnd)) {
+        if (isMinimized(hwnd)) {
             // Restore the window if it is minimized.
             ::ShowWindow(hwnd, SW_RESTORE);
             // Once we've been restored, throw us on the active monitor.
@@ -172,28 +202,6 @@
         ::SetActiveWindow(hwnd);
         // Throw us on the active monitor.
         moveWindowToMonitor(hwnd, activeMonitor);
-    }
-
-    static inline bool isFullScreen(HWND hwnd) {
-        RECT windowRect{};
-        ::GetWindowRect(hwnd, &windowRect);
-        // Compare to the full area of the screen, not the work area.
-        return (windowRect == getMonitorForWindow(hwnd).rcMonitor);
-    }
-
-    static inline bool isWindowNoState(HWND hwnd) {
-#if 0
-        WINDOWPLACEMENT wp{};
-        wp.length = sizeof(wp);
-        ::GetWindowPlacement(hwnd, &wp);
-        return ((wp.showCmd == SW_NORMAL) || (wp.showCmd == SW_RESTORE));
-#else
-        if (isFullScreen(hwnd)) {
-            return false;
-        }
-        const auto style = static_cast<DWORD>(::GetWindowLongPtrW(hwnd, GWL_STYLE));
-        return (!(style & (WS_MINIMIZE | WS_MAXIMIZE)));
-#endif
     }
 
     static void syncPaintEventWithDwm() {
@@ -241,17 +249,18 @@
         apis.ptimeEndPeriod(ms_granularity);
     }
 
-    static void showSystemMenu2(HWND hWnd, const POINT &pos, const bool selectFirstEntry,
-                                const bool fixedSize) {
+    // Returns false if the menu is canceled
+    static bool showSystemMenu_sys(HWND hWnd, const POINT &pos, const bool selectFirstEntry,
+                                   const bool fixedSize) {
         HMENU hMenu = ::GetSystemMenu(hWnd, FALSE);
         if (!hMenu) {
             // The corresponding window doesn't have a system menu, most likely due to the
             // lack of the "WS_SYSMENU" window style. This situation should not be treated
             // as an error so just ignore it and return early.
-            return;
+            return true;
         }
 
-        const bool maxOrFull = IsMaximized(hWnd) || isFullScreen(hWnd);
+        const bool maxOrFull = isMaximized(hWnd) || isFullScreen(hWnd);
         ::EnableMenuItem(hMenu, SC_CLOSE, (MF_BYCOMMAND | MFS_ENABLED));
         ::EnableMenuItem(hMenu, SC_MAXIMIZE,
                          (MF_BYCOMMAND | ((maxOrFull || fixedSize) ? MFS_DISABLED : MFS_ENABLED)));
@@ -292,7 +301,8 @@
         // Popup the system menu at the required position.
         const auto result = ::TrackPopupMenu(
             hMenu,
-            (TPM_RETURNCMD | (QGuiApplication::isRightToLeft() ? TPM_RIGHTALIGN : TPM_LEFTALIGN)),
+            (TPM_RETURNCMD | (QGuiApplication::isRightToLeft() ? TPM_RIGHTALIGN : TPM_LEFTALIGN) |
+             TPM_RIGHTBUTTON),
             pos.x, pos.y, 0, hWnd, nullptr);
 
         // Unhighlight the first menu item after the popup menu is closed, otherwise it will keep
@@ -301,11 +311,12 @@
 
         if (!result) {
             // The user canceled the menu, no need to continue.
-            return;
+            return false;
         }
 
         // Send the command that the user chooses to the corresponding window.
         ::PostMessageW(hWnd, WM_SYSCOMMAND, result, 0);
+        return true;
     }
 
     static inline Win32WindowContext::WindowPart getHitWindowPart(int hitTestResult) {
@@ -490,17 +501,38 @@
                 return false;
             }
 
-            // https://github.com/qt/qtbase/blob/e26a87f1ecc40bc8c6aa5b889fce67410a57a702/src/plugins/platforms/windows/qwindowscontext.cpp#L1546
-            // Qt needs to refer to the WM_NCCALCSIZE message data that hasn't been processed, so we
-            // have to process it after Qt acquires the initial data.
             auto msg = static_cast<const MSG *>(message);
-            if (msg->message == WM_NCCALCSIZE && lastMessageContext) {
-                LRESULT res;
-                if (lastMessageContext->nonClientCalcSizeHandler(msg->hwnd, msg->message,
-                                                                 msg->wParam, msg->lParam, &res)) {
-                    *result = decltype(*result)(res);
-                    return true;
+            switch (msg->message) {
+                case WM_NCCALCSIZE: {
+                    // https://github.com/qt/qtbase/blob/e26a87f1ecc40bc8c6aa5b889fce67410a57a702/src/plugins/platforms/windows/qwindowscontext.cpp#L1546
+                    // Qt needs to refer to the WM_NCCALCSIZE message data that hasn't been
+                    // processed, so we have to process it after Qt acquires the initial data.
+                    if (lastMessageContext) {
+                        LRESULT res;
+                        if (lastMessageContext->nonClientCalcSizeHandler(
+                                msg->hwnd, msg->message, msg->wParam, msg->lParam, &res)) {
+                            *result = decltype(*result)(res);
+                            return true;
+                        }
+                    }
+                    break;
                 }
+
+                    // case WM_NCHITTEST: {
+                    //     // The child window must return HTTRANSPARENT when processing
+                    //     WM_NCHITTEST for
+                    //     // the parent window to receive WM_NCHITTEST.
+                    //     if (!lastMessageContext) {
+                    //         auto rootHWnd = ::GetAncestor(msg->hwnd, GA_ROOT);
+                    //         if (rootHWnd != msg->hwnd) {
+                    //             if (auto ctx = g_wndProcHash->value(rootHWnd)) {
+                    //                 *result = HTTRANSPARENT;
+                    //                 return true;
+                    //             }
+                    //         }
+                    //     }
+                    //     break;
+                    // }
             }
             return false;
         }
@@ -589,18 +621,21 @@
             return ::DefWindowProcW(hWnd, message, wParam, lParam);
         }
 
+        WindowsNativeEventFilter::lastMessageContext = ctx;
+        const auto &contextCleaner = qScopeGuard([]() {
+            WindowsNativeEventFilter::lastMessageContext = nullptr; //
+        });
+
         // Since Qt does the necessary processing of the WM_NCCALCSIZE message, we need to
         // forward it right away and process it in our native event filter.
         if (message == WM_NCCALCSIZE) {
-            WindowsNativeEventFilter::lastMessageContext = ctx;
-            LRESULT result = ::CallWindowProcW(g_qtWindowProc, hWnd, message, wParam, lParam);
-            WindowsNativeEventFilter::lastMessageContext = nullptr;
-            return result;
+            return ::CallWindowProcW(g_qtWindowProc, hWnd, message, wParam, lParam);
         }
 
         // Try hooked procedure and save result
         LRESULT result;
         if (ctx->windowProc(hWnd, message, wParam, lParam, &result)) {
+            // https://github.com/stdware/qwindowkit/issues/45
             // Forward the event to user-defined native event filters, there may be some messages
             // that need to be processed by the user.
             std::ignore =
@@ -613,20 +648,10 @@
     }
 
     static inline void addManagedWindow(QWindow *window, HWND hWnd, Win32WindowContext *ctx) {
-#ifndef QTBUG_113736_WORKAROUND
-        const auto margins = [](HWND hWnd) -> QMargins {
-            const auto titleBarHeight = int(getTitleBarHeight(hWnd));
-            if (isSystemBorderEnabled()) {
-                return {0, -titleBarHeight, 0, 0};
-            } else {
-                const auto frameSize = int(getResizeBorderThickness(hWnd));
-                return {-frameSize, -titleBarHeight, -frameSize, -frameSize};
-            }
-        }(hWnd);
-
-        // Inform Qt we want and have set custom margins
-        setInternalWindowFrameMargins(window, margins);
-#endif
+        if (isSystemBorderEnabled()) {
+            // Inform Qt we want and have set custom margins
+            setInternalWindowFrameMargins(window, QMargins(0, -int(getTitleBarHeight(hWnd)), 0, 0));
+        }
 
         // Store original window proc
         if (!g_qtWindowProc) {
@@ -685,12 +710,12 @@
                 auto hWnd = reinterpret_cast<HWND>(m_windowId);
 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
                 const QPoint nativeGlobalPos =
-                    QHighDpi::toNativeGlobalPosition(pos, m_windowHandle);
+                    QHighDpi::toNativeGlobalPosition(pos, m_windowHandle.data());
 #else
-                const QPoint nativeGlobalPos = QHighDpi::toNativePixels(pos, m_windowHandle);
+                const QPoint nativeGlobalPos = QHighDpi::toNativePixels(pos, m_windowHandle.data());
 #endif
-                showSystemMenu2(hWnd, qpoint2point(nativeGlobalPos), false,
-                                m_delegate->isHostSizeFixed(m_host));
+                std::ignore = showSystemMenu_sys(hWnd, qpoint2point(nativeGlobalPos), false,
+                                                 isHostSizeFixed());
                 return;
             }
 
@@ -809,6 +834,11 @@
                        : 0;
         }
 
+        if (key == QStringLiteral("title-bar-height")) {
+            return m_windowId
+                       ? int(getTitleBarHeight(reinterpret_cast<HWND>(m_windowId)))
+                       : 0;
+        }
         return AbstractWindowContext::windowAttribute(key);
     }
 
@@ -816,11 +846,12 @@
         // Reset the context data
         mouseLeaveBlocked = false;
         lastHitTestResult = WindowPart::Outside;
+        lastHitTestResultRaw = HTNOWHERE;
 
-#ifdef QTBUG_113736_WORKAROUND
-        m_delegate->setWindowFlags(m_host,
-                                   m_delegate->getWindowFlags(m_host) | Qt::FramelessWindowHint);
-#endif
+        if (!isSystemBorderEnabled()) {
+            m_delegate->setWindowFlags(m_host, m_delegate->getWindowFlags(m_host) |
+                                                   Qt::FramelessWindowHint);
+        }
 
         // If the original window id is valid, remove all resources related
         if (oldWinId) {
@@ -1249,7 +1280,7 @@
                     POINT screenPoint{GET_X_LPARAM(dwScreenPos), GET_Y_LPARAM(dwScreenPos)};
                     ::ScreenToClient(hWnd, &screenPoint);
                     QPoint qtScenePos = QHighDpi::fromNativeLocalPosition(point2qpoint(screenPoint),
-                                                                          m_windowHandle);
+                                                                          m_windowHandle.data());
                     auto dummy = WindowAgentBase::Unknown;
                     if (isInSystemButtons(qtScenePos, &dummy)) {
                         // We must record whether the last WM_MOUSELEAVE was filtered, because if
@@ -1294,9 +1325,8 @@
     case WM_NCPOINTERUP:
 #endif
             case WM_NCMOUSEHOVER: {
-                const WindowPart currentWindowPart = lastHitTestResult;
                 if (message == WM_NCMOUSEMOVE) {
-                    if (currentWindowPart != WindowPart::ChromeButton) {
+                    if (lastHitTestResult != WindowPart::ChromeButton) {
                         // https://github.com/qt/qtbase/blob/e26a87f1ecc40bc8c6aa5b889fce67410a57a702/src/widgets/kernel/qwidgetwindow.cpp#L472
                         // When the mouse press event arrives, QWidgetWindow will implicitly grab
                         // the top widget right under the mouse, and set `qt_button_down` to this
@@ -1355,14 +1385,50 @@
                     }
                 }
 
-                if (currentWindowPart == WindowPart::ChromeButton) {
-                    emulateClientAreaMessage(hWnd, message, wParam, lParam);
+                if (lastHitTestResult == WindowPart::ChromeButton) {
                     if (message == WM_NCMOUSEMOVE) {
                         // ### FIXME FIXME FIXME
                         // ### FIXME: Calling DefWindowProc() here is really dangerous, investigate
                         // how to avoid doing this.
                         // ### FIXME FIXME FIXME
                         *result = ::DefWindowProcW(hWnd, WM_NCMOUSEMOVE, wParam, lParam);
+                        emulateClientAreaMessage(hWnd, message, wParam, lParam);
+                        return true;
+                    }
+
+                    if (lastHitTestResultRaw == HTSYSMENU) {
+                        switch (message) {
+                            case WM_NCLBUTTONDOWN:
+                                if (iconButtonClickLevel == 0) {
+                                    // A message of WM_SYSCOMMAND with SC_MOUSEMENU will be sent by
+                                    // Windows, and the current control flow will be blocked by the
+                                    // menu while Windows will create and execute a new event loop
+                                    // until the menu returns
+                                    iconButtonClickTime = ::GetTickCount64();
+                                    *result = ::DefWindowProcW(hWnd, message, wParam, lParam);
+                                    iconButtonClickTime = 0;
+                                    if (iconButtonClickLevel & IconButtonTriggersClose) {
+                                        ::PostMessageW(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0);
+                                    }
+                                    if (iconButtonClickLevel & IconButtonDoubleClicked) {
+                                        iconButtonClickLevel = 0;
+                                    }
+                                    // Otherwise, no need to reset `iconButtonClickLevel` if not to
+                                    // close, if it has value, there must be another incoming
+                                    // WM_NCLBUTTONDOWN
+                                } else {
+                                    iconButtonClickLevel = 0;
+                                }
+                                break;
+                            case WM_NCLBUTTONDBLCLK:
+                                // A message of WM_SYSCOMMAND with SC_CLOSE will be sent by Windows
+                                *result = ::DefWindowProcW(hWnd, message, wParam, lParam);
+                                break;
+                            default:
+                                *result = FALSE;
+                                emulateClientAreaMessage(hWnd, message, wParam, lParam);
+                                break;
+                        }
                     } else {
                         // According to MSDN, we should return non-zero for X button messages to
                         // indicate we have handled these messages (due to historical reasons), for
@@ -1371,6 +1437,7 @@
                             (((message >= WM_NCXBUTTONDOWN) && (message <= WM_NCXBUTTONDBLCLK))
                                  ? TRUE
                                  : FALSE);
+                        emulateClientAreaMessage(hWnd, message, wParam, lParam);
                     }
                     return true;
                 }
@@ -1500,7 +1567,8 @@
                 // color, our homemade top border can almost have exactly the same
                 // appearance with the system's one.
                 [[maybe_unused]] const auto &hitTestRecorder = qScopeGuard([this, result]() {
-                    lastHitTestResult = getHitWindowPart(int(*result)); //
+                    lastHitTestResultRaw = int(*result);
+                    lastHitTestResult = getHitWindowPart(lastHitTestResultRaw);
                 });
 
                 POINT nativeGlobalPos{GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
@@ -1512,10 +1580,10 @@
                 auto clientWidth = RECT_WIDTH(clientRect);
                 auto clientHeight = RECT_HEIGHT(clientRect);
 
-                QPoint qtScenePos =
-                    QHighDpi::fromNativeLocalPosition(point2qpoint(nativeLocalPos), m_windowHandle);
+                QPoint qtScenePos = QHighDpi::fromNativeLocalPosition(point2qpoint(nativeLocalPos),
+                                                                      m_windowHandle.data());
 
-                bool isFixedSize = m_delegate->isHostSizeFixed(m_host);
+                bool isFixedSize = isHostSizeFixed();
                 bool isTitleBar = isInTitleBarDraggableArea(qtScenePos);
                 bool dontOverrideCursor = false; // ### TODO
 
@@ -1594,7 +1662,7 @@
                 // OK, we are not inside any chrome buttons, try to find out which part of the
                 // window are we hitting.
 
-                bool max = IsMaximized(hWnd);
+                bool max = isMaximized(hWnd);
                 bool full = isFullScreen(hWnd);
                 int frameSize = getResizeBorderThickness(hWnd);
                 bool isTop = (nativeLocalPos.y < frameSize);
@@ -1890,9 +1958,9 @@
             // that's also how most applications customize their title bars on Windows. It's
             // totally OK but since we want to preserve as much original frame as possible,
             // we can't use that solution.
-            const LRESULT hitTestResult = ::DefWindowProcW(hWnd, WM_NCCALCSIZE, wParam, lParam);
-            if ((hitTestResult != HTERROR) && (hitTestResult != HTNOWHERE)) {
-                *result = hitTestResult;
+            const LRESULT originalResult = ::DefWindowProcW(hWnd, WM_NCCALCSIZE, wParam, lParam);
+            if (originalResult != 0) {
+                *result = originalResult;
                 return true;
             }
             // Re-apply the original top from before the size of the default frame was
@@ -1906,7 +1974,7 @@
             clientRect->top = originalTop;
         }
 
-        const bool max = IsMaximized(hWnd);
+        const bool max = isMaximized(hWnd);
         const bool full = isFullScreen(hWnd);
         // We don't need this correction when we're fullscreen. We will
         // have the WS_POPUP size, so we don't have to worry about
@@ -2021,7 +2089,7 @@
             return {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
         };
         const auto getNativeGlobalPosFromKeyboard = [hWnd]() -> POINT {
-            const bool maxOrFull = IsMaximized(hWnd) || isFullScreen(hWnd);
+            const bool maxOrFull = isMaximized(hWnd) || isFullScreen(hWnd);
             const quint32 frameSize = getResizeBorderThickness(hWnd);
             const quint32 horizontalOffset =
                 ((maxOrFull || !isSystemBorderEnabled()) ? 0 : frameSize);
@@ -2049,12 +2117,16 @@
         bool shouldShowSystemMenu = false;
         bool broughtByKeyboard = false;
         POINT nativeGlobalPos{};
+
         switch (message) {
             case WM_RBUTTONUP: {
                 const POINT nativeLocalPos = getNativePosFromMouse();
-                const QPoint qtScenePos =
-                    QHighDpi::fromNativeLocalPosition(point2qpoint(nativeLocalPos), m_windowHandle);
-                if (isInTitleBarDraggableArea(qtScenePos)) {
+                const QPoint qtScenePos = QHighDpi::fromNativeLocalPosition(
+                    point2qpoint(nativeLocalPos), m_windowHandle.data());
+                WindowAgentBase::SystemButton sysButtonType = WindowAgentBase::Unknown;
+                if (isInTitleBarDraggableArea(qtScenePos) ||
+                    (isInSystemButtons(qtScenePos, &sysButtonType) &&
+                     sysButtonType == WindowAgentBase::WindowIcon)) {
                     shouldShowSystemMenu = true;
                     nativeGlobalPos = nativeLocalPos;
                     ::ClientToScreen(hWnd, &nativeGlobalPos);
@@ -2070,10 +2142,20 @@
             }
             case WM_SYSCOMMAND: {
                 const WPARAM filteredWParam = (wParam & 0xFFF0);
-                if ((filteredWParam == SC_KEYMENU) && (lParam == VK_SPACE)) {
-                    shouldShowSystemMenu = true;
-                    broughtByKeyboard = true;
-                    nativeGlobalPos = getNativeGlobalPosFromKeyboard();
+                switch (filteredWParam) {
+                    case SC_MOUSEMENU:
+                        shouldShowSystemMenu = true;
+                        nativeGlobalPos = getNativeGlobalPosFromKeyboard();
+                        break;
+                    case SC_KEYMENU:
+                        if (lParam == VK_SPACE) {
+                            shouldShowSystemMenu = true;
+                            broughtByKeyboard = true;
+                            nativeGlobalPos = getNativeGlobalPosFromKeyboard();
+                        }
+                        break;
+                    default:
+                        break;
                 }
                 break;
             }
@@ -2092,8 +2174,86 @@
                 break;
         }
         if (shouldShowSystemMenu) {
-            showSystemMenu2(hWnd, nativeGlobalPos, broughtByKeyboard,
-                            m_delegate->isHostSizeFixed(m_host));
+            static HHOOK mouseHook = nullptr;
+            static std::optional<POINT> mouseClickPos;
+            static bool mouseDoubleClicked = false;
+            bool mouseHookedLocal = false;
+
+            // The menu is triggered by a click on icon button
+            if (iconButtonClickTime > 0) {
+                POINT menuPos{0, static_cast<LONG>(getTitleBarHeight(hWnd))};
+                if (const auto tb = titleBar()) {
+                    auto titleBarHeight = qreal(m_delegate->mapGeometryToScene(tb).height());
+                    titleBarHeight *= m_windowHandle->devicePixelRatio();
+                    menuPos.y = qRound(titleBarHeight);
+                }
+                ::ClientToScreen(hWnd, &menuPos);
+                nativeGlobalPos = menuPos;
+
+                // Install mouse hook
+                if (!mouseHook) {
+                    mouseHook = ::SetWindowsHookExW(
+                        WH_MOUSE,
+                        [](int nCode, WPARAM wParam, LPARAM lParam) {
+                            if (nCode >= 0) {
+                                switch (wParam) {
+                                    case WM_LBUTTONDBLCLK:
+                                        mouseDoubleClicked = true;
+                                        Q_FALLTHROUGH();
+
+                                        // case WM_POINTERDOWN:
+
+                                    case WM_LBUTTONDOWN: {
+                                        auto pMouseStruct =
+                                            reinterpret_cast<MOUSEHOOKSTRUCT *>(lParam);
+                                        if (pMouseStruct) {
+                                            mouseClickPos = pMouseStruct->pt;
+                                        }
+                                        break;
+                                    }
+                                    default:
+                                        break;
+                                }
+                            }
+                            return ::CallNextHookEx(nullptr, nCode, wParam, lParam);
+                        },
+                        nullptr, ::GetCurrentThreadId());
+                    mouseHookedLocal = true;
+                }
+            }
+
+            bool res =
+                showSystemMenu_sys(hWnd, nativeGlobalPos, broughtByKeyboard, isHostSizeFixed());
+
+            // Uninstall mouse hook and check if it's a double-click
+            if (mouseHookedLocal) {
+                ::UnhookWindowsHookEx(mouseHook);
+
+                // Emulate the Windows icon button's behavior
+                if (!res && mouseClickPos.has_value()) {
+                    POINT nativeLocalPos = mouseClickPos.value();
+                    ::ScreenToClient(hWnd, &nativeLocalPos);
+                    QPoint qtScenePos = QHighDpi::fromNativeLocalPosition(
+                        point2qpoint(nativeLocalPos), m_windowHandle.data());
+                    WindowAgentBase::SystemButton sysButtonType = WindowAgentBase::Unknown;
+                    if (isInSystemButtons(qtScenePos, &sysButtonType) &&
+                        sysButtonType == WindowAgentBase::WindowIcon) {
+                        iconButtonClickLevel |= IconButtonClicked;
+                        if (::GetTickCount64() - iconButtonClickTime <= ::GetDoubleClickTime()) {
+                            iconButtonClickLevel |= IconButtonTriggersClose;
+                        }
+                    }
+                }
+
+                if (mouseDoubleClicked) {
+                    iconButtonClickLevel |= IconButtonDoubleClicked;
+                }
+
+                mouseHook = nullptr;
+                mouseClickPos.reset();
+                mouseDoubleClicked = false;
+            }
+
             // QPA's internal code will handle system menu events separately, and its
             // behavior is not what we would want to see because it doesn't know our
             // window doesn't have any window frame now, so return early here to avoid

--
Gitblit v1.9.1