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>
28 #include <kapplication.h>
29 #include <kcolorscheme.h>
30 #include <kconfiggroup.h>
32 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
39 KWIN_EFFECT( boxswitch
, BoxSwitchEffect
)
41 BoxSwitchEffect::BoxSwitchEffect()
44 , selected_window( 0 )
45 , painting_desktop( 0 )
47 , highlight_is_set( false )
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
)
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
);
92 if( painting_desktop
)
94 if( w
->isOnDesktop( painting_desktop
))
95 w
->enablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP
);
97 w
->disablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP
);
101 effects
->prePaintWindow( w
, data
, time
);
104 void BoxSwitchEffect::prePaintScreen( ScreenPrePaintData
& data
, int time
)
107 activeTimeLine
.addTime( time
);
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
);
123 if( mMode
== TabBoxWindowsMode
)
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
) );
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() );
155 if( !painting_desktop
)
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 );
187 if( !scheduled_directions
.isEmpty() )
189 direction
= scheduled_directions
.dequeue();
193 QRect repaint
= QRect( frame_area
.x() - item_max_size
.width()*0.5,
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
;
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
)
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
);
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
)
264 if( mMode
== TabBoxWindowsMode
)
266 if( windows
.contains( w
))
268 effects
->addRepaint( windows
[ w
]->area
);
273 if( w
->isOnAllDesktops())
275 foreach( ItemInfo
* info
, desktops
)
276 effects
->addRepaint( info
->area
);
280 effects
->addRepaint( desktops
[ w
->desktop() ]->area
);
286 void BoxSwitchEffect::windowGeometryShapeChanged( EffectWindow
* w
, const QRect
& old
)
290 if( mMode
== TabBoxWindowsMode
)
292 if( windows
.contains( w
) && w
->size() != old
.size())
294 effects
->addRepaint( windows
[ w
]->area
);
299 if( w
->isOnAllDesktops())
301 foreach( ItemInfo
* info
, desktops
)
302 effects
->addRepaint( info
->area
);
306 effects
->addRepaint( desktops
[ w
->desktop() ]->area
);
312 void BoxSwitchEffect::tabBoxAdded( int mode
)
316 if( mode
== TabBoxWindowsMode
)
318 if( effects
->currentTabBoxWindowList().count() > 0 )
321 effects
->refTabBox();
322 highlight_is_set
= false;
324 scheduled_directions
.clear();
331 if( effects
->currentTabBoxDesktopList().count() > 0 )
334 painting_desktop
= 0;
335 effects
->refTabBox();
342 void BoxSwitchEffect::tabBoxClosed()
348 void BoxSwitchEffect::tabBoxUpdated()
352 if( mMode
== TabBoxWindowsMode
&& selected_window
!= effects
->currentTabBoxWindow() )
354 if( selected_window
!= NULL
)
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
;
363 new_direction
= Left
;
365 new_direction
= Right
;
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
;
376 new_direction
= Left
;
381 direction
= new_direction
;
384 for( int i
=0; i
<distance
; i
++ )
386 if( !scheduled_directions
.isEmpty() && scheduled_directions
.last() != new_direction
)
387 scheduled_directions
.pop_back();
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();
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
)
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()
430 // Do this here so we have correct fading on deactivation
431 qDeleteAll( windows
);
434 if( mMode
== TabBoxWindowsMode
)
436 original_windows
= effects
->currentTabBoxWindowList();
437 setSelectedWindow( effects
->currentTabBoxWindow());
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())
458 void BoxSwitchEffect::setInactive()
461 effects
->unrefTabBox();
464 effects
->destroyInputWindow( mInput
);
467 if( mMode
== TabBoxWindowsMode
)
469 foreach( EffectWindow
* w
, windows
.keys())
471 if( w
!= selected_window
)
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 );
481 qDeleteAll( windows
);
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 );
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()
519 if( mMode
== TabBoxWindowsMode
)
521 itemcount
= original_windows
.count();
522 item_max_size
.setWidth( 200 );
523 item_max_size
.setHeight( 200 );
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())
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
)
562 int index
= original_windows
.indexOf( effects
->currentTabBoxWindow() );
563 int leftIndex
= index
;
564 int rightIndex
= index
+ 1;
565 if( rightIndex
== original_windows
.count() )
567 EffectWindowList ordered_windows
;
569 int leftWindowCount
= original_windows
.count()/2;
570 int rightWindowCount
= leftWindowCount
;
571 if( original_windows
.count()%2 == 1 )
573 for( int i
=0; i
< leftWindowCount
; i
++ )
575 int tempIndex
= ( leftIndex
- i
);
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
];
591 EffectWindow
* w
= ordered_windows
.takeLast();
592 ordered_windows
.prepend( w
);
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();
606 ordered_windows
.prepend( w
);
610 EffectWindow
* w
= ordered_windows
.takeFirst();
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();
625 if( direction
== Left
)
626 offset
= (float)item_max_size
.width()*(1.0-timeLine
.value());
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();
636 if( animation
&& timeLine
.value() < 0.5 )
638 if( direction
== Left
)
643 if( ordered_windows
.count()%2 == 0 )
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;
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
;
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
);
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
);
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());
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 );
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
);
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());
757 void BoxSwitchEffect::paintWindowThumbnail( EffectWindow
* w
)
759 if( !windows
.contains( w
))
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();
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
)
788 if( quad
.right() <= splitPoint
)
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
;
797 data
.quads
= right_quads
;
801 if( direction
== Left
)
802 data
.quads
= right_quads
;
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());
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());
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());
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());
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();
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());
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
)
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
);
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
))
940 ScreenPaintData data
;
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
);
957 effects
->paintScreen( PAINT_SCREEN_TRANSFORMED
| PAINT_SCREEN_BACKGROUND_FIRST
,
961 void BoxSwitchEffect::paintWindowIcon( EffectWindow
* w
)
963 if( !windows
.contains( w
))
965 // Don't render null icons
966 if( w
->icon().isNull() )
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
)
977 if( timeLine
.value() < 0.5 )
978 alpha
= 255.0f
* (1.0 - timeLine
.value()*2.0);
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
);
992 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
993 if( effects
->compositingType() == XRenderCompositing
)
994 windows
[ w
]->iconPicture
= XRenderPicture( windows
[ w
]->icon
);
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
;
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
);
1017 x
+= windows
[ w
]->area
.width()*timeLine
.value();
1021 if( direction
== Left
)
1022 x
+= windows
[ w
]->area
.width()*(1.0-timeLine
.value());
1025 x
-= windows
[ w
]->area
.width()*(1.0-timeLine
.value());
1026 x
= qMax( x
, frame_area
.x() + frame_margin
);
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();
1042 x
-= windows
[ w
]->area
.width()*timeLine
.value();
1046 if( direction
== Left
)
1047 x
-= windows
[ w
]->area
.width()*(1.0 - timeLine
.value());
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
1061 if( ( windows
.size() % 2 == 1 ) && animation
&& w
== edge_window
)
1063 if( timeLine
.value() < 0.5 )
1064 alpha
*= (1.0 - timeLine
.value()*2.0);
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 );
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();
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
);
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
);