diff --git a/Cargo.lock b/Cargo.lock index ce4fe65..e4931d6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4205,6 +4205,7 @@ dependencies = [ "vulkano-shaders", "winit", "wlx-capture", + "xdg", ] [[package]] @@ -4256,6 +4257,12 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a0ccd7b4a5345edfcd0c3535718a4e9ff7798ffc536bb5b5a0e26ff84732911" +[[package]] +name = "xdg" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213b7324336b53d2414b2db8537e56544d981803139155afa84f76eeebb7a546" + [[package]] name = "xdg-home" version = "1.0.0" diff --git a/Cargo.toml b/Cargo.toml index cc69ddc..581d08c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,6 +43,7 @@ vulkano = { git = "https://github.com/vulkano-rs/vulkano", rev = "94f50f1" } vulkano-shaders = { git = "https://github.com/vulkano-rs/vulkano", rev = "94f50f1" } winit = "0.29.10" wlx-capture = { git = "https://github.com/galister/wlx-capture" } +xdg = "2.5.2" [features] openvr = ["dep:ovr_overlay"] diff --git a/src/backend/input.rs b/src/backend/input.rs index 1a9b107..a1dc542 100644 --- a/src/backend/input.rs +++ b/src/backend/input.rs @@ -1,14 +1,17 @@ use std::{collections::VecDeque, time::Instant}; use glam::{Affine3A, Vec2, Vec3A}; -use ovr_overlay::TrackedDeviceIndex; use tinyvec::array_vec; +#[cfg(feature = "openvr")] +use ovr_overlay::TrackedDeviceIndex; + use crate::state::AppState; use super::{common::OverlayContainer, overlay::OverlayData}; pub struct TrackedDevice { + #[cfg(feature = "openvr")] pub index: TrackedDeviceIndex, pub valid: bool, pub soc: Option, diff --git a/src/backend/openvr/mod.rs b/src/backend/openvr/mod.rs index 2dac613..71f0726 100644 --- a/src/backend/openvr/mod.rs +++ b/src/backend/openvr/mod.rs @@ -62,7 +62,7 @@ pub fn openvr_run(running: Arc) -> Result<(), BackendError> { }; let mut state = { - let graphics = WlxGraphics::new(instance_extensions, device_extensions_fn); + let graphics = WlxGraphics::new_openvr(instance_extensions, device_extensions_fn); AppState::from_graphics(graphics) }; diff --git a/src/backend/openvr/overlay.rs b/src/backend/openvr/overlay.rs index cefbf17..572a07d 100644 --- a/src/backend/openvr/overlay.rs +++ b/src/backend/openvr/overlay.rs @@ -225,7 +225,6 @@ impl OverlayData { m_pQueue: graphics.queue.handle().as_raw() as *mut _, m_nQueueFamilyIndex: graphics.queue.queue_family_index(), }; - log::info!( "{}: UploadTex {:?}, {}x{}, {:?}", self.state.name, diff --git a/src/backend/openxr/mod.rs b/src/backend/openxr/mod.rs index de7ec28..1bb4af9 100644 --- a/src/backend/openxr/mod.rs +++ b/src/backend/openxr/mod.rs @@ -54,7 +54,7 @@ pub fn openxr_run(running: Arc) -> Result<(), BackendError> { log::info!("Using environment blend mode: {:?}", environment_blend_mode); let mut app_state = { - let graphics = WlxGraphics::new_xr(xr_instance.clone(), system); + let graphics = WlxGraphics::new_openxr(xr_instance.clone(), system); AppState::from_graphics(graphics) }; diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..42e065f --- /dev/null +++ b/src/config.rs @@ -0,0 +1,105 @@ +use crate::config_io; +use crate::config_io::get_conf_d_path; +use crate::load_with_fallback; +use crate::overlays::keyboard; +use log::error; +use serde::Deserialize; +use serde::Serialize; + +pub fn def_pw_tokens() -> Vec<(String, String)> { + Vec::new() +} + +fn def_click_freeze_time_ms() -> u32 { + 300 +} + +fn def_true() -> bool { + true +} + +fn def_one() -> f32 { + 1.0 +} + +#[derive(Deserialize, Serialize)] +pub struct GeneralConfig { + #[serde(default = "def_click_freeze_time_ms")] + pub click_freeze_time_ms: u32, + + #[serde(default = "def_true")] + pub keyboard_sound_enabled: bool, + + #[serde(default = "def_one")] + pub keyboard_scale: f32, + + #[serde(default = "def_one")] + pub desktop_view_scale: f32, + + #[serde(default = "def_one")] + pub watch_scale: f32, + + #[serde(default = "def_pw_tokens")] + pub pw_tokens: Vec<(String, String)>, +} + +impl GeneralConfig { + fn sanitize_range(name: &str, val: f32, from: f32, to: f32) { + if !val.is_normal() || val < from || val > to { + panic!( + "GeneralConfig: {} needs to be between {} and {}", + name, from, to + ); + } + } + + pub fn load_from_disk() -> GeneralConfig { + let config = load_general(); + config.post_load(); + config + } + + fn post_load(&self) { + GeneralConfig::sanitize_range("keyboard_scale", self.keyboard_scale, 0.0, 5.0); + GeneralConfig::sanitize_range("desktop_view_scale", self.desktop_view_scale, 0.0, 5.0); + GeneralConfig::sanitize_range("watch_scale", self.watch_scale, 0.0, 5.0); + } +} + +pub fn load_keyboard() -> keyboard::Layout { + let yaml_data = load_with_fallback!("keyboard.yaml", "res/keyboard.yaml"); + serde_yaml::from_str(&yaml_data).expect("Failed to parse keyboard.yaml") +} + +pub fn load_general() -> GeneralConfig { + let mut yaml_data = String::new(); + + // Add files from conf.d directory + let path_conf_d = get_conf_d_path(); + if let Ok(paths_unsorted) = std::fs::read_dir(path_conf_d) { + // Sort paths alphabetically + let mut paths: Vec<_> = paths_unsorted.map(|r| r.unwrap()).collect(); + paths.sort_by_key(|dir| dir.path()); + for path in paths { + if !path.file_type().unwrap().is_file() { + continue; + } + + println!("Loading config file {}", path.path().to_string_lossy()); + + if let Ok(data) = std::fs::read_to_string(path.path()) { + yaml_data.push('\n'); // Just in case, if end of the config file was not newline + yaml_data.push_str(data.as_str()); + } else { + // Shouldn't happen anyways + error!("Failed to load {}", path.path().to_string_lossy()); + } + } + } + + if yaml_data.is_empty() { + yaml_data.push_str(load_with_fallback!("config.yaml", "res/config.yaml").as_str()); + } + + serde_yaml::from_str(&yaml_data).expect("Failed to parse config.yaml") +} diff --git a/src/config_io.rs b/src/config_io.rs new file mode 100644 index 0000000..8a88f14 --- /dev/null +++ b/src/config_io.rs @@ -0,0 +1,71 @@ +use log::error; +use once_cell::sync::Lazy; +use std::{ + fs::{self, create_dir}, + path::PathBuf, +}; + +const FALLBACK_CONFIG_PATH: &str = "/tmp/wlxoverlay"; + +pub 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"); + return dir; + } + //Return fallback config path + error!( + "Err: Failed to find config path, using {}", + FALLBACK_CONFIG_PATH + ); + 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 +} + +// 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); + + let path_conf_d = get_conf_d_path(); + let _ = 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 load(filename: &str) -> Option { + let path = get_config_file_path(filename); + println!("Loading config {}", path.to_string_lossy()); + + if let Ok(data) = fs::read_to_string(path) { + Some(data) + } else { + None + } +} + +#[macro_export] +macro_rules! load_with_fallback { + ($filename: expr, $fallback: expr) => { + if let Some(data) = config_io::load($filename) { + data + } else { + println!( + "Config {}/{} does not exist, using internal fallback", + config_io::CONFIG_ROOT_PATH.to_string_lossy(), + $filename + ); + include_str!($fallback).to_string() + } + }; +} diff --git a/src/graphics.rs b/src/graphics.rs index 71d0423..30b8c68 100644 --- a/src/graphics.rs +++ b/src/graphics.rs @@ -9,6 +9,7 @@ use std::{ use ash::vk::{self, SubmitInfo}; use smallvec::{smallvec, SmallVec}; +use vulkano::instance::InstanceCreateFlags; use vulkano::{ buffer::{ allocator::{SubbufferAllocator, SubbufferAllocatorCreateInfo}, @@ -25,9 +26,11 @@ use vulkano::{ descriptor_set::{ allocator::StandardDescriptorSetAllocator, DescriptorSet, WriteDescriptorSet, }, + device::physical::PhysicalDeviceType, + device::Features, device::{ - physical::{PhysicalDevice, PhysicalDeviceType}, - Device, DeviceCreateInfo, DeviceExtensions, Features, Queue, QueueCreateInfo, QueueFlags, + physical::PhysicalDevice, Device, DeviceCreateInfo, DeviceExtensions, Queue, + QueueCreateInfo, QueueFlags, }, format::Format, image::{ @@ -37,7 +40,8 @@ use vulkano::{ Image, ImageCreateInfo, ImageLayout, ImageTiling, ImageType, ImageUsage, SampleCount, SubresourceLayout, }, - instance::{Instance, InstanceCreateFlags, InstanceCreateInfo, InstanceExtensions}, + instance::InstanceExtensions, + instance::{Instance, InstanceCreateInfo}, memory::{ allocator::{ AllocationCreateInfo, GenericMemoryAllocatorCreateInfo, MemoryAllocator, @@ -72,6 +76,7 @@ use vulkano::{ }, DeviceSize, VulkanLibrary, VulkanObject, }; + use wlx_capture::frame::{ DmabufFrame, FourCC, DRM_FORMAT_ABGR8888, DRM_FORMAT_ARGB8888, DRM_FORMAT_XBGR8888, DRM_FORMAT_XRGB8888, @@ -108,7 +113,7 @@ pub struct WlxGraphics { impl WlxGraphics { #[cfg(feature = "openxr")] - pub fn new_xr(xr_instance: openxr::Instance, system: openxr::SystemId) -> Arc { + pub fn new_openxr(xr_instance: openxr::Instance, system: openxr::SystemId) -> Arc { use std::ffi::{self, c_char, CString}; use vulkano::Handle; @@ -269,7 +274,8 @@ impl WlxGraphics { Arc::new(me) } - pub fn new( + #[cfg(feature = "openvr")] + pub fn new_openvr( vk_instance_extensions: InstanceExtensions, mut vk_device_extensions_fn: impl FnMut(&PhysicalDevice) -> DeviceExtensions, ) -> Arc { @@ -901,7 +907,7 @@ impl WlxPipeline { ) -> Self { let render_pass_description = RenderPassCreateInfo { attachments: vec![AttachmentDescription { - format: format, + format, samples: SampleCount::Sample1, load_op: AttachmentLoadOp::Clear, store_op: AttachmentStoreOp::Store, diff --git a/src/gui/mod.rs b/src/gui/mod.rs index b72ac78..5759c1e 100644 --- a/src/gui/mod.rs +++ b/src/gui/mod.rs @@ -466,6 +466,7 @@ impl OverlayRenderer for Canvas { fn view(&mut self) -> Option> { Some(self.view_final.clone()) } + fn extent(&self) -> [u32; 3] { self.view_final.image().extent().clone() } diff --git a/src/main.rs b/src/main.rs index ca8a97d..4845a1f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,7 @@ #[allow(dead_code)] mod backend; +mod config; +mod config_io; mod graphics; mod gui; mod hid; @@ -33,11 +35,12 @@ fn main() { #[cfg(all(feature = "openxr", feature = "openvr"))] auto_run(running); + // TODO: Handle error messages if using cherry-picked features #[cfg(all(feature = "openvr", not(feature = "openxr")))] - crate::backend::openvr::openvr_run(running); + let _ = crate::backend::openvr::openvr_run(running); #[cfg(all(feature = "openxr", not(feature = "openvr")))] - crate::backend::openxr::openxr_run(running); + let _ = crate::backend::openxr::openxr_run(running); #[cfg(not(any(feature = "openxr", feature = "openvr")))] compile_error!("You must enable at least one backend feature (openxr or openvr)"); diff --git a/src/overlays/keyboard.rs b/src/overlays/keyboard.rs index 95031d6..152e941 100644 --- a/src/overlays/keyboard.rs +++ b/src/overlays/keyboard.rs @@ -1,9 +1,6 @@ use std::{ collections::HashMap, - env::var, - fs, io::Cursor, - path::PathBuf, process::{Child, Command}, str::FromStr, sync::Arc, @@ -11,14 +8,15 @@ use std::{ use crate::{ backend::overlay::{OverlayData, OverlayState}, + config, gui::{color_parse, CanvasBuilder, Control}, hid::{KeyModifier, VirtualKey, KEYS_TO_MODS}, - state::AppState, + state::{AppSession, AppState}, }; use glam::{vec2, vec3a, Affine2}; use once_cell::sync::Lazy; use regex::Regex; -use rodio::{Decoder, OutputStream, Source}; +use rodio::{Decoder, OutputStream, OutputStreamHandle, Source}; use serde::{Deserialize, Serialize}; const PIXELS_PER_UNIT: f32 = 80.; @@ -37,6 +35,8 @@ where modifiers: 0, processes: vec![], audio_stream: None, + first_try: true, + audio_handle: None, }; let mut canvas = CanvasBuilder::new( @@ -109,7 +109,7 @@ where let interaction_transform = Affine2::from_translation(vec2(0.5, 0.5)) * Affine2::from_scale(vec2(1., -size.x as f32 / size.y as f32)); - let width = LAYOUT.row_size * 0.05; + let width = LAYOUT.row_size * 0.05 * app.session.config.keyboard_scale; OverlayData { state: OverlayState { @@ -134,7 +134,7 @@ fn key_press( ) { match control.state.as_mut() { Some(KeyButtonData::Key { vk, pressed }) => { - data.key_click(); + data.key_click(&app.session); app.hid_provider.send_key(*vk as _, true); *pressed = true; } @@ -145,12 +145,12 @@ fn key_press( }) => { *sticky = data.modifiers & *modifier == 0; data.modifiers |= *modifier; - data.key_click(); + data.key_click(&app.session); app.hid_provider.set_modifiers(data.modifiers); *pressed = true; } Some(KeyButtonData::Macro { verbs }) => { - data.key_click(); + data.key_click(&app.session); for (vk, press) in verbs { app.hid_provider.send_key(*vk as _, *press); } @@ -160,7 +160,7 @@ fn key_press( data.processes .retain_mut(|child| !matches!(child.try_wait(), Ok(Some(_)))); - data.key_click(); + data.key_click(&app.session); if let Ok(child) = Command::new(program).args(args).spawn() { data.processes.push(child); } @@ -210,19 +210,31 @@ struct KeyboardData { modifiers: KeyModifier, processes: Vec, audio_stream: Option, + audio_handle: Option, + first_try: bool, } impl KeyboardData { - fn key_click(&mut self) { - let wav = include_bytes!("../res/421581.wav"); - let cursor = Cursor::new(wav); - let source = Decoder::new_wav(cursor).unwrap(); - self.audio_stream = None; - if let Ok((stream, handle)) = OutputStream::try_default() { + fn key_click(&mut self, session: &AppSession) { + if !session.config.keyboard_sound_enabled { + return; + } + + if self.audio_stream.is_none() && self.first_try { + self.first_try = false; + if let Ok((stream, handle)) = OutputStream::try_default() { + self.audio_stream = Some(stream); + self.audio_handle = Some(handle); + } else { + log::error!("Failed to open audio stream"); + } + } + + if let Some(handle) = &self.audio_handle { + let wav = include_bytes!("../res/421581.wav"); + let cursor = Cursor::new(wav); + let source = Decoder::new_wav(cursor).unwrap(); let _ = handle.play_raw(source.convert_samples()); - self.audio_stream = Some(stream); - } else { - log::error!("Failed to play key click"); } } } @@ -246,18 +258,13 @@ enum KeyButtonData { }, } -static KEYBOARD_YAML: Lazy = Lazy::new(|| { - let home = &var("HOME").unwrap(); - [home, ".config/wlxoverlay/keyboard.yaml"].iter().collect() //TODO other paths -}); - static LAYOUT: Lazy = Lazy::new(Layout::load_from_disk); static MACRO_REGEX: Lazy = Lazy::new(|| Regex::new(r"^([A-Za-z0-1_-]+)(?: +(UP|DOWN))?$").unwrap()); #[derive(Debug, Deserialize, Serialize)] -struct Layout { +pub struct Layout { name: String, row_size: f32, key_sizes: Vec>, @@ -269,16 +276,8 @@ struct Layout { impl Layout { fn load_from_disk() -> Layout { - let mut yaml = fs::read_to_string(KEYBOARD_YAML.as_path()).ok(); - - if yaml.is_none() { - yaml = Some(include_str!("../res/keyboard.yaml").to_string()); - } - - let mut layout: Layout = - serde_yaml::from_str(&yaml.unwrap()).expect("Failed to parse keyboard.yaml"); + let mut layout = config::load_keyboard(); layout.post_load(); - layout } diff --git a/src/overlays/screen.rs b/src/overlays/screen.rs index a1363d9..fe3f8a3 100644 --- a/src/overlays/screen.rs +++ b/src/overlays/screen.rs @@ -1,11 +1,14 @@ use core::slice; +use serde::{Deserialize, Serialize}; use std::{ + collections::HashMap, + error::Error, f32::consts::PI, - path::Path, + ops::Deref, + path::PathBuf, ptr, sync::{mpsc::Receiver, Arc}, time::{Duration, Instant}, - usize, }; use vulkano::{ buffer::Subbuffer, @@ -30,6 +33,8 @@ use crate::{ input::{InteractionHandler, PointerHit, PointerMode}, overlay::{OverlayData, OverlayRenderer, OverlayState, SplitOverlayBackend}, }, + config::def_pw_tokens, + config_io, graphics::{fourcc_to_vk, Vert2Uv, WlxGraphics, WlxPipeline}, hid::{MOUSE_LEFT, MOUSE_MIDDLE, MOUSE_RIGHT}, state::{AppSession, AppState}, @@ -79,9 +84,6 @@ impl InteractionHandler for ScreenInteractionHandler { } } fn on_pointer(&mut self, app: &mut AppState, hit: &PointerHit, pressed: bool) { - let pos = self.mouse_transform.transform_point2(hit.uv); - app.hid_provider.mouse_move(pos); - let btn = match hit.mode { PointerMode::Right => MOUSE_RIGHT, PointerMode::Middle => MOUSE_MIDDLE, @@ -89,11 +91,14 @@ impl InteractionHandler for ScreenInteractionHandler { }; if pressed { - self.next_move = - Instant::now() + Duration::from_millis(app.session.click_freeze_time_ms); + self.next_move = Instant::now() + + Duration::from_millis(app.session.config.click_freeze_time_ms as u64); } app.hid_provider.send_button(btn, pressed); + + let pos = self.mouse_transform.transform_point2(hit.uv); + app.hid_provider.mouse_move(pos); } fn on_scroll(&mut self, app: &mut AppState, _hit: &PointerHit, delta: f32) { let millis = (1. - delta.abs()) * delta; @@ -342,7 +347,12 @@ impl OverlayRenderer for ScreenRenderer { } } -fn try_create_screen(wl: &WlxClient, id: u32, session: &AppSession) -> Option> +fn try_create_screen( + wl: &WlxClient, + id: u32, + pw_token_store: &mut HashMap, + session: &AppSession, +) -> Option> where O: Default, { @@ -366,9 +376,18 @@ where if capture.is_none() { log::info!("{}: Using Pipewire capture", &output.name); - let file_name = format!("{}.token", &output.name); - let full_path = Path::new(&session.config_path).join(file_name); - let token = std::fs::read_to_string(full_path).ok(); + + let display_name = output.name.deref(); + + // Find existing token by display + let token = pw_token_store.get(display_name).map(|s| s.as_str()); + + if let Some(t) = token { + println!( + "Found existing Pipewire token for display {}: {}", + display_name, t + ); + } capture = ScreenRenderer::new_pw( output, @@ -416,7 +435,7 @@ where want_visible: session.show_screens.iter().any(|s| s == &*output.name), show_hide: true, grabbable: true, - spawn_scale: 1.5, + spawn_scale: 1.5 * session.config.desktop_view_scale, spawn_point: vec3a(0., 0.5, -1.), spawn_rotation: Quat::from_axis_angle(axis, angle), interaction_transform, @@ -431,6 +450,44 @@ where } } +#[derive(Deserialize, Serialize, Default)] +pub struct TokenConf { + #[serde(default = "def_pw_tokens")] + pub pw_tokens: Vec<(String, String)>, +} + +fn get_pw_token_path() -> PathBuf { + let mut path = config_io::get_conf_d_path(); + path.push("pw_tokens.yaml"); + path +} + +pub fn save_pw_token_config(tokens: &HashMap) -> Result<(), Box> { + let mut conf = TokenConf::default(); + + for (name, token) in tokens { + conf.pw_tokens.push((name.clone(), token.clone())); + } + + let yaml = serde_yaml::to_string(&conf)?; + std::fs::write(get_pw_token_path(), yaml)?; + + Ok(()) +} + +pub fn load_pw_token_config() -> Result, Box> { + let mut map: HashMap = HashMap::new(); + + let yaml = std::fs::read_to_string(get_pw_token_path())?; + let conf: TokenConf = serde_yaml::from_str(yaml.as_str())?; + + for (name, token) in conf.pw_tokens { + map.insert(name, token); + } + + Ok(map) +} + pub fn get_screens_wayland(session: &AppSession) -> (Vec>, Vec2) where O: Default, @@ -438,11 +495,28 @@ where let mut overlays = vec![]; let wl = WlxClient::new().unwrap(); + // Load existing Pipewire tokens from file + let mut pw_tokens: HashMap = if let Ok(conf) = load_pw_token_config() { + conf + } else { + HashMap::new() + }; + + let pw_tokens_copy = pw_tokens.clone(); + for id in wl.outputs.keys() { - if let Some(overlay) = try_create_screen(&wl, *id, &session) { + if let Some(overlay) = try_create_screen(&wl, *id, &mut pw_tokens, session) { overlays.push(overlay); } } + + if pw_tokens_copy != pw_tokens { + // Token list changed, re-create token config file + if let Err(err) = save_pw_token_config(&pw_tokens) { + log::error!("Failed to save Pipewire token config: {}", err); + } + } + let extent = wl.get_desktop_extent(); (overlays, Vec2::new(extent.0 as f32, extent.1 as f32)) } diff --git a/src/overlays/watch.rs b/src/overlays/watch.rs index 12383d0..f81f156 100644 --- a/src/overlays/watch.rs +++ b/src/overlays/watch.rs @@ -169,7 +169,7 @@ where name: "Watch".into(), size: (400, 200), want_visible: true, - spawn_scale: 0.065, + spawn_scale: 0.065 * state.session.config.watch_scale, spawn_point: state.session.watch_pos.into(), spawn_rotation: state.session.watch_rot, interaction_transform, diff --git a/src/res/config.yaml b/src/res/config.yaml new file mode 100644 index 0000000..523a5f4 --- /dev/null +++ b/src/res/config.yaml @@ -0,0 +1,13 @@ +# For how much time mouse motion events should be stopped after clicking? +# Prevents accidental dragging various GUI elements or links, making it easier to click +# Default: 300 +click_freeze_time_ms: 300 + +# Default: true +keyboard_sound_enabled: true + +# Alter default scale of various overlays +# Default: 1.0 +keyboard_scale: 1.0 +desktop_view_scale: 1.0 +watch_scale: 1.0 diff --git a/src/state.rs b/src/state.rs index c2f10fc..7ae391d 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1,10 +1,12 @@ -use std::{env::VarError, path::Path, sync::Arc}; +use std::{path::PathBuf, sync::Arc}; use glam::{Quat, Vec3}; use vulkano::{command_buffer::CommandBufferUsage, format::Format, image::view::ImageView}; use crate::{ backend::{common::TaskContainer, input::InputState}, + config::GeneralConfig, + config_io, graphics::WlxGraphics, gui::font::FontCache, hid::HidProvider, @@ -74,16 +76,10 @@ impl AppState { } pub struct AppSession { - pub config_path: String, + pub config_root_path: PathBuf, + pub config: GeneralConfig, pub show_screens: Vec, - pub show_keyboard: bool, - pub keyboard_volume: f32, - - pub screen_flip_h: bool, - pub screen_flip_v: bool, - pub screen_invert_color: bool, - pub screen_max_res: [u32; 2], pub watch_hand: usize, pub watch_pos: Vec3, @@ -97,34 +93,18 @@ pub struct AppSession { pub color_shift: Vec3, pub color_alt: Vec3, pub color_grab: Vec3, - - pub click_freeze_time_ms: u64, } impl AppSession { pub fn load() -> Self { - let config_path = std::env::var("XDG_CONFIG_HOME") - .or_else(|_| std::env::var("HOME").map(|home| format!("{}/.config", home))) - .or_else(|_| { - log::warn!("Err: $XDG_CONFIG_HOME and $HOME are not set, using /tmp/wlxoverlay"); - Ok::("/tmp".to_string()) - }) - .map(|config| Path::new(&config).join("wlxoverlay")) - .ok() - .and_then(|path| path.to_str().map(|path| path.to_string())) - .unwrap(); - - let _ = std::fs::create_dir(&config_path); + let config_root_path = config_io::ensure_config_root(); + println!("Config root path: {}", config_root_path.to_string_lossy()); + let config = GeneralConfig::load_from_disk(); AppSession { - config_path, + config_root_path, + config, show_screens: vec!["DP-3".to_string()], - keyboard_volume: 0.5, - show_keyboard: false, - screen_flip_h: false, - screen_flip_v: false, - screen_invert_color: false, - screen_max_res: [2560, 1440], capture_method: "auto".to_string(), primary_hand: 1, watch_hand: 0, @@ -150,7 +130,6 @@ impl AppSession { y: 0., z: 0., }, - click_freeze_time_ms: 300, } } }