diff --git a/effects/CMakeLists.txt b/effects/CMakeLists.txt
index cd9bdeed6e..ffc94f2ac7 100644
--- a/effects/CMakeLists.txt
+++ b/effects/CMakeLists.txt
@@ -95,6 +95,7 @@ if(KWIN_HAVE_OPENGL_COMPOSITING)
# opengl-based effects
SET(kwin4_effect_builtins_sources ${kwin4_effect_builtins_sources}
blur.cpp
+ coverswitch.cpp
explosioneffect.cpp
flipswitch.cpp
invert.cpp
@@ -108,6 +109,7 @@ if(KWIN_HAVE_OPENGL_COMPOSITING)
)
install( FILES
blur.desktop
+ coverswitch.desktop
explosion.desktop
flipswitch.desktop
invert.desktop
@@ -141,6 +143,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}
+ coverswitch_config.cpp
+ coverswitch_config.ui
flipswitch_config.cpp
flipswitch_config.ui
invert_config.cpp
@@ -156,6 +160,7 @@ if(KWIN_HAVE_OPENGL_COMPOSITING)
trackmouse_config.cpp
)
install( FILES
+ coverswitch_config.desktop
flipswitch_config.desktop
invert_config.desktop
lookingglass_config.desktop
diff --git a/effects/configs_builtins.cpp b/effects/configs_builtins.cpp
index 09cb832a06..c2116d3ca3 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 "coverswitch_config.h"
#include "flipswitch_config.h"
#include "invert_config.h"
#include "lookingglass_config.h"
@@ -58,6 +59,7 @@ KWIN_EFFECT_CONFIG_FACTORY
registerPlugin("zoom");
#define GL_PLUGINS \
+ registerPlugin("coverswitch"); \
registerPlugin("flipswitch"); \
registerPlugin("invert"); \
registerPlugin("lookingglass"); \
diff --git a/effects/coverswitch.cpp b/effects/coverswitch.cpp
new file mode 100644
index 0000000000..a4643f6b72
--- /dev/null
+++ b/effects/coverswitch.cpp
@@ -0,0 +1,818 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+ Copyright (C) 2008 Martin Gräßlin .
+*********************************************************************/
+#include "coverswitch.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+
+#include
+
+#include
+
+namespace KWin
+{
+
+KWIN_EFFECT( coverswitch, CoverSwitchEffect )
+
+CoverSwitchEffect::CoverSwitchEffect()
+ : mActivated( 0 )
+ , angle( 60.0 )
+ , animation( false )
+ , start( false )
+ , stop( false )
+ , forward( true )
+ , rearrangeWindows( 0 )
+ , slowMotionMode( false )
+ , stopRequested( false )
+ , startRequested( false )
+ {
+ KConfigGroup conf = effects->effectConfig( "CoverSwitch" );
+ animationDuration = conf.readEntry( "Duration", 300 );
+ animateSwitch = conf.readEntry( "AnimateSwitch", true );
+ animateStart = conf.readEntry( "AnimateStart", true );
+ animateStop = conf.readEntry( "AnimateStop", true );
+ reflection = conf.readEntry( "Reflection", true );
+ slowMotionFactor = conf.readEntry( "SlowMotionFactor", 4 );
+
+ KActionCollection* actionCollection = new KActionCollection( this );
+ KAction* a = static_cast< KAction* >( actionCollection->addAction( "SlowMotion" ));
+ a->setText( i18n( "Slow Motion" ));
+ a->setGlobalShortcut( KShortcut( Qt::META + Qt::Key_S ));
+ connect( a, SIGNAL( triggered( bool )), this, SLOT( slowMotion()));
+ }
+
+CoverSwitchEffect::~CoverSwitchEffect()
+ {
+ }
+
+void CoverSwitchEffect::prePaintScreen( ScreenPrePaintData& data, int time )
+ {
+ if( mActivated || stop || stopRequested )
+ {
+ data.mask |= Effect::PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS;
+ }
+ effects->prePaintScreen(data, time);
+ }
+
+void CoverSwitchEffect::paintScreen( int mask, QRegion region, ScreenPaintData& data )
+ {
+ effects->paintScreen( mask, region, data );
+ if( mActivated || stop || stopRequested )
+ {
+ glMatrixMode( GL_PROJECTION );
+ glPushMatrix();
+ glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT );
+ glEnable( GL_DEPTH_TEST );
+ 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();
+ glPushMatrix();
+ glTranslatef(-QApplication::desktop()->geometry().width()*0.5f,
+ -QApplication::desktop()->geometry().height()*0.5f,
+ -7.5);
+
+ QList< EffectWindow* > tempList = effects->currentTabBoxWindowList();
+ int index = tempList.indexOf( effects->currentTabBoxWindow() );
+ if( animation || start || stop )
+ {
+ if( !start && !stop )
+ {
+ if( forward )
+ index--;
+ else
+ index++;
+ }
+ index += rearrangeWindows;
+ if( index < 0 )
+ index = tempList.count() + index;
+ if( index >= tempList.count() )
+ index = index % tempList.count();
+ }
+ int rightIndex = index -1;
+ if( rightIndex < 0 )
+ rightIndex = tempList.count() -1;
+ int leftIndex = index +1;
+ if( leftIndex == tempList.count() )
+ leftIndex = 0;
+
+ EffectWindow* frontWindow = tempList[ index ];
+ QList< EffectWindow* > leftWindows;
+ QList< EffectWindow* > rightWindows;
+
+ bool evenWindows = ( tempList.count() % 2 == 0 ) ? true : false;
+ int leftWindowCount = 0;
+ if( evenWindows )
+ leftWindowCount = tempList.count()/2;
+ else
+ leftWindowCount = ( tempList.count() - 1 )/2;
+ for( int i=0; i < leftWindowCount; i++ )
+ {
+ int tempIndex = ( leftIndex + i ) % tempList.count();
+ leftWindows.prepend( tempList[ tempIndex ] );
+ }
+ int rightWindowCount = 0;
+ if( evenWindows )
+ rightWindowCount = tempList.count()/2 - 1;
+ else
+ rightWindowCount = ( tempList.count() - 1 )/2;
+ for( int i=0; i < rightWindowCount; i++ )
+ {
+ int tempIndex = ( rightIndex - i );
+ if( tempIndex < 0 )
+ tempIndex = tempList.count() + tempIndex;
+ rightWindows.prepend( tempList[ tempIndex ] );
+ }
+
+ // time since last animation
+ int elapsed = 0;
+ float timeFactor = 0.0;
+ if( animation || start || stop )
+ {
+ elapsed = animationTime.elapsed();
+ timeFactor = (float)((float)elapsed/(float)animationDuration);
+ if( timeFactor >= 1.0 )
+ timeFactor = 1.0;
+ }
+
+ if( reflection )
+ {
+ // no reflections during start and stop animation
+ if( !start && !stop )
+ paintScene( frontWindow, &leftWindows, &rightWindows, timeFactor, true );
+ glEnable( GL_BLEND );
+ glBlendFunc( GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA );
+ glPolygonMode( GL_FRONT, GL_FILL );
+ glBegin( GL_POLYGON );
+ float alpha = 0.9;
+ if( start )
+ alpha = 0.9 * timeFactor;
+ else if( stop )
+ alpha = 0.9 - 0.9 * timeFactor;
+ glColor4f( 0.3, 0.3, 0.3, alpha );
+ glVertex3f( 0.0, QApplication::desktop()->geometry().height(), 0.0 );
+ glVertex3f( QApplication::desktop()->geometry().width(), QApplication::desktop()->geometry().height(), 0.0 );
+ alpha = 1.0;
+ if( start )
+ alpha = timeFactor;
+ else if( stop )
+ alpha = 1.0 - timeFactor;
+ glColor4f( 0.19, 0.19, 0.19, alpha );
+ glVertex3f( QApplication::desktop()->geometry().width() * 5, QApplication::desktop()->geometry().height(), -60 );
+ glVertex3f( -QApplication::desktop()->geometry().width() * 4, QApplication::desktop()->geometry().height(), -60 );
+ glEnd();
+ glDisable( GL_BLEND );
+ }
+ paintScene( frontWindow, &leftWindows, &rightWindows, timeFactor );
+
+ 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();
+ if( start )
+ {
+ color_frame.setAlphaF( 0.9 * timeFactor );
+ color_text.setAlphaF( timeFactor );
+ }
+ else if( stop )
+ {
+ color_frame.setAlphaF( 0.9 - 0.9 * timeFactor );
+ color_text.setAlphaF( 1.0 - timeFactor );
+ }
+ 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.2f );
+ renderRoundBoxWithEdge( frameRect );
+ effects->paintText( effects->currentTabBoxWindow()->caption(),
+ frameRect.center(),
+ frameRect.width() - 100,
+ color_text,
+ text_font );
+ glPopAttrib();
+ // icon of selected window
+ QPixmap iconPixmap = effects->currentTabBoxWindow()->icon();
+ if( start || stop )
+ {
+ int alpha = 255.0f * timeFactor;
+ if( stop )
+ {
+ alpha = 255.0f - alpha;
+ }
+ QPixmap transparency = iconPixmap.copy( iconPixmap.rect() );
+ transparency.fill( QColor( 255, 255, 255, alpha ) );
+ iconPixmap.setAlphaChannel( transparency.alphaChannel() );
+ }
+ GLTexture* icon = new GLTexture( iconPixmap );
+ 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();
+ glDisable( GL_BLEND );
+ glPopAttrib();
+ }
+ }
+
+void CoverSwitchEffect::postPaintScreen()
+ {
+ if( ( mActivated && ( animation || start ) ) || stop || stopRequested )
+ {
+ if( animationTime.elapsed() >= animationDuration )
+ {
+ if( stop )
+ {
+ stop = false;
+ if( startRequested )
+ {
+ startRequested = false;
+ mActivated = true;
+ effects->refTabBox();
+ selectedWindow = effects->currentTabBoxWindowList().indexOf(effects->currentTabBoxWindow());
+ if( animateStart )
+ {
+ start = true;
+ animationTime.restart();
+ }
+ }
+ }
+ else if( rearrangeWindows != 0 )
+ {
+ if( rearrangeWindows < 0 )
+ rearrangeWindows++;
+ else
+ rearrangeWindows--;
+ animationTime.restart();
+ if( start )
+ {
+ animation = true;
+ start = false;
+ }
+ }
+ else
+ {
+ animation = false;
+ start = false;
+ if( stopRequested )
+ {
+ stopRequested = false;
+ stop = true;
+ animationTime.restart();
+ }
+ }
+ }
+ effects->addRepaintFull();
+ }
+ effects->postPaintScreen();
+ }
+
+void CoverSwitchEffect::paintScene( EffectWindow* frontWindow, QList< EffectWindow* >* leftWindows, QList< EffectWindow* >* rightWindows,
+ float timeFactor, bool reflectedWindows )
+ {
+ // LAYOUT
+ // one window in the front. Other windows left and right rotated
+ // for odd number of windows: left: (n-1)/2; front: 1; right: (n-1)/2
+ // for even number of windows: left: n/2; front: 1; right: n/2 -1
+ //
+ // ANIMATION
+ // forward (alt+tab)
+ // all left windows are moved to next position
+ // top most left window is rotated and moved to front window position
+ // front window is rotated and moved to next right window position
+ // right windows are moved to next position
+ // last right window becomes totally transparent in half the time
+ // appears transparent on left side and becomes totally opaque again
+ // backward (alt+shift+tab) same as forward but opposite direction
+ int width = QApplication::desktop()->geometry().width();
+ int height = QApplication::desktop()->geometry().height();
+ int leftWindowCount = leftWindows->count();
+ int rightWindowCount = rightWindows->count();
+
+
+ // Problem during animation: a window which is painted after another window
+ // appears in front of the other
+ // so during animation the painting order has to be rearreanged
+ // paint sequence no animation: left, right, front
+ // paint sequence forward animation: right, front, left
+
+ if( start || stop )
+ {
+ // start or stop animation
+ float radian = angle * timeFactor * ( 2 * M_PI / 360 );
+ if( stop )
+ radian = ( angle - angle * timeFactor ) * ( 2 * M_PI / 360 );
+ int x, y;
+ // left windows
+ for( int i=0; i< leftWindowCount; i++ )
+ {
+ EffectWindow* window = leftWindows->at( i );
+ x = window->x();
+ y = window->y();
+ if( window->isMinimized() )
+ {
+ // use icon instead of window
+ x = window->iconGeometry().x();
+ y = window->iconGeometry().y();
+ }
+ glPushMatrix();
+ int windowHeight = window->geometry().height();
+ float distance = -width*0.25f + ( width * 0.25f * i )/leftWindowCount - x;
+ float distanceY = height - windowHeight - y;
+ if( start )
+ glTranslatef( distance*timeFactor + x, distanceY * timeFactor + y, -5 * timeFactor - 2.5);
+ else if( stop )
+ glTranslatef( distance*( 1.0 - timeFactor ) + x, distanceY * ( 1.0 -timeFactor ) + y, -5 * ( 1.0 - timeFactor ) - 2.5);
+ glRotatef( radian, 0.0, 1.0, 0.0 );
+ int windowWidth = window->geometry().width() * cos( radian );
+ QRect windowRect = QRect( 0, 0, windowWidth, windowHeight );
+ paintWindowCover( window, windowRect, reflectedWindows );
+ glPopMatrix();
+ }
+
+ // right windows
+ for( int i=0; i < rightWindowCount; i++ )
+ {
+ EffectWindow* window = rightWindows->at( i );
+ x = window->x();
+ y = window->y();
+ if( window->isMinimized() )
+ {
+ // use icon instead of window
+ x = window->iconGeometry().x();
+ y = window->iconGeometry().y();
+ }
+ glPushMatrix();
+ int windowWidth = window->geometry().width() * cos( radian );
+ int windowHeight = window->geometry().height();
+ float distance = width*1.25f - ( width * 0.25f * i )/rightWindowCount - x - windowWidth;
+ float distanceY = height - windowHeight - y;
+ if( start )
+ glTranslatef( distance*timeFactor + x + windowWidth, distanceY * timeFactor + y, -5 * timeFactor - 2.5);
+ else if( stop )
+ glTranslatef( distance*( 1.0 - timeFactor ) + x + windowWidth, distanceY * ( 1.0 - timeFactor ) + y, -5 * ( 1.0 - timeFactor ) - 2.5);
+ glRotatef( -radian, 0.0, 1.0, 0.0 );
+ QRect windowRect = QRect( -windowWidth, 0, windowWidth, windowHeight );
+ paintWindowCover( window, windowRect, reflectedWindows );
+ glPopMatrix();
+ }
+
+ // front window
+ glPushMatrix();
+ x = frontWindow->x();
+ y = frontWindow->y();
+ if( frontWindow->isMinimized() )
+ {
+ // use icon instead of window
+ x = frontWindow->iconGeometry().x();
+ y = frontWindow->iconGeometry().y();
+ }
+ int windowHeight = frontWindow->geometry().height();
+ float distance = (width - frontWindow->geometry().width())*0.5f - x;
+ float distanceY = height - windowHeight - y;
+ if( start )
+ glTranslatef( distance * timeFactor + x, distanceY * timeFactor + y, -5*timeFactor - 2.5 );
+ else if( stop )
+ glTranslatef( distance * ( 1.0 - timeFactor ) + x, distanceY * ( 1.0 - timeFactor ) + y, -5 * ( 1.0 - timeFactor ) - 2.5 );
+ QRect windowRect = QRect( 0, 0, frontWindow->geometry().width(), windowHeight );
+ paintWindowCover( frontWindow, windowRect, reflectedWindows );
+ glPopMatrix();
+ }
+ else if( !animation )
+ {
+ paintWindows( leftWindows, timeFactor, true, reflectedWindows );
+ paintWindows( rightWindows, timeFactor, false, reflectedWindows );
+ paintFrontWindow( frontWindow, timeFactor, width, leftWindowCount, rightWindowCount, reflectedWindows );
+ }
+ else
+ {
+ if( forward )
+ {
+ if( timeFactor < 0.5 )
+ {
+ // paint in normal way
+ paintWindows( leftWindows, timeFactor, true, reflectedWindows );
+ paintWindows( rightWindows, timeFactor, false, reflectedWindows );
+ paintFrontWindow( frontWindow, timeFactor, width, leftWindowCount, rightWindowCount, reflectedWindows );
+ }
+ else
+ {
+ paintWindows( rightWindows, timeFactor, false, reflectedWindows );
+ EffectWindow* rightWindow;
+ if( rightWindowCount > 0)
+ {
+ rightWindow = rightWindows->at( 0 );
+ paintFrontWindow( frontWindow, timeFactor, width, leftWindowCount, rightWindowCount, reflectedWindows );
+ }
+ else
+ rightWindow = frontWindow;
+ paintWindows( leftWindows, timeFactor, true, reflectedWindows, rightWindow );
+ }
+ }
+ else
+ {
+ paintWindows( leftWindows, timeFactor, true, reflectedWindows );
+ if( timeFactor < 0.5 )
+ {
+ paintWindows( rightWindows, timeFactor, false, reflectedWindows );
+ paintFrontWindow( frontWindow, timeFactor, width, leftWindowCount, rightWindowCount, reflectedWindows );
+ }
+ else
+ {
+ paintFrontWindow( frontWindow, timeFactor, width, leftWindowCount, rightWindowCount, reflectedWindows );
+ paintWindows( rightWindows, timeFactor, false, reflectedWindows, leftWindows->at( 0 ) );
+ }
+ }
+ }
+ }
+
+void CoverSwitchEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
+ {
+ if( mActivated || stop || stopRequested )
+ {
+ if( !( mask & PAINT_WINDOW_TRANSFORMED ) && ( !w->isDesktop() ) )
+ {
+ if( ( start || stop ) && w->isDock() )
+ {
+ int elapsed = animationTime.elapsed();
+ float timeFactor = (float)((float)elapsed/(float)animationDuration);
+ if( timeFactor >= 1.0 )
+ timeFactor = 1.0;
+ data.opacity = 1.0 - timeFactor;
+ if( stop )
+ data.opacity = timeFactor;
+ }
+ else
+ return;
+ }
+ }
+ effects->paintWindow( w, mask, region, data );
+ }
+
+void CoverSwitchEffect::tabBoxAdded( int mode )
+ {
+ if( !mActivated )
+ {
+ // only for windows mode
+ if( mode == TabBoxWindowsMode && effects->currentTabBoxWindowList().count() > 0 )
+ {
+ if( !stop && !stopRequested )
+ {
+ effects->refTabBox();
+ selectedWindow = effects->currentTabBoxWindowList().indexOf(effects->currentTabBoxWindow());
+ mActivated = true;
+ if( animateStart )
+ {
+ start = true;
+ animationTime.restart();
+ }
+ effects->addRepaintFull();
+ }
+ else
+ {
+ startRequested = true;
+ }
+ }
+ }
+ }
+
+void CoverSwitchEffect::tabBoxClosed()
+ {
+ if( mActivated )
+ {
+ if( animateStop )
+ {
+ if( !animation && !start )
+ {
+ stop = true;
+ animationTime.restart();
+ }
+ else
+ {
+ stopRequested = true;
+ }
+ }
+ mActivated = false;
+ effects->unrefTabBox();
+ effects->addRepaintFull();
+ }
+ }
+
+void CoverSwitchEffect::tabBoxUpdated()
+ {
+ if( mActivated )
+ {
+ if( animateSwitch && effects->currentTabBoxWindowList().count() > 1)
+ {
+ // determine the switch direction
+ int index = effects->currentTabBoxWindowList().indexOf(effects->currentTabBoxWindow());
+ bool direction = false;
+ int windowCount = effects->currentTabBoxWindowList().count();
+ if( index > selectedWindow )
+ {
+ if( index == windowCount-1 && selectedWindow == 0 )
+ direction = false;
+ else
+ direction = true;
+ }
+ else if( index == 0 && ( selectedWindow == windowCount-1 ) )
+ {
+ direction = true;
+ }
+ else if( index == selectedWindow )
+ return; // nothing changed
+ else
+ {
+ direction = false;
+ }
+
+ // for two windows direction is always forward
+ if( windowCount == 2 )
+ direction = true;
+ selectedWindow = index;
+ if( !animation && !start )
+ {
+ forward = direction;
+ animation = true;
+ animationTime.restart();
+ }
+ else
+ {
+ if( direction )
+ rearrangeWindows--;
+ else
+ rearrangeWindows++;
+ if( rearrangeWindows >= windowCount )
+ rearrangeWindows = rearrangeWindows % windowCount;
+ else if( (-1*rearrangeWindows) >= windowCount )
+ rearrangeWindows = -1*((-1*rearrangeWindows) % windowCount);
+ }
+ }
+ effects->addRepaintFull();
+ }
+ }
+
+void CoverSwitchEffect::paintWindowCover( EffectWindow* w, QRect windowRect, bool reflectedWindow, float opacity )
+ {
+ WindowPaintData data( w );
+
+ data.opacity = opacity;
+
+ QRect thumbnail;
+ setPositionTransformations( data,
+ thumbnail, w,
+ windowRect,
+ Qt::IgnoreAspectRatio );
+
+ if( reflectedWindow )
+ {
+ glPushMatrix();
+ glScalef( 1.0, -1.0, 1.0 );
+ glTranslatef( 0.0, - QApplication::desktop()->geometry().height() - windowRect.y() - windowRect.height(), 0.0 );
+ effects->paintWindow( w,
+ PAINT_WINDOW_TRANSFORMED,
+ thumbnail, data );
+ glPopMatrix();
+ }
+ else
+ {
+ effects->paintWindow( w,
+ PAINT_WINDOW_TRANSFORMED,
+ thumbnail, data );
+ }
+ }
+
+void CoverSwitchEffect::paintFrontWindow( EffectWindow* frontWindow, float timeFactor, int width, int leftWindows, int rightWindows, bool reflectedWindow )
+ {
+ glPushMatrix();
+ glTranslatef((width - frontWindow->geometry().width())*0.5f, 0.0, -7.5);
+ int windowWidth = frontWindow->geometry().width();
+ int windowHeight = frontWindow->geometry().height();;
+ float distance = 0.0;
+ int height = QApplication::desktop()->geometry().height();
+ int x = 0;
+ bool specialHandlingForward = false;
+ if( leftWindows == 0 )
+ leftWindows = 1;
+ if( rightWindows == 0 )
+ {
+ rightWindows = 1;
+ specialHandlingForward = true;
+ }
+ if( animation )
+ {
+ float radian = 0.0;
+ if( specialHandlingForward )
+ timeFactor *= 2;
+ radian = angle * timeFactor * ( 2 * M_PI / 360 );
+ windowWidth = frontWindow->geometry().width() * cos( radian );
+ if( forward )
+ {
+ x = - windowWidth;
+ glTranslatef( frontWindow->geometry().width(), 0.0, 0.0 );
+ // move to right
+ // we are at: (width + frontWindow->geometry().width())*0.5f
+ // we want to: width*1.25 - ( width * 0.25 * (rightWindowCount -1) )/rightWindowCount
+ distance = width*1.25 - ( width * 0.25 * ( rightWindows - 1 ) )/rightWindows -
+ (width + frontWindow->geometry().width())*0.5f;
+ glTranslatef( distance * timeFactor, 0.0, 0.0 );
+ glRotatef(-radian, 0.0, 1.0, 0.0);
+ }
+ else
+ {
+ // move to left
+ // we are at: (width - frontWindow->geometry().width())*0.5f
+ // we want to: -width*0.25 + ( width * 0.25 * leftWindowCount - 1 )/leftWindowCount
+ distance = ( width - frontWindow->geometry().width() ) * 0.5f +
+ width*0.25 - ( width * 0.25 * ( leftWindows - 1 ) )/leftWindows;
+ glTranslatef( - distance * timeFactor, 0.0, 0.0 );
+ glRotatef(radian, 0.0, 1.0, 0.0);
+ }
+ }
+ QRect windowRect = QRect( x, height - windowHeight, windowWidth, windowHeight );
+ if( specialHandlingForward )
+ paintWindowCover( frontWindow, windowRect, reflectedWindow, 1.0 - timeFactor );
+ else
+ paintWindowCover( frontWindow, windowRect, reflectedWindow );
+ glPopMatrix();
+ }
+
+void CoverSwitchEffect::paintWindows( QList< EffectWindow* >* windows, float timeFactor, bool left, bool reflectedWindows, EffectWindow* additionalWindow )
+ {
+ int width = QApplication::desktop()->geometry().width();
+ int height = QApplication::desktop()->geometry().height();
+ float radian = angle * ( 2 * M_PI / 360 );
+ int windowCount = windows->count();
+ int windowWidth = 0;
+ int windowHeight = 0;
+ QRect windowRect;
+ EffectWindow* window;
+
+ int rotateFactor = 1;
+ float widthFactor = -0.25;
+ float widthFactorSingle = 0.25;
+ if( !left )
+ {
+ rotateFactor = -1;
+ widthFactor = 1.25;
+ widthFactorSingle = - 0.25;
+ }
+
+ glPushMatrix();
+ glTranslatef( width*widthFactor, 0.0, -7.5 );
+ // handling for additional window from other side
+ // has to appear on this side after half of the time
+ if( animation && timeFactor >= 0.5 && additionalWindow != NULL )
+ {
+ // window has to appear on left side
+ glPushMatrix();
+ glRotatef( radian * rotateFactor, 0.0, 1.0, 0.0 );
+ windowWidth = additionalWindow->geometry().width() * cos( radian );
+ windowHeight = additionalWindow->geometry().height();
+ int x = 0;
+ if( !left )
+ {
+ x = -windowWidth;
+ }
+ windowRect = QRect( x, height - windowHeight, windowWidth, windowHeight );
+ paintWindowCover( additionalWindow, windowRect, reflectedWindows, ( timeFactor - 0.5 ) * 2 );
+ glPopMatrix();
+ }
+ // normal behaviour
+ for( int i=0; i < windowCount; i++ )
+ {
+ window = windows->at( i );
+ glPushMatrix();
+ glTranslatef( ( width * widthFactorSingle * i )/windowCount, 0.0, 0.0 );
+ if( animation )
+ {
+ if( forward )
+ {
+ if( ( i == windowCount - 1 ) && left )
+ {
+ // right most window on left side -> move to front
+ // we are at: -width*0.25 + ( width * 0.25 * i )/leftWindowCount
+ // we want to: (width - leftWindow->geometry().width())*0.5f
+ float distance = (width - window->geometry().width())*0.5f + width*(-widthFactor) - ( width * widthFactorSingle * i )/windowCount;
+ glTranslatef( distance * timeFactor , 0.0, 0.0 );
+ radian = ( angle - angle * timeFactor ) * ( 2 * M_PI / 360 );
+ }
+ // right most window does not have to be moved
+ else if( !left && ( i == 0 ) ); // do nothing
+ else
+ {
+ // all other windows - move to next position
+ glTranslatef( ( width * 0.25 * timeFactor )/windowCount, 0.0, 0.0 );
+ }
+ }
+ else
+ {
+ if( ( i == windowCount - 1 ) && !left )
+ {
+ // left most window on right side -> move to front
+ // we are at: width*1.25 - ( width * 0.25 * i )/rightWindowCount
+ // we want to: (width + rightWindow->geometry().width())*0.5f
+ float distance = width*1.25 - ( width * 0.25 * i )/windowCount -
+ (width + window->geometry().width())*0.5f;
+ glTranslatef( - distance * timeFactor, 0.0, 0.0 );
+ radian = ( angle - angle * timeFactor ) * ( 2 * M_PI / 360 );
+ }
+ // left most window does not have to be moved
+ else if( i==0 && left); // do nothing
+ else
+ {
+ // all other windows - move to next position
+ glTranslatef( - ( width * 0.25 * timeFactor )/windowCount, 0.0, 0.0 );
+ }
+ }
+ }
+ glRotatef( rotateFactor * radian, 0.0, 1.0, 0.0 );
+ windowWidth = window->geometry().width() * cos( radian );
+ windowHeight = window->geometry().height();
+ int x = 0;
+ if( !left )
+ {
+ x = -windowWidth;
+ }
+ windowRect = QRect( x, height - windowHeight, windowWidth, windowHeight );
+ // make window most to edge transparent if animation
+ if( animation && i == 0 && ( ( !forward && left ) || ( forward && !left ) ) )
+ {
+ // only for the first half of the animation
+ if( timeFactor < 0.5 )
+ paintWindowCover( window, windowRect, reflectedWindows, 1.0 - timeFactor * 2 );
+ }
+ else
+ paintWindowCover( window, windowRect, reflectedWindows );
+ glPopMatrix();
+ }
+ glPopMatrix();
+ }
+
+void CoverSwitchEffect::slowMotion()
+ {
+ slowMotionMode = !slowMotionMode;
+ if( slowMotionMode )
+ {
+ animationDuration *= slowMotionFactor;
+ }
+ else
+ {
+ animationDuration /= slowMotionFactor;
+ }
+ }
+
+} // namespace
diff --git a/effects/coverswitch.desktop b/effects/coverswitch.desktop
new file mode 100644
index 0000000000..fece6be3c0
--- /dev/null
+++ b/effects/coverswitch.desktop
@@ -0,0 +1,17 @@
+[Desktop Entry]
+Name=Cover Switch
+Icon=preferences-system-windows-effect-coverswitch
+Comment=Cover Switch - an alternative alt+tab window switcher
+
+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_coverswitch
+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/coverswitch.h b/effects/coverswitch.h
new file mode 100644
index 0000000000..027955e8de
--- /dev/null
+++ b/effects/coverswitch.h
@@ -0,0 +1,76 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+ Copyright (C) 2008 Martin Gräßlin .
+*********************************************************************/
+
+#ifndef KWIN_COVERSWITCH_H
+#define KWIN_COVERSWITCH_H
+
+#include
+#include
+
+namespace KWin
+{
+
+class CoverSwitchEffect
+ : public QObject, public Effect
+ {
+ Q_OBJECT
+ public:
+ CoverSwitchEffect();
+ ~CoverSwitchEffect();
+
+ 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 slots:
+ void slowMotion();
+ private:
+ void paintScene( EffectWindow* frontWindow, QList< EffectWindow* >* leftWindows, QList< EffectWindow* >* rightWindows,
+ float timeFactor, bool reflectedWindows = false );
+ void paintWindowCover( EffectWindow* w, QRect windowRect, bool reflectedWindow, float opacity = 1.0 );
+ void paintFrontWindow( EffectWindow* frontWindow, float timeFactor, int width, int leftWindows, int rightWindows, bool reflectedWindow );
+ void paintWindows( QList< EffectWindow* >* windows, float timeFactor, bool left, bool reflectedWindows, EffectWindow* additionalWindow = NULL );
+ bool mActivated;
+ float angle;
+ bool animateSwitch;
+ bool animateStart;
+ bool animateStop;
+ bool animation;
+ bool start;
+ bool stop;
+ bool forward;
+ bool reflection;
+ QTime animationTime;
+ int animationDuration;
+ int selectedWindow;
+ int rearrangeWindows;
+ bool slowMotionMode;
+ int slowMotionFactor;
+ bool stopRequested;
+ bool startRequested;
+ };
+
+} // namespace
+
+#endif
diff --git a/effects/coverswitch_config.cpp b/effects/coverswitch_config.cpp
new file mode 100644
index 0000000000..5d7283d9ba
--- /dev/null
+++ b/effects/coverswitch_config.cpp
@@ -0,0 +1,160 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+ Copyright (C) 2008 Martin Gräßlin .
+*********************************************************************/
+#include "coverswitch_config.h"
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#ifndef KDE_USE_FINAL
+KWIN_EFFECT_CONFIG_FACTORY
+#endif
+
+namespace KWin
+{
+
+CoverSwitchEffectConfigForm::CoverSwitchEffectConfigForm(QWidget* parent) : QWidget(parent)
+{
+ setupUi(this);
+}
+
+CoverSwitchEffectConfig::CoverSwitchEffectConfig(QWidget* parent, const QVariantList& args) :
+ KCModule(EffectFactory::componentData(), parent, args)
+ {
+ m_ui = new CoverSwitchEffectConfigForm(this);
+
+ QGridLayout* layout = new QGridLayout(this);
+
+ layout->addWidget(m_ui, 0, 0);
+
+ connect(m_ui->editor, SIGNAL(keyChange()), this, SLOT(changed()));
+ connect(m_ui->checkAnimateSwitch, SIGNAL(stateChanged(int)), this, SLOT(changed()));
+ connect(m_ui->checkAnimateStart, SIGNAL(stateChanged(int)), this, SLOT(changed()));
+ connect(m_ui->checkAnimateStop, SIGNAL(stateChanged(int)), this, SLOT(changed()));
+ connect(m_ui->checkReflection, SIGNAL(stateChanged(int)), this, SLOT(changed()));
+ connect(m_ui->spinDuration, SIGNAL(valueChanged(int)), this, SLOT(changed()));
+ connect(m_ui->spinSlowMotionFactor, SIGNAL(valueChanged(int)), this, SLOT(changed()));
+
+ KGlobalAccel::self()->overrideMainComponentData( componentData() );
+ m_actionCollection = new KActionCollection( this, componentData() );
+ m_actionCollection->setConfigGroup( "CoverSwitch" );
+ m_actionCollection->setConfigGlobal( true );
+
+ KAction* a = (KAction*)m_actionCollection->addAction( "SlowMotion" );
+ a->setText( i18n("Slow Motion" ) );
+ a->setGlobalShortcut( KShortcut( Qt::META + Qt::Key_S ) );
+
+ load();
+ }
+
+CoverSwitchEffectConfig::~CoverSwitchEffectConfig()
+ {
+ }
+
+void CoverSwitchEffectConfig::load()
+ {
+ KCModule::load();
+
+ KConfigGroup conf = EffectsHandler::effectConfig( "CoverSwitch" );
+
+ int duration = conf.readEntry( "Duration", 300 );
+ int slowMotionFactor = conf.readEntry( "SlowMotionFactor", 4 );
+ bool animateSwitch = conf.readEntry( "AnimateSwitch", true );
+ bool animateStart = conf.readEntry( "AnimateStart", true );
+ bool animateStop = conf.readEntry( "AnimateStop", true );
+ bool reflection = conf.readEntry( "Reflection", true );
+ m_ui->spinDuration->setValue( duration );
+ m_ui->spinSlowMotionFactor->setValue( slowMotionFactor );
+ if( animateSwitch )
+ {
+ m_ui->checkAnimateSwitch->setCheckState( Qt::Checked );
+ }
+ else
+ {
+ m_ui->checkAnimateSwitch->setCheckState( Qt::Unchecked );
+ }
+ if( animateStart )
+ {
+ m_ui->checkAnimateStart->setCheckState( Qt::Checked );
+ }
+ else
+ {
+ m_ui->checkAnimateStart->setCheckState( Qt::Unchecked );
+ }
+ if( animateStop )
+ {
+ m_ui->checkAnimateStop->setCheckState( Qt::Checked );
+ }
+ else
+ {
+ m_ui->checkAnimateStop->setCheckState( Qt::Unchecked );
+ }
+ if( reflection )
+ {
+ m_ui->checkReflection->setCheckState( Qt::Checked );
+ }
+ else
+ {
+ m_ui->checkReflection->setCheckState( Qt::Unchecked );
+ }
+
+ m_actionCollection->readSettings();
+ m_ui->editor->addCollection(m_actionCollection);
+
+ emit changed(false);
+ }
+
+void CoverSwitchEffectConfig::save()
+ {
+ KConfigGroup conf = EffectsHandler::effectConfig( "CoverSwitch" );
+
+ conf.writeEntry( "Duration", m_ui->spinDuration->value() );
+ conf.writeEntry( "SlowMotionFactor", m_ui->spinSlowMotionFactor->value() );
+ conf.writeEntry( "AnimateSwitch", m_ui->checkAnimateSwitch->checkState() == Qt::Checked ? true : false );
+ conf.writeEntry( "AnimateStart", m_ui->checkAnimateStart->checkState() == Qt::Checked ? true : false );
+ conf.writeEntry( "AnimateStop", m_ui->checkAnimateStop->checkState() == Qt::Checked ? true : false );
+ conf.writeEntry( "Reflection", m_ui->checkReflection->checkState() == Qt::Checked ? true : false );
+
+ m_actionCollection->writeSettings();
+
+ conf.sync();
+
+ emit changed(false);
+ EffectsHandler::sendReloadMessage( "coverswitch" );
+ }
+
+void CoverSwitchEffectConfig::defaults()
+ {
+ m_ui->spinDuration->setValue( 300 );
+ m_ui->spinSlowMotionFactor->setValue( 4 );
+ m_ui->checkAnimateSwitch->setCheckState( Qt::Checked );
+ m_ui->checkAnimateStart->setCheckState( Qt::Checked );
+ m_ui->checkAnimateStop->setCheckState( Qt::Checked );
+ m_ui->checkReflection->setCheckState( Qt::Checked );
+ emit changed(true);
+ }
+
+
+} // namespace
+
+#include "coverswitch_config.moc"
diff --git a/effects/coverswitch_config.desktop b/effects/coverswitch_config.desktop
new file mode 100755
index 0000000000..785deffdd6
--- /dev/null
+++ b/effects/coverswitch_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_coverswitch
+X-KDE-PluginKeyword=coverswitch
+
+Name=Cover Switch
diff --git a/effects/coverswitch_config.h b/effects/coverswitch_config.h
new file mode 100644
index 0000000000..86d9591716
--- /dev/null
+++ b/effects/coverswitch_config.h
@@ -0,0 +1,61 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+ Copyright (C) 2008 Martin Gräßlin .
+*********************************************************************/
+
+#ifndef KWIN_COVERSWITCH_CONFIG_H
+#define KWIN_COVERSWITCH_CONFIG_H
+
+#define KDE3_SUPPORT
+#include
+#undef KDE3_SUPPORT
+
+#include "ui_coverswitch_config.h"
+
+class KActionCollection;
+
+namespace KWin
+{
+
+class CoverSwitchEffectConfigForm : public QWidget, public Ui::CoverSwitchEffectConfigForm
+{
+ Q_OBJECT
+ public:
+ explicit CoverSwitchEffectConfigForm(QWidget* parent);
+};
+
+class CoverSwitchEffectConfig : public KCModule
+ {
+ Q_OBJECT
+ public:
+ explicit CoverSwitchEffectConfig(QWidget* parent = 0, const QVariantList& args = QVariantList());
+ ~CoverSwitchEffectConfig();
+
+ public slots:
+ virtual void save();
+ virtual void load();
+ virtual void defaults();
+
+ private:
+ CoverSwitchEffectConfigForm* m_ui;
+ KActionCollection* m_actionCollection;
+ };
+
+} // namespace
+
+#endif
diff --git a/effects/coverswitch_config.ui b/effects/coverswitch_config.ui
new file mode 100644
index 0000000000..db7ae25668
--- /dev/null
+++ b/effects/coverswitch_config.ui
@@ -0,0 +1,118 @@
+
+ KWin::CoverSwitchEffectConfigForm
+
+
+
+ 0
+ 0
+ 359
+ 431
+
+
+
+ -
+
+
+ Appearance
+
+
+
-
+
+
+ Animate &Switch
+
+
+
+ -
+
+
+ Animation on Tab Box &open
+
+
+
+ -
+
+
+ Animation on Tab Box &close
+
+
+
+ -
+
+
+ &Reflections
+
+
+
+ -
+
+
+ &Animation Duration:
+
+
+ spinDuration
+
+
+
+ -
+
+
+ msec
+
+
+ 5000
+
+
+ 300
+
+
+
+ -
+
+
+ Slow &Motion Factor:
+
+
+ spinDuration
+
+
+
+ -
+
+
+ 1
+
+
+ 10
+
+
+ 4
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+ KWin::GlobalShortcutsEditor
+ QWidget
+
+ 1
+
+
+
+ checkAnimateSwitch
+ checkAnimateStart
+ checkAnimateStop
+ checkReflection
+ spinDuration
+
+
+
+