Skip to main content

smithay_client_toolkit/shell/wlr_layer/
mod.rs

1mod dispatch;
2
3use std::{
4    convert::TryFrom,
5    sync::{Arc, Weak},
6};
7
8use bitflags::bitflags;
9use wayland_client::{
10    globals::{BindError, GlobalList},
11    protocol::{wl_output, wl_surface},
12    Connection, Dispatch, Proxy, QueueHandle,
13};
14use wayland_protocols::xdg::shell::client::xdg_popup::XdgPopup;
15use wayland_protocols_wlr::layer_shell::v1::client::{zwlr_layer_shell_v1, zwlr_layer_surface_v1};
16
17use crate::{compositor::Surface, globals::GlobalData};
18
19use super::WaylandSurface;
20
21#[derive(Debug)]
22pub struct LayerShell {
23    wlr_layer_shell: zwlr_layer_shell_v1::ZwlrLayerShellV1,
24}
25
26impl LayerShell {
27    /// Binds the wlr layer shell global, `zwlr_layer_shell_v1`.
28    ///
29    /// # Errors
30    ///
31    /// This function will return [`Err`] if the `zwlr_layer_shell_v1` global is not available.
32    pub fn bind<State>(
33        globals: &GlobalList,
34        qh: &QueueHandle<State>,
35    ) -> Result<LayerShell, BindError>
36    where
37        State: Dispatch<zwlr_layer_shell_v1::ZwlrLayerShellV1, GlobalData, State>
38            + LayerShellHandler
39            + 'static,
40    {
41        let wlr_layer_shell = globals.bind(qh, 1..=4, GlobalData)?;
42        Ok(LayerShell { wlr_layer_shell })
43    }
44
45    #[must_use]
46    pub fn create_layer_surface<State>(
47        &self,
48        qh: &QueueHandle<State>,
49        surface: impl Into<Surface>,
50        layer: Layer,
51        namespace: Option<impl Into<String>>,
52        output: Option<&wl_output::WlOutput>,
53    ) -> LayerSurface
54    where
55        State: Dispatch<zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, LayerSurfaceData> + 'static,
56    {
57        // Freeze the queue during the creation of the Arc to avoid a race between events on the
58        // new objects being processed and the Weak in the LayerSurfaceData becoming usable.
59        let freeze = qh.freeze();
60        let surface = surface.into();
61
62        let inner = Arc::new_cyclic(|weak| {
63            let layer_surface = self.wlr_layer_shell.get_layer_surface(
64                surface.wl_surface(),
65                output,
66                layer.into(),
67                namespace.map(Into::into).unwrap_or_default(),
68                qh,
69                LayerSurfaceData { inner: weak.clone() },
70            );
71
72            LayerSurfaceInner { wl_surface: surface, kind: SurfaceKind::Wlr(layer_surface) }
73        });
74        drop(freeze);
75
76        LayerSurface(inner)
77    }
78}
79
80/// Handler for operations on a [`LayerSurface`]
81pub trait LayerShellHandler: Sized {
82    /// The layer surface has been closed.
83    ///
84    /// When this requested is called, the layer surface is no longer shown and all handles of the [`LayerSurface`]
85    /// should be dropped.
86    fn closed(&mut self, conn: &Connection, qh: &QueueHandle<Self>, layer: &LayerSurface);
87
88    /// Apply a suggested surface change.
89    ///
90    /// When this function is called, the compositor is requesting the layer surfaces's size or state to change.
91    fn configure(
92        &mut self,
93        conn: &Connection,
94        qh: &QueueHandle<Self>,
95        layer: &LayerSurface,
96        configure: LayerSurfaceConfigure,
97        serial: u32,
98    );
99}
100
101#[derive(Debug, Clone)]
102pub struct LayerSurface(Arc<LayerSurfaceInner>);
103
104impl PartialEq for LayerSurface {
105    fn eq(&self, other: &Self) -> bool {
106        Arc::ptr_eq(&self.0, &other.0)
107    }
108}
109
110impl LayerSurface {
111    pub fn from_wlr_surface(
112        surface: &zwlr_layer_surface_v1::ZwlrLayerSurfaceV1,
113    ) -> Option<LayerSurface> {
114        surface.data::<LayerSurfaceData>().and_then(|data| data.inner.upgrade()).map(LayerSurface)
115    }
116
117    pub fn get_popup(&self, popup: &XdgPopup) {
118        match self.0.kind {
119            SurfaceKind::Wlr(ref s) => s.get_popup(popup),
120        }
121    }
122
123    // Double buffered state
124
125    pub fn set_size(&self, width: u32, height: u32) {
126        match self.0.kind {
127            SurfaceKind::Wlr(ref wlr) => wlr.set_size(width, height),
128        }
129    }
130
131    pub fn set_anchor(&self, anchor: Anchor) {
132        match self.0.kind {
133            // We currently rely on the bitsets being the same
134            SurfaceKind::Wlr(ref wlr) => {
135                wlr.set_anchor(zwlr_layer_surface_v1::Anchor::from_bits_truncate(anchor.bits()))
136            }
137        }
138    }
139
140    pub fn set_exclusive_zone(&self, zone: i32) {
141        match self.0.kind {
142            SurfaceKind::Wlr(ref wlr) => wlr.set_exclusive_zone(zone),
143        }
144    }
145
146    pub fn set_margin(&self, top: i32, right: i32, bottom: i32, left: i32) {
147        match self.0.kind {
148            SurfaceKind::Wlr(ref wlr) => wlr.set_margin(top, right, bottom, left),
149        }
150    }
151
152    pub fn set_keyboard_interactivity(&self, value: KeyboardInteractivity) {
153        match self.0.kind {
154            SurfaceKind::Wlr(ref wlr) => wlr.set_keyboard_interactivity(value.into()),
155        }
156    }
157
158    pub fn set_layer(&self, layer: Layer) {
159        match self.0.kind {
160            SurfaceKind::Wlr(ref wlr) => wlr.set_layer(layer.into()),
161        }
162    }
163
164    pub fn kind(&self) -> &SurfaceKind {
165        &self.0.kind
166    }
167}
168
169impl WaylandSurface for LayerSurface {
170    fn wl_surface(&self) -> &wl_surface::WlSurface {
171        self.0.wl_surface.wl_surface()
172    }
173}
174
175#[non_exhaustive]
176#[derive(Debug, Clone, PartialEq, Eq)]
177pub enum SurfaceKind {
178    Wlr(zwlr_layer_surface_v1::ZwlrLayerSurfaceV1),
179}
180
181#[non_exhaustive]
182#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
183pub enum KeyboardInteractivity {
184    /// No keyboard focus is possible.
185    ///
186    /// This is the default value for all newly created layer shells.
187    #[default]
188    None,
189
190    /// Request exclusive keyboard focus if the layer is above shell surfaces.
191    ///
192    /// For [`Layer::Top`] and [`Layer::Overlay`], the seat will always give exclusive access to the layer
193    /// which has this interactivity mode set.
194    ///
195    /// This setting is intended for applications that need to ensure they receive all keyboard events, such
196    /// as a lock screen or a password prompt.
197    Exclusive,
198
199    /// The compositor should focus and unfocus this surface by the user in an implementation specific manner.
200    ///
201    /// Compositors may use their normal mechanisms to manage keyboard focus between layers and regular
202    /// desktop surfaces.
203    ///
204    /// This setting is intended for applications which allow keyboard interaction.  
205    OnDemand,
206}
207
208/// The z-depth of a layer.
209///
210/// These values indicate which order in which layer surfaces are rendered.
211#[non_exhaustive]
212#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
213pub enum Layer {
214    Background,
215
216    Bottom,
217
218    Top,
219
220    Overlay,
221}
222
223/// Error when converting a [`zwlr_layer_shell_v1::Layer`] to a [`Layer`]
224#[derive(Debug, thiserror::Error)]
225#[error("unknown layer")]
226pub struct UnknownLayer;
227
228bitflags! {
229    /// Specifies which edges and corners a layer should be placed at in the anchor rectangle.
230    ///
231    /// A combination of two orthogonal edges will cause the layer's anchor point to be the intersection of
232    /// the edges. For example [`Anchor::TOP`] and [`Anchor::LEFT`] will result in an anchor point in the top
233    /// left of the anchor rectangle.
234    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
235    pub struct Anchor: u32 {
236        /// Top edge of the anchor rectangle.
237        const TOP = 1;
238
239        /// The bottom edge of the anchor rectangle.
240        const BOTTOM = 2;
241
242        /// The left edge of the anchor rectangle.
243        const LEFT = 4;
244
245        /// The right edge of the anchor rectangle.
246        const RIGHT = 8;
247    }
248}
249
250/// A layer surface configure.
251///
252/// A configure describes a compositor request to resize the layer surface or change it's state.
253#[non_exhaustive]
254#[derive(Debug, Clone)]
255pub struct LayerSurfaceConfigure {
256    /// The compositor suggested new size of the layer in surface-local coordinates.
257    ///
258    /// The size is a hint, meaning the new size can be ignored. A smaller size could be picked to satisfy
259    /// some aspect ratio or resize in steps. If the size is smaller than suggested and the layer surface is
260    /// anchored to two opposite anchors then the layer surface will be centered on that axis.
261    ///
262    /// If the width is zero, you may choose any width you want. If the height is zero, you may choose any
263    /// height you want.
264    pub new_size: (u32, u32),
265}
266
267#[derive(Debug)]
268pub struct LayerSurfaceData {
269    inner: Weak<LayerSurfaceInner>,
270}
271
272impl LayerSurfaceData {
273    pub fn layer_surface(&self) -> Option<LayerSurface> {
274        self.inner.upgrade().map(LayerSurface)
275    }
276}
277
278#[derive(Debug)]
279struct LayerSurfaceInner {
280    wl_surface: Surface,
281    kind: SurfaceKind,
282}
283
284impl TryFrom<zwlr_layer_shell_v1::Layer> for Layer {
285    type Error = UnknownLayer;
286
287    fn try_from(layer: zwlr_layer_shell_v1::Layer) -> Result<Self, Self::Error> {
288        match layer {
289            zwlr_layer_shell_v1::Layer::Background => Ok(Self::Background),
290            zwlr_layer_shell_v1::Layer::Bottom => Ok(Self::Bottom),
291            zwlr_layer_shell_v1::Layer::Top => Ok(Self::Top),
292            zwlr_layer_shell_v1::Layer::Overlay => Ok(Self::Overlay),
293            _ => Err(UnknownLayer),
294        }
295    }
296}
297
298impl From<Layer> for zwlr_layer_shell_v1::Layer {
299    fn from(depth: Layer) -> Self {
300        match depth {
301            Layer::Background => Self::Background,
302            Layer::Bottom => Self::Bottom,
303            Layer::Top => Self::Top,
304            Layer::Overlay => Self::Overlay,
305        }
306    }
307}
308
309impl From<KeyboardInteractivity> for zwlr_layer_surface_v1::KeyboardInteractivity {
310    fn from(interactivity: KeyboardInteractivity) -> Self {
311        match interactivity {
312            KeyboardInteractivity::None => zwlr_layer_surface_v1::KeyboardInteractivity::None,
313            KeyboardInteractivity::Exclusive => {
314                zwlr_layer_surface_v1::KeyboardInteractivity::Exclusive
315            }
316            KeyboardInteractivity::OnDemand => {
317                zwlr_layer_surface_v1::KeyboardInteractivity::OnDemand
318            }
319        }
320    }
321}
322
323impl Drop for LayerSurfaceInner {
324    fn drop(&mut self) {
325        // Layer shell protocol dictates we must destroy the role object before the surface.
326        match self.kind {
327            SurfaceKind::Wlr(ref wlr) => wlr.destroy(),
328        }
329
330        // Surface will destroy the wl_surface
331        // self.wl_surface.destroy();
332    }
333}