add more spacing
[personal-kdebase.git] / workspace / kwin / effects / boxswitch.cpp
blobe0ead1e905de3b8f54d7d567cfc4fc818078ed2c
1 /********************************************************************
2 KWin - the KDE window manager
3 This file is part of the KDE project.
5 Copyright (C) 2007 Philip Falkner <philip.falkner@gmail.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 *********************************************************************/
21 #include "boxswitch.h"
23 #include <kwinconfig.h>
25 #include <QMouseEvent>
26 #include <QSize>
28 #include <kapplication.h>
29 #include <kcolorscheme.h>
30 #include <kconfiggroup.h>
32 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
33 #include <GL/gl.h>
34 #endif
36 namespace KWin
39 KWIN_EFFECT( boxswitch, BoxSwitchEffect )
41 BoxSwitchEffect::BoxSwitchEffect()
42 : mActivated( 0 )
43 , mMode( 0 )
44 , selected_window( 0 )
45 , painting_desktop( 0 )
46 , animation( false )
47 , highlight_is_set( false )
50 frame_margin = 10;
51 highlight_margin = 5;
52 reconfigure( ReconfigureAll );
55 BoxSwitchEffect::~BoxSwitchEffect()
59 void BoxSwitchEffect::reconfigure( ReconfigureFlags )
61 color_frame = KColorScheme( QPalette::Active, KColorScheme::Window ).background().color();
62 color_frame.setAlphaF( 0.9 );
63 color_highlight = KColorScheme( QPalette::Active, KColorScheme::Selection ).background().color();
64 color_highlight.setAlphaF( 0.9 );
65 color_text = KColorScheme( QPalette::Active, KColorScheme::Window ).foreground().color();
66 activeTimeLine.setDuration( animationTime( 250 ));
67 activeTimeLine.setCurveShape( TimeLine::EaseInOutCurve );
68 timeLine.setDuration( animationTime( 150 ));
69 timeLine.setCurveShape( TimeLine::EaseInOutCurve );
70 KConfigGroup conf = effects->effectConfig( "BoxSwitch" );
72 bg_opacity = conf.readEntry( "BackgroundOpacity", 25 ) / 100.0;
73 elevate_window = conf.readEntry( "ElevateSelected", true );
74 mAnimateSwitch = conf.readEntry( "AnimateSwitch", false );
77 void BoxSwitchEffect::prePaintWindow( EffectWindow* w, WindowPrePaintData& data, int time )
79 if( mActivated )
81 if( mMode == TabBoxWindowsMode )
83 if( windows.contains( w ))
85 if( w != selected_window )
86 data.setTranslucent();
87 w->enablePainting( EffectWindow::PAINT_DISABLED_BY_MINIMIZE );
90 else
92 if( painting_desktop )
94 if( w->isOnDesktop( painting_desktop ))
95 w->enablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP );
96 else
97 w->disablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP );
101 effects->prePaintWindow( w, data, time );
104 void BoxSwitchEffect::prePaintScreen( ScreenPrePaintData& data, int time )
106 if( mActivated )
107 activeTimeLine.addTime( time );
108 else
109 activeTimeLine.removeTime( time );
110 if( mActivated && animation )
112 timeLine.addTime( time );
113 calculateItemSizes();
115 effects->prePaintScreen( data, time );
118 void BoxSwitchEffect::paintScreen( int mask, QRegion region, ScreenPaintData& data )
120 effects->paintScreen( mask, region, data );
121 if( mActivated )
123 if( mMode == TabBoxWindowsMode )
125 paintFrame();
127 if( mAnimateSwitch )
129 // HACK: PaintClipper is used because window split is somehow wrong if the height is greater than width
130 PaintClipper::push( frame_area.adjusted( frame_margin, frame_margin, -frame_margin, -frame_margin ));
131 paintHighlight( highlight_area );
132 foreach( EffectWindow* w, windows.keys())
134 paintWindowThumbnail( w );
135 paintWindowIcon( w );
137 PaintClipper::pop( frame_area.adjusted( frame_margin, frame_margin, -frame_margin, -frame_margin ) );
139 else
141 foreach( EffectWindow* w, windows.keys())
143 if( w == selected_window )
145 paintHighlight( windows[ w ]->area );
147 paintWindowThumbnail( w );
148 paintWindowIcon( w );
151 paintText( selected_window->caption() );
153 else
155 if( !painting_desktop )
157 paintFrame();
159 foreach( painting_desktop, desktops.keys())
161 if( painting_desktop == selected_desktop )
163 paintHighlight( desktops[ painting_desktop ]->area ); //effects->desktopName( painting_desktop )
166 paintDesktopThumbnail( painting_desktop );
168 paintText( effects->desktopName( selected_desktop ));
169 painting_desktop = 0;
175 void BoxSwitchEffect::postPaintScreen()
177 if( mActivated && activeTimeLine.value() != 1.0 )
178 effects->addRepaintFull();
179 if( !mActivated && activeTimeLine.value() != 0.0 )
180 effects->addRepaintFull();
181 if( mActivated && animation )
183 if( timeLine.value() == 1.0 )
185 timeLine.setProgress( 0.0 );
186 animation = false;
187 if( !scheduled_directions.isEmpty() )
189 direction = scheduled_directions.dequeue();
190 animation = true;
193 QRect repaint = QRect( frame_area.x() - item_max_size.width()*0.5,
194 frame_area.y(),
195 frame_area.width() + item_max_size.width(),
196 frame_area.height() );
197 effects->addRepaint( repaint );
199 effects->postPaintScreen();
202 void BoxSwitchEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
204 if(( mActivated && mMode == TabBoxWindowsMode ) || ( !mActivated && activeTimeLine.value() != 0.0 ))
206 if( windows.contains( w ) && w != selected_window )
208 if( w->isMinimized() )
209 // TODO: When deactivating minimized windows are not painted at all
210 data.opacity *= activeTimeLine.value() * bg_opacity;
211 else
212 data.opacity *= 1.0 - activeTimeLine.value() * ( 1.0 - bg_opacity );
215 effects->paintWindow( w, mask, region, data );
218 void BoxSwitchEffect::windowInputMouseEvent( Window w, QEvent* e )
220 assert( w == mInput );
221 if( e->type() != QEvent::MouseButtonPress )
222 return;
223 QPoint pos = static_cast< QMouseEvent* >( e )->pos();
224 pos += frame_area.topLeft();
226 // determine which item was clicked
227 if( mMode == TabBoxWindowsMode )
229 foreach( EffectWindow* w, windows.keys())
231 if( windows[ w ]->clickable.contains( pos ))
233 effects->setTabBoxWindow( w );
236 // special handling for second half of window in case of animation and even number of windows
237 if( mAnimateSwitch && ( windows.size() % 2 == 0 ) )
239 QRect additionalRect = QRect( frame_area.x() + frame_margin,
240 frame_area.y() + frame_margin,
241 item_max_size.width()*0.5, item_max_size.height());
242 if( additionalRect.contains( pos ))
244 effects->setTabBoxWindow( right_window );
248 else
250 foreach( int i, desktops.keys())
252 if( desktops[ i ]->clickable.contains( pos ))
254 effects->setTabBoxDesktop( i );
260 void BoxSwitchEffect::windowDamaged( EffectWindow* w, const QRect& damage )
262 if( mActivated )
264 if( mMode == TabBoxWindowsMode )
266 if( windows.contains( w ))
268 effects->addRepaint( windows[ w ]->area );
271 else
273 if( w->isOnAllDesktops())
275 foreach( ItemInfo* info, desktops )
276 effects->addRepaint( info->area );
278 else
280 effects->addRepaint( desktops[ w->desktop() ]->area );
286 void BoxSwitchEffect::windowGeometryShapeChanged( EffectWindow* w, const QRect& old )
288 if( mActivated )
290 if( mMode == TabBoxWindowsMode )
292 if( windows.contains( w ) && w->size() != old.size())
294 effects->addRepaint( windows[ w ]->area );
297 else
299 if( w->isOnAllDesktops())
301 foreach( ItemInfo* info, desktops )
302 effects->addRepaint( info->area );
304 else
306 effects->addRepaint( desktops[ w->desktop() ]->area );
312 void BoxSwitchEffect::tabBoxAdded( int mode )
314 if( !mActivated )
316 if( mode == TabBoxWindowsMode )
318 if( effects->currentTabBoxWindowList().count() > 0 )
320 mMode = mode;
321 effects->refTabBox();
322 highlight_is_set = false;
323 animation = false;
324 scheduled_directions.clear();
325 right_window = 0;
326 setActive();
329 else
330 { // DesktopMode
331 if( effects->currentTabBoxDesktopList().count() > 0 )
333 mMode = mode;
334 painting_desktop = 0;
335 effects->refTabBox();
336 setActive();
342 void BoxSwitchEffect::tabBoxClosed()
344 if( mActivated )
345 setInactive();
348 void BoxSwitchEffect::tabBoxUpdated()
350 if( mActivated )
352 if( mMode == TabBoxWindowsMode && selected_window != effects->currentTabBoxWindow() )
354 if( selected_window != NULL )
356 if( mAnimateSwitch )
358 int old_index = effects->currentTabBoxWindowList().indexOf( selected_window );
359 int new_index = effects->currentTabBoxWindowList().indexOf( effects->currentTabBoxWindow() );
360 Direction new_direction;
361 int distance = new_index - old_index;
362 if( distance > 0 )
363 new_direction = Left;
364 if( distance < 0 )
365 new_direction = Right;
366 if( distance != 0 )
368 distance = abs( distance );
369 int tempDistance = effects->currentTabBoxWindowList().count() - distance;
370 if( tempDistance < abs( distance ) )
372 distance = tempDistance;
373 if( new_direction == Left )
374 new_direction = Right;
375 else
376 new_direction = Left;
378 if( !animation )
380 animation = true;
381 direction = new_direction;
382 distance--;
384 for( int i=0; i<distance; i++ )
386 if( !scheduled_directions.isEmpty() && scheduled_directions.last() != new_direction )
387 scheduled_directions.pop_back();
388 else
389 scheduled_directions.enqueue( new_direction );
390 if( scheduled_directions.count() == effects->currentTabBoxWindowList().count() )
391 scheduled_directions.clear();
395 if( windows.contains( selected_window ))
396 effects->addRepaint( windows.value( selected_window )->area );
397 selected_window->addRepaintFull();
399 setSelectedWindow( effects->currentTabBoxWindow());
400 if( windows.contains( selected_window ))
401 effects->addRepaint( windows.value( selected_window )->area );
402 selected_window->addRepaintFull();
403 effects->addRepaint( text_area );
404 original_windows = effects->currentTabBoxWindowList();
406 else
407 { // DesktopMode
408 if( desktops.contains( selected_desktop ))
409 effects->addRepaint( desktops.value( selected_desktop )->area );
410 selected_desktop = effects->currentTabBoxDesktop();
411 if( desktops.contains( selected_desktop ))
412 effects->addRepaint( desktops.value( selected_desktop )->area );
413 effects->addRepaint( text_area );
414 if( effects->currentTabBoxDesktopList() == original_desktops )
415 return;
416 original_desktops = effects->currentTabBoxDesktopList();
418 effects->addRepaint( frame_area );
419 calculateFrameSize();
420 calculateItemSizes();
421 moveResizeInputWindow( frame_area.x(), frame_area.y(), frame_area.width(), frame_area.height());
422 effects->addRepaint( frame_area );
426 void BoxSwitchEffect::setActive()
428 mActivated = true;
430 // Do this here so we have correct fading on deactivation
431 qDeleteAll( windows );
432 windows.clear();
434 if( mMode == TabBoxWindowsMode )
436 original_windows = effects->currentTabBoxWindowList();
437 setSelectedWindow( effects->currentTabBoxWindow());
439 else
441 original_desktops = effects->currentTabBoxDesktopList();
442 selected_desktop = effects->currentTabBoxDesktop();
444 calculateFrameSize();
445 calculateItemSizes();
446 mInput = effects->createInputWindow( this, frame_area.x(), frame_area.y(),
447 frame_area.width(), frame_area.height(), Qt::ArrowCursor );
448 effects->addRepaint( frame_area );
449 if( mMode == TabBoxWindowsMode )
451 foreach( EffectWindow* w, windows.keys())
453 w->addRepaintFull();
458 void BoxSwitchEffect::setInactive()
460 mActivated = false;
461 effects->unrefTabBox();
462 if( mInput != None )
464 effects->destroyInputWindow( mInput );
465 mInput = None;
467 if( mMode == TabBoxWindowsMode )
469 foreach( EffectWindow* w, windows.keys())
471 if( w != selected_window )
472 w->addRepaintFull();
474 // We don't unset the selected window so we have correct fading
475 // But we do need to remove elevation status
476 if( elevate_window && selected_window )
477 effects->setElevatedWindow( selected_window, false );
479 else
480 { // DesktopMode
481 qDeleteAll( windows );
482 desktops.clear();
484 effects->addRepaint( frame_area );
485 frame_area = QRect();
488 void BoxSwitchEffect::setSelectedWindow( EffectWindow* w )
490 if( elevate_window && selected_window )
492 effects->setElevatedWindow( selected_window, false );
494 selected_window = w;
495 if( elevate_window && w )
497 effects->setElevatedWindow( selected_window, true );
501 void BoxSwitchEffect::windowClosed( EffectWindow* w )
503 if( w == selected_window )
505 setSelectedWindow( 0 );
509 void BoxSwitchEffect::moveResizeInputWindow( int x, int y, int width, int height )
511 XMoveWindow( display(), mInput, x, y );
512 XResizeWindow( display(), mInput, width, height );
515 void BoxSwitchEffect::calculateFrameSize()
517 int itemcount;
519 if( mMode == TabBoxWindowsMode )
521 itemcount = original_windows.count();
522 item_max_size.setWidth( 200 );
523 item_max_size.setHeight( 200 );
525 else
527 itemcount = original_desktops.count();
528 item_max_size.setWidth( 200 );
529 item_max_size.setHeight( 200 );
531 // How much height to reserve for a one-line text label
532 text_font.setBold( true );
533 text_font.setPointSize( 12 );
534 text_area.setHeight( QFontMetrics( text_font ).height() * 1.2 );
535 // Separator space between items and text
536 const int separator_height = 6;
537 // Shrink the size until all windows/desktops can fit onscreen
538 frame_area.setWidth( frame_margin * 2 + itemcount * item_max_size.width());
539 QRect screenr = effects->clientArea( PlacementArea, effects->activeScreen(), effects->currentDesktop());
540 while( frame_area.width() > screenr.width())
542 item_max_size /= 2;
543 frame_area.setWidth( frame_margin * 2 + itemcount * item_max_size.width());
545 frame_area.setHeight( frame_margin * 2 + item_max_size.height() +
546 separator_height + text_area.height());
547 text_area.setWidth( frame_area.width() - frame_margin * 2 );
549 frame_area.moveTo( screenr.x() + ( screenr.width() - frame_area.width()) / 2,
550 screenr.y() + ( screenr.height() - frame_area.height()) / 2 );
551 text_area.moveTo( frame_area.x() + frame_margin,
552 frame_area.y() + frame_margin + item_max_size.height() + separator_height);
555 void BoxSwitchEffect::calculateItemSizes()
557 if( mMode == TabBoxWindowsMode )
559 windows.clear();
560 if( mAnimateSwitch )
562 int index = original_windows.indexOf( effects->currentTabBoxWindow() );
563 int leftIndex = index;
564 int rightIndex = index + 1;
565 if( rightIndex == original_windows.count() )
566 rightIndex = 0;
567 EffectWindowList ordered_windows;
569 int leftWindowCount = original_windows.count()/2;
570 int rightWindowCount = leftWindowCount;
571 if( original_windows.count()%2 == 1 )
572 leftWindowCount++;
573 for( int i=0; i < leftWindowCount; i++ )
575 int tempIndex = ( leftIndex - i );
576 if( tempIndex < 0 )
577 tempIndex = original_windows.count() + tempIndex;
578 ordered_windows.prepend( original_windows[ tempIndex ] );
580 for( int i=0; i < rightWindowCount; i++ )
582 int tempIndex = ( rightIndex + i ) % original_windows.count();
583 ordered_windows.append( original_windows[ tempIndex ] );
585 // move items cause of schedule
586 for( int i=0; i < scheduled_directions.count(); i++ )
588 Direction actual = scheduled_directions[ i ];
589 if( actual == Left )
591 EffectWindow* w = ordered_windows.takeLast();
592 ordered_windows.prepend( w );
594 else
596 EffectWindow* w = ordered_windows.takeFirst();
597 ordered_windows.append( w );
600 if( animation && timeLine.value() < 0.5 )
602 if( direction == Left )
604 EffectWindow* w = ordered_windows.takeLast();
605 edge_window = w;
606 ordered_windows.prepend( w );
608 else
610 EffectWindow* w = ordered_windows.takeFirst();
611 edge_window = w;
612 ordered_windows.append( w );
615 else if( animation && timeLine.value() >= 0.5 )
617 if( animation && direction == Left )
618 edge_window = ordered_windows.last();
619 if( animation && direction == Right )
620 edge_window = ordered_windows.first();
622 int offset = 0;
623 if( animation )
625 if( direction == Left )
626 offset = (float)item_max_size.width()*(1.0-timeLine.value());
627 else
628 offset = -(float)item_max_size.width()*(1.0-timeLine.value());
630 for( int i = 0; i < ordered_windows.count(); i++ )
632 EffectWindow* w = ordered_windows.at( i );
633 windows[ w ] = new ItemInfo();
635 float moveIndex = i;
636 if( animation && timeLine.value() < 0.5 )
638 if( direction == Left )
639 moveIndex--;
640 else
641 moveIndex++;
643 if( ordered_windows.count()%2 == 0 )
644 moveIndex += 0.5;
645 windows[ w ]->area = QRect( frame_area.x() + frame_margin
646 + moveIndex * item_max_size.width() + offset,
647 frame_area.y() + frame_margin,
648 item_max_size.width(), item_max_size.height());
649 windows[ w ]->clickable = windows[ w ]->area;
651 if( ordered_windows.count()%2 == 0 )
653 right_window = ordered_windows.last();
655 if( !highlight_is_set )
657 highlight_area = windows[ selected_window ]->area;
658 highlight_is_set = true;
661 else
663 for( int i = 0; i < original_windows.count(); i++ )
665 EffectWindow* w = original_windows.at( i );
666 windows[ w ] = new ItemInfo();
668 windows[ w ]->area = QRect( frame_area.x() + frame_margin
669 + i * item_max_size.width(),
670 frame_area.y() + frame_margin,
671 item_max_size.width(), item_max_size.height());
672 windows[ w ]->clickable = windows[ w ]->area;
676 else
678 desktops.clear();
679 for( int i = 0; i < original_desktops.count(); i++ )
681 int it = original_desktops.at( i );
682 desktops[ it ] = new ItemInfo();
684 desktops[ it ]->area = QRect( frame_area.x() + frame_margin
685 + i * item_max_size.width(),
686 frame_area.y() + frame_margin,
687 item_max_size.width(), item_max_size.height());
688 desktops[ it ]->clickable = desktops[ it ]->area;
693 void BoxSwitchEffect::paintFrame()
695 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
696 if( effects->compositingType() == OpenGLCompositing )
698 glPushAttrib( GL_CURRENT_BIT );
699 glColor4f( color_frame.redF(), color_frame.greenF(), color_frame.blueF(), color_frame.alphaF());
700 renderRoundBoxWithEdge( frame_area );
701 glPopAttrib();
703 #endif
704 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
705 if( effects->compositingType() == XRenderCompositing )
707 Pixmap pixmap = XCreatePixmap( display(), rootWindow(),
708 frame_area.width(), frame_area.height(), 32 );
709 XRenderPicture pic( pixmap, 32 );
710 XFreePixmap( display(), pixmap );
711 XRenderColor col;
712 col.alpha = int( color_frame.alphaF() * 0xffff );
713 col.red = int( color_frame.redF() * color_frame.alphaF() * 0xffff );
714 col.green = int( color_frame.greenF() * color_frame.alphaF() * 0xffff );
715 col.blue = int( color_frame.blueF() * color_frame.alphaF() * 0xffff );
716 XRenderFillRectangle( display(), PictOpSrc, pic, &col, 0, 0,
717 frame_area.width(), frame_area.height());
718 XRenderComposite( display(), color_frame.alphaF() != 1.0 ? PictOpOver : PictOpSrc,
719 pic, None, effects->xrenderBufferPicture(),
720 0, 0, 0, 0, frame_area.x(), frame_area.y(), frame_area.width(), frame_area.height());
722 #endif
725 void BoxSwitchEffect::paintHighlight( QRect area )
727 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
728 if( effects->compositingType() == OpenGLCompositing )
730 glPushAttrib( GL_CURRENT_BIT );
731 glColor4f( color_highlight.redF(), color_highlight.greenF(), color_highlight.blueF(), color_highlight.alphaF());
732 renderRoundBox( area, 6 );
733 glPopAttrib();
735 #endif
736 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
737 if( effects->compositingType() == XRenderCompositing )
739 Pixmap pixmap = XCreatePixmap( display(), rootWindow(),
740 area.width(), area.height(), 32 );
741 XRenderPicture pic( pixmap, 32 );
742 XFreePixmap( display(), pixmap );
743 XRenderColor col;
744 col.alpha = int( color_highlight.alphaF() * 0xffff );
745 col.red = int( color_highlight.redF() * color_highlight.alphaF() * 0xffff );
746 col.green = int( color_highlight.greenF() * color_highlight.alphaF() * 0xffff );
747 col.blue = int( color_highlight.blueF() * color_highlight.alphaF() * 0xffff );
748 XRenderFillRectangle( display(), PictOpSrc, pic, &col, 0, 0,
749 area.width(), area.height());
750 XRenderComposite( display(), color_highlight.alphaF() != 1.0 ? PictOpOver : PictOpSrc,
751 pic, None, effects->xrenderBufferPicture(),
752 0, 0, 0, 0, area.x(), area.y(), area.width(), area.height());
754 #endif
757 void BoxSwitchEffect::paintWindowThumbnail( EffectWindow* w )
759 if( !windows.contains( w ))
760 return;
761 WindowPaintData data( w );
763 setPositionTransformations( data,
764 windows[ w ]->thumbnail, w,
765 windows[ w ]->area.adjusted( highlight_margin, highlight_margin, -highlight_margin, -highlight_margin ),
766 Qt::KeepAspectRatio );
768 if( animation && ( w == edge_window ) && ( windows.size() % 2 == 1 ) )
770 // in case of animation:
771 // the window which has to change the side will be split and painted on both sides of the edge
772 double splitPoint = 0.0;
773 if( direction == Left )
775 splitPoint = w->geometry().width()*timeLine.value();
777 else
779 splitPoint = w->geometry().width() - w->geometry().width()*timeLine.value();
781 data.quads = data.quads.splitAtX( splitPoint );
782 WindowQuadList left_quads;
783 WindowQuadList right_quads;
784 foreach( const WindowQuad &quad, data.quads )
786 if( quad.left() >= splitPoint )
787 left_quads << quad;
788 if( quad.right() <= splitPoint )
789 right_quads << quad;
791 // the base position of the window is changed after half of the animation
792 if( timeLine.value() < 0.5 )
794 if( direction == Left )
795 data.quads = left_quads;
796 else
797 data.quads = right_quads;
799 else
801 if( direction == Left )
802 data.quads = right_quads;
803 else
804 data.quads = left_quads;
807 // paint one part of the thumbnail
808 effects->drawWindow( w,
809 PAINT_WINDOW_OPAQUE | PAINT_WINDOW_TRANSFORMED,
810 windows[ w ]->thumbnail, data );
812 QRect secondThumbnail;
814 // paint the second part of the thumbnail:
815 // the other window quads are needed and a new rect for transformation has to be calculated
816 if( direction == Left )
818 if( timeLine.value() < 0.5 )
820 data.quads = right_quads;
821 secondThumbnail = QRect( frame_area.x() + frame_area.width() - frame_margin
822 - (float)item_max_size.width()*timeLine.value(),
823 frame_area.y() + frame_margin, item_max_size.width(), item_max_size.height());
825 else
827 data.quads = left_quads;
828 secondThumbnail = QRect( frame_area.x() + frame_margin - (float)item_max_size.width()*timeLine.value(),
829 frame_area.y() + frame_margin, item_max_size.width(), item_max_size.height());
830 if( right_window )
831 secondThumbnail = QRect( frame_area.x() + frame_margin -
832 (float)item_max_size.width()*(timeLine.value()-0.5),
833 frame_area.y() + frame_margin, item_max_size.width(), item_max_size.height());
836 else
838 if( timeLine.value() < 0.5 )
840 data.quads = left_quads;
841 secondThumbnail = QRect( frame_area.x() + frame_margin -
842 (float)item_max_size.width()*(1.0 - timeLine.value()),
843 frame_area.y() + frame_margin, item_max_size.width(), item_max_size.height());
845 else
847 data.quads = right_quads;
848 secondThumbnail = QRect( frame_area.x() + frame_area.width() - frame_margin
849 - (float)item_max_size.width()*(1.0 - timeLine.value()),
850 frame_area.y() + frame_margin, item_max_size.width(), item_max_size.height());
853 setPositionTransformations( data,
854 windows[ w ]->thumbnail, w,
855 secondThumbnail.adjusted( highlight_margin, highlight_margin, -highlight_margin, -highlight_margin ),
856 Qt::KeepAspectRatio );
857 effects->drawWindow( w,
858 PAINT_WINDOW_OPAQUE | PAINT_WINDOW_TRANSFORMED,
859 windows[ w ]->thumbnail, data );
861 else if( ( windows.size() % 2 == 0 ) && ( w == right_window ) )
863 // in case of even number of thumbnails:
864 // the window on the right is painted one half on left and on half on the right side
865 float animationOffset = 0.0f;
866 double splitPoint = w->geometry().width()*0.5;
867 if( animation && timeLine.value() <= 0.5 )
869 // in case of animation the right window has only to be split during first half of animation
870 if( direction == Left )
872 splitPoint += w->geometry().width()*timeLine.value();
873 animationOffset = -(float)item_max_size.width()*timeLine.value();
875 else
877 splitPoint -= w->geometry().width()*timeLine.value();
878 animationOffset = (float)item_max_size.width()*timeLine.value();
881 if( animation && timeLine.value() > 0.5 )
883 // at half of animation a different window has become the right window
884 // we have to adjust the splitting again
885 if( direction == Left )
887 splitPoint -= w->geometry().width()*(1.0-timeLine.value());
888 animationOffset = (float)item_max_size.width()*(1.0-timeLine.value());
890 else
892 splitPoint += w->geometry().width()*(1.0-timeLine.value());
893 animationOffset = -(float)item_max_size.width()*(1.0-timeLine.value());
896 data.quads = data.quads.splitAtX( splitPoint );
897 WindowQuadList rightQuads;
898 WindowQuadList leftQuads;
899 foreach( const WindowQuad &quad, data.quads )
901 if( quad.right() <= splitPoint )
902 leftQuads << quad;
903 else
904 rightQuads << quad;
907 // left quads are painted on right side of frame
908 data.quads = leftQuads;
909 effects->drawWindow( w,
910 PAINT_WINDOW_OPAQUE | PAINT_WINDOW_TRANSFORMED,
911 windows[ w ]->thumbnail, data );
913 // right quads are painted on left side of frame
914 data.quads = rightQuads;
915 QRect secondThumbnail;
916 secondThumbnail = QRect( frame_area.x() + frame_margin -
917 (float)item_max_size.width()*0.5 + animationOffset,
918 frame_area.y() + frame_margin, item_max_size.width(), item_max_size.height());
919 setPositionTransformations( data,
920 windows[ w ]->thumbnail, w,
921 secondThumbnail.adjusted( highlight_margin, highlight_margin, -highlight_margin, -highlight_margin ),
922 Qt::KeepAspectRatio );
923 effects->drawWindow( w,
924 PAINT_WINDOW_OPAQUE | PAINT_WINDOW_TRANSFORMED,
925 windows[ w ]->thumbnail, data );
927 else
929 effects->drawWindow( w,
930 PAINT_WINDOW_OPAQUE | PAINT_WINDOW_TRANSFORMED,
931 windows[ w ]->thumbnail, data );
935 void BoxSwitchEffect::paintDesktopThumbnail( int iDesktop )
937 if( !desktops.contains( iDesktop ))
938 return;
940 ScreenPaintData data;
941 QRect region;
942 QRect r = desktops[ iDesktop ]->area.adjusted( highlight_margin, highlight_margin,
943 -highlight_margin, -highlight_margin );
944 QSize size = QSize( displayWidth(), displayHeight());
946 size.scale( r.size(), Qt::KeepAspectRatio );
947 data.xScale = size.width() / double( displayWidth());
948 data.yScale = size.height() / double( displayHeight());
949 int width = int( displayWidth() * data.xScale );
950 int height = int( displayHeight() * data.yScale );
951 int x = r.x() + ( r.width() - width ) / 2;
952 int y = r.y() + ( r.height() - height ) / 2;
953 region = QRect( x, y, width, height );
954 data.xTranslate = x;
955 data.yTranslate = y;
957 effects->paintScreen( PAINT_SCREEN_TRANSFORMED | PAINT_SCREEN_BACKGROUND_FIRST,
958 region, data );
961 void BoxSwitchEffect::paintWindowIcon( EffectWindow* w )
963 if( !windows.contains( w ))
964 return;
965 // Don't render null icons
966 if( w->icon().isNull() )
968 return;
971 if( windows[ w ]->icon.cacheKey() != w->icon().cacheKey())
972 { // make sure windows[ w ]->icon is the right QPixmap, and rebind
973 windows[ w ]->icon = w->icon();
974 if( ( windows.size() % 2 == 1 ) && animation && w == edge_window )
976 int alpha;
977 if( timeLine.value() < 0.5 )
978 alpha = 255.0f * (1.0 - timeLine.value()*2.0);
979 else
980 alpha = 255.0f * (timeLine.value()*2.0 - 1.0);
981 QPixmap transparency = windows[ w ]->icon.copy( windows[ w ]->icon.rect() );
982 transparency.fill( QColor( 255, 255, 255, alpha ) );
983 windows[ w ]->icon.setAlphaChannel( transparency.alphaChannel() );
985 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
986 if( effects->compositingType() == OpenGLCompositing )
988 windows[ w ]->iconTexture.load( windows[ w ]->icon );
989 windows[ w ]->iconTexture.setFilter( GL_LINEAR );
991 #endif
992 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
993 if( effects->compositingType() == XRenderCompositing )
994 windows[ w ]->iconPicture = XRenderPicture( windows[ w ]->icon );
995 #endif
997 int width = windows[ w ]->icon.width();
998 int height = windows[ w ]->icon.height();
999 int x = windows[ w ]->area.x() + windows[ w ]->area.width() - width - highlight_margin;
1000 int y = windows[ w ]->area.y() + windows[ w ]->area.height() - height - highlight_margin;
1001 if( ( windows.size() % 2 == 0 ) )
1003 if( w == right_window )
1005 // in case of right window the icon has to be painted on the left side of the frame
1006 x = frame_area.x() + windows[ w ]->area.width()*0.5 - width - highlight_margin;
1007 if( animation )
1009 if( timeLine.value() <= 0.5 )
1011 if( direction == Left )
1013 x -= windows[ w ]->area.width()*timeLine.value();
1014 x = qMax( x, frame_area.x() + frame_margin );
1016 else
1017 x += windows[ w ]->area.width()*timeLine.value();
1019 else
1021 if( direction == Left )
1022 x += windows[ w ]->area.width()*(1.0-timeLine.value());
1023 else
1025 x -= windows[ w ]->area.width()*(1.0-timeLine.value());
1026 x = qMax( x, frame_area.x() + frame_margin );
1032 else
1034 // during animation the icon of the edge window has to change position
1035 if( animation && w == edge_window )
1037 if( timeLine.value() < 0.5 )
1039 if( direction == Left )
1040 x += windows[ w ]->area.width()*timeLine.value();
1041 else
1042 x -= windows[ w ]->area.width()*timeLine.value();
1044 else
1046 if( direction == Left )
1047 x -= windows[ w ]->area.width()*(1.0 - timeLine.value());
1048 else
1049 x += windows[ w ]->area.width()*(1.0 - timeLine.value());
1053 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
1054 if( effects->compositingType() == OpenGLCompositing )
1056 glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT );
1057 glEnable( GL_BLEND );
1058 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
1059 // Render some background
1060 float alpha = 0.5;
1061 if( ( windows.size() % 2 == 1 ) && animation && w == edge_window )
1063 if( timeLine.value() < 0.5 )
1064 alpha *= (1.0 - timeLine.value()*2.0);
1065 else
1066 alpha *= (timeLine.value()*2.0 - 1.0);
1068 glColor4f( 0, 0, 0, alpha );
1069 renderRoundBox( QRect( x-3, y-3, width+6, height+6 ), 3 );
1070 // Render the icon
1071 glColor4f( 1, 1, 1, 1 );
1072 windows[ w ]->iconTexture.bind();
1073 windows[ w ]->iconTexture.render( infiniteRegion(), QRect( x, y, width, height ));
1074 windows[ w ]->iconTexture.unbind();
1075 glPopAttrib();
1077 #endif
1078 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
1079 if( effects->compositingType() == XRenderCompositing )
1081 XRenderComposite( display(),
1082 windows[ w ]->icon.depth() == 32 ? PictOpOver : PictOpSrc,
1083 windows[ w ]->iconPicture, None,
1084 effects->xrenderBufferPicture(),
1085 0, 0, 0, 0, x, y, width, height );
1087 #endif
1090 void BoxSwitchEffect::paintText( const QString& text )
1092 int maxwidth = text_area.width();
1093 effects->paintText( text, text_area.center(), maxwidth, color_text, text_font );
1096 } // namespace