diff --git a/Cargo.lock b/Cargo.lock index fadd0fe1..3d33a90f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -39,6 +39,18 @@ dependencies = [ "winapi", ] +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "cc" version = "1.0.72" @@ -191,9 +203,12 @@ version = "0.1.0" dependencies = [ "ahash", "anyhow", + "bitflags", "env_logger", "futures", "log", + "num-derive", + "num-traits", "thiserror", "uapi", "waker-fn", @@ -226,6 +241,26 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +[[package]] +name = "num-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + [[package]] name = "once_cell" version = "1.9.0" diff --git a/Cargo.toml b/Cargo.toml index fc408409..50a94f78 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,3 +20,6 @@ log = "0.4.14" env_logger = "0.9.0" futures = "0.3.19" waker-fn = "1.1.0" +num-traits = "0.2.14" +num-derive = "0.3.3" +bitflags = "1.3.2" diff --git a/src/acceptor.rs b/src/acceptor.rs index 08b410ce..5ff35eff 100644 --- a/src/acceptor.rs +++ b/src/acceptor.rs @@ -91,7 +91,7 @@ impl Acceptor { if let Err(e) = uapi::listen(fd.raw(), 4096) { return Err(AcceptorError::ListenFailed(e.into())); } - let id = global.el.id()?; + let id = global.el.id(); let acc = Rc::new(Acceptor { _unlinker: unlinker, id, diff --git a/src/async_engine.rs b/src/async_engine.rs index b56b996b..272b87c1 100644 --- a/src/async_engine.rs +++ b/src/async_engine.rs @@ -1,8 +1,8 @@ pub use crate::async_engine::yield_::Yield; -use crate::event_loop::{EventLoopError, EventLoopRef}; +use crate::event_loop::{EventLoop, EventLoopError}; use crate::utils::copyhashmap::CopyHashMap; use crate::utils::numcell::NumCell; -use crate::wheel::{WheelError, WheelRef}; +use crate::wheel::{Wheel, WheelError}; pub use fd::AsyncFd; use fd::AsyncFdData; use queue::{DispatchQueue, Dispatcher}; @@ -24,21 +24,21 @@ pub enum AsyncError { } pub struct AsyncEngine { - wheel: WheelRef, - el: EventLoopRef, + wheel: Rc, + el: Rc, queue: Rc, fds: CopyHashMap>, } impl AsyncEngine { - pub fn new(el: &EventLoopRef, wheel: &WheelRef) -> Result { + pub fn install(el: &Rc, wheel: &Rc) -> Result, AsyncError> { let queue = Dispatcher::install(el)?; - Ok(Self { + Ok(Rc::new(Self { wheel: wheel.clone(), el: el.clone(), queue, fds: CopyHashMap::new(), - }) + })) } pub fn timeout(&self, ms: u64) -> Result { @@ -46,7 +46,7 @@ impl AsyncEngine { expired: Cell::new(false), waker: RefCell::new(None), }); - let id = self.wheel.id()?; + let id = self.wheel.id(); self.wheel.timeout(id, ms, data.clone())?; Ok(Timeout { id, @@ -64,7 +64,7 @@ impl AsyncEngine { afd.ref_count.fetch_add(1); afd } else { - let id = self.el.id()?; + let id = self.el.id(); let afd = Rc::new(AsyncFdData { ref_count: NumCell::new(1), fd: fd.clone(), @@ -120,7 +120,7 @@ mod yield_ { } mod timeout { - use crate::wheel::{WheelDispatcher, WheelId, WheelRef}; + use crate::wheel::{Wheel, WheelDispatcher, WheelId}; use std::cell::{Cell, RefCell}; use std::error::Error; use std::future::Future; @@ -145,7 +145,7 @@ mod timeout { pub struct Timeout { pub(super) id: WheelId, - pub(super) wheel: WheelRef, + pub(super) wheel: Rc, pub(super) data: Rc, } @@ -402,7 +402,7 @@ mod task { mod queue { use crate::async_engine::task::Runnable; use crate::async_engine::AsyncError; - use crate::event_loop::{EventLoopDispatcher, EventLoopId, EventLoopRef}; + use crate::event_loop::{EventLoop, EventLoopDispatcher, EventLoopId}; use crate::utils::numcell::NumCell; use std::cell::{Cell, RefCell}; use std::collections::VecDeque; @@ -416,8 +416,8 @@ mod queue { } impl Dispatcher { - pub fn install(el: &EventLoopRef) -> Result, AsyncError> { - let id = el.id()?; + pub fn install(el: &Rc) -> Result, AsyncError> { + let id = el.id(); let queue = Rc::new(DispatchQueue { id, el: el.clone(), @@ -462,7 +462,7 @@ mod queue { pub(super) struct DispatchQueue { dispatch_scheduled: Cell, id: EventLoopId, - el: EventLoopRef, + el: Rc, queue: RefCell>, iteration: NumCell, } @@ -484,7 +484,7 @@ mod queue { mod fd { use crate::async_engine::{AsyncEngine, AsyncError}; - use crate::event_loop::{EventLoopDispatcher, EventLoopError, EventLoopId, EventLoopRef}; + use crate::event_loop::{EventLoop, EventLoopDispatcher, EventLoopError, EventLoopId}; use crate::utils::numcell::NumCell; use std::cell::{Cell, RefCell}; use std::error::Error; @@ -500,7 +500,7 @@ mod fd { pub(super) ref_count: NumCell, pub(super) fd: Rc, pub(super) id: EventLoopId, - pub(super) el: EventLoopRef, + pub(super) el: Rc, pub(super) write_registered: Cell, pub(super) read_registered: Cell, pub(super) readers: Queue, diff --git a/src/client/mod.rs b/src/client/mod.rs index 003f6930..d9a2304b 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -9,8 +9,12 @@ use crate::ifs::wl_shm::{WlShmError, WlShmObj}; use crate::ifs::wl_shm_pool::{WlShmPool, WlShmPoolError}; use crate::ifs::wl_subcompositor::{WlSubcompositorError, WlSubcompositorObj}; use crate::ifs::wl_surface::wl_subsurface::{WlSubsurface, WlSubsurfaceError}; +use crate::ifs::wl_surface::xdg_surface::xdg_popup::XdgPopupError; +use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::XdgToplevelError; +use crate::ifs::wl_surface::xdg_surface::{XdgSurface, XdgSurfaceError}; use crate::ifs::wl_surface::{WlSurface, WlSurfaceError}; -use crate::ifs::xdg_wm_base::XdgWmBaseObj; +use crate::ifs::xdg_positioner::{XdgPositioner, XdgPositionerError}; +use crate::ifs::xdg_wm_base::{XdgWmBaseError, XdgWmBaseObj}; use crate::object::{Object, ObjectId, WL_DISPLAY_ID}; use crate::state::State; use crate::utils::buffd::{BufFdError, MsgFormatter, MsgParser, MsgParserError}; @@ -86,6 +90,16 @@ pub enum ClientError { WlSubsurfaceError(#[source] Box), #[error("An error occurred in a `wl_subcompositor`")] WlSubcompositorError(#[source] Box), + #[error("An error occurred in a `xdg_surface`")] + XdgSurfaceError(#[source] Box), + #[error("An error occurred in a `xdg_positioner`")] + XdgPositionerError(#[source] Box), + #[error("An error occurred in a `xdg_popup`")] + XdgPopupError(#[source] Box), + #[error("An error occurred in a `xdg_toplevel`")] + XdgToplevelError(#[source] Box), + #[error("An error occurred in a `xdg_wm_base`")] + XdgWmBaseError(#[source] Box), #[error("Object {0} is not a display")] NotADisplay(ObjectId), } @@ -100,6 +114,11 @@ efrom!(ClientError, WlShmPoolError, WlShmPoolError); efrom!(ClientError, WlRegionError, WlRegionError); efrom!(ClientError, WlSubsurfaceError, WlSubsurfaceError); efrom!(ClientError, WlSubcompositorError, WlSubcompositorError); +efrom!(ClientError, XdgSurfaceError, XdgSurfaceError); +efrom!(ClientError, XdgPositionerError, XdgPositionerError); +efrom!(ClientError, XdgWmBaseError, XdgWmBaseError); +efrom!(ClientError, XdgToplevelError, XdgToplevelError); +efrom!(ClientError, XdgPopupError, XdgPopupError); impl ClientError { fn peer_closed(&self) -> bool { @@ -162,9 +181,9 @@ impl Clients { shutdown: Cell::new(Some(send)), shutdown_sent: Cell::new(false), }); - data.objects - .add_client_object(Rc::new(WlDisplay::new(&data))) - .expect(""); + let display = Rc::new(WlDisplay::new(&data)); + *data.objects.display.borrow_mut() = Some(display.clone()); + data.objects.add_client_object(display).expect(""); let client = ClientHolder { _handler: global.eng.spawn(tasks::client(data.clone(), recv)), data, @@ -272,7 +291,10 @@ impl Client { } pub fn display(&self) -> Result, ClientError> { - Ok(self.objects.get_obj(WL_DISPLAY_ID)?.into_display()?) + match self.objects.display.borrow_mut().clone() { + Some(d) => Ok(d), + _ => Err(ClientError::NotADisplay(WL_DISPLAY_ID)), + } } pub fn parse<'a, R: RequestParser<'a>>( @@ -292,6 +314,14 @@ impl Client { Ok(res) } + pub fn protocol_error(&self, obj: &dyn Object, code: u32, message: String) { + if let Ok(d) = self.display() { + self.fatal_event(d.error(obj.id(), code, message)); + } else { + self.state.clients.shutdown(self.id); + } + } + pub fn fatal_event(&self, event: Box) { self.events.push(WlEvent::Event(event)); self.state.clients.shutdown(self.id); @@ -407,7 +437,8 @@ simple_add_obj!(WlShmObj); simple_add_obj!(WlShmPool); simple_add_obj!(WlSubcompositorObj); simple_add_obj!(WlSubsurface); -simple_add_obj!(XdgWmBaseObj); +simple_add_obj!(XdgPositioner); +simple_add_obj!(XdgSurface); macro_rules! dedicated_add_obj { ($ty:ty, $field:ident) => { @@ -429,3 +460,4 @@ macro_rules! dedicated_add_obj { dedicated_add_obj!(WlRegion, regions); dedicated_add_obj!(WlSurface, surfaces); +dedicated_add_obj!(XdgWmBaseObj, xdg_wm_bases); diff --git a/src/client/objects.rs b/src/client/objects.rs index 014b1c9e..b7a31153 100644 --- a/src/client/objects.rs +++ b/src/client/objects.rs @@ -1,4 +1,5 @@ use crate::client::{Client, ClientError}; +use crate::ifs::wl_display::WlDisplay; use crate::ifs::wl_region::WlRegion; use crate::ifs::wl_registry::WlRegistry; use crate::ifs::wl_surface::WlSurface; @@ -8,12 +9,15 @@ use ahash::AHashMap; use std::cell::{RefCell, RefMut}; use std::mem; use std::rc::Rc; +use crate::ifs::xdg_wm_base::XdgWmBaseObj; pub struct Objects { + pub display: RefCell>>, registry: CopyHashMap>, registries: CopyHashMap>, pub surfaces: CopyHashMap>, pub regions: CopyHashMap>, + pub xdg_wm_bases: CopyHashMap>, ids: RefCell>, } @@ -23,10 +27,12 @@ const SEG_SIZE: usize = 8 * mem::size_of::(); impl Objects { pub fn new() -> Self { Self { + display: RefCell::new(None), registry: Default::default(), registries: Default::default(), surfaces: Default::default(), regions: Default::default(), + xdg_wm_bases: Default::default(), ids: RefCell::new(vec![]), } } @@ -38,6 +44,13 @@ impl Objects { surface.break_loops(); } } + { + let mut xdg_wm_bases = self.xdg_wm_bases.lock(); + for xdg_wm_base in xdg_wm_bases.values_mut() { + xdg_wm_base.break_loops(); + } + } + *self.display.borrow_mut() = None; self.registry.clear(); self.regions.clear(); self.registries.clear(); diff --git a/src/client/tasks.rs b/src/client/tasks.rs index c21e9be1..84e578d0 100644 --- a/src/client/tasks.rs +++ b/src/client/tasks.rs @@ -114,7 +114,10 @@ async fn send(data: Rc) { if log::log_enabled!(log::Level::Trace) { data.log_event(&*e); } - e.format(&mut MsgFormatter::new(&mut buf)); + let mut fds = vec![]; + let mut fmt = MsgFormatter::new(&mut buf, &mut fds); + e.format(&mut fmt); + fmt.write_len(); if buf.needs_flush() { buf.flush().await?; flush_requested = false; diff --git a/src/event_loop.rs b/src/event_loop.rs index f7c02549..a582540d 100644 --- a/src/event_loop.rs +++ b/src/event_loop.rs @@ -2,7 +2,7 @@ use crate::utils::copyhashmap::CopyHashMap; use crate::utils::numcell::NumCell; use std::cell::{Cell, RefCell}; use std::collections::VecDeque; -use std::rc::{Rc, Weak}; +use std::rc::Rc; use thiserror::Error; use uapi::{c, Errno, OwnedFd}; @@ -39,53 +39,53 @@ struct Entry { dispatcher: Rc, } -struct EventLoopData { +pub struct EventLoop { + destroyed: Cell, epoll: OwnedFd, - run: Cell, next_id: NumCell, entries: CopyHashMap, scheduled: RefCell>, } -pub struct EventLoop { - data: Rc, -} - -#[derive(Clone)] -pub struct EventLoopRef { - data: Weak, -} - -impl EventLoopData { - fn new() -> Result { +impl EventLoop { + pub fn new() -> Result, EventLoopError> { let epoll = match uapi::epoll_create1(c::EPOLL_CLOEXEC) { Ok(e) => e, Err(e) => return Err(EventLoopError::CreateFailed(e.into())), }; - Ok(Self { + Ok(Rc::new(Self { + destroyed: Cell::new(false), epoll, - run: Cell::new(true), next_id: NumCell::new(1), entries: CopyHashMap::new(), scheduled: RefCell::new(Default::default()), - }) + })) } - fn id(&self) -> EventLoopId { + fn check_destroyed(&self) -> Result<(), EventLoopError> { + if self.destroyed.get() { + return Err(EventLoopError::Destroyed); + } + Ok(()) + } + + pub fn id(&self) -> EventLoopId { EventLoopId(self.next_id.fetch_add(1)) } - fn stop(&self) { - self.run.set(false); + pub fn stop(&self) { + self.destroyed.set(true); + self.entries.clear(); } - fn insert( + pub fn insert( &self, id: EventLoopId, fd: Option, events: i32, dispatcher: Rc, ) -> Result<(), EventLoopError> { + self.check_destroyed()?; let id = id.0; if let Some(fd) = fd { let event = c::epoll_event { @@ -100,7 +100,8 @@ impl EventLoopData { Ok(()) } - fn modify(&self, id: EventLoopId, events: i32) -> Result<(), EventLoopError> { + pub fn modify(&self, id: EventLoopId, events: i32) -> Result<(), EventLoopError> { + self.check_destroyed()?; let id = id.0; let entry = match self.entries.get(&id) { Some(e) => e, @@ -118,7 +119,8 @@ impl EventLoopData { Ok(()) } - fn remove(&self, id: EventLoopId) -> Result<(), EventLoopError> { + pub fn remove(&self, id: EventLoopId) -> Result<(), EventLoopError> { + self.check_destroyed()?; let id = id.0; let entry = match self.entries.remove(&id) { Some(e) => e, @@ -132,15 +134,24 @@ impl EventLoopData { Ok(()) } - fn schedule(&self, id: EventLoopId) { + pub fn schedule(&self, id: EventLoopId) -> Result<(), EventLoopError> { + self.check_destroyed()?; self.scheduled.borrow_mut().push_back(id.0); + Ok(()) } - fn run(&self) -> Result<(), EventLoopError> { + pub fn run(&self) -> Result<(), EventLoopError> { + let res = self.run_(); + self.stop(); + res + } + + fn run_(&self) -> Result<(), EventLoopError> { + self.check_destroyed()?; let mut buf = [c::epoll_event { events: 0, u64: 0 }; 16]; - while self.run.get() { + while !self.destroyed.get() { while let Some(id) = self.scheduled.borrow_mut().pop_front() { - if !self.run.get() { + if self.destroyed.get() { break; } if let Some(entry) = self.entries.get(&id) { @@ -155,7 +166,7 @@ impl EventLoopData { Err(e) => return Err(EventLoopError::WaitFailed(e.into())), }; for event in &buf[..num] { - if !self.run.get() { + if self.destroyed.get() { break; } let id = event.u64; @@ -177,70 +188,3 @@ impl EventLoopData { Ok(()) } } - -impl EventLoop { - pub fn new() -> Result { - Ok(Self { - data: Rc::new(EventLoopData::new()?), - }) - } - - pub fn to_ref(&self) -> EventLoopRef { - EventLoopRef { - data: Rc::downgrade(&self.data), - } - } - - pub fn run(&self) -> Result<(), EventLoopError> { - self.data.run() - } -} - -impl EventLoopRef { - pub fn id(&self) -> Result { - match self.data.upgrade() { - Some(d) => Ok(d.id()), - None => Err(EventLoopError::Destroyed), - } - } - - pub fn stop(&self) { - if let Some(d) = self.data.upgrade() { - d.stop(); - } - } - - pub fn insert( - &self, - id: EventLoopId, - fd: Option, - events: i32, - dispatcher: Rc, - ) -> Result<(), EventLoopError> { - match self.data.upgrade() { - Some(d) => d.insert(id, fd, events, dispatcher), - None => Err(EventLoopError::Destroyed), - } - } - - pub fn modify(&self, id: EventLoopId, events: i32) -> Result<(), EventLoopError> { - match self.data.upgrade() { - Some(d) => d.modify(id, events), - None => Err(EventLoopError::Destroyed), - } - } - - pub fn remove(&self, id: EventLoopId) -> Result<(), EventLoopError> { - match self.data.upgrade() { - Some(d) => d.remove(id), - None => Err(EventLoopError::Destroyed), - } - } - - pub fn schedule(&self, id: EventLoopId) -> Result<(), EventLoopError> { - match self.data.upgrade() { - Some(d) => Ok(d.schedule(id)), - None => Err(EventLoopError::Destroyed), - } - } -} diff --git a/src/format.rs b/src/format.rs new file mode 100644 index 00000000..a12ad5f1 --- /dev/null +++ b/src/format.rs @@ -0,0 +1,462 @@ +use ahash::AHashMap; + +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct Format { + pub id: u32, + pub name: &'static str, +} + +pub fn formats() -> AHashMap { + let mut map = AHashMap::new(); + for format in FORMATS { + assert!(map.insert(format.id, format).is_none()); + } + map +} + +const fn fourcc_code(a: char, b: char, c: char, d: char) -> u32 { + (a as u32) | ((b as u32) << 8) | ((c as u32) << 16) | ((d as u32) << 24) +} + +static FORMATS: &[Format] = &[ + Format { + id: 0, + name: "argb8888", + }, + Format { + id: 1, + name: "xrgb8888", + }, + // Format { + // id: fourcc_code('C', '8', ' ', ' '), + // name: "c8", + // }, + // Format { + // id: fourcc_code('R', '8', ' ', ' '), + // name: "r8", + // }, + // Format { + // id: fourcc_code('R', '1', '6', ' '), + // name: "r16", + // }, + // Format { + // id: fourcc_code('R', 'G', '8', '8'), + // name: "rg88", + // }, + // Format { + // id: fourcc_code('G', 'R', '8', '8'), + // name: "gr88", + // }, + // Format { + // id: fourcc_code('R', 'G', '3', '2'), + // name: "rg1616", + // }, + // Format { + // id: fourcc_code('G', 'R', '3', '2'), + // name: "gr1616", + // }, + // Format { + // id: fourcc_code('R', 'G', 'B', '8'), + // name: "rgb332", + // }, + // Format { + // id: fourcc_code('B', 'G', 'R', '8'), + // name: "bgr233", + // }, + // Format { + // id: fourcc_code('X', 'R', '1', '2'), + // name: "xrgb4444", + // }, + // Format { + // id: fourcc_code('X', 'B', '1', '2'), + // name: "xbgr4444", + // }, + // Format { + // id: fourcc_code('R', 'X', '1', '2'), + // name: "rgbx4444", + // }, + // Format { + // id: fourcc_code('B', 'X', '1', '2'), + // name: "bgrx4444", + // }, + // Format { + // id: fourcc_code('A', 'R', '1', '2'), + // name: "argb4444", + // }, + // Format { + // id: fourcc_code('A', 'B', '1', '2'), + // name: "abgr4444", + // }, + // Format { + // id: fourcc_code('R', 'A', '1', '2'), + // name: "rgba4444", + // }, + // Format { + // id: fourcc_code('B', 'A', '1', '2'), + // name: "bgra4444", + // }, + // Format { + // id: fourcc_code('X', 'R', '1', '5'), + // name: "xrgb1555", + // }, + // Format { + // id: fourcc_code('X', 'B', '1', '5'), + // name: "xbgr1555", + // }, + // Format { + // id: fourcc_code('R', 'X', '1', '5'), + // name: "rgbx5551", + // }, + // Format { + // id: fourcc_code('B', 'X', '1', '5'), + // name: "bgrx5551", + // }, + // Format { + // id: fourcc_code('A', 'R', '1', '5'), + // name: "argb1555", + // }, + // Format { + // id: fourcc_code('A', 'B', '1', '5'), + // name: "abgr1555", + // }, + // Format { + // id: fourcc_code('R', 'A', '1', '5'), + // name: "rgba5551", + // }, + // Format { + // id: fourcc_code('B', 'A', '1', '5'), + // name: "bgra5551", + // }, + // Format { + // id: fourcc_code('R', 'G', '1', '6'), + // name: "rgb565", + // }, + // Format { + // id: fourcc_code('B', 'G', '1', '6'), + // name: "bgr565", + // }, + // Format { + // id: fourcc_code('R', 'G', '2', '4'), + // name: "rgb888", + // }, + // Format { + // id: fourcc_code('B', 'G', '2', '4'), + // name: "bgr888", + // }, + // Format { + // id: fourcc_code('X', 'R', '2', '4'), + // name: "xrgb8888", + // }, + // Format { + // id: fourcc_code('X', 'B', '2', '4'), + // name: "xbgr8888", + // }, + // Format { + // id: fourcc_code('R', 'X', '2', '4'), + // name: "rgbx8888", + // }, + // Format { + // id: fourcc_code('B', 'X', '2', '4'), + // name: "bgrx8888", + // }, + // Format { + // id: fourcc_code('A', 'R', '2', '4'), + // name: "argb8888", + // }, + // Format { + // id: fourcc_code('A', 'B', '2', '4'), + // name: "abgr8888", + // }, + // Format { + // id: fourcc_code('R', 'A', '2', '4'), + // name: "rgba8888", + // }, + // Format { + // id: fourcc_code('B', 'A', '2', '4'), + // name: "bgra8888", + // }, + // Format { + // id: fourcc_code('X', 'R', '3', '0'), + // name: "xrgb2101010", + // }, + // Format { + // id: fourcc_code('X', 'B', '3', '0'), + // name: "xbgr2101010", + // }, + // Format { + // id: fourcc_code('R', 'X', '3', '0'), + // name: "rgbx1010102", + // }, + // Format { + // id: fourcc_code('B', 'X', '3', '0'), + // name: "bgrx1010102", + // }, + // Format { + // id: fourcc_code('A', 'R', '3', '0'), + // name: "argb2101010", + // }, + // Format { + // id: fourcc_code('A', 'B', '3', '0'), + // name: "abgr2101010", + // }, + // Format { + // id: fourcc_code('R', 'A', '3', '0'), + // name: "rgba1010102", + // }, + // Format { + // id: fourcc_code('B', 'A', '3', '0'), + // name: "bgra1010102", + // }, + // Format { + // id: fourcc_code('X', 'R', '4', '8'), + // name: "xrgb16161616", + // }, + // Format { + // id: fourcc_code('X', 'B', '4', '8'), + // name: "xbgr16161616", + // }, + // Format { + // id: fourcc_code('A', 'R', '4', '8'), + // name: "argb16161616", + // }, + // Format { + // id: fourcc_code('A', 'B', '4', '8'), + // name: "abgr16161616", + // }, + // Format { + // id: fourcc_code('X', 'R', '4', 'H'), + // name: "xrgb16161616f", + // }, + // Format { + // id: fourcc_code('X', 'B', '4', 'H'), + // name: "xbgr16161616f", + // }, + // Format { + // id: fourcc_code('A', 'R', '4', 'H'), + // name: "argb16161616f", + // }, + // Format { + // id: fourcc_code('A', 'B', '4', 'H'), + // name: "abgr16161616f", + // }, + // Format { + // id: fourcc_code('A', 'B', '1', '0'), + // name: "axbxgxrx106106106106", + // }, + // Format { + // id: fourcc_code('Y', 'U', 'Y', 'V'), + // name: "yuyv", + // }, + // Format { + // id: fourcc_code('Y', 'V', 'Y', 'U'), + // name: "yvyu", + // }, + // Format { + // id: fourcc_code('U', 'Y', 'V', 'Y'), + // name: "uyvy", + // }, + // Format { + // id: fourcc_code('V', 'Y', 'U', 'Y'), + // name: "vyuy", + // }, + // Format { + // id: fourcc_code('A', 'Y', 'U', 'V'), + // name: "ayuv", + // }, + // Format { + // id: fourcc_code('X', 'Y', 'U', 'V'), + // name: "xyuv8888", + // }, + // Format { + // id: fourcc_code('V', 'U', '2', '4'), + // name: "vuy888", + // }, + // Format { + // id: fourcc_code('V', 'U', '3', '0'), + // name: "vuy101010", + // }, + // Format { + // id: fourcc_code('Y', '2', '1', '0'), + // name: "y210", + // }, + // Format { + // id: fourcc_code('Y', '2', '1', '2'), + // name: "y212", + // }, + // Format { + // id: fourcc_code('Y', '2', '1', '6'), + // name: "y216", + // }, + // Format { + // id: fourcc_code('Y', '4', '1', '0'), + // name: "y410", + // }, + // Format { + // id: fourcc_code('Y', '4', '1', '2'), + // name: "y412", + // }, + // Format { + // id: fourcc_code('Y', '4', '1', '6'), + // name: "y416", + // }, + // Format { + // id: fourcc_code('X', 'V', '3', '0'), + // name: "xvyu2101010", + // }, + // Format { + // id: fourcc_code('X', 'V', '3', '6'), + // name: "xvyu12_16161616", + // }, + // Format { + // id: fourcc_code('X', 'V', '4', '8'), + // name: "xvyu16161616", + // }, + // Format { + // id: fourcc_code('Y', '0', 'L', '0'), + // name: "y0l0", + // }, + // Format { + // id: fourcc_code('X', '0', 'L', '0'), + // name: "x0l0", + // }, + // Format { + // id: fourcc_code('Y', '0', 'L', '2'), + // name: "y0l2", + // }, + // Format { + // id: fourcc_code('X', '0', 'L', '2'), + // name: "x0l2", + // }, + // Format { + // id: fourcc_code('Y', 'U', '0', '8'), + // name: "yuv420_8bit", + // }, + // Format { + // id: fourcc_code('Y', 'U', '1', '0'), + // name: "yuv420_10bit", + // }, + // Format { + // id: fourcc_code('X', 'R', 'A', '8'), + // name: "xrgb8888_a8", + // }, + // Format { + // id: fourcc_code('X', 'B', 'A', '8'), + // name: "xbgr8888_a8", + // }, + // Format { + // id: fourcc_code('R', 'X', 'A', '8'), + // name: "rgbx8888_a8", + // }, + // Format { + // id: fourcc_code('B', 'X', 'A', '8'), + // name: "bgrx8888_a8", + // }, + // Format { + // id: fourcc_code('R', '8', 'A', '8'), + // name: "rgb888_a8", + // }, + // Format { + // id: fourcc_code('B', '8', 'A', '8'), + // name: "bgr888_a8", + // }, + // Format { + // id: fourcc_code('R', '5', 'A', '8'), + // name: "rgb565_a8", + // }, + // Format { + // id: fourcc_code('B', '5', 'A', '8'), + // name: "bgr565_a8", + // }, + // Format { + // id: fourcc_code('N', 'V', '1', '2'), + // name: "nv12", + // }, + // Format { + // id: fourcc_code('N', 'V', '2', '1'), + // name: "nv21", + // }, + // Format { + // id: fourcc_code('N', 'V', '1', '6'), + // name: "nv16", + // }, + // Format { + // id: fourcc_code('N', 'V', '6', '1'), + // name: "nv61", + // }, + // Format { + // id: fourcc_code('N', 'V', '2', '4'), + // name: "nv24", + // }, + // Format { + // id: fourcc_code('N', 'V', '4', '2'), + // name: "nv42", + // }, + // Format { + // id: fourcc_code('N', 'V', '1', '5'), + // name: "nv15", + // }, + // Format { + // id: fourcc_code('P', '2', '1', '0'), + // name: "p210", + // }, + // Format { + // id: fourcc_code('P', '0', '1', '0'), + // name: "p010", + // }, + // Format { + // id: fourcc_code('P', '0', '1', '2'), + // name: "p012", + // }, + // Format { + // id: fourcc_code('P', '0', '1', '6'), + // name: "p016", + // }, + // Format { + // id: fourcc_code('Q', '4', '1', '0'), + // name: "q410", + // }, + // Format { + // id: fourcc_code('Q', '4', '0', '1'), + // name: "q401", + // }, + // Format { + // id: fourcc_code('Y', 'U', 'V', '9'), + // name: "yuv410", + // }, + // Format { + // id: fourcc_code('Y', 'V', 'U', '9'), + // name: "yvu410", + // }, + // Format { + // id: fourcc_code('Y', 'U', '1', '1'), + // name: "yuv411", + // }, + // Format { + // id: fourcc_code('Y', 'V', '1', '1'), + // name: "yvu411", + // }, + // Format { + // id: fourcc_code('Y', 'U', '1', '2'), + // name: "yuv420", + // }, + // Format { + // id: fourcc_code('Y', 'V', '1', '2'), + // name: "yvu420", + // }, + // Format { + // id: fourcc_code('Y', 'U', '1', '6'), + // name: "yuv422", + // }, + // Format { + // id: fourcc_code('Y', 'V', '1', '6'), + // name: "yvu422", + // }, + // Format { + // id: fourcc_code('Y', 'U', '2', '4'), + // name: "yuv444", + // }, + // Format { + // id: fourcc_code('Y', 'V', '2', '4'), + // name: "yvu444", + // }, +]; diff --git a/src/ifs/mod.rs b/src/ifs/mod.rs index b9e074be..daabcaef 100644 --- a/src/ifs/mod.rs +++ b/src/ifs/mod.rs @@ -7,4 +7,5 @@ pub mod wl_shm; pub mod wl_shm_pool; pub mod wl_subcompositor; pub mod wl_surface; +pub mod xdg_positioner; pub mod xdg_wm_base; diff --git a/src/ifs/wl_display/mod.rs b/src/ifs/wl_display/mod.rs index 604f7da4..194ecd64 100644 --- a/src/ifs/wl_display/mod.rs +++ b/src/ifs/wl_display/mod.rs @@ -1,6 +1,6 @@ mod types; -use crate::client::{AddObj, Client, ClientError, DynEventFormatter}; +use crate::client::{AddObj, Client, DynEventFormatter}; use crate::ifs::wl_callback::WlCallback; use crate::ifs::wl_registry::WlRegistry; use crate::object::{Interface, Object, ObjectId, WL_DISPLAY_ID}; @@ -64,7 +64,7 @@ impl WlDisplay { Ok(()) } - fn error( + pub fn error( self: &Rc, object_id: ObjectId, code: u32, @@ -120,8 +120,4 @@ impl Object for WlDisplay { fn num_requests(&self) -> u32 { GET_REGISTRY + 1 } - - fn into_display(self: Rc) -> Result, ClientError> { - Ok(self) - } } diff --git a/src/ifs/wl_shm/mod.rs b/src/ifs/wl_shm/mod.rs index ac1f90c8..ba8a9e27 100644 --- a/src/ifs/wl_shm/mod.rs +++ b/src/ifs/wl_shm/mod.rs @@ -39,7 +39,7 @@ impl WlShmGlobal { client: client.clone(), }); client.add_client_obj(&obj)?; - for &format in Format::formats() { + for &format in client.state.formats.values() { client .event(Box::new(FormatE { obj: obj.clone(), @@ -80,25 +80,6 @@ impl WlShmObj { } } -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub enum Format { - Argb8888, - Xrgb8888, -} - -impl Format { - fn uint(self) -> u32 { - match self { - Format::Argb8888 => 0, - Format::Xrgb8888 => 1, - } - } - - fn formats() -> &'static [Format] { - &[Format::Argb8888, Format::Xrgb8888] - } -} - bind!(WlShmGlobal); impl Global for WlShmGlobal { diff --git a/src/ifs/wl_shm/types.rs b/src/ifs/wl_shm/types.rs index 4a44994f..c89ca10a 100644 --- a/src/ifs/wl_shm/types.rs +++ b/src/ifs/wl_shm/types.rs @@ -1,5 +1,6 @@ use crate::client::{ClientError, EventFormatter, RequestParser}; -use crate::ifs::wl_shm::{Format, WlShmObj, FORMAT}; +use crate::format::Format; +use crate::ifs::wl_shm::{WlShmObj, FORMAT}; use crate::ifs::wl_shm_pool::WlShmPoolError; use crate::object::{Object, ObjectId}; use crate::utils::buffd::{MsgFormatter, MsgParser, MsgParserError}; @@ -60,11 +61,11 @@ impl Debug for CreatePool { pub(super) struct FormatE { pub obj: Rc, - pub format: Format, + pub format: &'static Format, } impl EventFormatter for FormatE { fn format(self: Box, fmt: &mut MsgFormatter<'_>) { - fmt.header(self.obj.id, FORMAT).uint(self.format.uint()); + fmt.header(self.obj.id, FORMAT).uint(self.format.id); } fn obj(&self) -> &dyn Object { &*self.obj @@ -72,6 +73,10 @@ impl EventFormatter for FormatE { } impl Debug for FormatE { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "format(format: {:?})", self.format) + write!( + f, + "format(format: \"{}\" (0x{:x}))", + self.format.name, self.format.id + ) } } diff --git a/src/ifs/wl_shm_pool/mod.rs b/src/ifs/wl_shm_pool/mod.rs index 68a3201d..2e15dba3 100644 --- a/src/ifs/wl_shm_pool/mod.rs +++ b/src/ifs/wl_shm_pool/mod.rs @@ -36,26 +36,26 @@ impl WlShmPool { } async fn create_buffer(&self, parser: MsgParser<'_, '_>) -> Result<(), CreateBufferError> { - let create: CreateBuffer = self.client.parse(self, parser)?; + let req: CreateBuffer = self.client.parse(self, parser)?; Ok(()) } async fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { - let _destroy: Destroy = self.client.parse(self, parser)?; + let _req: Destroy = self.client.parse(self, parser)?; self.client.remove_obj(self).await?; Ok(()) } async fn resize(&self, parser: MsgParser<'_, '_>) -> Result<(), ResizeError> { - let resize: Resize = self.client.parse(self, parser)?; + let req: Resize = self.client.parse(self, parser)?; let mut mem = self.mem.borrow_mut(); - if resize.size < 0 { + if req.size < 0 { return Err(ResizeError::NegativeSize); } - if (resize.size as usize) < mem.len() { + if (req.size as usize) < mem.len() { return Err(ResizeError::CannotShrink); } - *mem = Rc::new(ClientMem::new(self.fd.raw(), resize.size as usize)?); + *mem = Rc::new(ClientMem::new(self.fd.raw(), req.size as usize)?); Ok(()) } diff --git a/src/ifs/wl_subcompositor/mod.rs b/src/ifs/wl_subcompositor/mod.rs index c9d5566b..651e8da9 100644 --- a/src/ifs/wl_subcompositor/mod.rs +++ b/src/ifs/wl_subcompositor/mod.rs @@ -55,9 +55,9 @@ impl WlSubcompositorObj { let req: GetSubsurface = self.client.parse(self, parser)?; let surface = self.client.get_surface(req.surface)?; let parent = self.client.get_surface(req.parent)?; - let subsurface = Rc::new(WlSubsurface::new(req.id, &surface)); + let subsurface = Rc::new(WlSubsurface::new(req.id, &surface, &parent)); self.client.add_client_obj(&subsurface)?; - subsurface.install(&parent)?; + subsurface.install()?; Ok(()) } diff --git a/src/ifs/wl_surface/mod.rs b/src/ifs/wl_surface/mod.rs index e3a96aef..54e94823 100644 --- a/src/ifs/wl_surface/mod.rs +++ b/src/ifs/wl_surface/mod.rs @@ -1,15 +1,18 @@ mod types; pub mod wl_subsurface; +pub mod xdg_surface; -use crate::client::{Client, RequestParser}; +use crate::client::{AddObj, Client, RequestParser}; use crate::ifs::wl_surface::wl_subsurface::WlSubsurface; use crate::object::{Interface, Object, ObjectId}; use crate::pixman::Region; use crate::utils::buffd::{MsgParser, MsgParserError}; +use crate::utils::linkedlist::{LinkedList, Node}; use ahash::AHashMap; use std::cell::{Cell, RefCell}; use std::rc::Rc; pub use types::*; +use crate::ifs::wl_surface::xdg_surface::XdgSurface; const DESTROY: u32 = 0; const ATTACH: u32 = 1; @@ -30,18 +33,41 @@ const INVALID_TRANSFORM: u32 = 1; const INVALID_SIZE: u32 = 2; #[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum SurfaceType { +pub enum SurfaceRole { None, Subsurface, + XdgSurface, +} + +impl SurfaceRole { + fn name(self) -> &'static str { + match self { + SurfaceRole::None => "none", + SurfaceRole::Subsurface => "subsurface", + SurfaceRole::XdgSurface => "xdg_surface", + } + } } pub struct WlSurface { id: ObjectId, client: Rc, - ty: Cell, + role: Cell, pending: PendingState, children: RefCell>>, - subsurface_data: RefCell>>, + role_data: RefCell, +} + +enum RoleData { + None, + Subsurface(Box), + XdgSurface(Box), +} + +impl RoleData { + fn is_some(&self) -> bool { + !matches!(self, RoleData::None) + } } #[derive(Default)] @@ -50,18 +76,52 @@ struct PendingState { input_region: Cell>, } +struct XdgSurfaceData { + xdg_surface: Rc, + role: XdgSurfaceRole, +} + +enum XdgSurfaceRole { + None, + Popup(XdgPopupData), + Toplevel(XdgToplevelData), +} + +struct XdgPopupData { + +} + +struct XdgToplevelData { + +} + struct SubsurfaceData { subsurface: Rc, - parent: Rc, + x: i32, + y: i32, sync_requested: bool, sync_ancestor: bool, - pending: bool, + node: Node, + depth: u32, + pending: PendingSubsurfaceData, +} + +#[derive(Default)] +struct PendingSubsurfaceData { + node: Option>, + position: Option<(i32, i32)>, } #[derive(Default)] struct ParentData { subsurfaces: AHashMap>, - pending_subsurfaces: AHashMap>, + below: LinkedList, + above: LinkedList, +} + +struct StackElement { + pending: Cell, + surface: Rc, } impl WlSurface { @@ -69,26 +129,26 @@ impl WlSurface { Self { id, client: client.clone(), - ty: Cell::new(SurfaceType::None), + role: Cell::new(SurfaceRole::None), pending: Default::default(), children: Default::default(), - subsurface_data: Default::default(), + role_data: RefCell::new(RoleData::None), } } pub fn break_loops(&self) { *self.children.borrow_mut() = None; - *self.subsurface_data.borrow_mut() = None; + *self.role_data.borrow_mut() = RoleData::None; } pub fn get_root(self: &Rc) -> Rc { let mut root = self.clone(); loop { let tmp = root; - let data = tmp.subsurface_data.borrow(); - match data.as_ref() { - Some(d) => root = d.parent.clone(), - None => { + let data = tmp.role_data.borrow(); + match &*data { + RoleData::Subsurface(d) => root = d.subsurface.parent.clone(), + _ => { drop(data); return tmp; } @@ -104,22 +164,25 @@ impl WlSurface { } async fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { - let destroy: Destroy = self.parse(parser)?; + let _req: Destroy = self.parse(parser)?; + *self.children.borrow_mut() = None; + *self.role_data.borrow_mut() = RoleData::None; + self.client.remove_obj(self).await?; Ok(()) } async fn attach(&self, parser: MsgParser<'_, '_>) -> Result<(), AttachError> { - let attach: Attach = self.parse(parser)?; + let req: Attach = self.parse(parser)?; Ok(()) } async fn damage(&self, parser: MsgParser<'_, '_>) -> Result<(), DamageError> { - let damage: Damage = self.parse(parser)?; + let req: Damage = self.parse(parser)?; Ok(()) } async fn frame(&self, parser: MsgParser<'_, '_>) -> Result<(), FrameError> { - let frame: Frame = self.parse(parser)?; + let req: Frame = self.parse(parser)?; Ok(()) } @@ -134,14 +197,14 @@ impl WlSurface { } async fn set_input_region(&self, parser: MsgParser<'_, '_>) -> Result<(), SetInputRegionError> { - let region: SetInputRegion = self.parse(parser)?; - let region = self.client.get_region(region.region)?; + let req: SetInputRegion = self.parse(parser)?; + let region = self.client.get_region(req.region)?; self.pending.input_region.set(Some(region.region())); Ok(()) } async fn commit(&self, parser: MsgParser<'_, '_>) -> Result<(), CommitError> { - let commit: Commit = self.parse(parser)?; + let req: Commit = self.parse(parser)?; Ok(()) } @@ -149,17 +212,17 @@ impl WlSurface { &self, parser: MsgParser<'_, '_>, ) -> Result<(), SetBufferTransformError> { - let transform: SetBufferTransform = self.parse(parser)?; + let req: SetBufferTransform = self.parse(parser)?; Ok(()) } async fn set_buffer_scale(&self, parser: MsgParser<'_, '_>) -> Result<(), SetBufferScaleError> { - let scale: SetBufferScale = self.parse(parser)?; + let req: SetBufferScale = self.parse(parser)?; Ok(()) } async fn damage_buffer(&self, parser: MsgParser<'_, '_>) -> Result<(), DamageBufferError> { - let damage: DamageBuffer = self.parse(parser)?; + let req: DamageBuffer = self.parse(parser)?; Ok(()) } diff --git a/src/ifs/wl_surface/types.rs b/src/ifs/wl_surface/types.rs index 066c1970..09105edd 100644 --- a/src/ifs/wl_surface/types.rs +++ b/src/ifs/wl_surface/types.rs @@ -46,8 +46,11 @@ efrom!(WlSurfaceError, DamageBufferError, DamageBufferError); pub enum DestroyError { #[error("Parsing failed")] ParseFailed(#[source] Box), + #[error(transparent)] + ClientError(Box), } efrom!(DestroyError, ParseFailed, MsgParserError); +efrom!(DestroyError, ClientError, ClientError); #[derive(Debug, Error)] pub enum AttachError { diff --git a/src/ifs/wl_surface/wl_subsurface/mod.rs b/src/ifs/wl_surface/wl_subsurface/mod.rs index 581cd740..1a8b5bf4 100644 --- a/src/ifs/wl_surface/wl_subsurface/mod.rs +++ b/src/ifs/wl_surface/wl_subsurface/mod.rs @@ -1,8 +1,10 @@ mod types; -use crate::ifs::wl_surface::{SubsurfaceData, SurfaceType, WlSurface}; +use crate::client::AddObj; +use crate::ifs::wl_surface::{RoleData, StackElement, SubsurfaceData, SurfaceRole, WlSurface}; use crate::object::{Interface, Object, ObjectId}; use crate::utils::buffd::MsgParser; +use std::cell::Cell; use std::rc::Rc; pub use types::*; @@ -15,85 +17,211 @@ const SET_DESYNC: u32 = 5; const BAD_SURFACE: u32 = 0; +const MAX_SUBSURFACE_DEPTH: u32 = 100; + pub struct WlSubsurface { id: ObjectId, surface: Rc, + pub(super) parent: Rc, +} + +fn update_children_sync(surface: &Rc, sync: bool) -> Result<(), WlSubsurfaceError> { + let children = surface.children.borrow(); + if let Some(children) = &*children { + for child in children.subsurfaces.values() { + let mut data = child.role_data.borrow_mut(); + if let RoleData::Subsurface(data) = &mut *data { + let was_sync = data.sync_ancestor || data.sync_requested; + data.sync_ancestor = sync; + let is_sync = data.sync_ancestor || data.sync_requested; + if was_sync != is_sync { + update_children_sync(child, sync); + } + } + } + } + Ok(()) +} + +fn update_children_attach( + surface: &Rc, + sync: bool, + depth: u32, +) -> Result<(), WlSubsurfaceError> { + let children = surface.children.borrow(); + if let Some(children) = &*children { + for child in children.subsurfaces.values() { + let mut data = child.role_data.borrow_mut(); + if let RoleData::Subsurface(data) = &mut *data { + data.depth = depth + 1; + if data.depth > MAX_SUBSURFACE_DEPTH { + return Err(WlSubsurfaceError::MaxDepthExceeded); + } + data.sync_ancestor = sync; + let sync = data.sync_ancestor || data.sync_requested; + update_children_attach(child, sync, depth + 1); + } + } + } + Ok(()) } impl WlSubsurface { - pub fn new(id: ObjectId, surface: &Rc) -> Self { + pub fn new(id: ObjectId, surface: &Rc, parent: &Rc) -> Self { Self { id, surface: surface.clone(), + parent: parent.clone(), } } - pub fn install(self: &Rc, parent: &Rc) -> Result<(), WlSubsurfaceError> { - let old_ty = self.surface.ty.get(); - if !matches!(old_ty, SurfaceType::None | SurfaceType::Subsurface) { - return Err(WlSubsurfaceError::IncompatibleType(self.surface.id, old_ty)); - } - self.surface.ty.set(SurfaceType::Subsurface); - let mut data = self.surface.subsurface_data.borrow_mut(); - if data.is_some() { - return Err(WlSubsurfaceError::AlreadyAttached(self.surface.id)); - } - if self.surface.id == parent.id { + pub fn install(self: &Rc) -> Result<(), WlSubsurfaceError> { + if self.surface.id == self.parent.id { return Err(WlSubsurfaceError::OwnParent(self.surface.id)); } - if self.surface.id == parent.get_root().id { - return Err(WlSubsurfaceError::Ancestor(self.surface.id, parent.id)); + let old_ty = self.surface.role.get(); + if !matches!(old_ty, SurfaceRole::None | SurfaceRole::Subsurface) { + return Err(WlSubsurfaceError::IncompatibleType(self.surface.id, old_ty)); + } + self.surface.role.set(SurfaceRole::Subsurface); + let mut data = self.surface.role_data.borrow_mut(); + if matches!(*data, RoleData::Subsurface(_)) { + return Err(WlSubsurfaceError::AlreadyAttached(self.surface.id)); + } + if self.surface.id == self.parent.get_root().id { + return Err(WlSubsurfaceError::Ancestor(self.surface.id, self.parent.id)); } let mut sync_ancestor = false; + let mut depth = 1; { - let data = parent.subsurface_data.borrow(); - if let Some(data) = data.as_ref() { + let data = self.parent.role_data.borrow(); + if let RoleData::Subsurface(data) = &*data { sync_ancestor = data.sync_requested || data.sync_ancestor; + depth = data.depth + 1; + if depth >= MAX_SUBSURFACE_DEPTH { + return Err(WlSubsurfaceError::MaxDepthExceeded); + } } } - *data = Some(Box::new(SubsurfaceData { + let node = { + let mut data = self.parent.children.borrow_mut(); + let data = data.get_or_insert_with(|| Default::default()); + data.subsurfaces + .insert(self.surface.id, self.surface.clone()); + data.above.prepend(StackElement { + pending: Cell::new(true), + surface: self.surface.clone(), + }) + }; + *data = RoleData::Subsurface(Box::new(SubsurfaceData { subsurface: self.clone(), - parent: parent.clone(), + x: 0, + y: 0, sync_requested: false, sync_ancestor, - pending: true, + depth, + node, + pending: Default::default(), })); - { - let mut data = parent.children.borrow_mut(); - let data = data.get_or_insert_with(|| Default::default()); - data.pending_subsurfaces - .insert(self.surface.id, self.surface.clone()); - } + update_children_attach(&self.surface, sync_ancestor, depth)?; + Ok(()) } async fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { let _req: Destroy = self.surface.client.parse(self, parser)?; + *self.surface.role_data.borrow_mut() = RoleData::None; + { + let mut children = self.parent.children.borrow_mut(); + if let Some(children) = &mut *children { + children.subsurfaces.remove(&self.surface.id); + } + } + self.surface.client.remove_obj(self).await?; Ok(()) } async fn set_position(&self, parser: MsgParser<'_, '_>) -> Result<(), SetPositionError> { let req: SetPosition = self.surface.client.parse(self, parser)?; + let mut data = self.surface.role_data.borrow_mut(); + if let RoleData::Subsurface(data) = &mut *data { + data.pending.position = Some((req.x, req.y)); + } + Ok(()) + } + + fn place(&self, sibling: ObjectId, above: bool) -> Result<(), PlacementError> { + if sibling == self.surface.id { + return Err(PlacementError::AboveSelf(sibling)); + } + let mut data = self.surface.role_data.borrow_mut(); + let pdata = self.parent.children.borrow(); + if let (RoleData::Subsurface(data), Some(pdata)) = (&mut *data, &*pdata) { + let element = StackElement { + pending: Cell::new(true), + surface: self.surface.clone(), + }; + if sibling == self.parent.id { + let node = match above { + true => pdata.above.prepend(element), + _ => pdata.below.append(element), + }; + data.pending.node = Some(node); + } else { + let sibling = match pdata.subsurfaces.get(&sibling) { + Some(s) => s, + _ => return Err(PlacementError::NotASibling(sibling, self.surface.id)), + }; + let sdata = sibling.role_data.borrow(); + if let RoleData::Subsurface(p) = &*sdata { + let node = match &p.pending.node { + Some(n) => n, + _ => &p.node, + }; + let node = match above { + true => node.append(element), + _ => node.prepend(element), + }; + data.pending.node = Some(node); + } + } + } Ok(()) } async fn place_above(&self, parser: MsgParser<'_, '_>) -> Result<(), PlaceAboveError> { let req: PlaceAbove = self.surface.client.parse(self, parser)?; + self.place(req.sibling, true)?; Ok(()) } async fn place_below(&self, parser: MsgParser<'_, '_>) -> Result<(), PlaceBelowError> { let req: PlaceBelow = self.surface.client.parse(self, parser)?; + self.place(req.sibling, false)?; Ok(()) } + fn update_sync(&self, sync: bool) { + let mut data = self.surface.role_data.borrow_mut(); + if let RoleData::Subsurface(data) = &mut *data { + let was_sync = data.sync_requested || data.sync_ancestor; + data.sync_requested = sync; + let is_sync = data.sync_requested || data.sync_ancestor; + if was_sync != is_sync { + update_children_sync(&self.surface, is_sync); + } + } + } + async fn set_sync(&self, parser: MsgParser<'_, '_>) -> Result<(), SetSyncError> { let _req: SetSync = self.surface.client.parse(self, parser)?; + self.update_sync(true); Ok(()) } async fn set_desync(&self, parser: MsgParser<'_, '_>) -> Result<(), SetDesyncError> { let _req: SetDesync = self.surface.client.parse(self, parser)?; + self.update_sync(false); Ok(()) } diff --git a/src/ifs/wl_surface/wl_subsurface/types.rs b/src/ifs/wl_surface/wl_subsurface/types.rs index dbe376d8..238b2cf7 100644 --- a/src/ifs/wl_surface/wl_subsurface/types.rs +++ b/src/ifs/wl_surface/wl_subsurface/types.rs @@ -1,5 +1,5 @@ -use crate::client::{RequestParser}; -use crate::ifs::wl_surface::SurfaceType; +use crate::client::{ClientError, RequestParser}; +use crate::ifs::wl_surface::SurfaceRole; use crate::object::ObjectId; use crate::utils::buffd::{MsgParser, MsgParserError}; use std::fmt::{Debug, Formatter}; @@ -20,21 +20,26 @@ pub enum WlSubsurfaceError { #[error("Could not process `set_desync` request")] SetDesync(#[from] SetDesyncError), #[error("Surface {0} cannot be assigned the role `Subsurface` because it already has the role `{1:?}`")] - IncompatibleType(ObjectId, SurfaceType), + IncompatibleType(ObjectId, SurfaceRole), #[error("Surface {0} already has an attached `wl_subsurface`")] AlreadyAttached(ObjectId), #[error("Surface {0} cannot be made its own parent")] OwnParent(ObjectId), #[error("Surface {0} cannot be made a subsurface of {1} because it's an ancestor of {1}")] Ancestor(ObjectId, ObjectId), + #[error("Subsurfaces cannot be nested deeper than 100 levels")] + MaxDepthExceeded, } #[derive(Debug, Error)] pub enum DestroyError { #[error("Parsing failed")] ParseFailed(#[source] Box), + #[error(transparent)] + ClientError(Box), } efrom!(DestroyError, ParseFailed, MsgParserError); +efrom!(DestroyError, ClientError, ClientError); #[derive(Debug, Error)] pub enum SetPositionError { @@ -47,13 +52,25 @@ efrom!(SetPositionError, ParseFailed, MsgParserError); pub enum PlaceAboveError { #[error("Parsing failed")] ParseFailed(#[source] Box), + #[error(transparent)] + PlacementError(#[from] PlacementError), } efrom!(PlaceAboveError, ParseFailed, MsgParserError); +#[derive(Debug, Error)] +pub enum PlacementError { + #[error("Cannot place {0} above/below itself")] + AboveSelf(ObjectId), + #[error("{0} is not a sibling of {1}")] + NotASibling(ObjectId, ObjectId), +} + #[derive(Debug, Error)] pub enum PlaceBelowError { #[error("Parsing failed")] ParseFailed(#[source] Box), + #[error(transparent)] + PlacementError(#[from] PlacementError), } efrom!(PlaceBelowError, ParseFailed, MsgParserError); diff --git a/src/ifs/wl_surface/xdg_surface/mod.rs b/src/ifs/wl_surface/xdg_surface/mod.rs new file mode 100644 index 00000000..d547780e --- /dev/null +++ b/src/ifs/wl_surface/xdg_surface/mod.rs @@ -0,0 +1,119 @@ +mod types; +pub mod xdg_popup; +pub mod xdg_toplevel; + +use crate::ifs::wl_surface::{RoleData, SurfaceRole, WlSurface, XdgSurfaceData}; +use crate::object::{Interface, Object, ObjectId}; +use crate::utils::buffd::MsgParser; +use std::rc::Rc; +pub use types::*; +use crate::client::AddObj; +use crate::ifs::xdg_wm_base::XdgWmBaseObj; + +const DESTROY: u32 = 0; +const GET_TOPLEVEL: u32 = 1; +const GET_POPUP: u32 = 2; +const SET_WINDOW_GEOMETRY: u32 = 3; +const ACK_CONFIGURE: u32 = 4; + +const CONFIGURE: u32 = 0; + +const NOT_CONSTRUCTED: u32 = 1; +const ALREADY_CONSTRUCTED: u32 = 2; +const UNCONFIGURED_BUFFER: u32 = 3; + +pub struct XdgSurface { + id: ObjectId, + wm_base: Rc, + surface: Rc, + version: u32, +} + +impl XdgSurface { + pub fn new(wm_base: &Rc, id: ObjectId, surface: &Rc, version: u32) -> Self { + Self { + id, + wm_base: wm_base.clone(), + surface: surface.clone(), + version, + } + } + + pub fn install(self: &Rc) -> Result<(), XdgSurfaceError> { + let old_role = self.surface.role.get(); + if !matches!(old_role, SurfaceRole::None | SurfaceRole::XdgSurface) { + return Err(XdgSurfaceError::IncompatibleRole(self.surface.id, old_role)); + } + let mut data = self.surface.role_data.borrow_mut(); + if data.is_some() { + return Err(XdgSurfaceError::AlreadyAttached(self.surface.id)); + } + *data = RoleData::XdgSurface(Box::new(XdgSurfaceData { + xdg_surface: self.clone(), + })); + Ok(()) + } + + async fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { + let _req: Destroy = self.surface.client.parse(self, parser)?; + *self.surface.role_data.borrow_mut() = RoleData::None; + self.wm_base.surfaces.remove(&self.id); + self.surface.client.remove_obj(self).await?; + Ok(()) + } + + async fn get_toplevel(&self, parser: MsgParser<'_, '_>) -> Result<(), GetToplevelError> { + let _req: GetToplevel = self.surface.client.parse(self, parser)?; + Ok(()) + } + + async fn get_popup(&self, parser: MsgParser<'_, '_>) -> Result<(), GetPopupError> { + let _req: GetPopup = self.surface.client.parse(self, parser)?; + Ok(()) + } + + async fn set_window_geometry( + &self, + parser: MsgParser<'_, '_>, + ) -> Result<(), SetWindowGeometryError> { + let _req: SetWindowGeometry = self.surface.client.parse(self, parser)?; + Ok(()) + } + + async fn ack_configure(&self, parser: MsgParser<'_, '_>) -> Result<(), AckConfigureError> { + let _req: AckConfigure = self.surface.client.parse(self, parser)?; + Ok(()) + } + + async fn handle_request_( + &self, + request: u32, + parser: MsgParser<'_, '_>, + ) -> Result<(), XdgSurfaceError> { + match request { + DESTROY => self.destroy(parser).await?, + GET_TOPLEVEL => self.get_toplevel(parser).await?, + GET_POPUP => self.get_popup(parser).await?, + SET_WINDOW_GEOMETRY => self.set_window_geometry(parser).await?, + ACK_CONFIGURE => self.ack_configure(parser).await?, + _ => unreachable!(), + } + Ok(()) + } +} + +handle_request!(XdgSurface); + +impl Object for XdgSurface { + fn id(&self) -> ObjectId { + self.id + } + + fn interface(&self) -> Interface { + Interface::XdgSurface + } + + fn num_requests(&self) -> u32 { + ACK_CONFIGURE + 1 + } +} diff --git a/src/ifs/wl_surface/xdg_surface/types.rs b/src/ifs/wl_surface/xdg_surface/types.rs new file mode 100644 index 00000000..18103823 --- /dev/null +++ b/src/ifs/wl_surface/xdg_surface/types.rs @@ -0,0 +1,189 @@ +use crate::client::{ClientError, EventFormatter, RequestParser}; +use crate::ifs::wl_surface::xdg_surface::{XdgSurface, CONFIGURE}; +use crate::object::{Object, ObjectId}; +use crate::utils::buffd::{MsgFormatter, MsgParser, MsgParserError}; +use std::fmt::{Debug, Formatter}; +use std::rc::Rc; +use thiserror::Error; +use crate::ifs::wl_surface::SurfaceRole; + +#[derive(Debug, Error)] +pub enum XdgSurfaceError { + #[error("Could not process `destroy` request")] + DestroyError(#[from] DestroyError), + #[error("Could not process `get_toplevel` request")] + GetToplevelError(#[from] GetToplevelError), + #[error("Could not process `get_popup` request")] + GetPopupError(#[from] GetPopupError), + #[error("Could not process `set_window_geometry` request")] + SetWindowGeometryError(#[from] SetWindowGeometryError), + #[error("Could not process `ack_configure` request")] + AckConfigureError(#[from] AckConfigureError), + #[error("Surface {0} cannot be turned into a xdg_surface because it already has the role {}", .1.name())] + IncompatibleRole(ObjectId, SurfaceRole), + #[error("Surface {0} cannot be turned into a xdg_surface because it already has an attached xdg_surface")] + AlreadyAttached(ObjectId), +} + +#[derive(Debug, Error)] +pub enum DestroyError { + #[error("Parsing failed")] + ParseFailed(#[source] Box), + #[error(transparent)] + ClientError(Box), +} +efrom!(DestroyError, ParseFailed, MsgParserError); +efrom!(DestroyError, ClientError, ClientError); + +#[derive(Debug, Error)] +pub enum GetToplevelError { + #[error("Parsing failed")] + ParseFailed(#[source] Box), + #[error(transparent)] + ClientError(Box), +} +efrom!(GetToplevelError, ParseFailed, MsgParserError); +efrom!(GetToplevelError, ClientError, ClientError); + +#[derive(Debug, Error)] +pub enum GetPopupError { + #[error("Parsing failed")] + ParseFailed(#[source] Box), + #[error(transparent)] + ClientError(Box), +} +efrom!(GetPopupError, ParseFailed, MsgParserError); +efrom!(GetPopupError, ClientError, ClientError); + +#[derive(Debug, Error)] +pub enum SetWindowGeometryError { + #[error("Parsing failed")] + ParseFailed(#[source] Box), + #[error(transparent)] + ClientError(Box), +} +efrom!(SetWindowGeometryError, ParseFailed, MsgParserError); +efrom!(SetWindowGeometryError, ClientError, ClientError); + +#[derive(Debug, Error)] +pub enum AckConfigureError { + #[error("Parsing failed")] + ParseFailed(#[source] Box), + #[error(transparent)] + ClientError(Box), +} +efrom!(AckConfigureError, ParseFailed, MsgParserError); +efrom!(AckConfigureError, ClientError, ClientError); + +pub(super) struct Destroy; +impl RequestParser<'_> for Destroy { + fn parse(_parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self) + } +} +impl Debug for Destroy { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "destroy()") + } +} + +pub(super) struct GetToplevel { + pub id: ObjectId, +} +impl RequestParser<'_> for GetToplevel { + fn parse(parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self { + id: parser.object()?, + }) + } +} +impl Debug for GetToplevel { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "get_toplevel(id: {})", self.id) + } +} + +pub(super) struct GetPopup { + pub id: ObjectId, + pub parent: ObjectId, + pub positioner: ObjectId, +} +impl RequestParser<'_> for GetPopup { + fn parse(parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self { + id: parser.object()?, + parent: parser.object()?, + positioner: parser.object()?, + }) + } +} +impl Debug for GetPopup { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "get_popup(id: {}, parent: {}, positioner: {})", + self.id, self.parent, self.positioner + ) + } +} + +pub(super) struct SetWindowGeometry { + pub x: i32, + pub y: i32, + pub width: i32, + pub height: i32, +} +impl RequestParser<'_> for SetWindowGeometry { + fn parse(parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self { + x: parser.int()?, + y: parser.int()?, + width: parser.int()?, + height: parser.int()?, + }) + } +} +impl Debug for SetWindowGeometry { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "set_window_geometry(x: {}, y: {}, width: {}, height: {})", + self.x, self.y, self.width, self.height + ) + } +} + +pub(super) struct AckConfigure { + pub serial: u32, +} +impl RequestParser<'_> for AckConfigure { + fn parse(parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self { + serial: parser.uint()?, + }) + } +} +impl Debug for AckConfigure { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "ack_configure(serial: {})", self.serial) + } +} + +pub(super) struct Configure { + pub obj: Rc, + pub serial: u32, +} +impl EventFormatter for Configure { + fn format(self: Box, fmt: &mut MsgFormatter<'_>) { + fmt.header(self.obj.id, CONFIGURE).uint(self.serial); + } + + fn obj(&self) -> &dyn Object { + &*self.obj + } +} +impl Debug for Configure { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "configure(serial: {})", self.serial) + } +} diff --git a/src/ifs/wl_surface/xdg_surface/xdg_popup/mod.rs b/src/ifs/wl_surface/xdg_surface/xdg_popup/mod.rs new file mode 100644 index 00000000..f1fccc81 --- /dev/null +++ b/src/ifs/wl_surface/xdg_surface/xdg_popup/mod.rs @@ -0,0 +1,78 @@ +mod types; + +use crate::ifs::wl_surface::xdg_surface::XdgSurface; +use crate::object::{Interface, Object, ObjectId}; +use crate::utils::buffd::MsgParser; +use std::rc::Rc; +pub use types::*; + +const DESTROY: u32 = 0; +const GRAB: u32 = 1; +const REPOSITION: u32 = 2; + +const CONFIGURE: u32 = 0; +const POPUP_DONE: u32 = 1; +const REPOSITIONED: u32 = 2; + +const INVALID_GRAB: u32 = 1; + +pub struct XdgPopup { + id: ObjectId, + surface: Rc, + version: u32, +} + +impl XdgPopup { + pub fn new(id: ObjectId, surface: &Rc, version: u32) -> Self { + Self { + id, + surface: surface.clone(), + version, + } + } + + async fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { + let _req: Destroy = self.surface.surface.client.parse(self, parser)?; + Ok(()) + } + + async fn grab(&self, parser: MsgParser<'_, '_>) -> Result<(), GrabError> { + let _req: Grab = self.surface.surface.client.parse(self, parser)?; + Ok(()) + } + + async fn reposition(&self, parser: MsgParser<'_, '_>) -> Result<(), RepositionError> { + let _req: Reposition = self.surface.surface.client.parse(self, parser)?; + Ok(()) + } + + async fn handle_request_( + &self, + request: u32, + parser: MsgParser<'_, '_>, + ) -> Result<(), XdgPopupError> { + match request { + DESTROY => self.destroy(parser).await?, + GRAB => self.grab(parser).await?, + REPOSITION => self.reposition(parser).await?, + _ => unreachable!(), + } + Ok(()) + } +} + +handle_request!(XdgPopup); + +impl Object for XdgPopup { + fn id(&self) -> ObjectId { + self.id + } + + fn interface(&self) -> Interface { + Interface::XdgPopup + } + + fn num_requests(&self) -> u32 { + REPOSITION + 1 + } +} diff --git a/src/ifs/wl_surface/xdg_surface/xdg_popup/types.rs b/src/ifs/wl_surface/xdg_surface/xdg_popup/types.rs new file mode 100644 index 00000000..52fe74fd --- /dev/null +++ b/src/ifs/wl_surface/xdg_surface/xdg_popup/types.rs @@ -0,0 +1,168 @@ +use crate::client::{ClientError, EventFormatter, RequestParser}; +use crate::ifs::wl_surface::xdg_surface::xdg_popup::{ + XdgPopup, CONFIGURE, POPUP_DONE, REPOSITIONED, +}; +use crate::object::{Object, ObjectId}; +use crate::utils::buffd::{MsgFormatter, MsgParser, MsgParserError}; +use std::fmt::{Debug, Formatter}; +use std::rc::Rc; +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum XdgPopupError { + #[error("Could not process `destroy` request")] + DestroyError(#[from] DestroyError), + #[error("Could not process `grab` request")] + GrabError(#[from] GrabError), + #[error("Could not process `reposition` request")] + RepositionError(#[from] RepositionError), +} + +#[derive(Debug, Error)] +pub enum DestroyError { + #[error("Parsing failed")] + ParseFailed(#[source] Box), + #[error(transparent)] + ClientError(Box), +} +efrom!(DestroyError, ParseFailed, MsgParserError); +efrom!(DestroyError, ClientError, ClientError); + +#[derive(Debug, Error)] +pub enum GrabError { + #[error("Parsing failed")] + ParseFailed(#[source] Box), + #[error(transparent)] + ClientError(Box), +} +efrom!(GrabError, ParseFailed, MsgParserError); +efrom!(GrabError, ClientError, ClientError); + +#[derive(Debug, Error)] +pub enum RepositionError { + #[error("Parsing failed")] + ParseFailed(#[source] Box), + #[error(transparent)] + ClientError(Box), +} +efrom!(RepositionError, ParseFailed, MsgParserError); +efrom!(RepositionError, ClientError, ClientError); + +pub(super) struct Destroy; +impl RequestParser<'_> for Destroy { + fn parse(_parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self) + } +} +impl Debug for Destroy { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "destroy()") + } +} + +pub(super) struct Grab { + pub seat: ObjectId, + pub serial: u32, +} +impl RequestParser<'_> for Grab { + fn parse(parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self { + seat: parser.object()?, + serial: parser.uint()?, + }) + } +} +impl Debug for Grab { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "grab(seat: {}, serial: {})", self.seat, self.serial) + } +} + +pub(super) struct Reposition { + pub positioner: ObjectId, + pub token: u32, +} +impl RequestParser<'_> for Reposition { + fn parse(parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self { + positioner: parser.object()?, + token: parser.uint()?, + }) + } +} +impl Debug for Reposition { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "reposition(positioner: {}, token: {})", + self.positioner, self.token, + ) + } +} + +pub(super) struct Configure { + pub obj: Rc, + pub x: i32, + pub y: i32, + pub width: i32, + pub height: i32, +} +impl EventFormatter for Configure { + fn format(self: Box, fmt: &mut MsgFormatter<'_>) { + fmt.header(self.obj.id, CONFIGURE) + .int(self.x) + .int(self.y) + .int(self.width) + .int(self.height); + } + + fn obj(&self) -> &dyn Object { + &*self.obj + } +} +impl Debug for Configure { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "configure(x: {}, y: {}, width: {}, height: {})", + self.x, self.y, self.width, self.height + ) + } +} + +pub(super) struct PopupDone { + pub obj: Rc, +} +impl EventFormatter for PopupDone { + fn format(self: Box, fmt: &mut MsgFormatter<'_>) { + fmt.header(self.obj.id, POPUP_DONE); + } + + fn obj(&self) -> &dyn Object { + &*self.obj + } +} +impl Debug for PopupDone { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "popup_done()") + } +} + +pub(super) struct Repositioned { + pub obj: Rc, + pub token: u32, +} +impl EventFormatter for Repositioned { + fn format(self: Box, fmt: &mut MsgFormatter<'_>) { + fmt.header(self.obj.id, REPOSITIONED).uint(self.token); + } + + fn obj(&self) -> &dyn Object { + &*self.obj + } +} +impl Debug for Repositioned { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "repositioned(token: {})", self.token) + } +} diff --git a/src/ifs/wl_surface/xdg_surface/xdg_toplevel/mod.rs b/src/ifs/wl_surface/xdg_surface/xdg_toplevel/mod.rs new file mode 100644 index 00000000..cf541ff3 --- /dev/null +++ b/src/ifs/wl_surface/xdg_surface/xdg_toplevel/mod.rs @@ -0,0 +1,178 @@ +mod types; + +use crate::ifs::wl_surface::xdg_surface::XdgSurface; +use crate::object::{Interface, Object, ObjectId}; +use crate::utils::buffd::MsgParser; +use num_derive::FromPrimitive; +use std::rc::Rc; +pub use types::*; + +const DESTROY: u32 = 0; +const SET_PARENT: u32 = 1; +const SET_TITLE: u32 = 2; +const SET_APP_ID: u32 = 3; +const SHOW_WINDOW_MENU: u32 = 4; +const MOVE: u32 = 5; +const RESIZE: u32 = 6; +const SET_MAX_SIZE: u32 = 7; +const SET_MIN_SIZE: u32 = 8; +const SET_MAXIMIZED: u32 = 9; +const UNSET_MAXIMIZED: u32 = 10; +const SET_FULLSCREEN: u32 = 11; +const UNSET_FULLSCREEN: u32 = 12; +const SET_MINIMIZED: u32 = 13; + +const CONFIGURE: u32 = 0; +const CLOSE: u32 = 1; + +#[derive(Copy, Clone, Debug, FromPrimitive)] +pub enum ResizeEdge { + None = 0, + Top = 1, + Bottom = 2, + Left = 4, + TopLeft = 5, + BottomLeft = 6, + Right = 8, + TopRight = 9, + BottomRight = 10, +} + +const STATE_MAXIMIZED: u32 = 1; +const STATE_FULLSCREEN: u32 = 2; +const STATE_RESIZING: u32 = 3; +const STATE_ACTIVATED: u32 = 4; +const STATE_TILED_LEFT: u32 = 5; +const STATE_TILED_RIGHT: u32 = 6; +const STATE_TILED_TOP: u32 = 7; +const STATE_TILED_BOTTOM: u32 = 8; + +pub struct XdgToplevel { + id: ObjectId, + surface: Rc, + version: u32, +} + +impl XdgToplevel { + pub fn new(id: ObjectId, surface: &Rc, version: u32) -> Self { + Self { + id, + surface: surface.clone(), + version, + } + } + + async fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { + let _req: Destroy = self.surface.surface.client.parse(self, parser)?; + Ok(()) + } + + async fn set_parent(&self, parser: MsgParser<'_, '_>) -> Result<(), SetParentError> { + let _req: SetParent = self.surface.surface.client.parse(self, parser)?; + Ok(()) + } + + async fn set_title(&self, parser: MsgParser<'_, '_>) -> Result<(), SetTitleError> { + let _req: SetTitle = self.surface.surface.client.parse(self, parser)?; + Ok(()) + } + + async fn set_app_id(&self, parser: MsgParser<'_, '_>) -> Result<(), SetAppIdError> { + let _req: SetAppId = self.surface.surface.client.parse(self, parser)?; + Ok(()) + } + + async fn show_window_menu(&self, parser: MsgParser<'_, '_>) -> Result<(), ShowWindowMenuError> { + let _req: ShowWindowMenu = self.surface.surface.client.parse(self, parser)?; + Ok(()) + } + + async fn move_(&self, parser: MsgParser<'_, '_>) -> Result<(), MoveError> { + let _req: Move = self.surface.surface.client.parse(self, parser)?; + Ok(()) + } + + async fn resize(&self, parser: MsgParser<'_, '_>) -> Result<(), ResizeError> { + let _req: Resize = self.surface.surface.client.parse(self, parser)?; + Ok(()) + } + + async fn set_max_size(&self, parser: MsgParser<'_, '_>) -> Result<(), SetMaxSizeError> { + let _req: SetMaxSize = self.surface.surface.client.parse(self, parser)?; + Ok(()) + } + + async fn set_min_size(&self, parser: MsgParser<'_, '_>) -> Result<(), SetMinSizeError> { + let _req: SetMinSize = self.surface.surface.client.parse(self, parser)?; + Ok(()) + } + + async fn set_maximized(&self, parser: MsgParser<'_, '_>) -> Result<(), SetMaximizedError> { + let _req: SetMaximized = self.surface.surface.client.parse(self, parser)?; + Ok(()) + } + + async fn unset_maximized(&self, parser: MsgParser<'_, '_>) -> Result<(), UnsetMaximizedError> { + let _req: UnsetMaximized = self.surface.surface.client.parse(self, parser)?; + Ok(()) + } + + async fn set_fullscreen(&self, parser: MsgParser<'_, '_>) -> Result<(), SetFullscreenError> { + let _req: SetFullscreen = self.surface.surface.client.parse(self, parser)?; + Ok(()) + } + + async fn unset_fullscreen( + &self, + parser: MsgParser<'_, '_>, + ) -> Result<(), UnsetFullscreenError> { + let _req: UnsetFullscreen = self.surface.surface.client.parse(self, parser)?; + Ok(()) + } + + async fn set_minimized(&self, parser: MsgParser<'_, '_>) -> Result<(), SetMinimizedError> { + let _req: SetMinimized = self.surface.surface.client.parse(self, parser)?; + Ok(()) + } + + async fn handle_request_( + &self, + request: u32, + parser: MsgParser<'_, '_>, + ) -> Result<(), XdgToplevelError> { + match request { + DESTROY => self.destroy(parser).await?, + SET_PARENT => self.set_parent(parser).await?, + SET_TITLE => self.set_title(parser).await?, + SET_APP_ID => self.set_app_id(parser).await?, + SHOW_WINDOW_MENU => self.show_window_menu(parser).await?, + MOVE => self.move_(parser).await?, + RESIZE => self.resize(parser).await?, + SET_MAX_SIZE => self.set_max_size(parser).await?, + SET_MIN_SIZE => self.set_min_size(parser).await?, + SET_MAXIMIZED => self.set_maximized(parser).await?, + UNSET_MAXIMIZED => self.unset_maximized(parser).await?, + SET_FULLSCREEN => self.set_fullscreen(parser).await?, + UNSET_FULLSCREEN => self.unset_fullscreen(parser).await?, + SET_MINIMIZED => self.set_minimized(parser).await?, + _ => unreachable!(), + } + Ok(()) + } +} + +handle_request!(XdgToplevel); + +impl Object for XdgToplevel { + fn id(&self) -> ObjectId { + self.id + } + + fn interface(&self) -> Interface { + Interface::XdgToplevel + } + + fn num_requests(&self) -> u32 { + SET_MINIMIZED + 1 + } +} diff --git a/src/ifs/wl_surface/xdg_surface/xdg_toplevel/types.rs b/src/ifs/wl_surface/xdg_surface/xdg_toplevel/types.rs new file mode 100644 index 00000000..c7698994 --- /dev/null +++ b/src/ifs/wl_surface/xdg_surface/xdg_toplevel/types.rs @@ -0,0 +1,433 @@ +use super::CONFIGURE; +use crate::client::{ClientError, EventFormatter, RequestParser}; +use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::{XdgToplevel, CLOSE}; +use crate::object::{Object, ObjectId}; +use crate::utils::buffd::{MsgFormatter, MsgParser, MsgParserError}; +use std::fmt::{Debug, Formatter}; +use std::rc::Rc; +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum XdgToplevelError { + #[error("Could not process `destroy` request")] + DestroyError(#[from] DestroyError), + #[error("Could not process `set_parent` request")] + SetParentError(#[from] SetParentError), + #[error("Could not process `set_title` request")] + SetTitleError(#[from] SetTitleError), + #[error("Could not process `set_app_id` request")] + SetAppIdError(#[from] SetAppIdError), + #[error("Could not process `show_window_menu` request")] + ShowWindowMenuError(#[from] ShowWindowMenuError), + #[error("Could not process `move` request")] + MoveError(#[from] MoveError), + #[error("Could not process `resize` request")] + ResizeError(#[from] ResizeError), + #[error("Could not process `set_max_size` request")] + SetMaxSizeError(#[from] SetMaxSizeError), + #[error("Could not process `set_min_size` request")] + SetMinSizeError(#[from] SetMinSizeError), + #[error("Could not process `set_maximized` request")] + SetMaximizedError(#[from] SetMaximizedError), + #[error("Could not process `unset_maximized` request")] + UnsetMaximizedError(#[from] UnsetMaximizedError), + #[error("Could not process `set_fullscreen` request")] + SetFullscreenError(#[from] SetFullscreenError), + #[error("Could not process `unset_fullscreen` request")] + UnsetFullscreenError(#[from] UnsetFullscreenError), + #[error("Could not process `set_minimized` request")] + SetMinimizedError(#[from] SetMinimizedError), +} + +#[derive(Debug, Error)] +pub enum DestroyError { + #[error("Parsing failed")] + ParseFailed(#[source] Box), + #[error(transparent)] + ClientError(Box), +} +efrom!(DestroyError, ParseFailed, MsgParserError); +efrom!(DestroyError, ClientError, ClientError); + +#[derive(Debug, Error)] +pub enum SetParentError { + #[error("Parsing failed")] + ParseFailed(#[source] Box), + #[error(transparent)] + ClientError(Box), +} +efrom!(SetParentError, ParseFailed, MsgParserError); +efrom!(SetParentError, ClientError, ClientError); + +#[derive(Debug, Error)] +pub enum SetTitleError { + #[error("Parsing failed")] + ParseFailed(#[source] Box), + #[error(transparent)] + ClientError(Box), +} +efrom!(SetTitleError, ParseFailed, MsgParserError); +efrom!(SetTitleError, ClientError, ClientError); + +#[derive(Debug, Error)] +pub enum SetAppIdError { + #[error("Parsing failed")] + ParseFailed(#[source] Box), + #[error(transparent)] + ClientError(Box), +} +efrom!(SetAppIdError, ParseFailed, MsgParserError); +efrom!(SetAppIdError, ClientError, ClientError); + +#[derive(Debug, Error)] +pub enum ShowWindowMenuError { + #[error("Parsing failed")] + ParseFailed(#[source] Box), + #[error(transparent)] + ClientError(Box), +} +efrom!(ShowWindowMenuError, ParseFailed, MsgParserError); +efrom!(ShowWindowMenuError, ClientError, ClientError); + +#[derive(Debug, Error)] +pub enum MoveError { + #[error("Parsing failed")] + ParseFailed(#[source] Box), + #[error(transparent)] + ClientError(Box), +} +efrom!(MoveError, ParseFailed, MsgParserError); +efrom!(MoveError, ClientError, ClientError); + +#[derive(Debug, Error)] +pub enum ResizeError { + #[error("Parsing failed")] + ParseFailed(#[source] Box), + #[error(transparent)] + ClientError(Box), +} +efrom!(ResizeError, ParseFailed, MsgParserError); +efrom!(ResizeError, ClientError, ClientError); + +#[derive(Debug, Error)] +pub enum SetMaxSizeError { + #[error("Parsing failed")] + ParseFailed(#[source] Box), + #[error(transparent)] + ClientError(Box), +} +efrom!(SetMaxSizeError, ParseFailed, MsgParserError); +efrom!(SetMaxSizeError, ClientError, ClientError); + +#[derive(Debug, Error)] +pub enum SetMinSizeError { + #[error("Parsing failed")] + ParseFailed(#[source] Box), + #[error(transparent)] + ClientError(Box), +} +efrom!(SetMinSizeError, ParseFailed, MsgParserError); +efrom!(SetMinSizeError, ClientError, ClientError); + +#[derive(Debug, Error)] +pub enum SetMaximizedError { + #[error("Parsing failed")] + ParseFailed(#[source] Box), + #[error(transparent)] + ClientError(Box), +} +efrom!(SetMaximizedError, ParseFailed, MsgParserError); +efrom!(SetMaximizedError, ClientError, ClientError); + +#[derive(Debug, Error)] +pub enum UnsetMaximizedError { + #[error("Parsing failed")] + ParseFailed(#[source] Box), + #[error(transparent)] + ClientError(Box), +} +efrom!(UnsetMaximizedError, ParseFailed, MsgParserError); +efrom!(UnsetMaximizedError, ClientError, ClientError); + +#[derive(Debug, Error)] +pub enum SetFullscreenError { + #[error("Parsing failed")] + ParseFailed(#[source] Box), + #[error(transparent)] + ClientError(Box), +} +efrom!(SetFullscreenError, ParseFailed, MsgParserError); +efrom!(SetFullscreenError, ClientError, ClientError); + +#[derive(Debug, Error)] +pub enum UnsetFullscreenError { + #[error("Parsing failed")] + ParseFailed(#[source] Box), + #[error(transparent)] + ClientError(Box), +} +efrom!(UnsetFullscreenError, ParseFailed, MsgParserError); +efrom!(UnsetFullscreenError, ClientError, ClientError); + +#[derive(Debug, Error)] +pub enum SetMinimizedError { + #[error("Parsing failed")] + ParseFailed(#[source] Box), + #[error(transparent)] + ClientError(Box), +} +efrom!(SetMinimizedError, ParseFailed, MsgParserError); +efrom!(SetMinimizedError, ClientError, ClientError); + +pub(super) struct Destroy; +impl RequestParser<'_> for Destroy { + fn parse(_parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self) + } +} +impl Debug for Destroy { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "destroy()") + } +} + +pub(super) struct SetParent { + pub parent: ObjectId, +} +impl RequestParser<'_> for SetParent { + fn parse(parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self { parent: parser.object()? }) + } +} +impl Debug for SetParent { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "set_parent(parent: {})", self.parent) + } +} + +pub(super) struct SetTitle<'a> { + pub title: &'a str, +} +impl<'a> RequestParser<'a> for SetTitle<'a> { + fn parse(parser: &mut MsgParser<'_, 'a>) -> Result { + Ok(Self { title: parser.string()? }) + } +} +impl<'a> Debug for SetTitle<'a> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "set_title(title: {:?})", self.title) + } +} + +pub(super) struct SetAppId<'a> { + pub app_id: &'a str, +} +impl<'a> RequestParser<'a> for SetAppId<'a> { + fn parse(parser: &mut MsgParser<'_, 'a>) -> Result { + Ok(Self { app_id: parser.string()? }) + } +} +impl<'a> Debug for SetAppId<'a> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "set_app_id(app_id: {:?})", self.app_id) + } +} + +pub(super) struct ShowWindowMenu { + pub seat: ObjectId, + pub serial: u32, + pub x: i32, + pub y: i32, +} +impl RequestParser<'_> for ShowWindowMenu { + fn parse(parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self { + seat: parser.object()?, + serial: parser.uint()?, + x: parser.int()?, + y: parser.int()?, + }) + } +} +impl Debug for ShowWindowMenu { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "show_window_menu(seat: {}, serial: {}, x: {}, y: {})", self.seat, self.serial, self.x, self.y) + } +} + +pub(super) struct Move { + pub seat: ObjectId, + pub serial: u32, +} +impl RequestParser<'_> for Move { + fn parse(parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self { seat: parser.object()?, serial: parser.uint()? }) + } +} +impl Debug for Move { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "move(seat: {}, serial: {})", self.seat, self.serial) + } +} + +pub(super) struct Resize { + pub seat: ObjectId, + pub serial: u32, + pub edges: u32, +} +impl RequestParser<'_> for Resize { + fn parse(parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self { + seat: parser.object()?, + serial: parser.uint()?, + edges: parser.uint()?, + }) + } +} +impl Debug for Resize { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "resize(seat: {}, serial: {}, edges: {})", self.seat, self.serial, self.edges) + } +} + +pub(super) struct SetMaxSize { + pub width: i32, + pub height: i32, +} +impl RequestParser<'_> for SetMaxSize { + fn parse(parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self { width: parser.int()?, height: parser.int()? }) + } +} +impl Debug for SetMaxSize { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "set_max_size(width: {}, height: {})", self.width, self.height) + } +} + +pub(super) struct SetMinSize { + pub width: i32, + pub height: i32, +} +impl RequestParser<'_> for SetMinSize { + fn parse(parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self { width: parser.int()?, height: parser.int()? }) + } +} +impl Debug for SetMinSize { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "set_min_size(width: {}, height: {})", self.width, self.height) + } +} + +pub(super) struct SetMaximized; +impl RequestParser<'_> for SetMaximized { + fn parse(_parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self) + } +} +impl Debug for SetMaximized { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "set_maximized()") + } +} + +pub(super) struct UnsetMaximized; +impl RequestParser<'_> for UnsetMaximized { + fn parse(_parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self) + } +} +impl Debug for UnsetMaximized { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "unset_maximized()") + } +} + +pub(super) struct SetFullscreen { + pub output: ObjectId, +} +impl RequestParser<'_> for SetFullscreen { + fn parse(parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self { output: parser.object()? }) + } +} +impl Debug for SetFullscreen { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "set_fullscreen(output: {})", self.output) + } +} + +pub(super) struct UnsetFullscreen; +impl RequestParser<'_> for UnsetFullscreen { + fn parse(_parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self) + } +} +impl Debug for UnsetFullscreen { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "unset_fullscreen()") + } +} + +pub(super) struct SetMinimized; +impl RequestParser<'_> for SetMinimized { + fn parse(_parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self) + } +} +impl Debug for SetMinimized { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "set_minimized()") + } +} + +pub(super) struct Configure { + pub obj: Rc, + pub width: i32, + pub height: i32, + pub states: Vec, +} +impl EventFormatter for Configure { + fn format(self: Box, fmt: &mut MsgFormatter<'_>) { + fmt.header(self.obj.id, CONFIGURE) + .int(self.width) + .int(self.height) + .array(|fmt| { + for &state in &self.states { + fmt.uint(state); + } + }); + } + + fn obj(&self) -> &dyn Object { + &*self.obj + } +} +impl Debug for Configure { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "configure(width: {}, height: {}, states: {:?})", + self.width, self.height, self.states + ) + } +} + +pub(super) struct Close { + pub obj: Rc, +} +impl EventFormatter for Close { + fn format(self: Box, fmt: &mut MsgFormatter<'_>) { + fmt.header(self.obj.id, CLOSE); + } + + fn obj(&self) -> &dyn Object { + &*self.obj + } +} +impl Debug for Close { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "close()") + } +} diff --git a/src/ifs/xdg_positioner/mod.rs b/src/ifs/xdg_positioner/mod.rs new file mode 100644 index 00000000..4e24033f --- /dev/null +++ b/src/ifs/xdg_positioner/mod.rs @@ -0,0 +1,269 @@ +mod types; + +use crate::client::{AddObj, Client}; +use crate::object::{Interface, Object, ObjectId}; +use crate::utils::buffd::MsgParser; +use bitflags::bitflags; +use num_derive::FromPrimitive; +use num_traits::FromPrimitive; +use std::cell::RefCell; +use std::rc::Rc; +pub use types::*; + +const DESTROY: u32 = 0; +const SET_SIZE: u32 = 1; +const SET_ANCHOR_RECT: u32 = 2; +const SET_ANCHOR: u32 = 3; +const SET_GRAVITY: u32 = 4; +const SET_CONSTRAINT_ADJUSTMENT: u32 = 5; +const SET_OFFSET: u32 = 6; +const SET_REACTIVE: u32 = 7; +const SET_PARENT_SIZE: u32 = 8; +const SET_PARENT_CONFIGURE: u32 = 9; + +const INVALID_INPUT: u32 = 0; + +#[derive(Debug, Eq, PartialEq, Copy, Clone, FromPrimitive)] +pub enum Anchor { + None = 0, + Top = 1, + Bottom = 2, + Left = 3, + Right = 4, + TopLeft = 5, + BottomLeft = 6, + TopRight = 7, + BottomRight = 8, +} + +impl Default for Anchor { + fn default() -> Self { + Self::None + } +} + +#[derive(Debug, Eq, PartialEq, Copy, Clone, FromPrimitive)] +pub enum Gravity { + None = 0, + Top = 1, + Bottom = 2, + Left = 3, + Right = 4, + TopLeft = 5, + BottomLeft = 6, + TopRight = 7, + BottomRight = 8, +} + +impl Default for Gravity { + fn default() -> Self { + Self::None + } +} + +bitflags! { + #[derive(Default)] + pub struct CA: u32 { + const NONE = 0; + const SLIDE_X = 1; + const SLIDE_Y = 2; + const FLIP_X = 4; + const FLIP_Y = 8; + const RESIZE_X = 16; + const RESIZE_Y = 32; + } +} + +pub struct XdgPositioner { + id: ObjectId, + client: Rc, + version: u32, + position: RefCell, +} + +#[derive(Copy, Clone, Debug, Default)] +pub struct XdgPositioned { + pub size_width: u32, + pub size_height: u32, + pub ar_x: i32, + pub ar_y: i32, + pub ar_width: u32, + pub ar_height: u32, + pub anchor: Anchor, + pub gravity: Gravity, + pub ca: CA, + pub off_x: i32, + pub off_y: i32, + pub reactive: bool, + pub parent_width: u32, + pub parent_height: u32, + pub parent_serial: u32, +} + +impl XdgPositioner { + pub fn new(id: ObjectId, client: &Rc, version: u32) -> Self { + Self { + id, + client: client.clone(), + version, + position: RefCell::new(Default::default()), + } + } + + pub fn clone(&self) -> Box { + Box::new(*self.position.borrow()) + } + + async fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { + let _req: Destroy = self.client.parse(self, parser)?; + self.client.remove_obj(self).await?; + Ok(()) + } + + async fn set_size(&self, parser: MsgParser<'_, '_>) -> Result<(), SetSizeError> { + let req: SetSize = self.client.parse(self, parser)?; + if req.width <= 0 || req.height <= 0 { + self.client.protocol_error( + self, + INVALID_INPUT, + format!("Cannot set a non-positive size"), + ); + return Err(SetSizeError::NonPositiveSize); + } + let mut position = self.position.borrow_mut(); + position.size_width = req.width as u32; + position.size_height = req.height as u32; + Ok(()) + } + + async fn set_anchor_rect(&self, parser: MsgParser<'_, '_>) -> Result<(), SetAnchorRectError> { + let req: SetAnchorRect = self.client.parse(self, parser)?; + if req.width < 0 || req.height < 0 { + self.client.protocol_error( + self, + INVALID_INPUT, + format!("Cannot set an anchor rect with negative size"), + ); + return Err(SetAnchorRectError::NegativeAnchorRect); + } + let mut position = self.position.borrow_mut(); + position.ar_x = req.x; + position.ar_y = req.y; + position.ar_width = req.width as u32; + position.ar_height = req.height as u32; + Ok(()) + } + + async fn set_anchor(&self, parser: MsgParser<'_, '_>) -> Result<(), SetAnchorError> { + let req: SetAnchor = self.client.parse(self, parser)?; + let anchor = match Anchor::from_u32(req.anchor) { + Some(a) => a, + _ => return Err(SetAnchorError::UnknownAnchor(req.anchor)), + }; + self.position.borrow_mut().anchor = anchor; + Ok(()) + } + + async fn set_gravity(&self, parser: MsgParser<'_, '_>) -> Result<(), SetGravityError> { + let req: SetGravity = self.client.parse(self, parser)?; + let gravity = match Gravity::from_u32(req.gravity) { + Some(a) => a, + _ => return Err(SetGravityError::UnknownGravity(req.gravity)), + }; + self.position.borrow_mut().gravity = gravity; + Ok(()) + } + + async fn set_constraint_adjustment( + &self, + parser: MsgParser<'_, '_>, + ) -> Result<(), SetConstraintAdjustmentError> { + let req: SetConstraintAdjustment = self.client.parse(self, parser)?; + let ca = match CA::from_bits(req.constraint_adjustment) { + Some(c) => c, + _ => { + return Err(SetConstraintAdjustmentError::UnknownCa( + req.constraint_adjustment, + )) + } + }; + self.position.borrow_mut().ca = ca; + Ok(()) + } + + async fn set_offset(&self, parser: MsgParser<'_, '_>) -> Result<(), SetOffsetError> { + let req: SetOffset = self.client.parse(self, parser)?; + let mut position = self.position.borrow_mut(); + position.off_x = req.x; + position.off_y = req.y; + Ok(()) + } + + async fn set_reactive(&self, parser: MsgParser<'_, '_>) -> Result<(), SetReactiveError> { + let _req: SetReactive = self.client.parse(self, parser)?; + self.position.borrow_mut().reactive = true; + Ok(()) + } + + async fn set_parent_size(&self, parser: MsgParser<'_, '_>) -> Result<(), SetParentSizeError> { + let req: SetParentSize = self.client.parse(self, parser)?; + if req.parent_width < 0 || req.parent_height < 0 { + self.client.protocol_error( + self, + INVALID_INPUT, + format!("Cannot set a negative parent size"), + ); + return Err(SetParentSizeError::NegativeParentSize); + } + let mut position = self.position.borrow_mut(); + position.parent_width = req.parent_width as u32; + position.parent_height = req.parent_height as u32; + Ok(()) + } + + async fn set_parent_configure( + &self, + parser: MsgParser<'_, '_>, + ) -> Result<(), SetParentConfigureError> { + let req: SetParentConfigure = self.client.parse(self, parser)?; + self.position.borrow_mut().parent_serial = req.serial; + Ok(()) + } + + async fn handle_request_( + &self, + request: u32, + parser: MsgParser<'_, '_>, + ) -> Result<(), XdgPositionerError> { + match request { + DESTROY => self.destroy(parser).await?, + SET_SIZE => self.set_size(parser).await?, + SET_ANCHOR_RECT => self.set_anchor_rect(parser).await?, + SET_ANCHOR => self.set_anchor(parser).await?, + SET_GRAVITY => self.set_gravity(parser).await?, + SET_CONSTRAINT_ADJUSTMENT => self.set_constraint_adjustment(parser).await?, + SET_OFFSET => self.set_offset(parser).await?, + SET_REACTIVE => self.set_reactive(parser).await?, + SET_PARENT_SIZE => self.set_parent_size(parser).await?, + SET_PARENT_CONFIGURE => self.set_parent_configure(parser).await?, + _ => unreachable!(), + } + Ok(()) + } +} + +handle_request!(XdgPositioner); + +impl Object for XdgPositioner { + fn id(&self) -> ObjectId { + self.id + } + + fn interface(&self) -> Interface { + Interface::XdgPositioner + } + + fn num_requests(&self) -> u32 { + SET_PARENT_CONFIGURE + 1 + } +} diff --git a/src/ifs/xdg_positioner/types.rs b/src/ifs/xdg_positioner/types.rs new file mode 100644 index 00000000..83ab6569 --- /dev/null +++ b/src/ifs/xdg_positioner/types.rs @@ -0,0 +1,293 @@ +use crate::client::{ClientError, RequestParser}; +use crate::utils::buffd::{MsgParser, MsgParserError}; +use std::fmt::{Debug, Formatter}; +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum XdgPositionerError { + #[error("Could not process a `destroy` request")] + DestroyError(#[from] DestroyError), + #[error("Could not process a `set_size` request")] + SetSizeError(#[from] SetSizeError), + #[error("Could not process a `set_anchor_rect` request")] + SetAnchorRectError(#[from] SetAnchorRectError), + #[error("Could not process a `set_anchor` request")] + SetAnchorError(#[from] SetAnchorError), + #[error("Could not process a `set_gravity` request")] + SetGravityError(#[from] SetGravityError), + #[error("Could not process a `set_constraint_adjustment` request")] + SetConstraintAdjustmentError(#[from] SetConstraintAdjustmentError), + #[error("Could not process a `set_offset` request")] + SetOffsetError(#[from] SetOffsetError), + #[error("Could not process a `set_reactive` request")] + SetReactiveError(#[from] SetReactiveError), + #[error("Could not process a `set_parent_size` request")] + SetParentSizeError(#[from] SetParentSizeError), + #[error("Could not process a `set_parent_configure` request")] + SetParentConfigureError(#[from] SetParentConfigureError), +} + +#[derive(Debug, Error)] +pub enum DestroyError { + #[error("Parsing failed")] + ParseError(#[source] Box), + #[error(transparent)] + ClientError(Box), +} +efrom!(DestroyError, ParseError, MsgParserError); +efrom!(DestroyError, ClientError, ClientError); + +#[derive(Debug, Error)] +pub enum SetSizeError { + #[error("Parsing failed")] + ParseError(#[source] Box), + #[error("Cannot set a non-positive size")] + NonPositiveSize, +} +efrom!(SetSizeError, ParseError, MsgParserError); + +#[derive(Debug, Error)] +pub enum SetAnchorRectError { + #[error("Parsing failed")] + ParseError(#[source] Box), + #[error("Cannot set an anchor rect with a negative size")] + NegativeAnchorRect, +} +efrom!(SetAnchorRectError, ParseError, MsgParserError); + +#[derive(Debug, Error)] +pub enum SetAnchorError { + #[error("Parsing failed")] + ParseError(#[source] Box), + #[error("Unknown anchor {0}")] + UnknownAnchor(u32), +} +efrom!(SetAnchorError, ParseError, MsgParserError); + +#[derive(Debug, Error)] +pub enum SetGravityError { + #[error("Parsing failed")] + ParseError(#[source] Box), + #[error("Unknown gravity {0}")] + UnknownGravity(u32), +} +efrom!(SetGravityError, ParseError, MsgParserError); + +#[derive(Debug, Error)] +pub enum SetConstraintAdjustmentError { + #[error("Parsing failed")] + ParseError(#[source] Box), + #[error("Unknown constraint adjustment {0}")] + UnknownCa(u32), +} +efrom!(SetConstraintAdjustmentError, ParseError, MsgParserError); + +#[derive(Debug, Error)] +pub enum SetOffsetError { + #[error("Parsing failed")] + ParseError(#[source] Box), +} +efrom!(SetOffsetError, ParseError, MsgParserError); + +#[derive(Debug, Error)] +pub enum SetReactiveError { + #[error("Parsing failed")] + ParseError(#[source] Box), +} +efrom!(SetReactiveError, ParseError, MsgParserError); + +#[derive(Debug, Error)] +pub enum SetParentSizeError { + #[error("Parsing failed")] + ParseError(#[source] Box), + #[error("Cannot set a negative parent size")] + NegativeParentSize, +} +efrom!(SetParentSizeError, ParseError, MsgParserError); + +#[derive(Debug, Error)] +pub enum SetParentConfigureError { + #[error("Parsing failed")] + ParseError(#[source] Box), +} +efrom!(SetParentConfigureError, ParseError, MsgParserError); + +pub(super) struct Destroy; +impl RequestParser<'_> for Destroy { + fn parse(_parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self) + } +} +impl Debug for Destroy { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "destroy()") + } +} + +pub(super) struct SetSize { + pub width: i32, + pub height: i32, +} +impl RequestParser<'_> for SetSize { + fn parse(parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self { + width: parser.int()?, + height: parser.int()?, + }) + } +} +impl Debug for SetSize { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "set_size(width: {}, height: {})", + self.width, self.height + ) + } +} + +pub(super) struct SetAnchorRect { + pub x: i32, + pub y: i32, + pub width: i32, + pub height: i32, +} +impl RequestParser<'_> for SetAnchorRect { + fn parse(parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self { + x: parser.int()?, + y: parser.int()?, + width: parser.int()?, + height: parser.int()?, + }) + } +} +impl Debug for SetAnchorRect { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "set_anchor_rect(x: {}, y: {}, width: {}, height: {})", + self.x, self.y, self.width, self.height + ) + } +} + +pub(super) struct SetAnchor { + pub anchor: u32, +} +impl RequestParser<'_> for SetAnchor { + fn parse(parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self { + anchor: parser.uint()?, + }) + } +} +impl Debug for SetAnchor { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "set_anchor(anchor: {})", self.anchor) + } +} + +pub(super) struct SetGravity { + pub gravity: u32, +} +impl RequestParser<'_> for SetGravity { + fn parse(parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self { + gravity: parser.uint()?, + }) + } +} +impl Debug for SetGravity { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "set_gravity(gravity: {})", self.gravity) + } +} + +pub(super) struct SetConstraintAdjustment { + pub constraint_adjustment: u32, +} +impl RequestParser<'_> for SetConstraintAdjustment { + fn parse(parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self { + constraint_adjustment: parser.uint()?, + }) + } +} +impl Debug for SetConstraintAdjustment { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "set_constraint_adjustment(constraint_adjustment: {})", + self.constraint_adjustment + ) + } +} + +pub(super) struct SetOffset { + pub x: i32, + pub y: i32, +} +impl RequestParser<'_> for SetOffset { + fn parse(parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self { + x: parser.int()?, + y: parser.int()?, + }) + } +} +impl Debug for SetOffset { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "set_offset(x: {}, y: {})", self.x, self.y) + } +} + +pub(super) struct SetReactive; +impl RequestParser<'_> for SetReactive { + fn parse(_parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self) + } +} +impl Debug for SetReactive { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "set_reactive()") + } +} + +pub(super) struct SetParentSize { + pub parent_width: i32, + pub parent_height: i32, +} +impl RequestParser<'_> for SetParentSize { + fn parse(parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self { + parent_width: parser.int()?, + parent_height: parser.int()?, + }) + } +} +impl Debug for SetParentSize { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "set_parent_size(parent_width: {}, parent_height: {})", + self.parent_width, self.parent_height + ) + } +} + +pub(super) struct SetParentConfigure { + pub serial: u32, +} +impl RequestParser<'_> for SetParentConfigure { + fn parse(parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self { + serial: parser.uint()?, + }) + } +} +impl Debug for SetParentConfigure { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "set_parent_configure(serial: {})", self.serial) + } +} diff --git a/src/ifs/xdg_wm_base/mod.rs b/src/ifs/xdg_wm_base/mod.rs index 0ec4d2d5..29d33390 100644 --- a/src/ifs/xdg_wm_base/mod.rs +++ b/src/ifs/xdg_wm_base/mod.rs @@ -1,12 +1,29 @@ mod types; -use crate::client::{AddObj, Client, ClientError}; +use crate::client::{AddObj, Client}; use crate::globals::{Global, GlobalName}; +use crate::ifs::wl_surface::xdg_surface::XdgSurface; +use crate::ifs::xdg_positioner::XdgPositioner; use crate::object::{Interface, Object, ObjectId}; use crate::utils::buffd::MsgParser; +use crate::utils::copyhashmap::CopyHashMap; use std::rc::Rc; pub use types::*; +const DESTROY: u32 = 0; +const CREATE_POSITIONER: u32 = 1; +const GET_XDG_SURFACE: u32 = 2; +const PONG: u32 = 3; + +const PING: u32 = 0; + +const ROLE: u32 = 0; +const DEFUNCT_SURFACES: u32 = 1; +const NOT_THE_TOPMOST_POPUP: u32 = 2; +const INVALID_POPUP_PARENT: u32 = 3; +const INVALID_SURFACE_STATE: u32 = 4; +const INVALID_POSITIONER: u32 = 5; + pub struct XdgWmBaseGlobal { name: GlobalName, } @@ -14,7 +31,9 @@ pub struct XdgWmBaseGlobal { pub struct XdgWmBaseObj { global: Rc, id: ObjectId, + client: Rc, version: u32, + pub(super) surfaces: CopyHashMap>, } impl XdgWmBaseGlobal { @@ -25,13 +44,15 @@ impl XdgWmBaseGlobal { async fn bind_( self: Rc, id: ObjectId, - client: &Client, + client: &Rc, version: u32, ) -> Result<(), XdgWmBaseError> { let obj = Rc::new(XdgWmBaseObj { global: self, id, + client: client.clone(), version, + surfaces: Default::default(), }); client.add_client_obj(&obj)?; Ok(()) @@ -39,12 +60,65 @@ impl XdgWmBaseGlobal { } impl XdgWmBaseObj { - async fn handle_request_( + pub fn break_loops(&self) { + self.surfaces.clear(); + } + + async fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { + let _req: Destroy = self.client.parse(self, parser)?; + if !self.surfaces.is_empty() { + self.client.protocol_error( + self, + DEFUNCT_SURFACES, + format!( + "Cannot destroy xdg_wm_base object {} before destroying its surfaces", + self.id + ), + ); + return Err(DestroyError::DefunctSurfaces); + } + self.client.remove_obj(self).await?; + Ok(()) + } + + async fn create_positioner( &self, + parser: MsgParser<'_, '_>, + ) -> Result<(), CreatePositionerError> { + let req: CreatePositioner = self.client.parse(self, parser)?; + let pos = Rc::new(XdgPositioner::new(req.id, &self.client, 3)); + self.client.add_client_obj(&pos)?; + Ok(()) + } + + async fn get_xdg_surface(self: &Rc, parser: MsgParser<'_, '_>) -> Result<(), GetXdgSurfaceError> { + let req: GetXdgSurface = self.client.parse(&**self, parser)?; + let surface = self.client.get_surface(req.surface)?; + let xdg_surface = Rc::new(XdgSurface::new(self, req.id, &surface, 3)); + self.client.add_client_obj(&xdg_surface)?; + xdg_surface.install()?; + self.surfaces.set(req.id, xdg_surface); + Ok(()) + } + + async fn pong(&self, parser: MsgParser<'_, '_>) -> Result<(), PongError> { + let _req: Pong = self.client.parse(self, parser)?; + Ok(()) + } + + async fn handle_request_( + self: &Rc, request: u32, parser: MsgParser<'_, '_>, - ) -> Result<(), ClientError> { - unreachable!(); + ) -> Result<(), XdgWmBaseError> { + match request { + DESTROY => self.destroy(parser).await?, + CREATE_POSITIONER => self.create_positioner(parser).await?, + GET_XDG_SURFACE => self.get_xdg_surface(parser).await?, + PONG => self.pong(parser).await?, + _ => unreachable!(), + } + Ok(()) } } @@ -80,6 +154,6 @@ impl Object for XdgWmBaseObj { } fn num_requests(&self) -> u32 { - 0 + PONG + 1 } } diff --git a/src/ifs/xdg_wm_base/types.rs b/src/ifs/xdg_wm_base/types.rs index b373714b..9f6a9428 100644 --- a/src/ifs/xdg_wm_base/types.rs +++ b/src/ifs/xdg_wm_base/types.rs @@ -1,10 +1,149 @@ -use crate::client::ClientError; +use crate::client::{ClientError, EventFormatter, RequestParser}; +use crate::ifs::xdg_wm_base::{XdgWmBaseObj, PING}; +use crate::object::{Object, ObjectId}; +use crate::utils::buffd::{MsgFormatter, MsgParser, MsgParserError}; +use std::fmt::{Debug, Formatter}; +use std::rc::Rc; use thiserror::Error; +use crate::ifs::wl_surface::xdg_surface::XdgSurfaceError; #[derive(Debug, Error)] pub enum XdgWmBaseError { #[error(transparent)] ClientError(Box), + #[error("Could not process a `destroy` request")] + DestroyError(#[from] DestroyError), + #[error("Could not process a `create_positioner` request")] + CreatePositionerError(#[from] CreatePositionerError), + #[error("Could not process a `get_xdg_surface` request")] + GetXdgSurfaceError(#[from] GetXdgSurfaceError), + #[error("Could not process a `pong` request")] + PongError(#[from] PongError), +} +efrom!(XdgWmBaseError, ClientError, ClientError); + +#[derive(Debug, Error)] +pub enum DestroyError { + #[error("Parsing failed")] + ParseError(#[source] Box), + #[error("Tried to destroy xdg_wm_base object before destroying its surfaces")] + DefunctSurfaces, + #[error(transparent)] + ClientError(Box), +} +efrom!(DestroyError, ParseError, MsgParserError); +efrom!(DestroyError, ClientError, ClientError); + +#[derive(Debug, Error)] +pub enum CreatePositionerError { + #[error("Parsing failed")] + ParseError(#[source] Box), + #[error(transparent)] + ClientError(Box), +} +efrom!(CreatePositionerError, ParseError, MsgParserError); +efrom!(CreatePositionerError, ClientError, ClientError); + +#[derive(Debug, Error)] +pub enum GetXdgSurfaceError { + #[error("Parsing failed")] + ParseError(#[source] Box), + #[error(transparent)] + ClientError(Box), + #[error(transparent)] + XdgSurfaceError(Box), +} +efrom!(GetXdgSurfaceError, ParseError, MsgParserError); +efrom!(GetXdgSurfaceError, ClientError, ClientError); +efrom!(GetXdgSurfaceError, XdgSurfaceError, XdgSurfaceError); + +#[derive(Debug, Error)] +pub enum PongError { + #[error("Parsing failed")] + ParseError(#[source] Box), +} +efrom!(PongError, ParseError, MsgParserError); + +pub(super) struct Destroy; +impl RequestParser<'_> for Destroy { + fn parse(_parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self) + } +} +impl Debug for Destroy { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "destroy()",) + } } -efrom!(XdgWmBaseError, ClientError, ClientError); +pub(super) struct CreatePositioner { + pub id: ObjectId, +} +impl RequestParser<'_> for CreatePositioner { + fn parse(parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self { + id: parser.object()?, + }) + } +} +impl Debug for CreatePositioner { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "create_positioner(id: {})", self.id,) + } +} + +pub(super) struct GetXdgSurface { + pub id: ObjectId, + pub surface: ObjectId, +} +impl RequestParser<'_> for GetXdgSurface { + fn parse(parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self { + id: parser.object()?, + surface: parser.object()?, + }) + } +} +impl Debug for GetXdgSurface { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "get_xdg_surface(id: {}, surface: {})", + self.id, self.surface, + ) + } +} + +pub(super) struct Pong { + pub serial: u32, +} +impl RequestParser<'_> for Pong { + fn parse(parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self { + serial: parser.uint()?, + }) + } +} +impl Debug for Pong { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "pong(serial: {})", self.serial,) + } +} + +pub(super) struct Ping { + pub obj: Rc, + pub serial: u32, +} +impl EventFormatter for Ping { + fn format(self: Box, fmt: &mut MsgFormatter<'_>) { + fmt.header(self.obj.id, PING).uint(self.serial); + } + fn obj(&self) -> &dyn Object { + &*self.obj + } +} +impl Debug for Ping { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "ping(serial: {})", self.serial) + } +} diff --git a/src/main.rs b/src/main.rs index f67d37ab..a0486790 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ #![feature(generic_associated_types, type_alias_impl_trait)] use crate::acceptor::AcceptorError; +use crate::async_engine::AsyncError; use crate::client::Clients; use crate::clientmem::ClientMemError; use crate::event_loop::EventLoopError; @@ -12,10 +13,15 @@ use crate::ifs::xdg_wm_base::XdgWmBaseGlobal; use crate::sighand::SighandError; use crate::state::State; use crate::utils::numcell::NumCell; +use crate::wheel::WheelError; +use acceptor::Acceptor; use anyhow::anyhow; +use async_engine::AsyncEngine; +use event_loop::EventLoop; use log::LevelFilter; use std::rc::Rc; use thiserror::Error; +use wheel::Wheel; #[macro_use] mod macros; @@ -24,6 +30,7 @@ mod async_engine; mod client; mod clientmem; mod event_loop; +mod format; mod globals; mod ifs; mod object; @@ -54,14 +61,18 @@ enum MainError { SighandError(#[from] SighandError), #[error("The clientmem subsystem caused an error")] ClientmemError(#[from] ClientMemError), + #[error("The timer subsystem caused an error")] + WheelError(#[from] WheelError), + #[error("The async subsystem caused an error")] + AsyncError(#[from] AsyncError), } fn main_() -> Result<(), MainError> { clientmem::init()?; - let el = event_loop::EventLoop::new().unwrap(); - sighand::install(&el.to_ref())?; - let wheel = wheel::WheelRef::new(&el.to_ref()).unwrap(); - let engine = Rc::new(async_engine::AsyncEngine::new(&el.to_ref(), &wheel).unwrap()); + let el = EventLoop::new()?; + sighand::install(&el)?; + let wheel = Wheel::install(&el)?; + let engine = AsyncEngine::install(&el, &wheel)?; let globals = Globals::new(); globals.insert_no_broadcast(Rc::new(WlCompositorGlobal::new(globals.name()))); globals.insert_no_broadcast(Rc::new(WlShmGlobal::new(globals.name()))); @@ -69,12 +80,13 @@ fn main_() -> Result<(), MainError> { globals.insert_no_broadcast(Rc::new(XdgWmBaseGlobal::new(globals.name()))); let state = Rc::new(State { eng: engine, - el: el.to_ref(), + el: el.clone(), clients: Clients::new(), next_name: NumCell::new(1), globals, + formats: format::formats(), }); - acceptor::Acceptor::install(&state)?; + Acceptor::install(&state)?; el.run()?; Ok(()) } diff --git a/src/object.rs b/src/object.rs index 4d74f16c..af115f35 100644 --- a/src/object.rs +++ b/src/object.rs @@ -1,5 +1,4 @@ use crate::client::ClientError; -use crate::ifs::wl_display::WlDisplay; use crate::utils::buffd::MsgParser; use std::fmt::{Display, Formatter}; use std::future::Future; @@ -39,9 +38,6 @@ pub trait Object: ObjectHandleRequest + 'static { fn id(&self) -> ObjectId; fn interface(&self) -> Interface; fn num_requests(&self) -> u32; - fn into_display(self: Rc) -> Result, ClientError> { - Err(ClientError::NotADisplay(self.id())) - } } #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -54,8 +50,12 @@ pub enum Interface { WlShmPool, WlSubcompositor, XdgWmBase, + XdgPositioner, WlSurface, WlSubsurface, + XdgSurface, + XdgPopup, + XdgToplevel, WlRegion, } @@ -73,6 +73,10 @@ impl Interface { Interface::WlSubsurface => "wl_subsurface", Interface::WlShmPool => "wl_shm_pool", Interface::WlRegion => "wl_region", + Interface::XdgSurface => "xdg_surface", + Interface::XdgPositioner => "xdg_positioner", + Interface::XdgPopup => "xdg_popup", + Interface::XdgToplevel => "xdg_toplevel", } } } diff --git a/src/sighand.rs b/src/sighand.rs index 5349940d..fb7914c0 100644 --- a/src/sighand.rs +++ b/src/sighand.rs @@ -1,4 +1,4 @@ -use crate::event_loop::{EventLoopDispatcher, EventLoopId, EventLoopRef}; +use crate::event_loop::{EventLoop, EventLoopDispatcher, EventLoopId}; use crate::EventLoopError; use std::error::Error; use std::rc::Rc; @@ -19,7 +19,7 @@ pub enum SighandError { EventLoopError(#[from] EventLoopError), } -pub fn install(el: &EventLoopRef) -> Result<(), SighandError> { +pub fn install(el: &Rc) -> Result<(), SighandError> { let mut set: c::sigset_t = uapi::pod_zeroed(); uapi::sigaddset(&mut set, c::SIGINT).unwrap(); if let Err(e) = uapi::pthread_sigmask(c::SIG_BLOCK, Some(&set), None) { @@ -29,7 +29,7 @@ pub fn install(el: &EventLoopRef) -> Result<(), SighandError> { Ok(fd) => fd, Err(e) => return Err(SighandError::CreateFailed(e.into())), }; - let id = el.id()?; + let id = el.id(); let sh = Rc::new(Sighand { fd, id, @@ -42,7 +42,7 @@ pub fn install(el: &EventLoopRef) -> Result<(), SighandError> { struct Sighand { fd: OwnedFd, id: EventLoopId, - el: EventLoopRef, + el: Rc, } impl EventLoopDispatcher for Sighand { diff --git a/src/state.rs b/src/state.rs index 1bf59bad..58347f3d 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1,14 +1,17 @@ use crate::async_engine::AsyncEngine; use crate::client::Clients; -use crate::event_loop::EventLoopRef; +use crate::event_loop::EventLoop; +use crate::format::Format; use crate::globals::Globals; use crate::utils::numcell::NumCell; +use ahash::AHashMap; use std::rc::Rc; pub struct State { pub eng: Rc, - pub el: EventLoopRef, + pub el: Rc, pub clients: Clients, pub next_name: NumCell, pub globals: Globals, + pub formats: AHashMap, } diff --git a/src/utils/buffd/formatter.rs b/src/utils/buffd/formatter.rs index 256831d2..87a45920 100644 --- a/src/utils/buffd/formatter.rs +++ b/src/utils/buffd/formatter.rs @@ -1,21 +1,21 @@ use crate::object::ObjectId; use crate::utils::buffd::buf_out::{BufFdOut, MsgFds}; use std::mem; -use std::mem::MaybeUninit; +use std::mem::{MaybeUninit}; use uapi::OwnedFd; pub struct MsgFormatter<'a> { buf: &'a mut BufFdOut, pos: usize, - fds: Vec, + fds: &'a mut Vec, } impl<'a> MsgFormatter<'a> { - pub fn new(buf: &'a mut BufFdOut) -> Self { + pub fn new(buf: &'a mut BufFdOut, fds: &'a mut Vec) -> Self { Self { pos: buf.out_pos, buf, - fds: vec![], + fds, } } @@ -57,10 +57,29 @@ impl<'a> MsgFormatter<'a> { pub fn header(&mut self, obj: ObjectId, event: u32) -> &mut Self { self.object(obj).uint(event) } -} -impl<'a> Drop for MsgFormatter<'a> { - fn drop(&mut self) { + pub fn array)>(&mut self, f: F) -> &mut Self { + let pos = self.buf.out_pos; + self.uint(0); + let len = { + let mut fmt = MsgFormatter { + buf: self.buf, + pos, + fds: self.fds, + }; + f(&mut fmt); + let len = self.buf.out_pos - pos + 4; + let none = [MaybeUninit::new(0); 4]; + self.buf.write(&none[..self.buf.out_pos.wrapping_neg() & 3]); + len as u32 + }; + unsafe { + (*self.buf.out_buf)[pos..pos + 4].copy_from_slice(uapi::as_maybe_uninit_bytes(&len)); + } + self + } + + pub fn write_len(self) { assert!(self.buf.out_pos - self.pos >= 8); assert_eq!(self.pos % 4, 0); unsafe { @@ -71,7 +90,7 @@ impl<'a> Drop for MsgFormatter<'a> { if self.fds.len() > 0 { self.buf.fds.push_back(MsgFds { pos: self.pos, - fds: mem::take(&mut self.fds), + fds: mem::take(self.fds), }) } } diff --git a/src/utils/copyhashmap.rs b/src/utils/copyhashmap.rs index d099e5df..e376ff68 100644 --- a/src/utils/copyhashmap.rs +++ b/src/utils/copyhashmap.rs @@ -1,6 +1,7 @@ use ahash::AHashMap; use std::cell::{RefCell, RefMut}; use std::hash::Hash; +use std::mem; pub struct CopyHashMap { map: RefCell>, @@ -40,6 +41,10 @@ impl CopyHashMap { } pub fn clear(&self) { - self.map.borrow_mut().clear(); + mem::take(&mut *self.map.borrow_mut()); + } + + pub fn is_empty(&self) -> bool { + self.map.borrow().is_empty() } } diff --git a/src/utils/linkedlist.rs b/src/utils/linkedlist.rs new file mode 100644 index 00000000..ef221643 --- /dev/null +++ b/src/utils/linkedlist.rs @@ -0,0 +1,176 @@ +use crate::utils::ptr_ext::PtrExt; +use crate::NumCell; +use std::cell::Cell; +use std::mem::MaybeUninit; +use std::ops::Deref; +use std::ptr::NonNull; + +pub struct LinkedList { + root: Node, +} + +impl Default for LinkedList { + fn default() -> Self { + Self::new() + } +} + +impl LinkedList { + pub fn new() -> Self { + let node = Box::into_raw(Box::new(NodeData { + rc: NumCell::new(3), + prev: Cell::new(NonNull::dangling()), + next: Cell::new(NonNull::dangling()), + data: MaybeUninit::uninit(), + })); + unsafe { + node.deref().prev.set(NonNull::new_unchecked(node)); + node.deref().next.set(NonNull::new_unchecked(node)); + Self { + root: Node { + data: NonNull::new_unchecked(node), + }, + } + } + } + + pub fn prepend(&self, t: T) -> Node { + self.root.prepend(t) + } + + pub fn append(&self, t: T) -> Node { + self.root.append(t) + } + + pub fn iter(&self) -> LinkedListIter { + unsafe { + let root = self.root.data.as_ref(); + root.rc.fetch_add(1); + root.next.get().as_ref().rc.fetch_add(1); + LinkedListIter { + root: self.root.data, + next: root.next.get(), + } + } + } +} + +pub struct LinkedListIter { + root: NonNull>, + next: NonNull>, +} + +impl Iterator for LinkedListIter { + type Item = NodeRef; + + fn next(&mut self) -> Option { + if self.root == self.next { + return None; + } + unsafe { + let old_next = self.next; + self.next = old_next.as_ref().next.get(); + self.next.as_ref().rc.fetch_add(1); + Some(NodeRef { data: old_next }) + } + } +} + +impl Drop for LinkedListIter { + fn drop(&mut self) { + unsafe { + dec_ref_count(self.root, 1); + dec_ref_count(self.next, 1); + } + } +} + +pub struct Node { + data: NonNull>, +} + +impl Deref for Node { + type Target = T; + + fn deref(&self) -> &Self::Target { + unsafe { self.data.as_ref().data.assume_init_ref() } + } +} + +pub struct NodeRef { + data: NonNull>, +} + +impl Deref for NodeRef { + type Target = T; + + fn deref(&self) -> &Self::Target { + unsafe { self.data.as_ref().data.assume_init_ref() } + } +} + +impl Drop for NodeRef { + fn drop(&mut self) { + unsafe { + dec_ref_count(self.data, 1); + } + } +} + +struct NodeData { + rc: NumCell, + prev: Cell>>, + next: Cell>>, + data: MaybeUninit, +} + +unsafe fn dec_ref_count(slf: NonNull>, n: usize) { + if slf.as_ref().rc.fetch_sub(n) == n { + drop(Box::from_raw(slf.as_ptr())); + } +} + +impl Drop for Node { + fn drop(&mut self) { + unsafe { + { + let data = self.data.as_ref(); + data.prev.get().as_ref().next.set(data.next.get()); + data.next.get().as_ref().prev.set(data.prev.get()); + } + dec_ref_count(self.data, 3); + } + } +} + +impl Node { + pub fn prepend(&self, t: T) -> Node { + unsafe { + let data = self.data.as_ref(); + let node = NonNull::new_unchecked(Box::into_raw(Box::new(NodeData { + rc: NumCell::new(3), + prev: Cell::new(data.prev.get()), + next: Cell::new(self.data), + data: MaybeUninit::new(t), + }))); + data.prev.get().as_ref().next.set(node); + data.prev.set(node); + Node { data: node } + } + } + + pub fn append(&self, t: T) -> Node { + unsafe { + let data = self.data.as_ref(); + let node = NonNull::new_unchecked(Box::into_raw(Box::new(NodeData { + rc: NumCell::new(3), + prev: Cell::new(self.data), + next: Cell::new(data.next.get()), + data: MaybeUninit::new(t), + }))); + data.next.get().as_ref().prev.set(node); + data.next.set(node); + Node { data: node } + } + } +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index b0cdbbbd..73e64567 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,7 +1,9 @@ pub mod buffd; pub mod copyhashmap; +pub mod linkedlist; pub mod lock; pub mod numcell; pub mod oneshot; +pub mod ptr_ext; pub mod queue; pub mod vec_ext; diff --git a/src/utils/ptr_ext.rs b/src/utils/ptr_ext.rs new file mode 100644 index 00000000..133b90cf --- /dev/null +++ b/src/utils/ptr_ext.rs @@ -0,0 +1,25 @@ +pub trait PtrExt { + unsafe fn deref<'a>(self) -> &'a T; +} + +pub trait MutPtrExt { + unsafe fn deref_mut<'a>(self) -> &'a mut T; +} + +impl PtrExt for *const T { + unsafe fn deref<'a>(self) -> &'a T { + &*self + } +} + +impl PtrExt for *mut T { + unsafe fn deref<'a>(self) -> &'a T { + &*self + } +} + +impl MutPtrExt for *mut T { + unsafe fn deref_mut<'a>(self) -> &'a mut T { + &mut *self + } +} diff --git a/src/wheel.rs b/src/wheel.rs index 1a18d81f..838c4243 100644 --- a/src/wheel.rs +++ b/src/wheel.rs @@ -1,11 +1,11 @@ -use crate::event_loop::{EventLoopDispatcher, EventLoopError, EventLoopId, EventLoopRef}; +use crate::event_loop::{EventLoop, EventLoopDispatcher, EventLoopError}; use crate::time::{Time, TimeError}; use crate::utils::copyhashmap::CopyHashMap; use crate::utils::numcell::NumCell; use std::cell::{Cell, RefCell}; use std::cmp::Reverse; use std::collections::BinaryHeap; -use std::rc::{Rc, Weak}; +use std::rc::Rc; use std::time::Duration; use thiserror::Error; use uapi::{c, OwnedFd}; @@ -30,11 +30,6 @@ pub trait WheelDispatcher { fn dispatch(self: Rc) -> Result<(), Box>; } -#[derive(Clone)] -pub struct WheelRef { - data: Weak, -} - #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)] struct WheelEntry { expiration: Time, @@ -44,10 +39,9 @@ struct WheelEntry { #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub struct WheelId(u64); -struct WheelData { - id: EventLoopId, +pub struct Wheel { + destroyed: Cell, fd: OwnedFd, - el: EventLoopRef, next_id: NumCell, start: Time, current_expiration: Cell>, @@ -55,37 +49,47 @@ struct WheelData { expirations: RefCell>>, } -impl WheelData { - fn new(el: &EventLoopRef) -> Result, WheelError> { +impl Wheel { + pub fn install(el: &Rc) -> Result, WheelError> { let fd = match uapi::timerfd_create(c::CLOCK_MONOTONIC, c::TFD_CLOEXEC | c::TFD_NONBLOCK) { Ok(fd) => fd, Err(e) => return Err(WheelError::CreateFailed(e.into())), }; - let id = el.id()?; + let id = el.id(); let wheel = Rc::new(Self { - id, + destroyed: Cell::new(false), fd, - el: el.clone(), next_id: Default::default(), start: Time::now()?, current_expiration: Cell::new(None), dispatchers: CopyHashMap::new(), expirations: RefCell::new(Default::default()), }); - el.insert(id, Some(wheel.fd.raw()), c::EPOLLIN, wheel.clone())?; + let wrapper = Rc::new(WheelWrapper { + wheel: wheel.clone(), + }); + el.insert(id, Some(wheel.fd.raw()), c::EPOLLIN, wrapper)?; Ok(wheel) } - fn id(&self) -> WheelId { + pub fn id(&self) -> WheelId { WheelId(self.next_id.fetch_add(1)) } - fn timeout( + fn check_destroyed(&self) -> Result<(), WheelError> { + if self.destroyed.get() { + return Err(WheelError::Destroyed); + } + Ok(()) + } + + pub fn timeout( &self, id: WheelId, ms: u64, dispatcher: Rc, ) -> Result<(), WheelError> { + self.check_destroyed()?; let expiration = (Time::now()? + Duration::from_millis(ms)).round_to_ms(); let current = self.current_expiration.get(); if current.is_none() || expiration - self.start < current.unwrap() - self.start { @@ -110,41 +114,45 @@ impl WheelData { Ok(()) } - fn remove(&self, id: WheelId) { - log::trace!("removing {:?} from wheel", id); + pub fn remove(&self, id: WheelId) { + // log::trace!("removing {:?} from wheel", id); self.dispatchers.remove(&id.0); } } -impl EventLoopDispatcher for WheelData { +struct WheelWrapper { + wheel: Rc, +} + +impl EventLoopDispatcher for WheelWrapper { fn dispatch(&self, events: i32) -> Result<(), Box> { if events & (c::EPOLLERR | c::EPOLLHUP) != 0 { return Err(Box::new(WheelError::ErrorEvent)); } let mut n = 0u64; - while uapi::read(self.fd.raw(), &mut n).is_ok() {} + while uapi::read(self.wheel.fd.raw(), &mut n).is_ok() {} let now = match Time::now() { Ok(n) => n, Err(e) => return Err(Box::new(e)), }; - let dist = now - self.start; + let dist = now - self.wheel.start; let mut to_dispatch = vec![]; { - let mut expirations = self.expirations.borrow_mut(); + let mut expirations = self.wheel.expirations.borrow_mut(); while let Some(Reverse(entry)) = expirations.peek() { - if entry.expiration - self.start > dist { + if entry.expiration - self.wheel.start > dist { break; } - if let Some(dispatcher) = self.dispatchers.remove(&entry.id) { + if let Some(dispatcher) = self.wheel.dispatchers.remove(&entry.id) { to_dispatch.push(dispatcher); } expirations.pop(); } - self.current_expiration.set(None); + self.wheel.current_expiration.set(None); while let Some(Reverse(entry)) = expirations.peek() { - if self.dispatchers.get(&entry.id).is_some() { + if self.wheel.dispatchers.get(&entry.id).is_some() { let res = uapi::timerfd_settime( - self.fd.raw(), + self.wheel.fd.raw(), c::TFD_TIMER_ABSTIME, &c::itimerspec { it_interval: uapi::pod_zeroed(), @@ -154,7 +162,7 @@ impl EventLoopDispatcher for WheelData { if let Err(e) = res { return Err(Box::new(WheelError::SetFailed(e.into()))); } - self.current_expiration.set(Some(entry.expiration)); + self.wheel.current_expiration.set(Some(entry.expiration)); break; } expirations.pop(); @@ -167,41 +175,9 @@ impl EventLoopDispatcher for WheelData { } } -impl Drop for WheelData { +impl Drop for WheelWrapper { fn drop(&mut self) { - let _ = self.el.remove(self.id); - } -} - -impl WheelRef { - pub fn new(el: &EventLoopRef) -> Result { - Ok(Self { - data: Rc::downgrade(&WheelData::new(el)?), - }) - } - - pub fn id(&self) -> Result { - match self.data.upgrade() { - Some(d) => Ok(d.id()), - _ => Err(WheelError::Destroyed), - } - } - - pub fn timeout( - &self, - id: WheelId, - ms: u64, - dispatcher: Rc, - ) -> Result<(), WheelError> { - match self.data.upgrade() { - Some(d) => d.timeout(id, ms, dispatcher), - _ => Err(WheelError::Destroyed), - } - } - - pub fn remove(&self, id: WheelId) { - if let Some(wheel) = self.data.upgrade() { - wheel.remove(id); - } + self.wheel.destroyed.set(true); + self.wheel.dispatchers.clear(); } }