diff --git a/compositor/src/handlers/compositor.rs b/compositor/src/handlers/compositor.rs index f56089a..0ca21b4 100644 --- a/compositor/src/handlers/compositor.rs +++ b/compositor/src/handlers/compositor.rs @@ -14,7 +14,7 @@ use smithay::{ }, }; -use super::xdg_shell; +use super::{layer_shell, xdg_shell}; use crate::{Ferese, state::ClientState}; impl CompositorHandler for Ferese { @@ -52,6 +52,7 @@ impl CompositorHandler for Ferese { self.record_client_commit(&window); } } + layer_shell::handle_commit(self, surface); xdg_shell::handle_commit(&mut self.popups, &mut self.space, surface); crate::backends::direct::render_all(self); } diff --git a/compositor/src/handlers/layer_shell.rs b/compositor/src/handlers/layer_shell.rs new file mode 100644 index 0000000..cfd5f22 --- /dev/null +++ b/compositor/src/handlers/layer_shell.rs @@ -0,0 +1,90 @@ +use smithay::{ + desktop::{ + LayerSurface as DesktopLayerSurface, PopupKind, WindowSurfaceType, layer_map_for_output, + }, + output::Output, + reexports::wayland_server::protocol::{wl_output::WlOutput, wl_surface::WlSurface}, + wayland::shell::{ + wlr_layer::{Layer, LayerSurface, WlrLayerShellHandler, WlrLayerShellState}, + xdg::PopupSurface, + }, +}; + +use crate::Ferese; + +impl WlrLayerShellHandler for Ferese { + fn shell_state(&mut self) -> &mut WlrLayerShellState { + &mut self.layer_shell_state + } + + fn new_layer_surface( + &mut self, + surface: LayerSurface, + output: Option, + _layer: Layer, + namespace: String, + ) { + let output = output + .as_ref() + .and_then(Output::from_resource) + .or_else(|| self.space.outputs().next().cloned()); + let Some(output) = output else { + tracing::warn!(%namespace, "layer surface has no available output"); + return; + }; + let layer = DesktopLayerSurface::new(surface, namespace.clone()); + + if let Err(error) = layer_map_for_output(&output).map_layer(&layer) { + tracing::warn!(%namespace, %error, "failed to map layer surface"); + return; + } + + tracing::debug!(%namespace, output = %output.name(), "mapped layer surface"); + self.relayout(); + crate::backends::direct::render_all(self); + } + + fn new_popup(&mut self, _parent: LayerSurface, popup: PopupSurface) { + if let Err(error) = self.popups.track_popup(PopupKind::Xdg(popup)) { + tracing::warn!(?error, "failed to track layer-shell popup"); + } + } + + fn layer_destroyed(&mut self, surface: LayerSurface) { + let Some(layer) = self + .space + .layer_for_surface(surface.wl_surface(), WindowSurfaceType::TOPLEVEL) + else { + return; + }; + let outputs = self.space.outputs().cloned().collect::>(); + + for output in outputs { + layer_map_for_output(&output).unmap_layer(&layer); + } + + self.relayout(); + crate::backends::direct::render_all(self); + } +} + +pub fn handle_commit(state: &mut Ferese, surface: &WlSurface) { + let Some(layer) = state + .space + .layer_for_surface(surface, WindowSurfaceType::TOPLEVEL) + else { + return; + }; + let outputs = state.space.outputs().cloned().collect::>(); + + for output in outputs { + let mut map = layer_map_for_output(&output); + if map.layer_geometry(&layer).is_some() { + map.arrange(); + layer.layer_surface().send_pending_configure(); + break; + } + } + + state.relayout(); +} diff --git a/compositor/src/handlers/mod.rs b/compositor/src/handlers/mod.rs index 64745d4..25b28bb 100644 --- a/compositor/src/handlers/mod.rs +++ b/compositor/src/handlers/mod.rs @@ -1,5 +1,6 @@ mod activation; mod compositor; +mod layer_shell; mod xdg_shell; use smithay::{ @@ -152,6 +153,7 @@ impl PrimarySelectionHandler for Ferese { smithay::delegate_compositor!(Ferese); smithay::delegate_data_device!(Ferese); smithay::delegate_fractional_scale!(Ferese); +smithay::delegate_layer_shell!(Ferese); smithay::delegate_output!(Ferese); smithay::delegate_pointer_constraints!(Ferese); smithay::delegate_presentation!(Ferese); diff --git a/compositor/src/state.rs b/compositor/src/state.rs index bcb90c1..6e547d5 100644 --- a/compositor/src/state.rs +++ b/compositor/src/state.rs @@ -33,6 +33,7 @@ use smithay::{ presentation::PresentationState, relative_pointer::RelativePointerManagerState, selection::{data_device::DataDeviceState, primary_selection::PrimarySelectionState}, + shell::wlr_layer::WlrLayerShellState, shell::xdg::decoration::XdgDecorationState, shell::xdg::{SurfaceCachedState, XdgShellState}, shm::ShmState, @@ -71,6 +72,7 @@ pub struct Ferese { pub seat_state: SeatState, pub shm_state: ShmState, pub viewporter_state: ViewporterState, + pub layer_shell_state: WlrLayerShellState, pub xdg_activation_state: XdgActivationState, pub xdg_shell_state: XdgShellState, } @@ -94,6 +96,7 @@ impl Ferese { let primary_selection_state = PrimarySelectionState::new::(&display_handle); let relative_pointer_state = RelativePointerManagerState::new::(&display_handle); let viewporter_state = ViewporterState::new::(&display_handle); + let layer_shell_state = WlrLayerShellState::new::(&display_handle); let xdg_activation_state = XdgActivationState::new::(&display_handle); let mut seat_state = SeatState::new(); let mut seat = seat_state.new_wl_seat(&display_handle, "ferese-winit"); @@ -132,6 +135,7 @@ impl Ferese { seat_state, shm_state, viewporter_state, + layer_shell_state, xdg_activation_state, xdg_shell_state, })