From f25787393c6ecd7f48fade369f58fb671e1205b3 Mon Sep 17 00:00:00 2001 From: thearturca Date: Tue, 23 Jul 2024 16:26:58 +0300 Subject: [PATCH] fix(animation): extend cancelling system to support multiple cancel call This commit fixes cross-monitor drag move by extending cancelling system. Now each cancel call have its own idx. And only latest cancel will continue animation. Others will be dropped. --- komorebi/src/animation.rs | 28 ++++++++++++++++++------- komorebi/src/animation_manager.rs | 35 ++++++++++++++++++++++++------- 2 files changed, 48 insertions(+), 15 deletions(-) diff --git a/komorebi/src/animation.rs b/komorebi/src/animation.rs index 3ebdd00e..9db9fc09 100644 --- a/komorebi/src/animation.rs +++ b/komorebi/src/animation.rs @@ -416,12 +416,15 @@ impl Animation { pub fn new(hwnd: isize) -> Self { Self { hwnd } } - pub fn cancel(&mut self) { + + /// Returns true if the animation needs to continue + pub fn cancel(&mut self) -> bool { if !ANIMATION_MANAGER.lock().in_progress(self.hwnd) { - return; + return true; } - ANIMATION_MANAGER.lock().cancel(self.hwnd); + // should be more than 0 + let cancel_idx = ANIMATION_MANAGER.lock().init_cancel(self.hwnd); let max_duration = Duration::from_secs(1); let spent_duration = Instant::now(); @@ -434,6 +437,10 @@ impl Animation { ANIMATION_DURATION.load(Ordering::SeqCst) / 2, )); } + + let latest_cancel_idx = ANIMATION_MANAGER.lock().end_cancel(self.hwnd); + + return latest_cancel_idx == cancel_idx; } #[allow(clippy::cast_possible_truncation)] @@ -460,7 +467,11 @@ impl Animation { mut render_callback: impl FnMut(f64) -> Result<()>, ) -> Result<()> { if ANIMATION_MANAGER.lock().in_progress(self.hwnd) { - self.cancel(); + let should_animate = self.cancel(); + + if !should_animate { + return Ok(()); + } } ANIMATION_MANAGER.lock().start(self.hwnd); @@ -474,8 +485,7 @@ impl Animation { // check if animation is cancelled if ANIMATION_MANAGER.lock().is_cancelled(self.hwnd) { // cancel animation - // set all flags - ANIMATION_MANAGER.lock().end(self.hwnd); + ANIMATION_MANAGER.lock().cancel(self.hwnd); return Ok(()); } @@ -485,8 +495,10 @@ impl Animation { render_callback(progress).ok(); // sleep until next frame - if frame_start.elapsed() < target_frame_time { - std::thread::sleep(target_frame_time - frame_start.elapsed()); + let frame_time_elapsed = frame_start.elapsed(); + + if frame_time_elapsed < target_frame_time { + std::thread::sleep(target_frame_time - frame_time_elapsed); } } diff --git a/komorebi/src/animation_manager.rs b/komorebi/src/animation_manager.rs index 2fd3f746..f0df8d21 100644 --- a/komorebi/src/animation_manager.rs +++ b/komorebi/src/animation_manager.rs @@ -8,7 +8,7 @@ pub static ANIMATIONS_IN_PROGRESS: AtomicUsize = AtomicUsize::new(0); #[derive(Debug, Clone, Copy)] struct AnimationState { pub in_progress: bool, - pub is_cancelled: bool, + pub cancelled_count: usize, } #[derive(Debug)] @@ -31,7 +31,7 @@ impl AnimationManager { pub fn is_cancelled(&self, hwnd: isize) -> bool { if let Some(animation_state) = self.animations.get(&hwnd) { - animation_state.is_cancelled + animation_state.cancelled_count > 0 } else { false } @@ -45,9 +45,29 @@ impl AnimationManager { } } + pub fn init_cancel(&mut self, hwnd: isize) -> usize { + if let Some(animation_state) = self.animations.get_mut(&hwnd) { + animation_state.cancelled_count += 1; + animation_state.cancelled_count + } else { + 0 + } + } + + pub fn end_cancel(&mut self, hwnd: isize) -> usize { + if let Some(animation_state) = self.animations.get_mut(&hwnd) { + let cancelled_count = animation_state.cancelled_count; + animation_state.cancelled_count -= 1; + + return cancelled_count; + } else { + 0 + } + } + pub fn cancel(&mut self, hwnd: isize) { if let Some(animation_state) = self.animations.get_mut(&hwnd) { - animation_state.is_cancelled = true; + animation_state.in_progress = false; } } @@ -55,7 +75,7 @@ impl AnimationManager { if let Entry::Vacant(e) = self.animations.entry(hwnd) { e.insert(AnimationState { in_progress: true, - is_cancelled: false, + cancelled_count: 0, }); ANIMATIONS_IN_PROGRESS.store(self.animations.len(), Ordering::Release); @@ -70,10 +90,11 @@ impl AnimationManager { pub fn end(&mut self, hwnd: isize) { if let Some(animation_state) = self.animations.get_mut(&hwnd) { animation_state.in_progress = false; - animation_state.is_cancelled = false; - self.animations.remove(&hwnd); - ANIMATIONS_IN_PROGRESS.store(self.animations.len(), Ordering::Release); + if animation_state.cancelled_count == 0 { + self.animations.remove(&hwnd); + ANIMATIONS_IN_PROGRESS.store(self.animations.len(), Ordering::Release); + } } } }