From dd1b16a432b37c306aa410428e767f90002ee575 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Thu, 21 Feb 2008 13:20:22 +0000 Subject: [PATCH] Alternative Alt+Tab window switcher similar to Compiz Fusion's cover switch of shift switcher effect svn path=/trunk/KDE/kdebase/workspace/; revision=777745 --- effects/CMakeLists.txt | 5 + effects/configs_builtins.cpp | 2 + effects/coverswitch.cpp | 818 +++++++++++++++++++++++++++++ effects/coverswitch.desktop | 17 + effects/coverswitch.h | 76 +++ effects/coverswitch_config.cpp | 160 ++++++ effects/coverswitch_config.desktop | 9 + effects/coverswitch_config.h | 61 +++ effects/coverswitch_config.ui | 118 +++++ 9 files changed, 1266 insertions(+) create mode 100644 effects/coverswitch.cpp create mode 100644 effects/coverswitch.desktop create mode 100644 effects/coverswitch.h create mode 100644 effects/coverswitch_config.cpp create mode 100755 effects/coverswitch_config.desktop create mode 100644 effects/coverswitch_config.h create mode 100644 effects/coverswitch_config.ui 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 +
kwineffects.h
+ 1 +
+
+ + checkAnimateSwitch + checkAnimateStart + checkAnimateStop + checkReflection + spinDuration + + + +