diff --git a/client.cpp b/client.cpp index 07ffe03127..a9a5f886a1 100644 --- a/client.cpp +++ b/client.cpp @@ -124,7 +124,6 @@ Client::Client(Workspace* ws) , padding_bottom(0) , sm_stacking_order(-1) , demandAttentionKNotifyTimer(NULL) - , m_responsibleForDecoPixmap(false) , paintRedirector(0) , m_firstInTabBox(false) , electricMaximizing(false) @@ -414,11 +413,10 @@ void Client::updateDecoration(bool check_workspace_pos, bool force) XMoveWindow(display(), decoration->widget()->winId(), -padding_left, -padding_top); move(calculateGravitation(false)); plainResize(sizeForClientSize(clientSize()), ForceGeometrySet); - paintRedirector = new PaintRedirector(decoration->widget()); - connect(paintRedirector, SIGNAL(paintPending()), SLOT(repaintDecorationPending())); - resizeDecorationPixmaps(); - if (compositing()) + if (Compositor::compositing()) { + paintRedirector = new PaintRedirector(this, decoration->widget()); discardWindowPixmap(); + } emit geometryShapeChanged(this, oldgeom); } else destroyDecoration(); @@ -437,21 +435,12 @@ void Client::destroyDecoration() if (decoration != NULL) { delete decoration; decoration = NULL; + paintRedirector = NULL; QPoint grav = calculateGravitation(true); border_left = border_right = border_top = border_bottom = 0; setMask(QRegion()); // Reset shape mask plainResize(sizeForClientSize(clientSize()), ForceGeometrySet); move(grav); - delete paintRedirector; - paintRedirector = NULL; - if (m_responsibleForDecoPixmap) { - XFreePixmap(display(), decorationPixmapTop.handle()); - XFreePixmap(display(), decorationPixmapBottom.handle()); - XFreePixmap(display(), decorationPixmapLeft.handle()); - XFreePixmap(display(), decorationPixmapRight.handle()); - m_responsibleForDecoPixmap = false; - } - decorationPixmapLeft = decorationPixmapRight = decorationPixmapTop = decorationPixmapBottom = QPixmap(); if (compositing()) discardWindowPixmap(); if (!deleting) { @@ -543,162 +532,6 @@ QRegion Client::decorationPendingRegion() const return paintRedirector->scheduledRepaintRegion().translated(x() - padding_left, y() - padding_top); } -void Client::repaintDecorationPending() -{ - if (compositing()) { - // The scene will update the decoration pixmaps in the next painting pass - // if it has not been already repainted before - const QRegion r = paintRedirector->scheduledRepaintRegion(); - if (!r.isEmpty()) { - addRepaint(r.translated(-padding_left,-padding_top)); - } - } -} - -bool Client::decorationPixmapRequiresRepaint() -{ - if (!paintRedirector) - return false; - QRegion r = paintRedirector->pendingRegion(); - return !r.isEmpty(); -} - -void Client::ensureDecorationPixmapsPainted() -{ - if (!paintRedirector || !compositing()) - return; - - QRegion r = paintRedirector->pendingRegion(); - if (r.isEmpty()) - return; - - QPixmap p = paintRedirector->performPendingPaint(); - - QRect lr, rr, tr, br; - layoutDecorationRects(lr, tr, rr, br, DecorationRelative); - - repaintDecorationPixmap(decorationPixmapLeft, lr, p, r); - repaintDecorationPixmap(decorationPixmapRight, rr, p, r); - repaintDecorationPixmap(decorationPixmapTop, tr, p, r); - repaintDecorationPixmap(decorationPixmapBottom, br, p, r); - - XSync(display(), false); -} - -void Client::repaintDecorationPixmap(QPixmap& pix, const QRect& r, const QPixmap& src, QRegion reg) -{ - if (!r.isValid()) - return; - QRect b = reg.boundingRect(); - reg &= r; - if (reg.isEmpty()) - return; - QPainter pt(&pix); - pt.translate(-r.topLeft()); - pt.setCompositionMode(QPainter::CompositionMode_Source); - pt.setClipRegion(reg); - pt.drawPixmap(b.topLeft(), src); - pt.end(); -} - -void Client::resizeDecorationPixmaps() -{ - if (!compositing()) { - // compositing disabled - we render directly on screen - triggerDecorationRepaint(); - return; - } - QRect lr, rr, tr, br; - layoutDecorationRects(lr, tr, rr, br, DecorationRelative); - - if (decorationPixmapTop.size() != tr.size()) { - if (m_responsibleForDecoPixmap && !decorationPixmapTop.isNull() && - decorationPixmapTop.paintEngine()->type() == QPaintEngine::X11) { - XFreePixmap(display(), decorationPixmapTop.handle()); - } - - if (effects->isOpenGLCompositing()) { - decorationPixmapTop = QPixmap(tr.size()); - m_responsibleForDecoPixmap = false; - } else { - Pixmap xpix = XCreatePixmap(QX11Info::display(), rootWindow(), - tr.size().width(), tr.height(), - 32); - decorationPixmapTop = QPixmap::fromX11Pixmap(xpix, QPixmap::ExplicitlyShared); - decorationPixmapTop.fill(Qt::transparent); - m_responsibleForDecoPixmap= true; - } - } - - if (decorationPixmapBottom.size() != br.size()) { - if (m_responsibleForDecoPixmap && !decorationPixmapBottom.isNull() && - decorationPixmapBottom.paintEngine()->type() == QPaintEngine::X11) { - XFreePixmap(display(), decorationPixmapBottom.handle()); - } - - if (effects->isOpenGLCompositing()) { - decorationPixmapBottom = QPixmap(br.size()); - m_responsibleForDecoPixmap = false; - } else { - Pixmap xpix = XCreatePixmap(QX11Info::display(), rootWindow(), - br.size().width(), br.height(), - 32); - decorationPixmapBottom = QPixmap::fromX11Pixmap(xpix, QPixmap::ExplicitlyShared); - decorationPixmapBottom.fill(Qt::transparent); - m_responsibleForDecoPixmap = true; - } - } - - if (decorationPixmapLeft.size() != lr.size()) { - if (m_responsibleForDecoPixmap && !decorationPixmapLeft.isNull() && - decorationPixmapLeft.paintEngine()->type() == QPaintEngine::X11) { - XFreePixmap(display(), decorationPixmapLeft.handle()); - } - - if (effects->isOpenGLCompositing()) { - decorationPixmapLeft = QPixmap(lr.size()); - m_responsibleForDecoPixmap = false; - } else { - Pixmap xpix = XCreatePixmap(QX11Info::display(), rootWindow(), - lr.size().width(), lr.height(), - 32); - decorationPixmapLeft = QPixmap::fromX11Pixmap(xpix, QPixmap::ExplicitlyShared); - decorationPixmapLeft.fill(Qt::transparent); - m_responsibleForDecoPixmap = true; - } - } - - if (decorationPixmapRight.size() != rr.size()) { - if (m_responsibleForDecoPixmap && !decorationPixmapRight.isNull() && - decorationPixmapRight.paintEngine()->type() == QPaintEngine::X11) { - XFreePixmap(display(), decorationPixmapRight.handle()); - } - - if (effects->isOpenGLCompositing()) { - decorationPixmapRight = QPixmap(rr.size()); - m_responsibleForDecoPixmap = false; - } else { - Pixmap xpix = XCreatePixmap(QX11Info::display(), rootWindow(), - rr.size().width(), rr.height(), - 32); - decorationPixmapRight = QPixmap::fromX11Pixmap(xpix, QPixmap::ExplicitlyShared); - decorationPixmapRight.fill(Qt::transparent); - m_responsibleForDecoPixmap = true; - } - } - -#ifdef HAVE_XRENDER - if (Extensions::renderAvailable()) { - // Make sure the pixmaps are created with alpha channels - decorationPixmapLeft.fill(Qt::transparent); - decorationPixmapRight.fill(Qt::transparent); - decorationPixmapTop.fill(Qt::transparent); - decorationPixmapBottom.fill(Qt::transparent); - } -#endif - triggerDecorationRepaint(); -} - QRect Client::transparentRect() const { if (isShade()) @@ -781,8 +614,10 @@ void Client::resizeDecoration(const QSize& s) if (oldSize == newSize) { QResizeEvent e(newSize, oldSize); QApplication::sendEvent(decoration->widget(), &e); - } else { // oldSize != newSize - resizeDecorationPixmaps(); + } else if (paintRedirector) { // oldSize != newSize + paintRedirector->resizePixmaps(); + } else { + triggerDecorationRepaint(); } updateInputWindow(); } diff --git a/client.h b/client.h index 130a67ae58..0752391503 100644 --- a/client.h +++ b/client.h @@ -584,17 +584,8 @@ public: } // Decorations <-> Effects - const QPixmap *topDecoPixmap() const { - return &decorationPixmapTop; - } - const QPixmap *leftDecoPixmap() const { - return &decorationPixmapLeft; - } - const QPixmap *bottomDecoPixmap() const { - return &decorationPixmapBottom; - } - const QPixmap *rightDecoPixmap() const { - return &decorationPixmapRight; + PaintRedirector *decorationPaintRedirector() { + return paintRedirector; } int paddingLeft() const { @@ -610,9 +601,6 @@ public: return padding_bottom; } - bool decorationPixmapRequiresRepaint(); - void ensureDecorationPixmapsPainted(); - QRect decorationRect() const; QRect transparentRect() const; @@ -694,7 +682,6 @@ private slots: void removeSyncSupport(); void pingTimeout(); void demandAttentionKNotify(); - void repaintDecorationPending(); //Signals for the scripting interface //Signals make an excellent way for communication @@ -795,8 +782,6 @@ private: void updateHiddenPreview(); void updateInputShape(); - void repaintDecorationPixmap(QPixmap& pix, const QRect& r, const QPixmap& src, QRegion reg); - void resizeDecorationPixmaps(); Time readUserTimeMapTimestamp(const KStartupInfoId* asn_id, const KStartupInfoData* asn_data, bool session) const; @@ -947,9 +932,6 @@ private: friend struct ResetupRulesProcedure; friend class GeometryUpdatesBlocker; QTimer* demandAttentionKNotifyTimer; - QPixmap decorationPixmapLeft, decorationPixmapRight, decorationPixmapTop, decorationPixmapBottom; - // we (instead of Qt) initialize the Pixmaps, and have to free them - bool m_responsibleForDecoPixmap; PaintRedirector* paintRedirector; QSharedPointer m_tabBoxClient; bool m_firstInTabBox; diff --git a/deleted.cpp b/deleted.cpp index e2e8b8c8c6..20258839d3 100644 --- a/deleted.cpp +++ b/deleted.cpp @@ -22,6 +22,7 @@ along with this program. If not, see . #include "workspace.h" #include "client.h" +#include "paintredirector.h" #include "shadow.h" namespace KWin @@ -37,6 +38,7 @@ Deleted::Deleted(Workspace* ws) , padding_bottom(0) , m_layer(UnknownLayer) , m_minimized(false) + , m_paintRedirector(NULL) { } @@ -88,10 +90,11 @@ void Deleted::copyToDeleted(Toplevel* c) decoration_right, decoration_bottom, Client::WindowRelative); - decorationPixmapLeft = *client->leftDecoPixmap(); - decorationPixmapRight = *client->rightDecoPixmap(); - decorationPixmapTop = *client->topDecoPixmap(); - decorationPixmapBottom = *client->bottomDecoPixmap(); + if (PaintRedirector *redirector = client->decorationPaintRedirector()) { + redirector->ensurePixmapsPainted(); + redirector->reparent(this); + m_paintRedirector = redirector; + } } m_minimized = client->isMinimized(); } diff --git a/deleted.h b/deleted.h index b91f4e2f5c..8d278ac597 100644 --- a/deleted.h +++ b/deleted.h @@ -25,6 +25,7 @@ along with this program. If not, see . namespace KWin { +class PaintRedirector; class Deleted : public Toplevel @@ -43,18 +44,6 @@ public: virtual QSize clientSize() const; virtual QRect transparentRect() const; virtual bool isDeleted() const; - const QPixmap *topDecoPixmap() const { - return &decorationPixmapTop; - } - const QPixmap *leftDecoPixmap() const { - return &decorationPixmapLeft; - } - const QPixmap *bottomDecoPixmap() const { - return &decorationPixmapBottom; - } - const QPixmap *rightDecoPixmap() const { - return &decorationPixmapRight; - } bool noBorder() const { return no_border; } @@ -67,10 +56,9 @@ public: return m_minimized; } NET::WindowType windowType(bool direct = false, int supported_types = 0) const; - bool decorationPixmapRequiresRepaint() const { - return false; + PaintRedirector *decorationPaintRedirector() { + return m_paintRedirector; } - void ensureDecorationPixmapsPainted() {} protected: virtual void debug(QDebug& stream) const; virtual bool shouldUnredirect() const; @@ -85,10 +73,6 @@ private: QRect contentsRect; // for clientPos()/clientSize() QRect transparent_rect; - QPixmap decorationPixmapLeft; - QPixmap decorationPixmapRight; - QPixmap decorationPixmapTop; - QPixmap decorationPixmapBottom; bool no_border; QRect decoration_left; QRect decoration_right; @@ -97,6 +81,7 @@ private: int padding_left, padding_top, padding_right, padding_bottom; Layer m_layer; bool m_minimized; + PaintRedirector *m_paintRedirector; }; inline void Deleted::refWindow() diff --git a/paintredirector.cpp b/paintredirector.cpp index 61282416bf..c8892c8f15 100644 --- a/paintredirector.cpp +++ b/paintredirector.cpp @@ -2,6 +2,7 @@ This file is part of the KDE project. Copyright (C) 2009 Lubos Lunak +Copyright (C) 2012 Martin Gräßlin Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -24,8 +25,11 @@ DEALINGS IN THE SOFTWARE. #include "paintredirector.h" -#include "composite.h" +#include "client.h" +#include "deleted.h" +#include "effects.h" #include +#include #include #include #include @@ -33,15 +37,39 @@ DEALINGS IN THE SOFTWARE. namespace KWin { -PaintRedirector::PaintRedirector(QWidget* w) - : widget(w) +PaintRedirector::PaintRedirector(Client *c, QWidget* w) + : QObject(w) + , widget(w) , recursionCheck(false) + , m_client(c) + , m_responsibleForPixmap(!effects->isOpenGLCompositing()) + , m_requiresRepaint(false) { added(w); + resizePixmaps(); +} + +PaintRedirector::~PaintRedirector() +{ + if (m_responsibleForPixmap) { + for (int i=0; irender(&scratch, QPoint(), pending.boundingRect(), QWidget::DrawChildren); recursionCheck = false; - pending = QRegion(); - scheduled = QRegion(); cleanupTimer.start(2000, this); return scratch; } @@ -68,6 +94,9 @@ bool PaintRedirector::isToolTip(QWidget *object) const bool PaintRedirector::eventFilter(QObject* o, QEvent* e) { + if (!widget || !m_client) { + return false; + } switch(e->type()) { case QEvent::ChildAdded: { QChildEvent* c = static_cast< QChildEvent* >(e); @@ -82,15 +111,18 @@ bool PaintRedirector::eventFilter(QObject* o, QEvent* e) break; } case QEvent::Paint: { - if (!Compositor::compositing()) { - return false; - } if (!recursionCheck) { QPaintEvent* pe = static_cast< QPaintEvent* >(e); QWidget* w = static_cast< QWidget* >(o); pending |= pe->region().translated(w->mapTo(widget, QPoint(0, 0))); scheduled = pending; - emit paintPending(); + + // schedule repaint + const int paddingLeft = m_client->paddingLeft(); + const int paddingTop = m_client->paddingTop(); + const bool needsTranslate = (paddingLeft != 0 || paddingTop != 0); + m_client->addRepaint(needsTranslate ? pending.translated(-paddingLeft, -paddingTop) : pending); + m_requiresRepaint = true; return true; // filter out } } @@ -138,6 +170,74 @@ void PaintRedirector::timerEvent(QTimerEvent* event) } } +void PaintRedirector::ensurePixmapsPainted() +{ + if (pending.isEmpty() || !m_client) + return; + + QPixmap p = performPendingPaint(); + + QRect rects[PixmapCount]; + m_client->layoutDecorationRects(rects[LeftPixmap], rects[TopPixmap], rects[RightPixmap], rects[BottomPixmap], Client::DecorationRelative); + + for (int i=0; ilayoutDecorationRects(rects[LeftPixmap], rects[TopPixmap], rects[RightPixmap], rects[BottomPixmap], Client::DecorationRelative); + + for (int i=0; itype() == QPaintEngine::X11) { + XFreePixmap(display(), m_pixmaps[i].handle()); + } + Pixmap xpix = XCreatePixmap(QX11Info::display(), rootWindow(), + rects[i].size().width(), rects[i].height(), + 32); + m_pixmaps[i] = QPixmap::fromX11Pixmap(xpix, QPixmap::ExplicitlyShared); + } + // Make sure the pixmaps are created with alpha channels + m_pixmaps[i].fill(Qt::transparent); + } + + // repaint + if (widget) { + widget->update(); + } +} + } // namespace #include "paintredirector.moc" diff --git a/paintredirector.h b/paintredirector.h index bb5d67c598..c5b3364456 100644 --- a/paintredirector.h +++ b/paintredirector.h @@ -2,6 +2,7 @@ This file is part of the KDE project. Copyright (C) 2009 Lubos Lunak +Copyright (C) 2012 Martin Gräßlin Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -32,6 +33,9 @@ DEALINGS IN THE SOFTWARE. namespace KWin { +// forward declarations +class Client; +class Deleted; // This class redirects all painting of a given widget (including its children) // into a paint device (QPixmap). @@ -40,24 +44,69 @@ class PaintRedirector { Q_OBJECT public: - PaintRedirector(QWidget* widget); + enum DecorationPixmap { + TopPixmap, + RightPixmap, + BottomPixmap, + LeftPixmap, + PixmapCount + }; + PaintRedirector(Client *c, QWidget* widget); + virtual ~PaintRedirector(); QPixmap performPendingPaint(); virtual bool eventFilter(QObject* o, QEvent* e); QRegion pendingRegion() const; QRegion scheduledRepaintRegion(); -signals: - void paintPending(); + + void markAsRepainted() { + m_requiresRepaint = false; + } + bool requiresRepaint() const { + return m_requiresRepaint; + } + void resizePixmaps(); + + const QPixmap *topDecoPixmap() const { + return &m_pixmaps[TopPixmap]; + } + const QPixmap *leftDecoPixmap() const { + return &m_pixmaps[LeftPixmap]; + } + const QPixmap *bottomDecoPixmap() const { + return &m_pixmaps[BottomPixmap]; + } + const QPixmap *rightDecoPixmap() const { + return &m_pixmaps[RightPixmap]; + } + + /** + * Used by Deleted::copyToDeleted() to move the PaintRedirector to the Deleted. + * The actual redirecting ends as the decoration gets destroyed after the Deleted + * is created. + **/ + void reparent(Deleted *d); + +public slots: + void ensurePixmapsPainted(); private: void added(QWidget* widget); void removed(QWidget* widget); bool isToolTip(QWidget* widget) const; void timerEvent(QTimerEvent* event); + + void repaintPixmap(QPixmap& pix, const QRect& r, const QPixmap& src, QRegion reg); QWidget* widget; QRegion pending; QRegion scheduled; QPixmap scratch; bool recursionCheck; QBasicTimer cleanupTimer; + + Client *m_client; + // we (instead of Qt) initialize the Pixmaps, and have to free them + bool m_responsibleForPixmap; + bool m_requiresRepaint; + QPixmap m_pixmaps[PixmapCount]; }; } // namespace diff --git a/scene_opengl.cpp b/scene_opengl.cpp index aa9bd15e1c..7f2368efff 100644 --- a/scene_opengl.cpp +++ b/scene_opengl.cpp @@ -83,6 +83,7 @@ Sources and other compositing managers: #include "deleted.h" #include "effects.h" #include "overlaywindow.h" +#include "paintredirector.h" #include @@ -894,20 +895,21 @@ template void SceneOpenGL::Window::paintDecorations(const WindowPaintData &data, const QRegion ®ion, bool hardwareClipping) { T* t = static_cast(toplevel); - if (t->noBorder()) { + PaintRedirector *redirector = t->decorationPaintRedirector(); + if (t->noBorder() || !redirector) { return; } WindowQuadList decoration = data.quads.select(WindowQuadDecoration); QRect topRect, leftRect, rightRect, bottomRect; - const bool updateDeco = t->decorationPixmapRequiresRepaint(); - t->ensureDecorationPixmapsPainted(); + const bool updateDeco = redirector->requiresRepaint(); t->layoutDecorationRects(leftRect, topRect, rightRect, bottomRect, Client::WindowRelative); - const QPixmap *left = t->leftDecoPixmap(); - const QPixmap *top = t->topDecoPixmap(); - const QPixmap *right = t->rightDecoPixmap(); - const QPixmap *bottom = t->bottomDecoPixmap(); + const QPixmap *left = redirector->leftDecoPixmap(); + const QPixmap *top = redirector->topDecoPixmap(); + const QPixmap *right = redirector->rightDecoPixmap(); + const QPixmap *bottom = redirector->bottomDecoPixmap(); + WindowQuadList topList, leftList, rightList, bottomList; foreach (const WindowQuad & quad, decoration) { @@ -929,10 +931,13 @@ void SceneOpenGL::Window::paintDecorations(const WindowPaintData &data, const QR } } + redirector->ensurePixmapsPainted(); paintDecoration(top, DecorationTop, region, topRect, data, topList, updateDeco, hardwareClipping); paintDecoration(left, DecorationLeft, region, leftRect, data, leftList, updateDeco, hardwareClipping); paintDecoration(right, DecorationRight, region, rightRect, data, rightList, updateDeco, hardwareClipping); paintDecoration(bottom, DecorationBottom, region, bottomRect, data, bottomList, updateDeco, hardwareClipping); + + redirector->markAsRepainted(); } diff --git a/scene_xrender.cpp b/scene_xrender.cpp index f0ac20b23a..bc49e26e41 100644 --- a/scene_xrender.cpp +++ b/scene_xrender.cpp @@ -47,6 +47,7 @@ along with this program. If not, see . #include "deleted.h" #include "effects.h" #include "overlaywindow.h" +#include "paintredirector.h" #include "kwinxrenderutils.h" #include @@ -584,25 +585,26 @@ void SceneXrender::Window::performPaint(int mask, QRegion region, WindowPaintDat const QPixmap *top = NULL; const QPixmap *right = NULL; const QPixmap *bottom = NULL; + PaintRedirector *redirector = NULL; QRect dtr, dlr, drr, dbr; if (client || deleted) { if (client && !client->noBorder()) { - client->ensureDecorationPixmapsPainted(); + redirector = client->decorationPaintRedirector(); noBorder = client->noBorder(); - left = client->leftDecoPixmap(); - top = client->topDecoPixmap(); - right = client->rightDecoPixmap(); - bottom = client->bottomDecoPixmap(); client->layoutDecorationRects(dlr, dtr, drr, dbr, Client::WindowRelative); } if (deleted && !deleted->noBorder()) { noBorder = deleted->noBorder(); - left = deleted->leftDecoPixmap(); - top = deleted->topDecoPixmap(); - right = deleted->rightDecoPixmap(); - bottom = deleted->bottomDecoPixmap(); + redirector = deleted->decorationPaintRedirector(); deleted->layoutDecorationRects(dlr, dtr, drr, dbr); } + if (redirector) { + redirector->ensurePixmapsPainted(); + left = redirector->leftDecoPixmap(); + top = redirector->topDecoPixmap(); + right = redirector->rightDecoPixmap(); + bottom = redirector->bottomDecoPixmap(); + } if (!noBorder) { MAP_RECT_TO_TARGET(dtr); MAP_RECT_TO_TARGET(dlr); @@ -686,6 +688,9 @@ XRenderComposite(display(), PictOpOver, _PART_->x11PictureHandle(), decorationAl RENDER_DECO_PART(right, drr); RENDER_DECO_PART(bottom, dbr); } + if (redirector) { + redirector->markAsRepainted(); + } } #undef RENDER_DECO_PART