From 2d08f989b16dad059d42c94e3a2cdccdbd3c379e Mon Sep 17 00:00:00 2001
From: Sine Striker <trueful@163.com>
Date: 周一, 04 12月 2023 03:38:52 +0800
Subject: [PATCH] Add more comments

---
 src/core/corewindowagent.cpp             |   10 +-
 src/core/corewindowagent_p.h             |    2 
 src/core/contexts/win32windowcontext_p.h |   11 ++-
 src/widgets/widgetwindowagent.cpp        |   14 ++--
 src/core/contexts/win32windowcontext.cpp |   83 ++++++++++++++++++---------
 src/quick/quickwindowagent.cpp           |   14 ++--
 6 files changed, 82 insertions(+), 52 deletions(-)

diff --git a/src/core/contexts/win32windowcontext.cpp b/src/core/contexts/win32windowcontext.cpp
index a2f885b..a901cae 100644
--- a/src/core/contexts/win32windowcontext.cpp
+++ b/src/core/contexts/win32windowcontext.cpp
@@ -17,24 +17,6 @@
 
     static WNDPROC g_qtWindowProc = nullptr; // Original Qt window proc function
 
-    static bool g_lastMessageHandled = false;
-
-    static LRESULT g_lastMessageResult = false;
-
-    class WindowsNativeEventFilter : public QAbstractNativeEventFilter {
-    public:
-        bool nativeEventFilter(const QByteArray &eventType, void *message,
-                               QT_NATIVE_EVENT_RESULT_TYPE *result) override {
-            if (g_lastMessageHandled) {
-                *result = static_cast<QT_NATIVE_EVENT_RESULT_TYPE>(g_lastMessageResult);
-                return true;
-            }
-            return false;
-        }
-    };
-
-    static WindowsNativeEventFilter *g_nativeFilter = nullptr;
-
     static inline QPoint fromNativeLocalPosition(const QWindow *window, const QPoint &point) {
 #if 1
         return QHighDpi::fromNativeLocalPosition(point, window);
@@ -105,6 +87,44 @@
         return true;
     }
 
+    // https://github.com/qt/qtbase/blob/e26a87f1ecc40bc8c6aa5b889fce67410a57a702/src/plugins/platforms/windows/qwindowscontext.cpp#L1556
+    // In QWindowsContext::windowsProc(), the messages will be passed to all global native event
+    // filters, but because we have already filtered the messages in the hook WndProc function for
+    // convenience, Qt does not know we may have already process the messages and thus will call
+    // DefWindowProc(). Consequently, we have to add a global native filter that forwards the result
+    // of the hook function, telling Qt whether we have filtered the events before. Since Qt only
+    // handles Windows window messages in the main thread, it is safe to do so.
+    class WindowsNativeEventFilter : public QAbstractNativeEventFilter {
+    public:
+        bool nativeEventFilter(const QByteArray &eventType, void *message,
+                               QT_NATIVE_EVENT_RESULT_TYPE *result) override {
+            if (lastMessageHandled) {
+                *result = static_cast<QT_NATIVE_EVENT_RESULT_TYPE>(lastMessageResult);
+                return true;
+            }
+            return false;
+        }
+
+        static bool lastMessageHandled;
+        static LRESULT lastMessageResult;
+        static WindowsNativeEventFilter *instance;
+
+        static inline void install() {
+            instance = new WindowsNativeEventFilter();
+            qApp->installNativeEventFilter(instance);
+        }
+
+        static inline void uninstall() {
+            qApp->removeNativeEventFilter(instance);
+            delete instance;
+            instance = nullptr;
+        }
+    };
+
+    bool WindowsNativeEventFilter::lastMessageHandled = false;
+    LRESULT WindowsNativeEventFilter::lastMessageResult = 0;
+    WindowsNativeEventFilter *WindowsNativeEventFilter::instance = nullptr;
+
     // https://github.com/qt/qtbase/blob/e26a87f1ecc40bc8c6aa5b889fce67410a57a702/src/plugins/platforms/windows/qwindowscontext.cpp#L1025
     // We can see from the source code that Qt will filter out some messages first and then send the
     // unfiltered messages to the event dispatcher. To activate the Snap Layout feature on Windows
@@ -171,7 +191,9 @@
         }
 
         // Try hooked procedure and save result
-        g_lastMessageHandled = ctx->windowProc(hWnd, message, wParam, lParam, &g_lastMessageResult);
+        auto &handled = WindowsNativeEventFilter::lastMessageHandled;
+        auto &result = WindowsNativeEventFilter::lastMessageResult;
+        handled = ctx->windowProc(hWnd, message, wParam, lParam, &result);
 
         // TODO: Determine whether to show system menu
         // ...
@@ -190,11 +212,9 @@
         if (auto hWnd = reinterpret_cast<HWND>(windowId); hWnd) {
             g_wndProcHash->remove(hWnd);
 
-            // Remove event filter if the last window is destroyed
+            // Remove event filter if the all windows has been destroyed
             if (g_wndProcHash->empty()) {
-                qApp->removeNativeEventFilter(g_nativeFilter);
-                delete g_nativeFilter;
-                g_nativeFilter = nullptr;
+                WindowsNativeEventFilter::uninstall();
             }
         }
     }
@@ -214,9 +234,8 @@
         ::SetWindowLongPtrW(hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(QWKHookedWndProc));
 
         // Install global native event filter
-        if (!g_nativeFilter) {
-            g_nativeFilter = new WindowsNativeEventFilter();
-            qApp->installNativeEventFilter(g_nativeFilter);
+        if (!WindowsNativeEventFilter::instance) {
+            WindowsNativeEventFilter::install();
         }
 
         // Cache window ID
@@ -411,7 +430,7 @@
     }
 
     bool Win32WindowContext::snapLayoutHandler(HWND hWnd, UINT message, WPARAM wParam,
-                                                     LPARAM lParam, LRESULT *result) {
+                                               LPARAM lParam, LRESULT *result) {
         switch (message) {
             case WM_MOUSELEAVE: {
                 if (!isTaggedMessage(wParam)) {
@@ -429,6 +448,9 @@
                                                                        GET_Y_LPARAM(dwScreenPos)));
                     auto dummy = CoreWindowAgent::Unknown;
                     if (isInSystemButtons(qtScenePos, &dummy)) {
+                        // We must record whether the last WM_MOUSELEAVE was filtered, because if
+                        // Qt does not receive this message it will not call TrackMouseEvent()
+                        // again, resulting in the client area not responding to any mouse event.
                         mouseLeaveBlocked = true;
                         *result = FALSE;
                         return true;
@@ -439,7 +461,10 @@
             }
 
             case WM_MOUSEMOVE: {
-                if ((lastHitTestResult != WindowPart::ChromeButton) && mouseLeaveBlocked) {
+                // At appropriate time, we will call TrackMouseEvent() for Qt. Simultaneously,
+                // we unset `mouseLeaveBlocked` mark and pretend as if Qt has received
+                // WM_MOUSELEAVE.
+                if (lastHitTestResult != WindowPart::ChromeButton && mouseLeaveBlocked) {
                     mouseLeaveBlocked = false;
                     std::ignore = requestForMouseLeaveMessage(hWnd, false);
                 }
@@ -479,7 +504,7 @@
                     // comes, so we reset it when we receive a WM_NCMOUSEMOVE.
 
                     // If the mouse is entering the client area, there must be a WM_NCHITTEST
-                    // setting it to `Client` before the WM_NCMOUSELEAVE comes; If the mouse is
+                    // setting it to `Client` before the WM_NCMOUSELEAVE comes; if the mouse is
                     // leaving the window, current window part remains as `Outside`.
                     lastHitTestResult = WindowPart::Outside;
                 }
diff --git a/src/core/contexts/win32windowcontext_p.h b/src/core/contexts/win32windowcontext_p.h
index 52f4433..b99314e 100644
--- a/src/core/contexts/win32windowcontext_p.h
+++ b/src/core/contexts/win32windowcontext_p.h
@@ -25,17 +25,22 @@
         bool setup() override;
 
         bool windowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result);
+
+        // In order to perfectly apply Windows 11 Snap Layout into the Qt window, we need to
+        // intercept and simulate most of the  mouse events, so that the processing logic
+        // is quite complex. Simultaneously, in order to make the handling code of other
+        // Windows messages clearer, we have separated them into this function.
         bool snapLayoutHandler(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam,
                                LRESULT *result);
 
     protected:
         WId windowId = 0;
 
-        // Store the last hit test result, it's helpful to handle WM_MOUSEMOVE and WM_NCMOUSELEAVE.
+        // The last hit test result, helpful to handle WM_MOUSEMOVE and WM_NCMOUSELEAVE.
         WindowPart lastHitTestResult = WindowPart::Outside;
 
-        // True if we blocked a WM_MOUSELEAVE when mouse moves on chrome button, false when a
-        // WM_MOUSELEAVE comes or we manually call TrackMouseEvent().
+        // Whether the last mouse leave message is blocked, mainly for handling the unexpected
+        // WM_MOUSELEAVE.
         bool mouseLeaveBlocked = false;
     };
 
diff --git a/src/core/corewindowagent.cpp b/src/core/corewindowagent.cpp
index abcd6fb..78ed335 100644
--- a/src/core/corewindowagent.cpp
+++ b/src/core/corewindowagent.cpp
@@ -13,7 +13,7 @@
 
 namespace QWK {
 
-    CoreWindowAgentPrivate::CoreWindowAgentPrivate() : q_ptr(nullptr), eventHandler(nullptr) {
+    CoreWindowAgentPrivate::CoreWindowAgentPrivate() : q_ptr(nullptr), context(nullptr) {
     }
 
     CoreWindowAgentPrivate::~CoreWindowAgentPrivate() = default;
@@ -38,7 +38,7 @@
             delete handler;
             return false;
         }
-        eventHandler.reset(handler);
+        context.reset(handler);
         return true;
     }
 
@@ -46,12 +46,12 @@
 
     void CoreWindowAgent::showSystemMenu(const QPoint &pos) {
         Q_D(CoreWindowAgent);
-        d->eventHandler->showSystemMenu(pos);
+        d->context->showSystemMenu(pos);
     }
 
     void CoreWindowAgent::startSystemMove(const QPoint &pos) {
         Q_D(CoreWindowAgent);
-        auto win = d->eventHandler->window();
+        auto win = d->context->window();
         if (!win) {
             return;
         }
@@ -62,7 +62,7 @@
 
     void CoreWindowAgent::startSystemResize(Qt::Edges edges, const QPoint &pos) {
         Q_D(CoreWindowAgent);
-        auto win = d->eventHandler->window();
+        auto win = d->context->window();
         if (!win) {
             return;
         }
diff --git a/src/core/corewindowagent_p.h b/src/core/corewindowagent_p.h
index 013ccbe..5916d89 100644
--- a/src/core/corewindowagent_p.h
+++ b/src/core/corewindowagent_p.h
@@ -18,7 +18,7 @@
 
         bool setup(QWindow *window, WindowItemDelegate *delegate);
 
-        std::unique_ptr<AbstractWindowContext> eventHandler;
+        std::unique_ptr<AbstractWindowContext> context;
 
         Q_DISABLE_COPY_MOVE(CoreWindowAgentPrivate)
     };
diff --git a/src/quick/quickwindowagent.cpp b/src/quick/quickwindowagent.cpp
index 83a7e9b..aae49f7 100644
--- a/src/quick/quickwindowagent.cpp
+++ b/src/quick/quickwindowagent.cpp
@@ -43,27 +43,27 @@
 
     bool QuickWindowAgent::isHitTestVisible(QQuickItem *item) const {
         Q_D(const QuickWindowAgent);
-        return d->eventHandler->isHitTestVisible(item);
+        return d->context->isHitTestVisible(item);
     }
 
     void QuickWindowAgent::setHitTestVisible(QQuickItem *item, bool visible) {
         Q_D(QuickWindowAgent);
-        d->eventHandler->setHitTestVisible(item, visible);
+        d->context->setHitTestVisible(item, visible);
     }
 
     void QuickWindowAgent::setHitTestVisible(const QRect &rect, bool visible) {
         Q_D(QuickWindowAgent);
-        d->eventHandler->setHitTestVisible(rect, visible);
+        d->context->setHitTestVisible(rect, visible);
     }
 
     QQuickItem *QuickWindowAgent::systemButton(SystemButton button) const {
         Q_D(const QuickWindowAgent);
-        return static_cast<QQuickItem *>(d->eventHandler->systemButton(button));
+        return static_cast<QQuickItem *>(d->context->systemButton(button));
     }
 
     void QuickWindowAgent::setSystemButton(SystemButton button, QQuickItem *item) {
         Q_D(QuickWindowAgent);
-        if (!d->eventHandler->setSystemButton(button, item)) {
+        if (!d->context->setSystemButton(button, item)) {
             return;
         }
         Q_EMIT systemButtonChanged(button, item);
@@ -71,12 +71,12 @@
 
     QQuickItem *QuickWindowAgent::titleBar() const {
         Q_D(const QuickWindowAgent);
-        return static_cast<QQuickItem *>(d->eventHandler->titleBar());
+        return static_cast<QQuickItem *>(d->context->titleBar());
     }
 
     void QuickWindowAgent::setTitleBar(QQuickItem *item) {
         Q_D(QuickWindowAgent);
-        if (!d->eventHandler->setTitleBar(item)) {
+        if (!d->context->setTitleBar(item)) {
             return;
         }
         Q_EMIT titleBarWidgetChanged(item);
diff --git a/src/widgets/widgetwindowagent.cpp b/src/widgets/widgetwindowagent.cpp
index 1bf0b4e..252213e 100644
--- a/src/widgets/widgetwindowagent.cpp
+++ b/src/widgets/widgetwindowagent.cpp
@@ -42,27 +42,27 @@
 
     bool WidgetWindowAgent::isHitTestVisible(QWidget *w) const {
         Q_D(const WidgetWindowAgent);
-        return d->eventHandler->isHitTestVisible(w);
+        return d->context->isHitTestVisible(w);
     }
 
     void WidgetWindowAgent::setHitTestVisible(QWidget *w, bool visible) {
         Q_D(WidgetWindowAgent);
-        d->eventHandler->setHitTestVisible(w, visible);
+        d->context->setHitTestVisible(w, visible);
     }
 
     void WidgetWindowAgent::setHitTestVisible(const QRect &rect, bool visible) {
         Q_D(WidgetWindowAgent);
-        d->eventHandler->setHitTestVisible(rect, visible);
+        d->context->setHitTestVisible(rect, visible);
     }
 
     QWidget *WidgetWindowAgent::systemButton(CoreWindowAgent::SystemButton button) const {
         Q_D(const WidgetWindowAgent);
-        return static_cast<QWidget *>(d->eventHandler->systemButton(button));
+        return static_cast<QWidget *>(d->context->systemButton(button));
     }
 
     void WidgetWindowAgent::setSystemButton(CoreWindowAgent::SystemButton button, QWidget *w) {
         Q_D(WidgetWindowAgent);
-        if (!d->eventHandler->setSystemButton(button, w)) {
+        if (!d->context->setSystemButton(button, w)) {
             return;
         }
         Q_EMIT systemButtonChanged(button, w);
@@ -70,12 +70,12 @@
 
     QWidget *WidgetWindowAgent::titleBar() const {
         Q_D(const WidgetWindowAgent);
-        return static_cast<QWidget *>(d->eventHandler->titleBar());
+        return static_cast<QWidget *>(d->context->titleBar());
     }
 
     void WidgetWindowAgent::setTitleBar(QWidget *w) {
         Q_D(WidgetWindowAgent);
-        if (!d->eventHandler->setTitleBar(w)) {
+        if (!d->context->setTitleBar(w)) {
             return;
         }
         Q_EMIT titleBarWidgetChanged(w);

--
Gitblit v1.9.1