add more spacing
[personal-kdebase.git] / workspace / kwin / effects / wobblywindows.cpp
blob72bb3862378198140b8e739924e8cc2f776151fd
1 /*****************************************************************
2 KWin - the KDE window manager
3 This file is part of the KDE project.
5 Copyright (C) 2008 Cédric Borgese <cedric.borgese@gmail.com>
7 You can Freely distribute this program under the GNU General Public
8 License. See the file "COPYING" for the exact licensing terms.
9 ******************************************************************/
12 #include "wobblywindows.h"
14 #include <kdebug.h>
15 #include <kconfiggroup.h>
16 #include <math.h>
18 #define USE_ASSERT
19 #ifdef USE_ASSERT
20 #define ASSERT1 assert
21 #else
22 #define ASSERT1
23 #endif
25 //#define COMPUTE_STATS
27 // if you enable it and run kwin in a terminal from the session it manages,
28 // be sure to redirect the output of kwin in a file or
29 // you'll propably get deadlocks.
30 //#define VERBOSE_MODE
32 #if defined COMPUTE_STATS && !defined VERBOSE_MODE
33 # ifdef __GNUC__
34 # warning "You enable COMPUTE_STATS without VERBOSE_MODE, computed stats will not be printed."
35 # endif
36 #endif
38 namespace KWin
41 static const qreal STIFFNESS = 0.15;
42 static const qreal DRAG = 0.80;
43 static const qreal MOVEFACTOR = 0.10;
45 static const int XTESSELATION = 20;
46 static const int YTESSELATION = 20;
48 static const qreal MINVELOCITY = 0.0;
49 static const qreal MAXVELOCITY = 1000.0;
50 static const qreal STOPVELOCITY = 0.5;
51 static const qreal MINACCELERATION = 0.0;
52 static const qreal MAXACCELERATION = 1000.0;
53 static const qreal STOPACCELERATION = 5.0;
55 struct ParameterSet
57 qreal stiffness;
58 qreal drag;
59 qreal move_factor;
61 qreal xTesselation;
62 qreal yTesselation;
64 qreal minVelocity;
65 qreal maxVelocity;
66 qreal stopVelocity;
67 qreal minAcceleration;
68 qreal maxAcceleration;
69 qreal stopAcceleration;
71 bool moveEffectEnabled;
72 bool openEffectEnabled;
73 bool closeEffectEnabled;
76 static const ParameterSet set_0 =
78 0.15,
79 0.80,
80 0.10,
81 20.0,
82 20.0,
83 0.0,
84 1000.0,
85 0.5,
86 0.0,
87 1000.0,
88 0.5,
89 true,
90 false,
91 false
94 static const ParameterSet set_1 =
96 0.10,
97 0.85,
98 0.10,
99 20.0,
100 20.0,
101 0.0,
102 1000.0,
103 0.5,
104 0.0,
105 1000.0,
106 0.5,
107 true,
108 false,
109 false
112 static const ParameterSet set_2 =
114 0.06,
115 0.90,
116 0.10,
117 20.0,
118 20.0,
119 0.0,
120 1000.0,
121 0.5,
122 0.0,
123 1000.0,
124 0.5,
125 true,
126 false,
127 false
130 static const ParameterSet set_3 =
132 0.03,
133 0.92,
134 0.20,
135 20.0,
136 20.0,
137 0.0,
138 1000.0,
139 0.5,
140 0.0,
141 1000.0,
142 0.5,
143 true,
144 false,
145 false
148 static const ParameterSet set_4 =
150 0.01,
151 0.97,
152 0.25,
153 20.0,
154 20.0,
155 0.0,
156 1000.0,
157 0.5,
158 0.0,
159 1000.0,
160 0.5,
161 true,
162 false,
163 false
166 static const ParameterSet pset[5] = { set_0, set_1, set_2, set_3, set_4 };
168 KWIN_EFFECT(wobblywindows, WobblyWindowsEffect)
170 WobblyWindowsEffect::WobblyWindowsEffect()
172 reconfigure( ReconfigureAll );
175 WobblyWindowsEffect::~WobblyWindowsEffect()
177 if (!windows.empty())
179 // we should be empty at this point...
180 // emit a warning and clean the list.
181 kDebug(1212) << "Windows list not empty. Left items : " << windows.count();
182 QHash< const EffectWindow*, WindowWobblyInfos >::iterator i;
183 for (i = windows.begin(); i != windows.end(); ++i)
185 freeWobblyInfo(i.value());
190 void WobblyWindowsEffect::reconfigure( ReconfigureFlags )
192 KConfigGroup conf = effects->effectConfig("Wobbly");
195 QString settingsMode = conf.readEntry("Settings", "Auto");
196 if (settingsMode != "Custom")
198 unsigned int wobblynessLevel = conf.readEntry("WobblynessLevel", 0);
199 if (wobblynessLevel > 4)
201 kDebug(1212) << "Wrong value for \"WobblynessLevel\" : " << wobblynessLevel;
202 wobblynessLevel = 4;
204 setParameterSet(pset[wobblynessLevel]);
206 if (conf.readEntry("AdvancedMode", false))
208 m_stiffness = conf.readEntry("Stiffness", STIFFNESS * 100.0) / 100.0;
209 m_drag = conf.readEntry("Drag", DRAG * 100.0) / 100.0;
210 m_move_factor = conf.readEntry("MoveFactor", MOVEFACTOR * 100.0) / 100.0;
213 else // Custom method, read all values from config file.
215 m_stiffness = conf.readEntry("Stiffness", STIFFNESS);
216 m_drag = conf.readEntry("Drag", DRAG);
217 m_move_factor = conf.readEntry("MoveFactor", MOVEFACTOR);
219 m_xTesselation = conf.readEntry("XTesselation", XTESSELATION);
220 m_yTesselation = conf.readEntry("YTesselation", YTESSELATION);
222 m_minVelocity = conf.readEntry("MinVelocity", MINVELOCITY);
223 m_maxVelocity = conf.readEntry("MaxVelocity", MAXVELOCITY);
224 m_stopVelocity = conf.readEntry("StopVelocity", STOPVELOCITY);
225 m_minAcceleration = conf.readEntry("MinAcceleration", MINACCELERATION);
226 m_maxAcceleration = conf.readEntry("MaxAcceleration", MAXACCELERATION);
227 m_stopAcceleration = conf.readEntry("StopAcceleration", STOPACCELERATION);
229 m_moveEffectEnabled = conf.readEntry("MoveEffect", true);
230 m_openEffectEnabled = conf.readEntry("OpenEffect", false);
231 // disable close effect by default for now as it doesn't do what I want.
232 m_closeEffectEnabled = conf.readEntry("CloseEffect", false);
235 m_moveWobble = conf.readEntry("MoveWobble", true);
236 m_resizeWobble = conf.readEntry("ResizeWobble", true);
238 #if defined VERBOSE_MODE
239 kDebug(1212) << "Parameters :\n" <<
240 "move : " << m_moveEffectEnabled << ", open : " << m_openEffectEnabled << ", close : " << m_closeEffectEnabled << "\n"
241 "grid(" << m_stiffness << ", " << m_drag << ", " << m_move_factor << ")\n" <<
242 "velocity(" << m_minVelocity << ", " << m_maxVelocity << ", " << m_stopVelocity << ")\n" <<
243 "acceleration(" << m_minAcceleration << ", " << m_maxAcceleration << ", " << m_stopAcceleration << ")\n" <<
244 "tesselation(" << m_xTesselation << ", " << m_yTesselation << ")";
245 #endif
249 void WobblyWindowsEffect::setParameterSet(const ParameterSet& pset)
251 m_stiffness = pset.stiffness;
252 m_drag = pset.drag;
253 m_move_factor = pset.move_factor;
255 m_xTesselation = pset.xTesselation;
256 m_yTesselation = pset.yTesselation;
258 m_minVelocity = pset.minVelocity;
259 m_maxVelocity = pset.maxVelocity;
260 m_stopVelocity = pset.stopVelocity;
261 m_minAcceleration = pset.minAcceleration;
262 m_maxAcceleration = pset.maxAcceleration;
263 m_stopAcceleration = pset.stopAcceleration;
265 m_moveEffectEnabled = pset.moveEffectEnabled;
266 m_openEffectEnabled = pset.openEffectEnabled;
267 m_closeEffectEnabled = pset.closeEffectEnabled;
270 void WobblyWindowsEffect::setVelocityThreshold(qreal m_minVelocity)
272 this->m_minVelocity = m_minVelocity;
275 void WobblyWindowsEffect::setMoveFactor(qreal factor)
277 m_move_factor = factor;
280 void WobblyWindowsEffect::setStiffness(qreal stiffness)
282 m_stiffness = stiffness;
285 void WobblyWindowsEffect::setDrag(qreal drag)
287 m_drag = drag;
290 void WobblyWindowsEffect::prePaintScreen(ScreenPrePaintData& data, int time)
292 // We need to mark the screen windows as transformed. Otherwise the whole
293 // screen won't be repainted, resulting in artefacts.
294 // Could we just set a subset of the screen to be repainted ?
295 if (windows.count() != 0)
297 data.mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS;
300 // this set the QRect invalid.
301 m_updateRegion.setWidth(0);
303 effects->prePaintScreen(data, time);
305 const qreal maxTime = 10.0;
306 void WobblyWindowsEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time)
308 if (windows.contains(w))
310 data.setTransformed();
311 data.quads = data.quads.makeRegularGrid(m_xTesselation, m_yTesselation);
312 bool stop = false;
313 qreal updateTime = time;
315 while (!stop && (updateTime > maxTime))
317 #if defined VERBOSE_MODE
318 kDebug(1212) << "loop time " << updateTime << " / " << time;
319 #endif
320 stop = !updateWindowWobblyDatas(w, maxTime);
321 updateTime -= maxTime;
323 if (!stop && updateTime > 0)
325 updateWindowWobblyDatas(w, updateTime);
329 effects->prePaintWindow(w, data, time);
332 void WobblyWindowsEffect::paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data)
334 if(windows.contains(w))
336 WindowWobblyInfos& wwi = windows[w];
337 int tx = w->geometry().x();
338 int ty = w->geometry().y();
339 for (int i = 0; i < data.quads.count(); ++i)
341 for(int j = 0; j < 4; ++j)
343 WindowVertex& v = data.quads[i][j];
344 Pair oldPos = {tx + v.x(), ty + v.y()};
345 Pair newPos = computeBezierPoint(wwi, oldPos);
346 v.move(newPos.x - tx, newPos.y - ty);
351 // Call the next effect.
352 effects->paintWindow(w, mask, region, data);
355 void WobblyWindowsEffect::postPaintScreen()
357 if (!windows.isEmpty())
359 effects->addRepaint(m_updateRegion);
362 // Call the next effect.
363 effects->postPaintScreen();
366 void WobblyWindowsEffect::windowUserMovedResized(EffectWindow* w, bool first, bool last)
368 if (m_moveEffectEnabled && first && !w->isSpecialWindow() &&
369 ((w->isUserMove() && m_moveWobble) || (w->isUserResize() && m_resizeWobble)))
371 if (!windows.contains(w))
373 WindowWobblyInfos new_wwi;
374 initWobblyInfo(new_wwi, w->geometry());
375 windows[w] = new_wwi;
378 WindowWobblyInfos& wwi = windows[w];
379 wwi.status = Moving;
380 const QRectF& rect = w->geometry();
382 qreal x_increment = rect.width() / (wwi.width-1.0);
383 qreal y_increment = rect.height() / (wwi.height-1.0);
385 Pair picked = {cursorPos().x(), cursorPos().y()};
386 int indx = (picked.x - rect.x()) / x_increment;
387 int indy = (picked.y - rect.y()) / y_increment;
388 int pickedPointIndex = indy*wwi.width + indx;
389 if (pickedPointIndex < 0)
391 kDebug(1212) << "Picked index == " << pickedPointIndex << " with (" << cursorPos().x() << "," << cursorPos().y() << ")";
392 pickedPointIndex = 0;
394 else if (static_cast<unsigned int>(pickedPointIndex) > wwi.count - 1)
396 kDebug(1212) << "Picked index == " << pickedPointIndex << " with (" << cursorPos().x() << "," << cursorPos().y() << ")";
397 pickedPointIndex = wwi.count - 1;
399 #if defined VERBOSE_MODE
400 kDebug(1212) << "Original Picked point -- x : " << picked.x << " - y : " << picked.y;
401 #endif
402 wwi.constraint[pickedPointIndex] = true;
404 if (w->isUserResize())
406 if (picked.x > rect.center().x())
407 if (picked.y > rect.center().y())
408 // picked somewhere in the bottom right, so constrain the top left corner too
409 wwi.locked[0] = wwi.constraint[0] = true;
410 else
411 wwi.locked[wwi.count-wwi.width] = wwi.constraint[wwi.count-wwi.width] = true;
412 else
413 if (picked.y > rect.center().y())
414 wwi.locked[wwi.width-1] = wwi.constraint[wwi.width-1] = true;
415 else
416 wwi.locked[wwi.count-1] = wwi.constraint[wwi.count-1] = true;
419 else if (m_moveEffectEnabled && last)
421 if (windows.contains(w))
423 WindowWobblyInfos& wwi = windows[w];
424 wwi.status = Free;
429 void WobblyWindowsEffect::windowAdded(EffectWindow* w)
431 if (m_openEffectEnabled)
433 if(windows.contains(w))
435 // could this happen ??
436 WindowWobblyInfos& wwi = windows[w];
437 wobblyOpenInit(wwi);
439 else
441 WindowWobblyInfos new_wwi;
442 initWobblyInfo(new_wwi, w->geometry());
443 wobblyOpenInit(new_wwi);
444 windows[w] = new_wwi;
449 void WobblyWindowsEffect::windowClosed(EffectWindow* w)
451 if(windows.contains(w))
453 WindowWobblyInfos& wwi = windows[w];
454 if (m_closeEffectEnabled)
456 wobblyCloseInit(wwi, w);
457 w->refWindow();
459 else
461 freeWobblyInfo(wwi);
462 windows.remove(w);
465 else if (m_closeEffectEnabled)
467 WindowWobblyInfos new_wwi;
468 initWobblyInfo(new_wwi, w->geometry());
469 wobblyCloseInit(new_wwi, w);
470 windows[w] = new_wwi;
471 w->refWindow();
475 void WobblyWindowsEffect::wobblyOpenInit(WindowWobblyInfos& wwi) const
477 Pair middle = { (wwi.origin[0].x + wwi.origin[15].x)/2, (wwi.origin[0].y + wwi.origin[15].y)/2 };
479 for (unsigned int j=0; j<4; ++j)
481 for (unsigned int i=0; i<4; ++i)
483 unsigned int idx = j*4 + i;
484 wwi.constraint[idx] = false;
485 wwi.locked[idx] = false;
486 wwi.position[idx].x = (wwi.position[idx].x + 3*middle.x)/4;
487 wwi.position[idx].y = (wwi.position[idx].y + 3*middle.y)/4;
490 wwi.status = Openning;
493 void WobblyWindowsEffect::wobblyCloseInit(WindowWobblyInfos& wwi, EffectWindow* w) const
495 const QRectF& rect = w->geometry();
496 QPointF center = rect.center();
497 int x1 = (rect.x() + 3*center.x())/4;
498 int x2 = (rect.x() + rect.width() + 3*center.x())/4;
499 int y1 = (rect.y() + 3*center.y())/4;
500 int y2 = (rect.y() + rect.height() + 3*center.y())/4;
501 wwi.closeRect.setCoords(x1, y1, x2, y2);
503 // for closing, not yet used...
504 for (unsigned int j=0; j<4; ++j)
506 for (unsigned int i=0; i<4; ++i)
508 unsigned int idx = j*4 + i;
509 wwi.constraint[idx] = false;
510 wwi.locked[idx] = false;
513 wwi.status = Closing;
516 void WobblyWindowsEffect::initWobblyInfo(WindowWobblyInfos& wwi, QRect geometry) const
518 wwi.count = 4*4;
519 wwi.width = 4;
520 wwi.height = 4;
522 wwi.bezierWidth = m_xTesselation;
523 wwi.bezierHeight = m_yTesselation;
524 wwi.bezierCount = m_xTesselation * m_yTesselation;
526 wwi.origin = new Pair[wwi.count];
527 wwi.position = new Pair[wwi.count];
528 wwi.velocity = new Pair[wwi.count];
529 wwi.acceleration = new Pair[wwi.count];
530 wwi.buffer = new Pair[wwi.count];
531 wwi.constraint = new bool[wwi.count];
532 wwi.locked = new bool[wwi.count];
534 wwi.bezierSurface = new Pair[wwi.bezierCount];
536 wwi.status = Moving;
538 qreal x = geometry.x(), y = geometry.y();
539 qreal width = geometry.width(), height = geometry.height();
541 Pair initValue = {x, y};
542 static const Pair nullPair = {0.0, 0.0};
544 qreal x_increment = width / (wwi.width-1.0);
545 qreal y_increment = height / (wwi.height-1.0);
547 for (unsigned int j=0; j<4; ++j)
549 for (unsigned int i=0; i<4; ++i)
551 unsigned int idx = j*4 + i;
552 wwi.origin[idx] = initValue;
553 wwi.position[idx] = initValue;
554 wwi.velocity[idx] = nullPair;
555 wwi.constraint[idx] = false;
556 wwi.locked[idx] = false;
557 if (i != 4-2) // x grid count - 2, i.e. not the last point
559 initValue.x += x_increment;
561 else
563 initValue.x = width + x;
565 initValue.x = initValue.x;
567 initValue.x = x;
568 initValue.x = initValue.x;
569 if (j != 4-2) // y grid count - 2, i.e. not the last point
571 initValue.y += y_increment;
573 else
575 initValue.y = height + y;
577 initValue.y = initValue.y;
581 void WobblyWindowsEffect::freeWobblyInfo(WindowWobblyInfos& wwi) const
583 delete[] wwi.origin;
584 delete[] wwi.position;
585 delete[] wwi.velocity;
586 delete[] wwi.acceleration;
587 delete[] wwi.buffer;
588 delete[] wwi.constraint;
589 delete[] wwi.locked;
591 delete[] wwi.bezierSurface;
594 WobblyWindowsEffect::Pair WobblyWindowsEffect::computeBezierPoint(const WindowWobblyInfos& wwi, Pair point) const
596 // compute the input value
597 Pair topleft = wwi.origin[0];
598 Pair bottomright = wwi.origin[wwi.count-1];
600 // ASSERT1(point.x >= topleft.x);
601 // ASSERT1(point.y >= topleft.y);
602 // ASSERT1(point.x <= bottomright.x);
603 // ASSERT1(point.y <= bottomright.y);
605 qreal tx = (point.x - topleft.x) / (bottomright.x - topleft.x);
606 qreal ty = (point.y - topleft.y) / (bottomright.y - topleft.y);
608 // ASSERT1(tx >= 0);
609 // ASSERT1(tx <= 1);
610 // ASSERT1(ty >= 0);
611 // ASSERT1(ty <= 1);
613 // compute polynomial coeff
615 qreal px[4];
616 px[0] = (1-tx)*(1-tx)*(1-tx);
617 px[1] = 3*(1-tx)*(1-tx)*tx;
618 px[2] = 3*(1-tx)*tx*tx;
619 px[3] = tx*tx*tx;
621 qreal py[4];
622 py[0] = (1-ty)*(1-ty)*(1-ty);
623 py[1] = 3*(1-ty)*(1-ty)*ty;
624 py[2] = 3*(1-ty)*ty*ty;
625 py[3] = ty*ty*ty;
627 Pair res = {0.0, 0.0};
629 for (unsigned int j = 0; j < 4; ++j)
631 for (unsigned int i = 0; i < 4; ++i)
633 // this assume the grid is 4*4
634 res.x += px[i] * py[j] * wwi.position[i + j * wwi.width].x;
635 res.y += px[i] * py[j] * wwi.position[i + j * wwi.width].y;
639 return res;
642 namespace
645 static inline void fixVectorBounds(WobblyWindowsEffect::Pair& vec, qreal min, qreal max)
647 if (fabs(vec.x) < min)
649 vec.x = 0.0;
651 else if (fabs(vec.x) > max)
653 if (vec.x > 0.0)
655 vec.x = max;
657 else
659 vec.x = -max;
663 if (fabs(vec.y) < min)
665 vec.y = 0.0;
667 else if (fabs(vec.y) > max)
669 if (vec.y > 0.0)
671 vec.y = max;
673 else
675 vec.y = -max;
680 static inline void computeVectorBounds(WobblyWindowsEffect::Pair& vec, WobblyWindowsEffect::Pair& bound)
682 if (fabs(vec.x) < bound.x)
684 bound.x = fabs(vec.x);
686 else if (fabs(vec.x) > bound.y)
688 bound.y = fabs(vec.x);
690 if (fabs(vec.y) < bound.x)
692 bound.x = fabs(vec.y);
694 else if (fabs(vec.y) > bound.y)
696 bound.y = fabs(vec.y);
700 } // close the anonymous namespace
702 bool WobblyWindowsEffect::updateWindowWobblyDatas(EffectWindow* w, qreal time)
704 QRectF rect = w->geometry();
705 WindowWobblyInfos& wwi = windows[w];
707 if (wwi.status == Closing)
709 rect = wwi.closeRect;
712 qreal x_length = rect.width() / (wwi.width-1.0);
713 qreal y_length = rect.height() / (wwi.height-1.0);
715 #if defined VERBOSE_MODE
716 kDebug(1212) << "time " << time;
717 kDebug(1212) << "increment x " << x_length << " // y" << y_length;
718 #endif
720 Pair origine = {rect.x(), rect.y()};
722 for (unsigned int j=0; j<wwi.height; ++j)
724 for (unsigned int i=0; i<wwi.width; ++i)
726 wwi.origin[wwi.width*j + i] = origine;
727 if (i != wwi.width-2)
729 origine.x += x_length;
731 else
733 origine.x = rect.width() + rect.x();
736 origine.x = rect.x();
737 if (j != wwi.height-2)
739 origine.y += y_length;
741 else
743 origine.y = rect.height() + rect.y();
747 Pair neibourgs[4];
748 Pair acceleration;
750 qreal acc_sum = 0.0;
751 qreal vel_sum = 0.0;
753 // compute acceleration, velocity and position for each point
755 // for corners
757 // top-left
759 if (wwi.constraint[0])
761 Pair window_pos = wwi.origin[0];
762 Pair current_pos = wwi.position[0];
763 Pair move = {window_pos.x - current_pos.x, window_pos.y - current_pos.y};
764 Pair accel = {move.x*m_stiffness, move.y*m_stiffness};
765 wwi.acceleration[0] = accel;
767 else
769 Pair& pos = wwi.position[0];
770 neibourgs[0] = wwi.position[1];
771 neibourgs[1] = wwi.position[wwi.width];
773 acceleration.x = ((neibourgs[0].x - pos.x) - x_length)*m_stiffness + (neibourgs[1].x - pos.x)*m_stiffness;
774 acceleration.y = ((neibourgs[1].y - pos.y) - y_length)*m_stiffness + (neibourgs[0].y - pos.y)*m_stiffness;
776 acceleration.x /= 2;
777 acceleration.y /= 2;
779 wwi.acceleration[0] = acceleration;
782 // top-right
784 if (wwi.constraint[wwi.width-1])
786 Pair window_pos = wwi.origin[wwi.width-1];
787 Pair current_pos = wwi.position[wwi.width-1];
788 Pair move = {window_pos.x - current_pos.x, window_pos.y - current_pos.y};
789 Pair accel = {move.x*m_stiffness, move.y*m_stiffness};
790 wwi.acceleration[wwi.width-1] = accel;
792 else
794 Pair& pos = wwi.position[wwi.width-1];
795 neibourgs[0] = wwi.position[wwi.width-2];
796 neibourgs[1] = wwi.position[2*wwi.width-1];
798 acceleration.x = (x_length - (pos.x - neibourgs[0].x))*m_stiffness + (neibourgs[1].x - pos.x)*m_stiffness;
799 acceleration.y = ((neibourgs[1].y - pos.y) - y_length)*m_stiffness + (neibourgs[0].y - pos.y)*m_stiffness;
801 acceleration.x /= 2;
802 acceleration.y /= 2;
804 wwi.acceleration[wwi.width-1] = acceleration;
807 // bottom-left
809 if (wwi.constraint[wwi.width*(wwi.height-1)])
811 Pair window_pos = wwi.origin[wwi.width*(wwi.height-1)];
812 Pair current_pos = wwi.position[wwi.width*(wwi.height-1)];
813 Pair move = {window_pos.x - current_pos.x, window_pos.y - current_pos.y};
814 Pair accel = {move.x*m_stiffness, move.y*m_stiffness};
815 wwi.acceleration[wwi.width*(wwi.height-1)] = accel;
817 else
819 Pair& pos = wwi.position[wwi.width*(wwi.height-1)];
820 neibourgs[0] = wwi.position[wwi.width*(wwi.height-1)+1];
821 neibourgs[1] = wwi.position[wwi.width*(wwi.height-2)];
823 acceleration.x = ((neibourgs[0].x - pos.x) - x_length)*m_stiffness + (neibourgs[1].x - pos.x)*m_stiffness;
824 acceleration.y = (y_length - (pos.y - neibourgs[1].y))*m_stiffness + (neibourgs[0].y - pos.y)*m_stiffness;
826 acceleration.x /= 2;
827 acceleration.y /= 2;
829 wwi.acceleration[wwi.width*(wwi.height-1)] = acceleration;
832 // bottom-right
834 if (wwi.constraint[wwi.count-1])
836 Pair window_pos = wwi.origin[wwi.count-1];
837 Pair current_pos = wwi.position[wwi.count-1];
838 Pair move = {window_pos.x - current_pos.x, window_pos.y - current_pos.y};
839 Pair accel = {move.x*m_stiffness, move.y*m_stiffness};
840 wwi.acceleration[wwi.count-1] = accel;
842 else
844 Pair& pos = wwi.position[wwi.count-1];
845 neibourgs[0] = wwi.position[wwi.count-2];
846 neibourgs[1] = wwi.position[wwi.width*(wwi.height-1)-1];
848 acceleration.x = (x_length - (pos.x - neibourgs[0].x))*m_stiffness + (neibourgs[1].x - pos.x)*m_stiffness;
849 acceleration.y = (y_length - (pos.y - neibourgs[1].y))*m_stiffness + (neibourgs[0].y - pos.y)*m_stiffness;
851 acceleration.x /= 2;
852 acceleration.y /= 2;
854 wwi.acceleration[wwi.count-1] = acceleration;
858 // for borders
860 // top border
861 for (unsigned int i=1; i<wwi.width-1; ++i)
863 if (wwi.constraint[i])
865 Pair window_pos = wwi.origin[i];
866 Pair current_pos = wwi.position[i];
867 Pair move = {window_pos.x - current_pos.x, window_pos.y - current_pos.y};
868 Pair accel = {move.x*m_stiffness, move.y*m_stiffness};
869 wwi.acceleration[i] = accel;
871 else
873 Pair& pos = wwi.position[i];
874 neibourgs[0] = wwi.position[i-1];
875 neibourgs[1] = wwi.position[i+1];
876 neibourgs[2] = wwi.position[i+wwi.width];
878 acceleration.x = (x_length - (pos.x - neibourgs[0].x))*m_stiffness + ((neibourgs[1].x - pos.x) - x_length)*m_stiffness + (neibourgs[2].x - pos.x)*m_stiffness;
879 acceleration.y = ((neibourgs[2].y - pos.y) - y_length)*m_stiffness + (neibourgs[0].y - pos.y)*m_stiffness + (neibourgs[1].y - pos.y)*m_stiffness;
881 acceleration.x /= 3;
882 acceleration.y /= 3;
884 wwi.acceleration[i] = acceleration;
888 // bottom border
889 for (unsigned int i=wwi.width*(wwi.height-1)+1; i<wwi.count-1; ++i)
891 if (wwi.constraint[i])
893 Pair window_pos = wwi.origin[i];
894 Pair current_pos = wwi.position[i];
895 Pair move = {window_pos.x - current_pos.x, window_pos.y - current_pos.y};
896 Pair accel = {move.x*m_stiffness, move.y*m_stiffness};
897 wwi.acceleration[i] = accel;
899 else
901 Pair& pos = wwi.position[i];
902 neibourgs[0] = wwi.position[i-1];
903 neibourgs[1] = wwi.position[i+1];
904 neibourgs[2] = wwi.position[i-wwi.width];
906 acceleration.x = (x_length - (pos.x - neibourgs[0].x))*m_stiffness + ((neibourgs[1].x - pos.x) - x_length)*m_stiffness + (neibourgs[2].x - pos.x)*m_stiffness;
907 acceleration.y = (y_length - (pos.y - neibourgs[2].y))*m_stiffness + (neibourgs[0].y - pos.y)*m_stiffness + (neibourgs[1].y - pos.y)*m_stiffness;
909 acceleration.x /= 3;
910 acceleration.y /= 3;
912 wwi.acceleration[i] = acceleration;
916 // left border
917 for (unsigned int i=wwi.width; i<wwi.width*(wwi.height-1); i+=wwi.width)
919 if (wwi.constraint[i])
921 Pair window_pos = wwi.origin[i];
922 Pair current_pos = wwi.position[i];
923 Pair move = {window_pos.x - current_pos.x, window_pos.y - current_pos.y};
924 Pair accel = {move.x*m_stiffness, move.y*m_stiffness};
925 wwi.acceleration[i] = accel;
927 else
929 Pair& pos = wwi.position[i];
930 neibourgs[0] = wwi.position[i+1];
931 neibourgs[1] = wwi.position[i-wwi.width];
932 neibourgs[2] = wwi.position[i+wwi.width];
934 acceleration.x = ((neibourgs[0].x - pos.x) - x_length)*m_stiffness + (neibourgs[1].x - pos.x)*m_stiffness + (neibourgs[2].x - pos.x)*m_stiffness;
935 acceleration.y = (y_length - (pos.y - neibourgs[1].y))*m_stiffness + ((neibourgs[2].y - pos.y) - y_length)*m_stiffness + (neibourgs[0].y - pos.y)*m_stiffness;
937 acceleration.x /= 3;
938 acceleration.y /= 3;
940 wwi.acceleration[i] = acceleration;
944 // right border
945 for (unsigned int i=2*wwi.width-1; i<wwi.count-1; i+=wwi.width)
947 if (wwi.constraint[i])
949 Pair window_pos = wwi.origin[i];
950 Pair current_pos = wwi.position[i];
951 Pair move = {window_pos.x - current_pos.x, window_pos.y - current_pos.y};
952 Pair accel = {move.x*m_stiffness, move.y*m_stiffness};
953 wwi.acceleration[i] = accel;
955 else
957 Pair& pos = wwi.position[i];
958 neibourgs[0] = wwi.position[i-1];
959 neibourgs[1] = wwi.position[i-wwi.width];
960 neibourgs[2] = wwi.position[i+wwi.width];
962 acceleration.x = (x_length - (pos.x - neibourgs[0].x))*m_stiffness + (neibourgs[1].x - pos.x)*m_stiffness + (neibourgs[2].x - pos.x)*m_stiffness;
963 acceleration.y = (y_length - (pos.y - neibourgs[1].y))*m_stiffness + ((neibourgs[2].y - pos.y) - y_length)*m_stiffness + (neibourgs[0].y - pos.y)*m_stiffness;
965 acceleration.x /= 3;
966 acceleration.y /= 3;
968 wwi.acceleration[i] = acceleration;
972 // for the inner points
973 for (unsigned int j=1; j<wwi.height-1; ++j)
975 for (unsigned int i=1; i<wwi.width-1; ++i)
977 unsigned int index = i+j*wwi.width;
979 if (wwi.constraint[index])
981 Pair window_pos = wwi.origin[index];
982 Pair current_pos = wwi.position[index];
983 Pair move = {window_pos.x - current_pos.x, window_pos.y - current_pos.y};
984 Pair accel = {move.x*m_stiffness, move.y*m_stiffness};
985 wwi.acceleration[index] = accel;
987 else
989 Pair& pos = wwi.position[index];
990 neibourgs[0] = wwi.position[index-1];
991 neibourgs[1] = wwi.position[index+1];
992 neibourgs[2] = wwi.position[index-wwi.width];
993 neibourgs[3] = wwi.position[index+wwi.width];
995 acceleration.x = ((neibourgs[0].x - pos.x) - x_length)*m_stiffness +
996 (x_length - (pos.x - neibourgs[1].x))*m_stiffness +
997 (neibourgs[2].x - pos.x)*m_stiffness +
998 (neibourgs[3].x - pos.x)*m_stiffness;
999 acceleration.y = (y_length - (pos.y - neibourgs[2].y))*m_stiffness +
1000 ((neibourgs[3].y - pos.y) - y_length)*m_stiffness +
1001 (neibourgs[0].y - pos.y)*m_stiffness +
1002 (neibourgs[1].y - pos.y)*m_stiffness;
1004 acceleration.x /= 4;
1005 acceleration.y /= 4;
1007 wwi.acceleration[index] = acceleration;
1012 heightRingLinearMean(&wwi.acceleration, wwi);
1014 #if defined COMPUTE_STATS
1015 Pair accBound = {m_maxAcceleration, m_minAcceleration};
1016 Pair velBound = {m_maxVelocity, m_minVelocity};
1017 #endif
1019 // compute the new velocity of each vertex.
1020 for (unsigned int i = 0; i < wwi.count; ++i)
1022 Pair acc = wwi.acceleration[i];
1023 fixVectorBounds(acc, m_minAcceleration, m_maxAcceleration);
1025 #if defined COMPUTE_STATS
1026 computeVectorBounds(acc, accBound);
1027 #endif
1029 Pair& vel = wwi.velocity[i];
1030 vel.x = acc.x*time + vel.x*m_drag;
1031 vel.y = acc.y*time + vel.y*m_drag;
1033 acc_sum += fabs(acc.x) + fabs(acc.y);
1036 heightRingLinearMean(&wwi.velocity, wwi);
1038 Pair topLeftCorner = {-10000.0, -10000.0};
1039 Pair bottomRightCorner = {10000.0, 10000.0};
1041 // compute the new pos of each vertex.
1042 for (unsigned int i = 0; i < wwi.count; ++i)
1044 Pair& pos = wwi.position[i];
1045 Pair& vel = wwi.velocity[i];
1047 fixVectorBounds(vel, m_minVelocity, m_maxVelocity);
1048 #if defined COMPUTE_STATS
1049 computeVectorBounds(vel, velBound);
1050 #endif
1052 pos.x += vel.x*time*m_move_factor;
1053 pos.y += vel.y*time*m_move_factor;
1055 if (pos.x < topLeftCorner.x)
1057 topLeftCorner.x = pos.x;
1059 if (pos.x > bottomRightCorner.x)
1061 bottomRightCorner.x = pos.x;
1063 if (pos.y < topLeftCorner.y)
1065 topLeftCorner.y = pos.y;
1067 if (pos.y > bottomRightCorner.y)
1069 bottomRightCorner.y = pos.y;
1072 vel_sum += fabs(vel.x) + fabs(vel.y);
1074 if (wwi.locked[i])
1076 wwi.position[i] = wwi.origin[i];
1078 #if defined VERBOSE_MODE
1079 if (wwi.constraint[i])
1081 kDebug(1212) << "Constraint point ** vel : " << vel.x << "," << vel.y << " ** move : " << vel.x*time << "," << vel.y*time;
1083 #endif
1086 #if defined VERBOSE_MODE
1087 # if defined COMPUTE_STATS
1088 kDebug(1212) << "Acceleration bounds (" << accBound.x << ", " << accBound.y << ")";
1089 kDebug(1212) << "Velocity bounds (" << velBound.x << ", " << velBound.y << ")";
1090 # endif
1091 kDebug(1212) << "sum_acc : " << acc_sum << " *** sum_vel :" << vel_sum;
1092 #endif
1094 if (wwi.status != Moving && acc_sum < m_stopAcceleration && vel_sum < m_stopVelocity)
1096 if (wwi.status == Closing)
1098 w->unrefWindow();
1100 freeWobblyInfo(wwi);
1101 windows.remove(w);
1102 return false;
1105 QRect windowRect(topLeftCorner.x, topLeftCorner.y,
1106 bottomRightCorner.x - topLeftCorner.x, bottomRightCorner.y - topLeftCorner.y);
1107 if (m_updateRegion.isValid())
1109 m_updateRegion = m_updateRegion.united(windowRect);
1111 else
1113 m_updateRegion = windowRect;
1116 return true;
1119 void WobblyWindowsEffect::heightRingLinearMean(Pair** datas_pointer, WindowWobblyInfos& wwi)
1121 Pair* datas = *datas_pointer;
1122 Pair neibourgs[8];
1124 // for corners
1126 // top-left
1128 Pair& res = wwi.buffer[0];
1129 Pair vit = datas[0];
1130 neibourgs[0] = datas[1];
1131 neibourgs[1] = datas[wwi.width];
1132 neibourgs[2] = datas[wwi.width+1];
1134 res.x = (neibourgs[0].x + neibourgs[1].x + neibourgs[2].x + 3.0*vit.x) / 6.0;
1135 res.y = (neibourgs[0].y + neibourgs[1].y + neibourgs[2].y + 3.0*vit.y) / 6.0;
1139 // top-right
1141 Pair& res = wwi.buffer[wwi.width-1];
1142 Pair vit = datas[wwi.width-1];
1143 neibourgs[0] = datas[wwi.width-2];
1144 neibourgs[1] = datas[2*wwi.width-1];
1145 neibourgs[2] = datas[2*wwi.width-2];
1147 res.x = (neibourgs[0].x + neibourgs[1].x + neibourgs[2].x + 3.0*vit.x) / 6.0;
1148 res.y = (neibourgs[0].y + neibourgs[1].y + neibourgs[2].y + 3.0*vit.y) / 6.0;
1152 // bottom-left
1154 Pair& res = wwi.buffer[wwi.width*(wwi.height-1)];
1155 Pair vit = datas[wwi.width*(wwi.height-1)];
1156 neibourgs[0] = datas[wwi.width*(wwi.height-1)+1];
1157 neibourgs[1] = datas[wwi.width*(wwi.height-2)];
1158 neibourgs[2] = datas[wwi.width*(wwi.height-2)+1];
1160 res.x = (neibourgs[0].x + neibourgs[1].x + neibourgs[2].x + 3.0*vit.x) / 6.0;
1161 res.y = (neibourgs[0].y + neibourgs[1].y + neibourgs[2].y + 3.0*vit.y) / 6.0;
1165 // bottom-right
1167 Pair& res = wwi.buffer[wwi.count-1];
1168 Pair vit = datas[wwi.count-1];
1169 neibourgs[0] = datas[wwi.count-2];
1170 neibourgs[1] = datas[wwi.width*(wwi.height-1)-1];
1171 neibourgs[2] = datas[wwi.width*(wwi.height-1)-2];
1173 res.x = (neibourgs[0].x + neibourgs[1].x + neibourgs[2].x + 3.0*vit.x) / 6.0;
1174 res.y = (neibourgs[0].y + neibourgs[1].y + neibourgs[2].y + 3.0*vit.y) / 6.0;
1178 // for borders
1180 // top border
1181 for (unsigned int i=1; i<wwi.width-1; ++i)
1183 Pair& res = wwi.buffer[i];
1184 Pair vit = datas[i];
1185 neibourgs[0] = datas[i-1];
1186 neibourgs[1] = datas[i+1];
1187 neibourgs[2] = datas[i+wwi.width];
1188 neibourgs[3] = datas[i+wwi.width-1];
1189 neibourgs[4] = datas[i+wwi.width+1];
1191 res.x = (neibourgs[0].x + neibourgs[1].x + neibourgs[2].x + neibourgs[3].x + neibourgs[4].x + 5.0*vit.x) / 10.0;
1192 res.y = (neibourgs[0].y + neibourgs[1].y + neibourgs[2].y + neibourgs[3].y + neibourgs[4].y + 5.0*vit.y) / 10.0;
1195 // bottom border
1196 for (unsigned int i=wwi.width*(wwi.height-1)+1; i<wwi.count-1; ++i)
1198 Pair& res = wwi.buffer[i];
1199 Pair vit = datas[i];
1200 neibourgs[0] = datas[i-1];
1201 neibourgs[1] = datas[i+1];
1202 neibourgs[2] = datas[i-wwi.width];
1203 neibourgs[3] = datas[i-wwi.width-1];
1204 neibourgs[4] = datas[i-wwi.width+1];
1206 res.x = (neibourgs[0].x + neibourgs[1].x + neibourgs[2].x + neibourgs[3].x + neibourgs[4].x + 5.0*vit.x) / 10.0;
1207 res.y = (neibourgs[0].y + neibourgs[1].y + neibourgs[2].y + neibourgs[3].y + neibourgs[4].y + 5.0*vit.y) / 10.0;
1210 // left border
1211 for (unsigned int i=wwi.width; i<wwi.width*(wwi.height-1); i+=wwi.width)
1213 Pair& res = wwi.buffer[i];
1214 Pair vit = datas[i];
1215 neibourgs[0] = datas[i+1];
1216 neibourgs[1] = datas[i-wwi.width];
1217 neibourgs[2] = datas[i+wwi.width];
1218 neibourgs[3] = datas[i-wwi.width+1];
1219 neibourgs[4] = datas[i+wwi.width+1];
1221 res.x = (neibourgs[0].x + neibourgs[1].x + neibourgs[2].x + neibourgs[3].x + neibourgs[4].x + 5.0*vit.x) / 10.0;
1222 res.y = (neibourgs[0].y + neibourgs[1].y + neibourgs[2].y + neibourgs[3].y + neibourgs[4].y + 5.0*vit.y) / 10.0;
1225 // right border
1226 for (unsigned int i=2*wwi.width-1; i<wwi.count-1; i+=wwi.width)
1228 Pair& res = wwi.buffer[i];
1229 Pair vit = datas[i];
1230 neibourgs[0] = datas[i-1];
1231 neibourgs[1] = datas[i-wwi.width];
1232 neibourgs[2] = datas[i+wwi.width];
1233 neibourgs[3] = datas[i-wwi.width-1];
1234 neibourgs[4] = datas[i+wwi.width-1];
1236 res.x = (neibourgs[0].x + neibourgs[1].x + neibourgs[2].x + neibourgs[3].x + neibourgs[4].x + 5.0*vit.x) / 10.0;
1237 res.y = (neibourgs[0].y + neibourgs[1].y + neibourgs[2].y + neibourgs[3].y + neibourgs[4].y + 5.0*vit.y) / 10.0;
1240 // for the inner points
1241 for (unsigned int j=1; j<wwi.height-1; ++j)
1243 for (unsigned int i=1; i<wwi.width-1; ++i)
1245 unsigned int index = i+j*wwi.width;
1247 Pair& res = wwi.buffer[index];
1248 Pair& vit = datas[index];
1249 neibourgs[0] = datas[index-1];
1250 neibourgs[1] = datas[index+1];
1251 neibourgs[2] = datas[index-wwi.width];
1252 neibourgs[3] = datas[index+wwi.width];
1253 neibourgs[4] = datas[index-wwi.width-1];
1254 neibourgs[5] = datas[index-wwi.width+1];
1255 neibourgs[6] = datas[index+wwi.width-1];
1256 neibourgs[7] = datas[index+wwi.width+1];
1258 res.x = (neibourgs[0].x + neibourgs[1].x + neibourgs[2].x + neibourgs[3].x + neibourgs[4].x + neibourgs[5].x + neibourgs[6].x + neibourgs[7].x + 8.0*vit.x) / 16.0;
1259 res.y = (neibourgs[0].y + neibourgs[1].y + neibourgs[2].y + neibourgs[3].y + neibourgs[4].y + neibourgs[5].y + neibourgs[6].y + neibourgs[7].y + 8.0*vit.y) / 16.0;
1263 Pair* tmp = datas;
1264 *datas_pointer = wwi.buffer;
1265 wwi.buffer = tmp;
1269 } // namespace KWin