use std::sync::Mutex;
use wayland_client::protocol::wl_seat::WlSeat;
use wayland_client::protocol::wl_surface::WlSurface;
use wayland_client::protocol::wl_touch::{Event as TouchEvent, WlTouch};
use wayland_client::{Connection, Dispatch, QueueHandle};
use crate::seat::SeatState;
#[derive(Debug)]
pub struct TouchData {
seat: WlSeat,
inner: Mutex<TouchDataInner>,
}
impl TouchData {
pub fn new(seat: WlSeat) -> Self {
Self { seat, inner: Default::default() }
}
pub fn seat(&self) -> &WlSeat {
&self.seat
}
}
#[derive(Debug, Default)]
pub(crate) struct TouchDataInner {
events: Vec<TouchEvent>,
}
#[macro_export]
macro_rules! delegate_touch {
($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
$crate::delegate_touch!(@{ $(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty }; touch: $crate::seat::touch::TouchData);
};
($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty, touch: [$($td:ty),* $(,)?]) => {
$crate::delegate_touch!(@{ $(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty }; [ $($td),* ]);
};
(@{$($ty:tt)*}; touch: $td:ty) => {
$crate::reexports::client::delegate_dispatch!($($ty)*:
[
$crate::reexports::client::protocol::wl_touch::WlTouch: $td
] => $crate::seat::SeatState
);
};
(@$ty:tt; [$($td:ty),*] ) => {
$(
$crate::delegate_touch!(@$ty, touch: $td);
)*
};
}
pub trait TouchDataExt: Send + Sync {
fn touch_data(&self) -> &TouchData;
}
impl TouchDataExt for TouchData {
fn touch_data(&self) -> &TouchData {
self
}
}
pub trait TouchHandler: Sized {
#[allow(clippy::too_many_arguments)]
fn down(
&mut self,
conn: &Connection,
qh: &QueueHandle<Self>,
touch: &WlTouch,
serial: u32,
time: u32,
surface: WlSurface,
id: i32,
position: (f64, f64),
);
fn up(
&mut self,
conn: &Connection,
qh: &QueueHandle<Self>,
touch: &WlTouch,
serial: u32,
time: u32,
id: i32,
);
fn motion(
&mut self,
conn: &Connection,
qh: &QueueHandle<Self>,
touch: &WlTouch,
time: u32,
id: i32,
position: (f64, f64),
);
fn shape(
&mut self,
conn: &Connection,
qh: &QueueHandle<Self>,
touch: &WlTouch,
id: i32,
major: f64,
minor: f64,
);
fn orientation(
&mut self,
conn: &Connection,
qh: &QueueHandle<Self>,
touch: &WlTouch,
id: i32,
orientation: f64,
);
fn cancel(&mut self, conn: &Connection, qh: &QueueHandle<Self>, touch: &WlTouch);
}
impl<D, U> Dispatch<WlTouch, U, D> for SeatState
where
D: Dispatch<WlTouch, U> + TouchHandler,
U: TouchDataExt,
{
fn event(
data: &mut D,
touch: &WlTouch,
event: TouchEvent,
udata: &U,
conn: &Connection,
qh: &QueueHandle<D>,
) {
let udata = udata.touch_data();
match event {
TouchEvent::Down { .. }
| TouchEvent::Up { .. }
| TouchEvent::Motion { .. }
| TouchEvent::Shape { .. }
| TouchEvent::Orientation { .. } => {
let mut guard = udata.inner.lock().unwrap();
guard.events.push(event);
}
TouchEvent::Frame => {
let mut guard = udata.inner.lock().unwrap();
for event in guard.events.drain(..) {
process_framed_event(data, touch, conn, qh, event);
}
}
TouchEvent::Cancel => {
let mut guard = udata.inner.lock().unwrap();
guard.events.clear();
data.cancel(conn, qh, touch);
}
_ => unreachable!(),
}
}
}
fn process_framed_event<D>(
data: &mut D,
touch: &WlTouch,
conn: &Connection,
qh: &QueueHandle<D>,
event: TouchEvent,
) where
D: TouchHandler,
{
match event {
TouchEvent::Down { serial, time, surface, id, x, y } => {
data.down(conn, qh, touch, serial, time, surface, id, (x, y));
}
TouchEvent::Up { serial, time, id } => {
data.up(conn, qh, touch, serial, time, id);
}
TouchEvent::Motion { time, id, x, y } => {
data.motion(conn, qh, touch, time, id, (x, y));
}
TouchEvent::Shape { id, major, minor } => {
data.shape(conn, qh, touch, id, major, minor);
}
TouchEvent::Orientation { id, orientation } => {
data.orientation(conn, qh, touch, id, orientation);
}
_ => unreachable!(),
}
}