diff --git a/src/lib/game.rs b/src/lib/game.rs index 46eae83..2f41d51 100644 --- a/src/lib/game.rs +++ b/src/lib/game.rs @@ -61,7 +61,7 @@ pub fn try_get_terminal() -> Option { /// Try to run the game /// /// If `debug = true`, then the game will be run in the new terminal window -pub fn run(debug: bool) -> Result<(), Error> { +pub fn run(debug: bool) -> std::io::Result<()> { let config = config::get()?; if !Path::new(&config.game.path).exists() { @@ -73,7 +73,15 @@ pub fn run(debug: bool) -> Result<(), Error> { None => return Err(Error::new(ErrorKind::Other, "Couldn't find wine executable")) }; - let mut command = Command::new(wine_executable); + // Prepare bash -c '' + + let mut bash_chain = String::new(); + + if config.game.enhancements.gamemode { + bash_chain += "gamemoderun "; + } + + bash_chain += &format!("'{}' ", wine_executable); if debug { // Is not supported now because new spawned terminal needs @@ -92,9 +100,16 @@ pub fn run(debug: bool) -> Result<(), Error> { } else { - command.arg("launcher.bat"); + bash_chain += "launcher.bat"; } + let mut command = Command::new("bash"); + + command.arg("-c"); + command.arg(&bash_chain); + + // Setup environment + command.env("WINEPREFIX", &config.game.wine.prefix); // Add DXVK_ASYNC=1 for dxvk-async builds automatically @@ -109,9 +124,13 @@ pub fn run(debug: bool) -> Result<(), Error> { command.envs(config.game.enhancements.fsr.get_env_vars()); command.envs(config.game.wine.language.get_env_vars()); - command.envs(config.game.environment) - .current_dir(config.game.path) - .spawn()?; + command.envs(config.game.environment); + + // Run command + + println!("Running command: bash -c \"{}\"", bash_chain); + + command.current_dir(config.game.path).spawn()?; Ok(()) } diff --git a/src/ui/main.rs b/src/ui/main.rs index 3b0d503..7932a38 100644 --- a/src/ui/main.rs +++ b/src/ui/main.rs @@ -15,7 +15,7 @@ use wait_not_await::Await; use crate::ui::*; use super::preferences::PreferencesStack; -use super::traits::toast_error::ToastError; +use super::traits::toast::Toast; use super::components::progress_bar::*; use crate::lib::config; @@ -135,7 +135,7 @@ pub enum Actions { ShowProgressBar, UpdateProgress { fraction: Rc, title: Rc }, HideProgressBar, - ToastError(Rc<(String, Error)>) + Toast(Rc<(String, Error)>) } impl Actions { @@ -239,7 +239,7 @@ impl App { glib::MainContext::default().invoke(move || { this.update(Actions::PreferencesGoBack).unwrap(); - this.toast_error("Failed to update preferences", err); + this.toast("Failed to update preferences", err); }); } })); @@ -270,7 +270,7 @@ impl App { if let Err(err) = game::run(false) { this.widgets.window.show(); - this.toast_error("Failed to run game", err); + this.toast("Failed to run game", err); } else { @@ -318,20 +318,20 @@ impl App { Ok(true) => synced = true, Ok(false) => { - this.update(Actions::ToastError(Rc::new(( + this.update(Actions::Toast(Rc::new(( String::from("Failed to sync patch folder"), Error::last_os_error() )))).unwrap(); } Err(err) => { - this.update(Actions::ToastError(Rc::new(( + this.update(Actions::Toast(Rc::new(( String::from("Failed to sync patch folder"), err )))).unwrap(); } } } - Err(err) => this.update(Actions::ToastError(Rc::new(( + Err(err) => this.update(Actions::Toast(Rc::new(( String::from("Failed to check patch folder state"), err )))).unwrap() } @@ -341,7 +341,7 @@ impl App { Ok(_) => (), Err(err) => { - this.update(Actions::ToastError(Rc::new(( + this.update(Actions::Toast(Rc::new(( String::from("Failed to patch game"), err )))).unwrap(); } @@ -395,7 +395,7 @@ impl App { ProgressUpdateResult::Error(msg, err) => { this.widgets.progress_bar.hide(); - this.toast_error(msg, err); + this.toast(msg, err); } ProgressUpdateResult::Finished => { @@ -419,10 +419,10 @@ impl App { }); }); }, - Err(err) => this.toast_error("Failed to init wine version installer", err) + Err(err) => this.toast("Failed to init wine version installer", err) } }, - Err(err) => this.toast_error("Failed to get latest wine version", err) + Err(err) => this.toast("Failed to get latest wine version", err) } } @@ -430,7 +430,7 @@ impl App { this.update_state(); } }, - Err(err) => this.toast_error("Failed to list downloaded wine versions", err) + Err(err) => this.toast("Failed to list downloaded wine versions", err) } } @@ -445,7 +445,7 @@ impl App { this.widgets.launch_game.set_sensitive(false); if let Err(err) = prefix.update(&config.game.wine.builds, wine) { - this.update(Actions::ToastError(Rc::new(( + this.update(Actions::Toast(Rc::new(( String::from("Failed to create wine prefix"), err )))).unwrap(); } @@ -455,7 +455,7 @@ impl App { this.update_state(); }); }, - None => this.toast_error("Failed to get selected wine version", Error::last_os_error()) + None => this.toast("Failed to get selected wine version", Error::last_os_error()) } } @@ -477,7 +477,7 @@ impl App { ProgressUpdateResult::Error(msg, err) => { this.widgets.progress_bar.hide(); - this.toast_error(msg, err); + this.toast(msg, err); } ProgressUpdateResult::Finished => { @@ -516,7 +516,7 @@ impl App { LauncherState::VoiceOutdated(_) => () } }, - Err(err) => this.toast_error("Failed to load config", err) + Err(err) => this.toast("Failed to load config", err) } } @@ -648,7 +648,7 @@ impl App { for (i, file) in broken.into_iter().enumerate() { if !is_patch_applied || !should_ignore(&file.path) { if let Err(err) = file.repair(&config.game.path) { - this.update(Actions::ToastError(Rc::new(( + this.update(Actions::Toast(Rc::new(( String::from("Failed to repair game file"), err )))).unwrap(); } @@ -666,7 +666,7 @@ impl App { this.update(Actions::HideProgressBar).unwrap(); }, Err(err) => { - this.update(Actions::ToastError(Rc::new(( + this.update(Actions::Toast(Rc::new(( String::from("Failed to get integrity files"), err )))).unwrap(); @@ -675,7 +675,7 @@ impl App { } }); }, - Err(err) => this.toast_error("Failed to load config", err) + Err(err) => this.toast("Failed to load config", err) } } @@ -691,10 +691,10 @@ impl App { this.widgets.progress_bar.hide(); } - Actions::ToastError(toast) => { + Actions::Toast(toast) => { let (msg, err) = (toast.0.clone(), toast.1.to_string()); - this.toast_error(msg, err); + this.toast(msg, err); } } @@ -829,7 +829,7 @@ impl App { send.send(Err(err.to_string())).unwrap(); glib::MainContext::default().invoke(move || { - this.toast_error("Failed to get initial launcher state", err); + this.toast("Failed to get initial launcher state", err); }); } } @@ -841,7 +841,7 @@ impl App { } } -impl ToastError for App { +impl Toast for App { fn get_toast_widgets(&self) -> (adw::ApplicationWindow, adw::ToastOverlay) { (self.widgets.window.clone(), self.widgets.toast_overlay.clone()) } diff --git a/src/ui/preferences/general.rs b/src/ui/preferences/general.rs index d1fc41e..49135d1 100644 --- a/src/ui/preferences/general.rs +++ b/src/ui/preferences/general.rs @@ -171,7 +171,7 @@ pub enum Actions { SelectDxvkVersion(Rc), UpdateWineComboRow, SelectWineVersion(Rc), - ToastError(Rc<(String, Error)>) + Toast(Rc<(String, Error)>) } impl Actions { @@ -304,7 +304,7 @@ impl App { match component.apply(&config.game.dxvk.builds, &config.game.wine.prefix) { Ok(output) => println!("{}", output), Err(err) => { - this.update(Actions::ToastError(Rc::new(( + this.update(Actions::Toast(Rc::new(( String::from("Failed to apply DXVK"), err )))).unwrap(); } @@ -352,7 +352,7 @@ impl App { std::thread::spawn(move || { if let Err(err) = component.package.delete_in(&config.game.path) { - this.update(Actions::ToastError(Rc::new(( + this.update(Actions::Toast(Rc::new(( String::from("Failed to delete voiceover"), err )))).unwrap(); } @@ -389,7 +389,7 @@ impl App { if component.is_downloaded(&config.game.dxvk.builds) { if let Err(err) = component.delete(&config.game.dxvk.builds) { - this.update(Actions::ToastError(Rc::new(( + this.update(Actions::Toast(Rc::new(( String::from("Failed to delete DXVK"), err )))).unwrap(); } @@ -405,7 +405,7 @@ impl App { match component.apply(&config.game.dxvk.builds, &config.game.wine.prefix) { Ok(output) => println!("{}", output), Err(err) => { - this.update(Actions::ToastError(Rc::new(( + this.update(Actions::Toast(Rc::new(( String::from("Failed to apply DXVK"), err )))).unwrap(); } @@ -426,7 +426,7 @@ impl App { if component.is_downloaded(&config.game.wine.builds) { if let Err(err) = component.delete(&config.game.wine.builds) { - this.update(Actions::ToastError(Rc::new(( + this.update(Actions::Toast(Rc::new(( String::from("Failed to delete wine"), err )))).unwrap(); } @@ -501,7 +501,7 @@ impl App { match version.apply(&config.game.dxvk.builds, &config.game.wine.prefix) { Ok(output) => println!("{}", output), Err(err) => { - this.update(Actions::ToastError(Rc::new(( + this.update(Actions::Toast(Rc::new(( String::from("Failed to apply DXVK"), err )))).unwrap(); } @@ -566,10 +566,10 @@ impl App { config::update(config); } - Actions::ToastError(toast) => { + Actions::Toast(toast) => { let (msg, err) = (toast.0.clone(), toast.1.to_string()); - this.toast_error(msg, err); + this.toast(msg, err); } } @@ -697,7 +697,7 @@ impl App { } } -impl ToastError for App { +impl Toast for App { fn get_toast_widgets(&self) -> (adw::ApplicationWindow, adw::ToastOverlay) { let app = (&*self.app).take(); self.app.set(app.clone()); diff --git a/src/ui/preferences/mod.rs b/src/ui/preferences/mod.rs index a8a9708..bc7fe9f 100644 --- a/src/ui/preferences/mod.rs +++ b/src/ui/preferences/mod.rs @@ -89,7 +89,7 @@ impl PreferencesStack { } } -impl ToastError for PreferencesStack { +impl Toast for PreferencesStack { fn get_toast_widgets(&self) -> (adw::ApplicationWindow, adw::ToastOverlay) { let app = (&*self.app).take(); self.app.set(app.clone()); diff --git a/src/ui/traits/mod.rs b/src/ui/traits/mod.rs index 77fbc8e..e79dc7a 100644 --- a/src/ui/traits/mod.rs +++ b/src/ui/traits/mod.rs @@ -1,7 +1,7 @@ -pub mod toast_error; +pub mod toast; pub mod download_component; pub mod prelude { - pub use super::toast_error::*; + pub use super::toast::*; pub use super::download_component::*; } diff --git a/src/ui/traits/toast.rs b/src/ui/traits/toast.rs new file mode 100644 index 0000000..b42eb87 --- /dev/null +++ b/src/ui/traits/toast.rs @@ -0,0 +1,44 @@ +use gtk4::{self as gtk, prelude::*}; +use libadwaita as adw; + +use crate::ui::add_action; + +pub trait Toast { + fn get_toast_widgets(&self) -> (adw::ApplicationWindow, adw::ToastOverlay); + + /// Show toast with `toast` title and `See message` button + /// + /// This button will show message dialog with some message + fn toast(&self, toast: T, message: F) { + let toast = adw::Toast::new(toast.to_string().as_str()); + let (window, toast_overlay) = self.get_toast_widgets(); + + toast.set_timeout(0); + + let message = format!("{}", message); + + if message.len() > 0 { + toast.set_button_label(Some("See message")); + toast.set_action_name(Some("see-message.see-message")); + + // Show message in a dialog window + add_action(&toast_overlay, "see-message", move || { + let dialog = gtk::MessageDialog::new( + Some(&window), + gtk::DialogFlags::all(), + gtk::MessageType::Info, + gtk::ButtonsType::Close, + &message + ); + + dialog.connect_response(move |dialog, _| { + dialog.close(); + }); + + dialog.show(); + }); + } + + toast_overlay.add_toast(&toast); + } +} diff --git a/src/ui/traits/toast_error.rs b/src/ui/traits/toast_error.rs deleted file mode 100644 index d74234b..0000000 --- a/src/ui/traits/toast_error.rs +++ /dev/null @@ -1,40 +0,0 @@ -use gtk4::{self as gtk, prelude::*}; -use libadwaita as adw; - -use crate::ui::add_action; - -pub trait ToastError { - fn get_toast_widgets(&self) -> (adw::ApplicationWindow, adw::ToastOverlay); - - /// Show toast with `toast` title and `See message` button - /// - /// This button will show message dialog with error message - fn toast_error(&self, toast: T, err: F) { - let toast = adw::Toast::new(toast.to_string().as_str()); - - toast.set_button_label(Some("See message")); - toast.set_action_name(Some("see-message.see-message")); - toast.set_timeout(0); - - let (window, toast_overlay) = self.get_toast_widgets(); - - // Show error message in a dialog window - add_action(&toast_overlay, "see-message", move || { - let dialog = gtk::MessageDialog::new( - Some(&window), - gtk::DialogFlags::all(), - gtk::MessageType::Info, - gtk::ButtonsType::Close, - &format!("{}", err) - ); - - dialog.connect_response(move |dialog, _| { - dialog.close(); - }); - - dialog.show(); - }); - - toast_overlay.add_toast(&toast); - } -}