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 *********************************************************************/
21 // based on minimize animation by Rivo Laks <rivolaks@hot.ee>
23 #include "magiclamp.h"
24 #include <kwinconfig.h>
25 #include <kconfiggroup.h>
30 KWIN_EFFECT( magiclamp
, MagicLampEffect
)
32 MagicLampEffect::MagicLampEffect()
34 mActiveAnimations
= 0;
35 reconfigure( ReconfigureAll
);
38 void MagicLampEffect::reconfigure( ReconfigureFlags
)
40 KConfigGroup conf
= effects
->effectConfig( "MagicLamp" );
41 mAnimationDuration
= animationTime( conf
, "AnimationDuration", 250 );
44 void MagicLampEffect::prePaintScreen( ScreenPrePaintData
& data
, int time
)
46 mActiveAnimations
= mTimeLineWindows
.count();
47 if( mActiveAnimations
> 0 )
48 // We need to mark the screen windows as transformed. Otherwise the
49 // whole screen won't be repainted, resulting in artefacts
50 data
.mask
|= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS
;
52 effects
->prePaintScreen(data
, time
);
55 void MagicLampEffect::prePaintWindow( EffectWindow
* w
, WindowPrePaintData
& data
, int time
)
57 if( mTimeLineWindows
.contains( w
))
59 if( w
->isMinimized() )
61 mTimeLineWindows
[w
].addTime(time
);
62 if( mTimeLineWindows
[w
].progress() >= 1.0f
)
63 mTimeLineWindows
.remove( w
);
67 mTimeLineWindows
[w
].removeTime(time
);
68 if( mTimeLineWindows
[w
].progress() <= 0.0f
)
69 mTimeLineWindows
.remove( w
);
72 // Schedule window for transformation if the animation is still in
74 if( mTimeLineWindows
.contains( w
))
76 // We'll transform this window
77 data
.setTransformed();
78 data
.quads
= data
.quads
.makeGrid( 40 );
79 w
->enablePainting( EffectWindow::PAINT_DISABLED_BY_MINIMIZE
);
83 effects
->prePaintWindow( w
, data
, time
);
86 void MagicLampEffect::paintWindow( EffectWindow
* w
, int mask
, QRegion region
, WindowPaintData
& data
)
88 if( mTimeLineWindows
.contains( w
))
90 // 0 = not minimized, 1 = fully minimized
91 float progress
= mTimeLineWindows
[w
].value();
93 QRect geo
= w
->geometry();
94 QRect icon
= w
->iconGeometry();
95 // If there's no icon geometry, minimize to the center of the screen
97 icon
= QRect( displayWidth() / 2, displayHeight(), 0, 0 );
99 QRect area
= effects
->clientArea( PlacementArea
, w
);
100 IconPosition position
= Bottom
;
102 if( icon
.y() + icon
.height() <= area
.y() )
107 if( icon
.y() >= area
.y()+area
.height() )
112 if( icon
.x() + icon
.width() <= area
.x() )
117 if( icon
.x() >= area
.x()+ area
.width() )
122 WindowQuadList newQuads
;
123 foreach( WindowQuad quad
, data
.quads
)
125 if( position
== Top
|| position
== Bottom
)
127 // quadFactor defines how fast a quad is vertically moved: y coordinates near to window top are slowed down
128 // it is used as quadFactor^3/windowHeight^3
129 // quadFactor is the y position of the quad but is changed towards becomming the window height
130 // by that the factor becomes 1 and has no influence any more
132 // how far has a quad to be moved? Distance between icon and window multiplied by the progress and by the quadFactor
135 // top and bottom progress is the factor which defines how far the x values have to be changed
136 // factor is the current moved y value diveded by the distance between icon and window
138 float bottomProgress
;
139 if( position
== Bottom
)
141 quadFactor
= quad
[0].y() + (geo
.height() - quad
[0].y())*progress
;
142 yOffsetTop
= (icon
.y() + quad
[0].y() - geo
.y())*progress
*
143 ((quadFactor
*quadFactor
*quadFactor
)/(geo
.height()*geo
.height()*geo
.height()));
144 quadFactor
= quad
[2].y() + (geo
.height() - quad
[2].y())*progress
;
145 yOffsetBottom
= (icon
.y() + quad
[2].y() - geo
.y())*progress
*
146 ((quadFactor
*quadFactor
*quadFactor
)/(geo
.height()*geo
.height()*geo
.height()));
147 topProgress
= qMin( yOffsetTop
/(icon
.y()+icon
.height() - geo
.y()-(float)(quad
[0].y()/geo
.height()*geo
.height())), 1.0f
);
148 bottomProgress
= qMin( yOffsetBottom
/(icon
.y()+icon
.height() - geo
.y()-(float)(quad
[2].y()/geo
.height()*geo
.height())), 1.0f
);
152 quadFactor
= geo
.height() - quad
[0].y() + (quad
[0].y())*progress
;
153 yOffsetTop
= (geo
.y() - icon
.height() + geo
.height() + quad
[0].y() - icon
.y())*progress
*
154 ((quadFactor
*quadFactor
*quadFactor
)/(geo
.height()*geo
.height()*geo
.height()));
155 quadFactor
= geo
.height() - quad
[2].y() + (quad
[2].y())*progress
;
156 yOffsetBottom
= (geo
.y() - icon
.height() + geo
.height() + quad
[2].y() - icon
.y())*progress
*
157 ((quadFactor
*quadFactor
*quadFactor
)/(geo
.height()*geo
.height()*geo
.height()));
158 topProgress
= qMin( yOffsetTop
/(geo
.y() - icon
.height() + geo
.height() - icon
.y() -
159 (float)((geo
.height()-quad
[0].y())/geo
.height()*geo
.height())), 1.0f
);
160 bottomProgress
= qMin( yOffsetBottom
/(geo
.y() - icon
.height() + geo
.height() - icon
.y() -
161 (float)((geo
.height()-quad
[2].y())/geo
.height()*geo
.height())), 1.0f
);
163 if( position
== Top
)
168 if( topProgress
< 0 )
170 if( bottomProgress
< 0 )
171 bottomProgress
*= -1;
173 // x values are moved towards the center of the icon
174 quad
[0].setX( (icon
.x() + icon
.width()*(quad
[0].x()/geo
.width()) - (quad
[0].x() + geo
.x()))*topProgress
+ quad
[0].x() );
175 quad
[1].setX( (icon
.x() + icon
.width()*(quad
[1].x()/geo
.width()) - (quad
[1].x() + geo
.x()))*topProgress
+ quad
[1].x() );
176 quad
[2].setX( (icon
.x() + icon
.width()*(quad
[2].x()/geo
.width()) - (quad
[2].x() + geo
.x()))*bottomProgress
+ quad
[2].x() );
177 quad
[3].setX( (icon
.x() + icon
.width()*(quad
[3].x()/geo
.width()) - (quad
[3].x() + geo
.x()))*bottomProgress
+ quad
[3].x() );
179 quad
[0].setY( quad
[0].y() + yOffsetTop
);
180 quad
[1].setY( quad
[1].y() + yOffsetTop
);
181 quad
[2].setY( quad
[2].y() + yOffsetBottom
);
182 quad
[3].setY( quad
[3].y() + yOffsetBottom
);
191 if( position
== Right
)
193 quadFactor
= quad
[0].x() + (geo
.width() - quad
[0].x())*progress
;
194 xOffsetLeft
= (icon
.x() + quad
[0].x() - geo
.x())*progress
*
195 ((quadFactor
*quadFactor
*quadFactor
)/(geo
.width()*geo
.width()*geo
.width()));
196 quadFactor
= quad
[1].x() + (geo
.width() - quad
[1].x())*progress
;
197 xOffsetRight
= (icon
.x() + quad
[1].x() - geo
.x())*progress
*
198 ((quadFactor
*quadFactor
*quadFactor
)/(geo
.width()*geo
.width()*geo
.width()));
199 leftProgress
= qMin( xOffsetLeft
/(icon
.x()+icon
.width() - geo
.x()-(float)(quad
[0].x()/geo
.width()*geo
.width())), 1.0f
);
200 rightProgress
= qMin( xOffsetRight
/(icon
.x()+icon
.width() - geo
.x()-(float)(quad
[1].x()/geo
.width()*geo
.width())), 1.0f
);
204 quadFactor
= geo
.width() - quad
[0].x() + (quad
[0].x())*progress
;
205 xOffsetLeft
= (geo
.x() - icon
.width() + geo
.width() + quad
[0].x() - icon
.x())*progress
*
206 ((quadFactor
*quadFactor
*quadFactor
)/(geo
.width()*geo
.width()*geo
.width()));
207 quadFactor
= geo
.width() - quad
[1].x() + (quad
[1].x())*progress
;
208 xOffsetRight
= (geo
.x() - icon
.width() + geo
.width() + quad
[1].x() - icon
.x())*progress
*
209 ((quadFactor
*quadFactor
*quadFactor
)/(geo
.width()*geo
.width()*geo
.width()));
210 leftProgress
= qMin( xOffsetLeft
/(geo
.x() - icon
.width() + geo
.width() - icon
.x() -
211 (float)((geo
.width()-quad
[0].x())/geo
.width()*geo
.width())), 1.0f
);
212 rightProgress
= qMin( xOffsetRight
/(geo
.x() - icon
.width() + geo
.width() - icon
.x() -
213 (float)((geo
.width()-quad
[1].x())/geo
.width()*geo
.width())), 1.0f
);
215 if( position
== Left
)
220 if( leftProgress
< 0 )
222 if( rightProgress
< 0 )
225 quad
[0].setY( (icon
.y() + icon
.height()*(quad
[0].y()/geo
.height()) - (quad
[0].y() + geo
.y()))*leftProgress
+ quad
[0].y() );
226 quad
[1].setY( (icon
.y() + icon
.height()*(quad
[1].y()/geo
.height()) - (quad
[1].y() + geo
.y()))*rightProgress
+ quad
[1].y() );
227 quad
[2].setY( (icon
.y() + icon
.height()*(quad
[2].y()/geo
.height()) - (quad
[2].y() + geo
.y()))*rightProgress
+ quad
[2].y() );
228 quad
[3].setY( (icon
.y() + icon
.height()*(quad
[3].y()/geo
.height()) - (quad
[3].y() + geo
.y()))*leftProgress
+ quad
[3].y() );
230 quad
[0].setX( quad
[0].x() + xOffsetLeft
);
231 quad
[1].setX( quad
[1].x() + xOffsetRight
);
232 quad
[2].setX( quad
[2].x() + xOffsetRight
);
233 quad
[3].setX( quad
[3].x() + xOffsetLeft
);
235 newQuads
.append( quad
);
237 data
.quads
= newQuads
;
240 // Call the next effect.
241 effects
->paintWindow( w
, mask
, region
, data
);
244 void MagicLampEffect::postPaintScreen()
246 if( mActiveAnimations
> 0 )
247 // Repaint the workspace so that everything would be repainted next time
248 effects
->addRepaintFull();
249 mActiveAnimations
= mTimeLineWindows
.count();
251 // Call the next effect.
252 effects
->postPaintScreen();
255 void MagicLampEffect::windowMinimized( EffectWindow
* w
)
257 mTimeLineWindows
[w
].setCurveShape(TimeLine::LinearCurve
);
258 mTimeLineWindows
[w
].setDuration( mAnimationDuration
);
259 mTimeLineWindows
[w
].setProgress(0.0f
);
262 void MagicLampEffect::windowUnminimized( EffectWindow
* w
)
264 mTimeLineWindows
[w
].setCurveShape(TimeLine::LinearCurve
);
265 mTimeLineWindows
[w
].setDuration( mAnimationDuration
);
266 mTimeLineWindows
[w
].setProgress(1.0f
);