diff --git a/komorebi/src/animation/ghost.rs b/komorebi/src/animation/ghost.rs index 94f91ffe..e0fd1a5a 100644 --- a/komorebi/src/animation/ghost.rs +++ b/komorebi/src/animation/ghost.rs @@ -273,6 +273,11 @@ impl GhostHost { (self.bounds.0, self.bounds.1) } + /// Whether there are no ghosts + fn is_idle(&self) -> bool { + self.thumbnails.is_empty() + } + fn register( &mut self, snapshot: &Snapshot, @@ -396,6 +401,22 @@ unsafe fn init_layered_transparent(hwnd: HWND) { } } +/// How often the owner thread looks for messages for its windows when no +/// command comes. While there are ghosts that is often, so that they are never +/// kept waiting; while there are none the windows it has are a host nobody can +/// see and nothing is sent to, and waking up every few milliseconds for them +/// keeps the processor from sleeping. +fn poll_interval(idle: bool) -> Duration { + if idle { + IDLE_POLL_INTERVAL + } else { + BUSY_POLL_INTERVAL + } +} + +const BUSY_POLL_INTERVAL: Duration = Duration::from_millis(8); +const IDLE_POLL_INTERVAL: Duration = Duration::from_millis(250); + fn run_owner_loop(cmd_rx: crossbeam_channel::Receiver) { let mut host = match GhostHost::create() { Ok(host) => Some(host), @@ -415,7 +436,7 @@ fn run_owner_loop(cmd_rx: crossbeam_channel::Receiver) { } } - match cmd_rx.recv_timeout(Duration::from_millis(8)) { + match cmd_rx.recv_timeout(poll_interval(host.as_ref().is_some_and(GhostHost::is_idle))) { Ok(GhostCmd::Create { snapshot, start_rect, @@ -658,6 +679,13 @@ mod tests { assert!(!is_swap_chain_class("")); } + #[test] + fn the_owner_thread_polls_slowly_when_there_are_no_ghosts() { + assert_eq!(poll_interval(false), BUSY_POLL_INTERVAL); + assert_eq!(poll_interval(true), IDLE_POLL_INTERVAL); + assert!(IDLE_POLL_INTERVAL >= BUSY_POLL_INTERVAL * 10); + } + #[test] fn the_ghost_is_opaque_until_the_window_is_shown_and_gone_at_the_end() { assert_eq!(ghost_opacity(0.0, REVEAL_AT), 255);