Sine Striker
2023-12-04 2d08f989b16dad059d42c94e3a2cdccdbd3c379e
Add more comments
6个文件已修改
132 ■■■■■ 已修改文件
src/core/contexts/win32windowcontext.cpp 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/contexts/win32windowcontext_p.h 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/corewindowagent.cpp 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/corewindowagent_p.h 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/quick/quickwindowagent.cpp 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/widgets/widgetwindowagent.cpp 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
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
@@ -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;
                }
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;
    };
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;
        }
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)
    };
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);
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);