use std::{future::Future, pin::Pin};
use runa_io::traits::WriteMessage;
use runa_wayland_protocols::wayland::{wl_display, wl_registry::v1 as wl_registry};
use crate::{
client::traits::{
Client, ClientParts, EventDispatcher, EventHandler, EventHandlerAction, StoreUpdate,
},
events::EventSource,
objects::DISPLAY_ID,
server::traits::{GlobalStore, GlobalsUpdate, Server},
};
pub trait MonoGlobal: Sized {
type Object;
const INTERFACE: &'static str;
const VERSION: u32;
const MAYBE_DEFAULT: Option<Self>;
fn new_object() -> Self::Object;
}
pub trait Bind<Ctx> {
type BindFut<'a>: Future<Output = std::io::Result<()>> + 'a
where
Ctx: 'a,
Self: 'a;
fn bind<'a>(&'a self, client: &'a mut Ctx, object_id: u32) -> Self::BindFut<'a>;
}
pub trait AnyGlobal {
type Object: crate::objects::AnyObject;
fn new_object(&self) -> Self::Object;
fn interface(&self) -> &'static str;
fn version(&self) -> u32;
fn cast<T: 'static>(&self) -> Option<&T>
where
Self: 'static + Sized;
}
#[derive(Debug, Clone, Copy, Default)]
pub struct Display;
impl MonoGlobal for Display {
type Object = crate::objects::Display;
const INTERFACE: &'static str = wl_display::v1::NAME;
const MAYBE_DEFAULT: Option<Self> = Some(Self);
const VERSION: u32 = wl_display::v1::VERSION;
#[inline]
fn new_object() -> Self::Object {
crate::objects::Display { initialized: false }
}
}
impl<Ctx: Client> Bind<Ctx> for Display {
type BindFut<'a > = impl Future<Output = std::io::Result<()>> + 'a where Self: 'a, Ctx: 'a;
fn bind<'a>(&'a self, client: &'a mut Ctx, object_id: u32) -> Self::BindFut<'a> {
use crate::client::traits::Store;
let ClientParts {
objects,
event_dispatcher,
..
} = client.as_mut_parts();
objects
.get_mut::<<Self as MonoGlobal>::Object>(object_id)
.unwrap()
.initialized = true;
struct DisplayEventHandler;
impl<Ctx: Client> EventHandler<Ctx> for DisplayEventHandler {
type Message = StoreUpdate;
type Future<'ctx> = impl Future<
Output = Result<
EventHandlerAction,
Box<dyn std::error::Error + std::marker::Send + Sync + 'static>,
>,
> + 'ctx;
fn handle_event<'ctx>(
&'ctx mut self,
_objects: &'ctx mut <Ctx as Client>::ObjectStore,
connection: &'ctx mut <Ctx as Client>::Connection,
_server_context: &'ctx <Ctx as Client>::ServerContext,
message: &'ctx mut Self::Message,
) -> Self::Future<'ctx> {
async move {
use crate::client::traits::StoreUpdateKind::*;
if matches!(message.kind, Removed { .. } | Replaced { .. }) {
connection
.send(DISPLAY_ID, wl_display::v1::events::DeleteId {
id: message.object_id,
})
.await?;
}
Ok(EventHandlerAction::Keep)
}
}
}
event_dispatcher.add_event_handler(objects.subscribe(), DisplayEventHandler);
futures_util::future::ok(())
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct Registry;
impl MonoGlobal for Registry {
type Object = crate::objects::Registry;
const INTERFACE: &'static str = wl_registry::NAME;
const MAYBE_DEFAULT: Option<Self> = Some(Self);
const VERSION: u32 = wl_registry::VERSION;
#[inline]
fn new_object() -> Self::Object {
crate::objects::Registry(None)
}
}
impl<Ctx: Client> Bind<Ctx> for Registry {
type BindFut<'a> = impl Future<Output = std::io::Result<()>> + 'a where Self: 'a, Ctx: 'a;
fn bind<'a>(&'a self, client: &'a mut Ctx, object_id: u32) -> Self::BindFut<'a> {
async move {
let ClientParts {
server_context,
connection,
event_dispatcher,
..
} = client.as_mut_parts();
let rx = server_context.globals().borrow().subscribe();
let globals: Vec<_> = server_context
.globals()
.borrow()
.iter()
.map(|(id, global)| (id, global.clone()))
.collect();
for (id, global) in globals {
let interface = global.interface();
let version = global.version();
connection
.send(object_id, wl_registry::events::Global {
name: id,
interface: interface.as_bytes().into(),
version,
})
.await
.unwrap()
}
connection.flush().await.unwrap();
event_dispatcher.add_event_handler(rx, RegistryEventHandler {
registry_id: object_id,
});
Ok(())
}
}
}
struct RegistryEventHandler {
registry_id: u32,
}
impl<Ctx: Client> EventHandler<Ctx> for RegistryEventHandler {
type Message = GlobalsUpdate<<Ctx::ServerContext as Server>::Global>;
type Future<'ctx> = impl Future<
Output = Result<
EventHandlerAction,
Box<dyn std::error::Error + std::marker::Send + Sync + 'static>,
>,
> + 'ctx;
fn handle_event<'ctx>(
&'ctx mut self,
_objects: &'ctx mut Ctx::ObjectStore,
connection: &'ctx mut Ctx::Connection,
_server_context: &'ctx Ctx::ServerContext,
message: &'ctx mut Self::Message,
) -> Self::Future<'ctx> {
async move {
let mut connection = Pin::new(connection);
match message {
GlobalsUpdate::Removed(name) => {
connection
.send(self.registry_id, wl_registry::events::GlobalRemove {
name: *name,
})
.await?;
},
GlobalsUpdate::Added(name, global) => {
let interface = global.interface();
let version = global.version();
connection
.send(self.registry_id, wl_registry::events::Global {
name: *name,
interface: interface.as_bytes().into(),
version,
})
.await?;
},
}
Ok(EventHandlerAction::Keep)
}
}
}