From be3271c8e0615b5db52d03b97215f2639cab43c4 Mon Sep 17 00:00:00 2001 From: Rivo Laks Date: Fri, 7 Dec 2007 17:03:59 +0000 Subject: [PATCH] Fix problem with partial repaints when effect's prePaintWindow() expands paint region. Also rework the code a bit to simplify it and make it more comprehensible (IMHO). svn path=/trunk/KDE/kdebase/workspace/; revision=746050 --- scene.cpp | 81 ++++++++++++++++++++++++++--------------------- scene.h | 6 ++-- scene_xrender.cpp | 2 +- 3 files changed, 50 insertions(+), 39 deletions(-) diff --git a/scene.cpp b/scene.cpp index d6efd50b01..8903a9449d 100644 --- a/scene.cpp +++ b/scene.cpp @@ -195,7 +195,7 @@ void Scene::paintGenericScreen( int orig_mask, ScreenPaintData ) #endif if( !w->isPaintingEnabled()) continue; - phase2.append( Phase2Data( w, infiniteRegion(), data.mask, data.quads )); + phase2.append( Phase2Data( w, infiniteRegion(), data.clip, data.mask, data.quads )); } foreach( Phase2Data d, phase2 ) @@ -211,9 +211,7 @@ void Scene::paintSimpleScreen( int orig_mask, QRegion region ) // perhaps the two enums should be separated assert(( orig_mask & ( PAINT_WINDOW_TRANSFORMED | PAINT_SCREEN_TRANSFORMED | PAINT_WINDOW_TRANSLUCENT | PAINT_WINDOW_OPAQUE )) == 0 ); - QList< Phase2Data > phase2opaque; - QList< Phase2Data > phase2translucent; - QRegion allclips; + QHash< Window*, Phase2Data > phase2data; // Draw each opaque window top to bottom, subtracting the bounding rect of // each window from the clip region after it's been drawn. for( int i = stacking_order.count() - 1; // top to bottom @@ -236,49 +234,60 @@ void Scene::paintSimpleScreen( int orig_mask, QRegion region ) #endif if( !w->isPaintingEnabled()) continue; - data.paint -= allclips; // make sure to avoid already clipped areas - // no painting outside visible screen (and no transformations) - data.paint &= QRect( 0, 0, displayWidth(), displayHeight()); - if( data.paint.isEmpty()) // completely clipped - continue; if( data.paint != region ) // prepaint added area to draw - { - region |= data.paint; // make sure other windows in that area get painted too painted_region |= data.paint; // make sure it makes it to the screen - } - // If the window is transparent, the transparent part will be done - // in the 2nd pass. - if( data.mask & PAINT_WINDOW_TRANSLUCENT ) - phase2translucent.prepend( Phase2Data( w, data.paint, data.mask, data.quads )); - if( data.mask & PAINT_WINDOW_OPAQUE ) - { - phase2opaque.append( Phase2Data( w, data.paint, data.mask, data.quads )); - // The window can clip by its opaque parts the windows below. - region -= data.clip; - allclips |= data.clip; - } + // Schedule the window for painting + phase2data[w] = Phase2Data( w, data.paint, data.clip, data.mask, data.quads ); } // Do the actual painting // First opaque windows, top to bottom - foreach( Phase2Data d, phase2opaque ) - paintWindow( d.window, d.mask, d.region, d.quads ); - if( !( orig_mask & PAINT_SCREEN_BACKGROUND_FIRST )) - paintBackground( region ); // Fill any areas of the root window not covered by windows - // Now walk the list bottom to top, drawing translucent windows. - // That we draw bottom to top is important now since we're drawing translucent objects - // and also are clipping only by opaque windows. - QRegion add_paint; - foreach( Phase2Data d, phase2translucent ) + // This also calculates correct paint regions for windows, also taking + // care of clipping + QRegion allclips; + for( int i = stacking_order.count() - 1; i >= 0; --i ) { - paintWindow( d.window, d.mask, d.region | add_paint, d.quads ); - // It is necessary to also add paint regions of windows below, because their - // pre-paint's might have extended the paint area, so those areas need to be painted too. - add_paint |= d.region; + Window* w = stacking_order[ i ]; + if( !phase2data.contains( w )) + continue; + Phase2Data d = phase2data[w]; + // Calculate correct paint region and take the clip region into account + d.region = painted_region - allclips; + allclips |= d.clip; + if( d.mask & PAINT_WINDOW_TRANSLUCENT ) + { + // For translucent windows, the paint region must contain the + // entire painted area, except areas clipped by opaque windows + // above the translucent window + phase2data[w].region = d.region; + } + else + { + // Paint the opaque window + paintWindow( d.window, d.mask, d.region, d.quads ); + } + } + // Fill any areas of the root window not covered by windows + if( !( orig_mask & PAINT_SCREEN_BACKGROUND_FIRST )) + paintBackground( painted_region - allclips ); + // Now walk the list bottom to top, drawing translucent windows. + for( int i = 0; i < stacking_order.count(); i++ ) + { + Window* w = stacking_order[ i ]; + if( !phase2data.contains( w )) + continue; + Phase2Data d = phase2data[w]; + if( d.mask & PAINT_WINDOW_TRANSLUCENT ) + paintWindow( d.window, d.mask, d.region, d.quads ); } } void Scene::paintWindow( Window* w, int mask, QRegion region, WindowQuadList quads ) { + // no painting outside visible screen (and no transformations) + region &= QRect( 0, 0, displayWidth(), displayHeight()); + if( region.isEmpty()) // completely clipped + return; + WindowPaintData data( w->window()->effectWindow()); data.quads = quads; effects->paintWindow( effectWindow( w ), mask, region, data ); diff --git a/scene.h b/scene.h index 2ca86a80a6..ff0b51028e 100644 --- a/scene.h +++ b/scene.h @@ -112,10 +112,12 @@ class Scene // saved data for 2nd pass of optimized screen painting struct Phase2Data { - Phase2Data( Window* w, QRegion r, int m, const WindowQuadList& q ) - : window( w ), region( r ), mask( m ), quads( q ) {} + Phase2Data( Window* w, QRegion r, QRegion c, int m, const WindowQuadList& q ) + : window( w ), region( r ), clip( c ), mask( m ), quads( q ) {} + Phase2Data() { window = 0; mask = 0; } Window* window; QRegion region; + QRegion clip; int mask; WindowQuadList quads; }; diff --git a/scene_xrender.cpp b/scene_xrender.cpp index 760abe8f62..da92e4a891 100644 --- a/scene_xrender.cpp +++ b/scene_xrender.cpp @@ -237,7 +237,7 @@ void SceneXrender::paintTransformedScreen( int orig_mask ) // If the window is transparent, the transparent part will be done // in the 2nd pass. if( data.mask & PAINT_WINDOW_TRANSLUCENT ) - phase2.prepend( Phase2Data( w, data.paint, data.mask, data.quads )); + phase2.prepend( Phase2Data( w, data.paint, data.clip, data.mask, data.quads )); if( data.mask & PAINT_WINDOW_OPAQUE ) { w->setTransformedShape( QRegion());