add more spacing
[personal-kdebase.git] / workspace / kwin / effects / cube.cpp
blob9298570e541b1e30135231a9a9afc41f744c0b8f
1 /********************************************************************
2 KWin - the KDE window manager
3 This file is part of the KDE project.
5 Copyright (C) 2008 Martin Gräßlin <ubuntu@martin-graesslin.com>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *********************************************************************/
20 #include "cube.h"
22 #include <kaction.h>
23 #include <kactioncollection.h>
24 #include <klocale.h>
25 #include <kwinconfig.h>
26 #include <kconfiggroup.h>
27 #include <kcolorscheme.h>
28 #include <kglobal.h>
29 #include <kstandarddirs.h>
30 #include <kdebug.h>
32 #include <QColor>
33 #include <QRect>
34 #include <QEvent>
35 #include <QKeyEvent>
37 #include <math.h>
39 #include <GL/gl.h>
41 namespace KWin
44 KWIN_EFFECT( cube, CubeEffect )
45 KWIN_EFFECT_SUPPORTED( cube, CubeEffect::supported() )
47 CubeEffect::CubeEffect()
48 : activated( false )
49 , cube_painting( false )
50 , keyboard_grab( false )
51 , schedule_close( false )
52 , borderActivate( ElectricNone )
53 , frontDesktop( 0 )
54 , cubeOpacity( 1.0 )
55 , displayDesktopName( true )
56 , reflection( true )
57 , rotating( false )
58 , desktopChangedWhileRotating( false )
59 , paintCaps( true )
60 , rotationDirection( Left )
61 , verticalRotationDirection( Upwards )
62 , verticalPosition( Normal )
63 , wallpaper( NULL )
64 , texturedCaps( true )
65 , capTexture( NULL )
66 , manualAngle( 0.0 )
67 , manualVerticalAngle( 0.0 )
68 , currentShape( TimeLine::EaseInOutCurve )
69 , start( false )
70 , stop( false )
71 , reflectionPainting( false )
72 , slide( false )
73 , oldDesktop( 0 )
74 , activeScreen( 0 )
75 , animateDesktopChange( false )
76 , bigCube( false )
77 , bottomCap( false )
78 , closeOnMouseRelease( false )
79 , zoom( 0.0 )
80 , zPosition( 0.0 )
81 , useForTabBox( false )
82 , tabBoxMode( false )
83 , capListCreated( false )
84 , capList( 0 )
86 reconfigure( ReconfigureAll );
88 KActionCollection* actionCollection = new KActionCollection( this );
89 KAction* a = static_cast< KAction* >( actionCollection->addAction( "Cube" ));
90 a->setText( i18n("Desktop Cube" ));
91 a->setGlobalShortcut( KShortcut( Qt::CTRL + Qt::Key_F11 ));
92 connect( a, SIGNAL( triggered( bool )), this, SLOT( toggle()));
95 bool CubeEffect::supported()
97 return effects->compositingType() == OpenGLCompositing;
100 void CubeEffect::reconfigure( ReconfigureFlags )
102 loadConfig( "Cube" );
105 void CubeEffect::loadConfig( QString config )
107 KConfigGroup conf = effects->effectConfig( config );
108 effects->unreserveElectricBorder( borderActivate );
109 borderActivate = (ElectricBorder)conf.readEntry( "BorderActivate", (int)ElectricNone );
110 effects->reserveElectricBorder( borderActivate );
112 cubeOpacity = (float)conf.readEntry( "Opacity", 80 )/100.0f;
113 displayDesktopName = conf.readEntry( "DisplayDesktopName", true );
114 reflection = conf.readEntry( "Reflection", true );
115 rotationDuration = animationTime( conf, "RotationDuration", 500 );
116 backgroundColor = conf.readEntry( "BackgroundColor", QColor( Qt::black ) );
117 animateDesktopChange = conf.readEntry( "AnimateDesktopChange", false );
118 bigCube = conf.readEntry( "BigCube", false );
119 capColor = conf.readEntry( "CapColor", KColorScheme( QPalette::Active, KColorScheme::Window ).background().color() );
120 paintCaps = conf.readEntry( "Caps", true );
121 closeOnMouseRelease = conf.readEntry( "CloseOnMouseRelease", false );
122 zPosition = conf.readEntry( "ZPosition", 100.0 );
123 useForTabBox = conf.readEntry( "TabBox", false );
124 QString file = conf.readEntry( "Wallpaper", QString("") );
125 delete wallpaper;
126 wallpaper = NULL;
127 if( !file.isEmpty() )
129 QImage img = QImage( file );
130 if( !img.isNull() )
132 wallpaper = new GLTexture( img );
135 delete capTexture;
136 capTexture = NULL;
137 texturedCaps = conf.readEntry( "TexturedCaps", true );
138 if( texturedCaps )
140 QString capPath = conf.readEntry( "CapPath", KGlobal::dirs()->findResource( "appdata", "cubecap.png" ) );
141 QImage img = QImage( capPath );
142 if( !img.isNull() )
144 // change the alpha value of each pixel
145 for( int x=0; x<img.width(); x++ )
147 for( int y=0; y<img.height(); y++ )
149 QRgb pixel = img.pixel( x, y );
150 if( x == 0 || x == img.width()-1 || y == 0 || y == img.height()-1 )
151 img.setPixel( x, y, qRgba( capColor.red(), capColor.green(), capColor.blue(), 255*cubeOpacity ) );
152 else
154 if( qAlpha(pixel) < 255 )
156 // Pixel is transparent - has to be blended with cap color
157 int red = (qAlpha(pixel)/255)*(qRed(pixel)/255) + (1 - qAlpha(pixel)/255 )*capColor.red();
158 int green = (qAlpha(pixel)/255)*(qGreen(pixel)/255) + (1 - qAlpha(pixel)/255 )*capColor.green();
159 int blue = (qAlpha(pixel)/255)*(qBlue(pixel)/255) + (1 - qAlpha(pixel)/255 )*capColor.blue();
160 int alpha = qAlpha(pixel) + (255 - qAlpha(pixel))*cubeOpacity;
161 img.setPixel( x, y, qRgba( red, green, blue, alpha ) );
163 else
165 img.setPixel( x, y, qRgba( qRed(pixel), qGreen(pixel), qBlue(pixel), ((float)qAlpha(pixel))*cubeOpacity ) );
170 capTexture = new GLTexture( img );
171 capTexture->setFilter( GL_LINEAR );
172 capTexture->setWrapMode( GL_CLAMP_TO_EDGE );
176 timeLine.setCurveShape( TimeLine::EaseInOutCurve );
177 timeLine.setDuration( rotationDuration );
179 verticalTimeLine.setCurveShape( TimeLine::EaseInOutCurve );
180 verticalTimeLine.setDuration( rotationDuration );
183 CubeEffect::~CubeEffect()
185 effects->unreserveElectricBorder( borderActivate );
186 delete wallpaper;
187 delete capTexture;
190 void CubeEffect::prePaintScreen( ScreenPrePaintData& data, int time )
192 if( activated )
194 data.mask |= PAINT_SCREEN_TRANSFORMED | Effect::PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS | PAINT_SCREEN_BACKGROUND_FIRST;
196 if( rotating || start || stop )
198 timeLine.addTime( time );
200 if( verticalRotating )
202 verticalTimeLine.addTime( time );
205 effects->prePaintScreen( data, time );
208 void CubeEffect::paintScreen( int mask, QRegion region, ScreenPaintData& data )
210 if( activated )
212 QRect rect = effects->clientArea( FullScreenArea, activeScreen, effects->currentDesktop());
213 if( effects->numScreens() > 1 && (slide || bigCube ) )
214 rect = effects->clientArea( FullArea, activeScreen, effects->currentDesktop() );
215 QRect fullRect = effects->clientArea( FullArea, activeScreen, effects->currentDesktop() );
217 // background
218 float clearColor[4];
219 glGetFloatv( GL_COLOR_CLEAR_VALUE, clearColor );
220 glClearColor( backgroundColor.redF(), backgroundColor.greenF(), backgroundColor.blueF(), 1.0 );
221 glClear( GL_COLOR_BUFFER_BIT );
222 glClearColor( clearColor[0], clearColor[1], clearColor[2], clearColor[3] );
224 // wallpaper
225 if( wallpaper && !slide )
227 wallpaper->bind();
228 wallpaper->render( region, rect );
229 wallpaper->unbind();
232 glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT );
233 glEnable( GL_BLEND );
234 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
236 if( effects->numScreens() > 1 && !slide && !bigCube )
238 windowsOnOtherScreens.clear();
239 // unfortunatelly we have to change the projection matrix in dual screen mode
240 glMatrixMode( GL_PROJECTION );
241 glPushMatrix();
242 glLoadIdentity();
243 float fovy = 60.0f;
244 float aspect = 1.0f;
245 float zNear = 0.1f;
246 float zFar = 100.0f;
247 float ymax = zNear * tan( fovy * M_PI / 360.0f );
248 float ymin = -ymax;
249 float xmin = ymin * aspect;
250 float xmax = ymax * aspect;
251 float xTranslate = 0.0;
252 float yTranslate = 0.0;
253 float xminFactor = 1.0;
254 float xmaxFactor = 1.0;
255 float yminFactor = 1.0;
256 float ymaxFactor = 1.0;
257 if( rect.x() == 0 && rect.width() != fullRect.width() )
259 // horizontal layout: left screen
260 xminFactor = (float)rect.width()/(float)fullRect.width();
261 xmaxFactor = ((float)fullRect.width()-(float)rect.width()*0.5f)/((float)fullRect.width()*0.5f);
262 xTranslate = (float)fullRect.width()*0.5f-(float)rect.width()*0.5f;
264 if( rect.x() != 0 && rect.width() != fullRect.width() )
266 // horizontal layout: right screen
267 xminFactor = ((float)fullRect.width()-(float)rect.width()*0.5f)/((float)fullRect.width()*0.5f);
268 xmaxFactor = (float)rect.width()/(float)fullRect.width();
269 xTranslate = (float)fullRect.width()*0.5f-(float)rect.width()*0.5f;
271 if( rect.y() == 0 && rect.height() != fullRect.height() )
273 // vertical layout: top screen
274 yminFactor = ((float)fullRect.height()-(float)rect.height()*0.5f)/((float)fullRect.height()*0.5f);
275 ymaxFactor = (float)rect.height()/(float)fullRect.height();
276 yTranslate = (float)fullRect.height()*0.5f-(float)rect.height()*0.5f;
278 if( rect.y() != 0 && rect.height() != fullRect.height() )
280 // vertical layout: bottom screen
281 yminFactor = (float)rect.height()/(float)fullRect.height();
282 ymaxFactor = ((float)fullRect.height()-(float)rect.height()*0.5f)/((float)fullRect.height()*0.5f);
283 yTranslate = (float)fullRect.height()*0.5f-(float)rect.height()*0.5f;
285 glFrustum( xmin*xminFactor, xmax*xmaxFactor, ymin*yminFactor, ymax*ymaxFactor, zNear, zFar );
286 glMatrixMode( GL_MODELVIEW );
287 glPushMatrix();
288 glTranslatef( xTranslate, yTranslate, 0.0 );
291 // reflection
292 if( reflection && (!slide) )
294 // restrict painting the reflections to the current screen
295 PaintClipper::push( QRegion( rect ));
296 glPushMatrix();
297 // we can use a huge scale factor (needed to calculate the rearground vertices)
298 // as we restrict with a PaintClipper painting on the current screen
299 float scaleFactor = 1000000 * tan( 60.0 * M_PI / 360.0f )/rect.height();
300 glScalef( 1.0, -1.0, 1.0 );
301 glTranslatef( 0.0, -rect.height()*2, 0.0 );
303 glEnable( GL_CLIP_PLANE0 );
304 reflectionPainting = true;
305 paintScene( mask, region, data );
306 reflectionPainting = false;
307 glDisable( GL_CLIP_PLANE0 );
309 glPopMatrix();
310 glPushMatrix();
311 if( effects->numScreens() > 1 && rect.x() != fullRect.x() && !slide && !bigCube )
313 // have to change the reflection area in horizontal layout and right screen
314 glTranslatef( -rect.x(), 0.0, 0.0 );
316 glTranslatef( rect.x() + rect.width()*0.5f, 0.0, 0.0 );
317 float vertices[] = {
318 -rect.width()*0.5f, rect.height(), 0.0,
319 rect.width()*0.5f, rect.height(), 0.0,
320 (float)rect.width()*scaleFactor, rect.height(), -5000,
321 -(float)rect.width()*scaleFactor, rect.height(), -5000 };
322 // foreground
323 float alpha = 0.7;
324 if( start )
325 alpha = 0.3 + 0.4 * timeLine.value();
326 if( stop )
327 alpha = 0.3 + 0.4 * ( 1.0 - timeLine.value() );
328 glColor4f( 0.0, 0.0, 0.0, alpha );
329 glBegin( GL_POLYGON );
330 glVertex3f( vertices[0], vertices[1], vertices[2] );
331 glVertex3f( vertices[3], vertices[4], vertices[5] );
332 // rearground
333 alpha = -1.0;
334 glColor4f( 0.0, 0.0, 0.0, alpha );
335 glVertex3f( vertices[6], vertices[7], vertices[8] );
336 glVertex3f( vertices[9], vertices[10], vertices[11] );
337 glEnd();
338 glPopMatrix();
339 PaintClipper::pop( QRegion( rect ));
341 glPushMatrix();
342 paintScene( mask, region, data );
343 glPopMatrix();
345 if( effects->numScreens() > 1 && !slide && !bigCube )
347 glPopMatrix();
348 // revert change of projection matrix
349 glMatrixMode( GL_PROJECTION );
350 glPopMatrix();
351 glMatrixMode( GL_MODELVIEW );
354 glDisable( GL_BLEND );
355 glPopAttrib();
357 // desktop name box - inspired from coverswitch
358 if( displayDesktopName && (!slide) )
360 QColor color_frame;
361 QColor color_text;
362 color_frame = KColorScheme( QPalette::Active, KColorScheme::Window ).background().color();
363 color_frame.setAlphaF( 0.5 );
364 color_text = KColorScheme( QPalette::Active, KColorScheme::Window ).foreground().color();
365 if( start )
367 color_frame.setAlphaF( 0.5 * timeLine.value() );
368 color_text.setAlphaF( timeLine.value() );
370 if( stop )
372 color_frame.setAlphaF( 0.5 - 0.5 * timeLine.value() );
373 color_text.setAlphaF( 1.0 - timeLine.value() );
375 QFont text_font;
376 text_font.setBold( true );
377 text_font.setPointSize( 14 );
378 glPushAttrib( GL_CURRENT_BIT );
379 glColor4f( color_frame.redF(), color_frame.greenF(), color_frame.blueF(), color_frame.alphaF());
380 QRect frameRect = QRect( rect.width()*0.33f + rect.x(),
381 rect.height() + rect.y() - QFontMetrics( text_font ).height() * 1.2f,
382 rect.width()*0.33f,
383 QFontMetrics( text_font ).height() * 1.2f );
384 renderRoundBoxWithEdge( frameRect );
385 effects->paintText( effects->desktopName( frontDesktop ),
386 frameRect.center(),
387 frameRect.width(),
388 color_text,
389 text_font );
390 glPopAttrib();
392 if( effects->numScreens() > 1 && !slide && !bigCube )
394 foreach( EffectWindow* w, windowsOnOtherScreens )
396 WindowPaintData wData( w );
397 if( start && !w->isDesktop() && !w->isDock() )
398 wData.opacity *= (1.0 - timeLine.value());
399 if( stop && !w->isDesktop() && !w->isDock() )
400 wData.opacity *= timeLine.value();
401 effects->paintWindow( w, 0, QRegion( w->x(), w->y(), w->width(), w->height() ), wData );
405 else
407 effects->paintScreen( mask, region, data );
411 void CubeEffect::paintScene( int mask, QRegion region, ScreenPaintData& data )
413 QRect rect = effects->clientArea( FullScreenArea, activeScreen, effects->currentDesktop());
414 if( effects->numScreens() > 1 && (slide || bigCube ) )
415 rect = effects->clientArea( FullArea, activeScreen, effects->currentDesktop() );
416 float xScale = 1.0;
417 float yScale = 1.0;
418 if( effects->numScreens() > 1 && !slide && !bigCube )
420 QRect fullRect = effects->clientArea( FullArea, activeScreen, effects->currentDesktop() );
421 xScale = (float)rect.width()/(float)fullRect.width();
422 yScale = (float)rect.height()/(float)fullRect.height();
423 if( start )
425 xScale = xScale + (1.0 - xScale) * (1.0 - timeLine.value());
426 yScale = yScale + (1.0 - yScale) * (1.0 - timeLine.value());
427 if( rect.x() > 0 )
428 glTranslatef( -rect.x()*(1.0 - timeLine.value()), 0.0, 0.0 );
429 if( rect.y() > 0 )
430 glTranslatef( 0.0, -rect.y()*(1.0 - timeLine.value()), 0.0 );
432 if( stop )
434 xScale = xScale + (1.0 - xScale) * timeLine.value();
435 yScale = yScale + (1.0 - yScale) * timeLine.value();
436 if( rect.x() > 0 )
437 glTranslatef( -rect.x()*timeLine.value(), 0.0, 0.0 );
438 if( rect.y() > 0 )
439 glTranslatef( 0.0, -rect.y()*timeLine.value(), 0.0 );
441 glScalef( xScale, yScale, 1.0 );
442 rect = fullRect;
444 int rightSteps = effects->numberOfDesktops()/2;
445 int leftSteps = rightSteps+1;
446 int rightSideCounter = 0;
447 int leftSideCounter = 0;
448 float internalCubeAngle = 360.0f / effects->numberOfDesktops();
449 cube_painting = true;
450 int desktopIndex = 0;
451 float zTranslate = zPosition + zoom;
452 if( start )
453 zTranslate *= timeLine.value();
454 if( stop )
455 zTranslate *= ( 1.0 - timeLine.value() );
456 if( slide )
457 zTranslate = 0.0;
459 bool topCapAfter = false;
460 bool topCapBefore = false;
462 // Rotation of the cube
463 float cubeAngle = (float)((float)(effects->numberOfDesktops() - 2 )/(float)effects->numberOfDesktops() * 180.0f);
464 float point = rect.width()/2*tan(cubeAngle*0.5f*M_PI/180.0f);
465 float zTexture = rect.width()/2*tan(45.0f*M_PI/180.0f);
466 if( verticalRotating || verticalPosition != Normal || manualVerticalAngle != 0.0 )
468 // change the verticalPosition if manualVerticalAngle > 90 or < -90 degrees
469 if( manualVerticalAngle <= -90.0 )
471 manualVerticalAngle += 90.0;
472 if( verticalPosition == Normal )
473 verticalPosition = Down;
474 if( verticalPosition == Up )
475 verticalPosition = Normal;
477 if( manualVerticalAngle >= 90.0 )
479 manualVerticalAngle -= 90.0;
480 if( verticalPosition == Normal )
481 verticalPosition = Up;
482 if( verticalPosition == Down )
483 verticalPosition = Normal;
485 float angle = 0.0;
486 if( verticalPosition == Up )
488 angle = 90.0;
489 if( !verticalRotating)
491 if( manualVerticalAngle < 0.0 )
492 angle += manualVerticalAngle;
493 else
494 manualVerticalAngle = 0.0;
497 else if( verticalPosition == Down )
499 angle = -90.0;
500 if( !verticalRotating)
502 if( manualVerticalAngle > 0.0 )
503 angle += manualVerticalAngle;
504 else
505 manualVerticalAngle = 0.0;
508 else
510 angle = manualVerticalAngle;
512 if( verticalRotating )
514 angle *= verticalTimeLine.value();
515 if( verticalPosition == Normal && verticalRotationDirection == Upwards )
516 angle = -90.0 + 90*verticalTimeLine.value();
517 if( verticalPosition == Normal && verticalRotationDirection == Downwards )
518 angle = 90.0 - 90*verticalTimeLine.value();
519 angle += manualVerticalAngle * (1.0-verticalTimeLine.value());
521 if( stop )
522 angle *= (1.0 - timeLine.value());
523 glTranslatef( rect.width()/2, rect.height()/2, -point-zTranslate );
524 glRotatef( angle, 1.0, 0.0, 0.0 );
525 glTranslatef( -rect.width()/2, -rect.height()/2, point+zTranslate );
527 // calculate if the caps have to be painted before/after or during desktop painting
528 if( paintCaps )
530 float M[16];
531 float P[16];
532 float V[4];
533 glGetFloatv( GL_PROJECTION_MATRIX, P );
534 glGetFloatv( GL_MODELVIEW_MATRIX, M );
535 glGetFloatv( GL_VIEWPORT, V );
537 // calculate y coordinate of the top of front desktop
538 float X = M[0]*0.0 + M[4]*0.0 + M[8]*(-zTranslate) + M[12]*1;
539 float Y = M[1]*0.0 + M[5]*0.0 + M[9]*(-zTranslate) + M[13]*1;
540 float Z = M[2]*0.0 + M[6]*0.0 + M[10]*(-zTranslate) + M[14]*1;
541 float W = M[3]*0.0 + M[7]*0.0 + M[11]*(-zTranslate) + M[15]*1;
542 float clipY = P[1]*X + P[5]*Y + P[9]*Z + P[13]*W;
543 float clipW = P[3]*X + P[7]*Y + P[11]*Z + P[15]*W;
544 float normY = clipY/clipW;
545 float yFront = (V[3]/2)*normY+(V[3]-V[1])/2;
547 // calculate y coordinate of the bottom of front desktop
548 X = M[0]*0.0 + M[4]*rect.height() + M[8]*(-zTranslate) + M[12]*1;
549 Y = M[1]*0.0 + M[5]*rect.height() + M[9]*(-zTranslate) + M[13]*1;
550 Z = M[2]*0.0 + M[6]*rect.height() + M[10]*(-zTranslate) + M[14]*1;
551 W = M[3]*0.0 + M[7]*rect.height() + M[11]*(-zTranslate) + M[15]*1;
552 clipY = P[1]*X + P[5]*Y + P[9]*Z + P[13]*W;
553 clipW = P[3]*X + P[7]*Y + P[11]*Z + P[15]*W;
554 normY = clipY/clipW;
555 float yFrontBottom = (V[3]/2)*normY+(V[3]-V[1])/2;
557 // change matrix to a rear position
558 glPushMatrix();
559 glTranslatef( 0.0, 0.0, -point-zTranslate );
560 float desktops = (effects->numberOfDesktops()/2.0);
561 glRotatef( desktops*internalCubeAngle, 1.0, 0.0, 0.0 );
562 glTranslatef( 0.0, 0.0, point );
563 glGetFloatv(GL_MODELVIEW_MATRIX, M);
564 // calculate y coordinate of the top of rear desktop
565 X = M[0]*0.0 + M[4]*0.0 + M[8]*0.0 + M[12]*1;
566 Y = M[1]*0.0 + M[5]*0.0 + M[9]*0.0 + M[13]*1;
567 Z = M[2]*0.0 + M[6]*0.0 + M[10]*0.0 + M[14]*1;
568 W = M[3]*0.0 + M[7]*0.0 + M[11]*0.0 + M[15]*1;
569 clipY = P[1]*X + P[5]*Y + P[9]*Z + P[13]*W;
570 clipW = P[3]*X + P[7]*Y + P[11]*Z + P[15]*W;
571 normY = clipY/clipW;
572 float yBack = (V[3]/2)*normY+(V[3]-V[1])/2;
574 // calculate y coordniate of the bottom of rear desktop
575 glTranslatef( 0.0, -rect.height(), 0.0 );
576 glGetFloatv(GL_MODELVIEW_MATRIX, M);
577 X = M[0]*0.0 + M[4]*0.0 + M[8]*0.0 + M[12]*1;
578 Y = M[1]*0.0 + M[5]*0.0 + M[9]*0.0 + M[13]*1;
579 Z = M[2]*0.0 + M[6]*0.0 + M[10]*0.0 + M[14]*1;
580 W = M[3]*0.0 + M[7]*0.0 + M[11]*0.0 + M[15]*1;
581 clipY = P[1]*X + P[5]*Y + P[9]*Z + P[13]*W;
582 clipW = P[3]*X + P[7]*Y + P[11]*Z + P[15]*W;
583 normY = clipY/clipW;
584 float yBackBottom = (V[3]/2)*normY+(V[3]-V[1])/2;
585 glPopMatrix();
586 if( yBack >= yFront )
587 topCapAfter = true;
588 if( yBackBottom <= yFrontBottom )
589 topCapBefore = true;
592 if( rotating || (manualAngle != 0.0) )
594 int tempFrontDesktop = frontDesktop;
595 if( manualAngle > internalCubeAngle * 0.5f )
597 manualAngle -= internalCubeAngle;
598 tempFrontDesktop--;
599 if( tempFrontDesktop == 0 )
600 tempFrontDesktop = effects->numberOfDesktops();
602 if( manualAngle < -internalCubeAngle * 0.5f )
604 manualAngle += internalCubeAngle;
605 tempFrontDesktop++;
606 if( tempFrontDesktop > effects->numberOfDesktops() )
607 tempFrontDesktop = 1;
609 float rotationAngle = internalCubeAngle * timeLine.value();
610 if( rotationAngle > internalCubeAngle * 0.5f )
612 rotationAngle -= internalCubeAngle;
613 if( !desktopChangedWhileRotating )
615 desktopChangedWhileRotating = true;
616 if( rotationDirection == Left )
618 tempFrontDesktop++;
620 else if( rotationDirection == Right )
622 tempFrontDesktop--;
624 if( tempFrontDesktop > effects->numberOfDesktops() )
625 tempFrontDesktop = 1;
626 else if( tempFrontDesktop == 0 )
627 tempFrontDesktop = effects->numberOfDesktops();
630 // don't change front desktop during stop animation as this would break some logic
631 if( !stop )
632 frontDesktop = tempFrontDesktop;
633 if( rotationDirection == Left )
635 rotationAngle *= -1;
637 if( stop )
638 rotationAngle = manualAngle * (1.0 - timeLine.value());
639 else
640 rotationAngle += manualAngle * (1.0 - timeLine.value());
641 glTranslatef( rect.width()/2, rect.height()/2, -point-zTranslate );
642 glRotatef( rotationAngle, 0.0, 1.0, 0.0 );
643 glTranslatef( -rect.width()/2, -rect.height()/2, point+zTranslate );
646 if( topCapBefore || topCapAfter )
648 if( (topCapAfter && !reflectionPainting) || (topCapBefore && reflectionPainting) )
650 // paint the bottom cap
651 bottomCap = true;
652 glTranslatef( 0.0, rect.height(), 0.0 );
653 paintCap( point, zTexture );
654 glTranslatef( 0.0, -rect.height(), 0.0 );
655 bottomCap = false;
657 if( (topCapBefore && !reflectionPainting) || (topCapAfter && reflectionPainting) )
659 // paint the top cap
660 paintCap( point, zTexture );
664 for( int i=0; i<effects->numberOfDesktops(); i++ )
666 if( !topCapAfter && !topCapBefore && i == effects->numberOfDesktops()/2 -1 && !slide )
668 // paint the bottom cap
669 bottomCap = true;
670 glTranslatef( 0.0, rect.height(), 0.0 );
671 paintCap( point, zTexture );
672 glTranslatef( 0.0, -rect.height(), 0.0 );
673 bottomCap = false;
674 // paint the top cap
675 paintCap( point, zTexture );
677 if( i%2 == 0 && i != effects->numberOfDesktops() -1)
679 // desktops on the right (including back)
680 desktopIndex = rightSteps - rightSideCounter;
681 rightSideCounter++;
683 else
685 // desktops on the left (including front)
686 desktopIndex = leftSteps + leftSideCounter;
687 leftSideCounter++;
690 // start painting the cube
691 painting_desktop = (desktopIndex + frontDesktop )%effects->numberOfDesktops();
692 if( painting_desktop == 0 )
694 painting_desktop = effects->numberOfDesktops();
696 if( slide )
698 // only paint required desktops during slide phase
699 if( painting_desktop != frontDesktop )
701 int leftDesktop = frontDesktop - 1;
702 int rightDesktop = frontDesktop + 1;
703 if( leftDesktop == 0 )
704 leftDesktop = effects->numberOfDesktops();
705 if( rightDesktop > effects->numberOfDesktops() )
706 rightDesktop = 1;
707 if( !desktopChangedWhileRotating && rotationDirection == Left && painting_desktop != rightDesktop )
709 continue;
711 if( desktopChangedWhileRotating && rotationDirection == Left && painting_desktop != leftDesktop )
713 continue;
715 if( !desktopChangedWhileRotating && rotationDirection == Right && painting_desktop != leftDesktop )
717 continue;
719 if( desktopChangedWhileRotating && rotationDirection == Right && painting_desktop != rightDesktop )
721 continue;
725 ScreenPaintData newData = data;
726 RotationData rot = RotationData();
727 rot.axis = RotationData::YAxis;
728 rot.angle = internalCubeAngle * desktopIndex;
729 rot.xRotationPoint = rect.width()/2;
730 rot.zRotationPoint = -point;
731 newData.rotation = &rot;
732 newData.zTranslate = -zTranslate;
733 effects->paintScreen( mask, region, newData );
735 if( topCapBefore || topCapAfter )
737 if( (topCapAfter && !reflectionPainting) || (topCapBefore && reflectionPainting) )
739 // paint the top cap
740 paintCap( point, zTexture );
742 if( (topCapBefore && !reflectionPainting) || (topCapAfter && reflectionPainting) )
744 // paint the bottom cap
745 bottomCap = true;
746 glTranslatef( 0.0, rect.height(), 0.0 );
747 paintCap( point, zTexture );
748 glTranslatef( 0.0, -rect.height(), 0.0 );
749 bottomCap = false;
752 cube_painting = false;
753 painting_desktop = effects->currentDesktop();
756 void CubeEffect::paintCap( float z, float zTexture )
758 QRect rect = effects->clientArea( FullArea, activeScreen, effects->currentDesktop());
759 if( ( !paintCaps ) || effects->numberOfDesktops() <= 2 )
760 return;
761 float opacity = cubeOpacity;
762 if( start )
763 opacity = 1.0 - (1.0 - opacity)*timeLine.value();
764 if( stop )
765 opacity = 1.0 - (1.0 - opacity)*( 1.0 - timeLine.value() );
766 glColor4f( capColor.redF(), capColor.greenF(), capColor.blueF(), opacity );
767 float angle = 360.0f/effects->numberOfDesktops();
768 glPushMatrix();
769 float zTranslate = zPosition + zoom;
770 if( start )
771 zTranslate *= timeLine.value();
772 if( stop )
773 zTranslate *= ( 1.0 - timeLine.value() );
774 glTranslatef( rect.width()/2, 0.0, -z-zTranslate );
775 glRotatef( (1-frontDesktop)*angle, 0.0, 1.0, 0.0 );
777 if( !capListCreated )
779 capListCreated = true;
780 glNewList( capList, GL_COMPILE_AND_EXECUTE );
781 bool texture = false;
782 if( texturedCaps && effects->numberOfDesktops() > 3 && capTexture )
784 texture = true;
785 paintCapStep( z, zTexture, true );
787 else
788 paintCapStep( z, zTexture, false );
789 glEndList();
791 else
792 glCallList( capList );
793 glPopMatrix();
796 void CubeEffect::paintCapStep( float z, float zTexture, bool texture )
798 QRect rect = effects->clientArea( FullArea, activeScreen, effects->currentDesktop());
799 float angle = 360.0f/effects->numberOfDesktops();
800 if( texture )
801 capTexture->bind();
802 for( int i=0; i<effects->numberOfDesktops(); i++ )
804 int triangleRows = effects->numberOfDesktops()*5;
805 float zTriangleDistance = z/(float)triangleRows;
806 float widthTriangle = tan( angle*0.5 * M_PI/180.0 ) * zTriangleDistance;
807 float currentWidth = 0.0;
808 glBegin( GL_TRIANGLES );
809 float cosValue = cos( i*angle * M_PI/180.0 );
810 float sinValue = sin( i*angle * M_PI/180.0 );
811 for( int j=0; j<triangleRows; j++ )
813 float previousWidth = currentWidth;
814 currentWidth = tan( angle*0.5 * M_PI/180.0 ) * zTriangleDistance * (j+1);
815 int evenTriangles = 0;
816 int oddTriangles = 0;
817 for( int k=0; k<floor(currentWidth/widthTriangle*2-1+0.5f); k++ )
819 float x1 = -previousWidth;
820 float x2 = -currentWidth;
821 float x3 = 0.0;
822 float z1 = 0.0;
823 float z2 = 0.0;
824 float z3 = 0.0;
825 if( k%2 == 0 )
827 x1 += evenTriangles*widthTriangle*2;
828 x2 += evenTriangles*widthTriangle*2;
829 x3 = x2+widthTriangle*2;
830 z1 = j*zTriangleDistance;
831 z2 = (j+1)*zTriangleDistance;
832 z3 = (j+1)*zTriangleDistance;
833 float xRot = cosValue * x1 - sinValue * z1;
834 float zRot = sinValue * x1 + cosValue * z1;
835 x1 = xRot;
836 z1 = zRot;
837 xRot = cosValue * x2 - sinValue * z2;
838 zRot = sinValue * x2 + cosValue * z2;
839 x2 = xRot;
840 z2 = zRot;
841 xRot = cosValue * x3 - sinValue * z3;
842 zRot = sinValue * x3 + cosValue * z3;
843 x3 = xRot;
844 z3 = zRot;
845 evenTriangles++;
847 else
849 x1 += oddTriangles*widthTriangle*2;
850 x2 += (oddTriangles+1)*widthTriangle*2;
851 x3 = x1+widthTriangle*2;
852 z1 = j*zTriangleDistance;
853 z2 = (j+1)*zTriangleDistance;
854 z3 = j*zTriangleDistance;
855 float xRot = cosValue * x1 - sinValue * z1;
856 float zRot = sinValue * x1 + cosValue * z1;
857 x1 = xRot;
858 z1 = zRot;
859 xRot = cosValue * x2 - sinValue * z2;
860 zRot = sinValue * x2 + cosValue * z2;
861 x2 = xRot;
862 z2 = zRot;
863 xRot = cosValue * x3 - sinValue * z3;
864 zRot = sinValue * x3 + cosValue * z3;
865 x3 = xRot;
866 z3 = zRot;
867 oddTriangles++;
869 float texX1 = 0.0;
870 float texX2 = 0.0;
871 float texX3 = 0.0;
872 float texY1 = 0.0;
873 float texY2 = 0.0;
874 float texY3 = 0.0;
875 if( texture )
877 texX1 = x1/(rect.width())+0.5;
878 texY1 = 0.5 - z1/zTexture * 0.5;
879 texX2 = x2/(rect.width())+0.5;
880 texY2 = 0.5 - z2/zTexture * 0.5;
881 texX3 = x3/(rect.width())+0.5;
882 texY3 = 0.5 - z3/zTexture * 0.5;
883 glTexCoord2f( texX1, texY1 );
885 glVertex3f( x1, 0.0, z1 );
886 if( texture )
888 glTexCoord2f( texX2, texY2 );
890 glVertex3f( x2, 0.0, z2 );
891 if( texture )
893 glTexCoord2f( texX3, texY3 );
895 glVertex3f( x3, 0.0, z3 );
898 glEnd();
900 if( texture )
902 capTexture->unbind();
906 void CubeEffect::postPaintScreen()
908 effects->postPaintScreen();
909 if( activated )
911 if( start )
913 if( timeLine.value() == 1.0 )
915 start = false;
916 timeLine.setProgress(0.0);
917 // more rotations?
918 if( !rotations.empty() )
920 rotationDirection = rotations.dequeue();
921 rotating = true;
922 // change the curve shape if current shape is not easeInOut
923 if( currentShape != TimeLine::EaseInOutCurve )
925 // more rotations follow -> linear curve
926 if( !rotations.empty() )
928 currentShape = TimeLine::LinearCurve;
930 // last rotation step -> easeOut curve
931 else
933 currentShape = TimeLine::EaseOutCurve;
935 timeLine.setCurveShape( currentShape );
937 else
939 // if there is at least one more rotation, we can change to easeIn
940 if( !rotations.empty() )
942 currentShape = TimeLine::EaseInCurve;
943 timeLine.setCurveShape( currentShape );
948 effects->addRepaintFull();
949 return; // schedule_close could have been called, start has to finish first
951 if( stop )
953 if( timeLine.value() == 1.0 )
955 effects->setCurrentDesktop( frontDesktop );
956 stop = false;
957 timeLine.setProgress(0.0);
958 activated = false;
959 // set the new desktop
960 if( keyboard_grab )
961 effects->ungrabKeyboard();
962 keyboard_grab = false;
963 effects->destroyInputWindow( input );
965 effects->setActiveFullScreenEffect( 0 );
967 // delete the GL lists
968 glDeleteLists( capList, 1 );
970 effects->addRepaintFull();
972 if( rotating || verticalRotating )
974 if( rotating && timeLine.value() == 1.0 )
976 timeLine.setProgress(0.0);
977 rotating = false;
978 desktopChangedWhileRotating = false;
979 manualAngle = 0.0;
980 // more rotations?
981 if( !rotations.empty() )
983 rotationDirection = rotations.dequeue();
984 rotating = true;
985 // change the curve shape if current shape is not easeInOut
986 if( currentShape != TimeLine::EaseInOutCurve )
988 // more rotations follow -> linear curve
989 if( !rotations.empty() )
991 currentShape = TimeLine::LinearCurve;
993 // last rotation step -> easeOut curve
994 else
996 currentShape = TimeLine::EaseOutCurve;
998 timeLine.setCurveShape( currentShape );
1000 else
1002 // if there is at least one more rotation, we can change to easeIn
1003 if( !rotations.empty() )
1005 currentShape = TimeLine::EaseInCurve;
1006 timeLine.setCurveShape( currentShape );
1010 else
1012 // reset curve shape if there are no more rotations
1013 if( currentShape != TimeLine::EaseInOutCurve )
1015 currentShape = TimeLine::EaseInOutCurve;
1016 timeLine.setCurveShape( currentShape );
1020 if( verticalRotating && verticalTimeLine.value() == 1.0 )
1022 verticalTimeLine.setProgress(0.0);
1023 verticalRotating = false;
1024 manualVerticalAngle = 0.0;
1025 // more rotations?
1026 if( !verticalRotations.empty() )
1028 verticalRotationDirection = verticalRotations.dequeue();
1029 verticalRotating = true;
1030 if( verticalRotationDirection == Upwards )
1032 if( verticalPosition == Normal )
1033 verticalPosition = Up;
1034 if( verticalPosition == Down )
1035 verticalPosition = Normal;
1037 if( verticalRotationDirection == Downwards )
1039 if( verticalPosition == Normal )
1040 verticalPosition = Down;
1041 if( verticalPosition == Up )
1042 verticalPosition = Normal;
1046 effects->addRepaintFull();
1047 return; // rotation has to end before cube is closed
1049 if( schedule_close )
1051 schedule_close = false;
1052 if( !slide )
1054 stop = true;
1056 else
1058 activated = false;
1059 slide = false;
1060 timeLine.setDuration( rotationDuration );
1061 effects->setActiveFullScreenEffect( 0 );
1063 effects->addRepaintFull();
1068 void CubeEffect::prePaintWindow( EffectWindow* w, WindowPrePaintData& data, int time )
1070 if( activated )
1072 if( cube_painting )
1074 if( ( w->isDesktop() || w->isDock() ) && w->screen() != activeScreen && w->isOnDesktop( effects->currentDesktop() ) )
1076 windowsOnOtherScreens.append( w );
1078 if( (start || stop) && w->screen() != activeScreen && w->isOnDesktop( effects->currentDesktop() )
1079 && !w->isDesktop() && !w->isDock() )
1081 windowsOnOtherScreens.append( w );
1083 if( w->isOnDesktop( painting_desktop ))
1085 QRect rect = effects->clientArea( FullArea, activeScreen, painting_desktop );
1086 if( w->x() < rect.x() )
1088 data.quads = data.quads.splitAtX( -w->x() );
1090 if( w->x() + w->width() > rect.x() + rect.width() )
1092 data.quads = data.quads.splitAtX( rect.width() - w->x() );
1094 if( w->y() < rect.y() )
1096 data.quads = data.quads.splitAtY( -w->y() );
1098 if( w->y() + w->height() > rect.y() + rect.height() )
1100 data.quads = data.quads.splitAtY( rect.height() - w->y() );
1102 w->enablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP );
1104 else
1106 // check for windows belonging to the previous desktop
1107 int prev_desktop = painting_desktop -1;
1108 if( prev_desktop == 0 )
1109 prev_desktop = effects->numberOfDesktops();
1110 if( w->isOnDesktop( prev_desktop ) )
1112 QRect rect = effects->clientArea( FullArea, activeScreen, prev_desktop);
1113 if( w->x()+w->width() > rect.x() + rect.width() )
1115 w->enablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP );
1116 data.quads = data.quads.splitAtX( rect.width() - w->x() );
1117 if( w->y() < rect.y() )
1119 data.quads = data.quads.splitAtY( -w->y() );
1121 if( w->y() + w->height() > rect.y() + rect.height() )
1123 data.quads = data.quads.splitAtY( rect.height() - w->y() );
1125 data.setTransformed();
1126 effects->prePaintWindow( w, data, time );
1127 return;
1130 // check for windows belonging to the next desktop
1131 int next_desktop = painting_desktop +1;
1132 if( next_desktop > effects->numberOfDesktops() )
1133 next_desktop = 1;
1134 if( w->isOnDesktop( next_desktop ) )
1136 QRect rect = effects->clientArea( FullArea, activeScreen, next_desktop);
1137 if( w->x() < rect.x() )
1139 w->enablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP );
1140 data.quads = data.quads.splitAtX( -w->x() );
1141 if( w->y() < rect.y() )
1143 data.quads = data.quads.splitAtY( -w->y() );
1145 if( w->y() + w->height() > rect.y() + rect.height() )
1147 data.quads = data.quads.splitAtY( rect.height() - w->y() );
1149 data.setTransformed();
1150 effects->prePaintWindow( w, data, time );
1151 return;
1154 w->disablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP );
1158 effects->prePaintWindow( w, data, time );
1161 void CubeEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
1163 if( activated && cube_painting )
1165 //kDebug(1212) << w->caption();
1166 float opacity = cubeOpacity;
1167 if( slide )
1168 opacity = 1.0f;
1169 if( start )
1171 opacity = 1.0 - (1.0 - opacity)*timeLine.value();
1172 if( reflectionPainting )
1173 opacity = 0.5 + ( cubeOpacity - 0.5 )*timeLine.value();
1174 // fade in windows belonging to different desktops
1175 if( painting_desktop == effects->currentDesktop() && (!w->isOnDesktop( painting_desktop )) )
1176 opacity = timeLine.value() * cubeOpacity;
1178 if( stop )
1180 opacity = 1.0 - (1.0 - opacity)*( 1.0 - timeLine.value() );
1181 if( reflectionPainting )
1182 opacity = 0.5 + ( cubeOpacity - 0.5 )*( 1.0 - timeLine.value() );
1183 // fade out windows belonging to different desktops
1184 if( painting_desktop == effects->currentDesktop() && (!w->isOnDesktop( painting_desktop )) )
1185 opacity = cubeOpacity * (1.0 - timeLine.value());
1187 bool slideOpacity = false;
1188 // fade in windows from different desktops in first slide step
1189 if( slide && painting_desktop == oldDesktop && (!w->isOnDesktop( painting_desktop )) )
1191 opacity = timeLine.value();
1192 slideOpacity = true;
1194 // fade out windows from different desktops in last slide step
1195 if( slide && rotations.empty() && painting_desktop == effects->currentDesktop() && (!w->isOnDesktop( painting_desktop )) )
1197 opacity = 1.0 - timeLine.value();
1198 slideOpacity = true;
1200 // check for windows belonging to the previous desktop
1201 int prev_desktop = painting_desktop -1;
1202 if( prev_desktop == 0 )
1203 prev_desktop = effects->numberOfDesktops();
1204 int next_desktop = painting_desktop +1;
1205 if( next_desktop > effects->numberOfDesktops() )
1206 next_desktop = 1;
1207 if( w->isOnDesktop( prev_desktop ) && ( mask & PAINT_WINDOW_TRANSFORMED ) )
1209 QRect rect = effects->clientArea( FullArea, activeScreen, prev_desktop);
1210 data.xTranslate = -rect.width();
1211 WindowQuadList new_quads;
1212 foreach( const WindowQuad &quad, data.quads )
1214 if( quad.right() > rect.width() - w->x() )
1216 new_quads.append( quad );
1219 data.quads = new_quads;
1221 if( w->isOnDesktop( next_desktop ) && ( mask & PAINT_WINDOW_TRANSFORMED ) )
1223 QRect rect = effects->clientArea( FullArea, activeScreen, next_desktop);
1224 data.xTranslate = rect.width();
1225 WindowQuadList new_quads;
1226 foreach( const WindowQuad &quad, data.quads )
1228 if( w->x() + quad.right() <= rect.x() )
1230 new_quads.append( quad );
1233 data.quads = new_quads;
1235 QRect rect = effects->clientArea( FullArea, activeScreen, painting_desktop );
1237 if( start || stop )
1239 // we have to change opacity values for fade in/out of windows which are shown on front-desktop
1240 if( prev_desktop == effects->currentDesktop() && w->x() < rect.x() )
1242 if( start )
1243 opacity = timeLine.value() * cubeOpacity;
1244 if( stop )
1245 opacity = cubeOpacity * (1.0 - timeLine.value());
1247 if( next_desktop == effects->currentDesktop() && w->x() + w->width() > rect.x() + rect.width() )
1249 if( start )
1250 opacity = timeLine.value() * cubeOpacity;
1251 if( stop )
1252 opacity = cubeOpacity * (1.0 - timeLine.value());
1255 if( !slide || (slide && !w->isDesktop()) || slideOpacity )
1257 // HACK set opacity to 0.99 in case of fully opaque to ensure that windows are painted in correct sequence
1258 // bug #173214
1259 if( opacity > 0.99f )
1260 opacity = 0.99f;
1261 data.opacity *= opacity;
1264 if( w->isOnDesktop(painting_desktop) && w->x() < rect.x() )
1266 WindowQuadList new_quads;
1267 foreach( const WindowQuad &quad, data.quads )
1269 if( quad.right() > -w->x() )
1271 new_quads.append( quad );
1274 data.quads = new_quads;
1276 if( w->isOnDesktop(painting_desktop) && w->x() + w->width() > rect.x() + rect.width() )
1278 WindowQuadList new_quads;
1279 foreach( const WindowQuad &quad, data.quads )
1281 if( quad.right() <= rect.width() - w->x() )
1283 new_quads.append( quad );
1286 data.quads = new_quads;
1288 if( w->y() < rect.y() )
1290 WindowQuadList new_quads;
1291 foreach( const WindowQuad &quad, data.quads )
1293 if( quad.bottom() > -w->y() )
1295 new_quads.append( quad );
1298 data.quads = new_quads;
1300 if( w->y() + w->height() > rect.y() + rect.height() )
1302 WindowQuadList new_quads;
1303 foreach( const WindowQuad &quad, data.quads )
1305 if( quad.bottom() <= rect.height() - w->y() )
1307 new_quads.append( quad );
1310 data.quads = new_quads;
1313 effects->paintWindow( w, mask, region, data );
1316 bool CubeEffect::borderActivated( ElectricBorder border )
1318 if( effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this )
1319 return false;
1320 if( border == borderActivate && !activated )
1322 kDebug(1212) << "border activated";
1323 toggle();
1324 return true;
1326 return false;
1329 void CubeEffect::toggle()
1331 if( effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this ||
1332 effects->numberOfDesktops() < 2 )
1333 return;
1334 if( !activated )
1336 setActive( true );
1338 else
1340 setActive( false );
1344 void CubeEffect::grabbedKeyboardEvent( QKeyEvent* e )
1346 if( stop )
1347 return;
1348 // taken from desktopgrid.cpp
1349 if( e->type() == QEvent::KeyPress )
1351 int desktop = -1;
1352 // switch by F<number> or just <number>
1353 if( e->key() >= Qt::Key_F1 && e->key() <= Qt::Key_F35 )
1354 desktop = e->key() - Qt::Key_F1 + 1;
1355 else if( e->key() >= Qt::Key_0 && e->key() <= Qt::Key_9 )
1356 desktop = e->key() == Qt::Key_0 ? 10 : e->key() - Qt::Key_0;
1357 if( desktop != -1 )
1359 if( desktop <= effects->numberOfDesktops())
1361 // we have to rotate to chosen desktop
1362 // and end effect when rotation finished
1363 rotateToDesktop( desktop );
1364 setActive( false );
1366 return;
1368 switch( e->key())
1369 { // wrap only on autorepeat
1370 case Qt::Key_Left:
1371 // rotate to previous desktop
1372 kDebug(1212) << "left";
1373 if( !rotating && !start )
1375 rotating = true;
1376 rotationDirection = Left;
1378 else
1380 if( rotations.count() < effects->numberOfDesktops() )
1381 rotations.enqueue( Left );
1383 break;
1384 case Qt::Key_Right:
1385 // rotate to next desktop
1386 kDebug(1212) << "right";
1387 if( !rotating && !start )
1389 rotating = true;
1390 rotationDirection = Right;
1392 else
1394 if( rotations.count() < effects->numberOfDesktops() )
1395 rotations.enqueue( Right );
1397 break;
1398 case Qt::Key_Up:
1399 kDebug(1212) << "up";
1400 if( verticalPosition != Up )
1402 if( !verticalRotating )
1404 verticalRotating = true;
1405 verticalRotationDirection = Upwards;
1406 if( verticalPosition == Normal )
1407 verticalPosition = Up;
1408 if( verticalPosition == Down )
1409 verticalPosition = Normal;
1411 else
1413 verticalRotations.enqueue( Upwards );
1416 else if( manualVerticalAngle < 0.0 && !verticalRotating )
1418 // rotate to up position from the manual position
1419 verticalRotating = true;
1420 verticalRotationDirection = Upwards;
1421 verticalPosition = Up;
1422 manualVerticalAngle += 90.0;
1424 break;
1425 case Qt::Key_Down:
1426 kDebug(1212) << "down";
1427 if( verticalPosition != Down )
1429 if( !verticalRotating )
1431 verticalRotating = true;
1432 verticalRotationDirection = Downwards;
1433 if( verticalPosition == Normal )
1434 verticalPosition = Down;
1435 if( verticalPosition == Up )
1436 verticalPosition = Normal;
1438 else
1440 verticalRotations.enqueue( Downwards );
1443 else if( manualVerticalAngle > 0.0 && !verticalRotating )
1445 // rotate to down position from the manual position
1446 verticalRotating = true;
1447 verticalRotationDirection = Downwards;
1448 verticalPosition = Down;
1449 manualVerticalAngle -= 90.0;
1451 break;
1452 case Qt::Key_Escape:
1453 rotateToDesktop( effects->currentDesktop() );
1454 setActive( false );
1455 return;
1456 case Qt::Key_Enter:
1457 case Qt::Key_Return:
1458 case Qt::Key_Space:
1459 setActive( false );
1460 return;
1461 case Qt::Key_Plus:
1462 zoom -= 10.0;
1463 zoom = qMax( -zPosition, zoom );
1464 break;
1465 case Qt::Key_Minus:
1466 zoom += 10.0f;
1467 break;
1468 default:
1469 break;
1471 effects->addRepaintFull();
1475 void CubeEffect::rotateToDesktop( int desktop )
1477 int tempFrontDesktop = frontDesktop;
1478 if( !rotations.empty() )
1480 // all scheduled rotations will be removed as a speed up
1481 rotations.clear();
1483 if( rotating && !desktopChangedWhileRotating )
1485 // front desktop will change during the actual rotation - this has to be considered
1486 if( rotationDirection == Left )
1488 tempFrontDesktop++;
1490 else if( rotationDirection == Right )
1492 tempFrontDesktop--;
1494 if( tempFrontDesktop > effects->numberOfDesktops() )
1495 tempFrontDesktop = 1;
1496 else if( tempFrontDesktop == 0 )
1497 tempFrontDesktop = effects->numberOfDesktops();
1499 // find the fastest rotation path from tempFrontDesktop to desktop
1500 int rightRotations = tempFrontDesktop - desktop;
1501 if( rightRotations < 0 )
1502 rightRotations += effects->numberOfDesktops();
1503 int leftRotations = desktop - tempFrontDesktop;
1504 if( leftRotations < 0 )
1505 leftRotations += effects->numberOfDesktops();
1506 if( leftRotations <= rightRotations )
1508 for( int i=0; i<leftRotations; i++ )
1510 rotations.enqueue( Left );
1513 else
1515 for( int i=0; i<rightRotations; i++ )
1517 rotations.enqueue( Right );
1520 if( !start && !rotating && !rotations.empty() )
1522 rotating = true;
1523 rotationDirection = rotations.dequeue();
1525 // change timeline curve if more rotations are following
1526 if( !rotations.empty() )
1528 currentShape = TimeLine::EaseInCurve;
1529 timeLine.setCurveShape( currentShape );
1530 // change timeline duration in slide mode
1531 if( slide )
1532 timeLine.setDuration( rotationDuration / (rotations.count()+1) );
1536 void CubeEffect::setActive( bool active )
1538 if( active )
1540 activated = true;
1541 activeScreen = effects->activeScreen();
1542 if( !slide )
1544 keyboard_grab = effects->grabKeyboard( this );
1545 input = effects->createInputWindow( this, 0, 0, displayWidth(), displayHeight(),
1546 Qt::OpenHandCursor );
1547 frontDesktop = effects->currentDesktop();
1548 zoom = 0.0;
1549 start = true;
1551 effects->setActiveFullScreenEffect( this );
1552 kDebug(1212) << "Cube is activated";
1553 verticalPosition = Normal;
1554 verticalRotating = false;
1555 manualAngle = 0.0;
1556 manualVerticalAngle = 0.0;
1557 if( reflection && !slide )
1559 // clip parts above the reflection area
1560 double eqn[4] = {0.0, 1.0, 0.0, 0.0};
1561 glPushMatrix();
1562 QRect rect = effects->clientArea( FullScreenArea, activeScreen, effects->currentDesktop());
1563 if( effects->numScreens() > 1 && bigCube )
1564 rect = effects->clientArea( FullArea, activeScreen, effects->currentDesktop() );
1565 glTranslatef( 0.0, rect.height(), 0.0 );
1566 glClipPlane( GL_CLIP_PLANE0, eqn );
1567 glPopMatrix();
1569 // create the needed GL lists
1570 capList = glGenLists(1);
1571 capListCreated = false;
1573 effects->addRepaintFull();
1575 else
1577 schedule_close = true;
1578 // we have to add a repaint, to start the deactivating
1579 effects->addRepaintFull();
1583 void CubeEffect::mouseChanged( const QPoint& pos, const QPoint& oldpos, Qt::MouseButtons buttons,
1584 Qt::MouseButtons oldbuttons, Qt::KeyboardModifiers modifiers, Qt::KeyboardModifiers oldmodifiers )
1586 if( !activated )
1587 return;
1588 if( tabBoxMode )
1589 return;
1590 if( stop || slide )
1591 return;
1592 QRect rect = effects->clientArea( FullScreenArea, activeScreen, effects->currentDesktop());
1593 if( effects->numScreens() > 1 && (slide || bigCube ) )
1594 rect = effects->clientArea( FullArea, activeScreen, effects->currentDesktop() );
1595 if( buttons.testFlag( Qt::LeftButton ) )
1597 bool repaint = false;
1598 // vertical movement only if there is not a rotation
1599 if( !verticalRotating )
1601 // display height corresponds to 180*
1602 int deltaY = pos.y() - oldpos.y();
1603 float deltaVerticalDegrees = (float)deltaY/rect.height()*180.0f;
1604 manualVerticalAngle -= deltaVerticalDegrees;
1605 if( deltaVerticalDegrees != 0.0 )
1606 repaint = true;
1608 // horizontal movement only if there is not a rotation
1609 if( !rotating )
1611 // display width corresponds to sum of angles of the polyhedron
1612 int deltaX = oldpos.x() - pos.x();
1613 float deltaDegrees = (float)deltaX/rect.width() * 360.0f;
1614 manualAngle -= deltaDegrees;
1615 if( deltaDegrees != 0.0 )
1616 repaint = true;
1618 if( repaint )
1619 effects->addRepaintFull();
1621 if( !oldbuttons.testFlag( Qt::LeftButton ) && buttons.testFlag( Qt::LeftButton ) )
1623 XDefineCursor( display(), input, QCursor( Qt::ClosedHandCursor).handle() );
1625 if( oldbuttons.testFlag( Qt::LeftButton) && !buttons.testFlag( Qt::LeftButton ) )
1627 XDefineCursor( display(), input, QCursor( Qt::OpenHandCursor).handle() );
1628 if( closeOnMouseRelease )
1629 setActive( false );
1631 if( oldbuttons.testFlag( Qt::RightButton) && !buttons.testFlag( Qt::RightButton ) )
1633 // end effect on right mouse button
1634 setActive( false );
1638 void CubeEffect::desktopChanged( int old )
1640 if( effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this )
1641 return;
1642 if( activated )
1643 return;
1644 if( !animateDesktopChange )
1645 return;
1646 slide = true;
1647 oldDesktop = old;
1648 setActive( true );
1649 frontDesktop = old;
1650 rotateToDesktop( effects->currentDesktop() );
1651 setActive( false );
1655 void CubeEffect::tabBoxAdded( int mode )
1657 if( activated )
1658 return;
1659 if( effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this )
1660 return;
1661 if( useForTabBox && mode != TabBoxWindowsMode )
1663 effects->refTabBox();
1664 tabBoxMode = true;
1665 setActive( true );
1666 rotateToDesktop( effects->currentTabBoxDesktop() );
1670 void CubeEffect::tabBoxUpdated()
1672 if( activated )
1673 rotateToDesktop( effects->currentTabBoxDesktop() );
1676 void CubeEffect::tabBoxClosed()
1678 if( activated )
1680 effects->unrefTabBox();
1681 tabBoxMode = false;
1682 setActive( false );
1686 } // namespace