use std::sync::{Arc, Mutex};
use commons::{Implementation, Interface};
use {NewProxy, Proxy};
use protocol::wl_registry::{self, RequestsTrait};
struct Inner {
list: Vec<(u32, String, u32)>,
callback: Box<Implementation<Proxy<wl_registry::WlRegistry>, GlobalEvent> + Send>,
}
pub struct GlobalManager {
inner: Arc<Mutex<Inner>>,
registry: Proxy<wl_registry::WlRegistry>,
}
#[derive(Debug)]
pub enum GlobalError {
Missing,
VersionTooLow(u32),
}
pub enum GlobalEvent {
New {
id: u32,
interface: String,
version: u32,
},
Removed {
id: u32,
interface: String,
},
}
impl GlobalManager {
pub fn new(registry: NewProxy<wl_registry::WlRegistry>) -> GlobalManager {
let inner = Arc::new(Mutex::new(Inner {
list: Vec::new(),
callback: Box::new(|_, _| {}),
}));
let inner_clone = inner.clone();
let registry = registry.implement(move |msg, _proxy| {
let mut inner = inner.lock().unwrap();
match msg {
wl_registry::Event::Global {
name,
interface,
version,
} => {
inner.list.push((name, interface, version));
}
wl_registry::Event::GlobalRemove { name } => {
inner.list.retain(|&(n, _, _)| n != name);
}
}
});
GlobalManager {
inner: inner_clone,
registry: registry,
}
}
pub fn new_with_cb<Impl>(registry: NewProxy<wl_registry::WlRegistry>, callback: Impl) -> GlobalManager
where
Impl: Implementation<Proxy<wl_registry::WlRegistry>, GlobalEvent> + Send + 'static,
{
let inner = Arc::new(Mutex::new(Inner {
list: Vec::new(),
callback: Box::new(callback),
}));
let inner_clone = inner.clone();
let registry = registry.implement(move |msg, proxy| {
let mut inner = inner.lock().unwrap();
match msg {
wl_registry::Event::Global {
name,
interface,
version,
} => {
inner.list.push((name, interface.clone(), version));
inner.callback.receive(
GlobalEvent::New {
id: name,
interface: interface,
version: version,
},
proxy,
);
}
wl_registry::Event::GlobalRemove { name } => {
if let Some((i, _)) = inner
.list
.iter()
.enumerate()
.find(|&(_, &(n, _, _))| n == name)
{
let (id, interface, _) = inner.list.swap_remove(i);
inner.callback.receive(
GlobalEvent::Removed {
id: id,
interface: interface,
},
proxy,
);
} else {
panic!(
"Wayland protocol error: the server removed non-existing global \"{}\".",
name
);
}
}
}
});
GlobalManager {
inner: inner_clone,
registry: registry,
}
}
pub fn instanciate_auto<I: Interface>(&self) -> Result<NewProxy<I>, GlobalError> {
let inner = self.inner.lock().unwrap();
for &(id, ref interface, version) in &inner.list {
if interface == I::NAME {
return Ok(self.registry.bind::<I>(version, id).unwrap());
}
}
Err(GlobalError::Missing)
}
pub fn instanciate_exact<I: Interface>(&self, version: u32) -> Result<NewProxy<I>, GlobalError> {
let inner = self.inner.lock().unwrap();
for &(id, ref interface, server_version) in &inner.list {
if interface == I::NAME {
if version > server_version {
return Err(GlobalError::VersionTooLow(server_version));
} else {
return Ok(self.registry.bind::<I>(version, id).unwrap());
}
}
}
Err(GlobalError::Missing)
}
pub fn list(&self) -> Vec<(u32, String, u32)> {
self.inner.lock().unwrap().list.clone()
}
}
#[macro_export]
macro_rules! global_filter {
($([$interface:ty, $version:expr, $callback:expr]),*) => {
{
use $crate::commons::{Implementation, Interface};
use $crate::protocol::wl_registry::{self, RequestsTrait};
use $crate::{Proxy, GlobalEvent, NewProxy};
type Callback = Box<Implementation<Proxy<wl_registry::WlRegistry>, (u32, u32)> + Send>;
let mut callbacks: Vec<(&'static str, Callback)> = Vec::new();
$({
let mut cb = { $callback };
fn typecheck<Impl: Implementation<(), Result<NewProxy<$interface>, u32>>>(_: &Impl) {}
typecheck(&cb);
callbacks.push((
<$interface as Interface>::NAME,
Box::new(move |(id, version), registry: Proxy<wl_registry::WlRegistry>| {
if version < $version {
cb.receive(Err(version), ())
} else {
cb.receive(Ok(registry.bind::<$interface>(version, id).unwrap()), ())
}
}) as Box<_>
));
})*
move |event: GlobalEvent, registry: Proxy<wl_registry::WlRegistry>| {
if let GlobalEvent::New { id, interface, version } = event {
for &mut (iface, ref mut cb) in &mut callbacks {
if iface == interface {
cb.receive((id, version), registry);
break;
}
}
}
}
}
}
}