From 01fea96545d63a154b484a718ce28c1e1096fbe6 Mon Sep 17 00:00:00 2001 From: galister <22305755+galister@users.noreply.github.com> Date: Wed, 10 Dec 2025 17:12:26 +0900 Subject: [PATCH] refactor tasks --- wlx-overlay-s/src/backend/input.rs | 9 +- wlx-overlay-s/src/backend/openvr/mod.rs | 80 ++------- wlx-overlay-s/src/backend/openvr/playspace.rs | 20 ++- wlx-overlay-s/src/backend/openxr/mod.rs | 79 ++------- wlx-overlay-s/src/backend/openxr/playspace.rs | 15 +- wlx-overlay-s/src/backend/task.rs | 22 ++- wlx-overlay-s/src/gui/panel/button.rs | 10 +- wlx-overlay-s/src/main.rs | 27 ++- wlx-overlay-s/src/overlays/edit/lock.rs | 4 +- wlx-overlay-s/src/overlays/edit/mod.rs | 20 ++- wlx-overlay-s/src/overlays/edit/pos.rs | 6 +- wlx-overlay-s/src/overlays/mirror.rs | 10 +- wlx-overlay-s/src/overlays/toast.rs | 18 +- wlx-overlay-s/src/overlays/watch.rs | 16 +- wlx-overlay-s/src/overlays/wayvr.rs | 14 +- wlx-overlay-s/src/windowing/manager.rs | 164 +++++++++++------- 16 files changed, 255 insertions(+), 259 deletions(-) diff --git a/wlx-overlay-s/src/backend/input.rs b/wlx-overlay-s/src/backend/input.rs index 27134f7..4535456 100644 --- a/wlx-overlay-s/src/backend/input.rs +++ b/wlx-overlay-s/src/backend/input.rs @@ -8,6 +8,7 @@ use idmap_derive::IntegerId; use smallvec::{smallvec, SmallVec}; use wlx_common::windowing::{OverlayWindowState, Positioning}; +use crate::backend::task::OverlayTask; use crate::overlays::anchor::ANCHOR_NAME; use crate::state::{AppSession, AppState}; use crate::subsystem::hid::WheelDelta; @@ -630,12 +631,12 @@ fn start_grab( }; // Show anchor - app.tasks.enqueue(TaskType::Overlay( + app.tasks.enqueue(TaskType::Overlay(OverlayTask::Modify( OverlaySelector::Name(ANCHOR_NAME.clone()), Box::new(|app, o| { o.activate(app); }), - )); + ))); } fn handle_scale(transform: &mut Affine3A, scroll_y: f32) { @@ -711,12 +712,12 @@ where } // Hide anchor - app.tasks.enqueue(TaskType::Overlay( + app.tasks.enqueue(TaskType::Overlay(OverlayTask::Modify( OverlaySelector::Name(ANCHOR_NAME.clone()), Box::new(|_app, o| { o.deactivate(); }), - )); + ))); log::debug!("Hand {}: dropped {}", idx, overlay.config.name); } } diff --git a/wlx-overlay-s/src/backend/openvr/mod.rs b/wlx-overlay-s/src/backend/openvr/mod.rs index bdce4ab..71d032e 100644 --- a/wlx-overlay-s/src/backend/openvr/mod.rs +++ b/wlx-overlay-s/src/backend/openvr/mod.rs @@ -1,10 +1,7 @@ use std::{ collections::VecDeque, ops::Add, - sync::{ - atomic::{AtomicBool, AtomicUsize, Ordering}, - Arc, - }, + sync::atomic::Ordering, time::{Duration, Instant}, }; @@ -26,7 +23,7 @@ use crate::{ manifest::{install_manifest, uninstall_manifest}, overlay::OpenVrOverlayData, }, - task::{ManagerTask, SystemTask, TaskType}, + task::{OpenVrTask, OverlayTask, TaskType}, BackendError, }, config::save_state, @@ -40,8 +37,8 @@ use crate::{ windowing::{ backend::{RenderResources, ShouldRender}, manager::OverlayWindowManager, - window::OverlayWindowData, }, + RUNNING, }; #[cfg(feature = "wayvr")] @@ -54,8 +51,6 @@ pub mod manifest; pub mod overlay; pub mod playspace; -static FRAME_COUNTER: AtomicUsize = AtomicUsize::new(0); - pub fn openvr_uninstall() { let app_type = EVRApplicationType::VRApplication_Overlay; let Ok(context) = ovr_overlay::Context::init(app_type) else { @@ -68,11 +63,7 @@ pub fn openvr_uninstall() { } #[allow(clippy::too_many_lines, clippy::cognitive_complexity)] -pub fn openvr_run( - running: Arc, - show_by_default: bool, - headless: bool, -) -> Result<(), BackendError> { +pub fn openvr_run(show_by_default: bool, headless: bool) -> Result<(), BackendError> { let app_type = EVRApplicationType::VRApplication_Overlay; let Ok(context) = ovr_overlay::Context::init(app_type) else { log::warn!("Will not use OpenVR: Context init failed"); @@ -107,7 +98,7 @@ pub fn openvr_run( if show_by_default { app.tasks.enqueue_at( - TaskType::Manager(ManagerTask::ShowHide), + TaskType::Overlay(OverlayTask::ShowHide), Instant::now().add(Duration::from_secs(1)), ); } @@ -159,13 +150,11 @@ pub fn openvr_run( 'main_loop: loop { let _ = overlay_mgr.wait_frame_sync(frame_timeout); - if !running.load(Ordering::Relaxed) { + if !RUNNING.load(Ordering::Relaxed) { log::warn!("Received shutdown signal."); break 'main_loop; } - let cur_frame = FRAME_COUNTER.fetch_add(1, Ordering::Relaxed); - while let Some(event) = system_mgr.poll_next_event() { match event.event_type { EVREventType::VREvent_Quit => { @@ -215,52 +204,17 @@ pub fn openvr_run( while let Some(task) = due_tasks.pop_front() { match task { - TaskType::Overlay(sel, f) => { - if let Some(o) = overlays.mut_by_selector(&sel) { - f(&mut app, &mut o.config); - } else { - log::warn!("Overlay not found for task: {sel:?}"); - } - } - TaskType::CreateOverlay(sel, f) => { - let None = overlays.mut_by_selector(&sel) else { - continue; - }; - - let Some(overlay_config) = f(&mut app) else { - continue; - }; - - overlays.add( - OverlayWindowData { - birthframe: cur_frame, - ..OverlayWindowData::from_config(overlay_config) - }, - &mut app, - ); - } - TaskType::DropOverlay(sel) => { - if let Some(o) = overlays.mut_by_selector(&sel) - && o.birthframe < cur_frame - { - o.destroy(&mut overlay_mgr); - overlays.remove_by_selector(&sel, &mut app); - } - } - TaskType::System(task) => match task { - SystemTask::ColorGain(channel, value) => { - let _ = adjust_gain(&mut settings_mgr, channel, value); - } - SystemTask::FixFloor => { - playspace.fix_floor(&mut chaperone_mgr, &app.input_state); - } - SystemTask::ResetPlayspace => { - playspace.reset_offset(&mut chaperone_mgr, &app.input_state); - } - }, - TaskType::Manager(task) => { + TaskType::Overlay(task) => { overlays.handle_task(&mut app, task)?; } + TaskType::Playspace(task) => { + playspace.handle_task(&mut app, &mut chaperone_mgr, task); + } + TaskType::OpenVR(task) => match task { + OpenVrTask::ColorGain(channel, value) => { + let _ = adjust_gain(&mut settings_mgr, channel, value); + } + }, #[cfg(feature = "wayvr")] TaskType::WayVR(action) => { wayvr_action(&mut app, &mut overlays, &action); @@ -268,6 +222,10 @@ pub fn openvr_run( } } + while let Some(mut o) = overlays.pop_dropped() { + o.destroy(&mut overlay_mgr); + } + let universe = playspace.get_universe(); app.input_state.pre_update(); diff --git a/wlx-overlay-s/src/backend/openvr/playspace.rs b/wlx-overlay-s/src/backend/openvr/playspace.rs index 69e7230..80bda0e 100644 --- a/wlx-overlay-s/src/backend/openvr/playspace.rs +++ b/wlx-overlay-s/src/backend/openvr/playspace.rs @@ -6,7 +6,9 @@ use ovr_overlay::{ }; use crate::{ - backend::input::InputState, state::AppState, windowing::manager::OverlayWindowManager, + backend::{input::InputState, task::PlayspaceTask}, + state::AppState, + windowing::manager::OverlayWindowManager, }; use super::{helpers::Affine3AConvert, overlay::OpenVrOverlayData}; @@ -32,6 +34,22 @@ impl PlayspaceMover { } } + pub fn handle_task( + &mut self, + app: &AppState, + chaperone_mgr: &mut ChaperoneSetupManager, + task: PlayspaceTask, + ) { + match task { + PlayspaceTask::FixFloor => { + self.fix_floor(chaperone_mgr, &app.input_state); + } + PlayspaceTask::ResetPlayspace => { + self.reset_offset(chaperone_mgr, &app.input_state); + } + } + } + #[allow(clippy::too_many_lines, clippy::cognitive_complexity)] pub fn update( &mut self, diff --git a/wlx-overlay-s/src/backend/openxr/mod.rs b/wlx-overlay-s/src/backend/openxr/mod.rs index 9b09c2c..94e733e 100644 --- a/wlx-overlay-s/src/backend/openxr/mod.rs +++ b/wlx-overlay-s/src/backend/openxr/mod.rs @@ -2,7 +2,7 @@ use std::{ collections::VecDeque, ops::Add, sync::{ - atomic::{AtomicBool, AtomicUsize, Ordering}, + atomic::{AtomicBool, Ordering}, Arc, }, time::{Duration, Instant}, @@ -20,7 +20,7 @@ use crate::{ backend::{ input::interact, openxr::{lines::LinePool, overlay::OpenXrOverlayData}, - task::{ManagerTask, SystemTask, TaskType}, + task::{OverlayTask, TaskType}, BackendError, }, config::save_state, @@ -34,8 +34,8 @@ use crate::{ windowing::{ backend::{RenderResources, ShouldRender}, manager::OverlayWindowManager, - window::OverlayWindowData, }, + FRAME_COUNTER, RUNNING, }; #[cfg(feature = "wayvr")] @@ -51,7 +51,6 @@ mod skybox; mod swapchain; const VIEW_TYPE: xr::ViewConfigurationType = xr::ViewConfigurationType::PRIMARY_STEREO; -static FRAME_COUNTER: AtomicUsize = AtomicUsize::new(0); struct XrState { instance: xr::Instance, @@ -63,11 +62,7 @@ struct XrState { } #[allow(clippy::too_many_lines, clippy::cognitive_complexity)] -pub fn openxr_run( - running: Arc, - show_by_default: bool, - headless: bool, -) -> Result<(), BackendError> { +pub fn openxr_run(show_by_default: bool, headless: bool) -> Result<(), BackendError> { let (xr_instance, system) = match helpers::init_xr() { Ok((xr_instance, system)) => (xr_instance, system), Err(e) => { @@ -95,7 +90,7 @@ pub fn openxr_run( if show_by_default { app.tasks.enqueue_at( - TaskType::Manager(ManagerTask::ShowHide), + TaskType::Overlay(OverlayTask::ShowHide), Instant::now().add(Duration::from_secs(1)), ); } @@ -178,7 +173,7 @@ pub fn openxr_run( 'main_loop: loop { let cur_frame = FRAME_COUNTER.fetch_add(1, Ordering::Relaxed); - if !running.load(Ordering::Relaxed) { + if !RUNNING.load(Ordering::Relaxed) { log::warn!("Received shutdown signal."); match xr_state.session.request_exit() { Ok(()) => log::info!("OpenXR session exit requested."), @@ -493,58 +488,16 @@ pub fn openxr_run( app.tasks.retrieve_due(&mut due_tasks); while let Some(task) = due_tasks.pop_front() { match task { - TaskType::Overlay(sel, f) => { - if let Some(o) = overlays.mut_by_selector(&sel) { - f(&mut app, &mut o.config); - } else { - log::warn!("Overlay not found for task: {sel:?}"); - } - } - TaskType::CreateOverlay(sel, f) => { - let None = overlays.mut_by_selector(&sel) else { - continue; - }; - let Some(overlay_config) = f(&mut app) else { - continue; - }; - overlays.add( - OverlayWindowData { - birthframe: cur_frame, - ..OverlayWindowData::from_config(overlay_config) - }, - &mut app, - ); - } - TaskType::DropOverlay(sel) => { - if let Some(o) = overlays.mut_by_selector(&sel) - && o.birthframe < cur_frame - { - log::debug!("{}: destroy", o.config.name); - if let Some(o) = overlays.remove_by_selector(&sel, &mut app) { - // set for deletion after all images are done showing - delete_queue.push((o, cur_frame + 5)); - } - } - } - TaskType::System(task) => match task { - SystemTask::FixFloor => { - if let Some(ref mut playspace) = playspace { - playspace.fix_floor( - &app.input_state, - monado.as_mut().unwrap(), // safe - ); - } - } - SystemTask::ResetPlayspace => { - if let Some(ref mut playspace) = playspace { - playspace.reset_offset(monado.as_mut().unwrap()); // safe - } - } - _ => {} - }, - TaskType::Manager(task) => { + TaskType::Overlay(task) => { overlays.handle_task(&mut app, task)?; } + TaskType::Playspace(task) => { + if let (Some(playspace), Some(monado)) = (playspace.as_mut(), monado.as_mut()) { + playspace.handle_task(&mut app, monado, task); + } + } + #[cfg(feature = "openvr")] + TaskType::OpenVR(_) => {} #[cfg(feature = "wayvr")] TaskType::WayVR(action) => { wayvr_action(&mut app, &mut overlays, &action); @@ -552,6 +505,10 @@ pub fn openxr_run( } } + while let Some(o) = overlays.pop_dropped() { + delete_queue.push((o, cur_frame + 5)); + } + delete_queue.retain(|(_, frame)| *frame > cur_frame); //FIXME: Temporary workaround for Monado bug diff --git a/wlx-overlay-s/src/backend/openxr/playspace.rs b/wlx-overlay-s/src/backend/openxr/playspace.rs index 2fb6603..0459cdd 100644 --- a/wlx-overlay-s/src/backend/openxr/playspace.rs +++ b/wlx-overlay-s/src/backend/openxr/playspace.rs @@ -2,7 +2,9 @@ use glam::{Affine3A, Quat, Vec3A}; use libmonado::{Monado, Pose, ReferenceSpaceType}; use crate::{ - backend::input::InputState, state::AppState, windowing::manager::OverlayWindowManager, + backend::{input::InputState, task::PlayspaceTask}, + state::AppState, + windowing::manager::OverlayWindowManager, }; use super::overlay::OpenXrOverlayData; @@ -41,6 +43,17 @@ impl PlayspaceMover { }) } + pub fn handle_task(&mut self, app: &AppState, monado: &mut Monado, task: PlayspaceTask) { + match task { + PlayspaceTask::FixFloor => { + self.fix_floor(&app.input_state, monado); + } + PlayspaceTask::ResetPlayspace => { + self.reset_offset(monado); + } + } + } + pub fn update( &mut self, overlays: &mut OverlayWindowManager, diff --git a/wlx-overlay-s/src/backend/task.rs b/wlx-overlay-s/src/backend/task.rs index db5d225..4f67c7e 100644 --- a/wlx-overlay-s/src/backend/task.rs +++ b/wlx-overlay-s/src/backend/task.rs @@ -43,28 +43,34 @@ impl Ord for AppTask { } } -pub enum SystemTask { +#[cfg(feature = "openvr")] +pub enum OpenVrTask { ColorGain(ColorChannel, f32), +} + +pub enum PlayspaceTask { ResetPlayspace, FixFloor, } -pub type OverlayTask = dyn FnOnce(&mut AppState, &mut OverlayWindowConfig) + Send; +pub type ModifyOverlayTask = dyn FnOnce(&mut AppState, &mut OverlayWindowConfig) + Send; pub type CreateOverlayTask = dyn FnOnce(&mut AppState) -> Option + Send; -pub enum ManagerTask { +pub enum OverlayTask { AddSet, ToggleSet(usize), DeleteActiveSet, ToggleEditMode, ShowHide, + Modify(OverlaySelector, Box), + Create(OverlaySelector, Box), + Drop(OverlaySelector), } pub enum TaskType { - Overlay(OverlaySelector, Box), - CreateOverlay(OverlaySelector, Box), - DropOverlay(OverlaySelector), - Manager(ManagerTask), - System(SystemTask), + Overlay(OverlayTask), + Playspace(PlayspaceTask), + #[cfg(feature = "openvr")] + OpenVR(OpenVrTask), #[cfg(feature = "wayvr")] WayVR(WayVRAction), } diff --git a/wlx-overlay-s/src/gui/panel/button.rs b/wlx-overlay-s/src/gui/panel/button.rs index 8fe7f69..0a201e4 100644 --- a/wlx-overlay-s/src/gui/panel/button.rs +++ b/wlx-overlay-s/src/gui/panel/button.rs @@ -13,7 +13,7 @@ use wgui::{ }; use crate::{ - backend::task::{ManagerTask, TaskType}, + backend::task::{OverlayTask, TaskType}, state::AppState, windowing::OverlaySelector, }; @@ -58,7 +58,7 @@ pub(super) fn setup_custom_button( }; Box::new(move |_common, _data, app, _| { app.tasks - .enqueue(TaskType::Manager(ManagerTask::ToggleSet(set_idx))); + .enqueue(TaskType::Overlay(OverlayTask::ToggleSet(set_idx))); Ok(EventResult::Consumed) }) } @@ -69,7 +69,7 @@ pub(super) fn setup_custom_button( }; Box::new(move |_common, _data, app, _| { - app.tasks.enqueue(TaskType::Overlay( + app.tasks.enqueue(TaskType::Overlay(OverlayTask::Modify( OverlaySelector::Name(arg.clone()), Box::new(move |app, owc| { if owc.active_state.is_none() { @@ -78,13 +78,13 @@ pub(super) fn setup_custom_button( owc.deactivate(); } }), - )); + ))); Ok(EventResult::Consumed) }) } "::EditToggle" => Box::new(move |_common, _data, app, _| { app.tasks - .enqueue(TaskType::Manager(ManagerTask::ToggleEditMode)); + .enqueue(TaskType::Overlay(OverlayTask::ToggleEditMode)); Ok(EventResult::Consumed) }), "::WatchHide" => todo!(), diff --git a/wlx-overlay-s/src/main.rs b/wlx-overlay-s/src/main.rs index a5dd142..47ee18c 100644 --- a/wlx-overlay-s/src/main.rs +++ b/wlx-overlay-s/src/main.rs @@ -33,10 +33,7 @@ mod config_wayvr; use std::{ path::PathBuf, - sync::{ - atomic::{AtomicBool, Ordering}, - Arc, - }, + sync::atomic::{AtomicBool, AtomicUsize, Ordering}, }; use clap::Parser; @@ -45,6 +42,9 @@ use sysinfo::Pid; use tracing::level_filters::LevelFilter; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter}; +pub static FRAME_COUNTER: AtomicUsize = AtomicUsize::new(0); +pub static RUNNING: AtomicBool = AtomicBool::new(true); + /// The lightweight desktop overlay for OpenVR and OpenXR #[derive(Default, Parser, Debug)] #[command(version, about, long_about = None)] @@ -82,11 +82,6 @@ struct Args { /// Path to write logs to #[arg(short, long, value_name = "FILE_PATH")] log_to: Option, - - #[cfg(feature = "uidev")] - /// Show a desktop window of a UI panel for development - #[arg(short, long, value_name = "UI_NAME")] - uidev: Option, } #[allow(clippy::unnecessary_wraps)] @@ -118,21 +113,19 @@ fn main() -> Result<(), Box> { return Ok(()); } - let running = Arc::new(AtomicBool::new(true)); let _ = ctrlc::set_handler({ - let running = running.clone(); - move || { - running.store(false, Ordering::Relaxed); + || { + RUNNING.store(false, Ordering::Relaxed); } }); - auto_run(running, args); + auto_run(args); Ok(()) } #[allow(unused_mut, clippy::similar_names)] -fn auto_run(running: Arc, args: Args) { +fn auto_run(args: Args) { let mut tried_xr = false; let mut tried_vr = false; @@ -140,7 +133,7 @@ fn auto_run(running: Arc, args: Args) { if !args_get_openvr(&args) { use crate::backend::{openxr::openxr_run, BackendError}; tried_xr = true; - match openxr_run(running.clone(), args.show, args.headless) { + match openxr_run(args.show, args.headless) { Ok(()) => return, Err(BackendError::NotSupported) => (), Err(e) => { @@ -154,7 +147,7 @@ fn auto_run(running: Arc, args: Args) { if !args_get_openxr(&args) { use crate::backend::{openvr::openvr_run, BackendError}; tried_vr = true; - match openvr_run(running, args.show, args.headless) { + match openvr_run(args.show, args.headless) { Ok(()) => return, Err(BackendError::NotSupported) => (), Err(e) => { diff --git a/wlx-overlay-s/src/overlays/edit/lock.rs b/wlx-overlay-s/src/overlays/edit/lock.rs index 9399881..c3412e7 100644 --- a/wlx-overlay-s/src/overlays/edit/lock.rs +++ b/wlx-overlay-s/src/overlays/edit/lock.rs @@ -7,7 +7,7 @@ use wgui::{ widget::rectangle::WidgetRectangle, }; -use crate::{backend::task::OverlayTask, overlays::edit::EditModeWrapPanel, state::AppState}; +use crate::{backend::task::ModifyOverlayTask, overlays::edit::EditModeWrapPanel, state::AppState}; #[derive(Default)] pub(super) struct InteractLockHandler { @@ -53,7 +53,7 @@ impl InteractLockHandler { &mut self, common: &mut CallbackDataCommon, app: &mut AppState, - ) -> Box { + ) -> Box { let defaults = app.wgui_globals.get().defaults.clone(); let rect_color = self.color; diff --git a/wlx-overlay-s/src/overlays/edit/mod.rs b/wlx-overlay-s/src/overlays/edit/mod.rs index a1456e2..6b14b29 100644 --- a/wlx-overlay-s/src/overlays/edit/mod.rs +++ b/wlx-overlay-s/src/overlays/edit/mod.rs @@ -18,7 +18,7 @@ use wgui::{ use crate::{ backend::{ input::HoverResult, - task::{TaskContainer, TaskType}, + task::{OverlayTask, TaskContainer, TaskType}, }, gui::panel::{button::BUTTON_EVENTS, GuiPanel, NewGuiPanelParams, OnCustomAttribFunc}, overlays::edit::{ @@ -247,7 +247,8 @@ fn make_edit_panel(app: &mut AppState) -> anyhow::Result { "::EditModeToggleLock" => Box::new(move |common, _data, app, state| { let sel = OverlaySelector::Id(*state.id.borrow()); let task = state.lock.toggle(common, app); - app.tasks.enqueue(TaskType::Overlay(sel, task)); + app.tasks + .enqueue(TaskType::Overlay(OverlayTask::Modify(sel, task))); Ok(EventResult::Consumed) }), "::EditModeTab" => { @@ -262,7 +263,8 @@ fn make_edit_panel(app: &mut AppState) -> anyhow::Result { Box::new(move |common, _data, app, state| { let sel = OverlaySelector::Id(*state.id.borrow()); let task = state.pos.pos_button_clicked(common, &pos_key); - app.tasks.enqueue(TaskType::Overlay(sel, task)); + app.tasks + .enqueue(TaskType::Overlay(OverlayTask::Modify(sel, task))); Ok(EventResult::Consumed) }) } @@ -275,12 +277,12 @@ fn make_edit_panel(app: &mut AppState) -> anyhow::Result { if state.delete.pressed.elapsed() < Duration::from_secs(1) { return Ok(EventResult::Pass); } - app.tasks.enqueue(TaskType::Overlay( + app.tasks.enqueue(TaskType::Overlay(OverlayTask::Modify( OverlaySelector::Id(*state.id.borrow()), Box::new(move |_app, owc| { owc.active_state = None; }), - )); + ))); Ok(EventResult::Consumed) }), _ => return, @@ -384,10 +386,10 @@ fn set_up_slider( let mut tasks = tasks.borrow_mut(); let e_value = e.value; - tasks.enqueue(TaskType::Overlay( + tasks.enqueue(TaskType::Overlay(OverlayTask::Modify( OverlaySelector::Id(*overlay_id.borrow()), Box::new(move |app, owc| callback(app, owc, e_value)), - )); + ))); Ok(()) })); @@ -408,10 +410,10 @@ fn set_up_checkbox( let mut tasks = tasks.borrow_mut(); let e_checked = e.checked; - tasks.enqueue(TaskType::Overlay( + tasks.enqueue(TaskType::Overlay(OverlayTask::Modify( OverlaySelector::Id(*overlay_id.borrow()), Box::new(move |app, owc| callback(app, owc, e_checked)), - )); + ))); Ok(()) })); diff --git a/wlx-overlay-s/src/overlays/edit/pos.rs b/wlx-overlay-s/src/overlays/edit/pos.rs index a1aca54..ce59fa6 100644 --- a/wlx-overlay-s/src/overlays/edit/pos.rs +++ b/wlx-overlay-s/src/overlays/edit/pos.rs @@ -7,7 +7,9 @@ use wgui::{ }; use wlx_common::{common::LeftRight, windowing::Positioning}; -use crate::{backend::task::OverlayTask, overlays::edit::EditModeWrapPanel, windowing::window}; +use crate::{ + backend::task::ModifyOverlayTask, overlays::edit::EditModeWrapPanel, windowing::window, +}; static POS_NAMES: [&str; 6] = ["static", "anchored", "floating", "hmd", "hand_l", "hand_r"]; @@ -89,7 +91,7 @@ impl PositioningHandler { &mut self, common: &mut CallbackDataCommon, key: &str, - ) -> Box { + ) -> Box { self.change_highlight(common, key); let pos = key_to_pos(key); diff --git a/wlx-overlay-s/src/overlays/mirror.rs b/wlx-overlay-s/src/overlays/mirror.rs index 544686b..0882425 100644 --- a/wlx-overlay-s/src/overlays/mirror.rs +++ b/wlx-overlay-s/src/overlays/mirror.rs @@ -11,7 +11,7 @@ use wlx_common::windowing::OverlayWindowState; use crate::{ backend::{ input::{HoverResult, PointerHit}, - task::TaskType, + task::{OverlayTask, TaskType}, }, state::{AppSession, AppState}, subsystem::hid::WheelDelta, @@ -73,21 +73,21 @@ impl OverlayBackend for MirrorBackend { let capture = PipewireCapture::new(self.name.clone(), node_id); self.renderer = Some(ScreenBackend::new_raw(self.name.clone(), Box::new(capture))); - app.tasks.enqueue(TaskType::Overlay( + app.tasks.enqueue(TaskType::Overlay(OverlayTask::Modify( OverlaySelector::Name(self.name.clone()), Box::new(|app, o| { o.activate(app); }), - )); + ))); } Err(e) => { log::warn!("Failed to create mirror due to PipeWire error: {e:?}"); self.renderer = None; // drop self app.tasks - .enqueue(TaskType::DropOverlay(OverlaySelector::Name( + .enqueue(TaskType::Overlay(OverlayTask::Drop(OverlaySelector::Name( self.name.clone(), - ))); + )))); } } } diff --git a/wlx-overlay-s/src/overlays/toast.rs b/wlx-overlay-s/src/overlays/toast.rs index 59a880a..04954e9 100644 --- a/wlx-overlay-s/src/overlays/toast.rs +++ b/wlx-overlay-s/src/overlays/toast.rs @@ -5,7 +5,7 @@ use std::{ time::Instant, }; -use glam::{Affine3A, Quat, Vec3, vec3}; +use glam::{vec3, Affine3A, Quat, Vec3}; use wgui::{ i18n::Translation, parser::parse_color_hex, @@ -27,10 +27,10 @@ use wlx_common::{ }; use crate::{ - backend::task::TaskType, + backend::task::{OverlayTask, TaskType}, gui::panel::GuiPanel, state::AppState, - windowing::{OverlaySelector, Z_ORDER_TOAST, window::OverlayWindowConfig}, + windowing::{window::OverlayWindowConfig, OverlaySelector, Z_ORDER_TOAST}, }; const FONT_SIZE: isize = 16; @@ -86,27 +86,29 @@ impl Toast { // drop any toast that was created before us. // (DropOverlay only drops overlays that were // created before current frame) - app.tasks - .enqueue_at(TaskType::DropOverlay(selector.clone()), instant); + app.tasks.enqueue_at( + TaskType::Overlay(OverlayTask::Drop(selector.clone())), + instant, + ); // CreateOverlay only creates the overlay if // the selector doesn't exist yet, so in case // multiple toasts are submitted for the same // frame, only the first one gets created app.tasks.enqueue_at( - TaskType::CreateOverlay( + TaskType::Overlay(OverlayTask::Create( selector.clone(), Box::new(move |app| { let maybe_toast = new_toast(self, app); app.tasks.enqueue_at( // at timeout, drop the overlay by ID instead // in order to avoid dropping any newer toasts - TaskType::DropOverlay(selector), + TaskType::Overlay(OverlayTask::Drop(selector)), destroy_at, ); maybe_toast }), - ), + )), instant, ); } diff --git a/wlx-overlay-s/src/overlays/watch.rs b/wlx-overlay-s/src/overlays/watch.rs index 4623190..b472ac5 100644 --- a/wlx-overlay-s/src/overlays/watch.rs +++ b/wlx-overlay-s/src/overlays/watch.rs @@ -14,26 +14,26 @@ use wgui::{ parser::Fetchable, renderer_vk::text::custom_glyph::CustomGlyphData, taffy, - widget::{EventResult, sprite::WidgetSprite}, + widget::{sprite::WidgetSprite, EventResult}, }; use wlx_common::windowing::{OverlayWindowState, Positioning}; use crate::{ backend::{ input::TrackedDeviceRole, - task::{ManagerTask, TaskType}, + task::{OverlayTask, TaskType}, }, gui::{ - panel::{GuiPanel, NewGuiPanelParams, OnCustomAttribFunc, button::BUTTON_EVENTS}, + panel::{button::BUTTON_EVENTS, GuiPanel, NewGuiPanelParams, OnCustomAttribFunc}, timer::GuiTimer, }, overlays::edit::LongPressButtonState, state::AppState, windowing::{ - OverlaySelector, Z_ORDER_WATCH, backend::{OverlayEventData, OverlayMeta}, manager::MAX_OVERLAY_SETS, window::{OverlayWindowConfig, OverlayWindowData}, + OverlaySelector, Z_ORDER_WATCH, }, }; @@ -81,11 +81,11 @@ pub fn create_watch(app: &mut AppState) -> anyhow::Result { return Ok(EventResult::Consumed); } app.tasks - .enqueue(TaskType::Manager(ManagerTask::DeleteActiveSet)); + .enqueue(TaskType::Overlay(OverlayTask::DeleteActiveSet)); Ok(EventResult::Consumed) }), "::EditModeAddSet" => Box::new(move |_common, _data, app, _state| { - app.tasks.enqueue(TaskType::Manager(ManagerTask::AddSet)); + app.tasks.enqueue(TaskType::Overlay(OverlayTask::AddSet)); Ok(EventResult::Consumed) }), "::EditModeOverlayToggle" => { @@ -100,7 +100,7 @@ pub fn create_watch(app: &mut AppState) -> anyhow::Result { return Ok(EventResult::Consumed); }; - app.tasks.enqueue(TaskType::Overlay( + app.tasks.enqueue(TaskType::Overlay(OverlayTask::Modify( OverlaySelector::Id(overlay.id), Box::new(move |app, owc| { if owc.active_state.is_none() { @@ -109,7 +109,7 @@ pub fn create_watch(app: &mut AppState) -> anyhow::Result { owc.deactivate(); } }), - )); + ))); Ok(EventResult::Consumed) }) } diff --git a/wlx-overlay-s/src/overlays/wayvr.rs b/wlx-overlay-s/src/overlays/wayvr.rs index f491c27..fe16bf3 100644 --- a/wlx-overlay-s/src/overlays/wayvr.rs +++ b/wlx-overlay-s/src/overlays/wayvr.rs @@ -19,7 +19,7 @@ use wlx_common::windowing::OverlayWindowState; use crate::{ backend::{ input::{self, HoverResult}, - task::TaskType, + task::{OverlayTask, TaskType}, wayvr::{ self, display, server_ipc::{gen_args_vec, gen_env_vec}, @@ -332,12 +332,12 @@ where WvrStateChanged::DashboardHidden })); - app.tasks.enqueue(TaskType::Overlay( + app.tasks.enqueue(TaskType::Overlay(OverlayTask::Modify( OverlaySelector::Id(overlay_id), Box::new(move |app, o| { o.toggle(app); }), - )); + ))); Ok(()) } @@ -429,12 +429,12 @@ where .data .state .set_display_visible(display_handle, visible); - app.tasks.enqueue(TaskType::Overlay( + app.tasks.enqueue(TaskType::Overlay(OverlayTask::Modify( OverlaySelector::Id(overlay_id), Box::new(move |app, o| { o.toggle(app); }), - )); + ))); } } wayvr::WayVRSignal::DisplayWindowLayout(display_handle, layout) => { @@ -448,7 +448,9 @@ where } wayvr::WayVRSignal::DropOverlay(overlay_id) => { app.tasks - .enqueue(TaskType::DropOverlay(OverlaySelector::Id(overlay_id))); + .enqueue(TaskType::Overlay(OverlayTask::Drop(OverlaySelector::Id( + overlay_id, + )))); } wayvr::WayVRSignal::Haptics(haptics) => { wayvr.pending_haptics = Some(haptics); diff --git a/wlx-overlay-s/src/windowing/manager.rs b/wlx-overlay-s/src/windowing/manager.rs index 20569ef..d0bf32e 100644 --- a/wlx-overlay-s/src/windowing/manager.rs +++ b/wlx-overlay-s/src/windowing/manager.rs @@ -1,11 +1,14 @@ -use std::collections::HashMap; +use std::{ + collections::{HashMap, VecDeque}, + sync::atomic::Ordering, +}; use glam::{Affine3A, Vec3, Vec3A}; use slotmap::{HopSlotMap, Key, SecondaryMap}; use wlx_common::{config::SerializedWindowSet, overlays::ToastTopic}; use crate::{ - backend::task::ManagerTask, + backend::task::OverlayTask, overlays::{ anchor::create_anchor, edit::EditWrapperManager, keyboard::builder::create_keyboard, screen::create_screens, toast::Toast, watch::create_watch, @@ -18,6 +21,7 @@ use crate::{ window::{OverlayCategory, OverlayWindowData}, OverlayID, OverlaySelector, }, + FRAME_COUNTER, }; pub const MAX_OVERLAY_SETS: usize = 7; @@ -34,6 +38,7 @@ pub struct OverlayWindowManager { anchor_local: Affine3A, watch_id: OverlayID, edit_mode: bool, + dropped_overlays: VecDeque>, } impl OverlayWindowManager @@ -52,6 +57,7 @@ where anchor_local: Affine3A::from_translation(Vec3::NEG_Z), watch_id: OverlayID::null(), // set down below edit_mode: false, + dropped_overlays: VecDeque::with_capacity(8), }; if headless { @@ -119,9 +125,104 @@ where Ok(me) } + + pub fn handle_task(&mut self, app: &mut AppState, task: OverlayTask) -> anyhow::Result<()> { + match task { + OverlayTask::ShowHide => self.show_hide(app), + OverlayTask::ToggleSet(set) => { + self.switch_or_toggle_set(app, set); + } + OverlayTask::ToggleEditMode => { + self.set_edit_mode(!self.edit_mode, app)?; + } + OverlayTask::AddSet => { + self.sets.push(OverlayWindowSet::default()); + let len = self.sets.len(); + if let Some(watch) = self.mut_by_id(self.watch_id) { + watch + .config + .backend + .notify(app, OverlayEventData::NumSetsChanged(len))?; + } + } + OverlayTask::DeleteActiveSet => { + let Some(set) = self.current_set else { + Toast::new( + ToastTopic::System, + "Can't remove set".into(), + "No set is selected!".into(), + ) + .with_timeout(5.) + .with_sound(true) + .submit(app); + return Ok(()); + }; + + if self.sets.len() <= 1 { + Toast::new( + ToastTopic::System, + "Can't remove set".into(), + "This is the last existing set!".into(), + ) + .with_timeout(5.) + .with_sound(true) + .submit(app); + return Ok(()); + } + + self.switch_to_set(app, None); + self.sets.remove(set); + let len = self.sets.len(); + if let Some(watch) = self.mut_by_id(self.watch_id) { + watch + .config + .backend + .notify(app, OverlayEventData::NumSetsChanged(len))?; + } + } + OverlayTask::Modify(sel, f) => { + if let Some(o) = self.mut_by_selector(&sel) { + f(app, &mut o.config); + } else { + log::warn!("Overlay not found for task: {sel:?}"); + } + } + OverlayTask::Create(sel, f) => { + let None = self.mut_by_selector(&sel) else { + return Ok(()); + }; + + let Some(overlay_config) = f(app) else { + return Ok(()); + }; + + self.add( + OverlayWindowData { + birthframe: FRAME_COUNTER.load(Ordering::Relaxed), + ..OverlayWindowData::from_config(overlay_config) + }, + app, + ); + } + OverlayTask::Drop(sel) => { + if let Some(o) = self.mut_by_selector(&sel) + && o.birthframe < FRAME_COUNTER.load(Ordering::Relaxed) + { + if let Some(o) = self.remove_by_selector(&sel, app) { + self.dropped_overlays.push_back(o); + } + } + } + } + Ok(()) + } } impl OverlayWindowManager { + pub fn pop_dropped(&mut self) -> Option> { + self.dropped_overlays.pop_front() + } + pub fn persist_layout(&mut self, app: &mut AppState) { app.session.config.sets.clear(); app.session.config.sets.reserve(self.sets.len()); @@ -390,65 +491,6 @@ impl OverlayWindowManager { self.mut_by_id(self.watch_id).unwrap().config.activate(app); } - pub fn handle_task(&mut self, app: &mut AppState, task: ManagerTask) -> anyhow::Result<()> { - match task { - ManagerTask::ShowHide => self.show_hide(app), - ManagerTask::ToggleSet(set) => { - self.switch_or_toggle_set(app, set); - } - ManagerTask::ToggleEditMode => { - self.set_edit_mode(!self.edit_mode, app)?; - } - ManagerTask::AddSet => { - self.sets.push(OverlayWindowSet::default()); - let len = self.sets.len(); - if let Some(watch) = self.mut_by_id(self.watch_id) { - watch - .config - .backend - .notify(app, OverlayEventData::NumSetsChanged(len))?; - } - } - ManagerTask::DeleteActiveSet => { - let Some(set) = self.current_set else { - Toast::new( - ToastTopic::System, - "Can't remove set".into(), - "No set is selected!".into(), - ) - .with_timeout(5.) - .with_sound(true) - .submit(app); - return Ok(()); - }; - - if self.sets.len() <= 1 { - Toast::new( - ToastTopic::System, - "Can't remove set".into(), - "This is the last existing set!".into(), - ) - .with_timeout(5.) - .with_sound(true) - .submit(app); - return Ok(()); - } - - self.switch_to_set(app, None); - self.sets.remove(set); - let len = self.sets.len(); - if let Some(watch) = self.mut_by_id(self.watch_id) { - watch - .config - .backend - .notify(app, OverlayEventData::NumSetsChanged(len))?; - } - } - } - - Ok(()) - } - fn overlays_changed(&mut self, app: &mut AppState) -> anyhow::Result<()> { let mut meta = Vec::with_capacity(self.overlays.len()); for (id, data) in &self.overlays {