Add post-painting pass to be used for triggering

repaints with animations.


svn path=/branches/work/kwin_composite/; revision=600156
This commit is contained in:
Luboš Luňák 2006-10-29 19:07:10 +00:00
parent 6b41c062c8
commit 3f9b754ee7
9 changed files with 95 additions and 36 deletions

View file

@ -115,8 +115,6 @@ TODO:
be created, but the old animation should be stopped - compare window id's?
? maybe just keep the object around in a special list
* add a postpaint pass
- needed for animations to trigger next repaint, currently window damage is reset after
the painting pass, meaning the damage cannot be added from there
- current workaround is to damage the whole screen, as there's a for resetting that damage
in advance
* don't add workspace damage in Toplevel::addDamage()
- instead add damage of windows to the screen only before doing the painting
- this should prevent repaints because of obscured windows

View file

@ -156,13 +156,12 @@ void Workspace::compositeTimeout()
else if( Unmanaged* c = findUnmanaged( HandleMatchPredicate( children[ i ] )))
windows.append( c );
}
effects->startPaint();
// TODO when effects cause damage, it should be only enqueued for next repaint
QRegion r = damage_region;
scene->prePaint();
scene->paint( damage_region, windows );
damage_region = QRegion();
scene->paint( r, windows );
foreach( Toplevel* c, windows )
c->resetDamage();
scene->postPaint();
lastCompositePaint.start();
}

View file

@ -47,6 +47,11 @@ void Effect::paintScreen( int mask, QRegion region, ScreenPaintData& data )
effects->paintScreen( mask, region, data );
}
void Effect::postPaintScreen()
{
effects->postPaintScreen();
}
void Effect::prePaintWindow( Scene::Window* w, int* mask, QRegion* region, int time )
{
effects->prePaintWindow( w, mask, region, time );
@ -57,6 +62,11 @@ void Effect::paintWindow( Scene::Window* w, int mask, QRegion region, WindowPain
effects->paintWindow( w, mask, region, data );
}
void Effect::postPaintWindow( Scene::Window* w )
{
effects->postPaintWindow( w );
}
void MakeHalfTransparent::prePaintWindow( Scene::Window* w, int* mask, QRegion* region, int time )
{
const Client* c = dynamic_cast< const Client* >( w->window());
@ -188,17 +198,9 @@ ShiftWorkspaceUp::ShiftWorkspaceUp( Workspace* ws )
void ShiftWorkspaceUp::prePaintScreen( int* mask, QRegion* region, int time )
{
if( up && diff < 1000 )
{
diff = qBound( 0, diff + time, 1000 ); // KDE3: note this differs from KCLAMP
if( diff < 1000 )
wspace->addDamageFull(); // affects next redraw
}
if( !up && diff > 0 )
{
diff = qBound( 0, diff - time, 1000 );
if( diff > 0 )
wspace->addDamageFull(); // affects next redraw
}
if( diff != 0 )
*mask |= Scene::PAINT_SCREEN_TRANSFORMED;
effects->prePaintScreen( mask, region, time );
@ -211,6 +213,13 @@ void ShiftWorkspaceUp::paintScreen( int mask, QRegion region, ScreenPaintData& d
effects->paintScreen( mask, region, data );
}
void ShiftWorkspaceUp::postPaintScreen()
{
if( up ? diff < 1000 : diff > 0 )
wspace->addDamageFull(); // trigger next animation repaint
effects->postPaintScreen();
}
void ShiftWorkspaceUp::tick()
{
up = !up;
@ -227,9 +236,6 @@ void FadeIn::prePaintWindow( Scene::Window* w, int* mask, QRegion* region, int t
{
*mask |= Scene::PAINT_WINDOW_TRANSLUCENT;
*mask &= ~Scene::PAINT_WINDOW_OPAQUE;
// TODO this should just damage the window, but right now window
// damage is cleared after the painting pass - a postpaint pass is needed
w->window()->workspace()->addDamageFull();
}
else
windows.remove( w->window());
@ -246,6 +252,13 @@ void FadeIn::paintWindow( Scene::Window* w, int mask, QRegion region, WindowPain
effects->paintWindow( w, mask, region, data );
}
void FadeIn::postPaintWindow( Scene::Window* w )
{
if( windows.contains( w->window()))
w->window()->addDamageFull(); // trigger next animation repaint
effects->postPaintWindow( w );
}
void FadeIn::windowAdded( Toplevel* c )
{
Client* cc = dynamic_cast< Client* >( c );
@ -268,12 +281,7 @@ void ScaleIn::prePaintWindow( Scene::Window* w, int* mask, QRegion* region, int
{
windows[ w->window() ] += time / 500.; // complete change in 500ms
if( windows[ w->window() ] < 1 )
{
*mask |= Scene::PAINT_WINDOW_TRANSFORMED;
// TODO this should just damage the window, but right now window
// damage is cleared after the painting pass - a postpaint pass is needed
w->window()->workspace()->addDamageFull();
}
else
windows.remove( w->window());
}
@ -286,12 +294,19 @@ void ScaleIn::paintWindow( Scene::Window* w, int mask, QRegion region, WindowPai
{
data.xScale *= windows[ w->window()];
data.yScale *= windows[ w->window()];
data.xTranslate += w->window()->width() / 2 * ( 1 - windows[ w->window()] );
data.yTranslate += w->window()->height() / 2 * ( 1 - windows[ w->window()] );
data.xTranslate += int( w->window()->width() / 2 * ( 1 - windows[ w->window()] ));
data.yTranslate += int( w->window()->height() / 2 * ( 1 - windows[ w->window()] ));
}
effects->paintWindow( w, mask, region, data );
}
void ScaleIn::postPaintWindow( Scene::Window* w )
{
if( windows.contains( w->window()))
w->window()->addDamageFull(); // trigger next animation repaint
effects->postPaintWindow( w );
}
void ScaleIn::windowAdded( Toplevel* c )
{
Client* cc = dynamic_cast< Client* >( c );
@ -359,7 +374,7 @@ void EffectsHandler::startPaint()
// the idea is that effects call this function again which calls the next one
void EffectsHandler::prePaintScreen( int* mask, QRegion* region, int time )
{
if( current_paint_screen < effects.size() - 1 )
if( current_paint_screen < effects.size())
{
effects[ current_paint_screen++ ]->prePaintScreen( mask, region, time );
--current_paint_screen;
@ -369,7 +384,7 @@ void EffectsHandler::prePaintScreen( int* mask, QRegion* region, int time )
void EffectsHandler::paintScreen( int mask, QRegion region, ScreenPaintData& data )
{
if( current_paint_screen < effects.size() - 1 )
if( current_paint_screen < effects.size())
{
effects[ current_paint_screen++ ]->paintScreen( mask, region, data );
--current_paint_screen;
@ -378,9 +393,19 @@ void EffectsHandler::paintScreen( int mask, QRegion region, ScreenPaintData& dat
scene->finalPaintScreen( mask, region, data );
}
void EffectsHandler::postPaintScreen()
{
if( current_paint_screen < effects.size())
{
effects[ current_paint_screen++ ]->postPaintScreen();
--current_paint_screen;
}
// no special final code
}
void EffectsHandler::prePaintWindow( Scene::Window* w, int* mask, QRegion* region, int time )
{
if( current_paint_window < effects.size() - 1 )
if( current_paint_window < effects.size())
{
effects[ current_paint_window++ ]->prePaintWindow( w, mask, region, time );
--current_paint_window;
@ -390,7 +415,7 @@ void EffectsHandler::prePaintWindow( Scene::Window* w, int* mask, QRegion* regio
void EffectsHandler::paintWindow( Scene::Window* w, int mask, QRegion region, WindowPaintData& data )
{
if( current_paint_window < effects.size() - 1 )
if( current_paint_window < effects.size())
{
effects[ current_paint_window++ ]->paintWindow( w, mask, region, data );
--current_paint_window;
@ -399,6 +424,16 @@ void EffectsHandler::paintWindow( Scene::Window* w, int mask, QRegion region, Wi
scene->finalPaintWindow( w, mask, region, data );
}
void EffectsHandler::postPaintWindow( Scene::Window* w )
{
if( current_paint_window < effects.size())
{
effects[ current_paint_window++ ]->postPaintWindow( w );
--current_paint_window;
}
// no special final code
}
EffectsHandler* effects;
} // namespace

View file

@ -50,8 +50,10 @@ class Effect
virtual ~Effect();
virtual void prePaintScreen( int* mask, QRegion* region, int time );
virtual void paintScreen( int mask, QRegion region, ScreenPaintData& data );
virtual void postPaintScreen();
virtual void prePaintWindow( Scene::Window* w, int* mask, QRegion* region, int time );
virtual void paintWindow( Scene::Window* w, int mask, QRegion region, WindowPaintData& data );
virtual void postPaintWindow( Scene::Window* w );
// called when moved/resized or once after it's finished
virtual void windowUserMovedResized( Toplevel* c, bool first, bool last );
virtual void windowAdded( Toplevel* c );
@ -66,8 +68,10 @@ class EffectsHandler
// for use by effects
void prePaintScreen( int* mask, QRegion* region, int time );
void paintScreen( int mask, QRegion region, ScreenPaintData& data );
void postPaintScreen();
void prePaintWindow( Scene::Window* w, int* mask, QRegion* region, int time );
void paintWindow( Scene::Window* w, int mask, QRegion region, WindowPaintData& data );
void postPaintWindow( Scene::Window* w );
// internal (used by kwin core or compositing code)
void startPaint();
void windowUserMovedResized( Toplevel* c, bool first, bool last );
@ -126,6 +130,7 @@ class ShiftWorkspaceUp
ShiftWorkspaceUp( Workspace* ws );
virtual void prePaintScreen( int* mask, QRegion* region, int time );
virtual void paintScreen( int mask, QRegion region, ScreenPaintData& data );
virtual void postPaintScreen();
private slots:
void tick();
private:
@ -141,6 +146,7 @@ class FadeIn
public:
virtual void prePaintWindow( Scene::Window* w, int* mask, QRegion* region, int time );
virtual void paintWindow( Scene::Window* w, int mask, QRegion region, WindowPaintData& data );
virtual void postPaintWindow( Scene::Window* w );
// TODO react also on virtual desktop changes
virtual void windowAdded( Toplevel* c );
virtual void windowDeleted( Toplevel* c );
@ -154,6 +160,7 @@ class ScaleIn
public:
virtual void prePaintWindow( Scene::Window* w, int* mask, QRegion* region, int time );
virtual void paintWindow( Scene::Window* w, int mask, QRegion region, WindowPaintData& data );
virtual void postPaintWindow( Scene::Window* w );
// TODO react also on virtual desktop changes
virtual void windowAdded( Toplevel* c );
virtual void windowDeleted( Toplevel* c );

View file

@ -33,6 +33,12 @@ Scene::~Scene()
{
}
void Scene::prePaint()
{
effects->startPaint();
// do the rest of prepaint pass together with paint pass
}
// returns mask and possibly modified region
void Scene::paintScreen( int* mask, QRegion* region )
{
@ -148,6 +154,14 @@ void Scene::finalPaintWindow( Scene::Window* w, int mask, QRegion region, Window
w->performPaint( mask, region, data );
}
void Scene::postPaint()
{
effects->postPaintScreen();
foreach( Window* w, stacking_order )
effects->postPaintWindow( w );
stacking_order.clear();
}
void Scene::windowGeometryShapeChanged( Toplevel* )
{
}

View file

@ -29,8 +29,10 @@ class Scene
Scene( Workspace* ws );
virtual ~Scene() = 0;
class Window;
virtual void prePaint();
// repaints the given screen areas, windows provides the stacking order
virtual void paint( QRegion damage, ToplevelList windows ) = 0;
virtual void postPaint();
// shape/size of a window changed
virtual void windowGeometryShapeChanged( Toplevel* );
// opacity of a window changed
@ -84,7 +86,7 @@ class Scene::Window
int y() const;
int width() const;
int height() const;
const Toplevel* window() const;
Toplevel* window();
bool isVisible() const;
bool isOpaque() const;
QRegion shape() const;
@ -130,7 +132,7 @@ int Scene::Window::height() const
}
inline
const Toplevel* Scene::Window::window() const
Toplevel* Scene::Window::window()
{
return toplevel;
}

View file

@ -279,7 +279,6 @@ void SceneOpenGL::paint( QRegion damage, ToplevelList toplevels )
glTranslatef( 0, -displayHeight(), 0 );
int mask = 0;
paintScreen( &mask, &damage );
stacking_order.clear();
glPopMatrix();
// TODO only partial repaint for mask & PAINT_SCREEN_REGION
if( root_db )
@ -292,7 +291,6 @@ void SceneOpenGL::paint( QRegion damage, ToplevelList toplevels )
XFlush( display());
}
ungrabXServer();
checkGLError( "PostPaint" );
}
void SceneOpenGL::paintGenericScreen( int mask, ScreenPaintData data )
@ -320,6 +318,12 @@ void SceneOpenGL::paintBackground( QRegion )
// TODO?
}
void SceneOpenGL::postPaint()
{
checkGLError( "PostPaint" );
Scene::postPaint();
}
void SceneOpenGL::windowAdded( Toplevel* c )
{
assert( !windows.contains( c ));

View file

@ -26,6 +26,7 @@ class SceneOpenGL
SceneOpenGL( Workspace* ws );
virtual ~SceneOpenGL();
virtual void paint( QRegion damage, ToplevelList windows );
virtual void postPaint();
virtual void windowGeometryShapeChanged( Toplevel* );
virtual void windowOpacityChanged( Toplevel* );
virtual void windowAdded( Toplevel* );

View file

@ -86,7 +86,6 @@ void SceneXrender::paint( QRegion damage, ToplevelList toplevels )
}
int mask = 0;
paintScreen( &mask, &damage );
stacking_order.clear();
if( mask & PAINT_SCREEN_REGION )
{
// Use the damage region as the clip region for the root window