From 251247023166cd51758b96b1c5687624aef54780 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sat, 30 Jul 2022 13:16:58 +0200 Subject: [PATCH] wayland: add a generic wayland client --- src/client.rs | 5 +- src/macros.rs | 40 ++ src/main.rs | 1 + src/wl_usr.rs | 357 ++++++++++++++++++ src/wl_usr/usr_ifs.rs | 28 ++ src/wl_usr/usr_ifs/usr_jay_compositor.rs | 145 +++++++ src/wl_usr/usr_ifs/usr_jay_output.rs | 60 +++ src/wl_usr/usr_ifs/usr_jay_pointer.rs | 32 ++ src/wl_usr/usr_ifs/usr_jay_render_ctx.rs | 60 +++ src/wl_usr/usr_ifs/usr_jay_screencast.rs | 248 ++++++++++++ src/wl_usr/usr_ifs/usr_jay_workspace.rs | 110 ++++++ .../usr_ifs/usr_jay_workspace_watcher.rs | 58 +++ src/wl_usr/usr_ifs/usr_linux_buffer_params.rs | 90 +++++ src/wl_usr/usr_ifs/usr_linux_dmabuf.rs | 81 ++++ src/wl_usr/usr_ifs/usr_wl_buffer.rs | 47 +++ src/wl_usr/usr_ifs/usr_wl_callback.rs | 52 +++ src/wl_usr/usr_ifs/usr_wl_compositor.rs | 37 ++ src/wl_usr/usr_ifs/usr_wl_display.rs | 47 +++ src/wl_usr/usr_ifs/usr_wl_output.rs | 112 ++++++ src/wl_usr/usr_ifs/usr_wl_pointer.rs | 164 ++++++++ src/wl_usr/usr_ifs/usr_wl_registry.rs | 74 ++++ src/wl_usr/usr_ifs/usr_wl_seat.rs | 78 ++++ src/wl_usr/usr_ifs/usr_wl_shm.rs | 57 +++ src/wl_usr/usr_ifs/usr_wl_shm_pool.rs | 32 ++ src/wl_usr/usr_ifs/usr_wl_surface.rs | 67 ++++ src/wl_usr/usr_ifs/usr_wlr_layer_shell.rs | 54 +++ src/wl_usr/usr_ifs/usr_wlr_layer_surface.rs | 86 +++++ src/wl_usr/usr_ifs/usr_wp_fractional_scale.rs | 49 +++ .../usr_wp_fractional_scale_manager.rs | 45 +++ src/wl_usr/usr_ifs/usr_wp_viewport.rs | 43 +++ src/wl_usr/usr_ifs/usr_wp_viewporter.rs | 42 +++ .../usr_ifs/usr_zwlr_screencopy_frame.rs | 138 +++++++ .../usr_ifs/usr_zwlr_screencopy_manager.rs | 45 +++ src/wl_usr/usr_object.rs | 44 +++ 34 files changed, 2627 insertions(+), 1 deletion(-) create mode 100644 src/wl_usr.rs create mode 100644 src/wl_usr/usr_ifs.rs create mode 100644 src/wl_usr/usr_ifs/usr_jay_compositor.rs create mode 100644 src/wl_usr/usr_ifs/usr_jay_output.rs create mode 100644 src/wl_usr/usr_ifs/usr_jay_pointer.rs create mode 100644 src/wl_usr/usr_ifs/usr_jay_render_ctx.rs create mode 100644 src/wl_usr/usr_ifs/usr_jay_screencast.rs create mode 100644 src/wl_usr/usr_ifs/usr_jay_workspace.rs create mode 100644 src/wl_usr/usr_ifs/usr_jay_workspace_watcher.rs create mode 100644 src/wl_usr/usr_ifs/usr_linux_buffer_params.rs create mode 100644 src/wl_usr/usr_ifs/usr_linux_dmabuf.rs create mode 100644 src/wl_usr/usr_ifs/usr_wl_buffer.rs create mode 100644 src/wl_usr/usr_ifs/usr_wl_callback.rs create mode 100644 src/wl_usr/usr_ifs/usr_wl_compositor.rs create mode 100644 src/wl_usr/usr_ifs/usr_wl_display.rs create mode 100644 src/wl_usr/usr_ifs/usr_wl_output.rs create mode 100644 src/wl_usr/usr_ifs/usr_wl_pointer.rs create mode 100644 src/wl_usr/usr_ifs/usr_wl_registry.rs create mode 100644 src/wl_usr/usr_ifs/usr_wl_seat.rs create mode 100644 src/wl_usr/usr_ifs/usr_wl_shm.rs create mode 100644 src/wl_usr/usr_ifs/usr_wl_shm_pool.rs create mode 100644 src/wl_usr/usr_ifs/usr_wl_surface.rs create mode 100644 src/wl_usr/usr_ifs/usr_wlr_layer_shell.rs create mode 100644 src/wl_usr/usr_ifs/usr_wlr_layer_surface.rs create mode 100644 src/wl_usr/usr_ifs/usr_wp_fractional_scale.rs create mode 100644 src/wl_usr/usr_ifs/usr_wp_fractional_scale_manager.rs create mode 100644 src/wl_usr/usr_ifs/usr_wp_viewport.rs create mode 100644 src/wl_usr/usr_ifs/usr_wp_viewporter.rs create mode 100644 src/wl_usr/usr_ifs/usr_zwlr_screencopy_frame.rs create mode 100644 src/wl_usr/usr_ifs/usr_zwlr_screencopy_manager.rs create mode 100644 src/wl_usr/usr_object.rs diff --git a/src/client.rs b/src/client.rs index d2ae6ce5..b4918bf3 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,4 +1,3 @@ -pub use error::{ClientError, MethodError, ObjectError}; use { crate::{ async_engine::SpawnedFuture, @@ -30,6 +29,10 @@ use { }, uapi::{c, OwnedFd}, }; +pub use { + error::{ClientError, MethodError, ObjectError}, + objects::MIN_SERVER_ID, +}; mod error; mod objects; diff --git a/src/macros.rs b/src/macros.rs index 872c5efe..193342e0 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -11,6 +11,46 @@ macro_rules! efrom { }; } +macro_rules! usr_object_base { + ($oname:ident, $iname:ident; $($code:ident => $f:ident,)*) => { + impl crate::wl_usr::usr_object::UsrObjectBase for $oname { + fn id(&self) -> crate::object::ObjectId { + self.id.into() + } + + #[allow(unused_variables, unreachable_code)] + fn handle_event( + self: std::rc::Rc, + event: u32, + parser: crate::utils::buffd::MsgParser<'_, '_>, + ) -> Result<(), crate::wl_usr::usr_object::UsrObjectError> { + let res: std::result::Result<(), _> = match event { + $( + $code => $oname::$f(&self, parser).map_err(|e| crate::wl_usr::usr_object::UsrObjectErrorType::EventError { + event: stringify!($f), + error: Box::new(e), + }), + )* + _ => Err(crate::wl_usr::usr_object::UsrObjectErrorType::UnknownEventError { + event, + }), + }; + if let Err(e) = res { + return Err(crate::wl_usr::usr_object::UsrObjectError { + interface: crate::wire::$iname, + ty: e, + }); + } + Ok(()) + } + + fn interface(&self) -> crate::object::Interface { + crate::wire::$iname + } + } + }; +} + macro_rules! object_base { ($oname:ident; $($code:ident => $f:ident,)*) => { impl crate::object::ObjectBase for $oname { diff --git a/src/main.rs b/src/main.rs index 2515365b..6a577302 100644 --- a/src/main.rs +++ b/src/main.rs @@ -78,6 +78,7 @@ mod wheel; mod wire; mod wire_dbus; mod wire_xcon; +mod wl_usr; mod xcon; mod xkbcommon; mod xwayland; diff --git a/src/wl_usr.rs b/src/wl_usr.rs new file mode 100644 index 00000000..329349fc --- /dev/null +++ b/src/wl_usr.rs @@ -0,0 +1,357 @@ +#![allow(dead_code)] + +pub mod usr_ifs; +pub mod usr_object; + +use { + crate::{ + async_engine::{AsyncEngine, SpawnedFuture}, + client::{EventFormatter, RequestParser, MIN_SERVER_ID}, + io_uring::IoUring, + object::{ObjectId, WL_DISPLAY_ID}, + utils::{ + asyncevent::AsyncEvent, + bitfield::Bitfield, + buffd::{ + BufFdError, BufFdIn, BufFdOut, MsgFormatter, MsgParser, MsgParserError, OutBuffer, + OutBufferSwapchain, + }, + clonecell::CloneCell, + copyhashmap::CopyHashMap, + errorfmt::ErrorFmt, + oserror::OsError, + vec_ext::VecExt, + }, + wheel::Wheel, + wire::wl_display, + wl_usr::{ + usr_ifs::{ + usr_wl_callback::UsrWlCallback, usr_wl_display::UsrWlDisplay, + usr_wl_registry::UsrWlRegistry, + }, + usr_object::{UsrObject, UsrObjectError}, + }, + }, + std::{ + cell::{Cell, RefCell}, + collections::VecDeque, + mem, + rc::Rc, + }, + thiserror::Error, + uapi::c, +}; + +#[derive(Debug, Error)] +pub enum UsrConError { + #[error("Could not create a socket")] + CreateSocket(#[source] OsError), + #[error("The socket path is too long")] + SocketPathTooLong, + #[error("Could not connect to the compositor")] + Connect(#[source] OsError), + #[error("The message length is smaller than 8 bytes")] + MsgLenTooSmall, + #[error("The size of the message is not a multiple of 4")] + UnalignedMessage, + #[error(transparent)] + BufFdError(#[from] BufFdError), + #[error("Could not read from the compositor")] + Read(#[source] BufFdError), + #[error("Could not write to the compositor")] + Write(#[source] BufFdError), + #[error(transparent)] + UsrObjectError(#[from] UsrObjectError), + #[error("Server sent an event for object {0} that does not exist")] + MissingObject(ObjectId), +} + +pub struct UsrCon { + pub ring: Rc, + pub wheel: Rc, + pub eng: Rc, + pub server_id: u32, + obj_ids: RefCell, + objects: CopyHashMap>>, + swapchain: Rc>, + flush_request: AsyncEvent, + incoming: Cell>>, + outgoing: Cell>>, + pub owner: CloneCell>>, +} + +pub trait UsrConOwner { + fn killed(&self); +} + +impl UsrCon { + pub fn new( + ring: &Rc, + wheel: &Rc, + eng: &Rc, + path: &str, + server_id: u32, + ) -> Result, UsrConError> { + let socket = match uapi::socket( + c::AF_UNIX, + c::SOCK_STREAM | c::SOCK_CLOEXEC | c::SOCK_NONBLOCK, + 0, + ) { + Ok(s) => Rc::new(s), + Err(e) => return Err(UsrConError::CreateSocket(e.into())), + }; + let mut addr: c::sockaddr_un = uapi::pod_zeroed(); + addr.sun_family = c::AF_UNIX as _; + if path.len() >= addr.sun_path.len() { + return Err(UsrConError::SocketPathTooLong); + } + let sun_path = uapi::as_bytes_mut(&mut addr.sun_path[..]); + sun_path[..path.len()].copy_from_slice(path.as_bytes()); + sun_path[path.len()] = 0; + if let Err(e) = uapi::connect(socket.raw(), &addr) { + return Err(UsrConError::Connect(e.into())); + } + let mut obj_ids = Bitfield::default(); + obj_ids.take(0); + obj_ids.take(1); + let slf = Rc::new(Self { + ring: ring.clone(), + wheel: wheel.clone(), + eng: eng.clone(), + server_id, + obj_ids: RefCell::new(obj_ids), + objects: Default::default(), + swapchain: Default::default(), + flush_request: Default::default(), + incoming: Default::default(), + outgoing: Default::default(), + owner: Default::default(), + }); + slf.objects.set( + WL_DISPLAY_ID.into(), + Some(Rc::new(UsrWlDisplay { + id: WL_DISPLAY_ID, + con: slf.clone(), + })), + ); + slf.incoming.set(Some( + slf.eng.spawn( + Incoming { + con: slf.clone(), + buf: BufFdIn::new(&socket, &slf.ring), + data: vec![], + } + .run(), + ), + )); + slf.outgoing.set(Some( + slf.eng.spawn( + Outgoing { + con: slf.clone(), + buf: BufFdOut::new(&socket, &slf.ring), + buffers: Default::default(), + } + .run(), + ), + )); + Ok(slf) + } + + pub fn kill(&self) { + for (_, obj) in self.objects.lock().drain() { + if let Some(obj) = obj { + obj.break_loops(); + } + } + self.incoming.take(); + self.outgoing.take(); + if let Some(owner) = self.owner.take() { + owner.killed(); + } + } + + pub fn release_id(&self, id: u32) { + self.obj_ids.borrow_mut().release(id); + self.objects.remove(&ObjectId::from_raw(id)); + } + + pub fn remove_obj(&self, obj: &impl UsrObject) { + obj.destroy(); + obj.break_loops(); + if obj.id().raw() >= MIN_SERVER_ID { + self.objects.remove(&obj.id()); + } else { + self.objects.set(obj.id(), None); + } + } + + pub fn add_object(&self, obj: Rc) { + self.objects.set(obj.id(), Some(obj)); + } + + pub fn get_registry(self: &Rc) -> Rc { + let registry = Rc::new(UsrWlRegistry { + id: self.id(), + con: self.clone(), + owner: Default::default(), + }); + self.request(wl_display::GetRegistry { + self_id: WL_DISPLAY_ID, + registry: registry.id, + }); + self.objects.set(registry.id.into(), Some(registry.clone())); + registry + } + + pub fn sync(self: &Rc, handler: F) + where + F: FnOnce() + 'static, + { + let callback = Rc::new(UsrWlCallback::new(self, handler)); + self.request(wl_display::Sync { + self_id: WL_DISPLAY_ID, + callback: callback.id, + }); + self.objects.set(callback.id.into(), Some(callback)); + } + + pub fn parse<'a, R: RequestParser<'a>>( + &self, + obj: &impl UsrObject, + mut parser: MsgParser<'_, 'a>, + ) -> Result { + let res = R::parse(&mut parser)?; + parser.eof()?; + log::trace!( + "Server {} -> {}@{}.{:?}", + self.server_id, + obj.interface().name(), + obj.id(), + res + ); + Ok(res) + } + + pub fn request(self: &Rc, event: T) { + if log::log_enabled!(log::Level::Trace) { + log::trace!( + "Server {} <= {}@{}.{:?}", + self.server_id, + event.interface().name(), + event.id(), + event, + ); + } + let mut fds = vec![]; + let mut swapchain = self.swapchain.borrow_mut(); + let mut fmt = MsgFormatter::new(&mut swapchain.cur, &mut fds); + event.format(&mut fmt); + fmt.write_len(); + if swapchain.cur.is_full() { + swapchain.commit(); + } + self.flush_request.trigger(); + } + + pub fn id>(&self) -> T { + let id = self.obj_ids.borrow_mut().acquire(); + ObjectId::from_raw(id).into() + } +} + +struct Outgoing { + con: Rc, + buf: BufFdOut, + buffers: VecDeque, +} + +impl Outgoing { + async fn run(mut self: Self) { + loop { + self.con.flush_request.triggered().await; + if let Err(e) = self.flush().await { + log::error!( + "Server {}: Could not process an outgoing message: {}", + self.con.server_id, + ErrorFmt(e) + ); + self.con.kill(); + return; + } + } + } + + async fn flush(&mut self) -> Result<(), UsrConError> { + { + let mut swapchain = self.con.swapchain.borrow_mut(); + swapchain.commit(); + mem::swap(&mut swapchain.pending, &mut self.buffers); + } + while let Some(mut cur) = self.buffers.pop_front() { + if let Err(e) = self.buf.flush_no_timeout(&mut cur).await { + return Err(UsrConError::Write(e)); + } + self.con.swapchain.borrow_mut().free.push(cur); + } + Ok(()) + } +} + +struct Incoming { + con: Rc, + buf: BufFdIn, + data: Vec, +} + +impl Incoming { + async fn run(mut self: Self) { + loop { + if let Err(e) = self.handle_msg().await { + log::error!( + "Server {}: Could not process an incoming message: {}", + self.con.server_id, + ErrorFmt(e) + ); + self.con.kill(); + return; + } + } + } + + async fn handle_msg(&mut self) -> Result<(), UsrConError> { + let mut hdr = [0u32, 0]; + if let Err(e) = self.buf.read_full(&mut hdr[..]).await { + return Err(UsrConError::Read(e)); + } + let obj_id = ObjectId::from_raw(hdr[0]); + let len = (hdr[1] >> 16) as usize; + let event = hdr[1] & 0xffff; + if len < 8 { + return Err(UsrConError::MsgLenTooSmall); + } + if len % 4 != 0 { + return Err(UsrConError::UnalignedMessage); + } + let len = len / 4 - 2; + self.data.clear(); + self.data.reserve(len); + let unused = self.data.split_at_spare_mut_ext().1; + if let Err(e) = self.buf.read_full(&mut unused[..len]).await { + return Err(UsrConError::Read(e)); + } + unsafe { + self.data.set_len(len); + } + if let Some(obj) = self.con.objects.get(&obj_id) { + if let Some(obj) = obj { + let parser = MsgParser::new(&mut self.buf, &self.data); + obj.handle_event(event, parser)?; + } + } else if obj_id.raw() < MIN_SERVER_ID { + return Err(UsrConError::MissingObject(obj_id)); + } else { + // ignore events for server-created objects that were never added to the state + } + Ok(()) + } +} diff --git a/src/wl_usr/usr_ifs.rs b/src/wl_usr/usr_ifs.rs new file mode 100644 index 00000000..6b398822 --- /dev/null +++ b/src/wl_usr/usr_ifs.rs @@ -0,0 +1,28 @@ +pub mod usr_jay_compositor; +pub mod usr_jay_output; +pub mod usr_jay_pointer; +pub mod usr_jay_render_ctx; +pub mod usr_jay_screencast; +pub mod usr_jay_workspace; +pub mod usr_jay_workspace_watcher; +pub mod usr_linux_buffer_params; +pub mod usr_linux_dmabuf; +pub mod usr_wl_buffer; +pub mod usr_wl_callback; +pub mod usr_wl_compositor; +pub mod usr_wl_display; +pub mod usr_wl_output; +pub mod usr_wl_pointer; +pub mod usr_wl_registry; +pub mod usr_wl_seat; +pub mod usr_wl_shm; +pub mod usr_wl_shm_pool; +pub mod usr_wl_surface; +pub mod usr_wlr_layer_shell; +pub mod usr_wlr_layer_surface; +pub mod usr_wp_fractional_scale; +pub mod usr_wp_fractional_scale_manager; +pub mod usr_wp_viewport; +pub mod usr_wp_viewporter; +pub mod usr_zwlr_screencopy_frame; +pub mod usr_zwlr_screencopy_manager; diff --git a/src/wl_usr/usr_ifs/usr_jay_compositor.rs b/src/wl_usr/usr_ifs/usr_jay_compositor.rs new file mode 100644 index 00000000..37095322 --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_jay_compositor.rs @@ -0,0 +1,145 @@ +use { + crate::{ + utils::{ + buffd::{MsgParser, MsgParserError}, + clonecell::CloneCell, + }, + wire::{jay_compositor::*, JayCompositorId}, + wl_usr::{ + usr_ifs::{ + usr_jay_output::UsrJayOutput, usr_jay_pointer::UsrJayPointer, + usr_jay_render_ctx::UsrJayRenderCtx, usr_jay_screencast::UsrJayScreencast, + usr_jay_workspace_watcher::UsrJayWorkspaceWatcher, usr_wl_output::UsrWlOutput, + usr_wl_seat::UsrWlSeat, + }, + usr_object::UsrObject, + UsrCon, + }, + }, + std::rc::Rc, +}; + +pub struct UsrJayCompositor { + pub id: JayCompositorId, + pub con: Rc, + pub owner: CloneCell>>, +} + +pub trait UsrJayCompositorOwner { + fn client_id(&self, ev: ClientId) { + let _ = ev; + } + + fn seat(&self, ev: Seat) { + let _ = ev; + } +} + +impl UsrJayCompositor { + pub fn get_render_context(&self) -> Rc { + let rc = Rc::new(UsrJayRenderCtx { + id: self.con.id(), + con: self.con.clone(), + owner: Default::default(), + }); + self.con.request(GetRenderCtx { + self_id: self.id, + id: rc.id, + }); + self.con.add_object(rc.clone()); + rc + } + + pub fn create_screencast(&self) -> Rc { + let sc = Rc::new(UsrJayScreencast { + id: self.con.id(), + con: self.con.clone(), + owner: Default::default(), + pending_buffers: Default::default(), + pending_planes: Default::default(), + pending_config: Default::default(), + }); + self.con.request(CreateScreencast { + self_id: self.id, + id: sc.id, + }); + self.con.add_object(sc.clone()); + sc + } + + pub fn get_output(&self, output: &UsrWlOutput) -> Rc { + let jo = Rc::new(UsrJayOutput { + id: self.con.id(), + con: self.con.clone(), + owner: Default::default(), + }); + self.con.request(GetOutput { + self_id: self.id, + id: jo.id, + output: output.id, + }); + self.con.add_object(jo.clone()); + jo + } + + pub fn watch_workspaces(&self) -> Rc { + let ww = Rc::new(UsrJayWorkspaceWatcher { + id: self.con.id(), + con: self.con.clone(), + owner: Default::default(), + }); + self.con.request(WatchWorkspaces { + self_id: self.id, + id: ww.id, + }); + self.con.add_object(ww.clone()); + ww + } + + pub fn get_pointer(&self, seat: &UsrWlSeat) -> Rc { + let jp = Rc::new(UsrJayPointer { + id: self.con.id(), + con: self.con.clone(), + }); + self.con.add_object(jp.clone()); + self.con.request(GetPointer { + self_id: self.id, + id: jp.id, + seat: seat.id, + }); + jp + } + + fn client_id(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: ClientId = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.client_id(ev); + } + Ok(()) + } + + fn seat(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: Seat = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.seat(ev); + } + Ok(()) + } +} + +usr_object_base! { + UsrJayCompositor, JayCompositor; + + CLIENT_ID => client_id, + SEAT => seat, +} + +impl UsrObject for UsrJayCompositor { + fn destroy(&self) { + self.con.request(Destroy { self_id: self.id }); + } + + fn break_loops(&self) { + self.owner.take(); + } +} diff --git a/src/wl_usr/usr_ifs/usr_jay_output.rs b/src/wl_usr/usr_ifs/usr_jay_output.rs new file mode 100644 index 00000000..953d007d --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_jay_output.rs @@ -0,0 +1,60 @@ +use { + crate::{ + utils::{ + buffd::{MsgParser, MsgParserError}, + clonecell::CloneCell, + }, + wire::{jay_output::*, JayOutputId}, + wl_usr::{usr_object::UsrObject, UsrCon}, + }, + std::rc::Rc, +}; + +pub struct UsrJayOutput { + pub id: JayOutputId, + pub con: Rc, + pub owner: CloneCell>>, +} + +pub trait UsrJayOutputOwner { + fn linear_id(self: Rc, ev: &LinearId) { + let _ = ev; + } + + fn destroyed(&self) {} +} + +impl UsrJayOutput { + fn linear_id(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: LinearId = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.linear_id(&ev); + } + Ok(()) + } + + fn destroyed(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let _ev: Destroyed = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.destroyed(); + } + Ok(()) + } +} + +usr_object_base! { + UsrJayOutput, JayOutput; + + LINEAR_ID => linear_id, + DESTROYED => destroyed, +} + +impl UsrObject for UsrJayOutput { + fn destroy(&self) { + self.con.request(Destroy { self_id: self.id }); + } + + fn break_loops(&self) { + self.owner.set(None); + } +} diff --git a/src/wl_usr/usr_ifs/usr_jay_pointer.rs b/src/wl_usr/usr_ifs/usr_jay_pointer.rs new file mode 100644 index 00000000..8e0316a0 --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_jay_pointer.rs @@ -0,0 +1,32 @@ +use { + crate::{ + cursor::KnownCursor, + wire::{jay_pointer::*, JayPointerId}, + wl_usr::{usr_object::UsrObject, UsrCon}, + }, + std::rc::Rc, +}; + +pub struct UsrJayPointer { + pub id: JayPointerId, + pub con: Rc, +} + +impl UsrJayPointer { + pub fn set_known_cursor(&self, cursor: KnownCursor) { + self.con.request(SetKnownCursor { + self_id: self.id, + idx: cursor as usize as _, + }); + } +} + +usr_object_base! { + UsrJayPointer, JayPointer; +} + +impl UsrObject for UsrJayPointer { + fn destroy(&self) { + self.con.request(Destroy { self_id: self.id }); + } +} diff --git a/src/wl_usr/usr_ifs/usr_jay_render_ctx.rs b/src/wl_usr/usr_ifs/usr_jay_render_ctx.rs new file mode 100644 index 00000000..54688164 --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_jay_render_ctx.rs @@ -0,0 +1,60 @@ +use { + crate::{ + utils::{ + buffd::{MsgParser, MsgParserError}, + clonecell::CloneCell, + }, + wire::{jay_render_ctx::*, JayRenderCtxId}, + wl_usr::{usr_object::UsrObject, UsrCon}, + }, + std::rc::Rc, + uapi::OwnedFd, +}; + +pub struct UsrJayRenderCtx { + pub id: JayRenderCtxId, + pub con: Rc, + pub owner: CloneCell>>, +} + +pub trait UsrJayRenderCtxOwner { + fn no_device(&self) {} + fn device(&self, fd: Rc) { + let _ = fd; + } +} + +impl UsrJayRenderCtx { + fn no_device(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let _ev: NoDevice = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.no_device(); + } + Ok(()) + } + + fn device(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: Device = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.device(ev.fd); + } + Ok(()) + } +} + +usr_object_base! { + UsrJayRenderCtx, JayRenderCtx; + + NO_DEVICE => no_device, + DEVICE => device, +} + +impl UsrObject for UsrJayRenderCtx { + fn destroy(&self) { + self.con.request(Destroy { self_id: self.id }); + } + + fn break_loops(&self) { + self.owner.take(); + } +} diff --git a/src/wl_usr/usr_ifs/usr_jay_screencast.rs b/src/wl_usr/usr_ifs/usr_jay_screencast.rs new file mode 100644 index 00000000..057c01e3 --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_jay_screencast.rs @@ -0,0 +1,248 @@ +use { + crate::{ + format::formats, + ifs::jay_workspace::JayWorkspace, + utils::{ + buffd::{MsgParser, MsgParserError}, + clonecell::CloneCell, + }, + video::dmabuf::{DmaBuf, DmaBufPlane}, + wire::{jay_screencast::*, JayScreencastId}, + wl_usr::{usr_ifs::usr_jay_output::UsrJayOutput, usr_object::UsrObject, UsrCon}, + }, + std::{cell::RefCell, mem, ops::DerefMut, rc::Rc}, + thiserror::Error, +}; + +pub struct UsrJayScreencast { + pub id: JayScreencastId, + pub con: Rc, + pub owner: CloneCell>>, + + pub pending_buffers: RefCell>, + pub pending_planes: RefCell>, + + pub pending_config: RefCell, +} + +#[derive(Default)] +pub struct UsrJayScreencastServerConfig { + pub output: Option, + pub show_all: bool, + pub running: bool, + pub use_linear_buffers: bool, + pub allowed_workspaces: Vec, +} + +pub trait UsrJayScreencastOwner { + fn buffers(&self, buffers: Vec) { + let _ = buffers; + } + + fn ready(&self, ev: &Ready) { + let _ = ev; + } + + fn destroyed(&self) {} + + fn missed_frame(&self) {} + + fn config(&self, config: UsrJayScreencastServerConfig) { + let _ = config; + } +} + +impl UsrJayScreencast { + pub fn set_output(&self, output: &UsrJayOutput) { + self.con.request(SetOutput { + self_id: self.id, + output: output.id, + }); + } + + pub fn set_allow_all_workspaces(&self, allow_all: bool) { + self.con.request(SetAllowAllWorkspaces { + self_id: self.id, + allow_all: allow_all as _, + }); + } + + pub fn allow_workspace(&self, ws: &JayWorkspace) { + self.con.request(AllowWorkspace { + self_id: self.id, + workspace: ws.id, + }); + } + + pub fn touch_allowed_workspaces(&self) { + self.con + .request(TouchAllowedWorkspaces { self_id: self.id }); + } + + pub fn set_use_linear_buffers(&self, linear: bool) { + self.con.request(SetUseLinearBuffers { + self_id: self.id, + use_linear: linear as _, + }); + } + + pub fn set_running(&self, running: bool) { + self.con.request(SetRunning { + self_id: self.id, + running: running as _, + }); + } + + pub fn configure(&self) { + self.con.request(Configure { self_id: self.id }); + } + + pub fn release_buffer(&self, idx: usize) { + self.con.request(ReleaseBuffer { + self_id: self.id, + idx: idx as _, + }); + } + + fn plane(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: Plane = self.con.parse(self, parser)?; + self.pending_planes.borrow_mut().push(DmaBufPlane { + offset: ev.offset, + stride: ev.stride, + fd: ev.fd, + }); + Ok(()) + } + + fn buffer(&self, parser: MsgParser<'_, '_>) -> Result<(), UsrJayScreencastError> { + let ev: Buffer = self.con.parse(self, parser)?; + let format = match formats().get(&ev.format) { + Some(f) => f, + _ => return Err(UsrJayScreencastError::UnknownFormat(ev.format)), + }; + self.pending_buffers.borrow_mut().push(DmaBuf { + width: ev.width, + height: ev.height, + format, + modifier: ev.modifier, + planes: mem::take(self.pending_planes.borrow_mut().deref_mut()), + }); + Ok(()) + } + + fn buffers_done(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: BuffersDone = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.buffers(mem::take(self.pending_buffers.borrow_mut().deref_mut())); + } + self.con.request(AckBuffers { + self_id: self.id, + serial: ev.serial, + }); + Ok(()) + } + + fn ready(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: Ready = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.ready(&ev); + } + Ok(()) + } + + fn destroyed(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let _ev: Destroyed = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.destroyed(); + } + Ok(()) + } + + fn missed_frame(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let _ev: MissedFrame = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.missed_frame(); + } + Ok(()) + } + + fn config_output(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: ConfigOutput = self.con.parse(self, parser)?; + self.pending_config.borrow_mut().output = Some(ev.linear_id); + Ok(()) + } + + fn config_allow_all_workspaces(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: ConfigAllowAllWorkspaces = self.con.parse(self, parser)?; + self.pending_config.borrow_mut().show_all = ev.allow_all != 0; + Ok(()) + } + + fn config_use_linear_buffers(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: ConfigUseLinearBuffers = self.con.parse(self, parser)?; + self.pending_config.borrow_mut().use_linear_buffers = ev.use_linear != 0; + Ok(()) + } + + fn config_running(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: ConfigRunning = self.con.parse(self, parser)?; + self.pending_config.borrow_mut().running = ev.running != 0; + Ok(()) + } + + fn config_allow_workspace(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: ConfigAllowWorkspace = self.con.parse(self, parser)?; + self.pending_config + .borrow_mut() + .allowed_workspaces + .push(ev.linear_id); + Ok(()) + } + + fn config_done(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: ConfigDone = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.config(mem::take(self.pending_config.borrow_mut().deref_mut())); + } + self.con.request(AckConfig { + self_id: self.id, + serial: ev.serial, + }); + Ok(()) + } +} + +usr_object_base! { + UsrJayScreencast, JayScreencast; + + PLANE => plane, + BUFFER => buffer, + BUFFERS_DONE => buffers_done, + READY => ready, + DESTROYED => destroyed, + MISSED_FRAME => missed_frame, + CONFIG_OUTPUT => config_output, + CONFIG_ALLOW_ALL_WORKSPACES => config_allow_all_workspaces, + CONFIG_ALLOW_WORKSPACE => config_allow_workspace, + CONFIG_USE_LINEAR_BUFFERS => config_use_linear_buffers, + CONFIG_RUNNING => config_running, + CONFIG_DONE => config_done, +} + +impl UsrObject for UsrJayScreencast { + fn destroy(&self) { + self.con.request(Destroy { self_id: self.id }); + } + + fn break_loops(&self) { + self.owner.take(); + } +} + +#[derive(Debug, Error)] +pub enum UsrJayScreencastError { + #[error("Parsing failed")] + MsgParserError(#[from] MsgParserError), + #[error("The server sent an unknown format {0}")] + UnknownFormat(u32), +} diff --git a/src/wl_usr/usr_ifs/usr_jay_workspace.rs b/src/wl_usr/usr_ifs/usr_jay_workspace.rs new file mode 100644 index 00000000..290692ca --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_jay_workspace.rs @@ -0,0 +1,110 @@ +use { + crate::{ + utils::{ + buffd::{MsgParser, MsgParserError}, + clonecell::CloneCell, + }, + wire::{jay_workspace::*, JayWorkspaceId}, + wl_usr::{usr_object::UsrObject, UsrCon}, + }, + std::rc::Rc, +}; + +pub struct UsrJayWorkspace { + pub id: JayWorkspaceId, + pub con: Rc, + pub owner: CloneCell>>, +} + +pub trait UsrJayWorkspaceOwner { + fn linear_id(self: Rc, ev: &LinearId) { + let _ = ev; + } + + fn name(&self, ev: &Name) { + let _ = ev; + } + + fn destroyed(&self) {} + + fn done(&self) {} + + fn output(self: Rc, ev: &Output) { + let _ = ev; + } + + fn visible(&self, visible: bool) { + let _ = visible; + } +} + +impl UsrJayWorkspace { + fn linear_id(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: LinearId = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.linear_id(&ev); + } + Ok(()) + } + + fn name(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: Name = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.name(&ev); + } + Ok(()) + } + + fn destroyed(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let _ev: Destroyed = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.destroyed(); + } + Ok(()) + } + + fn done(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let _ev: Done = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.done(); + } + Ok(()) + } + + fn output(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: Output = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.output(&ev); + } + Ok(()) + } + + fn visible(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: Visible = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.visible(ev.visible != 0); + } + Ok(()) + } +} + +usr_object_base! { + UsrJayWorkspace, JayWorkspace; + + LINEAR_ID => linear_id, + NAME => name, + DESTROYED => destroyed, + DONE => done, + OUTPUT => output, + VISIBLE => visible, +} + +impl UsrObject for UsrJayWorkspace { + fn destroy(&self) { + self.con.request(Destroy { self_id: self.id }); + } + + fn break_loops(&self) { + self.owner.set(None); + } +} diff --git a/src/wl_usr/usr_ifs/usr_jay_workspace_watcher.rs b/src/wl_usr/usr_ifs/usr_jay_workspace_watcher.rs new file mode 100644 index 00000000..16466c53 --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_jay_workspace_watcher.rs @@ -0,0 +1,58 @@ +use { + crate::{ + utils::{ + buffd::{MsgParser, MsgParserError}, + clonecell::CloneCell, + }, + wire::{jay_workspace_watcher::*, JayWorkspaceWatcherId}, + wl_usr::{usr_ifs::usr_jay_workspace::UsrJayWorkspace, usr_object::UsrObject, UsrCon}, + }, + std::{ops::Deref, rc::Rc}, +}; + +pub struct UsrJayWorkspaceWatcher { + pub id: JayWorkspaceWatcherId, + pub con: Rc, + pub owner: CloneCell>>, +} + +pub trait UsrJayWorkspaceWatcherOwner { + fn new(self: Rc, ev: Rc, linear_id: u32) { + let _ = linear_id; + ev.con.remove_obj(ev.deref()); + } +} + +impl UsrJayWorkspaceWatcher { + fn new(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: New = self.con.parse(self, parser)?; + let jw = Rc::new(UsrJayWorkspace { + id: ev.id, + con: self.con.clone(), + owner: Default::default(), + }); + self.con.add_object(jw.clone()); + if let Some(owner) = self.owner.get() { + owner.new(jw, ev.linear_id); + } else { + self.con.remove_obj(jw.deref()); + } + Ok(()) + } +} + +usr_object_base! { + UsrJayWorkspaceWatcher, JayWorkspaceWatcher; + + NEW => new, +} + +impl UsrObject for UsrJayWorkspaceWatcher { + fn destroy(&self) { + self.con.request(Destroy { self_id: self.id }); + } + + fn break_loops(&self) { + self.owner.set(None); + } +} diff --git a/src/wl_usr/usr_ifs/usr_linux_buffer_params.rs b/src/wl_usr/usr_ifs/usr_linux_buffer_params.rs new file mode 100644 index 00000000..7501f3fd --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_linux_buffer_params.rs @@ -0,0 +1,90 @@ +use { + crate::{ + utils::{ + buffd::{MsgParser, MsgParserError}, + clonecell::CloneCell, + }, + video::dmabuf::DmaBuf, + wire::{zwp_linux_buffer_params_v1::*, ZwpLinuxBufferParamsV1Id}, + wl_usr::{usr_ifs::usr_wl_buffer::UsrWlBuffer, usr_object::UsrObject, UsrCon}, + }, + std::{ops::Deref, rc::Rc}, +}; + +pub struct UsrLinuxBufferParams { + pub id: ZwpLinuxBufferParamsV1Id, + pub con: Rc, + pub owner: CloneCell>>, +} + +pub trait UsrLinuxBufferParamsOwner { + fn created(&self, buffer: Rc) { + buffer.con.remove_obj(buffer.deref()); + } + + fn failed(&self) {} +} + +impl UsrLinuxBufferParams { + pub fn create(&self, buf: &DmaBuf) { + for (idx, plane) in buf.planes.iter().enumerate() { + self.con.request(Add { + self_id: self.id, + fd: plane.fd.clone(), + plane_idx: idx as _, + offset: plane.offset, + stride: plane.stride, + modifier_hi: (buf.modifier >> 32) as _, + modifier_lo: buf.modifier as _, + }); + } + self.con.request(Create { + self_id: self.id, + width: buf.width, + height: buf.height, + format: buf.format.drm, + flags: 0, + }); + } + + fn created(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: Created = self.con.parse(self, parser)?; + let buffer = Rc::new(UsrWlBuffer { + id: ev.buffer, + con: self.con.clone(), + owner: Default::default(), + }); + self.con.add_object(buffer.clone()); + if let Some(owner) = self.owner.get() { + owner.created(buffer); + } else { + self.con.remove_obj(buffer.deref()); + } + Ok(()) + } + + fn failed(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let _ev: Failed = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.failed(); + } + Ok(()) + } +} + +usr_object_base! { + UsrLinuxBufferParams, ZwpLinuxBufferParamsV1; + + CREATED => created, + FAILED => failed, +} + +impl UsrObject for UsrLinuxBufferParams { + fn destroy(&self) { + self.con.request(Destroy { self_id: self.id }); + } + + fn break_loops(&self) { + self.owner.take(); + } +} diff --git a/src/wl_usr/usr_ifs/usr_linux_dmabuf.rs b/src/wl_usr/usr_ifs/usr_linux_dmabuf.rs new file mode 100644 index 00000000..3d9e636d --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_linux_dmabuf.rs @@ -0,0 +1,81 @@ +use { + crate::{ + format::{formats, Format}, + utils::{ + buffd::{MsgParser, MsgParserError}, + clonecell::CloneCell, + }, + wire::{ + zwp_linux_dmabuf_v1::{self, *}, + ZwpLinuxDmabufV1Id, + }, + wl_usr::{ + usr_ifs::usr_linux_buffer_params::UsrLinuxBufferParams, usr_object::UsrObject, UsrCon, + }, + }, + std::rc::Rc, +}; + +pub struct UsrLinuxDmabuf { + pub id: ZwpLinuxDmabufV1Id, + pub con: Rc, + pub owner: CloneCell>>, +} + +pub trait UsrLinuxDmabufOwner { + fn modifier(&self, format: &'static Format, modifier: u64) { + let _ = format; + let _ = modifier; + } +} + +impl UsrLinuxDmabuf { + pub fn create_params(&self) -> Rc { + let params = Rc::new(UsrLinuxBufferParams { + id: self.con.id(), + con: self.con.clone(), + owner: Default::default(), + }); + self.con.request(CreateParams { + self_id: self.id, + params_id: params.id, + }); + self.con.add_object(params.clone()); + params + } + + fn format(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let _ev: zwp_linux_dmabuf_v1::Format = self.con.parse(self, parser)?; + Ok(()) + } + + fn modifier(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: Modifier = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + if let Some(format) = formats().get(&ev.format) { + owner.modifier( + *format, + (ev.modifier_hi as u64) << 32 | (ev.modifier_lo as u64), + ); + } + } + Ok(()) + } +} + +usr_object_base! { + UsrLinuxDmabuf, ZwpLinuxDmabufV1; + + FORMAT => format, + MODIFIER => modifier, +} + +impl UsrObject for UsrLinuxDmabuf { + fn destroy(&self) { + self.con.request(Destroy { self_id: self.id }); + } + + fn break_loops(&self) { + self.owner.take(); + } +} diff --git a/src/wl_usr/usr_ifs/usr_wl_buffer.rs b/src/wl_usr/usr_ifs/usr_wl_buffer.rs new file mode 100644 index 00000000..7e045676 --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_wl_buffer.rs @@ -0,0 +1,47 @@ +use { + crate::{ + utils::{ + buffd::{MsgParser, MsgParserError}, + clonecell::CloneCell, + }, + wire::{wl_buffer::*, WlBufferId}, + wl_usr::{usr_object::UsrObject, UsrCon}, + }, + std::rc::Rc, +}; + +pub struct UsrWlBuffer { + pub id: WlBufferId, + pub con: Rc, + pub owner: CloneCell>>, +} + +pub trait UsrWlBufferOwner { + fn release(&self) {} +} + +impl UsrWlBuffer { + fn release(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let _ev: Release = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.release(); + } + Ok(()) + } +} + +usr_object_base! { + UsrWlBuffer, WlBuffer; + + RELEASE => release, +} + +impl UsrObject for UsrWlBuffer { + fn destroy(&self) { + self.con.request(Destroy { self_id: self.id }); + } + + fn break_loops(&self) { + self.owner.take(); + } +} diff --git a/src/wl_usr/usr_ifs/usr_wl_callback.rs b/src/wl_usr/usr_ifs/usr_wl_callback.rs new file mode 100644 index 00000000..9a839dd4 --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_wl_callback.rs @@ -0,0 +1,52 @@ +use { + crate::{ + utils::buffd::{MsgParser, MsgParserError}, + wire::{wl_callback::*, WlCallbackId}, + wl_usr::{usr_object::UsrObject, UsrCon}, + }, + std::{cell::Cell, rc::Rc}, +}; + +pub struct UsrWlCallback { + pub id: WlCallbackId, + pub con: Rc, + pub handler: Cell>>, +} + +impl UsrWlCallback { + pub fn new(con: &Rc, handler: F) -> Self + where + F: FnOnce() + 'static, + { + Self { + id: con.id(), + con: con.clone(), + handler: Cell::new(Some(Box::new(handler))), + } + } + + fn done(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let _ev: Done = self.con.parse(self, parser)?; + if let Some(handler) = self.handler.take() { + handler(); + } + self.con.remove_obj(self); + Ok(()) + } +} + +usr_object_base! { + UsrWlCallback, WlCallback; + + DONE => done, +} + +impl UsrObject for UsrWlCallback { + fn destroy(&self) { + // nothing + } + + fn break_loops(&self) { + self.handler.take(); + } +} diff --git a/src/wl_usr/usr_ifs/usr_wl_compositor.rs b/src/wl_usr/usr_ifs/usr_wl_compositor.rs new file mode 100644 index 00000000..e813994c --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_wl_compositor.rs @@ -0,0 +1,37 @@ +use { + crate::{ + wire::{wl_compositor::CreateSurface, WlCompositorId}, + wl_usr::{usr_ifs::usr_wl_surface::UsrWlSurface, usr_object::UsrObject, UsrCon}, + }, + std::rc::Rc, +}; + +pub struct UsrWlCompositor { + pub id: WlCompositorId, + pub con: Rc, +} + +impl UsrWlCompositor { + pub fn create_surface(&self) -> Rc { + let sfc = Rc::new(UsrWlSurface { + id: self.con.id(), + con: self.con.clone(), + }); + self.con.request(CreateSurface { + self_id: self.id, + id: sfc.id, + }); + self.con.add_object(sfc.clone()); + sfc + } +} + +usr_object_base! { + UsrWlCompositor, WlCompositor; +} + +impl UsrObject for UsrWlCompositor { + fn destroy(&self) { + // nothing + } +} diff --git a/src/wl_usr/usr_ifs/usr_wl_display.rs b/src/wl_usr/usr_ifs/usr_wl_display.rs new file mode 100644 index 00000000..282dd5ad --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_wl_display.rs @@ -0,0 +1,47 @@ +use { + crate::{ + utils::buffd::{MsgParser, MsgParserError}, + wire::{wl_display::*, WlDisplayId}, + wl_usr::{usr_object::UsrObject, UsrCon}, + }, + std::rc::Rc, +}; + +pub struct UsrWlDisplay { + pub id: WlDisplayId, + pub con: Rc, +} + +impl UsrWlDisplay { + fn error(&self, parser: MsgParser<'_, '_>) -> Result<(), UsrWlDisplayError> { + let ev: Error = self.con.parse(self, parser)?; + Err(UsrWlDisplayError::ServerError(ev.message.to_owned())) + } + + fn delete_id(&self, parser: MsgParser<'_, '_>) -> Result<(), UsrWlDisplayError> { + let ev: DeleteId = self.con.parse(self, parser)?; + self.con.release_id(ev.id); + Ok(()) + } +} + +#[derive(Debug, thiserror::Error)] +pub enum UsrWlDisplayError { + #[error("The server emitted an error: {0}")] + ServerError(String), + #[error(transparent)] + MsgParserError(#[from] MsgParserError), +} + +usr_object_base! { + UsrWlDisplay, WlDisplay; + + ERROR => error, + DELETE_ID => delete_id, +} + +impl UsrObject for UsrWlDisplay { + fn destroy(&self) { + // nothing + } +} diff --git a/src/wl_usr/usr_ifs/usr_wl_output.rs b/src/wl_usr/usr_ifs/usr_wl_output.rs new file mode 100644 index 00000000..a90dafa9 --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_wl_output.rs @@ -0,0 +1,112 @@ +use { + crate::{ + utils::{ + buffd::{MsgParser, MsgParserError}, + clonecell::CloneCell, + }, + wire::{wl_output::*, WlOutputId}, + wl_usr::{usr_object::UsrObject, UsrCon}, + }, + std::rc::Rc, +}; + +pub struct UsrWlOutput { + pub id: WlOutputId, + pub con: Rc, + pub owner: CloneCell>>, +} + +pub trait UsrWlOutputOwner { + fn geometry(&self, ev: &Geometry) { + let _ = ev; + } + + fn mode(&self, ev: &Mode) { + let _ = ev; + } + + fn done(&self) {} + + fn scale(&self, ev: &Scale) { + let _ = ev; + } + + fn name(&self, ev: &Name) { + let _ = ev; + } + + fn description(&self, ev: &Description) { + let _ = ev; + } +} + +impl UsrWlOutput { + fn geometry(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: Geometry = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.geometry(&ev); + } + Ok(()) + } + + fn mode(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: Mode = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.mode(&ev); + } + Ok(()) + } + + fn done(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let _ev: Done = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.done(); + } + Ok(()) + } + + fn scale(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: Scale = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.scale(&ev); + } + Ok(()) + } + + fn name(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: Name = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.name(&ev); + } + Ok(()) + } + + fn description(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: Description = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.description(&ev); + } + Ok(()) + } +} + +usr_object_base! { + UsrWlOutput, WlOutput; + + GEOMETRY => geometry, + MODE => mode, + DONE => done, + SCALE => scale, + NAME => name, + DESCRIPTION => description, +} + +impl UsrObject for UsrWlOutput { + fn destroy(&self) { + self.con.request(Release { self_id: self.id }); + } + + fn break_loops(&self) { + self.owner.set(None); + } +} diff --git a/src/wl_usr/usr_ifs/usr_wl_pointer.rs b/src/wl_usr/usr_ifs/usr_wl_pointer.rs new file mode 100644 index 00000000..adf6bb36 --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_wl_pointer.rs @@ -0,0 +1,164 @@ +use { + crate::{ + ifs::wl_seat::wl_pointer::PendingScroll, + utils::{ + buffd::{MsgParser, MsgParserError}, + clonecell::CloneCell, + }, + wire::{wl_pointer::*, WlPointerId}, + wl_usr::{usr_ifs::usr_wl_surface::UsrWlSurface, usr_object::UsrObject, UsrCon}, + }, + std::{cell::Cell, rc::Rc}, +}; + +pub struct UsrWlPointer { + pub id: WlPointerId, + pub con: Rc, + pub owner: CloneCell>>, + pub any_scroll_events: Cell, + pub pending_scroll: PendingScroll, +} + +pub trait UsrWlPointerOwner { + fn enter(&self, ev: &Enter) { + let _ = ev; + } + + fn leave(&self, ev: &Leave) { + let _ = ev; + } + + fn motion(&self, ev: &Motion) { + let _ = ev; + } + + fn button(&self, ev: &Button) { + let _ = ev; + } + + fn scroll(&self, ps: &PendingScroll) { + let _ = ps; + } +} + +impl UsrWlPointer { + pub fn set_cursor(&self, serial: u32, cursor: &UsrWlSurface, hot_x: i32, hot_y: i32) { + self.con.request(SetCursor { + self_id: self.id, + serial, + surface: cursor.id, + hotspot_x: hot_x, + hotspot_y: hot_y, + }); + } + + fn enter(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: Enter = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.enter(&ev); + } + Ok(()) + } + + fn leave(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: Leave = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.leave(&ev); + } + Ok(()) + } + + fn motion(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: Motion = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.motion(&ev); + } + Ok(()) + } + + fn button(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: Button = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.button(&ev); + } + Ok(()) + } + + fn axis(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: Axis = self.con.parse(self, parser)?; + self.pending_scroll.time_usec.set(ev.time as u64 * 1000); + if ev.axis < 2 { + self.pending_scroll.px[ev.axis as usize].set(Some(ev.value)); + } + self.any_scroll_events.set(true); + Ok(()) + } + + fn frame(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let _ev: Frame = self.con.parse(self, parser)?; + if self.any_scroll_events.take() { + let pe = self.pending_scroll.take(); + if let Some(owner) = self.owner.get() { + owner.scroll(&pe); + } + } + Ok(()) + } + + fn axis_source(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: AxisSource = self.con.parse(self, parser)?; + self.pending_scroll.source.set(Some(ev.axis_source)); + self.any_scroll_events.set(true); + Ok(()) + } + + fn axis_stop(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: AxisStop = self.con.parse(self, parser)?; + self.pending_scroll.time_usec.set(ev.time as u64 * 1000); + if ev.axis < 2 { + self.pending_scroll.stop[ev.axis as usize].set(true); + } + self.any_scroll_events.set(true); + Ok(()) + } + + fn axis_discrete(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let _ev: AxisDiscrete = self.con.parse(self, parser)?; + self.any_scroll_events.set(true); + Ok(()) + } + + fn axis_value120(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: AxisValue120 = self.con.parse(self, parser)?; + if ev.axis < 2 { + self.pending_scroll.v120[ev.axis as usize].set(Some(ev.value120)); + } + self.any_scroll_events.set(true); + Ok(()) + } +} + +usr_object_base! { + UsrWlPointer, WlPointer; + + ENTER => enter, + LEAVE => leave, + MOTION => motion, + BUTTON => button, + AXIS => axis, + FRAME => frame, + AXIS_SOURCE => axis_source, + AXIS_STOP => axis_stop, + AXIS_DISCRETE => axis_discrete, + AXIS_VALUE120 => axis_value120, +} + +impl UsrObject for UsrWlPointer { + fn destroy(&self) { + self.con.request(Release { self_id: self.id }); + } + + fn break_loops(&self) { + self.owner.take(); + } +} diff --git a/src/wl_usr/usr_ifs/usr_wl_registry.rs b/src/wl_usr/usr_ifs/usr_wl_registry.rs new file mode 100644 index 00000000..acfe7bc8 --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_wl_registry.rs @@ -0,0 +1,74 @@ +use { + crate::{ + utils::{ + buffd::{MsgParser, MsgParserError}, + clonecell::CloneCell, + }, + wire::{wl_registry::*, WlRegistryId}, + wl_usr::{usr_object::UsrObject, UsrCon}, + }, + std::rc::Rc, +}; + +pub struct UsrWlRegistry { + pub id: WlRegistryId, + pub con: Rc, + pub owner: CloneCell>>, +} + +pub trait UsrWlRegistryOwner { + fn global(self: Rc, name: u32, interface: &str, version: u32) { + let _ = name; + let _ = interface; + let _ = version; + } + + fn global_remove(&self, name: u32) { + let _ = name; + } +} + +impl UsrWlRegistry { + pub fn request_bind(&self, name: u32, version: u32, obj: &dyn UsrObject) { + self.con.request(Bind { + self_id: self.id, + name, + interface: obj.interface().name(), + version, + id: obj.id(), + }); + } + + fn global(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: Global = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.global(ev.name, ev.interface, ev.version); + } + Ok(()) + } + + fn global_remove(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: GlobalRemove = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.global_remove(ev.name); + } + Ok(()) + } +} + +usr_object_base! { + UsrWlRegistry, WlRegistry; + + GLOBAL => global, + GLOBAL_REMOVE => global_remove, +} + +impl UsrObject for UsrWlRegistry { + fn destroy(&self) { + // nothing + } + + fn break_loops(&self) { + self.owner.set(None); + } +} diff --git a/src/wl_usr/usr_ifs/usr_wl_seat.rs b/src/wl_usr/usr_ifs/usr_wl_seat.rs new file mode 100644 index 00000000..5f0c89bf --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_wl_seat.rs @@ -0,0 +1,78 @@ +use { + crate::{ + utils::{ + buffd::{MsgParser, MsgParserError}, + clonecell::CloneCell, + }, + wire::{wl_seat::*, WlSeatId}, + wl_usr::{usr_ifs::usr_wl_pointer::UsrWlPointer, usr_object::UsrObject, UsrCon}, + }, + std::{cell::Cell, rc::Rc}, +}; + +pub struct UsrWlSeat { + pub id: WlSeatId, + pub con: Rc, + pub owner: CloneCell>>, +} + +pub trait UsrWlSeatOwner { + fn capabilities(self: Rc, value: u32) { + let _ = value; + } + + fn name(&self, name: &str) { + let _ = name; + } +} + +impl UsrWlSeat { + pub fn get_pointer(&self) -> Rc { + let ptr = Rc::new(UsrWlPointer { + id: self.con.id(), + con: self.con.clone(), + owner: Default::default(), + any_scroll_events: Cell::new(false), + pending_scroll: Default::default(), + }); + self.con.add_object(ptr.clone()); + self.con.request(GetPointer { + self_id: self.id, + id: ptr.id, + }); + ptr + } + + fn capabilities(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: Capabilities = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.capabilities(ev.capabilities); + } + Ok(()) + } + + fn name(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: Name = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.name(ev.name); + } + Ok(()) + } +} + +usr_object_base! { + UsrWlSeat, WlSeat; + + CAPABILITIES => capabilities, + NAME => name, +} + +impl UsrObject for UsrWlSeat { + fn destroy(&self) { + self.con.request(Release { self_id: self.id }); + } + + fn break_loops(&self) { + self.owner.take(); + } +} diff --git a/src/wl_usr/usr_ifs/usr_wl_shm.rs b/src/wl_usr/usr_ifs/usr_wl_shm.rs new file mode 100644 index 00000000..aaafa7d9 --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_wl_shm.rs @@ -0,0 +1,57 @@ +use { + crate::{ + format::{formats, map_wayland_format_id}, + utils::{ + buffd::{MsgParser, MsgParserError}, + copyhashmap::CopyHashMap, + }, + wire::{wl_shm::*, WlShmId}, + wl_usr::{usr_ifs::usr_wl_shm_pool::UsrWlShmPool, usr_object::UsrObject, UsrCon}, + }, + std::rc::Rc, + uapi::OwnedFd, +}; + +pub struct UsrWlShm { + pub id: WlShmId, + pub con: Rc, + pub formats: CopyHashMap, +} + +impl UsrWlShm { + pub fn create_pool(&self, fd: &Rc, size: i32) -> Rc { + let pool = Rc::new(UsrWlShmPool { + id: self.con.id(), + con: self.con.clone(), + }); + self.con.request(CreatePool { + self_id: self.id, + id: pool.id, + fd: fd.clone(), + size, + }); + self.con.add_object(pool.clone()); + pool + } + + fn format(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: Format = self.con.parse(self, parser)?; + let format = map_wayland_format_id(ev.format); + if let Some(format) = formats().get(&format) { + self.formats.set(format.drm, *format); + } + Ok(()) + } +} + +usr_object_base! { + UsrWlShm, WlShm; + + FORMAT => format, +} + +impl UsrObject for UsrWlShm { + fn destroy(&self) { + // nothing + } +} diff --git a/src/wl_usr/usr_ifs/usr_wl_shm_pool.rs b/src/wl_usr/usr_ifs/usr_wl_shm_pool.rs new file mode 100644 index 00000000..6aa7fd39 --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_wl_shm_pool.rs @@ -0,0 +1,32 @@ +use { + crate::{ + wire::{wl_shm_pool::*, WlShmPoolId}, + wl_usr::{usr_object::UsrObject, UsrCon}, + }, + std::rc::Rc, +}; + +pub struct UsrWlShmPool { + pub id: WlShmPoolId, + pub con: Rc, +} + +impl UsrWlShmPool { + #[allow(dead_code)] + pub fn resize(&self, size: i32) { + self.con.request(Resize { + self_id: self.id, + size, + }); + } +} + +usr_object_base! { + UsrWlShmPool, WlShmPool; +} + +impl UsrObject for UsrWlShmPool { + fn destroy(&self) { + self.con.request(Destroy { self_id: self.id }); + } +} diff --git a/src/wl_usr/usr_ifs/usr_wl_surface.rs b/src/wl_usr/usr_ifs/usr_wl_surface.rs new file mode 100644 index 00000000..f035ccde --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_wl_surface.rs @@ -0,0 +1,67 @@ +use { + crate::{ + utils::buffd::{MsgParser, MsgParserError}, + wire::{wl_surface::*, WlSurfaceId}, + wl_usr::{ + usr_ifs::{usr_wl_buffer::UsrWlBuffer, usr_wl_callback::UsrWlCallback}, + usr_object::UsrObject, + UsrCon, + }, + }, + std::rc::Rc, +}; + +pub struct UsrWlSurface { + pub id: WlSurfaceId, + pub con: Rc, +} + +impl UsrWlSurface { + pub fn attach(&self, buffer: &UsrWlBuffer) { + self.con.request(Attach { + self_id: self.id, + buffer: buffer.id, + x: 0, + y: 0, + }); + } + + pub fn frame(&self, f: F) + where + F: FnOnce() + 'static, + { + let cb = Rc::new(UsrWlCallback::new(&self.con, f)); + self.con.request(Frame { + self_id: self.id, + callback: cb.id, + }); + self.con.add_object(cb); + } + + pub fn commit(&self) { + self.con.request(Commit { self_id: self.id }); + } + + fn enter(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let _ev: Enter = self.con.parse(self, parser)?; + Ok(()) + } + + fn leave(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let _ev: Leave = self.con.parse(self, parser)?; + Ok(()) + } +} + +usr_object_base! { + UsrWlSurface, WlSurface; + + ENTER => enter, + LEAVE => leave, +} + +impl UsrObject for UsrWlSurface { + fn destroy(&self) { + self.con.request(Destroy { self_id: self.id }); + } +} diff --git a/src/wl_usr/usr_ifs/usr_wlr_layer_shell.rs b/src/wl_usr/usr_ifs/usr_wlr_layer_shell.rs new file mode 100644 index 00000000..c95660c4 --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_wlr_layer_shell.rs @@ -0,0 +1,54 @@ +use { + crate::{ + wire::{zwlr_layer_shell_v1::*, ZwlrLayerShellV1Id}, + wl_usr::{ + usr_ifs::{ + usr_wl_output::UsrWlOutput, usr_wl_surface::UsrWlSurface, + usr_wlr_layer_surface::UsrWlrLayerSurface, + }, + usr_object::UsrObject, + UsrCon, + }, + }, + std::rc::Rc, +}; + +pub struct UsrWlrLayerShell { + pub id: ZwlrLayerShellV1Id, + pub con: Rc, +} + +impl UsrWlrLayerShell { + pub fn get_layer_surface( + &self, + surface: &UsrWlSurface, + output: &UsrWlOutput, + layer: u32, + ) -> Rc { + let sfc = Rc::new(UsrWlrLayerSurface { + id: self.con.id(), + con: self.con.clone(), + owner: Default::default(), + }); + self.con.add_object(sfc.clone()); + self.con.request(GetLayerSurface { + self_id: self.id, + id: sfc.id, + surface: surface.id, + output: output.id, + layer, + namespace: "", + }); + sfc + } +} + +usr_object_base! { + UsrWlrLayerShell, ZwlrLayerShellV1; +} + +impl UsrObject for UsrWlrLayerShell { + fn destroy(&self) { + self.con.request(Destroy { self_id: self.id }) + } +} diff --git a/src/wl_usr/usr_ifs/usr_wlr_layer_surface.rs b/src/wl_usr/usr_ifs/usr_wlr_layer_surface.rs new file mode 100644 index 00000000..904b23c5 --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_wlr_layer_surface.rs @@ -0,0 +1,86 @@ +use { + crate::{ + utils::{ + buffd::{MsgParser, MsgParserError}, + clonecell::CloneCell, + }, + wire::{zwlr_layer_surface_v1::*, ZwlrLayerSurfaceV1Id}, + wl_usr::{usr_object::UsrObject, UsrCon}, + }, + std::rc::Rc, +}; + +pub struct UsrWlrLayerSurface { + pub id: ZwlrLayerSurfaceV1Id, + pub con: Rc, + pub owner: CloneCell>>, +} + +pub trait UsrWlrLayerSurfaceOwner { + fn configure(&self, ev: &Configure) { + let _ = ev; + } + + fn closed(&self) {} +} + +impl UsrWlrLayerSurface { + pub fn set_size(&self, width: i32, height: i32) { + self.con.request(SetSize { + self_id: self.id, + width: width as _, + height: height as _, + }); + } + + pub fn set_keyboard_interactivity(&self, ki: u32) { + self.con.request(SetKeyboardInteractivity { + self_id: self.id, + keyboard_interactivity: ki, + }); + } + + pub fn set_layer(&self, layer: u32) { + self.con.request(SetLayer { + self_id: self.id, + layer, + }); + } + + fn configure(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: Configure = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.configure(&ev); + } + self.con.request(AckConfigure { + self_id: self.id, + serial: ev.serial, + }); + Ok(()) + } + + fn closed(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let _ev: Closed = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.closed(); + } + Ok(()) + } +} + +usr_object_base! { + UsrWlrLayerSurface, ZwlrLayerSurfaceV1; + + CONFIGURE => configure, + CLOSED => closed, +} + +impl UsrObject for UsrWlrLayerSurface { + fn destroy(&self) { + self.con.request(Destroy { self_id: self.id }); + } + + fn break_loops(&self) { + self.owner.take(); + } +} diff --git a/src/wl_usr/usr_ifs/usr_wp_fractional_scale.rs b/src/wl_usr/usr_ifs/usr_wp_fractional_scale.rs new file mode 100644 index 00000000..e704bd2d --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_wp_fractional_scale.rs @@ -0,0 +1,49 @@ +use { + crate::{ + utils::{ + buffd::{MsgParser, MsgParserError}, + clonecell::CloneCell, + }, + wire::{wp_fractional_scale_v1::*, WpFractionalScaleV1Id}, + wl_usr::{usr_object::UsrObject, UsrCon}, + }, + std::rc::Rc, +}; + +pub struct UsrWpFractionalScale { + pub id: WpFractionalScaleV1Id, + pub con: Rc, + pub owner: CloneCell>>, +} + +pub trait UsrWpFractionalScaleOwner { + fn preferred_scale(self: Rc, ev: &PreferredScale) { + let _ = ev; + } +} + +impl UsrWpFractionalScale { + fn preferred_scale(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: PreferredScale = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.preferred_scale(&ev); + } + Ok(()) + } +} + +usr_object_base! { + UsrWpFractionalScale, WpFractionalScaleV1; + + PREFERRED_SCALE => preferred_scale, +} + +impl UsrObject for UsrWpFractionalScale { + fn destroy(&self) { + self.con.request(Destroy { self_id: self.id }); + } + + fn break_loops(&self) { + self.owner.take(); + } +} diff --git a/src/wl_usr/usr_ifs/usr_wp_fractional_scale_manager.rs b/src/wl_usr/usr_ifs/usr_wp_fractional_scale_manager.rs new file mode 100644 index 00000000..553587b0 --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_wp_fractional_scale_manager.rs @@ -0,0 +1,45 @@ +use { + crate::{ + wire::{wp_fractional_scale_manager_v1::*, WpFractionalScaleManagerV1Id}, + wl_usr::{ + usr_ifs::{ + usr_wl_surface::UsrWlSurface, usr_wp_fractional_scale::UsrWpFractionalScale, + }, + usr_object::UsrObject, + UsrCon, + }, + }, + std::rc::Rc, +}; + +pub struct UsrWpFractionalScaleManager { + pub id: WpFractionalScaleManagerV1Id, + pub con: Rc, +} + +impl UsrWpFractionalScaleManager { + pub fn get_fractional_scale(&self, surface: &UsrWlSurface) -> Rc { + let fs = Rc::new(UsrWpFractionalScale { + id: self.con.id(), + con: self.con.clone(), + owner: Default::default(), + }); + self.con.add_object(fs.clone()); + self.con.request(GetFractionalScale { + self_id: self.id, + id: fs.id, + surface: surface.id, + }); + fs + } +} + +usr_object_base! { + UsrWpFractionalScaleManager, WpFractionalScaleManagerV1; +} + +impl UsrObject for UsrWpFractionalScaleManager { + fn destroy(&self) { + self.con.request(Destroy { self_id: self.id }) + } +} diff --git a/src/wl_usr/usr_ifs/usr_wp_viewport.rs b/src/wl_usr/usr_ifs/usr_wp_viewport.rs new file mode 100644 index 00000000..b563d7f3 --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_wp_viewport.rs @@ -0,0 +1,43 @@ +use { + crate::{ + fixed::Fixed, + wire::{wp_viewport::*, WpViewportId}, + wl_usr::{usr_object::UsrObject, UsrCon}, + }, + std::rc::Rc, +}; + +pub struct UsrWpViewport { + pub id: WpViewportId, + pub con: Rc, +} + +impl UsrWpViewport { + pub fn set_source(&self, x: Fixed, y: Fixed, width: Fixed, height: Fixed) { + self.con.request(SetSource { + self_id: self.id, + x, + y, + width, + height, + }); + } + + pub fn set_destination(&self, width: i32, height: i32) { + self.con.request(SetDestination { + self_id: self.id, + width, + height, + }); + } +} + +usr_object_base! { + UsrWpViewport, WpViewport; +} + +impl UsrObject for UsrWpViewport { + fn destroy(&self) { + self.con.request(Destroy { self_id: self.id }); + } +} diff --git a/src/wl_usr/usr_ifs/usr_wp_viewporter.rs b/src/wl_usr/usr_ifs/usr_wp_viewporter.rs new file mode 100644 index 00000000..0f3e224e --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_wp_viewporter.rs @@ -0,0 +1,42 @@ +use { + crate::{ + wire::{wp_viewporter::*, WpViewporterId}, + wl_usr::{ + usr_ifs::{usr_wl_surface::UsrWlSurface, usr_wp_viewport::UsrWpViewport}, + usr_object::UsrObject, + UsrCon, + }, + }, + std::rc::Rc, +}; + +pub struct UsrWpViewporter { + pub id: WpViewporterId, + pub con: Rc, +} + +impl UsrWpViewporter { + pub fn get_viewport(&self, surface: &UsrWlSurface) -> Rc { + let wv = Rc::new(UsrWpViewport { + id: self.con.id(), + con: self.con.clone(), + }); + self.con.add_object(wv.clone()); + self.con.request(GetViewport { + self_id: self.id, + id: wv.id, + surface: surface.id, + }); + wv + } +} + +usr_object_base! { + UsrWpViewporter, WpViewporter; +} + +impl UsrObject for UsrWpViewporter { + fn destroy(&self) { + self.con.request(Destroy { self_id: self.id }); + } +} diff --git a/src/wl_usr/usr_ifs/usr_zwlr_screencopy_frame.rs b/src/wl_usr/usr_ifs/usr_zwlr_screencopy_frame.rs new file mode 100644 index 00000000..4d2f80b9 --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_zwlr_screencopy_frame.rs @@ -0,0 +1,138 @@ +use { + crate::{ + utils::{ + buffd::{MsgParser, MsgParserError}, + clonecell::CloneCell, + }, + wire::{zwlr_screencopy_frame_v1::*, ZwlrScreencopyFrameV1Id}, + wl_usr::{usr_ifs::usr_wl_buffer::UsrWlBuffer, usr_object::UsrObject, UsrCon}, + }, + std::rc::Rc, +}; + +pub struct UsrZwlrScreencopyFrame { + pub id: ZwlrScreencopyFrameV1Id, + pub con: Rc, + pub owner: CloneCell>>, +} + +pub trait UsrZwlrScreencopyFrameOwner { + fn buffer(&self, buffer: &Buffer) { + let _ = buffer; + } + + fn flags(&self, flags: &Flags) { + let _ = flags; + } + + fn ready(&self, ready: &Ready) { + let _ = ready; + } + + fn failed(&self) {} + + fn damage(&self, damage: &Damage) { + let _ = damage; + } + + fn linux_dmabuf(&self, dmabuf: &LinuxDmabuf) { + let _ = dmabuf; + } + + fn buffer_done(&self) {} +} + +impl UsrZwlrScreencopyFrame { + pub fn copy(&self, buffer: &UsrWlBuffer) { + self.con.request(Copy { + self_id: self.id, + buffer: buffer.id, + }); + } + + #[allow(dead_code)] + pub fn copy_with_damage(&self, buffer: &UsrWlBuffer) { + self.con.request(CopyWithDamage { + self_id: self.id, + buffer: buffer.id, + }); + } + + fn buffer(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: Buffer = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.buffer(&ev); + } + Ok(()) + } + + fn flags(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: Flags = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.flags(&ev); + } + Ok(()) + } + + fn ready(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: Ready = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.ready(&ev); + } + Ok(()) + } + + fn failed(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let _ev: Failed = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.failed(); + } + Ok(()) + } + + fn damage(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: Damage = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.damage(&ev); + } + Ok(()) + } + + fn linux_dmabuf(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let ev: LinuxDmabuf = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.linux_dmabuf(&ev); + } + Ok(()) + } + + fn buffer_done(&self, parser: MsgParser<'_, '_>) -> Result<(), MsgParserError> { + let _ev: BufferDone = self.con.parse(self, parser)?; + if let Some(owner) = self.owner.get() { + owner.buffer_done(); + } + Ok(()) + } +} + +usr_object_base! { + UsrZwlrScreencopyFrame, ZwlrScreencopyFrameV1; + + BUFFER => buffer, + FLAGS => flags, + READY => ready, + FAILED => failed, + DAMAGE => damage, + LINUX_DMABUF => linux_dmabuf, + BUFFER_DONE => buffer_done, +} + +impl UsrObject for UsrZwlrScreencopyFrame { + fn destroy(&self) { + self.con.request(Destroy { self_id: self.id }); + } + + fn break_loops(&self) { + self.owner.take(); + } +} diff --git a/src/wl_usr/usr_ifs/usr_zwlr_screencopy_manager.rs b/src/wl_usr/usr_ifs/usr_zwlr_screencopy_manager.rs new file mode 100644 index 00000000..6013b87e --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_zwlr_screencopy_manager.rs @@ -0,0 +1,45 @@ +use { + crate::{ + wire::{zwlr_screencopy_manager_v1::*, ZwlrScreencopyManagerV1Id}, + wl_usr::{ + usr_ifs::{ + usr_wl_output::UsrWlOutput, usr_zwlr_screencopy_frame::UsrZwlrScreencopyFrame, + }, + usr_object::UsrObject, + UsrCon, + }, + }, + std::rc::Rc, +}; +pub struct UsrZwlrScreencopyManager { + pub id: ZwlrScreencopyManagerV1Id, + pub con: Rc, +} + +impl UsrZwlrScreencopyManager { + pub fn capture_output(&self, output: &UsrWlOutput) -> Rc { + let frame = Rc::new(UsrZwlrScreencopyFrame { + id: self.con.id(), + con: self.con.clone(), + owner: Default::default(), + }); + self.con.request(CaptureOutput { + self_id: self.id, + frame: frame.id, + overlay_cursor: 0, + output: output.id, + }); + self.con.add_object(frame.clone()); + frame + } +} + +usr_object_base! { + UsrZwlrScreencopyManager, ZwlrScreencopyManagerV1; +} + +impl UsrObject for UsrZwlrScreencopyManager { + fn destroy(&self) { + self.con.request(Destroy { self_id: self.id }); + } +} diff --git a/src/wl_usr/usr_object.rs b/src/wl_usr/usr_object.rs new file mode 100644 index 00000000..23a126d2 --- /dev/null +++ b/src/wl_usr/usr_object.rs @@ -0,0 +1,44 @@ +use { + crate::{ + object::{Interface, ObjectId}, + utils::buffd::MsgParser, + }, + std::rc::Rc, + thiserror::Error, +}; + +#[derive(Debug, Error)] +pub enum UsrObjectErrorType { + #[error("Could not process a `{event}` event")] + EventError { + event: &'static str, + #[source] + error: Box, + }, + #[error("Unknown event {event}")] + UnknownEventError { event: u32 }, +} + +#[derive(Debug, Error)] +#[error("An error occurred in a `{}`", .interface.name())] +pub struct UsrObjectError { + pub interface: Interface, + #[source] + pub ty: UsrObjectErrorType, +} + +pub trait UsrObjectBase { + fn id(&self) -> ObjectId; + fn handle_event( + self: Rc, + event: u32, + parser: MsgParser<'_, '_>, + ) -> Result<(), UsrObjectError>; + fn interface(&self) -> Interface; +} + +pub trait UsrObject: UsrObjectBase + 'static { + fn destroy(&self); + + fn break_loops(&self) {} +}