mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-21 02:01:55 +07:00
Unify pointer & touch move grab, add view offset to it
This commit is contained in:
@@ -40,7 +40,6 @@ use tracing::field::Empty;
|
||||
|
||||
use crate::input::move_grab::MoveGrab;
|
||||
use crate::input::resize_grab::ResizeGrab;
|
||||
use crate::input::touch_move_grab::TouchMoveGrab;
|
||||
use crate::input::touch_resize_grab::TouchResizeGrab;
|
||||
use crate::input::{PointerOrTouchStartData, DOUBLE_CLICK_TIME};
|
||||
use crate::layout::ActivateWindow;
|
||||
@@ -133,33 +132,17 @@ impl XdgShellHandler for State {
|
||||
let window = mapped.window.clone();
|
||||
let output = output.clone();
|
||||
|
||||
let output_pos = self
|
||||
.niri
|
||||
.global_space
|
||||
.output_geometry(&output)
|
||||
.unwrap()
|
||||
.loc
|
||||
.to_f64();
|
||||
|
||||
let pos_within_output = start_data.location() - output_pos;
|
||||
|
||||
if !self
|
||||
.niri
|
||||
.layout
|
||||
.interactive_move_begin(window.clone(), &output, pos_within_output)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
match start_data {
|
||||
PointerOrTouchStartData::Pointer(start_data) => {
|
||||
let grab = MoveGrab::new(start_data, window, false);
|
||||
pointer.set_grab(self, grab, serial, Focus::Clear);
|
||||
match &start_data {
|
||||
PointerOrTouchStartData::Pointer(_) => {
|
||||
if let Some(grab) = MoveGrab::new(self, start_data, window.clone(), true) {
|
||||
pointer.set_grab(self, grab, serial, Focus::Clear);
|
||||
}
|
||||
}
|
||||
PointerOrTouchStartData::Touch(start_data) => {
|
||||
PointerOrTouchStartData::Touch(_) => {
|
||||
let touch = self.niri.seat.get_touch().unwrap();
|
||||
let grab = TouchMoveGrab::new(start_data, window);
|
||||
touch.set_grab(self, grab, serial);
|
||||
if let Some(grab) = MoveGrab::new(self, start_data, window.clone(), true) {
|
||||
touch.set_grab(self, grab, serial);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+44
-37
@@ -36,7 +36,6 @@ use smithay::wayland::keyboard_shortcuts_inhibit::KeyboardShortcutsInhibitor;
|
||||
use smithay::wayland::pointer_constraints::{with_pointer_constraint, PointerConstraint};
|
||||
use smithay::wayland::selection::data_device::DnDGrab;
|
||||
use smithay::wayland::tablet_manager::{TabletDescriptor, TabletSeatTrait};
|
||||
use touch_move_grab::TouchMoveGrab;
|
||||
use touch_overview_grab::TouchOverviewGrab;
|
||||
|
||||
use self::move_grab::MoveGrab;
|
||||
@@ -59,7 +58,6 @@ pub mod scroll_swipe_gesture;
|
||||
pub mod scroll_tracker;
|
||||
pub mod spatial_movement_grab;
|
||||
pub mod swipe_tracker;
|
||||
pub mod touch_move_grab;
|
||||
pub mod touch_overview_grab;
|
||||
pub mod touch_resize_grab;
|
||||
|
||||
@@ -84,6 +82,28 @@ impl<D: SeatHandler> PointerOrTouchStartData<D> {
|
||||
PointerOrTouchStartData::Touch(x) => x.location,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unwrap_pointer(&self) -> &PointerGrabStartData<D> {
|
||||
match self {
|
||||
PointerOrTouchStartData::Pointer(x) => x,
|
||||
PointerOrTouchStartData::Touch(_) => panic!("start_data is not Pointer"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unwrap_touch(&self) -> &TouchGrabStartData<D> {
|
||||
match self {
|
||||
PointerOrTouchStartData::Pointer(_) => panic!("start_data is not Touch"),
|
||||
PointerOrTouchStartData::Touch(x) => x,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_pointer(&self) -> bool {
|
||||
matches!(self, Self::Pointer(_))
|
||||
}
|
||||
|
||||
pub fn is_touch(&self) -> bool {
|
||||
matches!(self, Self::Touch(_))
|
||||
}
|
||||
}
|
||||
|
||||
impl State {
|
||||
@@ -2773,31 +2793,19 @@ impl State {
|
||||
let mod_down = modifiers_from_state(mods).contains(mod_key.to_modifiers());
|
||||
if is_overview_open || mod_down {
|
||||
let location = pointer.current_location();
|
||||
let (output, pos_within_output) = self.niri.output_under(location).unwrap();
|
||||
let output = output.clone();
|
||||
|
||||
if !is_overview_open {
|
||||
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: button_code,
|
||||
location,
|
||||
};
|
||||
let grab = MoveGrab::new(start_data, window.clone(), is_overview_open);
|
||||
let start_data = PointerGrabStartData {
|
||||
focus: None,
|
||||
button: button_code,
|
||||
location,
|
||||
};
|
||||
let start_data = PointerOrTouchStartData::Pointer(start_data);
|
||||
if let Some(grab) = MoveGrab::new(self, start_data, window.clone(), false) {
|
||||
pointer.set_grab(self, grab, serial, Focus::Clear);
|
||||
|
||||
if !is_overview_open {
|
||||
self.niri
|
||||
.cursor_manager
|
||||
.set_cursor_image(CursorImageStatus::Named(CursorIcon::Move));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4037,22 +4045,15 @@ impl State {
|
||||
} else if let Some((window, _)) = under.window {
|
||||
self.niri.layout.activate_window(&window);
|
||||
|
||||
// Check if we need to start an interactive move.
|
||||
// Check if we need to start a touch move grab.
|
||||
if mod_down {
|
||||
let (output, pos_within_output) = self.niri.output_under(pos).unwrap();
|
||||
let output = output.clone();
|
||||
|
||||
if self.niri.layout.interactive_move_begin(
|
||||
window.clone(),
|
||||
&output,
|
||||
pos_within_output,
|
||||
) {
|
||||
let start_data = TouchGrabStartData {
|
||||
focus: None,
|
||||
slot,
|
||||
location: pos,
|
||||
};
|
||||
let grab = TouchMoveGrab::new(start_data, window.clone());
|
||||
let start_data = TouchGrabStartData {
|
||||
focus: None,
|
||||
slot,
|
||||
location: pos,
|
||||
};
|
||||
let start_data = PointerOrTouchStartData::Touch(start_data);
|
||||
if let Some(grab) = MoveGrab::new(self, start_data, window.clone(), true) {
|
||||
handle.set_grab(self, grab, serial);
|
||||
}
|
||||
}
|
||||
@@ -4908,13 +4909,19 @@ fn grab_allows_hot_corner(grab: &(dyn PointerGrab<State> + 'static)) -> bool {
|
||||
//
|
||||
// Some notable grabs not mentioned here:
|
||||
// - DnDGrab allows hot corner to DnD across workspaces.
|
||||
// - MoveGrab allows hot corner to DnD across workspaces.
|
||||
// - ClickGrab keeps pointer focus on the window, so the hot corner doesn't trigger.
|
||||
// - Touch grabs: touch doesn't trigger the hot corner.
|
||||
if grab.is::<ResizeGrab>() || grab.is::<SpatialMovementGrab>() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if let Some(grab) = grab.downcast_ref::<MoveGrab>() {
|
||||
// Window move allows hot corner to DnD across workspaces.
|
||||
if !grab.is_move() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
|
||||
+341
-67
@@ -1,3 +1,5 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use smithay::backend::input::ButtonState;
|
||||
use smithay::desktop::Window;
|
||||
use smithay::input::pointer::{
|
||||
@@ -7,52 +9,260 @@ use smithay::input::pointer::{
|
||||
GrabStartData as PointerGrabStartData, MotionEvent, PointerGrab, PointerInnerHandle,
|
||||
RelativeMotionEvent,
|
||||
};
|
||||
use smithay::input::touch::{
|
||||
self, GrabStartData as TouchGrabStartData, TouchGrab, TouchInnerHandle,
|
||||
};
|
||||
use smithay::input::SeatHandler;
|
||||
use smithay::utils::{IsAlive, Logical, Point};
|
||||
use smithay::output::Output;
|
||||
use smithay::utils::{IsAlive, Logical, Point, Serial};
|
||||
|
||||
use crate::input::PointerOrTouchStartData;
|
||||
use crate::niri::State;
|
||||
|
||||
pub struct MoveGrab {
|
||||
start_data: PointerGrabStartData<State>,
|
||||
start_data: PointerOrTouchStartData<State>,
|
||||
start_output: Output,
|
||||
start_pos_within_output: Point<f64, Logical>,
|
||||
last_location: Point<f64, Logical>,
|
||||
window: Window,
|
||||
gesture: GestureState,
|
||||
enable_view_offset: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum GestureState {
|
||||
Recognizing,
|
||||
Move,
|
||||
ViewOffset,
|
||||
}
|
||||
|
||||
impl MoveGrab {
|
||||
pub fn new(
|
||||
start_data: PointerGrabStartData<State>,
|
||||
state: &mut State,
|
||||
start_data: PointerOrTouchStartData<State>,
|
||||
window: Window,
|
||||
use_threshold: bool,
|
||||
) -> Self {
|
||||
let gesture = if use_threshold {
|
||||
GestureState::Recognizing
|
||||
} else {
|
||||
GestureState::Move
|
||||
};
|
||||
enable_view_offset: bool,
|
||||
) -> Option<Self> {
|
||||
let (output, pos_within_output) = state.niri.output_under(start_data.location())?;
|
||||
|
||||
Self {
|
||||
last_location: start_data.location,
|
||||
Some(Self {
|
||||
last_location: start_data.location(),
|
||||
start_data,
|
||||
start_output: output.clone(),
|
||||
start_pos_within_output: pos_within_output,
|
||||
window,
|
||||
gesture,
|
||||
}
|
||||
gesture: GestureState::Recognizing,
|
||||
enable_view_offset,
|
||||
})
|
||||
}
|
||||
|
||||
fn on_ungrab(&mut self, state: &mut State) {
|
||||
state.niri.layout.interactive_move_end(&self.window);
|
||||
pub fn is_move(&self) -> bool {
|
||||
self.gesture == GestureState::Move
|
||||
}
|
||||
|
||||
fn on_ungrab(&mut self, data: &mut State) {
|
||||
let layout = &mut data.niri.layout;
|
||||
match self.gesture {
|
||||
GestureState::Recognizing => {
|
||||
// Activate the window on release. This is most prominent in the overview where
|
||||
// windows are not activated on click. In the overview, we also try to do a nice
|
||||
// synchronized workspace animation.
|
||||
if layout.is_overview_open() {
|
||||
let res = layout.workspaces().find_map(|(mon, ws_idx, ws)| {
|
||||
ws.windows()
|
||||
.any(|w| w.window == self.window)
|
||||
.then(|| (mon.map(|mon| mon.output().clone()), ws_idx))
|
||||
});
|
||||
if let Some((Some(output), ws_idx)) = res {
|
||||
layout.focus_output(&output);
|
||||
layout.toggle_overview_to_workspace(ws_idx);
|
||||
}
|
||||
}
|
||||
|
||||
layout.activate_window(&self.window);
|
||||
}
|
||||
GestureState::Move => layout.interactive_move_end(&self.window),
|
||||
GestureState::ViewOffset => {
|
||||
layout.view_offset_gesture_end(Some(false));
|
||||
}
|
||||
}
|
||||
|
||||
if self.start_data.is_pointer() {
|
||||
data.niri
|
||||
.cursor_manager
|
||||
.set_cursor_image(CursorImageStatus::default_named());
|
||||
}
|
||||
|
||||
// FIXME: only redraw the window output.
|
||||
state.niri.queue_redraw_all();
|
||||
state
|
||||
.niri
|
||||
.cursor_manager
|
||||
.set_cursor_image(CursorImageStatus::default_named());
|
||||
data.niri.queue_redraw_all();
|
||||
}
|
||||
|
||||
fn begin_move(&mut self, data: &mut State) -> bool {
|
||||
if !data.niri.layout.interactive_move_begin(
|
||||
self.window.clone(),
|
||||
&self.start_output,
|
||||
self.start_pos_within_output,
|
||||
) {
|
||||
// Can no longer start the move.
|
||||
return false;
|
||||
}
|
||||
|
||||
self.gesture = GestureState::Move;
|
||||
|
||||
if self.start_data.is_pointer() {
|
||||
data.niri
|
||||
.cursor_manager
|
||||
.set_cursor_image(CursorImageStatus::Named(CursorIcon::Move));
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn begin_view_offset(&mut self, data: &mut State) -> bool {
|
||||
let layout = &mut data.niri.layout;
|
||||
let Some((output, ws_idx)) = layout.workspaces().find_map(|(mon, ws_idx, ws)| {
|
||||
let ws_idx = ws
|
||||
.windows()
|
||||
.any(|w| w.window == self.window)
|
||||
.then_some(ws_idx)?;
|
||||
let output = mon?.output().clone();
|
||||
Some((output, ws_idx))
|
||||
}) else {
|
||||
// Can no longer start the gesture.
|
||||
return false;
|
||||
};
|
||||
|
||||
layout.view_offset_gesture_begin(&output, Some(ws_idx), false);
|
||||
|
||||
self.gesture = GestureState::ViewOffset;
|
||||
|
||||
if self.start_data.is_pointer() {
|
||||
data.niri
|
||||
.cursor_manager
|
||||
.set_cursor_image(CursorImageStatus::Named(CursorIcon::AllScroll));
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn on_motion(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
location: Point<f64, Logical>,
|
||||
timestamp: Duration,
|
||||
) -> bool {
|
||||
let mut delta = location - self.last_location;
|
||||
self.last_location = location;
|
||||
|
||||
// Try to recognize the gesture.
|
||||
if self.gesture == GestureState::Recognizing {
|
||||
// Check if the window has closed.
|
||||
if !self.window.alive() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the gesture moved far enough to decide.
|
||||
let c = location - self.start_data.location();
|
||||
if c.x * c.x + c.y * c.y >= 8. * 8. {
|
||||
let is_floating = data
|
||||
.niri
|
||||
.layout
|
||||
.workspaces()
|
||||
.find_map(|(_, _, ws)| {
|
||||
ws.windows()
|
||||
.any(|w| w.window == self.window)
|
||||
.then(|| ws.is_floating(&self.window))
|
||||
})
|
||||
.unwrap_or(false);
|
||||
|
||||
let is_view_offset =
|
||||
self.enable_view_offset && !is_floating && c.x.abs() > c.y.abs();
|
||||
|
||||
let started = if is_view_offset {
|
||||
self.begin_view_offset(data)
|
||||
} else {
|
||||
self.begin_move(data)
|
||||
};
|
||||
if !started {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Apply the whole delta that accumulated during recognizing.
|
||||
delta = c;
|
||||
}
|
||||
}
|
||||
|
||||
match self.gesture {
|
||||
GestureState::Recognizing => return true,
|
||||
GestureState::Move => {
|
||||
let Some((output, pos_within_output)) = data.niri.output_under(self.last_location)
|
||||
else {
|
||||
return true;
|
||||
};
|
||||
let output = output.clone();
|
||||
|
||||
let ongoing = data.niri.layout.interactive_move_update(
|
||||
&self.window,
|
||||
delta,
|
||||
output,
|
||||
pos_within_output,
|
||||
);
|
||||
if ongoing {
|
||||
// FIXME: only redraw the previous and the new output.
|
||||
data.niri.queue_redraw_all();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
GestureState::ViewOffset => {
|
||||
let res = data
|
||||
.niri
|
||||
.layout
|
||||
.view_offset_gesture_update(-delta.x, timestamp, false);
|
||||
if let Some(output) = res {
|
||||
if let Some(output) = output {
|
||||
data.niri.queue_redraw(&output);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn on_toggle_floating(&mut self, data: &mut State) -> bool {
|
||||
if self.gesture == GestureState::ViewOffset {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Start move if still recognizing.
|
||||
if self.gesture == GestureState::Recognizing {
|
||||
let Some((output, pos_within_output)) = data.niri.output_under(self.last_location)
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
let output = output.clone();
|
||||
|
||||
if !self.begin_move(data) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Apply the delta accumulated during recognizing.
|
||||
let ongoing = data.niri.layout.interactive_move_update(
|
||||
&self.window,
|
||||
self.last_location - self.start_data.location(),
|
||||
output,
|
||||
pos_within_output,
|
||||
);
|
||||
if !ongoing {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
data.niri.layout.toggle_window_floating(Some(&self.window));
|
||||
data.niri.queue_redraw_all();
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,47 +277,11 @@ impl PointerGrab<State> for MoveGrab {
|
||||
// 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;
|
||||
|
||||
if self.gesture == GestureState::Recognizing {
|
||||
let c = event.location - self.start_data.location;
|
||||
|
||||
// Check if the gesture moved far enough to decide.
|
||||
if c.x * c.x + c.y * c.y >= 8. * 8. {
|
||||
self.gesture = GestureState::Move;
|
||||
|
||||
data.niri
|
||||
.cursor_manager
|
||||
.set_cursor_image(CursorImageStatus::Named(CursorIcon::Move));
|
||||
}
|
||||
}
|
||||
|
||||
if self.gesture != GestureState::Move {
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
let timestamp = Duration::from_millis(u64::from(event.time));
|
||||
if !self.on_motion(data, event.location, timestamp) {
|
||||
// The gesture is no longer ongoing.
|
||||
handle.unset_grab(self, data, event.serial, event.time, true);
|
||||
}
|
||||
|
||||
// The move is no longer ongoing.
|
||||
handle.unset_grab(self, data, event.serial, event.time, true);
|
||||
}
|
||||
|
||||
fn relative_motion(
|
||||
@@ -129,18 +303,25 @@ impl PointerGrab<State> for MoveGrab {
|
||||
) {
|
||||
handle.button(data, event);
|
||||
|
||||
let start_data = self.start_data.unwrap_pointer();
|
||||
|
||||
if !handle.current_pressed().contains(&start_data.button) {
|
||||
// The button that initiated the grab was released.
|
||||
handle.unset_grab(self, data, event.serial, event.time, true);
|
||||
return;
|
||||
}
|
||||
|
||||
// When moving with the left button, right toggles floating, and vice versa.
|
||||
let toggle_floating_button = if self.start_data.button == 0x110 {
|
||||
let toggle_floating_button = if start_data.button == 0x110 {
|
||||
0x111
|
||||
} else {
|
||||
0x110
|
||||
};
|
||||
if event.button == toggle_floating_button && event.state == ButtonState::Pressed {
|
||||
data.niri.layout.toggle_window_floating(Some(&self.window));
|
||||
if event.state != ButtonState::Pressed || event.button != toggle_floating_button {
|
||||
return;
|
||||
}
|
||||
|
||||
if !handle.current_pressed().contains(&self.start_data.button) {
|
||||
// The button that initiated the grab was released.
|
||||
if !self.on_toggle_floating(data) {
|
||||
handle.unset_grab(self, data, event.serial, event.time, true);
|
||||
}
|
||||
}
|
||||
@@ -231,7 +412,100 @@ impl PointerGrab<State> for MoveGrab {
|
||||
}
|
||||
|
||||
fn start_data(&self) -> &PointerGrabStartData<State> {
|
||||
&self.start_data
|
||||
self.start_data.unwrap_pointer()
|
||||
}
|
||||
|
||||
fn unset(&mut self, data: &mut State) {
|
||||
self.on_ungrab(data);
|
||||
}
|
||||
}
|
||||
|
||||
impl TouchGrab<State> for MoveGrab {
|
||||
fn down(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut TouchInnerHandle<'_, State>,
|
||||
_focus: Option<(<State as SeatHandler>::TouchFocus, Point<f64, Logical>)>,
|
||||
event: &touch::DownEvent,
|
||||
seq: Serial,
|
||||
) {
|
||||
handle.down(data, None, event, seq);
|
||||
|
||||
if event.slot == self.start_data.unwrap_touch().slot {
|
||||
return;
|
||||
}
|
||||
|
||||
if !self.on_toggle_floating(data) {
|
||||
handle.unset_grab(self, data);
|
||||
}
|
||||
}
|
||||
|
||||
fn up(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut TouchInnerHandle<'_, State>,
|
||||
event: &touch::UpEvent,
|
||||
seq: Serial,
|
||||
) {
|
||||
handle.up(data, event, seq);
|
||||
|
||||
if event.slot == self.start_data.unwrap_touch().slot {
|
||||
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: &touch::MotionEvent,
|
||||
seq: Serial,
|
||||
) {
|
||||
handle.motion(data, None, event, seq);
|
||||
|
||||
if event.slot != self.start_data.unwrap_touch().slot {
|
||||
return;
|
||||
}
|
||||
|
||||
let timestamp = Duration::from_millis(u64::from(event.time));
|
||||
if !self.on_motion(data, event.location, timestamp) {
|
||||
// The gesture 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: &touch::ShapeEvent,
|
||||
seq: Serial,
|
||||
) {
|
||||
handle.shape(data, event, seq);
|
||||
}
|
||||
|
||||
fn orientation(
|
||||
&mut self,
|
||||
data: &mut State,
|
||||
handle: &mut TouchInnerHandle<'_, State>,
|
||||
event: &touch::OrientationEvent,
|
||||
seq: Serial,
|
||||
) {
|
||||
handle.orientation(data, event, seq);
|
||||
}
|
||||
|
||||
fn start_data(&self) -> &TouchGrabStartData<State> {
|
||||
self.start_data.unwrap_touch()
|
||||
}
|
||||
|
||||
fn unset(&mut self, data: &mut State) {
|
||||
|
||||
@@ -1,136 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -4040,16 +4040,12 @@ impl<W: LayoutElement> Layout<W> {
|
||||
mon.dnd_scroll_gesture_end();
|
||||
}
|
||||
|
||||
let mut ws_id = None;
|
||||
for ws in self.workspaces_mut() {
|
||||
let id = ws.id();
|
||||
if let Some(tile) = ws.tiles_mut().find(|tile| *tile.window().id() == window_id)
|
||||
{
|
||||
let offset = tile.interactive_move_offset;
|
||||
tile.interactive_move_offset = Point::from((0., 0.));
|
||||
tile.animate_move_from(offset);
|
||||
|
||||
ws_id = Some(id);
|
||||
}
|
||||
|
||||
// Unlock the view on the workspaces, but if the moved window was active,
|
||||
@@ -4064,32 +4060,6 @@ impl<W: LayoutElement> Layout<W> {
|
||||
}
|
||||
}
|
||||
|
||||
// In the overview, we want to click on a window to focus it, and also to
|
||||
// click-and-drag to move the window. The way we handle this is by always starting
|
||||
// the interactive move (to get frozen view), then, when in the overview, *not*
|
||||
// calling interactive_move_update() until the cursor moves far enough. This means
|
||||
// that if we "just click" then we end up in this branch with state == Starting.
|
||||
// Close the overview in this case.
|
||||
if self.overview_open {
|
||||
let ws_id = ws_id.unwrap();
|
||||
if let MonitorSet::Normal { monitors, .. } = &mut self.monitor_set {
|
||||
for mon in monitors {
|
||||
if let Some(ws_idx) =
|
||||
mon.workspaces.iter().position(|ws| ws.id() == ws_id)
|
||||
{
|
||||
mon.activate_workspace_with_anim_config(
|
||||
ws_idx,
|
||||
Some(self.options.animations.overview_open_close.0),
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.activate_window(&window_id);
|
||||
self.close_overview();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
InteractiveMoveState::Moving(move_) => move_,
|
||||
|
||||
Reference in New Issue
Block a user