From 9425db9ae4607e9b0c666a7aaaec58014a253edd Mon Sep 17 00:00:00 2001 From: galister <22305755+galister@users.noreply.github.com> Date: Sun, 28 Dec 2025 18:44:58 +0000 Subject: [PATCH] generics + DashInterface impl (#334) --- dash-frontend/src/frontend.rs | 31 +++-- dash-frontend/src/tab/apps.rs | 24 ++-- dash-frontend/src/tab/games.rs | 19 ++- dash-frontend/src/tab/home.rs | 16 ++- dash-frontend/src/tab/mod.rs | 4 +- dash-frontend/src/tab/monado.rs | 16 ++- dash-frontend/src/tab/processes.rs | 18 +-- dash-frontend/src/tab/settings.rs | 25 ++-- dash-frontend/src/util/popup_manager.rs | 4 - dash-frontend/src/views/app_launcher.rs | 38 +++--- dash-frontend/src/views/process_list.rs | 27 +++-- dash-frontend/src/views/window_list.rs | 62 ++++++---- dash-frontend/src/views/window_options.rs | 39 +++--- wlx-common/src/dash_interface.rs | 20 ++-- wlx-common/src/dash_interface_emulated.rs | 18 +-- wlx-overlay-s/src/backend/wayvr/mod.rs | 4 + wlx-overlay-s/src/overlays/dashboard.rs | 139 ++++++++++++++++++++-- 17 files changed, 348 insertions(+), 156 deletions(-) diff --git a/dash-frontend/src/frontend.rs b/dash-frontend/src/frontend.rs index d8f1b73..6e4e555 100644 --- a/dash-frontend/src/frontend.rs +++ b/dash-frontend/src/frontend.rs @@ -38,12 +38,12 @@ pub struct FrontendWidgets { pub type FrontendTasks = Tasks; -pub struct Frontend { +pub struct Frontend { pub layout: Layout, globals: WguiGlobals, pub settings: Box, - pub interface: BoxDashInterface, + pub interface: BoxDashInterface, // async runtime executor pub executor: AsyncExecutor, @@ -51,7 +51,7 @@ pub struct Frontend { #[allow(dead_code)] state: ParserState, - current_tab: Option>, + current_tab: Option>>, pub tasks: FrontendTasks, @@ -68,9 +68,9 @@ pub struct Frontend { pub(crate) desktop_finder: DesktopFinder, } -pub struct InitParams { +pub struct InitParams { pub settings: Box, - pub interface: BoxDashInterface, + pub interface: BoxDashInterface, } #[derive(Clone)] @@ -86,8 +86,8 @@ pub enum FrontendTask { PushToast(Translation), } -impl Frontend { - pub fn new(params: InitParams) -> anyhow::Result { +impl Frontend { + pub fn new(params: InitParams) -> anyhow::Result> { let mut assets = Box::new(assets::Asset {}); let font_binary_bold = assets.load_from_path_gzip("Quicksand-Bold.ttf.gz")?; @@ -164,15 +164,15 @@ impl Frontend { Ok(frontend) } - pub fn update(&mut self, width: f32, height: f32, timestep_alpha: f32) -> anyhow::Result<()> { + pub fn update(&mut self, data: &mut T, width: f32, height: f32, timestep_alpha: f32) -> anyhow::Result<()> { let mut tasks = self.tasks.drain(); while let Some(task) = tasks.pop_front() { - self.process_task(task)?; + self.process_task(data, task)?; } if let Some(mut tab) = self.current_tab.take() { - tab.update(self)?; + tab.update(self, data)?; self.current_tab = Some(tab); } @@ -237,7 +237,6 @@ impl Frontend { self.globals.clone(), self.settings.as_ref(), &mut self.layout, - &mut self.interface, self.tasks.clone(), params, )?; @@ -273,7 +272,7 @@ impl Frontend { Ok(()) } - fn process_task(&mut self, task: FrontendTask) -> anyhow::Result<()> { + fn process_task(&mut self, data: &mut T, task: FrontendTask) -> anyhow::Result<()> { match task { FrontendTask::SetTab(tab_type) => self.set_tab(tab_type)?, FrontendTask::RefreshClock => self.update_time()?, @@ -282,7 +281,7 @@ impl Frontend { FrontendTask::RefreshPopupManager => self.refresh_popup_manager()?, FrontendTask::ShowAudioSettings => self.action_show_audio_settings()?, FrontendTask::UpdateAudioSettingsView => self.action_update_audio_settings()?, - FrontendTask::RecenterPlayspace => self.action_recenter_playspace()?, + FrontendTask::RecenterPlayspace => self.action_recenter_playspace(data)?, FrontendTask::PushToast(content) => self.toast_manager.push(content), }; Ok(()) @@ -293,7 +292,7 @@ impl Frontend { let widget_content = self.state.fetch_widget(&self.layout.state, "content")?; self.layout.remove_children(widget_content.id); - let tab: Box = match tab_type { + let tab: Box> = match tab_type { TabType::Home => Box::new(TabHome::new(self, widget_content.id)?), TabType::Apps => Box::new(TabApps::new(self, widget_content.id)?), TabType::Games => Box::new(TabGames::new(self, widget_content.id)?), @@ -407,8 +406,8 @@ impl Frontend { Ok(()) } - fn action_recenter_playspace(&mut self) -> anyhow::Result<()> { - self.interface.recenter_playspace()?; + fn action_recenter_playspace(&mut self, data: &mut T) -> anyhow::Result<()> { + self.interface.recenter_playspace(data)?; Ok(()) } } diff --git a/dash-frontend/src/tab/apps.rs b/dash-frontend/src/tab/apps.rs index 24344b2..1d1cc5d 100644 --- a/dash-frontend/src/tab/apps.rs +++ b/dash-frontend/src/tab/apps.rs @@ -1,4 +1,4 @@ -use std::{cell::RefCell, collections::HashMap, rc::Rc}; +use std::{cell::RefCell, collections::HashMap, marker::PhantomData, rc::Rc}; use wgui::{ assets::AssetPath, @@ -28,7 +28,7 @@ struct State { view_launcher: Option<(PopupHandle, views::app_launcher::View)>, } -pub struct TabApps { +pub struct TabApps { #[allow(dead_code)] parser_state: ParserState, @@ -36,14 +36,15 @@ pub struct TabApps { entries: Vec, app_list: AppList, tasks: Tasks, + marker: PhantomData, } -impl Tab for TabApps { +impl Tab for TabApps { fn get_type(&self) -> TabType { TabType::Apps } - fn update(&mut self, frontend: &mut Frontend) -> anyhow::Result<()> { + fn update(&mut self, frontend: &mut Frontend, data: &mut T) -> anyhow::Result<()> { let mut state = self.state.borrow_mut(); for task in self.tasks.drain() { @@ -53,7 +54,7 @@ impl Tab for TabApps { } if let Some((_, launcher)) = &mut state.view_launcher { - launcher.update(&mut frontend.layout, &mut frontend.interface)?; + launcher.update(&mut frontend.layout, &mut frontend.interface, data)?; } Ok(()) } @@ -108,8 +109,8 @@ fn on_app_click( }) } -impl TabApps { - pub fn new(frontend: &mut Frontend, parent_id: WidgetID) -> anyhow::Result { +impl TabApps { + pub fn new(frontend: &mut Frontend, parent_id: WidgetID) -> anyhow::Result { let doc_params = &ParseDocumentParams { globals: frontend.layout.state.globals.clone(), path: AssetPath::BuiltIn("gui/tab/apps.xml"), @@ -151,14 +152,15 @@ impl TabApps { entries, state, tasks, + marker: PhantomData, }) } } impl AppList { - fn mount_entry( + fn mount_entry( &mut self, - frontend: &mut Frontend, + frontend: &mut Frontend, parser_state: &mut ParserState, doc_params: &ParseDocumentParams, list_parent: &WidgetPair, @@ -197,9 +199,9 @@ impl AppList { data.fetch_component_as::("button") } - fn mount_entries( + fn mount_entries( &mut self, - frontend: &mut Frontend, + frontend: &mut Frontend, entries: &[DesktopEntry], parser_state: &mut ParserState, doc_params: &ParseDocumentParams, diff --git a/dash-frontend/src/tab/games.rs b/dash-frontend/src/tab/games.rs index f09742d..a757803 100644 --- a/dash-frontend/src/tab/games.rs +++ b/dash-frontend/src/tab/games.rs @@ -1,3 +1,5 @@ +use std::marker::PhantomData; + use wgui::{ assets::AssetPath, layout::WidgetID, @@ -10,26 +12,27 @@ use crate::{ views::game_list, }; -pub struct TabGames { +pub struct TabGames { #[allow(dead_code)] pub state: ParserState, view_game_list: game_list::View, + marker: PhantomData, } -impl Tab for TabGames { +impl Tab for TabGames { fn get_type(&self) -> TabType { TabType::Games } - fn update(&mut self, frontend: &mut Frontend) -> anyhow::Result<()> { + fn update(&mut self, frontend: &mut Frontend, _data: &mut T) -> anyhow::Result<()> { self.view_game_list.update(&mut frontend.layout, &frontend.executor)?; Ok(()) } } -impl TabGames { - pub fn new(frontend: &mut Frontend, parent_id: WidgetID) -> anyhow::Result { +impl TabGames { + pub fn new(frontend: &mut Frontend, parent_id: WidgetID) -> anyhow::Result { let state = wgui::parser::parse_from_assets( &ParseDocumentParams { globals: frontend.layout.state.globals.clone(), @@ -50,6 +53,10 @@ impl TabGames { parent_id: game_list_parent, })?; - Ok(Self { state, view_game_list }) + Ok(Self { + state, + view_game_list, + marker: PhantomData, + }) } } diff --git a/dash-frontend/src/tab/home.rs b/dash-frontend/src/tab/home.rs index d3d5d2f..06dff10 100644 --- a/dash-frontend/src/tab/home.rs +++ b/dash-frontend/src/tab/home.rs @@ -1,3 +1,5 @@ +use std::marker::PhantomData; + use wgui::{ assets::AssetPath, components::button::ComponentButton, @@ -15,12 +17,13 @@ use crate::{ various, }; -pub struct TabHome { +pub struct TabHome { #[allow(dead_code)] pub state: ParserState, + marker: PhantomData, } -impl Tab for TabHome { +impl Tab for TabHome { fn get_type(&self) -> TabType { TabType::Home } @@ -44,8 +47,8 @@ fn configure_label_hello(common: &mut CallbackDataCommon, label_hello: Widget, s label_hello.set_text(common, Translation::from_raw_text(&translated)); } -impl TabHome { - pub fn new(frontend: &mut Frontend, parent_id: WidgetID) -> anyhow::Result { +impl TabHome { + pub fn new(frontend: &mut Frontend, parent_id: WidgetID) -> anyhow::Result { let state = wgui::parser::parse_from_assets( &ParseDocumentParams { globals: frontend.layout.state.globals.clone(), @@ -73,6 +76,9 @@ impl TabHome { tasks.handle_button(&btn_processes, FrontendTask::SetTab(TabType::Processes)); tasks.handle_button(&btn_settings, FrontendTask::SetTab(TabType::Settings)); - Ok(Self { state }) + Ok(Self { + state, + marker: PhantomData, + }) } } diff --git a/dash-frontend/src/tab/mod.rs b/dash-frontend/src/tab/mod.rs index c2b88df..7f26ca1 100644 --- a/dash-frontend/src/tab/mod.rs +++ b/dash-frontend/src/tab/mod.rs @@ -17,11 +17,11 @@ pub enum TabType { Settings, } -pub trait Tab { +pub trait Tab { #[allow(dead_code)] fn get_type(&self) -> TabType; - fn update(&mut self, _: &mut Frontend) -> anyhow::Result<()> { + fn update(&mut self, _: &mut Frontend, _: &mut T) -> anyhow::Result<()> { Ok(()) } } diff --git a/dash-frontend/src/tab/monado.rs b/dash-frontend/src/tab/monado.rs index f2e0735..f6cdd93 100644 --- a/dash-frontend/src/tab/monado.rs +++ b/dash-frontend/src/tab/monado.rs @@ -1,3 +1,5 @@ +use std::marker::PhantomData; + use wgui::{ assets::AssetPath, layout::WidgetID, @@ -9,19 +11,20 @@ use crate::{ tab::{Tab, TabType}, }; -pub struct TabMonado { +pub struct TabMonado { #[allow(dead_code)] pub state: ParserState, + marker: PhantomData, } -impl Tab for TabMonado { +impl Tab for TabMonado { fn get_type(&self) -> TabType { TabType::Games } } -impl TabMonado { - pub fn new(frontend: &mut Frontend, parent_id: WidgetID) -> anyhow::Result { +impl TabMonado { + pub fn new(frontend: &mut Frontend, parent_id: WidgetID) -> anyhow::Result { let state = wgui::parser::parse_from_assets( &ParseDocumentParams { globals: frontend.layout.state.globals.clone(), @@ -32,6 +35,9 @@ impl TabMonado { parent_id, )?; - Ok(Self { state }) + Ok(Self { + state, + marker: PhantomData, + }) } } diff --git a/dash-frontend/src/tab/processes.rs b/dash-frontend/src/tab/processes.rs index 1c85b2c..c0447af 100644 --- a/dash-frontend/src/tab/processes.rs +++ b/dash-frontend/src/tab/processes.rs @@ -1,3 +1,5 @@ +use std::marker::PhantomData; + use wgui::{ assets::AssetPath, layout::WidgetID, @@ -10,32 +12,33 @@ use crate::{ views::{process_list, window_list}, }; -pub struct TabProcesses { +pub struct TabProcesses { #[allow(dead_code)] pub state: ParserState, view_window_list: window_list::View, view_process_list: process_list::View, + marker: PhantomData, } -impl Tab for TabProcesses { +impl Tab for TabProcesses { fn get_type(&self) -> TabType { TabType::Games } - fn update(&mut self, frontend: &mut Frontend) -> anyhow::Result<()> { + fn update(&mut self, frontend: &mut Frontend, data: &mut T) -> anyhow::Result<()> { self .view_window_list - .update(&mut frontend.layout, &mut frontend.interface)?; + .update(&mut frontend.layout, &mut frontend.interface, data)?; self .view_process_list - .update(&mut frontend.layout, &mut frontend.interface)?; + .update(&mut frontend.layout, &mut frontend.interface, data)?; Ok(()) } } -impl TabProcesses { - pub fn new(frontend: &mut Frontend, parent_id: WidgetID) -> anyhow::Result { +impl TabProcesses { + pub fn new(frontend: &mut Frontend, parent_id: WidgetID) -> anyhow::Result { let globals = frontend.layout.state.globals.clone(); let state = wgui::parser::parse_from_assets( &ParseDocumentParams { @@ -61,6 +64,7 @@ impl TabProcesses { globals, })?, state, + marker: PhantomData, }) } } diff --git a/dash-frontend/src/tab/settings.rs b/dash-frontend/src/tab/settings.rs index 49d6e63..8fa5898 100644 --- a/dash-frontend/src/tab/settings.rs +++ b/dash-frontend/src/tab/settings.rs @@ -1,4 +1,4 @@ -use std::rc::Rc; +use std::{marker::PhantomData, rc::Rc}; use wgui::{ assets::AssetPath, @@ -18,19 +18,20 @@ enum Task { ToggleSetting(SettingType, bool), } -pub struct TabSettings { +pub struct TabSettings { #[allow(dead_code)] pub state: ParserState, tasks: Tasks, + marker: PhantomData, } -impl Tab for TabSettings { +impl Tab for TabSettings { fn get_type(&self) -> TabType { TabType::Settings } - fn update(&mut self, frontend: &mut Frontend) -> anyhow::Result<()> { + fn update(&mut self, frontend: &mut Frontend, _data: &mut T) -> anyhow::Result<()> { for task in self.tasks.drain() { match task { Task::ToggleSetting(setting, n) => self.toggle_setting(frontend, setting, n), @@ -60,8 +61,8 @@ impl SettingType { } } -fn init_setting_checkbox( - frontend: &mut Frontend, +fn init_setting_checkbox( + frontend: &mut Frontend, tasks: &Tasks, checkbox: Rc, setting: SettingType, @@ -86,8 +87,8 @@ fn init_setting_checkbox( Ok(()) } -impl TabSettings { - pub fn new(frontend: &mut Frontend, parent_id: WidgetID) -> anyhow::Result { +impl TabSettings { + pub fn new(frontend: &mut Frontend, parent_id: WidgetID) -> anyhow::Result { let state = wgui::parser::parse_from_assets( &ParseDocumentParams { globals: frontend.layout.state.globals.clone(), @@ -136,10 +137,14 @@ impl TabSettings { None, )?; - Ok(Self { state, tasks }) + Ok(Self { + state, + tasks, + marker: PhantomData, + }) } - fn toggle_setting(&mut self, frontend: &mut Frontend, setting: SettingType, state: bool) { + fn toggle_setting(&mut self, frontend: &mut Frontend, setting: SettingType, state: bool) { *setting.get_bool(frontend.settings.get_mut()) = state; } } diff --git a/dash-frontend/src/util/popup_manager.rs b/dash-frontend/src/util/popup_manager.rs index 3f5c922..95b63ec 100644 --- a/dash-frontend/src/util/popup_manager.rs +++ b/dash-frontend/src/util/popup_manager.rs @@ -14,7 +14,6 @@ use wgui::{ taffy::Display, widget::label::WidgetLabel, }; -use wlx_common::dash_interface::BoxDashInterface; use crate::{ frontend::{FrontendTask, FrontendTasks}, @@ -61,7 +60,6 @@ pub struct PopupContentFuncData<'a> { pub layout: &'a mut Layout, pub settings: &'a dyn SettingsIO, pub handle: PopupHandle, - pub interface: &'a mut BoxDashInterface, pub id_content: WidgetID, } @@ -127,7 +125,6 @@ impl PopupManager { globals: WguiGlobals, settings: &dyn SettingsIO, layout: &mut Layout, - interface: &mut BoxDashInterface, frontend_tasks: FrontendTasks, params: MountPopupParams, ) -> anyhow::Result<()> { @@ -184,7 +181,6 @@ impl PopupManager { handle: popup_handle.clone(), id_content, settings, - interface, })?; Ok(()) diff --git a/dash-frontend/src/views/app_launcher.rs b/dash-frontend/src/views/app_launcher.rs index 8fd82d7..f8b6731 100644 --- a/dash-frontend/src/views/app_launcher.rs +++ b/dash-frontend/src/views/app_launcher.rs @@ -31,12 +31,13 @@ enum Task { Launch, } -struct LaunchParams<'a> { +struct LaunchParams<'a, T> { application: &'a DesktopEntry, run_mode: RunMode, globals: &'a WguiGlobals, frontend_tasks: &'a FrontendTasks, - interface: &'a mut BoxDashInterface, + interface: &'a mut BoxDashInterface, + data: &'a mut T, on_launched: &'a dyn Fn(), } @@ -157,7 +158,12 @@ impl View { }) } - pub fn update(&mut self, layout: &mut Layout, interface: &mut BoxDashInterface) -> anyhow::Result<()> { + pub fn update( + &mut self, + layout: &mut Layout, + interface: &mut BoxDashInterface, + data: &mut T, + ) -> anyhow::Result<()> { loop { let tasks = self.tasks.drain(); if tasks.is_empty() { @@ -166,7 +172,7 @@ impl View { for task in tasks { match task { Task::SetRunMode(run_mode) => self.action_set_run_mode(layout, run_mode)?, - Task::Launch => self.action_launch(interface), + Task::Launch => self.action_launch(interface, data), } } } @@ -188,18 +194,19 @@ impl View { Ok(()) } - fn action_launch(&mut self, interface: &mut BoxDashInterface) { + fn action_launch(&mut self, interface: &mut BoxDashInterface, data: &mut T) { View::try_launch(LaunchParams { application: &self.entry, frontend_tasks: &self.frontend_tasks, globals: &self.globals, run_mode: self.run_mode.clone(), interface, + data, on_launched: &self.on_launched, }); } - fn try_launch(params: LaunchParams) { + fn try_launch(params: LaunchParams) { let globals = params.globals.clone(); let frontend_tasks = params.frontend_tasks.clone(); @@ -213,7 +220,7 @@ impl View { )))); } - fn launch(params: LaunchParams) -> anyhow::Result<()> { + fn launch(params: LaunchParams) -> anyhow::Result<()> { let mut env = Vec::::new(); if params.run_mode == RunMode::Wayland { @@ -238,13 +245,16 @@ impl View { let mut userdata = HashMap::new(); userdata.insert("desktop-entry".to_string(), serde_json::to_string(params.application)?); - params.interface.process_launch(WvrProcessLaunchParams { - env, - exec, - name: params.application.app_name.to_string(), - args, - userdata, - })?; + params.interface.process_launch( + params.data, + WvrProcessLaunchParams { + env, + exec, + name: params.application.app_name.to_string(), + args, + userdata, + }, + )?; params .frontend_tasks diff --git a/dash-frontend/src/views/process_list.rs b/dash-frontend/src/views/process_list.rs index 4d831d6..4be9746 100644 --- a/dash-frontend/src/views/process_list.rs +++ b/dash-frontend/src/views/process_list.rs @@ -71,7 +71,12 @@ impl View { }) } - pub fn update(&mut self, layout: &mut Layout, interface: &mut BoxDashInterface) -> anyhow::Result<()> { + pub fn update( + &mut self, + layout: &mut Layout, + interface: &mut BoxDashInterface, + data: &mut T, + ) -> anyhow::Result<()> { loop { let tasks = self.tasks.drain(); if tasks.is_empty() { @@ -79,8 +84,8 @@ impl View { } for task in tasks { match task { - Task::Refresh => self.refresh(layout, interface)?, - Task::TerminateProcess(process) => self.action_terminate_process(interface, process)?, + Task::Refresh => self.refresh(layout, interface, data)?, + Task::TerminateProcess(process) => self.action_terminate_process(interface, data, process)?, } } } @@ -196,11 +201,16 @@ fn fill_process_list( } impl View { - fn refresh(&mut self, layout: &mut Layout, interface: &mut BoxDashInterface) -> anyhow::Result<()> { + fn refresh( + &mut self, + layout: &mut Layout, + interface: &mut BoxDashInterface, + data: &mut T, + ) -> anyhow::Result<()> { layout.remove_children(self.id_list_parent); let mut text: Option = None; - match interface.process_list() { + match interface.process_list(data) { Ok(list) => { if list.is_empty() { text = Some(Translation::from_translation_key("PROCESS_LIST.NO_PROCESSES_FOUND")) @@ -236,12 +246,13 @@ impl View { Ok(()) } - fn action_terminate_process( + fn action_terminate_process( &mut self, - interface: &mut BoxDashInterface, + interface: &mut BoxDashInterface, + data: &mut T, process: packet_server::WvrProcess, ) -> anyhow::Result<()> { - interface.process_terminate(process.handle)?; + interface.process_terminate(data, process.handle)?; self.tasks.push(Task::Refresh); Ok(()) } diff --git a/dash-frontend/src/views/window_list.rs b/dash-frontend/src/views/window_list.rs index 24da35f..12d0392 100644 --- a/dash-frontend/src/views/window_list.rs +++ b/dash-frontend/src/views/window_list.rs @@ -12,8 +12,8 @@ use wgui::{ taffy::{self, prelude::length}, task::Tasks, widget::{ - ConstructEssentials, label::{WidgetLabel, WidgetLabelParams}, + ConstructEssentials, }, }; use wlx_common::dash_interface::BoxDashInterface; @@ -84,7 +84,12 @@ impl View { }) } - pub fn update(&mut self, layout: &mut Layout, interface: &mut BoxDashInterface) -> anyhow::Result<()> { + pub fn update( + &mut self, + layout: &mut Layout, + interface: &mut BoxDashInterface, + data: &mut T, + ) -> anyhow::Result<()> { loop { let tasks = self.tasks.drain(); if tasks.is_empty() { @@ -94,23 +99,24 @@ impl View { match task { Task::WindowClicked(display) => self.action_window_clicked(display)?, Task::WindowOptionsFinish => self.action_window_options_finish(), - Task::Refresh => self.refresh(layout, interface)?, + Task::Refresh => self.refresh(layout, interface, data)?, } } } let mut state = self.state.borrow_mut(); if let Some((_, view)) = &mut state.view_window_options { - view.update(layout, interface)?; + view.update(layout, interface, data)?; } Ok(()) } } -pub fn construct_window_button( +pub fn construct_window_button( ess: &mut ConstructEssentials, - interface: &mut BoxDashInterface, + interface: &mut BoxDashInterface, + data: &mut T, globals: &WguiGlobals, window: &packet_server::WvrWindow, ) -> anyhow::Result<(WidgetPair, Rc)> { @@ -137,7 +143,7 @@ pub fn construct_window_button( }, )?; - let process_name = match interface.process_get(window.process_handle.clone()) { + let process_name = match interface.process_get(data, window.process_handle.clone()) { Some(process) => process.name.clone(), None => String::from("Unknown"), }; @@ -171,15 +177,16 @@ pub fn construct_window_button( Ok((widget_button, button)) } -fn fill_window_list( +fn fill_window_list( globals: &WguiGlobals, ess: &mut ConstructEssentials, - interface: &mut BoxDashInterface, + interface: &mut BoxDashInterface, + data: &mut T, list: Vec, tasks: &Tasks, ) -> anyhow::Result<()> { for entry in list { - let (_, button) = construct_window_button(ess, interface, globals, &entry)?; + let (_, button) = construct_window_button(ess, interface, data, globals, &entry)?; button.on_click({ let tasks = tasks.clone(); @@ -199,11 +206,16 @@ impl View { self.tasks.push(Task::Refresh); } - fn refresh(&mut self, layout: &mut Layout, interface: &mut BoxDashInterface) -> anyhow::Result<()> { + fn refresh( + &mut self, + layout: &mut Layout, + interface: &mut BoxDashInterface, + data: &mut T, + ) -> anyhow::Result<()> { layout.remove_children(self.id_list_parent); let mut text: Option = None; - match interface.window_list() { + match interface.window_list(data) { Ok(list) => { if list.is_empty() { text = Some(Translation::from_translation_key("NO_WINDOWS_FOUND")) @@ -215,6 +227,7 @@ impl View { parent: self.id_list_parent, }, interface, + data, list, &self.tasks, )? @@ -252,19 +265,20 @@ impl View { let state = self.state.clone(); let tasks = self.tasks.clone(); + //TODO + Rc::new(move |data| { - state.borrow_mut().view_window_options = Some(( - data.handle, - window_options::View::new(window_options::Params { - globals: globals.clone(), - layout: data.layout, - parent_id: data.id_content, - on_submit: tasks.make_callback(Task::WindowOptionsFinish), - window: window.clone(), - frontend_tasks: frontend_tasks.clone(), - interface: data.interface, - })?, - )); + // state.borrow_mut().view_window_options = Some(( + // data.handle, + // window_options::View::new(window_options::Params { + // globals: globals.clone(), + // layout: data.layout, + // parent_id: data.id_content, + // on_submit: tasks.make_callback(Task::WindowOptionsFinish), + // window: window.clone(), + // frontend_tasks: frontend_tasks.clone(), + // })?, + // )); Ok(()) }) }, diff --git a/dash-frontend/src/views/window_options.rs b/dash-frontend/src/views/window_options.rs index 5c0a178..b67e1e9 100644 --- a/dash-frontend/src/views/window_options.rs +++ b/dash-frontend/src/views/window_options.rs @@ -34,18 +34,19 @@ pub struct View { on_submit: Rc, } -pub struct Params<'a> { +pub struct Params<'a, T> { pub globals: WguiGlobals, pub frontend_tasks: FrontendTasks, pub layout: &'a mut Layout, pub parent_id: WidgetID, pub on_submit: Rc, pub window: packet_server::WvrWindow, - pub interface: &'a mut BoxDashInterface, + pub interface: &'a mut BoxDashInterface, + pub data: &'a mut T, } impl View { - pub fn new(params: Params) -> anyhow::Result { + pub fn new(params: Params) -> anyhow::Result { let doc_params = &ParseDocumentParams { globals: params.globals.clone(), path: AssetPath::BuiltIn("gui/view/window_options.xml"), @@ -67,6 +68,7 @@ impl View { parent: window_parent, }, params.interface, + params.data, ¶ms.globals, ¶ms.window, )?; @@ -93,12 +95,17 @@ impl View { }) } - pub fn update(&mut self, _layout: &mut Layout, interface: &mut BoxDashInterface) -> anyhow::Result<()> { + pub fn update( + &mut self, + _layout: &mut Layout, + interface: &mut BoxDashInterface, + data: &mut T, + ) -> anyhow::Result<()> { for task in self.tasks.drain() { match task { - Task::SetVisible(v) => self.action_set_visible(interface, v), - Task::Close => self.action_close(interface), - Task::Kill => self.action_kill(interface), + Task::SetVisible(v) => self.action_set_visible(interface, data, v), + Task::Close => self.action_close(interface, data), + Task::Kill => self.action_kill(interface, data), } } Ok(()) @@ -106,8 +113,8 @@ impl View { } impl View { - fn action_set_visible(&mut self, interface: &mut BoxDashInterface, visible: bool) { - if let Err(e) = interface.window_set_visible(self.window.handle.clone(), visible) { + fn action_set_visible(&mut self, interface: &mut BoxDashInterface, data: &mut T, visible: bool) { + if let Err(e) = interface.window_set_visible(data, self.window.handle.clone(), visible) { self .frontend_tasks .push(FrontendTask::PushToast(Translation::from_raw_text_string(format!( @@ -119,8 +126,8 @@ impl View { (*self.on_submit)(); } - fn action_close(&mut self, interface: &mut BoxDashInterface) { - if let Err(e) = interface.window_request_close(self.window.handle.clone()) { + fn action_close(&mut self, interface: &mut BoxDashInterface, data: &mut T) { + if let Err(e) = interface.window_request_close(data, self.window.handle.clone()) { self .frontend_tasks .push(FrontendTask::PushToast(Translation::from_raw_text_string(format!( @@ -132,16 +139,16 @@ impl View { (*self.on_submit)(); } - fn action_kill_process(&mut self, interface: &mut BoxDashInterface) -> anyhow::Result<()> { + fn action_kill_process(&mut self, interface: &mut BoxDashInterface, data: &mut T) -> anyhow::Result<()> { let process = interface - .process_get(self.window.process_handle.clone()) + .process_get(data, self.window.process_handle.clone()) .context("Process not found")?; - interface.process_terminate(process.handle)?; + interface.process_terminate(data, process.handle)?; Ok(()) } - fn action_kill(&mut self, interface: &mut BoxDashInterface) { - if let Err(e) = self.action_kill_process(interface) { + fn action_kill(&mut self, interface: &mut BoxDashInterface, data: &mut T) { + if let Err(e) = self.action_kill_process(interface, data) { self .frontend_tasks .push(FrontendTask::PushToast(Translation::from_raw_text_string(format!( diff --git a/wlx-common/src/dash_interface.rs b/wlx-common/src/dash_interface.rs index 23473fb..fd97cb8 100644 --- a/wlx-common/src/dash_interface.rs +++ b/wlx-common/src/dash_interface.rs @@ -3,15 +3,15 @@ use wayvr_ipc::{ packet_server::{WvrProcess, WvrProcessHandle, WvrWindow, WvrWindowHandle}, }; -pub trait DashInterface { - fn window_list(&mut self) -> anyhow::Result>; - fn window_set_visible(&mut self, handle: WvrWindowHandle, visible: bool) -> anyhow::Result<()>; - fn window_request_close(&mut self, handle: WvrWindowHandle) -> anyhow::Result<()>; - fn process_get(&mut self, handle: WvrProcessHandle) -> Option; - fn process_launch(&mut self, params: WvrProcessLaunchParams) -> anyhow::Result; - fn process_list(&mut self) -> anyhow::Result>; - fn process_terminate(&mut self, handle: WvrProcessHandle) -> anyhow::Result<()>; - fn recenter_playspace(&mut self) -> anyhow::Result<()>; +pub trait DashInterface { + fn window_list(&mut self, data: &mut T) -> anyhow::Result>; + fn window_set_visible(&mut self, data: &mut T, handle: WvrWindowHandle, visible: bool) -> anyhow::Result<()>; + fn window_request_close(&mut self, data: &mut T, handle: WvrWindowHandle) -> anyhow::Result<()>; + fn process_get(&mut self, data: &mut T, handle: WvrProcessHandle) -> Option; + fn process_launch(&mut self, data: &mut T, params: WvrProcessLaunchParams) -> anyhow::Result; + fn process_list(&mut self, data: &mut T) -> anyhow::Result>; + fn process_terminate(&mut self, data: &mut T, handle: WvrProcessHandle) -> anyhow::Result<()>; + fn recenter_playspace(&mut self, data: &mut T) -> anyhow::Result<()>; } -pub type BoxDashInterface = Box; +pub type BoxDashInterface = Box>; diff --git a/wlx-common/src/dash_interface_emulated.rs b/wlx-common/src/dash_interface_emulated.rs index fa14898..164de2e 100644 --- a/wlx-common/src/dash_interface_emulated.rs +++ b/wlx-common/src/dash_interface_emulated.rs @@ -79,12 +79,12 @@ impl Default for DashInterfaceEmulated { } } -impl DashInterface for DashInterfaceEmulated { - fn window_list(&mut self) -> anyhow::Result> { +impl DashInterface<()> for DashInterfaceEmulated { + fn window_list(&mut self, _: &mut ()) -> anyhow::Result> { Ok(self.windows.iter().map(|(handle, w)| w.to(handle)).collect()) } - fn window_request_close(&mut self, handle: WvrWindowHandle) -> anyhow::Result<()> { + fn window_request_close(&mut self, _: &mut (), handle: WvrWindowHandle) -> anyhow::Result<()> { self.windows.remove(&EmuWindowHandle { generation: handle.generation, idx: handle.idx, @@ -92,12 +92,12 @@ impl DashInterface for DashInterfaceEmulated { Ok(()) } - fn process_get(&mut self, handle: WvrProcessHandle) -> Option { + fn process_get(&mut self, _: &mut (), handle: WvrProcessHandle) -> Option { let emu_handle = EmuProcessHandle::new(handle.idx, handle.generation); self.processes.get(&emu_handle).map(|process| process.to(emu_handle)) } - fn process_launch(&mut self, params: WvrProcessLaunchParams) -> anyhow::Result { + fn process_launch(&mut self, _: &mut (), params: WvrProcessLaunchParams) -> anyhow::Result { let res = self.processes.add(EmuProcess { name: params.name }); self.windows.add(EmuWindow { @@ -111,7 +111,7 @@ impl DashInterface for DashInterfaceEmulated { }) } - fn process_list(&mut self) -> anyhow::Result> { + fn process_list(&mut self, _: &mut ()) -> anyhow::Result> { Ok( self .processes @@ -121,7 +121,7 @@ impl DashInterface for DashInterfaceEmulated { ) } - fn process_terminate(&mut self, handle: WvrProcessHandle) -> anyhow::Result<()> { + fn process_terminate(&mut self, _: &mut (), handle: WvrProcessHandle) -> anyhow::Result<()> { let mut to_remove = None; for (wh, w) in self.windows.iter() { @@ -140,7 +140,7 @@ impl DashInterface for DashInterfaceEmulated { Ok(()) } - fn window_set_visible(&mut self, handle: WvrWindowHandle, visible: bool) -> anyhow::Result<()> { + fn window_set_visible(&mut self, _: &mut (), handle: WvrWindowHandle, visible: bool) -> anyhow::Result<()> { match self.windows.get_mut(&EmuWindowHandle { generation: handle.generation, idx: handle.idx, @@ -153,7 +153,7 @@ impl DashInterface for DashInterfaceEmulated { } } - fn recenter_playspace(&mut self) -> anyhow::Result<()> { + fn recenter_playspace(&mut self, _: &mut ()) -> anyhow::Result<()> { // stub! Ok(()) } diff --git a/wlx-overlay-s/src/backend/wayvr/mod.rs b/wlx-overlay-s/src/backend/wayvr/mod.rs index b831cb7..b7c1236 100644 --- a/wlx-overlay-s/src/backend/wayvr/mod.rs +++ b/wlx-overlay-s/src/backend/wayvr/mod.rs @@ -386,6 +386,10 @@ impl WvrServerState { self.window_to_overlay.insert(window, oid); } + pub fn get_overlay_id(&self, window: window::WindowHandle) -> Option { + self.window_to_overlay.get(&window).cloned() + } + pub fn send_mouse_move(&mut self, handle: window::WindowHandle, x: u32, y: u32) { if self.mouse_freeze > Instant::now() { return; diff --git a/wlx-overlay-s/src/overlays/dashboard.rs b/wlx-overlay-s/src/overlays/dashboard.rs index 19da5b4..5f15405 100644 --- a/wlx-overlay-s/src/overlays/dashboard.rs +++ b/wlx-overlay-s/src/overlays/dashboard.rs @@ -3,6 +3,11 @@ use dash_frontend::{ settings::{self, SettingsIO}, }; use glam::{Affine2, Affine3A, Vec2, vec2, vec3}; +use tracing::instrument::WithSubscriber; +use wayvr_ipc::{ + packet_client::WvrProcessLaunchParams, + packet_server::{WvrProcess, WvrProcessHandle, WvrWindow, WvrWindowHandle}, +}; use wgui::{ event::{ Event as WguiEvent, MouseButtonIndex, MouseDownEvent, MouseLeaveEvent, MouseMotionEvent, @@ -13,7 +18,7 @@ use wgui::{ widget::EventResult, }; use wlx_common::{ - dash_interface_emulated::DashInterfaceEmulated, + dash_interface::DashInterface, overlays::{BackendAttrib, BackendAttribValue}, }; use wlx_common::{ @@ -22,11 +27,16 @@ use wlx_common::{ }; use crate::{ - backend::input::{Haptics, HoverResult, PointerHit, PointerMode}, + backend::{ + input::{Haptics, HoverResult, PointerHit, PointerMode}, + task::{OverlayTask, PlayspaceTask, TaskType}, + wayvr::{process::ProcessHandle, window::WindowHandle}, + }, + ipc::ipc_server::{gen_args_vec, gen_env_vec}, state::AppState, subsystem::hid::WheelDelta, windowing::{ - Z_ORDER_DASHBOARD, + OverlaySelector, Z_ORDER_DASHBOARD, backend::{ FrameMeta, OverlayBackend, OverlayEventData, RenderResources, ShouldRender, ui_transform, @@ -78,7 +88,7 @@ impl settings::SettingsIO for SimpleSettingsIO { } pub struct DashFrontend { - inner: frontend::Frontend, + inner: frontend::Frontend, initialized: bool, interaction_transform: Option, timestep: Timestep, @@ -91,7 +101,7 @@ const GUI_SCALE: f32 = 2.0; impl DashFrontend { fn new(app: &mut AppState) -> anyhow::Result { let settings = SimpleSettingsIO::new(); - let interface = DashInterfaceEmulated::new(); + let interface = DashInterfaceLive::new(); let frontend = frontend::Frontend::new(frontend::InitParams { settings: Box::new(settings), @@ -108,8 +118,9 @@ impl DashFrontend { }) } - fn update(&mut self, timestep_alpha: f32) -> anyhow::Result<()> { + fn update(&mut self, app: &mut AppState, timestep_alpha: f32) -> anyhow::Result<()> { self.inner.update( + app, DASH_RES_VEC2.x / GUI_SCALE, DASH_RES_VEC2.y / GUI_SCALE, timestep_alpha, @@ -134,7 +145,7 @@ impl OverlayBackend for DashFrontend { self.interaction_transform = Some(ui_transform(DASH_RES_U32A)); if self.inner.layout.content_size.x * self.inner.layout.content_size.y != 0.0 { - self.update(0.0)?; + self.update(app, 0.0)?; self.initialized = true; } Ok(()) @@ -150,12 +161,12 @@ impl OverlayBackend for DashFrontend { Ok(()) } - fn should_render(&mut self, _app: &mut AppState) -> anyhow::Result { + fn should_render(&mut self, app: &mut AppState) -> anyhow::Result { while self.timestep.on_tick() { self.inner.layout.tick()?; } - if let Err(e) = self.update(self.timestep.alpha) { + if let Err(e) = self.update(app, self.timestep.alpha) { log::error!("uncaught exception: {e:?}"); } @@ -301,3 +312,113 @@ pub fn create_dash_frontend(app: &mut AppState) -> anyhow::Result Self { + Self {} + } +} + +impl DashInterface for DashInterfaceLive { + fn window_list(&mut self, app: &mut AppState) -> anyhow::Result> { + let wvr_server = app.wvr_server.as_mut().unwrap(); + Ok(wvr_server + .wm + .windows + .iter() + .map(|(handle, win)| WvrWindow { + handle: WindowHandle::as_packet(&handle), + process_handle: ProcessHandle::as_packet(&win.process), + size_x: win.size_x, + size_y: win.size_y, + visible: win.visible, + }) + .collect()) + } + + fn window_request_close( + &mut self, + app: &mut AppState, + handle: WvrWindowHandle, + ) -> anyhow::Result<()> { + let wvr_server = app.wvr_server.as_mut().unwrap(); + wvr_server + .wm + .remove_window(WindowHandle::from_packet(handle)); + Ok(()) + } + + fn process_get(&mut self, app: &mut AppState, handle: WvrProcessHandle) -> Option { + let wvr_server = app.wvr_server.as_mut().unwrap(); + let handle = ProcessHandle::from_packet(handle); + wvr_server + .processes + .get(&handle) + .map(|x| x.to_packet(handle)) + } + + fn process_launch( + &mut self, + app: &mut AppState, + params: WvrProcessLaunchParams, + ) -> anyhow::Result { + let wvr_server = app.wvr_server.as_mut().unwrap(); + + let args_vec = gen_args_vec(¶ms.args); + let env_vec = gen_env_vec(¶ms.env); + + wvr_server + .spawn_process(¶ms.exec, &args_vec, &env_vec, None, params.userdata) + .map(|x| x.as_packet()) + } + + fn process_list(&mut self, app: &mut AppState) -> anyhow::Result> { + let wvr_server = app.wvr_server.as_mut().unwrap(); + Ok(wvr_server + .processes + .iter() + .map(|(hnd, p)| p.to_packet(hnd)) + .collect()) + } + + fn process_terminate( + &mut self, + app: &mut AppState, + handle: WvrProcessHandle, + ) -> anyhow::Result<()> { + let wvr_server = app.wvr_server.as_mut().unwrap(); + wvr_server.terminate_process(ProcessHandle::from_packet(handle)); + Ok(()) + } + + fn window_set_visible( + &mut self, + app: &mut AppState, + handle: WvrWindowHandle, + visible: bool, + ) -> anyhow::Result<()> { + let wvr_server = app.wvr_server.as_mut().unwrap(); + let Some(oid) = wvr_server.get_overlay_id(WindowHandle::from_packet(handle)) else { + return Ok(()); + }; + + app.tasks.enqueue(TaskType::Overlay(OverlayTask::Modify( + OverlaySelector::Id(oid), + Box::new(move |app, owc| { + if visible && !owc.is_active() { + owc.activate(app); + } else if !visible && owc.is_active() { + owc.deactivate(); + } + }), + ))); + Ok(()) + } + + fn recenter_playspace(&mut self, app: &mut AppState) -> anyhow::Result<()> { + app.tasks + .enqueue(TaskType::Playspace(PlayspaceTask::Recenter)); + Ok(()) + } +}