diff --git a/libkwineffects/kwinxrenderutils.cpp b/libkwineffects/kwinxrenderutils.cpp
index bc58705b3f..b6350454bb 100644
--- a/libkwineffects/kwinxrenderutils.cpp
+++ b/libkwineffects/kwinxrenderutils.cpp
@@ -23,6 +23,7 @@ along with this program. If not, see .
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
+#include
#include
#include
#include
@@ -212,6 +213,55 @@ XRenderPicture::XRenderPicture(Pixmap pix, int depth)
{
}
+static QPixmap *s_offscreenTarget = 0;
+static QStack s_scene_offscreenTargetStack;
+static int s_renderOffscreen = 0;
+
+void scene_setXRenderOffscreenTarget(QPixmap *pix)
+{
+ s_offscreenTarget = pix;
+}
+
+XRenderPicture *scene_xRenderOffscreenTarget()
+{
+ return s_scene_offscreenTargetStack.isEmpty() ? 0 : s_scene_offscreenTargetStack.top();
+}
+
+void setXRenderOffscreen(bool b)
+{
+ b ? ++s_renderOffscreen : --s_renderOffscreen;
+ if (s_renderOffscreen < 0) {
+ s_renderOffscreen = 0;
+ qWarning("*** SOMETHING IS MESSED UP WITH YOUR setXRenderOffscreen() USAGE ***");
+ }
+}
+
+void xRenderPushTarget(XRenderPicture *pic)
+{
+ s_scene_offscreenTargetStack.push(pic);
+ ++s_renderOffscreen;
+}
+
+void xRenderPopTarget()
+{
+ s_scene_offscreenTargetStack.pop();
+ --s_renderOffscreen;
+ if (s_renderOffscreen < 0) {
+ s_renderOffscreen = 0;
+ qWarning("*** SOMETHING IS MESSED UP WITH YOUR xRenderPopTarget() USAGE ***");
+ }
+}
+
+bool xRenderOffscreen()
+{
+ return s_renderOffscreen;
+}
+
+QPixmap *xRenderOffscreenTarget()
+{
+ return s_offscreenTarget;
+}
+
} // namespace
#endif
diff --git a/libkwineffects/kwinxrenderutils.h b/libkwineffects/kwinxrenderutils.h
index b0943890d7..f564002aee 100644
--- a/libkwineffects/kwinxrenderutils.h
+++ b/libkwineffects/kwinxrenderutils.h
@@ -126,6 +126,42 @@ KWIN_EXPORT XRenderPicture xRenderBlendPicture(double opacity);
KWIN_EXPORT XRenderPicture xRenderFill(const XRenderColor *c);
KWIN_EXPORT XRenderPicture xRenderFill(const QColor &c);
+/**
+ * Allows to render a window into a (transparent) pixmap
+ * NOTICE: the result can be queried as xRenderWindowOffscreenTarget()
+ * NOTICE: it may be 0
+ * NOTICE: when done call setXRenderWindowOffscreen(false) to continue normal render process
+ */
+KWIN_EXPORT void setXRenderOffscreen(bool b);
+
+/**
+ * Allows to define a persistent effect member as render target
+ * The window (including shadows) is rendered into the top left corner
+ * NOTICE: do NOT call setXRenderOffscreen(true) in addition!
+ * NOTICE: do not forget to xRenderPopTarget once you're done to continue the normal render process
+ */
+KWIN_EXPORT void xRenderPushTarget(XRenderPicture *pic);
+KWIN_EXPORT void xRenderPopTarget();
+
+/**
+ * Whether windows are currently rendered into an offscreen target buffer
+ */
+KWIN_EXPORT bool xRenderOffscreen();
+/**
+ * The offscreen buffer as set by the renderer because of setXRenderWindowOffscreen(true)
+ */
+KWIN_EXPORT QPixmap *xRenderOffscreenTarget();
+
+/**
+ * NOTICE: HANDS OFF!!!
+ * scene_setXRenderWindowOffscreenTarget() is ONLY to be used by the renderer - DO NOT TOUCH!
+ */
+KWIN_EXPORT void scene_setXRenderOffscreenTarget(QPixmap *pix);
+/**
+ * scene_xRenderWindowOffscreenTarget() is used by the scene to figure the target set by an effect
+ */
+KWIN_EXPORT XRenderPicture *scene_xRenderOffscreenTarget();
+
} // namespace
#endif
diff --git a/scene_xrender.cpp b/scene_xrender.cpp
index c9caa87142..b958be9fd1 100644
--- a/scene_xrender.cpp
+++ b/scene_xrender.cpp
@@ -417,8 +417,10 @@ void SceneXrender::Window::prepareTempPixmap()
XFreePixmap(display(), temp_pixmap->handle()); // The picture owns the pixmap now
if (!temp_pixmap)
temp_pixmap = new QPixmap(r.width(), r.height());
- else if (temp_pixmap->width() < r.width() || temp_pixmap->height() < r.height())
+ else if (temp_pixmap->width() < r.width() || temp_pixmap->height() < r.height()) {
*temp_pixmap = QPixmap(r.width(), r.height());
+ scene_setXRenderOffscreenTarget(0); // invalidate, better crash than cause weird results for developers
+ }
if (Extensions::nonNativePixmaps()) {
Pixmap pix = XCreatePixmap(display(), rootWindow(), temp_pixmap->width(), temp_pixmap->height(), DefaultDepth(display(), DefaultScreen(display())));
*temp_pixmap = QPixmap::fromX11Pixmap(pix);
@@ -532,12 +534,16 @@ void SceneXrender::Window::performPaint(int mask, QRegion region, WindowPaintDat
// the window has border
// This solves a number of glitches and on top of this
// it optimizes painting quite a bit
- const bool blitInTempPixmap = scaled && (wantShadow || (client && !client->noBorder()) || (deleted && !deleted->noBorder()));
- Picture renderTarget = buffer;
+ const bool blitInTempPixmap = xRenderOffscreen() || (scaled && (wantShadow || (client && !client->noBorder()) || (deleted && !deleted->noBorder())));
+ Picture renderTarget = buffer;
if (blitInTempPixmap) {
- prepareTempPixmap();
- renderTarget = temp_pixmap->x11PictureHandle();
+ if (scene_xRenderOffscreenTarget())
+ renderTarget = *scene_xRenderOffscreenTarget();
+ else {
+ prepareTempPixmap();
+ renderTarget = temp_pixmap->x11PictureHandle();
+ }
} else {
XRenderSetPictureTransform(display(), pic, &xform);
if (filter == ImageFilterGood) {
@@ -702,6 +708,8 @@ XRenderComposite(display(), PictOpOver, _PART_->x11PictureHandle(), decorationAl
XRenderChangePicture(display(), pic, CPRepeat, &attr);
}
}
+ if (xRenderOffscreen())
+ scene_setXRenderOffscreenTarget(temp_pixmap);
}
void SceneXrender::screenGeometryChanged(const QSize &size)