mirror of
https://gitlab.com/gabmus/envision.git
synced 2025-04-21 03:54:49 +00:00
Merge branch 'main' into feat/stardust
This commit is contained in:
commit
1f37b27de0
9 changed files with 192 additions and 88 deletions
|
@ -1,4 +1,4 @@
|
|||
image: "debian:testing"
|
||||
image: "debian:unstable"
|
||||
|
||||
stages:
|
||||
- check
|
||||
|
|
|
@ -12,7 +12,7 @@ Also consider that due to the unstable nature of the app, it's possible to encou
|
|||
|
||||
UI for building, configuring and running Monado, the open source OpenXR runtime.
|
||||
|
||||
Download the latest AppImage snapshot: [GitLab Pipelines](https://gitlab.com/gabmus/envision/-/pipelines)
|
||||
Download the latest AppImage snapshot: [GitLab Pipelines](https://gitlab.com/gabmus/envision/-/pipelines?page=1&scope=all&ref=main)
|
||||
|
||||
## Running
|
||||
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
#[macro_export]
|
||||
macro_rules! checkerr {
|
||||
($ex:expr) => {
|
||||
if $ex.is_err() {
|
||||
return Err(());
|
||||
}
|
||||
};
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
use crate::{
|
||||
checkerr,
|
||||
file_utils::{copy_file, deserialize_file, get_writer, set_file_readonly},
|
||||
paths::{get_backup_dir, get_xdg_config_dir, get_xdg_data_dir, SYSTEM_PREFIX},
|
||||
profile::{Profile, XRServiceType},
|
||||
|
@ -97,9 +96,9 @@ fn build_steam_active_runtime() -> ActiveRuntime {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn set_current_active_runtime_to_steam() -> Result<(), ()> {
|
||||
checkerr!(set_file_readonly(&get_active_runtime_json_path(), false));
|
||||
checkerr!(dump_current_active_runtime(&build_steam_active_runtime()));
|
||||
pub fn set_current_active_runtime_to_steam() -> anyhow::Result<()> {
|
||||
set_file_readonly(&get_active_runtime_json_path(), false)?;
|
||||
dump_current_active_runtime(&build_steam_active_runtime())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -156,9 +155,9 @@ fn relativize_active_runtime_lib_path(ar: &ActiveRuntime, dest: &str) -> ActiveR
|
|||
res
|
||||
}
|
||||
|
||||
pub fn set_current_active_runtime_to_profile(profile: &Profile) -> Result<(), ()> {
|
||||
pub fn set_current_active_runtime_to_profile(profile: &Profile) -> anyhow::Result<()> {
|
||||
let dest = get_active_runtime_json_path();
|
||||
checkerr!(set_file_readonly(&dest, false));
|
||||
set_file_readonly(&dest, false)?;
|
||||
backup_steam_active_runtime();
|
||||
let pfx = profile.clone().prefix;
|
||||
let mut ar = build_profile_active_runtime(profile);
|
||||
|
@ -166,8 +165,8 @@ pub fn set_current_active_runtime_to_profile(profile: &Profile) -> Result<(), ()
|
|||
if pfx == SYSTEM_PREFIX {
|
||||
ar = relativize_active_runtime_lib_path(&ar, &dest);
|
||||
}
|
||||
checkerr!(dump_current_active_runtime(&ar));
|
||||
checkerr!(set_file_readonly(&dest, true));
|
||||
dump_current_active_runtime(&ar)?;
|
||||
set_file_readonly(&dest, true)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use crate::{
|
||||
checkerr,
|
||||
file_utils::{copy_file, deserialize_file, get_writer, set_file_readonly},
|
||||
paths::{get_backup_dir, get_xdg_config_dir, get_xdg_data_dir},
|
||||
profile::Profile,
|
||||
|
@ -94,9 +93,9 @@ fn build_steam_openvrpaths() -> OpenVrPaths {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn set_current_openvrpaths_to_steam() -> Result<(), ()> {
|
||||
checkerr!(set_file_readonly(&get_openvrpaths_vrpath_path(), false));
|
||||
checkerr!(dump_current_openvrpaths(&build_steam_openvrpaths()));
|
||||
pub fn set_current_openvrpaths_to_steam() -> anyhow::Result<()> {
|
||||
set_file_readonly(&get_openvrpaths_vrpath_path(), false)?;
|
||||
dump_current_openvrpaths(&build_steam_openvrpaths())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -115,14 +114,12 @@ pub fn build_profile_openvrpaths(profile: &Profile) -> OpenVrPaths {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn set_current_openvrpaths_to_profile(profile: &Profile) -> Result<(), ()> {
|
||||
pub fn set_current_openvrpaths_to_profile(profile: &Profile) -> anyhow::Result<()> {
|
||||
let dest = get_openvrpaths_vrpath_path();
|
||||
checkerr!(set_file_readonly(&dest, false));
|
||||
set_file_readonly(&dest, false)?;
|
||||
backup_steam_openvrpaths();
|
||||
checkerr!(dump_current_openvrpaths(&build_profile_openvrpaths(
|
||||
profile
|
||||
)));
|
||||
checkerr!(set_file_readonly(&dest, true));
|
||||
dump_current_openvrpaths(&build_profile_openvrpaths(profile))?;
|
||||
set_file_readonly(&dest, true)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -9,39 +9,56 @@ pub enum LinuxDistro {
|
|||
Debian,
|
||||
Fedora,
|
||||
Gentoo,
|
||||
// TODO: add Nix,
|
||||
Suse,
|
||||
}
|
||||
|
||||
pub fn get_distro() -> Option<LinuxDistro> {
|
||||
if let Some(mut reader) = get_reader("/etc/issue") {
|
||||
let mut buf = String::default();
|
||||
if reader.read_to_string(&mut buf).is_ok() {
|
||||
buf = buf.trim().to_lowercase();
|
||||
if buf.contains("arch linux")
|
||||
|| buf.contains("manjaro")
|
||||
|| buf.contains("steamos")
|
||||
|| buf.contains("steam os")
|
||||
{
|
||||
return Some(LinuxDistro::Arch);
|
||||
}
|
||||
if buf.contains("debian")
|
||||
|| buf.contains("ubuntu")
|
||||
|| buf.contains("mint")
|
||||
|| buf.contains("elementary")
|
||||
|| buf.contains("pop")
|
||||
{
|
||||
return Some(LinuxDistro::Debian);
|
||||
}
|
||||
if buf.contains("fedora") || buf.contains("nobara") {
|
||||
return Some(LinuxDistro::Fedora);
|
||||
}
|
||||
if buf.contains("gentoo") {
|
||||
return Some(LinuxDistro::Gentoo);
|
||||
}
|
||||
if buf.contains("alpine") || buf.contains("postmarket") {
|
||||
return Some(LinuxDistro::Alpine);
|
||||
impl LinuxDistro {
|
||||
pub fn get() -> Option<Self> {
|
||||
if let Some(mut reader) = get_reader("/etc/issue") {
|
||||
let mut buf = String::default();
|
||||
if reader.read_to_string(&mut buf).is_ok() {
|
||||
buf = buf.trim().to_lowercase();
|
||||
if buf.contains("arch linux")
|
||||
|| buf.contains("manjaro")
|
||||
|| buf.contains("steamos")
|
||||
|| buf.contains("steam os")
|
||||
{
|
||||
return Some(Self::Arch);
|
||||
}
|
||||
if buf.contains("debian")
|
||||
|| buf.contains("ubuntu")
|
||||
|| buf.contains("mint")
|
||||
|| buf.contains("elementary")
|
||||
|| buf.contains("pop")
|
||||
{
|
||||
return Some(Self::Debian);
|
||||
}
|
||||
if buf.contains("fedora") || buf.contains("nobara") {
|
||||
return Some(Self::Fedora);
|
||||
}
|
||||
if buf.contains("gentoo") {
|
||||
return Some(Self::Gentoo);
|
||||
}
|
||||
if buf.contains("alpine") || buf.contains("postmarket") {
|
||||
return Some(Self::Alpine);
|
||||
}
|
||||
|
||||
// TODO: detect suse, sles, rhel, nix
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
None
|
||||
pub fn install_command(&self, packages: &[String]) -> String {
|
||||
match self {
|
||||
Self::Arch => format!("sudo pacman -Syu {}", packages.join(" ")),
|
||||
Self::Alpine => format!("sudo apk add {}", packages.join(" ")),
|
||||
Self::Debian => format!("sudo apt install {}", packages.join(" ")),
|
||||
Self::Fedora => format!("sudo dnf install {}", packages.join(" ")),
|
||||
Self::Gentoo => format!("sudo emerge {}", packages.join(" ")),
|
||||
Self::Suse => format!("sudo zypper install {}", packages.join(" ")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,6 @@ use ui::app::{App, AppInit};
|
|||
pub mod adb;
|
||||
pub mod build_tools;
|
||||
pub mod builders;
|
||||
pub mod checkerr;
|
||||
pub mod cmd_runner;
|
||||
pub mod config;
|
||||
pub mod constants;
|
||||
|
@ -49,7 +48,7 @@ fn restore_steam_xr_files() {
|
|||
if !file_builders::active_runtime_json::is_steam(&ar) {
|
||||
match set_current_active_runtime_to_steam() {
|
||||
Ok(_) => {}
|
||||
Err(_) => println!("Warning: failed to restore active runtime to steam!"),
|
||||
Err(e) => eprintln!("Warning: failed to restore active runtime to steam: {e}"),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +56,7 @@ fn restore_steam_xr_files() {
|
|||
if !file_builders::openvrpaths_vrpath::is_steam(&ovrp) {
|
||||
match set_current_openvrpaths_to_steam() {
|
||||
Ok(_) => {}
|
||||
Err(_) => println!("Warning: failed to restore openvrpaths to steam!"),
|
||||
Err(e) => eprintln!("Warning: failed to restore openvrpaths to steam: {e}"),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
use gtk::traits::{GtkApplicationExt, GtkWindowExt};
|
||||
use gtk::{
|
||||
prelude::IsA,
|
||||
traits::{GtkApplicationExt, GtkWindowExt},
|
||||
};
|
||||
use relm4::{adw::traits::MessageDialogExt, prelude::*};
|
||||
|
||||
pub fn alert(title: &str, msg: Option<&str>, parent: Option<>k::Window>) {
|
||||
fn alert_base(title: &str, msg: Option<&str>, parent: Option<>k::Window>) -> adw::MessageDialog {
|
||||
let d = adw::MessageDialog::builder()
|
||||
.modal(true)
|
||||
.heading(title)
|
||||
|
@ -15,5 +18,23 @@ pub fn alert(title: &str, msg: Option<&str>, parent: Option<>k::Window>) {
|
|||
d.set_transient_for(gtk::Application::default().active_window().as_ref());
|
||||
}
|
||||
d.add_response("ok", "_Ok");
|
||||
d
|
||||
}
|
||||
|
||||
pub fn alert(title: &str, msg: Option<&str>, parent: Option<>k::Window>) {
|
||||
let d = alert_base(title, msg, parent);
|
||||
d.present();
|
||||
}
|
||||
|
||||
pub fn alert_w_widget(
|
||||
title: &str,
|
||||
msg: Option<&str>,
|
||||
widget: Option<>k::Widget>,
|
||||
parent: Option<>k::Window>,
|
||||
) {
|
||||
let d = alert_base(title, msg, parent);
|
||||
if let Some(w) = widget {
|
||||
d.set_extra_child(Some(w));
|
||||
}
|
||||
d.present();
|
||||
}
|
||||
|
|
131
src/ui/app.rs
131
src/ui/app.rs
|
@ -1,5 +1,5 @@
|
|||
use super::about_dialog::AboutDialog;
|
||||
use super::alert::alert;
|
||||
use super::alert::{alert, alert_w_widget};
|
||||
use super::build_window::{BuildStatus, BuildWindow};
|
||||
use super::debug_view::{DebugView, DebugViewMsg};
|
||||
use super::fbt_config_editor::{FbtConfigEditor, FbtConfigEditorInit, FbtConfigEditorMsg};
|
||||
|
@ -8,7 +8,7 @@ use super::job_worker::job::WorkerJob;
|
|||
use super::job_worker::JobWorker;
|
||||
use super::libsurvive_setup_window::LibsurviveSetupWindow;
|
||||
use super::main_view::MainViewMsg;
|
||||
use super::util::open_with_default_handler;
|
||||
use super::util::{copy_text, open_with_default_handler};
|
||||
use super::wivrn_conf_editor::{WivrnConfEditor, WivrnConfEditorInit, WivrnConfEditorMsg};
|
||||
use crate::builders::build_basalt::get_build_basalt_jobs;
|
||||
use crate::builders::build_libsurvive::get_build_libsurvive_jobs;
|
||||
|
@ -34,7 +34,7 @@ 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::linux_distro::get_distro;
|
||||
use crate::linux_distro::LinuxDistro;
|
||||
use crate::log_parser::MonadoLog;
|
||||
use crate::paths::{get_data_dir, get_ipc_file_path};
|
||||
use crate::profile::{Profile, XRServiceType};
|
||||
|
@ -162,18 +162,22 @@ impl App {
|
|||
|
||||
pub fn start_xrservice(&mut self, sender: ComponentSender<Self>, debug: bool) {
|
||||
let prof = self.get_selected_profile();
|
||||
if set_current_active_runtime_to_profile(&prof).is_err() {
|
||||
if let Err(e) = set_current_active_runtime_to_profile(&prof) {
|
||||
alert(
|
||||
"Failed to start XR Service",
|
||||
Some("Error setting current active runtime to profile"),
|
||||
Some(&format!(
|
||||
"Error setting current active runtime to profile: {e}"
|
||||
)),
|
||||
Some(&self.app_win.clone().upcast::<gtk::Window>()),
|
||||
);
|
||||
return;
|
||||
}
|
||||
if set_current_openvrpaths_to_profile(&prof).is_err() {
|
||||
if let Err(e) = set_current_openvrpaths_to_profile(&prof) {
|
||||
alert(
|
||||
"Failed to start XR Service",
|
||||
Some("Error setting current openvrpaths file to profile"),
|
||||
Some(&format!(
|
||||
"Error setting current openvrpaths file to profile: {e}"
|
||||
)),
|
||||
Some(&self.app_win.clone().upcast::<gtk::Window>()),
|
||||
);
|
||||
return;
|
||||
|
@ -218,17 +222,17 @@ impl App {
|
|||
}
|
||||
|
||||
pub fn restore_openxr_openvr_files(&self) {
|
||||
if set_current_active_runtime_to_steam().is_err() {
|
||||
if let Err(e) = set_current_active_runtime_to_steam() {
|
||||
alert(
|
||||
"Could not restore Steam active runtime",
|
||||
None,
|
||||
Some(&format!("{e}")),
|
||||
Some(&self.app_win.clone().upcast::<gtk::Window>()),
|
||||
);
|
||||
}
|
||||
if set_current_openvrpaths_to_steam().is_err() {
|
||||
if let Err(e) = set_current_openvrpaths_to_steam() {
|
||||
alert(
|
||||
"Could not restore Steam openvrpaths",
|
||||
None,
|
||||
Some(&format!("{e}")),
|
||||
Some(&self.app_win.clone().upcast::<gtk::Window>()),
|
||||
);
|
||||
};
|
||||
|
@ -466,26 +470,101 @@ impl SimpleComponent for App {
|
|||
if !missing_deps.is_empty() {
|
||||
missing_deps.sort_unstable();
|
||||
missing_deps.dedup(); // dedup only works if sorted, hence the above
|
||||
let distro = get_distro();
|
||||
alert(
|
||||
"Missing dependencies:",
|
||||
Some(
|
||||
let distro = LinuxDistro::get();
|
||||
let (missing_package_list, install_missing_widget): (
|
||||
String,
|
||||
Option<gtk::Widget>,
|
||||
) = if let Some(d) = distro {
|
||||
(
|
||||
missing_deps
|
||||
.iter()
|
||||
.map(|dep| {
|
||||
if let Some(d) = distro {
|
||||
return dep
|
||||
.packages
|
||||
.get(&d)
|
||||
.unwrap_or_else(|| &dep.name)
|
||||
.clone();
|
||||
}
|
||||
dep.name.clone()
|
||||
dep.packages.get(&d).unwrap_or_else(|| &dep.name).clone()
|
||||
})
|
||||
.collect::<Vec<String>>()
|
||||
.join(", ")
|
||||
.as_str(),
|
||||
),
|
||||
.join(", "),
|
||||
{
|
||||
let packages = missing_deps
|
||||
.iter()
|
||||
.filter_map(|dep| {
|
||||
dep.packages.get(&d).and_then(|s| Some(s.clone()))
|
||||
})
|
||||
.collect::<Vec<String>>();
|
||||
if packages.is_empty() {
|
||||
None
|
||||
} else {
|
||||
let cmd = d.install_command(&packages);
|
||||
{
|
||||
let container = gtk::Box::builder()
|
||||
.orientation(gtk::Orientation::Horizontal)
|
||||
.spacing(6)
|
||||
.build();
|
||||
let btn = gtk::Button::builder()
|
||||
.css_classes(["flat", "circular"])
|
||||
.tooltip_text("Copy")
|
||||
.icon_name("edit-copy-symbolic")
|
||||
.vexpand(false)
|
||||
.hexpand(false)
|
||||
.valign(gtk::Align::Center)
|
||||
.halign(gtk::Align::Center)
|
||||
.build();
|
||||
btn.connect_clicked(
|
||||
clone!(@strong cmd => move |_| copy_text(&cmd)),
|
||||
);
|
||||
container.append(
|
||||
>k::ScrolledWindow::builder()
|
||||
.vscrollbar_policy(gtk::PolicyType::Never)
|
||||
.hscrollbar_policy(gtk::PolicyType::Automatic)
|
||||
.css_classes(["card"])
|
||||
.overflow(gtk::Overflow::Hidden)
|
||||
.child(
|
||||
>k::TextView::builder()
|
||||
.hexpand(true)
|
||||
.vexpand(false)
|
||||
.monospace(true)
|
||||
.editable(false)
|
||||
.left_margin(6)
|
||||
.right_margin(6)
|
||||
.top_margin(6)
|
||||
.bottom_margin(18)
|
||||
.buffer(
|
||||
>k::TextBuffer::builder()
|
||||
.text(&cmd)
|
||||
.enable_undo(false)
|
||||
.build(),
|
||||
)
|
||||
.build(),
|
||||
)
|
||||
.build(),
|
||||
);
|
||||
container.append(&btn);
|
||||
Some(container.upcast())
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
} else {
|
||||
(
|
||||
missing_deps
|
||||
.iter()
|
||||
.map(|dep| dep.name.clone())
|
||||
.collect::<Vec<String>>()
|
||||
.join(", "),
|
||||
None,
|
||||
)
|
||||
};
|
||||
alert_w_widget(
|
||||
"Missing dependencies:",
|
||||
Some(&format!(
|
||||
"{}{}",
|
||||
missing_package_list,
|
||||
if install_missing_widget.is_some() {
|
||||
"\n\nYou can install them with the following command:"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
)),
|
||||
install_missing_widget.as_ref(),
|
||||
Some(&self.app_win.clone().upcast::<gtk::Window>()),
|
||||
);
|
||||
return;
|
||||
|
|
Loading…
Add table
Reference in a new issue