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 @@
-
-
-
-
+
+
+
-
-
+
+
-
+
@@ -36,19 +35,30 @@
-
+
-
-
-
-
-
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
-
\ 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