diff --git a/Cargo.lock b/Cargo.lock index cb2d639..312a7aa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -445,16 +445,6 @@ dependencies = [ "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]] name = "deranged" version = "0.3.11" @@ -573,11 +563,10 @@ dependencies = [ [[package]] name = "envision" -version = "3.1.1" +version = "3.0.0" dependencies = [ "anyhow", "ash", - "delicious-adwaita", "gettext-rs", "git2", "gtk4", @@ -1084,9 +1073,9 @@ dependencies = [ [[package]] name = "gtk4" -version = "0.9.6" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1c491051f030994fd0cde6f3c44f3f5640210308cff1298c7673c47408091d" +checksum = "9376d14d7e33486c54823a42bef296e882b9f25cb4c52b52f4d1d57bbadb5b6d" dependencies = [ "cairo-rs", "field-offset", @@ -1117,9 +1106,9 @@ dependencies = [ [[package]] name = "gtk4-sys" -version = "0.9.6" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41e03b01e54d77c310e1d98647d73f996d04b2f29b9121fe493ea525a7ec03d6" +checksum = "e653b0a9001ba9be1ffddb9373bfe9a111f688222f5aeee2841481300d91b55a" dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", @@ -1534,9 +1523,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libadwaita" -version = "0.7.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500135d29c16aabf67baafd3e7741d48e8b8978ca98bac39e589165c8dc78191" +checksum = "8611ee9fb85e7606c362b513afcaf5b59853f79e4d98caaaf581d99465014247" dependencies = [ "gdk4", "gio", diff --git a/Cargo.toml b/Cargo.toml index 4ecd109..f41c7f6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "envision" -version = "3.1.1" +version = "3.0.0" edition = "2021" authors = [ "Gabriele Musco ", @@ -44,4 +44,3 @@ tracing-subscriber = { version = "0.3.19", features = ["env-filter", "json"] } tracing = "0.1.41" tracing-appender = "0.2.3" serde_yaml = "0.9.34" -delicious-adwaita = { version = "0.3.0", features = ["all_themes"] } diff --git a/data/org.gabmus.envision.metainfo.xml.in.in b/data/org.gabmus.envision.metainfo.xml.in.in index 76b4dd4..cbe2b3a 100644 --- a/data/org.gabmus.envision.metainfo.xml.in.in +++ b/data/org.gabmus.envision.metainfo.xml.in.in @@ -30,43 +30,6 @@ @REPO_URL@/issues - - -

Fixes

-
    -
  • add libusb and libusb-dev deps
  • -
  • Revert "disable and blacklist wayvr dashboard plugin"
  • -
-
-
- - -

What's new

-
    -
  • don't set openvrpaths as read only during profile startup
  • -
  • small design changes to build window ui
  • -
  • add support for vapor openvr compatibility module
  • -
  • remove monado vulkan layers check for nvidia
  • -
-

Fixes

-
    -
  • disable and blacklist wayvr dashboard plugin
  • -
  • monado dependencies: use wayland-protocols-devel on Fedora
  • -
-

Other changes

-
    -
  • clippy
  • -
-
-
- - -

Fixes

-
    -
  • libnotify headers path in wivrn depcheck
  • -
-
-

Breaking changes

diff --git a/dist/arch/PKGBUILD b/dist/arch/PKGBUILD index ee1a4b2..3ff8a64 100644 --- a/dist/arch/PKGBUILD +++ b/dist/arch/PKGBUILD @@ -33,6 +33,7 @@ makedepends=( ) optdepends=( 'libudev0-shim: steamvr_lh lighthouse driver support' + 'monado-vulkan-layers-git: Vulkan layers for NVIDIA users' ) provides=(envision) conflicts=(envision) diff --git a/meson.build b/meson.build index d58f4ed..8a4176b 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'envision', 'rust', - version: '3.1.1', # version number row + version: '3.0.0', # version number row meson_version: '>= 0.59', license: 'AGPL-3.0-or-later', ) diff --git a/src/builders/build_basalt.rs b/src/builders/build_basalt.rs index b2a55bd..10d6029 100644 --- a/src/builders/build_basalt.rs +++ b/src/builders/build_basalt.rs @@ -5,10 +5,7 @@ use crate::{ ui::job_worker::job::WorkerJob, util::file_utils::rm_rf, }; -use std::{ - collections::{HashMap, VecDeque}, - num::NonZero, -}; +use std::collections::{HashMap, VecDeque}; pub fn get_build_basalt_jobs(profile: &Profile, clean_build: bool) -> VecDeque { let mut jobs = VecDeque::::new(); @@ -43,23 +40,11 @@ pub fn get_build_basalt_jobs(profile: &Profile, clean_build: bool) -> VecDeque = HashMap::new(); for (k, v) in [ - // The basalt build uses a lot of RAM, so we have to limit the number of - // build processes to not starve the system of memory - // Limit to 6 build processes at most - ( - "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()), - ("BUILD_TESTS", "off".into()), + ("CMAKE_BUILD_PARALLEL_LEVEL", "2"), + ("CMAKE_BUILD_TYPE", "RelWithDebInfo"), + ("BUILD_TESTS", "off"), ] { - cmake_env.insert(k.to_string(), v); + cmake_env.insert(k.to_string(), v.to_string()); } cmake_env }), diff --git a/src/builders/build_vapor.rs b/src/builders/build_vapor.rs deleted file mode 100644 index 5a05932..0000000 --- a/src/builders/build_vapor.rs +++ /dev/null @@ -1,68 +0,0 @@ -use crate::{ - build_tools::{cmake::Cmake, git::Git}, - profile::Profile, - termcolor::TermColor, - ui::job_worker::job::WorkerJob, - util::file_utils::rm_rf, -}; -use std::{ - collections::{HashMap, VecDeque}, - path::Path, -}; - -pub fn get_build_vapor_jobs(profile: &Profile, clean_build: bool) -> VecDeque { - let mut jobs = VecDeque::::new(); - jobs.push_back(WorkerJob::new_printer( - "Building VapoR...", - Some(TermColor::Blue), - )); - - let git = Git { - repo: profile - .ovr_comp - .repo - .as_ref() - .unwrap_or(&"https://github.com/micheal65536/VapoR.git".into()) - .clone(), - dir: profile.ovr_comp.path.clone(), - branch: profile - .ovr_comp - .branch - .as_ref() - .unwrap_or(&"master".into()) - .clone(), - }; - - jobs.extend(git.get_pre_build_jobs(profile.pull_on_build)); - - let build_dir = profile.ovr_comp.path.join("build"); - let install_dir = build_dir.join("install_pfx"); - let cmake = Cmake { - env: None, - vars: Some({ - let mut cmake_vars: HashMap = HashMap::new(); - for (k, v) in [ - ("VAPOR_LOG_SILENT", "ON"), - ("USE_SYSTEM_OPENXR", "OFF"), - ("CMAKE_BUILD_TYPE", "RelWithDebInfo"), - ] { - 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 - }), - source_dir: profile.ovr_comp.path.clone(), - build_dir: build_dir.clone(), - }; - if !Path::new(&build_dir).is_dir() || clean_build { - rm_rf(&build_dir); - jobs.push_back(cmake.get_prepare_job()); - } - jobs.push_back(cmake.get_build_job()); - jobs.push_back(cmake.get_install_job()); - - jobs -} diff --git a/src/builders/mod.rs b/src/builders/mod.rs index 9d57245..1f66748 100644 --- a/src/builders/mod.rs +++ b/src/builders/mod.rs @@ -4,6 +4,5 @@ pub mod build_mercury; pub mod build_monado; pub mod build_opencomposite; pub mod build_openhmd; -pub mod build_vapor; pub mod build_wivrn; pub mod build_xrizer; diff --git a/src/config.rs b/src/config.rs index 80cf0f5..18cd864 100644 --- a/src/config.rs +++ b/src/config.rs @@ -45,10 +45,6 @@ const fn default_win_size() -> [i32; 2] { DEFAULT_WIN_SIZE } -fn default_theme_name() -> String { - "Follow system".into() -} - #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct Config { pub selected_profile_uuid: String, @@ -58,8 +54,6 @@ pub struct Config { pub win_size: [i32; 2], #[serde(default)] pub plugins: HashMap, - #[serde(default = "default_theme_name")] - pub theme_name: String, } impl Default for Config { @@ -71,7 +65,6 @@ impl Default for Config { user_profiles: Vec::default(), win_size: DEFAULT_WIN_SIZE, plugins: HashMap::default(), - theme_name: default_theme_name(), } } } diff --git a/src/depcheck/basalt_deps.rs b/src/depcheck/basalt_deps.rs index 00a29b6..2a05826 100644 --- a/src/depcheck/basalt_deps.rs +++ b/src/depcheck/basalt_deps.rs @@ -1,7 +1,7 @@ use super::{ boost_deps::boost_deps, 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 std::collections::HashMap; @@ -181,5 +181,9 @@ pub fn check_basalt_deps() -> Vec { } pub fn get_missing_basalt_deps() -> Vec { - check_basalt_deps().filter_missing_deps() + check_basalt_deps() + .iter() + .filter(|res| !res.found) + .map(|res| res.dependency.clone()) + .collect() } diff --git a/src/depcheck/common.rs b/src/depcheck/common.rs index 901d0ff..56ac4ef 100644 --- a/src/depcheck/common.rs +++ b/src/depcheck/common.rs @@ -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()), - ]), - } -} diff --git a/src/depcheck/libsurvive_deps.rs b/src/depcheck/libsurvive_deps.rs index 46eec55..c9e8d9c 100644 --- a/src/depcheck/libsurvive_deps.rs +++ b/src/depcheck/libsurvive_deps.rs @@ -1,6 +1,6 @@ use super::{ common::{dep_cmake, dep_eigen, dep_gcc, dep_git, dep_gpp, dep_ninja}, - DepcheckResultGetMissing, Dependency, DependencyCheckResult, + Dependency, DependencyCheckResult, }; fn libsurvive_deps() -> Vec { @@ -19,5 +19,9 @@ pub fn check_libsurvive_deps() -> Vec { } pub fn get_missing_libsurvive_deps() -> Vec { - check_libsurvive_deps().filter_missing_deps() + check_libsurvive_deps() + .iter() + .filter(|res| !res.found) + .map(|res| res.dependency.clone()) + .collect() } diff --git a/src/depcheck/mercury_deps.rs b/src/depcheck/mercury_deps.rs index a7e59be..cad3c80 100644 --- a/src/depcheck/mercury_deps.rs +++ b/src/depcheck/mercury_deps.rs @@ -1,6 +1,4 @@ -use super::{ - common::dep_opencv, DepType, DepcheckResultGetMissing, Dependency, DependencyCheckResult, -}; +use super::{common::dep_opencv, DepType, Dependency, DependencyCheckResult}; use crate::linux_distro::LinuxDistro; use std::collections::HashMap; @@ -41,5 +39,9 @@ pub fn check_mercury_deps() -> Vec { } pub fn get_missing_mercury_deps() -> Vec { - check_mercury_deps().filter_missing_deps() + check_mercury_deps() + .iter() + .filter(|res| !res.found) + .map(|res| res.dependency.clone()) + .collect() } diff --git a/src/depcheck/mod.rs b/src/depcheck/mod.rs index f2565eb..002a8c8 100644 --- a/src/depcheck/mod.rs +++ b/src/depcheck/mod.rs @@ -6,7 +6,6 @@ pub mod mercury_deps; pub mod monado_deps; pub mod openhmd_deps; pub mod wivrn_deps; -pub mod xrizer_deps; use crate::linux_distro::LinuxDistro; 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; -} - -impl DepcheckResultGetMissing for Vec { - fn filter_missing_deps(self) -> Vec { - self.into_iter() - .filter_map(|res| { - if !res.found { - Some(res.dependency) - } else { - None - } - }) - .collect() - } -} - fn shared_obj_paths() -> Vec { vec![ "/lib".into(), @@ -136,24 +117,6 @@ fn shared_obj_paths() -> Vec { "/usr/local/lib64".into(), "/usr/lib/x86_64-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/aarch64-linux-gnu".into(), "/app/lib".into(), @@ -177,8 +140,6 @@ fn include_paths() -> Vec { "/usr/include/ffmpeg/libpostproc".into(), "/usr/include/ffmpeg/libswresample".into(), "/usr/include/ffmpeg/libswscale".into(), - // opensuse puts wayland-client.h here - "/usr/include/wayland".into(), ] } diff --git a/src/depcheck/monado_deps.rs b/src/depcheck/monado_deps.rs index f9e1b9b..93055d3 100644 --- a/src/depcheck/monado_deps.rs +++ b/src/depcheck/monado_deps.rs @@ -4,12 +4,9 @@ use super::{ dep_libgl, dep_libudev, dep_libx11, dep_libxcb, dep_ninja, dep_openxr, dep_vulkan_headers, dep_vulkan_icd_loader, }, - DepType, DepcheckResultGetMissing, Dependency, DependencyCheckResult, -}; -use crate::{ - depcheck::common::{dep_glslc, dep_libxrandr}, - linux_distro::LinuxDistro, + DepType, Dependency, DependencyCheckResult, }; +use crate::{depcheck::common::dep_libxrandr, linux_distro::LinuxDistro}; use std::collections::HashMap; fn monado_deps() -> Vec { @@ -40,7 +37,7 @@ fn monado_deps() -> Vec { packages: HashMap::from([ (LinuxDistro::Arch, "wayland-protocols".into()), (LinuxDistro::Debian, "wayland-protocols".into()), - (LinuxDistro::Fedora, "wayland-protocols-devel".into()), + (LinuxDistro::Fedora, "wayland-protocols".into()), (LinuxDistro::Gentoo, "dev-libs/wayland-protocols".into()), (LinuxDistro::Suse, "wayland-protocols-devel".into()), ]), @@ -63,7 +60,19 @@ fn monado_deps() -> Vec { dep_ninja(), dep_gcc(), 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(), Dependency { name: "sdl2".into(), @@ -74,34 +83,10 @@ fn monado_deps() -> Vec { (LinuxDistro::Debian, "libsdl2-dev".into()), (LinuxDistro::Fedora, "SDL2-devel".into()), (LinuxDistro::Gentoo, "media-libs/libsdl2".into()), - (LinuxDistro::Suse, "sdl2-compat-devel".into()), + (LinuxDistro::Suse, "SDL2-devel".into()), ]), }, 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 { name: "mesa-common-dev".into(), dep_type: DepType::Include, @@ -122,5 +107,9 @@ pub fn check_monado_deps() -> Vec { } pub fn get_missing_monado_deps() -> Vec { - check_monado_deps().filter_missing_deps() + check_monado_deps() + .iter() + .filter(|res| !res.found) + .map(|res| res.dependency.clone()) + .collect() } diff --git a/src/depcheck/openhmd_deps.rs b/src/depcheck/openhmd_deps.rs index d31d013..819324f 100644 --- a/src/depcheck/openhmd_deps.rs +++ b/src/depcheck/openhmd_deps.rs @@ -1,6 +1,6 @@ use super::{ common::{dep_gcc, dep_git, dep_gpp, dep_ninja}, - DepcheckResultGetMissing, Dependency, DependencyCheckResult, + Dependency, DependencyCheckResult, }; use crate::linux_distro::LinuxDistro; use std::collections::HashMap; @@ -31,5 +31,9 @@ pub fn check_openhmd_deps() -> Vec { } pub fn get_missing_openhmd_deps() -> Vec { - check_openhmd_deps().filter_missing_deps() + check_openhmd_deps() + .iter() + .filter(|res| !res.found) + .map(|res| res.dependency.clone()) + .collect() } diff --git a/src/depcheck/wivrn_deps.rs b/src/depcheck/wivrn_deps.rs index 9126272..fc704d9 100644 --- a/src/depcheck/wivrn_deps.rs +++ b/src/depcheck/wivrn_deps.rs @@ -4,7 +4,7 @@ use super::{ dep_libudev, dep_libx11, dep_libxcb, dep_ninja, dep_openxr, dep_vulkan_headers, dep_vulkan_icd_loader, }, - DepType, DepcheckResultGetMissing, Dependency, DependencyCheckResult, + DepType, Dependency, DependencyCheckResult, }; use crate::{ depcheck::common::{dep_libgl, dep_libxrandr}, @@ -253,7 +253,7 @@ fn wivrn_deps() -> Vec { Dependency { name: "libnotify-dev".into(), dep_type: DepType::Include, - filename: "libnotify/notify.h".into(), + filename: "openssl/ssl3.h".into(), packages: HashMap::from([ (LinuxDistro::Arch, "libnotify".into()), (LinuxDistro::Alpine, "libnotify-dev".into()), @@ -270,5 +270,9 @@ pub fn check_wivrn_deps() -> Vec { } pub fn get_missing_wivrn_deps() -> Vec { - check_wivrn_deps().filter_missing_deps() + check_wivrn_deps() + .iter() + .filter(|res| !res.found) + .map(|res| res.dependency.clone()) + .collect() } diff --git a/src/depcheck/xrizer_deps.rs b/src/depcheck/xrizer_deps.rs deleted file mode 100644 index 49d9354..0000000 --- a/src/depcheck/xrizer_deps.rs +++ /dev/null @@ -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 { - 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 { - Dependency::check_many(xrizer_deps()) -} - -pub fn get_missing_xrizer_deps() -> Vec { - check_xrizer_deps().filter_missing_deps() -} diff --git a/src/file_builders/openvrpaths_vrpath.rs b/src/file_builders/openvrpaths_vrpath.rs index 1b888c2..7bd431b 100644 --- a/src/file_builders/openvrpaths_vrpath.rs +++ b/src/file_builders/openvrpaths_vrpath.rs @@ -85,7 +85,6 @@ fn build_steam_openvrpaths() -> OpenVrPaths { } pub fn set_current_openvrpaths_to_steam() -> anyhow::Result<()> { - // removing readonly flag just in case, remove this line in the future set_file_readonly(&get_openvrpaths_vrpath_path(), false)?; dump_current_openvrpaths(&build_steam_openvrpaths())?; Ok(()) @@ -105,18 +104,19 @@ pub fn build_profile_openvrpaths(profile: &Profile) -> OpenVrPaths { pub fn set_current_openvrpaths_to_profile(profile: &Profile) -> anyhow::Result<()> { let dest = get_openvrpaths_vrpath_path(); - // removing readonly flag just in case, remove this line in the future set_file_readonly(&dest, false)?; backup_steam_openvrpaths(); dump_current_openvrpaths(&build_profile_openvrpaths(profile))?; + set_file_readonly(&dest, true)?; Ok(()) } #[cfg(test)] mod tests { - use super::{dump_openvrpaths_to_path, get_openvrpaths_from_path, OpenVrPaths}; use std::path::Path; + use super::{dump_openvrpaths_to_path, get_openvrpaths_from_path, OpenVrPaths}; + #[test] fn can_read_openvrpaths_vrpath_steamvr() { let ovrp = get_openvrpaths_from_path(Path::new("./test/files/openvrpaths.vrpath")).unwrap(); diff --git a/src/linux_distro.rs b/src/linux_distro.rs index 2fcd76a..7bdfe0b 100644 --- a/src/linux_distro.rs +++ b/src/linux_distro.rs @@ -49,13 +49,13 @@ impl LinuxDistro { Ok(_) if buf.starts_with("PRETTY_NAME=\"") => { return buf .split('=') - .next_back() + .last() .map(|b| b.trim().trim_matches('"').trim().to_string()); } Ok(_) if buf.starts_with("NAME=\"") => { name = buf .split('=') - .next_back() + .last() .map(|b| b.trim().trim_matches('"').trim().to_string()); } _ => {} @@ -79,7 +79,7 @@ impl LinuxDistro { { let name = buf .split('=') - .next_back() + .last() .unwrap_or_default() .trim() .trim_matches('"') @@ -115,7 +115,6 @@ impl LinuxDistro { || s.contains("steamos") || s.contains("steam os") || s.contains("endeavour") - || s.contains("cachyos") || s.contains("garuda") { return Some(Self::Arch); @@ -151,33 +150,7 @@ impl LinuxDistro { Self::Alpine => format!("sudo apk add {}", packages.join(" ")), Self::Debian => format!("sudo apt install {}", packages.join(" ")), Self::Gentoo => format!("sudo emerge -av {}", packages.join(" ")), - Self::Suse => { - 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::>() - .join(" && ") - } + Self::Suse => format!("sudo zypper install {}", packages.join(" ")), Self::Fedora => { let mut install_rpmfusion_cmd: Option = None; let mut swap_ffmpeg_cmd: Option = None; @@ -217,10 +190,10 @@ impl LinuxDistro { #[cfg(test)] mod tests { - use super::LinuxDistro; - use crate::depcheck::common::{dep_openxr, dep_pkexec, dep_vulkan_icd_loader}; use std::path::Path; + use super::LinuxDistro; + #[test] fn can_detect_arch_linux_from_etc_os_release() { assert_eq!( @@ -230,34 +203,4 @@ mod tests { 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::>() - ) - .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::>() - ) - .as_str(), - "sudo zypper install polkit vulkan-devel" - ) - } } diff --git a/src/main.rs b/src/main.rs index 217434e..bb72425 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,14 +11,9 @@ use relm4::{ gtk::{self, gdk, gio, glib, prelude::*}, MessageBroker, RelmApp, }; -use std::{ - env, - fs::{read_dir, remove_file}, - os::unix::fs::MetadataExt, - path::{Path, PathBuf}, -}; +use std::env; use steam_linux_runtime_injector::restore_runtime_entrypoint; -use tracing::{error, warn}; +use tracing::warn; use tracing_subscriber::{ filter::LevelFilter, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, Layer, }; @@ -71,55 +66,11 @@ fn restore_steam_xr_files() { restore_runtime_entrypoint(); } -const LOGS_MAX_SIZE_BYTES: u64 = 1000000000; // 1GB - -fn remove_old_logs(dir: &Path, log_files: Option>) -> anyhow::Result<()> { - let log_files: Vec = log_files - .map::>, _>(Ok) - .unwrap_or_else(|| { - let mut files: Vec = 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<()> { if env::var("USER").unwrap_or_else(|_| env::var("USERNAME").unwrap_or_default()) == "root" { panic!("{APP_NAME} cannot run as root"); } 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 (non_blocking_appender, _appender_guard) = @@ -139,10 +90,6 @@ fn main() -> Result<()> { ) .init(); - if let Err(e) = old_logs_removal_res { - error!("Failed to remove old log files: {e}"); - } - // Prepare i18n gettextrs::setlocale(LocaleCategory::LcAll, ""); gettextrs::bindtextdomain(GETTEXT_PACKAGE, LOCALE_DIR).expect("Unable to bind the text domain"); diff --git a/src/profile.rs b/src/profile.rs index 2666291..ad6b170 100644 --- a/src/profile.rs +++ b/src/profile.rs @@ -2,8 +2,7 @@ use crate::{ depcheck::{ basalt_deps::get_missing_basalt_deps, libsurvive_deps::get_missing_libsurvive_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, - xrizer_deps::get_missing_xrizer_deps, Dependency, + openhmd_deps::get_missing_openhmd_deps, wivrn_deps::get_missing_wivrn_deps, Dependency, }, file_builders::active_runtime_json::ActiveRuntime, paths::{get_data_dir, BWRAP_SYSTEM_PREFIX, SYSTEM_PREFIX}, @@ -15,7 +14,7 @@ use serde::{Deserialize, Serialize}; use std::{ collections::HashMap, fmt::Display, - fs::{remove_dir_all, File}, + fs::File, io::BufReader, path::{Path, PathBuf}, slice::Iter, @@ -266,7 +265,6 @@ pub enum OvrCompatibilityModuleType { #[default] Opencomposite, Xrizer, - Vapor, } impl Display for OvrCompatibilityModuleType { @@ -274,23 +272,13 @@ impl Display for OvrCompatibilityModuleType { f.write_str(match self { Self::Opencomposite => "OpenComposite", Self::Xrizer => "xrizer", - Self::Vapor => "VapoR", }) } } impl OvrCompatibilityModuleType { pub fn iter() -> Iter<'static, Self> { - [Self::Opencomposite, Self::Xrizer, Self::Vapor].iter() - } - - pub fn get_missing_deps(&self) -> Vec { - match self { - OvrCompatibilityModuleType::Xrizer => get_missing_xrizer_deps(), - OvrCompatibilityModuleType::Opencomposite | OvrCompatibilityModuleType::Vapor => { - Vec::default() - } - } + [Self::Opencomposite, Self::Xrizer].iter() } } @@ -301,7 +289,6 @@ impl FromStr for OvrCompatibilityModuleType { match s.to_lowercase().trim() { "opencomposite" => Ok(Self::Opencomposite), "xrizer" => Ok(Self::Xrizer), - "vapor" => Ok(Self::Vapor), _ => Err(format!("no match for ovr compatibility module `{s}`")), } } @@ -312,8 +299,7 @@ impl From for OvrCompatibilityModuleType { match value { 0 => Self::Opencomposite, 1 => Self::Xrizer, - 2 => Self::Vapor, - _ => panic!("OvrCompatibilityModuleType index out of bounds"), + _ => panic!("OvrCompatibilityModuleType index out of bounds"), } } } @@ -342,7 +328,6 @@ impl ProfileOvrCompatibilityModule { pub fn runtime_dir(&self) -> PathBuf { match self.mod_type { OvrCompatibilityModuleType::Opencomposite => self.path.join("build"), - OvrCompatibilityModuleType::Vapor => self.path.join("build/install_pfx/lib/VapoR"), OvrCompatibilityModuleType::Xrizer => self.path.join("target/release"), } } @@ -459,29 +444,6 @@ impl Profile { get_data_dir().join("prefixes").join(uuid) } - /// deletes files and folders associated to this profile (mostly repo clones) - pub fn delete_files(&self) -> Vec> { - [ - 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 { format!( "XR_RUNTIME_JSON=\"{prefix}/share/openxr/1/openxr_{runtime}.json\"", @@ -746,7 +708,7 @@ impl Profile { if self.features.mercury_enabled { 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.dedup(); // dedup only works if sorted, hence the above diff --git a/src/ui/about_dialog.rs b/src/ui/about_dialog.rs index 0e28534..8f4235e 100644 --- a/src/ui/about_dialog.rs +++ b/src/ui/about_dialog.rs @@ -33,7 +33,7 @@ pub fn create_about_dialog() -> adw::AboutDialog { const UNKNOWN: &str = "UNKNOWN"; pub fn populate_debug_info(dialog: &adw::AboutDialog, vkinfo: Option<&VulkanInfo>) { - if !dialog.debug_info().is_empty() { + if dialog.debug_info().len() > 0 { return; } let distro_family = LinuxDistro::get(); @@ -70,7 +70,7 @@ pub fn populate_debug_info(dialog: &adw::AboutDialog, vkinfo: Option<&VulkanInfo .and_then(|s| { s.split("\n") .find(|line| line.starts_with("model name")) - .map(|line| line.split(':').next_back().map(|s| s.trim().to_string())) + .map(|line| line.split(':').last().map(|s| s.trim().to_string())) }) .flatten() .unwrap_or(UNKNOWN.into()) @@ -81,6 +81,12 @@ pub fn populate_debug_info(dialog: &adw::AboutDialog, vkinfo: Option<&VulkanInfo .map(|i| i.gpu_names.join(", ")) .unwrap_or(UNKNOWN.into()) ), + format!( + "Monado Vulkan Layers: {}", + vkinfo + .map(|i| i.has_monado_vulkan_layers.to_string()) + .unwrap_or(UNKNOWN.into()) + ), format!("Detected XR Devices: {}", { let devs = PhysicalXRDevice::from_usb(); if devs.is_empty() { diff --git a/src/ui/app.rs b/src/ui/app.rs index 6201648..98510a3 100644 --- a/src/ui/app.rs +++ b/src/ui/app.rs @@ -20,8 +20,7 @@ use crate::{ build_basalt::get_build_basalt_jobs, build_libsurvive::get_build_libsurvive_jobs, build_mercury::get_build_mercury_jobs, build_monado::get_build_monado_jobs, build_opencomposite::get_build_opencomposite_jobs, build_openhmd::get_build_openhmd_jobs, - build_vapor::get_build_vapor_jobs, build_wivrn::get_build_wivrn_jobs, - build_xrizer::get_build_xrizer_jobs, + build_wivrn::get_build_wivrn_jobs, build_xrizer::get_build_xrizer_jobs, }, config::{Config, PluginConfig}, constants::APP_NAME, @@ -43,7 +42,6 @@ use crate::{ steam_linux_runtime_injector::{ restore_runtime_entrypoint, set_runtime_entrypoint_launch_opts_from_profile, }, - termcolor::TermColor, util::file_utils::{ setcap_cap_sys_nice_eip, setcap_cap_sys_nice_eip_cmd, verify_cap_sys_nice_eip, }, @@ -52,7 +50,6 @@ use crate::{ xr_devices::XRDevice, }; use adw::{prelude::*, ResponseAppearance}; -use delicious_adwaita::{theme::Theme, ThemeEngine}; use gtk::glib::{self, clone}; use notify_rust::NotificationHandle; use relm4::{ @@ -98,8 +95,6 @@ pub struct App { inhibit_fail_notif: Option, pluginstore: Option>, - - theme_engine: ThemeEngine, } #[derive(Debug)] @@ -117,8 +112,7 @@ pub enum Msg { StartWithDebug, RestartXRService, ProfileSelected(Profile), - /// bool param: delete files - DeleteProfile(bool), + DeleteProfile, SaveProfile(Profile), RunSetCap, OpenLibsurviveSetup, @@ -134,8 +128,6 @@ pub enum Msg { WivrnCheckPairMode, OpenPluginStore, UpdateConfigPlugins(HashMap), - ShowThemeManager, - SaveThemeConfig, NoOp, } @@ -373,7 +365,7 @@ impl AsyncComponent for App { set_content: Some(&adw::NavigationPage::new(model.debug_view.widget(), "Debug View")), set_show_content: false, set_collapsed: !model.config.debug_view_enabled, - }, + } }, connect_close_request[sender] => move |win| { sender.input(Msg::SaveWinSize(win.width(), win.height())); @@ -397,27 +389,6 @@ impl AsyncComponent for App { ) { match message { 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) => { if !rows.is_empty() { self.debug_view @@ -562,9 +533,6 @@ impl AsyncComponent for App { OvrCompatibilityModuleType::Xrizer => { get_build_xrizer_jobs(&profile, clean_build) } - OvrCompatibilityModuleType::Vapor => { - get_build_vapor_jobs(&profile, clean_build) - } }); let missing_deps = profile.missing_dependencies(); if !(self.skip_depcheck || profile.skip_dependency_check || missing_deps.is_empty()) @@ -654,10 +622,6 @@ impl AsyncComponent for App { if dep_pkexec().check() { self.setcap_confirm_dialog.present(Some(&self.app_win)); } else { - self.build_window - .sender() - .emit(BuildWindowMsg::UpdateContent(vec![TermColor::Red - .colorize("pkexec not found, cannot set capabilities\n")])); alert_w_widget( "pkexec not found", Some(&format!( @@ -690,16 +654,9 @@ impl AsyncComponent for App { w.stop(); } } - Msg::DeleteProfile(delete_files) => { + Msg::DeleteProfile => { let todel = self.get_selected_profile(); 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.save(); self.profiles = self.config.profiles(); @@ -739,7 +696,6 @@ impl AsyncComponent for App { } Msg::RunSetCap => { if !dep_pkexec().check() { - // there's a precheck ahead of this, this should likely never happen error!("pkexec not found, skipping setcap"); } else { let profile = self.get_selected_profile(); @@ -757,26 +713,8 @@ impl AsyncComponent for App { if let Err(e) = setcap_cap_sys_nice_eip(&profile).await { setcap_failed_dialog(); 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 { 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") - ])); } } } @@ -1024,17 +962,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 // to enable/disable it in update() let configure_wivrn_action = { @@ -1071,12 +998,13 @@ impl AsyncComponent for App { config: config.clone(), selected_profile: selected_profile.clone(), root_win: root.clone().into(), + vkinfo: vkinfo.clone(), }) .forward(sender.input_sender(), |message| match message { MainViewOutMsg::DoStartStopXRService => Msg::DoStartStopXRService, MainViewOutMsg::RestartXRService => Msg::RestartXRService, 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::OpenLibsurviveSetup => Msg::OpenLibsurviveSetup, MainViewOutMsg::BuildProfile(clean) => Msg::BuildProfile(clean), @@ -1103,17 +1031,6 @@ impl AsyncComponent for App { .detach(), split_view: None, 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, profiles, xrservice_worker: None, @@ -1202,7 +1119,6 @@ new_stateless_action!(pub QuitAction, AppActionGroup, "quit"); new_stateful_action!(pub DebugViewToggleAction, AppActionGroup, "debugviewtoggle", (), bool); new_stateless_action!(pub ConfigureWivrnAction, AppActionGroup, "configurewivrn"); 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 DebugOpenPrefixAction, AppActionGroup, "debugopenprefix"); diff --git a/src/ui/build_window.rs b/src/ui/build_window.rs index f6f8b21..759af9b 100644 --- a/src/ui/build_window.rs +++ b/src/ui/build_window.rs @@ -1,5 +1,3 @@ -use crate::termcolor::TermColor; - use super::{term_widget::TermWidget, SENDER_IO_ERR_MSG}; use adw::prelude::*; use relm4::prelude::*; @@ -90,54 +88,43 @@ impl SimpleComponent for BuildWindow { gtk::Label { #[track = "model.changed(BuildWindow::build_status())"] set_markup: match &model.build_status { - BuildStatus::Building => String::default(), - BuildStatus::Done => "Build done, you can close this window".into(), + BuildStatus::Building => "Build in progress...".to_string(), + BuildStatus::Done => "Build done, you can close this window".to_string(), BuildStatus::Error(code) => { format!("Build failed: \"{c}\"", c = code) } }.as_str(), - #[track = "model.changed(BuildWindow::build_status())"] - set_visible: match &model.build_status { - BuildStatus::Building => false, - BuildStatus::Done | BuildStatus::Error(_) => true, - }, add_css_class: "title-2", set_wrap: true, set_wrap_mode: gtk::pango::WrapMode::Word, set_justify: gtk::Justification::Center, }, + gtk::Button { + #[track = "model.changed(BuildWindow::build_status())"] + set_visible: matches!(&model.build_status, BuildStatus::Building), + add_css_class: "destructive-action", + add_css_class: "circular", + set_icon_name: "window-close-symbolic", + set_tooltip_text: Some("Cancel build"), + connect_clicked[sender] => move |_| { + sender.output(Self::Output::CancelBuild).expect(SENDER_IO_ERR_MSG); + } + }, }, model.term.container.clone(), }, - add_bottom_bar: bottom_bar = >k::Box { - set_orientation: gtk::Orientation::Horizontal, + add_bottom_bar: bottom_bar = >k::Button { + add_css_class: "pill", set_halign: gtk::Align::Center, - set_hexpand: true, - set_margin_bottom: 24, - set_spacing: 12, - gtk::Button { - add_css_class: "pill", - set_halign: gtk::Align::Center, - set_label: "Close", - #[track = "model.changed(BuildWindow::can_close())"] - set_visible: model.can_close, - connect_clicked[win] => move |_| { - win.close(); - }, + set_label: "Close", + set_margin_all: 12, + #[track = "model.changed(BuildWindow::can_close())"] + set_sensitive: model.can_close, + connect_clicked[win] => move |_| { + + win.close(); }, - // this - gtk::Button { - #[track = "model.changed(BuildWindow::build_status())"] - set_visible: matches!(&model.build_status, BuildStatus::Building), - add_css_class: "destructive-action", - add_css_class: "pill", - set_label: "Cancel build", - connect_clicked[sender] => move |_| { - sender.output(Self::Output::CancelBuild).expect(SENDER_IO_ERR_MSG); - } - }, - // ^^^ - }, + } } } } @@ -166,18 +153,8 @@ impl SimpleComponent for BuildWindow { label.remove_css_class("success"); label.remove_css_class("error"); match status { - BuildStatus::Done => { - label.add_css_class("success"); - 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") - ])); - } + BuildStatus::Done => label.add_css_class("success"), + BuildStatus::Error(_) => label.add_css_class("error"), _ => {} } if status != BuildStatus::Building { diff --git a/src/ui/main_view.rs b/src/ui/main_view.rs index 8a2c145..c81a5a9 100644 --- a/src/ui/main_view.rs +++ b/src/ui/main_view.rs @@ -21,11 +21,11 @@ use crate::{ paths::{get_data_dir, get_home_dir}, profile::{LighthouseDriver, Profile, XRServiceType}, stateless_action, - ui::app::ThemeManagerAction, util::{ file_utils::{get_writer, mount_has_nosuid}, steamvr_utils::chaperone_info_exists, }, + vulkaninfo::VulkanInfo, wivrn_dbus, xr_devices::XRDevice, }; @@ -75,6 +75,8 @@ pub struct MainView { #[tracker::do_not_track] profile_export_action: gtk::gio::SimpleAction, xrservice_ready: bool, + #[tracker::do_not_track] + vkinfo: Option, wivrn_pairing_mode: bool, wivrn_pin: Option, wivrn_supports_pairing: bool, @@ -113,8 +115,7 @@ pub enum MainViewOutMsg { DoStartStopXRService, RestartXRService, ProfileSelected(Profile), - /// bool param: delete files - DeleteProfile(bool), + DeleteProfile, SaveProfile(Profile), OpenLibsurviveSetup, /// params: clean @@ -125,6 +126,7 @@ pub struct MainViewInit { pub config: Config, pub selected_profile: Profile, pub root_win: gtk::Window, + pub vkinfo: Option, } impl MainView { @@ -160,7 +162,6 @@ impl AsyncComponent for MainView { "Configure _WiVRn" => ConfigureWivrnAction, }, section! { - "Change _Theme" => ThemeManagerAction, "_About" => AboutAction, }, }, @@ -460,6 +461,34 @@ impl AsyncComponent for MainView { set_wrap_mode: gtk::pango::WrapMode::Word, } }, + gtk::Box { + set_orientation: gtk::Orientation::Vertical, + set_hexpand: true, + set_vexpand: false, + set_spacing: 12, + add_css_class: "card", + add_css_class: "padded", + set_visible: model + .vkinfo + .as_ref() + .is_some_and( + |i| i.has_nvidia_gpu && !i.has_monado_vulkan_layers + ), + warning_heading(), + gtk::Label { + set_label: concat!( + "An Nvidia GPU has been detected, but it ", + "seems you don't have the Monado Vulkan Layers ", + "installed on your system.\n\nInstall the ", + "Monado Vulkan Layers or your XR session will ", + "crash." + ), + add_css_class: "warning", + set_xalign: 0.0, + set_wrap: true, + set_wrap_mode: gtk::pango::WrapMode::Word, + } + }, gtk::Box { set_orientation: gtk::Orientation::Vertical, set_hexpand: true, @@ -934,13 +963,6 @@ impl AsyncComponent for MainView { let profile_delete_confirm_dialog = adw::AlertDialog::builder() .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(); profile_delete_confirm_dialog.add_response("no", "_No"); profile_delete_confirm_dialog.add_response("yes", "_Yes"); @@ -952,19 +974,10 @@ impl AsyncComponent for MainView { clone!( #[strong] sender, - move |dialog, res| { - let delete_files_checkbox = dialog - .extra_child() - .and_then(|child| child.downcast::().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); - } + move |_, res| { if res == "yes" { sender - .output(Self::Output::DeleteProfile(delete_files)) + .output(Self::Output::DeleteProfile) .expect("Sender output failed"); } } @@ -1090,6 +1103,7 @@ impl AsyncComponent for MainView { xrservice_ready: false, profile_delete_action, profile_export_action, + vkinfo: init.vkinfo, wivrn_pairing_mode: false, wivrn_supports_pairing: false, wivrn_pin: None, diff --git a/src/ui/plugins/mod.rs b/src/ui/plugins/mod.rs index cb18440..8d2d792 100644 --- a/src/ui/plugins/mod.rs +++ b/src/ui/plugins/mod.rs @@ -165,8 +165,8 @@ impl Plugin { /// each manifest should be json and the link should always point to the latest version const MANIFESTS: [&str;3] = [ "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/olekolek1000/wayvr-dashboard/raw/refs/heads/meta/dev.oo8.wayvr_dashboard.json", + "https://github.com/StardustXR/telescope/raw/refs/heads/main/envision/org.stardustxr.telescope.json", ]; pub async fn refresh_plugins() -> anyhow::Result>> { diff --git a/src/util/file_utils.rs b/src/util/file_utils.rs index 04efb13..ff56926 100644 --- a/src/util/file_utils.rs +++ b/src/util/file_utils.rs @@ -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 nix::{ errno::Errno, @@ -79,29 +79,9 @@ pub fn set_file_readonly(path: &Path, readonly: bool) -> anyhow::Result<()> { Ok(fs::set_permissions(path, perms)?) } -pub fn setcap_executable() -> Option { - 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 { - 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 { vec![ - setcap_executable().unwrap_or("setcap".into()), + "setcap".into(), "CAP_SYS_NICE=eip".into(), profile .prefix @@ -113,29 +93,24 @@ pub fn setcap_cap_sys_nice_eip_cmd(profile: &Profile) -> Vec { pub async fn verify_cap_sys_nice_eip(profile: &Profile) -> bool { let xrservice_binary = profile.xrservice_binary().to_string_lossy().to_string(); - if let Some(getcap_exec) = getcap_executable() { - match async_process(&getcap_exec, Some(&[&xrservice_binary]), None).await { - Err(e) => { - error!("failed to run `getcap {xrservice_binary}`: {e:?}"); + match async_process("getcap", Some(&[&xrservice_binary]), None).await { + Err(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 - } - 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 - } else { - out.stdout.to_lowercase().contains("cap_sys_nice=eip") - } + } else { + out.stdout.to_lowercase().contains("cap_sys_nice=eip") } } - } else { - error!("getcap executable does not exist"); - false } } diff --git a/src/vulkaninfo.rs b/src/vulkaninfo.rs index 6d76a92..a8f8110 100644 --- a/src/vulkaninfo.rs +++ b/src/vulkaninfo.rs @@ -5,10 +5,12 @@ use ash::{ #[derive(Debug, Clone)] pub struct VulkanInfo { + pub has_nvidia_gpu: bool, + pub has_monado_vulkan_layers: bool, pub gpu_names: Vec, } -// const NVIDIA_VENDOR_ID: u32 = 0x10de; +const NVIDIA_VENDOR_ID: u32 = 0x10de; impl VulkanInfo { /// # Safety @@ -23,19 +25,40 @@ impl VulkanInfo { None, ) }?; + let mut has_nvidia_gpu = false; + let mut has_monado_vulkan_layers = false; let gpu_names = unsafe { instance.enumerate_physical_devices() }? .into_iter() .filter_map(|d| { - Some( - unsafe { instance.get_physical_device_properties(d) } - .device_name_as_c_str() - .ok()? - .to_string_lossy() - .to_string(), - ) + let props = unsafe { instance.get_physical_device_properties(d) }; + if props.vendor_id == NVIDIA_VENDOR_ID { + has_nvidia_gpu = true; + } + if !has_monado_vulkan_layers { + has_monado_vulkan_layers = + unsafe { instance.enumerate_device_layer_properties(d) } + .ok() + .map(|layerprops| { + layerprops.iter().any(|lp| { + lp.layer_name_as_c_str().is_ok_and(|name| { + name.to_string_lossy() + == "VK_LAYER_MND_enable_timeline_semaphore" + }) + }) + }) + == Some(true); + } + props + .device_name_as_c_str() + .ok() + .map(|cs| cs.to_string_lossy().to_string()) }) .collect(); unsafe { instance.destroy_instance(None) }; - Ok(Self { gpu_names }) + Ok(Self { + gpu_names, + has_nvidia_gpu, + has_monado_vulkan_layers, + }) } }