aboutsummaryrefslogtreecommitdiff
path: root/src/input
diff options
context:
space:
mode:
Diffstat (limited to 'src/input')
-rw-r--r--src/input/mod.rs37
-rw-r--r--src/input/move_grab.rs223
2 files changed, 259 insertions, 1 deletions
diff --git a/src/input/mod.rs b/src/input/mod.rs
index 3bccb714..b3e38892 100644
--- a/src/input/mod.rs
+++ b/src/input/mod.rs
@@ -29,6 +29,7 @@ use smithay::utils::{Logical, Point, Rectangle, Transform, SERIAL_COUNTER};
use smithay::wayland::pointer_constraints::{with_pointer_constraint, PointerConstraint};
use smithay::wayland::tablet_manager::{TabletDescriptor, TabletSeatTrait};
+use self::move_grab::MoveGrab;
use self::resize_grab::ResizeGrab;
use self::spatial_movement_grab::SpatialMovementGrab;
use crate::niri::State;
@@ -36,6 +37,7 @@ use crate::ui::screenshot_ui::ScreenshotUi;
use crate::utils::spawning::spawn;
use crate::utils::{center, get_monotonic_time, ResizeEdge};
+pub mod move_grab;
pub mod resize_grab;
pub mod scroll_tracker;
pub mod spatial_movement_grab;
@@ -1535,8 +1537,41 @@ impl State {
if let Some(mapped) = self.niri.window_under_cursor() {
let window = mapped.window.clone();
+ // Check if we need to start an interactive move.
+ if event.button() == Some(MouseButton::Left) && !pointer.is_grabbed() {
+ let mods = self.niri.seat.get_keyboard().unwrap().modifier_state();
+ let mod_down = match self.backend.mod_key() {
+ CompositorMod::Super => mods.logo,
+ CompositorMod::Alt => mods.alt,
+ };
+ if mod_down {
+ let location = pointer.current_location();
+ let (output, pos_within_output) = self.niri.output_under(location).unwrap();
+ let output = output.clone();
+
+ self.niri.layout.activate_window(&window);
+
+ if self.niri.layout.interactive_move_begin(
+ window.clone(),
+ &output,
+ pos_within_output,
+ ) {
+ let start_data = PointerGrabStartData {
+ focus: None,
+ button: event.button_code(),
+ location,
+ };
+ let grab = MoveGrab::new(start_data, window.clone());
+ pointer.set_grab(self, grab, serial, Focus::Clear);
+ self.niri.pointer_grab_ongoing = true;
+ self.niri
+ .cursor_manager
+ .set_cursor_image(CursorImageStatus::Named(CursorIcon::Move));
+ }
+ }
+ }
// Check if we need to start an interactive resize.
- if event.button() == Some(MouseButton::Right) && !pointer.is_grabbed() {
+ else if event.button() == Some(MouseButton::Right) && !pointer.is_grabbed() {
let mods = self.niri.seat.get_keyboard().unwrap().modifier_state();
let mod_down = match self.backend.mod_key() {
CompositorMod::Super => mods.logo,
diff --git a/src/input/move_grab.rs b/src/input/move_grab.rs
new file mode 100644
index 00000000..71d115d7
--- /dev/null
+++ b/src/input/move_grab.rs
@@ -0,0 +1,223 @@
+use std::time::Duration;
+
+use smithay::backend::input::ButtonState;
+use smithay::desktop::Window;
+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::{IsAlive, Logical, Point};
+
+use crate::niri::State;
+
+pub struct MoveGrab {
+ start_data: PointerGrabStartData<State>,
+ last_location: Point<f64, Logical>,
+ window: Window,
+ is_moving: bool,
+}
+
+impl MoveGrab {
+ pub fn new(start_data: PointerGrabStartData<State>, window: Window) -> Self {
+ Self {
+ last_location: start_data.location,
+ start_data,
+ window,
+ is_moving: false,
+ }
+ }
+
+ fn on_ungrab(&mut self, state: &mut State) {
+ state.niri.layout.interactive_move_end(&self.window);
+ // FIXME: only redraw the window output.
+ state.niri.queue_redraw_all();
+ state.niri.pointer_grab_ongoing = false;
+ state
+ .niri
+ .cursor_manager
+ .set_cursor_image(CursorImageStatus::default_named());
+ }
+}
+
+impl PointerGrab<State> for MoveGrab {
+ 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);
+
+ if self.window.alive() {
+ if let Some((output, pos_within_output)) = data.niri.output_under(event.location) {
+ let output = output.clone();
+ let event_delta = event.location - self.last_location;
+ self.last_location = event.location;
+ let ongoing = data.niri.layout.interactive_move_update(
+ &self.window,
+ event_delta,
+ output,
+ pos_within_output,
+ );
+ if ongoing {
+ let timestamp = Duration::from_millis(u64::from(event.time));
+ if self.is_moving {
+ data.niri.layout.view_offset_gesture_update(
+ -event_delta.x,
+ timestamp,
+ false,
+ );
+ }
+ return;
+ }
+ } else {
+ return;
+ }
+ }
+
+ // The move 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);
+
+ // MouseButton::Middle
+ if event.button == 0x112 {
+ if event.state == ButtonState::Pressed {
+ let output = data
+ .niri
+ .output_under(handle.current_location())
+ .map(|(output, _)| output)
+ .cloned();
+ // TODO: workspace switch gesture.
+ if let Some(output) = output {
+ self.is_moving = true;
+ data.niri.layout.view_offset_gesture_begin(&output, false);
+ }
+ } else if event.state == ButtonState::Released {
+ self.is_moving = false;
+ data.niri.layout.view_offset_gesture_end(false, None);
+ }
+ }
+
+ 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);
+ }
+}