diff --git a/COMPOSITE_TODO b/COMPOSITE_TODO index 4633fad8b1..717d85d5f7 100644 --- a/COMPOSITE_TODO +++ b/COMPOSITE_TODO @@ -96,3 +96,8 @@ TODO: to be faster to not short-circuit the texture binding when there's been no damage * confirm and try to find out when to do it and when not + +* SceneXrender::Window::performPaint() doesn't use xScale/yScale + - XRenderSetPictureTransform() should be capable of doing this + - note that the matrix used seems to be weird (it doesn't act like the normal transformation + matrix as far as I can tell) diff --git a/effects.cpp b/effects.cpp index 0b24806b53..0ff89d9942 100644 --- a/effects.cpp +++ b/effects.cpp @@ -57,14 +57,25 @@ void Effect::paintWindow( Scene::Window* w, int mask, QRegion region, WindowPain effects->nextPaintWindow( w, mask, region, data ); } -#if 0 -void MakeHalfTransparent::transformWindow( Toplevel* c, Matrix&, EffectData& data ) +void MakeHalfTransparent::prePaintWindow( Scene::Window* w, int* mask, QRegion* region ) { - if( c->isDialog()) + const Client* c = dynamic_cast< const Client* >( w->window()); + if(( c != NULL && ( c->isMove() || c->isResize())) || w->window()->isDialog()) + { + *mask |= Scene::PAINT_WINDOW_TRANSLUCENT; + *mask &= ~Scene::PAINT_WINDOW_OPAQUE; + } + effects->nextPrePaintWindow( w, mask, region ); + } + +void MakeHalfTransparent::paintWindow( Scene::Window* w, int mask, QRegion region, WindowPaintData& data ) + { + const Client* c = dynamic_cast< const Client* >( w->window()); + if( w->window()->isDialog()) data.opacity *= 0.8; - if( Client* c2 = dynamic_cast< Client* >( c )) - if( c2->isMove() || c2->isResize()) - data.opacity *= 0.5; + if( c->isMove() || c->isResize()) + data.opacity *= 0.5; + effects->nextPaintWindow( w, mask, region, data ); } void MakeHalfTransparent::windowUserMovedResized( Toplevel* c, bool first, bool last ) @@ -81,14 +92,25 @@ 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, Matrix& matrix, EffectData& ) +void ShakyMove::prePaintScreen( int* mask, QRegion* region ) { - if( windows.contains( c )) - { - Matrix m; - m.m[ 0 ][ 3 ] = shaky_diff[ windows[ c ]]; - matrix *= m; - } + if( !windows.isEmpty()) + *mask |= Scene::PAINT_WINDOW_TRANSFORMED; + effects->nextPrePaintScreen( mask, region ); + } + +void ShakyMove::prePaintWindow( Scene::Window* w, int* mask, QRegion* region ) + { + if( windows.contains( w->window())) + *mask |= Scene::PAINT_WINDOW_TRANSFORMED; + effects->nextPrePaintWindow( w, mask, region ); + } + +void ShakyMove::paintWindow( Scene::Window* w, int mask, QRegion region, WindowPaintData& data ) + { + if( windows.contains( w->window())) + data.xTranslate += shaky_diff[ windows[ w->window() ]]; + effects->nextPaintWindow( w, mask, region, data ); } void ShakyMove::windowUserMovedResized( Toplevel* c, bool first, bool last ) @@ -102,8 +124,8 @@ void ShakyMove::windowUserMovedResized( Toplevel* c, bool first, bool last ) else if( last ) { windows.remove( c ); - // TODO just damage whole screen, transformation is involved - c->workspace()->addDamage( c->geometry().adjusted( -3, 7, 0, 0 )); + // just damage whole screen, transformation is involved + c->workspace()->addDamage( 0, 0, displayWidth(), displayHeight()); if( windows.isEmpty()) timer.stop(); } @@ -118,7 +140,7 @@ void ShakyMove::windowDeleted( Toplevel* c ) void ShakyMove::tick() { - for( QMap< Toplevel*, int >::Iterator it = windows.begin(); + for( QMap< const Toplevel*, int >::Iterator it = windows.begin(); it != windows.end(); ++it ) { @@ -126,11 +148,12 @@ void ShakyMove::tick() *it = 0; else ++(*it); - // TODO damage whole screen, transformation is involved - it.key()->workspace()->addDamage( it.key()->geometry().adjusted( -1, 2, 0, 0 )); + // just damage whole screen, transformation is involved + it.key()->workspace()->addDamage( 0, 0, displayWidth(), displayHeight()); } } +#if 0 void GrowMove::transformWindow( Toplevel* c, Matrix& matrix, EffectData& ) { if( Client* c2 = dynamic_cast< Client* >( c )) @@ -191,8 +214,8 @@ EffectsHandler::EffectsHandler( Workspace* ws ) { if( !compositing()) return; -// effects.append( new MakeHalfTransparent ); -// effects.append( new ShakyMove ); + effects.append( new MakeHalfTransparent ); + effects.append( new ShakyMove ); // effects.append( new GrowMove ); // effects.append( new ShiftWorkspaceUp( ws )); } diff --git a/effects.h b/effects.h index efc32c6304..53cbbfc612 100644 --- a/effects.h +++ b/effects.h @@ -84,13 +84,13 @@ class EffectsHandler extern EffectsHandler* effects; -#if 0 class MakeHalfTransparent : public Effect { public: virtual void windowUserMovedResized( Toplevel* c, bool first, bool last ); - virtual void transformWindow( Toplevel* c, Matrix& m, EffectData& data ); + virtual void prePaintWindow( Scene::Window* w, int* mask, QRegion* region ); + virtual void paintWindow( Scene::Window* w, int mask, QRegion region, WindowPaintData& data ); }; class ShakyMove @@ -100,15 +100,18 @@ class ShakyMove public: ShakyMove(); virtual void windowUserMovedResized( Toplevel* c, bool first, bool last ); - virtual void transformWindow( Toplevel* c, Matrix& m, EffectData& data ); + virtual void prePaintScreen( int* mask, QRegion* region ); + virtual void prePaintWindow( Scene::Window* w, int* mask, QRegion* region ); + virtual void paintWindow( Scene::Window* w, int mask, QRegion region, WindowPaintData& data ); virtual void windowDeleted( Toplevel* c ); private slots: void tick(); private: - QMap< Toplevel*, int > windows; + QMap< const Toplevel*, int > windows; QTimer timer; }; +#if 0 class GrowMove : public Effect { diff --git a/scene.cpp b/scene.cpp index bc76ab2bf1..4d4f86813b 100644 --- a/scene.cpp +++ b/scene.cpp @@ -57,21 +57,26 @@ void Scene::WrapperEffect::paintScreen( int mask, QRegion region, ScreenPaintDat // the generic painting code that should eventually handle even // transformations -void Scene::paintGenericScreen( int mask, ScreenPaintData ) +void Scene::paintGenericScreen( int orig_mask, ScreenPaintData ) { paintBackground( infiniteRegion()); foreach( Window* w, stacking_order ) // bottom to top { if( !w->isVisible()) continue; - paintWindow( w, mask | PAINT_WINDOW_OPAQUE | PAINT_WINDOW_TRANSLUCENT, infiniteRegion()); + int mask = orig_mask | ( w->isOpaque() ? PAINT_WINDOW_OPAQUE : PAINT_WINDOW_TRANSLUCENT ); + QRegion damage = infiniteRegion(); + WrapperEffect wrapper; + // preparation step + effects->prePaintWindow( w, &mask, &damage, &wrapper ); + paintWindow( w, mask, damage ); } } // the optimized case without any transformations at all -void Scene::paintSimpleScreen( int mask, QRegion region ) +void Scene::paintSimpleScreen( int orig_mask, QRegion region ) { - assert(( mask & ( PAINT_WINDOW_TRANSFORMED | PAINT_SCREEN_TRANSFORMED + assert(( orig_mask & ( PAINT_WINDOW_TRANSFORMED | PAINT_SCREEN_TRANSFORMED | PAINT_WINDOW_TRANSLUCENT | PAINT_WINDOW_OPAQUE )) == 0 ); QList< Phase2Data > phase2; // Draw each opaque window top to bottom, subtracting the bounding rect of @@ -85,14 +90,19 @@ void Scene::paintSimpleScreen( int mask, QRegion region ) continue; if( region.isEmpty()) // completely clipped continue; - if( !w->isOpaque()) + int mask = orig_mask | ( w->isOpaque() ? PAINT_WINDOW_OPAQUE : PAINT_WINDOW_TRANSLUCENT ); + QRegion damage = region; + WrapperEffect wrapper; + // preparation step + effects->prePaintWindow( w, &mask, &damage, &wrapper ); + if( mask & PAINT_WINDOW_TRANSLUCENT ) + phase2.prepend( Phase2Data( w, region, mask )); + if( mask & PAINT_WINDOW_OPAQUE ) { - phase2.prepend( Phase2Data( w, region )); - continue; + paintWindow( w, mask, region ); + if( ( mask & PAINT_WINDOW_TRANSLUCENT ) == 0 ) // window is not transparent, can clip windows below + region -= w->shape().translated( w->x(), w->y()); } - paintWindow( w, mask | PAINT_WINDOW_OPAQUE, region ); - // window is opaque, clip windows below - region -= w->shape().translated( w->x(), w->y()); } // Fill any areas of the root window not covered by windows paintBackground( region ); @@ -102,7 +112,7 @@ void Scene::paintSimpleScreen( int mask, QRegion region ) foreach( Phase2Data d, phase2 ) { Window* w = d.window; - paintWindow( w, mask | PAINT_WINDOW_TRANSLUCENT, d.region ); + paintWindow( w, d.mask, d.region ); } } @@ -114,7 +124,7 @@ void Scene::WrapperEffect::prePaintWindow( Scene::Window* , int*, QRegion* ) void Scene::paintWindow( Window* w, int mask, QRegion region ) { WindowPaintData data; -// data.opacity = w->opacity(); + data.opacity = w->window()->opacity(); WrapperEffect wrapper; effects->paintWindow( w, mask, region, data, &wrapper ); } @@ -122,7 +132,7 @@ void Scene::paintWindow( Window* w, int mask, QRegion region ) // the function that'll be eventually called by paintWindow() above void Scene::WrapperEffect::paintWindow( Scene::Window* w, int mask, QRegion region, WindowPaintData& data ) { - w->performPaint( region, mask ); + w->performPaint( mask, region, data ); } void Scene::windowGeometryShapeChanged( Toplevel* ) @@ -196,6 +206,7 @@ QRegion Scene::Window::shape() const bool Scene::Window::isVisible() const { + return true; // TODO there may be transformations, so always true for now // TODO mapping state? return !toplevel->geometry() .intersect( QRect( 0, 0, displayWidth(), displayHeight())) diff --git a/scene.h b/scene.h index 14dfdbb6b8..1222b22406 100644 --- a/scene.h +++ b/scene.h @@ -53,9 +53,10 @@ class Scene static QRegion infiniteRegion(); struct Phase2Data { - Phase2Data( Window* w, QRegion r ) : window( w ), region( r ) {} + Phase2Data( Window* w, QRegion r, int m ) : window( w ), region( r ), mask( m ) {} Window* window; QRegion region; + int mask; }; QVector< Window* > stacking_order; Workspace* wspace; @@ -68,11 +69,12 @@ class Scene::Window Window( Toplevel* c ); virtual ~Window(); virtual void free(); // is often copied by value, use manually instead of dtor - virtual void performPaint( QRegion region, int mask ) = 0; + virtual void performPaint( int mask, QRegion region, WindowPaintData data ) = 0; int x() const; int y() const; int width() const; int height() const; + const Toplevel* window() const; bool isVisible() const; bool isOpaque() const; QRegion shape() const; @@ -116,7 +118,13 @@ int Scene::Window::height() const { return toplevel->height(); } - + +inline +const Toplevel* Scene::Window::window() const + { + return toplevel; + } + } // namespace #endif diff --git a/scene_opengl.cpp b/scene_opengl.cpp index 5a1114af07..0dd460f97c 100644 --- a/scene_opengl.cpp +++ b/scene_opengl.cpp @@ -525,18 +525,19 @@ static void quadPaint( int x1, int y1, int x2, int y2, int ty1, int ty2 ) glVertex2i( x1, y2 ); } -void SceneOpenGL::Window::performPaint( QRegion region, int mask ) +void SceneOpenGL::Window::performPaint( int mask, QRegion region, WindowPaintData data ) { + bool opaque = isOpaque() && data.opacity == 1.0; if( mask & ( PAINT_WINDOW_OPAQUE | PAINT_WINDOW_TRANSLUCENT )) {} else if( mask & PAINT_WINDOW_OPAQUE ) { - if( !isOpaque()) + if( !opaque ) return; } else if( mask & PAINT_WINDOW_TRANSLUCENT ) { - if( isOpaque()) + if( opaque ) return; } // paint only requested areas @@ -547,24 +548,32 @@ void SceneOpenGL::Window::performPaint( QRegion region, int mask ) return; bindTexture(); glPushMatrix(); - glTranslatef( x(), y(), 0 ); + int x = toplevel->x(); + int y = toplevel->y(); + if( mask & PAINT_WINDOW_TRANSFORMED ) + { + x += data.xTranslate; + y += data.yTranslate; + glScalef( data.xScale, data.yScale, 1 ); + } + glTranslatef( x, y, 0 ); bool was_blend = glIsEnabled( GL_BLEND ); - if( !isOpaque()) + if( !opaque ) { glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); } - if( toplevel->opacity() != 1.0 ) + if( data.opacity != 1.0 ) { if( toplevel->hasAlpha()) { glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); - glColor4f( toplevel->opacity(), toplevel->opacity(), toplevel->opacity(), - toplevel->opacity()); + glColor4f( data.opacity, data.opacity, data.opacity, + data.opacity); } else { - float constant_alpha[] = { 0, 0, 0, toplevel->opacity() }; + float constant_alpha[] = { 0, 0, 0, data.opacity }; glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE ); glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE ); glTexEnvi( GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE ); @@ -590,7 +599,7 @@ void SceneOpenGL::Window::performPaint( QRegion region, int mask ) } glEnd(); glPopMatrix(); - if( toplevel->opacity() != 1.0 ) + if( data.opacity != 1.0 ) { glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE ); glColor4f( 0, 0, 0, 0 ); diff --git a/scene_opengl.h b/scene_opengl.h index 973713d166..29ce81e7f7 100644 --- a/scene_opengl.h +++ b/scene_opengl.h @@ -57,7 +57,7 @@ class SceneOpenGL::Window public: Window( Toplevel* c ); virtual void free(); - virtual void performPaint( QRegion region, int mask ); + virtual void performPaint( int mask, QRegion region, WindowPaintData data ); void bindTexture(); void discardTexture(); Window() {} // QMap sucks even in Qt4 diff --git a/scene_xrender.cpp b/scene_xrender.cpp index d09c700a95..caefb8e8a7 100644 --- a/scene_xrender.cpp +++ b/scene_xrender.cpp @@ -277,11 +277,11 @@ void SceneXrender::Window::discardAlpha() alpha = None; } -Picture SceneXrender::Window::alphaMask() +Picture SceneXrender::Window::alphaMask( double opacity ) { - if( isOpaque()) + if( isOpaque() && opacity == 1.0 ) return None; - if( alpha != None && alpha_cached_opacity != toplevel->opacity()) + if( alpha != None && alpha_cached_opacity != opacity ) { if( alpha != None ) XRenderFreePicture( display(), alpha ); @@ -289,7 +289,7 @@ Picture SceneXrender::Window::alphaMask() } if( alpha != None ) return alpha; - if( toplevel->opacity() == 1.0 ) + if( opacity == 1.0 ) { // no need to create alpha mask alpha_cached_opacity = 1.0; return None; @@ -301,24 +301,25 @@ Picture SceneXrender::Window::alphaMask() alpha = XRenderCreatePicture( display(), pixmap, format, CPRepeat, &pa ); XFreePixmap( display(), pixmap ); XRenderColor col; - col.alpha = int( toplevel->opacity() * 0xffff ); - alpha_cached_opacity = toplevel->opacity(); + col.alpha = int( opacity * 0xffff ); + alpha_cached_opacity = opacity; XRenderFillRectangle( display(), PictOpSrc, alpha, &col, 0, 0, 1, 1 ); return alpha; } -void SceneXrender::Window::performPaint( QRegion region, int mask ) +void SceneXrender::Window::performPaint( int mask, QRegion region, WindowPaintData data ) { + bool opaque = isOpaque() && data.opacity == 1.0; if( mask & ( PAINT_WINDOW_OPAQUE | PAINT_WINDOW_TRANSLUCENT )) {} else if( mask & PAINT_WINDOW_OPAQUE ) { - if( !isOpaque()) + if( !opaque ) return; } else if( mask & PAINT_WINDOW_TRANSLUCENT ) { - if( isOpaque()) + if( opaque ) return; } if( region != infiniteRegion()) @@ -337,14 +338,20 @@ void SceneXrender::Window::performPaint( QRegion region, int mask ) x += screen_paint.xTranslate; y += screen_paint.yTranslate; } - if( isOpaque()) + if( mask & PAINT_WINDOW_TRANSFORMED ) + { + x += data.xTranslate; + y += data.yTranslate; + } + // TODO xScale,yScale + if( opaque ) { XRenderComposite( display(), PictOpSrc, pic, None, buffer, 0, 0, 0, 0, x, y, toplevel->width(), toplevel->height()); } else { - Picture alpha = alphaMask(); + Picture alpha = alphaMask( data.opacity ); XRenderComposite( display(), PictOpOver, pic, alpha, buffer, 0, 0, 0, 0, x, y, toplevel->width(), toplevel->height()); } diff --git a/scene_xrender.h b/scene_xrender.h index 224e4ef93c..cba290348a 100644 --- a/scene_xrender.h +++ b/scene_xrender.h @@ -54,13 +54,13 @@ class SceneXrender::Window public: Window( Toplevel* c ); virtual void free(); - virtual void performPaint( QRegion region, int mask ); + virtual void performPaint( int mask, QRegion region, WindowPaintData data ); void discardPicture(); void discardAlpha(); Window() {} // QMap sucks even in Qt4 private: Picture picture(); - Picture alphaMask(); + Picture alphaMask( double opacity ); Picture _picture; XRenderPictFormat* format; Picture alpha;