Sine Striker
2024-05-08 dd961a654f29fe6a59a093f8b4b0fff726efbd4a
src/core/contexts/abstractwindowcontext.cpp
@@ -1,4 +1,5 @@
// Copyright (C) 2023-2024 Stdware Collections
// 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 "abstractwindowcontext_p.h"
@@ -6,7 +7,6 @@
#include <QtGui/QPen>
#include <QtGui/QPainter>
#include <QtGui/QScreen>
#include <memory>
#include "qwkglobal_p.h"
@@ -14,33 +14,23 @@
    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:
            explicit WindowEventFilter(QWindow *window, AbstractWindowContext *ctx,
                                       QObject *parent = nullptr)
                : QObject(parent), ctx(ctx), window(window) {
                window->installEventFilter(this);
                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:
@@ -50,7 +40,7 @@
        protected:
            AbstractWindowContext *ctx;
            QWindow *window;
            QPointer<QWindow> window;
        };
    }
@@ -65,16 +55,10 @@
        }
        m_host = host;
        m_delegate.reset(delegate);
        m_winIdChangeEventFilter = std::make_unique<WinIdChangeEventFilter>(host, this);
        m_windowHandle = m_delegate->hostWindow(m_host);
        if (m_windowHandle) {
            winIdChanged();
            m_windowEventFilter = std::make_unique<WindowEventFilter>(m_windowHandle, this);
        }
        m_winIdChangeEventFilter.reset(delegate->createWinIdEventFilter(host, this));
        m_windowEventFilter = std::make_unique<WindowEventFilter>(m_windowHandle, this);
        notifyWinIdChange();
    }
    bool AbstractWindowContext::setHitTestVisible(const QObject *obj, bool visible) {
        Q_ASSERT(obj);
@@ -123,8 +107,7 @@
    }
#ifdef Q_OS_MAC
    void
        AbstractWindowContext::setSystemButtonAreaCallback(const ScreenRectCallback &callback) {
    void AbstractWindowContext::setSystemButtonAreaCallback(const ScreenRectCallback &callback) {
        m_systemButtonAreaCallback = callback;
        virtual_hook(SystemButtonAreaChangedHook, nullptr);
    }
@@ -202,20 +185,21 @@
    void AbstractWindowContext::virtual_hook(int id, void *data) {
        switch (id) {
            case CentralizeHook: {
                if (!m_windowHandle)
                if (!m_windowId)
                    return;
                QRect windowGeometry = m_delegate->getGeometry(m_host);
                QRect screenGeometry = m_windowHandle->screen()->geometry();
                int x = (screenGeometry.width() - m_windowHandle->width()) / 2;
                int y = (screenGeometry.height() - m_windowHandle->height()) / 2;
                int x = (screenGeometry.width() - windowGeometry.width()) / 2;
                int y = (screenGeometry.height() - windowGeometry.height()) / 2;
                QPoint pos(x, y);
                pos += screenGeometry.topLeft();
                m_windowHandle->setPosition(pos);
                m_delegate->setGeometry(m_host, QRect(pos, windowGeometry.size()));
                return;
            }
            case RaiseWindowHook: {
                if (!m_windowHandle)
                if (!m_windowId)
                    return;
                m_delegate->setWindowVisible(m_host, true);
@@ -247,14 +231,24 @@
    }
    void AbstractWindowContext::notifyWinIdChange() {
        auto oldWindow = m_windowHandle;
        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);
        if (oldWindow == m_windowHandle)
            return;
        m_windowEventFilter.reset();
        winIdChanged();
        auto windowEventFilter = static_cast<WindowEventFilter *>(m_windowEventFilter.get());
        windowEventFilter->setWindow(nullptr);
        if (oldWinId != m_windowId) {
            winIdChanged(m_windowId, oldWinId);
        }
        if (m_windowHandle) {
            m_windowEventFilter = std::make_unique<WindowEventFilter>(m_windowHandle, this);
            windowEventFilter->setWindow(m_windowHandle);
            // Refresh window attributes
            auto attributes = m_windowAttributes;
@@ -266,6 +260,12 @@
                m_windowAttributes.insert(it.key(), it.value());
            }
        }
        // Send to shared dispatchers
        if (oldWinId != m_windowId) {
            QEvent e(QEvent::WinIdChange);
            sharedDispatch(m_host, &e);
        }
    }
    QVariant AbstractWindowContext::windowAttribute(const QString &key) const {