| | |
| | | |
| | | 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; |
| | |
| | | m_host = host; |
| | | m_delegate.reset(delegate); |
| | | 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) { |
| | | bool AbstractWindowContext::setHitTestVisible(QObject *obj, bool visible) { |
| | | Q_ASSERT(obj); |
| | | if (!obj) { |
| | | return false; |
| | | } |
| | | |
| | | auto it = m_hitTestVisibleItems.find(obj); |
| | | if (visible) { |
| | | if (it != m_hitTestVisibleItems.end()) { |
| | | return true; |
| | | } |
| | | connect(obj, &QObject::destroyed, this, |
| | | &AbstractWindowContext::_q_hitTestVisibleItemDestroyed); |
| | | m_hitTestVisibleItems.insert(obj); |
| | | } else { |
| | | m_hitTestVisibleItems.remove(obj); |
| | | if (it == m_hitTestVisibleItems.end()) { |
| | | return false; |
| | | } |
| | | disconnect(obj, &QObject::destroyed, this, |
| | | &AbstractWindowContext::_q_hitTestVisibleItemDestroyed); |
| | | m_hitTestVisibleItems.erase(it); |
| | | } |
| | | return true; |
| | | } |
| | |
| | | return false; |
| | | } |
| | | |
| | | if (m_systemButtons[button] == obj) { |
| | | return false; |
| | | auto org = m_systemButtons[button]; |
| | | if (org == obj) { |
| | | return true; |
| | | } |
| | | |
| | | if (org) { |
| | | disconnect(org, &QObject::destroyed, this, |
| | | &AbstractWindowContext::_q_systemButtonDestroyed); |
| | | } |
| | | if (obj) { |
| | | connect(obj, &QObject::destroyed, this, |
| | | &AbstractWindowContext::_q_systemButtonDestroyed); |
| | | } |
| | | m_systemButtons[button] = obj; |
| | | return true; |
| | |
| | | |
| | | bool AbstractWindowContext::setTitleBar(QObject *item) { |
| | | Q_ASSERT(item); |
| | | if (m_titleBar == item) { |
| | | auto org = m_titleBar; |
| | | if (org == item) { |
| | | return false; |
| | | } |
| | | |
| | | if (m_titleBar) { |
| | | if (org) { |
| | | // Since the title bar is changed, all items inside it should be dereferenced right away |
| | | for (auto &button : m_systemButtons) { |
| | | button = nullptr; |
| | | } |
| | | m_hitTestVisibleItems.clear(); |
| | | removeSystemButtonsAndHitTestItems(); |
| | | disconnect(org, &QObject::destroyed, this, |
| | | &AbstractWindowContext::_q_titleBarDistroyed); |
| | | } |
| | | |
| | | if (item) { |
| | | connect(item, &QObject::destroyed, this, &AbstractWindowContext::_q_titleBarDistroyed); |
| | | } |
| | | m_titleBar = item; |
| | | return true; |
| | | } |
| | |
| | | // 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; |
| | |
| | | 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) { |
| | | return false; |
| | | } |
| | | |
| | | void AbstractWindowContext::removeSystemButtonsAndHitTestItems() { |
| | | for (auto &button : m_systemButtons) { |
| | | if (!button) { |
| | | continue; |
| | | } |
| | | disconnect(button, &QObject::destroyed, this, |
| | | &AbstractWindowContext::_q_systemButtonDestroyed); |
| | | button = nullptr; |
| | | } |
| | | for (auto &item : m_hitTestVisibleItems) { |
| | | disconnect(item, &QObject::destroyed, this, |
| | | &AbstractWindowContext::_q_hitTestVisibleItemDestroyed); |
| | | } |
| | | m_hitTestVisibleItems.clear(); |
| | | } |
| | | |
| | | void AbstractWindowContext::_q_titleBarDistroyed(QObject *obj) { |
| | | Q_UNUSED(obj) |
| | | removeSystemButtonsAndHitTestItems(); |
| | | m_titleBar = nullptr; |
| | | } |
| | | |
| | | void AbstractWindowContext::_q_hitTestVisibleItemDestroyed(QObject *obj) { |
| | | m_hitTestVisibleItems.remove(obj); |
| | | } |
| | | |
| | | void AbstractWindowContext::_q_systemButtonDestroyed(QObject *obj) { |
| | | for (auto &item : m_systemButtons) { |
| | | if (item == obj) { |
| | | item = nullptr; |
| | | } |
| | | } |
| | | } |
| | | |
| | | } |