app autostart
This commit is contained in:
@@ -10,7 +10,7 @@
|
||||
round="8"
|
||||
align_items="center"
|
||||
justify_content="space_between"
|
||||
color="~color_background"
|
||||
color="~color_bg"
|
||||
border_color="~color_accent"
|
||||
>
|
||||
<label id="label_title" margin_left="8" color="~color_text" size="22" weight="bold" />
|
||||
@@ -29,4 +29,4 @@
|
||||
</rectangle>
|
||||
</div>
|
||||
</elements>
|
||||
</layout>
|
||||
</layout>
|
||||
|
||||
@@ -31,12 +31,12 @@
|
||||
"LOCK_INTERACTION": "Lock interaction",
|
||||
"MOVE_PRESS_AND_DRAG": "Move (press & drag)",
|
||||
"OPACITY": "Opacity",
|
||||
"POS_ANCHORED": "Anchored: Moves together with the rest of the set. Default.",
|
||||
"POS_FLOATING": "Floating: Stay in place, recenter when shown.",
|
||||
"POS_ANCHORED": "Anchored: Moves with center marker. Default.",
|
||||
"POS_FLOATING": "Floating: Moves independently, recenters when shown.",
|
||||
"POS_HAND_L": "Follow the left hand.",
|
||||
"POS_HAND_R": "Follow the right hand.",
|
||||
"POS_HMD": "Follow the HMD.",
|
||||
"POS_STATIC": "Static: Stay in place and never recenter.",
|
||||
"POS_STATIC": "Static: Not part of any set, no recenter.",
|
||||
"POSITIONING": "Positioning",
|
||||
"RESIZE_PRESS_AND_DRAG": "Resize (press & drag)",
|
||||
"STEREO_3D_MODE": {
|
||||
|
||||
@@ -106,20 +106,11 @@ impl BlitMethod {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Config {
|
||||
pub click_freeze_time_ms: i32,
|
||||
pub keyboard_repeat_delay_ms: u32,
|
||||
pub keyboard_repeat_rate: u32,
|
||||
pub auto_hide_delay: Option<u32>, // if None, auto-hide is disabled
|
||||
pub blit_method: BlitMethod,
|
||||
}
|
||||
|
||||
pub struct WvrServerState {
|
||||
time_start: u64,
|
||||
pub manager: client::WayVRCompositor,
|
||||
pub wm: window::WindowManager,
|
||||
pub processes: process::ProcessVec,
|
||||
pub config: Config,
|
||||
pub tasks: SyncEventQueue<WayVRTask>,
|
||||
ticks: u64,
|
||||
cur_modifiers: u8,
|
||||
@@ -139,11 +130,13 @@ pub enum TickTask {
|
||||
NewExternalProcess(ExternalProcessRequest), // Call WayVRCompositor::add_client after receiving this message
|
||||
}
|
||||
|
||||
const KEY_REPEAT_DELAY: i32 = 200;
|
||||
const KEY_REPEAT_RATE: i32 = 50;
|
||||
|
||||
impl WvrServerState {
|
||||
pub fn new(
|
||||
gfx: Arc<WGfx>,
|
||||
gfx_extras: &WGfxExtras,
|
||||
config: Config,
|
||||
signals: SyncEventQueue<WayVRSignal>,
|
||||
) -> anyhow::Result<Self> {
|
||||
log::info!("Initializing WayVR server");
|
||||
@@ -210,11 +203,8 @@ impl WvrServerState {
|
||||
},
|
||||
);
|
||||
|
||||
let seat_keyboard = seat.add_keyboard(
|
||||
XkbConfig::default(),
|
||||
config.keyboard_repeat_delay_ms as i32,
|
||||
config.keyboard_repeat_rate as i32,
|
||||
)?;
|
||||
let seat_keyboard =
|
||||
seat.add_keyboard(XkbConfig::default(), KEY_REPEAT_DELAY, KEY_REPEAT_RATE)?;
|
||||
let seat_pointer = seat.add_pointer();
|
||||
|
||||
let tasks = SyncEventQueue::new();
|
||||
@@ -241,7 +231,6 @@ impl WvrServerState {
|
||||
manager: client::WayVRCompositor::new(state, display, seat_keyboard, seat_pointer)?,
|
||||
processes: ProcessVec::new(),
|
||||
wm: window::WindowManager::new(),
|
||||
config,
|
||||
ticks: 0,
|
||||
tasks,
|
||||
cur_modifiers: 0,
|
||||
@@ -507,9 +496,13 @@ impl WvrServerState {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_mouse_down(&mut self, handle: window::WindowHandle, index: MouseIndex) {
|
||||
self.mouse_freeze =
|
||||
Instant::now() + Duration::from_millis(self.config.click_freeze_time_ms as _);
|
||||
pub fn send_mouse_down(
|
||||
&mut self,
|
||||
click_freeze: i32,
|
||||
handle: window::WindowHandle,
|
||||
index: MouseIndex,
|
||||
) {
|
||||
self.mouse_freeze = Instant::now() + Duration::from_millis(click_freeze as _);
|
||||
|
||||
if let Some(window) = self.wm.windows.get_mut(&handle) {
|
||||
window.send_mouse_down(&mut self.manager, index);
|
||||
|
||||
@@ -2,6 +2,7 @@ use config::{Config, File};
|
||||
use log::error;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::PathBuf;
|
||||
use wayvr_ipc::packet_client::WvrProcessLaunchParams;
|
||||
use wlx_common::{
|
||||
astr_containers::AStrMap,
|
||||
config::{
|
||||
@@ -142,6 +143,7 @@ pub struct AutoSettings {
|
||||
pub context_menu_hold_and_release: bool,
|
||||
pub capture_method: CaptureMethod,
|
||||
pub keyboard_middle_click_mode: AltModifier,
|
||||
pub autostart_apps: Vec<WvrProcessLaunchParams>,
|
||||
}
|
||||
|
||||
fn get_settings_path() -> PathBuf {
|
||||
@@ -187,6 +189,7 @@ pub fn save_settings(config: &GeneralConfig) -> anyhow::Result<()> {
|
||||
context_menu_hold_and_release: config.context_menu_hold_and_release,
|
||||
capture_method: config.capture_method,
|
||||
keyboard_middle_click_mode: config.keyboard_middle_click_mode,
|
||||
autostart_apps: config.autostart_apps.clone(),
|
||||
};
|
||||
|
||||
let json = serde_json::to_string_pretty(&conf).unwrap(); // want panic
|
||||
|
||||
@@ -1,286 +0,0 @@
|
||||
#[cfg(not(feature = "wayvr"))]
|
||||
compile_error!("WayVR feature is not enabled");
|
||||
|
||||
use std::{
|
||||
collections::{BTreeMap, HashMap},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use anyhow::Context;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use wgui::gfx::WGfx;
|
||||
use wlx_common::{common::LeftRight, config::GeneralConfig, config_io, windowing::Positioning};
|
||||
|
||||
use crate::{
|
||||
backend::{
|
||||
task::TaskContainer,
|
||||
wayvr::{self, WvrServerState},
|
||||
},
|
||||
config::load_config_with_conf_d,
|
||||
graphics::WGfxExtras,
|
||||
ipc::{event_queue::SyncEventQueue, signal::WayVRSignal},
|
||||
};
|
||||
|
||||
// Flat version of RelativeTo
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
pub enum AttachTo {
|
||||
None,
|
||||
HandLeft,
|
||||
HandRight,
|
||||
Head,
|
||||
Stage,
|
||||
}
|
||||
|
||||
impl AttachTo {
|
||||
// TODO: adjustable lerp factor
|
||||
pub const fn get_positioning(&self) -> Positioning {
|
||||
match self {
|
||||
Self::None => Positioning::Floating,
|
||||
Self::HandLeft => Positioning::FollowHand {
|
||||
hand: LeftRight::Left,
|
||||
lerp: 1.0,
|
||||
align_to_hmd: false,
|
||||
},
|
||||
Self::HandRight => Positioning::FollowHand {
|
||||
hand: LeftRight::Right,
|
||||
lerp: 1.0,
|
||||
align_to_hmd: false,
|
||||
},
|
||||
Self::Stage => Positioning::Static,
|
||||
Self::Head => Positioning::FollowHead { lerp: 1.0 },
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn from_packet(input: &wayvr_ipc::packet_client::AttachTo) -> Self {
|
||||
match input {
|
||||
wayvr_ipc::packet_client::AttachTo::None => Self::None,
|
||||
wayvr_ipc::packet_client::AttachTo::HandLeft => Self::HandLeft,
|
||||
wayvr_ipc::packet_client::AttachTo::HandRight => Self::HandRight,
|
||||
wayvr_ipc::packet_client::AttachTo::Head => Self::Head,
|
||||
wayvr_ipc::packet_client::AttachTo::Stage => Self::Stage,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
pub struct Rotation {
|
||||
pub axis: [f32; 3],
|
||||
pub angle: f32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
pub struct WayVRAppEntry {
|
||||
pub name: String,
|
||||
pub target_display: String,
|
||||
pub exec: String,
|
||||
pub args: Option<String>,
|
||||
pub env: Option<Vec<String>>,
|
||||
pub shown_at_start: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
pub struct WayVRDisplay {
|
||||
pub width: u16,
|
||||
pub height: u16,
|
||||
pub scale: Option<f32>,
|
||||
pub rotation: Option<Rotation>,
|
||||
pub pos: Option<[f32; 3]>,
|
||||
pub attach_to: Option<AttachTo>,
|
||||
pub primary: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
pub struct WayVRCatalog {
|
||||
pub apps: Vec<WayVRAppEntry>,
|
||||
}
|
||||
|
||||
impl WayVRCatalog {
|
||||
pub fn get_app(&self, name: &str) -> Option<&WayVRAppEntry> {
|
||||
self.apps.iter().find(|&app| app.name.as_str() == name)
|
||||
}
|
||||
}
|
||||
|
||||
const fn def_false() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
const fn def_true() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
const fn def_autohide_delay() -> u32 {
|
||||
750
|
||||
}
|
||||
|
||||
const fn def_keyboard_repeat_delay() -> u32 {
|
||||
200
|
||||
}
|
||||
|
||||
const fn def_keyboard_repeat_rate() -> u32 {
|
||||
50
|
||||
}
|
||||
|
||||
fn def_blit_method() -> String {
|
||||
String::from("dmabuf")
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
pub struct WayVRDashboard {
|
||||
pub exec: String,
|
||||
pub working_dir: Option<String>,
|
||||
pub args: Option<String>,
|
||||
pub env: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct WayVRConfig {
|
||||
#[serde(default = "Default::default")]
|
||||
pub catalogs: HashMap<String, WayVRCatalog>,
|
||||
|
||||
#[serde(default = "Default::default")]
|
||||
pub displays: BTreeMap<String, WayVRDisplay>, // sorted alphabetically
|
||||
|
||||
#[serde(default = "Default::default")]
|
||||
pub dashboard: Option<WayVRDashboard>,
|
||||
|
||||
#[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,
|
||||
|
||||
#[serde(default = "def_blit_method")]
|
||||
pub blit_method: String,
|
||||
}
|
||||
|
||||
impl WayVRConfig {
|
||||
pub fn get_catalog(&self, name: &str) -> Option<&WayVRCatalog> {
|
||||
self.catalogs.get(name)
|
||||
}
|
||||
|
||||
pub fn get_display(&self, name: &str) -> Option<&WayVRDisplay> {
|
||||
self.displays.get(name)
|
||||
}
|
||||
|
||||
pub fn get_default_display(&self) -> Option<(String, &WayVRDisplay)> {
|
||||
for (disp_name, disp) in &self.displays {
|
||||
if disp.primary.unwrap_or(false) {
|
||||
return Some((disp_name.clone(), disp));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn get_wayvr_config(
|
||||
config_general: &GeneralConfig,
|
||||
config_wayvr: &Self,
|
||||
) -> anyhow::Result<wayvr::Config> {
|
||||
Ok(wayvr::Config {
|
||||
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,
|
||||
blit_method: wayvr::BlitMethod::from_string(&config_wayvr.blit_method)
|
||||
.context("unknown blit method")?,
|
||||
auto_hide_delay: if config_wayvr.auto_hide {
|
||||
Some(config_wayvr.auto_hide_delay)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
pub fn post_load(
|
||||
&self,
|
||||
gfx: Arc<WGfx>,
|
||||
gfx_extras: &WGfxExtras,
|
||||
config: &GeneralConfig,
|
||||
_tasks: &mut TaskContainer,
|
||||
signals: SyncEventQueue<WayVRSignal>,
|
||||
) -> anyhow::Result<WvrServerState> {
|
||||
let primary_count = self
|
||||
.displays
|
||||
.iter()
|
||||
.filter(|d| d.1.primary.unwrap_or(false))
|
||||
.count();
|
||||
|
||||
if primary_count > 1 {
|
||||
anyhow::bail!("Number of primary displays is more than 1")
|
||||
}
|
||||
|
||||
for (_catalog_name, catalog) in &self.catalogs {
|
||||
for app in &catalog.apps {
|
||||
if let Some(b) = app.shown_at_start
|
||||
&& b
|
||||
{
|
||||
//CLEANUP: is this needed?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WvrServerState::new(
|
||||
gfx,
|
||||
gfx_extras,
|
||||
Self::get_wayvr_config(config, self)?,
|
||||
signals,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_default_dashboard_exec() -> (
|
||||
String, /* exec path */
|
||||
Option<String>, /* working directory */
|
||||
) {
|
||||
if let Ok(appdir) = std::env::var("APPDIR") {
|
||||
// Running in AppImage
|
||||
let embedded_path = format!("{appdir}/usr/bin/wayvr-dashboard");
|
||||
if executable_exists_in_path(&embedded_path) {
|
||||
log::info!("Using WayVR Dashboard from AppDir: {embedded_path}");
|
||||
return (embedded_path, Some(format!("{appdir}/usr")));
|
||||
}
|
||||
}
|
||||
(String::from("wayvr-dashboard"), None)
|
||||
}
|
||||
|
||||
pub fn executable_exists_in_path(command: &str) -> bool {
|
||||
let Ok(path) = std::env::var("PATH") else {
|
||||
return false; // very unlikely to happen
|
||||
};
|
||||
for dir in path.split(':') {
|
||||
let exec_path = std::path::PathBuf::from(dir).join(command);
|
||||
if exec_path.exists() && exec_path.is_file() {
|
||||
return true; // executable found
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn load_wayvr() -> WayVRConfig {
|
||||
let config_root_path = config_io::ConfigRoot::WayVR.ensure_dir();
|
||||
log::info!("WayVR Config root path: {}", config_root_path.display());
|
||||
log::info!(
|
||||
"WayVR conf.d path: {}",
|
||||
config_io::ConfigRoot::WayVR.get_conf_d_path().display()
|
||||
);
|
||||
|
||||
let mut conf =
|
||||
load_config_with_conf_d::<WayVRConfig>("wayvr.yaml", config_io::ConfigRoot::WayVR);
|
||||
|
||||
if conf.dashboard.is_none() {
|
||||
let (exec, working_dir) = get_default_dashboard_exec();
|
||||
|
||||
conf.dashboard = Some(WayVRDashboard {
|
||||
args: None,
|
||||
env: None,
|
||||
exec,
|
||||
working_dir,
|
||||
});
|
||||
}
|
||||
|
||||
conf
|
||||
}
|
||||
@@ -29,9 +29,6 @@ mod state;
|
||||
mod subsystem;
|
||||
mod windowing;
|
||||
|
||||
#[cfg(feature = "wayvr")]
|
||||
mod config_wayvr;
|
||||
|
||||
use std::{
|
||||
path::PathBuf,
|
||||
process::Command,
|
||||
|
||||
@@ -66,7 +66,11 @@ const GUI_SCALE: f32 = 2.0;
|
||||
|
||||
impl DashFrontend {
|
||||
fn new(app: &mut AppState) -> anyhow::Result<Self> {
|
||||
let interface = DashInterfaceLive::new();
|
||||
let mut interface = DashInterfaceLive::new();
|
||||
|
||||
for p in app.session.config.autostart_apps.clone() {
|
||||
let _ = interface.process_launch(app, false, p)?;
|
||||
}
|
||||
|
||||
let frontend = frontend::Frontend::new(
|
||||
frontend::InitParams {
|
||||
@@ -341,6 +345,7 @@ impl DashInterface<AppState> for DashInterfaceLive {
|
||||
fn process_launch(
|
||||
&mut self,
|
||||
app: &mut AppState,
|
||||
auto_start: bool,
|
||||
params: WvrProcessLaunchParams,
|
||||
) -> anyhow::Result<WvrProcessHandle> {
|
||||
let wvr_server = app.wvr_server.as_mut().unwrap();
|
||||
@@ -348,6 +353,11 @@ impl DashInterface<AppState> for DashInterfaceLive {
|
||||
let args_vec = gen_args_vec(¶ms.args);
|
||||
let env_vec = gen_env_vec(¶ms.env);
|
||||
|
||||
if auto_start {
|
||||
app.session.config.autostart_apps.push(params.clone());
|
||||
save_settings(&app.session.config)?;
|
||||
}
|
||||
|
||||
wvr_server
|
||||
.spawn_process(
|
||||
¶ms.name,
|
||||
|
||||
@@ -508,9 +508,10 @@ impl OverlayBackend for WvrWindowBackend {
|
||||
None
|
||||
}
|
||||
} {
|
||||
let click_freeze = app.session.config.click_freeze_time_ms;
|
||||
let wvr_server = app.wvr_server.as_mut().unwrap(); //never None
|
||||
if pressed {
|
||||
wvr_server.send_mouse_down(self.window, index);
|
||||
wvr_server.send_mouse_down(click_freeze, self.window, index);
|
||||
} else {
|
||||
wvr_server.send_mouse_up(index);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ use glam::Affine3A;
|
||||
use idmap::IdMap;
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
use std::sync::Arc;
|
||||
#[cfg(feature = "wayvr")]
|
||||
use wgui::log::LogErr;
|
||||
use wgui::{
|
||||
drawing, font_config::WguiFontConfig, gfx::WGfx, globals::WguiGlobals, parser::parse_color_hex,
|
||||
renderer_vk::context::SharedContext as WSharedContext,
|
||||
@@ -14,9 +16,6 @@ use wlx_common::{
|
||||
overlays::{ToastDisplayMethod, ToastTopic},
|
||||
};
|
||||
|
||||
#[cfg(feature = "wayvr")]
|
||||
use crate::config_wayvr::{self, WayVRConfig};
|
||||
|
||||
#[cfg(feature = "wayvr")]
|
||||
use crate::backend::wayvr::WvrServerState;
|
||||
#[cfg(feature = "osc")]
|
||||
@@ -78,19 +77,11 @@ impl AppState {
|
||||
let mut tasks = TaskContainer::new();
|
||||
|
||||
let session = AppSession::load();
|
||||
let wayvr_signals = SyncEventQueue::new();
|
||||
let wvr_signals = SyncEventQueue::new();
|
||||
|
||||
#[cfg(feature = "wayvr")]
|
||||
let wayvr_server = session
|
||||
.wayvr_config
|
||||
.post_load(
|
||||
gfx.clone(),
|
||||
&gfx_extras,
|
||||
&session.config,
|
||||
&mut tasks,
|
||||
wayvr_signals.clone(),
|
||||
)
|
||||
.inspect_err(|e| log::error!("Could not initialize wayland server: {e:?}"))
|
||||
let wvr_server = WvrServerState::new(gfx.clone(), &gfx_extras, wvr_signals.clone())
|
||||
.log_err("Could not initialize WayVR Server")
|
||||
.ok();
|
||||
|
||||
let mut hid_provider = HidWrapper::new();
|
||||
@@ -164,14 +155,14 @@ impl AppState {
|
||||
dbus,
|
||||
xr_backend,
|
||||
ipc_server,
|
||||
wayvr_signals,
|
||||
wayvr_signals: wvr_signals,
|
||||
desktop_finder,
|
||||
|
||||
#[cfg(feature = "osc")]
|
||||
osc_sender,
|
||||
|
||||
#[cfg(feature = "wayvr")]
|
||||
wvr_server: wayvr_server,
|
||||
wvr_server,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -180,9 +171,6 @@ pub struct AppSession {
|
||||
pub config: GeneralConfig,
|
||||
pub config_dirty: bool,
|
||||
|
||||
#[cfg(feature = "wayvr")]
|
||||
pub wayvr_config: WayVRConfig, // TODO: rename to "wayland_server_config"
|
||||
|
||||
pub toast_topics: IdMap<ToastTopic, ToastDisplayMethod>,
|
||||
}
|
||||
|
||||
@@ -202,13 +190,8 @@ impl AppSession {
|
||||
toast_topics.insert(*k, *v);
|
||||
});
|
||||
|
||||
#[cfg(feature = "wayvr")]
|
||||
let wayvr_config = config_wayvr::load_wayvr();
|
||||
|
||||
Self {
|
||||
config,
|
||||
#[cfg(feature = "wayvr")]
|
||||
wayvr_config,
|
||||
toast_topics,
|
||||
config_dirty: false,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user