mirror of
https://gitlab.com/gabmus/envision.git
synced 2025-08-05 07:39:00 +00:00
feat: debug info in about dialog
This commit is contained in:
parent
0c3f6e98f5
commit
56f2e0b0d6
9 changed files with 159 additions and 9 deletions
10
Cargo.lock
generated
10
Cargo.lock
generated
|
@ -32,6 +32,15 @@ version = "1.0.86"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
|
checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ash"
|
||||||
|
version = "0.38.0+1.3.281"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f"
|
||||||
|
dependencies = [
|
||||||
|
"libloading 0.8.5",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atomic-waker"
|
name = "atomic-waker"
|
||||||
version = "1.1.2"
|
version = "1.1.2"
|
||||||
|
@ -271,6 +280,7 @@ name = "envision"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"ash",
|
||||||
"gettext-rs",
|
"gettext-rs",
|
||||||
"git2",
|
"git2",
|
||||||
"gtk4",
|
"gtk4",
|
||||||
|
|
|
@ -29,3 +29,4 @@ xdg = "2.5.2"
|
||||||
openxr = { git = "https://github.com/galister/openxrs", rev = "af4a55d", features = [
|
openxr = { git = "https://github.com/galister/openxrs", rev = "af4a55d", features = [
|
||||||
"linked",
|
"linked",
|
||||||
] }
|
] }
|
||||||
|
ash = "0.38.0"
|
||||||
|
|
13
meson.build
13
meson.build
|
@ -13,7 +13,7 @@ base_id = 'org.gabmus.envision'
|
||||||
pretty_name = 'Envision'
|
pretty_name = 'Envision'
|
||||||
upstream_repo = 'https://gitlab.com/gabmus/envision'
|
upstream_repo = 'https://gitlab.com/gabmus/envision'
|
||||||
author = 'The Envision Team'
|
author = 'The Envision Team'
|
||||||
description = 'GUI for Monado' # temporary
|
description = 'Orchestrator for the free XR stack' # temporary
|
||||||
|
|
||||||
dependency('glib-2.0', version: '>= 2.66')
|
dependency('glib-2.0', version: '>= 2.66')
|
||||||
dependency('gio-2.0', version: '>= 2.66')
|
dependency('gio-2.0', version: '>= 2.66')
|
||||||
|
@ -55,8 +55,10 @@ endif
|
||||||
|
|
||||||
meson.add_dist_script(
|
meson.add_dist_script(
|
||||||
'build-aux/dist-vendor.sh',
|
'build-aux/dist-vendor.sh',
|
||||||
meson.project_build_root() / 'meson-dist' / meson.project_name() + '-' + version,
|
meson.project_build_root() / 'meson-dist' / meson.project_name()
|
||||||
meson.project_source_root()
|
+ '-'
|
||||||
|
+ version,
|
||||||
|
meson.project_source_root(),
|
||||||
)
|
)
|
||||||
|
|
||||||
global_conf = configuration_data()
|
global_conf = configuration_data()
|
||||||
|
@ -71,6 +73,11 @@ global_conf.set('AUTHOR', author)
|
||||||
global_conf.set('PRETTY_NAME', pretty_name)
|
global_conf.set('PRETTY_NAME', pretty_name)
|
||||||
global_conf.set('CMD_NAME', meson.project_name())
|
global_conf.set('CMD_NAME', meson.project_name())
|
||||||
global_conf.set('REPO_URL', upstream_repo)
|
global_conf.set('REPO_URL', upstream_repo)
|
||||||
|
global_conf.set('ISSUES_URL', upstream_repo + '/-/issues')
|
||||||
|
global_conf.set(
|
||||||
|
'BUILD_DATETIME',
|
||||||
|
run_command('date', '-Iseconds', '--utc', check: true).stdout().strip(),
|
||||||
|
)
|
||||||
|
|
||||||
subdir('data')
|
subdir('data')
|
||||||
subdir('po')
|
subdir('po')
|
||||||
|
|
|
@ -9,11 +9,13 @@ pub const PKG_DATA_DIR: &str = "@PKGDATADIR@";
|
||||||
pub const RESOURCES: &str = concat!("@PKGDATADIR@", "/resources.gresource");
|
pub const RESOURCES: &str = concat!("@PKGDATADIR@", "/resources.gresource");
|
||||||
pub const CMD_NAME: &str = "@CMD_NAME@";
|
pub const CMD_NAME: &str = "@CMD_NAME@";
|
||||||
pub const VERSION: &str = "@VERSION@";
|
pub const VERSION: &str = "@VERSION@";
|
||||||
pub const REPO_URL: &str = "@UPSTREAM_REPO_URL@";
|
pub const REPO_URL: &str = "@REPO_URL@";
|
||||||
|
pub const ISSUES_URL: &str = "@ISSUES_URL@";
|
||||||
pub const SINGLE_DEVELOPER: &str = "@AUTHOR@";
|
pub const SINGLE_DEVELOPER: &str = "@AUTHOR@";
|
||||||
pub const GETTEXT_PACKAGE: &str = "@GETTEXT_PACKAGE@";
|
pub const GETTEXT_PACKAGE: &str = "@GETTEXT_PACKAGE@";
|
||||||
pub const LOCALE_DIR: &str = "@LOCALEDIR@";
|
pub const LOCALE_DIR: &str = "@LOCALEDIR@";
|
||||||
pub const BUILD_PROFILE: &str = "@PROFILE@";
|
pub const BUILD_PROFILE: &str = "@PROFILE@";
|
||||||
|
pub const BUILD_DATETIME: &str = "@BUILD_DATETIME@";
|
||||||
|
|
||||||
pub fn get_developers() -> Vec<String> {
|
pub fn get_developers() -> Vec<String> {
|
||||||
vec!["Gabriele Musco <gabmus@disroot.org>".to_string()]
|
vec!["Gabriele Musco <gabmus@disroot.org>".to_string()]
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::file_utils::get_reader;
|
use crate::file_utils::get_reader;
|
||||||
use std::{
|
use std::{
|
||||||
|
fmt::Display,
|
||||||
io::{BufRead, Read},
|
io::{BufRead, Read},
|
||||||
path::Path,
|
path::Path,
|
||||||
};
|
};
|
||||||
|
@ -15,6 +16,19 @@ pub enum LinuxDistro {
|
||||||
Suse,
|
Suse,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for LinuxDistro {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.write_str(match self {
|
||||||
|
Self::Alpine => "Alpine",
|
||||||
|
Self::Arch => "Arch",
|
||||||
|
Self::Debian => "Debian",
|
||||||
|
Self::Fedora => "Fedora",
|
||||||
|
Self::Gentoo => "Gentoo",
|
||||||
|
Self::Suse => "Suse",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl LinuxDistro {
|
impl LinuxDistro {
|
||||||
pub fn get() -> Option<Self> {
|
pub fn get() -> Option<Self> {
|
||||||
Self::get_from_etc_os_release().or_else(Self::get_from_etc_issue)
|
Self::get_from_etc_os_release().or_else(Self::get_from_etc_issue)
|
||||||
|
@ -24,12 +38,40 @@ impl LinuxDistro {
|
||||||
Self::get_from_etc_os_release_file(Path::new("/etc/os-release"))
|
Self::get_from_etc_os_release_file(Path::new("/etc/os-release"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// does it make sense to be here?
|
||||||
|
pub fn get_specific_distro() -> Option<String> {
|
||||||
|
let mut name: Option<String> = None;
|
||||||
|
if let Some(mut reader) = get_reader(Path::new("/etc/os-release")) {
|
||||||
|
let mut buf = String::new();
|
||||||
|
loop {
|
||||||
|
match reader.read_line(&mut buf) {
|
||||||
|
Ok(0) | Err(_) => break,
|
||||||
|
Ok(_) if buf.starts_with("PRETTY_NAME=\"") => {
|
||||||
|
return buf
|
||||||
|
.split('=')
|
||||||
|
.last()
|
||||||
|
.map(|b| b.trim().trim_matches('"').trim().to_string());
|
||||||
|
}
|
||||||
|
Ok(_) if buf.starts_with("NAME=\"") => {
|
||||||
|
name = buf
|
||||||
|
.split('=')
|
||||||
|
.last()
|
||||||
|
.map(|b| b.trim().trim_matches('"').trim().to_string());
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
buf.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
name
|
||||||
|
}
|
||||||
|
|
||||||
fn get_from_etc_os_release_file(fp: &Path) -> Option<Self> {
|
fn get_from_etc_os_release_file(fp: &Path) -> Option<Self> {
|
||||||
if let Some(mut reader) = get_reader(fp) {
|
if let Some(mut reader) = get_reader(fp) {
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
loop {
|
loop {
|
||||||
match reader.read_line(&mut buf) {
|
match reader.read_line(&mut buf) {
|
||||||
Ok(0) => break,
|
Ok(0) | Err(_) => break,
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
if buf.starts_with("NAME=\"")
|
if buf.starts_with("NAME=\"")
|
||||||
|| buf.starts_with("ID=\"")
|
|| buf.starts_with("ID=\"")
|
||||||
|
@ -39,7 +81,7 @@ impl LinuxDistro {
|
||||||
.split('=')
|
.split('=')
|
||||||
.last()
|
.last()
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.to_string()
|
.trim()
|
||||||
.trim_matches('"')
|
.trim_matches('"')
|
||||||
.to_lowercase();
|
.to_lowercase();
|
||||||
let res = Self::name_matcher(&name);
|
let res = Self::name_matcher(&name);
|
||||||
|
@ -48,8 +90,8 @@ impl LinuxDistro {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(_) => break,
|
|
||||||
}
|
}
|
||||||
|
buf.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
|
|
|
@ -44,6 +44,7 @@ pub mod steam_linux_runtime_injector;
|
||||||
pub mod steamvr_utils;
|
pub mod steamvr_utils;
|
||||||
pub mod termcolor;
|
pub mod termcolor;
|
||||||
pub mod ui;
|
pub mod ui;
|
||||||
|
pub mod vulkaninfo;
|
||||||
pub mod xdg;
|
pub mod xdg;
|
||||||
pub mod xr_devices;
|
pub mod xr_devices;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,14 @@
|
||||||
use crate::constants::{get_developers, APP_ID, APP_NAME, REPO_URL, SINGLE_DEVELOPER, VERSION};
|
use crate::{
|
||||||
|
constants::{
|
||||||
|
get_developers, APP_ID, APP_NAME, BUILD_DATETIME, ISSUES_URL, REPO_URL, SINGLE_DEVELOPER,
|
||||||
|
VERSION,
|
||||||
|
},
|
||||||
|
linux_distro::LinuxDistro,
|
||||||
|
vulkaninfo::gpu_names,
|
||||||
|
xdg::XDG,
|
||||||
|
};
|
||||||
use relm4::prelude::*;
|
use relm4::prelude::*;
|
||||||
|
use std::env;
|
||||||
|
|
||||||
pub fn create_about_dialog() -> adw::AboutDialog {
|
pub fn create_about_dialog() -> adw::AboutDialog {
|
||||||
adw::AboutDialog::builder()
|
adw::AboutDialog::builder()
|
||||||
|
@ -8,7 +17,55 @@ pub fn create_about_dialog() -> adw::AboutDialog {
|
||||||
.license_type(gtk::License::Agpl30)
|
.license_type(gtk::License::Agpl30)
|
||||||
.version(VERSION)
|
.version(VERSION)
|
||||||
.website(REPO_URL)
|
.website(REPO_URL)
|
||||||
|
.issue_url(ISSUES_URL)
|
||||||
.developer_name(SINGLE_DEVELOPER)
|
.developer_name(SINGLE_DEVELOPER)
|
||||||
.developers(get_developers())
|
.developers(get_developers())
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn populate_debug_info(dialog: &adw::AboutDialog) {
|
||||||
|
if dialog.debug_info().len() > 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let distro_family = LinuxDistro::get();
|
||||||
|
let distro = LinuxDistro::get_specific_distro();
|
||||||
|
dialog.set_debug_info(
|
||||||
|
&[
|
||||||
|
format!("Version: {VERSION}"),
|
||||||
|
format!("Build time: {BUILD_DATETIME}"),
|
||||||
|
format!(
|
||||||
|
"Operating system: {d} ({f})",
|
||||||
|
d = distro.unwrap_or("unknown".into()),
|
||||||
|
f = distro_family
|
||||||
|
.map(|f| f.to_string())
|
||||||
|
.unwrap_or("unknown".into())
|
||||||
|
),
|
||||||
|
format!(
|
||||||
|
"Session type: {}",
|
||||||
|
env::var("XDG_SESSION_TYPE").unwrap_or("unknown".into())
|
||||||
|
),
|
||||||
|
format!(
|
||||||
|
"Desktop: {}",
|
||||||
|
env::var("XDG_CURRENT_DESKTOP").unwrap_or("unknown".into())
|
||||||
|
),
|
||||||
|
format!(
|
||||||
|
"GPUs: {}",
|
||||||
|
unsafe { gpu_names() }
|
||||||
|
.ok()
|
||||||
|
.map(|names| names.join(", "))
|
||||||
|
.unwrap_or("unknown".into())
|
||||||
|
),
|
||||||
|
format!(
|
||||||
|
"Steam found: {}",
|
||||||
|
if XDG.get_data_home().join("Steam").is_dir()
|
||||||
|
|| XDG.get_data_home().join("steam").is_dir()
|
||||||
|
{
|
||||||
|
"yes"
|
||||||
|
} else {
|
||||||
|
"no"
|
||||||
|
}
|
||||||
|
),
|
||||||
|
]
|
||||||
|
.join("\n"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ use crate::stateless_action;
|
||||||
use crate::steam_linux_runtime_injector::{
|
use crate::steam_linux_runtime_injector::{
|
||||||
restore_runtime_entrypoint, set_runtime_entrypoint_launch_opts_from_profile,
|
restore_runtime_entrypoint, set_runtime_entrypoint_launch_opts_from_profile,
|
||||||
};
|
};
|
||||||
use crate::ui::about_dialog::create_about_dialog;
|
use crate::ui::about_dialog::{create_about_dialog, populate_debug_info};
|
||||||
use crate::ui::build_window::{BuildWindowInit, BuildWindowMsg, BuildWindowOutMsg};
|
use crate::ui::build_window::{BuildWindowInit, BuildWindowMsg, BuildWindowOutMsg};
|
||||||
use crate::ui::debug_view::{DebugViewInit, DebugViewOutMsg};
|
use crate::ui::debug_view::{DebugViewInit, DebugViewOutMsg};
|
||||||
use crate::ui::libsurvive_setup_window::LibsurviveSetupMsg;
|
use crate::ui::libsurvive_setup_window::LibsurviveSetupMsg;
|
||||||
|
@ -942,6 +942,7 @@ impl SimpleComponent for App {
|
||||||
#[strong(rename_to = app_win)]
|
#[strong(rename_to = app_win)]
|
||||||
model.app_win,
|
model.app_win,
|
||||||
move |_| {
|
move |_| {
|
||||||
|
populate_debug_info(&about_dialog);
|
||||||
about_dialog.present(Some(&app_win));
|
about_dialog.present(Some(&app_win));
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
29
src/vulkaninfo.rs
Normal file
29
src/vulkaninfo.rs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
use ash::{
|
||||||
|
vk::{ApplicationInfo, InstanceCreateInfo},
|
||||||
|
Entry,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// Dlopens the vulkan library, so this is inherently unsafe. Should be fine in
|
||||||
|
/// most circumstances
|
||||||
|
pub unsafe fn gpu_names() -> anyhow::Result<Vec<String>> {
|
||||||
|
let entry = Entry::load()?;
|
||||||
|
let instance = entry.create_instance(
|
||||||
|
&InstanceCreateInfo::default().application_info(&ApplicationInfo::default()),
|
||||||
|
None,
|
||||||
|
)?;
|
||||||
|
let names = instance
|
||||||
|
.enumerate_physical_devices()?
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|d| {
|
||||||
|
instance
|
||||||
|
.get_physical_device_properties(d)
|
||||||
|
.device_name_as_c_str()
|
||||||
|
.ok()
|
||||||
|
.map(|cs| cs.to_string_lossy().to_string())
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
instance.destroy_instance(None);
|
||||||
|
Ok(names)
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue