From b166e1ff1384c694962f57ac7d0dca9c337eae62 Mon Sep 17 00:00:00 2001 From: Kirill Chibisov Date: Sat, 15 Jul 2023 08:09:28 +0000 Subject: [PATCH] On Wayland, make the CSD frame double click reliable It was discovered that on GNOME the click sometimes being swallowed by the mutter's `wl_pointer::enter/leave` sequences. This was happening due to `xdg_toplevel::move` making the pointer to leave the surface. To make handling of that more robust, we could start the `xdg_toplevel::move` when the actual pointer motion is being performed. Links: https://github.com/alacritty/alacritty/issues/7011 Links: https://gitlab.gnome.org/GNOME/mutter/-/issues/2669#note_1790825 --- CHANGELOG.md | 1 + .../linux/wayland/seat/pointer/mod.rs | 2 +- .../linux/wayland/window/state.rs | 29 +++++++++++++++++-- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b4d1b990..e7819823 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ And please only add new entries to the top of this list, right below the `# Unre # Unreleased +- On Wayland, make double clicking and moving the CSD frame more reliable. - On macOS, add tabbing APIs on `WindowExtMacOS` and `EventLoopWindowTargetExtMacOS`. - **Breaking:** Rename `Window::set_inner_size` to `Window::request_inner_size` and indicate if the size was applied immediately. - On X11, fix false positive flagging of key repeats when pressing different keys with no release between presses. diff --git a/src/platform_impl/linux/wayland/seat/pointer/mod.rs b/src/platform_impl/linux/wayland/seat/pointer/mod.rs index 607b0e1b..4d65e1fa 100644 --- a/src/platform_impl/linux/wayland/seat/pointer/mod.rs +++ b/src/platform_impl/linux/wayland/seat/pointer/mod.rs @@ -68,7 +68,7 @@ impl PointerHandler for WinitState { if parent_surface != surface => { if let Some(icon) = - window.frame_point_moved(surface, event.position.0, event.position.1) + window.frame_point_moved(seat, surface, event.position.0, event.position.1) { if let Some(pointer) = seat_state.pointer.as_ref() { let surface = pointer diff --git a/src/platform_impl/linux/wayland/window/state.rs b/src/platform_impl/linux/wayland/window/state.rs index e67e1652..d9da53db 100644 --- a/src/platform_impl/linux/wayland/window/state.rs +++ b/src/platform_impl/linux/wayland/window/state.rs @@ -127,6 +127,11 @@ pub struct WindowState { viewport: Option, fractional_scale: Option, + + /// Whether the client side decorations have pending move operations. + /// + /// The value is the serial of the event triggered moved. + has_pending_move: Option, } /// The state of the cursor grabs. @@ -279,7 +284,7 @@ impl WindowState { FrameAction::Maximize => self.window.set_maximized(), FrameAction::UnMaximize => self.window.unset_maximized(), FrameAction::Close => WinitState::queue_close(updates, window_id), - FrameAction::Move => self.window.move_(seat, serial), + FrameAction::Move => self.has_pending_move = Some(serial), FrameAction::Resize(edge) => self.window.resize(seat, serial, edge), FrameAction::ShowMenu(x, y) => self.window.show_window_menu(seat, serial, (x, y)), }; @@ -294,9 +299,26 @@ impl WindowState { } // Move the point over decorations. - pub fn frame_point_moved(&mut self, surface: &WlSurface, x: f64, y: f64) -> Option<&str> { + pub fn frame_point_moved( + &mut self, + seat: &WlSeat, + surface: &WlSurface, + x: f64, + y: f64, + ) -> Option<&str> { + // Take the serial if we had any, so it doesn't stick around. + let serial = self.has_pending_move.take(); + if let Some(frame) = self.frame.as_mut() { - frame.click_point_moved(surface, x, y) + let cursor = frame.click_point_moved(surface, x, y); + // If we have a cursor change, that means that cursor is over the decorations, + // so try to apply move. + if let Some(serial) = cursor.is_some().then_some(serial).flatten() { + self.window.move_(seat, serial); + None + } else { + cursor + } } else { None } @@ -419,6 +441,7 @@ impl WindowState { resizable: true, viewport, window: ManuallyDrop::new(window), + has_pending_move: None, } }