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