diff options
| author | Ivan Molodetskikh <yalterz@gmail.com> | 2024-10-20 08:23:16 +0300 |
|---|---|---|
| committer | Ivan Molodetskikh <yalterz@gmail.com> | 2024-10-27 23:07:39 -0700 |
| commit | 26ab4dfb87550b2f8ceed5d11be614a239703fd7 (patch) | |
| tree | b18cfb830f34e2c308cb11159b8459b31be5f9aa | |
| parent | e887ee93a30390b641bf647d694a1424f7ce4592 (diff) | |
| download | niri-26ab4dfb87550b2f8ceed5d11be614a239703fd7.tar.gz niri-26ab4dfb87550b2f8ceed5d11be614a239703fd7.tar.bz2 niri-26ab4dfb87550b2f8ceed5d11be614a239703fd7.zip | |
Implement touch interactive move
| -rw-r--r-- | src/handlers/xdg_shell.rs | 60 | ||||
| -rw-r--r-- | src/input/mod.rs | 20 | ||||
| -rw-r--r-- | src/input/move_grab.rs | 2 | ||||
| -rw-r--r-- | src/input/touch_move_grab.rs | 136 |
4 files changed, 200 insertions, 18 deletions
diff --git a/src/handlers/xdg_shell.rs b/src/handlers/xdg_shell.rs index 2397f22a..856a0453 100644 --- a/src/handlers/xdg_shell.rs +++ b/src/handlers/xdg_shell.rs @@ -6,7 +6,7 @@ use smithay::desktop::{ PopupKeyboardGrab, PopupKind, PopupManager, PopupPointerGrab, PopupUngrabStrategy, Window, WindowSurfaceType, }; -use smithay::input::pointer::{Focus, PointerGrab}; +use smithay::input::pointer::Focus; use smithay::output::Output; use smithay::reexports::wayland_protocols::xdg::decoration::zv1::server::zxdg_toplevel_decoration_v1; use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_positioner::ConstraintAdjustment; @@ -38,7 +38,8 @@ use tracing::field::Empty; use crate::input::move_grab::MoveGrab; use crate::input::resize_grab::ResizeGrab; -use crate::input::DOUBLE_CLICK_TIME; +use crate::input::touch_move_grab::TouchMoveGrab; +use crate::input::{PointerOrTouchStartData, DOUBLE_CLICK_TIME}; use crate::layout::workspace::ColumnWidth; use crate::niri::{PopupGrabState, State}; use crate::utils::transaction::Transaction; @@ -67,24 +68,39 @@ impl XdgShellHandler for State { } fn move_request(&mut self, surface: ToplevelSurface, _seat: WlSeat, serial: Serial) { + let wl_surface = surface.wl_surface(); + + let mut grab_start_data = None; + + // See if this comes from a pointer grab. let pointer = self.niri.seat.get_pointer().unwrap(); - if !pointer.has_grab(serial) { - return; + if pointer.has_grab(serial) { + if let Some(start_data) = pointer.grab_start_data() { + if let Some((focus, _)) = &start_data.focus { + if focus.id().same_client_as(&wl_surface.id()) { + grab_start_data = Some(PointerOrTouchStartData::Pointer(start_data)); + } + } + } } - let Some(start_data) = pointer.grab_start_data() else { - return; - }; + // See if this comes from a touch grab. + if let Some(touch) = self.niri.seat.get_touch() { + if touch.has_grab(serial) { + if let Some(start_data) = touch.grab_start_data() { + if let Some((focus, _)) = &start_data.focus { + if focus.id().same_client_as(&wl_surface.id()) { + grab_start_data = Some(PointerOrTouchStartData::Touch(start_data)); + } + } + } + } + } - let Some((focus, _)) = &start_data.focus else { + let Some(start_data) = grab_start_data else { return; }; - let wl_surface = surface.wl_surface(); - if !focus.id().same_client_as(&wl_surface.id()) { - return; - } - let Some((mapped, output)) = self.niri.layout.find_window_and_output(wl_surface) else { return; }; @@ -100,7 +116,7 @@ impl XdgShellHandler for State { .loc .to_f64(); - let pos_within_output = start_data.location - output_pos; + let pos_within_output = start_data.location() - output_pos; if !self .niri @@ -110,10 +126,20 @@ impl XdgShellHandler for State { return; } - let grab = MoveGrab::new(start_data, window.clone()); + match start_data { + PointerOrTouchStartData::Pointer(start_data) => { + let grab = MoveGrab::new(start_data, window); + pointer.set_grab(self, grab, serial, Focus::Clear); + self.niri.pointer_grab_ongoing = true; + } + PointerOrTouchStartData::Touch(start_data) => { + let touch = self.niri.seat.get_touch().unwrap(); + let grab = TouchMoveGrab::new(start_data, window); + touch.set_grab(self, grab, serial); + } + } - pointer.set_grab(self, grab, serial, Focus::Clear); - self.niri.pointer_grab_ongoing = true; + self.niri.queue_redraw(&output); } fn resize_request( diff --git a/src/input/mod.rs b/src/input/mod.rs index b3e38892..11612f2f 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -24,7 +24,10 @@ use smithay::input::pointer::{ GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent, GrabStartData as PointerGrabStartData, MotionEvent, RelativeMotionEvent, }; -use smithay::input::touch::{DownEvent, MotionEvent as TouchMotionEvent, UpEvent}; +use smithay::input::touch::{ + DownEvent, GrabStartData as TouchGrabStartData, MotionEvent as TouchMotionEvent, UpEvent, +}; +use smithay::input::SeatHandler; 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}; @@ -42,6 +45,7 @@ pub mod resize_grab; pub mod scroll_tracker; pub mod spatial_movement_grab; pub mod swipe_tracker; +pub mod touch_move_grab; pub const DOUBLE_CLICK_TIME: Duration = Duration::from_millis(400); @@ -56,6 +60,20 @@ pub struct TabletData { pub aspect_ratio: f64, } +pub enum PointerOrTouchStartData<D: SeatHandler> { + Pointer(PointerGrabStartData<D>), + Touch(TouchGrabStartData<D>), +} + +impl<D: SeatHandler> PointerOrTouchStartData<D> { + pub fn location(&self) -> Point<f64, Logical> { + match self { + PointerOrTouchStartData::Pointer(x) => x.location, + PointerOrTouchStartData::Touch(x) => x.location, + } + } +} + impl State { pub fn process_input_event<I: InputBackend + 'static>(&mut self, event: InputEvent<I>) where diff --git a/src/input/move_grab.rs b/src/input/move_grab.rs index 71d115d7..e62a74f8 100644 --- a/src/input/move_grab.rs +++ b/src/input/move_grab.rs @@ -73,6 +73,8 @@ impl PointerGrab<State> for MoveGrab { false, ); } + // FIXME: only redraw the previous and the new output. + data.niri.queue_redraw_all(); return; } } else { diff --git a/src/input/touch_move_grab.rs b/src/input/touch_move_grab.rs new file mode 100644 index 00000000..e69f4c6e --- /dev/null +++ b/src/input/touch_move_grab.rs @@ -0,0 +1,136 @@ +use smithay::desktop::Window; +use smithay::input::touch::{ + DownEvent, GrabStartData as TouchGrabStartData, MotionEvent, OrientationEvent, ShapeEvent, + TouchGrab, TouchInnerHandle, UpEvent, +}; +use smithay::input::SeatHandler; +use smithay::utils::{IsAlive, Logical, Point, Serial}; + +use crate::niri::State; + +pub struct TouchMoveGrab { + start_data: TouchGrabStartData<State>, + last_location: Point<f64, Logical>, + window: Window, +} + +impl TouchMoveGrab { + pub fn new(start_data: TouchGrabStartData<State>, window: Window) -> Self { + Self { + last_location: start_data.location, + start_data, + window, + } + } + + 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(); + } +} + +impl TouchGrab<State> for TouchMoveGrab { + fn down( + &mut self, + data: &mut State, + handle: &mut TouchInnerHandle<'_, State>, + _focus: Option<(<State as SeatHandler>::TouchFocus, Point<f64, Logical>)>, + event: &DownEvent, + seq: Serial, + ) { + handle.down(data, None, event, seq); + } + + fn up( + &mut self, + data: &mut State, + handle: &mut TouchInnerHandle<'_, State>, + event: &UpEvent, + seq: Serial, + ) { + handle.up(data, event, seq); + + if event.slot != self.start_data.slot { + return; + } + + handle.unset_grab(self, data); + } + + fn motion( + &mut self, + data: &mut State, + handle: &mut TouchInnerHandle<'_, State>, + _focus: Option<(<State as SeatHandler>::TouchFocus, Point<f64, Logical>)>, + event: &MotionEvent, + seq: Serial, + ) { + handle.motion(data, None, event, seq); + + if event.slot != self.start_data.slot { + return; + } + + 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 { + // FIXME: only redraw the previous and the new output. + data.niri.queue_redraw_all(); + return; + } + } else { + return; + } + } + + // The move is no longer ongoing. + handle.unset_grab(self, data); + } + + fn frame(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, seq: Serial) { + handle.frame(data, seq); + } + + fn cancel(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, seq: Serial) { + handle.cancel(data, seq); + handle.unset_grab(self, data); + } + + fn shape( + &mut self, + data: &mut State, + handle: &mut TouchInnerHandle<'_, State>, + event: &ShapeEvent, + seq: Serial, + ) { + handle.shape(data, event, seq); + } + + fn orientation( + &mut self, + data: &mut State, + handle: &mut TouchInnerHandle<'_, State>, + event: &OrientationEvent, + seq: Serial, + ) { + handle.orientation(data, event, seq); + } + + fn start_data(&self) -> &TouchGrabStartData<State> { + &self.start_data + } + + fn unset(&mut self, data: &mut State) { + self.on_ungrab(data); + } +} |
