From db89d4d3dd1440e18193d4ce98d207531c7720e0 Mon Sep 17 00:00:00 2001 From: Ivan Molodetskikh Date: Wed, 19 Jun 2024 21:54:46 +0300 Subject: Implement vertical middle mouse gesture --- src/input/mod.rs | 16 +-- src/input/spatial_movement_grab.rs | 231 +++++++++++++++++++++++++++++++++++++ src/input/view_offset_grab.rs | 190 ------------------------------ 3 files changed, 239 insertions(+), 198 deletions(-) create mode 100644 src/input/spatial_movement_grab.rs delete mode 100644 src/input/view_offset_grab.rs (limited to 'src/input') diff --git a/src/input/mod.rs b/src/input/mod.rs index d0e1c55b..d5b0cd0e 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -29,7 +29,7 @@ use smithay::wayland::pointer_constraints::{with_pointer_constraint, PointerCons use smithay::wayland::tablet_manager::{TabletDescriptor, TabletSeatTrait}; use self::resize_grab::ResizeGrab; -use self::view_offset_grab::ViewOffsetGrab; +use self::spatial_movement_grab::SpatialMovementGrab; use crate::niri::State; use crate::ui::screenshot_ui::ScreenshotUi; use crate::utils::spawning::spawn; @@ -37,8 +37,8 @@ use crate::utils::{center, get_monotonic_time, ResizeEdge}; pub mod resize_grab; pub mod scroll_tracker; +pub mod spatial_movement_grab; pub mod swipe_tracker; -pub mod view_offset_grab; pub const DOUBLE_CLICK_TIME: Duration = Duration::from_millis(400); @@ -1252,15 +1252,13 @@ impl State { }; if mod_down { if let Some(output) = self.niri.output_under_cursor() { - self.niri.layout.view_offset_gesture_begin(&output, false); - let location = pointer.current_location(); let start_data = PointerGrabStartData { focus: None, button: event.button_code(), location, }; - let grab = ViewOffsetGrab::new(start_data); + let grab = SpatialMovementGrab::new(start_data, output); pointer.set_grab(self, grab, serial, Focus::Clear); self.niri.pointer_grab_ongoing = true; self.niri @@ -1699,7 +1697,9 @@ impl State { if cx.abs() > cy.abs() { self.niri.layout.view_offset_gesture_begin(&output, true); } else { - self.niri.layout.workspace_switch_gesture_begin(&output); + self.niri + .layout + .workspace_switch_gesture_begin(&output, true); } } } @@ -1711,7 +1711,7 @@ impl State { let res = self .niri .layout - .workspace_switch_gesture_update(delta_y, timestamp); + .workspace_switch_gesture_update(delta_y, timestamp, true); if let Some(output) = res { if let Some(output) = output { self.niri.queue_redraw(&output); @@ -1757,7 +1757,7 @@ impl State { let res = self .niri .layout - .workspace_switch_gesture_end(event.cancelled()); + .workspace_switch_gesture_end(event.cancelled(), Some(true)); if let Some(output) = res { self.niri.queue_redraw(&output); handled = true; diff --git a/src/input/spatial_movement_grab.rs b/src/input/spatial_movement_grab.rs new file mode 100644 index 00000000..5a0e6a8a --- /dev/null +++ b/src/input/spatial_movement_grab.rs @@ -0,0 +1,231 @@ +use std::time::Duration; + +use smithay::input::pointer::{ + AxisFrame, ButtonEvent, CursorImageStatus, GestureHoldBeginEvent, GestureHoldEndEvent, + GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent, GestureSwipeBeginEvent, + GestureSwipeEndEvent, GestureSwipeUpdateEvent, GrabStartData as PointerGrabStartData, + MotionEvent, PointerGrab, PointerInnerHandle, RelativeMotionEvent, +}; +use smithay::input::SeatHandler; +use smithay::output::Output; +use smithay::utils::{Logical, Point}; + +use crate::niri::State; + +pub struct SpatialMovementGrab { + start_data: PointerGrabStartData, + last_location: Point, + output: Output, + gesture: GestureState, +} + +#[derive(Debug, Clone, Copy)] +enum GestureState { + Recognizing, + ViewOffset, + WorkspaceSwitch, +} + +impl SpatialMovementGrab { + pub fn new(start_data: PointerGrabStartData, output: Output) -> Self { + Self { + last_location: start_data.location, + start_data, + output, + gesture: GestureState::Recognizing, + } + } + + fn on_ungrab(&mut self, state: &mut State) { + let layout = &mut state.niri.layout; + let res = match self.gesture { + GestureState::Recognizing => None, + GestureState::ViewOffset => layout.view_offset_gesture_end(false, Some(false)), + GestureState::WorkspaceSwitch => { + layout.workspace_switch_gesture_end(false, Some(false)) + } + }; + + if let Some(output) = res { + state.niri.queue_redraw(&output); + } + + state.niri.pointer_grab_ongoing = false; + state + .niri + .cursor_manager + .set_cursor_image(CursorImageStatus::default_named()); + } +} + +impl PointerGrab for SpatialMovementGrab { + fn motion( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + _focus: Option<(::PointerFocus, Point)>, + event: &MotionEvent, + ) { + // While the grab is active, no client has pointer focus. + handle.motion(data, None, event); + + let timestamp = Duration::from_millis(u64::from(event.time)); + let delta = event.location - self.last_location; + self.last_location = event.location; + + let layout = &mut data.niri.layout; + let res = match self.gesture { + GestureState::Recognizing => { + let c = event.location - self.start_data.location; + + // Check if the gesture moved far enough to decide. Threshold copied from GTK 4. + if c.x * c.x + c.y * c.y >= 8. * 8. { + if c.x.abs() > c.y.abs() { + self.gesture = GestureState::ViewOffset; + layout.view_offset_gesture_begin(&self.output, false); + layout.view_offset_gesture_update(-c.x, timestamp, false) + } else { + self.gesture = GestureState::WorkspaceSwitch; + layout.workspace_switch_gesture_begin(&self.output, false); + layout.workspace_switch_gesture_update(-c.y, timestamp, false) + } + } else { + Some(None) + } + } + GestureState::ViewOffset => { + layout.view_offset_gesture_update(-delta.x, timestamp, false) + } + GestureState::WorkspaceSwitch => { + layout.workspace_switch_gesture_update(-delta.y, timestamp, false) + } + }; + + if let Some(output) = res { + if let Some(output) = output { + data.niri.queue_redraw(&output); + } + } else { + // The resize is no longer ongoing. + handle.unset_grab(self, data, event.serial, event.time, true); + } + } + + fn relative_motion( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + _focus: Option<(::PointerFocus, Point)>, + event: &RelativeMotionEvent, + ) { + // While the grab is active, no client has pointer focus. + handle.relative_motion(data, None, event); + } + + fn button( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + event: &ButtonEvent, + ) { + handle.button(data, event); + + if handle.current_pressed().is_empty() { + // No more buttons are pressed, release the grab. + handle.unset_grab(self, data, event.serial, event.time, true); + } + } + + fn axis( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + details: AxisFrame, + ) { + handle.axis(data, details); + } + + fn frame(&mut self, data: &mut State, handle: &mut PointerInnerHandle<'_, State>) { + handle.frame(data); + } + + fn gesture_swipe_begin( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + event: &GestureSwipeBeginEvent, + ) { + handle.gesture_swipe_begin(data, event); + } + + fn gesture_swipe_update( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + event: &GestureSwipeUpdateEvent, + ) { + handle.gesture_swipe_update(data, event); + } + + fn gesture_swipe_end( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + event: &GestureSwipeEndEvent, + ) { + handle.gesture_swipe_end(data, event); + } + + fn gesture_pinch_begin( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + event: &GesturePinchBeginEvent, + ) { + handle.gesture_pinch_begin(data, event); + } + + fn gesture_pinch_update( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + event: &GesturePinchUpdateEvent, + ) { + handle.gesture_pinch_update(data, event); + } + + fn gesture_pinch_end( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + event: &GesturePinchEndEvent, + ) { + handle.gesture_pinch_end(data, event); + } + + fn gesture_hold_begin( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + event: &GestureHoldBeginEvent, + ) { + handle.gesture_hold_begin(data, event); + } + + fn gesture_hold_end( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + event: &GestureHoldEndEvent, + ) { + handle.gesture_hold_end(data, event); + } + + fn start_data(&self) -> &PointerGrabStartData { + &self.start_data + } + + fn unset(&mut self, data: &mut State) { + self.on_ungrab(data); + } +} diff --git a/src/input/view_offset_grab.rs b/src/input/view_offset_grab.rs deleted file mode 100644 index b4f9f96c..00000000 --- a/src/input/view_offset_grab.rs +++ /dev/null @@ -1,190 +0,0 @@ -use std::time::Duration; - -use smithay::input::pointer::{ - AxisFrame, ButtonEvent, CursorImageStatus, GestureHoldBeginEvent, GestureHoldEndEvent, - GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent, GestureSwipeBeginEvent, - GestureSwipeEndEvent, GestureSwipeUpdateEvent, GrabStartData as PointerGrabStartData, - MotionEvent, PointerGrab, PointerInnerHandle, RelativeMotionEvent, -}; -use smithay::input::SeatHandler; -use smithay::utils::{Logical, Point}; - -use crate::niri::State; - -pub struct ViewOffsetGrab { - start_data: PointerGrabStartData, - last_location: Point, -} - -impl ViewOffsetGrab { - pub fn new(start_data: PointerGrabStartData) -> Self { - Self { - last_location: start_data.location, - start_data, - } - } - - fn on_ungrab(&mut self, state: &mut State) { - let res = state - .niri - .layout - .view_offset_gesture_end(false, Some(false)); - if let Some(output) = res { - state.niri.queue_redraw(&output); - } - - state.niri.pointer_grab_ongoing = false; - state - .niri - .cursor_manager - .set_cursor_image(CursorImageStatus::default_named()); - } -} - -impl PointerGrab for ViewOffsetGrab { - fn motion( - &mut self, - data: &mut State, - handle: &mut PointerInnerHandle<'_, State>, - _focus: Option<(::PointerFocus, Point)>, - event: &MotionEvent, - ) { - // While the grab is active, no client has pointer focus. - handle.motion(data, None, event); - - let timestamp = Duration::from_millis(u64::from(event.time)); - let delta = event.location - self.last_location; - self.last_location = event.location; - - let res = data - .niri - .layout - .view_offset_gesture_update(-delta.x, timestamp, false); - if let Some(output) = res { - if let Some(output) = output { - data.niri.queue_redraw(&output); - } - } else { - // The resize is no longer ongoing. - handle.unset_grab(self, data, event.serial, event.time, true); - } - } - - fn relative_motion( - &mut self, - data: &mut State, - handle: &mut PointerInnerHandle<'_, State>, - _focus: Option<(::PointerFocus, Point)>, - event: &RelativeMotionEvent, - ) { - // While the grab is active, no client has pointer focus. - handle.relative_motion(data, None, event); - } - - fn button( - &mut self, - data: &mut State, - handle: &mut PointerInnerHandle<'_, State>, - event: &ButtonEvent, - ) { - handle.button(data, event); - - if handle.current_pressed().is_empty() { - // No more buttons are pressed, release the grab. - handle.unset_grab(self, data, event.serial, event.time, true); - } - } - - fn axis( - &mut self, - data: &mut State, - handle: &mut PointerInnerHandle<'_, State>, - details: AxisFrame, - ) { - handle.axis(data, details); - } - - fn frame(&mut self, data: &mut State, handle: &mut PointerInnerHandle<'_, State>) { - handle.frame(data); - } - - fn gesture_swipe_begin( - &mut self, - data: &mut State, - handle: &mut PointerInnerHandle<'_, State>, - event: &GestureSwipeBeginEvent, - ) { - handle.gesture_swipe_begin(data, event); - } - - fn gesture_swipe_update( - &mut self, - data: &mut State, - handle: &mut PointerInnerHandle<'_, State>, - event: &GestureSwipeUpdateEvent, - ) { - handle.gesture_swipe_update(data, event); - } - - fn gesture_swipe_end( - &mut self, - data: &mut State, - handle: &mut PointerInnerHandle<'_, State>, - event: &GestureSwipeEndEvent, - ) { - handle.gesture_swipe_end(data, event); - } - - fn gesture_pinch_begin( - &mut self, - data: &mut State, - handle: &mut PointerInnerHandle<'_, State>, - event: &GesturePinchBeginEvent, - ) { - handle.gesture_pinch_begin(data, event); - } - - fn gesture_pinch_update( - &mut self, - data: &mut State, - handle: &mut PointerInnerHandle<'_, State>, - event: &GesturePinchUpdateEvent, - ) { - handle.gesture_pinch_update(data, event); - } - - fn gesture_pinch_end( - &mut self, - data: &mut State, - handle: &mut PointerInnerHandle<'_, State>, - event: &GesturePinchEndEvent, - ) { - handle.gesture_pinch_end(data, event); - } - - fn gesture_hold_begin( - &mut self, - data: &mut State, - handle: &mut PointerInnerHandle<'_, State>, - event: &GestureHoldBeginEvent, - ) { - handle.gesture_hold_begin(data, event); - } - - fn gesture_hold_end( - &mut self, - data: &mut State, - handle: &mut PointerInnerHandle<'_, State>, - event: &GestureHoldEndEvent, - ) { - handle.gesture_hold_end(data, event); - } - - fn start_data(&self) -> &PointerGrabStartData { - &self.start_data - } - - fn unset(&mut self, data: &mut State) { - self.on_ungrab(data); - } -} -- cgit