diff --git a/autotests/mock_effectshandler.h b/autotests/mock_effectshandler.h --- a/autotests/mock_effectshandler.h +++ b/autotests/mock_effectshandler.h @@ -278,6 +278,9 @@ KSharedConfigPtr config() const override; KSharedConfigPtr inputConfig() const override; + void renderEffectQuickView(KWin::EffectQuickView *quickView) const override { + Q_UNUSED(quickView); + } private: bool m_animationsSuported = true; diff --git a/effects.h b/effects.h --- a/effects.h +++ b/effects.h @@ -273,6 +273,8 @@ */ Effect *findEffect(const QString &name) const; + void renderEffectQuickView(EffectQuickView *effectQuickView) const override; + public Q_SLOTS: void slotCurrentTabAboutToChange(EffectWindow* from, EffectWindow* to); void slotTabAdded(EffectWindow* from, EffectWindow* to); diff --git a/effects.cpp b/effects.cpp --- a/effects.cpp +++ b/effects.cpp @@ -46,9 +46,9 @@ #include "window_property_notify_x11_filter.h" #include "workspace.h" #include "kwinglutils.h" +#include "kwineffectquickview.h" #include -#include #include @@ -1702,6 +1702,14 @@ return (*it).second; } +void EffectsHandlerImpl::renderEffectQuickView(EffectQuickView *w) const +{ + if (!w->isVisible()) { + return; + } + scene()->paintEffectQuickView(w); +} + //**************************************** // EffectWindowImpl //**************************************** diff --git a/libkwineffects/CMakeLists.txt b/libkwineffects/CMakeLists.txt --- a/libkwineffects/CMakeLists.txt +++ b/libkwineffects/CMakeLists.txt @@ -40,19 +40,22 @@ set(kwin_EFFECTSLIB_SRCS anidata.cpp kwinanimationeffect.cpp + kwineffectquickview.cpp kwineffects.cpp logging.cpp ) set(kwineffects_QT_LIBS Qt5::DBus Qt5::Widgets + Qt5::Quick ) set(kwineffects_KDE_LIBS KF5::ConfigCore KF5::CoreAddons KF5::WindowSystem + KF5::Declarative ) set(kwineffects_XCB_LIBS @@ -66,6 +69,7 @@ ${kwineffects_QT_LIBS} ${kwineffects_KDE_LIBS} ${kwineffects_XCB_LIBS} + kwinglutils ) if (KWIN_HAVE_XRENDER_COMPOSITING) target_link_libraries(kwineffects PRIVATE kwinxrenderutils XCB::XFIXES) @@ -112,6 +116,7 @@ ${CMAKE_CURRENT_BINARY_DIR}/kwinglutils_export.h ${CMAKE_CURRENT_BINARY_DIR}/kwinxrenderutils_export.h kwinanimationeffect.h + kwineffectquickview.h kwineffects.h kwinglobals.h kwinglplatform.h diff --git a/libkwineffects/kwineffectquickview.h b/libkwineffects/kwineffectquickview.h new file mode 100644 --- /dev/null +++ b/libkwineffects/kwineffectquickview.h @@ -0,0 +1,179 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2019 David Edmundson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ + +#pragma once + +#include +#include +#include + +#include + +#include "kwineffects.h" + +#include + +class QKeyEvent; +class QMouseEvent; +class QOpenGLContext; + +class QMouseEvent; +class QKeyEvent; + +class QQmlContext; +class QQuickItem; + +namespace KWin +{ +class GLTexture; + +class EffectQuickView; + +/** + * @brief The KwinQuickView class provides a convenient API for exporting + * QtQuick scenes as buffers that can be composited in any other fashion. + * + * Contents can be fetched as a GL Texture or as a QImage + * If data is to be fetched as an image, it should be specified upfront as + * blitting is performed when we update our FBO to keep kwin's render loop + * as fast as possible. + */ +class KWINEFFECTS_EXPORT EffectQuickView : public QObject +{ + Q_OBJECT + +public: + static void setShareContext(std::unique_ptr context); + + enum class ExportMode { + /** The contents will be available as a texture in the shared contexts. Image will be blank*/ + Texture, + /** The contents will be blit during the update into a QImage buffer. */ + Image + }; + + /** + * Construct a new KWinQuickView + * Export mode will be determined by the current effectsHandler + */ + EffectQuickView(QObject *parent); + + /** + * Construct a new KWinQuickView explicitly stating an export mode + */ + EffectQuickView(QObject *parent, ExportMode exportMode); + + /** + * Note that this may change the current GL Context + */ + ~EffectQuickView(); + + QSize size() const; + + /** + * The geometry of the current view + * This may be out of sync with the current buffer size if an update is pending + */ + void setGeometry(const QRect &rect); + QRect geometry() const; + + /** + * Render the current scene graph into the FBO. + * This is typically done automatically when the scene changes + * albeit deffered by a timer + * + * It can be manually invoked to update the contents immediately. + * Note this will change the GL context + */ + void update(); + + /** The invisble root item of the window*/ + QQuickItem *contentItem() const; + + /** + * @brief Marks the window as visible/invisible + * This can be used to release resources used by the window + * The default is true. + */ + void setVisible(bool visible); + bool isVisible() const; + + void show(); + void hide(); + + /** + * Returns the current output of the scene graph + * @note The render context must valid at the time of calling + */ + GLTexture *bufferAsTexture(); + + /** + * Returns the current output of the scene graph + */ + QImage bufferAsImage() const; + + /** + * Inject any mouse event into the QQuickWindow. + * Local co-ordinates are transformed + * If it is handled the event will be accepted + */ + void forwardMouseEvent(QEvent *mouseEvent); + /** + * Inject a key event into the window. + * If it is handled the event will be accepted + */ + void forwardKeyEvent(QKeyEvent *keyEvent); + +Q_SIGNALS: + /** + * The frame buffer has changed, contents need re-rendering on screen + */ + void repaintNeeded(); + void geometryChanged(const QRect &oldGeometry, const QRect &newGeometry); + +private: + class Private; + QScopedPointer d; +}; + +/** + * The KWinQuickScene class extends KWinQuickView + * adding QML support. This will represent a context + * powered by an engine + */ +class KWINEFFECTS_EXPORT EffectQuickScene : public EffectQuickView +{ +public: + EffectQuickScene(QObject *parent); + EffectQuickScene(QObject *parent, ExportMode exportMode); + ~EffectQuickScene(); + + QQmlContext *rootContext() const; + /** top level item in the given source*/ + QQuickItem *rootItem() const; + + void setSource(const QUrl &source); + +private: + class Private; + QScopedPointer d; +}; + +} diff --git a/libkwineffects/kwineffectquickview.cpp b/libkwineffects/kwineffectquickview.cpp new file mode 100644 --- /dev/null +++ b/libkwineffects/kwineffectquickview.cpp @@ -0,0 +1,357 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2019 David Edmundson + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ + +#include "kwineffectquickview.h" + +#include "kwinglutils.h" +#include "kwineffects.h" +#include "logging_p.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +using namespace KWin; + +static std::unique_ptr s_shareContext; + +class Q_DECL_HIDDEN EffectQuickView::Private +{ +public: + QQuickWindow *m_view; + QQuickRenderControl *m_renderControl; + QScopedPointer m_glcontext; + QScopedPointer m_offscreenSurface; + QScopedPointer m_fbo; + + QImage m_image; + QScopedPointer m_textureExport; + // if we should capture a QImage after rendering into our BO. + // Used for either software QtQuick rendering and nonGL kwin rendering + bool m_useBlit = false; + bool m_visible = true; + + void releaseResources(); +}; + +class Q_DECL_HIDDEN EffectQuickScene::Private +{ +public: + KDeclarative::QmlObjectSharedEngine *qmlObject = nullptr; +}; + +EffectQuickView::EffectQuickView(QObject *parent) + : EffectQuickView(parent, effects->isOpenGLCompositing() ? ExportMode::Texture : ExportMode::Image) +{ +} + +EffectQuickView::EffectQuickView(QObject *parent, ExportMode exportMode) + : QObject(parent) + , d(new EffectQuickView::Private) +{ + d->m_renderControl = new QQuickRenderControl(this); + + d->m_view = new QQuickWindow(d->m_renderControl); + d->m_view->setFlags(Qt::FramelessWindowHint); + d->m_view->setColor(Qt::transparent); + + if (exportMode == ExportMode::Image) { + d->m_useBlit = true; + } + + const bool usingGl = d->m_view->rendererInterface()->graphicsApi() == QSGRendererInterface::OpenGL; + + if (!usingGl) { + qCDebug(LIBKWINEFFECTS) << "QtQuick Software rendering mode detected"; + d->m_useBlit = true; + d->m_renderControl->initialize(nullptr); + } else { + QSurfaceFormat format; + format.setOption(QSurfaceFormat::ResetNotification); + format.setDepthBufferSize(16); + format.setStencilBufferSize(8); + + d->m_glcontext.reset(new QOpenGLContext); + d->m_glcontext->setShareContext(s_shareContext.get()); + d->m_glcontext->setFormat(format); + d->m_glcontext->create(); + + // and the offscreen surface + d->m_offscreenSurface.reset(new QOffscreenSurface); + d->m_offscreenSurface->setFormat(d->m_glcontext->format()); + d->m_offscreenSurface->create(); + + d->m_glcontext->makeCurrent(d->m_offscreenSurface.data()); + d->m_renderControl->initialize(d->m_glcontext.data()); + d->m_glcontext->doneCurrent(); + + if (!d->m_glcontext->shareContext()) { + qCDebug(LIBKWINEFFECTS) << "Failed to create a shared context, falling back to raster rendering"; + + qCDebug(LIBKWINEFFECTS) << "Extra debug:"; + qCDebug(LIBKWINEFFECTS) << "our context:" << d->m_glcontext.data(); + qCDebug(LIBKWINEFFECTS) << "share context:" << s_shareContext.get(); + + // still render via GL, but blit for presentation + d->m_useBlit = true; + } + } + + auto updateSize = [this]() { contentItem()->setSize(d->m_view->size()); }; + updateSize(); + connect(d->m_view, &QWindow::widthChanged, this, updateSize); + connect(d->m_view, &QWindow::heightChanged, this, updateSize); + + QTimer *t = new QTimer(this); + t->setSingleShot(true); + t->setInterval(10); + + connect(t, &QTimer::timeout, this, &EffectQuickView::update); + connect(d->m_renderControl, &QQuickRenderControl::renderRequested, t, [t]() { t->start(); }); + connect(d->m_renderControl, &QQuickRenderControl::sceneChanged, t, [t]() { t->start(); }); +} + +EffectQuickView::~EffectQuickView() +{ + if (d->m_glcontext) { + d->m_glcontext->makeCurrent(d->m_offscreenSurface.data()); + d->m_renderControl->invalidate(); + d->m_glcontext->doneCurrent(); + } +} + +void EffectQuickView::update() +{ + if (!d->m_visible) { + return; + } + if (d->m_view->size().isEmpty()) { + return; + } + + bool usingGl = d->m_glcontext; + + if (usingGl) { + if (!d->m_glcontext->makeCurrent(d->m_offscreenSurface.data())) { + // probably a context loss event, kwin is about to reset all the effects anyway + return; + } + + if (d->m_fbo.isNull() || d->m_fbo->size() != d->m_view->size()) { + d->m_textureExport.reset(nullptr); + d->m_fbo.reset(new QOpenGLFramebufferObject(d->m_view->size(), QOpenGLFramebufferObject::CombinedDepthStencil)); + if (!d->m_fbo->isValid()) { + d->m_fbo.reset(); + d->m_glcontext->doneCurrent(); + return; + } + } + d->m_view->setRenderTarget(d->m_fbo.data()); + } + + d->m_renderControl->polishItems(); + d->m_renderControl->sync(); + + d->m_renderControl->render(); + if (usingGl) { + d->m_view->resetOpenGLState(); + } + + if (d->m_useBlit) { + d->m_image = d->m_renderControl->grab(); + } + + if (usingGl) { + QOpenGLFramebufferObject::bindDefault(); + d->m_glcontext->doneCurrent(); + } + emit repaintNeeded(); +} + +void EffectQuickView::forwardMouseEvent(QEvent *e) +{ + if (!d->m_visible) { + return; + } + QMouseEvent *me = static_cast(e); + const QPoint widgetPos = d->m_view->mapFromGlobal(me->pos()); + + QMouseEvent cloneEvent(me->type(), widgetPos, me->pos(), me->button(), me->buttons(), me->modifiers()); + QCoreApplication::sendEvent(d->m_view, &cloneEvent); + e->setAccepted(cloneEvent.isAccepted()); +} + +void EffectQuickView::forwardKeyEvent(QKeyEvent *keyEvent) +{ + if (!d->m_visible) { + return; + } + QCoreApplication::sendEvent(d->m_view, keyEvent); +} + +void EffectQuickView::setShareContext(std::unique_ptr context) +{ + s_shareContext = std::move(context); +} + +QRect EffectQuickView::geometry() const +{ + return d->m_view->geometry(); +} + +QQuickItem *EffectQuickView::contentItem() const +{ + return d->m_view->contentItem(); +} + +void EffectQuickView::setVisible(bool visible) +{ + if (d->m_visible == visible) { + return; + } + d->m_visible = visible; + + if (visible){ + d->m_renderControl->renderRequested(); + } else { + // deferred to not change GL context + QTimer::singleShot(0, this, [this]() { + d->releaseResources(); + }); + } +} + +bool EffectQuickView::isVisible() const +{ + return d->m_visible; +} + +void EffectQuickView::show() +{ + setVisible(true); +} + +void EffectQuickView::hide() +{ + setVisible(false); +} + +GLTexture *EffectQuickView::bufferAsTexture() +{ + if (d->m_useBlit) { + if (d->m_image.isNull()) { + return nullptr; + } + d->m_textureExport.reset(new GLTexture(d->m_image)); + } else { + if (!d->m_fbo) { + return nullptr; + } + if (!d->m_textureExport) { + d->m_textureExport.reset(new GLTexture(d->m_fbo->texture(), d->m_fbo->format().internalTextureFormat(), d->m_fbo->size())); + } + } + return d->m_textureExport.data(); +} + +QImage EffectQuickView::bufferAsImage() const +{ + return d->m_image; +} + +QSize EffectQuickView::size() const +{ + return d->m_view->geometry().size(); +} + +void EffectQuickView::setGeometry(const QRect &rect) +{ + const QRect oldGeometry = d->m_view->geometry(); + d->m_view->setGeometry(rect); + emit geometryChanged(oldGeometry, rect); +} + +void EffectQuickView::Private::releaseResources() +{ + if (m_glcontext) { + m_glcontext->makeCurrent(m_offscreenSurface.data()); + m_view->releaseResources(); + m_glcontext->doneCurrent(); + } else { + m_view->releaseResources(); + } +} + +EffectQuickScene::EffectQuickScene(QObject *parent) + : EffectQuickView(parent) + , d(new EffectQuickScene::Private) +{ +} + +EffectQuickScene::EffectQuickScene(QObject *parent, EffectQuickView::ExportMode exportMode) + : EffectQuickView(parent, exportMode) + , d(new EffectQuickScene::Private) +{ +} + +EffectQuickScene::~EffectQuickScene() +{ +} + +void EffectQuickScene::setSource(const QUrl &source) +{ + if (!d->qmlObject) { + d->qmlObject = new KDeclarative::QmlObjectSharedEngine(this); + } + d->qmlObject->setSource(source); + + QQuickItem *item = rootItem(); + if (!item) { + qCDebug(LIBKWINEFFECTS) << "Could not load effect quick view" << source; + return; + } + item->setParentItem(contentItem()); + + auto updateSize = [item, this]() { item->setSize(contentItem()->size()); }; + updateSize(); + connect(contentItem(), &QQuickItem::widthChanged, item, updateSize); + connect(contentItem(), &QQuickItem::heightChanged, item, updateSize); +} + +QQmlContext *EffectQuickScene::rootContext() const +{ + return d->qmlObject->rootContext(); +} + +QQuickItem *EffectQuickScene::rootItem() const +{ + return qobject_cast(d->qmlObject->rootObject()); +} diff --git a/libkwineffects/kwineffects.h b/libkwineffects/kwineffects.h --- a/libkwineffects/kwineffects.h +++ b/libkwineffects/kwineffects.h @@ -82,6 +82,7 @@ class EffectWindowGroup; class EffectFrame; class EffectFramePrivate; +class EffectQuickView; class Effect; class WindowQuad; class GLShader; @@ -187,7 +188,7 @@ #define KWIN_EFFECT_API_MAKE_VERSION( major, minor ) (( major ) << 8 | ( minor )) #define KWIN_EFFECT_API_VERSION_MAJOR 0 -#define KWIN_EFFECT_API_VERSION_MINOR 228 +#define KWIN_EFFECT_API_VERSION_MINOR 229 #define KWIN_EFFECT_API_VERSION KWIN_EFFECT_API_MAKE_VERSION( \ KWIN_EFFECT_API_VERSION_MAJOR, KWIN_EFFECT_API_VERSION_MINOR ) @@ -1359,6 +1360,13 @@ */ virtual bool hasActiveFullScreenEffect() const = 0; + /** + * Render the supplied EffectQuickView onto the scene + * It can be called at any point during the scene rendering + * @since 5.18 + */ + virtual void renderEffectQuickView(EffectQuickView *effectQuickView) const = 0; + Q_SIGNALS: /** * Signal emitted when the current desktop changed. diff --git a/plugins/platforms/x11/standalone/CMakeLists.txt b/plugins/platforms/x11/standalone/CMakeLists.txt --- a/plugins/platforms/x11/standalone/CMakeLists.txt +++ b/plugins/platforms/x11/standalone/CMakeLists.txt @@ -28,7 +28,7 @@ add_library(KWinX11Platform MODULE ${X11PLATFORM_SOURCES}) set_target_properties(KWinX11Platform PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/org.kde.kwin.platforms/") -target_link_libraries(KWinX11Platform eglx11common kwin kwinxrenderutils SceneOpenGLBackend Qt5::X11Extras XCB::CURSOR KF5::Crash) +target_link_libraries(KWinX11Platform eglx11common kwin kwinxrenderutils SceneOpenGLBackend Qt5::X11Extras XCB::CURSOR KF5::Crash ) if (X11_Xinput_FOUND) target_link_libraries(KWinX11Platform ${X11_Xinput_LIB}) endif() diff --git a/plugins/platforms/x11/standalone/glxbackend.cpp b/plugins/platforms/x11/standalone/glxbackend.cpp --- a/plugins/platforms/x11/standalone/glxbackend.cpp +++ b/plugins/platforms/x11/standalone/glxbackend.cpp @@ -38,11 +38,13 @@ // kwin libs #include #include +#include #include // Qt #include #include #include +#include // system #include @@ -137,6 +139,7 @@ // do cleanup after initBuffer() cleanupGL(); doneCurrent(); + EffectQuickView::setShareContext(nullptr); gs_tripleBufferUndetected = true; gs_tripleBufferNeedsDetection = false; @@ -359,6 +362,12 @@ return false; } + auto qtContext = new QOpenGLContext; + QGLXNativeContext native(ctx, display()); + qtContext->setNativeHandle(QVariant::fromValue(native)); + qtContext->create(); + EffectQuickView::setShareContext(std::unique_ptr(qtContext)); + return true; } diff --git a/plugins/scenes/opengl/scene_opengl.h b/plugins/scenes/opengl/scene_opengl.h --- a/plugins/scenes/opengl/scene_opengl.h +++ b/plugins/scenes/opengl/scene_opengl.h @@ -90,6 +90,7 @@ void extendPaintRegion(QRegion ®ion, bool opaqueFullscreen) override; QMatrix4x4 transformation(int mask, const ScreenPaintData &data) const; void paintDesktop(int desktop, int mask, const QRegion ®ion, ScreenPaintData &data) override; + void paintEffectQuickView(EffectQuickView *w) override; void handleGraphicsReset(GLenum status); diff --git a/plugins/scenes/opengl/scene_opengl.cpp b/plugins/scenes/opengl/scene_opengl.cpp --- a/plugins/scenes/opengl/scene_opengl.cpp +++ b/plugins/scenes/opengl/scene_opengl.cpp @@ -33,6 +33,7 @@ #include "platformsupport/scenes/opengl/texture.h" #include +#include #include "utils.h" #include "x11client.h" @@ -858,6 +859,30 @@ glDisable(GL_SCISSOR_TEST); } +void SceneOpenGL::paintEffectQuickView(EffectQuickView *w) +{ + GLShader *shader = ShaderManager::instance()->pushShader(ShaderTrait::MapTexture); + const QRect rect = w->geometry(); + + GLTexture *t = w->bufferAsTexture(); + if (!t) { + return; + } + + QMatrix4x4 mvp(projectionMatrix()); + mvp.translate(rect.x(), rect.y()); + shader->setUniform(GLShader::ModelViewProjectionMatrix, mvp); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + t->bind(); + t->render(QRegion(infiniteRegion()), w->geometry()); + t->unbind(); + glDisable(GL_BLEND); + return; +} + bool SceneOpenGL::makeOpenGLContextCurrent() { return m_backend->makeCurrent(); diff --git a/plugins/scenes/qpainter/scene_qpainter.h b/plugins/scenes/qpainter/scene_qpainter.h --- a/plugins/scenes/qpainter/scene_qpainter.h +++ b/plugins/scenes/qpainter/scene_qpainter.h @@ -62,6 +62,7 @@ void paintBackground(QRegion region) override; Scene::Window *createWindow(Toplevel *toplevel) override; void paintCursor() override; + void paintEffectQuickView(EffectQuickView *w) override; private: explicit SceneQPainter(QPainterBackend *backend, QObject *parent = nullptr); diff --git a/plugins/scenes/qpainter/scene_qpainter.cpp b/plugins/scenes/qpainter/scene_qpainter.cpp --- a/plugins/scenes/qpainter/scene_qpainter.cpp +++ b/plugins/scenes/qpainter/scene_qpainter.cpp @@ -29,6 +29,9 @@ #include "toplevel.h" #include "platform.h" #include "wayland_server.h" + +#include + #include #include #include @@ -173,6 +176,16 @@ kwinApp()->platform()->markCursorAsRendered(); } +void SceneQPainter::paintEffectQuickView(EffectQuickView *w) +{ + QPainter *painter = effects->scenePainter(); + const QImage buffer = w->bufferAsImage(); + if (buffer.isNull()) { + return; + } + painter->drawImage(w->geometry(), buffer); +} + Scene::Window *SceneQPainter::createWindow(Toplevel *toplevel) { return new SceneQPainter::Window(this, toplevel); diff --git a/plugins/scenes/xrender/scene_xrender.h b/plugins/scenes/xrender/scene_xrender.h --- a/plugins/scenes/xrender/scene_xrender.h +++ b/plugins/scenes/xrender/scene_xrender.h @@ -178,6 +178,7 @@ void paintGenericScreen(int mask, ScreenPaintData data) override; void paintDesktop(int desktop, int mask, const QRegion ®ion, ScreenPaintData &data) override; void paintCursor() override; + void paintEffectQuickView(EffectQuickView *w) override; private: explicit SceneXrender(XRenderBackend *backend, QObject *parent = nullptr); static ScreenPaintData screen_paint; diff --git a/plugins/scenes/xrender/scene_xrender.cpp b/plugins/scenes/xrender/scene_xrender.cpp --- a/plugins/scenes/xrender/scene_xrender.cpp +++ b/plugins/scenes/xrender/scene_xrender.cpp @@ -36,9 +36,11 @@ #include "platform.h" #include "screens.h" #include "xcbutils.h" -#include "kwinxrenderutils.h" #include "decorations/decoratedclient.h" +#include +#include + #include #include @@ -1329,3 +1331,16 @@ { } + +void KWin::SceneXrender::paintEffectQuickView(KWin::EffectQuickView *w) +{ + const QImage buffer = w->bufferAsImage(); + if (buffer.isNull()) { + return; + } + XRenderPicture picture(buffer); + xcb_render_composite(connection(), XCB_RENDER_PICT_OP_OVER, picture, XCB_RENDER_PICTURE_NONE, + effects->xrenderBufferPicture(), + 0, 0, 0, 0, w->geometry().x(), w->geometry().y(), + w->geometry().width(), w->geometry().height()); +} diff --git a/scene.h b/scene.h --- a/scene.h +++ b/scene.h @@ -236,6 +236,9 @@ // the default is NOOP virtual void extendPaintRegion(QRegion ®ion, bool opaqueFullscreen); virtual void paintDesktop(int desktop, int mask, const QRegion ®ion, ScreenPaintData &data); + + virtual void paintEffectQuickView(EffectQuickView *w) = 0; + // compute time since the last repaint void updateTimeDiff(); // saved data for 2nd pass of optimized screen painting