use {Handler, Proxy};
use std::any::Any;
use std::io::{Error as IoError, Result as IoResult};
use std::io::Write;
use std::ops::{Deref, DerefMut};
use std::os::raw::{c_int, c_void};
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, AtomicPtr};
use wayland_sys::RUST_MANAGED;
use wayland_sys::client::*;
use wayland_sys::common::*;
type ProxyUserData = (*mut EventQueueHandle, *mut c_void, Arc<(AtomicBool, AtomicPtr<()>)>);
pub enum RegisterStatus {
Registered,
Unmanaged,
Dead,
}
pub struct EventQueueHandle {
handlers: Vec<Option<Box<Any + Send>>>,
wlevq: Option<*mut wl_event_queue>,
}
pub trait Init {
fn init(&mut self, evqh: &mut EventQueueHandle, index: usize);
}
impl EventQueueHandle {
pub fn register<P, H>(&mut self, proxy: &P, handler_id: usize) -> RegisterStatus
where
P: Proxy,
H: Handler<P> + Any + Send + 'static,
{
let h = self.handlers[handler_id]
.as_ref()
.expect("Handler has already been removed.")
.downcast_ref::<H>()
.expect("Handler type do not match.");
match proxy.status() {
::Liveness::Dead => return RegisterStatus::Dead,
::Liveness::Unmanaged => return RegisterStatus::Unmanaged,
::Liveness::Alive => { }
}
unsafe {
let data: *mut ProxyUserData =
ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_get_user_data, proxy.ptr()) as *mut _;
(&mut *data).0 = self as *const _ as *mut _;
(&mut *data).1 = h as *const _ as *mut c_void;
ffi_dispatch!(
WAYLAND_CLIENT_HANDLE,
wl_proxy_add_dispatcher,
proxy.ptr(),
dispatch_func::<P, H>,
&RUST_MANAGED as *const _ as *const _,
data as *mut c_void
);
ffi_dispatch!(
WAYLAND_CLIENT_HANDLE,
wl_proxy_set_queue,
proxy.ptr(),
match self.wlevq {
Some(ptr) => ptr,
None => ::std::ptr::null_mut(),
}
);
}
RegisterStatus::Registered
}
fn insert_handler(&mut self, h: Box<Any + Send>) -> usize {
{
let empty_slot = self.handlers.iter_mut().enumerate().find(|&(_, ref s)| {
s.is_none()
});
if let Some((id, slot)) = empty_slot {
*slot = Some(h);
return id;
}
}
self.handlers.push(Some(h));
self.handlers.len() - 1
}
pub fn add_handler<H: Any + Send + 'static>(&mut self, handler: H) -> usize {
self.insert_handler(Box::new(handler) as Box<Any + Send>)
}
pub fn add_handler_with_init<H: Init + Any + Send + 'static>(&mut self, handler: H) -> usize {
let mut box_ = Box::new(handler);
let h = &mut *box_ as *mut H;
let index = self.insert_handler(box_ as Box<Any + Send>);
unsafe { (&mut *h).init(self, index) };
index
}
pub unsafe fn remove_handler<H: Any + Send + 'static>(&mut self, idx: usize) -> H {
let is_type = self.handlers[idx]
.as_ref()
.expect("Handler has already been removed.")
.is::<H>();
assert!(is_type, "Handler type do not match.");
*(self.handlers[idx].take().unwrap().downcast().unwrap())
}
}
pub struct StateGuard<'evq> {
evq: &'evq mut EventQueue,
}
impl<'evq> StateGuard<'evq> {
pub fn get_handler<H: Any + 'static>(&self, handler_id: usize) -> &H {
self.evq.handle.handlers[handler_id]
.as_ref()
.expect("Handler has already been removed")
.downcast_ref::<H>()
.expect("Handler type do not match.")
}
pub fn get_mut_handler<H: Any + 'static>(&mut self, handler_id: usize) -> &mut H {
self.evq.handle.handlers[handler_id]
.as_mut()
.expect("Handler has already been removed")
.downcast_mut::<H>()
.expect("Handler type do not match.")
}
}
pub struct EventQueue {
handle: Box<EventQueueHandle>,
display: *mut wl_display,
}
impl EventQueue {
pub fn dispatch(&mut self) -> IoResult<u32> {
let ret = match self.handle.wlevq {
Some(evq) => unsafe {
ffi_dispatch!(
WAYLAND_CLIENT_HANDLE,
wl_display_dispatch_queue,
self.display,
evq
)
},
None => unsafe { ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_display_dispatch, self.display) },
};
if ret >= 0 {
Ok(ret as u32)
} else {
Err(IoError::last_os_error())
}
}
pub fn dispatch_pending(&mut self) -> IoResult<u32> {
let ret = match self.handle.wlevq {
Some(evq) => unsafe {
ffi_dispatch!(
WAYLAND_CLIENT_HANDLE,
wl_display_dispatch_queue_pending,
self.display,
evq
)
},
None => unsafe {
ffi_dispatch!(
WAYLAND_CLIENT_HANDLE,
wl_display_dispatch_pending,
self.display
)
},
};
if ret >= 0 {
Ok(ret as u32)
} else {
Err(IoError::last_os_error())
}
}
pub fn sync_roundtrip(&mut self) -> IoResult<i32> {
let ret = unsafe {
match self.handle.wlevq {
Some(evtq) => {
ffi_dispatch!(
WAYLAND_CLIENT_HANDLE,
wl_display_roundtrip_queue,
self.display,
evtq
)
}
None => ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_display_roundtrip, self.display),
}
};
if ret >= 0 {
Ok(ret)
} else {
Err(IoError::last_os_error())
}
}
pub fn state(&mut self) -> StateGuard {
StateGuard { evq: self }
}
pub fn prepare_read(&self) -> Option<ReadEventsGuard> {
let ret = unsafe {
match self.handle.wlevq {
Some(evtq) => {
ffi_dispatch!(
WAYLAND_CLIENT_HANDLE,
wl_display_prepare_read_queue,
self.display,
evtq
)
}
None => ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_display_prepare_read, self.display),
}
};
if ret >= 0 {
Some(ReadEventsGuard { display: self.display })
} else {
None
}
}
}
unsafe impl Send for EventQueue {}
impl Deref for EventQueue {
type Target = EventQueueHandle;
fn deref(&self) -> &EventQueueHandle {
&*self.handle
}
}
impl DerefMut for EventQueue {
fn deref_mut(&mut self) -> &mut EventQueueHandle {
&mut *self.handle
}
}
pub struct ReadEventsGuard {
display: *mut wl_display,
}
impl ReadEventsGuard {
pub fn read_events(self) -> IoResult<i32> {
let ret = unsafe { ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_display_read_events, self.display) };
::std::mem::forget(self);
if ret >= 0 {
Ok(ret)
} else {
Err(IoError::last_os_error())
}
}
pub fn cancel(self) {
}
}
impl Drop for ReadEventsGuard {
fn drop(&mut self) {
unsafe { ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_display_cancel_read, self.display) }
}
}
pub unsafe fn create_event_queue(display: *mut wl_display, evq: Option<*mut wl_event_queue>) -> EventQueue {
EventQueue {
display: display,
handle: Box::new(EventQueueHandle {
handlers: Vec::new(),
wlevq: evq,
}),
}
}
unsafe extern "C" fn dispatch_func<P: Proxy, H: Handler<P>>(_impl: *const c_void, proxy: *mut c_void,
opcode: u32, _msg: *const wl_message,
args: *const wl_argument)
-> c_int {
if _impl != &RUST_MANAGED as *const _ as *const _ {
let _ = write!(
::std::io::stderr(),
"[wayland-client error] Dispatcher got called for a message on a non-managed object."
);
::libc::abort();
}
let ret = ::std::panic::catch_unwind(move || {
let proxy = P::from_ptr_initialized(proxy as *mut wl_proxy);
let data = &mut *(ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_get_user_data, proxy.ptr()) as
*mut ProxyUserData);
let evqhandle = &mut *data.0;
let handler = &mut *(data.1 as *mut H);
handler.message(evqhandle, &proxy, opcode, args)
});
match ret {
Ok(Ok(())) => return 0, Ok(Err(())) => {
let _ = write!(
::std::io::stderr(),
"[wayland-client error] Attempted to dispatch unknown opcode {} for {}, aborting.",
opcode, P::interface_name()
);
::libc::abort();
}
Err(_) => {
let _ = write!(
::std::io::stderr(),
"[wayland-client error] A handler for {} panicked, aborting.",
P::interface_name()
);
::libc::abort();
}
}
}
#[macro_export]
macro_rules! client_declare_handler(
($handler_struct: ident <$($tyarg:ident : [$($trait: ident $(<$($traitarg:ty),*>)*),*]),*>, $handler_trait: path, $handled_type: ty) => {
unsafe impl<$($tyarg : $($trait $(<$($traitarg),*>)* +)* 'static),*> $crate::Handler<$handled_type> for $handler_struct<$($tyarg),*> {
unsafe fn message(&mut self,
evq: &mut $crate::EventQueueHandle,
proxy: &$handled_type,
opcode: u32,
args: *const $crate::sys::wl_argument
) -> ::std::result::Result<(),()> {
<$handler_trait>::__message(self, evq, proxy, opcode, args)
}
}
};
($handler_struct: ident, $handler_trait: path, $handled_type: ty) => {
unsafe impl $crate::Handler<$handled_type> for $handler_struct {
unsafe fn message(&mut self,
evq: &mut $crate::EventQueueHandle,
proxy: &$handled_type,
opcode: u32,
args: *const $crate::sys::wl_argument
) -> ::std::result::Result<(),()> {
<$handler_trait>::__message(self, evq, proxy, opcode, args)
}
}
};
);
#[macro_export]
macro_rules! declare_handler(
($handler_struct: ident <$($tyarg:ident : [$($trait: ident $(<$($traitarg:ty),*>)*),*]),*>, $handler_trait: path, $handled_type: ty) => {
client_declare_handler!($handler_struct<$($tyarg: [$($trait $(<$($traitarg),*>)*),*]),*>, $handler_trait, $handled_type);
};
($handler_struct: ident, $handler_trait: path, $handled_type: ty) => {
client_declare_handler!($handler_struct, $handler_trait, $handled_type);
};
);
#[macro_export]
macro_rules! client_declare_delegating_handler(
($handler_struct: ident <$($tyarg:ident : [$($trait: ident $(<$($traitarg:ty),*>)*),*]),*>, $($handler_field: ident).+ , $handler_trait: path, $handled_type: ty) => {
unsafe impl<$($tyarg : $($trait $(<$($traitarg),*>)* +)* 'static),*> $crate::Handler<$handled_type> for $handler_struct<$($tyarg),*> {
unsafe fn message(&mut self,
evq: &mut $crate::EventQueueHandle,
proxy: &$handled_type,
opcode: u32,
args: *const $crate::sys::wl_argument
) -> ::std::result::Result<(),()> {
<$handler_trait>::__message(&mut self.$($handler_field).+, evq, proxy, opcode, args)
}
}
};
($handler_struct: ident, $($handler_field: ident).+ , $handler_trait: path, $handled_type: ty) => {
unsafe impl $crate::Handler<$handled_type> for $handler_struct {
unsafe fn message(&mut self,
evq: &mut $crate::EventQueueHandle,
proxy: &$handled_type,
opcode: u32,
args: *const $crate::sys::wl_argument
) -> ::std::result::Result<(),()> {
<$handler_trait>::__message(&mut self.$($handler_field).+, evq, proxy, opcode, args)
}
}
};
);
#[macro_export]
macro_rules! declare_delegating_handler(
($handler_struct: ident <$($tyarg:ident : [$($trait: ident $(<$($traitarg:ty),*>)*),*]),*>, $($handler_field: ident).+ , $handler_trait: path, $handled_type: ty) => {
client_declare_delegating_handler!($handler_struct<$($tyarg: [$($trait $(<$($traitarg),*>)*),*]),*>, $($handler_field).+, $handler_trait, $handled_type);
};
($handler_struct: ident, $($handler_field: ident).+ , $handler_trait: path, $handled_type: ty) => {
client_declare_delegating_handler!($handler_struct, $($handler_field).+, $handler_trait, $handled_type);
};
);