Separate methods of WlClient into multiple files for different wayland protocols
- WlMessage trait and impl for Vec moved to vec_utils.rs - wl_shm_format, wl_shm_create_pool, and wl_shm_pool_create_buffer moved to wl_shm.rs - wl_display_error, wl_display_get_registry, wl_registry_global, and wl_registry_bind moved to wl_registry.rs - WlClient definition, WlClient::new, and WlClient.read_event moved to wl_client.rs
This commit is contained in:
351
src/main.rs
351
src/main.rs
@@ -1,351 +1,12 @@
|
|||||||
#![feature(unix_socket_ancillary_data)]
|
#![feature(unix_socket_ancillary_data)]
|
||||||
use std::{env, error::Error, io::{Read, Write}, os::unix::net::{UnixStream, SocketAncillary}, u32};
|
use std::error::Error;
|
||||||
|
|
||||||
use shm::shm::ShmPool;
|
mod wl_client;
|
||||||
|
mod wl_registry;
|
||||||
|
mod wl_shm;
|
||||||
|
mod vec_utils;
|
||||||
mod shm;
|
mod shm;
|
||||||
|
use wl_client::WlClient;
|
||||||
struct WlClient {
|
|
||||||
socket: UnixStream,
|
|
||||||
current_id: u32,
|
|
||||||
registry_id: Option<u32>,
|
|
||||||
shm_id: Option<u32>,
|
|
||||||
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 {
|
|
||||||
object: u32,
|
|
||||||
opcode: u16,
|
|
||||||
size: u16
|
|
||||||
}
|
|
||||||
|
|
||||||
trait WlMessage {
|
|
||||||
/// Write a u32 to self at offset and increment offset by four
|
|
||||||
fn write_u32(&mut self, value: &u32, offset: &mut usize);
|
|
||||||
/// Write a u16 to self at offset and increment offset by four
|
|
||||||
fn write_u16(&mut self, value: &u16, offset: &mut usize);
|
|
||||||
/// Write a string to self at offset
|
|
||||||
/// and increment offset by string length rounded up to four bytes
|
|
||||||
fn write_string(&mut self, str: &String, offset: &mut usize);
|
|
||||||
/// Read a u32 from self at offset and increment offset by four
|
|
||||||
fn read_u32(&self, offset: &mut usize) -> u32;
|
|
||||||
/// Read a u16 from self at offset and increment offset by two
|
|
||||||
fn read_u16(&self, offset: &mut usize) -> u16;
|
|
||||||
/// Read a string from self at offset
|
|
||||||
/// and increment offset by string length rounded up to four bytes
|
|
||||||
fn read_string(&self, offset: &mut usize) -> String;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WlMessage for Vec<u8> {
|
|
||||||
fn write_u32(&mut self, value: &u32, offset: &mut usize) {
|
|
||||||
self[*offset..*offset+4].copy_from_slice(&value.to_ne_bytes());
|
|
||||||
*offset += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_u16(&mut self, value: &u16, offset: &mut usize) {
|
|
||||||
self[*offset..*offset+2].copy_from_slice(&value.to_ne_bytes());
|
|
||||||
*offset += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_string(&mut self, str: &String, offset: &mut usize) {
|
|
||||||
let mut str = str.clone();
|
|
||||||
str.push('\0');
|
|
||||||
let rounded_len: u32 = (str.len()+3) as u32 & (u32::MAX-3);
|
|
||||||
self.write_u32(&rounded_len, offset);
|
|
||||||
self[*offset..*offset+str.len()].copy_from_slice(str.as_bytes());
|
|
||||||
*offset += rounded_len as usize;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_u32(&self, offset: &mut usize) -> u32 {
|
|
||||||
let res = u32::from_ne_bytes(
|
|
||||||
self[*offset..*offset+4]
|
|
||||||
.try_into()
|
|
||||||
.expect("u32::from_ne_bytes failed in WlEvent::read_u32")
|
|
||||||
);
|
|
||||||
*offset += 4;
|
|
||||||
res
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_u16(&self, offset: &mut usize) -> u16 {
|
|
||||||
let res = u16::from_ne_bytes(
|
|
||||||
self[*offset..*offset+2]
|
|
||||||
.try_into()
|
|
||||||
.expect("u32::from_ne_bytes failed in WlEvent::read_u32")
|
|
||||||
);
|
|
||||||
*offset += 2;
|
|
||||||
res
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_string(&self, offset: &mut usize) -> String {
|
|
||||||
let str_len = u32::from_ne_bytes(
|
|
||||||
self[*offset..*offset+4]
|
|
||||||
.try_into()
|
|
||||||
.expect("u32::from_ne_bytes failed in WlEvent::read_string")
|
|
||||||
);
|
|
||||||
*offset += 4;
|
|
||||||
let str = String::from_utf8(
|
|
||||||
self[*offset..*offset+((str_len-1) as usize)]
|
|
||||||
.to_vec())
|
|
||||||
.expect("String::from_utf8 failed in WlEvent::read_string()"
|
|
||||||
);
|
|
||||||
*offset += (str_len+3 & u32::MAX-3) as usize;
|
|
||||||
str
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
let mut wl_client = WlClient::new()?;
|
let mut wl_client = WlClient::new()?;
|
||||||
|
|||||||
18
src/shm.rs
18
src/shm.rs
@@ -1,16 +1,14 @@
|
|||||||
pub mod shm {
|
use libc::{c_void, ftruncate, mmap, munmap, shm_open, shm_unlink, MAP_FAILED, MAP_SHARED, O_CREAT, O_EXCL, O_RDWR, PROT_READ};
|
||||||
|
|
||||||
use libc::{c_void, ftruncate, mmap, munmap, shm_open, shm_unlink, MAP_FAILED, MAP_SHARED, O_CREAT, O_EXCL, O_RDWR, PROT_READ};
|
#[derive(Clone)]
|
||||||
|
pub struct ShmPool {
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct ShmPool {
|
|
||||||
pub fd: i32,
|
pub fd: i32,
|
||||||
pub id: u32,
|
pub id: u32,
|
||||||
pub addr: *mut c_void,
|
pub addr: *mut c_void,
|
||||||
pub size: usize,
|
pub size: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ShmPool {
|
impl ShmPool {
|
||||||
pub fn new(size: usize, id: u32) -> std::io::Result<ShmPool> {
|
pub fn new(size: usize, id: u32) -> std::io::Result<ShmPool> {
|
||||||
let shm_path: *const i8 = b"/chlorostart\0".as_ptr() as *const i8;
|
let shm_path: *const i8 = b"/chlorostart\0".as_ptr() as *const i8;
|
||||||
let fd = unsafe { shm_open(shm_path, O_RDWR | O_EXCL | O_CREAT, 0o600) };
|
let fd = unsafe { shm_open(shm_path, O_RDWR | O_EXCL | O_CREAT, 0o600) };
|
||||||
@@ -51,12 +49,10 @@ pub mod shm {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for ShmPool {
|
impl Drop for ShmPool {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe { munmap(self.addr, self.size); }
|
unsafe { munmap(self.addr, self.size); }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
73
src/vec_utils.rs
Normal file
73
src/vec_utils.rs
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
|
||||||
|
pub trait WlMessage {
|
||||||
|
/// Write a u32 to self at offset and increment offset by four
|
||||||
|
fn write_u32(&mut self, value: &u32, offset: &mut usize);
|
||||||
|
/// Write a u16 to self at offset and increment offset by four
|
||||||
|
fn write_u16(&mut self, value: &u16, offset: &mut usize);
|
||||||
|
/// Write a string to self at offset
|
||||||
|
/// and increment offset by string length rounded up to four bytes
|
||||||
|
fn write_string(&mut self, str: &String, offset: &mut usize);
|
||||||
|
/// Read a u32 from self at offset and increment offset by four
|
||||||
|
fn read_u32(&self, offset: &mut usize) -> u32;
|
||||||
|
/// Read a u16 from self at offset and increment offset by two
|
||||||
|
fn read_u16(&self, offset: &mut usize) -> u16;
|
||||||
|
/// Read a string from self at offset
|
||||||
|
/// and increment offset by string length rounded up to four bytes
|
||||||
|
fn read_string(&self, offset: &mut usize) -> String;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WlMessage for Vec<u8> {
|
||||||
|
fn write_u32(&mut self, value: &u32, offset: &mut usize) {
|
||||||
|
self[*offset..*offset+4].copy_from_slice(&value.to_ne_bytes());
|
||||||
|
*offset += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_u16(&mut self, value: &u16, offset: &mut usize) {
|
||||||
|
self[*offset..*offset+2].copy_from_slice(&value.to_ne_bytes());
|
||||||
|
*offset += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_string(&mut self, str: &String, offset: &mut usize) {
|
||||||
|
let mut str = str.clone();
|
||||||
|
str.push('\0');
|
||||||
|
let rounded_len: u32 = (str.len()+3) as u32 & (u32::MAX-3);
|
||||||
|
self.write_u32(&rounded_len, offset);
|
||||||
|
self[*offset..*offset+str.len()].copy_from_slice(str.as_bytes());
|
||||||
|
*offset += rounded_len as usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_u32(&self, offset: &mut usize) -> u32 {
|
||||||
|
let res = u32::from_ne_bytes(
|
||||||
|
self[*offset..*offset+4]
|
||||||
|
.try_into()
|
||||||
|
.expect("u32::from_ne_bytes failed in WlEvent::read_u32")
|
||||||
|
);
|
||||||
|
*offset += 4;
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_u16(&self, offset: &mut usize) -> u16 {
|
||||||
|
let res = u16::from_ne_bytes(
|
||||||
|
self[*offset..*offset+2]
|
||||||
|
.try_into()
|
||||||
|
.expect("u32::from_ne_bytes failed in WlEvent::read_u32")
|
||||||
|
);
|
||||||
|
*offset += 2;
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_string(&self, offset: &mut usize) -> String {
|
||||||
|
let str_len = u32::from_ne_bytes(
|
||||||
|
self[*offset..*offset+4]
|
||||||
|
.try_into()
|
||||||
|
.expect("u32::from_ne_bytes failed in WlEvent::read_string")
|
||||||
|
);
|
||||||
|
*offset += 4;
|
||||||
|
let str = String::from_utf8(
|
||||||
|
self[*offset..*offset+((str_len-1) as usize)]
|
||||||
|
.to_vec()
|
||||||
|
).expect("String::from_utf8 failed in WlEvent::read_string()");
|
||||||
|
*offset += (str_len+3 & u32::MAX-3) as usize;
|
||||||
|
str
|
||||||
|
}
|
||||||
|
}
|
||||||
74
src/wl_client.rs
Normal file
74
src/wl_client.rs
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
use std::{env::var, error::Error, io::Read, os::unix::net::UnixStream, u32};
|
||||||
|
|
||||||
|
use crate::shm;
|
||||||
|
|
||||||
|
struct WlHeader {
|
||||||
|
object: u32,
|
||||||
|
opcode: u16,
|
||||||
|
size: u16
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct WlClient {
|
||||||
|
pub socket: UnixStream,
|
||||||
|
pub current_id: u32,
|
||||||
|
pub registry_id: Option<u32>,
|
||||||
|
pub shm_id: Option<u32>,
|
||||||
|
pub shm_pool: Option<shm::ShmPool>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WlClient {
|
||||||
|
pub fn new() -> Result<Self, Box<dyn Error>> {
|
||||||
|
let sock = UnixStream::connect(format!(
|
||||||
|
"{}/{}",
|
||||||
|
var("XDG_RUNTIME_DIR")?,
|
||||||
|
var("WAYLAND_DISPLAY")?
|
||||||
|
))?;
|
||||||
|
|
||||||
|
let res = WlClient {
|
||||||
|
socket: sock,
|
||||||
|
current_id: 1,
|
||||||
|
registry_id: None,
|
||||||
|
shm_id: None,
|
||||||
|
shm_pool: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub 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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
105
src/wl_registry.rs
Normal file
105
src/wl_registry.rs
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
use crate::{WlClient, vec_utils::WlMessage};
|
||||||
|
use std::{io::Write, error::Error};
|
||||||
|
|
||||||
|
impl WlClient {
|
||||||
|
pub 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 = vec![0u8; MSG_SIZE as usize];
|
||||||
|
let mut offset: usize = 0;
|
||||||
|
|
||||||
|
request.write_u32(&OBJECT, &mut offset);
|
||||||
|
request.write_u16(&OPCODE, &mut offset);
|
||||||
|
request.write_u16(&MSG_SIZE, &mut offset);
|
||||||
|
|
||||||
|
self.current_id += 1;
|
||||||
|
request.write_u32(&self.current_id, &mut offset);
|
||||||
|
self.registry_id = Some(self.current_id);
|
||||||
|
|
||||||
|
let written = self.socket.write(&request)?;
|
||||||
|
assert!(written == MSG_SIZE.into());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub 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(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub 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(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub 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)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
95
src/wl_shm.rs
Normal file
95
src/wl_shm.rs
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
use std::{io::Write, error::Error, os::unix::net::SocketAncillary};
|
||||||
|
use crate::{WlClient, vec_utils::WlMessage, shm};
|
||||||
|
|
||||||
|
impl WlClient {
|
||||||
|
pub fn wl_shm_format(event: &Vec<u8>) {
|
||||||
|
let mut offset = 0;
|
||||||
|
println!("Received pixel format: {:x}", event.read_u32(&mut offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn wl_shm_create_pool(&mut self) -> Result<(), String> {
|
||||||
|
self.current_id += 1;
|
||||||
|
self.shm_pool = Some(match shm::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(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub 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);
|
||||||
|
|
||||||
|
self.socket.write(&request)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user