File indexing completed on 2024-05-19 16:34:30

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 <QEasingCurve>
0014 #include <QElapsedTimer>
0015 #include <QtMath>
0016 #include <kwinoffscreeneffect.h>
0017 #include <kwineffects_export.h>
0018 
0019 namespace KWin
0020 {
0021 
0022 class KWINEFFECTS_EXPORT FPx2
0023 {
0024 public:
0025     FPx2()
0026     {
0027         f[0] = f[1] = 0.0;
0028         valid = false;
0029     }
0030     explicit FPx2(float v)
0031     {
0032         f[0] = f[1] = v;
0033         valid = true;
0034     }
0035     FPx2(float v1, float v2)
0036     {
0037         f[0] = v1;
0038         f[1] = v2;
0039         valid = true;
0040     }
0041     FPx2(const FPx2 &other)
0042     {
0043         f[0] = other.f[0];
0044         f[1] = other.f[1];
0045         valid = other.valid;
0046     }
0047     explicit FPx2(const QPoint &other)
0048     {
0049         f[0] = other.x();
0050         f[1] = other.y();
0051         valid = true;
0052     }
0053     explicit FPx2(const QPointF &other)
0054     {
0055         f[0] = other.x();
0056         f[1] = other.y();
0057         valid = true;
0058     }
0059     explicit FPx2(const QSize &other)
0060     {
0061         f[0] = other.width();
0062         f[1] = other.height();
0063         valid = true;
0064     }
0065     explicit FPx2(const QSizeF &other)
0066     {
0067         f[0] = other.width();
0068         f[1] = other.height();
0069         valid = true;
0070     }
0071     inline void invalidate()
0072     {
0073         valid = false;
0074     }
0075     inline bool isValid() const
0076     {
0077         return valid;
0078     }
0079     inline float operator[](int n) const
0080     {
0081         return f[n];
0082     }
0083     inline QString toString() const
0084     {
0085         QString ret;
0086         if (valid) {
0087             ret = QString::number(f[0]) + QLatin1Char(',') + QString::number(f[1]);
0088         } else {
0089             ret = QString();
0090         }
0091         return ret;
0092     }
0093 
0094     inline FPx2 &operator=(const FPx2 &other)
0095     {
0096         f[0] = other.f[0];
0097         f[1] = other.f[1];
0098         valid = other.valid;
0099         return *this;
0100     }
0101     inline FPx2 &operator+=(const FPx2 &other)
0102     {
0103         f[0] += other[0];
0104         f[1] += other[1];
0105         return *this;
0106     }
0107     inline FPx2 &operator-=(const FPx2 &other)
0108     {
0109         f[0] -= other[0];
0110         f[1] -= other[1];
0111         return *this;
0112     }
0113     inline FPx2 &operator*=(float fl)
0114     {
0115         f[0] *= fl;
0116         f[1] *= fl;
0117         return *this;
0118     }
0119     inline FPx2 &operator/=(float fl)
0120     {
0121         f[0] /= fl;
0122         f[1] /= fl;
0123         return *this;
0124     }
0125 
0126     friend inline bool operator==(const FPx2 &f1, const FPx2 &f2)
0127     {
0128         return f1[0] == f2[0] && f1[1] == f2[1];
0129     }
0130     friend inline bool operator!=(const FPx2 &f1, const FPx2 &f2)
0131     {
0132         return f1[0] != f2[0] || f1[1] != f2[1];
0133     }
0134     friend inline const FPx2 operator+(const FPx2 &f1, const FPx2 &f2)
0135     {
0136         return FPx2(f1[0] + f2[0], f1[1] + f2[1]);
0137     }
0138     friend inline const FPx2 operator-(const FPx2 &f1, const FPx2 &f2)
0139     {
0140         return FPx2(f1[0] - f2[0], f1[1] - f2[1]);
0141     }
0142     friend inline const FPx2 operator*(const FPx2 &f, float fl)
0143     {
0144         return FPx2(f[0] * fl, f[1] * fl);
0145     }
0146     friend inline const FPx2 operator*(float fl, const FPx2 &f)
0147     {
0148         return FPx2(f[0] * fl, f[1] * fl);
0149     }
0150     friend inline const FPx2 operator-(const FPx2 &f)
0151     {
0152         return FPx2(-f[0], -f[1]);
0153     }
0154     friend inline const FPx2 operator/(const FPx2 &f, float fl)
0155     {
0156         return FPx2(f[0] / fl, f[1] / fl);
0157     }
0158 
0159     inline void set(float v)
0160     {
0161         f[0] = v;
0162         valid = true;
0163     }
0164     inline void set(float v1, float v2)
0165     {
0166         f[0] = v1;
0167         f[1] = v2;
0168         valid = true;
0169     }
0170 
0171 private:
0172     float f[2];
0173     bool valid;
0174 };
0175 
0176 class AniData;
0177 class AnimationEffectPrivate;
0178 
0179 /**
0180  * Base class for animation effects.
0181  *
0182  * AnimationEffect serves as a base class for animation effects. It makes easier
0183  * implementing animated transitions, without having to worry about low-level
0184  * specific stuff, e.g. referencing and unreferencing deleted windows, scheduling
0185  * repaints for the next frame, etc.
0186  *
0187  * Each animation animates one specific attribute, e.g. size, position, scale, etc.
0188  * You can provide your own implementation of the Generic attribute if none of the
0189  * standard attributes(e.g. size, position, etc) satisfy your requirements.
0190  *
0191  * @since 4.8
0192  */
0193 class KWINEFFECTS_EXPORT AnimationEffect : public CrossFadeEffect
0194 {
0195     Q_OBJECT
0196 
0197 public:
0198     enum Anchor { Left = 1 << 0,
0199                   Top = 1 << 1,
0200                   Right = 1 << 2,
0201                   Bottom = 1 << 3,
0202                   Horizontal = Left | Right,
0203                   Vertical = Top | Bottom,
0204                   Mouse = 1 << 4 };
0205     Q_ENUM(Anchor)
0206 
0207     enum Attribute {
0208         Opacity = 0,
0209         Brightness,
0210         Saturation,
0211         Scale,
0212         Rotation,
0213         Position,
0214         Size,
0215         Translation,
0216         Clip,
0217         Generic,
0218         CrossFadePrevious,
0219         /**
0220          * Performs an animation with a provided shader.
0221          * The float uniform @c animationProgress is set to the current progress of the animation.
0222          **/
0223         Shader,
0224         /**
0225          * Like Shader, but additionally allows to animate a float uniform passed to the shader.
0226          * The uniform location must be provided as metadata.
0227          **/
0228         ShaderUniform,
0229         NonFloatBase = Position
0230     };
0231     Q_ENUM(Attribute)
0232 
0233     enum MetaType { SourceAnchor,
0234                     TargetAnchor,
0235                     RelativeSourceX,
0236                     RelativeSourceY,
0237                     RelativeTargetX,
0238                     RelativeTargetY,
0239                     Axis };
0240     Q_ENUM(MetaType)
0241 
0242     /**
0243      * This enum type is used to specify the direction of the animation.
0244      *
0245      * @since 5.15
0246      */
0247     enum Direction {
0248         Forward, ///< The animation goes from source to target.
0249         Backward ///< The animation goes from target to source.
0250     };
0251     Q_ENUM(Direction)
0252 
0253     /**
0254      * This enum type is used to specify when the animation should be terminated.
0255      *
0256      * @since 5.15
0257      */
0258     enum TerminationFlag {
0259         /**
0260          * Don't terminate the animation when it reaches source or target position.
0261          */
0262         DontTerminate = 0x00,
0263         /**
0264          * Terminate the animation when it reaches the source position. An animation
0265          * can reach the source position if its direction was changed to go backward
0266          * (from target to source).
0267          */
0268         TerminateAtSource = 0x01,
0269         /**
0270          * Terminate the animation when it reaches the target position. If this flag
0271          * is not set, then the animation will be persistent.
0272          */
0273         TerminateAtTarget = 0x02
0274     };
0275     Q_DECLARE_FLAGS(TerminationFlags, TerminationFlag)
0276     Q_FLAG(TerminationFlags)
0277 
0278     /**
0279      * Constructs AnimationEffect.
0280      *
0281      * Whenever you intend to connect to the EffectsHandler::windowClosed() signal,
0282      * do so when reimplementing the constructor. Do not add private slots named
0283      * _windowClosed or _windowDeleted! The AnimationEffect connects them right after
0284      * the construction.
0285      *
0286      * If you shadow the _windowDeleted slot (it doesn't matter that it's a private
0287      * slot), this will lead to segfaults.
0288      *
0289      * If you shadow _windowClosed or connect your slot to EffectsHandler::windowClosed()
0290      * after _windowClosed was connected, animations for closing windows will fail.
0291      */
0292     AnimationEffect();
0293     ~AnimationEffect() override;
0294 
0295     bool isActive() const override;
0296 
0297     /**
0298      * Gets stored metadata.
0299      *
0300      * Metadata can be used to store some extra information, for example rotation axis,
0301      * etc. The first 24 bits are reserved for the AnimationEffect class, you can use
0302      * the last 8 bits for custom hints. In case when you transform a Generic attribute,
0303      * all 32 bits are yours and you can use them as you want and read them in your
0304      * genericAnimation() implementation.
0305      *
0306      * @param type The type of the metadata.
0307      * @param meta Where the metadata is stored.
0308      * @returns Stored metadata.
0309      * @since 4.8
0310      */
0311     static int metaData(MetaType type, uint meta);
0312 
0313     /**
0314      * Sets metadata.
0315      *
0316      * @param type The type of the metadata.
0317      * @param value The data to be stored.
0318      * @param meta Where the metadata will be stored.
0319      * @since 4.8
0320      */
0321     static void setMetaData(MetaType type, uint value, uint &meta);
0322 
0323     // Reimplemented from KWin::Effect.
0324     QString debug(const QString &parameter) const override;
0325     void prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime) override;
0326     void prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std::chrono::milliseconds presentTime) override;
0327     void paintWindow(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 disconnectGeometryChanges();
0514     void updateLayerRepaints();
0515     void validate(Attribute a, uint &meta, FPx2 *from, FPx2 *to, const EffectWindow *w) const;
0516 
0517 private Q_SLOTS:
0518     void init();
0519     void triggerRepaint();
0520     void _windowClosed(KWin::EffectWindow *w);
0521     void _windowDeleted(KWin::EffectWindow *w);
0522     void _windowExpandedGeometryChanged(KWin::EffectWindow *w);
0523 
0524 private:
0525     static QElapsedTimer s_clock;
0526     const std::unique_ptr<AnimationEffectPrivate> d_ptr;
0527     Q_DECLARE_PRIVATE(AnimationEffect)
0528     Q_DISABLE_COPY(AnimationEffect)
0529 };
0530 
0531 } // namespace
0532 
0533 Q_DECLARE_METATYPE(KWin::FPx2)
0534 Q_DECLARE_OPERATORS_FOR_FLAGS(KWin::AnimationEffect::TerminationFlags)