From d42b6df2b433b1e207a6e99620998e7e4fdc9dd9 Mon Sep 17 00:00:00 2001 From: Ryan Brue Date: Sun, 31 Mar 2024 18:57:30 -0500 Subject: [PATCH] feat: touchpad gesture configuration --- cosmic-comp-config/src/input.rs | 37 ++++++++++ cosmic-comp-config/src/lib.rs | 2 + src/config/mod.rs | 7 +- src/input/gestures/mod.rs | 9 +-- src/input/mod.rs | 117 ++++++++++++++++++++++---------- src/shell/focus/mod.rs | 28 ++++---- 6 files changed, 142 insertions(+), 58 deletions(-) diff --git a/cosmic-comp-config/src/input.rs b/cosmic-comp-config/src/input.rs index 5ac4889e..93d72ac5 100644 --- a/cosmic-comp-config/src/input.rs +++ b/cosmic-comp-config/src/input.rs @@ -46,6 +46,43 @@ pub struct ScrollConfig { pub scroll_button: Option, pub scroll_factor: Option, } +#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] +pub struct TouchpadGestureConfig { + pub three_finger: Option, + pub four_finger: Option, + pub five_finger: Option, +} +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub enum GestureConfig { + WorkspaceDependent(RelativeGestureConfig), + Directional(AbsoluteGestureConfig), +} +#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)] +pub struct RelativeGestureConfig { + pub action_forward: Option, + pub action_backward: Option, + pub action_side_1: Option, + pub action_side_2: Option, +} +#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)] +pub struct AbsoluteGestureConfig { + pub action_up: Option, + pub action_down: Option, + pub action_left: Option, + pub action_right: Option, +} +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub enum GestureCommand { + WorkspaceForward, + WorkspaceBackward, + WorkspaceOverviewEnable, + WorkspaceOverviewDisable, + WindowUp, + WindowDown, + WindowLeft, + WindowRight, + Custom(String), +} #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum DeviceState { diff --git a/cosmic-comp-config/src/lib.rs b/cosmic-comp-config/src/lib.rs index 32dbd3f4..9cd832a5 100644 --- a/cosmic-comp-config/src/lib.rs +++ b/cosmic-comp-config/src/lib.rs @@ -13,6 +13,7 @@ pub struct CosmicCompConfig { pub workspaces: workspace::WorkspaceConfig, pub input_default: input::InputConfig, pub input_touchpad: input::InputConfig, + pub input_touchpad_gestures: input::TouchpadGestureConfig, pub input_devices: HashMap, pub xkb_config: XkbConfig, /// Autotiling enabled @@ -31,6 +32,7 @@ impl Default for CosmicCompConfig { workspaces: Default::default(), input_default: Default::default(), input_touchpad: Default::default(), + input_touchpad_gestures: Default::default(), input_devices: Default::default(), xkb_config: Default::default(), autotile: Default::default(), diff --git a/src/config/mod.rs b/src/config/mod.rs index 9b9ec9bf..402006a6 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -30,7 +30,7 @@ pub use key_bindings::{Action, KeyModifier, KeyModifiers, KeyPattern}; mod types; pub use self::types::*; use cosmic_comp_config::{ - input::InputConfig, + input::{InputConfig, TouchpadGestureConfig}, workspace::{WorkspaceConfig, WorkspaceLayout}, CosmicCompConfig, TileBehavior, XkbConfig, }; @@ -553,6 +553,11 @@ fn config_changed(config: cosmic_config::Config, keys: Vec, state: &mut state.common.config.cosmic_conf.input_touchpad = value; update_input(state); } + "input_touchpad_gestures" => { + let value = get_config::(&config, "input_touchpad_gestures"); + state.common.config.cosmic_conf.input_touchpad_gestures = value; + update_input(state); + } "input_devices" => { let value = get_config::>(&config, "input_devices"); state.common.config.cosmic_conf.input_devices = value; diff --git a/src/input/gestures/mod.rs b/src/input/gestures/mod.rs index 2998615a..70dceca4 100644 --- a/src/input/gestures/mod.rs +++ b/src/input/gestures/mod.rs @@ -1,3 +1,4 @@ +use cosmic_comp_config::input::GestureCommand; use smithay::utils::{Logical, Point}; use std::{collections::VecDeque, time::Duration}; use tracing::trace; @@ -13,17 +14,11 @@ pub struct SwipeEvent { timestamp: Duration, } -#[derive(Debug, Clone, Copy)] -pub enum SwipeAction { - NextWorkspace, - PrevWorkspace, -} - #[derive(Debug, Clone)] pub struct GestureState { pub fingers: u32, pub direction: Option, - pub action: Option, + pub action: Option, pub delta: f64, // Delta tracking inspired by Niri (GPL-3.0) https://github.com/YaLTeR/niri/tree/v0.1.3 pub history: VecDeque, diff --git a/src/input/mod.rs b/src/input/mod.rs index 197a0640..1b950b60 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -3,7 +3,7 @@ use crate::{ backend::render::cursor::CursorState, config::{xkb_config_to_wl, Action, Config, KeyModifiers, KeyPattern}, - input::gestures::{GestureState, SwipeAction}, + input::gestures::GestureState, shell::{ focus::{ target::{KeyboardFocusTarget, PointerFocusTarget}, @@ -25,7 +25,11 @@ use crate::{ }, }; use calloop::{timer::Timer, RegistrationToken}; -use cosmic_comp_config::{workspace::WorkspaceLayout, TileBehavior}; +use cosmic_comp_config::{ + input::{GestureCommand, GestureConfig}, + workspace::WorkspaceLayout, + TileBehavior, +}; use cosmic_config::ConfigSet; use smithay::{ backend::input::{ @@ -1121,7 +1125,7 @@ impl State { } InputEvent::GestureSwipeUpdate { event, .. } => { if let Some(seat) = self.common.seat_with_device(&event.device()).cloned() { - let mut activate_action: Option = None; + let mut activate_action: Option = None; if let Some(ref mut gesture_state) = self.common.gesture_state { let first_update = gesture_state.update( event.delta(), @@ -1129,44 +1133,84 @@ impl State { ); // 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 + let target_config = match gesture_state.fingers { + 3 => self + .common + .config + .cosmic_conf + .input_touchpad_gestures + .three_finger + .clone(), + 4 => self + .common + .config + .cosmic_conf + .input_touchpad_gestures + .four_finger + .clone(), + 5 => self + .common + .config + .cosmic_conf + .input_touchpad_gestures + .five_finger + .clone(), + _ => None, + }; + + activate_action = match target_config { + Some(GestureConfig::WorkspaceDependent(config)) => { + match ( + self.common.config.cosmic_conf.workspaces.workspace_layout, + gesture_state.direction, + ) { + (WorkspaceLayout::Vertical, Some(Direction::Down)) => { + config.action_forward.clone() } - } else { - match gesture_state.direction { - Some(Direction::Up) => Some(SwipeAction::NextWorkspace), - Some(Direction::Down) => { - Some(SwipeAction::PrevWorkspace) - } - _ => None, // TODO: Other actions + (WorkspaceLayout::Vertical, Some(Direction::Up)) => { + config.action_backward.clone() + } + (WorkspaceLayout::Vertical, Some(Direction::Right)) => { + config.action_side_1.clone() + } + (WorkspaceLayout::Vertical, Some(Direction::Left)) => { + config.action_side_2.clone() + } + (WorkspaceLayout::Horizontal, Some(Direction::Down)) => { + config.action_side_1.clone() + } + (WorkspaceLayout::Horizontal, Some(Direction::Up)) => { + config.action_side_2.clone() + } + (WorkspaceLayout::Horizontal, Some(Direction::Right)) => { + config.action_forward.clone() + } + (WorkspaceLayout::Horizontal, Some(Direction::Left)) => { + config.action_backward.clone() } + _ => None, } } - _ => None, + Some(GestureConfig::Directional(config)) => { + match gesture_state.direction { + Some(Direction::Up) => config.action_up.clone(), + Some(Direction::Down) => config.action_down.clone(), + Some(Direction::Right) => config.action_right.clone(), + Some(Direction::Left) => config.action_left.clone(), + None => None, + } + } + None => None, }; - - gesture_state.action = activate_action; + gesture_state.action = activate_action.clone(); } match gesture_state.action { - Some(SwipeAction::NextWorkspace) | Some(SwipeAction::PrevWorkspace) => { - self.common.shell.update_workspace_delta( - &seat.active_output(), - gesture_state.delta, - ) - } + Some(GestureCommand::WorkspaceForward) + | Some(GestureCommand::WorkspaceBackward) => self + .common + .shell + .update_workspace_delta(&seat.active_output(), gesture_state.delta), _ => {} } } else { @@ -1180,10 +1224,10 @@ impl State { ); } match activate_action { - Some(SwipeAction::NextWorkspace) => { + Some(GestureCommand::WorkspaceForward) => { let _ = self.to_next_workspace(&seat, true); } - Some(SwipeAction::PrevWorkspace) => { + Some(GestureCommand::WorkspaceBackward) => { let _ = self.to_previous_workspace(&seat, true); } _ => {} @@ -1194,7 +1238,8 @@ impl State { 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) => { + Some(GestureCommand::WorkspaceForward) + | Some(GestureCommand::WorkspaceBackward) => { let velocity = gesture_state.velocity(); let norm_velocity = if self.common.config.cosmic_conf.workspaces.workspace_layout diff --git a/src/shell/focus/mod.rs b/src/shell/focus/mod.rs index 135ffe5c..c81d8b04 100644 --- a/src/shell/focus/mod.rs +++ b/src/shell/focus/mod.rs @@ -266,21 +266,21 @@ impl Common { .get::() .and_then(|x| x.take()) { - if !popup_grab.has_ended() { - if let Some(new) = popup_grab.current_grab() { - trace!("restore focus to previous popup grab"); - if let Some(keyboard) = seat.get_keyboard() { - keyboard.set_focus( - state, - Some(new.clone()), - SERIAL_COUNTER.next_serial(), - ); - } - ActiveFocus::set(&seat, Some(new)); - seat.user_data() + if !popup_grab.has_ended() { + if let Some(new) = popup_grab.current_grab() { + trace!("restore focus to previous popup grab"); + if let Some(keyboard) = seat.get_keyboard() { + keyboard.set_focus( + state, + Some(new.clone()), + SERIAL_COUNTER.next_serial(), + ); + } + ActiveFocus::set(&seat, Some(new)); + seat.user_data() .get_or_insert::(PopupGrabData::default) - .set(Some(popup_grab)); - continue; + .set(Some(popup_grab)); + continue; } } }