use std::ffi::CStr;
use std::sync::{Arc, Mutex};
use libc::{c_void, c_char, uint32_t};
use super::{From, Compositor, Display, Output, Seat, Shell, Shm, SubCompositor};
use ffi::interfaces::display::wl_display_get_registry;
use ffi::interfaces::registry::{wl_registry, wl_registry_destroy,
wl_registry_listener, wl_registry_add_listener,
wl_registry_bind};
use ffi::{FFI, Bind};
struct RegistryData {
global_objects: Vec<(u32, String, u32)>,
}
impl RegistryData {
fn new() -> RegistryData {
RegistryData {
global_objects: Vec::new(),
}
}
fn register_object(&mut self, id: u32, interface: &[u8], version: u32) {
self.global_objects.push(
(id, String::from_utf8_lossy(interface).into_owned(), version)
);
}
fn unregister_object(&mut self, id: u32) {
match self.global_objects.iter().position(|e| e.0 == id) {
Some(i) => { self.global_objects.swap_remove(i); },
None => {}
}
}
fn get_objects_with_interface(&self, interface: &str) -> Vec<(u32, u32)> {
self.global_objects.iter().filter_map(|&(id, ref iface, v)| {
if iface == interface {
Some((id, v))
} else {
None
}
}).collect()
}
}
struct RegistryListener {
global_handler: Box<Fn(u32, &[u8], u32, &mut RegistryData)>,
global_remover: Box<Fn(u32, &mut RegistryData)>,
data: Mutex<RegistryData>
}
impl RegistryListener {
fn default_handlers(data: RegistryData) -> RegistryListener {
RegistryListener {
global_handler: Box::new(move |id, interface, version, data| {
data.register_object(id, interface, version);
}),
global_remover: Box::new(move |id, data| {
data.unregister_object(id);
}),
data: Mutex::new(data)
}
}
}
struct RegistryInternal {
pub display: Display,
pub ptr: *mut wl_registry,
pub listener: Box<RegistryListener>,
}
unsafe impl Send for RegistryInternal {}
#[derive(Clone)]
pub struct Registry {
internal: Arc<Mutex<RegistryInternal>>
}
impl Registry{
pub fn get_display(&self) -> Display {
self.internal.lock().unwrap().display.clone()
}
pub fn get_global_objects(&self) -> Vec<(u32, String, u32)> {
let internal = self.internal.lock().unwrap();
let v = internal.listener.data.lock().unwrap().global_objects.clone();
v
}
pub fn get_objects_with_interface(&self, interface: &str) -> Vec<(u32, u32)> {
let internal = self.internal.lock().unwrap();
let data = internal.listener.data.lock().unwrap();
data.get_objects_with_interface(interface)
}
pub fn get_compositor(&self) -> Option<Compositor> {
self.bind_with_interface("wl_compositor").into_iter().next()
}
pub fn get_outputs(&self) -> Vec<Output> {
self.bind_with_interface("wl_output")
}
pub fn get_seats(&self) -> Vec<Seat> {
self.bind_with_interface("wl_seat")
}
pub fn get_shell(&self) -> Option<Shell> {
self.bind_with_interface("wl_shell").into_iter().next()
}
pub fn get_shm(&self) -> Option<Shm> {
self.bind_with_interface("wl_shm").into_iter().next()
}
pub fn get_subcompositor(&self) -> Option<SubCompositor> {
self.bind_with_interface("wl_subcompositor").into_iter().next()
}
pub unsafe fn bind<T>(&self, id: u32, version: u32) -> T
where T: Bind<Registry>
{
let ptr = wl_registry_bind(
self.internal.lock().unwrap().ptr,
id,
<T as Bind<Registry>>::interface(),
version
);
<T as Bind<Registry>>::wrap(ptr as *mut _, self.clone())
}
fn bind_with_interface<T>(&self, interface: &str) -> Vec<T>
where T: Bind<Registry>
{
let internal = self.internal.lock().unwrap();
let data = internal.listener.data.lock().unwrap();
let v = data.get_objects_with_interface(interface);
v.into_iter().map(|(id, version)| {
unsafe {
let ptr = wl_registry_bind(
internal.ptr,
id,
<T as Bind<Registry>>::interface(),
version
);
<T as Bind<Registry>>::wrap(ptr as *mut _, self.clone())
}
}).collect()
}
}
impl From<Display> for Registry {
fn from(display: Display) -> Registry {
let ptr = unsafe { wl_display_get_registry(display.ptr_mut()) };
let listener = RegistryListener::default_handlers(RegistryData::new());
let r = Registry {
internal : Arc::new(Mutex::new(RegistryInternal {
display: display,
ptr: ptr,
listener: Box::new(listener)
}))
};
{
let internal = r.internal.lock().unwrap();
unsafe {
wl_registry_add_listener(
internal.ptr,
®ISTRY_LISTENER as *const _,
&*internal.listener as *const _ as *mut _
)
};
}
r
}
}
impl Drop for RegistryInternal {
fn drop(&mut self) {
unsafe { wl_registry_destroy(self.ptr) };
}
}
impl FFI for Registry {
type Ptr = wl_registry;
fn ptr(&self) -> *const wl_registry {
self.internal.lock().unwrap().ptr as *const wl_registry
}
unsafe fn ptr_mut(&self) -> *mut wl_registry {
self.internal.lock().unwrap().ptr
}
}
extern "C" fn registry_global_handler(data: *mut c_void,
_registry: *mut wl_registry,
name: uint32_t,
interface: *const c_char,
version: uint32_t
) {
let listener = unsafe { &*(data as *const RegistryListener) };
let interface_str = unsafe { CStr::from_ptr(interface) };
let mut data = listener.data.lock().unwrap();
(listener.global_handler)(name, interface_str.to_bytes(), version, &mut *data);
}
extern "C" fn registry_global_remover(data: *mut c_void,
_registry: *mut wl_registry,
name: uint32_t
) {
let listener = unsafe { &*(data as *const RegistryListener) };
let mut data = listener.data.lock().unwrap();
(listener.global_remover)(name, &mut *data);
}
static REGISTRY_LISTENER: wl_registry_listener = wl_registry_listener {
global: registry_global_handler,
global_remove: registry_global_remover
};