From 8209cdfb1d85a40cc770f854d773c3a10f5ab576 Mon Sep 17 00:00:00 2001 From: Sine Striker <trueful@163.com> Date: 周三, 20 12月 2023 17:32:57 +0800 Subject: [PATCH] Add hot-switch to agent --- src/core/contexts/abstractwindowcontext.cpp | 37 +++++++++++++++--- src/core/contexts/win32windowcontext_p.h | 2 src/core/contexts/cocoawindowcontext.mm | 2 src/core/contexts/abstractwindowcontext_p.h | 13 ++++++ src/core/windowagentbase.h | 3 + src/core/contexts/cocoawindowcontext_p.h | 2 src/core/contexts/qtwindowcontext.cpp | 2 src/core/windowagentbase.cpp | 10 +++++ src/core/contexts/qtwindowcontext_p.h | 2 src/core/contexts/win32windowcontext.cpp | 25 ++++++++---- 10 files changed, 78 insertions(+), 20 deletions(-) diff --git a/src/core/contexts/abstractwindowcontext.cpp b/src/core/contexts/abstractwindowcontext.cpp index 0602bdc..1669cd4 100644 --- a/src/core/contexts/abstractwindowcontext.cpp +++ b/src/core/contexts/abstractwindowcontext.cpp @@ -18,10 +18,7 @@ } m_host = host; m_delegate.reset(delegate); - m_windowHandle = m_delegate->hostWindow(m_host); - if (m_windowHandle) { - winIdChanged(nullptr); - } + setEnabled(true); } void AbstractWindowContext::setWindowAttribute(const QString &key, const QVariant &var) { @@ -193,11 +190,39 @@ } void AbstractWindowContext::notifyWinIdChange() { + if (!m_internalEnabled) + return; + auto oldWindow = m_windowHandle; - m_windowHandle = m_delegate->window(m_host); if (oldWindow == m_windowHandle) return; - winIdChanged(oldWindow); + auto isDestroyed = oldWindow && m_windowHandleCache.isNull(); + m_windowHandle = m_delegate->window(m_host); + m_windowHandleCache = m_windowHandle; + winIdChanged(oldWindow, isDestroyed); + } + + void AbstractWindowContext::setEnabled(bool enabled) { + if (enabled == m_internalEnabled) + return; + m_internalEnabled = enabled; + + if (enabled) { + m_windowHandle = m_delegate->window(m_host); + m_windowHandleCache = m_windowHandle; + if (m_windowHandle) { + winIdChanged(nullptr, false); + } + return; + } + + if (!m_windowHandle) + return; + + auto oldWindow = m_windowHandle; + m_windowHandle = nullptr; + m_windowHandleCache.clear(); + winIdChanged(oldWindow, false); } } diff --git a/src/core/contexts/abstractwindowcontext_p.h b/src/core/contexts/abstractwindowcontext_p.h index ecd2323..1882369 100644 --- a/src/core/contexts/abstractwindowcontext_p.h +++ b/src/core/contexts/abstractwindowcontext_p.h @@ -73,8 +73,11 @@ void showSystemMenu(const QPoint &pos); void notifyWinIdChange(); + inline bool isEnabled() const; + void setEnabled(bool enabled); + protected: - virtual void winIdChanged(QWindow *oldWindow) = 0; + virtual void winIdChanged(QWindow *oldWindow, bool isDestroyed) = 0; protected: QObject *m_host{}; @@ -90,6 +93,10 @@ std::array<QObject *, WindowAgentBase::NumSystemButton> m_systemButtons{}; QVariantHash m_windowAttributes; + + private: + bool m_internalEnabled = false; + QPointer<QWindow> m_windowHandleCache; }; inline QObject *AbstractWindowContext::host() const { @@ -127,6 +134,10 @@ } #endif + inline bool AbstractWindowContext::isEnabled() const { + return m_internalEnabled; + } + } #endif // ABSTRACTWINDOWCONTEXT_P_H diff --git a/src/core/contexts/cocoawindowcontext.mm b/src/core/contexts/cocoawindowcontext.mm index 5011e28..cbfed18 100644 --- a/src/core/contexts/cocoawindowcontext.mm +++ b/src/core/contexts/cocoawindowcontext.mm @@ -401,7 +401,7 @@ AbstractWindowContext::virtual_hook(id, data); } - void CocoaWindowContext::winIdChanged(QWindow *oldWindow) { + void CocoaWindowContext::winIdChanged(QWindow *oldWindow, bool isDestroyed) { releaseWindowProxy(windowId); if (!m_windowHandle) { return; diff --git a/src/core/contexts/cocoawindowcontext_p.h b/src/core/contexts/cocoawindowcontext_p.h index 01b8699..0bbf661 100644 --- a/src/core/contexts/cocoawindowcontext_p.h +++ b/src/core/contexts/cocoawindowcontext_p.h @@ -24,7 +24,7 @@ void virtual_hook(int id, void *data) override; protected: - void winIdChanged(QWindow *oldWindow) override; + void winIdChanged(QWindow *oldWindow, bool isDestroyed) override; protected: WId windowId = 0; diff --git a/src/core/contexts/qtwindowcontext.cpp b/src/core/contexts/qtwindowcontext.cpp index 4bbb0e6..7941b56 100644 --- a/src/core/contexts/qtwindowcontext.cpp +++ b/src/core/contexts/qtwindowcontext.cpp @@ -247,7 +247,7 @@ AbstractWindowContext::virtual_hook(id, data); } - void QtWindowContext::winIdChanged(QWindow *oldWindow) { + void QtWindowContext::winIdChanged(QWindow *oldWindow, bool isDestroyed) { Q_UNUSED(oldWindow) 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 6905d67..c7d04eb 100644 --- a/src/core/contexts/qtwindowcontext_p.h +++ b/src/core/contexts/qtwindowcontext_p.h @@ -24,7 +24,7 @@ void virtual_hook(int id, void *data) override; protected: - void winIdChanged(QWindow *oldWindow) override; + void winIdChanged(QWindow *oldWindow, bool isDestroyed) override; protected: std::unique_ptr<QObject> qtWindowEventFilter; diff --git a/src/core/contexts/win32windowcontext.cpp b/src/core/contexts/win32windowcontext.cpp index 145b19c..3b2d3e8 100644 --- a/src/core/contexts/win32windowcontext.cpp +++ b/src/core/contexts/win32windowcontext.cpp @@ -845,6 +845,7 @@ g_wndProcHash->insert(hWnd, ctx); } + template <bool Destroyed = true> static inline void removeManagedWindow(HWND hWnd) { // Remove window handle mapping if (!g_wndProcHash->remove(hWnd)) @@ -853,6 +854,11 @@ // Remove event filter if the all windows has been destroyed if (g_wndProcHash->empty()) { WindowsNativeEventFilter::uninstall(); + } + + // Restore window proc + if constexpr (!Destroyed) { + ::SetWindowLongPtrW(hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(g_qtWindowProc)); } } @@ -964,9 +970,8 @@ return; } - default: { + default: break; - } } AbstractWindowContext::virtual_hook(id, data); } @@ -979,8 +984,12 @@ return getWindowFrameBorderThickness(reinterpret_cast<HWND>(windowId)); } - void Win32WindowContext::winIdChanged(QWindow *oldWindow) { - removeManagedWindow(reinterpret_cast<HWND>(windowId)); + void Win32WindowContext::winIdChanged(QWindow *oldWindow, bool isDestroyed) { + if (isDestroyed) { + removeManagedWindow(reinterpret_cast<HWND>(windowId)); + } else { + removeManagedWindow<false>(reinterpret_cast<HWND>(windowId)); + } if (!m_windowHandle) { return; } @@ -1000,7 +1009,7 @@ #endif // Inform Qt we want and have set custom margins - updateInternalWindowFrameMargins(hWnd, m_windowHandle); + updateInternalWindowFrameMargins(hWnd, m_windowHandle); // TODO: Restore? // Add managed window addManagedWindow(hWnd, this); @@ -1296,9 +1305,9 @@ // widget to be implicitly grabbed. After the menu is closed, Windows // immediately sends WM_NCHITTEST, because the mouse is in the title bar // draggable area, the result is HTCAPTION, so when the mouse is released, - // Windows sends WM_NCLBUTTONUP, which is a non-client area message, and it + // Windows sends WM_NCLBUTTONUP, which is a non-client message, and it // will be ignored by Qt. As a consequence, QWidgetWindow can't receive a - // mouse release messages in the client area, so the grab remains, and other + // mouse release message in the client area, so the grab remains, and other // widgets cannot receive mouse events. // Since we didn't watch the menu window, we cannot capture any mouse @@ -1609,7 +1618,7 @@ *result = (isTitleBar ? HTCAPTION : HTCLIENT); return true; } - // At this point, we know that the cursor is inside the client area + // At this point, we know that the cursor is inside the client area, // so it has to be either the little border at the top of our custom // title bar or the drag bar. Apparently, it must be the drag bar or // the little border at the top which the user can use to move or diff --git a/src/core/contexts/win32windowcontext_p.h b/src/core/contexts/win32windowcontext_p.h index 8e25be7..698958f 100644 --- a/src/core/contexts/win32windowcontext_p.h +++ b/src/core/contexts/win32windowcontext_p.h @@ -39,7 +39,7 @@ int borderThickness() const; protected: - void winIdChanged(QWindow *oldWindow) override; + void winIdChanged(QWindow *oldWindow, bool isDestroyed) override; public: bool windowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result); diff --git a/src/core/windowagentbase.cpp b/src/core/windowagentbase.cpp index c043838..159d678 100644 --- a/src/core/windowagentbase.cpp +++ b/src/core/windowagentbase.cpp @@ -60,6 +60,16 @@ d->context->setWindowAttribute(key, var); } + bool WindowAgentBase::isEnabled() const { + Q_D(const WindowAgentBase); + return d->context->isEnabled(); + } + + void WindowAgentBase::setEnabled(bool enabled) { + Q_D(WindowAgentBase); + d->context->setEnabled(enabled); + } + void WindowAgentBase::showSystemMenu(const QPoint &pos) { Q_D(WindowAgentBase); d->context->showSystemMenu(pos); diff --git a/src/core/windowagentbase.h b/src/core/windowagentbase.h index d5b02fa..c252b9b 100644 --- a/src/core/windowagentbase.h +++ b/src/core/windowagentbase.h @@ -31,6 +31,9 @@ QVariant windowAttribute(const QString &key) const; void setWindowAttribute(const QString &key, const QVariant &var); + bool isEnabled() const; + void setEnabled(bool enabled); + public Q_SLOTS: void showSystemMenu(const QPoint &pos); void centralize(); -- Gitblit v1.9.1