[Window Thumbnail] Also monitor scene visibility and clean up

Just because the item is visible doesn't mean the window itself is. Keep track of the window it's in.
Use itemChange instead of connects and move the check for starting to startRedirect so we don't have to check the conditions
for that in every change handler (visible && enabled && window->visible). It also saves three connects in the constructor.
Also, don't unredirect if we didn't redirect in the first place to avoid warnings printed on console.

BUG: 406303

Differential Revision: https://phabricator.kde.org/D20805
This commit is contained in:
Kai Uwe Broulik 2019-04-25 15:01:40 +02:00
parent 9aeaf7cbb5
commit 1b2424879a
2 changed files with 69 additions and 33 deletions

View File

@ -137,6 +137,7 @@ WindowThumbnail::WindowThumbnail(QQuickItem *parent)
, 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 @@ WindowThumbnail::WindowThumbnail(QQuickItem *parent)
#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<QGuiApplication *>(QCoreApplication::instance())) {
m_xcb = (gui->platformName() == QStringLiteral("xcb"));
if (m_xcb) {
@ -216,6 +191,42 @@ WindowThumbnail::~WindowThumbnail()
}
}
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,7 +854,10 @@ void WindowThumbnail::stopRedirecting()
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;
}
@ -852,14 +866,14 @@ void WindowThumbnail::stopRedirecting()
#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();
@ -868,6 +882,7 @@ void WindowThumbnail::startRedirecting()
// 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 @@ void WindowThumbnail::startRedirecting()
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::setThumbnailAvailable(bool thumbnailAvailable)
}
}
void WindowThumbnail::sceneVisibilityChanged(bool visible)
{
if (visible) {
if (startRedirecting()) {
update();
}
} else {
stopRedirecting();
releaseResources();
}
}
} // namespace

View File

@ -27,6 +27,8 @@
#include <QAbstractNativeEventFilter>
#include <QSGSimpleTextureNode>
#include <QQuickItem>
#include <QPointer>
#include <QWindow>
// xcb
#if HAVE_XCB_COMPOSITE
#include <xcb/damage.h>
@ -100,21 +102,25 @@ Q_SIGNALS:
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<QWindow> 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