use std::any::Any;
use std::collections::VecDeque;
use std::convert::Infallible;
use std::marker::PhantomData;
use std::sync::{atomic::Ordering, Arc, Condvar, Mutex};
use std::task;
use nix::Error;
use wayland_backend::{
client::{Backend, ObjectData, ObjectId, ReadEventsGuard, WaylandError},
io_lifetimes::OwnedFd,
protocol::{Argument, Message},
};
use crate::{conn::SyncData, Connection, DispatchError, Proxy};
pub trait Dispatch<I, UserData, State = Self>
where
Self: Sized,
I: Proxy,
State: Dispatch<I, UserData, State>,
{
fn event(
state: &mut State,
proxy: &I,
event: I::Event,
data: &UserData,
conn: &Connection,
qhandle: &QueueHandle<State>,
);
#[cfg_attr(coverage, no_coverage)]
fn event_created_child(opcode: u16, _qhandle: &QueueHandle<State>) -> Arc<dyn ObjectData> {
panic!(
"Missing event_created_child specialization for event opcode {} of {}",
opcode,
I::interface().name
);
}
}
#[macro_export]
macro_rules! event_created_child {
($(@< $( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+ >)? $selftype:ty, $iface:ty, [$($opcode:pat => ($child_iface:ty, $child_udata:expr)),* $(,)?]) => {
fn event_created_child(
opcode: u16,
qhandle: &$crate::QueueHandle<$selftype>
) -> std::sync::Arc<dyn $crate::backend::ObjectData> {
match opcode {
$(
$opcode => {
qhandle.make_data::<$child_iface, _>({$child_udata})
},
)*
_ => {
panic!("Missing event_created_child specialization for event opcode {} of {}", opcode, <$iface as $crate::Proxy>::interface().name);
},
}
}
};
}
type QueueCallback<State> = fn(
&Connection,
Message<ObjectId, OwnedFd>,
&mut State,
Arc<dyn ObjectData>,
&QueueHandle<State>,
) -> Result<(), DispatchError>;
struct QueueEvent<State>(QueueCallback<State>, Message<ObjectId, OwnedFd>, Arc<dyn ObjectData>);
impl<State> std::fmt::Debug for QueueEvent<State> {
#[cfg_attr(coverage, no_coverage)]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("QueueEvent").field("msg", &self.1).finish_non_exhaustive()
}
}
pub struct EventQueue<State> {
handle: QueueHandle<State>,
conn: Connection,
}
#[derive(Debug)]
pub(crate) struct EventQueueInner<State> {
queue: VecDeque<QueueEvent<State>>,
freeze_count: usize,
waker: Option<task::Waker>,
}
impl<State> EventQueueInner<State> {
pub(crate) fn enqueue_event<I, U>(
&mut self,
msg: Message<ObjectId, OwnedFd>,
odata: Arc<dyn ObjectData>,
) where
State: Dispatch<I, U> + 'static,
U: Send + Sync + 'static,
I: Proxy + 'static,
{
let func = queue_callback::<I, U, State>;
self.queue.push_back(QueueEvent(func, msg, odata));
if self.freeze_count == 0 {
if let Some(waker) = self.waker.take() {
waker.wake();
}
}
}
}
impl<State> std::fmt::Debug for EventQueue<State> {
#[cfg_attr(coverage, no_coverage)]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("EventQueue").field("handle", &self.handle).finish_non_exhaustive()
}
}
impl<State> EventQueue<State> {
pub(crate) fn new(conn: Connection) -> Self {
let inner = Arc::new(Mutex::new(EventQueueInner {
queue: VecDeque::new(),
freeze_count: 0,
waker: None,
}));
Self { handle: QueueHandle { inner }, conn }
}
pub fn handle(&self) -> QueueHandle<State> {
self.handle.clone()
}
pub fn dispatch_pending(&mut self, data: &mut State) -> Result<usize, DispatchError> {
Self::dispatching_impl(&self.conn, &self.handle, data)
}
pub fn blocking_dispatch(&mut self, data: &mut State) -> Result<usize, DispatchError> {
let dispatched = self.dispatch_pending(data)?;
if dispatched > 0 {
return Ok(dispatched);
}
self.conn.flush()?;
let guard = self.conn.prepare_read()?;
if self.handle.inner.lock().unwrap().queue.is_empty() {
crate::conn::blocking_read(guard)?;
} else {
drop(guard);
}
self.dispatch_pending(data)
}
pub fn roundtrip(&mut self, data: &mut State) -> Result<usize, DispatchError> {
let done = Arc::new(SyncData::default());
let display = self.conn.display();
self.conn
.send_request(
&display,
crate::protocol::wl_display::Request::Sync {},
Some(done.clone()),
)
.map_err(|_| WaylandError::Io(Error::EPIPE.into()))?;
let mut dispatched = 0;
while !done.done.load(Ordering::Relaxed) {
dispatched += self.blocking_dispatch(data)?;
}
Ok(dispatched)
}
pub fn prepare_read(&self) -> Result<ReadEventsGuard, WaylandError> {
self.conn.prepare_read()
}
pub fn flush(&self) -> Result<(), WaylandError> {
self.conn.flush()
}
fn dispatching_impl(
backend: &Connection,
qhandle: &QueueHandle<State>,
data: &mut State,
) -> Result<usize, DispatchError> {
let _ = backend.backend.dispatch_inner_queue();
let mut dispatched = 0;
while let Some(QueueEvent(cb, msg, odata)) = Self::try_next(&qhandle.inner) {
cb(backend, msg, data, odata, qhandle)?;
dispatched += 1;
}
Ok(dispatched)
}
fn try_next(inner: &Mutex<EventQueueInner<State>>) -> Option<QueueEvent<State>> {
let mut lock = inner.lock().unwrap();
if lock.freeze_count != 0 && !lock.queue.is_empty() {
let waker = Arc::new(DispatchWaker { cond: Condvar::new() });
while lock.freeze_count != 0 {
lock.waker = Some(waker.clone().into());
lock = waker.cond.wait(lock).unwrap();
}
}
lock.queue.pop_front()
}
pub fn poll_dispatch_pending(
&mut self,
cx: &mut task::Context,
data: &mut State,
) -> task::Poll<Result<Infallible, DispatchError>> {
loop {
if let Err(e) = self.conn.backend.dispatch_inner_queue() {
return task::Poll::Ready(Err(e.into()));
}
let mut lock = self.handle.inner.lock().unwrap();
if lock.freeze_count != 0 {
lock.waker = Some(cx.waker().clone());
return task::Poll::Pending;
}
let QueueEvent(cb, msg, odata) = if let Some(elt) = lock.queue.pop_front() {
elt
} else {
lock.waker = Some(cx.waker().clone());
return task::Poll::Pending;
};
drop(lock);
cb(&self.conn, msg, data, odata, &self.handle)?
}
}
}
struct DispatchWaker {
cond: Condvar,
}
impl task::Wake for DispatchWaker {
fn wake(self: Arc<Self>) {
self.cond.notify_all()
}
}
pub struct QueueHandle<State> {
pub(crate) inner: Arc<Mutex<EventQueueInner<State>>>,
}
#[derive(Debug)]
pub struct QueueFreezeGuard<'a, State> {
qh: &'a QueueHandle<State>,
}
impl<State> std::fmt::Debug for QueueHandle<State> {
#[cfg_attr(coverage, no_coverage)]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("QueueHandle").field("inner", &Arc::as_ptr(&self.inner)).finish()
}
}
impl<State> Clone for QueueHandle<State> {
fn clone(&self) -> Self {
Self { inner: self.inner.clone() }
}
}
impl<State: 'static> QueueHandle<State> {
pub fn make_data<I: Proxy + 'static, U: Send + Sync + 'static>(
&self,
user_data: U,
) -> Arc<dyn ObjectData>
where
State: Dispatch<I, U, State>,
{
Arc::new(QueueProxyData::<I, U, State> {
handle: self.clone(),
udata: user_data,
_phantom: PhantomData,
})
}
pub fn freeze(&self) -> QueueFreezeGuard<State> {
self.inner.lock().unwrap().freeze_count += 1;
QueueFreezeGuard { qh: self }
}
}
impl<'a, State> Drop for QueueFreezeGuard<'a, State> {
fn drop(&mut self) {
let mut lock = self.qh.inner.lock().unwrap();
lock.freeze_count -= 1;
if lock.freeze_count == 0 && !lock.queue.is_empty() {
if let Some(waker) = lock.waker.take() {
waker.wake();
}
}
}
}
fn queue_callback<
I: Proxy + 'static,
U: Send + Sync + 'static,
State: Dispatch<I, U, State> + 'static,
>(
handle: &Connection,
msg: Message<ObjectId, OwnedFd>,
data: &mut State,
odata: Arc<dyn ObjectData>,
qhandle: &QueueHandle<State>,
) -> Result<(), DispatchError> {
let (proxy, event) = I::parse_event(handle, msg)?;
let udata = odata.data_as_any().downcast_ref().expect("Wrong user_data value for object");
<State as Dispatch<I, U, State>>::event(data, &proxy, event, udata, handle, qhandle);
Ok(())
}
pub struct QueueProxyData<I: Proxy, U, State> {
handle: QueueHandle<State>,
pub udata: U,
_phantom: PhantomData<fn(&I)>,
}
impl<I: Proxy + 'static, U: Send + Sync + 'static, State> ObjectData for QueueProxyData<I, U, State>
where
State: Dispatch<I, U, State> + 'static,
{
fn event(
self: Arc<Self>,
_: &Backend,
msg: Message<ObjectId, OwnedFd>,
) -> Option<Arc<dyn ObjectData>> {
let new_data = msg
.args
.iter()
.any(|arg| matches!(arg, Argument::NewId(id) if !id.is_null()))
.then(|| State::event_created_child(msg.opcode, &self.handle));
self.handle.inner.lock().unwrap().enqueue_event::<I, U>(msg, self.clone());
new_data
}
fn destroyed(&self, _: ObjectId) {}
fn data_as_any(&self) -> &dyn Any {
&self.udata
}
}
impl<I: Proxy, U: std::fmt::Debug, State> std::fmt::Debug for QueueProxyData<I, U, State> {
#[cfg_attr(coverage, no_coverage)]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("QueueProxyData").field("udata", &self.udata).finish()
}
}
struct TemporaryData;
impl ObjectData for TemporaryData {
fn event(
self: Arc<Self>,
_: &Backend,
_: Message<ObjectId, OwnedFd>,
) -> Option<Arc<dyn ObjectData>> {
unreachable!()
}
fn destroyed(&self, _: ObjectId) {}
}
#[macro_export]
macro_rules! delegate_dispatch {
($(@< $( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+ >)? $dispatch_from:ty : [$interface: ty: $udata: ty] => $dispatch_to: ty) => {
impl$(< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $crate::Dispatch<$interface, $udata> for $dispatch_from {
fn event(
state: &mut Self,
proxy: &$interface,
event: <$interface as $crate::Proxy>::Event,
data: &$udata,
conn: &$crate::Connection,
qhandle: &$crate::QueueHandle<Self>,
) {
<$dispatch_to as $crate::Dispatch<$interface, $udata, Self>>::event(state, proxy, event, data, conn, qhandle)
}
fn event_created_child(
opcode: u16,
qhandle: &$crate::QueueHandle<Self>
) -> ::std::sync::Arc<dyn $crate::backend::ObjectData> {
<$dispatch_to as $crate::Dispatch<$interface, $udata, Self>>::event_created_child(opcode, qhandle)
}
}
};
}
#[macro_export]
macro_rules! delegate_noop {
($(@< $( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+ >)? $dispatch_from: ty : $interface: ty) => {
impl$(< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $crate::Dispatch<$interface, ()> for $dispatch_from {
fn event(
_: &mut Self,
_: &$interface,
_: <$interface as $crate::Proxy>::Event,
_: &(),
_: &$crate::Connection,
_: &$crate::QueueHandle<Self>,
) {
unreachable!();
}
}
};
($(@< $( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+ >)? $dispatch_from: ty : ignore $interface: ty) => {
impl$(< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $crate::Dispatch<$interface, ()> for $dispatch_from {
fn event(
_: &mut Self,
_: &$interface,
_: <$interface as $crate::Proxy>::Event,
_: &(),
_: &$crate::Connection,
_: &$crate::QueueHandle<Self>,
) {
}
}
};
}