mirror of
https://github.com/2e3s/awatcher.git
synced 2025-06-05 19:15:33 +00:00
Unify idle logic
This commit is contained in:
parent
f960dd6697
commit
ea215b432d
@ -1,16 +1,17 @@
|
||||
use super::{gnome_wayland::load_watcher, gnome_wayland::GnomeWatcher, idle, Watcher};
|
||||
use super::{gnome_wayland::load_watcher, idle, Watcher};
|
||||
use crate::report_client::ReportClient;
|
||||
use anyhow::Context;
|
||||
use async_trait::async_trait;
|
||||
use chrono::Duration;
|
||||
use std::sync::Arc;
|
||||
use zbus::Connection;
|
||||
|
||||
pub struct IdleWatcher {
|
||||
dbus_connection: Connection,
|
||||
is_idle: bool,
|
||||
idle_state: idle::State,
|
||||
}
|
||||
|
||||
impl idle::SinceLastInput for IdleWatcher {
|
||||
impl IdleWatcher {
|
||||
async fn seconds_since_input(&mut self) -> anyhow::Result<u32> {
|
||||
let ms = self
|
||||
.dbus_connection
|
||||
@ -27,26 +28,26 @@ impl idle::SinceLastInput for IdleWatcher {
|
||||
}
|
||||
}
|
||||
|
||||
impl GnomeWatcher for IdleWatcher {
|
||||
async fn load() -> anyhow::Result<Self> {
|
||||
let mut watcher = Self {
|
||||
dbus_connection: Connection::session().await?,
|
||||
is_idle: false,
|
||||
};
|
||||
idle::SinceLastInput::seconds_since_input(&mut watcher).await?;
|
||||
|
||||
Ok(watcher)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Watcher for IdleWatcher {
|
||||
async fn new(_: &Arc<ReportClient>) -> anyhow::Result<Self> {
|
||||
load_watcher().await
|
||||
async fn new(client: &Arc<ReportClient>) -> anyhow::Result<Self> {
|
||||
let duration = Duration::from_std(client.config.idle_timeout).unwrap();
|
||||
load_watcher(|| async move {
|
||||
let mut watcher = Self {
|
||||
dbus_connection: Connection::session().await?,
|
||||
idle_state: idle::State::new(duration),
|
||||
};
|
||||
watcher.seconds_since_input().await?;
|
||||
Ok(watcher)
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn run_iteration(&mut self, client: &Arc<ReportClient>) -> anyhow::Result<()> {
|
||||
self.is_idle = idle::ping_since_last_input(self, self.is_idle, client).await?;
|
||||
let seconds = self.seconds_since_input().await?;
|
||||
self.idle_state
|
||||
.send_with_last_input(seconds, client)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1,9 +1,4 @@
|
||||
// The extension may not be loaded and available right away in Gnome, this mod will retry a few times.
|
||||
pub trait GnomeWatcher {
|
||||
async fn load() -> anyhow::Result<Self>
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
use std::future::Future;
|
||||
|
||||
fn is_gnome() -> bool {
|
||||
if let Ok(de) = std::env::var("XDG_CURRENT_DESKTOP") {
|
||||
@ -21,12 +16,16 @@ fn is_wayland() -> bool {
|
||||
.contains("wayland")
|
||||
}
|
||||
|
||||
pub async fn load_watcher<T: GnomeWatcher>() -> anyhow::Result<T> {
|
||||
pub async fn load_watcher<T, F, Fut>(loader: F) -> anyhow::Result<T>
|
||||
where
|
||||
F: Fn() -> Fut,
|
||||
Fut: Future<Output = anyhow::Result<T>>,
|
||||
{
|
||||
if is_gnome() && is_wayland() {
|
||||
debug!("Gnome Wayland detected");
|
||||
let mut watcher = Err(anyhow::anyhow!(""));
|
||||
for _ in 0..3 {
|
||||
watcher = T::load().await;
|
||||
watcher = loader().await;
|
||||
if let Err(e) = &watcher {
|
||||
debug!("Failed to load Gnome Wayland watcher: {e}");
|
||||
tokio::time::sleep(tokio::time::Duration::from_secs(3)).await;
|
||||
@ -35,6 +34,6 @@ pub async fn load_watcher<T: GnomeWatcher>() -> anyhow::Result<T> {
|
||||
|
||||
watcher
|
||||
} else {
|
||||
T::load().await
|
||||
loader().await
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ use serde::Deserialize;
|
||||
use std::sync::Arc;
|
||||
use zbus::Connection;
|
||||
|
||||
use super::{gnome_wayland::load_watcher, gnome_wayland::GnomeWatcher, Watcher};
|
||||
use super::{gnome_wayland::load_watcher, Watcher};
|
||||
|
||||
pub struct WindowWatcher {
|
||||
dbus_connection: Connection,
|
||||
@ -79,23 +79,20 @@ impl WindowWatcher {
|
||||
}
|
||||
}
|
||||
|
||||
impl GnomeWatcher for WindowWatcher {
|
||||
async fn load() -> anyhow::Result<Self> {
|
||||
let watcher = Self {
|
||||
dbus_connection: Connection::session().await?,
|
||||
last_app_id: String::new(),
|
||||
last_title: String::new(),
|
||||
};
|
||||
watcher.get_window_data().await?;
|
||||
|
||||
Ok(watcher)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Watcher for WindowWatcher {
|
||||
async fn new(_: &Arc<ReportClient>) -> anyhow::Result<Self> {
|
||||
load_watcher().await
|
||||
load_watcher(|| async move {
|
||||
let watcher = Self {
|
||||
dbus_connection: Connection::session().await?,
|
||||
last_app_id: String::new(),
|
||||
last_title: String::new(),
|
||||
};
|
||||
watcher.get_window_data().await?;
|
||||
|
||||
Ok(watcher)
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
async fn run_iteration(&mut self, client: &Arc<ReportClient>) -> anyhow::Result<()> {
|
||||
|
@ -1,53 +1,119 @@
|
||||
use crate::report_client::ReportClient;
|
||||
use chrono::{Duration, Utc};
|
||||
use chrono::{DateTime, Duration, Utc};
|
||||
use std::sync::Arc;
|
||||
|
||||
pub trait SinceLastInput {
|
||||
async fn seconds_since_input(&mut self) -> anyhow::Result<u32>;
|
||||
pub struct State {
|
||||
last_input_time: DateTime<Utc>,
|
||||
is_idle: bool,
|
||||
is_changed: bool,
|
||||
idle_timeout: Duration,
|
||||
}
|
||||
|
||||
pub async fn ping_since_last_input(
|
||||
watcher: &mut impl SinceLastInput,
|
||||
is_idle: bool,
|
||||
client: &Arc<ReportClient>,
|
||||
) -> anyhow::Result<bool> {
|
||||
// The logic is rewritten from the original Python code:
|
||||
// https://github.com/ActivityWatch/aw-watcher-afk/blob/ef531605cd8238e00138bbb980e5457054e05248/aw_watcher_afk/afk.py#L73
|
||||
let duration_1ms: Duration = Duration::milliseconds(1);
|
||||
let duration_zero: Duration = Duration::zero();
|
||||
|
||||
let seconds_since_input = watcher.seconds_since_input().await?;
|
||||
let now = Utc::now();
|
||||
let time_since_input = Duration::seconds(i64::from(seconds_since_input));
|
||||
let last_input = now - time_since_input;
|
||||
let mut is_idle_again = is_idle;
|
||||
|
||||
if is_idle && u64::from(seconds_since_input) < client.config.idle_timeout.as_secs() {
|
||||
debug!("No longer idle");
|
||||
client.ping(is_idle, last_input, duration_zero).await?;
|
||||
is_idle_again = false;
|
||||
// ping with timestamp+1ms with the next event (to ensure the latest event gets retrieved by get_event)
|
||||
client
|
||||
.ping(is_idle, last_input + duration_1ms, duration_zero)
|
||||
.await?;
|
||||
} else if !is_idle && u64::from(seconds_since_input) >= client.config.idle_timeout.as_secs() {
|
||||
debug!("Idle again");
|
||||
client.ping(is_idle, last_input, duration_zero).await?;
|
||||
is_idle_again = true;
|
||||
// ping with timestamp+1ms with the next event (to ensure the latest event gets retrieved by get_event)
|
||||
client
|
||||
.ping(is_idle, last_input + duration_1ms, time_since_input)
|
||||
.await?;
|
||||
} else {
|
||||
// Send a heartbeat if no state change was made
|
||||
if is_idle {
|
||||
trace!("Reporting as idle");
|
||||
client.ping(is_idle, last_input, time_since_input).await?;
|
||||
} else {
|
||||
trace!("Reporting as not idle");
|
||||
client.ping(is_idle, last_input, duration_zero).await?;
|
||||
impl State {
|
||||
pub fn new(idle_timeout: Duration) -> Self {
|
||||
Self {
|
||||
last_input_time: Utc::now(),
|
||||
is_idle: false,
|
||||
is_changed: false,
|
||||
idle_timeout,
|
||||
}
|
||||
}
|
||||
|
||||
Ok(is_idle_again)
|
||||
pub fn mark_not_idle(&mut self) {
|
||||
self.is_idle = false;
|
||||
self.is_changed = true;
|
||||
self.last_input_time = Utc::now();
|
||||
}
|
||||
|
||||
pub fn mark_idle(&mut self) {
|
||||
self.is_idle = true;
|
||||
self.is_changed = true;
|
||||
self.last_input_time -= self.idle_timeout;
|
||||
}
|
||||
|
||||
// The logic is rewritten from the original Python code:
|
||||
// https://github.com/ActivityWatch/aw-watcher-afk/blob/ef531605cd8238e00138bbb980e5457054e05248/aw_watcher_afk/afk.py#L73
|
||||
pub async fn send_with_last_input(
|
||||
&mut self,
|
||||
seconds_since_input: u32,
|
||||
client: &Arc<ReportClient>,
|
||||
) -> anyhow::Result<()> {
|
||||
let time_since_input = Duration::seconds(i64::from(seconds_since_input));
|
||||
|
||||
self.last_input_time = Utc::now() - time_since_input;
|
||||
|
||||
if self.is_idle
|
||||
&& u64::from(seconds_since_input) < self.idle_timeout.num_seconds().try_into().unwrap()
|
||||
{
|
||||
debug!("No longer idle");
|
||||
self.is_idle = false;
|
||||
self.is_changed = true;
|
||||
} else if !self.is_idle
|
||||
&& u64::from(seconds_since_input) >= self.idle_timeout.num_seconds().try_into().unwrap()
|
||||
{
|
||||
debug!("Idle again");
|
||||
self.is_idle = true;
|
||||
self.is_changed = true;
|
||||
}
|
||||
|
||||
self.send_ping(client).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn send_reactive(&mut self, client: &Arc<ReportClient>) -> anyhow::Result<()> {
|
||||
let now = Utc::now();
|
||||
if !self.is_idle {
|
||||
self.last_input_time = now;
|
||||
}
|
||||
|
||||
self.send_ping(client).await
|
||||
}
|
||||
|
||||
async fn send_ping(&mut self, client: &Arc<ReportClient>) -> anyhow::Result<()> {
|
||||
let now = Utc::now();
|
||||
|
||||
if self.is_changed {
|
||||
let result = if self.is_idle {
|
||||
debug!("Reporting as changed to idle");
|
||||
client
|
||||
.ping(false, self.last_input_time, Duration::zero())
|
||||
.await?;
|
||||
|
||||
// ping with timestamp+1ms with the next event (to ensure the latest event gets retrieved by get_event)
|
||||
client
|
||||
.ping(
|
||||
true,
|
||||
self.last_input_time + Duration::milliseconds(1),
|
||||
Duration::zero(),
|
||||
)
|
||||
.await
|
||||
} else {
|
||||
debug!("Reporting as no longer idle");
|
||||
|
||||
client
|
||||
.ping(true, self.last_input_time, Duration::zero())
|
||||
.await?;
|
||||
client
|
||||
.ping(
|
||||
false,
|
||||
self.last_input_time + Duration::milliseconds(1),
|
||||
Duration::zero(),
|
||||
)
|
||||
.await
|
||||
};
|
||||
self.is_changed = false;
|
||||
result
|
||||
} else if self.is_idle {
|
||||
trace!("Reporting as idle");
|
||||
client
|
||||
.ping(true, self.last_input_time, now - self.last_input_time)
|
||||
.await
|
||||
} else {
|
||||
trace!("Reporting as not idle");
|
||||
client
|
||||
.ping(false, self.last_input_time, Duration::zero())
|
||||
.await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
use super::idle;
|
||||
use super::wl_connection::{subscribe_state, WlEventConnection};
|
||||
use super::Watcher;
|
||||
use crate::report_client::ReportClient;
|
||||
use anyhow::anyhow;
|
||||
use async_trait::async_trait;
|
||||
use chrono::{DateTime, Duration, Utc};
|
||||
use chrono::Duration;
|
||||
use std::sync::Arc;
|
||||
use wayland_client::{
|
||||
globals::GlobalListContents,
|
||||
@ -14,101 +15,43 @@ use wayland_protocols::ext::idle_notify::v1::client::ext_idle_notification_v1::E
|
||||
use wayland_protocols::ext::idle_notify::v1::client::ext_idle_notification_v1::ExtIdleNotificationV1;
|
||||
use wayland_protocols::ext::idle_notify::v1::client::ext_idle_notifier_v1::ExtIdleNotifierV1;
|
||||
|
||||
struct IdleState {
|
||||
struct WatcherState {
|
||||
idle_notification: ExtIdleNotificationV1,
|
||||
last_input_time: DateTime<Utc>,
|
||||
is_idle: bool,
|
||||
is_changed: bool,
|
||||
idle_timeout: Duration,
|
||||
idle_state: idle::State,
|
||||
}
|
||||
|
||||
impl Drop for IdleState {
|
||||
impl Drop for WatcherState {
|
||||
fn drop(&mut self) {
|
||||
info!("Releasing idle notification");
|
||||
self.idle_notification.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
impl IdleState {
|
||||
impl WatcherState {
|
||||
fn new(idle_notification: ExtIdleNotificationV1, idle_timeout: Duration) -> Self {
|
||||
Self {
|
||||
idle_notification,
|
||||
last_input_time: Utc::now(),
|
||||
is_idle: false,
|
||||
is_changed: false,
|
||||
idle_timeout,
|
||||
idle_state: idle::State::new(idle_timeout),
|
||||
}
|
||||
}
|
||||
|
||||
fn idle(&mut self) {
|
||||
self.is_idle = true;
|
||||
self.is_changed = true;
|
||||
self.last_input_time -= self.idle_timeout;
|
||||
self.idle_state.mark_idle();
|
||||
debug!("Idle");
|
||||
}
|
||||
|
||||
fn resume(&mut self) {
|
||||
self.is_idle = false;
|
||||
self.last_input_time = Utc::now();
|
||||
self.is_changed = true;
|
||||
self.idle_state.mark_not_idle();
|
||||
debug!("Resumed");
|
||||
}
|
||||
|
||||
async fn send_ping(&mut self, client: &Arc<ReportClient>) -> anyhow::Result<()> {
|
||||
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");
|
||||
client
|
||||
.ping(false, self.last_input_time, Duration::zero())
|
||||
.await?;
|
||||
client
|
||||
.ping(
|
||||
true,
|
||||
self.last_input_time + Duration::milliseconds(1),
|
||||
Duration::zero(),
|
||||
)
|
||||
.await
|
||||
} else {
|
||||
debug!("Reporting as no longer idle");
|
||||
|
||||
client
|
||||
.ping(true, self.last_input_time, Duration::zero())
|
||||
.await?;
|
||||
client
|
||||
.ping(
|
||||
false,
|
||||
self.last_input_time + Duration::milliseconds(1),
|
||||
Duration::zero(),
|
||||
)
|
||||
.await
|
||||
};
|
||||
self.is_changed = false;
|
||||
result
|
||||
} else if self.is_idle {
|
||||
trace!("Reporting as idle");
|
||||
client
|
||||
.ping(true, self.last_input_time, now - self.last_input_time)
|
||||
.await
|
||||
} else {
|
||||
trace!("Reporting as not idle");
|
||||
client
|
||||
.ping(false, self.last_input_time, Duration::zero())
|
||||
.await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
subscribe_state!(wl_registry::WlRegistry, GlobalListContents, IdleState);
|
||||
subscribe_state!(wl_registry::WlRegistry, (), IdleState);
|
||||
subscribe_state!(WlSeat, (), IdleState);
|
||||
subscribe_state!(ExtIdleNotifierV1, (), IdleState);
|
||||
subscribe_state!(wl_registry::WlRegistry, GlobalListContents, WatcherState);
|
||||
subscribe_state!(wl_registry::WlRegistry, (), WatcherState);
|
||||
subscribe_state!(WlSeat, (), WatcherState);
|
||||
subscribe_state!(ExtIdleNotifierV1, (), WatcherState);
|
||||
|
||||
impl Dispatch<ExtIdleNotificationV1, ()> for IdleState {
|
||||
impl Dispatch<ExtIdleNotificationV1, ()> for WatcherState {
|
||||
fn event(
|
||||
state: &mut Self,
|
||||
_: &ExtIdleNotificationV1,
|
||||
@ -126,37 +69,40 @@ impl Dispatch<ExtIdleNotificationV1, ()> for IdleState {
|
||||
}
|
||||
|
||||
pub struct IdleWatcher {
|
||||
connection: WlEventConnection<IdleState>,
|
||||
idle_state: IdleState,
|
||||
connection: WlEventConnection<WatcherState>,
|
||||
watcher_state: WatcherState,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Watcher for IdleWatcher {
|
||||
async fn new(client: &Arc<ReportClient>) -> anyhow::Result<Self> {
|
||||
let mut connection: WlEventConnection<IdleState> = WlEventConnection::connect()?;
|
||||
let mut connection: WlEventConnection<WatcherState> = WlEventConnection::connect()?;
|
||||
connection.get_ext_idle()?;
|
||||
|
||||
let timeout = u32::try_from(client.config.idle_timeout.as_secs() * 1000);
|
||||
let mut idle_state = IdleState::new(
|
||||
let mut watcher_state = WatcherState::new(
|
||||
connection
|
||||
.get_ext_idle_notification(timeout.unwrap())
|
||||
.unwrap(),
|
||||
Duration::from_std(client.config.idle_timeout).unwrap(),
|
||||
);
|
||||
connection.event_queue.roundtrip(&mut idle_state).unwrap();
|
||||
connection
|
||||
.event_queue
|
||||
.roundtrip(&mut watcher_state)
|
||||
.unwrap();
|
||||
|
||||
Ok(Self {
|
||||
connection,
|
||||
idle_state,
|
||||
watcher_state,
|
||||
})
|
||||
}
|
||||
|
||||
async fn run_iteration(&mut self, client: &Arc<ReportClient>) -> anyhow::Result<()> {
|
||||
self.connection
|
||||
.event_queue
|
||||
.roundtrip(&mut self.idle_state)
|
||||
.roundtrip(&mut self.watcher_state)
|
||||
.map_err(|e| anyhow!("Event queue is not processed: {e}"))?;
|
||||
|
||||
self.idle_state.send_ping(client).await
|
||||
self.watcher_state.idle_state.send_reactive(client).await
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
use super::idle;
|
||||
use super::wl_connection::{subscribe_state, WlEventConnection};
|
||||
use super::Watcher;
|
||||
use crate::report_client::ReportClient;
|
||||
use anyhow::anyhow;
|
||||
use async_trait::async_trait;
|
||||
use chrono::{DateTime, Duration, Utc};
|
||||
use chrono::Duration;
|
||||
use std::sync::Arc;
|
||||
use wayland_client::{
|
||||
globals::GlobalListContents,
|
||||
@ -15,101 +16,43 @@ use wayland_protocols_plasma::idle::client::org_kde_kwin_idle_timeout::{
|
||||
Event as OrgKdeKwinIdleTimeoutEvent, OrgKdeKwinIdleTimeout,
|
||||
};
|
||||
|
||||
struct IdleState {
|
||||
struct WatcherState {
|
||||
kwin_idle_timeout: OrgKdeKwinIdleTimeout,
|
||||
last_input_time: DateTime<Utc>,
|
||||
is_idle: bool,
|
||||
is_changed: bool,
|
||||
idle_timeout: Duration,
|
||||
idle_state: idle::State,
|
||||
}
|
||||
|
||||
impl Drop for IdleState {
|
||||
impl Drop for WatcherState {
|
||||
fn drop(&mut self) {
|
||||
info!("Releasing idle timeout");
|
||||
self.kwin_idle_timeout.release();
|
||||
}
|
||||
}
|
||||
|
||||
impl IdleState {
|
||||
impl WatcherState {
|
||||
fn new(kwin_idle_timeout: OrgKdeKwinIdleTimeout, idle_timeout: Duration) -> Self {
|
||||
Self {
|
||||
kwin_idle_timeout,
|
||||
last_input_time: Utc::now(),
|
||||
is_idle: false,
|
||||
is_changed: false,
|
||||
idle_timeout,
|
||||
idle_state: idle::State::new(idle_timeout),
|
||||
}
|
||||
}
|
||||
|
||||
fn idle(&mut self) {
|
||||
self.is_idle = true;
|
||||
self.is_changed = true;
|
||||
self.last_input_time -= self.idle_timeout;
|
||||
self.idle_state.mark_idle();
|
||||
debug!("Idle");
|
||||
}
|
||||
|
||||
fn resume(&mut self) {
|
||||
self.is_idle = false;
|
||||
self.last_input_time = Utc::now();
|
||||
self.is_changed = true;
|
||||
self.idle_state.mark_not_idle();
|
||||
debug!("Resumed");
|
||||
}
|
||||
|
||||
async fn send_ping(&mut self, client: &Arc<ReportClient>) -> anyhow::Result<()> {
|
||||
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");
|
||||
client
|
||||
.ping(false, self.last_input_time, Duration::zero())
|
||||
.await?;
|
||||
client
|
||||
.ping(
|
||||
true,
|
||||
self.last_input_time + Duration::milliseconds(1),
|
||||
Duration::zero(),
|
||||
)
|
||||
.await
|
||||
} else {
|
||||
debug!("Reporting as no longer idle");
|
||||
|
||||
client
|
||||
.ping(true, self.last_input_time, Duration::zero())
|
||||
.await?;
|
||||
client
|
||||
.ping(
|
||||
false,
|
||||
self.last_input_time + Duration::milliseconds(1),
|
||||
Duration::zero(),
|
||||
)
|
||||
.await
|
||||
};
|
||||
self.is_changed = false;
|
||||
result
|
||||
} else if self.is_idle {
|
||||
trace!("Reporting as idle");
|
||||
client
|
||||
.ping(true, self.last_input_time, now - self.last_input_time)
|
||||
.await
|
||||
} else {
|
||||
trace!("Reporting as not idle");
|
||||
client
|
||||
.ping(false, self.last_input_time, Duration::zero())
|
||||
.await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
subscribe_state!(wl_registry::WlRegistry, GlobalListContents, IdleState);
|
||||
subscribe_state!(wl_registry::WlRegistry, (), IdleState);
|
||||
subscribe_state!(WlSeat, (), IdleState);
|
||||
subscribe_state!(OrgKdeKwinIdle, (), IdleState);
|
||||
subscribe_state!(wl_registry::WlRegistry, GlobalListContents, WatcherState);
|
||||
subscribe_state!(wl_registry::WlRegistry, (), WatcherState);
|
||||
subscribe_state!(WlSeat, (), WatcherState);
|
||||
subscribe_state!(OrgKdeKwinIdle, (), WatcherState);
|
||||
|
||||
impl Dispatch<OrgKdeKwinIdleTimeout, ()> for IdleState {
|
||||
impl Dispatch<OrgKdeKwinIdleTimeout, ()> for WatcherState {
|
||||
fn event(
|
||||
state: &mut Self,
|
||||
_: &OrgKdeKwinIdleTimeout,
|
||||
@ -127,35 +70,38 @@ impl Dispatch<OrgKdeKwinIdleTimeout, ()> for IdleState {
|
||||
}
|
||||
|
||||
pub struct IdleWatcher {
|
||||
connection: WlEventConnection<IdleState>,
|
||||
idle_state: IdleState,
|
||||
connection: WlEventConnection<WatcherState>,
|
||||
watcher_state: WatcherState,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Watcher for IdleWatcher {
|
||||
async fn new(client: &Arc<ReportClient>) -> anyhow::Result<Self> {
|
||||
let mut connection: WlEventConnection<IdleState> = WlEventConnection::connect()?;
|
||||
let mut connection: WlEventConnection<WatcherState> = WlEventConnection::connect()?;
|
||||
connection.get_kwin_idle()?;
|
||||
|
||||
let timeout = u32::try_from(client.config.idle_timeout.as_secs() * 1000);
|
||||
let mut idle_state = IdleState::new(
|
||||
let mut watcher_state = WatcherState::new(
|
||||
connection.get_kwin_idle_timeout(timeout.unwrap()).unwrap(),
|
||||
Duration::from_std(client.config.idle_timeout).unwrap(),
|
||||
);
|
||||
connection.event_queue.roundtrip(&mut idle_state).unwrap();
|
||||
connection
|
||||
.event_queue
|
||||
.roundtrip(&mut watcher_state)
|
||||
.unwrap();
|
||||
|
||||
Ok(Self {
|
||||
connection,
|
||||
idle_state,
|
||||
watcher_state,
|
||||
})
|
||||
}
|
||||
|
||||
async fn run_iteration(&mut self, client: &Arc<ReportClient>) -> anyhow::Result<()> {
|
||||
self.connection
|
||||
.event_queue
|
||||
.roundtrip(&mut self.idle_state)
|
||||
.roundtrip(&mut self.watcher_state)
|
||||
.map_err(|e| anyhow!("Event queue is not processed: {e}"))?;
|
||||
|
||||
self.idle_state.send_ping(client).await
|
||||
self.watcher_state.idle_state.send_reactive(client).await
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
use async_trait::async_trait;
|
||||
use chrono::Duration;
|
||||
|
||||
use super::{idle, x11_connection::X11Client, Watcher};
|
||||
use crate::report_client::ReportClient;
|
||||
@ -6,10 +7,10 @@ use std::sync::Arc;
|
||||
|
||||
pub struct IdleWatcher {
|
||||
client: X11Client,
|
||||
is_idle: bool,
|
||||
idle_state: idle::State,
|
||||
}
|
||||
|
||||
impl idle::SinceLastInput for IdleWatcher {
|
||||
impl IdleWatcher {
|
||||
async fn seconds_since_input(&mut self) -> anyhow::Result<u32> {
|
||||
self.client.seconds_since_last_input()
|
||||
}
|
||||
@ -17,7 +18,7 @@ impl idle::SinceLastInput for IdleWatcher {
|
||||
|
||||
#[async_trait]
|
||||
impl Watcher for IdleWatcher {
|
||||
async fn new(_: &Arc<ReportClient>) -> anyhow::Result<Self> {
|
||||
async fn new(report_client: &Arc<ReportClient>) -> anyhow::Result<Self> {
|
||||
let mut client = X11Client::new()?;
|
||||
|
||||
// Check if screensaver extension is supported
|
||||
@ -25,12 +26,17 @@ impl Watcher for IdleWatcher {
|
||||
|
||||
Ok(IdleWatcher {
|
||||
client,
|
||||
is_idle: false,
|
||||
idle_state: idle::State::new(
|
||||
Duration::from_std(report_client.config.idle_timeout).unwrap(),
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
async fn run_iteration(&mut self, client: &Arc<ReportClient>) -> anyhow::Result<()> {
|
||||
self.is_idle = idle::ping_since_last_input(self, self.is_idle, client).await?;
|
||||
let seconds = self.seconds_since_input().await?;
|
||||
self.idle_state
|
||||
.send_with_last_input(seconds, client)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user