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

veridian_kernel/graphics/
compositor.rs

1//! Window compositor
2//!
3//! Provides a higher-level window abstraction on top of the Wayland surface
4//! model. Each `Window` maps to a Wayland surface with an xdg_toplevel role.
5//! The compositor maintains a window list, focus tracking, and coordinates
6//! rendering by delegating to the Wayland compositor's compositing engine.
7#![allow(dead_code)] // Window compositor public API -- methods retained for Phase 6+ integration
8
9use alloc::vec::Vec;
10
11use spin::RwLock;
12
13use super::Rect;
14use crate::{error::KernelError, sync::once_lock::GlobalState};
15
16/// Window handle
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub struct WindowId(pub u32);
19
20/// Window
21#[derive(Debug, Clone)]
22pub struct Window {
23    pub id: WindowId,
24    pub rect: Rect,
25    pub title: &'static str,
26    pub visible: bool,
27    pub focused: bool,
28    /// Associated Wayland surface ID (0 if none)
29    pub surface_id: u32,
30}
31
32impl Window {
33    pub fn new(id: WindowId, rect: Rect, title: &'static str) -> Self {
34        Self {
35            id,
36            rect,
37            title,
38            visible: true,
39            focused: false,
40            surface_id: 0,
41        }
42    }
43}
44
45/// Compositor state
46pub struct Compositor {
47    windows: Vec<Window>,
48    next_id: u32,
49    focused_window: Option<WindowId>,
50    /// Desktop background color (ARGB packed u32)
51    bg_color: u32,
52}
53
54impl Compositor {
55    pub const fn new() -> Self {
56        Self {
57            windows: Vec::new(),
58            next_id: 1,
59            focused_window: None,
60            bg_color: 0xFF2D_3436,
61        }
62    }
63}
64
65impl Default for Compositor {
66    fn default() -> Self {
67        Self::new()
68    }
69}
70
71impl Compositor {
72    /// Create a new window
73    pub fn create_window(&mut self, rect: Rect, title: &'static str) -> WindowId {
74        let id = WindowId(self.next_id);
75        self.next_id += 1;
76
77        let window = Window::new(id, rect, title);
78        self.windows.push(window);
79
80        if self.focused_window.is_none() {
81            self.focused_window = Some(id);
82        }
83
84        id
85    }
86
87    /// Destroy a window
88    pub fn destroy_window(&mut self, id: WindowId) {
89        self.windows.retain(|w| w.id != id);
90        if self.focused_window == Some(id) {
91            self.focused_window = self.windows.first().map(|w| w.id);
92        }
93    }
94
95    /// Get window
96    pub fn get_window(&self, id: WindowId) -> Option<&Window> {
97        self.windows.iter().find(|w| w.id == id)
98    }
99
100    /// Focus window
101    pub fn focus_window(&mut self, id: WindowId) {
102        for window in &mut self.windows {
103            window.focused = window.id == id;
104        }
105        self.focused_window = Some(id);
106    }
107
108    /// Get the currently focused window ID.
109    pub fn focused_window(&self) -> Option<WindowId> {
110        self.focused_window
111    }
112
113    /// Number of windows.
114    pub fn window_count(&self) -> usize {
115        self.windows.len()
116    }
117
118    /// Render all windows.
119    ///
120    /// Delegates actual pixel compositing to the Wayland compositor. This
121    /// method handles the window-manager level logic (visibility, ordering).
122    pub fn render(&mut self) {
123        // Collect visible windows -- in the future this feeds into the
124        // Wayland compositor's surface Z-order.
125        for _window in &self.windows {
126            // Window rendering is handled by Wayland compositor composite()
127        }
128    }
129}
130
131static COMPOSITOR: GlobalState<RwLock<Compositor>> = GlobalState::new();
132
133/// Execute a function with the compositor
134pub fn with_compositor<R, F: FnOnce(&mut Compositor) -> R>(f: F) -> Option<R> {
135    COMPOSITOR.with(|comp| {
136        let mut compositor = comp.write();
137        f(&mut compositor)
138    })
139}
140
141/// Initialize compositor
142pub fn init() -> Result<(), KernelError> {
143    println!("[COMP] Initializing compositor...");
144
145    // Try to initialize, but don't fail if already initialized
146    if COMPOSITOR.init(RwLock::new(Compositor::new())).is_err() {
147        // Already initialized - this is fine
148        println!("[COMP] Compositor already initialized, skipping...");
149        return Ok(());
150    }
151
152    // Create a test window
153    with_compositor(|comp| {
154        comp.create_window(
155            Rect {
156                x: 100,
157                y: 100,
158                width: 640,
159                height: 480,
160            },
161            "VeridianOS",
162        )
163    });
164
165    println!("[COMP] Compositor initialized");
166    Ok(())
167}
168
169#[cfg(test)]
170mod tests {
171    use super::*;
172
173    #[test]
174    fn test_compositor_create_window() {
175        let mut comp = Compositor::new();
176        let id = comp.create_window(
177            Rect {
178                x: 0,
179                y: 0,
180                width: 100,
181                height: 100,
182            },
183            "Test",
184        );
185        assert!(comp.get_window(id).is_some());
186    }
187
188    #[test]
189    fn test_compositor_destroy_window() {
190        let mut comp = Compositor::new();
191        let id = comp.create_window(
192            Rect {
193                x: 0,
194                y: 0,
195                width: 100,
196                height: 100,
197            },
198            "Test",
199        );
200        comp.destroy_window(id);
201        assert!(comp.get_window(id).is_none());
202    }
203}