/******************************************************************** 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 the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . *********************************************************************/ #include "coverswitch.h" #include #include #include #include #include #include #include #include #include #include #include "../boxswitch/boxswitch_proxy.h" namespace KWin { KWIN_EFFECT( coverswitch, CoverSwitchEffect ) KWIN_EFFECT_SUPPORTED( coverswitch, CoverSwitchEffect::supported() ) CoverSwitchEffect::CoverSwitchEffect() : mActivated( 0 ) , angle( 60.0 ) , animation( false ) , start( false ) , stop( false ) , stopRequested( false ) , startRequested( false ) , zPosition( 900.0 ) , scaleFactor( 0.0 ) , direction( Left ) , selected_window( 0 ) , captionFrame( effects->effectFrame( EffectFrameStyled ) ) , primaryTabBox( false ) , secondaryTabBox( false ) { reconfigure( ReconfigureAll ); // Caption frame captionFont.setBold( true ); captionFont.setPointSize( captionFont.pointSize() * 2 ); captionFrame->setFont( captionFont ); captionFrame->enableCrossFade( true ); } CoverSwitchEffect::~CoverSwitchEffect() { delete captionFrame; } bool CoverSwitchEffect::supported() { return effects->compositingType() == OpenGLCompositing; } void CoverSwitchEffect::reconfigure( ReconfigureFlags ) { KConfigGroup conf = effects->effectConfig( "CoverSwitch" ); animationDuration = animationTime( conf, "Duration", 200 ); animateSwitch = conf.readEntry( "AnimateSwitch", true ); animateStart = conf.readEntry( "AnimateStart", true ); animateStop = conf.readEntry( "AnimateStop", true ); reflection = conf.readEntry( "Reflection", true ); windowTitle = conf.readEntry( "WindowTitle", true ); zPosition = conf.readEntry( "ZPosition", 900.0 ); thumbnails = conf.readEntry( "Thumbnails", true ); dynamicThumbnails = conf.readEntry( "DynamicThumbnails", true ); thumbnailWindows = conf.readEntry( "ThumbnailWindows", 8 ); timeLine.setCurveShape( TimeLine::EaseInOutCurve ); timeLine.setDuration( animationDuration ); primaryTabBox = conf.readEntry( "TabBox", false ); secondaryTabBox = conf.readEntry( "TabBoxAlternative", false ); QColor tmp = conf.readEntry( "MirrorFrontColor", QColor(0,0,0) ); mirrorColor[0][0] = tmp.redF(); mirrorColor[0][1] = tmp.greenF(); mirrorColor[0][2] = tmp.blueF(); mirrorColor[0][3] = 1.0; tmp = conf.readEntry( "MirrorRearColor", QColor(0,0,0) ); mirrorColor[1][0] = tmp.redF(); mirrorColor[1][1] = tmp.greenF(); mirrorColor[1][2] = tmp.blueF(); mirrorColor[1][3] = -1.0; } void CoverSwitchEffect::prePaintScreen( ScreenPrePaintData& data, int time ) { if( mActivated || stop || stopRequested ) { data.mask |= Effect::PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS; if( animation || start || stop ) { timeLine.addTime( (double)time ); } if( selected_window == NULL ) abort(); } effects->prePaintScreen(data, time); } void CoverSwitchEffect::paintScreen( int mask, QRegion region, ScreenPaintData& data ) { effects->paintScreen( mask, region, data ); if( mActivated || stop || stopRequested ) { if( effects->numScreens() > 1 ) { // unfortunatelly we have to change the projection matrix in dual screen mode QRect fullRect = effects->clientArea( FullArea, activeScreen, effects->currentDesktop() ); glMatrixMode( GL_PROJECTION ); glPushMatrix(); 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( area.x() == 0 && area.width() != fullRect.width() ) { // horizontal layout: left screen xminFactor = (float)area.width()/(float)fullRect.width(); xmaxFactor = ((float)fullRect.width()-(float)area.width()*0.5f)/((float)fullRect.width()*0.5f); xTranslate = (float)fullRect.width()*0.5f-(float)area.width()*0.5f; } if( area.x() != 0 && area.width() != fullRect.width() ) { // horizontal layout: right screen xminFactor = ((float)fullRect.width()-(float)area.width()*0.5f)/((float)fullRect.width()*0.5f); xmaxFactor = (float)area.width()/(float)fullRect.width(); xTranslate = (float)fullRect.width()*0.5f-(float)area.width()*0.5f; } if( area.y() == 0 && area.height() != fullRect.height() ) { // vertical layout: top screen yminFactor = ((float)fullRect.height()-(float)area.height()*0.5f)/((float)fullRect.height()*0.5f); ymaxFactor = (float)area.height()/(float)fullRect.height(); yTranslate = (float)fullRect.height()*0.5f-(float)area.height()*0.5f; } if( area.y() != 0 && area.height() != fullRect.height() ) { // vertical layout: bottom screen yminFactor = (float)area.height()/(float)fullRect.height(); ymaxFactor = ((float)fullRect.height()-(float)area.height()*0.5f)/((float)fullRect.height()*0.5f); yTranslate = (float)fullRect.height()*0.5f-(float)area.height()*0.5f; } glFrustum( xmin*xminFactor, xmax*xmaxFactor, ymin*yminFactor, ymax*ymaxFactor, zNear, zFar ); glMatrixMode( GL_MODELVIEW ); glPushMatrix(); glTranslatef( xTranslate, yTranslate, 0.0 ); } QList< EffectWindow* > tempList = currentWindowList; int index = tempList.indexOf( selected_window ); if( animation || start || stop ) { if( !start && !stop ) { if( direction == Right ) index++; else index--; if( index < 0 ) index = tempList.count() + index; if( index >= tempList.count() ) index = index % tempList.count(); } foreach( Direction direction, scheduled_directions ) { if( direction == Right ) index++; else index--; if( index < 0 ) index = tempList.count() + index; if( index >= tempList.count() ) index = index % tempList.count(); } } int leftIndex = index -1; if( leftIndex < 0 ) leftIndex = tempList.count() -1; int rightIndex = index +1; if( rightIndex == tempList.count() ) rightIndex = 0; EffectWindow* frontWindow = tempList[ index ]; leftWindows.clear(); rightWindows.clear(); bool evenWindows = ( tempList.count() % 2 == 0 ) ? true : false; int leftWindowCount = 0; if( evenWindows ) leftWindowCount = tempList.count()/2 - 1; else leftWindowCount = ( tempList.count() - 1 )/2; for( int i=0; i < leftWindowCount; i++ ) { int tempIndex = ( leftIndex - i ); if( tempIndex < 0 ) tempIndex = tempList.count() + tempIndex; leftWindows.prepend( tempList[ tempIndex ] ); } int rightWindowCount = 0; if( evenWindows ) rightWindowCount = tempList.count()/2; else rightWindowCount = ( tempList.count() - 1 )/2; for( int i=0; i < rightWindowCount; i++ ) { int tempIndex = ( rightIndex + i ) % tempList.count(); rightWindows.prepend( tempList[ tempIndex ] ); } if( reflection ) { // restrict painting the reflections to the current screen QRegion clip = QRegion( area ); PaintClipper::push( clip ); // no reflections during start and stop animation if( !start && !stop ) paintScene( frontWindow, leftWindows, rightWindows, true ); PaintClipper::pop( clip ); glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA ); glPolygonMode( GL_FRONT, GL_FILL ); glPushMatrix(); QRect fullRect = effects->clientArea( FullArea, activeScreen, effects->currentDesktop() ); // we can use a huge scale factor (needed to calculate the rearground vertices) // as we restrict with a PaintClipper painting on the current screen float reflectionScaleFactor = 100000 * tan( 60.0 * M_PI / 360.0f )/area.width(); if( effects->numScreens() > 1 && area.x() != fullRect.x() ) { // have to change the reflection area in horizontal layout and right screen glTranslatef( -area.x(), 0.0, 0.0 ); } glTranslatef( area.x() + area.width()*0.5f, 0.0, 0.0 ); float vertices[] = { -area.width()*0.5f, area.height(), 0.0, area.width()*0.5f, area.height(), 0.0, (float)area.width()*reflectionScaleFactor, area.height(), -5000, -(float)area.width()*reflectionScaleFactor, area.height(), -5000 }; // foreground if( start ) mirrorColor[0][3] = timeLine.value(); else if( stop ) mirrorColor[0][3] = 1.0 - timeLine.value(); glColor4fv( mirrorColor[0] ); mirrorColor[0][3] = 1.0; int y = 0; // have to adjust the y values to fit OpenGL // in OpenGL y==0 is at bottom, in Qt at top if( effects->numScreens() > 1 ) { QRect fullArea = effects->clientArea( FullArea, 0, 1 ); if( fullArea.height() != area.height() ) { if( area.y() == 0 ) y = fullArea.height() - area.height(); else y = fullArea.height() - area.y() - area.height(); } } // use scissor to restrict painting of the reflection plane to current screen glScissor( area.x(), y, area.width(), area.height() ); glEnable( GL_SCISSOR_TEST ); glBegin( GL_POLYGON ); glVertex3f( vertices[0], vertices[1], vertices[2] ); glVertex3f( vertices[3], vertices[4], vertices[5] ); // rearground glColor4fv( mirrorColor[1] ); glVertex3f( vertices[6], vertices[7], vertices[8] ); glVertex3f( vertices[9], vertices[10], vertices[11] ); glEnd(); glDisable( GL_SCISSOR_TEST ); glPopMatrix(); glDisable( GL_BLEND ); } paintScene( frontWindow, leftWindows, rightWindows ); if( effects->numScreens() > 1 ) { glPopMatrix(); // revert change of projection matrix glMatrixMode( GL_PROJECTION ); glPopMatrix(); glMatrixMode( GL_MODELVIEW ); } // Render the caption frame if (windowTitle) { double opacity = 1.0; if( start ) opacity = timeLine.value(); else if( stop ) opacity = 1.0 - timeLine.value(); if( animation ) captionFrame->setCrossFadeProgress( timeLine.value() ); captionFrame->render( region, opacity ); } if( ( thumbnails && (!dynamicThumbnails || (dynamicThumbnails && currentWindowList.size() >= thumbnailWindows)) ) && !( start || stop ) ) { BoxSwitchEffectProxy *proxy = static_cast( effects->getProxy( "boxswitch" ) ); if( proxy ) proxy->paintWindowsBox( region ); } } } void CoverSwitchEffect::postPaintScreen() { if( ( mActivated && ( animation || start ) ) || stop || stopRequested ) { if( timeLine.value() == 1.0 ) { timeLine.setProgress(0.0); if( stop ) { stop = false; effects->setActiveFullScreenEffect( 0 ); foreach( EffectWindow* window, referrencedWindows ) { window->unrefWindow(); } referrencedWindows.clear(); currentWindowList.clear(); if( startRequested ) { startRequested = false; mActivated = true; effects->refTabBox(); currentWindowList = effects->currentTabBoxWindowList(); if( animateStart ) { start = true; } } } else if( !scheduled_directions.isEmpty() ) { direction = scheduled_directions.dequeue(); if( start ) { animation = true; start = false; } } else { animation = false; start = false; if( stopRequested ) { stopRequested = false; stop = true; } } } effects->addRepaintFull(); } effects->postPaintScreen(); } void CoverSwitchEffect::paintScene( EffectWindow* frontWindow, const EffectWindowList& leftWindows, const EffectWindowList& rightWindows, 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 = area.width(); int leftWindowCount = leftWindows.count(); int rightWindowCount = rightWindows.count(); RotationData rot; rot.axis = RotationData::YAxis; // 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( !animation ) { paintWindows( leftWindows, true, reflectedWindows ); paintWindows( rightWindows, false, reflectedWindows ); paintFrontWindow( frontWindow, width, leftWindowCount, rightWindowCount, reflectedWindows ); } else { if( direction == Right ) { if( timeLine.value() < 0.5 ) { // paint in normal way paintWindows( leftWindows, true, reflectedWindows ); paintWindows( rightWindows, false, reflectedWindows ); paintFrontWindow( frontWindow, width, leftWindowCount, rightWindowCount, reflectedWindows ); } else { paintWindows( rightWindows, false, reflectedWindows ); paintFrontWindow( frontWindow, width, leftWindowCount, rightWindowCount, reflectedWindows ); paintWindows( leftWindows, true, reflectedWindows, rightWindows.at( 0 ) ); } } else { paintWindows( leftWindows, true, reflectedWindows ); if( timeLine.value() < 0.5 ) { paintWindows( rightWindows, false, reflectedWindows ); paintFrontWindow( frontWindow, width, leftWindowCount, rightWindowCount, reflectedWindows ); } else { EffectWindow* leftWindow; if( leftWindowCount > 0) { leftWindow = leftWindows.at( 0 ); paintFrontWindow( frontWindow, width, leftWindowCount, rightWindowCount, reflectedWindows ); } else leftWindow = frontWindow; paintWindows( rightWindows, false, reflectedWindows, leftWindow ); } } } } 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() ) { data.opacity = 1.0 - timeLine.value(); if( stop ) data.opacity = timeLine.value(); } else return; } } if ( ( start || stop ) && (!w->isOnCurrentDesktop() || w->isMinimized() ) ) { if (stop) // Fade out windows not on the current desktop data.opacity = (1.0 - timeLine.value()); else // Fade in Windows from other desktops when animation is started data.opacity = timeLine.value(); } effects->paintWindow( w, mask, region, data ); } void CoverSwitchEffect::tabBoxAdded( int mode ) { if( effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this ) return; if( !mActivated ) { // only for windows mode if( (( mode == TabBoxWindowsMode && primaryTabBox ) || ( mode == TabBoxWindowsAlternativeMode && secondaryTabBox )) && effects->currentTabBoxWindowList().count() > 0 ) { input = effects->createFullScreenInputWindow( this, Qt::ArrowCursor ); activeScreen = effects->activeScreen(); BoxSwitchEffectProxy *proxy = static_cast( effects->getProxy( "boxswitch" ) ); if( proxy ) proxy->activate( mode, true, false, 0.05f ); if( !stop && !stopRequested ) { effects->refTabBox(); effects->setActiveFullScreenEffect( this ); scheduled_directions.clear(); selected_window = effects->currentTabBoxWindow(); currentWindowList = effects->currentTabBoxWindowList(); direction = Left; mActivated = true; if( animateStart ) { start = true; } // Calculation of correct area area = effects->clientArea( FullScreenArea, activeScreen, effects->currentDesktop()); scaleFactor = (zPosition+1100) * 2.0 * tan( 60.0 * M_PI / 360.0f )/displayWidth(); if( displayWidth()-area.width() != 0 ) { // one of the screens is smaller than the other (horizontal) if( area.width() < displayWidth() - area.width() ) scaleFactor *= (float)area.width()/(float)(displayWidth()-area.width()); else if( area.width() != displayWidth() - area.width() ) { // vertical layout with different width // but we don't want to catch screens with same width and different height if( displayHeight() != area.height() ) scaleFactor *= (float)area.width()/(float)(displayWidth()); } } // Setup caption frame geometry if (windowTitle) { QRect frameRect = QRect( area.width() * 0.25f + area.x(), area.height() * 0.9f + area.y(), area.width() * 0.5f, QFontMetrics( captionFont ).height() ); captionFrame->setGeometry( frameRect ); captionFrame->setIconSize( QSize( frameRect.height(), frameRect.height() )); // And initial contents captionFrame->setText( selected_window->caption() ); captionFrame->setIcon( selected_window->icon() ); } effects->addRepaintFull(); } else { startRequested = true; } } } } void CoverSwitchEffect::tabBoxClosed() { if( mActivated ) { if( animateStop ) { if( !animation && !start ) { stop = true; } else if( start && scheduled_directions.isEmpty() ) { start = false; stop = true; timeLine.setProgress( 1.0 - timeLine.value() ); } else { stopRequested = true; } } else effects->setActiveFullScreenEffect( 0 ); mActivated = false; effects->unrefTabBox(); effects->destroyInputWindow( input ); effects->addRepaintFull(); } } void CoverSwitchEffect::tabBoxUpdated() { if( mActivated ) { if( animateSwitch && currentWindowList.count() > 1) { // determine the switch direction if( selected_window != effects->currentTabBoxWindow() ) { if( selected_window != NULL ) { int old_index = currentWindowList.indexOf( selected_window ); int new_index = effects->currentTabBoxWindowList().indexOf( effects->currentTabBoxWindow() ); Direction new_direction; int distance = new_index - old_index; if( distance > 0 ) new_direction = Left; if( distance < 0 ) new_direction = Right; if( effects->currentTabBoxWindowList().count() == 2 ) { new_direction = Left; distance = 1; } if( distance != 0 ) { distance = abs( distance ); int tempDistance = effects->currentTabBoxWindowList().count() - distance; if( tempDistance < abs( distance ) ) { distance = tempDistance; if( new_direction == Left ) new_direction = Right; else new_direction = Left; } if( !animation && !start ) { animation = true; direction = new_direction; distance--; } for( int i=0; icurrentTabBoxWindowList().count() ) scheduled_directions.clear(); } } } selected_window = effects->currentTabBoxWindow(); currentWindowList = effects->currentTabBoxWindowList(); captionFrame->setText( selected_window->caption() ); captionFrame->setIcon( selected_window->icon() ); } } effects->addRepaintFull(); } } void CoverSwitchEffect::paintWindowCover( EffectWindow* w, bool reflectedWindow, WindowPaintData& data ) { QRect windowRect = w->geometry(); data.yTranslate = area.height() - windowRect.y() - windowRect.height(); data.zTranslate = -zPosition; if( start ) { if( w->isMinimized() ) { data.opacity *= timeLine.value(); } else { data.xTranslate *= timeLine.value(); data.yTranslate *= timeLine.value(); if( effects->numScreens() > 1) { QRect clientRect = effects->clientArea( FullScreenArea, w->screen(), effects->currentDesktop() ); QRect fullRect = effects->clientArea( FullArea, activeScreen, effects->currentDesktop() ); if( w->screen() == activeScreen ) { if( clientRect.width() != fullRect.width() && clientRect.x() != fullRect.x() ) { data.xTranslate -= clientRect.x()*(1.0f-timeLine.value()); } if( clientRect.height() != fullRect.height() && clientRect.y() != fullRect.y() ) { data.yTranslate -= clientRect.y()*(1.0f-timeLine.value()); } } else { if( clientRect.width() != fullRect.width() && clientRect.x() < area.x()) { data.xTranslate -= clientRect.width()*(1.0f-timeLine.value()); } if( clientRect.height() != fullRect.height() && clientRect.y() < area.y() ) { data.yTranslate -= clientRect.height()*(1.0f-timeLine.value()); } } } data.zTranslate *= timeLine.value(); if( data.rotation ) data.rotation->angle *= timeLine.value(); } } if( stop ) { if( w->isMinimized() && w != effects->activeWindow() ) { data.opacity *= (1.0 - timeLine.value()); } else { data.xTranslate *= (1.0 - timeLine.value()); data.yTranslate *= (1.0 - timeLine.value()); if( effects->numScreens() > 1) { QRect clientRect = effects->clientArea( FullScreenArea, w->screen(), effects->currentDesktop() ); QRect rect = effects->clientArea( FullScreenArea, activeScreen, effects->currentDesktop() ); QRect fullRect = effects->clientArea( FullArea, activeScreen, effects->currentDesktop() ); if( w->screen() == activeScreen ) { if( clientRect.width() != fullRect.width() && clientRect.x() != fullRect.x() ) { data.xTranslate -= clientRect.x()*timeLine.value(); } if( clientRect.height() != fullRect.height() && clientRect.y() != fullRect.y() ) { data.yTranslate -= clientRect.y()*timeLine.value(); } } else { if( clientRect.width() != fullRect.width() && clientRect.x() < rect.x()) { data.xTranslate -= clientRect.width()*timeLine.value(); } if( clientRect.height() != fullRect.height() && clientRect.y() < area.y() ) { data.yTranslate -= clientRect.height()*timeLine.value(); } } } data.zTranslate *= (1.0 - timeLine.value()); if( data.rotation ) data.rotation->angle *= (1.0 - timeLine.value()); } } QRect thumbnail = infiniteRegion(); if( reflectedWindow ) { glPushMatrix(); glScalef( 1.0, -1.0, 1.0 ); data.yTranslate = - area.height() - windowRect.y() - windowRect.height(); effects->paintWindow( w, PAINT_WINDOW_TRANSFORMED, infiniteRegion(), data ); glPopMatrix(); } else { effects->paintWindow( w, PAINT_WINDOW_TRANSFORMED, infiniteRegion(), data ); } } void CoverSwitchEffect::paintFrontWindow( EffectWindow* frontWindow, int width, int leftWindows, int rightWindows, bool reflectedWindow ) { if( frontWindow == NULL ) return; float distance = 0.0; bool specialHandlingForward = false; WindowPaintData data( frontWindow ); data.xTranslate = area.width()*0.5 - frontWindow->geometry().x() - frontWindow->geometry().width()*0.5; if( leftWindows == 0 ) { leftWindows = 1; if( !start && !stop ) specialHandlingForward = true; } if( rightWindows == 0 ) { rightWindows = 1; } if( animation ) { if( direction == Right ) { // move to right distance = -frontWindow->geometry().width()*0.5f + area.width()*0.5f + (((float)displayWidth()*0.5*scaleFactor)-(float)area.width()*0.5f)/rightWindows; data.xTranslate += distance * timeLine.value(); RotationData rot; rot.axis = RotationData::YAxis; rot.angle = -angle*timeLine.value(); rot.xRotationPoint = frontWindow->geometry().width(); data.rotation = &rot; } else { // move to left distance = frontWindow->geometry().width()*0.5f - area.width()*0.5f + ((float)width*0.5f-((float)displayWidth()*0.5*scaleFactor))/leftWindows; float factor = 1.0; if( specialHandlingForward ) factor = 2.0; data.xTranslate += distance * timeLine.value() * factor; RotationData rot; rot.axis = RotationData::YAxis; rot.angle = angle*timeLine.value(); data.rotation = &rot; } } if( specialHandlingForward ) { data.opacity *= (1.0 - timeLine.value() * 2.0); paintWindowCover( frontWindow, reflectedWindow, data ); } else paintWindowCover( frontWindow, reflectedWindow, data ); } void CoverSwitchEffect::paintWindows( const EffectWindowList& windows, bool left, bool reflectedWindows, EffectWindow* additionalWindow ) { int width = area.width(); int windowCount = windows.count(); EffectWindow* window; int rotateFactor = 1; if( !left ) { rotateFactor = -1; } float xTranslate = -((float)(width)*0.5f-((float)displayWidth()*0.5*scaleFactor)); if( !left ) xTranslate = ((float)displayWidth()*0.5*scaleFactor)-(float)width*0.5f; // handling for additional window from other side // has to appear on this side after half of the time if( animation && timeLine.value() >= 0.5 && additionalWindow != NULL ) { RotationData rot; rot.axis = RotationData::YAxis; rot.angle = angle; rot.angle = angle*rotateFactor; WindowPaintData data( additionalWindow ); if( left ) data.xTranslate += -xTranslate - additionalWindow->geometry().x(); else { data.xTranslate += xTranslate + area.width() - additionalWindow->geometry().x() - additionalWindow->geometry().width(); rot.xRotationPoint = additionalWindow->geometry().width(); } data.rotation = &rot; data.opacity *= ( timeLine.value() - 0.5 ) * 2.0; paintWindowCover( additionalWindow, reflectedWindows, data ); } RotationData rot; rot.axis = RotationData::YAxis; // normal behaviour for( int i=0; i < windows.count(); i++) { window = windows.at( i ); if( window == NULL || window->isDeleted() ) { continue; } WindowPaintData data( window ); rot.angle = angle; if( left ) data.xTranslate += -xTranslate + xTranslate*i/windowCount - window->geometry().x(); else data.xTranslate += xTranslate + width - xTranslate*i/windowCount - window->geometry().x() - window->geometry().width(); if( animation ) { if( direction == Right ) { if( ( i == windowCount - 1 ) && left ) { // right most window on left side -> move to front // have to move one window distance plus half the difference between the window and the desktop size data.xTranslate += (xTranslate/windowCount + (width - window->geometry().width())*0.5f)*timeLine.value(); rot.angle = ( angle - angle * timeLine.value() ); } // right most window does not have to be moved else if( !left && ( i == 0 ) ); // do nothing else { // all other windows - move to next position data.xTranslate += xTranslate/windowCount * timeLine.value(); } } else { if( ( i == windowCount - 1 ) && !left ) { // left most window on right side -> move to front data.xTranslate -= (xTranslate/windowCount + (width - window->geometry().width())*0.5f)*timeLine.value(); rot.angle = ( angle - angle * timeLine.value() ); } // left most window does not have to be moved else if( i==0 && left); // do nothing else { // all other windows - move to next position data.xTranslate -= xTranslate/windowCount * timeLine.value(); } } } if( left ) rot.xRotationPoint = 0.0; else rot.xRotationPoint = window->geometry().width(); rot.angle *= rotateFactor; data.rotation = &rot; // make window most to edge transparent if animation if( animation && i == 0 && ( ( direction == Left && left ) || ( direction == Right && !left ) ) ) { // only for the first half of the animation if( timeLine.value() < 0.5 ) { data.opacity *= (1.0 - timeLine.value() * 2.0); paintWindowCover( window, reflectedWindows, data ); } } else { paintWindowCover( window, reflectedWindows, data ); } } } void CoverSwitchEffect::windowInputMouseEvent( Window w, QEvent* e ) { assert( w == input ); Q_UNUSED( w ); if( e->type() != QEvent::MouseButtonPress ) return; // we don't want click events during animations if( animation ) return; QPoint pos = static_cast< QMouseEvent* >( e )->pos(); // determine if a window has been clicked // not interested in events above a fullscreen window (ignoring panel size) if( pos.y() < (area.height()*scaleFactor - area.height())*0.5f*(1.0f/scaleFactor) ) return; // if there is no selected window (that is no window at all) we cannot click it if( !selected_window ) return; if( pos.x() < (area.width()*scaleFactor - selected_window->width())*0.5f*(1.0f/scaleFactor) ) { float availableSize = (area.width()*scaleFactor - area.width())*0.5f*(1.0f/scaleFactor); for( int i=0;i availableSize/leftWindows.count()*(i+1) ) continue; } effects->setTabBoxWindow( leftWindows[i] ); return; } } if( pos.x() > area.width() - (area.width()*scaleFactor - selected_window->width())*0.5f*(1.0f/scaleFactor) ) { float availableSize = (area.width()*scaleFactor - area.width())*0.5f*(1.0f/scaleFactor); for( int i=0;i windowPos ) continue; if( i+1 < rightWindows.count() ) { if( pos.x() < area.width() - availableSize/rightWindows.count()*(i+1) ) continue; } effects->setTabBoxWindow( rightWindows[i] ); return; } } } void CoverSwitchEffect::abort() { // it's possible that abort is called after tabbox has been closed // in this case the cleanup is already done (see bug 207554) if( mActivated ) { effects->unrefTabBox(); effects->destroyInputWindow( input ); } effects->setActiveFullScreenEffect( 0 ); mActivated = false; stop = false; stopRequested = false; effects->addRepaintFull(); captionFrame->free(); } void CoverSwitchEffect::windowClosed( EffectWindow* c ) { // if the list is not empty, the effect is active if( !currentWindowList.isEmpty() ) { c->refWindow(); referrencedWindows.append( c ); currentWindowList.removeAll( c ); leftWindows.removeAll( c ); rightWindows.removeAll( c ); } } } // namespace