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 ¶meter) 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)