From 77bce901860548cd84c1680672ec75fbd6184cf8 Mon Sep 17 00:00:00 2001
From: Sine Striker <trueful@163.com>
Date: 周四, 22 2月 2024 15:40:09 +0800
Subject: [PATCH] Add new winIdChange event filter

---
 src/widgets/widgetitemdelegate.cpp          |   33 ++++++
 src/widgets/widgetitemdelegate_p.h          |    3 
 src/core/contexts/abstractwindowcontext.cpp |   44 ++------
 src/core/contexts/cocoawindowcontext.mm     |   24 ++--
 src/core/contexts/abstractwindowcontext_p.h |    6 
 src/core/contexts/cocoawindowcontext_p.h    |    4 
 src/core/kernel/winidchangeeventfilter_p.h  |   56 +++++++++++
 src/core/contexts/qtwindowcontext_p.h       |    2 
 src/core/contexts/win32windowcontext.cpp    |   63 +++++++----
 src/core/windowitemdelegate.cpp             |    8 +
 src/core/contexts/win32windowcontext_p.h    |    5 
 src/core/windowitemdelegate_p.h             |    5 +
 src/widgets/widgetwindowagent.cpp           |    2 
 src/core/CMakeLists.txt                     |    2 
 src/core/kernel/winidchangeeventfilter.cpp  |   37 +++++++
 src/core/contexts/qtwindowcontext.cpp       |    2 
 16 files changed, 213 insertions(+), 83 deletions(-)

diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 45aa224..fb059bc 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -15,6 +15,8 @@
     kernel/nativeeventfilter.cpp
     kernel/sharedeventfilter_p.h
     kernel/sharedeventfilter.cpp
+    kernel/winidchangeeventfilter_p.h
+    kernel/winidchangeeventfilter.cpp
     shared/systemwindow_p.h
     contexts/abstractwindowcontext_p.h
     contexts/abstractwindowcontext.cpp
diff --git a/src/core/contexts/abstractwindowcontext.cpp b/src/core/contexts/abstractwindowcontext.cpp
index 8fa851a..3b441c0 100644
--- a/src/core/contexts/abstractwindowcontext.cpp
+++ b/src/core/contexts/abstractwindowcontext.cpp
@@ -7,34 +7,12 @@
 #include <QtGui/QPen>
 #include <QtGui/QPainter>
 #include <QtGui/QScreen>
-#include <memory>
 
 #include "qwkglobal_p.h"
 
 namespace QWK {
 
     namespace {
-
-        class WinIdChangeEventFilter : public QObject {
-        public:
-            explicit WinIdChangeEventFilter(QObject *widget, AbstractWindowContext *ctx,
-                                            QObject *parent = nullptr)
-                : QObject(parent), 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:
-            AbstractWindowContext *ctx;
-        };
 
         class WindowEventFilter : public QObject {
         public:
@@ -77,16 +55,10 @@
         }
         m_host = host;
         m_delegate.reset(delegate);
-        m_winIdChangeEventFilter = std::make_unique<WinIdChangeEventFilter>(host, this);
+        m_winIdChangeEventFilter.reset(delegate->createWinIdEventFilter(host, this));
         m_windowEventFilter = std::make_unique<WindowEventFilter>(m_windowHandle, this);
-
-        m_windowHandle = m_delegate->hostWindow(m_host);
-        if (m_windowHandle) {
-            winIdChanged();
-        }
+        notifyWinIdChange();
     }
-
-
 
     bool AbstractWindowContext::setHitTestVisible(const QObject *obj, bool visible) {
         Q_ASSERT(obj);
@@ -259,15 +231,21 @@
     }
 
     void AbstractWindowContext::notifyWinIdChange() {
-        auto windowEventFilter = static_cast<WindowEventFilter *>(m_windowEventFilter.get());
-        windowEventFilter->setWindow(nullptr);
+        auto oldWinId = m_windowId;
+        m_windowId = m_winIdChangeEventFilter->winId();
 
         // In Qt6, after QWidget::close() is called, the related QWindow's all surfaces and the
         // 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.
         m_windowHandle = m_delegate->hostWindow(m_host);
-        winIdChanged();
+
+        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);
diff --git a/src/core/contexts/abstractwindowcontext_p.h b/src/core/contexts/abstractwindowcontext_p.h
index c35d306..e7711d7 100644
--- a/src/core/contexts/abstractwindowcontext_p.h
+++ b/src/core/contexts/abstractwindowcontext_p.h
@@ -26,6 +26,7 @@
 #include <QWKCore/private/nativeeventfilter_p.h>
 #include <QWKCore/private/sharedeventfilter_p.h>
 #include <QWKCore/private/windowitemdelegate_p.h>
+#include <QWKCore/private/winidchangeeventfilter_p.h>
 
 namespace QWK {
 
@@ -81,7 +82,7 @@
         virtual bool setWindowAttribute(const QString &key, const QVariant &attribute);
 
     protected:
-        virtual void winIdChanged() = 0;
+        virtual void winIdChanged(WId winId, WId oldWinId) = 0;
         virtual bool windowAttributeChanged(const QString &key, const QVariant &attribute,
                                             const QVariant &oldAttribute);
 
@@ -89,6 +90,7 @@
         QObject *m_host{};
         std::unique_ptr<WindowItemDelegate> m_delegate;
         QWindow *m_windowHandle{};
+        WId m_windowId{};
 
         QSet<const QObject *> m_hitTestVisibleItems;
 #ifdef Q_OS_MAC
@@ -101,7 +103,7 @@
         QVariantHash m_windowAttributes;
 
         std::unique_ptr<QObject> m_windowEventFilter;
-        std::unique_ptr<QObject> m_winIdChangeEventFilter;
+        std::unique_ptr<WinIdChangeEventFilter> m_winIdChangeEventFilter;
     };
 
     inline QObject *AbstractWindowContext::host() const {
diff --git a/src/core/contexts/cocoawindowcontext.mm b/src/core/contexts/cocoawindowcontext.mm
index 91565c0..a7e857e 100644
--- a/src/core/contexts/cocoawindowcontext.mm
+++ b/src/core/contexts/cocoawindowcontext.mm
@@ -664,7 +664,7 @@
     }
 
     CocoaWindowContext::~CocoaWindowContext() {
-        releaseWindowProxy(windowId);
+        releaseWindowProxy(m_windowId);
     }
 
     QString CocoaWindowContext::key() const {
@@ -674,7 +674,7 @@
     void CocoaWindowContext::virtual_hook(int id, void *data) {
         switch (id) {
             case SystemButtonAreaChangedHook: {
-                ensureWindowProxy(windowId)->setScreenRectCallback(m_systemButtonAreaCallback);
+                ensureWindowProxy(m_windowId)->setScreenRectCallback(m_systemButtonAreaCallback);
                 return;
             }
 
@@ -686,18 +686,17 @@
 
     QVariant CocoaWindowContext::windowAttribute(const QString &key) const {
         if (key == QStringLiteral("title-bar-height")) {
-            if (!m_windowHandle)
-                return 0;
-            return ensureWindowProxy(windowId)->titleBarHeight();
+            if (!m_windowId)
+                return {};
+            return ensureWindowProxy(m_windowId)->titleBarHeight();
         }
         return AbstractWindowContext::windowAttribute(key);
     }
 
-    void CocoaWindowContext::winIdChanged() {
+    void CocoaWindowContext::winIdChanged(WId winId, WId oldWinId) {
         // If the original window id is valid, remove all resources related
-        if (windowId) {
-            releaseWindowProxy(windowId);
-            windowId = 0;
+        if (oldWinId) {
+            releaseWindowProxy(oldWinId);
         }
 
         if (!m_windowHandle) {
@@ -705,8 +704,7 @@
         }
 
         // Allocate new resources
-        windowId = m_windowHandle->winId();
-        ensureWindowProxy(windowId)->setSystemTitleBarVisible(false);
+        ensureWindowProxy(winId)->setSystemTitleBarVisible(false);
     }
 
     bool CocoaWindowContext::windowAttributeChanged(const QString &key, const QVariant &attribute,
@@ -716,7 +714,7 @@
         if (key == QStringLiteral("no-system-buttons")) {
             if (attribute.type() != QVariant::Bool)
                 return false;
-            ensureWindowProxy(windowId)->setSystemButtonVisible(!attribute.toBool());
+            ensureWindowProxy(m_windowId)->setSystemButtonVisible(!attribute.toBool());
             return true;
         }
 
@@ -743,7 +741,7 @@
             } else {
                 return false;
             }
-            return ensureWindowProxy(windowId)->setBlurEffect(mode);
+            return ensureWindowProxy(m_windowId)->setBlurEffect(mode);
         }
 
         return false;
diff --git a/src/core/contexts/cocoawindowcontext_p.h b/src/core/contexts/cocoawindowcontext_p.h
index f2e28cc..e35c686 100644
--- a/src/core/contexts/cocoawindowcontext_p.h
+++ b/src/core/contexts/cocoawindowcontext_p.h
@@ -30,13 +30,11 @@
         QVariant windowAttribute(const QString &key) const override;
 
     protected:
-        void winIdChanged() override;
+        void winIdChanged(WId winId, WId oldWinId) override;
         bool windowAttributeChanged(const QString &key, const QVariant &attribute,
                                     const QVariant &oldAttribute) override;
 
     protected:
-        WId windowId = 0;
-
         std::unique_ptr<SharedEventFilter> cocoaWindowEventFilter;
     };
 
diff --git a/src/core/contexts/qtwindowcontext.cpp b/src/core/contexts/qtwindowcontext.cpp
index 3a21965..a72bce0 100644
--- a/src/core/contexts/qtwindowcontext.cpp
+++ b/src/core/contexts/qtwindowcontext.cpp
@@ -253,7 +253,7 @@
         AbstractWindowContext::virtual_hook(id, data);
     }
 
-    void QtWindowContext::winIdChanged() {
+    void QtWindowContext::winIdChanged(WId winId, WId oldWinId) {
         if (!m_windowHandle) {
             m_delegate->setWindowFlags(m_host, m_delegate->getWindowFlags(m_host) &
                                                    ~Qt::FramelessWindowHint);
diff --git a/src/core/contexts/qtwindowcontext_p.h b/src/core/contexts/qtwindowcontext_p.h
index caee804..1625ea1 100644
--- a/src/core/contexts/qtwindowcontext_p.h
+++ b/src/core/contexts/qtwindowcontext_p.h
@@ -28,7 +28,7 @@
         void virtual_hook(int id, void *data) override;
 
     protected:
-        void winIdChanged() override;
+        void winIdChanged(WId winId, WId oldWinId) override;
 
     protected:
         std::unique_ptr<SharedEventFilter> qtWindowEventFilter;
diff --git a/src/core/contexts/win32windowcontext.cpp b/src/core/contexts/win32windowcontext.cpp
index 4a859c7..e0db522 100644
--- a/src/core/contexts/win32windowcontext.cpp
+++ b/src/core/contexts/win32windowcontext.cpp
@@ -321,7 +321,7 @@
             case HTBORDER:
                 return Win32WindowContext::FixedBorder;
             default:
-                // unreachable
+                Q_UNREACHABLE();
                 break;
         }
         return Win32WindowContext::Outside;
@@ -540,8 +540,8 @@
     }
 
     Win32WindowContext::~Win32WindowContext() {
-        if (windowId) {
-            removeManagedWindow(reinterpret_cast<HWND>(windowId));
+        if (m_windowId) {
+            removeManagedWindow(reinterpret_cast<HWND>(m_windowId));
         }
     }
 
@@ -552,19 +552,19 @@
     void Win32WindowContext::virtual_hook(int id, void *data) {
         switch (id) {
             case RaiseWindowHook: {
-                if (!windowId)
+                if (!m_windowId)
                     return;
                 m_delegate->setWindowVisible(m_host, true);
-                const auto hwnd = reinterpret_cast<HWND>(windowId);
+                const auto hwnd = reinterpret_cast<HWND>(m_windowId);
                 bringWindowToFront(hwnd);
                 return;
             }
 
             case ShowSystemMenuHook: {
-                if (!windowId)
+                if (!m_windowId)
                     return;
                 const auto &pos = *static_cast<const QPoint *>(data);
-                auto hWnd = reinterpret_cast<HWND>(windowId);
+                auto hWnd = reinterpret_cast<HWND>(m_windowId);
 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
                 const QPoint nativeGlobalPos =
                     QHighDpi::toNativeGlobalPosition(pos, m_windowHandle);
@@ -588,14 +588,14 @@
 
 #if QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDERS)
             case DrawWindows10BorderHook: {
-                if (!windowId)
+                if (!m_windowId)
                     return;
 
                 auto args = static_cast<void **>(data);
                 auto &painter = *static_cast<QPainter *>(args[0]);
                 const auto &rect = *static_cast<const QRect *>(args[1]);
                 const auto &region = *static_cast<const QRegion *>(args[2]);
-                const auto hwnd = reinterpret_cast<HWND>(windowId);
+                const auto hwnd = reinterpret_cast<HWND>(m_windowId);
 
                 QPen pen;
                 pen.setWidth(int(getWindowFrameBorderThickness(hwnd)) * 2);
@@ -638,7 +638,7 @@
                 // https://docs.microsoft.com/en-us/windows/win32/dwm/customframe#extending-the-client-frame
                 // Draw a black rectangle to make Windows native top border show
 
-                auto hWnd = reinterpret_cast<HWND>(windowId);
+                auto hWnd = reinterpret_cast<HWND>(m_windowId);
                 HDC hdc = ::GetDC(hWnd);
                 RECT windowRect{};
                 ::GetClientRect(hWnd, &windowRect);
@@ -667,7 +667,7 @@
                 return {};
 
             RECT frame{};
-            auto hwnd = reinterpret_cast<HWND>(windowId);
+            auto hwnd = reinterpret_cast<HWND>(m_windowId);
             // According to MSDN, WS_OVERLAPPED is not allowed for AdjustWindowRect.
             auto style = static_cast<DWORD>(::GetWindowLongPtrW(hwnd, GWL_STYLE) & ~WS_OVERLAPPED);
             auto exStyle = static_cast<DWORD>(::GetWindowLongPtrW(hwnd, GWL_EXSTYLE));
@@ -687,28 +687,25 @@
 
         if (key == QStringLiteral("border-thickness")) {
             return m_windowHandle
-                       ? int(getWindowFrameBorderThickness(reinterpret_cast<HWND>(windowId)))
+                       ? int(getWindowFrameBorderThickness(reinterpret_cast<HWND>(m_windowId)))
                        : 0;
         }
 
         return AbstractWindowContext::windowAttribute(key);
     }
 
-    void Win32WindowContext::winIdChanged() {
+    void Win32WindowContext::winIdChanged(WId winId, WId oldWinId) {
         // If the original window id is valid, remove all resources related
-        if (windowId) {
-            removeManagedWindow(reinterpret_cast<HWND>(windowId));
-            windowId = 0;
+        if (oldWinId) {
+            removeManagedWindow(reinterpret_cast<HWND>(oldWinId));
         }
 
-        if (!m_windowHandle) {
+        if (!m_windowHandle || ! winId) {
             return;
         }
 
         // Install window hook
-        auto winId = m_windowHandle->winId();
         auto hWnd = reinterpret_cast<HWND>(winId);
-
         if (!isSystemBorderEnabled()) {
             static auto margins = QVariant::fromValue(QMargins(1, 1, 1, 1));
 
@@ -732,14 +729,15 @@
 
         // Add managed window
         addManagedWindow(m_windowHandle, hWnd, this);
-
-        // Cache win id
-        windowId = winId;
     }
 
     bool Win32WindowContext::windowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam,
                                         LRESULT *result) {
         *result = FALSE;
+
+        if (message == WM_DESTROY) {
+            qDebug() << "WM_DESTROY";
+        }
 
         // We should skip these messages otherwise we will get crashes.
         // NOTE: WM_QUIT won't be posted to the WindowProc function.
@@ -757,6 +755,20 @@
 
         if (!isValidWindow(hWnd, false, true)) {
             return false;
+        }
+
+        switch (message) {
+            case WM_NCMOUSELEAVE:
+                qDebug() << "WM_NCMOUSELEAVE" << mouseLeaveBlocked;
+                break;
+            case WM_MOUSEHOVER:
+                qDebug() << "WM_MOUSEHOVER" << mouseLeaveBlocked;
+                break;
+            case WM_NCMOUSEHOVER:
+                qDebug() << "WM_NCMOUSEHOVER" << mouseLeaveBlocked;
+                break;
+            default:
+                break;
         }
 
         // Test snap layout
@@ -794,7 +806,7 @@
                                                     const QVariant &oldAttribute) {
         Q_UNUSED(oldAttribute)
 
-        const auto hwnd = reinterpret_cast<HWND>(m_windowHandle->winId());
+        const auto hwnd = reinterpret_cast<HWND>(m_windowId);
         const DynamicApis &apis = DynamicApis::instance();
         static constexpr const MARGINS extendedMargins = {-1, -1, -1, -1};
         const auto &restoreMargins = [this, &apis, hwnd]() {
@@ -1144,6 +1156,8 @@
                     }
                 }
                 mouseLeaveBlocked = false;
+                
+                qDebug() << "WM_MOUSELEAVE";
                 break;
             }
 
@@ -1152,6 +1166,7 @@
                 // we unset `mouseLeaveBlocked` mark and pretend as if Qt has received
                 // WM_MOUSELEAVE.
                 if (lastHitTestResult != WindowPart::ChromeButton && mouseLeaveBlocked) {
+                    qDebug() << lastHitTestResult << "Track";
                     mouseLeaveBlocked = false;
                     requestForMouseLeaveMessage(hWnd, false);
                 }
@@ -1240,7 +1255,7 @@
                     // 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
                     // leaving the window, current window part remains as `Outside`.
-                    lastHitTestResult = WindowPart::Outside;
+                    // lastHitTestResult = WindowPart::Outside;
                 }
 
                 if (currentWindowPart == WindowPart::ChromeButton) {
diff --git a/src/core/contexts/win32windowcontext_p.h b/src/core/contexts/win32windowcontext_p.h
index b99c90d..1389dbb 100644
--- a/src/core/contexts/win32windowcontext_p.h
+++ b/src/core/contexts/win32windowcontext_p.h
@@ -33,6 +33,7 @@
             FixedBorder,
             TitleBar,
         };
+        Q_ENUM(WindowPart)
 
         QString key() const override;
         void virtual_hook(int id, void *data) override;
@@ -40,7 +41,7 @@
         QVariant windowAttribute(const QString &key) const override;
 
     protected:
-        void winIdChanged() override;
+        void winIdChanged(WId winId, WId oldWinId) override;
         bool windowAttributeChanged(const QString &key, const QVariant &attribute,
                                     const QVariant &oldAttribute) override;
 
@@ -64,8 +65,6 @@
                                       LRESULT *result);
 
     protected:
-        WId windowId = 0;
-
         // The last hit test result, helpful to handle WM_MOUSEMOVE and WM_NCMOUSELEAVE.
         WindowPart lastHitTestResult = WindowPart::Outside;
 
diff --git a/src/core/kernel/winidchangeeventfilter.cpp b/src/core/kernel/winidchangeeventfilter.cpp
new file mode 100644
index 0000000..b11d16a
--- /dev/null
+++ b/src/core/kernel/winidchangeeventfilter.cpp
@@ -0,0 +1,37 @@
+// 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 "winidchangeeventfilter_p.h"
+
+#include <qpa/qplatformwindow.h>
+
+#include "abstractwindowcontext_p.h"
+
+namespace QWK {
+
+    WId WindowWinIdChangeEventFilter::winId() const {
+        auto win = static_cast<QWindow *>(host);
+        if (isAboutToBeDestroyed)
+            return 0;
+        if (auto platformWindow = win->handle())
+            return platformWindow->winId();
+        return 0;
+    }
+
+    bool WindowWinIdChangeEventFilter::eventFilter(QObject *obj, QEvent *event) {
+        Q_UNUSED(obj)
+        if (event->type() == QEvent::PlatformSurface) {
+            auto e = static_cast<QPlatformSurfaceEvent *>(event);
+            if (e->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed) {
+                isAboutToBeDestroyed = true;
+                context->notifyWinIdChange();
+                isAboutToBeDestroyed = false;
+            } else {
+                context->notifyWinIdChange();
+            }
+        }
+        return false;
+    }
+
+}
diff --git a/src/core/kernel/winidchangeeventfilter_p.h b/src/core/kernel/winidchangeeventfilter_p.h
new file mode 100644
index 0000000..4e0ab36
--- /dev/null
+++ b/src/core/kernel/winidchangeeventfilter_p.h
@@ -0,0 +1,56 @@
+锘�// Copyright (C) 2023-2024 Stdware Collections (https://www.github.com/stdware)
+// Copyright (C) 2021-2023 wangwenx190 (Yuhang Zhao)
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef WINIDCHANGEEVENTFILTER_P_H
+#define WINIDCHANGEEVENTFILTER_P_H
+
+//
+//  W A R N I N G !!!
+//  -----------------
+//
+// This file is not part of the QWindowKit API. It is used purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or may even be removed.
+//
+
+#include <QtGui/QWindow>
+
+#include <QWKCore/qwkglobal.h>
+
+namespace QWK {
+
+    class AbstractWindowContext;
+
+    class WinIdChangeEventFilter : public QObject {
+    public:
+        WinIdChangeEventFilter(QObject *host, AbstractWindowContext *context)
+            : host(host), context(context) {
+        }
+
+        virtual WId winId() const = 0;
+
+    protected:
+        QObject *host;
+        AbstractWindowContext *context;
+    };
+
+    class QWK_CORE_EXPORT WindowWinIdChangeEventFilter : public WinIdChangeEventFilter {
+    public:
+        WindowWinIdChangeEventFilter(QObject *host, AbstractWindowContext *context)
+            : WinIdChangeEventFilter(host, context), win(static_cast<QWindow *>(host)),
+              isAboutToBeDestroyed(false) {
+        }
+
+        WId winId() const override;
+
+    protected:
+        QWindow *win;
+        bool isAboutToBeDestroyed;
+
+        bool eventFilter(QObject *obj, QEvent *event) override;
+    };
+
+}
+
+#endif // WINIDCHANGEEVENTFILTER_P_H
diff --git a/src/core/windowitemdelegate.cpp b/src/core/windowitemdelegate.cpp
index 25f0bf3..9285958 100644
--- a/src/core/windowitemdelegate.cpp
+++ b/src/core/windowitemdelegate.cpp
@@ -14,4 +14,10 @@
         Q_UNUSED(host);
     }
 
-}
\ No newline at end of file
+    WinIdChangeEventFilter *
+        WindowItemDelegate::createWinIdEventFilter(QObject *host,
+                                                   AbstractWindowContext *context) const {
+        return new WindowWinIdChangeEventFilter(host, context);
+    }
+
+}
diff --git a/src/core/windowitemdelegate_p.h b/src/core/windowitemdelegate_p.h
index 75bbf1e..70d5fe9 100644
--- a/src/core/windowitemdelegate_p.h
+++ b/src/core/windowitemdelegate_p.h
@@ -18,6 +18,7 @@
 #include <QtCore/QPoint>
 #include <QtGui/QWindow>
 
+#include <QWKCore/private/winidchangeeventfilter_p.h>
 #include <QWKCore/qwkglobal.h>
 
 namespace QWK {
@@ -52,6 +53,10 @@
         virtual void setGeometry(QObject *host, const QRect &rect) = 0;
         virtual void bringWindowToTop(QObject *host) const = 0;
 
+        // Factories
+        virtual WinIdChangeEventFilter *
+            createWinIdEventFilter(QObject *host, AbstractWindowContext *context) const;
+
     private:
         Q_DISABLE_COPY(WindowItemDelegate)
     };
diff --git a/src/widgets/widgetitemdelegate.cpp b/src/widgets/widgetitemdelegate.cpp
index e1ff752..6980175 100644
--- a/src/widgets/widgetitemdelegate.cpp
+++ b/src/widgets/widgetitemdelegate.cpp
@@ -5,12 +5,37 @@
 #include "widgetitemdelegate_p.h"
 
 #include <QtGui/QMouseEvent>
-#include <QtWidgets/QWidget>
 #include <QtWidgets/QApplication>
+#include <QtWidgets/QWidget>
+
+#include <QWKCore/private/abstractwindowcontext_p.h>
 
 extern Q_DECL_IMPORT QWidget *qt_button_down;
 
 namespace QWK {
+
+    class WidgetWinIdChangeEventFilter : public WinIdChangeEventFilter {
+    public:
+        explicit WidgetWinIdChangeEventFilter(QObject *host, AbstractWindowContext *ctx)
+            : WinIdChangeEventFilter(host, ctx), widget(static_cast<QWidget *>(host)) {
+            widget->installEventFilter(this);
+        }
+
+        WId winId() const override {
+            return widget->effectiveWinId();
+        }
+
+    protected:
+        bool eventFilter(QObject *obj, QEvent *event) override {
+            Q_UNUSED(obj)
+            if (event->type() == QEvent::WinIdChange) {
+                context->notifyWinIdChange();
+            }
+            return false;
+        }
+
+        QWidget *widget;
+    };
 
     WidgetItemDelegate::WidgetItemDelegate() = default;
 
@@ -112,4 +137,10 @@
         static_cast<QWidget *>(host)->raise();
     }
 
+    WinIdChangeEventFilter *
+        WidgetItemDelegate::createWinIdEventFilter(QObject *host,
+                                                   AbstractWindowContext *context) const {
+        return new WidgetWinIdChangeEventFilter(host, context);
+    }
+
 }
\ No newline at end of file
diff --git a/src/widgets/widgetitemdelegate_p.h b/src/widgets/widgetitemdelegate_p.h
index 19de708..f5c58a6 100644
--- a/src/widgets/widgetitemdelegate_p.h
+++ b/src/widgets/widgetitemdelegate_p.h
@@ -48,6 +48,9 @@
         void setWindowVisible(QObject *host, bool visible) const override;
         void setGeometry(QObject *host, const QRect &rect) override;
         void bringWindowToTop(QObject *host) const override;
+
+        WinIdChangeEventFilter *
+            createWinIdEventFilter(QObject *host, AbstractWindowContext *context) const override;
     };
 
 }
diff --git a/src/widgets/widgetwindowagent.cpp b/src/widgets/widgetwindowagent.cpp
index 6ba46dd..991c28f 100644
--- a/src/widgets/widgetwindowagent.cpp
+++ b/src/widgets/widgetwindowagent.cpp
@@ -56,7 +56,7 @@
         }
 
         w->setAttribute(Qt::WA_DontCreateNativeAncestors);
-        w->setAttribute(Qt::WA_NativeWindow);
+        w->setAttribute(Qt::WA_NativeWindow); // Create new window id
 
         d->setup(w, new WidgetItemDelegate());
         d->hostWidget = w;

--
Gitblit v1.9.1