File indexing completed on 2025-03-23 11:13:55
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 ¶meter) 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)