diff --git a/scene.cpp b/scene.cpp index 27da36e893..89eeeb9bb0 100644 --- a/scene.cpp +++ b/scene.cpp @@ -82,6 +82,7 @@ along with this program. If not, see . #include "thumbnailitem.h" #include +#include #include namespace KWin @@ -937,6 +938,15 @@ WindowPixmap::WindowPixmap(Scene::Window *window) { } +WindowPixmap::WindowPixmap(const QPointer &subSurface, WindowPixmap *parent) + : m_window(parent->m_window) + , m_pixmap(XCB_PIXMAP_NONE) + , m_discarded(false) + , m_parent(parent) + , m_subSurface(subSurface) +{ +} + WindowPixmap::~WindowPixmap() { if (isValid() && !kwinApp()->shouldUseWaylandForCompositing()) { @@ -957,7 +967,7 @@ void WindowPixmap::create() if (kwinApp()->shouldUseWaylandForCompositing()) { // use Buffer updateBuffer(); - if (m_buffer || !m_fbo.isNull()) { + if ((m_buffer || !m_fbo.isNull()) && m_subSurface.isNull()) { m_window->unreferencePreviousPixmap(); } return; @@ -991,6 +1001,12 @@ void WindowPixmap::create() m_window->unreferencePreviousPixmap(); } +WindowPixmap *WindowPixmap::createChild(const QPointer &subSurface) +{ + Q_UNUSED(subSurface) + return nullptr; +} + bool WindowPixmap::isValid() const { if (kwinApp()->shouldUseWaylandForCompositing()) { @@ -1001,9 +1017,42 @@ bool WindowPixmap::isValid() const void WindowPixmap::updateBuffer() { - if (auto s = toplevel()->surface()) { + using namespace KWayland::Server; + SurfaceInterface *s = nullptr; + if (!m_subSurface.isNull()) { + s = m_subSurface->surface().data(); + } else { + s = toplevel()->surface(); + } + if (s) { + QVector oldTree = m_children; + QVector children; using namespace KWayland::Server; + const auto subSurfaces = s->childSubSurfaces(); + for (const auto &subSurface : subSurfaces) { + if (subSurface.isNull()) { + continue; + } + auto it = std::find_if(oldTree.begin(), oldTree.end(), [subSurface] (WindowPixmap *p) { return p->m_subSurface == subSurface; }); + if (it != oldTree.end()) { + children << *it; + (*it)->updateBuffer(); + oldTree.erase(it); + } else { + WindowPixmap *p = createChild(subSurface); + if (p) { + p->create(); + children << p; + } + } + } + setChildren(children); + qDeleteAll(oldTree); if (auto b = s->buffer()) { + if (b == m_buffer) { + // no change + return; + } if (m_buffer) { QObject::disconnect(m_buffer.data(), &BufferInterface::aboutToBeDestroyed, m_buffer.data(), &BufferInterface::unref); m_buffer->unref(); @@ -1011,6 +1060,12 @@ void WindowPixmap::updateBuffer() m_buffer = b; m_buffer->ref(); QObject::connect(m_buffer.data(), &BufferInterface::aboutToBeDestroyed, m_buffer.data(), &BufferInterface::unref); + } else if (m_subSurface) { + if (m_buffer) { + QObject::disconnect(m_buffer.data(), &BufferInterface::aboutToBeDestroyed, m_buffer.data(), &BufferInterface::unref); + m_buffer->unref(); + m_buffer.clear(); + } } else { // might be an internal window const auto &fbo = toplevel()->internalFramebufferObject(); @@ -1018,6 +1073,12 @@ void WindowPixmap::updateBuffer() m_fbo = fbo; } } + } else { + if (m_buffer) { + QObject::disconnect(m_buffer.data(), &BufferInterface::aboutToBeDestroyed, m_buffer.data(), &BufferInterface::unref); + m_buffer->unref(); + m_buffer.clear(); + } } } diff --git a/scene.h b/scene.h index 279f71394d..7eb1347da7 100644 --- a/scene.h +++ b/scene.h @@ -35,6 +35,7 @@ namespace KWayland namespace Server { class BufferInterface; +class SubSurfaceInterface; } } @@ -392,8 +393,31 @@ public: */ Toplevel *toplevel() const; + /** + * @returns the parent WindowPixmap in the sub-surface tree + **/ + WindowPixmap *parent() const { + return m_parent; + } + + /** + * @returns the current sub-surface tree + **/ + QVector children() const { + return m_children; + } + + /** + * @returns the subsurface this WindowPixmap is for if it is not for a root window + **/ + QPointer subSurface() const { + return m_subSurface; + } + protected: explicit WindowPixmap(Scene::Window *window); + explicit WindowPixmap(const QPointer &subSurface, WindowPixmap *parent); + virtual WindowPixmap *createChild(const QPointer &subSurface); /** * @return The Window this WindowPixmap belongs to */ @@ -403,7 +427,15 @@ protected: * Should be called by the implementing subclasses when the Wayland Buffer changed and needs * updating. **/ - void updateBuffer(); + virtual void updateBuffer(); + + /** + * Sets the sub-surface tree to @p children. + **/ + void setChildren(const QVector &children) { + m_children = children; + } + private: Scene::Window *m_window; xcb_pixmap_t m_pixmap; @@ -412,6 +444,9 @@ private: QRect m_contentsRect; QPointer m_buffer; QSharedPointer m_fbo; + WindowPixmap *m_parent = nullptr; + QVector m_children; + QPointer m_subSurface; }; class Scene::EffectFrame