1 /********************************************************************
2 KWin - the KDE window manager
3 This file is part of the KDE project.
5 Copyright (C) 2007 Lubos Lunak <l.lunak@kde.org>
6 Copyright (C) 2008 Lucas Murray <lmurray@undefinedfire.com>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 *********************************************************************/
29 KWIN_EFFECT( slide
, SlideEffect
)
31 SlideEffect::SlideEffect()
34 mTimeLine
.setCurveShape(TimeLine::EaseInOutCurve
);
35 reconfigure( ReconfigureAll
);
38 void SlideEffect::reconfigure( ReconfigureFlags
)
40 mTimeLine
.setDuration( animationTime( 250 ));
43 void SlideEffect::prePaintScreen( ScreenPrePaintData
& data
, int time
)
47 mTimeLine
.addTime(time
);
49 // PAINT_SCREEN_BACKGROUND_FIRST is needed because screen will be actually painted more than once,
50 // so with normal screen painting second screen paint would erase parts of the first paint
51 if( mTimeLine
.value() != 1 )
52 data
.mask
|= PAINT_SCREEN_TRANSFORMED
| PAINT_SCREEN_BACKGROUND_FIRST
;
56 mTimeLine
.setProgress(0);
57 effects
->setActiveFullScreenEffect( NULL
);
60 effects
->prePaintScreen( data
, time
);
63 void SlideEffect::prePaintWindow( EffectWindow
* w
, WindowPrePaintData
& data
, int time
)
67 if( w
->isOnAllDesktops())
69 if( slide_painting_sticky
)
70 data
.setTransformed();
72 w
->disablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP
);
74 else if( w
->isOnDesktop( painting_desktop
))
75 w
->enablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP
);
77 w
->disablePainting( EffectWindow::PAINT_DISABLED_BY_DESKTOP
);
79 effects
->prePaintWindow( w
, data
, time
);
82 void SlideEffect::paintScreen( int mask
, QRegion region
, ScreenPaintData
& data
)
84 if( mTimeLine
.value() == 0 )
86 effects
->paintScreen( mask
, region
, data
);
91 Transformations are done by remembering starting position of the change and the progress
92 of it, the destination is computed from the current desktop. Positions of desktops
93 are done using their topleft corner.
95 QPoint destPos
= desktopRect( effects
->currentDesktop(), false ).topLeft();
96 QPoint diffPos
= destPos
- slide_start_pos
;
99 if( effects
->optionRollOverDesktops())
102 Qt::Orientation orientation
;
103 effects
->calcDesktopLayout( &x
, &y
, &orientation
);
104 w
= x
* displayWidth();
105 h
= y
* displayHeight();
106 // wrap around if shorter
107 if( diffPos
.x() > 0 && diffPos
.x() > w
/ 2 )
108 diffPos
.setX( diffPos
.x() - w
);
109 if( diffPos
.x() < 0 && abs( diffPos
.x()) > w
/ 2 )
110 diffPos
.setX( diffPos
.x() + w
);
111 if( diffPos
.y() > 0 && diffPos
.y() > h
/ 2 )
112 diffPos
.setY( diffPos
.y() - h
);
113 if( diffPos
.y() < 0 && abs( diffPos
.y()) > h
/ 2 )
114 diffPos
.setY( diffPos
.y() + h
);
116 QPoint currentPos
= slide_start_pos
+ mTimeLine
.value() * diffPos
;
117 QSize
displaySize( displayWidth(), displayHeight());
118 QRegion currentRegion
= QRect( currentPos
, displaySize
);
119 if( effects
->optionRollOverDesktops())
121 currentRegion
|= ( currentRegion
& QRect( -w
, 0, w
, h
)).translated( w
, 0 );
122 currentRegion
|= ( currentRegion
& QRect( 0, -h
, w
, h
)).translated( 0, h
);
123 currentRegion
|= ( currentRegion
& QRect( w
, 0, w
, h
)).translated( -w
, 0 );
124 currentRegion
|= ( currentRegion
& QRect( 0, h
, w
, h
)).translated( 0, -h
);
126 bool do_sticky
= true;
127 for( int desktop
= 1;
128 desktop
<= effects
->numberOfDesktops();
131 QRect rect
= desktopRect( desktop
, false );
132 if( currentRegion
.contains( rect
)) // part of the desktop needs painting
134 painting_desktop
= desktop
;
135 slide_painting_sticky
= do_sticky
;
136 slide_painting_diff
= rect
.topLeft() - currentPos
;
137 if( effects
->optionRollOverDesktops())
139 if( slide_painting_diff
.x() > displayWidth())
140 slide_painting_diff
.setX( slide_painting_diff
.x() - w
);
141 if( slide_painting_diff
.x() < -displayWidth())
142 slide_painting_diff
.setX( slide_painting_diff
.x() + w
);
143 if( slide_painting_diff
.y() > displayHeight())
144 slide_painting_diff
.setY( slide_painting_diff
.y() - h
);
145 if( slide_painting_diff
.y() < -displayHeight())
146 slide_painting_diff
.setY( slide_painting_diff
.y() + h
);
148 do_sticky
= false; // paint on-all-desktop windows only once
149 ScreenPaintData d
= data
;
150 d
.xTranslate
+= slide_painting_diff
.x();
151 d
.yTranslate
+= slide_painting_diff
.y();
152 // TODO mask parts that are not visible?
153 effects
->paintScreen( mask
, region
, d
);
158 void SlideEffect::paintWindow( EffectWindow
* w
, int mask
, QRegion region
, WindowPaintData
& data
)
161 { // don't move windows on all desktops (compensate screen transformation)
162 if( w
->isOnAllDesktops()) // TODO also fix 'Workspace::movingClient'
164 data
.xTranslate
-= slide_painting_diff
.x();
165 data
.yTranslate
-= slide_painting_diff
.y();
168 effects
->paintWindow( w
, mask
, region
, data
);
171 void SlideEffect::postPaintScreen()
174 effects
->addRepaintFull();
175 effects
->postPaintScreen();
178 // Gives a position of the given desktop when all desktops are arranged in a grid
179 QRect
SlideEffect::desktopRect( int desktop
, bool scaled
) const
182 Qt::Orientation orientation
;
183 effects
->calcDesktopLayout( &x
, &y
, &orientation
);
184 --desktop
; // make it start with 0
186 if( orientation
== Qt::Horizontal
)
187 rect
= QRect(( desktop
% x
) * displayWidth(), ( desktop
/ x
) * displayHeight(),
188 displayWidth(), displayHeight());
190 rect
= QRect(( desktop
/ y
) * displayWidth(), ( desktop
% y
) * displayHeight(),
191 displayWidth(), displayHeight());
194 QRect current
= desktopRect( effects
->currentDesktop(), false );
195 double progress
= mTimeLine
.value();
196 rect
= QRect( qRound( interpolate( rect
.x() - current
.x(), rect
.x() / double( x
), progress
)),
197 qRound( interpolate( rect
.y() - current
.y(), rect
.y() / double( y
), progress
)),
198 qRound( interpolate( rect
.width(), displayWidth() / double( x
), progress
)),
199 qRound( interpolate( rect
.height(), displayHeight() / double( y
), progress
)));
203 void SlideEffect::desktopChanged( int old
)
205 if( effects
->activeFullScreenEffect() && effects
->activeFullScreenEffect() != this )
208 if( slide
) // old slide still in progress
210 QPoint diffPos
= desktopRect( old
, false ).topLeft() - slide_start_pos
;
213 if( effects
->optionRollOverDesktops())
216 Qt::Orientation orientation
;
217 effects
->calcDesktopLayout( &x
, &y
, &orientation
);
218 w
= x
* displayWidth();
219 h
= y
* displayHeight();
220 // wrap around if shorter
221 if( diffPos
.x() > 0 && diffPos
.x() > w
/ 2 )
222 diffPos
.setX( diffPos
.x() - w
);
223 if( diffPos
.x() < 0 && abs( diffPos
.x()) > w
/ 2 )
224 diffPos
.setX( diffPos
.x() + w
);
225 if( diffPos
.y() > 0 && diffPos
.y() > h
/ 2 )
226 diffPos
.setY( diffPos
.y() - h
);
227 if( diffPos
.y() < 0 && abs( diffPos
.y()) > h
/ 2 )
228 diffPos
.setY( diffPos
.y() + h
);
230 QPoint currentPos
= slide_start_pos
+ mTimeLine
.value() * diffPos
;
231 QRegion currentRegion
= QRect( currentPos
, QSize( displayWidth(), displayHeight()));
232 if( effects
->optionRollOverDesktops())
234 currentRegion
|= ( currentRegion
& QRect( -w
, 0, w
, h
)).translated( w
, 0 );
235 currentRegion
|= ( currentRegion
& QRect( 0, -h
, w
, h
)).translated( 0, h
);
236 currentRegion
|= ( currentRegion
& QRect( w
, 0, w
, h
)).translated( -w
, 0 );
237 currentRegion
|= ( currentRegion
& QRect( 0, h
, w
, h
)).translated( 0, -h
);
239 QRect rect
= desktopRect( effects
->currentDesktop(), false );
240 if( currentRegion
.contains( rect
))
241 { // current position is in new current desktop (e.g. quickly changing back),
242 // don't do full progress
243 if( abs( currentPos
.x() - rect
.x()) > abs( currentPos
.y() - rect
.y()))
244 mTimeLine
.setProgress(1 - abs( currentPos
.x() - rect
.x()) / double( displayWidth()));
246 mTimeLine
.setProgress(1 - abs( currentPos
.y() - rect
.y()) / double( displayHeight()));
248 else // current position is not on current desktop, do full progress
249 mTimeLine
.setProgress(0);
250 diffPos
= rect
.topLeft() - currentPos
;
251 if( mTimeLine
.value() <= 0 )
253 // Compute starting point for this new move (given current and end positions)
254 slide_start_pos
= rect
.topLeft() - diffPos
* 1 / ( 1 - mTimeLine
.value() );
257 { // at the end, stop
259 mTimeLine
.setProgress(0);
260 effects
->setActiveFullScreenEffect( NULL
);
265 if( effects
->activeFullScreenEffect() && effects
->activeFullScreenEffect() != this )
267 mTimeLine
.setProgress(0);
268 slide_start_pos
= desktopRect( old
, false ).topLeft();
270 effects
->setActiveFullScreenEffect( this );
272 effects
->addRepaintFull();