git.lucas.co / cce-compositor
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 }