fix(animation): add async focus manager for mff

This commit adds a new focus manager module to be used to trigger async
focus changes with mouse follows focus updates. Currently this should
only need to be used with animations as all other focus calls are
synchronous.

fix #910
This commit is contained in:
LGUG2Z
2024-07-11 18:29:44 -07:00
parent bdc1cad597
commit 2c8f25ef82
4 changed files with 77 additions and 0 deletions

View File

@@ -0,0 +1,70 @@
#![deny(clippy::unwrap_used, clippy::expect_used)]
use crossbeam_channel::Receiver;
use crossbeam_channel::Sender;
use parking_lot::Mutex;
use std::ops::Deref;
use std::sync::Arc;
use std::sync::OnceLock;
use crate::Window;
use crate::WindowManager;
pub struct Notification(isize);
impl Deref for Notification {
type Target = isize;
fn deref(&self) -> &Self::Target {
&self.0
}
}
static CHANNEL: OnceLock<(Sender<Notification>, Receiver<Notification>)> = OnceLock::new();
pub fn channel() -> &'static (Sender<Notification>, Receiver<Notification>) {
CHANNEL.get_or_init(|| crossbeam_channel::bounded(20))
}
fn event_tx() -> Sender<Notification> {
channel().0.clone()
}
fn event_rx() -> Receiver<Notification> {
channel().1.clone()
}
// Currently this should only be used for async focus updates, such as
// when an animation finishes and we need to focus to set the cursor
// position if the user has mouse follows focus enabled
pub fn send_notification(hwnd: isize) {
if event_tx().try_send(Notification(hwnd)).is_err() {
tracing::warn!("channel is full; dropping notification")
}
}
pub fn listen_for_notifications(wm: Arc<Mutex<WindowManager>>) {
std::thread::spawn(move || loop {
match handle_notifications(wm.clone()) {
Ok(()) => {
tracing::warn!("restarting finished thread");
}
Err(error) => {
tracing::warn!("restarting failed thread: {}", error);
}
}
});
}
pub fn handle_notifications(wm: Arc<Mutex<WindowManager>>) -> color_eyre::Result<()> {
tracing::info!("listening");
let receiver = event_rx();
for notification in receiver {
let mouse_follows_focus = wm.lock().mouse_follows_focus;
let _ = Window::from(*notification).focus(mouse_follows_focus);
}
Ok(())
}

View File

@@ -8,6 +8,7 @@ pub mod com;
pub mod ring;
pub mod colour;
pub mod container;
pub mod focus_manager;
pub mod monitor;
pub mod monitor_reconciliator;
pub mod process_command;

View File

@@ -25,6 +25,7 @@ use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::EnvFilter;
use komorebi::border_manager;
use komorebi::focus_manager;
use komorebi::load_configuration;
use komorebi::monitor_reconciliator;
use komorebi::process_command::listen_for_commands;
@@ -265,6 +266,7 @@ fn main() -> Result<()> {
workspace_reconciliator::listen_for_notifications(wm.clone());
monitor_reconciliator::listen_for_notifications(wm.clone())?;
reaper::watch_for_orphans(wm.clone());
focus_manager::listen_for_notifications(wm.clone());
let (ctrlc_sender, ctrlc_receiver) = crossbeam_channel::bounded(1);
ctrlc::set_handler(move || {

View File

@@ -1,5 +1,6 @@
use crate::border_manager;
use crate::com::SetCloak;
use crate::focus_manager;
use crate::stackbar_manager;
use crate::ANIMATIONS_IN_PROGRESS;
use crate::ANIMATION_DURATION;
@@ -189,6 +190,9 @@ impl Window {
if progress == 1.0 {
WindowsApi::position_window(hwnd, &new_rect, top)?;
if WindowsApi::foreground_window().unwrap_or_default() == hwnd.0 {
focus_manager::send_notification(hwnd.0)
}
if ANIMATIONS_IN_PROGRESS.load(Ordering::Acquire) == 0 {
border_manager::BORDER_TEMPORARILY_DISABLED.store(false, Ordering::SeqCst);