image/loading: Adjust frame timing by accrued delay
This should fix animations systematically slowing down.
This commit is contained in:
parent
5505f5d876
commit
eee2b415d2
4 changed files with 26 additions and 14 deletions
1
news.d/51.alpha/fixed-animation-dont-accumulate-delay
Normal file
1
news.d/51.alpha/fixed-animation-dont-accumulate-delay
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Don't accumulate delays during animations. !596
|
||||||
|
|
@ -649,22 +649,24 @@ impl SharedFrameBuffer {
|
||||||
tiling.unwrap()
|
tiling.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return true if the next frame should be shown and removes the outdated
|
/// Remove current frame if frame delay elapsed
|
||||||
/// frame
|
///
|
||||||
pub fn frame_timeout(&self, elapsed: Duration) -> bool {
|
/// Returns the amount of time the frame is shown 'too late'
|
||||||
|
pub fn frame_timeout(&self, elapsed: Duration) -> Option<Duration> {
|
||||||
let images = &self.buffer.load().images;
|
let images = &self.buffer.load().images;
|
||||||
|
|
||||||
// Only move to next image if there is one buffered
|
// Only move to next image if there is one buffered
|
||||||
if images.len() > 1
|
if images.len() > 1
|
||||||
&& images
|
&& let Some(next_frame) = images.front()
|
||||||
.front()
|
&& elapsed >= next_frame.delay
|
||||||
.is_some_and(|next_frame| elapsed >= next_frame.delay)
|
|
||||||
{
|
{
|
||||||
|
let delay = elapsed - next_frame.delay;
|
||||||
self.next_frame();
|
self.next_frame();
|
||||||
return true;
|
let delay = delay.min(next_frame.delay);
|
||||||
|
return Some(delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
false
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn next_frame(&self) {
|
pub fn next_frame(&self) {
|
||||||
|
|
|
||||||
|
|
@ -253,8 +253,8 @@ mod imp {
|
||||||
|
|
||||||
/// Ticks callback for animated image formats
|
/// Ticks callback for animated image formats
|
||||||
pub(super) tick_callback: RefCell<Option<gtk::TickCallbackId>>,
|
pub(super) tick_callback: RefCell<Option<gtk::TickCallbackId>>,
|
||||||
/// Frame block time for currently shown frame
|
/// Adjusted frame clock time for when the current frame was shown
|
||||||
pub(super) last_animated_frame: Cell<i64>,
|
pub(super) last_animated_frame: Cell<Option<i64>>,
|
||||||
|
|
||||||
/// Gesture, zoom or rotate, used for the duration of the gesture
|
/// Gesture, zoom or rotate, used for the duration of the gesture
|
||||||
pub(super) locked_gestured: Cell<Option<Gesture>>,
|
pub(super) locked_gestured: Cell<Option<Gesture>>,
|
||||||
|
|
|
||||||
|
|
@ -160,17 +160,26 @@ impl imp::LpImage {
|
||||||
|
|
||||||
// Do not animate if not visible
|
// Do not animate if not visible
|
||||||
if !obj.is_mapped() {
|
if !obj.is_mapped() {
|
||||||
|
self.last_animated_frame.set(None);
|
||||||
return glib::ControlFlow::Continue;
|
return glib::ControlFlow::Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let elapsed = clock.frame_time() - self.last_animated_frame.get();
|
let duration = if let Some(last_animated_frame) = self.last_animated_frame.get() {
|
||||||
let duration = std::time::Duration::from_micros(elapsed as u64);
|
let elapsed = clock.frame_time() - last_animated_frame;
|
||||||
|
std::time::Duration::from_micros(elapsed as u64)
|
||||||
|
} else {
|
||||||
|
self.last_animated_frame.set(Some(clock.frame_time()));
|
||||||
|
std::time::Duration::ZERO
|
||||||
|
};
|
||||||
|
|
||||||
// Check if it's time to show the next frame
|
// Check if it's time to show the next frame
|
||||||
if self.frame_buffer.frame_timeout(duration) {
|
if let Some(delay) = self.frame_buffer.frame_timeout(duration) {
|
||||||
// Just draw since frame_timeout updated to new frame
|
// Just draw since frame_timeout updated to new frame
|
||||||
obj.queue_draw();
|
obj.queue_draw();
|
||||||
self.last_animated_frame.set(clock.frame_time());
|
// Adjust the time when the frame was shown by how much anwanted delay we
|
||||||
|
// accumulated
|
||||||
|
self.last_animated_frame
|
||||||
|
.set(Some(clock.frame_time() - delay.as_micros() as i64));
|
||||||
if let Some(decoder) = self.decoder.borrow().as_ref() {
|
if let Some(decoder) = self.decoder.borrow().as_ref() {
|
||||||
// Decode new frame and load it into buffer
|
// Decode new frame and load it into buffer
|
||||||
decoder.fill_frame_buffer();
|
decoder.fill_frame_buffer();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue