From 0f5d654535d0a7308443f40302801caaac02ba1a Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Fri, 28 Jul 2023 12:54:02 -0700 Subject: [PATCH] Use `cosmic-config` for input configuration; allow dynamic changes --- Cargo.lock | 31 +++++++------ Cargo.toml | 5 +- src/backend/kms/mod.rs | 13 +++++- src/config/mod.rs | 103 +++++++++++++++++++++++++---------------- src/state.rs | 2 +- 5 files changed, 94 insertions(+), 60 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 75fe423d..e51b8f51 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -481,6 +481,7 @@ dependencies = [ "bitflags 1.3.2", "bytemuck", "calloop", + "cosmic-config", "cosmic-protocols", "edid-rs", "egui", @@ -524,9 +525,10 @@ dependencies = [ [[package]] name = "cosmic-config" 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 = [ "atomicwrites", + "calloop", "cosmic-config-derive", "dirs 5.0.1", "iced_futures", @@ -538,7 +540,7 @@ dependencies = [ [[package]] name = "cosmic-config-derive" 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 = [ "quote", "syn 1.0.109", @@ -578,7 +580,7 @@ dependencies = [ [[package]] name = "cosmic-theme" 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 = [ "anyhow", "cosmic-config", @@ -1746,7 +1748,7 @@ dependencies = [ [[package]] name = "iced" 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 = [ "iced_core", "iced_futures", @@ -1759,7 +1761,7 @@ dependencies = [ [[package]] name = "iced_core" 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 = [ "bitflags 1.3.2", "instant", @@ -1772,7 +1774,7 @@ dependencies = [ [[package]] name = "iced_futures" 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 = [ "futures", "iced_core", @@ -1784,7 +1786,7 @@ dependencies = [ [[package]] name = "iced_graphics" 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 = [ "bitflags 1.3.2", "bytemuck", @@ -1801,7 +1803,7 @@ dependencies = [ [[package]] name = "iced_renderer" 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 = [ "iced_graphics", "iced_tiny_skia", @@ -1813,7 +1815,7 @@ dependencies = [ [[package]] name = "iced_runtime" 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 = [ "iced_core", "iced_futures", @@ -1823,7 +1825,7 @@ dependencies = [ [[package]] name = "iced_style" 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 = [ "iced_core", "once_cell", @@ -1833,7 +1835,7 @@ dependencies = [ [[package]] name = "iced_tiny_skia" 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 = [ "bytemuck", "cosmic-text", @@ -1851,7 +1853,7 @@ dependencies = [ [[package]] name = "iced_wgpu" 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 = [ "bitflags 1.3.2", "bytemuck", @@ -1872,7 +1874,7 @@ dependencies = [ [[package]] name = "iced_widget" 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 = [ "iced_renderer", "iced_runtime", @@ -2167,7 +2169,7 @@ checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "libcosmic" 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 = [ "apply", "cosmic-config", @@ -2186,6 +2188,7 @@ dependencies = [ "lazy_static", "palette", "slotmap", + "thiserror", "tracing", ] diff --git a/Cargo.toml b/Cargo.toml index a5890a3c..495b9459 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,9 +30,10 @@ ron = "0.7" libsystemd = { version = "0.5", optional = true } wayland-backend = "0.1.0" wayland-scanner = "0.30.0" +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 = "42d7baf", default-features = false } -iced_tiny_skia = { git = "https://github.com/pop-os/libcosmic/", rev = "42d7baf" } +libcosmic = { git = "https://github.com/pop-os/libcosmic/", rev = "4895b0c", default-features = false } +iced_tiny_skia = { git = "https://github.com/pop-os/libcosmic/", rev = "4895b0c" } tiny-skia = "0.9" ordered-float = "3.0" glow = "0.11.2" diff --git a/src/backend/kms/mod.rs b/src/backend/kms/mod.rs index 13026233..305baeb5 100644 --- a/src/backend/kms/mod.rs +++ b/src/backend/kms/mod.rs @@ -57,7 +57,7 @@ use smithay::{ control::{connector, crtc, Device as ControlDevice, ModeTypeFlags}, Device as _, }, - input::Libinput, + input::{self, Libinput}, nix::{fcntl::OFlag, sys::stat::dev_t}, wayland_protocols::wp::{ linux_dmabuf::zv1::server::zwp_linux_dmabuf_feedback_v1, @@ -97,6 +97,7 @@ const MIN_RENDER_TIME: Duration = Duration::from_millis(3); #[derive(Debug)] pub struct KmsState { devices: HashMap, + pub input_devices: HashMap, pub api: GpuManager>, pub primary: DrmNode, session: LibSeatSession, @@ -172,8 +173,15 @@ pub fn init_backend( let libinput_event_source = event_loop .handle() .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 + .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); for output in data.state.common.shell.outputs() { @@ -363,6 +371,7 @@ pub fn init_backend( primary, session, devices: HashMap::new(), + input_devices: HashMap::new(), }); // Create relative pointer global diff --git a/src/config/mod.rs b/src/config/mod.rs index 832724a9..81dd8da4 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -5,6 +5,7 @@ use crate::{ state::{BackendData, Data, State}, wayland::protocols::output_configuration::OutputConfigurationState, }; +use cosmic_config::{ConfigGet, ConfigSet}; use serde::{Deserialize, Serialize}; use smithay::input::Seat; pub use smithay::{ @@ -34,6 +35,9 @@ pub use self::types::*; pub struct Config { pub static_conf: StaticConfig, pub dynamic_conf: DynamicConfig, + pub config: cosmic_config::Config, + pub xkb: XkbConfig, + pub input_devices: HashMap, } #[derive(Debug, Deserialize)] @@ -65,7 +69,6 @@ pub enum WorkspaceLayout { #[derive(Debug)] pub struct DynamicConfig { outputs: (Option, OutputsConfig), - inputs: (Option, InputsConfig), } #[derive(Debug, Deserialize, Serialize)] @@ -152,18 +155,22 @@ impl OutputConfig { } } -#[derive(Debug, Deserialize, Serialize)] -pub struct InputsConfig { - xkb: XkbConfig, - devices: HashMap, -} - 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(); Config { static_conf: Self::load_static(xdg.as_ref()), dynamic_conf: Self::load_dynamic(xdg.as_ref()), + xkb: get_config(&config, "xkb-config"), + input_devices: get_config(&config, "input-devices"), + config, } } @@ -218,12 +225,8 @@ impl Config { xdg.and_then(|base| base.place_state_file("cosmic-comp/outputs.ron").ok()); 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 { outputs: (output_path, outputs), - inputs: (input_path, inputs), } } @@ -247,27 +250,6 @@ impl Config { } } - fn load_inputs(path: &Option) -> 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( &mut self, output_state: &mut OutputConfigurationState, @@ -422,17 +404,23 @@ impl Config { } pub fn xkb_config(&self) -> XkbConfig { - self.dynamic_conf.inputs().xkb.clone() + self.xkb.clone() } pub fn read_device(&mut self, device: &mut InputDevice) { use std::collections::hash_map::Entry; - let mut inputs = self.dynamic_conf.inputs_mut(); - match inputs.devices.entry(device.name().into()) { + 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'"); } } } @@ -483,12 +471,45 @@ impl DynamicConfig { pub fn outputs_mut<'a>(&'a mut self) -> PersistenceGuard<'a, OutputsConfig> { PersistenceGuard(self.outputs.0.clone(), &mut self.outputs.1) } +} - pub fn inputs(&self) -> &InputsConfig { - &self.inputs.1 - } +fn get_config( + config: &cosmic_config::Config, + key: &str, +) -> T { + config.get(key).unwrap_or_else(|err| { + error!(?err, "Failed to read config '{}'", key); + T::default() + }) +} - pub fn inputs_mut<'a>(&'a mut self) -> PersistenceGuard<'a, InputsConfig> { - PersistenceGuard(self.inputs.0.clone(), &mut self.inputs.1) +fn config_changed(config: cosmic_config::Config, keys: Vec, state: &mut State) { + for key in &keys { + match key.as_str() { + "xkb-config" => { + 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()) { + error!(?err, "Failed to load provided xkb config"); + // TODO Revert to default? + } + } + } + state.common.config.xkb = value; + } + "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; + } + _ => {} + } } } diff --git a/src/state.rs b/src/state.rs index 8ba5ff4f..f1d1740e 100644 --- a/src/state.rs +++ b/src/state.rs @@ -278,7 +278,7 @@ impl State { .unwrap(); let clock = Clock::new().expect("Failed to initialize clock"); - let config = Config::load(); + let config = Config::load(&handle); let compositor_state = CompositorState::new::(dh); let data_device_state = DataDeviceState::new::(dh); let dmabuf_state = DmabufState::new();