add more spacing
[personal-kdebase.git] / workspace / kwin / effects / flipswitch.cpp
blob1c6583a491321282f89de84badd360019f458e2c
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 "flipswitch.h"
22 #include <kwinconfig.h>
23 #include <QFont>
24 #include <kapplication.h>
25 #include <kcolorscheme.h>
26 #include <kconfiggroup.h>
28 #include <kwinglutils.h>
30 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
31 #include <GL/gl.h>
32 #endif
34 namespace KWin
37 KWIN_EFFECT( flipswitch, FlipSwitchEffect )
38 KWIN_EFFECT_SUPPORTED( flipswitch, FlipSwitchEffect::supported() )
40 FlipSwitchEffect::FlipSwitchEffect()
41 : mActivated( 0 )
42 , animateFlip( false )
43 , forward( true )
44 , start( false )
45 , stop( false )
46 , addFullRepaint( false )
47 , rearrangeWindows( 0 )
48 , stopRequested( false )
49 , startRequested( false )
50 , twinview( false )
52 reconfigure( ReconfigureAll );
55 FlipSwitchEffect::~FlipSwitchEffect()
59 bool FlipSwitchEffect::supported()
61 return effects->compositingType() == OpenGLCompositing;
64 void FlipSwitchEffect::reconfigure( ReconfigureFlags )
66 KConfigGroup conf = effects->effectConfig( "FlipSwitch" );
67 mFlipDuration = animationTime( conf, "FlipDuration", 200 );
68 mAnimation = conf.readEntry( "AnimateFlip", true );
69 timeLine.setCurveShape( TimeLine::EaseInOutCurve );
70 timeLine.setDuration( mFlipDuration );
73 void FlipSwitchEffect::prePaintScreen( ScreenPrePaintData& data, int time )
75 if( mActivated || stopRequested || stop )
77 data.mask |= Effect::PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS;
78 if( mAnimation && ( start || stop || animateFlip ) )
79 timeLine.addTime( (double)time );
81 effects->prePaintScreen(data, time);
84 void FlipSwitchEffect::paintScreen( int mask, QRegion region, ScreenPaintData& data )
86 effects->paintScreen( mask, region, data );
87 if( mActivated || stopRequested || stop )
89 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
90 glMatrixMode( GL_PROJECTION );
91 glPushMatrix();
92 glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT );
93 glEnable( GL_BLEND );
94 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
95 glLoadIdentity();
96 int viewport[4];
97 glGetIntegerv( GL_VIEWPORT, viewport );
98 int yPos = area.y();
99 QRect fullArea = effects->clientArea( FullArea, effects->activeScreen(), effects->currentDesktop());
100 if( twinview )
102 if( effects->clientArea( FullScreenArea, effects->activeScreen(), effects->currentDesktop()).x() == 0
103 && effects->clientArea( FullScreenArea, effects->activeScreen()==0?1:0, effects->currentDesktop()).x() == 0 )
105 // top <-> bottom
106 // have to correct the yPos for top bottom constellation
107 yPos = area.height()-area.y();
108 if( ( area.height() * 2 != fullArea.height() ) ||
109 ( effects->clientArea( FullScreenArea, effects->activeScreen(), effects->currentDesktop()).width() !=
110 effects->clientArea( FullScreenArea, effects->activeScreen()==0?1:0, effects->currentDesktop()).width() ) )
112 // different resolutions
113 if( area.y() > 0 )
114 yPos = 0;
115 else
116 yPos = fullArea.height() - area.height();
119 else
121 // left <-> right
122 if( ( area.width() * 2 != fullArea.width() ) ||
123 ( effects->clientArea( FullScreenArea, effects->activeScreen(), effects->currentDesktop()).height() !=
124 effects->clientArea( FullScreenArea, effects->activeScreen()==0?1:0, effects->currentDesktop()).height() ) )
126 // different resolutions
127 yPos = area.y() + fullArea.height() - area.height();
131 float left, right, top, bottom;
132 left = -area.width() * 0.5f;
133 right = area.width() * 0.5f;
134 top = area.height()*0.5f;
135 bottom = -area.height()*0.5f;
136 if( twinview && ( start || stop ) )
138 // special handling for start and stop animation in twin view setup
139 glViewport( fullArea.x(), fullArea.y(), fullArea.width(), fullArea.height() );
140 left = -(area.x() + area.width() * 0.5f);
141 right = fullArea.width() + left;
142 bottom = -(area.y() + area.height() * 0.5f);
143 top = fullArea.height() + bottom;
145 else
147 glViewport( area.x(), yPos, area.width(), area.height() );
149 glFrustum( left, right, top, bottom, 10, 50 );
151 glMatrixMode( GL_MODELVIEW );
152 glLoadIdentity();
153 float xOffset = area.width()*0.33f;
154 float zOffset = 10.0;
156 // bring the selected window to the back of the list
157 QList< EffectWindow* > tempList = effects->currentTabBoxWindowList();
158 int index = tempList.indexOf( effects->currentTabBoxWindow() );
159 QList< EffectWindow* > windowList;
160 for( int i=index; i<tempList.count(); i++)
162 windowList.push_front( tempList[i] );
164 for( int i=0; i<index; i++)
166 windowList.push_front( tempList[i] );
168 // do we have to rearrange the windows as an animation has to follow?
169 if( rearrangeWindows != 0 )
171 if( rearrangeWindows < 0 )
173 for( int i=0; i>rearrangeWindows; i-- )
175 EffectWindow* w = windowList.front();
176 windowList.pop_front();
177 windowList.append( w );
180 else
182 for( int i=0; i<rearrangeWindows; i++ )
184 EffectWindow* w = windowList.back();
185 windowList.pop_back();
186 windowList.prepend( w );
191 // do we have a start or stop animation
192 if( ( start || stop ) && mAnimation )
194 for( int i=0; i<windowList.count(); i++)
196 glPushMatrix();
197 EffectWindow *w = windowList[ i ];
198 // Position of the window in OpenGL
199 float x = w->x()+left;
200 float y = bottom-area.height()+w->y()+w->height();
201 float z = -10.0;
202 if( w->isMinimized() )
204 // use icon instead of window
205 x = w->iconGeometry().x()+left;
206 y = bottom-area.height()+w->iconGeometry().y()+w->height();
208 // Position of the window in the stack
209 float stackX = -area.width()*0.25f-(xOffset*windowList.count())+xOffset*(i+1);
210 float stackY = -area.height()*0.5f;
211 float stackZ = (-1*zOffset*windowList.count()) -12.5+zOffset*(i+1);
213 float animateXOffset;
214 float animateYOffset;
215 float animateZOffset;
216 float rotation;
217 // if start move to stack, if stop move from stack
218 if( start )
220 animateXOffset = x+timeLine.value()*(stackX-x);
221 animateYOffset = y+timeLine.value()*(stackY-y);
222 animateZOffset = z+timeLine.value()*(stackZ-z);
223 rotation = timeLine.value()*0.25;
225 else // = if( stop )
227 animateXOffset = stackX+timeLine.value()*(x-stackX);
228 animateYOffset = stackY+timeLine.value()*(y-stackY);
229 animateZOffset = stackZ+timeLine.value()*(z-stackZ);
230 rotation = 0.25-timeLine.value()*0.25;
233 // go to current position and rotate by the time based factor
234 glTranslatef(animateXOffset, animateYOffset, animateZOffset );
235 glRotatef(rotation, 0.0, 1.0, 0.0);
237 // top most window has to be painted not drawn.
238 if( i<windowList.count()-1 )
240 paintWindowFlip( windowList[i] );
242 else paintWindowFlip( windowList[i], false);
243 glPopMatrix();
245 // time elapsed - so no more animation
246 if( timeLine.value() == 1.0 )
248 timeLine.setProgress( 0.0 );
249 if( start )
251 start = false;
252 // more animations have to follow?
253 if( rearrangeWindows != 0 )
255 animateFlip = true;
256 if( rearrangeWindows < 0 )
258 forward = true;
259 rearrangeWindows++;
261 else
263 forward = false;
264 rearrangeWindows--;
267 else if( stopRequested )
269 // no more animations but effect has to stop
270 stop = true;
271 stopRequested = false;
274 else if( stop )
276 stop = false;
277 if( startRequested )
279 // tabbox already referenced again - so restart
280 start = true;
281 startRequested = false;
282 mActivated = true;
284 else
286 mActivated = false;
287 // we need one more FullRepaint
288 addFullRepaint = true;
293 // normal behaviour - no start or stop animation
294 else
296 double localProgress = timeLine.value();
297 glPushMatrix();
298 glTranslatef(-area.width()*0.25f-(xOffset*windowList.count()),
299 -area.height()*0.5f,
300 (-1*zOffset*windowList.count()) -12.5);
301 if( animateFlip && windowList.count() > 1 )
303 if( timeLine.value() < 1.0 )
305 float animateXOffset = timeLine.value()*xOffset;
306 float animateZOffset = timeLine.value()*zOffset;
307 if( forward )
309 if( animateXOffset > xOffset ) animateXOffset = xOffset;
310 if( animateZOffset > zOffset ) animateZOffset = zOffset;
311 glTranslatef(animateXOffset, 0.0, animateZOffset);
312 EffectWindow* w = windowList.front();
313 windowList.pop_front();
314 windowList.append( w );
316 else
318 animateXOffset = xOffset - animateXOffset;
319 animateZOffset = zOffset - animateZOffset;
320 if( animateXOffset < 0.0 ) animateXOffset = 0.0;
321 if( animateZOffset < 0.0 ) animateZOffset = 0.0;
322 glTranslatef(animateXOffset, 0.0, animateZOffset);
325 else
327 timeLine.setProgress( 0.0 );
328 if( rearrangeWindows != 0 )
330 animateFlip = true;
331 if( rearrangeWindows < 0 )
333 forward = true;
334 rearrangeWindows++;
335 localProgress = 0.0;
337 else
339 forward = false;
340 rearrangeWindows--;
341 localProgress = 1.0;
344 else
346 animateFlip = false;
347 if( stopRequested )
349 stop = true;
350 stopRequested = false;
355 for( int i=0; i<windowList.count(); i++)
357 glPushMatrix();
358 glTranslatef(xOffset*(i+1), 0.0, zOffset*(i+1));
359 glRotatef(0.25, 0.0, 1.0, 0.0);
360 // top most window has to be painted not drawn.
361 if( i<windowList.count()-1 )
363 paintWindowFlip( windowList[i] );
365 else
367 // last window - change opacity if animated
368 float opacity = 0.8;
369 if( animateFlip && windowList.count() > 1 )
371 if( forward ) opacity = opacity - localProgress*opacity;
372 else opacity = localProgress*opacity;
374 paintWindowFlip( windowList[i], false, opacity);
376 glPopMatrix();
378 glPopMatrix();
380 glPopAttrib();
381 glMatrixMode( GL_PROJECTION );
382 glPopMatrix();
383 glMatrixMode( GL_MODELVIEW );
384 glViewport( viewport[0], viewport[1], viewport[2], viewport[3] );
386 // caption of selected window
387 QColor color_frame;
388 QColor color_text;
389 color_frame = KColorScheme( QPalette::Active, KColorScheme::Window ).background().color();
390 color_frame.setAlphaF( 0.9 );
391 color_text = KColorScheme( QPalette::Active, KColorScheme::Window ).foreground().color();
392 if( start )
394 color_frame.setAlphaF( 0.9 * timeLine.value() );
395 color_text.setAlphaF( timeLine.value() );
397 else if( stop )
399 color_frame.setAlphaF( 0.9 - 0.9 * timeLine.value() );
400 color_text.setAlphaF( 1.0 - timeLine.value() );
402 else if( addFullRepaint )
404 // special case: timeLine was reset, but actual frame will be painted
405 color_frame.setAlphaF( 0.0 );
406 color_text.setAlphaF( 0.0 );
408 QFont text_font;
409 text_font.setBold( true );
410 text_font.setPointSize( 20 );
411 glPushAttrib( GL_CURRENT_BIT );
412 glColor4f( color_frame.redF(), color_frame.greenF(), color_frame.blueF(), color_frame.alphaF());
413 QRect frameRect = QRect( area.width()*0.25f + area.x(),
414 area.height()*0.9f + area.y(),
415 area.width()*0.5f,
416 QFontMetrics( text_font ).height() * 1.2 );
417 renderRoundBoxWithEdge( frameRect );
418 effects->paintText( effects->currentTabBoxWindow()->caption(),
419 frameRect.center(),
420 frameRect.width() - 100,
421 color_text,
422 text_font );
423 glPopAttrib();
424 // icon of selected window
425 QPixmap iconPixmap = effects->currentTabBoxWindow()->icon();
426 if( start || stop || addFullRepaint )
428 int alpha = 255.0f * timeLine.value();
429 if( stop )
431 alpha = 255.0f - alpha;
433 else if( addFullRepaint )
435 alpha = 0.0f;
437 QPixmap transparency = iconPixmap.copy( iconPixmap.rect() );
438 transparency.fill( QColor( 255, 255, 255, alpha ) );
439 iconPixmap.setAlphaChannel( transparency.alphaChannel() );
441 GLTexture* icon = new GLTexture( iconPixmap );
442 icon->bind();
443 glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT );
444 icon->bind();
445 glEnable( GL_BLEND );
446 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
447 // icon takes 80 % of the height of the frame. So each 10 % space left on the top and bottom
448 QRect iconRect = QRect( frameRect.x() + frameRect.height()*0.1f,
449 frameRect.y() + frameRect.height()*0.1f,
450 frameRect.height()*0.8f,
451 frameRect.height()*0.8f );
452 icon->render( region, iconRect);
453 icon->unbind();
454 delete icon;
455 glDisable( GL_BLEND );
456 glPopAttrib();
457 #endif
461 void FlipSwitchEffect::postPaintScreen()
463 if( (mActivated && ( animateFlip || start )) || stopRequested || stop )
465 effects->addRepaintFull();
467 if( addFullRepaint )
469 addFullRepaint = false;
470 effects->setActiveFullScreenEffect( 0 );
471 effects->addRepaintFull();
473 effects->postPaintScreen();
476 void FlipSwitchEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
478 if( mActivated || stopRequested || stop )
480 if( !( mask & PAINT_WINDOW_TRANSFORMED ) && ( !w->isDesktop() ) )
482 if( ( start || stop ) && w->isDock() )
484 data.opacity = 1.0 - timeLine.value();
485 if( stop )
486 data.opacity = timeLine.value();
488 else
489 return;
492 effects->paintWindow( w, mask, region, data );
495 void FlipSwitchEffect::tabBoxAdded( int mode )
497 if( effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this )
498 return;
499 if( !mActivated )
501 // only for windows mode
502 if( mode == TabBoxWindowsMode && effects->currentTabBoxWindowList().count() > 0 )
504 input = effects->createFullScreenInputWindow( this, Qt::BlankCursor );
505 effects->refTabBox();
506 effects->setActiveFullScreenEffect( this );
507 selectedWindow = effects->currentTabBoxWindowList().indexOf(effects->currentTabBoxWindow());
508 if( !stop && !stopRequested )
510 mActivated = true;
511 start = true;
512 effects->addRepaintFull();
514 else
516 // last tabbox effect still running - schedule start effect
517 startRequested = true;
520 // Calculation of correct area
521 area = effects->clientArea( FullScreenArea, effects->activeScreen(), effects->currentDesktop());
522 QRect fullArea = effects->clientArea( FullArea, effects->activeScreen(), effects->currentDesktop());
523 // twinview?
524 if( area.height() != fullArea.height() || area.width() != fullArea.width() )
525 twinview = true;
526 else
527 twinview = false;
531 void FlipSwitchEffect::tabBoxClosed()
533 if( mActivated )
535 // if animation than deactivate after animation
536 mActivated = false;
537 effects->unrefTabBox();
538 if( input )
539 effects->destroyInputWindow( input );
540 if( mAnimation )
542 if( start && rearrangeWindows == 0 )
544 stop = true;
545 start = false;
546 timeLine.setProgress( 1.0 - timeLine.value() );
548 else if( start || animateFlip )
549 stopRequested = true;
550 else
552 stop = true;
553 effects->addRepaintFull();
556 else
558 effects->setActiveFullScreenEffect( 0 );
563 void FlipSwitchEffect::tabBoxUpdated()
565 if( mActivated )
567 if( mAnimation && effects->currentTabBoxWindowList().count() > 1 )
569 // determine the switch direction
570 int index = effects->currentTabBoxWindowList().indexOf(effects->currentTabBoxWindow());
571 bool direction = false;
572 int windowCount = effects->currentTabBoxWindowList().count();
573 if( index > selectedWindow )
575 if( index == windowCount-1 && selectedWindow == 0 ) forward = false;
576 else direction = true;
578 else if( index == 0 && ( selectedWindow == windowCount-1 ) )
580 direction = true;
582 else if( index == selectedWindow ) return; // nothing changed
583 else
585 direction = false;
587 selectedWindow = index;
588 if( !animateFlip && !start )
590 forward = direction;
591 animateFlip = true;
593 else
595 if( direction ) rearrangeWindows--;
596 else rearrangeWindows++;
597 if( rearrangeWindows >= windowCount ) rearrangeWindows = rearrangeWindows % windowCount;
598 else if( (-1*rearrangeWindows) >= windowCount ) rearrangeWindows = -1*((-1*rearrangeWindows) % windowCount);
601 effects->addRepaintFull();
605 void FlipSwitchEffect::paintWindowFlip( EffectWindow* w, bool draw, float opacity )
607 WindowPaintData data( w );
609 int x = 0;
610 int y = area.height() - w->geometry().height();
611 QRect thumbnail;
612 setPositionTransformations( data,
613 thumbnail, w,
614 QRect( x, y, w->geometry().width(), w->geometry().height() ),
615 Qt::KeepAspectRatio );
617 data.opacity *= opacity;
618 thumbnail = infiniteRegion();
619 // if paintWindow() is used the window behind the initial selected window is not painted on the stack,
620 // but painted when it is selected
621 // if drawWindow() is used the front window does not glide through the monitor during animation
622 // so use drawWindow() for all windows but the selected and paintWindow() for the selected window
623 if( draw )
624 effects->drawWindow( w,
625 PAINT_WINDOW_TRANSFORMED,
626 thumbnail, data );
627 else
628 effects->paintWindow( w,
629 PAINT_WINDOW_TRANSFORMED,
630 thumbnail, data );
633 } // namespace