From abe5c4ff04eb4cb57cda4763d5e0b24435799e16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Tue, 21 Jul 2009 10:18:48 +0000 Subject: [PATCH] Complete rewrite of flip switch. * no more usage of OpenGL directly. Only highlevel API (except multiscreen :-() * better animations by adjusting the TimeLine's curve shape * new configuration options for window positions * Usage without tabbox (also supporting electric border) * Effect Frame showing the window title * many more things I have forgotten to mention BUG: 187761 svn path=/trunk/KDE/kdebase/workspace/; revision=1000437 --- effects/flipswitch/flipswitch.cpp | 1408 ++++++++++++++-------- effects/flipswitch/flipswitch.h | 93 +- effects/flipswitch/flipswitch_config.cpp | 63 +- effects/flipswitch/flipswitch_config.h | 5 +- effects/flipswitch/flipswitch_config.ui | 228 +++- kcmkwin/kwincompositing/main.cpp | 11 +- kcmkwin/kwinscreenedges/main.cpp | 46 + kcmkwin/kwinscreenedges/main.h | 4 +- 8 files changed, 1284 insertions(+), 574 deletions(-) diff --git a/effects/flipswitch/flipswitch.cpp b/effects/flipswitch/flipswitch.cpp index 1c6583a491..9ab32d9242 100644 --- a/effects/flipswitch/flipswitch.cpp +++ b/effects/flipswitch/flipswitch.cpp @@ -2,7 +2,7 @@ KWin - the KDE window manager This file is part of the KDE project. - Copyright (C) 2008 Martin Gräßlin + Copyright (C) 2008, 2009 Martin Gräßlin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,15 +21,15 @@ along with this program. If not, see . #include #include -#include -#include #include +#include +#include +#include + #include -#ifdef KWIN_HAVE_OPENGL_COMPOSITING -#include -#endif +#include namespace KWin { @@ -38,22 +38,46 @@ KWIN_EFFECT( flipswitch, FlipSwitchEffect ) KWIN_EFFECT_SUPPORTED( flipswitch, FlipSwitchEffect::supported() ) FlipSwitchEffect::FlipSwitchEffect() - : mActivated( 0 ) - , animateFlip( false ) - , forward( true ) - , start( false ) - , stop( false ) - , addFullRepaint( false ) - , rearrangeWindows( 0 ) - , stopRequested( false ) - , startRequested( false ) - , twinview( false ) + : m_currentAnimationShape( TimeLine::EaseInOutCurve ) + , m_active( false ) + , m_start( false ) + , m_stop( false ) + , m_animation( false ) + , m_hasKeyboardGrab( false ) + , m_captionFrame( EffectFrame::Styled ) { reconfigure( ReconfigureAll ); + + // Caption frame + m_captionFont.setBold( true ); + m_captionFont.setPointSize( m_captionFont.pointSize() * 2 ); + m_captionFrame.setFont( m_captionFont ); + + KActionCollection* actionCollection = new KActionCollection( this ); + KAction* a = ( KAction* )actionCollection->addAction( "FlipSwitchCurrent" ); + a->setText( i18n( "Toggle Flip Switch (Current desktop)" )); + a->setGlobalShortcut( KShortcut(), KAction::ActiveShortcut ); + m_shortcutCurrent = a->globalShortcut(); + connect( a, SIGNAL( triggered(bool) ), this, SLOT( toggleActiveCurrent() )); + connect( a, SIGNAL( globalShortcutChanged(QKeySequence) ), this, SLOT( globalShortcutChangedCurrent(QKeySequence))); + KAction* b = ( KAction* )actionCollection->addAction( "FlipSwitchAll" ); + b->setText( i18n( "Toggle Flip Switch (All desktops)" )); + b->setGlobalShortcut( KShortcut(), KAction::ActiveShortcut ); + m_shortcutAll = b->globalShortcut(); + connect( b, SIGNAL( triggered(bool) ), this, SLOT( toggleActiveAllDesktops() )); + connect( b, SIGNAL( globalShortcutChanged(QKeySequence) ), this, SLOT( globalShortcutChangedAll(QKeySequence))); } FlipSwitchEffect::~FlipSwitchEffect() { + foreach( ElectricBorder border, m_borderActivate ) + { + effects->unreserveElectricBorder( border ); + } + foreach( ElectricBorder border, m_borderActivateAll ) + { + effects->unreserveElectricBorder( border ); + } } bool FlipSwitchEffect::supported() @@ -64,570 +88,960 @@ bool FlipSwitchEffect::supported() void FlipSwitchEffect::reconfigure( ReconfigureFlags ) { KConfigGroup conf = effects->effectConfig( "FlipSwitch" ); - mFlipDuration = animationTime( conf, "FlipDuration", 200 ); - mAnimation = conf.readEntry( "AnimateFlip", true ); - timeLine.setCurveShape( TimeLine::EaseInOutCurve ); - timeLine.setDuration( mFlipDuration ); + foreach( ElectricBorder border, m_borderActivate ) + { + effects->unreserveElectricBorder( border ); + } + foreach( ElectricBorder border, m_borderActivateAll ) + { + effects->unreserveElectricBorder( border ); + } + m_borderActivate.clear(); + m_borderActivateAll.clear(); + QList borderList = QList(); + borderList.append( int( ElectricNone ) ); + borderList = conf.readEntry( "BorderActivate", borderList ); + foreach( int i, borderList ) + { + m_borderActivate.append( ElectricBorder( i ) ); + effects->reserveElectricBorder( ElectricBorder( i ) ); + } + borderList.clear(); + borderList.append( int( ElectricNone ) ); + borderList = conf.readEntry( "BorderActivateAll", borderList ); + foreach( int i, borderList ) + { + m_borderActivateAll.append( ElectricBorder( i ) ); + effects->reserveElectricBorder( ElectricBorder( i ) ); + } + m_tabbox = conf.readEntry( "TabBox", false ); + float duration = animationTime( conf, "Duration", 200 ); + m_timeLine.setDuration( duration ); + m_startStopTimeLine.setDuration( duration ); + + m_angle = conf.readEntry( "Angle", 30 ); + m_xPosition = float( conf.readEntry( "XPosition", 33 ))/100.0f; + m_yPosition = float( conf.readEntry( "YPosition", 100 ))/100.0f; + m_windowTitle = conf.readEntry( "WindowTitle", true ); } void FlipSwitchEffect::prePaintScreen( ScreenPrePaintData& data, int time ) { - if( mActivated || stopRequested || stop ) + if( m_active ) { - data.mask |= Effect::PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS; - if( mAnimation && ( start || stop || animateFlip ) ) - timeLine.addTime( (double)time ); + data.mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS; + if( m_start ) + m_startStopTimeLine.addTime( time ); + if( m_stop && m_scheduledDirections.isEmpty() ) + m_startStopTimeLine.removeTime( time ); + if( m_animation ) + m_timeLine.addTime( time ); } - effects->prePaintScreen(data, time); + effects->prePaintScreen( data, time ); } void FlipSwitchEffect::paintScreen( int mask, QRegion region, ScreenPaintData& data ) { effects->paintScreen( mask, region, data ); - if( mActivated || stopRequested || stop ) + if( m_active ) { -#ifdef KWIN_HAVE_OPENGL_COMPOSITING - glMatrixMode( GL_PROJECTION ); - glPushMatrix(); - glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT ); - glEnable( GL_BLEND ); - glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); - glLoadIdentity(); - int viewport[4]; - glGetIntegerv( GL_VIEWPORT, viewport ); - int yPos = area.y(); - QRect fullArea = effects->clientArea( FullArea, effects->activeScreen(), effects->currentDesktop()); - if( twinview ) + EffectWindowList tempList; + if( m_mode == TabboxMode ) + tempList = effects->currentTabBoxWindowList(); + else { - if( effects->clientArea( FullScreenArea, effects->activeScreen(), effects->currentDesktop()).x() == 0 - && effects->clientArea( FullScreenArea, effects->activeScreen()==0?1:0, effects->currentDesktop()).x() == 0 ) + // we have to setup the list + // using stacking order directly is not possible + // as not each window in stacking order is shown + // TODO: store list instead of calculating in each frame? + foreach( EffectWindow* w, effects->stackingOrder() ) { - // top <-> bottom - // have to correct the yPos for top bottom constellation - yPos = area.height()-area.y(); - if( ( area.height() * 2 != fullArea.height() ) || - ( effects->clientArea( FullScreenArea, effects->activeScreen(), effects->currentDesktop()).width() != - effects->clientArea( FullScreenArea, effects->activeScreen()==0?1:0, effects->currentDesktop()).width() ) ) - { - // different resolutions - if( area.y() > 0 ) - yPos = 0; - else - yPos = fullArea.height() - area.height(); - } - } - else - { - // left <-> right - if( ( area.width() * 2 != fullArea.width() ) || - ( effects->clientArea( FullScreenArea, effects->activeScreen(), effects->currentDesktop()).height() != - effects->clientArea( FullScreenArea, effects->activeScreen()==0?1:0, effects->currentDesktop()).height() ) ) - { - // different resolutions - yPos = area.y() + fullArea.height() - area.height(); - } + if( m_windows.contains( w ) ) + tempList.append( w ); } } - float left, right, top, bottom; - left = -area.width() * 0.5f; - right = area.width() * 0.5f; - top = area.height()*0.5f; - bottom = -area.height()*0.5f; - if( twinview && ( start || stop ) ) + m_flipOrderedWindows.clear(); + int index = tempList.indexOf( m_selectedWindow ); + + int tabIndex = index; + if( m_mode == TabboxMode ) { - // special handling for start and stop animation in twin view setup - glViewport( fullArea.x(), fullArea.y(), fullArea.width(), fullArea.height() ); - left = -(area.x() + area.width() * 0.5f); - right = fullArea.width() + left; - bottom = -(area.y() + area.height() * 0.5f); - top = fullArea.height() + bottom; + foreach( SwitchingDirection direction, m_scheduledDirections ) + { + if( direction == DirectionBackward ) + index++; + else + index--; + if( index < 0 ) + index = tempList.count() + index; + if( index >= tempList.count() ) + index = index % tempList.count(); + } + tabIndex = index; + EffectWindow* w = NULL; + if( !m_scheduledDirections.isEmpty() && m_scheduledDirections.head() == DirectionBackward ) + { + index--; + if( index < 0 ) + index = tempList.count() + index; + w = tempList.at( index ); + } + for( int i=index-1; i>=0; i-- ) + m_flipOrderedWindows.append(tempList.at( i )); + for( int i=effects->currentTabBoxWindowList().count()-1; i>=index; i-- ) + m_flipOrderedWindows.append(tempList.at( i )); + if( w ) + { + m_flipOrderedWindows.removeAll( w ); + m_flipOrderedWindows.append( w ); + } } else { - glViewport( area.x(), yPos, area.width(), area.height() ); - } - glFrustum( left, right, top, bottom, 10, 50 ); - - glMatrixMode( GL_MODELVIEW ); - glLoadIdentity(); - float xOffset = area.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 ); - } + if( direction == DirectionForward ) + index++; + else + index--; + if( index < 0 ) + index = tempList.count() -1; + if( index >= tempList.count() ) + index = 0; } - else + tabIndex = index; + EffectWindow* w = NULL; + if( !m_scheduledDirections.isEmpty() && m_scheduledDirections.head() == DirectionBackward ) { - for( int i=0; i= tempList.count() ) + index = 0; + } + // sort from stacking order + for( int i=index+1; inumScreens() > 1 ) { - for( int i=0; ix()+left; - float y = bottom-area.height()+w->y()+w->height(); - float z = -10.0; - if( w->isMinimized() ) - { - // use icon instead of window - x = w->iconGeometry().x()+left; - y = bottom-area.height()+w->iconGeometry().y()+w->height(); - } - // Position of the window in the stack - float stackX = -area.width()*0.25f-(xOffset*windowList.count())+xOffset*(i+1); - float stackY = -area.height()*0.5f; - float stackZ = (-1*zOffset*windowList.count()) -12.5+zOffset*(i+1); - - float animateXOffset; - float animateYOffset; - float animateZOffset; - float rotation; - // if start move to stack, if stop move from stack - if( start ) - { - animateXOffset = x+timeLine.value()*(stackX-x); - animateYOffset = y+timeLine.value()*(stackY-y); - animateZOffset = z+timeLine.value()*(stackZ-z); - rotation = timeLine.value()*0.25; - } - else // = if( stop ) - { - animateXOffset = stackX+timeLine.value()*(x-stackX); - animateYOffset = stackY+timeLine.value()*(y-stackY); - animateZOffset = stackZ+timeLine.value()*(z-stackZ); - rotation = 0.25-timeLine.value()*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( iclientArea( FullArea, effects->activeScreen(), effects->currentDesktop() ); + glMatrixMode( GL_PROJECTION ); glPushMatrix(); - glTranslatef(-area.width()*0.25f-(xOffset*windowList.count()), - -area.height()*0.5f, - (-1*zOffset*windowList.count()) -12.5); - if( animateFlip && windowList.count() > 1 ) + glLoadIdentity(); + float fovy = 60.0f; + float aspect = 1.0f; + float zNear = 0.1f; + float zFar = 100.0f; + float ymax = zNear * tan( fovy * M_PI / 360.0f ); + float ymin = -ymax; + float xmin = ymin * aspect; + float xmax = ymax * aspect; + float xTranslate = 0.0; + float yTranslate = 0.0; + float xminFactor = 1.0; + float xmaxFactor = 1.0; + float yminFactor = 1.0; + float ymaxFactor = 1.0; + if( m_screenArea.x() == 0 && m_screenArea.width() != fullRect.width() ) { - if( timeLine.value() < 1.0 ) - { - float animateXOffset = timeLine.value()*xOffset; - float animateZOffset = timeLine.value()*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 - { - timeLine.setProgress( 0.0 ); - if( rearrangeWindows != 0 ) - { - animateFlip = true; - if( rearrangeWindows < 0 ) - { - forward = true; - rearrangeWindows++; - localProgress = 0.0; - } - else - { - forward = false; - rearrangeWindows--; - localProgress = 1.0; - } - } - else - { - animateFlip = false; - if( stopRequested ) - { - stop = true; - stopRequested = false; - } - } - } + // horizontal layout: left screen + xminFactor = (float)m_screenArea.width()/(float)fullRect.width(); + xmaxFactor = ((float)fullRect.width()-(float)m_screenArea.width()*0.5f)/((float)fullRect.width()*0.5f); + xTranslate = (float)fullRect.width()*0.5f-(float)m_screenArea.width()*0.5f; } - for( int i=0; i 1 ) - { - if( forward ) opacity = opacity - localProgress*opacity; - else opacity = localProgress*opacity; - } - paintWindowFlip( windowList[i], false, opacity); - } - glPopMatrix(); + // horizontal layout: right screen + xminFactor = ((float)fullRect.width()-(float)m_screenArea.width()*0.5f)/((float)fullRect.width()*0.5f); + xmaxFactor = (float)m_screenArea.width()/(float)fullRect.width(); + xTranslate = (float)fullRect.width()*0.5f-(float)m_screenArea.width()*0.5f; } - glPopMatrix(); + if( m_screenArea.y() == 0 && m_screenArea.height() != fullRect.height() ) + { + // vertical layout: top screen + yminFactor = ((float)fullRect.height()-(float)m_screenArea.height()*0.5f)/((float)fullRect.height()*0.5f); + ymaxFactor = (float)m_screenArea.height()/(float)fullRect.height(); + yTranslate = (float)fullRect.height()*0.5f-(float)m_screenArea.height()*0.5f; + } + if( m_screenArea.y() != 0 && m_screenArea.height() != fullRect.height() ) + { + // vertical layout: bottom screen + yminFactor = (float)m_screenArea.height()/(float)fullRect.height(); + ymaxFactor = ((float)fullRect.height()-(float)m_screenArea.height()*0.5f)/((float)fullRect.height()*0.5f); + yTranslate = (float)fullRect.height()*0.5f-(float)m_screenArea.height()*0.5f; + } + glFrustum( xmin*xminFactor, xmax*xmaxFactor, ymin*yminFactor, ymax*ymaxFactor, zNear, zFar ); + glMatrixMode( GL_MODELVIEW ); + glPushMatrix(); + glTranslatef( xTranslate, yTranslate, 0.0 ); } - glPopAttrib(); - glMatrixMode( GL_PROJECTION ); - glPopMatrix(); - glMatrixMode( GL_MODELVIEW ); - glViewport( viewport[0], viewport[1], viewport[2], viewport[3] ); - // 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 ) + int winMask = PAINT_WINDOW_TRANSFORMED | PAINT_WINDOW_TRANSLUCENT; + RotationData rot; + rot.axis = RotationData::YAxis; + rot.angle = m_angle * m_startStopTimeLine.value(); + // fade in/out one window at the end of the stack during animation + if( m_animation && !m_scheduledDirections.isEmpty() ) { - color_frame.setAlphaF( 0.9 * timeLine.value() ); - color_text.setAlphaF( timeLine.value() ); - } - else if( stop ) - { - color_frame.setAlphaF( 0.9 - 0.9 * timeLine.value() ); - color_text.setAlphaF( 1.0 - timeLine.value() ); - } - else if( addFullRepaint ) - { - // special case: timeLine was reset, but actual frame will be painted - color_frame.setAlphaF( 0.0 ); - color_text.setAlphaF( 0.0 ); - } - 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( area.width()*0.25f + area.x(), - area.height()*0.9f + area.y(), - area.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 - QPixmap iconPixmap = effects->currentTabBoxWindow()->icon(); - if( start || stop || addFullRepaint ) - { - int alpha = 255.0f * timeLine.value(); - if( stop ) + EffectWindow* w = m_flipOrderedWindows.last(); + if( m_windows.contains( w ) ) { - alpha = 255.0f - alpha; + WindowPaintData data( w ); + data.opacity = m_windows[ w ]->opacity; + data.brightness = m_windows[ w ]->brightness; + data.saturation = m_windows[ w ]->saturation; + int distance = tempList.count() - 1; + float zDistance = 500.0f; + data.xTranslate -= (w->x() - m_screenArea.x() + data.xTranslate) * m_startStopTimeLine.value(); + data.xTranslate += m_screenArea.width()*m_xPosition * m_startStopTimeLine.value(); + data.yTranslate += (m_screenArea.y() + m_screenArea.height()*m_yPosition - ( w->y() + w->height() + data.yTranslate )) * m_startStopTimeLine.value(); + + data.xTranslate -= (m_screenArea.width()*0.25f) * distance * m_startStopTimeLine.value(); + data.yTranslate -= (m_screenArea.height()*0.10f) * distance * m_startStopTimeLine.value(); + data.zTranslate -= (zDistance * distance) * m_startStopTimeLine.value(); + if( m_scheduledDirections.head() == DirectionForward ) + data.opacity *= 0.8 * m_timeLine.value(); + else + data.opacity *= 0.8 * (1.0 - m_timeLine.value() ); + + if( effects->numScreens() > 1) + { + adjustWindowMultiScreen( w, data ); + } + data.rotation = &rot; + effects->drawWindow( w, winMask, infiniteRegion(), data ); } - else if( addFullRepaint ) - { - alpha = 0.0f; - } - 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 bottom - 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( region, iconRect); - icon->unbind(); - delete icon; - glDisable( GL_BLEND ); - glPopAttrib(); -#endif + + foreach( EffectWindow* w, m_flipOrderedWindows ) + { + if( !m_windows.contains( w ) ) + continue; + WindowPaintData data( w ); + data.opacity = m_windows[ w ]->opacity; + data.brightness = m_windows[ w ]->brightness; + data.saturation = m_windows[ w ]->saturation; + int windowIndex = tempList.indexOf( w ); + int distance; + if( m_mode == TabboxMode ) + { + if( windowIndex < tabIndex ) + distance = tempList.count() - (tabIndex - windowIndex); + else if( windowIndex > tabIndex) + distance = windowIndex - tabIndex; + else + distance = 0; + } + else + { + distance = m_flipOrderedWindows.count() - m_flipOrderedWindows.indexOf( w ) - 1; + + if( !m_scheduledDirections.isEmpty() && m_scheduledDirections.head() == DirectionBackward ) + { + distance--; + } + } + if( !m_scheduledDirections.isEmpty() && m_scheduledDirections.head() == DirectionBackward ) + { + if( w == m_flipOrderedWindows.last() ) + { + distance = -1; + data.opacity *= m_timeLine.value(); + } + } + float zDistance = 500.0f; + data.xTranslate -= (w->x() - m_screenArea.x() + data.xTranslate) * m_startStopTimeLine.value(); + data.xTranslate += m_screenArea.width()*m_xPosition * m_startStopTimeLine.value(); + data.yTranslate += (m_screenArea.y() + m_screenArea.height()*m_yPosition - ( w->y() + w->height() + data.yTranslate )) * m_startStopTimeLine.value(); + + data.xTranslate -= (m_screenArea.width()*0.25f) * distance * m_startStopTimeLine.value(); + data.yTranslate -= (m_screenArea.height()*0.10f) * distance * m_startStopTimeLine.value(); + data.zTranslate -= (zDistance * distance) * m_startStopTimeLine.value(); + if( m_animation && !m_scheduledDirections.isEmpty() ) + { + if( m_scheduledDirections.head() == DirectionForward ) + { + data.xTranslate += (m_screenArea.width()*0.25f) * m_timeLine.value(); + data.yTranslate += (m_screenArea.height()*0.10f) * m_timeLine.value(); + data.zTranslate += zDistance * m_timeLine.value(); + if( distance == 0 ) + data.opacity *= (1.0 - m_timeLine.value() ); + } + else + { + data.xTranslate -= (m_screenArea.width()*0.25f) * m_timeLine.value(); + data.yTranslate -= (m_screenArea.height()*0.10f) * m_timeLine.value(); + data.zTranslate -= zDistance * m_timeLine.value(); + } + } + data.opacity *= (0.8 + 0.2 * (1.0 - m_startStopTimeLine.value())); + if( effects->numScreens() > 1) + { + adjustWindowMultiScreen( w, data ); + } + + data.rotation = &rot; + effects->drawWindow( w, winMask, infiniteRegion(), data ); + } + + if( effects->numScreens() > 1 ) + { + glPopMatrix(); + // revert change of projection matrix + glMatrixMode( GL_PROJECTION ); + glPopMatrix(); + glMatrixMode( GL_MODELVIEW ); + } + + if( m_windowTitle ) + { + // Render the caption frame + double opacity = 1.0; + opacity = m_startStopTimeLine.value(); + QPixmap iconPixmap = m_selectedWindow->icon(); + if( m_start || m_stop ) + { + int alpha = 255.0f * m_startStopTimeLine.value(); + QPixmap transparency = iconPixmap.copy( iconPixmap.rect() ); + transparency.fill( QColor( 255, 255, 255, alpha )); + iconPixmap.setAlphaChannel( transparency.alphaChannel() ); + } + m_captionFrame.setText( m_selectedWindow->caption() ); + m_captionFrame.setIcon( iconPixmap ); + m_captionFrame.render( region, opacity ); + } } } void FlipSwitchEffect::postPaintScreen() { - if( (mActivated && ( animateFlip || start )) || stopRequested || stop ) + if( m_active ) { - effects->addRepaintFull(); - } - if( addFullRepaint ) - { - addFullRepaint = false; - effects->setActiveFullScreenEffect( 0 ); - effects->addRepaintFull(); + if( m_start && m_startStopTimeLine.value() == 1.0f ) + { + m_start = false; + if( !m_scheduledDirections.isEmpty() ) + { + m_animation = true; + m_timeLine.setProgress( 0.0f ); + if( m_scheduledDirections.count() == 1 ) + { + m_currentAnimationShape = TimeLine::EaseOutCurve; + m_timeLine.setCurveShape( m_currentAnimationShape ); + } + else + { + m_currentAnimationShape = TimeLine::LinearCurve; + m_timeLine.setCurveShape( m_currentAnimationShape ); + } + } + effects->addRepaintFull(); + } + if( m_stop && m_startStopTimeLine.value() == 0.0f ) + { + m_stop = false; + m_active = false; + m_captionFrame.free(); + effects->setActiveFullScreenEffect( 0 ); + effects->addRepaintFull(); + qDeleteAll( m_windows ); + m_windows.clear(); + } + if( m_animation && m_timeLine.value() == 1.0f ) + { + m_timeLine.setProgress( 0.0f ); + m_scheduledDirections.dequeue(); + if( m_scheduledDirections.isEmpty() ) + { + m_animation = false; + effects->addRepaintFull(); + } + else + { + if( m_scheduledDirections.count() == 1 ) + { + if( m_stop ) + m_currentAnimationShape = TimeLine::LinearCurve; + else + m_currentAnimationShape = TimeLine::EaseOutCurve; + } + else + { + m_currentAnimationShape = TimeLine::LinearCurve; + } + m_timeLine.setCurveShape( m_currentAnimationShape ); + } + } + if( m_start || m_stop || m_animation ) + effects->addRepaintFull(); } effects->postPaintScreen(); } - -void FlipSwitchEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ) + +void FlipSwitchEffect::prePaintWindow( EffectWindow* w, WindowPrePaintData& data, int time ) { - if( mActivated || stopRequested || stop ) + if( m_active ) { - if( !( mask & PAINT_WINDOW_TRANSFORMED ) && ( !w->isDesktop() ) ) + if( m_windows.contains( w ) ) { - if( ( start || stop ) && w->isDock() ) - { - data.opacity = 1.0 - timeLine.value(); - if( stop ) - data.opacity = timeLine.value(); - } - else - return; + data.setTransformed(); + data.setTranslucent(); + if( !w->isOnCurrentDesktop() ) + w->enablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP ); + if( w->isMinimized() ) + w->enablePainting( EffectWindow::PAINT_DISABLED_BY_MINIMIZE ); + } + else + { + if( ( m_start || m_stop ) && !w->isDesktop() && w->isOnCurrentDesktop() ) + data.setTranslucent(); + else if( !w->isDesktop() ) + w->disablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP ); } } - effects->paintWindow( w, mask, region, data ); + effects->prePaintWindow( w, data, time ); } - + +void FlipSwitchEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ) + { + if( m_active ) + { + if( w->isDesktop() ) + { + // desktop is painted in normal way + effects->paintWindow( w, mask, region, data ); + return; + } + if( ( m_start || m_stop ) && !m_windows.contains( w ) ) + { + // fade out all windows not in window list + data.opacity *= ( 1.0 - m_startStopTimeLine.value() ); + effects->paintWindow( w, mask, region, data ); + return; + } + m_windows[ w ]->opacity = data.opacity; + m_windows[ w ]->brightness = data.brightness; + m_windows[ w ]->saturation = data.saturation; + // it's not nice but it removes flickering + return; + } + else + { + effects->paintWindow( w, mask, region, data ); + } + } + +//************************************************************* +// Tabbox handling +//************************************************************* void FlipSwitchEffect::tabBoxAdded( int mode ) { if( effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this ) return; - if( !mActivated ) + // only for windows mode + if( m_tabbox + && (!m_active || (m_active && m_stop)) + && mode == TabBoxWindowsMode + && !effects->currentTabBoxWindowList().isEmpty() ) { - // only for windows mode - if( mode == TabBoxWindowsMode && effects->currentTabBoxWindowList().count() > 0 ) - { - input = effects->createFullScreenInputWindow( this, Qt::BlankCursor ); + setActive( true, TabboxMode ); + if( m_active ) effects->refTabBox(); - effects->setActiveFullScreenEffect( this ); - selectedWindow = effects->currentTabBoxWindowList().indexOf(effects->currentTabBoxWindow()); - if( !stop && !stopRequested ) - { - mActivated = true; - start = true; - effects->addRepaintFull(); - } - else - { - // last tabbox effect still running - schedule start effect - startRequested = true; - } - - // Calculation of correct area - area = effects->clientArea( FullScreenArea, effects->activeScreen(), effects->currentDesktop()); - QRect fullArea = effects->clientArea( FullArea, effects->activeScreen(), effects->currentDesktop()); - // twinview? - if( area.height() != fullArea.height() || area.width() != fullArea.width() ) - twinview = true; - else - twinview = false; - } } } + void FlipSwitchEffect::tabBoxClosed() { - if( mActivated ) + if( m_active ) { - // if animation than deactivate after animation - mActivated = false; + setActive( false, TabboxMode ); effects->unrefTabBox(); - if( input ) - effects->destroyInputWindow( input ); - if( mAnimation ) - { - if( start && rearrangeWindows == 0 ) - { - stop = true; - start = false; - timeLine.setProgress( 1.0 - timeLine.value() ); - } - else if( start || animateFlip ) - stopRequested = true; - else - { - stop = true; - effects->addRepaintFull(); - } - } - else - { - effects->setActiveFullScreenEffect( 0 ); - } } } void FlipSwitchEffect::tabBoxUpdated() { - if( mActivated ) + if( m_active && !m_stop ) { - if( mAnimation && effects->currentTabBoxWindowList().count() > 1 ) + if( !effects->currentTabBoxWindowList().isEmpty() ) { // determine the switch direction - int index = effects->currentTabBoxWindowList().indexOf(effects->currentTabBoxWindow()); - bool direction = false; - int windowCount = effects->currentTabBoxWindowList().count(); - if( index > selectedWindow ) + if( m_selectedWindow != effects->currentTabBoxWindow() ) { - if( index == windowCount-1 && selectedWindow == 0 ) forward = false; - else direction = true; - } - else if( index == 0 && ( selectedWindow == windowCount-1 ) ) - { - direction = true; - } - else if( index == selectedWindow ) return; // nothing changed - else - { - direction = false; - } - selectedWindow = index; - if( !animateFlip && !start ) - { - forward = direction; - animateFlip = true; - } - else - { - if( direction ) rearrangeWindows--; - else rearrangeWindows++; - if( rearrangeWindows >= windowCount ) rearrangeWindows = rearrangeWindows % windowCount; - else if( (-1*rearrangeWindows) >= windowCount ) rearrangeWindows = -1*((-1*rearrangeWindows) % windowCount); + if( m_selectedWindow != NULL ) + { + int old_index = effects->currentTabBoxWindowList().indexOf( m_selectedWindow ); + int new_index = effects->currentTabBoxWindowList().indexOf( effects->currentTabBoxWindow() ); + SwitchingDirection new_direction; + int distance = new_index - old_index; + if( distance > 0 ) + new_direction = DirectionForward; + if( distance < 0 ) + new_direction = DirectionBackward; + if( effects->currentTabBoxWindowList().count() == 2 ) + { + new_direction = DirectionForward; + distance = 1; + } + if( distance != 0 ) + { + distance = abs( distance ); + int tempDistance = effects->currentTabBoxWindowList().count() - distance; + if( tempDistance < abs( distance ) ) + { + distance = tempDistance; + if( new_direction == DirectionForward ) + new_direction = DirectionBackward; + else + new_direction = DirectionForward; + } + scheduleAnimation( new_direction, distance ); + } + } + m_selectedWindow = effects->currentTabBoxWindow(); } } effects->addRepaintFull(); } } -void FlipSwitchEffect::paintWindowFlip( EffectWindow* w, bool draw, float opacity ) +//************************************************************* +// Window adding/removing handling +//************************************************************* + +void FlipSwitchEffect::windowAdded( EffectWindow* w ) { - WindowPaintData data( w ); + if( m_active && isSelectableWindow( w ) ) + { + m_windows[ w ] = new ItemInfo(); + } + } - int x = 0; - int y = area.height() - w->geometry().height(); - QRect thumbnail; - setPositionTransformations( data, - thumbnail, w, - QRect( x, y, w->geometry().width(), w->geometry().height() ), - Qt::KeepAspectRatio ); +void FlipSwitchEffect::windowClosed( EffectWindow* w ) + { + if( m_active && m_windows.contains( w ) ) + { + m_windows.remove( w ); + } + } - data.opacity *= opacity; - thumbnail = infiniteRegion(); - // 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 ); +//************************************************************* +// Activation +//************************************************************* + +void FlipSwitchEffect::setActive( bool activate, FlipSwitchMode mode ) + { + if( activate ) + { + // effect already active, do some sanity checks + if( m_active ) + { + if( m_stop ) + { + if( mode != m_mode ) + { + // only the same mode may reactivate the effect + return; + } + } + else + { + // active, but not scheduled for closing -> abort + return; + } + } + + m_mode = mode; + foreach( EffectWindow* w, effects->stackingOrder() ) + { + if( isSelectableWindow( w ) && !m_windows.contains( w ) ) + m_windows[ w ] = new ItemInfo(); + } + if( m_windows.isEmpty() ) + return; + + effects->setActiveFullScreenEffect( this ); + m_active = true; + m_start = true; + m_startStopTimeLine.setCurveShape( TimeLine::EaseInOutCurve ); + m_activeScreen = effects->activeScreen(); + m_screenArea = effects->clientArea( ScreenArea, m_activeScreen, effects->currentDesktop() ); + + if( m_stop ) + { + // effect is still closing from last usage + m_stop = false; + } + else + { + // things to do only when there is no closing animation + m_scheduledDirections.clear(); + } + + switch( m_mode ) + { + case TabboxMode: + m_selectedWindow = effects->currentTabBoxWindow(); + break; + case CurrentDesktopMode: + m_selectedWindow = effects->activeWindow(); + m_input = effects->createFullScreenInputWindow( this, Qt::BlankCursor ); + m_hasKeyboardGrab = effects->grabKeyboard( this ); + break; + case AllDesktopsMode: + m_selectedWindow = effects->activeWindow(); + m_input = effects->createFullScreenInputWindow( this, Qt::BlankCursor ); + m_hasKeyboardGrab = effects->grabKeyboard( this ); + break; + } + + // Setup caption frame geometry + QRect frameRect = QRect( m_screenArea.width() * 0.25f + m_screenArea.x(), + m_screenArea.height() * 0.1f + m_screenArea.y() - QFontMetrics( m_captionFont ).height(), + m_screenArea.width() * 0.5f, + QFontMetrics( m_captionFont ).height() ); + m_captionFrame.setGeometry( frameRect ); + m_captionFrame.setIconSize( QSize( frameRect.height(), frameRect.height() )); + effects->addRepaintFull(); + } + else + { + // only deactivate if mode is current mode + if( mode != m_mode ) + return; + if( m_start && m_scheduledDirections.isEmpty() ) + { + m_start = false; + } + m_stop = true; + if( m_animation ) + { + m_startStopTimeLine.setCurveShape( TimeLine::EaseOutCurve ); + if( m_scheduledDirections.count() == 1 ) + { + if( m_currentAnimationShape == TimeLine::EaseInOutCurve ) + m_currentAnimationShape = TimeLine::EaseInCurve; + else if( m_currentAnimationShape == TimeLine::EaseOutCurve ) + m_currentAnimationShape = TimeLine::LinearCurve; + m_timeLine.setCurveShape( m_currentAnimationShape ); + } + } + else + m_startStopTimeLine.setCurveShape( TimeLine::EaseInOutCurve ); + if( mode != TabboxMode ) + effects->destroyInputWindow( m_input ); + if( m_hasKeyboardGrab ) + { + effects->ungrabKeyboard(); + m_hasKeyboardGrab = false; + } + effects->addRepaintFull(); + } + } + +void FlipSwitchEffect::toggleActiveAllDesktops() + { + if( m_active ) + { + if( m_stop ) + { + // reactivate if stopping + setActive( true, AllDesktopsMode ); + } + else + { + // deactivate if not stopping + setActive( false, AllDesktopsMode ); + } + } + else + { + setActive( true, AllDesktopsMode ); + } + } + +void FlipSwitchEffect::toggleActiveCurrent() + { + if( m_active ) + { + if( m_stop ) + { + // reactivate if stopping + setActive( true, CurrentDesktopMode ); + } + else + { + // deactivate if not stopping + setActive( false, CurrentDesktopMode ); + } + } + else + { + setActive( true, CurrentDesktopMode ); + } + } + +bool FlipSwitchEffect::borderActivated(ElectricBorder border) + { + if( !m_borderActivate.contains( border ) && !m_borderActivateAll.contains( border ) ) + return false; + if( effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this ) + return true; + if( m_borderActivate.contains( border ) ) + toggleActiveCurrent(); + else + toggleActiveAllDesktops(); + return true; + } + +//************************************************************* +// Helper function +//************************************************************* + +bool FlipSwitchEffect::isSelectableWindow( EffectWindow* w ) const + { + if( w->isSpecialWindow() || w->isUtility() ) + return false; + if( w->isDeleted() ) + return false; + if( !w->acceptsFocus() ) + return false; + switch( m_mode ) + { + case TabboxMode: + return effects->currentTabBoxWindowList().contains( w ); + case CurrentDesktopMode: + return w->isOnCurrentDesktop(); + case AllDesktopsMode: + //nothing special + break; + } + return true; + } + +void FlipSwitchEffect::scheduleAnimation( const SwitchingDirection& direction, int distance ) + { + if( m_start ) + { + // start is still active so change the shape to have a nice transition + m_startStopTimeLine.setCurveShape( TimeLine::EaseInCurve ); + } + if( !m_animation && !m_start ) + { + m_animation = true; + m_scheduledDirections.enqueue( direction ); + distance--; + // reset shape just to make sure + m_currentAnimationShape = TimeLine::EaseInOutCurve; + m_timeLine.setCurveShape( m_currentAnimationShape ); + } + for( int i=0; i 1 && m_scheduledDirections.last() != direction ) + m_scheduledDirections.pop_back(); + else + m_scheduledDirections.enqueue( direction ); + if( m_scheduledDirections.count() == m_windows.count() + 1 ) + { + SwitchingDirection temp = m_scheduledDirections.dequeue(); + m_scheduledDirections.clear(); + m_scheduledDirections.enqueue( temp ); + } + } + if( m_scheduledDirections.count() > 1 ) + { + TimeLine::CurveShape newShape = TimeLine::EaseInOutCurve; + switch( m_currentAnimationShape ) + { + case TimeLine::EaseInOutCurve: + newShape = TimeLine::EaseInCurve; + break; + case TimeLine::EaseOutCurve: + newShape = TimeLine::LinearCurve; + break; + default: + newShape = m_currentAnimationShape; + } + if( newShape != m_currentAnimationShape ) + { + m_currentAnimationShape = newShape; + m_timeLine.setCurveShape( m_currentAnimationShape ); + } + } + } + +void FlipSwitchEffect::adjustWindowMultiScreen( const KWin::EffectWindow* w, WindowPaintData& data ) + { + if( effects->numScreens() <= 1 ) + return; + QRect clientRect = effects->clientArea( FullScreenArea, w->screen(), effects->currentDesktop() ); + QRect rect = effects->clientArea( ScreenArea, m_activeScreen, effects->currentDesktop() ); + QRect fullRect = effects->clientArea( FullArea, m_activeScreen, effects->currentDesktop() ); + if( w->screen() == m_activeScreen ) + { + if( clientRect.width() != fullRect.width() && clientRect.x() != fullRect.x() ) + { + data.xTranslate -= clientRect.x(); + } + if( clientRect.height() != fullRect.height() && clientRect.y() != fullRect.y() ) + { + data.yTranslate -= clientRect.y(); + } + } + else + { + if( clientRect.width() != fullRect.width() && clientRect.x() < rect.x()) + { + data.xTranslate -= clientRect.width(); + } + if( clientRect.height() != fullRect.height() && clientRect.y() < m_screenArea.y() ) + { + data.yTranslate -= clientRect.height(); + } + } + } + + +//************************************************************* +// Keyboard handling +//************************************************************* +void FlipSwitchEffect::globalShortcutChangedAll( QKeySequence shortcut ) + { + m_shortcutAll = KShortcut( shortcut ); + } + +void FlipSwitchEffect::globalShortcutChangedCurrent(QKeySequence shortcut) + { + m_shortcutCurrent = KShortcut( shortcut ); + } + +void FlipSwitchEffect::grabbedKeyboardEvent(QKeyEvent* e) + { + if( e->type() == QEvent::KeyPress ) + { + // check for global shortcuts + // HACK: keyboard grab disables the global shortcuts so we have to check for global shortcut (bug 156155) + if( m_mode == CurrentDesktopMode && m_shortcutCurrent.contains( e->key() + e->modifiers() ) ) + { + toggleActiveCurrent(); + return; + } + if( m_mode == AllDesktopsMode && m_shortcutAll.contains( e->key() + e->modifiers() ) ) + { + toggleActiveAllDesktops(); + return; + } + + switch( e->key() ) + { + case Qt::Key_Escape: + setActive( false, m_mode ); + return; + case Qt::Key_Tab: + { + // find next window + if( m_windows.isEmpty() ) + return; // sanity check + bool found = false; + for( int i=effects->stackingOrder().indexOf( m_selectedWindow)-1; i>=0; i-- ) + { + if( isSelectableWindow( effects->stackingOrder().at( i )) ) + { + m_selectedWindow = effects->stackingOrder().at( i ); + found = true; + break; + } + } + if( !found ) + { + for( int i=effects->stackingOrder().count()-1; i>effects->stackingOrder().indexOf( m_selectedWindow); i-- ) + { + if( isSelectableWindow( effects->stackingOrder().at( i )) ) + { + m_selectedWindow = effects->stackingOrder().at( i ); + found = true; + break; + } + } + } + if( found ) + { + scheduleAnimation( DirectionForward ); + } + break; + } + case Qt::Key_Backtab: + { + // find previous window + if( m_windows.isEmpty() ) + return; // sanity check + bool found = false; + for( int i=effects->stackingOrder().indexOf( m_selectedWindow)+1; istackingOrder().count(); i++ ) + { + if( isSelectableWindow( effects->stackingOrder().at( i )) ) + { + m_selectedWindow = effects->stackingOrder().at( i ); + found = true; + break; + } + } + if( !found ) + { + for( int i=0; istackingOrder().indexOf( m_selectedWindow); i++ ) + { + if( isSelectableWindow( effects->stackingOrder().at( i )) ) + { + m_selectedWindow = effects->stackingOrder().at( i ); + found = true; + break; + } + } + } + if( found ) + { + scheduleAnimation( DirectionBackward ); + } + break; + } + case Qt::Key_Return: + case Qt::Key_Enter: + case Qt::Key_Space: + if( m_selectedWindow ) + effects->activateWindow( m_selectedWindow ); + setActive( false, m_mode ); + break; + default: + break; + } + effects->addRepaintFull(); + } + } + +//************************************************************* +// Item Info +//************************************************************* +FlipSwitchEffect::ItemInfo::ItemInfo() + : deleted(false) + , opacity( 0.0 ) + , brightness( 0.0 ) + , saturation( 0.0 ) + { + } + +FlipSwitchEffect::ItemInfo::~ItemInfo() + { } } // namespace + +#include "flipswitch.moc" diff --git a/effects/flipswitch/flipswitch.h b/effects/flipswitch/flipswitch.h index b74890f6bc..e05a6ec253 100644 --- a/effects/flipswitch/flipswitch.h +++ b/effects/flipswitch/flipswitch.h @@ -2,7 +2,7 @@ KWin - the KDE window manager This file is part of the KDE project. - Copyright (C) 2008 Martin Gräßlin + Copyright (C) 2008, 2009 Martin Gräßlin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,13 +22,18 @@ along with this program. If not, see . #define KWIN_FLIPSWITCH_H #include +#include +#include + +class KShortcut; namespace KWin { class FlipSwitchEffect - : public Effect + : public QObject, public Effect { + Q_OBJECT public: FlipSwitchEffect(); ~FlipSwitchEffect(); @@ -37,30 +42,80 @@ class FlipSwitchEffect virtual void prePaintScreen( ScreenPrePaintData& data, int time ); virtual void paintScreen( int mask, QRegion region, ScreenPaintData& data ); virtual void postPaintScreen(); + virtual void prePaintWindow( EffectWindow *w, WindowPrePaintData &data, int time ); virtual void paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ); virtual void tabBoxAdded( int mode ); virtual void tabBoxClosed(); virtual void tabBoxUpdated(); + virtual void windowAdded( EffectWindow* w ); + virtual void windowClosed( EffectWindow* w ); + virtual bool borderActivated( ElectricBorder border ); + virtual void grabbedKeyboardEvent( QKeyEvent* e ); static bool supported(); + private Q_SLOTS: + void toggleActiveCurrent(); + void toggleActiveAllDesktops(); + void globalShortcutChangedCurrent( QKeySequence shortcut ); + void globalShortcutChangedAll( QKeySequence shortcut ); + private: - void paintWindowFlip( EffectWindow* w, bool draw = true, float opacity = 0.8 ); - bool mActivated; - bool mAnimation; - int mFlipDuration; - bool animateFlip; - bool forward; - int selectedWindow; - bool start; - bool stop; - bool addFullRepaint; - int rearrangeWindows; - bool stopRequested; - bool startRequested; - bool twinview; - QRect area; - TimeLine timeLine; - Window input; + class ItemInfo; + enum SwitchingDirection + { + DirectionForward, + DirectionBackward + }; + enum FlipSwitchMode + { + TabboxMode, + CurrentDesktopMode, + AllDesktopsMode + }; + void setActive( bool activate, FlipSwitchMode mode ); + bool isSelectableWindow( EffectWindow *w ) const; + void scheduleAnimation( const SwitchingDirection& direction, int distance = 1 ); + void adjustWindowMultiScreen( const EffectWindow *w, WindowPaintData& data ); + QQueue< SwitchingDirection> m_scheduledDirections; + EffectWindow* m_selectedWindow; + TimeLine m_timeLine; + TimeLine m_startStopTimeLine; + TimeLine::CurveShape m_currentAnimationShape; + QRect m_screenArea; + int m_activeScreen; + bool m_active; + bool m_start; + bool m_stop; + bool m_animation; + bool m_hasKeyboardGrab; + Window m_input; + FlipSwitchMode m_mode; + EffectFrame m_captionFrame; + QFont m_captionFont; + EffectWindowList m_flipOrderedWindows; + QHash< const EffectWindow*, ItemInfo* > m_windows; + // options + QList m_borderActivate; + QList m_borderActivateAll; + bool m_tabbox; + float m_angle; + float m_xPosition; + float m_yPosition; + bool m_windowTitle; + // Shortcuts + KShortcut m_shortcutCurrent; + KShortcut m_shortcutAll; + }; + +class FlipSwitchEffect::ItemInfo + { + public: + ItemInfo(); + ~ItemInfo(); + bool deleted; + double opacity; + double brightness; + double saturation; }; } // namespace diff --git a/effects/flipswitch/flipswitch_config.cpp b/effects/flipswitch/flipswitch_config.cpp index eda60ea0c2..acdf79f539 100644 --- a/effects/flipswitch/flipswitch_config.cpp +++ b/effects/flipswitch/flipswitch_config.cpp @@ -2,7 +2,7 @@ KWin - the KDE window manager This file is part of the KDE project. - Copyright (C) 2008 Martin Gräßlin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,6 +21,8 @@ along with this program. If not, see . #include #include +#include +#include #include @@ -43,8 +45,26 @@ FlipSwitchEffectConfig::FlipSwitchEffectConfig(QWidget* parent, const QVariantLi layout->addWidget(m_ui); - connect(m_ui->checkAnimateFlip, SIGNAL(stateChanged(int)), this, SLOT(changed())); - connect(m_ui->spinFlipDuration, SIGNAL(valueChanged(int)), this, SLOT(changed())); + // Shortcut config. The shortcut belongs to the component "kwin"! + m_actionCollection = new KActionCollection( this, KComponentData("kwin") ); + KAction* a = ( KAction* )m_actionCollection->addAction( "FlipSwitchCurrent" ); + a->setText( i18n( "Toggle Flip Switch (Current desktop)" )); + a->setGlobalShortcut( KShortcut(), KAction::ActiveShortcut ); + KAction* b = ( KAction* )m_actionCollection->addAction( "FlipSwitchAll" ); + b->setText( i18n( "Toggle Flip Switch (All desktops)" )); + b->setGlobalShortcut( KShortcut(), KAction::ActiveShortcut ); + + m_actionCollection->setConfigGroup( "FlipSwitch" ); + m_actionCollection->setConfigGlobal( true ); + + m_ui->shortcutEditor->addCollection( m_actionCollection ); + + connect(m_ui->durationSpin, SIGNAL(valueChanged(int)), SLOT(changed())); + connect(m_ui->angleSpin, SIGNAL(valueChanged(int)), SLOT(changed())); + connect(m_ui->horizontalSlider, SIGNAL(valueChanged(int)), SLOT(changed())); + connect(m_ui->verticalSlider, SIGNAL(valueChanged(int)), SLOT(changed())); + connect(m_ui->windowTitleBox, SIGNAL(stateChanged(int)), SLOT(changed())); + connect( m_ui->shortcutEditor, SIGNAL( keyChange() ), this, SLOT( changed() )); load(); } @@ -59,18 +79,12 @@ void FlipSwitchEffectConfig::load() KConfigGroup conf = EffectsHandler::effectConfig( "FlipSwitch" ); - int flipDuration = conf.readEntry( "FlipDuration", 0 ); - bool animateFlip = conf.readEntry( "AnimateFlip", true ); - m_ui->spinFlipDuration->setValue( flipDuration ); - m_ui->spinFlipDuration->setSuffix( ki18np ( " milisecond", " miliseconds" ) ); - if( animateFlip ) - { - m_ui->checkAnimateFlip->setCheckState( Qt::Checked ); - } - else - { - m_ui->checkAnimateFlip->setCheckState( Qt::Unchecked ); - } + m_ui->durationSpin->setValue( conf.readEntry( "Duration", 0 )); + m_ui->angleSpin->setValue( conf.readEntry( "Angle", 30 )); + m_ui->horizontalSlider->setValue( conf.readEntry( "XPosition", 33 )); + // slider bottom is 0, effect bottom is 100 + m_ui->verticalSlider->setValue( 100 - conf.readEntry( "YPosition", 100 )); + m_ui->windowTitleBox->setChecked( conf.readEntry( "WindowTitle", true )); emit changed(false); } @@ -79,8 +93,14 @@ 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.writeEntry( "Duration", m_ui->durationSpin->value() ); + conf.writeEntry( "Angle", m_ui->angleSpin->value() ); + conf.writeEntry( "XPosition", m_ui->horizontalSlider->value() ); + // slider bottom is 0, effect bottom is 100 + conf.writeEntry( "YPosition", 100 - m_ui->verticalSlider->value() ); + conf.writeEntry( "WindowTitle", m_ui->windowTitleBox->isChecked() ); + + m_ui->shortcutEditor->save(); conf.sync(); @@ -90,8 +110,13 @@ void FlipSwitchEffectConfig::save() void FlipSwitchEffectConfig::defaults() { - m_ui->spinFlipDuration->setValue( 0 ); - m_ui->checkAnimateFlip->setCheckState( Qt::Checked ); + m_ui->durationSpin->setValue( 0 ); + m_ui->angleSpin->setValue( 30 ); + m_ui->horizontalSlider->setValue( 33 ); + // slider bottom is 0, effect bottom is 100 + m_ui->verticalSlider->setValue( 0 ); + m_ui->windowTitleBox->setChecked( true ); + m_ui->shortcutEditor->allDefault(); emit changed(true); } diff --git a/effects/flipswitch/flipswitch_config.h b/effects/flipswitch/flipswitch_config.h index 3cdb3d102e..54a473e093 100644 --- a/effects/flipswitch/flipswitch_config.h +++ b/effects/flipswitch/flipswitch_config.h @@ -2,7 +2,7 @@ KWin - the KDE window manager This file is part of the KDE project. - Copyright (C) 2008 Martin Gräßlin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -25,6 +25,8 @@ along with this program. If not, see . #include "ui_flipswitch_config.h" +class KActionCollection; + namespace KWin { @@ -49,6 +51,7 @@ class FlipSwitchEffectConfig : public KCModule private: FlipSwitchEffectConfigForm* m_ui; + KActionCollection* m_actionCollection; }; } // namespace diff --git a/effects/flipswitch/flipswitch_config.ui b/effects/flipswitch/flipswitch_config.ui index 9c833fcf3e..4e0ce3d717 100644 --- a/effects/flipswitch/flipswitch_config.ui +++ b/effects/flipswitch/flipswitch_config.ui @@ -1,60 +1,219 @@ - + + KWin::FlipSwitchEffectConfigForm - - + + 0 0 - 267 - 105 + 400 + 316 - + - - + + Appearance - - - - - Animate &flip + + + + + Flip animation duration: - - - - - - F&lip animation duration: - - + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - spinFlipDuration + + durationSpin - - - - + + + + 0 0 - + Default - + 5000 - + 10 + + + + Angle: + + + angleSpin + + + + + + + + 0 + 0 + + + + ° + + + 360 + + + + + + + Horizontal position of front: + + + horizontalSlider + + + + + + + + + 100 + + + Qt::Horizontal + + + + + + + + + Left + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Right + + + + + + + + + + + Vertical position of front: + + + verticalSlider + + + + + + + + + 100 + + + Qt::Vertical + + + + + + + + + Top + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Bottom + + + + + + + + + + + Display window &titles + + + + + + + + + + + + + Activation + + + + + + + 0 + 0 + + + + @@ -66,10 +225,15 @@ QSpinBox
knuminput.h
+ + KWin::GlobalShortcutsEditor + QWidget +
kwineffects.h
+ 1 +
- checkAnimateFlip - spinFlipDuration + durationSpin diff --git a/kcmkwin/kwincompositing/main.cpp b/kcmkwin/kwincompositing/main.cpp index 6bdcd7a691..0563ddec93 100644 --- a/kcmkwin/kwincompositing/main.cpp +++ b/kcmkwin/kwincompositing/main.cpp @@ -338,7 +338,8 @@ void KWinCompositingConfig::loadGeneralTab() ui.windowSwitchingCombo->setCurrentIndex( 1 ); if( effectEnabled( "coverswitch", effectconfig )) ui.windowSwitchingCombo->setCurrentIndex( 3 ); - if( effectEnabled( "flipswitch", effectconfig )) + KConfigGroup flipswitchconfig(mKWinConfig, "Effect-FlipSwitch"); + if( effectEnabled( "flipswitch", effectconfig ) && flipswitchconfig.readEntry("TabBox", false)) ui.windowSwitchingCombo->setCurrentIndex( 4 ); KConfigGroup presentwindowsconfig(mKWinConfig, "Effect-PresentWindows"); if( effectEnabled( "presentwindows", effectconfig ) && presentwindowsconfig.readEntry("TabBox", false) ) @@ -490,19 +491,18 @@ void KWinCompositingConfig::saveGeneralTab() int windowSwitcher = ui.windowSwitchingCombo->currentIndex(); bool presentWindowSwitching = false; + bool flipSwitch = false; switch( windowSwitcher ) { case 0: // no effect effectconfig.writeEntry("kwin4_effect_boxswitchEnabled", false); effectconfig.writeEntry("kwin4_effect_coverswitchEnabled", false); - effectconfig.writeEntry("kwin4_effect_flipswitchEnabled", false); break; case 1: // box switch effectconfig.writeEntry("kwin4_effect_boxswitchEnabled", true); effectconfig.writeEntry("kwin4_effect_coverswitchEnabled", false); - effectconfig.writeEntry("kwin4_effect_flipswitchEnabled", false); break; case 2: // present windows @@ -510,16 +510,15 @@ void KWinCompositingConfig::saveGeneralTab() effectconfig.writeEntry("kwin4_effect_presentwindowsEnabled", true); effectconfig.writeEntry("kwin4_effect_boxswitchEnabled", false); effectconfig.writeEntry("kwin4_effect_coverswitchEnabled", false); - effectconfig.writeEntry("kwin4_effect_flipswitchEnabled", false); break; case 3: // coverswitch effectconfig.writeEntry("kwin4_effect_boxswitchEnabled", false); effectconfig.writeEntry("kwin4_effect_coverswitchEnabled", true); - effectconfig.writeEntry("kwin4_effect_flipswitchEnabled", false); break; case 4: // flipswitch + flipSwitch = true; effectconfig.writeEntry("kwin4_effect_boxswitchEnabled", false); effectconfig.writeEntry("kwin4_effect_coverswitchEnabled", false); effectconfig.writeEntry("kwin4_effect_flipswitchEnabled", true); @@ -527,6 +526,8 @@ void KWinCompositingConfig::saveGeneralTab() } KConfigGroup presentwindowsconfig(mKWinConfig, "Effect-PresentWindows"); presentwindowsconfig.writeEntry("TabBox", presentWindowSwitching); + KConfigGroup flipswitchconfig(mKWinConfig, "Effect-FlipSwitch"); + flipswitchconfig.writeEntry("TabBox", flipSwitch); int desktopSwitcher = ui.desktopSwitchingCombo->currentIndex(); switch( desktopSwitcher ) diff --git a/kcmkwin/kwinscreenedges/main.cpp b/kcmkwin/kwinscreenedges/main.cpp index cecdc46512..95fe047eb8 100644 --- a/kcmkwin/kwinscreenedges/main.cpp +++ b/kcmkwin/kwinscreenedges/main.cpp @@ -214,6 +214,19 @@ void KWinScreenEdgesConfig::monitorInit() monitorAddItem( services.first()->name() + " - " + i18n( "Cylinder" )); monitorAddItem( services.first()->name() + " - " + i18n( "Sphere" )); } + services = trader->query( "KWin/Effect", "[X-KDE-PluginInfo-Name] == 'kwin4_effect_flipswitch'" ); + if( services.isEmpty() ) + { + // adding empty strings in case the effect is not found + // TODO: after string freeze add a info that the effect is missing + monitorAddItem( QString() ); + monitorAddItem( QString() ); + } + else + { + monitorAddItem( services.first()->name() + " - " + i18n( "All Desktops" )); + monitorAddItem( services.first()->name() + " - " + i18n( "Current Desktop" )); + } monitorShowEvent(); } @@ -291,6 +304,25 @@ void KWinScreenEdgesConfig::monitorLoad() { monitorChangeEdge( ElectricBorder( i ), int( Sphere ) ); } + + // Flip Switch + KConfigGroup flipSwitchConfig( m_config, "Effect-FlipSwitch" ); + list.clear(); + // FlipSwitch BorderActivateAll + list.append( int( ElectricNone ) ); + list = flipSwitchConfig.readEntry( "BorderActivateAll", list ); + foreach( int i, list ) + { + monitorChangeEdge( ElectricBorder( i ), int( FlipSwitchAll ) ); + } + // FlipSwitch BorderActivate + list.clear(); + list.append( int( ElectricNone ) ); + list = flipSwitchConfig.readEntry( "BorderActivate", list ); + foreach( int i, list ) + { + monitorChangeEdge( ElectricBorder( i ), int( FlipSwitchCurrent ) ); + } } void KWinScreenEdgesConfig::monitorSaveAction( int edge, const QString& configName ) @@ -339,6 +371,13 @@ void KWinScreenEdgesConfig::monitorSave() monitorCheckEffectHasEdge( int( Cylinder ))); cubeConfig.writeEntry( "BorderActivateSphere", monitorCheckEffectHasEdge( int( Sphere ))); + + // Flip Switch + KConfigGroup flipSwitchConfig( m_config, "Effect-FlipSwitch" ); + flipSwitchConfig.writeEntry( "BorderActivateAll", + monitorCheckEffectHasEdge( int( FlipSwitchAll ))); + flipSwitchConfig.writeEntry( "BorderActivate", + monitorCheckEffectHasEdge( int( FlipSwitchCurrent ))); } void KWinScreenEdgesConfig::monitorDefaults() @@ -373,6 +412,11 @@ void KWinScreenEdgesConfig::monitorShowEvent() monitorItemSetEnabled( int( Cube ), enabled ); monitorItemSetEnabled( int( Cylinder ), enabled ); monitorItemSetEnabled( int( Sphere ), enabled ); + + // Flip Switch + enabled = effectEnabled( "flipswitch", config ); + monitorItemSetEnabled( int( FlipSwitchAll ), enabled ); + monitorItemSetEnabled( int( FlipSwitchCurrent ), enabled ); } else // Compositing disabled { @@ -382,6 +426,8 @@ void KWinScreenEdgesConfig::monitorShowEvent() monitorItemSetEnabled( int( Cube ), false ); monitorItemSetEnabled( int( Cylinder ), false ); monitorItemSetEnabled( int( Sphere ), false ); + monitorItemSetEnabled( int( FlipSwitchAll ), false ); + monitorItemSetEnabled( int( FlipSwitchCurrent ), false ); } } diff --git a/kcmkwin/kwinscreenedges/main.h b/kcmkwin/kwinscreenedges/main.h index da82c28f7f..146f6e8ce5 100644 --- a/kcmkwin/kwinscreenedges/main.h +++ b/kcmkwin/kwinscreenedges/main.h @@ -70,7 +70,9 @@ class KWinScreenEdgesConfig : public KCModule DesktopGrid, Cube, Cylinder, - Sphere + Sphere, + FlipSwitchAll, + FlipSwitchCurrent }; bool effectEnabled( const QString& effect, const KConfigGroup& cfg ) const;