diff --git a/composite.cpp b/composite.cpp index bb00d5f77c..f5de2fb66d 100644 --- a/composite.cpp +++ b/composite.cpp @@ -881,45 +881,10 @@ void Toplevel::finishCompositing() void Toplevel::discardWindowPixmap() { addDamageFull(); - if (window_pix == XCB_PIXMAP_NONE) - return; - xcb_free_pixmap(connection(), window_pix); - window_pix = XCB_PIXMAP_NONE; if (effectWindow() != NULL && effectWindow()->sceneWindow() != NULL) effectWindow()->sceneWindow()->pixmapDiscarded(); } -xcb_pixmap_t Toplevel::createWindowPixmap() -{ - assert(compositing()); - if (unredirected()) - return XCB_PIXMAP_NONE; - XServerGrabber grabber(); - xcb_pixmap_t pix = xcb_generate_id(connection()); - xcb_void_cookie_t namePixmapCookie = xcb_composite_name_window_pixmap_checked(connection(), frameId(), pix); - Xcb::WindowAttributes windowAttributes(frameId()); - Xcb::WindowGeometry windowGeometry(frameId()); - if (xcb_generic_error_t *error = xcb_request_check(connection(), namePixmapCookie)) { - kDebug(1212) << "Creating window pixmap failed: " << error->error_code; - free(error); - return XCB_PIXMAP_NONE; - } - // check that the received pixmap is valid and actually matches what we - // know about the window (i.e. size) - if (!windowAttributes || windowAttributes->map_state != XCB_MAP_STATE_VIEWABLE) { - kDebug(1212) << "Creating window pixmap failed: " << this; - xcb_free_pixmap(connection(), pix); - return XCB_PIXMAP_NONE; - } - if (!windowGeometry || - windowGeometry->width != width() || windowGeometry->height != height()) { - kDebug(1212) << "Creating window pixmap failed: " << this; - xcb_free_pixmap(connection(), pix); - return XCB_PIXMAP_NONE; - } - return pix; -} - void Toplevel::damageNotifyEvent() { m_isDamaged = true; diff --git a/scene.cpp b/scene.cpp index ed10e22242..45564eb686 100644 --- a/scene.cpp +++ b/scene.cpp @@ -581,6 +581,9 @@ Scene::Window::Window(Toplevel * c) : toplevel(c) , filter(ImageFilterFast) , m_shadow(NULL) + , m_currentPixmap() + , m_previousPixmap() + , m_referencePixmapCounter(0) , disable_painting(0) , shape_valid(false) , cached_quad_list(NULL) @@ -593,6 +596,32 @@ Scene::Window::~Window() delete m_shadow; } +void Scene::Window::referencePreviousPixmap() +{ + if (!m_previousPixmap.isNull() && m_previousPixmap->isDiscarded()) { + m_referencePixmapCounter++; + } +} + +void Scene::Window::unreferencePreviousPixmap() +{ + if (m_previousPixmap.isNull() || !m_previousPixmap->isDiscarded()) { + return; + } + m_referencePixmapCounter--; + if (m_referencePixmapCounter == 0) { + m_previousPixmap.reset(); + } +} + +void Scene::Window::pixmapDiscarded() +{ + if (!m_currentPixmap.isNull() && m_currentPixmap->isValid()) { + m_previousPixmap.reset(m_currentPixmap.take()); + m_previousPixmap->markAsDiscarded(); + } +} + void Scene::Window::discardShape() { // it is created on-demand and cached, simply @@ -797,6 +826,56 @@ WindowQuadList Scene::Window::makeQuads(WindowQuadType type, const QRegion& reg) return ret; } +//**************************************** +// WindowPixmap +//**************************************** +WindowPixmap::WindowPixmap(Scene::Window *window) + : m_window(window) + , m_pixmap(XCB_PIXMAP_NONE) + , m_discarded(false) +{ +} + +WindowPixmap::~WindowPixmap() +{ + if (isValid()) { + xcb_free_pixmap(connection(), m_pixmap); + } +} + +void WindowPixmap::create() +{ + if (isValid()) { + return; + } + XServerGrabber grabber(); + xcb_pixmap_t pix = xcb_generate_id(connection()); + xcb_void_cookie_t namePixmapCookie = xcb_composite_name_window_pixmap_checked(connection(), toplevel()->frameId(), pix); + Xcb::WindowAttributes windowAttributes(toplevel()->frameId()); + Xcb::WindowGeometry windowGeometry(toplevel()->frameId()); + if (xcb_generic_error_t *error = xcb_request_check(connection(), namePixmapCookie)) { + kDebug(1212) << "Creating window pixmap failed: " << error->error_code; + free(error); + return; + } + // check that the received pixmap is valid and actually matches what we + // know about the window (i.e. size) + if (!windowAttributes || windowAttributes->map_state != XCB_MAP_STATE_VIEWABLE) { + kDebug(1212) << "Creating window pixmap failed: " << this; + xcb_free_pixmap(connection(), pix); + return; + } + if (!windowGeometry || + windowGeometry->width != toplevel()->width() || windowGeometry->height != toplevel()->height()) { + kDebug(1212) << "Creating window pixmap failed: " << this; + xcb_free_pixmap(connection(), pix); + return; + } + m_pixmap = pix; + m_pixmapSize = QSize(toplevel()->width(), toplevel()->height()); + m_window->unreferencePreviousPixmap(); +} + //**************************************** // Scene::EffectFrame //**************************************** diff --git a/scene.h b/scene.h index c96065d605..a6685ce489 100644 --- a/scene.h +++ b/scene.h @@ -39,6 +39,7 @@ class EffectFrameImpl; class EffectWindowImpl; class OverlayWindow; class Shadow; +class WindowPixmap; // The base class for compositing backends. class Scene : public QObject @@ -184,7 +185,7 @@ public: // perform the actual painting of the window virtual void performPaint(int mask, QRegion region, WindowPaintData data) = 0; // do any cleanup needed when the window's composite pixmap is discarded - virtual void pixmapDiscarded() {} + void pixmapDiscarded(); int x() const; int y() const; int width() const; @@ -231,13 +232,41 @@ public: void updateShadow(Shadow* shadow); const Shadow* shadow() const; Shadow* shadow(); + void referencePreviousPixmap(); + void unreferencePreviousPixmap(); protected: WindowQuadList makeQuads(WindowQuadType type, const QRegion& reg) const; WindowQuadList makeDecorationQuads(const QRect *rects, const QRegion ®ion) const; + /** + * @brief Returns the WindowPixmap for this Window. + * + * If the WindowPixmap does not yet exist, this method will invoke @link createWindowPixmap. + * If the WindowPixmap is not valid it tries to create it, in case this succeeds the WindowPixmap is + * returned. In case it fails, the previous (and still valid) WindowPixmap is returned. + * + * Note: this method can return @c NULL as there might neither be a valid previous nor current WindowPixmap + * around. + * + * The WindowPixmap gets casted to the type passed in as a template parameter. That way this class does not + * need to know the actual WindowPixmap subclass used by the concrete Scene implementations. + * + * @return The WindowPixmap casted to T* or @c NULL if there is no valid window pixmap. + */ + template T *windowPixmap(); + /** + * @brief Factory method to create a WindowPixmap. + * + * The inheriting classes need to implement this method to create a new instance of their WindowPixmap subclass. + * Note: do not use @link WindowPixmap::create on the created instance. The Scene will take care of that. + */ + virtual WindowPixmap *createWindowPixmap() = 0; Toplevel* toplevel; ImageFilterType filter; Shadow *m_shadow; private: + QScopedPointer m_currentPixmap; + QScopedPointer m_previousPixmap; + int m_referencePixmapCounter; int disable_painting; mutable QRegion shape_region; mutable bool shape_valid; @@ -245,6 +274,78 @@ private: Q_DISABLE_COPY(Window) }; +/** + * @brief Wrapper for a pixmap of the @link Scene::Window. + * + * This class encapsulates the functionality to get the pixmap for a window. When initialized the pixmap is not yet + * mapped to the window and @link isValid will return @c false. The pixmap mapping to the window can be established + * through @link create. If it succeeds @link isValid will return @c true, otherwise it will keep in the non valid + * state and it can be tried to create the pixmap mapping again (e.g. in the next frame). + * + * This class is not intended to be updated when the pixmap is no longer valid due to e.g. resizing the window. + * Instead a new instance of this class should be instantiated. The idea behind this is that a valid pixmap does not + * get destroyed, but can continue to be used. To indicate that a newer pixmap should in generally be around, one can + * use @link markAsDiscarded. + * + * This class is intended to be inherited for the needs of the compositor backends which need further mapping from + * the native pixmap to the respective rendering format. + */ +class WindowPixmap +{ +public: + virtual ~WindowPixmap(); + /** + * @brief Tries to create the mapping between the Window and the pixmap. + * + * In case this method succeeds in creating the pixmap for the window, @link isValid will return @c true otherwise + * @c false. + * + * Inheriting classes should re-implement this method in case they need to add further functionality for mapping the + * native pixmap to the rendering format. + */ + virtual void create(); + /** + * @return @c true if the pixmap has been created and is valid, @c false otherwise + */ + bool isValid() const; + /** + * @return The native X11 pixmap handle + */ + xcb_pixmap_t pixmap() const; + /** + * @brief Whether this WindowPixmap is considered as discarded. This means the window has changed in a way that a new + * WindowPixmap should have been created already. + * + * @return @c true if this WindowPixmap is considered as discarded, @c false otherwise. + * @see markAsDiscarded + */ + bool isDiscarded() const; + /** + * @brief Marks this WindowPixmap as discarded. From now on @link isDiscarded will return @c true. This method should + * only be used by the Window when it changes in a way that a new pixmap is required. + * + * @see isDiscarded + */ + void markAsDiscarded(); + +protected: + explicit WindowPixmap(Scene::Window *window); + /** + * @brief Returns the Toplevel this WindowPixmap belongs to. + * Note: the Toplevel can change over the lifetime of the WindowPixmap in case the Toplevel is copied to Deleted. + */ + Toplevel *toplevel(); + /** + * @return The Window this WindowPixmap belongs to + */ + Scene::Window *window(); +private: + Scene::Window *m_window; + xcb_pixmap_t m_pixmap; + QSize m_pixmapSize; + bool m_discarded; +}; + class Scene::EffectFrame { public: @@ -346,6 +447,55 @@ Shadow* Scene::Window::shadow() return m_shadow; } +inline +bool WindowPixmap::isValid() const +{ + return m_pixmap != XCB_PIXMAP_NONE; +} + +template +inline +T* Scene::Window::windowPixmap() +{ + if (m_currentPixmap.isNull()) { + m_currentPixmap.reset(createWindowPixmap()); + } + if (m_currentPixmap->isValid()) { + return static_cast(m_currentPixmap.data()); + } + m_currentPixmap->create(); + if (m_currentPixmap->isValid()) { + return static_cast(m_currentPixmap.data()); + } else { + return static_cast(m_previousPixmap.data()); + } +} + +inline +Toplevel* WindowPixmap::toplevel() +{ + return m_window->window(); +} + +inline +xcb_pixmap_t WindowPixmap::pixmap() const +{ + return m_pixmap; +} + +inline +bool WindowPixmap::isDiscarded() const +{ + return m_discarded; +} + +inline +void WindowPixmap::markAsDiscarded() +{ + m_discarded = true; + m_window->referencePreviousPixmap(); +} + } // namespace #endif diff --git a/scene_opengl.cpp b/scene_opengl.cpp index 38442f914a..71908310e6 100644 --- a/scene_opengl.cpp +++ b/scene_opengl.cpp @@ -479,7 +479,6 @@ void SceneOpenGL::windowGeometryShapeChanged(KWin::Toplevel* c) return; // by default Window* w = windows[ c ]; w->discardShape(); - w->checkTextureSize(); } void SceneOpenGL::windowOpacityChanged(KWin::Toplevel* t) @@ -960,73 +959,27 @@ SceneOpenGL::TexturePrivate::~TexturePrivate() SceneOpenGL::Window::Window(Toplevel* c) : Scene::Window(c) , m_scene(NULL) - , m_texture(NULL) { } SceneOpenGL::Window::~Window() { - delete m_texture; } +static SceneOpenGL::Texture *s_frameTexture = NULL; // Bind the window pixmap to an OpenGL texture. bool SceneOpenGL::Window::bindTexture() { - if (!m_texture) { - m_texture = m_scene->createTexture(); - } - if (!m_texture->isNull()) { - if (!toplevel->damage().isEmpty()) { - // mipmaps need to be updated - m_texture->setDirty(); - toplevel->resetDamage(); - } - return true; - } - // Get the pixmap with the window contents - Pixmap pix = toplevel->windowPixmap(); - if (pix == None) + s_frameTexture = NULL; + OpenGLWindowPixmap *pixmap = windowPixmap(); + if (!pixmap) { return false; - - bool success = m_texture->load(pix, toplevel->size(), toplevel->depth(), - toplevel->damage()); - - if (success) - toplevel->resetDamage(); - else - kDebug(1212) << "Failed to bind window"; - - return success; -} - -void SceneOpenGL::Window::discardTexture() -{ - if (m_texture) - m_texture->discard(); -} - -// This call is used in SceneOpenGL::windowGeometryShapeChanged(), -// which originally called discardTexture(), however this was causing performance -// problems with the launch feedback icon - large number of texture rebinds. -// Since the launch feedback icon does not resize, only changes shape, it -// is not necessary to rebind the texture (with no strict binding), therefore -// discard the texture only if size changes. -void SceneOpenGL::Window::checkTextureSize() -{ - if (!m_texture) - return; - - if (m_texture->size() != size()) - discardTexture(); -} - -// when the window's composite pixmap is discarded, undo binding it to the texture -void SceneOpenGL::Window::pixmapDiscarded() -{ - if (!m_texture) - return; - - m_texture->discard(); + } + s_frameTexture = pixmap->texture(); + if (pixmap->isDiscarded()) { + return !pixmap->texture()->isNull(); + } + return pixmap->bind(); } QMatrix4x4 SceneOpenGL::Window::transformation(int mask, const WindowPaintData &data) const @@ -1082,7 +1035,7 @@ bool SceneOpenGL::Window::beginRenderWindow(int mask, const QRegion ®ion, Win data.quads = quads; } - if (!bindTexture()) { + if (!bindTexture() || !s_frameTexture) { return false; } @@ -1097,7 +1050,7 @@ bool SceneOpenGL::Window::beginRenderWindow(int mask, const QRegion ®ion, Win else filter = ImageFilterFast; - m_texture->setFilter(filter == ImageFilterGood ? GL_LINEAR : GL_NEAREST); + s_frameTexture->setFilter(filter == ImageFilterGood ? GL_LINEAR : GL_NEAREST); const GLVertexAttrib attribs[] = { { VA_Position, 2, GL_FLOAT, offsetof(GLVertex2D, position) }, @@ -1309,7 +1262,7 @@ GLTexture *SceneOpenGL::Window::textureForType(SceneOpenGL::Window::TextureType switch(type) { case Content: - tex = m_texture; + tex = s_frameTexture; break; case DecorationLeftRight: @@ -1326,6 +1279,10 @@ GLTexture *SceneOpenGL::Window::textureForType(SceneOpenGL::Window::TextureType return tex; } +WindowPixmap* SceneOpenGL::Window::createWindowPixmap() +{ + return new OpenGLWindowPixmap(this, m_scene); +} //*************************************** // SceneOpenGL2Window @@ -1382,7 +1339,7 @@ void SceneOpenGL2Window::setupLeafNodes(LeafNode *nodes, const WindowQuadList *q nodes[TopBottomLeaf].coordinateType = UnnormalizedCoordinates; } - nodes[ContentLeaf].texture = m_texture; + nodes[ContentLeaf].texture = s_frameTexture; nodes[ContentLeaf].hasAlpha = !isOpaque(); nodes[ContentLeaf].opacity = data.opacity(); nodes[ContentLeaf].coordinateType = UnnormalizedCoordinates; @@ -1589,16 +1546,16 @@ void SceneOpenGL1Window::performPaint(int mask, QRegion region, WindowPaintData // paint the content WindowQuadList contentQuads = data.quads.select(WindowQuadContents); if (!contentQuads.empty()) { - m_texture->bind(); + s_frameTexture->bind(); prepareStates(Content, data.opacity(), data.brightness(), data.saturation(), data.screen()); - renderQuads(mask, region, contentQuads, m_texture, false); + renderQuads(mask, region, contentQuads, s_frameTexture, false); restoreStates(Content, data.opacity(), data.brightness(), data.saturation()); - m_texture->unbind(); + s_frameTexture->unbind(); #ifndef KWIN_HAVE_OPENGLES if (m_scene && m_scene->debug()) { glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - renderQuads(mask, region, contentQuads, m_texture, false); + renderQuads(mask, region, contentQuads, s_frameTexture, false); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } #endif @@ -1763,6 +1720,44 @@ void SceneOpenGL1Window::restoreStates(TextureType type, qreal opacity, qreal br } #endif +//**************************************** +// OpenGLWindowPixmap +//**************************************** + +OpenGLWindowPixmap::OpenGLWindowPixmap(Scene::Window *window, SceneOpenGL* scene) + : WindowPixmap(window) + , m_scene(scene) + , m_texture(scene->createTexture()) +{ +} + +OpenGLWindowPixmap::~OpenGLWindowPixmap() +{ +} + +bool OpenGLWindowPixmap::bind() +{ + if (!m_texture->isNull()) { + if (!toplevel()->damage().isEmpty()) { + // mipmaps need to be updated + m_texture->setDirty(); + toplevel()->resetDamage(); + } + return true; + } + if (!isValid()) { + return false; + } + + bool success = m_texture->load(pixmap(), toplevel()->size(), toplevel()->depth(), toplevel()->damage()); + + if (success) + toplevel()->resetDamage(); + else + kDebug(1212) << "Failed to bind window"; + return success; +} + //**************************************** // SceneOpenGL::EffectFrame //**************************************** diff --git a/scene_opengl.h b/scene_opengl.h index c5045a84ab..55a684076e 100644 --- a/scene_opengl.h +++ b/scene_opengl.h @@ -207,7 +207,7 @@ protected: private: Q_DECLARE_PRIVATE(Texture) - friend class SceneOpenGL::Window; + friend class OpenGLWindowPixmap; }; class SceneOpenGL::Window @@ -218,15 +218,13 @@ public: bool beginRenderWindow(int mask, const QRegion ®ion, WindowPaintData &data); virtual void performPaint(int mask, QRegion region, WindowPaintData data) = 0; void endRenderWindow(); - virtual void pixmapDiscarded(); bool bindTexture(); - void discardTexture(); - void checkTextureSize(); void setScene(SceneOpenGL *scene) { m_scene = scene; } protected: + virtual WindowPixmap* createWindowPixmap(); Window(Toplevel* c); enum TextureType { Content, @@ -274,7 +272,6 @@ protected: protected: SceneOpenGL *m_scene; bool m_hardwareClipping; - Texture *m_texture; private: OpenGLPaintRedirector *paintRedirector() const; @@ -337,6 +334,18 @@ protected: }; #endif +class OpenGLWindowPixmap : public WindowPixmap +{ +public: + explicit OpenGLWindowPixmap(Scene::Window *window, SceneOpenGL *scene); + virtual ~OpenGLWindowPixmap(); + SceneOpenGL::Texture *texture() const; + bool bind(); +private: + SceneOpenGL *m_scene; + QScopedPointer m_texture; +}; + class SceneOpenGL::EffectFrame : public Scene::EffectFrame { @@ -624,6 +633,11 @@ inline bool SceneOpenGL::hasPendingFlush() const return m_backend->hasPendingFlush(); } +inline SceneOpenGL::Texture* OpenGLWindowPixmap::texture() const +{ + return m_texture.data(); +} + } // namespace #endif diff --git a/scene_xrender.cpp b/scene_xrender.cpp index 72086f0bdd..b61bc76a28 100644 --- a/scene_xrender.cpp +++ b/scene_xrender.cpp @@ -244,7 +244,6 @@ void SceneXrender::windowGeometryShapeChanged(KWin::Toplevel* c) if (!windows.contains(c)) // this is ok, shape is not valid by default return; Window* w = windows[ c ]; - w->discardPicture(); w->discardShape(); } @@ -297,7 +296,6 @@ QRect SceneXrender::Window::temp_visibleRect; SceneXrender::Window::Window(Toplevel* c) : Scene::Window(c) - , _picture(XCB_RENDER_PICTURE_NONE) , format(findFormatForVisual(c->visual()->visualid)) , alpha_cached_opacity(0.0) { @@ -305,7 +303,6 @@ SceneXrender::Window::Window(Toplevel* c) SceneXrender::Window::~Window() { - discardPicture(); discardShape(); } @@ -315,33 +312,6 @@ void SceneXrender::Window::cleanup() s_tempPicture = NULL; } -// Create XRender picture for the pixmap with the window contents. -xcb_render_picture_t SceneXrender::Window::picture() -{ - if (!toplevel->damage().isEmpty() && _picture != XCB_RENDER_PICTURE_NONE) { - xcb_render_free_picture(connection(), _picture); - _picture = XCB_RENDER_PICTURE_NONE; - } - if (_picture == XCB_RENDER_PICTURE_NONE && format != 0) { - // Get the pixmap with the window contents. - xcb_pixmap_t pix = toplevel->windowPixmap(); - if (pix == XCB_PIXMAP_NONE) - return XCB_RENDER_PICTURE_NONE; - _picture = xcb_generate_id(connection()); - xcb_render_create_picture(connection(), _picture, pix, format, 0, NULL); - toplevel->resetDamage(); - } - return _picture; -} - - -void SceneXrender::Window::discardPicture() -{ - if (_picture != XCB_RENDER_PICTURE_NONE) - xcb_render_free_picture(connection(), _picture); - _picture = XCB_RENDER_PICTURE_NONE; -} - // Maps window coordinates to screen coordinates QRect SceneXrender::Window::mapToScreen(int mask, const WindowPaintData &data, const QRect &rect) const { @@ -432,9 +402,14 @@ void SceneXrender::Window::performPaint(int mask, QRegion region, WindowPaintDat if (region.isEmpty()) return; - xcb_render_picture_t pic = picture(); // get XRender picture + XRenderWindowPixmap *pixmap = windowPixmap(); + if (!pixmap || !pixmap->isValid()) { + return; + } + xcb_render_picture_t pic = pixmap->picture(); if (pic == XCB_RENDER_PICTURE_NONE) // The render format can be null for GL and/or Xv visuals return; + toplevel->resetDamage(); // set picture filter if (options->isXrenderSmoothScale()) { // only when forced, it's slow if (mask & PAINT_WINDOW_TRANSFORMED) @@ -734,12 +709,48 @@ void SceneXrender::Window::setPictureFilter(xcb_render_picture_t pic, Scene::Ima xcb_render_set_picture_filter(connection(), pic, filterName.length(), filterName.constData(), 0, NULL); } +WindowPixmap* SceneXrender::Window::createWindowPixmap() +{ + return new XRenderWindowPixmap(this, format); +} + void SceneXrender::screenGeometryChanged(const QSize &size) { Scene::screenGeometryChanged(size); initXRender(false); } +//**************************************** +// XRenderWindowPixmap +//**************************************** + +XRenderWindowPixmap::XRenderWindowPixmap(Scene::Window *window, xcb_render_pictformat_t format) + : WindowPixmap(window) + , m_picture(XCB_RENDER_PICTURE_NONE) + , m_format(format) +{ +} + +XRenderWindowPixmap::~XRenderWindowPixmap() +{ + if (m_picture != XCB_RENDER_PICTURE_NONE) { + xcb_render_free_picture(connection(), m_picture); + } +} + +void XRenderWindowPixmap::create() +{ + if (isValid()) { + return; + } + KWin::WindowPixmap::create(); + if (!isValid()) { + return; + } + m_picture = xcb_generate_id(connection()); + xcb_render_create_picture(connection(), m_picture, pixmap(), m_format, 0, NULL); +} + //**************************************** // SceneXrender::EffectFrame //**************************************** diff --git a/scene_xrender.h b/scene_xrender.h index e31b13615e..0edf890011 100644 --- a/scene_xrender.h +++ b/scene_xrender.h @@ -79,17 +79,16 @@ public: Window(Toplevel* c); virtual ~Window(); virtual void performPaint(int mask, QRegion region, WindowPaintData data); - void discardPicture(); QRegion transformedShape() const; void setTransformedShape(const QRegion& shape); static void cleanup(); +protected: + virtual WindowPixmap* createWindowPixmap(); private: - xcb_render_picture_t picture(); QRect mapToScreen(int mask, const WindowPaintData &data, const QRect &rect) const; QPoint mapToScreen(int mask, const WindowPaintData &data, const QPoint &point) const; void prepareTempPixmap(); void setPictureFilter(xcb_render_picture_t pic, ImageFilterType filter); - xcb_render_picture_t _picture; xcb_render_pictformat_t format; double alpha_cached_opacity; QRegion transformed_shape; @@ -97,6 +96,18 @@ private: static XRenderPicture *s_tempPicture; }; +class XRenderWindowPixmap : public WindowPixmap +{ +public: + explicit XRenderWindowPixmap(Scene::Window *window, xcb_render_pictformat_t format); + virtual ~XRenderWindowPixmap(); + xcb_render_picture_t picture() const; + virtual void create(); +private: + xcb_render_picture_t m_picture; + xcb_render_pictformat_t m_format; +}; + class SceneXrender::EffectFrame : public Scene::EffectFrame { @@ -143,6 +154,12 @@ void SceneXrender::Window::setTransformedShape(const QRegion& shape) transformed_shape = shape; } +inline +xcb_render_picture_t XRenderWindowPixmap::picture() const +{ + return m_picture; +} + /** * @short XRender implementation of Shadow. * diff --git a/toplevel.cpp b/toplevel.cpp index 4841d9c92a..1c172211f2 100644 --- a/toplevel.cpp +++ b/toplevel.cpp @@ -43,7 +43,6 @@ Toplevel::Toplevel() , m_isDamaged(false) , client(None) , frame(None) - , window_pix(None) , damage_handle(None) , is_shape(false) , effect_window(NULL) @@ -63,7 +62,6 @@ Toplevel::Toplevel() Toplevel::~Toplevel() { assert(damage_handle == None); - discardWindowPixmap(); delete info; } @@ -114,7 +112,6 @@ void Toplevel::copyToDeleted(Toplevel* c) info = c->info; client = c->client; frame = c->frame; - window_pix = c->window_pix; ready_for_painting = c->ready_for_painting; damage_handle = None; damage_region = c->damage_region; @@ -131,9 +128,6 @@ void Toplevel::copyToDeleted(Toplevel* c) window_role = c->windowRole(); opaque_region = c->opaqueRegion(); m_screen = c->m_screen; - // this needs to be done already here, otherwise 'c' could very likely - // call discardWindowPixmap() in something called during cleanup - c->window_pix = None; } // before being deleted, remove references to everything that's now diff --git a/toplevel.h b/toplevel.h index 0bd9c456d7..3ad7563d4f 100644 --- a/toplevel.h +++ b/toplevel.h @@ -226,7 +226,6 @@ public: pid_t pid() const; static bool resourceMatch(const Toplevel* c1, const Toplevel* c2); - Pixmap windowPixmap(bool allow_create = true); // may return None (e.g. at a bad moment while resizing) bool readyForPainting() const; // true if the window has been already painted its contents Visual* visual() const; bool shape() const; @@ -350,7 +349,6 @@ protected: void detectShape(Window id); virtual void propertyNotifyEvent(XPropertyEvent* e); virtual void damageNotifyEvent(); - xcb_pixmap_t createWindowPixmap(); void discardWindowPixmap(); void addDamageFull(); void getWmClientLeader(); @@ -395,7 +393,6 @@ private: // when adding new data members, check also copyToDeleted() Window client; Window frame; - Pixmap window_pix; xcb_damage_damage_t damage_handle; QRegion damage_region; // damage is really damaged window (XDamage) and texture needs bool is_shape; @@ -557,13 +554,6 @@ inline bool Toplevel::isDNDIcon() const return windowType() == NET::DNDIcon; } -inline Pixmap Toplevel::windowPixmap(bool allow_create) -{ - if (window_pix == None && allow_create) - window_pix = createWindowPixmap(); - return window_pix; -} - inline QRegion Toplevel::damage() const { return damage_region;