use smithay::delegate_layer_shell; use smithay::desktop::{layer_map_for_output, LayerSurface, WindowSurfaceType}; use smithay::output::Output; use smithay::reexports::wayland_server::protocol::wl_output::WlOutput; use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface; use smithay::wayland::compositor::{send_surface_state, with_states}; use smithay::wayland::shell::wlr_layer::{ Layer, LayerSurface as WlrLayerSurface, LayerSurfaceData, WlrLayerShellHandler, WlrLayerShellState, }; use smithay::wayland::shell::xdg::PopupSurface; use crate::niri::State; impl WlrLayerShellHandler for State { fn shell_state(&mut self) -> &mut WlrLayerShellState { &mut self.niri.layer_shell_state } fn new_layer_surface( &mut self, surface: WlrLayerSurface, wl_output: Option, _layer: Layer, namespace: String, ) { let output = wl_output .as_ref() .and_then(Output::from_resource) .or_else(|| self.niri.layout.active_output().cloned()) .unwrap(); let mut map = layer_map_for_output(&output); map.map_layer(&LayerSurface::new(surface, namespace)) .unwrap(); } fn layer_destroyed(&mut self, surface: WlrLayerSurface) { let output = if let Some((output, mut map, layer)) = self.niri.layout.outputs().find_map(|o| { let map = layer_map_for_output(o); let layer = map .layers() .find(|&layer| layer.layer_surface() == &surface) .cloned(); layer.map(|layer| (o.clone(), map, layer)) }) { map.unmap_layer(&layer); Some(output) } else { None }; if let Some(output) = output { self.niri.output_resized(output); } } fn new_popup(&mut self, _parent: WlrLayerSurface, popup: PopupSurface) { self.unconstrain_popup(&popup); } } delegate_layer_shell!(State); impl State { pub fn layer_shell_handle_commit(&mut self, surface: &WlSurface) { let Some(output) = self .niri .layout .outputs() .find(|o| { let map = layer_map_for_output(o); map.layer_for_surface(surface, WindowSurfaceType::TOPLEVEL) .is_some() }) .cloned() else { return; }; let initial_configure_sent = with_states(surface, |states| { states .data_map .get::() .unwrap() .lock() .unwrap() .initial_configure_sent }); let mut map = layer_map_for_output(&output); // arrange the layers before sending the initial configure // to respect any size the client may have sent map.arrange(); // send the initial configure if relevant if !initial_configure_sent { let layer = map .layer_for_surface(surface, WindowSurfaceType::TOPLEVEL) .unwrap(); let scale = output.current_scale().integer_scale(); let transform = output.current_transform(); with_states(surface, |data| { send_surface_state(surface, data, scale, transform); }); layer.layer_surface().send_configure(); } drop(map); self.niri.output_resized(output); } }