From 245810353e2c524fec8b9319628e2786061daba9 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Wed, 18 Oct 2023 16:27:36 -0700 Subject: [PATCH] Add `restore_focus` argument to `PointerInnerHandle::unset_grab` Used in `ClickGrab` to prevent `motion` events from occurring with every `button` event. Otherwise, behavior should be unchanged. This matches the argument taken by `KeyboardInnerHandle::unset_grab`. This seems like the simplest solution. It would also be possible to add a method to the `PointerGrab` trait indicating if focus should be restored, but that's complicated since `unset_grab` can't access the grab when it's `Borrowed`, so it would have to add a bool to `GrabStatus::Borrowed`, etc. This still doesn't send a `frame`, but since this takes a serial and a time, it probably will be sent along with other pointer events, and hopefully part of a `frame`. The Wayland spec isn't all that specific about when things can/should be part of a `frame`... Calling `motion` is also incorrect with pointer constraints, but grabs other than `ClickGrab` generally shouldn't exist while a constraint is active. It would be good to enforce that some way. Fixes https://github.com/Smithay/smithay/issues/1148. --- anvil/src/shell/grabs.rs | 6 +-- src/desktop/wayland/popup/grab.rs | 6 +-- src/input/pointer/grab.rs | 2 +- src/input/pointer/mod.rs | 43 +++++++++++-------- src/wayland/selection/data_device/dnd_grab.rs | 2 +- .../selection/data_device/server_dnd_grab.rs | 2 +- 6 files changed, 34 insertions(+), 27 deletions(-) diff --git a/anvil/src/shell/grabs.rs b/anvil/src/shell/grabs.rs index 8d4b6752bb5a..02187bc1be5a 100644 --- a/anvil/src/shell/grabs.rs +++ b/anvil/src/shell/grabs.rs @@ -64,7 +64,7 @@ impl PointerGrab> for MoveSurfaceG handle.button(data, event); if handle.current_pressed().is_empty() { // No more buttons are pressed, release the grab. - handle.unset_grab(data, event.serial, event.time); + handle.unset_grab(data, event.serial, event.time, true); } } @@ -254,7 +254,7 @@ impl PointerGrab> for ResizeSurfac // It is impossible to get `min_size` and `max_size` of dead toplevel, so we return early. if !self.window.alive() { - handle.unset_grab(data, event.serial, event.time); + handle.unset_grab(data, event.serial, event.time, true); return; } @@ -346,7 +346,7 @@ impl PointerGrab> for ResizeSurfac handle.button(data, event); if handle.current_pressed().is_empty() { // No more buttons are pressed, release the grab. - handle.unset_grab(data, event.serial, event.time); + handle.unset_grab(data, event.serial, event.time, true); // If toplevel is dead, we can't resize it, so we return early. if !self.window.alive() { diff --git a/src/desktop/wayland/popup/grab.rs b/src/desktop/wayland/popup/grab.rs index d4016f480942..2d18d6574a22 100644 --- a/src/desktop/wayland/popup/grab.rs +++ b/src/desktop/wayland/popup/grab.rs @@ -551,7 +551,7 @@ where event: &MotionEvent, ) { if self.popup_grab.has_ended() { - handle.unset_grab(data, event.serial, event.time); + handle.unset_grab(data, event.serial, event.time, true); self.popup_grab.unset_keyboard_grab(data, event.serial); return; } @@ -591,7 +591,7 @@ where let state = event.state; if self.popup_grab.has_ended() { - handle.unset_grab(data, serial, time); + handle.unset_grab(data, serial, time, true); handle.button(data, event); self.popup_grab.unset_keyboard_grab(data, serial); return; @@ -610,7 +610,7 @@ where .unwrap_or(false) { let _ = self.popup_grab.ungrab(PopupUngrabStrategy::All); - handle.unset_grab(data, serial, time); + handle.unset_grab(data, serial, time, true); handle.button(data, event); self.popup_grab.unset_keyboard_grab(data, serial); return; diff --git a/src/input/pointer/grab.rs b/src/input/pointer/grab.rs index b038060a872f..dd1fd0d016ae 100644 --- a/src/input/pointer/grab.rs +++ b/src/input/pointer/grab.rs @@ -379,7 +379,7 @@ impl PointerGrab for ClickGrab { handle.button(data, event); if handle.current_pressed().is_empty() { // no more buttons are pressed, release the grab - handle.unset_grab(data, event.serial, event.time); + handle.unset_grab(data, event.serial, event.time, false); } } diff --git a/src/input/pointer/mod.rs b/src/input/pointer/mod.rs index 8d89165c2394..655654dbda01 100644 --- a/src/input/pointer/mod.rs +++ b/src/input/pointer/mod.rs @@ -181,7 +181,10 @@ impl PointerHandle { #[instrument(level = "debug", parent = &self.span, skip(self, data))] pub fn unset_grab(&self, data: &mut D, serial: Serial, time: u32) { let seat = self.get_seat(data); - self.inner.lock().unwrap().unset_grab(data, &seat, serial, time); + self.inner + .lock() + .unwrap() + .unset_grab(data, &seat, serial, time, true); } /// Check if this pointer is currently grabbed with this serial @@ -460,9 +463,11 @@ impl<'a, D: SeatHandler + 'static> PointerInnerHandle<'a, D> { /// Remove any current grab on this pointer, resetting it to the default behavior /// - /// This will also restore the focus of the underlying pointer - pub fn unset_grab(&mut self, data: &mut D, serial: Serial, time: u32) { - self.inner.unset_grab(data, self.seat, serial, time); + /// This will also restore the focus of the underlying pointer if restore_focus + /// is [`true`] + pub fn unset_grab(&mut self, data: &mut D, serial: Serial, time: u32, restore_focus: bool) { + self.inner + .unset_grab(data, self.seat, serial, time, restore_focus); } /// Access the current focus of this pointer @@ -678,21 +683,23 @@ impl PointerInternal { } } - fn unset_grab(&mut self, data: &mut D, seat: &Seat, serial: Serial, time: u32) { + fn unset_grab(&mut self, data: &mut D, seat: &Seat, serial: Serial, time: u32, restore_focus: bool) { self.grab = GrabStatus::None; - // restore the focus - let location = self.location; - let focus = self.pending_focus.clone(); - self.motion( - data, - seat, - focus, - &MotionEvent { - location, - serial, - time, - }, - ); + if restore_focus { + // restore the focus + let location = self.location; + let focus = self.pending_focus.clone(); + self.motion( + data, + seat, + focus, + &MotionEvent { + location, + serial, + time, + }, + ); + } } fn motion( diff --git a/src/wayland/selection/data_device/dnd_grab.rs b/src/wayland/selection/data_device/dnd_grab.rs index 39cf87490452..b70cc64d500f 100644 --- a/src/wayland/selection/data_device/dnd_grab.rs +++ b/src/wayland/selection/data_device/dnd_grab.rs @@ -245,7 +245,7 @@ where } } } - handle.unset_grab(data, event.serial, event.time); + handle.unset_grab(data, event.serial, event.time, true); } } diff --git a/src/wayland/selection/data_device/server_dnd_grab.rs b/src/wayland/selection/data_device/server_dnd_grab.rs index 1e2ddba83d87..a37f21d62a88 100644 --- a/src/wayland/selection/data_device/server_dnd_grab.rs +++ b/src/wayland/selection/data_device/server_dnd_grab.rs @@ -224,7 +224,7 @@ where } } } - handle.unset_grab(data, serial, time); + handle.unset_grab(data, serial, time, true); } }