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 };