From 437840fecbd22a8f86e175c89c2fbd4e7948b1cb Mon Sep 17 00:00:00 2001 From: galister <22305755+galister@users.noreply.github.com> Date: Fri, 9 Jan 2026 00:12:36 +0900 Subject: [PATCH] app autostart --- .../assets/gui/view/app_launcher.xml | 46 +-- dash-frontend/assets/lang/en.json | 26 ++ dash-frontend/src/views/app_launcher.rs | 76 ++++- wayvr-ipc/src/packet_client.rs | 13 +- wayvrctl/src/helper.rs | 6 +- wayvrctl/src/main.rs | 24 +- wlx-common/src/config.rs | 4 + wlx-common/src/dash_interface.rs | 7 +- wlx-common/src/dash_interface_emulated.rs | 7 +- wlx-overlay-s/src/assets/gui/decor.xml | 4 +- wlx-overlay-s/src/assets/lang/en.json | 6 +- wlx-overlay-s/src/backend/wayvr/mod.rs | 31 +- wlx-overlay-s/src/config.rs | 3 + wlx-overlay-s/src/config_wayvr.rs | 286 ------------------ wlx-overlay-s/src/main.rs | 3 - wlx-overlay-s/src/overlays/dashboard.rs | 12 +- wlx-overlay-s/src/overlays/wayvr.rs | 3 +- wlx-overlay-s/src/state.rs | 31 +- 18 files changed, 211 insertions(+), 377 deletions(-) delete mode 100644 wlx-overlay-s/src/config_wayvr.rs diff --git a/dash-frontend/assets/gui/view/app_launcher.xml b/dash-frontend/assets/gui/view/app_launcher.xml index 3611edf..64955a6 100644 --- a/dash-frontend/assets/gui/view/app_launcher.xml +++ b/dash-frontend/assets/gui/view/app_launcher.xml @@ -18,17 +18,16 @@ -
-
- \ No newline at end of file + diff --git a/dash-frontend/assets/lang/en.json b/dash-frontend/assets/lang/en.json index 8f70c46..b253ea1 100644 --- a/dash-frontend/assets/lang/en.json +++ b/dash-frontend/assets/lang/en.json @@ -83,6 +83,32 @@ "SCREENCOPY_HELP": "Slow. Works on: Hyprland, Niri, River, Sway" } }, + "APP_LAUNCHER": { + "MODE": { + "NATIVE": "Native mode", + "CAGE": "Compatibility mode (Cage)" + }, + "RES_TITLE": "Resolution", + "ASPECT_TITLE": "Aspect", + "ASPECT": { + "WIDE": "Wide", + "SEMI_WIDE": "Semi-wide", + "SQUARE": "Square", + "SEMI_TALL": "Semi-tall", + "TALL": "Tall" + }, + "POS_TITLE": "Positioning", + "POS": { + "FLOATING": "Floating", + "ANCHORED": "Anchored", + "STATIC": "Static", + "FLOATING_HELP": "Moves independently, recenters on show.", + "ANCHORED_HELP": "Stays in place relative to center marker.", + "STATIC_HELP": "Not part of any set. Does not recenter." + }, + "AUTOSTART": "Run automatically on startup", + "LAUNCH": "Launch" + }, "APPLICATION_LAUNCHER": "Application launcher", "APPLICATION_STARTED": "Application started", "APPLICATIONS": "Applications", diff --git a/dash-frontend/src/views/app_launcher.rs b/dash-frontend/src/views/app_launcher.rs index b84266c..c5aaf05 100644 --- a/dash-frontend/src/views/app_launcher.rs +++ b/dash-frontend/src/views/app_launcher.rs @@ -1,10 +1,10 @@ use std::{collections::HashMap, rc::Rc, str::FromStr}; use strum::{AsRefStr, EnumString, VariantNames}; -use wayvr_ipc::packet_client::WvrProcessLaunchParams; +use wayvr_ipc::packet_client::{PositionMode, WvrProcessLaunchParams}; use wgui::{ assets::AssetPath, - components::{button::ComponentButton, radio_group::ComponentRadioGroup}, + components::{button::ComponentButton, checkbox::ComponentCheckbox, radio_group::ComponentRadioGroup}, globals::WguiGlobals, i18n::Translation, layout::{Layout, WidgetID}, @@ -16,6 +16,13 @@ use wlx_common::{config::GeneralConfig, dash_interface::BoxDashInterface, deskto use crate::frontend::{FrontendTask, FrontendTasks, SoundType}; +#[derive(Clone, Copy, Eq, PartialEq, EnumString, VariantNames, AsRefStr)] +enum PosMode { + Floating, + Anchored, + Static, +} + #[derive(Clone, Copy, Eq, PartialEq, EnumString, VariantNames, AsRefStr)] enum ResMode { Res1440, @@ -43,18 +50,22 @@ enum CompositorMode { enum Task { SetCompositor(CompositorMode), SetRes(ResMode), + SetPos(PosMode), SetOrientation(OrientationMode), + SetAutoStart(bool), Launch, } struct LaunchParams<'a, T> { application: &'a DesktopEntry, compositor_mode: CompositorMode, + pos_mode: PosMode, res_mode: ResMode, orientation_mode: OrientationMode, globals: &'a WguiGlobals, frontend_tasks: &'a FrontendTasks, interface: &'a mut BoxDashInterface, + auto_start: bool, data: &'a mut T, on_launched: &'a dyn Fn(), } @@ -75,9 +86,12 @@ pub struct View { radio_orientation: Rc, compositor_mode: CompositorMode, + pos_mode: PosMode, res_mode: ResMode, orientation_mode: OrientationMode, + auto_start: bool, + on_launched: Box, } @@ -103,22 +117,18 @@ impl View { let radio_compositor = state.fetch_component_as::("radio_compositor")?; let radio_res = state.fetch_component_as::("radio_res")?; + let radio_pos = state.fetch_component_as::("radio_pos")?; let radio_orientation = state.fetch_component_as::("radio_orientation")?; + let cb_autostart = state.fetch_component_as::("cb_autostart")?; let btn_launch = state.fetch_component_as::("btn_launch")?; { let mut label_exec = state.fetch_widget_as::(¶ms.layout.state, "label_exec")?; - let mut label_args = state.fetch_widget_as::(¶ms.layout.state, "label_args")?; label_exec.set_text_simple( &mut params.globals.get(), - Translation::from_raw_text_rc(params.entry.exec_path.clone()), - ); - - label_args.set_text_simple( - &mut params.globals.get(), - Translation::from_raw_text_rc(params.entry.exec_args.clone()), + Translation::from_raw_text_string(format!("{} {}", params.entry.exec_path, params.entry.exec_args)), ); } @@ -159,6 +169,13 @@ impl View { //radio_orientation.set_value(orientation_mode.as_ref())?; //tasks.push(Task::SetOrientation(orientation_mode)); + let pos_mode = PosMode::Floating; + // TODO: configurable defaults ? + //radio_pos.set_value(pos_mode.as_ref())?; + //tasks.push(Task::SetPos(pos_mode)); + + let auto_start = false; + radio_compositor.on_value_changed({ let tasks = tasks.clone(); Box::new(move |_, ev| { @@ -197,6 +214,25 @@ impl View { }) }); + radio_pos.on_value_changed({ + let tasks = tasks.clone(); + Box::new(move |_, ev| { + if let Some(mode) = ev.value.and_then(|v| { + PosMode::from_str(&*v) + .inspect_err(|_| { + log::error!( + "Invalid value for position: '{v}'. Valid values are: {:?}", + PosMode::VARIANTS + ) + }) + .ok() + }) { + tasks.push(Task::SetPos(mode)); + } + Ok(()) + }) + }); + radio_orientation.on_value_changed({ let tasks = tasks.clone(); Box::new(move |_, ev| { @@ -216,6 +252,14 @@ impl View { }) }); + cb_autostart.on_toggle({ + let tasks = tasks.clone(); + Box::new(move |_, ev| { + tasks.push(Task::SetAutoStart(ev.checked)); + Ok(()) + }) + }); + let mut label_title = state.fetch_widget_as::(¶ms.layout.state, "label_title")?; label_title.set_text_simple( @@ -230,8 +274,10 @@ impl View { radio_res, radio_orientation, compositor_mode, + pos_mode, res_mode, orientation_mode, + auto_start, entry: params.entry, frontend_tasks: params.frontend_tasks.clone(), globals: params.globals.clone(), @@ -249,7 +295,9 @@ impl View { match task { Task::SetCompositor(mode) => self.compositor_mode = mode, Task::SetRes(mode) => self.res_mode = mode, + Task::SetPos(mode) => self.pos_mode = mode, Task::SetOrientation(mode) => self.orientation_mode = mode, + Task::SetAutoStart(auto_start) => self.auto_start = auto_start, Task::Launch => self.action_launch(interface, data), } } @@ -265,7 +313,9 @@ impl View { globals: &self.globals, compositor_mode: self.compositor_mode, res_mode: self.res_mode, + pos_mode: self.pos_mode, orientation_mode: self.orientation_mode, + auto_start: self.auto_start, interface, data, on_launched: &self.on_launched, @@ -308,6 +358,12 @@ impl View { CompositorMode::Native => params.application.exec_path.to_string(), }; + let pos_mode = match params.pos_mode { + PosMode::Floating => PositionMode::Anchor, + PosMode::Anchored => PositionMode::Anchor, + PosMode::Static => PositionMode::Static, + }; + let mut userdata = HashMap::new(); userdata.insert("desktop-entry".to_string(), serde_json::to_string(params.application)?); @@ -315,12 +371,14 @@ impl View { params.interface.process_launch( params.data, + params.auto_start, WvrProcessLaunchParams { env, exec, name: params.application.app_name.to_string(), args, resolution, + pos_mode, icon: params.application.icon_path.as_ref().map(|x| x.as_ref().to_string()), userdata, }, diff --git a/wayvr-ipc/src/packet_client.rs b/wayvr-ipc/src/packet_client.rs index f32c4d4..4cb5b9f 100644 --- a/wayvr-ipc/src/packet_client.rs +++ b/wayvr-ipc/src/packet_client.rs @@ -14,15 +14,13 @@ pub struct Handshake { } #[derive(Debug, Clone, Deserialize, Serialize)] -pub enum AttachTo { - None, - HandLeft, - HandRight, - Head, - Stage, +pub enum PositionMode { + Float, + Anchor, + Static, } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct WvrProcessLaunchParams { pub name: String, pub exec: String, @@ -30,6 +28,7 @@ pub struct WvrProcessLaunchParams { pub args: String, pub icon: Option, pub resolution: [u32; 2], + pub pos_mode: PositionMode, pub userdata: HashMap, } diff --git a/wayvrctl/src/helper.rs b/wayvrctl/src/helper.rs index d1aeb00..43cea32 100644 --- a/wayvrctl/src/helper.rs +++ b/wayvrctl/src/helper.rs @@ -4,7 +4,9 @@ use anyhow::Context; use serde::Serialize; use wayvr_ipc::{ client::{WayVRClient, WayVRClientMutex}, - ipc, packet_client, packet_server, + ipc, + packet_client::{self, PositionMode}, + packet_server, }; pub struct WayVRClientState { @@ -106,6 +108,7 @@ pub async fn wvr_process_launch( name: String, env: Vec, resolution: [u32; 2], + pos_mode: PositionMode, icon: Option, args: String, userdata: HashMap, @@ -121,6 +124,7 @@ pub async fn wvr_process_launch( name, args, resolution, + pos_mode, icon, userdata, }, diff --git a/wayvrctl/src/main.rs b/wayvrctl/src/main.rs index b504b85..91f6893 100644 --- a/wayvrctl/src/main.rs +++ b/wayvrctl/src/main.rs @@ -7,7 +7,11 @@ use std::{ use anyhow::Context; use clap::Parser; use env_logger::Env; -use wayvr_ipc::{client::WayVRClient, ipc, packet_client}; +use wayvr_ipc::{ + client::WayVRClient, + ipc, + packet_client::{self, PositionMode}, +}; use crate::helper::{ WayVRClientState, wlx_device_haptics, wlx_input_state, wlx_panel_modify, wvr_process_get, @@ -120,6 +124,7 @@ async fn run_once(state: &mut WayVRClientState, args: Args) -> anyhow::Result<() name, env, resolution, + pos, icon, args, } => { @@ -131,12 +136,19 @@ async fn run_once(state: &mut WayVRClientState, args: Args) -> anyhow::Result<() "Invalid resolution format. Expecting x, for example: 1920x1080, 1280x720", )?; + let pos_mode = match pos { + PosModeEnum::Floating => PositionMode::Float, + PosModeEnum::Static => PositionMode::Static, + PosModeEnum::Anchored => PositionMode::Anchor, + }; + wvr_process_launch( state, exec, name, env, resolution, + pos_mode, icon, args, HashMap::new(), @@ -237,6 +249,9 @@ enum Subcommands { exec: String, #[arg(default_value = "1920x1080")] resolution: String, + /// Default positioning + pos: PosModeEnum, + /// Absolute path to the app icon icon: Option, /// Arguments to pass to executable #[arg(default_value = "")] @@ -265,6 +280,13 @@ enum Subcommands { }, } +#[derive(Debug, Clone, Copy, clap::ValueEnum)] +enum PosModeEnum { + Floating, + Anchored, + Static, +} + #[derive(clap::Parser, Debug)] enum SubcommandPanelModify { /// Set the text of a