From 3c792608e74ce163d661a688fb81818447e32ae2 Mon Sep 17 00:00:00 2001 From: Aleksander Date: Mon, 20 Jan 2025 15:26:17 +0100 Subject: [PATCH] config_io: Support `wayvr.conf.d` directory, refactoring (#139) --- src/backend/openvr/input.rs | 10 +++---- src/backend/openvr/manifest.rs | 6 ++-- src/backend/openxr/skybox.rs | 4 +-- src/config.rs | 35 ++++++++++++++--------- src/config_io.rs | 52 ++++++++++++++++++++-------------- src/config_wayvr.rs | 15 ++++++++-- src/gui/modular/mod.rs | 4 +-- src/overlays/screen.rs | 2 +- src/overlays/wayvr.rs | 8 +++++- src/state.rs | 4 +-- 10 files changed, 86 insertions(+), 54 deletions(-) diff --git a/src/backend/openvr/input.rs b/src/backend/openvr/input.rs index 9b549d8..bebcb6f 100644 --- a/src/backend/openvr/input.rs +++ b/src/backend/openvr/input.rs @@ -13,7 +13,7 @@ use ovr_overlay::{ use crate::{ backend::input::{Haptics, TrackedDevice, TrackedDeviceRole}, - config_io::CONFIG_ROOT_PATH, + config_io, state::AppState, }; @@ -325,7 +325,7 @@ fn get_tracked_device( } pub fn set_action_manifest(input: &mut InputManager) -> anyhow::Result<()> { - let action_path = CONFIG_ROOT_PATH.join("actions.json"); + let action_path = config_io::get_config_root().join("actions.json"); if let Err(e) = File::create(&action_path) .and_then(|mut f| f.write_all(include_bytes!("../../res/actions.json"))) @@ -333,19 +333,19 @@ pub fn set_action_manifest(input: &mut InputManager) -> anyhow::Result<()> { log::warn!("Could not write action manifest: {}", e); } - let binding_path = CONFIG_ROOT_PATH.join("actions_binding_knuckles.json"); + let binding_path = config_io::get_config_root().join("actions_binding_knuckles.json"); if !binding_path.is_file() { File::create(&binding_path)? .write_all(include_bytes!("../../res/actions_binding_knuckles.json"))?; } - let binding_path = CONFIG_ROOT_PATH.join("actions_binding_vive.json"); + let binding_path = config_io::get_config_root().join("actions_binding_vive.json"); if !binding_path.is_file() { File::create(&binding_path)? .write_all(include_bytes!("../../res/actions_binding_vive.json"))?; } - let binding_path = CONFIG_ROOT_PATH.join("actions_binding_oculus.json"); + let binding_path = config_io::get_config_root().join("actions_binding_oculus.json"); if !binding_path.is_file() { File::create(&binding_path)? .write_all(include_bytes!("../../res/actions_binding_oculus.json"))?; diff --git a/src/backend/openvr/manifest.rs b/src/backend/openvr/manifest.rs index 3ff40bd..a995270 100644 --- a/src/backend/openvr/manifest.rs +++ b/src/backend/openvr/manifest.rs @@ -4,12 +4,12 @@ use anyhow::bail; use json::{array, object}; use ovr_overlay::applications::ApplicationsManager; -use crate::config_io::CONFIG_ROOT_PATH; +use crate::config_io; const APP_KEY: &str = "galister.wlxoverlay-s"; pub(super) fn install_manifest(app_mgr: &mut ApplicationsManager) -> anyhow::Result<()> { - let manifest_path = CONFIG_ROOT_PATH.join("wlx-overlay-s.vrmanifest"); + let manifest_path = config_io::get_config_root().join("wlx-overlay-s.vrmanifest"); let appimage_path = std::env::var("APPIMAGE"); let executable_pathbuf = std::env::current_exe()?; @@ -76,7 +76,7 @@ pub(super) fn install_manifest(app_mgr: &mut ApplicationsManager) -> anyhow::Res } pub(super) fn uninstall_manifest(app_mgr: &mut ApplicationsManager) -> anyhow::Result<()> { - let manifest_path = CONFIG_ROOT_PATH.join("wlx-overlay-s.vrmanifest"); + let manifest_path = config_io::get_config_root().join("wlx-overlay-s.vrmanifest"); if let Ok(true) = app_mgr.is_application_installed(APP_KEY) { if let Err(e) = app_mgr.remove_application_manifest(&manifest_path) { diff --git a/src/backend/openxr/skybox.rs b/src/backend/openxr/skybox.rs index 1de439b..adaa255 100644 --- a/src/backend/openxr/skybox.rs +++ b/src/backend/openxr/skybox.rs @@ -7,7 +7,7 @@ use vulkano::{command_buffer::CommandBufferUsage, image::view::ImageView}; use crate::{ backend::openxr::{helpers::translation_rotation_to_posef, swapchain::SwapchainOpts}, - config_io::CONFIG_ROOT_PATH, + config_io, graphics::{dds::WlxCommandBufferDds, format_is_srgb, WlxCommandBuffer}, state::AppState, }; @@ -35,7 +35,7 @@ impl Skybox { break 'custom_tex; } - let real_path = CONFIG_ROOT_PATH.join(&*app.session.config.skybox_texture); + let real_path = config_io::get_config_root().join(&*app.session.config.skybox_texture); let Ok(f) = File::open(real_path) else { log::warn!( "Could not open custom skybox texture at: {}", diff --git a/src/config.rs b/src/config.rs index 07b4bd6..84ba31f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -2,8 +2,6 @@ use std::path::PathBuf; use std::sync::Arc; use crate::config_io; -use crate::config_io::get_conf_d_path; -use crate::config_io::CONFIG_ROOT_PATH; use crate::gui::modular::ModularUiConfig; use crate::overlays::toast::DisplayMethod; use crate::overlays::toast::ToastTopic; @@ -390,14 +388,20 @@ pub fn load_custom_ui(name: &str) -> anyhow::Result { Ok(serde_yaml::from_str(&yaml_data)?) } -pub fn load_general() -> GeneralConfig { +pub fn load_config_with_conf_d( + root_config_filename: &str, + ctype: config_io::ConfigRoot, +) -> ConfigData +where + ConfigData: for<'de> Deserialize<'de>, +{ let mut settings_builder = Config::builder(); // Add files from conf.d directory - let path_conf_d = get_conf_d_path(); + let path_conf_d = ctype.get_conf_d_path(); - for mut base_conf in [CONFIG_ROOT_PATH.clone(), path_conf_d.clone()] { - base_conf.push("config.yaml"); + for mut base_conf in [config_io::get_config_root(), path_conf_d.clone()] { + base_conf.push(root_config_filename); if base_conf.exists() { log::info!("Loading config file: {}", base_conf.to_string_lossy()); settings_builder = settings_builder.add_source(File::from(base_conf)); @@ -423,7 +427,7 @@ pub fn load_general() -> GeneralConfig { } match settings_builder.build() { - Ok(settings) => match settings.try_deserialize::() { + Ok(settings) => match settings.try_deserialize::() { Ok(config) => config, Err(e) => { panic!("Failed to deserialize settings: {}", e); @@ -435,6 +439,10 @@ pub fn load_general() -> GeneralConfig { } } +pub fn load_general() -> GeneralConfig { + load_config_with_conf_d::("config.yaml", config_io::ConfigRoot::Generic) +} + // Config that is saved from the settings panel #[derive(Serialize)] @@ -452,10 +460,11 @@ pub struct AutoSettings { } fn get_settings_path() -> PathBuf { - let mut path = config_io::get_conf_d_path(); - path.push("zz-saved-config.json5"); - path + config_io::ConfigRoot::Generic + .get_conf_d_path() + .join("zz-saved-config.json5") } + pub fn save_settings(config: &GeneralConfig) -> anyhow::Result<()> { let conf = AutoSettings { watch_pos: config.watch_pos, @@ -486,9 +495,9 @@ pub struct AutoState { } fn get_state_path() -> PathBuf { - let mut path = config_io::get_conf_d_path(); - path.push("zz-saved-state.json5"); - path + config_io::ConfigRoot::Generic + .get_conf_d_path() + .join("zz-saved-state.json5") } pub fn save_layout(config: &GeneralConfig) -> anyhow::Result<()> { diff --git a/src/config_io.rs b/src/config_io.rs index 92d0e6c..48cfc69 100644 --- a/src/config_io.rs +++ b/src/config_io.rs @@ -1,13 +1,16 @@ use log::error; use once_cell::sync::Lazy; -use std::{ - fs::{self, create_dir}, - path::PathBuf, -}; +use std::path::PathBuf; + +pub enum ConfigRoot { + Generic, + #[allow(dead_code)] + WayVR, +} const FALLBACK_CONFIG_PATH: &str = "/tmp/wlxoverlay"; -pub static CONFIG_ROOT_PATH: Lazy = Lazy::new(|| { +static CONFIG_ROOT_PATH: Lazy = Lazy::new(|| { if let Ok(xdg_dirs) = xdg::BaseDirectories::new() { let mut dir = xdg_dirs.get_config_home(); dir.push("wlxoverlay"); @@ -21,33 +24,38 @@ pub static CONFIG_ROOT_PATH: Lazy = Lazy::new(|| { PathBuf::from(FALLBACK_CONFIG_PATH) }); -pub fn get_conf_d_path() -> PathBuf { - let mut config_root = CONFIG_ROOT_PATH.clone(); - config_root.push("conf.d"); - config_root +pub fn get_config_root() -> PathBuf { + CONFIG_ROOT_PATH.clone() } -// Make sure config directory is present and return root config path -pub fn ensure_config_root() -> PathBuf { - let path = CONFIG_ROOT_PATH.clone(); - let _ = create_dir(&path); +impl ConfigRoot { + pub fn get_conf_d_path(&self) -> PathBuf { + get_config_root().join(match self { + ConfigRoot::Generic => "conf.d", + ConfigRoot::WayVR => "wayvr.conf.d", + }) + } - let path_conf_d = get_conf_d_path(); - let _ = create_dir(path_conf_d); - path + // Make sure config directory is present and return root config path + pub fn ensure_dir(&self) -> PathBuf { + let path = get_config_root(); + let _ = std::fs::create_dir(&path); + + let path_conf_d = self.get_conf_d_path(); + let _ = std::fs::create_dir(path_conf_d); + path + } } -fn get_config_file_path(filename: &str) -> PathBuf { - let mut config_root = CONFIG_ROOT_PATH.clone(); - config_root.push(filename); - config_root +pub fn get_config_file_path(filename: &str) -> PathBuf { + get_config_root().join(filename) } pub fn load(filename: &str) -> Option { let path = get_config_file_path(filename); - log::info!("Loading config {}", path.to_string_lossy()); + log::info!("Loading config: {}", path.to_string_lossy()); - if let Ok(data) = fs::read_to_string(path) { + if let Ok(data) = std::fs::read_to_string(path) { Some(data) } else { None diff --git a/src/config_wayvr.rs b/src/config_wayvr.rs index d113d29..1a7f508 100644 --- a/src/config_wayvr.rs +++ b/src/config_wayvr.rs @@ -16,7 +16,8 @@ use crate::{ task::{TaskContainer, TaskType}, wayvr, }, - config::{load_known_yaml, ConfigType}, + config::load_config_with_conf_d, + config_io, gui::modular::button::WayVRAction, overlays::wayvr::WayVRData, }; @@ -120,7 +121,7 @@ pub struct WayVRConfig { pub run_compositor_at_start: bool, pub catalogs: HashMap, pub displays: BTreeMap, // sorted alphabetically - pub dashboard: WayVRDashboard, + pub dashboard: Option, #[serde(default = "def_true")] pub auto_hide: bool, @@ -212,7 +213,15 @@ impl WayVRConfig { } pub fn load_wayvr() -> WayVRConfig { - let config = load_known_yaml::(ConfigType::WayVR); + let config_root_path = config_io::ConfigRoot::WayVR.ensure_dir(); + log::info!("WayVR Config root path: {:?}", config_root_path); + log::info!( + "WayVR conf.d path: {:?}", + config_io::ConfigRoot::WayVR.get_conf_d_path() + ); + + let config = load_config_with_conf_d::("wayvr.yaml", config_io::ConfigRoot::WayVR); + if config.version != 1 { panic!("WayVR config version {} is not supported", config.version); } diff --git a/src/gui/modular/mod.rs b/src/gui/modular/mod.rs index ccd2ea6..100f50e 100644 --- a/src/gui/modular/mod.rs +++ b/src/gui/modular/mod.rs @@ -11,7 +11,7 @@ use serde::Deserialize; use vulkano::{command_buffer::CommandBufferUsage, image::view::ImageView}; use crate::{ - backend::common::OverlaySelector, config::AStrMapExt, config_io::CONFIG_ROOT_PATH, + backend::common::OverlaySelector, config::AStrMapExt, config_io, graphics::dds::WlxCommandBufferDds, state::AppState, }; @@ -545,7 +545,7 @@ fn sprite_from_path(path: Arc, app: &mut AppState) -> anyhow::Result PathBuf { - let mut path = config_io::get_conf_d_path(); + let mut path = config_io::ConfigRoot::Generic.get_conf_d_path(); path.push("pw_tokens.yaml"); path } diff --git a/src/overlays/wayvr.rs b/src/overlays/wayvr.rs index 9de7c40..1de6959 100644 --- a/src/overlays/wayvr.rs +++ b/src/overlays/wayvr.rs @@ -244,6 +244,10 @@ where { let conf_dash = &app.session.wayvr_config.dashboard; + let Some(conf_dash) = &conf_dash else { + anyhow::bail!("Dashboard is not configured"); + }; + if !wayvr.dashboard_executed && !executable_exists_in_path(&conf_dash.exec) { anyhow::bail!("Executable \"{}\" not found", &conf_dash.exec); } @@ -280,7 +284,9 @@ where overlay.state.z_order = Z_ORDER_DASHBOARD; overlay.state.reset(app, true); - let conf_dash = &app.session.wayvr_config.dashboard; + let Some(conf_dash) = &app.session.wayvr_config.dashboard else { + unreachable!(); /* safe, not possible to trigger */ + }; // FIXME: overlay curvature needs to be dispatched for some unknown reason, this value is not set otherwise app.tasks.enqueue(TaskType::Overlay( diff --git a/src/state.rs b/src/state.rs index 67b268f..71ebe8a 100644 --- a/src/state.rs +++ b/src/state.rs @@ -146,8 +146,8 @@ pub struct AppSession { impl AppSession { pub fn load() -> Self { - let config_root_path = config_io::ensure_config_root(); - log::info!("Config root path: {}", config_root_path.to_string_lossy()); + let config_root_path = config_io::ConfigRoot::Generic.ensure_dir(); + log::info!("Config root path: {:?}", config_root_path); let config = GeneralConfig::load_from_disk(); let mut toast_topics = IdMap::new();