use { crate::{ client::{Client, ClientError}, ifs::{ wl_output::OutputGlobalOpt, wl_seat::{NodeSeatState, WlSeatGlobal}, wl_surface::{ PendingState, SurfaceExt, SurfaceRole, WlSurface, WlSurfaceError, xdg_surface::xdg_popup::{XdgPopup, XdgPopupParent}, }, zwlr_layer_shell_v1::{OVERLAY, ZwlrLayerShellV1}, }, leaks::Tracker, object::Object, rect::Rect, renderer::Renderer, tree::{ Direction, FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId, NodeLayerLink, NodeLocation, NodeVisitor, OutputNode, StackedNode, }, utils::{ bitflags::BitflagsExt, copyhashmap::CopyHashMap, hash_map_ext::HashMapExt, linkedlist::{LinkedList, LinkedNode}, numcell::NumCell, option_ext::OptionExt, }, wire::{WlSurfaceId, XdgPopupId, ZwlrLayerSurfaceV1Id, zwlr_layer_surface_v1::*}, }, std::{ cell::{Cell, RefCell, RefMut}, ops::Deref, rc::Rc, }, thiserror::Error, }; const KI_NONE: u32 = 0; const KI_EXCLUSIVE: u32 = 1; const KI_ON_DEMAND: u32 = 2; const TOP: u32 = 1; const BOTTOM: u32 = 2; const LEFT: u32 = 4; const RIGHT: u32 = 8; tree_id!(ZwlrLayerSurfaceV1NodeId); pub struct ZwlrLayerSurfaceV1 { pub id: ZwlrLayerSurfaceV1Id, node_id: ZwlrLayerSurfaceV1NodeId, pub shell: Rc, pub client: Rc, pub surface: Rc, pub output: Rc, pub _namespace: String, pub tracker: Tracker, output_extents: Cell, pos: Cell, mapped: Cell, layer: Cell, requested_serial: NumCell, size: Cell<(i32, i32)>, anchor: Cell, exclusive_zone: Cell, margin: Cell<(i32, i32, i32, i32)>, keyboard_interactivity: Cell, link: RefCell>>>, seat_state: NodeSeatState, last_configure: Cell<(i32, i32)>, exclusive_edge: Cell>, exclusive_size: Cell, popups: CopyHashMap>, need_position_update: Cell, } #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] pub struct ExclusiveSize { pub top: i32, pub right: i32, pub bottom: i32, pub left: i32, } impl ExclusiveSize { pub fn is_empty(&self) -> bool { *self == ExclusiveSize::default() } pub fn is_not_empty(&self) -> bool { !self.is_empty() } pub fn max(&self, other: &Self) -> Self { Self { top: self.top.max(other.top), right: self.right.max(other.right), bottom: self.bottom.max(other.bottom), left: self.left.max(other.left), } } } #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum ExclusiveZone { MoveSelf, FixedSelf, Acquire(i32), } struct Popup { parent: Rc, popup: Rc, stack: Rc>>, stack_link: RefCell>>>, } #[derive(Default)] pub struct PendingLayerSurfaceData { size: Option<(i32, i32)>, anchor: Option, exclusive_zone: Option, margin: Option<(i32, i32, i32, i32)>, keyboard_interactivity: Option, layer: Option, exclusive_edge: Option, } impl PendingLayerSurfaceData { pub fn merge(&mut self, next: &mut Self) { macro_rules! opt { ($name:ident) => { if let Some(n) = next.$name.take() { self.$name = Some(n); } }; } opt!(size); opt!(anchor); opt!(exclusive_zone); opt!(margin); opt!(keyboard_interactivity); opt!(layer); } } impl ZwlrLayerSurfaceV1 { pub fn new( id: ZwlrLayerSurfaceV1Id, shell: &Rc, surface: &Rc, output: &Rc, layer: u32, namespace: &str, ) -> Self { Self { id, node_id: shell.client.state.node_ids.next(), shell: shell.clone(), client: shell.client.clone(), surface: surface.clone(), output: output.clone(), _namespace: namespace.to_string(), tracker: Default::default(), output_extents: Default::default(), pos: Default::default(), mapped: Cell::new(false), layer: Cell::new(layer), requested_serial: Default::default(), size: Cell::new((0, 0)), anchor: Cell::new(0), exclusive_zone: Cell::new(ExclusiveZone::MoveSelf), margin: Cell::new((0, 0, 0, 0)), keyboard_interactivity: Cell::new(0), link: Default::default(), seat_state: Default::default(), last_configure: Default::default(), exclusive_edge: Default::default(), exclusive_size: Default::default(), popups: Default::default(), need_position_update: Default::default(), } } pub fn install(self: &Rc) -> Result<(), ZwlrLayerSurfaceV1Error> { self.surface.set_role(SurfaceRole::ZwlrLayerSurface)?; if self.surface.ext.get().is_some() { return Err(ZwlrLayerSurfaceV1Error::AlreadyAttached(self.surface.id)); } self.surface.ext.set(self.clone()); if let Some(output) = self.output.node() { self.surface .set_output(&output, NodeLocation::Output(output.id)); } Ok(()) } fn send_configure(&self, serial: u32, width: u32, height: u32) { self.client.event(Configure { self_id: self.id, serial, width, height, }); } pub fn send_closed(&self) { self.client.event(Closed { self_id: self.id }); } fn pending(&self) -> RefMut<'_, Box> { RefMut::map(self.surface.pending.borrow_mut(), |m| { m.layer_surface.get_or_insert_default_ext() }) } pub fn for_each_popup(&self, mut f: impl FnMut(&Rc)) { for popup in self.popups.lock().values() { f(&popup.popup); } } } impl ZwlrLayerSurfaceV1RequestHandler for ZwlrLayerSurfaceV1 { type Error = ZwlrLayerSurfaceV1Error; fn set_size(&self, req: SetSize, _slf: &Rc) -> Result<(), Self::Error> { if req.width > u16::MAX as u32 || req.height > u16::MAX as u32 { return Err(ZwlrLayerSurfaceV1Error::ExcessiveSize); } let mut pending = self.pending(); pending.size = Some((req.width as _, req.height as _)); Ok(()) } fn set_anchor(&self, req: SetAnchor, _slf: &Rc) -> Result<(), Self::Error> { if req.anchor & !(LEFT | RIGHT | TOP | BOTTOM) != 0 { return Err(ZwlrLayerSurfaceV1Error::UnknownAnchor(req.anchor)); } let mut pending = self.pending(); pending.anchor = Some(req.anchor); Ok(()) } fn set_exclusive_zone( &self, req: SetExclusiveZone, _slf: &Rc, ) -> Result<(), Self::Error> { let mut pending = self.pending(); let zone = if req.zone < 0 { ExclusiveZone::FixedSelf } else if req.zone == 0 { ExclusiveZone::MoveSelf } else if req.zone > u16::MAX as i32 { return Err(ZwlrLayerSurfaceV1Error::ExcessiveExclusive); } else { ExclusiveZone::Acquire(req.zone) }; pending.exclusive_zone = Some(zone); Ok(()) } fn set_margin(&self, req: SetMargin, _slf: &Rc) -> Result<(), Self::Error> { let mut pending = self.pending(); for s in [req.top, req.right, req.bottom, req.left] { if (s as i64).abs() > u16::MAX as i64 { return Err(ZwlrLayerSurfaceV1Error::ExcessiveMargin); } } pending.margin = Some((req.top, req.right, req.bottom, req.left)); Ok(()) } fn set_keyboard_interactivity( &self, req: SetKeyboardInteractivity, _slf: &Rc, ) -> Result<(), Self::Error> { if req.keyboard_interactivity > KI_ON_DEMAND { return Err(ZwlrLayerSurfaceV1Error::UnknownKi( req.keyboard_interactivity, )); } let mut pending = self.pending(); pending.keyboard_interactivity = Some(req.keyboard_interactivity); Ok(()) } fn get_popup(&self, req: GetPopup, slf: &Rc) -> Result<(), Self::Error> { let popup = self.client.lookup(req.popup)?; if popup.parent.is_some() { return Err(ZwlrLayerSurfaceV1Error::PopupHasParent); } let stack = self.client.state.root.stacked_above_layers.clone(); popup.xdg.set_popup_stack(&stack, true); let user = Rc::new(Popup { parent: slf.clone(), popup: popup.clone(), stack, stack_link: Default::default(), }); popup.parent.set(Some(user.clone())); self.popups.set(popup.id, user); Ok(()) } fn ack_configure(&self, _req: AckConfigure, _slf: &Rc) -> Result<(), Self::Error> { Ok(()) } fn destroy(&self, _req: Destroy, _slf: &Rc) -> Result<(), Self::Error> { if self.popups.is_not_empty() { return Err(ZwlrLayerSurfaceV1Error::HasPopups); } self.destroy_node(); self.client.remove_obj(self)?; self.surface.unset_ext(); Ok(()) } fn set_layer(&self, req: SetLayer, _slf: &Rc) -> Result<(), Self::Error> { if req.layer > OVERLAY { return Err(ZwlrLayerSurfaceV1Error::UnknownLayer(req.layer)); } let mut pending = self.pending(); pending.layer = Some(req.layer); Ok(()) } fn set_exclusive_edge( &self, req: SetExclusiveEdge, _slf: &Rc, ) -> Result<(), Self::Error> { if req.edge & !(LEFT | RIGHT | TOP | BOTTOM) != 0 { return Err(ZwlrLayerSurfaceV1Error::UnknownAnchor(req.edge)); } if req.edge.count_ones() > 1 { return Err(ZwlrLayerSurfaceV1Error::TooManyExclusiveEdges); } let mut pending = self.pending(); if req.edge == 0 { pending.exclusive_edge = None; } else { pending.exclusive_edge = Some(req.edge); } Ok(()) } } impl ZwlrLayerSurfaceV1 { pub fn exclusive_size(&self) -> ExclusiveSize { self.exclusive_size.get() } fn update_exclusive_size(&self) { let exclusive_edge = { if let Some(ee) = self.exclusive_edge.get() { Some(ee) } else { let anchor = self.anchor.get(); let edges = anchor.count_ones(); if edges == 1 { Some(anchor) } else if edges == 3 { match (!anchor) & (TOP | BOTTOM | LEFT | RIGHT) { TOP => Some(BOTTOM), BOTTOM => Some(TOP), LEFT => Some(RIGHT), RIGHT => Some(LEFT), _ => None, } } else { None } } }; let mut exclusive_size = ExclusiveSize::default(); if let (ExclusiveZone::Acquire(s), Some(edge)) = (self.exclusive_zone.get(), exclusive_edge) { match edge { TOP => exclusive_size.top = s, RIGHT => exclusive_size.right = s, BOTTOM => exclusive_size.bottom = s, LEFT => exclusive_size.left = s, _ => {} } } if self.exclusive_size.replace(exclusive_size) != exclusive_size && let Some(output) = self.output.node.get() { output.update_exclusive_zones(); } } fn pre_commit(&self, pending: &mut PendingState) -> Result<(), ZwlrLayerSurfaceV1Error> { let pending = pending.layer_surface.get_or_insert_default_ext(); if let Some(size) = pending.size.take() { self.size.set(size); } if let Some(anchor) = pending.anchor.take() { if self.anchor.replace(anchor) != anchor { self.need_position_update.set(true); } } if let Some(ez) = pending.exclusive_zone.take() { if self.exclusive_zone.replace(ez) != ez { self.need_position_update.set(true); } } if let Some(margin) = pending.margin.take() { if self.margin.replace(margin) != margin { self.need_position_update.set(true); } } if let Some(ki) = pending.keyboard_interactivity.take() { self.keyboard_interactivity.set(ki); } if let Some(layer) = pending.layer.take() { self.layer.set(layer); } if let Some(edge) = pending.exclusive_edge.take() { self.exclusive_edge.set(Some(edge)); } let anchor = self.anchor.get(); let (width, height) = self.size.get(); if width == 0 && !anchor.contains(LEFT | RIGHT) { return Err(ZwlrLayerSurfaceV1Error::WidthZero); } if height == 0 && !anchor.contains(TOP | BOTTOM) { return Err(ZwlrLayerSurfaceV1Error::HeightZero); } if let Some(ee) = self.exclusive_edge.get() && !self.anchor.get().contains(ee) { return Err(ZwlrLayerSurfaceV1Error::ExclusiveEdgeNotAnchored); } self.configure(); Ok(()) } fn configure(&self) { let Some(node) = self.output.node() else { return; }; let (mut width, mut height) = self.size.get(); let (mt, mr, mb, ml) = self.margin.get(); let (mut available_width, mut available_height) = match self.exclusive_zone.get() { ExclusiveZone::MoveSelf => node.non_exclusive_rect.get().size(), _ => node.global.pos.get().size(), }; let anchor = self.anchor.get(); if anchor.contains(LEFT) { available_width -= ml; } if anchor.contains(RIGHT) { available_width -= mr; } if anchor.contains(TOP) { available_height -= mt; } if anchor.contains(BOTTOM) { available_height -= mb; } if width == 0 { width = available_width; } width = width.min(available_width).max(1); if height == 0 { height = available_height; } height = height.min(available_height).max(1); let serial = self.requested_serial.fetch_add(1) + 1; if self.last_configure.replace((width, height)) != (width, height) { self.send_configure(serial, width as _, height as _); } } pub fn output_extents(&self) -> Rect { self.output_extents.get() } fn compute_position(&self) { let Some(output) = self.output.node() else { return; }; let extents = self.surface.extents.get(); let (width, height) = extents.size(); let mut anchor = self.anchor.get(); if anchor == 0 { anchor = LEFT | RIGHT | TOP | BOTTOM; } let (mt, mr, mb, ml) = self.margin.get(); let opos = output.global.pos.get(); let rect = match self.exclusive_zone.get() { ExclusiveZone::MoveSelf => output.non_exclusive_rect.get(), _ => opos, }; let (owidth, oheight) = rect.size(); let mut x1 = 0; let mut y1 = 0; if anchor.contains(LEFT | RIGHT) { x1 = (owidth - width) / 2; } else if anchor.contains(LEFT) { x1 = ml; } else if anchor.contains(RIGHT) { x1 = owidth - width - mr; } if anchor.contains(TOP | BOTTOM) { y1 = (oheight - height) / 2; } else if anchor.contains(TOP) { y1 = mt; } else if anchor.contains(BOTTOM) { y1 = oheight - height - mb; } let a_rect = Rect::new_sized(x1 + rect.x1(), y1 + rect.y1(), width, height).unwrap(); let o_rect = a_rect.move_(-opos.x1(), -opos.y1()); self.output_extents.set(o_rect); let a_rect_old = self.pos.replace(a_rect); let abs_x = a_rect.x1() - extents.x1(); let abs_y = a_rect.y1() - extents.y1(); self.surface.set_absolute_position(abs_x, abs_y); if a_rect_old != a_rect { for popup in self.popups.lock().values() { popup.popup.update_absolute_position(); } } self.client.state.tree_changed(); self.need_position_update.set(false); } pub fn output_resized(&self) { self.configure(); self.compute_position(); } pub fn exclusive_zones_changed(&self) { if self.exclusive_zone.get() != ExclusiveZone::MoveSelf { return; } self.output_resized(); } pub fn destroy_node(&self) { self.link.borrow_mut().take(); self.mapped.set(false); self.surface.destroy_node(); self.seat_state.destroy_node(self); self.client.state.tree_changed(); self.last_configure.take(); if self.exclusive_size.take().is_not_empty() && let Some(node) = self.output.node() { node.update_exclusive_zones(); } for popup in self.popups.lock().drain_values() { popup.popup.destroy_node(); } } pub fn set_visible(&self, visible: bool) { self.surface.set_visible(visible); if !visible { for popup in self.popups.lock().drain_values() { popup.popup.set_visible(false); popup.popup.destroy_node(); } } } } impl SurfaceExt for ZwlrLayerSurfaceV1 { fn node_layer(&self) -> NodeLayerLink { let Some(link) = self.link.borrow().as_ref().map(|l| l.to_ref()) else { return NodeLayerLink::Display; }; match self.layer.get() { 0 => NodeLayerLink::Layer0(link), 1 => NodeLayerLink::Layer1(link), 2 => NodeLayerLink::Layer2(link), _ => NodeLayerLink::Layer3(link), } } fn before_apply_commit( self: Rc, pending: &mut PendingState, ) -> Result<(), WlSurfaceError> { self.deref().pre_commit(pending)?; Ok(()) } fn after_apply_commit(self: Rc) { let Some(output) = self.output.node() else { return; }; let buffer_is_some = self.surface.buffer.is_some(); let was_mapped = self.mapped.get(); if self.mapped.get() { if !buffer_is_some { self.destroy_node(); } else { if self.surface.extents.get().size() != self.pos.get().size() { self.need_position_update.set(true); } if self.need_position_update.get() { self.compute_position(); } self.update_exclusive_size(); } } else if buffer_is_some { let layer = &output.layers[self.layer.get() as usize]; *self.link.borrow_mut() = Some(layer.add_last(self.clone())); self.mapped.set(true); self.compute_position(); self.update_exclusive_size(); } if self.mapped.get() != was_mapped { output.update_visible(); if self.mapped.get() { let (x, y) = self.surface.buffer_abs_pos.get().position(); let extents = self.surface.extents.get().move_(x, y); self.client.state.damage(extents); } } if self.mapped.get() { match self.keyboard_interactivity.get() { KI_NONE => { let was_active = self.surface.seat_state.is_active(); self.surface.seat_state.release_kb_focus(); if was_active { self.surface.node_active_changed(false); } } KI_ON_DEMAND => self.surface.seat_state.release_kb_grab(), KI_EXCLUSIVE => { let seats = self.client.state.globals.seats.lock(); for seat in seats.values() { seat.grab(self.surface.clone()); } } _ => unreachable!(), } } } fn focus_node(&self) -> Option> { if self.keyboard_interactivity.get() != KI_NONE { Some(self.surface.clone()) } else { None } } } impl Node for ZwlrLayerSurfaceV1 { fn node_id(&self) -> NodeId { self.node_id.into() } fn node_seat_state(&self) -> &NodeSeatState { &self.seat_state } fn node_visit(self: Rc, visitor: &mut dyn NodeVisitor) { visitor.visit_layer_surface(&self); } fn node_visit_children(&self, visitor: &mut dyn NodeVisitor) { visitor.visit_surface(&self.surface); } fn node_visible(&self) -> bool { true } fn node_absolute_position(&self) -> Rect { self.pos.get() } fn node_output(&self) -> Option> { self.output.node() } fn node_location(&self) -> Option { self.surface.node_location() } fn node_layer(&self) -> NodeLayerLink { SurfaceExt::node_layer(self) } fn node_accepts_focus(&self) -> bool { self.keyboard_interactivity.get() != KI_NONE } fn node_do_focus(self: Rc, seat: &Rc, _direction: Direction) { seat.focus_node(self.surface.clone()) } fn node_find_tree_at( &self, x: i32, y: i32, tree: &mut Vec, _usecase: FindTreeUsecase, ) -> FindTreeResult { let (dx, dy) = self.surface.extents.get().position(); self.surface.find_tree_at_(x + dx, y + dy, tree) } fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32, _bounds: Option<&Rect>) { renderer.render_layer_surface(self, x, y); } } impl XdgPopupParent for Popup { fn position(&self) -> Rect { self.parent.pos.get() } fn remove_popup(&self) { self.parent.popups.remove(&self.popup.id); } fn output(&self) -> Rc { self.parent.surface.output.get() } fn has_workspace_link(&self) -> bool { false } fn post_commit(&self) { let mut dl = self.stack_link.borrow_mut(); let output = self.output(); let surface = &self.popup.xdg.surface; let state = &surface.client.state; if surface.buffer.is_some() { if dl.is_none() { if self.parent.surface.visible.get() { self.popup.xdg.set_output(&output); *dl = Some(self.stack.add_last(self.popup.clone())); state.tree_changed(); self.popup.set_visible(self.parent.surface.visible.get()); } else { self.popup.destroy_node(); } } } else { if dl.take().is_some() { drop(dl); self.popup.set_visible(false); self.popup.destroy_node(); } } } fn visible(&self) -> bool { self.parent.node_visible() } fn make_visible(self: Rc) { // nothing } fn node_layer(&self) -> NodeLayerLink { let Some(link) = self.stack_link.borrow().as_ref().map(|w| w.to_ref()) else { return NodeLayerLink::Display; }; NodeLayerLink::StackedAboveLayers(link) } } object_base! { self = ZwlrLayerSurfaceV1; version = self.shell.version; } impl Object for ZwlrLayerSurfaceV1 { fn break_loops(&self) { self.destroy_node(); self.link.borrow_mut().take(); } } simple_add_obj!(ZwlrLayerSurfaceV1); #[derive(Debug, Error)] pub enum ZwlrLayerSurfaceV1Error { #[error( "Surface {0} cannot be turned into a zwlr_layer_surface because it already has an attached zwlr_layer_surface" )] AlreadyAttached(WlSurfaceId), #[error("Width was set to 0 but anchor did not contain LEFT and RIGHT")] WidthZero, #[error("Height was set to 0 but anchor did not contain TOP and BOTTOM")] HeightZero, #[error(transparent)] WlSurfaceError(Box), #[error(transparent)] ClientError(Box), #[error("Unknown layer {0}")] UnknownLayer(u32), #[error("Surface size must not be larger than 65535x65535")] ExcessiveSize, #[error("Margin must not be larger than 65535")] ExcessiveMargin, #[error("Unknown anchor {0}")] UnknownAnchor(u32), #[error("Unknown keyboard interactivity {0}")] UnknownKi(u32), #[error("Surface is not anchored at exclusive edge")] ExclusiveEdgeNotAnchored, #[error("Request must contain exactly one edge")] TooManyExclusiveEdges, #[error("Exclusive zone not be larger than 65535")] ExcessiveExclusive, #[error("Popup already has a parent")] PopupHasParent, #[error("Surface still has popups")] HasPopups, } efrom!(ZwlrLayerSurfaceV1Error, WlSurfaceError); efrom!(ZwlrLayerSurfaceV1Error, ClientError);