From 1495cc1f222c12614826cd0192bce96e0beaf101 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Thu, 28 Nov 2024 11:25:04 +0100 Subject: [PATCH 1/2] 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() } From f27e4253a1544e1735192435a038982092a19fae Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Wed, 27 Nov 2024 13:15:56 +0100 Subject: [PATCH 2/2] ei: implement ei_touchscreen v2 --- release-notes.md | 1 + src/ei/ei_ifs/ei_device.rs | 1 + src/ei/ei_ifs/ei_seat.rs | 13 +++++++++++++ src/ei/ei_ifs/ei_touchscreen.rs | 21 ++++++++++++++++++--- src/ifs/wl_seat/event_handling.rs | 4 ++-- wire-ei/ei_touchscreen.txt | 8 ++++++++ 6 files changed, 43 insertions(+), 5 deletions(-) diff --git a/release-notes.md b/release-notes.md index e457f75d..e7568aea 100644 --- a/release-notes.md +++ b/release-notes.md @@ -3,6 +3,7 @@ - Various bugfixes. - Add support fo ext-data-control-v1. - Implement wl-fixes. +- Implement ei_touchscreen v2. # 1.7.0 (2024-10-25) diff --git a/src/ei/ei_ifs/ei_device.rs b/src/ei/ei_ifs/ei_device.rs index 46342a3e..81e6c3d6 100644 --- a/src/ei/ei_ifs/ei_device.rs +++ b/src/ei/ei_ifs/ei_device.rs @@ -233,6 +233,7 @@ impl EiDeviceRequestHandler for EiDevice { seat.touch_motion_at(time, id, x, y); } TouchChange::Up => seat.touch_up(time, id), + TouchChange::Cancel => seat.touch_cancel(time, id), } } seat.touch_frame(time); diff --git a/src/ei/ei_ifs/ei_seat.rs b/src/ei/ei_ifs/ei_seat.rs index d8469b40..430f55d5 100644 --- a/src/ei/ei_ifs/ei_seat.rs +++ b/src/ei/ei_ifs/ei_seat.rs @@ -197,6 +197,19 @@ impl EiSeat { } } + pub fn handle_touch_cancel(&self, id: u32) { + if self.is_sender() { + return; + } + if let Some(b) = self.touchscreen.get() { + if self.client.versions.ei_touchscreen() >= EiVersion(2) { + b.send_cancel(id); + } else { + b.send_up(id); + } + } + } + pub fn handle_touch_frame(&self, time_usec: u64) { if self.is_sender() { return; diff --git a/src/ei/ei_ifs/ei_touchscreen.rs b/src/ei/ei_ifs/ei_touchscreen.rs index a62dc06a..b9bb8dfb 100644 --- a/src/ei/ei_ifs/ei_touchscreen.rs +++ b/src/ei/ei_ifs/ei_touchscreen.rs @@ -10,8 +10,8 @@ use { utils::clonecell::UnsafeCellCloneSafe, wire_ei::{ ei_touchscreen::{ - ClientDown, ClientMotion, ClientUp, EiTouchscreenRequestHandler, Release, - ServerDown, ServerMotion, ServerUp, + ClientCancel, ClientDown, ClientMotion, ClientUp, EiTouchscreenRequestHandler, + Release, ServerCancel, ServerDown, ServerMotion, ServerUp, }, EiTouchscreenId, }, @@ -33,6 +33,7 @@ pub enum TouchChange { Down(f32, f32), Motion(f32, f32), Up, + Cancel, } unsafe impl UnsafeCellCloneSafe for TouchChange {} @@ -65,12 +66,22 @@ impl EiTouchscreen { }); } + 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) => { + (Motion(_, _), Motion(_, _)) + | (Down(_, _), Down(_, _)) + | (Up, Up) + | (Cancel, Cancel) => { o.insert(event); Ok(()) } @@ -104,6 +115,10 @@ impl EiTouchscreenRequestHandler for EiTouchscreen { fn client_up(&self, req: ClientUp, _slf: &Rc) -> Result<(), Self::Error> { self.set_client_event(req.touchid, TouchChange::Up) } + + fn client_cancel(&self, req: ClientCancel, _slf: &Rc) -> Result<(), Self::Error> { + self.set_client_event(req.touchid, TouchChange::Cancel) + } } ei_object_base! { diff --git a/src/ifs/wl_seat/event_handling.rs b/src/ifs/wl_seat/event_handling.rs index 159dd676..e3778b95 100644 --- a/src/ifs/wl_seat/event_handling.rs +++ b/src/ifs/wl_seat/event_handling.rs @@ -761,9 +761,9 @@ impl WlSeatGlobal { self.touch_owner.motion(self, time_usec, id, x, y); } - fn touch_cancel(self: &Rc, time_usec: u64, id: i32) { + pub fn touch_cancel(self: &Rc, time_usec: u64, id: i32) { self.for_each_ei_seat(|ei_seat| { - ei_seat.handle_touch_up(id as _); + ei_seat.handle_touch_cancel(id as _); }); self.state.for_each_seat_tester(|t| { t.send_touch_cancel(self.id, time_usec, id); diff --git a/wire-ei/ei_touchscreen.txt b/wire-ei/ei_touchscreen.txt index 2bca8286..3c732898 100644 --- a/wire-ei/ei_touchscreen.txt +++ b/wire-ei/ei_touchscreen.txt @@ -17,6 +17,10 @@ request client_up (sender) { touchid: u32, } +request client_cancel (sender, since = 2) { + touchid: u32, +} + event destroyed { serial: u32, } @@ -36,3 +40,7 @@ event server_motion (receiver) { event server_up (receiver) { touchid: u32, } + +event server_cancel (receiver, since = 2) { + touchid: u32, +}