Use cosmic-config for input configuration; allow dynamic changes

This commit is contained in:
Ian Douglas Scott 2023-07-28 12:54:02 -07:00
parent 75912df270
commit 0f5d654535
5 changed files with 94 additions and 60 deletions

31
Cargo.lock generated
View file

@ -481,6 +481,7 @@ dependencies = [
"bitflags 1.3.2", "bitflags 1.3.2",
"bytemuck", "bytemuck",
"calloop", "calloop",
"cosmic-config",
"cosmic-protocols", "cosmic-protocols",
"edid-rs", "edid-rs",
"egui", "egui",
@ -524,9 +525,10 @@ dependencies = [
[[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 +540,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 +580,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 +1748,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 +1761,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 +1774,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 +1786,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 +1803,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 +1815,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 +1825,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 +1835,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 +1853,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 +1874,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",
@ -2167,7 +2169,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 +2188,7 @@ dependencies = [
"lazy_static", "lazy_static",
"palette", "palette",
"slotmap", "slotmap",
"thiserror",
"tracing", "tracing",
] ]

View file

@ -30,9 +30,10 @@ 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-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"

View file

@ -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

View file

@ -5,6 +5,7 @@ use crate::{
state::{BackendData, Data, State}, state::{BackendData, Data, State},
wayland::protocols::output_configuration::OutputConfigurationState, wayland::protocols::output_configuration::OutputConfigurationState,
}; };
use cosmic_config::{ConfigGet, ConfigSet};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use smithay::input::Seat; use smithay::input::Seat;
pub use smithay::{ pub use smithay::{
@ -34,6 +35,9 @@ pub use self::types::*;
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_devices: HashMap<String, InputConfig>,
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
@ -65,7 +69,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)]
@ -152,18 +155,22 @@ impl OutputConfig {
} }
} }
#[derive(Debug, Deserialize, Serialize)]
pub struct InputsConfig {
xkb: XkbConfig,
devices: HashMap<String, InputConfig>,
}
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_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()); 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),
} }
} }
@ -247,27 +250,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>,
@ -422,17 +404,23 @@ 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(&mut self, device: &mut InputDevice) {
use std::collections::hash_map::Entry; use std::collections::hash_map::Entry;
let mut inputs = self.dynamic_conf.inputs_mut(); let mut config_changed = false;
match inputs.devices.entry(device.name().into()) { match self.input_devices.entry(device.name().into()) {
Entry::Occupied(entry) => entry.get().update_device(device), Entry::Occupied(entry) => entry.get().update_device(device),
Entry::Vacant(entry) => { Entry::Vacant(entry) => {
entry.insert(InputConfig::for_device(device)); 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> { 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 { fn get_config<T: Default + serde::de::DeserializeOwned>(
&self.inputs.1 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> { fn config_changed(config: cosmic_config::Config, keys: Vec<String>, state: &mut State) {
PersistenceGuard(self.inputs.0.clone(), &mut self.inputs.1) for key in &keys {
match key.as_str() {
"xkb-config" => {
let value = get_config::<XkbConfig>(&config, "xkb-config");
for seat in state.common.seats().cloned().collect::<Vec<_>>().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::<HashMap<String, InputConfig>>(&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;
}
_ => {}
}
} }
} }

View file

@ -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();