Sine Striker
2023-12-18 8b72eabae325c34d8eab1544203993015cc91741
Add win32 winIdChange workaround
14个文件已修改
170 ■■■■■ 已修改文件
src/core/contexts/abstractwindowcontext.cpp 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/contexts/abstractwindowcontext_p.h 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/contexts/cocoawindowcontext.mm 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/contexts/cocoawindowcontext_p.h 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/contexts/qtwindowcontext.cpp 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/contexts/qtwindowcontext_p.h 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/contexts/win32windowcontext.cpp 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/contexts/win32windowcontext_p.h 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/windowagentbase.cpp 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/windowagentbase_p.h 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/quick/quickwindowagent.cpp 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/widgets/widgetwindowagent.cpp 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/widgets/widgetwindowagent_mac.cpp 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/widgets/widgetwindowagent_win.cpp 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/contexts/abstractwindowcontext.cpp
@@ -11,27 +11,17 @@
    AbstractWindowContext::~AbstractWindowContext() = default;
    bool AbstractWindowContext::setup(QObject *host, WindowItemDelegate *delegate) {
        if (!host || !delegate) {
            return false;
    void AbstractWindowContext::setup(QObject *host, WindowItemDelegate *delegate) {
        if (m_host || !host || !delegate) {
            return;
        }
        auto windowHandle = delegate->hostWindow(host);
        if (!windowHandle) {
            return false;
        }
        m_host = host;
        m_delegate.reset(delegate);
        m_windowHandle = windowHandle;
        if (!setupHost()) {
            m_host = nullptr;
            m_delegate.reset();
            m_windowHandle = nullptr;
            return false;
        m_windowHandle = m_delegate->hostWindow(m_host);
        if (m_windowHandle) {
            m_windowHandleGuard = m_windowHandle;
            winIdChanged(nullptr, false);
        }
        return true;
    }
    bool AbstractWindowContext::setHitTestVisible(const QObject *obj, bool visible) {
@@ -183,4 +173,10 @@
        virtual_hook(ShowSystemMenuHook, &const_cast<QPoint &>(pos));
    }
    void AbstractWindowContext::notifyWinIdChange() {
        auto oldWindow = m_windowHandle;
        m_windowHandle = m_delegate->window(m_host);
        winIdChanged(oldWindow, oldWindow && m_windowHandleGuard.isNull());
    }
}
src/core/contexts/abstractwindowcontext_p.h
@@ -5,6 +5,7 @@
#include <memory>
#include <QtCore/QSet>
#include <QtCore/QPointer>
#include <QtGui/QRegion>
#include <QtGui/QWindow>
@@ -21,7 +22,7 @@
        ~AbstractWindowContext() override;
    public:
        bool setup(QObject *host, WindowItemDelegate *delegate);
        void setup(QObject *host, WindowItemDelegate *delegate);
        inline QObject *host() const;
        inline QWindow *window() const;
@@ -56,14 +57,16 @@
        virtual void virtual_hook(int id, void *data);
        void showSystemMenu(const QPoint &pos);
        void notifyWinIdChange();
    protected:
        virtual bool setupHost() = 0;
        virtual void winIdChanged(QWindow *oldWindow, bool destroyed) = 0;
    protected:
        QObject *m_host{};
        std::unique_ptr<WindowItemDelegate> m_delegate;
        QWindow *m_windowHandle{};
        QPointer<QWindow> m_windowHandleGuard;
        QSet<const QObject *> m_hitTestVisibleItems;
#ifdef Q_OS_MAC
src/core/contexts/cocoawindowcontext.mm
@@ -259,7 +259,8 @@
    CocoaWindowEventFilter::~CocoaWindowEventFilter() = default;
    bool CocoaWindowEventFilter::eventFilter(QObject *object, QEvent *event) {
    bool CocoaWindowEventFilter::eventFilter(QObject *obj, QEvent *event) {
        Q_UNUSED(obj)
        auto type = event->type();
        if (type < QEvent::MouseButtonPress || type > QEvent::MouseMove) {
            return false;
@@ -389,7 +390,7 @@
        AbstractWindowContext::virtual_hook(id, data);
    }
    bool CocoaWindowContext::setupHost() {
    bool CocoaWindowContext::winIdChanged(QWindow *oldWindow) {
        windowId = m_windowHandle->winId();
        ensureWindowProxy(windowId)->setSystemTitleBarVisible(false);
        std::ignore = new CocoaWindowEventFilter(this, this);
src/core/contexts/cocoawindowcontext_p.h
@@ -15,7 +15,7 @@
        void virtual_hook(int id, void *data) override;
    protected:
        bool setupHost() override;
        void winIdChanged(QWindow *oldWindow) override;
    protected:
        WId windowId = 0;
src/core/contexts/qtwindowcontext.cpp
@@ -103,7 +103,8 @@
    QtWindowEventFilter::~QtWindowEventFilter() = default;
    bool QtWindowEventFilter::eventFilter(QObject *object, QEvent *event) {
    bool QtWindowEventFilter::eventFilter(QObject *obj, QEvent *event) {
        Q_UNUSED(obj)
        auto type = event->type();
        if (type < QEvent::MouseButtonPress || type > QEvent::MouseMove) {
            return false;
@@ -252,7 +253,7 @@
        AbstractWindowContext::virtual_hook(id, data);
    }
    bool QtWindowContext::setupHost() {
    bool QtWindowContext::winIdChanged() {
        m_delegate->setWindowFlags(m_host, Qt::FramelessWindowHint);
        std::ignore = new QtWindowEventFilter(this, this);
        return true;
src/core/contexts/qtwindowcontext_p.h
@@ -15,7 +15,7 @@
        void virtual_hook(int id, void *data) override;
    protected:
        bool setupHost() override;
        bool winIdChanged() override;
    };
}
src/core/contexts/win32windowcontext.cpp
@@ -764,18 +764,44 @@
        return ::CallWindowProcW(g_qtWindowProc, hWnd, message, wParam, lParam);
    }
    Win32WindowContext::Win32WindowContext() : AbstractWindowContext() {
    static inline void addManagedWindow(HWND hWnd, Win32WindowContext *ctx) {
        // Store original window proc
        if (!g_qtWindowProc) {
            g_qtWindowProc = reinterpret_cast<WNDPROC>(::GetWindowLongPtrW(hWnd, GWLP_WNDPROC));
    }
    Win32WindowContext::~Win32WindowContext() {
        // Hook window proc
        ::SetWindowLongPtrW(hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(QWKHookedWndProc));
        // Install global native event filter
        WindowsNativeEventFilter::install();
        // Save window handle mapping
        g_wndProcHash->insert(hWnd, ctx);
    }
    static inline void removeManagedWindow(HWND hWnd, bool restore) {
        // Remove window handle mapping
        if (auto hWnd = reinterpret_cast<HWND>(windowId); hWnd) {
            g_wndProcHash->remove(hWnd);
        if (!g_wndProcHash->remove(hWnd))
            return;
            // Remove event filter if the all windows has been destroyed
            if (g_wndProcHash->empty()) {
                WindowsNativeEventFilter::uninstall();
            }
        // Restore window proc
        if (restore) {
            ::SetWindowLongPtrW(hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(g_qtWindowProc));
        }
    }
    Win32WindowContext::Win32WindowContext() : AbstractWindowContext() {
    }
    Win32WindowContext::~Win32WindowContext() {
        if (windowId) {
            removeManagedWindow(reinterpret_cast<HWND>(windowId), false);
        }
    }
@@ -871,14 +897,24 @@
        return getWindowFrameBorderThickness(reinterpret_cast<HWND>(windowId));
    }
    bool Win32WindowContext::setupHost() {
    void Win32WindowContext::winIdChanged(QWindow *oldWindow, bool destroyed) {
        if (oldWindow) {
            removeManagedWindow(reinterpret_cast<HWND>(windowId), !destroyed);
        }
        if (!m_windowHandle) {
            return;
        }
        // Install window hook
        auto winId = m_windowHandle->winId();
        auto hWnd = reinterpret_cast<HWND>(winId);
#if QT_VERSION < QT_VERSION_CHECK(6, 5, 0)
        for (const auto attr :
             {_DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1, _DWMWA_USE_IMMERSIVE_DARK_MODE}) {
        for (const auto attr : {
                 _DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1,
                 _DWMWA_USE_IMMERSIVE_DARK_MODE,
             }) {
            const BOOL enable = TRUE;
            DynamicApis::instance().pDwmSetWindowAttribute(hWnd, attr, &enable, sizeof(enable));
        }
@@ -887,24 +923,11 @@
        // Inform Qt we want and have set custom margins
        updateInternalWindowFrameMargins(hWnd, m_windowHandle);
        // Store original window proc
        if (!g_qtWindowProc) {
            g_qtWindowProc = reinterpret_cast<WNDPROC>(::GetWindowLongPtrW(hWnd, GWLP_WNDPROC));
        }
        // Add managed window
        addManagedWindow(hWnd, this);
        // Hook window proc
        ::SetWindowLongPtrW(hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(QWKHookedWndProc));
        // Install global native event filter
        WindowsNativeEventFilter::install();
        // Cache window ID
        // Cache win id
        windowId = winId;
        // Save window handle mapping
        g_wndProcHash->insert(hWnd, this);
        return true;
    }
    bool Win32WindowContext::windowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam,
src/core/contexts/win32windowcontext_p.h
@@ -30,7 +30,7 @@
        int borderThickness() const;
    protected:
        bool setupHost() override;
        void winIdChanged(QWindow *oldWindow, bool destroyed) override;
    public:
        bool windowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result);
src/core/windowagentbase.cpp
@@ -42,13 +42,10 @@
#endif
    }
    bool WindowAgentBasePrivate::setup(QObject *host, WindowItemDelegate *delegate) {
        std::unique_ptr<AbstractWindowContext> ctx(createContext());
        if (!ctx->setup(host, delegate)) {
            return false;
        }
        context = std::move(ctx);
        return true;
    void WindowAgentBasePrivate::setup(QObject *host, WindowItemDelegate *delegate) {
        auto ctx = createContext();
        ctx->setup(host, delegate);
        context.reset(ctx);
    }
    WindowAgentBase::~WindowAgentBase() = default;
src/core/windowagentbase_p.h
@@ -18,7 +18,7 @@
        virtual AbstractWindowContext *createContext() const;
        bool setup(QObject *host, WindowItemDelegate *delegate);
        void setup(QObject *host, WindowItemDelegate *delegate);
        std::unique_ptr<AbstractWindowContext> context;
src/quick/quickwindowagent.cpp
@@ -32,9 +32,7 @@
            return false;
        }
        if (!d->setup(window, new QuickItemDelegate())) {
            return false;
        }
        d->setup(window, new QuickItemDelegate());
        d->hostWindow = window;
#ifdef Q_OS_WINDOWS
src/widgets/widgetwindowagent.cpp
@@ -9,6 +9,27 @@
namespace QWK {
    class WidgetWinIdChangeEventFilter : public QObject {
    public:
        explicit WidgetWinIdChangeEventFilter(QWidget *widget, AbstractWindowContext *ctx)
            : QObject(ctx), widget(widget), ctx(ctx) {
            widget->installEventFilter(this);
        }
    protected:
        bool eventFilter(QObject *obj, QEvent *event) override {
            Q_UNUSED(obj)
            if (event->type() == QEvent::WinIdChange) {
                ctx->notifyWinIdChange();
            }
            return false;
        }
    protected:
        QWidget *widget;
        AbstractWindowContext *ctx;
    };
    WidgetWindowAgentPrivate::WidgetWindowAgentPrivate() = default;
    WidgetWindowAgentPrivate::~WidgetWindowAgentPrivate() = default;
@@ -36,14 +57,14 @@
        w->setAttribute(Qt::WA_DontCreateNativeAncestors);
        w->setAttribute(Qt::WA_NativeWindow);
        if (!d->setup(w, new WidgetItemDelegate())) {
            return false;
        }
        d->setup(w, new WidgetItemDelegate());
        d->hostWidget = w;
#ifdef Q_OS_WINDOWS
        d->setupWindows10BorderWorkaround();
#endif
        std::ignore = new WidgetWinIdChangeEventFilter(w, d->context.get());
        return true;
    }
src/widgets/widgetwindowagent_mac.cpp
@@ -15,6 +15,7 @@
    protected:
        bool eventFilter(QObject *obj, QEvent *event) override {
            Q_UNUSED(obj)
            switch (event->type()) {
                case QEvent::Move:
                case QEvent::Resize: {
@@ -25,7 +26,7 @@
                default:
                    break;
            }
            return QObject::eventFilter(obj, event);
            return false;
        }
    protected:
src/widgets/widgetwindowagent_win.cpp
@@ -64,6 +64,7 @@
        }
        bool eventFilter(QObject *obj, QEvent *event) override {
            Q_UNUSED(obj)
            switch (event->type()) {
                case QEvent::Paint: {
                    if (widget->windowState() & (Qt::WindowMinimized | Qt::WindowMaximized | Qt::WindowFullScreen))