Add support for translation and add two "plugins" that

make windows transparent or shake them while moving.


svn path=/branches/work/kwin_composite/; revision=559013
This commit is contained in:
Luboš Luňák 2006-07-06 13:17:44 +00:00
parent 391bb6b28d
commit 0516e1e73b
18 changed files with 498 additions and 136 deletions

View file

@ -1600,58 +1600,6 @@ bool Client::wantsInput() const
return rules()->checkAcceptFocus( input || Ptakefocus );
}
bool Client::isDesktop() const
{
return windowType() == NET::Desktop;
}
bool Client::isDock() const
{
return windowType() == NET::Dock;
}
bool Client::isTopMenu() const
{
return windowType() == NET::TopMenu;
}
bool Client::isMenu() const
{
return windowType() == NET::Menu && !isTopMenu(); // because of backwards comp.
}
bool Client::isToolbar() const
{
return windowType() == NET::Toolbar;
}
bool Client::isSplash() const
{
return windowType() == NET::Splash;
}
bool Client::isUtility() const
{
return windowType() == NET::Utility;
}
bool Client::isDialog() const
{
return windowType() == NET::Dialog;
}
bool Client::isNormalWindow() const
{
return windowType() == NET::Normal;
}
bool Client::isSpecialWindow() const
{
return isDesktop() || isDock() || isSplash() || isTopMenu()
|| isToolbar(); // TODO
}
NET::WindowType Client::windowType( bool direct, int supported_types ) const
{
NET::WindowType wt = info->windowType( supported_types );
@ -1683,6 +1631,12 @@ NET::WindowType Client::windowType( bool direct, int supported_types ) const
return wt;
}
bool Client::isSpecialWindow() const
{
return isDesktop() || isDock() || isSplash() || isTopMenu()
|| isToolbar(); // TODO
}
/*!
Sets an appropriate cursor shape for the logical mouse position \a m

View file

@ -67,12 +67,17 @@ class Client
const Group* group() const;
Group* group();
void checkGroup( Group* gr = NULL, bool force = false );
// prefer isXXX() instead
NET::WindowType windowType( bool direct = false, int supported_types = SUPPORTED_WINDOW_TYPES_MASK ) const;
const WindowRules* rules() const;
void removeRule( Rules* r );
void setupWindowRules( bool ignore_temporary );
void applyWindowRules();
virtual NET::WindowType windowType( bool direct = false, int supported_types = SUPPORTED_WINDOW_TYPES_MASK ) const;
// returns true for "special" windows and false for windows which are "normal"
// (normal=window which has a border, can be moved by the user, can be closed, etc.)
// true for Desktop, Dock, Splash, Override and TopMenu (and Toolbar??? - for now)
// false for Normal, Dialog, Utility and Menu (and Toolbar??? - not yet) TODO
bool isSpecialWindow() const;
bool hasNETSupport() const;
QSize minSize() const;
QSize maxSize() const;
@ -158,24 +163,9 @@ class Client
// auxiliary functions, depend on the windowType
bool wantsTabFocus() const;
bool wantsInput() const;
bool hasNETSupport() const;
bool isMovable() const;
bool isDesktop() const;
bool isDock() const;
bool isToolbar() const;
bool isTopMenu() const;
bool isMenu() const;
bool isNormalWindow() const; // normal as in 'NET::Normal or NET::Unknown non-transient'
bool isDialog() const;
bool isSplash() const;
bool isUtility() const;
// returns true for "special" windows and false for windows which are "normal"
// (normal=window which has a border, can be moved by the user, can be closed, etc.)
// true for Desktop, Dock, Splash, Override and TopMenu (and Toolbar??? - for now)
// false for Normal, Dialog, Utility and Menu (and Toolbar??? - not yet) TODO
bool isSpecialWindow() const;
bool isResizable() const;
bool isMovable() const;
bool isCloseable() const; // may be closed by the user (may have a close button)
void takeActivity( int flags, bool handled, allowed_t ); // takes ActivityFlags as arg (in utils.h)
@ -282,6 +272,15 @@ class Client
void destroyClient();
void checkActiveModal();
bool hasStrut() const;
bool isMove() const
{
return moveResizeMode && mode == PositionCenter;
}
bool isResize() const
{
return moveResizeMode && mode != PositionCenter;
}
private slots:
void autoRaise();
@ -411,14 +410,6 @@ class Client
bool move_faked_activity;
Window move_resize_grab_window;
bool unrestrictedMoveResize;
bool isMove() const
{
return moveResizeMode && mode == PositionCenter;
}
bool isResize() const
{
return moveResizeMode && mode != PositionCenter;
}
Position mode;
QPoint moveOffset;

View file

@ -74,6 +74,8 @@ void Workspace::addDamage( const QRect& r )
void Workspace::addDamage( int x, int y, int w, int h )
{
if( !compositing())
return;
XRectangle r;
r.x = x;
r.y = y;
@ -103,7 +105,45 @@ void Workspace::addDamage( XserverRegion r, bool destroy )
}
}
}
void Workspace::addDamage( Toplevel* c, const QRect& r )
{
addDamage( c, r.x(), r.y(), r.width(), r.height());
}
void Workspace::addDamage( Toplevel* c, int x, int y, int w, int h )
{
if( !compositing())
return;
XRectangle r;
r.x = x;
r.y = y;
r.width = w;
r.height = h;
addDamage( c, XFixesCreateRegion( display(), &r, 1 ), true );
}
void Workspace::addDamage( Toplevel* c, XserverRegion r, bool destroy )
{
if( !compositing())
return;
if( !destroy )
{
XserverRegion r2 = XFixesCreateRegion( display(), NULL, 0 );
XFixesCopyRegion( display(), r2, r );
r = r2;
destroy = true;
}
scene->transformWindowDamage( c, r );
if( damage != None )
{
XFixesUnionRegion( display(), damage, damage, r );
XFixesDestroyRegion( display(), r );
}
else
damage = r;
}
void Workspace::compositeTimeout()
{
if( damage == None )
@ -177,9 +217,9 @@ void Toplevel::damageNotifyEvent( XDamageNotifyEvent* e )
{
XserverRegion r = XFixesCreateRegion( display(), &e->area, 1 );
XFixesTranslateRegion( display(), r, x(), y());
workspace()->addDamage( r, true );
workspace()->addDamage( this, r, true );
}
#endif
} // namespace

View file

@ -10,6 +10,10 @@ License. See the file "COPYING" for the exact licensing terms.
#include "effects.h"
#include "toplevel.h"
#include "client.h"
#include "scene.h"
namespace KWinInternal
{
@ -37,6 +41,67 @@ Matrix::Matrix()
m[ 3 ][ 3 ] = 1;
}
Matrix operator*( const Matrix& m1, const Matrix& m2 )
{
Matrix r;
for( int i = 0;
i < 4;
++i )
for( int j = 0;
j < 4;
++j )
{
double s = 0;
for( int k = 0;
k < 4;
++k )
s += m1.m[ i ][ k ] * m2.m[ k ][ j ];
r.m[ i ][ j ] = s;
}
return r;
}
bool Matrix::isIdentity() const
{
return m[ 0 ][ 0 ] == 1
&& m[ 0 ][ 1 ] == 0
&& m[ 0 ][ 2 ] == 0
&& m[ 0 ][ 3 ] == 0
&& m[ 1 ][ 0 ] == 0
&& m[ 1 ][ 1 ] == 1
&& m[ 1 ][ 2 ] == 0
&& m[ 1 ][ 3 ] == 0
&& m[ 2 ][ 0 ] == 0
&& m[ 2 ][ 1 ] == 0
&& m[ 2 ][ 2 ] == 1
&& m[ 2 ][ 3 ] == 0
&& m[ 3 ][ 0 ] == 0
&& m[ 3 ][ 1 ] == 0
&& m[ 3 ][ 2 ] == 0
&& m[ 3 ][ 3 ] == 1;
}
bool Matrix::isOnlyTranslate() const
{
return m[ 0 ][ 0 ] == 1
&& m[ 0 ][ 1 ] == 0
&& m[ 0 ][ 2 ] == 0
// && m[ 0 ][ 3 ] ==
&& m[ 1 ][ 0 ] == 0
&& m[ 1 ][ 1 ] == 1
&& m[ 1 ][ 2 ] == 0
// && m[ 1 ][ 3 ] ==
&& m[ 2 ][ 0 ] == 0
&& m[ 2 ][ 1 ] == 0
&& m[ 2 ][ 2 ] == 1
// && m[ 2 ][ 3 ] ==
&& m[ 3 ][ 0 ] == 0
&& m[ 3 ][ 1 ] == 0
&& m[ 3 ][ 2 ] == 0
&& m[ 3 ][ 3 ] == 1;
}
//****************************************
// Effect
//****************************************
@ -45,61 +110,142 @@ Effect::~Effect()
{
}
void Effect::windowUserMoved( Toplevel* )
void Effect::windowUserMovedResized( Toplevel* , bool, bool )
{
}
void Effect::windowUserResized( Toplevel* )
void Effect::transformWindow( Toplevel*, EffectData& )
{
}
void Effect::paintWindow( Toplevel*, EffectData& )
void Effect::transformWorkspace( Workspace*, EffectData& )
{
}
void Effect::paintWorkspace( Workspace*, EffectData& )
void Effect::windowDeleted( Toplevel* )
{
}
void MakeHalfTransparent::transformWindow( Toplevel* c, EffectData& data )
{
if( c->isDialog())
data.opacity *= 0.8;
if( Client* c2 = dynamic_cast< Client* >( c ))
if( c2->isMove() || c2->isResize())
data.opacity *= 0.5;
}
void MakeHalfTransparent::windowUserMovedResized( Toplevel* c, bool first, bool last )
{
if( first || last )
c->workspace()->addDamage( c, c->geometry());
}
ShakyMove::ShakyMove()
{
connect( &timer, SIGNAL( timeout()), SLOT( tick()));
}
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 )
{
if( windows.contains( c ))
{
Matrix m;
m.m[ 0 ][ 3 ] = shaky_diff[ windows[ c ]];
data.matrix *= m;
}
}
void ShakyMove::windowUserMovedResized( Toplevel* c, bool first, bool last )
{
if( first )
{
if( windows.isEmpty())
timer.start( 50 );
windows[ c ] = 0;
}
else if( last )
{
windows.remove( c );
scene->updateTransformation( c );
c->workspace()->addDamage( c, c->geometry().adjusted( -3, 7, 0, 0 ));
if( windows.isEmpty())
timer.stop();
}
}
void ShakyMove::windowDeleted( Toplevel* c )
{
windows.remove( c );
if( windows.isEmpty())
timer.stop();
}
void ShakyMove::tick()
{
for( QMap< Toplevel*, int >::Iterator it = windows.begin();
it != windows.end();
++it )
{
if( *it == SHAKY_MAX - 1 )
*it = 0;
else
++(*it);
scene->updateTransformation( it.key());
it.key()->workspace()->addDamage( it.key(), it.key()->geometry().adjusted( -1, 2, 0, 0 ));
}
}
static MakeHalfTransparent* mht;
static ShakyMove* sm;
//****************************************
// EffectsHandler
//****************************************
class MakeHalfTransparent
: public Effect
{
public:
virtual void paintWindow( Toplevel* c, EffectData& data );
};
void MakeHalfTransparent::paintWindow( Toplevel*, EffectData& data )
{
data.opacity *= 0.8;
}
static MakeHalfTransparent* mht;
EffectsHandler::EffectsHandler()
{
mht = new MakeHalfTransparent;
sm = new ShakyMove;
}
void EffectsHandler::windowUserMoved( Toplevel* )
void EffectsHandler::windowUserMovedResized( Toplevel* c, bool first, bool last )
{
if( mht )
mht->windowUserMovedResized( c, first, last );
if( sm )
sm->windowUserMovedResized( c, first, last );
}
void EffectsHandler::windowUserResized( Toplevel* )
void EffectsHandler::transformWindow( Toplevel* c, EffectData& data )
{
if( mht )
mht->transformWindow( c, data );
if( sm )
sm->transformWindow( c, data );
}
void EffectsHandler::paintWindow( Toplevel* c, EffectData& data )
void EffectsHandler::transformWorkspace( Workspace* w, EffectData& data )
{
mht->paintWindow( c, data );
if( mht )
mht->transformWorkspace( w, data );
if( sm )
sm->transformWorkspace( w, data );
}
void EffectsHandler::paintWorkspace( Workspace*, EffectData& )
void EffectsHandler::windowDeleted( Toplevel* c )
{
if( mht )
mht->windowDeleted( c );
if( sm )
sm->windowDeleted( c );
}
EffectsHandler* effects;
} // namespace
#include "effects.moc"

View file

@ -13,6 +13,9 @@ License. See the file "COPYING" for the exact licensing terms.
#ifndef KWIN_EFFECTS_H
#define KWIN_EFFECTS_H
#include <QMap>
#include <QTimer>
namespace KWinInternal
{
@ -23,9 +26,37 @@ class Matrix
{
public:
Matrix();
Matrix& operator*=( const Matrix& m );
bool isOnlyTranslate() const;
bool isIdentity() const;
double xTranslate() const;
double yTranslate() const;
double zTranslate() const;
double m[ 4 ][ 4 ];
};
Matrix operator*( const Matrix& m1, const Matrix& m2 );
inline Matrix& Matrix::operator*=( const Matrix& m )
{
return *this = *this * m;
}
inline double Matrix::xTranslate() const
{
return m[ 0 ][ 3 ];
}
inline double Matrix::yTranslate() const
{
return m[ 1 ][ 3 ];
}
inline double Matrix::zTranslate() const
{
return m[ 2 ][ 3 ];
}
class EffectData
{
public:
@ -37,24 +68,50 @@ class Effect
{
public:
virtual ~Effect();
virtual void windowUserMoved( Toplevel* c );
virtual void windowUserResized( Toplevel* c );
virtual void paintWindow( Toplevel* c, EffectData& data );
virtual void paintWorkspace( Workspace*, EffectData& data );
// 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 );
};
class EffectsHandler
{
public:
EffectsHandler();
void windowUserMoved( Toplevel* c );
void windowUserResized( Toplevel* c );
void paintWindow( Toplevel* c, EffectData& data );
void paintWorkspace( Workspace*, EffectData& data );
void windowUserMovedResized( Toplevel* c, bool first, bool last );
void windowDeleted( Toplevel* c );
void transformWindow( Toplevel* c, EffectData& data );
void transformWorkspace( Workspace*, EffectData& data );
};
extern EffectsHandler* effects;
class MakeHalfTransparent
: public Effect
{
public:
virtual void windowUserMovedResized( Toplevel* c, bool first, bool last );
virtual void transformWindow( Toplevel* c, EffectData& data );
};
class ShakyMove
: public QObject, public Effect
{
Q_OBJECT
public:
ShakyMove();
virtual void windowUserMovedResized( Toplevel* c, bool first, bool last );
virtual void transformWindow( Toplevel* c, EffectData& data );
virtual void windowDeleted( Toplevel* c );
private slots:
void tick();
private:
QMap< Toplevel*, int > windows;
QTimer timer;
};
} // namespace
#endif

View file

@ -577,7 +577,7 @@ bool Client::windowEvent( XEvent* e )
{
if( compositing())
{
workspace()->addDamage( geometry());
workspace()->addDamage( this, geometry());
scene->windowOpacityChanged( this );
}
else
@ -1613,7 +1613,7 @@ bool Unmanaged::windowEvent( XEvent* e )
if( dirty[ NETWinInfo::PROTOCOLS2 ] & NET::WM2Opacity )
{
scene->windowOpacityChanged( this );
workspace()->addDamage( geometry());
workspace()->addDamage( this, geometry());
}
switch (e->type)
{
@ -1647,9 +1647,9 @@ void Unmanaged::configureNotifyEvent( XConfigureEvent* e )
{
resetWindowPixmap();
// add old and new geometry to damage
workspace()->addDamage( geometry());
workspace()->addDamage( this, geometry());
geom = QRect( e->x, e->y, e->width, e->height );
workspace()->addDamage( geometry());
workspace()->addDamage( this, geometry());
}
// ****************************************

View file

@ -1660,7 +1660,7 @@ void Client::setGeometry( int x, int y, int w, int h, ForceGeometry_t force )
}
if( force == NormalGeometrySet && geom == QRect( x, y, w, h ))
return;
workspace()->addDamage( geometry()); // TODO cache the previous real geometry
workspace()->addDamage( this, geometry()); // TODO cache the previous real geometry
geom = QRect( x, y, w, h );
updateWorkareaDiffs();
if( postpone_geometry_updates != 0 )
@ -1686,7 +1686,7 @@ void Client::setGeometry( int x, int y, int w, int h, ForceGeometry_t force )
updateWindowRules();
checkMaximizeGeometry();
resetWindowPixmap();
workspace()->addDamage( geometry());
workspace()->addDamage( this, geometry());
}
void Client::plainResize( int w, int h, ForceGeometry_t force )
@ -1718,7 +1718,7 @@ void Client::plainResize( int w, int h, ForceGeometry_t force )
}
if( force == NormalGeometrySet && geom.size() == QSize( w, h ))
return;
workspace()->addDamage( geometry()); // TODO cache the previous real geometry
workspace()->addDamage( this, geometry()); // TODO cache the previous real geometry
geom.setSize( QSize( w, h ));
updateWorkareaDiffs();
if( postpone_geometry_updates != 0 )
@ -1743,7 +1743,7 @@ void Client::plainResize( int w, int h, ForceGeometry_t force )
updateWindowRules();
checkMaximizeGeometry();
resetWindowPixmap();
workspace()->addDamage( geometry());
workspace()->addDamage( this, geometry());
}
/*!
@ -1753,7 +1753,7 @@ void Client::move( int x, int y, ForceGeometry_t force )
{
if( force == NormalGeometrySet && geom.topLeft() == QPoint( x, y ))
return;
workspace()->addDamage( geometry()); // TODO cache the previous real geometry
workspace()->addDamage( this, geometry()); // TODO cache the previous real geometry
geom.moveTopLeft( QPoint( x, y ));
updateWorkareaDiffs();
if( postpone_geometry_updates != 0 )
@ -1765,7 +1765,7 @@ void Client::move( int x, int y, ForceGeometry_t force )
sendSyntheticConfigureNotify();
updateWindowRules();
checkMaximizeGeometry();
workspace()->addDamage( geometry());
workspace()->addDamage( this, geometry());
}
void Client::postponeGeometryUpdates( bool postpone )
@ -2265,6 +2265,8 @@ bool Client::startMoveResize()
// not needed anymore? kapp->installEventFilter( eater );
}
Notify::raise( isResize() ? Notify::ResizeStart : Notify::MoveStart );
if( effects )
effects->windowUserMovedResized( this, true, false );
return true;
}
@ -2278,6 +2280,8 @@ void Client::finishMoveResize( bool cancel )
checkMaximizeGeometry();
// FRAME update();
Notify::raise( isResize() ? Notify::ResizeEnd : Notify::MoveEnd );
if( effects )
effects->windowUserMovedResized( this, false, true );
}
void Client::leaveMoveResize()
@ -2541,10 +2545,8 @@ void Client::handleMoveResize( int x, int y, int x_root, int y_root )
}
if ( isMove() )
workspace()->clientMoved(globalPos, xTime());
if( isMove())
effects->windowUserMoved( this );
else
effects->windowUserResized( this );
if( effects )
effects->windowUserMovedResized( this, false, false );
}
} // namespace

View file

@ -523,7 +523,7 @@ bool Client::manage( Window w, bool isMapped )
delete session;
if( isMapped ) // otherwise damage will come when the client paints it
workspace()->addDamage( geometry());
workspace()->addDamage( this, geometry());
ungrabXServer();

View file

@ -43,6 +43,14 @@ void Scene::windowDeleted( Toplevel* )
{
}
void Scene::transformWindowDamage( Toplevel*, XserverRegion ) const
{
}
void Scene::updateTransformation( Toplevel* )
{
}
Scene* scene;
} // namespace

View file

@ -28,6 +28,8 @@ class Scene
virtual void windowGeometryShapeChanged( Toplevel* );
virtual void windowOpacityChanged( Toplevel* );
virtual void windowDeleted( Toplevel* );
virtual void transformWindowDamage( Toplevel*, XserverRegion ) const;
virtual void updateTransformation( Toplevel* );
protected:
Workspace* wspace;
ToplevelList windows;

View file

@ -64,19 +64,26 @@ void SceneXrender::paint( XserverRegion damage )
{
Toplevel* c = windows[ i ];
checkWindowData( c );
effects->paintWindow( c, window_data[ c ].effect );
WindowData& data = window_data[ c ];
effects->transformWindow( c, data.effect ); // TODO remove, instead add initWindow() to effects
if( isOpaque( c ))
{
Picture picture = windowPicture( c );
Picture shape = windowShape( 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(), c->y(), c->width(), c->height());
c->x() + int( matrix.xTranslate()), c->y() + int( matrix.yTranslate()), c->width(), c->height());
}
}
saveWindowClipRegion( c, damage );
@ -102,9 +109,10 @@ void SceneXrender::paint( XserverRegion damage )
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(), c->y(), c->width(), c->height());
c->x() + int( matrix.xTranslate()), c->y() + int( matrix.yTranslate()), c->width(), c->height());
}
}
XFixesDestroyRegion( display(), r );
@ -115,6 +123,27 @@ void SceneXrender::paint( XserverRegion damage )
XFlush( display());
}
void SceneXrender::transformWindowDamage( Toplevel* c, XserverRegion r ) const
{
if( !window_data.contains( c ))
return;
const Matrix& matrix = window_data[ c ].effect.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()));
}
void SceneXrender::updateTransformation( Toplevel* c )
{
// TODO maybe only mark as invalid and update on-demand
checkWindowData( c );
WindowData& data = window_data[ c ];
effects->transformWindow( c, data.effect );
}
void SceneXrender::checkWindowData( Toplevel* c )
{
if( !window_data.contains( c ))
@ -139,7 +168,7 @@ void SceneXrender::windowGeometryShapeChanged( Toplevel* c )
XRenderFreePicture( display(), data.alpha );
data.alpha = None;
if( data.shape != None )
XRenderFreePicture( display(), data.shape );
XFixesDestroyRegion( display(), data.shape );
data.shape = None;
}
@ -220,8 +249,9 @@ Picture SceneXrender::windowAlphaMask( Toplevel* c )
return data.alpha;
}
Picture SceneXrender::windowShape( Toplevel* c )
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( data.shape == None )
{
@ -229,6 +259,11 @@ Picture SceneXrender::windowShape( Toplevel* c )
XFixesTranslateRegion( display(), data.shape, c->x(), c->y());
}
return data.shape;
#else
XserverRegion shape = XFixesCreateRegionFromWindow( display(), c->handle(), WindowRegionBounding );
XFixesTranslateRegion( display(), shape, c->x(), c->y());
return shape;
#endif
}
// TODO handle xrandr changes
@ -242,6 +277,36 @@ void SceneXrender::createBuffer()
XFreePixmap( display(), pixmap ); // The picture owns the pixmap now
}
void SceneXrender::setPictureMatrix( Picture pic, const Matrix& m )
{
if( pic == None )
return;
XTransform t;
// ignore z axis
t.matrix[ 0 ][ 0 ] = XDoubleToFixed( 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 ][ 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 ] );
XRenderSetPictureTransform( display(), pic, &t );
if( t.matrix[ 0 ][ 0 ] != XDoubleToFixed( 1 ) // fast filter for identity or translation
|| t.matrix[ 1 ][ 1 ] != XDoubleToFixed( 1 )
|| t.matrix[ 2 ][ 2 ] != XDoubleToFixed( 1 )
|| t.matrix[ 0 ][ 1 ] != XDoubleToFixed( 0 )
|| t.matrix[ 1 ][ 0 ] != XDoubleToFixed( 0 ))
{
XRenderSetPictureFilter( display(), pic, const_cast< char* >( FilterGood ), 0, 0 );
}
else
{
XRenderSetPictureFilter( display(), pic, const_cast< char* >( FilterFast ), 0, 0 );
}
}
SceneXrender::WindowData::WindowData()
: picture( None )
, format( NULL )

View file

@ -34,6 +34,8 @@ class SceneXrender
virtual void windowGeometryShapeChanged( Toplevel* );
virtual void windowOpacityChanged( Toplevel* );
virtual void windowDeleted( Toplevel* );
virtual void transformWindowDamage( Toplevel*, XserverRegion ) const;
virtual void updateTransformation( Toplevel* );
private:
void createBuffer();
void checkWindowData( Toplevel* c );
@ -42,7 +44,8 @@ class SceneXrender
XserverRegion savedWindowClipRegion( Toplevel* c );
bool isOpaque( Toplevel* c ) const;
Picture windowAlphaMask( Toplevel* c );
Picture windowShape( Toplevel* c );
XserverRegion windowShape( Toplevel* c );
static void setPictureMatrix( Picture pic, const Matrix& m );
XRenderPictFormat* format;
Picture front;
Picture buffer;

View file

@ -39,6 +39,20 @@ class Toplevel
int y() const;
int width() const;
int height() const;
// prefer isXXX() instead
virtual NET::WindowType windowType( bool direct = false, int supported_types = SUPPORTED_WINDOW_TYPES_MASK ) const = 0;
bool hasNETSupport() const;
bool isDesktop() const;
bool isDock() const;
bool isToolbar() const;
bool isTopMenu() const;
bool isMenu() const;
bool isNormalWindow() const; // normal as in 'NET::Normal or NET::Unknown non-transient'
bool isDialog() const;
bool isSplash() const;
bool isUtility() const;
Pixmap windowPixmap() const;
Visual* visual() const;
virtual double opacity() const = 0;
@ -120,6 +134,51 @@ inline Visual* Toplevel::visual() const
return vis;
}
inline bool Toplevel::isDesktop() const
{
return windowType() == NET::Desktop;
}
inline bool Toplevel::isDock() const
{
return windowType() == NET::Dock;
}
inline bool Toplevel::isTopMenu() const
{
return windowType() == NET::TopMenu;
}
inline bool Toplevel::isMenu() const
{
return windowType() == NET::Menu && !isTopMenu(); // because of backwards comp.
}
inline bool Toplevel::isToolbar() const
{
return windowType() == NET::Toolbar;
}
inline bool Toplevel::isSplash() const
{
return windowType() == NET::Splash;
}
inline bool Toplevel::isUtility() const
{
return windowType() == NET::Utility;
}
inline bool Toplevel::isDialog() const
{
return windowType() == NET::Dialog;
}
inline bool Toplevel::isNormalWindow() const
{
return windowType() == NET::Normal;
}
#ifdef NDEBUG
inline
kndbgstream& operator<<( kndbgstream& stream, const Toplevel* ) { return stream; }

View file

@ -47,7 +47,7 @@ bool Unmanaged::track( Window w )
setupCompositing();
resetWindowPixmap();
workspace()->addDamage( geometry());
workspace()->addDamage( this, geometry());
return true;
}
@ -63,6 +63,11 @@ void Unmanaged::deleteUnmanaged( Unmanaged* c, allowed_t )
delete c;
}
NET::WindowType Unmanaged::windowType( bool, int supported_types ) const
{
return info->windowType( supported_types );
}
double Unmanaged::opacity() const
{
if( info->opacity() == 0xffffffff )

View file

@ -28,6 +28,7 @@ class Unmanaged
bool windowEvent( XEvent* e );
void release();
bool track( Window w );
virtual NET::WindowType windowType( bool direct = false, int supported_types = SUPPORTED_WINDOW_TYPES_MASK ) const;
static void deleteUnmanaged( Unmanaged* c, allowed_t );
virtual double opacity() const;
protected:

View file

@ -315,6 +315,20 @@ bool grabbedXServer()
return server_grab_count > 0;
}
kdbgstream& operator<<( kdbgstream& stream, RegionDebug r )
{
if( r.rr == None )
return stream << "EMPTY";
int num;
XRectangle* rects = XFixesFetchRegion( display(), r.rr, &num );
if( rects == NULL || num == 0 )
return stream << "EMPTY";
for( int i = 0;
i < num;
++i )
stream << "[" << rects[ i ].x << "+" << rects[ i ].y << " " << rects[ i ].width << "x" << rects[ i ].height << "]";
return stream;
}
#endif
bool isLocalMachine( const QByteArray& host )
@ -381,8 +395,6 @@ void ShortcutDialog::accept()
KShortcutDialog::accept();
}
#endif
} // namespace
#ifndef KCMRULES

14
utils.h
View file

@ -120,6 +120,20 @@ enum allowed_t { Allowed };
// some enums to have more readable code, instead of using bools
enum ForceGeometry_t { NormalGeometrySet, ForceGeometrySet };
struct RegionDebug
{
RegionDebug( XserverRegion r ) : rr( r ) {}
XserverRegion rr;
};
#ifdef NDEBUG
inline
kndbgstream& operator<<( kndbgstream& stream, RegionDebug ) { return stream; }
#else
kdbgstream& operator<<( kdbgstream& stream, RegionDebug r );
#endif
// Areas, mostly related to Xinerama
enum clientAreaOption
{

View file

@ -286,6 +286,9 @@ class Workspace : public QObject, public KDecorationDefines
void addDamage( const QRect& r );
void addDamage( int x, int y, int w, int h );
void addDamage( XserverRegion r, bool destroy );
void addDamage( Toplevel* c, const QRect& r );
void addDamage( Toplevel* c, int x, int y, int w, int h );
void addDamage( Toplevel* c, XserverRegion r, bool destroy );
public slots:
void refresh();