feat: extract devices from monado logs and represent them in ui

This commit is contained in:
Gabriele Musco 2023-07-07 06:38:07 +02:00
parent 94932b0214
commit b5ad5e0e80
No known key found for this signature in database
GPG key ID: 1068D795C80E51DE
5 changed files with 304 additions and 4 deletions

View file

@ -90,9 +90,9 @@ impl Runner {
}
}
pub fn xrservice_runner_from_profile(profile: Profile) -> Self {
pub fn xrservice_runner_from_profile(profile: &Profile) -> Self {
Self::new(
Some(profile.environment),
Some(profile.environment.clone()),
match profile.xrservice_type {
XRServiceType::Monado => format!("{pfx}/bin/monado-service", pfx = profile.prefix),
XRServiceType::Wivrn => format!("{pfx}/bin/wivrn-server", pfx = profile.prefix),
@ -253,7 +253,7 @@ mod tests {
#[test]
fn can_create_from_profile() {
Runner::xrservice_runner_from_profile(Profile::load_profile(
Runner::xrservice_runner_from_profile(&Profile::load_profile(
&"./test/files/profile.json".to_string(),
));
}

View file

@ -19,6 +19,7 @@ use crate::dependencies::monado_deps::get_missing_monado_deps;
use crate::dependencies::pkexec_dep::pkexec_dep;
use crate::dependencies::wivrn_deps::get_missing_wivrn_deps;
use crate::file_utils::setcap_cap_sys_nice_eip;
use crate::log_parser::MonadoLog;
use crate::profile::{Profile, XRServiceType};
use crate::profiles::system_valve_index::system_valve_index_profile;
use crate::profiles::valve_index::valve_index_profile;
@ -29,6 +30,7 @@ use crate::ui::build_window::BuildWindowMsg;
use crate::ui::debug_view::DebugViewInit;
use crate::ui::libsurvive_setup_window::LibsurviveSetupMsg;
use crate::ui::main_view::{MainView, MainViewInit, MainViewOutMsg};
use crate::xr_devices::XRDevices;
use expect_dialog::ExpectDialog;
use gtk::prelude::*;
use relm4::actions::{AccelsPlus, ActionGroupName, RelmAction, RelmActionGroup};
@ -71,6 +73,8 @@ pub struct App {
build_pipeline: Option<RunnerPipeline>,
#[tracker::do_not_track]
profiles: Vec<Profile>,
#[tracker::do_not_track]
devices_processed: bool,
}
#[derive(Debug)]
@ -85,6 +89,7 @@ pub enum Msg {
RunSetCap,
OpenLibsurviveSetup,
Quit,
ProcessDevicesLog(Vec<String>),
}
impl App {
@ -102,10 +107,15 @@ impl App {
}
pub fn start_xrservice(&mut self) {
let prof = self.get_selected_profile();
self.devices_processed = match prof.xrservice_type {
XRServiceType::Monado => false,
XRServiceType::Wivrn => true, // no device from log in wivrn
};
self.debug_view
.sender()
.emit(DebugViewMsg::ClearLog);
let mut runner = Runner::xrservice_runner_from_profile(self.get_selected_profile().clone());
let mut runner = Runner::xrservice_runner_from_profile(&prof);
match runner.try_start() {
Ok(_) => {
self.xrservice_runner = Some(runner);
@ -189,6 +199,9 @@ impl SimpleComponent for App {
Some(runner) => {
let n_rows = runner.consume_rows();
if !n_rows.is_empty() {
if !self.devices_processed {
sender.input(Msg::ProcessDevicesLog(n_rows.clone()))
}
self.debug_view
.sender()
.emit(DebugViewMsg::LogUpdated(n_rows));
@ -245,6 +258,25 @@ impl SimpleComponent for App {
};
self.main_view.sender().emit(MainViewMsg::ClockTicking);
}
Msg::ProcessDevicesLog(rows) => {
for row in rows {
match MonadoLog::from_str(row.as_str()) {
None => {}
Some(parsed) => {
if parsed.func == "p_create_system" {
match XRDevices::from_log_message(parsed.message) {
None => {},
Some(devices) => {
self.devices_processed = true;
self.main_view.sender().emit(MainViewMsg::UpdateDevices(Some(devices)));
break;
}
};
}
}
};
}
}
Msg::EnableDebugViewChanged(val) => {
self.set_enable_debug_view(val);
self.config.debug_view_enabled = val;
@ -501,6 +533,7 @@ impl SimpleComponent for App {
profiles,
xrservice_runner: None,
build_pipeline: None,
devices_processed: false,
};
let widgets = view_output!();

253
src/ui/devices_box.rs Normal file
View file

@ -0,0 +1,253 @@
use crate::xr_devices::{XRDevice, XRDevices};
use gtk::prelude::*;
use relm4::prelude::*;
#[tracker::track]
pub struct DevicesBox {
devices: Option<XRDevices>,
}
#[derive(Debug)]
pub enum DevicesBoxMsg {
UpdateDevices(Option<XRDevices>),
}
impl DevicesBox {
fn get_dev(&self, key: XRDevice) -> Option<String> {
match &self.devices {
None => None,
Some(devs) => match key {
XRDevice::Head => devs.head.clone(),
XRDevice::Left => devs.left.clone(),
XRDevice::Right => devs.right.clone(),
XRDevice::Gamepad => devs.gamepad.clone(),
XRDevice::Eyes => devs.eyes.clone(),
XRDevice::HandTrackingLeft => devs.hand_tracking_left.clone(),
XRDevice::HandTrackingRight => devs.hand_tracking_right.clone(),
},
}
}
}
#[relm4::component(pub)]
impl SimpleComponent for DevicesBox {
type Init = ();
type Input = DevicesBoxMsg;
type Output = ();
view! {
gtk::Box {
set_orientation: gtk::Orientation::Vertical,
set_hexpand: true,
set_vexpand: false,
set_spacing: 12,
set_margin_top: 12,
#[track = "model.changed(Self::devices())"]
set_visible: model.devices.is_some(),
gtk::Separator {
set_orientation: gtk::Orientation::Horizontal,
set_hexpand: true,
},
// Head
gtk::Box {
set_orientation: gtk::Orientation::Horizontal,
set_hexpand: true,
set_spacing: 12,
set_margin_start: 12,
set_margin_end: 12,
gtk::Image {
#[track = "model.changed(Self::devices())"]
set_icon_name: Some(match model.get_dev(XRDevice::Head) {
Some(_) => "emblem-ok-symbolic",
None => "dialog-question-symbolic",
}),
#[track = "model.changed(Self::devices())"]
set_class_active: ("error", model.get_dev(XRDevice::Head).is_none()),
},
gtk::Label {
set_xalign: 0.0,
set_hexpand: true,
#[track = "model.changed(Self::devices())"]
set_label: format!("Head: {}", match model.get_dev(XRDevice::Head) {
Some(v) => v.clone(),
None => "None".to_string(),
}).as_str(),
#[track = "model.changed(Self::devices())"]
set_class_active: ("error", model.get_dev(XRDevice::Head).is_none()),
// TODO: status icon with popover
},
},
// Left
gtk::Box {
set_orientation: gtk::Orientation::Horizontal,
set_hexpand: true,
set_spacing: 12,
set_margin_start: 12,
set_margin_end: 12,
gtk::Image {
#[track = "model.changed(Self::devices())"]
set_icon_name: Some(match model.get_dev(XRDevice::Left) {
Some(_) => "emblem-ok-symbolic",
None => "dialog-question-symbolic",
}),
#[track = "model.changed(Self::devices())"]
set_class_active: ("error", model.get_dev(XRDevice::Left).is_none()),
},
gtk::Label {
set_xalign: 0.0,
set_hexpand: true,
#[track = "model.changed(Self::devices())"]
set_label: format!("Left: {}", match model.get_dev(XRDevice::Left) {
Some(v) => v.clone(),
None => "None".to_string(),
}).as_str(),
#[track = "model.changed(Self::devices())"]
set_class_active: ("error", model.get_dev(XRDevice::Left).is_none()),
// TODO: status icon with popover
},
},
// Right
gtk::Box {
set_orientation: gtk::Orientation::Horizontal,
set_hexpand: true,
set_spacing: 12,
set_margin_start: 12,
set_margin_end: 12,
gtk::Image {
#[track = "model.changed(Self::devices())"]
set_icon_name: Some(match model.get_dev(XRDevice::Right) {
Some(_) => "emblem-ok-symbolic",
None => "dialog-question-symbolic",
}),
#[track = "model.changed(Self::devices())"]
set_class_active: ("error", model.get_dev(XRDevice::Right).is_none()),
},
gtk::Label {
set_xalign: 0.0,
set_hexpand: true,
#[track = "model.changed(Self::devices())"]
set_label: format!("Right: {}", match model.get_dev(XRDevice::Right) {
Some(v) => v.clone(),
None => "None".to_string(),
}).as_str(),
#[track = "model.changed(Self::devices())"]
set_class_active: ("error", model.get_dev(XRDevice::Right).is_none()),
// TODO: status icon with popover
},
},
// Gamepad
gtk::Box {
set_orientation: gtk::Orientation::Horizontal,
set_hexpand: true,
set_spacing: 12,
set_margin_start: 12,
set_margin_end: 12,
#[track = "model.changed(Self::devices())"]
set_visible: model.get_dev(XRDevice::Gamepad).is_some(),
gtk::Image {
set_icon_name: Some("emblem-ok-symbolic"),
},
gtk::Label {
set_xalign: 0.0,
set_hexpand: true,
#[track = "model.changed(Self::devices())"]
set_label: format!("Gamepad: {}", match model.get_dev(XRDevice::Gamepad) {
Some(v) => v.clone(),
None => "None".to_string(),
}).as_str(),
},
},
// Eyes
gtk::Box {
set_orientation: gtk::Orientation::Horizontal,
set_hexpand: true,
set_spacing: 12,
set_margin_start: 12,
set_margin_end: 12,
#[track = "model.changed(Self::devices())"]
set_visible: model.get_dev(XRDevice::Eyes).is_some(),
gtk::Image {
set_icon_name: Some("emblem-ok-symbolic"),
},
gtk::Label {
set_xalign: 0.0,
set_hexpand: true,
#[track = "model.changed(Self::devices())"]
set_label: format!("Eye Tracking: {}", match model.get_dev(XRDevice::Eyes) {
Some(v) => v.clone(),
None => "None".to_string(),
}).as_str(),
},
},
// Hand Tracking Left
gtk::Box {
set_orientation: gtk::Orientation::Horizontal,
set_hexpand: true,
set_spacing: 12,
set_margin_start: 12,
set_margin_end: 12,
#[track = "model.changed(Self::devices())"]
set_visible: model.get_dev(XRDevice::HandTrackingLeft).is_some(),
gtk::Image {
set_icon_name: Some("emblem-ok-symbolic"),
},
gtk::Label {
set_xalign: 0.0,
set_hexpand: true,
#[track = "model.changed(Self::devices())"]
set_label: format!("Hand Tracking Left: {}", match model.get_dev(XRDevice::HandTrackingLeft) {
Some(v) => v.clone(),
None => "None".to_string(),
}).as_str(),
},
},
// Hand Tracking Right
gtk::Box {
set_orientation: gtk::Orientation::Horizontal,
set_hexpand: true,
set_spacing: 12,
set_margin_start: 12,
set_margin_end: 12,
#[track = "model.changed(Self::devices())"]
set_visible: model.get_dev(XRDevice::HandTrackingRight).is_some(),
gtk::Image {
set_icon_name: Some("emblem-ok-symbolic"),
},
gtk::Label {
set_xalign: 0.0,
set_hexpand: true,
#[track = "model.changed(Self::devices())"]
set_label: format!("Hand Tracking Left: {}", match model.get_dev(XRDevice::HandTrackingRight) {
Some(v) => v.clone(),
None => "None".to_string(),
}).as_str(),
},
},
}
}
fn update(&mut self, message: Self::Input, sender: ComponentSender<Self>) {
self.reset();
match message {
Self::Input::UpdateDevices(devs) => {
self.set_devices(devs);
}
}
}
fn init(
init: Self::Init,
root: &Self::Root,
sender: ComponentSender<Self>,
) -> ComponentParts<Self> {
let model = Self {
tracker: 0,
devices: None,
};
let widgets = view_output!();
ComponentParts { model, widgets }
}
}

View file

@ -1,3 +1,4 @@
use super::devices_box::{DevicesBox, DevicesBoxMsg};
use super::install_wivrn_box::{InstallWivrnBox, InstallWivrnBoxInit, InstallWivrnBoxMsg};
use super::profile_editor::{ProfileEditor, ProfileEditorMsg, ProfileEditorOutMsg};
use super::runtime_switcher_box::{
@ -11,6 +12,7 @@ use crate::ui::app::{
AboutAction, BuildProfileAction, DebugViewToggleAction, LibsurviveSetupAction,
};
use crate::ui::profile_editor::ProfileEditorInit;
use crate::xr_devices::XRDevices;
use gtk::prelude::*;
use relm4::adw::traits::MessageDialogExt;
use relm4::adw::ResponseAppearance;
@ -32,6 +34,8 @@ pub struct MainView {
#[tracker::do_not_track]
runtime_switcher_box: Controller<RuntimeSwitcherBox>,
#[tracker::do_not_track]
devices_box: Controller<DevicesBox>,
#[tracker::do_not_track]
profile_editor: Controller<ProfileEditor>,
#[tracker::do_not_track]
profile_not_editable_dialog: adw::MessageDialog,
@ -54,6 +58,7 @@ pub enum MainViewMsg {
DeleteProfile,
DuplicateProfile,
SaveProfile(Profile),
UpdateDevices(Option<XRDevices>),
}
#[derive(Debug)]
@ -141,6 +146,7 @@ impl SimpleComponent for MainView {
sender.input(MainViewMsg::StartStopClicked)
},
},
model.devices_box.widget(),
model.runtime_switcher_box.widget(),
model.steam_launch_options_box.widget(),
model.install_wivrn_box.widget(),
@ -221,6 +227,9 @@ impl SimpleComponent for MainView {
}
Self::Input::XRServiceActiveChanged(active, profile) => {
self.set_xrservice_active(active);
if !active {
sender.input(Self::Input::UpdateDevices(None));
}
self.steam_launch_options_box
.sender()
.emit(SteamLaunchOptionsBoxMsg::UpdateXRServiceActive(active));
@ -299,6 +308,9 @@ impl SimpleComponent for MainView {
self.selected_profile.create_duplicate(),
));
}
Self::Input::UpdateDevices(devs) => {
self.devices_box.sender().emit(DevicesBoxMsg::UpdateDevices(devs))
}
}
}
@ -376,6 +388,7 @@ impl SimpleComponent for MainView {
.forward(sender.input_sender(), |message| match message {
ProfileEditorOutMsg::SaveProfile(p) => Self::Input::SaveProfile(p),
}),
devices_box: DevicesBox::builder().launch(()).detach(),
selected_profile: init.selected_profile.clone(),
profile_not_editable_dialog,
profile_delete_confirm_dialog,

View file

@ -10,3 +10,4 @@ pub mod runtime_switcher_box;
pub mod profile_editor;
pub mod factories;
pub mod wivrn_conf_editor;
pub mod devices_box;