From 3f9b754ee73715bb27bf51350f33a058ff04fc31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lubo=C5=A1=20Lu=C5=88=C3=A1k?= Date: Sun, 29 Oct 2006 19:07:10 +0000 Subject: [PATCH] Add post-painting pass to be used for triggering repaints with animations. svn path=/branches/work/kwin_composite/; revision=600156 --- COMPOSITE_TODO | 8 ++--- composite.cpp | 7 ++--- effects.cpp | 79 ++++++++++++++++++++++++++++++++++------------- effects.h | 7 +++++ scene.cpp | 14 +++++++++ scene.h | 6 ++-- scene_opengl.cpp | 8 +++-- scene_opengl.h | 1 + scene_xrender.cpp | 1 - 9 files changed, 95 insertions(+), 36 deletions(-) diff --git a/COMPOSITE_TODO b/COMPOSITE_TODO index 3513fd67dd..7b3a22dab0 100644 --- a/COMPOSITE_TODO +++ b/COMPOSITE_TODO @@ -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 diff --git a/composite.cpp b/composite.cpp index b266899333..e3ad68ac5e 100644 --- a/composite.cpp +++ b/composite.cpp @@ -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(); } diff --git a/effects.cpp b/effects.cpp index e5c9feddfb..a1af1be892 100644 --- a/effects.cpp +++ b/effects.cpp @@ -46,6 +46,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 ) { @@ -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 diff --git a/effects.h b/effects.h index 097b980142..fd3ff5bf92 100644 --- a/effects.h +++ b/effects.h @@ -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 ); diff --git a/scene.cpp b/scene.cpp index c38c9dee5a..6868e92c40 100644 --- a/scene.cpp +++ b/scene.cpp @@ -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* ) { } diff --git a/scene.h b/scene.h index 88472c0dad..c316468d2a 100644 --- a/scene.h +++ b/scene.h @@ -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; } diff --git a/scene_opengl.cpp b/scene_opengl.cpp index 09f8beef5a..3af7ccd04b 100644 --- a/scene_opengl.cpp +++ b/scene_opengl.cpp @@ -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 )); diff --git a/scene_opengl.h b/scene_opengl.h index 29ce81e7f7..9a83f8c521 100644 --- a/scene_opengl.h +++ b/scene_opengl.h @@ -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* ); diff --git a/scene_xrender.cpp b/scene_xrender.cpp index 32fb34acd0..9d5d3083ac 100644 --- a/scene_xrender.cpp +++ b/scene_xrender.cpp @@ -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