File indexing completed on 2024-05-19 05:31:39

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2011 Thomas Lübking <thomas.luebking@web.de>
0006     SPDX-FileCopyrightText: 2018 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
0007 
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 
0011 #pragma once
0012 
0013 #include "kwin_export.h"
0014 
0015 #include "effect/offscreeneffect.h"
0016 #include <QEasingCurve>
0017 #include <QElapsedTimer>
0018 #include <QtMath>
0019 
0020 namespace KWin
0021 {
0022 
0023 class KWIN_EXPORT FPx2
0024 {
0025 public:
0026     FPx2()
0027     {
0028         f[0] = f[1] = 0.0;
0029         valid = false;
0030     }
0031     explicit FPx2(float v)
0032     {
0033         f[0] = f[1] = v;
0034         valid = true;
0035     }
0036     FPx2(float v1, float v2)
0037     {
0038         f[0] = v1;
0039         f[1] = v2;
0040         valid = true;
0041     }
0042     FPx2(const FPx2 &other)
0043     {
0044         f[0] = other.f[0];
0045         f[1] = other.f[1];
0046         valid = other.valid;
0047     }
0048     explicit FPx2(const QPoint &other)
0049     {
0050         f[0] = other.x();
0051         f[1] = other.y();
0052         valid = true;
0053     }
0054     explicit FPx2(const QPointF &other)
0055     {
0056         f[0] = other.x();
0057         f[1] = other.y();
0058         valid = true;
0059     }
0060     explicit FPx2(const QSize &other)
0061     {
0062         f[0] = other.width();
0063         f[1] = other.height();
0064         valid = true;
0065     }
0066     explicit FPx2(const QSizeF &other)
0067     {
0068         f[0] = other.width();
0069         f[1] = other.height();
0070         valid = true;
0071     }
0072     inline void invalidate()
0073     {
0074         valid = false;
0075     }
0076     inline bool isValid() const
0077     {
0078         return valid;
0079     }
0080     inline float operator[](int n) const
0081     {
0082         return f[n];
0083     }
0084     inline QString toString() const
0085     {
0086         QString ret;
0087         if (valid) {
0088             ret = QString::number(f[0]) + QLatin1Char(',') + QString::number(f[1]);
0089         } else {
0090             ret = QString();
0091         }
0092         return ret;
0093     }
0094 
0095     inline FPx2 &operator=(const FPx2 &other)
0096     {
0097         f[0] = other.f[0];
0098         f[1] = other.f[1];
0099         valid = other.valid;
0100         return *this;
0101     }
0102     inline FPx2 &operator+=(const FPx2 &other)
0103     {
0104         f[0] += other[0];
0105         f[1] += other[1];
0106         return *this;
0107     }
0108     inline FPx2 &operator-=(const FPx2 &other)
0109     {
0110         f[0] -= other[0];
0111         f[1] -= other[1];
0112         return *this;
0113     }
0114     inline FPx2 &operator*=(float fl)
0115     {
0116         f[0] *= fl;
0117         f[1] *= fl;
0118         return *this;
0119     }
0120     inline FPx2 &operator/=(float fl)
0121     {
0122         f[0] /= fl;
0123         f[1] /= fl;
0124         return *this;
0125     }
0126 
0127     friend inline bool operator==(const FPx2 &f1, const FPx2 &f2)
0128     {
0129         return f1[0] == f2[0] && f1[1] == f2[1];
0130     }
0131     friend inline bool operator!=(const FPx2 &f1, const FPx2 &f2)
0132     {
0133         return f1[0] != f2[0] || f1[1] != f2[1];
0134     }
0135     friend inline const FPx2 operator+(const FPx2 &f1, const FPx2 &f2)
0136     {
0137         return FPx2(f1[0] + f2[0], f1[1] + f2[1]);
0138     }
0139     friend inline const FPx2 operator-(const FPx2 &f1, const FPx2 &f2)
0140     {
0141         return FPx2(f1[0] - f2[0], f1[1] - f2[1]);
0142     }
0143     friend inline const FPx2 operator*(const FPx2 &f, float fl)
0144     {
0145         return FPx2(f[0] * fl, f[1] * fl);
0146     }
0147     friend inline const FPx2 operator*(float fl, const FPx2 &f)
0148     {
0149         return FPx2(f[0] * fl, f[1] * fl);
0150     }
0151     friend inline const FPx2 operator-(const FPx2 &f)
0152     {
0153         return FPx2(-f[0], -f[1]);
0154     }
0155     friend inline const FPx2 operator/(const FPx2 &f, float fl)
0156     {
0157         return FPx2(f[0] / fl, f[1] / fl);
0158     }
0159 
0160     inline void set(float v)
0161     {
0162         f[0] = v;
0163         valid = true;
0164     }
0165     inline void set(float v1, float v2)
0166     {
0167         f[0] = v1;
0168         f[1] = v2;
0169         valid = true;
0170     }
0171 
0172 private:
0173     float f[2];
0174     bool valid;
0175 };
0176 
0177 class AniData;
0178 class AnimationEffectPrivate;
0179 
0180 /**
0181  * Base class for animation effects.
0182  *
0183  * AnimationEffect serves as a base class for animation effects. It makes easier
0184  * implementing animated transitions, without having to worry about low-level
0185  * specific stuff, e.g. referencing and unreferencing deleted windows, scheduling
0186  * repaints for the next frame, etc.
0187  *
0188  * Each animation animates one specific attribute, e.g. size, position, scale, etc.
0189  * You can provide your own implementation of the Generic attribute if none of the
0190  * standard attributes(e.g. size, position, etc) satisfy your requirements.
0191  *
0192  * @since 4.8
0193  */
0194 class KWIN_EXPORT AnimationEffect : public CrossFadeEffect
0195 {
0196     Q_OBJECT
0197 
0198 public:
0199     enum Anchor { Left = 1 << 0,
0200                   Top = 1 << 1,
0201                   Right = 1 << 2,
0202                   Bottom = 1 << 3,
0203                   Horizontal = Left | Right,
0204                   Vertical = Top | Bottom,
0205                   Mouse = 1 << 4 };
0206     Q_ENUM(Anchor)
0207 
0208     enum Attribute {
0209         Opacity = 0,
0210         Brightness,
0211         Saturation,
0212         Scale,
0213         Rotation,
0214         Position,
0215         Size,
0216         Translation,
0217         Clip,
0218         Generic,
0219         CrossFadePrevious,
0220         /**
0221          * Performs an animation with a provided shader.
0222          * The float uniform @c animationProgress is set to the current progress of the animation.
0223          **/
0224         Shader,
0225         /**
0226          * Like Shader, but additionally allows to animate a float uniform passed to the shader.
0227          * The uniform location must be provided as metadata.
0228          **/
0229         ShaderUniform,
0230         NonFloatBase = Position
0231     };
0232     Q_ENUM(Attribute)
0233 
0234     enum MetaType { SourceAnchor,
0235                     TargetAnchor,
0236                     RelativeSourceX,
0237                     RelativeSourceY,
0238                     RelativeTargetX,
0239                     RelativeTargetY,
0240                     Axis };
0241     Q_ENUM(MetaType)
0242 
0243     /**
0244      * This enum type is used to specify the direction of the animation.
0245      *
0246      * @since 5.15
0247      */
0248     enum Direction {
0249         Forward, ///< The animation goes from source to target.
0250         Backward ///< The animation goes from target to source.
0251     };
0252     Q_ENUM(Direction)
0253 
0254     /**
0255      * This enum type is used to specify when the animation should be terminated.
0256      *
0257      * @since 5.15
0258      */
0259     enum TerminationFlag {
0260         /**
0261          * Don't terminate the animation when it reaches source or target position.
0262          */
0263         DontTerminate = 0x00,
0264         /**
0265          * Terminate the animation when it reaches the source position. An animation
0266          * can reach the source position if its direction was changed to go backward
0267          * (from target to source).
0268          */
0269         TerminateAtSource = 0x01,
0270         /**
0271          * Terminate the animation when it reaches the target position. If this flag
0272          * is not set, then the animation will be persistent.
0273          */
0274         TerminateAtTarget = 0x02
0275     };
0276     Q_DECLARE_FLAGS(TerminationFlags, TerminationFlag)
0277     Q_FLAG(TerminationFlags)
0278 
0279     /**
0280      * Constructs AnimationEffect.
0281      *
0282      * Whenever you intend to connect to the EffectsHandler::windowClosed() signal,
0283      * do so when reimplementing the constructor. Do not add private slots named
0284      * _windowClosed or _windowDeleted! The AnimationEffect connects them right after
0285      * the construction.
0286      *
0287      * If you shadow the _windowDeleted slot (it doesn't matter that it's a private
0288      * slot), this will lead to segfaults.
0289      *
0290      * If you shadow _windowClosed or connect your slot to EffectsHandler::windowClosed()
0291      * after _windowClosed was connected, animations for closing windows will fail.
0292      */
0293     AnimationEffect();
0294     ~AnimationEffect() override;
0295 
0296     bool isActive() const override;
0297 
0298     /**
0299      * Gets stored metadata.
0300      *
0301      * Metadata can be used to store some extra information, for example rotation axis,
0302      * etc. The first 24 bits are reserved for the AnimationEffect class, you can use
0303      * the last 8 bits for custom hints. In case when you transform a Generic attribute,
0304      * all 32 bits are yours and you can use them as you want and read them in your
0305      * genericAnimation() implementation.
0306      *
0307      * @param type The type of the metadata.
0308      * @param meta Where the metadata is stored.
0309      * @returns Stored metadata.
0310      * @since 4.8
0311      */
0312     static int metaData(MetaType type, uint meta);
0313 
0314     /**
0315      * Sets metadata.
0316      *
0317      * @param type The type of the metadata.
0318      * @param value The data to be stored.
0319      * @param meta Where the metadata will be stored.
0320      * @since 4.8
0321      */
0322     static void setMetaData(MetaType type, uint value, uint &meta);
0323 
0324     // Reimplemented from KWin::Effect.
0325     QString debug(const QString &parameter) const override;
0326     void prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std::chrono::milliseconds presentTime) override;
0327     void paintWindow(const RenderTarget &renderTarget, const RenderViewport &viewport, EffectWindow *w, int mask, QRegion region, WindowPaintData &data) override;
0328     void postPaintScreen() override;
0329 
0330     /**
0331      * Gaussian (bumper) animation curve for QEasingCurve.
0332      *
0333      * @since 4.8
0334      */
0335     static qreal qecGaussian(qreal progress)
0336     {
0337         progress = 2 * progress - 1;
0338         progress *= -5 * progress;
0339         return qExp(progress);
0340     }
0341 
0342     /**
0343      * @since 4.8
0344      */
0345     static inline qint64 clock()
0346     {
0347         return s_clock.elapsed();
0348     }
0349 
0350 protected:
0351     /**
0352      * Starts an animated transition of any supported attribute.
0353      *
0354      * @param w The animated window.
0355      * @param a The animated attribute.
0356      * @param meta Basically a wildcard to carry various extra information, e.g.
0357      *   the anchor, relativity or rotation axis. You will probably use it when
0358      *   performing Generic animations.
0359      * @param ms How long the transition will last.
0360      * @param to The target value. FPx2 is an agnostic two component float type
0361      *   (like QPointF or QSizeF, but without requiring to be either and supporting
0362      *   an invalid state).
0363      * @param curve How the animation progresses, e.g. Linear progresses constantly
0364      *   while Exponential start slow and becomes very fast in the end.
0365      * @param delay When the animation will start compared to "now" (the window will
0366      *   remain at the "from" position until then).
0367      * @param from The starting value, the default is invalid, ie. the attribute for
0368      *   the window is not transformed in the beginning.
0369      * @param fullScreen Sets this effect as the active full screen effect for the
0370      *   duration of the animation.
0371      * @param keepAlive Whether closed windows should be kept alive during animation.
0372      * @param shader Optional shader to use to render the window.
0373      * @returns An ID that you can use to cancel a running animation.
0374      * @since 4.8
0375      */
0376     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)
0377     {
0378         return p_animate(w, a, meta, ms, to, curve, delay, from, false, fullScreen, keepAlive, shader);
0379     }
0380 
0381     /**
0382      * Starts a persistent animated transition of any supported attribute.
0383      *
0384      * This method is equal to animate() with one important difference:
0385      * the target value for the attribute is kept until you call cancel().
0386      *
0387      * @param w The animated window.
0388      * @param a The animated attribute.
0389      * @param meta Basically a wildcard to carry various extra information, e.g.
0390      *   the anchor, relativity or rotation axis. You will probably use it when
0391      *   performing Generic animations.
0392      * @param ms How long the transition will last.
0393      * @param to The target value. FPx2 is an agnostic two component float type
0394      *   (like QPointF or QSizeF, but without requiring to be either and supporting
0395      *   an invalid state).
0396      * @param curve How the animation progresses, e.g. Linear progresses constantly
0397      *   while Exponential start slow and becomes very fast in the end.
0398      * @param delay When the animation will start compared to "now" (the window will
0399      *   remain at the "from" position until then).
0400      * @param from The starting value, the default is invalid, ie. the attribute for
0401      *   the window is not transformed in the beginning.
0402      * @param fullScreen Sets this effect as the active full screen effect for the
0403      *   duration of the animation.
0404      * @param keepAlive Whether closed windows should be kept alive during animation.
0405      * @param shader Optional shader to use to render the window.
0406      * @returns An ID that you need to use to cancel this manipulation.
0407      * @since 4.11
0408      */
0409     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)
0410     {
0411         return p_animate(w, a, meta, ms, to, curve, delay, from, true, fullScreen, keepAlive, shader);
0412     }
0413 
0414     /**
0415      * Changes the target (but not type or curve) of a running animation.
0416      *
0417      * Please use cancel() to cancel an animation rather than altering it.
0418      *
0419      * @param animationId The id of the animation to be retargetted.
0420      * @param newTarget The new target.
0421      * @param newRemainingTime The new duration of the transition. By default (-1),
0422      *   the remaining time remains unchanged.
0423      * @returns @c true if the animation was retargetted successfully, @c false otherwise.
0424      * @note You can NOT retarget an animation that just has just ended!
0425      * @since 5.6
0426      */
0427     bool retarget(quint64 animationId, FPx2 newTarget, int newRemainingTime = -1);
0428 
0429     bool freezeInTime(quint64 animationId, qint64 frozenTime);
0430 
0431     /**
0432      * Changes the direction of the animation.
0433      *
0434      * @param animationId The id of the animation.
0435      * @param direction The new direction of the animation.
0436      * @param terminationFlags Whether the animation should be terminated when it
0437      *   reaches the source position after its direction was changed to go backward.
0438      *   Currently, TerminationFlag::TerminateAtTarget has no effect.
0439      * @returns @c true if the direction of the animation was changed successfully,
0440      *   otherwise @c false.
0441      * @since 5.15
0442      */
0443     bool redirect(quint64 animationId,
0444                   Direction direction,
0445                   TerminationFlags terminationFlags = TerminateAtSource);
0446 
0447     /**
0448      * Fast-forwards the animation to the target position.
0449      *
0450      * @param animationId The id of the animation.
0451      * @returns @c true if the animation was fast-forwarded successfully, otherwise
0452      *   @c false.
0453      * @since 5.15
0454      */
0455     bool complete(quint64 animationId);
0456 
0457     /**
0458      * Called whenever an animation ends.
0459      *
0460      * You can reimplement this method to keep a constant transformation for the window
0461      * (i.e. keep it at some opacity or position) or to start another animation.
0462      *
0463      * @param w The animated window.
0464      * @param a The animated attribute.
0465      * @param meta Originally supplied metadata to animate() or set().
0466      * @since 4.8
0467      */
0468     virtual void animationEnded(EffectWindow *w, Attribute a, uint meta);
0469 
0470     /**
0471      * Cancels a running animation.
0472      *
0473      * @param animationId The id of the animation.
0474      * @returns @c true if the animation was found (and canceled), @c false otherwise.
0475      * @note There is NO animated reset of the original value. You'll have to provide
0476      *   that with a second animation.
0477      * @note This will eventually release a Deleted window as well.
0478      * @note If you intend to run another animation on the (Deleted) window, you have
0479      *   to do that before cancelling the old animation (to keep the window around).
0480      * @since 4.11
0481      */
0482     bool cancel(quint64 animationId);
0483 
0484     /**
0485      * Called whenever animation that transforms Generic attribute needs to be painted.
0486      *
0487      * You should reimplement this method if you transform Generic attribute. @p meta
0488      * can be used to support more than one additional animations.
0489      *
0490      * @param w The animated window.
0491      * @param data The paint data.
0492      * @param progress Current progress value.
0493      * @param meta The metadata.
0494      * @since 4.8
0495      */
0496     virtual void genericAnimation(EffectWindow *w, WindowPaintData &data, float progress, uint meta);
0497 
0498     /**
0499      * @internal
0500      */
0501     typedef QMap<EffectWindow *, QPair<QList<AniData>, QRect>> AniMap;
0502 
0503     /**
0504      * @internal
0505      */
0506     AniMap state() const;
0507 
0508 private:
0509     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);
0510     QRect clipRect(const QRect &windowRect, const AniData &) const;
0511     float interpolated(const AniData &, int i = 0) const;
0512     float progress(const AniData &) const;
0513     void updateLayerRepaints();
0514     void validate(Attribute a, uint &meta, FPx2 *from, FPx2 *to, const EffectWindow *w) const;
0515 
0516 private Q_SLOTS:
0517     void init();
0518     void triggerRepaint();
0519     void _windowClosed(KWin::EffectWindow *w);
0520     void _windowDeleted(KWin::EffectWindow *w);
0521     void _windowExpandedGeometryChanged(KWin::EffectWindow *w);
0522 
0523 private:
0524     static QElapsedTimer s_clock;
0525     const std::unique_ptr<AnimationEffectPrivate> d_ptr;
0526     Q_DECLARE_PRIVATE(AnimationEffect)
0527     Q_DISABLE_COPY(AnimationEffect)
0528 };
0529 
0530 } // namespace
0531 
0532 Q_DECLARE_METATYPE(KWin::FPx2)
0533 Q_DECLARE_OPERATORS_FOR_FLAGS(KWin::AnimationEffect::TerminationFlags)