Refactor to use common watchers loop

This commit is contained in:
Demmie 2023-05-11 18:42:18 -04:00
parent cdc05e0d5f
commit 79f8e53850
No known key found for this signature in database
GPG Key ID: B06DAA3D432C6E9A
8 changed files with 199 additions and 197 deletions

View File

@ -13,38 +13,96 @@ mod x11_connection;
mod x11_screensaver_idle; mod x11_screensaver_idle;
mod x11_window; mod x11_window;
use crate::report_client::ReportClient; use crate::{config::Config, report_client::ReportClient};
use std::{ use std::{
sync::{atomic::AtomicBool, Arc}, fmt::Display,
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
thread::{self, JoinHandle}, thread::{self, JoinHandle},
time::Duration,
}; };
pub enum WatcherType {
Idle,
ActiveWindow,
}
impl WatcherType {
fn sleep_time(&self, config: &Config) -> Duration {
match self {
WatcherType::Idle => config.poll_time_idle,
WatcherType::ActiveWindow => config.poll_time_idle,
}
}
}
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"),
}
}
}
pub trait Watcher: Send { pub trait Watcher: Send {
fn new() -> anyhow::Result<Self> fn new(client: &Arc<ReportClient>) -> anyhow::Result<Self>
where where
Self: Sized; Self: Sized;
fn watch(&mut self, client: &Arc<ReportClient>, is_stopped: Arc<AtomicBool>);
fn run(
&mut self,
watcher_type: &WatcherType,
client: &Arc<ReportClient>,
is_stopped: Arc<AtomicBool>,
) {
info!("Starting {watcher_type} watcher");
loop {
if is_stopped.load(Ordering::Relaxed) {
warn!("Received an exit signal, shutting down {watcher_type}");
break;
}
self.run_iteration(client);
thread::sleep(watcher_type.sleep_time(&client.config));
}
}
fn run_iteration(&mut self, client: &Arc<ReportClient>);
} }
type BoxedWatcher = Box<dyn Watcher>; type BoxedWatcher = Box<dyn Watcher>;
type WatcherConstructors = [(
type WatcherConstructor = (&'static str, fn() -> anyhow::Result<BoxedWatcher>); &'static str,
type WatcherConstructors = [WatcherConstructor]; WatcherType,
fn(&Arc<ReportClient>) -> anyhow::Result<BoxedWatcher>,
)];
pub trait ConstructorFilter { pub trait ConstructorFilter {
fn filter_first_supported(&self) -> Option<BoxedWatcher>; fn filter_first_supported(
&self,
client: &Arc<ReportClient>,
) -> Option<(&WatcherType, BoxedWatcher)>;
fn run_first_supported( fn run_first_supported(
&self, &'static self,
client: &Arc<ReportClient>, client: &Arc<ReportClient>,
is_stopped: Arc<AtomicBool>, is_stopped: Arc<AtomicBool>,
) -> Option<JoinHandle<()>>; ) -> Option<JoinHandle<()>>;
} }
impl ConstructorFilter for WatcherConstructors { impl ConstructorFilter for WatcherConstructors {
fn filter_first_supported(&self) -> Option<BoxedWatcher> { fn filter_first_supported(
self.iter().find_map(|(name, watcher)| match watcher() { &self,
Ok(watcher) => Some(watcher), client: &Arc<ReportClient>,
) -> Option<(&WatcherType, BoxedWatcher)> {
self.iter()
.find_map(|(name, watcher_type, watcher)| match watcher(client) {
Ok(watcher) => {
info!("Selected {name} as {watcher_type} watcher");
Some((watcher_type, watcher))
}
Err(e) => { Err(e) => {
debug!("{name} cannot run: {e}"); debug!("{name} cannot run: {e}");
None None
@ -53,14 +111,15 @@ impl ConstructorFilter for WatcherConstructors {
} }
fn run_first_supported( fn run_first_supported(
&self, &'static self,
client: &Arc<ReportClient>, client: &Arc<ReportClient>,
is_stopped: Arc<AtomicBool>, is_stopped: Arc<AtomicBool>,
) -> Option<JoinHandle<()>> { ) -> Option<JoinHandle<()>> {
let idle_watcher = self.filter_first_supported(); let idle_watcher = self.filter_first_supported(client);
if let Some(mut watcher) = idle_watcher { if let Some((watcher_type, mut watcher)) = idle_watcher {
let thread_client = Arc::clone(client); let thread_client = Arc::clone(client);
let idle_handler = thread::spawn(move || watcher.watch(&thread_client, is_stopped)); let idle_handler =
thread::spawn(move || watcher.run(watcher_type, &thread_client, is_stopped));
Some(idle_handler) Some(idle_handler)
} else { } else {
None None
@ -69,26 +128,29 @@ impl ConstructorFilter for WatcherConstructors {
} }
macro_rules! watcher { macro_rules! watcher {
($watcher_struct:ty) => { ($watcher_struct:ty, $watcher_type:expr) => {
(stringify!($watcher_struct), || { (stringify!($watcher_struct), $watcher_type, |client| {
Ok(Box::new(<$watcher_struct>::new()?)) Ok(Box::new(<$watcher_struct>::new(client)?))
}) })
}; };
} }
pub const IDLE: &WatcherConstructors = &[ pub const IDLE: &WatcherConstructors = &[
watcher!(wl_kwin_idle::IdleWatcher), watcher!(wl_kwin_idle::IdleWatcher, WatcherType::Idle),
watcher!(x11_screensaver_idle::IdleWatcher), watcher!(x11_screensaver_idle::IdleWatcher, WatcherType::Idle),
#[cfg(feature = "gnome")] #[cfg(feature = "gnome")]
watcher!(gnome_idle::IdleWatcher), watcher!(gnome_idle::IdleWatcher, WatcherType::Idle),
]; ];
pub const ACTIVE_WINDOW: &WatcherConstructors = &[ pub const ACTIVE_WINDOW: &WatcherConstructors = &[
watcher!(wl_foreign_toplevel::WindowWatcher), watcher!(
wl_foreign_toplevel::WindowWatcher,
WatcherType::ActiveWindow
),
// XWayland gives _NET_WM_NAME on some windows in KDE, but not on others // XWayland gives _NET_WM_NAME on some windows in KDE, but not on others
#[cfg(feature = "kwin_window")] #[cfg(feature = "kwin_window")]
watcher!(kwin_window::WindowWatcher), watcher!(kwin_window::WindowWatcher, WatcherType::ActiveWindow),
watcher!(x11_window::WindowWatcher), watcher!(x11_window::WindowWatcher, WatcherType::ActiveWindow),
#[cfg(feature = "gnome")] #[cfg(feature = "gnome")]
watcher!(gnome_window::WindowWatcher), watcher!(gnome_window::WindowWatcher, WatcherType::ActiveWindow),
]; ];

View File

@ -1,13 +1,12 @@
use super::{idle, Watcher}; use super::{idle, Watcher};
use crate::report_client::ReportClient; use crate::report_client::ReportClient;
use anyhow::Context; use anyhow::Context;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc; use std::sync::Arc;
use std::thread;
use zbus::blocking::Connection; use zbus::blocking::Connection;
pub struct IdleWatcher { pub struct IdleWatcher {
dbus_connection: Connection, dbus_connection: Connection,
is_idle: bool,
} }
impl idle::SinceLastInput for IdleWatcher { impl idle::SinceLastInput for IdleWatcher {
@ -27,30 +26,22 @@ impl idle::SinceLastInput for IdleWatcher {
} }
impl Watcher for IdleWatcher { impl Watcher for IdleWatcher {
fn new() -> anyhow::Result<Self> { fn new(_: &Arc<ReportClient>) -> anyhow::Result<Self> {
let mut watcher = Self { let mut watcher = Self {
dbus_connection: Connection::session()?, dbus_connection: Connection::session()?,
is_idle: false,
}; };
idle::SinceLastInput::seconds_since_input(&mut watcher)?; idle::SinceLastInput::seconds_since_input(&mut watcher)?;
Ok(watcher) Ok(watcher)
} }
fn watch(&mut self, client: &Arc<ReportClient>, is_stopped: Arc<AtomicBool>) { fn run_iteration(&mut self, client: &Arc<ReportClient>) {
let mut is_idle = false; match idle::ping_since_last_input(self, self.is_idle, client) {
info!("Starting idle watcher");
loop {
if is_stopped.load(Ordering::Relaxed) {
warn!("Received an exit signal, shutting down");
break;
}
match idle::ping_since_last_input(self, is_idle, client) {
Ok(is_idle_again) => { Ok(is_idle_again) => {
is_idle = is_idle_again; self.is_idle = is_idle_again;
} }
Err(e) => error!("Error on idle iteration: {e}"), Err(e) => error!("Error on idle iteration: {e}"),
}; };
thread::sleep(client.config.poll_time_idle);
}
} }
} }

View File

@ -1,9 +1,7 @@
use crate::report_client::ReportClient; use crate::report_client::ReportClient;
use anyhow::Context; use anyhow::Context;
use serde::Deserialize; use serde::Deserialize;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc; use std::sync::Arc;
use std::thread;
use zbus::blocking::Connection; use zbus::blocking::Connection;
use super::Watcher; use super::Watcher;
@ -77,7 +75,7 @@ impl WindowWatcher {
} }
impl Watcher for WindowWatcher { impl Watcher for WindowWatcher {
fn new() -> anyhow::Result<Self> { fn new(_: &Arc<ReportClient>) -> anyhow::Result<Self> {
let watcher = Self { let watcher = Self {
dbus_connection: Connection::session()?, dbus_connection: Connection::session()?,
last_app_id: String::new(), last_app_id: String::new(),
@ -87,17 +85,9 @@ impl Watcher for WindowWatcher {
Ok(watcher) Ok(watcher)
} }
fn watch(&mut self, client: &Arc<ReportClient>, is_stopped: Arc<AtomicBool>) { fn run_iteration(&mut self, client: &Arc<ReportClient>) {
info!("Starting active window watcher");
loop {
if is_stopped.load(Ordering::Relaxed) {
warn!("Received an exit signal, shutting down");
break;
}
if let Err(error) = self.send_active_window(client) { if let Err(error) = self.send_active_window(client) {
error!("Error on active window: {error}"); error!("Error on active window: {error}");
} }
thread::sleep(client.config.poll_time_window);
}
} }
} }

View File

@ -8,7 +8,6 @@ use crate::report_client::ReportClient;
use anyhow::{anyhow, Context}; use anyhow::{anyhow, Context};
use std::env::temp_dir; use std::env::temp_dir;
use std::path::Path; use std::path::Path;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{mpsc::channel, Arc, Mutex}; use std::sync::{mpsc::channel, Arc, Mutex};
use std::thread; use std::thread;
use zbus::blocking::{Connection, ConnectionBuilder}; use zbus::blocking::{Connection, ConnectionBuilder};
@ -151,22 +150,19 @@ impl ActiveWindowInterface {
} }
pub struct WindowWatcher { pub struct WindowWatcher {
kwin_script: KWinScript, active_window: Arc<Mutex<ActiveWindow>>,
// Prolong its lifetime
_kwin_script: KWinScript,
} }
impl Watcher for WindowWatcher { impl Watcher for WindowWatcher {
fn new() -> anyhow::Result<Self> { fn new(_: &Arc<ReportClient>) -> anyhow::Result<Self> {
let kwin_script = KWinScript::new(Connection::session()?); let mut kwin_script = KWinScript::new(Connection::session()?);
if kwin_script.is_loaded()? { if kwin_script.is_loaded()? {
debug!("KWin script is already loaded, unloading"); debug!("KWin script is already loaded, unloading");
kwin_script.unload()?; kwin_script.unload()?;
} }
kwin_script.load().unwrap();
Ok(Self { kwin_script })
}
fn watch(&mut self, client: &Arc<ReportClient>, is_stopped: Arc<AtomicBool>) {
self.kwin_script.load().unwrap();
let active_window = Arc::new(Mutex::new(ActiveWindow { let active_window = Arc::new(Mutex::new(ActiveWindow {
caption: String::new(), caption: String::new(),
@ -199,16 +195,15 @@ impl Watcher for WindowWatcher {
panic!("Failed to run a DBus interface: {error}"); panic!("Failed to run a DBus interface: {error}");
} }
info!("Starting active window watcher"); Ok(Self {
loop { active_window,
if is_stopped.load(Ordering::Relaxed) { _kwin_script: kwin_script,
warn!("Received an exit signal, shutting down"); })
break;
} }
if let Err(error) = send_active_window(client, &active_window) {
fn run_iteration(&mut self, client: &Arc<ReportClient>) {
if let Err(error) = send_active_window(client, &self.active_window) {
error!("Error on sending active window: {error}"); error!("Error on sending active window: {error}");
} }
thread::sleep(client.config.poll_time_window);
}
} }
} }

View File

@ -9,8 +9,7 @@ use super::{wl_connection::subscribe_state, Watcher};
use crate::report_client::ReportClient; use crate::report_client::ReportClient;
use anyhow::{anyhow, Context}; use anyhow::{anyhow, Context};
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc;
use std::{sync::Arc, thread};
use wayland_client::{ use wayland_client::{
event_created_child, globals::GlobalListContents, protocol::wl_registry, Connection, Dispatch, event_created_child, globals::GlobalListContents, protocol::wl_registry, Connection, Dispatch,
Proxy, QueueHandle, Proxy, QueueHandle,
@ -24,15 +23,13 @@ struct WindowData {
struct ToplevelState { struct ToplevelState {
windows: HashMap<String, WindowData>, windows: HashMap<String, WindowData>,
current_window_id: Option<String>, current_window_id: Option<String>,
client: Arc<ReportClient>,
} }
impl ToplevelState { impl ToplevelState {
fn new(client: Arc<ReportClient>) -> Self { fn new() -> Self {
Self { Self {
windows: HashMap::new(), windows: HashMap::new(),
current_window_id: None, current_window_id: None,
client,
} }
} }
} }
@ -114,55 +111,59 @@ impl Dispatch<ZwlrForeignToplevelHandleV1, ()> for ToplevelState {
} }
} }
impl ToplevelState { pub struct WindowWatcher {
fn send_active_window(&self) -> anyhow::Result<()> { connection: WlEventConnection<ToplevelState>,
toplevel_state: ToplevelState,
}
impl WindowWatcher {
fn send_active_window(&self, client: &Arc<ReportClient>) -> anyhow::Result<()> {
let active_window_id = self let active_window_id = self
.toplevel_state
.current_window_id .current_window_id
.as_ref() .as_ref()
.ok_or(anyhow!("Current window is unknown"))?; .ok_or(anyhow!("Current window is unknown"))?;
let active_window = self.windows.get(active_window_id).ok_or(anyhow!( let active_window = self
.toplevel_state
.windows
.get(active_window_id)
.ok_or(anyhow!(
"Current window is not found by ID {active_window_id}" "Current window is not found by ID {active_window_id}"
))?; ))?;
self.client client
.send_active_window(&active_window.app_id, &active_window.title) .send_active_window(&active_window.app_id, &active_window.title)
.with_context(|| "Failed to send heartbeat for active window") .with_context(|| "Failed to send heartbeat for active window")
} }
} }
pub struct WindowWatcher {
connection: WlEventConnection<ToplevelState>,
}
impl Watcher for WindowWatcher { impl Watcher for WindowWatcher {
fn new() -> anyhow::Result<Self> { fn new(_: &Arc<ReportClient>) -> anyhow::Result<Self> {
let connection: WlEventConnection<ToplevelState> = WlEventConnection::connect()?; let mut connection: WlEventConnection<ToplevelState> = WlEventConnection::connect()?;
connection.get_foreign_toplevel_manager()?; connection.get_foreign_toplevel_manager()?;
Ok(Self { connection }) let mut toplevel_state = ToplevelState::new();
}
fn watch(&mut self, client: &Arc<ReportClient>, is_stopped: Arc<AtomicBool>) { connection
let mut toplevel_state = ToplevelState::new(Arc::clone(client));
self.connection
.event_queue .event_queue
.roundtrip(&mut toplevel_state) .roundtrip(&mut toplevel_state)
.unwrap(); .unwrap();
info!("Starting wlr foreign toplevel watcher"); Ok(Self {
loop { connection,
if is_stopped.load(Ordering::Relaxed) { toplevel_state,
warn!("Received an exit signal, shutting down"); })
break;
}
if let Err(e) = self.connection.event_queue.roundtrip(&mut toplevel_state) {
error!("Event queue is not processed: {e}");
} else if let Err(e) = toplevel_state.send_active_window() {
error!("Error on iteration: {e}");
} }
thread::sleep(client.config.poll_time_window); fn run_iteration(&mut self, client: &Arc<ReportClient>) {
if let Err(e) = self
.connection
.event_queue
.roundtrip(&mut self.toplevel_state)
{
error!("Event queue is not processed: {e}");
} else if let Err(e) = self.send_active_window(client) {
error!("Error on iteration: {e}");
} }
} }
} }

View File

@ -3,8 +3,7 @@ use super::wl_connection::{subscribe_state, WlEventConnection};
use super::Watcher; use super::Watcher;
use crate::report_client::ReportClient; use crate::report_client::ReportClient;
use chrono::{DateTime, Duration, Utc}; use chrono::{DateTime, Duration, Utc};
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc;
use std::{sync::Arc, thread};
use wayland_client::{ use wayland_client::{
globals::GlobalListContents, globals::GlobalListContents,
protocol::{wl_registry, wl_seat::WlSeat}, protocol::{wl_registry, wl_seat::WlSeat},
@ -20,7 +19,6 @@ struct IdleState {
last_input_time: DateTime<Utc>, last_input_time: DateTime<Utc>,
is_idle: bool, is_idle: bool,
is_changed: bool, is_changed: bool,
client: Arc<ReportClient>,
} }
impl Drop for IdleState { impl Drop for IdleState {
@ -31,13 +29,12 @@ impl Drop for IdleState {
} }
impl IdleState { impl IdleState {
fn new(idle_timeout: OrgKdeKwinIdleTimeout, client: Arc<ReportClient>) -> Self { fn new(idle_timeout: OrgKdeKwinIdleTimeout) -> Self {
Self { Self {
idle_timeout, idle_timeout,
last_input_time: Utc::now(), last_input_time: Utc::now(),
is_idle: false, is_idle: false,
is_changed: false, is_changed: false,
client,
} }
} }
@ -54,7 +51,7 @@ impl IdleState {
debug!("Resumed"); debug!("Resumed");
} }
fn send_ping(&mut self) -> anyhow::Result<()> { fn send_ping(&mut self, client: &Arc<ReportClient>) -> anyhow::Result<()> {
let now = Utc::now(); let now = Utc::now();
if !self.is_idle { if !self.is_idle {
self.last_input_time = now; self.last_input_time = now;
@ -63,9 +60,8 @@ impl IdleState {
if self.is_changed { if self.is_changed {
let result = if self.is_idle { let result = if self.is_idle {
debug!("Reporting as changed to idle"); debug!("Reporting as changed to idle");
self.client client.ping(false, self.last_input_time, Duration::zero())?;
.ping(false, self.last_input_time, Duration::zero())?; client.ping(
self.client.ping(
true, true,
self.last_input_time + Duration::milliseconds(1), self.last_input_time + Duration::milliseconds(1),
Duration::zero(), Duration::zero(),
@ -73,9 +69,8 @@ impl IdleState {
} else { } else {
debug!("Reporting as no longer idle"); debug!("Reporting as no longer idle");
self.client client.ping(true, self.last_input_time, Duration::zero())?;
.ping(true, self.last_input_time, Duration::zero())?; client.ping(
self.client.ping(
false, false,
self.last_input_time + Duration::milliseconds(1), self.last_input_time + Duration::milliseconds(1),
Duration::zero(), Duration::zero(),
@ -85,12 +80,10 @@ impl IdleState {
result result
} else if self.is_idle { } else if self.is_idle {
trace!("Reporting as idle"); trace!("Reporting as idle");
self.client client.ping(true, self.last_input_time, now - self.last_input_time)
.ping(true, self.last_input_time, now - self.last_input_time)
} else { } else {
trace!("Reporting as not idle"); trace!("Reporting as not idle");
self.client client.ping(false, self.last_input_time, Duration::zero())
.ping(false, self.last_input_time, Duration::zero())
} }
} }
} }
@ -119,41 +112,30 @@ impl Dispatch<OrgKdeKwinIdleTimeout, ()> for IdleState {
pub struct IdleWatcher { pub struct IdleWatcher {
connection: WlEventConnection<IdleState>, connection: WlEventConnection<IdleState>,
idle_state: IdleState,
} }
impl Watcher for IdleWatcher { impl Watcher for IdleWatcher {
fn new() -> anyhow::Result<Self> { fn new(client: &Arc<ReportClient>) -> anyhow::Result<Self> {
let connection: WlEventConnection<IdleState> = WlEventConnection::connect()?; let mut connection: WlEventConnection<IdleState> = WlEventConnection::connect()?;
connection.get_kwin_idle()?; connection.get_kwin_idle()?;
Ok(Self { connection })
}
fn watch(&mut self, client: &Arc<ReportClient>, is_stopped: Arc<AtomicBool>) {
let timeout = u32::try_from(client.config.idle_timeout.as_secs() * 1000); let timeout = u32::try_from(client.config.idle_timeout.as_secs() * 1000);
let mut idle_state = IdleState::new( let mut idle_state =
self.connection IdleState::new(connection.get_kwin_idle_timeout(timeout.unwrap()).unwrap());
.get_kwin_idle_timeout(timeout.unwrap()) connection.event_queue.roundtrip(&mut idle_state).unwrap();
.unwrap(),
Arc::clone(client),
);
self.connection
.event_queue
.roundtrip(&mut idle_state)
.unwrap();
info!("Starting idle watcher"); Ok(Self {
loop { connection,
if is_stopped.load(Ordering::Relaxed) { idle_state,
warn!("Received an exit signal, shutting down"); })
break;
} }
if let Err(e) = self.connection.event_queue.roundtrip(&mut idle_state) {
fn run_iteration(&mut self, client: &Arc<ReportClient>) {
if let Err(e) = self.connection.event_queue.roundtrip(&mut self.idle_state) {
error!("Event queue is not processed: {e}"); error!("Event queue is not processed: {e}");
} else if let Err(e) = idle_state.send_ping() { } else if let Err(e) = self.idle_state.send_ping(client) {
error!("Error on idle iteration: {e}"); error!("Error on idle iteration: {e}");
} }
thread::sleep(client.config.poll_time_idle);
}
} }
} }

View File

@ -1,11 +1,10 @@
use super::{idle, x11_connection::X11Client, Watcher}; use super::{idle, x11_connection::X11Client, Watcher};
use crate::report_client::ReportClient; use crate::report_client::ReportClient;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc; use std::sync::Arc;
use std::thread;
pub struct IdleWatcher { pub struct IdleWatcher {
client: X11Client, client: X11Client,
is_idle: bool,
} }
impl idle::SinceLastInput for IdleWatcher { impl idle::SinceLastInput for IdleWatcher {
@ -15,31 +14,24 @@ impl idle::SinceLastInput for IdleWatcher {
} }
impl Watcher for IdleWatcher { impl Watcher for IdleWatcher {
fn new() -> anyhow::Result<Self> { fn new(_: &Arc<ReportClient>) -> anyhow::Result<Self> {
let mut client = X11Client::new()?; let mut client = X11Client::new()?;
// Check if screensaver extension is supported // Check if screensaver extension is supported
client.seconds_since_last_input()?; client.seconds_since_last_input()?;
Ok(IdleWatcher { client }) Ok(IdleWatcher {
client,
is_idle: false,
})
} }
fn watch(&mut self, client: &Arc<ReportClient>, is_stopped: Arc<AtomicBool>) { fn run_iteration(&mut self, client: &Arc<ReportClient>) {
info!("Starting idle watcher"); match idle::ping_since_last_input(self, self.is_idle, client) {
let mut is_idle = false;
loop {
if is_stopped.load(Ordering::Relaxed) {
warn!("Received an exit signal, shutting down");
break;
}
match idle::ping_since_last_input(self, is_idle, client) {
Ok(is_idle_again) => { Ok(is_idle_again) => {
is_idle = is_idle_again; self.is_idle = is_idle_again;
} }
Err(e) => error!("Error on idle iteration: {e}"), Err(e) => error!("Error on idle iteration: {e}"),
}; };
thread::sleep(client.config.poll_time_idle);
}
} }
} }

View File

@ -1,9 +1,7 @@
use super::{x11_connection::X11Client, Watcher}; use super::{x11_connection::X11Client, Watcher};
use crate::report_client::ReportClient; use crate::report_client::ReportClient;
use anyhow::Context; use anyhow::Context;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc; use std::sync::Arc;
use std::thread;
pub struct WindowWatcher { pub struct WindowWatcher {
client: X11Client, client: X11Client,
@ -31,7 +29,7 @@ impl WindowWatcher {
} }
impl Watcher for WindowWatcher { impl Watcher for WindowWatcher {
fn new() -> anyhow::Result<Self> { fn new(_: &Arc<ReportClient>) -> anyhow::Result<Self> {
let mut client = X11Client::new()?; let mut client = X11Client::new()?;
client.active_window_data()?; client.active_window_data()?;
@ -42,18 +40,9 @@ impl Watcher for WindowWatcher {
}) })
} }
fn watch(&mut self, client: &Arc<ReportClient>, is_stopped: Arc<AtomicBool>) { fn run_iteration(&mut self, client: &Arc<ReportClient>) {
info!("Starting active window watcher");
loop {
if is_stopped.load(Ordering::Relaxed) {
warn!("Received an exit signal, shutting down");
break;
}
if let Err(error) = self.send_active_window(client) { if let Err(error) = self.send_active_window(client) {
error!("Error on sending active window: {error}"); error!("Error on sending active window: {error}");
} }
thread::sleep(client.config.poll_time_window);
}
} }
} }