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()
|
||||
}
|
||||
|
||||
/// Return true if the next frame should be shown and removes the outdated
|
||||
/// frame
|
||||
pub fn frame_timeout(&self, elapsed: Duration) -> bool {
|
||||
/// Remove current frame if frame delay elapsed
|
||||
///
|
||||
/// 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;
|
||||
|
||||
// Only move to next image if there is one buffered
|
||||
if images.len() > 1
|
||||
&& images
|
||||
.front()
|
||||
.is_some_and(|next_frame| elapsed >= next_frame.delay)
|
||||
&& let Some(next_frame) = images.front()
|
||||
&& elapsed >= next_frame.delay
|
||||
{
|
||||
let delay = elapsed - next_frame.delay;
|
||||
self.next_frame();
|
||||
return true;
|
||||
let delay = delay.min(next_frame.delay);
|
||||
return Some(delay);
|
||||
}
|
||||
|
||||
false
|
||||
None
|
||||
}
|
||||
|
||||
pub fn next_frame(&self) {
|
||||
|
|
|
|||
|
|
@ -253,8 +253,8 @@ mod imp {
|
|||
|
||||
/// Ticks callback for animated image formats
|
||||
pub(super) tick_callback: RefCell<Option<gtk::TickCallbackId>>,
|
||||
/// Frame block time for currently shown frame
|
||||
pub(super) last_animated_frame: Cell<i64>,
|
||||
/// Adjusted frame clock time for when the current frame was shown
|
||||
pub(super) last_animated_frame: Cell<Option<i64>>,
|
||||
|
||||
/// Gesture, zoom or rotate, used for the duration of the gesture
|
||||
pub(super) locked_gestured: Cell<Option<Gesture>>,
|
||||
|
|
|
|||
|
|
@ -160,17 +160,26 @@ impl imp::LpImage {
|
|||
|
||||
// Do not animate if not visible
|
||||
if !obj.is_mapped() {
|
||||
self.last_animated_frame.set(None);
|
||||
return glib::ControlFlow::Continue;
|
||||
}
|
||||
|
||||
let elapsed = clock.frame_time() - self.last_animated_frame.get();
|
||||
let duration = std::time::Duration::from_micros(elapsed as u64);
|
||||
let duration = if let Some(last_animated_frame) = self.last_animated_frame.get() {
|
||||
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
|
||||
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
|
||||
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() {
|
||||
// Decode new frame and load it into buffer
|
||||
decoder.fill_frame_buffer();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue