diff --git a/src/shell/grabs/delay.rs b/src/shell/grabs/delay.rs new file mode 100644 index 00000000..84446ef3 --- /dev/null +++ b/src/shell/grabs/delay.rs @@ -0,0 +1,285 @@ +use smithay::{ + input::{ + Seat, SeatHandler, + pointer::{ + AxisFrame, ButtonEvent, Focus, GestureHoldBeginEvent, GestureHoldEndEvent, + GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent, + GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent, + GrabStartData as PointerGrabStartData, MotionEvent as PointerMotionEvent, PointerGrab, + PointerInnerHandle, RelativeMotionEvent, + }, + touch::{ + DownEvent, GrabStartData as TouchGrabStartData, MotionEvent as TouchMotionEvent, + OrientationEvent, ShapeEvent, TouchGrab, TouchInnerHandle, UpEvent, + }, + }, + utils::{Logical, Point, SERIAL_COUNTER, Serial}, +}; + +use crate::state::State; + +use super::GrabStartData; + +pub struct DelayGrab { + grab_factory: Option Option<(G, Focus)>>>, + seat: Seat, + serial: Option, + start_data: GrabStartData, +} + +unsafe impl Send for DelayGrab {} + +impl DelayGrab { + pub fn new( + factory: impl FnOnce(&mut State) -> Option<(G, Focus)> + 'static, + seat: Seat, + serial: Option, + start_data: GrabStartData, + ) -> Self { + DelayGrab { + grab_factory: Some(Box::new(factory)), + seat, + serial, + start_data, + } + } + + pub fn is_touch_grab(&self) -> bool { + match self.start_data { + GrabStartData::Touch(_) => true, + GrabStartData::Pointer(_) => false, + } + } +} + +impl> PointerGrab for DelayGrab { + fn motion( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + focus: Option<(::PointerFocus, Point)>, + event: &PointerMotionEvent, + ) { + handle.motion(data, focus, event); + + let distance = self.start_data.distance(event.location); + if distance >= 1. { + if let Some(factory) = self.grab_factory.take() { + let serial = self.serial.unwrap_or(event.serial); + let seat = self.seat.clone(); + data.common.event_loop_handle.insert_idle(move |data| { + if let Some((grab, focus)) = factory(data) { + seat.get_pointer() + .unwrap() + .set_grab(data, grab, serial, focus); + } + }); + } + } + } + + fn relative_motion( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + focus: Option<(::PointerFocus, Point)>, + event: &RelativeMotionEvent, + ) { + handle.relative_motion(data, focus, event); + } + + fn button( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + event: &ButtonEvent, + ) { + handle.button(data, event); + if handle.current_pressed().is_empty() { + 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 { + match &self.start_data { + GrabStartData::Pointer(start_data) => start_data, + _ => unreachable!(), + } + } + + fn unset(&mut self, _data: &mut State) {} +} + +impl> TouchGrab for DelayGrab { + fn down( + &mut self, + data: &mut State, + handle: &mut TouchInnerHandle<'_, State>, + focus: Option<(::TouchFocus, Point)>, + event: &DownEvent, + seq: Serial, + ) { + handle.down(data, focus, 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 == TouchGrab::start_data(self).slot { + handle.unset_grab(self, data); + } + } + + fn motion( + &mut self, + data: &mut State, + handle: &mut TouchInnerHandle<'_, State>, + focus: Option<(::TouchFocus, Point)>, + event: &TouchMotionEvent, + seq: Serial, + ) { + handle.motion(data, focus, event, seq); + + let distance = self.start_data.distance(event.location); + if distance >= 1. { + if let Some(factory) = self.grab_factory.take() { + let seat = self.seat.clone(); + let serial = self.serial.unwrap_or_else(|| SERIAL_COUNTER.next_serial()); + data.common.event_loop_handle.insert_idle(move |data| { + if let Some((grab, _)) = factory(data) { + seat.get_touch().unwrap().set_grab(data, grab, serial); + } + }); + } + } + } + + 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 { + match &self.start_data { + GrabStartData::Touch(start_data) => start_data, + _ => unreachable!(), + } + } + + fn unset(&mut self, _data: &mut State) {} +} diff --git a/src/shell/grabs/mod.rs b/src/shell/grabs/mod.rs index 91741e33..0c5448c1 100644 --- a/src/shell/grabs/mod.rs +++ b/src/shell/grabs/mod.rs @@ -1,6 +1,8 @@ +use calloop::LoopHandle; use cosmic_settings_config::shortcuts; use smithay::{ input::{ + Seat, pointer::{ AxisFrame, ButtonEvent, GestureHoldBeginEvent, GestureHoldEndEvent, GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent, @@ -13,12 +15,20 @@ use smithay::{ OrientationEvent, ShapeEvent, TouchGrab, TouchInnerHandle, UpEvent, }, }, - reexports::wayland_protocols::xdg::shell::server::xdg_toplevel, + output::Output, + reexports::{ + wayland_protocols::xdg::shell::server::xdg_toplevel, + wayland_server::protocol::wl_surface::WlSurface, + }, utils::{Logical, Point, Serial}, xwayland::xwm, }; -use crate::state::State; +use crate::{ + shell::{CosmicMapped, ManagedLayer}, + state::State, + utils::prelude::Global, +}; use super::{ focus::target::PointerFocusTarget, @@ -59,6 +69,13 @@ impl GrabStartData { Self::Pointer(pointer) => pointer.location = location, } } + + pub fn distance(&self, cursor_location: Point) -> f64 { + let old = self.location(); + let new = cursor_location; + + ((new.x - old.x).powi(2) + (new.y - old.y).powi(2)).sqrt() + } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -70,7 +87,8 @@ pub enum ReleaseMode { mod menu; pub use self::menu::*; mod moving; -pub use self::moving::*; +pub use self::moving::SeatMoveGrabState; +mod delay; bitflags::bitflags! { #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -458,3 +476,345 @@ impl TouchGrab for ResizeGrab { } } } + +pub enum MoveGrab { + Move(moving::MoveGrab), + Delayed(delay::DelayGrab), +} + +impl MoveGrab { + pub fn new( + start_data: GrabStartData, + window: CosmicMapped, + seat: &Seat, + initial_window_location: Point, + cursor_output: Output, + indicator_thickness: u8, + edge_snap_threshold: f64, + previous_layer: ManagedLayer, + release: ReleaseMode, + evlh: LoopHandle<'static, State>, + ) -> MoveGrab { + MoveGrab::Move(moving::MoveGrab::new( + start_data, + window, + seat, + initial_window_location, + cursor_output, + indicator_thickness, + edge_snap_threshold, + previous_layer, + release, + evlh, + )) + } + + pub fn delayed( + start_data: GrabStartData, + surface: &WlSurface, + seat: &Seat, + serial: Option, + release: ReleaseMode, + move_out_of_stack: bool, + ) -> MoveGrab { + let surface = surface.clone(); + let seat_clone = seat.clone(); + + MoveGrab::Delayed(delay::DelayGrab::new( + move |data| { + data.common.shell.write().move_request( + &surface, + &seat_clone, + serial, + release, + move_out_of_stack, + &data.common.config, + &data.common.event_loop_handle, + false, + ) + }, + seat.clone(), + serial, + start_data, + )) + } + + pub fn is_tiling_grab(&self) -> bool { + match self { + MoveGrab::Move(m) => m.is_tiling_grab(), + _ => false, + } + } + + pub fn is_touch_grab(&self) -> bool { + match self { + MoveGrab::Move(m) => m.is_touch_grab(), + MoveGrab::Delayed(d) => d.is_touch_grab(), + } + } +} +impl PointerGrab for MoveGrab { + fn motion( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + focus: Option<(PointerFocusTarget, Point)>, + event: &MotionEvent, + ) { + match self { + MoveGrab::Move(grab) => PointerGrab::motion(grab, data, handle, focus, event), + MoveGrab::Delayed(grab) => PointerGrab::motion(grab, data, handle, focus, event), + } + } + + fn relative_motion( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + focus: Option<(PointerFocusTarget, Point)>, + event: &RelativeMotionEvent, + ) { + match self { + MoveGrab::Move(grab) => grab.relative_motion(data, handle, focus, event), + MoveGrab::Delayed(grab) => grab.relative_motion(data, handle, focus, event), + } + } + + fn button( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + event: &ButtonEvent, + ) { + match self { + MoveGrab::Move(grab) => grab.button(data, handle, event), + MoveGrab::Delayed(grab) => grab.button(data, handle, event), + } + } + + fn axis( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + details: AxisFrame, + ) { + match self { + MoveGrab::Move(grab) => grab.axis(data, handle, details), + MoveGrab::Delayed(grab) => grab.axis(data, handle, details), + } + } + + fn frame(&mut self, data: &mut State, handle: &mut PointerInnerHandle<'_, State>) { + match self { + MoveGrab::Move(grab) => PointerGrab::frame(grab, data, handle), + MoveGrab::Delayed(grab) => PointerGrab::frame(grab, data, handle), + } + } + + fn gesture_swipe_begin( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + event: &GestureSwipeBeginEvent, + ) { + match self { + MoveGrab::Move(grab) => grab.gesture_swipe_begin(data, handle, event), + MoveGrab::Delayed(grab) => grab.gesture_swipe_begin(data, handle, event), + } + } + + fn gesture_swipe_update( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + event: &GestureSwipeUpdateEvent, + ) { + match self { + MoveGrab::Move(grab) => grab.gesture_swipe_update(data, handle, event), + MoveGrab::Delayed(grab) => grab.gesture_swipe_update(data, handle, event), + } + } + + fn gesture_swipe_end( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + event: &GestureSwipeEndEvent, + ) { + match self { + MoveGrab::Move(grab) => grab.gesture_swipe_end(data, handle, event), + MoveGrab::Delayed(grab) => grab.gesture_swipe_end(data, handle, event), + } + } + + fn gesture_pinch_begin( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + event: &GesturePinchBeginEvent, + ) { + match self { + MoveGrab::Move(grab) => grab.gesture_pinch_begin(data, handle, event), + MoveGrab::Delayed(grab) => grab.gesture_pinch_begin(data, handle, event), + } + } + + fn gesture_pinch_update( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + event: &GesturePinchUpdateEvent, + ) { + match self { + MoveGrab::Move(grab) => grab.gesture_pinch_update(data, handle, event), + MoveGrab::Delayed(grab) => grab.gesture_pinch_update(data, handle, event), + } + } + + fn gesture_pinch_end( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + event: &GesturePinchEndEvent, + ) { + match self { + MoveGrab::Move(grab) => grab.gesture_pinch_end(data, handle, event), + MoveGrab::Delayed(grab) => grab.gesture_pinch_end(data, handle, event), + } + } + + fn gesture_hold_begin( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + event: &GestureHoldBeginEvent, + ) { + match self { + MoveGrab::Move(grab) => grab.gesture_hold_begin(data, handle, event), + MoveGrab::Delayed(grab) => grab.gesture_hold_begin(data, handle, event), + } + } + + fn gesture_hold_end( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + event: &GestureHoldEndEvent, + ) { + match self { + MoveGrab::Move(grab) => grab.gesture_hold_end(data, handle, event), + MoveGrab::Delayed(grab) => grab.gesture_hold_end(data, handle, event), + } + } + + fn start_data(&self) -> &PointerGrabStartData { + match self { + MoveGrab::Move(grab) => PointerGrab::start_data(grab), + MoveGrab::Delayed(grab) => PointerGrab::start_data(grab), + } + } + + fn unset(&mut self, data: &mut State) { + match self { + MoveGrab::Move(grab) => PointerGrab::unset(grab, data), + MoveGrab::Delayed(grab) => PointerGrab::unset(grab, data), + } + } +} + +impl TouchGrab for MoveGrab { + fn down( + &mut self, + data: &mut State, + handle: &mut TouchInnerHandle<'_, State>, + focus: Option<(PointerFocusTarget, Point)>, + event: &DownEvent, + seq: Serial, + ) { + match self { + MoveGrab::Move(grab) => TouchGrab::down(grab, data, handle, focus, event, seq), + MoveGrab::Delayed(grab) => TouchGrab::down(grab, data, handle, focus, event, seq), + } + } + + fn up( + &mut self, + data: &mut State, + handle: &mut TouchInnerHandle<'_, State>, + event: &UpEvent, + seq: Serial, + ) { + match self { + MoveGrab::Move(grab) => TouchGrab::up(grab, data, handle, event, seq), + MoveGrab::Delayed(grab) => TouchGrab::up(grab, data, handle, event, seq), + } + } + + fn motion( + &mut self, + data: &mut State, + handle: &mut TouchInnerHandle<'_, State>, + focus: Option<(PointerFocusTarget, Point)>, + event: &TouchMotionEvent, + seq: Serial, + ) { + match self { + MoveGrab::Move(grab) => TouchGrab::motion(grab, data, handle, focus, event, seq), + MoveGrab::Delayed(grab) => TouchGrab::motion(grab, data, handle, focus, event, seq), + } + } + + fn frame(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, seq: Serial) { + match self { + MoveGrab::Move(grab) => TouchGrab::frame(grab, data, handle, seq), + MoveGrab::Delayed(grab) => TouchGrab::frame(grab, data, handle, seq), + } + } + + fn cancel(&mut self, data: &mut State, handle: &mut TouchInnerHandle<'_, State>, seq: Serial) { + match self { + MoveGrab::Move(grab) => TouchGrab::cancel(grab, data, handle, seq), + MoveGrab::Delayed(grab) => TouchGrab::cancel(grab, data, handle, seq), + } + } + + fn shape( + &mut self, + data: &mut State, + handle: &mut TouchInnerHandle<'_, State>, + event: &ShapeEvent, + seq: Serial, + ) { + match self { + MoveGrab::Move(grab) => TouchGrab::shape(grab, data, handle, event, seq), + MoveGrab::Delayed(grab) => TouchGrab::shape(grab, data, handle, event, seq), + } + } + + fn orientation( + &mut self, + data: &mut State, + handle: &mut TouchInnerHandle<'_, State>, + event: &OrientationEvent, + seq: Serial, + ) { + match self { + MoveGrab::Move(grab) => TouchGrab::orientation(grab, data, handle, event, seq), + MoveGrab::Delayed(grab) => TouchGrab::orientation(grab, data, handle, event, seq), + } + } + + fn start_data(&self) -> &TouchGrabStartData { + match self { + MoveGrab::Move(grab) => TouchGrab::start_data(grab), + MoveGrab::Delayed(grab) => TouchGrab::start_data(grab), + } + } + + fn unset(&mut self, data: &mut State) { + match self { + MoveGrab::Move(grab) => TouchGrab::unset(grab, data), + MoveGrab::Delayed(grab) => TouchGrab::unset(grab, data), + } + } +} diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 2090ddf9..7e06090f 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -3498,6 +3498,22 @@ impl Shell { let mut start_data = check_grab_preconditions(seat, serial, client_initiated.then_some(surface))?; + if client_initiated + && start_data.distance(seat.get_pointer().unwrap().current_location()) < 1. + { + return Some(( + MoveGrab::delayed( + start_data, + surface, + seat, + serial, + release, + move_out_of_stack, + ), + Focus::Keep, + )); + } + let maybe_fullscreen_workspace = self .workspaces .spaces_mut()