Adding a DesktopThumbnailItem declarative item

Similar to WindowThumbnailItem for rendering a desktop thumbnail.
Uses the new paintDesktop hook.

FEATURE: 296067
FIXED-IN: 4.11.0
REVIEW: 104441
icc-effect-5.14.5
Martin Gräßlin 2012-03-29 20:17:57 +02:00
parent ae7be07d0f
commit 466bef3a6d
12 changed files with 237 additions and 36 deletions

View File

@ -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<DesktopThumbnailItem*>(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<DesktopThumbnailItem*>(object));
}
//****************************************
// EffectWindowGroupImpl
//****************************************

View File

@ -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<WindowThumbnailItem*, QWeakPointer<EffectWindowImpl> > const &thumbnails() const {
return m_thumbnails;
}
QList<DesktopThumbnailItem*> 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<int, QVariant> dataMap;
QHash<WindowThumbnailItem*, QWeakPointer<EffectWindowImpl> > m_thumbnails;
QList<DesktopThumbnailItem*> m_desktopThumbnails;
};
class EffectWindowGroupImpl

138
scene.cpp
View File

@ -72,6 +72,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QVector2D>
#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<EffectWindowImpl*>(effectWindow(w));
for (QHash<WindowThumbnailItem*, QWeakPointer<EffectWindowImpl> >::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<QGraphicsView*> 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<EffectWindowImpl*>(effectWindow(w));
for (QList<DesktopThumbnailItem*>::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<QGraphicsView*> 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 &region, ScreenPaintData &data)
{
static_cast<EffectsHandlerImpl*>(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)
{

14
scene.h
View File

@ -25,9 +25,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#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 &region, bool opaqueFullscreen);
virtual void paintDesktop(int desktop, int mask, const QRegion &region, 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

View File

@ -547,6 +547,15 @@ void SceneOpenGL::screenGeometryChanged(const QSize &size)
ShaderManager::instance()->resetAllShaders();
}
void SceneOpenGL::paintDesktop(int desktop, int mask, const QRegion &region, 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 &region, 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());

View File

@ -77,6 +77,7 @@ protected:
virtual void paintBackground(QRegion region);
virtual void extendPaintRegion(QRegion &region, bool opaqueFullscreen);
QMatrix4x4 transformation(int mask, const ScreenPaintData &data) const;
virtual void paintDesktop(int desktop, int mask, const QRegion &region, ScreenPaintData &data);
virtual void doPaintBackground(const QVector<float> &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 &region, ScreenPaintData &data);
private Q_SLOTS:
void slotColorCorrectedChanged();

View File

@ -245,6 +245,13 @@ void SceneXrender::paintGenericScreen(int mask, ScreenPaintData data)
Scene::paintGenericScreen(mask, data);
}
void SceneXrender::paintDesktop(int desktop, int mask, const QRegion &region, ScreenPaintData &data)
{
PaintClipper::push(region);
KWin::Scene::paintDesktop(desktop, mask, region, data);
PaintClipper::pop(region);
}
// fill the screen background
void SceneXrender::paintBackground(QRegion region)
{

View File

@ -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 &region, ScreenPaintData &data);
public Q_SLOTS:
virtual void windowOpacityChanged(KWin::Toplevel* c);
virtual void windowGeometryShapeChanged(KWin::Toplevel* c);

View File

@ -555,6 +555,7 @@ void KWin::DeclarativeScript::run()
kdeclarative.initialize();
kdeclarative.setupBindings();
installScriptFunctions(kdeclarative.scriptEngine());
qmlRegisterType<DesktopThumbnailItem>("org.kde.kwin", 0, 1, "DesktopThumbnailItem");
qmlRegisterType<WindowThumbnailItem>("org.kde.kwin", 0, 1, "ThumbnailItem");
qmlRegisterType<KWin::ScriptingClientModel::ClientModel>();
qmlRegisterType<KWin::ScriptingClientModel::SimpleClientModel>("org.kde.kwin", 0, 1, "ClientModel");

View File

@ -156,6 +156,9 @@ DeclarativeView::DeclarativeView(QAbstractItemModel *model, TabBoxConfig::TabBox
kdeclarative.setDeclarativeEngine(engine());
kdeclarative.initialize();
kdeclarative.setupBindings();
#ifndef TABBOX_KCM
qmlRegisterType<DesktopThumbnailItem>("org.kde.kwin", 0, 1, "DesktopThumbnailItem");
#endif
qmlRegisterType<WindowThumbnailItem>("org.kde.kwin", 0, 1, "ThumbnailItem");
rootContext()->setContextProperty("viewId", static_cast<qulonglong>(winId()));
rootContext()->setContextProperty("plasmaThemeVariant", plasmaThemeVariant());

View File

@ -21,6 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#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<int>(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

View File

@ -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
{