smithay/wayland/shell/wlr_layer/
mod.rs

1//! Utilities for handling shell surfaces with the `wlr_layer_shell` protocol
2//!
3//! This interface should be suitable for the implementation of many desktop shell components,
4//! and a broad number of other applications that interact with the desktop.
5//!
6//! ### Initialization
7//!
8//! To initialize this handler, create the [`WlrLayerShellState`], store it inside your `State` and
9//! implement the [`WlrLayerShellHandler`], as shown in this example:
10//!
11//! ```no_run
12//! # extern crate wayland_server;
13//! #
14//! use smithay::delegate_layer_shell;
15//! use smithay::wayland::shell::wlr_layer::{WlrLayerShellState, WlrLayerShellHandler, LayerSurface, Layer};
16//! use smithay::reexports::wayland_server::protocol::wl_output::WlOutput;
17//!
18//! # struct State { layer_shell_state: WlrLayerShellState }
19//! # let mut display = wayland_server::Display::<State>::new().unwrap();
20//! let layer_shell_state = WlrLayerShellState::new::<State>(
21//!     &display.handle(),
22//! );
23//!
24//! // - Put your layer_shell_state into your `State`.
25//! // - And implement `LayerShellHandler
26//! impl WlrLayerShellHandler for State {
27//!     fn shell_state(&mut self) -> &mut WlrLayerShellState {
28//!         &mut self.layer_shell_state
29//!     }
30//!
31//!     fn new_layer_surface(
32//!         &mut self,
33//!         surface: LayerSurface,
34//!         output: Option<WlOutput>,
35//!         layer: Layer,
36//!         namespace: String,
37//!     ) {
38//!         # let _ = (surface, output, layer, namespace);
39//!         // your implementation
40//!     }
41//! }
42//! // let smithay implement wayland_server::DelegateDispatch
43//! delegate_layer_shell!(State);
44//!
45//! // You're now ready to go!
46//! ```
47
48use std::sync::{Arc, Mutex};
49
50use wayland_protocols_wlr::layer_shell::v1::server::{
51    zwlr_layer_shell_v1::{self, ZwlrLayerShellV1},
52    zwlr_layer_surface_v1,
53};
54use wayland_server::{
55    backend::GlobalId,
56    protocol::{wl_output::WlOutput, wl_surface},
57    Client, DisplayHandle, GlobalDispatch, Resource,
58};
59
60use crate::{
61    utils::{alive_tracker::IsAlive, Logical, Serial, Size, SERIAL_COUNTER},
62    wayland::{
63        compositor::{self, Cacheable},
64        shell::xdg,
65    },
66};
67
68mod handlers;
69mod types;
70
71pub use handlers::WlrLayerSurfaceUserData;
72pub use types::{Anchor, ExclusiveZone, KeyboardInteractivity, Layer, Margins};
73
74/// The role of a wlr_layer_shell_surface
75pub const LAYER_SURFACE_ROLE: &str = "zwlr_layer_surface_v1";
76
77/// Data associated with XDG popup surface  
78///
79/// ```no_run
80/// use smithay::wayland::compositor;
81/// use smithay::wayland::shell::wlr_layer::LayerSurfaceData;
82///
83/// # let wl_surface = todo!();
84/// compositor::with_states(&wl_surface, |states| {
85///     states.data_map.get::<LayerSurfaceData>();
86/// });
87/// ```
88pub type LayerSurfaceData = Mutex<LayerSurfaceAttributes>;
89
90/// Attributes for layer surface
91#[derive(Debug)]
92pub struct LayerSurfaceAttributes {
93    surface: zwlr_layer_surface_v1::ZwlrLayerSurfaceV1,
94    /// Defines if the surface has received at least one
95    /// layer_surface.ack_configure from the client
96    pub configured: bool,
97    /// The serial of the last acked configure
98    pub configure_serial: Option<Serial>,
99    /// Holds the state if the surface has sent the initial
100    /// configure event to the client. It is expected that
101    /// during the first commit a initial
102    /// configure event is sent to the client
103    pub initial_configure_sent: bool,
104    /// Holds the configures the server has sent out
105    /// to the client waiting to be acknowledged by
106    /// the client. All pending configures that are older
107    /// than the acknowledged one will be discarded during
108    /// processing layer_surface.ack_configure.
109    pending_configures: Vec<LayerSurfaceConfigure>,
110    /// Holds the pending state as set by the server.
111    pub server_pending: Option<LayerSurfaceState>,
112    /// Holds the last server_pending state that has been acknowledged
113    /// by the client. This state should be cloned to the current
114    /// during a commit.
115    pub last_acked: Option<LayerSurfaceState>,
116    /// Holds the current state of the layer after a successful
117    /// commit.
118    pub current: LayerSurfaceState,
119}
120
121impl LayerSurfaceAttributes {
122    fn new(surface: zwlr_layer_surface_v1::ZwlrLayerSurfaceV1) -> Self {
123        Self {
124            surface,
125            configured: false,
126            configure_serial: None,
127            initial_configure_sent: false,
128            pending_configures: Vec::new(),
129            server_pending: None,
130            last_acked: None,
131            current: Default::default(),
132        }
133    }
134
135    fn ack_configure(&mut self, serial: Serial) -> Option<LayerSurfaceConfigure> {
136        let configure = self
137            .pending_configures
138            .iter()
139            .find(|configure| configure.serial == serial)
140            .cloned()?;
141
142        self.last_acked = Some(configure.state.clone());
143
144        self.configured = true;
145        self.configure_serial = Some(serial);
146        self.pending_configures.retain(|c| c.serial > serial);
147        Some(configure)
148    }
149
150    fn reset(&mut self) {
151        self.configured = false;
152        self.configure_serial = None;
153        self.initial_configure_sent = false;
154        self.pending_configures = Vec::new();
155        self.server_pending = None;
156        self.last_acked = None;
157        self.current = Default::default();
158    }
159
160    fn current_server_state(&self) -> &LayerSurfaceState {
161        self.pending_configures
162            .last()
163            .map(|c| &c.state)
164            .or(self.last_acked.as_ref())
165            .unwrap_or(&self.current)
166    }
167
168    fn has_pending_changes(&self) -> bool {
169        self.server_pending
170            .as_ref()
171            .map(|s| s != self.current_server_state())
172            .unwrap_or(false)
173    }
174}
175
176/// State of a layer surface
177#[derive(Debug, Default, Clone, PartialEq, Eq)]
178pub struct LayerSurfaceState {
179    /// The suggested size of the surface
180    pub size: Option<Size<i32, Logical>>,
181}
182
183/// Represents the client pending state
184#[derive(Debug, Default, Clone, Copy)]
185pub struct LayerSurfaceCachedState {
186    /// The size requested by the client
187    pub size: Size<i32, Logical>,
188    /// Anchor bitflags, describing how the layers surface should be positioned and sized
189    pub anchor: Anchor,
190    /// Descripton of exclusive zone
191    pub exclusive_zone: ExclusiveZone,
192    /// Describes distance from the anchor point of the output
193    pub margin: Margins,
194    /// Describes how keyboard events are delivered to this surface
195    pub keyboard_interactivity: KeyboardInteractivity,
196    /// The layer that the surface is rendered on
197    pub layer: Layer,
198}
199
200impl Cacheable for LayerSurfaceCachedState {
201    fn commit(&mut self, _dh: &DisplayHandle) -> Self {
202        *self
203    }
204    fn merge_into(self, into: &mut Self, _dh: &DisplayHandle) {
205        *into = self;
206    }
207}
208
209/// Shell global state
210///
211/// This state allows you to retrieve a list of surfaces
212/// currently known to the shell global.
213#[derive(Debug, Clone)]
214pub struct WlrLayerShellState {
215    known_layers: Arc<Mutex<Vec<LayerSurface>>>,
216    shell_global: GlobalId,
217}
218
219/// Data associated with a layer shell global
220#[allow(missing_debug_implementations)]
221pub struct WlrLayerShellGlobalData {
222    filter: Box<dyn for<'c> Fn(&'c Client) -> bool + Send + Sync>,
223}
224
225impl WlrLayerShellState {
226    /// Create a new `wlr_layer_shell` global
227    pub fn new<D>(display: &DisplayHandle) -> WlrLayerShellState
228    where
229        D: GlobalDispatch<ZwlrLayerShellV1, WlrLayerShellGlobalData>,
230        D: 'static,
231    {
232        Self::new_with_filter::<D, _>(display, |_| true)
233    }
234
235    /// Create a new `wlr_layer_shell` global with a client filter
236    pub fn new_with_filter<D, F>(display: &DisplayHandle, filter: F) -> WlrLayerShellState
237    where
238        D: GlobalDispatch<ZwlrLayerShellV1, WlrLayerShellGlobalData>,
239        D: 'static,
240        F: for<'c> Fn(&'c Client) -> bool + Send + Sync + 'static,
241    {
242        let shell_global = display.create_global::<D, ZwlrLayerShellV1, WlrLayerShellGlobalData>(
243            4,
244            WlrLayerShellGlobalData {
245                filter: Box::new(filter),
246            },
247        );
248
249        WlrLayerShellState {
250            known_layers: Default::default(),
251            shell_global,
252        }
253    }
254
255    /// Get shell global id
256    pub fn shell_global(&self) -> GlobalId {
257        self.shell_global.clone()
258    }
259
260    /// Access all the shell surfaces known by this handler
261    pub fn layer_surfaces(&self) -> impl DoubleEndedIterator<Item = LayerSurface> {
262        self.known_layers.lock().unwrap().clone().into_iter()
263    }
264}
265
266/// Handler for wlr layer shell
267#[allow(unused_variables)]
268pub trait WlrLayerShellHandler {
269    /// [WlrLayerShellState] getter
270    fn shell_state(&mut self) -> &mut WlrLayerShellState;
271
272    /// A new layer surface was created
273    ///
274    /// You likely need to send a [`LayerSurfaceConfigure`] to the surface, to hint the
275    /// client as to how its layer surface should be sized.
276    fn new_layer_surface(
277        &mut self,
278        surface: LayerSurface,
279        output: Option<WlOutput>,
280        layer: Layer,
281        namespace: String,
282    );
283
284    /// A new popup was assigned a layer surface as it's parent
285    fn new_popup(&mut self, parent: LayerSurface, popup: xdg::PopupSurface) {}
286
287    /// A surface has acknowledged a configure serial.
288    fn ack_configure(&mut self, surface: wl_surface::WlSurface, configure: LayerSurfaceConfigure) {}
289
290    /// A layer surface was destroyed.
291    fn layer_destroyed(&mut self, surface: LayerSurface) {}
292}
293
294/// A handle to a layer surface
295#[derive(Debug, Clone)]
296pub struct LayerSurface {
297    wl_surface: wl_surface::WlSurface,
298    shell_surface: zwlr_layer_surface_v1::ZwlrLayerSurfaceV1,
299}
300
301impl std::cmp::PartialEq for LayerSurface {
302    #[inline]
303    fn eq(&self, other: &Self) -> bool {
304        self.wl_surface == other.wl_surface
305    }
306}
307
308impl LayerSurface {
309    /// Checks if the surface is still alive
310    #[inline]
311    pub fn alive(&self) -> bool {
312        self.wl_surface.alive() && self.shell_surface.alive()
313    }
314
315    /// Gets the current pending state for a configure
316    ///
317    /// Returns `Some` if either no initial configure has been sent or
318    /// the `server_pending` is `Some` and different from the last pending
319    /// configure or `last_acked` if there is no pending
320    ///
321    /// Returns `None` if either no `server_pending` or the pending
322    /// has already been sent to the client or the pending is equal
323    /// to the `last_acked`
324    fn get_pending_state(&self, attributes: &mut LayerSurfaceAttributes) -> Option<LayerSurfaceState> {
325        if !attributes.initial_configure_sent {
326            return Some(
327                attributes
328                    .server_pending
329                    .take()
330                    .unwrap_or_else(|| attributes.current_server_state().clone()),
331            );
332        }
333
334        // Check if the state really changed, it is possible
335        // that with_pending_state has been called without
336        // modifying the state.
337        if !attributes.has_pending_changes() {
338            return None;
339        }
340
341        attributes.server_pending.take()
342    }
343
344    /// Send a pending configure event to this layer surface to suggest it a new configuration
345    ///
346    /// If changes have occurred a configure event will be send to the clients and the serial will be returned
347    /// (for tracking the configure in [`WlrLayerShellHandler::ack_configure`] if desired).
348    /// If no changes occurred no event will be send and `None` will be returned.
349    ///
350    /// See [`send_configure`](LayerSurface::send_configure) and [`has_pending_changes`](LayerSurface::has_pending_changes)
351    /// for more information.
352    pub fn send_pending_configure(&self) -> Option<Serial> {
353        if self.has_pending_changes() {
354            Some(self.send_configure())
355        } else {
356            None
357        }
358    }
359
360    /// Send a configure event to this layer surface to suggest it a new configuration
361    ///
362    /// The serial of this configure will be tracked waiting for the client to ACK it.
363    ///
364    /// You can manipulate the state that will be sent to the client with the [`with_pending_state`](#method.with_pending_state)
365    /// method.
366    ///
367    /// Note: This will always send a configure event, if you intend to only send a configure event on changes take a look at
368    /// [`send_pending_configure`](LayerSurface::send_pending_configure)
369    pub fn send_configure(&self) -> Serial {
370        let configure = compositor::with_states(&self.wl_surface, |states| {
371            let mut attributes = states
372                .data_map
373                .get::<Mutex<LayerSurfaceAttributes>>()
374                .unwrap()
375                .lock()
376                .unwrap();
377
378            let state = self
379                .get_pending_state(&mut attributes)
380                .unwrap_or_else(|| attributes.current_server_state().clone());
381
382            let configure = LayerSurfaceConfigure {
383                serial: SERIAL_COUNTER.next_serial(),
384                state,
385            };
386
387            attributes.pending_configures.push(configure.clone());
388            attributes.initial_configure_sent = true;
389
390            configure
391        });
392
393        // send surface configure
394        let (width, height) = configure.state.size.unwrap_or_default().into();
395        let serial = configure.serial;
396        self.shell_surface
397            .configure(serial.into(), width as u32, height as u32);
398        serial
399    }
400
401    /// Make sure this surface was configured
402    ///
403    /// Returns `true` if it was, if not, returns `false` and raise
404    /// a protocol error to the associated layer surface. Also returns `false`
405    /// if the surface is already destroyed.
406    pub fn ensure_configured(&self) -> bool {
407        let configured = compositor::with_states(&self.wl_surface, |states| {
408            states
409                .data_map
410                .get::<Mutex<LayerSurfaceAttributes>>()
411                .unwrap()
412                .lock()
413                .unwrap()
414                .configured
415        });
416        if !configured {
417            self.shell_surface.post_error(
418                zwlr_layer_shell_v1::Error::AlreadyConstructed,
419                "layer_surface has never been configured",
420            );
421        }
422        configured
423    }
424
425    /// Send a "close" event to the client
426    pub fn send_close(&self) {
427        self.shell_surface.closed()
428    }
429
430    /// Access the underlying `wl_surface` of this layer surface
431    ///
432    /// Returns `None` if the layer surface actually no longer exists.
433    #[inline]
434    pub fn wl_surface(&self) -> &wl_surface::WlSurface {
435        &self.wl_surface
436    }
437
438    /// Allows the pending state of this layer to
439    /// be manipulated.
440    ///
441    /// This should be used to inform the client about size and state changes,
442    /// for example after a resize request from the client.
443    ///
444    /// The state will be sent to the client when calling [`send_configure`](#method.send_configure).
445    pub fn with_pending_state<F, T>(&self, f: F) -> T
446    where
447        F: FnOnce(&mut LayerSurfaceState) -> T,
448    {
449        compositor::with_states(&self.wl_surface, |states| {
450            let mut attributes = states
451                .data_map
452                .get::<Mutex<LayerSurfaceAttributes>>()
453                .unwrap()
454                .lock()
455                .unwrap();
456            if attributes.server_pending.is_none() {
457                attributes.server_pending = Some(attributes.current_server_state().clone());
458            }
459
460            let server_pending = attributes.server_pending.as_mut().unwrap();
461            f(server_pending)
462        })
463    }
464
465    /// Tests this [`LayerSurface`] for pending changes
466    ///
467    /// Returns `true` if [`with_pending_state`](LayerSurface::with_pending_state) was used to manipulate the state
468    /// and resulted in a different state or if the initial configure is still pending.
469    pub fn has_pending_changes(&self) -> bool {
470        compositor::with_states(&self.wl_surface, |states| {
471            let attributes = states
472                .data_map
473                .get::<Mutex<LayerSurfaceAttributes>>()
474                .unwrap()
475                .lock()
476                .unwrap();
477
478            !attributes.initial_configure_sent || attributes.has_pending_changes()
479        })
480    }
481
482    /// Gets a copy of the current state of this layer
483    ///
484    /// Returns `None` if the underlying surface has been
485    /// destroyed
486    pub fn current_state(&self) -> LayerSurfaceState {
487        compositor::with_states(&self.wl_surface, |states| {
488            let attributes = states
489                .data_map
490                .get::<Mutex<LayerSurfaceAttributes>>()
491                .unwrap()
492                .lock()
493                .unwrap();
494
495            attributes.current.clone()
496        })
497    }
498
499    /// Access the underlying `zwlr_layer_surface_v1` of this layer surface
500    ///
501    pub fn shell_surface(&self) -> &zwlr_layer_surface_v1::ZwlrLayerSurfaceV1 {
502        &self.shell_surface
503    }
504}
505
506/// A configure message for layer surfaces
507#[derive(Debug, Clone)]
508pub struct LayerSurfaceConfigure {
509    /// The state associated with this configure
510    pub state: LayerSurfaceState,
511
512    /// A serial number to track ACK from the client
513    ///
514    /// This should be an ever increasing number, as the ACK-ing
515    /// from a client for a serial will validate all pending lower
516    /// serials.
517    pub serial: Serial,
518}
519
520/// Macro to delegate implementation of wlr layer shell to [`WlrLayerShellState`].
521///
522/// You must also implement [`WlrLayerShellHandler`] to use this.
523#[macro_export]
524macro_rules! delegate_layer_shell {
525    ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
526        type __ZwlrLayerShellV1 =
527            $crate::reexports::wayland_protocols_wlr::layer_shell::v1::server::zwlr_layer_shell_v1::ZwlrLayerShellV1;
528        type __ZwlrLayerShellSurfaceV1 =
529            $crate::reexports::wayland_protocols_wlr::layer_shell::v1::server::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1;
530
531        $crate::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
532            __ZwlrLayerShellV1: ()
533        ] => $crate::wayland::shell::wlr_layer::WlrLayerShellState);
534        $crate::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
535            __ZwlrLayerShellSurfaceV1: $crate::wayland::shell::wlr_layer::WlrLayerSurfaceUserData
536        ] => $crate::wayland::shell::wlr_layer::WlrLayerShellState);
537
538        $crate::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
539            __ZwlrLayerShellV1: $crate::wayland::shell::wlr_layer::WlrLayerShellGlobalData
540        ] => $crate::wayland::shell::wlr_layer::WlrLayerShellState);
541    };
542}