use {
crate::{
ei::{
ei_client::{EiClient, EiClientError},
ei_ifs::ei_device::{EiDevice, EiDeviceInterface},
ei_object::{EiObject, EiVersion},
},
fixed::Fixed,
leaks::Tracker,
utils::clonecell::UnsafeCellCloneSafe,
wire_ei::{
EiTouchscreenId,
ei_touchscreen::{
ClientCancel, ClientDown, ClientMotion, ClientUp, EiTouchscreenRequestHandler,
Release, ServerCancel, ServerDown, ServerMotion, ServerUp,
},
},
},
std::{collections::hash_map::Entry, rc::Rc},
thiserror::Error,
};
pub struct EiTouchscreen {
pub id: EiTouchscreenId,
pub client: Rc<EiClient>,
pub tracker: Tracker<Self>,
pub version: EiVersion,
pub device: Rc<EiDevice>,
}
#[derive(Copy, Clone, Debug)]
pub enum TouchChange {
Down(f32, f32),
Motion(f32, f32),
Up,
Cancel,
}
unsafe impl UnsafeCellCloneSafe for TouchChange {}
ei_device_interface!(EiTouchscreen, ei_touchscreen, touchscreen);
impl EiTouchscreen {
pub fn send_down(&self, touchid: u32, x: Fixed, y: Fixed) {
self.client.event(ServerDown {
self_id: self.id,
touchid,
x: x.to_f32(),
y: y.to_f32(),
});
}
pub fn send_motion(&self, touchid: u32, x: Fixed, y: Fixed) {
self.client.event(ServerMotion {
self_id: self.id,
touchid,
x: x.to_f32(),
y: y.to_f32(),
});
}
pub fn send_up(&self, touchid: u32) {
self.client.event(ServerUp {
self_id: self.id,
touchid,
});
}
pub fn send_cancel(&self, touchid: u32) {
self.client.event(ServerCancel {
self_id: self.id,
touchid,
});
}
fn set_client_event(&self, touchid: u32, event: TouchChange) -> Result<(), EiTouchscreenError> {
match self.device.touch_changes.lock().entry(touchid) {
Entry::Occupied(mut o) => {
use TouchChange::*;
match (o.get(), event) {
(Motion(_, _), Motion(_, _))
| (Down(_, _), Down(_, _))
| (Up, Up)
| (Cancel, Cancel) => {
o.insert(event);
Ok(())
}
_ => Err(EiTouchscreenError::InvalidEventCombination),
}
}
Entry::Vacant(v) => {
v.insert(event);
Ok(())
}
}
}
}
impl EiTouchscreenRequestHandler for EiTouchscreen {
type Error = EiTouchscreenError;
fn release(&self, _req: Release, _slf: &Rc<Self>) -> Result<(), Self::Error> {
self.destroy()?;
Ok(())
}
fn client_down(&self, req: ClientDown, _slf: &Rc<Self>) -> Result<(), Self::Error> {
self.set_client_event(req.touchid, TouchChange::Down(req.x, req.y))
}
fn client_motion(&self, req: ClientMotion, _slf: &Rc<Self>) -> Result<(), Self::Error> {
self.set_client_event(req.touchid, TouchChange::Motion(req.x, req.y))
}
fn client_up(&self, req: ClientUp, _slf: &Rc<Self>) -> Result<(), Self::Error> {
self.set_client_event(req.touchid, TouchChange::Up)
}
fn client_cancel(&self, req: ClientCancel, _slf: &Rc<Self>) -> Result<(), Self::Error> {
self.set_client_event(req.touchid, TouchChange::Cancel)
}
}
ei_object_base! {
self = EiTouchscreen;
version = self.version;
}
impl EiObject for EiTouchscreen {}
#[derive(Debug, Error)]
pub enum EiTouchscreenError {
#[error(transparent)]
EiClientError(Box<EiClientError>),
#[error("Touch frame contains an invalid combination of events")]
InvalidEventCombination,
}
efrom!(EiTouchscreenError, EiClientError);