diff options
Diffstat (limited to 'src/input')
| -rw-r--r-- | src/input/mod.rs | 37 | ||||
| -rw-r--r-- | src/input/move_grab.rs | 223 |
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); + } +} |
