From ba044793dc91326bd5a50181a3d04505c090d4ee Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sat, 7 Mar 2026 13:50:26 +0100 Subject: [PATCH] control-center: add idle pane --- src/config/handler.rs | 4 +- src/control_center.rs | 8 ++- src/control_center/cc_idle.rs | 72 +++++++++++++++++++++ src/control_center/cc_sidebar.rs | 3 + src/ifs/jay_idle.rs | 4 +- src/ifs/wl_surface/zwp_idle_inhibitor_v1.rs | 4 +- src/state.rs | 24 +++---- 7 files changed, 101 insertions(+), 18 deletions(-) create mode 100644 src/control_center/cc_idle.rs diff --git a/src/config/handler.rs b/src/config/handler.rs index 54196937..77dd9a68 100644 --- a/src/config/handler.rs +++ b/src/config/handler.rs @@ -1123,11 +1123,11 @@ impl ConfigProxyHandler { } fn handle_set_idle(&self, timeout: Duration) { - self.state.idle.set_timeout(timeout); + self.state.idle.set_timeout(&self.state, timeout); } fn handle_set_idle_grace_period(&self, period: Duration) { - self.state.idle.set_grace_period(period); + self.state.idle.set_grace_period(&self.state, period); } fn handle_set_explicit_sync_enabled(&self, enabled: bool) { diff --git a/src/control_center.rs b/src/control_center.rs index 9ca3ca01..a357c2af 100644 --- a/src/control_center.rs +++ b/src/control_center.rs @@ -1,6 +1,6 @@ use { crate::{ - control_center::cc_compositor::CompositorPane, + control_center::{cc_compositor::CompositorPane, cc_idle::IdlePane}, egui_adapter::egui_platform::{ EggError, EggWindow, EggWindowOwner, icons::{ICON_CLOSE, ICON_DRAG_INDICATOR, ICON_INFO}, @@ -31,6 +31,7 @@ use { }; mod cc_compositor; +mod cc_idle; mod cc_sidebar; #[derive(Debug, Error)] @@ -65,6 +66,7 @@ pub struct ControlCenters { bitflags! { ControlCenterInterest: u32; CCI_COMPOSITOR, + CCI_IDLE, } pub struct ControlCenter { @@ -106,6 +108,7 @@ struct PaneState { enum PaneType { Compositor(CompositorPane), + Idle(IdlePane), } struct CcBehavior<'a> { @@ -125,12 +128,14 @@ impl Pane { fn title(&self, res: &mut String) { match &self.ty { PaneType::Compositor(v) => v.title(res), + PaneType::Idle(v) => v.title(res), } } fn show(&mut self, _behavior: &mut CcBehavior<'_>, ui: &mut Ui) { match &mut self.ty { PaneType::Compositor(p) => p.show(ui), + PaneType::Idle(p) => p.show(ui), } } } @@ -139,6 +144,7 @@ impl PaneType { fn interest(&self) -> ControlCenterInterest { match self { PaneType::Compositor(_) => CCI_COMPOSITOR, + PaneType::Idle(_) => CCI_IDLE, } } } diff --git a/src/control_center/cc_idle.rs b/src/control_center/cc_idle.rs new file mode 100644 index 00000000..2520463f --- /dev/null +++ b/src/control_center/cc_idle.rs @@ -0,0 +1,72 @@ +use { + crate::{ + control_center::{ControlCenterInner, grid, row}, + state::State, + }, + egui::{CollapsingHeader, DragValue, Ui, Widget}, + std::{rc::Rc, time::Duration}, +}; + +pub struct IdlePane { + state: Rc, +} + +impl ControlCenterInner { + pub fn create_idle_pane(self: &Rc) -> IdlePane { + IdlePane { + state: self.state.clone(), + } + } +} + +impl IdlePane { + pub fn title(&self, res: &mut String) { + res.push_str("Idle"); + } + + pub fn show(&mut self, ui: &mut Ui) { + grid(ui, "sliders", |ui| { + for interval in [true, false] { + let label = match interval { + true => "Interval", + false => "Grace period", + }; + let idle = &self.state.idle; + let field = match interval { + true => &idle.timeout, + false => &idle.grace_period, + }; + row(ui, label, |ui| { + let secs = field.get().as_secs(); + let mut minutes = secs / 60; + let mut seconds = secs % 60; + let mut changed = false; + changed |= DragValue::new(&mut minutes).ui(ui).changed(); + ui.label("minutes"); + changed |= DragValue::new(&mut seconds).range(0..=59).ui(ui).changed(); + ui.label("seconds"); + if changed { + let duration = + Duration::from_secs(minutes.saturating_mul(60).saturating_add(seconds)); + match interval { + true => idle.set_timeout(&self.state, duration), + false => idle.set_grace_period(&self.state, duration), + } + } + }); + } + }); + let inhibitors = self.state.idle.inhibitors.lock(); + let mut is: Vec<_> = inhibitors.values().collect(); + is.sort_by_key(|is| is.inhibit_id); + CollapsingHeader::new(format!("Inhibitors ({})", is.len())) + .id_salt("Inhibitors") + .show(ui, |ui| { + for i in is { + ui.horizontal(|ui| { + ui.label(&i.client.pid_info.comm); + }); + } + }); + } +} diff --git a/src/control_center/cc_sidebar.rs b/src/control_center/cc_sidebar.rs index f1a484d1..57475be3 100644 --- a/src/control_center/cc_sidebar.rs +++ b/src/control_center/cc_sidebar.rs @@ -9,12 +9,14 @@ use { #[derive(Copy, Clone, Linearize)] enum PaneName { Compositor, + Idle, } impl PaneName { fn name(self) -> &'static str { match self { PaneName::Compositor => "Compositor", + PaneName::Idle => "Idle", } } } @@ -42,6 +44,7 @@ impl ControlCenterInner { PaneName::Compositor => { PaneType::Compositor(self.create_compositor_pane()) } + PaneName::Idle => PaneType::Idle(self.create_idle_pane()), }; self.open(tree, ty); ui.ctx().request_repaint(); diff --git a/src/ifs/jay_idle.rs b/src/ifs/jay_idle.rs index a91a8b20..48cbd7a4 100644 --- a/src/ifs/jay_idle.rs +++ b/src/ifs/jay_idle.rs @@ -68,14 +68,14 @@ impl JayIdleRequestHandler for JayIdle { fn set_interval(&self, req: SetInterval, _slf: &Rc) -> Result<(), Self::Error> { let interval = Duration::from_secs(req.interval); let state = &self.client.state; - state.idle.set_timeout(interval); + state.idle.set_timeout(state, interval); Ok(()) } fn set_grace_period(&self, req: SetGracePeriod, _slf: &Rc) -> Result<(), Self::Error> { let period = Duration::from_secs(req.period); let state = &self.client.state; - state.idle.set_grace_period(period); + state.idle.set_grace_period(state, period); Ok(()) } } diff --git a/src/ifs/wl_surface/zwp_idle_inhibitor_v1.rs b/src/ifs/wl_surface/zwp_idle_inhibitor_v1.rs index 34d26581..73a6fec1 100644 --- a/src/ifs/wl_surface/zwp_idle_inhibitor_v1.rs +++ b/src/ifs/wl_surface/zwp_idle_inhibitor_v1.rs @@ -44,12 +44,12 @@ impl ZwpIdleInhibitorV1 { pub fn activate(self: &Rc) { let state = &self.client.state; - state.idle.add_inhibitor(self); + state.idle.add_inhibitor(state, self); } pub fn deactivate(&self) { let state = &self.client.state; - state.idle.remove_inhibitor(self); + state.idle.remove_inhibitor(state, self); } } diff --git a/src/state.rs b/src/state.rs index a6c6cfaa..b0805b89 100644 --- a/src/state.rs +++ b/src/state.rs @@ -16,7 +16,7 @@ use { cmm::{cmm_description::ColorDescription, cmm_manager::ColorManager}, compositor::{LIBEI_SOCKET, LogLevel}, config::ConfigProxy, - control_center::{CCI_COMPOSITOR, ControlCenters}, + control_center::{CCI_COMPOSITOR, CCI_IDLE, ControlCenters}, copy_device::CopyDeviceRegistry, cpu_worker::CpuWorker, criteria::{clm::ClMatcherManager, tlm::TlMatcherManager}, @@ -347,37 +347,39 @@ pub struct IdleState { } impl IdleState { - pub fn set_timeout(&self, timeout: Duration) { + pub fn set_timeout(&self, state: &State, timeout: Duration) { self.timeout.set(timeout); - self.timeout_changed(); + self.timeout_changed(state); } - pub fn set_grace_period(&self, grace_period: Duration) { + pub fn set_grace_period(&self, state: &State, grace_period: Duration) { self.grace_period.set(grace_period); - self.timeout_changed(); + self.timeout_changed(state); } - fn timeout_changed(&self) { + fn timeout_changed(&self, state: &State) { self.timeout_changed.set(true); self.change.trigger(); + state.trigger_cci(CCI_IDLE); } - pub fn add_inhibitor(&self, inhibitor: &Rc) { + pub fn add_inhibitor(&self, state: &State, inhibitor: &Rc) { self.inhibitors.set(inhibitor.inhibit_id, inhibitor.clone()); - self.inhibitors_changed(); + self.inhibitors_changed(state); } - pub fn remove_inhibitor(&self, inhibitor: &ZwpIdleInhibitorV1) { + pub fn remove_inhibitor(&self, state: &State, inhibitor: &ZwpIdleInhibitorV1) { self.inhibitors.remove(&inhibitor.inhibit_id); - self.inhibitors_changed(); + self.inhibitors_changed(state); if self.inhibitors.is_empty() { self.resume_inhibited_notifications(); } } - fn inhibitors_changed(&self) { + fn inhibitors_changed(&self, state: &State) { self.inhibitors_changed.set(true); self.change.trigger(); + state.trigger_cci(CCI_IDLE); } fn resume_inhibited_notifications(&self) {