feat: workspace switching touchpad gestures
This commit is contained in:
parent
f1d8225ddb
commit
fc2173d028
9 changed files with 767 additions and 89 deletions
266
src/input/mod.rs
266
src/input/mod.rs
|
|
@ -3,6 +3,7 @@
|
|||
use crate::{
|
||||
backend::render::cursor::CursorState,
|
||||
config::{xkb_config_to_wl, Action, Config, KeyModifiers, KeyPattern},
|
||||
input::gestures::{GestureState, SwipeAction},
|
||||
shell::{
|
||||
focus::{target::PointerFocusTarget, FocusDirection},
|
||||
grabs::{ResizeEdge, SeatMenuGrabState, SeatMoveGrabState},
|
||||
|
|
@ -10,7 +11,8 @@ use crate::{
|
|||
floating::ResizeGrabMarker,
|
||||
tiling::{SwapWindowGrab, TilingLayout},
|
||||
},
|
||||
Direction, FocusResult, MoveResult, OverviewMode, ResizeDirection, ResizeMode, Trigger,
|
||||
Direction, FocusResult, InvalidWorkspaceIndex, MoveResult, OverviewMode, ResizeDirection,
|
||||
ResizeMode, Trigger, WorkspaceDelta,
|
||||
},
|
||||
state::Common,
|
||||
utils::prelude::*,
|
||||
|
|
@ -68,6 +70,8 @@ use std::{
|
|||
|
||||
crate::utils::id_gen!(next_seat_id, SEAT_ID, SEAT_IDS);
|
||||
|
||||
pub mod gestures;
|
||||
|
||||
#[repr(transparent)]
|
||||
pub struct SeatId(pub usize);
|
||||
pub struct ActiveOutput(pub RefCell<Output>);
|
||||
|
|
@ -1071,42 +1075,127 @@ impl State {
|
|||
}
|
||||
InputEvent::GestureSwipeBegin { event, .. } => {
|
||||
if let Some(seat) = self.common.seat_with_device(&event.device()) {
|
||||
let serial = SERIAL_COUNTER.next_serial();
|
||||
let pointer = seat.get_pointer().unwrap();
|
||||
pointer.gesture_swipe_begin(
|
||||
self,
|
||||
&GestureSwipeBeginEvent {
|
||||
serial,
|
||||
time: event.time_msec(),
|
||||
fingers: event.fingers(),
|
||||
},
|
||||
);
|
||||
if event.fingers() >= 3 {
|
||||
self.common.gesture_state = Some(GestureState::new(event.fingers()));
|
||||
} else {
|
||||
let serial = SERIAL_COUNTER.next_serial();
|
||||
let pointer = seat.get_pointer().unwrap();
|
||||
pointer.gesture_swipe_begin(
|
||||
self,
|
||||
&GestureSwipeBeginEvent {
|
||||
serial,
|
||||
time: event.time_msec(),
|
||||
fingers: event.fingers(),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
InputEvent::GestureSwipeUpdate { event, .. } => {
|
||||
if let Some(seat) = self.common.seat_with_device(&event.device()) {
|
||||
let pointer = seat.get_pointer().unwrap();
|
||||
pointer.gesture_swipe_update(
|
||||
self,
|
||||
&GestureSwipeUpdateEvent {
|
||||
time: event.time_msec(),
|
||||
delta: event.delta(),
|
||||
},
|
||||
);
|
||||
if let Some(seat) = self.common.seat_with_device(&event.device()).cloned() {
|
||||
let mut activate_action: Option<SwipeAction> = None;
|
||||
if let Some(ref mut gesture_state) = self.common.gesture_state {
|
||||
let first_update = gesture_state.update(
|
||||
event.delta(),
|
||||
Duration::from_millis(event.time_msec() as u64),
|
||||
);
|
||||
// Decide on action if first update
|
||||
if first_update {
|
||||
activate_action = match gesture_state.fingers {
|
||||
3 => None, // TODO: 3 finger gestures
|
||||
4 => {
|
||||
if self.common.config.cosmic_conf.workspaces.workspace_layout
|
||||
== WorkspaceLayout::Horizontal
|
||||
{
|
||||
match gesture_state.direction {
|
||||
Some(Direction::Left) => {
|
||||
Some(SwipeAction::NextWorkspace)
|
||||
}
|
||||
Some(Direction::Right) => {
|
||||
Some(SwipeAction::PrevWorkspace)
|
||||
}
|
||||
_ => None, // TODO: Other actions
|
||||
}
|
||||
} else {
|
||||
match gesture_state.direction {
|
||||
Some(Direction::Up) => Some(SwipeAction::NextWorkspace),
|
||||
Some(Direction::Down) => {
|
||||
Some(SwipeAction::PrevWorkspace)
|
||||
}
|
||||
_ => None, // TODO: Other actions
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
gesture_state.action = activate_action;
|
||||
}
|
||||
|
||||
match gesture_state.action {
|
||||
Some(SwipeAction::NextWorkspace) | Some(SwipeAction::PrevWorkspace) => {
|
||||
self.common.shell.update_workspace_delta(
|
||||
&seat.active_output(),
|
||||
gesture_state.delta,
|
||||
)
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
} else {
|
||||
let pointer = seat.get_pointer().unwrap();
|
||||
pointer.gesture_swipe_update(
|
||||
self,
|
||||
&GestureSwipeUpdateEvent {
|
||||
time: event.time_msec(),
|
||||
delta: event.delta(),
|
||||
},
|
||||
);
|
||||
}
|
||||
match activate_action {
|
||||
Some(SwipeAction::NextWorkspace) => {
|
||||
let _ = self.to_next_workspace(&seat, true);
|
||||
}
|
||||
Some(SwipeAction::PrevWorkspace) => {
|
||||
let _ = self.to_previous_workspace(&seat, true);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
InputEvent::GestureSwipeEnd { event, .. } => {
|
||||
if let Some(seat) = self.common.seat_with_device(&event.device()) {
|
||||
let serial = SERIAL_COUNTER.next_serial();
|
||||
let pointer = seat.get_pointer().unwrap();
|
||||
pointer.gesture_swipe_end(
|
||||
self,
|
||||
&GestureSwipeEndEvent {
|
||||
serial,
|
||||
time: event.time_msec(),
|
||||
cancelled: event.cancelled(),
|
||||
},
|
||||
);
|
||||
if let Some(seat) = self.common.seat_with_device(&event.device()).cloned() {
|
||||
if let Some(ref gesture_state) = self.common.gesture_state {
|
||||
match gesture_state.action {
|
||||
Some(SwipeAction::NextWorkspace) | Some(SwipeAction::PrevWorkspace) => {
|
||||
let velocity = gesture_state.velocity();
|
||||
let norm_velocity =
|
||||
if self.common.config.cosmic_conf.workspaces.workspace_layout
|
||||
== WorkspaceLayout::Horizontal
|
||||
{
|
||||
velocity / seat.active_output().geometry().size.w as f64
|
||||
} else {
|
||||
velocity / seat.active_output().geometry().size.h as f64
|
||||
};
|
||||
let _ = self
|
||||
.common
|
||||
.shell
|
||||
.end_workspace_swipe(&seat.active_output(), norm_velocity);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
self.common.gesture_state = None;
|
||||
} else {
|
||||
let serial = SERIAL_COUNTER.next_serial();
|
||||
let pointer = seat.get_pointer().unwrap();
|
||||
pointer.gesture_swipe_end(
|
||||
self,
|
||||
&GestureSwipeEndEvent {
|
||||
serial,
|
||||
time: event.time_msec(),
|
||||
cancelled: event.cancelled(),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
InputEvent::GesturePinchBegin { event, .. } => {
|
||||
|
|
@ -1471,10 +1560,11 @@ impl State {
|
|||
0 => 9,
|
||||
x => x - 1,
|
||||
};
|
||||
let _ = self
|
||||
.common
|
||||
.shell
|
||||
.activate(¤t_output, workspace as usize);
|
||||
let _ = self.common.shell.activate(
|
||||
¤t_output,
|
||||
workspace as usize,
|
||||
WorkspaceDelta::new_shortcut(),
|
||||
);
|
||||
}
|
||||
Action::LastWorkspace => {
|
||||
let current_output = seat.active_output();
|
||||
|
|
@ -1484,24 +1574,14 @@ impl State {
|
|||
.workspaces
|
||||
.len(¤t_output)
|
||||
.saturating_sub(1);
|
||||
let _ = self.common.shell.activate(¤t_output, workspace);
|
||||
let _ = self.common.shell.activate(
|
||||
¤t_output,
|
||||
workspace,
|
||||
WorkspaceDelta::new_shortcut(),
|
||||
);
|
||||
}
|
||||
Action::NextWorkspace => {
|
||||
let current_output = seat.active_output();
|
||||
let workspace = self
|
||||
.common
|
||||
.shell
|
||||
.workspaces
|
||||
.active_num(¤t_output)
|
||||
.1
|
||||
.saturating_add(1);
|
||||
if self
|
||||
.common
|
||||
.shell
|
||||
.activate(¤t_output, workspace)
|
||||
.is_err()
|
||||
&& propagate
|
||||
{
|
||||
if self.to_next_workspace(seat, false).is_err() && propagate {
|
||||
if let Some(inferred) = pattern.inferred_direction() {
|
||||
self.handle_action(
|
||||
Action::SwitchOutput(inferred),
|
||||
|
|
@ -1516,21 +1596,7 @@ impl State {
|
|||
}
|
||||
}
|
||||
Action::PreviousWorkspace => {
|
||||
let current_output = seat.active_output();
|
||||
let workspace = self
|
||||
.common
|
||||
.shell
|
||||
.workspaces
|
||||
.active_num(¤t_output)
|
||||
.1
|
||||
.saturating_sub(1);
|
||||
if self
|
||||
.common
|
||||
.shell
|
||||
.activate(¤t_output, workspace)
|
||||
.is_err()
|
||||
&& propagate
|
||||
{
|
||||
if self.to_previous_workspace(seat, false).is_err() && propagate {
|
||||
if let Some(inferred) = pattern.inferred_direction() {
|
||||
self.handle_action(
|
||||
Action::SwitchOutput(inferred),
|
||||
|
|
@ -1663,7 +1729,11 @@ impl State {
|
|||
|
||||
if let Some(next_output) = next_output {
|
||||
let idx = self.common.shell.workspaces.active_num(&next_output).1;
|
||||
match self.common.shell.activate(&next_output, idx) {
|
||||
match self.common.shell.activate(
|
||||
&next_output,
|
||||
idx,
|
||||
WorkspaceDelta::new_shortcut(),
|
||||
) {
|
||||
Ok(Some(new_pos)) => {
|
||||
seat.set_active_output(&next_output);
|
||||
if let Some(ptr) = seat.get_pointer() {
|
||||
|
|
@ -1726,7 +1796,11 @@ impl State {
|
|||
.cloned();
|
||||
if let Some(next_output) = next_output {
|
||||
let idx = self.common.shell.workspaces.active_num(&next_output).1;
|
||||
match self.common.shell.activate(&next_output, idx) {
|
||||
match self.common.shell.activate(
|
||||
&next_output,
|
||||
idx,
|
||||
WorkspaceDelta::new_shortcut(),
|
||||
) {
|
||||
Ok(Some(new_pos)) => {
|
||||
seat.set_active_output(&next_output);
|
||||
if let Some(ptr) = seat.get_pointer() {
|
||||
|
|
@ -1762,7 +1836,11 @@ impl State {
|
|||
.cloned();
|
||||
if let Some(prev_output) = prev_output {
|
||||
let idx = self.common.shell.workspaces.active_num(&prev_output).1;
|
||||
match self.common.shell.activate(&prev_output, idx) {
|
||||
match self.common.shell.activate(
|
||||
&prev_output,
|
||||
idx,
|
||||
WorkspaceDelta::new_shortcut(),
|
||||
) {
|
||||
Ok(Some(new_pos)) => {
|
||||
seat.set_active_output(&prev_output);
|
||||
if let Some(ptr) = seat.get_pointer() {
|
||||
|
|
@ -2271,6 +2349,56 @@ impl State {
|
|||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_next_workspace(
|
||||
&mut self,
|
||||
seat: &Seat<State>,
|
||||
gesture: bool,
|
||||
) -> Result<Option<Point<i32, Global>>, InvalidWorkspaceIndex> {
|
||||
let current_output = seat.active_output();
|
||||
let workspace = self
|
||||
.common
|
||||
.shell
|
||||
.workspaces
|
||||
.active_num(¤t_output)
|
||||
.1
|
||||
.saturating_add(1);
|
||||
|
||||
self.common.shell.activate(
|
||||
¤t_output,
|
||||
workspace,
|
||||
if gesture {
|
||||
WorkspaceDelta::new_gesture()
|
||||
} else {
|
||||
WorkspaceDelta::new_shortcut()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub fn to_previous_workspace(
|
||||
&mut self,
|
||||
seat: &Seat<State>,
|
||||
gesture: bool,
|
||||
) -> Result<Option<Point<i32, Global>>, InvalidWorkspaceIndex> {
|
||||
let current_output = seat.active_output();
|
||||
let workspace = self
|
||||
.common
|
||||
.shell
|
||||
.workspaces
|
||||
.active_num(¤t_output)
|
||||
.1
|
||||
.saturating_sub(1);
|
||||
|
||||
self.common.shell.activate(
|
||||
¤t_output,
|
||||
workspace,
|
||||
if gesture {
|
||||
WorkspaceDelta::new_gesture()
|
||||
} else {
|
||||
WorkspaceDelta::new_shortcut()
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn sessions_for_output(state: &Common, output: &Output) -> impl Iterator<Item = Session> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue