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