Commit 6a7e780d authored by Vlad Zahorodnii's avatar Vlad Zahorodnii

[effects] Rewrite the Glide effect

There are several reasons why I "re-wrote" the Glide effect:
* it doesn't work correctly because it suffers from undesired perspective distortions: {F5914378}
   The worst part is that windows are distorted so much on multiple monitor setups that it's hard to say whether that's glide animation.
* window close animation is not quite intuitive: if the close button is
  located at the top and I click it, I would expect that window is
  rotated around the bottom edge, not the top; (IMHO)
* it's too much distracting when working on something for quite good
  amount of time: e.g. when editing photos, which involves a big number
  of different dialogs;
* there are issues with deletion of QTimeLine;
* windows are not gracefully released if some other effect grabs them;
* its code doesn't follow common coding style in KWin.

So, the "new" Glide effect is more subtle, it's possible to have
different rotation edges for window open/close animations, it doesn't
animate special windows(like audio volume feedback), the code is simpler
and readable. Yet, there are some issues with QTimeLine, which are
common to all effects in KWin anyway.

### Demos

//Window Open Animation//

//Window Close Animation//

{F5889805, layout=center, size=full}

CCBUG: 394245

Test Plan:
* Enabled the Glide effect
* Closed System Settings
* Opened it again

Reviewers: #kwin, #plasma, #vdg, davidedmundson

Reviewed By: #kwin, #plasma, #vdg, davidedmundson

Subscribers: ngraham, kwin

Tags: #kwin

Differential Revision:
parent df802d49
This diff is collapsed.
......@@ -5,6 +5,7 @@
Copyright (C) 2007 Philip Falkner <>
Copyright (C) 2009 Martin Gräßlin <>
Copyright (C) 2010 Alexandre Pereira <>
Copyright (C) 2018 Vlad Zagorodniy <>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -23,81 +24,133 @@ along with this program. If not, see <>.
#ifndef KWIN_GLIDE_H
#define KWIN_GLIDE_H
// kwineffects
#include <kwineffects.h>
class QTimeLine;
namespace KWin
class GlideEffect
: public Effect
class GlideEffect : public Effect
Q_PROPERTY(int duration READ configuredDuration)
Q_PROPERTY(int effect READ configuredEffect)
Q_PROPERTY(int angle READ configuredAngle)
Q_PROPERTY(int duration READ duration)
Q_PROPERTY(RotationEdge inRotationEdge READ inRotationEdge)
Q_PROPERTY(qreal inRotationAngle READ inRotationAngle)
Q_PROPERTY(qreal inDistance READ inDistance)
Q_PROPERTY(qreal inOpacity READ inOpacity)
Q_PROPERTY(RotationEdge outRotationEdge READ outRotationEdge)
Q_PROPERTY(qreal outRotationAngle READ outRotationAngle)
Q_PROPERTY(qreal outDistance READ outDistance)
Q_PROPERTY(qreal outOpacity READ outOpacity)
virtual void reconfigure(ReconfigureFlags);
virtual void prePaintScreen(ScreenPrePaintData& data, int time);
virtual void prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time);
virtual void paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data);
virtual void postPaintWindow(EffectWindow* w);
virtual bool isActive() const;
int requestedEffectChainPosition() const override {
return 50;
~GlideEffect() override;
void reconfigure(ReconfigureFlags flags) override;
void prePaintScreen(ScreenPrePaintData &data, int time) override;
void prePaintWindow(EffectWindow *w, WindowPrePaintData &data, int time) override;
void paintWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data) override;
void postPaintScreen() override;
bool isActive() const override;
int requestedEffectChainPosition() const override;
static bool supported();
// for properties
int configuredDuration() const {
return duration;
int configuredEffect() const {
return effect;
int configuredAngle() const {
return angle;
public Q_SLOTS:
void slotWindowAdded(KWin::EffectWindow* c);
void slotWindowClosed(KWin::EffectWindow *c);
void slotWindowDeleted(KWin::EffectWindow *w);
enum RotationEdge {
Top = 0,
Right = 1,
Bottom = 2,
Left = 3
int duration() const;
RotationEdge inRotationEdge() const;
qreal inRotationAngle() const;
qreal inDistance() const;
qreal inOpacity() const;
RotationEdge outRotationEdge() const;
qreal outRotationAngle() const;
qreal outDistance() const;
qreal outOpacity() const;
private Q_SLOTS:
void windowAdded(EffectWindow *w);
void windowClosed(EffectWindow *w);
void windowDeleted(EffectWindow *w);
void windowDataChanged(EffectWindow *w, int role);
class WindowInfo;
typedef QMap< const EffectWindow*, WindowInfo > InfoHash;
void glideIn(EffectWindow* w, WindowPaintData& data, const InfoHash::const_iterator &info);
void glideOut(EffectWindow* w, WindowPaintData& data, const InfoHash::const_iterator &info);
bool isGlideWindow(EffectWindow* w);
void cancelWindowGrab(EffectWindow *w, int grabRole);
InfoHash windows;
float duration;
int angle;
enum EffectStyle {
GlideIn = 0,
GlideInOut = 1,
GlideOutIn = 2,
GlideOut = 3
bool isGlideWindow(EffectWindow *w) const;
std::chrono::milliseconds m_duration;
QHash<EffectWindow*, TimeLine> m_animations;
struct GlideParams {
RotationEdge edge;
struct {
qreal from;
qreal to;
} angle, distance, opacity;
EffectStyle effect;
GlideParams m_inParams;
GlideParams m_outParams;
class GlideEffect::WindowInfo
inline int GlideEffect::requestedEffectChainPosition() const
bool deleted;
bool added;
bool closed;
QTimeLine *timeLine;
return 50;
inline int GlideEffect::duration() const
return m_duration.count();
inline GlideEffect::RotationEdge GlideEffect::inRotationEdge() const
return m_inParams.edge;
inline qreal GlideEffect::inRotationAngle() const
return m_inParams.angle.from;
inline qreal GlideEffect::inDistance() const
return m_inParams.distance.from;
inline qreal GlideEffect::inOpacity() const
return m_inParams.opacity.from;
inline GlideEffect::RotationEdge GlideEffect::outRotationEdge() const
return m_outParams.edge;
inline qreal GlideEffect::outRotationAngle() const
inline qreal GlideEffect::outDistance() const
inline qreal GlideEffect::outOpacity() const
} // namespace
} // namespace KWin
......@@ -8,11 +8,33 @@
<entry name="Duration" type="UInt">
<entry name="GlideEffect" type="Int">
<entry name="InRotationEdge" type="Int">
<entry name="GlideAngle" type="Int">
<entry name="InRotationAngle" type="Double">
<entry name="InDistance" type="Double">
<entry name="InOpacity" type="Double">
<entry name="OutRotationEdge" type="Int">
<entry name="OutRotationAngle" type="Double">
<entry name="OutDistance" type="Double">
<entry name="OutOpacity" type="Double">
......@@ -55,5 +55,7 @@ void GlideEffectConfig::save()
} // namespace KWin
#include "glide_config.moc"
......@@ -32,10 +32,10 @@ class GlideEffectConfig : public KCModule
explicit GlideEffectConfig(QWidget *parent = 0, const QVariantList& args = QVariantList());
explicit GlideEffectConfig(QWidget *parent = nullptr, const QVariantList &args = QVariantList());
~GlideEffectConfig() override;
void save();
void save() override;
::Ui::GlideEffectConfig ui;
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment