You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

533 lines
17 KiB

/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2011 Thomas Lübking <thomas.luebking@web.de>
SPDX-FileCopyrightText: 2018 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include "kwin_export.h"
#include "effect/offscreeneffect.h"
#include <QEasingCurve>
#include <QElapsedTimer>
#include <QtMath>
namespace KWin
{
class KWIN_EXPORT FPx2
{
public:
FPx2()
{
f[0] = f[1] = 0.0;
valid = false;
}
explicit FPx2(float v)
{
f[0] = f[1] = v;
valid = true;
}
FPx2(float v1, float v2)
{
f[0] = v1;
f[1] = v2;
valid = true;
}
FPx2(const FPx2 &other)
{
f[0] = other.f[0];
f[1] = other.f[1];
valid = other.valid;
}
explicit FPx2(const QPoint &other)
{
f[0] = other.x();
f[1] = other.y();
valid = true;
}
explicit FPx2(const QPointF &other)
{
f[0] = other.x();
f[1] = other.y();
valid = true;
}
explicit FPx2(const QSize &other)
{
f[0] = other.width();
f[1] = other.height();
valid = true;
}
explicit FPx2(const QSizeF &other)
{
f[0] = other.width();
f[1] = other.height();
valid = true;
}
inline void invalidate()
{
valid = false;
}
inline bool isValid() const
{
return valid;
}
inline float operator[](int n) const
{
return f[n];
}
inline QString toString() const
{
QString ret;
if (valid) {
ret = QString::number(f[0]) + QLatin1Char(',') + QString::number(f[1]);
} else {
ret = QString();
}
return ret;
}
inline FPx2 &operator=(const FPx2 &other)
{
f[0] = other.f[0];
f[1] = other.f[1];
valid = other.valid;
return *this;
}
inline FPx2 &operator+=(const FPx2 &other)
{
f[0] += other[0];
f[1] += other[1];
return *this;
}
inline FPx2 &operator-=(const FPx2 &other)
{
f[0] -= other[0];
f[1] -= other[1];
return *this;
}
inline FPx2 &operator*=(float fl)
{
f[0] *= fl;
f[1] *= fl;
return *this;
}
inline FPx2 &operator/=(float fl)
{
f[0] /= fl;
f[1] /= fl;
return *this;
}
friend inline bool operator==(const FPx2 &f1, const FPx2 &f2)
{
return f1[0] == f2[0] && f1[1] == f2[1];
}
friend inline bool operator!=(const FPx2 &f1, const FPx2 &f2)
{
return f1[0] != f2[0] || f1[1] != f2[1];
}
friend inline const FPx2 operator+(const FPx2 &f1, const FPx2 &f2)
{
return FPx2(f1[0] + f2[0], f1[1] + f2[1]);
}
friend inline const FPx2 operator-(const FPx2 &f1, const FPx2 &f2)
{
return FPx2(f1[0] - f2[0], f1[1] - f2[1]);
}
friend inline const FPx2 operator*(const FPx2 &f, float fl)
{
return FPx2(f[0] * fl, f[1] * fl);
}
friend inline const FPx2 operator*(float fl, const FPx2 &f)
{
return FPx2(f[0] * fl, f[1] * fl);
}
friend inline const FPx2 operator-(const FPx2 &f)
{
return FPx2(-f[0], -f[1]);
}
friend inline const FPx2 operator/(const FPx2 &f, float fl)
{
return FPx2(f[0] / fl, f[1] / fl);
}
inline void set(float v)
{
f[0] = v;
valid = true;
}
inline void set(float v1, float v2)
{
f[0] = v1;
f[1] = v2;
valid = true;
}
private:
float f[2];
bool valid;
};
class AniData;
class AnimationEffectPrivate;
/**
* Base class for animation effects.
*
* AnimationEffect serves as a base class for animation effects. It makes easier
* implementing animated transitions, without having to worry about low-level
* specific stuff, e.g. referencing and unreferencing deleted windows, scheduling
* repaints for the next frame, etc.
*
* Each animation animates one specific attribute, e.g. size, position, scale, etc.
* You can provide your own implementation of the Generic attribute if none of the
* standard attributes(e.g. size, position, etc) satisfy your requirements.
*
* @since 4.8
*/
class KWIN_EXPORT AnimationEffect : public CrossFadeEffect
{
Q_OBJECT
public:
enum Anchor { Left = 1 << 0,
Top = 1 << 1,
Right = 1 << 2,
Bottom = 1 << 3,
Horizontal = Left | Right,
Vertical = Top | Bottom,
Mouse = 1 << 4 };
Q_ENUM(Anchor)
enum Attribute {
Opacity = 0,
Brightness,
Saturation,
Scale,
Rotation,
Position,
Size,
Translation,
Clip,
Generic,
CrossFadePrevious,
/**
* Performs an animation with a provided shader.
* The float uniform @c animationProgress is set to the current progress of the animation.
**/
Shader,
/**
* Like Shader, but additionally allows to animate a float uniform passed to the shader.
* The uniform location must be provided as metadata.
**/
ShaderUniform,
NonFloatBase = Position
};
Q_ENUM(Attribute)
enum MetaType { SourceAnchor,
TargetAnchor,
RelativeSourceX,
RelativeSourceY,
RelativeTargetX,
RelativeTargetY,
Axis };
Q_ENUM(MetaType)
/**
* This enum type is used to specify the direction of the animation.
*
* @since 5.15
*/
enum Direction {
Forward, ///< The animation goes from source to target.
Backward ///< The animation goes from target to source.
};
Q_ENUM(Direction)
/**
* This enum type is used to specify when the animation should be terminated.
*
* @since 5.15
*/
enum TerminationFlag {
/**
* Don't terminate the animation when it reaches source or target position.
*/
DontTerminate = 0x00,
/**
* Terminate the animation when it reaches the source position. An animation
* can reach the source position if its direction was changed to go backward
* (from target to source).
*/
TerminateAtSource = 0x01,
/**
* Terminate the animation when it reaches the target position. If this flag
* is not set, then the animation will be persistent.
*/
TerminateAtTarget = 0x02
};
Q_DECLARE_FLAGS(TerminationFlags, TerminationFlag)
Q_FLAG(TerminationFlags)
/**
* Constructs AnimationEffect.
*
* Whenever you intend to connect to the EffectsHandler::windowClosed() signal,
* do so when reimplementing the constructor. Do not add private slots named
* _windowClosed or _windowDeleted! The AnimationEffect connects them right after
* the construction.
*
* If you shadow the _windowDeleted slot (it doesn't matter that it's a private
* slot), this will lead to segfaults.
*
* If you shadow _windowClosed or connect your slot to EffectsHandler::windowClosed()
* after _windowClosed was connected, animations for closing windows will fail.
*/
AnimationEffect();
~AnimationEffect() override;
bool isActive() const override;
/**
* Gets stored metadata.
*
* Metadata can be used to store some extra information, for example rotation axis,
* etc. The first 24 bits are reserved for the AnimationEffect class, you can use
* the last 8 bits for custom hints. In case when you transform a Generic attribute,
* all 32 bits are yours and you can use them as you want and read them in your
* genericAnimation() implementation.
*
* @param type The type of the metadata.
* @param meta Where the metadata is stored.
* @returns Stored metadata.
* @since 4.8
*/
static int metaData(MetaType type, uint meta);
/**
* Sets metadata.
*
* @param type The type of the metadata.
* @param value The data to be stored.
* @param meta Where the metadata will be stored.
* @since 4.8
*/
static void setMetaData(MetaType type, uint value, uint &meta);
// Reimplemented from KWin::Effect.
QString debug(const QString &parameter) const override;
void prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std::chrono::milliseconds presentTime) override;
void paintWindow(const RenderTarget &renderTarget, const RenderViewport &viewport, EffectWindow *w, int mask, QRegion region, WindowPaintData &data) override;
void postPaintScreen() override;
/**
* Gaussian (bumper) animation curve for QEasingCurve.
*
* @since 4.8
*/
static qreal qecGaussian(qreal progress)
{
progress = 2 * progress - 1;
progress *= -5 * progress;
return qExp(progress);
}
/**
* @since 4.8
*/
static inline qint64 clock()
{
return s_clock.elapsed();
}
protected:
/**
* Starts an animated transition of any supported attribute.
*
* @param w The animated window.
* @param a The animated attribute.
* @param meta Basically a wildcard to carry various extra information, e.g.
* the anchor, relativity or rotation axis. You will probably use it when
* performing Generic animations.
* @param ms How long the transition will last.
* @param to The target value. FPx2 is an agnostic two component float type
* (like QPointF or QSizeF, but without requiring to be either and supporting
* an invalid state).
* @param curve How the animation progresses, e.g. Linear progresses constantly
* while Exponential start slow and becomes very fast in the end.
* @param delay When the animation will start compared to "now" (the window will
* remain at the "from" position until then).
* @param from The starting value, the default is invalid, ie. the attribute for
* the window is not transformed in the beginning.
* @param fullScreen Sets this effect as the active full screen effect for the
* duration of the animation.
* @param keepAlive Whether closed windows should be kept alive during animation.
* @param shader Optional shader to use to render the window.
* @returns An ID that you can use to cancel a running animation.
* @since 4.8
*/
quint64 animate(EffectWindow *w, Attribute a, uint meta, int ms, const FPx2 &to, const QEasingCurve &curve = QEasingCurve(), int delay = 0, const FPx2 &from = FPx2(), bool fullScreen = false, bool keepAlive = true, GLShader *shader = nullptr)
{
return p_animate(w, a, meta, ms, to, curve, delay, from, false, fullScreen, keepAlive, shader);
}
/**
* Starts a persistent animated transition of any supported attribute.
*
* This method is equal to animate() with one important difference:
* the target value for the attribute is kept until you call cancel().
*
* @param w The animated window.
* @param a The animated attribute.
* @param meta Basically a wildcard to carry various extra information, e.g.
* the anchor, relativity or rotation axis. You will probably use it when
* performing Generic animations.
* @param ms How long the transition will last.
* @param to The target value. FPx2 is an agnostic two component float type
* (like QPointF or QSizeF, but without requiring to be either and supporting
* an invalid state).
* @param curve How the animation progresses, e.g. Linear progresses constantly
* while Exponential start slow and becomes very fast in the end.
* @param delay When the animation will start compared to "now" (the window will
* remain at the "from" position until then).
* @param from The starting value, the default is invalid, ie. the attribute for
* the window is not transformed in the beginning.
* @param fullScreen Sets this effect as the active full screen effect for the
* duration of the animation.
* @param keepAlive Whether closed windows should be kept alive during animation.
* @param shader Optional shader to use to render the window.
* @returns An ID that you need to use to cancel this manipulation.
* @since 4.11
*/
quint64 set(EffectWindow *w, Attribute a, uint meta, int ms, const FPx2 &to, const QEasingCurve &curve = QEasingCurve(), int delay = 0, const FPx2 &from = FPx2(), bool fullScreen = false, bool keepAlive = true, GLShader *shader = nullptr)
{
return p_animate(w, a, meta, ms, to, curve, delay, from, true, fullScreen, keepAlive, shader);
}
/**
* Changes the target (but not type or curve) of a running animation.
*
* Please use cancel() to cancel an animation rather than altering it.
*
* @param animationId The id of the animation to be retargetted.
* @param newTarget The new target.
* @param newRemainingTime The new duration of the transition. By default (-1),
* the remaining time remains unchanged.
* @returns @c true if the animation was retargetted successfully, @c false otherwise.
* @note You can NOT retarget an animation that just has just ended!
* @since 5.6
*/
bool retarget(quint64 animationId, FPx2 newTarget, int newRemainingTime = -1);
bool freezeInTime(quint64 animationId, qint64 frozenTime);
/**
* Changes the direction of the animation.
*
* @param animationId The id of the animation.
* @param direction The new direction of the animation.
* @param terminationFlags Whether the animation should be terminated when it
* reaches the source position after its direction was changed to go backward.
* Currently, TerminationFlag::TerminateAtTarget has no effect.
* @returns @c true if the direction of the animation was changed successfully,
* otherwise @c false.
* @since 5.15
*/
bool redirect(quint64 animationId,
Direction direction,
TerminationFlags terminationFlags = TerminateAtSource);
/**
* Fast-forwards the animation to the target position.
*
* @param animationId The id of the animation.
* @returns @c true if the animation was fast-forwarded successfully, otherwise
* @c false.
* @since 5.15
*/
bool complete(quint64 animationId);
/**
* Called whenever an animation ends.
*
* You can reimplement this method to keep a constant transformation for the window
* (i.e. keep it at some opacity or position) or to start another animation.
*
* @param w The animated window.
* @param a The animated attribute.
* @param meta Originally supplied metadata to animate() or set().
* @since 4.8
*/
virtual void animationEnded(EffectWindow *w, Attribute a, uint meta);
/**
* Cancels a running animation.
*
* @param animationId The id of the animation.
* @returns @c true if the animation was found (and canceled), @c false otherwise.
* @note There is NO animated reset of the original value. You'll have to provide
* that with a second animation.
* @note This will eventually release a Deleted window as well.
* @note If you intend to run another animation on the (Deleted) window, you have
* to do that before cancelling the old animation (to keep the window around).
* @since 4.11
*/
bool cancel(quint64 animationId);
/**
* Called whenever animation that transforms Generic attribute needs to be painted.
*
* You should reimplement this method if you transform Generic attribute. @p meta
* can be used to support more than one additional animations.
*
* @param w The animated window.
* @param data The paint data.
* @param progress Current progress value.
* @param meta The metadata.
* @since 4.8
*/
virtual void genericAnimation(EffectWindow *w, WindowPaintData &data, float progress, uint meta);
/**
* @internal
*/
typedef QMap<EffectWindow *, QPair<QList<AniData>, QRect>> AniMap;
/**
* @internal
*/
AniMap state() const;
private:
quint64 p_animate(EffectWindow *w, Attribute a, uint meta, int ms, FPx2 to, const QEasingCurve &curve, int delay, FPx2 from, bool keepAtTarget, bool fullScreenEffect, bool keepAlive, GLShader *shader);
QRect clipRect(const QRect &windowRect, const AniData &) const;
float interpolated(const AniData &, int i = 0) const;
float progress(const AniData &) const;
void updateLayerRepaints();
void validate(Attribute a, uint &meta, FPx2 *from, FPx2 *to, const EffectWindow *w) const;
private Q_SLOTS:
void init();
void triggerRepaint();
void _windowClosed(KWin::EffectWindow *w);
void _windowDeleted(KWin::EffectWindow *w);
void _windowExpandedGeometryChanged(KWin::EffectWindow *w);
private:
static QElapsedTimer s_clock;
const std::unique_ptr<AnimationEffectPrivate> d_ptr;
Q_DECLARE_PRIVATE(AnimationEffect)
Q_DISABLE_COPY(AnimationEffect)
};
} // namespace
Q_DECLARE_METATYPE(KWin::FPx2)
Q_DECLARE_OPERATORS_FOR_FLAGS(KWin::AnimationEffect::TerminationFlags)