feat: remove runtime switch; switch runtime on the fly on service start/stop

This commit is contained in:
Gabriele Musco 2023-07-11 13:36:08 +02:00
parent 261703ae5a
commit 50cf3a4511
No known key found for this signature in database
GPG key ID: 1068D795C80E51DE
9 changed files with 124 additions and 203 deletions

View file

@ -23,14 +23,21 @@ pub struct ActiveRuntime {
pub runtime: ActiveRuntimeInnerRuntime,
}
fn get_active_runtime_json_path() -> String {
pub fn get_openxr_conf_dir() -> String {
format!(
"{config}/openxr/1/active_runtime.json",
"{config}/openxr",
config = get_xdg_config_dir()
)
}
pub fn is_steam(active_runtime: ActiveRuntime) -> bool {
fn get_active_runtime_json_path() -> String {
format!(
"{config}/1/active_runtime.json",
config = get_openxr_conf_dir()
)
}
pub fn is_steam(active_runtime: &ActiveRuntime) -> bool {
match active_runtime.runtime.valve_runtime_is_steamvr {
Some(true) => true,
_ => false,
@ -45,16 +52,16 @@ pub fn get_current_active_runtime() -> Option<ActiveRuntime> {
get_active_runtime_from_path(&get_active_runtime_json_path())
}
fn dump_active_runtime_to_path(active_runtime: ActiveRuntime, path_s: String) {
set_file_radonly(&path_s, false);
let writer = get_writer(&path_s);
serde_json::to_writer_pretty(writer, &active_runtime)
fn dump_active_runtime_to_path(active_runtime: &ActiveRuntime, path_s: &String) {
set_file_radonly(path_s, false);
let writer = get_writer(path_s);
serde_json::to_writer_pretty(writer, active_runtime)
.expect_dialog("Unable to save active runtime");
set_file_radonly(&path_s, true);
set_file_radonly(path_s, true);
}
pub fn dump_current_active_runtime(active_runtime: ActiveRuntime) {
dump_active_runtime_to_path(active_runtime, get_active_runtime_json_path());
pub fn dump_current_active_runtime(active_runtime: &ActiveRuntime) {
dump_active_runtime_to_path(active_runtime, &get_active_runtime_json_path());
}
fn build_steam_active_runtime() -> ActiveRuntime {
@ -72,10 +79,10 @@ fn build_steam_active_runtime() -> ActiveRuntime {
}
pub fn set_current_active_runtime_to_steam() {
dump_current_active_runtime(build_steam_active_runtime())
dump_current_active_runtime(&build_steam_active_runtime())
}
fn build_profile_active_runtime(profile: Profile) -> ActiveRuntime {
pub fn build_profile_active_runtime(profile: &Profile) -> ActiveRuntime {
ActiveRuntime {
file_format_version: "1.0.0".into(),
runtime: ActiveRuntimeInnerRuntime {
@ -93,7 +100,7 @@ fn build_profile_active_runtime(profile: Profile) -> ActiveRuntime {
}
}
pub fn set_current_active_runtime_to_profile(profile: Profile) {
pub fn set_current_active_runtime_to_profile(profile: &Profile) {
let pfx = profile.clone().prefix;
let mut ar = build_profile_active_runtime(profile);
// hack: relativize libopenxr_monado.so path for system installs
@ -111,7 +118,7 @@ pub fn set_current_active_runtime_to_profile(profile: Profile) {
rels = rel_chain.join("/")
);
}
dump_current_active_runtime(ar);
dump_current_active_runtime(&ar);
}
#[cfg(test)]
@ -146,6 +153,6 @@ mod tests {
name: Some("SteamVR".into()),
},
};
dump_active_runtime_to_path(ar, "./target/testout/active_runtime.json.steamvr".into());
dump_active_runtime_to_path(&ar, &"./target/testout/active_runtime.json.steamvr".into());
}
}

View file

@ -17,14 +17,21 @@ pub struct OpenVrPaths {
version: u32,
}
fn get_openvrpaths_vrpath_path() -> String {
pub fn get_openvr_conf_dir() -> String {
format!(
"{config}/openvr/openvrpaths.vrpath",
"{config}/openvr",
config = get_xdg_config_dir()
)
}
pub fn is_steam(ovr_paths: OpenVrPaths) -> bool {
fn get_openvrpaths_vrpath_path() -> String {
format!(
"{config}/openvrpaths.vrpath",
config = get_openvr_conf_dir()
)
}
pub fn is_steam(ovr_paths: &OpenVrPaths) -> bool {
ovr_paths
.runtime
.iter()
@ -43,15 +50,15 @@ pub fn get_current_openvrpaths() -> Option<OpenVrPaths> {
get_openvrpaths_from_path(&get_openvrpaths_vrpath_path())
}
fn dump_openvrpaths_to_path(ovr_paths: OpenVrPaths, path_s: String) {
set_file_radonly(&path_s, false);
let writer = get_writer(&path_s);
serde_json::to_writer_pretty(writer, &ovr_paths).expect_dialog("Unable to save openvrpaths");
set_file_radonly(&path_s, true);
fn dump_openvrpaths_to_path(ovr_paths: &OpenVrPaths, path_s: &String) {
set_file_radonly(path_s, false);
let writer = get_writer(path_s);
serde_json::to_writer_pretty(writer, ovr_paths).expect_dialog("Unable to save openvrpaths");
set_file_radonly(path_s, true);
}
pub fn dump_current_openvrpaths(ovr_paths: OpenVrPaths) {
dump_openvrpaths_to_path(ovr_paths, get_openvrpaths_vrpath_path())
pub fn dump_current_openvrpaths(ovr_paths: &OpenVrPaths) {
dump_openvrpaths_to_path(ovr_paths, &get_openvrpaths_vrpath_path())
}
fn build_steam_openvrpaths() -> OpenVrPaths {
@ -70,10 +77,10 @@ fn build_steam_openvrpaths() -> OpenVrPaths {
}
pub fn set_current_openvrpaths_to_steam() {
dump_current_openvrpaths(build_steam_openvrpaths())
dump_current_openvrpaths(&build_steam_openvrpaths())
}
fn build_profile_openvrpaths(profile: Profile) -> OpenVrPaths {
pub fn build_profile_openvrpaths(profile: &Profile) -> OpenVrPaths {
let datadir = get_xdg_data_dir();
OpenVrPaths {
config: vec![format!("{data}/Steam/config", data = datadir)],
@ -88,8 +95,8 @@ fn build_profile_openvrpaths(profile: Profile) -> OpenVrPaths {
}
}
pub fn set_current_openvrpaths_to_profile(profile: Profile) {
dump_current_openvrpaths(build_profile_openvrpaths(profile))
pub fn set_current_openvrpaths_to_profile(profile: &Profile) {
dump_current_openvrpaths(&build_profile_openvrpaths(profile))
}
#[cfg(test)]
@ -119,6 +126,6 @@ mod tests {
runtime: vec!["/home/user/.local/share/Steam/steamapps/common/SteamVR".into()],
version: 1,
};
dump_openvrpaths_to_path(ovrp, "./target/testout/openvrpaths.vrpath".into())
dump_openvrpaths_to_path(&ovrp, &"./target/testout/openvrpaths.vrpath".into())
}
}

View file

@ -2,7 +2,7 @@ use crate::{constants::CMD_NAME, runner::Runner};
use expect_dialog::ExpectDialog;
use std::{
env,
fs::{self, create_dir_all, File, OpenOptions},
fs::{self, create_dir_all, remove_dir_all, File, OpenOptions},
io::{BufReader, BufWriter},
path::Path,
};
@ -78,6 +78,10 @@ pub fn get_xdg_cache_dir() -> String {
}
}
pub fn get_xdg_runtime_dir() -> String {
env::var("XDG_RUNTIME_DIR").expect_dialog("XDG_RUNTIME_DIR is not set")
}
pub fn get_config_dir() -> String {
format!(
"{config}/{name}",
@ -137,3 +141,10 @@ pub fn get_exec_prefix() -> String {
.unwrap()
.to_string()
}
pub fn rm_rf(path_s: &String) {
match remove_dir_all(path_s) {
Err(_) => println!("Failed to remove path {}", path_s),
Ok(_) => {}
}
}

View file

@ -173,27 +173,32 @@ impl Default 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_{runtime}.json",
prefix = match self.prefix.as_str() {
SYSTEM_PREFIX => BWRAP_SYSTEM_PREFIX,
other => other,
},
runtime = match self.xrservice_type {
XRServiceType::Monado => "monado",
XRServiceType::Wivrn => "wivrn",
}
));
opts.push(format!(
"PRESSURE_VESSEL_FILESYSTEMS_RW=$XDG_RUNTIME_DIR/{xrservice}_comp_ipc",
xrservice = match self.xrservice_type {
XRServiceType::Monado => "monado",
XRServiceType::Wivrn => "wivrn",
}
));
opts.push("%command%".into());
opts.join(" ")
vec![
format!(
"VR_OVERRIDE={opencomp}/build",
opencomp = self.opencomposite_path,
),
format!(
"XR_RUNTIME_JSON={prefix}/share/openxr/1/openxr_{runtime}.json",
prefix = match self.prefix.as_str() {
SYSTEM_PREFIX => BWRAP_SYSTEM_PREFIX,
other => other,
},
runtime = match self.xrservice_type {
XRServiceType::Monado => "monado",
XRServiceType::Wivrn => "wivrn",
}
),
format!(
"PRESSURE_VESSEL_FILESYSTEMS_RW=$XDG_RUNTIME_DIR/{xrservice}_comp_ipc",
xrservice = match self.xrservice_type {
XRServiceType::Monado => "monado",
XRServiceType::Wivrn => "wivrn",
}
),
"%command%".into(),
]
.join(" ")
}
pub fn load_profile(path: &String) -> Self {

View file

@ -18,6 +18,8 @@ use crate::dependencies::mercury_deps::get_missing_mercury_deps;
use crate::dependencies::monado_deps::get_missing_monado_deps;
use crate::dependencies::pkexec_dep::pkexec_dep;
use crate::dependencies::wivrn_deps::get_missing_wivrn_deps;
use crate::file_builders::active_runtime_json::{set_current_active_runtime_to_profile, set_current_active_runtime_to_steam};
use crate::file_builders::openvrpaths_vrpath::{set_current_openvrpaths_to_profile, set_current_openvrpaths_to_steam};
use crate::file_utils::setcap_cap_sys_nice_eip;
use crate::log_parser::MonadoLog;
use crate::profile::{Profile, XRServiceType};
@ -94,7 +96,6 @@ pub enum Msg {
OpenLibsurviveSetup,
Quit,
ProcessDevicesLog(Vec<String>),
InhibitSession(bool),
}
impl App {
@ -134,6 +135,8 @@ impl App {
pub fn start_xrservice(&mut self) {
self.set_inhibit_session(true);
let prof = self.get_selected_profile();
set_current_active_runtime_to_profile(&prof);
set_current_openvrpaths_to_profile(&prof);
self.devices_processed = match prof.xrservice_type {
XRServiceType::Monado => false,
XRServiceType::Wivrn => true, // no device from log in wivrn
@ -156,6 +159,20 @@ impl App {
};
}
pub fn shutdown_xrservice(&mut self) {
if self.xrservice_runner.is_some() {
if self.xrservice_runner.as_mut().unwrap().status() == RunnerStatus::Running {
self.xrservice_runner.as_mut().unwrap().terminate();
}
}
set_current_active_runtime_to_steam();
set_current_openvrpaths_to_steam();
self.set_inhibit_session(false);
self.main_view
.sender()
.emit(MainViewMsg::XRServiceActiveChanged(false, None));
}
pub fn profiles_list(config: &Config) -> Vec<Profile> {
let mut profiles = vec![
valve_index_profile(),
@ -200,17 +217,18 @@ impl SimpleComponent for App {
},
model.debug_view.widget(),
}
}
},
}
}
fn shutdown(&mut self, widgets: &mut Self::Widgets, output: relm4::Sender<Self::Output>) {
match &mut self.xrservice_runner {
None => {}
Some(runner) => {
runner.terminate();
if self.xrservice_runner.is_some() {
if self.xrservice_runner.as_mut().unwrap().status() == RunnerStatus::Running {
self.xrservice_runner.as_mut().unwrap().terminate();
}
}
set_current_active_runtime_to_steam();
set_current_openvrpaths_to_steam();
}
fn update(&mut self, message: Self::Input, sender: ComponentSender<Self>) {
@ -320,18 +338,13 @@ impl SimpleComponent for App {
}
Some(runner) => match runner.status() {
RunnerStatus::Running => {
sender.input(Msg::InhibitSession(false));
runner.terminate();
self.main_view
.sender()
.emit(MainViewMsg::XRServiceActiveChanged(false, None));
self.shutdown_xrservice();
}
RunnerStatus::Stopped(_) => {
self.start_xrservice();
}
},
},
Msg::InhibitSession(state) => self.set_inhibit_session(state),
Msg::BuildProfile => {
let profile = self.get_selected_profile();
let mut missing_deps = vec![];

View file

@ -1,9 +1,6 @@
use super::devices_box::{DevicesBox, DevicesBoxMsg};
use super::install_wivrn_box::{InstallWivrnBox, InstallWivrnBoxInit, InstallWivrnBoxMsg};
use super::profile_editor::{ProfileEditor, ProfileEditorMsg, ProfileEditorOutMsg};
use super::runtime_switcher_box::{
RuntimeSwitcherBox, RuntimeSwitcherBoxInit, RuntimeSwitcherBoxMsg,
};
use super::steam_launch_options_box::{SteamLaunchOptionsBox, SteamLaunchOptionsBoxMsg};
use crate::config::Config;
use crate::constants::APP_NAME;
@ -32,8 +29,6 @@ pub struct MainView {
#[tracker::do_not_track]
steam_launch_options_box: Controller<SteamLaunchOptionsBox>,
#[tracker::do_not_track]
runtime_switcher_box: Controller<RuntimeSwitcherBox>,
#[tracker::do_not_track]
devices_box: Controller<DevicesBox>,
#[tracker::do_not_track]
profile_editor: Controller<ProfileEditor>,
@ -147,7 +142,6 @@ impl SimpleComponent for MainView {
},
},
model.devices_box.widget(),
model.runtime_switcher_box.widget(),
model.steam_launch_options_box.widget(),
model.install_wivrn_box.widget(),
}
@ -250,9 +244,6 @@ impl SimpleComponent for MainView {
self.install_wivrn_box
.sender()
.emit(InstallWivrnBoxMsg::UpdateSelectedProfile(prof.clone()));
self.runtime_switcher_box
.sender()
.emit(RuntimeSwitcherBoxMsg::UpdateSelectedProfile(prof.clone()));
}
Self::Input::UpdateProfiles(profiles, config) => {
self.set_profiles(profiles);
@ -376,11 +367,6 @@ impl SimpleComponent for MainView {
root_win: init.root_win.clone(),
})
.detach(),
runtime_switcher_box: RuntimeSwitcherBox::builder()
.launch(RuntimeSwitcherBoxInit {
selected_profile: init.selected_profile.clone(),
})
.detach(),
profile_editor: ProfileEditor::builder()
.launch(ProfileEditorInit {
root_win: init.root_win.clone(),

View file

@ -6,7 +6,6 @@ pub mod build_window;
pub mod libsurvive_setup_window;
pub mod install_wivrn_box;
pub mod steam_launch_options_box;
pub mod runtime_switcher_box;
pub mod profile_editor;
pub mod factories;
pub mod wivrn_conf_editor;

View file

@ -1,109 +0,0 @@
use relm4::prelude::*;
use gtk::prelude::*;
use crate::{constants::APP_NAME, file_builders::{active_runtime_json::{get_current_active_runtime, self, set_current_active_runtime_to_profile, set_current_active_runtime_to_steam}, openvrpaths_vrpath::{set_current_openvrpaths_to_profile, set_current_openvrpaths_to_steam}}, profile::Profile};
pub struct RuntimeSwitcherBox {
selected_profile: Profile,
}
#[derive(Debug)]
pub enum RuntimeSwitcherBoxMsg {
UpdateSelectedProfile(Profile),
SetXRServiceRuntime(bool),
}
pub struct RuntimeSwitcherBoxInit {
pub selected_profile: Profile,
}
#[relm4::component(pub)]
impl SimpleComponent for RuntimeSwitcherBox {
type Init = RuntimeSwitcherBoxInit;
type Input = RuntimeSwitcherBoxMsg;
type Output = ();
view! {
gtk::Box {
set_orientation: gtk::Orientation::Vertical,
set_hexpand: true,
set_spacing: 12,
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: "OpenXR/OpenVR Runtime",
set_wrap: true,
set_wrap_mode: gtk::pango::WrapMode::Word,
},
gtk::Box {
set_orientation: gtk::Orientation::Horizontal,
set_hexpand: true,
set_halign: gtk::Align::Start,
set_margin_start: 12,
set_margin_end: 12,
set_spacing: 12,
gtk::Label {
set_label: "Steam",
},
#[name(runtime_switch)]
gtk::Switch {
},
gtk::Label {
set_label: APP_NAME,
},
},
}
}
fn update(&mut self, message: Self::Input, sender: ComponentSender<Self>) {
match message {
Self::Input::UpdateSelectedProfile(prof) => {
self.selected_profile = prof;
}
Self::Input::SetXRServiceRuntime(is_rex) => {
if is_rex {
set_current_active_runtime_to_profile(self.selected_profile.clone());
set_current_openvrpaths_to_profile(self.selected_profile.clone());
} else {
set_current_active_runtime_to_steam();
set_current_openvrpaths_to_steam();
}
}
}
}
fn init(
init: Self::Init,
root: &Self::Root,
sender: ComponentSender<Self>,
) -> ComponentParts<Self> {
let model = Self {
selected_profile: init.selected_profile,
};
let widgets = view_output!();
{
match get_current_active_runtime() {
None => {}
Some(runtime) => {
widgets
.runtime_switch
.set_active(!active_runtime_json::is_steam(runtime));
}
}
widgets.runtime_switch.connect_state_set(move |_, state| {
sender.input(Self::Input::SetXRServiceRuntime(state));
gtk::Inhibit(false)
});
}
ComponentParts { model, widgets }
}
}

View file

@ -64,22 +64,24 @@ impl SimpleComponent for SteamLaunchOptionsBox {
set_margin_end: 12,
set_orientation: gtk::Orientation::Horizontal,
set_spacing: 6,
gtk::TextView {
gtk::ScrolledWindow {
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(Self::launch_options())"]
set_text: model.launch_options.as_str(),
set_vscrollbar_policy: gtk::PolicyType::Never,
set_overflow: gtk::Overflow::Hidden,
gtk::TextView {
set_hexpand: true,
set_vexpand: false,
set_monospace: true,
set_editable: false,
set_left_margin: 6,
set_right_margin: 6,
set_top_margin: 6,
set_bottom_margin: 18,
#[wrap(Some)]
set_buffer: cmdbuf = &gtk::TextBuffer {
#[track = "model.changed(Self::launch_options())"]
set_text: model.launch_options.as_str(),
}
}
},
gtk::Button {