/******************************************************************** 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 "cube.h" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace KWin { KWIN_EFFECT( cube, CubeEffect ) CubeEffect::CubeEffect() : activated( false ) , cube_painting( false ) , keyboard_grab( false ) , schedule_close( false ) , frontDesktop( 0 ) , cubeOpacity( 1.0 ) , displayDesktopName( true ) , reflection( true ) , rotating( false ) , desktopChangedWhileRotating( false ) , paintCaps( true ) , rotationDirection( Left ) , verticalRotationDirection( Upwards ) , verticalPosition( Normal ) , wallpaper( NULL ) , manualAngle( 0.0 ) , manualVerticalAngle( 0.0 ) , currentShape( TimeLine::EaseInOutCurve ) , start( false ) , stop( false ) , reflectionPainting( false ) , slide( false ) { KConfigGroup conf = effects->effectConfig( "Cube" ); borderActivate = (ElectricBorder)conf.readEntry( "BorderActivate", (int)ElectricNone ); effects->reserveElectricBorder( borderActivate ); cubeOpacity = (float)conf.readEntry( "Opacity", 80 )/100.0f; displayDesktopName = conf.readEntry( "DisplayDesktopName", true ); reflection = conf.readEntry( "Reflection", true ); int rotationDuration = conf.readEntry( "RotationDuration", 500 ); backgroundColor = conf.readEntry( "BackgroundColor", QColor( Qt::black ) ); capColor = conf.readEntry( "CapColor", KColorScheme( QPalette::Active, KColorScheme::Window ).background().color() ); paintCaps = conf.readEntry( "Caps", true ); QString file = conf.readEntry( "Wallpaper", QString("") ); if( !file.isEmpty() ) { QImage img = QImage( file ); if( !img.isNull() ) { wallpaper = new GLTexture( img ); } } timeLine.setCurveShape( TimeLine::EaseInOutCurve ); timeLine.setDuration( rotationDuration ); verticalTimeLine.setCurveShape( TimeLine::EaseInOutCurve ); verticalTimeLine.setDuration( rotationDuration ); KActionCollection* actionCollection = new KActionCollection( this ); KAction* a = static_cast< KAction* >( actionCollection->addAction( "Cube" )); a->setText( i18n("Desktop Cube" )); a->setGlobalShortcut( KShortcut( Qt::CTRL + Qt::Key_F11 )); connect( a, SIGNAL( triggered( bool )), this, SLOT( toggle())); // calculate values for projection matrix // we use the projection matrix as in compiz (see Compiz: screen.c) // with following values: // fovy = 60.0 // acpect = 1.0 // zNear = 0.1 // zFar = 100.0 fovy = 60.0f; aspect = 1.0f; zNear = 0.1f; zFar = 100.0f; ymax = zNear * tan( fovy * M_PI / 360.0f ); ymin = -ymax; xmin = ymin * aspect; xmax = ymax * aspect; } CubeEffect::~CubeEffect() { effects->unreserveElectricBorder( borderActivate ); delete wallpaper; } void CubeEffect::prePaintScreen( ScreenPrePaintData& data, int time ) { if( activated ) { //kDebug(); data.mask |= PAINT_SCREEN_TRANSFORMED | Effect::PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS | PAINT_SCREEN_BACKGROUND_FIRST; if( rotating || start || stop ) { timeLine.addTime( time ); } if( verticalRotating ) { verticalTimeLine.addTime( time ); } } effects->prePaintScreen( data, time ); } void CubeEffect::paintScreen( int mask, QRegion region, ScreenPaintData& data ) { if( activated ) { //kDebug(); QRect rect = effects->clientArea( FullArea, effects->activeScreen(), effects->currentDesktop()); // background float clearColor[4]; glGetFloatv( GL_COLOR_CLEAR_VALUE, clearColor ); glClearColor( backgroundColor.redF(), backgroundColor.greenF(), backgroundColor.blueF(), 1.0 ); glClear( GL_COLOR_BUFFER_BIT ); glClearColor( clearColor[0], clearColor[1], clearColor[2], clearColor[3] ); // wallpaper if( wallpaper ) { wallpaper->bind(); wallpaper->render( region, rect ); wallpaper->unbind(); } glMatrixMode( GL_PROJECTION ); glPushMatrix(); glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT ); glLoadIdentity(); glFrustum( xmin, xmax, ymin, ymax, zNear, zFar ); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); glPushMatrix(); float zTranslate = -zNear*2.0-2.0; if( start ) zTranslate = -zNear - (zNear + 2.0)*timeLine.value(); if( stop ) zTranslate = -zNear - (zNear + 2.0)*( 1.0 - timeLine.value() ); if( slide ) zTranslate = -zNear*2; glTranslatef( 0.0, 0.0, zTranslate ); glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); // reflection if( reflection && (!slide) ) { glPushMatrix(); float zValue = -1.0f; float scaleFactor = ( zNear*2+1 - zValue * 0.8f ) * tan( fovy * M_PI / 360.0f )/ymax; float scaleFactor2 = zFar*0.3* tan( fovy * M_PI / 360.0f )/ymax; if( start ) { zValue = zValue * timeLine.value(); scaleFactor = ( zNear + (zNear+1.0)*timeLine.value() - zValue * 0.8f) * tan( fovy * M_PI / 360.0f )/ymax; } if( stop ) { zValue = zValue * ( 1.0 - timeLine.value() ); scaleFactor = ( zNear + (zNear+1.0)*( 1.0 - timeLine.value() ) - zValue * 0.8f) * tan( fovy * M_PI / 360.0f )/ymax; } glScalef( 1.0, -1.0, 1.0 ); glTranslatef( 0.0, ymax*scaleFactor*2, 0.0 ); reflectionPainting = true; paintScene( mask, region, data ); reflectionPainting = false; glPopMatrix(); glPushMatrix(); if( start || stop ) { zValue = -1.0f; scaleFactor = ( zNear*2+1 - zValue * 0.8f ) * tan( fovy * M_PI / 360.0f )/ymax; glPushMatrix(); glTranslatef( 0.0, 0.0, -zTranslate + (-zNear*2.0-2.0) ); } glTranslatef( 0.0, ymin*scaleFactor, 0.0 ); float vertices[] = { xmin*scaleFactor, 0.0, zNear*2+2, xmax*scaleFactor, 0.0, zNear*2+2, xmax*scaleFactor2, 0.0, -zFar*0.3+zNear*2+2, xmin*scaleFactor2, 0.0, -zFar*0.3+zNear*2+2 }; // foreground float alpha = 0.9; if( start ) alpha = 0.5 + 0.4 * timeLine.value(); if( stop ) alpha = 0.5 + 0.4 * ( 1.0 - timeLine.value() ); glColor4f( 0.0, 0.0, 0.0, alpha ); glBegin( GL_POLYGON ); glVertex3f( vertices[0], vertices[1], vertices[2] ); glVertex3f( vertices[3], vertices[4], vertices[5] ); // rearground alpha = -1.0; glColor4f( 0.0, 0.0, 0.0, alpha ); glVertex3f( vertices[6], vertices[7], vertices[8] ); glVertex3f( vertices[9], vertices[10], vertices[11] ); glEnd(); if( start || stop ) { glPopMatrix(); } glPopMatrix(); } paintScene( mask, region, data ); glPopMatrix(); glDisable( GL_BLEND ); glPopAttrib(); glMatrixMode( GL_PROJECTION ); glPopMatrix(); glMatrixMode( GL_MODELVIEW ); // desktop name box - inspired from coverswitch if( displayDesktopName && (!slide) ) { QColor color_frame; QColor color_text; color_frame = KColorScheme( QPalette::Active, KColorScheme::Window ).background().color(); color_frame.setAlphaF( 0.5 ); color_text = KColorScheme( QPalette::Active, KColorScheme::Window ).foreground().color(); if( start ) { color_frame.setAlphaF( 0.5 * timeLine.value() ); color_text.setAlphaF( timeLine.value() ); } if( stop ) { color_frame.setAlphaF( 0.5 - 0.5 * timeLine.value() ); color_text.setAlphaF( 1.0 - timeLine.value() ); } QFont text_font; text_font.setBold( true ); text_font.setPointSize( 14 ); glPushAttrib( GL_CURRENT_BIT ); glColor4f( color_frame.redF(), color_frame.greenF(), color_frame.blueF(), color_frame.alphaF()); QRect frameRect = QRect( rect.width()*0.33f + rect.x(), rect.height() + rect.y() - QFontMetrics( text_font ).height() * 1.2f, rect.width()*0.33f, QFontMetrics( text_font ).height() * 1.2f ); renderRoundBoxWithEdge( frameRect ); effects->paintText( effects->desktopName( frontDesktop ), frameRect.center(), frameRect.width(), color_text, text_font ); glPopAttrib(); } if( stop && timeLine.value() == 1.0 ) { effects->paintScreen( mask, region, data ); } } else { effects->paintScreen( mask, region, data ); } } void CubeEffect::paintScene( int mask, QRegion region, ScreenPaintData& data ) { QRect rect = effects->clientArea( FullArea, effects->activeScreen(), effects->currentDesktop()); float zValue = -1.0f; float scaleFactor = ( zNear*2+1 - zValue * 0.8f ) * tan( fovy * M_PI / 360.0f )/ymax; if( start ) { zValue = zValue * timeLine.value(); scaleFactor = ( zNear + (zNear+1)*timeLine.value() - zValue * 0.8f) * tan( fovy * M_PI / 360.0f )/ymax; } if( stop ) { zValue = zValue * ( 1.0 - timeLine.value() ); scaleFactor = ( zNear + (zNear+1)*( 1.0 - timeLine.value() ) - zValue * 0.8f) * tan( fovy * M_PI / 360.0f )/ymax; } if( slide ) { scaleFactor = zNear * 2 * tan( fovy * M_PI / 360.0f )/ymax; } int rightSteps = effects->numberOfDesktops()/2; int leftSteps = rightSteps+1; int rightSideCounter = 0; int leftSideCounter = 0; float internalCubeAngle = 360.0f / effects->numberOfDesktops(); cube_painting = true; float xTranslate = xmin*scaleFactor; float xRight = (xmax-xmin)*scaleFactor; float yTranslate = ymax*scaleFactor; float yTop = (ymax-ymin)*scaleFactor; int desktopIndex = 0; bool topCapAfter = false; bool topCapBefore = false; // Rotation of the cube float cubeAngle = (float)((float)(effects->numberOfDesktops() - 2 )/(float)effects->numberOfDesktops() * 180.0f); float point = xmax*scaleFactor*tan(cubeAngle*0.5f*M_PI/180.0f); if( verticalRotating || verticalPosition != Normal || manualVerticalAngle != 0.0 ) { // change the verticalPosition if manualVerticalAngle > 90 or < -90 degrees if( manualVerticalAngle <= -90.0 ) { manualVerticalAngle += 90.0; if( verticalPosition == Normal ) verticalPosition = Down; if( verticalPosition == Up ) verticalPosition = Normal; } if( manualVerticalAngle >= 90.0 ) { manualVerticalAngle -= 90.0; if( verticalPosition == Normal ) verticalPosition = Up; if( verticalPosition == Down ) verticalPosition = Normal; } float angle = 0.0; if( verticalPosition == Up ) { angle = 90.0; if( !verticalRotating) { if( manualVerticalAngle < 0.0 ) angle += manualVerticalAngle; else manualVerticalAngle = 0.0; } } else if( verticalPosition == Down ) { angle = -90.0; if( !verticalRotating) { if( manualVerticalAngle > 0.0 ) angle += manualVerticalAngle; else manualVerticalAngle = 0.0; } } else { angle = manualVerticalAngle; } if( verticalRotating ) { angle *= verticalTimeLine.value(); if( verticalPosition == Normal && verticalRotationDirection == Upwards ) angle = -90.0 + 90*verticalTimeLine.value(); if( verticalPosition == Normal && verticalRotationDirection == Downwards ) angle = 90.0 - 90*verticalTimeLine.value(); angle += manualVerticalAngle * (1.0-verticalTimeLine.value()); } glTranslatef( 0.0, 0.0, -point); glRotatef( angle, 1.0, 0.0, 0.0 ); glTranslatef( 0.0, 0.0, point); // calculate if the caps have to be painted before/after or during desktop painting if( paintCaps ) { float M[16]; float P[16]; float V[4]; glGetFloatv( GL_PROJECTION_MATRIX, P ); glGetFloatv( GL_MODELVIEW_MATRIX, M ); glGetFloatv( GL_VIEWPORT, V ); // calculate y coordinate of the top of front desktop float X = M[0]*xTranslate + M[4]*yTranslate + M[8]*0 + M[12]*1; float Y = M[1]*xTranslate + M[5]*yTranslate + M[9]*0 + M[13]*1; float Z = M[2]*xTranslate + M[6]*yTranslate + M[10]*0 + M[14]*1; float W = M[3]*xTranslate + M[7]*yTranslate + M[11]*0 + M[15]*1; float clipY = P[1]*X + P[5]*Y + P[9]*Z + P[13]*W; float clipW = P[3]*X + P[7]*Y + P[11]*Z + P[15]*W; float normY = clipY/clipW; float yFront = (V[3]/2)*normY+(V[3]-V[1])/2; // calculate y coordinate of the bottom of front desktop X = M[0]*xTranslate + M[4]*(-yTranslate) + M[8]*0 + M[12]*1; Y = M[1]*xTranslate + M[5]*(-yTranslate) + M[9]*0 + M[13]*1; Z = M[2]*xTranslate + M[6]*(-yTranslate) + M[10]*0 + M[14]*1; W = M[3]*xTranslate + M[7]*(-yTranslate) + M[11]*0 + M[15]*1; clipY = P[1]*X + P[5]*Y + P[9]*Z + P[13]*W; clipW = P[3]*X + P[7]*Y + P[11]*Z + P[15]*W; normY = clipY/clipW; float yFrontBottom = (V[3]/2)*normY+(V[3]-V[1])/2; // change matrix to a rear position glPushMatrix(); glTranslatef( 0.0, 0.0, -point); float desktops = (effects->numberOfDesktops()/2.0); glRotatef( desktops*internalCubeAngle, 1.0, 0.0, 0.0 ); glTranslatef( xTranslate, -yTranslate, point ); glGetFloatv(GL_MODELVIEW_MATRIX, M); // calculate y coordinate of the top of rear desktop X = M[0]*0.0 + M[4]*0.0 + M[8]*0.0 + M[12]*1; Y = M[1]*0.0 + M[5]*0.0 + M[9]*0.0 + M[13]*1; Z = M[2]*0.0 + M[6]*0.0 + M[10]*0.0 + M[14]*1; W = M[3]*0.0 + M[7]*0.0 + M[11]*0.0 + M[15]*1; clipY = P[1]*X + P[5]*Y + P[9]*Z + P[13]*W; clipW = P[3]*X + P[7]*Y + P[11]*Z + P[15]*W; normY = clipY/clipW; float yBack = (V[3]/2)*normY+(V[3]-V[1])/2; // calculate y coordniate of the bottom of rear desktop glTranslatef( 0.0, yTranslate*2, 0.0 ); glGetFloatv(GL_MODELVIEW_MATRIX, M); X = M[0]*0.0 + M[4]*0.0 + M[8]*0.0 + M[12]*1; Y = M[1]*0.0 + M[5]*0.0 + M[9]*0.0 + M[13]*1; Z = M[2]*0.0 + M[6]*0.0 + M[10]*0.0 + M[14]*1; W = M[3]*0.0 + M[7]*0.0 + M[11]*0.0 + M[15]*1; clipY = P[1]*X + P[5]*Y + P[9]*Z + P[13]*W; clipW = P[3]*X + P[7]*Y + P[11]*Z + P[15]*W; normY = clipY/clipW; float yBackBottom = (V[3]/2)*normY+(V[3]-V[1])/2; glPopMatrix(); if( yBack >= yFront ) topCapAfter = true; if( yBackBottom <= yFrontBottom ) topCapBefore = true; } } if( rotating || ( (manualAngle != 0.0) && !stop ) ) { if( manualAngle > internalCubeAngle * 0.5f ) { manualAngle -= internalCubeAngle; frontDesktop--; if( frontDesktop == 0 ) frontDesktop = effects->numberOfDesktops(); } if( manualAngle < -internalCubeAngle * 0.5f ) { manualAngle += internalCubeAngle; frontDesktop++; if( frontDesktop > effects->numberOfDesktops() ) frontDesktop = 1; } float rotationAngle = internalCubeAngle * timeLine.value(); if( rotationAngle > internalCubeAngle * 0.5f ) { rotationAngle -= internalCubeAngle; if( !desktopChangedWhileRotating ) { desktopChangedWhileRotating = true; if( rotationDirection == Left ) { frontDesktop++; } else if( rotationDirection == Right ) { frontDesktop--; } if( frontDesktop > effects->numberOfDesktops() ) frontDesktop = 1; else if( frontDesktop == 0 ) frontDesktop = effects->numberOfDesktops(); } } if( rotationDirection == Left ) { rotationAngle *= -1; } rotationAngle += manualAngle * (1.0 - timeLine.value()); glTranslatef( 0.0, 0.0, -point); glRotatef( rotationAngle, 0.0, 1.0, 0.0 ); glTranslatef( 0.0, 0.0, point); } if( topCapBefore || topCapAfter ) { if( (topCapAfter && !reflectionPainting) || (topCapBefore && reflectionPainting) ) { // paint the bottom cap glTranslatef( 0.0, -yTranslate, 0.0 ); paintCap( xmin*scaleFactor, xmax*scaleFactor, point ); glTranslatef( 0.0, yTranslate, 0.0 ); } if( (topCapBefore && !reflectionPainting) || (topCapAfter && reflectionPainting) ) { // paint the top cap glTranslatef( 0.0, yTranslate, 0.0 ); paintCap( xmin*scaleFactor, xmax*scaleFactor, point ); glTranslatef( 0.0, -yTranslate, 0.0 ); } } for( int i=0; inumberOfDesktops(); i++ ) { if( !topCapAfter && !topCapBefore && i == effects->numberOfDesktops()/2 -1 && !slide ) { // paint the bottom cap glTranslatef( 0.0, -yTranslate, 0.0 ); paintCap( xmin*scaleFactor, xmax*scaleFactor, point ); glTranslatef( 0.0, yTranslate, 0.0 ); // paint the top cap glTranslatef( 0.0, yTranslate, 0.0 ); paintCap( xmin*scaleFactor, xmax*scaleFactor, point ); glTranslatef( 0.0, -yTranslate, 0.0 ); } if( i%2 == 0 && i != effects->numberOfDesktops() -1) { // desktops on the right (including back) desktopIndex = rightSteps - rightSideCounter; rightSideCounter++; } else { // desktops on the left (including front) desktopIndex = leftSteps + leftSideCounter; leftSideCounter++; } glPushMatrix(); glTranslatef( 0.0, 0.0, -point ); glRotatef( internalCubeAngle * desktopIndex, 0.0, 1.0, 0.0 ); glTranslatef( xTranslate, yTranslate, point ); glScalef( xRight/rect.width(), -yTop/rect.height(), 1.0 ); // start painting the cube painting_desktop = (desktopIndex + frontDesktop )%effects->numberOfDesktops(); if( painting_desktop == 0 ) { painting_desktop = effects->numberOfDesktops(); } effects->paintScreen( mask, region, data ); glPopMatrix(); } if( topCapBefore || topCapAfter ) { if( (topCapAfter && !reflectionPainting) || (topCapBefore && reflectionPainting) ) { // paint the top cap glTranslatef( 0.0, yTranslate, 0.0 ); paintCap( xmin*scaleFactor, xmax*scaleFactor, point ); glTranslatef( 0.0, -yTranslate, 0.0 ); } if( (topCapBefore && !reflectionPainting) || (topCapAfter && reflectionPainting) ) { // paint the bottom cap glTranslatef( 0.0, -yTranslate, 0.0 ); paintCap( xmin*scaleFactor, xmax*scaleFactor, point ); glTranslatef( 0.0, yTranslate, 0.0 ); } } cube_painting = false; painting_desktop = effects->currentDesktop(); } void CubeEffect::paintCap( float left, float right, float z ) { if( ( !paintCaps ) || effects->numberOfDesktops() <= 2 ) return; float opacity = cubeOpacity; if( start ) opacity = 1.0 - (1.0 - opacity)*timeLine.value(); if( stop ) opacity = 1.0 - (1.0 - opacity)*( 1.0 - timeLine.value() ); glColor4f( capColor.redF(), capColor.greenF(), capColor.blueF(), opacity ); float angle = 360.0f/effects->numberOfDesktops(); glPushMatrix(); glTranslatef( 0.0, 0.0, -z ); for( int i=0; inumberOfDesktops(); i++ ) { glPushMatrix(); glRotatef( i*angle, 0.0, 1.0, 0.0 ); glBegin( GL_POLYGON ); glVertex3f( left, 0.0, z ); glVertex3f(right, 0.0, z ); glVertex3f( 0.0, 0.0, 0.0 ); glEnd(); glPopMatrix(); } glPopMatrix(); } void CubeEffect::postPaintScreen() { effects->postPaintScreen(); if( activated ) { //kDebug(); if( start ) { if( timeLine.value() == 1.0 ) { start = false; timeLine.setProgress(0.0); } effects->addRepaintFull(); } if( stop ) { if( timeLine.value() == 1.0 ) { effects->setCurrentDesktop( frontDesktop ); stop = false; timeLine.setProgress(0.0); activated = false; // set the new desktop if( keyboard_grab ) effects->ungrabKeyboard(); keyboard_grab = false; effects->destroyInputWindow( input ); effects->setActiveFullScreenEffect( 0 ); } effects->addRepaintFull(); } if( rotating || verticalRotating ) { if( rotating && timeLine.value() == 1.0 ) { timeLine.setProgress(0.0); rotating = false; desktopChangedWhileRotating = false; manualAngle = 0.0; // more rotations? if( !rotations.empty() ) { rotationDirection = rotations.dequeue(); rotating = true; // change the curve shape if current shape is not easeInOut if( currentShape != TimeLine::EaseInOutCurve ) { // more rotations follow -> linear curve if( !rotations.empty() ) { currentShape = TimeLine::LinearCurve; } // last rotation step -> easeOut curve else { currentShape = TimeLine::EaseOutCurve; } timeLine.setCurveShape( currentShape ); } else { // if there is at least one more rotation, we can change to easeIn if( !rotations.empty() ) { currentShape = TimeLine::EaseInCurve; timeLine.setCurveShape( currentShape ); } } } else { // reset curve shape if there are no more rotations if( currentShape != TimeLine::EaseInOutCurve ) { currentShape = TimeLine::EaseInOutCurve; timeLine.setCurveShape( currentShape ); } } } if( verticalRotating && verticalTimeLine.value() == 1.0 ) { verticalTimeLine.setProgress(0.0); verticalRotating = false; manualVerticalAngle = 0.0; // more rotations? if( !verticalRotations.empty() ) { verticalRotationDirection = verticalRotations.dequeue(); verticalRotating = true; if( verticalRotationDirection == Upwards ) { if( verticalPosition == Normal ) verticalPosition = Up; if( verticalPosition == Down ) verticalPosition = Normal; } if( verticalRotationDirection == Downwards ) { if( verticalPosition == Normal ) verticalPosition = Down; if( verticalPosition == Up ) verticalPosition = Normal; } } } effects->addRepaintFull(); return; // rotation has to end before cube is closed } if( schedule_close ) { schedule_close = false; if( !slide ) { stop = true; } else { activated = false; slide = false; effects->setActiveFullScreenEffect( 0 ); } effects->addRepaintFull(); } } } void CubeEffect::prePaintWindow( EffectWindow* w, WindowPrePaintData& data, int time ) { if( activated ) { //kDebug(); if( cube_painting ) { if( w->isOnDesktop( painting_desktop )) { QRect rect = effects->clientArea( FullArea, effects->activeScreen(), painting_desktop ); if( w->x() < rect.x() ) { data.quads = data.quads.splitAtX( -w->x() ); } if( w->x() + w->width() > rect.x() + rect.width() ) { data.quads = data.quads.splitAtX( rect.width() - w->x() ); } if( w->y() < rect.y() ) { data.quads = data.quads.splitAtY( -w->y() ); } if( w->y() + w->height() > rect.y() + rect.height() ) { data.quads = data.quads.splitAtY( rect.height() - w->y() ); } w->enablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP ); } else { // check for windows belonging to the previous desktop int prev_desktop = painting_desktop -1; if( prev_desktop == 0 ) prev_desktop = effects->numberOfDesktops(); if( w->isOnDesktop( prev_desktop ) ) { QRect rect = effects->clientArea( FullArea, effects->activeScreen(), prev_desktop); if( w->x()+w->width() > rect.x() + rect.width() ) { w->enablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP ); data.quads = data.quads.splitAtX( rect.width() - w->x() ); if( w->y() < rect.y() ) { data.quads = data.quads.splitAtY( -w->y() ); } if( w->y() + w->height() > rect.y() + rect.height() ) { data.quads = data.quads.splitAtY( rect.height() - w->y() ); } data.setTransformed(); effects->prePaintWindow( w, data, time ); return; } } // check for windows belonging to the next desktop int next_desktop = painting_desktop +1; if( next_desktop > effects->numberOfDesktops() ) next_desktop = 1; if( w->isOnDesktop( next_desktop ) ) { QRect rect = effects->clientArea( FullArea, effects->activeScreen(), next_desktop); if( w->x() < rect.x() ) { w->enablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP ); data.quads = data.quads.splitAtX( -w->x() ); if( w->y() < rect.y() ) { data.quads = data.quads.splitAtY( -w->y() ); } if( w->y() + w->height() > rect.y() + rect.height() ) { data.quads = data.quads.splitAtY( rect.height() - w->y() ); } data.setTransformed(); effects->prePaintWindow( w, data, time ); return; } } w->disablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP ); } } } effects->prePaintWindow( w, data, time ); } void CubeEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ) { if( activated && cube_painting ) { //kDebug() << w->caption(); float opacity = cubeOpacity; if( start ) { opacity = 1.0 - (1.0 - opacity)*timeLine.value(); if( reflectionPainting ) opacity = 0.5 + ( cubeOpacity - 0.5 )*timeLine.value(); } if( stop ) { opacity = 1.0 - (1.0 - opacity)*( 1.0 - timeLine.value() ); if( reflectionPainting ) opacity = 0.5 + ( cubeOpacity - 0.5 )*( 1.0 - timeLine.value() ); } if( !slide || (slide && !w->isDesktop()) ) data.opacity *= opacity; // check for windows belonging to the previous desktop int prev_desktop = painting_desktop -1; if( prev_desktop == 0 ) prev_desktop = effects->numberOfDesktops(); int next_desktop = painting_desktop +1; if( next_desktop > effects->numberOfDesktops() ) next_desktop = 1; if( w->isOnDesktop( prev_desktop ) && ( mask & PAINT_WINDOW_TRANSFORMED ) ) { QRect rect = effects->clientArea( FullArea, effects->activeScreen(), prev_desktop); data.xTranslate = -rect.width(); WindowQuadList new_quads; foreach( WindowQuad quad, data.quads ) { if( quad.right() > rect.width() - w->x() ) { new_quads.append( quad ); } } data.quads = new_quads; } if( w->isOnDesktop( next_desktop ) && ( mask & PAINT_WINDOW_TRANSFORMED ) ) { QRect rect = effects->clientArea( FullArea, effects->activeScreen(), next_desktop); data.xTranslate = rect.width(); WindowQuadList new_quads; foreach( WindowQuad quad, data.quads ) { if( w->x() + quad.right() <= rect.x() ) { new_quads.append( quad ); } } data.quads = new_quads; } QRect rect = effects->clientArea( FullArea, effects->activeScreen(), painting_desktop ); if( w->isOnDesktop(painting_desktop) && w->x() < rect.x() ) { WindowQuadList new_quads; foreach( WindowQuad quad, data.quads ) { if( quad.right() > -w->x() ) { new_quads.append( quad ); } } data.quads = new_quads; } if( w->isOnDesktop(painting_desktop) && w->x() + w->width() > rect.x() + rect.width() ) { WindowQuadList new_quads; foreach( WindowQuad quad, data.quads ) { if( quad.right() <= rect.width() - w->x() ) { new_quads.append( quad ); } } data.quads = new_quads; } if( w->y() < rect.y() ) { WindowQuadList new_quads; foreach( WindowQuad quad, data.quads ) { if( quad.bottom() > -w->y() ) { new_quads.append( quad ); } } data.quads = new_quads; } if( w->y() + w->height() > rect.y() + rect.height() ) { WindowQuadList new_quads; foreach( WindowQuad quad, data.quads ) { if( quad.bottom() <= rect.height() - w->y() ) { new_quads.append( quad ); } } data.quads = new_quads; } } effects->paintWindow( w, mask, region, data ); } void CubeEffect::postPaintWindow( EffectWindow* w ) { if( activated && !cube_painting ) { // a window was updated which has not been handled by cube_painting. // trigger full repaint, so that this window will be updated //effects->addRepaintFull(); } effects->postPaintWindow( w ); } bool CubeEffect::borderActivated( ElectricBorder border ) { if( effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this ) return false; if( border == borderActivate && !activated ) { kDebug() << "border activated"; toggle(); return true; } return false; } void CubeEffect::toggle() { if( effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this ) return; if( !activated ) { setActive( true ); } else { setActive( false ); } } void CubeEffect::grabbedKeyboardEvent( QKeyEvent* e ) { if( start || stop ) return; // taken from desktopgrid.cpp if( e->type() == QEvent::KeyPress ) { int desktop = -1; // switch by F or just if( e->key() >= Qt::Key_F1 && e->key() <= Qt::Key_F35 ) desktop = e->key() - Qt::Key_F1 + 1; else if( e->key() >= Qt::Key_0 && e->key() <= Qt::Key_9 ) desktop = e->key() == Qt::Key_0 ? 10 : e->key() - Qt::Key_0; if( desktop != -1 ) { if( desktop <= effects->numberOfDesktops()) { // we have to rotate to chosen desktop // and end effect when rotation finished rotateToDesktop( desktop ); setActive( false ); } return; } switch( e->key()) { // wrap only on autorepeat case Qt::Key_Left: // rotate to previous desktop kDebug() << "left"; if( !rotating ) { rotating = true; rotationDirection = Left; } else { rotations.enqueue( Left ); } break; case Qt::Key_Right: // rotate to next desktop kDebug() << "right"; if( !rotating ) { rotating = true; rotationDirection = Right; } else { rotations.enqueue( Right ); } break; case Qt::Key_Up: kDebug() << "up"; if( verticalPosition != Up ) { if( !verticalRotating ) { verticalRotating = true; verticalRotationDirection = Upwards; if( verticalPosition == Normal ) verticalPosition = Up; if( verticalPosition == Down ) verticalPosition = Normal; } else { verticalRotations.enqueue( Upwards ); } } else if( manualVerticalAngle < 0.0 && !verticalRotating ) { // rotate to up position from the manual position verticalRotating = true; verticalRotationDirection = Upwards; verticalPosition = Up; manualVerticalAngle += 90.0; } break; case Qt::Key_Down: kDebug() << "down"; if( verticalPosition != Down ) { if( !verticalRotating ) { verticalRotating = true; verticalRotationDirection = Downwards; if( verticalPosition == Normal ) verticalPosition = Down; if( verticalPosition == Up ) verticalPosition = Normal; } else { verticalRotations.enqueue( Downwards ); } } else if( manualVerticalAngle > 0.0 && !verticalRotating ) { // rotate to down position from the manual position verticalRotating = true; verticalRotationDirection = Downwards; verticalPosition = Down; manualVerticalAngle -= 90.0; } break; case Qt::Key_Escape: rotateToDesktop( effects->currentDesktop() ); setActive( false ); return; case Qt::Key_Enter: case Qt::Key_Return: case Qt::Key_Space: setActive( false ); return; default: break; } effects->addRepaintFull(); } } void CubeEffect::rotateToDesktop( int desktop ) { int tempFrontDesktop = frontDesktop; if( !rotations.empty() ) { // all scheduled rotations will be removed as a speed up rotations.clear(); } if( rotating && !desktopChangedWhileRotating ) { // front desktop will change during the actual rotation - this has to be considered if( rotationDirection == Left ) { tempFrontDesktop++; } else if( rotationDirection == Right ) { tempFrontDesktop--; } if( tempFrontDesktop > effects->numberOfDesktops() ) tempFrontDesktop = 1; else if( tempFrontDesktop == 0 ) tempFrontDesktop = effects->numberOfDesktops(); } // find the fastest rotation path from tempFrontDesktop to desktop int rightRotations = tempFrontDesktop - desktop; if( rightRotations < 0 ) rightRotations += effects->numberOfDesktops(); int leftRotations = desktop - tempFrontDesktop; if( leftRotations < 0 ) leftRotations += effects->numberOfDesktops(); if( leftRotations <= rightRotations ) { for( int i=0; igrabKeyboard( this ); input = effects->createInputWindow( this, 0, 0, displayWidth(), displayHeight(), Qt::OpenHandCursor ); frontDesktop = effects->currentDesktop(); start = true; } effects->setActiveFullScreenEffect( this ); kDebug() << "Cube is activated"; verticalPosition = Normal; verticalRotating = false; manualAngle = 0.0; manualVerticalAngle = 0.0; effects->addRepaintFull(); } else { schedule_close = true; // we have to add a repaint, to start the deactivating effects->addRepaintFull(); } } void CubeEffect::mouseChanged( const QPoint& pos, const QPoint& oldpos, Qt::MouseButtons buttons, Qt::MouseButtons oldbuttons, Qt::KeyboardModifiers modifiers, Qt::KeyboardModifiers oldmodifiers ) { if( !activated ) return; if( stop || slide ) return; QRect rect = effects->clientArea( FullArea, effects->activeScreen(), effects->currentDesktop()); if( buttons.testFlag( Qt::LeftButton ) ) { bool repaint = false; // vertical movement only if there is not a rotation if( !verticalRotating ) { // display height corresponds to 180* int deltaY = oldpos.y() - pos.y(); float deltaVerticalDegrees = (float)deltaY/rect.height()*180.0f; manualVerticalAngle -= deltaVerticalDegrees; if( deltaVerticalDegrees != 0.0 ) repaint = true; } // horizontal movement only if there is not a rotation if( !rotating ) { // display width corresponds to sum of angles of the polyhedron int deltaX = oldpos.x() - pos.x(); float deltaDegrees = (float)deltaX/rect.width() * 360.0f; manualAngle -= deltaDegrees; if( deltaDegrees != 0.0 ) repaint = true; } if( repaint ) effects->addRepaintFull(); } if( !oldbuttons.testFlag( Qt::LeftButton ) && buttons.testFlag( Qt::LeftButton ) ) { XDefineCursor( display(), input, QCursor( Qt::ClosedHandCursor).handle() ); } if( oldbuttons.testFlag( Qt::LeftButton) && !buttons.testFlag( Qt::LeftButton ) ) { XDefineCursor( display(), input, QCursor( Qt::OpenHandCursor).handle() ); } if( oldbuttons.testFlag( Qt::RightButton) && !buttons.testFlag( Qt::RightButton ) ) { // end effect on right mouse button setActive( false ); } } void CubeEffect::desktopChanged( int old ) { if( effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this ) return; if( activated ) return; slide = true; setActive( true ); frontDesktop = old; rotateToDesktop( effects->currentDesktop() ); setActive( false ); } } // namespace