diff --git a/src/declarativeimports/core/windowthumbnail.h b/src/declarativeimports/core/windowthumbnail.h --- a/src/declarativeimports/core/windowthumbnail.h +++ b/src/declarativeimports/core/windowthumbnail.h @@ -27,6 +27,8 @@ #include #include #include +#include +#include // xcb #if HAVE_XCB_COMPOSITE #include @@ -100,21 +102,25 @@ void thumbnailAvailableChanged(); protected: + void itemChange(ItemChange change, const ItemChangeData &data) override; void releaseResources() override; private: void iconToTexture(WindowTextureNode *textureNode); void windowToTexture(WindowTextureNode *textureNode); - void startRedirecting(); + bool startRedirecting(); void stopRedirecting(); void resetDamaged(); void setThumbnailAvailable(bool thumbnailAvailable); + void sceneVisibilityChanged(bool visible); bool m_xcb; bool m_composite; + QPointer m_scene; uint32_t m_winId; QSizeF m_paintedSize; bool m_thumbnailAvailable; + bool m_redirecting; bool m_damaged; int m_depth; #if HAVE_XCB_COMPOSITE diff --git a/src/declarativeimports/core/windowthumbnail.cpp b/src/declarativeimports/core/windowthumbnail.cpp --- a/src/declarativeimports/core/windowthumbnail.cpp +++ b/src/declarativeimports/core/windowthumbnail.cpp @@ -137,6 +137,7 @@ , m_winId(0) , m_paintedSize(QSizeF()) , m_thumbnailAvailable(false) + , m_redirecting(false) , m_damaged(false) , m_depth(0) #if HAVE_XCB_COMPOSITE @@ -160,33 +161,7 @@ #endif { setFlag(ItemHasContents); - connect(this, &QQuickItem::windowChanged, [this](QQuickWindow * window) { - if (!window) { - return; - } - // restart the redirection, it might not have been active yet - stopRedirecting(); - startRedirecting(); - update(); - }); - connect(this, &QQuickItem::enabledChanged, [this]() { - if (!isEnabled()) { - stopRedirecting(); - releaseResources(); - } else if (isVisible()) { - startRedirecting(); - update(); - } - }); - connect(this, &QQuickItem::visibleChanged, [this]() { - if (!isVisible()) { - stopRedirecting(); - releaseResources(); - } else if (isEnabled()) { - startRedirecting(); - update(); - } - }); + if (QGuiApplication *gui = dynamic_cast(QCoreApplication::instance())) { m_xcb = (gui->platformName() == QStringLiteral("xcb")); if (m_xcb) { @@ -216,6 +191,42 @@ } } +void WindowThumbnail::itemChange(ItemChange change, const ItemChangeData &data) +{ + switch (change) { + case ItemSceneChange: + if (m_scene) { + disconnect(m_scene.data(), &QWindow::visibleChanged, this, &WindowThumbnail::sceneVisibilityChanged); + } + m_scene = data.window; + if (m_scene) { + connect(m_scene.data(), &QWindow::visibleChanged, this, &WindowThumbnail::sceneVisibilityChanged); + // restart the redirection, it might not have been active yet + stopRedirecting(); + if (startRedirecting()) { + update(); + } + } + break; + + case ItemEnabledHasChanged: + Q_FALLTHROUGH(); + case ItemVisibleHasChanged: + if (data.boolValue) { + if (startRedirecting()) { + update(); + } + } else { + stopRedirecting(); + releaseResources(); + } + break; + + default: + break; + } +} + void WindowThumbnail::releaseResources() { #if HAVE_XCB_COMPOSITE @@ -843,31 +854,35 @@ if (m_winId == XCB_WINDOW_NONE) { return; } - xcb_composite_unredirect_window(c, m_winId, XCB_COMPOSITE_REDIRECT_AUTOMATIC); + if (m_redirecting) { + xcb_composite_unredirect_window(c, m_winId, XCB_COMPOSITE_REDIRECT_AUTOMATIC); + } + m_redirecting = false; if (m_damage == XCB_NONE) { return; } xcb_damage_destroy(c, m_damage); m_damage = XCB_NONE; #endif } -void WindowThumbnail::startRedirecting() +bool WindowThumbnail::startRedirecting() { - if (!m_xcb || !m_composite || !window() || window()->winId() == m_winId) { - return; + if (!m_xcb || !m_composite || !window() || !window()->isVisible() || window()->winId() == m_winId || !isEnabled() || !isVisible()) { + return false; } #if HAVE_XCB_COMPOSITE if (m_winId == XCB_WINDOW_NONE) { - return; + return false; } xcb_connection_t *c = QX11Info::connection(); // need to get the window attributes for the existing event mask const auto attribsCookie = xcb_get_window_attributes_unchecked(c, m_winId); // redirect the window xcb_composite_redirect_window(c, m_winId, XCB_COMPOSITE_REDIRECT_AUTOMATIC); + m_redirecting = true; // generate the damage handle m_damage = xcb_generate_id(c); @@ -883,6 +898,9 @@ xcb_change_window_attributes(c, m_winId, XCB_CW_EVENT_MASK, &events); // force to update the texture m_damaged = true; + return true; +#else + return false; #endif } @@ -896,4 +914,16 @@ } } +void WindowThumbnail::sceneVisibilityChanged(bool visible) +{ + if (visible) { + if (startRedirecting()) { + update(); + } + } else { + stopRedirecting(); + releaseResources(); + } +} + } // namespace