use std::{
convert::Infallible,
future::Future,
pin::Pin,
task::{ready, Context, Poll},
};
use ::runa_wayland_protocols::wayland::{
wl_callback, wl_display::v1 as wl_display, wl_registry::v1 as wl_registry,
};
use runa_io::traits::WriteMessage;
pub use runa_macros::wayland_object;
#[doc(no_inline)]
pub use runa_macros::Object;
use runa_wayland_types::{NewId, Str};
use tracing::debug;
use crate::{
client::traits::{Client, ClientParts, Store},
globals::{AnyGlobal, Bind},
server::traits::{GlobalStore, Server},
};
pub trait AnyObject: 'static + Sized {
fn interface(&self) -> &'static str;
fn cast<T: 'static>(&self) -> Option<&T>;
fn cast_mut<T: 'static>(&mut self) -> Option<&mut T>;
fn new_singleton_state(&self) -> Box<dyn std::any::Any>;
fn type_id(&self) -> std::any::TypeId;
}
pub trait MonoObject: 'static {
type SingletonState: 'static;
fn new_singleton_state() -> Self::SingletonState;
const INTERFACE: &'static str;
}
pub trait Object<Ctx: crate::client::traits::Client>: 'static {
type Request<'a>: runa_io::traits::de::Deserialize<'a>
where
Ctx: 'a;
type Error: crate::error::ProtocolError;
type Fut<'a>: Future<Output = (Result<(), Self::Error>, usize, usize)> + 'a
where
Ctx: 'a;
fn on_disconnect(
&mut self,
_server_ctx: &mut Ctx::ServerContext,
_state: &mut dyn std::any::Any,
) {
}
fn dispatch<'a>(ctx: &'a mut Ctx, object_id: u32, msg: Self::Request<'a>) -> Self::Fut<'a>;
}
pub const DISPLAY_ID: u32 = 1;
#[derive(Debug, Clone, Copy, Default)]
pub struct Display {
pub(crate) initialized: bool,
}
#[wayland_object(crate = "crate")]
impl<Ctx> wl_display::RequestDispatch<Ctx> for Display
where
Ctx: Client + std::fmt::Debug,
Ctx::Object: From<Self>,
{
type Error = crate::error::Error;
type GetRegistryFut<'a> = impl std::future::Future<Output = Result<(), Self::Error>> + 'a where Ctx: 'a;
type SyncFut<'a> = impl std::future::Future<Output = Result<(), Self::Error>> + 'a where Ctx: 'a;
fn sync(ctx: &mut Ctx, object_id: u32, callback: NewId) -> Self::SyncFut<'_> {
assert!(ctx.objects().get::<Self>(object_id).unwrap().initialized);
async move {
debug!("wl_display.sync {}", callback);
let objects = ctx.objects();
if objects.contains(callback.0) {
return Err(crate::error::Error::IdExists(callback.0))
}
let conn = ctx.connection_mut();
conn.send(callback.0, wl_callback::v1::events::Done {
callback_data: 0,
})
.await?;
conn.send(DISPLAY_ID, wl_display::events::DeleteId { id: callback.0 })
.await?;
Ok(())
}
}
fn get_registry(ctx: &mut Ctx, object_id: u32, registry: NewId) -> Self::GetRegistryFut<'_> {
assert!(ctx.objects().get::<Self>(object_id).unwrap().initialized);
async move {
debug!("wl_display.get_registry {}", registry);
let ClientParts {
server_context,
objects,
..
} = ctx.as_mut_parts();
let global = {
let globals = server_context.globals().borrow();
let global = globals
.iter()
.find_map(|(_, g)| {
if g.interface() == wl_registry::NAME {
Some(g)
} else {
None
}
})
.expect("wl_registry not found")
.clone();
global
};
let inserted = objects
.try_insert_with(registry.0, || global.new_object())
.is_some();
if inserted {
global.bind(ctx, registry.0).await?;
Ok(())
} else {
Err(crate::error::Error::IdExists(registry.0))
}
}
}
}
#[derive(Debug)]
pub struct Registry(pub(crate) Option<futures_util::future::AbortHandle>);
impl Drop for Registry {
fn drop(&mut self) {
if let Some(abort) = self.0.take() {
abort.abort();
}
}
}
#[wayland_object(crate = "crate")]
impl<Ctx> wl_registry::RequestDispatch<Ctx> for Registry
where
Ctx: Client + std::fmt::Debug,
{
type Error = crate::error::Error;
type BindFut<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Ctx: 'a;
fn bind<'a>(
ctx: &'a mut Ctx,
_object_id: u32,
name: u32,
_interface: Str<'a>,
_version: u32,
id: NewId,
) -> Self::BindFut<'a> {
tracing::debug!("bind name:{name}, id:{id}");
async move {
let ClientParts {
server_context,
objects,
..
} = ctx.as_mut_parts();
let global = server_context.globals().borrow().get(name).cloned();
if let Some(global) = global {
let inserted = objects
.try_insert_with(id.0, || global.new_object())
.is_some();
if !inserted {
Err(crate::error::Error::IdExists(id.0))
} else {
global.bind(ctx, id.0).await?;
Ok(())
}
} else {
Err(crate::error::Error::UnknownGlobal(name))
}
}
}
}
#[derive(Debug, Default, Clone, Copy)]
pub struct Callback {
fired: bool,
}
impl MonoObject for Callback {
type SingletonState = ();
const INTERFACE: &'static str = runa_wayland_protocols::wayland::wl_callback::v1::NAME;
fn new_singleton_state() {}
}
impl<Ctx: crate::client::traits::Client> Object<Ctx> for Callback {
type Error = crate::error::Error;
type Request<'a> = Infallible where Ctx: 'a;
type Fut<'a> = impl Future<Output = (Result<(), Self::Error>, usize, usize)> + 'a where Ctx: 'a;
fn dispatch<'a>(_ctx: &'a mut Ctx, _object_id: u32, msg: Self::Request<'a>) -> Self::Fut<'a> {
async move { match msg {} }
}
}
impl Callback {
pub fn poll_fire<O: AnyObject + 'static>(
cx: &mut Context<'_>,
object_id: u32,
data: u32,
objects: &mut impl Store<O>,
mut conn: Pin<&mut impl WriteMessage>,
) -> Poll<std::io::Result<()>> {
let this = objects.get_mut::<Self>(object_id).unwrap();
if !this.fired {
ready!(conn.as_mut().poll_ready(cx))?;
conn.as_mut().start_send(
object_id,
runa_wayland_protocols::wayland::wl_callback::v1::events::Done {
callback_data: data,
},
);
this.fired = true;
}
ready!(conn.as_mut().poll_ready(cx))?;
objects.remove(object_id).unwrap();
Poll::Ready(Ok(()))
}
pub async fn fire<'a, O: AnyObject + 'static>(
object_id: u32,
data: u32,
objects: &mut impl Store<O>,
conn: &mut (impl WriteMessage + Unpin),
) -> std::io::Result<()> {
objects.get::<Self>(object_id).unwrap();
conn.send(
object_id,
runa_wayland_protocols::wayland::wl_callback::v1::events::Done {
callback_data: data,
},
)
.await?;
objects.remove(object_id).unwrap();
Ok(())
}
}