From 45697befddbd0d65b08d315d6cc223420fd7bd96 Mon Sep 17 00:00:00 2001 From: Aleksander Date: Tue, 5 Nov 2024 16:20:38 +0100 Subject: [PATCH] WayVR: Display auto-hide support (Fixes #98), keyboard settings in config --- src/backend/wayvr/display.rs | 30 ++++++++++++++++++++--- src/backend/wayvr/mod.rs | 14 ++++++++--- src/config_wayvr.rs | 46 ++++++++++++++++++++++++++++++++---- src/overlays/wayvr.rs | 28 ++++++++++++++++++---- src/res/wayvr.yaml | 13 ++++++++++ src/state.rs | 2 +- 6 files changed, 117 insertions(+), 16 deletions(-) diff --git a/src/backend/wayvr/display.rs b/src/backend/wayvr/display.rs index 912f97e..01c1762 100644 --- a/src/backend/wayvr/display.rs +++ b/src/backend/wayvr/display.rs @@ -15,11 +15,14 @@ use smithay::{ wayland::shell::xdg::ToplevelSurface, }; -use crate::{backend::overlay::OverlayID, gen_id}; +use crate::{ + backend::{overlay::OverlayID, wayvr::time::get_millis}, + gen_id, +}; use super::{ client::WayVRManager, comp::send_frames_surface_tree, egl_data, event_queue::SyncEventQueue, - process, smithay_wrapper, time, window, + process, smithay_wrapper, time, window, WayVRSignal, }; fn generate_auth_key() -> String { @@ -55,6 +58,7 @@ pub struct Display { pub displayed_windows: Vec, wayland_env: super::WaylandEnv, last_pressed_time_ms: u64, + pub no_windows_since: Option, // Render data stuff gles_texture: GlesTexture, // TODO: drop texture @@ -123,6 +127,7 @@ impl Display { overlay_id: None, tasks: SyncEventQueue::new(), last_pressed_time_ms: 0, + no_windows_since: None, }) } @@ -158,7 +163,24 @@ impl Display { } } - pub fn tick(&mut self) { + pub fn tick( + &mut self, + config: &super::Config, + handle: &DisplayHandle, + signals: &mut SyncEventQueue, + ) { + if self.visible { + if !self.displayed_windows.is_empty() { + self.no_windows_since = None; + } else if let Some(auto_hide_delay) = config.auto_hide_delay { + if let Some(s) = self.no_windows_since { + if s + (auto_hide_delay as u64) < get_millis() { + signals.send(WayVRSignal::DisplayHideRequest(*handle)); + } + } + } + } + while let Some(task) = self.tasks.read() { match task { DisplayTask::ProcessCleanup(process_handle) => { @@ -169,6 +191,7 @@ impl Display { self.name, self.displayed_windows.len() ); + self.no_windows_since = Some(get_millis()); self.reposition_windows(); } @@ -248,6 +271,7 @@ impl Display { self.visible = visible; if visible { self.wants_redraw = true; + self.no_windows_since = None; } } } diff --git a/src/backend/wayvr/mod.rs b/src/backend/wayvr/mod.rs index c2dcf90..cadfda0 100644 --- a/src/backend/wayvr/mod.rs +++ b/src/backend/wayvr/mod.rs @@ -65,10 +65,16 @@ pub enum WayVRTask { ProcessTerminationRequest(process::ProcessHandle), } +#[derive(Clone)] +pub enum WayVRSignal { + DisplayHideRequest(display::DisplayHandle), +} + pub struct Config { pub click_freeze_time_ms: u32, pub keyboard_repeat_delay_ms: u32, pub keyboard_repeat_rate: u32, + pub auto_hide_delay: Option, // if None, auto-hide is disabled } #[allow(dead_code)] @@ -83,6 +89,7 @@ pub struct WayVR { config: Config, tasks: SyncEventQueue, + pub signals: SyncEventQueue, } pub enum MouseIndex { @@ -140,6 +147,7 @@ impl WayVR { processes: ProcessVec::new(), egl_data: Rc::new(egl_data), wm: Rc::new(RefCell::new(window::WindowManager::new())), + signals: SyncEventQueue::new(), tasks, config, }) @@ -206,9 +214,9 @@ impl WayVR { } } - for display in self.displays.vec.iter_mut().flatten() { - display.obj.tick(); - } + self.displays.iter_mut(&mut |handle, display| { + display.tick(&self.config, &handle, &mut self.signals); + }); while let Some(task) = self.tasks.read() { match task { diff --git a/src/config_wayvr.rs b/src/config_wayvr.rs index ef11843..f212a9a 100644 --- a/src/config_wayvr.rs +++ b/src/config_wayvr.rs @@ -80,12 +80,40 @@ impl WayVRCatalog { } } +fn def_true() -> bool { + true +} + +fn def_autohide_delay() -> u32 { + 750 +} + +fn def_keyboard_repeat_delay() -> u32 { + 200 +} + +fn def_keyboard_repeat_rate() -> u32 { + 50 +} + #[derive(Deserialize, Serialize)] pub struct WayVRConfig { pub version: u32, pub run_compositor_at_start: bool, pub catalogs: HashMap, pub displays: BTreeMap, // sorted alphabetically + + #[serde(default = "def_true")] + pub auto_hide: bool, + + #[serde(default = "def_autohide_delay")] + pub auto_hide_delay: u32, + + #[serde(default = "def_keyboard_repeat_delay")] + pub keyboard_repeat_delay: u32, + + #[serde(default = "def_keyboard_repeat_rate")] + pub keyboard_repeat_rate: u32, } impl WayVRConfig { @@ -106,11 +134,19 @@ impl WayVRConfig { None } - pub fn get_wayvr_config(config: &crate::config::GeneralConfig) -> wayvr::Config { + pub fn get_wayvr_config( + config_general: &crate::config::GeneralConfig, + config_wayvr: &crate::config_wayvr::WayVRConfig, + ) -> wayvr::Config { wayvr::Config { - click_freeze_time_ms: config.click_freeze_time_ms, - keyboard_repeat_delay_ms: 200, - keyboard_repeat_rate: 50, + click_freeze_time_ms: config_general.click_freeze_time_ms, + keyboard_repeat_delay_ms: config_wayvr.keyboard_repeat_delay, + keyboard_repeat_rate: config_wayvr.keyboard_repeat_rate, + auto_hide_delay: if config_wayvr.auto_hide { + Some(config_wayvr.auto_hide_delay) + } else { + None + }, } } @@ -147,7 +183,7 @@ impl WayVRConfig { if self.run_compositor_at_start { // Start Wayland server instantly Ok(Some(Rc::new(RefCell::new(WayVRState::new( - Self::get_wayvr_config(config), + Self::get_wayvr_config(config, &self), )?)))) } else { // Lazy-init WayVR later if the user requested diff --git a/src/overlays/wayvr.rs b/src/overlays/wayvr.rs index d757f55..251bb17 100644 --- a/src/overlays/wayvr.rs +++ b/src/overlays/wayvr.rs @@ -6,12 +6,13 @@ use wlx_capture::frame::{DmabufFrame, FourCC, FrameFormat, FramePlane}; use crate::{ backend::{ - common::OverlayContainer, + common::{OverlayContainer, OverlaySelector}, input::{self, InteractionHandler}, overlay::{ ui_transform, OverlayData, OverlayID, OverlayRenderer, OverlayState, SplitOverlayBackend, }, + task::TaskType, wayvr::{self, display, WayVR}, }, graphics::WlxGraphics, @@ -213,8 +214,27 @@ pub fn tick_events(app: &mut AppState, overlays: &mut OverlayContainer) -> where O: Default, { - if let Some(wayvr) = app.wayvr.clone() { - let res = wayvr.borrow_mut().state.tick_events()?; + if let Some(r_wayvr) = app.wayvr.clone() { + let mut wayvr = r_wayvr.borrow_mut(); + while let Some(signal) = wayvr.state.signals.read() { + match signal { + wayvr::WayVRSignal::DisplayHideRequest(display_handle) => { + if let Some(overlay_id) = wayvr.display_handle_map.get(&display_handle) { + let overlay_id = *overlay_id; + wayvr.state.set_display_visible(display_handle, false); + app.tasks.enqueue(TaskType::Overlay( + OverlaySelector::Id(overlay_id), + Box::new(move |_app, o| { + o.want_visible = false; + }), + )); + } + } + } + } + + let res = wayvr.state.tick_events()?; + drop(wayvr); for result in res { match result { @@ -232,7 +252,7 @@ where }; if let Some(disp_name) = disp_name { - let mut wayvr = wayvr.borrow_mut(); + let mut wayvr = r_wayvr.borrow_mut(); log::info!("Registering external process with PID {}", req.pid); diff --git a/src/res/wayvr.yaml b/src/res/wayvr.yaml index ac3d1f9..a3b378d 100644 --- a/src/res/wayvr.yaml +++ b/src/res/wayvr.yaml @@ -9,6 +9,19 @@ version: 1 # (used for remote starting external processes) run_compositor_at_start: false +# Automatically close overlays with zero window count? +auto_hide: true + +# For how long an overlay should be visible in case if there are no windows present? (in milliseconds, auto_hide needs to be enabled) +# This value shouldn't be set at 0, because some programs could re-initialize a window during startup (splash screens for example) +auto_hide_delay: 750 + +# In milliseconds +keyboard_repeat_delay: 200 + +# Chars per second +keyboard_repeat_rate: 50 + displays: Watch: width: 400 diff --git a/src/state.rs b/src/state.rs index de8698f..b3c4cb2 100644 --- a/src/state.rs +++ b/src/state.rs @@ -127,7 +127,7 @@ impl AppState { Ok(wvr.clone()) } else { let wayvr = Rc::new(RefCell::new(WayVRState::new( - WayVRConfig::get_wayvr_config(&self.session.config), + WayVRConfig::get_wayvr_config(&self.session.config, &self.session.wayvr_config), )?)); self.wayvr = Some(wayvr.clone()); Ok(wayvr)