Configurable effects loading by Cedric Borgese.

svn path=/branches/work/kwin_composite/; revision=630276
icc-effect-5.14.5
Luboš Luňák 2007-02-04 22:19:17 +00:00
parent 35206efd25
commit 00136f014f
21 changed files with 211 additions and 86 deletions

View File

@ -118,7 +118,7 @@ void Workspace::setupCompositing()
kDebug( 1212 ) << "XRender compositing" << endl;
else if( dynamic_cast< SceneBasic* >( scene ))
kDebug( 1212 ) << "X compositing" << endl;
new EffectsHandler( this ); // sets also the 'effects' pointer
new EffectsHandler(); // sets also the 'effects' pointer
addDamageFull();
foreach( Client* c, clients )
c->setupCompositing();

View File

@ -13,6 +13,7 @@ License. See the file "COPYING" for the exact licensing terms.
#include "toplevel.h"
#include "client.h"
#include "scene.h"
#include "options.h"
#include "effects/desktopchangeslide.h"
#include "effects/dialogparent.h"
@ -112,85 +113,95 @@ void Effect::postPaintWindow( EffectWindow* w )
// EffectsHandler
//****************************************
EffectsHandler::EffectsHandler( Workspace* ws )
EffectsHandler::EffectsHandler()
: current_paint_window( 0 )
, current_paint_screen( 0 )
{
if( !compositing())
return;
KWinInternal::effects = this;
effects.append( new ShowFpsEffect( ws ));
// effects.append( new ZoomEffect( ws ));
// effects.append( new PresentWindowsEffect( ws ));
// effects.append( new WavyWindowsEffect( ws ));
// effects.append( new MinimizeAnimationEffect( ws ));
// effects.append( new HowtoEffect );
// effects.append( new MakeTransparentEffect );
// effects.append( new ShakyMoveEffect );
// effects.append( new ShiftWorkspaceUpEffect( ws ));
// effects.append( new FadeInEffect );
effects.append( new FadeOutEffect );
// effects.append( new ScaleInEffect );
// effects.append( new DialogParentEffect );
// effects.append( new DesktopChangeSlideEffect );
// effects.append( new TestInputEffect );
registerEffect("ShowFps", new GenericEffectFactory<ShowFpsEffect>);
registerEffect("Zoom", new GenericEffectFactory<ZoomEffect>);
registerEffect("PresentWindows", new GenericEffectFactory<PresentWindowsEffect>);
registerEffect("WavyWindows", new GenericEffectFactory<WavyWindowsEffect>);
registerEffect("MinimizeAnimation", new GenericEffectFactory<MinimizeAnimationEffect>);
registerEffect("Howto", new GenericEffectFactory<HowtoEffect>);
registerEffect("MakeTransparent", new GenericEffectFactory<MakeTransparentEffect>);
registerEffect("ShakyMove", new GenericEffectFactory<ShakyMoveEffect>);
registerEffect("ShiftWorkspaceUp", new GenericEffectFactory<ShiftWorkspaceUpEffect>);
registerEffect("FadeIn", new GenericEffectFactory<FadeInEffect>);
registerEffect("FadeOut", new GenericEffectFactory<FadeOutEffect>);
registerEffect("ScaleIn", new GenericEffectFactory<ScaleInEffect>);
registerEffect("DialogParent", new GenericEffectFactory<DialogParentEffect>);
registerEffect("TestInput", new GenericEffectFactory<TestInputEffect>);
QStringList::const_iterator effectsIterator;
for( effectsIterator = options->defaultEffects.constBegin();
effectsIterator != options->defaultEffects.constEnd();
++effectsIterator)
{
loadEffect(*effectsIterator);
}
}
EffectsHandler::~EffectsHandler()
{
foreach( Effect* e, effects )
delete e;
foreach( EffectPair ep, loaded_effects )
delete ep.second;
foreach( EffectFactory* ef, effect_factories )
delete ef;
foreach( InputWindowPair pos, input_windows )
XDestroyWindow( display(), pos.second );
}
void EffectsHandler::windowUserMovedResized( EffectWindow* c, bool first, bool last )
{
foreach( Effect* e, effects )
e->windowUserMovedResized( c, first, last );
foreach( EffectPair ep, loaded_effects )
ep.second->windowUserMovedResized( c, first, last );
}
void EffectsHandler::windowAdded( EffectWindow* c )
{
foreach( Effect* e, effects )
e->windowAdded( c );
foreach( EffectPair ep, loaded_effects )
ep.second->windowAdded( c );
}
void EffectsHandler::windowDeleted( EffectWindow* c )
{
foreach( Effect* e, effects )
e->windowDeleted( c );
foreach( EffectPair ep, loaded_effects )
ep.second->windowDeleted( c );
}
void EffectsHandler::windowClosed( EffectWindow* c )
{
foreach( Effect* e, effects )
e->windowClosed( c );
foreach( EffectPair ep, loaded_effects )
ep.second->windowClosed( c );
}
void EffectsHandler::windowActivated( EffectWindow* c )
{
foreach( Effect* e, effects )
e->windowActivated( c );
foreach( EffectPair ep, loaded_effects )
ep.second->windowActivated( c );
}
void EffectsHandler::windowMinimized( EffectWindow* c )
{
foreach( Effect* e, effects )
e->windowMinimized( c );
foreach( EffectPair ep, loaded_effects )
ep.second->windowMinimized( c );
}
void EffectsHandler::windowUnminimized( EffectWindow* c )
{
foreach( Effect* e, effects )
e->windowUnminimized( c );
foreach( EffectPair ep, loaded_effects )
ep.second->windowUnminimized( c );
}
void EffectsHandler::desktopChanged( int old )
{
foreach( Effect* e, effects )
e->desktopChanged( old );
foreach( EffectPair ep, loaded_effects )
ep.second->desktopChanged( old );
}
// start another painting pass
@ -203,9 +214,9 @@ void EffectsHandler::startPaint()
// the idea is that effects call this function again which calls the next one
void EffectsHandler::prePaintScreen( int* mask, QRegion* region, int time )
{
if( current_paint_screen < effects.size())
if( current_paint_screen < loaded_effects.size())
{
effects[ current_paint_screen++ ]->prePaintScreen( mask, region, time );
loaded_effects[current_paint_screen++].second->prePaintScreen( mask, region, time );
--current_paint_screen;
}
// no special final code
@ -213,9 +224,9 @@ void EffectsHandler::prePaintScreen( int* mask, QRegion* region, int time )
void EffectsHandler::paintScreen( int mask, QRegion region, ScreenPaintData& data )
{
if( current_paint_screen < effects.size())
if( current_paint_screen < loaded_effects.size())
{
effects[ current_paint_screen++ ]->paintScreen( mask, region, data );
loaded_effects[current_paint_screen++].second->paintScreen( mask, region, data );
--current_paint_screen;
}
else
@ -224,9 +235,9 @@ void EffectsHandler::paintScreen( int mask, QRegion region, ScreenPaintData& dat
void EffectsHandler::postPaintScreen()
{
if( current_paint_screen < effects.size())
if( current_paint_screen < loaded_effects.size())
{
effects[ current_paint_screen++ ]->postPaintScreen();
loaded_effects[current_paint_screen++].second->postPaintScreen();
--current_paint_screen;
}
// no special final code
@ -234,9 +245,9 @@ void EffectsHandler::postPaintScreen()
void EffectsHandler::prePaintWindow( EffectWindow* w, int* mask, QRegion* region, int time )
{
if( current_paint_window < effects.size())
if( current_paint_window < loaded_effects.size())
{
effects[ current_paint_window++ ]->prePaintWindow( w, mask, region, time );
loaded_effects[current_paint_window++].second->prePaintWindow( w, mask, region, time );
--current_paint_window;
}
// no special final code
@ -244,9 +255,9 @@ void EffectsHandler::prePaintWindow( EffectWindow* w, int* mask, QRegion* region
void EffectsHandler::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
{
if( current_paint_window < effects.size())
if( current_paint_window < loaded_effects.size())
{
effects[ current_paint_window++ ]->paintWindow( w, mask, region, data );
loaded_effects[current_paint_window++].second->paintWindow( w, mask, region, data );
--current_paint_window;
}
else
@ -255,9 +266,9 @@ void EffectsHandler::paintWindow( EffectWindow* w, int mask, QRegion region, Win
void EffectsHandler::postPaintWindow( EffectWindow* w )
{
if( current_paint_window < effects.size())
if( current_paint_window < loaded_effects.size())
{
effects[ current_paint_window++ ]->postPaintWindow( w );
loaded_effects[current_paint_window++].second->postPaintWindow( w );
--current_paint_window;
}
// no special final code
@ -351,6 +362,69 @@ void EffectsHandler::activateWindow( EffectWindow* c )
Workspace::self()->activateClient( cl, true );
}
void EffectsHandler::registerEffect( const QString& name, EffectFactory* factory )
{
QMap<QString, EffectFactory*>::const_iterator factories_iterator = effect_factories.find(name);
if( factories_iterator != effect_factories.end() )
{
kDebug( 1212 ) << "EffectsHandler::registerEffect : Effect name already registered : " << name << endl;
}
else
{
kDebug( 1212 ) << "EffectsHandler::registerEffect : Register effect : " << name << endl;
effect_factories[name] = factory;
}
}
void EffectsHandler::loadEffect( const QString& name )
{
assert( current_paint_screen == 0 );
assert( current_paint_window == 0 );
for(QVector< EffectPair >::const_iterator it = loaded_effects.constBegin(); it != loaded_effects.constEnd(); it++)
{
if( (*it).first == name )
{
kDebug( 1212 ) << "EffectsHandler::loadEffect : Effect already loaded : " << name << endl;
return;
}
}
QMap<QString, EffectFactory*>::const_iterator factories_iterator = effect_factories.find(name);
if( factories_iterator != effect_factories.end() )
{
kDebug( 1212 ) << "EffectsHandler::loadEffect : Loading effect : " << name << endl;
loaded_effects.append( EffectPair( name, factories_iterator.value()->create() ) );
}
else
{
kDebug( 1212 ) << "EffectsHandler::loadEffect : Unknown effect : " << name << endl;
}
}
void EffectsHandler::unloadEffect( const QString& name )
{
assert( current_paint_screen == 0 );
assert( current_paint_window == 0 );
for( QVector< EffectPair >::iterator it = loaded_effects.begin(); it != loaded_effects.end(); it++)
{
if ( (*it).first == name )
{
kDebug( 1212 ) << "EffectsHandler::unloadEffect : Unloading Effect : " << name << endl;
delete (*it).second;
loaded_effects.erase(it);
return;
}
}
kDebug( 1212 ) << "EffectsHandler::unloadEffect : Effect not loaded : " << name << endl;
}
EffectFactory::~EffectFactory()
{
}
int EffectsHandler::currentDesktop() const
{
return Workspace::self()->currentDesktop();

View File

@ -87,12 +87,35 @@ class Effect
{
return x * (1 - a) + y * a;
}
protected:
Workspace* workspace() const;
};
class EffectFactory
{
public:
// only here to avoid warnings
virtual ~EffectFactory();
virtual Effect* create() const = 0;
};
template <class EFFECT>
class GenericEffectFactory : public EffectFactory
{
virtual Effect* create() const
{
return new EFFECT();
}
};
class EffectsHandler
{
friend class Effect;
public:
EffectsHandler( Workspace* ws );
EffectsHandler();
~EffectsHandler();
// for use by effects
void prePaintScreen( int* mask, QRegion* region, int time );
@ -123,10 +146,16 @@ class EffectsHandler
bool checkInputWindowEvent( XEvent* e );
void checkInputWindowStacking();
void desktopChanged( int old );
void registerEffect( const QString& name, EffectFactory* factory );
void loadEffect( const QString& name );
void unloadEffect( const QString& name );
private:
QVector< Effect* > effects;
typedef QPair< QString, Effect* > EffectPair;
QVector< EffectPair > loaded_effects;
typedef QPair< Effect*, Window > InputWindowPair;
QList< InputWindowPair > input_windows;
QMap< QString, EffectFactory* > effect_factories;
int current_paint_window;
int current_paint_screen;
};
@ -225,6 +254,12 @@ EffectWindow* effectWindow( Scene::Window* w )
return ret;
}
inline
Workspace* Effect::workspace() const
{
return Workspace::self();
}
} // namespace
#endif

View File

@ -21,9 +21,8 @@ License. See the file "COPYING" for the exact licensing terms.
namespace KWinInternal
{
MinimizeAnimationEffect::MinimizeAnimationEffect( Workspace* ws ) : Effect()
MinimizeAnimationEffect::MinimizeAnimationEffect()
{
mWorkspace = ws;
mActiveAnimations = 0;
}
@ -101,7 +100,7 @@ void MinimizeAnimationEffect::postPaintScreen()
{
if( mActiveAnimations > 0 )
// Damage the workspace so that everything would be repainted next time
mWorkspace->addDamageFull();
workspace()->addDamageFull();
// Call the next effect.
effects->postPaintScreen();

View File

@ -25,7 +25,7 @@ class MinimizeAnimationEffect
: public Effect
{
public:
MinimizeAnimationEffect( Workspace* ws );
MinimizeAnimationEffect();
virtual void prePaintScreen( int* mask, QRegion* region, int time );
virtual void prePaintWindow( EffectWindow* w, int* mask, QRegion* region, int time );
@ -36,7 +36,6 @@ class MinimizeAnimationEffect
virtual void windowUnminimized( EffectWindow* c );
private:
Workspace* mWorkspace;
QMap< EffectWindow*, float > mAnimationProgress;
int mActiveAnimations;
};

View File

@ -29,9 +29,8 @@ namespace KWinInternal
{
PresentWindowsEffect::PresentWindowsEffect(Workspace* ws) : Effect()
PresentWindowsEffect::PresentWindowsEffect()
{
mWorkspace = ws;
mActivated = false;
mActiveness = 0.0;
@ -108,7 +107,7 @@ void PresentWindowsEffect::postPaintScreen()
// If mActiveness is between 0 and 1, the effect is still in progress and the
// workspace has to be repainted during the next pass
if( mActiveness > 0.0 && mActiveness < 1.0 )
mWorkspace->addDamageFull(); // trigger next animation repaint
workspace()->addDamageFull(); // trigger next animation repaint
// Call the next effect.
effects->postPaintScreen();
@ -173,7 +172,7 @@ void PresentWindowsEffect::rearrangeWindows()
mWindowData.clear();
const ClientList& originalclientlist = mWorkspace->stackingOrder();
const ClientList& originalclientlist = workspace()->stackingOrder();
// Filter out special windows such as panels and taskbars
ClientList clientlist;
foreach( Client* client, originalclientlist )
@ -191,7 +190,7 @@ void PresentWindowsEffect::rearrangeWindows()
calculateWindowTransformationsKompose( clientlist );
// Schedule entire desktop to be repainted
mWorkspace->addDamageFull();
workspace()->addDamageFull();
}
void PresentWindowsEffect::calculateWindowTransformationsDumb(ClientList clientlist)
@ -200,7 +199,7 @@ void PresentWindowsEffect::calculateWindowTransformationsDumb(ClientList clientl
int rows = clientlist.count() / 4 + 1;
int cols = clientlist.count() / rows + clientlist.count() % rows;
// Get rect which we can use on current desktop. This excludes e.g. panels
QRect placementRect = mWorkspace->clientArea( PlacementArea, QPoint( 0, 0 ), 0 );
QRect placementRect = workspace()->clientArea( PlacementArea, QPoint( 0, 0 ), 0 );
// Size of one cell
int cellwidth = placementRect.width() / cols;
int cellheight = placementRect.height() / rows;
@ -245,7 +244,7 @@ int PresentWindowsEffect::clientHeightForWidth(Client* c, int w)
void PresentWindowsEffect::calculateWindowTransformationsKompose(ClientList clientlist)
{
// Get rect which we can use on current desktop. This excludes e.g. panels
QRect availRect = mWorkspace->clientArea( PlacementArea, QPoint( 0, 0 ), 0 );
QRect availRect = workspace()->clientArea( PlacementArea, QPoint( 0, 0 ), 0 );
// Following code is taken from Kompose 0.5.4, src/komposelayout.cpp

View File

@ -27,7 +27,7 @@ class PresentWindowsEffect
{
Q_OBJECT
public:
PresentWindowsEffect(Workspace* ws);
PresentWindowsEffect();
virtual void prePaintScreen( int* mask, QRegion* region, int time );
@ -65,7 +65,6 @@ class PresentWindowsEffect
// 0 = not active, 1 = fully active
float mActiveness;
Workspace* mWorkspace;
Window mInput;
struct WindowData

View File

@ -15,10 +15,9 @@ License. See the file "COPYING" for the exact licensing terms.
namespace KWinInternal
{
ShiftWorkspaceUpEffect::ShiftWorkspaceUpEffect( Workspace* ws )
ShiftWorkspaceUpEffect::ShiftWorkspaceUpEffect()
: up( false )
, diff( 0 )
, wspace( ws )
{
connect( &timer, SIGNAL( timeout()), SLOT( tick()));
timer.start( 2000 );
@ -45,14 +44,14 @@ void ShiftWorkspaceUpEffect::paintScreen( int mask, QRegion region, ScreenPaintD
void ShiftWorkspaceUpEffect::postPaintScreen()
{
if( up ? diff < 1000 : diff > 0 )
wspace->addDamageFull(); // trigger next animation repaint
workspace()->addDamageFull(); // trigger next animation repaint
effects->postPaintScreen();
}
void ShiftWorkspaceUpEffect::tick()
{
up = !up;
wspace->addDamageFull();
workspace()->addDamageFull();
}
} // namespace

View File

@ -25,7 +25,7 @@ class ShiftWorkspaceUpEffect
{
Q_OBJECT
public:
ShiftWorkspaceUpEffect( Workspace* ws );
ShiftWorkspaceUpEffect();
virtual void prePaintScreen( int* mask, QRegion* region, int time );
virtual void paintScreen( int mask, QRegion region, ScreenPaintData& data );
virtual void postPaintScreen();
@ -35,7 +35,6 @@ class ShiftWorkspaceUpEffect
QTimer timer;
bool up;
int diff;
Workspace* wspace;
};
} // namespace

View File

@ -24,9 +24,8 @@ namespace KWinInternal
const int FPS_WIDTH = 10;
const int MAX_TIME = 100;
ShowFpsEffect::ShowFpsEffect( Workspace* ws )
: wspace( ws )
, paints_pos( 0 )
ShowFpsEffect::ShowFpsEffect()
: paints_pos( 0 )
, frames_pos( 0 )
{
for( int i = 0;
@ -217,7 +216,7 @@ void ShowFpsEffect::postPaintScreen()
paints[ paints_pos ] = t.elapsed();
if( ++paints_pos == NUM_PAINTS )
paints_pos = 0;
wspace->addDamage( x, y, FPS_WIDTH + NUM_PAINTS, MAX_TIME );
workspace()->addDamage( x, y, FPS_WIDTH + NUM_PAINTS, MAX_TIME );
}
} // namespace

View File

@ -24,14 +24,13 @@ class ShowFpsEffect
: public Effect
{
public:
ShowFpsEffect( Workspace* ws );
ShowFpsEffect();
virtual void prePaintScreen( int* mask, QRegion* region, int time );
virtual void paintScreen( int mask, QRegion region, ScreenPaintData& data );
virtual void postPaintScreen();
private:
void paintGL( int fps );
void paintX( int fps );
Workspace* wspace;
QTime t;
enum { NUM_PAINTS = 100 }; // remember time needed to paint this many paints
int paints[ NUM_PAINTS ]; // time needed to paint

View File

@ -24,9 +24,8 @@ License. See the file "COPYING" for the exact licensing terms.
namespace KWinInternal
{
WavyWindowsEffect::WavyWindowsEffect( Workspace* ws ) : Effect()
WavyWindowsEffect::WavyWindowsEffect()
{
mWorkspace = ws;
mTimeElapsed = 0.0f;
}
@ -85,7 +84,7 @@ void WavyWindowsEffect::paintWindow( EffectWindow* w, int mask, QRegion region,
void WavyWindowsEffect::postPaintScreen()
{
// Damage the workspace so that everything would be repainted next time
mWorkspace->addDamageFull();
workspace()->addDamageFull();
// Call the next effect.
effects->postPaintScreen();

View File

@ -25,7 +25,7 @@ class WavyWindowsEffect
: public Effect
{
public:
WavyWindowsEffect( Workspace* ws );
WavyWindowsEffect();
virtual void prePaintScreen( int* mask, QRegion* region, int time );
virtual void prePaintWindow( EffectWindow* w, int* mask, QRegion* region, int time );
@ -33,7 +33,6 @@ class WavyWindowsEffect
virtual void postPaintScreen();
private:
Workspace* mWorkspace;
float mTimeElapsed;
};

View File

@ -15,10 +15,9 @@ License. See the file "COPYING" for the exact licensing terms.
namespace KWinInternal
{
ZoomEffect::ZoomEffect( Workspace* ws )
ZoomEffect::ZoomEffect()
: zoom( 1 )
, target_zoom( 2 )
, wspace( ws )
{
}
@ -54,7 +53,7 @@ void ZoomEffect::paintScreen( int mask, QRegion region, ScreenPaintData& data )
void ZoomEffect::postPaintScreen()
{
if( zoom != target_zoom )
wspace->addDamageFull();
workspace()->addDamageFull();
effects->postPaintScreen();
}

View File

@ -22,14 +22,13 @@ class ZoomEffect
: public Effect
{
public:
ZoomEffect( Workspace* ws );
ZoomEffect();
virtual void prePaintScreen( int* mask, QRegion* region, int time );
virtual void paintScreen( int mask, QRegion region, ScreenPaintData& data );
virtual void postPaintScreen();
private:
double zoom;
double target_zoom;
Workspace* wspace;
};
} // namespace

View File

@ -32,6 +32,7 @@ DEALINGS IN THE SOFTWARE.
#include <klibloader.h>
#include <kconfiggroup.h>
#include <assert.h>
#include <kconfig.h>
#include <QDir>
#include <QFile>

View File

@ -208,6 +208,9 @@ unsigned long Options::updateSettings()
glDirect = config->readEntry("GLDirect", true );
glVSync = config->readEntry("GLVSync", true );
config->setGroup( "Effects" );
defaultEffects = config->readEntry( "Load", QStringList() << "ShowFps" << "FadeOut" );
config->setGroup( "EffectShowFps" );
effectShowFpsAlpha = config->readEntry( "Alpha", 0.5 );
effectShowFpsX = config->readEntry( "X", -10000 );

View File

@ -311,6 +311,8 @@ class Options : public KDecorationOptions
bool glDirect;
bool glVSync;
QStringList defaultEffects;
double effectShowFpsAlpha;
int effectShowFpsX;
int effectShowFpsY;

View File

@ -1,7 +1,7 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.kde.KWin">
<interface name="org.kde.KWin">
<method name="cascadeDesktop">
<annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/>
</method>
@ -38,6 +38,11 @@
<method name="nextDesktop"/>
<method name="previousDesktop"/>
<method name="circulateDesktopApplications"/>
<signal name="reloadConfig"/>
<method name="loadEffect">
<arg name="name" type="s" direction="in"/>
</method>
<method name="unloadEffect">
<arg name="name" type="s" direction="in"/>
</method>
</interface>
</node>

View File

@ -19,6 +19,7 @@ License. See the file "COPYING" for the exact licensing terms.
#include "client.h"
#include "workspace.h"
#include "effects.h"
#include <fixx11h.h>
#include <QPushButton>
@ -686,6 +687,18 @@ void Workspace::showWindowMenuAt( unsigned long, int, int )
slotWindowOperations();
}
void Workspace::loadEffect( const QString& name )
{
if( effects )
effects->loadEffect( name );
}
void Workspace::unloadEffect( const QString& name )
{
if( effects )
effects->unloadEffect( name );
}
void Workspace::slotActivateAttentionWindow()
{
if( attention_chain.count() > 0 )

View File

@ -195,6 +195,10 @@ class Workspace : public QObject, public KDecorationDefines
// KDE4 remove me - and it's also in the DCOP interface :(
void showWindowMenuAt( unsigned long id, int x, int y );
void loadEffect( const QString& name );
void unloadEffect( const QString& name );
/**
* Shows the menu operations menu for the client and makes it active if
* it's not already.