From f46c7bae8ddc8e1b6893bc52900a8d44f6954df7 Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Mon, 26 Apr 2021 19:38:40 +0300 Subject: [PATCH] Move decoration renderer to decoration item Currently, the implementation of the DecoratedClient and the decoration renderer are strongly coupled. This poses a problem with the item based design as the ultimate goal is to have scene items construct paint nodes which are then fed to the renderer. The DecorationItem has to have control over the decoration texture. Another issue is that the scene cannot smoothly cross-fade between two window states if the decoration is removed, e.g. from fullscreen mode to normal and vice versa. This change moves the decoration renderer to the decoration item. With the introduction of a generic scene texture atlas, we hope to get rid of the decoration renderer altogether. --- src/CMakeLists.txt | 1 - src/decorationitem.cpp | 120 +++++++++++++++++- src/decorationitem.h | 47 +++++++ src/decorations/decoratedclient.cpp | 27 ---- src/decorations/decoratedclient.h | 9 -- src/decorations/decorationbridge.cpp | 1 - src/decorations/decorationrenderer.cpp | 102 --------------- src/decorations/decorationrenderer.h | 76 ----------- src/deleted.cpp | 18 +-- src/deleted.h | 12 -- src/platform.cpp | 8 -- src/platform.h | 13 -- .../platforms/x11/standalone/CMakeLists.txt | 1 - .../standalone/x11_decoration_renderer.cpp | 98 -------------- .../x11/standalone/x11_decoration_renderer.h | 44 ------- .../platforms/x11/standalone/x11_platform.cpp | 10 -- .../platforms/x11/standalone/x11_platform.h | 1 - src/plugins/scenes/opengl/scene_opengl.cpp | 41 ++---- src/plugins/scenes/opengl/scene_opengl.h | 10 +- .../scenes/qpainter/scene_qpainter.cpp | 41 ++---- src/plugins/scenes/qpainter/scene_qpainter.h | 11 +- src/plugins/scenes/xrender/scene_xrender.cpp | 44 +++---- src/plugins/scenes/xrender/scene_xrender.h | 9 +- src/scene.cpp | 1 - src/scene.h | 5 +- src/windowitem.h | 1 + src/x11client.cpp | 87 +++++++++++++ src/x11client.h | 27 ++++ 28 files changed, 328 insertions(+), 537 deletions(-) delete mode 100644 src/decorations/decorationrenderer.cpp delete mode 100644 src/decorations/decorationrenderer.h delete mode 100644 src/plugins/platforms/x11/standalone/x11_decoration_renderer.cpp delete mode 100644 src/plugins/platforms/x11/standalone/x11_decoration_renderer.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 64843c77e2..d84de67625 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -37,7 +37,6 @@ set(kwin_SRCS decorations/decoratedclient.cpp decorations/decorationbridge.cpp decorations/decorationpalette.cpp - decorations/decorationrenderer.cpp decorations/decorations_logging.cpp decorations/settings.cpp deleted.cpp diff --git a/src/decorationitem.cpp b/src/decorationitem.cpp index 772be06143..3aed875393 100644 --- a/src/decorationitem.cpp +++ b/src/decorationitem.cpp @@ -1,30 +1,137 @@ /* + SPDX-FileCopyrightText: 2014 Martin Gräßlin SPDX-FileCopyrightText: 2021 Vlad Zahorodnii SPDX-License-Identifier: GPL-2.0-or-later */ #include "decorationitem.h" +#include "abstract_client.h" +#include "composite.h" +#include "decorations/decoratedclient.h" +#include "scene.h" +#include "utils.h" #include +#include + +#include namespace KWin { +DecorationRenderer::DecorationRenderer(Decoration::DecoratedClientImpl *client) + : m_client(client) + , m_imageSizesDirty(true) +{ + connect(client->decoration(), &KDecoration2::Decoration::damaged, + this, &DecorationRenderer::addDamage); + + connect(client->client(), &AbstractClient::screenScaleChanged, + this, &DecorationRenderer::invalidate); + connect(client->decoration(), &KDecoration2::Decoration::bordersChanged, + this, &DecorationRenderer::invalidate); + connect(client->decoratedClient(), &KDecoration2::DecoratedClient::sizeChanged, + this, &DecorationRenderer::invalidate); + + invalidate(); +} + +Decoration::DecoratedClientImpl *DecorationRenderer::client() const +{ + return m_client; +} + +void DecorationRenderer::invalidate() +{ + addDamage(m_client->client()->rect()); + m_imageSizesDirty = true; +} + +QRegion DecorationRenderer::damage() const +{ + return m_damage; +} + +void DecorationRenderer::addDamage(const QRegion ®ion) +{ + m_damage += region; + emit damaged(region); +} + +void DecorationRenderer::resetDamage() +{ + m_damage = QRegion(); +} + +QImage DecorationRenderer::renderToImage(const QRect &geo) +{ + Q_ASSERT(m_client); + auto dpr = client()->client()->screenScale(); + + // Guess the pixel format of the X pixmap into which the QImage will be copied. + QImage::Format format; + const int depth = client()->client()->depth(); + switch (depth) { + case 30: + format = QImage::Format_A2RGB30_Premultiplied; + break; + case 24: + case 32: + format = QImage::Format_ARGB32_Premultiplied; + break; + default: + qCCritical(KWIN_CORE) << "Unsupported client depth" << depth; + format = QImage::Format_ARGB32_Premultiplied; + break; + }; + + QImage image(geo.width() * dpr, geo.height() * dpr, format); + image.setDevicePixelRatio(dpr); + image.fill(Qt::transparent); + QPainter p(&image); + p.setRenderHint(QPainter::Antialiasing); + p.setWindow(QRect(geo.topLeft(), geo.size() * qPainterEffectiveDevicePixelRatio(&p))); + p.setClipRect(geo); + renderToPainter(&p, geo); + return image; +} + +void DecorationRenderer::renderToPainter(QPainter *painter, const QRect &rect) +{ + client()->decoration()->paint(painter, rect); +} + DecorationItem::DecorationItem(KDecoration2::Decoration *decoration, Scene::Window *window, Item *parent) : Item(window, parent) { - Toplevel *toplevel = window->window(); + AbstractClient *client = qobject_cast(window->window()); + m_renderer.reset(Compositor::self()->scene()->createDecorationRenderer(client->decoratedClient())); - connect(toplevel, &Toplevel::frameGeometryChanged, + connect(client, &Toplevel::frameGeometryChanged, this, &DecorationItem::handleFrameGeometryChanged); - connect(toplevel, &Toplevel::screenScaleChanged, + connect(client, &Toplevel::screenScaleChanged, this, &DecorationItem::discardQuads); connect(decoration, &KDecoration2::Decoration::bordersChanged, this, &DecorationItem::discardQuads); - setSize(toplevel->size()); + connect(renderer(), &DecorationRenderer::damaged, + this, &DecorationItem::scheduleRepaint); + + // If the decoration is about to be destroyed, render the decoration for the last time. + connect(client, &Toplevel::markedAsZombie, this, &DecorationItem::preprocess); + + setSize(client->size()); +} + +void DecorationItem::preprocess() +{ + const QRegion damage = m_renderer->damage(); + if (!damage.isEmpty()) { + m_renderer->render(damage); + m_renderer->resetDamage(); + } } void DecorationItem::handleFrameGeometryChanged() @@ -32,4 +139,9 @@ void DecorationItem::handleFrameGeometryChanged() setSize(window()->size()); } +DecorationRenderer *DecorationItem::renderer() const +{ + return m_renderer.data(); +} + } // namespace KWin diff --git a/src/decorationitem.h b/src/decorationitem.h index 1abd298433..f31abe8d54 100644 --- a/src/decorationitem.h +++ b/src/decorationitem.h @@ -16,6 +16,47 @@ class Decoration; namespace KWin { +namespace Decoration +{ +class DecoratedClientImpl; +} + +class KWIN_EXPORT DecorationRenderer : public QObject +{ + Q_OBJECT + +public: + virtual void render(const QRegion ®ion) = 0; + void invalidate(); + + // TODO: Move damage tracking inside DecorationItem. + QRegion damage() const; + void addDamage(const QRegion ®ion); + void resetDamage(); + +Q_SIGNALS: + void damaged(const QRegion ®ion); + +protected: + explicit DecorationRenderer(Decoration::DecoratedClientImpl *client); + + Decoration::DecoratedClientImpl *client() const; + + bool areImageSizesDirty() const { + return m_imageSizesDirty; + } + void resetImageSizesDirty() { + m_imageSizesDirty = false; + } + QImage renderToImage(const QRect &geo); + void renderToPainter(QPainter *painter, const QRect &rect); + +private: + QPointer m_client; + QRegion m_damage; + bool m_imageSizesDirty; +}; + /** * The DecorationItem class represents a server-side decoration. */ @@ -26,11 +67,17 @@ class KWIN_EXPORT DecorationItem : public Item public: explicit DecorationItem(KDecoration2::Decoration *decoration, Scene::Window *window, Item *parent = nullptr); + DecorationRenderer *renderer() const; + private Q_SLOTS: void handleFrameGeometryChanged(); +protected: + void preprocess() override; + private: QPointer m_decoration; + QScopedPointer m_renderer; }; } // namespace KWin diff --git a/src/decorations/decoratedclient.cpp b/src/decorations/decoratedclient.cpp index f8782be60a..ac55de3010 100644 --- a/src/decorations/decoratedclient.cpp +++ b/src/decorations/decoratedclient.cpp @@ -9,7 +9,6 @@ #include "decoratedclient.h" #include "decorationbridge.h" #include "decorationpalette.h" -#include "decorationrenderer.h" #include "abstract_client.h" #include "composite.h" #include "cursor.h" @@ -33,9 +32,7 @@ DecoratedClientImpl::DecoratedClientImpl(AbstractClient *client, KDecoration2::D , ApplicationMenuEnabledDecoratedClientPrivate(decoratedClient, decoration) , m_client(client) , m_clientSize(client->clientSize()) - , m_renderer(nullptr) { - createRenderer(); client->setDecoratedClient(QPointer(this)); connect(client, &AbstractClient::activeChanged, this, [decoratedClient, client]() { @@ -77,19 +74,6 @@ DecoratedClientImpl::DecoratedClientImpl(AbstractClient *client, KDecoration2::D &Decoration::DecoratedClientImpl::signalShadeChange); connect(client, &AbstractClient::keepAboveChanged, decoratedClient, &KDecoration2::DecoratedClient::keepAboveChanged); connect(client, &AbstractClient::keepBelowChanged, decoratedClient, &KDecoration2::DecoratedClient::keepBelowChanged); - connect(Compositor::self(), &Compositor::aboutToToggleCompositing, this, &DecoratedClientImpl::destroyRenderer); - m_compositorToggledConnection = connect(Compositor::self(), &Compositor::compositingToggled, this, - [this, decoration]() { - createRenderer(); - decoration->update(); - } - ); - connect(Compositor::self(), &Compositor::aboutToDestroy, this, - [this] { - disconnect(m_compositorToggledConnection); - m_compositorToggledConnection = QMetaObject::Connection(); - } - ); connect(client, &AbstractClient::quickTileModeChanged, decoratedClient, [this, decoratedClient]() { emit decoratedClient->adjacentScreenEdgesChanged(adjacentScreenEdges()); @@ -318,16 +302,5 @@ bool DecoratedClientImpl::isApplicationMenuActive() const return m_client->applicationMenuActive(); } -void DecoratedClientImpl::createRenderer() -{ - m_renderer = kwinApp()->platform()->createDecorationRenderer(this); -} - -void DecoratedClientImpl::destroyRenderer() -{ - delete m_renderer; - m_renderer = nullptr; -} - } } diff --git a/src/decorations/decoratedclient.h b/src/decorations/decoratedclient.h index 49f8be515f..78d036788e 100644 --- a/src/decorations/decoratedclient.h +++ b/src/decorations/decoratedclient.h @@ -24,8 +24,6 @@ class AbstractClient; namespace Decoration { -class Renderer; - class DecoratedClientImpl : public QObject, public KDecoration2::ApplicationMenuEnabledDecoratedClientPrivate { Q_OBJECT @@ -82,9 +80,6 @@ public: AbstractClient *client() { return m_client; } - Renderer *renderer() { - return m_renderer; - } KDecoration2::DecoratedClient *decoratedClient() { return KDecoration2::DecoratedClientPrivate::client(); } @@ -95,12 +90,8 @@ private Q_SLOTS: void delayedRequestToggleMaximization(Options::WindowOperation operation); private: - void createRenderer(); - void destroyRenderer(); AbstractClient *m_client; QSize m_clientSize; - Renderer *m_renderer; - QMetaObject::Connection m_compositorToggledConnection; QString m_toolTipText; QTimer m_toolTipWakeUp; diff --git a/src/decorations/decorationbridge.cpp b/src/decorations/decorationbridge.cpp index 66ac9e9b4c..362927df36 100644 --- a/src/decorations/decorationbridge.cpp +++ b/src/decorations/decorationbridge.cpp @@ -8,7 +8,6 @@ */ #include "decorationbridge.h" #include "decoratedclient.h" -#include "decorationrenderer.h" #include "decorations_logging.h" #include "settings.h" // KWin core diff --git a/src/decorations/decorationrenderer.cpp b/src/decorations/decorationrenderer.cpp deleted file mode 100644 index 612870b073..0000000000 --- a/src/decorations/decorationrenderer.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* - KWin - the KDE window manager - This file is part of the KDE project. - - SPDX-FileCopyrightText: 2014 Martin Gräßlin - - SPDX-License-Identifier: GPL-2.0-or-later -*/ -#include "decorationrenderer.h" -#include "decoratedclient.h" -#include "decorations/decorations_logging.h" -#include "deleted.h" -#include "abstract_client.h" -#include "screens.h" - -#include -#include - -#include -#include - -namespace KWin -{ -namespace Decoration -{ - -Renderer::Renderer(DecoratedClientImpl *client) - : QObject(client) - , m_client(client) - , m_imageSizesDirty(true) -{ - auto markImageSizesDirty = [this]{ - schedule(m_client->client()->rect()); - m_imageSizesDirty = true; - }; - connect(client->decoration(), &KDecoration2::Decoration::damaged, this, &Renderer::schedule); - connect(client->client(), &AbstractClient::screenScaleChanged, this, markImageSizesDirty); - connect(client->decoration(), &KDecoration2::Decoration::bordersChanged, this, markImageSizesDirty); - connect(client->decoratedClient(), &KDecoration2::DecoratedClient::sizeChanged, this, markImageSizesDirty); -} - -Renderer::~Renderer() = default; - -void Renderer::schedule(const QRegion &rect) -{ - m_scheduled = m_scheduled.united(rect); - emit renderScheduled(rect); -} - -QRegion Renderer::getScheduled() -{ - QRegion region = m_scheduled; - m_scheduled = QRegion(); - return region; -} - -QImage Renderer::renderToImage(const QRect &geo) -{ - Q_ASSERT(m_client); - auto dpr = client()->client()->screenScale(); - - // Guess the pixel format of the X pixmap into which the QImage will be copied. - QImage::Format format; - const int depth = client()->client()->depth(); - switch (depth) { - case 30: - format = QImage::Format_A2RGB30_Premultiplied; - break; - case 24: - case 32: - format = QImage::Format_ARGB32_Premultiplied; - break; - default: - qCCritical(KWIN_DECORATIONS) << "Unsupported client depth" << depth; - format = QImage::Format_ARGB32_Premultiplied; - break; - }; - - QImage image(geo.width() * dpr, geo.height() * dpr, format); - image.setDevicePixelRatio(dpr); - image.fill(Qt::transparent); - QPainter p(&image); - p.setRenderHint(QPainter::Antialiasing); - p.setWindow(QRect(geo.topLeft(), geo.size() * qPainterEffectiveDevicePixelRatio(&p))); - p.setClipRect(geo); - renderToPainter(&p, geo); - return image; -} - -void Renderer::renderToPainter(QPainter *painter, const QRect &rect) -{ - client()->decoration()->paint(painter, rect); -} - -void Renderer::reparent(Deleted *deleted) -{ - setParent(deleted); - m_client = nullptr; -} - -} -} diff --git a/src/decorations/decorationrenderer.h b/src/decorations/decorationrenderer.h deleted file mode 100644 index 0946658694..0000000000 --- a/src/decorations/decorationrenderer.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - KWin - the KDE window manager - This file is part of the KDE project. - - SPDX-FileCopyrightText: 2014 Martin Gräßlin - - SPDX-License-Identifier: GPL-2.0-or-later -*/ -#ifndef KWIN_DECORATION_RENDERER_H -#define KWIN_DECORATION_RENDERER_H - -#include -#include - -#include - -namespace KWin -{ - -class Deleted; - -namespace Decoration -{ - -class DecoratedClientImpl; - -class KWIN_EXPORT Renderer : public QObject -{ - Q_OBJECT -public: - ~Renderer() override; - - void schedule(const QRegion ®ion); - - /** - * Reparents this Renderer to the @p deleted. - * After this call the Renderer is no longer able to render - * anything, client() returns a nullptr. - */ - virtual void reparent(Deleted *deleted); - -Q_SIGNALS: - void renderScheduled(const QRegion &geo); - -protected: - explicit Renderer(DecoratedClientImpl *client); - /** - * @returns the scheduled paint region and resets - */ - QRegion getScheduled(); - - virtual void render() = 0; - - DecoratedClientImpl *client() { - return m_client; - } - - bool areImageSizesDirty() const { - return m_imageSizesDirty; - } - void resetImageSizesDirty() { - m_imageSizesDirty = false; - } - QImage renderToImage(const QRect &geo); - void renderToPainter(QPainter *painter, const QRect &rect); - -private: - DecoratedClientImpl *m_client; - QRegion m_scheduled; - bool m_imageSizesDirty; -}; - -} -} - -#endif diff --git a/src/deleted.cpp b/src/deleted.cpp index c52808f4ab..9f4188f852 100644 --- a/src/deleted.cpp +++ b/src/deleted.cpp @@ -14,8 +14,6 @@ #include "group.h" #include "netinfo.h" #include "shadow.h" -#include "decorations/decoratedclient.h" -#include "decorations/decorationrenderer.h" #include @@ -30,13 +28,11 @@ Deleted::Deleted() , m_minimized(false) , m_modal(false) , m_wasClient(false) - , m_decorationRenderer(nullptr) , m_fullscreen(false) , m_keepAbove(false) , m_keepBelow(false) , m_wasPopupWindow(false) , m_wasOutline(false) - , m_wasDecorated(false) , m_wasLockScreen(false) { } @@ -85,18 +81,11 @@ void Deleted::copyToDeleted(Toplevel* c) if (WinInfo* cinfo = dynamic_cast< WinInfo* >(info)) cinfo->disable(); if (AbstractClient *client = dynamic_cast(c)) { - m_wasDecorated = client->isDecorated(); - if (m_wasDecorated) { + if (client->isDecorated()) { client->layoutDecorationRects(decoration_left, decoration_top, decoration_right, decoration_bottom); - if (client->isDecorated()) { - if (Decoration::Renderer *renderer = client->decoratedClient()->renderer()) { - m_decorationRenderer = renderer; - m_decorationRenderer->reparent(this); - } - } } m_wasClient = true; m_minimized = client->isMinimized(); @@ -163,11 +152,6 @@ QPoint Deleted::clientPos() const return contentsRect.topLeft(); } -bool Deleted::wasDecorated() const -{ - return m_wasDecorated; -} - void Deleted::layoutDecorationRects(QRect& left, QRect& top, QRect& right, QRect& bottom) const { left = decoration_left; diff --git a/src/deleted.h b/src/deleted.h index 7512426f97..9165abe46c 100644 --- a/src/deleted.h +++ b/src/deleted.h @@ -17,11 +17,6 @@ namespace KWin class AbstractClient; -namespace Decoration -{ -class Renderer; -} - class KWIN_EXPORT Deleted : public Toplevel { Q_OBJECT @@ -41,7 +36,6 @@ public: QRect transparentRect() const override; bool isDeleted() const override; xcb_window_t frameId() const override; - bool wasDecorated() const; void layoutDecorationRects(QRect &left, QRect &top, QRect &right, QRect &bottom) const; Layer layer() const override { return m_layer; @@ -61,10 +55,6 @@ public: } QByteArray windowRole() const override; - const Decoration::Renderer *decorationRenderer() const { - return m_decorationRenderer; - } - bool isFullScreen() const { return m_fullscreen; } @@ -127,7 +117,6 @@ private: bool m_modal; QList m_mainClients; bool m_wasClient; - Decoration::Renderer *m_decorationRenderer; NET::WindowType m_type = NET::Unknown; QByteArray m_windowRole; bool m_fullscreen; @@ -136,7 +125,6 @@ private: QString m_caption; bool m_wasPopupWindow; bool m_wasOutline; - bool m_wasDecorated; bool m_wasLockScreen; qreal m_bufferScale = 1; }; diff --git a/src/platform.cpp b/src/platform.cpp index c9c31ab160..5e86995236 100644 --- a/src/platform.cpp +++ b/src/platform.cpp @@ -595,14 +595,6 @@ OutlineVisual *Platform::createOutline(Outline *outline) return nullptr; } -Decoration::Renderer *Platform::createDecorationRenderer(Decoration::DecoratedClientImpl *client) -{ - if (Compositor::self()->scene()) { - return Compositor::self()->scene()->createDecorationRenderer(client); - } - return nullptr; -} - void Platform::invertScreen() { if (effects) { diff --git a/src/platform.h b/src/platform.h index 43a6cfc135..1671958f81 100644 --- a/src/platform.h +++ b/src/platform.h @@ -45,12 +45,6 @@ class Toplevel; class XRenderBackend; #endif -namespace Decoration -{ -class Renderer; -class DecoratedClientImpl; -} - class KWIN_EXPORT Outputs : public QVector { public: @@ -359,13 +353,6 @@ public: */ virtual OutlineVisual *createOutline(Outline *outline); - /** - * Creates the Decoration::Renderer for the given @p client. - * - * The default implementation creates a Renderer suited for the Compositor, @c nullptr if there is no Compositor. - */ - virtual Decoration::Renderer *createDecorationRenderer(Decoration::DecoratedClientImpl *client); - /** * Platform specific way to invert the screen. * Default implementation invokes the invert effect diff --git a/src/plugins/platforms/x11/standalone/CMakeLists.txt b/src/plugins/platforms/x11/standalone/CMakeLists.txt index eb75be594a..38b16fec68 100644 --- a/src/plugins/platforms/x11/standalone/CMakeLists.txt +++ b/src/plugins/platforms/x11/standalone/CMakeLists.txt @@ -8,7 +8,6 @@ set(X11PLATFORM_SOURCES overlaywindow_x11.cpp screenedges_filter.cpp windowselector.cpp - x11_decoration_renderer.cpp x11_output.cpp x11_platform.cpp x11cursor.cpp diff --git a/src/plugins/platforms/x11/standalone/x11_decoration_renderer.cpp b/src/plugins/platforms/x11/standalone/x11_decoration_renderer.cpp deleted file mode 100644 index bb2096c89f..0000000000 --- a/src/plugins/platforms/x11/standalone/x11_decoration_renderer.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* - KWin - the KDE window manager - This file is part of the KDE project. - - SPDX-FileCopyrightText: 2014 Martin Gräßlin - - SPDX-License-Identifier: GPL-2.0-or-later -*/ -#include "x11_decoration_renderer.h" -#include "decorations/decoratedclient.h" -#include "x11client.h" -#include "deleted.h" - -#include - -#include -#include - -#include - -namespace KWin -{ -namespace Decoration -{ - -X11Renderer::X11Renderer(DecoratedClientImpl *client) - : Renderer(client) - , m_scheduleTimer(new QTimer(this)) - , m_gc(XCB_NONE) -{ - // delay any rendering to end of event cycle to catch multiple updates per cycle - m_scheduleTimer->setSingleShot(true); - m_scheduleTimer->setInterval(0); - connect(m_scheduleTimer, &QTimer::timeout, this, &X11Renderer::render); - connect(this, &Renderer::renderScheduled, m_scheduleTimer, static_cast(&QTimer::start)); -} - -X11Renderer::~X11Renderer() -{ - if (m_gc != XCB_NONE) { - xcb_free_gc(connection(), m_gc); - } -} - -void X11Renderer::reparent(Deleted *deleted) -{ - if (m_scheduleTimer->isActive()) { - m_scheduleTimer->stop(); - } - disconnect(m_scheduleTimer, &QTimer::timeout, this, &X11Renderer::render); - disconnect(this, &Renderer::renderScheduled, m_scheduleTimer, static_cast(&QTimer::start)); - Renderer::reparent(deleted); -} - -void X11Renderer::render() -{ - if (!client()) { - return; - } - const QRegion scheduled = getScheduled(); - if (scheduled.isEmpty()) { - return; - } - xcb_connection_t *c = connection(); - if (m_gc == XCB_NONE) { - m_gc = xcb_generate_id(c); - xcb_create_gc(c, m_gc, client()->client()->frameId(), 0, nullptr); - } - - QRect left, top, right, bottom; - client()->client()->layoutDecorationRects(left, top, right, bottom); - - const QRect geometry = scheduled.boundingRect(); - left = left.intersected(geometry); - top = top.intersected(geometry); - right = right.intersected(geometry); - bottom = bottom.intersected(geometry); - - auto renderPart = [this, c](const QRect &geo) { - if (!geo.isValid()) { - return; - } - QImage image = renderToImage(geo); - xcb_put_image(c, XCB_IMAGE_FORMAT_Z_PIXMAP, client()->client()->frameId(), m_gc, - image.width(), image.height(), geo.x(), geo.y(), 0, client()->client()->depth(), - image.sizeInBytes(), image.constBits()); - }; - renderPart(left); - renderPart(top); - renderPart(right); - renderPart(bottom); - - xcb_flush(c); - resetImageSizesDirty(); -} - -} -} diff --git a/src/plugins/platforms/x11/standalone/x11_decoration_renderer.h b/src/plugins/platforms/x11/standalone/x11_decoration_renderer.h deleted file mode 100644 index 5a54e4dc52..0000000000 --- a/src/plugins/platforms/x11/standalone/x11_decoration_renderer.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - KWin - the KDE window manager - This file is part of the KDE project. - - SPDX-FileCopyrightText: 2014 Martin Gräßlin - - SPDX-License-Identifier: GPL-2.0-or-later -*/ -#ifndef KWIN_DECORATION_X11_RENDERER_H -#define KWIN_DECORATION_X11_RENDERER_H - -#include "decorations/decorationrenderer.h" - -#include - -class QTimer; - -namespace KWin -{ - -namespace Decoration -{ - -class X11Renderer : public Renderer -{ - Q_OBJECT -public: - explicit X11Renderer(DecoratedClientImpl *client); - ~X11Renderer() override; - - void reparent(Deleted *deleted) override; - -protected: - void render() override; - -private: - QTimer *m_scheduleTimer; - xcb_gcontext_t m_gc; -}; - -} -} - -#endif diff --git a/src/plugins/platforms/x11/standalone/x11_platform.cpp b/src/plugins/platforms/x11/standalone/x11_platform.cpp index f6eb1ba9e0..be5239453b 100644 --- a/src/plugins/platforms/x11/standalone/x11_platform.cpp +++ b/src/plugins/platforms/x11/standalone/x11_platform.cpp @@ -33,7 +33,6 @@ #include "overlaywindow_x11.h" #include "non_composited_outline.h" #include "workspace.h" -#include "x11_decoration_renderer.h" #include "x11_output.h" #include "xcbutils.h" #include "renderloop.h" @@ -406,15 +405,6 @@ OutlineVisual *X11StandalonePlatform::createOutline(Outline *outline) return ret; } -Decoration::Renderer *X11StandalonePlatform::createDecorationRenderer(Decoration::DecoratedClientImpl *client) -{ - auto renderer = Platform::createDecorationRenderer(client); - if (!renderer) { - renderer = new Decoration::X11Renderer(client); - } - return renderer; -} - void X11StandalonePlatform::invertScreen() { using namespace Xcb::RandR; diff --git a/src/plugins/platforms/x11/standalone/x11_platform.h b/src/plugins/platforms/x11/standalone/x11_platform.h index 8b1b33265c..541eddd8f8 100644 --- a/src/plugins/platforms/x11/standalone/x11_platform.h +++ b/src/plugins/platforms/x11/standalone/x11_platform.h @@ -57,7 +57,6 @@ public: OverlayWindow *createOverlayWindow() override; OutlineVisual *createOutline(Outline *outline) override; - Decoration::Renderer *createDecorationRenderer(Decoration::DecoratedClientImpl *client) override; void invertScreen() override; diff --git a/src/plugins/scenes/opengl/scene_opengl.cpp b/src/plugins/scenes/opengl/scene_opengl.cpp index 60355ad282..3d8c38d3f0 100644 --- a/src/plugins/scenes/opengl/scene_opengl.cpp +++ b/src/plugins/scenes/opengl/scene_opengl.cpp @@ -39,6 +39,7 @@ #include "decorations/decoratedclient.h" #include "shadowitem.h" #include "surfaceitem.h" +#include "windowitem.h" #include #include @@ -901,7 +902,7 @@ Shadow *SceneOpenGL::createShadow(Toplevel *toplevel) return new SceneOpenGLShadow(toplevel); } -Decoration::Renderer *SceneOpenGL::createDecorationRenderer(Decoration::DecoratedClientImpl *impl) +DecorationRenderer *SceneOpenGL::createDecorationRenderer(Decoration::DecoratedClientImpl *impl) { return new SceneOpenGLDecorationRenderer(impl); } @@ -1213,22 +1214,10 @@ void OpenGLWindow::endRenderWindow() GLTexture *OpenGLWindow::getDecorationTexture() const { - if (AbstractClient *client = dynamic_cast(toplevel)) { - if (!client->isDecorated()) { - return nullptr; - } - if (SceneOpenGLDecorationRenderer *renderer = static_cast(client->decoratedClient()->renderer())) { - renderer->render(); - return renderer->texture(); - } - } else if (toplevel->isDeleted()) { - Deleted *deleted = static_cast(toplevel); - if (!deleted->wasDecorated()) { - return nullptr; - } - if (const SceneOpenGLDecorationRenderer *renderer = static_cast(deleted->decorationRenderer())) { - return renderer->texture(); - } + const DecorationItem *decorationItem = windowItem()->decorationItem(); + if (decorationItem) { + auto renderer = static_cast(decorationItem->renderer()); + return renderer->texture(); } return nullptr; } @@ -2489,10 +2478,9 @@ bool SceneOpenGLShadow::prepareBackend() } SceneOpenGLDecorationRenderer::SceneOpenGLDecorationRenderer(Decoration::DecoratedClientImpl *client) - : Renderer(client) + : DecorationRenderer(client) , m_texture() { - connect(this, &Renderer::renderScheduled, client->client(), static_cast(&AbstractClient::addRepaint)); } SceneOpenGLDecorationRenderer::~SceneOpenGLDecorationRenderer() @@ -2573,12 +2561,8 @@ static void clamp(QImage &image, const QRect &viewport) } } -void SceneOpenGLDecorationRenderer::render() +void SceneOpenGLDecorationRenderer::render(const QRegion ®ion) { - const QRegion scheduled = getScheduled(); - if (scheduled.isEmpty()) { - return; - } if (areImageSizesDirty()) { resizeTexture(); resetImageSizesDirty(); @@ -2645,7 +2629,7 @@ void SceneOpenGLDecorationRenderer::render() m_texture->update(image, (position + dirtyOffset - viewport.topLeft()) * image.devicePixelRatio()); }; - const QRect geometry = scheduled.boundingRect(); + const QRect geometry = region.boundingRect(); const QPoint topPosition(padding, padding); const QPoint bottomPosition(padding, topPosition.y() + top.height() + 2 * padding); @@ -2695,13 +2679,6 @@ void SceneOpenGLDecorationRenderer::resizeTexture() } } -void SceneOpenGLDecorationRenderer::reparent(Deleted *deleted) -{ - render(); - Renderer::reparent(deleted); -} - - OpenGLFactory::OpenGLFactory(QObject *parent) : SceneFactory(parent) { diff --git a/src/plugins/scenes/opengl/scene_opengl.h b/src/plugins/scenes/opengl/scene_opengl.h index 655240a09a..66bd916711 100644 --- a/src/plugins/scenes/opengl/scene_opengl.h +++ b/src/plugins/scenes/opengl/scene_opengl.h @@ -13,13 +13,12 @@ #include "openglbackend.h" +#include "decorationitem.h" #include "scene.h" #include "shadow.h" #include "kwinglutils.h" -#include "decorations/decorationrenderer.h" - namespace KWin { class LanczosFilter; @@ -45,7 +44,7 @@ public: void doneOpenGLContextCurrent() override; bool supportsSurfacelessContext() const override; bool supportsNativeFence() const override; - Decoration::Renderer *createDecorationRenderer(Decoration::DecoratedClientImpl *impl) override; + DecorationRenderer *createDecorationRenderer(Decoration::DecoratedClientImpl *impl) override; void triggerFence() override; virtual QMatrix4x4 projectionMatrix() const = 0; bool animationsSupported() const override; @@ -256,7 +255,7 @@ private: QSharedPointer m_texture; }; -class SceneOpenGLDecorationRenderer : public Decoration::Renderer +class SceneOpenGLDecorationRenderer : public DecorationRenderer { Q_OBJECT public: @@ -270,8 +269,7 @@ public: explicit SceneOpenGLDecorationRenderer(Decoration::DecoratedClientImpl *client); ~SceneOpenGLDecorationRenderer() override; - void render() override; - void reparent(Deleted *deleted) override; + void render(const QRegion ®ion) override; GLTexture *texture() { return m_texture.data(); diff --git a/src/plugins/scenes/qpainter/scene_qpainter.cpp b/src/plugins/scenes/qpainter/scene_qpainter.cpp index a3d7fd7817..83bdc804c4 100644 --- a/src/plugins/scenes/qpainter/scene_qpainter.cpp +++ b/src/plugins/scenes/qpainter/scene_qpainter.cpp @@ -314,25 +314,18 @@ void SceneQPainter::Window::renderShadow(QPainter* painter) void SceneQPainter::Window::renderWindowDecorations(QPainter *painter) { // TODO: custom decoration opacity - AbstractClient *client = dynamic_cast(toplevel); - Deleted *deleted = dynamic_cast(toplevel); - if (!client && !deleted) { + const DecorationItem *decorationItem = windowItem()->decorationItem(); + if (!decorationItem) { return; } - const SceneQPainterDecorationRenderer *renderer = nullptr; + const auto renderer = static_cast(decorationItem->renderer()); QRect dtr, dlr, drr, dbr; - if (client && client->isDecorated()) { - if (SceneQPainterDecorationRenderer *r = static_cast(client->decoratedClient()->renderer())) { - r->render(); - renderer = r; - } + if (auto client = qobject_cast(toplevel)) { client->layoutDecorationRects(dlr, dtr, drr, dbr); - } else if (deleted && deleted->wasDecorated()) { + } else if (auto deleted = qobject_cast(toplevel)) { deleted->layoutDecorationRects(dlr, dtr, drr, dbr); - renderer = static_cast(deleted->decorationRenderer()); - } - if (!renderer) { + } else { return; } @@ -342,7 +335,7 @@ void SceneQPainter::Window::renderWindowDecorations(QPainter *painter) painter->drawImage(dbr, renderer->image(SceneQPainterDecorationRenderer::DecorationPart::Bottom)); } -Decoration::Renderer *SceneQPainter::createDecorationRenderer(Decoration::DecoratedClientImpl *impl) +DecorationRenderer *SceneQPainter::createDecorationRenderer(Decoration::DecoratedClientImpl *impl) { return new SceneQPainterDecorationRenderer(impl); } @@ -690,25 +683,18 @@ bool SceneQPainterShadow::prepareBackend() // QPainterDecorationRenderer //**************************************** SceneQPainterDecorationRenderer::SceneQPainterDecorationRenderer(Decoration::DecoratedClientImpl *client) - : Renderer(client) + : DecorationRenderer(client) { - connect(this, &Renderer::renderScheduled, client->client(), static_cast(&AbstractClient::addRepaint)); } -SceneQPainterDecorationRenderer::~SceneQPainterDecorationRenderer() = default; - QImage SceneQPainterDecorationRenderer::image(SceneQPainterDecorationRenderer::DecorationPart part) const { Q_ASSERT(part != DecorationPart::Count); return m_images[int(part)]; } -void SceneQPainterDecorationRenderer::render() +void SceneQPainterDecorationRenderer::render(const QRegion ®ion) { - const QRegion scheduled = getScheduled(); - if (scheduled.isEmpty()) { - return; - } if (areImageSizesDirty()) { resizeImages(); resetImageSizesDirty(); @@ -723,7 +709,7 @@ void SceneQPainterDecorationRenderer::render() const QRect right(QPoint(top.width() - imageSize(DecorationPart::Right).width(), top.height()), imageSize(DecorationPart::Right)); const QRect bottom(QPoint(0, left.y() + left.height()), imageSize(DecorationPart::Bottom)); - const QRect geometry = scheduled.boundingRect(); + const QRect geometry = region.boundingRect(); auto renderPart = [this](const QRect &rect, const QRect &partRect, int index) { if (rect.isEmpty()) { return; @@ -767,13 +753,6 @@ void SceneQPainterDecorationRenderer::resizeImages() checkAndCreate(int(DecorationPart::Bottom), bottom.size()); } -void SceneQPainterDecorationRenderer::reparent(Deleted *deleted) -{ - render(); - Renderer::reparent(deleted); -} - - QPainterFactory::QPainterFactory(QObject *parent) : SceneFactory(parent) { diff --git a/src/plugins/scenes/qpainter/scene_qpainter.h b/src/plugins/scenes/qpainter/scene_qpainter.h index 14aeed0928..586f6c4f3b 100644 --- a/src/plugins/scenes/qpainter/scene_qpainter.h +++ b/src/plugins/scenes/qpainter/scene_qpainter.h @@ -11,11 +11,10 @@ #include "qpainterbackend.h" +#include "decorationitem.h" #include "scene.h" #include "shadow.h" -#include "decorations/decorationrenderer.h" - namespace KWin { class KWIN_EXPORT SceneQPainter : public Scene @@ -32,7 +31,7 @@ public: bool initFailed() const override; EffectFrame *createEffectFrame(EffectFrameImpl *frame) override; Shadow *createShadow(Toplevel *toplevel) override; - Decoration::Renderer *createDecorationRenderer(Decoration::DecoratedClientImpl *impl) override; + DecorationRenderer *createDecorationRenderer(Decoration::DecoratedClientImpl *impl) override; void screenGeometryChanged(const QSize &size) override; PlatformSurfaceTexture *createPlatformSurfaceTextureInternal(SurfacePixmapInternal *pixmap) override; PlatformSurfaceTexture *createPlatformSurfaceTextureWayland(SurfacePixmapWayland *pixmap) override; @@ -112,7 +111,7 @@ private: QImage m_texture; }; -class SceneQPainterDecorationRenderer : public Decoration::Renderer +class SceneQPainterDecorationRenderer : public DecorationRenderer { Q_OBJECT public: @@ -124,10 +123,8 @@ public: Count }; explicit SceneQPainterDecorationRenderer(Decoration::DecoratedClientImpl *client); - ~SceneQPainterDecorationRenderer() override; - void render() override; - void reparent(Deleted *deleted) override; + void render(const QRegion ®ion) override; QImage image(DecorationPart part) const; diff --git a/src/plugins/scenes/xrender/scene_xrender.cpp b/src/plugins/scenes/xrender/scene_xrender.cpp index 4eeb0c3bbd..7d27f34090 100644 --- a/src/plugins/scenes/xrender/scene_xrender.cpp +++ b/src/plugins/scenes/xrender/scene_xrender.cpp @@ -28,6 +28,7 @@ #include "screens.h" #include "shadowitem.h" #include "surfaceitem_x11.h" +#include "windowitem.h" #include "xcbutils.h" #include "decorations/decoratedclient.h" @@ -135,7 +136,7 @@ Shadow *SceneXrender::createShadow(Toplevel *toplevel) return new SceneXRenderShadow(toplevel); } -Decoration::Renderer *SceneXrender::createDecorationRenderer(Decoration::DecoratedClientImpl* client) +DecorationRenderer *SceneXrender::createDecorationRenderer(Decoration::DecoratedClientImpl *client) { return new SceneXRenderDecorationRenderer(client); } @@ -309,7 +310,8 @@ void SceneXrender::Window::performPaint(int mask, const QRegion &_region, const X11Client *client = dynamic_cast(toplevel); Deleted *deleted = dynamic_cast(toplevel); const QRect decorationRect = toplevel->rect(); - if ((client && client->isDecorated()) || (deleted && deleted->wasDecorated())) { + const DecorationItem *decorationItem = windowItem()->decorationItem(); + if (decorationItem) { // decorated client transformed_shape = decorationRect; if (toplevel->shape()) { @@ -378,7 +380,7 @@ void SceneXrender::Window::performPaint(int mask, const QRegion &_region, const // This solves a number of glitches and on top of this // it optimizes painting quite a bit const bool blitInTempPixmap = xRenderOffscreen() || (data.crossFadeProgress() < 1.0 && !opaque) || - (scaled && (wantShadow || (client && client->isDecorated()) || (deleted && deleted->wasDecorated()))); + (scaled && (wantShadow || decorationItem)); xcb_render_picture_t renderTarget = m_scene->xrenderBufferPicture(); if (blitInTempPixmap) { @@ -423,18 +425,15 @@ void SceneXrender::Window::performPaint(int mask, const QRegion &_region, const xcb_render_picture_t bottom = XCB_RENDER_PICTURE_NONE; QRect dtr, dlr, drr, dbr; const SceneXRenderDecorationRenderer *renderer = nullptr; - if (client && client->isDecorated()) { - SceneXRenderDecorationRenderer *r = static_cast(client->decoratedClient()->renderer()); - if (r) { - r->render(); - renderer = r; + if (decorationItem) { + renderer = static_cast(decorationItem->renderer()); + noBorder = false; + + if (client) { + client->layoutDecorationRects(dlr, dtr, drr, dbr); + } else if (deleted) { + deleted->layoutDecorationRects(dlr, dtr, drr, dbr); } - noBorder = false; - client->layoutDecorationRects(dlr, dtr, drr, dbr); - } else if (deleted && deleted->wasDecorated()) { - renderer = static_cast(deleted->decorationRenderer()); - noBorder = false; - deleted->layoutDecorationRects(dlr, dtr, drr, dbr); } if (renderer) { left = renderer->picture(SceneXRenderDecorationRenderer::DecorationPart::Left); @@ -1004,10 +1003,9 @@ xcb_render_picture_t SceneXRenderShadow::picture(Shadow::ShadowElements element) } SceneXRenderDecorationRenderer::SceneXRenderDecorationRenderer(Decoration::DecoratedClientImpl *client) - : Renderer(client) + : DecorationRenderer(client) , m_gc(XCB_NONE) { - connect(this, &Renderer::renderScheduled, client->client(), static_cast(&AbstractClient::addRepaint)); for (int i = 0; i < int(DecorationPart::Count); ++i) { m_pixmaps[i] = XCB_PIXMAP_NONE; m_pictures[i] = nullptr; @@ -1027,12 +1025,8 @@ SceneXRenderDecorationRenderer::~SceneXRenderDecorationRenderer() } } -void SceneXRenderDecorationRenderer::render() +void SceneXRenderDecorationRenderer::render(const QRegion ®ion) { - QRegion scheduled = getScheduled(); - if (scheduled.isEmpty()) { - return; - } if (areImageSizesDirty()) { resizePixmaps(); resetImageSizesDirty(); @@ -1058,7 +1052,7 @@ void SceneXRenderDecorationRenderer::render() image.width(), image.height(), geo.x() - offset.x(), geo.y() - offset.y(), 0, 32, image.sizeInBytes(), image.constBits()); }; - const QRect geometry = scheduled.boundingRect(); + const QRect geometry = region.boundingRect(); renderPart(left.intersected(geometry), left.topLeft(), int(DecorationPart::Left)); renderPart(top.intersected(geometry), top.topLeft(), int(DecorationPart::Top)); renderPart(right.intersected(geometry), right.topLeft(), int(DecorationPart::Right)); @@ -1113,12 +1107,6 @@ xcb_render_picture_t SceneXRenderDecorationRenderer::picture(SceneXRenderDecorat return *picture; } -void SceneXRenderDecorationRenderer::reparent(Deleted *deleted) -{ - render(); - Renderer::reparent(deleted); -} - #undef DOUBLE_TO_FIXED #undef FIXED_TO_DOUBLE diff --git a/src/plugins/scenes/xrender/scene_xrender.h b/src/plugins/scenes/xrender/scene_xrender.h index 31aa8e5337..896755b116 100644 --- a/src/plugins/scenes/xrender/scene_xrender.h +++ b/src/plugins/scenes/xrender/scene_xrender.h @@ -10,9 +10,9 @@ #ifndef KWIN_SCENE_XRENDER_H #define KWIN_SCENE_XRENDER_H +#include "decorationitem.h" #include "scene.h" #include "shadow.h" -#include "decorations/decorationrenderer.h" #ifdef KWIN_HAVE_XRENDER_COMPOSITING @@ -39,7 +39,7 @@ public: void screenGeometryChanged(const QSize &size) override; xcb_render_picture_t xrenderBufferPicture() const override; OverlayWindow *overlayWindow() const override; - Decoration::Renderer *createDecorationRenderer(Decoration::DecoratedClientImpl *client) override; + DecorationRenderer *createDecorationRenderer(Decoration::DecoratedClientImpl *client) override; PlatformSurfaceTexture *createPlatformSurfaceTextureX11(SurfacePixmapX11 *pixmap) override; bool animationsSupported() const override { @@ -162,7 +162,7 @@ private: XRenderPicture* m_pictures[ShadowElementsCount]; }; -class SceneXRenderDecorationRenderer : public Decoration::Renderer +class SceneXRenderDecorationRenderer : public DecorationRenderer { Q_OBJECT public: @@ -176,8 +176,7 @@ public: explicit SceneXRenderDecorationRenderer(Decoration::DecoratedClientImpl *client); ~SceneXRenderDecorationRenderer() override; - void render() override; - void reparent(Deleted *deleted) override; + void render(const QRegion ®ion) override; xcb_render_picture_t picture(DecorationPart part) const; diff --git a/src/scene.cpp b/src/scene.cpp index a349f56d15..ba9d691837 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -57,7 +57,6 @@ #include "scene.h" #include "abstract_output.h" -#include "decorationitem.h" #include "internal_client.h" #include "platform.h" #include "shadowitem.h" diff --git a/src/scene.h b/src/scene.h index 7e1d51c4b5..bc714424b2 100644 --- a/src/scene.h +++ b/src/scene.h @@ -23,12 +23,11 @@ namespace KWin namespace Decoration { class DecoratedClientImpl; -class Renderer; } class AbstractOutput; class AbstractThumbnailItem; -class DecorationItem; +class DecorationRenderer; class Deleted; class EffectFrameImpl; class EffectWindowImpl; @@ -156,7 +155,7 @@ public: virtual void triggerFence(); - virtual Decoration::Renderer *createDecorationRenderer(Decoration::DecoratedClientImpl *) = 0; + virtual DecorationRenderer *createDecorationRenderer(Decoration::DecoratedClientImpl *) = 0; /** * Whether the Scene is able to drive animations. diff --git a/src/windowitem.h b/src/windowitem.h index 0d0a7a4286..5e98f204f0 100644 --- a/src/windowitem.h +++ b/src/windowitem.h @@ -15,6 +15,7 @@ class Decoration; namespace KWin { +class DecorationItem; /** * The WindowItem class represents a window in the scene. diff --git a/src/x11client.cpp b/src/x11client.cpp index 9339c9ecbb..796d8ef36d 100644 --- a/src/x11client.cpp +++ b/src/x11client.cpp @@ -75,6 +75,71 @@ const NET::WindowTypes SUPPORTED_MANAGED_WINDOW_TYPES_MASK = NET::NormalMask | N | NET::UtilityMask | NET::SplashMask | NET::NotificationMask | NET::OnScreenDisplayMask | NET::CriticalNotificationMask; +X11DecorationRenderer::X11DecorationRenderer(Decoration::DecoratedClientImpl *client) + : DecorationRenderer(client) + , m_scheduleTimer(new QTimer(this)) + , m_gc(XCB_NONE) +{ + // Delay any rendering to end of event cycle to catch multiple updates per cycle. + m_scheduleTimer->setSingleShot(true); + m_scheduleTimer->setInterval(0); + connect(m_scheduleTimer, &QTimer::timeout, this, &X11DecorationRenderer::update); + connect(this, &X11DecorationRenderer::damaged, m_scheduleTimer, static_cast(&QTimer::start)); +} + +X11DecorationRenderer::~X11DecorationRenderer() +{ + if (m_gc != XCB_NONE) { + xcb_free_gc(connection(), m_gc); + } +} + +void X11DecorationRenderer::update() +{ + if (!damage().isEmpty()) { + render(damage()); + resetDamage(); + } +} + +void X11DecorationRenderer::render(const QRegion ®ion) +{ + if (!client()) { + return; + } + xcb_connection_t *c = kwinApp()->x11Connection(); + if (m_gc == XCB_NONE) { + m_gc = xcb_generate_id(c); + xcb_create_gc(c, m_gc, client()->client()->frameId(), 0, nullptr); + } + + QRect left, top, right, bottom; + client()->client()->layoutDecorationRects(left, top, right, bottom); + + const QRect geometry = region.boundingRect(); + left = left.intersected(geometry); + top = top.intersected(geometry); + right = right.intersected(geometry); + bottom = bottom.intersected(geometry); + + auto renderPart = [this, c](const QRect &geo) { + if (!geo.isValid()) { + return; + } + QImage image = renderToImage(geo); + xcb_put_image(c, XCB_IMAGE_FORMAT_Z_PIXMAP, client()->client()->frameId(), m_gc, + image.width(), image.height(), geo.x(), geo.y(), 0, client()->client()->depth(), + image.sizeInBytes(), image.constBits()); + }; + renderPart(left); + renderPart(top); + renderPart(right); + renderPart(bottom); + + xcb_flush(c); + resetImageSizesDirty(); +} + // Creating a client: // - only by calling Workspace::createClient() // - it creates a new client and calls manage() for it @@ -1054,6 +1119,7 @@ void X11Client::createDecoration(const QRect& oldgeom) move(calculateGravitation(false)); resize(adjustedSize()); updateDecorationInputShape(); + maybeCreateX11DecorationRenderer(); if (Compositor::compositing()) { discardWindowPixmap(); } @@ -1066,6 +1132,7 @@ void X11Client::destroyDecoration() if (isDecorated()) { QPoint grav = calculateGravitation(true); AbstractClient::destroyDecoration(); + maybeDestroyX11DecorationRenderer(); resize(adjustedSize()); move(grav); if (compositing()) @@ -1077,6 +1144,22 @@ void X11Client::destroyDecoration() m_decoInputExtent.reset(); } +void X11Client::maybeCreateX11DecorationRenderer() +{ + if (kwinApp()->operationMode() != Application::OperationModeX11) { + return; + } + if (!compositing() && decoratedClient()) { + m_decorationRenderer.reset(new X11DecorationRenderer(decoratedClient())); + decoration()->update(); + } +} + +void X11Client::maybeDestroyX11DecorationRenderer() +{ + m_decorationRenderer.reset(); +} + void X11Client::layoutDecorationRects(QRect &left, QRect &top, QRect &right, QRect &bottom) const { if (!isDecorated()) { @@ -1353,6 +1436,8 @@ bool X11Client::setupCompositing() if (!Toplevel::setupCompositing()){ return false; } + // If compositing is back on, stop rendering decoration in the frame window. + maybeDestroyX11DecorationRenderer(); updateVisibility(); // for internalKeep() return true; } @@ -1363,6 +1448,8 @@ void X11Client::finishCompositing(ReleaseReason releaseReason) updateVisibility(); // for safety in case KWin is just resizing the window resetHaveResizeEffect(); + // If compositing is off, render the decoration in the X11 frame window. + maybeCreateX11DecorationRenderer(); } /** diff --git a/src/x11client.h b/src/x11client.h index 68e17005d4..f2e4000f7c 100644 --- a/src/x11client.h +++ b/src/x11client.h @@ -11,6 +11,7 @@ #pragma once // kwin +#include "decorationitem.h" #include "options.h" #include "rules.h" #include "abstract_client.h" @@ -46,6 +47,28 @@ enum class Predicate { InputIdMatch, }; +/** + * @todo Remove when the X11 platform support is dropped. This decoration renderer + * will be used if compositing is off. + */ +class X11DecorationRenderer : public DecorationRenderer +{ + Q_OBJECT + +public: + explicit X11DecorationRenderer(Decoration::DecoratedClientImpl *client); + ~X11DecorationRenderer() override; + +protected: + void render(const QRegion ®ion) override; + +private: + void update(); + + QTimer *m_scheduleTimer; + xcb_gcontext_t m_gc; +}; + class KWIN_EXPORT X11Client : public AbstractClient { Q_OBJECT @@ -424,6 +447,9 @@ private: */ void updateShowOnScreenEdge(); + void maybeCreateX11DecorationRenderer(); + void maybeDestroyX11DecorationRenderer(); + Xcb::Window m_client; Xcb::Window m_wrapper; Xcb::Window m_frame; @@ -506,6 +532,7 @@ private: QRect m_bufferGeometryBeforeUpdateBlocking; QRect m_frameGeometryBeforeUpdateBlocking; QRect m_clientGeometryBeforeUpdateBlocking; + QScopedPointer m_decorationRenderer; }; inline xcb_window_t X11Client::wrapperId() const