diff --git a/src/profile.rs b/src/profile.rs index b6d08e3..3e24ffc 100644 --- a/src/profile.rs +++ b/src/profile.rs @@ -1,9 +1,6 @@ use crate::{ file_utils::get_writer, - paths::{ - data_monado_path, data_opencomposite_path, get_data_dir, get_ipc_file_path, - BWRAP_SYSTEM_PREFIX, SYSTEM_PREFIX, - }, + paths::{get_data_dir, get_ipc_file_path, BWRAP_SYSTEM_PREFIX, SYSTEM_PREFIX}, }; use serde::{Deserialize, Serialize}; use std::{collections::HashMap, fmt::Display, fs::File, io::BufReader, path::Path, slice::Iter}; @@ -230,6 +227,7 @@ pub struct Profile { pub lighthouse_driver: LighthouseDriver, #[serde(default = "String::default")] pub xrservice_launch_options: String, + pub autostart_command: Option, } impl Display for Profile { @@ -284,6 +282,7 @@ impl Default for Profile { lighthouse_driver: LighthouseDriver::default(), xrservice_launch_options: String::default(), uuid, + autostart_command: None, } } } diff --git a/src/ui/app.rs b/src/ui/app.rs index 6c635e4..e1d8199 100644 --- a/src/ui/app.rs +++ b/src/ui/app.rs @@ -92,6 +92,8 @@ pub struct App { #[tracker::do_not_track] xrservice_worker: Option, #[tracker::do_not_track] + autostart_worker: Option, + #[tracker::do_not_track] restart_xrservice: bool, #[tracker::do_not_track] build_worker: Option, @@ -112,6 +114,7 @@ pub struct App { pub enum Msg { OnServiceLog(Vec), OnServiceExit(i32), + OnAutostartExit(i32), OnBuildLog(Vec), OnBuildExit(i32), ClockTicking, @@ -197,6 +200,23 @@ impl App { debug, ); worker.start(); + if let Some(autostart_cmd) = prof.autostart_command { + let autostart_worker = JobWorker::new_with_timer( + Duration::from_secs(5), + WorkerJob::new_cmd( + Some(prof.environment.clone()), + "sh".into(), + Some(vec!["-c".into(), autostart_cmd.clone()]), + ), + sender.input_sender(), + |msg| match msg { + JobWorkerOut::Log(rows) => Msg::OnServiceLog(rows), + JobWorkerOut::Exit(code) => Msg::OnAutostartExit(code), + }, + ); + autostart_worker.start(); + self.autostart_worker = Some(autostart_worker) + } self.xrservice_worker = Some(worker); self.main_view .sender() @@ -242,6 +262,9 @@ impl App { if let Some(worker) = self.xrservice_worker.as_ref() { worker.stop(); } + if let Some(worker) = self.autostart_worker.as_ref() { + worker.stop(); + } self.libmonado = None; self.restore_openxr_openvr_files(); self.main_view @@ -325,24 +348,20 @@ impl SimpleComponent for App { .emit(DebugViewMsg::LogUpdated(rows)); } } - Msg::OnServiceExit(_) => { + Msg::OnServiceExit(code) => { self.main_view .sender() .emit(MainViewMsg::XRServiceActiveChanged(false, None)); self.debug_view .sender() .emit(DebugViewMsg::XRServiceActiveChanged(false)); - if let Some(worker) = self.xrservice_worker.as_ref() { - if let Some(code) = worker.exit_code() { - if code != 0 && code != 15 { - // 15 is SIGTERM - sender.input(Msg::OnServiceLog(vec![format!( - "{} exited with code {}", - self.get_selected_profile().xrservice_type, - code - )])); - } - } + if code != 0 && code != 15 { + // 15 is SIGTERM + sender.input(Msg::OnServiceLog(vec![format!( + "{} exited with code {}", + self.get_selected_profile().xrservice_type, + code + )])); } self.xrservice_worker = None; if self.restart_xrservice { @@ -350,6 +369,7 @@ impl SimpleComponent for App { self.start_xrservice(sender, false); } } + Msg::OnAutostartExit(_) => self.autostart_worker = None, Msg::ClockTicking => { self.main_view.sender().emit(MainViewMsg::ClockTicking); if let Some(w) = self.xrservice_worker.as_ref() { @@ -798,6 +818,7 @@ impl SimpleComponent for App { config, profiles, xrservice_worker: None, + autostart_worker: None, build_worker: None, xr_devices: vec![], fbt_config_editor: None, diff --git a/src/ui/job_worker/job.rs b/src/ui/job_worker/job.rs index 46f266b..5c5102e 100644 --- a/src/ui/job_worker/job.rs +++ b/src/ui/job_worker/job.rs @@ -7,12 +7,21 @@ pub struct CmdWorkerData { pub args: Vec, } -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone)] pub struct FuncWorkerOut { pub success: bool, pub out: Vec, } +impl Default for FuncWorkerOut { + fn default() -> Self { + Self { + success: true, + out: vec![], + } + } +} + pub struct FuncWorkerData { pub func: Box FuncWorkerOut + Send + Sync + 'static>, } diff --git a/src/ui/job_worker/mod.rs b/src/ui/job_worker/mod.rs index 8c38e79..0c6c689 100644 --- a/src/ui/job_worker/mod.rs +++ b/src/ui/job_worker/mod.rs @@ -1,6 +1,6 @@ use self::{ internal_worker::{InternalJobWorker, JobWorkerInit, JobWorkerMsg, JobWorkerOut}, - job::WorkerJob, + job::{FuncWorkerOut, WorkerJob}, state::JobWorkerState, }; use crate::profile::Profile; @@ -44,6 +44,32 @@ impl JobWorker { } } + pub fn new_with_timer X) + 'static>( + duration: Duration, + job: WorkerJob, + sender: &Sender, + transform: F, + ) -> Self { + let timer_job = WorkerJob::new_func(Box::new(move || { + thread::sleep(duration); + FuncWorkerOut::default() + })); + let mut jobs = VecDeque::new(); + let state = Arc::new(Mutex::new(JobWorkerState::default())); + jobs.push_back(timer_job); + jobs.push_back(job); + let init = JobWorkerInit { + jobs, + state: state.clone(), + }; + Self { + worker: InternalJobWorker::builder() + .detach_worker(init) + .forward(sender, transform), + state, + } + } + pub fn xrservice_worker_wrap_from_profile X) + 'static>( prof: &Profile, sender: &Sender, diff --git a/src/ui/profile_editor.rs b/src/ui/profile_editor.rs index 3087a92..2db7dbc 100644 --- a/src/ui/profile_editor.rs +++ b/src/ui/profile_editor.rs @@ -113,6 +113,14 @@ impl SimpleComponent for ProfileEditor { prof.borrow_mut().prefix = n_path.unwrap_or_default() }), ), + add: &entry_row("Autostart Command", + model.profile.borrow().autostart_command.as_ref().unwrap_or(&String::default()), + clone!(@strong prof => move |row| { + let txt = row.text().trim().to_string(); + prof.borrow_mut().autostart_command = + if txt.is_empty() {None} else {Some(txt)}; + }) + ) }, add: xrservicegrp = &adw::PreferencesGroup { set_title: "XR Service",