Use object oriented WlClient instead of WlState

This commit is contained in:
2025-04-22 18:32:35 -07:00
parent ad72c2855e
commit 2918fc9d30

View File

@@ -1,10 +1,10 @@
#![feature(unix_socket_ancillary_data)] #![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; use shm::shm::ShmPool;
mod shm; mod shm;
struct WlState { struct WlClient {
socket: UnixStream, socket: UnixStream,
current_id: u32, current_id: u32,
registry_id: Option<u32>, registry_id: Option<u32>,
@@ -12,6 +12,259 @@ struct WlState {
shm_pool: Option<ShmPool> shm_pool: Option<ShmPool>
} }
impl WlClient {
fn new() -> Result<Self, Box<dyn Error>> {
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<dyn Error>> {
// 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<UnixStream, Box<dyn Error>> {
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<u8>) {
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<dyn Error>> {
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<u8>) {
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<dyn Error>> {
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<u8>) -> Result<(), Box<dyn Error>> {
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 { struct WlHeader {
object: u32, object: u32,
opcode: u16, opcode: u16,
@@ -92,259 +345,16 @@ impl WlMessage for Vec<u8> {
} }
} }
fn wl_connect() -> Result<UnixStream, Box<dyn Error>> {
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<u8>) {
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<dyn Error>> {
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<u8>) {
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<dyn Error>> {
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<u8>, wl_state: &mut WlState) -> Result<(), Box<dyn Error>> {
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<dyn Error>> { fn main() -> Result<(), Box<dyn Error>> {
let wl_sock = match wl_connect() { let mut wl_client = WlClient::new()?;
Ok(res) => res,
Err(err) => {
eprintln!("wl_connect failed: {}", err);
return Err(err);
}
};
let mut wl_state = WlState { wl_client.wl_display_get_registry()?;
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<u8> = Vec::new();
let mut header = [0u8; 8];
loop { 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 { if false {
break break
} }