diff --git a/Cargo.lock b/Cargo.lock index e51b8f51..4e5359f7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -481,6 +481,7 @@ dependencies = [ "bitflags 1.3.2", "bytemuck", "calloop", + "cosmic-comp-config", "cosmic-config", "cosmic-protocols", "edid-rs", @@ -522,6 +523,14 @@ dependencies = [ "xkbcommon 0.4.1", ] +[[package]] +name = "cosmic-comp-config" +version = "0.1.0" +dependencies = [ + "input", + "serde", +] + [[package]] name = "cosmic-config" version = "0.1.0" @@ -1981,6 +1990,7 @@ dependencies = [ "input-sys", "io-lifetimes", "libc", + "log", "udev", ] diff --git a/Cargo.toml b/Cargo.toml index 495b9459..8d7bec91 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,11 @@ edition = "2021" license = "GPL-3.0-only" authors = ["Victoria Brekenfeld"] +[workspace] +members = [ + "cosmic-comp-config" +] + [dependencies] apply = "0.3.0" anyhow = { version = "1.0.51", features = ["backtrace"] } @@ -30,6 +35,7 @@ ron = "0.7" libsystemd = { version = "0.5", optional = true } wayland-backend = "0.1.0" wayland-scanner = "0.30.0" +cosmic-comp-config = { path = "cosmic-comp-config" } cosmic-config = { git = "https://github.com/pop-os/libcosmic/", rev = "4895b0c", features = ["calloop"] } cosmic-protocols = { git = "https://github.com/pop-os/cosmic-protocols", branch = "main", default-features = false, features = ["server"] } libcosmic = { git = "https://github.com/pop-os/libcosmic/", rev = "4895b0c", default-features = false } diff --git a/cosmic-comp-config/Cargo.toml b/cosmic-comp-config/Cargo.toml new file mode 100644 index 00000000..7f4f6588 --- /dev/null +++ b/cosmic-comp-config/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "cosmic-comp-config" +version = "0.1.0" +edition = "2021" + +[dependencies] +input = "0.8.3" +serde = { version = "1", features = ["derive"] } diff --git a/cosmic-comp-config/src/input.rs b/cosmic-comp-config/src/input.rs new file mode 100644 index 00000000..1d15abb0 --- /dev/null +++ b/cosmic-comp-config/src/input.rs @@ -0,0 +1,209 @@ +// SPDX-License-Identifier: GPL-3.0-only + +#![allow(non_snake_case)] + +use input::{AccelProfile, ClickMethod, ScrollMethod, TapButtonMap}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Default, Deserialize, Serialize)] +pub struct InputConfig { + pub state: DeviceState, + #[serde(skip_serializing_if = "Option::is_none", default)] + pub acceleration: Option, + #[serde(skip_serializing_if = "Option::is_none", default)] + pub calibration: Option<[f32; 6]>, + #[serde(with = "ClickMethodDef")] + #[serde(skip_serializing_if = "Option::is_none", default)] + pub click_method: Option, + #[serde(skip_serializing_if = "Option::is_none", default)] + pub disable_while_typing: Option, + #[serde(skip_serializing_if = "Option::is_none", default)] + pub left_handed: Option, + #[serde(skip_serializing_if = "Option::is_none", default)] + pub middle_button_emulation: Option, + #[serde(skip_serializing_if = "Option::is_none", default)] + pub rotation_angle: Option, + #[serde(skip_serializing_if = "Option::is_none", default)] + pub scroll_config: Option, + #[serde(skip_serializing_if = "Option::is_none", default)] + pub tap_config: Option, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct AccelConfig { + #[serde(with = "AccelProfileDef")] + pub profile: Option, + pub speed: f64, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct ScrollConfig { + #[serde(with = "ScrollMethodDef")] + pub method: Option, + pub natural_scroll: Option, + pub scroll_button: Option, +} + +#[derive(Copy, Clone, Debug, Serialize, Deserialize)] +pub enum DeviceState { + Enabled, + Disabled, + DisabledOnExternalMouse, +} + +impl Default for DeviceState { + fn default() -> Self { + Self::Enabled + } +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct TapConfig { + pub enabled: bool, + #[serde(with = "TapButtonMapDef")] + pub button_map: Option, + pub drag: bool, + pub drag_lock: bool, +} + +mod ClickMethodDef { + use input::ClickMethod as ClickMethodOrig; + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + + #[derive(Debug, Serialize, Deserialize)] + pub enum ClickMethod { + ButtonAreas, + Clickfinger, + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + { + let o = Option::deserialize(deserializer)?; + Ok(o.map(|x| match x { + ClickMethod::ButtonAreas => ClickMethodOrig::ButtonAreas, + ClickMethod::Clickfinger => ClickMethodOrig::Clickfinger, + })) + } + + pub fn serialize(arg: &Option, ser: S) -> Result + where + S: Serializer, + { + let arg = match arg { + Some(ClickMethodOrig::ButtonAreas) => Some(ClickMethod::ButtonAreas), + Some(ClickMethodOrig::Clickfinger) => Some(ClickMethod::Clickfinger), + Some(_) | None => None, + }; + Option::serialize(&arg, ser) + } +} + +mod AccelProfileDef { + use input::AccelProfile as AccelProfileOrig; + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + + #[derive(Debug, Serialize, Deserialize)] + enum AccelProfile { + Flat, + Adaptive, + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + { + let o = Option::deserialize(deserializer)?; + Ok(o.map(|x| match x { + AccelProfile::Flat => AccelProfileOrig::Flat, + AccelProfile::Adaptive => AccelProfileOrig::Adaptive, + })) + } + + pub fn serialize(arg: &Option, ser: S) -> Result + where + S: Serializer, + { + let arg = match arg { + Some(AccelProfileOrig::Flat) => Some(AccelProfile::Flat), + Some(AccelProfileOrig::Adaptive) => Some(AccelProfile::Adaptive), + Some(_) | None => None, + }; + Option::serialize(&arg, ser) + } +} + +mod ScrollMethodDef { + use input::ScrollMethod as ScrollMethodOrig; + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + + #[derive(Debug, Serialize, Deserialize)] + pub enum ScrollMethod { + NoScroll, + TwoFinger, + Edge, + OnButtonDown, + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + { + let o = Option::deserialize(deserializer)?; + Ok(o.map(|x| match x { + ScrollMethod::NoScroll => ScrollMethodOrig::NoScroll, + ScrollMethod::TwoFinger => ScrollMethodOrig::TwoFinger, + ScrollMethod::Edge => ScrollMethodOrig::Edge, + ScrollMethod::OnButtonDown => ScrollMethodOrig::OnButtonDown, + })) + } + + pub fn serialize(arg: &Option, ser: S) -> Result + where + S: Serializer, + { + let arg = match arg { + Some(ScrollMethodOrig::NoScroll) => Some(ScrollMethod::NoScroll), + Some(ScrollMethodOrig::TwoFinger) => Some(ScrollMethod::TwoFinger), + Some(ScrollMethodOrig::Edge) => Some(ScrollMethod::Edge), + Some(ScrollMethodOrig::OnButtonDown) => Some(ScrollMethod::OnButtonDown), + Some(_) | None => None, + }; + Option::serialize(&arg, ser) + } +} + +mod TapButtonMapDef { + use input::TapButtonMap as TapButtonMapOrig; + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + + #[derive(Debug, Serialize, Deserialize)] + pub enum TapButtonMap { + LeftRightMiddle, + LeftMiddleRight, + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + { + let o = Option::deserialize(deserializer)?; + Ok(o.map(|x| match x { + TapButtonMap::LeftRightMiddle => TapButtonMapOrig::LeftRightMiddle, + TapButtonMap::LeftMiddleRight => TapButtonMapOrig::LeftMiddleRight, + })) + } + + pub fn serialize(arg: &Option, ser: S) -> Result + where + S: Serializer, + { + let arg = match arg { + Some(TapButtonMapOrig::LeftRightMiddle) => Some(TapButtonMap::LeftRightMiddle), + Some(TapButtonMapOrig::LeftMiddleRight) => Some(TapButtonMap::LeftMiddleRight), + Some(_) | None => None, + }; + Option::serialize(&arg, ser) + } +} diff --git a/cosmic-comp-config/src/lib.rs b/cosmic-comp-config/src/lib.rs new file mode 100644 index 00000000..b65c114b --- /dev/null +++ b/cosmic-comp-config/src/lib.rs @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-3.0-only + +use serde::{Deserialize, Serialize}; + +pub mod input; + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct XkbConfig { + pub rules: String, + pub model: String, + pub layout: String, + pub variant: String, + pub options: Option, +} + +impl Default for XkbConfig { + fn default() -> XkbConfig { + XkbConfig { + rules: String::new(), + model: String::new(), + layout: String::new(), + variant: String::new(), + options: None, + } + } +} diff --git a/src/config/input_config.rs b/src/config/input_config.rs index 86a01140..e979ec51 100644 --- a/src/config/input_config.rs +++ b/src/config/input_config.rs @@ -1,4 +1,3 @@ -use serde::{Deserialize, Serialize}; pub use smithay::{ backend::input::KeyState, input::keyboard::{keysyms as KeySyms, Keysym, ModifiersState}, @@ -14,302 +13,269 @@ pub use smithay::{ }; use tracing::warn; -use super::types::*; +use cosmic_comp_config::input::*; -#[derive(Debug, Deserialize, Serialize)] -pub struct InputConfig { - state: DeviceState, - #[serde(skip_serializing_if = "Option::is_none", default)] - acceleration: Option, - #[serde(skip_serializing_if = "Option::is_none", default)] - calibration: Option<[f32; 6]>, - #[serde(with = "ClickMethodDef")] - #[serde(skip_serializing_if = "Option::is_none", default)] - click_method: Option, - #[serde(skip_serializing_if = "Option::is_none", default)] - disable_while_typing: Option, - #[serde(skip_serializing_if = "Option::is_none", default)] - left_handed: Option, - #[serde(skip_serializing_if = "Option::is_none", default)] - middle_button_emulation: Option, - #[serde(skip_serializing_if = "Option::is_none", default)] - rotation_angle: Option, - #[serde(skip_serializing_if = "Option::is_none", default)] - scroll_config: Option, - #[serde(skip_serializing_if = "Option::is_none", default)] - tap_config: Option, +#[allow(dead_code)] +pub fn for_device(device: &InputDevice) -> InputConfig { + InputConfig { + state: match device.config_send_events_mode() { + x if x.contains(SendEventsMode::ENABLED) => DeviceState::Enabled, + x if x.contains(SendEventsMode::DISABLED_ON_EXTERNAL_MOUSE) => { + DeviceState::DisabledOnExternalMouse + } + x if x.contains(SendEventsMode::DISABLED) => DeviceState::Disabled, + _ => DeviceState::Disabled, + }, + acceleration: if device.config_accel_is_available() { + Some(AccelConfig { + profile: device.config_accel_profile(), + speed: device.config_accel_speed(), + }) + } else { + None + }, + calibration: device.config_calibration_matrix(), + click_method: device.config_click_method(), + disable_while_typing: if device.config_dwt_is_available() { + Some(device.config_dwt_enabled()) + } else { + None + }, + left_handed: if device.config_left_handed_is_available() { + Some(device.config_left_handed()) + } else { + None + }, + middle_button_emulation: if device.config_middle_emulation_is_available() { + Some(device.config_middle_emulation_enabled()) + } else { + None + }, + rotation_angle: if device.config_rotation_is_available() { + Some(device.config_rotation_angle()) + } else { + None + }, + scroll_config: if device + .config_scroll_methods() + .iter() + .any(|x| *x != ScrollMethod::NoScroll) + { + Some(ScrollConfig { + method: device.config_scroll_method(), + natural_scroll: if device.config_scroll_has_natural_scroll() { + Some(device.config_scroll_natural_scroll_enabled()) + } else { + None + }, + scroll_button: if device.config_scroll_method() == Some(ScrollMethod::OnButtonDown) + { + Some(device.config_scroll_button()) + } else { + None + }, + }) + } else { + None + }, + tap_config: if device.config_tap_finger_count() > 0 { + Some(TapConfig { + enabled: device.config_tap_enabled(), + button_map: device.config_tap_button_map(), + drag: device.config_tap_drag_enabled(), + drag_lock: device.config_tap_drag_lock_enabled(), + }) + } else { + None + }, + } } -#[derive(Debug, Deserialize, Serialize)] -pub struct AccelConfig { - #[serde(with = "AccelProfileDef")] - profile: Option, - speed: f64, -} - -#[derive(Debug, Deserialize, Serialize)] -pub struct ScrollConfig { - #[serde(with = "ScrollMethodDef")] - method: Option, - natural_scroll: Option, - scroll_button: Option, -} - -#[derive(Debug, Serialize, Deserialize)] -pub enum DeviceState { - Enabled, - Disabled, - DisabledOnExternalMouse, -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct TapConfig { - enabled: bool, - #[serde(with = "TapButtonMapDef")] - button_map: Option, - drag: bool, - drag_lock: bool, -} - -impl InputConfig { - pub fn for_device(device: &InputDevice) -> Self { - InputConfig { - state: match device.config_send_events_mode() { - x if x.contains(SendEventsMode::ENABLED) => DeviceState::Enabled, - x if x.contains(SendEventsMode::DISABLED_ON_EXTERNAL_MOUSE) => { - DeviceState::DisabledOnExternalMouse - } - x if x.contains(SendEventsMode::DISABLED) => DeviceState::Disabled, - _ => DeviceState::Disabled, - }, - acceleration: if device.config_accel_is_available() { - Some(AccelConfig { - profile: device.config_accel_profile(), - speed: device.config_accel_speed(), - }) - } else { - None - }, - calibration: device.config_calibration_matrix(), - click_method: device.config_click_method(), - disable_while_typing: if device.config_dwt_is_available() { - Some(device.config_dwt_enabled()) - } else { - None - }, - left_handed: if device.config_left_handed_is_available() { - Some(device.config_left_handed()) - } else { - None - }, - middle_button_emulation: if device.config_middle_emulation_is_available() { - Some(device.config_middle_emulation_enabled()) - } else { - None - }, - rotation_angle: if device.config_rotation_is_available() { - Some(device.config_rotation_angle()) - } else { - None - }, - scroll_config: if device - .config_scroll_methods() - .iter() - .any(|x| *x != ScrollMethod::NoScroll) - { - Some(ScrollConfig { - method: device.config_scroll_method(), - natural_scroll: if device.config_scroll_has_natural_scroll() { - Some(device.config_scroll_natural_scroll_enabled()) - } else { - None - }, - scroll_button: if device.config_scroll_method() - == Some(ScrollMethod::OnButtonDown) - { - Some(device.config_scroll_button()) - } else { - None - }, - }) - } else { - None - }, - tap_config: if device.config_tap_finger_count() > 0 { - Some(TapConfig { - enabled: device.config_tap_enabled(), - button_map: device.config_tap_button_map(), - drag: device.config_tap_drag_enabled(), - drag_lock: device.config_tap_drag_lock_enabled(), - }) - } else { - None - }, +fn get_config<'a, T: 'a, F: Fn(&'a InputConfig) -> Option>( + device_config: Option<&'a InputConfig>, + default_config: &'a InputConfig, + f: F, +) -> Option { + if let Some(device_config) = device_config { + if let Some(setting) = f(device_config) { + return Some(setting); } } + f(default_config) +} - pub fn update_device(&self, device: &mut InputDevice) { - if let Err(err) = match self.state { - DeviceState::Enabled => device.config_send_events_set_mode(SendEventsMode::ENABLED), - DeviceState::Disabled => device.config_send_events_set_mode(SendEventsMode::DISABLED), - DeviceState::DisabledOnExternalMouse => { - device.config_send_events_set_mode(SendEventsMode::DISABLED_ON_EXTERNAL_MOUSE) +pub fn update_device( + device: &mut InputDevice, + device_config: Option<&InputConfig>, + default_config: &InputConfig, +) { + macro_rules! config { + ($f:expr) => { + get_config(device_config, default_config, $f) + }; + } + + let state = device_config.unwrap_or(default_config).state; + if let Err(err) = match state { + DeviceState::Enabled => device.config_send_events_set_mode(SendEventsMode::ENABLED), + DeviceState::Disabled => device.config_send_events_set_mode(SendEventsMode::DISABLED), + DeviceState::DisabledOnExternalMouse => { + device.config_send_events_set_mode(SendEventsMode::DISABLED_ON_EXTERNAL_MOUSE) + } + } { + warn!( + ?err, + "Failed to apply mode {:?} for device {:?}.", + state, + device.name(), + ); + } + if let Some(accel) = config!(|x| x.acceleration.as_ref()) { + if let Some(profile) = accel.profile { + if let Err(err) = device.config_accel_set_profile(profile) { + warn!( + ?err, + "Failed to apply acceleration profile {:?} for device {:?}.", + profile, + device.name(), + ); } - } { + } + if let Err(err) = device.config_accel_set_speed(accel.speed) { warn!( ?err, - "Failed to apply mode {:?} for device {:?}.", - self.state, + "Failed to apply acceleration speed {:?} for device {:?}.", + accel.speed, device.name(), ); } - if let Some(accel) = self.acceleration.as_ref() { - if let Some(profile) = accel.profile { - if let Err(err) = device.config_accel_set_profile(profile) { - warn!( - ?err, - "Failed to apply acceleration profile {:?} for device {:?}.", - profile, - device.name(), - ); - } - } - if let Err(err) = device.config_accel_set_speed(accel.speed) { - warn!( - ?err, - "Failed to apply acceleration speed {:?} for device {:?}.", - accel.speed, - device.name(), - ); - } + } + if let Some(matrix) = config!(|x| x.calibration) { + if let Err(err) = device.config_calibration_set_matrix(matrix) { + warn!( + ?err, + "Failed to apply calibration matrix {:?} for device {:?}.", + matrix, + device.name(), + ); } - if let Some(matrix) = self.calibration { - if let Err(err) = device.config_calibration_set_matrix(matrix) { - warn!( - ?err, - "Failed to apply calibration matrix {:?} for device {:?}.", - matrix, - device.name(), - ); - } + } + if let Some(method) = config!(|x| x.click_method) { + if let Err(err) = device.config_click_set_method(method) { + warn!( + ?err, + "Failed to apply click method {:?} for device {:?}.", + method, + device.name(), + ); } - if let Some(method) = self.click_method { - if let Err(err) = device.config_click_set_method(method) { + } + if let Some(dwt) = config!(|x| x.disable_while_typing) { + if let Err(err) = device.config_dwt_set_enabled(dwt) { + warn!( + ?err, + "Failed to apply disable-while-typing {:?} for device {:?}.", + dwt, + device.name(), + ); + } + } + if let Some(left) = config!(|x| x.left_handed) { + if let Err(err) = device.config_left_handed_set(left) { + warn!( + ?err, + "Failed to apply left-handed {:?} for device {:?}.", + left, + device.name(), + ); + } + } + if let Some(middle) = config!(|x| x.middle_button_emulation) { + if let Err(err) = device.config_middle_emulation_set_enabled(middle) { + warn!( + ?err, + "Failed to apply middle-button-emulation {:?} for device {:?}.", + middle, + device.name(), + ); + } + } + if let Some(angle) = config!(|x| x.rotation_angle) { + if let Err(err) = device.config_rotation_set_angle(angle) { + warn!( + ?err, + "Failed to apply rotation-angle {:?} for device {:?}", + angle, + device.name(), + ); + } + } + if let Some(scroll) = config!(|x| x.scroll_config.as_ref()) { + if let Some(method) = scroll.method { + if let Err(err) = device.config_scroll_set_method(method) { warn!( ?err, - "Failed to apply click method {:?} for device {:?}.", + "Failed to apply scroll method {:?} for device {:?}.", method, device.name(), ); } } - if let Some(dwt) = self.disable_while_typing { - if let Err(err) = device.config_dwt_set_enabled(dwt) { + if let Some(natural) = scroll.natural_scroll { + if let Err(err) = device.config_scroll_set_natural_scroll_enabled(natural) { warn!( ?err, - "Failed to apply disable-while-typing {:?} for device {:?}.", - dwt, + "Failed to apply natural scrolling {:?} for device {:?}.", + natural, device.name(), ); } } - if let Some(left) = self.left_handed { - if let Err(err) = device.config_left_handed_set(left) { + if let Some(button) = scroll.scroll_button { + if let Err(err) = device.config_scroll_set_button(button) { warn!( ?err, - "Failed to apply left-handed {:?} for device {:?}.", - left, - device.name(), - ); - } - } - if let Some(middle) = self.middle_button_emulation { - if let Err(err) = device.config_middle_emulation_set_enabled(middle) { - warn!( - ?err, - "Failed to apply middle-button-emulation {:?} for device {:?}.", - middle, - device.name(), - ); - } - } - if let Some(angle) = self.rotation_angle { - if let Err(err) = device.config_rotation_set_angle(angle) { - warn!( - ?err, - "Failed to apply rotation-angle {:?} for device {:?}", - angle, - device.name(), - ); - } - } - if let Some(scroll) = self.scroll_config.as_ref() { - if let Some(method) = scroll.method { - if let Err(err) = device.config_scroll_set_method(method) { - warn!( - ?err, - "Failed to apply scroll method {:?} for device {:?}.", - method, - device.name(), - ); - } - } - if let Some(natural) = scroll.natural_scroll { - if let Err(err) = device.config_scroll_set_natural_scroll_enabled(natural) { - warn!( - ?err, - "Failed to apply natural scrolling {:?} for device {:?}.", - natural, - device.name(), - ); - } - } - if let Some(button) = scroll.scroll_button { - if let Err(err) = device.config_scroll_set_button(button) { - warn!( - ?err, - "Failed to apply scroll button {:?} for device {:?}.", - button, - device.name(), - ); - } - } - } - if let Some(tap) = self.tap_config.as_ref() { - if let Err(err) = device.config_tap_set_enabled(tap.enabled) { - warn!( - ?err, - "Failed to apply tap-to-click {:?} for device {:?}.", - tap.enabled, - device.name(), - ); - } - if let Some(button_map) = tap.button_map { - if let Err(err) = device.config_tap_set_button_map(button_map) { - warn!( - ?err, - "Failed to apply button map {:?} for device {:?}.", - button_map, - device.name(), - ); - } - } - if let Err(err) = device.config_tap_set_drag_enabled(tap.drag) { - warn!( - ?err, - "Failed to apply tap-drag {:?} for device {:?}.", - tap.drag, - device.name(), - ); - } - if let Err(err) = device.config_tap_set_drag_lock_enabled(tap.drag_lock) { - warn!( - ?err, - "Failed to apply tap-drag-lock {:?} for device {:?}.", - tap.drag_lock, + "Failed to apply scroll button {:?} for device {:?}.", + button, device.name(), ); } } } + if let Some(tap) = config!(|x| x.tap_config.as_ref()) { + if let Err(err) = device.config_tap_set_enabled(tap.enabled) { + warn!( + ?err, + "Failed to apply tap-to-click {:?} for device {:?}.", + tap.enabled, + device.name(), + ); + } + if let Some(button_map) = tap.button_map { + if let Err(err) = device.config_tap_set_button_map(button_map) { + warn!( + ?err, + "Failed to apply button map {:?} for device {:?}.", + button_map, + device.name(), + ); + } + } + if let Err(err) = device.config_tap_set_drag_enabled(tap.drag) { + warn!( + ?err, + "Failed to apply tap-drag {:?} for device {:?}.", + tap.drag, + device.name(), + ); + } + if let Err(err) = device.config_tap_set_drag_lock_enabled(tap.drag_lock) { + warn!( + ?err, + "Failed to apply tap-drag-lock {:?} for device {:?}.", + tap.drag_lock, + device.name(), + ); + } + } } diff --git a/src/config/mod.rs b/src/config/mod.rs index 81dd8da4..826bf220 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -5,7 +5,7 @@ use crate::{ state::{BackendData, Data, State}, wayland::protocols::output_configuration::OutputConfigurationState, }; -use cosmic_config::{ConfigGet, ConfigSet}; +use cosmic_config::ConfigGet; use serde::{Deserialize, Serialize}; use smithay::input::Seat; pub use smithay::{ @@ -25,11 +25,11 @@ use std::{cell::RefCell, collections::HashMap, fs::OpenOptions, path::PathBuf}; use tracing::{debug, error, info, warn}; mod input_config; -use input_config::InputConfig; mod key_bindings; pub use key_bindings::{Action, KeyModifier, KeyModifiers, KeyPattern}; mod types; pub use self::types::*; +use cosmic_comp_config::{input::InputConfig, XkbConfig}; #[derive(Debug)] pub struct Config { @@ -37,6 +37,8 @@ pub struct Config { pub dynamic_conf: DynamicConfig, pub config: cosmic_config::Config, pub xkb: XkbConfig, + pub input_default: InputConfig, + pub input_touchpad: InputConfig, pub input_devices: HashMap, } @@ -169,6 +171,8 @@ impl Config { static_conf: Self::load_static(xdg.as_ref()), dynamic_conf: Self::load_dynamic(xdg.as_ref()), xkb: get_config(&config, "xkb-config"), + input_default: get_config(&config, "input-default"), + input_touchpad: get_config(&config, "input-touchpad"), input_devices: get_config(&config, "input-devices"), config, } @@ -407,22 +411,14 @@ impl Config { self.xkb.clone() } - pub fn read_device(&mut self, device: &mut InputDevice) { - use std::collections::hash_map::Entry; - - let mut config_changed = false; - match self.input_devices.entry(device.name().into()) { - Entry::Occupied(entry) => entry.get().update_device(device), - Entry::Vacant(entry) => { - entry.insert(InputConfig::for_device(device)); - config_changed = true; - } - } - if config_changed { - if let Err(err) = self.config.set("input-devices", &self.input_devices) { - error!(?err, "Failed to write config 'input-devices'"); - } - } + pub fn read_device(&self, device: &mut InputDevice) { + let default_config = if device.config_tap_finger_count() > 0 { + &self.input_touchpad + } else { + &self.input_default + }; + let device_config = self.input_devices.get(device.name()); + input_config::update_device(device, device_config, default_config); } } @@ -483,6 +479,14 @@ fn get_config( }) } +fn update_input(state: &mut State) { + if let BackendData::Kms(ref mut kms_state) = &mut state.backend { + for device in kms_state.input_devices.values_mut() { + state.common.config.read_device(device); + } + } +} + fn config_changed(config: cosmic_config::Config, keys: Vec, state: &mut State) { for key in &keys { match key.as_str() { @@ -490,7 +494,7 @@ fn config_changed(config: cosmic_config::Config, keys: Vec, state: &mut let value = get_config::(&config, "xkb-config"); for seat in state.common.seats().cloned().collect::>().iter() { if let Some(keyboard) = seat.get_keyboard() { - if let Err(err) = keyboard.set_xkb_config(state, (&value).into()) { + if let Err(err) = keyboard.set_xkb_config(state, xkb_config_to_wl(&value)) { error!(?err, "Failed to load provided xkb config"); // TODO Revert to default? } @@ -498,18 +502,32 @@ fn config_changed(config: cosmic_config::Config, keys: Vec, state: &mut } state.common.config.xkb = value; } + "input-default" => { + let value = get_config::(&config, "input-default"); + state.common.config.input_default = value; + update_input(state); + } + "input-touchpad" => { + let value = get_config::(&config, "input-touchpad"); + state.common.config.input_touchpad = value; + update_input(state); + } "input-devices" => { let value = get_config::>(&config, "input-devices"); - if let BackendData::Kms(ref mut kms_state) = &mut state.backend { - for (name, device) in kms_state.input_devices.iter_mut() { - if let Some(input_config) = value.get(name) { - input_config.update_device(device); - } - } - } state.common.config.input_devices = value; + update_input(state); } _ => {} } } } + +pub fn xkb_config_to_wl(config: &XkbConfig) -> WlXkbConfig<'_> { + WlXkbConfig { + rules: &config.rules, + model: &config.model, + layout: &config.layout, + variant: &config.variant, + options: config.options.clone(), + } +} diff --git a/src/config/types.rs b/src/config/types.rs index d9f2577c..349dc216 100644 --- a/src/config/types.rs +++ b/src/config/types.rs @@ -13,147 +13,6 @@ pub use smithay::{ use tracing::warn; use xkbcommon::xkb; -#[derive(Debug, Clone, Deserialize, Serialize)] -pub struct XkbConfig { - pub rules: String, - pub model: String, - pub layout: String, - pub variant: String, - pub options: Option, -} - -impl Default for XkbConfig { - fn default() -> XkbConfig { - XkbConfig { - rules: String::new(), - model: String::new(), - layout: String::new(), - variant: String::new(), - options: None, - } - } -} - -impl<'a> Into> for &'a XkbConfig { - fn into(self) -> WlXkbConfig<'a> { - WlXkbConfig { - rules: &self.rules, - model: &self.model, - layout: &self.layout, - variant: &self.variant, - options: self.options.clone(), - } - } -} - -pub mod ClickMethodDef { - use serde::{Deserialize, Deserializer, Serialize, Serializer}; - use smithay::reexports::input::ClickMethod as ClickMethodOrig; - - #[derive(Debug, Serialize, Deserialize)] - pub enum ClickMethod { - ButtonAreas, - Clickfinger, - } - - pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> - where - D: Deserializer<'de>, - { - let o = Option::deserialize(deserializer)?; - Ok(o.map(|x| match x { - ClickMethod::ButtonAreas => ClickMethodOrig::ButtonAreas, - ClickMethod::Clickfinger => ClickMethodOrig::Clickfinger, - })) - } - - pub fn serialize(arg: &Option, ser: S) -> Result - where - S: Serializer, - { - let arg = match arg { - Some(ClickMethodOrig::ButtonAreas) => Some(ClickMethod::ButtonAreas), - Some(ClickMethodOrig::Clickfinger) => Some(ClickMethod::Clickfinger), - Some(_) | None => None, - }; - Option::serialize(&arg, ser) - } -} - -pub mod AccelProfileDef { - use serde::{Deserialize, Deserializer, Serialize, Serializer}; - use smithay::reexports::input::AccelProfile as AccelProfileOrig; - - #[derive(Debug, Serialize, Deserialize)] - enum AccelProfile { - Flat, - Adaptive, - } - - pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> - where - D: Deserializer<'de>, - { - let o = Option::deserialize(deserializer)?; - Ok(o.map(|x| match x { - AccelProfile::Flat => AccelProfileOrig::Flat, - AccelProfile::Adaptive => AccelProfileOrig::Adaptive, - })) - } - - pub fn serialize(arg: &Option, ser: S) -> Result - where - S: Serializer, - { - let arg = match arg { - Some(AccelProfileOrig::Flat) => Some(AccelProfile::Flat), - Some(AccelProfileOrig::Adaptive) => Some(AccelProfile::Adaptive), - Some(_) | None => None, - }; - Option::serialize(&arg, ser) - } -} - -pub mod ScrollMethodDef { - use serde::{Deserialize, Deserializer, Serialize, Serializer}; - use smithay::reexports::input::ScrollMethod as ScrollMethodOrig; - - #[derive(Debug, Serialize, Deserialize)] - pub enum ScrollMethod { - NoScroll, - TwoFinger, - Edge, - OnButtonDown, - } - - pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> - where - D: Deserializer<'de>, - { - let o = Option::deserialize(deserializer)?; - Ok(o.map(|x| match x { - ScrollMethod::NoScroll => ScrollMethodOrig::NoScroll, - ScrollMethod::TwoFinger => ScrollMethodOrig::TwoFinger, - ScrollMethod::Edge => ScrollMethodOrig::Edge, - ScrollMethod::OnButtonDown => ScrollMethodOrig::OnButtonDown, - })) - } - - pub fn serialize(arg: &Option, ser: S) -> Result - where - S: Serializer, - { - let arg = match arg { - Some(ScrollMethodOrig::NoScroll) => Some(ScrollMethod::NoScroll), - Some(ScrollMethodOrig::TwoFinger) => Some(ScrollMethod::TwoFinger), - Some(ScrollMethodOrig::Edge) => Some(ScrollMethod::Edge), - Some(ScrollMethodOrig::OnButtonDown) => Some(ScrollMethod::OnButtonDown), - Some(_) | None => None, - }; - Option::serialize(&arg, ser) - } -} - #[derive(Serialize, Deserialize)] #[serde(remote = "Transform")] pub enum TransformDef { @@ -167,40 +26,6 @@ pub enum TransformDef { Flipped270, } -pub mod TapButtonMapDef { - use serde::{Deserialize, Deserializer, Serialize, Serializer}; - use smithay::reexports::input::TapButtonMap as TapButtonMapOrig; - - #[derive(Debug, Serialize, Deserialize)] - pub enum TapButtonMap { - LeftRightMiddle, - LeftMiddleRight, - } - - pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> - where - D: Deserializer<'de>, - { - let o = Option::deserialize(deserializer)?; - Ok(o.map(|x| match x { - TapButtonMap::LeftRightMiddle => TapButtonMapOrig::LeftRightMiddle, - TapButtonMap::LeftMiddleRight => TapButtonMapOrig::LeftMiddleRight, - })) - } - - pub fn serialize(arg: &Option, ser: S) -> Result - where - S: Serializer, - { - let arg = match arg { - Some(TapButtonMapOrig::LeftRightMiddle) => Some(TapButtonMap::LeftRightMiddle), - Some(TapButtonMapOrig::LeftMiddleRight) => Some(TapButtonMap::LeftMiddleRight), - Some(_) | None => None, - }; - Option::serialize(&arg, ser) - } -} - #[derive(Deserialize)] #[serde(transparent)] pub struct KeyModifiersDef(Vec); diff --git a/src/input/mod.rs b/src/input/mod.rs index 0c647243..27ec163f 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -2,7 +2,7 @@ use crate::{ backend::render::cursor::CursorState, - config::{Action, Config, KeyPattern, WorkspaceLayout}, + config::{xkb_config_to_wl, Action, Config, KeyPattern, WorkspaceLayout}, shell::{ focus::{target::PointerFocusTarget, FocusDirection}, grabs::{ResizeEdge, SeatMoveGrabState}, @@ -153,7 +153,7 @@ pub fn add_seat( // So instead of doing the right thing (and initialize these capabilities as matching // devices appear), we have to surrender to reality and just always expose a keyboard and pointer. let conf = config.xkb_config(); - if let Err(err) = seat.add_keyboard((&conf).into(), 200, 25) { + if let Err(err) = seat.add_keyboard(xkb_config_to_wl(&conf), 200, 25) { warn!( ?err, "Failed to load provided xkb config. Trying default...",