Sine Striker
2024-05-08 564f33e8b29a6f73050f4da3f843b942aaf0d739
Improve event filter handling
6个文件已修改
1个文件已添加
143 ■■■■■ 已修改文件
src/core/CMakeLists.txt 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/contexts/abstractwindowcontext.cpp 49 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/contexts/abstractwindowcontext_p.h 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/contexts/win32windowcontext.cpp 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/qwkglobal.cpp 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/qwkglobal_p.h 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/widgets/widgetwindowagent_win.cpp 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/CMakeLists.txt
@@ -6,6 +6,7 @@
set(_src
    qwkglobal.h
    qwkglobal_p.h
    qwkglobal.cpp
    windowagentbase.h
    windowagentbase_p.h
    windowagentbase.cpp
src/core/contexts/abstractwindowcontext.cpp
@@ -12,39 +12,6 @@
namespace QWK {
    namespace {
        class WindowEventFilter : public QObject {
        public:
            explicit WindowEventFilter(QWindow *window, AbstractWindowContext *ctx,
                                       QObject *parent = nullptr)
                : QObject(parent), ctx(ctx), window(window) {
                if (window)
                    window->installEventFilter(this);
            }
            inline void setWindow(QWindow *win) {
                if (auto oldWin = window.data(); oldWin) {
                    oldWin->removeEventFilter(this);
                }
                window = win;
                if (win) {
                    win->installEventFilter(this);
                }
            }
        protected:
            bool eventFilter(QObject *obj, QEvent *event) override {
                return ctx->sharedDispatch(obj, event);
            }
        protected:
            AbstractWindowContext *ctx;
            QPointer<QWindow> window;
        };
    }
    AbstractWindowContext::AbstractWindowContext() = default;
    AbstractWindowContext::~AbstractWindowContext() = default;
@@ -56,7 +23,6 @@
        m_host = host;
        m_delegate.reset(delegate);
        m_winIdChangeEventFilter.reset(delegate->createWinIdEventFilter(host, this));
        m_windowEventFilter = std::make_unique<WindowEventFilter>(m_windowHandle, this);
        notifyWinIdChange();
    }
@@ -238,17 +204,17 @@
        // platform window will be removed, and the WinId will be set to 0. After that, when the
        // QWidget is shown again, the whole things will be recreated again.
        // As a result, we must update our WindowContext each time the WinId changes.
        if (m_windowHandle) {
            removeEventFilter(m_windowHandle);
        }
        m_windowHandle = m_delegate->hostWindow(m_host);
        auto windowEventFilter = static_cast<WindowEventFilter *>(m_windowEventFilter.get());
        windowEventFilter->setWindow(nullptr);
        if (oldWinId != m_windowId) {
            winIdChanged(m_windowId, oldWinId);
        }
        if (m_windowHandle) {
            windowEventFilter->setWindow(m_windowHandle);
            m_windowHandle->installEventFilter(this);
            // Refresh window attributes
            auto attributes = m_windowAttributes;
@@ -299,6 +265,13 @@
        return true;
    }
    bool AbstractWindowContext::eventFilter(QObject *obj, QEvent *event) {
        if (obj == m_windowHandle && sharedDispatch(obj, event)) {
            return true;
        }
        return QObject::eventFilter(obj, event);
    }
    bool AbstractWindowContext::windowAttributeChanged(const QString &key,
                                                       const QVariant &attribute,
                                                       const QVariant &oldAttribute) {
src/core/contexts/abstractwindowcontext_p.h
@@ -83,6 +83,9 @@
        virtual bool setWindowAttribute(const QString &key, const QVariant &attribute);
    protected:
        bool eventFilter(QObject *obj, QEvent *event) override;
    protected:
        virtual void winIdChanged(WId winId, WId oldWinId) = 0;
        virtual bool windowAttributeChanged(const QString &key, const QVariant &attribute,
                                            const QVariant &oldAttribute);
@@ -90,7 +93,7 @@
    protected:
        QObject *m_host{};
        std::unique_ptr<WindowItemDelegate> m_delegate;
        QWindow *m_windowHandle{};
        QPointer<QWindow> m_windowHandle;
        WId m_windowId{};
        QSet<const QObject *> m_hitTestVisibleItems;
@@ -102,8 +105,6 @@
        std::array<QObject *, WindowAgentBase::Close + 1> m_systemButtons{};
        QVariantHash m_windowAttributes;
        std::unique_ptr<QObject> m_windowEventFilter;
        std::unique_ptr<WinIdChangeEventFilter> m_winIdChangeEventFilter;
    };
src/core/contexts/win32windowcontext.cpp
@@ -699,9 +699,9 @@
                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
                std::ignore = showSystemMenu_sys(hWnd, qpoint2point(nativeGlobalPos), false,
                                                 m_delegate->isHostSizeFixed(m_host));
@@ -1263,7 +1263,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
@@ -1563,8 +1563,8 @@
                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 isTitleBar = isInTitleBarDraggableArea(qtScenePos);
@@ -2104,8 +2104,8 @@
        switch (message) {
            case WM_RBUTTONUP: {
                const POINT nativeLocalPos = getNativePosFromMouse();
                const QPoint qtScenePos =
                    QHighDpi::fromNativeLocalPosition(point2qpoint(nativeLocalPos), m_windowHandle);
                const QPoint qtScenePos = QHighDpi::fromNativeLocalPosition(
                    point2qpoint(nativeLocalPos), m_windowHandle.data());
                WindowAgentBase::SystemButton sysButtonType = WindowAgentBase::Unknown;
                if (isInTitleBarDraggableArea(qtScenePos) ||
                    (isInSystemButtons(qtScenePos, &sysButtonType) &&
@@ -2217,7 +2217,7 @@
                    POINT nativeLocalPos = mouseClickPos.value();
                    ::ScreenToClient(hWnd, &nativeLocalPos);
                    QPoint qtScenePos = QHighDpi::fromNativeLocalPosition(
                        point2qpoint(nativeLocalPos), m_windowHandle);
                        point2qpoint(nativeLocalPos), m_windowHandle.data());
                    WindowAgentBase::SystemButton sysButtonType = WindowAgentBase::Unknown;
                    if (isInSystemButtons(qtScenePos, &sysButtonType) &&
                        sysButtonType == WindowAgentBase::WindowIcon) {
src/core/qwkglobal.cpp
New file
@@ -0,0 +1,50 @@
// Copyright (C) 2023-2024 Stdware Collections (https://www.github.com/stdware)
// Copyright (C) 2021-2023 wangwenx190 (Yuhang Zhao)
// SPDX-License-Identifier: Apache-2.0
#include "qwkglobal_p.h"
#include <QtCore/QCoreApplication>
#include <QtCore/private/qobject_p.h>
namespace QWK {
    class HackedObject : public QObject {
    public:
        QObjectPrivate *d_func() const {
            return static_cast<QObjectPrivate *>(d_ptr.data());
        }
    };
    bool forwardObjectEventFilters(QObject *currentFilter, QObject *receiver, QEvent *event) {
        // https://github.com/qt/qtbase/blob/e26a87f1ecc40bc8c6aa5b889fce67410a57a702/src/corelib/kernel/qcoreapplication.cpp#L1244
        // Send the event through the rest event filters
        auto d = static_cast<HackedObject *>(receiver)->d_func();
        bool findCurrent = false;
        if (receiver != QCoreApplication::instance() && d->extraData) {
            for (qsizetype i = 0; i < d->extraData->eventFilters.size(); ++i) {
                QObject *obj = d->extraData->eventFilters.at(i);
                if (!findCurrent) {
                    if (obj == currentFilter) {
                        findCurrent = true; // Will start to filter from the next one
                    }
                    continue;
                }
                if (!obj)
                    continue;
                if (static_cast<HackedObject *>(obj)->d_func()->threadData.loadRelaxed() !=
                    d->threadData.loadRelaxed()) {
                    qWarning(
                        "QCoreApplication: Object event filter cannot be in a different thread.");
                    continue;
                }
                if (obj->eventFilter(receiver, event))
                    return true;
            }
        }
        return false;
    }
}
src/core/qwkglobal_p.h
@@ -62,6 +62,10 @@
        return event->screenPos().toPoint();
#endif
    }
    // Be careful when apply this function to a widget
    QWK_CORE_EXPORT bool forwardObjectEventFilters(QObject *currentFilter, QObject *receiver,
                                                   QEvent *event);
}
#endif // QWKGLOBAL_P_H
src/widgets/widgetwindowagent_win.cpp
@@ -8,6 +8,8 @@
#include <QtCore/QDateTime>
#include <QtGui/QPainter>
#include <QtCore/private/qcoreapplication_p.h>
#include <QWKCore/qwindowkit_windows.h>
#include <QWKCore/private/qwkglobal_p.h>
#include <QWKCore/private/windows10borderhandler_p.h>
@@ -62,8 +64,13 @@
        }
        inline void forwardEventToWidgetAndDraw(QWidget *w, QEvent *event) {
            // https://github.com/qt/qtbase/blob/e26a87f1ecc40bc8c6aa5b889fce67410a57a702/src/widgets/kernel/qapplication.cpp#L3286
            // Deliver the event
            if (!forwardObjectEventFilters(ctx, w, event)) {
            // Let the widget paint first
            static_cast<QObject *>(w)->event(event);
                std::ignore = static_cast<QObject *>(w)->event(event);
                QCoreApplicationPrivate::setEventSpontaneous(event, false);
            }
            // Due to the timer or user action, Qt will repaint some regions spontaneously,
            // even if there is no WM_PAINT message, we must wait for it to finish painting
@@ -72,8 +79,13 @@
        }
        inline void forwardEventToWindowAndDraw(QWindow *window, QEvent *event) {
            // https://github.com/qt/qtbase/blob/e26a87f1ecc40bc8c6aa5b889fce67410a57a702/src/widgets/kernel/qapplication.cpp#L3286
            // Deliver the event;
            if (!forwardObjectEventFilters(ctx, window, event)) {
            // Let Qt paint first
            static_cast<QObject *>(window)->event(event);
                std::ignore = static_cast<QObject *>(window)->event(event);
                QCoreApplicationPrivate::setEventSpontaneous(event, false);
            }
            // Upon receiving the WM_PAINT message, Qt will repaint the entire view, and we
            // must wait for it to finish painting before drawing this top border area.