aboutsummaryrefslogtreecommitdiff
path: root/src/input/spatial_movement_grab.rs
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2024-06-19 21:54:46 +0300
committerIvan Molodetskikh <yalterz@gmail.com>2024-06-19 21:55:39 +0300
commitdb89d4d3dd1440e18193d4ce98d207531c7720e0 (patch)
tree9c4974f68ad38928d4bb0b53f219cc607cf9ea59 /src/input/spatial_movement_grab.rs
parent226273f6607ae83b17c06e0e094ace64ed7a4f7c (diff)
downloadniri-db89d4d3dd1440e18193d4ce98d207531c7720e0.tar.gz
niri-db89d4d3dd1440e18193d4ce98d207531c7720e0.tar.bz2
niri-db89d4d3dd1440e18193d4ce98d207531c7720e0.zip
Implement vertical middle mouse gesture
Diffstat (limited to 'src/input/spatial_movement_grab.rs')
-rw-r--r--src/input/spatial_movement_grab.rs231
1 files changed, 231 insertions, 0 deletions
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<State>,
+ last_location: Point<f64, Logical>,
+ output: Output,
+ gesture: GestureState,
+}
+
+#[derive(Debug, Clone, Copy)]
+enum GestureState {
+ Recognizing,
+ ViewOffset,
+ WorkspaceSwitch,
+}
+
+impl SpatialMovementGrab {
+ pub fn new(start_data: PointerGrabStartData<State>, 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<State> for SpatialMovementGrab {
+ fn motion(
+ &mut self,
+ data: &mut State,
+ handle: &mut PointerInnerHandle<'_, State>,
+ _focus: Option<(<State as SeatHandler>::PointerFocus, Point<f64, Logical>)>,
+ 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<(<State as SeatHandler>::PointerFocus, Point<f64, Logical>)>,
+ 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<State> {
+ &self.start_data
+ }
+
+ fn unset(&mut self, data: &mut State) {
+ self.on_ungrab(data);
+ }
+}