//! Test 5 — Wayland handshake server/client sur Redox. //! //! Valide que wayland-rs (server + client + backend) ne se contente pas de //! compiler pour Redox mais fonctionne réellement à l'exécution : //! //! 1. Serveur Wayland local + globals (wl_compositor, wl_shm) //! 2. socketpair AF_UNIX, on insère le côté serveur via insert_client //! 3. Client Wayland connecté sur l'autre côté via WAYLAND_SOCKET fd env //! 4. Client fait wl_display.get_registry, dispatch //! 5. On vérifie que les globals attendus arrivent côté client //! //! Si ça passe, le port wayland-rs sur Redox est validé runtime, pas juste //! compile-time. use std::os::unix::net::UnixStream; use std::process::ExitCode; use std::sync::Arc; use wayland_client::{ Connection as ClientConnection, Dispatch as ClientDispatch, EventQueue, backend::Backend as ClientBackend, protocol::wl_registry, }; use wayland_server::{ Display as ServerDisplay, GlobalDispatch, New, backend::ClientData, protocol::{wl_compositor, wl_shm}, }; // ---- Server side ---- struct ServerState; #[derive(Debug)] struct DumbClientData; impl ClientData for DumbClientData {} impl GlobalDispatch for ServerState { fn bind( _state: &mut Self, _handle: &wayland_server::DisplayHandle, _client: &wayland_server::Client, _resource: New, _data: &(), _data_init: &mut wayland_server::DataInit<'_, Self>, ) { } } impl wayland_server::Dispatch for ServerState { fn request( _state: &mut Self, _client: &wayland_server::Client, _resource: &wl_compositor::WlCompositor, _request: wl_compositor::Request, _data: &(), _dh: &wayland_server::DisplayHandle, _data_init: &mut wayland_server::DataInit<'_, Self>, ) { } } impl GlobalDispatch for ServerState { fn bind( _state: &mut Self, _handle: &wayland_server::DisplayHandle, _client: &wayland_server::Client, _resource: New, _data: &(), _data_init: &mut wayland_server::DataInit<'_, Self>, ) { } } impl wayland_server::Dispatch for ServerState { fn request( _state: &mut Self, _client: &wayland_server::Client, _resource: &wl_shm::WlShm, _request: wl_shm::Request, _data: &(), _dh: &wayland_server::DisplayHandle, _data_init: &mut wayland_server::DataInit<'_, Self>, ) { } } // ---- Client side ---- #[derive(Default, Debug)] struct ClientState { globals: Vec<(u32, String, u32)>, done: bool, } impl ClientDispatch for ClientState { fn event( state: &mut Self, _registry: &wl_registry::WlRegistry, event: wl_registry::Event, _data: &(), _conn: &ClientConnection, _qhandle: &wayland_client::QueueHandle, ) { if let wl_registry::Event::Global { name, interface, version } = event { println!("[test-05 CLIENT] global #{name}: {interface} v{version}"); state.globals.push((name, interface, version)); } } } fn run() -> Result<(), Box> { println!("[test-05] wayland-rs handshake server/client on Redox"); // -- Server setup -- let mut server_display: ServerDisplay = ServerDisplay::new()?; let mut dh = server_display.handle(); dh.create_global::(5, ()); dh.create_global::(1, ()); println!("[test-05 SERVER] created wl_compositor v5 + wl_shm v1 globals"); // -- Socket linking -- let (s_server, s_client) = UnixStream::pair()?; s_server.set_nonblocking(true)?; let _client_handle = dh.insert_client(s_server, Arc::new(DumbClientData))?; println!("[test-05] linked server side via insert_client"); // -- Client setup using the other end of the socketpair -- let client_backend = ClientBackend::connect(s_client)?; let client_conn = ClientConnection::from_backend(client_backend); let mut event_queue: EventQueue = client_conn.new_event_queue(); let qhandle = event_queue.handle(); let _registry = client_conn.display().get_registry(&qhandle, ()); println!("[test-05 CLIENT] called get_registry, dispatching..."); let mut server_state = ServerState; let mut client_state = ClientState::default(); // -- Roundtrip: dispatch alternately until client has events -- for round in 0..10 { // server side server_display.dispatch_clients(&mut server_state)?; server_display.flush_clients()?; // client side let _ = event_queue.flush(); let processed = event_queue.dispatch_pending(&mut client_state)?; if processed > 0 { println!("[test-05] round {round}: client processed {processed} event(s)"); } if !client_state.globals.is_empty() { client_state.done = true; break; } // Block briefly waiting for incoming events on client side match event_queue.prepare_read() { Some(read_guard) => { let _ = read_guard.read(); } None => {} } } if !client_state.done || client_state.globals.is_empty() { return Err(format!( "client did not receive globals (got {})", client_state.globals.len() ) .into()); } let names: Vec<&str> = client_state.globals.iter().map(|(_, n, _)| n.as_str()).collect(); let has_compositor = names.contains(&"wl_compositor"); let has_shm = names.contains(&"wl_shm"); if !has_compositor || !has_shm { return Err(format!("missing expected globals: got {:?}", names).into()); } println!( "[test-05] received {} global(s): {:?}", client_state.globals.len(), names ); Ok(()) } fn main() -> ExitCode { match run() { Ok(()) => { println!("[test-05] PASS: wayland-rs server/client handshake works on Redox"); ExitCode::SUCCESS } Err(e) => { eprintln!("[test-05] FAIL: {e}"); ExitCode::FAILURE } } }