diff --git a/effects/CMakeLists.txt b/effects/CMakeLists.txt index 16f8fb733e..b3607839f8 100644 --- a/effects/CMakeLists.txt +++ b/effects/CMakeLists.txt @@ -96,6 +96,7 @@ if(KWIN_HAVE_OPENGL_COMPOSITING) SET(kwin4_effect_builtins_sources ${kwin4_effect_builtins_sources} blur.cpp explosioneffect.cpp + flipswitch.cpp invert.cpp lookingglass.cpp magnifier.cpp @@ -108,6 +109,7 @@ if(KWIN_HAVE_OPENGL_COMPOSITING) install( FILES blur.desktop explosion.desktop + flipswitch.desktop invert.desktop lookingglass.desktop magnifier.desktop @@ -139,6 +141,8 @@ if(KWIN_HAVE_OPENGL_COMPOSITING) data/circle-edgy.png DESTINATION ${DATA_INSTALL_DIR}/kwin ) SET(kwin4_effect_builtins_config_sources ${kwin4_effect_builtins_config_sources} + flipswitch_config.cpp + flipswitch_config.ui invert_config.cpp lookingglass_config.cpp lookingglass_config.ui @@ -152,6 +156,7 @@ if(KWIN_HAVE_OPENGL_COMPOSITING) trackmouse_config.cpp ) install( FILES + flipswitch_config.desktop invert_config.desktop lookingglass_config.desktop magnifier_config.desktop diff --git a/effects/configs_builtins.cpp b/effects/configs_builtins.cpp index 669e2c00d2..36f06d9553 100644 --- a/effects/configs_builtins.cpp +++ b/effects/configs_builtins.cpp @@ -30,6 +30,7 @@ along with this program. If not, see . #include "zoom_config.h" #ifdef KWIN_HAVE_OPENGL_COMPOSITING +#include "flipswitch_config.h" #include "invert_config.h" #include "lookingglass_config.h" #include "mousemark_config.h" @@ -56,6 +57,7 @@ KWIN_EFFECT_CONFIG_FACTORY registerPlugin("zoom"); #define GL_PLUGINS \ + registerPlugin("flipswitch"); \ registerPlugin("invert"); \ registerPlugin("lookingglass"); \ registerPlugin("mousemark"); \ diff --git a/effects/flipswitch.cpp b/effects/flipswitch.cpp new file mode 100644 index 0000000000..8323b64e2f --- /dev/null +++ b/effects/flipswitch.cpp @@ -0,0 +1,510 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + + Copyright (C) 2008 Martin Gräßlin . +*********************************************************************/ +#include "flipswitch.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef KWIN_HAVE_OPENGL_COMPOSITING +#include +#endif + +namespace KWin +{ + +KWIN_EFFECT( flipswitch, FlipSwitchEffect ) + +FlipSwitchEffect::FlipSwitchEffect() + : mActivated( 0 ) + , animateFlip( false ) + , forward( true ) + , start( false ) + , stop( false ) + , addFullRepaint( false ) + , rearrangeWindows( 0 ) + , stopRequested( false ) + , startRequested( false ) + { + KConfigGroup conf = effects->effectConfig( "FlipSwitch" ); + mFlipDuration = conf.readEntry( "FlipDuration", 300 ); + mAnimation = conf.readEntry( "AnimateFlip", true ); + } + +FlipSwitchEffect::~FlipSwitchEffect() + { + } + +void FlipSwitchEffect::prePaintScreen( ScreenPrePaintData& data, int time ) + { + if( mActivated || stopRequested || stop ) + { + data.mask |= Effect::PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS; + } + effects->prePaintScreen(data, time); + } + +void FlipSwitchEffect::paintScreen( int mask, QRegion region, ScreenPaintData& data ) + { + effects->paintScreen( mask, region, data ); + if( mActivated || stopRequested || stop ) + { +#ifdef KWIN_HAVE_OPENGL_COMPOSITING + glMatrixMode( GL_PROJECTION ); + glPushMatrix(); + glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT); + glEnable( GL_DEPTH_TEST ); + glEnable( GL_BLEND ); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + glEnable( GL_POLYGON_SMOOTH ); + glLoadIdentity(); + glFrustum(-QApplication::desktop()->geometry().width()*0.5f, + QApplication::desktop()->geometry().width()*0.5f, + QApplication::desktop()->geometry().height()*0.5f, + -QApplication::desktop()->geometry().height()*0.5f, 10, 50); + + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + float xOffset = QApplication::desktop()->geometry().width()*0.33f; + float zOffset = 10.0; + + // bring the selected window to the back of the list + QList< EffectWindow* > tempList = effects->currentTabBoxWindowList(); + int index = tempList.indexOf( effects->currentTabBoxWindow() ); + QList< EffectWindow* > windowList; + for( int i=index; irearrangeWindows; i-- ) + { + EffectWindow* w = windowList.front(); + windowList.pop_front(); + windowList.append( w ); + } + } + else + { + for( int i=0; ix()-QApplication::desktop()->geometry().width()*0.5f; + float y = -QApplication::desktop()->geometry().height()*1.5f+w->y()+w->height(); + float z = -10.0; + if( w->isMinimized() ) + { + // use icon instead of window + x = w->iconGeometry().x()-QApplication::desktop()->geometry().width()*0.5f; + y = -QApplication::desktop()->geometry().height()*1.5f+w->iconGeometry().y()+w->height(); + } + // Position of the window in the stack + float stackX = -QApplication::desktop()->geometry().width()*0.25f-(xOffset*windowList.count())+xOffset*(i+1); + float stackY = -QApplication::desktop()->geometry().height()*0.5f; + float stackZ = (-1*zOffset*windowList.count()) -12.5+zOffset*(i+1); + + float timeFactor = (float)((float)elapsed/(float)mFlipDuration); + // limit animation to final position + if( timeFactor > 1.0 ) timeFactor = 1.0; + + float animateXOffset; + float animateYOffset; + float animateZOffset; + float rotation; + // if start move to stack, if stop move from stack + if( start ) + { + animateXOffset = x+timeFactor*(stackX-x); + animateYOffset = y+timeFactor*(stackY-y); + animateZOffset = z+timeFactor*(stackZ-z); + rotation = timeFactor*0.25; + } + else if( stop ) + { + animateXOffset = stackX+timeFactor*(x-stackX); + animateYOffset = stackY+timeFactor*(y-stackY); + animateZOffset = stackZ+timeFactor*(z-stackZ); + rotation = 0.25-timeFactor*0.25; + } + + // go to current position and rotate by the time based factor + glTranslatef(animateXOffset, animateYOffset, animateZOffset ); + glRotatef(rotation, 0.0, 1.0, 0.0); + + // top most window has to be painted not drawn. + if( i= mFlipDuration ) + { + if( start ) + { + start = false; + // more animations have to follow? + if( rearrangeWindows != 0 ) + { + animateFlip = true; + animationTime.restart(); + if( rearrangeWindows < 0 ) + { + forward = true; + rearrangeWindows++; + } + else + { + forward = false; + rearrangeWindows--; + } + } + else if( stopRequested ) + { + // no more animations but effect has to stop + stop = true; + stopRequested = false; + animationTime.restart(); + } + } + else if( stop ) + { + stop = false; + if( startRequested ) + { + // tabbox allready referenced again - so restart + start = true; + startRequested = false; + mActivated = true; + animationTime.restart(); + } + else + { + mActivated = false; + // we need one more FullRepaint + addFullRepaint = true; + } + } + } + } + // normal behaviour - no start or stop animation + else + { + glPushMatrix(); + glTranslatef(-QApplication::desktop()->geometry().width()*0.25f-(xOffset*windowList.count()), + -QApplication::desktop()->geometry().height()*0.5f, + (-1*zOffset*windowList.count()) -12.5); + int elapsed = animationTime.elapsed(); + float timeFactor = (float)((float)elapsed/(float)mFlipDuration); + if( animateFlip && windowList.count() > 1 ) + { + if( elapsed <= mFlipDuration) + { + float animateXOffset = timeFactor*xOffset; + float animateZOffset = timeFactor*zOffset; + if( forward ) + { + if( animateXOffset > xOffset ) animateXOffset = xOffset; + if( animateZOffset > zOffset ) animateZOffset = zOffset; + glTranslatef(animateXOffset, 0.0, animateZOffset); + EffectWindow* w = windowList.front(); + windowList.pop_front(); + windowList.append( w ); + } + else + { + animateXOffset = xOffset - animateXOffset; + animateZOffset = zOffset - animateZOffset; + if( animateXOffset < 0.0 ) animateXOffset = 0.0; + if( animateZOffset < 0.0 ) animateZOffset = 0.0; + glTranslatef(animateXOffset, 0.0, animateZOffset); + } + } + else + { + if( rearrangeWindows != 0 ) + { + animateFlip = true; + animationTime.restart(); + if( rearrangeWindows < 0 ) + { + forward = true; + rearrangeWindows++; + timeFactor = 0.0; + } + else + { + forward = false; + rearrangeWindows--; + timeFactor = 1.0; + } + } + else + { + animateFlip = false; + if( stopRequested ) + { + stop = true; + stopRequested = false; + animationTime.restart(); + } + } + } + } + for( int i=0; i 1 ) + { + if( forward ) opacity = opacity - timeFactor*opacity; + else opacity = timeFactor*opacity; + } + paintWindowFlip( windowList[i], false, opacity); + } + glPopMatrix(); + } + glPopMatrix(); + } + glPopAttrib(); + glMatrixMode( GL_PROJECTION ); + glPopMatrix(); + glMatrixMode( GL_MODELVIEW ); + + // caption of selected window + QColor color_frame; + QColor color_text; + color_frame = KColorScheme( QPalette::Active, KColorScheme::Window ).background().color(); + color_frame.setAlphaF( 0.9 ); + color_text = KColorScheme( QPalette::Active, KColorScheme::Window ).foreground().color(); + QFont text_font; + text_font.setBold( true ); + text_font.setPointSize( 20 ); + glPushAttrib( GL_CURRENT_BIT ); + glColor4f( color_frame.redF(), color_frame.greenF(), color_frame.blueF(), color_frame.alphaF()); + QRect frameRect = QRect( QApplication::desktop()->geometry().width()*0.25f, + QApplication::desktop()->geometry().height()*0.9f, + QApplication::desktop()->geometry().width()*0.5f, + QFontMetrics( text_font ).height() * 1.2 ); + renderRoundBoxWithEdge( frameRect ); + effects->paintText( effects->currentTabBoxWindow()->caption(), + frameRect.center(), + frameRect.width() - 100, + color_text, + text_font ); + glPopAttrib(); + // icon of selected window + GLTexture* icon = new GLTexture( effects->currentTabBoxWindow()->icon() ); + icon->bind(); + glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT ); + icon->bind(); + glEnable( GL_BLEND ); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + // icon takes 80 % of the height of the frame. So each 10 % space left on the top and botton + QRect iconRect = QRect( frameRect.x() + frameRect.height()*0.1f, + frameRect.y() + frameRect.height()*0.1f, + frameRect.height()*0.8f, + frameRect.height()*0.8f ); + icon->render( false, region, iconRect); + icon->unbind(); + glPopAttrib(); +#endif + } + } + +void FlipSwitchEffect::postPaintScreen() + { + if( (mActivated && ( animateFlip || start )) || stopRequested || stop ) + { + effects->addRepaintFull(); + } + if( addFullRepaint ) + { + addFullRepaint = false; + effects->addRepaintFull(); + } + effects->postPaintScreen(); + } + +void FlipSwitchEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ) + { + if( mActivated || stopRequested || stop ) + { + if( !( mask & PAINT_WINDOW_TRANSFORMED ) && ( !w->isDesktop() ) ) + { + return; + } + } + effects->paintWindow( w, mask, region, data ); + } + +void FlipSwitchEffect::tabBoxAdded( int mode ) + { + if( !mActivated ) + { + // only for windows mode + if( mode == TabBoxWindowsMode && effects->currentTabBoxWindowList().count() > 0 ) + { + effects->refTabBox(); + selectedWindow = effects->currentTabBoxWindowList().indexOf(effects->currentTabBoxWindow()); + if( !stop && !stopRequested ) + { + mActivated = true; + start = true; + animationTime.restart(); + effects->addRepaintFull(); + } + else + { + // last tabbox effect still running - schedule start effect + startRequested = true; + } + } + } + } +void FlipSwitchEffect::tabBoxClosed() + { + if( mActivated ) + { + // if animation than deactivate after animation + mActivated = false; + effects->unrefTabBox(); + if( mAnimation ) + { + if ( start || animateFlip ) stopRequested = true; + else + { + stop = true; + animationTime.restart(); + effects->addRepaintFull(); + } + } + } + } + +void FlipSwitchEffect::tabBoxUpdated() + { + if( mActivated ) + { + if( mAnimation ) + { + // determine the switch direction + int index = effects->currentTabBoxWindowList().indexOf(effects->currentTabBoxWindow()); + bool direction = false; + if( index > selectedWindow ) + { + if( index == effects->currentTabBoxWindowList().count()-1 && selectedWindow == 0 ) forward = false; + else direction = true; + } + else if( index == 0 && ( selectedWindow == effects->currentTabBoxWindowList().count()-1 ) ) + { + direction = true; + } + else if( index == selectedWindow ) return; // nothing changed + else + { + direction = false; + } + selectedWindow = index; + if( !animateFlip && !start ) + { + forward = direction; + animateFlip = true; + animationTime.restart(); + } + else + { + if( direction ) rearrangeWindows--; + else rearrangeWindows++; + } + } + effects->addRepaintFull(); + } + } + +void FlipSwitchEffect::paintWindowFlip( EffectWindow* w, bool draw, float opacity ) + { + WindowPaintData data( w ); + + int x = 0; + int y = QApplication::desktop()->geometry().height() - w->geometry().height(); + QRect thumbnail; + setPositionTransformations( data, + thumbnail, w, + QRect( x, y, w->geometry().width(), w->geometry().height() ), + Qt::KeepAspectRatio ); + + data.opacity = opacity; + // if paintWindow() is used the window behind the initial selected window is not painted on the stack, + // but painted when it is selected + // if drawWindow() is used the front window does not glide through the monitor during animation + // so use drawWindow() for all windows but the selected and paintWindow() for the selected window + if( draw ) + effects->drawWindow( w, + PAINT_WINDOW_TRANSFORMED, + thumbnail, data ); + else + effects->paintWindow( w, + PAINT_WINDOW_TRANSFORMED, + thumbnail, data ); + } + +} // namespace diff --git a/effects/flipswitch.desktop b/effects/flipswitch.desktop new file mode 100644 index 0000000000..ea4076a892 --- /dev/null +++ b/effects/flipswitch.desktop @@ -0,0 +1,17 @@ +[Desktop Entry] +Name=Flip Switch +Icon=preferences-system-windows-effect-flipswitch +Comment=Alt-tab window switcher flipping through windows on a stack + +Type=Service +X-KDE-ServiceTypes=KWin/Effect +X-KDE-PluginInfo-Author=Martin Gräßlin +X-KDE-PluginInfo-Email=ubuntu@martin-graesslin.com +X-KDE-PluginInfo-Name=kwin4_effect_flipswitch +X-KDE-PluginInfo-Version=0.1.0 +X-KDE-PluginInfo-Category=Window Management +X-KDE-PluginInfo-Depends= +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-EnabledByDefault=false +X-KDE-Library=kwin4_effect_builtins +X-Ordering=50 diff --git a/effects/flipswitch.h b/effects/flipswitch.h new file mode 100644 index 0000000000..b5d77fcd1f --- /dev/null +++ b/effects/flipswitch.h @@ -0,0 +1,63 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + + Copyright (C) 2008 Martin Gräßlin . +*********************************************************************/ + +#ifndef KWIN_FLIPSWITCH_H +#define KWIN_FLIPSWITCH_H + +#include +#include + +namespace KWin +{ + +class FlipSwitchEffect + : public Effect + { + public: + FlipSwitchEffect(); + ~FlipSwitchEffect(); + + virtual void prePaintScreen( ScreenPrePaintData& data, int time ); + virtual void paintScreen( int mask, QRegion region, ScreenPaintData& data ); + virtual void postPaintScreen(); + virtual void paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ); + virtual void tabBoxAdded( int mode ); + virtual void tabBoxClosed(); + virtual void tabBoxUpdated(); + private: + void paintWindowFlip( EffectWindow* w, bool draw = true, float opacity = 0.8 ); + bool mActivated; + bool mAnimation; + int mFlipDuration; + bool animateFlip; + bool forward; + QTime animationTime; + int selectedWindow; + bool start; + bool stop; + bool addFullRepaint; + int rearrangeWindows; + bool stopRequested; + bool startRequested; + }; + +} // namespace + +#endif diff --git a/effects/flipswitch_config.cpp b/effects/flipswitch_config.cpp new file mode 100644 index 0000000000..f9f666c784 --- /dev/null +++ b/effects/flipswitch_config.cpp @@ -0,0 +1,101 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + + Copyright (C) 2008 Martin Gräßlin . +*********************************************************************/ +#include "flipswitch_config.h" +#include + +#include + +#include +#ifndef KDE_USE_FINAL +KWIN_EFFECT_CONFIG_FACTORY +#endif + +namespace KWin +{ + +FlipSwitchEffectConfigForm::FlipSwitchEffectConfigForm(QWidget* parent) : QWidget(parent) +{ + setupUi(this); +} + +FlipSwitchEffectConfig::FlipSwitchEffectConfig(QWidget* parent, const QVariantList& args) : + KCModule(EffectFactory::componentData(), parent, args) + { + m_ui = new FlipSwitchEffectConfigForm(this); + + QGridLayout* layout = new QGridLayout(this); + + layout->addWidget(m_ui, 0, 0); + + connect(m_ui->checkAnimateFlip, SIGNAL(stateChanged(int)), this, SLOT(changed())); + connect(m_ui->spinFlipDuration, SIGNAL(valueChanged(int)), this, SLOT(changed())); + + load(); + } + +FlipSwitchEffectConfig::~FlipSwitchEffectConfig() + { + } + +void FlipSwitchEffectConfig::load() + { + KCModule::load(); + + KConfigGroup conf = EffectsHandler::effectConfig( "FlipSwitch" ); + + int flipDuration = conf.readEntry( "FlipDuration", 300 ); + bool animateFlip = conf.readEntry( "AnimateFlip", true ); + m_ui->spinFlipDuration->setValue( flipDuration ); + if( animateFlip ) + { + m_ui->checkAnimateFlip->setCheckState( Qt::Checked ); + } + else + { + m_ui->checkAnimateFlip->setCheckState( Qt::Unchecked ); + } + + emit changed(false); + } + +void FlipSwitchEffectConfig::save() + { + KConfigGroup conf = EffectsHandler::effectConfig( "FlipSwitch" ); + + conf.writeEntry( "FlipDuration", m_ui->spinFlipDuration->value() ); + conf.writeEntry( "AnimateFlip", m_ui->checkAnimateFlip->checkState() == Qt::Checked ? true : false ); + + conf.sync(); + + emit changed(false); + EffectsHandler::sendReloadMessage( "flipswitch" ); + } + +void FlipSwitchEffectConfig::defaults() + { + m_ui->spinFlipDuration->setValue( 300 ); + m_ui->checkAnimateFlip->setCheckState( Qt::Checked ); + emit changed(true); + } + + +} // namespace + +#include "flipswitch_config.moc" \ No newline at end of file diff --git a/effects/flipswitch_config.desktop b/effects/flipswitch_config.desktop new file mode 100755 index 0000000000..a85138fa7b --- /dev/null +++ b/effects/flipswitch_config.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Type=Service +X-KDE-ServiceTypes=KCModule + +X-KDE-Library=kcm_kwin4_effect_builtins +X-KDE-ParentComponents=kwin4_effect_flipswitch +X-KDE-PluginKeyword=flipswitch + +Name=Flip Switch \ No newline at end of file diff --git a/effects/flipswitch_config.h b/effects/flipswitch_config.h new file mode 100644 index 0000000000..d5656e1bdb --- /dev/null +++ b/effects/flipswitch_config.h @@ -0,0 +1,58 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + + Copyright (C) 2008 Martin Gräßlin . +*********************************************************************/ + +#ifndef KWIN_FLIPSWITCH_CONFIG_H +#define KWIN_FLIPSWITCH_CONFIG_H + +#define KDE3_SUPPORT +#include +#undef KDE3_SUPPORT + +#include "ui_flipswitch_config.h" + +namespace KWin +{ + +class FlipSwitchEffectConfigForm : public QWidget, public Ui::FlipSwitchEffectConfigForm +{ + Q_OBJECT + public: + explicit FlipSwitchEffectConfigForm(QWidget* parent); +}; + +class FlipSwitchEffectConfig : public KCModule + { + Q_OBJECT + public: + explicit FlipSwitchEffectConfig(QWidget* parent = 0, const QVariantList& args = QVariantList()); + ~FlipSwitchEffectConfig(); + + public slots: + virtual void save(); + virtual void load(); + virtual void defaults(); + + private: + FlipSwitchEffectConfigForm* m_ui; + }; + +} // namespace + +#endif \ No newline at end of file diff --git a/effects/flipswitch_config.ui b/effects/flipswitch_config.ui new file mode 100644 index 0000000000..1e04bcf178 --- /dev/null +++ b/effects/flipswitch_config.ui @@ -0,0 +1,60 @@ + + KWin::FlipSwitchEffectConfigForm + + + + 0 + 0 + 400 + 103 + + + + + + + Appearance + + + + + + Animate &Flip + + + + + + + F&lip Animation Duration + + + spinFlipDuration + + + + + + + msec + + + 5000 + + + 750 + + + + + + + + + + checkAnimateFlip + spinFlipDuration + + + +