From e6c23e4cd301b5a892900b7420cf93b9f1378e7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lubo=C5=A1=20Lu=C5=88=C3=A1k?= Date: Thu, 6 Jul 2006 18:22:01 +0000 Subject: [PATCH] Ok, I give up, whoever wants more complicated transformations than just translation are welcome to implement it themselves. I'm no graphics guy after all and this seems to be far beyond me. svn path=/branches/work/kwin_composite/; revision=559182 --- composite.cpp | 3 +- effects.cpp | 54 ++++++++++--- effects.h | 20 +++-- scene.cpp | 5 -- scene.h | 4 +- scene_basic.cpp | 2 +- scene_basic.h | 2 +- scene_xrender.cpp | 193 ++++++++++++++++++++++++++++++---------------- scene_xrender.h | 8 +- 9 files changed, 191 insertions(+), 100 deletions(-) diff --git a/composite.cpp b/composite.cpp index 0da1293167..b60dc0497f 100644 --- a/composite.cpp +++ b/composite.cpp @@ -165,8 +165,7 @@ void Workspace::compositeTimeout() else if( Unmanaged* c = findUnmanaged( HandleMatchPredicate( children[ i ] ))) windows.append( c ); } - scene->setWindows( windows ); - scene->paint( damage ); + scene->paint( damage, windows ); XFixesDestroyRegion( display(), damage ); damage = None; } diff --git a/effects.cpp b/effects.cpp index 2f5c87d897..a4a6b1f13e 100644 --- a/effects.cpp +++ b/effects.cpp @@ -132,11 +132,11 @@ void Effect::windowUserMovedResized( Toplevel* , bool, bool ) { } -void Effect::transformWindow( Toplevel*, EffectData& ) +void Effect::transformWindow( Toplevel*, Matrix&, EffectData& ) { } -void Effect::transformWorkspace( Workspace*, EffectData& ) +void Effect::transformWorkspace( Workspace*, Matrix&, EffectData& ) { } @@ -144,7 +144,7 @@ void Effect::windowDeleted( Toplevel* ) { } -void MakeHalfTransparent::transformWindow( Toplevel* c, EffectData& data ) +void MakeHalfTransparent::transformWindow( Toplevel* c, Matrix&, EffectData& data ) { if( c->isDialog()) data.opacity *= 0.8; @@ -167,13 +167,13 @@ ShakyMove::ShakyMove() static const int shaky_diff[] = { 0, 1, 2, 3, 2, 1, 0, -1, -2, -3, -2, -1 }; static const int SHAKY_MAX = sizeof( shaky_diff ) / sizeof( shaky_diff[ 0 ] ); -void ShakyMove::transformWindow( Toplevel* c, EffectData& data ) +void ShakyMove::transformWindow( Toplevel* c, Matrix& matrix, EffectData& ) { if( windows.contains( c )) { Matrix m; m.m[ 0 ][ 3 ] = shaky_diff[ windows[ c ]]; - data.matrix *= m; + matrix *= m; } } @@ -217,8 +217,31 @@ void ShakyMove::tick() } } +void GrowMove::transformWindow( Toplevel* c, Matrix& matrix, EffectData& ) + { + if( Client* c2 = dynamic_cast< Client* >( c )) + if( c2->isMove()) + { + Matrix m; + m.m[ 0 ][ 0 ] = 1.2; + m.m[ 1 ][ 1 ] = 1.4; + matrix *= m; + } + } + +void GrowMove::windowUserMovedResized( Toplevel* c, bool first, bool last ) + { + if( first || last ) + { + c->workspace()->addDamage( c, c->geometry()); + scene->updateTransformation( c ); + c->workspace()->addDamage( c, c->geometry()); + } + } + static MakeHalfTransparent* mht; static ShakyMove* sm; +static GrowMove* gm; //**************************************** // EffectsHandler @@ -228,6 +251,7 @@ EffectsHandler::EffectsHandler() { mht = new MakeHalfTransparent; sm = new ShakyMove; +// gm = new GrowMove; } void EffectsHandler::windowUserMovedResized( Toplevel* c, bool first, bool last ) @@ -236,22 +260,28 @@ void EffectsHandler::windowUserMovedResized( Toplevel* c, bool first, bool last mht->windowUserMovedResized( c, first, last ); if( sm ) sm->windowUserMovedResized( c, first, last ); + if( gm ) + gm->windowUserMovedResized( c, first, last ); } -void EffectsHandler::transformWindow( Toplevel* c, EffectData& data ) +void EffectsHandler::transformWindow( Toplevel* c, Matrix& matrix, EffectData& data ) { if( mht ) - mht->transformWindow( c, data ); + mht->transformWindow( c, matrix, data ); if( sm ) - sm->transformWindow( c, data ); + sm->transformWindow( c, matrix, data ); + if( gm ) + gm->transformWindow( c, matrix, data ); } -void EffectsHandler::transformWorkspace( Workspace* w, EffectData& data ) +void EffectsHandler::transformWorkspace( Workspace* w, Matrix& matrix, EffectData& data ) { if( mht ) - mht->transformWorkspace( w, data ); + mht->transformWorkspace( w, matrix, data ); if( sm ) - sm->transformWorkspace( w, data ); + sm->transformWorkspace( w, matrix, data ); + if( gm ) + gm->transformWorkspace( w, matrix, data ); } void EffectsHandler::windowDeleted( Toplevel* c ) @@ -260,6 +290,8 @@ void EffectsHandler::windowDeleted( Toplevel* c ) mht->windowDeleted( c ); if( sm ) sm->windowDeleted( c ); + if( gm ) + gm->windowDeleted( c ); } EffectsHandler* effects; diff --git a/effects.h b/effects.h index 92bdb91a03..b0e1e9bce2 100644 --- a/effects.h +++ b/effects.h @@ -62,7 +62,6 @@ inline double Matrix::zTranslate() const class EffectData { public: - Matrix matrix; double opacity; }; @@ -73,8 +72,8 @@ class Effect // called when moved/resized or once after it's finished virtual void windowUserMovedResized( Toplevel* c, bool first, bool last ); virtual void windowDeleted( Toplevel* c ); - virtual void transformWindow( Toplevel* c, EffectData& data ); - virtual void transformWorkspace( Workspace*, EffectData& data ); + virtual void transformWindow( Toplevel* c, Matrix& m, EffectData& data ); + virtual void transformWorkspace( Workspace*, Matrix& m, EffectData& data ); }; class EffectsHandler @@ -83,8 +82,8 @@ class EffectsHandler EffectsHandler(); void windowUserMovedResized( Toplevel* c, bool first, bool last ); void windowDeleted( Toplevel* c ); - void transformWindow( Toplevel* c, EffectData& data ); - void transformWorkspace( Workspace*, EffectData& data ); + void transformWindow( Toplevel* c, Matrix& m, EffectData& data ); + void transformWorkspace( Workspace*, Matrix& m, EffectData& data ); }; extern EffectsHandler* effects; @@ -94,7 +93,7 @@ class MakeHalfTransparent { public: virtual void windowUserMovedResized( Toplevel* c, bool first, bool last ); - virtual void transformWindow( Toplevel* c, EffectData& data ); + virtual void transformWindow( Toplevel* c, Matrix& m, EffectData& data ); }; class ShakyMove @@ -104,7 +103,7 @@ class ShakyMove public: ShakyMove(); virtual void windowUserMovedResized( Toplevel* c, bool first, bool last ); - virtual void transformWindow( Toplevel* c, EffectData& data ); + virtual void transformWindow( Toplevel* c, Matrix& m, EffectData& data ); virtual void windowDeleted( Toplevel* c ); private slots: void tick(); @@ -113,6 +112,13 @@ class ShakyMove QTimer timer; }; +class GrowMove + : public Effect + { + public: + virtual void windowUserMovedResized( Toplevel* c, bool first, bool last ); + virtual void transformWindow( Toplevel* c, Matrix& m, EffectData& data ); + }; } // namespace diff --git a/scene.cpp b/scene.cpp index 48f77457e4..2a7d1af24c 100644 --- a/scene.cpp +++ b/scene.cpp @@ -26,11 +26,6 @@ Scene::~Scene() { } -void Scene::setWindows( const ToplevelList& list ) - { - windows = list; - } - void Scene::windowGeometryShapeChanged( Toplevel* ) { } diff --git a/scene.h b/scene.h index c5543ad92b..1f4e3cea6c 100644 --- a/scene.h +++ b/scene.h @@ -23,8 +23,7 @@ class Scene public: Scene( Workspace* ws ); virtual ~Scene(); - void setWindows( const ToplevelList& list ); - virtual void paint( XserverRegion damage ) = 0; + virtual void paint( XserverRegion damage, ToplevelList windows ) = 0; virtual void windowGeometryShapeChanged( Toplevel* ); virtual void windowOpacityChanged( Toplevel* ); virtual void windowDeleted( Toplevel* ); @@ -32,7 +31,6 @@ class Scene virtual void updateTransformation( Toplevel* ); protected: Workspace* wspace; - ToplevelList windows; }; extern Scene* scene; diff --git a/scene_basic.cpp b/scene_basic.cpp index a6ff7ee3a9..9962200ec9 100644 --- a/scene_basic.cpp +++ b/scene_basic.cpp @@ -29,7 +29,7 @@ SceneBasic::~SceneBasic() { } -void SceneBasic::paint( XserverRegion ) +void SceneBasic::paint( XserverRegion, ToplevelList windows ) { Pixmap composite_pixmap = XCreatePixmap( display(), rootWindow(), displayWidth(), displayHeight(), QX11Info::appDepth()); XGCValues val; diff --git a/scene_basic.h b/scene_basic.h index eb39b943b3..2a8a04af4a 100644 --- a/scene_basic.h +++ b/scene_basic.h @@ -22,7 +22,7 @@ class SceneBasic public: SceneBasic( Workspace* ws ); virtual ~SceneBasic(); - virtual void paint( XserverRegion damage ); + virtual void paint( XserverRegion damage, ToplevelList windows ); }; } // namespace diff --git a/scene_xrender.cpp b/scene_xrender.cpp index 7dcbe4221f..bd5b13ea61 100644 --- a/scene_xrender.cpp +++ b/scene_xrender.cpp @@ -42,9 +42,9 @@ SceneXrender::~SceneXrender() (*it).free(); } -void SceneXrender::paint( XserverRegion damage ) +void SceneXrender::paint( XserverRegion damage, ToplevelList windows ) { -#if 0 +#if 1 XRectangle r; r.x = 0; r.y = 0; @@ -54,8 +54,38 @@ void SceneXrender::paint( XserverRegion damage ) #endif // Use the damage region as the clip region for the root window XFixesSetPictureClipRegion( display(), front, 0, 0, damage ); - // Client list for clients that are either translucent or have a shadow - ToplevelList translucents; + // Prepare pass for windows + // Go top to bottom so that clipping is computed properly for phase1 + for( int i = windows.count() - 1; + i >= 0; + --i ) + { + Toplevel* c = windows[ i ]; + resetWindowData( c ); + WindowData& data = window_data[ c ]; + Picture picture = windowPicture( c ); + if( picture == None ) // The render format can be null for GL and/or Xv visuals + { + windows.removeAt( i ); + continue; + } + effects->transformWindow( c, data.matrix, data.effect ); // TODO remove, instead add initWindow() to effects + saveWindowClipRegion( c, damage ); + if( data.simpleTransformation() && isOpaque( c )) + { // is opaque, has simple shape, can be clipped, will be painted using simpler faster method + // Subtract the clients shape from the damage region + XserverRegion shape = windowShape( c ); + assert( shape != None ); + XFixesSubtractRegion( display(), damage, damage, shape ); + data.phase = 1; + } + else + data.phase = 2; // will be painted later bottom to top + } + // Fill any areas of the root window not covered by windows + XFixesSetPictureClipRegion( display(), buffer, 0, 0, damage ); + XRenderColor col = { 0xffff, 0xffff, 0xffff, 0xffff }; + XRenderFillRectangle( display(), PictOpSrc, buffer, &col, 0, 0, displayWidth(), displayHeight()); // 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 = windows.count() - 1; @@ -63,59 +93,50 @@ void SceneXrender::paint( XserverRegion damage ) --i ) { Toplevel* c = windows[ i ]; - checkWindowData( c ); WindowData& data = window_data[ c ]; - effects->transformWindow( c, data.effect ); // TODO remove, instead add initWindow() to effects - if( isOpaque( c )) - { - Picture picture = windowPicture( c ); - XserverRegion shape = windowShape( c ); - if( picture != None && shape != None ) - { - // Set the clip region for the buffer to the damage region, and - // subtract the clients shape from the damage region - XFixesSetPictureClipRegion( display(), buffer, 0, 0, damage ); - const Matrix& matrix = data.effect.matrix; - if( !matrix.isIdentity()) - { - assert( matrix.isOnlyTranslate()); - XFixesTranslateRegion( display(), shape, int( matrix.xTranslate()), int( matrix.yTranslate())); - } - XFixesSubtractRegion( display(), damage, damage, shape ); - XRenderComposite( display(), PictOpSrc, picture, None, buffer, 0, 0, 0, 0, - c->x() + int( matrix.xTranslate()), c->y() + int( matrix.yTranslate()), c->width(), c->height()); - } - } - saveWindowClipRegion( c, damage ); - translucents.prepend( c ); + if( data.phase != 1 ) + continue; + XFixesSetPictureClipRegion( display(), buffer, 0, 0, savedWindowClipRegion( c )); + Picture picture = windowPicture( c ); + XRenderComposite( display(), PictOpSrc, picture, None, buffer, 0, 0, 0, 0, + c->x() + int( data.matrix.xTranslate()), c->y() + int( data.matrix.yTranslate()), c->width(), c->height()); } - // Fill any areas of the root window not covered by windows - XFixesSetPictureClipRegion( display(), buffer, 0, 0, damage ); - XRenderColor col = { 0xffff, 0xffff, 0xffff, 0xffff }; - XRenderFillRectangle( display(), PictOpSrc, buffer, &col, 0, 0, displayWidth(), displayHeight()); - // Now walk the list bottom to top, drawing translucent windows and shadows. - // That we draw bottom to top is important now since we're drawing translucent objects. + // Now walk the list bottom to top, drawing translucent and complicated windows. + // That we draw bottom to top is important now since we're drawing translucent objects + // and also are clipping only by opaque windows. for( int i = 0; - i < translucents.count(); + i < windows.count(); ++i ) { - Toplevel* c = translucents[ i ]; - // Restore the previously saved clip region - XserverRegion r = savedWindowClipRegion( c ); - XFixesSetPictureClipRegion( display(), buffer, 0, 0, r ); - if( !isOpaque( c )) + Toplevel* c = windows[ i ]; + WindowData& data = window_data[ c ]; + if( data.phase != 2 && false) + continue; + XFixesSetPictureClipRegion( display(), buffer, 0, 0, savedWindowClipRegion( c )); + Picture picture = windowPicture( c ); + Picture alpha = windowAlphaMask( c ); + if( data.simpleTransformation()) { - Picture picture = windowPicture( c ); - Picture alpha = windowAlphaMask( c ); - if( picture != None ) - { - const Matrix& matrix = window_data[ c ].effect.matrix; - // TODO clip also using shape? also above? - XRenderComposite( display(), PictOpOver, picture, alpha, buffer, 0, 0, 0, 0, - c->x() + int( matrix.xTranslate()), c->y() + int( matrix.yTranslate()), c->width(), c->height()); - } + XRenderComposite( display(), PictOpOver, picture, alpha, buffer, 0, 0, 0, 0, + c->x() + int( data.matrix.xTranslate()), c->y() + int( data.matrix.yTranslate()), c->width(), c->height()); } - XFixesDestroyRegion( display(), r ); + else + { + // TODO Okay, I'm at loss here. Whoever wants advanced transformations can implement + // it themselves. If not, they actually don't want it that badly *shrug*. +// setPictureMatrix( picture, data.matrix ); + XRenderComposite( display(), PictOpSrc, picture, alpha, buffer, 0, 0, 0, 0, + c->x(), c->y(), c->width(), c->height()); +// setPictureMatrix( picture, Matrix()); + } + } + // cleanup + for( int i = 0; + i < windows.count(); + ++i ) + { + Toplevel* c = windows[ i ]; + cleanup( c ); } // copy composed buffer to the root window XFixesSetPictureClipRegion( display(), buffer, 0, 0, None ); @@ -127,24 +148,33 @@ void SceneXrender::transformWindowDamage( Toplevel* c, XserverRegion r ) const { if( !window_data.contains( c )) return; - const Matrix& matrix = window_data[ c ].effect.matrix; + const Matrix& matrix = window_data[ c ].matrix; if( matrix.isIdentity()) return; - assert( matrix.isOnlyTranslate()); - // TODO the matrix here is not valid after it changes but before it's first painted - // (i.e. a changes to state where it should be translated but the matrix is not yet updated) - XFixesTranslateRegion( display(), r, int( matrix.xTranslate()), int( matrix.yTranslate())); + if( matrix.isOnlyTranslate()) + XFixesTranslateRegion( display(), r, int( matrix.xTranslate()), int( matrix.yTranslate())); + else + { + // The region here should be translated using the matrix, but that's not possible + // (well, maybe fetch the region and transform manually - TODO check). So simply + // mark whole screen as damaged. + XRectangle s; + s.x = s.y = 0; + s.width = displayWidth(); + s.height = displayHeight(); + XFixesSetRegion( display(), r, &s, 1 ); + } } void SceneXrender::updateTransformation( Toplevel* c ) { // TODO maybe only mark as invalid and update on-demand - checkWindowData( c ); + resetWindowData( c ); WindowData& data = window_data[ c ]; - effects->transformWindow( c, data.effect ); + effects->transformWindow( c, data.matrix, data.effect ); } -void SceneXrender::checkWindowData( Toplevel* c ) +void SceneXrender::resetWindowData( Toplevel* c ) { if( !window_data.contains( c )) { @@ -152,7 +182,7 @@ void SceneXrender::checkWindowData( Toplevel* c ) window_data[ c ].format = XRenderFindVisualFormat( display(), c->visual()); } WindowData& data = window_data[ c ]; - data.effect.matrix = Matrix(); + data.matrix = Matrix(); data.effect.opacity = c->opacity(); } @@ -206,11 +236,15 @@ void SceneXrender::saveWindowClipRegion( Toplevel* c, XserverRegion r ) } XserverRegion SceneXrender::savedWindowClipRegion( Toplevel* c ) - { // always called after saveWindowClipRegion(), also resets + { + return window_data[ c ].saved_clip_region; + } + +void SceneXrender::cleanup( Toplevel* c ) + { WindowData& data = window_data[ c ]; - XserverRegion r = data.saved_clip_region; + XFixesDestroyRegion( display(), data.saved_clip_region ); data.saved_clip_region = None; - return r; } bool SceneXrender::isOpaque( Toplevel* c ) const @@ -249,10 +283,11 @@ Picture SceneXrender::windowAlphaMask( Toplevel* c ) return data.alpha; } + XserverRegion SceneXrender::windowShape( Toplevel* c ) { -#if 0 // it probably doesn't make sense to cache this, and perhaps some others - they aren't roundtrips WindowData& data = window_data[ c ]; +#if 0 // it probably doesn't make sense to cache this, and perhaps some others - they aren't roundtrips if( data.shape == None ) { data.shape = XFixesCreateRegionFromWindow( display(), c->handle(), WindowRegionBounding ); @@ -260,8 +295,15 @@ XserverRegion SceneXrender::windowShape( Toplevel* c ) } return data.shape; #else + if( !data.simpleTransformation()) + { + // The region here should be translated using the matrix, but that's not possible + // (well, maybe fetch the region and transform manually - TODO check). + return None; + } XserverRegion shape = XFixesCreateRegionFromWindow( display(), c->handle(), WindowRegionBounding ); - XFixesTranslateRegion( display(), shape, c->x(), c->y()); + XFixesTranslateRegion( display(), shape, + c->x() + int( data.matrix.xTranslate()), c->y() + int( data.matrix.yTranslate())); return shape; #endif } @@ -281,19 +323,28 @@ void SceneXrender::setPictureMatrix( Picture pic, const Matrix& m ) { if( pic == None ) return; +#if 0 XTransform t; // ignore z axis - t.matrix[ 0 ][ 0 ] = XDoubleToFixed( m.m[ 0 ][ 0 ] ); + t.matrix[ 0 ][ 0 ] = XDoubleToFixed( 1 / m.m[ 0 ][ 0 ] ); t.matrix[ 0 ][ 1 ] = XDoubleToFixed( m.m[ 0 ][ 1 ] ); t.matrix[ 0 ][ 2 ] = -XDoubleToFixed( m.m[ 0 ][ 3 ] ); // translation seems to be inverted t.matrix[ 1 ][ 0 ] = XDoubleToFixed( m.m[ 1 ][ 0 ] ); - t.matrix[ 1 ][ 1 ] = XDoubleToFixed( m.m[ 1 ][ 1 ] ); + t.matrix[ 1 ][ 1 ] = XDoubleToFixed( 1 / m.m[ 1 ][ 1 ] ); t.matrix[ 1 ][ 2 ] = -XDoubleToFixed( m.m[ 1 ][ 3 ] ); t.matrix[ 2 ][ 0 ] = XDoubleToFixed( m.m[ 3 ][ 0 ] ); t.matrix[ 2 ][ 1 ] = XDoubleToFixed( m.m[ 3 ][ 1 ] ); t.matrix[ 2 ][ 2 ] = XDoubleToFixed( m.m[ 3 ][ 3 ] ); + // and scaling seems to be wrong too + // or maybe I just don't get it, but anyway, for now + if( m.m[ 3 ][ 3 ] != 1 ) + { + t.matrix[ 0 ][ 0 ] = XDoubleToFixed( 1 / m.m[ 0 ][ 0 ] * m.m[ 3 ][ 3 ] ); + t.matrix[ 1 ][ 1 ] = XDoubleToFixed( 1 / m.m[ 1 ][ 1 ] * m.m[ 3 ][ 3 ] ); + t.matrix[ 2 ][ 2 ] = XDoubleToFixed( 1 ); + } XRenderSetPictureTransform( display(), pic, &t ); - if( t.matrix[ 0 ][ 0 ] != XDoubleToFixed( 1 ) // fast filter for identity or translation + if( t.matrix[ 0 ][ 0 ] != XDoubleToFixed( 1 ) || t.matrix[ 1 ][ 1 ] != XDoubleToFixed( 1 ) || t.matrix[ 2 ][ 2 ] != XDoubleToFixed( 1 ) || t.matrix[ 0 ][ 1 ] != XDoubleToFixed( 0 ) @@ -301,10 +352,11 @@ void SceneXrender::setPictureMatrix( Picture pic, const Matrix& m ) { XRenderSetPictureFilter( display(), pic, const_cast< char* >( FilterGood ), 0, 0 ); } - else + else // fast filter for identity or translation { XRenderSetPictureFilter( display(), pic, const_cast< char* >( FilterFast ), 0, 0 ); } +#endif } SceneXrender::WindowData::WindowData() @@ -326,5 +378,10 @@ void SceneXrender::WindowData::free() XRenderFreePicture( display(), shape ); } +bool SceneXrender::WindowData::simpleTransformation() const + { + return ( matrix.isIdentity() || matrix.isOnlyTranslate()); + } + } // namespace #endif diff --git a/scene_xrender.h b/scene_xrender.h index cd64f7264c..33b2cdb68c 100644 --- a/scene_xrender.h +++ b/scene_xrender.h @@ -30,7 +30,7 @@ class SceneXrender public: SceneXrender( Workspace* ws ); virtual ~SceneXrender(); - virtual void paint( XserverRegion damage ); + virtual void paint( XserverRegion damage, ToplevelList windows ); virtual void windowGeometryShapeChanged( Toplevel* ); virtual void windowOpacityChanged( Toplevel* ); virtual void windowDeleted( Toplevel* ); @@ -38,7 +38,7 @@ class SceneXrender virtual void updateTransformation( Toplevel* ); private: void createBuffer(); - void checkWindowData( Toplevel* c ); + void resetWindowData( Toplevel* c ); Picture windowPicture( Toplevel* c ); void saveWindowClipRegion( Toplevel* c, XserverRegion r ); XserverRegion savedWindowClipRegion( Toplevel* c ); @@ -46,6 +46,7 @@ class SceneXrender Picture windowAlphaMask( Toplevel* c ); XserverRegion windowShape( Toplevel* c ); static void setPictureMatrix( Picture pic, const Matrix& m ); + void cleanup( Toplevel* c ); XRenderPictFormat* format; Picture front; Picture buffer; @@ -53,13 +54,16 @@ class SceneXrender { WindowData(); void free(); + bool simpleTransformation() const; Picture picture; XRenderPictFormat* format; XserverRegion saved_clip_region; Picture alpha; double alpha_cached_opacity; XserverRegion shape; + Matrix matrix; EffectData effect; + int phase; }; QMap< Toplevel*, WindowData > window_data; };