Merge branch 'main' into feat/stardust

This commit is contained in:
Gabriele Musco 2024-01-14 23:22:52 +01:00
commit 21d84252ca
No known key found for this signature in database
GPG key ID: 1068D795C80E51DE
37 changed files with 354 additions and 191 deletions

View file

@ -22,7 +22,7 @@ cargo:test:
script:
- echo 'deb http://deb.debian.org/debian experimental main' > /etc/apt/sources.list.d/experimental.list
- apt-get update
- apt-get -t experimental install libgtk-4-dev libadwaita-1-dev libgtksourceview-5-dev libssl-dev libjxl-dev libvte-2.91-gtk4-dev -y
- apt-get -t experimental install libgtk-4-dev libadwaita-1-dev libssl-dev libjxl-dev libvte-2.91-gtk4-dev -y
- apt-get install meson ninja-build git desktop-file-utils gettext file libusb-dev libusb-1.0-0-dev curl -y
- curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs -o /tmp/rustup.sh
- chmod +x /tmp/rustup.sh
@ -41,7 +41,7 @@ appimage:
script:
- echo 'deb http://deb.debian.org/debian experimental main' > /etc/apt/sources.list.d/experimental.list
- apt-get update
- apt-get -t experimental install libgtk-4-dev libadwaita-1-dev libgtksourceview-5-dev libssl-dev libjxl-dev libvte-2.91-gtk4-dev -y
- apt-get -t experimental install libgtk-4-dev libadwaita-1-dev libssl-dev libjxl-dev libvte-2.91-gtk4-dev -y
- apt-get install meson ninja-build git desktop-file-utils gettext file libusb-dev libusb-1.0-0-dev curl -y
- curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs -o /tmp/rustup.sh
- chmod +x /tmp/rustup.sh

36
Cargo.lock generated
View file

@ -301,7 +301,6 @@ dependencies = [
"reqwest",
"serde",
"serde_json",
"sourceview5",
"tracker",
"uuid",
"zoha-vte4",
@ -1877,41 +1876,6 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "sourceview5"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88c5f976a113e947bc5ec67758b2960c0db4ca76f80fb410d7cd86cd456d9ee5"
dependencies = [
"futures-channel",
"futures-core",
"gdk-pixbuf",
"gdk4",
"gio",
"glib",
"gtk4",
"libc",
"pango",
"sourceview5-sys",
]
[[package]]
name = "sourceview5-sys"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29637cccd56075a37ba72c0cc8b8d599dbc1d857e30dadea97eaacbc29b7fd46"
dependencies = [
"gdk-pixbuf-sys",
"gdk4-sys",
"gio-sys",
"glib-sys",
"gobject-sys",
"gtk4-sys",
"libc",
"pango-sys",
"system-deps",
]
[[package]]
name = "spin"
version = "0.9.8"

View file

@ -36,9 +36,6 @@ serde = { version = "1.0.188", features = [
"derive"
] }
serde_json = "1.0.106"
sourceview5 = { version = "0.7.1", features = [
"v5_6"
] }
tracker = "0.2.1"
uuid = { version = "1.4.1", features = ["v4", "fast-rng"] }
zoha-vte4 = { version = "0.0.2", features = ["v0_72"] }

View file

@ -1,7 +1,3 @@
.padded {
padding: 18px;
}
.sourceview-transparent-bg, .sourceview-transparent-bg * {
background-color: transparent;
}

2
dist/arch/PKGBUILD vendored
View file

@ -9,7 +9,6 @@ url='https://gitlab.com/gabmus/envision'
license=(GPL)
depends=(
gtk4
gtksourceview5
libadwaita
openxr
libgl
@ -23,6 +22,7 @@ depends=(
ninja
shaderc
vulkan-headers
vte4
)
makedepends=(
meson

View file

@ -18,7 +18,7 @@ description = 'GUI for Monado' # temporary
dependency('glib-2.0', version: '>= 2.66')
dependency('gio-2.0', version: '>= 2.66')
dependency('gtk4', version: '>= 4.10.0')
dependency('gtksourceview-5', version: '>= 5.6.0')
dependency('vte-2.91-gtk4', version: '>= 0.72.0')
glib_compile_resources = find_program('glib-compile-resources', required: true)
# glib_compile_schemas = find_program('glib-compile-schemas', required: true)

View file

@ -6,7 +6,7 @@ use std::path::Path;
pub struct Git {
pub repo: String,
pub dir: String,
pub default_branch: String,
pub branch: String,
}
impl Git {
@ -88,7 +88,7 @@ impl Git {
}
pub fn get_checkout_ref_job(&self) -> WorkerJob {
let gref = self.get_ref().unwrap_or(self.default_branch.clone());
let gref = self.get_ref().unwrap_or(self.branch.clone());
self.cmd(vec!["checkout".into(), gref])
}

View file

@ -18,7 +18,10 @@ pub fn get_build_basalt_jobs(profile: &Profile, clean_build: bool) -> VecDeque<W
None => "https://gitlab.freedesktop.org/mateosss/basalt.git".into(),
},
dir: profile.features.basalt.path.as_ref().unwrap().clone(),
default_branch: "main".into(),
branch: match profile.features.basalt.branch.as_ref() {
Some(r) => r.clone(),
None => "main".into(),
},
};
jobs.extend(git.get_pre_build_jobs(profile.pull_on_build));

View file

@ -18,7 +18,10 @@ pub fn get_build_libsurvive_jobs(profile: &Profile, clean_build: bool) -> VecDeq
None => "https://github.com/cntools/libsurvive".into(),
},
dir: profile.features.libsurvive.path.as_ref().unwrap().clone(),
default_branch: "master".into(),
branch: match profile.features.libsurvive.branch.as_ref() {
Some(r) => r.clone(),
None => "master".into(),
},
};
jobs.extend(git.get_pre_build_jobs(profile.pull_on_build));

View file

@ -22,7 +22,10 @@ pub fn get_build_monado_jobs(
None => "https://gitlab.freedesktop.org/monado/monado".into(),
},
dir: profile.xrservice_path.clone(),
default_branch: "main".into(),
branch: match profile.xrservice_branch.as_ref() {
Some(r) => r.clone(),
None => "main".into(),
},
};
jobs.extend(git.get_pre_build_jobs(profile.pull_on_build));

View file

@ -22,7 +22,10 @@ pub fn get_build_opencomposite_jobs(
None => "https://gitlab.com/znixian/OpenOVR.git".into(),
},
dir: profile.opencomposite_path.clone(),
default_branch: "openxr".into(),
branch: match profile.opencomposite_branch.as_ref() {
Some(r) => r.clone(),
None => "openxr".into(),
},
};
jobs.extend(git.get_pre_build_jobs(profile.pull_on_build));

View file

@ -18,7 +18,10 @@ pub fn get_build_openhmd_jobs(profile: &Profile, clean_build: bool) -> VecDeque<
None => "https://github.com/OpenHMD/OpenHMD".into(),
},
dir: profile.features.openhmd.path.as_ref().unwrap().clone(),
default_branch: "master".into(),
branch: match profile.features.openhmd.branch.as_ref() {
Some(r) => r.clone(),
None => "master".into(),
},
};
jobs.extend(git.get_pre_build_jobs(profile.pull_on_build));

View file

@ -22,7 +22,10 @@ pub fn get_build_wivrn_jobs(
None => "https://github.com/Meumeu/WiVRn".into(),
},
dir: profile.xrservice_path.clone(),
default_branch: "master".into(),
branch: match profile.xrservice_branch.as_ref() {
Some(r) => r.clone(),
None => "master".into(),
},
};
jobs.extend(git.get_pre_build_jobs(profile.pull_on_build));

View file

@ -40,6 +40,16 @@ fn monado_deps() -> Vec<Dependency> {
]),
},
dep_glslang_validator(),
Dependency {
name: "sdl2".into(),
dep_type: DepType::SharedObject,
filename: "libSDL2.so".into(),
packages: HashMap::from([
(LinuxDistro::Arch, "sdl2".into()),
(LinuxDistro::Debian, "libsdl2".into()),
(LinuxDistro::Fedora, "SDL2".into()),
]),
},
]
}

View file

@ -14,6 +14,7 @@ pub static ENV_VAR_DESCRIPTIONS: Map<&str, &str> = phf_map! {
"XRT_DEBUG_GUI" => "Set to 1 to enable the Monado debug UI.",
"XRT_CURATED_GUI" => "Set to 1 to enable the Monado preview UI. Requires XRT_DEBUG_GUI=1 to work.",
"XRT_JSON_LOG" => "Set to 1 to enable JSON logging for Monado. This enables better log visualization and log level filtering.",
"QWERTY_ENABLE" => "Set to 1 to enable QWERTY Simulation driver. This enables simulated driver that allows you to use Monado without HMD and controllers. It's also possible to mix and match different profiles with this.",
"LH_DRIVER" => "Lighthouse driver, this overrides the \"Lighthouse driver option in the profile\"; Valid options are: \"vive\" for the default built-in driver, \"survive\" for Libsurvive, \"steamvr\" for the SteamVR based implementation.",
"LH_LOG" => "Lighthouse log level. Can be one of: \"trace\", \"debug\", \"info\", \"warn\", \"error\".",
"LIGHTHOUSE_LOG" => "Lighthouse driver log level. Can be one of: \"trace\", \"debug\", \"info\", \"warn\", \"error\"."

View file

@ -85,6 +85,10 @@ pub struct WivrnConfEncoder {
#[serde(skip_serializing_if = "Option::is_none")]
pub height: Option<f32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub offset_x: Option<f32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub offset_y: Option<f32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub group: Option<i32>,
}
@ -96,6 +100,8 @@ impl Default for WivrnConfEncoder {
bitrate: None,
width: None,
height: None,
offset_x: None,
offset_y: None,
group: None,
}
}
@ -118,6 +124,8 @@ impl Default for WivrnConfig {
bitrate: Some(100000000),
width: Some(1.0),
height: Some(1.0),
offset_x: Some(0.0),
offset_y: Some(0.0),
group: None,
}],
}
@ -162,5 +170,7 @@ mod tests {
assert_eq!(conf.encoders.get(0).unwrap().bitrate, Some(100000000));
assert_eq!(conf.encoders.get(0).unwrap().width, Some(1.0));
assert_eq!(conf.encoders.get(0).unwrap().height, Some(1.0));
assert_eq!(conf.encoders.get(0).unwrap().offset_x, Some(0.0));
assert_eq!(conf.encoders.get(0).unwrap().offset_y, Some(0.0));
}
}

View file

@ -90,6 +90,7 @@ pub struct ProfileFeature {
pub enabled: bool,
pub path: Option<String>,
pub repo: Option<String>,
pub branch: Option<String>,
}
impl Default for ProfileFeature {
@ -99,6 +100,7 @@ impl Default for ProfileFeature {
enabled: false,
path: None,
repo: None,
branch: None,
}
}
}
@ -210,10 +212,12 @@ pub struct Profile {
pub xrservice_type: XRServiceType,
pub xrservice_path: String,
pub xrservice_repo: Option<String>,
pub xrservice_branch: Option<String>,
#[serde(default = "HashMap::<String, String>::default")]
pub xrservice_cmake_flags: HashMap<String, String>,
pub opencomposite_path: String,
pub opencomposite_repo: Option<String>,
pub opencomposite_branch: Option<String>,
pub features: ProfileFeatures,
pub environment: HashMap<String, String>,
/** Install prefix */
@ -243,24 +247,28 @@ impl Default for Profile {
xrservice_path: format!("{}/xrservice", profile_dir),
xrservice_type: XRServiceType::Monado,
xrservice_repo: None,
xrservice_branch: None,
xrservice_cmake_flags: HashMap::<String, String>::default(),
features: ProfileFeatures {
libsurvive: ProfileFeature {
enabled: false,
path: Some(format!("{}/libsurvive", profile_dir)),
repo: None,
branch: None,
feature_type: ProfileFeatureType::Libsurvive,
},
basalt: ProfileFeature {
enabled: false,
path: Some(format!("{}/basalt", profile_dir)),
repo: None,
branch: None,
feature_type: ProfileFeatureType::Basalt,
},
openhmd: ProfileFeature {
enabled: false,
path: Some(format!("{}/openhmd", profile_dir)),
repo: None,
branch: None,
feature_type: ProfileFeatureType::OpenHmd,
},
mercury_enabled: false,
@ -269,8 +277,9 @@ impl Default for Profile {
prefix: format!("{}/prefixes/{}", get_data_dir(), uuid),
can_be_built: true,
pull_on_build: true,
opencomposite_repo: None,
opencomposite_path: format!("{}/opencomposite", profile_dir),
opencomposite_repo: None,
opencomposite_branch: None,
editable: true,
lighthouse_driver: LighthouseDriver::default(),
xrservice_launch_options: String::default(),
@ -337,17 +346,28 @@ impl Profile {
dup.name = format!("Duplicate of {}", self.name);
dup.xrservice_type = self.xrservice_type.clone();
dup.xrservice_repo = self.xrservice_repo.clone();
dup.xrservice_branch = self.xrservice_branch.clone();
dup.xrservice_cmake_flags = self.xrservice_cmake_flags.clone();
dup.features.libsurvive.enabled = self.features.libsurvive.enabled;
dup.features.libsurvive.repo = self.features.libsurvive.repo.clone();
dup.features.libsurvive.branch = self.features.libsurvive.branch.clone();
dup.features.basalt.enabled = self.features.basalt.enabled;
dup.features.basalt.repo = self.features.basalt.repo.clone();
dup.features.basalt.branch = self.features.basalt.branch.clone();
dup.features.openhmd.enabled = self.features.openhmd.enabled;
dup.features.openhmd.repo = self.features.openhmd.repo.clone();
dup.features.openhmd.branch = self.features.openhmd.branch.clone();
dup.features.mercury_enabled = self.features.mercury_enabled;
dup.environment = self.environment.clone();
if dup.environment.contains_key("LD_LIBRARY_PATH".into()) {
dup.environment.insert(
"LD_LIBRARY_PATH".into(),
prepare_ld_library_path(&dup.prefix),
);
}
dup.pull_on_build = self.pull_on_build;
dup.opencomposite_repo = self.opencomposite_repo.clone();
dup.opencomposite_branch = self.opencomposite_branch.clone();
dup.lighthouse_driver = self.lighthouse_driver;
dup.xrservice_launch_options = self.xrservice_launch_options.clone();
dup
@ -467,6 +487,7 @@ mod tests {
enabled: true,
path: Some(String::from("/home/user/libsurvive")),
repo: None,
branch: None,
},
basalt: ProfileFeature::default_basalt(),
openhmd: ProfileFeature::default_openhmd(),
@ -494,3 +515,7 @@ mod tests {
);
}
}
pub fn prepare_ld_library_path(prefix: &str) -> String {
format!("{pfx}/lib:{pfx}/lib64", pfx = prefix)
}

View file

@ -1,7 +1,7 @@
use crate::{
constants::APP_NAME,
paths::{data_monado_path, data_opencomposite_path, get_data_dir},
profile::{LighthouseDriver, Profile, ProfileFeatures, XRServiceType},
profile::{prepare_ld_library_path, LighthouseDriver, Profile, ProfileFeatures, XRServiceType},
};
use std::collections::HashMap;
@ -15,10 +15,7 @@ pub fn lighthouse_profile() -> Profile {
environment.insert("XRT_DEBUG_GUI".into(), "1".into());
environment.insert("XRT_CURATED_GUI".into(), "1".into());
environment.insert("U_PACING_APP_USE_MIN_FRAME_PERIOD".into(), "1".into());
environment.insert(
"LD_LIBRARY_PATH".into(),
format!("{pfx}/lib:{pfx}/lib64", pfx = prefix),
);
environment.insert("LD_LIBRARY_PATH".into(), prepare_ld_library_path(&prefix));
Profile {
uuid: "lighthouse-default".into(),
name: format!("Lighthouse Driver - {name} Default", name = APP_NAME),

View file

@ -1,5 +1,6 @@
pub mod lighthouse;
pub mod openhmd;
pub mod simulated;
pub mod survive;
pub mod wivrn;
pub mod wmr;

View file

@ -2,8 +2,8 @@ use crate::{
constants::APP_NAME,
paths::{data_monado_path, data_opencomposite_path, data_openhmd_path, get_data_dir},
profile::{
LighthouseDriver, Profile, ProfileFeature, ProfileFeatureType, ProfileFeatures,
XRServiceType,
prepare_ld_library_path, LighthouseDriver, Profile, ProfileFeature, ProfileFeatureType,
ProfileFeatures, XRServiceType,
},
};
use std::collections::HashMap;
@ -18,10 +18,7 @@ pub fn openhmd_profile() -> Profile {
environment.insert("XRT_DEBUG_GUI".into(), "1".into());
environment.insert("XRT_CURATED_GUI".into(), "1".into());
environment.insert("U_PACING_APP_USE_MIN_FRAME_PERIOD".into(), "1".into());
environment.insert(
"LD_LIBRARY_PATH".into(),
format!("{pfx}/lib:{pfx}/lib64", pfx = prefix),
);
environment.insert("LD_LIBRARY_PATH".into(), prepare_ld_library_path(&prefix));
Profile {
uuid: "openhmd-default".into(),
name: format!("OpenHMD - {name} Default", name = APP_NAME),
@ -34,6 +31,7 @@ pub fn openhmd_profile() -> Profile {
enabled: true,
path: Some(data_openhmd_path()),
repo: None,
branch: None,
},
..Default::default()
},

36
src/profiles/simulated.rs Normal file
View file

@ -0,0 +1,36 @@
use crate::{
constants::APP_NAME,
paths::{data_monado_path, data_opencomposite_path, get_data_dir},
profile::{Profile, ProfileFeatures, XRServiceType},
};
use std::collections::HashMap;
pub fn simulated_profile() -> Profile {
let data_dir = get_data_dir();
let prefix = format!("{data}/prefixes/simulated_default", data = data_dir);
let mut environment: HashMap<String, String> = HashMap::new();
environment.insert("QWERTY_ENABLE".into(), "1".into());
environment.insert("XRT_JSON_LOG".into(), "1".into());
environment.insert("XRT_COMPOSITOR_SCALE_PERCENTAGE".into(), "140".into());
environment.insert("XRT_COMPOSITOR_COMPUTE".into(), "1".into());
environment.insert("XRT_DEBUG_GUI".into(), "1".into());
environment.insert("XRT_CURATED_GUI".into(), "1".into());
environment.insert("U_PACING_APP_USE_MIN_FRAME_PERIOD".into(), "1".into());
environment.insert(
"LD_LIBRARY_PATH".into(),
format!("{pfx}/lib:{pfx}/lib64", pfx = prefix),
);
Profile {
uuid: "simulated-default".into(),
name: format!("Simulated Driver - {name} Default", name = APP_NAME),
xrservice_path: data_monado_path(),
xrservice_type: XRServiceType::Monado,
opencomposite_path: data_opencomposite_path(),
features: ProfileFeatures::default(),
environment,
prefix,
can_be_built: true,
editable: false,
..Default::default()
}
}

View file

@ -2,8 +2,8 @@ use crate::{
constants::APP_NAME,
paths::{data_libsurvive_path, data_monado_path, data_opencomposite_path, get_data_dir},
profile::{
LighthouseDriver, Profile, ProfileFeature, ProfileFeatureType, ProfileFeatures,
XRServiceType,
prepare_ld_library_path, LighthouseDriver, Profile, ProfileFeature, ProfileFeatureType,
ProfileFeatures, XRServiceType,
},
};
use std::collections::HashMap;
@ -20,10 +20,7 @@ pub fn survive_profile() -> Profile {
environment.insert("XRT_DEBUG_GUI".into(), "1".into());
environment.insert("XRT_CURATED_GUI".into(), "1".into());
environment.insert("U_PACING_APP_USE_MIN_FRAME_PERIOD".into(), "1".into());
environment.insert(
"LD_LIBRARY_PATH".into(),
format!("{pfx}/lib:{pfx}/lib64", pfx = prefix),
);
environment.insert("LD_LIBRARY_PATH".into(), prepare_ld_library_path(&prefix));
Profile {
uuid: "survive-default".into(),
name: format!("Survive - {name} Default", name = APP_NAME),
@ -36,6 +33,7 @@ pub fn survive_profile() -> Profile {
enabled: true,
path: Some(data_libsurvive_path()),
repo: None,
branch: None,
},
..Default::default()
},

View file

@ -1,7 +1,7 @@
use crate::{
constants::APP_NAME,
paths::{data_opencomposite_path, data_wivrn_path, get_data_dir},
profile::{Profile, ProfileFeatures, XRServiceType},
profile::{prepare_ld_library_path, Profile, ProfileFeatures, XRServiceType},
};
use std::collections::HashMap;
@ -9,10 +9,7 @@ pub fn wivrn_profile() -> Profile {
let data_dir = get_data_dir();
let prefix = format!("{data}/prefixes/wivrn_default", data = data_dir);
let mut environment: HashMap<String, String> = HashMap::new();
environment.insert(
"LD_LIBRARY_PATH".into(),
format!("{pfx}/lib:{pfx}/lib64", pfx = prefix),
);
environment.insert("LD_LIBRARY_PATH".into(), prepare_ld_library_path(&prefix));
environment.insert("XRT_DEBUG_GUI".into(), "1".into());
environment.insert("XRT_CURATED_GUI".into(), "1".into());
environment.insert("U_PACING_APP_USE_MIN_FRAME_PERIOD".into(), "1".into());

View file

@ -2,8 +2,8 @@ use crate::{
constants::APP_NAME,
paths::{data_basalt_path, data_monado_path, data_opencomposite_path, get_data_dir},
profile::{
LighthouseDriver, Profile, ProfileFeature, ProfileFeatureType, ProfileFeatures,
XRServiceType,
prepare_ld_library_path, LighthouseDriver, Profile, ProfileFeature, ProfileFeatureType,
ProfileFeatures, XRServiceType,
},
};
use std::collections::HashMap;
@ -18,10 +18,7 @@ pub fn wmr_profile() -> Profile {
environment.insert("XRT_DEBUG_GUI".into(), "1".into());
environment.insert("XRT_CURATED_GUI".into(), "1".into());
environment.insert("U_PACING_APP_USE_MIN_FRAME_PERIOD".into(), "1".into());
environment.insert(
"LD_LIBRARY_PATH".into(),
format!("{pfx}/lib:{pfx}/lib64", pfx = prefix),
);
environment.insert("LD_LIBRARY_PATH".into(), prepare_ld_library_path(&prefix));
Profile {
uuid: "wmr-default".into(),
name: format!("WMR - {name} Default", name = APP_NAME),
@ -34,6 +31,7 @@ pub fn wmr_profile() -> Profile {
enabled: true,
path: Some(data_basalt_path()),
repo: None,
branch: None,
},
mercury_enabled: true,
..Default::default()

View file

@ -40,6 +40,7 @@ use crate::paths::{get_data_dir, get_ipc_file_path};
use crate::profile::{Profile, XRServiceType};
use crate::profiles::lighthouse::lighthouse_profile;
use crate::profiles::openhmd::openhmd_profile;
use crate::profiles::simulated::simulated_profile;
use crate::profiles::survive::survive_profile;
use crate::profiles::wivrn::wivrn_profile;
use crate::profiles::wmr::wmr_profile;
@ -256,6 +257,7 @@ impl App {
wivrn_profile(),
wmr_profile(),
openhmd_profile(),
simulated_profile(),
];
profiles.extend(config.user_profiles.clone());
profiles.sort_unstable_by(|a, b| a.name.cmp(&b.name));

View file

@ -1,3 +1,4 @@
use super::term_widget::TermWidget;
use gtk::prelude::*;
use relm4::prelude::*;
@ -11,20 +12,15 @@ pub enum BuildStatus {
#[tracker::track]
pub struct BuildWindow {
title: String,
content: String,
can_close: bool,
build_status: BuildStatus,
#[tracker::do_not_track]
pub textbuf: gtk::TextBuffer,
#[tracker::do_not_track]
pub textview: Option<gtk::TextView>,
#[tracker::do_not_track]
pub win: Option<adw::Window>,
#[tracker::do_not_track]
build_status_label: Option<gtk::Label>,
#[tracker::do_not_track]
scrolledwin: Option<gtk::ScrolledWindow>,
term: TermWidget,
}
#[derive(Debug)]
@ -108,26 +104,7 @@ impl SimpleComponent for BuildWindow {
}
},
},
#[name(scrolledwin)]
gtk::ScrolledWindow {
set_hexpand: true,
set_vexpand: true,
set_margin_all: 12,
add_css_class: "card",
set_overflow: gtk::Overflow::Hidden,
#[name(textview)]
gtk::TextView {
set_hexpand: true,
set_vexpand: true,
set_editable: false,
set_monospace: true,
set_left_margin: 6,
set_right_margin: 6,
set_top_margin: 6,
set_bottom_margin: 6,
set_buffer: Some(&model.textbuf),
},
},
model.term.container.clone(),
},
add_bottom_bar: bottom_bar = &gtk::Button {
add_css_class: "pill",
@ -150,10 +127,10 @@ impl SimpleComponent for BuildWindow {
match message {
Self::Input::Present => {
self.win.as_ref().unwrap().present();
self.term.set_color_scheme();
sender.input(BuildWindowMsg::UpdateBuildStatus(BuildStatus::Building));
self.set_content("".into());
self.textbuf.set_text("");
self.term.clear();
self.win.as_ref().unwrap().present();
}
Self::Input::UpdateTitle(t) => {
self.set_title(t);
@ -161,17 +138,7 @@ impl SimpleComponent for BuildWindow {
Self::Input::UpdateContent(c) => {
if !c.is_empty() {
let n_lines = c.concat();
let mut n_content = self.content.clone();
n_content.push_str(n_lines.as_str());
self.set_content(n_content);
self.textbuf
.insert(&mut self.textbuf.end_iter(), n_lines.as_str());
let textbuf = self.textbuf.clone();
let textview = self.textview.as_ref().unwrap().clone();
gtk::glib::idle_add_local_once(move || {
let end_mark = textbuf.create_mark(None, &textbuf.end_iter(), false);
textview.scroll_mark_onscreen(&end_mark);
});
self.term.feed(&n_lines);
}
}
Self::Input::UpdateBuildStatus(status) => {
@ -202,20 +169,21 @@ impl SimpleComponent for BuildWindow {
let mut model = Self {
tracker: 0,
title: "".into(),
content: "".into(),
can_close: false,
textbuf: gtk::TextBuffer::builder().enable_undo(false).build(),
textview: None,
build_status: BuildStatus::Building,
win: None,
scrolledwin: None,
build_status_label: None,
term: {
let t = TermWidget::new();
t.container.add_css_class("card");
t.container.set_margin_all(12);
t.container.set_overflow(gtk::Overflow::Hidden);
t
},
};
let widgets = view_output!();
model.win = Some(widgets.win.clone());
model.build_status_label = Some(widgets.build_status_label.clone());
model.textview = Some(widgets.textview.clone());
model.scrolledwin = Some(widgets.scrolledwin.clone());
ComponentParts { model, widgets }
}
}

View file

@ -6,7 +6,9 @@ use gtk::glib::clone;
use gtk::prelude::*;
use relm4::prelude::*;
use relm4::{ComponentSender, SimpleComponent};
use zoha_vte4::{Terminal, TerminalExt};
use zoha_vte4::TerminalExt;
use super::term_widget::TermWidget;
#[derive(Debug)]
pub enum SearchDirection {
@ -37,13 +39,11 @@ pub struct DebugView {
#[tracker::do_not_track]
log_level: LogLevel,
#[tracker::do_not_track]
vte_terminal: Terminal,
term: TermWidget,
}
pub struct DebugViewInit {}
const MAX_SCROLLBACK: u32 = 2000;
#[relm4::component(pub)]
impl SimpleComponent for DebugView {
type Init = DebugViewInit;
@ -115,16 +115,11 @@ impl SimpleComponent for DebugView {
},
connect_entry: &search_entry,
},
#[wrap(Some)]
set_content: sw = &gtk::ScrolledWindow {
set_hexpand: true,
set_vexpand: true,
model.vte_terminal.clone(),
}
set_content: Some(&model.term.container),
}
}
fn update(&mut self, message: Self::Input, sender: ComponentSender<Self>) {
fn update(&mut self, message: Self::Input, _sender: ComponentSender<Self>) {
self.reset();
match message {
@ -142,19 +137,17 @@ impl SimpleComponent for DebugView {
let search_entry = self.search_entry.as_ref().unwrap().clone();
let search_text = search_entry.text().to_string();
if searchbar.is_search_mode() && !search_text.is_empty() {
if let Ok(regex) = zoha_vte4::Regex::for_search(&search_text, 0) {
self.vte_terminal.search_set_regex(Some(&regex), 0);
}
self.term.set_search_term(Some(&search_text));
} else {
self.vte_terminal.search_set_regex(None, 0);
self.term.set_search_term(None);
}
}
Self::Input::SearchFindMatch(direction) => match direction {
SearchDirection::Forward => {
self.vte_terminal.search_find_next();
self.term.search_next();
}
SearchDirection::Backward => {
self.vte_terminal.search_find_previous();
self.term.search_prev();
}
},
Self::Input::LogUpdated(n_log) => {
@ -173,15 +166,15 @@ impl SimpleComponent for DebugView {
None => Some(row),
};
if let Some(t) = txt {
self.vte_terminal.feed(t.as_bytes())
self.term.feed(&t);
}
}
}
Self::Input::ClearLog => {
self.vte_terminal.feed("\x1bc".as_bytes());
self.term.clear();
}
Self::Input::SetColorScheme => {
Self::set_color_scheme(&self.vte_terminal);
self.term.set_color_scheme();
}
}
}
@ -223,24 +216,13 @@ impl SimpleComponent for DebugView {
search_entry: None,
dropdown: None,
log_level: LogLevel::Trace,
vte_terminal: {
let t = Terminal::builder()
.scroll_on_output(true)
.scrollback_lines(MAX_SCROLLBACK)
.scroll_unit_is_pixels(true)
.vexpand(true)
.hexpand(true)
.build();
t.set_clear_background(false);
t.search_set_wrap_around(true);
Self::set_color_scheme(&t);
t
},
term: TermWidget::new(),
};
model.term.set_color_scheme();
{
let sc = gtk::ShortcutController::new();
let term = model.vte_terminal.clone();
let term = model.term.term.clone();
sc.add_shortcut(gtk::Shortcut::new(
gtk::ShortcutTrigger::parse_string("<Control>c"),
Some(gtk::CallbackAction::new(move |_, _| {
@ -250,7 +232,7 @@ impl SimpleComponent for DebugView {
true
})),
));
let term = model.vte_terminal.clone();
let term = model.term.term.clone();
sc.add_shortcut(gtk::Shortcut::new(
gtk::ShortcutTrigger::parse_string("<Control>a"),
Some(gtk::CallbackAction::new(move |_, _| {
@ -258,7 +240,7 @@ impl SimpleComponent for DebugView {
true
})),
));
model.vte_terminal.add_controller(sc);
model.term.term.add_controller(sc);
}
let widgets = view_output!();
@ -269,13 +251,3 @@ impl SimpleComponent for DebugView {
ComponentParts { model, widgets }
}
}
impl DebugView {
fn set_color_scheme(term: &Terminal) {
if adw::StyleManager::default().is_dark() {
term.set_color_foreground(&gtk::gdk::RGBA::new(1.0, 1.0, 1.0, 1.0));
} else {
term.set_color_foreground(&gtk::gdk::RGBA::new(0.0, 0.0, 0.0, 1.0));
}
}
}

View file

@ -2,6 +2,7 @@ use crate::{
file_builders::wivrn_config::{Codec, Encoder, WivrnConfEncoder},
ui::{
preference_rows::{combo_row, number_entry_row, spin_row},
util::{bits_from_mbits, bits_to_mbits},
wivrn_conf_editor::WivrnConfEditorMsg,
},
};
@ -24,6 +25,8 @@ pub enum WivrnEncoderModelMsg {
BitrateChanged(Option<u32>),
WidthChanged(Option<f32>),
HeightChanged(Option<f32>),
OffsetXChanged(Option<f32>),
OffsetYChanged(Option<f32>),
GroupChanged(Option<i32>),
Delete,
}
@ -83,9 +86,13 @@ impl AsyncFactoryComponent for WivrnEncoderModel {
}
) -> adw::ComboRow,
add: bitrate_row = &number_entry_row(
"Bitrate",
"Bitrate (Mbps)",
&self.encoder_conf.bitrate
.and_then(|n| Some(n.to_string()))
.and_then(|n| if let Some(mbits) = bits_to_mbits(n) {
Some(mbits.to_string())
} else {
None
})
.unwrap_or_default(),
false,
{
@ -96,7 +103,10 @@ impl AsyncFactoryComponent for WivrnEncoderModel {
if txt.is_empty() {
None
} else {
Some(txt.parse::<u32>().unwrap())
match txt.parse::<u32>() {
Ok(bits) => bits_from_mbits(bits),
Err(e) => None,
}
}
));
}
@ -134,6 +144,38 @@ impl AsyncFactoryComponent for WivrnEncoderModel {
}
}
) -> adw::SpinRow,
add: offset_x_row = &spin_row(
"Offset X",
None,
self.encoder_conf.offset_x.unwrap_or(0.0).into(),
0.0,
1.0,
0.01,
{
let sender = sender.clone();
move |adj| {
sender.input(Self::Input::OffsetXChanged(
Some(adj.value() as f32)
));
}
}
) -> adw::SpinRow,
add: offset_y_row = &spin_row(
"Offset Y",
None,
self.encoder_conf.offset_y.unwrap_or(0.0).into(),
0.0,
1.0,
0.01,
{
let sender = sender.clone();
move |adj| {
sender.input(Self::Input::OffsetYChanged(
Some(adj.value() as f32)
));
}
}
) -> adw::SpinRow,
add: group_row = &spin_row(
"Group",
None,
@ -170,6 +212,12 @@ impl AsyncFactoryComponent for WivrnEncoderModel {
Self::Input::HeightChanged(val) => {
self.encoder_conf.height = val;
}
Self::Input::OffsetXChanged(val) => {
self.encoder_conf.offset_x = val;
}
Self::Input::OffsetYChanged(val) => {
self.encoder_conf.offset_y = val;
}
Self::Input::GroupChanged(val) => {
self.encoder_conf.group = val;
}

View file

@ -174,11 +174,11 @@ impl InternalJobWorker {
let mut launch_opts = prof.xrservice_launch_options.trim();
let debug_launch_opts = if debug {
if launch_opts.contains(LAUNCH_OPTS_CMD_PLACEHOLDER) {
format!("{} {}", "gdb -batch -ex run -ex bt --args", launch_opts)
format!("{} {}", "gdbserver localhost:9000", launch_opts)
} else {
format!(
"{} {} {}",
"gdb -batch -ex run -ex bt --args", LAUNCH_OPTS_CMD_PLACEHOLDER, launch_opts
"gdbserver localhost:9000", LAUNCH_OPTS_CMD_PLACEHOLDER, launch_opts
)
}
} else {

View file

@ -1,11 +1,14 @@
use crate::{cmd_runner::CmdRunner, profile::Profile, runner::Runner};
use super::alert::alert;
use crate::{
cmd_runner::CmdRunner,
profile::{prepare_ld_library_path, Profile},
runner::Runner,
};
use adw::prelude::*;
use gtk::glib;
use relm4::prelude::*;
use std::{cell::Cell, collections::HashMap, path::Path, rc::Rc, time::Duration};
use super::alert::alert;
const NO_FILE_MSG: &str = "(No file selected)";
const CALIBRATION_RUN_TIME_SECONDS: f64 = 30.0;
@ -57,9 +60,10 @@ impl LibsurviveSetupWindow {
fn create_calibration_runner(&mut self, survive_cli_path: String) -> CmdRunner {
let lh_path = self.steam_lighthouse_path.clone();
let mut env = HashMap::new();
let profile_prefix = &self.profile.as_ref().unwrap().prefix;
env.insert(
"LD_LIBRARY_PATH".to_string(),
format!("{pfx}/lib", pfx = self.profile.as_ref().unwrap().prefix),
"LD_LIBRARY_PATH".into(),
prepare_ld_library_path(&profile_prefix),
);
CmdRunner::new(
Some(env),

View file

@ -185,7 +185,7 @@ impl SimpleComponent for MainView {
},
},
gtk::Button {
set_label: "Start with GDB",
set_label: "Start with gdbserver",
#[track = "model.changed(Self::xrservice_active()) || model.changed(Self::enable_debug_view())"]
set_visible: model.enable_debug_view && !model.xrservice_active,
connect_clicked[sender] => move |_| {

View file

@ -16,5 +16,6 @@ pub mod profile_editor;
pub mod stardust;
pub mod steam_launch_options_box;
mod steamvr_calibration_box;
pub mod term_widget;
pub mod util;
pub mod wivrn_conf_editor;

View file

@ -176,6 +176,14 @@ impl SimpleComponent for ProfileEditor {
prof.borrow_mut().xrservice_repo = (!n_val.is_empty()).then_some(n_val);
})
),
add: &entry_row(
"XR Service Branch",
model.profile.borrow().xrservice_branch.clone().unwrap_or_default().as_str(),
clone!(@strong prof => move |row| {
let n_val = row.text().to_string();
prof.borrow_mut().xrservice_branch = (!n_val.is_empty()).then_some(n_val);
})
),
},
add: model.xrservice_cmake_flags_rows.widget(),
add: opencompgrp = &adw::PreferencesGroup {
@ -197,6 +205,14 @@ impl SimpleComponent for ProfileEditor {
prof.borrow_mut().opencomposite_repo = (!n_val.is_empty()).then_some(n_val);
})
),
add: &entry_row(
"OpenComposite Branch",
model.profile.borrow().opencomposite_branch.clone().unwrap_or_default().as_str(),
clone!(@strong prof => move |row| {
let n_val = row.text().to_string();
prof.borrow_mut().opencomposite_branch = (!n_val.is_empty()).then_some(n_val);
})
),
},
add: libsurvivegrp = &adw::PreferencesGroup {
set_title: "Libsurvive",
@ -225,6 +241,14 @@ impl SimpleComponent for ProfileEditor {
prof.borrow_mut().features.libsurvive.repo = (!n_val.is_empty()).then_some(n_val);
})
),
add: &entry_row(
"Libsurvive Branch",
model.profile.borrow().features.libsurvive.branch.clone().unwrap_or_default().as_str(),
clone!(@strong prof => move |row| {
let n_val = row.text().to_string();
prof.borrow_mut().features.libsurvive.branch = (!n_val.is_empty()).then_some(n_val);
})
),
},
add: openhmdgrp = &adw::PreferencesGroup {
set_title: "OpenHMD",
@ -253,6 +277,14 @@ impl SimpleComponent for ProfileEditor {
prof.borrow_mut().features.openhmd.repo = (!n_val.is_empty()).then_some(n_val);
})
),
add: &entry_row(
"OpenHMD Branch",
model.profile.borrow().features.openhmd.branch.clone().unwrap_or_default().as_str(),
clone!(@strong prof => move |row| {
let n_val = row.text().to_string();
prof.borrow_mut().features.openhmd.branch = (!n_val.is_empty()).then_some(n_val);
})
),
},
add: basaltgrp = &adw::PreferencesGroup {
set_title: "Basalt",
@ -281,6 +313,14 @@ impl SimpleComponent for ProfileEditor {
prof.borrow_mut().features.basalt.repo = n_val.is_empty().then_some(n_val);
})
),
add: &entry_row(
"Basalt Branch",
model.profile.borrow().features.basalt.branch.clone().unwrap_or_default().as_str(),
clone!(@strong prof => move |row| {
let n_val = row.text().to_string();
prof.borrow_mut().features.basalt.branch = n_val.is_empty().then_some(n_val);
})
),
},
add: mercurygrp = &adw::PreferencesGroup {
set_title: "Mercury",

68
src/ui/term_widget.rs Normal file
View file

@ -0,0 +1,68 @@
use gtk4::gdk;
use relm4::adw;
use zoha_vte4::{Terminal, TerminalExt};
const MAX_SCROLLBACK: u32 = 2000;
#[derive(Debug, Clone)]
pub struct TermWidget {
pub container: gtk4::ScrolledWindow,
pub term: Terminal,
}
impl TermWidget {
pub fn new() -> Self {
let term = Terminal::builder()
.scroll_on_output(true)
.scrollback_lines(MAX_SCROLLBACK)
.scroll_unit_is_pixels(true)
.vexpand(true)
.hexpand(true)
.build();
term.set_clear_background(false);
term.search_set_wrap_around(true);
let container = gtk4::ScrolledWindow::builder()
.hexpand(true)
.vexpand(true)
.child(&term)
.build();
let this = Self { container, term };
this
}
pub fn set_color_scheme(&self) {
// TODO: use theme colors
if adw::StyleManager::default().is_dark() {
self.term
.set_color_foreground(&gdk::RGBA::new(1.0, 1.0, 1.0, 1.0));
} else {
self.term
.set_color_foreground(&gdk::RGBA::new(0.0, 0.0, 0.0, 1.0));
}
}
pub fn feed(&self, txt: &str) {
self.term.feed(txt.replace('\n', "\r\n").as_bytes())
}
pub fn clear(&self) {
self.term.feed("\x1bc".as_bytes());
}
pub fn set_search_term(&self, term: Option<&str>) {
self.term.search_set_regex(
term.map(|txt| zoha_vte4::Regex::for_search(txt, 0).ok())
.flatten()
.as_ref(),
0,
);
}
pub fn search_next(&self) {
self.term.search_find_next();
}
pub fn search_prev(&self) {
self.term.search_find_previous();
}
}

View file

@ -61,3 +61,11 @@ pub fn copy_text(txt: &str) {
}
}
}
pub fn bits_to_mbits(bits: u32) -> Option<u32> {
bits.checked_div(1000000)
}
pub fn bits_from_mbits(mbits: u32) -> Option<u32> {
mbits.checked_mul(1000000)
}

View file

@ -4,20 +4,24 @@
"xrservice_type": "Monado",
"xrservice_path": "/home/user/monado",
"xrservice_repo": null,
"xrservice_branch": null,
"opencomposite_path": "/home/user/opencomposite",
"opencomposite_repo": null,
"opencomposite_branch": null,
"features": {
"libsurvive": {
"feature_type": "Libsurvive",
"enabled": true,
"path": "/home/user/libsurvive",
"repo": null
"repo": null,
"branch": null
},
"basalt": {
"feature_type": "Basalt",
"enabled": false,
"path": null,
"repo": null
"repo": null,
"branch": null
},
"mercury_enabled": false
},
@ -30,4 +34,4 @@
"can_be_built": true,
"editable": true,
"pull_on_build": true
}
}

View file

@ -6,7 +6,9 @@
"codec": "h264",
"bitrate": 100000000,
"width": 1.0,
"height": 1.0
"height": 1.0,
"offset_x": 0.0,
"offset_y": 0.0
}
]
}