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; - } - noBorder = false; - client->layoutDecorationRects(dlr, dtr, drr, dbr); - } else if (deleted && deleted->wasDecorated()) { - renderer = static_cast(deleted->decorationRenderer()); + if (decorationItem) { + renderer = static_cast(decorationItem->renderer()); noBorder = false; - deleted->layoutDecorationRects(dlr, dtr, drr, dbr); + + if (client) { + client->layoutDecorationRects(dlr, dtr, drr, dbr); + } else if (deleted) { + 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