git.lucas.co / cce-compositor
Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git

src/server/wm_node.rs (7.3K)

  1 // SPDX-FileCopyrightText: © 2024 The River Developers
  2 // SPDX-License-Identifier: GPL-3.0-only
  3 
  4 use crate::ffi;
  5 use crate::server::{WlList, wl_list_insert, wl_list_remove};
  6 use crate::window::Window;
  7 use crate::shell_surface::ShellSurface;
  8 
  9 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
 10 pub enum WmNodeTag {
 11     Window,
 12     ShellSurface,
 13 }
 14 
 15 pub struct WmNode {
 16     pub tag: WmNodeTag,
 17     pub object: *mut ffi::wl_resource, // zcce_node_v1
 18     pub link: ffi::wl_list,
 19 }
 20 
 21 pub enum WmNodeType {
 22     Window(*mut Window),
 23     ShellSurface(*mut ShellSurface),
 24 }
 25 
 26 impl WmNode {
 27     pub unsafe fn init(&mut self, tag: WmNodeTag) {
 28         self.tag = tag;
 29         self.object = std::ptr::null_mut();
 30         self.link.prev = &mut self.link;
 31         self.link.next = &mut self.link;
 32     }
 33 
 34     pub unsafe fn deinit(&mut self) {
 35         self.make_inert();
 36         if !self.link.prev.is_null() && !self.link.next.is_null() {
 37             wl_list_remove(&mut self.link as *mut ffi::wl_list as *mut WlList);
 38         }
 39     }
 40 
 41     pub unsafe fn get(&self) -> WmNodeType {
 42         match self.tag {
 43             WmNodeTag::Window => {
 44                 let window_ptr = crate::container_of!(self, Window, node);
 45                 WmNodeType::Window(window_ptr)
 46             }
 47             WmNodeTag::ShellSurface => {
 48                 let shell_surface_ptr = crate::container_of!(self, ShellSurface, node);
 49                 WmNodeType::ShellSurface(shell_surface_ptr)
 50             }
 51         }
 52     }
 53 
 54     pub unsafe fn create_object(&mut self, client: *mut ffi::wl_client, version: u32, id: u32) {
 55         assert!(self.object.is_null());
 56         let resource = ffi::wl_resource_create(client, &ffi::zcce_node_v1_interface, version as i32, id);
 57         if resource.is_null() {
 58             log::error!("out of memory");
 59             ffi::wl_client_post_no_memory(client);
 60             return;
 61         }
 62 
 63         ffi::wl_resource_set_implementation(
 64             resource,
 65             &NODE_INTERFACE as *const _ as *const _,
 66             self as *mut WmNode as *mut _,
 67             Some(handle_destroy),
 68         );
 69         self.object = resource;
 70     }
 71 
 72     pub unsafe fn make_inert(&mut self) {
 73         if !self.object.is_null() {
 74             ffi::wl_resource_set_implementation(
 75                 self.object,
 76                 &INERT_NODE_INTERFACE as *const _ as *const _,
 77                 std::ptr::null_mut(),
 78                 None,
 79             );
 80             self.object = std::ptr::null_mut();
 81         }
 82     }
 83 }
 84 
 85 unsafe extern "C" fn handle_destroy(resource: *mut ffi::wl_resource) {
 86     let node = ffi::wl_resource_get_user_data(resource) as *mut WmNode;
 87     if !node.is_null() {
 88         (*node).object = std::ptr::null_mut();
 89     }
 90 }
 91 
 92 unsafe extern "C" fn node_destroy(_client: *mut ffi::wl_client, resource: *mut ffi::wl_resource) {
 93     ffi::wl_resource_destroy(resource);
 94 }
 95 
 96 unsafe extern "C" fn node_set_position(
 97     _client: *mut ffi::wl_client,
 98     resource: *mut ffi::wl_resource,
 99     x: i32,
100     y: i32,
101 ) {
102     let node = ffi::wl_resource_get_user_data(resource) as *mut WmNode;
103     if node.is_null() {
104         return;
105     }
106     
107     let server = match (*node).get() {
108         WmNodeType::Window(w) => (*w).server,
109         WmNodeType::ShellSurface(s) => (*s).server,
110     };
111     
112     if !(*server).wm.ensure_rendering() {
113         return;
114     }
115     
116     match (*node).get() {
117         WmNodeType::Window(w) => {
118             if (*w).get_parent().is_null() {
119                 (*w).rendering_requested.x = x;
120                 (*w).rendering_requested.y = y;
121             }
122         }
123         WmNodeType::ShellSurface(s) => {
124             (*s).rendering_requested.x = x;
125             (*s).rendering_requested.y = y;
126         }
127     }
128 }
129 
130 unsafe extern "C" fn node_place_top(
131     _client: *mut ffi::wl_client,
132     resource: *mut ffi::wl_resource,
133 ) {
134     let node = ffi::wl_resource_get_user_data(resource) as *mut WmNode;
135     if node.is_null() {
136         return;
137     }
138     let server = match (*node).get() {
139         WmNodeType::Window(w) => (*w).server,
140         WmNodeType::ShellSurface(s) => (*s).server,
141     };
142     if !(*server).wm.ensure_rendering() {
143         return;
144     }
145     let node_link = &mut (*node).link as *mut ffi::wl_list as *mut WlList;
146     let list_head = &mut (*server).wm.rendering_requested.list as *mut ffi::wl_list as *mut WlList;
147     if (*node_link).next != list_head {
148         wl_list_remove(node_link);
149         wl_list_insert((*list_head).prev, node_link);
150     }
151 }
152 
153 unsafe extern "C" fn node_place_bottom(
154     _client: *mut ffi::wl_client,
155     resource: *mut ffi::wl_resource,
156 ) {
157     let node = ffi::wl_resource_get_user_data(resource) as *mut WmNode;
158     if node.is_null() {
159         return;
160     }
161     let server = match (*node).get() {
162         WmNodeType::Window(w) => (*w).server,
163         WmNodeType::ShellSurface(s) => (*s).server,
164     };
165     if !(*server).wm.ensure_rendering() {
166         return;
167     }
168     let node_link = &mut (*node).link as *mut ffi::wl_list as *mut WlList;
169     let list_head = &mut (*server).wm.rendering_requested.list as *mut ffi::wl_list as *mut WlList;
170     if (*node_link).prev != list_head {
171         wl_list_remove(node_link);
172         wl_list_insert(list_head, node_link);
173     }
174 }
175 
176 unsafe extern "C" fn node_place_above(
177     _client: *mut ffi::wl_client,
178     resource: *mut ffi::wl_resource,
179     other: *mut ffi::wl_resource,
180 ) {
181     let node = ffi::wl_resource_get_user_data(resource) as *mut WmNode;
182     if node.is_null() {
183         return;
184     }
185     let server = match (*node).get() {
186         WmNodeType::Window(w) => (*w).server,
187         WmNodeType::ShellSurface(s) => (*s).server,
188     };
189     if !(*server).wm.ensure_rendering() {
190         return;
191     }
192     
193     let other_node = ffi::wl_resource_get_user_data(other) as *mut WmNode;
194     if other_node.is_null() || other_node == node {
195         return;
196     }
197     
198     wl_list_remove(&mut (*node).link as *mut ffi::wl_list as *mut WlList);
199     wl_list_insert(
200         &mut (*other_node).link as *mut ffi::wl_list as *mut WlList,
201         &mut (*node).link as *mut ffi::wl_list as *mut WlList,
202     );
203 }
204 
205 unsafe extern "C" fn node_place_below(
206     _client: *mut ffi::wl_client,
207     resource: *mut ffi::wl_resource,
208     other: *mut ffi::wl_resource,
209 ) {
210     let node = ffi::wl_resource_get_user_data(resource) as *mut WmNode;
211     if node.is_null() {
212         return;
213     }
214     let server = match (*node).get() {
215         WmNodeType::Window(w) => (*w).server,
216         WmNodeType::ShellSurface(s) => (*s).server,
217     };
218     if !(*server).wm.ensure_rendering() {
219         return;
220     }
221     
222     let other_node = ffi::wl_resource_get_user_data(other) as *mut WmNode;
223     if other_node.is_null() || other_node == node {
224         return;
225     }
226     
227     wl_list_remove(&mut (*node).link as *mut ffi::wl_list as *mut WlList);
228     wl_list_insert(
229         (*other_node).link.prev as *mut WlList,
230         &mut (*node).link as *mut ffi::wl_list as *mut WlList,
231     );
232 }
233 
234 static NODE_INTERFACE: ffi::zcce_node_v1_interface = ffi::zcce_node_v1_interface {
235     destroy: Some(node_destroy),
236     set_position: Some(node_set_position),
237     place_top: Some(node_place_top),
238     place_bottom: Some(node_place_bottom),
239     place_above: Some(node_place_above),
240     place_below: Some(node_place_below),
241 };
242 
243 static INERT_NODE_INTERFACE: ffi::zcce_node_v1_interface = ffi::zcce_node_v1_interface {
244     destroy: Some(node_destroy),
245     set_position: None,
246     place_top: None,
247     place_bottom: None,
248     place_above: None,
249     place_below: None,
250 };