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
This commit is contained in:
Eric Edlund 2022-03-16 15:42:58 -04:00
parent c7c1ac78ea
commit 3c557be707
2 changed files with 337 additions and 179 deletions

View file

@ -15,6 +15,9 @@
// KConfigSkeleton
#include "slideconfig.h"
#include <cmath>
#include <iostream>
namespace KWin
{
@ -27,21 +30,27 @@ SlideEffect::SlideEffect()
connect(effects, QOverload<int, int, EffectWindow *>::of(&EffectsHandler::desktopChanged),
this, &SlideEffect::desktopChanged);
connect(effects, QOverload<uint, QPointF, EffectWindow *>::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<SlideConfig>(500)));
m_animationDuration = animationTime<SlideConfig>(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 &region, 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<int> 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 &region, 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

View file

@ -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