Move window motion manager to the slideback effect
Slide back is the only remaining its user.
This commit is contained in:
parent
b0292fc0de
commit
96e979c736
6 changed files with 649 additions and 623 deletions
|
@ -2412,276 +2412,6 @@ void RenderGeometry::postProcessTextureCoordinates(const QMatrix4x4 &textureMatr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************************
|
|
||||||
Motion1D
|
|
||||||
***************************************************************/
|
|
||||||
|
|
||||||
Motion1D::Motion1D(double initial, double strength, double smoothness)
|
|
||||||
: Motion<double>(initial, strength, smoothness)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Motion1D::Motion1D(const Motion1D &other)
|
|
||||||
: Motion<double>(other)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Motion1D::~Motion1D()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/***************************************************************
|
|
||||||
Motion2D
|
|
||||||
***************************************************************/
|
|
||||||
|
|
||||||
Motion2D::Motion2D(QPointF initial, double strength, double smoothness)
|
|
||||||
: Motion<QPointF>(initial, strength, smoothness)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Motion2D::Motion2D(const Motion2D &other)
|
|
||||||
: Motion<QPointF>(other)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Motion2D::~Motion2D()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/***************************************************************
|
|
||||||
WindowMotionManager
|
|
||||||
***************************************************************/
|
|
||||||
|
|
||||||
WindowMotionManager::WindowMotionManager(bool useGlobalAnimationModifier)
|
|
||||||
: m_useGlobalAnimationModifier(useGlobalAnimationModifier)
|
|
||||||
|
|
||||||
{
|
|
||||||
// TODO: Allow developer to modify motion attributes
|
|
||||||
} // TODO: What happens when the window moves by an external force?
|
|
||||||
|
|
||||||
WindowMotionManager::~WindowMotionManager()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void WindowMotionManager::manage(EffectWindow *w)
|
|
||||||
{
|
|
||||||
if (m_managedWindows.contains(w)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
double strength = 0.08;
|
|
||||||
double smoothness = 4.0;
|
|
||||||
if (m_useGlobalAnimationModifier && effects->animationTimeFactor()) {
|
|
||||||
// If the factor is == 0 then we just skip the calculation completely
|
|
||||||
strength = 0.08 / effects->animationTimeFactor();
|
|
||||||
smoothness = effects->animationTimeFactor() * 4.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
WindowMotion &motion = m_managedWindows[w];
|
|
||||||
motion.translation.setStrength(strength);
|
|
||||||
motion.translation.setSmoothness(smoothness);
|
|
||||||
motion.scale.setStrength(strength * 1.33);
|
|
||||||
motion.scale.setSmoothness(smoothness / 2.0);
|
|
||||||
|
|
||||||
motion.translation.setValue(w->pos());
|
|
||||||
motion.scale.setValue(QPointF(1.0, 1.0));
|
|
||||||
}
|
|
||||||
|
|
||||||
void WindowMotionManager::unmanage(EffectWindow *w)
|
|
||||||
{
|
|
||||||
m_movingWindowsSet.remove(w);
|
|
||||||
m_managedWindows.remove(w);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WindowMotionManager::unmanageAll()
|
|
||||||
{
|
|
||||||
m_managedWindows.clear();
|
|
||||||
m_movingWindowsSet.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WindowMotionManager::calculate(int time)
|
|
||||||
{
|
|
||||||
if (!effects->animationTimeFactor()) {
|
|
||||||
// Just skip it completely if the user wants no animation
|
|
||||||
m_movingWindowsSet.clear();
|
|
||||||
QHash<EffectWindow *, WindowMotion>::iterator it = m_managedWindows.begin();
|
|
||||||
for (; it != m_managedWindows.end(); ++it) {
|
|
||||||
WindowMotion *motion = &it.value();
|
|
||||||
motion->translation.finish();
|
|
||||||
motion->scale.finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QHash<EffectWindow *, WindowMotion>::iterator it = m_managedWindows.begin();
|
|
||||||
for (; it != m_managedWindows.end(); ++it) {
|
|
||||||
WindowMotion *motion = &it.value();
|
|
||||||
int stopped = 0;
|
|
||||||
|
|
||||||
// TODO: What happens when distance() == 0 but we are still moving fast?
|
|
||||||
// TODO: Motion needs to be calculated from the window's center
|
|
||||||
|
|
||||||
Motion2D *trans = &motion->translation;
|
|
||||||
if (trans->distance().isNull()) {
|
|
||||||
++stopped;
|
|
||||||
} else {
|
|
||||||
// Still moving
|
|
||||||
trans->calculate(time);
|
|
||||||
const short fx = trans->target().x() <= trans->startValue().x() ? -1 : 1;
|
|
||||||
const short fy = trans->target().y() <= trans->startValue().y() ? -1 : 1;
|
|
||||||
if (trans->distance().x() * fx / 0.5 < 1.0 && trans->velocity().x() * fx / 0.2 < 1.0
|
|
||||||
&& trans->distance().y() * fy / 0.5 < 1.0 && trans->velocity().y() * fy / 0.2 < 1.0) {
|
|
||||||
// Hide tiny oscillations
|
|
||||||
motion->translation.finish();
|
|
||||||
++stopped;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Motion2D *scale = &motion->scale;
|
|
||||||
if (scale->distance().isNull()) {
|
|
||||||
++stopped;
|
|
||||||
} else {
|
|
||||||
// Still scaling
|
|
||||||
scale->calculate(time);
|
|
||||||
const short fx = scale->target().x() < 1.0 ? -1 : 1;
|
|
||||||
const short fy = scale->target().y() < 1.0 ? -1 : 1;
|
|
||||||
if (scale->distance().x() * fx / 0.001 < 1.0 && scale->velocity().x() * fx / 0.05 < 1.0
|
|
||||||
&& scale->distance().y() * fy / 0.001 < 1.0 && scale->velocity().y() * fy / 0.05 < 1.0) {
|
|
||||||
// Hide tiny oscillations
|
|
||||||
motion->scale.finish();
|
|
||||||
++stopped;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We just finished this window's motion
|
|
||||||
if (stopped == 2) {
|
|
||||||
m_movingWindowsSet.remove(it.key());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WindowMotionManager::reset()
|
|
||||||
{
|
|
||||||
QHash<EffectWindow *, WindowMotion>::iterator it = m_managedWindows.begin();
|
|
||||||
for (; it != m_managedWindows.end(); ++it) {
|
|
||||||
WindowMotion *motion = &it.value();
|
|
||||||
EffectWindow *window = it.key();
|
|
||||||
motion->translation.setTarget(window->pos());
|
|
||||||
motion->translation.finish();
|
|
||||||
motion->scale.setTarget(QPointF(1.0, 1.0));
|
|
||||||
motion->scale.finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WindowMotionManager::reset(EffectWindow *w)
|
|
||||||
{
|
|
||||||
QHash<EffectWindow *, WindowMotion>::iterator it = m_managedWindows.find(w);
|
|
||||||
if (it == m_managedWindows.end()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
WindowMotion *motion = &it.value();
|
|
||||||
motion->translation.setTarget(w->pos());
|
|
||||||
motion->translation.finish();
|
|
||||||
motion->scale.setTarget(QPointF(1.0, 1.0));
|
|
||||||
motion->scale.finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WindowMotionManager::apply(EffectWindow *w, WindowPaintData &data)
|
|
||||||
{
|
|
||||||
QHash<EffectWindow *, WindowMotion>::iterator it = m_managedWindows.find(w);
|
|
||||||
if (it == m_managedWindows.end()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Take into account existing scale so that we can work with multiple managers (E.g. Present windows + grid)
|
|
||||||
WindowMotion *motion = &it.value();
|
|
||||||
data += (motion->translation.value() - QPointF(w->x(), w->y()));
|
|
||||||
data *= QVector2D(motion->scale.value());
|
|
||||||
}
|
|
||||||
|
|
||||||
void WindowMotionManager::moveWindow(EffectWindow *w, QPoint target, double scale, double yScale)
|
|
||||||
{
|
|
||||||
QHash<EffectWindow *, WindowMotion>::iterator it = m_managedWindows.find(w);
|
|
||||||
Q_ASSERT(it != m_managedWindows.end()); // Notify the effect author that they did something wrong
|
|
||||||
|
|
||||||
WindowMotion *motion = &it.value();
|
|
||||||
|
|
||||||
if (yScale == 0.0) {
|
|
||||||
yScale = scale;
|
|
||||||
}
|
|
||||||
QPointF scalePoint(scale, yScale);
|
|
||||||
|
|
||||||
if (motion->translation.value() == target && motion->scale.value() == scalePoint) {
|
|
||||||
return; // Window already at that position
|
|
||||||
}
|
|
||||||
|
|
||||||
motion->translation.setTarget(target);
|
|
||||||
motion->scale.setTarget(scalePoint);
|
|
||||||
|
|
||||||
m_movingWindowsSet << w;
|
|
||||||
}
|
|
||||||
|
|
||||||
QRectF WindowMotionManager::transformedGeometry(EffectWindow *w) const
|
|
||||||
{
|
|
||||||
QHash<EffectWindow *, WindowMotion>::const_iterator it = m_managedWindows.constFind(w);
|
|
||||||
if (it == m_managedWindows.end()) {
|
|
||||||
return w->frameGeometry();
|
|
||||||
}
|
|
||||||
|
|
||||||
const WindowMotion *motion = &it.value();
|
|
||||||
QRectF geometry(w->frameGeometry());
|
|
||||||
|
|
||||||
// TODO: Take into account existing scale so that we can work with multiple managers (E.g. Present windows + grid)
|
|
||||||
geometry.moveTo(motion->translation.value());
|
|
||||||
geometry.setWidth(geometry.width() * motion->scale.value().x());
|
|
||||||
geometry.setHeight(geometry.height() * motion->scale.value().y());
|
|
||||||
|
|
||||||
return geometry;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WindowMotionManager::setTransformedGeometry(EffectWindow *w, const QRectF &geometry)
|
|
||||||
{
|
|
||||||
QHash<EffectWindow *, WindowMotion>::iterator it = m_managedWindows.find(w);
|
|
||||||
if (it == m_managedWindows.end()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
WindowMotion *motion = &it.value();
|
|
||||||
motion->translation.setValue(geometry.topLeft());
|
|
||||||
motion->scale.setValue(QPointF(geometry.width() / qreal(w->width()), geometry.height() / qreal(w->height())));
|
|
||||||
}
|
|
||||||
|
|
||||||
QRectF WindowMotionManager::targetGeometry(EffectWindow *w) const
|
|
||||||
{
|
|
||||||
QHash<EffectWindow *, WindowMotion>::const_iterator it = m_managedWindows.constFind(w);
|
|
||||||
if (it == m_managedWindows.end()) {
|
|
||||||
return w->frameGeometry();
|
|
||||||
}
|
|
||||||
|
|
||||||
const WindowMotion *motion = &it.value();
|
|
||||||
QRectF geometry(w->frameGeometry());
|
|
||||||
|
|
||||||
// TODO: Take into account existing scale so that we can work with multiple managers (E.g. Present windows + grid)
|
|
||||||
geometry.moveTo(motion->translation.target());
|
|
||||||
geometry.setWidth(geometry.width() * motion->scale.target().x());
|
|
||||||
geometry.setHeight(geometry.height() * motion->scale.target().y());
|
|
||||||
|
|
||||||
return geometry;
|
|
||||||
}
|
|
||||||
|
|
||||||
EffectWindow *WindowMotionManager::windowAtPoint(QPoint point, bool useStackingOrder) const
|
|
||||||
{
|
|
||||||
// TODO: Stacking order uses EffectsHandler::stackingOrder() then filters by m_managedWindows
|
|
||||||
QHash<EffectWindow *, WindowMotion>::ConstIterator it = m_managedWindows.constBegin();
|
|
||||||
while (it != m_managedWindows.constEnd()) {
|
|
||||||
if (exclusiveContains(transformedGeometry(it.key()), point)) {
|
|
||||||
return it.key();
|
|
||||||
}
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
#include "moc_effects.cpp"
|
#include "moc_effects.cpp"
|
||||||
|
|
|
@ -2294,300 +2294,6 @@ private:
|
||||||
VertexSnappingMode m_vertexSnappingMode = VertexSnappingMode::Round;
|
VertexSnappingMode m_vertexSnappingMode = VertexSnappingMode::Round;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
template<typename T>
|
|
||||||
class KWIN_EXPORT Motion
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Creates a new motion object. "Strength" is the amount of
|
|
||||||
* acceleration that is applied to the object when the target
|
|
||||||
* changes and "smoothness" relates to how fast the object
|
|
||||||
* can change its direction and speed.
|
|
||||||
*/
|
|
||||||
explicit Motion(T initial, double strength, double smoothness);
|
|
||||||
/**
|
|
||||||
* Creates an exact copy of another motion object, including
|
|
||||||
* position, target and velocity.
|
|
||||||
*/
|
|
||||||
Motion(const Motion<T> &other);
|
|
||||||
~Motion();
|
|
||||||
|
|
||||||
inline T value() const
|
|
||||||
{
|
|
||||||
return m_value;
|
|
||||||
}
|
|
||||||
inline void setValue(const T value)
|
|
||||||
{
|
|
||||||
m_value = value;
|
|
||||||
}
|
|
||||||
inline T target() const
|
|
||||||
{
|
|
||||||
return m_target;
|
|
||||||
}
|
|
||||||
inline void setTarget(const T target)
|
|
||||||
{
|
|
||||||
m_start = m_value;
|
|
||||||
m_target = target;
|
|
||||||
}
|
|
||||||
inline T velocity() const
|
|
||||||
{
|
|
||||||
return m_velocity;
|
|
||||||
}
|
|
||||||
inline void setVelocity(const T velocity)
|
|
||||||
{
|
|
||||||
m_velocity = velocity;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline double strength() const
|
|
||||||
{
|
|
||||||
return m_strength;
|
|
||||||
}
|
|
||||||
inline void setStrength(const double strength)
|
|
||||||
{
|
|
||||||
m_strength = strength;
|
|
||||||
}
|
|
||||||
inline double smoothness() const
|
|
||||||
{
|
|
||||||
return m_smoothness;
|
|
||||||
}
|
|
||||||
inline void setSmoothness(const double smoothness)
|
|
||||||
{
|
|
||||||
m_smoothness = smoothness;
|
|
||||||
}
|
|
||||||
inline T startValue()
|
|
||||||
{
|
|
||||||
return m_start;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The distance between the current position and the target.
|
|
||||||
*/
|
|
||||||
inline T distance() const
|
|
||||||
{
|
|
||||||
return m_target - m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the new position if not at the target. Called
|
|
||||||
* once per frame only.
|
|
||||||
*/
|
|
||||||
void calculate(const int msec);
|
|
||||||
/**
|
|
||||||
* Place the object on top of the target immediately,
|
|
||||||
* bypassing all movement calculation.
|
|
||||||
*/
|
|
||||||
void finish();
|
|
||||||
|
|
||||||
private:
|
|
||||||
T m_value;
|
|
||||||
T m_start;
|
|
||||||
T m_target;
|
|
||||||
T m_velocity;
|
|
||||||
double m_strength;
|
|
||||||
double m_smoothness;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @short A single 1D motion dynamics object.
|
|
||||||
*
|
|
||||||
* This class represents a single object that can be moved around a
|
|
||||||
* 1D space. Although it can be used directly by itself it is
|
|
||||||
* recommended to use a motion manager instead.
|
|
||||||
*/
|
|
||||||
class KWIN_EXPORT Motion1D : public Motion<double>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit Motion1D(double initial = 0.0, double strength = 0.08, double smoothness = 4.0);
|
|
||||||
Motion1D(const Motion1D &other);
|
|
||||||
~Motion1D();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @short A single 2D motion dynamics object.
|
|
||||||
*
|
|
||||||
* This class represents a single object that can be moved around a
|
|
||||||
* 2D space. Although it can be used directly by itself it is
|
|
||||||
* recommended to use a motion manager instead.
|
|
||||||
*/
|
|
||||||
class KWIN_EXPORT Motion2D : public Motion<QPointF>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit Motion2D(QPointF initial = QPointF(), double strength = 0.08, double smoothness = 4.0);
|
|
||||||
Motion2D(const Motion2D &other);
|
|
||||||
~Motion2D();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @short Helper class for motion dynamics in KWin effects.
|
|
||||||
*
|
|
||||||
* This motion manager class is intended to help KWin effect authors
|
|
||||||
* move windows across the screen smoothly and naturally. Once
|
|
||||||
* windows are registered by the manager the effect can issue move
|
|
||||||
* commands with the moveWindow() methods. The position of any
|
|
||||||
* managed window can be determined in realtime by the
|
|
||||||
* transformedGeometry() method. As the manager knows if any windows
|
|
||||||
* are moving at any given time it can also be used as a notifier as
|
|
||||||
* to see whether the effect is active or not.
|
|
||||||
*/
|
|
||||||
class KWIN_EXPORT WindowMotionManager
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Creates a new window manager object.
|
|
||||||
*/
|
|
||||||
explicit WindowMotionManager(bool useGlobalAnimationModifier = true);
|
|
||||||
~WindowMotionManager();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a window for managing.
|
|
||||||
*/
|
|
||||||
void manage(EffectWindow *w);
|
|
||||||
/**
|
|
||||||
* Register a list of windows for managing.
|
|
||||||
*/
|
|
||||||
inline void manage(const EffectWindowList &list)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < list.size(); i++) {
|
|
||||||
manage(list.at(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Deregister a window. All transformations applied to the
|
|
||||||
* window will be permanently removed and cannot be recovered.
|
|
||||||
*/
|
|
||||||
void unmanage(EffectWindow *w);
|
|
||||||
/**
|
|
||||||
* Deregister all windows, returning the manager to its
|
|
||||||
* originally initiated state.
|
|
||||||
*/
|
|
||||||
void unmanageAll();
|
|
||||||
/**
|
|
||||||
* Determine the new positions for windows that have not
|
|
||||||
* reached their target. Called once per frame, usually in
|
|
||||||
* prePaintScreen(). Remember to set the
|
|
||||||
* Effect::PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS flag.
|
|
||||||
*/
|
|
||||||
void calculate(int time);
|
|
||||||
/**
|
|
||||||
* Modify a registered window's paint data to make it appear
|
|
||||||
* at its real location on the screen. Usually called in
|
|
||||||
* paintWindow(). Remember to flag the window as having been
|
|
||||||
* transformed in prePaintWindow() by calling
|
|
||||||
* WindowPrePaintData::setTransformed()
|
|
||||||
*/
|
|
||||||
void apply(EffectWindow *w, WindowPaintData &data);
|
|
||||||
/**
|
|
||||||
* Set all motion targets and values back to where the
|
|
||||||
* windows were before transformations. The same as
|
|
||||||
* unmanaging then remanaging all windows.
|
|
||||||
*/
|
|
||||||
void reset();
|
|
||||||
/**
|
|
||||||
* Resets the motion target and current value of a single
|
|
||||||
* window.
|
|
||||||
*/
|
|
||||||
void reset(EffectWindow *w);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ask the manager to move the window to the target position
|
|
||||||
* with the specified scale. If `yScale` is not provided or
|
|
||||||
* set to 0.0, `scale` will be used as the scale in the
|
|
||||||
* vertical direction as well as in the horizontal direction.
|
|
||||||
*/
|
|
||||||
void moveWindow(EffectWindow *w, QPoint target, double scale = 1.0, double yScale = 0.0);
|
|
||||||
/**
|
|
||||||
* This is an overloaded method, provided for convenience.
|
|
||||||
*
|
|
||||||
* Ask the manager to move the window to the target rectangle.
|
|
||||||
* Automatically determines scale.
|
|
||||||
*/
|
|
||||||
inline void moveWindow(EffectWindow *w, QRect target)
|
|
||||||
{
|
|
||||||
// TODO: Scale might be slightly different in the comparison due to rounding
|
|
||||||
moveWindow(w, target.topLeft(),
|
|
||||||
target.width() / double(w->width()), target.height() / double(w->height()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the current tranformed geometry of a registered
|
|
||||||
* window.
|
|
||||||
*/
|
|
||||||
QRectF transformedGeometry(EffectWindow *w) const;
|
|
||||||
/**
|
|
||||||
* Sets the current transformed geometry of a registered window to the given geometry.
|
|
||||||
* @see transformedGeometry
|
|
||||||
* @since 4.5
|
|
||||||
*/
|
|
||||||
void setTransformedGeometry(EffectWindow *w, const QRectF &geometry);
|
|
||||||
/**
|
|
||||||
* Retrieve the current target geometry of a registered
|
|
||||||
* window.
|
|
||||||
*/
|
|
||||||
QRectF targetGeometry(EffectWindow *w) const;
|
|
||||||
/**
|
|
||||||
* Return the window that has its transformed geometry under
|
|
||||||
* the specified point. It is recommended to use the stacking
|
|
||||||
* order as it's what the user sees, but it is slightly
|
|
||||||
* slower to process.
|
|
||||||
*/
|
|
||||||
EffectWindow *windowAtPoint(QPoint point, bool useStackingOrder = true) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a list of all currently registered windows.
|
|
||||||
*/
|
|
||||||
inline EffectWindowList managedWindows() const
|
|
||||||
{
|
|
||||||
return m_managedWindows.keys();
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Returns whether or not a specified window is being managed
|
|
||||||
* by this manager object.
|
|
||||||
*/
|
|
||||||
inline bool isManaging(EffectWindow *w) const
|
|
||||||
{
|
|
||||||
return m_managedWindows.contains(w);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Returns whether or not this manager object is actually
|
|
||||||
* managing any windows or not.
|
|
||||||
*/
|
|
||||||
inline bool managingWindows() const
|
|
||||||
{
|
|
||||||
return !m_managedWindows.empty();
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Returns whether all windows have reached their targets yet
|
|
||||||
* or not. Can be used to see if an effect should be
|
|
||||||
* processed and displayed or not.
|
|
||||||
*/
|
|
||||||
inline bool areWindowsMoving() const
|
|
||||||
{
|
|
||||||
return !m_movingWindowsSet.isEmpty();
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Returns whether a window has reached its targets yet
|
|
||||||
* or not.
|
|
||||||
*/
|
|
||||||
inline bool isWindowMoving(EffectWindow *w) const
|
|
||||||
{
|
|
||||||
return m_movingWindowsSet.contains(w);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool m_useGlobalAnimationModifier;
|
|
||||||
struct WindowMotion
|
|
||||||
{
|
|
||||||
// TODO: Rotation, etc?
|
|
||||||
Motion2D translation; // Absolute position
|
|
||||||
Motion2D scale; // xScale and yScale
|
|
||||||
};
|
|
||||||
QHash<EffectWindow *, WindowMotion> m_managedWindows;
|
|
||||||
QSet<EffectWindow *> m_movingWindowsSet;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pointer to the global EffectsHandler object.
|
* Pointer to the global EffectsHandler object.
|
||||||
*/
|
*/
|
||||||
|
@ -2682,61 +2388,6 @@ inline QRectF WindowQuad::bounds() const
|
||||||
return QRectF(QPointF(left(), top()), QPointF(right(), bottom()));
|
return QRectF(QPointF(left(), top()), QPointF(right(), bottom()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************************
|
|
||||||
Motion
|
|
||||||
***************************************************************/
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
Motion<T>::Motion(T initial, double strength, double smoothness)
|
|
||||||
: m_value(initial)
|
|
||||||
, m_start(initial)
|
|
||||||
, m_target(initial)
|
|
||||||
, m_velocity()
|
|
||||||
, m_strength(strength)
|
|
||||||
, m_smoothness(smoothness)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
Motion<T>::Motion(const Motion &other)
|
|
||||||
: m_value(other.value())
|
|
||||||
, m_start(other.target())
|
|
||||||
, m_target(other.target())
|
|
||||||
, m_velocity(other.velocity())
|
|
||||||
, m_strength(other.strength())
|
|
||||||
, m_smoothness(other.smoothness())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
Motion<T>::~Motion()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
void Motion<T>::calculate(const int msec)
|
|
||||||
{
|
|
||||||
if (m_value == m_target && m_velocity == T()) { // At target and not moving
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Poor man's time independent calculation
|
|
||||||
int steps = std::max(1, msec / 5);
|
|
||||||
for (int i = 0; i < steps; i++) {
|
|
||||||
T diff = m_target - m_value;
|
|
||||||
T strength = diff * m_strength;
|
|
||||||
m_velocity = (m_smoothness * m_velocity + strength) / (m_smoothness + 1.0);
|
|
||||||
m_value += m_velocity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
void Motion<T>::finish()
|
|
||||||
{
|
|
||||||
m_value = m_target;
|
|
||||||
m_velocity = T();
|
|
||||||
}
|
|
||||||
|
|
||||||
/***************************************************************
|
/***************************************************************
|
||||||
EffectWindow
|
EffectWindow
|
||||||
***************************************************************/
|
***************************************************************/
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
#######################################
|
#######################################
|
||||||
# Effect
|
# Effect
|
||||||
|
|
||||||
# Source files
|
kwin_add_builtin_effect(slideback)
|
||||||
set(slideback_SOURCES
|
target_sources(slideback PRIVATE
|
||||||
main.cpp
|
main.cpp
|
||||||
|
motionmanager.cpp
|
||||||
slideback.cpp
|
slideback.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
kwin_add_builtin_effect(slideback ${slideback_SOURCES})
|
|
||||||
target_link_libraries(slideback PRIVATE
|
target_link_libraries(slideback PRIVATE
|
||||||
kwin
|
kwin
|
||||||
)
|
)
|
||||||
|
|
284
src/plugins/slideback/motionmanager.cpp
Normal file
284
src/plugins/slideback/motionmanager.cpp
Normal file
|
@ -0,0 +1,284 @@
|
||||||
|
/*
|
||||||
|
SPDX-FileCopyrightText: 2006 Lubos Lunak <l.lunak@kde.org>
|
||||||
|
SPDX-FileCopyrightText: 2009 Lucas Murray <lmurray@undefinedfire.com>
|
||||||
|
SPDX-FileCopyrightText: 2010, 2011 Martin Gräßlin <mgraesslin@kde.org>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "plugins/slideback/motionmanager.h"
|
||||||
|
|
||||||
|
namespace KWin
|
||||||
|
{
|
||||||
|
|
||||||
|
/***************************************************************
|
||||||
|
Motion1D
|
||||||
|
***************************************************************/
|
||||||
|
|
||||||
|
Motion1D::Motion1D(double initial, double strength, double smoothness)
|
||||||
|
: Motion<double>(initial, strength, smoothness)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Motion1D::Motion1D(const Motion1D &other)
|
||||||
|
: Motion<double>(other)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Motion1D::~Motion1D()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************
|
||||||
|
Motion2D
|
||||||
|
***************************************************************/
|
||||||
|
|
||||||
|
Motion2D::Motion2D(QPointF initial, double strength, double smoothness)
|
||||||
|
: Motion<QPointF>(initial, strength, smoothness)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Motion2D::Motion2D(const Motion2D &other)
|
||||||
|
: Motion<QPointF>(other)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Motion2D::~Motion2D()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************
|
||||||
|
WindowMotionManager
|
||||||
|
***************************************************************/
|
||||||
|
|
||||||
|
WindowMotionManager::WindowMotionManager(bool useGlobalAnimationModifier)
|
||||||
|
: m_useGlobalAnimationModifier(useGlobalAnimationModifier)
|
||||||
|
|
||||||
|
{
|
||||||
|
// TODO: Allow developer to modify motion attributes
|
||||||
|
} // TODO: What happens when the window moves by an external force?
|
||||||
|
|
||||||
|
WindowMotionManager::~WindowMotionManager()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowMotionManager::manage(EffectWindow *w)
|
||||||
|
{
|
||||||
|
if (m_managedWindows.contains(w)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double strength = 0.08;
|
||||||
|
double smoothness = 4.0;
|
||||||
|
if (m_useGlobalAnimationModifier && effects->animationTimeFactor()) {
|
||||||
|
// If the factor is == 0 then we just skip the calculation completely
|
||||||
|
strength = 0.08 / effects->animationTimeFactor();
|
||||||
|
smoothness = effects->animationTimeFactor() * 4.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
WindowMotion &motion = m_managedWindows[w];
|
||||||
|
motion.translation.setStrength(strength);
|
||||||
|
motion.translation.setSmoothness(smoothness);
|
||||||
|
motion.scale.setStrength(strength * 1.33);
|
||||||
|
motion.scale.setSmoothness(smoothness / 2.0);
|
||||||
|
|
||||||
|
motion.translation.setValue(w->pos());
|
||||||
|
motion.scale.setValue(QPointF(1.0, 1.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowMotionManager::unmanage(EffectWindow *w)
|
||||||
|
{
|
||||||
|
m_movingWindowsSet.remove(w);
|
||||||
|
m_managedWindows.remove(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowMotionManager::unmanageAll()
|
||||||
|
{
|
||||||
|
m_managedWindows.clear();
|
||||||
|
m_movingWindowsSet.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowMotionManager::calculate(int time)
|
||||||
|
{
|
||||||
|
if (!effects->animationTimeFactor()) {
|
||||||
|
// Just skip it completely if the user wants no animation
|
||||||
|
m_movingWindowsSet.clear();
|
||||||
|
QHash<EffectWindow *, WindowMotion>::iterator it = m_managedWindows.begin();
|
||||||
|
for (; it != m_managedWindows.end(); ++it) {
|
||||||
|
WindowMotion *motion = &it.value();
|
||||||
|
motion->translation.finish();
|
||||||
|
motion->scale.finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QHash<EffectWindow *, WindowMotion>::iterator it = m_managedWindows.begin();
|
||||||
|
for (; it != m_managedWindows.end(); ++it) {
|
||||||
|
WindowMotion *motion = &it.value();
|
||||||
|
int stopped = 0;
|
||||||
|
|
||||||
|
// TODO: What happens when distance() == 0 but we are still moving fast?
|
||||||
|
// TODO: Motion needs to be calculated from the window's center
|
||||||
|
|
||||||
|
Motion2D *trans = &motion->translation;
|
||||||
|
if (trans->distance().isNull()) {
|
||||||
|
++stopped;
|
||||||
|
} else {
|
||||||
|
// Still moving
|
||||||
|
trans->calculate(time);
|
||||||
|
const short fx = trans->target().x() <= trans->startValue().x() ? -1 : 1;
|
||||||
|
const short fy = trans->target().y() <= trans->startValue().y() ? -1 : 1;
|
||||||
|
if (trans->distance().x() * fx / 0.5 < 1.0 && trans->velocity().x() * fx / 0.2 < 1.0
|
||||||
|
&& trans->distance().y() * fy / 0.5 < 1.0 && trans->velocity().y() * fy / 0.2 < 1.0) {
|
||||||
|
// Hide tiny oscillations
|
||||||
|
motion->translation.finish();
|
||||||
|
++stopped;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Motion2D *scale = &motion->scale;
|
||||||
|
if (scale->distance().isNull()) {
|
||||||
|
++stopped;
|
||||||
|
} else {
|
||||||
|
// Still scaling
|
||||||
|
scale->calculate(time);
|
||||||
|
const short fx = scale->target().x() < 1.0 ? -1 : 1;
|
||||||
|
const short fy = scale->target().y() < 1.0 ? -1 : 1;
|
||||||
|
if (scale->distance().x() * fx / 0.001 < 1.0 && scale->velocity().x() * fx / 0.05 < 1.0
|
||||||
|
&& scale->distance().y() * fy / 0.001 < 1.0 && scale->velocity().y() * fy / 0.05 < 1.0) {
|
||||||
|
// Hide tiny oscillations
|
||||||
|
motion->scale.finish();
|
||||||
|
++stopped;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We just finished this window's motion
|
||||||
|
if (stopped == 2) {
|
||||||
|
m_movingWindowsSet.remove(it.key());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowMotionManager::reset()
|
||||||
|
{
|
||||||
|
QHash<EffectWindow *, WindowMotion>::iterator it = m_managedWindows.begin();
|
||||||
|
for (; it != m_managedWindows.end(); ++it) {
|
||||||
|
WindowMotion *motion = &it.value();
|
||||||
|
EffectWindow *window = it.key();
|
||||||
|
motion->translation.setTarget(window->pos());
|
||||||
|
motion->translation.finish();
|
||||||
|
motion->scale.setTarget(QPointF(1.0, 1.0));
|
||||||
|
motion->scale.finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowMotionManager::reset(EffectWindow *w)
|
||||||
|
{
|
||||||
|
QHash<EffectWindow *, WindowMotion>::iterator it = m_managedWindows.find(w);
|
||||||
|
if (it == m_managedWindows.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
WindowMotion *motion = &it.value();
|
||||||
|
motion->translation.setTarget(w->pos());
|
||||||
|
motion->translation.finish();
|
||||||
|
motion->scale.setTarget(QPointF(1.0, 1.0));
|
||||||
|
motion->scale.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowMotionManager::apply(EffectWindow *w, WindowPaintData &data)
|
||||||
|
{
|
||||||
|
QHash<EffectWindow *, WindowMotion>::iterator it = m_managedWindows.find(w);
|
||||||
|
if (it == m_managedWindows.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Take into account existing scale so that we can work with multiple managers (E.g. Present windows + grid)
|
||||||
|
WindowMotion *motion = &it.value();
|
||||||
|
data += (motion->translation.value() - QPointF(w->x(), w->y()));
|
||||||
|
data *= QVector2D(motion->scale.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowMotionManager::moveWindow(EffectWindow *w, QPoint target, double scale, double yScale)
|
||||||
|
{
|
||||||
|
QHash<EffectWindow *, WindowMotion>::iterator it = m_managedWindows.find(w);
|
||||||
|
Q_ASSERT(it != m_managedWindows.end()); // Notify the effect author that they did something wrong
|
||||||
|
|
||||||
|
WindowMotion *motion = &it.value();
|
||||||
|
|
||||||
|
if (yScale == 0.0) {
|
||||||
|
yScale = scale;
|
||||||
|
}
|
||||||
|
QPointF scalePoint(scale, yScale);
|
||||||
|
|
||||||
|
if (motion->translation.value() == target && motion->scale.value() == scalePoint) {
|
||||||
|
return; // Window already at that position
|
||||||
|
}
|
||||||
|
|
||||||
|
motion->translation.setTarget(target);
|
||||||
|
motion->scale.setTarget(scalePoint);
|
||||||
|
|
||||||
|
m_movingWindowsSet << w;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF WindowMotionManager::transformedGeometry(EffectWindow *w) const
|
||||||
|
{
|
||||||
|
QHash<EffectWindow *, WindowMotion>::const_iterator it = m_managedWindows.constFind(w);
|
||||||
|
if (it == m_managedWindows.end()) {
|
||||||
|
return w->frameGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
|
const WindowMotion *motion = &it.value();
|
||||||
|
QRectF geometry(w->frameGeometry());
|
||||||
|
|
||||||
|
// TODO: Take into account existing scale so that we can work with multiple managers (E.g. Present windows + grid)
|
||||||
|
geometry.moveTo(motion->translation.value());
|
||||||
|
geometry.setWidth(geometry.width() * motion->scale.value().x());
|
||||||
|
geometry.setHeight(geometry.height() * motion->scale.value().y());
|
||||||
|
|
||||||
|
return geometry;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowMotionManager::setTransformedGeometry(EffectWindow *w, const QRectF &geometry)
|
||||||
|
{
|
||||||
|
QHash<EffectWindow *, WindowMotion>::iterator it = m_managedWindows.find(w);
|
||||||
|
if (it == m_managedWindows.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
WindowMotion *motion = &it.value();
|
||||||
|
motion->translation.setValue(geometry.topLeft());
|
||||||
|
motion->scale.setValue(QPointF(geometry.width() / qreal(w->width()), geometry.height() / qreal(w->height())));
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF WindowMotionManager::targetGeometry(EffectWindow *w) const
|
||||||
|
{
|
||||||
|
QHash<EffectWindow *, WindowMotion>::const_iterator it = m_managedWindows.constFind(w);
|
||||||
|
if (it == m_managedWindows.end()) {
|
||||||
|
return w->frameGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
|
const WindowMotion *motion = &it.value();
|
||||||
|
QRectF geometry(w->frameGeometry());
|
||||||
|
|
||||||
|
// TODO: Take into account existing scale so that we can work with multiple managers (E.g. Present windows + grid)
|
||||||
|
geometry.moveTo(motion->translation.target());
|
||||||
|
geometry.setWidth(geometry.width() * motion->scale.target().x());
|
||||||
|
geometry.setHeight(geometry.height() * motion->scale.target().y());
|
||||||
|
|
||||||
|
return geometry;
|
||||||
|
}
|
||||||
|
|
||||||
|
EffectWindow *WindowMotionManager::windowAtPoint(QPoint point, bool useStackingOrder) const
|
||||||
|
{
|
||||||
|
// TODO: Stacking order uses EffectsHandler::stackingOrder() then filters by m_managedWindows
|
||||||
|
QHash<EffectWindow *, WindowMotion>::ConstIterator it = m_managedWindows.constBegin();
|
||||||
|
while (it != m_managedWindows.constEnd()) {
|
||||||
|
if (exclusiveContains(transformedGeometry(it.key()), point)) {
|
||||||
|
return it.key();
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace KWin
|
361
src/plugins/slideback/motionmanager.h
Normal file
361
src/plugins/slideback/motionmanager.h
Normal file
|
@ -0,0 +1,361 @@
|
||||||
|
/*
|
||||||
|
SPDX-FileCopyrightText: 2006 Lubos Lunak <l.lunak@kde.org>
|
||||||
|
SPDX-FileCopyrightText: 2009 Lucas Murray <lmurray@undefinedfire.com>
|
||||||
|
SPDX-FileCopyrightText: 2010, 2011 Martin Gräßlin <mgraesslin@kde.org>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "libkwineffects/effects.h"
|
||||||
|
|
||||||
|
namespace KWin
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
class KWIN_EXPORT Motion
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Creates a new motion object. "Strength" is the amount of
|
||||||
|
* acceleration that is applied to the object when the target
|
||||||
|
* changes and "smoothness" relates to how fast the object
|
||||||
|
* can change its direction and speed.
|
||||||
|
*/
|
||||||
|
explicit Motion(T initial, double strength, double smoothness);
|
||||||
|
/**
|
||||||
|
* Creates an exact copy of another motion object, including
|
||||||
|
* position, target and velocity.
|
||||||
|
*/
|
||||||
|
Motion(const Motion<T> &other);
|
||||||
|
~Motion();
|
||||||
|
|
||||||
|
inline T value() const
|
||||||
|
{
|
||||||
|
return m_value;
|
||||||
|
}
|
||||||
|
inline void setValue(const T value)
|
||||||
|
{
|
||||||
|
m_value = value;
|
||||||
|
}
|
||||||
|
inline T target() const
|
||||||
|
{
|
||||||
|
return m_target;
|
||||||
|
}
|
||||||
|
inline void setTarget(const T target)
|
||||||
|
{
|
||||||
|
m_start = m_value;
|
||||||
|
m_target = target;
|
||||||
|
}
|
||||||
|
inline T velocity() const
|
||||||
|
{
|
||||||
|
return m_velocity;
|
||||||
|
}
|
||||||
|
inline void setVelocity(const T velocity)
|
||||||
|
{
|
||||||
|
m_velocity = velocity;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline double strength() const
|
||||||
|
{
|
||||||
|
return m_strength;
|
||||||
|
}
|
||||||
|
inline void setStrength(const double strength)
|
||||||
|
{
|
||||||
|
m_strength = strength;
|
||||||
|
}
|
||||||
|
inline double smoothness() const
|
||||||
|
{
|
||||||
|
return m_smoothness;
|
||||||
|
}
|
||||||
|
inline void setSmoothness(const double smoothness)
|
||||||
|
{
|
||||||
|
m_smoothness = smoothness;
|
||||||
|
}
|
||||||
|
inline T startValue()
|
||||||
|
{
|
||||||
|
return m_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The distance between the current position and the target.
|
||||||
|
*/
|
||||||
|
inline T distance() const
|
||||||
|
{
|
||||||
|
return m_target - m_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the new position if not at the target. Called
|
||||||
|
* once per frame only.
|
||||||
|
*/
|
||||||
|
void calculate(const int msec);
|
||||||
|
/**
|
||||||
|
* Place the object on top of the target immediately,
|
||||||
|
* bypassing all movement calculation.
|
||||||
|
*/
|
||||||
|
void finish();
|
||||||
|
|
||||||
|
private:
|
||||||
|
T m_value;
|
||||||
|
T m_start;
|
||||||
|
T m_target;
|
||||||
|
T m_velocity;
|
||||||
|
double m_strength;
|
||||||
|
double m_smoothness;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @short A single 1D motion dynamics object.
|
||||||
|
*
|
||||||
|
* This class represents a single object that can be moved around a
|
||||||
|
* 1D space. Although it can be used directly by itself it is
|
||||||
|
* recommended to use a motion manager instead.
|
||||||
|
*/
|
||||||
|
class KWIN_EXPORT Motion1D : public Motion<double>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit Motion1D(double initial = 0.0, double strength = 0.08, double smoothness = 4.0);
|
||||||
|
Motion1D(const Motion1D &other);
|
||||||
|
~Motion1D();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @short A single 2D motion dynamics object.
|
||||||
|
*
|
||||||
|
* This class represents a single object that can be moved around a
|
||||||
|
* 2D space. Although it can be used directly by itself it is
|
||||||
|
* recommended to use a motion manager instead.
|
||||||
|
*/
|
||||||
|
class KWIN_EXPORT Motion2D : public Motion<QPointF>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit Motion2D(QPointF initial = QPointF(), double strength = 0.08, double smoothness = 4.0);
|
||||||
|
Motion2D(const Motion2D &other);
|
||||||
|
~Motion2D();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @short Helper class for motion dynamics in KWin effects.
|
||||||
|
*
|
||||||
|
* This motion manager class is intended to help KWin effect authors
|
||||||
|
* move windows across the screen smoothly and naturally. Once
|
||||||
|
* windows are registered by the manager the effect can issue move
|
||||||
|
* commands with the moveWindow() methods. The position of any
|
||||||
|
* managed window can be determined in realtime by the
|
||||||
|
* transformedGeometry() method. As the manager knows if any windows
|
||||||
|
* are moving at any given time it can also be used as a notifier as
|
||||||
|
* to see whether the effect is active or not.
|
||||||
|
*/
|
||||||
|
class KWIN_EXPORT WindowMotionManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Creates a new window manager object.
|
||||||
|
*/
|
||||||
|
explicit WindowMotionManager(bool useGlobalAnimationModifier = true);
|
||||||
|
~WindowMotionManager();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a window for managing.
|
||||||
|
*/
|
||||||
|
void manage(EffectWindow *w);
|
||||||
|
/**
|
||||||
|
* Register a list of windows for managing.
|
||||||
|
*/
|
||||||
|
inline void manage(const EffectWindowList &list)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < list.size(); i++) {
|
||||||
|
manage(list.at(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Deregister a window. All transformations applied to the
|
||||||
|
* window will be permanently removed and cannot be recovered.
|
||||||
|
*/
|
||||||
|
void unmanage(EffectWindow *w);
|
||||||
|
/**
|
||||||
|
* Deregister all windows, returning the manager to its
|
||||||
|
* originally initiated state.
|
||||||
|
*/
|
||||||
|
void unmanageAll();
|
||||||
|
/**
|
||||||
|
* Determine the new positions for windows that have not
|
||||||
|
* reached their target. Called once per frame, usually in
|
||||||
|
* prePaintScreen(). Remember to set the
|
||||||
|
* Effect::PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS flag.
|
||||||
|
*/
|
||||||
|
void calculate(int time);
|
||||||
|
/**
|
||||||
|
* Modify a registered window's paint data to make it appear
|
||||||
|
* at its real location on the screen. Usually called in
|
||||||
|
* paintWindow(). Remember to flag the window as having been
|
||||||
|
* transformed in prePaintWindow() by calling
|
||||||
|
* WindowPrePaintData::setTransformed()
|
||||||
|
*/
|
||||||
|
void apply(EffectWindow *w, WindowPaintData &data);
|
||||||
|
/**
|
||||||
|
* Set all motion targets and values back to where the
|
||||||
|
* windows were before transformations. The same as
|
||||||
|
* unmanaging then remanaging all windows.
|
||||||
|
*/
|
||||||
|
void reset();
|
||||||
|
/**
|
||||||
|
* Resets the motion target and current value of a single
|
||||||
|
* window.
|
||||||
|
*/
|
||||||
|
void reset(EffectWindow *w);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ask the manager to move the window to the target position
|
||||||
|
* with the specified scale. If `yScale` is not provided or
|
||||||
|
* set to 0.0, `scale` will be used as the scale in the
|
||||||
|
* vertical direction as well as in the horizontal direction.
|
||||||
|
*/
|
||||||
|
void moveWindow(EffectWindow *w, QPoint target, double scale = 1.0, double yScale = 0.0);
|
||||||
|
/**
|
||||||
|
* This is an overloaded method, provided for convenience.
|
||||||
|
*
|
||||||
|
* Ask the manager to move the window to the target rectangle.
|
||||||
|
* Automatically determines scale.
|
||||||
|
*/
|
||||||
|
inline void moveWindow(EffectWindow *w, QRect target)
|
||||||
|
{
|
||||||
|
// TODO: Scale might be slightly different in the comparison due to rounding
|
||||||
|
moveWindow(w, target.topLeft(),
|
||||||
|
target.width() / double(w->width()), target.height() / double(w->height()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the current tranformed geometry of a registered
|
||||||
|
* window.
|
||||||
|
*/
|
||||||
|
QRectF transformedGeometry(EffectWindow *w) const;
|
||||||
|
/**
|
||||||
|
* Sets the current transformed geometry of a registered window to the given geometry.
|
||||||
|
* @see transformedGeometry
|
||||||
|
* @since 4.5
|
||||||
|
*/
|
||||||
|
void setTransformedGeometry(EffectWindow *w, const QRectF &geometry);
|
||||||
|
/**
|
||||||
|
* Retrieve the current target geometry of a registered
|
||||||
|
* window.
|
||||||
|
*/
|
||||||
|
QRectF targetGeometry(EffectWindow *w) const;
|
||||||
|
/**
|
||||||
|
* Return the window that has its transformed geometry under
|
||||||
|
* the specified point. It is recommended to use the stacking
|
||||||
|
* order as it's what the user sees, but it is slightly
|
||||||
|
* slower to process.
|
||||||
|
*/
|
||||||
|
EffectWindow *windowAtPoint(QPoint point, bool useStackingOrder = true) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a list of all currently registered windows.
|
||||||
|
*/
|
||||||
|
inline EffectWindowList managedWindows() const
|
||||||
|
{
|
||||||
|
return m_managedWindows.keys();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns whether or not a specified window is being managed
|
||||||
|
* by this manager object.
|
||||||
|
*/
|
||||||
|
inline bool isManaging(EffectWindow *w) const
|
||||||
|
{
|
||||||
|
return m_managedWindows.contains(w);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns whether or not this manager object is actually
|
||||||
|
* managing any windows or not.
|
||||||
|
*/
|
||||||
|
inline bool managingWindows() const
|
||||||
|
{
|
||||||
|
return !m_managedWindows.empty();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns whether all windows have reached their targets yet
|
||||||
|
* or not. Can be used to see if an effect should be
|
||||||
|
* processed and displayed or not.
|
||||||
|
*/
|
||||||
|
inline bool areWindowsMoving() const
|
||||||
|
{
|
||||||
|
return !m_movingWindowsSet.isEmpty();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns whether a window has reached its targets yet
|
||||||
|
* or not.
|
||||||
|
*/
|
||||||
|
inline bool isWindowMoving(EffectWindow *w) const
|
||||||
|
{
|
||||||
|
return m_movingWindowsSet.contains(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_useGlobalAnimationModifier;
|
||||||
|
struct WindowMotion
|
||||||
|
{
|
||||||
|
// TODO: Rotation, etc?
|
||||||
|
Motion2D translation; // Absolute position
|
||||||
|
Motion2D scale; // xScale and yScale
|
||||||
|
};
|
||||||
|
QHash<EffectWindow *, WindowMotion> m_managedWindows;
|
||||||
|
QSet<EffectWindow *> m_movingWindowsSet;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
Motion<T>::Motion(T initial, double strength, double smoothness)
|
||||||
|
: m_value(initial)
|
||||||
|
, m_start(initial)
|
||||||
|
, m_target(initial)
|
||||||
|
, m_velocity()
|
||||||
|
, m_strength(strength)
|
||||||
|
, m_smoothness(smoothness)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
Motion<T>::Motion(const Motion &other)
|
||||||
|
: m_value(other.value())
|
||||||
|
, m_start(other.target())
|
||||||
|
, m_target(other.target())
|
||||||
|
, m_velocity(other.velocity())
|
||||||
|
, m_strength(other.strength())
|
||||||
|
, m_smoothness(other.smoothness())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
Motion<T>::~Motion()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void Motion<T>::calculate(const int msec)
|
||||||
|
{
|
||||||
|
if (m_value == m_target && m_velocity == T()) { // At target and not moving
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Poor man's time independent calculation
|
||||||
|
int steps = std::max(1, msec / 5);
|
||||||
|
for (int i = 0; i < steps; i++) {
|
||||||
|
T diff = m_target - m_value;
|
||||||
|
T strength = diff * m_strength;
|
||||||
|
m_velocity = (m_smoothness * m_velocity + strength) / (m_smoothness + 1.0);
|
||||||
|
m_value += m_velocity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void Motion<T>::finish()
|
||||||
|
{
|
||||||
|
m_value = m_target;
|
||||||
|
m_velocity = T();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace KWin
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
// Include with base class for effects.
|
// Include with base class for effects.
|
||||||
#include "libkwineffects/effects.h"
|
#include "libkwineffects/effects.h"
|
||||||
|
#include "plugins/slideback/motionmanager.h"
|
||||||
|
|
||||||
namespace KWin
|
namespace KWin
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue