Compare commits

...

10 commits
3.0.0 ... main

Author SHA1 Message Date
Gabriele Musco
139f72e294
chore: update version to 3.1.0
Some checks failed
/ cargo-fmtcheck (push) Has been cancelled
/ cargo-clippy (push) Has been cancelled
/ cargo-test (push) Has been cancelled
/ appimage (push) Has been cancelled
2025-04-08 15:49:55 +02:00
Gabriele Musco
7a02fcc5d1
fix: disable and blacklist wayvr dashboard plugin 2025-04-08 15:38:20 +02:00
Gabriele Musco
2f5ec57a0a
feat: don't set openvrpaths as read only during profile startup
Some checks are pending
/ cargo-test (push) Waiting to run
/ cargo-fmtcheck (push) Waiting to run
/ cargo-clippy (push) Waiting to run
/ appimage (push) Waiting to run
2025-04-07 08:12:18 +02:00
Gabriele Musco
8742a27b7c
feat: small design changes to build window ui
Some checks are pending
/ cargo-test (push) Waiting to run
/ appimage (push) Waiting to run
/ cargo-fmtcheck (push) Waiting to run
/ cargo-clippy (push) Waiting to run
2025-04-07 08:12:08 +02:00
Gabriele Musco
25c90d175f
chore: clippy
Some checks are pending
/ cargo-fmtcheck (push) Waiting to run
/ cargo-clippy (push) Waiting to run
/ cargo-test (push) Waiting to run
/ appimage (push) Waiting to run
2025-04-06 13:30:30 +02:00
Gabriele Musco
2fc33b10b0
feat: add support for vapor openvr compatibility module 2025-04-06 13:26:48 +02:00
Gabriele Musco
f38199601e
feat: remove monado vulkan layers check for nvidia
fixes #208
2025-04-06 12:33:26 +02:00
hypevhs
db45103d1b fix(monado dependencies): use wayland-protocols-devel on Fedora
Some checks failed
/ cargo-fmtcheck (push) Has been cancelled
/ cargo-clippy (push) Has been cancelled
/ cargo-test (push) Has been cancelled
/ appimage (push) Has been cancelled
2025-03-13 11:30:35 -05:00
Bones
e117986715 chore: update version to 3.0.1
Some checks failed
/ cargo-fmtcheck (push) Has been cancelled
/ cargo-clippy (push) Has been cancelled
/ cargo-test (push) Has been cancelled
/ appimage (push) Has been cancelled
2025-03-02 13:51:58 -05:00
Etch9
1ac253ecbf fix: libnotify headers path in wivrn depcheck 2025-03-02 18:28:28 +00:00
18 changed files with 190 additions and 115 deletions

2
Cargo.lock generated
View file

@ -563,7 +563,7 @@ dependencies = [
[[package]]
name = "envision"
version = "3.0.0"
version = "3.0.1"
dependencies = [
"anyhow",
"ash",

View file

@ -1,6 +1,6 @@
[package]
name = "envision"
version = "3.0.0"
version = "3.1.0"
edition = "2021"
authors = [
"Gabriele Musco <gabmus@disroot.org>",

View file

@ -30,6 +30,34 @@
<url type="bugtracker">@REPO_URL@/issues</url>
<content_rating type="oars-1.0" />
<releases>
<release version="3.1.0" date="2025-04-08">
<description>
<p>What's new</p>
<ul>
<li>don&#x27;t set openvrpaths as read only during profile startup</li>
<li>small design changes to build window ui</li>
<li>add support for vapor openvr compatibility module</li>
<li>remove monado vulkan layers check for nvidia</li>
</ul>
<p>Fixes</p>
<ul>
<li>disable and blacklist wayvr dashboard plugin</li>
<li>monado dependencies: use wayland-protocols-devel on Fedora</li>
</ul>
<p>Other changes</p>
<ul>
<li>clippy</li>
</ul>
</description>
</release>
<release version="3.0.1" date="2025-03-02">
<description>
<p>Fixes</p>
<ul>
<li>libnotify headers path in wivrn depcheck</li>
</ul>
</description>
</release>
<release version="3.0.0" date="2025-03-01">
<description>
<p>Breaking changes</p>

1
dist/arch/PKGBUILD vendored
View file

@ -33,7 +33,6 @@ makedepends=(
)
optdepends=(
'libudev0-shim: steamvr_lh lighthouse driver support'
'monado-vulkan-layers-git: Vulkan layers for NVIDIA users'
)
provides=(envision)
conflicts=(envision)

View file

@ -1,7 +1,7 @@
project(
'envision',
'rust',
version: '3.0.0', # version number row
version: '3.1.0', # version number row
meson_version: '>= 0.59',
license: 'AGPL-3.0-or-later',
)

View file

@ -0,0 +1,85 @@
use crate::{
build_tools::{cmake::Cmake, git::Git},
profile::Profile,
termcolor::TermColor,
ui::job_worker::job::{FuncWorkerData, FuncWorkerOut, WorkerJob},
util::file_utils::{copy_file, rm_rf},
};
use std::{
collections::{HashMap, VecDeque},
fs::create_dir_all,
path::Path,
};
pub fn get_build_vapor_jobs(profile: &Profile, clean_build: bool) -> VecDeque<WorkerJob> {
let mut jobs = VecDeque::<WorkerJob>::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 cmake = Cmake {
env: None,
vars: Some({
let mut cmake_vars: HashMap<String, String> = HashMap::new();
for (k, v) in [
("VAPOR_LOG_SILENT=ON", "ON"),
("CMAKE_BUILD_TYPE", "RelWithDebInfo"),
] {
cmake_vars.insert(k.to_string(), v.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(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
}

View file

@ -4,5 +4,6 @@ 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;

View file

@ -37,7 +37,7 @@ fn monado_deps() -> Vec<Dependency> {
packages: HashMap::from([
(LinuxDistro::Arch, "wayland-protocols".into()),
(LinuxDistro::Debian, "wayland-protocols".into()),
(LinuxDistro::Fedora, "wayland-protocols".into()),
(LinuxDistro::Fedora, "wayland-protocols-devel".into()),
(LinuxDistro::Gentoo, "dev-libs/wayland-protocols".into()),
(LinuxDistro::Suse, "wayland-protocols-devel".into()),
]),

View file

@ -253,7 +253,7 @@ fn wivrn_deps() -> Vec<Dependency> {
Dependency {
name: "libnotify-dev".into(),
dep_type: DepType::Include,
filename: "openssl/ssl3.h".into(),
filename: "libnotify/notify.h".into(),
packages: HashMap::from([
(LinuxDistro::Arch, "libnotify".into()),
(LinuxDistro::Alpine, "libnotify-dev".into()),

View file

@ -85,6 +85,7 @@ 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(())
@ -104,18 +105,17 @@ 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 std::path::Path;
use super::{dump_openvrpaths_to_path, get_openvrpaths_from_path, OpenVrPaths};
use std::path::Path;
#[test]
fn can_read_openvrpaths_vrpath_steamvr() {

View file

@ -49,13 +49,13 @@ impl LinuxDistro {
Ok(_) if buf.starts_with("PRETTY_NAME=\"") => {
return buf
.split('=')
.last()
.next_back()
.map(|b| b.trim().trim_matches('"').trim().to_string());
}
Ok(_) if buf.starts_with("NAME=\"") => {
name = buf
.split('=')
.last()
.next_back()
.map(|b| b.trim().trim_matches('"').trim().to_string());
}
_ => {}
@ -79,7 +79,7 @@ impl LinuxDistro {
{
let name = buf
.split('=')
.last()
.next_back()
.unwrap_or_default()
.trim()
.trim_matches('"')

View file

@ -265,6 +265,7 @@ pub enum OvrCompatibilityModuleType {
#[default]
Opencomposite,
Xrizer,
Vapor,
}
impl Display for OvrCompatibilityModuleType {
@ -272,13 +273,14 @@ 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].iter()
[Self::Opencomposite, Self::Xrizer, Self::Vapor].iter()
}
}
@ -289,6 +291,7 @@ 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}`")),
}
}
@ -299,7 +302,8 @@ impl From<u32> for OvrCompatibilityModuleType {
match value {
0 => Self::Opencomposite,
1 => Self::Xrizer,
_ => panic!("OvrCompatibilityModuleType index out of bounds"),
2 => Self::Vapor,
_ => panic!("OvrCompatibilityModuleType index out of bounds"),
}
}
}
@ -327,7 +331,9 @@ impl ProfileOvrCompatibilityModule {
/// this should correspond to the build output directory
pub fn runtime_dir(&self) -> PathBuf {
match self.mod_type {
OvrCompatibilityModuleType::Opencomposite => self.path.join("build"),
OvrCompatibilityModuleType::Opencomposite | OvrCompatibilityModuleType::Vapor => {
self.path.join("build")
}
OvrCompatibilityModuleType::Xrizer => self.path.join("target/release"),
}
}

View file

@ -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().len() > 0 {
if !dialog.debug_info().is_empty() {
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(':').last().map(|s| s.trim().to_string()))
.map(|line| line.split(':').next_back().map(|s| s.trim().to_string()))
})
.flatten()
.unwrap_or(UNKNOWN.into())
@ -81,12 +81,6 @@ 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() {

View file

@ -20,7 +20,8 @@ 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_wivrn::get_build_wivrn_jobs, build_xrizer::get_build_xrizer_jobs,
build_vapor::get_build_vapor_jobs, build_wivrn::get_build_wivrn_jobs,
build_xrizer::get_build_xrizer_jobs,
},
config::{Config, PluginConfig},
constants::APP_NAME,
@ -248,6 +249,10 @@ impl App {
.plugins
.values()
.filter_map(|cp| {
// disable potentially unsafe wayvr_dashboard
if cp.plugin.appid.contains("wayvr_dashboard") {
return None;
}
if cp.enabled && cp.plugin.validate() {
if let Err(e) = cp.plugin.mark_as_executable() {
error!(
@ -533,6 +538,9 @@ 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())
@ -998,7 +1006,6 @@ 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,

View file

@ -88,43 +88,54 @@ impl SimpleComponent for BuildWindow {
gtk::Label {
#[track = "model.changed(BuildWindow::build_status())"]
set_markup: match &model.build_status {
BuildStatus::Building => "Build in progress...".to_string(),
BuildStatus::Done => "Build done, you can close this window".to_string(),
BuildStatus::Building => String::default(),
BuildStatus::Done => "Build done, you can close this window".into(),
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 = &gtk::Button {
add_css_class: "pill",
add_bottom_bar: bottom_bar = &gtk::Box {
set_orientation: gtk::Orientation::Horizontal,
set_halign: gtk::Align::Center,
set_label: "Close",
set_margin_all: 12,
#[track = "model.changed(BuildWindow::can_close())"]
set_sensitive: model.can_close,
connect_clicked[win] => move |_| {
win.close();
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();
},
},
}
// 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);
}
},
// ^^^
},
}
}
}

View file

@ -25,7 +25,6 @@ use crate::{
file_utils::{get_writer, mount_has_nosuid},
steamvr_utils::chaperone_info_exists,
},
vulkaninfo::VulkanInfo,
wivrn_dbus,
xr_devices::XRDevice,
};
@ -75,8 +74,6 @@ pub struct MainView {
#[tracker::do_not_track]
profile_export_action: gtk::gio::SimpleAction,
xrservice_ready: bool,
#[tracker::do_not_track]
vkinfo: Option<VulkanInfo>,
wivrn_pairing_mode: bool,
wivrn_pin: Option<String>,
wivrn_supports_pairing: bool,
@ -126,7 +123,6 @@ pub struct MainViewInit {
pub config: Config,
pub selected_profile: Profile,
pub root_win: gtk::Window,
pub vkinfo: Option<VulkanInfo>,
}
impl MainView {
@ -461,34 +457,6 @@ 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,
@ -1103,7 +1071,6 @@ 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,

View file

@ -163,10 +163,10 @@ impl Plugin {
/// urls to manifest json files representing plugins.
/// 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/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",
// wayvr dashboard potentially unsafe
];
pub async fn refresh_plugins() -> anyhow::Result<Vec<anyhow::Result<Plugin>>> {

View file

@ -5,12 +5,10 @@ use ash::{
#[derive(Debug, Clone)]
pub struct VulkanInfo {
pub has_nvidia_gpu: bool,
pub has_monado_vulkan_layers: bool,
pub gpu_names: Vec<String>,
}
const NVIDIA_VENDOR_ID: u32 = 0x10de;
// const NVIDIA_VENDOR_ID: u32 = 0x10de;
impl VulkanInfo {
/// # Safety
@ -25,40 +23,19 @@ 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| {
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())
Some(
unsafe { instance.get_physical_device_properties(d) }
.device_name_as_c_str()
.ok()?
.to_string_lossy()
.to_string(),
)
})
.collect();
unsafe { instance.destroy_instance(None) };
Ok(Self {
gpu_names,
has_nvidia_gpu,
has_monado_vulkan_layers,
})
Ok(Self { gpu_names })
}
}