use std::sync::{atomic::Ordering, Arc}; use atomic_float::AtomicF64; use wayland_server::{ backend::ClientId, protocol::wl_touch::{self, WlTouch}, Dispatch, DisplayHandle, Resource, }; use super::{SeatHandler, SeatState}; use crate::input::touch::TouchTarget; use crate::input::{ touch::{MotionEvent, OrientationEvent, ShapeEvent, UpEvent}, Seat, }; use crate::{input::touch::DownEvent, wayland::seat::wl_surface::WlSurface}; use crate::{input::touch::TouchHandle, utils::Serial}; impl TouchHandle { pub(crate) fn new_touch(&self, touch: WlTouch) { let mut guard = self.known_instances.lock().unwrap(); guard.push((touch.downgrade(), None)); } } impl TouchHandle { /// Attempt to retrieve a [`TouchHandle`] from an existing resource /// /// May return `None` for a valid `WlTouch` that was created without /// the keyboard capability. pub fn from_resource(seat: &WlTouch) -> Option { seat.data::>()?.handle.clone() } } fn for_each_focused_touch( seat: &Seat, surface: &WlSurface, seq: Serial, mut f: impl FnMut(WlTouch), ) { if let Some(touch) = seat.get_touch() { let mut inner = touch.known_instances.lock().unwrap(); for (ptr, last_seq) in &mut *inner { let Ok(ptr) = ptr.upgrade() else { continue; }; if ptr.id().same_client_as(&surface.id()) && last_seq.map(|last| last < seq).unwrap_or(true) { *last_seq = Some(seq); f(ptr.clone()); } } } } #[cfg(feature = "wayland_frontend")] impl TouchTarget for WlSurface where D: SeatHandler + 'static, { fn down(&self, seat: &Seat, _data: &mut D, event: &DownEvent, seq: Serial) { let serial = event.serial; let slot = event.slot; for_each_focused_touch(seat, self, seq, |touch| { let client_scale = touch .data::>() .unwrap() .client_scale .load(Ordering::Acquire); let location = event.location.to_client(client_scale); touch.down( serial.into(), event.time, self, slot.into(), location.x, location.y, ); }) } fn up(&self, seat: &Seat, _data: &mut D, event: &UpEvent, seq: Serial) { let serial = event.serial; let slot = event.slot; for_each_focused_touch(seat, self, seq, |touch| { touch.up(serial.into(), event.time, slot.into()); }) } fn motion(&self, seat: &Seat, _data: &mut D, event: &MotionEvent, seq: Serial) { let slot = event.slot; for_each_focused_touch(seat, self, seq, |touch| { let client_scale = touch .data::>() .unwrap() .client_scale .load(Ordering::Acquire); let location = event.location.to_client(client_scale); touch.motion(event.time, slot.into(), location.x, location.y); }) } fn frame(&self, seat: &Seat, _data: &mut D, seq: Serial) { for_each_focused_touch(seat, self, seq, |touch| { touch.frame(); }) } fn cancel(&self, seat: &Seat, _data: &mut D, seq: Serial) { for_each_focused_touch(seat, self, seq, |touch| { touch.cancel(); }) } fn shape(&self, seat: &Seat, _data: &mut D, event: &ShapeEvent, seq: Serial) { let slot = event.slot; for_each_focused_touch(seat, self, seq, |touch| { touch.shape(slot.into(), event.major, event.minor); }) } fn orientation(&self, seat: &Seat, _data: &mut D, event: &OrientationEvent, seq: Serial) { let slot = event.slot; for_each_focused_touch(seat, self, seq, |touch| { touch.orientation(slot.into(), event.orientation); }) } } /// User data for touch #[derive(Debug)] pub struct TouchUserData { pub(crate) handle: Option>, pub(crate) client_scale: Arc, } impl Dispatch, D> for SeatState where D: Dispatch>, D: SeatHandler, D: 'static, { fn request( _state: &mut D, _client: &wayland_server::Client, _resource: &WlTouch, _request: wl_touch::Request, _data: &TouchUserData, _dhandle: &DisplayHandle, _data_init: &mut wayland_server::DataInit<'_, D>, ) { } fn destroyed(_state: &mut D, _client_id: ClientId, touch: &WlTouch, data: &TouchUserData) { if let Some(ref handle) = data.handle { handle .known_instances .lock() .unwrap() .retain(|(p, _)| p.id() != touch.id()); } } }