use {Implementable, 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};
pub use token_store::{Store as State, StoreProxy as StateProxy, Token as StateToken};
use wayland_sys::RUST_MANAGED;
use wayland_sys::client::*;
use wayland_sys::common::*;
type ProxyUserData = (
*mut EventQueueHandle,
Option<Box<Any>>,
Arc<(AtomicBool, AtomicPtr<()>)>,
);
pub enum RegisterStatus {
Registered,
Unmanaged,
Dead,
}
pub struct EventQueueHandle {
state: State,
wlevq: Option<*mut wl_event_queue>,
}
impl EventQueueHandle {
pub fn register<P, ID>(&mut self, proxy: &P, implementation: P::Implementation, idata: ID)
-> RegisterStatus
where
P: Proxy + Implementable<ID>,
ID: 'static,
{
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 = Some(Box::new((implementation, idata)) as Box<Any>);
ffi_dispatch!(
WAYLAND_CLIENT_HANDLE,
wl_proxy_add_dispatcher,
proxy.ptr(),
dispatch_func::<P, ID>,
&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
}
pub fn state(&mut self) -> &mut State {
&mut self.state
}
}
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 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
}
}
}
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 {
state: State::new(),
wlevq: evq,
}),
}
}
unsafe extern "C" fn dispatch_func<P, ID>(_impl: *const c_void, proxy: *mut c_void, opcode: u32,
_msg: *const wl_message, args: *const wl_argument)
-> c_int
where
P: Proxy + Implementable<ID>,
ID: 'static,
{
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);
proxy.__dispatch_msg(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();
}
}
}