diff --git a/effects.cpp b/effects.cpp index 4443c5ba9f..260d4e4e46 100644 --- a/effects.cpp +++ b/effects.cpp @@ -1813,6 +1813,9 @@ void EffectWindowImpl::registerThumbnail(AbstractThumbnailItem *item) insertThumbnail(thumb); connect(thumb, SIGNAL(destroyed(QObject*)), SLOT(thumbnailDestroyed(QObject*))); connect(thumb, SIGNAL(wIdChanged(qulonglong)), SLOT(thumbnailTargetChanged())); + } else if (DesktopThumbnailItem *desktopThumb = qobject_cast(item)) { + m_desktopThumbnails.append(desktopThumb); + connect(desktopThumb, SIGNAL(destroyed(QObject*)), SLOT(desktopThumbnailDestroyed(QObject*))); } } @@ -1839,6 +1842,12 @@ void EffectWindowImpl::insertThumbnail(WindowThumbnailItem *item) } } +void EffectWindowImpl::desktopThumbnailDestroyed(QObject *object) +{ + // we know it is a DesktopThumbnailItem + m_desktopThumbnails.removeAll(static_cast(object)); +} + //**************************************** // EffectWindowGroupImpl //**************************************** diff --git a/effects.h b/effects.h index 3ecad8ebac..0cc2e28ecb 100644 --- a/effects.h +++ b/effects.h @@ -41,6 +41,7 @@ namespace KWin typedef QPair< Effect*, xcb_window_t > InputWindowPair; class AbstractThumbnailItem; +class DesktopThumbnailItem; class WindowThumbnailItem; class Client; @@ -310,15 +311,20 @@ public: QHash > const &thumbnails() const { return m_thumbnails; } + QList const &desktopThumbnails() const { + return m_desktopThumbnails; + } private Q_SLOTS: void thumbnailDestroyed(QObject *object); void thumbnailTargetChanged(); + void desktopThumbnailDestroyed(QObject *object); private: void insertThumbnail(WindowThumbnailItem *item); Toplevel* toplevel; Scene::Window* sw; // This one is used only during paint pass. QHash dataMap; QHash > m_thumbnails; + QList m_desktopThumbnails; }; class EffectWindowGroupImpl diff --git a/scene.cpp b/scene.cpp index 4f0a4b7c36..45c726a30d 100644 --- a/scene.cpp +++ b/scene.cpp @@ -72,6 +72,7 @@ along with this program. If not, see . #include #include +#include #include "client.h" #include "decorations.h" @@ -361,6 +362,8 @@ void Scene::paintSimpleScreen(int orig_mask, QRegion region) painted_region |= paintedArea; } +static Scene::Window *s_recursionCheck = NULL; + void Scene::paintWindow(Window* w, int mask, QRegion region, WindowQuadList quads) { // no painting outside visible screen (and no transformations) @@ -368,10 +371,21 @@ void Scene::paintWindow(Window* w, int mask, QRegion region, WindowQuadList quad if (region.isEmpty()) // completely clipped return; + if (s_recursionCheck == w) { + return; + } + WindowPaintData data(w->window()->effectWindow()); data.quads = quads; effects->paintWindow(effectWindow(w), mask, region, data); // paint thumbnails on top of window + paintWindowThumbnails(w, region, data.opacity(), data.brightness(), data.saturation()); + // and desktop thumbnails + paintDesktopThumbnails(w); +} + +void Scene::paintWindowThumbnails(Scene::Window *w, QRegion region, qreal opacity, qreal brightness, qreal saturation) +{ EffectWindowImpl *wImpl = static_cast(effectWindow(w)); for (QHash >::const_iterator it = wImpl->thumbnails().constBegin(); it != wImpl->thumbnails().constEnd(); @@ -385,9 +399,9 @@ void Scene::paintWindow(Window* w, int mask, QRegion region, WindowQuadList quad } EffectWindowImpl *thumb = it.value().data(); WindowPaintData thumbData(thumb); - thumbData.setOpacity(data.opacity()); - thumbData.setBrightness(data.brightness() * item->brightness()); - thumbData.setSaturation(data.saturation() * item->saturation()); + thumbData.setOpacity(opacity); + thumbData.setBrightness(brightness * item->brightness()); + thumbData.setSaturation(saturation * item->saturation()); const QRect visualThumbRect(thumb->expandedGeometry()); @@ -403,35 +417,12 @@ void Scene::paintWindow(Window* w, int mask, QRegion region, WindowQuadList quad if (item->scene() == 0) { continue; } - // in principle there could be more than one QGraphicsView per QGraphicsScene, - // although TabBox does not make use of it so far - QList views = item->scene()->views(); - QGraphicsView* declview = 0; - QPoint viewPos; - foreach (QGraphicsView* view, views) { - if (view->winId() == w->window()->window()) { - declview = view; - break; - } - QWidget *parent = view; - while ((parent = parent->parentWidget())) { - // if the graphicsview is not the topmost widget we try to go up to the - // toplevel widget and check whether that is the window we are looking for. - if (parent->winId() == w->window()->window()) { - declview = view; - viewPos = view->mapTo(parent, QPoint()); - break; - } - } - if (declview) { - // our nested loop found it, so we can break this loop as well - // doesn't look nice, but still better than goto - break; - } - } + + QGraphicsView* declview = findViewForThumbnailItem(item, w); if (declview == 0) { continue; } + QPoint viewPos = findOffsetInWindow(declview, w->window()->window()); const QPoint point = viewPos + declview->mapFromScene(item->scenePos()); qreal x = point.x() + w->x() + (item->width() - size.width())/2; qreal y = point.y() + w->y() + (item->height() - size.height()) / 2; @@ -462,6 +453,95 @@ void Scene::paintWindow(Window* w, int mask, QRegion region, WindowQuadList quad } } +void Scene::paintDesktopThumbnails(Scene::Window *w) +{ + EffectWindowImpl *wImpl = static_cast(effectWindow(w)); + for (QList::const_iterator it = wImpl->desktopThumbnails().constBegin(); + it != wImpl->desktopThumbnails().constEnd(); + ++it) { + DesktopThumbnailItem *item = *it; + if (!item->isVisible()) { + continue; + } + // it can happen in the init/closing phase of the tabbox + // that the corresponding QGraphicsScene is not available + if (item->scene() == 0) { + continue; + } + QGraphicsView* declview = findViewForThumbnailItem(item, w); + if (declview == 0) { + continue; + } + QPoint viewPos = findOffsetInWindow(declview, w->window()->window()); + s_recursionCheck = w; + + ScreenPaintData data; + QSize size = QSize(displayWidth(), displayHeight()); + + size.scale(item->width(), item->height(), Qt::KeepAspectRatio); + data *= QVector2D(size.width() / double(displayWidth()), + size.height() / double(displayHeight())); + const QPoint point = viewPos + declview->mapFromScene(item->scenePos()); + const qreal x = point.x() + w->x() + (item->width() - size.width())/2; + const qreal y = point.y() + w->y() + (item->height() - size.height()) / 2; + const QRect region = QRect(x, y, item->width(), item->height()); + QRegion clippingRegion = region; + clippingRegion &= QRegion(wImpl->x(), wImpl->y(), wImpl->width(), wImpl->height()); + QPainterPath path = item->clipPath(); + if (!path.isEmpty()) { + // here we assume that the clippath consists of a single rectangle + const QPolygonF sceneBounds = item->mapToScene(path.boundingRect()); + const QRect viewBounds = declview->mapFromScene(sceneBounds).boundingRect(); + // shrinking the rect due to rounding errors + clippingRegion &= viewBounds.adjusted(0,0,-1,-1).translated(viewPos + w->pos()); + } + data += QPointF(x, y); + const int desktopMask = PAINT_SCREEN_TRANSFORMED | PAINT_WINDOW_TRANSFORMED | PAINT_SCREEN_BACKGROUND_FIRST; + paintDesktop(item->desktop(), desktopMask, clippingRegion, data); + s_recursionCheck = NULL; + } +} + +QGraphicsView *Scene::findViewForThumbnailItem(AbstractThumbnailItem *item, Scene::Window *w) +{ + // in principle there could be more than one QGraphicsView per QGraphicsScene, + // although TabBox does not make use of it so far + QList views = item->scene()->views(); + foreach (QGraphicsView* view, views) { + if (view->winId() == w->window()->window()) { + return view; + } + QWidget *parent = view; + while ((parent = parent->parentWidget())) { + // if the graphicsview is not the topmost widget we try to go up to the + // toplevel widget and check whether that is the window we are looking for. + if (parent->winId() == w->window()->window()) { + return view; + } + } + } + return NULL; +} + +QPoint Scene::findOffsetInWindow(QWidget *view, xcb_window_t idOfTopmostWindow) +{ + if (view->winId() == idOfTopmostWindow) { + return QPoint(); + } + QWidget *parent = view; + while ((parent = parent->parentWidget())) { + if (parent->winId() == idOfTopmostWindow) { + return view->mapTo(parent, QPoint()); + } + } + return QPoint(); +} + +void Scene::paintDesktop(int desktop, int mask, const QRegion ®ion, ScreenPaintData &data) +{ + static_cast(effects)->paintDesktop(desktop, mask, region, data); +} + // the function that'll be eventually called by paintWindow() above void Scene::finalPaintWindow(EffectWindowImpl* w, int mask, QRegion region, WindowPaintData& data) { diff --git a/scene.h b/scene.h index 5d49c40abd..3b8a667e08 100644 --- a/scene.h +++ b/scene.h @@ -25,9 +25,12 @@ along with this program. If not, see . #include "utils.h" #include "kwineffects.h" +class QGraphicsView; + namespace KWin { +class AbstractThumbnailItem; class Workspace; class Deleted; class EffectFrameImpl; @@ -128,6 +131,7 @@ protected: // let the scene decide whether it's better to paint more of the screen, eg. in order to allow a buffer swap // the default is NOOP virtual void extendPaintRegion(QRegion ®ion, bool opaqueFullscreen); + virtual void paintDesktop(int desktop, int mask, const QRegion ®ion, ScreenPaintData &data); // compute time since the last repaint void updateTimeDiff(); // saved data for 2nd pass of optimized screen painting @@ -156,6 +160,16 @@ protected: int time_diff; QElapsedTimer last_time; Workspace* wspace; +private: + void paintWindowThumbnails(Scene::Window *w, QRegion region, qreal opacity, qreal brightness, qreal saturation); + void paintDesktopThumbnails(Scene::Window *w); + /** + * Helper function to find the GraphicsView the ThumbnailItem @p item is rendered in which + * matches our Window @p w. + * If not found @c NULL is returned. + **/ + QGraphicsView *findViewForThumbnailItem(AbstractThumbnailItem *item, Scene::Window *w); + QPoint findOffsetInWindow(QWidget *view, xcb_window_t idOfTopmostWindow); }; // The base class for windows representations in composite backends diff --git a/scene_opengl.cpp b/scene_opengl.cpp index 72dea96f8e..85ea3cd7ff 100644 --- a/scene_opengl.cpp +++ b/scene_opengl.cpp @@ -547,6 +547,15 @@ void SceneOpenGL::screenGeometryChanged(const QSize &size) ShaderManager::instance()->resetAllShaders(); } +void SceneOpenGL::paintDesktop(int desktop, int mask, const QRegion ®ion, ScreenPaintData &data) +{ + const QRect r = region.boundingRect(); + glEnable(GL_SCISSOR_TEST); + glScissor(r.x(), displayHeight() - r.y() - r.height(), r.width(), r.height()); + KWin::Scene::paintDesktop(desktop, mask, region, data); + glDisable(GL_SCISSOR_TEST); +} + //**************************************** // SceneOpenGL2 //**************************************** @@ -623,6 +632,17 @@ void SceneOpenGL2::paintGenericScreen(int mask, ScreenPaintData data) Scene::paintGenericScreen(mask, data); } +void SceneOpenGL2::paintDesktop(int desktop, int mask, const QRegion ®ion, ScreenPaintData &data) +{ + ShaderBinder binder(ShaderManager::GenericShader); + GLShader *shader = binder.shader(); + QMatrix4x4 screenTransformation = shader->getUniformMatrix4x4("screenTransformation"); + + KWin::SceneOpenGL::paintDesktop(desktop, mask, region, data); + + shader->setUniform(GLShader::ScreenTransformation, screenTransformation); +} + void SceneOpenGL2::doPaintBackground(const QVector< float >& vertices) { GLVertexBuffer *vbo = GLVertexBuffer::streamingBuffer(); @@ -995,7 +1015,7 @@ void SceneOpenGL::Window::performPaint(int mask, QRegion region, WindowPaintData if (region.isEmpty()) return; - bool hardwareClipping = region != infiniteRegion() && (mask & PAINT_WINDOW_TRANSFORMED); + bool hardwareClipping = region != infiniteRegion() && (mask & PAINT_WINDOW_TRANSFORMED) && !(mask & PAINT_SCREEN_TRANSFORMED); if (region != infiniteRegion() && !hardwareClipping) { WindowQuadList quads; const QRegion filterRegion = region.translated(-x(), -y()); diff --git a/scene_opengl.h b/scene_opengl.h index 409ec3d6a5..774057dc3c 100644 --- a/scene_opengl.h +++ b/scene_opengl.h @@ -77,6 +77,7 @@ protected: virtual void paintBackground(QRegion region); virtual void extendPaintRegion(QRegion ®ion, bool opaqueFullscreen); QMatrix4x4 transformation(int mask, const ScreenPaintData &data) const; + virtual void paintDesktop(int desktop, int mask, const QRegion ®ion, ScreenPaintData &data); virtual void doPaintBackground(const QVector &vertices) = 0; virtual SceneOpenGL::Window *createWindow(Toplevel *t) = 0; @@ -113,6 +114,7 @@ protected: virtual void doPaintBackground(const QVector< float >& vertices); virtual SceneOpenGL::Window *createWindow(Toplevel *t); virtual void finalDrawWindow(EffectWindowImpl* w, int mask, QRegion region, WindowPaintData& data); + virtual void paintDesktop(int desktop, int mask, const QRegion ®ion, ScreenPaintData &data); private Q_SLOTS: void slotColorCorrectedChanged(); diff --git a/scene_xrender.cpp b/scene_xrender.cpp index 04ad958437..bea0530c05 100644 --- a/scene_xrender.cpp +++ b/scene_xrender.cpp @@ -245,6 +245,13 @@ void SceneXrender::paintGenericScreen(int mask, ScreenPaintData data) Scene::paintGenericScreen(mask, data); } +void SceneXrender::paintDesktop(int desktop, int mask, const QRegion ®ion, ScreenPaintData &data) +{ + PaintClipper::push(region); + KWin::Scene::paintDesktop(desktop, mask, region, data); + PaintClipper::pop(region); +} + // fill the screen background void SceneXrender::paintBackground(QRegion region) { diff --git a/scene_xrender.h b/scene_xrender.h index 4a939406f9..96cd8e3356 100644 --- a/scene_xrender.h +++ b/scene_xrender.h @@ -53,6 +53,7 @@ public: protected: virtual void paintBackground(QRegion region); virtual void paintGenericScreen(int mask, ScreenPaintData data); + virtual void paintDesktop(int desktop, int mask, const QRegion ®ion, ScreenPaintData &data); public Q_SLOTS: virtual void windowOpacityChanged(KWin::Toplevel* c); virtual void windowGeometryShapeChanged(KWin::Toplevel* c); diff --git a/scripting/scripting.cpp b/scripting/scripting.cpp index ef7b31be96..2618c4e3eb 100644 --- a/scripting/scripting.cpp +++ b/scripting/scripting.cpp @@ -555,6 +555,7 @@ void KWin::DeclarativeScript::run() kdeclarative.initialize(); kdeclarative.setupBindings(); installScriptFunctions(kdeclarative.scriptEngine()); + qmlRegisterType("org.kde.kwin", 0, 1, "DesktopThumbnailItem"); qmlRegisterType("org.kde.kwin", 0, 1, "ThumbnailItem"); qmlRegisterType(); qmlRegisterType("org.kde.kwin", 0, 1, "ClientModel"); diff --git a/tabbox/declarative.cpp b/tabbox/declarative.cpp index 859d8a92d7..4af5471e3e 100644 --- a/tabbox/declarative.cpp +++ b/tabbox/declarative.cpp @@ -156,6 +156,9 @@ DeclarativeView::DeclarativeView(QAbstractItemModel *model, TabBoxConfig::TabBox kdeclarative.setDeclarativeEngine(engine()); kdeclarative.initialize(); kdeclarative.setupBindings(); +#ifndef TABBOX_KCM + qmlRegisterType("org.kde.kwin", 0, 1, "DesktopThumbnailItem"); +#endif qmlRegisterType("org.kde.kwin", 0, 1, "ThumbnailItem"); rootContext()->setContextProperty("viewId", static_cast(winId())); rootContext()->setContextProperty("plasmaThemeVariant", plasmaThemeVariant()); diff --git a/thumbnailitem.cpp b/thumbnailitem.cpp index db30252f80..9ec604b049 100644 --- a/thumbnailitem.cpp +++ b/thumbnailitem.cpp @@ -21,6 +21,7 @@ along with this program. If not, see . #include "thumbnailitem.h" // KWin #include "client.h" +#include "composite.h" #include "effects.h" #include "workspace.h" #include "composite.h" @@ -150,9 +151,6 @@ WindowThumbnailItem::WindowThumbnailItem(QDeclarativeItem* parent) , m_wId(0) , m_client(NULL) { - if (effects) { - connect(effects, SIGNAL(windowDamaged(KWin::EffectWindow*,QRect)), SLOT(repaint(KWin::EffectWindow*))); - } } WindowThumbnailItem::~WindowThumbnailItem() @@ -188,7 +186,6 @@ void WindowThumbnailItem::setClient(Client *client) emit clientChanged(); } - void WindowThumbnailItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { if (effects) { @@ -213,4 +210,41 @@ void WindowThumbnailItem::repaint(KWin::EffectWindow *w) } } +DesktopThumbnailItem::DesktopThumbnailItem(QDeclarativeItem *parent) + : AbstractThumbnailItem(parent) + , m_desktop(0) +{ +} + +DesktopThumbnailItem::~DesktopThumbnailItem() +{ +} + +void DesktopThumbnailItem::setDesktop(int desktop) +{ + desktop = qBound(1, desktop, VirtualDesktopManager::self()->count()); + if (desktop == m_desktop) { + return; + } + m_desktop = desktop; + update(); + emit desktopChanged(m_desktop); +} + +void DesktopThumbnailItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + if (effects) { + QDeclarativeItem::paint(painter, option, widget); + return; + } + // TODO: render icon +} + +void DesktopThumbnailItem::repaint(EffectWindow *w) +{ + if (w->isOnDesktop(m_desktop)) { + update(); + } +} + } // namespace KWin diff --git a/thumbnailitem.h b/thumbnailitem.h index ca05a4238c..89fd48d715 100644 --- a/thumbnailitem.h +++ b/thumbnailitem.h @@ -63,6 +63,9 @@ Q_SIGNALS: protected: explicit AbstractThumbnailItem(QDeclarativeItem *parent = 0); +protected Q_SLOTS: + virtual void repaint(KWin::EffectWindow* w) = 0; + private Q_SLOTS: void init(); void effectWindowAdded(); @@ -96,13 +99,34 @@ public: Q_SIGNALS: void wIdChanged(qulonglong wid); void clientChanged(); -private Q_SLOTS: - void repaint(KWin::EffectWindow* w); +protected Q_SLOTS: + virtual void repaint(KWin::EffectWindow* w); private: qulonglong m_wId; Client *m_client; }; +class DesktopThumbnailItem : public AbstractThumbnailItem +{ + Q_OBJECT + Q_PROPERTY(int desktop READ desktop WRITE setDesktop NOTIFY desktopChanged) +public: + DesktopThumbnailItem(QDeclarativeItem *parent = 0); + virtual ~DesktopThumbnailItem(); + + int desktop() const { + return m_desktop; + } + void setDesktop(int desktop); + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); +Q_SIGNALS: + void desktopChanged(int desktop); +protected Q_SLOTS: + virtual void repaint(KWin::EffectWindow* w); +private: + int m_desktop; +}; + inline qreal AbstractThumbnailItem::brightness() const {