From 6c95607d448fc7c9642161fd340ece2269beada8 Mon Sep 17 00:00:00 2001 From: Aleksander Date: Sun, 19 Jan 2025 00:53:59 +0100 Subject: [PATCH] Watch: Add "Toggle Dashboard" button by default, Toast: Show user-specific error messages in various places, WayVR: Modify example env vars --- src/backend/openvr/mod.rs | 2 +- src/backend/openxr/mod.rs | 2 +- src/backend/task.rs | 2 +- src/backend/wayvr/egl_data.rs | 14 ++------- src/config_wayvr.rs | 3 +- src/gui/modular/button.rs | 59 ++++++++++++++++++++++++++--------- src/gui/modular/label.rs | 21 ++++++++++--- src/gui/modular/mod.rs | 32 ++++++++++--------- src/overlays/toast.rs | 23 ++++++++++++++ src/overlays/wayvr.rs | 56 ++++++++++++++++++--------------- src/res/watch.yaml | 16 ++++++++-- src/res/wayvr.yaml | 3 +- 12 files changed, 155 insertions(+), 78 deletions(-) diff --git a/src/backend/openvr/mod.rs b/src/backend/openvr/mod.rs index 21c57f0..50ecc6e 100644 --- a/src/backend/openvr/mod.rs +++ b/src/backend/openvr/mod.rs @@ -43,7 +43,7 @@ use crate::{ }; #[cfg(feature = "wayvr")] -use crate::overlays::wayvr::{wayvr_action, WayVRAction}; +use crate::{gui::modular::button::WayVRAction, overlays::wayvr::wayvr_action}; pub mod helpers; pub mod input; diff --git a/src/backend/openxr/mod.rs b/src/backend/openxr/mod.rs index 431010c..eebf3af 100644 --- a/src/backend/openxr/mod.rs +++ b/src/backend/openxr/mod.rs @@ -32,7 +32,7 @@ use crate::{ }; #[cfg(feature = "wayvr")] -use crate::overlays::wayvr::{wayvr_action, WayVRAction}; +use crate::{gui::modular::button::WayVRAction, overlays::wayvr::wayvr_action}; mod helpers; mod input; diff --git a/src/backend/task.rs b/src/backend/task.rs index 76ce0e8..9b58806 100644 --- a/src/backend/task.rs +++ b/src/backend/task.rs @@ -10,7 +10,7 @@ use serde::Deserialize; use crate::state::AppState; #[cfg(feature = "wayvr")] -use crate::overlays::wayvr::WayVRAction; +use crate::gui::modular::button::WayVRAction; use super::{ common::OverlaySelector, diff --git a/src/backend/wayvr/egl_data.rs b/src/backend/wayvr/egl_data.rs index db72796..7842fd3 100644 --- a/src/backend/wayvr/egl_data.rs +++ b/src/backend/wayvr/egl_data.rs @@ -83,6 +83,8 @@ impl EGLData { let context = egl.create_context(display, config, None, &context_attrib_list)?; + log::debug!("eglMakeCurrent"); + egl.make_current(display, None, None, Some(context))?; Ok(EGLData { @@ -94,18 +96,6 @@ impl EGLData { } } - #[allow(dead_code)] - pub fn make_current(&self, surface: &khronos_egl::Surface) -> anyhow::Result<()> { - self.egl.make_current( - self.display, - Some(*surface), - Some(*surface), - Some(self.context), - )?; - - Ok(()) - } - fn query_dmabuf_mod_info(&self) -> anyhow::Result { let target_fourcc = 0x34324258; //XB24 diff --git a/src/config_wayvr.rs b/src/config_wayvr.rs index f8c5dd9..d113d29 100644 --- a/src/config_wayvr.rs +++ b/src/config_wayvr.rs @@ -17,7 +17,8 @@ use crate::{ wayvr, }, config::{load_known_yaml, ConfigType}, - overlays::wayvr::{WayVRAction, WayVRData}, + gui::modular::button::WayVRAction, + overlays::wayvr::WayVRData, }; // Flat version of RelativeTo diff --git a/src/gui/modular/button.rs b/src/gui/modular/button.rs index d408d97..45e6bc8 100644 --- a/src/gui/modular/button.rs +++ b/src/gui/modular/button.rs @@ -19,14 +19,14 @@ use crate::{ config::{save_layout, save_settings, AStrSetExt}, hid::VirtualKey, overlays::{ - toast::{Toast, ToastTopic}, + toast::{error_toast, Toast, ToastTopic}, watch::WATCH_NAME, }, state::AppState, }; -#[cfg(feature = "wayvr")] -use crate::overlays::wayvr::WayVRAction; +#[cfg(not(feature = "wayvr"))] +use crate::overlays::toast::error_toast_str; use super::{ExecArgs, ModularControl, ModularData}; @@ -119,6 +119,26 @@ pub enum WindowAction { Destroy, } +#[derive(Deserialize, Clone)] +pub enum WayVRDisplayClickAction { + ToggleVisibility, + Reset, +} + +#[derive(Deserialize, Clone)] +#[allow(dead_code)] // in case if WayVR feature is disabled +pub enum WayVRAction { + AppClick { + catalog_name: Arc, + app_name: Arc, + }, + DisplayClick { + display_name: Arc, + action: WayVRDisplayClickAction, + }, + ToggleDashboard, +} + #[derive(Deserialize, Clone)] #[serde(tag = "type")] pub enum ButtonAction { @@ -137,8 +157,10 @@ pub enum ButtonAction { target: OverlaySelector, action: OverlayAction, }, - #[cfg(feature = "wayvr")] - WayVR(WayVRAction), + // Ignored if "wayvr" feature is not enabled + WayVR { + action: WayVRAction, + }, Window { target: Arc, action: WindowAction, @@ -332,9 +354,16 @@ fn handle_action(action: &ButtonAction, press: &mut PressData, app: &mut AppStat ButtonAction::Watch { action } => run_watch(action, app), ButtonAction::Overlay { target, action } => run_overlay(target, action, app), ButtonAction::Window { target, action } => run_window(target, action, app), - #[cfg(feature = "wayvr")] - ButtonAction::WayVR(action) => { - app.tasks.enqueue(TaskType::WayVR(action.clone())); + ButtonAction::WayVR { action } => { + #[cfg(feature = "wayvr")] + { + app.tasks.enqueue(TaskType::WayVR(action.clone())); + } + #[cfg(not(feature = "wayvr"))] + { + let _ = &action; + error_toast_str(app, "WayVR feature is not enabled"); + } } ButtonAction::VirtualKey { keycode, action } => app .hid_provider @@ -461,12 +490,12 @@ fn run_system(action: &SystemAction, app: &mut AppState) { } SystemAction::PersistConfig => { if let Err(e) = save_settings(&app.session.config) { - log::error!("Failed to save config: {:?}", e); + error_toast(app, "Failed to save config", e); } } SystemAction::PersistLayout => { if let Err(e) = save_layout(&app.session.config) { - log::error!("Failed to save layout: {:?}", e); + error_toast(app, "Failed to save layout", e); } } } @@ -477,7 +506,7 @@ fn run_exec(args: &ExecArgs, toast: &Option>, press: &mut PressData, ap match proc.try_wait() { Ok(Some(code)) => { if !code.success() { - log::error!("Child process exited with code: {}", code); + error_toast(app, "Child process exited with code", code); } press.child = None; } @@ -487,7 +516,7 @@ fn run_exec(args: &ExecArgs, toast: &Option>, press: &mut PressData, ap } Err(e) => { press.child = None; - log::error!("Error checking child process: {:?}", e); + error_toast(app, "Error checking child process", e); } } } @@ -500,7 +529,7 @@ fn run_exec(args: &ExecArgs, toast: &Option>, press: &mut PressData, ap } } Err(e) => { - log::error!("Failed to spawn process {:?}: {:?}", args, e); + error_toast(app, &format!("Failed to spawn process {:?}", args), e); } }; } @@ -651,7 +680,9 @@ fn run_overlay(overlay: &OverlaySelector, action: &OverlayAction, app: &mut AppS if state_dirty { match save_layout(&app.session.config) { Ok(_) => log::debug!("Saved state"), - Err(e) => log::error!("Failed to save state: {:?}", e), + Err(e) => { + error_toast(app, "Failed to save state", e); + } } } }), diff --git a/src/gui/modular/label.rs b/src/gui/modular/label.rs index b858e25..fa06256 100644 --- a/src/gui/modular/label.rs +++ b/src/gui/modular/label.rs @@ -9,7 +9,11 @@ use std::{ time::Instant, }; -use crate::{gui::modular::FALLBACK_COLOR, state::AppState}; +use crate::{ + gui::modular::FALLBACK_COLOR, + overlays::toast::{error_toast, error_toast_str}, + state::AppState, +}; use serde::Deserialize; @@ -233,14 +237,21 @@ pub(super) fn label_update(control: &mut ModularControl, _: &mut (), app: &mut A match proc.try_wait() { Ok(Some(code)) => { if !code.success() { - log::error!("Child process exited with code: {}", code); + error_toast( + app, + "LabelData::Exec: Child process exited with code", + code, + ); } else { if let Some(mut stdout) = proc.stdout.take() { let mut buf = String::new(); if stdout.read_to_string(&mut buf).is_ok() { control.set_text(&buf); } else { - log::error!("Failed to read stdout for child process"); + error_toast_str( + app, + "LabelData::Exec: Failed to read stdout for child process", + ); return; } return; @@ -256,7 +267,7 @@ pub(super) fn label_update(control: &mut ModularControl, _: &mut (), app: &mut A } Err(e) => { *child = None; - log::error!("Error checking child process: {:?}", e); + error_toast(app, "Error checking child process", e); return; } } @@ -282,7 +293,7 @@ pub(super) fn label_update(control: &mut ModularControl, _: &mut (), app: &mut A *child = Some(proc); } Err(e) => { - log::error!("Failed to spawn process {:?}: {:?}", args, e); + error_toast(app, &format!("Failed to spawn process {:?}", args), e); } }; } diff --git a/src/gui/modular/mod.rs b/src/gui/modular/mod.rs index aef110a..ccd2ea6 100644 --- a/src/gui/modular/mod.rs +++ b/src/gui/modular/mod.rs @@ -3,6 +3,9 @@ pub mod label; use std::{fs::File, sync::Arc}; +#[cfg(feature = "wayvr")] +use button::{WayVRAction, WayVRDisplayClickAction}; + use glam::Vec4; use serde::Deserialize; use vulkano::{command_buffer::CommandBufferUsage, image::view::ImageView}; @@ -12,9 +15,6 @@ use crate::{ graphics::dds::WlxCommandBufferDds, state::AppState, }; -#[cfg(feature = "wayvr")] -use crate::overlays::wayvr::{WayVRAction, WayVRDisplayClickAction}; - use self::{ button::{modular_button_init, ButtonAction, ButtonData, OverlayAction}, label::{modular_label_init, LabelContent, LabelData}, @@ -452,10 +452,12 @@ pub fn modular_canvas( ); let data = ButtonData { - click_up: Some(vec![ButtonAction::WayVR(WayVRAction::AppClick { - catalog_name: catalog_name.clone(), - app_name: Arc::from(app.name.as_str()), - })]), + click_up: Some(vec![ButtonAction::WayVR { + action: WayVRAction::AppClick { + catalog_name: catalog_name.clone(), + app_name: Arc::from(app.name.as_str()), + }, + }]), ..Default::default() }; @@ -502,16 +504,18 @@ pub fn modular_canvas( ); let data = ButtonData { - click_up: Some(vec![ButtonAction::WayVR(WayVRAction::DisplayClick { - display_name: Arc::from(display_name.as_str()), - action: WayVRDisplayClickAction::ToggleVisibility, - })]), - long_click_up: Some(vec![ButtonAction::WayVR( - WayVRAction::DisplayClick { + click_up: Some(vec![ButtonAction::WayVR { + action: WayVRAction::DisplayClick { + display_name: Arc::from(display_name.as_str()), + action: WayVRDisplayClickAction::ToggleVisibility, + }, + }]), + long_click_up: Some(vec![ButtonAction::WayVR { + action: WayVRAction::DisplayClick { display_name: Arc::from(display_name.as_str()), action: WayVRDisplayClickAction::Reset, }, - )]), + }]), ..Default::default() }; diff --git a/src/overlays/toast.rs b/src/overlays/toast.rs index e042ae3..7e856f3 100644 --- a/src/overlays/toast.rs +++ b/src/overlays/toast.rs @@ -207,3 +207,26 @@ fn new_toast(toast: Toast, app: &mut AppState) -> Option<(OverlayState, Box(app: &mut AppState, title: &str, err: ErrorType) +where + ErrorType: std::fmt::Display + std::fmt::Debug, +{ + log::error!("{}: {:?}", title, err); // More detailed version (use Debug) + + // Brief version (use Display) + msg_err(app, &format!("{}: {}", title, err)); +} + +pub fn error_toast_str(app: &mut AppState, message: &str) { + log::error!("{}", message); + msg_err(app, message); +} diff --git a/src/overlays/wayvr.rs b/src/overlays/wayvr.rs index d9e9771..9050e9f 100644 --- a/src/overlays/wayvr.rs +++ b/src/overlays/wayvr.rs @@ -1,5 +1,4 @@ use glam::{vec3a, Affine2, Vec3, Vec3A}; -use serde::Deserialize; use std::{cell::RefCell, collections::HashMap, rc::Rc, sync::Arc}; use vulkano::image::SubresourceLayout; use wlx_capture::frame::{DmabufFrame, FourCC, FrameFormat, FramePlane}; @@ -21,9 +20,12 @@ use crate::{ }, config_wayvr, graphics::WlxGraphics, + gui::modular::button::{WayVRAction, WayVRDisplayClickAction}, state::{self, AppState, KeyboardFocus}, }; +use super::toast::error_toast; + // Hard-coded for now const DASHBOARD_WIDTH: u16 = 960; const DASHBOARD_HEIGHT: u16 = 540; @@ -54,6 +56,7 @@ struct OverlayToCreate { pub struct WayVRData { display_handle_map: HashMap, overlays_to_create: Vec, + dashboard_executed: bool, pub data: WayVR, } @@ -63,6 +66,7 @@ impl WayVRData { display_handle_map: Default::default(), data: WayVR::new(config)?, overlays_to_create: Vec::new(), + dashboard_executed: false, }) } @@ -217,6 +221,19 @@ fn get_or_create_display_by_name( Ok(disp_handle) } +fn executable_exists_in_path(command: &str) -> bool { + let Ok(path) = std::env::var("PATH") else { + return false; // very unlikely to happen + }; + for dir in path.split(':') { + let exec_path = std::path::PathBuf::from(dir).join(command); + if exec_path.exists() && exec_path.is_file() { + return true; // executable found + } + } + false +} + fn toggle_dashboard( app: &mut AppState, overlays: &mut OverlayContainer, @@ -225,6 +242,12 @@ fn toggle_dashboard( where O: Default, { + let conf_dash = &app.session.wayvr_config.dashboard; + + if !wayvr.dashboard_executed && !executable_exists_in_path(&conf_dash.exec) { + anyhow::bail!("Executable \"{}\" not found", &conf_dash.exec); + } + let (newly_created, disp_handle) = wayvr.data.state.get_or_create_dashboard_display( DASHBOARD_WIDTH, DASHBOARD_HEIGHT, @@ -257,6 +280,8 @@ where overlay.state.z_order = Z_ORDER_DASHBOARD; overlay.state.reset(app, true); + let conf_dash = &app.session.wayvr_config.dashboard; + // FIXME: overlay curvature needs to be dispatched for some unknown reason, this value is not set otherwise app.tasks.enqueue(TaskType::Overlay( OverlaySelector::Id(overlay.state.id), @@ -267,8 +292,6 @@ where overlays.add(overlay); - let conf_dash = &app.session.wayvr_config.dashboard; - let args_vec = match &conf_dash.args { Some(args) => gen_args_vec(args), None => vec![], @@ -286,6 +309,8 @@ where .state .spawn_process(disp_handle, &conf_dash.exec, &args_vec, &env_vec)?; + wayvr.dashboard_executed = true; + return Ok(()); } @@ -626,25 +651,6 @@ where }) } -#[derive(Deserialize, Clone)] -pub enum WayVRDisplayClickAction { - ToggleVisibility, - Reset, -} - -#[derive(Deserialize, Clone)] -pub enum WayVRAction { - AppClick { - catalog_name: Arc, - app_name: Arc, - }, - DisplayClick { - display_name: Arc, - action: WayVRDisplayClickAction, - }, - ToggleDashboard, -} - fn show_display(wayvr: &mut WayVRData, overlays: &mut OverlayContainer, display_name: &str) where O: Default, @@ -775,7 +781,7 @@ where if let Err(e) = action_app_click(app, overlays, catalog_name, app_name) { // Happens if something went wrong with initialization // or input exec path is invalid. Do nothing, just print an error - log::error!("action_app_click failed: {}", e); + error_toast(app, "action_app_click failed", e); } } WayVRAction::DisplayClick { @@ -783,7 +789,7 @@ where action, } => { if let Err(e) = action_display_click::(app, overlays, display_name, action) { - log::error!("action_display_click failed: {}", e); + error_toast(app, "action_display_click failed", e); } } WayVRAction::ToggleDashboard => { @@ -791,7 +797,7 @@ where let mut wayvr = wayvr.borrow_mut(); if let Err(e) = toggle_dashboard::(app, overlays, &mut wayvr) { - log::error!("toggle_dashboard failed: {}", e); + error_toast(app, "toggle_dashboard failed", e); } } } diff --git a/src/res/watch.yaml b/src/res/watch.yaml index 0abeb08..ddeb73c 100644 --- a/src/res/watch.yaml +++ b/src/res/watch.yaml @@ -28,9 +28,21 @@ elements: target: settings action: Destroy # only triggers if exists since before current frame + # Dashboard toggle button + - type: Button + rect: [32, 162, 48, 36] + corner_radius: 4 + font_size: 15 + bg_color: "#2288FF" + fg_color: "#24273a" + text: "Dash" + click_up: + - type: WayVR + action: ToggleDashboard + # Keyboard button - type: Button - rect: [32, 162, 60, 36] + rect: [84, 162, 48, 36] corner_radius: 4 font_size: 15 fg_color: "#24273a" @@ -65,7 +77,7 @@ elements: # bottom row, of keyboard + overlays - type: OverlayList - rect: [94, 160, 306, 40] + rect: [134, 160, 266, 40] corner_radius: 4 font_size: 15 fg_color: "#cad3f5" diff --git a/src/res/wayvr.yaml b/src/res/wayvr.yaml index 69309bb..a1062aa 100644 --- a/src/res/wayvr.yaml +++ b/src/res/wayvr.yaml @@ -28,11 +28,10 @@ keyboard_repeat_rate: 50 # Build instructions: https://github.com/olekolek1000/wayvr-dashboard # exec: Executable path, for example /home/USER/wayvr_dashboard/src-tauri/target/release/wayvr_dashboard # GDK_BACKEND=wayland: Force-use Wayland for GTK apps -# LIBGL_ALWAYS_SOFTWARE: Mesa crash mitigation for Tauri apps on AMD GPUs dashboard: exec: "wayvr_dashboard" args: "" - env: ["GDK_BACKEND=wayland", "LIBGL_ALWAYS_SOFTWARE=1"] + env: ["GDK_BACKEND=wayland"] displays: Watch: