From 679b4b7d74abdb6ebfcb8c3216a4803b7ad71bdf Mon Sep 17 00:00:00 2001 From: Christian Meissl Date: Sun, 18 Feb 2024 19:27:09 +0100 Subject: [PATCH] input: allow PointerTarget to handle focus replace this adds a new function to PointerTarget that is called when the focus is replaced. this allows implementing a nested stack of focus targets without sacrificing grab guarantees. the default impl will do the same like the old behavior, so call leave on the previous target and enter on the new one. --- src/input/pointer/mod.rs | 61 ++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/src/input/pointer/mod.rs b/src/input/pointer/mod.rs index e0101a8f291a..4b91ed62c5d7 100644 --- a/src/input/pointer/mod.rs +++ b/src/input/pointer/mod.rs @@ -141,6 +141,17 @@ where fn gesture_hold_end(&self, seat: &Seat, data: &mut D, event: &GestureHoldEndEvent); /// A pointer of a given seat left this handler fn leave(&self, seat: &Seat, data: &mut D, serial: Serial, time: u32); + /// A pointer of a given seat moved from another handler to this handler + fn replace( + &self, + replaced: ::PointerFocus, + seat: &Seat, + data: &mut D, + event: &MotionEvent, + ) { + PointerTarget::::leave(&replaced, seat, data, event.serial, event.time); + PointerTarget::::enter(self, seat, data, event); + } } impl PointerHandle { @@ -717,42 +728,30 @@ impl PointerInternal { focus: Option<(::PointerFocus, Point)>, event: &MotionEvent, ) { - // do we leave a surface ? - let mut leave = true; self.location = event.location; - if let Some((ref current_focus, _)) = self.focus { - if let Some((ref new_focus, _)) = focus { - if current_focus == new_focus { - leave = false; - } - } - } - if leave { - if let Some((focused, _)) = self.focus.as_mut() { - focused.leave(seat, data, event.serial, event.time); - } - self.focus = None; - data.cursor_image(seat, CursorImageStatus::default_named()); - } - - // do we enter one ? - if let Some((surface, surface_location)) = focus { - let entered = self.focus.is_none(); - // in all cases, update the focus, the coordinates of the surface - // might have changed - self.focus = Some((surface, surface_location)); + if let Some((focus, loc)) = focus { let event = MotionEvent { - location: event.location - surface_location.to_f64(), + location: event.location - loc.to_f64(), serial: event.serial, time: event.time, }; - let (focused, _) = self.focus.as_mut().unwrap(); - if entered { - focused.enter(seat, data, &event); - } else { - // we were on top of a surface and remained on it - focused.motion(seat, data, &event); - } + let old_focus = self.focus.replace((focus.clone(), loc)); + match (focus, old_focus) { + (focus, Some((old_focus, _))) if focus == old_focus => { + // we were on top of a target and remained on it + focus.motion(seat, data, &event); + } + (focus, Some((old_focus, _))) => { + // the target has been replaced + focus.replace(old_focus, seat, data, &event); + } + (focus, None) => { + // we entered a new target + focus.enter(seat, data, &event); + } + }; + } else if let Some((old_focus, _)) = self.focus.take() { + old_focus.leave(seat, data, event.serial, event.time); } }