1#![allow(dead_code)]
11
12use alloc::vec::Vec;
13
14use crate::{error::KernelError, ipc::EndpointId, process::pcb::ProcessId};
15
16pub const DESKTOP_WM_ENDPOINT: EndpointId = 1000;
22pub const DESKTOP_INPUT_ENDPOINT: EndpointId = 1001;
24pub const DESKTOP_COMPOSITOR_ENDPOINT: EndpointId = 1002;
26pub const DESKTOP_NOTIFICATION_ENDPOINT: EndpointId = 1003;
28pub const DESKTOP_CLIPBOARD_ENDPOINT: EndpointId = 1004;
30pub const DESKTOP_LAUNCHER_ENDPOINT: EndpointId = 1005;
32
33pub const WINDOW_MANAGER_ENDPOINT: EndpointId = DESKTOP_WM_ENDPOINT;
35pub const INPUT_SERVER_ENDPOINT: EndpointId = DESKTOP_INPUT_ENDPOINT;
36pub const COMPOSITOR_ENDPOINT: EndpointId = DESKTOP_COMPOSITOR_ENDPOINT;
37
38#[repr(u32)]
47#[derive(Debug, Clone, Copy, PartialEq, Eq)]
48pub enum DesktopMessageType {
49 CreateWindow = 100,
52 DestroyWindow = 101,
54 MoveWindow = 102,
56 ResizeWindow = 103,
58 FocusWindow = 104,
60 UpdateWindowContent = 105,
62 MinimizeWindow = 106,
64 MaximizeWindow = 107,
66 SetWindowTitle = 108,
68 GetWindowGeometry = 109,
70
71 KeyPress = 200,
74 KeyRelease = 201,
76 MouseMove = 202,
78 MouseButton = 203,
80 ScrollEvent = 204,
82 TouchDown = 205,
84 TouchUp = 206,
86 TouchMotion = 207,
88
89 TerminalInput = 300,
92 TerminalOutput = 301,
94 TerminalResize = 302,
96
97 SurfaceCommit = 400,
100 SurfaceAttach = 401,
102 SurfaceDamage = 402,
104 FrameCallback = 403,
106
107 NotificationShow = 500,
110 NotificationDismiss = 501,
112 NotificationAction = 502,
114
115 ClipboardSet = 600,
118 ClipboardGet = 601,
120 ClipboardChanged = 602,
122
123 LaunchApp = 700,
126 ListApps = 701,
128
129 Success = 900,
132 Error = 901,
134}
135
136impl DesktopMessageType {
137 pub fn from_u32(v: u32) -> Option<Self> {
139 match v {
140 100 => Some(Self::CreateWindow),
141 101 => Some(Self::DestroyWindow),
142 102 => Some(Self::MoveWindow),
143 103 => Some(Self::ResizeWindow),
144 104 => Some(Self::FocusWindow),
145 105 => Some(Self::UpdateWindowContent),
146 106 => Some(Self::MinimizeWindow),
147 107 => Some(Self::MaximizeWindow),
148 108 => Some(Self::SetWindowTitle),
149 109 => Some(Self::GetWindowGeometry),
150
151 200 => Some(Self::KeyPress),
152 201 => Some(Self::KeyRelease),
153 202 => Some(Self::MouseMove),
154 203 => Some(Self::MouseButton),
155 204 => Some(Self::ScrollEvent),
156 205 => Some(Self::TouchDown),
157 206 => Some(Self::TouchUp),
158 207 => Some(Self::TouchMotion),
159
160 300 => Some(Self::TerminalInput),
161 301 => Some(Self::TerminalOutput),
162 302 => Some(Self::TerminalResize),
163
164 400 => Some(Self::SurfaceCommit),
165 401 => Some(Self::SurfaceAttach),
166 402 => Some(Self::SurfaceDamage),
167 403 => Some(Self::FrameCallback),
168
169 500 => Some(Self::NotificationShow),
170 501 => Some(Self::NotificationDismiss),
171 502 => Some(Self::NotificationAction),
172
173 600 => Some(Self::ClipboardSet),
174 601 => Some(Self::ClipboardGet),
175 602 => Some(Self::ClipboardChanged),
176
177 700 => Some(Self::LaunchApp),
178 701 => Some(Self::ListApps),
179
180 900 => Some(Self::Success),
181 901 => Some(Self::Error),
182 _ => None,
183 }
184 }
185}
186
187#[repr(C)]
193#[derive(Debug, Clone, Copy)]
194pub struct CreateWindowRequest {
195 pub x: i32,
196 pub y: i32,
197 pub width: u32,
198 pub height: u32,
199 pub title_len: u32,
200 }
202
203#[repr(C)]
205#[derive(Debug, Clone, Copy)]
206pub struct CreateWindowResponse {
207 pub window_id: u64,
208}
209
210#[repr(C)]
212#[derive(Debug, Clone, Copy)]
213pub struct UpdateWindowRequest {
214 pub window_id: u64,
215 pub x: u32,
216 pub y: u32,
217 pub width: u32,
218 pub height: u32,
219 pub data_len: u32,
220 }
222
223#[repr(C)]
225#[derive(Debug, Clone, Copy)]
226pub struct WindowGeometryRequest {
227 pub window_id: u64,
228}
229
230#[repr(C)]
232#[derive(Debug, Clone, Copy)]
233pub struct KeyEvent {
234 pub key_code: u32,
235 pub modifiers: u32,
236 pub pressed: bool,
237}
238
239#[repr(C)]
241#[derive(Debug, Clone, Copy)]
242pub struct MouseEvent {
243 pub x: i32,
244 pub y: i32,
245 pub button: u8,
246 pub pressed: bool,
247}
248
249#[repr(C)]
251#[derive(Debug, Clone, Copy)]
252pub struct ScrollEvent {
253 pub x: i32,
254 pub y: i32,
255 pub dx: i32,
256 pub dy: i32,
257}
258
259#[repr(C)]
261#[derive(Debug, Clone, Copy)]
262pub struct NotificationRequest {
263 pub urgency: u8,
264 pub timeout_ms: u32,
265 pub title_len: u32,
266 pub body_len: u32,
267 }
269
270#[repr(C)]
272#[derive(Debug, Clone, Copy)]
273pub struct ClipboardHeader {
274 pub mime_type_len: u32,
275 pub data_len: u32,
276 }
278
279pub mod helpers {
285 use super::*;
286
287 pub fn create_window_message(x: i32, y: i32, width: u32, height: u32, title: &str) -> Vec<u8> {
289 let mut data = Vec::new();
290
291 data.extend_from_slice(&(DesktopMessageType::CreateWindow as u32).to_le_bytes());
293
294 let req = CreateWindowRequest {
296 x,
297 y,
298 width,
299 height,
300 title_len: title.len() as u32,
301 };
302
303 unsafe {
308 let req_bytes = core::slice::from_raw_parts(
309 &req as *const _ as *const u8,
310 core::mem::size_of::<CreateWindowRequest>(),
311 );
312 data.extend_from_slice(req_bytes);
313 }
314
315 data.extend_from_slice(title.as_bytes());
317
318 data
319 }
320
321 pub fn parse_window_response(data: &[u8]) -> Result<u64, KernelError> {
323 if data.len() < core::mem::size_of::<CreateWindowResponse>() {
324 return Err(KernelError::InvalidArgument {
325 name: "response_size",
326 value: "too_small",
327 });
328 }
329
330 unsafe {
335 let resp = core::ptr::read_unaligned(data.as_ptr() as *const CreateWindowResponse);
336 Ok(resp.window_id)
337 }
338 }
339
340 pub fn keyboard_event_message(key_code: u32, modifiers: u32, pressed: bool) -> Vec<u8> {
342 let mut data = Vec::new();
343
344 let msg_type = if pressed {
346 DesktopMessageType::KeyPress
347 } else {
348 DesktopMessageType::KeyRelease
349 };
350 data.extend_from_slice(&(msg_type as u32).to_le_bytes());
351
352 let event = KeyEvent {
354 key_code,
355 modifiers,
356 pressed,
357 };
358
359 unsafe {
363 let event_bytes = core::slice::from_raw_parts(
364 &event as *const _ as *const u8,
365 core::mem::size_of::<KeyEvent>(),
366 );
367 data.extend_from_slice(event_bytes);
368 }
369
370 data
371 }
372
373 pub fn mouse_event_message(x: i32, y: i32, button: u8, pressed: bool) -> Vec<u8> {
375 let mut data = Vec::new();
376
377 data.extend_from_slice(&(DesktopMessageType::MouseMove as u32).to_le_bytes());
379
380 let event = MouseEvent {
382 x,
383 y,
384 button,
385 pressed,
386 };
387
388 unsafe {
392 let event_bytes = core::slice::from_raw_parts(
393 &event as *const _ as *const u8,
394 core::mem::size_of::<MouseEvent>(),
395 );
396 data.extend_from_slice(event_bytes);
397 }
398
399 data
400 }
401}
402
403pub struct DesktopIpcServer {
409 endpoints_registered: bool,
411 registered_count: u32,
413}
414
415impl DesktopIpcServer {
416 pub fn new() -> Self {
418 Self {
419 endpoints_registered: false,
420 registered_count: 0,
421 }
422 }
423
424 pub fn register_endpoints(&mut self) -> Result<(), KernelError> {
430 let kernel_pid = ProcessId(0);
431 let endpoints: &[(EndpointId, &str)] = &[
432 (DESKTOP_WM_ENDPOINT, "window_manager"),
433 (DESKTOP_INPUT_ENDPOINT, "input_server"),
434 (DESKTOP_COMPOSITOR_ENDPOINT, "compositor"),
435 (DESKTOP_NOTIFICATION_ENDPOINT, "notifications"),
436 (DESKTOP_CLIPBOARD_ENDPOINT, "clipboard"),
437 (DESKTOP_LAUNCHER_ENDPOINT, "launcher"),
438 ];
439
440 for &(id, name) in endpoints {
441 match crate::ipc::create_endpoint(kernel_pid) {
442 Ok((_endpoint_id, _cap)) => {
443 self.registered_count += 1;
444 crate::println!("[DESKTOP-IPC] Registered endpoint {} (ID {})", name, id);
445 }
446 Err(e) => {
447 crate::println!(
448 "[DESKTOP-IPC] Warning: failed to register {} (ID {}): {:?}",
449 name,
450 id,
451 e
452 );
453 }
454 }
455 }
456
457 self.endpoints_registered = true;
458 Ok(())
459 }
460
461 pub fn is_registered(&self) -> bool {
463 self.endpoints_registered
464 }
465
466 pub fn registered_count(&self) -> u32 {
468 self.registered_count
469 }
470}
471
472impl Default for DesktopIpcServer {
473 fn default() -> Self {
474 Self::new()
475 }
476}
477
478static DESKTOP_IPC: spin::Mutex<Option<DesktopIpcServer>> = spin::Mutex::new(None);
484
485pub fn is_initialized() -> bool {
487 DESKTOP_IPC
488 .lock()
489 .as_ref()
490 .is_some_and(|s| s.is_registered())
491}
492
493pub fn init() -> Result<(), KernelError> {
497 crate::println!("[DESKTOP-IPC] Initializing desktop IPC protocol...");
498
499 let mut server = DesktopIpcServer::new();
500 server.register_endpoints()?;
501
502 let count = server.registered_count();
503 *DESKTOP_IPC.lock() = Some(server);
504
505 crate::println!(
506 "[DESKTOP-IPC] Desktop IPC protocol initialized ({} endpoints)",
507 count
508 );
509 Ok(())
510}
511
512#[cfg(test)]
517mod tests {
518 use super::{helpers::*, *};
519
520 #[test]
521 fn test_create_window_message() {
522 let msg = create_window_message(100, 200, 800, 600, "Test Window");
523
524 assert!(msg.len() > core::mem::size_of::<CreateWindowRequest>());
526 }
527
528 #[test]
529 fn test_keyboard_event() {
530 let msg = keyboard_event_message(65, 0, true); assert_eq!(msg.len(), 4 + core::mem::size_of::<KeyEvent>());
534 }
535
536 #[test]
537 fn test_message_type_round_trip() {
538 let cases: &[DesktopMessageType] = &[
539 DesktopMessageType::CreateWindow,
540 DesktopMessageType::KeyPress,
541 DesktopMessageType::TerminalInput,
542 DesktopMessageType::SurfaceCommit,
543 DesktopMessageType::NotificationShow,
544 DesktopMessageType::ClipboardSet,
545 DesktopMessageType::LaunchApp,
546 DesktopMessageType::Success,
547 DesktopMessageType::Error,
548 ];
549 for &mt in cases {
550 let v = mt as u32;
551 assert_eq!(DesktopMessageType::from_u32(v), Some(mt));
552 }
553 }
554
555 #[test]
556 fn test_message_type_unknown() {
557 assert_eq!(DesktopMessageType::from_u32(0), None);
558 assert_eq!(DesktopMessageType::from_u32(9999), None);
559 }
560
561 #[test]
562 fn test_desktop_ipc_server_new() {
563 let server = DesktopIpcServer::new();
564 assert!(!server.is_registered());
565 assert_eq!(server.registered_count(), 0);
566 }
567
568 #[test]
569 fn test_endpoint_constants() {
570 assert_eq!(WINDOW_MANAGER_ENDPOINT, DESKTOP_WM_ENDPOINT);
572 assert_eq!(INPUT_SERVER_ENDPOINT, DESKTOP_INPUT_ENDPOINT);
573 assert_eq!(COMPOSITOR_ENDPOINT, DESKTOP_COMPOSITOR_ENDPOINT);
574
575 let ids = [
577 DESKTOP_WM_ENDPOINT,
578 DESKTOP_INPUT_ENDPOINT,
579 DESKTOP_COMPOSITOR_ENDPOINT,
580 DESKTOP_NOTIFICATION_ENDPOINT,
581 DESKTOP_CLIPBOARD_ENDPOINT,
582 DESKTOP_LAUNCHER_ENDPOINT,
583 ];
584 for i in 0..ids.len() {
585 for j in (i + 1)..ids.len() {
586 assert_ne!(ids[i], ids[j]);
587 }
588 }
589 }
590}