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; };