Support for window thumbnails.

svn path=/branches/work/kwin_composite/; revision=640344
This commit is contained in:
Luboš Luňák 2007-03-07 17:50:33 +00:00
parent 3da3488448
commit f6ad1881e1
12 changed files with 229 additions and 5 deletions

View file

@ -71,10 +71,11 @@ set(kwin_KDEINIT_SRCS
effects/dialogparent.cpp effects/dialogparent.cpp
effects/showfps.cpp effects/showfps.cpp
effects/zoom.cpp effects/zoom.cpp
effects/test_input.cpp
effects/presentwindows.cpp effects/presentwindows.cpp
effects/minimizeanimation.cpp effects/minimizeanimation.cpp
effects/desktopchangeslide.cpp effects/desktopchangeslide.cpp
effects/test_input.cpp
effects/test_thumbnail.cpp
) )
if( CAPTURY_FOUND ) if( CAPTURY_FOUND )

View file

@ -281,6 +281,7 @@ void Client::updateDecoration( bool check_workspace_pos, bool force )
|| ( decoration != NULL && !noBorder()))) || ( decoration != NULL && !noBorder())))
return; return;
bool do_show = false; bool do_show = false;
QRect oldgeom = geometry();
blockGeometryUpdates( true ); blockGeometryUpdates( true );
if( force ) if( force )
destroyDecoration(); destroyDecoration();
@ -304,6 +305,8 @@ void Client::updateDecoration( bool check_workspace_pos, bool force )
discardWindowPixmap(); discardWindowPixmap();
if( scene != NULL ) if( scene != NULL )
scene->windowGeometryShapeChanged( this ); scene->windowGeometryShapeChanged( this );
if( effects != NULL )
effects->windowGeometryShapeChanged( effectWindow(), oldgeom );
} }
else else
destroyDecoration(); destroyDecoration();
@ -317,6 +320,7 @@ void Client::updateDecoration( bool check_workspace_pos, bool force )
void Client::destroyDecoration() void Client::destroyDecoration()
{ {
QRect oldgeom = geometry();
if( decoration != NULL ) if( decoration != NULL )
{ {
delete decoration; delete decoration;
@ -334,6 +338,8 @@ void Client::destroyDecoration()
discardWindowPixmap(); discardWindowPixmap();
if( scene != NULL && !deleting ) if( scene != NULL && !deleting )
scene->windowGeometryShapeChanged( this ); scene->windowGeometryShapeChanged( this );
if( effects != NULL && !deleting )
effects->windowGeometryShapeChanged( effectWindow(), oldgeom );
} }
} }
@ -462,6 +468,8 @@ void Client::updateShape()
addDamageFull(); addDamageFull();
if( scene != NULL ) if( scene != NULL )
scene->windowGeometryShapeChanged( this ); scene->windowGeometryShapeChanged( this );
if( effects != NULL )
effects->windowGeometryShapeChanged( effectWindow(), geometry());
// workaround for #19644 - shaped windows shouldn't have decoration // workaround for #19644 - shaped windows shouldn't have decoration
if( shape() && !noBorder()) if( shape() && !noBorder())
{ {
@ -500,6 +508,8 @@ void Client::setMask( const QRegion& reg, int mode )
addDamageFull(); addDamageFull();
if( scene != NULL ) if( scene != NULL )
scene->windowGeometryShapeChanged( this ); scene->windowGeometryShapeChanged( this );
if( effects != NULL )
effects->windowGeometryShapeChanged( effectWindow(), geometry());
} }
QRegion Client::mask() const QRegion Client::mask() const

View file

@ -429,6 +429,7 @@ void Toplevel::addDamage( int x, int y, int w, int h )
r &= rect(); r &= rect();
damage_region += r; damage_region += r;
repaints_region += r; repaints_region += r;
effects->windowDamaged( effectWindow(), r );
} }
void Toplevel::addDamageFull() void Toplevel::addDamageFull()
@ -437,6 +438,7 @@ void Toplevel::addDamageFull()
return; return;
damage_region = rect(); damage_region = rect();
repaints_region = rect(); repaints_region = rect();
effects->windowDamaged( effectWindow(), rect());
} }
void Toplevel::resetDamage( const QRect& r ) void Toplevel::resetDamage( const QRect& r )

View file

@ -35,6 +35,7 @@ License. See the file "COPYING" for the exact licensing terms.
#include "effects/zoom.h" #include "effects/zoom.h"
#include "effects/test_input.h" #include "effects/test_input.h"
#include "effects/test_thumbnail.h"
namespace KWinInternal namespace KWinInternal
{ {
@ -87,6 +88,14 @@ void Effect::desktopChanged( int )
{ {
} }
void Effect::windowDamaged( EffectWindow*, const QRect& )
{
}
void Effect::windowGeometryShapeChanged( EffectWindow*, const QRect& )
{
}
void Effect::prePaintScreen( int* mask, QRegion* region, int time ) void Effect::prePaintScreen( int* mask, QRegion* region, int time )
{ {
effects->prePaintScreen( mask, region, time ); effects->prePaintScreen( mask, region, time );
@ -117,13 +126,35 @@ void Effect::postPaintWindow( EffectWindow* w )
effects->postPaintWindow( w ); effects->postPaintWindow( w );
} }
void Effect::drawWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
{
effects->drawWindow( w, mask, region, data );
}
void Effect::setPositionTransformations( WindowPaintData& data, QRect& region, EffectWindow* w,
const QRect& r, Qt::AspectRatioMode aspect )
{
QSize size = w->size();
size.scale( r.size(), aspect );
data.xScale = size.width() / double( w->width());
data.yScale = size.height() / double( w->height());
int width = int( w->width() * data.xScale );
int height = int( w->height() * data.yScale );
int x = r.x() + ( r.width() - width ) / 2;
int y = r.y() + ( r.height() - height ) / 2;
region = QRect( x, y, width, height );
data.xTranslate = x - w->x();
data.yTranslate = y - w->y();
}
//**************************************** //****************************************
// EffectsHandler // EffectsHandler
//**************************************** //****************************************
EffectsHandler::EffectsHandler() EffectsHandler::EffectsHandler()
: current_paint_window( 0 ) : current_paint_screen( 0 )
, current_paint_screen( 0 ) , current_paint_window( 0 )
, current_draw_window( 0 )
{ {
if( !compositing()) if( !compositing())
return; return;
@ -147,7 +178,9 @@ EffectsHandler::EffectsHandler()
registerEffect("ScaleIn", new GenericEffectFactory<ScaleInEffect>); registerEffect("ScaleIn", new GenericEffectFactory<ScaleInEffect>);
registerEffect("DialogParent", new GenericEffectFactory<DialogParentEffect>); registerEffect("DialogParent", new GenericEffectFactory<DialogParentEffect>);
registerEffect("DesktopChangeSlide", new GenericEffectFactory<DesktopChangeSlideEffect>); registerEffect("DesktopChangeSlide", new GenericEffectFactory<DesktopChangeSlideEffect>);
registerEffect("TestInput", new GenericEffectFactory<TestInputEffect>); registerEffect("TestInput", new GenericEffectFactory<TestInputEffect>);
registerEffect("TestThumbnail", new GenericEffectFactory<TestThumbnailEffect>);
QStringList::const_iterator effectsIterator; QStringList::const_iterator effectsIterator;
for( effectsIterator = options->defaultEffects.constBegin(); for( effectsIterator = options->defaultEffects.constBegin();
@ -224,11 +257,26 @@ void EffectsHandler::desktopChanged( int old )
ep.second->desktopChanged( old ); ep.second->desktopChanged( old );
} }
void EffectsHandler::windowDamaged( EffectWindow* w, const QRect& r )
{
foreach( EffectPair ep, loaded_effects )
ep.second->windowDamaged( w, r );
}
void EffectsHandler::windowGeometryShapeChanged( EffectWindow* w, const QRect& old )
{
if( w == NULL ) // during late cleanup effectWindow() may be already NULL
return; // in some functions that may still call this
foreach( EffectPair ep, loaded_effects )
ep.second->windowGeometryShapeChanged( w, old );
}
// start another painting pass // start another painting pass
void EffectsHandler::startPaint() void EffectsHandler::startPaint()
{ {
assert( current_paint_screen == 0 ); assert( current_paint_screen == 0 );
assert( current_paint_window == 0 ); assert( current_paint_window == 0 );
assert( current_draw_window == 0 );
} }
// the idea is that effects call this function again which calls the next one // the idea is that effects call this function again which calls the next one
@ -294,6 +342,17 @@ void EffectsHandler::postPaintWindow( EffectWindow* w )
// no special final code // no special final code
} }
void EffectsHandler::drawWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
{
if( current_draw_window < loaded_effects.size())
{
loaded_effects[current_draw_window++].second->drawWindow( w, mask, region, data );
--current_draw_window;
}
else
scene->finalDrawWindow( w, mask, region, data );
}
Window EffectsHandler::createInputWindow( Effect* e, int x, int y, int w, int h, const QCursor& cursor ) Window EffectsHandler::createInputWindow( Effect* e, int x, int y, int w, int h, const QCursor& cursor )
{ {
XSetWindowAttributes attrs; XSetWindowAttributes attrs;
@ -400,6 +459,7 @@ void EffectsHandler::loadEffect( const QString& name )
{ {
assert( current_paint_screen == 0 ); assert( current_paint_screen == 0 );
assert( current_paint_window == 0 ); assert( current_paint_window == 0 );
assert( current_draw_window == 0 );
for(QVector< EffectPair >::const_iterator it = loaded_effects.constBegin(); it != loaded_effects.constEnd(); it++) for(QVector< EffectPair >::const_iterator it = loaded_effects.constBegin(); it != loaded_effects.constEnd(); it++)
{ {
@ -426,6 +486,7 @@ void EffectsHandler::unloadEffect( const QString& name )
{ {
assert( current_paint_screen == 0 ); assert( current_paint_screen == 0 );
assert( current_paint_window == 0 ); assert( current_paint_window == 0 );
assert( current_draw_window == 0 );
for( QVector< EffectPair >::iterator it = loaded_effects.begin(); it != loaded_effects.end(); it++) for( QVector< EffectPair >::iterator it = loaded_effects.begin(); it != loaded_effects.end(); it++)
{ {

View file

@ -69,8 +69,12 @@ class Effect
virtual void paintScreen( int mask, QRegion region, ScreenPaintData& data ); virtual void paintScreen( int mask, QRegion region, ScreenPaintData& data );
virtual void postPaintScreen(); virtual void postPaintScreen();
virtual void prePaintWindow( EffectWindow* w, int* mask, QRegion* region, int time ); virtual void prePaintWindow( EffectWindow* w, int* mask, QRegion* region, int time );
// paintWindow() can do various transformations
virtual void paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ); virtual void paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data );
virtual void postPaintWindow( EffectWindow* w ); virtual void postPaintWindow( EffectWindow* w );
// drawWindow() is used even for thumbnails etc. - it can alter the window itself where it
// makes sense (e.g.darkening out unresponsive windows), but it cannot do transformations
virtual void drawWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data );
// called when moved/resized or once after it's finished // called when moved/resized or once after it's finished
virtual void windowUserMovedResized( EffectWindow* c, bool first, bool last ); virtual void windowUserMovedResized( EffectWindow* c, bool first, bool last );
virtual void windowOpacityChanged( EffectWindow* c, double old_opacity ); virtual void windowOpacityChanged( EffectWindow* c, double old_opacity );
@ -82,12 +86,18 @@ class Effect
virtual void windowUnminimized( EffectWindow* c ); virtual void windowUnminimized( EffectWindow* c );
virtual void windowInputMouseEvent( Window w, QEvent* e ); virtual void windowInputMouseEvent( Window w, QEvent* e );
virtual void desktopChanged( int old ); virtual void desktopChanged( int old );
virtual void windowDamaged( EffectWindow* w, const QRect& r );
virtual void windowGeometryShapeChanged( EffectWindow* w, const QRect& old );
// Interpolates between x and y // Interpolates between x and y
static float interpolate(float x, float y, float a) static float interpolate(float x, float y, float a)
{ {
return x * (1 - a) + y * a; return x * (1 - a) + y * a;
} }
// helper to set WindowPaintData and QRegion to necessary transformations so that
// a following drawWindow() would put the window at the requested geometry (useful for thumbnails)
static void setPositionTransformations( WindowPaintData& data, QRect& region, EffectWindow* w,
const QRect& r, Qt::AspectRatioMode aspect );
protected: protected:
Workspace* workspace() const; Workspace* workspace() const;
@ -125,6 +135,7 @@ class EffectsHandler
void prePaintWindow( EffectWindow* w, int* mask, QRegion* region, int time ); void prePaintWindow( EffectWindow* w, int* mask, QRegion* region, int time );
void paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ); void paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data );
void postPaintWindow( EffectWindow* w ); void postPaintWindow( EffectWindow* w );
void drawWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data );
// Functions for handling input - e.g. when an Expose-like effect is shown, an input window // Functions for handling input - e.g. when an Expose-like effect is shown, an input window
// covering the whole screen is created and all mouse events will be intercepted by it. // covering the whole screen is created and all mouse events will be intercepted by it.
// The effect's windowInputMouseEvent() will get called with such events. // The effect's windowInputMouseEvent() will get called with such events.
@ -148,6 +159,9 @@ class EffectsHandler
bool checkInputWindowEvent( XEvent* e ); bool checkInputWindowEvent( XEvent* e );
void checkInputWindowStacking(); void checkInputWindowStacking();
void desktopChanged( int old ); void desktopChanged( int old );
void windowDamaged( EffectWindow* w, const QRect& r );
void windowGeometryShapeChanged( EffectWindow* w, const QRect& old );
void registerEffect( const QString& name, EffectFactory* factory ); void registerEffect( const QString& name, EffectFactory* factory );
void loadEffect( const QString& name ); void loadEffect( const QString& name );
void unloadEffect( const QString& name ); void unloadEffect( const QString& name );
@ -158,8 +172,9 @@ class EffectsHandler
typedef QPair< Effect*, Window > InputWindowPair; typedef QPair< Effect*, Window > InputWindowPair;
QList< InputWindowPair > input_windows; QList< InputWindowPair > input_windows;
QMap< QString, EffectFactory* > effect_factories; QMap< QString, EffectFactory* > effect_factories;
int current_paint_window;
int current_paint_screen; int current_paint_screen;
int current_paint_window;
int current_draw_window;
}; };
// This class is a representation of a window used by/for Effect classes. // This class is a representation of a window used by/for Effect classes.

View file

@ -0,0 +1,75 @@
/*****************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2007 Lubos Lunak <l.lunak@kde.org>
You can Freely distribute this program under the GNU General Public
License. See the file "COPYING" for the exact licensing terms.
******************************************************************/
/*
Testing of painting a window more than once. The active window is painted
once more as a thumbnail in the bottom-right corner of the screen.
*/
#include "test_thumbnail.h"
namespace KWinInternal
{
TestThumbnailEffect::TestThumbnailEffect()
: active_window( NULL )
{
}
void TestThumbnailEffect::paintScreen( int mask, QRegion region, ScreenPaintData& data )
{
effects->paintScreen( mask, region, data );
if( active_window != NULL && region.contains( thumbnailRect()))
{
WindowPaintData data;
QRect region;
setPositionTransformations( data, region, active_window, thumbnailRect(), Qt::KeepAspectRatio );
effects->drawWindow( active_window,
Scene::PAINT_WINDOW_OPAQUE | Scene::PAINT_WINDOW_TRANSLUCENT | Scene::PAINT_WINDOW_TRANSFORMED,
region, data );
}
}
void TestThumbnailEffect::windowActivated( EffectWindow* act )
{
active_window = act;
workspace()->addRepaint( thumbnailRect());
}
void TestThumbnailEffect::windowDamaged( EffectWindow* w, const QRect& )
{
if( w == active_window )
workspace()->addRepaint( thumbnailRect());
// TODO maybe just the relevant part of the area should be repainted?
}
void TestThumbnailEffect::windowGeometryShapeChanged( EffectWindow* w, const QRect& old )
{
if( w == active_window && w->size() != old.size())
workspace()->addRepaint( thumbnailRect());
}
void TestThumbnailEffect::windowClosed( EffectWindow* w )
{
if( w == active_window )
{
active_window = NULL;
workspace()->addRepaint( thumbnailRect());
}
}
QRect TestThumbnailEffect::thumbnailRect() const
{
return QRect( displayWidth() - 100, displayHeight() - 100, 100, 100 );
}
} // namespace

42
effects/test_thumbnail.h Normal file
View file

@ -0,0 +1,42 @@
/*****************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2007 Lubos Lunak <l.lunak@kde.org>
You can Freely distribute this program under the GNU General Public
License. See the file "COPYING" for the exact licensing terms.
******************************************************************/
/*
Testing of painting a window more than once.
*/
#ifndef KWIN_TEST_THUMBNAIL_H
#define KWIN_TEST_THUMBNAIL_H
#include <effects.h>
namespace KWinInternal
{
class TestThumbnailEffect
: public Effect
{
public:
TestThumbnailEffect();
virtual void paintScreen( int mask, QRegion region, ScreenPaintData& data );
virtual void windowActivated( EffectWindow* w );
virtual void windowDamaged( EffectWindow* w, const QRect& damage );
virtual void windowGeometryShapeChanged( EffectWindow* w, const QRect& old );
virtual void windowClosed( EffectWindow* w );
private:
QRect thumbnailRect() const;
EffectWindow* active_window;
};
} // namespace
#endif

View file

@ -1636,6 +1636,8 @@ bool Unmanaged::windowEvent( XEvent* e )
addDamageFull(); addDamageFull();
if( scene != NULL ) if( scene != NULL )
scene->windowGeometryShapeChanged( this ); scene->windowGeometryShapeChanged( this );
if( effects != NULL )
effects->windowGeometryShapeChanged( effectWindow(), geometry());
} }
#ifdef HAVE_XDAMAGE #ifdef HAVE_XDAMAGE
if( e->type == Extensions::damageNotifyEvent()) if( e->type == Extensions::damageNotifyEvent())
@ -1664,10 +1666,13 @@ void Unmanaged::configureNotifyEvent( XConfigureEvent* e )
if( newgeom == geom ) if( newgeom == geom )
return; return;
workspace()->addRepaint( geometry()); // damage old area workspace()->addRepaint( geometry()); // damage old area
QRect old = geom;
geom = newgeom; geom = newgeom;
discardWindowPixmap(); discardWindowPixmap();
if( scene != NULL ) if( scene != NULL )
scene->windowGeometryShapeChanged( this ); scene->windowGeometryShapeChanged( this );
if( effects != NULL )
effects->windowGeometryShapeChanged( effectWindow(), old );
} }
// **************************************** // ****************************************

View file

@ -1704,6 +1704,8 @@ void Client::setGeometry( int x, int y, int w, int h, ForceGeometry_t force )
discardWindowPixmap(); discardWindowPixmap();
if( scene != NULL ) if( scene != NULL )
scene->windowGeometryShapeChanged( this ); scene->windowGeometryShapeChanged( this );
if( effects != NULL )
effects->windowGeometryShapeChanged( effectWindow(), geom_before_block );
} }
workspace()->addRepaint( geom_before_block ); workspace()->addRepaint( geom_before_block );
geom_before_block = geom; geom_before_block = geom;
@ -1764,6 +1766,8 @@ void Client::plainResize( int w, int h, ForceGeometry_t force )
discardWindowPixmap(); discardWindowPixmap();
if( scene != NULL ) if( scene != NULL )
scene->windowGeometryShapeChanged( this ); scene->windowGeometryShapeChanged( this );
if( effects != NULL )
effects->windowGeometryShapeChanged( effectWindow(), geom_before_block );
workspace()->addRepaint( geom_before_block ); workspace()->addRepaint( geom_before_block );
geom_before_block = geom; geom_before_block = geom;
} }

View file

@ -230,6 +230,12 @@ void Scene::paintWindow( Window* w, int mask, QRegion region )
// the function that'll be eventually called by paintWindow() above // the function that'll be eventually called by paintWindow() above
void Scene::finalPaintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ) void Scene::finalPaintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
{
effects->drawWindow( w, mask, region, data );
}
// will be eventually called from drawWindow()
void Scene::finalDrawWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
{ {
w->sceneWindow()->performPaint( mask, region, data ); w->sceneWindow()->performPaint( mask, region, data );
} }

View file

@ -90,6 +90,8 @@ class Scene
void finalPaintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ); void finalPaintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data );
// shared implementation, starts painting the window // shared implementation, starts painting the window
virtual void paintWindow( Window* w, int mask, QRegion region ); virtual void paintWindow( Window* w, int mask, QRegion region );
// called after all effects had their drawWindow() called
void finalDrawWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data );
// infinite region, i.e. everything // infinite region, i.e. everything
static QRegion infiniteRegion(); static QRegion infiniteRegion();
// compute time since the last repaint // compute time since the last repaint

View file

@ -1140,7 +1140,8 @@ void SceneOpenGL::Window::performPaint( int mask, QRegion region, WindowPaintDat
// paint only requested areas // paint only requested areas
if( region != infiniteRegion()) // avoid integer overflow if( region != infiniteRegion()) // avoid integer overflow
region.translate( -x(), -y()); region.translate( -x(), -y());
region &= shape(); if(( mask & ( PAINT_SCREEN_TRANSFORMED | PAINT_WINDOW_TRANSFORMED )) == 0 )
region &= shape();
if( region.isEmpty()) if( region.isEmpty())
return; return;
if( !bindTexture()) if( !bindTexture())