⚠️ VeridianOS Kernel Documentation - This is low-level kernel code. All functions are unsafe unless explicitly marked otherwise. no_std

veridian_kernel/desktop/wayland/
idle_inhibit.rs

1//! Idle Inhibit Protocol (zwp_idle_inhibit_manager_v1)
2//!
3//! Allows surfaces to prevent the system from going idle (screen dimming,
4//! locking) while they are visible. This is commonly used by video players,
5//! presentation software, and games to keep the display active.
6//!
7//! An inhibitor is associated with a specific surface. The idle state is
8//! inhibited as long as at least one active inhibitor exists whose surface
9//! is visible (mapped).
10
11#![allow(dead_code)]
12
13use alloc::collections::BTreeMap;
14
15use crate::error::KernelError;
16
17// ---------------------------------------------------------------------------
18// Protocol constants
19// ---------------------------------------------------------------------------
20
21/// Wayland global interface name for idle inhibit manager
22pub const ZWP_IDLE_INHIBIT_MANAGER_V1: &str = "zwp_idle_inhibit_manager_v1";
23
24/// Protocol version
25pub const ZWP_IDLE_INHIBIT_MANAGER_V1_VERSION: u32 = 1;
26
27// Manager request opcodes
28/// destroy
29pub const ZWP_IDLE_INHIBIT_MANAGER_V1_DESTROY: u16 = 0;
30/// create_inhibitor(id: new_id, surface: object)
31pub const ZWP_IDLE_INHIBIT_MANAGER_V1_CREATE_INHIBITOR: u16 = 1;
32
33// Inhibitor request opcodes
34/// destroy
35pub const ZWP_IDLE_INHIBITOR_V1_DESTROY: u16 = 0;
36
37// ---------------------------------------------------------------------------
38// Types
39// ---------------------------------------------------------------------------
40
41/// An idle inhibitor tied to a specific surface.
42///
43/// While active, prevents the system from entering idle state (e.g.,
44/// dimming the screen or activating a screen locker). The inhibitor
45/// is automatically deactivated when its associated surface is destroyed
46/// or unmapped.
47pub struct IdleInhibitor {
48    /// Inhibitor object ID
49    pub id: u32,
50    /// Surface ID that this inhibitor is tied to
51    pub surface_id: u32,
52    /// Whether this inhibitor is currently active
53    pub active: bool,
54}
55
56impl IdleInhibitor {
57    /// Create a new active idle inhibitor for the given surface.
58    pub fn new(id: u32, surface_id: u32) -> Self {
59        Self {
60            id,
61            surface_id,
62            active: true,
63        }
64    }
65}
66
67// ---------------------------------------------------------------------------
68// Idle inhibit manager
69// ---------------------------------------------------------------------------
70
71/// Manages idle inhibitors and queries the global idle-inhibited state.
72pub struct IdleInhibitManager {
73    /// All inhibitors keyed by their object ID
74    inhibitors: BTreeMap<u32, IdleInhibitor>,
75    /// Next inhibitor ID
76    next_id: u32,
77}
78
79impl IdleInhibitManager {
80    /// Create a new idle inhibit manager.
81    pub fn new() -> Self {
82        Self {
83            inhibitors: BTreeMap::new(),
84            next_id: 1,
85        }
86    }
87
88    /// Create a new inhibitor for the specified surface.
89    ///
90    /// Returns the inhibitor ID assigned by the manager.
91    pub fn create_inhibitor(&mut self, surface_id: u32) -> Result<u32, KernelError> {
92        let id = self.next_id;
93        self.next_id += 1;
94
95        let inhibitor = IdleInhibitor::new(id, surface_id);
96        self.inhibitors.insert(id, inhibitor);
97
98        Ok(id)
99    }
100
101    /// Destroy an inhibitor by its object ID.
102    pub fn destroy_inhibitor(&mut self, id: u32) -> Result<(), KernelError> {
103        self.inhibitors.remove(&id).ok_or(KernelError::NotFound {
104            resource: "idle_inhibitor",
105            id: id as u64,
106        })?;
107        Ok(())
108    }
109
110    /// Remove all inhibitors associated with a specific surface.
111    ///
112    /// Called when a surface is destroyed to clean up its inhibitors.
113    /// Returns the number of inhibitors removed.
114    pub fn remove_inhibitors_for_surface(&mut self, surface_id: u32) -> usize {
115        let before = self.inhibitors.len();
116        self.inhibitors
117            .retain(|_, inh| inh.surface_id != surface_id);
118        before - self.inhibitors.len()
119    }
120
121    /// Check whether idle should be inhibited.
122    ///
123    /// Returns `true` if at least one active inhibitor exists. In a full
124    /// implementation, this would also check whether the inhibitor's
125    /// surface is currently visible/mapped.
126    pub fn is_idle_inhibited(&self) -> bool {
127        self.inhibitors.values().any(|inh| inh.active)
128    }
129
130    /// Get the number of active inhibitors.
131    pub fn active_count(&self) -> usize {
132        self.inhibitors.values().filter(|inh| inh.active).count()
133    }
134
135    /// Get a reference to a specific inhibitor.
136    pub fn get_inhibitor(&self, id: u32) -> Option<&IdleInhibitor> {
137        self.inhibitors.get(&id)
138    }
139
140    /// Total number of inhibitors (active and inactive).
141    pub fn inhibitor_count(&self) -> usize {
142        self.inhibitors.len()
143    }
144}
145
146impl Default for IdleInhibitManager {
147    fn default() -> Self {
148        Self::new()
149    }
150}
151
152// ---------------------------------------------------------------------------
153// Tests
154// ---------------------------------------------------------------------------
155
156#[cfg(test)]
157mod tests {
158    use super::*;
159
160    #[test]
161    fn test_create_inhibitor() {
162        let mut mgr = IdleInhibitManager::new();
163        let id = mgr.create_inhibitor(10).unwrap();
164        assert!(mgr.is_idle_inhibited());
165        assert_eq!(mgr.active_count(), 1);
166
167        let inh = mgr.get_inhibitor(id).unwrap();
168        assert_eq!(inh.surface_id, 10);
169        assert!(inh.active);
170    }
171
172    #[test]
173    fn test_destroy_inhibitor() {
174        let mut mgr = IdleInhibitManager::new();
175        let id = mgr.create_inhibitor(10).unwrap();
176        assert!(mgr.is_idle_inhibited());
177
178        mgr.destroy_inhibitor(id).unwrap();
179        assert!(!mgr.is_idle_inhibited());
180        assert_eq!(mgr.inhibitor_count(), 0);
181    }
182
183    #[test]
184    fn test_destroy_nonexistent() {
185        let mut mgr = IdleInhibitManager::new();
186        assert!(mgr.destroy_inhibitor(999).is_err());
187    }
188
189    #[test]
190    fn test_remove_for_surface() {
191        let mut mgr = IdleInhibitManager::new();
192        mgr.create_inhibitor(10).unwrap();
193        mgr.create_inhibitor(10).unwrap();
194        mgr.create_inhibitor(20).unwrap();
195
196        let removed = mgr.remove_inhibitors_for_surface(10);
197        assert_eq!(removed, 2);
198        assert_eq!(mgr.inhibitor_count(), 1);
199        assert!(mgr.is_idle_inhibited()); // surface 20 still active
200    }
201
202    #[test]
203    fn test_not_inhibited_when_empty() {
204        let mgr = IdleInhibitManager::new();
205        assert!(!mgr.is_idle_inhibited());
206        assert_eq!(mgr.active_count(), 0);
207    }
208
209    #[test]
210    fn test_multiple_inhibitors() {
211        let mut mgr = IdleInhibitManager::new();
212        mgr.create_inhibitor(1).unwrap();
213        mgr.create_inhibitor(2).unwrap();
214        mgr.create_inhibitor(3).unwrap();
215        assert_eq!(mgr.active_count(), 3);
216        assert!(mgr.is_idle_inhibited());
217    }
218}