Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
src/server/idle_inhibit_manager.rs (5.3K)
1 // SPDX-FileCopyrightText: © 2026 The River Developers
2 // SPDX-License-Identifier: GPL-3.0-only
3
4 use crate::ffi;
5 use crate::server::{Server, WlListener, wl_signal_add, wl_listener_remove};
6 use crate::scene_node_data::SceneNodeData;
7
8 pub struct IdleInhibitManager {
9 pub wlr_manager: *mut ffi::wlr_idle_inhibit_manager_v1,
10 pub new_idle_inhibitor: ffi::wl_listener,
11 pub inhibitors: ffi::wl_list,
12 pub server: *mut Server,
13 }
14
15 impl IdleInhibitManager {
16 pub unsafe fn init(&mut self, server: *mut Server) -> Result<(), &'static str> {
17 self.server = server;
18 ffi::wl_list_init(&mut self.inhibitors);
19
20 let wlr_manager = ffi::wlr_idle_inhibit_v1_create((*server).wl_server);
21 if wlr_manager.is_null() {
22 return Err("Failed to create wlr_idle_inhibit_manager_v1");
23 }
24 self.wlr_manager = wlr_manager;
25
26 let new_inhibitor_listener = &mut self.new_idle_inhibitor as *mut ffi::wl_listener as *mut WlListener;
27 (*new_inhibitor_listener).notify = Some(handle_new_idle_inhibitor);
28 wl_signal_add(
29 &mut (*self.wlr_manager).events.new_inhibitor,
30 &mut self.new_idle_inhibitor,
31 );
32
33 Ok(())
34 }
35
36 pub unsafe fn deinit(&mut self) {
37 wl_listener_remove(&mut self.new_idle_inhibitor);
38
39 let inhibitors_head = &mut self.inhibitors as *mut ffi::wl_list as *mut crate::server::WlList;
40 let mut curr = (*inhibitors_head).next;
41 while curr != inhibitors_head {
42 let next = (*curr).next;
43 let inhibitor = crate::container_of!(curr, IdleInhibitor, link);
44 IdleInhibitor::destroy(inhibitor);
45 curr = next;
46 }
47 }
48
49 pub unsafe fn check_active(&self) {
50 let mut inhibited = false;
51
52 let inhibitors_head = &self.inhibitors as *const ffi::wl_list as *mut crate::server::WlList;
53 let mut curr = (*inhibitors_head).next;
54 while curr != inhibitors_head {
55 let next = (*curr).next;
56 let inhibitor = crate::container_of!(curr, IdleInhibitor, link);
57
58 let surface = (*(*inhibitor).wlr_inhibitor).surface;
59 if let Some(node_data) = SceneNodeData::from_surface(surface) {
60 match node_data.data {
61 crate::scene_node_data::SceneNodeDataVal::Window(_) |
62 crate::scene_node_data::SceneNodeDataVal::ShellSurface(_) |
63 crate::scene_node_data::SceneNodeDataVal::LockSurface(_) |
64 crate::scene_node_data::SceneNodeDataVal::LayerSurface(_) |
65 crate::scene_node_data::SceneNodeDataVal::OverrideRedirect(_) => {
66 inhibited = true;
67 break;
68 }
69 }
70 }
71 curr = next;
72 }
73
74 let notifier = (*self.server).input_manager.idle_notifier;
75 if !notifier.is_null() {
76 ffi::wlr_idle_notifier_v1_set_inhibited(notifier, inhibited);
77 }
78 (*self.server).idle.set_inhibited(inhibited);
79 }
80 }
81
82 pub struct IdleInhibitor {
83 pub inhibit_manager: *mut IdleInhibitManager,
84 pub wlr_inhibitor: *mut ffi::wlr_idle_inhibitor_v1,
85 pub listen_destroy: ffi::wl_listener,
86 pub link: ffi::wl_list,
87 }
88
89 impl IdleInhibitor {
90 pub unsafe fn create(
91 wlr_inhibitor: *mut ffi::wlr_idle_inhibitor_v1,
92 inhibit_manager: *mut IdleInhibitManager,
93 ) -> Result<*mut Self, &'static str> {
94 let inhibitor = Box::into_raw(Box::new(Self {
95 inhibit_manager,
96 wlr_inhibitor,
97 listen_destroy: std::mem::zeroed(),
98 link: std::mem::zeroed(),
99 }));
100
101 let destroy_listener = &mut (*inhibitor).listen_destroy as *mut ffi::wl_listener as *mut WlListener;
102 (*destroy_listener).notify = Some(handle_inhibitor_destroy);
103 wl_signal_add(
104 &mut (*wlr_inhibitor).events.destroy,
105 &mut (*inhibitor).listen_destroy,
106 );
107
108 let list_head = &mut (*inhibit_manager).inhibitors as *mut ffi::wl_list as *mut crate::server::WlList;
109 crate::server::wl_list_insert((*list_head).prev, &mut (*inhibitor).link as *mut ffi::wl_list as *mut crate::server::WlList);
110
111 (*inhibit_manager).check_active();
112
113 Ok(inhibitor)
114 }
115
116 pub unsafe fn destroy(inhibitor: *mut Self) {
117 wl_listener_remove(&mut (*inhibitor).listen_destroy);
118 crate::server::wl_list_remove(&mut (*inhibitor).link as *mut ffi::wl_list as *mut crate::server::WlList);
119
120 let manager = (*inhibitor).inhibit_manager;
121 let _boxed = Box::from_raw(inhibitor);
122
123 (*manager).check_active();
124 }
125 }
126
127 unsafe extern "C" fn handle_new_idle_inhibitor(
128 listener: *mut ffi::wl_listener,
129 data: *mut std::ffi::c_void,
130 ) {
131 let manager = &mut *crate::container_of!(listener, IdleInhibitManager, new_idle_inhibitor);
132 let inhibitor = data as *mut ffi::wlr_idle_inhibitor_v1;
133
134 if IdleInhibitor::create(inhibitor, manager).is_err() {
135 log::error!("failed to create idle inhibitor");
136 }
137 }
138
139 unsafe extern "C" fn handle_inhibitor_destroy(
140 listener: *mut ffi::wl_listener,
141 _data: *mut std::ffi::c_void,
142 ) {
143 let inhibitor = crate::container_of!(listener, IdleInhibitor, listen_destroy);
144 IdleInhibitor::destroy(inhibitor);
145 }