⚠️ VeridianOS Kernel Documentation - This is low-level kernel code. All functions are unsafe unless explicitly marked otherwise. no_std

veridian_kernel/desktop/wayland/
layer_shell.rs

1//! Layer Shell Protocol (zwlr_layer_shell_v1)
2//!
3//! Provides surfaces anchored to screen edges for panels, notifications,
4//! screen locks, and overlays. Based on wlr-layer-shell-unstable-v1.
5//!
6//! Layer surfaces are positioned relative to the output edges using anchor
7//! flags and can claim exclusive zones that reduce the usable area for
8//! normal windows. The rendering order from bottom to top is:
9//!
10//!   Background -> Bottom -> Top -> Overlay
11//!
12//! This ensures that overlay surfaces (screen locks) always appear above
13//! everything, while background surfaces (wallpaper) sit behind all windows.
14
15#![allow(dead_code)]
16
17use alloc::{collections::BTreeMap, vec::Vec};
18
19use crate::error::KernelError;
20
21// ---------------------------------------------------------------------------
22// Layer shell protocol constants
23// ---------------------------------------------------------------------------
24
25/// Wayland global interface name for layer shell
26pub const ZWLR_LAYER_SHELL_V1: &str = "zwlr_layer_shell_v1";
27
28/// Protocol version
29pub const ZWLR_LAYER_SHELL_V1_VERSION: u32 = 4;
30
31// Layer shell request opcodes
32/// get_layer_surface(id, surface, output, layer, namespace)
33pub const ZWLR_LAYER_SHELL_V1_GET_LAYER_SURFACE: u16 = 0;
34/// destroy
35pub const ZWLR_LAYER_SHELL_V1_DESTROY: u16 = 1;
36
37// Layer surface request opcodes
38/// set_size(width, height)
39pub const ZWLR_LAYER_SURFACE_V1_SET_SIZE: u16 = 0;
40/// set_anchor(anchor)
41pub const ZWLR_LAYER_SURFACE_V1_SET_ANCHOR: u16 = 1;
42/// set_exclusive_zone(zone)
43pub const ZWLR_LAYER_SURFACE_V1_SET_EXCLUSIVE_ZONE: u16 = 2;
44/// set_margin(top, right, bottom, left)
45pub const ZWLR_LAYER_SURFACE_V1_SET_MARGIN: u16 = 3;
46/// set_keyboard_interactivity(mode)
47pub const ZWLR_LAYER_SURFACE_V1_SET_KEYBOARD_INTERACTIVITY: u16 = 4;
48/// get_popup(popup)
49pub const ZWLR_LAYER_SURFACE_V1_GET_POPUP: u16 = 5;
50/// ack_configure(serial)
51pub const ZWLR_LAYER_SURFACE_V1_ACK_CONFIGURE: u16 = 6;
52/// destroy
53pub const ZWLR_LAYER_SURFACE_V1_DESTROY: u16 = 7;
54/// set_layer(layer) -- since version 2
55pub const ZWLR_LAYER_SURFACE_V1_SET_LAYER: u16 = 8;
56
57// Layer surface event opcodes
58/// configure(serial, width, height)
59pub const ZWLR_LAYER_SURFACE_V1_CONFIGURE: u16 = 0;
60/// closed
61pub const ZWLR_LAYER_SURFACE_V1_CLOSED: u16 = 1;
62
63// ---------------------------------------------------------------------------
64// Types
65// ---------------------------------------------------------------------------
66
67/// Layer shell layers (bottom to top rendering order).
68///
69/// Surfaces in higher layers are always rendered above surfaces in lower
70/// layers. Normal windows sit between Bottom and Top.
71#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
72#[repr(u32)]
73pub enum Layer {
74    /// Below all windows (e.g., desktop wallpaper)
75    Background = 0,
76    /// Below normal windows but above background (e.g., bottom panels)
77    Bottom = 1,
78    /// Above normal windows (e.g., top panels, notification popups)
79    Top = 2,
80    /// Above everything including fullscreen (e.g., screen lock, OSD)
81    Overlay = 3,
82}
83
84impl Layer {
85    /// Convert a raw protocol value to a Layer.
86    pub fn from_u32(value: u32) -> Option<Self> {
87        match value {
88            0 => Some(Self::Background),
89            1 => Some(Self::Bottom),
90            2 => Some(Self::Top),
91            3 => Some(Self::Overlay),
92            _ => None,
93        }
94    }
95}
96
97/// Anchor edges for layer surface positioning.
98///
99/// When opposite edges are anchored (e.g., left + right), the surface
100/// stretches to fill that axis. When only one edge is anchored, the
101/// surface is placed at that edge with its requested size.
102#[derive(Debug, Clone, Copy, PartialEq, Eq)]
103pub struct Anchor {
104    pub top: bool,
105    pub bottom: bool,
106    pub left: bool,
107    pub right: bool,
108}
109
110impl Anchor {
111    /// Create an Anchor with no edges set.
112    pub fn none() -> Self {
113        Self {
114            top: false,
115            bottom: false,
116            left: false,
117            right: false,
118        }
119    }
120
121    /// Create an Anchor from a bitfield (protocol wire format).
122    ///
123    /// Bit 0 = top, bit 1 = bottom, bit 2 = left, bit 3 = right.
124    pub fn from_bits(bits: u32) -> Self {
125        Self {
126            top: bits & 1 != 0,
127            bottom: bits & 2 != 0,
128            left: bits & 4 != 0,
129            right: bits & 8 != 0,
130        }
131    }
132
133    /// Convert to bitfield representation.
134    pub fn to_bits(&self) -> u32 {
135        let mut bits = 0u32;
136        if self.top {
137            bits |= 1;
138        }
139        if self.bottom {
140            bits |= 2;
141        }
142        if self.left {
143            bits |= 4;
144        }
145        if self.right {
146            bits |= 8;
147        }
148        bits
149    }
150
151    /// Whether this anchor stretches horizontally (left + right).
152    pub fn stretches_horizontal(&self) -> bool {
153        self.left && self.right
154    }
155
156    /// Whether this anchor stretches vertically (top + bottom).
157    pub fn stretches_vertical(&self) -> bool {
158        self.top && self.bottom
159    }
160}
161
162/// Keyboard interactivity mode for layer surfaces.
163#[derive(Debug, Clone, Copy, PartialEq, Eq)]
164#[repr(u32)]
165pub enum KeyboardInteractivity {
166    /// Surface does not receive keyboard events
167    None = 0,
168    /// Surface grabs keyboard focus exclusively (e.g., screen lock)
169    Exclusive = 1,
170    /// Surface receives keyboard focus on demand (e.g., when clicked)
171    OnDemand = 2,
172}
173
174impl KeyboardInteractivity {
175    /// Convert from raw protocol value.
176    pub fn from_u32(value: u32) -> Option<Self> {
177        match value {
178            0 => Some(Self::None),
179            1 => Some(Self::Exclusive),
180            2 => Some(Self::OnDemand),
181            _ => None,
182        }
183    }
184}
185
186// ---------------------------------------------------------------------------
187// Layer surface
188// ---------------------------------------------------------------------------
189
190/// Layer surface configuration.
191///
192/// A layer surface is a surface that is anchored to screen edges and
193/// belongs to a specific rendering layer. It can claim an exclusive zone
194/// to prevent normal windows from occupying that screen area.
195pub struct LayerSurface {
196    /// Layer surface object ID
197    pub id: u32,
198    /// Underlying compositor surface ID
199    pub surface_id: u32,
200    /// Which layer this surface belongs to
201    pub layer: Layer,
202    /// Which screen edges the surface is anchored to
203    pub anchor: Anchor,
204    /// Exclusive zone in pixels (-1 = no exclusive zone, 0+ = reserve space)
205    pub exclusive_zone: i32,
206    /// Margin from top edge in pixels
207    pub margin_top: i32,
208    /// Margin from bottom edge in pixels
209    pub margin_bottom: i32,
210    /// Margin from left edge in pixels
211    pub margin_left: i32,
212    /// Margin from right edge in pixels
213    pub margin_right: i32,
214    /// Keyboard focus mode
215    pub keyboard_interactivity: KeyboardInteractivity,
216    /// Requested width (0 = fill available width when anchored)
217    pub desired_width: u32,
218    /// Requested height (0 = fill available height when anchored)
219    pub desired_height: u32,
220    /// Actual configured width (assigned by compositor)
221    pub actual_width: u32,
222    /// Actual configured height (assigned by compositor)
223    pub actual_height: u32,
224    /// Namespace for grouping (e.g., "panel", "notifications", "wallpaper")
225    pub namespace: [u8; 64],
226    /// Length of the namespace string
227    pub namespace_len: usize,
228    /// Whether the client has acknowledged the latest configure
229    pub configured: bool,
230    /// Last configure serial sent to client
231    pub configure_serial: u32,
232    /// Whether the surface is currently mapped (has a buffer and is visible)
233    pub mapped: bool,
234}
235
236impl LayerSurface {
237    /// Create a new layer surface with default settings.
238    pub fn new(id: u32, surface_id: u32, layer: Layer) -> Self {
239        Self {
240            id,
241            surface_id,
242            layer,
243            anchor: Anchor::none(),
244            exclusive_zone: 0,
245            margin_top: 0,
246            margin_bottom: 0,
247            margin_left: 0,
248            margin_right: 0,
249            keyboard_interactivity: KeyboardInteractivity::None,
250            desired_width: 0,
251            desired_height: 0,
252            actual_width: 0,
253            actual_height: 0,
254            namespace: [0u8; 64],
255            namespace_len: 0,
256            configured: false,
257            configure_serial: 0,
258            mapped: false,
259        }
260    }
261
262    /// Set the namespace string for this layer surface.
263    pub fn set_namespace(&mut self, ns: &[u8]) {
264        let copy_len = ns.len().min(self.namespace.len());
265        self.namespace[..copy_len].copy_from_slice(&ns[..copy_len]);
266        self.namespace_len = copy_len;
267    }
268
269    /// Get the namespace as a byte slice.
270    pub fn namespace_bytes(&self) -> &[u8] {
271        &self.namespace[..self.namespace_len]
272    }
273}
274
275// ---------------------------------------------------------------------------
276// Layer shell manager
277// ---------------------------------------------------------------------------
278
279/// Usable screen area after exclusive zones are subtracted.
280#[derive(Debug, Clone, Copy, PartialEq, Eq)]
281pub struct UsableArea {
282    pub x: i32,
283    pub y: i32,
284    pub width: u32,
285    pub height: u32,
286}
287
288/// Layer shell manager.
289///
290/// Tracks all layer surfaces and computes exclusive zones for the output.
291pub struct LayerShellManager {
292    /// All layer surfaces keyed by their object ID
293    surfaces: BTreeMap<u32, LayerSurface>,
294    /// Next layer surface ID
295    next_id: u32,
296    /// Next configure serial
297    next_serial: u32,
298}
299
300impl LayerShellManager {
301    /// Create a new layer shell manager.
302    pub fn new() -> Self {
303        Self {
304            surfaces: BTreeMap::new(),
305            next_id: 1,
306            next_serial: 1,
307        }
308    }
309
310    /// Allocate the next serial number.
311    fn alloc_serial(&mut self) -> u32 {
312        let s = self.next_serial;
313        self.next_serial += 1;
314        s
315    }
316
317    /// Create a new layer surface.
318    ///
319    /// Returns the layer surface ID assigned by the manager.
320    pub fn create_surface(
321        &mut self,
322        surface_id: u32,
323        layer: Layer,
324        namespace: &[u8],
325    ) -> Result<u32, KernelError> {
326        let id = self.next_id;
327        self.next_id += 1;
328
329        let mut ls = LayerSurface::new(id, surface_id, layer);
330        ls.set_namespace(namespace);
331
332        self.surfaces.insert(id, ls);
333        Ok(id)
334    }
335
336    /// Destroy a layer surface.
337    pub fn destroy_surface(&mut self, id: u32) -> Result<(), KernelError> {
338        self.surfaces.remove(&id).ok_or(KernelError::NotFound {
339            resource: "layer_surface",
340            id: id as u64,
341        })?;
342        Ok(())
343    }
344
345    /// Get a reference to a layer surface.
346    pub fn get_surface(&self, id: u32) -> Option<&LayerSurface> {
347        self.surfaces.get(&id)
348    }
349
350    /// Get a mutable reference to a layer surface.
351    pub fn get_surface_mut(&mut self, id: u32) -> Option<&mut LayerSurface> {
352        self.surfaces.get_mut(&id)
353    }
354
355    /// Configure a layer surface with its actual dimensions and send a
356    /// configure serial to the client.
357    ///
358    /// Returns the serial number to be sent in the configure event.
359    pub fn configure_surface(
360        &mut self,
361        id: u32,
362        width: u32,
363        height: u32,
364    ) -> Result<u32, KernelError> {
365        let serial = self.alloc_serial();
366
367        let ls = self.surfaces.get_mut(&id).ok_or(KernelError::NotFound {
368            resource: "layer_surface",
369            id: id as u64,
370        })?;
371
372        ls.actual_width = width;
373        ls.actual_height = height;
374        ls.configure_serial = serial;
375        ls.configured = false;
376
377        Ok(serial)
378    }
379
380    /// Handle ack_configure from the client.
381    pub fn ack_configure(&mut self, id: u32, serial: u32) -> bool {
382        if let Some(ls) = self.surfaces.get_mut(&id) {
383            if ls.configure_serial == serial {
384                ls.configured = true;
385                return true;
386            }
387        }
388        false
389    }
390
391    /// Get all layer surfaces belonging to a specific layer, sorted by
392    /// creation order.
393    pub fn get_surfaces_for_layer(&self, layer: Layer) -> Vec<&LayerSurface> {
394        self.surfaces
395            .values()
396            .filter(|ls| ls.layer == layer)
397            .collect()
398    }
399
400    /// Calculate the total exclusive zone offsets for an output.
401    ///
402    /// Returns (top, bottom, left, right) pixel offsets that normal
403    /// windows should respect.
404    pub fn calculate_exclusive_zones(&self) -> (i32, i32, i32, i32) {
405        let mut top = 0i32;
406        let mut bottom = 0i32;
407        let mut left = 0i32;
408        let mut right = 0i32;
409
410        for ls in self.surfaces.values() {
411            if ls.exclusive_zone <= 0 || !ls.mapped {
412                continue;
413            }
414
415            let zone = ls.exclusive_zone;
416
417            // Determine which edge the exclusive zone applies to based on
418            // the anchor configuration.
419            if ls.anchor.top && !ls.anchor.bottom {
420                // Anchored to top only -> reserves top space
421                top = top.max(zone + ls.margin_top);
422            } else if ls.anchor.bottom && !ls.anchor.top {
423                // Anchored to bottom only -> reserves bottom space
424                bottom = bottom.max(zone + ls.margin_bottom);
425            } else if ls.anchor.left && !ls.anchor.right {
426                // Anchored to left only -> reserves left space
427                left = left.max(zone + ls.margin_left);
428            } else if ls.anchor.right && !ls.anchor.left {
429                // Anchored to right only -> reserves right space
430                right = right.max(zone + ls.margin_right);
431            } else if ls.anchor.top && ls.anchor.bottom {
432                // Vertically stretched -- exclusive zone applies to the
433                // narrowest horizontal anchor
434                if ls.anchor.left && !ls.anchor.right {
435                    left = left.max(zone + ls.margin_left);
436                } else if ls.anchor.right && !ls.anchor.left {
437                    right = right.max(zone + ls.margin_right);
438                }
439            } else if ls.anchor.left && ls.anchor.right {
440                // Horizontally stretched -- exclusive zone applies to the
441                // narrowest vertical anchor
442                if ls.anchor.top && !ls.anchor.bottom {
443                    top = top.max(zone + ls.margin_top);
444                } else if ls.anchor.bottom && !ls.anchor.top {
445                    bottom = bottom.max(zone + ls.margin_bottom);
446                }
447            }
448        }
449
450        (top, bottom, left, right)
451    }
452
453    /// Compute the usable area after subtracting all exclusive zones from
454    /// the full output dimensions.
455    pub fn get_usable_area(&self, output_width: u32, output_height: u32) -> UsableArea {
456        let (top, bottom, left, right) = self.calculate_exclusive_zones();
457
458        let x = left;
459        let y = top;
460        let w = (output_width as i32 - left - right).max(0) as u32;
461        let h = (output_height as i32 - top - bottom).max(0) as u32;
462
463        UsableArea {
464            x,
465            y,
466            width: w,
467            height: h,
468        }
469    }
470
471    /// Return the total number of layer surfaces.
472    pub fn surface_count(&self) -> usize {
473        self.surfaces.len()
474    }
475}
476
477impl Default for LayerShellManager {
478    fn default() -> Self {
479        Self::new()
480    }
481}
482
483// ---------------------------------------------------------------------------
484// Tests
485// ---------------------------------------------------------------------------
486
487#[cfg(test)]
488mod tests {
489    use super::*;
490
491    #[test]
492    fn test_layer_ordering() {
493        assert!(Layer::Background < Layer::Bottom);
494        assert!(Layer::Bottom < Layer::Top);
495        assert!(Layer::Top < Layer::Overlay);
496    }
497
498    #[test]
499    fn test_anchor_from_bits() {
500        let a = Anchor::from_bits(0b1111);
501        assert!(a.top && a.bottom && a.left && a.right);
502
503        let b = Anchor::from_bits(0b0001);
504        assert!(b.top && !b.bottom && !b.left && !b.right);
505
506        let c = Anchor::from_bits(0);
507        assert!(!c.top && !c.bottom && !c.left && !c.right);
508    }
509
510    #[test]
511    fn test_anchor_roundtrip() {
512        let a = Anchor {
513            top: true,
514            bottom: false,
515            left: true,
516            right: false,
517        };
518        let bits = a.to_bits();
519        let b = Anchor::from_bits(bits);
520        assert_eq!(a, b);
521    }
522
523    #[test]
524    fn test_layer_surface_creation() {
525        let mut mgr = LayerShellManager::new();
526        let id = mgr.create_surface(10, Layer::Top, b"panel").unwrap();
527        assert_eq!(mgr.surface_count(), 1);
528
529        let ls = mgr.get_surface(id).unwrap();
530        assert_eq!(ls.surface_id, 10);
531        assert_eq!(ls.layer, Layer::Top);
532        assert_eq!(ls.namespace_bytes(), b"panel");
533    }
534
535    #[test]
536    fn test_layer_surface_destroy() {
537        let mut mgr = LayerShellManager::new();
538        let id = mgr.create_surface(10, Layer::Bottom, b"dock").unwrap();
539        assert_eq!(mgr.surface_count(), 1);
540        mgr.destroy_surface(id).unwrap();
541        assert_eq!(mgr.surface_count(), 0);
542    }
543
544    #[test]
545    fn test_configure_ack() {
546        let mut mgr = LayerShellManager::new();
547        let id = mgr.create_surface(10, Layer::Top, b"bar").unwrap();
548
549        let serial = mgr.configure_surface(id, 1280, 32).unwrap();
550        assert!(!mgr.get_surface(id).unwrap().configured);
551
552        assert!(mgr.ack_configure(id, serial));
553        assert!(mgr.get_surface(id).unwrap().configured);
554
555        // Wrong serial
556        assert!(!mgr.ack_configure(id, serial + 999));
557    }
558
559    #[test]
560    fn test_exclusive_zones() {
561        let mut mgr = LayerShellManager::new();
562
563        // Top panel: anchored top, left, right with 32px exclusive zone
564        let id = mgr.create_surface(10, Layer::Top, b"panel").unwrap();
565        {
566            let ls = mgr.get_surface_mut(id).unwrap();
567            ls.anchor = Anchor {
568                top: true,
569                bottom: false,
570                left: true,
571                right: true,
572            };
573            ls.exclusive_zone = 32;
574            ls.mapped = true;
575        }
576
577        let (top, bottom, left, right) = mgr.calculate_exclusive_zones();
578        assert_eq!(top, 32);
579        assert_eq!(bottom, 0);
580        assert_eq!(left, 0);
581        assert_eq!(right, 0);
582
583        let usable = mgr.get_usable_area(1280, 800);
584        assert_eq!(usable.x, 0);
585        assert_eq!(usable.y, 32);
586        assert_eq!(usable.width, 1280);
587        assert_eq!(usable.height, 768);
588    }
589
590    #[test]
591    fn test_usable_area_no_exclusions() {
592        let mgr = LayerShellManager::new();
593        let area = mgr.get_usable_area(1920, 1080);
594        assert_eq!(area.x, 0);
595        assert_eq!(area.y, 0);
596        assert_eq!(area.width, 1920);
597        assert_eq!(area.height, 1080);
598    }
599
600    #[test]
601    fn test_get_surfaces_for_layer() {
602        let mut mgr = LayerShellManager::new();
603        mgr.create_surface(1, Layer::Top, b"a").unwrap();
604        mgr.create_surface(2, Layer::Bottom, b"b").unwrap();
605        mgr.create_surface(3, Layer::Top, b"c").unwrap();
606
607        let top_surfaces = mgr.get_surfaces_for_layer(Layer::Top);
608        assert_eq!(top_surfaces.len(), 2);
609
610        let bottom_surfaces = mgr.get_surfaces_for_layer(Layer::Bottom);
611        assert_eq!(bottom_surfaces.len(), 1);
612
613        let bg_surfaces = mgr.get_surfaces_for_layer(Layer::Background);
614        assert_eq!(bg_surfaces.len(), 0);
615    }
616}