Basic window transformations.
svn path=/branches/work/kwin_composite/; revision=597997
This commit is contained in:
parent
74ab9819de
commit
1d7b94acfc
9 changed files with 130 additions and 64 deletions
|
@ -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)
|
||||
|
|
63
effects.cpp
63
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 ));
|
||||
}
|
||||
|
|
11
effects.h
11
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
|
||||
{
|
||||
|
|
37
scene.cpp
37
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()))
|
||||
|
|
14
scene.h
14
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
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue