Merge pull request #140 from pop-os/cosmic-comp-config
Use cosmic-config for input config; changeable at runtime
This commit is contained in:
commit
511ee8d87a
12 changed files with 892 additions and 809 deletions
41
Cargo.lock
generated
41
Cargo.lock
generated
|
|
@ -481,6 +481,8 @@ dependencies = [
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"calloop",
|
"calloop",
|
||||||
|
"cosmic-comp-config",
|
||||||
|
"cosmic-config",
|
||||||
"cosmic-protocols",
|
"cosmic-protocols",
|
||||||
"edid-rs",
|
"edid-rs",
|
||||||
"egui",
|
"egui",
|
||||||
|
|
@ -521,12 +523,21 @@ dependencies = [
|
||||||
"xkbcommon 0.4.1",
|
"xkbcommon 0.4.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cosmic-comp-config"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"input",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cosmic-config"
|
name = "cosmic-config"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic/?rev=42d7baf#42d7baf0d5cb14ab476120be9dfcaea9bd1d0be4"
|
source = "git+https://github.com/pop-os/libcosmic/?rev=4895b0c#4895b0c9bda9e46fc7db173e239d155dac957186"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atomicwrites",
|
"atomicwrites",
|
||||||
|
"calloop",
|
||||||
"cosmic-config-derive",
|
"cosmic-config-derive",
|
||||||
"dirs 5.0.1",
|
"dirs 5.0.1",
|
||||||
"iced_futures",
|
"iced_futures",
|
||||||
|
|
@ -538,7 +549,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cosmic-config-derive"
|
name = "cosmic-config-derive"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic/?rev=42d7baf#42d7baf0d5cb14ab476120be9dfcaea9bd1d0be4"
|
source = "git+https://github.com/pop-os/libcosmic/?rev=4895b0c#4895b0c9bda9e46fc7db173e239d155dac957186"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
|
|
@ -578,7 +589,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cosmic-theme"
|
name = "cosmic-theme"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic/?rev=42d7baf#42d7baf0d5cb14ab476120be9dfcaea9bd1d0be4"
|
source = "git+https://github.com/pop-os/libcosmic/?rev=4895b0c#4895b0c9bda9e46fc7db173e239d155dac957186"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"cosmic-config",
|
"cosmic-config",
|
||||||
|
|
@ -1746,7 +1757,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced"
|
name = "iced"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic/?rev=42d7baf#42d7baf0d5cb14ab476120be9dfcaea9bd1d0be4"
|
source = "git+https://github.com/pop-os/libcosmic/?rev=4895b0c#4895b0c9bda9e46fc7db173e239d155dac957186"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"iced_core",
|
"iced_core",
|
||||||
"iced_futures",
|
"iced_futures",
|
||||||
|
|
@ -1759,7 +1770,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_core"
|
name = "iced_core"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic/?rev=42d7baf#42d7baf0d5cb14ab476120be9dfcaea9bd1d0be4"
|
source = "git+https://github.com/pop-os/libcosmic/?rev=4895b0c#4895b0c9bda9e46fc7db173e239d155dac957186"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
"instant",
|
"instant",
|
||||||
|
|
@ -1772,7 +1783,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_futures"
|
name = "iced_futures"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic/?rev=42d7baf#42d7baf0d5cb14ab476120be9dfcaea9bd1d0be4"
|
source = "git+https://github.com/pop-os/libcosmic/?rev=4895b0c#4895b0c9bda9e46fc7db173e239d155dac957186"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures",
|
"futures",
|
||||||
"iced_core",
|
"iced_core",
|
||||||
|
|
@ -1784,7 +1795,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_graphics"
|
name = "iced_graphics"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic/?rev=42d7baf#42d7baf0d5cb14ab476120be9dfcaea9bd1d0be4"
|
source = "git+https://github.com/pop-os/libcosmic/?rev=4895b0c#4895b0c9bda9e46fc7db173e239d155dac957186"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
|
|
@ -1801,7 +1812,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_renderer"
|
name = "iced_renderer"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic/?rev=42d7baf#42d7baf0d5cb14ab476120be9dfcaea9bd1d0be4"
|
source = "git+https://github.com/pop-os/libcosmic/?rev=4895b0c#4895b0c9bda9e46fc7db173e239d155dac957186"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"iced_graphics",
|
"iced_graphics",
|
||||||
"iced_tiny_skia",
|
"iced_tiny_skia",
|
||||||
|
|
@ -1813,7 +1824,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_runtime"
|
name = "iced_runtime"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic/?rev=42d7baf#42d7baf0d5cb14ab476120be9dfcaea9bd1d0be4"
|
source = "git+https://github.com/pop-os/libcosmic/?rev=4895b0c#4895b0c9bda9e46fc7db173e239d155dac957186"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"iced_core",
|
"iced_core",
|
||||||
"iced_futures",
|
"iced_futures",
|
||||||
|
|
@ -1823,7 +1834,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_style"
|
name = "iced_style"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic/?rev=42d7baf#42d7baf0d5cb14ab476120be9dfcaea9bd1d0be4"
|
source = "git+https://github.com/pop-os/libcosmic/?rev=4895b0c#4895b0c9bda9e46fc7db173e239d155dac957186"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"iced_core",
|
"iced_core",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
|
@ -1833,7 +1844,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_tiny_skia"
|
name = "iced_tiny_skia"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic/?rev=42d7baf#42d7baf0d5cb14ab476120be9dfcaea9bd1d0be4"
|
source = "git+https://github.com/pop-os/libcosmic/?rev=4895b0c#4895b0c9bda9e46fc7db173e239d155dac957186"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"cosmic-text",
|
"cosmic-text",
|
||||||
|
|
@ -1851,7 +1862,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_wgpu"
|
name = "iced_wgpu"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic/?rev=42d7baf#42d7baf0d5cb14ab476120be9dfcaea9bd1d0be4"
|
source = "git+https://github.com/pop-os/libcosmic/?rev=4895b0c#4895b0c9bda9e46fc7db173e239d155dac957186"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
|
|
@ -1872,7 +1883,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced_widget"
|
name = "iced_widget"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic/?rev=42d7baf#42d7baf0d5cb14ab476120be9dfcaea9bd1d0be4"
|
source = "git+https://github.com/pop-os/libcosmic/?rev=4895b0c#4895b0c9bda9e46fc7db173e239d155dac957186"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"iced_renderer",
|
"iced_renderer",
|
||||||
"iced_runtime",
|
"iced_runtime",
|
||||||
|
|
@ -1979,6 +1990,7 @@ dependencies = [
|
||||||
"input-sys",
|
"input-sys",
|
||||||
"io-lifetimes",
|
"io-lifetimes",
|
||||||
"libc",
|
"libc",
|
||||||
|
"log",
|
||||||
"udev",
|
"udev",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -2167,7 +2179,7 @@ checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libcosmic"
|
name = "libcosmic"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/pop-os/libcosmic/?rev=42d7baf#42d7baf0d5cb14ab476120be9dfcaea9bd1d0be4"
|
source = "git+https://github.com/pop-os/libcosmic/?rev=4895b0c#4895b0c9bda9e46fc7db173e239d155dac957186"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"apply",
|
"apply",
|
||||||
"cosmic-config",
|
"cosmic-config",
|
||||||
|
|
@ -2186,6 +2198,7 @@ dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"palette",
|
"palette",
|
||||||
"slotmap",
|
"slotmap",
|
||||||
|
"thiserror",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
11
Cargo.toml
11
Cargo.toml
|
|
@ -5,6 +5,11 @@ edition = "2021"
|
||||||
license = "GPL-3.0-only"
|
license = "GPL-3.0-only"
|
||||||
authors = ["Victoria Brekenfeld"]
|
authors = ["Victoria Brekenfeld"]
|
||||||
|
|
||||||
|
[workspace]
|
||||||
|
members = [
|
||||||
|
"cosmic-comp-config"
|
||||||
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
apply = "0.3.0"
|
apply = "0.3.0"
|
||||||
anyhow = { version = "1.0.51", features = ["backtrace"] }
|
anyhow = { version = "1.0.51", features = ["backtrace"] }
|
||||||
|
|
@ -30,9 +35,11 @@ ron = "0.7"
|
||||||
libsystemd = { version = "0.5", optional = true }
|
libsystemd = { version = "0.5", optional = true }
|
||||||
wayland-backend = "0.1.0"
|
wayland-backend = "0.1.0"
|
||||||
wayland-scanner = "0.30.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"] }
|
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 = "42d7baf", default-features = false }
|
libcosmic = { git = "https://github.com/pop-os/libcosmic/", rev = "4895b0c", default-features = false }
|
||||||
iced_tiny_skia = { git = "https://github.com/pop-os/libcosmic/", rev = "42d7baf" }
|
iced_tiny_skia = { git = "https://github.com/pop-os/libcosmic/", rev = "4895b0c" }
|
||||||
tiny-skia = "0.9"
|
tiny-skia = "0.9"
|
||||||
ordered-float = "3.0"
|
ordered-float = "3.0"
|
||||||
glow = "0.11.2"
|
glow = "0.11.2"
|
||||||
|
|
|
||||||
8
cosmic-comp-config/Cargo.toml
Normal file
8
cosmic-comp-config/Cargo.toml
Normal file
|
|
@ -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"] }
|
||||||
209
cosmic-comp-config/src/input.rs
Normal file
209
cosmic-comp-config/src/input.rs
Normal file
|
|
@ -0,0 +1,209 @@
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
|
pub use input::{AccelProfile, ClickMethod, ScrollMethod, TapButtonMap};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
||||||
|
pub struct InputConfig {
|
||||||
|
pub state: DeviceState,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none", default)]
|
||||||
|
pub acceleration: Option<AccelConfig>,
|
||||||
|
#[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<ClickMethod>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none", default)]
|
||||||
|
pub disable_while_typing: Option<bool>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none", default)]
|
||||||
|
pub left_handed: Option<bool>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none", default)]
|
||||||
|
pub middle_button_emulation: Option<bool>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none", default)]
|
||||||
|
pub rotation_angle: Option<u32>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none", default)]
|
||||||
|
pub scroll_config: Option<ScrollConfig>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none", default)]
|
||||||
|
pub tap_config: Option<TapConfig>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
||||||
|
pub struct AccelConfig {
|
||||||
|
#[serde(with = "AccelProfileDef")]
|
||||||
|
pub profile: Option<AccelProfile>,
|
||||||
|
pub speed: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
||||||
|
pub struct ScrollConfig {
|
||||||
|
#[serde(with = "ScrollMethodDef")]
|
||||||
|
pub method: Option<ScrollMethod>,
|
||||||
|
pub natural_scroll: Option<bool>,
|
||||||
|
pub scroll_button: Option<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub enum DeviceState {
|
||||||
|
Enabled,
|
||||||
|
Disabled,
|
||||||
|
DisabledOnExternalMouse,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for DeviceState {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Enabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct TapConfig {
|
||||||
|
pub enabled: bool,
|
||||||
|
#[serde(with = "TapButtonMapDef")]
|
||||||
|
pub button_map: Option<TapButtonMap>,
|
||||||
|
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<Option<ClickMethodOrig>, 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<S>(arg: &Option<ClickMethodOrig>, ser: S) -> Result<S::Ok, S::Error>
|
||||||
|
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<Option<AccelProfileOrig>, 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<S>(arg: &Option<AccelProfileOrig>, ser: S) -> Result<S::Ok, S::Error>
|
||||||
|
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<Option<ScrollMethodOrig>, 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<S>(arg: &Option<ScrollMethodOrig>, ser: S) -> Result<S::Ok, S::Error>
|
||||||
|
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<Option<TapButtonMapOrig>, 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<S>(arg: &Option<TapButtonMapOrig>, ser: S) -> Result<S::Ok, S::Error>
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
26
cosmic-comp-config/src/lib.rs
Normal file
26
cosmic-comp-config/src/lib.rs
Normal file
|
|
@ -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<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for XkbConfig {
|
||||||
|
fn default() -> XkbConfig {
|
||||||
|
XkbConfig {
|
||||||
|
rules: String::new(),
|
||||||
|
model: String::new(),
|
||||||
|
layout: String::new(),
|
||||||
|
variant: String::new(),
|
||||||
|
options: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -57,7 +57,7 @@ use smithay::{
|
||||||
control::{connector, crtc, Device as ControlDevice, ModeTypeFlags},
|
control::{connector, crtc, Device as ControlDevice, ModeTypeFlags},
|
||||||
Device as _,
|
Device as _,
|
||||||
},
|
},
|
||||||
input::Libinput,
|
input::{self, Libinput},
|
||||||
nix::{fcntl::OFlag, sys::stat::dev_t},
|
nix::{fcntl::OFlag, sys::stat::dev_t},
|
||||||
wayland_protocols::wp::{
|
wayland_protocols::wp::{
|
||||||
linux_dmabuf::zv1::server::zwp_linux_dmabuf_feedback_v1,
|
linux_dmabuf::zv1::server::zwp_linux_dmabuf_feedback_v1,
|
||||||
|
|
@ -97,6 +97,7 @@ const MIN_RENDER_TIME: Duration = Duration::from_millis(3);
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct KmsState {
|
pub struct KmsState {
|
||||||
devices: HashMap<DrmNode, Device>,
|
devices: HashMap<DrmNode, Device>,
|
||||||
|
pub input_devices: HashMap<String, input::Device>,
|
||||||
pub api: GpuManager<GbmGlesBackend<GlowRenderer>>,
|
pub api: GpuManager<GbmGlesBackend<GlowRenderer>>,
|
||||||
pub primary: DrmNode,
|
pub primary: DrmNode,
|
||||||
session: LibSeatSession,
|
session: LibSeatSession,
|
||||||
|
|
@ -172,8 +173,15 @@ pub fn init_backend(
|
||||||
let libinput_event_source = event_loop
|
let libinput_event_source = event_loop
|
||||||
.handle()
|
.handle()
|
||||||
.insert_source(libinput_backend, move |mut event, _, data| {
|
.insert_source(libinput_backend, move |mut event, _, data| {
|
||||||
if let &mut InputEvent::DeviceAdded { ref mut device } = &mut event {
|
if let InputEvent::DeviceAdded { ref mut device } = &mut event {
|
||||||
data.state.common.config.read_device(device);
|
data.state.common.config.read_device(device);
|
||||||
|
data.state
|
||||||
|
.backend
|
||||||
|
.kms()
|
||||||
|
.input_devices
|
||||||
|
.insert(device.name().into(), device.clone());
|
||||||
|
} else if let InputEvent::DeviceRemoved { device } = &event {
|
||||||
|
data.state.backend.kms().input_devices.remove(device.name());
|
||||||
}
|
}
|
||||||
data.state.process_input_event(event, true);
|
data.state.process_input_event(event, true);
|
||||||
for output in data.state.common.shell.outputs() {
|
for output in data.state.common.shell.outputs() {
|
||||||
|
|
@ -363,6 +371,7 @@ pub fn init_backend(
|
||||||
primary,
|
primary,
|
||||||
session,
|
session,
|
||||||
devices: HashMap::new(),
|
devices: HashMap::new(),
|
||||||
|
input_devices: HashMap::new(),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create relative pointer global
|
// Create relative pointer global
|
||||||
|
|
|
||||||
217
src/config/input_config.rs
Normal file
217
src/config/input_config.rs
Normal file
|
|
@ -0,0 +1,217 @@
|
||||||
|
use smithay::reexports::input::{
|
||||||
|
Device as InputDevice, DeviceConfigError, ScrollMethod, SendEventsMode,
|
||||||
|
};
|
||||||
|
use tracing::warn;
|
||||||
|
|
||||||
|
use cosmic_comp_config::input::*;
|
||||||
|
|
||||||
|
#[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
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get setting from `device_config` if present, then `default_config`
|
||||||
|
// Returns `is_default` to indicate this is a default value.
|
||||||
|
fn get_config<'a, T: 'a, F: Fn(&'a InputConfig) -> Option<T>>(
|
||||||
|
device_config: Option<&'a InputConfig>,
|
||||||
|
default_config: &'a InputConfig,
|
||||||
|
f: F,
|
||||||
|
) -> Option<(T, bool)> {
|
||||||
|
if let Some(setting) = device_config.and_then(&f) {
|
||||||
|
Some((setting, false))
|
||||||
|
} else if let Some(setting) = f(default_config) {
|
||||||
|
Some((setting, true))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn config_set_error<T: std::fmt::Debug>(
|
||||||
|
device: &InputDevice,
|
||||||
|
setting: &str,
|
||||||
|
value: T,
|
||||||
|
err: DeviceConfigError,
|
||||||
|
is_default: bool,
|
||||||
|
) {
|
||||||
|
if !(is_default && err == DeviceConfigError::Unsupported) {
|
||||||
|
warn!(
|
||||||
|
?err,
|
||||||
|
"Failed to apply {} {:?} for device {:?}.",
|
||||||
|
setting,
|
||||||
|
value,
|
||||||
|
device.name(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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, is_default)) = config!(|x| x.acceleration.as_ref()) {
|
||||||
|
if let Some(profile) = accel.profile {
|
||||||
|
if let Err(err) = device.config_accel_set_profile(profile) {
|
||||||
|
config_set_error(device, "acceleration profile", profile, err, is_default);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Err(err) = device.config_accel_set_speed(accel.speed) {
|
||||||
|
config_set_error(device, "acceleration speed", accel.speed, err, is_default);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some((matrix, is_default)) = config!(|x| x.calibration) {
|
||||||
|
if let Err(err) = device.config_calibration_set_matrix(matrix) {
|
||||||
|
config_set_error(device, "calibration matrix", matrix, err, is_default);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some((method, is_default)) = config!(|x| x.click_method) {
|
||||||
|
if let Err(err) = device.config_click_set_method(method) {
|
||||||
|
config_set_error(device, "click method", method, err, is_default);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some((dwt, is_default)) = config!(|x| x.disable_while_typing) {
|
||||||
|
if let Err(err) = device.config_dwt_set_enabled(dwt) {
|
||||||
|
config_set_error(device, "disable-while-typing", dwt, err, is_default);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some((left, is_default)) = config!(|x| x.left_handed) {
|
||||||
|
if let Err(err) = device.config_left_handed_set(left) {
|
||||||
|
config_set_error(device, "left-handed", left, err, is_default);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some((middle, is_default)) = config!(|x| x.middle_button_emulation) {
|
||||||
|
if let Err(err) = device.config_middle_emulation_set_enabled(middle) {
|
||||||
|
config_set_error(device, "middle-button-emulation", middle, err, is_default);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some((angle, is_default)) = config!(|x| x.rotation_angle) {
|
||||||
|
if let Err(err) = device.config_rotation_set_angle(angle) {
|
||||||
|
config_set_error(device, "rotation-angle", angle, err, is_default);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some((scroll, is_default)) = config!(|x| x.scroll_config.as_ref()) {
|
||||||
|
if let Some(method) = scroll.method {
|
||||||
|
if let Err(err) = device.config_scroll_set_method(method) {
|
||||||
|
config_set_error(device, "scroll method", scroll, err, is_default);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(natural) = scroll.natural_scroll {
|
||||||
|
if let Err(err) = device.config_scroll_set_natural_scroll_enabled(natural) {
|
||||||
|
config_set_error(device, "natural scrolling", natural, err, is_default);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(button) = scroll.scroll_button {
|
||||||
|
if let Err(err) = device.config_scroll_set_button(button) {
|
||||||
|
config_set_error(device, "scroll button", button, err, is_default);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some((tap, is_default)) = config!(|x| x.tap_config.as_ref()) {
|
||||||
|
if let Err(err) = device.config_tap_set_enabled(tap.enabled) {
|
||||||
|
config_set_error(device, "tap-to-click", tap.enabled, err, is_default);
|
||||||
|
}
|
||||||
|
if let Some(button_map) = tap.button_map {
|
||||||
|
if let Err(err) = device.config_tap_set_button_map(button_map) {
|
||||||
|
config_set_error(device, "button map", button_map, err, is_default);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Err(err) = device.config_tap_set_drag_enabled(tap.drag) {
|
||||||
|
config_set_error(device, "tap-drag", tap.drag, err, is_default);
|
||||||
|
}
|
||||||
|
if let Err(err) = device.config_tap_set_drag_lock_enabled(tap.drag_lock) {
|
||||||
|
config_set_error(device, "tap-drag-lock", tap.drag_lock, err, is_default);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
295
src/config/key_bindings.rs
Normal file
295
src/config/key_bindings.rs
Normal file
|
|
@ -0,0 +1,295 @@
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
|
use crate::shell::{
|
||||||
|
focus::FocusDirection, grabs::ResizeEdge, layout::tiling::Direction, ResizeDirection,
|
||||||
|
};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use smithay::{
|
||||||
|
backend::input::KeyState,
|
||||||
|
input::keyboard::{keysyms as KeySyms, xkb::keysym_get_name, ModifiersState},
|
||||||
|
};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use super::{types::*, WorkspaceLayout};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
|
||||||
|
pub enum KeyModifier {
|
||||||
|
Ctrl,
|
||||||
|
Alt,
|
||||||
|
Shift,
|
||||||
|
Super,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
|
||||||
|
pub struct KeyModifiers {
|
||||||
|
pub ctrl: bool,
|
||||||
|
pub alt: bool,
|
||||||
|
pub shift: bool,
|
||||||
|
pub logo: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<ModifiersState> for KeyModifiers {
|
||||||
|
fn eq(&self, other: &ModifiersState) -> bool {
|
||||||
|
self.ctrl == other.ctrl
|
||||||
|
&& self.alt == other.alt
|
||||||
|
&& self.shift == other.shift
|
||||||
|
&& self.logo == other.logo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<KeyModifiers> for ModifiersState {
|
||||||
|
fn into(self) -> KeyModifiers {
|
||||||
|
KeyModifiers {
|
||||||
|
ctrl: self.ctrl,
|
||||||
|
alt: self.alt,
|
||||||
|
shift: self.shift,
|
||||||
|
logo: self.logo,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::AddAssign<KeyModifier> for KeyModifiers {
|
||||||
|
fn add_assign(&mut self, rhs: KeyModifier) {
|
||||||
|
match rhs {
|
||||||
|
KeyModifier::Ctrl => self.ctrl = true,
|
||||||
|
KeyModifier::Alt => self.alt = true,
|
||||||
|
KeyModifier::Shift => self.shift = true,
|
||||||
|
KeyModifier::Super => self.logo = true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::BitOr for KeyModifier {
|
||||||
|
type Output = KeyModifiers;
|
||||||
|
|
||||||
|
fn bitor(self, rhs: KeyModifier) -> Self::Output {
|
||||||
|
let mut modifiers = self.into();
|
||||||
|
modifiers += rhs;
|
||||||
|
modifiers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<KeyModifiers> for KeyModifier {
|
||||||
|
fn into(self) -> KeyModifiers {
|
||||||
|
let mut modifiers = KeyModifiers {
|
||||||
|
ctrl: false,
|
||||||
|
alt: false,
|
||||||
|
shift: false,
|
||||||
|
logo: false,
|
||||||
|
};
|
||||||
|
modifiers += self;
|
||||||
|
modifiers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Describtion of a key combination that might be
|
||||||
|
/// handled by the compositor.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Hash)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub struct KeyPattern {
|
||||||
|
/// What modifiers are expected to be pressed alongside the key
|
||||||
|
#[serde(deserialize_with = "deserialize_KeyModifiers")]
|
||||||
|
pub modifiers: KeyModifiers,
|
||||||
|
/// The actual key, that was pressed
|
||||||
|
#[serde(deserialize_with = "deserialize_Keysym")]
|
||||||
|
pub key: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KeyPattern {
|
||||||
|
pub fn new(modifiers: impl Into<KeyModifiers>, key: u32) -> KeyPattern {
|
||||||
|
KeyPattern {
|
||||||
|
modifiers: modifiers.into(),
|
||||||
|
key,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToString for KeyPattern {
|
||||||
|
fn to_string(&self) -> String {
|
||||||
|
let mut result = String::new();
|
||||||
|
if self.modifiers.logo {
|
||||||
|
result += "Super+";
|
||||||
|
}
|
||||||
|
if self.modifiers.ctrl {
|
||||||
|
result += "Ctrl+";
|
||||||
|
}
|
||||||
|
if self.modifiers.alt {
|
||||||
|
result += "Alt+";
|
||||||
|
}
|
||||||
|
if self.modifiers.shift {
|
||||||
|
result += "Shift+";
|
||||||
|
}
|
||||||
|
result += &keysym_get_name(self.key);
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Clone, PartialEq, Eq)]
|
||||||
|
pub enum Action {
|
||||||
|
Terminate,
|
||||||
|
Debug,
|
||||||
|
Close,
|
||||||
|
|
||||||
|
Workspace(u8),
|
||||||
|
NextWorkspace,
|
||||||
|
PreviousWorkspace,
|
||||||
|
LastWorkspace,
|
||||||
|
MoveToWorkspace(u8),
|
||||||
|
MoveToNextWorkspace,
|
||||||
|
MoveToPreviousWorkspace,
|
||||||
|
MoveToLastWorkspace,
|
||||||
|
SendToWorkspace(u8),
|
||||||
|
SendToNextWorkspace,
|
||||||
|
SendToPreviousWorkspace,
|
||||||
|
SendToLastWorkspace,
|
||||||
|
|
||||||
|
NextOutput,
|
||||||
|
PreviousOutput,
|
||||||
|
MoveToNextOutput,
|
||||||
|
MoveToPreviousOutput,
|
||||||
|
SendToNextOutput,
|
||||||
|
SendToPreviousOutput,
|
||||||
|
|
||||||
|
Focus(FocusDirection),
|
||||||
|
Move(Direction),
|
||||||
|
|
||||||
|
ToggleOrientation,
|
||||||
|
Orientation(crate::shell::layout::Orientation),
|
||||||
|
|
||||||
|
ToggleStacking,
|
||||||
|
|
||||||
|
ToggleTiling,
|
||||||
|
ToggleWindowFloating,
|
||||||
|
|
||||||
|
Resizing(ResizeDirection),
|
||||||
|
#[serde(skip)]
|
||||||
|
_ResizingInternal(ResizeDirection, ResizeEdge, KeyState),
|
||||||
|
Maximize,
|
||||||
|
Spawn(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert_binding(
|
||||||
|
key_bindings: &mut HashMap<KeyPattern, Action>,
|
||||||
|
modifiers: KeyModifiers,
|
||||||
|
keys: impl Iterator<Item = u32>,
|
||||||
|
action: Action,
|
||||||
|
) {
|
||||||
|
if !key_bindings.values().any(|a| a == &action) {
|
||||||
|
for key in keys {
|
||||||
|
let pattern = KeyPattern {
|
||||||
|
modifiers: modifiers.clone(),
|
||||||
|
key,
|
||||||
|
};
|
||||||
|
if !key_bindings.contains_key(&pattern) {
|
||||||
|
key_bindings.insert(pattern, action.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_default_bindings(
|
||||||
|
key_bindings: &mut HashMap<KeyPattern, Action>,
|
||||||
|
workspace_layout: WorkspaceLayout,
|
||||||
|
) {
|
||||||
|
let (workspace_previous, workspace_next, output_previous, output_next) = match workspace_layout
|
||||||
|
{
|
||||||
|
WorkspaceLayout::Horizontal => (
|
||||||
|
[KeySyms::KEY_Left, KeySyms::KEY_h],
|
||||||
|
[KeySyms::KEY_Right, KeySyms::KEY_l],
|
||||||
|
[KeySyms::KEY_Up, KeySyms::KEY_k],
|
||||||
|
[KeySyms::KEY_Down, KeySyms::KEY_j],
|
||||||
|
),
|
||||||
|
WorkspaceLayout::Vertical => (
|
||||||
|
[KeySyms::KEY_Up, KeySyms::KEY_k],
|
||||||
|
[KeySyms::KEY_Down, KeySyms::KEY_j],
|
||||||
|
[KeySyms::KEY_Left, KeySyms::KEY_h],
|
||||||
|
[KeySyms::KEY_Right, KeySyms::KEY_l],
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
insert_binding(
|
||||||
|
key_bindings,
|
||||||
|
KeyModifiers {
|
||||||
|
logo: true,
|
||||||
|
ctrl: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
workspace_previous.iter().copied(),
|
||||||
|
Action::PreviousWorkspace,
|
||||||
|
);
|
||||||
|
insert_binding(
|
||||||
|
key_bindings,
|
||||||
|
KeyModifiers {
|
||||||
|
logo: true,
|
||||||
|
ctrl: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
workspace_next.iter().copied(),
|
||||||
|
Action::NextWorkspace,
|
||||||
|
);
|
||||||
|
insert_binding(
|
||||||
|
key_bindings,
|
||||||
|
KeyModifiers {
|
||||||
|
logo: true,
|
||||||
|
ctrl: true,
|
||||||
|
shift: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
workspace_previous.iter().copied(),
|
||||||
|
Action::MoveToPreviousWorkspace,
|
||||||
|
);
|
||||||
|
insert_binding(
|
||||||
|
key_bindings,
|
||||||
|
KeyModifiers {
|
||||||
|
logo: true,
|
||||||
|
ctrl: true,
|
||||||
|
shift: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
workspace_next.iter().copied(),
|
||||||
|
Action::MoveToNextWorkspace,
|
||||||
|
);
|
||||||
|
|
||||||
|
insert_binding(
|
||||||
|
key_bindings,
|
||||||
|
KeyModifiers {
|
||||||
|
logo: true,
|
||||||
|
ctrl: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
output_previous.iter().copied(),
|
||||||
|
Action::PreviousOutput,
|
||||||
|
);
|
||||||
|
insert_binding(
|
||||||
|
key_bindings,
|
||||||
|
KeyModifiers {
|
||||||
|
logo: true,
|
||||||
|
ctrl: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
output_next.iter().copied(),
|
||||||
|
Action::NextOutput,
|
||||||
|
);
|
||||||
|
insert_binding(
|
||||||
|
key_bindings,
|
||||||
|
KeyModifiers {
|
||||||
|
logo: true,
|
||||||
|
ctrl: true,
|
||||||
|
shift: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
output_previous.iter().copied(),
|
||||||
|
Action::MoveToPreviousOutput,
|
||||||
|
);
|
||||||
|
insert_binding(
|
||||||
|
key_bindings,
|
||||||
|
KeyModifiers {
|
||||||
|
logo: true,
|
||||||
|
ctrl: true,
|
||||||
|
shift: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
output_next.iter().copied(),
|
||||||
|
Action::MoveToNextOutput,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -1,15 +1,13 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
shell::{
|
shell::{Shell, WorkspaceAmount},
|
||||||
focus::FocusDirection, grabs::ResizeEdge, layout::tiling::Direction, ResizeDirection,
|
|
||||||
Shell, WorkspaceAmount,
|
|
||||||
},
|
|
||||||
state::{BackendData, Data, State},
|
state::{BackendData, Data, State},
|
||||||
wayland::protocols::output_configuration::OutputConfigurationState,
|
wayland::protocols::output_configuration::OutputConfigurationState,
|
||||||
};
|
};
|
||||||
|
use cosmic_config::ConfigGet;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use smithay::input::{keyboard::xkb::keysym_get_name, Seat};
|
use smithay::input::Seat;
|
||||||
pub use smithay::{
|
pub use smithay::{
|
||||||
backend::input::KeyState,
|
backend::input::KeyState,
|
||||||
input::keyboard::{keysyms as KeySyms, Keysym, ModifiersState},
|
input::keyboard::{keysyms as KeySyms, Keysym, ModifiersState},
|
||||||
|
|
@ -26,18 +24,27 @@ pub use smithay::{
|
||||||
use std::{cell::RefCell, collections::HashMap, fs::OpenOptions, path::PathBuf};
|
use std::{cell::RefCell, collections::HashMap, fs::OpenOptions, path::PathBuf};
|
||||||
use tracing::{debug, error, info, warn};
|
use tracing::{debug, error, info, warn};
|
||||||
|
|
||||||
|
mod input_config;
|
||||||
|
mod key_bindings;
|
||||||
|
pub use key_bindings::{Action, KeyModifier, KeyModifiers, KeyPattern};
|
||||||
mod types;
|
mod types;
|
||||||
pub use self::types::*;
|
pub use self::types::*;
|
||||||
|
use cosmic_comp_config::{input::InputConfig, XkbConfig};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub static_conf: StaticConfig,
|
pub static_conf: StaticConfig,
|
||||||
pub dynamic_conf: DynamicConfig,
|
pub dynamic_conf: DynamicConfig,
|
||||||
|
pub config: cosmic_config::Config,
|
||||||
|
pub xkb: XkbConfig,
|
||||||
|
pub input_default: InputConfig,
|
||||||
|
pub input_touchpad: InputConfig,
|
||||||
|
pub input_devices: HashMap<String, InputConfig>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct StaticConfig {
|
pub struct StaticConfig {
|
||||||
pub key_bindings: HashMap<KeyPattern, Action>,
|
pub key_bindings: HashMap<key_bindings::KeyPattern, key_bindings::Action>,
|
||||||
pub workspace_mode: WorkspaceMode,
|
pub workspace_mode: WorkspaceMode,
|
||||||
pub workspace_amount: WorkspaceAmount,
|
pub workspace_amount: WorkspaceAmount,
|
||||||
#[serde(default = "default_workspace_layout")]
|
#[serde(default = "default_workspace_layout")]
|
||||||
|
|
@ -64,7 +71,6 @@ pub enum WorkspaceLayout {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct DynamicConfig {
|
pub struct DynamicConfig {
|
||||||
outputs: (Option<PathBuf>, OutputsConfig),
|
outputs: (Option<PathBuf>, OutputsConfig),
|
||||||
inputs: (Option<PathBuf>, InputsConfig),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
|
|
@ -151,73 +157,24 @@ impl OutputConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
|
||||||
pub struct InputsConfig {
|
|
||||||
xkb: XkbConfig,
|
|
||||||
devices: HashMap<String, InputConfig>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
|
||||||
pub struct InputConfig {
|
|
||||||
state: DeviceState,
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none", default)]
|
|
||||||
acceleration: Option<AccelConfig>,
|
|
||||||
#[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<ClickMethod>,
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none", default)]
|
|
||||||
disable_while_typing: Option<bool>,
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none", default)]
|
|
||||||
left_handed: Option<bool>,
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none", default)]
|
|
||||||
middle_button_emulation: Option<bool>,
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none", default)]
|
|
||||||
rotation_angle: Option<u32>,
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none", default)]
|
|
||||||
scroll_config: Option<ScrollConfig>,
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none", default)]
|
|
||||||
tap_config: Option<TapConfig>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
|
||||||
pub struct AccelConfig {
|
|
||||||
#[serde(with = "AccelProfileDef")]
|
|
||||||
profile: Option<AccelProfile>,
|
|
||||||
speed: f64,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
|
||||||
pub struct ScrollConfig {
|
|
||||||
#[serde(with = "ScrollMethodDef")]
|
|
||||||
method: Option<ScrollMethod>,
|
|
||||||
natural_scroll: Option<bool>,
|
|
||||||
scroll_button: Option<u32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[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<TapButtonMap>,
|
|
||||||
drag: bool,
|
|
||||||
drag_lock: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn load() -> Config {
|
pub fn load(loop_handle: &LoopHandle<'_, Data>) -> Config {
|
||||||
|
let config = cosmic_config::Config::new("com.system76.CosmicComp", 1).unwrap();
|
||||||
|
let source = cosmic_config::calloop::ConfigWatchSource::new(&config).unwrap();
|
||||||
|
loop_handle
|
||||||
|
.insert_source(source, |(config, keys), (), shared_data| {
|
||||||
|
config_changed(config, keys, &mut shared_data.state);
|
||||||
|
})
|
||||||
|
.expect("Failed to add cosmic-config to the event loop");
|
||||||
let xdg = xdg::BaseDirectories::new().ok();
|
let xdg = xdg::BaseDirectories::new().ok();
|
||||||
Config {
|
Config {
|
||||||
static_conf: Self::load_static(xdg.as_ref()),
|
static_conf: Self::load_static(xdg.as_ref()),
|
||||||
dynamic_conf: Self::load_dynamic(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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -247,125 +204,9 @@ impl Config {
|
||||||
ron::de::from_reader(OpenOptions::new().read(true).open(path).unwrap())
|
ron::de::from_reader(OpenOptions::new().read(true).open(path).unwrap())
|
||||||
.expect("Malformed config file");
|
.expect("Malformed config file");
|
||||||
|
|
||||||
let (workspace_previous, workspace_next, output_previous, output_next) =
|
key_bindings::add_default_bindings(
|
||||||
match config.workspace_layout {
|
|
||||||
WorkspaceLayout::Horizontal => (
|
|
||||||
[KeySyms::KEY_Left, KeySyms::KEY_h],
|
|
||||||
[KeySyms::KEY_Right, KeySyms::KEY_j],
|
|
||||||
[KeySyms::KEY_Up, KeySyms::KEY_k],
|
|
||||||
[KeySyms::KEY_Down, KeySyms::KEY_j],
|
|
||||||
),
|
|
||||||
WorkspaceLayout::Vertical => (
|
|
||||||
[KeySyms::KEY_Up, KeySyms::KEY_k],
|
|
||||||
[KeySyms::KEY_Down, KeySyms::KEY_j],
|
|
||||||
[KeySyms::KEY_Left, KeySyms::KEY_h],
|
|
||||||
[KeySyms::KEY_Right, KeySyms::KEY_j],
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
fn insert_binding(
|
|
||||||
key_bindings: &mut HashMap<KeyPattern, Action>,
|
|
||||||
modifiers: KeyModifiers,
|
|
||||||
keys: impl Iterator<Item = u32>,
|
|
||||||
action: Action,
|
|
||||||
) {
|
|
||||||
if !key_bindings.values().any(|a| a == &action) {
|
|
||||||
for key in keys {
|
|
||||||
let pattern = KeyPattern {
|
|
||||||
modifiers: modifiers.clone(),
|
|
||||||
key,
|
|
||||||
};
|
|
||||||
if !key_bindings.contains_key(&pattern) {
|
|
||||||
key_bindings.insert(pattern, action.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
insert_binding(
|
|
||||||
&mut config.key_bindings,
|
&mut config.key_bindings,
|
||||||
KeyModifiers {
|
config.workspace_layout,
|
||||||
logo: true,
|
|
||||||
ctrl: true,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
workspace_previous.iter().copied(),
|
|
||||||
Action::PreviousWorkspace,
|
|
||||||
);
|
|
||||||
insert_binding(
|
|
||||||
&mut config.key_bindings,
|
|
||||||
KeyModifiers {
|
|
||||||
logo: true,
|
|
||||||
ctrl: true,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
workspace_next.iter().copied(),
|
|
||||||
Action::NextWorkspace,
|
|
||||||
);
|
|
||||||
insert_binding(
|
|
||||||
&mut config.key_bindings,
|
|
||||||
KeyModifiers {
|
|
||||||
logo: true,
|
|
||||||
ctrl: true,
|
|
||||||
shift: true,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
workspace_previous.iter().copied(),
|
|
||||||
Action::MoveToPreviousWorkspace,
|
|
||||||
);
|
|
||||||
insert_binding(
|
|
||||||
&mut config.key_bindings,
|
|
||||||
KeyModifiers {
|
|
||||||
logo: true,
|
|
||||||
ctrl: true,
|
|
||||||
shift: true,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
workspace_next.iter().copied(),
|
|
||||||
Action::MoveToNextWorkspace,
|
|
||||||
);
|
|
||||||
|
|
||||||
insert_binding(
|
|
||||||
&mut config.key_bindings,
|
|
||||||
KeyModifiers {
|
|
||||||
logo: true,
|
|
||||||
ctrl: true,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
output_previous.iter().copied(),
|
|
||||||
Action::PreviousOutput,
|
|
||||||
);
|
|
||||||
insert_binding(
|
|
||||||
&mut config.key_bindings,
|
|
||||||
KeyModifiers {
|
|
||||||
logo: true,
|
|
||||||
ctrl: true,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
output_next.iter().copied(),
|
|
||||||
Action::NextOutput,
|
|
||||||
);
|
|
||||||
insert_binding(
|
|
||||||
&mut config.key_bindings,
|
|
||||||
KeyModifiers {
|
|
||||||
logo: true,
|
|
||||||
ctrl: true,
|
|
||||||
shift: true,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
output_previous.iter().copied(),
|
|
||||||
Action::MoveToPreviousOutput,
|
|
||||||
);
|
|
||||||
insert_binding(
|
|
||||||
&mut config.key_bindings,
|
|
||||||
KeyModifiers {
|
|
||||||
logo: true,
|
|
||||||
ctrl: true,
|
|
||||||
shift: true,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
output_next.iter().copied(),
|
|
||||||
Action::MoveToNextOutput,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
|
|
@ -388,12 +229,8 @@ impl Config {
|
||||||
xdg.and_then(|base| base.place_state_file("cosmic-comp/outputs.ron").ok());
|
xdg.and_then(|base| base.place_state_file("cosmic-comp/outputs.ron").ok());
|
||||||
let outputs = Self::load_outputs(&output_path);
|
let outputs = Self::load_outputs(&output_path);
|
||||||
|
|
||||||
let input_path = xdg.and_then(|base| base.place_state_file("cosmic-comp/inputs.ron").ok());
|
|
||||||
let inputs = Self::load_inputs(&input_path);
|
|
||||||
|
|
||||||
DynamicConfig {
|
DynamicConfig {
|
||||||
outputs: (output_path, outputs),
|
outputs: (output_path, outputs),
|
||||||
inputs: (input_path, inputs),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -417,27 +254,6 @@ impl Config {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_inputs(path: &Option<PathBuf>) -> InputsConfig {
|
|
||||||
if let Some(path) = path.as_ref() {
|
|
||||||
if path.exists() {
|
|
||||||
match ron::de::from_reader(OpenOptions::new().read(true).open(path).unwrap()) {
|
|
||||||
Ok(config) => return config,
|
|
||||||
Err(err) => {
|
|
||||||
warn!(?err, "Failed to read input_config, resetting..");
|
|
||||||
if let Err(err) = std::fs::remove_file(path) {
|
|
||||||
error!(?err, "Failed to remove input_config.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
InputsConfig {
|
|
||||||
xkb: XkbConfig::default(),
|
|
||||||
devices: HashMap::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read_outputs(
|
pub fn read_outputs(
|
||||||
&mut self,
|
&mut self,
|
||||||
output_state: &mut OutputConfigurationState<State>,
|
output_state: &mut OutputConfigurationState<State>,
|
||||||
|
|
@ -592,258 +408,17 @@ impl Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn xkb_config(&self) -> XkbConfig {
|
pub fn xkb_config(&self) -> XkbConfig {
|
||||||
self.dynamic_conf.inputs().xkb.clone()
|
self.xkb.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_device(&mut self, device: &mut InputDevice) {
|
pub fn read_device(&self, device: &mut InputDevice) {
|
||||||
use std::collections::hash_map::Entry;
|
let default_config = if device.config_tap_finger_count() > 0 {
|
||||||
|
&self.input_touchpad
|
||||||
let mut inputs = self.dynamic_conf.inputs_mut();
|
} else {
|
||||||
match inputs.devices.entry(device.name().into()) {
|
&self.input_default
|
||||||
Entry::Occupied(entry) => {
|
};
|
||||||
let config = entry.get();
|
let device_config = self.input_devices.get(device.name());
|
||||||
if let Err(err) = match config.state {
|
input_config::update_device(device, device_config, default_config);
|
||||||
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 {:?}.",
|
|
||||||
config.state,
|
|
||||||
device.name(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if let Some(accel) = config.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.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.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(dwt) = config.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.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.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.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.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) = config.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(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Entry::Vacant(entry) => {
|
|
||||||
entry.insert(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
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -892,168 +467,67 @@ impl DynamicConfig {
|
||||||
pub fn outputs_mut<'a>(&'a mut self) -> PersistenceGuard<'a, OutputsConfig> {
|
pub fn outputs_mut<'a>(&'a mut self) -> PersistenceGuard<'a, OutputsConfig> {
|
||||||
PersistenceGuard(self.outputs.0.clone(), &mut self.outputs.1)
|
PersistenceGuard(self.outputs.0.clone(), &mut self.outputs.1)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn inputs(&self) -> &InputsConfig {
|
|
||||||
&self.inputs.1
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn inputs_mut<'a>(&'a mut self) -> PersistenceGuard<'a, InputsConfig> {
|
|
||||||
PersistenceGuard(self.inputs.0.clone(), &mut self.inputs.1)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
|
fn get_config<T: Default + serde::de::DeserializeOwned>(
|
||||||
pub enum KeyModifier {
|
config: &cosmic_config::Config,
|
||||||
Ctrl,
|
key: &str,
|
||||||
Alt,
|
) -> T {
|
||||||
Shift,
|
config.get(key).unwrap_or_else(|err| {
|
||||||
Super,
|
error!(?err, "Failed to read config '{}'", key);
|
||||||
|
T::default()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
|
fn update_input(state: &mut State) {
|
||||||
pub struct KeyModifiers {
|
if let BackendData::Kms(ref mut kms_state) = &mut state.backend {
|
||||||
pub ctrl: bool,
|
for device in kms_state.input_devices.values_mut() {
|
||||||
pub alt: bool,
|
state.common.config.read_device(device);
|
||||||
pub shift: bool,
|
|
||||||
pub logo: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq<ModifiersState> for KeyModifiers {
|
|
||||||
fn eq(&self, other: &ModifiersState) -> bool {
|
|
||||||
self.ctrl == other.ctrl
|
|
||||||
&& self.alt == other.alt
|
|
||||||
&& self.shift == other.shift
|
|
||||||
&& self.logo == other.logo
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<KeyModifiers> for ModifiersState {
|
|
||||||
fn into(self) -> KeyModifiers {
|
|
||||||
KeyModifiers {
|
|
||||||
ctrl: self.ctrl,
|
|
||||||
alt: self.alt,
|
|
||||||
shift: self.shift,
|
|
||||||
logo: self.logo,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::ops::AddAssign<KeyModifier> for KeyModifiers {
|
fn config_changed(config: cosmic_config::Config, keys: Vec<String>, state: &mut State) {
|
||||||
fn add_assign(&mut self, rhs: KeyModifier) {
|
for key in &keys {
|
||||||
match rhs {
|
match key.as_str() {
|
||||||
KeyModifier::Ctrl => self.ctrl = true,
|
"xkb-config" => {
|
||||||
KeyModifier::Alt => self.alt = true,
|
let value = get_config::<XkbConfig>(&config, "xkb-config");
|
||||||
KeyModifier::Shift => self.shift = true,
|
for seat in state.common.seats().cloned().collect::<Vec<_>>().iter() {
|
||||||
KeyModifier::Super => self.logo = true,
|
if let Some(keyboard) = seat.get_keyboard() {
|
||||||
};
|
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?
|
||||||
|
}
|
||||||
impl std::ops::BitOr for KeyModifier {
|
}
|
||||||
type Output = KeyModifiers;
|
}
|
||||||
|
state.common.config.xkb = value;
|
||||||
fn bitor(self, rhs: KeyModifier) -> Self::Output {
|
}
|
||||||
let mut modifiers = self.into();
|
"input-default" => {
|
||||||
modifiers += rhs;
|
let value = get_config::<InputConfig>(&config, "input-default");
|
||||||
modifiers
|
state.common.config.input_default = value;
|
||||||
}
|
update_input(state);
|
||||||
}
|
}
|
||||||
|
"input-touchpad" => {
|
||||||
impl Into<KeyModifiers> for KeyModifier {
|
let value = get_config::<InputConfig>(&config, "input-touchpad");
|
||||||
fn into(self) -> KeyModifiers {
|
state.common.config.input_touchpad = value;
|
||||||
let mut modifiers = KeyModifiers {
|
update_input(state);
|
||||||
ctrl: false,
|
}
|
||||||
alt: false,
|
"input-devices" => {
|
||||||
shift: false,
|
let value = get_config::<HashMap<String, InputConfig>>(&config, "input-devices");
|
||||||
logo: false,
|
state.common.config.input_devices = value;
|
||||||
};
|
update_input(state);
|
||||||
modifiers += self;
|
}
|
||||||
modifiers
|
_ => {}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Describtion of a key combination that might be
|
|
||||||
/// handled by the compositor.
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Hash)]
|
|
||||||
#[serde(deny_unknown_fields)]
|
|
||||||
pub struct KeyPattern {
|
|
||||||
/// What modifiers are expected to be pressed alongside the key
|
|
||||||
#[serde(deserialize_with = "deserialize_KeyModifiers")]
|
|
||||||
pub modifiers: KeyModifiers,
|
|
||||||
/// The actual key, that was pressed
|
|
||||||
#[serde(deserialize_with = "deserialize_Keysym")]
|
|
||||||
pub key: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl KeyPattern {
|
|
||||||
pub fn new(modifiers: impl Into<KeyModifiers>, key: u32) -> KeyPattern {
|
|
||||||
KeyPattern {
|
|
||||||
modifiers: modifiers.into(),
|
|
||||||
key,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for KeyPattern {
|
pub fn xkb_config_to_wl(config: &XkbConfig) -> WlXkbConfig<'_> {
|
||||||
fn to_string(&self) -> String {
|
WlXkbConfig {
|
||||||
let mut result = String::new();
|
rules: &config.rules,
|
||||||
if self.modifiers.logo {
|
model: &config.model,
|
||||||
result += "Super+";
|
layout: &config.layout,
|
||||||
}
|
variant: &config.variant,
|
||||||
if self.modifiers.ctrl {
|
options: config.options.clone(),
|
||||||
result += "Ctrl+";
|
|
||||||
}
|
|
||||||
if self.modifiers.alt {
|
|
||||||
result += "Alt+";
|
|
||||||
}
|
|
||||||
if self.modifiers.shift {
|
|
||||||
result += "Shift+";
|
|
||||||
}
|
|
||||||
result += &keysym_get_name(self.key);
|
|
||||||
result
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Clone, PartialEq, Eq)]
|
|
||||||
pub enum Action {
|
|
||||||
Terminate,
|
|
||||||
Debug,
|
|
||||||
Close,
|
|
||||||
|
|
||||||
Workspace(u8),
|
|
||||||
NextWorkspace,
|
|
||||||
PreviousWorkspace,
|
|
||||||
LastWorkspace,
|
|
||||||
MoveToWorkspace(u8),
|
|
||||||
MoveToNextWorkspace,
|
|
||||||
MoveToPreviousWorkspace,
|
|
||||||
MoveToLastWorkspace,
|
|
||||||
SendToWorkspace(u8),
|
|
||||||
SendToNextWorkspace,
|
|
||||||
SendToPreviousWorkspace,
|
|
||||||
SendToLastWorkspace,
|
|
||||||
|
|
||||||
NextOutput,
|
|
||||||
PreviousOutput,
|
|
||||||
MoveToNextOutput,
|
|
||||||
MoveToPreviousOutput,
|
|
||||||
SendToNextOutput,
|
|
||||||
SendToPreviousOutput,
|
|
||||||
|
|
||||||
Focus(FocusDirection),
|
|
||||||
Move(Direction),
|
|
||||||
|
|
||||||
ToggleOrientation,
|
|
||||||
Orientation(crate::shell::layout::Orientation),
|
|
||||||
|
|
||||||
ToggleStacking,
|
|
||||||
|
|
||||||
ToggleTiling,
|
|
||||||
ToggleWindowFloating,
|
|
||||||
|
|
||||||
Resizing(ResizeDirection),
|
|
||||||
#[serde(skip)]
|
|
||||||
_ResizingInternal(ResizeDirection, ResizeEdge, KeyState),
|
|
||||||
Maximize,
|
|
||||||
Spawn(String),
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -13,147 +13,6 @@ pub use smithay::{
|
||||||
use tracing::warn;
|
use tracing::warn;
|
||||||
use xkbcommon::xkb;
|
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<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
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<WlXkbConfig<'a>> 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<Option<ClickMethodOrig>, 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<S>(arg: &Option<ClickMethodOrig>, ser: S) -> Result<S::Ok, S::Error>
|
|
||||||
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<Option<AccelProfileOrig>, 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<S>(arg: &Option<AccelProfileOrig>, ser: S) -> Result<S::Ok, S::Error>
|
|
||||||
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<Option<ScrollMethodOrig>, 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<S>(arg: &Option<ScrollMethodOrig>, ser: S) -> Result<S::Ok, S::Error>
|
|
||||||
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)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(remote = "Transform")]
|
#[serde(remote = "Transform")]
|
||||||
pub enum TransformDef {
|
pub enum TransformDef {
|
||||||
|
|
@ -167,40 +26,6 @@ pub enum TransformDef {
|
||||||
Flipped270,
|
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<Option<TapButtonMapOrig>, 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<S>(arg: &Option<TapButtonMapOrig>, ser: S) -> Result<S::Ok, S::Error>
|
|
||||||
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)]
|
#[derive(Deserialize)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct KeyModifiersDef(Vec<KeyModifier>);
|
pub struct KeyModifiersDef(Vec<KeyModifier>);
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::render::cursor::CursorState,
|
backend::render::cursor::CursorState,
|
||||||
config::{Action, Config, KeyPattern, WorkspaceLayout},
|
config::{xkb_config_to_wl, Action, Config, KeyPattern, WorkspaceLayout},
|
||||||
shell::{
|
shell::{
|
||||||
focus::{target::PointerFocusTarget, FocusDirection},
|
focus::{target::PointerFocusTarget, FocusDirection},
|
||||||
grabs::{ResizeEdge, SeatMoveGrabState},
|
grabs::{ResizeEdge, SeatMoveGrabState},
|
||||||
|
|
@ -153,7 +153,7 @@ pub fn add_seat(
|
||||||
// So instead of doing the right thing (and initialize these capabilities as matching
|
// 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.
|
// devices appear), we have to surrender to reality and just always expose a keyboard and pointer.
|
||||||
let conf = config.xkb_config();
|
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!(
|
warn!(
|
||||||
?err,
|
?err,
|
||||||
"Failed to load provided xkb config. Trying default...",
|
"Failed to load provided xkb config. Trying default...",
|
||||||
|
|
|
||||||
|
|
@ -278,7 +278,7 @@ impl State {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let clock = Clock::new().expect("Failed to initialize clock");
|
let clock = Clock::new().expect("Failed to initialize clock");
|
||||||
let config = Config::load();
|
let config = Config::load(&handle);
|
||||||
let compositor_state = CompositorState::new::<Self>(dh);
|
let compositor_state = CompositorState::new::<Self>(dh);
|
||||||
let data_device_state = DataDeviceState::new::<Self>(dh);
|
let data_device_state = DataDeviceState::new::<Self>(dh);
|
||||||
let dmabuf_state = DmabufState::new();
|
let dmabuf_state = DmabufState::new();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue