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//! ```
4748use std::sync::{Arc, Mutex};
4950use 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};
5960use crate::{
61 utils::{alive_tracker::IsAlive, Logical, Serial, Size, SERIAL_COUNTER},
62 wayland::{
63 compositor::{self, Cacheable},
64 shell::xdg,
65 },
66};
6768mod handlers;
69mod types;
7071pub use handlers::WlrLayerSurfaceUserData;
72pub use types::{Anchor, ExclusiveZone, KeyboardInteractivity, Layer, Margins};
7374/// The role of a wlr_layer_shell_surface
75pub const LAYER_SURFACE_ROLE: &str = "zwlr_layer_surface_v1";
7677/// 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>;
8990/// 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
96pub configured: bool,
97/// The serial of the last acked configure
98pub 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
103pub 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.
109pending_configures: Vec<LayerSurfaceConfigure>,
110/// Holds the pending state as set by the server.
111pub 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.
115pub last_acked: Option<LayerSurfaceState>,
116/// Holds the current state of the layer after a successful
117 /// commit.
118pub current: LayerSurfaceState,
119}
120121impl LayerSurfaceAttributes {
122fn new(surface: zwlr_layer_surface_v1::ZwlrLayerSurfaceV1) -> Self {
123Self {
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 }
134135fn ack_configure(&mut self, serial: Serial) -> Option<LayerSurfaceConfigure> {
136let configure = self
137.pending_configures
138 .iter()
139 .find(|configure| configure.serial == serial)
140 .cloned()?;
141142self.last_acked = Some(configure.state.clone());
143144self.configured = true;
145self.configure_serial = Some(serial);
146self.pending_configures.retain(|c| c.serial > serial);
147Some(configure)
148 }
149150fn reset(&mut self) {
151self.configured = false;
152self.configure_serial = None;
153self.initial_configure_sent = false;
154self.pending_configures = Vec::new();
155self.server_pending = None;
156self.last_acked = None;
157self.current = Default::default();
158 }
159160fn current_server_state(&self) -> &LayerSurfaceState {
161self.pending_configures
162 .last()
163 .map(|c| &c.state)
164 .or(self.last_acked.as_ref())
165 .unwrap_or(&self.current)
166 }
167168fn has_pending_changes(&self) -> bool {
169self.server_pending
170 .as_ref()
171 .map(|s| s != self.current_server_state())
172 .unwrap_or(false)
173 }
174}
175176/// State of a layer surface
177#[derive(Debug, Default, Clone, PartialEq, Eq)]
178pub struct LayerSurfaceState {
179/// The suggested size of the surface
180pub size: Option<Size<i32, Logical>>,
181}
182183/// Represents the client pending state
184#[derive(Debug, Default, Clone, Copy)]
185pub struct LayerSurfaceCachedState {
186/// The size requested by the client
187pub size: Size<i32, Logical>,
188/// Anchor bitflags, describing how the layers surface should be positioned and sized
189pub anchor: Anchor,
190/// Descripton of exclusive zone
191pub exclusive_zone: ExclusiveZone,
192/// Describes distance from the anchor point of the output
193pub margin: Margins,
194/// Describes how keyboard events are delivered to this surface
195pub keyboard_interactivity: KeyboardInteractivity,
196/// The layer that the surface is rendered on
197pub layer: Layer,
198}
199200impl Cacheable for LayerSurfaceCachedState {
201fn commit(&mut self, _dh: &DisplayHandle) -> Self {
202*self
203}
204fn merge_into(self, into: &mut Self, _dh: &DisplayHandle) {
205*into = self;
206 }
207}
208209/// 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}
218219/// 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}
224225impl WlrLayerShellState {
226/// Create a new `wlr_layer_shell` global
227pub fn new<D>(display: &DisplayHandle) -> WlrLayerShellState
228where
229D: GlobalDispatch<ZwlrLayerShellV1, WlrLayerShellGlobalData>,
230 D: 'static,
231 {
232Self::new_with_filter::<D, _>(display, |_| true)
233 }
234235/// Create a new `wlr_layer_shell` global with a client filter
236pub fn new_with_filter<D, F>(display: &DisplayHandle, filter: F) -> WlrLayerShellState
237where
238D: GlobalDispatch<ZwlrLayerShellV1, WlrLayerShellGlobalData>,
239 D: 'static,
240 F: for<'c> Fn(&'c Client) -> bool + Send + Sync + 'static,
241 {
242let shell_global = display.create_global::<D, ZwlrLayerShellV1, WlrLayerShellGlobalData>(
2434,
244 WlrLayerShellGlobalData {
245 filter: Box::new(filter),
246 },
247 );
248249 WlrLayerShellState {
250 known_layers: Default::default(),
251 shell_global,
252 }
253 }
254255/// Get shell global id
256pub fn shell_global(&self) -> GlobalId {
257self.shell_global.clone()
258 }
259260/// Access all the shell surfaces known by this handler
261pub fn layer_surfaces(&self) -> impl DoubleEndedIterator<Item = LayerSurface> {
262self.known_layers.lock().unwrap().clone().into_iter()
263 }
264}
265266/// Handler for wlr layer shell
267#[allow(unused_variables)]
268pub trait WlrLayerShellHandler {
269/// [WlrLayerShellState] getter
270fn shell_state(&mut self) -> &mut WlrLayerShellState;
271272/// 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.
276fn new_layer_surface(
277&mut self,
278 surface: LayerSurface,
279 output: Option<WlOutput>,
280 layer: Layer,
281 namespace: String,
282 );
283284/// A new popup was assigned a layer surface as it's parent
285fn new_popup(&mut self, parent: LayerSurface, popup: xdg::PopupSurface) {}
286287/// A surface has acknowledged a configure serial.
288fn ack_configure(&mut self, surface: wl_surface::WlSurface, configure: LayerSurfaceConfigure) {}
289290/// A layer surface was destroyed.
291fn layer_destroyed(&mut self, surface: LayerSurface) {}
292}
293294/// 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}
300301impl std::cmp::PartialEq for LayerSurface {
302#[inline]
303fn eq(&self, other: &Self) -> bool {
304self.wl_surface == other.wl_surface
305 }
306}
307308impl LayerSurface {
309/// Checks if the surface is still alive
310#[inline]
311pub fn alive(&self) -> bool {
312self.wl_surface.alive() && self.shell_surface.alive()
313 }
314315/// 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`
324fn get_pending_state(&self, attributes: &mut LayerSurfaceAttributes) -> Option<LayerSurfaceState> {
325if !attributes.initial_configure_sent {
326return Some(
327 attributes
328 .server_pending
329 .take()
330 .unwrap_or_else(|| attributes.current_server_state().clone()),
331 );
332 }
333334// Check if the state really changed, it is possible
335 // that with_pending_state has been called without
336 // modifying the state.
337if !attributes.has_pending_changes() {
338return None;
339 }
340341 attributes.server_pending.take()
342 }
343344/// 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.
352pub fn send_pending_configure(&self) -> Option<Serial> {
353if self.has_pending_changes() {
354Some(self.send_configure())
355 } else {
356None
357}
358 }
359360/// 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)
369pub fn send_configure(&self) -> Serial {
370let configure = compositor::with_states(&self.wl_surface, |states| {
371let mut attributes = states
372 .data_map
373 .get::<Mutex<LayerSurfaceAttributes>>()
374 .unwrap()
375 .lock()
376 .unwrap();
377378let state = self
379.get_pending_state(&mut attributes)
380 .unwrap_or_else(|| attributes.current_server_state().clone());
381382let configure = LayerSurfaceConfigure {
383 serial: SERIAL_COUNTER.next_serial(),
384 state,
385 };
386387 attributes.pending_configures.push(configure.clone());
388 attributes.initial_configure_sent = true;
389390 configure
391 });
392393// send surface configure
394let (width, height) = configure.state.size.unwrap_or_default().into();
395let serial = configure.serial;
396self.shell_surface
397 .configure(serial.into(), width as u32, height as u32);
398 serial
399 }
400401/// 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.
406pub fn ensure_configured(&self) -> bool {
407let 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 });
416if !configured {
417self.shell_surface.post_error(
418 zwlr_layer_shell_v1::Error::AlreadyConstructed,
419"layer_surface has never been configured",
420 );
421 }
422 configured
423 }
424425/// Send a "close" event to the client
426pub fn send_close(&self) {
427self.shell_surface.closed()
428 }
429430/// Access the underlying `wl_surface` of this layer surface
431 ///
432 /// Returns `None` if the layer surface actually no longer exists.
433#[inline]
434pub fn wl_surface(&self) -> &wl_surface::WlSurface {
435&self.wl_surface
436 }
437438/// 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).
445pub fn with_pending_state<F, T>(&self, f: F) -> T
446where
447F: FnOnce(&mut LayerSurfaceState) -> T,
448 {
449 compositor::with_states(&self.wl_surface, |states| {
450let mut attributes = states
451 .data_map
452 .get::<Mutex<LayerSurfaceAttributes>>()
453 .unwrap()
454 .lock()
455 .unwrap();
456if attributes.server_pending.is_none() {
457 attributes.server_pending = Some(attributes.current_server_state().clone());
458 }
459460let server_pending = attributes.server_pending.as_mut().unwrap();
461 f(server_pending)
462 })
463 }
464465/// 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.
469pub fn has_pending_changes(&self) -> bool {
470 compositor::with_states(&self.wl_surface, |states| {
471let attributes = states
472 .data_map
473 .get::<Mutex<LayerSurfaceAttributes>>()
474 .unwrap()
475 .lock()
476 .unwrap();
477478 !attributes.initial_configure_sent || attributes.has_pending_changes()
479 })
480 }
481482/// Gets a copy of the current state of this layer
483 ///
484 /// Returns `None` if the underlying surface has been
485 /// destroyed
486pub fn current_state(&self) -> LayerSurfaceState {
487 compositor::with_states(&self.wl_surface, |states| {
488let attributes = states
489 .data_map
490 .get::<Mutex<LayerSurfaceAttributes>>()
491 .unwrap()
492 .lock()
493 .unwrap();
494495 attributes.current.clone()
496 })
497 }
498499/// Access the underlying `zwlr_layer_surface_v1` of this layer surface
500 ///
501pub fn shell_surface(&self) -> &zwlr_layer_surface_v1::ZwlrLayerSurfaceV1 {
502&self.shell_surface
503 }
504}
505506/// A configure message for layer surfaces
507#[derive(Debug, Clone)]
508pub struct LayerSurfaceConfigure {
509/// The state associated with this configure
510pub state: LayerSurfaceState,
511512/// 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.
517pub serial: Serial,
518}
519520/// 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) => {
526type __ZwlrLayerShellV1 =
527$crate::reexports::wayland_protocols_wlr::layer_shell::v1::server::zwlr_layer_shell_v1::ZwlrLayerShellV1;
528type __ZwlrLayerShellSurfaceV1 =
529$crate::reexports::wayland_protocols_wlr::layer_shell::v1::server::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1;
530531$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);
537538$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}