diff --git a/deploy-notes.md b/deploy-notes.md index 01dfd8fc..aec75929 100644 --- a/deploy-notes.md +++ b/deploy-notes.md @@ -1,5 +1,9 @@ # Unreleased +- Needs jay-config release. +- Needs jay-toml-config release. +- Needs jay-compositor release. + # 1.7.0 - Needs jay-config release. diff --git a/docs/features.md b/docs/features.md index b0451a02..15a2e344 100644 --- a/docs/features.md +++ b/docs/features.md @@ -143,7 +143,7 @@ Jay supports the following wayland protocols: | ext_data_control_manager_v1 | 1 | Yes | | ext_foreign_toplevel_image_capture_source_manager_v1 | 1 | | | ext_foreign_toplevel_list_v1 | 1 | Yes | -| ext_idle_notifier_v1 | 1 | Yes | +| ext_idle_notifier_v1 | 2 | Yes | | ext_image_copy_capture_manager_v1 | 1[^composited] | Yes | | ext_output_image_capture_source_manager_v1 | 1 | | | ext_session_lock_manager_v1 | 1 | Yes | diff --git a/release-notes.md b/release-notes.md index e7568aea..86ca1c28 100644 --- a/release-notes.md +++ b/release-notes.md @@ -4,6 +4,7 @@ - Add support fo ext-data-control-v1. - Implement wl-fixes. - Implement ei_touchscreen v2. +- Implement idle-notification v2. # 1.7.0 (2024-10-25) diff --git a/src/compositor.rs b/src/compositor.rs index a77d6170..738d370f 100644 --- a/src/compositor.rs +++ b/src/compositor.rs @@ -203,6 +203,7 @@ fn start_compositor2( timeout_changed: Default::default(), inhibitors: Default::default(), inhibitors_changed: Default::default(), + inhibited_idle_notifications: Default::default(), backend_idle: Cell::new(true), }, run_args, diff --git a/src/ifs/ext_idle_notification_v1.rs b/src/ifs/ext_idle_notification_v1.rs index 935ddfbb..4ecd7b08 100644 --- a/src/ifs/ext_idle_notification_v1.rs +++ b/src/ifs/ext_idle_notification_v1.rs @@ -26,6 +26,7 @@ pub struct ExtIdleNotificationV1 { impl ExtIdleNotificationV1 { fn detach(&self) { self.seat.remove_idle_notification(self); + self.client.state.idle.remove_inhibited_notification(self); self.task.take(); } } diff --git a/src/ifs/ext_idle_notifier_v1.rs b/src/ifs/ext_idle_notifier_v1.rs index ca70529b..6df798f9 100644 --- a/src/ifs/ext_idle_notifier_v1.rs +++ b/src/ifs/ext_idle_notifier_v1.rs @@ -6,7 +6,7 @@ use { leaks::Tracker, object::{Object, Version}, utils::errorfmt::ErrorFmt, - wire::{ext_idle_notifier_v1::*, ExtIdleNotifierV1Id}, + wire::{ext_idle_notifier_v1::*, ExtIdleNotificationV1Id, ExtIdleNotifierV1Id, WlSeatId}, }, std::{cell::Cell, rc::Rc}, thiserror::Error, @@ -46,6 +46,36 @@ pub struct ExtIdleNotifierV1 { pub version: Version, } +impl ExtIdleNotifierV1 { + fn create_notification( + &self, + id: ExtIdleNotificationV1Id, + timeout: u32, + seat: WlSeatId, + skip_if_inhibited: bool, + ) -> Result<(), ExtIdleNotifierV1Error> { + let seat = self.client.lookup(seat)?; + let notification = Rc::new(ExtIdleNotificationV1 { + id, + client: self.client.clone(), + tracker: Default::default(), + resume: Default::default(), + task: Cell::new(None), + seat: seat.global.clone(), + duration_usec: (timeout as u64).max(1000).saturating_mul(1000), + version: self.version, + }); + track!(self.client, notification); + self.client.add_client_obj(¬ification)?; + let future = self.client.state.eng.spawn( + "idle notifier", + run(notification.clone(), skip_if_inhibited), + ); + notification.task.set(Some(future)); + Ok(()) + } +} + impl ExtIdleNotifierV1RequestHandler for ExtIdleNotifierV1 { type Error = ExtIdleNotifierV1Error; @@ -59,30 +89,19 @@ impl ExtIdleNotifierV1RequestHandler for ExtIdleNotifierV1 { req: GetIdleNotification, _slf: &Rc, ) -> Result<(), Self::Error> { - let seat = self.client.lookup(req.seat)?; - let notification = Rc::new(ExtIdleNotificationV1 { - id: req.id, - client: self.client.clone(), - tracker: Default::default(), - resume: Default::default(), - task: Cell::new(None), - seat: seat.global.clone(), - duration_usec: (req.timeout as u64).max(1000).saturating_mul(1000), - version: self.version, - }); - track!(self.client, notification); - self.client.add_client_obj(¬ification)?; - let future = self - .client - .state - .eng - .spawn("idle notifier", run(notification.clone())); - notification.task.set(Some(future)); - Ok(()) + self.create_notification(req.id, req.timeout, req.seat, true) + } + + fn get_input_idle_notification( + &self, + req: GetInputIdleNotification, + _slf: &Rc, + ) -> Result<(), Self::Error> { + self.create_notification(req.id, req.timeout, req.seat, false) } } -async fn run(n: Rc) { +async fn run(n: Rc, skip_if_inhibited: bool) { loop { let now = n.client.state.now_usec(); let elapsed = now.saturating_sub(n.seat.last_input()); @@ -98,10 +117,18 @@ async fn run(n: Rc) { return; } } else { - n.send_idled(); - n.seat.add_idle_notification(&n); + let idle = &n.client.state.idle; + let send_idle = !skip_if_inhibited || idle.inhibitors.is_empty(); + if send_idle { + n.send_idled(); + n.seat.add_idle_notification(&n); + } else { + idle.add_inhibited_notification(&n); + } n.resume.triggered().await; - n.send_resumed(); + if send_idle { + n.send_resumed(); + } } } } @@ -118,7 +145,7 @@ impl Global for ExtIdleNotifierV1Global { } fn version(&self) -> u32 { - 1 + 2 } fn required_caps(&self) -> ClientCaps { diff --git a/src/state.rs b/src/state.rs index 6a958b72..242243e3 100644 --- a/src/state.rs +++ b/src/state.rs @@ -34,6 +34,7 @@ use { globals::{Globals, GlobalsError, RemovableWaylandGlobal, WaylandGlobal}, ifs::{ ext_foreign_toplevel_list_v1::ExtForeignToplevelListV1, + ext_idle_notification_v1::ExtIdleNotificationV1, ext_session_lock_v1::ExtSessionLockV1, ipc::{ data_control::DataControlDeviceIds, x_data_device::XIpcDeviceIds, DataOfferIds, @@ -94,8 +95,8 @@ use { }, wheel::Wheel, wire::{ - ExtForeignToplevelListV1Id, JayRenderCtxId, JaySeatEventsId, JayWorkspaceWatcherId, - ZwpLinuxDmabufFeedbackV1Id, + ExtForeignToplevelListV1Id, ExtIdleNotificationV1Id, JayRenderCtxId, JaySeatEventsId, + JayWorkspaceWatcherId, ZwpLinuxDmabufFeedbackV1Id, }, xkbcommon::{KeyboardStateIds, XkbContext, XkbKeymap, XkbState}, xwayland::{self, XWaylandEvent}, @@ -264,6 +265,8 @@ pub struct IdleState { pub inhibitors: CopyHashMap>, pub inhibitors_changed: Cell, pub backend_idle: Cell, + pub inhibited_idle_notifications: + CopyHashMap<(ClientId, ExtIdleNotificationV1Id), Rc>, } impl IdleState { @@ -283,6 +286,25 @@ impl IdleState { self.inhibitors.remove(&inhibitor.inhibit_id); self.inhibitors_changed.set(true); self.change.trigger(); + if self.inhibitors.is_empty() { + self.resume_inhibited_notifications(); + } + } + + fn resume_inhibited_notifications(&self) { + for notification in self.inhibited_idle_notifications.lock().drain_values() { + notification.resume.trigger(); + } + } + + pub fn add_inhibited_notification(&self, n: &Rc) { + self.inhibited_idle_notifications + .set((n.client.id, n.id), n.clone()); + } + + pub fn remove_inhibited_notification(&self, n: &ExtIdleNotificationV1) { + self.inhibited_idle_notifications + .remove(&(n.client.id, n.id)); } } diff --git a/wire/ext_idle_notifier_v1.txt b/wire/ext_idle_notifier_v1.txt index 99f95d47..bf3e1e10 100644 --- a/wire/ext_idle_notifier_v1.txt +++ b/wire/ext_idle_notifier_v1.txt @@ -8,3 +8,9 @@ request get_idle_notification { timeout: u32, seat: id(wl_seat), } + +request get_input_idle_notification { + id: id(ext_idle_notification_v1), + timeout: u32, + seat: id(wl_seat), +}