File indexing completed on 2024-11-10 04:57:13

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2008 Cédric Borgese <cedric.borgese@gmail.com>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 
0010 #include "wobblywindows.h"
0011 #include "effect/effecthandler.h"
0012 #include "wobblywindowsconfig.h"
0013 
0014 #include <cmath>
0015 
0016 //#define COMPUTE_STATS
0017 
0018 // if you enable it and run kwin in a terminal from the session it manages,
0019 // be sure to redirect the output of kwin in a file or
0020 // you'll propably get deadlocks.
0021 //#define VERBOSE_MODE
0022 
0023 #if defined COMPUTE_STATS && !defined VERBOSE_MODE
0024 #ifdef __GNUC__
0025 #warning "You enable COMPUTE_STATS without VERBOSE_MODE, computed stats will not be printed."
0026 #endif
0027 #endif
0028 
0029 Q_LOGGING_CATEGORY(KWIN_WOBBLYWINDOWS, "kwin_effect_wobblywindows", QtWarningMsg)
0030 
0031 namespace KWin
0032 {
0033 
0034 struct ParameterSet
0035 {
0036     qreal stiffness;
0037     qreal drag;
0038     qreal move_factor;
0039 
0040     qreal xTesselation;
0041     qreal yTesselation;
0042 
0043     qreal minVelocity;
0044     qreal maxVelocity;
0045     qreal stopVelocity;
0046     qreal minAcceleration;
0047     qreal maxAcceleration;
0048     qreal stopAcceleration;
0049 };
0050 
0051 static const ParameterSet set_0 = {
0052     0.15,
0053     0.80,
0054     0.10,
0055     20.0,
0056     20.0,
0057     0.0,
0058     1000.0,
0059     0.5,
0060     0.0,
0061     1000.0,
0062     0.5,
0063 };
0064 
0065 static const ParameterSet set_1 = {
0066     0.10,
0067     0.85,
0068     0.10,
0069     20.0,
0070     20.0,
0071     0.0,
0072     1000.0,
0073     0.5,
0074     0.0,
0075     1000.0,
0076     0.5,
0077 };
0078 
0079 static const ParameterSet set_2 = {
0080     0.06,
0081     0.90,
0082     0.10,
0083     20.0,
0084     20.0,
0085     0.0,
0086     1000.0,
0087     0.5,
0088     0.0,
0089     1000.0,
0090     0.5,
0091 };
0092 
0093 static const ParameterSet set_3 = {
0094     0.03,
0095     0.92,
0096     0.20,
0097     20.0,
0098     20.0,
0099     0.0,
0100     1000.0,
0101     0.5,
0102     0.0,
0103     1000.0,
0104     0.5,
0105 };
0106 
0107 static const ParameterSet set_4 = {
0108     0.01,
0109     0.97,
0110     0.25,
0111     20.0,
0112     20.0,
0113     0.0,
0114     1000.0,
0115     0.5,
0116     0.0,
0117     1000.0,
0118     0.5,
0119 };
0120 
0121 static const ParameterSet pset[5] = {set_0, set_1, set_2, set_3, set_4};
0122 
0123 WobblyWindowsEffect::WobblyWindowsEffect()
0124 {
0125     WobblyWindowsConfig::instance(effects->config());
0126     reconfigure(ReconfigureAll);
0127     connect(effects, &EffectsHandler::windowAdded, this, &WobblyWindowsEffect::slotWindowAdded);
0128 
0129     const auto windows = effects->stackingOrder();
0130     for (EffectWindow *window : windows) {
0131         slotWindowAdded(window);
0132     }
0133 }
0134 
0135 WobblyWindowsEffect::~WobblyWindowsEffect()
0136 {
0137     if (!windows.empty()) {
0138         // we should be empty at this point...
0139         qCDebug(KWIN_WOBBLYWINDOWS) << "Windows list not empty. Left items : " << windows.count();
0140     }
0141 }
0142 
0143 void WobblyWindowsEffect::reconfigure(ReconfigureFlags)
0144 {
0145     WobblyWindowsConfig::self()->read();
0146 
0147     QString settingsMode = WobblyWindowsConfig::settings();
0148     if (settingsMode != QStringLiteral("Custom")) {
0149         unsigned int wobblynessLevel = WobblyWindowsConfig::wobblynessLevel();
0150         if (wobblynessLevel > 4) {
0151             qCDebug(KWIN_WOBBLYWINDOWS) << "Wrong value for \"WobblynessLevel\" : " << wobblynessLevel;
0152             wobblynessLevel = 4;
0153         }
0154         setParameterSet(pset[wobblynessLevel]);
0155 
0156         if (WobblyWindowsConfig::advancedMode()) {
0157             m_stiffness = WobblyWindowsConfig::stiffness() / 100.0;
0158             m_drag = WobblyWindowsConfig::drag() / 100.0;
0159             m_move_factor = WobblyWindowsConfig::moveFactor() / 100.0;
0160         }
0161     } else { // Custom method, read all values from config file.
0162         m_stiffness = WobblyWindowsConfig::stiffness() / 100.0;
0163         m_drag = WobblyWindowsConfig::drag() / 100.0;
0164         m_move_factor = WobblyWindowsConfig::moveFactor() / 100.0;
0165 
0166         m_xTesselation = WobblyWindowsConfig::xTesselation();
0167         m_yTesselation = WobblyWindowsConfig::yTesselation();
0168 
0169         m_minVelocity = WobblyWindowsConfig::minVelocity();
0170         m_maxVelocity = WobblyWindowsConfig::maxVelocity();
0171         m_stopVelocity = WobblyWindowsConfig::stopVelocity();
0172         m_minAcceleration = WobblyWindowsConfig::minAcceleration();
0173         m_maxAcceleration = WobblyWindowsConfig::maxAcceleration();
0174         m_stopAcceleration = WobblyWindowsConfig::stopAcceleration();
0175     }
0176 
0177     m_moveWobble = WobblyWindowsConfig::moveWobble();
0178     m_resizeWobble = WobblyWindowsConfig::resizeWobble();
0179 
0180 #if defined VERBOSE_MODE
0181     qCDebug(KWIN_WOBBLYWINDOWS) << "Parameters :\n"
0182                                 << "grid(" << m_stiffness << ", " << m_drag << ", " << m_move_factor << ")\n"
0183                                 << "velocity(" << m_minVelocity << ", " << m_maxVelocity << ", " << m_stopVelocity << ")\n"
0184                                 << "acceleration(" << m_minAcceleration << ", " << m_maxAcceleration << ", " << m_stopAcceleration << ")\n"
0185                                 << "tesselation(" << m_xTesselation << ", " << m_yTesselation << ")";
0186 #endif
0187 }
0188 
0189 bool WobblyWindowsEffect::supported()
0190 {
0191     return OffscreenEffect::supported() && effects->animationsSupported();
0192 }
0193 
0194 void WobblyWindowsEffect::setParameterSet(const ParameterSet &pset)
0195 {
0196     m_stiffness = pset.stiffness;
0197     m_drag = pset.drag;
0198     m_move_factor = pset.move_factor;
0199 
0200     m_xTesselation = pset.xTesselation;
0201     m_yTesselation = pset.yTesselation;
0202 
0203     m_minVelocity = pset.minVelocity;
0204     m_maxVelocity = pset.maxVelocity;
0205     m_stopVelocity = pset.stopVelocity;
0206     m_minAcceleration = pset.minAcceleration;
0207     m_maxAcceleration = pset.maxAcceleration;
0208     m_stopAcceleration = pset.stopAcceleration;
0209 }
0210 
0211 void WobblyWindowsEffect::setVelocityThreshold(qreal m_minVelocity)
0212 {
0213     this->m_minVelocity = m_minVelocity;
0214 }
0215 
0216 void WobblyWindowsEffect::setMoveFactor(qreal factor)
0217 {
0218     m_move_factor = factor;
0219 }
0220 
0221 void WobblyWindowsEffect::setStiffness(qreal stiffness)
0222 {
0223     m_stiffness = stiffness;
0224 }
0225 
0226 void WobblyWindowsEffect::setDrag(qreal drag)
0227 {
0228     m_drag = drag;
0229 }
0230 
0231 void WobblyWindowsEffect::prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime)
0232 {
0233     effects->prePaintScreen(data, presentTime);
0234 }
0235 
0236 static const std::chrono::milliseconds integrationStep(10);
0237 
0238 void WobblyWindowsEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std::chrono::milliseconds presentTime)
0239 {
0240     auto infoIt = windows.find(w);
0241     if (infoIt != windows.end()) {
0242         data.setTransformed();
0243 
0244         while ((presentTime - infoIt->clock).count() > 0) {
0245             const auto delta = std::min(presentTime - infoIt->clock, integrationStep);
0246             infoIt->clock += delta;
0247 
0248             if (!updateWindowWobblyDatas(w, delta.count())) {
0249                 break;
0250             }
0251         }
0252     }
0253 
0254     effects->prePaintWindow(w, data, presentTime);
0255 }
0256 
0257 void WobblyWindowsEffect::apply(EffectWindow *w, int mask, WindowPaintData &data, WindowQuadList &quads)
0258 {
0259     if (!(mask & PAINT_SCREEN_TRANSFORMED) && windows.contains(w)) {
0260         WindowWobblyInfos &wwi = windows[w];
0261         if (!wwi.wobblying) {
0262             return;
0263         }
0264 
0265         int tx = w->frameGeometry().x();
0266         int ty = w->frameGeometry().y();
0267         int width = w->frameGeometry().width();
0268         int height = w->frameGeometry().height();
0269         double left = 0.0;
0270         double top = 0.0;
0271         double right = w->width();
0272         double bottom = w->height();
0273 
0274         quads = quads.makeRegularGrid(m_xTesselation, m_yTesselation);
0275         for (int i = 0; i < quads.count(); ++i) {
0276             for (int j = 0; j < 4; ++j) {
0277                 WindowVertex &v = quads[i][j];
0278                 Pair uv = {v.x() / width, v.y() / height};
0279                 Pair newPos = computeBezierPoint(wwi, uv);
0280                 v.move(newPos.x - tx, newPos.y - ty);
0281             }
0282             left = std::min(left, quads[i].left());
0283             top = std::min(top, quads[i].top());
0284             right = std::max(right, quads[i].right());
0285             bottom = std::max(bottom, quads[i].bottom());
0286         }
0287         QRectF dirtyRect(
0288             left * data.xScale() + w->x() + data.xTranslation(),
0289             top * data.yScale() + w->y() + data.yTranslation(),
0290             (right - left + 1.0) * data.xScale(),
0291             (bottom - top + 1.0) * data.yScale());
0292         // Expand the dirty region by 1px to fix potential round/floor issues.
0293         dirtyRect.adjust(-1.0, -1.0, 1.0, 1.0);
0294         m_updateRegion = m_updateRegion.united(dirtyRect.toRect());
0295     }
0296 }
0297 
0298 void WobblyWindowsEffect::postPaintScreen()
0299 {
0300     if (!m_updateRegion.isEmpty()) {
0301         effects->addRepaint(m_updateRegion);
0302         m_updateRegion = QRegion();
0303     }
0304 
0305     // Call the next effect.
0306     effects->postPaintScreen();
0307 }
0308 
0309 void WobblyWindowsEffect::slotWindowAdded(EffectWindow *w)
0310 {
0311     connect(w, &EffectWindow::windowStartUserMovedResized, this, &WobblyWindowsEffect::slotWindowStartUserMovedResized);
0312     connect(w, &EffectWindow::windowStepUserMovedResized, this, &WobblyWindowsEffect::slotWindowStepUserMovedResized);
0313     connect(w, &EffectWindow::windowFinishUserMovedResized, this, &WobblyWindowsEffect::slotWindowFinishUserMovedResized);
0314     connect(w, &EffectWindow::windowMaximizedStateChanged, this, &WobblyWindowsEffect::slotWindowMaximizeStateChanged);
0315 }
0316 
0317 void WobblyWindowsEffect::slotWindowStartUserMovedResized(EffectWindow *w)
0318 {
0319     if (w->isSpecialWindow()) {
0320         return;
0321     }
0322 
0323     if ((w->isUserMove() && m_moveWobble) || (w->isUserResize() && m_resizeWobble)) {
0324         startMovedResized(w);
0325     }
0326 }
0327 
0328 void WobblyWindowsEffect::slotWindowStepUserMovedResized(EffectWindow *w, const QRectF &geometry)
0329 {
0330     if (windows.contains(w)) {
0331         WindowWobblyInfos &wwi = windows[w];
0332         const QRectF rect = w->frameGeometry();
0333         if (rect.y() != wwi.resize_original_rect.y()) {
0334             wwi.can_wobble_top = true;
0335         }
0336         if (rect.x() != wwi.resize_original_rect.x()) {
0337             wwi.can_wobble_left = true;
0338         }
0339         if (rect.right() != wwi.resize_original_rect.right()) {
0340             wwi.can_wobble_right = true;
0341         }
0342         if (rect.bottom() != wwi.resize_original_rect.bottom()) {
0343             wwi.can_wobble_bottom = true;
0344         }
0345         setVertexSnappingMode(RenderGeometry::VertexSnappingMode::None);
0346     }
0347 }
0348 
0349 void WobblyWindowsEffect::slotWindowFinishUserMovedResized(EffectWindow *w)
0350 {
0351     if (windows.contains(w)) {
0352         WindowWobblyInfos &wwi = windows[w];
0353         wwi.status = Free;
0354         const QRectF rect = w->frameGeometry();
0355         if (rect.y() != wwi.resize_original_rect.y()) {
0356             wwi.can_wobble_top = true;
0357         }
0358         if (rect.x() != wwi.resize_original_rect.x()) {
0359             wwi.can_wobble_left = true;
0360         }
0361         if (rect.right() != wwi.resize_original_rect.right()) {
0362             wwi.can_wobble_right = true;
0363         }
0364         if (rect.bottom() != wwi.resize_original_rect.bottom()) {
0365             wwi.can_wobble_bottom = true;
0366         }
0367     }
0368 }
0369 
0370 void WobblyWindowsEffect::slotWindowMaximizeStateChanged(EffectWindow *w, bool horizontal, bool vertical)
0371 {
0372     if (w->isUserMove() || w->isSpecialWindow()) {
0373         return;
0374     }
0375 
0376     if (m_moveWobble && m_resizeWobble) {
0377         stepMovedResized(w);
0378     }
0379 
0380     if (windows.contains(w)) {
0381         WindowWobblyInfos &wwi = windows[w];
0382         const QRectF rect = w->frameGeometry();
0383         if (rect.y() != wwi.resize_original_rect.y()) {
0384             wwi.can_wobble_top = true;
0385         }
0386         if (rect.x() != wwi.resize_original_rect.x()) {
0387             wwi.can_wobble_left = true;
0388         }
0389         if (rect.right() != wwi.resize_original_rect.right()) {
0390             wwi.can_wobble_right = true;
0391         }
0392         if (rect.bottom() != wwi.resize_original_rect.bottom()) {
0393             wwi.can_wobble_bottom = true;
0394         }
0395     }
0396 }
0397 
0398 void WobblyWindowsEffect::startMovedResized(EffectWindow *w)
0399 {
0400     if (!windows.contains(w)) {
0401         WindowWobblyInfos new_wwi;
0402         initWobblyInfo(new_wwi, w->frameGeometry());
0403         windows[w] = new_wwi;
0404         redirect(w);
0405     }
0406 
0407     WindowWobblyInfos &wwi = windows[w];
0408     wwi.status = Moving;
0409     const QRectF &rect = w->frameGeometry();
0410 
0411     qreal x_increment = rect.width() / (wwi.width - 1.0);
0412     qreal y_increment = rect.height() / (wwi.height - 1.0);
0413 
0414     Pair picked = {static_cast<qreal>(cursorPos().x()), static_cast<qreal>(cursorPos().y())};
0415     int indx = (picked.x - rect.x()) / x_increment + 0.5;
0416     int indy = (picked.y - rect.y()) / y_increment + 0.5;
0417     int pickedPointIndex = indy * wwi.width + indx;
0418     if (pickedPointIndex < 0) {
0419         qCDebug(KWIN_WOBBLYWINDOWS) << "Picked index == " << pickedPointIndex << " with (" << cursorPos().x() << "," << cursorPos().y() << ")";
0420         pickedPointIndex = 0;
0421     } else if (static_cast<unsigned int>(pickedPointIndex) > wwi.count - 1) {
0422         qCDebug(KWIN_WOBBLYWINDOWS) << "Picked index == " << pickedPointIndex << " with (" << cursorPos().x() << "," << cursorPos().y() << ")";
0423         pickedPointIndex = wwi.count - 1;
0424     }
0425 #if defined VERBOSE_MODE
0426     qCDebug(KWIN_WOBBLYWINDOWS) << "Original Picked point -- x : " << picked.x << " - y : " << picked.y;
0427 #endif
0428     wwi.constraint[pickedPointIndex] = true;
0429 
0430     if (w->isUserResize()) {
0431         // on a resize, do not allow any edges to wobble until it has been moved from
0432         // its original location
0433         wwi.can_wobble_top = wwi.can_wobble_left = wwi.can_wobble_right = wwi.can_wobble_bottom = false;
0434         wwi.resize_original_rect = w->frameGeometry();
0435     } else {
0436         wwi.can_wobble_top = wwi.can_wobble_left = wwi.can_wobble_right = wwi.can_wobble_bottom = true;
0437     }
0438 }
0439 
0440 void WobblyWindowsEffect::stepMovedResized(EffectWindow *w)
0441 {
0442     QRectF new_geometry = w->frameGeometry();
0443     if (!windows.contains(w)) {
0444         WindowWobblyInfos new_wwi;
0445         initWobblyInfo(new_wwi, new_geometry);
0446         windows[w] = new_wwi;
0447     }
0448 
0449     WindowWobblyInfos &wwi = windows[w];
0450     wwi.status = Free;
0451 
0452     QRectF maximized_area = effects->clientArea(MaximizeArea, w);
0453     bool throb_direction_out = (new_geometry.top() == maximized_area.top() && new_geometry.bottom() == maximized_area.bottom()) || (new_geometry.left() == maximized_area.left() && new_geometry.right() == maximized_area.right());
0454     qreal magnitude = throb_direction_out ? 10 : -30; // a small throb out when maximized, a larger throb inwards when restored
0455     for (unsigned int j = 0; j < wwi.height; ++j) {
0456         for (unsigned int i = 0; i < wwi.width; ++i) {
0457             Pair v = {magnitude * (i / qreal(wwi.width - 1) - 0.5), magnitude * (j / qreal(wwi.height - 1) - 0.5)};
0458             wwi.velocity[j * wwi.width + i] = v;
0459         }
0460     }
0461 
0462     // constrain the middle of the window, so that any asymetry wont cause it to drift off-center
0463     for (unsigned int j = 1; j < wwi.height - 1; ++j) {
0464         for (unsigned int i = 1; i < wwi.width - 1; ++i) {
0465             wwi.constraint[j * wwi.width + i] = true;
0466         }
0467     }
0468 }
0469 
0470 void WobblyWindowsEffect::initWobblyInfo(WindowWobblyInfos &wwi, QRectF geometry) const
0471 {
0472     wwi.count = 4 * 4;
0473     wwi.width = 4;
0474     wwi.height = 4;
0475 
0476     wwi.bezierWidth = m_xTesselation;
0477     wwi.bezierHeight = m_yTesselation;
0478     wwi.bezierCount = m_xTesselation * m_yTesselation;
0479 
0480     wwi.origin.resize(wwi.count);
0481     wwi.position.resize(wwi.count);
0482     wwi.velocity.resize(wwi.count);
0483     wwi.acceleration.resize(wwi.count);
0484     wwi.buffer.resize(wwi.count);
0485     wwi.constraint.resize(wwi.count);
0486 
0487     wwi.bezierSurface.resize(wwi.bezierCount);
0488 
0489     wwi.status = Moving;
0490     wwi.clock = std::chrono::duration_cast<std::chrono::milliseconds>(
0491         std::chrono::steady_clock::now().time_since_epoch());
0492 
0493     qreal x = geometry.x(), y = geometry.y();
0494     qreal width = geometry.width(), height = geometry.height();
0495 
0496     Pair initValue = {x, y};
0497     static const Pair nullPair = {0.0, 0.0};
0498 
0499     qreal x_increment = width / (wwi.width - 1.0);
0500     qreal y_increment = height / (wwi.height - 1.0);
0501 
0502     for (unsigned int j = 0; j < 4; ++j) {
0503         for (unsigned int i = 0; i < 4; ++i) {
0504             unsigned int idx = j * 4 + i;
0505             wwi.origin[idx] = initValue;
0506             wwi.position[idx] = initValue;
0507             wwi.velocity[idx] = nullPair;
0508             wwi.constraint[idx] = false;
0509             if (i != 4 - 2) { // x grid count - 2, i.e. not the last point
0510                 initValue.x += x_increment;
0511             } else {
0512                 initValue.x = width + x;
0513             }
0514             initValue.x = initValue.x;
0515         }
0516         initValue.x = x;
0517         initValue.x = initValue.x;
0518         if (j != 4 - 2) { // y grid count - 2, i.e. not the last point
0519             initValue.y += y_increment;
0520         } else {
0521             initValue.y = height + y;
0522         }
0523         initValue.y = initValue.y;
0524     }
0525 }
0526 
0527 WobblyWindowsEffect::Pair WobblyWindowsEffect::computeBezierPoint(const WindowWobblyInfos &wwi, Pair point) const
0528 {
0529     const qreal tx = point.x;
0530     const qreal ty = point.y;
0531 
0532     // compute polynomial coeff
0533 
0534     qreal px[4];
0535     px[0] = (1 - tx) * (1 - tx) * (1 - tx);
0536     px[1] = 3 * (1 - tx) * (1 - tx) * tx;
0537     px[2] = 3 * (1 - tx) * tx * tx;
0538     px[3] = tx * tx * tx;
0539 
0540     qreal py[4];
0541     py[0] = (1 - ty) * (1 - ty) * (1 - ty);
0542     py[1] = 3 * (1 - ty) * (1 - ty) * ty;
0543     py[2] = 3 * (1 - ty) * ty * ty;
0544     py[3] = ty * ty * ty;
0545 
0546     Pair res = {0.0, 0.0};
0547 
0548     for (unsigned int j = 0; j < 4; ++j) {
0549         for (unsigned int i = 0; i < 4; ++i) {
0550             // this assume the grid is 4*4
0551             res.x += px[i] * py[j] * wwi.position[i + j * wwi.width].x;
0552             res.y += px[i] * py[j] * wwi.position[i + j * wwi.width].y;
0553         }
0554     }
0555 
0556     return res;
0557 }
0558 
0559 namespace
0560 {
0561 
0562 static inline void fixVectorBounds(WobblyWindowsEffect::Pair &vec, qreal min, qreal max)
0563 {
0564     if (fabs(vec.x) < min) {
0565         vec.x = 0.0;
0566     } else if (fabs(vec.x) > max) {
0567         if (vec.x > 0.0) {
0568             vec.x = max;
0569         } else {
0570             vec.x = -max;
0571         }
0572     }
0573 
0574     if (fabs(vec.y) < min) {
0575         vec.y = 0.0;
0576     } else if (fabs(vec.y) > max) {
0577         if (vec.y > 0.0) {
0578             vec.y = max;
0579         } else {
0580             vec.y = -max;
0581         }
0582     }
0583 }
0584 
0585 #if defined COMPUTE_STATS
0586 static inline void computeVectorBounds(WobblyWindowsEffect::Pair &vec, WobblyWindowsEffect::Pair &bound)
0587 {
0588     if (fabs(vec.x) < bound.x) {
0589         bound.x = fabs(vec.x);
0590     } else if (fabs(vec.x) > bound.y) {
0591         bound.y = fabs(vec.x);
0592     }
0593     if (fabs(vec.y) < bound.x) {
0594         bound.x = fabs(vec.y);
0595     } else if (fabs(vec.y) > bound.y) {
0596         bound.y = fabs(vec.y);
0597     }
0598 }
0599 #endif
0600 
0601 } // close the anonymous namespace
0602 
0603 bool WobblyWindowsEffect::updateWindowWobblyDatas(EffectWindow *w, qreal time)
0604 {
0605     QRectF rect = w->frameGeometry();
0606     WindowWobblyInfos &wwi = windows[w];
0607 
0608     qreal x_length = rect.width() / (wwi.width - 1.0);
0609     qreal y_length = rect.height() / (wwi.height - 1.0);
0610 
0611 #if defined VERBOSE_MODE
0612     qCDebug(KWIN_WOBBLYWINDOWS) << "time " << time;
0613     qCDebug(KWIN_WOBBLYWINDOWS) << "increment x " << x_length << " // y" << y_length;
0614 #endif
0615 
0616     Pair origine = {rect.x(), rect.y()};
0617 
0618     for (unsigned int j = 0; j < wwi.height; ++j) {
0619         for (unsigned int i = 0; i < wwi.width; ++i) {
0620             wwi.origin[wwi.width * j + i] = origine;
0621             if (i != wwi.width - 2) {
0622                 origine.x += x_length;
0623             } else {
0624                 origine.x = rect.width() + rect.x();
0625             }
0626         }
0627         origine.x = rect.x();
0628         if (j != wwi.height - 2) {
0629             origine.y += y_length;
0630         } else {
0631             origine.y = rect.height() + rect.y();
0632         }
0633     }
0634 
0635     Pair neibourgs[4];
0636     Pair acceleration;
0637 
0638     qreal acc_sum = 0.0;
0639     qreal vel_sum = 0.0;
0640 
0641     // compute acceleration, velocity and position for each point
0642 
0643     // for corners
0644 
0645     // top-left
0646 
0647     if (wwi.constraint[0]) {
0648         Pair window_pos = wwi.origin[0];
0649         Pair current_pos = wwi.position[0];
0650         Pair move = {window_pos.x - current_pos.x, window_pos.y - current_pos.y};
0651         Pair accel = {move.x * m_stiffness, move.y * m_stiffness};
0652         wwi.acceleration[0] = accel;
0653     } else {
0654         Pair &pos = wwi.position[0];
0655         neibourgs[0] = wwi.position[1];
0656         neibourgs[1] = wwi.position[wwi.width];
0657 
0658         acceleration.x = ((neibourgs[0].x - pos.x) - x_length) * m_stiffness + (neibourgs[1].x - pos.x) * m_stiffness;
0659         acceleration.y = ((neibourgs[1].y - pos.y) - y_length) * m_stiffness + (neibourgs[0].y - pos.y) * m_stiffness;
0660 
0661         acceleration.x /= 2;
0662         acceleration.y /= 2;
0663 
0664         wwi.acceleration[0] = acceleration;
0665     }
0666 
0667     // top-right
0668 
0669     if (wwi.constraint[wwi.width - 1]) {
0670         Pair window_pos = wwi.origin[wwi.width - 1];
0671         Pair current_pos = wwi.position[wwi.width - 1];
0672         Pair move = {window_pos.x - current_pos.x, window_pos.y - current_pos.y};
0673         Pair accel = {move.x * m_stiffness, move.y * m_stiffness};
0674         wwi.acceleration[wwi.width - 1] = accel;
0675     } else {
0676         Pair &pos = wwi.position[wwi.width - 1];
0677         neibourgs[0] = wwi.position[wwi.width - 2];
0678         neibourgs[1] = wwi.position[2 * wwi.width - 1];
0679 
0680         acceleration.x = (x_length - (pos.x - neibourgs[0].x)) * m_stiffness + (neibourgs[1].x - pos.x) * m_stiffness;
0681         acceleration.y = ((neibourgs[1].y - pos.y) - y_length) * m_stiffness + (neibourgs[0].y - pos.y) * m_stiffness;
0682 
0683         acceleration.x /= 2;
0684         acceleration.y /= 2;
0685 
0686         wwi.acceleration[wwi.width - 1] = acceleration;
0687     }
0688 
0689     // bottom-left
0690 
0691     if (wwi.constraint[wwi.width * (wwi.height - 1)]) {
0692         Pair window_pos = wwi.origin[wwi.width * (wwi.height - 1)];
0693         Pair current_pos = wwi.position[wwi.width * (wwi.height - 1)];
0694         Pair move = {window_pos.x - current_pos.x, window_pos.y - current_pos.y};
0695         Pair accel = {move.x * m_stiffness, move.y * m_stiffness};
0696         wwi.acceleration[wwi.width * (wwi.height - 1)] = accel;
0697     } else {
0698         Pair &pos = wwi.position[wwi.width * (wwi.height - 1)];
0699         neibourgs[0] = wwi.position[wwi.width * (wwi.height - 1) + 1];
0700         neibourgs[1] = wwi.position[wwi.width * (wwi.height - 2)];
0701 
0702         acceleration.x = ((neibourgs[0].x - pos.x) - x_length) * m_stiffness + (neibourgs[1].x - pos.x) * m_stiffness;
0703         acceleration.y = (y_length - (pos.y - neibourgs[1].y)) * m_stiffness + (neibourgs[0].y - pos.y) * m_stiffness;
0704 
0705         acceleration.x /= 2;
0706         acceleration.y /= 2;
0707 
0708         wwi.acceleration[wwi.width * (wwi.height - 1)] = acceleration;
0709     }
0710 
0711     // bottom-right
0712 
0713     if (wwi.constraint[wwi.count - 1]) {
0714         Pair window_pos = wwi.origin[wwi.count - 1];
0715         Pair current_pos = wwi.position[wwi.count - 1];
0716         Pair move = {window_pos.x - current_pos.x, window_pos.y - current_pos.y};
0717         Pair accel = {move.x * m_stiffness, move.y * m_stiffness};
0718         wwi.acceleration[wwi.count - 1] = accel;
0719     } else {
0720         Pair &pos = wwi.position[wwi.count - 1];
0721         neibourgs[0] = wwi.position[wwi.count - 2];
0722         neibourgs[1] = wwi.position[wwi.width * (wwi.height - 1) - 1];
0723 
0724         acceleration.x = (x_length - (pos.x - neibourgs[0].x)) * m_stiffness + (neibourgs[1].x - pos.x) * m_stiffness;
0725         acceleration.y = (y_length - (pos.y - neibourgs[1].y)) * m_stiffness + (neibourgs[0].y - pos.y) * m_stiffness;
0726 
0727         acceleration.x /= 2;
0728         acceleration.y /= 2;
0729 
0730         wwi.acceleration[wwi.count - 1] = acceleration;
0731     }
0732 
0733     // for borders
0734 
0735     // top border
0736     for (unsigned int i = 1; i < wwi.width - 1; ++i) {
0737         if (wwi.constraint[i]) {
0738             Pair window_pos = wwi.origin[i];
0739             Pair current_pos = wwi.position[i];
0740             Pair move = {window_pos.x - current_pos.x, window_pos.y - current_pos.y};
0741             Pair accel = {move.x * m_stiffness, move.y * m_stiffness};
0742             wwi.acceleration[i] = accel;
0743         } else {
0744             Pair &pos = wwi.position[i];
0745             neibourgs[0] = wwi.position[i - 1];
0746             neibourgs[1] = wwi.position[i + 1];
0747             neibourgs[2] = wwi.position[i + wwi.width];
0748 
0749             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;
0750             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;
0751 
0752             acceleration.x /= 3;
0753             acceleration.y /= 3;
0754 
0755             wwi.acceleration[i] = acceleration;
0756         }
0757     }
0758 
0759     // bottom border
0760     for (unsigned int i = wwi.width * (wwi.height - 1) + 1; i < wwi.count - 1; ++i) {
0761         if (wwi.constraint[i]) {
0762             Pair window_pos = wwi.origin[i];
0763             Pair current_pos = wwi.position[i];
0764             Pair move = {window_pos.x - current_pos.x, window_pos.y - current_pos.y};
0765             Pair accel = {move.x * m_stiffness, move.y * m_stiffness};
0766             wwi.acceleration[i] = accel;
0767         } else {
0768             Pair &pos = wwi.position[i];
0769             neibourgs[0] = wwi.position[i - 1];
0770             neibourgs[1] = wwi.position[i + 1];
0771             neibourgs[2] = wwi.position[i - wwi.width];
0772 
0773             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;
0774             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;
0775 
0776             acceleration.x /= 3;
0777             acceleration.y /= 3;
0778 
0779             wwi.acceleration[i] = acceleration;
0780         }
0781     }
0782 
0783     // left border
0784     for (unsigned int i = wwi.width; i < wwi.width * (wwi.height - 1); i += wwi.width) {
0785         if (wwi.constraint[i]) {
0786             Pair window_pos = wwi.origin[i];
0787             Pair current_pos = wwi.position[i];
0788             Pair move = {window_pos.x - current_pos.x, window_pos.y - current_pos.y};
0789             Pair accel = {move.x * m_stiffness, move.y * m_stiffness};
0790             wwi.acceleration[i] = accel;
0791         } else {
0792             Pair &pos = wwi.position[i];
0793             neibourgs[0] = wwi.position[i + 1];
0794             neibourgs[1] = wwi.position[i - wwi.width];
0795             neibourgs[2] = wwi.position[i + wwi.width];
0796 
0797             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;
0798             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;
0799 
0800             acceleration.x /= 3;
0801             acceleration.y /= 3;
0802 
0803             wwi.acceleration[i] = acceleration;
0804         }
0805     }
0806 
0807     // right border
0808     for (unsigned int i = 2 * wwi.width - 1; i < wwi.count - 1; i += wwi.width) {
0809         if (wwi.constraint[i]) {
0810             Pair window_pos = wwi.origin[i];
0811             Pair current_pos = wwi.position[i];
0812             Pair move = {window_pos.x - current_pos.x, window_pos.y - current_pos.y};
0813             Pair accel = {move.x * m_stiffness, move.y * m_stiffness};
0814             wwi.acceleration[i] = accel;
0815         } else {
0816             Pair &pos = wwi.position[i];
0817             neibourgs[0] = wwi.position[i - 1];
0818             neibourgs[1] = wwi.position[i - wwi.width];
0819             neibourgs[2] = wwi.position[i + wwi.width];
0820 
0821             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;
0822             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;
0823 
0824             acceleration.x /= 3;
0825             acceleration.y /= 3;
0826 
0827             wwi.acceleration[i] = acceleration;
0828         }
0829     }
0830 
0831     // for the inner points
0832     for (unsigned int j = 1; j < wwi.height - 1; ++j) {
0833         for (unsigned int i = 1; i < wwi.width - 1; ++i) {
0834             unsigned int index = i + j * wwi.width;
0835 
0836             if (wwi.constraint[index]) {
0837                 Pair window_pos = wwi.origin[index];
0838                 Pair current_pos = wwi.position[index];
0839                 Pair move = {window_pos.x - current_pos.x, window_pos.y - current_pos.y};
0840                 Pair accel = {move.x * m_stiffness, move.y * m_stiffness};
0841                 wwi.acceleration[index] = accel;
0842             } else {
0843                 Pair &pos = wwi.position[index];
0844                 neibourgs[0] = wwi.position[index - 1];
0845                 neibourgs[1] = wwi.position[index + 1];
0846                 neibourgs[2] = wwi.position[index - wwi.width];
0847                 neibourgs[3] = wwi.position[index + wwi.width];
0848 
0849                 acceleration.x = ((neibourgs[0].x - pos.x) - x_length) * m_stiffness + (x_length - (pos.x - neibourgs[1].x)) * m_stiffness + (neibourgs[2].x - pos.x) * m_stiffness + (neibourgs[3].x - pos.x) * m_stiffness;
0850                 acceleration.y = (y_length - (pos.y - neibourgs[2].y)) * m_stiffness + ((neibourgs[3].y - pos.y) - y_length) * m_stiffness + (neibourgs[0].y - pos.y) * m_stiffness + (neibourgs[1].y - pos.y) * m_stiffness;
0851 
0852                 acceleration.x /= 4;
0853                 acceleration.y /= 4;
0854 
0855                 wwi.acceleration[index] = acceleration;
0856             }
0857         }
0858     }
0859 
0860     heightRingLinearMean(wwi.acceleration, wwi);
0861 
0862 #if defined COMPUTE_STATS
0863     Pair accBound = {m_maxAcceleration, m_minAcceleration};
0864     Pair velBound = {m_maxVelocity, m_minVelocity};
0865 #endif
0866 
0867     // compute the new velocity of each vertex.
0868     for (unsigned int i = 0; i < wwi.count; ++i) {
0869         Pair acc = wwi.acceleration[i];
0870         fixVectorBounds(acc, m_minAcceleration, m_maxAcceleration);
0871 
0872 #if defined COMPUTE_STATS
0873         computeVectorBounds(acc, accBound);
0874 #endif
0875 
0876         Pair &vel = wwi.velocity[i];
0877         vel.x = acc.x * time + vel.x * m_drag;
0878         vel.y = acc.y * time + vel.y * m_drag;
0879 
0880         acc_sum += fabs(acc.x) + fabs(acc.y);
0881     }
0882 
0883     heightRingLinearMean(wwi.velocity, wwi);
0884 
0885     // compute the new pos of each vertex.
0886     for (unsigned int i = 0; i < wwi.count; ++i) {
0887         Pair &pos = wwi.position[i];
0888         Pair &vel = wwi.velocity[i];
0889 
0890         fixVectorBounds(vel, m_minVelocity, m_maxVelocity);
0891 #if defined COMPUTE_STATS
0892         computeVectorBounds(vel, velBound);
0893 #endif
0894 
0895         pos.x += vel.x * time * m_move_factor;
0896         pos.y += vel.y * time * m_move_factor;
0897 
0898         vel_sum += fabs(vel.x) + fabs(vel.y);
0899 
0900 #if defined VERBOSE_MODE
0901         if (wwi.constraint[i]) {
0902             qCDebug(KWIN_WOBBLYWINDOWS) << "Constraint point ** vel : " << vel.x << "," << vel.y << " ** move : " << vel.x * time << "," << vel.y * time;
0903         }
0904 #endif
0905     }
0906 
0907     if (!wwi.can_wobble_top) {
0908         for (unsigned int i = 0; i < wwi.width; ++i) {
0909             for (unsigned j = 0; j < wwi.width - 1; ++j) {
0910                 wwi.position[i + wwi.width * j].y = wwi.origin[i + wwi.width * j].y;
0911             }
0912         }
0913     }
0914     if (!wwi.can_wobble_bottom) {
0915         for (unsigned int i = wwi.width * (wwi.height - 1); i < wwi.count; ++i) {
0916             for (unsigned j = 0; j < wwi.width - 1; ++j) {
0917                 wwi.position[i - wwi.width * j].y = wwi.origin[i - wwi.width * j].y;
0918             }
0919         }
0920     }
0921     if (!wwi.can_wobble_left) {
0922         for (unsigned int i = 0; i < wwi.count; i += wwi.width) {
0923             for (unsigned j = 0; j < wwi.width - 1; ++j) {
0924                 wwi.position[i + j].x = wwi.origin[i + j].x;
0925             }
0926         }
0927     }
0928     if (!wwi.can_wobble_right) {
0929         for (unsigned int i = wwi.width - 1; i < wwi.count; i += wwi.width) {
0930             for (unsigned j = 0; j < wwi.width - 1; ++j) {
0931                 wwi.position[i - j].x = wwi.origin[i - j].x;
0932             }
0933         }
0934     }
0935 
0936 #if defined VERBOSE_MODE
0937 #if defined COMPUTE_STATS
0938     qCDebug(KWIN_WOBBLYWINDOWS) << "Acceleration bounds (" << accBound.x << ", " << accBound.y << ")";
0939     qCDebug(KWIN_WOBBLYWINDOWS) << "Velocity bounds (" << velBound.x << ", " << velBound.y << ")";
0940 #endif
0941     qCDebug(KWIN_WOBBLYWINDOWS) << "sum_acc : " << acc_sum << "  ***  sum_vel :" << vel_sum;
0942 #endif
0943 
0944     wwi.wobblying = !(acc_sum < m_stopAcceleration && vel_sum < m_stopVelocity);
0945     if (wwi.status != Moving && !wwi.wobblying) {
0946         windows.remove(w);
0947         unredirect(w);
0948         if (windows.isEmpty()) {
0949             effects->addRepaintFull();
0950         }
0951         return false;
0952     } else if (!wwi.wobblying) {
0953         setVertexSnappingMode(RenderGeometry::VertexSnappingMode::Round);
0954     }
0955 
0956     return true;
0957 }
0958 
0959 void WobblyWindowsEffect::heightRingLinearMean(QList<Pair> &data, WindowWobblyInfos &wwi)
0960 {
0961     Pair neibourgs[8];
0962 
0963     // for corners
0964 
0965     // top-left
0966     {
0967         Pair &res = wwi.buffer[0];
0968         Pair vit = data[0];
0969         neibourgs[0] = data[1];
0970         neibourgs[1] = data[wwi.width];
0971         neibourgs[2] = data[wwi.width + 1];
0972 
0973         res.x = (neibourgs[0].x + neibourgs[1].x + neibourgs[2].x + 3.0 * vit.x) / 6.0;
0974         res.y = (neibourgs[0].y + neibourgs[1].y + neibourgs[2].y + 3.0 * vit.y) / 6.0;
0975     }
0976 
0977     // top-right
0978     {
0979         Pair &res = wwi.buffer[wwi.width - 1];
0980         Pair vit = data[wwi.width - 1];
0981         neibourgs[0] = data[wwi.width - 2];
0982         neibourgs[1] = data[2 * wwi.width - 1];
0983         neibourgs[2] = data[2 * wwi.width - 2];
0984 
0985         res.x = (neibourgs[0].x + neibourgs[1].x + neibourgs[2].x + 3.0 * vit.x) / 6.0;
0986         res.y = (neibourgs[0].y + neibourgs[1].y + neibourgs[2].y + 3.0 * vit.y) / 6.0;
0987     }
0988 
0989     // bottom-left
0990     {
0991         Pair &res = wwi.buffer[wwi.width * (wwi.height - 1)];
0992         Pair vit = data[wwi.width * (wwi.height - 1)];
0993         neibourgs[0] = data[wwi.width * (wwi.height - 1) + 1];
0994         neibourgs[1] = data[wwi.width * (wwi.height - 2)];
0995         neibourgs[2] = data[wwi.width * (wwi.height - 2) + 1];
0996 
0997         res.x = (neibourgs[0].x + neibourgs[1].x + neibourgs[2].x + 3.0 * vit.x) / 6.0;
0998         res.y = (neibourgs[0].y + neibourgs[1].y + neibourgs[2].y + 3.0 * vit.y) / 6.0;
0999     }
1000 
1001     // bottom-right
1002     {
1003         Pair &res = wwi.buffer[wwi.count - 1];
1004         Pair vit = data[wwi.count - 1];
1005         neibourgs[0] = data[wwi.count - 2];
1006         neibourgs[1] = data[wwi.width * (wwi.height - 1) - 1];
1007         neibourgs[2] = data[wwi.width * (wwi.height - 1) - 2];
1008 
1009         res.x = (neibourgs[0].x + neibourgs[1].x + neibourgs[2].x + 3.0 * vit.x) / 6.0;
1010         res.y = (neibourgs[0].y + neibourgs[1].y + neibourgs[2].y + 3.0 * vit.y) / 6.0;
1011     }
1012 
1013     // for borders
1014 
1015     // top border
1016     for (unsigned int i = 1; i < wwi.width - 1; ++i) {
1017         Pair &res = wwi.buffer[i];
1018         Pair vit = data[i];
1019         neibourgs[0] = data[i - 1];
1020         neibourgs[1] = data[i + 1];
1021         neibourgs[2] = data[i + wwi.width];
1022         neibourgs[3] = data[i + wwi.width - 1];
1023         neibourgs[4] = data[i + wwi.width + 1];
1024 
1025         res.x = (neibourgs[0].x + neibourgs[1].x + neibourgs[2].x + neibourgs[3].x + neibourgs[4].x + 5.0 * vit.x) / 10.0;
1026         res.y = (neibourgs[0].y + neibourgs[1].y + neibourgs[2].y + neibourgs[3].y + neibourgs[4].y + 5.0 * vit.y) / 10.0;
1027     }
1028 
1029     // bottom border
1030     for (unsigned int i = wwi.width * (wwi.height - 1) + 1; i < wwi.count - 1; ++i) {
1031         Pair &res = wwi.buffer[i];
1032         Pair vit = data[i];
1033         neibourgs[0] = data[i - 1];
1034         neibourgs[1] = data[i + 1];
1035         neibourgs[2] = data[i - wwi.width];
1036         neibourgs[3] = data[i - wwi.width - 1];
1037         neibourgs[4] = data[i - wwi.width + 1];
1038 
1039         res.x = (neibourgs[0].x + neibourgs[1].x + neibourgs[2].x + neibourgs[3].x + neibourgs[4].x + 5.0 * vit.x) / 10.0;
1040         res.y = (neibourgs[0].y + neibourgs[1].y + neibourgs[2].y + neibourgs[3].y + neibourgs[4].y + 5.0 * vit.y) / 10.0;
1041     }
1042 
1043     // left border
1044     for (unsigned int i = wwi.width; i < wwi.width * (wwi.height - 1); i += wwi.width) {
1045         Pair &res = wwi.buffer[i];
1046         Pair vit = data[i];
1047         neibourgs[0] = data[i + 1];
1048         neibourgs[1] = data[i - wwi.width];
1049         neibourgs[2] = data[i + wwi.width];
1050         neibourgs[3] = data[i - wwi.width + 1];
1051         neibourgs[4] = data[i + wwi.width + 1];
1052 
1053         res.x = (neibourgs[0].x + neibourgs[1].x + neibourgs[2].x + neibourgs[3].x + neibourgs[4].x + 5.0 * vit.x) / 10.0;
1054         res.y = (neibourgs[0].y + neibourgs[1].y + neibourgs[2].y + neibourgs[3].y + neibourgs[4].y + 5.0 * vit.y) / 10.0;
1055     }
1056 
1057     // right border
1058     for (unsigned int i = 2 * wwi.width - 1; i < wwi.count - 1; i += wwi.width) {
1059         Pair &res = wwi.buffer[i];
1060         Pair vit = data[i];
1061         neibourgs[0] = data[i - 1];
1062         neibourgs[1] = data[i - wwi.width];
1063         neibourgs[2] = data[i + wwi.width];
1064         neibourgs[3] = data[i - wwi.width - 1];
1065         neibourgs[4] = data[i + wwi.width - 1];
1066 
1067         res.x = (neibourgs[0].x + neibourgs[1].x + neibourgs[2].x + neibourgs[3].x + neibourgs[4].x + 5.0 * vit.x) / 10.0;
1068         res.y = (neibourgs[0].y + neibourgs[1].y + neibourgs[2].y + neibourgs[3].y + neibourgs[4].y + 5.0 * vit.y) / 10.0;
1069     }
1070 
1071     // for the inner points
1072     for (unsigned int j = 1; j < wwi.height - 1; ++j) {
1073         for (unsigned int i = 1; i < wwi.width - 1; ++i) {
1074             unsigned int index = i + j * wwi.width;
1075 
1076             Pair &res = wwi.buffer[index];
1077             Pair &vit = data[index];
1078             neibourgs[0] = data[index - 1];
1079             neibourgs[1] = data[index + 1];
1080             neibourgs[2] = data[index - wwi.width];
1081             neibourgs[3] = data[index + wwi.width];
1082             neibourgs[4] = data[index - wwi.width - 1];
1083             neibourgs[5] = data[index - wwi.width + 1];
1084             neibourgs[6] = data[index + wwi.width - 1];
1085             neibourgs[7] = data[index + wwi.width + 1];
1086 
1087             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;
1088             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;
1089         }
1090     }
1091 
1092     auto tmp = data;
1093     data = wwi.buffer;
1094     wwi.buffer = tmp;
1095 }
1096 
1097 bool WobblyWindowsEffect::isActive() const
1098 {
1099     return !windows.isEmpty();
1100 }
1101 
1102 qreal WobblyWindowsEffect::stiffness() const
1103 {
1104     return m_stiffness;
1105 }
1106 
1107 qreal WobblyWindowsEffect::drag() const
1108 {
1109     return m_drag;
1110 }
1111 
1112 qreal WobblyWindowsEffect::moveFactor() const
1113 {
1114     return m_move_factor;
1115 }
1116 
1117 qreal WobblyWindowsEffect::xTesselation() const
1118 {
1119     return m_xTesselation;
1120 }
1121 
1122 qreal WobblyWindowsEffect::yTesselation() const
1123 {
1124     return m_yTesselation;
1125 }
1126 
1127 qreal WobblyWindowsEffect::minVelocity() const
1128 {
1129     return m_minVelocity;
1130 }
1131 
1132 qreal WobblyWindowsEffect::maxVelocity() const
1133 {
1134     return m_maxVelocity;
1135 }
1136 
1137 qreal WobblyWindowsEffect::stopVelocity() const
1138 {
1139     return m_stopVelocity;
1140 }
1141 
1142 qreal WobblyWindowsEffect::minAcceleration() const
1143 {
1144     return m_minAcceleration;
1145 }
1146 
1147 qreal WobblyWindowsEffect::maxAcceleration() const
1148 {
1149     return m_maxAcceleration;
1150 }
1151 
1152 qreal WobblyWindowsEffect::stopAcceleration() const
1153 {
1154     return m_stopAcceleration;
1155 }
1156 
1157 bool WobblyWindowsEffect::isMoveWobble() const
1158 {
1159     return m_moveWobble;
1160 }
1161 
1162 bool WobblyWindowsEffect::isResizeWobble() const
1163 {
1164     return m_resizeWobble;
1165 }
1166 
1167 } // namespace KWin
1168 
1169 #include "moc_wobblywindows.cpp"