From 2918fc9d300ae1f982d28efd346179fbd7ffde5e Mon Sep 17 00:00:00 2001 From: chlorospingus Date: Tue, 22 Apr 2025 18:32:35 -0700 Subject: [PATCH] Use object oriented WlClient instead of WlState --- src/main.rs | 506 +++++++++++++++++++++++++++------------------------- 1 file changed, 258 insertions(+), 248 deletions(-) diff --git a/src/main.rs b/src/main.rs index d500473..c3edaba 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,10 @@ #![feature(unix_socket_ancillary_data)] -use std::{env, error::Error, io::{Read, Write}, os::unix::net::{UnixStream, SocketAncillary, AncillaryData}, u32}; +use std::{env, error::Error, io::{Read, Write}, os::unix::net::{UnixStream, SocketAncillary}, u32}; use shm::shm::ShmPool; mod shm; -struct WlState { +struct WlClient { socket: UnixStream, current_id: u32, registry_id: Option, @@ -12,6 +12,259 @@ struct WlState { shm_pool: Option } +impl WlClient { + fn new() -> Result> { + let sock = WlClient::connect()?; + + let res = WlClient { + socket: sock, + current_id: 1, + registry_id: None, + shm_id: None, + shm_pool: None, + }; + + Ok(res) + } + + fn read_event(&mut self) -> Result<(), Box> { + // TODO: Don't realloc header and event + + let mut header = vec![0u8; 8]; + self.socket.read_exact(&mut header)?; + + let header = WlHeader { + object: u32::from_ne_bytes(header[0..4].try_into()?), + opcode: u16::from_ne_bytes(header[4..6].try_into()?), + size: u16::from_ne_bytes(header[6..8].try_into()?) + }; + + let mut event = vec![0u8; header.size as usize - 8]; + self.socket.read_exact(&mut event)?; + + if header.object == self.registry_id.unwrap() && header.opcode == 0 { // wl_registry::global + self.wl_registry_global(&event)?; + } + else if header.object == 1 && header.opcode == 0 { // wl_display::error + WlClient::wl_display_error(&event); + } + else if self.shm_id.is_some() && header.object == self.shm_id.unwrap() && header.opcode == 0 { // wl_shm::format + WlClient::wl_shm_format(&event); + } + else { + println!( + "Received event:\n\tObject: {}\n\tOpcode: {}\n\tSize: {}", + header.object, + header.opcode, + header.size + ); + } + + Ok(()) + } + + fn connect() -> Result> { + let wl_sock_path: String = format!( + "{}/{}", + env::var("XDG_RUNTIME_DIR")?, + env::var("WAYLAND_DISPLAY")? + ); + let sock = UnixStream::connect(wl_sock_path)?; + + Ok(sock) + } + + fn wl_display_error(event: &Vec) { + let mut offset: usize = 0; + eprintln!( + "Received error:\n\tObject: {}\n\tCode: {}\n\tMessage: {}", + event.read_u32(&mut offset), + event.read_u32(&mut offset), + event.read_string(&mut offset) + ); + } + + fn wl_display_get_registry(&mut self) -> Result<(), Box> { + const OBJECT: u32 = 1; + const OPCODE: u16 = 1; + const MSG_SIZE: u16 = 12; + + let mut request = [0u8; MSG_SIZE as usize]; + request[0..4].copy_from_slice(&OBJECT.to_ne_bytes()); + request[4..6].copy_from_slice(&OPCODE.to_ne_bytes()); + request[6..8].copy_from_slice(&MSG_SIZE.to_ne_bytes()); + + self.current_id += 1; + request[8..12].copy_from_slice(&self.current_id.to_ne_bytes()); + self.registry_id = Some(self.current_id); + + let written = self.socket.write(&request)?; + assert!(written == MSG_SIZE.into()); + + Ok(()) + } + + fn wl_registry_bind( + &mut self, + name: &u32, + interface: &String, + version: &u32, + id: &u32 + ) -> Result<(), String> { + let object: u32 = match self.registry_id { + Some(id) => id, + None => return Err(String::from("wl_registry_bind failed: wl_state.registry_id not set!")) + }; + const OPCODE: u16 = 0; + + let req_size: u16 = 24 + ((interface.len() as u16+3) & (u16::MAX-3)); + let mut request = vec![0u8; req_size as usize]; + let mut offset: usize = 0; + + request.write_u32 (&object, &mut offset); + request.write_u16 (&OPCODE, &mut offset); + request.write_u16 (&req_size, &mut offset); + + request.write_u32 (&name, &mut offset); + request.write_string (&interface, &mut offset); + request.write_u32 (&version, &mut offset); + request.write_u32 (&id, &mut offset); + + match self.socket.write(&request) { + Ok(bytes) => { + assert!(bytes == req_size as usize) + } + Err(err) => { + return Err(err.to_string()); + } + }; + + Ok(()) + } + + fn wl_shm_format(event: &Vec) { + let mut offset = 0; + println!("Received pixel format: {:x}", event.read_u32(&mut offset)); + } + + fn wl_shm_create_pool(&mut self) -> Result<(), String> { + self.current_id += 1; + self.shm_pool = Some(match ShmPool::new(4096, self.current_id) { + Ok(val) => val, + Err(err) => { + return Err(err.to_string()); + } + }); + + let object = match self.shm_id { + Some(val) => val, + None => { + return Err("error in wl_shm_create_pool: shm_id not set!".to_string()); + } + }; + const OPCODE: u16 = 0; + const REQ_SIZE: u16 = 16; + let id = self.shm_pool.as_ref().unwrap().id; + let fds = [self.shm_pool.as_ref().unwrap().fd]; + let shm_size = self.shm_pool.as_ref().unwrap().size; + + let mut request = vec![0u8; REQ_SIZE as usize]; + let mut offset: usize = 0; + + // Request header + request.write_u32(&object, &mut offset); + request.write_u16(&OPCODE, &mut offset); + request.write_u16(&REQ_SIZE, &mut offset); + + // Id, size of shm pool + request.write_u32(&id, &mut offset); + request.write_u32(&(shm_size as u32), &mut offset); + + let mut ancillary_buf = [0u8; 32]; + let mut ancillary = SocketAncillary::new(&mut ancillary_buf[..]); + if !ancillary.add_fds(&fds[..]) { + return Err("Error in wl_shm_create_pool: ancillary.add_fds failed".to_string()); + } + + match self.socket.send_vectored_with_ancillary(&[std::io::IoSlice::new(&request)], &mut ancillary) { + Ok(bytes) => { + assert!(bytes == REQ_SIZE as usize); + } + Err(err) => { + return Err(err.to_string()); + } + }; + + Ok(()) + } + + fn wl_shm_pool_create_buffer( + &mut self, + shm_offset: u32, + width: u32, + height: u32 + ) -> Result<(), Box> { + let object: u32 = self.shm_pool.as_ref().unwrap().id; + const REQ_SIZE: u16 = 32; + const OPCODE: u16 = 0; + + let stride: u32 = width * 4; + self.current_id += 1; + let id = self.current_id; + let format = 0; + + let mut offset: usize = 0; + let mut request = vec![0u8; REQ_SIZE as usize]; + request.write_u32(&object, &mut offset); + request.write_u16(&OPCODE, &mut offset); + request.write_u16(&REQ_SIZE, &mut offset); + + request.write_u32(&id, &mut offset); + request.write_u32(&shm_offset, &mut offset); + request.write_u32(&width, &mut offset); + request.write_u32(&height, &mut offset); + request.write_u32(&stride, &mut offset); + request.write_u32(&format, &mut offset); + + println!("Creating wl_buffer: {:?}", request); + + self.socket.write(&request)?; + + Ok(()) + } + + fn wl_registry_global(&mut self, event: &Vec) -> Result<(), Box> { + let mut offset: usize = 0; + + let name = event.read_u32(&mut offset); + let interface = event.read_string(&mut offset); + let version = event.read_u32(&mut offset); + + println!( + "Received global:\n\tName: {}\n\tInterface: {}\n\tVersion: {}", + name, + interface, + version, + ); + + if interface == "wl_shm" { + self.current_id += 1; + self.wl_registry_bind( + &name, + &interface, + &version, + &self.current_id.clone() + )?; + self.shm_id = Some(self.current_id); + + self.wl_shm_create_pool()?; + self.wl_shm_pool_create_buffer(0, 200, 200)?; + } + + Ok(()) + } +} + struct WlHeader { object: u32, opcode: u16, @@ -92,259 +345,16 @@ impl WlMessage for Vec { } } -fn wl_connect() -> Result> { - let wl_sock_path: String = format!( - "{}/{}", - env::var("XDG_RUNTIME_DIR")?, - env::var("WAYLAND_DISPLAY")? - ); - let sock = UnixStream::connect(wl_sock_path)?; - Ok(sock) -} - -fn wl_display_error(event: &Vec) { - let mut offset: usize = 0; - eprintln!( - "Received error:\n\tObject: {}\n\tCode: {}\n\tMessage: {}", - event.read_u32(&mut offset), - event.read_u32(&mut offset), - event.read_string(&mut offset) - ); -} - -fn wl_display_get_registry(wl_state: &mut WlState) -> Result<(), Box> { - const OBJECT: u32 = 1; - const OPCODE: u16 = 1; - const MSG_SIZE: u16 = 12; - - let mut request = [0u8; MSG_SIZE as usize]; - request[0..4].copy_from_slice(&OBJECT.to_ne_bytes()); - request[4..6].copy_from_slice(&OPCODE.to_ne_bytes()); - request[6..8].copy_from_slice(&MSG_SIZE.to_ne_bytes()); - - wl_state.current_id += 1; - request[8..12].copy_from_slice(&wl_state.current_id.to_ne_bytes()); - wl_state.registry_id = Some(wl_state.current_id); - - let written = wl_state.socket.write(&request)?; - assert!(written == MSG_SIZE.into()); - - Ok(()) -} - -fn wl_registry_bind( - wl_state: &mut WlState, - name: &u32, - interface: &String, - version: &u32, - id: &u32 -) -> Result<(), String> { - let object: u32 = match wl_state.registry_id { - Some(id) => id, - None => return Err(String::from("wl_registry_bind failed: wl_state.registry_id not set!")) - }; - const OPCODE: u16 = 0; - - let req_size: u16 = 24 + ((interface.len() as u16+3) & (u16::MAX-3)); - let mut request = vec![0u8; req_size as usize]; - let mut offset: usize = 0; - - request.write_u32 (&object, &mut offset); - request.write_u16 (&OPCODE, &mut offset); - request.write_u16 (&req_size, &mut offset); - - request.write_u32 (&name, &mut offset); - request.write_string (&interface, &mut offset); - request.write_u32 (&version, &mut offset); - request.write_u32 (&id, &mut offset); - - match wl_state.socket.write(&request) { - Ok(bytes) => { - assert!(bytes == req_size as usize) - } - Err(err) => { - return Err(err.to_string()); - } - }; - - Ok(()) -} - -fn wl_shm_format(event: &Vec) { - let mut offset = 0; - println!("Received pixel format: {:x}", event.read_u32(&mut offset)); -} - -fn wl_shm_create_pool(wl_state: &mut WlState) -> Result<(), String> { - wl_state.current_id += 1; - wl_state.shm_pool = Some(match ShmPool::new(4096, wl_state.current_id) { - Ok(val) => val, - Err(err) => { - return Err(err.to_string()); - } - }); - - let object = match wl_state.shm_id { - Some(val) => val, - None => { - return Err("error in wl_shm_create_pool: shm_id not set!".to_string()); - } - }; - const OPCODE: u16 = 0; - const REQ_SIZE: u16 = 16; - let id = wl_state.shm_pool.as_ref().unwrap().id; - let fds = [wl_state.shm_pool.as_ref().unwrap().fd]; - let shm_size = wl_state.shm_pool.as_ref().unwrap().size; - - let mut request = vec![0u8; REQ_SIZE as usize]; - let mut offset: usize = 0; - - // Request header - request.write_u32(&object, &mut offset); - request.write_u16(&OPCODE, &mut offset); - request.write_u16(&REQ_SIZE, &mut offset); - - // Id, size of shm pool - request.write_u32(&id, &mut offset); - request.write_u32(&(shm_size as u32), &mut offset); - - let mut ancillary_buf = [0u8; 32]; - let mut ancillary = SocketAncillary::new(&mut ancillary_buf[..]); - if !ancillary.add_fds(&fds[..]) { - return Err("Error in wl_shm_create_pool: ancillary.add_fds failed".to_string()); - } - - match wl_state.socket.send_vectored_with_ancillary(&[std::io::IoSlice::new(&request)], &mut ancillary) { - Ok(bytes) => { - assert!(bytes == REQ_SIZE as usize); - } - Err(err) => { - return Err(err.to_string()); - } - }; - - Ok(()) -} - -fn wl_shm_pool_create_buffer( - wl_state: &mut WlState, - shm_offset: u32, - width: u32, - height: u32 -) -> Result<(), Box> { - let object: u32 = wl_state.shm_pool.as_ref().unwrap().id; - const REQ_SIZE: u16 = 32; - const OPCODE: u16 = 0; - - let stride: u32 = width * 4; - wl_state.current_id += 1; - let id = wl_state.current_id; - let format = 0; - - let mut offset: usize = 0; - let mut request = vec![0u8; REQ_SIZE as usize]; - request.write_u32(&object, &mut offset); - request.write_u16(&OPCODE, &mut offset); - request.write_u16(&REQ_SIZE, &mut offset); - - request.write_u32(&id, &mut offset); - request.write_u32(&shm_offset, &mut offset); - request.write_u32(&width, &mut offset); - request.write_u32(&height, &mut offset); - request.write_u32(&stride, &mut offset); - request.write_u32(&format, &mut offset); - - println!("Creating wl_buffer: {:?}", request); - - wl_state.socket.write(&request)?; - - Ok(()) -} - -fn wl_registry_global(event: &Vec, wl_state: &mut WlState) -> Result<(), Box> { - let mut offset: usize = 0; - - let name = event.read_u32(&mut offset); - let interface = event.read_string(&mut offset); - let version = event.read_u32(&mut offset); - - println!( - "Received global:\n\tName: {}\n\tInterface: {}\n\tVersion: {}", - name, - interface, - version, - ); - - if interface == "wl_shm" { - wl_state.current_id += 1; - wl_registry_bind( - wl_state, - &name, - &interface, - &version, - &wl_state.current_id.clone() - )?; - wl_state.shm_id = Some(wl_state.current_id); - - wl_shm_create_pool(wl_state)?; - wl_shm_pool_create_buffer(wl_state, 0, 200, 200)?; - } - - Ok(()) -} fn main() -> Result<(), Box> { - let wl_sock = match wl_connect() { - Ok(res) => res, - Err(err) => { - eprintln!("wl_connect failed: {}", err); - return Err(err); - } - }; + let mut wl_client = WlClient::new()?; - let mut wl_state = WlState { - socket: wl_sock, - current_id: 1, - registry_id: None, - shm_id: None, - shm_pool: None, - }; - - wl_display_get_registry(&mut wl_state)?; - - let mut event: Vec = Vec::new(); - let mut header = [0u8; 8]; + wl_client.wl_display_get_registry()?; loop { - wl_state.socket.read_exact(&mut header)?; + wl_client.read_event()?; - let header = WlHeader { - object: u32::from_ne_bytes(header[0..4].try_into()?), - opcode: u16::from_ne_bytes(header[4..6].try_into()?), - size: u16::from_ne_bytes(header[6..8].try_into()?) - }; - - event.resize((header.size-8) as usize, 0); - wl_state.socket.read_exact(&mut event)?; - - if header.object == wl_state.registry_id.unwrap() && header.opcode == 0 { - wl_registry_global(&event, &mut wl_state)?; - } - else if header.object == 1 && header.opcode == 0 { // wl_display::error - wl_display_error(&event); - } - else if wl_state.shm_id.is_some() && header.object == wl_state.shm_id.unwrap() && header.opcode == 0 { // wl_shm::format - wl_shm_format(&event); - } - else { - println!( - "Received event:\n\tObject: {}\n\tOpcode: {}\n\tSize: {}", - header.object, - header.opcode, - header.size - ); - } if false { break }