From e449861c10badcc229d137d22c3d4f5e08befd91 Mon Sep 17 00:00:00 2001 From: thearturca Date: Mon, 14 Oct 2024 20:47:30 +0300 Subject: [PATCH] refactor(animation): generalized ANIMATION_MANAGER instead of isize key for ANIMATION_MANAGER hashmap, now we use string key. For window move animation key wouldbe `window_move:{hwnd}`. That allows to use single manager for more types of animations. --- komorebi/src/animation/animation.rs | 36 +++++------ komorebi/src/animation/animation_manager.rs | 49 ++++++++------- komorebi/src/animation/mod.rs | 2 - komorebi/src/window.rs | 68 +++++++++++---------- 4 files changed, 76 insertions(+), 79 deletions(-) diff --git a/komorebi/src/animation/animation.rs b/komorebi/src/animation/animation.rs index 8c88200b..aca08ca9 100644 --- a/komorebi/src/animation/animation.rs +++ b/komorebi/src/animation/animation.rs @@ -13,29 +13,23 @@ use super::ANIMATION_FPS; use super::ANIMATION_MANAGER; #[derive(Debug, Default, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq)] -pub struct Animation { - pub hwnd: isize, -} +pub struct Animation {} impl Animation { - pub fn new(hwnd: isize) -> Self { - Self { hwnd } - } - /// Returns true if the animation needs to continue - pub fn cancel(&mut self) -> bool { - if !ANIMATION_MANAGER.lock().in_progress(self.hwnd) { + pub fn cancel(animation_key: &str) -> bool { + if !ANIMATION_MANAGER.lock().in_progress(animation_key) { return true; } // should be more than 0 - let cancel_idx = ANIMATION_MANAGER.lock().init_cancel(self.hwnd); + let cancel_idx = ANIMATION_MANAGER.lock().init_cancel(animation_key); let max_duration = Duration::from_secs(1); let spent_duration = Instant::now(); - while ANIMATION_MANAGER.lock().in_progress(self.hwnd) { + while ANIMATION_MANAGER.lock().in_progress(animation_key) { if spent_duration.elapsed() >= max_duration { - ANIMATION_MANAGER.lock().end(self.hwnd); + ANIMATION_MANAGER.lock().end(animation_key); } std::thread::sleep(Duration::from_millis( @@ -43,28 +37,28 @@ impl Animation { )); } - let latest_cancel_idx = ANIMATION_MANAGER.lock().latest_cancel_idx(self.hwnd); + let latest_cancel_idx = ANIMATION_MANAGER.lock().latest_cancel_idx(animation_key); - ANIMATION_MANAGER.lock().end_cancel(self.hwnd); + ANIMATION_MANAGER.lock().end_cancel(animation_key); latest_cancel_idx == cancel_idx } #[allow(clippy::cast_precision_loss)] pub fn animate( - &mut self, + animation_key: &str, duration: Duration, mut render_callback: impl FnMut(f64) -> Result<()>, ) -> Result<()> { - if ANIMATION_MANAGER.lock().in_progress(self.hwnd) { - let should_animate = self.cancel(); + if ANIMATION_MANAGER.lock().in_progress(animation_key) { + let should_animate = Self::cancel(animation_key); if !should_animate { return Ok(()); } } - ANIMATION_MANAGER.lock().start(self.hwnd); + ANIMATION_MANAGER.lock().start(animation_key); let target_frame_time = Duration::from_millis(1000 / ANIMATION_FPS.load(Ordering::Relaxed)); let mut progress = 0.0; @@ -73,9 +67,9 @@ impl Animation { // start animation while progress < 1.0 { // check if animation is cancelled - if ANIMATION_MANAGER.lock().is_cancelled(self.hwnd) { + if ANIMATION_MANAGER.lock().is_cancelled(animation_key) { // cancel animation - ANIMATION_MANAGER.lock().cancel(self.hwnd); + ANIMATION_MANAGER.lock().cancel(animation_key); return Ok(()); } @@ -92,7 +86,7 @@ impl Animation { } } - ANIMATION_MANAGER.lock().end(self.hwnd); + ANIMATION_MANAGER.lock().end(animation_key); // limit progress to 1.0 if animation took longer if progress > 1.0 { diff --git a/komorebi/src/animation/animation_manager.rs b/komorebi/src/animation/animation_manager.rs index e425a086..b610c8a6 100644 --- a/komorebi/src/animation/animation_manager.rs +++ b/komorebi/src/animation/animation_manager.rs @@ -1,7 +1,5 @@ -use super::ANIMATIONS_IN_PROGRESS; use std::collections::hash_map::Entry; use std::collections::HashMap; -use std::sync::atomic::Ordering; #[derive(Debug, Clone, Copy)] struct AnimationState { @@ -12,7 +10,7 @@ struct AnimationState { #[derive(Debug)] pub struct AnimationManager { - animations: HashMap, + animations: HashMap, } impl Default for AnimationManager { @@ -28,24 +26,24 @@ impl AnimationManager { } } - pub fn is_cancelled(&self, hwnd: isize) -> bool { - if let Some(animation_state) = self.animations.get(&hwnd) { + pub fn is_cancelled(&self, animation_key: &str) -> bool { + if let Some(animation_state) = self.animations.get(animation_key) { animation_state.pending_cancel_count > 0 } else { false } } - pub fn in_progress(&self, hwnd: isize) -> bool { - if let Some(animation_state) = self.animations.get(&hwnd) { + pub fn in_progress(&self, animation_key: &str) -> bool { + if let Some(animation_state) = self.animations.get(animation_key) { animation_state.in_progress } else { false } } - pub fn init_cancel(&mut self, hwnd: isize) -> usize { - if let Some(animation_state) = self.animations.get_mut(&hwnd) { + pub fn init_cancel(&mut self, animation_key: &str) -> usize { + if let Some(animation_state) = self.animations.get_mut(animation_key) { animation_state.pending_cancel_count += 1; animation_state.cancel_idx_counter += 1; @@ -56,51 +54,56 @@ impl AnimationManager { } } - pub fn latest_cancel_idx(&mut self, hwnd: isize) -> usize { - if let Some(animation_state) = self.animations.get_mut(&hwnd) { + pub fn latest_cancel_idx(&mut self, animation_key: &str) -> usize { + if let Some(animation_state) = self.animations.get_mut(animation_key) { animation_state.cancel_idx_counter } else { 0 } } - pub fn end_cancel(&mut self, hwnd: isize) { - if let Some(animation_state) = self.animations.get_mut(&hwnd) { + pub fn end_cancel(&mut self, animation_key: &str) { + if let Some(animation_state) = self.animations.get_mut(animation_key) { animation_state.pending_cancel_count -= 1; } } - pub fn cancel(&mut self, hwnd: isize) { - if let Some(animation_state) = self.animations.get_mut(&hwnd) { + pub fn cancel(&mut self, animation_key: &str) { + if let Some(animation_state) = self.animations.get_mut(animation_key) { animation_state.in_progress = false; } } - pub fn start(&mut self, hwnd: isize) { - if let Entry::Vacant(e) = self.animations.entry(hwnd) { + pub fn start(&mut self, animation_key: &str) { + if let Entry::Vacant(e) = self.animations.entry(animation_key.to_string()) { e.insert(AnimationState { in_progress: true, cancel_idx_counter: 0, pending_cancel_count: 0, }); - ANIMATIONS_IN_PROGRESS.store(self.animations.len(), Ordering::Release); return; } - if let Some(animation_state) = self.animations.get_mut(&hwnd) { + if let Some(animation_state) = self.animations.get_mut(animation_key) { animation_state.in_progress = true; } } - pub fn end(&mut self, hwnd: isize) { - if let Some(animation_state) = self.animations.get_mut(&hwnd) { + pub fn end(&mut self, animation_key: &str) { + if let Some(animation_state) = self.animations.get_mut(animation_key) { animation_state.in_progress = false; if animation_state.pending_cancel_count == 0 { - self.animations.remove(&hwnd); - ANIMATIONS_IN_PROGRESS.store(self.animations.len(), Ordering::Release); + self.animations.remove(animation_key); } } } + + pub fn animations_in_progress(&self, animation_key_prefix: &str) -> usize { + self.animations + .keys() + .filter(|key| key.starts_with(animation_key_prefix)) + .count() + } } diff --git a/komorebi/src/animation/mod.rs b/komorebi/src/animation/mod.rs index 5c986fcd..e35c1962 100644 --- a/komorebi/src/animation/mod.rs +++ b/komorebi/src/animation/mod.rs @@ -4,7 +4,6 @@ use crate::core::animation::AnimationStyle; use lazy_static::lazy_static; use std::sync::atomic::AtomicBool; use std::sync::atomic::AtomicU64; -use std::sync::atomic::AtomicUsize; use std::sync::Arc; use parking_lot::Mutex; @@ -25,4 +24,3 @@ lazy_static! { pub static ANIMATION_ENABLED: AtomicBool = AtomicBool::new(false); pub static ANIMATION_DURATION: AtomicU64 = AtomicU64::new(250); pub static ANIMATION_FPS: AtomicU64 = AtomicU64::new(60); -pub static ANIMATIONS_IN_PROGRESS: AtomicUsize = AtomicUsize::new(0); diff --git a/komorebi/src/window.rs b/komorebi/src/window.rs index e6c23ecd..10df51d0 100644 --- a/komorebi/src/window.rs +++ b/komorebi/src/window.rs @@ -1,7 +1,7 @@ use crate::animation::lerp::Lerp; -use crate::animation::ANIMATIONS_IN_PROGRESS; use crate::animation::ANIMATION_DURATION; use crate::animation::ANIMATION_ENABLED; +use crate::animation::ANIMATION_MANAGER; use crate::animation::ANIMATION_STYLE; use crate::border_manager; use crate::com::SetCloak; @@ -60,16 +60,11 @@ pub static MINIMUM_HEIGHT: AtomicI32 = AtomicI32::new(0); #[derive(Debug, Default, Clone, Copy, Deserialize, JsonSchema, PartialEq)] pub struct Window { pub hwnd: isize, - #[serde(skip)] - animation: Animation, } impl From for Window { fn from(value: isize) -> Self { - Self { - hwnd: value, - animation: Animation::new(value), - } + Self { hwnd: value } } } @@ -77,7 +72,6 @@ impl From for Window { fn from(value: HWND) -> Self { Self { hwnd: value.0 as isize, - animation: Animation::new(value.0 as isize), } } } @@ -205,7 +199,6 @@ impl Window { pub fn animate_position(&self, start_rect: &Rect, target_rect: &Rect, top: bool) -> Result<()> { let start_rect = *start_rect; let target_rect = *target_rect; - let mut animation = self.animation; let duration = Duration::from_millis(ANIMATION_DURATION.load(Ordering::SeqCst)); let style = *ANIMATION_STYLE.lock(); @@ -218,33 +211,42 @@ impl Window { let hwnd = self.hwnd; std::thread::spawn(move || { - animation.animate(duration, |progress: f64| { - let new_rect = start_rect.lerp(target_rect, progress, style); + Animation::animate( + format!("window_move:{}", hwnd).as_str(), + duration, + |progress: f64| { + let new_rect = start_rect.lerp(target_rect, progress, style); - if progress == 1.0 { - WindowsApi::position_window(hwnd, &new_rect, top)?; - if WindowsApi::foreground_window().unwrap_or_default() == hwnd { - focus_manager::send_notification(hwnd) + if progress == 1.0 { + WindowsApi::position_window(hwnd, &new_rect, top)?; + if WindowsApi::foreground_window().unwrap_or_default() == hwnd { + focus_manager::send_notification(hwnd) + } + + if ANIMATION_MANAGER + .lock() + .animations_in_progress("window_move") + == 0 + { + border_manager::BORDER_TEMPORARILY_DISABLED + .store(false, Ordering::SeqCst); + stackbar_manager::STACKBAR_TEMPORARILY_DISABLED + .store(false, Ordering::SeqCst); + + border_manager::send_notification(Some(hwnd)); + stackbar_manager::send_notification(); + transparency_manager::send_notification(); + } + } else { + // using MoveWindow because it runs faster than SetWindowPos + // so animation have more fps and feel smoother + WindowsApi::move_window(hwnd, &new_rect, false)?; + WindowsApi::invalidate_rect(hwnd, None, false); } - if ANIMATIONS_IN_PROGRESS.load(Ordering::Acquire) == 0 { - border_manager::BORDER_TEMPORARILY_DISABLED.store(false, Ordering::SeqCst); - stackbar_manager::STACKBAR_TEMPORARILY_DISABLED - .store(false, Ordering::SeqCst); - - border_manager::send_notification(Some(hwnd)); - stackbar_manager::send_notification(); - transparency_manager::send_notification(); - } - } else { - // using MoveWindow because it runs faster than SetWindowPos - // so animation have more fps and feel smoother - WindowsApi::move_window(hwnd, &new_rect, false)?; - WindowsApi::invalidate_rect(hwnd, None, false); - } - - Ok(()) - }) + Ok(()) + }, + ) }); Ok(())