use std::io::Result;
use std::rc::Rc;
use std::{cell::RefCell, fmt};
use wayland_client::{
protocol::{wl_display, wl_registry},
Attached, DispatchData, EventQueue, GlobalEvent, GlobalManager, Interface, Proxy,
};
pub trait GlobalHandler<I: Interface> {
fn created(
&mut self,
registry: Attached<wl_registry::WlRegistry>,
id: u32,
version: u32,
ddata: DispatchData,
);
fn get(&self) -> Option<Attached<I>>;
}
pub trait MultiGlobalHandler<I: Interface> {
fn created(
&mut self,
registry: Attached<wl_registry::WlRegistry>,
id: u32,
version: u32,
ddata: DispatchData,
);
fn removed(&mut self, id: u32, ddata: DispatchData);
fn get_all(&self) -> Vec<Attached<I>>;
}
pub struct Environment<E> {
pub manager: GlobalManager,
inner: Rc<RefCell<E>>,
}
impl<E: InnerEnv + 'static> Environment<E> {
pub fn new(
display: &Attached<wl_display::WlDisplay>,
queue: &mut EventQueue,
env: E,
) -> Result<Environment<E>> {
let environment = Self::new_pending(display, env);
queue.sync_roundtrip(&mut (), |event, _, _| {
panic!(
"Encountered unhandled event during initial roundtrip ({}::{})",
event.interface, event.name
);
})?;
queue.sync_roundtrip(&mut (), |event, _, _| {
panic!(
"Encountered unhandled event during initial roundtrip ({}::{})",
event.interface, event.name
);
})?;
Ok(environment)
}
pub fn new_pending(display: &Attached<wl_display::WlDisplay>, env: E) -> Environment<E> {
let inner = Rc::new(RefCell::new(env));
let my_inner = inner.clone();
let my_cb = move |event, registry, ddata: DispatchData| {
let mut inner = my_inner.borrow_mut();
inner.process_event(event, registry, ddata);
};
let manager = GlobalManager::new_with_cb(display, my_cb);
Self { manager, inner }
}
}
impl<E> Environment<E> {
pub fn get_global<I: Interface>(&self) -> Option<Attached<I>>
where
E: GlobalHandler<I>,
{
self.inner.borrow().get()
}
pub fn require_global<I: Interface>(&self) -> Attached<I>
where
E: GlobalHandler<I>,
{
match self.inner.borrow().get() {
Some(g) => g,
None => panic!("[SCTK] A missing global was required: {}", I::NAME),
}
}
pub fn get_all_globals<I: Interface>(&self) -> Vec<Attached<I>>
where
E: MultiGlobalHandler<I>,
{
self.inner.borrow().get_all()
}
pub fn with_inner<T, F: FnOnce(&mut E) -> T>(&self, f: F) -> T {
let mut inner = self.inner.borrow_mut();
f(&mut *inner)
}
}
impl<E> Clone for Environment<E> {
fn clone(&self) -> Environment<E> {
Environment { manager: self.manager.clone(), inner: self.inner.clone() }
}
}
impl<E> fmt::Debug for Environment<E>
where
E: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Environment")
.field("manager", &self.manager)
.field("inner", &self.inner)
.finish()
}
}
pub trait InnerEnv {
fn process_event(
&mut self,
event: GlobalEvent,
registry: Attached<wl_registry::WlRegistry>,
data: DispatchData,
);
}
#[derive(Debug)]
pub struct SimpleGlobal<I: Interface> {
global: Option<Attached<I>>,
}
impl<I: Interface> SimpleGlobal<I> {
pub fn new() -> SimpleGlobal<I> {
SimpleGlobal { global: None }
}
}
impl<I: Interface + Clone + From<Proxy<I>> + AsRef<Proxy<I>>> GlobalHandler<I> for SimpleGlobal<I> {
fn created(
&mut self,
registry: Attached<wl_registry::WlRegistry>,
id: u32,
version: u32,
_: DispatchData,
) {
self.global = Some((*registry.bind::<I>(version, id)).clone())
}
fn get(&self) -> Option<Attached<I>> {
self.global.clone()
}
}
#[macro_export]
macro_rules! environment {
($env_name:ident,
singles = [$($sty:ty => $sname:ident),* $(,)?],
multis = [$($mty:ty => $mname:ident),* $(,)?]$(,)?
) => {
impl $crate::environment::InnerEnv for $env_name {
fn process_event(
&mut self,
event: $crate::reexports::client::GlobalEvent,
registry: $crate::reexports::client::Attached<$crate::reexports::client::protocol::wl_registry::WlRegistry>,
ddata: $crate::reexports::client::DispatchData,
) {
match event {
$crate::reexports::client::GlobalEvent::New { id, interface, version } => match &interface[..] {
$(
<$sty as $crate::reexports::client::Interface>::NAME => $crate::environment::GlobalHandler::<$sty>::created(&mut self.$sname, registry, id, version, ddata),
)*
$(
<$mty as $crate::reexports::client::Interface>::NAME => $crate::environment::MultiGlobalHandler::<$mty>::created(&mut self.$mname, registry, id, version, ddata),
)*
_ => { }
},
$crate::reexports::client::GlobalEvent::Removed { id, interface } => match &interface[..] {
$(
<$mty as $crate::reexports::client::Interface>::NAME => $crate::environment::MultiGlobalHandler::<$mty>::removed(&mut self.$mname, id, ddata),
)*
_ => { }
}
}
}
}
$(
impl $crate::environment::GlobalHandler<$sty> for $env_name {
fn created(&mut self, registry: $crate::reexports::client::Attached<$crate::reexports::client::protocol::wl_registry::WlRegistry>, id: u32, version: u32, ddata: $crate::reexports::client::DispatchData) {
$crate::environment::GlobalHandler::<$sty>::created(&mut self.$sname, registry, id, version, ddata)
}
fn get(&self) -> Option<$crate::reexports::client::Attached<$sty>> {
$crate::environment::GlobalHandler::<$sty>::get(&self.$sname)
}
}
)*
$(
impl $crate::environment::MultiGlobalHandler<$mty> for $env_name {
fn created(&mut self, registry: $crate::reexports::client::Attached<$crate::reexports::client::protocol::wl_registry::WlRegistry>, id: u32, version: u32, ddata: $crate::reexports::client::DispatchData) {
$crate::environment::MultiGlobalHandler::<$mty>::created(&mut self.$mname, registry, id, version, ddata)
}
fn removed(&mut self, id: u32, ddata: $crate::reexports::client::DispatchData) {
$crate::environment::MultiGlobalHandler::<$mty>::removed(&mut self.$mname, id, ddata)
}
fn get_all(&self) -> Vec<$crate::reexports::client::Attached<$mty>> {
$crate::environment::MultiGlobalHandler::<$mty>::get_all(&self.$mname)
}
}
)*
};
}