1 | mod dispatch; |
2 | |
3 | use std::{ |
4 | convert::TryFrom, |
5 | sync::{Arc, Weak}, |
6 | }; |
7 | |
8 | use bitflags::bitflags; |
9 | use wayland_client::{ |
10 | globals::{BindError, GlobalList}, |
11 | protocol::{wl_output, wl_surface}, |
12 | Connection, Dispatch, Proxy, QueueHandle, |
13 | }; |
14 | use wayland_protocols::xdg::shell::client::xdg_popup::XdgPopup; |
15 | use wayland_protocols_wlr::layer_shell::v1::client::{zwlr_layer_shell_v1, zwlr_layer_surface_v1}; |
16 | |
17 | use crate::{compositor::Surface, globals::GlobalData}; |
18 | |
19 | use super::WaylandSurface; |
20 | |
21 | #[derive (Debug)] |
22 | pub struct LayerShell { |
23 | wlr_layer_shell: zwlr_layer_shell_v1::ZwlrLayerShellV1, |
24 | } |
25 | |
26 | impl 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`] |
81 | pub 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)] |
102 | pub struct LayerSurface(Arc<LayerSurfaceInner>); |
103 | |
104 | impl PartialEq for LayerSurface { |
105 | fn eq(&self, other: &Self) -> bool { |
106 | Arc::ptr_eq(&self.0, &other.0) |
107 | } |
108 | } |
109 | |
110 | impl 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 | |
169 | impl 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)] |
177 | pub enum SurfaceKind { |
178 | Wlr(zwlr_layer_surface_v1::ZwlrLayerSurfaceV1), |
179 | } |
180 | |
181 | #[non_exhaustive ] |
182 | #[derive (Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] |
183 | pub enum KeyboardInteractivity { |
184 | /// No keyboard focus is possible. |
185 | /// |
186 | /// This is the default value for all newly created layer shells. |
187 | None, |
188 | |
189 | /// Request exclusive keyboard focus if the layer is above shell surfaces. |
190 | /// |
191 | /// For [`Layer::Top`] and [`Layer::Overlay`], the seat will always give exclusive access to the layer |
192 | /// which has this interactivity mode set. |
193 | /// |
194 | /// This setting is intended for applications that need to ensure they receive all keyboard events, such |
195 | /// as a lock screen or a password prompt. |
196 | Exclusive, |
197 | |
198 | /// The compositor should focus and unfocus this surface by the user in an implementation specific manner. |
199 | /// |
200 | /// Compositors may use their normal mechanisms to manage keyboard focus between layers and regular |
201 | /// desktop surfaces. |
202 | /// |
203 | /// This setting is intended for applications which allow keyboard interaction. |
204 | OnDemand, |
205 | } |
206 | |
207 | impl Default for KeyboardInteractivity { |
208 | fn default() -> Self { |
209 | Self::None |
210 | } |
211 | } |
212 | |
213 | /// The z-depth of a layer. |
214 | /// |
215 | /// These values indicate which order in which layer surfaces are rendered. |
216 | #[non_exhaustive ] |
217 | #[derive (Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] |
218 | pub enum Layer { |
219 | Background, |
220 | |
221 | Bottom, |
222 | |
223 | Top, |
224 | |
225 | Overlay, |
226 | } |
227 | |
228 | /// Error when converting a [`zwlr_layer_shell_v1::Layer`] to a [`Layer`] |
229 | #[derive (Debug, thiserror::Error)] |
230 | #[error("unknown layer" )] |
231 | pub struct UnknownLayer; |
232 | |
233 | bitflags! { |
234 | /// Specifies which edges and corners a layer should be placed at in the anchor rectangle. |
235 | /// |
236 | /// A combination of two orthogonal edges will cause the layer's anchor point to be the intersection of |
237 | /// the edges. For example [`Anchor::TOP`] and [`Anchor::LEFT`] will result in an anchor point in the top |
238 | /// left of the anchor rectangle. |
239 | #[derive (Debug, Clone, Copy, PartialEq, Eq, Hash)] |
240 | pub struct Anchor: u32 { |
241 | /// Top edge of the anchor rectangle. |
242 | const TOP = 1; |
243 | |
244 | /// The bottom edge of the anchor rectangle. |
245 | const BOTTOM = 2; |
246 | |
247 | /// The left edge of the anchor rectangle. |
248 | const LEFT = 4; |
249 | |
250 | /// The right edge of the anchor rectangle. |
251 | const RIGHT = 8; |
252 | } |
253 | } |
254 | |
255 | /// A layer surface configure. |
256 | /// |
257 | /// A configure describes a compositor request to resize the layer surface or change it's state. |
258 | #[non_exhaustive ] |
259 | #[derive (Debug, Clone)] |
260 | pub struct LayerSurfaceConfigure { |
261 | /// The compositor suggested new size of the layer in surface-local coordinates. |
262 | /// |
263 | /// The size is a hint, meaning the new size can be ignored. A smaller size could be picked to satisfy |
264 | /// some aspect ratio or resize in steps. If the size is smaller than suggested and the layer surface is |
265 | /// anchored to two opposite anchors then the layer surface will be centered on that axis. |
266 | /// |
267 | /// If the width is zero, you may choose any width you want. If the height is zero, you may choose any |
268 | /// height you want. |
269 | pub new_size: (u32, u32), |
270 | } |
271 | |
272 | #[derive (Debug)] |
273 | pub struct LayerSurfaceData { |
274 | inner: Weak<LayerSurfaceInner>, |
275 | } |
276 | |
277 | impl LayerSurfaceData { |
278 | pub fn layer_surface(&self) -> Option<LayerSurface> { |
279 | self.inner.upgrade().map(LayerSurface) |
280 | } |
281 | } |
282 | |
283 | #[macro_export ] |
284 | macro_rules! delegate_layer { |
285 | ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => { |
286 | $crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ |
287 | $crate::reexports::protocols_wlr::layer_shell::v1::client::zwlr_layer_shell_v1::ZwlrLayerShellV1: $crate::globals::GlobalData |
288 | ] => $crate::shell::wlr_layer::LayerShell); |
289 | $crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ |
290 | $crate::reexports::protocols_wlr::layer_shell::v1::client::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1: $crate::shell::wlr_layer::LayerSurfaceData |
291 | ] => $crate::shell::wlr_layer::LayerShell); |
292 | }; |
293 | } |
294 | |
295 | #[derive (Debug)] |
296 | struct LayerSurfaceInner { |
297 | wl_surface: Surface, |
298 | kind: SurfaceKind, |
299 | } |
300 | |
301 | impl TryFrom<zwlr_layer_shell_v1::Layer> for Layer { |
302 | type Error = UnknownLayer; |
303 | |
304 | fn try_from(layer: zwlr_layer_shell_v1::Layer) -> Result<Self, Self::Error> { |
305 | match layer { |
306 | zwlr_layer_shell_v1::Layer::Background => Ok(Self::Background), |
307 | zwlr_layer_shell_v1::Layer::Bottom => Ok(Self::Bottom), |
308 | zwlr_layer_shell_v1::Layer::Top => Ok(Self::Top), |
309 | zwlr_layer_shell_v1::Layer::Overlay => Ok(Self::Overlay), |
310 | _ => Err(UnknownLayer), |
311 | } |
312 | } |
313 | } |
314 | |
315 | impl From<Layer> for zwlr_layer_shell_v1::Layer { |
316 | fn from(depth: Layer) -> Self { |
317 | match depth { |
318 | Layer::Background => Self::Background, |
319 | Layer::Bottom => Self::Bottom, |
320 | Layer::Top => Self::Top, |
321 | Layer::Overlay => Self::Overlay, |
322 | } |
323 | } |
324 | } |
325 | |
326 | impl From<KeyboardInteractivity> for zwlr_layer_surface_v1::KeyboardInteractivity { |
327 | fn from(interactivity: KeyboardInteractivity) -> Self { |
328 | match interactivity { |
329 | KeyboardInteractivity::None => zwlr_layer_surface_v1::KeyboardInteractivity::None, |
330 | KeyboardInteractivity::Exclusive => { |
331 | zwlr_layer_surface_v1::KeyboardInteractivity::Exclusive |
332 | } |
333 | KeyboardInteractivity::OnDemand => { |
334 | zwlr_layer_surface_v1::KeyboardInteractivity::OnDemand |
335 | } |
336 | } |
337 | } |
338 | } |
339 | |
340 | impl Drop for LayerSurfaceInner { |
341 | fn drop(&mut self) { |
342 | // Layer shell protocol dictates we must destroy the role object before the surface. |
343 | match self.kind { |
344 | SurfaceKind::Wlr(ref wlr: &{unknown}) => wlr.destroy(), |
345 | } |
346 | |
347 | // Surface will destroy the wl_surface |
348 | // self.wl_surface.destroy(); |
349 | } |
350 | } |
351 | |