File indexing completed on 2024-11-10 04:57:09

0001 /*
0002     SPDX-FileCopyrightText: 2006 Lubos Lunak <l.lunak@kde.org>
0003     SPDX-FileCopyrightText: 2009 Lucas Murray <lmurray@undefinedfire.com>
0004     SPDX-FileCopyrightText: 2010, 2011 Martin Gräßlin <mgraesslin@kde.org>
0005 
0006     SPDX-License-Identifier: GPL-2.0-or-later
0007 */
0008 
0009 #pragma once
0010 
0011 #include "effect/effecthandler.h"
0012 
0013 namespace KWin
0014 {
0015 
0016 /**
0017  * @internal
0018  */
0019 template<typename T>
0020 class KWIN_EXPORT Motion
0021 {
0022 public:
0023     /**
0024      * Creates a new motion object. "Strength" is the amount of
0025      * acceleration that is applied to the object when the target
0026      * changes and "smoothness" relates to how fast the object
0027      * can change its direction and speed.
0028      */
0029     explicit Motion(T initial, double strength, double smoothness);
0030     /**
0031      * Creates an exact copy of another motion object, including
0032      * position, target and velocity.
0033      */
0034     Motion(const Motion<T> &other);
0035     ~Motion();
0036 
0037     inline T value() const
0038     {
0039         return m_value;
0040     }
0041     inline void setValue(const T value)
0042     {
0043         m_value = value;
0044     }
0045     inline T target() const
0046     {
0047         return m_target;
0048     }
0049     inline void setTarget(const T target)
0050     {
0051         m_start = m_value;
0052         m_target = target;
0053     }
0054     inline T velocity() const
0055     {
0056         return m_velocity;
0057     }
0058     inline void setVelocity(const T velocity)
0059     {
0060         m_velocity = velocity;
0061     }
0062 
0063     inline double strength() const
0064     {
0065         return m_strength;
0066     }
0067     inline void setStrength(const double strength)
0068     {
0069         m_strength = strength;
0070     }
0071     inline double smoothness() const
0072     {
0073         return m_smoothness;
0074     }
0075     inline void setSmoothness(const double smoothness)
0076     {
0077         m_smoothness = smoothness;
0078     }
0079     inline T startValue()
0080     {
0081         return m_start;
0082     }
0083 
0084     /**
0085      * The distance between the current position and the target.
0086      */
0087     inline T distance() const
0088     {
0089         return m_target - m_value;
0090     }
0091 
0092     /**
0093      * Calculates the new position if not at the target. Called
0094      * once per frame only.
0095      */
0096     void calculate(const int msec);
0097     /**
0098      * Place the object on top of the target immediately,
0099      * bypassing all movement calculation.
0100      */
0101     void finish();
0102 
0103 private:
0104     T m_value;
0105     T m_start;
0106     T m_target;
0107     T m_velocity;
0108     double m_strength;
0109     double m_smoothness;
0110 };
0111 
0112 /**
0113  * @short A single 1D motion dynamics object.
0114  *
0115  * This class represents a single object that can be moved around a
0116  * 1D space. Although it can be used directly by itself it is
0117  * recommended to use a motion manager instead.
0118  */
0119 class KWIN_EXPORT Motion1D : public Motion<double>
0120 {
0121 public:
0122     explicit Motion1D(double initial = 0.0, double strength = 0.08, double smoothness = 4.0);
0123     Motion1D(const Motion1D &other);
0124     ~Motion1D();
0125 };
0126 
0127 /**
0128  * @short A single 2D motion dynamics object.
0129  *
0130  * This class represents a single object that can be moved around a
0131  * 2D space. Although it can be used directly by itself it is
0132  * recommended to use a motion manager instead.
0133  */
0134 class KWIN_EXPORT Motion2D : public Motion<QPointF>
0135 {
0136 public:
0137     explicit Motion2D(QPointF initial = QPointF(), double strength = 0.08, double smoothness = 4.0);
0138     Motion2D(const Motion2D &other);
0139     ~Motion2D();
0140 };
0141 
0142 /**
0143  * @short Helper class for motion dynamics in KWin effects.
0144  *
0145  * This motion manager class is intended to help KWin effect authors
0146  * move windows across the screen smoothly and naturally. Once
0147  * windows are registered by the manager the effect can issue move
0148  * commands with the moveWindow() methods. The position of any
0149  * managed window can be determined in realtime by the
0150  * transformedGeometry() method. As the manager knows if any windows
0151  * are moving at any given time it can also be used as a notifier as
0152  * to see whether the effect is active or not.
0153  */
0154 class KWIN_EXPORT WindowMotionManager
0155 {
0156 public:
0157     /**
0158      * Creates a new window manager object.
0159      */
0160     explicit WindowMotionManager(bool useGlobalAnimationModifier = true);
0161     ~WindowMotionManager();
0162 
0163     /**
0164      * Register a window for managing.
0165      */
0166     void manage(EffectWindow *w);
0167     /**
0168      * Register a list of windows for managing.
0169      */
0170     inline void manage(const QList<EffectWindow *> &list)
0171     {
0172         for (int i = 0; i < list.size(); i++) {
0173             manage(list.at(i));
0174         }
0175     }
0176     /**
0177      * Deregister a window. All transformations applied to the
0178      * window will be permanently removed and cannot be recovered.
0179      */
0180     void unmanage(EffectWindow *w);
0181     /**
0182      * Deregister all windows, returning the manager to its
0183      * originally initiated state.
0184      */
0185     void unmanageAll();
0186     /**
0187      * Determine the new positions for windows that have not
0188      * reached their target. Called once per frame, usually in
0189      * prePaintScreen(). Remember to set the
0190      * Effect::PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS flag.
0191      */
0192     void calculate(int time);
0193     /**
0194      * Modify a registered window's paint data to make it appear
0195      * at its real location on the screen. Usually called in
0196      * paintWindow(). Remember to flag the window as having been
0197      * transformed in prePaintWindow() by calling
0198      * WindowPrePaintData::setTransformed()
0199      */
0200     void apply(EffectWindow *w, WindowPaintData &data);
0201     /**
0202      * Set all motion targets and values back to where the
0203      * windows were before transformations. The same as
0204      * unmanaging then remanaging all windows.
0205      */
0206     void reset();
0207     /**
0208      * Resets the motion target and current value of a single
0209      * window.
0210      */
0211     void reset(EffectWindow *w);
0212 
0213     /**
0214      * Ask the manager to move the window to the target position
0215      * with the specified scale. If `yScale` is not provided or
0216      * set to 0.0, `scale` will be used as the scale in the
0217      * vertical direction as well as in the horizontal direction.
0218      */
0219     void moveWindow(EffectWindow *w, QPoint target, double scale = 1.0, double yScale = 0.0);
0220     /**
0221      * This is an overloaded method, provided for convenience.
0222      *
0223      * Ask the manager to move the window to the target rectangle.
0224      * Automatically determines scale.
0225      */
0226     inline void moveWindow(EffectWindow *w, QRect target)
0227     {
0228         // TODO: Scale might be slightly different in the comparison due to rounding
0229         moveWindow(w, target.topLeft(),
0230                    target.width() / double(w->width()), target.height() / double(w->height()));
0231     }
0232 
0233     /**
0234      * Retrieve the current tranformed geometry of a registered
0235      * window.
0236      */
0237     QRectF transformedGeometry(EffectWindow *w) const;
0238     /**
0239      * Sets the current transformed geometry of a registered window to the given geometry.
0240      * @see transformedGeometry
0241      * @since 4.5
0242      */
0243     void setTransformedGeometry(EffectWindow *w, const QRectF &geometry);
0244     /**
0245      * Retrieve the current target geometry of a registered
0246      * window.
0247      */
0248     QRectF targetGeometry(EffectWindow *w) const;
0249     /**
0250      * Return the window that has its transformed geometry under
0251      * the specified point. It is recommended to use the stacking
0252      * order as it's what the user sees, but it is slightly
0253      * slower to process.
0254      */
0255     EffectWindow *windowAtPoint(QPoint point, bool useStackingOrder = true) const;
0256 
0257     /**
0258      * Return a list of all currently registered windows.
0259      */
0260     inline QList<EffectWindow *> managedWindows() const
0261     {
0262         return m_managedWindows.keys();
0263     }
0264     /**
0265      * Returns whether or not a specified window is being managed
0266      * by this manager object.
0267      */
0268     inline bool isManaging(EffectWindow *w) const
0269     {
0270         return m_managedWindows.contains(w);
0271     }
0272     /**
0273      * Returns whether or not this manager object is actually
0274      * managing any windows or not.
0275      */
0276     inline bool managingWindows() const
0277     {
0278         return !m_managedWindows.empty();
0279     }
0280     /**
0281      * Returns whether all windows have reached their targets yet
0282      * or not. Can be used to see if an effect should be
0283      * processed and displayed or not.
0284      */
0285     inline bool areWindowsMoving() const
0286     {
0287         return !m_movingWindowsSet.isEmpty();
0288     }
0289     /**
0290      * Returns whether a window has reached its targets yet
0291      * or not.
0292      */
0293     inline bool isWindowMoving(EffectWindow *w) const
0294     {
0295         return m_movingWindowsSet.contains(w);
0296     }
0297 
0298 private:
0299     bool m_useGlobalAnimationModifier;
0300     struct WindowMotion
0301     {
0302         // TODO: Rotation, etc?
0303         Motion2D translation; // Absolute position
0304         Motion2D scale; // xScale and yScale
0305     };
0306     QHash<EffectWindow *, WindowMotion> m_managedWindows;
0307     QSet<EffectWindow *> m_movingWindowsSet;
0308 };
0309 
0310 template<typename T>
0311 Motion<T>::Motion(T initial, double strength, double smoothness)
0312     : m_value(initial)
0313     , m_start(initial)
0314     , m_target(initial)
0315     , m_velocity()
0316     , m_strength(strength)
0317     , m_smoothness(smoothness)
0318 {
0319 }
0320 
0321 template<typename T>
0322 Motion<T>::Motion(const Motion &other)
0323     : m_value(other.value())
0324     , m_start(other.target())
0325     , m_target(other.target())
0326     , m_velocity(other.velocity())
0327     , m_strength(other.strength())
0328     , m_smoothness(other.smoothness())
0329 {
0330 }
0331 
0332 template<typename T>
0333 Motion<T>::~Motion()
0334 {
0335 }
0336 
0337 template<typename T>
0338 void Motion<T>::calculate(const int msec)
0339 {
0340     if (m_value == m_target && m_velocity == T()) { // At target and not moving
0341         return;
0342     }
0343 
0344     // Poor man's time independent calculation
0345     int steps = std::max(1, msec / 5);
0346     for (int i = 0; i < steps; i++) {
0347         T diff = m_target - m_value;
0348         T strength = diff * m_strength;
0349         m_velocity = (m_smoothness * m_velocity + strength) / (m_smoothness + 1.0);
0350         m_value += m_velocity;
0351     }
0352 }
0353 
0354 template<typename T>
0355 void Motion<T>::finish()
0356 {
0357     m_value = m_target;
0358     m_velocity = T();
0359 }
0360 
0361 } // namespace KWin