Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
src/server/layer_shell.rs (50.8K)
1 // SPDX-FileCopyrightText: © 2025 The River Developers
2 // SPDX-License-Identifier: GPL-3.0-only
3
4 use std::ffi::CStr;
5 use crate::ffi;
6 use crate::server::{Server, WlListener, WlList, wl_list_insert, wl_list_remove, wl_signal_add, wl_listener_remove};
7 use crate::slotmap::{SlotMap, Key};
8 use crate::output::Output;
9 use crate::seat::Seat;
10 use crate::scene_node_data::{SceneNodeData, SceneNodeDataVal};
11 use crate::xdg_popup::XdgPopup;
12
13 #[derive(Clone, Copy, PartialEq, Eq)]
14 pub enum LayerShellSeatFocus {
15 Exclusive(Key),
16 NonExclusive(Key),
17 None,
18 }
19
20 pub struct LayerShellObject {
21 pub resource: *mut ffi::wl_resource,
22 pub link: ffi::wl_list,
23 }
24
25 pub struct LayerShell {
26 pub server: *mut Server,
27 pub global: *mut ffi::wl_global,
28 pub wlr_shell: *mut ffi::wlr_layer_shell_v1,
29 pub objects: ffi::wl_list,
30 pub surfaces: SlotMap<*mut LayerSurface>,
31 pub new_surface: ffi::wl_listener,
32 }
33
34 impl LayerShell {
35 pub unsafe fn init(&mut self, server: *mut Server, wl_display: *mut ffi::wl_display) -> Result<(), ()> {
36 self.server = server;
37 self.global = ffi::wl_global_create(
38 wl_display,
39 &ffi::river_layer_shell_v1_interface,
40 1,
41 self as *mut LayerShell as *mut _,
42 Some(bind),
43 );
44 if self.global.is_null() {
45 return Err(());
46 }
47
48 self.wlr_shell = ffi::wlr_layer_shell_v1_create(wl_display, 4);
49 if self.wlr_shell.is_null() {
50 ffi::wl_global_destroy(self.global);
51 self.global = std::ptr::null_mut();
52 return Err(());
53 }
54
55 ffi::wl_list_init(&mut self.objects);
56
57 let new_surface_ptr = &mut self.new_surface as *mut ffi::wl_listener as *mut WlListener;
58 (*new_surface_ptr).notify = Some(handle_new_surface);
59 wl_signal_add(&mut (*self.wlr_shell).events.new_surface, &mut self.new_surface);
60
61 Ok(())
62 }
63
64 pub unsafe fn deinit(&mut self) {
65 if !self.global.is_null() {
66 ffi::wl_global_destroy(self.global);
67 self.global = std::ptr::null_mut();
68 }
69 if !self.new_surface.link.prev.is_null() {
70 wl_listener_remove(&mut self.new_surface);
71 }
72 }
73
74 pub unsafe fn supported(&self) -> bool {
75 let wm_v1 = (*self.server).wm.object;
76 if wm_v1.is_null() {
77 return true;
78 }
79 let wm_client = ffi::wl_resource_get_client(wm_v1);
80
81 let objects_list = &self.objects as *const ffi::wl_list as *mut WlList;
82 let mut curr = (*objects_list).next;
83 while curr != objects_list {
84 let next = (*curr).next;
85 let obj = crate::container_of!(curr, LayerShellObject, link);
86 let obj_client = ffi::wl_resource_get_client((*obj).resource);
87 if obj_client == wm_client {
88 return true;
89 }
90 curr = next;
91 }
92 false
93 }
94
95 pub unsafe fn check_exclusive_focus(&mut self) {
96 let layers = [
97 ffi::zwlr_layer_shell_v1_layer_ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY,
98 ffi::zwlr_layer_shell_v1_layer_ZWLR_LAYER_SHELL_V1_LAYER_TOP,
99 ];
100 let mut to_focus: *mut LayerSurface = std::ptr::null_mut();
101
102 'outer: for &layer in &layers {
103 let tree = (*self.server).scene.layer_surface_tree(layer);
104 let children_head = ffi::river_scene_tree_get_children(tree) as *mut WlList;
105 let mut curr = (*children_head).prev;
106 while curr != children_head {
107 let prev = (*curr).prev;
108 let node = ffi::river_scene_node_from_children_link(curr as *mut ffi::wl_list);
109 if let Some(node_data) = SceneNodeData::from_node(node) {
110 if let SceneNodeDataVal::LayerSurface(layer_surface) = node_data.data {
111 let wlr_layer_surface = (*layer_surface).wlr_layer_surface;
112 if ffi::river_wlr_surface_is_mapped((*wlr_layer_surface).surface) &&
113 (*wlr_layer_surface).current.keyboard_interactive == ffi::zwlr_layer_surface_v1_keyboard_interactivity_ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE {
114 to_focus = layer_surface;
115 break 'outer;
116 }
117 }
118 }
119 curr = prev;
120 }
121 }
122
123 let seats = &mut (*self.server).input_manager.seats as *mut ffi::wl_list as *mut WlList;
124 let mut curr = (*seats).next;
125 while curr != seats {
126 let next = (*curr).next;
127 let seat = crate::container_of!(curr, Seat, link);
128 if !to_focus.is_null() {
129 (*seat).layer_shell.scheduled_focus = LayerShellSeatFocus::Exclusive((*to_focus).ref_key);
130 } else if matches!((*seat).layer_shell.scheduled_focus, LayerShellSeatFocus::Exclusive(_)) {
131 (*seat).layer_shell.scheduled_focus = LayerShellSeatFocus::None;
132 }
133 curr = next;
134 }
135 }
136 }
137
138 unsafe extern "C" fn bind(
139 client: *mut ffi::wl_client,
140 data: *mut std::ffi::c_void,
141 version: u32,
142 id: u32,
143 ) {
144 let layer_shell = data as *mut LayerShell;
145 if layer_shell.is_null() {
146 return;
147 }
148
149 let resource = ffi::wl_resource_create(client, &ffi::river_layer_shell_v1_interface, version as i32, id);
150 if resource.is_null() {
151 ffi::wl_client_post_no_memory(client);
152 log::error!("out of memory binding river_layer_shell_v1");
153 return;
154 }
155
156 let obj = Box::into_raw(Box::new(LayerShellObject {
157 resource,
158 link: std::mem::zeroed(),
159 }));
160 ffi::wl_list_init(&mut (*obj).link);
161 let objects_list = &mut (*layer_shell).objects as *mut ffi::wl_list as *mut WlList;
162 let link_custom = &mut (*obj).link as *mut ffi::wl_list as *mut WlList;
163 wl_list_insert(objects_list, link_custom);
164
165 ffi::wl_resource_set_implementation(
166 resource,
167 &LAYER_SHELL_INTERFACE as *const _ as *const _,
168 obj as *mut _,
169 Some(handle_destroy_resource),
170 );
171 }
172
173 unsafe extern "C" fn handle_destroy_resource(resource: *mut ffi::wl_resource) {
174 let obj = ffi::wl_resource_get_user_data(resource) as *mut LayerShellObject;
175 if !obj.is_null() {
176 wl_list_remove(&mut (*obj).link as *mut ffi::wl_list as *mut WlList);
177 let _ = Box::from_raw(obj);
178 }
179 }
180
181 unsafe extern "C" fn layer_shell_destroy(client: *mut ffi::wl_client, resource: *mut ffi::wl_resource) {
182 let _ = client;
183 ffi::wl_resource_destroy(resource);
184 }
185
186 unsafe extern "C" fn layer_shell_get_output(
187 client: *mut ffi::wl_client,
188 resource: *mut ffi::wl_resource,
189 id: u32,
190 output_resource: *mut ffi::wl_resource,
191 ) {
192 let output = ffi::wl_resource_get_user_data(output_resource) as *mut Output;
193 if output.is_null() {
194 return;
195 }
196 if !(*output).layer_shell.object.is_null() {
197 ffi::wl_resource_post_error(
198 resource,
199 ffi::river_layer_shell_v1_error_RIVER_LAYER_SHELL_V1_ERROR_OBJECT_ALREADY_CREATED,
200 b"river_layer_shell_output_v1 already created\0".as_ptr() as *const _,
201 );
202 return;
203 }
204 let version = ffi::wl_resource_get_version(resource);
205 (*output).layer_shell.create_object(client, version as u32, id, output);
206 }
207
208 unsafe extern "C" fn layer_shell_get_seat(
209 client: *mut ffi::wl_client,
210 resource: *mut ffi::wl_resource,
211 id: u32,
212 seat_resource: *mut ffi::wl_resource,
213 ) {
214 let seat = ffi::wl_resource_get_user_data(seat_resource) as *mut Seat;
215 if seat.is_null() {
216 return;
217 }
218 if !(*seat).layer_shell.object.is_null() {
219 ffi::wl_resource_post_error(
220 resource,
221 ffi::river_layer_shell_v1_error_RIVER_LAYER_SHELL_V1_ERROR_OBJECT_ALREADY_CREATED,
222 b"river_layer_shell_seat_v1 already created\0".as_ptr() as *const _,
223 );
224 return;
225 }
226 let version = ffi::wl_resource_get_version(resource);
227 (*seat).layer_shell.create_object(client, version as u32, id, seat);
228 }
229
230 static LAYER_SHELL_INTERFACE: ffi::river_layer_shell_v1_interface = ffi::river_layer_shell_v1_interface {
231 destroy: Some(layer_shell_destroy),
232 get_output: Some(layer_shell_get_output),
233 get_seat: Some(layer_shell_get_seat),
234 };
235
236 unsafe extern "C" fn handle_new_surface(listener: *mut ffi::wl_listener, data: *mut std::ffi::c_void) {
237 let layer_shell = crate::container_of!(listener, LayerShell, new_surface);
238 let wlr_layer_surface = data as *mut ffi::wlr_layer_surface_v1;
239
240 log::debug!(
241 "new layer surface: namespace {:?}, layer {}, anchor {}, size {}x{}, margin: top={}, right={}, bottom={}, left={}, exclusive_zone={}",
242 CStr::from_ptr((*wlr_layer_surface).namespace),
243 (*wlr_layer_surface).current.layer,
244 (*wlr_layer_surface).current.anchor,
245 (*wlr_layer_surface).current.desired_width,
246 (*wlr_layer_surface).current.desired_height,
247 (*wlr_layer_surface).current.margin.top,
248 (*wlr_layer_surface).current.margin.right,
249 (*wlr_layer_surface).current.margin.bottom,
250 (*wlr_layer_surface).current.margin.left,
251 (*wlr_layer_surface).current.exclusive_zone,
252 );
253
254 if !(*layer_shell).supported() {
255 log::info!("window manager did not bind river_layer_shell_v1, closing layer surface");
256 ffi::wlr_layer_surface_v1_destroy(wlr_layer_surface);
257 return;
258 }
259
260 if (*wlr_layer_surface).output.is_null() {
261 let outputs = &mut (*(*layer_shell).server).om.outputs as *mut ffi::wl_list as *mut WlList;
262 let mut curr = (*outputs).next;
263 while curr != outputs {
264 let next = (*curr).next;
265 let output = crate::container_of!(curr, Output, link);
266 if (*output).layer_shell.requested.default {
267 (*wlr_layer_surface).output = (*output).wlr_output;
268 break;
269 }
270 curr = next;
271 }
272
273 if (*wlr_layer_surface).output.is_null() {
274 let first_node = (*outputs).next;
275 if first_node != outputs {
276 let output = crate::container_of!(first_node, Output, link);
277 log::info!("window manager did not set default layer surface output, choosing arbitrary output");
278 (*wlr_layer_surface).output = (*output).wlr_output;
279 } else {
280 log::error!("no output available for layer surface {:?}", CStr::from_ptr((*wlr_layer_surface).namespace));
281 ffi::wlr_layer_surface_v1_destroy(wlr_layer_surface);
282 return;
283 }
284 }
285 }
286
287 if let Err(e) = LayerSurface::create(wlr_layer_surface, (*layer_shell).server) {
288 log::error!("Failed to create layer surface: {}", e);
289 ffi::wl_resource_post_no_memory((*wlr_layer_surface).resource);
290 }
291 }
292
293 pub struct LayerSurface {
294 pub ref_key: Key,
295 pub server: *mut Server,
296 pub wlr_layer_surface: *mut ffi::wlr_layer_surface_v1,
297 pub scene_layer_surface: *mut ffi::wlr_scene_layer_surface_v1,
298 pub popup_tree: *mut ffi::wlr_scene_tree,
299 /// Where the open/close dissolve currently stands, 0.0 (invisible) to
300 /// 1.0. Applied to the whole scene subtree, so the scenefx backdrop blur
301 /// behind the surface fades with it (`river_scene_node_set_opacity`) —
302 /// which is the thing a client fading its own pixels can never do.
303 pub opacity: f32,
304 /// Where `opacity` is easing to: 1.0 for an open fade, 0.0 for a close.
305 pub opacity_target: f32,
306 /// Linear per-tick step, from the configured duration at the moment the
307 /// fade starts. Linear rather than exponential because a close fade has
308 /// to actually reach zero before the client's exit deadline.
309 pub opacity_step: f32,
310 pub animation_timer: *mut ffi::wl_event_source,
311
312 pub destroy: ffi::wl_listener,
313 pub map: ffi::wl_listener,
314 pub unmap: ffi::wl_listener,
315 pub commit: ffi::wl_listener,
316 pub new_popup: ffi::wl_listener,
317 pub parent_offset_applied: bool,
318 }
319
320 impl LayerSurface {
321 pub unsafe fn create(
322 wlr_layer_surface: *mut ffi::wlr_layer_surface_v1,
323 server: *mut Server,
324 ) -> Result<*mut Self, &'static str> {
325 let layer_tree = (*server).scene.layer_surface_tree((*wlr_layer_surface).current.layer);
326 let scene_layer_surface = ffi::wlr_scene_layer_surface_v1_create(layer_tree, wlr_layer_surface);
327 if scene_layer_surface.is_null() {
328 return Err("Failed to create wlr_scene_layer_surface_v1");
329 }
330
331 let popup_tree = ffi::wlr_scene_tree_create((*server).scene.layers.popups);
332 if popup_tree.is_null() {
333 ffi::wlr_scene_node_destroy((*scene_layer_surface).tree as *mut ffi::wlr_scene_node);
334 return Err("Failed to create popup_tree");
335 }
336
337 let layer_surface = Box::into_raw(Box::new(LayerSurface {
338 ref_key: Key { generation: 0, index: 0 },
339 server,
340 wlr_layer_surface,
341 scene_layer_surface,
342 popup_tree,
343 opacity: 1.0,
344 opacity_target: 1.0,
345 opacity_step: 1.0,
346 animation_timer: std::ptr::null_mut(),
347 destroy: std::mem::zeroed(),
348 map: std::mem::zeroed(),
349 unmap: std::mem::zeroed(),
350 commit: std::mem::zeroed(),
351 new_popup: std::mem::zeroed(),
352 parent_offset_applied: false,
353 }));
354
355 let key = (*server).layer_shell.surfaces.put(layer_surface);
356 (*layer_surface).ref_key = key;
357
358 SceneNodeData::attach((*scene_layer_surface).tree as *mut _, SceneNodeDataVal::LayerSurface(layer_surface));
359 SceneNodeData::attach(popup_tree as *mut _, SceneNodeDataVal::LayerSurface(layer_surface));
360
361 ffi::river_wlr_surface_set_data((*wlr_layer_surface).surface, (*scene_layer_surface).tree as *mut _);
362
363 let destroy_ptr = &mut (*layer_surface).destroy as *mut ffi::wl_listener as *mut WlListener;
364 (*destroy_ptr).notify = Some(handle_layer_surface_destroy);
365 wl_signal_add(&mut (*wlr_layer_surface).events.destroy, &mut (*layer_surface).destroy);
366
367 let map_ptr = &mut (*layer_surface).map as *mut ffi::wl_listener as *mut WlListener;
368 (*map_ptr).notify = Some(handle_layer_surface_map);
369 wl_signal_add(ffi::river_wlr_surface_get_map_signal((*wlr_layer_surface).surface), &mut (*layer_surface).map);
370
371 let unmap_ptr = &mut (*layer_surface).unmap as *mut ffi::wl_listener as *mut WlListener;
372 (*unmap_ptr).notify = Some(handle_layer_surface_unmap);
373 wl_signal_add(ffi::river_wlr_surface_get_unmap_signal((*wlr_layer_surface).surface), &mut (*layer_surface).unmap);
374
375 let commit_ptr = &mut (*layer_surface).commit as *mut ffi::wl_listener as *mut WlListener;
376 (*commit_ptr).notify = Some(handle_layer_surface_commit);
377 wl_signal_add(ffi::river_wlr_surface_get_commit_signal((*wlr_layer_surface).surface), &mut (*layer_surface).commit);
378
379 let new_popup_ptr = &mut (*layer_surface).new_popup as *mut ffi::wl_listener as *mut WlListener;
380 (*new_popup_ptr).notify = Some(handle_layer_surface_new_popup);
381 wl_signal_add(&mut (*wlr_layer_surface).events.new_popup, &mut (*layer_surface).new_popup);
382
383 Ok(layer_surface)
384 }
385
386 pub unsafe fn destroy_popups(&mut self) {
387 let popups_list = &mut (*self.wlr_layer_surface).popups as *mut ffi::wl_list as *mut WlList;
388 let mut curr = (*popups_list).next;
389 while curr != popups_list {
390 let next = (*curr).next;
391 let wlr_xdg_popup = crate::container_of!(curr, ffi::wlr_xdg_popup, link);
392 ffi::wlr_xdg_popup_destroy(wlr_xdg_popup);
393 curr = next;
394 }
395 }
396 }
397
398 unsafe extern "C" fn handle_layer_surface_destroy(listener: *mut ffi::wl_listener, _data: *mut std::ffi::c_void) {
399 let layer_surface = crate::container_of!(listener, LayerSurface, destroy);
400
401 log::debug!("layer surface {:?} destroyed", CStr::from_ptr((*(*layer_surface).wlr_layer_surface).namespace));
402
403 if !(*layer_surface).animation_timer.is_null() {
404 ffi::wl_event_source_remove((*layer_surface).animation_timer);
405 (*layer_surface).animation_timer = std::ptr::null_mut();
406 }
407
408 wl_listener_remove(&mut (*layer_surface).destroy);
409 wl_listener_remove(&mut (*layer_surface).map);
410 wl_listener_remove(&mut (*layer_surface).unmap);
411 wl_listener_remove(&mut (*layer_surface).commit);
412 wl_listener_remove(&mut (*layer_surface).new_popup);
413
414 (*layer_surface).destroy_popups();
415
416 ffi::wlr_scene_node_destroy((*layer_surface).popup_tree as *mut ffi::wlr_scene_node);
417
418 ffi::river_wlr_surface_set_data((*(*layer_surface).wlr_layer_surface).surface, std::ptr::null_mut());
419
420 let server = (*layer_surface).server;
421 (*server).layer_shell.surfaces.remove((*layer_surface).ref_key);
422 let _ = Box::from_raw(layer_surface);
423 }
424
425 /// Steps one layer surface's dissolve toward `opacity_target` and re-arms
426 /// itself until it lands. Unlike the window fade — which rides the window
427 /// manager's shared border-fade timer — each layer surface keeps its own,
428 /// because a layer surface is not in `wm.windows` and there is no list to
429 /// sweep.
430 unsafe extern "C" fn handle_animation_tick(data: *mut std::ffi::c_void) -> std::os::raw::c_int {
431 let layer_surface = data as *mut LayerSurface;
432
433 let target = (*layer_surface).opacity_target;
434 let delta = target - (*layer_surface).opacity;
435 let settled = if delta.abs() <= (*layer_surface).opacity_step {
436 (*layer_surface).opacity = target;
437 true
438 } else {
439 (*layer_surface).opacity += (*layer_surface).opacity_step * delta.signum();
440 false
441 };
442
443 ffi::river_scene_node_set_opacity(
444 (*(*layer_surface).scene_layer_surface).tree as *mut ffi::wlr_scene_node,
445 (*layer_surface).opacity,
446 );
447
448 if settled {
449 if !(*layer_surface).animation_timer.is_null() {
450 ffi::wl_event_source_remove((*layer_surface).animation_timer);
451 (*layer_surface).animation_timer = std::ptr::null_mut();
452 }
453 } else {
454 if !(*layer_surface).animation_timer.is_null() {
455 ffi::wl_event_source_timer_update((*layer_surface).animation_timer, 16);
456 }
457 }
458
459 0
460 }
461
462 impl LayerSurface {
463 /// Begin a dissolve toward `target` (0.0 out, 1.0 in) over `ms`. A `ms`
464 /// of 0 snaps, so callers can treat this as "put the surface at
465 /// `target`" whether or not fading is configured on.
466 pub unsafe fn start_fade(&mut self, target: f32, ms: u32) {
467 self.opacity_target = target.clamp(0.0, 1.0);
468 if !self.animation_timer.is_null() {
469 ffi::wl_event_source_remove(self.animation_timer);
470 self.animation_timer = std::ptr::null_mut();
471 }
472 if ms == 0 {
473 self.opacity = self.opacity_target;
474 ffi::river_scene_node_set_opacity(
475 (*self.scene_layer_surface).tree as *mut ffi::wlr_scene_node,
476 self.opacity,
477 );
478 return;
479 }
480 // Ticks at 16 ms; at least one step so a sub-frame duration still
481 // lands rather than dividing by zero.
482 let ticks = ((ms as f32) / 16.0).max(1.0);
483 self.opacity_step = ((self.opacity_target - self.opacity).abs() / ticks).max(1.0e-4);
484 ffi::river_scene_node_set_opacity(
485 (*self.scene_layer_surface).tree as *mut ffi::wlr_scene_node,
486 self.opacity,
487 );
488
489 let event_loop = ffi::wl_display_get_event_loop((*self.server).wl_server);
490 let timer = ffi::wl_event_loop_add_timer(
491 event_loop,
492 Some(handle_animation_tick),
493 self as *mut LayerSurface as *mut _,
494 );
495 if timer.is_null() {
496 log::error!("Failed to create layer surface animation timer");
497 // No timer means no ramp; land on the target rather than leave
498 // the surface stranded at whatever it was mid-fade.
499 self.opacity = self.opacity_target;
500 ffi::river_scene_node_set_opacity(
501 (*self.scene_layer_surface).tree as *mut ffi::wlr_scene_node,
502 self.opacity,
503 );
504 } else {
505 self.animation_timer = timer;
506 ffi::wl_event_source_timer_update(timer, 16);
507 }
508 }
509
510 /// PID of the client owning this layer surface, from its wl_resource.
511 /// 0 when it cannot be read. Used to resolve a `fade-out` to the caller.
512 pub unsafe fn client_pid(&self) -> i32 {
513 let surface = (*self.wlr_layer_surface).surface;
514 if surface.is_null() {
515 return 0;
516 }
517 let res = ffi::river_wlr_surface_get_resource(surface);
518 if res.is_null() {
519 return 0;
520 }
521 let client = ffi::wl_resource_get_client(res);
522 if client.is_null() {
523 return 0;
524 }
525 let (mut pid, mut uid, mut gid) = (0, 0, 0);
526 ffi::wl_client_get_credentials(client, &mut pid, &mut uid, &mut gid);
527 pid
528 }
529 }
530
531 unsafe fn update_scheduled_focus_and_dirty_windowing<F>(server: *mut Server, f: F)
532 where F: FnOnce() {
533 let seats = &mut (*server).input_manager.seats as *mut ffi::wl_list as *mut WlList;
534 let mut curr = (*seats).next;
535 let mut old_focuses = Vec::new();
536 while curr != seats {
537 let seat = crate::container_of!(curr, Seat, link);
538 old_focuses.push((*seat).layer_shell.scheduled_focus);
539 curr = (*curr).next;
540 }
541
542 f();
543
544 let mut changed = false;
545 let mut curr = (*seats).next;
546 let mut idx = 0;
547 while curr != seats {
548 let seat = crate::container_of!(curr, Seat, link);
549 if (*seat).layer_shell.scheduled_focus != old_focuses[idx] {
550 changed = true;
551 }
552 idx += 1;
553 curr = (*curr).next;
554 }
555
556 if changed {
557 (*server).wm.dirty_windowing();
558 } else {
559 (*server).wm.dirty_rendering();
560 }
561 }
562
563
564 unsafe extern "C" fn handle_layer_surface_map(listener: *mut ffi::wl_listener, _data: *mut std::ffi::c_void) {
565 let layer_surface = crate::container_of!(listener, LayerSurface, map);
566 let wlr_layer_surface = (*layer_surface).wlr_layer_surface;
567
568 log::debug!("layer surface {:?} mapped", CStr::from_ptr((*wlr_layer_surface).namespace));
569
570 let server = (*layer_surface).server;
571
572 // Overlay layer only: these are the transient surfaces the user opens
573 // (the launcher, the notifier), so a dissolve reads as the thing
574 // arriving. The Background/Bottom/Top layers are the desktop's own
575 // furniture — wallpaper, status bar — and map once at login, where a
576 // fade reads as the desktop failing to draw.
577 if (*wlr_layer_surface).current.layer == ffi::zwlr_layer_shell_v1_layer_ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY {
578 let ms = (*server).wm.layout.fade_in_ms;
579 if ms > 0 {
580 (*layer_surface).opacity = 0.0;
581 }
582 (*layer_surface).start_fade(1.0, ms);
583 }
584
585 update_scheduled_focus_and_dirty_windowing(server, || {
586 if (*wlr_layer_surface).current.keyboard_interactive == ffi::zwlr_layer_surface_v1_keyboard_interactivity_ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND {
587 let seats = &mut (*server).input_manager.seats as *mut ffi::wl_list as *mut WlList;
588 let mut curr = (*seats).next;
589 while curr != seats {
590 let next = (*curr).next;
591 let seat = crate::container_of!(curr, Seat, link);
592 if !matches!((*seat).layer_shell.scheduled_focus, LayerShellSeatFocus::Exclusive(_)) {
593 (*seat).layer_shell.scheduled_focus = LayerShellSeatFocus::NonExclusive((*layer_surface).ref_key);
594 }
595 curr = next;
596 }
597 }
598
599 let wlr_output = (*wlr_layer_surface).output;
600 if !wlr_output.is_null() {
601 let output = ffi::river_wlr_output_get_data(wlr_output) as *mut Output;
602 if !output.is_null() {
603 (*output).layer_shell.arrange(output);
604 }
605 }
606 (*server).layer_shell.check_exclusive_focus();
607 });
608 }
609
610 unsafe extern "C" fn handle_layer_surface_unmap(listener: *mut ffi::wl_listener, _data: *mut std::ffi::c_void) {
611 let layer_surface = crate::container_of!(listener, LayerSurface, unmap);
612 let wlr_layer_surface = (*layer_surface).wlr_layer_surface;
613
614 log::debug!("layer surface {:?} unmapped", CStr::from_ptr((*wlr_layer_surface).namespace));
615
616 if !(*layer_surface).animation_timer.is_null() {
617 ffi::wl_event_source_remove((*layer_surface).animation_timer);
618 (*layer_surface).animation_timer = std::ptr::null_mut();
619 }
620
621 let server = (*layer_surface).server;
622
623 update_scheduled_focus_and_dirty_windowing(server, || {
624 let seats = &mut (*server).input_manager.seats as *mut ffi::wl_list as *mut WlList;
625 let mut curr = (*seats).next;
626 while curr != seats {
627 let next = (*curr).next;
628 let seat = crate::container_of!(curr, Seat, link);
629 if let crate::seat::Focus::LayerSurface(surface) = (*seat).focused {
630 if surface == (*wlr_layer_surface).surface {
631 (*seat).focus(crate::seat::Focus::None);
632 // cce-cloud surfaces skip the focus_next fallback: the bare
633 // launcher is about to be replaced by whatever it spawned,
634 // and refocusing the old window first would fight the new
635 // map. But a PARENTED popup ("cce-cloud:<app-id>", e.g. the
636 // designer's add-node palette) is chrome OF that app —
637 // closing it must hand the keyboard straight back to its
638 // parent, not leave the seat focused on nothing.
639 let mut is_cce_cloud = false;
640 let mut cloud_parent: Option<String> = None;
641 if !(*wlr_layer_surface).namespace.is_null() {
642 let ns = std::ffi::CStr::from_ptr((*wlr_layer_surface).namespace).to_string_lossy();
643 if ns.starts_with("cce-cloud") {
644 is_cce_cloud = true;
645 cloud_parent = ns.strip_prefix("cce-cloud:").map(str::to_string);
646 }
647 }
648 if let Some(parent_app_id) = cloud_parent {
649 // Status modules parent their submenus too; the bar is
650 // never a keyboard-focus target, so those keep the old
651 // leave-it-unfocused behavior.
652 if !parent_app_id.starts_with("cce-status") {
653 for &win_ptr in (*server).wm.windows.iter() {
654 if win_ptr.is_null()
655 || (*win_ptr).closed
656 || (*win_ptr).minimized
657 || !matches!((*win_ptr).state, crate::window::WindowState::Mapped)
658 {
659 continue;
660 }
661 if (*win_ptr).get_app_id_string().as_deref() == Some(parent_app_id.as_str()) {
662 // Dismissing chrome, not switching windows:
663 // the camera stays where the user left it.
664 (*seat).suppress_focus_pan = true;
665 (*seat).focus(crate::seat::Focus::Window(win_ptr));
666 (*seat).suppress_focus_pan = false;
667 break;
668 }
669 }
670 }
671 } else if !is_cce_cloud {
672 (*server).wm.focus_next_visible_window(seat);
673 }
674 }
675 }
676 if let LayerShellSeatFocus::NonExclusive(key) = (*seat).layer_shell.scheduled_focus {
677 if key == (*layer_surface).ref_key {
678 (*seat).layer_shell.scheduled_focus = LayerShellSeatFocus::None;
679 }
680 }
681 curr = next;
682 }
683
684 let wlr_output = (*wlr_layer_surface).output;
685 if !wlr_output.is_null() {
686 let output = ffi::river_wlr_output_get_data(wlr_output) as *mut Output;
687 if !output.is_null() {
688 (*output).layer_shell.arrange(output);
689 }
690 }
691 (*server).layer_shell.check_exclusive_focus();
692 });
693 }
694
695 unsafe extern "C" fn handle_layer_surface_commit(listener: *mut ffi::wl_listener, _data: *mut std::ffi::c_void) {
696 let layer_surface = crate::container_of!(listener, LayerSurface, commit);
697 let wlr_layer_surface = (*layer_surface).wlr_layer_surface;
698
699 if (*wlr_layer_surface).current.layer != ffi::zwlr_layer_shell_v1_layer_ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND {
700 let server = (*layer_surface).server;
701 let mut blur_enabled = (*server).wm.layout.window_blur;
702 let mut ignore_transparent = (*server).wm.layout.window_backdrop_blur_ignore_transparent;
703 let mut is_status = false;
704 if !(*wlr_layer_surface).namespace.is_null() {
705 let ns = std::ffi::CStr::from_ptr((*wlr_layer_surface).namespace).to_string_lossy();
706 if ns == "cce-status" || ns == "cce-status-interface" {
707 blur_enabled = (*server).wm.layout.status_background_blur > 0.001;
708 ignore_transparent = (*server).wm.layout.status_backdrop_blur_ignore_transparent;
709 is_status = true;
710 }
711 }
712 // Optimized (cached) blur is counterproductive for surfaces stacked ABOVE
713 // windows (Top/Overlay): the scene graph re-dirties an optimized-blur node
714 // whenever any node below it updates (scenefx wlr_scene.c:744), so window
715 // content panning underneath forces a full re-bake every frame — a fixed-
716 // position shimmer (e.g. the always-mapped cce-notifier overlay). Regular
717 // blur is immune to that path and only re-bakes on real damage, so fall back
718 // to it here, exactly as status surfaces already do. Bottom/Background layers
719 // sit below windows and are unaffected, so they keep the cache.
720 let layer = (*wlr_layer_surface).current.layer;
721 let above_windows = layer == ffi::zwlr_layer_shell_v1_layer_ZWLR_LAYER_SHELL_V1_LAYER_TOP
722 || layer == ffi::zwlr_layer_shell_v1_layer_ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY;
723 let use_optimized = if is_status || above_windows { false } else { (*server).wm.layout.scenefx_optimized_blur };
724 let wlr_surface = (*wlr_layer_surface).surface;
725 let geom_w = if !wlr_surface.is_null() {
726 ffi::river_wlr_surface_get_width(wlr_surface)
727 } else {
728 (*wlr_layer_surface).current.actual_width as i32
729 };
730 let geom_h = if !wlr_surface.is_null() {
731 ffi::river_wlr_surface_get_height(wlr_surface)
732 } else {
733 (*wlr_layer_surface).current.actual_height as i32
734 };
735 ffi::river_scene_node_enable_blur(
736 (*(*layer_surface).scene_layer_surface).tree as *mut ffi::wlr_scene_node,
737 blur_enabled,
738 use_optimized,
739 ignore_transparent,
740 0,
741 0,
742 geom_w,
743 geom_h,
744 // 0 preserves existing behaviour: layer surfaces (status bar, etc.) never had a
745 // blur radius applied, and their corner rounding is handled separately. Left
746 // deliberately unchanged so this fix stays scoped to toplevels.
747 0,
748 );
749 }
750
751 if (*layer_surface).opacity < 1.0 {
752 ffi::river_scene_node_set_opacity(
753 (*(*layer_surface).scene_layer_surface).tree as *mut ffi::wlr_scene_node,
754 (*layer_surface).opacity,
755 );
756 }
757
758 let wlr_output = (*wlr_layer_surface).output;
759 if wlr_output.is_null() {
760 return;
761 }
762 let output = ffi::river_wlr_output_get_data(wlr_output) as *mut Output;
763 if output.is_null() {
764 return;
765 }
766
767 let server = (*layer_surface).server;
768
769 // Position offset for cce-cloud sub-modules
770 if !(*layer_surface).parent_offset_applied {
771 if !(*wlr_layer_surface).namespace.is_null() {
772 let ns = std::ffi::CStr::from_ptr((*wlr_layer_surface).namespace).to_string_lossy();
773 if ns.starts_with("cce-cloud:") {
774 let parent_app_id = &ns["cce-cloud:".len()..];
775 let mut parent_x = None;
776 let mut parent_y = None;
777 let mut parent_w = 0;
778
779 for &win_ptr in (*server).wm.windows.iter() {
780 if win_ptr.is_null() || (*win_ptr).closed {
781 continue;
782 }
783 if let Some(win_app_id) = (*win_ptr).get_app_id_string() {
784 if win_app_id == parent_app_id {
785 parent_x = Some((*win_ptr).rendering_requested.x);
786 parent_y = Some((*win_ptr).rendering_requested.y);
787 parent_w = (*win_ptr).box_geom.width;
788 break;
789 }
790 }
791 }
792
793 if let (Some(px), Some(py)) = (parent_x, parent_y) {
794 let wlr_output = (*wlr_layer_surface).output;
795 if !wlr_output.is_null() {
796 let mut output_x = 0;
797 let mut output_y = 0;
798 let mut output_w = 0;
799 let outputs_list = &mut (*server).om.outputs as *mut ffi::wl_list as *mut WlList;
800 let mut curr_out = (*outputs_list).next;
801 while curr_out != outputs_list {
802 let output = crate::container_of!(curr_out, crate::output::Output, link);
803 if (*output).wlr_output == wlr_output {
804 let wlr_box = (*output).sent.box_layout();
805 output_x = wlr_box.x;
806 output_y = wlr_box.y;
807 output_w = wlr_box.width;
808 break;
809 }
810 curr_out = (*curr_out).next;
811 }
812
813 let relative_parent_x = px - output_x;
814 let relative_parent_y = py - output_y;
815
816 let anchor = (*wlr_layer_surface).current.anchor;
817 let is_align_right = (anchor & ffi::zwlr_layer_surface_v1_anchor_ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT) != 0;
818
819 if is_align_right {
820 (*wlr_layer_surface).pending.margin.right = (output_w - relative_parent_x - parent_w) + (*wlr_layer_surface).pending.margin.right;
821 (*wlr_layer_surface).current.margin.right = (*wlr_layer_surface).pending.margin.right;
822 } else {
823 (*wlr_layer_surface).pending.margin.left = relative_parent_x + (*wlr_layer_surface).pending.margin.left;
824 (*wlr_layer_surface).current.margin.left = (*wlr_layer_surface).pending.margin.left;
825 }
826 (*wlr_layer_surface).pending.margin.top = relative_parent_y + (*wlr_layer_surface).pending.margin.top;
827 (*wlr_layer_surface).current.margin.top = (*wlr_layer_surface).pending.margin.top;
828
829 (*layer_surface).parent_offset_applied = true;
830 }
831 }
832 }
833 }
834 }
835
836 // Check if layer was changed
837 if (*wlr_layer_surface).current.committed & ffi::wlr_layer_surface_v1_state_field_WLR_LAYER_SURFACE_V1_STATE_LAYER != 0 {
838 let tree = (*server).scene.layer_surface_tree((*wlr_layer_surface).current.layer);
839 ffi::wlr_scene_node_reparent(
840 (*(*layer_surface).scene_layer_surface).tree as *mut ffi::wlr_scene_node,
841 tree,
842 );
843 }
844
845 if (*wlr_layer_surface).initial_commit || ((*wlr_layer_surface).current.committed != 0) {
846 update_scheduled_focus_and_dirty_windowing(server, || {
847 (*output).layer_shell.arrange(output);
848 (*server).layer_shell.check_exclusive_focus();
849 });
850 }
851 }
852
853 unsafe extern "C" fn handle_layer_surface_new_popup(listener: *mut ffi::wl_listener, data: *mut std::ffi::c_void) {
854 let layer_surface = crate::container_of!(listener, LayerSurface, new_popup);
855 let wlr_xdg_popup = data as *mut ffi::wlr_xdg_popup;
856
857 if let Err(e) = XdgPopup::create(wlr_xdg_popup, (*layer_surface).popup_tree, std::ptr::null_mut()) {
858 log::error!("Failed to create layer surface popup: {}", e);
859 ffi::wl_resource_post_no_memory((*wlr_xdg_popup).resource);
860 }
861 }
862
863 #[derive(Clone, Copy)]
864 pub struct LayerShellOutputScheduled {
865 pub non_exclusive_area: ffi::wlr_box,
866 }
867
868 #[derive(Clone, Copy)]
869 pub struct LayerShellOutputSent {
870 pub non_exclusive_area: Option<ffi::wlr_box>,
871 }
872
873 #[derive(Clone, Copy)]
874 pub struct LayerShellOutputRequested {
875 pub default: bool,
876 }
877
878 pub struct LayerShellOutput {
879 pub object: *mut ffi::wl_resource, // river_layer_shell_output_v1
880 pub scheduled: LayerShellOutputScheduled,
881 pub sent: LayerShellOutputSent,
882 pub requested: LayerShellOutputRequested,
883 }
884
885 impl Default for LayerShellOutput {
886 fn default() -> Self {
887 Self {
888 object: std::ptr::null_mut(),
889 scheduled: LayerShellOutputScheduled {
890 non_exclusive_area: ffi::wlr_box { x: 0, y: 0, width: 0, height: 0 },
891 },
892 sent: LayerShellOutputSent {
893 non_exclusive_area: None,
894 },
895 requested: LayerShellOutputRequested {
896 default: false,
897 },
898 }
899 }
900 }
901
902 impl LayerShellOutput {
903 pub unsafe fn create_object(&mut self, client: *mut ffi::wl_client, version: u32, id: u32, output: *mut Output) {
904 assert!(self.object.is_null());
905 let resource = ffi::wl_resource_create(client, &ffi::river_layer_shell_output_v1_interface, version as i32, id);
906 if resource.is_null() {
907 ffi::wl_client_post_no_memory(client);
908 log::error!("out of memory creating river_layer_shell_output_v1");
909 return;
910 }
911
912 ffi::wl_resource_set_implementation(
913 resource,
914 &LAYER_SHELL_OUTPUT_INTERFACE as *const _ as *const _,
915 self as *mut LayerShellOutput as *mut _,
916 Some(handle_layer_shell_output_destroy),
917 );
918 self.object = resource;
919 (*(*output).server).wm.dirty_windowing();
920 }
921
922 pub unsafe fn make_inert(&mut self) {
923 if !self.object.is_null() {
924 ffi::wl_resource_set_implementation(
925 self.object,
926 &INERT_LAYER_SHELL_OUTPUT_INTERFACE as *const _ as *const _,
927 std::ptr::null_mut(),
928 None,
929 );
930 self.object = std::ptr::null_mut();
931 }
932 }
933
934 pub unsafe fn arrange(&mut self, output: *mut Output) {
935 let (w, h) = (*output).scheduled.dimensions();
936 let box_geom = ffi::wlr_box {
937 x: (*output).scheduled.x,
938 y: (*output).scheduled.y,
939 width: w,
940 height: h,
941 };
942 self.scheduled.non_exclusive_area = box_geom;
943 self.send_configures(output, true);
944 self.send_configures(output, false);
945
946 let area_changed = match self.sent.non_exclusive_area {
947 Some(sent_box) => {
948 sent_box.x != self.scheduled.non_exclusive_area.x ||
949 sent_box.y != self.scheduled.non_exclusive_area.y ||
950 sent_box.width != self.scheduled.non_exclusive_area.width ||
951 sent_box.height != self.scheduled.non_exclusive_area.height
952 }
953 None => true,
954 };
955
956 if area_changed {
957 (*(*output).server).wm.dirty_windowing();
958 }
959 }
960
961 unsafe fn send_configures(&mut self, output: *mut Output, exclusive: bool) {
962 let (output_width, output_height) = (*output).scheduled.dimensions();
963 let output_box = ffi::wlr_box {
964 x: (*output).scheduled.x,
965 y: (*output).scheduled.y,
966 width: output_width,
967 height: output_height,
968 };
969
970 let layers = [
971 ffi::zwlr_layer_shell_v1_layer_ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND,
972 ffi::zwlr_layer_shell_v1_layer_ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM,
973 ffi::zwlr_layer_shell_v1_layer_ZWLR_LAYER_SHELL_V1_LAYER_TOP,
974 ffi::zwlr_layer_shell_v1_layer_ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY,
975 ];
976
977 for &layer in &layers {
978 let tree = (*(*output).server).scene.layer_surface_tree(layer);
979 let children_head = ffi::river_scene_tree_get_children(tree) as *mut WlList;
980 let mut curr = (*children_head).next;
981 while curr != children_head {
982 let next = (*curr).next;
983 let node = ffi::river_scene_node_from_children_link(curr as *mut ffi::wl_list);
984 if let Some(node_data) = SceneNodeData::from_node(node) {
985 if let SceneNodeDataVal::LayerSurface(layer_surface) = node_data.data {
986 let wlr_layer_surface = (*layer_surface).wlr_layer_surface;
987 if !ffi::river_wlr_surface_is_mapped((*wlr_layer_surface).surface) && !(*wlr_layer_surface).initial_commit {
988 curr = next;
989 continue;
990 }
991 if (*wlr_layer_surface).output != (*output).wlr_output {
992 curr = next;
993 continue;
994 }
995 let current_exclusive = (*wlr_layer_surface).current.exclusive_zone > 0;
996 if current_exclusive != exclusive {
997 curr = next;
998 continue;
999 }
1000
1001 let mut new_area = self.scheduled.non_exclusive_area;
1002 ffi::wlr_scene_layer_surface_v1_configure(
1003 (*layer_surface).scene_layer_surface,
1004 &output_box,
1005 &mut new_area,
1006 );
1007
1008 if new_area.width < (output_width / 2) || new_area.height < (output_height / 2) {
1009 ffi::wlr_layer_surface_v1_destroy(wlr_layer_surface);
1010 curr = next;
1011 continue;
1012 }
1013 self.scheduled.non_exclusive_area = new_area;
1014
1015 let x = ffi::river_scene_node_get_x((*(*layer_surface).scene_layer_surface).tree as *mut ffi::wlr_scene_node);
1016 let y = ffi::river_scene_node_get_y((*(*layer_surface).scene_layer_surface).tree as *mut ffi::wlr_scene_node);
1017 ffi::wlr_scene_node_set_position((*layer_surface).popup_tree as *mut ffi::wlr_scene_node, x, y);
1018
1019 let clip = ffi::wlr_box {
1020 x: -(x - (*output).scheduled.x),
1021 y: -(y - (*output).scheduled.y),
1022 width: output_width,
1023 height: output_height,
1024 };
1025 ffi::wlr_scene_subsurface_tree_set_clip(
1026 (*(*layer_surface).scene_layer_surface).tree as *mut ffi::wlr_scene_node,
1027 &clip,
1028 );
1029 }
1030 }
1031 curr = next;
1032 }
1033 }
1034 }
1035
1036 pub unsafe fn manage_start(&mut self, output: *mut Output) {
1037 let state = (*output).scheduled.state;
1038 assert!(
1039 matches!(state, crate::output::OutputStateValue::Enabled)
1040 || matches!(state, crate::output::OutputStateValue::DisabledSoft)
1041 );
1042
1043 let (w, h) = (*output).scheduled.dimensions();
1044 let scheduled_box = ffi::wlr_box {
1045 x: (*output).scheduled.x,
1046 y: (*output).scheduled.y,
1047 width: w,
1048 height: h,
1049 };
1050
1051 let (w_sent, h_sent) = (*output).sent.dimensions();
1052 let sent_box = ffi::wlr_box {
1053 x: (*output).sent.x,
1054 y: (*output).sent.y,
1055 width: w_sent,
1056 height: h_sent,
1057 };
1058
1059 let box_changed = scheduled_box.x != sent_box.x ||
1060 scheduled_box.y != sent_box.y ||
1061 scheduled_box.width != sent_box.width ||
1062 scheduled_box.height != sent_box.height;
1063
1064 if box_changed {
1065 self.scheduled.non_exclusive_area = scheduled_box;
1066 self.send_configures(output, true);
1067 self.send_configures(output, false);
1068 }
1069
1070 let area_changed = match self.sent.non_exclusive_area {
1071 Some(sent_box) => {
1072 sent_box.x != self.scheduled.non_exclusive_area.x ||
1073 sent_box.y != self.scheduled.non_exclusive_area.y ||
1074 sent_box.width != self.scheduled.non_exclusive_area.width ||
1075 sent_box.height != self.scheduled.non_exclusive_area.height
1076 }
1077 None => true,
1078 };
1079
1080 if area_changed {
1081 if !self.object.is_null() {
1082 ffi::wl_resource_post_event(
1083 self.object,
1084 ffi::RIVER_LAYER_SHELL_OUTPUT_V1_NON_EXCLUSIVE_AREA,
1085 self.scheduled.non_exclusive_area.x,
1086 self.scheduled.non_exclusive_area.y,
1087 self.scheduled.non_exclusive_area.width,
1088 self.scheduled.non_exclusive_area.height,
1089 );
1090 }
1091 self.sent.non_exclusive_area = Some(self.scheduled.non_exclusive_area);
1092 }
1093 }
1094 }
1095
1096 unsafe extern "C" fn handle_layer_shell_output_destroy(resource: *mut ffi::wl_resource) {
1097 let layer_shell_output = ffi::wl_resource_get_user_data(resource) as *mut LayerShellOutput;
1098 if !layer_shell_output.is_null() {
1099 (*layer_shell_output).object = std::ptr::null_mut();
1100 (*layer_shell_output).sent.non_exclusive_area = None;
1101 (*layer_shell_output).requested.default = false;
1102 }
1103 }
1104
1105 unsafe extern "C" fn layer_shell_output_destroy(client: *mut ffi::wl_client, resource: *mut ffi::wl_resource) {
1106 let _ = client;
1107 ffi::wl_resource_destroy(resource);
1108 }
1109
1110 unsafe extern "C" fn layer_shell_output_set_default(client: *mut ffi::wl_client, resource: *mut ffi::wl_resource) {
1111 let _ = client;
1112 let layer_shell_output = ffi::wl_resource_get_user_data(resource) as *mut LayerShellOutput;
1113 if layer_shell_output.is_null() {
1114 return;
1115 }
1116 let server = if !(*layer_shell_output).object.is_null() {
1117 // Find server. We can get it via finding Output from the parent link.
1118 // Let's traverse the outputs to set requested.default to false on all outputs
1119 let output = container_of_output(layer_shell_output);
1120 (*output).server
1121 } else {
1122 std::ptr::null_mut()
1123 };
1124
1125 if !server.is_null() {
1126 let outputs = &mut (*server).om.outputs as *mut ffi::wl_list as *mut WlList;
1127 let mut curr = (*outputs).next;
1128 while curr != outputs {
1129 let next = (*curr).next;
1130 let output = crate::container_of!(curr, Output, link);
1131 (*output).layer_shell.requested.default = false;
1132 curr = next;
1133 }
1134 (*layer_shell_output).requested.default = true;
1135 }
1136 }
1137
1138 static LAYER_SHELL_OUTPUT_INTERFACE: ffi::river_layer_shell_output_v1_interface = ffi::river_layer_shell_output_v1_interface {
1139 destroy: Some(layer_shell_output_destroy),
1140 set_default: Some(layer_shell_output_set_default),
1141 };
1142
1143 unsafe extern "C" fn layer_shell_output_inert_set_default(
1144 _client: *mut ffi::wl_client,
1145 _resource: *mut ffi::wl_resource,
1146 ) {}
1147
1148 static INERT_LAYER_SHELL_OUTPUT_INTERFACE: ffi::river_layer_shell_output_v1_interface = ffi::river_layer_shell_output_v1_interface {
1149 destroy: Some(layer_shell_output_destroy),
1150 set_default: Some(layer_shell_output_inert_set_default),
1151 };
1152
1153 unsafe fn container_of_output(layer_shell_output: *mut LayerShellOutput) -> *mut Output {
1154 crate::container_of!(layer_shell_output, Output, layer_shell)
1155 }
1156
1157 pub struct LayerShellSeat {
1158 pub object: *mut ffi::wl_resource, // river_layer_shell_seat_v1
1159 pub scheduled_focus: LayerShellSeatFocus,
1160 pub sent_focus: LayerShellSeatFocus,
1161 }
1162
1163 impl Default for LayerShellSeat {
1164 fn default() -> Self {
1165 Self {
1166 object: std::ptr::null_mut(),
1167 scheduled_focus: LayerShellSeatFocus::None,
1168 sent_focus: LayerShellSeatFocus::None,
1169 }
1170 }
1171 }
1172
1173 impl LayerShellSeat {
1174 pub unsafe fn create_object(&mut self, client: *mut ffi::wl_client, version: u32, id: u32, seat: *mut Seat) {
1175 assert!(self.object.is_null());
1176 let resource = ffi::wl_resource_create(client, &ffi::river_layer_shell_seat_v1_interface, version as i32, id);
1177 if resource.is_null() {
1178 ffi::wl_client_post_no_memory(client);
1179 log::error!("out of memory creating river_layer_shell_seat_v1");
1180 return;
1181 }
1182
1183 ffi::wl_resource_set_implementation(
1184 resource,
1185 &LAYER_SHELL_SEAT_INTERFACE as *const _ as *const _,
1186 self as *mut LayerShellSeat as *mut _,
1187 Some(handle_layer_shell_seat_destroy),
1188 );
1189 self.object = resource;
1190 (*(*seat).server).wm.dirty_windowing();
1191 }
1192
1193 pub unsafe fn make_inert(&mut self) {
1194 if !self.object.is_null() {
1195 ffi::wl_resource_set_implementation(
1196 self.object,
1197 &INERT_LAYER_SHELL_SEAT_INTERFACE as *const _ as *const _,
1198 std::ptr::null_mut(),
1199 None,
1200 );
1201 self.object = std::ptr::null_mut();
1202 }
1203 }
1204
1205 pub unsafe fn manage_start(&mut self) {
1206 if self.scheduled_focus != self.sent_focus {
1207 if !self.object.is_null() {
1208 match self.scheduled_focus {
1209 LayerShellSeatFocus::Exclusive(_) => {
1210 ffi::wl_resource_post_event(self.object, ffi::RIVER_LAYER_SHELL_SEAT_V1_FOCUS_EXCLUSIVE);
1211 }
1212 LayerShellSeatFocus::NonExclusive(_) => {
1213 ffi::wl_resource_post_event(self.object, ffi::RIVER_LAYER_SHELL_SEAT_V1_FOCUS_NON_EXCLUSIVE);
1214 }
1215 LayerShellSeatFocus::None => {
1216 ffi::wl_resource_post_event(self.object, ffi::RIVER_LAYER_SHELL_SEAT_V1_FOCUS_NONE);
1217 }
1218 }
1219 }
1220 self.sent_focus = self.scheduled_focus;
1221 }
1222 }
1223 }
1224
1225 unsafe extern "C" fn handle_layer_shell_seat_destroy(resource: *mut ffi::wl_resource) {
1226 let layer_shell_seat = ffi::wl_resource_get_user_data(resource) as *mut LayerShellSeat;
1227 if !layer_shell_seat.is_null() {
1228 (*layer_shell_seat).object = std::ptr::null_mut();
1229 }
1230 }
1231
1232 unsafe extern "C" fn layer_shell_seat_destroy(client: *mut ffi::wl_client, resource: *mut ffi::wl_resource) {
1233 let _ = client;
1234 ffi::wl_resource_destroy(resource);
1235 }
1236
1237 static LAYER_SHELL_SEAT_INTERFACE: ffi::river_layer_shell_seat_v1_interface = ffi::river_layer_shell_seat_v1_interface {
1238 destroy: Some(layer_shell_seat_destroy),
1239 };
1240
1241 static INERT_LAYER_SHELL_SEAT_INTERFACE: ffi::river_layer_shell_seat_v1_interface = ffi::river_layer_shell_seat_v1_interface {
1242 destroy: Some(layer_shell_seat_destroy),
1243 };