/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2007 Martin Gräßlin .
*********************************************************************/
#include "snow.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
#include
#endif
namespace KWin
{
KWIN_EFFECT( snow, SnowEffect )
SnowEffect::SnowEffect()
: texture( NULL )
, flakes( NULL )
, active( false)
{
srandom( std::time( NULL ) );
lastFlakeTime = QTime::currentTime();
nextFlakeMillis = 0;
KConfigGroup conf = effects->effectConfig("Snow");
mNumberFlakes = conf.readEntry("Number", 50);
mMinFlakeSize = conf.readEntry("MinFlakes", 10);
mMaxFlakeSize = conf.readEntry("MaxFlakes", 50);
KActionCollection* actionCollection = new KActionCollection( this );
KAction* a = static_cast< KAction* >( actionCollection->addAction( "Snow" ));
a->setText( i18n("Snow" ));
a->setGlobalShortcut( KShortcut( Qt::CTRL + Qt::META + Qt::Key_F12 ));
connect( a, SIGNAL( triggered( bool )), this, SLOT( toggle()));
}
SnowEffect::~SnowEffect()
{
delete texture;
delete flakes;
}
void SnowEffect::prePaintScreen( ScreenPrePaintData& data, int time )
{
if ( active )
{
if (! flakes )
{
flakes = new QList();
lastFlakeTime.start();
}
int count = flakes->count();
for (int i=0; ifirst();
flakes->pop_front();
int size = flake.height();
int y = flake.y();
// if flake has reached bottom, don't push it back
if ( y >= QApplication::desktop()->geometry().bottom() )
{
continue;
}
int speed;
float factor = (float)(size-mMinFlakeSize) / (float)(mMaxFlakeSize-mMinFlakeSize);
if (factor >= 0.5) speed = 2;
else speed = 1;
flake.setY(y + speed);
flake.setHeight(size);
flakes->append(flake);
}
// if number of active snowflakes is smaller than maximum number
// create a random new snowflake
if ( ( lastFlakeTime.elapsed() >= nextFlakeMillis ) && flakes->count() < mNumberFlakes)
{
int size = 0;
while ( size < mMinFlakeSize )
size = random() % mMaxFlakeSize;
QRect flake = QRect( random() % (QApplication::desktop()->geometry().right() - size), -1 * size, size, size );
flakes->append( flake );
// calculation of next time of snowflake
// depends on the time the flow needs to get to the bottom (screen size)
// and the fps
int speed;
float factor = (float)(size-mMinFlakeSize) / (float)(mMaxFlakeSize-mMinFlakeSize);
if (factor >= 0.5) speed = 4;
else speed = 2;
long next = ((1000/(time+5))*(Effect::displayHeight()/speed))/mNumberFlakes;
nextFlakeMillis = next;
lastFlakeTime.restart();
}
}
effects->prePaintScreen( data, time );
}
void SnowEffect::paintScreen( int mask, QRegion region, ScreenPaintData& data )
{
effects->paintScreen( mask, region, data ); // paint normal screen
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
if( active )
{
if(! texture ) loadTexture();
if( texture )
{
glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT );
texture->bind();
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
for (int i=0; icount(); i++)
{
texture->render( region, flakes->at(i));
}
texture->unbind();
glPopAttrib();
}
}
#endif
}
void SnowEffect::postPaintScreen()
{
if( active )
{
effects->addRepaintFull();
}
effects->postPaintScreen();
}
void SnowEffect::toggle()
{
active = !active;
if (!active) flakes->clear();
effects->addRepaintFull();
}
void SnowEffect::loadTexture()
{
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
QString file = KGlobal::dirs()->findResource( "appdata", "snowflake.png" );
if( file.isEmpty())
return;
texture = new GLTexture( file );
#endif
}
} // namespace