mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-07-09 06:25:23 +02:00
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.
This commit is contained in:
@@ -13,29 +13,23 @@ use super::ANIMATION_FPS;
|
|||||||
use super::ANIMATION_MANAGER;
|
use super::ANIMATION_MANAGER;
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq)]
|
#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq)]
|
||||||
pub struct Animation {
|
pub struct Animation {}
|
||||||
pub hwnd: isize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Animation {
|
impl Animation {
|
||||||
pub fn new(hwnd: isize) -> Self {
|
|
||||||
Self { hwnd }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if the animation needs to continue
|
/// Returns true if the animation needs to continue
|
||||||
pub fn cancel(&mut self) -> bool {
|
pub fn cancel(animation_key: &str) -> bool {
|
||||||
if !ANIMATION_MANAGER.lock().in_progress(self.hwnd) {
|
if !ANIMATION_MANAGER.lock().in_progress(animation_key) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// should be more than 0
|
// 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 max_duration = Duration::from_secs(1);
|
||||||
let spent_duration = Instant::now();
|
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 {
|
if spent_duration.elapsed() >= max_duration {
|
||||||
ANIMATION_MANAGER.lock().end(self.hwnd);
|
ANIMATION_MANAGER.lock().end(animation_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::thread::sleep(Duration::from_millis(
|
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
|
latest_cancel_idx == cancel_idx
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::cast_precision_loss)]
|
#[allow(clippy::cast_precision_loss)]
|
||||||
pub fn animate(
|
pub fn animate(
|
||||||
&mut self,
|
animation_key: &str,
|
||||||
duration: Duration,
|
duration: Duration,
|
||||||
mut render_callback: impl FnMut(f64) -> Result<()>,
|
mut render_callback: impl FnMut(f64) -> Result<()>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
if ANIMATION_MANAGER.lock().in_progress(self.hwnd) {
|
if ANIMATION_MANAGER.lock().in_progress(animation_key) {
|
||||||
let should_animate = self.cancel();
|
let should_animate = Self::cancel(animation_key);
|
||||||
|
|
||||||
if !should_animate {
|
if !should_animate {
|
||||||
return Ok(());
|
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 target_frame_time = Duration::from_millis(1000 / ANIMATION_FPS.load(Ordering::Relaxed));
|
||||||
let mut progress = 0.0;
|
let mut progress = 0.0;
|
||||||
@@ -73,9 +67,9 @@ impl Animation {
|
|||||||
// start animation
|
// start animation
|
||||||
while progress < 1.0 {
|
while progress < 1.0 {
|
||||||
// check if animation is cancelled
|
// check if animation is cancelled
|
||||||
if ANIMATION_MANAGER.lock().is_cancelled(self.hwnd) {
|
if ANIMATION_MANAGER.lock().is_cancelled(animation_key) {
|
||||||
// cancel animation
|
// cancel animation
|
||||||
ANIMATION_MANAGER.lock().cancel(self.hwnd);
|
ANIMATION_MANAGER.lock().cancel(animation_key);
|
||||||
return Ok(());
|
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
|
// limit progress to 1.0 if animation took longer
|
||||||
if progress > 1.0 {
|
if progress > 1.0 {
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
use super::ANIMATIONS_IN_PROGRESS;
|
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::atomic::Ordering;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
struct AnimationState {
|
struct AnimationState {
|
||||||
@@ -12,7 +10,7 @@ struct AnimationState {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct AnimationManager {
|
pub struct AnimationManager {
|
||||||
animations: HashMap<isize, AnimationState>,
|
animations: HashMap<String, AnimationState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for AnimationManager {
|
impl Default for AnimationManager {
|
||||||
@@ -28,24 +26,24 @@ impl AnimationManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_cancelled(&self, hwnd: isize) -> bool {
|
pub fn is_cancelled(&self, animation_key: &str) -> bool {
|
||||||
if let Some(animation_state) = self.animations.get(&hwnd) {
|
if let Some(animation_state) = self.animations.get(animation_key) {
|
||||||
animation_state.pending_cancel_count > 0
|
animation_state.pending_cancel_count > 0
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn in_progress(&self, hwnd: isize) -> bool {
|
pub fn in_progress(&self, animation_key: &str) -> bool {
|
||||||
if let Some(animation_state) = self.animations.get(&hwnd) {
|
if let Some(animation_state) = self.animations.get(animation_key) {
|
||||||
animation_state.in_progress
|
animation_state.in_progress
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init_cancel(&mut self, hwnd: isize) -> usize {
|
pub fn init_cancel(&mut self, animation_key: &str) -> usize {
|
||||||
if let Some(animation_state) = self.animations.get_mut(&hwnd) {
|
if let Some(animation_state) = self.animations.get_mut(animation_key) {
|
||||||
animation_state.pending_cancel_count += 1;
|
animation_state.pending_cancel_count += 1;
|
||||||
animation_state.cancel_idx_counter += 1;
|
animation_state.cancel_idx_counter += 1;
|
||||||
|
|
||||||
@@ -56,51 +54,56 @@ impl AnimationManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn latest_cancel_idx(&mut self, hwnd: isize) -> usize {
|
pub fn latest_cancel_idx(&mut self, animation_key: &str) -> usize {
|
||||||
if let Some(animation_state) = self.animations.get_mut(&hwnd) {
|
if let Some(animation_state) = self.animations.get_mut(animation_key) {
|
||||||
animation_state.cancel_idx_counter
|
animation_state.cancel_idx_counter
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn end_cancel(&mut self, hwnd: isize) {
|
pub fn end_cancel(&mut self, animation_key: &str) {
|
||||||
if let Some(animation_state) = self.animations.get_mut(&hwnd) {
|
if let Some(animation_state) = self.animations.get_mut(animation_key) {
|
||||||
animation_state.pending_cancel_count -= 1;
|
animation_state.pending_cancel_count -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cancel(&mut self, hwnd: isize) {
|
pub fn cancel(&mut self, animation_key: &str) {
|
||||||
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 = false;
|
animation_state.in_progress = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start(&mut self, hwnd: isize) {
|
pub fn start(&mut self, animation_key: &str) {
|
||||||
if let Entry::Vacant(e) = self.animations.entry(hwnd) {
|
if let Entry::Vacant(e) = self.animations.entry(animation_key.to_string()) {
|
||||||
e.insert(AnimationState {
|
e.insert(AnimationState {
|
||||||
in_progress: true,
|
in_progress: true,
|
||||||
cancel_idx_counter: 0,
|
cancel_idx_counter: 0,
|
||||||
pending_cancel_count: 0,
|
pending_cancel_count: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
ANIMATIONS_IN_PROGRESS.store(self.animations.len(), Ordering::Release);
|
|
||||||
return;
|
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;
|
animation_state.in_progress = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn end(&mut self, hwnd: isize) {
|
pub fn end(&mut self, animation_key: &str) {
|
||||||
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 = false;
|
animation_state.in_progress = false;
|
||||||
|
|
||||||
if animation_state.pending_cancel_count == 0 {
|
if animation_state.pending_cancel_count == 0 {
|
||||||
self.animations.remove(&hwnd);
|
self.animations.remove(animation_key);
|
||||||
ANIMATIONS_IN_PROGRESS.store(self.animations.len(), Ordering::Release);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn animations_in_progress(&self, animation_key_prefix: &str) -> usize {
|
||||||
|
self.animations
|
||||||
|
.keys()
|
||||||
|
.filter(|key| key.starts_with(animation_key_prefix))
|
||||||
|
.count()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ use crate::core::animation::AnimationStyle;
|
|||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use std::sync::atomic::AtomicBool;
|
use std::sync::atomic::AtomicBool;
|
||||||
use std::sync::atomic::AtomicU64;
|
use std::sync::atomic::AtomicU64;
|
||||||
use std::sync::atomic::AtomicUsize;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
@@ -25,4 +24,3 @@ lazy_static! {
|
|||||||
pub static ANIMATION_ENABLED: AtomicBool = AtomicBool::new(false);
|
pub static ANIMATION_ENABLED: AtomicBool = AtomicBool::new(false);
|
||||||
pub static ANIMATION_DURATION: AtomicU64 = AtomicU64::new(250);
|
pub static ANIMATION_DURATION: AtomicU64 = AtomicU64::new(250);
|
||||||
pub static ANIMATION_FPS: AtomicU64 = AtomicU64::new(60);
|
pub static ANIMATION_FPS: AtomicU64 = AtomicU64::new(60);
|
||||||
pub static ANIMATIONS_IN_PROGRESS: AtomicUsize = AtomicUsize::new(0);
|
|
||||||
|
|||||||
+35
-33
@@ -1,7 +1,7 @@
|
|||||||
use crate::animation::lerp::Lerp;
|
use crate::animation::lerp::Lerp;
|
||||||
use crate::animation::ANIMATIONS_IN_PROGRESS;
|
|
||||||
use crate::animation::ANIMATION_DURATION;
|
use crate::animation::ANIMATION_DURATION;
|
||||||
use crate::animation::ANIMATION_ENABLED;
|
use crate::animation::ANIMATION_ENABLED;
|
||||||
|
use crate::animation::ANIMATION_MANAGER;
|
||||||
use crate::animation::ANIMATION_STYLE;
|
use crate::animation::ANIMATION_STYLE;
|
||||||
use crate::border_manager;
|
use crate::border_manager;
|
||||||
use crate::com::SetCloak;
|
use crate::com::SetCloak;
|
||||||
@@ -60,16 +60,11 @@ pub static MINIMUM_HEIGHT: AtomicI32 = AtomicI32::new(0);
|
|||||||
#[derive(Debug, Default, Clone, Copy, Deserialize, JsonSchema, PartialEq)]
|
#[derive(Debug, Default, Clone, Copy, Deserialize, JsonSchema, PartialEq)]
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
pub hwnd: isize,
|
pub hwnd: isize,
|
||||||
#[serde(skip)]
|
|
||||||
animation: Animation,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<isize> for Window {
|
impl From<isize> for Window {
|
||||||
fn from(value: isize) -> Self {
|
fn from(value: isize) -> Self {
|
||||||
Self {
|
Self { hwnd: value }
|
||||||
hwnd: value,
|
|
||||||
animation: Animation::new(value),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,7 +72,6 @@ impl From<HWND> for Window {
|
|||||||
fn from(value: HWND) -> Self {
|
fn from(value: HWND) -> Self {
|
||||||
Self {
|
Self {
|
||||||
hwnd: value.0 as isize,
|
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<()> {
|
pub fn animate_position(&self, start_rect: &Rect, target_rect: &Rect, top: bool) -> Result<()> {
|
||||||
let start_rect = *start_rect;
|
let start_rect = *start_rect;
|
||||||
let target_rect = *target_rect;
|
let target_rect = *target_rect;
|
||||||
let mut animation = self.animation;
|
|
||||||
let duration = Duration::from_millis(ANIMATION_DURATION.load(Ordering::SeqCst));
|
let duration = Duration::from_millis(ANIMATION_DURATION.load(Ordering::SeqCst));
|
||||||
let style = *ANIMATION_STYLE.lock();
|
let style = *ANIMATION_STYLE.lock();
|
||||||
|
|
||||||
@@ -218,33 +211,42 @@ impl Window {
|
|||||||
let hwnd = self.hwnd;
|
let hwnd = self.hwnd;
|
||||||
|
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
animation.animate(duration, |progress: f64| {
|
Animation::animate(
|
||||||
let new_rect = start_rect.lerp(target_rect, progress, style);
|
format!("window_move:{}", hwnd).as_str(),
|
||||||
|
duration,
|
||||||
|
|progress: f64| {
|
||||||
|
let new_rect = start_rect.lerp(target_rect, progress, style);
|
||||||
|
|
||||||
if progress == 1.0 {
|
if progress == 1.0 {
|
||||||
WindowsApi::position_window(hwnd, &new_rect, top)?;
|
WindowsApi::position_window(hwnd, &new_rect, top)?;
|
||||||
if WindowsApi::foreground_window().unwrap_or_default() == hwnd {
|
if WindowsApi::foreground_window().unwrap_or_default() == hwnd {
|
||||||
focus_manager::send_notification(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 {
|
Ok(())
|
||||||
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(())
|
||||||
|
|||||||
Reference in New Issue
Block a user