mirror of
https://github.com/2e3s/awatcher.git
synced 2025-06-07 12:05:49 +00:00
Refactor to use common watchers loop
This commit is contained in:
parent
cdc05e0d5f
commit
79f8e53850
@ -13,54 +13,113 @@ 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>,
|
||||||
Err(e) => {
|
) -> Option<(&WatcherType, BoxedWatcher)> {
|
||||||
debug!("{name} cannot run: {e}");
|
self.iter()
|
||||||
None
|
.find_map(|(name, watcher_type, watcher)| match watcher(client) {
|
||||||
}
|
Ok(watcher) => {
|
||||||
})
|
info!("Selected {name} as {watcher_type} watcher");
|
||||||
|
Some((watcher_type, watcher))
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
debug!("{name} cannot run: {e}");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
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),
|
||||||
];
|
];
|
||||||
|
@ -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");
|
Ok(is_idle_again) => {
|
||||||
loop {
|
self.is_idle = is_idle_again;
|
||||||
if is_stopped.load(Ordering::Relaxed) {
|
|
||||||
warn!("Received an exit signal, shutting down");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
match idle::ping_since_last_input(self, is_idle, client) {
|
Err(e) => error!("Error on idle iteration: {e}"),
|
||||||
Ok(is_idle_again) => {
|
};
|
||||||
is_idle = is_idle_again;
|
|
||||||
}
|
|
||||||
Err(e) => error!("Error on idle iteration: {e}"),
|
|
||||||
};
|
|
||||||
thread::sleep(client.config.poll_time_idle);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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");
|
if let Err(error) = self.send_active_window(client) {
|
||||||
loop {
|
error!("Error on active window: {error}");
|
||||||
if is_stopped.load(Ordering::Relaxed) {
|
|
||||||
warn!("Received an exit signal, shutting down");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if let Err(error) = self.send_active_window(client) {
|
|
||||||
error!("Error on active window: {error}");
|
|
||||||
}
|
|
||||||
thread::sleep(client.config.poll_time_window);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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>) {
|
||||||
error!("Error on sending active window: {error}");
|
if let Err(error) = send_active_window(client, &self.active_window) {
|
||||||
}
|
error!("Error on sending active window: {error}");
|
||||||
thread::sleep(client.config.poll_time_window);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
"Current window is not found by ID {active_window_id}"
|
.toplevel_state
|
||||||
))?;
|
.windows
|
||||||
|
.get(active_window_id)
|
||||||
|
.ok_or(anyhow!(
|
||||||
|
"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}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 })
|
let timeout = u32::try_from(client.config.idle_timeout.as_secs() * 1000);
|
||||||
|
let mut idle_state =
|
||||||
|
IdleState::new(connection.get_kwin_idle_timeout(timeout.unwrap()).unwrap());
|
||||||
|
connection.event_queue.roundtrip(&mut idle_state).unwrap();
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
connection,
|
||||||
|
idle_state,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn watch(&mut self, client: &Arc<ReportClient>, is_stopped: Arc<AtomicBool>) {
|
fn run_iteration(&mut self, client: &Arc<ReportClient>) {
|
||||||
let timeout = u32::try_from(client.config.idle_timeout.as_secs() * 1000);
|
if let Err(e) = self.connection.event_queue.roundtrip(&mut self.idle_state) {
|
||||||
let mut idle_state = IdleState::new(
|
error!("Event queue is not processed: {e}");
|
||||||
self.connection
|
} else if let Err(e) = self.idle_state.send_ping(client) {
|
||||||
.get_kwin_idle_timeout(timeout.unwrap())
|
error!("Error on idle iteration: {e}");
|
||||||
.unwrap(),
|
|
||||||
Arc::clone(client),
|
|
||||||
);
|
|
||||||
self.connection
|
|
||||||
.event_queue
|
|
||||||
.roundtrip(&mut idle_state)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
info!("Starting idle watcher");
|
|
||||||
loop {
|
|
||||||
if is_stopped.load(Ordering::Relaxed) {
|
|
||||||
warn!("Received an exit signal, shutting down");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if let Err(e) = self.connection.event_queue.roundtrip(&mut idle_state) {
|
|
||||||
error!("Event queue is not processed: {e}");
|
|
||||||
} else if let Err(e) = idle_state.send_ping() {
|
|
||||||
error!("Error on idle iteration: {e}");
|
|
||||||
}
|
|
||||||
thread::sleep(client.config.poll_time_idle);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
Ok(is_idle_again) => {
|
||||||
loop {
|
self.is_idle = is_idle_again;
|
||||||
if is_stopped.load(Ordering::Relaxed) {
|
|
||||||
warn!("Received an exit signal, shutting down");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
match idle::ping_since_last_input(self, is_idle, client) {
|
Err(e) => error!("Error on idle iteration: {e}"),
|
||||||
Ok(is_idle_again) => {
|
};
|
||||||
is_idle = is_idle_again;
|
|
||||||
}
|
|
||||||
Err(e) => error!("Error on idle iteration: {e}"),
|
|
||||||
};
|
|
||||||
|
|
||||||
thread::sleep(client.config.poll_time_idle);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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");
|
if let Err(error) = self.send_active_window(client) {
|
||||||
loop {
|
error!("Error on sending active window: {error}");
|
||||||
if is_stopped.load(Ordering::Relaxed) {
|
|
||||||
warn!("Received an exit signal, shutting down");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if let Err(error) = self.send_active_window(client) {
|
|
||||||
error!("Error on sending active window: {error}");
|
|
||||||
}
|
|
||||||
|
|
||||||
thread::sleep(client.config.poll_time_window);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user