use {EventQueueHandle, StateToken};
use protocol::wl_registry::{Implementation, WlRegistry};
#[doc(hidden)]
pub trait EnvHandlerInner: Sized {
fn create(&WlRegistry, &[(u32, String, u32)]) -> Option<Self>;
fn clone_env(&self) -> Self;
}
pub struct EnvHandler<H: EnvHandlerInner> {
globals: Vec<(u32, String, u32)>,
inner: Option<H>,
}
impl<H: EnvHandlerInner + 'static> EnvHandler<H> {
pub fn init(evqh: &mut EventQueueHandle, registry: &WlRegistry) -> StateToken<EnvHandler<H>> {
let token = {
let state = evqh.state();
state.insert(EnvHandler {
globals: Vec::new(),
inner: None,
})
};
evqh.register(registry, env_handler_impl(), token.clone());
token
}
pub fn init_with_notify<ID: 'static>(evqh: &mut EventQueueHandle, registry: &WlRegistry,
notify: EnvNotify<ID>, idata: ID)
-> StateToken<EnvHandler<H>> {
let token = {
let state = evqh.state();
state.insert(EnvHandler {
globals: Vec::new(),
inner: None,
})
};
evqh.register(
registry,
env_handler_impl_notify(),
(token.clone(), (notify, idata)),
);
token
}
pub fn ready(&self) -> bool {
self.inner.is_some()
}
pub fn globals(&self) -> &[(u32, String, u32)] {
&self.globals
}
pub fn clone_inner(&self) -> Option<H> {
self.inner.as_ref().map(|h| h.clone_env())
}
fn try_make_ready(&mut self, registry: &WlRegistry) -> bool {
if self.inner.is_some() {
return false;
}
self.inner = H::create(registry, &self.globals);
self.ready()
}
}
impl<H: EnvHandlerInner> ::std::ops::Deref for EnvHandler<H> {
type Target = H;
fn deref(&self) -> &H {
self.inner
.as_ref()
.expect("Tried to get contents of a not-ready EnvHandler.")
}
}
fn env_handler_impl<H: EnvHandlerInner + 'static>() -> Implementation<StateToken<EnvHandler<H>>> {
Implementation {
global: |evqh, token, registry, name, interface, version| {
let state = evqh.state();
let me = state.get_mut(token);
me.globals.push((name, interface, version));
me.try_make_ready(registry);
},
global_remove: |evqh, token, _, name| {
let state = evqh.state();
let me = state.get_mut(token);
me.globals.retain(|&(i, _, _)| i != name)
},
}
}
fn env_handler_impl_notify<H: EnvHandlerInner + 'static, ID: 'static>(
)
-> Implementation<(StateToken<EnvHandler<H>>, (EnvNotify<ID>, ID))>
{
Implementation {
global: |evqh, &mut (ref token, (ref implem, ref mut idata)), registry, name, interface, version| {
(implem.new_global)(evqh, idata, registry, name, &interface, version);
let became_ready = {
let state = evqh.state();
let me = state.get_mut(token);
me.globals.push((name, interface, version));
me.try_make_ready(registry)
};
if became_ready {
(implem.ready)(evqh, idata, registry);
}
},
global_remove: |evqh, &mut (ref token, (ref implem, ref mut idata)), registry, name| {
(implem.del_global)(evqh, idata, registry, name);
let state = evqh.state();
let me = state.get_mut(token);
me.globals.retain(|&(i, _, _)| i != name);
},
}
}
pub struct EnvNotify<ID> {
pub new_global: fn(
evqh: &mut EventQueueHandle,
idata: &mut ID,
registry: &WlRegistry,
id: u32,
interface: &str,
version: u32,
),
pub del_global: fn(evqh: &mut EventQueueHandle, idata: &mut ID, registry: &WlRegistry, id: u32),
pub ready: fn(evqh: &mut EventQueueHandle, idata: &mut ID, registry: &WlRegistry),
}
#[macro_export]
macro_rules! wayland_env(
(pub $name: ident) => {
pub struct $name;
impl $crate::EnvHandlerInner for $name {
fn create(_registry: &$crate::protocol::wl_registry::WlRegistry, _globals: &[(u32, String, u32)]) -> Option<$name> {
Some($name)
}
fn clone_env(&self) -> $name {
$name
}
}
};
(pub $name: ident, $($global_name: ident : $global_type: path),+) => {
pub struct $name {
$(
pub $global_name: $global_type
),+
}
wayland_env!(__impl $name, $($global_name : $global_type),+);
};
($name: ident) => {
struct $name;
impl $crate::EnvHandlerInner for $name {
fn create(_registry: &$crate::protocol::wl_registry::WlRegistry, _globals: &[(u32, String, u32)]) -> Option<$name> {
Some($name)
}
fn clone_env(&self) -> $name {
$name
}
}
};
($name: ident, $($global_name: ident : $global_type: path),+) => {
struct $name {
$(
pub $global_name: $global_type
),+
}
wayland_env!(__impl $name, $($global_name : $global_type),+);
};
(__impl $name: ident, $($global_name: ident : $global_type: path),+) => {
impl $crate::EnvHandlerInner for $name {
fn create(registry: &$crate::protocol::wl_registry::WlRegistry, globals: &[(u32, String, u32)]) -> Option<$name> {
let mut need = 0usize;
$(
let _ = stringify!($global_name);
need += 1;
)+
if need > globals.len() { return None }
let mut my_globals: Vec<(u32, &str, u32)> = globals.iter().map(|&(i,ref n,v)| (i,&n[..],v)).collect();
$(
let $global_name = {
let iname = <$global_type as $crate::Proxy>::interface_name();
let index = my_globals.iter().position(|&(_,name,_)| name == iname);
match index {
None => return None,
Some(i) => my_globals.swap_remove(i)
}
};
)*
$(
let $global_name = {
let (id, _, v) = $global_name;
let version = ::std::cmp::min(v, <$global_type as $crate::Proxy>::supported_version());
registry.bind::<$global_type>(version, id)
};
)+
Some($name {
$(
$global_name: $global_name
),+
})
}
fn clone_env(&self) -> $name {
$name {
$(
$global_name: $crate::Proxy::clone(&self.$global_name).unwrap()
),+
}
}
}
};
);