This commit is contained in:
galister
2025-12-24 00:58:40 +09:00
parent 6672fb71e4
commit 3f5a363136
23 changed files with 484 additions and 430 deletions

View File

@@ -1,8 +1,7 @@
use bytes::BufMut; use bytes::BufMut;
use interprocess::local_socket::{ use interprocess::local_socket::{
self, self, GenericNamespaced,
tokio::{prelude::*, Stream}, tokio::{Stream, prelude::*},
GenericNamespaced,
}; };
use serde::Serialize; use serde::Serialize;
use smallvec::SmallVec; use smallvec::SmallVec;

View File

@@ -1,167 +1,164 @@
#[macro_export] #[macro_export]
macro_rules! gen_id { macro_rules! gen_id {
( (
$container_name:ident, $container_name:ident,
$instance_name:ident, $instance_name:ident,
$cell_name:ident, $cell_name:ident,
$handle_name:ident) => { $handle_name:ident) => {
//ThingCell //ThingCell
pub struct $cell_name { pub struct $cell_name {
pub obj: $instance_name, pub obj: $instance_name,
pub generation: u64, pub generation: u64,
} }
//ThingVec //ThingVec
pub struct $container_name { pub struct $container_name {
// Vec<Option<ThingCell>> // Vec<Option<ThingCell>>
pub vec: Vec<Option<$cell_name>>, pub vec: Vec<Option<$cell_name>>,
cur_generation: u64, cur_generation: u64,
} }
//ThingHandle //ThingHandle
#[derive(Default, Clone, Copy, PartialEq, Hash, Eq)] #[derive(Default, Clone, Copy, PartialEq, Hash, Eq)]
pub struct $handle_name { pub struct $handle_name {
idx: u32, idx: u32,
generation: u64, generation: u64,
} }
#[allow(dead_code)] #[allow(dead_code)]
impl $handle_name { impl $handle_name {
pub fn reset(&mut self) { pub fn reset(&mut self) {
self.generation = 0; self.generation = 0;
} }
pub fn is_set(&self) -> bool { pub fn is_set(&self) -> bool {
self.generation > 0 self.generation > 0
} }
pub fn id(&self) -> u32 { pub fn id(&self) -> u32 {
self.idx self.idx
} }
pub fn new(idx: u32, generation: u64) -> Self { pub fn new(idx: u32, generation: u64) -> Self {
Self { idx, generation } Self { idx, generation }
} }
} }
//ThingVec //ThingVec
#[allow(dead_code)] #[allow(dead_code)]
impl $container_name { impl $container_name {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
vec: Vec::new(), vec: Vec::new(),
cur_generation: 0, cur_generation: 0,
} }
} }
pub fn iter(&self, callback: &dyn Fn($handle_name, &$instance_name)) { pub fn iter(&self, callback: &dyn Fn($handle_name, &$instance_name)) {
for (idx, opt_cell) in self.vec.iter().enumerate() { for (idx, opt_cell) in self.vec.iter().enumerate() {
if let Some(cell) = opt_cell { if let Some(cell) = opt_cell {
let handle = $container_name::get_handle(&cell, idx); let handle = $container_name::get_handle(&cell, idx);
callback(handle, &cell.obj); callback(handle, &cell.obj);
} }
} }
} }
pub fn iter_mut( pub fn iter_mut(&mut self, callback: &mut dyn FnMut($handle_name, &mut $instance_name)) {
&mut self, for (idx, opt_cell) in self.vec.iter_mut().enumerate() {
callback: &mut dyn FnMut($handle_name, &mut $instance_name), if let Some(cell) = opt_cell {
) { let handle = $container_name::get_handle(&cell, idx);
for (idx, opt_cell) in self.vec.iter_mut().enumerate() { callback(handle, &mut cell.obj);
if let Some(cell) = opt_cell { }
let handle = $container_name::get_handle(&cell, idx); }
callback(handle, &mut cell.obj); }
}
}
}
pub fn get_handle(cell: &$cell_name, idx: usize) -> $handle_name { pub fn get_handle(cell: &$cell_name, idx: usize) -> $handle_name {
$handle_name { $handle_name {
idx: idx as u32, idx: idx as u32,
generation: cell.generation, generation: cell.generation,
} }
} }
fn find_unused_idx(&mut self) -> Option<u32> { fn find_unused_idx(&mut self) -> Option<u32> {
for (num, obj) in self.vec.iter().enumerate() { for (num, obj) in self.vec.iter().enumerate() {
if obj.is_none() { if obj.is_none() {
return Some(num as u32); return Some(num as u32);
} }
} }
None None
} }
pub fn add(&mut self, obj: $instance_name) -> $handle_name { pub fn add(&mut self, obj: $instance_name) -> $handle_name {
self.cur_generation += 1; self.cur_generation += 1;
let generation = self.cur_generation; let generation = self.cur_generation;
let unused_idx = self.find_unused_idx(); let unused_idx = self.find_unused_idx();
let idx = if let Some(idx) = unused_idx { let idx = if let Some(idx) = unused_idx {
idx idx
} else { } else {
self.vec.len() as u32 self.vec.len() as u32
}; };
let handle = $handle_name { idx, generation }; let handle = $handle_name { idx, generation };
let cell = $cell_name { obj, generation }; let cell = $cell_name { obj, generation };
if let Some(idx) = unused_idx { if let Some(idx) = unused_idx {
self.vec[idx as usize] = Some(cell); self.vec[idx as usize] = Some(cell);
} else { } else {
self.vec.push(Some(cell)) self.vec.push(Some(cell))
} }
handle handle
} }
pub fn remove(&mut self, handle: &$handle_name) { pub fn remove(&mut self, handle: &$handle_name) {
// Out of bounds, ignore // Out of bounds, ignore
if handle.idx as usize >= self.vec.len() { if handle.idx as usize >= self.vec.len() {
return; return;
} }
// Remove only if the generation matches // Remove only if the generation matches
if let Some(cell) = &self.vec[handle.idx as usize] { if let Some(cell) = &self.vec[handle.idx as usize] {
if cell.generation == handle.generation { if cell.generation == handle.generation {
self.vec[handle.idx as usize] = None; self.vec[handle.idx as usize] = None;
} }
} }
} }
pub fn get(&self, handle: &$handle_name) -> Option<&$instance_name> { pub fn get(&self, handle: &$handle_name) -> Option<&$instance_name> {
// Out of bounds, ignore // Out of bounds, ignore
if handle.idx as usize >= self.vec.len() { if handle.idx as usize >= self.vec.len() {
return None; return None;
} }
if let Some(cell) = &self.vec[handle.idx as usize] { if let Some(cell) = &self.vec[handle.idx as usize] {
if cell.generation == handle.generation { if cell.generation == handle.generation {
return Some(&cell.obj); return Some(&cell.obj);
} }
} }
None None
} }
pub fn get_mut(&mut self, handle: &$handle_name) -> Option<&mut $instance_name> { pub fn get_mut(&mut self, handle: &$handle_name) -> Option<&mut $instance_name> {
// Out of bounds, ignore // Out of bounds, ignore
if handle.idx as usize >= self.vec.len() { if handle.idx as usize >= self.vec.len() {
return None; return None;
} }
if let Some(cell) = &mut self.vec[handle.idx as usize] { if let Some(cell) = &mut self.vec[handle.idx as usize] {
if cell.generation == handle.generation { if cell.generation == handle.generation {
return Some(&mut cell.obj); return Some(&mut cell.obj);
} }
} }
None None
} }
} }
}; };
} }
/* Example usage: /* Example usage:

View File

@@ -1,246 +1,267 @@
use std::{collections::HashMap}; use std::collections::HashMap;
use anyhow::Context; use anyhow::Context;
use serde::Serialize; use serde::Serialize;
use wayvr_ipc::{client::{WayVRClient, WayVRClientMutex}, ipc, packet_client, packet_server}; use wayvr_ipc::{
client::{WayVRClient, WayVRClientMutex},
ipc, packet_client, packet_server,
};
pub struct WayVRClientState { pub struct WayVRClientState {
pub wayvr_client: WayVRClientMutex, pub wayvr_client: WayVRClientMutex,
pub serial_generator: ipc::SerialGenerator, pub serial_generator: ipc::SerialGenerator,
pub pretty_print: bool, pub pretty_print: bool,
} }
fn handle_empty_result(result: anyhow::Result<()>) { fn handle_empty_result(result: anyhow::Result<()>) {
if let Err(e) = result { if let Err(e) = result {
log::error!("{e:?}"); log::error!("{e:?}");
} }
} }
fn handle_result<T: Serialize>(pretty_print: bool, result: anyhow::Result<T>) { fn handle_result<T: Serialize>(pretty_print: bool, result: anyhow::Result<T>) {
match result { match result {
Ok(t) => { Ok(t) => {
let maybe_json = if pretty_print {
serde_json::to_string_pretty(&t)
} else {
serde_json::to_string(&t)
};
let maybe_json = if pretty_print { match maybe_json {
serde_json::to_string_pretty(&t) Ok(json_string) => println!("{}", json_string),
} else { Err(e) => log::error!("Failed to serialize JSON: {e:?}"),
serde_json::to_string(&t) }
}; }
Err(e) => log::error!("{e:?}"),
match maybe_json { }
Ok(json_string) => println!("{}", json_string),
Err(e) => log::error!("Failed to serialize JSON: {e:?}")
}
}
Err(e) => log::error!("{e:?}")
}
} }
pub async fn wvr_display_create( pub async fn wvr_display_create(
state: &mut WayVRClientState, state: &mut WayVRClientState,
width: u16, width: u16,
height: u16, height: u16,
name: String, name: String,
scale: Option<f32>, scale: Option<f32>,
attach_to: packet_client::AttachTo, attach_to: packet_client::AttachTo,
) { ) {
handle_result(state.pretty_print, handle_result(
WayVRClient::fn_wvr_display_create( state.pretty_print,
state.wayvr_client.clone(), WayVRClient::fn_wvr_display_create(
state.serial_generator.increment_get(), state.wayvr_client.clone(),
packet_client::WvrDisplayCreateParams { state.serial_generator.increment_get(),
width, packet_client::WvrDisplayCreateParams {
height, width,
name, height,
scale, name,
attach_to, scale,
}, attach_to,
) },
.await.context("failed to create display") )
); .await
.context("failed to create display"),
);
} }
pub async fn wvr_display_list( pub async fn wvr_display_list(state: &mut WayVRClientState) {
state: &mut WayVRClientState, handle_result(
) { state.pretty_print,
handle_result(state.pretty_print, WayVRClient::fn_wvr_display_list(
WayVRClient::fn_wvr_display_list( state.wayvr_client.clone(),
state.wayvr_client.clone(), state.serial_generator.increment_get(),
state.serial_generator.increment_get(), )
) .await
.await.context("failed to fetch displays") .context("failed to fetch displays"),
); );
} }
pub async fn wvr_display_get( pub async fn wvr_display_get(
state: &mut WayVRClientState, state: &mut WayVRClientState,
handle: packet_server::WvrDisplayHandle, handle: packet_server::WvrDisplayHandle,
) { ) {
handle_result(state.pretty_print, handle_result(
WayVRClient::fn_wvr_display_get( state.pretty_print,
state.wayvr_client.clone(), WayVRClient::fn_wvr_display_get(
state.serial_generator.increment_get(), state.wayvr_client.clone(),
handle, state.serial_generator.increment_get(),
) handle,
.await.context("failed to fetch display") )
); .await
.context("failed to fetch display"),
);
} }
pub async fn wvr_display_window_list( pub async fn wvr_display_window_list(
state: &mut WayVRClientState, state: &mut WayVRClientState,
handle: packet_server::WvrDisplayHandle, handle: packet_server::WvrDisplayHandle,
) { ) {
handle_result(state.pretty_print, handle_result(
WayVRClient::fn_wvr_display_window_list( state.pretty_print,
state.wayvr_client.clone(), WayVRClient::fn_wvr_display_window_list(
state.serial_generator.increment_get(), state.wayvr_client.clone(),
handle, state.serial_generator.increment_get(),
) handle,
.await.context("failed to list window displays") )
); .await
.context("failed to list window displays"),
);
} }
pub async fn wvr_display_remove( pub async fn wvr_display_remove(
state: &mut WayVRClientState, state: &mut WayVRClientState,
handle: packet_server::WvrDisplayHandle, handle: packet_server::WvrDisplayHandle,
) { ) {
handle_result(state.pretty_print, handle_result(
WayVRClient::fn_wvr_display_remove( state.pretty_print,
state.wayvr_client.clone(), WayVRClient::fn_wvr_display_remove(
state.serial_generator.increment_get(), state.wayvr_client.clone(),
handle, state.serial_generator.increment_get(),
) handle,
.await.context("failed to remove display") )
); .await
.context("failed to remove display"),
);
} }
pub async fn wvr_display_set_visible( pub async fn wvr_display_set_visible(
state: &mut WayVRClientState, state: &mut WayVRClientState,
handle: packet_server::WvrDisplayHandle, handle: packet_server::WvrDisplayHandle,
visible: bool, visible: bool,
) { ) {
handle_empty_result( handle_empty_result(
WayVRClient::fn_wvr_display_set_visible(state.wayvr_client.clone(), handle, visible).await.context("failed to set display visibility"), WayVRClient::fn_wvr_display_set_visible(state.wayvr_client.clone(), handle, visible)
) .await
.context("failed to set display visibility"),
)
} }
pub async fn wvr_window_set_visible( pub async fn wvr_window_set_visible(
state: &mut WayVRClientState, state: &mut WayVRClientState,
handle: packet_server::WvrWindowHandle, handle: packet_server::WvrWindowHandle,
visible: bool, visible: bool,
) { ) {
handle_empty_result( handle_empty_result(
WayVRClient::fn_wvr_window_set_visible(state.wayvr_client.clone(), handle, visible).await.context("failed to set window visibility"), WayVRClient::fn_wvr_window_set_visible(state.wayvr_client.clone(), handle, visible)
) .await
.context("failed to set window visibility"),
)
} }
pub async fn wvr_process_get( pub async fn wvr_process_get(
state: &mut WayVRClientState, state: &mut WayVRClientState,
handle: packet_server::WvrProcessHandle, handle: packet_server::WvrProcessHandle,
) { ) {
handle_result(state.pretty_print, handle_result(
WayVRClient::fn_wvr_process_get( state.pretty_print,
state.wayvr_client.clone(), WayVRClient::fn_wvr_process_get(
state.serial_generator.increment_get(), state.wayvr_client.clone(),
handle, state.serial_generator.increment_get(),
) handle,
.await.context("failed to get process"), )
); .await
.context("failed to get process"),
);
} }
pub async fn wvr_process_list( pub async fn wvr_process_list(state: &mut WayVRClientState) {
state: &mut WayVRClientState, handle_result(
) { state.pretty_print,
handle_result(state.pretty_print, WayVRClient::fn_wvr_process_list(
WayVRClient::fn_wvr_process_list( state.wayvr_client.clone(),
state.wayvr_client.clone(), state.serial_generator.increment_get(),
state.serial_generator.increment_get(), )
) .await
.await.context("failed to list processes"), .context("failed to list processes"),
) )
} }
pub async fn wvr_process_terminate( pub async fn wvr_process_terminate(
state: &mut WayVRClientState, state: &mut WayVRClientState,
handle: packet_server::WvrProcessHandle, handle: packet_server::WvrProcessHandle,
) { ) {
handle_empty_result( handle_empty_result(
WayVRClient::fn_wvr_process_terminate(state.wayvr_client.clone(), handle).await.context("failed to terminate process"), WayVRClient::fn_wvr_process_terminate(state.wayvr_client.clone(), handle)
) .await
.context("failed to terminate process"),
)
} }
pub async fn wvr_process_launch( pub async fn wvr_process_launch(
state: &mut WayVRClientState, state: &mut WayVRClientState,
exec: String, exec: String,
name: String, name: String,
env: Vec<String>, env: Vec<String>,
target_display: packet_server::WvrDisplayHandle, target_display: packet_server::WvrDisplayHandle,
args: String, args: String,
userdata: HashMap<String, String>, userdata: HashMap<String, String>,
) { ) {
handle_result(state.pretty_print, handle_result(
WayVRClient::fn_wvr_process_launch( state.pretty_print,
state.wayvr_client.clone(), WayVRClient::fn_wvr_process_launch(
state.serial_generator.increment_get(), state.wayvr_client.clone(),
packet_client::WvrProcessLaunchParams { state.serial_generator.increment_get(),
env, packet_client::WvrProcessLaunchParams {
exec, env,
name, exec,
target_display, name,
args, target_display,
userdata, args,
}, userdata,
) },
.await.context("failed to launch process"), )
) .await
.context("failed to launch process"),
)
} }
pub async fn wlx_haptics( pub async fn wlx_haptics(
state: &mut WayVRClientState, state: &mut WayVRClientState,
intensity: f32, intensity: f32,
duration: f32, duration: f32,
frequency: f32, frequency: f32,
) { ) {
handle_empty_result( handle_empty_result(
WayVRClient::fn_wlx_haptics( WayVRClient::fn_wlx_haptics(
state.wayvr_client.clone(), state.wayvr_client.clone(),
packet_client::WlxHapticsParams { packet_client::WlxHapticsParams {
intensity, intensity,
duration, duration,
frequency, frequency,
}, },
) )
.await.context("failed to trigger haptics"), .await
) .context("failed to trigger haptics"),
)
} }
pub async fn wlx_panel_modify( pub async fn wlx_panel_modify(
state: &mut WayVRClientState, state: &mut WayVRClientState,
overlay: String, overlay: String,
element: String, element: String,
command: packet_client::WlxModifyPanelCommand, command: packet_client::WlxModifyPanelCommand,
) { ) {
handle_empty_result( handle_empty_result(
WayVRClient::fn_wlx_modify_panel( WayVRClient::fn_wlx_modify_panel(
state.wayvr_client.clone(), state.wayvr_client.clone(),
packet_client::WlxModifyPanelParams { packet_client::WlxModifyPanelParams {
overlay, overlay,
element, element,
command, command,
}, },
) )
.await.context("failed to modify panel"), .await
) .context("failed to modify panel"),
)
} }
pub async fn wlx_input_state( pub async fn wlx_input_state(state: &mut WayVRClientState) {
state: &mut WayVRClientState, handle_result(
) { state.pretty_print,
handle_result(state.pretty_print, WayVRClient::fn_wlx_input_state(
WayVRClient::fn_wlx_input_state( state.wayvr_client.clone(),
state.wayvr_client.clone(), state.serial_generator.increment_get(),
state.serial_generator.increment_get(), )
) .await
.await.context("failed to get input state"), .context("failed to get input state"),
) )
} }

View File

@@ -1,36 +1,47 @@
use std::{collections::HashMap, process::{self, ExitCode}, time::Duration}; use std::{
collections::HashMap,
process::{self, ExitCode},
time::Duration,
};
use anyhow::Context; use anyhow::Context;
use clap::Parser; use clap::Parser;
use env_logger::Env; use env_logger::Env;
use wayvr_ipc::{client::WayVRClient, ipc, packet_client, }; use wayvr_ipc::{client::WayVRClient, ipc, packet_client};
use crate::helper::{wlx_haptics, wlx_input_state, wlx_panel_modify, wvr_display_create, wvr_display_get, wvr_display_list, wvr_display_remove, wvr_display_set_visible, wvr_display_window_list, wvr_process_get, wvr_process_launch, wvr_process_list, wvr_process_terminate, wvr_window_set_visible, WayVRClientState}; use crate::helper::{
WayVRClientState, wlx_haptics, wlx_input_state, wlx_panel_modify, wvr_display_create,
wvr_display_get, wvr_display_list, wvr_display_remove, wvr_display_set_visible,
wvr_display_window_list, wvr_process_get, wvr_process_launch, wvr_process_list,
wvr_process_terminate, wvr_window_set_visible,
};
mod helper; mod helper;
#[tokio::main(flavor = "current_thread")] #[tokio::main(flavor = "current_thread")]
async fn main() -> ExitCode { async fn main() -> ExitCode {
env_logger::init_from_env(Env::default().default_filter_or("info")); env_logger::init_from_env(Env::default().default_filter_or("info"));
let args = Args::parse(); let args = Args::parse();
let mut state = WayVRClientState { let mut state = WayVRClientState {
wayvr_client : WayVRClient::new(&format!("wayvrctl-{}", process::id())).await.inspect_err(|e| { wayvr_client: WayVRClient::new(&format!("wayvrctl-{}", process::id()))
log::error!("Failed to initialize WayVR connection: {e:?}"); .await
process::exit(1); .inspect_err(|e| {
}).unwrap(), log::error!("Failed to initialize WayVR connection: {e:?}");
process::exit(1);
})
.unwrap(),
serial_generator: ipc::SerialGenerator::new(), serial_generator: ipc::SerialGenerator::new(),
pretty_print: args.pretty, pretty_print: args.pretty,
}; };
let maybe_err = if let Subcommands::Batch {fail_fast} = args.command { let maybe_err = if let Subcommands::Batch { fail_fast } = args.command {
run_batch(&mut state, fail_fast).await run_batch(&mut state, fail_fast).await
} else { } else {
run_once(&mut state, args).await run_once(&mut state, args).await
}; };
if let Err(e) = maybe_err{ if let Err(e) = maybe_err {
log::error!("{e:?}"); log::error!("{e:?}");
return ExitCode::FAILURE; return ExitCode::FAILURE;
} else { } else {
@@ -50,30 +61,30 @@ async fn run_batch(state: &mut WayVRClientState, fail_fast: bool) -> anyhow::Res
continue; continue;
} }
if let Err(e) = parse_run_line(state, &line).await.with_context(|| format!("error on line {}", line_no + 1)) { if let Err(e) = parse_run_line(state, &line)
.await
.with_context(|| format!("error on line {}", line_no + 1))
{
if fail_fast { if fail_fast {
return Err(e) return Err(e);
} else { } else {
log::error!("{e:?}"); log::error!("{e:?}");
} }
} }
} }
Ok(()) Ok(())
} }
async fn parse_run_line(state: &mut WayVRClientState, line: &str) -> anyhow::Result<()> { async fn parse_run_line(state: &mut WayVRClientState, line: &str) -> anyhow::Result<()> {
let mut argv = shell_words::split(&line) let mut argv = shell_words::split(&line).with_context(|| format!("parse error"))?;
.with_context(|| format!("parse error"))
?;
// clap expects argv[0] to be the binary name // clap expects argv[0] to be the binary name
argv.insert(0, env!("CARGO_PKG_NAME").to_string()); argv.insert(0, env!("CARGO_PKG_NAME").to_string());
let args = Args::try_parse_from(argv).with_context(|| format!("invalid arguments"))?; let args = Args::try_parse_from(argv).with_context(|| format!("invalid arguments"))?;
run_once(state, args).await?; run_once(state, args).await?;
Ok(()) Ok(())
} }
async fn run_once(state: &mut WayVRClientState, args: Args) -> anyhow::Result<()> { async fn run_once(state: &mut WayVRClientState, args: Args) -> anyhow::Result<()> {
@@ -84,8 +95,21 @@ async fn run_once(state: &mut WayVRClientState, args: Args) -> anyhow::Result<()
Subcommands::InputState => { Subcommands::InputState => {
wlx_input_state(state).await; wlx_input_state(state).await;
} }
Subcommands::DisplayCreate { width, height, name, scale } => { Subcommands::DisplayCreate {
wvr_display_create(state, width, height, name, scale, packet_client::AttachTo::None).await; width,
height,
name,
scale,
} => {
wvr_display_create(
state,
width,
height,
name,
scale,
packet_client::AttachTo::None,
)
.await;
} }
Subcommands::DisplayList => { Subcommands::DisplayList => {
wvr_display_list(state).await; wvr_display_list(state).await;
@@ -102,11 +126,17 @@ async fn run_once(state: &mut WayVRClientState, args: Args) -> anyhow::Result<()
let handle = serde_json::from_str(&handle).context("Invalid handle")?; let handle = serde_json::from_str(&handle).context("Invalid handle")?;
wvr_display_remove(state, handle).await; wvr_display_remove(state, handle).await;
} }
Subcommands::DisplaySetVisible { handle, visible_0_or_1 } => { Subcommands::DisplaySetVisible {
handle,
visible_0_or_1,
} => {
let handle = serde_json::from_str(&handle).context("Invalid handle")?; let handle = serde_json::from_str(&handle).context("Invalid handle")?;
wvr_display_set_visible(state, handle, visible_0_or_1 != 0).await; wvr_display_set_visible(state, handle, visible_0_or_1 != 0).await;
} }
Subcommands::WindowSetVisible { handle, visible_0_or_1 } => { Subcommands::WindowSetVisible {
handle,
visible_0_or_1,
} => {
let handle = serde_json::from_str(&handle).context("Invalid handle")?; let handle = serde_json::from_str(&handle).context("Invalid handle")?;
wvr_window_set_visible(state, handle, visible_0_or_1 != 0).await; wvr_window_set_visible(state, handle, visible_0_or_1 != 0).await;
} }
@@ -121,20 +151,44 @@ async fn run_once(state: &mut WayVRClientState, args: Args) -> anyhow::Result<()
let handle = serde_json::from_str(&handle).context("Invalid handle")?; let handle = serde_json::from_str(&handle).context("Invalid handle")?;
wvr_process_terminate(state, handle).await; wvr_process_terminate(state, handle).await;
} }
Subcommands::ProcessLaunch { exec, name, env, target_display, args } => { Subcommands::ProcessLaunch {
exec,
name,
env,
target_display,
args,
} => {
let handle = serde_json::from_str(&target_display).context("Invalid target_display")?; let handle = serde_json::from_str(&target_display).context("Invalid target_display")?;
wvr_process_launch(state, exec, name, env, handle, args, HashMap::new()).await; wvr_process_launch(state, exec, name, env, handle, args, HashMap::new()).await;
} }
Subcommands::Haptics { intensity, duration, frequency } => { Subcommands::Haptics {
intensity,
duration,
frequency,
} => {
wlx_haptics(state, intensity, duration, frequency).await; wlx_haptics(state, intensity, duration, frequency).await;
} }
Subcommands::PanelModify { overlay, element, command } => { Subcommands::PanelModify {
overlay,
element,
command,
} => {
let command = match command { let command = match command {
SubcommandPanelModify::SetText { text } => packet_client::WlxModifyPanelCommand::SetText(text), SubcommandPanelModify::SetText { text } => {
SubcommandPanelModify::SetColor { hex_color } => packet_client::WlxModifyPanelCommand::SetColor(hex_color), packet_client::WlxModifyPanelCommand::SetText(text)
SubcommandPanelModify::SetImage { absolute_path } => packet_client::WlxModifyPanelCommand::SetImage(absolute_path), }
SubcommandPanelModify::SetVisible { visible_0_or_1 } => packet_client::WlxModifyPanelCommand::SetVisible(visible_0_or_1 != 0), SubcommandPanelModify::SetColor { hex_color } => {
SubcommandPanelModify::SetStickyState { sticky_state_0_or_1 } => packet_client::WlxModifyPanelCommand::SetStickyState(sticky_state_0_or_1 != 0), packet_client::WlxModifyPanelCommand::SetColor(hex_color)
}
SubcommandPanelModify::SetImage { absolute_path } => {
packet_client::WlxModifyPanelCommand::SetImage(absolute_path)
}
SubcommandPanelModify::SetVisible { visible_0_or_1 } => {
packet_client::WlxModifyPanelCommand::SetVisible(visible_0_or_1 != 0)
}
SubcommandPanelModify::SetStickyState {
sticky_state_0_or_1,
} => packet_client::WlxModifyPanelCommand::SetStickyState(sticky_state_0_or_1 != 0),
}; };
wlx_panel_modify(state, overlay, element, command).await; wlx_panel_modify(state, overlay, element, command).await;
@@ -143,7 +197,6 @@ async fn run_once(state: &mut WayVRClientState, args: Args) -> anyhow::Result<()
Ok(()) Ok(())
} }
/// A command-line interface for WayVR IPC /// A command-line interface for WayVR IPC
#[derive(clap::Parser, Debug)] #[derive(clap::Parser, Debug)]
#[command(version, about, long_about = None)] #[command(version, about, long_about = None)]
@@ -161,96 +214,92 @@ struct Args {
enum Subcommands { enum Subcommands {
/// Read commands from stdout, one per line. /// Read commands from stdout, one per line.
Batch { Batch {
/// Stop on the first error /// Stop on the first error
#[arg(short, long)] #[arg(short, long)]
fail_fast: bool, fail_fast: bool,
}, },
/// Get the positions of HMD & controllers /// Get the positions of HMD & controllers
InputState, InputState,
/// Create a new WayVR display /// Create a new WayVR display
DisplayCreate{ DisplayCreate {
width: u16, width: u16,
height: u16, height: u16,
name: String, name: String,
#[arg(short, long)] #[arg(short, long)]
scale: Option<f32>, scale: Option<f32>,
//attach_to: packet_client::AttachTo,
//attach_to: packet_client::AttachTo,
}, },
/// List WayVR displays /// List WayVR displays
DisplayList, DisplayList,
/// Retrieve information about a single WayVR display /// Retrieve information about a single WayVR display
DisplayGet { DisplayGet {
/// A display handle JSON returned by DisplayList or DisplayCreate /// A display handle JSON returned by DisplayList or DisplayCreate
handle: String, handle: String,
}, },
/// List windows attached to a WayVR display /// List windows attached to a WayVR display
DisplayWindowList { DisplayWindowList {
/// A display handle JSON returned by DisplayList or DisplayCreate /// A display handle JSON returned by DisplayList or DisplayCreate
handle: String, handle: String,
}, },
/// Delete a WayVR display /// Delete a WayVR display
DisplayRemove { DisplayRemove {
/// A display handle JSON returned by DisplayList or DisplayCreate /// A display handle JSON returned by DisplayList or DisplayCreate
handle: String, handle: String,
}, },
/// Change the visibility of a WayVR display /// Change the visibility of a WayVR display
DisplaySetVisible { DisplaySetVisible {
/// A display handle JSON returned by DisplayList or DisplayCreate /// A display handle JSON returned by DisplayList or DisplayCreate
handle: String, handle: String,
visible_0_or_1: u8, visible_0_or_1: u8,
}, },
// DisplaySetLayout skipped // DisplaySetLayout skipped
/// Change the visibility of a window on a WayVR display /// Change the visibility of a window on a WayVR display
WindowSetVisible { WindowSetVisible {
/// A JSON window handle returned by DisplayWindowList /// A JSON window handle returned by DisplayWindowList
handle: String, handle: String,
visible_0_or_1: u8, visible_0_or_1: u8,
}, },
/// Retrieve information about a WayVR-managed process /// Retrieve information about a WayVR-managed process
ProcessGet { ProcessGet {
/// A JSON process handle returned by ProcessList or ProcessLaunch /// A JSON process handle returned by ProcessList or ProcessLaunch
handle: String, handle: String,
}, },
/// List all processes managed by WayVR /// List all processes managed by WayVR
ProcessList, ProcessList,
/// Terminate a WayVR-managed process /// Terminate a WayVR-managed process
ProcessTerminate { ProcessTerminate {
/// A JSON process handle returned by ProcessList or ProcessLaunch /// A JSON process handle returned by ProcessList or ProcessLaunch
handle: String, handle: String,
}, },
/// Launch a new process inside WayVR /// Launch a new process inside WayVR
ProcessLaunch { ProcessLaunch {
exec: String, exec: String,
name: String, name: String,
env: Vec<String>, env: Vec<String>,
/// A display handle JSON returned by DisplayList or DisplayCreate /// A display handle JSON returned by DisplayList or DisplayCreate
target_display: String, target_display: String,
args: String, args: String,
}, },
/// Trigger haptics on the user's controller /// Trigger haptics on the user's controller
Haptics { Haptics {
#[arg(short, long, default_value = "0.25")] #[arg(short, long, default_value = "0.25")]
intensity: f32, intensity: f32,
#[arg(short, long , default_value = "0.1")]
duration: f32,
#[arg(short, long, default_value = "0.1")] #[arg(short, long, default_value = "0.1")]
frequency: f32, duration: f32,
#[arg(short, long, default_value = "0.1")]
frequency: f32,
}, },
/// Apply a modification to a panel element /// Apply a modification to a panel element
PanelModify { PanelModify {
/// The name of the overlay (XML file name without extension) /// The name of the overlay (XML file name without extension)
overlay: String, overlay: String,
/// The id of the element to modify, as set in the XML /// The id of the element to modify, as set in the XML
element: String, element: String,
/// Command to execute /// Command to execute
#[command(subcommand)] #[command(subcommand)]
command: SubcommandPanelModify, command: SubcommandPanelModify,
} },
} }
#[derive(clap::Parser, Debug)] #[derive(clap::Parser, Debug)]
@@ -271,11 +320,7 @@ enum SubcommandPanelModify {
absolute_path: String, absolute_path: String,
}, },
/// Set the visibility of a <div>, <rectangle>, <label>, <sprite> or <image> /// Set the visibility of a <div>, <rectangle>, <label>, <sprite> or <image>
SetVisible { SetVisible { visible_0_or_1: u8 },
visible_0_or_1: u8,
},
/// Set the sticky state of a <Button>. Intended for buttons without `sticky="1"`. /// Set the sticky state of a <Button>. Intended for buttons without `sticky="1"`.
SetStickyState { SetStickyState { sticky_state_0_or_1: u8 },
sticky_state_0_or_1: u8,
}
} }

View File

@@ -1,25 +1,24 @@
use crate::{ use crate::{
animation::{Animation, AnimationEasing}, animation::{Animation, AnimationEasing},
assets::AssetPath, assets::AssetPath,
components::{self, tooltip::ComponentTooltip, Component, ComponentBase, ComponentTrait, RefreshData}, components::{self, Component, ComponentBase, ComponentTrait, RefreshData, tooltip::ComponentTooltip},
drawing::{self, Boundary, Color}, drawing::{self, Boundary, Color},
event::{CallbackDataCommon, EventListenerCollection, EventListenerID, EventListenerKind}, event::{CallbackDataCommon, EventListenerCollection, EventListenerID, EventListenerKind},
i18n::Translation, i18n::Translation,
layout::{LayoutTask, WidgetID, WidgetPair}, layout::{LayoutTask, WidgetID, WidgetPair},
renderer_vk::{ renderer_vk::{
text::{ text::{
custom_glyph::{CustomGlyphContent, CustomGlyphData},
FontWeight, TextStyle, FontWeight, TextStyle,
custom_glyph::{CustomGlyphContent, CustomGlyphData},
}, },
util::centered_matrix, util::centered_matrix,
}, },
widget::{ widget::{
self, self, ConstructEssentials, EventResult, WidgetData,
label::{WidgetLabel, WidgetLabelParams}, label::{WidgetLabel, WidgetLabelParams},
rectangle::{WidgetRectangle, WidgetRectangleParams}, rectangle::{WidgetRectangle, WidgetRectangleParams},
sprite::{WidgetSprite, WidgetSpriteParams}, sprite::{WidgetSprite, WidgetSpriteParams},
util::WLength, util::WLength,
ConstructEssentials, EventResult, WidgetData,
}, },
}; };
use glam::{Mat4, Vec3}; use glam::{Mat4, Vec3};
@@ -28,7 +27,7 @@ use std::{
rc::Rc, rc::Rc,
time::{Duration, Instant}, time::{Duration, Instant},
}; };
use taffy::{prelude::length, AlignItems, JustifyContent}; use taffy::{AlignItems, JustifyContent, prelude::length};
pub struct Params<'a> { pub struct Params<'a> {
pub text: Option<Translation>, // if unset, label will not be populated pub text: Option<Translation>, // if unset, label will not be populated

View File

@@ -1,7 +1,7 @@
use std::{cell::RefCell, rc::Rc}; use std::{cell::RefCell, rc::Rc};
use taffy::{ use taffy::{
prelude::{length, percent},
AlignItems, AlignItems,
prelude::{length, percent},
}; };
use crate::{ use crate::{
@@ -13,10 +13,10 @@ use crate::{
layout::{self, WidgetID, WidgetPair}, layout::{self, WidgetID, WidgetPair},
renderer_vk::text::{FontWeight, TextStyle}, renderer_vk::text::{FontWeight, TextStyle},
widget::{ widget::{
ConstructEssentials, EventResult,
label::{WidgetLabel, WidgetLabelParams}, label::{WidgetLabel, WidgetLabelParams},
rectangle::{WidgetRectangle, WidgetRectangleParams}, rectangle::{WidgetRectangle, WidgetRectangleParams},
util::WLength, util::WLength,
ConstructEssentials, EventResult,
}, },
}; };

View File

@@ -18,11 +18,11 @@ use crate::{
util, util,
}, },
widget::{ widget::{
ConstructEssentials, EventResult,
div::WidgetDiv, div::WidgetDiv,
label::{WidgetLabel, WidgetLabelParams}, label::{WidgetLabel, WidgetLabelParams},
rectangle::{WidgetRectangle, WidgetRectangleParams}, rectangle::{WidgetRectangle, WidgetRectangleParams},
util::WLength, util::WLength,
ConstructEssentials, EventResult,
}, },
}; };

View File

@@ -10,8 +10,8 @@ use crate::{
globals::Globals, globals::Globals,
layout::Widget, layout::Widget,
renderer_vk::text::{ renderer_vk::text::{
custom_glyph::{CustomGlyph, CustomGlyphData},
TextShadow, TextShadow,
custom_glyph::{CustomGlyph, CustomGlyphData},
}, },
stack::{self, ScissorBoundary, ScissorStack, TransformStack}, stack::{self, ScissorBoundary, ScissorStack, TransformStack},
widget::{self, ScrollbarInfo, WidgetState}, widget::{self, ScrollbarInfo, WidgetState},

View File

@@ -1,13 +1,13 @@
use crate::{ use crate::{
assets::AssetPath, assets::AssetPath,
components::{button, tooltip, Component}, components::{Component, button, tooltip},
drawing::Color, drawing::Color,
i18n::Translation, i18n::Translation,
layout::WidgetID, layout::WidgetID,
parser::{ parser::{
parse_check_f32, parse_check_i32, parse_children, parse_f32, print_invalid_attrib, process_component, AttribPair, ParserContext, ParserFile, parse_check_f32, parse_check_i32, parse_children, parse_f32,
print_invalid_attrib, process_component,
style::{parse_color_opt, parse_round, parse_style, parse_text_style}, style::{parse_color_opt, parse_round, parse_style, parse_text_style},
AttribPair, ParserContext, ParserFile,
}, },
widget::util::WLength, widget::util::WLength,
}; };

View File

@@ -9,7 +9,7 @@ mod widget_rectangle;
mod widget_sprite; mod widget_sprite;
use crate::{ use crate::{
assets::{normalize_path, AssetPath, AssetPathOwned}, assets::{AssetPath, AssetPathOwned, normalize_path},
components::{Component, ComponentWeak}, components::{Component, ComponentWeak},
drawing::{self}, drawing::{self},
globals::WguiGlobals, globals::WguiGlobals,

View File

@@ -6,8 +6,8 @@ use taffy::{
use crate::{ use crate::{
drawing, drawing,
parser::{ parser::{
is_percent, parse_color_hex, parse_f32, parse_percent, parse_size_unit, parse_val, print_invalid_attrib, AttribPair, is_percent, parse_color_hex, parse_f32, parse_percent, parse_size_unit, parse_val,
print_invalid_value, AttribPair, print_invalid_attrib, print_invalid_value,
}, },
renderer_vk::text::{FontWeight, HorizontalAlign, TextStyle}, renderer_vk::text::{FontWeight, HorizontalAlign, TextStyle},
widget::util::WLength, widget::util::WLength,

View File

@@ -2,9 +2,8 @@ use crate::{
assets::AssetPath, assets::AssetPath,
layout::WidgetID, layout::WidgetID,
parser::{ parser::{
parse_children, parse_widget_universal, print_invalid_attrib, AttribPair, ParserContext, ParserFile, parse_children, parse_widget_universal, print_invalid_attrib,
style::{parse_color, parse_round, parse_style}, style::{parse_color, parse_round, parse_style},
AttribPair, ParserContext, ParserFile,
}, },
renderer_vk::text::custom_glyph::{CustomGlyphContent, CustomGlyphData}, renderer_vk::text::custom_glyph::{CustomGlyphContent, CustomGlyphData},
widget::image::{WidgetImage, WidgetImageParams}, widget::image::{WidgetImage, WidgetImageParams},

View File

@@ -2,9 +2,8 @@ use crate::{
drawing::GradientMode, drawing::GradientMode,
layout::WidgetID, layout::WidgetID,
parser::{ parser::{
parse_children, parse_widget_universal, print_invalid_attrib, AttribPair, ParserContext, ParserFile, parse_children, parse_widget_universal, print_invalid_attrib,
style::{parse_color, parse_round, parse_style}, style::{parse_color, parse_round, parse_style},
AttribPair, ParserContext, ParserFile,
}, },
widget::rectangle::{WidgetRectangle, WidgetRectangleParams}, widget::rectangle::{WidgetRectangle, WidgetRectangleParams},
}; };

View File

@@ -1,7 +1,7 @@
use crate::{ use crate::{
assets::AssetPath, assets::AssetPath,
layout::WidgetID, layout::WidgetID,
parser::{parse_children, parse_widget_universal, style::parse_style, AttribPair, ParserContext, ParserFile}, parser::{AttribPair, ParserContext, ParserFile, parse_children, parse_widget_universal, style::parse_style},
renderer_vk::text::custom_glyph::{CustomGlyphContent, CustomGlyphData}, renderer_vk::text::custom_glyph::{CustomGlyphContent, CustomGlyphData},
widget::sprite::{WidgetSprite, WidgetSpriteParams}, widget::sprite::{WidgetSprite, WidgetSpriteParams},
}; };

View File

@@ -2,22 +2,22 @@ use std::{cell::RefCell, rc::Rc, sync::Arc};
use cosmic_text::Buffer; use cosmic_text::Buffer;
use glam::{Mat4, Vec2, Vec3}; use glam::{Mat4, Vec2, Vec3};
use slotmap::{new_key_type, SlotMap}; use slotmap::{SlotMap, new_key_type};
use vulkano::pipeline::graphics::viewport; use vulkano::pipeline::graphics::viewport;
use crate::{ use crate::{
drawing::{self}, drawing::{self},
font_config, font_config,
gfx::{cmd::GfxCommandBuffer, WGfx}, gfx::{WGfx, cmd::GfxCommandBuffer},
renderer_vk::image::{ImagePipeline, ImageRenderer}, renderer_vk::image::{ImagePipeline, ImageRenderer},
}; };
use super::{ use super::{
rect::{RectPipeline, RectRenderer}, rect::{RectPipeline, RectRenderer},
text::{ text::{
DEFAULT_METRICS, SWASH_CACHE, TextArea, TextBounds,
text_atlas::{TextAtlas, TextPipeline}, text_atlas::{TextAtlas, TextPipeline},
text_renderer::TextRenderer, text_renderer::TextRenderer,
TextArea, TextBounds, DEFAULT_METRICS, SWASH_CACHE,
}, },
viewport::Viewport, viewport::Viewport,
}; };

View File

@@ -14,10 +14,10 @@ use vulkano::{
use crate::{ use crate::{
drawing::{Boundary, ImagePrimitive}, drawing::{Boundary, ImagePrimitive},
gfx::{ gfx::{
BLEND_ALPHA, WGfx,
cmd::GfxCommandBuffer, cmd::GfxCommandBuffer,
pass::WGfxPass, pass::WGfxPass,
pipeline::{WGfxPipeline, WPipelineCreateInfo}, pipeline::{WGfxPipeline, WPipelineCreateInfo},
WGfx, BLEND_ALPHA,
}, },
renderer_vk::{ renderer_vk::{
model_buffer::ModelBuffer, model_buffer::ModelBuffer,

View File

@@ -10,10 +10,10 @@ use vulkano::{
use crate::{ use crate::{
drawing::{Boundary, Rectangle}, drawing::{Boundary, Rectangle},
gfx::{ gfx::{
BLEND_ALPHA, WGfx,
cmd::GfxCommandBuffer, cmd::GfxCommandBuffer,
pass::WGfxPass, pass::WGfxPass,
pipeline::{WGfxPipeline, WPipelineCreateInfo}, pipeline::{WGfxPipeline, WPipelineCreateInfo},
WGfx, BLEND_ALPHA,
}, },
renderer_vk::model_buffer::ModelBuffer, renderer_vk::model_buffer::ModelBuffer,
}; };

View File

@@ -1,8 +1,8 @@
use std::{ use std::{
f32, f32,
sync::{ sync::{
atomic::{AtomicUsize, Ordering},
Arc, Arc,
atomic::{AtomicUsize, Ordering},
}, },
}; };

View File

@@ -8,7 +8,7 @@ use crate::{
globals::Globals, globals::Globals,
layout::WidgetID, layout::WidgetID,
renderer_vk::text::custom_glyph::CustomGlyphData, renderer_vk::text::custom_glyph::CustomGlyphData,
widget::{util::WLength, WidgetStateFlags}, widget::{WidgetStateFlags, util::WLength},
}; };
use super::{WidgetObj, WidgetState}; use super::{WidgetObj, WidgetState};

View File

@@ -206,11 +206,7 @@ impl EventResult {
#[must_use] #[must_use]
pub fn merge(self, other: Self) -> Self { pub fn merge(self, other: Self) -> Self {
if self > other { if self > other { self } else { other }
self
} else {
other
}
} }
} }

View File

@@ -4,7 +4,7 @@ use crate::{
drawing::{self, GradientMode, PrimitiveExtent}, drawing::{self, GradientMode, PrimitiveExtent},
event::CallbackDataCommon, event::CallbackDataCommon,
layout::WidgetID, layout::WidgetID,
widget::{util::WLength, WidgetStateFlags}, widget::{WidgetStateFlags, util::WLength},
}; };
use super::{WidgetObj, WidgetState}; use super::{WidgetObj, WidgetState};

View File

@@ -9,8 +9,8 @@ use crate::{
globals::Globals, globals::Globals,
layout::WidgetID, layout::WidgetID,
renderer_vk::text::{ renderer_vk::text::{
custom_glyph::{CustomGlyph, CustomGlyphData},
DEFAULT_METRICS, DEFAULT_METRICS,
custom_glyph::{CustomGlyph, CustomGlyphData},
}, },
widget::WidgetStateFlags, widget::WidgetStateFlags,
}; };

View File

@@ -33,7 +33,6 @@ use crate::{
use super::timer::GuiTimer; use super::timer::GuiTimer;
pub mod button; pub mod button;
mod helper;
mod label; mod label;
const DEFAULT_MAX_SIZE: f32 = 2048.0; const DEFAULT_MAX_SIZE: f32 = 2048.0;