awatcher/src/wl_kwin_idle.rs
Demmie 6645695149
Implement wlr foreign toplevel v1 protocol
This watches active windows.
2023-04-16 01:17:35 -04:00

158 lines
4.6 KiB
Rust

use crate::Watcher;
use super::report_client::ReportClient;
use super::wl_bindings;
use super::wl_connection::{subscribe_state, WlEventConnection};
use super::BoxedError;
use chrono::{DateTime, Duration, Utc};
use std::{sync::Arc, thread, time};
use wayland_client::{
globals::GlobalListContents,
protocol::{wl_registry, wl_seat::WlSeat},
Connection, Dispatch, Proxy, QueueHandle,
};
use wl_bindings::idle::org_kde_kwin_idle::OrgKdeKwinIdle;
use wl_bindings::idle::org_kde_kwin_idle_timeout::{
Event as OrgKdeKwinIdleTimeoutEvent, OrgKdeKwinIdleTimeout,
};
struct IdleState {
idle_timeout: OrgKdeKwinIdleTimeout,
last_input_time: DateTime<Utc>,
is_idle: bool,
is_changed: bool,
client: Arc<ReportClient>,
}
impl Drop for IdleState {
fn drop(&mut self) {
info!("Releasing idle timeout");
self.idle_timeout.release();
}
}
impl IdleState {
fn new(idle_timeout: OrgKdeKwinIdleTimeout, client: Arc<ReportClient>) -> Self {
Self {
idle_timeout,
last_input_time: Utc::now(),
is_idle: false,
is_changed: false,
client,
}
}
fn idle(&mut self) {
self.is_idle = true;
self.is_changed = true;
debug!("Idle");
}
fn resume(&mut self) {
self.is_idle = false;
self.last_input_time = Utc::now();
self.is_changed = true;
debug!("Resumed");
}
fn send_ping(&mut self) -> Result<(), BoxedError> {
let now = Utc::now();
if !self.is_idle {
self.last_input_time = now;
}
if self.is_changed {
let result = if self.is_idle {
debug!("Reporting as changed to idle");
self.client
.ping(false, self.last_input_time, Duration::zero())?;
self.client.ping(
true,
self.last_input_time + Duration::milliseconds(1),
Duration::zero(),
)
} else {
debug!("Reporting as no longer idle");
self.client
.ping(true, self.last_input_time, Duration::zero())?;
self.client.ping(
false,
self.last_input_time + Duration::milliseconds(1),
Duration::zero(),
)
};
self.is_changed = false;
result
} else if self.is_idle {
trace!("Reporting as idle");
self.client
.ping(true, self.last_input_time, now - self.last_input_time)
} else {
trace!("Reporting as not idle");
self.client
.ping(false, self.last_input_time, Duration::zero())
}
}
}
subscribe_state!(wl_registry::WlRegistry, GlobalListContents, IdleState);
subscribe_state!(wl_registry::WlRegistry, (), IdleState);
subscribe_state!(WlSeat, (), IdleState);
subscribe_state!(OrgKdeKwinIdle, (), IdleState);
impl Dispatch<OrgKdeKwinIdleTimeout, ()> for IdleState {
fn event(
state: &mut Self,
_: &OrgKdeKwinIdleTimeout,
event: <OrgKdeKwinIdleTimeout as Proxy>::Event,
_: &(),
_: &Connection,
_: &QueueHandle<Self>,
) {
if let OrgKdeKwinIdleTimeoutEvent::Idle = event {
state.idle();
} else if let OrgKdeKwinIdleTimeoutEvent::Resumed = event {
state.resume();
}
}
}
pub struct KwinIdleWatcher {
connection: WlEventConnection<IdleState>,
}
impl Watcher for KwinIdleWatcher {
fn new() -> Result<Self, BoxedError> {
let connection: WlEventConnection<IdleState> = WlEventConnection::connect()?;
connection.get_kwin_idle()?;
Ok(Self { connection })
}
fn watch(&mut self, client: &Arc<ReportClient>) {
let mut idle_state = IdleState::new(
self.connection
.get_kwin_idle_timeout(client.config.idle_timeout * 1000)
.unwrap(),
Arc::clone(client),
);
self.connection
.event_queue
.roundtrip(&mut idle_state)
.unwrap();
info!("Starting idle watcher");
loop {
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(time::Duration::from_secs(u64::from(
client.config.poll_time_idle,
)));
}
}
}