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)