From 5d3b8a9afcdeafdc288a341e097e1f2c08bb75ba Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Thu, 28 Nov 2024 11:25:04 +0100 Subject: [PATCH] ei: make handling of touchscreen events stricter --- src/ei/ei_ifs/ei_device.rs | 6 ++--- src/ei/ei_ifs/ei_touchscreen.rs | 41 ++++++++++++++++++++++----------- src/utils/syncqueue.rs | 1 + 3 files changed, 32 insertions(+), 16 deletions(-) diff --git a/src/ei/ei_ifs/ei_device.rs b/src/ei/ei_ifs/ei_device.rs index e3e6cc6a..46342a3e 100644 --- a/src/ei/ei_ifs/ei_device.rs +++ b/src/ei/ei_ifs/ei_device.rs @@ -11,7 +11,7 @@ use { leaks::Tracker, rect::Rect, scale::Scale, - utils::syncqueue::SyncQueue, + utils::{copyhashmap::CopyHashMap, syncqueue::SyncQueue}, wire_ei::{ ei_device::{ ClientFrame, ClientStartEmulating, ClientStopEmulating, Destroyed, DeviceType, @@ -37,7 +37,7 @@ pub struct EiDevice { pub seat: Rc, pub button_changes: SyncQueue<(u32, KeyState)>, - pub touch_changes: SyncQueue<(u32, TouchChange)>, + pub touch_changes: CopyHashMap, pub scroll_px: [Cell>; 2], pub scroll_v120: [Cell>; 2], pub scroll_stop: [Cell>; 2], @@ -219,7 +219,7 @@ impl EiDeviceRequestHandler for EiDevice { } } if self.touch_changes.is_not_empty() { - while let Some((touch_id, change)) = self.touch_changes.pop() { + for (touch_id, change) in self.touch_changes.lock().drain() { let id = touch_id as i32; match change { TouchChange::Down(x, y) => { diff --git a/src/ei/ei_ifs/ei_touchscreen.rs b/src/ei/ei_ifs/ei_touchscreen.rs index 52c0d60d..a62dc06a 100644 --- a/src/ei/ei_ifs/ei_touchscreen.rs +++ b/src/ei/ei_ifs/ei_touchscreen.rs @@ -7,6 +7,7 @@ use { }, fixed::Fixed, leaks::Tracker, + utils::clonecell::UnsafeCellCloneSafe, wire_ei::{ ei_touchscreen::{ ClientDown, ClientMotion, ClientUp, EiTouchscreenRequestHandler, Release, @@ -15,7 +16,7 @@ use { EiTouchscreenId, }, }, - std::rc::Rc, + std::{collections::hash_map::Entry, rc::Rc}, thiserror::Error, }; @@ -34,6 +35,8 @@ pub enum TouchChange { Up, } +unsafe impl UnsafeCellCloneSafe for TouchChange {} + ei_device_interface!(EiTouchscreen, ei_touchscreen, touchscreen); impl EiTouchscreen { @@ -61,6 +64,25 @@ impl EiTouchscreen { 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) => { + o.insert(event); + Ok(()) + } + _ => Err(EiTouchscreenError::InvalidEventCombination), + } + } + Entry::Vacant(v) => { + v.insert(event); + Ok(()) + } + } + } } impl EiTouchscreenRequestHandler for EiTouchscreen { @@ -72,24 +94,15 @@ impl EiTouchscreenRequestHandler for EiTouchscreen { } fn client_down(&self, req: ClientDown, _slf: &Rc) -> Result<(), Self::Error> { - self.device - .touch_changes - .push((req.touchid, TouchChange::Down(req.x, req.y))); - Ok(()) + self.set_client_event(req.touchid, TouchChange::Down(req.x, req.y)) } fn client_motion(&self, req: ClientMotion, _slf: &Rc) -> Result<(), Self::Error> { - self.device - .touch_changes - .push((req.touchid, TouchChange::Motion(req.x, req.y))); - Ok(()) + self.set_client_event(req.touchid, TouchChange::Motion(req.x, req.y)) } fn client_up(&self, req: ClientUp, _slf: &Rc) -> Result<(), Self::Error> { - self.device - .touch_changes - .push((req.touchid, TouchChange::Up)); - Ok(()) + self.set_client_event(req.touchid, TouchChange::Up) } } @@ -104,5 +117,7 @@ impl EiObject for EiTouchscreen {} pub enum EiTouchscreenError { #[error(transparent)] EiClientError(Box), + #[error("Touch frame contains an invalid combination of events")] + InvalidEventCombination, } efrom!(EiTouchscreenError, EiClientError); diff --git a/src/utils/syncqueue.rs b/src/utils/syncqueue.rs index 55d8a1ba..4ab3f24a 100644 --- a/src/utils/syncqueue.rs +++ b/src/utils/syncqueue.rs @@ -37,6 +37,7 @@ impl SyncQueue { unsafe { self.el.get().deref_mut().is_empty() } } + #[expect(dead_code)] pub fn is_not_empty(&self) -> bool { !self.is_empty() }