mirror of
https://gitlab.com/gabmus/envision.git
synced 2025-08-03 14:49:04 +00:00
Compare commits
No commits in common. "main" and "3.1.0" have entirely different histories.
44 changed files with 242 additions and 735 deletions
25
Cargo.lock
generated
25
Cargo.lock
generated
|
@ -445,16 +445,6 @@ dependencies = [
|
||||||
"typenum",
|
"typenum",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "delicious-adwaita"
|
|
||||||
version = "0.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e53548c789a95211e0ce6d26c213067002b9b4360f8de69046d84de78ad9da3f"
|
|
||||||
dependencies = [
|
|
||||||
"gtk4",
|
|
||||||
"libadwaita",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deranged"
|
name = "deranged"
|
||||||
version = "0.3.11"
|
version = "0.3.11"
|
||||||
|
@ -573,11 +563,10 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "envision"
|
name = "envision"
|
||||||
version = "3.1.1"
|
version = "3.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"ash",
|
"ash",
|
||||||
"delicious-adwaita",
|
|
||||||
"gettext-rs",
|
"gettext-rs",
|
||||||
"git2",
|
"git2",
|
||||||
"gtk4",
|
"gtk4",
|
||||||
|
@ -1084,9 +1073,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gtk4"
|
name = "gtk4"
|
||||||
version = "0.9.6"
|
version = "0.9.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "af1c491051f030994fd0cde6f3c44f3f5640210308cff1298c7673c47408091d"
|
checksum = "9376d14d7e33486c54823a42bef296e882b9f25cb4c52b52f4d1d57bbadb5b6d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cairo-rs",
|
"cairo-rs",
|
||||||
"field-offset",
|
"field-offset",
|
||||||
|
@ -1117,9 +1106,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gtk4-sys"
|
name = "gtk4-sys"
|
||||||
version = "0.9.6"
|
version = "0.9.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "41e03b01e54d77c310e1d98647d73f996d04b2f29b9121fe493ea525a7ec03d6"
|
checksum = "e653b0a9001ba9be1ffddb9373bfe9a111f688222f5aeee2841481300d91b55a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cairo-sys-rs",
|
"cairo-sys-rs",
|
||||||
"gdk-pixbuf-sys",
|
"gdk-pixbuf-sys",
|
||||||
|
@ -1534,9 +1523,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libadwaita"
|
name = "libadwaita"
|
||||||
version = "0.7.2"
|
version = "0.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "500135d29c16aabf67baafd3e7741d48e8b8978ca98bac39e589165c8dc78191"
|
checksum = "8611ee9fb85e7606c362b513afcaf5b59853f79e4d98caaaf581d99465014247"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gdk4",
|
"gdk4",
|
||||||
"gio",
|
"gio",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "envision"
|
name = "envision"
|
||||||
version = "3.1.1"
|
version = "3.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
authors = [
|
authors = [
|
||||||
"Gabriele Musco <gabmus@disroot.org>",
|
"Gabriele Musco <gabmus@disroot.org>",
|
||||||
|
@ -44,4 +44,3 @@ tracing-subscriber = { version = "0.3.19", features = ["env-filter", "json"] }
|
||||||
tracing = "0.1.41"
|
tracing = "0.1.41"
|
||||||
tracing-appender = "0.2.3"
|
tracing-appender = "0.2.3"
|
||||||
serde_yaml = "0.9.34"
|
serde_yaml = "0.9.34"
|
||||||
delicious-adwaita = { version = "0.3.0", features = ["all_themes"] }
|
|
||||||
|
|
|
@ -30,15 +30,6 @@
|
||||||
<url type="bugtracker">@REPO_URL@/issues</url>
|
<url type="bugtracker">@REPO_URL@/issues</url>
|
||||||
<content_rating type="oars-1.0" />
|
<content_rating type="oars-1.0" />
|
||||||
<releases>
|
<releases>
|
||||||
<release version="3.1.1" date="2025-04-22">
|
|
||||||
<description>
|
|
||||||
<p>Fixes</p>
|
|
||||||
<ul>
|
|
||||||
<li>add libusb and libusb-dev deps</li>
|
|
||||||
<li>Revert "disable and blacklist wayvr dashboard plugin"</li>
|
|
||||||
</ul>
|
|
||||||
</description>
|
|
||||||
</release>
|
|
||||||
<release version="3.1.0" date="2025-04-08">
|
<release version="3.1.0" date="2025-04-08">
|
||||||
<description>
|
<description>
|
||||||
<p>What's new</p>
|
<p>What's new</p>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
project(
|
project(
|
||||||
'envision',
|
'envision',
|
||||||
'rust',
|
'rust',
|
||||||
version: '3.1.1', # version number row
|
version: '3.1.0', # version number row
|
||||||
meson_version: '>= 0.59',
|
meson_version: '>= 0.59',
|
||||||
license: 'AGPL-3.0-or-later',
|
license: 'AGPL-3.0-or-later',
|
||||||
)
|
)
|
||||||
|
|
|
@ -2,6 +2,57 @@
|
||||||
|
|
||||||
set -ev
|
set -ev
|
||||||
|
|
||||||
|
PREFIX=$1
|
||||||
|
|
||||||
|
CACHE_DIR=$2
|
||||||
|
|
||||||
|
if [[ -z $PREFIX ]] || [[ -z $CACHE_DIR ]]; then
|
||||||
|
echo "Usage: $0 PREFIX CACHE_DIR"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
ONNX_RELEASES=$(curl -sSL "https://api.github.com/repos/microsoft/onnxruntime/releases")
|
||||||
|
NUM_RELEASES=$(echo "$ONNX_RELEASES" | jq -r '[ select (.[]!=null) ] | length')
|
||||||
|
|
||||||
|
for (( IDX=0; IDX<NUM_RELEASES; IDX++ )); do
|
||||||
|
ASSETS_LEN=$(echo "$ONNX_RELEASES" | jq -r ".[$IDX].assets_url" | xargs -n 1 curl -sSL | jq -r '[ select (.[]!=null) ] | length')
|
||||||
|
if [[ $ASSETS_LEN -gt 0 ]]; then
|
||||||
|
ONNX_VER=$(echo "$ONNX_RELEASES" | jq -r ".[$IDX].tag_name" | tr -d v)
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ -z $ONNX_VER ]]; then
|
||||||
|
echo "Failed to find a suitable ONNX Runtime release."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
SYS_ARCH=$(uname -m)
|
||||||
|
|
||||||
|
if [[ $SYS_ARCH == x*64 ]]; then
|
||||||
|
ARCH="x64"
|
||||||
|
elif [[ $SYS_ARCH == arm64 ]] || [[ $ARCH == aarch64 ]]; then
|
||||||
|
ARCH="aarch64"
|
||||||
|
else
|
||||||
|
echo "CPU architecture '$SYS_ARCH' is not supported"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
ONNX="onnxruntime-linux-${ARCH}-${ONNX_VER}"
|
||||||
|
ONNX_URL="https://github.com/microsoft/onnxruntime/releases/download/v${ONNX_VER}/${ONNX}.tgz"
|
||||||
|
|
||||||
|
mkdir -p "$CACHE_DIR"
|
||||||
|
|
||||||
|
curl -sSL "$ONNX_URL" -o "${CACHE_DIR}/onnxruntime.tgz"
|
||||||
|
|
||||||
|
tar xf "${CACHE_DIR}/onnxruntime.tgz" --directory="${CACHE_DIR}"
|
||||||
|
|
||||||
|
mkdir -p "${PREFIX}/lib"
|
||||||
|
mkdir -p "${PREFIX}/include"
|
||||||
|
|
||||||
|
cp -r "${CACHE_DIR}/${ONNX}/include/"* "${PREFIX}/include/"
|
||||||
|
cp -r "${CACHE_DIR}/${ONNX}/lib/"* "${PREFIX}/lib/"
|
||||||
|
|
||||||
if [[ -z $XDG_DATA_HOME ]]; then
|
if [[ -z $XDG_DATA_HOME ]]; then
|
||||||
DATA_HOME=$HOME/.local/share
|
DATA_HOME=$HOME/.local/share
|
||||||
else
|
else
|
||||||
|
|
|
@ -22,7 +22,7 @@ impl Cmake {
|
||||||
if k.contains(' ') {
|
if k.contains(' ') {
|
||||||
panic!("Cmake vars cannot contain spaces!");
|
panic!("Cmake vars cannot contain spaces!");
|
||||||
}
|
}
|
||||||
args.push(format!("-D{k}={v}"));
|
args.push(format!("-D{k}={v}", k = k, v = v));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
args.push(self.source_dir.to_string_lossy().to_string());
|
args.push(self.source_dir.to_string_lossy().to_string());
|
||||||
|
|
|
@ -5,10 +5,7 @@ use crate::{
|
||||||
ui::job_worker::job::WorkerJob,
|
ui::job_worker::job::WorkerJob,
|
||||||
util::file_utils::rm_rf,
|
util::file_utils::rm_rf,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::collections::{HashMap, VecDeque};
|
||||||
collections::{HashMap, VecDeque},
|
|
||||||
num::NonZero,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn get_build_basalt_jobs(profile: &Profile, clean_build: bool) -> VecDeque<WorkerJob> {
|
pub fn get_build_basalt_jobs(profile: &Profile, clean_build: bool) -> VecDeque<WorkerJob> {
|
||||||
let mut jobs = VecDeque::<WorkerJob>::new();
|
let mut jobs = VecDeque::<WorkerJob>::new();
|
||||||
|
@ -43,24 +40,11 @@ pub fn get_build_basalt_jobs(profile: &Profile, clean_build: bool) -> VecDeque<W
|
||||||
env: Some({
|
env: Some({
|
||||||
let mut cmake_env: HashMap<String, String> = HashMap::new();
|
let mut cmake_env: HashMap<String, String> = HashMap::new();
|
||||||
for (k, v) in [
|
for (k, v) in [
|
||||||
// The basalt build uses a lot of RAM, so we have to limit the number of
|
("CMAKE_BUILD_PARALLEL_LEVEL", "2"),
|
||||||
// build processes to not starve the system of memory
|
("CMAKE_BUILD_TYPE", "RelWithDebInfo"),
|
||||||
// Limit to 6 build processes at most
|
("BUILD_TESTS", "off"),
|
||||||
(
|
|
||||||
"CMAKE_BUILD_PARALLEL_LEVEL",
|
|
||||||
std::cmp::min(
|
|
||||||
6,
|
|
||||||
std::thread::available_parallelism()
|
|
||||||
.map(NonZero::get)
|
|
||||||
.unwrap_or(2),
|
|
||||||
)
|
|
||||||
.to_string(),
|
|
||||||
),
|
|
||||||
("CMAKE_BUILD_TYPE", "RelWithDebInfo".into()),
|
|
||||||
("CMAKE_POLICY_VERSION_MINIMUM", "3.5".into()),
|
|
||||||
("BUILD_TESTS", "off".into()),
|
|
||||||
] {
|
] {
|
||||||
cmake_env.insert(k.to_string(), v);
|
cmake_env.insert(k.to_string(), v.to_string());
|
||||||
}
|
}
|
||||||
cmake_env
|
cmake_env
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
use crate::{constants::pkg_data_dir, termcolor::TermColor, ui::job_worker::job::WorkerJob};
|
use crate::{
|
||||||
|
constants::pkg_data_dir, paths::get_cache_dir, profile::Profile, termcolor::TermColor,
|
||||||
|
ui::job_worker::job::WorkerJob,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn get_build_mercury_jobs() -> VecDeque<WorkerJob> {
|
pub fn get_build_mercury_jobs(profile: &Profile) -> VecDeque<WorkerJob> {
|
||||||
let mut jobs = VecDeque::new();
|
let mut jobs = VecDeque::new();
|
||||||
jobs.push_back(WorkerJob::new_printer(
|
jobs.push_back(WorkerJob::new_printer(
|
||||||
"Building Mercury...",
|
"Building Mercury...",
|
||||||
|
@ -14,7 +17,10 @@ pub fn get_build_mercury_jobs() -> VecDeque<WorkerJob> {
|
||||||
.join("scripts/build_mercury.sh")
|
.join("scripts/build_mercury.sh")
|
||||||
.to_string_lossy()
|
.to_string_lossy()
|
||||||
.to_string(),
|
.to_string(),
|
||||||
None,
|
Some(vec![
|
||||||
|
profile.prefix.to_string_lossy().to_string(),
|
||||||
|
get_cache_dir().to_string_lossy().to_string(),
|
||||||
|
]),
|
||||||
));
|
));
|
||||||
|
|
||||||
jobs
|
jobs
|
||||||
|
|
|
@ -2,11 +2,12 @@ use crate::{
|
||||||
build_tools::{cmake::Cmake, git::Git},
|
build_tools::{cmake::Cmake, git::Git},
|
||||||
profile::Profile,
|
profile::Profile,
|
||||||
termcolor::TermColor,
|
termcolor::TermColor,
|
||||||
ui::job_worker::job::WorkerJob,
|
ui::job_worker::job::{FuncWorkerData, FuncWorkerOut, WorkerJob},
|
||||||
util::file_utils::rm_rf,
|
util::file_utils::{copy_file, rm_rf},
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
collections::{HashMap, VecDeque},
|
collections::{HashMap, VecDeque},
|
||||||
|
fs::create_dir_all,
|
||||||
path::Path,
|
path::Path,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -36,22 +37,16 @@ pub fn get_build_vapor_jobs(profile: &Profile, clean_build: bool) -> VecDeque<Wo
|
||||||
jobs.extend(git.get_pre_build_jobs(profile.pull_on_build));
|
jobs.extend(git.get_pre_build_jobs(profile.pull_on_build));
|
||||||
|
|
||||||
let build_dir = profile.ovr_comp.path.join("build");
|
let build_dir = profile.ovr_comp.path.join("build");
|
||||||
let install_dir = build_dir.join("install_pfx");
|
|
||||||
let cmake = Cmake {
|
let cmake = Cmake {
|
||||||
env: None,
|
env: None,
|
||||||
vars: Some({
|
vars: Some({
|
||||||
let mut cmake_vars: HashMap<String, String> = HashMap::new();
|
let mut cmake_vars: HashMap<String, String> = HashMap::new();
|
||||||
for (k, v) in [
|
for (k, v) in [
|
||||||
("VAPOR_LOG_SILENT", "ON"),
|
("VAPOR_LOG_SILENT=ON", "ON"),
|
||||||
("USE_SYSTEM_OPENXR", "OFF"),
|
|
||||||
("CMAKE_BUILD_TYPE", "RelWithDebInfo"),
|
("CMAKE_BUILD_TYPE", "RelWithDebInfo"),
|
||||||
] {
|
] {
|
||||||
cmake_vars.insert(k.to_string(), v.to_string());
|
cmake_vars.insert(k.to_string(), v.to_string());
|
||||||
}
|
}
|
||||||
cmake_vars.insert(
|
|
||||||
"CMAKE_INSTALL_PREFIX".into(),
|
|
||||||
install_dir.to_string_lossy().to_string(),
|
|
||||||
);
|
|
||||||
cmake_vars
|
cmake_vars
|
||||||
}),
|
}),
|
||||||
source_dir: profile.ovr_comp.path.clone(),
|
source_dir: profile.ovr_comp.path.clone(),
|
||||||
|
@ -62,7 +57,29 @@ pub fn get_build_vapor_jobs(profile: &Profile, clean_build: bool) -> VecDeque<Wo
|
||||||
jobs.push_back(cmake.get_prepare_job());
|
jobs.push_back(cmake.get_prepare_job());
|
||||||
}
|
}
|
||||||
jobs.push_back(cmake.get_build_job());
|
jobs.push_back(cmake.get_build_job());
|
||||||
jobs.push_back(cmake.get_install_job());
|
jobs.push_back(WorkerJob::Func(FuncWorkerData {
|
||||||
|
func: Box::new(move || {
|
||||||
|
let dest_dir = build_dir.join("bin/linux64");
|
||||||
|
if let Err(e) = create_dir_all(&dest_dir) {
|
||||||
|
return FuncWorkerOut {
|
||||||
|
success: false,
|
||||||
|
out: vec![format!(
|
||||||
|
"failed to create dir {}: {e}",
|
||||||
|
dest_dir.to_string_lossy()
|
||||||
|
)],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
copy_file(
|
||||||
|
&build_dir.join("src/vrclient.so"),
|
||||||
|
&dest_dir.join("vrclient.so"),
|
||||||
|
);
|
||||||
|
|
||||||
|
FuncWorkerOut {
|
||||||
|
success: true,
|
||||||
|
out: Vec::default(),
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
jobs
|
jobs
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,10 +45,6 @@ const fn default_win_size() -> [i32; 2] {
|
||||||
DEFAULT_WIN_SIZE
|
DEFAULT_WIN_SIZE
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_theme_name() -> String {
|
|
||||||
"Follow system".into()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub selected_profile_uuid: String,
|
pub selected_profile_uuid: String,
|
||||||
|
@ -58,8 +54,6 @@ pub struct Config {
|
||||||
pub win_size: [i32; 2],
|
pub win_size: [i32; 2],
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub plugins: HashMap<String, PluginConfig>,
|
pub plugins: HashMap<String, PluginConfig>,
|
||||||
#[serde(default = "default_theme_name")]
|
|
||||||
pub theme_name: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
|
@ -71,7 +65,6 @@ impl Default for Config {
|
||||||
user_profiles: Vec::default(),
|
user_profiles: Vec::default(),
|
||||||
win_size: DEFAULT_WIN_SIZE,
|
win_size: DEFAULT_WIN_SIZE,
|
||||||
plugins: HashMap::default(),
|
plugins: HashMap::default(),
|
||||||
theme_name: default_theme_name(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use super::{
|
use super::{
|
||||||
boost_deps::boost_deps,
|
boost_deps::boost_deps,
|
||||||
common::{dep_cmake, dep_eigen, dep_gpp, dep_libgl, dep_ninja, dep_opencv},
|
common::{dep_cmake, dep_eigen, dep_gpp, dep_libgl, dep_ninja, dep_opencv},
|
||||||
DepType, DepcheckResultGetMissing, Dependency, DependencyCheckResult,
|
DepType, Dependency, DependencyCheckResult,
|
||||||
};
|
};
|
||||||
use crate::linux_distro::LinuxDistro;
|
use crate::linux_distro::LinuxDistro;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
@ -181,5 +181,9 @@ pub fn check_basalt_deps() -> Vec<DependencyCheckResult> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_missing_basalt_deps() -> Vec<Dependency> {
|
pub fn get_missing_basalt_deps() -> Vec<Dependency> {
|
||||||
check_basalt_deps().filter_missing_deps()
|
check_basalt_deps()
|
||||||
|
.iter()
|
||||||
|
.filter(|res| !res.found)
|
||||||
|
.map(|res| res.dependency.clone())
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
|
@ -303,35 +303,3 @@ pub fn dep_adb() -> Dependency {
|
||||||
]),
|
]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dep_getcap_setcap() -> Dependency {
|
|
||||||
Dependency {
|
|
||||||
name: "libcap".into(),
|
|
||||||
dep_type: DepType::Executable,
|
|
||||||
filename: "setcap".into(),
|
|
||||||
packages: HashMap::from([
|
|
||||||
(LinuxDistro::Arch, "libcap".into()),
|
|
||||||
(LinuxDistro::Debian, "libcap2-bin".into()),
|
|
||||||
(LinuxDistro::Fedora, "libcap".into()),
|
|
||||||
(LinuxDistro::Alpine, "libcap".into()),
|
|
||||||
(LinuxDistro::Gentoo, "sys-libs/libcap".into()),
|
|
||||||
(LinuxDistro::Suse, "libcap-progs".into()),
|
|
||||||
]),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn dep_glslc() -> Dependency {
|
|
||||||
Dependency {
|
|
||||||
name: "glslc".into(),
|
|
||||||
dep_type: DepType::Executable,
|
|
||||||
filename: "glslc".into(),
|
|
||||||
packages: HashMap::from([
|
|
||||||
(LinuxDistro::Arch, "shaderc".into()),
|
|
||||||
(LinuxDistro::Debian, "glslc".into()),
|
|
||||||
(LinuxDistro::Fedora, "glslc".into()),
|
|
||||||
(LinuxDistro::Alpine, "shaderc".into()),
|
|
||||||
(LinuxDistro::Gentoo, "media-libs/shaderc".into()),
|
|
||||||
(LinuxDistro::Suse, "shaderc".into()),
|
|
||||||
]),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use super::{
|
use super::{
|
||||||
common::{dep_cmake, dep_eigen, dep_gcc, dep_git, dep_gpp, dep_ninja},
|
common::{dep_cmake, dep_eigen, dep_gcc, dep_git, dep_gpp, dep_ninja},
|
||||||
DepcheckResultGetMissing, Dependency, DependencyCheckResult,
|
Dependency, DependencyCheckResult,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn libsurvive_deps() -> Vec<Dependency> {
|
fn libsurvive_deps() -> Vec<Dependency> {
|
||||||
|
@ -19,5 +19,9 @@ pub fn check_libsurvive_deps() -> Vec<DependencyCheckResult> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_missing_libsurvive_deps() -> Vec<Dependency> {
|
pub fn get_missing_libsurvive_deps() -> Vec<Dependency> {
|
||||||
check_libsurvive_deps().filter_missing_deps()
|
check_libsurvive_deps()
|
||||||
|
.iter()
|
||||||
|
.filter(|res| !res.found)
|
||||||
|
.map(|res| res.dependency.clone())
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,27 +1,10 @@
|
||||||
use super::{
|
use super::{common::dep_opencv, DepType, Dependency, DependencyCheckResult};
|
||||||
common::dep_opencv, DepType, DepcheckResultGetMissing, Dependency, DependencyCheckResult,
|
|
||||||
};
|
|
||||||
use crate::linux_distro::LinuxDistro;
|
use crate::linux_distro::LinuxDistro;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
fn mercury_deps() -> Vec<Dependency> {
|
fn mercury_deps() -> Vec<Dependency> {
|
||||||
vec![
|
vec![
|
||||||
dep_opencv(),
|
dep_opencv(),
|
||||||
Dependency {
|
|
||||||
name: "onnxruntime-dev".into(),
|
|
||||||
dep_type: DepType::Include,
|
|
||||||
filename: "onnxruntime/onnxruntime_c_api.h".into(),
|
|
||||||
packages: HashMap::from([
|
|
||||||
(LinuxDistro::Arch, "onnxruntime".into()),
|
|
||||||
(LinuxDistro::Debian, "libonnxruntime-dev".into()),
|
|
||||||
(LinuxDistro::Fedora, "onnxruntime-devel".into()),
|
|
||||||
// alpine doesn't seem to have the package
|
|
||||||
// (LinuxDistro::Alpine, "".into()),
|
|
||||||
(LinuxDistro::Gentoo, "sci-ml/onnx".into()),
|
|
||||||
// opensuse doesn't seem to have the package
|
|
||||||
// (LinuxDistro::Suse, "".into()),
|
|
||||||
]),
|
|
||||||
},
|
|
||||||
Dependency {
|
Dependency {
|
||||||
name: "jq".into(),
|
name: "jq".into(),
|
||||||
dep_type: DepType::Executable,
|
dep_type: DepType::Executable,
|
||||||
|
@ -56,5 +39,9 @@ pub fn check_mercury_deps() -> Vec<DependencyCheckResult> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_missing_mercury_deps() -> Vec<Dependency> {
|
pub fn get_missing_mercury_deps() -> Vec<Dependency> {
|
||||||
check_mercury_deps().filter_missing_deps()
|
check_mercury_deps()
|
||||||
|
.iter()
|
||||||
|
.filter(|res| !res.found)
|
||||||
|
.map(|res| res.dependency.clone())
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ pub mod mercury_deps;
|
||||||
pub mod monado_deps;
|
pub mod monado_deps;
|
||||||
pub mod openhmd_deps;
|
pub mod openhmd_deps;
|
||||||
pub mod wivrn_deps;
|
pub mod wivrn_deps;
|
||||||
pub mod xrizer_deps;
|
|
||||||
|
|
||||||
use crate::linux_distro::LinuxDistro;
|
use crate::linux_distro::LinuxDistro;
|
||||||
use std::{collections::HashMap, env, fmt::Display, path::Path};
|
use std::{collections::HashMap, env, fmt::Display, path::Path};
|
||||||
|
@ -109,24 +108,6 @@ impl Display for DependencyCheckResult {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait DepcheckResultGetMissing {
|
|
||||||
fn filter_missing_deps(self) -> Vec<Dependency>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DepcheckResultGetMissing for Vec<DependencyCheckResult> {
|
|
||||||
fn filter_missing_deps(self) -> Vec<Dependency> {
|
|
||||||
self.into_iter()
|
|
||||||
.filter_map(|res| {
|
|
||||||
if !res.found {
|
|
||||||
Some(res.dependency)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn shared_obj_paths() -> Vec<String> {
|
fn shared_obj_paths() -> Vec<String> {
|
||||||
vec![
|
vec![
|
||||||
"/lib".into(),
|
"/lib".into(),
|
||||||
|
@ -136,24 +117,6 @@ fn shared_obj_paths() -> Vec<String> {
|
||||||
"/usr/local/lib64".into(),
|
"/usr/local/lib64".into(),
|
||||||
"/usr/lib/x86_64-linux-gnu".into(),
|
"/usr/lib/x86_64-linux-gnu".into(),
|
||||||
"/usr/lib/aarch64-linux-gnu".into(),
|
"/usr/lib/aarch64-linux-gnu".into(),
|
||||||
// Debian puts libclang in /usr/lib/llvm-[llvm major version]/lib.
|
|
||||||
"/usr/lib/llvm-15/lib".into(),
|
|
||||||
"/usr/lib/llvm-16/lib".into(),
|
|
||||||
"/usr/lib/llvm-19/lib".into(),
|
|
||||||
// Fedora puts libclang in /usr/lib64/llvm[llvm major version]/lib as well as /usr/lib64.
|
|
||||||
"/usr/lib64/llvm15/lib".into(),
|
|
||||||
"/usr/lib64/llvm16/lib".into(),
|
|
||||||
"/usr/lib64/llvm17/lib".into(),
|
|
||||||
"/usr/lib64/llvm18/lib".into(),
|
|
||||||
"/usr/lib64/llvm19/lib".into(),
|
|
||||||
"/usr/lib64/llvm20/lib".into(),
|
|
||||||
// Gentoo puts libclang in /usr/lib/llvm/[llvm major version]/lib64.
|
|
||||||
"/usr/lib/llvm/15/lib64".into(),
|
|
||||||
"/usr/lib/llvm/16/lib64".into(),
|
|
||||||
"/usr/lib/llvm/17/lib64".into(),
|
|
||||||
"/usr/lib/llvm/18/lib64".into(),
|
|
||||||
"/usr/lib/llvm/19/lib64".into(),
|
|
||||||
"/usr/lib/llvm/20/lib64".into(),
|
|
||||||
"/lib/x86_64-linux-gnu".into(),
|
"/lib/x86_64-linux-gnu".into(),
|
||||||
"/lib/aarch64-linux-gnu".into(),
|
"/lib/aarch64-linux-gnu".into(),
|
||||||
"/app/lib".into(),
|
"/app/lib".into(),
|
||||||
|
@ -177,8 +140,6 @@ fn include_paths() -> Vec<String> {
|
||||||
"/usr/include/ffmpeg/libpostproc".into(),
|
"/usr/include/ffmpeg/libpostproc".into(),
|
||||||
"/usr/include/ffmpeg/libswresample".into(),
|
"/usr/include/ffmpeg/libswresample".into(),
|
||||||
"/usr/include/ffmpeg/libswscale".into(),
|
"/usr/include/ffmpeg/libswscale".into(),
|
||||||
// opensuse puts wayland-client.h here
|
|
||||||
"/usr/include/wayland".into(),
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,12 +4,9 @@ use super::{
|
||||||
dep_libgl, dep_libudev, dep_libx11, dep_libxcb, dep_ninja, dep_openxr, dep_vulkan_headers,
|
dep_libgl, dep_libudev, dep_libx11, dep_libxcb, dep_ninja, dep_openxr, dep_vulkan_headers,
|
||||||
dep_vulkan_icd_loader,
|
dep_vulkan_icd_loader,
|
||||||
},
|
},
|
||||||
DepType, DepcheckResultGetMissing, Dependency, DependencyCheckResult,
|
DepType, Dependency, DependencyCheckResult,
|
||||||
};
|
|
||||||
use crate::{
|
|
||||||
depcheck::common::{dep_glslc, dep_libxrandr},
|
|
||||||
linux_distro::LinuxDistro,
|
|
||||||
};
|
};
|
||||||
|
use crate::{depcheck::common::dep_libxrandr, linux_distro::LinuxDistro};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
fn monado_deps() -> Vec<Dependency> {
|
fn monado_deps() -> Vec<Dependency> {
|
||||||
|
@ -63,7 +60,19 @@ fn monado_deps() -> Vec<Dependency> {
|
||||||
dep_ninja(),
|
dep_ninja(),
|
||||||
dep_gcc(),
|
dep_gcc(),
|
||||||
dep_gpp(),
|
dep_gpp(),
|
||||||
dep_glslc(),
|
Dependency {
|
||||||
|
name: "glslc".into(),
|
||||||
|
dep_type: DepType::Executable,
|
||||||
|
filename: "glslc".into(),
|
||||||
|
packages: HashMap::from([
|
||||||
|
(LinuxDistro::Arch, "shaderc".into()),
|
||||||
|
(LinuxDistro::Debian, "glslc".into()),
|
||||||
|
(LinuxDistro::Fedora, "glslc".into()),
|
||||||
|
(LinuxDistro::Alpine, "shaderc".into()),
|
||||||
|
(LinuxDistro::Gentoo, "media-libs/shaderc".into()),
|
||||||
|
(LinuxDistro::Suse, "shaderc".into()),
|
||||||
|
]),
|
||||||
|
},
|
||||||
dep_glslang_validator(),
|
dep_glslang_validator(),
|
||||||
Dependency {
|
Dependency {
|
||||||
name: "sdl2".into(),
|
name: "sdl2".into(),
|
||||||
|
@ -74,34 +83,10 @@ fn monado_deps() -> Vec<Dependency> {
|
||||||
(LinuxDistro::Debian, "libsdl2-dev".into()),
|
(LinuxDistro::Debian, "libsdl2-dev".into()),
|
||||||
(LinuxDistro::Fedora, "SDL2-devel".into()),
|
(LinuxDistro::Fedora, "SDL2-devel".into()),
|
||||||
(LinuxDistro::Gentoo, "media-libs/libsdl2".into()),
|
(LinuxDistro::Gentoo, "media-libs/libsdl2".into()),
|
||||||
(LinuxDistro::Suse, "sdl2-compat-devel".into()),
|
(LinuxDistro::Suse, "SDL2-devel".into()),
|
||||||
]),
|
]),
|
||||||
},
|
},
|
||||||
dep_libudev(),
|
dep_libudev(),
|
||||||
Dependency {
|
|
||||||
name: "libusb".into(),
|
|
||||||
dep_type: DepType::SharedObject,
|
|
||||||
filename: "libusb-1.0.so".into(),
|
|
||||||
packages: HashMap::from([
|
|
||||||
(LinuxDistro::Arch, "libusb".into()),
|
|
||||||
(LinuxDistro::Debian, "libusb-1.0-0".into()),
|
|
||||||
(LinuxDistro::Fedora, "libusb1".into()),
|
|
||||||
(LinuxDistro::Gentoo, "dev-libs/libusb".into()),
|
|
||||||
(LinuxDistro::Suse, "libusb-1_0-0".into()),
|
|
||||||
]),
|
|
||||||
},
|
|
||||||
Dependency {
|
|
||||||
name: "libusb-dev".into(),
|
|
||||||
dep_type: DepType::Include,
|
|
||||||
filename: "libusb-1.0/libusb.h".into(),
|
|
||||||
packages: HashMap::from([
|
|
||||||
(LinuxDistro::Arch, "libusb".into()),
|
|
||||||
(LinuxDistro::Debian, "libusb-1.0-0-dev".into()),
|
|
||||||
(LinuxDistro::Fedora, "libusb1-devel".into()),
|
|
||||||
(LinuxDistro::Gentoo, "dev-libs/libusb".into()),
|
|
||||||
(LinuxDistro::Suse, "libusb-1_0-devel".into()),
|
|
||||||
]),
|
|
||||||
},
|
|
||||||
Dependency {
|
Dependency {
|
||||||
name: "mesa-common-dev".into(),
|
name: "mesa-common-dev".into(),
|
||||||
dep_type: DepType::Include,
|
dep_type: DepType::Include,
|
||||||
|
@ -122,5 +107,9 @@ pub fn check_monado_deps() -> Vec<DependencyCheckResult> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_missing_monado_deps() -> Vec<Dependency> {
|
pub fn get_missing_monado_deps() -> Vec<Dependency> {
|
||||||
check_monado_deps().filter_missing_deps()
|
check_monado_deps()
|
||||||
|
.iter()
|
||||||
|
.filter(|res| !res.found)
|
||||||
|
.map(|res| res.dependency.clone())
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use super::{
|
use super::{
|
||||||
common::{dep_gcc, dep_git, dep_gpp, dep_ninja},
|
common::{dep_gcc, dep_git, dep_gpp, dep_ninja},
|
||||||
DepcheckResultGetMissing, Dependency, DependencyCheckResult,
|
Dependency, DependencyCheckResult,
|
||||||
};
|
};
|
||||||
use crate::linux_distro::LinuxDistro;
|
use crate::linux_distro::LinuxDistro;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
@ -31,5 +31,9 @@ pub fn check_openhmd_deps() -> Vec<DependencyCheckResult> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_missing_openhmd_deps() -> Vec<Dependency> {
|
pub fn get_missing_openhmd_deps() -> Vec<Dependency> {
|
||||||
check_openhmd_deps().filter_missing_deps()
|
check_openhmd_deps()
|
||||||
|
.iter()
|
||||||
|
.filter(|res| !res.found)
|
||||||
|
.map(|res| res.dependency.clone())
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use super::{
|
||||||
dep_libudev, dep_libx11, dep_libxcb, dep_ninja, dep_openxr, dep_vulkan_headers,
|
dep_libudev, dep_libx11, dep_libxcb, dep_ninja, dep_openxr, dep_vulkan_headers,
|
||||||
dep_vulkan_icd_loader,
|
dep_vulkan_icd_loader,
|
||||||
},
|
},
|
||||||
DepType, DepcheckResultGetMissing, Dependency, DependencyCheckResult,
|
DepType, Dependency, DependencyCheckResult,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
depcheck::common::{dep_libgl, dep_libxrandr},
|
depcheck::common::{dep_libgl, dep_libxrandr},
|
||||||
|
@ -270,5 +270,9 @@ pub fn check_wivrn_deps() -> Vec<DependencyCheckResult> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_missing_wivrn_deps() -> Vec<Dependency> {
|
pub fn get_missing_wivrn_deps() -> Vec<Dependency> {
|
||||||
check_wivrn_deps().filter_missing_deps()
|
check_wivrn_deps()
|
||||||
|
.iter()
|
||||||
|
.filter(|res| !res.found)
|
||||||
|
.map(|res| res.dependency.clone())
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,65 +0,0 @@
|
||||||
use super::{DepType, DepcheckResultGetMissing, Dependency, DependencyCheckResult};
|
|
||||||
use crate::{depcheck::common::dep_glslc, linux_distro::LinuxDistro};
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
fn xrizer_deps() -> Vec<Dependency> {
|
|
||||||
vec![
|
|
||||||
dep_glslc(),
|
|
||||||
Dependency {
|
|
||||||
name: "cargo".into(),
|
|
||||||
dep_type: DepType::Executable,
|
|
||||||
filename: "cargo".into(),
|
|
||||||
packages: HashMap::from([
|
|
||||||
(LinuxDistro::Arch, "rust".into()),
|
|
||||||
(LinuxDistro::Debian, "cargo".into()),
|
|
||||||
(LinuxDistro::Fedora, "cargo".into()),
|
|
||||||
(LinuxDistro::Alpine, "cargo".into()),
|
|
||||||
(LinuxDistro::Suse, "cargo".into()),
|
|
||||||
]),
|
|
||||||
},
|
|
||||||
Dependency {
|
|
||||||
name: "libxcb-glx".into(),
|
|
||||||
dep_type: DepType::Include,
|
|
||||||
filename: "xcb/glx.h".into(),
|
|
||||||
packages: HashMap::from([
|
|
||||||
(LinuxDistro::Arch, "libxcb".into()),
|
|
||||||
(LinuxDistro::Debian, "libxcb-glx0-dev".into()),
|
|
||||||
(LinuxDistro::Fedora, "libxcb-devel".into()),
|
|
||||||
(LinuxDistro::Gentoo, "x11-libs/libxcb".into()),
|
|
||||||
(LinuxDistro::Suse, "libxcb-devel".into()),
|
|
||||||
]),
|
|
||||||
},
|
|
||||||
Dependency {
|
|
||||||
name: "libclang".into(),
|
|
||||||
dep_type: DepType::SharedObject,
|
|
||||||
filename: "libclang.so".into(),
|
|
||||||
packages: HashMap::from([
|
|
||||||
(LinuxDistro::Arch, "clang".into()),
|
|
||||||
(LinuxDistro::Debian, "libclang-19-dev".into()),
|
|
||||||
(LinuxDistro::Fedora, "clang19-devel".into()),
|
|
||||||
(LinuxDistro::Gentoo, "llvm-core/clang-runtime".into()),
|
|
||||||
(LinuxDistro::Suse, "clang19-devel".into()),
|
|
||||||
]),
|
|
||||||
},
|
|
||||||
Dependency {
|
|
||||||
name: "wayland-dev".into(),
|
|
||||||
dep_type: DepType::Include,
|
|
||||||
filename: "wayland-client.h".into(),
|
|
||||||
packages: HashMap::from([
|
|
||||||
(LinuxDistro::Arch, "wayland".into()),
|
|
||||||
(LinuxDistro::Debian, "libwayland-dev".into()),
|
|
||||||
(LinuxDistro::Fedora, "wayland-devel".into()),
|
|
||||||
(LinuxDistro::Gentoo, "dev-libs/wayland".into()),
|
|
||||||
(LinuxDistro::Suse, "wayland-devel".into()),
|
|
||||||
]),
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn check_xrizer_deps() -> Vec<DependencyCheckResult> {
|
|
||||||
Dependency::check_many(xrizer_deps())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_missing_xrizer_deps() -> Vec<Dependency> {
|
|
||||||
check_xrizer_deps().filter_missing_deps()
|
|
||||||
}
|
|
|
@ -13,7 +13,7 @@ const CHUNK_SIZE: usize = 1024;
|
||||||
|
|
||||||
fn headers() -> HeaderMap {
|
fn headers() -> HeaderMap {
|
||||||
let mut headers = HeaderMap::new();
|
let mut headers = HeaderMap::new();
|
||||||
headers.insert(USER_AGENT, format!("{APP_ID}/1.0").parse().unwrap());
|
headers.insert(USER_AGENT, format!("{}/1.0", APP_ID).parse().unwrap());
|
||||||
headers
|
headers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,7 +65,7 @@ fn env_var_descriptions() -> Vec<(&'static str, &'static str)> {
|
||||||
fn env_var_descriptions_as_paragraph() -> String {
|
fn env_var_descriptions_as_paragraph() -> String {
|
||||||
ENV_VAR_DESCRIPTIONS
|
ENV_VAR_DESCRIPTIONS
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(k, v)| format!("<span size=\"large\" weight=\"bold\">{k}</span>\n{v}"))
|
.map(|(k, v)| format!("<span size=\"large\" weight=\"bold\">{}</span>\n{}", k, v))
|
||||||
.collect::<Vec<String>>()
|
.collect::<Vec<String>>()
|
||||||
.join("\n\n")
|
.join("\n\n")
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,7 +143,7 @@ pub struct WivrnConfig {
|
||||||
pub encoders: Vec<WivrnConfEncoder>,
|
pub encoders: Vec<WivrnConfEncoder>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub application: Option<WivrnConfigApplication>,
|
pub application: Option<WivrnConfigApplication>,
|
||||||
#[serde(default, rename = "tcp-only")]
|
#[serde(default)]
|
||||||
pub tcp_only: bool,
|
pub tcp_only: bool,
|
||||||
/// contains unknown fields
|
/// contains unknown fields
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
|
|
|
@ -116,7 +116,7 @@ fn list_gpus() -> Vec<GpuSysDrm> {
|
||||||
|
|
||||||
for i in 0..5 {
|
for i in 0..5 {
|
||||||
// arbitrary range, find a better way
|
// arbitrary range, find a better way
|
||||||
let card_dir = PathBuf::from(format!("/sys/class/drm/card{i}"));
|
let card_dir = PathBuf::from(format!("/sys/class/drm/card{}", i));
|
||||||
let vendor_file = card_dir.join("device/vendor");
|
let vendor_file = card_dir.join("device/vendor");
|
||||||
if let Some(mut reader) = get_reader(&vendor_file) {
|
if let Some(mut reader) = get_reader(&vendor_file) {
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
|
|
|
@ -115,7 +115,6 @@ impl LinuxDistro {
|
||||||
|| s.contains("steamos")
|
|| s.contains("steamos")
|
||||||
|| s.contains("steam os")
|
|| s.contains("steam os")
|
||||||
|| s.contains("endeavour")
|
|| s.contains("endeavour")
|
||||||
|| s.contains("cachyos")
|
|
||||||
|| s.contains("garuda")
|
|| s.contains("garuda")
|
||||||
{
|
{
|
||||||
return Some(Self::Arch);
|
return Some(Self::Arch);
|
||||||
|
@ -151,33 +150,7 @@ impl LinuxDistro {
|
||||||
Self::Alpine => format!("sudo apk add {}", packages.join(" ")),
|
Self::Alpine => format!("sudo apk add {}", packages.join(" ")),
|
||||||
Self::Debian => format!("sudo apt install {}", packages.join(" ")),
|
Self::Debian => format!("sudo apt install {}", packages.join(" ")),
|
||||||
Self::Gentoo => format!("sudo emerge -av {}", packages.join(" ")),
|
Self::Gentoo => format!("sudo emerge -av {}", packages.join(" ")),
|
||||||
Self::Suse => {
|
Self::Suse => format!("sudo zypper install {}", packages.join(" ")),
|
||||||
let mut opi_pkgs = Vec::new();
|
|
||||||
let mut zypper_pkgs = Vec::new();
|
|
||||||
for pkg in packages {
|
|
||||||
if ["OpenXR-SDK-devel"].contains(&pkg.as_str()) {
|
|
||||||
opi_pkgs.push(pkg.clone());
|
|
||||||
} else {
|
|
||||||
zypper_pkgs.push(pkg.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
[
|
|
||||||
if opi_pkgs.is_empty() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(format!("opi {}", opi_pkgs.join(" ")))
|
|
||||||
},
|
|
||||||
if zypper_pkgs.is_empty() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(format!("sudo zypper install {}", zypper_pkgs.join(" ")))
|
|
||||||
},
|
|
||||||
]
|
|
||||||
.iter()
|
|
||||||
.filter_map(|c| c.clone())
|
|
||||||
.collect::<Vec<String>>()
|
|
||||||
.join(" && ")
|
|
||||||
}
|
|
||||||
Self::Fedora => {
|
Self::Fedora => {
|
||||||
let mut install_rpmfusion_cmd: Option<String> = None;
|
let mut install_rpmfusion_cmd: Option<String> = None;
|
||||||
let mut swap_ffmpeg_cmd: Option<String> = None;
|
let mut swap_ffmpeg_cmd: Option<String> = None;
|
||||||
|
@ -217,10 +190,10 @@ impl LinuxDistro {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::LinuxDistro;
|
|
||||||
use crate::depcheck::common::{dep_openxr, dep_pkexec, dep_vulkan_icd_loader};
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
|
use super::LinuxDistro;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_detect_arch_linux_from_etc_os_release() {
|
fn can_detect_arch_linux_from_etc_os_release() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -230,34 +203,4 @@ mod tests {
|
||||||
Some(LinuxDistro::Arch)
|
Some(LinuxDistro::Arch)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn can_account_for_opensuse_opi_packages() {
|
|
||||||
assert_eq!(
|
|
||||||
LinuxDistro::Suse
|
|
||||||
.install_command(
|
|
||||||
&[dep_openxr(), dep_vulkan_icd_loader()]
|
|
||||||
.iter()
|
|
||||||
.map(|dep| dep.package_name_for_distro(Some(&LinuxDistro::Suse)))
|
|
||||||
.collect::<Vec<String>>()
|
|
||||||
)
|
|
||||||
.as_str(),
|
|
||||||
"opi OpenXR-SDK-devel && sudo zypper install vulkan-devel"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn opensuse_opi_does_not_interfere_if_not_needed() {
|
|
||||||
assert_eq!(
|
|
||||||
LinuxDistro::Suse
|
|
||||||
.install_command(
|
|
||||||
&[dep_pkexec(), dep_vulkan_icd_loader()]
|
|
||||||
.iter()
|
|
||||||
.map(|dep| dep.package_name_for_distro(Some(&LinuxDistro::Suse)))
|
|
||||||
.collect::<Vec<String>>()
|
|
||||||
)
|
|
||||||
.as_str(),
|
|
||||||
"sudo zypper install polkit vulkan-devel"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
66
src/main.rs
66
src/main.rs
|
@ -11,16 +11,9 @@ use relm4::{
|
||||||
gtk::{self, gdk, gio, glib, prelude::*},
|
gtk::{self, gdk, gio, glib, prelude::*},
|
||||||
MessageBroker, RelmApp,
|
MessageBroker, RelmApp,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::env;
|
||||||
env,
|
use steam_linux_runtime_injector::restore_runtime_entrypoint;
|
||||||
fs::{read_dir, remove_file},
|
use tracing::warn;
|
||||||
os::unix::fs::MetadataExt,
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
};
|
|
||||||
use steam_linux_runtime_injector::{
|
|
||||||
restore_sniper_runtime_entrypoint, restore_soldier_runtime_entrypoint,
|
|
||||||
};
|
|
||||||
use tracing::{error, warn};
|
|
||||||
use tracing_subscriber::{
|
use tracing_subscriber::{
|
||||||
filter::LevelFilter, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, Layer,
|
filter::LevelFilter, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, Layer,
|
||||||
};
|
};
|
||||||
|
@ -70,50 +63,7 @@ fn restore_steam_xr_files() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
restore_sniper_runtime_entrypoint();
|
restore_runtime_entrypoint();
|
||||||
restore_soldier_runtime_entrypoint();
|
|
||||||
}
|
|
||||||
|
|
||||||
const LOGS_MAX_SIZE_BYTES: u64 = 1000000000; // 1GB
|
|
||||||
|
|
||||||
fn remove_old_logs(dir: &Path, log_files: Option<Vec<PathBuf>>) -> anyhow::Result<()> {
|
|
||||||
let log_files: Vec<PathBuf> = log_files
|
|
||||||
.map::<anyhow::Result<Vec<PathBuf>>, _>(Ok)
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
let mut files: Vec<PathBuf> = read_dir(dir)?
|
|
||||||
.filter_map(|de| {
|
|
||||||
let p = de.ok()?.path();
|
|
||||||
if p.is_file() && !p.is_symlink() {
|
|
||||||
Some(p)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
files.sort_unstable();
|
|
||||||
Ok(files)
|
|
||||||
})?;
|
|
||||||
let total_size = log_files
|
|
||||||
.iter()
|
|
||||||
.filter_map(|p| Some(p.metadata().ok()?.size()))
|
|
||||||
.reduce(u64::saturating_add)
|
|
||||||
.unwrap_or(0);
|
|
||||||
// if size is under threshold, finish
|
|
||||||
if total_size < LOGS_MAX_SIZE_BYTES {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
// keep a minimum of 3 logs
|
|
||||||
if log_files.len() <= 3 {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
remove_file(log_files.first().ok_or_else(||
|
|
||||||
anyhow::Error::msg(
|
|
||||||
"Could not get first item in log files list, but they should be more than 3! This is a bug!"
|
|
||||||
)
|
|
||||||
)?)?;
|
|
||||||
|
|
||||||
remove_old_logs(dir, Some(log_files))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
|
@ -121,8 +71,6 @@ fn main() -> Result<()> {
|
||||||
panic!("{APP_NAME} cannot run as root");
|
panic!("{APP_NAME} cannot run as root");
|
||||||
}
|
}
|
||||||
restore_steam_xr_files();
|
restore_steam_xr_files();
|
||||||
// deferring error logging for this since tracing isn't initialized yet
|
|
||||||
let old_logs_removal_res = remove_old_logs(&get_logs_dir(), None);
|
|
||||||
|
|
||||||
let rolling_log_writer = tracing_appender::rolling::daily(get_logs_dir(), "log");
|
let rolling_log_writer = tracing_appender::rolling::daily(get_logs_dir(), "log");
|
||||||
let (non_blocking_appender, _appender_guard) =
|
let (non_blocking_appender, _appender_guard) =
|
||||||
|
@ -142,10 +90,6 @@ fn main() -> Result<()> {
|
||||||
)
|
)
|
||||||
.init();
|
.init();
|
||||||
|
|
||||||
if let Err(e) = old_logs_removal_res {
|
|
||||||
error!("Failed to remove old log files: {e}");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare i18n
|
// Prepare i18n
|
||||||
gettextrs::setlocale(LocaleCategory::LcAll, "");
|
gettextrs::setlocale(LocaleCategory::LcAll, "");
|
||||||
gettextrs::bindtextdomain(GETTEXT_PACKAGE, LOCALE_DIR).expect("Unable to bind the text domain");
|
gettextrs::bindtextdomain(GETTEXT_PACKAGE, LOCALE_DIR).expect("Unable to bind the text domain");
|
||||||
|
@ -160,7 +104,7 @@ fn main() -> Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let provider = gtk::CssProvider::new();
|
let provider = gtk::CssProvider::new();
|
||||||
provider.load_from_resource(&format!("{RESOURCES_BASE_PATH}/style.css"));
|
provider.load_from_resource(&format!("{}/style.css", RESOURCES_BASE_PATH));
|
||||||
if let Some(display) = gdk::Display::default() {
|
if let Some(display) = gdk::Display::default() {
|
||||||
gtk::style_context_add_provider_for_display(
|
gtk::style_context_add_provider_for_display(
|
||||||
&display,
|
&display,
|
||||||
|
|
|
@ -17,7 +17,7 @@ pub fn is_openxr_ready() -> bool {
|
||||||
|
|
||||||
let Ok(xr_instance) = entry.create_instance(
|
let Ok(xr_instance) = entry.create_instance(
|
||||||
&xr::ApplicationInfo {
|
&xr::ApplicationInfo {
|
||||||
application_name: &format!("{CMD_NAME}-openxr-prober"),
|
application_name: &format!("{}-openxr-prober", CMD_NAME),
|
||||||
application_version: 0,
|
application_version: 0,
|
||||||
engine_name: CMD_NAME,
|
engine_name: CMD_NAME,
|
||||||
engine_version: 0,
|
engine_version: 0,
|
||||||
|
|
|
@ -2,8 +2,7 @@ use crate::{
|
||||||
depcheck::{
|
depcheck::{
|
||||||
basalt_deps::get_missing_basalt_deps, libsurvive_deps::get_missing_libsurvive_deps,
|
basalt_deps::get_missing_basalt_deps, libsurvive_deps::get_missing_libsurvive_deps,
|
||||||
mercury_deps::get_missing_mercury_deps, monado_deps::get_missing_monado_deps,
|
mercury_deps::get_missing_mercury_deps, monado_deps::get_missing_monado_deps,
|
||||||
openhmd_deps::get_missing_openhmd_deps, wivrn_deps::get_missing_wivrn_deps,
|
openhmd_deps::get_missing_openhmd_deps, wivrn_deps::get_missing_wivrn_deps, Dependency,
|
||||||
xrizer_deps::get_missing_xrizer_deps, Dependency,
|
|
||||||
},
|
},
|
||||||
file_builders::active_runtime_json::ActiveRuntime,
|
file_builders::active_runtime_json::ActiveRuntime,
|
||||||
paths::{get_data_dir, BWRAP_SYSTEM_PREFIX, SYSTEM_PREFIX},
|
paths::{get_data_dir, BWRAP_SYSTEM_PREFIX, SYSTEM_PREFIX},
|
||||||
|
@ -15,7 +14,7 @@ use serde::{Deserialize, Serialize};
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
fmt::Display,
|
fmt::Display,
|
||||||
fs::{remove_dir_all, File},
|
fs::File,
|
||||||
io::BufReader,
|
io::BufReader,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
slice::Iter,
|
slice::Iter,
|
||||||
|
@ -283,15 +282,6 @@ impl OvrCompatibilityModuleType {
|
||||||
pub fn iter() -> Iter<'static, Self> {
|
pub fn iter() -> Iter<'static, Self> {
|
||||||
[Self::Opencomposite, Self::Xrizer, Self::Vapor].iter()
|
[Self::Opencomposite, Self::Xrizer, Self::Vapor].iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_missing_deps(&self) -> Vec<Dependency> {
|
|
||||||
match self {
|
|
||||||
OvrCompatibilityModuleType::Xrizer => get_missing_xrizer_deps(),
|
|
||||||
OvrCompatibilityModuleType::Opencomposite | OvrCompatibilityModuleType::Vapor => {
|
|
||||||
Vec::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for OvrCompatibilityModuleType {
|
impl FromStr for OvrCompatibilityModuleType {
|
||||||
|
@ -341,8 +331,9 @@ impl ProfileOvrCompatibilityModule {
|
||||||
/// this should correspond to the build output directory
|
/// this should correspond to the build output directory
|
||||||
pub fn runtime_dir(&self) -> PathBuf {
|
pub fn runtime_dir(&self) -> PathBuf {
|
||||||
match self.mod_type {
|
match self.mod_type {
|
||||||
OvrCompatibilityModuleType::Opencomposite => self.path.join("build"),
|
OvrCompatibilityModuleType::Opencomposite | OvrCompatibilityModuleType::Vapor => {
|
||||||
OvrCompatibilityModuleType::Vapor => self.path.join("build/install_pfx/lib/VapoR"),
|
self.path.join("build")
|
||||||
|
}
|
||||||
OvrCompatibilityModuleType::Xrizer => self.path.join("target/release"),
|
OvrCompatibilityModuleType::Xrizer => self.path.join("target/release"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -459,29 +450,6 @@ impl Profile {
|
||||||
get_data_dir().join("prefixes").join(uuid)
|
get_data_dir().join("prefixes").join(uuid)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// deletes files and folders associated to this profile (mostly repo clones)
|
|
||||||
pub fn delete_files(&self) -> Vec<std::io::Result<()>> {
|
|
||||||
[
|
|
||||||
Some(&self.xrservice_path),
|
|
||||||
Some(&self.ovr_comp.path),
|
|
||||||
self.features.libsurvive.path.as_ref(),
|
|
||||||
self.features.basalt.path.as_ref(),
|
|
||||||
self.features.openhmd.path.as_ref(),
|
|
||||||
]
|
|
||||||
.iter()
|
|
||||||
.map(|dir| match dir {
|
|
||||||
Some(dir) => {
|
|
||||||
if dir.try_exists().unwrap_or_default() {
|
|
||||||
remove_dir_all(dir)
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => Ok(()),
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn xr_runtime_json_env_var(&self) -> String {
|
pub fn xr_runtime_json_env_var(&self) -> String {
|
||||||
format!(
|
format!(
|
||||||
"XR_RUNTIME_JSON=\"{prefix}/share/openxr/1/openxr_{runtime}.json\"",
|
"XR_RUNTIME_JSON=\"{prefix}/share/openxr/1/openxr_{runtime}.json\"",
|
||||||
|
@ -746,7 +714,7 @@ impl Profile {
|
||||||
if self.features.mercury_enabled {
|
if self.features.mercury_enabled {
|
||||||
missing_deps.extend(get_missing_mercury_deps());
|
missing_deps.extend(get_missing_mercury_deps());
|
||||||
}
|
}
|
||||||
missing_deps.extend(self.ovr_comp.mod_type.get_missing_deps());
|
// no listed deps for opencomp
|
||||||
}
|
}
|
||||||
missing_deps.sort_unstable();
|
missing_deps.sort_unstable();
|
||||||
missing_deps.dedup(); // dedup only works if sorted, hence the above
|
missing_deps.dedup(); // dedup only works if sorted, hence the above
|
||||||
|
|
|
@ -21,7 +21,7 @@ pub fn lighthouse_profile() -> Profile {
|
||||||
environment.insert("LD_LIBRARY_PATH".into(), prepare_ld_library_path(&prefix));
|
environment.insert("LD_LIBRARY_PATH".into(), prepare_ld_library_path(&prefix));
|
||||||
Profile {
|
Profile {
|
||||||
uuid: "lighthouse-default".into(),
|
uuid: "lighthouse-default".into(),
|
||||||
name: format!("Lighthouse Driver - {APP_NAME} Default"),
|
name: format!("Lighthouse Driver - {name} Default", name = APP_NAME),
|
||||||
xrservice_path: data_monado_path(),
|
xrservice_path: data_monado_path(),
|
||||||
xrservice_type: XRServiceType::Monado,
|
xrservice_type: XRServiceType::Monado,
|
||||||
ovr_comp: ProfileOvrCompatibilityModule {
|
ovr_comp: ProfileOvrCompatibilityModule {
|
||||||
|
|
|
@ -21,7 +21,7 @@ pub fn openhmd_profile() -> Profile {
|
||||||
environment.insert("LD_LIBRARY_PATH".into(), prepare_ld_library_path(&prefix));
|
environment.insert("LD_LIBRARY_PATH".into(), prepare_ld_library_path(&prefix));
|
||||||
Profile {
|
Profile {
|
||||||
uuid: "openhmd-default".into(),
|
uuid: "openhmd-default".into(),
|
||||||
name: format!("OpenHMD - {APP_NAME} Default"),
|
name: format!("OpenHMD - {name} Default", name = APP_NAME),
|
||||||
xrservice_path: data_monado_path(),
|
xrservice_path: data_monado_path(),
|
||||||
xrservice_type: XRServiceType::Monado,
|
xrservice_type: XRServiceType::Monado,
|
||||||
ovr_comp: ProfileOvrCompatibilityModule {
|
ovr_comp: ProfileOvrCompatibilityModule {
|
||||||
|
|
|
@ -22,7 +22,7 @@ pub fn simulated_profile() -> Profile {
|
||||||
);
|
);
|
||||||
Profile {
|
Profile {
|
||||||
uuid: "simulated-default".into(),
|
uuid: "simulated-default".into(),
|
||||||
name: format!("Simulated Driver - {APP_NAME} Default"),
|
name: format!("Simulated Driver - {name} Default", name = APP_NAME),
|
||||||
xrservice_path: data_monado_path(),
|
xrservice_path: data_monado_path(),
|
||||||
xrservice_type: XRServiceType::Monado,
|
xrservice_type: XRServiceType::Monado,
|
||||||
ovr_comp: ProfileOvrCompatibilityModule {
|
ovr_comp: ProfileOvrCompatibilityModule {
|
||||||
|
|
|
@ -23,7 +23,7 @@ pub fn survive_profile() -> Profile {
|
||||||
environment.insert("LD_LIBRARY_PATH".into(), prepare_ld_library_path(&prefix));
|
environment.insert("LD_LIBRARY_PATH".into(), prepare_ld_library_path(&prefix));
|
||||||
Profile {
|
Profile {
|
||||||
uuid: "survive-default".into(),
|
uuid: "survive-default".into(),
|
||||||
name: format!("Survive - {APP_NAME} Default"),
|
name: format!("Survive - {name} Default", name = APP_NAME),
|
||||||
xrservice_path: data_monado_path(),
|
xrservice_path: data_monado_path(),
|
||||||
xrservice_type: XRServiceType::Monado,
|
xrservice_type: XRServiceType::Monado,
|
||||||
ovr_comp: ProfileOvrCompatibilityModule {
|
ovr_comp: ProfileOvrCompatibilityModule {
|
||||||
|
|
|
@ -19,7 +19,7 @@ pub fn wivrn_profile() -> Profile {
|
||||||
environment.insert("U_PACING_APP_USE_MIN_FRAME_PERIOD".into(), "1".into());
|
environment.insert("U_PACING_APP_USE_MIN_FRAME_PERIOD".into(), "1".into());
|
||||||
Profile {
|
Profile {
|
||||||
uuid: "wivrn-default".into(),
|
uuid: "wivrn-default".into(),
|
||||||
name: format!("WiVRn - {APP_NAME} Default"),
|
name: format!("WiVRn - {name} Default", name = APP_NAME),
|
||||||
xrservice_path: data_wivrn_path(),
|
xrservice_path: data_wivrn_path(),
|
||||||
xrservice_type: XRServiceType::Wivrn,
|
xrservice_type: XRServiceType::Wivrn,
|
||||||
ovr_comp: ProfileOvrCompatibilityModule {
|
ovr_comp: ProfileOvrCompatibilityModule {
|
||||||
|
|
|
@ -21,7 +21,7 @@ pub fn wmr_profile() -> Profile {
|
||||||
environment.insert("LD_LIBRARY_PATH".into(), prepare_ld_library_path(&prefix));
|
environment.insert("LD_LIBRARY_PATH".into(), prepare_ld_library_path(&prefix));
|
||||||
Profile {
|
Profile {
|
||||||
uuid: "wmr-default".into(),
|
uuid: "wmr-default".into(),
|
||||||
name: format!("WMR - {APP_NAME} Default"),
|
name: format!("WMR - {name} Default", name = APP_NAME),
|
||||||
xrservice_path: data_monado_path(),
|
xrservice_path: data_monado_path(),
|
||||||
xrservice_type: XRServiceType::Monado,
|
xrservice_type: XRServiceType::Monado,
|
||||||
ovr_comp: ProfileOvrCompatibilityModule {
|
ovr_comp: ProfileOvrCompatibilityModule {
|
||||||
|
|
|
@ -2,7 +2,7 @@ use crate::{
|
||||||
paths::get_backup_dir,
|
paths::get_backup_dir,
|
||||||
profile::Profile,
|
profile::Profile,
|
||||||
util::{
|
util::{
|
||||||
file_utils::{copy_file, get_writer, mark_as_executable},
|
file_utils::{copy_file, get_writer},
|
||||||
steam_library_folder::SteamLibraryFolder,
|
steam_library_folder::SteamLibraryFolder,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -15,85 +15,45 @@ use std::{
|
||||||
};
|
};
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
|
|
||||||
pub const SNIPER_RUNTIME_STEAM_APPID: u32 = 1628350;
|
pub const PRESSURE_VESSEL_STEAM_APPID: u32 = 1628350;
|
||||||
pub const SOLDIER_RUNTIME_STEAM_APPID: u32 = 1391110;
|
|
||||||
|
|
||||||
fn get_sniper_runtime_entrypoint_path() -> Option<PathBuf> {
|
fn get_runtime_entrypoint_path() -> Option<PathBuf> {
|
||||||
match SteamLibraryFolder::get_folders() {
|
match SteamLibraryFolder::get_folders() {
|
||||||
Ok(libraryfolders) => libraryfolders
|
Ok(libraryfolders) => libraryfolders
|
||||||
.iter()
|
.iter()
|
||||||
.find(|(_, folder)| folder.apps.contains_key(&SNIPER_RUNTIME_STEAM_APPID))
|
.find(|(_, folder)| folder.apps.contains_key(&PRESSURE_VESSEL_STEAM_APPID))
|
||||||
.map(|(_, folder)| {
|
.map(|(_, folder)| {
|
||||||
PathBuf::from(&folder.path)
|
PathBuf::from(&folder.path)
|
||||||
.join("steamapps/common/SteamLinuxRuntime_sniper/_v2-entry-point")
|
.join("steamapps/common/SteamLinuxRuntime_sniper/_v2-entry-point")
|
||||||
}),
|
}),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("unable to get sniper runtime entrypoint path: {e}");
|
error!("unable to get runtime entrypoint path: {e}");
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_soldier_runtime_entrypoint_path() -> Option<PathBuf> {
|
|
||||||
match SteamLibraryFolder::get_folders() {
|
|
||||||
Ok(libraryfolders) => libraryfolders
|
|
||||||
.iter()
|
|
||||||
.find(|(_, folder)| folder.apps.contains_key(&SOLDIER_RUNTIME_STEAM_APPID))
|
|
||||||
.map(|(_, folder)| {
|
|
||||||
PathBuf::from(&folder.path)
|
|
||||||
.join("steamapps/common/SteamLinuxRuntime_soldier/_v2-entry-point")
|
|
||||||
}),
|
|
||||||
Err(e) => {
|
|
||||||
error!("unable to get soldier runtime entrypoint path: {e}");
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref STEAM_SNIPER_RUNTIME_ENTRYPOINT_PATH: Option<PathBuf> =
|
static ref STEAM_RUNTIME_ENTRYPOINT_PATH: Option<PathBuf> = get_runtime_entrypoint_path();
|
||||||
get_sniper_runtime_entrypoint_path();
|
|
||||||
static ref STEAM_SOLDIER_RUNTIME_ENTRYPOINT_PATH: Option<PathBuf> =
|
|
||||||
get_soldier_runtime_entrypoint_path();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_backup_sniper_runtime_entrypoint_location() -> PathBuf {
|
fn get_backup_runtime_entrypoint_location() -> PathBuf {
|
||||||
get_backup_dir().join("_v2-entry-point.bak")
|
get_backup_dir().join("_v2-entry-point.bak")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_backup_soldier_runtime_entrypoint_location() -> PathBuf {
|
fn backup_runtime_entrypoint(path: &Path) {
|
||||||
get_backup_dir().join("_v2-entry-point.soldier.bak")
|
copy_file(path, &get_backup_runtime_entrypoint_location());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn backup_sniper_runtime_entrypoint(path: &Path) {
|
pub fn restore_runtime_entrypoint() {
|
||||||
copy_file(path, &get_backup_sniper_runtime_entrypoint_location());
|
if let Some(path) = STEAM_RUNTIME_ENTRYPOINT_PATH.as_ref() {
|
||||||
}
|
let backup = get_backup_runtime_entrypoint_location();
|
||||||
|
|
||||||
fn backup_soldier_runtime_entrypoint(path: &Path) {
|
|
||||||
copy_file(path, &get_backup_soldier_runtime_entrypoint_location());
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn restore_sniper_runtime_entrypoint() {
|
|
||||||
if let Some(path) = STEAM_SNIPER_RUNTIME_ENTRYPOINT_PATH.as_ref() {
|
|
||||||
let backup = get_backup_sniper_runtime_entrypoint_location();
|
|
||||||
if Path::new(&backup).is_file() {
|
if Path::new(&backup).is_file() {
|
||||||
copy_file(&backup, path);
|
copy_file(&backup, path);
|
||||||
let _ = mark_as_executable(path);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn restore_soldier_runtime_entrypoint() {
|
|
||||||
if let Some(path) = STEAM_SOLDIER_RUNTIME_ENTRYPOINT_PATH.as_ref() {
|
|
||||||
let backup = get_backup_soldier_runtime_entrypoint_location();
|
|
||||||
if Path::new(&backup).is_file() {
|
|
||||||
copy_file(&backup, path);
|
|
||||||
let _ = mark_as_executable(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// this implementation is identical for both sniper and soldier runtimes
|
|
||||||
fn append_to_runtime_entrypoint(data: &str, path: &Path) -> anyhow::Result<()> {
|
fn append_to_runtime_entrypoint(data: &str, path: &Path) -> anyhow::Result<()> {
|
||||||
let existing = read_to_string(path)?;
|
let existing = read_to_string(path)?;
|
||||||
let new = existing.replace(
|
let new = existing.replace(
|
||||||
|
@ -105,12 +65,10 @@ fn append_to_runtime_entrypoint(data: &str, path: &Path) -> anyhow::Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_sniper_runtime_entrypoint_launch_opts_from_profile(
|
pub fn set_runtime_entrypoint_launch_opts_from_profile(profile: &Profile) -> anyhow::Result<()> {
|
||||||
profile: &Profile,
|
restore_runtime_entrypoint();
|
||||||
) -> anyhow::Result<()> {
|
if let Some(dest) = STEAM_RUNTIME_ENTRYPOINT_PATH.as_ref() {
|
||||||
restore_sniper_runtime_entrypoint();
|
backup_runtime_entrypoint(dest);
|
||||||
if let Some(dest) = STEAM_SNIPER_RUNTIME_ENTRYPOINT_PATH.as_ref() {
|
|
||||||
backup_sniper_runtime_entrypoint(dest);
|
|
||||||
append_to_runtime_entrypoint(
|
append_to_runtime_entrypoint(
|
||||||
&profile
|
&profile
|
||||||
.get_env_vars()
|
.get_env_vars()
|
||||||
|
@ -120,31 +78,8 @@ pub fn set_sniper_runtime_entrypoint_launch_opts_from_profile(
|
||||||
.join("\n"),
|
.join("\n"),
|
||||||
dest,
|
dest,
|
||||||
)?;
|
)?;
|
||||||
mark_as_executable(dest)?;
|
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
bail!("Could not find valid sniper runtime entrypoint");
|
bail!("Could not find valid runtime entrypoint");
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_soldier_runtime_entrypoint_launch_opts_from_profile(
|
|
||||||
profile: &Profile,
|
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
restore_soldier_runtime_entrypoint();
|
|
||||||
if let Some(dest) = STEAM_SOLDIER_RUNTIME_ENTRYPOINT_PATH.as_ref() {
|
|
||||||
backup_soldier_runtime_entrypoint(dest);
|
|
||||||
append_to_runtime_entrypoint(
|
|
||||||
&profile
|
|
||||||
.get_env_vars()
|
|
||||||
.iter()
|
|
||||||
.map(|ev| "export ".to_string() + ev)
|
|
||||||
.collect::<Vec<String>>()
|
|
||||||
.join("\n"),
|
|
||||||
dest,
|
|
||||||
)?;
|
|
||||||
mark_as_executable(dest)?;
|
|
||||||
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
bail!("Could not find valid soldier runtime entrypoint");
|
|
||||||
}
|
}
|
||||||
|
|
110
src/ui/app.rs
110
src/ui/app.rs
|
@ -41,11 +41,8 @@ use crate::{
|
||||||
profile::{OvrCompatibilityModuleType, Profile, XRServiceType},
|
profile::{OvrCompatibilityModuleType, Profile, XRServiceType},
|
||||||
stateless_action,
|
stateless_action,
|
||||||
steam_linux_runtime_injector::{
|
steam_linux_runtime_injector::{
|
||||||
restore_sniper_runtime_entrypoint, restore_soldier_runtime_entrypoint,
|
restore_runtime_entrypoint, set_runtime_entrypoint_launch_opts_from_profile,
|
||||||
set_sniper_runtime_entrypoint_launch_opts_from_profile,
|
|
||||||
set_soldier_runtime_entrypoint_launch_opts_from_profile,
|
|
||||||
},
|
},
|
||||||
termcolor::TermColor,
|
|
||||||
util::file_utils::{
|
util::file_utils::{
|
||||||
setcap_cap_sys_nice_eip, setcap_cap_sys_nice_eip_cmd, verify_cap_sys_nice_eip,
|
setcap_cap_sys_nice_eip, setcap_cap_sys_nice_eip_cmd, verify_cap_sys_nice_eip,
|
||||||
},
|
},
|
||||||
|
@ -54,7 +51,6 @@ use crate::{
|
||||||
xr_devices::XRDevice,
|
xr_devices::XRDevice,
|
||||||
};
|
};
|
||||||
use adw::{prelude::*, ResponseAppearance};
|
use adw::{prelude::*, ResponseAppearance};
|
||||||
use delicious_adwaita::{theme::Theme, ThemeEngine};
|
|
||||||
use gtk::glib::{self, clone};
|
use gtk::glib::{self, clone};
|
||||||
use notify_rust::NotificationHandle;
|
use notify_rust::NotificationHandle;
|
||||||
use relm4::{
|
use relm4::{
|
||||||
|
@ -100,8 +96,6 @@ pub struct App {
|
||||||
|
|
||||||
inhibit_fail_notif: Option<NotificationHandle>,
|
inhibit_fail_notif: Option<NotificationHandle>,
|
||||||
pluginstore: Option<AsyncController<PluginStore>>,
|
pluginstore: Option<AsyncController<PluginStore>>,
|
||||||
|
|
||||||
theme_engine: ThemeEngine,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -119,8 +113,7 @@ pub enum Msg {
|
||||||
StartWithDebug,
|
StartWithDebug,
|
||||||
RestartXRService,
|
RestartXRService,
|
||||||
ProfileSelected(Profile),
|
ProfileSelected(Profile),
|
||||||
/// bool param: delete files
|
DeleteProfile,
|
||||||
DeleteProfile(bool),
|
|
||||||
SaveProfile(Profile),
|
SaveProfile(Profile),
|
||||||
RunSetCap,
|
RunSetCap,
|
||||||
OpenLibsurviveSetup,
|
OpenLibsurviveSetup,
|
||||||
|
@ -136,8 +129,6 @@ pub enum Msg {
|
||||||
WivrnCheckPairMode,
|
WivrnCheckPairMode,
|
||||||
OpenPluginStore,
|
OpenPluginStore,
|
||||||
UpdateConfigPlugins(HashMap<String, PluginConfig>),
|
UpdateConfigPlugins(HashMap<String, PluginConfig>),
|
||||||
ShowThemeManager,
|
|
||||||
SaveThemeConfig,
|
|
||||||
NoOp,
|
NoOp,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,17 +227,13 @@ impl App {
|
||||||
);
|
);
|
||||||
worker.start();
|
worker.start();
|
||||||
self.xrservice_worker = Some(worker);
|
self.xrservice_worker = Some(worker);
|
||||||
let set_sniper_launch_opts_res =
|
|
||||||
set_sniper_runtime_entrypoint_launch_opts_from_profile(&prof);
|
|
||||||
let set_soldier_launch_opts_res =
|
|
||||||
set_soldier_runtime_entrypoint_launch_opts_from_profile(&prof);
|
|
||||||
self.main_view
|
self.main_view
|
||||||
.sender()
|
.sender()
|
||||||
.emit(MainViewMsg::XRServiceActiveChanged(
|
.emit(MainViewMsg::XRServiceActiveChanged(
|
||||||
true,
|
true,
|
||||||
Some(self.get_selected_profile()),
|
Some(self.get_selected_profile()),
|
||||||
// show launch opts only if setting the runtime entrypoint fails
|
// show launch opts only if setting the runtime entrypoint fails
|
||||||
set_sniper_launch_opts_res.is_err() || set_soldier_launch_opts_res.is_err(),
|
set_runtime_entrypoint_launch_opts_from_profile(&prof).is_err(),
|
||||||
));
|
));
|
||||||
self.debug_view
|
self.debug_view
|
||||||
.sender()
|
.sender()
|
||||||
|
@ -262,6 +249,10 @@ impl App {
|
||||||
.plugins
|
.plugins
|
||||||
.values()
|
.values()
|
||||||
.filter_map(|cp| {
|
.filter_map(|cp| {
|
||||||
|
// disable potentially unsafe wayvr_dashboard
|
||||||
|
if cp.plugin.appid.contains("wayvr_dashboard") {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
if cp.enabled && cp.plugin.validate() {
|
if cp.enabled && cp.plugin.validate() {
|
||||||
if let Err(e) = cp.plugin.mark_as_executable() {
|
if let Err(e) = cp.plugin.mark_as_executable() {
|
||||||
error!(
|
error!(
|
||||||
|
@ -310,8 +301,7 @@ impl App {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn restore_openxr_openvr_files(&self) {
|
pub fn restore_openxr_openvr_files(&self) {
|
||||||
restore_sniper_runtime_entrypoint();
|
restore_runtime_entrypoint();
|
||||||
restore_soldier_runtime_entrypoint();
|
|
||||||
if let Err(e) = remove_current_active_runtime() {
|
if let Err(e) = remove_current_active_runtime() {
|
||||||
alert(
|
alert(
|
||||||
"Could not remove profile active runtime",
|
"Could not remove profile active runtime",
|
||||||
|
@ -380,7 +370,7 @@ impl AsyncComponent for App {
|
||||||
set_content: Some(&adw::NavigationPage::new(model.debug_view.widget(), "Debug View")),
|
set_content: Some(&adw::NavigationPage::new(model.debug_view.widget(), "Debug View")),
|
||||||
set_show_content: false,
|
set_show_content: false,
|
||||||
set_collapsed: !model.config.debug_view_enabled,
|
set_collapsed: !model.config.debug_view_enabled,
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
connect_close_request[sender] => move |win| {
|
connect_close_request[sender] => move |win| {
|
||||||
sender.input(Msg::SaveWinSize(win.width(), win.height()));
|
sender.input(Msg::SaveWinSize(win.width(), win.height()));
|
||||||
|
@ -404,27 +394,6 @@ impl AsyncComponent for App {
|
||||||
) {
|
) {
|
||||||
match message {
|
match message {
|
||||||
Msg::NoOp => {}
|
Msg::NoOp => {}
|
||||||
Msg::ShowThemeManager => {
|
|
||||||
let dialog = self
|
|
||||||
.theme_engine
|
|
||||||
.theme_chooser_dialog(Theme::default_themes().as_ref());
|
|
||||||
dialog.set_content_height(2000);
|
|
||||||
dialog.present(Some(&self.app_win));
|
|
||||||
dialog.connect_closed(clone!(
|
|
||||||
#[strong]
|
|
||||||
sender,
|
|
||||||
move |_| {
|
|
||||||
sender.input(Msg::SaveThemeConfig);
|
|
||||||
}
|
|
||||||
));
|
|
||||||
}
|
|
||||||
Msg::SaveThemeConfig => {
|
|
||||||
let name = self.theme_engine.current_theme_name();
|
|
||||||
if self.config.theme_name != name {
|
|
||||||
self.config.theme_name = name;
|
|
||||||
self.config.save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Msg::OnServiceLog(rows) => {
|
Msg::OnServiceLog(rows) => {
|
||||||
if !rows.is_empty() {
|
if !rows.is_empty() {
|
||||||
self.debug_view
|
self.debug_view
|
||||||
|
@ -555,7 +524,7 @@ impl AsyncComponent for App {
|
||||||
jobs.extend(get_build_basalt_jobs(&profile, clean_build));
|
jobs.extend(get_build_basalt_jobs(&profile, clean_build));
|
||||||
}
|
}
|
||||||
if profile.features.mercury_enabled {
|
if profile.features.mercury_enabled {
|
||||||
jobs.extend(get_build_mercury_jobs());
|
jobs.extend(get_build_mercury_jobs(&profile));
|
||||||
}
|
}
|
||||||
jobs.extend(match profile.xrservice_type {
|
jobs.extend(match profile.xrservice_type {
|
||||||
XRServiceType::Monado => get_build_monado_jobs(&profile, clean_build),
|
XRServiceType::Monado => get_build_monado_jobs(&profile, clean_build),
|
||||||
|
@ -661,10 +630,6 @@ impl AsyncComponent for App {
|
||||||
if dep_pkexec().check() {
|
if dep_pkexec().check() {
|
||||||
self.setcap_confirm_dialog.present(Some(&self.app_win));
|
self.setcap_confirm_dialog.present(Some(&self.app_win));
|
||||||
} else {
|
} else {
|
||||||
self.build_window
|
|
||||||
.sender()
|
|
||||||
.emit(BuildWindowMsg::UpdateContent(vec![TermColor::Red
|
|
||||||
.colorize("pkexec not found, cannot set capabilities\n")]));
|
|
||||||
alert_w_widget(
|
alert_w_widget(
|
||||||
"pkexec not found",
|
"pkexec not found",
|
||||||
Some(&format!(
|
Some(&format!(
|
||||||
|
@ -687,7 +652,7 @@ impl AsyncComponent for App {
|
||||||
self.build_window
|
self.build_window
|
||||||
.sender()
|
.sender()
|
||||||
.emit(BuildWindowMsg::UpdateBuildStatus(BuildStatus::Error(
|
.emit(BuildWindowMsg::UpdateBuildStatus(BuildStatus::Error(
|
||||||
format!("Exit status {errcode}"),
|
format!("Exit status {}", errcode),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -697,16 +662,9 @@ impl AsyncComponent for App {
|
||||||
w.stop();
|
w.stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Msg::DeleteProfile(delete_files) => {
|
Msg::DeleteProfile => {
|
||||||
let todel = self.get_selected_profile();
|
let todel = self.get_selected_profile();
|
||||||
if todel.editable {
|
if todel.editable {
|
||||||
if delete_files {
|
|
||||||
for res in todel.delete_files() {
|
|
||||||
if let Err(e) = res {
|
|
||||||
error!("Error deleting profile directory: {e}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.config.user_profiles.retain(|p| p.uuid != todel.uuid);
|
self.config.user_profiles.retain(|p| p.uuid != todel.uuid);
|
||||||
self.config.save();
|
self.config.save();
|
||||||
self.profiles = self.config.profiles();
|
self.profiles = self.config.profiles();
|
||||||
|
@ -746,7 +704,6 @@ impl AsyncComponent for App {
|
||||||
}
|
}
|
||||||
Msg::RunSetCap => {
|
Msg::RunSetCap => {
|
||||||
if !dep_pkexec().check() {
|
if !dep_pkexec().check() {
|
||||||
// there's a precheck ahead of this, this should likely never happen
|
|
||||||
error!("pkexec not found, skipping setcap");
|
error!("pkexec not found, skipping setcap");
|
||||||
} else {
|
} else {
|
||||||
let profile = self.get_selected_profile();
|
let profile = self.get_selected_profile();
|
||||||
|
@ -764,26 +721,8 @@ impl AsyncComponent for App {
|
||||||
if let Err(e) = setcap_cap_sys_nice_eip(&profile).await {
|
if let Err(e) = setcap_cap_sys_nice_eip(&profile).await {
|
||||||
setcap_failed_dialog();
|
setcap_failed_dialog();
|
||||||
error!("failed running setcap: {e}");
|
error!("failed running setcap: {e}");
|
||||||
self.build_window
|
|
||||||
.sender()
|
|
||||||
.emit(BuildWindowMsg::UpdateContent(vec![
|
|
||||||
TermColor::Red.colorize("Setting capabilities failed\n")
|
|
||||||
]));
|
|
||||||
} else if !verify_cap_sys_nice_eip(&profile).await {
|
} else if !verify_cap_sys_nice_eip(&profile).await {
|
||||||
setcap_failed_dialog();
|
setcap_failed_dialog();
|
||||||
error!("setcap succeeded but capabilities were reset");
|
|
||||||
self.build_window
|
|
||||||
.sender()
|
|
||||||
.emit(BuildWindowMsg::UpdateContent(vec![TermColor::Red
|
|
||||||
.colorize(
|
|
||||||
"Setting capabilities succeeded, but capabilities have been reset\n",
|
|
||||||
)]));
|
|
||||||
} else {
|
|
||||||
self.build_window
|
|
||||||
.sender()
|
|
||||||
.emit(BuildWindowMsg::UpdateContent(vec![
|
|
||||||
TermColor::Green.colorize("Capabilities set correctly\n")
|
|
||||||
]));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1031,17 +970,6 @@ impl AsyncComponent for App {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
stateless_action!(
|
|
||||||
actions,
|
|
||||||
ThemeManagerAction,
|
|
||||||
clone!(
|
|
||||||
#[strong]
|
|
||||||
sender,
|
|
||||||
move |_| {
|
|
||||||
sender.input(Msg::ShowThemeManager);
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
// this bypasses the macro because I need the underlying gio action
|
// this bypasses the macro because I need the underlying gio action
|
||||||
// to enable/disable it in update()
|
// to enable/disable it in update()
|
||||||
let configure_wivrn_action = {
|
let configure_wivrn_action = {
|
||||||
|
@ -1083,7 +1011,7 @@ impl AsyncComponent for App {
|
||||||
MainViewOutMsg::DoStartStopXRService => Msg::DoStartStopXRService,
|
MainViewOutMsg::DoStartStopXRService => Msg::DoStartStopXRService,
|
||||||
MainViewOutMsg::RestartXRService => Msg::RestartXRService,
|
MainViewOutMsg::RestartXRService => Msg::RestartXRService,
|
||||||
MainViewOutMsg::ProfileSelected(uuid) => Msg::ProfileSelected(uuid),
|
MainViewOutMsg::ProfileSelected(uuid) => Msg::ProfileSelected(uuid),
|
||||||
MainViewOutMsg::DeleteProfile(delete_files) => Msg::DeleteProfile(delete_files),
|
MainViewOutMsg::DeleteProfile => Msg::DeleteProfile,
|
||||||
MainViewOutMsg::SaveProfile(p) => Msg::SaveProfile(p),
|
MainViewOutMsg::SaveProfile(p) => Msg::SaveProfile(p),
|
||||||
MainViewOutMsg::OpenLibsurviveSetup => Msg::OpenLibsurviveSetup,
|
MainViewOutMsg::OpenLibsurviveSetup => Msg::OpenLibsurviveSetup,
|
||||||
MainViewOutMsg::BuildProfile(clean) => Msg::BuildProfile(clean),
|
MainViewOutMsg::BuildProfile(clean) => Msg::BuildProfile(clean),
|
||||||
|
@ -1110,17 +1038,6 @@ impl AsyncComponent for App {
|
||||||
.detach(),
|
.detach(),
|
||||||
split_view: None,
|
split_view: None,
|
||||||
setcap_confirm_dialog,
|
setcap_confirm_dialog,
|
||||||
theme_engine: ThemeEngine::new_with_theme(&{
|
|
||||||
if config.theme_name == "Follow system" {
|
|
||||||
Theme::default()
|
|
||||||
} else {
|
|
||||||
Theme::default_themes()
|
|
||||||
.into_iter()
|
|
||||||
.find(|t| t.name == config.theme_name)
|
|
||||||
.unwrap_or_default()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.unwrap(),
|
|
||||||
config,
|
config,
|
||||||
profiles,
|
profiles,
|
||||||
xrservice_worker: None,
|
xrservice_worker: None,
|
||||||
|
@ -1209,7 +1126,6 @@ new_stateless_action!(pub QuitAction, AppActionGroup, "quit");
|
||||||
new_stateful_action!(pub DebugViewToggleAction, AppActionGroup, "debugviewtoggle", (), bool);
|
new_stateful_action!(pub DebugViewToggleAction, AppActionGroup, "debugviewtoggle", (), bool);
|
||||||
new_stateless_action!(pub ConfigureWivrnAction, AppActionGroup, "configurewivrn");
|
new_stateless_action!(pub ConfigureWivrnAction, AppActionGroup, "configurewivrn");
|
||||||
new_stateless_action!(pub PluginStoreAction, AppActionGroup, "store");
|
new_stateless_action!(pub PluginStoreAction, AppActionGroup, "store");
|
||||||
new_stateless_action!(pub ThemeManagerAction, AppActionGroup, "thememanager");
|
|
||||||
|
|
||||||
new_stateless_action!(pub DebugOpenDataAction, AppActionGroup, "debugopendata");
|
new_stateless_action!(pub DebugOpenDataAction, AppActionGroup, "debugopendata");
|
||||||
new_stateless_action!(pub DebugOpenPrefixAction, AppActionGroup, "debugopenprefix");
|
new_stateless_action!(pub DebugOpenPrefixAction, AppActionGroup, "debugopenprefix");
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
use crate::termcolor::TermColor;
|
|
||||||
|
|
||||||
use super::{term_widget::TermWidget, SENDER_IO_ERR_MSG};
|
use super::{term_widget::TermWidget, SENDER_IO_ERR_MSG};
|
||||||
use adw::prelude::*;
|
use adw::prelude::*;
|
||||||
use relm4::prelude::*;
|
use relm4::prelude::*;
|
||||||
|
@ -93,7 +91,7 @@ impl SimpleComponent for BuildWindow {
|
||||||
BuildStatus::Building => String::default(),
|
BuildStatus::Building => String::default(),
|
||||||
BuildStatus::Done => "Build done, you can close this window".into(),
|
BuildStatus::Done => "Build done, you can close this window".into(),
|
||||||
BuildStatus::Error(code) => {
|
BuildStatus::Error(code) => {
|
||||||
format!("Build failed: \"{code}\"")
|
format!("Build failed: \"{c}\"", c = code)
|
||||||
}
|
}
|
||||||
}.as_str(),
|
}.as_str(),
|
||||||
#[track = "model.changed(BuildWindow::build_status())"]
|
#[track = "model.changed(BuildWindow::build_status())"]
|
||||||
|
@ -166,18 +164,8 @@ impl SimpleComponent for BuildWindow {
|
||||||
label.remove_css_class("success");
|
label.remove_css_class("success");
|
||||||
label.remove_css_class("error");
|
label.remove_css_class("error");
|
||||||
match status {
|
match status {
|
||||||
BuildStatus::Done => {
|
BuildStatus::Done => label.add_css_class("success"),
|
||||||
label.add_css_class("success");
|
BuildStatus::Error(_) => label.add_css_class("error"),
|
||||||
sender.input(BuildWindowMsg::UpdateContent(vec![
|
|
||||||
TermColor::Blue.colorize("Build completed!\n")
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
BuildStatus::Error(_) => {
|
|
||||||
label.add_css_class("error");
|
|
||||||
sender.input(BuildWindowMsg::UpdateContent(vec![
|
|
||||||
TermColor::Blue.colorize("Build failed!\n")
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
if status != BuildStatus::Building {
|
if status != BuildStatus::Building {
|
||||||
|
|
|
@ -21,7 +21,6 @@ use crate::{
|
||||||
paths::{get_data_dir, get_home_dir},
|
paths::{get_data_dir, get_home_dir},
|
||||||
profile::{LighthouseDriver, Profile, XRServiceType},
|
profile::{LighthouseDriver, Profile, XRServiceType},
|
||||||
stateless_action,
|
stateless_action,
|
||||||
ui::app::ThemeManagerAction,
|
|
||||||
util::{
|
util::{
|
||||||
file_utils::{get_writer, mount_has_nosuid},
|
file_utils::{get_writer, mount_has_nosuid},
|
||||||
steamvr_utils::chaperone_info_exists,
|
steamvr_utils::chaperone_info_exists,
|
||||||
|
@ -113,8 +112,7 @@ pub enum MainViewOutMsg {
|
||||||
DoStartStopXRService,
|
DoStartStopXRService,
|
||||||
RestartXRService,
|
RestartXRService,
|
||||||
ProfileSelected(Profile),
|
ProfileSelected(Profile),
|
||||||
/// bool param: delete files
|
DeleteProfile,
|
||||||
DeleteProfile(bool),
|
|
||||||
SaveProfile(Profile),
|
SaveProfile(Profile),
|
||||||
OpenLibsurviveSetup,
|
OpenLibsurviveSetup,
|
||||||
/// params: clean
|
/// params: clean
|
||||||
|
@ -160,7 +158,6 @@ impl AsyncComponent for MainView {
|
||||||
"Configure _WiVRn" => ConfigureWivrnAction,
|
"Configure _WiVRn" => ConfigureWivrnAction,
|
||||||
},
|
},
|
||||||
section! {
|
section! {
|
||||||
"Change _Theme" => ThemeManagerAction,
|
|
||||||
"_About" => AboutAction,
|
"_About" => AboutAction,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -934,13 +931,6 @@ impl AsyncComponent for MainView {
|
||||||
|
|
||||||
let profile_delete_confirm_dialog = adw::AlertDialog::builder()
|
let profile_delete_confirm_dialog = adw::AlertDialog::builder()
|
||||||
.heading("Are you sure you want to delete this profile?")
|
.heading("Are you sure you want to delete this profile?")
|
||||||
.extra_child(
|
|
||||||
>k::CheckButton::builder()
|
|
||||||
.label("Delete all files and folders associated with profile")
|
|
||||||
.halign(gtk::Align::Center)
|
|
||||||
.hexpand(true)
|
|
||||||
.build(),
|
|
||||||
)
|
|
||||||
.build();
|
.build();
|
||||||
profile_delete_confirm_dialog.add_response("no", "_No");
|
profile_delete_confirm_dialog.add_response("no", "_No");
|
||||||
profile_delete_confirm_dialog.add_response("yes", "_Yes");
|
profile_delete_confirm_dialog.add_response("yes", "_Yes");
|
||||||
|
@ -952,19 +942,10 @@ impl AsyncComponent for MainView {
|
||||||
clone!(
|
clone!(
|
||||||
#[strong]
|
#[strong]
|
||||||
sender,
|
sender,
|
||||||
move |dialog, res| {
|
move |_, res| {
|
||||||
let delete_files_checkbox = dialog
|
|
||||||
.extra_child()
|
|
||||||
.and_then(|child| child.downcast::<gtk::CheckButton>().ok());
|
|
||||||
let delete_files = delete_files_checkbox
|
|
||||||
.as_ref()
|
|
||||||
.is_some_and(|c| c.is_active());
|
|
||||||
if let Some(check) = delete_files_checkbox {
|
|
||||||
check.set_active(false);
|
|
||||||
}
|
|
||||||
if res == "yes" {
|
if res == "yes" {
|
||||||
sender
|
sender
|
||||||
.output(Self::Output::DeleteProfile(delete_files))
|
.output(Self::Output::DeleteProfile)
|
||||||
.expect("Sender output failed");
|
.expect("Sender output failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,6 @@ pub enum AddCustomPluginWinMsg {
|
||||||
Present,
|
Present,
|
||||||
Close,
|
Close,
|
||||||
OnNameChange(String),
|
OnNameChange(String),
|
||||||
OnArgsChange(String),
|
|
||||||
OnExecPathChange(Option<String>),
|
OnExecPathChange(Option<String>),
|
||||||
Add,
|
Add,
|
||||||
}
|
}
|
||||||
|
@ -96,11 +95,7 @@ impl SimpleComponent for AddCustomPluginWin {
|
||||||
"",
|
"",
|
||||||
clone!(
|
clone!(
|
||||||
#[strong] sender,
|
#[strong] sender,
|
||||||
move |row| sender.input(
|
move |row| sender.input(Self::Input::OnNameChange(row.text().to_string()))
|
||||||
Self::Input::OnNameChange(
|
|
||||||
row.text().to_string()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
add: &file_row(
|
add: &file_row(
|
||||||
|
@ -110,23 +105,9 @@ impl SimpleComponent for AddCustomPluginWin {
|
||||||
Some(model.parent.clone()),
|
Some(model.parent.clone()),
|
||||||
clone!(
|
clone!(
|
||||||
#[strong] sender,
|
#[strong] sender,
|
||||||
move |path_s| sender.input(
|
move |path_s| sender.input(Self::Input::OnExecPathChange(path_s))
|
||||||
Self::Input::OnExecPathChange(path_s)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
),
|
)
|
||||||
add: &entry_row(
|
|
||||||
"Plugin Arguments",
|
|
||||||
"",
|
|
||||||
clone!(
|
|
||||||
#[strong] sender,
|
|
||||||
move |row| sender.input(
|
|
||||||
Self::Input::OnArgsChange(
|
|
||||||
row.text().to_string()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -158,17 +139,6 @@ impl SimpleComponent for AddCustomPluginWin {
|
||||||
self.plugin.name = name;
|
self.plugin.name = name;
|
||||||
self.set_can_add(self.plugin.validate());
|
self.set_can_add(self.plugin.validate());
|
||||||
}
|
}
|
||||||
Self::Input::OnArgsChange(args) => {
|
|
||||||
let args = args.trim().to_string();
|
|
||||||
self.plugin.args = if args.is_empty() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
// it's fine to have them joined
|
|
||||||
// since they will ultimately be
|
|
||||||
// passed as a joined string
|
|
||||||
Some(vec![args])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Self::Input::OnExecPathChange(ep) => {
|
Self::Input::OnExecPathChange(ep) => {
|
||||||
self.plugin.exec_path = ep.map(PathBuf::from);
|
self.plugin.exec_path = ep.map(PathBuf::from);
|
||||||
self.set_can_add(self.plugin.validate());
|
self.set_can_add(self.plugin.validate());
|
||||||
|
|
|
@ -163,10 +163,10 @@ impl Plugin {
|
||||||
|
|
||||||
/// urls to manifest json files representing plugins.
|
/// urls to manifest json files representing plugins.
|
||||||
/// each manifest should be json and the link should always point to the latest version
|
/// each manifest should be json and the link should always point to the latest version
|
||||||
const MANIFESTS: [&str;3] = [
|
const MANIFESTS: [&str;2] = [
|
||||||
"https://github.com/galister/wlx-overlay-s/raw/refs/heads/meta/com.github.galister.wlx-overlay-s.json",
|
"https://github.com/galister/wlx-overlay-s/raw/refs/heads/meta/com.github.galister.wlx-overlay-s.json",
|
||||||
"https://github.com/StardustXR/telescope/raw/refs/heads/main/envision/org.stardustxr.telescope.json",
|
"https://github.com/StardustXR/telescope/raw/refs/heads/main/envision/org.stardustxr.telescope.json",
|
||||||
"https://github.com/olekolek1000/wayvr-dashboard/raw/refs/heads/meta/dev.oo8.wayvr_dashboard.json",
|
// wayvr dashboard potentially unsafe
|
||||||
];
|
];
|
||||||
|
|
||||||
pub async fn refresh_plugins() -> anyhow::Result<Vec<anyhow::Result<Plugin>>> {
|
pub async fn refresh_plugins() -> anyhow::Result<Vec<anyhow::Result<Plugin>>> {
|
||||||
|
|
|
@ -213,7 +213,7 @@ pub fn file_row<F: Fn(Option<String>) + 'static + Clone>(
|
||||||
|
|
||||||
let filedialog = gtk::FileDialog::builder()
|
let filedialog = gtk::FileDialog::builder()
|
||||||
.modal(true)
|
.modal(true)
|
||||||
.title(format!("Select {title}"))
|
.title(format!("Select {}", title))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
row.connect_activated(clone!(
|
row.connect_activated(clone!(
|
||||||
|
@ -255,7 +255,7 @@ pub fn path_row<F: Fn(Option<String>) + 'static + Clone>(
|
||||||
let (row, path_label) = filedialog_row_base(title, description, value, cb.clone());
|
let (row, path_label) = filedialog_row_base(title, description, value, cb.clone());
|
||||||
let filedialog = gtk::FileDialog::builder()
|
let filedialog = gtk::FileDialog::builder()
|
||||||
.modal(true)
|
.modal(true)
|
||||||
.title(format!("Select Path for {title}"))
|
.title(format!("Select Path for {}", title))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
row.connect_activated(clone!(
|
row.connect_activated(clone!(
|
||||||
|
|
|
@ -45,7 +45,8 @@ impl SimpleComponent for SteamLaunchOptionsBox {
|
||||||
add_css_class: "dim-label",
|
add_css_class: "dim-label",
|
||||||
set_hexpand: true,
|
set_hexpand: true,
|
||||||
set_label: format!(
|
set_label: format!(
|
||||||
"Set this string in the launch options of Steam games, so that they can pick up the {APP_NAME} runtime correctly")
|
"Set this string in the launch options of Steam games, so that they can pick up the {app} runtime correctly",
|
||||||
|
app = APP_NAME)
|
||||||
.as_str(),
|
.as_str(),
|
||||||
set_xalign: 0.0,
|
set_xalign: 0.0,
|
||||||
set_wrap: true,
|
set_wrap: true,
|
||||||
|
|
|
@ -112,7 +112,7 @@ impl AsyncComponent for WivrnWiredStartBox {
|
||||||
Self::Input::UpdateSelectedProfile(p) => self.set_selected_profile(p),
|
Self::Input::UpdateSelectedProfile(p) => self.set_selected_profile(p),
|
||||||
Self::Input::StartWivrnClient => {
|
Self::Input::StartWivrnClient => {
|
||||||
if !dep_adb().check() {
|
if !dep_adb().check() {
|
||||||
alert("ADB is not installed", Some(&format!("Please install ADB on your computer to start the WiVRn client from {APP_NAME}.")), Some(&self.root_win));
|
alert("ADB is not installed", Some(&format!("Please install ADB on your computer to start the WiVRn client from {}.", APP_NAME)), Some(&self.root_win));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.set_start_client_status(StartClientStatus::InProgress);
|
self.set_start_client_status(StartClientStatus::InProgress);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{async_process::async_process, depcheck::common::dep_getcap_setcap, profile::Profile};
|
use crate::{async_process::async_process, profile::Profile};
|
||||||
use anyhow::bail;
|
use anyhow::bail;
|
||||||
use nix::{
|
use nix::{
|
||||||
errno::Errno,
|
errno::Errno,
|
||||||
|
@ -79,29 +79,9 @@ pub fn set_file_readonly(path: &Path, readonly: bool) -> anyhow::Result<()> {
|
||||||
Ok(fs::set_permissions(path, perms)?)
|
Ok(fs::set_permissions(path, perms)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setcap_executable() -> Option<String> {
|
|
||||||
if dep_getcap_setcap().check() {
|
|
||||||
Some("setcap".into())
|
|
||||||
} else if Path::new("/sbin/setcap").try_exists().unwrap_or_default() {
|
|
||||||
Some("/sbin/setcap".into())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn getcap_executable() -> Option<String> {
|
|
||||||
if dep_getcap_setcap().check() {
|
|
||||||
Some("getcap".into())
|
|
||||||
} else if Path::new("/sbin/getcap").try_exists().unwrap_or_default() {
|
|
||||||
Some("/sbin/getcap".into())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn setcap_cap_sys_nice_eip_cmd(profile: &Profile) -> Vec<String> {
|
pub fn setcap_cap_sys_nice_eip_cmd(profile: &Profile) -> Vec<String> {
|
||||||
vec![
|
vec![
|
||||||
setcap_executable().unwrap_or("setcap".into()),
|
"setcap".into(),
|
||||||
"CAP_SYS_NICE=eip".into(),
|
"CAP_SYS_NICE=eip".into(),
|
||||||
profile
|
profile
|
||||||
.prefix
|
.prefix
|
||||||
|
@ -113,29 +93,24 @@ pub fn setcap_cap_sys_nice_eip_cmd(profile: &Profile) -> Vec<String> {
|
||||||
|
|
||||||
pub async fn verify_cap_sys_nice_eip(profile: &Profile) -> bool {
|
pub async fn verify_cap_sys_nice_eip(profile: &Profile) -> bool {
|
||||||
let xrservice_binary = profile.xrservice_binary().to_string_lossy().to_string();
|
let xrservice_binary = profile.xrservice_binary().to_string_lossy().to_string();
|
||||||
if let Some(getcap_exec) = getcap_executable() {
|
match async_process("getcap", Some(&[&xrservice_binary]), None).await {
|
||||||
match async_process(&getcap_exec, Some(&[&xrservice_binary]), None).await {
|
Err(e) => {
|
||||||
Err(e) => {
|
error!("failed to run `getcap {xrservice_binary}`: {e:?}");
|
||||||
error!("failed to run `getcap {xrservice_binary}`: {e:?}");
|
false
|
||||||
|
}
|
||||||
|
Ok(out) => {
|
||||||
|
debug!("getcap {xrservice_binary} stdout: {}", out.stdout);
|
||||||
|
debug!("getcap {xrservice_binary} stderr: {}", out.stderr);
|
||||||
|
if out.exit_code != 0 {
|
||||||
|
error!(
|
||||||
|
"command `getcap {xrservice_binary}` failed with status code {}",
|
||||||
|
out.exit_code
|
||||||
|
);
|
||||||
false
|
false
|
||||||
}
|
} else {
|
||||||
Ok(out) => {
|
out.stdout.to_lowercase().contains("cap_sys_nice=eip")
|
||||||
debug!("getcap {xrservice_binary} stdout: {}", out.stdout);
|
|
||||||
debug!("getcap {xrservice_binary} stderr: {}", out.stderr);
|
|
||||||
if out.exit_code != 0 {
|
|
||||||
error!(
|
|
||||||
"command `getcap {xrservice_binary}` failed with status code {}",
|
|
||||||
out.exit_code
|
|
||||||
);
|
|
||||||
false
|
|
||||||
} else {
|
|
||||||
out.stdout.to_lowercase().contains("cap_sys_nice=eip")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
error!("getcap executable does not exist");
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,5 +12,5 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"application": ["foobar", "baz"],
|
"application": ["foobar", "baz"],
|
||||||
"tcp-only": true
|
"tcp_only": true
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue