awatcher/watchers/src/watchers.rs
2024-02-03 16:47:47 -05:00

140 lines
3.9 KiB
Rust

#[cfg(feature = "gnome")]
mod gnome_idle;
#[cfg(feature = "gnome")]
mod gnome_wayland;
#[cfg(feature = "gnome")]
mod gnome_window;
mod idle;
#[cfg(feature = "kwin_window")]
mod kwin_window;
mod wl_connection;
mod wl_ext_idle_notify;
mod wl_foreign_toplevel;
mod wl_kwin_idle;
mod x11_connection;
mod x11_screensaver_idle;
mod x11_window;
use crate::{config::Config, report_client::ReportClient};
use async_trait::async_trait;
use std::{fmt::Display, sync::Arc};
use tokio::time;
pub enum WatcherType {
Idle,
ActiveWindow,
}
impl WatcherType {
fn sleep_time(&self, config: &Config) -> time::Duration {
match self {
WatcherType::Idle => config.poll_time_idle,
WatcherType::ActiveWindow => config.poll_time_window,
}
}
}
impl Display for WatcherType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
WatcherType::Idle => write!(f, "idle"),
WatcherType::ActiveWindow => write!(f, "active window"),
}
}
}
#[async_trait]
pub trait Watcher: Send {
async fn new(client: &Arc<ReportClient>) -> anyhow::Result<Self>
where
Self: Sized;
async fn run_iteration(&mut self, client: &Arc<ReportClient>) -> anyhow::Result<()>;
}
async fn create_watcher<T: Watcher>(client: &Arc<ReportClient>, name: &str) -> Option<T> {
match T::new(client).await {
Ok(watcher) => {
info!("Selected watcher: {name}");
Some(watcher)
}
Err(e) => {
debug!("Watcher \"{name}\" cannot run: {e}");
None
}
}
}
macro_rules! watch {
($watcher:expr) => {
if let Some(watcher) = $watcher.await {
return Some(Box::new(watcher));
}
};
}
async fn filter_first_supported(
client: &Arc<ReportClient>,
watcher_type: &WatcherType,
) -> Option<Box<dyn Watcher>> {
match watcher_type {
WatcherType::Idle => {
watch!(create_watcher::<wl_ext_idle_notify::IdleWatcher>(
client,
"Wayland idle (ext_idle_notification_v1)"
));
watch!(create_watcher::<wl_kwin_idle::IdleWatcher>(
client,
"Wayland idle (KWin)"
));
watch!(create_watcher::<x11_screensaver_idle::IdleWatcher>(
client,
"X11 idle (screensaver)"
));
#[cfg(feature = "gnome")]
watch!(create_watcher::<gnome_idle::IdleWatcher>(
client,
"Gnome idle (Mutter/IdleMonitor)"
));
}
WatcherType::ActiveWindow => {
watch!(create_watcher::<wl_foreign_toplevel::WindowWatcher>(
client,
"Wayland window (wlr-foreign-toplevel-management-unstable-v1)"
));
// XWayland gives _NET_WM_NAME on some windows in KDE, but not on others
#[cfg(feature = "kwin_window")]
watch!(create_watcher::<kwin_window::WindowWatcher>(
client,
"KWin window (script)"
));
watch!(create_watcher::<x11_window::WindowWatcher>(
client,
"X11 window"
));
#[cfg(feature = "gnome")]
watch!(create_watcher::<gnome_window::WindowWatcher>(
client,
"Gnome window (extension)"
));
}
};
None
}
pub async fn run_first_supported(client: Arc<ReportClient>, watcher_type: &WatcherType) -> bool {
let supported_watcher = filter_first_supported(&client, watcher_type).await;
if let Some(mut watcher) = supported_watcher {
info!("Starting {watcher_type} watcher");
loop {
if let Err(e) = watcher.run_iteration(&client).await {
error!("Error on {watcher_type} iteration: {e}");
}
time::sleep(watcher_type.sleep_time(&client.config)).await;
}
}
false
}