iris: a capture cancels every other gesture, and the pointer leaves UiRenderState
Two defects Iris reported from her phone on 2026-09-08, one root cause each, both in how a gesture ends. A widget that takes pointer capture cuts every other widget off from the press completely -- no PressEnd, no Drop -- so anything else tracking it was left with an open gesture at a stale origin, and the *next* touch anywhere was measured from that origin. That is the transcript jumping on a tap after a code fence was panned sideways. CursorSense::Cancel is the missing state: delivered once to each loser of a capture race, the way Android sends ACTION_CANCEL and the web sends pointercancel. And registered click_or_drag|unclick, which never matches a Drop, so a Scroll that had captured never saw its own gesture end and stayed panning from where the finger left. That is the horizontal snap back. CursorSense::drag_senses() states the rule once for every widget driving a DragGesture instead of per call site. The pointer's own state (who holds capture, who is tracking the press) no longer lives in a Mutex on UiRenderState. It is Event::Global for the cursor senses -- owned by the event manager that runs the dispatch, reached by &mut, with a per-dispatch PointerRequests slot for handlers -- per Iris: never reach for locks first, and input-wide state belongs to the general input handler. What had forced the lock was a Data: Send bound on task_on that nothing needed; the spawned future never sees the event's data. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
cdeb7b0857
commit
b863f9f3df
13 files changed
+554
-129
No files matched your search
@@ -9,6 +9,20 @@ pub use rsc::*;
|
||||
pub trait Event: Sized + 'static + Clone {
|
||||
type Data<'a>: Clone = ();
|
||||
type State: Default = ();
|
||||
/// State this event owns that belongs to no single widget -- what the
|
||||
/// thing dispatching the event knows about the *input*, rather than
|
||||
/// about a listener. `()` for almost every event; the cursor's is
|
||||
/// `iris::sense::PointerInput` (which widget holds pointer capture,
|
||||
/// and who is tracking the press in flight).
|
||||
///
|
||||
/// It lives here so that such state has one owner, reached by `&mut`
|
||||
/// through the event manager, instead of being parked on whatever
|
||||
/// structure a handler happens to be able to reach and guarded with a
|
||||
/// lock. Iris asked for that on 2026-09-08, of the pointer capture
|
||||
/// that used to sit in a `Mutex` on `UiRenderState`: "everything
|
||||
/// global should be stored in the general input handler, not in
|
||||
/// specific senses with locking stuff."
|
||||
type Global: Default = ();
|
||||
#[allow(unused_variables)]
|
||||
fn should_run<'a>(&self, data: &Self::Data<'a>) -> Option<Self::Data<'a>> {
|
||||
Some(data.clone())
|
||||
|
||||
Reference in new issue
Block a user