mirror of https://github.com/wayvr-org/wayvr.git
223 lines
7.2 KiB
Rust
223 lines
7.2 KiB
Rust
use config::{Config, File};
|
|
use log::error;
|
|
use serde::{Deserialize, Serialize};
|
|
use std::path::PathBuf;
|
|
use wlx_common::{
|
|
astr_containers::AStrMap,
|
|
config::{GeneralConfig, SerializedWindowSet, SerializedWindowStates},
|
|
config_io,
|
|
overlays::BackendAttribValue,
|
|
};
|
|
|
|
const FALLBACKS: [&str; 2] = [
|
|
include_str!("res/keyboard.yaml"),
|
|
include_str!("res/wayvr.yaml"),
|
|
];
|
|
|
|
const FILES: [&str; 2] = ["keyboard.yaml", "wayvr.yaml"];
|
|
|
|
#[derive(Clone, Copy)]
|
|
#[repr(usize)]
|
|
pub enum ConfigType {
|
|
Keyboard,
|
|
Watch,
|
|
Settings,
|
|
Anchor,
|
|
#[allow(dead_code)]
|
|
WayVR,
|
|
}
|
|
|
|
pub fn load_known_yaml<T>(config_type: ConfigType) -> T
|
|
where
|
|
T: for<'de> Deserialize<'de>,
|
|
{
|
|
let fallback = FALLBACKS[config_type as usize];
|
|
let file_name = FILES[config_type as usize];
|
|
let maybe_override = config_io::load(file_name);
|
|
|
|
for yaml in [maybe_override.as_deref(), Some(fallback)].iter().flatten() {
|
|
match serde_yaml::from_str::<T>(yaml) {
|
|
Ok(d) => return d,
|
|
Err(e) => {
|
|
error!("Failed to parse {file_name}, falling back to defaults.");
|
|
error!("{e}");
|
|
}
|
|
}
|
|
}
|
|
// can only get here if internal fallback is broken
|
|
panic!("No usable config found.");
|
|
}
|
|
|
|
pub fn load_config_with_conf_d<ConfigData>(
|
|
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 = ctype.get_conf_d_path();
|
|
|
|
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));
|
|
}
|
|
}
|
|
|
|
if let Ok(paths_unsorted) = std::fs::read_dir(path_conf_d) {
|
|
let mut paths: Vec<_> = paths_unsorted
|
|
.filter_map(|r| match r {
|
|
Ok(entry) => Some(entry),
|
|
Err(e) => {
|
|
error!("Failed to read conf.d directory: {e}");
|
|
None
|
|
}
|
|
})
|
|
.collect();
|
|
// Sort paths alphabetically
|
|
paths.sort_by_key(std::fs::DirEntry::path);
|
|
for path in paths {
|
|
log::info!("Loading config file: {}", path.path().to_string_lossy());
|
|
settings_builder = settings_builder.add_source(File::from(path.path()));
|
|
}
|
|
}
|
|
|
|
match settings_builder.build() {
|
|
Ok(settings) => match settings.try_deserialize::<ConfigData>() {
|
|
Ok(config) => config,
|
|
Err(e) => {
|
|
panic!("Failed to deserialize settings: {e}");
|
|
}
|
|
},
|
|
Err(e) => {
|
|
panic!("Failed to build settings: {e}");
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn load_general_config() -> GeneralConfig {
|
|
load_config_with_conf_d::<GeneralConfig>("config.yaml", config_io::ConfigRoot::Generic)
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
pub struct AutoSettings {
|
|
pub animation_speed: f32,
|
|
pub round_multiplier: f32,
|
|
pub click_freeze_time_ms: i32,
|
|
pub invert_scroll_direction_x: bool,
|
|
pub invert_scroll_direction_y: bool,
|
|
pub scroll_speed: f32,
|
|
pub long_press_duration: f32,
|
|
pub notifications_enabled: bool,
|
|
pub notifications_sound_enabled: bool,
|
|
pub keyboard_sound_enabled: bool,
|
|
pub upright_screen_fix: bool,
|
|
pub double_cursor_fix: bool,
|
|
pub sets_on_watch: bool,
|
|
pub hide_grab_help: bool,
|
|
pub xr_click_sensitivity: f32,
|
|
pub xr_click_sensitivity_release: f32,
|
|
pub allow_sliding: bool,
|
|
pub focus_follows_mouse_mode: bool,
|
|
pub left_handed_mouse: bool,
|
|
pub block_game_input: bool,
|
|
pub block_game_input_ignore_watch: bool,
|
|
pub space_drag_multiplier: f32,
|
|
pub use_skybox: bool,
|
|
pub use_passthrough: bool,
|
|
pub screen_render_down: bool,
|
|
pub pointer_lerp_factor: f32,
|
|
pub space_drag_unlocked: bool,
|
|
pub space_rotate_unlocked: bool,
|
|
pub clock_12h: bool,
|
|
pub hide_username: bool,
|
|
pub opaque_background: bool,
|
|
pub xwayland_by_default: bool,
|
|
pub context_menu_hold_and_release: bool,
|
|
}
|
|
|
|
fn get_settings_path() -> PathBuf {
|
|
config_io::ConfigRoot::Generic
|
|
.get_conf_d_path()
|
|
.join("zz-saved-config.json5")
|
|
}
|
|
|
|
pub fn save_settings(config: &GeneralConfig) -> anyhow::Result<()> {
|
|
let conf = AutoSettings {
|
|
animation_speed: config.animation_speed,
|
|
round_multiplier: config.round_multiplier,
|
|
click_freeze_time_ms: config.click_freeze_time_ms,
|
|
invert_scroll_direction_x: config.invert_scroll_direction_x,
|
|
invert_scroll_direction_y: config.invert_scroll_direction_y,
|
|
scroll_speed: config.scroll_speed,
|
|
long_press_duration: config.long_press_duration,
|
|
notifications_enabled: config.notifications_enabled,
|
|
notifications_sound_enabled: config.notifications_sound_enabled,
|
|
keyboard_sound_enabled: config.keyboard_sound_enabled,
|
|
upright_screen_fix: config.upright_screen_fix,
|
|
double_cursor_fix: config.double_cursor_fix,
|
|
sets_on_watch: config.sets_on_watch,
|
|
hide_grab_help: config.hide_grab_help,
|
|
xr_click_sensitivity: config.xr_click_sensitivity,
|
|
xr_click_sensitivity_release: config.xr_click_sensitivity_release,
|
|
allow_sliding: config.allow_sliding,
|
|
focus_follows_mouse_mode: config.focus_follows_mouse_mode,
|
|
left_handed_mouse: config.left_handed_mouse,
|
|
block_game_input: config.block_game_input,
|
|
block_game_input_ignore_watch: config.block_game_input_ignore_watch,
|
|
space_drag_multiplier: config.space_drag_multiplier,
|
|
use_skybox: config.use_skybox,
|
|
use_passthrough: config.use_passthrough,
|
|
screen_render_down: config.screen_render_down,
|
|
pointer_lerp_factor: config.pointer_lerp_factor,
|
|
space_drag_unlocked: config.space_drag_unlocked,
|
|
space_rotate_unlocked: config.space_rotate_unlocked,
|
|
clock_12h: config.clock_12h,
|
|
hide_username: config.hide_username,
|
|
opaque_background: config.opaque_background,
|
|
xwayland_by_default: config.xwayland_by_default,
|
|
context_menu_hold_and_release: config.context_menu_hold_and_release,
|
|
};
|
|
|
|
let json = serde_json::to_string_pretty(&conf).unwrap(); // want panic
|
|
std::fs::write(get_settings_path(), json)?;
|
|
|
|
log::info!("Saved settings.");
|
|
Ok(())
|
|
}
|
|
|
|
// Config that is saved after manipulating overlays
|
|
|
|
#[derive(Serialize)]
|
|
pub struct AutoState {
|
|
pub sets: Vec<SerializedWindowSet>,
|
|
pub global_set: SerializedWindowStates,
|
|
pub last_set: u32,
|
|
pub attribs: AStrMap<Vec<BackendAttribValue>>,
|
|
}
|
|
|
|
fn get_state_path() -> PathBuf {
|
|
config_io::ConfigRoot::Generic
|
|
.get_conf_d_path()
|
|
.join("zz-saved-state.json5")
|
|
}
|
|
|
|
pub fn save_state(config: &GeneralConfig) -> anyhow::Result<()> {
|
|
let conf = AutoState {
|
|
sets: config.sets.clone(),
|
|
last_set: config.last_set,
|
|
global_set: config.global_set.clone(),
|
|
attribs: config.attribs.clone(),
|
|
};
|
|
|
|
let json = serde_json::to_string_pretty(&conf).unwrap(); // want panic
|
|
std::fs::write(get_state_path(), json)?;
|
|
|
|
log::info!("State was saved successfully.");
|
|
Ok(())
|
|
}
|