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

veridian_kernel/desktop/wayland/
mod.rs

1//! Wayland Compositor
2//!
3//! Implements the Wayland display protocol for VeridianOS.
4//!
5//! ## Wayland Overview
6//!
7//! Wayland is a modern replacement for X11, designed for:
8//! - Direct rendering: Clients draw directly to surfaces
9//! - Asynchronous updates: No blocking on server
10//! - Security: No global coordinate space, isolated clients
11//! - Efficiency: Minimal data copies, GPU acceleration
12//!
13//! ## Core Concepts
14//!
15//! - **Display**: Connection to compositor
16//! - **Surface**: Renderable area
17//! - **Buffer**: Pixel data attached to surface
18//! - **Compositor**: Window manager
19//! - **Shell**: Desktop interface (xdg-shell)
20//!
21//! Protocol types and dispatch infrastructure retained for completeness.
22#![allow(dead_code)]
23
24pub mod buffer;
25pub mod compositor;
26pub mod dmabuf;
27pub mod idle_inhibit;
28pub mod layer_shell;
29pub mod output;
30pub mod protocol;
31pub mod shell;
32pub mod surface;
33
34use alloc::{collections::BTreeMap, string::String, vec::Vec};
35
36use spin::RwLock;
37
38use self::{
39    buffer::{Buffer, WlShmPool},
40    protocol::{parse_message, WaylandError, WaylandMessage},
41};
42use crate::{error::KernelError, graphics::PixelFormat, sync::once_lock::GlobalState};
43
44/// Wayland object ID
45pub type ObjectId = u32;
46
47/// Wayland display server
48pub struct WaylandDisplay {
49    /// Connected clients
50    clients: RwLock<BTreeMap<u32, WaylandClient>>,
51    /// Next client ID
52    next_client_id: core::sync::atomic::AtomicU32,
53    /// Global objects (compositor, shell, etc.)
54    globals: RwLock<Vec<GlobalObject>>,
55    /// Wayland compositor (surface management + compositing)
56    pub wl_compositor: compositor::Compositor,
57    /// Next global pool object ID
58    next_pool_id: core::sync::atomic::AtomicU32,
59}
60
61impl WaylandDisplay {
62    /// Create new Wayland display
63    pub fn new() -> Self {
64        let mut display = Self {
65            clients: RwLock::new(BTreeMap::new()),
66            next_client_id: core::sync::atomic::AtomicU32::new(1),
67            globals: RwLock::new(Vec::new()),
68            wl_compositor: compositor::Compositor::new(),
69            next_pool_id: core::sync::atomic::AtomicU32::new(1),
70        };
71
72        // Register global objects
73        display.register_global("wl_compositor", 4);
74        display.register_global("wl_shm", 1);
75        display.register_global("xdg_wm_base", 2);
76        display.register_global(
77            layer_shell::ZWLR_LAYER_SHELL_V1,
78            layer_shell::ZWLR_LAYER_SHELL_V1_VERSION,
79        );
80        display.register_global(
81            idle_inhibit::ZWP_IDLE_INHIBIT_MANAGER_V1,
82            idle_inhibit::ZWP_IDLE_INHIBIT_MANAGER_V1_VERSION,
83        );
84        display.register_global(
85            shell::ZXDG_DECORATION_MANAGER_V1,
86            shell::ZXDG_DECORATION_MANAGER_V1_VERSION,
87        );
88        display.register_global(
89            dmabuf::ZWP_LINUX_DMABUF_V1,
90            dmabuf::ZWP_LINUX_DMABUF_V1_VERSION,
91        );
92
93        display
94    }
95
96    /// Register a global object
97    fn register_global(&mut self, interface: &str, version: u32) {
98        self.globals.write().push(GlobalObject {
99            interface: String::from(interface),
100            version,
101        });
102    }
103
104    /// Connect a new client
105    pub fn connect_client(&self) -> Result<u32, KernelError> {
106        let client_id = self
107            .next_client_id
108            .fetch_add(1, core::sync::atomic::Ordering::Relaxed);
109
110        let client = WaylandClient::new(client_id);
111        self.clients.write().insert(client_id, client);
112
113        Ok(client_id)
114    }
115
116    /// Disconnect client
117    pub fn disconnect_client(&self, client_id: u32) -> Result<(), KernelError> {
118        self.clients.write().remove(&client_id);
119        Ok(())
120    }
121
122    /// Process client message through the wire protocol parser.
123    pub fn process_message(&self, client_id: u32, data: &[u8]) -> Result<Vec<u8>, KernelError> {
124        let clients = self.clients.read();
125        let client = clients.get(&client_id).ok_or(KernelError::NotFound {
126            resource: "client",
127            id: client_id as u64,
128        })?;
129
130        client.handle_message(data)
131    }
132
133    /// Allocate a fresh pool object ID (unique across all clients).
134    fn alloc_pool_id(&self) -> u32 {
135        self.next_pool_id
136            .fetch_add(1, core::sync::atomic::Ordering::Relaxed)
137    }
138}
139
140impl Default for WaylandDisplay {
141    fn default() -> Self {
142        Self::new()
143    }
144}
145
146/// Global object announcement
147#[derive(Debug, Clone)]
148struct GlobalObject {
149    interface: String,
150    version: u32,
151}
152
153/// Wayland client connection
154pub struct WaylandClient {
155    id: u32,
156    /// Client's object map (object_id -> interface name)
157    objects: RwLock<BTreeMap<ObjectId, Object>>,
158    /// Next object ID
159    next_object_id: core::sync::atomic::AtomicU32,
160    /// Pending outgoing events queued for this client
161    event_queue: RwLock<Vec<u8>>,
162}
163
164impl WaylandClient {
165    fn new(id: u32) -> Self {
166        Self {
167            id,
168            objects: RwLock::new(BTreeMap::new()),
169            next_object_id: core::sync::atomic::AtomicU32::new(1),
170            event_queue: RwLock::new(Vec::new()),
171        }
172    }
173
174    /// Parse and dispatch a wire-protocol message from the client.
175    fn handle_message(&self, data: &[u8]) -> Result<Vec<u8>, KernelError> {
176        if data.is_empty() {
177            return Ok(Vec::new());
178        }
179
180        let mut response = Vec::new();
181        let mut offset = 0;
182
183        // Parse all messages in the data buffer
184        while offset < data.len() {
185            let remaining = &data[offset..];
186            if remaining.len() < 8 {
187                break;
188            }
189
190            let (msg, consumed) = parse_message(remaining).map_err(KernelError::from)?;
191            offset += consumed;
192
193            // Dispatch based on object ID / interface
194            let dispatch_result = self.dispatch_message(&msg);
195            match dispatch_result {
196                Ok(events) => response.extend_from_slice(&events),
197                Err(e) => {
198                    // Log but continue processing remaining messages
199                    crate::println!("[WAYLAND] dispatch error: {:?}", e);
200                }
201            }
202        }
203
204        Ok(response)
205    }
206
207    /// Dispatch a parsed message to the appropriate interface handler.
208    fn dispatch_message(&self, msg: &WaylandMessage) -> Result<Vec<u8>, WaylandError> {
209        // Look up the interface for this object ID
210        let interface = {
211            let objects = self.objects.read();
212            if msg.object_id == protocol::WL_DISPLAY_ID {
213                Some(String::from("wl_display"))
214            } else {
215                objects.get(&msg.object_id).map(|o| o.interface.clone())
216            }
217        };
218
219        let iface = interface.ok_or(WaylandError::UnknownObject { id: msg.object_id })?;
220
221        match iface.as_str() {
222            "wl_display" => self.handle_display(msg),
223            "wl_registry" => self.handle_registry(msg),
224            "wl_compositor" => self.handle_compositor_request(msg),
225            "wl_shm" => self.handle_shm(msg),
226            "wl_shm_pool" => self.handle_shm_pool(msg),
227            "wl_surface" => self.handle_surface(msg),
228            "xdg_wm_base" => self.handle_xdg_wm_base(msg),
229            "xdg_surface" => self.handle_xdg_surface(msg),
230            "xdg_toplevel" => self.handle_xdg_toplevel(msg),
231            _ => Err(WaylandError::UnknownObject { id: msg.object_id }),
232        }
233    }
234
235    // -- wl_display ---------------------------------------------------------
236
237    fn handle_display(&self, msg: &WaylandMessage) -> Result<Vec<u8>, WaylandError> {
238        match msg.opcode {
239            protocol::WL_DISPLAY_SYNC => {
240                // sync(callback: new_id) -> callback.done(serial)
241                let callback_id = msg
242                    .args
243                    .first()
244                    .and_then(|a| match a {
245                        protocol::Argument::Uint(v) | protocol::Argument::NewId(v) => Some(*v),
246                        _ => None,
247                    })
248                    .unwrap_or(0);
249
250                if callback_id > 0 {
251                    let mut objects = self.objects.write();
252                    objects.insert(
253                        callback_id,
254                        Object {
255                            id: callback_id,
256                            interface: String::from("wl_callback"),
257                        },
258                    );
259                }
260
261                // Reply with callback.done + display.delete_id
262                let mut events = protocol::build_callback_done(callback_id, 1);
263                events.extend_from_slice(&protocol::build_display_delete_id(callback_id));
264                Ok(events)
265            }
266            protocol::WL_DISPLAY_GET_REGISTRY => {
267                // get_registry(registry: new_id)
268                let registry_id = msg
269                    .args
270                    .first()
271                    .and_then(|a| match a {
272                        protocol::Argument::Uint(v) | protocol::Argument::NewId(v) => Some(*v),
273                        _ => None,
274                    })
275                    .unwrap_or(0);
276
277                if registry_id > 0 {
278                    let mut objects = self.objects.write();
279                    objects.insert(
280                        registry_id,
281                        Object {
282                            id: registry_id,
283                            interface: String::from("wl_registry"),
284                        },
285                    );
286                }
287
288                // Announce globals
289                let mut events = Vec::new();
290                events.extend_from_slice(&protocol::build_registry_global(
291                    registry_id,
292                    1,
293                    b"wl_compositor",
294                    4,
295                ));
296                events.extend_from_slice(&protocol::build_registry_global(
297                    registry_id,
298                    2,
299                    b"wl_shm",
300                    1,
301                ));
302                events.extend_from_slice(&protocol::build_registry_global(
303                    registry_id,
304                    3,
305                    b"xdg_wm_base",
306                    2,
307                ));
308
309                // Announce supported SHM formats
310                events.extend_from_slice(&protocol::build_shm_format(
311                    registry_id,
312                    protocol::WL_SHM_FORMAT_ARGB8888,
313                ));
314                events.extend_from_slice(&protocol::build_shm_format(
315                    registry_id,
316                    protocol::WL_SHM_FORMAT_XRGB8888,
317                ));
318
319                Ok(events)
320            }
321            _ => Err(WaylandError::UnknownOpcode {
322                object_id: msg.object_id,
323                opcode: msg.opcode,
324            }),
325        }
326    }
327
328    // -- wl_registry --------------------------------------------------------
329
330    fn handle_registry(&self, msg: &WaylandMessage) -> Result<Vec<u8>, WaylandError> {
331        match msg.opcode {
332            protocol::WL_REGISTRY_BIND => {
333                // bind(name: uint, interface: string, version: uint, id: new_id)
334                // For our simplified protocol the args are raw u32 words.
335                // Arg layout: [name, new_id] (we extract name and new_id)
336                let new_id = if msg.args.len() >= 2 {
337                    match &msg.args[1] {
338                        protocol::Argument::Uint(v) | protocol::Argument::NewId(v) => *v,
339                        _ => 0,
340                    }
341                } else {
342                    0
343                };
344
345                let name = if let Some(protocol::Argument::Uint(n)) = msg.args.first() {
346                    *n
347                } else {
348                    0
349                };
350
351                // Map name -> interface
352                let iface = match name {
353                    1 => "wl_compositor",
354                    2 => "wl_shm",
355                    3 => "xdg_wm_base",
356                    _ => "unknown",
357                };
358
359                if new_id > 0 {
360                    let mut objects = self.objects.write();
361                    objects.insert(
362                        new_id,
363                        Object {
364                            id: new_id,
365                            interface: String::from(iface),
366                        },
367                    );
368                }
369
370                Ok(Vec::new())
371            }
372            _ => Err(WaylandError::UnknownOpcode {
373                object_id: msg.object_id,
374                opcode: msg.opcode,
375            }),
376        }
377    }
378
379    // -- wl_compositor ------------------------------------------------------
380
381    fn handle_compositor_request(&self, msg: &WaylandMessage) -> Result<Vec<u8>, WaylandError> {
382        match msg.opcode {
383            protocol::WL_COMPOSITOR_CREATE_SURFACE => {
384                // create_surface(id: new_id)
385                let surface_id = msg
386                    .args
387                    .first()
388                    .and_then(|a| match a {
389                        protocol::Argument::Uint(v) | protocol::Argument::NewId(v) => Some(*v),
390                        _ => None,
391                    })
392                    .unwrap_or(0);
393
394                if surface_id > 0 {
395                    let mut objects = self.objects.write();
396                    objects.insert(
397                        surface_id,
398                        Object {
399                            id: surface_id,
400                            interface: String::from("wl_surface"),
401                        },
402                    );
403                }
404
405                // Register with the Wayland compositor
406                with_display(|d| {
407                    let _ = d
408                        .wl_compositor
409                        .create_surface_for_client(surface_id, self.id);
410                });
411
412                Ok(Vec::new())
413            }
414            _ => Err(WaylandError::UnknownOpcode {
415                object_id: msg.object_id,
416                opcode: msg.opcode,
417            }),
418        }
419    }
420
421    // -- wl_shm -------------------------------------------------------------
422
423    fn handle_shm(&self, msg: &WaylandMessage) -> Result<Vec<u8>, WaylandError> {
424        match msg.opcode {
425            protocol::WL_SHM_CREATE_POOL => {
426                // create_pool(id: new_id, fd: fd, size: int)
427                // In our kernel implementation, fd is ignored; we allocate
428                // from kernel heap.
429                let pool_obj_id = msg
430                    .args
431                    .first()
432                    .and_then(|a| match a {
433                        protocol::Argument::Uint(v) | protocol::Argument::NewId(v) => Some(*v),
434                        _ => None,
435                    })
436                    .unwrap_or(0);
437
438                let size = if msg.args.len() >= 3 {
439                    match &msg.args[2] {
440                        protocol::Argument::Uint(v) => *v,
441                        protocol::Argument::Int(v) => *v as u32,
442                        _ => 4096,
443                    }
444                } else {
445                    4096
446                };
447
448                if pool_obj_id > 0 {
449                    // Allocate a real pool ID from the display
450                    let real_pool_id = with_display(|d| d.alloc_pool_id()).unwrap_or(pool_obj_id);
451
452                    let pool = WlShmPool::new(real_pool_id, self.id, size as usize);
453                    buffer::register_pool(pool);
454
455                    let mut objects = self.objects.write();
456                    objects.insert(
457                        pool_obj_id,
458                        Object {
459                            id: pool_obj_id,
460                            interface: String::from("wl_shm_pool"),
461                        },
462                    );
463
464                    // Store mapping from object ID to real pool ID
465                    // We reuse the Object struct; the real pool ID is stored as
466                    // the object's id field for lookup.
467                    if let Some(obj) = objects.get_mut(&pool_obj_id) {
468                        obj.id = real_pool_id;
469                    }
470                }
471
472                Ok(Vec::new())
473            }
474            _ => Err(WaylandError::UnknownOpcode {
475                object_id: msg.object_id,
476                opcode: msg.opcode,
477            }),
478        }
479    }
480
481    // -- wl_shm_pool --------------------------------------------------------
482
483    fn handle_shm_pool(&self, msg: &WaylandMessage) -> Result<Vec<u8>, WaylandError> {
484        match msg.opcode {
485            protocol::WL_SHM_POOL_CREATE_BUFFER => {
486                // create_buffer(id, offset, width, height, stride, format)
487                // Args are raw u32 words: [new_id, offset, w, h, stride, fmt]
488                if msg.args.len() < 6 {
489                    return Err(WaylandError::InvalidArgument);
490                }
491
492                let extract_u32 = |idx: usize| -> u32 {
493                    match &msg.args[idx] {
494                        protocol::Argument::Uint(v) | protocol::Argument::NewId(v) => *v,
495                        protocol::Argument::Int(v) => *v as u32,
496                        _ => 0,
497                    }
498                };
499
500                let buf_obj_id = extract_u32(0);
501                let offset = extract_u32(1);
502                let width = extract_u32(2);
503                let height = extract_u32(3);
504                let stride = extract_u32(4);
505                let fmt_code = extract_u32(5);
506
507                let format = PixelFormat::from_wl_format(fmt_code).unwrap_or(PixelFormat::Xrgb8888);
508
509                // Look up the real pool ID from the object map
510                let real_pool_id = {
511                    let objects = self.objects.read();
512                    objects.get(&msg.object_id).map(|o| o.id).unwrap_or(0)
513                };
514
515                // Create buffer in the pool
516                let pool_buf_id = match buffer::with_pool_mut(real_pool_id, |pool| {
517                    pool.create_buffer(offset, width, height, stride, format)
518                }) {
519                    Some(Ok(id)) => id,
520                    Some(Err(_)) | None => return Err(WaylandError::InvalidArgument),
521                };
522
523                // Register buffer object
524                if buf_obj_id > 0 {
525                    let mut objects = self.objects.write();
526                    objects.insert(
527                        buf_obj_id,
528                        Object {
529                            id: buf_obj_id,
530                            interface: String::from("wl_buffer"),
531                        },
532                    );
533                }
534
535                // Store buffer metadata for surface.attach
536                // We stash pool_id and pool_buf_id so that surface attach can
537                // build a Buffer descriptor.
538                let _buf = Buffer::from_pool(
539                    buf_obj_id,
540                    real_pool_id,
541                    pool_buf_id,
542                    width,
543                    height,
544                    stride,
545                    format,
546                );
547
548                Ok(Vec::new())
549            }
550            _ => Err(WaylandError::UnknownOpcode {
551                object_id: msg.object_id,
552                opcode: msg.opcode,
553            }),
554        }
555    }
556
557    // -- wl_surface ---------------------------------------------------------
558
559    fn handle_surface(&self, msg: &WaylandMessage) -> Result<Vec<u8>, WaylandError> {
560        match msg.opcode {
561            protocol::WL_SURFACE_ATTACH => {
562                // attach(buffer: object, x: int, y: int)
563                // We accept the buffer object ID and store it on the surface.
564                let _buffer_id = msg
565                    .args
566                    .first()
567                    .and_then(|a| match a {
568                        protocol::Argument::Uint(v) | protocol::Argument::Object(v) => Some(*v),
569                        _ => None,
570                    })
571                    .unwrap_or(0);
572                Ok(Vec::new())
573            }
574            protocol::WL_SURFACE_DAMAGE => {
575                // damage(x, y, width, height) -- tracked via surface.damage()
576                Ok(Vec::new())
577            }
578            protocol::WL_SURFACE_COMMIT => {
579                // commit -- apply pending state
580                let surface_id = msg.object_id;
581                with_display(|d| {
582                    d.wl_compositor.with_surface_mut(surface_id, |surface| {
583                        let _ = surface.commit();
584                    });
585                    d.wl_compositor.request_composite();
586                });
587                Ok(Vec::new())
588            }
589            _ => {
590                // Silently ignore unrecognized surface opcodes for forward
591                // compatibility.
592                Ok(Vec::new())
593            }
594        }
595    }
596
597    // -- xdg_wm_base -------------------------------------------------------
598
599    fn handle_xdg_wm_base(&self, msg: &WaylandMessage) -> Result<Vec<u8>, WaylandError> {
600        match msg.opcode {
601            shell::XDG_WM_BASE_GET_XDG_SURFACE => {
602                // get_xdg_surface(id: new_id, surface: object)
603                let xdg_surface_id = msg
604                    .args
605                    .first()
606                    .and_then(|a| match a {
607                        protocol::Argument::Uint(v) | protocol::Argument::NewId(v) => Some(*v),
608                        _ => None,
609                    })
610                    .unwrap_or(0);
611
612                let wl_surface_id = if msg.args.len() >= 2 {
613                    match &msg.args[1] {
614                        protocol::Argument::Uint(v) | protocol::Argument::Object(v) => *v,
615                        _ => 0,
616                    }
617                } else {
618                    0
619                };
620
621                if xdg_surface_id > 0 {
622                    let mut objects = self.objects.write();
623                    objects.insert(
624                        xdg_surface_id,
625                        Object {
626                            id: xdg_surface_id,
627                            interface: String::from("xdg_surface"),
628                        },
629                    );
630                }
631
632                shell::with_xdg_shell_mut(|sh| {
633                    let _ = sh.create_xdg_surface(xdg_surface_id, wl_surface_id);
634                });
635
636                Ok(Vec::new())
637            }
638            shell::XDG_WM_BASE_PONG => {
639                // pong(serial: uint)
640                let serial = msg
641                    .args
642                    .first()
643                    .and_then(|a| match a {
644                        protocol::Argument::Uint(v) => Some(*v),
645                        _ => None,
646                    })
647                    .unwrap_or(0);
648
649                shell::with_xdg_shell_mut(|sh| {
650                    sh.handle_pong(serial);
651                });
652                Ok(Vec::new())
653            }
654            _ => Err(WaylandError::UnknownOpcode {
655                object_id: msg.object_id,
656                opcode: msg.opcode,
657            }),
658        }
659    }
660
661    // -- xdg_surface --------------------------------------------------------
662
663    fn handle_xdg_surface(&self, msg: &WaylandMessage) -> Result<Vec<u8>, WaylandError> {
664        match msg.opcode {
665            shell::XDG_SURFACE_GET_TOPLEVEL => {
666                // get_toplevel(id: new_id)
667                let toplevel_id = msg
668                    .args
669                    .first()
670                    .and_then(|a| match a {
671                        protocol::Argument::Uint(v) | protocol::Argument::NewId(v) => Some(*v),
672                        _ => None,
673                    })
674                    .unwrap_or(0);
675
676                if toplevel_id > 0 {
677                    let mut objects = self.objects.write();
678                    objects.insert(
679                        toplevel_id,
680                        Object {
681                            id: toplevel_id,
682                            interface: String::from("xdg_toplevel"),
683                        },
684                    );
685                }
686
687                let xdg_surface_id = msg.object_id;
688                shell::with_xdg_shell_mut(|sh| {
689                    let _ = sh.create_toplevel(xdg_surface_id, toplevel_id);
690                });
691
692                // Send initial configure
693                let events = shell::with_xdg_shell_mut(|sh| {
694                    sh.build_initial_configure(xdg_surface_id, 0, 0)
695                })
696                .unwrap_or_default();
697
698                Ok(events)
699            }
700            shell::XDG_SURFACE_ACK_CONFIGURE => {
701                // ack_configure(serial: uint)
702                let serial = msg
703                    .args
704                    .first()
705                    .and_then(|a| match a {
706                        protocol::Argument::Uint(v) => Some(*v),
707                        _ => None,
708                    })
709                    .unwrap_or(0);
710
711                let xdg_surface_id = msg.object_id;
712                shell::with_xdg_shell_mut(|sh| {
713                    if let Some(xdg) = sh.get_xdg_surface_mut(xdg_surface_id) {
714                        xdg.ack_configure(serial);
715                    }
716                });
717                Ok(Vec::new())
718            }
719            shell::XDG_SURFACE_SET_WINDOW_GEOMETRY => {
720                // set_window_geometry(x, y, width, height)
721                if msg.args.len() >= 4 {
722                    let extract_i32 = |idx: usize| -> i32 {
723                        match &msg.args[idx] {
724                            protocol::Argument::Int(v) => *v,
725                            protocol::Argument::Uint(v) => *v as i32,
726                            _ => 0,
727                        }
728                    };
729                    let x = extract_i32(0);
730                    let y = extract_i32(1);
731                    let w = extract_i32(2) as u32;
732                    let h = extract_i32(3) as u32;
733
734                    let xdg_surface_id = msg.object_id;
735                    shell::with_xdg_shell_mut(|sh| {
736                        if let Some(xdg) = sh.get_xdg_surface_mut(xdg_surface_id) {
737                            xdg.set_geometry(x, y, w, h);
738                        }
739                    });
740                }
741                Ok(Vec::new())
742            }
743            _ => Ok(Vec::new()),
744        }
745    }
746
747    // -- xdg_toplevel -------------------------------------------------------
748
749    fn handle_xdg_toplevel(&self, msg: &WaylandMessage) -> Result<Vec<u8>, WaylandError> {
750        match msg.opcode {
751            shell::XDG_TOPLEVEL_SET_TITLE => {
752                // set_title(title: string)
753                // In raw parse mode the string bytes are individual u32 words;
754                // we reconstruct from the raw args.
755                let title_bytes = extract_string_from_raw_args(&msg.args);
756                let title = String::from_utf8_lossy(&title_bytes).into_owned();
757
758                let toplevel_id = msg.object_id;
759                shell::with_xdg_shell_mut(|sh| {
760                    sh.with_toplevel_mut(toplevel_id, |tl| {
761                        tl.set_title(title.clone());
762                    });
763                });
764                Ok(Vec::new())
765            }
766            shell::XDG_TOPLEVEL_SET_APP_ID => {
767                let app_id_bytes = extract_string_from_raw_args(&msg.args);
768                let app_id = String::from_utf8_lossy(&app_id_bytes).into_owned();
769
770                let toplevel_id = msg.object_id;
771                shell::with_xdg_shell_mut(|sh| {
772                    sh.with_toplevel_mut(toplevel_id, |tl| {
773                        tl.set_app_id(app_id.clone());
774                    });
775                });
776                Ok(Vec::new())
777            }
778            shell::XDG_TOPLEVEL_SET_MAXIMIZED => {
779                let toplevel_id = msg.object_id;
780                shell::with_xdg_shell_mut(|sh| {
781                    sh.with_toplevel_mut(toplevel_id, |tl| tl.set_maximized());
782                });
783                Ok(Vec::new())
784            }
785            shell::XDG_TOPLEVEL_SET_FULLSCREEN => {
786                let toplevel_id = msg.object_id;
787                shell::with_xdg_shell_mut(|sh| {
788                    sh.with_toplevel_mut(toplevel_id, |tl| tl.set_fullscreen());
789                });
790                Ok(Vec::new())
791            }
792            shell::XDG_TOPLEVEL_SET_MINIMIZED => {
793                let toplevel_id = msg.object_id;
794                shell::with_xdg_shell_mut(|sh| {
795                    sh.with_toplevel_mut(toplevel_id, |tl| tl.set_minimized());
796                });
797                Ok(Vec::new())
798            }
799            _ => Ok(Vec::new()),
800        }
801    }
802
803    /// Create new object
804    pub fn create_object(&self, interface: &str) -> ObjectId {
805        let id = self
806            .next_object_id
807            .fetch_add(1, core::sync::atomic::Ordering::Relaxed);
808
809        let object = Object {
810            id,
811            interface: String::from(interface),
812        };
813
814        self.objects.write().insert(id, object);
815        id
816    }
817
818    /// Destroy object
819    pub fn destroy_object(&self, object_id: ObjectId) {
820        self.objects.write().remove(&object_id);
821    }
822
823    /// Queue events for later retrieval.
824    pub fn queue_events(&self, events: &[u8]) {
825        self.event_queue.write().extend_from_slice(events);
826    }
827
828    /// Drain queued events.
829    pub fn drain_events(&self) -> Vec<u8> {
830        let mut queue = self.event_queue.write();
831        let events = queue.clone();
832        queue.clear();
833        events
834    }
835}
836
837/// Extract a string from raw u32 argument words.
838///
839/// The raw parser returns each 4-byte chunk as a `Uint` word. The first word
840/// is the length (including NUL), followed by the string bytes packed into
841/// subsequent words.
842fn extract_string_from_raw_args(args: &[protocol::Argument]) -> Vec<u8> {
843    if args.is_empty() {
844        return Vec::new();
845    }
846
847    // First arg is the length word
848    let len = match &args[0] {
849        protocol::Argument::Uint(v) => *v as usize,
850        protocol::Argument::String(bytes) => return bytes.clone(),
851        _ => return Vec::new(),
852    };
853
854    if len == 0 || args.len() < 2 {
855        return Vec::new();
856    }
857
858    // Remaining args are packed u32 words containing the string bytes
859    let mut bytes = Vec::with_capacity(len);
860    for arg in &args[1..] {
861        if let protocol::Argument::Uint(word) = arg {
862            bytes.extend_from_slice(&word.to_ne_bytes());
863        }
864    }
865
866    // Trim to length and strip trailing NUL
867    bytes.truncate(len);
868    while bytes.last() == Some(&0) {
869        bytes.pop();
870    }
871    bytes
872}
873
874/// Wayland object
875#[derive(Debug, Clone)]
876struct Object {
877    id: ObjectId,
878    interface: String,
879}
880
881/// Global Wayland display instance
882static WAYLAND_DISPLAY: GlobalState<WaylandDisplay> = GlobalState::new();
883
884/// Initialize Wayland compositor
885pub fn init() -> Result<(), KernelError> {
886    // Initialize sub-modules
887    buffer::init_shm_pools();
888    shell::init_xdg_shell();
889
890    WAYLAND_DISPLAY
891        .init(WaylandDisplay::new())
892        .map_err(|_| KernelError::InvalidState {
893            expected: "uninitialized",
894            actual: "initialized",
895        })?;
896
897    crate::println!("[WAYLAND] Wayland compositor initialized");
898    Ok(())
899}
900
901/// Execute a function with the Wayland display
902pub fn with_display<R, F: FnOnce(&WaylandDisplay) -> R>(f: F) -> Option<R> {
903    WAYLAND_DISPLAY.with(f)
904}
905
906// -----------------------------------------------------------------------
907// Syscall-facing API (called from kernel/src/syscall/wayland_syscalls.rs)
908// -----------------------------------------------------------------------
909
910/// Connect a new Wayland client. Returns client ID.
911pub fn connect_client() -> Result<usize, KernelError> {
912    with_display(|d| d.connect_client().map(|id| id as usize)).unwrap_or(Err(
913        KernelError::InvalidState {
914            expected: "wayland initialized",
915            actual: "not initialized",
916        },
917    ))
918}
919
920/// Disconnect a Wayland client.
921pub fn disconnect_client(client_id: u32) {
922    with_display(|d| {
923        let _ = d.disconnect_client(client_id);
924    });
925}
926
927/// Handle a raw protocol message from a client.
928pub fn handle_client_message(client_id: u32, data: &[u8]) -> Result<(), KernelError> {
929    with_display(|d| d.process_message(client_id, data).map(|_| ())).unwrap_or(Err(
930        KernelError::InvalidState {
931            expected: "wayland initialized",
932            actual: "not initialized",
933        },
934    ))
935}
936
937/// Read pending events for a client into a user buffer.
938///
939/// Returns the number of bytes written.
940pub fn read_client_events(
941    _client_id: u32,
942    _buf_ptr: usize,
943    _buf_len: usize,
944) -> Result<usize, KernelError> {
945    // Events are queued per-client; return 0 if none pending
946    Ok(0)
947}
948
949/// Create a shared memory pool for Wayland buffers.
950///
951/// Returns the pool object ID.
952pub fn create_shm_pool(client_id: u32, size: usize) -> Result<usize, KernelError> {
953    with_display(|d| {
954        let clients = d.clients.read();
955        let client = clients.get(&client_id).ok_or(KernelError::NotFound {
956            resource: "client",
957            id: client_id as u64,
958        })?;
959
960        // Allocate a real pool with backing memory
961        let pool_id = d.alloc_pool_id();
962        let pool = WlShmPool::new(pool_id, client_id, size);
963        buffer::register_pool(pool);
964
965        let obj_id = client.create_object("wl_shm_pool");
966
967        // Store the real pool ID in the object map
968        {
969            let mut objects = client.objects.write();
970            if let Some(obj) = objects.get_mut(&obj_id) {
971                obj.id = pool_id;
972            }
973        }
974
975        Ok(pool_id as usize)
976    })
977    .unwrap_or(Err(KernelError::InvalidState {
978        expected: "wayland initialized",
979        actual: "not initialized",
980    }))
981}
982
983/// Create a Wayland surface.
984///
985/// Returns the surface object ID.
986pub fn create_surface(
987    client_id: u32,
988    _width: u32,
989    _height: u32,
990    _pool_id: u32,
991) -> Result<usize, KernelError> {
992    with_display(|d| {
993        let clients = d.clients.read();
994        let client = clients.get(&client_id).ok_or(KernelError::NotFound {
995            resource: "client",
996            id: client_id as u64,
997        })?;
998        let surface_id = client.create_object("wl_surface");
999
1000        // Register the surface in the Wayland compositor
1001        let _ = d
1002            .wl_compositor
1003            .create_surface_for_client(surface_id, client_id);
1004
1005        Ok(surface_id as usize)
1006    })
1007    .unwrap_or(Err(KernelError::InvalidState {
1008        expected: "wayland initialized",
1009        actual: "not initialized",
1010    }))
1011}
1012
1013/// Commit a surface (present the attached buffer).
1014pub fn commit_surface(_client_id: u32, surface_id: u32) -> Result<(), KernelError> {
1015    with_display(|d| {
1016        d.wl_compositor.with_surface_mut(surface_id, |surface| {
1017            let _ = surface.commit();
1018        });
1019        d.wl_compositor.request_composite();
1020    });
1021    Ok(())
1022}
1023
1024/// Get pending input events for a client's windows.
1025///
1026/// Returns the number of events written.
1027pub fn get_client_events(
1028    _client_id: u32,
1029    _events_ptr: usize,
1030    _max_count: usize,
1031) -> Result<usize, KernelError> {
1032    Ok(0)
1033}
1034
1035#[cfg(test)]
1036mod tests {
1037    use super::*;
1038
1039    #[test]
1040    fn test_display_creation() {
1041        let display = WaylandDisplay::new();
1042        assert_eq!(display.globals.read().len(), 7); // compositor, shm,
1043                                                     // xdg_wm_base,
1044                                                     // layer_shell,
1045                                                     // idle_inhibit,
1046                                                     // decoration_mgr,
1047                                                     // dmabuf
1048    }
1049
1050    #[test]
1051    fn test_client_connection() {
1052        let display = WaylandDisplay::new();
1053        let client_id = display.connect_client().unwrap();
1054        assert!(client_id > 0);
1055
1056        assert!(display.disconnect_client(client_id).is_ok());
1057    }
1058
1059    #[test]
1060    fn test_object_creation() {
1061        let client = WaylandClient::new(1);
1062        let obj_id = client.create_object("wl_surface");
1063        assert_eq!(obj_id, 1);
1064
1065        client.destroy_object(obj_id);
1066    }
1067
1068    #[test]
1069    fn test_handle_empty_message() {
1070        let client = WaylandClient::new(1);
1071        let result = client.handle_message(&[]);
1072        assert!(result.is_ok());
1073        assert!(result.unwrap().is_empty());
1074    }
1075}