From a7c295631393618f13fdf3ecebf175f94f1820cb Mon Sep 17 00:00:00 2001 From: chlorospingus Date: Fri, 9 May 2025 01:45:37 -0700 Subject: [PATCH] mmap fd received from wl_keyboard.keymap --- src/main.rs | 2 +- src/wayland/layer_shell.rs | 2 +- src/wayland/mod.rs | 1 + src/wayland/seat.rs | 78 ++++++++++++++++++++++++++++ src/wayland/shm.rs | 13 +++-- src/wayland/wl_client.rs | 103 +++++++++++++++++++++++++++++++++---- src/wayland/wl_registry.rs | 58 ++++++++------------- src/wayland/wl_shm.rs | 10 ++-- 8 files changed, 211 insertions(+), 56 deletions(-) create mode 100644 src/wayland/seat.rs diff --git a/src/main.rs b/src/main.rs index 16d7a8c..21fe521 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,5 @@ #![feature(unix_socket_ancillary_data)] -use std::error::Error; +use std::{error::Error, thread, time::Duration}; mod wayland; use wayland::wl_client::WlClient; diff --git a/src/wayland/layer_shell.rs b/src/wayland/layer_shell.rs index 4dcc3b7..646cd68 100644 --- a/src/wayland/layer_shell.rs +++ b/src/wayland/layer_shell.rs @@ -3,7 +3,7 @@ use crate::wayland::{surface::UnsetErr, vec_utils::WlMessage, wl_client::WlClien const NAMESPACE: &str = "chlorostart"; const OVERLAY: u32 = 3; -const EXCLUSIVE: u32 = 0; // exclusize keyboard focus +const EXCLUSIVE: u32 = 1; // exclusize keyboard focus impl WlClient { pub fn layer_shell_get_layer_surface(&self) -> Result<(), Box> { diff --git a/src/wayland/mod.rs b/src/wayland/mod.rs index e479b53..6d654b5 100644 --- a/src/wayland/mod.rs +++ b/src/wayland/mod.rs @@ -6,3 +6,4 @@ pub mod wl_shm; pub mod vec_utils; pub mod shm; pub mod wl_registry; +pub mod seat; diff --git a/src/wayland/seat.rs b/src/wayland/seat.rs new file mode 100644 index 0000000..a1c9fb0 --- /dev/null +++ b/src/wayland/seat.rs @@ -0,0 +1,78 @@ +#![feature(unix_socket_ancillary_data)] + +use std::{error::Error, io::{IoSliceMut, Write}, os::unix::net::{AncillaryData, SocketAncillary}, sync::atomic::Ordering}; + +use crate::wayland::{shm, vec_utils::WlMessage, wl_client::WlClient, surface::UnsetErr}; + + +impl WlClient { + pub fn wl_seat_capabilities(&self, event: &Vec) -> Result<(), Box> { + let mut offset: usize = 0; + let capability = event.read_u32(&mut offset); + println!( + "Received seat capabilities:\n\tPointer: {}\n\tKeyboard: {}\n\tTouch: {}", + (capability & 1) > 0, + (capability & 2) > 0, + (capability & 4) > 0, + ); + if (capability & 2) > 0 { + self.wl_seat_get_keyboard()?; + } + + Ok(()) + } + + pub fn wl_seat_name(&self, event: &Vec) { + let mut offset: usize = 0; + let name = event.read_string(&mut offset); + println!("Recieved seat name: {}", name); + } + + pub fn wl_seat_get_keyboard(&self) -> Result<(), Box> { + let object = self.seat_id.load(Ordering::Relaxed); + if object == 0 { + return Err(UnsetErr("keyboard_id".to_string()).into()) + } + 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); + + let current_id = self.current_id.fetch_add(1, Ordering::Relaxed) + 1; + self.keyboard_id.store(current_id, Ordering::Relaxed); + request.write_u32(¤t_id, &mut offset); + + self.socket.lock().unwrap().write(&request)?; + + Ok(()) + } + + pub fn wl_keyboard_keymap(&self, event: &Vec, fd: i32) -> Result<(), Box>{ + let mut offset: usize = 0; + let format = event.read_u32(&mut offset); + let size = event.read_u32(&mut offset); + + *self.keymap.lock().unwrap() = Some(shm::ShmPool::from_fd(fd, size as usize)?); + + Ok(()) + } + + pub fn wl_keyboard_key(&self, event: &Vec) { + let mut offset: usize = 0; + let serial = event.read_u32(&mut offset); + let time = event.read_u32(&mut offset); + let key = event.read_u32(&mut offset); + let state = event.read_u32(&mut offset); + println!( + "Received key:\n\tSerial: {}\n\tTime: {}\n\tKey: {}\n\tState: {}", + serial, + time, + key, + state + ) + } +} diff --git a/src/wayland/shm.rs b/src/wayland/shm.rs index 3309585..d647d4b 100644 --- a/src/wayland/shm.rs +++ b/src/wayland/shm.rs @@ -1,9 +1,8 @@ -use libc::{c_void, ftruncate, mmap, munmap, shm_open, shm_unlink, MAP_FAILED, MAP_SHARED, O_CREAT, O_EXCL, O_RDWR, PROT_READ, PROT_WRITE}; +use libc::{c_void, ftruncate, mmap, munmap, shm_open, shm_unlink, MAP_FAILED, MAP_PRIVATE, MAP_SHARED, O_CREAT, O_EXCL, O_RDWR, PROT_READ, PROT_WRITE}; #[derive(Clone)] pub struct ShmPool { pub fd: i32, - pub id: u32, pub addr: *mut c_void, pub size: usize, pub width: usize, @@ -38,13 +37,21 @@ impl ShmPool { Ok(ShmPool { fd, - id, addr, size, width, }) } + pub fn from_fd(fd: i32, size: usize) -> std::io::Result { + let addr = unsafe { mmap(std::ptr::null_mut(), size, PROT_READ, MAP_PRIVATE, fd, 0) }; + if addr == MAP_FAILED { + eprint!("mmap in ShmPool::from_fd() failed: "); + return Err(std::io::Error::last_os_error()); + } + Ok(ShmPool {fd, addr, size, width: 0}) + } + pub fn resize(&mut self, size: usize) -> std::io::Result<()> { if unsafe { ftruncate(self.fd, size as i64) } == -1 { return Err(std::io::Error::last_os_error()) diff --git a/src/wayland/wl_client.rs b/src/wayland/wl_client.rs index 0c24869..57a6d4e 100644 --- a/src/wayland/wl_client.rs +++ b/src/wayland/wl_client.rs @@ -1,4 +1,6 @@ -use std::{env::var, error::Error, fmt::Debug, io::Read, os::unix::net::UnixStream, sync::{atomic::{AtomicU32, Ordering}, Arc, Mutex}, thread::{self, JoinHandle}, u32}; +#![feature(unix_socket_ancillary_data)] + +use std::{env::var, error::Error, fmt::Debug, io::{IoSliceMut, Read}, os::unix::net::{AncillaryData, SocketAncillary, UnixStream}, sync::{atomic::{AtomicU32, Ordering}, Arc, Mutex}, thread::{self, JoinHandle}, u32}; use crate::wayland::shm; @@ -13,6 +15,7 @@ pub struct WlClient { pub current_id: AtomicU32, pub registry_id: AtomicU32, pub shm_id: AtomicU32, + pub shmpool_id: AtomicU32, pub shm_pool: Mutex>, pub buffer_id: AtomicU32, pub compositor_id: AtomicU32, @@ -20,10 +23,13 @@ pub struct WlClient { pub xdg_wm_base_id: AtomicU32, pub layer_shell_id: AtomicU32, pub layer_surface_id: AtomicU32, + pub seat_id: AtomicU32, + pub keyboard_id: AtomicU32, + pub keymap: Mutex>, } impl WlClient { - pub fn run() -> Result, Box> { + pub fn run() -> Result<(), Box> { let sock = UnixStream::connect(format!( "{}/{}", var("XDG_RUNTIME_DIR")?, @@ -35,6 +41,7 @@ impl WlClient { current_id: AtomicU32::from(1), registry_id: AtomicU32::from(0), shm_id: AtomicU32::from(0), + shmpool_id: AtomicU32::from(0), shm_pool: Mutex::new(None), buffer_id: AtomicU32::from(0), compositor_id: AtomicU32::from(0), @@ -42,6 +49,9 @@ impl WlClient { xdg_wm_base_id: AtomicU32::from(0), layer_shell_id: AtomicU32::from(0), layer_surface_id: AtomicU32::from(0), + seat_id: AtomicU32::from(0), + keyboard_id: AtomicU32::from(0), + keymap: Mutex::new(None), }); let mut wl_client2 = wl_client.clone(); @@ -55,15 +65,32 @@ impl WlClient { readloop.join(); - Ok(wl_client) + Ok(()) } pub fn read_event(&self) -> Result<(), Box> { // TODO: Don't realloc header and event + // FIXME: Using fd like this is unreliable because fd could be before or after + // event it was intended to be with + let mut fd = 0; + let mut header = vec![0u8; 8]; let mut socket = self.socket.lock().unwrap(); - socket.read_exact(&mut header)?; + let mut ancillary_buf = [0; 128]; + let mut ancillary = SocketAncillary::new(&mut ancillary_buf); + + socket.recv_vectored_with_ancillary( + &mut [IoSliceMut::new(header.as_mut_slice())], + &mut ancillary + )?; + for ancillary_result in ancillary.messages() { + if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() { + scm_rights.for_each(|received| { + fd = received; + }); + } + } let header = WlHeader { object: u32::from_ne_bytes(header[0..4].try_into()?), @@ -72,15 +99,20 @@ impl WlClient { }; let mut event = vec![0u8; header.size as usize - 8]; - socket.read_exact(&mut event)?; + socket.recv_vectored_with_ancillary( + &mut [IoSliceMut::new(event.as_mut_slice())], + &mut ancillary + )?; + for ancillary_result in ancillary.messages() { + if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() { + scm_rights.for_each(|fd| { + println!("found {}", fd); + }); + } + } + drop(socket); - println!( - "Received event:\n\tObject: {}\n\tOpcode: {}\n\tSize: {}", - header.object, - header.opcode, - header.size - ); if header.object == self.registry_id.load(Ordering::Relaxed) && header.opcode == 0 { // wl_registry::global self.wl_registry_global(&event)?; } @@ -102,8 +134,57 @@ impl WlClient { else if header.object == self.surface_id.load(Ordering::Relaxed) && header.opcode == 3 { // wl_surface::preferred_buffer_transform println!("Preferred buffer transform: {}", i32::from_ne_bytes(event[0..4].try_into().unwrap())); } + else if header.object == self.seat_id.load(Ordering::Relaxed) && header.opcode == 0 { // wl_seat::capabilities + self.wl_seat_capabilities(&event)?; + } + else if header.object == self.seat_id.load(Ordering::Relaxed) && header.opcode == 1 { // wl_seat::name + self.wl_seat_name(&event); + } + else if header.object == self.keyboard_id.load(Ordering::Relaxed) && header.opcode == 0 { // wl_keyboard::keymap + self.wl_keyboard_keymap(&event, fd); + } + else if header.object == self.keyboard_id.load(Ordering::Relaxed) && header.opcode == 3 { // wl_keyboard::key + self.wl_keyboard_key(&event); + } + else { + println!( + "Received event:\n\tObject: {}\n\tOpcode: {}\n\tSize: {}", + header.object, + header.opcode, + header.size + ); + } Ok(()) } } +impl Debug for WlClient { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "WlClient {{ + current_id: {}, + registry_id: {}, + shm_id: {}, + buffer_id: {}, + compositor_id: {}, + surface_id: {}, + xdg_wm_base_id: {}, + layer_shell_id: {}, + layer_surface_id: {}, + seat_id: {}, + keyboard_id: {}, +}}", + self.current_id.load(Ordering::Relaxed), + self.registry_id.load(Ordering::Relaxed), + self.shm_id.load(Ordering::Relaxed), + self.buffer_id.load(Ordering::Relaxed), + self.compositor_id.load(Ordering::Relaxed), + self.surface_id.load(Ordering::Relaxed), + self.xdg_wm_base_id.load(Ordering::Relaxed), + self.layer_shell_id.load(Ordering::Relaxed), + self.layer_surface_id.load(Ordering::Relaxed), + self.seat_id.load(Ordering::Relaxed), + self.keyboard_id.load(Ordering::Relaxed), + ) + } +} diff --git a/src/wayland/wl_registry.rs b/src/wayland/wl_registry.rs index 29004be..98ef7e9 100644 --- a/src/wayland/wl_registry.rs +++ b/src/wayland/wl_registry.rs @@ -15,6 +15,9 @@ impl WlClient { if self.layer_shell_id.load(Ordering::Relaxed) == 0 { return Err(UnsetErr("layer_shell_id".to_string()).into()); } + if self.seat_id.load(Ordering::Relaxed) == 0 { + return Err(UnsetErr("seat_id".to_string()).into()); + } println!("Initializing toplevel!"); self.wl_compositor_create_surface()?; self.layer_shell_get_layer_surface()?; @@ -57,62 +60,45 @@ impl WlClient { 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, - ); + // println!( + // "Received global:\n\tName: {}\n\tInterface: {}\n\tVersion: {}", + // name, + // interface, + // version, + // ); // TODO: Collapse these into one line (probably using a macro) if interface == "wl_shm" { let current_id = self.current_id.fetch_add(1, Ordering::Relaxed) + 1; - self.wl_registry_bind( - &name, - &interface, - &version, - ¤t_id - )?; + self.wl_registry_bind(&name, &interface, &version, ¤t_id)?; self.shm_id.store(current_id, Ordering::Relaxed); self.init_toplevel().unwrap_or_else(|err| {eprintln!("{}", err)}); } - - if interface == "wl_compositor" { + else if interface == "wl_compositor" { let current_id = self.current_id.fetch_add(1, Ordering::Relaxed) + 1; - self.wl_registry_bind( - &name, - &interface, - &version, - ¤t_id - )?; + self.wl_registry_bind(&name, &interface, &version, ¤t_id)?; self.compositor_id.store(current_id, Ordering::Relaxed); self.init_toplevel().unwrap_or_else(|err| {eprintln!("{}", err)}); } - - if interface == "xdg_wm_base" { + else if interface == "xdg_wm_base" { let current_id = self.current_id.fetch_add(1, Ordering::Relaxed) + 1; - self.wl_registry_bind( - &name, - &interface, - &version, - ¤t_id - )?; + self.wl_registry_bind(&name, &interface, &version, ¤t_id)?; self.xdg_wm_base_id.store(current_id, Ordering::Relaxed); self.init_toplevel().unwrap_or_else(|err| {eprintln!("{}", err)}); } - - if interface == "zwlr_layer_shell_v1" { + else if interface == "zwlr_layer_shell_v1" { let current_id = self.current_id.fetch_add(1, Ordering::Relaxed) + 1; - self.wl_registry_bind( - &name, - &interface, - &version, - ¤t_id - )?; + self.wl_registry_bind(&name, &interface, &version, ¤t_id)?; self.layer_shell_id.store(current_id, Ordering::Relaxed); self.init_toplevel().unwrap_or_else(|err| {eprintln!("{}", err)}); } + else if interface == "wl_seat" { + let current_id = self.current_id.fetch_add(1, Ordering::Relaxed) + 1; + self.wl_registry_bind(&name, &interface, &version, ¤t_id)?; + self.seat_id.store(current_id, Ordering::Relaxed); + self.init_toplevel().unwrap_or_else(|err| {eprintln!("{}", err)}); + } Ok(()) } diff --git a/src/wayland/wl_shm.rs b/src/wayland/wl_shm.rs index 97919e5..921b0e1 100644 --- a/src/wayland/wl_shm.rs +++ b/src/wayland/wl_shm.rs @@ -5,14 +5,16 @@ const STRIDE: usize = 4; impl WlClient { pub fn wl_shm_format(event: &Vec) { - let mut offset = 0; - println!("Received pixel format: {:x}", event.read_u32(&mut offset)); + // let mut offset = 0; + // println!("Received pixel format: {:x}", event.read_u32(&mut offset)); } pub fn wl_shm_create_pool(&self, width: usize, height: usize) -> Result<(), Box> { let mut shm_pool = self.shm_pool.lock().unwrap(); let current_id = self.current_id.fetch_add(1, Ordering::Relaxed) + 1; *shm_pool = Some(shm::ShmPool::new(width, height, current_id)?); + self.shmpool_id.store(current_id, Ordering::Relaxed); + shm_pool.as_mut().unwrap().write(&vec![0xffff0000; width * height], 0); shm_pool.as_mut().unwrap().rectangle(50, 50, 50, 50, 0xff00ff00); shm_pool.as_mut().unwrap().circle(300, 300, 200, 0xff0000ff); @@ -24,7 +26,7 @@ impl WlClient { } const OPCODE: u16 = 0; const REQ_SIZE: u16 = 16; - let id = shm_pool.as_ref().unwrap().id; + let id = self.shmpool_id.load(Ordering::Relaxed); let fds = [shm_pool.as_ref().unwrap().fd]; let shm_size = shm_pool.as_ref().unwrap().size; @@ -61,7 +63,7 @@ impl WlClient { width: u32, height: u32 ) -> Result<(), Box> { - let object: u32 = self.shm_pool.lock().unwrap().as_ref().unwrap().id; + let object: u32 = self.shmpool_id.load(Ordering::Relaxed); const REQ_SIZE: u16 = 32; const OPCODE: u16 = 0;