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

src/server/layer_shell.rs (51K)

   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 = if cce_core::motion::enabled() { (*server).wm.layout.fade_in_ms } else { 0 };
 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(
 858         wlr_xdg_popup,
 859         (*layer_surface).popup_tree,
 860         std::ptr::null_mut(),
 861         (*layer_surface).popup_tree,
 862     ) {
 863         log::error!("Failed to create layer surface popup: {}", e);
 864         ffi::wl_resource_post_no_memory((*wlr_xdg_popup).resource);
 865     }
 866 }
 867 
 868 #[derive(Clone, Copy)]
 869 pub struct LayerShellOutputScheduled {
 870     pub non_exclusive_area: ffi::wlr_box,
 871 }
 872 
 873 #[derive(Clone, Copy)]
 874 pub struct LayerShellOutputSent {
 875     pub non_exclusive_area: Option<ffi::wlr_box>,
 876 }
 877 
 878 #[derive(Clone, Copy)]
 879 pub struct LayerShellOutputRequested {
 880     pub default: bool,
 881 }
 882 
 883 pub struct LayerShellOutput {
 884     pub object: *mut ffi::wl_resource, // river_layer_shell_output_v1
 885     pub scheduled: LayerShellOutputScheduled,
 886     pub sent: LayerShellOutputSent,
 887     pub requested: LayerShellOutputRequested,
 888 }
 889 
 890 impl Default for LayerShellOutput {
 891     fn default() -> Self {
 892         Self {
 893             object: std::ptr::null_mut(),
 894             scheduled: LayerShellOutputScheduled {
 895                 non_exclusive_area: ffi::wlr_box { x: 0, y: 0, width: 0, height: 0 },
 896             },
 897             sent: LayerShellOutputSent {
 898                 non_exclusive_area: None,
 899             },
 900             requested: LayerShellOutputRequested {
 901                 default: false,
 902             },
 903         }
 904     }
 905 }
 906 
 907 impl LayerShellOutput {
 908     pub unsafe fn create_object(&mut self, client: *mut ffi::wl_client, version: u32, id: u32, output: *mut Output) {
 909         assert!(self.object.is_null());
 910         let resource = ffi::wl_resource_create(client, &ffi::river_layer_shell_output_v1_interface, version as i32, id);
 911         if resource.is_null() {
 912             ffi::wl_client_post_no_memory(client);
 913             log::error!("out of memory creating river_layer_shell_output_v1");
 914             return;
 915         }
 916 
 917         ffi::wl_resource_set_implementation(
 918             resource,
 919             &LAYER_SHELL_OUTPUT_INTERFACE as *const _ as *const _,
 920             self as *mut LayerShellOutput as *mut _,
 921             Some(handle_layer_shell_output_destroy),
 922         );
 923         self.object = resource;
 924         (*(*output).server).wm.dirty_windowing();
 925     }
 926 
 927     pub unsafe fn make_inert(&mut self) {
 928         if !self.object.is_null() {
 929             ffi::wl_resource_set_implementation(
 930                 self.object,
 931                 &INERT_LAYER_SHELL_OUTPUT_INTERFACE as *const _ as *const _,
 932                 std::ptr::null_mut(),
 933                 None,
 934             );
 935             self.object = std::ptr::null_mut();
 936         }
 937     }
 938 
 939     pub unsafe fn arrange(&mut self, output: *mut Output) {
 940         let (w, h) = (*output).scheduled.dimensions();
 941         let box_geom = ffi::wlr_box {
 942             x: (*output).scheduled.x,
 943             y: (*output).scheduled.y,
 944             width: w,
 945             height: h,
 946         };
 947         self.scheduled.non_exclusive_area = box_geom;
 948         self.send_configures(output, true);
 949         self.send_configures(output, false);
 950 
 951         let area_changed = match self.sent.non_exclusive_area {
 952             Some(sent_box) => {
 953                 sent_box.x != self.scheduled.non_exclusive_area.x ||
 954                 sent_box.y != self.scheduled.non_exclusive_area.y ||
 955                 sent_box.width != self.scheduled.non_exclusive_area.width ||
 956                 sent_box.height != self.scheduled.non_exclusive_area.height
 957             }
 958             None => true,
 959         };
 960 
 961         if area_changed {
 962             (*(*output).server).wm.dirty_windowing();
 963         }
 964     }
 965 
 966     unsafe fn send_configures(&mut self, output: *mut Output, exclusive: bool) {
 967         let (output_width, output_height) = (*output).scheduled.dimensions();
 968         let output_box = ffi::wlr_box {
 969             x: (*output).scheduled.x,
 970             y: (*output).scheduled.y,
 971             width: output_width,
 972             height: output_height,
 973         };
 974 
 975         let layers = [
 976             ffi::zwlr_layer_shell_v1_layer_ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND,
 977             ffi::zwlr_layer_shell_v1_layer_ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM,
 978             ffi::zwlr_layer_shell_v1_layer_ZWLR_LAYER_SHELL_V1_LAYER_TOP,
 979             ffi::zwlr_layer_shell_v1_layer_ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY,
 980         ];
 981 
 982         for &layer in &layers {
 983             let tree = (*(*output).server).scene.layer_surface_tree(layer);
 984             let children_head = ffi::river_scene_tree_get_children(tree) as *mut WlList;
 985             let mut curr = (*children_head).next;
 986             while curr != children_head {
 987                 let next = (*curr).next;
 988                 let node = ffi::river_scene_node_from_children_link(curr as *mut ffi::wl_list);
 989                 if let Some(node_data) = SceneNodeData::from_node(node) {
 990                     if let SceneNodeDataVal::LayerSurface(layer_surface) = node_data.data {
 991                         let wlr_layer_surface = (*layer_surface).wlr_layer_surface;
 992                         if !ffi::river_wlr_surface_is_mapped((*wlr_layer_surface).surface) && !(*wlr_layer_surface).initial_commit {
 993                             curr = next;
 994                             continue;
 995                         }
 996                         if (*wlr_layer_surface).output != (*output).wlr_output {
 997                             curr = next;
 998                             continue;
 999                         }
1000                         let current_exclusive = (*wlr_layer_surface).current.exclusive_zone > 0;
1001                         if current_exclusive != exclusive {
1002                             curr = next;
1003                             continue;
1004                         }
1005 
1006                         let mut new_area = self.scheduled.non_exclusive_area;
1007                         ffi::wlr_scene_layer_surface_v1_configure(
1008                             (*layer_surface).scene_layer_surface,
1009                             &output_box,
1010                             &mut new_area,
1011                         );
1012 
1013                         if new_area.width < (output_width / 2) || new_area.height < (output_height / 2) {
1014                             ffi::wlr_layer_surface_v1_destroy(wlr_layer_surface);
1015                             curr = next;
1016                             continue;
1017                         }
1018                         self.scheduled.non_exclusive_area = new_area;
1019 
1020                         let x = ffi::river_scene_node_get_x((*(*layer_surface).scene_layer_surface).tree as *mut ffi::wlr_scene_node);
1021                         let y = ffi::river_scene_node_get_y((*(*layer_surface).scene_layer_surface).tree as *mut ffi::wlr_scene_node);
1022                         ffi::wlr_scene_node_set_position((*layer_surface).popup_tree as *mut ffi::wlr_scene_node, x, y);
1023 
1024                         let clip = ffi::wlr_box {
1025                             x: -(x - (*output).scheduled.x),
1026                             y: -(y - (*output).scheduled.y),
1027                             width: output_width,
1028                             height: output_height,
1029                         };
1030                         ffi::wlr_scene_subsurface_tree_set_clip(
1031                             (*(*layer_surface).scene_layer_surface).tree as *mut ffi::wlr_scene_node,
1032                             &clip,
1033                         );
1034                     }
1035                 }
1036                 curr = next;
1037             }
1038         }
1039     }
1040 
1041     pub unsafe fn manage_start(&mut self, output: *mut Output) {
1042         let state = (*output).scheduled.state;
1043         assert!(
1044             matches!(state, crate::output::OutputStateValue::Enabled)
1045                 || matches!(state, crate::output::OutputStateValue::DisabledSoft)
1046         );
1047 
1048         let (w, h) = (*output).scheduled.dimensions();
1049         let scheduled_box = ffi::wlr_box {
1050             x: (*output).scheduled.x,
1051             y: (*output).scheduled.y,
1052             width: w,
1053             height: h,
1054         };
1055 
1056         let (w_sent, h_sent) = (*output).sent.dimensions();
1057         let sent_box = ffi::wlr_box {
1058             x: (*output).sent.x,
1059             y: (*output).sent.y,
1060             width: w_sent,
1061             height: h_sent,
1062         };
1063 
1064         let box_changed = scheduled_box.x != sent_box.x ||
1065                           scheduled_box.y != sent_box.y ||
1066                           scheduled_box.width != sent_box.width ||
1067                           scheduled_box.height != sent_box.height;
1068 
1069         if box_changed {
1070             self.scheduled.non_exclusive_area = scheduled_box;
1071             self.send_configures(output, true);
1072             self.send_configures(output, false);
1073         }
1074 
1075         let area_changed = match self.sent.non_exclusive_area {
1076             Some(sent_box) => {
1077                 sent_box.x != self.scheduled.non_exclusive_area.x ||
1078                 sent_box.y != self.scheduled.non_exclusive_area.y ||
1079                 sent_box.width != self.scheduled.non_exclusive_area.width ||
1080                 sent_box.height != self.scheduled.non_exclusive_area.height
1081             }
1082             None => true,
1083         };
1084 
1085         if area_changed {
1086             if !self.object.is_null() {
1087                 ffi::wl_resource_post_event(
1088                     self.object,
1089                     ffi::RIVER_LAYER_SHELL_OUTPUT_V1_NON_EXCLUSIVE_AREA,
1090                     self.scheduled.non_exclusive_area.x,
1091                     self.scheduled.non_exclusive_area.y,
1092                     self.scheduled.non_exclusive_area.width,
1093                     self.scheduled.non_exclusive_area.height,
1094                 );
1095             }
1096             self.sent.non_exclusive_area = Some(self.scheduled.non_exclusive_area);
1097         }
1098     }
1099 }
1100 
1101 unsafe extern "C" fn handle_layer_shell_output_destroy(resource: *mut ffi::wl_resource) {
1102     let layer_shell_output = ffi::wl_resource_get_user_data(resource) as *mut LayerShellOutput;
1103     if !layer_shell_output.is_null() {
1104         (*layer_shell_output).object = std::ptr::null_mut();
1105         (*layer_shell_output).sent.non_exclusive_area = None;
1106         (*layer_shell_output).requested.default = false;
1107     }
1108 }
1109 
1110 unsafe extern "C" fn layer_shell_output_destroy(client: *mut ffi::wl_client, resource: *mut ffi::wl_resource) {
1111     let _ = client;
1112     ffi::wl_resource_destroy(resource);
1113 }
1114 
1115 unsafe extern "C" fn layer_shell_output_set_default(client: *mut ffi::wl_client, resource: *mut ffi::wl_resource) {
1116     let _ = client;
1117     let layer_shell_output = ffi::wl_resource_get_user_data(resource) as *mut LayerShellOutput;
1118     if layer_shell_output.is_null() {
1119         return;
1120     }
1121     let server = if !(*layer_shell_output).object.is_null() {
1122         // Find server. We can get it via finding Output from the parent link.
1123         // Let's traverse the outputs to set requested.default to false on all outputs
1124         let output = container_of_output(layer_shell_output);
1125         (*output).server
1126     } else {
1127         std::ptr::null_mut()
1128     };
1129 
1130     if !server.is_null() {
1131         let outputs = &mut (*server).om.outputs as *mut ffi::wl_list as *mut WlList;
1132         let mut curr = (*outputs).next;
1133         while curr != outputs {
1134             let next = (*curr).next;
1135             let output = crate::container_of!(curr, Output, link);
1136             (*output).layer_shell.requested.default = false;
1137             curr = next;
1138         }
1139         (*layer_shell_output).requested.default = true;
1140     }
1141 }
1142 
1143 static LAYER_SHELL_OUTPUT_INTERFACE: ffi::river_layer_shell_output_v1_interface = ffi::river_layer_shell_output_v1_interface {
1144     destroy: Some(layer_shell_output_destroy),
1145     set_default: Some(layer_shell_output_set_default),
1146 };
1147 
1148 unsafe extern "C" fn layer_shell_output_inert_set_default(
1149     _client: *mut ffi::wl_client,
1150     _resource: *mut ffi::wl_resource,
1151 ) {}
1152 
1153 static INERT_LAYER_SHELL_OUTPUT_INTERFACE: ffi::river_layer_shell_output_v1_interface = ffi::river_layer_shell_output_v1_interface {
1154     destroy: Some(layer_shell_output_destroy),
1155     set_default: Some(layer_shell_output_inert_set_default),
1156 };
1157 
1158 unsafe fn container_of_output(layer_shell_output: *mut LayerShellOutput) -> *mut Output {
1159     crate::container_of!(layer_shell_output, Output, layer_shell)
1160 }
1161 
1162 pub struct LayerShellSeat {
1163     pub object: *mut ffi::wl_resource, // river_layer_shell_seat_v1
1164     pub scheduled_focus: LayerShellSeatFocus,
1165     pub sent_focus: LayerShellSeatFocus,
1166 }
1167 
1168 impl Default for LayerShellSeat {
1169     fn default() -> Self {
1170         Self {
1171             object: std::ptr::null_mut(),
1172             scheduled_focus: LayerShellSeatFocus::None,
1173             sent_focus: LayerShellSeatFocus::None,
1174         }
1175     }
1176 }
1177 
1178 impl LayerShellSeat {
1179     pub unsafe fn create_object(&mut self, client: *mut ffi::wl_client, version: u32, id: u32, seat: *mut Seat) {
1180         assert!(self.object.is_null());
1181         let resource = ffi::wl_resource_create(client, &ffi::river_layer_shell_seat_v1_interface, version as i32, id);
1182         if resource.is_null() {
1183             ffi::wl_client_post_no_memory(client);
1184             log::error!("out of memory creating river_layer_shell_seat_v1");
1185             return;
1186         }
1187 
1188         ffi::wl_resource_set_implementation(
1189             resource,
1190             &LAYER_SHELL_SEAT_INTERFACE as *const _ as *const _,
1191             self as *mut LayerShellSeat as *mut _,
1192             Some(handle_layer_shell_seat_destroy),
1193         );
1194         self.object = resource;
1195         (*(*seat).server).wm.dirty_windowing();
1196     }
1197 
1198     pub unsafe fn make_inert(&mut self) {
1199         if !self.object.is_null() {
1200             ffi::wl_resource_set_implementation(
1201                 self.object,
1202                 &INERT_LAYER_SHELL_SEAT_INTERFACE as *const _ as *const _,
1203                 std::ptr::null_mut(),
1204                 None,
1205             );
1206             self.object = std::ptr::null_mut();
1207         }
1208     }
1209 
1210     pub unsafe fn manage_start(&mut self) {
1211         if self.scheduled_focus != self.sent_focus {
1212             if !self.object.is_null() {
1213                 match self.scheduled_focus {
1214                     LayerShellSeatFocus::Exclusive(_) => {
1215                         ffi::wl_resource_post_event(self.object, ffi::RIVER_LAYER_SHELL_SEAT_V1_FOCUS_EXCLUSIVE);
1216                     }
1217                     LayerShellSeatFocus::NonExclusive(_) => {
1218                         ffi::wl_resource_post_event(self.object, ffi::RIVER_LAYER_SHELL_SEAT_V1_FOCUS_NON_EXCLUSIVE);
1219                     }
1220                     LayerShellSeatFocus::None => {
1221                         ffi::wl_resource_post_event(self.object, ffi::RIVER_LAYER_SHELL_SEAT_V1_FOCUS_NONE);
1222                     }
1223                 }
1224             }
1225             self.sent_focus = self.scheduled_focus;
1226         }
1227     }
1228 }
1229 
1230 unsafe extern "C" fn handle_layer_shell_seat_destroy(resource: *mut ffi::wl_resource) {
1231     let layer_shell_seat = ffi::wl_resource_get_user_data(resource) as *mut LayerShellSeat;
1232     if !layer_shell_seat.is_null() {
1233         (*layer_shell_seat).object = std::ptr::null_mut();
1234     }
1235 }
1236 
1237 unsafe extern "C" fn layer_shell_seat_destroy(client: *mut ffi::wl_client, resource: *mut ffi::wl_resource) {
1238     let _ = client;
1239     ffi::wl_resource_destroy(resource);
1240 }
1241 
1242 static LAYER_SHELL_SEAT_INTERFACE: ffi::river_layer_shell_seat_v1_interface = ffi::river_layer_shell_seat_v1_interface {
1243     destroy: Some(layer_shell_seat_destroy),
1244 };
1245 
1246 static INERT_LAYER_SHELL_SEAT_INTERFACE: ffi::river_layer_shell_seat_v1_interface = ffi::river_layer_shell_seat_v1_interface {
1247     destroy: Some(layer_shell_seat_destroy),
1248 };