aboutsummaryrefslogtreecommitdiff
path: root/src/animation
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2024-11-23 11:27:27 +0300
committerIvan Molodetskikh <yalterz@gmail.com>2024-11-25 04:07:59 -0800
commit93cee2994ab9ccf59a09f61d5b8acf6cd937d654 (patch)
treefb00cdb266e9e94891f226558cd93a09e0091d69 /src/animation
parent9c7e8d04d27d2f914ad3e9a54c64b64c34aea4d4 (diff)
downloadniri-93cee2994ab9ccf59a09f61d5b8acf6cd937d654.tar.gz
niri-93cee2994ab9ccf59a09f61d5b8acf6cd937d654.tar.bz2
niri-93cee2994ab9ccf59a09f61d5b8acf6cd937d654.zip
Refactor animations to take explicit current time
Diffstat (limited to 'src/animation')
-rw-r--r--src/animation/clock.rs41
-rw-r--r--src/animation/mod.rs80
2 files changed, 93 insertions, 28 deletions
diff --git a/src/animation/clock.rs b/src/animation/clock.rs
new file mode 100644
index 00000000..3cfa727b
--- /dev/null
+++ b/src/animation/clock.rs
@@ -0,0 +1,41 @@
+use std::cell::Cell;
+use std::rc::Rc;
+use std::time::Duration;
+
+use crate::utils::get_monotonic_time;
+
+/// Clock that can have its time value overridden.
+///
+/// Can be cloned to share the same clock.
+#[derive(Debug, Default, Clone)]
+pub struct Clock {
+ time_override: Rc<Cell<Option<Duration>>>,
+}
+
+impl Clock {
+ /// Creates a new [`Clock`] with time override in place.
+ pub fn with_override(time: Duration) -> Self {
+ Self {
+ time_override: Rc::new(Cell::new(Some(time))),
+ }
+ }
+
+ /// Sets the current time override.
+ pub fn set_time_override(&mut self, time: Option<Duration>) {
+ self.time_override.set(time);
+ }
+
+ /// Gets the current time.
+ #[inline]
+ pub fn now(&self) -> Duration {
+ self.time_override.get().unwrap_or_else(get_monotonic_time)
+ }
+}
+
+impl PartialEq for Clock {
+ fn eq(&self, other: &Self) -> bool {
+ Rc::ptr_eq(&self.time_override, &other.time_override)
+ }
+}
+
+impl Eq for Clock {}
diff --git a/src/animation/mod.rs b/src/animation/mod.rs
index 780cb3a8..5efb0f16 100644
--- a/src/animation/mod.rs
+++ b/src/animation/mod.rs
@@ -4,11 +4,12 @@ use keyframe::functions::{EaseOutCubic, EaseOutQuad};
use keyframe::EasingFunction;
use portable_atomic::{AtomicF64, Ordering};
-use crate::utils::get_monotonic_time;
-
mod spring;
pub use spring::{Spring, SpringParams};
+mod clock;
+pub use clock::Clock;
+
pub static ANIMATION_SLOWDOWN: AtomicF64 = AtomicF64::new(1.);
#[derive(Debug, Clone)]
@@ -48,11 +49,24 @@ pub enum Curve {
}
impl Animation {
- pub fn new(from: f64, to: f64, initial_velocity: f64, config: niri_config::Animation) -> Self {
+ pub fn new(
+ current_time: Duration,
+ from: f64,
+ to: f64,
+ initial_velocity: f64,
+ config: niri_config::Animation,
+ ) -> Self {
// Scale the velocity by slowdown to keep the touchpad gestures feeling right.
let initial_velocity = initial_velocity * ANIMATION_SLOWDOWN.load(Ordering::Relaxed);
- let mut rv = Self::ease(from, to, initial_velocity, 0, Curve::EaseOutCubic);
+ let mut rv = Self::ease(
+ current_time,
+ from,
+ to,
+ initial_velocity,
+ 0,
+ Curve::EaseOutCubic,
+ );
if config.off {
rv.is_off = true;
return rv;
@@ -83,10 +97,11 @@ impl Animation {
initial_velocity: self.initial_velocity,
params,
};
- *self = Self::spring(spring);
+ *self = Self::spring(current_time, spring);
}
niri_config::AnimationKind::Easing(p) => {
*self = Self::ease(
+ current_time,
self.from,
self.to,
self.initial_velocity,
@@ -101,7 +116,13 @@ impl Animation {
}
/// Restarts the animation using the previous config.
- pub fn restarted(&self, from: f64, to: f64, initial_velocity: f64) -> Self {
+ pub fn restarted(
+ &self,
+ current_time: Duration,
+ from: f64,
+ to: f64,
+ initial_velocity: f64,
+ ) -> Self {
if self.is_off {
return self.clone();
}
@@ -111,6 +132,7 @@ impl Animation {
match self.kind {
Kind::Easing { curve } => Self::ease(
+ current_time,
from,
to,
initial_velocity,
@@ -124,23 +146,32 @@ impl Animation {
initial_velocity: self.initial_velocity,
params: spring.params,
};
- Self::spring(spring)
+ Self::spring(current_time, spring)
}
Kind::Deceleration {
initial_velocity,
deceleration_rate,
} => {
let threshold = 0.001; // FIXME
- Self::decelerate(from, initial_velocity, deceleration_rate, threshold)
+ Self::decelerate(
+ current_time,
+ from,
+ initial_velocity,
+ deceleration_rate,
+ threshold,
+ )
}
}
}
- pub fn ease(from: f64, to: f64, initial_velocity: f64, duration_ms: u64, curve: Curve) -> Self {
- // FIXME: ideally we shouldn't use current time here because animations started within the
- // same frame cycle should have the same start time to be synchronized.
- let now = get_monotonic_time();
-
+ pub fn ease(
+ current_time: Duration,
+ from: f64,
+ to: f64,
+ initial_velocity: f64,
+ duration_ms: u64,
+ curve: Curve,
+ ) -> Self {
let duration = Duration::from_millis(duration_ms);
let kind = Kind::Easing { curve };
@@ -152,19 +183,15 @@ impl Animation {
duration,
// Our current curves never overshoot.
clamped_duration: duration,
- start_time: now,
- current_time: now,
+ start_time: current_time,
+ current_time,
kind,
}
}
- pub fn spring(spring: Spring) -> Self {
+ pub fn spring(current_time: Duration, spring: Spring) -> Self {
let _span = tracy_client::span!("Animation::spring");
- // FIXME: ideally we shouldn't use current time here because animations started within the
- // same frame cycle should have the same start time to be synchronized.
- let now = get_monotonic_time();
-
let duration = spring.duration();
let clamped_duration = spring.clamped_duration().unwrap_or(duration);
let kind = Kind::Spring(spring);
@@ -176,22 +203,19 @@ impl Animation {
is_off: false,
duration,
clamped_duration,
- start_time: now,
- current_time: now,
+ start_time: current_time,
+ current_time,
kind,
}
}
pub fn decelerate(
+ current_time: Duration,
from: f64,
initial_velocity: f64,
deceleration_rate: f64,
threshold: f64,
) -> Self {
- // FIXME: ideally we shouldn't use current time here because animations started within the
- // same frame cycle should have the same start time to be synchronized.
- let now = get_monotonic_time();
-
let duration_s = if initial_velocity == 0. {
0.
} else {
@@ -214,8 +238,8 @@ impl Animation {
is_off: false,
duration,
clamped_duration: duration,
- start_time: now,
- current_time: now,
+ start_time: current_time,
+ current_time,
kind,
}
}