autocommit 2022-01-02 16:30:30 CET
This commit is contained in:
parent
d6172b273f
commit
c21f231ce7
34 changed files with 874 additions and 844 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
|
use crate::client::ClientError;
|
||||||
use crate::event_loop::{EventLoopDispatcher, EventLoopError, EventLoopId};
|
use crate::event_loop::{EventLoopDispatcher, EventLoopError, EventLoopId};
|
||||||
use crate::state::State;
|
use crate::state::State;
|
||||||
use crate::wl_client::WlClientError;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use uapi::{c, Errno, OwnedFd};
|
use uapi::{c, Errno, OwnedFd};
|
||||||
|
|
@ -20,7 +20,7 @@ pub enum AcceptorError {
|
||||||
#[error("Could not accept new connections")]
|
#[error("Could not accept new connections")]
|
||||||
AcceptFailed(#[source] std::io::Error),
|
AcceptFailed(#[source] std::io::Error),
|
||||||
#[error("Could not spawn an event handler for a new connection")]
|
#[error("Could not spawn an event handler for a new connection")]
|
||||||
SpawnFailed(#[source] WlClientError),
|
SpawnFailed(#[source] ClientError),
|
||||||
#[error("Could not bind the socket to an address")]
|
#[error("Could not bind the socket to an address")]
|
||||||
BindFailed(#[source] std::io::Error),
|
BindFailed(#[source] std::io::Error),
|
||||||
#[error("All wayland addresses in the range 0..1000 are already in use")]
|
#[error("All wayland addresses in the range 0..1000 are already in use")]
|
||||||
|
|
|
||||||
395
src/client/mod.rs
Normal file
395
src/client/mod.rs
Normal file
|
|
@ -0,0 +1,395 @@
|
||||||
|
use crate::async_engine::{AsyncError, AsyncFd, SpawnedFuture};
|
||||||
|
use crate::client::objects::Objects;
|
||||||
|
use crate::ifs::wl_callback::WlCallback;
|
||||||
|
use crate::ifs::wl_compositor::{WlCompositorError, WlCompositorObj};
|
||||||
|
use crate::ifs::wl_display::{WlDisplay, WlDisplayError};
|
||||||
|
use crate::ifs::wl_region::{WlRegion, WlRegionError};
|
||||||
|
use crate::ifs::wl_registry::{WlRegistry, WlRegistryError};
|
||||||
|
use crate::ifs::wl_shm::{WlShmError, WlShmObj};
|
||||||
|
use crate::ifs::wl_shm_pool::{WlShmPool, WlShmPoolError};
|
||||||
|
use crate::ifs::wl_subcompositor::WlSubcompositorObj;
|
||||||
|
use crate::ifs::wl_surface::{WlSurface, WlSurfaceError};
|
||||||
|
use crate::ifs::xdg_wm_base::XdgWmBaseObj;
|
||||||
|
use crate::object::{Object, ObjectId, WL_DISPLAY_ID};
|
||||||
|
use crate::state::State;
|
||||||
|
use crate::utils::buffd::{BufFdError, WlFormatter, WlParser, WlParserError};
|
||||||
|
use crate::utils::copyhashmap::CopyHashMap;
|
||||||
|
use crate::utils::numcell::NumCell;
|
||||||
|
use crate::utils::oneshot::{oneshot, OneshotTx};
|
||||||
|
use crate::utils::queue::AsyncQueue;
|
||||||
|
use ahash::AHashMap;
|
||||||
|
use anyhow::anyhow;
|
||||||
|
use std::cell::{Cell, RefMut};
|
||||||
|
use std::fmt::{Debug, Display, Formatter};
|
||||||
|
use std::future::Future;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use thiserror::Error;
|
||||||
|
use uapi::OwnedFd;
|
||||||
|
|
||||||
|
mod objects;
|
||||||
|
mod tasks;
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum ClientError {
|
||||||
|
#[error("An error occurred in the async engine")]
|
||||||
|
Async(#[from] AsyncError),
|
||||||
|
#[error("An error occurred reading from/writing to the client")]
|
||||||
|
Io(#[from] BufFdError),
|
||||||
|
#[error("An error occurred while processing a request")]
|
||||||
|
RequestError(#[source] Box<ClientError>),
|
||||||
|
#[error("Client tried to invoke a non-existent method")]
|
||||||
|
InvalidMethod,
|
||||||
|
#[error("Client tried to access non-existent object {0}")]
|
||||||
|
InvalidObject(ObjectId),
|
||||||
|
#[error("The message size is < 8")]
|
||||||
|
MessageSizeTooSmall,
|
||||||
|
#[error("The size of the message is not a multiple of 4")]
|
||||||
|
UnalignedMessage,
|
||||||
|
#[error("The outgoing buffer overflowed")]
|
||||||
|
OutBufferOverflow,
|
||||||
|
#[error("The requested client {0} does not exist")]
|
||||||
|
ClientDoesNotExist(ClientId),
|
||||||
|
#[error("There is no region with id {0}")]
|
||||||
|
RegionDoesNotExist(ObjectId),
|
||||||
|
#[error("Cannot parse the message")]
|
||||||
|
ParserError(#[source] Box<WlParserError>),
|
||||||
|
#[error("Server tried to allocate more than 0x1_00_00_00 ids")]
|
||||||
|
TooManyIds,
|
||||||
|
#[error("The server object id is out of bounds")]
|
||||||
|
ServerIdOutOfBounds,
|
||||||
|
#[error("The object id is unknown")]
|
||||||
|
UnknownId,
|
||||||
|
#[error("The id is already in use")]
|
||||||
|
IdAlreadyInUse,
|
||||||
|
#[error("The client object id is out of bounds")]
|
||||||
|
ClientIdOutOfBounds,
|
||||||
|
#[error("An error occurred in a `wl_display`")]
|
||||||
|
WlDisplayError(#[source] Box<WlDisplayError>),
|
||||||
|
#[error("An error occurred in a `wl_registry`")]
|
||||||
|
WlRegistryError(#[source] Box<WlRegistryError>),
|
||||||
|
#[error("Could not add object {0} to the client")]
|
||||||
|
AddObjectError(ObjectId, #[source] Box<ClientError>),
|
||||||
|
#[error("An error occurred in a `wl_surface`")]
|
||||||
|
WlSurfaceError(#[source] Box<WlSurfaceError>),
|
||||||
|
#[error("An error occurred in a `wl_compositor`")]
|
||||||
|
WlCompositorError(#[source] Box<WlCompositorError>),
|
||||||
|
#[error("An error occurred in a `wl_shm`")]
|
||||||
|
WlShmError(#[source] Box<WlShmError>),
|
||||||
|
#[error("An error occurred in a `wl_shm_pool`")]
|
||||||
|
WlShmPoolError(#[source] Box<WlShmPoolError>),
|
||||||
|
#[error("An error occurred in a `wl_region`")]
|
||||||
|
WlRegionError(#[source] Box<WlRegionError>),
|
||||||
|
#[error("Object {0} is not a display")]
|
||||||
|
NotADisplay(ObjectId),
|
||||||
|
}
|
||||||
|
|
||||||
|
efrom!(ClientError, ParserError, WlParserError);
|
||||||
|
efrom!(ClientError, WlDisplayError, WlDisplayError);
|
||||||
|
efrom!(ClientError, WlRegistryError, WlRegistryError);
|
||||||
|
efrom!(ClientError, WlSurfaceError, WlSurfaceError);
|
||||||
|
efrom!(ClientError, WlCompositorError, WlCompositorError);
|
||||||
|
efrom!(ClientError, WlShmError, WlShmError);
|
||||||
|
efrom!(ClientError, WlShmPoolError, WlShmPoolError);
|
||||||
|
efrom!(ClientError, WlRegionError, WlRegionError);
|
||||||
|
|
||||||
|
impl ClientError {
|
||||||
|
fn peer_closed(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
ClientError::Io(BufFdError::Closed) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
|
||||||
|
pub struct ClientId(u64);
|
||||||
|
|
||||||
|
impl Display for ClientId {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
Display::fmt(&self.0, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Clients {
|
||||||
|
next_client_id: NumCell<u64>,
|
||||||
|
clients: CopyHashMap<ClientId, Rc<ClientHolder>>,
|
||||||
|
shutdown_clients: CopyHashMap<ClientId, Rc<ClientHolder>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clients {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
next_client_id: NumCell::new(1),
|
||||||
|
clients: CopyHashMap::new(),
|
||||||
|
shutdown_clients: CopyHashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn id(&self) -> ClientId {
|
||||||
|
ClientId(self.next_client_id.fetch_add(1))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self, id: ClientId) -> Result<Rc<Client>, ClientError> {
|
||||||
|
match self.clients.get(&id) {
|
||||||
|
Some(c) => Ok(c.data.clone()),
|
||||||
|
_ => Err(ClientError::ClientDoesNotExist(id)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn spawn(
|
||||||
|
&self,
|
||||||
|
id: ClientId,
|
||||||
|
global: &Rc<State>,
|
||||||
|
socket: OwnedFd,
|
||||||
|
) -> Result<(), ClientError> {
|
||||||
|
let (send, recv) = oneshot();
|
||||||
|
let data = Rc::new(Client {
|
||||||
|
id,
|
||||||
|
state: global.clone(),
|
||||||
|
socket: global.eng.fd(&Rc::new(socket))?,
|
||||||
|
objects: Objects::new(),
|
||||||
|
events: AsyncQueue::new(),
|
||||||
|
shutdown: Cell::new(Some(send)),
|
||||||
|
shutdown_sent: Cell::new(false),
|
||||||
|
});
|
||||||
|
data.objects
|
||||||
|
.add_client_object(Rc::new(WlDisplay::new(&data)))
|
||||||
|
.expect("");
|
||||||
|
let client = Rc::new(ClientHolder {
|
||||||
|
_handler: global.eng.spawn(tasks::client(data.clone(), recv)),
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
self.clients.set(client.data.id, client.clone());
|
||||||
|
log::info!("Client {} connected", id);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn kill(&self, client: ClientId) {
|
||||||
|
log::info!("Removing client {}", client.0);
|
||||||
|
if self.clients.remove(&client).is_none() {
|
||||||
|
self.shutdown_clients.remove(&client);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn shutdown(&self, client_id: ClientId) {
|
||||||
|
if let Some(client) = self.clients.remove(&client_id) {
|
||||||
|
log::info!("Shutting down client {}", client.data.id.0);
|
||||||
|
client.data.shutdown.replace(None).unwrap().send(());
|
||||||
|
client.data.events.push(WlEvent::Shutdown);
|
||||||
|
client.data.shutdown_sent.set(true);
|
||||||
|
self.shutdown_clients.set(client_id, client);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn broadcast<B>(&self, mut f: B)
|
||||||
|
where
|
||||||
|
B: FnMut(&Rc<Client>),
|
||||||
|
{
|
||||||
|
let clients = self.clients.lock();
|
||||||
|
for client in clients.values() {
|
||||||
|
f(&client.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ClientHolder {
|
||||||
|
data: Rc<Client>,
|
||||||
|
_handler: SpawnedFuture<()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for ClientHolder {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.data.objects.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait EventFormatter: Debug {
|
||||||
|
fn format(self: Box<Self>, fmt: &mut WlFormatter<'_>);
|
||||||
|
fn obj(&self) -> &dyn Object;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type DynEventFormatter = Box<dyn EventFormatter>;
|
||||||
|
|
||||||
|
pub trait RequestParser<'a>: Debug + Sized {
|
||||||
|
fn parse(parser: &mut WlParser<'_, 'a>) -> Result<Self, WlParserError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum WlEvent {
|
||||||
|
Flush,
|
||||||
|
Shutdown,
|
||||||
|
Event(Box<dyn EventFormatter>),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Client {
|
||||||
|
pub id: ClientId,
|
||||||
|
pub state: Rc<State>,
|
||||||
|
socket: AsyncFd,
|
||||||
|
objects: Objects,
|
||||||
|
events: AsyncQueue<WlEvent>,
|
||||||
|
shutdown: Cell<Option<OneshotTx<()>>>,
|
||||||
|
shutdown_sent: Cell<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
const MAX_PENDING_EVENTS: usize = 100;
|
||||||
|
|
||||||
|
impl Client {
|
||||||
|
pub fn invalid_request(&self, obj: &dyn Object, request: u32) {
|
||||||
|
log::error!(
|
||||||
|
"Client {} sent an invalid request {} on object {} of type {}",
|
||||||
|
self.id.0,
|
||||||
|
request,
|
||||||
|
obj.id(),
|
||||||
|
obj.interface().name(),
|
||||||
|
);
|
||||||
|
match self.display() {
|
||||||
|
Ok(d) => self.fatal_event(d.invalid_request(obj, request)),
|
||||||
|
Err(e) => {
|
||||||
|
log::error!(
|
||||||
|
"Could not retrieve display of client {}: {:#}",
|
||||||
|
self.id,
|
||||||
|
anyhow!(e)
|
||||||
|
);
|
||||||
|
self.state.clients.kill(self.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn display(&self) -> Result<Rc<WlDisplay>, ClientError> {
|
||||||
|
Ok(self.objects.get_obj(WL_DISPLAY_ID)?.into_display()?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse<'a, R: RequestParser<'a>>(
|
||||||
|
&self,
|
||||||
|
obj: &impl Object,
|
||||||
|
mut parser: WlParser<'_, 'a>,
|
||||||
|
) -> Result<R, WlParserError> {
|
||||||
|
let res = R::parse(&mut parser)?;
|
||||||
|
parser.eof()?;
|
||||||
|
log::trace!(
|
||||||
|
"Client {} -> {}@{}.{:?}",
|
||||||
|
self.id,
|
||||||
|
obj.interface().name(),
|
||||||
|
obj.id(),
|
||||||
|
res
|
||||||
|
);
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fatal_event(&self, event: Box<dyn EventFormatter>) {
|
||||||
|
self.events.push(WlEvent::Event(event));
|
||||||
|
self.state.clients.shutdown(self.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn event_locked(&self, event: Box<dyn EventFormatter>) -> bool {
|
||||||
|
self.events.push(WlEvent::Event(event));
|
||||||
|
self.events.size() > MAX_PENDING_EVENTS
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn event(&self, event: Box<dyn EventFormatter>) -> Result<(), ClientError> {
|
||||||
|
self.event2(WlEvent::Event(event)).await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn event2(&self, event: WlEvent) -> Result<(), ClientError> {
|
||||||
|
self.events.push(event);
|
||||||
|
self.check_queue_size().await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn check_queue_size(&self) -> Result<(), ClientError> {
|
||||||
|
if self.events.size() > MAX_PENDING_EVENTS {
|
||||||
|
self.state.eng.yield_now().await;
|
||||||
|
if self.events.size() > MAX_PENDING_EVENTS {
|
||||||
|
log::error!("Client {} is too slow at fetching events", self.id.0);
|
||||||
|
self.state.clients.kill(self.id);
|
||||||
|
return Err(ClientError::OutBufferOverflow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_region(&self, id: ObjectId) -> Result<Rc<WlRegion>, ClientError> {
|
||||||
|
match self.objects.regions.get(&id) {
|
||||||
|
Some(r) => Ok(r),
|
||||||
|
_ => Err(ClientError::RegionDoesNotExist(id)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn simple_add_obj<T: Object>(&self, obj: &Rc<T>, client: bool) -> Result<(), ClientError> {
|
||||||
|
if client {
|
||||||
|
self.objects.add_client_object(obj.clone())
|
||||||
|
} else {
|
||||||
|
self.objects.add_server_object(obj.clone());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn simple_remove_obj<'a>(
|
||||||
|
&'a self,
|
||||||
|
id: ObjectId,
|
||||||
|
) -> impl Future<Output = Result<(), ClientError>> + 'a {
|
||||||
|
self.objects.remove_obj(self, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lock_registries(&self) -> RefMut<AHashMap<ObjectId, Rc<WlRegistry>>> {
|
||||||
|
self.objects.registries()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait AddObj<T> {
|
||||||
|
type RemoveObj<'a>: Future<Output = Result<(), ClientError>> + 'a;
|
||||||
|
|
||||||
|
fn add_client_obj(&self, obj: &Rc<T>) -> Result<(), ClientError> {
|
||||||
|
self.add_obj(obj, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_server_obj(&self, obj: &Rc<T>) {
|
||||||
|
self.add_obj(obj, false).expect("add_server_obj failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_obj(&self, obj: &Rc<T>, client: bool) -> Result<(), ClientError>;
|
||||||
|
|
||||||
|
fn remove_obj<'a>(&'a self, obj: &'a T) -> Self::RemoveObj<'a>;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! simple_add_obj {
|
||||||
|
($ty:ty) => {
|
||||||
|
impl AddObj<$ty> for Client {
|
||||||
|
type RemoveObj<'a> = impl Future<Output = Result<(), ClientError>> + 'a;
|
||||||
|
|
||||||
|
fn add_obj(&self, obj: &Rc<$ty>, client: bool) -> Result<(), ClientError> {
|
||||||
|
self.simple_add_obj(obj, client)
|
||||||
|
}
|
||||||
|
fn remove_obj<'a>(&'a self, obj: &'a $ty) -> Self::RemoveObj<'a> {
|
||||||
|
self.simple_remove_obj(obj.id())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
simple_add_obj!(WlCompositorObj);
|
||||||
|
simple_add_obj!(WlCallback);
|
||||||
|
simple_add_obj!(WlRegistry);
|
||||||
|
simple_add_obj!(WlShmObj);
|
||||||
|
simple_add_obj!(WlShmPool);
|
||||||
|
simple_add_obj!(WlSubcompositorObj);
|
||||||
|
simple_add_obj!(XdgWmBaseObj);
|
||||||
|
|
||||||
|
macro_rules! dedicated_add_obj {
|
||||||
|
($ty:ty, $field:ident) => {
|
||||||
|
impl AddObj<$ty> for Client {
|
||||||
|
type RemoveObj<'a> = impl Future<Output = Result<(), ClientError>> + 'a;
|
||||||
|
|
||||||
|
fn add_obj(&self, obj: &Rc<$ty>, client: bool) -> Result<(), ClientError> {
|
||||||
|
self.simple_add_obj(obj, client)?;
|
||||||
|
self.objects.$field.set(obj.id(), obj.clone());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
fn remove_obj<'a>(&'a self, obj: &'a $ty) -> Self::RemoveObj<'a> {
|
||||||
|
self.objects.$field.remove(&obj.id());
|
||||||
|
self.simple_remove_obj(obj.id())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
dedicated_add_obj!(WlRegion, regions);
|
||||||
|
dedicated_add_obj!(WlSurface, surfaces);
|
||||||
122
src/client/objects.rs
Normal file
122
src/client/objects.rs
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
use crate::client::{Client, ClientError};
|
||||||
|
use crate::ifs::wl_region::WlRegion;
|
||||||
|
use crate::ifs::wl_registry::WlRegistry;
|
||||||
|
use crate::ifs::wl_surface::WlSurface;
|
||||||
|
use crate::object::{Object, ObjectId};
|
||||||
|
use crate::utils::copyhashmap::CopyHashMap;
|
||||||
|
use ahash::AHashMap;
|
||||||
|
use std::cell::{RefCell, RefMut};
|
||||||
|
use std::mem;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
pub struct Objects {
|
||||||
|
registry: CopyHashMap<ObjectId, Rc<dyn Object>>,
|
||||||
|
registries: CopyHashMap<ObjectId, Rc<WlRegistry>>,
|
||||||
|
pub surfaces: CopyHashMap<ObjectId, Rc<WlSurface>>,
|
||||||
|
pub regions: CopyHashMap<ObjectId, Rc<WlRegion>>,
|
||||||
|
ids: RefCell<Vec<usize>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const MIN_SERVER_ID: u32 = 0xff000000;
|
||||||
|
const SEG_SIZE: usize = 8 * mem::size_of::<usize>();
|
||||||
|
|
||||||
|
impl Objects {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
registry: Default::default(),
|
||||||
|
registries: Default::default(),
|
||||||
|
surfaces: Default::default(),
|
||||||
|
regions: Default::default(),
|
||||||
|
ids: RefCell::new(vec![]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy(&self) {
|
||||||
|
self.registry.clear();
|
||||||
|
self.registries.clear();
|
||||||
|
self.surfaces.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn id(&self, client_data: &Client) -> Result<ObjectId, ClientError> {
|
||||||
|
const MAX_ID_OFFSET: u32 = u32::MAX - MIN_SERVER_ID;
|
||||||
|
let offset = self.id_offset();
|
||||||
|
if offset > MAX_ID_OFFSET {
|
||||||
|
log::error!(
|
||||||
|
"Client {} caused the server to allocate more than 0x{:x} ids",
|
||||||
|
client_data.id,
|
||||||
|
MAX_ID_OFFSET + 1
|
||||||
|
);
|
||||||
|
return Err(ClientError::TooManyIds);
|
||||||
|
}
|
||||||
|
Ok(ObjectId::from_raw(MIN_SERVER_ID + offset))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_obj(&self, id: ObjectId) -> Result<Rc<dyn Object>, ClientError> {
|
||||||
|
match self.registry.get(&id) {
|
||||||
|
Some(o) => Ok(o),
|
||||||
|
_ => Err(ClientError::UnknownId),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_server_object(&self, obj: Rc<dyn Object>) {
|
||||||
|
let id = obj.id();
|
||||||
|
assert!(id.raw() >= MIN_SERVER_ID);
|
||||||
|
assert!(!self.registry.contains(&id));
|
||||||
|
self.registry.set(id, obj.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_client_object(&self, obj: Rc<dyn Object>) -> Result<(), ClientError> {
|
||||||
|
let id = obj.id();
|
||||||
|
let res = (|| {
|
||||||
|
if id.raw() == 0 || id.raw() >= MIN_SERVER_ID {
|
||||||
|
return Err(ClientError::ClientIdOutOfBounds);
|
||||||
|
}
|
||||||
|
if self.registry.contains(&id) {
|
||||||
|
return Err(ClientError::IdAlreadyInUse);
|
||||||
|
}
|
||||||
|
self.registry.set(id, obj.clone());
|
||||||
|
Ok(())
|
||||||
|
})();
|
||||||
|
if let Err(e) = res {
|
||||||
|
return Err(ClientError::AddObjectError(id, Box::new(e)));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn remove_obj(&self, client_data: &Client, id: ObjectId) -> Result<(), ClientError> {
|
||||||
|
if self.registry.remove(&id).is_none() {
|
||||||
|
return Err(ClientError::UnknownId);
|
||||||
|
}
|
||||||
|
if id.raw() >= MIN_SERVER_ID {
|
||||||
|
let offset = (id.raw() - MIN_SERVER_ID) as usize;
|
||||||
|
let pos = offset / SEG_SIZE;
|
||||||
|
let seg_offset = offset % SEG_SIZE;
|
||||||
|
let mut ids = self.ids.borrow_mut();
|
||||||
|
if ids.len() <= pos {
|
||||||
|
return Err(ClientError::ServerIdOutOfBounds);
|
||||||
|
}
|
||||||
|
ids[pos] |= 1 << seg_offset;
|
||||||
|
}
|
||||||
|
client_data
|
||||||
|
.event(client_data.display()?.delete_id(id))
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn registries(&self) -> RefMut<AHashMap<ObjectId, Rc<WlRegistry>>> {
|
||||||
|
self.registries.lock()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn id_offset(&self) -> u32 {
|
||||||
|
let mut ids = self.ids.borrow_mut();
|
||||||
|
for (pos, seg) in ids.iter_mut().enumerate() {
|
||||||
|
if *seg != 0 {
|
||||||
|
let offset = seg.trailing_zeros();
|
||||||
|
*seg &= !(1 << offset);
|
||||||
|
return (pos * SEG_SIZE) as u32 + offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ids.push(!1);
|
||||||
|
((ids.len() - 1) * SEG_SIZE) as u32
|
||||||
|
}
|
||||||
|
}
|
||||||
154
src/client/tasks.rs
Normal file
154
src/client/tasks.rs
Normal file
|
|
@ -0,0 +1,154 @@
|
||||||
|
use crate::client::{Client, ClientError, WlEvent};
|
||||||
|
use crate::object::ObjectId;
|
||||||
|
use crate::utils::buffd::{BufFdIn, BufFdOut, WlFormatter, WlParser};
|
||||||
|
use crate::utils::oneshot::OneshotRx;
|
||||||
|
use crate::utils::vec_ext::VecExt;
|
||||||
|
use anyhow::anyhow;
|
||||||
|
use futures::{select, FutureExt};
|
||||||
|
use std::mem;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
pub async fn client(data: Rc<Client>, shutdown: OneshotRx<()>) {
|
||||||
|
let mut recv = data.state.eng.spawn(receive(data.clone())).fuse();
|
||||||
|
let _send = data.state.eng.spawn(send(data.clone()));
|
||||||
|
select! {
|
||||||
|
_ = recv => { },
|
||||||
|
_ = shutdown.fuse() => { },
|
||||||
|
}
|
||||||
|
drop(recv);
|
||||||
|
if !data.shutdown_sent.get() {
|
||||||
|
data.events.push(WlEvent::Shutdown);
|
||||||
|
}
|
||||||
|
match data.state.eng.timeout(5000) {
|
||||||
|
Ok(timeout) => {
|
||||||
|
timeout.await;
|
||||||
|
log::error!("Could not shut down client {} within 5 seconds", data.id.0);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Could not create a timeout: {:#}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data.state.clients.kill(data.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn receive(data: Rc<Client>) {
|
||||||
|
let display = data.display().unwrap();
|
||||||
|
let recv = async {
|
||||||
|
let mut buf = BufFdIn::new(data.socket.clone());
|
||||||
|
let mut data_buf = Vec::<u32>::new();
|
||||||
|
loop {
|
||||||
|
let mut hdr = [0u32, 0];
|
||||||
|
buf.read_full(&mut hdr[..]).await?;
|
||||||
|
let obj_id = ObjectId::from_raw(hdr[0]);
|
||||||
|
let len = (hdr[1] >> 16) as usize;
|
||||||
|
let request = hdr[1] & 0xffff;
|
||||||
|
let obj = match data.objects.get_obj(obj_id) {
|
||||||
|
Ok(obj) => obj,
|
||||||
|
_ => {
|
||||||
|
data.fatal_event(display.invalid_object(obj_id));
|
||||||
|
return Err(ClientError::InvalidObject(obj_id));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// log::trace!("obj: {}, request: {}, len: {}", obj_id, request, len);
|
||||||
|
if request >= obj.num_requests() {
|
||||||
|
data.invalid_request(&*obj, request);
|
||||||
|
return Err(ClientError::InvalidMethod);
|
||||||
|
}
|
||||||
|
if len < 8 {
|
||||||
|
return Err(ClientError::MessageSizeTooSmall);
|
||||||
|
}
|
||||||
|
if len % 4 != 0 {
|
||||||
|
return Err(ClientError::UnalignedMessage);
|
||||||
|
}
|
||||||
|
let len = len / 4 - 2;
|
||||||
|
data_buf.clear();
|
||||||
|
data_buf.reserve(len);
|
||||||
|
let unused = data_buf.split_at_spare_mut_ext().1;
|
||||||
|
buf.read_full(&mut unused[..len]).await?;
|
||||||
|
unsafe {
|
||||||
|
data_buf.set_len(len);
|
||||||
|
}
|
||||||
|
// log::trace!("{:x?}", data_buf);
|
||||||
|
let parser = WlParser::new(&mut buf, &data_buf[..]);
|
||||||
|
if let Err(e) = obj.handle_request(request, parser).await {
|
||||||
|
return Err(ClientError::RequestError(Box::new(e)));
|
||||||
|
}
|
||||||
|
data.event2(WlEvent::Flush).await?;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let res: Result<(), ClientError> = recv.await;
|
||||||
|
if let Err(e) = res {
|
||||||
|
if e.peer_closed() {
|
||||||
|
log::info!("Client {} terminated the connection", data.id.0);
|
||||||
|
data.state.clients.kill(data.id);
|
||||||
|
} else {
|
||||||
|
let e = anyhow!(e);
|
||||||
|
log::error!(
|
||||||
|
"An error occurred while trying to handle a message from client {}: {:#}",
|
||||||
|
data.id.0,
|
||||||
|
e
|
||||||
|
);
|
||||||
|
if !data.shutdown_sent.get() {
|
||||||
|
data.fatal_event(display.implementation_error(format!("{:#}", e)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn send(data: Rc<Client>) {
|
||||||
|
let send = async {
|
||||||
|
let mut buf = BufFdOut::new(data.socket.clone());
|
||||||
|
let mut flush_requested = false;
|
||||||
|
loop {
|
||||||
|
let mut event = data.events.pop().await;
|
||||||
|
loop {
|
||||||
|
match event {
|
||||||
|
WlEvent::Flush => {
|
||||||
|
flush_requested = true;
|
||||||
|
}
|
||||||
|
WlEvent::Shutdown => {
|
||||||
|
buf.flush().await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
WlEvent::Event(e) => {
|
||||||
|
if log::log_enabled!(log::Level::Trace) {
|
||||||
|
let obj = e.obj();
|
||||||
|
log::trace!(
|
||||||
|
"Client {} <= {}@{}.{:?}",
|
||||||
|
data.id,
|
||||||
|
obj.interface().name(),
|
||||||
|
obj.id(),
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
e.format(&mut WlFormatter::new(&mut buf));
|
||||||
|
if buf.needs_flush() {
|
||||||
|
buf.flush().await?;
|
||||||
|
flush_requested = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
event = match data.events.try_pop() {
|
||||||
|
Some(e) => e,
|
||||||
|
_ => break,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if mem::take(&mut flush_requested) {
|
||||||
|
buf.flush().await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let res: Result<(), ClientError> = send.await;
|
||||||
|
if let Err(e) = res {
|
||||||
|
if e.peer_closed() {
|
||||||
|
log::info!("Client {} terminated the connection", data.id.0);
|
||||||
|
} else {
|
||||||
|
log::error!(
|
||||||
|
"An error occurred while sending data to client {}: {:#}",
|
||||||
|
data.id.0,
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data.state.clients.kill(data.id);
|
||||||
|
}
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
|
use crate::client::{Client, ClientError, DynEventFormatter};
|
||||||
use crate::ifs::wl_compositor::WlCompositorError;
|
use crate::ifs::wl_compositor::WlCompositorError;
|
||||||
use crate::ifs::wl_registry::WlRegistry;
|
use crate::ifs::wl_registry::WlRegistry;
|
||||||
use crate::ifs::wl_shm::WlShmError;
|
use crate::ifs::wl_shm::WlShmError;
|
||||||
use crate::ifs::wl_subcompositor::WlSubcompositorError;
|
use crate::ifs::wl_subcompositor::WlSubcompositorError;
|
||||||
use crate::ifs::xdg_wm_base::XdgWmBaseError;
|
use crate::ifs::xdg_wm_base::XdgWmBaseError;
|
||||||
use crate::objects::{Interface, ObjectId};
|
use crate::object::{Interface, ObjectId};
|
||||||
use crate::utils::copyhashmap::CopyHashMap;
|
use crate::utils::copyhashmap::CopyHashMap;
|
||||||
use crate::wl_client::{DynEventFormatter, WlClientData, WlClientError};
|
|
||||||
use crate::{NumCell, State};
|
use crate::{NumCell, State};
|
||||||
use ahash::AHashSet;
|
use ahash::AHashSet;
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
|
|
@ -19,7 +19,7 @@ pub enum GlobalError {
|
||||||
#[error("The requested global {0} does not exist")]
|
#[error("The requested global {0} does not exist")]
|
||||||
GlobalDoesNotExist(GlobalName),
|
GlobalDoesNotExist(GlobalName),
|
||||||
#[error("An error occurred while trying to send all globals via a new registry")]
|
#[error("An error occurred while trying to send all globals via a new registry")]
|
||||||
SendAllError(#[source] Box<WlClientError>),
|
SendAllError(#[source] Box<ClientError>),
|
||||||
#[error("An error occurred in a wl_compositor")]
|
#[error("An error occurred in a wl_compositor")]
|
||||||
WlCompositorError(#[source] Box<WlCompositorError>),
|
WlCompositorError(#[source] Box<WlCompositorError>),
|
||||||
#[error("An error occurred in a wl_shm")]
|
#[error("An error occurred in a wl_shm")]
|
||||||
|
|
@ -57,7 +57,7 @@ impl Display for GlobalName {
|
||||||
pub trait GlobalBind {
|
pub trait GlobalBind {
|
||||||
fn bind<'a>(
|
fn bind<'a>(
|
||||||
self: Rc<Self>,
|
self: Rc<Self>,
|
||||||
client: &'a Rc<WlClientData>,
|
client: &'a Rc<Client>,
|
||||||
id: ObjectId,
|
id: ObjectId,
|
||||||
version: u32,
|
version: u32,
|
||||||
) -> Pin<Box<dyn Future<Output = Result<(), GlobalError>> + 'a>>;
|
) -> Pin<Box<dyn Future<Output = Result<(), GlobalError>> + 'a>>;
|
||||||
|
|
@ -121,7 +121,7 @@ impl Globals {
|
||||||
|
|
||||||
pub async fn notify_all(
|
pub async fn notify_all(
|
||||||
&self,
|
&self,
|
||||||
client: &WlClientData,
|
client: &Client,
|
||||||
registry: &Rc<WlRegistry>,
|
registry: &Rc<WlRegistry>,
|
||||||
) -> Result<(), GlobalError> {
|
) -> Result<(), GlobalError> {
|
||||||
let globals = self.registry.lock();
|
let globals = self.registry.lock();
|
||||||
|
|
@ -136,7 +136,7 @@ impl Globals {
|
||||||
async fn broadcast<F: Fn(&Rc<WlRegistry>) -> DynEventFormatter>(&self, state: &State, f: F) {
|
async fn broadcast<F: Fn(&Rc<WlRegistry>) -> DynEventFormatter>(&self, state: &State, f: F) {
|
||||||
let mut clients_to_check = AHashSet::new();
|
let mut clients_to_check = AHashSet::new();
|
||||||
state.clients.broadcast(|c| {
|
state.clients.broadcast(|c| {
|
||||||
let registries = c.objects.registries();
|
let registries = c.lock_registries();
|
||||||
for registry in registries.values() {
|
for registry in registries.values() {
|
||||||
if c.event_locked(f(registry)) {
|
if c.event_locked(f(registry)) {
|
||||||
clients_to_check.insert(c.id);
|
clients_to_check.insert(c.id);
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
mod types;
|
mod types;
|
||||||
|
|
||||||
use crate::objects::{Interface, Object, ObjectError, ObjectId};
|
use crate::client::{ClientError, DynEventFormatter};
|
||||||
|
use crate::object::{Interface, Object, ObjectId};
|
||||||
use crate::utils::buffd::WlParser;
|
use crate::utils::buffd::WlParser;
|
||||||
use crate::wl_client::DynEventFormatter;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use types::*;
|
use types::*;
|
||||||
|
|
||||||
|
|
@ -25,7 +25,7 @@ impl WlCallback {
|
||||||
&self,
|
&self,
|
||||||
_request: u32,
|
_request: u32,
|
||||||
_parser: WlParser<'_, '_>,
|
_parser: WlParser<'_, '_>,
|
||||||
) -> Result<(), ObjectError> {
|
) -> Result<(), ClientError> {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
|
use crate::client::EventFormatter;
|
||||||
use crate::ifs::wl_callback::{WlCallback, DONE};
|
use crate::ifs::wl_callback::{WlCallback, DONE};
|
||||||
use crate::objects::Object;
|
use crate::object::Object;
|
||||||
use crate::utils::buffd::WlFormatter;
|
use crate::utils::buffd::WlFormatter;
|
||||||
use crate::wl_client::EventFormatter;
|
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::{Debug, Formatter};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
mod types;
|
mod types;
|
||||||
|
|
||||||
|
use crate::client::{AddObj, Client};
|
||||||
use crate::globals::{Global, GlobalName};
|
use crate::globals::{Global, GlobalName};
|
||||||
|
use crate::ifs::wl_region::WlRegion;
|
||||||
use crate::ifs::wl_surface::WlSurface;
|
use crate::ifs::wl_surface::WlSurface;
|
||||||
use crate::objects::{Interface, Object, ObjectId};
|
use crate::object::{Interface, Object, ObjectId};
|
||||||
use crate::utils::buffd::WlParser;
|
use crate::utils::buffd::WlParser;
|
||||||
use crate::wl_client::WlClientData;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
pub use types::*;
|
pub use types::*;
|
||||||
use crate::ifs::wl_region::WlRegion;
|
|
||||||
|
|
||||||
const CREATE_SURFACE: u32 = 0;
|
const CREATE_SURFACE: u32 = 0;
|
||||||
const CREATE_REGION: u32 = 1;
|
const CREATE_REGION: u32 = 1;
|
||||||
|
|
@ -19,7 +19,7 @@ pub struct WlCompositorGlobal {
|
||||||
pub struct WlCompositorObj {
|
pub struct WlCompositorObj {
|
||||||
global: Rc<WlCompositorGlobal>,
|
global: Rc<WlCompositorGlobal>,
|
||||||
id: ObjectId,
|
id: ObjectId,
|
||||||
client: Rc<WlClientData>,
|
client: Rc<Client>,
|
||||||
version: u32,
|
version: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -31,7 +31,7 @@ impl WlCompositorGlobal {
|
||||||
async fn bind_(
|
async fn bind_(
|
||||||
self: Rc<Self>,
|
self: Rc<Self>,
|
||||||
id: ObjectId,
|
id: ObjectId,
|
||||||
client: &Rc<WlClientData>,
|
client: &Rc<Client>,
|
||||||
version: u32,
|
version: u32,
|
||||||
) -> Result<(), WlCompositorError> {
|
) -> Result<(), WlCompositorError> {
|
||||||
let obj = Rc::new(WlCompositorObj {
|
let obj = Rc::new(WlCompositorObj {
|
||||||
|
|
@ -40,7 +40,7 @@ impl WlCompositorGlobal {
|
||||||
client: client.clone(),
|
client: client.clone(),
|
||||||
version,
|
version,
|
||||||
});
|
});
|
||||||
client.attach_client_object(obj)?;
|
client.add_client_obj(&obj)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -49,14 +49,14 @@ impl WlCompositorObj {
|
||||||
async fn create_surface(&self, parser: WlParser<'_, '_>) -> Result<(), CreateSurfaceError> {
|
async fn create_surface(&self, parser: WlParser<'_, '_>) -> Result<(), CreateSurfaceError> {
|
||||||
let surface: CreateSurface = self.client.parse(self, parser)?;
|
let surface: CreateSurface = self.client.parse(self, parser)?;
|
||||||
let surface = Rc::new(WlSurface::new(surface.id, &self.client));
|
let surface = Rc::new(WlSurface::new(surface.id, &self.client));
|
||||||
self.client.attach_client_object(surface)?;
|
self.client.add_client_obj(&surface)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn create_region(&self, parser: WlParser<'_, '_>) -> Result<(), CreateRegionError> {
|
async fn create_region(&self, parser: WlParser<'_, '_>) -> Result<(), CreateRegionError> {
|
||||||
let region: CreateRegion = self.client.parse(self, parser)?;
|
let region: CreateRegion = self.client.parse(self, parser)?;
|
||||||
let region = Rc::new(WlRegion::new(region.id, &self.client));
|
let region = Rc::new(WlRegion::new(region.id, &self.client));
|
||||||
self.client.attach_client_object(region)?;
|
self.client.add_client_obj(®ion)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,20 @@
|
||||||
use crate::objects::{ObjectError, ObjectId};
|
use crate::client::{ClientError, RequestParser};
|
||||||
|
use crate::object::ObjectId;
|
||||||
use crate::utils::buffd::{WlParser, WlParserError};
|
use crate::utils::buffd::{WlParser, WlParserError};
|
||||||
use crate::wl_client::{RequestParser, WlClientError};
|
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::{Debug, Formatter};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum WlCompositorError {
|
pub enum WlCompositorError {
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
ObjectError(Box<ObjectError>),
|
ClientError(Box<ClientError>),
|
||||||
#[error(transparent)]
|
|
||||||
ClientError(Box<WlClientError>),
|
|
||||||
#[error("Could not process `create_surface` request")]
|
#[error("Could not process `create_surface` request")]
|
||||||
CreateSurfaceError(#[source] Box<CreateSurfaceError>),
|
CreateSurfaceError(#[source] Box<CreateSurfaceError>),
|
||||||
#[error("Could not process `create_region` request")]
|
#[error("Could not process `create_region` request")]
|
||||||
CreateRegionError(#[source] Box<CreateRegionError>),
|
CreateRegionError(#[source] Box<CreateRegionError>),
|
||||||
}
|
}
|
||||||
|
|
||||||
efrom!(WlCompositorError, ObjectError, ObjectError);
|
efrom!(WlCompositorError, ClientError, ClientError);
|
||||||
efrom!(WlCompositorError, ClientError, WlClientError);
|
|
||||||
efrom!(WlCompositorError, CreateSurfaceError, CreateSurfaceError);
|
efrom!(WlCompositorError, CreateSurfaceError, CreateSurfaceError);
|
||||||
efrom!(WlCompositorError, CreateRegionError, CreateRegionError);
|
efrom!(WlCompositorError, CreateRegionError, CreateRegionError);
|
||||||
|
|
||||||
|
|
@ -26,22 +23,22 @@ pub enum CreateSurfaceError {
|
||||||
#[error("Parsing failed")]
|
#[error("Parsing failed")]
|
||||||
ParseFailed(#[source] Box<WlParserError>),
|
ParseFailed(#[source] Box<WlParserError>),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
ClientError(Box<WlClientError>),
|
ClientError(Box<ClientError>),
|
||||||
}
|
}
|
||||||
|
|
||||||
efrom!(CreateSurfaceError, ParseFailed, WlParserError);
|
efrom!(CreateSurfaceError, ParseFailed, WlParserError);
|
||||||
efrom!(CreateSurfaceError, ClientError, WlClientError);
|
efrom!(CreateSurfaceError, ClientError, ClientError);
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum CreateRegionError {
|
pub enum CreateRegionError {
|
||||||
#[error("Parsing failed")]
|
#[error("Parsing failed")]
|
||||||
ParseFailed(#[source] Box<WlParserError>),
|
ParseFailed(#[source] Box<WlParserError>),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
ClientError(Box<WlClientError>),
|
ClientError(Box<ClientError>),
|
||||||
}
|
}
|
||||||
|
|
||||||
efrom!(CreateRegionError, ParseFailed, WlParserError);
|
efrom!(CreateRegionError, ParseFailed, WlParserError);
|
||||||
efrom!(CreateRegionError, ClientError, WlClientError);
|
efrom!(CreateRegionError, ClientError, ClientError);
|
||||||
|
|
||||||
pub(super) struct CreateSurface {
|
pub(super) struct CreateSurface {
|
||||||
pub id: ObjectId,
|
pub id: ObjectId,
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
mod types;
|
mod types;
|
||||||
|
|
||||||
|
use crate::client::{AddObj, Client, ClientError, DynEventFormatter};
|
||||||
use crate::ifs::wl_callback::WlCallback;
|
use crate::ifs::wl_callback::WlCallback;
|
||||||
use crate::ifs::wl_registry::WlRegistry;
|
use crate::ifs::wl_registry::WlRegistry;
|
||||||
use crate::objects::{Interface, Object, ObjectError, ObjectId, WL_DISPLAY_ID};
|
use crate::object::{Interface, Object, ObjectId, WL_DISPLAY_ID};
|
||||||
use crate::utils::buffd::WlParser;
|
use crate::utils::buffd::WlParser;
|
||||||
use crate::wl_client::{DynEventFormatter, WlClientData};
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
pub use types::*;
|
pub use types::*;
|
||||||
|
|
||||||
|
|
@ -20,11 +20,11 @@ const NO_MEMORY: u32 = 2;
|
||||||
const IMPLEMENTATION: u32 = 3;
|
const IMPLEMENTATION: u32 = 3;
|
||||||
|
|
||||||
pub struct WlDisplay {
|
pub struct WlDisplay {
|
||||||
client: Rc<WlClientData>,
|
client: Rc<Client>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WlDisplay {
|
impl WlDisplay {
|
||||||
pub fn new(client: &Rc<WlClientData>) -> Self {
|
pub fn new(client: &Rc<Client>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
client: client.clone(),
|
client: client.clone(),
|
||||||
}
|
}
|
||||||
|
|
@ -46,19 +46,16 @@ impl WlDisplay {
|
||||||
async fn sync(&self, parser: WlParser<'_, '_>) -> Result<(), SyncError> {
|
async fn sync(&self, parser: WlParser<'_, '_>) -> Result<(), SyncError> {
|
||||||
let sync: Sync = self.client.parse(self, parser)?;
|
let sync: Sync = self.client.parse(self, parser)?;
|
||||||
let cb = Rc::new(WlCallback::new(sync.callback));
|
let cb = Rc::new(WlCallback::new(sync.callback));
|
||||||
self.client.attach_client_object(cb.clone())?;
|
self.client.add_client_obj(&cb)?;
|
||||||
self.client.event(cb.done()).await?;
|
self.client.event(cb.done()).await?;
|
||||||
self.client
|
self.client.remove_obj(&*cb).await?;
|
||||||
.objects
|
|
||||||
.remove_obj(&self.client, cb.id())
|
|
||||||
.await?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_registry(&self, parser: WlParser<'_, '_>) -> Result<(), GetRegistryError> {
|
async fn get_registry(&self, parser: WlParser<'_, '_>) -> Result<(), GetRegistryError> {
|
||||||
let gr: GetRegistry = self.client.parse(self, parser)?;
|
let gr: GetRegistry = self.client.parse(self, parser)?;
|
||||||
let registry = Rc::new(WlRegistry::new(gr.registry, &self.client));
|
let registry = Rc::new(WlRegistry::new(gr.registry, &self.client));
|
||||||
self.client.attach_client_object(registry.clone())?;
|
self.client.add_client_obj(®istry)?;
|
||||||
self.client
|
self.client
|
||||||
.state
|
.state
|
||||||
.globals
|
.globals
|
||||||
|
|
@ -124,7 +121,7 @@ impl Object for WlDisplay {
|
||||||
GET_REGISTRY + 1
|
GET_REGISTRY + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_display(self: Rc<Self>) -> Result<Rc<WlDisplay>, ObjectError> {
|
fn into_display(self: Rc<Self>) -> Result<Rc<WlDisplay>, ClientError> {
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
|
use crate::client::{ClientError, EventFormatter, RequestParser};
|
||||||
use crate::globals::GlobalError;
|
use crate::globals::GlobalError;
|
||||||
use crate::ifs::wl_display::{WlDisplay, DELETE_ID, ERROR};
|
use crate::ifs::wl_display::{WlDisplay, DELETE_ID, ERROR};
|
||||||
use crate::objects::{Object, ObjectError, ObjectId, WL_DISPLAY_ID};
|
use crate::object::{Object, ObjectId, WL_DISPLAY_ID};
|
||||||
use crate::utils::buffd::{WlFormatter, WlParser, WlParserError};
|
use crate::utils::buffd::{WlFormatter, WlParser, WlParserError};
|
||||||
use crate::wl_client::{EventFormatter, RequestParser, WlClientError};
|
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::{Debug, Formatter};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
@ -22,32 +22,26 @@ efrom!(WlDisplayError, SyncError, SyncError);
|
||||||
pub enum GetRegistryError {
|
pub enum GetRegistryError {
|
||||||
#[error("Parsing failed")]
|
#[error("Parsing failed")]
|
||||||
ParseFailed(#[source] Box<WlParserError>),
|
ParseFailed(#[source] Box<WlParserError>),
|
||||||
#[error("An object error occurred")]
|
#[error(transparent)]
|
||||||
ObjectError(#[source] Box<ObjectError>),
|
ClientError(Box<ClientError>),
|
||||||
#[error("An object error occurred")]
|
|
||||||
ClientError(#[source] Box<WlClientError>),
|
|
||||||
#[error("An error occurred while processing globals")]
|
#[error("An error occurred while processing globals")]
|
||||||
GlobalError(#[source] Box<GlobalError>),
|
GlobalError(#[source] Box<GlobalError>),
|
||||||
}
|
}
|
||||||
|
|
||||||
efrom!(GetRegistryError, ParseFailed, WlParserError);
|
efrom!(GetRegistryError, ParseFailed, WlParserError);
|
||||||
efrom!(GetRegistryError, ObjectError, ObjectError);
|
|
||||||
efrom!(GetRegistryError, GlobalError, GlobalError);
|
efrom!(GetRegistryError, GlobalError, GlobalError);
|
||||||
efrom!(GetRegistryError, ClientError, WlClientError);
|
efrom!(GetRegistryError, ClientError, ClientError);
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum SyncError {
|
pub enum SyncError {
|
||||||
#[error("Parsing failed")]
|
#[error("Parsing failed")]
|
||||||
ParseFailed(#[source] Box<WlParserError>),
|
ParseFailed(#[source] Box<WlParserError>),
|
||||||
#[error("An object error occurred")]
|
#[error(transparent)]
|
||||||
ObjectError(#[source] Box<ObjectError>),
|
ClientError(Box<ClientError>),
|
||||||
#[error("A client error occurred")]
|
|
||||||
ClientError(#[source] Box<WlClientError>),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
efrom!(SyncError, ParseFailed, WlParserError);
|
efrom!(SyncError, ParseFailed, WlParserError);
|
||||||
efrom!(SyncError, ObjectError, ObjectError);
|
efrom!(SyncError, ClientError, ClientError);
|
||||||
efrom!(SyncError, ClientError, WlClientError);
|
|
||||||
|
|
||||||
pub(super) struct GetRegistry {
|
pub(super) struct GetRegistry {
|
||||||
pub registry: ObjectId,
|
pub registry: ObjectId,
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,12 @@
|
||||||
mod types;
|
mod types;
|
||||||
|
|
||||||
use crate::objects::{Interface, Object, ObjectError, ObjectId};
|
use crate::client::{AddObj, Client};
|
||||||
|
use crate::object::{Interface, Object, ObjectId};
|
||||||
use crate::pixman::Region;
|
use crate::pixman::Region;
|
||||||
use crate::utils::buffd::{WlParser, WlParserError};
|
use crate::utils::buffd::WlParser;
|
||||||
use crate::wl_client::{RequestParser, WlClientData};
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
pub use types::*;
|
pub use types::*;
|
||||||
use crate::ifs::wl_display::WlDisplay;
|
|
||||||
|
|
||||||
const DESTROY: u32 = 0;
|
const DESTROY: u32 = 0;
|
||||||
const ADD: u32 = 1;
|
const ADD: u32 = 1;
|
||||||
|
|
@ -15,12 +14,12 @@ const SUBTRACT: u32 = 2;
|
||||||
|
|
||||||
pub struct WlRegion {
|
pub struct WlRegion {
|
||||||
id: ObjectId,
|
id: ObjectId,
|
||||||
client: Rc<WlClientData>,
|
client: Rc<Client>,
|
||||||
rect: RefCell<Region>,
|
rect: RefCell<Region>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WlRegion {
|
impl WlRegion {
|
||||||
pub fn new(id: ObjectId, client: &Rc<WlClientData>) -> Self {
|
pub fn new(id: ObjectId, client: &Rc<Client>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id,
|
id,
|
||||||
client: client.clone(),
|
client: client.clone(),
|
||||||
|
|
@ -34,7 +33,7 @@ impl WlRegion {
|
||||||
|
|
||||||
async fn destroy(&self, parser: WlParser<'_, '_>) -> Result<(), DestroyError> {
|
async fn destroy(&self, parser: WlParser<'_, '_>) -> Result<(), DestroyError> {
|
||||||
let _destroy: Destroy = self.client.parse(self, parser)?;
|
let _destroy: Destroy = self.client.parse(self, parser)?;
|
||||||
self.client.objects.remove_obj(&self.client, self.id).await?;
|
self.client.remove_obj(self).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -92,13 +91,4 @@ impl Object for WlRegion {
|
||||||
fn num_requests(&self) -> u32 {
|
fn num_requests(&self) -> u32 {
|
||||||
SUBTRACT + 1
|
SUBTRACT + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn post_attach(self: Rc<Self>) {
|
|
||||||
self.client.objects.regions.set(self.id, self.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pre_release(&self) -> Result<(), ObjectError> {
|
|
||||||
self.client.objects.regions.remove(&self.id);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
use crate::objects::{ObjectError, ObjectId};
|
use crate::client::{ClientError, RequestParser};
|
||||||
use crate::utils::buffd::{WlParser, WlParserError};
|
use crate::utils::buffd::{WlParser, WlParserError};
|
||||||
use crate::wl_client::RequestParser;
|
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::{Debug, Formatter};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
|
@ -19,10 +18,10 @@ pub enum DestroyError {
|
||||||
#[error("Parsing failed")]
|
#[error("Parsing failed")]
|
||||||
ParseFailed(#[source] Box<WlParserError>),
|
ParseFailed(#[source] Box<WlParserError>),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
ObjectError(Box<ObjectError>),
|
ClientError(Box<ClientError>),
|
||||||
}
|
}
|
||||||
efrom!(DestroyError, ParseFailed, WlParserError);
|
efrom!(DestroyError, ParseFailed, WlParserError);
|
||||||
efrom!(DestroyError, ObjectError, ObjectError);
|
efrom!(DestroyError, ClientError, ClientError);
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum AddError {
|
pub enum AddError {
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
mod types;
|
mod types;
|
||||||
|
|
||||||
|
use crate::client::{Client, DynEventFormatter};
|
||||||
use crate::globals::{Global, GlobalName};
|
use crate::globals::{Global, GlobalName};
|
||||||
use crate::objects::{Interface, Object, ObjectId};
|
use crate::object::{Interface, Object, ObjectId};
|
||||||
use crate::utils::buffd::WlParser;
|
use crate::utils::buffd::WlParser;
|
||||||
use crate::wl_client::{DynEventFormatter, WlClientData};
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
pub use types::*;
|
pub use types::*;
|
||||||
|
|
||||||
|
|
@ -14,11 +14,11 @@ const GLOBAL_REMOVE: u32 = 1;
|
||||||
|
|
||||||
pub struct WlRegistry {
|
pub struct WlRegistry {
|
||||||
id: ObjectId,
|
id: ObjectId,
|
||||||
client: Rc<WlClientData>,
|
client: Rc<Client>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WlRegistry {
|
impl WlRegistry {
|
||||||
pub fn new(id: ObjectId, client: &Rc<WlClientData>) -> Self {
|
pub fn new(id: ObjectId, client: &Rc<Client>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id,
|
id,
|
||||||
client: client.clone(),
|
client: client.clone(),
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
|
use crate::client::{EventFormatter, RequestParser};
|
||||||
use crate::globals::{Global, GlobalError, GlobalName};
|
use crate::globals::{Global, GlobalError, GlobalName};
|
||||||
use crate::ifs::wl_registry::{WlRegistry, GLOBAL, GLOBAL_REMOVE};
|
use crate::ifs::wl_registry::{WlRegistry, GLOBAL, GLOBAL_REMOVE};
|
||||||
use crate::objects::{Interface, Object, ObjectId};
|
use crate::object::{Interface, Object, ObjectId};
|
||||||
use crate::utils::buffd::{WlFormatter, WlParser, WlParserError};
|
use crate::utils::buffd::{WlFormatter, WlParser, WlParserError};
|
||||||
use crate::wl_client::{EventFormatter, RequestParser};
|
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::{Debug, Formatter};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
mod types;
|
mod types;
|
||||||
|
|
||||||
|
use crate::client::{AddObj, Client};
|
||||||
use crate::globals::{Global, GlobalName};
|
use crate::globals::{Global, GlobalName};
|
||||||
use crate::ifs::wl_shm_pool::WlShmPool;
|
use crate::ifs::wl_shm_pool::WlShmPool;
|
||||||
use crate::objects::{Interface, Object, ObjectId};
|
use crate::object::{Interface, Object, ObjectId};
|
||||||
use crate::utils::buffd::WlParser;
|
use crate::utils::buffd::WlParser;
|
||||||
use crate::wl_client::WlClientData;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
pub use types::*;
|
pub use types::*;
|
||||||
|
|
||||||
|
|
@ -19,7 +19,7 @@ pub struct WlShmGlobal {
|
||||||
pub struct WlShmObj {
|
pub struct WlShmObj {
|
||||||
global: Rc<WlShmGlobal>,
|
global: Rc<WlShmGlobal>,
|
||||||
id: ObjectId,
|
id: ObjectId,
|
||||||
client: Rc<WlClientData>,
|
client: Rc<Client>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WlShmGlobal {
|
impl WlShmGlobal {
|
||||||
|
|
@ -30,7 +30,7 @@ impl WlShmGlobal {
|
||||||
async fn bind_(
|
async fn bind_(
|
||||||
self: Rc<Self>,
|
self: Rc<Self>,
|
||||||
id: ObjectId,
|
id: ObjectId,
|
||||||
client: &Rc<WlClientData>,
|
client: &Rc<Client>,
|
||||||
_version: u32,
|
_version: u32,
|
||||||
) -> Result<(), WlShmError> {
|
) -> Result<(), WlShmError> {
|
||||||
let obj = Rc::new(WlShmObj {
|
let obj = Rc::new(WlShmObj {
|
||||||
|
|
@ -38,7 +38,7 @@ impl WlShmGlobal {
|
||||||
id,
|
id,
|
||||||
client: client.clone(),
|
client: client.clone(),
|
||||||
});
|
});
|
||||||
client.attach_client_object(obj.clone())?;
|
client.add_client_obj(&obj)?;
|
||||||
for &format in Format::formats() {
|
for &format in Format::formats() {
|
||||||
client
|
client
|
||||||
.event(Box::new(FormatE {
|
.event(Box::new(FormatE {
|
||||||
|
|
@ -63,7 +63,7 @@ impl WlShmObj {
|
||||||
create.fd,
|
create.fd,
|
||||||
create.size as usize,
|
create.size as usize,
|
||||||
)?);
|
)?);
|
||||||
self.client.attach_client_object(pool)?;
|
self.client.add_client_obj(&pool)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
|
use crate::client::{ClientError, EventFormatter, RequestParser};
|
||||||
use crate::ifs::wl_shm::{Format, WlShmObj, FORMAT};
|
use crate::ifs::wl_shm::{Format, WlShmObj, FORMAT};
|
||||||
use crate::ifs::wl_shm_pool::WlShmPoolError;
|
use crate::ifs::wl_shm_pool::WlShmPoolError;
|
||||||
use crate::objects::{Object, ObjectError, ObjectId};
|
use crate::object::{Object, ObjectId};
|
||||||
use crate::utils::buffd::{WlFormatter, WlParser, WlParserError};
|
use crate::utils::buffd::{WlFormatter, WlParser, WlParserError};
|
||||||
use crate::wl_client::{EventFormatter, RequestParser, WlClientError};
|
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::{Debug, Formatter};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
@ -11,14 +11,11 @@ use uapi::OwnedFd;
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum WlShmError {
|
pub enum WlShmError {
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
ObjectError(Box<ObjectError>),
|
ClientError(Box<ClientError>),
|
||||||
#[error(transparent)]
|
|
||||||
ClientError(Box<WlClientError>),
|
|
||||||
#[error("Could not process a `create_pool` request")]
|
#[error("Could not process a `create_pool` request")]
|
||||||
CreatePoolError(#[from] CreatePoolError),
|
CreatePoolError(#[from] CreatePoolError),
|
||||||
}
|
}
|
||||||
efrom!(WlShmError, ObjectError, ObjectError);
|
efrom!(WlShmError, ClientError, ClientError);
|
||||||
efrom!(WlShmError, ClientError, WlClientError);
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum CreatePoolError {
|
pub enum CreatePoolError {
|
||||||
|
|
@ -29,11 +26,11 @@ pub enum CreatePoolError {
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
WlShmPoolError(Box<WlShmPoolError>),
|
WlShmPoolError(Box<WlShmPoolError>),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
ClientError(Box<WlClientError>),
|
ClientError(Box<ClientError>),
|
||||||
}
|
}
|
||||||
efrom!(CreatePoolError, ParseError, WlParserError);
|
efrom!(CreatePoolError, ParseError, WlParserError);
|
||||||
efrom!(CreatePoolError, WlShmPoolError, WlShmPoolError);
|
efrom!(CreatePoolError, WlShmPoolError, WlShmPoolError);
|
||||||
efrom!(CreatePoolError, ClientError, WlClientError);
|
efrom!(CreatePoolError, ClientError, ClientError);
|
||||||
|
|
||||||
pub(super) struct CreatePool {
|
pub(super) struct CreatePool {
|
||||||
pub id: ObjectId,
|
pub id: ObjectId,
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
mod types;
|
mod types;
|
||||||
|
|
||||||
|
use crate::client::{AddObj, Client};
|
||||||
use crate::clientmem::ClientMem;
|
use crate::clientmem::ClientMem;
|
||||||
use crate::objects::{Interface, Object, ObjectId};
|
use crate::object::{Interface, Object, ObjectId};
|
||||||
use crate::utils::buffd::WlParser;
|
use crate::utils::buffd::WlParser;
|
||||||
use crate::wl_client::WlClientData;
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
pub use types::*;
|
pub use types::*;
|
||||||
|
|
@ -15,7 +15,7 @@ const RESIZE: u32 = 2;
|
||||||
|
|
||||||
pub struct WlShmPool {
|
pub struct WlShmPool {
|
||||||
id: ObjectId,
|
id: ObjectId,
|
||||||
client: Rc<WlClientData>,
|
client: Rc<Client>,
|
||||||
fd: OwnedFd,
|
fd: OwnedFd,
|
||||||
mem: RefCell<Rc<ClientMem>>,
|
mem: RefCell<Rc<ClientMem>>,
|
||||||
}
|
}
|
||||||
|
|
@ -23,7 +23,7 @@ pub struct WlShmPool {
|
||||||
impl WlShmPool {
|
impl WlShmPool {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
id: ObjectId,
|
id: ObjectId,
|
||||||
client: &Rc<WlClientData>,
|
client: &Rc<Client>,
|
||||||
fd: OwnedFd,
|
fd: OwnedFd,
|
||||||
len: usize,
|
len: usize,
|
||||||
) -> Result<Self, WlShmPoolError> {
|
) -> Result<Self, WlShmPoolError> {
|
||||||
|
|
@ -42,10 +42,7 @@ impl WlShmPool {
|
||||||
|
|
||||||
async fn destroy(&self, parser: WlParser<'_, '_>) -> Result<(), DestroyError> {
|
async fn destroy(&self, parser: WlParser<'_, '_>) -> Result<(), DestroyError> {
|
||||||
let _destroy: Destroy = self.client.parse(self, parser)?;
|
let _destroy: Destroy = self.client.parse(self, parser)?;
|
||||||
self.client
|
self.client.remove_obj(self).await?;
|
||||||
.objects
|
|
||||||
.remove_obj(&self.client, self.id)
|
|
||||||
.await?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,14 @@
|
||||||
|
use crate::client::{ClientError, RequestParser};
|
||||||
use crate::clientmem::ClientMemError;
|
use crate::clientmem::ClientMemError;
|
||||||
use crate::objects::{ObjectError, ObjectId};
|
use crate::object::ObjectId;
|
||||||
use crate::utils::buffd::{WlParser, WlParserError};
|
use crate::utils::buffd::{WlParser, WlParserError};
|
||||||
use crate::wl_client::{RequestParser, WlClientError};
|
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::{Debug, Formatter};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum WlShmPoolError {
|
pub enum WlShmPoolError {
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
ObjectError(Box<ObjectError>),
|
ClientError(Box<ClientError>),
|
||||||
#[error(transparent)]
|
|
||||||
ClientError(Box<WlClientError>),
|
|
||||||
#[error("Could not process a `create_buffer` request")]
|
#[error("Could not process a `create_buffer` request")]
|
||||||
CreateBufferError(#[from] CreateBufferError),
|
CreateBufferError(#[from] CreateBufferError),
|
||||||
#[error("Could not process a `destroy` request")]
|
#[error("Could not process a `destroy` request")]
|
||||||
|
|
@ -20,8 +18,7 @@ pub enum WlShmPoolError {
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
ClientMemError(Box<ClientMemError>),
|
ClientMemError(Box<ClientMemError>),
|
||||||
}
|
}
|
||||||
efrom!(WlShmPoolError, ObjectError, ObjectError);
|
efrom!(WlShmPoolError, ClientError, ClientError);
|
||||||
efrom!(WlShmPoolError, ClientError, WlClientError);
|
|
||||||
efrom!(WlShmPoolError, ClientMemError, ClientMemError);
|
efrom!(WlShmPoolError, ClientMemError, ClientMemError);
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
|
|
@ -29,20 +26,20 @@ pub enum CreateBufferError {
|
||||||
#[error("Parsing failed")]
|
#[error("Parsing failed")]
|
||||||
ParseError(#[source] Box<WlParserError>),
|
ParseError(#[source] Box<WlParserError>),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
ObjectError(Box<ObjectError>),
|
ClientError(Box<ClientError>),
|
||||||
}
|
}
|
||||||
efrom!(CreateBufferError, ParseError, WlParserError);
|
efrom!(CreateBufferError, ParseError, WlParserError);
|
||||||
efrom!(CreateBufferError, ObjectError, ObjectError);
|
efrom!(CreateBufferError, ClientError, ClientError);
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum DestroyError {
|
pub enum DestroyError {
|
||||||
#[error("Parsing failed")]
|
#[error("Parsing failed")]
|
||||||
ParseError(#[source] Box<WlParserError>),
|
ParseError(#[source] Box<WlParserError>),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
ObjectError(Box<ObjectError>),
|
ClientError(Box<ClientError>),
|
||||||
}
|
}
|
||||||
efrom!(DestroyError, ParseError, WlParserError);
|
efrom!(DestroyError, ParseError, WlParserError);
|
||||||
efrom!(DestroyError, ObjectError, ObjectError);
|
efrom!(DestroyError, ClientError, ClientError);
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum ResizeError {
|
pub enum ResizeError {
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
mod types;
|
mod types;
|
||||||
|
|
||||||
|
use crate::client::{AddObj, Client, ClientError};
|
||||||
use crate::globals::{Global, GlobalName};
|
use crate::globals::{Global, GlobalName};
|
||||||
use crate::objects::{Interface, Object, ObjectError, ObjectId};
|
use crate::object::{Interface, Object, ObjectId};
|
||||||
use crate::utils::buffd::WlParser;
|
use crate::utils::buffd::WlParser;
|
||||||
use crate::wl_client::WlClientData;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
pub use types::*;
|
pub use types::*;
|
||||||
|
|
||||||
|
|
@ -24,11 +24,11 @@ impl WlSubcompositorGlobal {
|
||||||
async fn bind_(
|
async fn bind_(
|
||||||
self: Rc<Self>,
|
self: Rc<Self>,
|
||||||
id: ObjectId,
|
id: ObjectId,
|
||||||
client: &WlClientData,
|
client: &Client,
|
||||||
_version: u32,
|
_version: u32,
|
||||||
) -> Result<(), WlSubcompositorError> {
|
) -> Result<(), WlSubcompositorError> {
|
||||||
let obj = Rc::new(WlSubcompositorObj { global: self, id });
|
let obj = Rc::new(WlSubcompositorObj { global: self, id });
|
||||||
client.attach_client_object(obj)?;
|
client.add_client_obj(&obj)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -38,7 +38,7 @@ impl WlSubcompositorObj {
|
||||||
&self,
|
&self,
|
||||||
request: u32,
|
request: u32,
|
||||||
parser: WlParser<'_, '_>,
|
parser: WlParser<'_, '_>,
|
||||||
) -> Result<(), ObjectError> {
|
) -> Result<(), ClientError> {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,10 @@
|
||||||
use crate::objects::ObjectError;
|
use crate::client::ClientError;
|
||||||
use crate::wl_client::WlClientError;
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum WlSubcompositorError {
|
pub enum WlSubcompositorError {
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
ObjectError(Box<ObjectError>),
|
ClientError(Box<ClientError>),
|
||||||
#[error(transparent)]
|
|
||||||
ClientError(Box<WlClientError>),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
efrom!(WlSubcompositorError, ObjectError, ObjectError);
|
efrom!(WlSubcompositorError, ClientError, ClientError);
|
||||||
efrom!(WlSubcompositorError, ClientError, WlClientError);
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
mod types;
|
mod types;
|
||||||
|
|
||||||
use std::cell::Cell;
|
use crate::client::{Client, RequestParser};
|
||||||
use crate::objects::{Interface, Object, ObjectError, ObjectId};
|
use crate::object::{Interface, Object, ObjectId};
|
||||||
|
use crate::pixman::Region;
|
||||||
use crate::utils::buffd::{WlParser, WlParserError};
|
use crate::utils::buffd::{WlParser, WlParserError};
|
||||||
use crate::wl_client::{RequestParser, WlClientData};
|
use std::cell::Cell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
pub use types::*;
|
pub use types::*;
|
||||||
use crate::pixman::Region;
|
|
||||||
|
|
||||||
const DESTROY: u32 = 0;
|
const DESTROY: u32 = 0;
|
||||||
const ATTACH: u32 = 1;
|
const ATTACH: u32 = 1;
|
||||||
|
|
@ -28,7 +28,7 @@ const INVALID_SIZE: u32 = 2;
|
||||||
|
|
||||||
pub struct WlSurface {
|
pub struct WlSurface {
|
||||||
id: ObjectId,
|
id: ObjectId,
|
||||||
client: Rc<WlClientData>,
|
client: Rc<Client>,
|
||||||
pending: PendingState,
|
pending: PendingState,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -39,7 +39,7 @@ struct PendingState {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WlSurface {
|
impl WlSurface {
|
||||||
pub fn new(id: ObjectId, client: &Rc<WlClientData>) -> Self {
|
pub fn new(id: ObjectId, client: &Rc<Client>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id,
|
id,
|
||||||
client: client.clone(),
|
client: client.clone(),
|
||||||
|
|
@ -150,13 +150,4 @@ impl Object for WlSurface {
|
||||||
fn num_requests(&self) -> u32 {
|
fn num_requests(&self) -> u32 {
|
||||||
DAMAGE_BUFFER + 1
|
DAMAGE_BUFFER + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pre_release(&self) -> Result<(), ObjectError> {
|
|
||||||
self.client.objects.surfaces.remove(&self.id);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn post_attach(self: Rc<Self>) {
|
|
||||||
self.client.objects.surfaces.set(self.id, self.clone());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::objects::ObjectId;
|
use crate::client::{ClientError, RequestParser};
|
||||||
|
use crate::object::ObjectId;
|
||||||
use crate::utils::buffd::{WlParser, WlParserError};
|
use crate::utils::buffd::{WlParser, WlParserError};
|
||||||
use crate::wl_client::{RequestParser, WlClientError};
|
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::{Debug, Formatter};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
|
@ -75,20 +75,20 @@ pub enum SetOpaqueRegionError {
|
||||||
#[error("Parsing failed")]
|
#[error("Parsing failed")]
|
||||||
ParseFailed(#[source] Box<WlParserError>),
|
ParseFailed(#[source] Box<WlParserError>),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
ClientError(Box<WlClientError>),
|
ClientError(Box<ClientError>),
|
||||||
}
|
}
|
||||||
efrom!(SetOpaqueRegionError, ParseFailed, WlParserError);
|
efrom!(SetOpaqueRegionError, ParseFailed, WlParserError);
|
||||||
efrom!(SetOpaqueRegionError, ClientError, WlClientError);
|
efrom!(SetOpaqueRegionError, ClientError, ClientError);
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum SetInputRegionError {
|
pub enum SetInputRegionError {
|
||||||
#[error("Parsing failed")]
|
#[error("Parsing failed")]
|
||||||
ParseFailed(#[source] Box<WlParserError>),
|
ParseFailed(#[source] Box<WlParserError>),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
ClientError(Box<WlClientError>),
|
ClientError(Box<ClientError>),
|
||||||
}
|
}
|
||||||
efrom!(SetInputRegionError, ParseFailed, WlParserError);
|
efrom!(SetInputRegionError, ParseFailed, WlParserError);
|
||||||
efrom!(SetInputRegionError, ClientError, WlClientError);
|
efrom!(SetInputRegionError, ClientError, ClientError);
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum CommitError {
|
pub enum CommitError {
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
mod types;
|
mod types;
|
||||||
|
|
||||||
|
use crate::client::{AddObj, Client, ClientError};
|
||||||
use crate::globals::{Global, GlobalName};
|
use crate::globals::{Global, GlobalName};
|
||||||
use crate::objects::{Interface, Object, ObjectError, ObjectId};
|
use crate::object::{Interface, Object, ObjectId};
|
||||||
use crate::utils::buffd::WlParser;
|
use crate::utils::buffd::WlParser;
|
||||||
use crate::wl_client::WlClientData;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
pub use types::*;
|
pub use types::*;
|
||||||
|
|
||||||
|
|
@ -25,7 +25,7 @@ impl XdgWmBaseGlobal {
|
||||||
async fn bind_(
|
async fn bind_(
|
||||||
self: Rc<Self>,
|
self: Rc<Self>,
|
||||||
id: ObjectId,
|
id: ObjectId,
|
||||||
client: &WlClientData,
|
client: &Client,
|
||||||
version: u32,
|
version: u32,
|
||||||
) -> Result<(), XdgWmBaseError> {
|
) -> Result<(), XdgWmBaseError> {
|
||||||
let obj = Rc::new(XdgWmBaseObj {
|
let obj = Rc::new(XdgWmBaseObj {
|
||||||
|
|
@ -33,7 +33,7 @@ impl XdgWmBaseGlobal {
|
||||||
id,
|
id,
|
||||||
version,
|
version,
|
||||||
});
|
});
|
||||||
client.attach_client_object(obj)?;
|
client.add_client_obj(&obj)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -43,7 +43,7 @@ impl XdgWmBaseObj {
|
||||||
&self,
|
&self,
|
||||||
request: u32,
|
request: u32,
|
||||||
parser: WlParser<'_, '_>,
|
parser: WlParser<'_, '_>,
|
||||||
) -> Result<(), ObjectError> {
|
) -> Result<(), ClientError> {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,10 @@
|
||||||
use crate::objects::ObjectError;
|
use crate::client::ClientError;
|
||||||
use crate::wl_client::WlClientError;
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum XdgWmBaseError {
|
pub enum XdgWmBaseError {
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
ObjectError(Box<ObjectError>),
|
ClientError(Box<ClientError>),
|
||||||
#[error(transparent)]
|
|
||||||
ClientError(Box<WlClientError>),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
efrom!(XdgWmBaseError, ObjectError, ObjectError);
|
efrom!(XdgWmBaseError, ClientError, ClientError);
|
||||||
efrom!(XdgWmBaseError, ClientError, WlClientError);
|
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,13 @@ macro_rules! efrom {
|
||||||
|
|
||||||
macro_rules! handle_request {
|
macro_rules! handle_request {
|
||||||
($oname:ty) => {
|
($oname:ty) => {
|
||||||
impl crate::objects::ObjectHandleRequest for $oname {
|
impl crate::object::ObjectHandleRequest for $oname {
|
||||||
fn handle_request<'a>(
|
fn handle_request<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
request: u32,
|
request: u32,
|
||||||
parser: crate::utils::buffd::WlParser<'a, 'a>,
|
parser: crate::utils::buffd::WlParser<'a, 'a>,
|
||||||
) -> std::pin::Pin<
|
) -> std::pin::Pin<
|
||||||
Box<dyn std::future::Future<Output = Result<(), crate::objects::ObjectError>> + 'a>,
|
Box<dyn std::future::Future<Output = Result<(), crate::client::ClientError>> + 'a>,
|
||||||
> {
|
> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
self.handle_request_(request, parser).await?;
|
self.handle_request_(request, parser).await?;
|
||||||
|
|
@ -32,8 +32,8 @@ macro_rules! bind {
|
||||||
impl crate::globals::GlobalBind for $oname {
|
impl crate::globals::GlobalBind for $oname {
|
||||||
fn bind<'a>(
|
fn bind<'a>(
|
||||||
self: std::rc::Rc<Self>,
|
self: std::rc::Rc<Self>,
|
||||||
client: &'a std::rc::Rc<crate::wl_client::WlClientData>,
|
client: &'a std::rc::Rc<crate::client::Client>,
|
||||||
id: crate::objects::ObjectId,
|
id: crate::object::ObjectId,
|
||||||
version: u32,
|
version: u32,
|
||||||
) -> std::pin::Pin<
|
) -> std::pin::Pin<
|
||||||
Box<dyn std::future::Future<Output = Result<(), crate::globals::GlobalError>> + 'a>,
|
Box<dyn std::future::Future<Output = Result<(), crate::globals::GlobalError>> + 'a>,
|
||||||
|
|
|
||||||
10
src/main.rs
10
src/main.rs
|
|
@ -1,4 +1,7 @@
|
||||||
|
#![feature(generic_associated_types, type_alias_impl_trait)]
|
||||||
|
|
||||||
use crate::acceptor::AcceptorError;
|
use crate::acceptor::AcceptorError;
|
||||||
|
use crate::client::Clients;
|
||||||
use crate::clientmem::ClientMemError;
|
use crate::clientmem::ClientMemError;
|
||||||
use crate::event_loop::EventLoopError;
|
use crate::event_loop::EventLoopError;
|
||||||
use crate::globals::Globals;
|
use crate::globals::Globals;
|
||||||
|
|
@ -9,7 +12,6 @@ use crate::ifs::xdg_wm_base::XdgWmBaseGlobal;
|
||||||
use crate::sighand::SighandError;
|
use crate::sighand::SighandError;
|
||||||
use crate::state::State;
|
use crate::state::State;
|
||||||
use crate::utils::numcell::NumCell;
|
use crate::utils::numcell::NumCell;
|
||||||
use crate::wl_client::WlClients;
|
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use log::LevelFilter;
|
use log::LevelFilter;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
@ -19,18 +21,18 @@ use thiserror::Error;
|
||||||
mod macros;
|
mod macros;
|
||||||
mod acceptor;
|
mod acceptor;
|
||||||
mod async_engine;
|
mod async_engine;
|
||||||
|
mod client;
|
||||||
mod clientmem;
|
mod clientmem;
|
||||||
mod event_loop;
|
mod event_loop;
|
||||||
mod globals;
|
mod globals;
|
||||||
mod ifs;
|
mod ifs;
|
||||||
mod objects;
|
mod object;
|
||||||
mod pixman;
|
mod pixman;
|
||||||
mod sighand;
|
mod sighand;
|
||||||
mod state;
|
mod state;
|
||||||
mod time;
|
mod time;
|
||||||
mod utils;
|
mod utils;
|
||||||
mod wheel;
|
mod wheel;
|
||||||
mod wl_client;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
env_logger::builder()
|
env_logger::builder()
|
||||||
|
|
@ -68,7 +70,7 @@ fn main_() -> Result<(), MainError> {
|
||||||
let state = Rc::new(State {
|
let state = Rc::new(State {
|
||||||
eng: engine,
|
eng: engine,
|
||||||
el: el.to_ref(),
|
el: el.to_ref(),
|
||||||
clients: WlClients::new(),
|
clients: Clients::new(),
|
||||||
next_name: NumCell::new(1),
|
next_name: NumCell::new(1),
|
||||||
globals,
|
globals,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
76
src/object.rs
Normal file
76
src/object.rs
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
use crate::client::ClientError;
|
||||||
|
use crate::ifs::wl_display::WlDisplay;
|
||||||
|
use crate::utils::buffd::WlParser;
|
||||||
|
use std::fmt::{Display, Formatter};
|
||||||
|
use std::future::Future;
|
||||||
|
use std::pin::Pin;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
pub const WL_DISPLAY_ID: ObjectId = ObjectId(1);
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
|
||||||
|
pub struct ObjectId(u32);
|
||||||
|
|
||||||
|
impl ObjectId {
|
||||||
|
pub fn from_raw(raw: u32) -> Self {
|
||||||
|
Self(raw)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn raw(self) -> u32 {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for ObjectId {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
Display::fmt(&self.0, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ObjectHandleRequest {
|
||||||
|
fn handle_request<'a>(
|
||||||
|
&'a self,
|
||||||
|
request: u32,
|
||||||
|
parser: WlParser<'a, 'a>,
|
||||||
|
) -> Pin<Box<dyn Future<Output = Result<(), ClientError>> + 'a>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Object: ObjectHandleRequest + 'static {
|
||||||
|
fn id(&self) -> ObjectId;
|
||||||
|
fn interface(&self) -> Interface;
|
||||||
|
fn num_requests(&self) -> u32;
|
||||||
|
fn into_display(self: Rc<Self>) -> Result<Rc<WlDisplay>, ClientError> {
|
||||||
|
Err(ClientError::NotADisplay(self.id()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub enum Interface {
|
||||||
|
WlDisplay,
|
||||||
|
WlCallback,
|
||||||
|
WlCompositor,
|
||||||
|
WlRegistry,
|
||||||
|
WlShm,
|
||||||
|
WlShmPool,
|
||||||
|
WlSubcompositor,
|
||||||
|
XdgWmBase,
|
||||||
|
WlSurface,
|
||||||
|
WlRegion,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Interface {
|
||||||
|
pub fn name(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Interface::WlDisplay => "wl_display",
|
||||||
|
Interface::WlCallback => "wl_callback",
|
||||||
|
Interface::WlCompositor => "wl_compositor",
|
||||||
|
Interface::WlRegistry => "wl_registry",
|
||||||
|
Interface::WlShm => "wl_shm",
|
||||||
|
Interface::WlSubcompositor => "wl_subcompositor",
|
||||||
|
Interface::XdgWmBase => "xdg_wm_base",
|
||||||
|
Interface::WlSurface => "wl_surface",
|
||||||
|
Interface::WlShmPool => "wl_shm_pool",
|
||||||
|
Interface::WlRegion => "wl_region",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
249
src/objects.rs
249
src/objects.rs
|
|
@ -1,249 +0,0 @@
|
||||||
use crate::ifs::wl_compositor::WlCompositorError;
|
|
||||||
use crate::ifs::wl_display::{WlDisplay, WlDisplayError};
|
|
||||||
use crate::ifs::wl_registry::{WlRegistry, WlRegistryError};
|
|
||||||
use crate::ifs::wl_shm::WlShmError;
|
|
||||||
use crate::ifs::wl_shm_pool::WlShmPoolError;
|
|
||||||
use crate::ifs::wl_surface::{WlSurface, WlSurfaceError};
|
|
||||||
use crate::utils::buffd::{WlParser, WlParserError};
|
|
||||||
use crate::utils::copyhashmap::CopyHashMap;
|
|
||||||
use crate::wl_client::{WlClientData, WlClientError};
|
|
||||||
use ahash::AHashMap;
|
|
||||||
use std::cell::{RefCell, RefMut};
|
|
||||||
use std::fmt::{Display, Formatter};
|
|
||||||
use std::future::Future;
|
|
||||||
use std::mem;
|
|
||||||
use std::pin::Pin;
|
|
||||||
use std::rc::Rc;
|
|
||||||
use thiserror::Error;
|
|
||||||
use crate::ifs::wl_region::{WlRegion, WlRegionError};
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
|
||||||
pub enum ObjectError {
|
|
||||||
#[error("A client error occurred")]
|
|
||||||
ClientError(#[source] Box<WlClientError>),
|
|
||||||
#[error("Cannot parse the message")]
|
|
||||||
ParserError(#[source] Box<WlParserError>),
|
|
||||||
#[error("Server tried to allocate more than 0x1_00_00_00 ids")]
|
|
||||||
TooManyIds,
|
|
||||||
#[error("The server object id is out of bounds")]
|
|
||||||
ServerIdOutOfBounds,
|
|
||||||
#[error("The object id is unknown")]
|
|
||||||
UnknownId,
|
|
||||||
#[error("The id is already in use")]
|
|
||||||
IdAlreadyInUse,
|
|
||||||
#[error("The client object id is out of bounds")]
|
|
||||||
ClientIdOutOfBounds,
|
|
||||||
#[error("An error occurred in a `wl_display`")]
|
|
||||||
WlDisplayError(#[source] Box<WlDisplayError>),
|
|
||||||
#[error("An error occurred in a `wl_registry`")]
|
|
||||||
WlRegistryError(#[source] Box<WlRegistryError>),
|
|
||||||
#[error("Could not add object {0} to the client")]
|
|
||||||
AddObjectError(ObjectId, #[source] Box<ObjectError>),
|
|
||||||
#[error("An error occurred in a `wl_surface`")]
|
|
||||||
WlSurfaceError(#[source] Box<WlSurfaceError>),
|
|
||||||
#[error("An error occurred in a `wl_compositor`")]
|
|
||||||
WlCompositorError(#[source] Box<WlCompositorError>),
|
|
||||||
#[error("An error occurred in a `wl_shm`")]
|
|
||||||
WlShmError(#[source] Box<WlShmError>),
|
|
||||||
#[error("An error occurred in a `wl_shm_pool`")]
|
|
||||||
WlShmPoolError(#[source] Box<WlShmPoolError>),
|
|
||||||
#[error("An error occurred in a `wl_region`")]
|
|
||||||
WlRegionError(#[source] Box<WlRegionError>),
|
|
||||||
#[error("Object {0} is not a display")]
|
|
||||||
NotADisplay(ObjectId),
|
|
||||||
}
|
|
||||||
|
|
||||||
efrom!(ObjectError, ClientError, WlClientError);
|
|
||||||
efrom!(ObjectError, ParserError, WlParserError);
|
|
||||||
efrom!(ObjectError, WlDisplayError, WlDisplayError);
|
|
||||||
efrom!(ObjectError, WlRegistryError, WlRegistryError);
|
|
||||||
efrom!(ObjectError, WlSurfaceError, WlSurfaceError);
|
|
||||||
efrom!(ObjectError, WlCompositorError, WlCompositorError);
|
|
||||||
efrom!(ObjectError, WlShmError, WlShmError);
|
|
||||||
efrom!(ObjectError, WlShmPoolError, WlShmPoolError);
|
|
||||||
efrom!(ObjectError, WlRegionError, WlRegionError);
|
|
||||||
|
|
||||||
pub const WL_DISPLAY_ID: ObjectId = ObjectId(1);
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
|
|
||||||
pub struct ObjectId(u32);
|
|
||||||
|
|
||||||
impl ObjectId {
|
|
||||||
pub fn from_raw(raw: u32) -> Self {
|
|
||||||
Self(raw)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn raw(self) -> u32 {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for ObjectId {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
||||||
Display::fmt(&self.0, f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait ObjectHandleRequest {
|
|
||||||
fn handle_request<'a>(
|
|
||||||
&'a self,
|
|
||||||
request: u32,
|
|
||||||
parser: WlParser<'a, 'a>,
|
|
||||||
) -> Pin<Box<dyn Future<Output = Result<(), ObjectError>> + 'a>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Object: ObjectHandleRequest {
|
|
||||||
fn id(&self) -> ObjectId;
|
|
||||||
fn interface(&self) -> Interface;
|
|
||||||
fn num_requests(&self) -> u32;
|
|
||||||
fn pre_release(&self) -> Result<(), ObjectError> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
fn post_attach(self: Rc<Self>) {}
|
|
||||||
fn into_display(self: Rc<Self>) -> Result<Rc<WlDisplay>, ObjectError> {
|
|
||||||
Err(ObjectError::NotADisplay(self.id()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
|
||||||
pub enum Interface {
|
|
||||||
WlDisplay,
|
|
||||||
WlCallback,
|
|
||||||
WlCompositor,
|
|
||||||
WlRegistry,
|
|
||||||
WlShm,
|
|
||||||
WlShmPool,
|
|
||||||
WlSubcompositor,
|
|
||||||
XdgWmBase,
|
|
||||||
WlSurface,
|
|
||||||
WlRegion,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Interface {
|
|
||||||
pub fn name(self) -> &'static str {
|
|
||||||
match self {
|
|
||||||
Interface::WlDisplay => "wl_display",
|
|
||||||
Interface::WlCallback => "wl_callback",
|
|
||||||
Interface::WlCompositor => "wl_compositor",
|
|
||||||
Interface::WlRegistry => "wl_registry",
|
|
||||||
Interface::WlShm => "wl_shm",
|
|
||||||
Interface::WlSubcompositor => "wl_subcompositor",
|
|
||||||
Interface::XdgWmBase => "xdg_wm_base",
|
|
||||||
Interface::WlSurface => "wl_surface",
|
|
||||||
Interface::WlShmPool => "wl_shm_pool",
|
|
||||||
Interface::WlRegion => "wl_region",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Objects {
|
|
||||||
registry: CopyHashMap<ObjectId, Rc<dyn Object>>,
|
|
||||||
registries: CopyHashMap<ObjectId, Rc<WlRegistry>>,
|
|
||||||
pub surfaces: CopyHashMap<ObjectId, Rc<WlSurface>>,
|
|
||||||
pub regions: CopyHashMap<ObjectId, Rc<WlRegion>>,
|
|
||||||
ids: RefCell<Vec<usize>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
const MIN_SERVER_ID: u32 = 0xff000000;
|
|
||||||
const SEG_SIZE: usize = 8 * mem::size_of::<usize>();
|
|
||||||
|
|
||||||
impl Objects {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
registry: Default::default(),
|
|
||||||
registries: Default::default(),
|
|
||||||
surfaces: Default::default(),
|
|
||||||
regions: Default::default(),
|
|
||||||
ids: RefCell::new(vec![]),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn destroy(&self) {
|
|
||||||
self.registry.clear();
|
|
||||||
self.registries.clear();
|
|
||||||
self.surfaces.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn id(&self, client_data: &WlClientData) -> Result<ObjectId, ObjectError> {
|
|
||||||
const MAX_ID_OFFSET: u32 = u32::MAX - MIN_SERVER_ID;
|
|
||||||
let offset = self.id_offset();
|
|
||||||
if offset > MAX_ID_OFFSET {
|
|
||||||
log::error!(
|
|
||||||
"Client {} caused the server to allocate more than 0x{:x} ids",
|
|
||||||
client_data.id,
|
|
||||||
MAX_ID_OFFSET + 1
|
|
||||||
);
|
|
||||||
return Err(ObjectError::TooManyIds);
|
|
||||||
}
|
|
||||||
Ok(ObjectId(MIN_SERVER_ID + offset))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_obj(&self, id: ObjectId) -> Result<Rc<dyn Object>, ObjectError> {
|
|
||||||
match self.registry.get(&id) {
|
|
||||||
Some(o) => Ok(o),
|
|
||||||
_ => Err(ObjectError::UnknownId),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_client_object(&self, obj: Rc<dyn Object>) -> Result<(), ObjectError> {
|
|
||||||
let id = obj.id();
|
|
||||||
let res = (|| {
|
|
||||||
if id.0 == 0 || id.0 >= MIN_SERVER_ID {
|
|
||||||
return Err(ObjectError::ClientIdOutOfBounds);
|
|
||||||
}
|
|
||||||
if self.registry.contains(&id) {
|
|
||||||
return Err(ObjectError::IdAlreadyInUse);
|
|
||||||
}
|
|
||||||
self.registry.set(id, obj.clone());
|
|
||||||
obj.post_attach();
|
|
||||||
Ok(())
|
|
||||||
})();
|
|
||||||
if let Err(e) = res {
|
|
||||||
return Err(ObjectError::AddObjectError(id, Box::new(e)));
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn remove_obj(
|
|
||||||
&self,
|
|
||||||
client_data: &WlClientData,
|
|
||||||
id: ObjectId,
|
|
||||||
) -> Result<(), ObjectError> {
|
|
||||||
let obj = match self.registry.remove(&id) {
|
|
||||||
Some(o) => o,
|
|
||||||
_ => return Err(ObjectError::UnknownId),
|
|
||||||
};
|
|
||||||
obj.pre_release()?;
|
|
||||||
if id.0 >= MIN_SERVER_ID {
|
|
||||||
let offset = (id.0 - MIN_SERVER_ID) as usize;
|
|
||||||
let pos = offset / SEG_SIZE;
|
|
||||||
let seg_offset = offset % SEG_SIZE;
|
|
||||||
let mut ids = self.ids.borrow_mut();
|
|
||||||
if ids.len() <= pos {
|
|
||||||
return Err(ObjectError::ServerIdOutOfBounds);
|
|
||||||
}
|
|
||||||
ids[pos] |= 1 << seg_offset;
|
|
||||||
}
|
|
||||||
client_data
|
|
||||||
.event(client_data.display()?.delete_id(id))
|
|
||||||
.await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn registries(&self) -> RefMut<AHashMap<ObjectId, Rc<WlRegistry>>> {
|
|
||||||
self.registries.lock()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn id_offset(&self) -> u32 {
|
|
||||||
let mut ids = self.ids.borrow_mut();
|
|
||||||
for (pos, seg) in ids.iter_mut().enumerate() {
|
|
||||||
if *seg != 0 {
|
|
||||||
let offset = seg.trailing_zeros();
|
|
||||||
*seg &= !(1 << offset);
|
|
||||||
return (pos * SEG_SIZE) as u32 + offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ids.push(!1);
|
|
||||||
((ids.len() - 1) * SEG_SIZE) as u32
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
use std::ops::{Add, Sub};
|
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use uapi::c;
|
use uapi::c;
|
||||||
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
use crate::async_engine::AsyncEngine;
|
use crate::async_engine::AsyncEngine;
|
||||||
|
use crate::client::Clients;
|
||||||
use crate::event_loop::EventLoopRef;
|
use crate::event_loop::EventLoopRef;
|
||||||
use crate::globals::Globals;
|
use crate::globals::Globals;
|
||||||
use crate::utils::numcell::NumCell;
|
use crate::utils::numcell::NumCell;
|
||||||
use crate::wl_client::WlClients;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct State {
|
pub struct State {
|
||||||
pub eng: Rc<AsyncEngine>,
|
pub eng: Rc<AsyncEngine>,
|
||||||
pub el: EventLoopRef,
|
pub el: EventLoopRef,
|
||||||
pub clients: WlClients,
|
pub clients: Clients,
|
||||||
pub next_name: NumCell<u32>,
|
pub next_name: NumCell<u32>,
|
||||||
pub globals: Globals,
|
pub globals: Globals,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::objects::ObjectId;
|
use crate::object::ObjectId;
|
||||||
use crate::utils::buffd::buf_out::{BufFdOut, MsgFds};
|
use crate::utils::buffd::buf_out::{BufFdOut, MsgFds};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::mem::MaybeUninit;
|
use std::mem::MaybeUninit;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::globals::GlobalName;
|
use crate::globals::GlobalName;
|
||||||
use crate::objects::ObjectId;
|
use crate::object::ObjectId;
|
||||||
use crate::utils::buffd::BufFdIn;
|
use crate::utils::buffd::BufFdIn;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use uapi::OwnedFd;
|
use uapi::OwnedFd;
|
||||||
|
|
|
||||||
420
src/wl_client.rs
420
src/wl_client.rs
|
|
@ -1,420 +0,0 @@
|
||||||
use crate::async_engine::{AsyncError, AsyncFd, SpawnedFuture};
|
|
||||||
use crate::ifs::wl_display::WlDisplay;
|
|
||||||
use crate::objects::{Object, ObjectError, ObjectId, Objects, WL_DISPLAY_ID};
|
|
||||||
use crate::state::State;
|
|
||||||
use crate::utils::buffd::{BufFdError, BufFdIn, BufFdOut, WlFormatter, WlParser, WlParserError};
|
|
||||||
use crate::utils::copyhashmap::CopyHashMap;
|
|
||||||
use crate::utils::numcell::NumCell;
|
|
||||||
use crate::utils::oneshot::{oneshot, OneshotRx, OneshotTx};
|
|
||||||
use crate::utils::queue::AsyncQueue;
|
|
||||||
use crate::utils::vec_ext::VecExt;
|
|
||||||
use anyhow::anyhow;
|
|
||||||
use futures::{select, FutureExt};
|
|
||||||
use std::cell::Cell;
|
|
||||||
use std::fmt::{Debug, Display, Formatter};
|
|
||||||
use std::mem;
|
|
||||||
use std::rc::Rc;
|
|
||||||
use thiserror::Error;
|
|
||||||
use uapi::OwnedFd;
|
|
||||||
use crate::ifs::wl_region::WlRegion;
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
|
||||||
pub enum WlClientError {
|
|
||||||
#[error("An error occurred in the async engine")]
|
|
||||||
Async(#[from] AsyncError),
|
|
||||||
#[error("An error occurred reading from/writing to the client")]
|
|
||||||
Io(#[from] BufFdError),
|
|
||||||
#[error("An error occurred while processing a request")]
|
|
||||||
RequestError(#[source] Box<ObjectError>),
|
|
||||||
#[error("Client tried to invoke a non-existent method")]
|
|
||||||
InvalidMethod,
|
|
||||||
#[error("Client tried to access non-existent object {0}")]
|
|
||||||
InvalidObject(ObjectId),
|
|
||||||
#[error("The message size is < 8")]
|
|
||||||
MessageSizeTooSmall,
|
|
||||||
#[error("The size of the message is not a multiple of 4")]
|
|
||||||
UnalignedMessage,
|
|
||||||
#[error("The outgoing buffer overflowed")]
|
|
||||||
OutBufferOverflow,
|
|
||||||
#[error("The requested client {0} does not exist")]
|
|
||||||
ClientDoesNotExist(ClientId),
|
|
||||||
#[error(transparent)]
|
|
||||||
ObjectError(Box<ObjectError>),
|
|
||||||
#[error("There is no region with id {0}")]
|
|
||||||
RegionDoesNotExist(ObjectId),
|
|
||||||
}
|
|
||||||
|
|
||||||
efrom!(WlClientError, ObjectError, ObjectError);
|
|
||||||
|
|
||||||
impl WlClientError {
|
|
||||||
fn peer_closed(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
WlClientError::Io(BufFdError::Closed) => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
|
|
||||||
pub struct ClientId(u64);
|
|
||||||
|
|
||||||
impl Display for ClientId {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
||||||
Display::fmt(&self.0, f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct WlClients {
|
|
||||||
next_client_id: NumCell<u64>,
|
|
||||||
clients: CopyHashMap<ClientId, Rc<WlClient>>,
|
|
||||||
shutdown_clients: CopyHashMap<ClientId, Rc<WlClient>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WlClients {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
next_client_id: NumCell::new(1),
|
|
||||||
clients: CopyHashMap::new(),
|
|
||||||
shutdown_clients: CopyHashMap::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn id(&self) -> ClientId {
|
|
||||||
ClientId(self.next_client_id.fetch_add(1))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get(&self, id: ClientId) -> Result<Rc<WlClientData>, WlClientError> {
|
|
||||||
match self.clients.get(&id) {
|
|
||||||
Some(c) => Ok(c.data.clone()),
|
|
||||||
_ => Err(WlClientError::ClientDoesNotExist(id)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn spawn(
|
|
||||||
&self,
|
|
||||||
id: ClientId,
|
|
||||||
global: &Rc<State>,
|
|
||||||
socket: OwnedFd,
|
|
||||||
) -> Result<(), WlClientError> {
|
|
||||||
let (send, recv) = oneshot();
|
|
||||||
let data = Rc::new(WlClientData {
|
|
||||||
id,
|
|
||||||
state: global.clone(),
|
|
||||||
socket: global.eng.fd(&Rc::new(socket))?,
|
|
||||||
objects: Objects::new(),
|
|
||||||
events: AsyncQueue::new(),
|
|
||||||
shutdown: Cell::new(Some(send)),
|
|
||||||
shutdown_sent: Cell::new(false),
|
|
||||||
});
|
|
||||||
data.objects
|
|
||||||
.add_client_object(Rc::new(WlDisplay::new(&data)))
|
|
||||||
.expect("");
|
|
||||||
let client = Rc::new(WlClient {
|
|
||||||
_handler: global.eng.spawn(client(data.clone(), recv)),
|
|
||||||
data,
|
|
||||||
});
|
|
||||||
self.clients.set(client.data.id, client.clone());
|
|
||||||
log::info!("Client {} connected", id);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn kill(&self, client: ClientId) {
|
|
||||||
log::info!("Removing client {}", client.0);
|
|
||||||
if self.clients.remove(&client).is_none() {
|
|
||||||
self.shutdown_clients.remove(&client);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn shutdown(&self, client_id: ClientId) {
|
|
||||||
if let Some(client) = self.clients.remove(&client_id) {
|
|
||||||
log::info!("Shutting down client {}", client.data.id.0);
|
|
||||||
client.data.shutdown.replace(None).unwrap().send(());
|
|
||||||
client.data.events.push(WlEvent::Shutdown);
|
|
||||||
client.data.shutdown_sent.set(true);
|
|
||||||
self.shutdown_clients.set(client_id, client);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn broadcast<B>(&self, mut f: B)
|
|
||||||
where
|
|
||||||
B: FnMut(&Rc<WlClientData>),
|
|
||||||
{
|
|
||||||
let clients = self.clients.lock();
|
|
||||||
for client in clients.values() {
|
|
||||||
f(&client.data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct WlClient {
|
|
||||||
data: Rc<WlClientData>,
|
|
||||||
_handler: SpawnedFuture<()>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for WlClient {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
self.data.objects.destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait EventFormatter: Debug {
|
|
||||||
fn format(self: Box<Self>, fmt: &mut WlFormatter<'_>);
|
|
||||||
fn obj(&self) -> &dyn Object;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type DynEventFormatter = Box<dyn EventFormatter>;
|
|
||||||
|
|
||||||
pub trait RequestParser<'a>: Debug + Sized {
|
|
||||||
fn parse(parser: &mut WlParser<'_, 'a>) -> Result<Self, WlParserError>;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum WlEvent {
|
|
||||||
Flush,
|
|
||||||
Shutdown,
|
|
||||||
Event(Box<dyn EventFormatter>),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct WlClientData {
|
|
||||||
pub id: ClientId,
|
|
||||||
pub state: Rc<State>,
|
|
||||||
socket: AsyncFd,
|
|
||||||
pub objects: Objects,
|
|
||||||
events: AsyncQueue<WlEvent>,
|
|
||||||
shutdown: Cell<Option<OneshotTx<()>>>,
|
|
||||||
shutdown_sent: Cell<bool>,
|
|
||||||
}
|
|
||||||
|
|
||||||
const MAX_PENDING_EVENTS: usize = 100;
|
|
||||||
|
|
||||||
impl WlClientData {
|
|
||||||
pub fn invalid_request(&self, obj: &dyn Object, request: u32) {
|
|
||||||
log::error!(
|
|
||||||
"Client {} sent an invalid request {} on object {} of type {}",
|
|
||||||
self.id.0,
|
|
||||||
request,
|
|
||||||
obj.id(),
|
|
||||||
obj.interface().name(),
|
|
||||||
);
|
|
||||||
match self.display() {
|
|
||||||
Ok(d) => self.fatal_event(d.invalid_request(obj, request)),
|
|
||||||
Err(e) => {
|
|
||||||
log::error!(
|
|
||||||
"Could not retrieve display of client {}: {:#}",
|
|
||||||
self.id,
|
|
||||||
anyhow!(e)
|
|
||||||
);
|
|
||||||
self.state.clients.kill(self.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn display(&self) -> Result<Rc<WlDisplay>, WlClientError> {
|
|
||||||
Ok(self.objects.get_obj(WL_DISPLAY_ID)?.into_display()?)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse<'a, R: RequestParser<'a>>(
|
|
||||||
&self,
|
|
||||||
obj: &impl Object,
|
|
||||||
mut parser: WlParser<'_, 'a>,
|
|
||||||
) -> Result<R, WlParserError> {
|
|
||||||
let res = R::parse(&mut parser)?;
|
|
||||||
parser.eof()?;
|
|
||||||
log::trace!(
|
|
||||||
"Client {} -> {}@{}.{:?}",
|
|
||||||
self.id,
|
|
||||||
obj.interface().name(),
|
|
||||||
obj.id(),
|
|
||||||
res
|
|
||||||
);
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn fatal_event(&self, event: Box<dyn EventFormatter>) {
|
|
||||||
self.events.push(WlEvent::Event(event));
|
|
||||||
self.state.clients.shutdown(self.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn event_locked(&self, event: Box<dyn EventFormatter>) -> bool {
|
|
||||||
self.events.push(WlEvent::Event(event));
|
|
||||||
self.events.size() > MAX_PENDING_EVENTS
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn event(&self, event: Box<dyn EventFormatter>) -> Result<(), WlClientError> {
|
|
||||||
self.event2(WlEvent::Event(event)).await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn event2(&self, event: WlEvent) -> Result<(), WlClientError> {
|
|
||||||
self.events.push(event);
|
|
||||||
self.check_queue_size().await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn check_queue_size(&self) -> Result<(), WlClientError> {
|
|
||||||
if self.events.size() > MAX_PENDING_EVENTS {
|
|
||||||
self.state.eng.yield_now().await;
|
|
||||||
if self.events.size() > MAX_PENDING_EVENTS {
|
|
||||||
log::error!("Client {} is too slow at fetching events", self.id.0);
|
|
||||||
self.state.clients.kill(self.id);
|
|
||||||
return Err(WlClientError::OutBufferOverflow);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn attach_client_object(&self, obj: Rc<dyn Object>) -> Result<(), WlClientError> {
|
|
||||||
self.objects.add_client_object(obj.clone())?;
|
|
||||||
obj.post_attach();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_region(&self, id: ObjectId) -> Result<Rc<WlRegion>, WlClientError> {
|
|
||||||
match self.objects.regions.get(&id) {
|
|
||||||
Some(r) => Ok(r),
|
|
||||||
_ => Err(WlClientError::RegionDoesNotExist(id)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn client(data: Rc<WlClientData>, shutdown: OneshotRx<()>) {
|
|
||||||
let mut recv = data.state.eng.spawn(receive(data.clone())).fuse();
|
|
||||||
let _send = data.state.eng.spawn(send(data.clone()));
|
|
||||||
select! {
|
|
||||||
_ = recv => { },
|
|
||||||
_ = shutdown.fuse() => { },
|
|
||||||
}
|
|
||||||
drop(recv);
|
|
||||||
if !data.shutdown_sent.get() {
|
|
||||||
data.events.push(WlEvent::Shutdown);
|
|
||||||
}
|
|
||||||
match data.state.eng.timeout(5000) {
|
|
||||||
Ok(timeout) => {
|
|
||||||
timeout.await;
|
|
||||||
log::error!("Could not shut down client {} within 5 seconds", data.id.0);
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("Could not create a timeout: {:#}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
data.state.clients.kill(data.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn receive(data: Rc<WlClientData>) {
|
|
||||||
let display = data.display().unwrap();
|
|
||||||
let recv = async {
|
|
||||||
let mut buf = BufFdIn::new(data.socket.clone());
|
|
||||||
let mut data_buf = Vec::<u32>::new();
|
|
||||||
loop {
|
|
||||||
let mut hdr = [0u32, 0];
|
|
||||||
buf.read_full(&mut hdr[..]).await?;
|
|
||||||
let obj_id = ObjectId::from_raw(hdr[0]);
|
|
||||||
let len = (hdr[1] >> 16) as usize;
|
|
||||||
let request = hdr[1] & 0xffff;
|
|
||||||
let obj = match data.objects.get_obj(obj_id) {
|
|
||||||
Ok(obj) => obj,
|
|
||||||
_ => {
|
|
||||||
data.fatal_event(display.invalid_object(obj_id));
|
|
||||||
return Err(WlClientError::InvalidObject(obj_id));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// log::trace!("obj: {}, request: {}, len: {}", obj_id, request, len);
|
|
||||||
if request >= obj.num_requests() {
|
|
||||||
data.invalid_request(&*obj, request);
|
|
||||||
return Err(WlClientError::InvalidMethod);
|
|
||||||
}
|
|
||||||
if len < 8 {
|
|
||||||
return Err(WlClientError::MessageSizeTooSmall);
|
|
||||||
}
|
|
||||||
if len % 4 != 0 {
|
|
||||||
return Err(WlClientError::UnalignedMessage);
|
|
||||||
}
|
|
||||||
let len = len / 4 - 2;
|
|
||||||
data_buf.clear();
|
|
||||||
data_buf.reserve(len);
|
|
||||||
let unused = data_buf.split_at_spare_mut_ext().1;
|
|
||||||
buf.read_full(&mut unused[..len]).await?;
|
|
||||||
unsafe {
|
|
||||||
data_buf.set_len(len);
|
|
||||||
}
|
|
||||||
// log::trace!("{:x?}", data_buf);
|
|
||||||
let parser = WlParser::new(&mut buf, &data_buf[..]);
|
|
||||||
if let Err(e) = obj.handle_request(request, parser).await {
|
|
||||||
return Err(WlClientError::RequestError(Box::new(e)));
|
|
||||||
}
|
|
||||||
data.event2(WlEvent::Flush).await?;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let res: Result<(), WlClientError> = recv.await;
|
|
||||||
if let Err(e) = res {
|
|
||||||
if e.peer_closed() {
|
|
||||||
log::info!("Client {} terminated the connection", data.id.0);
|
|
||||||
data.state.clients.kill(data.id);
|
|
||||||
} else {
|
|
||||||
let e = anyhow!(e);
|
|
||||||
log::error!(
|
|
||||||
"An error occurred while trying to handle a message from client {}: {:#}",
|
|
||||||
data.id.0,
|
|
||||||
e
|
|
||||||
);
|
|
||||||
if !data.shutdown_sent.get() {
|
|
||||||
data.fatal_event(display.implementation_error(format!("{:#}", e)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn send(data: Rc<WlClientData>) {
|
|
||||||
let send = async {
|
|
||||||
let mut buf = BufFdOut::new(data.socket.clone());
|
|
||||||
let mut flush_requested = false;
|
|
||||||
loop {
|
|
||||||
let mut event = data.events.pop().await;
|
|
||||||
loop {
|
|
||||||
match event {
|
|
||||||
WlEvent::Flush => {
|
|
||||||
flush_requested = true;
|
|
||||||
}
|
|
||||||
WlEvent::Shutdown => {
|
|
||||||
buf.flush().await?;
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
WlEvent::Event(e) => {
|
|
||||||
if log::log_enabled!(log::Level::Trace) {
|
|
||||||
let obj = e.obj();
|
|
||||||
log::trace!(
|
|
||||||
"Client {} <= {}@{}.{:?}",
|
|
||||||
data.id,
|
|
||||||
obj.interface().name(),
|
|
||||||
obj.id(),
|
|
||||||
e
|
|
||||||
);
|
|
||||||
}
|
|
||||||
e.format(&mut WlFormatter::new(&mut buf));
|
|
||||||
if buf.needs_flush() {
|
|
||||||
buf.flush().await?;
|
|
||||||
flush_requested = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
event = match data.events.try_pop() {
|
|
||||||
Some(e) => e,
|
|
||||||
_ => break,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if mem::take(&mut flush_requested) {
|
|
||||||
buf.flush().await?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let res: Result<(), WlClientError> = send.await;
|
|
||||||
if let Err(e) = res {
|
|
||||||
if e.peer_closed() {
|
|
||||||
log::info!("Client {} terminated the connection", data.id.0);
|
|
||||||
} else {
|
|
||||||
log::error!(
|
|
||||||
"An error occurred while sending data to client {}: {:#}",
|
|
||||||
data.id.0,
|
|
||||||
e
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
data.state.clients.kill(data.id);
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue