diff --git a/src/runner.rs b/src/runner.rs index b2872cd..4ddc8d3 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -1,4 +1,7 @@ -use crate::{file_utils::get_writer, profile::{Profile, XRServiceType}}; +use crate::{ + file_utils::get_writer, + profile::{Profile, XRServiceType}, +}; use expect_dialog::ExpectDialog; use nix::{ sys::signal::{kill, Signal::SIGTERM}, @@ -98,23 +101,29 @@ impl Runner { ) } - pub fn start(&mut self) { + pub fn try_start(&mut self) -> Result<(), std::io::Error> { self.threads = Vec::new(); - self.process = Some( - Command::new(self.command.clone()) - .args(self.args.clone()) - .envs(self.environment.clone()) - .stderr(Stdio::piped()) - .stdout(Stdio::piped()) - .spawn() - .expect_dialog("Failed to execute runner"), - ); + let cmd = Command::new(self.command.clone()) + .args(self.args.clone()) + .envs(self.environment.clone()) + .stderr(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn(); + if cmd.is_err() { + return Err(cmd.unwrap_err()); + } + self.process = Some(cmd.unwrap()); let stdout = self.process.as_mut().unwrap().stdout.take().unwrap(); let stderr = self.process.as_mut().unwrap().stderr.take().unwrap(); let stdout_sender = self.sender.clone(); let stderr_sender = self.sender.clone(); self.threads.push(logger_thread!(stdout, stdout_sender)); self.threads.push(logger_thread!(stderr, stderr_sender)); + Ok(()) + } + + pub fn start(&mut self) { + self.try_start().expect_dialog("Failed to execute runner"); } fn join_threads(&mut self) { diff --git a/src/ui/app.rs b/src/ui/app.rs index 64737bb..9de3e70 100644 --- a/src/ui/app.rs +++ b/src/ui/app.rs @@ -58,6 +58,8 @@ pub struct App { setcap_confirm_dialog: adw::MessageDialog, #[tracker::do_not_track] libsurvive_setup_window: Controller, + #[tracker::do_not_track] + profile_runner_failed_dialog: adw::MessageDialog, #[tracker::do_not_track] config: Config, @@ -101,9 +103,24 @@ impl App { pub fn start_xrservice(&mut self) { self.xrservice_log.clear(); + self.debug_view + .sender() + .emit(DebugViewMsg::LogUpdated(vec![])); let mut runner = Runner::xrservice_runner_from_profile(self.get_selected_profile().clone()); - runner.start(); - self.xrservice_runner = Some(runner); + match runner.try_start() { + Ok(_) => { + self.xrservice_runner = Some(runner); + self.main_view + .sender() + .emit(MainViewMsg::XRServiceActiveChanged( + true, + Some(self.get_selected_profile()), + )); + } + Err(_) => { + self.profile_runner_failed_dialog.present(); + } + }; } pub fn profiles_list(config: &Config) -> Vec { @@ -243,16 +260,7 @@ impl SimpleComponent for App { } Msg::DoStartStopXRService => match &mut self.xrservice_runner { None => { - self.debug_view - .sender() - .emit(DebugViewMsg::LogUpdated(vec![])); self.start_xrservice(); - self.main_view - .sender() - .emit(MainViewMsg::XRServiceActiveChanged( - true, - Some(self.get_selected_profile()), - )); } Some(runner) => match runner.status() { RunnerStatus::Running => { @@ -262,16 +270,7 @@ impl SimpleComponent for App { .emit(MainViewMsg::XRServiceActiveChanged(false, None)); } RunnerStatus::Stopped(_) => { - self.debug_view - .sender() - .emit(DebugViewMsg::LogUpdated(vec![])); self.start_xrservice(); - self.main_view - .sender() - .emit(MainViewMsg::XRServiceActiveChanged( - true, - Some(self.get_selected_profile()), - )); } }, }, @@ -449,6 +448,18 @@ impl SimpleComponent for App { }); } + let profile_runner_failed_dialog = adw::MessageDialog::builder() + .modal(true) + .transient_for(root) + .heading("Failed to start profile") + .body(concat!( + "You need to build the current profile before starting it.", + "\n\nYou can do this from the menu." + )) + .hide_on_close(true) + .build(); + profile_runner_failed_dialog.add_response("ok", "_Ok"); + let model = App { application: init.application, main_view: MainView::builder() @@ -485,6 +496,7 @@ impl SimpleComponent for App { .detach(), dependencies_dialog, setcap_confirm_dialog, + profile_runner_failed_dialog, enable_debug_view: config.debug_view_enabled, config, tracker: 0,