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 ); 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 Client::windowType( bool direct, int supported_types ) const
{ {
NET::WindowType wt = info->windowType( supported_types ); NET::WindowType wt = info->windowType( supported_types );
@ -1683,6 +1631,12 @@ NET::WindowType Client::windowType( bool direct, int supported_types ) const
return wt; 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 Sets an appropriate cursor shape for the logical mouse position \a m

View file

@ -67,12 +67,17 @@ class Client
const Group* group() const; const Group* group() const;
Group* group(); Group* group();
void checkGroup( Group* gr = NULL, bool force = false ); 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; const WindowRules* rules() const;
void removeRule( Rules* r ); void removeRule( Rules* r );
void setupWindowRules( bool ignore_temporary ); void setupWindowRules( bool ignore_temporary );
void applyWindowRules(); 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 minSize() const;
QSize maxSize() const; QSize maxSize() const;
@ -158,24 +163,9 @@ class Client
// auxiliary functions, depend on the windowType // auxiliary functions, depend on the windowType
bool wantsTabFocus() const; bool wantsTabFocus() const;
bool wantsInput() 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 isResizable() const;
bool isMovable() const;
bool isCloseable() const; // may be closed by the user (may have a close button) 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) void takeActivity( int flags, bool handled, allowed_t ); // takes ActivityFlags as arg (in utils.h)
@ -283,6 +273,15 @@ class Client
void checkActiveModal(); void checkActiveModal();
bool hasStrut() const; bool hasStrut() const;
bool isMove() const
{
return moveResizeMode && mode == PositionCenter;
}
bool isResize() const
{
return moveResizeMode && mode != PositionCenter;
}
private slots: private slots:
void autoRaise(); void autoRaise();
void shadeHover(); void shadeHover();
@ -411,14 +410,6 @@ class Client
bool move_faked_activity; bool move_faked_activity;
Window move_resize_grab_window; Window move_resize_grab_window;
bool unrestrictedMoveResize; bool unrestrictedMoveResize;
bool isMove() const
{
return moveResizeMode && mode == PositionCenter;
}
bool isResize() const
{
return moveResizeMode && mode != PositionCenter;
}
Position mode; Position mode;
QPoint moveOffset; 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 ) void Workspace::addDamage( int x, int y, int w, int h )
{ {
if( !compositing())
return;
XRectangle r; XRectangle r;
r.x = x; r.x = x;
r.y = y; r.y = y;
@ -104,6 +106,44 @@ 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() void Workspace::compositeTimeout()
{ {
if( damage == None ) if( damage == None )
@ -177,7 +217,7 @@ void Toplevel::damageNotifyEvent( XDamageNotifyEvent* e )
{ {
XserverRegion r = XFixesCreateRegion( display(), &e->area, 1 ); XserverRegion r = XFixesCreateRegion( display(), &e->area, 1 );
XFixesTranslateRegion( display(), r, x(), y()); XFixesTranslateRegion( display(), r, x(), y());
workspace()->addDamage( r, true ); workspace()->addDamage( this, r, true );
} }
#endif #endif

View file

@ -10,6 +10,10 @@ License. See the file "COPYING" for the exact licensing terms.
#include "effects.h" #include "effects.h"
#include "toplevel.h"
#include "client.h"
#include "scene.h"
namespace KWinInternal namespace KWinInternal
{ {
@ -37,6 +41,67 @@ Matrix::Matrix()
m[ 3 ][ 3 ] = 1; 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 // 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 // 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() EffectsHandler::EffectsHandler()
{ {
mht = new MakeHalfTransparent; 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; EffectsHandler* effects;
} // namespace } // namespace
#include "effects.moc"

View file

@ -13,6 +13,9 @@ License. See the file "COPYING" for the exact licensing terms.
#ifndef KWIN_EFFECTS_H #ifndef KWIN_EFFECTS_H
#define KWIN_EFFECTS_H #define KWIN_EFFECTS_H
#include <QMap>
#include <QTimer>
namespace KWinInternal namespace KWinInternal
{ {
@ -23,9 +26,37 @@ class Matrix
{ {
public: public:
Matrix(); 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 ]; 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 class EffectData
{ {
public: public:
@ -37,24 +68,50 @@ class Effect
{ {
public: public:
virtual ~Effect(); virtual ~Effect();
virtual void windowUserMoved( Toplevel* c ); // called when moved/resized or once after it's finished
virtual void windowUserResized( Toplevel* c ); virtual void windowUserMovedResized( Toplevel* c, bool first, bool last );
virtual void paintWindow( Toplevel* c, EffectData& data ); virtual void windowDeleted( Toplevel* c );
virtual void paintWorkspace( Workspace*, EffectData& data ); virtual void transformWindow( Toplevel* c, EffectData& data );
virtual void transformWorkspace( Workspace*, EffectData& data );
}; };
class EffectsHandler class EffectsHandler
{ {
public: public:
EffectsHandler(); EffectsHandler();
void windowUserMoved( Toplevel* c ); void windowUserMovedResized( Toplevel* c, bool first, bool last );
void windowUserResized( Toplevel* c ); void windowDeleted( Toplevel* c );
void paintWindow( Toplevel* c, EffectData& data ); void transformWindow( Toplevel* c, EffectData& data );
void paintWorkspace( Workspace*, EffectData& data ); void transformWorkspace( Workspace*, EffectData& data );
}; };
extern EffectsHandler* effects; 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 } // namespace
#endif #endif

View file

@ -577,7 +577,7 @@ bool Client::windowEvent( XEvent* e )
{ {
if( compositing()) if( compositing())
{ {
workspace()->addDamage( geometry()); workspace()->addDamage( this, geometry());
scene->windowOpacityChanged( this ); scene->windowOpacityChanged( this );
} }
else else
@ -1613,7 +1613,7 @@ bool Unmanaged::windowEvent( XEvent* e )
if( dirty[ NETWinInfo::PROTOCOLS2 ] & NET::WM2Opacity ) if( dirty[ NETWinInfo::PROTOCOLS2 ] & NET::WM2Opacity )
{ {
scene->windowOpacityChanged( this ); scene->windowOpacityChanged( this );
workspace()->addDamage( geometry()); workspace()->addDamage( this, geometry());
} }
switch (e->type) switch (e->type)
{ {
@ -1647,9 +1647,9 @@ void Unmanaged::configureNotifyEvent( XConfigureEvent* e )
{ {
resetWindowPixmap(); resetWindowPixmap();
// add old and new geometry to damage // add old and new geometry to damage
workspace()->addDamage( geometry()); workspace()->addDamage( this, geometry());
geom = QRect( e->x, e->y, e->width, e->height ); 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 )) if( force == NormalGeometrySet && geom == QRect( x, y, w, h ))
return; 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 ); geom = QRect( x, y, w, h );
updateWorkareaDiffs(); updateWorkareaDiffs();
if( postpone_geometry_updates != 0 ) if( postpone_geometry_updates != 0 )
@ -1686,7 +1686,7 @@ void Client::setGeometry( int x, int y, int w, int h, ForceGeometry_t force )
updateWindowRules(); updateWindowRules();
checkMaximizeGeometry(); checkMaximizeGeometry();
resetWindowPixmap(); resetWindowPixmap();
workspace()->addDamage( geometry()); workspace()->addDamage( this, geometry());
} }
void Client::plainResize( int w, int h, ForceGeometry_t force ) 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 )) if( force == NormalGeometrySet && geom.size() == QSize( w, h ))
return; 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 )); geom.setSize( QSize( w, h ));
updateWorkareaDiffs(); updateWorkareaDiffs();
if( postpone_geometry_updates != 0 ) if( postpone_geometry_updates != 0 )
@ -1743,7 +1743,7 @@ void Client::plainResize( int w, int h, ForceGeometry_t force )
updateWindowRules(); updateWindowRules();
checkMaximizeGeometry(); checkMaximizeGeometry();
resetWindowPixmap(); 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 )) if( force == NormalGeometrySet && geom.topLeft() == QPoint( x, y ))
return; 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 )); geom.moveTopLeft( QPoint( x, y ));
updateWorkareaDiffs(); updateWorkareaDiffs();
if( postpone_geometry_updates != 0 ) if( postpone_geometry_updates != 0 )
@ -1765,7 +1765,7 @@ void Client::move( int x, int y, ForceGeometry_t force )
sendSyntheticConfigureNotify(); sendSyntheticConfigureNotify();
updateWindowRules(); updateWindowRules();
checkMaximizeGeometry(); checkMaximizeGeometry();
workspace()->addDamage( geometry()); workspace()->addDamage( this, geometry());
} }
void Client::postponeGeometryUpdates( bool postpone ) void Client::postponeGeometryUpdates( bool postpone )
@ -2265,6 +2265,8 @@ bool Client::startMoveResize()
// not needed anymore? kapp->installEventFilter( eater ); // not needed anymore? kapp->installEventFilter( eater );
} }
Notify::raise( isResize() ? Notify::ResizeStart : Notify::MoveStart ); Notify::raise( isResize() ? Notify::ResizeStart : Notify::MoveStart );
if( effects )
effects->windowUserMovedResized( this, true, false );
return true; return true;
} }
@ -2278,6 +2280,8 @@ void Client::finishMoveResize( bool cancel )
checkMaximizeGeometry(); checkMaximizeGeometry();
// FRAME update(); // FRAME update();
Notify::raise( isResize() ? Notify::ResizeEnd : Notify::MoveEnd ); Notify::raise( isResize() ? Notify::ResizeEnd : Notify::MoveEnd );
if( effects )
effects->windowUserMovedResized( this, false, true );
} }
void Client::leaveMoveResize() void Client::leaveMoveResize()
@ -2541,10 +2545,8 @@ void Client::handleMoveResize( int x, int y, int x_root, int y_root )
} }
if ( isMove() ) if ( isMove() )
workspace()->clientMoved(globalPos, xTime()); workspace()->clientMoved(globalPos, xTime());
if( isMove()) if( effects )
effects->windowUserMoved( this ); effects->windowUserMovedResized( this, false, false );
else
effects->windowUserResized( this );
} }
} // namespace } // namespace

View file

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

View file

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

View file

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

View file

@ -64,19 +64,26 @@ void SceneXrender::paint( XserverRegion damage )
{ {
Toplevel* c = windows[ i ]; Toplevel* c = windows[ i ];
checkWindowData( c ); 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 )) if( isOpaque( c ))
{ {
Picture picture = windowPicture( c ); Picture picture = windowPicture( c );
Picture shape = windowShape( c ); XserverRegion shape = windowShape( c );
if( picture != None && shape != None ) if( picture != None && shape != None )
{ {
// Set the clip region for the buffer to the damage region, and // Set the clip region for the buffer to the damage region, and
// subtract the clients shape from the damage region // subtract the clients shape from the damage region
XFixesSetPictureClipRegion( display(), buffer, 0, 0, damage ); 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 ); XFixesSubtractRegion( display(), damage, damage, shape );
XRenderComposite( display(), PictOpSrc, picture, None, buffer, 0, 0, 0, 0, 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 ); saveWindowClipRegion( c, damage );
@ -102,9 +109,10 @@ void SceneXrender::paint( XserverRegion damage )
Picture alpha = windowAlphaMask( c ); Picture alpha = windowAlphaMask( c );
if( picture != None ) if( picture != None )
{ {
const Matrix& matrix = window_data[ c ].effect.matrix;
// TODO clip also using shape? also above? // TODO clip also using shape? also above?
XRenderComposite( display(), PictOpOver, picture, alpha, buffer, 0, 0, 0, 0, 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 ); XFixesDestroyRegion( display(), r );
@ -115,6 +123,27 @@ void SceneXrender::paint( XserverRegion damage )
XFlush( display()); 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 ) void SceneXrender::checkWindowData( Toplevel* c )
{ {
if( !window_data.contains( c )) if( !window_data.contains( c ))
@ -139,7 +168,7 @@ void SceneXrender::windowGeometryShapeChanged( Toplevel* c )
XRenderFreePicture( display(), data.alpha ); XRenderFreePicture( display(), data.alpha );
data.alpha = None; data.alpha = None;
if( data.shape != None ) if( data.shape != None )
XRenderFreePicture( display(), data.shape ); XFixesDestroyRegion( display(), data.shape );
data.shape = None; data.shape = None;
} }
@ -220,8 +249,9 @@ Picture SceneXrender::windowAlphaMask( Toplevel* c )
return data.alpha; 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 ]; WindowData& data = window_data[ c ];
if( data.shape == None ) if( data.shape == None )
{ {
@ -229,6 +259,11 @@ Picture SceneXrender::windowShape( Toplevel* c )
XFixesTranslateRegion( display(), data.shape, c->x(), c->y()); XFixesTranslateRegion( display(), data.shape, c->x(), c->y());
} }
return data.shape; 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 // TODO handle xrandr changes
@ -242,6 +277,36 @@ void SceneXrender::createBuffer()
XFreePixmap( display(), pixmap ); // The picture owns the pixmap now 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() SceneXrender::WindowData::WindowData()
: picture( None ) : picture( None )
, format( NULL ) , format( NULL )

View file

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

View file

@ -39,6 +39,20 @@ class Toplevel
int y() const; int y() const;
int width() const; int width() const;
int height() 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; Pixmap windowPixmap() const;
Visual* visual() const; Visual* visual() const;
virtual double opacity() const = 0; virtual double opacity() const = 0;
@ -120,6 +134,51 @@ inline Visual* Toplevel::visual() const
return vis; 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 #ifdef NDEBUG
inline inline
kndbgstream& operator<<( kndbgstream& stream, const Toplevel* ) { return stream; } kndbgstream& operator<<( kndbgstream& stream, const Toplevel* ) { return stream; }

View file

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

View file

@ -28,6 +28,7 @@ class Unmanaged
bool windowEvent( XEvent* e ); bool windowEvent( XEvent* e );
void release(); void release();
bool track( Window w ); 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 ); static void deleteUnmanaged( Unmanaged* c, allowed_t );
virtual double opacity() const; virtual double opacity() const;
protected: protected:

View file

@ -315,6 +315,20 @@ bool grabbedXServer()
return server_grab_count > 0; 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 #endif
bool isLocalMachine( const QByteArray& host ) bool isLocalMachine( const QByteArray& host )
@ -381,8 +395,6 @@ void ShortcutDialog::accept()
KShortcutDialog::accept(); KShortcutDialog::accept();
} }
#endif #endif
} // namespace } // namespace
#ifndef KCMRULES #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 // some enums to have more readable code, instead of using bools
enum ForceGeometry_t { NormalGeometrySet, ForceGeometrySet }; 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 // Areas, mostly related to Xinerama
enum clientAreaOption enum clientAreaOption
{ {

View file

@ -286,6 +286,9 @@ class Workspace : public QObject, public KDecorationDefines
void addDamage( const QRect& r ); void addDamage( const QRect& r );
void addDamage( int x, int y, int w, int h ); void addDamage( int x, int y, int w, int h );
void addDamage( XserverRegion r, bool destroy ); 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: public slots:
void refresh(); void refresh();