use crate::client::{Client, ClientError}; use crate::ifs::wl_seat::NodeSeatState; use crate::ifs::wl_surface::{ CommitAction, CommitContext, SurfaceExt, SurfaceRole, WlSurface, WlSurfaceError, }; use crate::ifs::zwlr_layer_shell_v1::{ZwlrLayerShellV1, OVERLAY}; use crate::leaks::Tracker; use crate::object::Object; use crate::rect::Rect; use crate::render::Renderer; use crate::tree::walker::NodeVisitor; use crate::tree::{FindTreeResult, FoundNode, Node, NodeId, OutputNode}; use crate::utils::bitflags::BitflagsExt; use crate::utils::buffd::MsgParser; use crate::utils::buffd::MsgParserError; use crate::utils::linkedlist::LinkedNode; use crate::wire::zwlr_layer_surface_v1::*; use crate::wire::{WlSurfaceId, ZwlrLayerSurfaceV1Id}; use crate::NumCell; use std::cell::Cell; use std::ops::Deref; use std::rc::Rc; use thiserror::Error; const KI_NONE: u32 = 0; #[allow(dead_code)] 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, pos: Cell, mapped: Cell, layer: Cell, pending: Pending, requested_serial: NumCell, acked_serial: Cell>, size: Cell<(i32, i32)>, anchor: Cell, exclusive_zone: Cell, margin: Cell<(i32, i32, i32, i32)>, keyboard_interactivity: Cell, link: Cell>>>, seat_state: NodeSeatState, } #[derive(Default)] struct Pending { size: Cell>, anchor: Cell>, exclusive_zone: Cell>, margin: Cell>, keyboard_interactivity: Cell>, layer: Cell>, } 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(), pos: Cell::new(Default::default()), mapped: Cell::new(false), layer: Cell::new(layer), pending: Default::default(), requested_serial: Default::default(), acked_serial: Cell::new(None), size: Cell::new((0, 0)), anchor: Cell::new(0), exclusive_zone: Cell::new(0), margin: Cell::new((0, 0, 0, 0)), keyboard_interactivity: Cell::new(0), link: Cell::new(None), seat_state: 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()); Ok(()) } fn send_configure(&self, serial: u32, width: u32, height: u32) { self.client.event(Configure { self_id: self.id, serial, width, height, }); } #[allow(dead_code)] fn send_closed(&self) { self.client.event(Closed { self_id: self.id }); } fn set_size(&self, parser: MsgParser<'_, '_>) -> Result<(), SetSizeError> { let req: SetSize = self.client.parse(self, parser)?; if req.width > u16::MAX as u32 || req.height > u16::MAX as u32 { return Err(SetSizeError::ExcessiveSize); } self.pending .size .set(Some((req.width as _, req.height as _))); Ok(()) } fn set_anchor(&self, parser: MsgParser<'_, '_>) -> Result<(), SetAnchorError> { let req: SetAnchor = self.client.parse(self, parser)?; if req.anchor & !(LEFT | RIGHT | TOP | BOTTOM) != 0 { return Err(SetAnchorError::UnknownAnchor(req.anchor)); } self.pending.anchor.set(Some(req.anchor)); Ok(()) } fn set_exclusive_zone(&self, parser: MsgParser<'_, '_>) -> Result<(), SetExclusiveZoneError> { let req: SetExclusiveZone = self.client.parse(self, parser)?; self.pending.exclusive_zone.set(Some(req.zone)); Ok(()) } fn set_margin(&self, parser: MsgParser<'_, '_>) -> Result<(), SetMarginError> { let req: SetMargin = self.client.parse(self, parser)?; self.pending .margin .set(Some((req.top, req.right, req.bottom, req.left))); Ok(()) } fn set_keyboard_interactivity( &self, parser: MsgParser<'_, '_>, ) -> Result<(), SetKeyboardInteractivityError> { let req: SetKeyboardInteractivity = self.client.parse(self, parser)?; if req.keyboard_interactivity > KI_ON_DEMAND { return Err(SetKeyboardInteractivityError::UnknownKi( req.keyboard_interactivity, )); } self.pending .keyboard_interactivity .set(Some(req.keyboard_interactivity)); Ok(()) } fn get_popup(&self, parser: MsgParser<'_, '_>) -> Result<(), GetPopupError> { let _req: GetPopup = self.client.parse(self, parser)?; Ok(()) } fn ack_configure(&self, parser: MsgParser<'_, '_>) -> Result<(), AckConfigureError> { let req: AckConfigure = self.client.parse(self, parser)?; self.acked_serial.set(Some(req.serial)); Ok(()) } fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { let _req: Destroy = self.client.parse(self, parser)?; self.destroy_node(true); self.client.remove_obj(self)?; self.surface.unset_ext(); Ok(()) } fn set_layer(&self, parser: MsgParser<'_, '_>) -> Result<(), SetLayerError> { let req: SetLayer = self.client.parse(self, parser)?; if req.layer > OVERLAY { return Err(SetLayerError::UnknownLayer(req.layer)); } self.pending.layer.set(Some(req.layer)); Ok(()) } fn pre_commit(&self) -> Result<(), ZwlrLayerSurfaceV1Error> { let mut send_configure = false; if let Some(size) = self.pending.size.take() { self.size.set(size); } if let Some(anchor) = self.pending.anchor.take() { self.anchor.set(anchor); } if let Some(ez) = self.pending.exclusive_zone.take() { self.exclusive_zone.set(ez); } if let Some(margin) = self.pending.margin.take() { self.margin.set(margin); } if let Some(ki) = self.pending.keyboard_interactivity.take() { self.keyboard_interactivity.set(ki); } if let Some(layer) = self.pending.layer.take() { self.layer.set(layer); } { let (mut width, mut height) = self.size.get(); let anchor = self.anchor.get(); if width == 0 { if !anchor.contains(LEFT | RIGHT) { return Err(ZwlrLayerSurfaceV1Error::WidthZero); } send_configure = true; width = self.output.global.position().width(); } if height == 0 { if !anchor.contains(TOP | BOTTOM) { return Err(ZwlrLayerSurfaceV1Error::HeightZero); } send_configure = true; height = self.output.global.position().height(); } self.size.set((width, height)); } if self.acked_serial.get().is_none() { send_configure = true; } if send_configure { let (width, height) = self.size.get(); let serial = self.requested_serial.fetch_add(1) + 1; self.send_configure(serial, width as _, height as _); } Ok(()) } pub fn position(&self) -> Rect { self.pos.get() } fn compute_position(&self) { let (width, height) = self.size.get(); let mut anchor = self.anchor.get(); if anchor == 0 { anchor = LEFT | RIGHT | TOP | BOTTOM; } let opos = self.output.position.get(); let mut x1 = opos.x1(); let mut y1 = opos.y1(); if anchor.contains(LEFT) { if anchor.contains(RIGHT) { x1 += (opos.width() - width) / 2; } } else if anchor.contains(RIGHT) { x1 += opos.width() - width; } if anchor.contains(TOP) { if anchor.contains(BOTTOM) { y1 += (opos.height() - height) / 2; } } else if anchor.contains(BOTTOM) { y1 += opos.height() - height; } self.pos .set(Rect::new_sized(x1, y1, width, height).unwrap()); self.client.state.tree_changed(); } } impl SurfaceExt for ZwlrLayerSurfaceV1 { fn pre_commit(self: Rc, _ctx: CommitContext) -> Result { self.deref().pre_commit()?; Ok(CommitAction::ContinueCommit) } fn post_commit(self: Rc) { let buffer = self.surface.buffer.get(); if self.mapped.get() { if buffer.is_none() { self.destroy_node(true); } else { let pos = self.pos.get(); let (width, height) = self.size.get(); if width != pos.width() || height != pos.height() { self.compute_position(); } } } else if buffer.is_some() { let layer = &self.output.layers[self.layer.get() as usize]; self.link.set(Some(layer.add_last(self.clone()))); self.mapped.set(true); self.compute_position(); } 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.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 accepts_kb_focus(&self) -> bool { self.keyboard_interactivity.get() != KI_NONE } } impl Node for ZwlrLayerSurfaceV1 { fn id(&self) -> NodeId { self.node_id.into() } fn seat_state(&self) -> &NodeSeatState { &self.seat_state } fn destroy_node(&self, _detach: bool) { self.link.set(None); self.mapped.set(false); self.surface.destroy_node(false); self.seat_state.destroy_node(self); } fn visit(self: Rc, visitor: &mut dyn NodeVisitor) { visitor.visit_layer_surface(&self); } fn visit_children(&self, visitor: &mut dyn NodeVisitor) { self.surface.clone().visit(visitor); } fn render(&self, renderer: &mut Renderer, x: i32, y: i32) { renderer.render_layer_surface(self, x, y); } fn absolute_position(&self) -> Rect { self.pos.get() } fn find_tree_at(&self, x: i32, y: i32, tree: &mut Vec) -> FindTreeResult { tree.push(FoundNode { node: self.surface.clone(), x, y, }); self.surface.find_tree_at(x, y, tree) } fn change_extents(self: Rc, _rect: &Rect) { self.compute_position(); } } object_base! { ZwlrLayerSurfaceV1, ZwlrLayerSurfaceV1Error; SET_SIZE => set_size, SET_ANCHOR => set_anchor, SET_EXCLUSIVE_ZONE => set_exclusive_zone, SET_MARGIN => set_margin, SET_KEYBOARD_INTERACTIVITY => set_keyboard_interactivity, GET_POPUP => get_popup, ACK_CONFIGURE => ack_configure, DESTROY => destroy, SET_LAYER => set_layer, } impl Object for ZwlrLayerSurfaceV1 { fn num_requests(&self) -> u32 { let last_req = match self.shell.version { 0..=1 => DESTROY, _ => SET_LAYER, }; last_req + 1 } fn break_loops(&self) { self.destroy_node(true); self.link.set(None); } } simple_add_obj!(ZwlrLayerSurfaceV1); #[derive(Debug, Error)] pub enum ZwlrLayerSurfaceV1Error { #[error("Could not process `set_size` request")] SetSizeError(#[from] SetSizeError), #[error("Could not process `set_anchor` request")] SetAnchorError(#[from] SetAnchorError), #[error("Could not process `set_exclusive_zone` request")] SetExclusiveZoneError(#[from] SetExclusiveZoneError), #[error("Could not process `set_margin` request")] SetMarginError(#[from] SetMarginError), #[error("Could not process `set_keyboard_interactivity` request")] SetKeyboardInteractivityError(#[from] SetKeyboardInteractivityError), #[error("Could not process `get_popup` request")] GetPopupError(#[from] GetPopupError), #[error("Could not process `ack_configure` request")] AckConfigureError(#[from] AckConfigureError), #[error("Could not process `destroy` request")] DestroyError(#[from] DestroyError), #[error("Could not process `set_layer` request")] SetLayerError(#[from] SetLayerError), #[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), } efrom!(ZwlrLayerSurfaceV1Error, WlSurfaceError); #[derive(Debug, Error)] pub enum SetSizeError { #[error("Parsing failed")] MsgParserError(#[source] Box), #[error(transparent)] ClientError(Box), #[error("Surface size must not be larger than 65535x65535")] ExcessiveSize, } efrom!(SetSizeError, MsgParserError); efrom!(SetSizeError, ClientError); #[derive(Debug, Error)] pub enum SetAnchorError { #[error("Parsing failed")] MsgParserError(#[source] Box), #[error(transparent)] ClientError(Box), #[error("Unknown anchor {0}")] UnknownAnchor(u32), } efrom!(SetAnchorError, MsgParserError); efrom!(SetAnchorError, ClientError); #[derive(Debug, Error)] pub enum SetExclusiveZoneError { #[error("Parsing failed")] MsgParserError(#[source] Box), #[error(transparent)] ClientError(Box), } efrom!(SetExclusiveZoneError, MsgParserError); efrom!(SetExclusiveZoneError, ClientError); #[derive(Debug, Error)] pub enum SetMarginError { #[error("Parsing failed")] MsgParserError(#[source] Box), #[error(transparent)] ClientError(Box), } efrom!(SetMarginError, MsgParserError); efrom!(SetMarginError, ClientError); #[derive(Debug, Error)] pub enum SetKeyboardInteractivityError { #[error("Parsing failed")] MsgParserError(#[source] Box), #[error(transparent)] ClientError(Box), #[error("Unknown keyboard interactivity {0}")] UnknownKi(u32), } efrom!(SetKeyboardInteractivityError, MsgParserError); efrom!(SetKeyboardInteractivityError, ClientError); #[derive(Debug, Error)] pub enum GetPopupError { #[error("Parsing failed")] MsgParserError(#[source] Box), #[error(transparent)] ClientError(Box), } efrom!(GetPopupError, MsgParserError); efrom!(GetPopupError, ClientError); #[derive(Debug, Error)] pub enum AckConfigureError { #[error("Parsing failed")] MsgParserError(#[source] Box), #[error(transparent)] ClientError(Box), } efrom!(AckConfigureError, MsgParserError); efrom!(AckConfigureError, ClientError); #[derive(Debug, Error)] pub enum DestroyError { #[error("Parsing failed")] MsgParserError(#[source] Box), #[error(transparent)] ClientError(Box), } efrom!(DestroyError, MsgParserError); efrom!(DestroyError, ClientError); #[derive(Debug, Error)] pub enum SetLayerError { #[error("Parsing failed")] MsgParserError(#[source] Box), #[error(transparent)] ClientError(Box), #[error("Unknown layer {0}")] UnknownLayer(u32), } efrom!(SetLayerError, MsgParserError); efrom!(SetLayerError, ClientError);