feat: show steam launch options on start; rename openovr to opencomposite; fallback for selected profile

This commit is contained in:
Gabriele Musco 2023-06-15 17:25:26 +02:00
commit 7da1f6f7ae
No known key found for this signature in database
GPG key ID: 1068D795C80E51DE
7 changed files with 141 additions and 44 deletions

View file

@ -13,7 +13,7 @@ relm4 = { version = "0.6.0", features = [
] } ] }
relm4-components = "0.6.0" relm4-components = "0.6.0"
relm4-icons = { version = "0.6.0", features = [ relm4-icons = { version = "0.6.0", features = [
"menu", "loupe" "menu", "loupe", "copy"
] } ] }
serde = { version = "1.0.163", features = [ serde = { version = "1.0.163", features = [
"derive" "derive"

View file

@ -23,7 +23,7 @@ fn config_file_path() -> String {
fn default_config() -> Config { fn default_config() -> Config {
Config { Config {
// TODO: handle first start with no profile selected // TODO: handle first start with no profile selected
selected_profile_name: "Demo profile".to_string(), selected_profile_name: "".to_string(),
debug_view_enabled: false, debug_view_enabled: false,
} }
} }

View file

@ -8,7 +8,7 @@ use crate::file_utils::get_writer;
pub struct Profile { pub struct Profile {
pub name: String, pub name: String,
pub monado_path: String, pub monado_path: String,
pub openovr_path: String, pub opencomposite_path: String,
pub libsurvive_path: Option<String>, pub libsurvive_path: Option<String>,
pub basalt_path: Option<String>, pub basalt_path: Option<String>,
pub mercury_path: Option<String>, pub mercury_path: Option<String>,
@ -26,6 +26,16 @@ impl Display for Profile {
} }
} }
impl Profile {
pub fn get_steam_launch_options(&self) -> String {
let mut opts = vec![];
opts.push(format!("XR_RUNTIME_JSON={prefix}/share/openxr/1/openxr_monado.json", prefix = self.prefix));
opts.push(format!("PRESSURE_VESSEL_FILESYSTEMS_RW=$XDG_RUNTIME_DIR/monado_comp_ipc"));
opts.push("%command%".into());
opts.join(" ")
}
}
pub fn load_profile(path: &String) -> Profile { pub fn load_profile(path: &String) -> Profile {
let file = File::open(path).expect_dialog("Unable to open profile"); let file = File::open(path).expect_dialog("Unable to open profile");
let reader = BufReader::new(file); let reader = BufReader::new(file);
@ -48,7 +58,7 @@ mod tests {
let profile = load_profile(&"./test/files/profile.json".to_string()); let profile = load_profile(&"./test/files/profile.json".to_string());
assert_eq!(profile.name, "Demo profile"); assert_eq!(profile.name, "Demo profile");
assert_eq!(profile.monado_path, "/home/user/monado"); assert_eq!(profile.monado_path, "/home/user/monado");
assert_eq!(profile.openovr_path, "/home/user/openovr"); assert_eq!(profile.opencomposite_path, "/home/user/opencomposite");
assert_eq!(profile.prefix, "/home/user/rex2prefix"); assert_eq!(profile.prefix, "/home/user/rex2prefix");
assert_eq!( assert_eq!(
profile.libsurvive_path.as_deref(), profile.libsurvive_path.as_deref(),
@ -76,7 +86,7 @@ mod tests {
let p = Profile { let p = Profile {
name: "Demo profile".into(), name: "Demo profile".into(),
monado_path: String::from("/home/user/monado"), monado_path: String::from("/home/user/monado"),
openovr_path: String::from("/home/user/openovr"), opencomposite_path: String::from("/home/user/opencomposite"),
libsurvive_path: Some(String::from("/home/user/libsurvive")), libsurvive_path: Some(String::from("/home/user/libsurvive")),
basalt_path: None, basalt_path: None,
mercury_path: None, mercury_path: None,

View file

@ -13,7 +13,7 @@ pub fn valve_index_profile() -> Profile {
Profile { Profile {
name: format!("Valve Index - {name} Default", name = APP_NAME), name: format!("Valve Index - {name} Default", name = APP_NAME),
monado_path: format!("{data}/monado", data = data_dir), monado_path: format!("{data}/monado", data = data_dir),
openovr_path: format!("{data}/openovr", data = data_dir), opencomposite_path: format!("{data}/opencomposite", data = data_dir),
libsurvive_path: Some(format!("{data}/libsurvive", data = data_dir)), libsurvive_path: Some(format!("{data}/libsurvive", data = data_dir)),
basalt_path: None, basalt_path: None,
mercury_path: None, mercury_path: None,

View file

@ -1,11 +1,14 @@
use std::time::Duration; use super::about_dialog::AboutDialog;
use super::build_window::BuildWindow;
use super::debug_view::{DebugView, DebugViewMsg};
use super::main_view::MainViewMsg;
use crate::builders::build_libsurvive::get_build_libsurvive_runner; use crate::builders::build_libsurvive::get_build_libsurvive_runner;
use crate::builders::build_monado::get_build_monado_runner; use crate::builders::build_monado::get_build_monado_runner;
use crate::builders::build_opencomposite::get_build_opencomposite_runner;
use crate::config::{get_config, save_config, Config}; use crate::config::{get_config, save_config, Config};
use crate::constants::APP_NAME; use crate::constants::APP_NAME;
use crate::dependencies::libsurvive_deps::get_missing_libsurvive_deps; use crate::dependencies::libsurvive_deps::get_missing_libsurvive_deps;
use crate::dependencies::monado_deps::{check_monado_deps, get_missing_monado_deps}; use crate::dependencies::monado_deps::get_missing_monado_deps;
use crate::profile::Profile; use crate::profile::Profile;
use crate::profiles::valve_index::valve_index_profile; use crate::profiles::valve_index::valve_index_profile;
use crate::runner::{Runner, RunnerStatus}; use crate::runner::{Runner, RunnerStatus};
@ -20,12 +23,7 @@ use relm4::adw::traits::MessageDialogExt;
use relm4::gtk::glib; use relm4::gtk::glib;
use relm4::{new_action_group, new_stateful_action, new_stateless_action, prelude::*}; use relm4::{new_action_group, new_stateful_action, new_stateless_action, prelude::*};
use relm4::{ComponentParts, ComponentSender, SimpleComponent}; use relm4::{ComponentParts, ComponentSender, SimpleComponent};
use relm4_components::alert::{Alert, AlertSettings}; use std::time::Duration;
use super::about_dialog::AboutDialog;
use super::build_window::BuildWindow;
use super::debug_view::{DebugView, DebugViewMsg};
use super::main_view::MainViewMsg;
#[tracker::track] #[tracker::track]
pub struct App { pub struct App {
@ -74,8 +72,10 @@ impl App {
} }
pub fn get_selected_profile(&self) -> &Profile { pub fn get_selected_profile(&self) -> &Profile {
self.get_profile_by_name(&self.config.selected_profile_name) match self.get_profile_by_name(&self.config.selected_profile_name) {
.expect_dialog("Could not find selected profile") Some(profile) => profile,
None => self.profiles.get(0).expect_dialog("No profiles found"),
}
} }
pub fn start_monado(&mut self) { pub fn start_monado(&mut self) {
@ -152,7 +152,7 @@ impl SimpleComponent for App {
self.build_window self.build_window
.sender() .sender()
.emit(BuildWindowMsg::UpdateContent(pipeline.get_log())); .emit(BuildWindowMsg::UpdateContent(pipeline.get_log()));
}, }
false => { false => {
self.build_window self.build_window
.sender() .sender()
@ -181,6 +181,11 @@ impl SimpleComponent for App {
self.main_view self.main_view
.sender() .sender()
.emit(MainViewMsg::MonadoActiveChanged(true)); .emit(MainViewMsg::MonadoActiveChanged(true));
self.main_view
.sender()
.emit(MainViewMsg::SteamLaunchOptionsChanged(
self.get_selected_profile().get_steam_launch_options(),
));
} }
Some(runner) => match runner.status() { Some(runner) => match runner.status() {
RunnerStatus::Running => { RunnerStatus::Running => {
@ -217,6 +222,8 @@ impl SimpleComponent for App {
// runners.push(get_build_mercury_runner(profile.clone())); // runners.push(get_build_mercury_runner(profile.clone()));
// } // }
runners.push(get_build_monado_runner(profile.clone())); runners.push(get_build_monado_runner(profile.clone()));
// no listed deps for opencomp
runners.push(get_build_opencomposite_runner(profile.clone()));
if !missing_deps.is_empty() { if !missing_deps.is_empty() {
self.dependencies_dialog.set_body( self.dependencies_dialog.set_body(
missing_deps missing_deps

View file

@ -1,16 +1,17 @@
use gtk::prelude::*;
use relm4::prelude::*;
use relm4::{SimpleComponent, ComponentSender, ComponentParts};
use relm4_icons::icon_name;
use crate::config::Config; use crate::config::Config;
use crate::constants::APP_NAME; use crate::constants::APP_NAME;
use crate::ui::app::{AboutAction, DebugViewToggleAction, BuildProfileAction}; use crate::ui::app::{AboutAction, BuildProfileAction, DebugViewToggleAction};
use gtk::prelude::*;
use relm4::prelude::*;
use relm4::{ComponentParts, ComponentSender, SimpleComponent};
use relm4_icons::icon_name;
#[tracker::track] #[tracker::track]
pub struct MainView { pub struct MainView {
monado_active: bool, monado_active: bool,
enable_debug_view: bool, enable_debug_view: bool,
profile_names: Vec<String>, profile_names: Vec<String>,
steam_launch_options: String,
} }
#[derive(Debug)] #[derive(Debug)]
@ -19,6 +20,7 @@ pub enum MainViewMsg {
MonadoActiveChanged(bool), MonadoActiveChanged(bool),
EnableDebugViewChanged(bool), EnableDebugViewChanged(bool),
UpdateProfileNames(Vec<String>), UpdateProfileNames(Vec<String>),
SteamLaunchOptionsChanged(String),
} }
#[derive(Debug)] #[derive(Debug)]
@ -84,26 +86,98 @@ impl SimpleComponent for MainView {
set_show_end_title_buttons: !model.enable_debug_view, set_show_end_title_buttons: !model.enable_debug_view,
}, },
}, },
gtk::Box { gtk::ScrolledWindow {
set_spacing: 12, set_hscrollbar_policy: gtk::PolicyType::Never,
set_margin_all: 12, set_hexpand: true,
gtk::Button { set_vexpand: true,
add_css_class: "pill", gtk::Box {
add_css_class: "suggested-action", set_spacing: 12,
add_css_class: "destructive-action", set_margin_top: 12,
set_hexpand: true, set_margin_bottom: 12,
set_halign: gtk::Align::Center, set_orientation: gtk::Orientation::Vertical,
#[track = "model.changed(MainView::monado_active())"] gtk::Button {
set_class_active: ("suggested-action", !model.monado_active), add_css_class: "pill",
#[track = "model.changed(MainView::monado_active())"] add_css_class: "suggested-action",
set_label: match model.monado_active { add_css_class: "destructive-action",
true => "Stop", set_hexpand: true,
false => "Start", set_halign: gtk::Align::Center,
#[track = "model.changed(MainView::monado_active())"]
set_class_active: ("suggested-action", !model.monado_active),
#[track = "model.changed(MainView::monado_active())"]
set_label: match model.monado_active {
true => "Stop",
false => "Start",
},
connect_clicked[sender] => move |_| {
sender.input(MainViewMsg::StartStopClicked)
},
}, },
connect_clicked[sender] => move |_| { gtk::Box {
sender.input(MainViewMsg::StartStopClicked) set_orientation: gtk::Orientation::Vertical,
set_hexpand: true,
set_vexpand: false,
set_spacing: 12,
set_margin_top: 12,
set_margin_bottom: 12,
#[track = "model.changed(MainView::monado_active())"]
set_visible: model.monado_active,
gtk::Separator {
set_orientation: gtk::Orientation::Horizontal,
set_hexpand: true,
},
gtk::Label {
add_css_class: "heading",
set_hexpand: true,
set_xalign: 0.0,
set_margin_start: 12,
set_margin_end: 12,
set_label: "Steam Launch Options",
set_wrap: true,
set_wrap_mode: gtk::pango::WrapMode::Word,
},
gtk::Label {
add_css_class: "dim-label",
set_hexpand: true,
set_xalign: 0.0,
set_margin_start: 12,
set_margin_end: 12,
set_label: "Set this string in the launch options of Steam games, so that they can pick up Monado and OpenOVR correctly",
set_wrap: true,
set_wrap_mode: gtk::pango::WrapMode::Word,
},
gtk::Box {
set_margin_start: 12,
set_margin_end: 12,
set_orientation: gtk::Orientation::Horizontal,
set_spacing: 6,
gtk::TextView {
add_css_class: "card",
set_hexpand: true,
set_vexpand: false,
set_monospace: true,
set_editable: false,
set_wrap_mode: gtk::WrapMode::Word,
set_left_margin: 6,
set_right_margin: 6,
set_top_margin: 6,
set_bottom_margin: 6,
set_size_request: (-1, 150),
#[wrap(Some)]
set_buffer: cmdbuf = &gtk::TextBuffer {
#[track = "model.changed(MainView::steam_launch_options())"]
set_text: model.steam_launch_options.as_str(),
}
},
gtk::Button {
add_css_class: "flat",
add_css_class: "circular",
set_icon_name: icon_name::COPY,
set_vexpand: false,
set_valign: gtk::Align::Center,
},
},
} }
}, }
} }
} }
} }
@ -114,7 +188,7 @@ impl SimpleComponent for MainView {
match message { match message {
MainViewMsg::StartStopClicked => { MainViewMsg::StartStopClicked => {
sender.output(MainViewOutMsg::DoStartStopMonado); sender.output(MainViewOutMsg::DoStartStopMonado);
}, }
MainViewMsg::MonadoActiveChanged(active) => { MainViewMsg::MonadoActiveChanged(active) => {
self.set_monado_active(active); self.set_monado_active(active);
} }
@ -124,14 +198,20 @@ impl SimpleComponent for MainView {
MainViewMsg::UpdateProfileNames(names) => { MainViewMsg::UpdateProfileNames(names) => {
self.set_profile_names(names); self.set_profile_names(names);
} }
MainViewMsg::SteamLaunchOptionsChanged(lo) => self.set_steam_launch_options(lo),
} }
} }
fn init(init: Self::Init, root: &Self::Root, sender: ComponentSender<Self>) -> ComponentParts<Self> { fn init(
init: Self::Init,
root: &Self::Root,
sender: ComponentSender<Self>,
) -> ComponentParts<Self> {
let model = MainView { let model = MainView {
monado_active: false, monado_active: false,
enable_debug_view: init.config.debug_view_enabled, enable_debug_view: init.config.debug_view_enabled,
profile_names: vec![], profile_names: vec![],
steam_launch_options: "".into(),
tracker: 0, tracker: 0,
}; };
let widgets = view_output!(); let widgets = view_output!();

View file

@ -1,7 +1,7 @@
{ {
"name": "Demo profile", "name": "Demo profile",
"monado_path": "/home/user/monado", "monado_path": "/home/user/monado",
"openovr_path": "/home/user/openovr", "opencomposite_path": "/home/user/opencomposite",
"libsurvive_path": "/home/user/libsurvive", "libsurvive_path": "/home/user/libsurvive",
"basalt_path": null, "basalt_path": null,
"mercury_path": null, "mercury_path": null,