From 3c557be70785a293d8d56a935530665fe4daf6ab Mon Sep 17 00:00:00 2001 From: Eric Edlund Date: Wed, 16 Mar 2022 15:42:58 -0400 Subject: [PATCH] rework of slide effect internals Fixed a bunch of bugs and polished the slide effect. Plugged the slide effect into the new VirtualDesktopManager interface desktopChanging() to allow for mac os style desktop switching. BUG: 448419 BUG: 401479 --- src/effects/slide/slide.cpp | 460 +++++++++++++++++++++++------------- src/effects/slide/slide.h | 56 ++++- 2 files changed, 337 insertions(+), 179 deletions(-) diff --git a/src/effects/slide/slide.cpp b/src/effects/slide/slide.cpp index c9cc15c916..33c0680b9b 100644 --- a/src/effects/slide/slide.cpp +++ b/src/effects/slide/slide.cpp @@ -15,6 +15,9 @@ // KConfigSkeleton #include "slideconfig.h" +#include +#include + namespace KWin { @@ -27,21 +30,27 @@ SlideEffect::SlideEffect() connect(effects, QOverload::of(&EffectsHandler::desktopChanged), this, &SlideEffect::desktopChanged); + connect(effects, QOverload::of(&EffectsHandler::desktopChanging), + this, &SlideEffect::desktopChanging); + connect(effects, QOverload<>::of(&EffectsHandler::desktopChangingCancelled), + this, &SlideEffect::desktopChangingCancelled); connect(effects, &EffectsHandler::windowAdded, this, &SlideEffect::windowAdded); connect(effects, &EffectsHandler::windowDeleted, this, &SlideEffect::windowDeleted); connect(effects, &EffectsHandler::numberDesktopsChanged, - this, &SlideEffect::stop); + this, &SlideEffect::finishedSwitching); connect(effects, &EffectsHandler::screenAdded, - this, &SlideEffect::stop); + this, &SlideEffect::finishedSwitching); connect(effects, &EffectsHandler::screenRemoved, - this, &SlideEffect::stop); + this, &SlideEffect::finishedSwitching); + + m_currentPosition = effects->desktopCoords(effects->currentDesktop()); } SlideEffect::~SlideEffect() { - stop(); + finishedSwitching(); } bool SlideEffect::supported() @@ -53,8 +62,8 @@ void SlideEffect::reconfigure(ReconfigureFlags) { SlideConfig::self()->read(); - m_timeLine.setDuration( - std::chrono::milliseconds(animationTime(500))); + m_animationDuration = animationTime(500); + m_timeLine.setDuration(std::chrono::milliseconds(m_animationDuration)); m_hGap = SlideConfig::horizontalGap(); m_vGap = SlideConfig::verticalGap(); @@ -64,98 +73,69 @@ void SlideEffect::reconfigure(ReconfigureFlags) void SlideEffect::prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime) { - std::chrono::milliseconds delta = std::chrono::milliseconds::zero(); - if (m_lastPresentTime.count()) { - delta = presentTime - m_lastPresentTime; - } - m_lastPresentTime = presentTime; + std::chrono::milliseconds timeDelta = std::chrono::milliseconds::zero(); + if (m_lastPresentTime.count()) { + timeDelta = presentTime - m_lastPresentTime; + } + m_lastPresentTime = presentTime; - m_timeLine.update(delta); + m_timeLine.update(timeDelta); - data.mask |= PAINT_SCREEN_TRANSFORMED - | PAINT_SCREEN_BACKGROUND_FIRST; + if (!m_gestureActive) { // When animating + m_currentPosition = m_startPos + (m_endPos - m_startPos) * m_timeLine.value(); + } - effects->prePaintScreen(data, presentTime); -} + data.mask |= PAINT_SCREEN_TRANSFORMED + | PAINT_SCREEN_BACKGROUND_FIRST; -/** - * Wrap vector @p diff around grid @p w x @p h. - * - * Wrapping is done in such a way that magnitude of x and y component of vector - * @p diff is less than half of @p w and half of @p h, respectively. This will - * result in having the "shortest" path between two points. - * - * @param diff Vector between two points - * @param w Width of the desktop grid - * @param h Height of the desktop grid - */ -inline void wrapDiff(QPoint &diff, int w, int h) -{ - if (diff.x() > w/2) { - diff.setX(diff.x() - w); - } else if (diff.x() < -w/2) { - diff.setX(diff.x() + w); - } - - if (diff.y() > h/2) { - diff.setY(diff.y() - h); - } else if (diff.y() < -h/2) { - diff.setY(diff.y() + h); - } -} - -inline QRegion buildClipRegion(const QPoint &pos, int w, int h) -{ - const QSize screenSize = effects->virtualScreenSize(); - QRegion r = QRect(pos, screenSize); - if (effects->optionRollOverDesktops()) { - r |= (r & QRect(-w, 0, w, h)).translated(w, 0); // W - r |= (r & QRect(w, 0, w, h)).translated(-w, 0); // E - - r |= (r & QRect(0, -h, w, h)).translated(0, h); // N - r |= (r & QRect(0, h, w, h)).translated(0, -h); // S - - r |= (r & QRect(-w, -h, w, h)).translated(w, h); // NW - r |= (r & QRect(w, -h, w, h)).translated(-w, h); // NE - r |= (r & QRect(w, h, w, h)).translated(-w, -h); // SE - r |= (r & QRect(-w, h, w, h)).translated(w, -h); // SW - } - return r; + effects->prePaintScreen(data, presentTime); } void SlideEffect::paintScreen(int mask, const QRegion ®ion, ScreenPaintData &data) { const bool wrap = effects->optionRollOverDesktops(); - const int w = workspaceWidth(); - const int h = workspaceHeight(); + const int w = effects->desktopGridWidth(); + const int h = effects->desktopGridHeight(); + bool wrappingX = false, wrappingY = false; - QPoint currentPos = m_startPos + m_diff * m_timeLine.value(); + QPointF drawPosition = forcePositivePosition(m_currentPosition); - // When "Desktop navigation wraps around" checkbox is checked, currentPos - // can be outside the rectangle Rect{x:-w, y:-h, width:2*w, height: 2*h}, - // so we map currentPos back to the rect. - if (wrap) { - currentPos.setX(currentPos.x() % w); - currentPos.setY(currentPos.y() % h); + if (wrap) { // + drawPosition = constrainToDrawableRange(drawPosition); } + //Clipping QVector visibleDesktops; visibleDesktops.reserve(4); // 4 - maximum number of visible desktops - const QRegion clipRegion = buildClipRegion(currentPos, w, h); for (int i = 1; i <= effects->numberOfDesktops(); i++) { - const QRect desktopGeo = desktopGeometry(i); - if (!clipRegion.contains(desktopGeo)) { - continue; + if (effects->desktopGridCoords(i).x() % w == (int)(m_currentPosition.x()) % w) { + visibleDesktops << i; + } else if (effects->desktopGridCoords(i).x() % w == ((int)(m_currentPosition.x()) + 1) % w) { + visibleDesktops << i; + } else if (effects->desktopGridCoords(i).y() % h == (int)(m_currentPosition.y()) % h) { + visibleDesktops << i; + } else if (effects->desktopGridCoords(i).y() % h == ((int)(m_currentPosition.y()) + 1) % h) { + visibleDesktops << i; } - visibleDesktops << i; } - // When we enter a virtual desktop that has a window in fullscreen mode, - // stacking order is fine. When we leave a virtual desktop that has - // a window in fullscreen mode, stacking order is no longer valid - // because panels are raised above the fullscreen window. Construct - // a list of fullscreen windows, so we can decide later whether - // docks should be visible on different virtual desktops. + //If we're wrapping, draw the desktop in the second position. + if (drawPosition.x() > w - 1) { + wrappingX = true; + } + + if (drawPosition.y() > h - 1) { + wrappingY = true; + } + + /* + * When we enter a virtual desktop that has a window in fullscreen mode, + * stacking order is fine. When we leave a virtual desktop that has + * a window in fullscreen mode, stacking order is no longer valid + * because panels are raised above the fullscreen window. Construct + * a list of fullscreen windows, so we can decide later whether + * docks should be visible on different virtual desktops. + */ if (m_slideDocks) { const auto windows = effects->stackingOrder(); m_paintCtx.fullscreenWindows.clear(); @@ -167,25 +147,41 @@ void SlideEffect::paintScreen(int mask, const QRegion ®ion, ScreenPaintData & } } - // Screen is painted in several passes. Each painting pass paints - // a single virtual desktop. There could be either 2 or 4 painting - // passes, depending how an user moves between virtual desktops. - // Windows, such as docks or keep-above windows, are painted in - // the last pass so they are above other windows. + /* + * Screen is painted in several passes. Each painting pass paints + * a single virtual desktop. There could be either 2 or 4 painting + * passes, depending how an user moves between virtual desktops. + * Windows, such as docks or keep-above windows, are painted in + * the last pass so they are above other windows. + */ m_paintCtx.firstPass = true; const int lastDesktop = visibleDesktops.last(); for (int desktop : qAsConst(visibleDesktops)) { m_paintCtx.desktop = desktop; m_paintCtx.lastPass = (lastDesktop == desktop); - m_paintCtx.translation = desktopCoords(desktop) - currentPos; - if (wrap) { - wrapDiff(m_paintCtx.translation, w, h); + m_paintCtx.translation = QPointF(effects->desktopGridCoords(desktop)) - drawPosition;//TODO: verify + + // Decide if that first desktop should be drawn at 0 or the higher position used for wrapping. + if (effects->desktopGridCoords(desktop).x() == 0 && wrappingX) { + m_paintCtx.translation = QPointF(m_paintCtx.translation.x() + w, m_paintCtx.translation.y()); } + + if (effects->desktopGridCoords(desktop).y() == 0 && wrappingY) { + m_paintCtx.translation = QPointF(m_paintCtx.translation.x(), m_paintCtx.translation.y() + h); + } + effects->paintScreen(mask, region, data); m_paintCtx.firstPass = false; } } +QPoint SlideEffect::getDrawCoords(QPointF pos, EffectScreen *screen){ + QPoint c = QPoint(); + c.setX(pos.x() * (screen->geometry().width() + m_hGap)); + c.setY(pos.y() * (screen->geometry().height() + m_vGap)); + return c; +} + /** * Decide whether given window @p w should be transformed/translated. * @returns @c true if given window @p w should be transformed, otherwise @c false @@ -228,15 +224,19 @@ bool SlideEffect::isPainted(const EffectWindow *w) const return true; } if (w->isDesktop()) { - // If desktop background is not being slided, draw it only - // in the first pass. Otherwise, desktop backgrounds from - // follow-up virtual desktops will be drawn above windows - // from previous virtual desktops. + /* + * If desktop background is not being slided, draw it only + * in the first pass. Otherwise, desktop backgrounds from + * follow-up virtual desktops will be drawn above windows + * from previous virtual desktops. + */ return m_slideBackground || m_paintCtx.firstPass; } - // In order to make sure that 'keep above' windows are above - // other windows during transition to another virtual desktop, - // they should be painted in the last pass. + /* + * In order to make sure that 'keep above' windowscreen->geometry().x()s are above + * other windows during transition to another virtual desktop, + * they should be painted in the last pass. + */ if (w->keepAbove()) { return m_paintCtx.lastPass; } @@ -252,6 +252,7 @@ bool SlideEffect::isPainted(const EffectWindow *w) const void SlideEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std::chrono::milliseconds presentTime) { const bool painted = isPainted(w); + if (painted) { w->enablePainting(EffectWindow::PAINT_DISABLED_BY_DESKTOP); } else { @@ -265,96 +266,74 @@ void SlideEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std: void SlideEffect::paintWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data) { - if (isTranslated(w)) { - data += m_paintCtx.translation; + for (EffectScreen *screen: effects->screens()) { + QPoint translation = getDrawCoords(m_paintCtx.translation, screen); + if (isTranslated(w)) { + data += translation; + } + + effects->paintWindow( + w, + mask, + // Only paint the region that intersects the current screen and desktop. + region.intersected(effects->clientArea(ScreenArea, w)).intersected(effects->clientArea(ScreenArea, screen, effects->currentDesktop())), + data); + + if (isTranslated(w)) { + // Undo the translation for the next screen. I know, it hurts me too. + data += QPoint(-translation.x(), -translation.y()); + } } - effects->paintWindow(w, mask, region, data); } void SlideEffect::postPaintScreen() { - if (m_timeLine.done()) { - stop(); + if (m_timeLine.done() && !m_gestureActive) { + finishedSwitching(); } effects->addRepaintFull(); effects->postPaintScreen(); } -/** - * Get position of the top-left corner of desktop @p id within desktop grid with gaps. - * @param id ID of a virtual desktop +/* + * Negative desktop positions aren't allowed. */ -QPoint SlideEffect::desktopCoords(int id) const +QPointF SlideEffect::forcePositivePosition(QPointF p) const { - QPoint c = effects->desktopCoords(id); - const QPoint gridPos = effects->desktopGridCoords(id); - c.setX(c.x() + m_hGap * gridPos.x()); - c.setY(c.y() + m_vGap * gridPos.y()); - return c; -} - -/** - * Get geometry of desktop @p id within desktop grid with gaps. - * @param id ID of a virtual desktop - */ -QRect SlideEffect::desktopGeometry(int id) const -{ - QRect g = effects->virtualScreenGeometry(); - g.translate(desktopCoords(id)); - return g; -} - -/** - * Get width of a virtual desktop grid. - */ -int SlideEffect::workspaceWidth() const -{ - int w = effects->workspaceWidth(); - w += m_hGap * effects->desktopGridWidth(); - return w; -} - -/** - * Get height of a virtual desktop grid. - */ -int SlideEffect::workspaceHeight() const -{ - int h = effects->workspaceHeight(); - h += m_vGap * effects->desktopGridHeight(); - return h; + while (p.x() < 0) { + p.setX(p.x() + effects->desktopGridWidth()); + } + while (p.y() < 0) { + p.setY(p.y() + effects->desktopGridHeight()); + } + return p; } bool SlideEffect::shouldElevate(const EffectWindow *w) const { - // Static docks(i.e. this effect doesn't slide docks) should be elevated - // so they can properly animate themselves when an user enters or leaves - // a virtual desktop with a window in fullscreen mode. + /* + * Static docks(i.e. this effect doesn't slide docks) should be elevated + * so they can properly animate themselves when an user enters or leaves + * a virtual desktop with a window in fullscreen mode. + */ return w->isDock() && !m_slideDocks; } -void SlideEffect::start(int old, int current, EffectWindow *movingWindow) +/* + * This function is called when the desktop changes. + * Called AFTER the gesture is released. + * Sets up animation to round off to the new current desktop. + */ +void SlideEffect::startAnimation(int old, int current, EffectWindow *movingWindow) { + Q_UNUSED(old) + m_movingWindow = movingWindow; const bool wrap = effects->optionRollOverDesktops(); - const int w = workspaceWidth(); - const int h = workspaceHeight(); - - if (m_active) { - QPoint passed = m_diff * m_timeLine.value(); - QPoint currentPos = m_startPos + passed; - QPoint delta = desktopCoords(current) - desktopCoords(old); - if (wrap) { - wrapDiff(delta, w, h); - } - m_diff += delta - passed; - m_startPos = currentPos; - // TODO: Figure out how to smooth movement. - m_timeLine.reset(); - return; - } + //Handle stacking order const auto windows = effects->stackingOrder(); for (EffectWindow *w : windows) { if (shouldElevate(w)) { @@ -365,18 +344,35 @@ void SlideEffect::start(int old, int current, EffectWindow *movingWindow) w->setData(WindowForceBlurRole, QVariant(true)); } - m_diff = desktopCoords(current) - desktopCoords(old); - if (wrap) { - wrapDiff(m_diff, w, h); - } - m_startPos = desktopCoords(old); - m_timeLine.reset(); + // Set up animation m_active = true; + m_timeLine.reset(); + + m_startPos = m_currentPosition; + m_endPos = effects->desktopGridCoords(current); + if (wrap) { + optimizePath(); + } + + // Find an apropriate duration + m_timeLine.setDuration(std::chrono::milliseconds(m_animationDuration)); + + QPointF distance = m_startPos - m_endPos; + distance.setX(std::abs(distance.x())); + distance.setY(std::abs(distance.y())); + if (distance.x() < 1 && distance.y() < 1) { + if (distance.x() > distance.y()) { + m_timeLine.setDuration(std::chrono::milliseconds((int)(m_animationDuration * distance.x()))); + } else { + m_timeLine.setDuration(std::chrono::milliseconds((int)(m_animationDuration * distance.y()))); + } + } + effects->setActiveFullScreenEffect(this); effects->addRepaintFull(); } -void SlideEffect::stop() +void SlideEffect::finishedSwitching() { if (!m_active) { return; @@ -397,14 +393,70 @@ void SlideEffect::stop() m_active = false; m_lastPresentTime = std::chrono::milliseconds::zero(); effects->setActiveFullScreenEffect(nullptr); + m_currentPosition = effects->desktopGridCoords(effects->currentDesktop()); } void SlideEffect::desktopChanged(int old, int current, EffectWindow *with) { - if (effects->activeFullScreenEffect() && effects->activeFullScreenEffect() != this) { + if (effects->hasActiveFullScreenEffect() && effects->activeFullScreenEffect() != this) { + m_currentPosition = effects->desktopGridCoords(effects->currentDesktop()); return; } - start(old, current, with); + + m_gestureActive = false; + startAnimation(old, current, with); +} + +void SlideEffect::desktopChanging(uint old, QPointF desktopOffset, EffectWindow *with) +{ + if (effects->hasActiveFullScreenEffect() && effects->activeFullScreenEffect() != this) { + return; + } + + m_gestureActive = true; + m_movingWindow = with; + + const bool wrap = effects->optionRollOverDesktops(); + + // Find desktop position based on animationDelta + QPoint gridPos = effects->desktopGridCoords(old); + m_currentPosition.setX(gridPos.x() + desktopOffset.x()); + m_currentPosition.setY(gridPos.y() + desktopOffset.y()); + + m_currentPosition = forcePositivePosition(m_currentPosition); + + if (!wrap) { + m_currentPosition = moveInsideDesktopGrid(m_currentPosition); + } + + m_active = true; + effects->setActiveFullScreenEffect(this); + effects->addRepaintFull(); +} + +void SlideEffect::desktopChangingCancelled() +{ + if (effects->hasActiveFullScreenEffect() && effects->activeFullScreenEffect() != this) { + return; + } + + std::cout << "Cancelled" << std::endl; + m_gestureActive = false; + startAnimation(effects->currentDesktop(), effects->currentDesktop(), nullptr); +} + +QPointF SlideEffect::moveInsideDesktopGrid(QPointF p) +{ + if (p.x() < 0) { + p.setX(0); + } else if (p.y() < 0) { + p.setY(0); + } else if (p.x() > effects->desktopGridWidth() - 1) { + p.setX(effects->desktopGridWidth() - 1); + } else if (p.y() > effects->desktopGridHeight() - 1) { + p.setY(effects->desktopGridHeight() - 1); + } + return p; } void SlideEffect::windowAdded(EffectWindow *w) @@ -432,4 +484,76 @@ void SlideEffect::windowDeleted(EffectWindow *w) m_paintCtx.fullscreenWindows.removeAll(w); } +/* + * Find the fastest path between two desktops. + * This function decides when it's better to wrap around the grid or not. + * Only call if wrapping is enabled. + */ +void SlideEffect::optimizePath() +{ + int w = effects->desktopGridWidth(); + int h = effects->desktopGridHeight(); + + // Keep coordinates as low as possible + if(m_startPos.x() >= w && m_endPos.x() >= w) { + m_startPos.setX(fmod(m_startPos.x(), w)); + m_endPos.setX(fmod(m_endPos.x(), w)); + } + if(m_startPos.y() >= h && m_endPos.y() >= h) { + m_startPos.setY(fmod(m_startPos.y(), h)); + m_endPos.setY(fmod(m_endPos.y(), h)); + } + + /* + * Is there is a shorter possible route? + * If the x distance to be traveled is more than half the grid width, it's faster to wrap. + * To avoid negative coordinates, take the lower coordinate and raise. + */ + if (std::abs((m_startPos.x() - m_endPos.x())) > (double)w / (double)2) { + if (m_startPos.x() < m_endPos.x()) { + while (m_startPos.x() < m_endPos.x()) + m_startPos.setX(m_startPos.x() + w); + + } else { + while (m_endPos.x() < m_startPos.x()) + m_endPos.setX(m_endPos.x() + w); + } + // Keep coordinates as low as possible + if(m_startPos.x() >= w && m_endPos.x() >= w) { + m_startPos.setX(fmod(m_startPos.x(), w)); + m_endPos.setX(fmod(m_endPos.x(), w)); + } + } + + // Same for y + if (std::abs((m_endPos.y() - m_startPos.y())) > (double)h / (double)2) { + if (m_startPos.y() < m_endPos.y()) { + while (m_startPos.y() < m_endPos.y()) + m_startPos.setY(m_startPos.y() + h); + + } else { + while (m_endPos.y() < m_startPos.y()) + m_endPos.setY(m_endPos.y() + h); + } + // Keep coordinates as low as possible + if(m_startPos.y() >= h && m_endPos.y() >= h) { + m_startPos.setY(fmod(m_startPos.y(), h)); + m_endPos.setY(fmod(m_endPos.y(), h)); + } + } +} + +/* + * Takes the point and uses modulus to keep draw position within [0, desktopGridWidth] + * The render loop will draw the first desktop (0) after the last one (at position desktopGridWidth) for the wrap animation. + * This function finds the true fastest path, regardless of which direction the animation is already going; + * I was a little upset about this limitation until I realized that MacOS can't even wrap desktops :) + */ +QPointF SlideEffect::constrainToDrawableRange(QPointF p) +{ + p.setX(fmod(p.x(), effects->desktopGridWidth())); + p.setY(fmod(p.y(), effects->desktopGridHeight())); + return p; +} + } // namespace KWin diff --git a/src/effects/slide/slide.h b/src/effects/slide/slide.h index c7c7ef572e..586b27d07c 100644 --- a/src/effects/slide/slide.h +++ b/src/effects/slide/slide.h @@ -18,6 +18,31 @@ namespace KWin { +/* + * How it Works: + * + * This effect doesn't change the current desktop, only recieves changes from the VirtualDesktopManager. + * The only visually aparent inputs are desktopChanged() and desktopChanging(). + * + * When responding to desktopChanging(), the draw position is only affected by what's recieved from there. + * After desktopChanging() is done, or without desktopChanging() having been called at all, desktopChanged() is called. + * The desktopChanged() function configures the m_startPos and m_endPos for the animation, and the duration. + * + * m_currentPosition and m_paintCtx.translation and everything else not labeled "drawCoordinate" uses desktops as a unit. + * Exmp: 1.2 means the dekstop at index 1 shifted over by .2 desktops. + * All coords must be positive. + * + * For the wrapping effect, the render loop has to handle desktop coordinates larger than the total grid's width. + * 1. It uses modulus to keep the desktop coords in the range [0, gridWidth]. + * 2. It will draw the desktop at index 0 at index gridWidth if it has to. + * I will not draw any thing farther outside the range than that. + * + * I've put an explanation of all the important private vars down at the bottom. + * + * Good luck :) + */ + + class SlideEffect : public Effect { Q_OBJECT @@ -58,40 +83,49 @@ public: private Q_SLOTS: void desktopChanged(int old, int current, EffectWindow *with); + void desktopChanging(uint old, QPointF desktopOffset, EffectWindow* with); + void desktopChangingCancelled(); void windowAdded(EffectWindow *w); void windowDeleted(EffectWindow *w); private: - QPoint desktopCoords(int id) const; - QRect desktopGeometry(int id) const; - int workspaceWidth() const; - int workspaceHeight() const; - + QPoint getDrawCoords(QPointF pos, EffectScreen *screen); bool isTranslated(const EffectWindow *w) const; bool isPainted(const EffectWindow *w) const; bool shouldElevate(const EffectWindow *w) const; + QPointF moveInsideDesktopGrid(QPointF p); + QPointF constrainToDrawableRange(QPointF p); + QPointF forcePositivePosition(QPointF p) const; + void optimizePath(); //Find the best path to target desktop - void start(int old, int current, EffectWindow *movingWindow = nullptr); - void stop(); + void startAnimation(int old, int current, EffectWindow *movingWindow = nullptr); + void finishedSwitching(); private: int m_hGap; int m_vGap; bool m_slideDocks; bool m_slideBackground; + int m_animationDuration; // Miliseconds for 1 complete desktop switch bool m_active = false; TimeLine m_timeLine; - QPoint m_startPos; - QPoint m_diff; + + // When the desktop isn't desktopChanging(), these two variables are used to control the animation path. + // They use desktops as a unit. + QPointF m_startPos; + QPointF m_endPos; + EffectWindow *m_movingWindow = nullptr; std::chrono::milliseconds m_lastPresentTime = std::chrono::milliseconds::zero(); + bool m_gestureActive = false; // If we're currently animating a gesture + QPointF m_currentPosition; // Should always be kept up to date with where on the grid we're seeing. struct { int desktop; bool firstPass; bool lastPass; - QPoint translation; + QPointF translation; //Uses desktops as units EffectWindowList fullscreenWindows; } m_paintCtx; @@ -101,7 +135,7 @@ private: inline int SlideEffect::duration() const { - return m_timeLine.duration().count(); + return m_animationDuration; } inline int SlideEffect::horizontalGap() const