refactors & clippy recommendations
This commit is contained in:
10
Cargo.toml
10
Cargo.toml
@@ -6,6 +6,12 @@ debug = true
|
|||||||
name = "wlx-overlay-s"
|
name = "wlx-overlay-s"
|
||||||
version = "25.4.0"
|
version = "25.4.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
license = "GPL-3.0-only"
|
||||||
|
authors = ["galister"]
|
||||||
|
description = "Access your Wayland/X11 desktop from Monado/WiVRn/SteamVR. Now with Vulkan!"
|
||||||
|
repository = "https://github.com/galister/wlx-overlay-s"
|
||||||
|
keywords = ["linux", "openvr", "openxr", "x11", "wayland", "openvr-overlay", "openxr-overlay"]
|
||||||
|
categories = ["games"]
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
@@ -39,7 +45,7 @@ ovr_overlay = { features = [
|
|||||||
"ovr_input",
|
"ovr_input",
|
||||||
"ovr_system",
|
"ovr_system",
|
||||||
], git = "https://github.com/galister/ovr_overlay_oyasumi", optional = true }
|
], git = "https://github.com/galister/ovr_overlay_oyasumi", optional = true }
|
||||||
regex = "1.10.4"
|
regex = "1.11.1"
|
||||||
rodio = { version = "0.20.1", default-features = false, features = [
|
rodio = { version = "0.20.1", default-features = false, features = [
|
||||||
"wav",
|
"wav",
|
||||||
"hound",
|
"hound",
|
||||||
@@ -91,7 +97,7 @@ wayvr_ipc = { git = "https://github.com/olekolek1000/wayvr-ipc.git", rev = "a725
|
|||||||
################################
|
################################
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
regex = { version = "*" }
|
regex = { version = "1.11.1" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["openvr", "openxr", "osc", "x11", "wayland", "wayvr"]
|
default = ["openvr", "openxr", "osc", "x11", "wayland", "wayvr"]
|
||||||
|
|||||||
@@ -69,17 +69,17 @@ where
|
|||||||
app.screens.clear();
|
app.screens.clear();
|
||||||
let data = if let Some(wl) = wl.as_mut() {
|
let data = if let Some(wl) = wl.as_mut() {
|
||||||
keymap = get_keymap_wl()
|
keymap = get_keymap_wl()
|
||||||
.map_err(|f| log::warn!("Could not load keyboard layout: {}", f))
|
.map_err(|f| log::warn!("Could not load keyboard layout: {f}"))
|
||||||
.ok();
|
.ok();
|
||||||
crate::overlays::screen::create_screens_wayland(wl, app)?
|
crate::overlays::screen::create_screens_wayland(wl, app)
|
||||||
} else {
|
} else {
|
||||||
keymap = get_keymap_x11()
|
keymap = get_keymap_x11()
|
||||||
.map_err(|f| log::warn!("Could not load keyboard layout: {}", f))
|
.map_err(|f| log::warn!("Could not load keyboard layout: {f}"))
|
||||||
.ok();
|
.ok();
|
||||||
match crate::overlays::screen::create_screens_x11pw(app) {
|
match crate::overlays::screen::create_screens_x11pw(app) {
|
||||||
Ok(data) => data,
|
Ok(data) => data,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::info!("Will not use PipeWire capture: {:?}", e);
|
log::info!("Will not use PipeWire capture: {e:?}");
|
||||||
crate::overlays::screen::create_screens_xshm(app)?
|
crate::overlays::screen::create_screens_xshm(app)?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -127,6 +127,8 @@ where
|
|||||||
Ok(vec![])
|
Ok(vec![])
|
||||||
}
|
}
|
||||||
#[cfg(feature = "wayland")]
|
#[cfg(feature = "wayland")]
|
||||||
|
#[allow(clippy::too_many_lines, clippy::cognitive_complexity)]
|
||||||
|
#[allow(clippy::all, clippy::pedantic, clippy::nursery, clippy::cargo)]
|
||||||
pub fn update(&mut self, app: &mut AppState) -> anyhow::Result<Vec<OverlayData<T>>> {
|
pub fn update(&mut self, app: &mut AppState) -> anyhow::Result<Vec<OverlayData<T>>> {
|
||||||
use crate::overlays::{
|
use crate::overlays::{
|
||||||
screen::{create_screen_interaction, create_screen_renderer_wl, load_pw_token_config},
|
screen::{create_screen_interaction, create_screen_renderer_wl, load_pw_token_config},
|
||||||
@@ -154,7 +156,7 @@ where
|
|||||||
if create_ran {
|
if create_ran {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let data = crate::overlays::screen::create_screens_wayland(wl, app)?;
|
let data = crate::overlays::screen::create_screens_wayland(wl, app);
|
||||||
create_ran = true;
|
create_ran = true;
|
||||||
for (meta, state, backend) in data.screens {
|
for (meta, state, backend) in data.screens {
|
||||||
self.overlays.insert(
|
self.overlays.insert(
|
||||||
@@ -337,7 +339,7 @@ where
|
|||||||
if !any_shown && *o.state.name == *WATCH_NAME {
|
if !any_shown && *o.state.name == *WATCH_NAME {
|
||||||
o.state.reset(app, true);
|
o.state.reset(app, true);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ impl InputState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pre_update(&mut self) {
|
pub const fn pre_update(&mut self) {
|
||||||
self.pointers[0].before = self.pointers[0].now;
|
self.pointers[0].before = self.pointers[0].now;
|
||||||
self.pointers[1].before = self.pointers[1].now;
|
self.pointers[1].before = self.pointers[1].now;
|
||||||
}
|
}
|
||||||
@@ -58,6 +58,73 @@ impl InputState {
|
|||||||
pub fn post_update(&mut self, session: &AppSession) {
|
pub fn post_update(&mut self, session: &AppSession) {
|
||||||
for hand in &mut self.pointers {
|
for hand in &mut self.pointers {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
|
debug_print_hand(hand);
|
||||||
|
|
||||||
|
if hand.now.click {
|
||||||
|
hand.last_click = Instant::now();
|
||||||
|
}
|
||||||
|
|
||||||
|
if hand.now.click_modifier_right {
|
||||||
|
hand.interaction.mode = PointerMode::Right;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if hand.now.click_modifier_middle {
|
||||||
|
hand.interaction.mode = PointerMode::Middle;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let hmd_up = self.hmd.transform_vector3a(Vec3A::Y);
|
||||||
|
let dot = hmd_up.dot(hand.pose.transform_vector3a(Vec3A::X))
|
||||||
|
* 2.0f32.mul_add(-(hand.idx as f32), 1.0);
|
||||||
|
|
||||||
|
hand.interaction.mode = if dot < -0.85 {
|
||||||
|
PointerMode::Right
|
||||||
|
} else if dot > 0.7 {
|
||||||
|
PointerMode::Middle
|
||||||
|
} else {
|
||||||
|
PointerMode::Left
|
||||||
|
};
|
||||||
|
|
||||||
|
let middle_click_orientation = false;
|
||||||
|
let right_click_orientation = false;
|
||||||
|
match hand.interaction.mode {
|
||||||
|
PointerMode::Middle => {
|
||||||
|
if !middle_click_orientation {
|
||||||
|
hand.interaction.mode = PointerMode::Left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PointerMode::Right => {
|
||||||
|
if !right_click_orientation {
|
||||||
|
hand.interaction.mode = PointerMode::Left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if hand.now.alt_click != hand.before.alt_click {
|
||||||
|
// Reap previous processes
|
||||||
|
self.processes
|
||||||
|
.retain_mut(|child| !matches!(child.try_wait(), Ok(Some(_))));
|
||||||
|
|
||||||
|
let mut args = if hand.now.alt_click {
|
||||||
|
session.config.alt_click_down.iter()
|
||||||
|
} else {
|
||||||
|
session.config.alt_click_up.iter()
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(program) = args.next() {
|
||||||
|
if let Ok(child) = Command::new(program).args(args).spawn() {
|
||||||
|
self.processes.push(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
fn debug_print_hand(hand: &Pointer) {
|
||||||
{
|
{
|
||||||
if hand.now.click != hand.before.click {
|
if hand.now.click != hand.before.click {
|
||||||
log::debug!("Hand {}: click {}", hand.idx, hand.now.click);
|
log::debug!("Hand {}: click {}", hand.idx, hand.now.click);
|
||||||
@@ -102,68 +169,6 @@ impl InputState {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if hand.now.click {
|
|
||||||
hand.last_click = Instant::now();
|
|
||||||
}
|
|
||||||
|
|
||||||
if hand.now.click_modifier_right {
|
|
||||||
hand.interaction.mode = PointerMode::Right;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if hand.now.click_modifier_middle {
|
|
||||||
hand.interaction.mode = PointerMode::Middle;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let hmd_up = self.hmd.transform_vector3a(Vec3A::Y);
|
|
||||||
let dot =
|
|
||||||
hmd_up.dot(hand.pose.transform_vector3a(Vec3A::X)) * (1.0 - 2.0 * hand.idx as f32);
|
|
||||||
|
|
||||||
hand.interaction.mode = if dot < -0.85 {
|
|
||||||
PointerMode::Right
|
|
||||||
} else if dot > 0.7 {
|
|
||||||
PointerMode::Middle
|
|
||||||
} else {
|
|
||||||
PointerMode::Left
|
|
||||||
};
|
|
||||||
|
|
||||||
let middle_click_orientation = false;
|
|
||||||
let right_click_orientation = false;
|
|
||||||
match hand.interaction.mode {
|
|
||||||
PointerMode::Middle => {
|
|
||||||
if !middle_click_orientation {
|
|
||||||
hand.interaction.mode = PointerMode::Left;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PointerMode::Right => {
|
|
||||||
if !right_click_orientation {
|
|
||||||
hand.interaction.mode = PointerMode::Left;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
|
|
||||||
if hand.now.alt_click != hand.before.alt_click {
|
|
||||||
// Reap previous processes
|
|
||||||
self.processes
|
|
||||||
.retain_mut(|child| !matches!(child.try_wait(), Ok(Some(_))));
|
|
||||||
|
|
||||||
let mut args = if hand.now.alt_click {
|
|
||||||
session.config.alt_click_down.iter()
|
|
||||||
} else {
|
|
||||||
session.config.alt_click_up.iter()
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(program) = args.next() {
|
|
||||||
if let Ok(child) = Command::new(program).args(args).spawn() {
|
|
||||||
self.processes.push(child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct InteractionState {
|
pub struct InteractionState {
|
||||||
@@ -207,10 +212,10 @@ impl Pointer {
|
|||||||
idx,
|
idx,
|
||||||
pose: Affine3A::IDENTITY,
|
pose: Affine3A::IDENTITY,
|
||||||
raw_pose: Affine3A::IDENTITY,
|
raw_pose: Affine3A::IDENTITY,
|
||||||
now: Default::default(),
|
now: PointerState::default(),
|
||||||
before: Default::default(),
|
before: PointerState::default(),
|
||||||
last_click: Instant::now(),
|
last_click: Instant::now(),
|
||||||
interaction: Default::default(),
|
interaction: InteractionState::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -320,6 +325,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_lines, clippy::cognitive_complexity)]
|
||||||
fn interact_hand<O>(
|
fn interact_hand<O>(
|
||||||
idx: usize,
|
idx: usize,
|
||||||
overlays: &mut OverlayContainer<O>,
|
overlays: &mut OverlayContainer<O>,
|
||||||
@@ -434,7 +440,7 @@ where
|
|||||||
|
|
||||||
if can_curve {
|
if can_curve {
|
||||||
let cur = hovered.state.curvature.unwrap_or(0.0);
|
let cur = hovered.state.curvature.unwrap_or(0.0);
|
||||||
let new = (cur - scroll_y * 0.01).min(0.5);
|
let new = scroll_y.mul_add(-0.01, cur).min(0.5);
|
||||||
if new <= f32::EPSILON {
|
if new <= f32::EPSILON {
|
||||||
hovered.state.curvature = None;
|
hovered.state.curvature = None;
|
||||||
} else {
|
} else {
|
||||||
@@ -480,7 +486,7 @@ impl Pointer {
|
|||||||
if let Some(hit) = self.ray_test(
|
if let Some(hit) = self.ray_test(
|
||||||
overlay.state.id,
|
overlay.state.id,
|
||||||
&overlay.state.transform,
|
&overlay.state.transform,
|
||||||
&overlay.state.curvature,
|
overlay.state.curvature.as_ref(),
|
||||||
) {
|
) {
|
||||||
if hit.dist.is_infinite() || hit.dist.is_nan() {
|
if hit.dist.is_infinite() || hit.dist.is_nan() {
|
||||||
continue;
|
continue;
|
||||||
@@ -491,7 +497,7 @@ impl Pointer {
|
|||||||
|
|
||||||
hits.sort_by(|a, b| a.dist.total_cmp(&b.dist));
|
hits.sort_by(|a, b| a.dist.total_cmp(&b.dist));
|
||||||
|
|
||||||
for hit in hits.iter() {
|
for hit in &hits {
|
||||||
let overlay = overlays.get_by_id(hit.overlay).unwrap(); // safe because we just got the id from the overlay
|
let overlay = overlays.get_by_id(hit.overlay).unwrap(); // safe because we just got the id from the overlay
|
||||||
|
|
||||||
let uv = overlay
|
let uv = overlay
|
||||||
@@ -573,7 +579,7 @@ impl Pointer {
|
|||||||
.state
|
.state
|
||||||
.transform
|
.transform
|
||||||
.matrix3
|
.matrix3
|
||||||
.mul_scalar(1.0 - 0.025 * self.now.scroll_y);
|
.mul_scalar(0.025f32.mul_add(-self.now.scroll_y, 1.0));
|
||||||
} else if config.allow_sliding && self.now.scroll_y.is_finite() {
|
} else if config.allow_sliding && self.now.scroll_y.is_finite() {
|
||||||
grab_data.offset.z -= self.now.scroll_y * 0.05;
|
grab_data.offset.z -= self.now.scroll_y * 0.05;
|
||||||
}
|
}
|
||||||
@@ -620,12 +626,19 @@ impl Pointer {
|
|||||||
&self,
|
&self,
|
||||||
overlay: OverlayID,
|
overlay: OverlayID,
|
||||||
transform: &Affine3A,
|
transform: &Affine3A,
|
||||||
curvature: &Option<f32>,
|
curvature: Option<&f32>,
|
||||||
) -> Option<RayHit> {
|
) -> Option<RayHit> {
|
||||||
let (dist, local_pos) = match curvature {
|
let (dist, local_pos) = curvature.map_or_else(
|
||||||
Some(curvature) => raycast_cylinder(&self.pose, Vec3A::NEG_Z, transform, *curvature),
|
|| {
|
||||||
_ => raycast_plane(&self.pose, Vec3A::NEG_Z, transform, Vec3A::NEG_Z),
|
Some(raycast_plane(
|
||||||
}?;
|
&self.pose,
|
||||||
|
Vec3A::NEG_Z,
|
||||||
|
transform,
|
||||||
|
Vec3A::NEG_Z,
|
||||||
|
))
|
||||||
|
},
|
||||||
|
|curvature| raycast_cylinder(&self.pose, Vec3A::NEG_Z, transform, *curvature),
|
||||||
|
)?;
|
||||||
|
|
||||||
if dist < 0.0 {
|
if dist < 0.0 {
|
||||||
// hit is behind us
|
// hit is behind us
|
||||||
@@ -646,7 +659,7 @@ fn raycast_plane(
|
|||||||
source_fwd: Vec3A,
|
source_fwd: Vec3A,
|
||||||
plane: &Affine3A,
|
plane: &Affine3A,
|
||||||
plane_norm: Vec3A,
|
plane_norm: Vec3A,
|
||||||
) -> Option<(f32, Vec2)> {
|
) -> (f32, Vec2) {
|
||||||
let plane_normal = plane.transform_vector3a(plane_norm);
|
let plane_normal = plane.transform_vector3a(plane_norm);
|
||||||
let ray_dir = source.transform_vector3a(source_fwd);
|
let ray_dir = source.transform_vector3a(source_fwd);
|
||||||
|
|
||||||
@@ -658,7 +671,7 @@ fn raycast_plane(
|
|||||||
.transform_point3a(source.translation + ray_dir * dist)
|
.transform_point3a(source.translation + ray_dir * dist)
|
||||||
.xy();
|
.xy();
|
||||||
|
|
||||||
Some((dist, hit_local))
|
(dist, hit_local)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn raycast_cylinder(
|
fn raycast_cylinder(
|
||||||
@@ -675,27 +688,27 @@ fn raycast_cylinder(
|
|||||||
}
|
}
|
||||||
.inverse();
|
.inverse();
|
||||||
|
|
||||||
let r = size / (2.0 * PI * curvature);
|
let radius = size / (2.0 * PI * curvature);
|
||||||
|
|
||||||
let ray_dir = to_local.transform_vector3a(source.transform_vector3a(source_fwd));
|
let ray_dir = to_local.transform_vector3a(source.transform_vector3a(source_fwd));
|
||||||
let ray_origin = to_local.transform_point3a(source.translation) + Vec3A::NEG_Z * r;
|
let ray_origin = to_local.transform_point3a(source.translation) + Vec3A::NEG_Z * radius;
|
||||||
|
|
||||||
let d = ray_dir.xz();
|
let v_dir = ray_dir.xz();
|
||||||
let s = ray_origin.xz();
|
let v_pos = ray_origin.xz();
|
||||||
|
|
||||||
let a = d.dot(d);
|
let l_dir = v_dir.dot(v_dir);
|
||||||
let b = d.dot(s);
|
let l_pos = v_dir.dot(v_pos);
|
||||||
let c = s.dot(s) - r * r;
|
let c = radius.mul_add(-radius, v_pos.dot(v_pos));
|
||||||
|
|
||||||
let d = (b * b) - (a * c);
|
let d = l_pos.mul_add(l_pos, -(l_dir * c));
|
||||||
if d < f32::EPSILON {
|
if d < f32::EPSILON {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let sqrt_d = d.sqrt();
|
let sqrt_d = d.sqrt();
|
||||||
|
|
||||||
let t1 = (-b - sqrt_d) / a;
|
let t1 = (-l_pos - sqrt_d) / l_dir;
|
||||||
let t2 = (-b + sqrt_d) / a;
|
let t2 = (-l_pos + sqrt_d) / l_dir;
|
||||||
|
|
||||||
let t = t1.max(t2);
|
let t = t1.max(t2);
|
||||||
|
|
||||||
@@ -709,8 +722,8 @@ fn raycast_cylinder(
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let max_angle = 2.0 * (size / (2.0 * r));
|
let max_angle = 2.0 * (size / (2.0 * radius));
|
||||||
let x_angle = (hit_local.x / r).asin();
|
let x_angle = (hit_local.x / radius).asin();
|
||||||
|
|
||||||
hit_local.x = x_angle / max_angle;
|
hit_local.x = x_angle / max_angle;
|
||||||
hit_local.y /= size;
|
hit_local.y /= size;
|
||||||
|
|||||||
@@ -57,8 +57,7 @@ impl NotificationManager {
|
|||||||
Ok(c) => c,
|
Ok(c) => c,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!(
|
log::error!(
|
||||||
"Failed to connect to dbus. Desktop notifications will not work. Cause: {:?}",
|
"Failed to connect to dbus. Desktop notifications will not work. Cause: {e:?}"
|
||||||
e
|
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -81,17 +80,16 @@ impl NotificationManager {
|
|||||||
(vec![rule.match_str()], 0u32),
|
(vec![rule.match_str()], 0u32),
|
||||||
);
|
);
|
||||||
|
|
||||||
match result {
|
if matches!(result, Ok(())) {
|
||||||
Ok(_) => {
|
|
||||||
let sender = self.tx_toast.clone();
|
let sender = self.tx_toast.clone();
|
||||||
c.start_receive(
|
c.start_receive(
|
||||||
rule,
|
rule,
|
||||||
Box::new(move |msg, _| {
|
Box::new(move |msg, _| {
|
||||||
if let Ok(toast) = parse_dbus(&msg) {
|
if let Ok(toast) = parse_dbus(&msg) {
|
||||||
match sender.try_send(toast) {
|
match sender.try_send(toast) {
|
||||||
Ok(_) => {}
|
Ok(()) => {}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("Failed to send notification: {:?}", e);
|
log::error!("Failed to send notification: {e:?}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -99,8 +97,7 @@ impl NotificationManager {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
log::info!("Listening to DBus notifications via BecomeMonitor.");
|
log::info!("Listening to DBus notifications via BecomeMonitor.");
|
||||||
}
|
} else {
|
||||||
Err(_) => {
|
|
||||||
let rule_with_eavesdrop = {
|
let rule_with_eavesdrop = {
|
||||||
let mut rule = rule.clone();
|
let mut rule = rule.clone();
|
||||||
rule.eavesdrop = true;
|
rule.eavesdrop = true;
|
||||||
@@ -108,12 +105,12 @@ impl NotificationManager {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let sender2 = self.tx_toast.clone();
|
let sender2 = self.tx_toast.clone();
|
||||||
let result = c.add_match(rule_with_eavesdrop, move |_: (), _, msg| {
|
let result = c.add_match(rule_with_eavesdrop, move |(): (), _, msg| {
|
||||||
if let Ok(toast) = parse_dbus(msg) {
|
if let Ok(toast) = parse_dbus(msg) {
|
||||||
match sender2.try_send(toast) {
|
match sender2.try_send(toast) {
|
||||||
Ok(_) => {}
|
Ok(()) => {}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("Failed to send notification: {:?}", e);
|
log::error!("Failed to send notification: {e:?}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -125,10 +122,7 @@ impl NotificationManager {
|
|||||||
log::info!("Listening to DBus notifications via eavesdrop.");
|
log::info!("Listening to DBus notifications via eavesdrop.");
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
log::error!(
|
log::error!("Failed to add DBus match. Desktop notifications will not work.",);
|
||||||
"Failed to add DBus match. Desktop notifications will not work.",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -144,12 +138,12 @@ impl NotificationManager {
|
|||||||
let socket = match std::net::UdpSocket::bind(addr) {
|
let socket = match std::net::UdpSocket::bind(addr) {
|
||||||
Ok(s) => s,
|
Ok(s) => s,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("Failed to bind notification socket @ {}: {:?}", addr, e);
|
log::error!("Failed to bind notification socket @ {addr}: {e:?}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if let Err(err) = socket.set_read_timeout(Some(Duration::from_millis(200))) {
|
if let Err(err) = socket.set_read_timeout(Some(Duration::from_millis(200))) {
|
||||||
log::error!("Failed to set read timeout: {:?}", err);
|
log::error!("Failed to set read timeout: {err:?}");
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut buf = [0u8; 1024 * 16]; // vrcx embeds icons as b64
|
let mut buf = [0u8; 1024 * 16]; // vrcx embeds icons as b64
|
||||||
@@ -159,14 +153,14 @@ impl NotificationManager {
|
|||||||
let json_str = match std::str::from_utf8(&buf[..num_bytes]) {
|
let json_str = match std::str::from_utf8(&buf[..num_bytes]) {
|
||||||
Ok(s) => s,
|
Ok(s) => s,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("Failed to receive notification message: {:?}", e);
|
log::error!("Failed to receive notification message: {e:?}");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let msg = match serde_json::from_str::<XsoMessage>(json_str) {
|
let msg = match serde_json::from_str::<XsoMessage>(json_str) {
|
||||||
Ok(m) => m,
|
Ok(m) => m,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("Failed to parse notification message: {:?}", e);
|
log::error!("Failed to parse notification message: {e:?}");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -184,9 +178,9 @@ impl NotificationManager {
|
|||||||
.with_sound(msg.volume.unwrap_or(-1.) >= 0.); // XSOverlay still plays at 0,
|
.with_sound(msg.volume.unwrap_or(-1.) >= 0.); // XSOverlay still plays at 0,
|
||||||
|
|
||||||
match sender.try_send(toast) {
|
match sender.try_send(toast) {
|
||||||
Ok(_) => {}
|
Ok(()) => {}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("Failed to send notification: {:?}", e);
|
log::error!("Failed to send notification: {e:?}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -278,6 +272,7 @@ fn parse_dbus(msg: &dbus::Message) -> anyhow::Result<Toast> {
|
|||||||
// leave the audio part to the desktop env
|
// leave the audio part to the desktop env
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
struct XsoMessage {
|
struct XsoMessage {
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ impl arg::AppendAll for OrgFreedesktopDBusPropertiesPropertiesChanged {
|
|||||||
|
|
||||||
impl arg::ReadAll for OrgFreedesktopDBusPropertiesPropertiesChanged {
|
impl arg::ReadAll for OrgFreedesktopDBusPropertiesPropertiesChanged {
|
||||||
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
|
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
|
||||||
Ok(OrgFreedesktopDBusPropertiesPropertiesChanged {
|
Ok(Self {
|
||||||
interface_name: i.read()?,
|
interface_name: i.read()?,
|
||||||
changed_properties: i.read()?,
|
changed_properties: i.read()?,
|
||||||
invalidated_properties: i.read()?,
|
invalidated_properties: i.read()?,
|
||||||
@@ -158,7 +158,7 @@ impl arg::AppendAll for OrgFreedesktopNotificationsOnDndToggle {
|
|||||||
|
|
||||||
impl arg::ReadAll for OrgFreedesktopNotificationsOnDndToggle {
|
impl arg::ReadAll for OrgFreedesktopNotificationsOnDndToggle {
|
||||||
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
|
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
|
||||||
Ok(OrgFreedesktopNotificationsOnDndToggle { dnd: i.read()? })
|
Ok(Self { dnd: i.read()? })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,7 +182,7 @@ impl arg::AppendAll for OrgFreedesktopNotificationsNotificationClosed {
|
|||||||
|
|
||||||
impl arg::ReadAll for OrgFreedesktopNotificationsNotificationClosed {
|
impl arg::ReadAll for OrgFreedesktopNotificationsNotificationClosed {
|
||||||
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
|
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
|
||||||
Ok(OrgFreedesktopNotificationsNotificationClosed {
|
Ok(Self {
|
||||||
id: i.read()?,
|
id: i.read()?,
|
||||||
reason: i.read()?,
|
reason: i.read()?,
|
||||||
})
|
})
|
||||||
@@ -209,7 +209,7 @@ impl arg::AppendAll for OrgFreedesktopNotificationsActionInvoked {
|
|||||||
|
|
||||||
impl arg::ReadAll for OrgFreedesktopNotificationsActionInvoked {
|
impl arg::ReadAll for OrgFreedesktopNotificationsActionInvoked {
|
||||||
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
|
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
|
||||||
Ok(OrgFreedesktopNotificationsActionInvoked {
|
Ok(Self {
|
||||||
id: i.read()?,
|
id: i.read()?,
|
||||||
action_key: i.read()?,
|
action_key: i.read()?,
|
||||||
})
|
})
|
||||||
@@ -236,7 +236,7 @@ impl arg::AppendAll for OrgFreedesktopNotificationsNotificationReplied {
|
|||||||
|
|
||||||
impl arg::ReadAll for OrgFreedesktopNotificationsNotificationReplied {
|
impl arg::ReadAll for OrgFreedesktopNotificationsNotificationReplied {
|
||||||
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
|
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
|
||||||
Ok(OrgFreedesktopNotificationsNotificationReplied {
|
Ok(Self {
|
||||||
id: i.read()?,
|
id: i.read()?,
|
||||||
text: i.read()?,
|
text: i.read()?,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ pub trait Affine3AConvert {
|
|||||||
|
|
||||||
impl Affine3AConvert for Matrix3x4 {
|
impl Affine3AConvert for Matrix3x4 {
|
||||||
fn from_affine(affine: &Affine3A) -> Self {
|
fn from_affine(affine: &Affine3A) -> Self {
|
||||||
Matrix3x4([
|
Self([
|
||||||
[
|
[
|
||||||
affine.matrix3.x_axis.x,
|
affine.matrix3.x_axis.x,
|
||||||
affine.matrix3.y_axis.x,
|
affine.matrix3.y_axis.x,
|
||||||
@@ -47,7 +47,7 @@ impl Affine3AConvert for Matrix3x4 {
|
|||||||
|
|
||||||
impl Affine3AConvert for HmdMatrix34_t {
|
impl Affine3AConvert for HmdMatrix34_t {
|
||||||
fn from_affine(affine: &Affine3A) -> Self {
|
fn from_affine(affine: &Affine3A) -> Self {
|
||||||
HmdMatrix34_t {
|
Self {
|
||||||
m: [
|
m: [
|
||||||
[
|
[
|
||||||
affine.matrix3.x_axis.x,
|
affine.matrix3.x_axis.x,
|
||||||
@@ -89,13 +89,13 @@ pub(super) enum OVRError {
|
|||||||
|
|
||||||
impl From<ovr_overlay::errors::EVRInputError> for OVRError {
|
impl From<ovr_overlay::errors::EVRInputError> for OVRError {
|
||||||
fn from(e: ovr_overlay::errors::EVRInputError) -> Self {
|
fn from(e: ovr_overlay::errors::EVRInputError) -> Self {
|
||||||
OVRError::InputError(e.description())
|
Self::InputError(e.description())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<OVRError> for BackendError {
|
impl From<OVRError> for BackendError {
|
||||||
fn from(e: OVRError) -> Self {
|
fn from(e: OVRError) -> Self {
|
||||||
BackendError::Fatal(anyhow::Error::new(e))
|
Self::Fatal(anyhow::Error::new(e))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -107,7 +107,8 @@ impl OpenVrInputSource {
|
|||||||
haptics_hnd: haptics_hnd[i],
|
haptics_hnd: haptics_hnd[i],
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(OpenVrInputSource {
|
Ok(Self {
|
||||||
|
hands,
|
||||||
set_hnd,
|
set_hnd,
|
||||||
click_hnd,
|
click_hnd,
|
||||||
grab_hnd,
|
grab_hnd,
|
||||||
@@ -120,14 +121,13 @@ impl OpenVrInputSource {
|
|||||||
click_modifier_right_hnd,
|
click_modifier_right_hnd,
|
||||||
click_modifier_middle_hnd,
|
click_modifier_middle_hnd,
|
||||||
move_mouse_hnd,
|
move_mouse_hnd,
|
||||||
hands,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn haptics(&mut self, input: &mut InputManager, hand: usize, haptics: &Haptics) {
|
pub fn haptics(&mut self, input: &mut InputManager, hand: usize, haptics: &Haptics) {
|
||||||
let hnd = self.hands[hand].haptics_hnd;
|
let action_handle = self.hands[hand].haptics_hnd;
|
||||||
let _ = input.trigger_haptic_vibration_action(
|
let _ = input.trigger_haptic_vibration_action(
|
||||||
hnd,
|
action_handle,
|
||||||
0.0,
|
0.0,
|
||||||
Duration::from_secs_f32(haptics.duration),
|
Duration::from_secs_f32(haptics.duration),
|
||||||
haptics.frequency,
|
haptics.frequency,
|
||||||
@@ -277,8 +277,8 @@ impl OpenVrInputSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
app.input_state.devices.sort_by(|a, b| {
|
app.input_state.devices.sort_by(|a, b| {
|
||||||
(a.soc.is_none() as u8)
|
u8::from(a.soc.is_none())
|
||||||
.cmp(&(b.soc.is_none() as u8))
|
.cmp(&u8::from(b.soc.is_none()))
|
||||||
.then((a.role as u8).cmp(&(b.role as u8)))
|
.then((a.role as u8).cmp(&(b.role as u8)))
|
||||||
.then(a.soc.unwrap_or(999.).total_cmp(&b.soc.unwrap_or(999.)))
|
.then(a.soc.unwrap_or(999.).total_cmp(&b.soc.unwrap_or(999.)))
|
||||||
});
|
});
|
||||||
@@ -332,7 +332,7 @@ pub fn set_action_manifest(input: &mut InputManager) -> anyhow::Result<()> {
|
|||||||
if let Err(e) = File::create(&action_path)
|
if let Err(e) = File::create(&action_path)
|
||||||
.and_then(|mut f| f.write_all(include_bytes!("../../res/actions.json")))
|
.and_then(|mut f| f.write_all(include_bytes!("../../res/actions.json")))
|
||||||
{
|
{
|
||||||
log::warn!("Could not write action manifest: {}", e);
|
log::warn!("Could not write action manifest: {e}");
|
||||||
}
|
}
|
||||||
|
|
||||||
let binding_path = config_io::get_config_root().join("actions_binding_knuckles.json");
|
let binding_path = config_io::get_config_root().join("actions_binding_knuckles.json");
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ impl LinePool {
|
|||||||
|
|
||||||
let view = ImageView::new_default(texture)?;
|
let view = ImageView::new_default(texture)?;
|
||||||
|
|
||||||
Ok(LinePool {
|
Ok(Self {
|
||||||
lines: IdMap::new(),
|
lines: IdMap::new(),
|
||||||
view,
|
view,
|
||||||
colors: [
|
colors: [
|
||||||
@@ -66,7 +66,7 @@ impl LinePool {
|
|||||||
|
|
||||||
let mut data = OverlayData::<OpenVrOverlayData> {
|
let mut data = OverlayData::<OpenVrOverlayData> {
|
||||||
state: OverlayState {
|
state: OverlayState {
|
||||||
name: Arc::from(format!("wlx-line{}", id)),
|
name: Arc::from(format!("wlx-line{id}")),
|
||||||
show_hide: true,
|
show_hide: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
@@ -132,15 +132,7 @@ impl LinePool {
|
|||||||
data.state.transform = transform;
|
data.state.transform = transform;
|
||||||
data.data.color = color;
|
data.data.color = color;
|
||||||
} else {
|
} else {
|
||||||
log::warn!("Line {} does not exist", id);
|
log::warn!("Line {id} does not exist");
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn hide(&mut self, id: usize) {
|
|
||||||
if let Some(data) = self.lines.get_mut(id) {
|
|
||||||
data.state.want_visible = false;
|
|
||||||
} else {
|
|
||||||
log::warn!("Line {} does not exist", id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ pub(super) fn install_manifest(app_mgr: &mut ApplicationsManager) -> anyhow::Res
|
|||||||
.ok_or_else(|| anyhow::anyhow!("Invalid executable path"))?,
|
.ok_or_else(|| anyhow::anyhow!("Invalid executable path"))?,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Ok(true) = app_mgr.is_application_installed(APP_KEY) {
|
if app_mgr.is_application_installed(APP_KEY) == Ok(true) {
|
||||||
if let Ok(mut file) = File::open(&manifest_path) {
|
if let Ok(mut file) = File::open(&manifest_path) {
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
if file.read_to_string(&mut buf).is_ok() {
|
if file.read_to_string(&mut buf).is_ok() {
|
||||||
@@ -62,15 +62,15 @@ pub(super) fn install_manifest(app_mgr: &mut ApplicationsManager) -> anyhow::Res
|
|||||||
manifest_path,
|
manifest_path,
|
||||||
e
|
e
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|
||||||
if let Err(e) = app_mgr.add_application_manifest(&manifest_path, false) {
|
if let Err(e) = app_mgr.add_application_manifest(&manifest_path, false) {
|
||||||
bail!("Failed to add manifest to OpenVR: {}", e.description());
|
bail!("Failed to add manifest to OpenVR: {}", e.description());
|
||||||
};
|
}
|
||||||
|
|
||||||
if let Err(e) = app_mgr.set_application_auto_launch(APP_KEY, true) {
|
if let Err(e) = app_mgr.set_application_auto_launch(APP_KEY, true) {
|
||||||
bail!("Failed to set auto launch: {}", e.description());
|
bail!("Failed to set auto launch: {}", e.description());
|
||||||
};
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -78,10 +78,10 @@ pub(super) fn install_manifest(app_mgr: &mut ApplicationsManager) -> anyhow::Res
|
|||||||
pub(super) fn uninstall_manifest(app_mgr: &mut ApplicationsManager) -> anyhow::Result<()> {
|
pub(super) fn uninstall_manifest(app_mgr: &mut ApplicationsManager) -> anyhow::Result<()> {
|
||||||
let manifest_path = config_io::get_config_root().join("wlx-overlay-s.vrmanifest");
|
let manifest_path = config_io::get_config_root().join("wlx-overlay-s.vrmanifest");
|
||||||
|
|
||||||
if let Ok(true) = app_mgr.is_application_installed(APP_KEY) {
|
if app_mgr.is_application_installed(APP_KEY) == Ok(true) {
|
||||||
if let Err(e) = app_mgr.remove_application_manifest(&manifest_path) {
|
if let Err(e) = app_mgr.remove_application_manifest(&manifest_path) {
|
||||||
bail!("Failed to remove manifest from OpenVR: {}", e.description());
|
bail!("Failed to remove manifest from OpenVR: {}", e.description());
|
||||||
};
|
}
|
||||||
log::info!("Uninstalled manifest");
|
log::info!("Uninstalled manifest");
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -13,11 +13,7 @@ use ovr_overlay::{
|
|||||||
sys::{ETrackedDeviceProperty, EVRApplicationType, EVREventType},
|
sys::{ETrackedDeviceProperty, EVRApplicationType, EVREventType},
|
||||||
TrackedDeviceIndex,
|
TrackedDeviceIndex,
|
||||||
};
|
};
|
||||||
use vulkano::{
|
use vulkano::{device::physical::PhysicalDevice, Handle, VulkanObject};
|
||||||
device::{physical::PhysicalDevice, DeviceExtensions},
|
|
||||||
instance::InstanceExtensions,
|
|
||||||
Handle, VulkanObject,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::{
|
backend::{
|
||||||
@@ -65,6 +61,7 @@ pub fn openvr_uninstall() {
|
|||||||
let _ = uninstall_manifest(&mut app_mgr);
|
let _ = uninstall_manifest(&mut app_mgr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_lines, clippy::cognitive_complexity)]
|
||||||
pub fn openvr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(), BackendError> {
|
pub fn openvr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(), BackendError> {
|
||||||
let app_type = EVRApplicationType::VRApplication_Overlay;
|
let app_type = EVRApplicationType::VRApplication_Overlay;
|
||||||
let Ok(context) = ovr_overlay::Context::init(app_type) else {
|
let Ok(context) = ovr_overlay::Context::init(app_type) else {
|
||||||
@@ -84,14 +81,13 @@ pub fn openvr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
|
|||||||
|
|
||||||
let device_extensions_fn = |device: &PhysicalDevice| {
|
let device_extensions_fn = |device: &PhysicalDevice| {
|
||||||
let names = compositor_mgr.get_vulkan_device_extensions_required(device.handle().as_raw());
|
let names = compositor_mgr.get_vulkan_device_extensions_required(device.handle().as_raw());
|
||||||
let ext = DeviceExtensions::from_iter(names.iter().map(|s| s.as_str()));
|
names.iter().map(std::string::String::as_str).collect()
|
||||||
ext
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut compositor_mngr = context.compositor_mngr();
|
let mut compositor_mgr = context.compositor_mngr();
|
||||||
let instance_extensions = {
|
let instance_extensions = {
|
||||||
let names = compositor_mngr.get_vulkan_instance_extensions_required();
|
let names = compositor_mgr.get_vulkan_instance_extensions_required();
|
||||||
InstanceExtensions::from_iter(names.iter().map(|s| s.as_str()))
|
names.iter().map(std::string::String::as_str).collect()
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut state = {
|
let mut state = {
|
||||||
@@ -103,7 +99,7 @@ pub fn openvr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
|
|||||||
state.tasks.enqueue_at(
|
state.tasks.enqueue_at(
|
||||||
TaskType::System(SystemTask::ShowHide),
|
TaskType::System(SystemTask::ShowHide),
|
||||||
Instant::now().add(Duration::from_secs(1)),
|
Instant::now().add(Duration::from_secs(1)),
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(ipd) = system_mgr.get_tracked_device_property::<f32>(
|
if let Ok(ipd) = system_mgr.get_tracked_device_property::<f32>(
|
||||||
@@ -137,7 +133,7 @@ pub fn openvr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
|
|||||||
)));
|
)));
|
||||||
};
|
};
|
||||||
|
|
||||||
log::info!("HMD running @ {} Hz", refresh_rate);
|
log::info!("HMD running @ {refresh_rate} Hz");
|
||||||
|
|
||||||
let watch_id = overlays.get_by_name(WATCH_NAME).unwrap().state.id; // want panic
|
let watch_id = overlays.get_by_name(WATCH_NAME).unwrap().state.id; // want panic
|
||||||
|
|
||||||
@@ -188,7 +184,7 @@ pub fn openvr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
|
|||||||
Toast::new(
|
Toast::new(
|
||||||
ToastTopic::IpdChange,
|
ToastTopic::IpdChange,
|
||||||
"IPD".into(),
|
"IPD".into(),
|
||||||
format!("{:.1} mm", ipd).into(),
|
format!("{ipd:.1} mm").into(),
|
||||||
)
|
)
|
||||||
.submit(&mut state);
|
.submit(&mut state);
|
||||||
}
|
}
|
||||||
@@ -209,18 +205,17 @@ pub fn openvr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
|
|||||||
state.tasks.retrieve_due(&mut due_tasks);
|
state.tasks.retrieve_due(&mut due_tasks);
|
||||||
|
|
||||||
let mut removed_overlays = overlays.update(&mut state)?;
|
let mut removed_overlays = overlays.update(&mut state)?;
|
||||||
for o in removed_overlays.iter_mut() {
|
for o in &mut removed_overlays {
|
||||||
o.destroy(&mut overlay_mgr);
|
o.destroy(&mut overlay_mgr);
|
||||||
}
|
}
|
||||||
|
|
||||||
while let Some(task) = due_tasks.pop_front() {
|
while let Some(task) = due_tasks.pop_front() {
|
||||||
match task {
|
match task {
|
||||||
TaskType::Global(f) => f(&mut state),
|
|
||||||
TaskType::Overlay(sel, f) => {
|
TaskType::Overlay(sel, f) => {
|
||||||
if let Some(o) = overlays.mut_by_selector(&sel) {
|
if let Some(o) = overlays.mut_by_selector(&sel) {
|
||||||
f(&mut state, &mut o.state);
|
f(&mut state, &mut o.state);
|
||||||
} else {
|
} else {
|
||||||
log::warn!("Overlay not found for task: {:?}", sel);
|
log::warn!("Overlay not found for task: {sel:?}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TaskType::CreateOverlay(sel, f) => {
|
TaskType::CreateOverlay(sel, f) => {
|
||||||
@@ -316,7 +311,7 @@ pub fn openvr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
|
|||||||
&state.input_state.hmd,
|
&state.input_state.hmd,
|
||||||
);
|
);
|
||||||
if let Some(haptics) = haptics {
|
if let Some(haptics) = haptics {
|
||||||
input_source.haptics(&mut input_mgr, idx, haptics)
|
input_source.haptics(&mut input_mgr, idx, haptics);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,13 +327,13 @@ pub fn openvr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
|
|||||||
#[cfg(feature = "osc")]
|
#[cfg(feature = "osc")]
|
||||||
if let Some(ref mut sender) = state.osc_sender {
|
if let Some(ref mut sender) = state.osc_sender {
|
||||||
let _ = sender.send_params(&overlays, &state.input_state.devices);
|
let _ = sender.send_params(&overlays, &state.input_state.devices);
|
||||||
};
|
}
|
||||||
|
|
||||||
#[cfg(feature = "wayvr")]
|
#[cfg(feature = "wayvr")]
|
||||||
if let Err(e) =
|
if let Err(e) =
|
||||||
crate::overlays::wayvr::tick_events::<OpenVrOverlayData>(&mut state, &mut overlays)
|
crate::overlays::wayvr::tick_events::<OpenVrOverlayData>(&mut state, &mut overlays)
|
||||||
{
|
{
|
||||||
log::error!("WayVR tick_events failed: {:?}", e);
|
log::error!("WayVR tick_events failed: {e:?}");
|
||||||
}
|
}
|
||||||
|
|
||||||
log::trace!("Rendering frame");
|
log::trace!("Rendering frame");
|
||||||
@@ -365,7 +360,7 @@ pub fn openvr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
|
|||||||
if let Some(mut future) = buffers.execute_now(state.graphics.queue.clone())? {
|
if let Some(mut future) = buffers.execute_now(state.graphics.queue.clone())? {
|
||||||
if let Err(e) = future.flush() {
|
if let Err(e) = future.flush() {
|
||||||
return Err(BackendError::Fatal(e.into()));
|
return Err(BackendError::Fatal(e.into()));
|
||||||
};
|
}
|
||||||
future.cleanup_finished();
|
future.cleanup_finished();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,11 +9,7 @@ use ovr_overlay::{
|
|||||||
};
|
};
|
||||||
use vulkano::{image::view::ImageView, Handle, VulkanObject};
|
use vulkano::{image::view::ImageView, Handle, VulkanObject};
|
||||||
|
|
||||||
use crate::{
|
use crate::{backend::overlay::OverlayData, graphics::WlxGraphics, state::AppState};
|
||||||
backend::overlay::{OverlayData, RelativeTo},
|
|
||||||
graphics::WlxGraphics,
|
|
||||||
state::AppState,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::helpers::Affine3AConvert;
|
use super::helpers::Affine3AConvert;
|
||||||
|
|
||||||
@@ -24,7 +20,6 @@ pub(super) struct OpenVrOverlayData {
|
|||||||
pub(super) color: Vec4,
|
pub(super) color: Vec4,
|
||||||
pub(crate) width: f32,
|
pub(crate) width: f32,
|
||||||
pub(super) override_width: bool,
|
pub(super) override_width: bool,
|
||||||
pub(super) relative_to: RelativeTo,
|
|
||||||
pub(super) image_view: Option<Arc<ImageView>>,
|
pub(super) image_view: Option<Arc<ImageView>>,
|
||||||
pub(super) image_dirty: bool,
|
pub(super) image_dirty: bool,
|
||||||
}
|
}
|
||||||
@@ -40,7 +35,7 @@ impl OverlayData<OpenVrOverlayData> {
|
|||||||
let handle = match overlay.create_overlay(&key, &key) {
|
let handle = match overlay.create_overlay(&key, &key) {
|
||||||
Ok(handle) => handle,
|
Ok(handle) => handle,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
panic!("Failed to create overlay: {}", e);
|
panic!("Failed to create overlay: {e}");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
log::debug!("{}: initialize", self.state.name);
|
log::debug!("{}: initialize", self.state.name);
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ pub(super) struct PlayspaceMover {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PlayspaceMover {
|
impl PlayspaceMover {
|
||||||
pub fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
universe: ETrackingUniverseOrigin::TrackingUniverseRawAndUncalibrated,
|
universe: ETrackingUniverseOrigin::TrackingUniverseRawAndUncalibrated,
|
||||||
drag: None,
|
drag: None,
|
||||||
@@ -33,6 +33,7 @@ impl PlayspaceMover {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_lines, clippy::cognitive_complexity)]
|
||||||
pub fn update(
|
pub fn update(
|
||||||
&mut self,
|
&mut self,
|
||||||
chaperone_mgr: &mut ChaperoneSetupManager,
|
chaperone_mgr: &mut ChaperoneSetupManager,
|
||||||
@@ -54,8 +55,8 @@ impl PlayspaceMover {
|
|||||||
|
|
||||||
let dq = new_hand * data.hand_pose.conjugate();
|
let dq = new_hand * data.hand_pose.conjugate();
|
||||||
let rel_y = f32::atan2(
|
let rel_y = f32::atan2(
|
||||||
2.0 * (dq.y * dq.w + dq.x * dq.z),
|
2.0 * dq.y.mul_add(dq.w, dq.x * dq.z),
|
||||||
(2.0 * (dq.w * dq.w + dq.x * dq.x)) - 1.0,
|
2.0f32.mul_add(dq.w.mul_add(dq.w, dq.x * dq.x), -1.0),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut space_transform = Affine3A::from_rotation_y(rel_y);
|
let mut space_transform = Affine3A::from_rotation_y(rel_y);
|
||||||
@@ -241,7 +242,7 @@ impl PlayspaceMover {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn universe_str(universe: &ETrackingUniverseOrigin) -> &'static str {
|
const fn universe_str(universe: &ETrackingUniverseOrigin) -> &'static str {
|
||||||
match universe {
|
match universe {
|
||||||
ETrackingUniverseOrigin::TrackingUniverseSeated => "Seated",
|
ETrackingUniverseOrigin::TrackingUniverseSeated => "Seated",
|
||||||
ETrackingUniverseOrigin::TrackingUniverseStanding => "Standing",
|
ETrackingUniverseOrigin::TrackingUniverseStanding => "Standing",
|
||||||
@@ -271,31 +272,31 @@ fn set_working_copy(
|
|||||||
let mat = HmdMatrix34_t::from_affine(mat);
|
let mat = HmdMatrix34_t::from_affine(mat);
|
||||||
match universe {
|
match universe {
|
||||||
ETrackingUniverseOrigin::TrackingUniverseStanding => {
|
ETrackingUniverseOrigin::TrackingUniverseStanding => {
|
||||||
chaperone_mgr.set_working_standing_zero_pose_to_raw_tracking_pose(&mat)
|
chaperone_mgr.set_working_standing_zero_pose_to_raw_tracking_pose(&mat);
|
||||||
}
|
}
|
||||||
_ => chaperone_mgr.set_working_seated_zero_pose_to_raw_tracking_pose(&mat),
|
_ => chaperone_mgr.set_working_seated_zero_pose_to_raw_tracking_pose(&mat),
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_chaperone_offset(offset: Vec3A, chaperone_mgr: &mut ChaperoneSetupManager) {
|
fn apply_chaperone_offset(offset: Vec3A, chaperone_mgr: &mut ChaperoneSetupManager) {
|
||||||
let mut quads = chaperone_mgr.get_live_collision_bounds_info();
|
let mut quads = chaperone_mgr.get_live_collision_bounds_info();
|
||||||
quads.iter_mut().for_each(|quad| {
|
for quad in &mut quads {
|
||||||
quad.vCorners.iter_mut().for_each(|corner| {
|
quad.vCorners.iter_mut().for_each(|corner| {
|
||||||
corner.v[0] += offset.x;
|
corner.v[0] += offset.x;
|
||||||
corner.v[2] += offset.z;
|
corner.v[2] += offset.z;
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
chaperone_mgr.set_working_collision_bounds_info(quads.as_mut_slice());
|
chaperone_mgr.set_working_collision_bounds_info(quads.as_mut_slice());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_chaperone_transform(transform: Affine3A, chaperone_mgr: &mut ChaperoneSetupManager) {
|
fn apply_chaperone_transform(transform: Affine3A, chaperone_mgr: &mut ChaperoneSetupManager) {
|
||||||
let mut quads = chaperone_mgr.get_live_collision_bounds_info();
|
let mut quads = chaperone_mgr.get_live_collision_bounds_info();
|
||||||
quads.iter_mut().for_each(|quad| {
|
for quad in &mut quads {
|
||||||
quad.vCorners.iter_mut().for_each(|corner| {
|
quad.vCorners.iter_mut().for_each(|corner| {
|
||||||
let coord = transform.transform_point3a(Vec3A::from_slice(&corner.v));
|
let coord = transform.transform_point3a(Vec3A::from_slice(&corner.v));
|
||||||
corner.v[0] = coord.x;
|
corner.v[0] = coord.x;
|
||||||
corner.v[2] = coord.z;
|
corner.v[2] = coord.z;
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
chaperone_mgr.set_working_collision_bounds_info(quads.as_mut_slice());
|
chaperone_mgr.set_working_collision_bounds_info(quads.as_mut_slice());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use anyhow::{bail, ensure};
|
use anyhow::{bail, ensure};
|
||||||
use glam::{Affine3A, Quat, Vec3, Vec3A};
|
use glam::{Affine3A, Quat, Vec3, Vec3A};
|
||||||
use openxr as xr;
|
use openxr::{self as xr, SessionCreateFlags};
|
||||||
use xr::OverlaySessionCreateFlagsEXTX;
|
use xr::OverlaySessionCreateFlagsEXTX;
|
||||||
|
|
||||||
pub(super) fn init_xr() -> Result<(xr::Instance, xr::SystemId), anyhow::Error> {
|
pub(super) fn init_xr() -> Result<(xr::Instance, xr::SystemId), anyhow::Error> {
|
||||||
@@ -110,7 +110,7 @@ pub(super) unsafe fn create_overlay_session(
|
|||||||
};
|
};
|
||||||
let binding = xr::sys::GraphicsBindingVulkanKHR {
|
let binding = xr::sys::GraphicsBindingVulkanKHR {
|
||||||
ty: xr::sys::GraphicsBindingVulkanKHR::TYPE,
|
ty: xr::sys::GraphicsBindingVulkanKHR::TYPE,
|
||||||
next: &overlay as *const _ as *const _,
|
next: (&raw const overlay).cast(),
|
||||||
instance: info.instance,
|
instance: info.instance,
|
||||||
physical_device: info.physical_device,
|
physical_device: info.physical_device,
|
||||||
device: info.device,
|
device: info.device,
|
||||||
@@ -119,8 +119,8 @@ pub(super) unsafe fn create_overlay_session(
|
|||||||
};
|
};
|
||||||
let info = xr::sys::SessionCreateInfo {
|
let info = xr::sys::SessionCreateInfo {
|
||||||
ty: xr::sys::SessionCreateInfo::TYPE,
|
ty: xr::sys::SessionCreateInfo::TYPE,
|
||||||
next: &binding as *const _ as *const _,
|
next: (&raw const binding).cast(),
|
||||||
create_flags: Default::default(),
|
create_flags: SessionCreateFlags::default(),
|
||||||
system_id: system,
|
system_id: system,
|
||||||
};
|
};
|
||||||
let mut out = xr::sys::Session::NULL;
|
let mut out = xr::sys::Session::NULL;
|
||||||
|
|||||||
@@ -17,16 +17,12 @@ use crate::{
|
|||||||
|
|
||||||
use super::{helpers::posef_to_transform, XrState};
|
use super::{helpers::posef_to_transform, XrState};
|
||||||
|
|
||||||
type XrSession = xr::Session<xr::Vulkan>;
|
|
||||||
|
|
||||||
static CLICK_TIMES: [Duration; 3] = [
|
static CLICK_TIMES: [Duration; 3] = [
|
||||||
Duration::ZERO,
|
Duration::ZERO,
|
||||||
Duration::from_millis(500),
|
Duration::from_millis(500),
|
||||||
Duration::from_millis(750),
|
Duration::from_millis(750),
|
||||||
];
|
];
|
||||||
|
|
||||||
pub(super) struct OpenXrAction {}
|
|
||||||
|
|
||||||
pub(super) struct OpenXrInputSource {
|
pub(super) struct OpenXrInputSource {
|
||||||
action_set: xr::ActionSet,
|
action_set: xr::ActionSet,
|
||||||
hands: [OpenXrHand; 2],
|
hands: [OpenXrHand; 2],
|
||||||
@@ -48,7 +44,7 @@ pub struct MultiClickHandler<const COUNT: usize> {
|
|||||||
|
|
||||||
impl<const COUNT: usize> MultiClickHandler<COUNT> {
|
impl<const COUNT: usize> MultiClickHandler<COUNT> {
|
||||||
fn new(action_set: &xr::ActionSet, action_name: &str, side: &str) -> anyhow::Result<Self> {
|
fn new(action_set: &xr::ActionSet, action_name: &str, side: &str) -> anyhow::Result<Self> {
|
||||||
let name = format!("{}_{}-{}", side, COUNT, action_name);
|
let name = format!("{side}_{COUNT}-{action_name}");
|
||||||
let name_f32 = format!("{}_value", &name);
|
let name_f32 = format!("{}_value", &name);
|
||||||
|
|
||||||
let action_bool = action_set.create_action::<bool>(&name, &name, &[])?;
|
let action_bool = action_set.create_action::<bool>(&name, &name, &[])?;
|
||||||
@@ -97,10 +93,10 @@ impl<const COUNT: usize> MultiClickHandler<COUNT> {
|
|||||||
self.held_inactive = false;
|
self.held_inactive = false;
|
||||||
|
|
||||||
// reset to no prior clicks
|
// reset to no prior clicks
|
||||||
let long_ago = Instant::now() - Duration::from_secs(10);
|
let long_ago = Instant::now().checked_sub(Duration::from_secs(10)).unwrap();
|
||||||
self.previous
|
self.previous
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.for_each(|instant| *instant = long_ago)
|
.for_each(|instant| *instant = long_ago);
|
||||||
} else if COUNT > 0 {
|
} else if COUNT > 0 {
|
||||||
log::trace!("{}: rotate", self.name);
|
log::trace!("{}: rotate", self.name);
|
||||||
self.previous.rotate_right(1);
|
self.previous.rotate_right(1);
|
||||||
@@ -149,20 +145,20 @@ impl CustomClickAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct OpenXrHandSource {
|
pub(super) struct OpenXrHandSource {
|
||||||
action_pose: xr::Action<xr::Posef>,
|
pose: xr::Action<xr::Posef>,
|
||||||
action_click: CustomClickAction,
|
click: CustomClickAction,
|
||||||
action_grab: CustomClickAction,
|
grab: CustomClickAction,
|
||||||
action_alt_click: CustomClickAction,
|
alt_click: CustomClickAction,
|
||||||
action_show_hide: CustomClickAction,
|
show_hide: CustomClickAction,
|
||||||
action_toggle_dashboard: CustomClickAction,
|
toggle_dashboard: CustomClickAction,
|
||||||
action_space_drag: CustomClickAction,
|
space_drag: CustomClickAction,
|
||||||
action_space_rotate: CustomClickAction,
|
space_rotate: CustomClickAction,
|
||||||
action_space_reset: CustomClickAction,
|
space_reset: CustomClickAction,
|
||||||
action_modifier_right: CustomClickAction,
|
modifier_right: CustomClickAction,
|
||||||
action_modifier_middle: CustomClickAction,
|
modifier_middle: CustomClickAction,
|
||||||
action_move_mouse: CustomClickAction,
|
move_mouse: CustomClickAction,
|
||||||
action_scroll: xr::Action<Vector2f>,
|
scroll: xr::Action<Vector2f>,
|
||||||
action_haptics: xr::Action<xr::Haptic>,
|
haptics: xr::Action<xr::Haptic>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OpenXrInputSource {
|
impl OpenXrInputSource {
|
||||||
@@ -175,7 +171,7 @@ impl OpenXrInputSource {
|
|||||||
let left_source = OpenXrHandSource::new(&mut action_set, "left")?;
|
let left_source = OpenXrHandSource::new(&mut action_set, "left")?;
|
||||||
let right_source = OpenXrHandSource::new(&mut action_set, "right")?;
|
let right_source = OpenXrHandSource::new(&mut action_set, "right")?;
|
||||||
|
|
||||||
suggest_bindings(&xr.instance, &[&left_source, &right_source])?;
|
suggest_bindings(&xr.instance, &[&left_source, &right_source]);
|
||||||
|
|
||||||
xr.session.attach_action_sets(&[&action_set])?;
|
xr.session.attach_action_sets(&[&action_set])?;
|
||||||
|
|
||||||
@@ -189,9 +185,9 @@ impl OpenXrInputSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn haptics(&self, xr: &XrState, hand: usize, haptics: &Haptics) {
|
pub fn haptics(&self, xr: &XrState, hand: usize, haptics: &Haptics) {
|
||||||
let action = &self.hands[hand].source.action_haptics;
|
let action = &self.hands[hand].source.haptics;
|
||||||
|
|
||||||
let duration_nanos = (haptics.duration as f64) * 1_000_000_000.0;
|
let duration_nanos = f64::from(haptics.duration) * 1_000_000_000.0;
|
||||||
|
|
||||||
let _ = action.apply_feedback(
|
let _ = action.apply_feedback(
|
||||||
&xr.session,
|
&xr.session,
|
||||||
@@ -251,7 +247,7 @@ impl OpenXrInputSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_devices(&mut self, app: &mut AppState, monado: &mut mnd::Monado) {
|
pub fn update_devices(app: &mut AppState, monado: &mut mnd::Monado) {
|
||||||
app.input_state.devices.clear();
|
app.input_state.devices.clear();
|
||||||
|
|
||||||
let roles = [
|
let roles = [
|
||||||
@@ -293,8 +289,8 @@ impl OpenXrInputSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
app.input_state.devices.sort_by(|a, b| {
|
app.input_state.devices.sort_by(|a, b| {
|
||||||
(a.soc.is_none() as u8)
|
u8::from(a.soc.is_none())
|
||||||
.cmp(&(b.soc.is_none() as u8))
|
.cmp(&u8::from(b.soc.is_none()))
|
||||||
.then((a.role as u8).cmp(&(b.role as u8)))
|
.then((a.role as u8).cmp(&(b.role as u8)))
|
||||||
.then(a.soc.unwrap_or(999.).total_cmp(&b.soc.unwrap_or(999.)))
|
.then(a.soc.unwrap_or(999.).total_cmp(&b.soc.unwrap_or(999.)))
|
||||||
});
|
});
|
||||||
@@ -303,11 +299,10 @@ impl OpenXrInputSource {
|
|||||||
|
|
||||||
impl OpenXrHand {
|
impl OpenXrHand {
|
||||||
pub(super) fn new(xr: &XrState, source: OpenXrHandSource) -> Result<Self, xr::sys::Result> {
|
pub(super) fn new(xr: &XrState, source: OpenXrHandSource) -> Result<Self, xr::sys::Result> {
|
||||||
let space = source.action_pose.create_space(
|
let space =
|
||||||
xr.session.clone(),
|
source
|
||||||
xr::Path::NULL,
|
.pose
|
||||||
xr::Posef::IDENTITY,
|
.create_space(xr.session.clone(), xr::Path::NULL, xr::Posef::IDENTITY)?;
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(Self { source, space })
|
Ok(Self { source, space })
|
||||||
}
|
}
|
||||||
@@ -340,19 +335,13 @@ impl OpenXrHand {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pointer.now.click = self
|
pointer.now.click = self.source.click.state(pointer.before.click, xr, session)?;
|
||||||
.source
|
|
||||||
.action_click
|
|
||||||
.state(pointer.before.click, xr, session)?;
|
|
||||||
|
|
||||||
pointer.now.grab = self
|
pointer.now.grab = self.source.grab.state(pointer.before.grab, xr, session)?;
|
||||||
.source
|
|
||||||
.action_grab
|
|
||||||
.state(pointer.before.grab, xr, session)?;
|
|
||||||
|
|
||||||
let scroll = self
|
let scroll = self
|
||||||
.source
|
.source
|
||||||
.action_scroll
|
.scroll
|
||||||
.state(&xr.session, xr::Path::NULL)?
|
.state(&xr.session, xr::Path::NULL)?
|
||||||
.current_state;
|
.current_state;
|
||||||
|
|
||||||
@@ -361,50 +350,47 @@ impl OpenXrHand {
|
|||||||
|
|
||||||
pointer.now.alt_click =
|
pointer.now.alt_click =
|
||||||
self.source
|
self.source
|
||||||
.action_alt_click
|
.alt_click
|
||||||
.state(pointer.before.alt_click, xr, session)?;
|
.state(pointer.before.alt_click, xr, session)?;
|
||||||
|
|
||||||
pointer.now.show_hide =
|
pointer.now.show_hide =
|
||||||
self.source
|
self.source
|
||||||
.action_show_hide
|
.show_hide
|
||||||
.state(pointer.before.show_hide, xr, session)?;
|
.state(pointer.before.show_hide, xr, session)?;
|
||||||
|
|
||||||
pointer.now.click_modifier_right = self.source.action_modifier_right.state(
|
pointer.now.click_modifier_right =
|
||||||
pointer.before.click_modifier_right,
|
self.source
|
||||||
xr,
|
.modifier_right
|
||||||
session,
|
.state(pointer.before.click_modifier_right, xr, session)?;
|
||||||
)?;
|
|
||||||
|
|
||||||
pointer.now.toggle_dashboard = self.source.action_toggle_dashboard.state(
|
pointer.now.toggle_dashboard =
|
||||||
pointer.before.toggle_dashboard,
|
self.source
|
||||||
xr,
|
.toggle_dashboard
|
||||||
session,
|
.state(pointer.before.toggle_dashboard, xr, session)?;
|
||||||
)?;
|
|
||||||
|
|
||||||
pointer.now.click_modifier_middle = self.source.action_modifier_middle.state(
|
pointer.now.click_modifier_middle =
|
||||||
pointer.before.click_modifier_middle,
|
self.source
|
||||||
xr,
|
.modifier_middle
|
||||||
session,
|
.state(pointer.before.click_modifier_middle, xr, session)?;
|
||||||
)?;
|
|
||||||
|
|
||||||
pointer.now.move_mouse =
|
pointer.now.move_mouse =
|
||||||
self.source
|
self.source
|
||||||
.action_move_mouse
|
.move_mouse
|
||||||
.state(pointer.before.move_mouse, xr, session)?;
|
.state(pointer.before.move_mouse, xr, session)?;
|
||||||
|
|
||||||
pointer.now.space_drag =
|
pointer.now.space_drag =
|
||||||
self.source
|
self.source
|
||||||
.action_space_drag
|
.space_drag
|
||||||
.state(pointer.before.space_drag, xr, session)?;
|
.state(pointer.before.space_drag, xr, session)?;
|
||||||
|
|
||||||
pointer.now.space_rotate =
|
pointer.now.space_rotate =
|
||||||
self.source
|
self.source
|
||||||
.action_space_rotate
|
.space_rotate
|
||||||
.state(pointer.before.space_rotate, xr, session)?;
|
.state(pointer.before.space_rotate, xr, session)?;
|
||||||
|
|
||||||
pointer.now.space_reset =
|
pointer.now.space_reset =
|
||||||
self.source
|
self.source
|
||||||
.action_space_reset
|
.space_reset
|
||||||
.state(pointer.before.space_reset, xr, session)?;
|
.state(pointer.before.space_reset, xr, session)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -415,76 +401,66 @@ impl OpenXrHand {
|
|||||||
impl OpenXrHandSource {
|
impl OpenXrHandSource {
|
||||||
pub(super) fn new(action_set: &mut xr::ActionSet, side: &str) -> anyhow::Result<Self> {
|
pub(super) fn new(action_set: &mut xr::ActionSet, side: &str) -> anyhow::Result<Self> {
|
||||||
let action_pose = action_set.create_action::<xr::Posef>(
|
let action_pose = action_set.create_action::<xr::Posef>(
|
||||||
&format!("{}_hand", side),
|
&format!("{side}_hand"),
|
||||||
&format!("{} hand pose", side),
|
&format!("{side} hand pose"),
|
||||||
&[],
|
&[],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let action_scroll = action_set.create_action::<Vector2f>(
|
let action_scroll = action_set.create_action::<Vector2f>(
|
||||||
&format!("{}_scroll", side),
|
&format!("{side}_scroll"),
|
||||||
&format!("{} hand scroll", side),
|
&format!("{side} hand scroll"),
|
||||||
&[],
|
&[],
|
||||||
)?;
|
)?;
|
||||||
let action_haptics = action_set.create_action::<xr::Haptic>(
|
let action_haptics = action_set.create_action::<xr::Haptic>(
|
||||||
&format!("{}_haptics", side),
|
&format!("{side}_haptics"),
|
||||||
&format!("{} hand haptics", side),
|
&format!("{side} hand haptics"),
|
||||||
&[],
|
&[],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
action_pose,
|
pose: action_pose,
|
||||||
action_click: CustomClickAction::new(action_set, "click", side)?,
|
click: CustomClickAction::new(action_set, "click", side)?,
|
||||||
action_grab: CustomClickAction::new(action_set, "grab", side)?,
|
grab: CustomClickAction::new(action_set, "grab", side)?,
|
||||||
action_scroll,
|
scroll: action_scroll,
|
||||||
action_alt_click: CustomClickAction::new(action_set, "alt_click", side)?,
|
alt_click: CustomClickAction::new(action_set, "alt_click", side)?,
|
||||||
action_show_hide: CustomClickAction::new(action_set, "show_hide", side)?,
|
show_hide: CustomClickAction::new(action_set, "show_hide", side)?,
|
||||||
action_toggle_dashboard: CustomClickAction::new(action_set, "toggle_dashboard", side)?,
|
toggle_dashboard: CustomClickAction::new(action_set, "toggle_dashboard", side)?,
|
||||||
action_space_drag: CustomClickAction::new(action_set, "space_drag", side)?,
|
space_drag: CustomClickAction::new(action_set, "space_drag", side)?,
|
||||||
action_space_rotate: CustomClickAction::new(action_set, "space_rotate", side)?,
|
space_rotate: CustomClickAction::new(action_set, "space_rotate", side)?,
|
||||||
action_space_reset: CustomClickAction::new(action_set, "space_reset", side)?,
|
space_reset: CustomClickAction::new(action_set, "space_reset", side)?,
|
||||||
action_modifier_right: CustomClickAction::new(
|
modifier_right: CustomClickAction::new(action_set, "click_modifier_right", side)?,
|
||||||
action_set,
|
modifier_middle: CustomClickAction::new(action_set, "click_modifier_middle", side)?,
|
||||||
"click_modifier_right",
|
move_mouse: CustomClickAction::new(action_set, "move_mouse", side)?,
|
||||||
side,
|
haptics: action_haptics,
|
||||||
)?,
|
|
||||||
action_modifier_middle: CustomClickAction::new(
|
|
||||||
action_set,
|
|
||||||
"click_modifier_middle",
|
|
||||||
side,
|
|
||||||
)?,
|
|
||||||
action_move_mouse: CustomClickAction::new(action_set, "move_mouse", side)?,
|
|
||||||
action_haptics,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_path(maybe_path_str: &Option<String>, instance: &xr::Instance) -> Option<xr::Path> {
|
fn to_path(maybe_path_str: Option<&String>, instance: &xr::Instance) -> Option<xr::Path> {
|
||||||
maybe_path_str
|
maybe_path_str.as_ref().and_then(|s| {
|
||||||
.as_ref()
|
instance
|
||||||
.and_then(|s| match instance.string_to_path(s) {
|
.string_to_path(s)
|
||||||
Ok(path) => Some(path),
|
.inspect_err(|_| {
|
||||||
Err(_) => {
|
log::warn!("Invalid binding path: {s}");
|
||||||
log::warn!("Invalid binding path: {}", s);
|
})
|
||||||
None
|
.ok()
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_bool(maybe_type_str: &Option<String>) -> bool {
|
fn is_bool(maybe_type_str: Option<&String>) -> bool {
|
||||||
maybe_type_str
|
maybe_type_str
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap() // want panic
|
.unwrap() // want panic
|
||||||
.split('/')
|
.split('/')
|
||||||
.next_back()
|
.next_back()
|
||||||
.map(|last| matches!(last, "click" | "touch"))
|
.is_some_and(|last| matches!(last, "click" | "touch"))
|
||||||
.unwrap_or(false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! add_custom {
|
macro_rules! add_custom {
|
||||||
($action:expr, $left:expr, $right:expr, $bindings:expr, $instance:expr) => {
|
($action:expr, $left:expr, $right:expr, $bindings:expr, $instance:expr) => {
|
||||||
if let Some(action) = $action.as_ref() {
|
if let Some(action) = $action.as_ref() {
|
||||||
if let Some(p) = to_path(&action.left, $instance) {
|
if let Some(p) = to_path(action.left.as_ref(), $instance) {
|
||||||
if is_bool(&action.left) {
|
if is_bool(action.left.as_ref()) {
|
||||||
if action.triple_click.unwrap_or(false) {
|
if action.triple_click.unwrap_or(false) {
|
||||||
$bindings.push(xr::Binding::new(&$left.triple.action_bool, p));
|
$bindings.push(xr::Binding::new(&$left.triple.action_bool, p));
|
||||||
} else if action.double_click.unwrap_or(false) {
|
} else if action.double_click.unwrap_or(false) {
|
||||||
@@ -502,8 +478,8 @@ macro_rules! add_custom {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(p) = to_path(&action.right, $instance) {
|
if let Some(p) = to_path(action.right.as_ref(), $instance) {
|
||||||
if is_bool(&action.right) {
|
if is_bool(action.right.as_ref()) {
|
||||||
if action.triple_click.unwrap_or(false) {
|
if action.triple_click.unwrap_or(false) {
|
||||||
$bindings.push(xr::Binding::new(&$right.triple.action_bool, p));
|
$bindings.push(xr::Binding::new(&$right.triple.action_bool, p));
|
||||||
} else if action.double_click.unwrap_or(false) {
|
} else if action.double_click.unwrap_or(false) {
|
||||||
@@ -525,8 +501,9 @@ macro_rules! add_custom {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn suggest_bindings(instance: &xr::Instance, hands: &[&OpenXrHandSource; 2]) -> anyhow::Result<()> {
|
#[allow(clippy::too_many_lines, clippy::cognitive_complexity)]
|
||||||
let profiles = load_action_profiles()?;
|
fn suggest_bindings(instance: &xr::Instance, hands: &[&OpenXrHandSource; 2]) {
|
||||||
|
let profiles = load_action_profiles();
|
||||||
|
|
||||||
for profile in profiles {
|
for profile in profiles {
|
||||||
let Ok(profile_path) = instance.string_to_path(&profile.profile) else {
|
let Ok(profile_path) = instance.string_to_path(&profile.profile) else {
|
||||||
@@ -537,116 +514,116 @@ fn suggest_bindings(instance: &xr::Instance, hands: &[&OpenXrHandSource; 2]) ->
|
|||||||
let mut bindings: Vec<xr::Binding> = vec![];
|
let mut bindings: Vec<xr::Binding> = vec![];
|
||||||
|
|
||||||
if let Some(action) = profile.pose {
|
if let Some(action) = profile.pose {
|
||||||
if let Some(p) = to_path(&action.left, instance) {
|
if let Some(p) = to_path(action.left.as_ref(), instance) {
|
||||||
bindings.push(xr::Binding::new(&hands[0].action_pose, p));
|
bindings.push(xr::Binding::new(&hands[0].pose, p));
|
||||||
}
|
}
|
||||||
if let Some(p) = to_path(&action.right, instance) {
|
if let Some(p) = to_path(action.right.as_ref(), instance) {
|
||||||
bindings.push(xr::Binding::new(&hands[1].action_pose, p));
|
bindings.push(xr::Binding::new(&hands[1].pose, p));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(action) = profile.haptic {
|
if let Some(action) = profile.haptic {
|
||||||
if let Some(p) = to_path(&action.left, instance) {
|
if let Some(p) = to_path(action.left.as_ref(), instance) {
|
||||||
bindings.push(xr::Binding::new(&hands[0].action_haptics, p));
|
bindings.push(xr::Binding::new(&hands[0].haptics, p));
|
||||||
}
|
}
|
||||||
if let Some(p) = to_path(&action.right, instance) {
|
if let Some(p) = to_path(action.right.as_ref(), instance) {
|
||||||
bindings.push(xr::Binding::new(&hands[1].action_haptics, p));
|
bindings.push(xr::Binding::new(&hands[1].haptics, p));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(action) = profile.scroll {
|
if let Some(action) = profile.scroll {
|
||||||
if let Some(p) = to_path(&action.left, instance) {
|
if let Some(p) = to_path(action.left.as_ref(), instance) {
|
||||||
bindings.push(xr::Binding::new(&hands[0].action_scroll, p));
|
bindings.push(xr::Binding::new(&hands[0].scroll, p));
|
||||||
}
|
}
|
||||||
if let Some(p) = to_path(&action.right, instance) {
|
if let Some(p) = to_path(action.right.as_ref(), instance) {
|
||||||
bindings.push(xr::Binding::new(&hands[1].action_scroll, p));
|
bindings.push(xr::Binding::new(&hands[1].scroll, p));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
add_custom!(
|
add_custom!(
|
||||||
profile.click,
|
profile.click,
|
||||||
hands[0].action_click,
|
hands[0].click,
|
||||||
hands[1].action_click,
|
hands[1].click,
|
||||||
bindings,
|
bindings,
|
||||||
instance
|
instance
|
||||||
);
|
);
|
||||||
|
|
||||||
add_custom!(
|
add_custom!(
|
||||||
profile.alt_click,
|
profile.alt_click,
|
||||||
&hands[0].action_alt_click,
|
&hands[0].alt_click,
|
||||||
&hands[1].action_alt_click,
|
&hands[1].alt_click,
|
||||||
bindings,
|
bindings,
|
||||||
instance
|
instance
|
||||||
);
|
);
|
||||||
|
|
||||||
add_custom!(
|
add_custom!(
|
||||||
profile.grab,
|
profile.grab,
|
||||||
&hands[0].action_grab,
|
&hands[0].grab,
|
||||||
&hands[1].action_grab,
|
&hands[1].grab,
|
||||||
bindings,
|
bindings,
|
||||||
instance
|
instance
|
||||||
);
|
);
|
||||||
|
|
||||||
add_custom!(
|
add_custom!(
|
||||||
profile.show_hide,
|
profile.show_hide,
|
||||||
&hands[0].action_show_hide,
|
&hands[0].show_hide,
|
||||||
&hands[1].action_show_hide,
|
&hands[1].show_hide,
|
||||||
bindings,
|
bindings,
|
||||||
instance
|
instance
|
||||||
);
|
);
|
||||||
|
|
||||||
add_custom!(
|
add_custom!(
|
||||||
profile.toggle_dashboard,
|
profile.toggle_dashboard,
|
||||||
&hands[0].action_toggle_dashboard,
|
&hands[0].toggle_dashboard,
|
||||||
&hands[1].action_toggle_dashboard,
|
&hands[1].toggle_dashboard,
|
||||||
bindings,
|
bindings,
|
||||||
instance
|
instance
|
||||||
);
|
);
|
||||||
|
|
||||||
add_custom!(
|
add_custom!(
|
||||||
profile.space_drag,
|
profile.space_drag,
|
||||||
&hands[0].action_space_drag,
|
&hands[0].space_drag,
|
||||||
&hands[1].action_space_drag,
|
&hands[1].space_drag,
|
||||||
bindings,
|
bindings,
|
||||||
instance
|
instance
|
||||||
);
|
);
|
||||||
|
|
||||||
add_custom!(
|
add_custom!(
|
||||||
profile.space_rotate,
|
profile.space_rotate,
|
||||||
&hands[0].action_space_rotate,
|
&hands[0].space_rotate,
|
||||||
&hands[1].action_space_rotate,
|
&hands[1].space_rotate,
|
||||||
bindings,
|
bindings,
|
||||||
instance
|
instance
|
||||||
);
|
);
|
||||||
|
|
||||||
add_custom!(
|
add_custom!(
|
||||||
profile.space_reset,
|
profile.space_reset,
|
||||||
&hands[0].action_space_reset,
|
&hands[0].space_reset,
|
||||||
&hands[1].action_space_reset,
|
&hands[1].space_reset,
|
||||||
bindings,
|
bindings,
|
||||||
instance
|
instance
|
||||||
);
|
);
|
||||||
|
|
||||||
add_custom!(
|
add_custom!(
|
||||||
profile.click_modifier_right,
|
profile.click_modifier_right,
|
||||||
&hands[0].action_modifier_right,
|
&hands[0].modifier_right,
|
||||||
&hands[1].action_modifier_right,
|
&hands[1].modifier_right,
|
||||||
bindings,
|
bindings,
|
||||||
instance
|
instance
|
||||||
);
|
);
|
||||||
|
|
||||||
add_custom!(
|
add_custom!(
|
||||||
profile.click_modifier_middle,
|
profile.click_modifier_middle,
|
||||||
&hands[0].action_modifier_middle,
|
&hands[0].modifier_middle,
|
||||||
&hands[1].action_modifier_middle,
|
&hands[1].modifier_middle,
|
||||||
bindings,
|
bindings,
|
||||||
instance
|
instance
|
||||||
);
|
);
|
||||||
|
|
||||||
add_custom!(
|
add_custom!(
|
||||||
profile.move_mouse,
|
profile.move_mouse,
|
||||||
&hands[0].action_move_mouse,
|
&hands[0].move_mouse,
|
||||||
&hands[1].action_move_mouse,
|
&hands[1].move_mouse,
|
||||||
bindings,
|
bindings,
|
||||||
instance
|
instance
|
||||||
);
|
);
|
||||||
@@ -659,8 +636,6 @@ fn suggest_bindings(instance: &xr::Instance, hands: &[&OpenXrHandSource; 2]) ->
|
|||||||
log::error!("Verify config: ~/.config/wlxoverlay/openxr_actions.json5");
|
log::error!("Verify config: ~/.config/wlxoverlay/openxr_actions.json5");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
@@ -693,26 +668,26 @@ struct OpenXrActionConfProfile {
|
|||||||
|
|
||||||
const DEFAULT_PROFILES: &str = include_str!("openxr_actions.json5");
|
const DEFAULT_PROFILES: &str = include_str!("openxr_actions.json5");
|
||||||
|
|
||||||
fn load_action_profiles() -> anyhow::Result<Vec<OpenXrActionConfProfile>> {
|
fn load_action_profiles() -> Vec<OpenXrActionConfProfile> {
|
||||||
let mut profiles: Vec<OpenXrActionConfProfile> =
|
let mut profiles: Vec<OpenXrActionConfProfile> =
|
||||||
serde_json5::from_str(DEFAULT_PROFILES).unwrap(); // want panic
|
serde_json5::from_str(DEFAULT_PROFILES).unwrap(); // want panic
|
||||||
|
|
||||||
let Some(conf) = config_io::load("openxr_actions.json5") else {
|
let Some(conf) = config_io::load("openxr_actions.json5") else {
|
||||||
return Ok(profiles);
|
return profiles;
|
||||||
};
|
};
|
||||||
|
|
||||||
match serde_json5::from_str::<Vec<OpenXrActionConfProfile>>(&conf) {
|
match serde_json5::from_str::<Vec<OpenXrActionConfProfile>>(&conf) {
|
||||||
Ok(override_profiles) => {
|
Ok(override_profiles) => {
|
||||||
override_profiles.into_iter().for_each(|new| {
|
for new in override_profiles {
|
||||||
if let Some(i) = profiles.iter().position(|old| old.profile == new.profile) {
|
if let Some(i) = profiles.iter().position(|old| old.profile == new.profile) {
|
||||||
profiles[i] = new;
|
profiles[i] = new;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("Failed to load openxr_actions.json5: {}", e);
|
log::error!("Failed to load openxr_actions.json5: {e}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(profiles)
|
profiles
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ impl LinePool {
|
|||||||
None,
|
None,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(LinePool {
|
Ok(Self {
|
||||||
lines: IdMap::new(),
|
lines: IdMap::new(),
|
||||||
pipeline,
|
pipeline,
|
||||||
})
|
})
|
||||||
@@ -92,7 +92,7 @@ impl LinePool {
|
|||||||
debug_assert!(color < COLORS.len());
|
debug_assert!(color < COLORS.len());
|
||||||
|
|
||||||
let Some(line) = self.lines.get_mut(id) else {
|
let Some(line) = self.lines.get_mut(id) else {
|
||||||
log::warn!("Line {} not found", id);
|
log::warn!("Line {id} not found");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -184,14 +184,6 @@ impl LinePool {
|
|||||||
|
|
||||||
Ok(quads)
|
Ok(quads)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// the number of lines that are waiting to be drawn
|
|
||||||
pub(super) fn num_pending(&self) -> usize {
|
|
||||||
self.lines
|
|
||||||
.values()
|
|
||||||
.filter(|l| l.maybe_line.is_some())
|
|
||||||
.count()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct Line {
|
pub(super) struct Line {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use glam::{Affine3A, Vec3};
|
use glam::{Affine3A, Vec3};
|
||||||
|
use input::OpenXrInputSource;
|
||||||
use libmonado::Monado;
|
use libmonado::Monado;
|
||||||
use openxr as xr;
|
use openxr as xr;
|
||||||
use skybox::create_skybox;
|
use skybox::create_skybox;
|
||||||
@@ -43,30 +44,28 @@ mod skybox;
|
|||||||
mod swapchain;
|
mod swapchain;
|
||||||
|
|
||||||
const VIEW_TYPE: xr::ViewConfigurationType = xr::ViewConfigurationType::PRIMARY_STEREO;
|
const VIEW_TYPE: xr::ViewConfigurationType = xr::ViewConfigurationType::PRIMARY_STEREO;
|
||||||
const VIEW_COUNT: u32 = 2;
|
|
||||||
static FRAME_COUNTER: AtomicUsize = AtomicUsize::new(0);
|
static FRAME_COUNTER: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
|
||||||
struct XrState {
|
struct XrState {
|
||||||
instance: xr::Instance,
|
instance: xr::Instance,
|
||||||
system: xr::SystemId,
|
|
||||||
session: xr::Session<xr::Vulkan>,
|
session: xr::Session<xr::Vulkan>,
|
||||||
predicted_display_time: xr::Time,
|
predicted_display_time: xr::Time,
|
||||||
fps: f32,
|
fps: f32,
|
||||||
stage: Arc<xr::Space>,
|
stage: Arc<xr::Space>,
|
||||||
view: Arc<xr::Space>,
|
view: Arc<xr::Space>,
|
||||||
stage_offset: Affine3A,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_lines, clippy::cognitive_complexity)]
|
||||||
pub fn openxr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(), BackendError> {
|
pub fn openxr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(), BackendError> {
|
||||||
let (xr_instance, system) = match helpers::init_xr() {
|
let (xr_instance, system) = match helpers::init_xr() {
|
||||||
Ok((xr_instance, system)) => (xr_instance, system),
|
Ok((xr_instance, system)) => (xr_instance, system),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::warn!("Will not use OpenXR: {}", e);
|
log::warn!("Will not use OpenXR: {e}");
|
||||||
return Err(BackendError::NotSupported);
|
return Err(BackendError::NotSupported);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut app_state = {
|
let mut app = {
|
||||||
let graphics = WlxGraphics::new_openxr(xr_instance.clone(), system)?;
|
let graphics = WlxGraphics::new_openxr(xr_instance.clone(), system)?;
|
||||||
AppState::from_graphics(graphics)?
|
AppState::from_graphics(graphics)?
|
||||||
};
|
};
|
||||||
@@ -74,24 +73,24 @@ pub fn openxr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
|
|||||||
let environment_blend_mode = {
|
let environment_blend_mode = {
|
||||||
let modes = xr_instance.enumerate_environment_blend_modes(system, VIEW_TYPE)?;
|
let modes = xr_instance.enumerate_environment_blend_modes(system, VIEW_TYPE)?;
|
||||||
if modes.contains(&xr::EnvironmentBlendMode::ALPHA_BLEND)
|
if modes.contains(&xr::EnvironmentBlendMode::ALPHA_BLEND)
|
||||||
&& app_state.session.config.use_passthrough
|
&& app.session.config.use_passthrough
|
||||||
{
|
{
|
||||||
xr::EnvironmentBlendMode::ALPHA_BLEND
|
xr::EnvironmentBlendMode::ALPHA_BLEND
|
||||||
} else {
|
} else {
|
||||||
modes[0]
|
modes[0]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
log::info!("Using environment blend mode: {:?}", environment_blend_mode);
|
log::info!("Using environment blend mode: {environment_blend_mode:?}");
|
||||||
|
|
||||||
if show_by_default {
|
if show_by_default {
|
||||||
app_state.tasks.enqueue_at(
|
app.tasks.enqueue_at(
|
||||||
TaskType::System(SystemTask::ShowHide),
|
TaskType::System(SystemTask::ShowHide),
|
||||||
Instant::now().add(Duration::from_secs(1)),
|
Instant::now().add(Duration::from_secs(1)),
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut overlays = OverlayContainer::<OpenXrOverlayData>::new(&mut app_state)?;
|
let mut overlays = OverlayContainer::<OpenXrOverlayData>::new(&mut app)?;
|
||||||
let mut lines = LinePool::new(app_state.graphics.clone())?;
|
let mut lines = LinePool::new(app.graphics.clone())?;
|
||||||
|
|
||||||
let mut notifications = NotificationManager::new();
|
let mut notifications = NotificationManager::new();
|
||||||
notifications.run_dbus();
|
notifications.run_dbus();
|
||||||
@@ -100,12 +99,12 @@ pub fn openxr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
|
|||||||
let mut delete_queue = vec![];
|
let mut delete_queue = vec![];
|
||||||
|
|
||||||
let mut monado = Monado::auto_connect()
|
let mut monado = Monado::auto_connect()
|
||||||
.map_err(|e| log::warn!("Will not use libmonado: {}", e))
|
.map_err(|e| log::warn!("Will not use libmonado: {e}"))
|
||||||
.ok();
|
.ok();
|
||||||
|
|
||||||
let mut playspace = monado.as_mut().and_then(|m| {
|
let mut playspace = monado.as_mut().and_then(|m| {
|
||||||
playspace::PlayspaceMover::new(m)
|
playspace::PlayspaceMover::new(m)
|
||||||
.map_err(|e| log::warn!("Will not use Monado playspace mover: {}", e))
|
.map_err(|e| log::warn!("Will not use Monado playspace mover: {e}"))
|
||||||
.ok()
|
.ok()
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -114,15 +113,10 @@ pub fn openxr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
|
|||||||
&xr_instance,
|
&xr_instance,
|
||||||
system,
|
system,
|
||||||
&xr::vulkan::SessionCreateInfo {
|
&xr::vulkan::SessionCreateInfo {
|
||||||
instance: app_state.graphics.instance.handle().as_raw() as _,
|
instance: app.graphics.instance.handle().as_raw() as _,
|
||||||
physical_device: app_state
|
physical_device: app.graphics.device.physical_device().handle().as_raw() as _,
|
||||||
.graphics
|
device: app.graphics.device.handle().as_raw() as _,
|
||||||
.device
|
queue_family_index: app.graphics.queue.queue_family_index(),
|
||||||
.physical_device()
|
|
||||||
.handle()
|
|
||||||
.as_raw() as _,
|
|
||||||
device: app_state.graphics.device.handle().as_raw() as _,
|
|
||||||
queue_family_index: app_state.graphics.queue.queue_family_index(),
|
|
||||||
queue_index: 0,
|
queue_index: 0,
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
@@ -136,24 +130,22 @@ pub fn openxr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
|
|||||||
|
|
||||||
let mut xr_state = XrState {
|
let mut xr_state = XrState {
|
||||||
instance: xr_instance,
|
instance: xr_instance,
|
||||||
system,
|
|
||||||
session,
|
session,
|
||||||
predicted_display_time: xr::Time::from_nanos(0),
|
predicted_display_time: xr::Time::from_nanos(0),
|
||||||
fps: 30.0,
|
fps: 30.0,
|
||||||
stage: Arc::new(stage),
|
stage: Arc::new(stage),
|
||||||
view: Arc::new(view),
|
view: Arc::new(view),
|
||||||
stage_offset: Affine3A::IDENTITY,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut skybox = if environment_blend_mode == xr::EnvironmentBlendMode::OPAQUE {
|
let mut skybox = if environment_blend_mode == xr::EnvironmentBlendMode::OPAQUE {
|
||||||
create_skybox(&xr_state, &app_state)
|
create_skybox(&xr_state, &app)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let pointer_lines = [
|
let pointer_lines = [
|
||||||
lines.allocate(&xr_state, app_state.graphics.clone())?,
|
lines.allocate(&xr_state, app.graphics.clone())?,
|
||||||
lines.allocate(&xr_state, app_state.graphics.clone())?,
|
lines.allocate(&xr_state, app.graphics.clone())?,
|
||||||
];
|
];
|
||||||
|
|
||||||
let watch_id = overlays.get_by_name(WATCH_NAME).unwrap().state.id; // want panic
|
let watch_id = overlays.get_by_name(WATCH_NAME).unwrap().state.id; // want panic
|
||||||
@@ -176,19 +168,18 @@ pub fn openxr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
|
|||||||
if !running.load(Ordering::Relaxed) {
|
if !running.load(Ordering::Relaxed) {
|
||||||
log::warn!("Received shutdown signal.");
|
log::warn!("Received shutdown signal.");
|
||||||
match xr_state.session.request_exit() {
|
match xr_state.session.request_exit() {
|
||||||
Ok(_) => log::info!("OpenXR session exit requested."),
|
Ok(()) => log::info!("OpenXR session exit requested."),
|
||||||
Err(xr::sys::Result::ERROR_SESSION_NOT_RUNNING) => break 'main_loop,
|
Err(xr::sys::Result::ERROR_SESSION_NOT_RUNNING) => break 'main_loop,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("Failed to request OpenXR session exit: {}", e);
|
log::error!("Failed to request OpenXR session exit: {e}");
|
||||||
break 'main_loop;
|
break 'main_loop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while let Some(event) = xr_state.instance.poll_event(&mut event_storage)? {
|
while let Some(event) = xr_state.instance.poll_event(&mut event_storage)? {
|
||||||
use xr::Event::*;
|
|
||||||
match event {
|
match event {
|
||||||
SessionStateChanged(e) => {
|
xr::Event::SessionStateChanged(e) => {
|
||||||
// Session state change is where we can begin and end sessions, as well as
|
// Session state change is where we can begin and end sessions, as well as
|
||||||
// find quit messages!
|
// find quit messages!
|
||||||
log::info!("entered state {:?}", e.state());
|
log::info!("entered state {:?}", e.state());
|
||||||
@@ -207,22 +198,22 @@ pub fn openxr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InstanceLossPending(_) => {
|
xr::Event::InstanceLossPending(_) => {
|
||||||
break 'main_loop;
|
break 'main_loop;
|
||||||
}
|
}
|
||||||
EventsLost(e) => {
|
xr::Event::EventsLost(e) => {
|
||||||
log::warn!("lost {} events", e.lost_event_count());
|
log::warn!("lost {} events", e.lost_event_count());
|
||||||
}
|
}
|
||||||
MainSessionVisibilityChangedEXTX(e) => {
|
xr::Event::MainSessionVisibilityChangedEXTX(e) => {
|
||||||
if main_session_visible != e.visible() {
|
if main_session_visible != e.visible() {
|
||||||
main_session_visible = e.visible();
|
main_session_visible = e.visible();
|
||||||
log::info!("Main session visible: {}", main_session_visible);
|
log::info!("Main session visible: {main_session_visible}");
|
||||||
if main_session_visible {
|
if main_session_visible {
|
||||||
log::debug!("Destroying skybox.");
|
log::debug!("Destroying skybox.");
|
||||||
skybox = None;
|
skybox = None;
|
||||||
} else if environment_blend_mode == xr::EnvironmentBlendMode::OPAQUE {
|
} else if environment_blend_mode == xr::EnvironmentBlendMode::OPAQUE {
|
||||||
log::debug!("Allocating skybox.");
|
log::debug!("Allocating skybox.");
|
||||||
skybox = create_skybox(&xr_state, &app_state);
|
skybox = create_skybox(&xr_state, &app);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -232,7 +223,7 @@ pub fn openxr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
|
|||||||
|
|
||||||
if next_device_update <= Instant::now() {
|
if next_device_update <= Instant::now() {
|
||||||
if let Some(monado) = &mut monado {
|
if let Some(monado) = &mut monado {
|
||||||
input_source.update_devices(&mut app_state, monado);
|
OpenXrInputSource::update_devices(&mut app, monado);
|
||||||
next_device_update = Instant::now() + Duration::from_secs(30);
|
next_device_update = Instant::now() + Duration::from_secs(30);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -259,8 +250,7 @@ pub fn openxr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
|
|||||||
|
|
||||||
let total_elapsed = fps_counter
|
let total_elapsed = fps_counter
|
||||||
.front()
|
.front()
|
||||||
.map(|time| time.elapsed().as_secs_f32())
|
.map_or(0f32, |time| time.elapsed().as_secs_f32());
|
||||||
.unwrap_or(0f32);
|
|
||||||
|
|
||||||
fps_counter.len() as f32 / total_elapsed
|
fps_counter.len() as f32 / total_elapsed
|
||||||
};
|
};
|
||||||
@@ -274,46 +264,46 @@ pub fn openxr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
|
|||||||
continue 'main_loop;
|
continue 'main_loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
app_state.input_state.pre_update();
|
app.input_state.pre_update();
|
||||||
input_source.update(&xr_state, &mut app_state)?;
|
input_source.update(&xr_state, &mut app)?;
|
||||||
app_state.input_state.post_update(&app_state.session);
|
app.input_state.post_update(&app.session);
|
||||||
|
|
||||||
if app_state
|
if app
|
||||||
.input_state
|
.input_state
|
||||||
.pointers
|
.pointers
|
||||||
.iter()
|
.iter()
|
||||||
.any(|p| p.now.show_hide && !p.before.show_hide)
|
.any(|p| p.now.show_hide && !p.before.show_hide)
|
||||||
{
|
{
|
||||||
overlays.show_hide(&mut app_state);
|
overlays.show_hide(&mut app);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "wayvr")]
|
#[cfg(feature = "wayvr")]
|
||||||
if app_state
|
if app
|
||||||
.input_state
|
.input_state
|
||||||
.pointers
|
.pointers
|
||||||
.iter()
|
.iter()
|
||||||
.any(|p| p.now.toggle_dashboard && !p.before.toggle_dashboard)
|
.any(|p| p.now.toggle_dashboard && !p.before.toggle_dashboard)
|
||||||
{
|
{
|
||||||
wayvr_action(&mut app_state, &mut overlays, &WayVRAction::ToggleDashboard);
|
wayvr_action(&mut app, &mut overlays, &WayVRAction::ToggleDashboard);
|
||||||
}
|
}
|
||||||
|
|
||||||
watch_fade(&mut app_state, overlays.mut_by_id(watch_id).unwrap()); // want panic
|
watch_fade(&mut app, overlays.mut_by_id(watch_id).unwrap()); // want panic
|
||||||
if let Some(ref mut space_mover) = playspace {
|
if let Some(ref mut space_mover) = playspace {
|
||||||
space_mover.update(
|
space_mover.update(
|
||||||
&mut overlays,
|
&mut overlays,
|
||||||
&app_state,
|
&app,
|
||||||
monado.as_mut().unwrap(), // safe
|
monado.as_mut().unwrap(), // safe
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for o in overlays.iter_mut() {
|
for o in overlays.iter_mut() {
|
||||||
o.after_input(&mut app_state)?;
|
o.after_input(&mut app)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "osc")]
|
#[cfg(feature = "osc")]
|
||||||
if let Some(ref mut sender) = app_state.osc_sender {
|
if let Some(ref mut sender) = app.osc_sender {
|
||||||
let _ = sender.send_params(&overlays, &app_state.input_state.devices);
|
let _ = sender.send_params(&overlays, &app.input_state.devices);
|
||||||
};
|
}
|
||||||
|
|
||||||
let (_, views) = xr_state.session.locate_views(
|
let (_, views) = xr_state.session.locate_views(
|
||||||
VIEW_TYPE,
|
VIEW_TYPE,
|
||||||
@@ -322,36 +312,36 @@ pub fn openxr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
let ipd = helpers::ipd_from_views(&views);
|
let ipd = helpers::ipd_from_views(&views);
|
||||||
if (app_state.input_state.ipd - ipd).abs() > 0.01 {
|
if (app.input_state.ipd - ipd).abs() > 0.01 {
|
||||||
log::info!("IPD changed: {} -> {}", app_state.input_state.ipd, ipd);
|
log::info!("IPD changed: {} -> {}", app.input_state.ipd, ipd);
|
||||||
app_state.input_state.ipd = ipd;
|
app.input_state.ipd = ipd;
|
||||||
Toast::new(
|
Toast::new(
|
||||||
ToastTopic::IpdChange,
|
ToastTopic::IpdChange,
|
||||||
"IPD".into(),
|
"IPD".into(),
|
||||||
format!("{:.1} mm", ipd).into(),
|
format!("{ipd:.1} mm").into(),
|
||||||
)
|
)
|
||||||
.submit(&mut app_state);
|
.submit(&mut app);
|
||||||
}
|
}
|
||||||
|
|
||||||
overlays
|
overlays
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.for_each(|o| o.state.auto_movement(&mut app_state));
|
.for_each(|o| o.state.auto_movement(&mut app));
|
||||||
|
|
||||||
let lengths_haptics = interact(&mut overlays, &mut app_state);
|
let lengths_haptics = interact(&mut overlays, &mut app);
|
||||||
for (idx, (len, haptics)) in lengths_haptics.iter().enumerate() {
|
for (idx, (len, haptics)) in lengths_haptics.iter().enumerate() {
|
||||||
lines.draw_from(
|
lines.draw_from(
|
||||||
pointer_lines[idx],
|
pointer_lines[idx],
|
||||||
app_state.input_state.pointers[idx].pose,
|
app.input_state.pointers[idx].pose,
|
||||||
*len,
|
*len,
|
||||||
app_state.input_state.pointers[idx].interaction.mode as usize + 1,
|
app.input_state.pointers[idx].interaction.mode as usize + 1,
|
||||||
&app_state.input_state.hmd,
|
&app.input_state.hmd,
|
||||||
);
|
);
|
||||||
if let Some(haptics) = haptics {
|
if let Some(haptics) = haptics {
|
||||||
input_source.haptics(&xr_state, idx, haptics);
|
input_source.haptics(&xr_state, idx, haptics);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
app_state.hid_provider.commit();
|
app.hid_provider.commit();
|
||||||
|
|
||||||
let watch = overlays.mut_by_id(watch_id).unwrap(); // want panic
|
let watch = overlays.mut_by_id(watch_id).unwrap(); // want panic
|
||||||
let watch_transform = watch.state.transform;
|
let watch_transform = watch.state.transform;
|
||||||
@@ -366,9 +356,9 @@ pub fn openxr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
|
|||||||
|
|
||||||
#[cfg(feature = "wayvr")]
|
#[cfg(feature = "wayvr")]
|
||||||
if let Err(e) =
|
if let Err(e) =
|
||||||
crate::overlays::wayvr::tick_events::<OpenXrOverlayData>(&mut app_state, &mut overlays)
|
crate::overlays::wayvr::tick_events::<OpenXrOverlayData>(&mut app, &mut overlays)
|
||||||
{
|
{
|
||||||
log::error!("WayVR tick_events failed: {:?}", e);
|
log::error!("WayVR tick_events failed: {e:?}");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Begin rendering
|
// Begin rendering
|
||||||
@@ -376,7 +366,7 @@ pub fn openxr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
|
|||||||
|
|
||||||
if !main_session_visible {
|
if !main_session_visible {
|
||||||
if let Some(skybox) = skybox.as_mut() {
|
if let Some(skybox) = skybox.as_mut() {
|
||||||
skybox.render(&xr_state, &app_state, &mut buffers)?;
|
skybox.render(&xr_state, &app, &mut buffers)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -387,22 +377,22 @@ pub fn openxr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !o.data.init {
|
if !o.data.init {
|
||||||
o.init(&mut app_state)?;
|
o.init(&mut app)?;
|
||||||
o.data.init = true;
|
o.data.init = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let should_render = match o.should_render(&mut app_state)? {
|
let should_render = match o.should_render(&mut app)? {
|
||||||
ShouldRender::Should => true,
|
ShouldRender::Should => true,
|
||||||
ShouldRender::Can => o.data.last_alpha != o.state.alpha,
|
ShouldRender::Can => (o.data.last_alpha - o.state.alpha).abs() > f32::EPSILON,
|
||||||
ShouldRender::Unable => false, //try show old image if exists
|
ShouldRender::Unable => false, //try show old image if exists
|
||||||
};
|
};
|
||||||
|
|
||||||
if should_render {
|
if should_render {
|
||||||
if !o.ensure_swapchain(&app_state, &xr_state)? {
|
if !o.ensure_swapchain(&app, &xr_state)? {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let tgt = o.data.swapchain.as_mut().unwrap().acquire_wait_image()?; // want
|
let tgt = o.data.swapchain.as_mut().unwrap().acquire_wait_image()?; // want
|
||||||
if !o.render(&mut app_state, tgt, &mut buffers, o.state.alpha)? {
|
if !o.render(&mut app, tgt, &mut buffers, o.state.alpha)? {
|
||||||
o.data.swapchain.as_mut().unwrap().ensure_image_released()?; // want
|
o.data.swapchain.as_mut().unwrap().ensure_image_released()?; // want
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -413,13 +403,13 @@ pub fn openxr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
|
|||||||
o.data.cur_visible = true;
|
o.data.cur_visible = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
lines.render(app_state.graphics.clone(), &mut buffers)?;
|
lines.render(app.graphics.clone(), &mut buffers)?;
|
||||||
|
|
||||||
let future = buffers.execute_now(app_state.graphics.queue.clone())?;
|
let future = buffers.execute_now(app.graphics.queue.clone())?;
|
||||||
if let Some(mut future) = future {
|
if let Some(mut future) = future {
|
||||||
if let Err(e) = future.flush() {
|
if let Err(e) = future.flush() {
|
||||||
return Err(BackendError::Fatal(e.into()));
|
return Err(BackendError::Fatal(e.into()));
|
||||||
};
|
}
|
||||||
future.cleanup_finished();
|
future.cleanup_finished();
|
||||||
}
|
}
|
||||||
// End rendering
|
// End rendering
|
||||||
@@ -428,12 +418,8 @@ pub fn openxr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
|
|||||||
let mut layers = vec![];
|
let mut layers = vec![];
|
||||||
if !main_session_visible {
|
if !main_session_visible {
|
||||||
if let Some(skybox) = skybox.as_mut() {
|
if let Some(skybox) = skybox.as_mut() {
|
||||||
for (idx, layer) in skybox
|
for (idx, layer) in skybox.present(&xr_state, &app)?.into_iter().enumerate() {
|
||||||
.present(&xr_state, &app_state)?
|
layers.push(((idx as f32).mul_add(-50.0, 200.0), layer));
|
||||||
.into_iter()
|
|
||||||
.enumerate()
|
|
||||||
{
|
|
||||||
layers.push((200.0 - 50.0 * (idx as f32), layer));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -442,7 +428,7 @@ pub fn openxr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
|
|||||||
if !o.data.cur_visible {
|
if !o.data.cur_visible {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let dist_sq = (app_state.input_state.hmd.translation - o.state.transform.translation)
|
let dist_sq = (app.input_state.hmd.translation - o.state.transform.translation)
|
||||||
.length_squared()
|
.length_squared()
|
||||||
+ (100f32 - o.state.z_order as f32);
|
+ (100f32 - o.state.z_order as f32);
|
||||||
if !dist_sq.is_normal() {
|
if !dist_sq.is_normal() {
|
||||||
@@ -450,14 +436,14 @@ pub fn openxr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let maybe_layer = o.present(&xr_state)?;
|
let maybe_layer = o.present(&xr_state)?;
|
||||||
if let CompositionLayer::None = maybe_layer {
|
if matches!(maybe_layer, CompositionLayer::None) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
layers.push((dist_sq, maybe_layer));
|
layers.push((dist_sq, maybe_layer));
|
||||||
}
|
}
|
||||||
|
|
||||||
for maybe_layer in lines.present(&xr_state)? {
|
for maybe_layer in lines.present(&xr_state)? {
|
||||||
if let CompositionLayer::None = maybe_layer {
|
if matches!(maybe_layer, CompositionLayer::None) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
layers.push((0.0, maybe_layer));
|
layers.push((0.0, maybe_layer));
|
||||||
@@ -465,7 +451,7 @@ pub fn openxr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
|
|||||||
// End layer composition
|
// End layer composition
|
||||||
|
|
||||||
#[cfg(feature = "wayvr")]
|
#[cfg(feature = "wayvr")]
|
||||||
if let Some(wayvr) = &app_state.wayvr {
|
if let Some(wayvr) = &app.wayvr {
|
||||||
wayvr.borrow_mut().data.tick_finish()?;
|
wayvr.borrow_mut().data.tick_finish()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -489,22 +475,21 @@ pub fn openxr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
|
|||||||
)?;
|
)?;
|
||||||
// End layer submit
|
// End layer submit
|
||||||
|
|
||||||
let removed_overlays = overlays.update(&mut app_state)?;
|
let removed_overlays = overlays.update(&mut app)?;
|
||||||
for o in removed_overlays {
|
for o in removed_overlays {
|
||||||
delete_queue.push((o, cur_frame + 5));
|
delete_queue.push((o, cur_frame + 5));
|
||||||
}
|
}
|
||||||
|
|
||||||
notifications.submit_pending(&mut app_state);
|
notifications.submit_pending(&mut app);
|
||||||
|
|
||||||
app_state.tasks.retrieve_due(&mut due_tasks);
|
app.tasks.retrieve_due(&mut due_tasks);
|
||||||
while let Some(task) = due_tasks.pop_front() {
|
while let Some(task) = due_tasks.pop_front() {
|
||||||
match task {
|
match task {
|
||||||
TaskType::Global(f) => f(&mut app_state),
|
|
||||||
TaskType::Overlay(sel, f) => {
|
TaskType::Overlay(sel, f) => {
|
||||||
if let Some(o) = overlays.mut_by_selector(&sel) {
|
if let Some(o) = overlays.mut_by_selector(&sel) {
|
||||||
f(&mut app_state, &mut o.state);
|
f(&mut app, &mut o.state);
|
||||||
} else {
|
} else {
|
||||||
log::warn!("Overlay not found for task: {:?}", sel);
|
log::warn!("Overlay not found for task: {sel:?}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TaskType::CreateOverlay(sel, f) => {
|
TaskType::CreateOverlay(sel, f) => {
|
||||||
@@ -512,14 +497,14 @@ pub fn openxr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
|
|||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some((mut state, backend)) = f(&mut app_state) else {
|
let Some((mut overlay_state, overlay_backend)) = f(&mut app) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
state.birthframe = cur_frame;
|
overlay_state.birthframe = cur_frame;
|
||||||
|
|
||||||
overlays.add(OverlayData {
|
overlays.add(OverlayData {
|
||||||
state,
|
state: overlay_state,
|
||||||
backend,
|
backend: overlay_backend,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -538,7 +523,7 @@ pub fn openxr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
|
|||||||
SystemTask::FixFloor => {
|
SystemTask::FixFloor => {
|
||||||
if let Some(ref mut playspace) = playspace {
|
if let Some(ref mut playspace) = playspace {
|
||||||
playspace.fix_floor(
|
playspace.fix_floor(
|
||||||
&app_state.input_state,
|
&app.input_state,
|
||||||
monado.as_mut().unwrap(), // safe
|
monado.as_mut().unwrap(), // safe
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -549,13 +534,13 @@ pub fn openxr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
SystemTask::ShowHide => {
|
SystemTask::ShowHide => {
|
||||||
overlays.show_hide(&mut app_state);
|
overlays.show_hide(&mut app);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
#[cfg(feature = "wayvr")]
|
#[cfg(feature = "wayvr")]
|
||||||
TaskType::WayVR(action) => {
|
TaskType::WayVR(action) => {
|
||||||
wayvr_action(&mut app_state, &mut overlays, &action);
|
wayvr_action(&mut app, &mut overlays, &action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,13 +8,6 @@ use crate::{
|
|||||||
|
|
||||||
use super::overlay::OpenXrOverlayData;
|
use super::overlay::OpenXrOverlayData;
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Default, Debug)]
|
|
||||||
struct XrtPose {
|
|
||||||
orientation: [f32; 4],
|
|
||||||
position: [f32; 3],
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MoverData<T> {
|
struct MoverData<T> {
|
||||||
pose: Affine3A,
|
pose: Affine3A,
|
||||||
hand: usize,
|
hand: usize,
|
||||||
@@ -55,7 +48,7 @@ impl PlayspaceMover {
|
|||||||
state: &AppState,
|
state: &AppState,
|
||||||
monado: &mut Monado,
|
monado: &mut Monado,
|
||||||
) {
|
) {
|
||||||
for pointer in state.input_state.pointers.iter() {
|
for pointer in &state.input_state.pointers {
|
||||||
if pointer.now.space_reset {
|
if pointer.now.space_reset {
|
||||||
if !pointer.before.space_reset {
|
if !pointer.before.space_reset {
|
||||||
log::info!("Space reset");
|
log::info!("Space reset");
|
||||||
@@ -81,8 +74,8 @@ impl PlayspaceMover {
|
|||||||
Affine3A::from_quat(dq)
|
Affine3A::from_quat(dq)
|
||||||
} else {
|
} else {
|
||||||
let rel_y = f32::atan2(
|
let rel_y = f32::atan2(
|
||||||
2.0 * (dq.y * dq.w + dq.x * dq.z),
|
2.0 * dq.y.mul_add(dq.w, dq.x * dq.z),
|
||||||
(2.0 * (dq.w * dq.w + dq.x * dq.x)) - 1.0,
|
2.0f32.mul_add(dq.w.mul_add(dq.w, dq.x * dq.x), -1.0),
|
||||||
);
|
);
|
||||||
|
|
||||||
Affine3A::from_rotation_y(rel_y)
|
Affine3A::from_rotation_y(rel_y)
|
||||||
@@ -96,7 +89,7 @@ impl PlayspaceMover {
|
|||||||
data.pose *= space_transform;
|
data.pose *= space_transform;
|
||||||
data.hand_pose = new_hand;
|
data.hand_pose = new_hand;
|
||||||
|
|
||||||
self.apply_offset(data.pose, monado);
|
apply_offset(data.pose, monado);
|
||||||
self.rotate = Some(data);
|
self.rotate = Some(data);
|
||||||
} else {
|
} else {
|
||||||
for (i, pointer) in state.input_state.pointers.iter().enumerate() {
|
for (i, pointer) in state.input_state.pointers.iter().enumerate() {
|
||||||
@@ -145,7 +138,7 @@ impl PlayspaceMover {
|
|||||||
data.pose.translation += relative_pos;
|
data.pose.translation += relative_pos;
|
||||||
data.hand_pose = new_hand;
|
data.hand_pose = new_hand;
|
||||||
|
|
||||||
self.apply_offset(data.pose, monado);
|
apply_offset(data.pose, monado);
|
||||||
self.drag = Some(data);
|
self.drag = Some(data);
|
||||||
} else {
|
} else {
|
||||||
for (i, pointer) in state.input_state.pointers.iter().enumerate() {
|
for (i, pointer) in state.input_state.pointers.iter().enumerate() {
|
||||||
@@ -176,7 +169,7 @@ impl PlayspaceMover {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.last_transform = Affine3A::IDENTITY;
|
self.last_transform = Affine3A::IDENTITY;
|
||||||
self.apply_offset(self.last_transform, monado);
|
apply_offset(self.last_transform, monado);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fix_floor(&mut self, input: &InputState, monado: &mut Monado) {
|
pub fn fix_floor(&mut self, input: &InputState, monado: &mut Monado) {
|
||||||
@@ -193,14 +186,14 @@ impl PlayspaceMover {
|
|||||||
let y2 = input.pointers[1].raw_pose.translation.y;
|
let y2 = input.pointers[1].raw_pose.translation.y;
|
||||||
let delta = y1.min(y2) - 0.03;
|
let delta = y1.min(y2) - 0.03;
|
||||||
self.last_transform.translation.y += delta;
|
self.last_transform.translation.y += delta;
|
||||||
self.apply_offset(self.last_transform, monado);
|
apply_offset(self.last_transform, monado);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_offset(&self, transform: Affine3A, monado: &mut Monado) {
|
fn apply_offset(transform: Affine3A, monado: &mut Monado) {
|
||||||
let pose = Pose {
|
let pose = Pose {
|
||||||
position: transform.translation.into(),
|
position: transform.translation.into(),
|
||||||
orientation: Quat::from_affine3(&transform).into(),
|
orientation: Quat::from_affine3(&transform).into(),
|
||||||
};
|
};
|
||||||
let _ = monado.set_reference_space_offset(ReferenceSpaceType::Stage, pose);
|
let _ = monado.set_reference_space_offset(ReferenceSpaceType::Stage, pose);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ impl Skybox {
|
|||||||
"Could not use custom skybox texture at: {}",
|
"Could not use custom skybox texture at: {}",
|
||||||
app.session.config.skybox_texture
|
app.session.config.skybox_texture
|
||||||
);
|
);
|
||||||
log::warn!("{:?}", e);
|
log::warn!("{e:?}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -181,6 +181,11 @@ impl Skybox {
|
|||||||
xr: &'a XrState,
|
xr: &'a XrState,
|
||||||
app: &AppState,
|
app: &AppState,
|
||||||
) -> anyhow::Result<Vec<CompositionLayer<'a>>> {
|
) -> anyhow::Result<Vec<CompositionLayer<'a>>> {
|
||||||
|
// cover the entire sphere
|
||||||
|
const HORIZ_ANGLE: f32 = 2.0 * PI;
|
||||||
|
const HI_VERT_ANGLE: f32 = 0.5 * PI;
|
||||||
|
const LO_VERT_ANGLE: f32 = -0.5 * PI;
|
||||||
|
|
||||||
static GRID_POSE: Lazy<xr::Posef> = Lazy::new(|| {
|
static GRID_POSE: Lazy<xr::Posef> = Lazy::new(|| {
|
||||||
translation_rotation_to_posef(Vec3A::ZERO, Quat::from_rotation_x(PI * -0.5))
|
translation_rotation_to_posef(Vec3A::ZERO, Quat::from_rotation_x(PI * -0.5))
|
||||||
});
|
});
|
||||||
@@ -194,11 +199,6 @@ impl Skybox {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// cover the entire sphere
|
|
||||||
const HORIZ_ANGLE: f32 = 2.0 * PI;
|
|
||||||
const HI_VERT_ANGLE: f32 = 0.5 * PI;
|
|
||||||
const LO_VERT_ANGLE: f32 = -0.5 * PI;
|
|
||||||
|
|
||||||
self.sky.as_mut().unwrap().ensure_image_released()?;
|
self.sky.as_mut().unwrap().ensure_image_released()?;
|
||||||
|
|
||||||
let sky = xr::CompositionLayerEquirect2KHR::new()
|
let sky = xr::CompositionLayerEquirect2KHR::new()
|
||||||
|
|||||||
@@ -20,9 +20,9 @@ pub(super) struct SwapchainOpts {
|
|||||||
|
|
||||||
impl SwapchainOpts {
|
impl SwapchainOpts {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Default::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
pub fn immutable(mut self) -> Self {
|
pub const fn immutable(mut self) -> Self {
|
||||||
self.immutable = true;
|
self.immutable = true;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ impl OscSender {
|
|||||||
bail!("Failed to bind UDP socket - OSC will not function.");
|
bail!("Failed to bind UDP socket - OSC will not function.");
|
||||||
};
|
};
|
||||||
|
|
||||||
let Ok(_) = upstream.connect(SocketAddr::new(ip, send_port)) else {
|
let Ok(()) = upstream.connect(SocketAddr::new(ip, send_port)) else {
|
||||||
bail!("Failed to connect UDP socket - OSC will not function.");
|
bail!("Failed to connect UDP socket - OSC will not function.");
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ impl OscSender {
|
|||||||
KEYBOARD_NAME => has_keyboard = true,
|
KEYBOARD_NAME => has_keyboard = true,
|
||||||
_ => {
|
_ => {
|
||||||
if o.state.interactable {
|
if o.state.interactable {
|
||||||
num_overlays += 1
|
num_overlays += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -159,12 +159,12 @@ impl OscSender {
|
|||||||
self.send_message(
|
self.send_message(
|
||||||
String::from("/avatar/parameters/averageControllerBattery"),
|
String::from("/avatar/parameters/averageControllerBattery"),
|
||||||
vec![OscType::Float(
|
vec![OscType::Float(
|
||||||
controller_total_bat / controller_count as f32,
|
controller_total_bat / f32::from(controller_count),
|
||||||
)],
|
)],
|
||||||
)?;
|
)?;
|
||||||
self.send_message(
|
self.send_message(
|
||||||
String::from("/avatar/parameters/averageTrackerBattery"),
|
String::from("/avatar/parameters/averageTrackerBattery"),
|
||||||
vec![OscType::Float(tracker_total_bat / tracker_count as f32)],
|
vec![OscType::Float(tracker_total_bat / f32::from(tracker_count))],
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,14 +56,13 @@ pub struct OverlayState {
|
|||||||
pub saved_transform: Option<Affine3A>,
|
pub saved_transform: Option<Affine3A>,
|
||||||
pub relative_to: RelativeTo,
|
pub relative_to: RelativeTo,
|
||||||
pub curvature: Option<f32>,
|
pub curvature: Option<f32>,
|
||||||
pub primary_pointer: Option<usize>,
|
|
||||||
pub interaction_transform: Affine2,
|
pub interaction_transform: Affine2,
|
||||||
pub birthframe: usize,
|
pub birthframe: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for OverlayState {
|
impl Default for OverlayState {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
OverlayState {
|
Self {
|
||||||
id: OverlayID(OVERLAY_AUTO_INCREMENT.fetch_add(1, Ordering::Relaxed)),
|
id: OverlayID(OVERLAY_AUTO_INCREMENT.fetch_add(1, Ordering::Relaxed)),
|
||||||
name: Arc::from(""),
|
name: Arc::from(""),
|
||||||
want_visible: false,
|
want_visible: false,
|
||||||
@@ -83,7 +82,6 @@ impl Default for OverlayState {
|
|||||||
spawn_rotation: Quat::IDENTITY,
|
spawn_rotation: Quat::IDENTITY,
|
||||||
saved_transform: None,
|
saved_transform: None,
|
||||||
transform: Affine3A::IDENTITY,
|
transform: Affine3A::IDENTITY,
|
||||||
primary_pointer: None,
|
|
||||||
interaction_transform: Affine2::IDENTITY,
|
interaction_transform: Affine2::IDENTITY,
|
||||||
birthframe: 0,
|
birthframe: 0,
|
||||||
}
|
}
|
||||||
@@ -105,8 +103,8 @@ where
|
|||||||
T: Default,
|
T: Default,
|
||||||
{
|
{
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
OverlayData {
|
Self {
|
||||||
state: Default::default(),
|
state: OverlayState::default(),
|
||||||
backend: Box::<SplitOverlayBackend>::default(),
|
backend: Box::<SplitOverlayBackend>::default(),
|
||||||
primary_pointer: None,
|
primary_pointer: None,
|
||||||
data: Default::default(),
|
data: Default::default(),
|
||||||
@@ -115,7 +113,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl OverlayState {
|
impl OverlayState {
|
||||||
pub fn parent_transform(&self, app: &AppState) -> Option<Affine3A> {
|
pub const fn parent_transform(&self, app: &AppState) -> Option<Affine3A> {
|
||||||
match self.relative_to {
|
match self.relative_to {
|
||||||
RelativeTo::Head => Some(app.input_state.hmd),
|
RelativeTo::Head => Some(app.input_state.hmd),
|
||||||
RelativeTo::Hand(idx) => Some(app.input_state.pointers[idx].pose),
|
RelativeTo::Hand(idx) => Some(app.input_state.pointers[idx].pose),
|
||||||
@@ -123,7 +121,7 @@ impl OverlayState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_anchor(&self, app: &AppState) -> Affine3A {
|
const fn get_anchor(&self, app: &AppState) -> Affine3A {
|
||||||
if self.anchored {
|
if self.anchored {
|
||||||
app.anchor
|
app.anchor
|
||||||
} else {
|
} else {
|
||||||
@@ -211,12 +209,14 @@ where
|
|||||||
T: Default,
|
T: Default,
|
||||||
{
|
{
|
||||||
pub fn init(&mut self, app: &mut AppState) -> anyhow::Result<()> {
|
pub fn init(&mut self, app: &mut AppState) -> anyhow::Result<()> {
|
||||||
|
if self.state.curvature.is_none() {
|
||||||
self.state.curvature = app
|
self.state.curvature = app
|
||||||
.session
|
.session
|
||||||
.config
|
.config
|
||||||
.curve_values
|
.curve_values
|
||||||
.arc_get(self.state.name.as_ref())
|
.arc_get(self.state.name.as_ref())
|
||||||
.copied();
|
.copied();
|
||||||
|
}
|
||||||
|
|
||||||
if matches!(self.state.relative_to, RelativeTo::None) {
|
if matches!(self.state.relative_to, RelativeTo::None) {
|
||||||
let hard_reset;
|
let hard_reset;
|
||||||
@@ -250,18 +250,6 @@ where
|
|||||||
pub fn frame_meta(&mut self) -> Option<FrameMeta> {
|
pub fn frame_meta(&mut self) -> Option<FrameMeta> {
|
||||||
self.backend.frame_meta()
|
self.backend.frame_meta()
|
||||||
}
|
}
|
||||||
pub fn set_visible(&mut self, app: &mut AppState, visible: bool) -> anyhow::Result<()> {
|
|
||||||
let old_visible = self.state.want_visible;
|
|
||||||
self.state.want_visible = visible;
|
|
||||||
if visible != old_visible {
|
|
||||||
if visible {
|
|
||||||
self.backend.resume(app)?;
|
|
||||||
} else {
|
|
||||||
self.backend.pause(app)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Clone, Copy)]
|
#[derive(Default, Clone, Copy)]
|
||||||
@@ -351,8 +339,8 @@ pub struct SplitOverlayBackend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Default for SplitOverlayBackend {
|
impl Default for SplitOverlayBackend {
|
||||||
fn default() -> SplitOverlayBackend {
|
fn default() -> Self {
|
||||||
SplitOverlayBackend {
|
Self {
|
||||||
renderer: Box::new(FallbackRenderer),
|
renderer: Box::new(FallbackRenderer),
|
||||||
interaction: Box::new(DummyInteractionHandler),
|
interaction: Box::new(DummyInteractionHandler),
|
||||||
}
|
}
|
||||||
@@ -409,7 +397,7 @@ impl InteractionHandler for SplitOverlayBackend {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ui_transform(extent: &[u32; 2]) -> Affine2 {
|
pub fn ui_transform(extent: [u32; 2]) -> Affine2 {
|
||||||
let aspect = extent[0] as f32 / extent[1] as f32;
|
let aspect = extent[0] as f32 / extent[1] as f32;
|
||||||
let scale = if aspect < 1.0 {
|
let scale = if aspect < 1.0 {
|
||||||
Vec2 {
|
Vec2 {
|
||||||
|
|||||||
@@ -25,12 +25,12 @@ struct AppTask {
|
|||||||
pub task: TaskType,
|
pub task: TaskType,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq<AppTask> for AppTask {
|
impl PartialEq<Self> for AppTask {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.cmp(other) == cmp::Ordering::Equal
|
self.cmp(other) == cmp::Ordering::Equal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl PartialOrd<AppTask> for AppTask {
|
impl PartialOrd<Self> for AppTask {
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
|
||||||
Some(self.cmp(other))
|
Some(self.cmp(other))
|
||||||
}
|
}
|
||||||
@@ -57,7 +57,6 @@ pub type CreateOverlayTask =
|
|||||||
dyn FnOnce(&mut AppState) -> Option<(OverlayState, Box<dyn OverlayBackend>)> + Send;
|
dyn FnOnce(&mut AppState) -> Option<(OverlayState, Box<dyn OverlayBackend>)> + Send;
|
||||||
|
|
||||||
pub enum TaskType {
|
pub enum TaskType {
|
||||||
Global(Box<dyn FnOnce(&mut AppState) + Send>),
|
|
||||||
Overlay(OverlaySelector, Box<OverlayTask>),
|
Overlay(OverlaySelector, Box<OverlayTask>),
|
||||||
CreateOverlay(OverlaySelector, Box<CreateOverlayTask>),
|
CreateOverlay(OverlaySelector, Box<CreateOverlayTask>),
|
||||||
DropOverlay(OverlaySelector),
|
DropOverlay(OverlaySelector),
|
||||||
@@ -79,7 +78,7 @@ pub struct TaskContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TaskContainer {
|
impl TaskContainer {
|
||||||
pub fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
tasks: BinaryHeap::new(),
|
tasks: BinaryHeap::new(),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ use std::sync::Arc;
|
|||||||
use vulkano::{
|
use vulkano::{
|
||||||
image::{view::ImageView, ImageUsage},
|
image::{view::ImageView, ImageUsage},
|
||||||
swapchain::{
|
swapchain::{
|
||||||
acquire_next_image, Surface, Swapchain, SwapchainCreateInfo, SwapchainPresentInfo,
|
acquire_next_image, Surface, SurfaceInfo, Swapchain, SwapchainCreateInfo,
|
||||||
|
SwapchainPresentInfo,
|
||||||
},
|
},
|
||||||
sync::GpuFuture,
|
sync::GpuFuture,
|
||||||
Validated, VulkanError,
|
Validated, VulkanError,
|
||||||
@@ -67,13 +68,12 @@ impl PreviewState {
|
|||||||
|
|
||||||
let inner_size = window.inner_size();
|
let inner_size = window.inner_size();
|
||||||
let swapchain_size = [inner_size.width, inner_size.height];
|
let swapchain_size = [inner_size.width, inner_size.height];
|
||||||
let (swapchain, images) =
|
let (swapchain, images) = create_swapchain(&state.graphics, surface, swapchain_size)?;
|
||||||
create_swapchain(&state.graphics, surface.clone(), swapchain_size)?;
|
|
||||||
|
|
||||||
let mut canvas = modular_canvas(&config.size, &config.elements, state)?;
|
let mut canvas = modular_canvas(config.size, &config.elements, state)?;
|
||||||
canvas.init(state)?;
|
canvas.init(state)?;
|
||||||
|
|
||||||
Ok(PreviewState {
|
Ok(Self {
|
||||||
canvas,
|
canvas,
|
||||||
swapchain,
|
swapchain,
|
||||||
images,
|
images,
|
||||||
@@ -99,7 +99,7 @@ pub fn uidev_run(panel_name: &str) -> anyhow::Result<()> {
|
|||||||
panel_name,
|
panel_name,
|
||||||
)?);
|
)?);
|
||||||
|
|
||||||
let watch_path = config_io::get_config_root().join(format!("{}.yaml", panel_name));
|
let watch_path = config_io::get_config_root().join(format!("{panel_name}.yaml"));
|
||||||
let mut path_last_modified = watch_path.metadata()?.modified()?;
|
let mut path_last_modified = watch_path.metadata()?.modified()?;
|
||||||
let mut recreate = false;
|
let mut recreate = false;
|
||||||
let mut last_draw = std::time::Instant::now();
|
let mut last_draw = std::time::Instant::now();
|
||||||
@@ -164,7 +164,7 @@ pub fn uidev_run(panel_name: &str) -> anyhow::Result<()> {
|
|||||||
{
|
{
|
||||||
log::error!("failed to render canvas: {e}");
|
log::error!("failed to render canvas: {e}");
|
||||||
window.request_redraw();
|
window.request_redraw();
|
||||||
};
|
}
|
||||||
|
|
||||||
last_draw = std::time::Instant::now();
|
last_draw = std::time::Instant::now();
|
||||||
|
|
||||||
@@ -204,12 +204,12 @@ fn create_swapchain(
|
|||||||
let surface_capabilities = graphics
|
let surface_capabilities = graphics
|
||||||
.device
|
.device
|
||||||
.physical_device()
|
.physical_device()
|
||||||
.surface_capabilities(&surface, Default::default())
|
.surface_capabilities(&surface, SurfaceInfo::default())
|
||||||
.unwrap(); // want panic
|
.unwrap(); // want panic
|
||||||
|
|
||||||
let (swapchain, images) = Swapchain::new(
|
let (swapchain, images) = Swapchain::new(
|
||||||
graphics.device.clone(),
|
graphics.device.clone(),
|
||||||
surface.clone(),
|
surface,
|
||||||
SwapchainCreateInfo {
|
SwapchainCreateInfo {
|
||||||
min_image_count: surface_capabilities.min_image_count.max(2),
|
min_image_count: surface_capabilities.min_image_count.max(2),
|
||||||
image_format: graphics.native_format,
|
image_format: graphics.native_format,
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ pub struct WayVRCompositor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_wayvr_env_from_pid(pid: i32) -> anyhow::Result<ProcessWayVREnv> {
|
fn get_wayvr_env_from_pid(pid: i32) -> anyhow::Result<ProcessWayVREnv> {
|
||||||
let path = format!("/proc/{}/environ", pid);
|
let path = format!("/proc/{pid}/environ");
|
||||||
let mut env_data = String::new();
|
let mut env_data = String::new();
|
||||||
std::fs::File::open(path)?.read_to_string(&mut env_data)?;
|
std::fs::File::open(path)?.read_to_string(&mut env_data)?;
|
||||||
|
|
||||||
@@ -162,7 +162,7 @@ impl WayVRCompositor {
|
|||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
if let Some(stream) = self.listener.accept()? {
|
if let Some(stream) = self.listener.accept()? {
|
||||||
if let Err(e) = self.accept_connection(stream, displays, processes) {
|
if let Err(e) = self.accept_connection(stream, displays, processes) {
|
||||||
log::error!("Failed to accept connection: {}", e);
|
log::error!("Failed to accept connection: {e}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,7 +175,7 @@ impl WayVRCompositor {
|
|||||||
processes: &mut process::ProcessVec,
|
processes: &mut process::ProcessVec,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
if let Err(e) = self.accept_connections(displays, processes) {
|
if let Err(e) = self.accept_connections(displays, processes) {
|
||||||
log::error!("accept_connections failed: {}", e);
|
log::error!("accept_connections failed: {e}");
|
||||||
}
|
}
|
||||||
|
|
||||||
self.display.dispatch_clients(&mut self.state)?;
|
self.display.dispatch_clients(&mut self.state)?;
|
||||||
@@ -184,7 +184,7 @@ impl WayVRCompositor {
|
|||||||
let surf_count = self.state.xdg_shell.toplevel_surfaces().len() as u32;
|
let surf_count = self.state.xdg_shell.toplevel_surfaces().len() as u32;
|
||||||
if surf_count != self.toplevel_surf_count {
|
if surf_count != self.toplevel_surf_count {
|
||||||
self.toplevel_surf_count = surf_count;
|
self.toplevel_surf_count = surf_count;
|
||||||
log::info!("Toplevel surface count changed: {}", surf_count);
|
log::info!("Toplevel surface count changed: {surf_count}");
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -211,11 +211,9 @@ impl WayVRCompositor {
|
|||||||
const STARTING_WAYLAND_ADDR_IDX: u32 = 20;
|
const STARTING_WAYLAND_ADDR_IDX: u32 = 20;
|
||||||
|
|
||||||
fn export_display_number(display_num: u32) -> anyhow::Result<()> {
|
fn export_display_number(display_num: u32) -> anyhow::Result<()> {
|
||||||
let mut path = std::env::var("XDG_RUNTIME_DIR")
|
let mut path = std::env::var("XDG_RUNTIME_DIR").map_or_else(|_| PathBuf::from("/tmp"), PathBuf::from);
|
||||||
.map(PathBuf::from)
|
|
||||||
.unwrap_or_else(|_| PathBuf::from("/tmp"));
|
|
||||||
path.push("wayvr.disp");
|
path.push("wayvr.disp");
|
||||||
std::fs::write(path, format!("{}\n", display_num))?;
|
std::fs::write(path, format!("{display_num}\n"))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,17 +225,15 @@ fn create_wayland_listener() -> anyhow::Result<(super::WaylandEnv, wayland_serve
|
|||||||
|
|
||||||
let listener = loop {
|
let listener = loop {
|
||||||
let display_str = env.display_num_string();
|
let display_str = env.display_num_string();
|
||||||
log::debug!("Trying to open socket \"{}\"", display_str);
|
log::debug!("Trying to open socket \"{display_str}\"");
|
||||||
match wayland_server::ListeningSocket::bind(display_str.as_str()) {
|
match wayland_server::ListeningSocket::bind(display_str.as_str()) {
|
||||||
Ok(listener) => {
|
Ok(listener) => {
|
||||||
log::debug!("Listening to {}", display_str);
|
log::debug!("Listening to {display_str}");
|
||||||
break listener;
|
break listener;
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::debug!(
|
log::debug!(
|
||||||
"Failed to open socket \"{}\" (reason: {}), trying next...",
|
"Failed to open socket \"{display_str}\" (reason: {e}), trying next..."
|
||||||
display_str,
|
|
||||||
e
|
|
||||||
);
|
);
|
||||||
|
|
||||||
env.display_num += 1;
|
env.display_num += 1;
|
||||||
|
|||||||
@@ -122,15 +122,13 @@ pub struct ClientState {
|
|||||||
|
|
||||||
impl ClientData for ClientState {
|
impl ClientData for ClientState {
|
||||||
fn initialized(&self, client_id: ClientId) {
|
fn initialized(&self, client_id: ClientId) {
|
||||||
log::debug!("Client ID {:?} connected", client_id);
|
log::debug!("Client ID {client_id:?} connected");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn disconnected(&self, client_id: ClientId, reason: DisconnectReason) {
|
fn disconnected(&self, client_id: ClientId, reason: DisconnectReason) {
|
||||||
*self.disconnected.lock().unwrap() = true;
|
*self.disconnected.lock().unwrap() = true;
|
||||||
log::debug!(
|
log::debug!(
|
||||||
"Client ID {:?} disconnected. Reason: {:?}",
|
"Client ID {client_id:?} disconnected. Reason: {reason:?}"
|
||||||
client_id,
|
|
||||||
reason
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -202,7 +200,7 @@ impl DmabufHandler for Application {
|
|||||||
notifier: ImportNotifier,
|
notifier: ImportNotifier,
|
||||||
) {
|
) {
|
||||||
if self.gles_renderer.import_dmabuf(&dmabuf, None).is_ok() {
|
if self.gles_renderer.import_dmabuf(&dmabuf, None).is_ok() {
|
||||||
let _ = notifier.successful::<Application>();
|
let _ = notifier.successful::<Self>();
|
||||||
} else {
|
} else {
|
||||||
notifier.failed();
|
notifier.failed();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,8 +122,8 @@ impl Display {
|
|||||||
let tex_id = params.renderer.with_context(|gl| {
|
let tex_id = params.renderer.with_context(|gl| {
|
||||||
smithay_wrapper::create_framebuffer_texture(
|
smithay_wrapper::create_framebuffer_texture(
|
||||||
gl,
|
gl,
|
||||||
params.width as u32,
|
u32::from(params.width),
|
||||||
params.height as u32,
|
u32::from(params.height),
|
||||||
tex_format,
|
tex_format,
|
||||||
internal_format,
|
internal_format,
|
||||||
)
|
)
|
||||||
@@ -139,7 +139,7 @@ impl Display {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let opaque = false;
|
let opaque = false;
|
||||||
let size = (params.width as i32, params.height as i32).into();
|
let size = (i32::from(params.width), i32::from(params.height)).into();
|
||||||
let gles_texture = unsafe {
|
let gles_texture = unsafe {
|
||||||
GlesTexture::from_raw(params.renderer, Some(tex_format), opaque, tex_id, size)
|
GlesTexture::from_raw(params.renderer, Some(tex_format), opaque, tex_id, size)
|
||||||
};
|
};
|
||||||
@@ -202,7 +202,7 @@ impl Display {
|
|||||||
match &self.layout {
|
match &self.layout {
|
||||||
packet_server::WvrDisplayWindowLayout::Tiling => {
|
packet_server::WvrDisplayWindowLayout::Tiling => {
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
for win in self.displayed_windows.iter_mut() {
|
for win in &mut self.displayed_windows {
|
||||||
if let Some(window) = self.wm.borrow_mut().windows.get_mut(&win.window_handle) {
|
if let Some(window) = self.wm.borrow_mut().windows.get_mut(&win.window_handle) {
|
||||||
if !window.visible {
|
if !window.visible {
|
||||||
continue;
|
continue;
|
||||||
@@ -210,21 +210,21 @@ impl Display {
|
|||||||
let d_cur = i as f32 / window_count as f32;
|
let d_cur = i as f32 / window_count as f32;
|
||||||
let d_next = (i + 1) as f32 / window_count as f32;
|
let d_next = (i + 1) as f32 / window_count as f32;
|
||||||
|
|
||||||
let left = (d_cur * self.width as f32) as i32;
|
let left = (d_cur * f32::from(self.width)) as i32;
|
||||||
let right = (d_next * self.width as f32) as i32;
|
let right = (d_next * f32::from(self.width)) as i32;
|
||||||
|
|
||||||
window.set_pos(left, 0);
|
window.set_pos(left, 0);
|
||||||
window.set_size((right - left) as u32, self.height as u32);
|
window.set_size((right - left) as u32, u32::from(self.height));
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
packet_server::WvrDisplayWindowLayout::Stacking(opts) => {
|
packet_server::WvrDisplayWindowLayout::Stacking(opts) => {
|
||||||
let do_margins = |margins: &packet_server::Margins, window: &mut window::Window| {
|
let do_margins = |margins: &packet_server::Margins, window: &mut window::Window| {
|
||||||
let top = margins.top as i32;
|
let top = i32::from(margins.top);
|
||||||
let bottom = self.height as i32 - margins.bottom as i32;
|
let bottom = i32::from(self.height) - i32::from(margins.bottom);
|
||||||
let left = margins.left as i32;
|
let left = i32::from(margins.left);
|
||||||
let right = self.width as i32 - margins.right as i32;
|
let right = i32::from(self.width) - i32::from(margins.right);
|
||||||
let width = right - left;
|
let width = right - left;
|
||||||
let height = bottom - top;
|
let height = bottom - top;
|
||||||
if width < 0 || height < 0 {
|
if width < 0 || height < 0 {
|
||||||
@@ -236,7 +236,7 @@ impl Display {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
for win in self.displayed_windows.iter_mut() {
|
for win in &mut self.displayed_windows {
|
||||||
if let Some(window) = self.wm.borrow_mut().windows.get_mut(&win.window_handle) {
|
if let Some(window) = self.wm.borrow_mut().windows.get_mut(&win.window_handle) {
|
||||||
if !window.visible {
|
if !window.visible {
|
||||||
continue;
|
continue;
|
||||||
@@ -267,7 +267,7 @@ impl Display {
|
|||||||
self.no_windows_since = None;
|
self.no_windows_since = None;
|
||||||
} else if let Some(auto_hide_delay) = config.auto_hide_delay {
|
} else if let Some(auto_hide_delay) = config.auto_hide_delay {
|
||||||
if let Some(s) = self.no_windows_since {
|
if let Some(s) = self.no_windows_since {
|
||||||
if s + (auto_hide_delay as u64) < get_millis() {
|
if s + u64::from(auto_hide_delay) < get_millis() {
|
||||||
// Auto-hide after specific time
|
// Auto-hide after specific time
|
||||||
signals.send(WayVRSignal::DisplayVisibility(*handle, false));
|
signals.send(WayVRSignal::DisplayVisibility(*handle, false));
|
||||||
}
|
}
|
||||||
@@ -303,7 +303,7 @@ impl Display {
|
|||||||
pub fn tick_render(&mut self, renderer: &mut GlesRenderer, time_ms: u64) -> anyhow::Result<()> {
|
pub fn tick_render(&mut self, renderer: &mut GlesRenderer, time_ms: u64) -> anyhow::Result<()> {
|
||||||
renderer.bind(self.gles_texture.clone())?;
|
renderer.bind(self.gles_texture.clone())?;
|
||||||
|
|
||||||
let size = Size::from((self.width as i32, self.height as i32));
|
let size = Size::from((i32::from(self.width), i32::from(self.height)));
|
||||||
let damage: Rectangle<i32, smithay::utils::Physical> = Rectangle::from_size(size);
|
let damage: Rectangle<i32, smithay::utils::Physical> = Rectangle::from_size(size);
|
||||||
|
|
||||||
let elements: Vec<WaylandSurfaceRenderElement<GlesRenderer>> = self
|
let elements: Vec<WaylandSurfaceRenderElement<GlesRenderer>> = self
|
||||||
@@ -358,8 +358,8 @@ impl Display {
|
|||||||
gl.ReadPixels(
|
gl.ReadPixels(
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
self.width as i32,
|
i32::from(self.width),
|
||||||
self.height as i32,
|
i32::from(self.height),
|
||||||
ffi::RGBA,
|
ffi::RGBA,
|
||||||
ffi::UNSIGNED_BYTE,
|
ffi::UNSIGNED_BYTE,
|
||||||
data.as_mut_ptr().cast(),
|
data.as_mut_ptr().cast(),
|
||||||
@@ -401,7 +401,7 @@ impl Display {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn trigger_rerender(&mut self) {
|
pub const fn trigger_rerender(&mut self) {
|
||||||
self.wants_redraw = true;
|
self.wants_redraw = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -435,7 +435,7 @@ impl Display {
|
|||||||
y: u32,
|
y: u32,
|
||||||
) {
|
) {
|
||||||
let current_ms = time::get_millis();
|
let current_ms = time::get_millis();
|
||||||
if self.last_pressed_time_ms + config.click_freeze_time_ms as u64 > current_ms {
|
if self.last_pressed_time_ms + u64::from(config.click_freeze_time_ms) > current_ms {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -444,8 +444,8 @@ impl Display {
|
|||||||
if let Some(window) = wm.windows.get(&window_handle) {
|
if let Some(window) = wm.windows.get(&window_handle) {
|
||||||
let surf = window.toplevel.wl_surface().clone();
|
let surf = window.toplevel.wl_surface().clone();
|
||||||
let point = Point::<f64, Logical>::from((
|
let point = Point::<f64, Logical>::from((
|
||||||
(x as i32 - window.pos_x) as f64,
|
f64::from(x as i32 - window.pos_x),
|
||||||
(y as i32 - window.pos_y) as f64,
|
f64::from(y as i32 - window.pos_y),
|
||||||
));
|
));
|
||||||
|
|
||||||
manager.seat_pointer.motion(
|
manager.seat_pointer.motion(
|
||||||
@@ -463,7 +463,7 @@ impl Display {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_mouse_index_number(index: super::MouseIndex) -> u32 {
|
const fn get_mouse_index_number(index: super::MouseIndex) -> u32 {
|
||||||
match index {
|
match index {
|
||||||
super::MouseIndex::Left => 0x110, /* BTN_LEFT */
|
super::MouseIndex::Left => 0x110, /* BTN_LEFT */
|
||||||
super::MouseIndex::Center => 0x112, /* BTN_MIDDLE */
|
super::MouseIndex::Center => 0x112, /* BTN_MIDDLE */
|
||||||
@@ -505,7 +505,7 @@ impl Display {
|
|||||||
manager.seat_pointer.frame(&mut manager.state);
|
manager.seat_pointer.frame(&mut manager.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_mouse_up(&self, manager: &mut WayVRCompositor, index: super::MouseIndex) {
|
pub fn send_mouse_up(manager: &mut WayVRCompositor, index: super::MouseIndex) {
|
||||||
manager.seat_pointer.button(
|
manager.seat_pointer.button(
|
||||||
&mut manager.state,
|
&mut manager.state,
|
||||||
&input::pointer::ButtonEvent {
|
&input::pointer::ButtonEvent {
|
||||||
@@ -519,7 +519,7 @@ impl Display {
|
|||||||
manager.seat_pointer.frame(&mut manager.state);
|
manager.seat_pointer.frame(&mut manager.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_mouse_scroll(&self, manager: &mut WayVRCompositor, delta_y: f32, delta_x: f32) {
|
pub fn send_mouse_scroll(manager: &mut WayVRCompositor, delta_y: f32, delta_x: f32) {
|
||||||
manager.seat_pointer.axis(
|
manager.seat_pointer.axis(
|
||||||
&mut manager.state,
|
&mut manager.state,
|
||||||
input::pointer::AxisFrame {
|
input::pointer::AxisFrame {
|
||||||
@@ -529,7 +529,7 @@ impl Display {
|
|||||||
smithay::backend::input::AxisRelativeDirection::Identical,
|
smithay::backend::input::AxisRelativeDirection::Identical,
|
||||||
),
|
),
|
||||||
time: 0,
|
time: 0,
|
||||||
axis: (delta_x as f64, -delta_y as f64),
|
axis: (f64::from(delta_x), f64::from(-delta_y)),
|
||||||
v120: Some((0, (delta_y * -120.0) as i32)),
|
v120: Some((0, (delta_y * -120.0) as i32)),
|
||||||
stop: (false, false),
|
stop: (false, false),
|
||||||
},
|
},
|
||||||
@@ -549,7 +549,7 @@ impl Display {
|
|||||||
args: &[&str],
|
args: &[&str],
|
||||||
env: &[(&str, &str)],
|
env: &[(&str, &str)],
|
||||||
) -> anyhow::Result<SpawnProcessResult> {
|
) -> anyhow::Result<SpawnProcessResult> {
|
||||||
log::info!("Spawning subprocess with exec path \"{}\"", exec_path);
|
log::info!("Spawning subprocess with exec path \"{exec_path}\"");
|
||||||
|
|
||||||
let auth_key = generate_auth_key();
|
let auth_key = generate_auth_key();
|
||||||
|
|
||||||
@@ -577,14 +577,14 @@ impl Display {
|
|||||||
gen_id!(DisplayVec, Display, DisplayCell, DisplayHandle);
|
gen_id!(DisplayVec, Display, DisplayCell, DisplayHandle);
|
||||||
|
|
||||||
impl DisplayHandle {
|
impl DisplayHandle {
|
||||||
pub fn from_packet(handle: packet_server::WvrDisplayHandle) -> Self {
|
pub const fn from_packet(handle: packet_server::WvrDisplayHandle) -> Self {
|
||||||
Self {
|
Self {
|
||||||
generation: handle.generation,
|
generation: handle.generation,
|
||||||
idx: handle.idx,
|
idx: handle.idx,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_packet(&self) -> packet_server::WvrDisplayHandle {
|
pub const fn as_packet(&self) -> packet_server::WvrDisplayHandle {
|
||||||
packet_server::WvrDisplayHandle {
|
packet_server::WvrDisplayHandle {
|
||||||
idx: self.idx,
|
idx: self.idx,
|
||||||
generation: self.generation,
|
generation: self.generation,
|
||||||
|
|||||||
@@ -47,25 +47,25 @@ pub enum RenderData {
|
|||||||
|
|
||||||
impl EGLData {
|
impl EGLData {
|
||||||
pub fn load_func(&self, func_name: &str) -> anyhow::Result<extern "system" fn()> {
|
pub fn load_func(&self, func_name: &str) -> anyhow::Result<extern "system" fn()> {
|
||||||
let raw_fn = self.egl.get_proc_address(func_name).ok_or(anyhow::anyhow!(
|
let raw_fn = self
|
||||||
"Required EGL function {} not found",
|
.egl
|
||||||
func_name
|
.get_proc_address(func_name)
|
||||||
))?;
|
.ok_or_else(|| anyhow::anyhow!("Required EGL function {} not found", func_name))?;
|
||||||
Ok(raw_fn)
|
Ok(raw_fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new() -> anyhow::Result<EGLData> {
|
pub fn new() -> anyhow::Result<Self> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let egl = khronos_egl::Instance::new(khronos_egl::Static);
|
let egl = khronos_egl::Instance::new(khronos_egl::Static);
|
||||||
|
|
||||||
let display = egl
|
let display = egl
|
||||||
.get_display(khronos_egl::DEFAULT_DISPLAY)
|
.get_display(khronos_egl::DEFAULT_DISPLAY)
|
||||||
.ok_or(anyhow!(
|
.ok_or_else(|| anyhow!(
|
||||||
"eglGetDisplay failed. This shouldn't happen unless you don't have any display manager running. Cannot continue, check your EGL installation."
|
"eglGetDisplay failed. This shouldn't happen unless you don't have any display manager running. Cannot continue, check your EGL installation."
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
let (major, minor) = egl.initialize(display)?;
|
let (major, minor) = egl.initialize(display)?;
|
||||||
log::debug!("EGL version: {}.{}", major, minor);
|
log::debug!("EGL version: {major}.{minor}");
|
||||||
|
|
||||||
let attrib_list = [
|
let attrib_list = [
|
||||||
khronos_egl::RED_SIZE,
|
khronos_egl::RED_SIZE,
|
||||||
@@ -83,7 +83,7 @@ impl EGLData {
|
|||||||
|
|
||||||
let config = egl
|
let config = egl
|
||||||
.choose_first_config(display, &attrib_list)?
|
.choose_first_config(display, &attrib_list)?
|
||||||
.ok_or(anyhow!("Failed to get EGL config"))?;
|
.ok_or_else(|| anyhow!("Failed to get EGL config"))?;
|
||||||
|
|
||||||
egl.bind_api(khronos_egl::OPENGL_ES_API)?;
|
egl.bind_api(khronos_egl::OPENGL_ES_API)?;
|
||||||
|
|
||||||
@@ -104,7 +104,7 @@ impl EGLData {
|
|||||||
|
|
||||||
egl.make_current(display, None, None, Some(context))?;
|
egl.make_current(display, None, None, Some(context))?;
|
||||||
|
|
||||||
Ok(EGLData {
|
Ok(Self {
|
||||||
egl,
|
egl,
|
||||||
display,
|
display,
|
||||||
config,
|
config,
|
||||||
@@ -114,7 +114,7 @@ impl EGLData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn query_dmabuf_mod_info(&self) -> anyhow::Result<DMAbufModifierInfo> {
|
fn query_dmabuf_mod_info(&self) -> anyhow::Result<DMAbufModifierInfo> {
|
||||||
let target_fourcc = 0x34324258; //XB24
|
let target_fourcc = 0x3432_4258; //XB24
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
use egl_ex::PFNEGLQUERYDMABUFFORMATSEXTPROC;
|
use egl_ex::PFNEGLQUERYDMABUFFORMATSEXTPROC;
|
||||||
@@ -187,13 +187,13 @@ impl EGLData {
|
|||||||
&mut num_mods,
|
&mut num_mods,
|
||||||
);
|
);
|
||||||
|
|
||||||
if mods[0] == 0xFFFFFFFFFFFFFFFF {
|
if mods[0] == 0xFFFF_FFFF_FFFF_FFFF {
|
||||||
anyhow::bail!("modifier is -1")
|
anyhow::bail!("modifier is -1")
|
||||||
}
|
}
|
||||||
|
|
||||||
log::trace!("Modifier list:");
|
log::trace!("Modifier list:");
|
||||||
for modifier in &mods {
|
for modifier in &mods {
|
||||||
log::trace!("{:#x}", modifier);
|
log::trace!("{modifier:#x}");
|
||||||
}
|
}
|
||||||
|
|
||||||
// We should not change these modifier values. Passing all of them to the Vulkan dmabuf
|
// We should not change these modifier values. Passing all of them to the Vulkan dmabuf
|
||||||
@@ -203,13 +203,13 @@ impl EGLData {
|
|||||||
// If not, the full list of modifiers will be passed. Further testing is required.
|
// If not, the full list of modifiers will be passed. Further testing is required.
|
||||||
// For now, it looks like only NAVI32-based gpus have this problem.
|
// For now, it looks like only NAVI32-based gpus have this problem.
|
||||||
let mod_whitelist: [u64; 2] = [
|
let mod_whitelist: [u64; 2] = [
|
||||||
0x20000002086bf04, /* AMD RX 7800 XT, Navi32 */
|
0x200_0000_2086_bf04, /* AMD RX 7800 XT, Navi32 */
|
||||||
0x20000001866bf04, /* AMD RX 7600 XT, Navi33 */
|
0x200_0000_1866_bf04, /* AMD RX 7600 XT, Navi33 */
|
||||||
];
|
];
|
||||||
|
|
||||||
for modifier in &mod_whitelist {
|
for modifier in &mod_whitelist {
|
||||||
if mods.contains(modifier) {
|
if mods.contains(modifier) {
|
||||||
log::warn!("Using whitelisted dmabuf tiling modifier: {:#x}", modifier);
|
log::warn!("Using whitelisted dmabuf tiling modifier: {modifier:#x}");
|
||||||
mods = vec![*modifier, 0x0 /* also important (???) */];
|
mods = vec![*modifier, 0x0 /* also important (???) */];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ impl<DataType> SyncEventQueue<DataType> {
|
|||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
data: Rc::new(RefCell::new(Data {
|
data: Rc::new(RefCell::new(Data {
|
||||||
queue: Default::default(),
|
queue: VecDeque::default(),
|
||||||
})),
|
})),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,27 +30,27 @@ macro_rules! gen_id {
|
|||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
impl $handle_name {
|
impl $handle_name {
|
||||||
pub fn reset(&mut self) {
|
pub const fn reset(&mut self) {
|
||||||
self.generation = 0;
|
self.generation = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_set(&self) -> bool {
|
pub const fn is_set(&self) -> bool {
|
||||||
self.generation > 0
|
self.generation > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn id(&self) -> u32 {
|
pub const fn id(&self) -> u32 {
|
||||||
self.idx
|
self.idx
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(idx: u32, generation: u64) -> Self {
|
pub const fn new(idx: u32, generation: u64) -> Self {
|
||||||
Self { idx, generation }
|
Self { idx, generation }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//ThingVec
|
//ThingVec
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code, clippy::iter_not_returning_iterator)]
|
||||||
impl $container_name {
|
impl $container_name {
|
||||||
pub fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
vec: Vec::new(),
|
vec: Vec::new(),
|
||||||
cur_generation: 0,
|
cur_generation: 0,
|
||||||
@@ -78,7 +78,7 @@ macro_rules! gen_id {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_handle(cell: &$cell_name, idx: usize) -> $handle_name {
|
pub const 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,
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ mod smithay_wrapper;
|
|||||||
mod time;
|
mod time;
|
||||||
mod window;
|
mod window;
|
||||||
use comp::Application;
|
use comp::Application;
|
||||||
use display::{DisplayInitParams, DisplayVec};
|
use display::{Display, DisplayInitParams, DisplayVec};
|
||||||
use event_queue::SyncEventQueue;
|
use event_queue::SyncEventQueue;
|
||||||
use process::ProcessVec;
|
use process::ProcessVec;
|
||||||
use server_ipc::WayVRServer;
|
use server_ipc::WayVRServer;
|
||||||
@@ -21,7 +21,7 @@ use smithay::{
|
|||||||
egl,
|
egl,
|
||||||
renderer::{gles::GlesRenderer, ImportDma},
|
renderer::{gles::GlesRenderer, ImportDma},
|
||||||
},
|
},
|
||||||
input::SeatState,
|
input::{keyboard::XkbConfig, SeatState},
|
||||||
output::{Mode, Output},
|
output::{Mode, Output},
|
||||||
reexports::wayland_server::{self, backend::ClientId},
|
reexports::wayland_server::{self, backend::ClientId},
|
||||||
wayland::{
|
wayland::{
|
||||||
@@ -43,7 +43,6 @@ use wayvr_ipc::{packet_client, packet_server};
|
|||||||
use crate::{hid::MODS_TO_KEYS, state::AppState};
|
use crate::{hid::MODS_TO_KEYS, state::AppState};
|
||||||
|
|
||||||
const STR_INVALID_HANDLE_DISP: &str = "Invalid display handle";
|
const STR_INVALID_HANDLE_DISP: &str = "Invalid display handle";
|
||||||
const STR_INVALID_HANDLE_PROCESS: &str = "Invalid process handle";
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct WaylandEnv {
|
pub struct WaylandEnv {
|
||||||
@@ -96,10 +95,10 @@ pub enum BlitMethod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl BlitMethod {
|
impl BlitMethod {
|
||||||
pub fn from_string(str: &str) -> Option<BlitMethod> {
|
pub fn from_string(str: &str) -> Option<Self> {
|
||||||
match str {
|
match str {
|
||||||
"dmabuf" => Some(BlitMethod::Dmabuf),
|
"dmabuf" => Some(Self::Dmabuf),
|
||||||
"software" => Some(BlitMethod::Software),
|
"software" => Some(Self::Software),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -150,6 +149,7 @@ pub enum TickTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl WayVR {
|
impl WayVR {
|
||||||
|
#[allow(clippy::too_many_lines, clippy::cognitive_complexity)]
|
||||||
pub fn new(config: Config) -> anyhow::Result<Self> {
|
pub fn new(config: Config) -> anyhow::Result<Self> {
|
||||||
log::info!("Initializing WayVR");
|
log::info!("Initializing WayVR");
|
||||||
let display: wayland_server::Display<Application> = wayland_server::Display::new()?;
|
let display: wayland_server::Display<Application> = wayland_server::Display::new()?;
|
||||||
@@ -208,28 +208,32 @@ impl WayVR {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::warn!("dmabuf: Failed to get egl device for display: {}", err);
|
log::warn!("dmabuf: Failed to get egl device for display: {err}");
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let dmabuf_state = if let Some(default_feedback) = dmabuf_default_feedback {
|
let dmabuf_state = dmabuf_default_feedback.map_or_else(
|
||||||
let mut dmabuf_state = DmabufState::new();
|
|| {
|
||||||
let dmabuf_global = dmabuf_state.create_global_with_default_feedback::<Application>(
|
|
||||||
&display.handle(),
|
|
||||||
&default_feedback,
|
|
||||||
);
|
|
||||||
(dmabuf_state, dmabuf_global, Some(default_feedback))
|
|
||||||
} else {
|
|
||||||
let dmabuf_formats = gles_renderer.dmabuf_formats();
|
let dmabuf_formats = gles_renderer.dmabuf_formats();
|
||||||
let mut dmabuf_state = DmabufState::new();
|
let mut dmabuf_state = DmabufState::new();
|
||||||
let dmabuf_global =
|
let dmabuf_global =
|
||||||
dmabuf_state.create_global::<Application>(&display.handle(), dmabuf_formats);
|
dmabuf_state.create_global::<Application>(&display.handle(), dmabuf_formats);
|
||||||
(dmabuf_state, dmabuf_global, None)
|
(dmabuf_state, dmabuf_global, None)
|
||||||
};
|
},
|
||||||
|
|default_feedback| {
|
||||||
|
let mut dmabuf_state = DmabufState::new();
|
||||||
|
let dmabuf_global = dmabuf_state
|
||||||
|
.create_global_with_default_feedback::<Application>(
|
||||||
|
&display.handle(),
|
||||||
|
&default_feedback,
|
||||||
|
);
|
||||||
|
(dmabuf_state, dmabuf_global, Some(default_feedback))
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
let seat_keyboard = seat.add_keyboard(
|
let seat_keyboard = seat.add_keyboard(
|
||||||
Default::default(),
|
XkbConfig::default(),
|
||||||
config.keyboard_repeat_delay_ms as i32,
|
config.keyboard_repeat_delay_ms as i32,
|
||||||
config.keyboard_repeat_rate as i32,
|
config.keyboard_repeat_rate as i32,
|
||||||
)?;
|
)?;
|
||||||
@@ -278,7 +282,7 @@ impl WayVR {
|
|||||||
.state
|
.state
|
||||||
.displays
|
.displays
|
||||||
.get_mut(&display)
|
.get_mut(&display)
|
||||||
.ok_or(anyhow::anyhow!(STR_INVALID_HANDLE_DISP))?;
|
.ok_or_else(|| anyhow::anyhow!(STR_INVALID_HANDLE_DISP))?;
|
||||||
|
|
||||||
if !display.wants_redraw {
|
if !display.wants_redraw {
|
||||||
// Nothing changed, do not render
|
// Nothing changed, do not render
|
||||||
@@ -298,6 +302,7 @@ impl WayVR {
|
|||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_lines, clippy::cognitive_complexity)]
|
||||||
pub fn tick_events(&mut self, app: &AppState) -> anyhow::Result<Vec<TickTask>> {
|
pub fn tick_events(&mut self, app: &AppState) -> anyhow::Result<Vec<TickTask>> {
|
||||||
let mut tasks: Vec<TickTask> = Vec::new();
|
let mut tasks: Vec<TickTask> = Vec::new();
|
||||||
|
|
||||||
@@ -305,7 +310,7 @@ impl WayVR {
|
|||||||
state: &mut self.state,
|
state: &mut self.state,
|
||||||
tasks: &mut tasks,
|
tasks: &mut tasks,
|
||||||
app,
|
app,
|
||||||
})?;
|
});
|
||||||
|
|
||||||
// Check for redraw events
|
// Check for redraw events
|
||||||
self.state.displays.iter_mut(&mut |_, disp| {
|
self.state.displays.iter_mut(&mut |_, disp| {
|
||||||
@@ -458,6 +463,7 @@ impl WayVR {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn get_primary_display(displays: &DisplayVec) -> Option<display::DisplayHandle> {
|
pub fn get_primary_display(displays: &DisplayVec) -> Option<display::DisplayHandle> {
|
||||||
for (idx, cell) in displays.vec.iter().enumerate() {
|
for (idx, cell) in displays.vec.iter().enumerate() {
|
||||||
if let Some(cell) = cell {
|
if let Some(cell) = cell {
|
||||||
@@ -503,21 +509,12 @@ impl WayVRState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_mouse_up(&mut self, display: display::DisplayHandle, index: MouseIndex) {
|
pub fn send_mouse_up(&mut self, index: MouseIndex) {
|
||||||
if let Some(display) = self.displays.get(&display) {
|
Display::send_mouse_up(&mut self.manager, index);
|
||||||
display.send_mouse_up(&mut self.manager, index);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_mouse_scroll(
|
pub fn send_mouse_scroll(&mut self, delta_y: f32, delta_x: f32) {
|
||||||
&mut self,
|
Display::send_mouse_scroll(&mut self.manager, delta_y, delta_x);
|
||||||
display: display::DisplayHandle,
|
|
||||||
delta_y: f32,
|
|
||||||
delta_x: f32,
|
|
||||||
) {
|
|
||||||
if let Some(display) = self.displays.get(&display) {
|
|
||||||
display.send_mouse_scroll(&mut self.manager, delta_y, delta_x);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_key(&mut self, virtual_key: u32, down: bool) {
|
pub fn send_key(&mut self, virtual_key: u32, down: bool) {
|
||||||
@@ -617,7 +614,7 @@ impl WayVRState {
|
|||||||
|
|
||||||
self.manager.cleanup_clients();
|
self.manager.cleanup_clients();
|
||||||
|
|
||||||
for client in self.manager.clients.iter() {
|
for client in &self.manager.clients {
|
||||||
if client.display_handle == handle {
|
if client.display_handle == handle {
|
||||||
// This shouldn't happen, but make sure we are all set to destroy this display
|
// This shouldn't happen, but make sure we are all set to destroy this display
|
||||||
anyhow::bail!("Wayland client still exists");
|
anyhow::bail!("Wayland client still exists");
|
||||||
@@ -684,8 +681,8 @@ impl WayVRState {
|
|||||||
) -> process::ProcessHandle {
|
) -> process::ProcessHandle {
|
||||||
self.processes
|
self.processes
|
||||||
.add(process::Process::External(process::ExternalProcess {
|
.add(process::Process::External(process::ExternalProcess {
|
||||||
display_handle,
|
|
||||||
pid,
|
pid,
|
||||||
|
display_handle,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -700,7 +697,7 @@ impl WayVRState {
|
|||||||
let display = self
|
let display = self
|
||||||
.displays
|
.displays
|
||||||
.get_mut(&display_handle)
|
.get_mut(&display_handle)
|
||||||
.ok_or(anyhow::anyhow!(STR_INVALID_HANDLE_DISP))?;
|
.ok_or_else(|| anyhow::anyhow!(STR_INVALID_HANDLE_DISP))?;
|
||||||
|
|
||||||
let res = display.spawn_process(exec_path, args, env)?;
|
let res = display.spawn_process(exec_path, args, env)?;
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use crate::gen_id;
|
|||||||
use super::display;
|
use super::display;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
#[allow(dead_code)]
|
||||||
pub struct WayVRProcess {
|
pub struct WayVRProcess {
|
||||||
pub auth_key: String,
|
pub auth_key: String,
|
||||||
pub child: std::process::Child,
|
pub child: std::process::Child,
|
||||||
@@ -32,45 +33,45 @@ pub enum Process {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Process {
|
impl Process {
|
||||||
pub fn display_handle(&self) -> display::DisplayHandle {
|
pub const fn display_handle(&self) -> display::DisplayHandle {
|
||||||
match self {
|
match self {
|
||||||
Process::Managed(p) => p.display_handle,
|
Self::Managed(p) => p.display_handle,
|
||||||
Process::External(p) => p.display_handle,
|
Self::External(p) => p.display_handle,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_running(&mut self) -> bool {
|
pub fn is_running(&mut self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Process::Managed(p) => p.is_running(),
|
Self::Managed(p) => p.is_running(),
|
||||||
Process::External(p) => p.is_running(),
|
Self::External(p) => p.is_running(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn terminate(&mut self) {
|
pub fn terminate(&mut self) {
|
||||||
match self {
|
match self {
|
||||||
Process::Managed(p) => p.terminate(),
|
Self::Managed(p) => p.terminate(),
|
||||||
Process::External(p) => p.terminate(),
|
Self::External(p) => p.terminate(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_name(&self) -> String {
|
pub fn get_name(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
Process::Managed(p) => p.get_name().unwrap_or(String::from("unknown")),
|
Self::Managed(p) => p.get_name().unwrap_or_else(|| String::from("unknown")),
|
||||||
Process::External(p) => p.get_name().unwrap_or(String::from("unknown")),
|
Self::External(p) => p.get_name().unwrap_or_else(|| String::from("unknown")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_packet(&self, handle: ProcessHandle) -> packet_server::WvrProcess {
|
pub fn to_packet(&self, handle: ProcessHandle) -> packet_server::WvrProcess {
|
||||||
match self {
|
match self {
|
||||||
Process::Managed(p) => packet_server::WvrProcess {
|
Self::Managed(p) => packet_server::WvrProcess {
|
||||||
name: p.get_name().unwrap_or(String::from("unknown")),
|
name: p.get_name().unwrap_or_else(|| String::from("unknown")),
|
||||||
userdata: p.userdata.clone(),
|
userdata: p.userdata.clone(),
|
||||||
display_handle: p.display_handle.as_packet(),
|
display_handle: p.display_handle.as_packet(),
|
||||||
handle: handle.as_packet(),
|
handle: handle.as_packet(),
|
||||||
},
|
},
|
||||||
Process::External(p) => packet_server::WvrProcess {
|
Self::External(p) => packet_server::WvrProcess {
|
||||||
name: p.get_name().unwrap_or(String::from("unknown")),
|
name: p.get_name().unwrap_or_else(|| String::from("unknown")),
|
||||||
userdata: Default::default(),
|
userdata: HashMap::default(),
|
||||||
display_handle: p.display_handle.as_packet(),
|
display_handle: p.display_handle.as_packet(),
|
||||||
handle: handle.as_packet(),
|
handle: handle.as_packet(),
|
||||||
},
|
},
|
||||||
@@ -89,7 +90,7 @@ impl Drop for WayVRProcess {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_process_env_value(pid: i32, key: &str) -> anyhow::Result<Option<String>> {
|
fn get_process_env_value(pid: i32, key: &str) -> anyhow::Result<Option<String>> {
|
||||||
let path = format!("/proc/{}/environ", pid);
|
let path = format!("/proc/{pid}/environ");
|
||||||
let mut env_data = String::new();
|
let mut env_data = String::new();
|
||||||
std::fs::File::open(path)?.read_to_string(&mut env_data)?;
|
std::fs::File::open(path)?.read_to_string(&mut env_data)?;
|
||||||
let lines: Vec<&str> = env_data.split('\0').filter(|s| !s.is_empty()).collect();
|
let lines: Vec<&str> = env_data.split('\0').filter(|s| !s.is_empty()).collect();
|
||||||
@@ -112,7 +113,7 @@ impl WayVRProcess {
|
|||||||
Ok(None) => true,
|
Ok(None) => true,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
// this shouldn't happen
|
// this shouldn't happen
|
||||||
log::error!("Child::try_wait failed: {}", e);
|
log::error!("Child::try_wait failed: {e}");
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -131,7 +132,7 @@ impl WayVRProcess {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_exec_name_from_pid(pid: u32) -> Option<String> {
|
fn get_exec_name_from_pid(pid: u32) -> Option<String> {
|
||||||
let path = format!("/proc/{}/exe", pid);
|
let path = format!("/proc/{pid}/exe");
|
||||||
match std::fs::read_link(&path) {
|
match std::fs::read_link(&path) {
|
||||||
Ok(buf) => {
|
Ok(buf) => {
|
||||||
if let Some(process_name) = buf.file_name().and_then(|s| s.to_str()) {
|
if let Some(process_name) = buf.file_name().and_then(|s| s.to_str()) {
|
||||||
@@ -170,7 +171,7 @@ impl ExternalProcess {
|
|||||||
gen_id!(ProcessVec, Process, ProcessCell, ProcessHandle);
|
gen_id!(ProcessVec, Process, ProcessCell, ProcessHandle);
|
||||||
|
|
||||||
pub fn find_by_pid(processes: &ProcessVec, pid: u32) -> Option<ProcessHandle> {
|
pub fn find_by_pid(processes: &ProcessVec, pid: u32) -> Option<ProcessHandle> {
|
||||||
log::debug!("Finding process with PID {}", pid);
|
log::debug!("Finding process with PID {pid}");
|
||||||
|
|
||||||
for (idx, cell) in processes.vec.iter().enumerate() {
|
for (idx, cell) in processes.vec.iter().enumerate() {
|
||||||
let Some(cell) = cell else {
|
let Some(cell) = cell else {
|
||||||
@@ -205,19 +206,19 @@ pub fn find_by_pid(processes: &ProcessVec, pid: u32) -> Option<ProcessHandle> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log::debug!("Process find with PID {} failed", pid);
|
log::debug!("Process find with PID {pid} failed");
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProcessHandle {
|
impl ProcessHandle {
|
||||||
pub fn from_packet(handle: packet_server::WvrProcessHandle) -> Self {
|
pub const fn from_packet(handle: packet_server::WvrProcessHandle) -> Self {
|
||||||
Self {
|
Self {
|
||||||
generation: handle.generation,
|
generation: handle.generation,
|
||||||
idx: handle.idx,
|
idx: handle.idx,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_packet(&self) -> packet_server::WvrProcessHandle {
|
pub const fn as_packet(&self) -> packet_server::WvrProcessHandle {
|
||||||
packet_server::WvrProcessHandle {
|
packet_server::WvrProcessHandle {
|
||||||
idx: self.idx,
|
idx: self.idx,
|
||||||
generation: self.generation,
|
generation: self.generation,
|
||||||
|
|||||||
@@ -44,11 +44,11 @@ fn read_check(expected_size: u32, res: std::io::Result<usize>) -> bool {
|
|||||||
if count == 0 {
|
if count == 0 {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if count as u32 != expected_size {
|
if count as u32 == expected_size {
|
||||||
log::error!("count {} is not {}", count, expected_size);
|
|
||||||
false
|
|
||||||
} else {
|
|
||||||
true // read succeeded
|
true // read succeeded
|
||||||
|
} else {
|
||||||
|
log::error!("count {count} is not {expected_size}");
|
||||||
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(_e) => {
|
Err(_e) => {
|
||||||
@@ -63,10 +63,10 @@ type Payload = SmallVec<[u8; 64]>;
|
|||||||
fn read_payload(conn: &mut local_socket::Stream, size: u32) -> Option<Payload> {
|
fn read_payload(conn: &mut local_socket::Stream, size: u32) -> Option<Payload> {
|
||||||
let mut payload = Payload::new();
|
let mut payload = Payload::new();
|
||||||
payload.resize(size as usize, 0);
|
payload.resize(size as usize, 0);
|
||||||
if !read_check(size, conn.read(&mut payload)) {
|
if read_check(size, conn.read(&mut payload)) {
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(payload)
|
Some(payload)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +89,7 @@ pub fn gen_env_vec(input: &[String]) -> Vec<(&str, &str)> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Connection {
|
impl Connection {
|
||||||
fn new(conn: local_socket::Stream) -> Self {
|
const fn new(conn: local_socket::Stream) -> Self {
|
||||||
Self {
|
Self {
|
||||||
conn,
|
conn,
|
||||||
alive: true,
|
alive: true,
|
||||||
@@ -222,10 +222,9 @@ impl Connection {
|
|||||||
false,
|
false,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
params.tasks.push(TickTask::NewDisplay(
|
params
|
||||||
packet_params.clone(),
|
.tasks
|
||||||
Some(display_handle),
|
.push(TickTask::NewDisplay(packet_params, Some(display_handle)));
|
||||||
));
|
|
||||||
|
|
||||||
send_packet(
|
send_packet(
|
||||||
&mut self.conn,
|
&mut self.conn,
|
||||||
@@ -246,7 +245,7 @@ impl Connection {
|
|||||||
let res = params
|
let res = params
|
||||||
.state
|
.state
|
||||||
.destroy_display(display::DisplayHandle::from_packet(handle))
|
.destroy_display(display::DisplayHandle::from_packet(handle))
|
||||||
.map_err(|e| format!("{:?}", e));
|
.map_err(|e| format!("{e:?}"));
|
||||||
|
|
||||||
send_packet(
|
send_packet(
|
||||||
&mut self.conn,
|
&mut self.conn,
|
||||||
@@ -256,29 +255,25 @@ impl Connection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handle_wvr_display_set_visible(
|
fn handle_wvr_display_set_visible(
|
||||||
&mut self,
|
|
||||||
params: &mut TickParams,
|
params: &mut TickParams,
|
||||||
handle: packet_server::WvrDisplayHandle,
|
handle: packet_server::WvrDisplayHandle,
|
||||||
visible: bool,
|
visible: bool,
|
||||||
) -> anyhow::Result<()> {
|
) {
|
||||||
params.state.signals.send(WayVRSignal::DisplayVisibility(
|
params.state.signals.send(WayVRSignal::DisplayVisibility(
|
||||||
display::DisplayHandle::from_packet(handle),
|
display::DisplayHandle::from_packet(handle),
|
||||||
visible,
|
visible,
|
||||||
));
|
));
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_wvr_display_set_window_layout(
|
fn handle_wvr_display_set_window_layout(
|
||||||
&mut self,
|
|
||||||
params: &mut TickParams,
|
params: &mut TickParams,
|
||||||
handle: packet_server::WvrDisplayHandle,
|
handle: packet_server::WvrDisplayHandle,
|
||||||
layout: packet_server::WvrDisplayWindowLayout,
|
layout: packet_server::WvrDisplayWindowLayout,
|
||||||
) -> anyhow::Result<()> {
|
) {
|
||||||
params.state.signals.send(WayVRSignal::DisplayWindowLayout(
|
params.state.signals.send(WayVRSignal::DisplayWindowLayout(
|
||||||
display::DisplayHandle::from_packet(handle),
|
display::DisplayHandle::from_packet(handle),
|
||||||
layout,
|
layout,
|
||||||
));
|
));
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_wvr_display_window_list(
|
fn handle_wvr_display_window_list(
|
||||||
@@ -331,11 +326,10 @@ impl Connection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handle_wvr_window_set_visible(
|
fn handle_wvr_window_set_visible(
|
||||||
&mut self,
|
|
||||||
params: &mut TickParams,
|
params: &mut TickParams,
|
||||||
handle: packet_server::WvrWindowHandle,
|
handle: packet_server::WvrWindowHandle,
|
||||||
visible: bool,
|
visible: bool,
|
||||||
) -> anyhow::Result<()> {
|
) {
|
||||||
let mut to_resize = None;
|
let mut to_resize = None;
|
||||||
|
|
||||||
if let Some(window) = params
|
if let Some(window) = params
|
||||||
@@ -355,8 +349,6 @@ impl Connection {
|
|||||||
display.trigger_rerender();
|
display.trigger_rerender();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_wvr_process_launch(
|
fn handle_wvr_process_launch(
|
||||||
@@ -392,7 +384,7 @@ impl Connection {
|
|||||||
serial: ipc::Serial,
|
serial: ipc::Serial,
|
||||||
display_handle: packet_server::WvrDisplayHandle,
|
display_handle: packet_server::WvrDisplayHandle,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let native_handle = &display::DisplayHandle::from_packet(display_handle.clone());
|
let native_handle = &display::DisplayHandle::from_packet(display_handle);
|
||||||
let disp = params
|
let disp = params
|
||||||
.state
|
.state
|
||||||
.displays
|
.displays
|
||||||
@@ -440,20 +432,17 @@ impl Connection {
|
|||||||
|
|
||||||
// This request doesn't return anything to the client
|
// This request doesn't return anything to the client
|
||||||
fn handle_wvr_process_terminate(
|
fn handle_wvr_process_terminate(
|
||||||
&mut self,
|
|
||||||
params: &mut TickParams,
|
params: &mut TickParams,
|
||||||
process_handle: packet_server::WvrProcessHandle,
|
process_handle: packet_server::WvrProcessHandle,
|
||||||
) -> anyhow::Result<()> {
|
) {
|
||||||
let native_handle = &process::ProcessHandle::from_packet(process_handle.clone());
|
let native_handle = &process::ProcessHandle::from_packet(process_handle);
|
||||||
let process = params.state.processes.get_mut(native_handle);
|
let process = params.state.processes.get_mut(native_handle);
|
||||||
|
|
||||||
let Some(process) = process else {
|
let Some(process) = process else {
|
||||||
return Ok(());
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
process.terminate();
|
process.terminate();
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_wvr_process_get(
|
fn handle_wvr_process_get(
|
||||||
@@ -462,7 +451,7 @@ impl Connection {
|
|||||||
serial: ipc::Serial,
|
serial: ipc::Serial,
|
||||||
process_handle: packet_server::WvrProcessHandle,
|
process_handle: packet_server::WvrProcessHandle,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let native_handle = &process::ProcessHandle::from_packet(process_handle.clone());
|
let native_handle = &process::ProcessHandle::from_packet(process_handle);
|
||||||
let process = params
|
let process = params
|
||||||
.state
|
.state
|
||||||
.processes
|
.processes
|
||||||
@@ -478,10 +467,9 @@ impl Connection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handle_wlx_haptics(
|
fn handle_wlx_haptics(
|
||||||
&mut self,
|
|
||||||
params: &mut TickParams,
|
params: &mut TickParams,
|
||||||
haptics_params: packet_client::WlxHapticsParams,
|
haptics_params: packet_client::WlxHapticsParams,
|
||||||
) -> anyhow::Result<()> {
|
) {
|
||||||
params
|
params
|
||||||
.state
|
.state
|
||||||
.tasks
|
.tasks
|
||||||
@@ -490,7 +478,6 @@ impl Connection {
|
|||||||
frequency: haptics_params.frequency,
|
frequency: haptics_params.frequency,
|
||||||
intensity: haptics_params.intensity,
|
intensity: haptics_params.intensity,
|
||||||
}));
|
}));
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_payload(&mut self, params: &mut TickParams, payload: Payload) -> anyhow::Result<()> {
|
fn process_payload(&mut self, params: &mut TickParams, payload: Payload) -> anyhow::Result<()> {
|
||||||
@@ -516,16 +503,16 @@ impl Connection {
|
|||||||
self.handle_wvr_display_remove(params, serial, display_handle)?;
|
self.handle_wvr_display_remove(params, serial, display_handle)?;
|
||||||
}
|
}
|
||||||
PacketClient::WvrDisplaySetVisible(display_handle, visible) => {
|
PacketClient::WvrDisplaySetVisible(display_handle, visible) => {
|
||||||
self.handle_wvr_display_set_visible(params, display_handle, visible)?;
|
Self::handle_wvr_display_set_visible(params, display_handle, visible);
|
||||||
}
|
}
|
||||||
PacketClient::WvrDisplaySetWindowLayout(display_handle, layout) => {
|
PacketClient::WvrDisplaySetWindowLayout(display_handle, layout) => {
|
||||||
self.handle_wvr_display_set_window_layout(params, display_handle, layout)?;
|
Self::handle_wvr_display_set_window_layout(params, display_handle, layout);
|
||||||
}
|
}
|
||||||
PacketClient::WvrDisplayWindowList(serial, display_handle) => {
|
PacketClient::WvrDisplayWindowList(serial, display_handle) => {
|
||||||
self.handle_wvr_display_window_list(params, serial, display_handle)?;
|
self.handle_wvr_display_window_list(params, serial, display_handle)?;
|
||||||
}
|
}
|
||||||
PacketClient::WvrWindowSetVisible(window_handle, visible) => {
|
PacketClient::WvrWindowSetVisible(window_handle, visible) => {
|
||||||
self.handle_wvr_window_set_visible(params, window_handle, visible)?;
|
Self::handle_wvr_window_set_visible(params, window_handle, visible);
|
||||||
}
|
}
|
||||||
PacketClient::WvrProcessGet(serial, process_handle) => {
|
PacketClient::WvrProcessGet(serial, process_handle) => {
|
||||||
self.handle_wvr_process_get(params, serial, process_handle)?;
|
self.handle_wvr_process_get(params, serial, process_handle)?;
|
||||||
@@ -540,10 +527,10 @@ impl Connection {
|
|||||||
self.handle_wvr_display_create(params, serial, packet_params)?;
|
self.handle_wvr_display_create(params, serial, packet_params)?;
|
||||||
}
|
}
|
||||||
PacketClient::WvrProcessTerminate(process_handle) => {
|
PacketClient::WvrProcessTerminate(process_handle) => {
|
||||||
self.handle_wvr_process_terminate(params, process_handle)?;
|
Self::handle_wvr_process_terminate(params, process_handle);
|
||||||
}
|
}
|
||||||
PacketClient::WlxHaptics(haptics_params) => {
|
PacketClient::WlxHaptics(haptics_params) => {
|
||||||
self.handle_wlx_haptics(params, haptics_params)?;
|
Self::handle_wlx_haptics(params, haptics_params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -554,9 +541,9 @@ impl Connection {
|
|||||||
log::debug!("payload size {}", payload.len());
|
log::debug!("payload size {}", payload.len());
|
||||||
|
|
||||||
if let Err(e) = self.process_payload(params, payload) {
|
if let Err(e) = self.process_payload(params, payload) {
|
||||||
log::error!("Invalid payload from the client, closing connection: {}", e);
|
log::error!("Invalid payload from the client, closing connection: {e}");
|
||||||
// send also error message directly to the client before disconnecting
|
// send also error message directly to the client before disconnecting
|
||||||
self.kill(format!("{}", e).as_str());
|
self.kill(format!("{e}").as_str());
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
@@ -589,8 +576,7 @@ impl Connection {
|
|||||||
if payload_size > size_limit {
|
if payload_size > size_limit {
|
||||||
// over 128 KiB?
|
// over 128 KiB?
|
||||||
log::error!(
|
log::error!(
|
||||||
"Client sent a packet header with the size over {} bytes, closing connection.",
|
"Client sent a packet header with the size over {size_limit} bytes, closing connection."
|
||||||
size_limit
|
|
||||||
);
|
);
|
||||||
self.kill("Too big packet received (over 128 KiB)");
|
self.kill("Too big packet received (over 128 KiB)");
|
||||||
return false;
|
return false;
|
||||||
@@ -637,7 +623,7 @@ impl WayVRServer {
|
|||||||
Err(e) => anyhow::bail!("Failed to start WayVRServer IPC listener. Reason: {}", e),
|
Err(e) => anyhow::bail!("Failed to start WayVRServer IPC listener. Reason: {}", e),
|
||||||
};
|
};
|
||||||
|
|
||||||
log::info!("WayVRServer IPC running at {}", printname);
|
log::info!("WayVRServer IPC running at {printname}");
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
listener,
|
listener,
|
||||||
@@ -662,16 +648,15 @@ impl WayVRServer {
|
|||||||
self.connections.retain(|c| c.alive);
|
self.connections.retain(|c| c.alive);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tick(&mut self, params: &mut TickParams) -> anyhow::Result<()> {
|
pub fn tick(&mut self, params: &mut TickParams) {
|
||||||
self.accept_connections();
|
self.accept_connections();
|
||||||
self.tick_connections(params);
|
self.tick_connections(params);
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn broadcast(&mut self, packet: packet_server::PacketServer) {
|
pub fn broadcast(&mut self, packet: packet_server::PacketServer) {
|
||||||
for connection in &mut self.connections {
|
for connection in &mut self.connections {
|
||||||
if let Err(e) = send_packet(&mut connection.conn, &ipc::data_encode(&packet)) {
|
if let Err(e) = send_packet(&mut connection.conn, &ipc::data_encode(&packet)) {
|
||||||
log::error!("failed to broadcast packet: {:?}", e);
|
log::error!("failed to broadcast packet: {e:?}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ impl Window {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_pos(&mut self, pos_x: i32, pos_y: i32) {
|
pub const fn set_pos(&mut self, pos_x: i32, pos_y: i32) {
|
||||||
self.pos_x = pos_x;
|
self.pos_x = pos_x;
|
||||||
self.pos_y = pos_y;
|
self.pos_y = pos_y;
|
||||||
}
|
}
|
||||||
@@ -52,7 +52,7 @@ pub struct WindowManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl WindowManager {
|
impl WindowManager {
|
||||||
pub fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
windows: WindowVec::new(),
|
windows: WindowVec::new(),
|
||||||
}
|
}
|
||||||
@@ -86,14 +86,14 @@ impl WindowManager {
|
|||||||
gen_id!(WindowVec, Window, WindowCell, WindowHandle);
|
gen_id!(WindowVec, Window, WindowCell, WindowHandle);
|
||||||
|
|
||||||
impl WindowHandle {
|
impl WindowHandle {
|
||||||
pub fn from_packet(handle: packet_server::WvrWindowHandle) -> Self {
|
pub const fn from_packet(handle: packet_server::WvrWindowHandle) -> Self {
|
||||||
Self {
|
Self {
|
||||||
generation: handle.generation,
|
generation: handle.generation,
|
||||||
idx: handle.idx,
|
idx: handle.idx,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_packet(&self) -> packet_server::WvrWindowHandle {
|
pub const fn as_packet(&self) -> packet_server::WvrWindowHandle {
|
||||||
packet_server::WvrWindowHandle {
|
packet_server::WvrWindowHandle {
|
||||||
idx: self.idx,
|
idx: self.idx,
|
||||||
generation: self.generation,
|
generation: self.generation,
|
||||||
|
|||||||
@@ -69,79 +69,76 @@ impl AStrSetExt for AStrSet {
|
|||||||
|
|
||||||
fn arc_rm(&mut self, value: &str) -> bool {
|
fn arc_rm(&mut self, value: &str) -> bool {
|
||||||
let index = self.iter().position(|v| v.as_ref().eq(value));
|
let index = self.iter().position(|v| v.as_ref().eq(value));
|
||||||
index
|
index.is_some_and(|i| {
|
||||||
.map(|i| {
|
|
||||||
self.remove(i);
|
self.remove(i);
|
||||||
true
|
true
|
||||||
})
|
})
|
||||||
.unwrap_or(false)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type PwTokenMap = AStrMap<String>;
|
pub type PwTokenMap = AStrMap<String>;
|
||||||
|
|
||||||
pub fn def_watch_pos() -> Vec3A {
|
pub const fn def_watch_pos() -> Vec3A {
|
||||||
vec3a(-0.03, -0.01, 0.125)
|
vec3a(-0.03, -0.01, 0.125)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn def_watch_rot() -> Quat {
|
pub const fn def_watch_rot() -> Quat {
|
||||||
Quat::from_xyzw(-0.7071066, 0.0007963618, 0.7071066, 0.0)
|
Quat::from_xyzw(-0.707_106_6, 0.000_796_361_8, 0.707_106_6, 0.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn def_left() -> LeftRight {
|
pub const fn def_left() -> LeftRight {
|
||||||
LeftRight::Left
|
LeftRight::Left
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn def_pw_tokens() -> PwTokenMap {
|
pub const fn def_pw_tokens() -> PwTokenMap {
|
||||||
AStrMap::new()
|
AStrMap::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn def_mouse_move_interval_ms() -> u32 {
|
const fn def_mouse_move_interval_ms() -> u32 {
|
||||||
10 // 100fps
|
10 // 100fps
|
||||||
}
|
}
|
||||||
|
|
||||||
fn def_click_freeze_time_ms() -> u32 {
|
const fn def_click_freeze_time_ms() -> u32 {
|
||||||
300
|
300
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn def_true() -> bool {
|
pub const fn def_true() -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn def_false() -> bool {
|
const fn def_false() -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn def_one() -> f32 {
|
const fn def_one() -> f32 {
|
||||||
1.0
|
1.0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn def_half() -> f32 {
|
pub const fn def_half() -> f32 {
|
||||||
0.5
|
0.5
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn def_point7() -> f32 {
|
pub const fn def_point7() -> f32 {
|
||||||
0.7
|
0.7
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn def_point3() -> f32 {
|
pub const fn def_point3() -> f32 {
|
||||||
0.3
|
0.3
|
||||||
}
|
}
|
||||||
|
|
||||||
fn def_osc_port() -> u16 {
|
const fn def_osc_port() -> u16 {
|
||||||
9000
|
9000
|
||||||
}
|
}
|
||||||
|
|
||||||
fn def_empty_vec_string() -> Vec<String> {
|
const fn def_empty_vec_string() -> Vec<String> {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn def_timezones() -> Vec<String> {
|
fn def_timezones() -> Vec<String> {
|
||||||
let offset = chrono::Local::now().offset().fix();
|
|
||||||
|
|
||||||
const EMEA: i32 = -60 * 60; // UTC-1
|
const EMEA: i32 = -60 * 60; // UTC-1
|
||||||
const APAC: i32 = 5 * 60 * 60; // UTC+5
|
const APAC: i32 = 5 * 60 * 60; // UTC+5
|
||||||
|
|
||||||
|
let offset = chrono::Local::now().offset().fix();
|
||||||
match offset.local_minus_utc() {
|
match offset.local_minus_utc() {
|
||||||
i32::MIN..EMEA => vec!["Europe/Paris".into(), "Asia/Tokyo".into()],
|
i32::MIN..EMEA => vec!["Europe/Paris".into(), "Asia/Tokyo".into()],
|
||||||
EMEA..APAC => vec!["America/New_York".into(), "Asia/Tokyo".into()],
|
EMEA..APAC => vec!["America/New_York".into(), "Asia/Tokyo".into()],
|
||||||
@@ -149,15 +146,15 @@ fn def_timezones() -> Vec<String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn def_screens() -> AStrSet {
|
const fn def_screens() -> AStrSet {
|
||||||
AStrSet::new()
|
AStrSet::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn def_curve_values() -> AStrMap<f32> {
|
const fn def_curve_values() -> AStrMap<f32> {
|
||||||
AStrMap::new()
|
AStrMap::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn def_transforms() -> AStrMap<Affine3A> {
|
const fn def_transforms() -> AStrMap<Affine3A> {
|
||||||
AStrMap::new()
|
AStrMap::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,7 +174,7 @@ fn def_font() -> Arc<str> {
|
|||||||
"LiberationSans:style=Bold".into()
|
"LiberationSans:style=Bold".into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn def_max_height() -> u16 {
|
const fn def_max_height() -> u16 {
|
||||||
1440
|
1440
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,7 +291,7 @@ pub struct GeneralConfig {
|
|||||||
#[serde(default = "def_max_height")]
|
#[serde(default = "def_max_height")]
|
||||||
pub screen_max_height: u16,
|
pub screen_max_height: u16,
|
||||||
|
|
||||||
#[serde(default = "def_true")]
|
#[serde(default = "def_false")]
|
||||||
pub screen_render_down: bool,
|
pub screen_render_down: bool,
|
||||||
|
|
||||||
#[serde(default = "def_point3")]
|
#[serde(default = "def_point3")]
|
||||||
@@ -315,23 +312,21 @@ pub struct GeneralConfig {
|
|||||||
|
|
||||||
impl GeneralConfig {
|
impl GeneralConfig {
|
||||||
fn sanitize_range(name: &str, val: f32, from: f32, to: f32) {
|
fn sanitize_range(name: &str, val: f32, from: f32, to: f32) {
|
||||||
if !val.is_normal() || val < from || val > to {
|
assert!(
|
||||||
panic!(
|
!(!val.is_normal() || val < from || val > to),
|
||||||
"GeneralConfig: {} needs to be between {} and {}",
|
"GeneralConfig: {name} needs to be between {from} and {to}"
|
||||||
name, from, to
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn load_from_disk() -> GeneralConfig {
|
pub fn load_from_disk() -> Self {
|
||||||
let config = load_general();
|
let config = load_general();
|
||||||
config.post_load();
|
config.post_load();
|
||||||
config
|
config
|
||||||
}
|
}
|
||||||
|
|
||||||
fn post_load(&self) {
|
fn post_load(&self) {
|
||||||
GeneralConfig::sanitize_range("keyboard_scale", self.keyboard_scale, 0.05, 5.0);
|
Self::sanitize_range("keyboard_scale", self.keyboard_scale, 0.05, 5.0);
|
||||||
GeneralConfig::sanitize_range("desktop_view_scale", self.desktop_view_scale, 0.05, 5.0);
|
Self::sanitize_range("desktop_view_scale", self.desktop_view_scale, 0.05, 5.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -374,8 +369,8 @@ where
|
|||||||
match serde_yaml::from_str::<T>(yaml) {
|
match serde_yaml::from_str::<T>(yaml) {
|
||||||
Ok(d) => return d,
|
Ok(d) => return d,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Failed to parse {}, falling back to defaults.", file_name);
|
error!("Failed to parse {file_name}, falling back to defaults.");
|
||||||
error!("{}", e);
|
error!("{e}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -384,7 +379,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_custom_ui(name: &str) -> anyhow::Result<ModularUiConfig> {
|
pub fn load_custom_ui(name: &str) -> anyhow::Result<ModularUiConfig> {
|
||||||
let filename = format!("{}.yaml", name);
|
let filename = format!("{name}.yaml");
|
||||||
let Some(yaml_data) = config_io::load(&filename) else {
|
let Some(yaml_data) = config_io::load(&filename) else {
|
||||||
bail!("Could not read file at {}", &filename);
|
bail!("Could not read file at {}", &filename);
|
||||||
};
|
};
|
||||||
@@ -416,13 +411,13 @@ where
|
|||||||
.filter_map(|r| match r {
|
.filter_map(|r| match r {
|
||||||
Ok(entry) => Some(entry),
|
Ok(entry) => Some(entry),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Failed to read conf.d directory: {}", e);
|
error!("Failed to read conf.d directory: {e}");
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
// Sort paths alphabetically
|
// Sort paths alphabetically
|
||||||
paths.sort_by_key(|dir| dir.path());
|
paths.sort_by_key(std::fs::DirEntry::path);
|
||||||
for path in paths {
|
for path in paths {
|
||||||
log::info!("Loading config file: {}", path.path().to_string_lossy());
|
log::info!("Loading config file: {}", path.path().to_string_lossy());
|
||||||
settings_builder = settings_builder.add_source(File::from(path.path()));
|
settings_builder = settings_builder.add_source(File::from(path.path()));
|
||||||
@@ -433,11 +428,11 @@ where
|
|||||||
Ok(settings) => match settings.try_deserialize::<ConfigData>() {
|
Ok(settings) => match settings.try_deserialize::<ConfigData>() {
|
||||||
Ok(config) => config,
|
Ok(config) => config,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
panic!("Failed to deserialize settings: {}", e);
|
panic!("Failed to deserialize settings: {e}");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
panic!("Failed to build settings: {}", e);
|
panic!("Failed to build settings: {e}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,8 +18,7 @@ static CONFIG_ROOT_PATH: Lazy<PathBuf> = Lazy::new(|| {
|
|||||||
}
|
}
|
||||||
//Return fallback config path
|
//Return fallback config path
|
||||||
error!(
|
error!(
|
||||||
"Err: Failed to find config path, using {}",
|
"Err: Failed to find config path, using {FALLBACK_CONFIG_PATH}"
|
||||||
FALLBACK_CONFIG_PATH
|
|
||||||
);
|
);
|
||||||
PathBuf::from(FALLBACK_CONFIG_PATH)
|
PathBuf::from(FALLBACK_CONFIG_PATH)
|
||||||
});
|
});
|
||||||
@@ -31,8 +30,8 @@ pub fn get_config_root() -> PathBuf {
|
|||||||
impl ConfigRoot {
|
impl ConfigRoot {
|
||||||
pub fn get_conf_d_path(&self) -> PathBuf {
|
pub fn get_conf_d_path(&self) -> PathBuf {
|
||||||
get_config_root().join(match self {
|
get_config_root().join(match self {
|
||||||
ConfigRoot::Generic => "conf.d",
|
Self::Generic => "conf.d",
|
||||||
ConfigRoot::WayVR => "wayvr.conf.d",
|
Self::WayVR => "wayvr.conf.d",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,23 +33,23 @@ pub enum AttachTo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AttachTo {
|
impl AttachTo {
|
||||||
pub fn get_relative_to(&self) -> RelativeTo {
|
pub const fn get_relative_to(&self) -> RelativeTo {
|
||||||
match self {
|
match self {
|
||||||
AttachTo::None => RelativeTo::None,
|
Self::None => RelativeTo::None,
|
||||||
AttachTo::HandLeft => RelativeTo::Hand(0),
|
Self::HandLeft => RelativeTo::Hand(0),
|
||||||
AttachTo::HandRight => RelativeTo::Hand(1),
|
Self::HandRight => RelativeTo::Hand(1),
|
||||||
AttachTo::Stage => RelativeTo::Stage,
|
Self::Stage => RelativeTo::Stage,
|
||||||
AttachTo::Head => RelativeTo::Head,
|
Self::Head => RelativeTo::Head,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_packet(input: &wayvr_ipc::packet_client::AttachTo) -> AttachTo {
|
pub const fn from_packet(input: &wayvr_ipc::packet_client::AttachTo) -> Self {
|
||||||
match input {
|
match input {
|
||||||
wayvr_ipc::packet_client::AttachTo::None => AttachTo::None,
|
wayvr_ipc::packet_client::AttachTo::None => Self::None,
|
||||||
wayvr_ipc::packet_client::AttachTo::HandLeft => AttachTo::HandLeft,
|
wayvr_ipc::packet_client::AttachTo::HandLeft => Self::HandLeft,
|
||||||
wayvr_ipc::packet_client::AttachTo::HandRight => AttachTo::HandRight,
|
wayvr_ipc::packet_client::AttachTo::HandRight => Self::HandRight,
|
||||||
wayvr_ipc::packet_client::AttachTo::Head => AttachTo::Head,
|
wayvr_ipc::packet_client::AttachTo::Head => Self::Head,
|
||||||
wayvr_ipc::packet_client::AttachTo::Stage => AttachTo::Stage,
|
wayvr_ipc::packet_client::AttachTo::Stage => Self::Stage,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -92,23 +92,23 @@ impl WayVRCatalog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn def_false() -> bool {
|
const fn def_false() -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn def_true() -> bool {
|
const fn def_true() -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn def_autohide_delay() -> u32 {
|
const fn def_autohide_delay() -> u32 {
|
||||||
750
|
750
|
||||||
}
|
}
|
||||||
|
|
||||||
fn def_keyboard_repeat_delay() -> u32 {
|
const fn def_keyboard_repeat_delay() -> u32 {
|
||||||
200
|
200
|
||||||
}
|
}
|
||||||
|
|
||||||
fn def_keyboard_repeat_rate() -> u32 {
|
const fn def_keyboard_repeat_rate() -> u32 {
|
||||||
50
|
50
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,14 +173,14 @@ impl WayVRConfig {
|
|||||||
|
|
||||||
pub fn get_wayvr_config(
|
pub fn get_wayvr_config(
|
||||||
config_general: &crate::config::GeneralConfig,
|
config_general: &crate::config::GeneralConfig,
|
||||||
config_wayvr: &crate::config_wayvr::WayVRConfig,
|
config_wayvr: &Self,
|
||||||
) -> anyhow::Result<wayvr::Config> {
|
) -> anyhow::Result<wayvr::Config> {
|
||||||
Ok(wayvr::Config {
|
Ok(wayvr::Config {
|
||||||
click_freeze_time_ms: config_general.click_freeze_time_ms,
|
click_freeze_time_ms: config_general.click_freeze_time_ms,
|
||||||
keyboard_repeat_delay_ms: config_wayvr.keyboard_repeat_delay,
|
keyboard_repeat_delay_ms: config_wayvr.keyboard_repeat_delay,
|
||||||
keyboard_repeat_rate: config_wayvr.keyboard_repeat_rate,
|
keyboard_repeat_rate: config_wayvr.keyboard_repeat_rate,
|
||||||
blit_method: wayvr::BlitMethod::from_string(&config_wayvr.blit_method)
|
blit_method: wayvr::BlitMethod::from_string(&config_wayvr.blit_method)
|
||||||
.ok_or(anyhow::anyhow!("Unknown blit method"))?,
|
.ok_or_else(|| anyhow::anyhow!("Unknown blit method"))?,
|
||||||
auto_hide_delay: if config_wayvr.auto_hide {
|
auto_hide_delay: if config_wayvr.auto_hide {
|
||||||
Some(config_wayvr.auto_hide_delay)
|
Some(config_wayvr.auto_hide_delay)
|
||||||
} else {
|
} else {
|
||||||
@@ -235,7 +235,7 @@ impl WayVRConfig {
|
|||||||
|
|
||||||
pub fn load_wayvr() -> WayVRConfig {
|
pub fn load_wayvr() -> WayVRConfig {
|
||||||
let config_root_path = config_io::ConfigRoot::WayVR.ensure_dir();
|
let config_root_path = config_io::ConfigRoot::WayVR.ensure_dir();
|
||||||
log::info!("WayVR Config root path: {:?}", config_root_path);
|
log::info!("WayVR Config root path: {config_root_path:?}");
|
||||||
log::info!(
|
log::info!(
|
||||||
"WayVR conf.d path: {:?}",
|
"WayVR conf.d path: {:?}",
|
||||||
config_io::ConfigRoot::WayVR.get_conf_d_path()
|
config_io::ConfigRoot::WayVR.get_conf_d_path()
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
pub(crate) mod dds;
|
pub mod dds;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
@@ -128,7 +128,7 @@ pub struct WlxGraphics {
|
|||||||
pub shared_shaders: RwLock<HashMap<&'static str, Arc<ShaderModule>>>,
|
pub shared_shaders: RwLock<HashMap<&'static str, Arc<ShaderModule>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_dmabuf_extensions() -> DeviceExtensions {
|
const fn get_dmabuf_extensions() -> DeviceExtensions {
|
||||||
DeviceExtensions {
|
DeviceExtensions {
|
||||||
khr_external_memory: true,
|
khr_external_memory: true,
|
||||||
khr_external_memory_fd: true,
|
khr_external_memory_fd: true,
|
||||||
@@ -155,14 +155,17 @@ unsafe extern "system" fn get_instance_proc_addr(
|
|||||||
|
|
||||||
impl WlxGraphics {
|
impl WlxGraphics {
|
||||||
#[cfg(feature = "openxr")]
|
#[cfg(feature = "openxr")]
|
||||||
|
#[allow(clippy::too_many_lines)]
|
||||||
pub fn new_openxr(
|
pub fn new_openxr(
|
||||||
xr_instance: openxr::Instance,
|
xr_instance: openxr::Instance,
|
||||||
system: openxr::SystemId,
|
system: openxr::SystemId,
|
||||||
) -> anyhow::Result<Arc<Self>> {
|
) -> anyhow::Result<Arc<Self>> {
|
||||||
use std::ffi::{self, c_char, CString};
|
use std::ffi::{self, CString};
|
||||||
|
|
||||||
use ash::vk::PhysicalDeviceDynamicRenderingFeatures;
|
use ash::vk::PhysicalDeviceDynamicRenderingFeatures;
|
||||||
use vulkano::{Handle, Version};
|
use vulkano::{
|
||||||
|
descriptor_set::allocator::StandardDescriptorSetAllocatorCreateInfo, Handle, Version,
|
||||||
|
};
|
||||||
|
|
||||||
let instance_extensions = InstanceExtensions {
|
let instance_extensions = InstanceExtensions {
|
||||||
khr_get_physical_device_properties2: true,
|
khr_get_physical_device_properties2: true,
|
||||||
@@ -173,7 +176,7 @@ impl WlxGraphics {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|(name, enabled)| {
|
.filter_map(|(name, enabled)| {
|
||||||
if enabled {
|
if enabled {
|
||||||
Some(ffi::CString::new(name).unwrap().into_raw() as *const c_char)
|
Some(ffi::CString::new(name).unwrap().into_raw().cast_const())
|
||||||
// want panic
|
// want panic
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@@ -195,10 +198,12 @@ impl WlxGraphics {
|
|||||||
.create_vulkan_instance(
|
.create_vulkan_instance(
|
||||||
system,
|
system,
|
||||||
get_instance_proc_addr,
|
get_instance_proc_addr,
|
||||||
|
std::ptr::from_ref(
|
||||||
&vk::InstanceCreateInfo::builder()
|
&vk::InstanceCreateInfo::builder()
|
||||||
.application_info(&vk_app_info_raw)
|
.application_info(&vk_app_info_raw)
|
||||||
.enabled_extension_names(&instance_extensions_raw)
|
.enabled_extension_names(&instance_extensions_raw),
|
||||||
as *const _ as *const _,
|
)
|
||||||
|
.cast(),
|
||||||
)
|
)
|
||||||
.expect("XR error creating Vulkan instance")
|
.expect("XR error creating Vulkan instance")
|
||||||
.map_err(vk::Result::from_raw)
|
.map_err(vk::Result::from_raw)
|
||||||
@@ -228,12 +233,10 @@ impl WlxGraphics {
|
|||||||
}?;
|
}?;
|
||||||
|
|
||||||
let vk_device_properties = physical_device.properties();
|
let vk_device_properties = physical_device.properties();
|
||||||
if vk_device_properties.api_version < target_version {
|
assert!(
|
||||||
panic!(
|
(vk_device_properties.api_version >= target_version),
|
||||||
"Vulkan physical device doesn't support Vulkan {}",
|
"Vulkan physical device doesn't support Vulkan {target_version}"
|
||||||
target_version
|
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
log::info!(
|
log::info!(
|
||||||
"Using vkPhysicalDevice: {}",
|
"Using vkPhysicalDevice: {}",
|
||||||
@@ -268,7 +271,7 @@ impl WlxGraphics {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|(name, enabled)| {
|
.filter_map(|(name, enabled)| {
|
||||||
if enabled {
|
if enabled {
|
||||||
Some(ffi::CString::new(name).unwrap().into_raw() as *const c_char)
|
Some(ffi::CString::new(name).unwrap().into_raw().cast_const())
|
||||||
// want panic
|
// want panic
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@@ -296,8 +299,8 @@ impl WlxGraphics {
|
|||||||
let mut dynamic_rendering =
|
let mut dynamic_rendering =
|
||||||
PhysicalDeviceDynamicRenderingFeatures::builder().dynamic_rendering(true);
|
PhysicalDeviceDynamicRenderingFeatures::builder().dynamic_rendering(true);
|
||||||
|
|
||||||
dynamic_rendering.p_next = device_create_info.p_next as _;
|
dynamic_rendering.p_next = device_create_info.p_next.cast_mut();
|
||||||
device_create_info.p_next = (&mut dynamic_rendering) as *const _ as *const c_void;
|
device_create_info.p_next = &raw mut dynamic_rendering as *const c_void;
|
||||||
|
|
||||||
let texture_filtering = if physical_device.supported_extensions().ext_filter_cubic {
|
let texture_filtering = if physical_device.supported_extensions().ext_filter_cubic {
|
||||||
Filter::Cubic
|
Filter::Cubic
|
||||||
@@ -311,7 +314,7 @@ impl WlxGraphics {
|
|||||||
system,
|
system,
|
||||||
get_instance_proc_addr,
|
get_instance_proc_addr,
|
||||||
physical_device.handle().as_raw() as _,
|
physical_device.handle().as_raw() as _,
|
||||||
(&device_create_info) as *const _ as *const _,
|
(&raw const device_create_info).cast(),
|
||||||
)
|
)
|
||||||
.expect("XR error creating Vulkan device")
|
.expect("XR error creating Vulkan device")
|
||||||
.map_err(vk::Result::from_raw)
|
.map_err(vk::Result::from_raw)
|
||||||
@@ -346,7 +349,7 @@ impl WlxGraphics {
|
|||||||
device_extensions_raw
|
device_extensions_raw
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.for_each(|c_string| unsafe {
|
.for_each(|c_string| unsafe {
|
||||||
let _ = CString::from_raw(c_string as _);
|
let _ = CString::from_raw(c_string.cast_mut());
|
||||||
});
|
});
|
||||||
|
|
||||||
let queue = queues
|
let queue = queues
|
||||||
@@ -363,7 +366,7 @@ impl WlxGraphics {
|
|||||||
));
|
));
|
||||||
let descriptor_set_allocator = Arc::new(StandardDescriptorSetAllocator::new(
|
let descriptor_set_allocator = Arc::new(StandardDescriptorSetAllocator::new(
|
||||||
device.clone(),
|
device.clone(),
|
||||||
Default::default(),
|
StandardDescriptorSetAllocatorCreateInfo::default(),
|
||||||
));
|
));
|
||||||
|
|
||||||
let (quad_verts, quad_indices) = Self::default_quad(memory_allocator.clone())?;
|
let (quad_verts, quad_indices) = Self::default_quad(memory_allocator.clone())?;
|
||||||
@@ -385,6 +388,7 @@ impl WlxGraphics {
|
|||||||
Ok(Arc::new(me))
|
Ok(Arc::new(me))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_lines)]
|
||||||
#[cfg(feature = "openvr")]
|
#[cfg(feature = "openvr")]
|
||||||
pub fn new_openvr(
|
pub fn new_openvr(
|
||||||
mut vk_instance_extensions: InstanceExtensions,
|
mut vk_instance_extensions: InstanceExtensions,
|
||||||
@@ -394,6 +398,8 @@ impl WlxGraphics {
|
|||||||
//let layers = vec!["VK_LAYER_KHRONOS_validation".to_owned()];
|
//let layers = vec!["VK_LAYER_KHRONOS_validation".to_owned()];
|
||||||
//#[cfg(not(debug_assertions))]
|
//#[cfg(not(debug_assertions))]
|
||||||
|
|
||||||
|
use vulkano::descriptor_set::allocator::StandardDescriptorSetAllocatorCreateInfo;
|
||||||
|
|
||||||
let layers = vec![];
|
let layers = vec![];
|
||||||
|
|
||||||
log::debug!("Instance exts for runtime: {:?}", &vk_instance_extensions);
|
log::debug!("Instance exts for runtime: {:?}", &vk_instance_extensions);
|
||||||
@@ -424,7 +430,7 @@ impl WlxGraphics {
|
|||||||
);
|
);
|
||||||
for (ext, missing) in p.supported_extensions().difference(&my_extensions) {
|
for (ext, missing) in p.supported_extensions().difference(&my_extensions) {
|
||||||
if missing {
|
if missing {
|
||||||
log::debug!(" {}", ext);
|
log::debug!(" {ext}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return None;
|
return None;
|
||||||
@@ -514,7 +520,7 @@ impl WlxGraphics {
|
|||||||
));
|
));
|
||||||
let descriptor_set_allocator = Arc::new(StandardDescriptorSetAllocator::new(
|
let descriptor_set_allocator = Arc::new(StandardDescriptorSetAllocator::new(
|
||||||
device.clone(),
|
device.clone(),
|
||||||
Default::default(),
|
StandardDescriptorSetAllocatorCreateInfo::default(),
|
||||||
));
|
));
|
||||||
|
|
||||||
let (quad_verts, quad_indices) = Self::default_quad(memory_allocator.clone())?;
|
let (quad_verts, quad_indices) = Self::default_quad(memory_allocator.clone())?;
|
||||||
@@ -536,8 +542,8 @@ impl WlxGraphics {
|
|||||||
Ok(Arc::new(me))
|
Ok(Arc::new(me))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::type_complexity)]
|
|
||||||
#[cfg(feature = "uidev")]
|
#[cfg(feature = "uidev")]
|
||||||
|
#[allow(clippy::type_complexity, clippy::too_many_lines)]
|
||||||
pub fn new_window() -> anyhow::Result<(
|
pub fn new_window() -> anyhow::Result<(
|
||||||
Arc<Self>,
|
Arc<Self>,
|
||||||
winit::event_loop::EventLoop<()>,
|
winit::event_loop::EventLoop<()>,
|
||||||
@@ -545,7 +551,10 @@ impl WlxGraphics {
|
|||||||
Arc<vulkano::swapchain::Surface>,
|
Arc<vulkano::swapchain::Surface>,
|
||||||
)> {
|
)> {
|
||||||
use vulkano::{
|
use vulkano::{
|
||||||
device::physical::PhysicalDeviceType, instance::InstanceCreateFlags, swapchain::Surface,
|
descriptor_set::allocator::StandardDescriptorSetAllocatorCreateInfo,
|
||||||
|
device::physical::PhysicalDeviceType,
|
||||||
|
instance::InstanceCreateFlags,
|
||||||
|
swapchain::{Surface, SurfaceInfo},
|
||||||
};
|
};
|
||||||
use winit::{event_loop::EventLoop, window::Window};
|
use winit::{event_loop::EventLoop, window::Window};
|
||||||
|
|
||||||
@@ -588,7 +597,7 @@ impl WlxGraphics {
|
|||||||
);
|
);
|
||||||
for (ext, missing) in p.supported_extensions().difference(&device_extensions) {
|
for (ext, missing) in p.supported_extensions().difference(&device_extensions) {
|
||||||
if missing {
|
if missing {
|
||||||
log::debug!(" {}", ext);
|
log::debug!(" {ext}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
@@ -635,10 +644,10 @@ impl WlxGraphics {
|
|||||||
|
|
||||||
let native_format = device
|
let native_format = device
|
||||||
.physical_device()
|
.physical_device()
|
||||||
.surface_formats(&surface, Default::default())
|
.surface_formats(&surface, SurfaceInfo::default())
|
||||||
.unwrap()[0] // want panic
|
.unwrap()[0] // want panic
|
||||||
.0;
|
.0;
|
||||||
log::info!("Using surface format: {:?}", native_format);
|
log::info!("Using surface format: {native_format:?}");
|
||||||
|
|
||||||
let queue = queues
|
let queue = queues
|
||||||
.next()
|
.next()
|
||||||
@@ -654,7 +663,7 @@ impl WlxGraphics {
|
|||||||
));
|
));
|
||||||
let descriptor_set_allocator = Arc::new(StandardDescriptorSetAllocator::new(
|
let descriptor_set_allocator = Arc::new(StandardDescriptorSetAllocator::new(
|
||||||
device.clone(),
|
device.clone(),
|
||||||
Default::default(),
|
StandardDescriptorSetAllocatorCreateInfo::default(),
|
||||||
));
|
));
|
||||||
|
|
||||||
let (quad_verts, quad_indices) = Self::default_quad(memory_allocator.clone())?;
|
let (quad_verts, quad_indices) = Self::default_quad(memory_allocator.clone())?;
|
||||||
@@ -721,7 +730,7 @@ impl WlxGraphics {
|
|||||||
| MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
|
| MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
INDICES.iter().cloned(),
|
INDICES.iter().copied(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok((quad_verts, quad_indices))
|
Ok((quad_verts, quad_indices))
|
||||||
@@ -874,7 +883,7 @@ impl WlxGraphics {
|
|||||||
(0..frame.num_planes).for_each(|i| {
|
(0..frame.num_planes).for_each(|i| {
|
||||||
let plane = &frame.planes[i];
|
let plane = &frame.planes[i];
|
||||||
layouts.push(SubresourceLayout {
|
layouts.push(SubresourceLayout {
|
||||||
offset: plane.offset as _,
|
offset: plane.offset.into(),
|
||||||
size: 0,
|
size: 0,
|
||||||
row_pitch: plane.stride as _,
|
row_pitch: plane.stride as _,
|
||||||
array_pitch: None,
|
array_pitch: None,
|
||||||
@@ -883,7 +892,7 @@ impl WlxGraphics {
|
|||||||
modifiers.push(frame.format.modifier);
|
modifiers.push(frame.format.modifier);
|
||||||
});
|
});
|
||||||
tiling = ImageTiling::DrmFormatModifier;
|
tiling = ImageTiling::DrmFormatModifier;
|
||||||
};
|
}
|
||||||
|
|
||||||
self.dmabuf_texture_ex(frame, tiling, layouts, &modifiers)
|
self.dmabuf_texture_ex(frame, tiling, layouts, &modifiers)
|
||||||
}
|
}
|
||||||
@@ -1023,7 +1032,7 @@ impl WlxCommandBuffer {
|
|||||||
load_op: AttachmentLoadOp::Clear,
|
load_op: AttachmentLoadOp::Clear,
|
||||||
store_op: AttachmentStoreOp::Store,
|
store_op: AttachmentStoreOp::Store,
|
||||||
clear_value: Some([0.0, 0.0, 0.0, 0.0].into()),
|
clear_value: Some([0.0, 0.0, 0.0, 0.0].into()),
|
||||||
..RenderingAttachmentInfo::image_view(render_target.clone())
|
..RenderingAttachmentInfo::image_view(render_target)
|
||||||
})],
|
})],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})?;
|
})?;
|
||||||
@@ -1157,7 +1166,7 @@ impl WlxPipeline {
|
|||||||
}],
|
}],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
dynamic_state: [DynamicState::Viewport].into_iter().collect(),
|
dynamic_state: std::iter::once(DynamicState::Viewport).collect(),
|
||||||
subpass: Some(subpass.into()),
|
subpass: Some(subpass.into()),
|
||||||
..GraphicsPipelineCreateInfo::layout(layout)
|
..GraphicsPipelineCreateInfo::layout(layout)
|
||||||
},
|
},
|
||||||
@@ -1279,7 +1288,7 @@ impl WlxPass {
|
|||||||
extent: dimensions,
|
extent: dimensions,
|
||||||
depth_range: 0.0..=1.0,
|
depth_range: 0.0..=1.0,
|
||||||
};
|
};
|
||||||
let pipeline_inner = pipeline.inner().clone();
|
let pipeline_inner = pipeline.inner();
|
||||||
let mut command_buffer = RecordingCommandBuffer::new(
|
let mut command_buffer = RecordingCommandBuffer::new(
|
||||||
pipeline.graphics.command_buffer_allocator.clone(),
|
pipeline.graphics.command_buffer_allocator.clone(),
|
||||||
pipeline.graphics.queue.queue_family_index(),
|
pipeline.graphics.queue.queue_family_index(),
|
||||||
@@ -1307,9 +1316,9 @@ impl WlxPass {
|
|||||||
PipelineBindPoint::Graphics,
|
PipelineBindPoint::Graphics,
|
||||||
pipeline.inner().layout().clone(),
|
pipeline.inner().layout().clone(),
|
||||||
0,
|
0,
|
||||||
descriptor_sets.clone(),
|
descriptor_sets,
|
||||||
)?
|
)?
|
||||||
.bind_vertex_buffers(0, vertex_buffer.clone())?
|
.bind_vertex_buffers(0, vertex_buffer)?
|
||||||
.bind_index_buffer(index_buffer.clone())?
|
.bind_index_buffer(index_buffer.clone())?
|
||||||
.draw_indexed(index_buffer.len() as u32, 1, 0, 0, 0)?
|
.draw_indexed(index_buffer.len() as u32, 1, 0, 0, 0)?
|
||||||
};
|
};
|
||||||
@@ -1335,7 +1344,7 @@ impl CommandBuffers {
|
|||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
|
|
||||||
let future = first.execute(queue.clone())?;
|
let future = first.execute(queue)?;
|
||||||
let mut future: Box<dyn GpuFuture> = Box::new(future);
|
let mut future: Box<dyn GpuFuture> = Box::new(future);
|
||||||
|
|
||||||
for buf in buffers {
|
for buf in buffers {
|
||||||
@@ -1368,12 +1377,9 @@ impl CommandBuffers {
|
|||||||
|
|
||||||
pub fn fourcc_to_vk(fourcc: FourCC) -> anyhow::Result<Format> {
|
pub fn fourcc_to_vk(fourcc: FourCC) -> anyhow::Result<Format> {
|
||||||
match fourcc.value {
|
match fourcc.value {
|
||||||
DRM_FORMAT_ABGR8888 => Ok(Format::R8G8B8A8_UNORM),
|
DRM_FORMAT_ABGR8888 | DRM_FORMAT_XBGR8888 => Ok(Format::R8G8B8A8_UNORM),
|
||||||
DRM_FORMAT_XBGR8888 => Ok(Format::R8G8B8A8_UNORM),
|
DRM_FORMAT_ARGB8888 | DRM_FORMAT_XRGB8888 => Ok(Format::B8G8R8A8_UNORM),
|
||||||
DRM_FORMAT_ARGB8888 => Ok(Format::B8G8R8A8_UNORM),
|
DRM_FORMAT_ABGR2101010 | DRM_FORMAT_XBGR2101010 => Ok(Format::A2B10G10R10_UNORM_PACK32),
|
||||||
DRM_FORMAT_XRGB8888 => Ok(Format::B8G8R8A8_UNORM),
|
|
||||||
DRM_FORMAT_ABGR2101010 => Ok(Format::A2B10G10R10_UNORM_PACK32),
|
|
||||||
DRM_FORMAT_XBGR2101010 => Ok(Format::A2B10G10R10_UNORM_PACK32),
|
|
||||||
_ => bail!("Unsupported format {}", fourcc),
|
_ => bail!("Unsupported format {}", fourcc),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ impl<D, S> CanvasBuilder<D, S> {
|
|||||||
h,
|
h,
|
||||||
};
|
};
|
||||||
let rect1 = Rect {
|
let rect1 = Rect {
|
||||||
x: x + w * 0.5 + 12.,
|
x: w.mul_add(0.5, x) + 12.,
|
||||||
y: y + h - (self.font_size as f32) + 8.,
|
y: y + h - (self.font_size as f32) + 8.,
|
||||||
w,
|
w,
|
||||||
h,
|
h,
|
||||||
@@ -213,7 +213,7 @@ impl<D, S> CanvasBuilder<D, S> {
|
|||||||
};
|
};
|
||||||
let rect1 = Rect {
|
let rect1 = Rect {
|
||||||
x,
|
x,
|
||||||
y: y + h * 0.5 + 2.0,
|
y: h.mul_add(0.5, y) + 2.0,
|
||||||
w,
|
w,
|
||||||
h: h * 0.5,
|
h: h * 0.5,
|
||||||
};
|
};
|
||||||
@@ -234,7 +234,7 @@ impl<D, S> CanvasBuilder<D, S> {
|
|||||||
h,
|
h,
|
||||||
};
|
};
|
||||||
let rect2 = Rect {
|
let rect2 = Rect {
|
||||||
x: x + w * 0.5 + 8.,
|
x: w.mul_add(0.5, x) + 8.,
|
||||||
y: y + h - (self.font_size as f32) + 4.,
|
y: y + h - (self.font_size as f32) + 4.,
|
||||||
w,
|
w,
|
||||||
h,
|
h,
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ pub type ControlRendererHl<D, S> = fn(
|
|||||||
) -> anyhow::Result<()>;
|
) -> anyhow::Result<()>;
|
||||||
|
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
pub(crate) struct Control<D, S> {
|
pub struct Control<D, S> {
|
||||||
pub state: Option<S>,
|
pub state: Option<S>,
|
||||||
pub rect: Rect,
|
pub rect: Rect,
|
||||||
pub corner_radius: f32,
|
pub corner_radius: f32,
|
||||||
@@ -74,7 +74,6 @@ impl<D, S> Control<D, S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn set_text(&mut self, text: &str) {
|
pub fn set_text(&mut self, text: &str) {
|
||||||
if *self.text == *text {
|
if *self.text == *text {
|
||||||
return;
|
return;
|
||||||
@@ -83,13 +82,11 @@ impl<D, S> Control<D, S> {
|
|||||||
self.fg_dirty = true;
|
self.fg_dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn set_sprite(&mut self, sprite: Arc<ImageView>) {
|
pub fn set_sprite(&mut self, sprite: Arc<ImageView>) {
|
||||||
self.sprite.replace(sprite);
|
self.sprite.replace(sprite);
|
||||||
self.bg_dirty = true;
|
self.bg_dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn set_sprite_st(&mut self, sprite_st: Vec4) {
|
pub fn set_sprite_st(&mut self, sprite_st: Vec4) {
|
||||||
if self.sprite_st == sprite_st {
|
if self.sprite_st == sprite_st {
|
||||||
return;
|
return;
|
||||||
@@ -98,7 +95,6 @@ impl<D, S> Control<D, S> {
|
|||||||
self.bg_dirty = true;
|
self.bg_dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn set_fg_color(&mut self, color: GuiColor) {
|
pub fn set_fg_color(&mut self, color: GuiColor) {
|
||||||
if self.fg_color == color {
|
if self.fg_color == color {
|
||||||
return;
|
return;
|
||||||
@@ -190,7 +186,7 @@ impl<D, S> Control<D, S> {
|
|||||||
|
|
||||||
let pass = canvas.pipeline_hl_color.create_pass(
|
let pass = canvas.pipeline_hl_color.create_pass(
|
||||||
[canvas.width as _, canvas.height as _],
|
[canvas.width as _, canvas.height as _],
|
||||||
vertex_buffer.clone(),
|
vertex_buffer,
|
||||||
canvas.graphics.quad_indices.clone(),
|
canvas.graphics.quad_indices.clone(),
|
||||||
vec![set0],
|
vec![set0],
|
||||||
)?;
|
)?;
|
||||||
@@ -253,9 +249,10 @@ impl<D, S> Control<D, S> {
|
|||||||
.fc
|
.fc
|
||||||
.get_text_size(&self.text, self.size, canvas.graphics.clone())?;
|
.get_text_size(&self.text, self.size, canvas.graphics.clone())?;
|
||||||
|
|
||||||
let mut cur_y = self.rect.y + (self.rect.h) - (h * 0.5) - (self.size as f32 * 0.25);
|
let mut cur_y =
|
||||||
|
(self.size as f32).mul_add(-0.25, h.mul_add(-0.5, self.rect.y + (self.rect.h)));
|
||||||
for line in self.text.lines() {
|
for line in self.text.lines() {
|
||||||
let mut cur_x = self.rect.x + (self.rect.w * 0.5) - (w * 0.5);
|
let mut cur_x = w.mul_add(-0.5, self.rect.w.mul_add(0.5, self.rect.x));
|
||||||
for glyph in app
|
for glyph in app
|
||||||
.fc
|
.fc
|
||||||
.get_glyphs(line, self.size, canvas.graphics.clone())?
|
.get_glyphs(line, self.size, canvas.graphics.clone())?
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
pub(crate) mod builder;
|
pub mod builder;
|
||||||
pub(crate) mod control;
|
pub mod control;
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ pub struct CanvasData<D> {
|
|||||||
|
|
||||||
pub struct Canvas<D, S> {
|
pub struct Canvas<D, S> {
|
||||||
controls: Vec<control::Control<D, S>>,
|
controls: Vec<control::Control<D, S>>,
|
||||||
canvas: CanvasData<D>,
|
data: CanvasData<D>,
|
||||||
|
|
||||||
hover_controls: [Option<usize>; 2],
|
hover_controls: [Option<usize>; 2],
|
||||||
pressed_controls: [Option<usize>; 2],
|
pressed_controls: [Option<usize>; 2],
|
||||||
@@ -51,14 +51,14 @@ pub struct Canvas<D, S> {
|
|||||||
|
|
||||||
pipeline_final: Arc<WlxPipeline>,
|
pipeline_final: Arc<WlxPipeline>,
|
||||||
|
|
||||||
view_fg: Arc<ImageView>,
|
view_fore: Arc<ImageView>,
|
||||||
view_bg: Arc<ImageView>,
|
view_back: Arc<ImageView>,
|
||||||
|
|
||||||
format: Format,
|
format: Format,
|
||||||
|
|
||||||
bg_dirty: bool,
|
back_dirty: bool,
|
||||||
hl_dirty: bool,
|
high_dirty: bool,
|
||||||
fg_dirty: bool,
|
fore_dirty: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D, S> Canvas<D, S> {
|
impl<D, S> Canvas<D, S> {
|
||||||
@@ -69,11 +69,11 @@ impl<D, S> Canvas<D, S> {
|
|||||||
format: Format,
|
format: Format,
|
||||||
data: D,
|
data: D,
|
||||||
) -> anyhow::Result<Self> {
|
) -> anyhow::Result<Self> {
|
||||||
let tex_fg = graphics.render_texture(width as _, height as _, format)?;
|
let tex_fore = graphics.render_texture(width as _, height as _, format)?;
|
||||||
let tex_bg = graphics.render_texture(width as _, height as _, format)?;
|
let tex_back = graphics.render_texture(width as _, height as _, format)?;
|
||||||
|
|
||||||
let view_fg = ImageView::new_default(tex_fg.clone())?;
|
let view_fore = ImageView::new_default(tex_fore)?;
|
||||||
let view_bg = ImageView::new_default(tex_bg.clone())?;
|
let view_back = ImageView::new_default(tex_back)?;
|
||||||
|
|
||||||
let Ok(shaders) = graphics.shared_shaders.read() else {
|
let Ok(shaders) = graphics.shared_shaders.read() else {
|
||||||
anyhow::bail!("Failed to lock shared shaders for reading");
|
anyhow::bail!("Failed to lock shared shaders for reading");
|
||||||
@@ -117,7 +117,7 @@ impl<D, S> Canvas<D, S> {
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
let pipeline_final = graphics.create_pipeline(
|
let pipeline_final = graphics.create_pipeline(
|
||||||
vert.clone(),
|
vert,
|
||||||
shaders.get("frag_srgb").unwrap().clone(), // want panic
|
shaders.get("frag_srgb").unwrap().clone(), // want panic
|
||||||
SWAPCHAIN_FORMAT,
|
SWAPCHAIN_FORMAT,
|
||||||
Some(BLEND_ALPHA),
|
Some(BLEND_ALPHA),
|
||||||
@@ -127,7 +127,7 @@ impl<D, S> Canvas<D, S> {
|
|||||||
let rows = height / RES_DIVIDER;
|
let rows = height / RES_DIVIDER;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
canvas: CanvasData {
|
data: CanvasData {
|
||||||
data,
|
data,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
@@ -145,12 +145,12 @@ impl<D, S> Canvas<D, S> {
|
|||||||
interact_stride: stride,
|
interact_stride: stride,
|
||||||
interact_rows: rows,
|
interact_rows: rows,
|
||||||
pipeline_final,
|
pipeline_final,
|
||||||
view_fg,
|
view_fore,
|
||||||
view_bg,
|
view_back,
|
||||||
format,
|
format,
|
||||||
bg_dirty: false,
|
back_dirty: false,
|
||||||
hl_dirty: false,
|
high_dirty: false,
|
||||||
fg_dirty: false,
|
fore_dirty: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,27 +170,27 @@ impl<D, S> Canvas<D, S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn interactive_get_idx(&self, uv: Vec2) -> Option<usize> {
|
fn interactive_get_idx(&self, uv: Vec2) -> Option<usize> {
|
||||||
let x = (uv.x * self.canvas.width as f32) as usize;
|
let x = (uv.x * self.data.width as f32) as usize;
|
||||||
let y = (uv.y * self.canvas.height as f32) as usize;
|
let y = (uv.y * self.data.height as f32) as usize;
|
||||||
let x = (x / RES_DIVIDER).max(0).min(self.interact_stride - 1);
|
let x = (x / RES_DIVIDER).max(0).min(self.interact_stride - 1);
|
||||||
let y = (y / RES_DIVIDER).max(0).min(self.interact_rows - 1);
|
let y = (y / RES_DIVIDER).max(0).min(self.interact_rows - 1);
|
||||||
self.interact_map[y * self.interact_stride + x].map(|x| x as usize)
|
self.interact_map[y * self.interact_stride + x].map(|x| x as usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn data_mut(&mut self) -> &mut D {
|
pub const fn data_mut(&mut self) -> &mut D {
|
||||||
&mut self.canvas.data
|
&mut self.data.data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D, S> InteractionHandler for Canvas<D, S> {
|
impl<D, S> InteractionHandler for Canvas<D, S> {
|
||||||
fn on_left(&mut self, _app: &mut AppState, pointer: usize) {
|
fn on_left(&mut self, _app: &mut AppState, pointer: usize) {
|
||||||
self.hl_dirty = true;
|
self.high_dirty = true;
|
||||||
|
|
||||||
self.hover_controls[pointer] = None;
|
self.hover_controls[pointer] = None;
|
||||||
}
|
}
|
||||||
fn on_hover(&mut self, _app: &mut AppState, hit: &PointerHit) -> Option<Haptics> {
|
fn on_hover(&mut self, _app: &mut AppState, hit: &PointerHit) -> Option<Haptics> {
|
||||||
// render on every frame if we are being hovered
|
// render on every frame if we are being hovered
|
||||||
self.hl_dirty = true;
|
self.high_dirty = true;
|
||||||
|
|
||||||
let old = self.hover_controls[hit.pointer];
|
let old = self.hover_controls[hit.pointer];
|
||||||
if let Some(i) = self.interactive_get_idx(hit.uv) {
|
if let Some(i) = self.interactive_get_idx(hit.uv) {
|
||||||
@@ -198,14 +198,14 @@ impl<D, S> InteractionHandler for Canvas<D, S> {
|
|||||||
} else {
|
} else {
|
||||||
self.hover_controls[hit.pointer] = None;
|
self.hover_controls[hit.pointer] = None;
|
||||||
}
|
}
|
||||||
if old != self.hover_controls[hit.pointer] {
|
if old == self.hover_controls[hit.pointer] {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
Some(Haptics {
|
Some(Haptics {
|
||||||
intensity: 0.1,
|
intensity: 0.1,
|
||||||
duration: 0.01,
|
duration: 0.01,
|
||||||
frequency: 5.0,
|
frequency: 5.0,
|
||||||
})
|
})
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn on_pointer(&mut self, app: &mut AppState, hit: &PointerHit, pressed: bool) {
|
fn on_pointer(&mut self, app: &mut AppState, hit: &PointerHit, pressed: bool) {
|
||||||
@@ -220,11 +220,11 @@ impl<D, S> InteractionHandler for Canvas<D, S> {
|
|||||||
if pressed {
|
if pressed {
|
||||||
if let Some(ref mut f) = c.on_press {
|
if let Some(ref mut f) = c.on_press {
|
||||||
self.pressed_controls[hit.pointer] = Some(idx);
|
self.pressed_controls[hit.pointer] = Some(idx);
|
||||||
f(c, &mut self.canvas.data, app, hit.mode);
|
f(c, &mut self.data.data, app, hit.mode);
|
||||||
}
|
}
|
||||||
} else if let Some(ref mut f) = c.on_release {
|
} else if let Some(ref mut f) = c.on_release {
|
||||||
self.pressed_controls[hit.pointer] = None;
|
self.pressed_controls[hit.pointer] = None;
|
||||||
f(c, &mut self.canvas.data, app);
|
f(c, &mut self.data.data, app);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -234,7 +234,7 @@ impl<D, S> InteractionHandler for Canvas<D, S> {
|
|||||||
if let Some(idx) = idx {
|
if let Some(idx) = idx {
|
||||||
let c = &mut self.controls[idx];
|
let c = &mut self.controls[idx];
|
||||||
if let Some(ref mut f) = c.on_scroll {
|
if let Some(ref mut f) = c.on_scroll {
|
||||||
f(c, &mut self.canvas.data, app, delta_y, delta_x);
|
f(c, &mut self.data.data, app, delta_y, delta_x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -251,21 +251,21 @@ impl<D, S> OverlayRenderer for Canvas<D, S> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn should_render(&mut self, app: &mut AppState) -> anyhow::Result<ShouldRender> {
|
fn should_render(&mut self, app: &mut AppState) -> anyhow::Result<ShouldRender> {
|
||||||
for c in self.controls.iter_mut() {
|
for c in &mut self.controls {
|
||||||
if let Some(fun) = c.on_update {
|
if let Some(fun) = c.on_update {
|
||||||
fun(c, &mut self.canvas.data, app);
|
fun(c, &mut self.data.data, app);
|
||||||
}
|
}
|
||||||
if c.fg_dirty {
|
if c.fg_dirty {
|
||||||
self.fg_dirty = true;
|
self.fore_dirty = true;
|
||||||
c.fg_dirty = false;
|
c.fg_dirty = false;
|
||||||
}
|
}
|
||||||
if c.bg_dirty {
|
if c.bg_dirty {
|
||||||
self.bg_dirty = true;
|
self.back_dirty = true;
|
||||||
c.bg_dirty = false;
|
c.bg_dirty = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.bg_dirty || self.fg_dirty || self.hl_dirty {
|
if self.back_dirty || self.fore_dirty || self.high_dirty {
|
||||||
Ok(ShouldRender::Should)
|
Ok(ShouldRender::Should)
|
||||||
} else {
|
} else {
|
||||||
Ok(ShouldRender::Can)
|
Ok(ShouldRender::Can)
|
||||||
@@ -278,68 +278,68 @@ impl<D, S> OverlayRenderer for Canvas<D, S> {
|
|||||||
buf: &mut CommandBuffers,
|
buf: &mut CommandBuffers,
|
||||||
alpha: f32,
|
alpha: f32,
|
||||||
) -> anyhow::Result<bool> {
|
) -> anyhow::Result<bool> {
|
||||||
self.hl_dirty = false;
|
self.high_dirty = false;
|
||||||
|
|
||||||
let mut cmd_buffer = self
|
let mut cmd_buffer = self
|
||||||
.canvas
|
.data
|
||||||
.graphics
|
.graphics
|
||||||
.create_command_buffer(CommandBufferUsage::OneTimeSubmit)?;
|
.create_command_buffer(CommandBufferUsage::OneTimeSubmit)?;
|
||||||
|
|
||||||
if self.bg_dirty {
|
if self.back_dirty {
|
||||||
cmd_buffer.begin_rendering(self.view_bg.clone())?;
|
cmd_buffer.begin_rendering(self.view_back.clone())?;
|
||||||
for c in self.controls.iter_mut() {
|
for c in &mut self.controls {
|
||||||
if let Some(fun) = c.on_render_bg {
|
if let Some(fun) = c.on_render_bg {
|
||||||
fun(c, &self.canvas, app, &mut cmd_buffer)?;
|
fun(c, &self.data, app, &mut cmd_buffer)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cmd_buffer.end_rendering()?;
|
cmd_buffer.end_rendering()?;
|
||||||
self.bg_dirty = false;
|
self.back_dirty = false;
|
||||||
}
|
}
|
||||||
if self.fg_dirty {
|
if self.fore_dirty {
|
||||||
cmd_buffer.begin_rendering(self.view_fg.clone())?;
|
cmd_buffer.begin_rendering(self.view_fore.clone())?;
|
||||||
for c in self.controls.iter_mut() {
|
for c in &mut self.controls {
|
||||||
if let Some(fun) = c.on_render_fg {
|
if let Some(fun) = c.on_render_fg {
|
||||||
fun(c, &self.canvas, app, &mut cmd_buffer)?;
|
fun(c, &self.data, app, &mut cmd_buffer)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cmd_buffer.end_rendering()?;
|
cmd_buffer.end_rendering()?;
|
||||||
self.fg_dirty = false;
|
self.fore_dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let set0_fg = self.pipeline_final.uniform_sampler(
|
let set0_fg = self.pipeline_final.uniform_sampler(
|
||||||
0,
|
0,
|
||||||
self.view_fg.clone(),
|
self.view_fore.clone(),
|
||||||
app.graphics.texture_filtering,
|
app.graphics.texture_filtering,
|
||||||
)?;
|
)?;
|
||||||
let set0_bg = self.pipeline_final.uniform_sampler(
|
let set0_bg = self.pipeline_final.uniform_sampler(
|
||||||
0,
|
0,
|
||||||
self.view_bg.clone(),
|
self.view_back.clone(),
|
||||||
app.graphics.texture_filtering,
|
app.graphics.texture_filtering,
|
||||||
)?;
|
)?;
|
||||||
let set1 = self.pipeline_final.uniform_buffer(1, vec![alpha])?;
|
let set1 = self.pipeline_final.uniform_buffer(1, vec![alpha])?;
|
||||||
|
|
||||||
let pass_fg = self
|
let pass_fore = self
|
||||||
.pipeline_final
|
.pipeline_final
|
||||||
.create_pass_for_target(tgt.clone(), vec![set0_fg, set1.clone()])?;
|
.create_pass_for_target(tgt.clone(), vec![set0_fg, set1.clone()])?;
|
||||||
|
|
||||||
let pass_bg = self
|
let pass_back = self
|
||||||
.pipeline_final
|
.pipeline_final
|
||||||
.create_pass_for_target(tgt.clone(), vec![set0_bg, set1])?;
|
.create_pass_for_target(tgt.clone(), vec![set0_bg, set1])?;
|
||||||
|
|
||||||
cmd_buffer.begin_rendering(tgt.clone())?;
|
cmd_buffer.begin_rendering(tgt)?;
|
||||||
cmd_buffer.run_ref(&pass_bg)?;
|
cmd_buffer.run_ref(&pass_back)?;
|
||||||
|
|
||||||
for (i, c) in self.controls.iter_mut().enumerate() {
|
for (i, c) in self.controls.iter_mut().enumerate() {
|
||||||
if let Some(render) = c.on_render_hl {
|
if let Some(render) = c.on_render_hl {
|
||||||
if let Some(test) = c.test_highlight {
|
if let Some(test) = c.test_highlight {
|
||||||
if let Some(hl_color) = test(c, &mut self.canvas.data, app) {
|
if let Some(hl_color) = test(c, &mut self.data.data, app) {
|
||||||
render(c, &self.canvas, app, &mut cmd_buffer, hl_color)?;
|
render(c, &self.data, app, &mut cmd_buffer, hl_color)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if self.hover_controls.contains(&Some(i)) {
|
if self.hover_controls.contains(&Some(i)) {
|
||||||
render(
|
render(
|
||||||
c,
|
c,
|
||||||
&self.canvas,
|
&self.data,
|
||||||
app,
|
app,
|
||||||
&mut cmd_buffer,
|
&mut cmd_buffer,
|
||||||
Vec4::new(1., 1., 1., 0.3),
|
Vec4::new(1., 1., 1., 0.3),
|
||||||
@@ -349,7 +349,7 @@ impl<D, S> OverlayRenderer for Canvas<D, S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// mostly static text
|
// mostly static text
|
||||||
cmd_buffer.run_ref(&pass_fg)?;
|
cmd_buffer.run_ref(&pass_fore)?;
|
||||||
|
|
||||||
cmd_buffer.end_rendering()?;
|
cmd_buffer.end_rendering()?;
|
||||||
buf.push(cmd_buffer.build()?);
|
buf.push(cmd_buffer.build()?);
|
||||||
@@ -358,7 +358,7 @@ impl<D, S> OverlayRenderer for Canvas<D, S> {
|
|||||||
|
|
||||||
fn frame_meta(&mut self) -> Option<FrameMeta> {
|
fn frame_meta(&mut self) -> Option<FrameMeta> {
|
||||||
Some(FrameMeta {
|
Some(FrameMeta {
|
||||||
extent: [self.canvas.width as _, self.canvas.height as _, 1],
|
extent: [self.data.width as _, self.data.height as _, 1],
|
||||||
format: self.format,
|
format: self.format,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ impl FontCache {
|
|||||||
let ft = Library::init()?;
|
let ft = Library::init()?;
|
||||||
let fc = FontConfig::default();
|
let fc = FontConfig::default();
|
||||||
|
|
||||||
Ok(FontCache {
|
Ok(Self {
|
||||||
primary_font,
|
primary_font,
|
||||||
fc,
|
fc,
|
||||||
ft,
|
ft,
|
||||||
@@ -55,7 +55,7 @@ impl FontCache {
|
|||||||
) -> anyhow::Result<(f32, f32)> {
|
) -> anyhow::Result<(f32, f32)> {
|
||||||
let sizef = size as f32;
|
let sizef = size as f32;
|
||||||
|
|
||||||
let height = sizef + ((text.lines().count() as f32) - 1f32) * (sizef * 1.5);
|
let height = ((text.lines().count() as f32) - 1f32).mul_add(sizef * 1.5, sizef);
|
||||||
let mut cmd_buffer = None;
|
let mut cmd_buffer = None;
|
||||||
|
|
||||||
let mut max_w = sizef * 0.33;
|
let mut max_w = sizef * 0.33;
|
||||||
@@ -143,26 +143,26 @@ impl FontCache {
|
|||||||
|
|
||||||
if let Some(path) = pattern.filename() {
|
if let Some(path) = pattern.filename() {
|
||||||
let name = pattern.name().unwrap_or(path);
|
let name = pattern.name().unwrap_or(path);
|
||||||
log::debug!("Loading font: {} {}pt", name, size);
|
log::debug!("Loading font: {name} {size}pt");
|
||||||
|
|
||||||
let font_idx = pattern.face_index().unwrap_or(0);
|
let font_idx = pattern.face_index().unwrap_or(0);
|
||||||
|
|
||||||
let face = match self.ft.new_face(path, font_idx as _) {
|
let face = match self.ft.new_face(path, font_idx as _) {
|
||||||
Ok(face) => face,
|
Ok(face) => face,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::warn!("Failed to load font at {}: {:?}", path, e);
|
log::warn!("Failed to load font at {path}: {e:?}");
|
||||||
coll.cp_map.insert(cp, 0);
|
coll.cp_map.insert(cp, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
match face.set_char_size(size << 6, size << 6, 96, 96) {
|
match face.set_char_size(size << 6, size << 6, 96, 96) {
|
||||||
Ok(_) => {}
|
Ok(()) => {}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::warn!("Failed to set font size: {:?}", e);
|
log::warn!("Failed to set font size: {e:?}");
|
||||||
coll.cp_map.insert(cp, 0);
|
coll.cp_map.insert(cp, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
let idx = coll.fonts.len();
|
let idx = coll.fonts.len();
|
||||||
for (cp, _) in face.chars() {
|
for (cp, _) in face.chars() {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ pub mod font;
|
|||||||
pub mod modular;
|
pub mod modular;
|
||||||
|
|
||||||
pub type GuiColor = Vec4;
|
pub type GuiColor = Vec4;
|
||||||
pub(super) static FALLBACK_COLOR: Lazy<GuiColor> = Lazy::new(|| Vec4::new(1., 0., 1., 1.));
|
pub static FALLBACK_COLOR: Lazy<GuiColor> = Lazy::new(|| Vec4::new(1., 0., 1., 1.));
|
||||||
|
|
||||||
// Parses a color from a HTML hex string
|
// Parses a color from a HTML hex string
|
||||||
pub fn color_parse(html_hex: &str) -> anyhow::Result<GuiColor> {
|
pub fn color_parse(html_hex: &str) -> anyhow::Result<GuiColor> {
|
||||||
@@ -17,9 +17,9 @@ pub fn color_parse(html_hex: &str) -> anyhow::Result<GuiColor> {
|
|||||||
u8::from_str_radix(&html_hex[5..7], 16),
|
u8::from_str_radix(&html_hex[5..7], 16),
|
||||||
) {
|
) {
|
||||||
return Ok(Vec4::new(
|
return Ok(Vec4::new(
|
||||||
r as f32 / 255.,
|
f32::from(r) / 255.,
|
||||||
g as f32 / 255.,
|
f32::from(g) / 255.,
|
||||||
b as f32 / 255.,
|
f32::from(b) / 255.,
|
||||||
1.,
|
1.,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@@ -31,10 +31,10 @@ pub fn color_parse(html_hex: &str) -> anyhow::Result<GuiColor> {
|
|||||||
u8::from_str_radix(&html_hex[7..9], 16),
|
u8::from_str_radix(&html_hex[7..9], 16),
|
||||||
) {
|
) {
|
||||||
return Ok(Vec4::new(
|
return Ok(Vec4::new(
|
||||||
r as f32 / 255.,
|
f32::from(r) / 255.,
|
||||||
g as f32 / 255.,
|
f32::from(g) / 255.,
|
||||||
b as f32 / 255.,
|
f32::from(b) / 255.,
|
||||||
a as f32 / 255.,
|
f32::from(a) / 255.,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -379,7 +379,7 @@ fn modular_button_highlight(
|
|||||||
|
|
||||||
fn handle_action(action: &ButtonAction, press: &mut PressData, app: &mut AppState) {
|
fn handle_action(action: &ButtonAction, press: &mut PressData, app: &mut AppState) {
|
||||||
match action {
|
match action {
|
||||||
ButtonAction::Exec { command, toast } => run_exec(command, toast, press, app),
|
ButtonAction::Exec { command, toast } => run_exec(command, toast.clone(), press, app),
|
||||||
ButtonAction::Watch { action } => run_watch(action, app),
|
ButtonAction::Watch { action } => run_watch(action, app),
|
||||||
ButtonAction::Overlay { target, action } => run_overlay(target, action, app),
|
ButtonAction::Overlay { target, action } => run_overlay(target, action, app),
|
||||||
ButtonAction::Window { target, action } => run_window(target, action, app),
|
ButtonAction::Window { target, action } => run_window(target, action, app),
|
||||||
@@ -439,7 +439,7 @@ fn handle_action(action: &ButtonAction, press: &mut PressData, app: &mut AppStat
|
|||||||
|
|
||||||
let _ = sender.send_single_param(parameter.to_string(), converted);
|
let _ = sender.send_single_param(parameter.to_string(), converted);
|
||||||
audio_thump(app); // play sound for feedback
|
audio_thump(app); // play sound for feedback
|
||||||
};
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "osc"))]
|
#[cfg(not(feature = "osc"))]
|
||||||
{
|
{
|
||||||
@@ -453,6 +453,7 @@ fn handle_action(action: &ButtonAction, press: &mut PressData, app: &mut AppStat
|
|||||||
|
|
||||||
const ENABLED_DISABLED: [&str; 2] = ["enabled", "disabled"];
|
const ENABLED_DISABLED: [&str; 2] = ["enabled", "disabled"];
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_lines)]
|
||||||
fn run_system(action: &SystemAction, app: &mut AppState) {
|
fn run_system(action: &SystemAction, app: &mut AppState) {
|
||||||
match action {
|
match action {
|
||||||
SystemAction::ToggleAllowSliding => {
|
SystemAction::ToggleAllowSliding => {
|
||||||
@@ -461,7 +462,7 @@ fn run_system(action: &SystemAction, app: &mut AppState) {
|
|||||||
ToastTopic::System,
|
ToastTopic::System,
|
||||||
format!(
|
format!(
|
||||||
"Sliding is {}.",
|
"Sliding is {}.",
|
||||||
ENABLED_DISABLED[app.session.config.allow_sliding as usize]
|
ENABLED_DISABLED[usize::from(app.session.config.allow_sliding)]
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
"".into(),
|
"".into(),
|
||||||
@@ -474,7 +475,7 @@ fn run_system(action: &SystemAction, app: &mut AppState) {
|
|||||||
ToastTopic::System,
|
ToastTopic::System,
|
||||||
format!(
|
format!(
|
||||||
"Auto realign is {}.",
|
"Auto realign is {}.",
|
||||||
ENABLED_DISABLED[app.session.config.realign_on_showhide as usize]
|
ENABLED_DISABLED[usize::from(app.session.config.realign_on_showhide)]
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
"".into(),
|
"".into(),
|
||||||
@@ -487,7 +488,7 @@ fn run_system(action: &SystemAction, app: &mut AppState) {
|
|||||||
ToastTopic::System,
|
ToastTopic::System,
|
||||||
format!(
|
format!(
|
||||||
"Space rotate axis lock now {}.",
|
"Space rotate axis lock now {}.",
|
||||||
ENABLED_DISABLED[!app.session.config.space_rotate_unlocked as usize]
|
ENABLED_DISABLED[usize::from(!app.session.config.space_rotate_unlocked)]
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
"".into(),
|
"".into(),
|
||||||
@@ -506,7 +507,7 @@ fn run_system(action: &SystemAction, app: &mut AppState) {
|
|||||||
let display = 5 - i;
|
let display = 5 - i;
|
||||||
Toast::new(
|
Toast::new(
|
||||||
ToastTopic::System,
|
ToastTopic::System,
|
||||||
format!("Fixing floor in {}", display).into(),
|
format!("Fixing floor in {display}").into(),
|
||||||
"Place either controller on the floor.".into(),
|
"Place either controller on the floor.".into(),
|
||||||
)
|
)
|
||||||
.with_timeout(1.0)
|
.with_timeout(1.0)
|
||||||
@@ -524,7 +525,7 @@ fn run_system(action: &SystemAction, app: &mut AppState) {
|
|||||||
ToastTopic::System,
|
ToastTopic::System,
|
||||||
format!(
|
format!(
|
||||||
"Notifications are {}.",
|
"Notifications are {}.",
|
||||||
ENABLED_DISABLED[app.session.config.notifications_enabled as usize]
|
ENABLED_DISABLED[usize::from(app.session.config.notifications_enabled)]
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
"".into(),
|
"".into(),
|
||||||
@@ -538,7 +539,7 @@ fn run_system(action: &SystemAction, app: &mut AppState) {
|
|||||||
ToastTopic::System,
|
ToastTopic::System,
|
||||||
format!(
|
format!(
|
||||||
"Notification sounds are {}.",
|
"Notification sounds are {}.",
|
||||||
ENABLED_DISABLED[app.session.config.notifications_sound_enabled as usize]
|
ENABLED_DISABLED[usize::from(app.session.config.notifications_sound_enabled)]
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
"".into(),
|
"".into(),
|
||||||
@@ -558,7 +559,7 @@ fn run_system(action: &SystemAction, app: &mut AppState) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_exec(args: &ExecArgs, toast: &Option<Arc<str>>, press: &mut PressData, app: &mut AppState) {
|
fn run_exec(args: &ExecArgs, toast: Option<Arc<str>>, press: &mut PressData, app: &mut AppState) {
|
||||||
if let Some(proc) = press.child.as_mut() {
|
if let Some(proc) = press.child.as_mut() {
|
||||||
match proc.try_wait() {
|
match proc.try_wait() {
|
||||||
Ok(Some(code)) => {
|
Ok(Some(code)) => {
|
||||||
@@ -577,7 +578,10 @@ fn run_exec(args: &ExecArgs, toast: &Option<Arc<str>>, press: &mut PressData, ap
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let args = args.iter().map(|s| s.as_ref()).collect::<Vec<&str>>();
|
let args = args
|
||||||
|
.iter()
|
||||||
|
.map(std::convert::AsRef::as_ref)
|
||||||
|
.collect::<Vec<&str>>();
|
||||||
match process::Command::new(args[0]).args(&args[1..]).spawn() {
|
match process::Command::new(args[0]).args(&args[1..]).spawn() {
|
||||||
Ok(proc) => {
|
Ok(proc) => {
|
||||||
press.child = Some(proc);
|
press.child = Some(proc);
|
||||||
@@ -586,11 +590,12 @@ fn run_exec(args: &ExecArgs, toast: &Option<Arc<str>>, press: &mut PressData, ap
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error_toast(app, &format!("Failed to spawn process {:?}", args), e);
|
error_toast(app, &format!("Failed to spawn process {args:?}"), e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_lines)]
|
||||||
fn run_watch(data: &WatchAction, app: &mut AppState) {
|
fn run_watch(data: &WatchAction, app: &mut AppState) {
|
||||||
match data {
|
match data {
|
||||||
WatchAction::Hide => {
|
WatchAction::Hide => {
|
||||||
@@ -621,7 +626,7 @@ fn run_watch(data: &WatchAction, app: &mut AppState) {
|
|||||||
app.tasks.enqueue(TaskType::Overlay(
|
app.tasks.enqueue(TaskType::Overlay(
|
||||||
OverlaySelector::Name(WATCH_NAME.into()),
|
OverlaySelector::Name(WATCH_NAME.into()),
|
||||||
Box::new(|app, o| {
|
Box::new(|app, o| {
|
||||||
if let RelativeTo::Hand(0) = o.relative_to {
|
if matches!(o.relative_to, RelativeTo::Hand(0)) {
|
||||||
o.relative_to = RelativeTo::Hand(1);
|
o.relative_to = RelativeTo::Hand(1);
|
||||||
o.spawn_rotation = app.session.config.watch_rot
|
o.spawn_rotation = app.session.config.watch_rot
|
||||||
* Quat::from_rotation_x(PI)
|
* Quat::from_rotation_x(PI)
|
||||||
@@ -701,6 +706,7 @@ fn run_watch(data: &WatchAction, app: &mut AppState) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_lines)]
|
||||||
fn run_overlay(overlay: &OverlaySelector, action: &OverlayAction, app: &mut AppState) {
|
fn run_overlay(overlay: &OverlaySelector, action: &OverlayAction, app: &mut AppState) {
|
||||||
match action {
|
match action {
|
||||||
OverlayAction::Reset => {
|
OverlayAction::Reset => {
|
||||||
@@ -736,7 +742,7 @@ fn run_overlay(overlay: &OverlaySelector, action: &OverlayAction, app: &mut AppS
|
|||||||
|
|
||||||
if state_dirty {
|
if state_dirty {
|
||||||
match save_layout(&app.session.config) {
|
match save_layout(&app.session.config) {
|
||||||
Ok(_) => log::debug!("Saved state"),
|
Ok(()) => log::debug!("Saved state"),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error_toast(app, "Failed to save state", e);
|
error_toast(app, "Failed to save state", e);
|
||||||
}
|
}
|
||||||
@@ -752,17 +758,17 @@ fn run_overlay(overlay: &OverlaySelector, action: &OverlayAction, app: &mut AppS
|
|||||||
o.recenter = !o.recenter;
|
o.recenter = !o.recenter;
|
||||||
o.grabbable = o.recenter;
|
o.grabbable = o.recenter;
|
||||||
o.show_hide = o.recenter;
|
o.show_hide = o.recenter;
|
||||||
if !o.recenter {
|
if o.recenter {
|
||||||
Toast::new(
|
Toast::new(
|
||||||
ToastTopic::System,
|
ToastTopic::System,
|
||||||
format!("{} is now locked in place!", o.name).into(),
|
format!("{} is now unlocked!", o.name).into(),
|
||||||
"".into(),
|
"".into(),
|
||||||
)
|
)
|
||||||
.submit(app);
|
.submit(app);
|
||||||
} else {
|
} else {
|
||||||
Toast::new(
|
Toast::new(
|
||||||
ToastTopic::System,
|
ToastTopic::System,
|
||||||
format!("{} is now unlocked!", o.name).into(),
|
format!("{} is now locked in place!", o.name).into(),
|
||||||
"".into(),
|
"".into(),
|
||||||
)
|
)
|
||||||
.submit(app);
|
.submit(app);
|
||||||
@@ -776,17 +782,17 @@ fn run_overlay(overlay: &OverlaySelector, action: &OverlayAction, app: &mut AppS
|
|||||||
overlay.clone(),
|
overlay.clone(),
|
||||||
Box::new(|app, o| {
|
Box::new(|app, o| {
|
||||||
o.interactable = !o.interactable;
|
o.interactable = !o.interactable;
|
||||||
if !o.interactable {
|
if o.interactable {
|
||||||
Toast::new(
|
Toast::new(
|
||||||
ToastTopic::System,
|
ToastTopic::System,
|
||||||
format!("{} is now non-interactable!", o.name).into(),
|
format!("{} is now interactable!", o.name).into(),
|
||||||
"".into(),
|
"".into(),
|
||||||
)
|
)
|
||||||
.submit(app);
|
.submit(app);
|
||||||
} else {
|
} else {
|
||||||
Toast::new(
|
Toast::new(
|
||||||
ToastTopic::System,
|
ToastTopic::System,
|
||||||
format!("{} is now interactable!", o.name).into(),
|
format!("{} is now non-interactable!", o.name).into(),
|
||||||
"".into(),
|
"".into(),
|
||||||
)
|
)
|
||||||
.submit(app);
|
.submit(app);
|
||||||
@@ -827,7 +833,11 @@ fn run_window(window: &Arc<str>, action: &WindowAction, app: &mut AppState) {
|
|||||||
)
|
)
|
||||||
.with_sound(true)
|
.with_sound(true)
|
||||||
.submit(app);
|
.submit(app);
|
||||||
crate::overlays::mirror::new_mirror(name.clone(), false, &app.session)
|
Some(crate::overlays::mirror::new_mirror(
|
||||||
|
name,
|
||||||
|
false,
|
||||||
|
&app.session,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
));
|
));
|
||||||
|
|||||||
@@ -100,15 +100,14 @@ pub fn modular_label_init(label: &mut ModularControl, content: &LabelContent, ap
|
|||||||
}),
|
}),
|
||||||
LabelContent::Clock { format, timezone } => {
|
LabelContent::Clock { format, timezone } => {
|
||||||
let tz_str = match timezone {
|
let tz_str = match timezone {
|
||||||
Some(TimezoneDef::Idx(idx)) => {
|
Some(TimezoneDef::Idx(idx)) => app.session.config.timezones.get(*idx).map_or_else(
|
||||||
if let Some(tz) = app.session.config.timezones.get(*idx) {
|
|| {
|
||||||
Some(tz.as_str())
|
log::error!("Timezone index out of range '{idx}'");
|
||||||
} else {
|
|
||||||
log::error!("Timezone index out of range '{}'", idx);
|
|
||||||
label.set_fg_color(*FALLBACK_COLOR);
|
label.set_fg_color(*FALLBACK_COLOR);
|
||||||
None
|
None
|
||||||
}
|
},
|
||||||
}
|
|tz| Some(tz.as_str()),
|
||||||
|
),
|
||||||
Some(TimezoneDef::Str(tz_str)) => Some(tz_str.as_ref()),
|
Some(TimezoneDef::Str(tz_str)) => Some(tz_str.as_ref()),
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
@@ -127,14 +126,13 @@ pub fn modular_label_init(label: &mut ModularControl, content: &LabelContent, ap
|
|||||||
}
|
}
|
||||||
LabelContent::Timezone { timezone } => {
|
LabelContent::Timezone { timezone } => {
|
||||||
if let Some(tz) = app.session.config.timezones.get(*timezone) {
|
if let Some(tz) = app.session.config.timezones.get(*timezone) {
|
||||||
let pretty_tz = tz.split('/').next_back().map(|x| x.replace("_", " "));
|
let pretty_tz = tz.split('/').next_back().map(|x| x.replace('_', " "));
|
||||||
|
|
||||||
if let Some(pretty_tz) = pretty_tz {
|
if let Some(pretty_tz) = pretty_tz {
|
||||||
label.set_text(&pretty_tz);
|
label.set_text(&pretty_tz);
|
||||||
return;
|
return;
|
||||||
} else {
|
|
||||||
log::error!("Timezone name not valid '{}'", &tz);
|
|
||||||
}
|
}
|
||||||
|
log::error!("Timezone name not valid '{}'", &tz);
|
||||||
} else {
|
} else {
|
||||||
log::error!("Timezone index out of range '{}'", &timezone);
|
log::error!("Timezone index out of range '{}'", &timezone);
|
||||||
}
|
}
|
||||||
@@ -166,6 +164,7 @@ pub fn modular_label_init(label: &mut ModularControl, content: &LabelContent, ap
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_lines)]
|
||||||
pub(super) fn label_update(control: &mut ModularControl, _: &mut (), app: &mut AppState) {
|
pub(super) fn label_update(control: &mut ModularControl, _: &mut (), app: &mut AppState) {
|
||||||
// want panic
|
// want panic
|
||||||
let ModularData::Label(data) = control.state.as_mut().unwrap() else {
|
let ModularData::Label(data) = control.state.as_mut().unwrap() else {
|
||||||
@@ -184,9 +183,9 @@ pub(super) fn label_update(control: &mut ModularControl, _: &mut (), app: &mut A
|
|||||||
let tags = ["", "H", "L", "R", "T"];
|
let tags = ["", "H", "L", "R", "T"];
|
||||||
|
|
||||||
if let Some(device) = device {
|
if let Some(device) = device {
|
||||||
let (text, color) = device
|
let (text, color) = device.soc.map_or_else(
|
||||||
.soc
|
|| (String::new(), Vec4::ZERO),
|
||||||
.map(|soc| {
|
|soc| {
|
||||||
let text = format!(
|
let text = format!(
|
||||||
"{}{}",
|
"{}{}",
|
||||||
tags[device.role as usize],
|
tags[device.role as usize],
|
||||||
@@ -200,8 +199,8 @@ pub(super) fn label_update(control: &mut ModularControl, _: &mut (), app: &mut A
|
|||||||
*normal_color
|
*normal_color
|
||||||
};
|
};
|
||||||
(text, color)
|
(text, color)
|
||||||
})
|
},
|
||||||
.unwrap_or_else(|| ("".into(), Vec4::ZERO));
|
);
|
||||||
|
|
||||||
control.set_text(&text);
|
control.set_text(&text);
|
||||||
control.set_fg_color(color);
|
control.set_fg_color(color);
|
||||||
@@ -212,11 +211,11 @@ pub(super) fn label_update(control: &mut ModularControl, _: &mut (), app: &mut A
|
|||||||
LabelData::Clock { format, timezone } => {
|
LabelData::Clock { format, timezone } => {
|
||||||
let format = format.clone();
|
let format = format.clone();
|
||||||
if let Some(tz) = timezone {
|
if let Some(tz) = timezone {
|
||||||
let date = Local::now().with_timezone(tz);
|
let date_time = Local::now().with_timezone(tz);
|
||||||
control.set_text(&format!("{}", &date.format(&format)));
|
control.set_text(&format!("{}", &date_time.format(&format)));
|
||||||
} else {
|
} else {
|
||||||
let date = Local::now();
|
let date_time = Local::now();
|
||||||
control.set_text(&format!("{}", &date.format(&format)));
|
control.set_text(&format!("{}", &date_time.format(&format)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LabelData::Timer { format, start } => {
|
LabelData::Timer { format, start } => {
|
||||||
@@ -236,13 +235,7 @@ pub(super) fn label_update(control: &mut ModularControl, _: &mut (), app: &mut A
|
|||||||
if let Some(mut proc) = child.take() {
|
if let Some(mut proc) = child.take() {
|
||||||
match proc.try_wait() {
|
match proc.try_wait() {
|
||||||
Ok(Some(code)) => {
|
Ok(Some(code)) => {
|
||||||
if !code.success() {
|
if code.success() {
|
||||||
error_toast(
|
|
||||||
app,
|
|
||||||
"LabelData::Exec: Child process exited with code",
|
|
||||||
code,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
if let Some(mut stdout) = proc.stdout.take() {
|
if let Some(mut stdout) = proc.stdout.take() {
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
if stdout.read_to_string(&mut buf).is_ok() {
|
if stdout.read_to_string(&mut buf).is_ok() {
|
||||||
@@ -259,6 +252,7 @@ pub(super) fn label_update(control: &mut ModularControl, _: &mut (), app: &mut A
|
|||||||
log::error!("No stdout for child process");
|
log::error!("No stdout for child process");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
error_toast(app, "LabelData::Exec: Child process exited with code", code);
|
||||||
}
|
}
|
||||||
Ok(None) => {
|
Ok(None) => {
|
||||||
*child = Some(proc);
|
*child = Some(proc);
|
||||||
@@ -281,7 +275,7 @@ pub(super) fn label_update(control: &mut ModularControl, _: &mut (), app: &mut A
|
|||||||
*last_exec = Instant::now();
|
*last_exec = Instant::now();
|
||||||
let args = command
|
let args = command
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| s.as_ref())
|
.map(std::convert::AsRef::as_ref)
|
||||||
.collect::<SmallVec<[&str; 8]>>();
|
.collect::<SmallVec<[&str; 8]>>();
|
||||||
|
|
||||||
match process::Command::new(args[0])
|
match process::Command::new(args[0])
|
||||||
@@ -293,9 +287,9 @@ pub(super) fn label_update(control: &mut ModularControl, _: &mut (), app: &mut A
|
|||||||
*child = Some(proc);
|
*child = Some(proc);
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error_toast(app, &format!("Failed to spawn process {:?}", args), e);
|
error_toast(app, &format!("Failed to spawn process {args:?}"), e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LabelData::Ipd { last_ipd } => {
|
LabelData::Ipd { last_ipd } => {
|
||||||
|
|||||||
@@ -149,8 +149,9 @@ pub enum ModularData {
|
|||||||
Button(Box<ButtonData>),
|
Button(Box<ButtonData>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_lines, clippy::many_single_char_names)]
|
||||||
pub fn modular_canvas(
|
pub fn modular_canvas(
|
||||||
size: &[u32; 2],
|
size: [u32; 2],
|
||||||
elements: &[ModularElement],
|
elements: &[ModularElement],
|
||||||
state: &mut AppState,
|
state: &mut AppState,
|
||||||
) -> anyhow::Result<Canvas<(), ModularData>> {
|
) -> anyhow::Result<Canvas<(), ModularData>> {
|
||||||
@@ -162,7 +163,7 @@ pub fn modular_canvas(
|
|||||||
(),
|
(),
|
||||||
)?;
|
)?;
|
||||||
let empty_str: Arc<str> = Arc::from("");
|
let empty_str: Arc<str> = Arc::from("");
|
||||||
for elem in elements.iter() {
|
for elem in elements {
|
||||||
match elem {
|
match elem {
|
||||||
ModularElement::Panel {
|
ModularElement::Panel {
|
||||||
rect: [x, y, w, h],
|
rect: [x, y, w, h],
|
||||||
@@ -226,7 +227,7 @@ pub fn modular_canvas(
|
|||||||
sprite.set_sprite_st(st);
|
sprite.set_sprite_st(st);
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::warn!("Could not load custom UI sprite: {:?}", e);
|
log::warn!("Could not load custom UI sprite: {e:?}");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ModularElement::Button {
|
ModularElement::Button {
|
||||||
@@ -326,7 +327,7 @@ pub fn modular_canvas(
|
|||||||
canvas.fg_color = color_parse(fg_color).unwrap_or(*FALLBACK_COLOR);
|
canvas.fg_color = color_parse(fg_color).unwrap_or(*FALLBACK_COLOR);
|
||||||
canvas.font_size = *font_size;
|
canvas.font_size = *font_size;
|
||||||
|
|
||||||
for screen in state.screens.iter() {
|
for screen in &state.screens {
|
||||||
let button = canvas.button(
|
let button = canvas.button(
|
||||||
button_x + 2.,
|
button_x + 2.,
|
||||||
button_y + 2.,
|
button_y + 2.,
|
||||||
@@ -465,7 +466,7 @@ pub fn modular_canvas(
|
|||||||
button_x += button_w;
|
button_x += button_w;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log::error!("WayVR catalog \"{}\" not found", catalog_name);
|
log::error!("WayVR catalog \"{catalog_name}\" not found");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "wayvr"))]
|
#[cfg(not(feature = "wayvr"))]
|
||||||
@@ -535,7 +536,7 @@ pub fn modular_canvas(
|
|||||||
|
|
||||||
pub fn color_parse_or_default(color: &str) -> GuiColor {
|
pub fn color_parse_or_default(color: &str) -> GuiColor {
|
||||||
color_parse(color).unwrap_or_else(|e| {
|
color_parse(color).unwrap_or_else(|e| {
|
||||||
log::error!("Failed to parse color '{}': {}", color, e);
|
log::error!("Failed to parse color '{color}': {e}");
|
||||||
*FALLBACK_COLOR
|
*FALLBACK_COLOR
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,10 +34,7 @@ pub fn initialize() -> Box<dyn HidProvider> {
|
|||||||
log::error!("Could not create uinput provider. Keyboard/Mouse input will not work!");
|
log::error!("Could not create uinput provider. Keyboard/Mouse input will not work!");
|
||||||
log::error!("To check if you're in input group, run: id -nG");
|
log::error!("To check if you're in input group, run: id -nG");
|
||||||
if let Ok(user) = std::env::var("USER") {
|
if let Ok(user) = std::env::var("USER") {
|
||||||
log::error!(
|
log::error!("To add yourself to the input group, run: sudo usermod -aG input {user}");
|
||||||
"To add yourself to the input group, run: sudo usermod -aG input {}",
|
|
||||||
user
|
|
||||||
);
|
|
||||||
log::error!("After adding yourself to the input group, you will need to reboot.");
|
log::error!("After adding yourself to the input group, you will need to reboot.");
|
||||||
}
|
}
|
||||||
Box::new(DummyProvider {})
|
Box::new(DummyProvider {})
|
||||||
@@ -163,28 +160,28 @@ impl UInputProvider {
|
|||||||
.create(&mouse_id, mouse_name, 0, &abs_info)
|
.create(&mouse_id, mouse_name, 0, &abs_info)
|
||||||
.ok()?;
|
.ok()?;
|
||||||
|
|
||||||
Some(UInputProvider {
|
Some(Self {
|
||||||
keyboard_handle,
|
keyboard_handle,
|
||||||
mouse_handle,
|
mouse_handle,
|
||||||
desktop_extent: Vec2::ZERO,
|
desktop_extent: Vec2::ZERO,
|
||||||
desktop_origin: Vec2::ZERO,
|
desktop_origin: Vec2::ZERO,
|
||||||
current_action: Default::default(),
|
current_action: MouseAction::default(),
|
||||||
cur_modifiers: 0,
|
cur_modifiers: 0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fn send_button_internal(&self, button: u16, down: bool) {
|
fn send_button_internal(&self, button: u16, down: bool) {
|
||||||
let time = get_time();
|
let time = get_time();
|
||||||
let events = [
|
let events = [
|
||||||
new_event(time, EV_KEY, button, down as _),
|
new_event(time, EV_KEY, button, down.into()),
|
||||||
new_event(time, EV_SYN, 0, 0),
|
new_event(time, EV_SYN, 0, 0),
|
||||||
];
|
];
|
||||||
if let Err(res) = self.mouse_handle.write(&events) {
|
if let Err(res) = self.mouse_handle.write(&events) {
|
||||||
log::error!("send_button: {}", res.to_string());
|
log::error!("send_button: {res}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn mouse_move_internal(&mut self, pos: Vec2) {
|
fn mouse_move_internal(&mut self, pos: Vec2) {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
log::trace!("Mouse move: {:?}", pos);
|
log::trace!("Mouse move: {pos:?}");
|
||||||
|
|
||||||
let pos = (pos - self.desktop_origin) * (MOUSE_EXTENT / self.desktop_extent);
|
let pos = (pos - self.desktop_origin) * (MOUSE_EXTENT / self.desktop_extent);
|
||||||
|
|
||||||
@@ -195,7 +192,7 @@ impl UInputProvider {
|
|||||||
new_event(time, EV_SYN, 0, 0),
|
new_event(time, EV_SYN, 0, 0),
|
||||||
];
|
];
|
||||||
if let Err(res) = self.mouse_handle.write(&events) {
|
if let Err(res) = self.mouse_handle.write(&events) {
|
||||||
log::error!("{}", res.to_string());
|
log::error!("{res}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn wheel_internal(&self, delta_y: i32, delta_x: i32) {
|
fn wheel_internal(&self, delta_y: i32, delta_x: i32) {
|
||||||
@@ -211,7 +208,7 @@ impl UInputProvider {
|
|||||||
new_event(time, EV_SYN, 0, 0),
|
new_event(time, EV_SYN, 0, 0),
|
||||||
];
|
];
|
||||||
if let Err(res) = self.mouse_handle.write(&events) {
|
if let Err(res) = self.mouse_handle.write(&events) {
|
||||||
log::error!("wheel: {}", res.to_string());
|
log::error!("wheel: {res}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -231,15 +228,15 @@ impl HidProvider for UInputProvider {
|
|||||||
}
|
}
|
||||||
fn send_key(&self, key: VirtualKey, down: bool) {
|
fn send_key(&self, key: VirtualKey, down: bool) {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
log::trace!("send_key: {:?} {}", key, down);
|
log::trace!("send_key: {key:?} {down}");
|
||||||
|
|
||||||
let time = get_time();
|
let time = get_time();
|
||||||
let events = [
|
let events = [
|
||||||
new_event(time, EV_KEY, (key as u16) - 8, down as _),
|
new_event(time, EV_KEY, (key as u16) - 8, down.into()),
|
||||||
new_event(time, EV_SYN, 0, 0),
|
new_event(time, EV_SYN, 0, 0),
|
||||||
];
|
];
|
||||||
if let Err(res) = self.keyboard_handle.write(&events) {
|
if let Err(res) = self.keyboard_handle.write(&events) {
|
||||||
log::error!("send_key: {}", res.to_string());
|
log::error!("send_key: {res}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn set_desktop_extent(&mut self, extent: Vec2) {
|
fn set_desktop_extent(&mut self, extent: Vec2) {
|
||||||
@@ -303,7 +300,7 @@ fn get_time() -> timeval {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn new_event(time: timeval, type_: u16, code: u16, value: i32) -> input_event {
|
const fn new_event(time: timeval, type_: u16, code: u16, value: i32) -> input_event {
|
||||||
input_event {
|
input_event {
|
||||||
time,
|
time,
|
||||||
type_,
|
type_,
|
||||||
@@ -323,7 +320,7 @@ pub const META: KeyModifier = 0x80;
|
|||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
#[repr(u16)]
|
#[repr(u16)]
|
||||||
#[derive(Debug, Deserialize, PartialEq, Clone, Copy, IntegerId, EnumString, EnumIter)]
|
#[derive(Debug, Deserialize, PartialEq, Eq, Clone, Copy, IntegerId, EnumString, EnumIter)]
|
||||||
pub enum VirtualKey {
|
pub enum VirtualKey {
|
||||||
Escape = 9,
|
Escape = 9,
|
||||||
N1, // number row
|
N1, // number row
|
||||||
@@ -524,7 +521,7 @@ macro_rules! key_is {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_key_type(key: VirtualKey) -> KeyType {
|
pub const fn get_key_type(key: VirtualKey) -> KeyType {
|
||||||
if key_between!(key, VirtualKey::N1, VirtualKey::Plus)
|
if key_between!(key, VirtualKey::N1, VirtualKey::Plus)
|
||||||
|| key_between!(key, VirtualKey::Q, VirtualKey::Oem6)
|
|| key_between!(key, VirtualKey::Q, VirtualKey::Oem6)
|
||||||
|| key_between!(key, VirtualKey::A, VirtualKey::Oem3)
|
|| key_between!(key, VirtualKey::A, VirtualKey::Oem3)
|
||||||
|
|||||||
@@ -46,11 +46,9 @@ pub fn get_keymap_wl() -> anyhow::Result<XkbKeymap> {
|
|||||||
// this gets us the wl_keyboard
|
// this gets us the wl_keyboard
|
||||||
let _ = queue.blocking_dispatch(&mut me);
|
let _ = queue.blocking_dispatch(&mut me);
|
||||||
|
|
||||||
if let Some(keymap) = me.keymap.take() {
|
me.keymap
|
||||||
Ok(keymap)
|
.take()
|
||||||
} else {
|
.ok_or_else(|| anyhow::anyhow!("Could not load keymap"))
|
||||||
Err(anyhow::anyhow!("Could not load keymap"))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Dispatch<WlRegistry, GlobalListContents> for WlKeymapHandler {
|
impl Dispatch<WlRegistry, GlobalListContents> for WlKeymapHandler {
|
||||||
@@ -84,7 +82,7 @@ impl Dispatch<WlSeat, ()> for WlKeymapHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
wl_seat::Event::Name { name } => {
|
wl_seat::Event::Name { name } => {
|
||||||
log::debug!("Using WlSeat: {}", name);
|
log::debug!("Using WlSeat: {name}");
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@@ -127,14 +125,14 @@ impl Dispatch<WlKeyboard, ()> for WlKeymapHandler {
|
|||||||
log::error!("Default layout will be used.");
|
log::error!("Default layout will be used.");
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::error!("Could not load keymap: {}", err);
|
log::error!("Could not load keymap: {err}");
|
||||||
log::error!("Default layout will be used.");
|
log::error!("Default layout will be used.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wl_keyboard::Event::RepeatInfo { rate, delay } => {
|
wl_keyboard::Event::RepeatInfo { rate, delay } => {
|
||||||
log::debug!("WlKeyboard RepeatInfo rate: {}, delay: {}", rate, delay);
|
log::debug!("WlKeyboard RepeatInfo rate: {rate}, delay: {delay}");
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|||||||
49
src/main.rs
49
src/main.rs
@@ -1,4 +1,18 @@
|
|||||||
#[allow(dead_code)]
|
#![warn(clippy::all, clippy::pedantic, clippy::nursery, clippy::cargo)]
|
||||||
|
#![allow(
|
||||||
|
dead_code,
|
||||||
|
clippy::cast_precision_loss,
|
||||||
|
clippy::cast_possible_truncation,
|
||||||
|
clippy::cast_sign_loss,
|
||||||
|
clippy::cast_possible_wrap,
|
||||||
|
clippy::cast_lossless,
|
||||||
|
clippy::match_wildcard_for_single_variants,
|
||||||
|
clippy::doc_markdown,
|
||||||
|
clippy::struct_excessive_bools,
|
||||||
|
clippy::needless_pass_by_value,
|
||||||
|
clippy::needless_pass_by_ref_mut,
|
||||||
|
clippy::multiple_crate_versions
|
||||||
|
)]
|
||||||
mod backend;
|
mod backend;
|
||||||
mod config;
|
mod config;
|
||||||
mod config_io;
|
mod config_io;
|
||||||
@@ -65,6 +79,7 @@ struct Args {
|
|||||||
uidev: Option<String>,
|
uidev: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::unnecessary_wraps)]
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut args = if std::env::args().skip(1).any(|a| !a.is_empty()) {
|
let mut args = if std::env::args().skip(1).any(|a| !a.is_empty()) {
|
||||||
Args::parse()
|
Args::parse()
|
||||||
@@ -78,7 +93,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
logging_init(&mut args)?;
|
logging_init(&mut args);
|
||||||
|
|
||||||
log::info!(
|
log::info!(
|
||||||
"Welcome to {} version {}!",
|
"Welcome to {} version {}!",
|
||||||
@@ -122,23 +137,23 @@ fn auto_run(running: Arc<AtomicBool>, args: Args) {
|
|||||||
Ok(()) => return,
|
Ok(()) => return,
|
||||||
Err(BackendError::NotSupported) => (),
|
Err(BackendError::NotSupported) => (),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("{}", e.to_string());
|
log::error!("{e}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "openvr")]
|
#[cfg(feature = "openvr")]
|
||||||
if !args_get_openxr(&args) {
|
if !args_get_openxr(&args) {
|
||||||
use crate::backend::openvr::openvr_run;
|
use crate::backend::openvr::openvr_run;
|
||||||
match openvr_run(running.clone(), args.show) {
|
match openvr_run(running, args.show) {
|
||||||
Ok(()) => return,
|
Ok(()) => return,
|
||||||
Err(BackendError::NotSupported) => (),
|
Err(BackendError::NotSupported) => (),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("{}", e.to_string());
|
log::error!("{e}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log::error!("No more backends to try");
|
log::error!("No more backends to try");
|
||||||
@@ -151,9 +166,9 @@ fn auto_run(running: Arc<AtomicBool>, args: Args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn args_get_openvr(_args: &Args) -> bool {
|
const fn args_get_openvr(args: &Args) -> bool {
|
||||||
#[cfg(feature = "openvr")]
|
#[cfg(feature = "openvr")]
|
||||||
let ret = _args.openvr;
|
let ret = args.openvr;
|
||||||
|
|
||||||
#[cfg(not(feature = "openvr"))]
|
#[cfg(not(feature = "openvr"))]
|
||||||
let ret = false;
|
let ret = false;
|
||||||
@@ -162,9 +177,9 @@ fn args_get_openvr(_args: &Args) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn args_get_openxr(_args: &Args) -> bool {
|
const fn args_get_openxr(args: &Args) -> bool {
|
||||||
#[cfg(feature = "openxr")]
|
#[cfg(feature = "openxr")]
|
||||||
let ret = _args.openxr;
|
let ret = args.openxr;
|
||||||
|
|
||||||
#[cfg(not(feature = "openxr"))]
|
#[cfg(not(feature = "openxr"))]
|
||||||
let ret = false;
|
let ret = false;
|
||||||
@@ -172,12 +187,12 @@ fn args_get_openxr(_args: &Args) -> bool {
|
|||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
fn logging_init(args: &mut Args) -> anyhow::Result<()> {
|
fn logging_init(args: &mut Args) {
|
||||||
let log_file_path = args
|
let log_file_path = args
|
||||||
.log_to
|
.log_to
|
||||||
.take()
|
.take()
|
||||||
.or_else(|| std::env::var("WLX_LOGFILE").ok())
|
.or_else(|| std::env::var("WLX_LOGFILE").ok())
|
||||||
.unwrap_or(String::from("/tmp/wlx.log"));
|
.unwrap_or_else(|| String::from("/tmp/wlx.log"));
|
||||||
|
|
||||||
let file_writer = match std::fs::OpenOptions::new()
|
let file_writer = match std::fs::OpenOptions::new()
|
||||||
.write(true)
|
.write(true)
|
||||||
@@ -189,7 +204,7 @@ fn logging_init(args: &mut Args) -> anyhow::Result<()> {
|
|||||||
Some(file)
|
Some(file)
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("Failed to open log file (path: {:?}): {}", e, log_file_path);
|
println!("Failed to open log file (path: {e:?}): {log_file_path}");
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -225,13 +240,11 @@ fn logging_init(args: &mut Args) -> anyhow::Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
log_panics::init();
|
log_panics::init();
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ensure_single_instance(replace: bool) -> bool {
|
fn ensure_single_instance(replace: bool) -> bool {
|
||||||
let mut path = std::env::var("XDG_RUNTIME_DIR")
|
let mut path =
|
||||||
.map(PathBuf::from)
|
std::env::var("XDG_RUNTIME_DIR").map_or_else(|_| PathBuf::from("/tmp"), PathBuf::from);
|
||||||
.unwrap_or_else(|_| PathBuf::from("/tmp"));
|
|
||||||
path.push("wlx-overlay-s.pid");
|
path.push("wlx-overlay-s.pid");
|
||||||
|
|
||||||
if path.exists() {
|
if path.exists() {
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ where
|
|||||||
relative_to: RelativeTo::Stage,
|
relative_to: RelativeTo::Stage,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
backend: Box::new(modular_canvas(&config.size, &config.elements, state)?),
|
backend: Box::new(modular_canvas(config.size, &config.elements, state)?),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,28 +21,28 @@ pub fn create_custom(
|
|||||||
match load_custom_ui(&name) {
|
match load_custom_ui(&name) {
|
||||||
Ok(config) => config,
|
Ok(config) => config,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("Failed to load custom UI config for {}: {:?}", name, e);
|
log::error!("Failed to load custom UI config for {name}: {e:?}");
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let canvas = match modular_canvas(&config.size, &config.elements, state) {
|
let canvas = match modular_canvas(config.size, &config.elements, state) {
|
||||||
Ok(canvas) => canvas,
|
Ok(canvas) => canvas,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("Failed to create canvas for {}: {:?}", name, e);
|
log::error!("Failed to create canvas for {name}: {e:?}");
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let state = OverlayState {
|
let state = OverlayState {
|
||||||
name: name.clone(),
|
name,
|
||||||
want_visible: true,
|
want_visible: true,
|
||||||
interactable: true,
|
interactable: true,
|
||||||
grabbable: true,
|
grabbable: true,
|
||||||
spawn_scale: config.width,
|
spawn_scale: config.width,
|
||||||
spawn_point: Vec3A::from_array(config.spawn_pos.unwrap_or([0., 0., -0.5])),
|
spawn_point: Vec3A::from_array(config.spawn_pos.unwrap_or([0., 0., -0.5])),
|
||||||
interaction_transform: ui_transform(&config.size),
|
interaction_transform: ui_transform(config.size),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let backend = Box::new(canvas);
|
let backend = Box::new(canvas);
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ fn set_modifiers(app: &mut AppState, mods: u8) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_lines)]
|
||||||
pub fn create_keyboard<O>(
|
pub fn create_keyboard<O>(
|
||||||
app: &AppState,
|
app: &AppState,
|
||||||
mut keymap: Option<XkbKeymap>,
|
mut keymap: Option<XkbKeymap>,
|
||||||
@@ -106,23 +107,25 @@ where
|
|||||||
canvas.fg_color = color_parse("#cad3f5").unwrap(); //safe
|
canvas.fg_color = color_parse("#cad3f5").unwrap(); //safe
|
||||||
canvas.bg_color = color_parse("#1e2030").unwrap(); //safe
|
canvas.bg_color = color_parse("#1e2030").unwrap(); //safe
|
||||||
|
|
||||||
let has_altgr = keymap.as_ref().is_some_and(|k| k.has_altgr());
|
let has_altgr = keymap
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(super::super::hid::XkbKeymap::has_altgr);
|
||||||
|
|
||||||
if !LAYOUT.auto_labels.unwrap_or(true) {
|
if !LAYOUT.auto_labels.unwrap_or(true) {
|
||||||
keymap = None;
|
keymap = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let unit_size = size.x / LAYOUT.row_size;
|
let unit_size = size.x / LAYOUT.row_size;
|
||||||
let h = unit_size - 2. * BUTTON_PADDING;
|
let h = 2.0f32.mul_add(-BUTTON_PADDING, unit_size);
|
||||||
|
|
||||||
for row in 0..LAYOUT.key_sizes.len() {
|
for row in 0..LAYOUT.key_sizes.len() {
|
||||||
let y = unit_size * (row as f32) + BUTTON_PADDING;
|
let y = unit_size.mul_add(row as f32, BUTTON_PADDING);
|
||||||
let mut sum_size = 0f32;
|
let mut sum_size = 0f32;
|
||||||
|
|
||||||
for col in 0..LAYOUT.key_sizes[row].len() {
|
for col in 0..LAYOUT.key_sizes[row].len() {
|
||||||
let my_size = LAYOUT.key_sizes[row][col];
|
let my_size = LAYOUT.key_sizes[row][col];
|
||||||
let x = unit_size * sum_size + BUTTON_PADDING;
|
let x = unit_size.mul_add(sum_size, BUTTON_PADDING);
|
||||||
let w = unit_size * my_size - 2. * BUTTON_PADDING;
|
let w = unit_size.mul_add(my_size, -(2. * BUTTON_PADDING));
|
||||||
|
|
||||||
if let Some(key) = LAYOUT.main_layout[row][col].as_ref() {
|
if let Some(key) = LAYOUT.main_layout[row][col].as_ref() {
|
||||||
let mut label = Vec::with_capacity(2);
|
let mut label = Vec::with_capacity(2);
|
||||||
@@ -136,7 +139,7 @@ where
|
|||||||
let label0 = keymap.label_for_key(vk, 0);
|
let label0 = keymap.label_for_key(vk, 0);
|
||||||
let label1 = keymap.label_for_key(vk, SHIFT);
|
let label1 = keymap.label_for_key(vk, SHIFT);
|
||||||
|
|
||||||
if label0.chars().next().is_some_and(|f| f.is_alphabetic()) {
|
if label0.chars().next().is_some_and(char::is_alphabetic) {
|
||||||
label.push(label1);
|
label.push(label1);
|
||||||
if has_altgr {
|
if has_altgr {
|
||||||
cap_type = KeyCapType::RegularAltGr;
|
cap_type = KeyCapType::RegularAltGr;
|
||||||
@@ -176,7 +179,7 @@ where
|
|||||||
});
|
});
|
||||||
} else if let Some(exec_args) = LAYOUT.exec_commands.get(key) {
|
} else if let Some(exec_args) = LAYOUT.exec_commands.get(key) {
|
||||||
if exec_args.is_empty() {
|
if exec_args.is_empty() {
|
||||||
log::error!("Keyboard: EXEC args empty for {}", key);
|
log::error!("Keyboard: EXEC args empty for {key}");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let mut iter = exec_args.iter().cloned();
|
let mut iter = exec_args.iter().cloned();
|
||||||
@@ -186,10 +189,10 @@ where
|
|||||||
args: iter.by_ref().take_while(|arg| arg[..] != *"null").collect(),
|
args: iter.by_ref().take_while(|arg| arg[..] != *"null").collect(),
|
||||||
release_program: iter.next(),
|
release_program: iter.next(),
|
||||||
release_args: iter.collect(),
|
release_args: iter.collect(),
|
||||||
})
|
});
|
||||||
};
|
}
|
||||||
} else {
|
} else {
|
||||||
log::error!("Unknown key: {}", key);
|
log::error!("Unknown key: {key}");
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(state) = maybe_state {
|
if let Some(state) = maybe_state {
|
||||||
@@ -240,7 +243,7 @@ fn key_press(
|
|||||||
) {
|
) {
|
||||||
match control.state.as_mut() {
|
match control.state.as_mut() {
|
||||||
Some(KeyButtonData::Key { vk, pressed }) => {
|
Some(KeyButtonData::Key { vk, pressed }) => {
|
||||||
data.key_click(app);
|
key_click(app);
|
||||||
|
|
||||||
data.modifiers |= match mode {
|
data.modifiers |= match mode {
|
||||||
PointerMode::Right => SHIFT,
|
PointerMode::Right => SHIFT,
|
||||||
@@ -256,11 +259,11 @@ fn key_press(
|
|||||||
Some(KeyButtonData::Modifier { modifier, sticky }) => {
|
Some(KeyButtonData::Modifier { modifier, sticky }) => {
|
||||||
*sticky = data.modifiers & *modifier == 0;
|
*sticky = data.modifiers & *modifier == 0;
|
||||||
data.modifiers |= *modifier;
|
data.modifiers |= *modifier;
|
||||||
data.key_click(app);
|
key_click(app);
|
||||||
set_modifiers(app, data.modifiers);
|
set_modifiers(app, data.modifiers);
|
||||||
}
|
}
|
||||||
Some(KeyButtonData::Macro { verbs }) => {
|
Some(KeyButtonData::Macro { verbs }) => {
|
||||||
data.key_click(app);
|
key_click(app);
|
||||||
for (vk, press) in verbs {
|
for (vk, press) in verbs {
|
||||||
send_key(app, *vk, *press);
|
send_key(app, *vk, *press);
|
||||||
}
|
}
|
||||||
@@ -270,7 +273,7 @@ fn key_press(
|
|||||||
data.processes
|
data.processes
|
||||||
.retain_mut(|child| !matches!(child.try_wait(), Ok(Some(_))));
|
.retain_mut(|child| !matches!(child.try_wait(), Ok(Some(_))));
|
||||||
|
|
||||||
data.key_click(app);
|
key_click(app);
|
||||||
if let Ok(child) = Command::new(program).args(args).spawn() {
|
if let Ok(child) = Command::new(program).args(args).spawn() {
|
||||||
data.processes.push(child);
|
data.processes.push(child);
|
||||||
}
|
}
|
||||||
@@ -289,7 +292,7 @@ fn key_release(
|
|||||||
send_key(app, *vk, false);
|
send_key(app, *vk, false);
|
||||||
*pressed = false;
|
*pressed = false;
|
||||||
|
|
||||||
for m in AUTO_RELEASE_MODS.iter() {
|
for m in &AUTO_RELEASE_MODS {
|
||||||
if data.modifiers & *m != 0 {
|
if data.modifiers & *m != 0 {
|
||||||
data.modifiers &= !*m;
|
data.modifiers &= !*m;
|
||||||
set_modifiers(app, data.modifiers);
|
set_modifiers(app, data.modifiers);
|
||||||
@@ -349,13 +352,11 @@ struct KeyboardData {
|
|||||||
|
|
||||||
const KEY_AUDIO_WAV: &[u8] = include_bytes!("../res/421581.wav");
|
const KEY_AUDIO_WAV: &[u8] = include_bytes!("../res/421581.wav");
|
||||||
|
|
||||||
impl KeyboardData {
|
fn key_click(app: &mut AppState) {
|
||||||
fn key_click(&mut self, app: &mut AppState) {
|
|
||||||
if app.session.config.keyboard_sound_enabled {
|
if app.session.config.keyboard_sound_enabled {
|
||||||
app.audio.play(KEY_AUDIO_WAV);
|
app.audio.play(KEY_AUDIO_WAV);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
enum KeyButtonData {
|
enum KeyButtonData {
|
||||||
Key {
|
Key {
|
||||||
@@ -395,6 +396,7 @@ pub enum AltModifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
|
#[allow(clippy::struct_field_names)]
|
||||||
pub struct Layout {
|
pub struct Layout {
|
||||||
name: String,
|
name: String,
|
||||||
row_size: f32,
|
row_size: f32,
|
||||||
@@ -408,8 +410,8 @@ pub struct Layout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Layout {
|
impl Layout {
|
||||||
fn load_from_disk() -> Layout {
|
fn load_from_disk() -> Self {
|
||||||
let mut layout = config::load_known_yaml::<Layout>(ConfigType::Keyboard);
|
let mut layout = config::load_known_yaml::<Self>(ConfigType::Keyboard);
|
||||||
layout.post_load();
|
layout.post_load();
|
||||||
layout
|
layout
|
||||||
}
|
}
|
||||||
@@ -418,19 +420,20 @@ impl Layout {
|
|||||||
for i in 0..self.key_sizes.len() {
|
for i in 0..self.key_sizes.len() {
|
||||||
let row = &self.key_sizes[i];
|
let row = &self.key_sizes[i];
|
||||||
let width: f32 = row.iter().sum();
|
let width: f32 = row.iter().sum();
|
||||||
if (width - self.row_size).abs() > 0.001 {
|
assert!(
|
||||||
panic!(
|
(width - self.row_size).abs() < 0.001,
|
||||||
"Row {} has a width of {}, but the row size is {}",
|
"Row {} has a width of {}, but the row size is {}",
|
||||||
i, width, self.row_size
|
i,
|
||||||
|
width,
|
||||||
|
self.row_size
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for i in 0..self.main_layout.len() {
|
for i in 0..self.main_layout.len() {
|
||||||
let row = &self.main_layout[i];
|
let row = &self.main_layout[i];
|
||||||
let width = row.len();
|
let width = row.len();
|
||||||
if width != self.key_sizes[i].len() {
|
assert!(
|
||||||
panic!(
|
(width == self.key_sizes[i].len()),
|
||||||
"Row {} has {} keys, needs to have {} according to key_sizes",
|
"Row {} has {} keys, needs to have {} according to key_sizes",
|
||||||
i,
|
i,
|
||||||
width,
|
width,
|
||||||
@@ -438,7 +441,6 @@ impl Layout {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn label_for_key(&self, key: &str) -> Vec<String> {
|
fn label_for_key(&self, key: &str) -> Vec<String> {
|
||||||
if let Some(label) = self.labels.get(key) {
|
if let Some(label) = self.labels.get(key) {
|
||||||
@@ -456,10 +458,7 @@ impl Layout {
|
|||||||
}
|
}
|
||||||
if key.contains('_') {
|
if key.contains('_') {
|
||||||
key = key.split('_').next().unwrap_or_else(|| {
|
key = key.split('_').next().unwrap_or_else(|| {
|
||||||
log::error!(
|
log::error!("keyboard.yaml: Key '{key}' must not start or end with '_'!");
|
||||||
"keyboard.yaml: Key '{}' must not start or end with '_'!",
|
|
||||||
key
|
|
||||||
);
|
|
||||||
"???"
|
"???"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -507,10 +506,10 @@ struct KeyboardBackend {
|
|||||||
|
|
||||||
impl OverlayBackend for KeyboardBackend {
|
impl OverlayBackend for KeyboardBackend {
|
||||||
fn set_interaction(&mut self, interaction: Box<dyn crate::backend::input::InteractionHandler>) {
|
fn set_interaction(&mut self, interaction: Box<dyn crate::backend::input::InteractionHandler>) {
|
||||||
self.canvas.set_interaction(interaction)
|
self.canvas.set_interaction(interaction);
|
||||||
}
|
}
|
||||||
fn set_renderer(&mut self, renderer: Box<dyn crate::backend::overlay::OverlayRenderer>) {
|
fn set_renderer(&mut self, renderer: Box<dyn crate::backend::overlay::OverlayRenderer>) {
|
||||||
self.canvas.set_renderer(renderer)
|
self.canvas.set_renderer(renderer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -521,7 +520,7 @@ impl InteractionHandler for KeyboardBackend {
|
|||||||
hit: &crate::backend::input::PointerHit,
|
hit: &crate::backend::input::PointerHit,
|
||||||
pressed: bool,
|
pressed: bool,
|
||||||
) {
|
) {
|
||||||
self.canvas.on_pointer(app, hit, pressed)
|
self.canvas.on_pointer(app, hit, pressed);
|
||||||
}
|
}
|
||||||
fn on_scroll(
|
fn on_scroll(
|
||||||
&mut self,
|
&mut self,
|
||||||
@@ -530,10 +529,10 @@ impl InteractionHandler for KeyboardBackend {
|
|||||||
delta_y: f32,
|
delta_y: f32,
|
||||||
delta_x: f32,
|
delta_x: f32,
|
||||||
) {
|
) {
|
||||||
self.canvas.on_scroll(app, hit, delta_y, delta_x)
|
self.canvas.on_scroll(app, hit, delta_y, delta_x);
|
||||||
}
|
}
|
||||||
fn on_left(&mut self, app: &mut AppState, pointer: usize) {
|
fn on_left(&mut self, app: &mut AppState, pointer: usize) {
|
||||||
self.canvas.on_left(app, pointer)
|
self.canvas.on_left(app, pointer);
|
||||||
}
|
}
|
||||||
fn on_hover(
|
fn on_hover(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|||||||
@@ -50,8 +50,7 @@ impl OverlayRenderer for MirrorRenderer {
|
|||||||
fn should_render(&mut self, app: &mut AppState) -> anyhow::Result<ShouldRender> {
|
fn should_render(&mut self, app: &mut AppState) -> anyhow::Result<ShouldRender> {
|
||||||
self.renderer
|
self.renderer
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.map(|r| r.should_render(app))
|
.map_or(Ok(ShouldRender::Unable), |r| r.should_render(app))
|
||||||
.unwrap_or(Ok(ShouldRender::Unable))
|
|
||||||
}
|
}
|
||||||
fn render(
|
fn render(
|
||||||
&mut self,
|
&mut self,
|
||||||
@@ -90,7 +89,7 @@ impl OverlayRenderer for MirrorRenderer {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::warn!("Failed to create mirror due to PipeWire error: {:?}", e);
|
log::warn!("Failed to create mirror due to PipeWire error: {e:?}");
|
||||||
self.renderer = None;
|
self.renderer = None;
|
||||||
// drop self
|
// drop self
|
||||||
app.tasks
|
app.tasks
|
||||||
@@ -112,7 +111,7 @@ impl OverlayRenderer for MirrorRenderer {
|
|||||||
app.tasks.enqueue(TaskType::Overlay(
|
app.tasks.enqueue(TaskType::Overlay(
|
||||||
OverlaySelector::Name(self.name.clone()),
|
OverlaySelector::Name(self.name.clone()),
|
||||||
Box::new(move |_app, o| {
|
Box::new(move |_app, o| {
|
||||||
o.interaction_transform = ui_transform(&[extent[0], extent[1]]);
|
o.interaction_transform = ui_transform([extent[0], extent[1]]);
|
||||||
}),
|
}),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@@ -146,7 +145,7 @@ pub fn new_mirror(
|
|||||||
name: Arc<str>,
|
name: Arc<str>,
|
||||||
show_hide: bool,
|
show_hide: bool,
|
||||||
session: &AppSession,
|
session: &AppSession,
|
||||||
) -> Option<(OverlayState, Box<dyn OverlayBackend>)> {
|
) -> (OverlayState, Box<dyn OverlayBackend>) {
|
||||||
let state = OverlayState {
|
let state = OverlayState {
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
show_hide,
|
show_hide,
|
||||||
@@ -159,5 +158,5 @@ pub fn new_mirror(
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
|
|
||||||
Some((state, backend))
|
(state, backend)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
use vulkano::{
|
use vulkano::{
|
||||||
command_buffer::CommandBufferUsage,
|
command_buffer::CommandBufferUsage,
|
||||||
|
format::Format,
|
||||||
image::{sampler::Filter, view::ImageView, Image},
|
image::{sampler::Filter, view::ImageView, Image},
|
||||||
pipeline::graphics::color_blend::AttachmentBlend,
|
pipeline::graphics::color_blend::AttachmentBlend,
|
||||||
};
|
};
|
||||||
@@ -26,7 +27,7 @@ use wlx_capture::{
|
|||||||
use {
|
use {
|
||||||
crate::config_io,
|
crate::config_io,
|
||||||
std::error::Error,
|
std::error::Error,
|
||||||
std::{ops::Deref, path::PathBuf, task},
|
std::{path::PathBuf, task},
|
||||||
wlx_capture::pipewire::PipewireCapture,
|
wlx_capture::pipewire::PipewireCapture,
|
||||||
wlx_capture::pipewire::PipewireSelectScreenResult,
|
wlx_capture::pipewire::PipewireSelectScreenResult,
|
||||||
};
|
};
|
||||||
@@ -64,7 +65,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "wayland")]
|
#[cfg(feature = "wayland")]
|
||||||
pub(crate) type WlxClientAlias = wlx_capture::wayland::WlxClient;
|
pub type WlxClientAlias = wlx_capture::wayland::WlxClient;
|
||||||
|
|
||||||
#[cfg(not(feature = "wayland"))]
|
#[cfg(not(feature = "wayland"))]
|
||||||
pub(crate) type WlxClientAlias = ();
|
pub(crate) type WlxClientAlias = ();
|
||||||
@@ -91,7 +92,7 @@ pub struct ScreenInteractionHandler {
|
|||||||
mouse_transform: Affine2,
|
mouse_transform: Affine2,
|
||||||
}
|
}
|
||||||
impl ScreenInteractionHandler {
|
impl ScreenInteractionHandler {
|
||||||
fn new(pos: Vec2, size: Vec2, transform: Transform) -> ScreenInteractionHandler {
|
fn new(pos: Vec2, size: Vec2, transform: Transform) -> Self {
|
||||||
let transform = match transform {
|
let transform = match transform {
|
||||||
Transform::_90 | Transform::Flipped90 => Affine2::from_cols(
|
Transform::_90 | Transform::Flipped90 => Affine2::from_cols(
|
||||||
vec2(0., size.y),
|
vec2(0., size.y),
|
||||||
@@ -111,7 +112,7 @@ impl ScreenInteractionHandler {
|
|||||||
_ => Affine2::from_cols(vec2(size.x, 0.), vec2(0., size.y), pos),
|
_ => Affine2::from_cols(vec2(size.x, 0.), vec2(0., size.y), pos),
|
||||||
};
|
};
|
||||||
|
|
||||||
ScreenInteractionHandler {
|
Self {
|
||||||
mouse_transform: transform,
|
mouse_transform: transform,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -127,7 +128,7 @@ impl InteractionHandler for ScreenInteractionHandler {
|
|||||||
{
|
{
|
||||||
let pos = self.mouse_transform.transform_point2(hit.uv);
|
let pos = self.mouse_transform.transform_point2(hit.uv);
|
||||||
app.hid_provider.mouse_move(pos);
|
app.hid_provider.mouse_move(pos);
|
||||||
set_next_move(app.session.config.mouse_move_interval_ms as u64);
|
set_next_move(u64::from(app.session.config.mouse_move_interval_ms));
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@@ -139,7 +140,7 @@ impl InteractionHandler for ScreenInteractionHandler {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if pressed {
|
if pressed {
|
||||||
set_next_move(app.session.config.click_freeze_time_ms as u64);
|
set_next_move(u64::from(app.session.config.click_freeze_time_ms));
|
||||||
}
|
}
|
||||||
|
|
||||||
app.hid_provider.send_button(btn, pressed);
|
app.hid_provider.send_button(btn, pressed);
|
||||||
@@ -152,7 +153,7 @@ impl InteractionHandler for ScreenInteractionHandler {
|
|||||||
}
|
}
|
||||||
fn on_scroll(&mut self, app: &mut AppState, _hit: &PointerHit, delta_y: f32, delta_x: f32) {
|
fn on_scroll(&mut self, app: &mut AppState, _hit: &PointerHit, delta_y: f32, delta_x: f32) {
|
||||||
app.hid_provider
|
app.hid_provider
|
||||||
.wheel((delta_y * 64.) as i32, (delta_x * 64.) as i32)
|
.wheel((delta_y * 64.) as i32, (delta_x * 64.) as i32);
|
||||||
}
|
}
|
||||||
fn on_left(&mut self, _app: &mut AppState, _hand: usize) {}
|
fn on_left(&mut self, _app: &mut AppState, _hand: usize) {}
|
||||||
}
|
}
|
||||||
@@ -165,7 +166,7 @@ struct ScreenPipeline {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ScreenPipeline {
|
impl ScreenPipeline {
|
||||||
fn new(extent: &[u32; 3], app: &mut AppState) -> anyhow::Result<ScreenPipeline> {
|
fn new(extent: &[u32; 3], app: &mut AppState) -> anyhow::Result<Self> {
|
||||||
let Ok(shaders) = app.graphics.shared_shaders.read() else {
|
let Ok(shaders) = app.graphics.shared_shaders.read() else {
|
||||||
return Err(anyhow::anyhow!("Could not lock shared shaders for reading"));
|
return Err(anyhow::anyhow!("Could not lock shared shaders for reading"));
|
||||||
};
|
};
|
||||||
@@ -179,7 +180,7 @@ impl ScreenPipeline {
|
|||||||
|
|
||||||
let extentf = [extent[0] as f32, extent[1] as f32];
|
let extentf = [extent[0] as f32, extent[1] as f32];
|
||||||
|
|
||||||
Ok(ScreenPipeline {
|
Ok(Self {
|
||||||
mouse: None,
|
mouse: None,
|
||||||
pipeline,
|
pipeline,
|
||||||
extentf,
|
extentf,
|
||||||
@@ -236,15 +237,15 @@ impl ScreenPipeline {
|
|||||||
let vertex_buffer = app.graphics.upload_verts(
|
let vertex_buffer = app.graphics.upload_verts(
|
||||||
self.extentf[0],
|
self.extentf[0],
|
||||||
self.extentf[1],
|
self.extentf[1],
|
||||||
mouse.x * self.extentf[0] - half_size,
|
mouse.x.mul_add(self.extentf[0], -half_size),
|
||||||
mouse.y * self.extentf[1] - half_size,
|
mouse.y.mul_add(self.extentf[1], -half_size),
|
||||||
size,
|
size,
|
||||||
size,
|
size,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let set0 = self
|
let set0 = self
|
||||||
.pipeline
|
.pipeline
|
||||||
.uniform_sampler(0, mouse_view.clone(), Filter::Nearest)?;
|
.uniform_sampler(0, mouse_view, Filter::Nearest)?;
|
||||||
|
|
||||||
let pass = self.pipeline.create_pass(
|
let pass = self.pipeline.create_pass(
|
||||||
self.extentf,
|
self.extentf,
|
||||||
@@ -275,8 +276,8 @@ impl ScreenRenderer {
|
|||||||
pub fn new_raw(
|
pub fn new_raw(
|
||||||
name: Arc<str>,
|
name: Arc<str>,
|
||||||
capture: Box<dyn WlxCapture<WlxCaptureIn, WlxCaptureOut>>,
|
capture: Box<dyn WlxCapture<WlxCaptureIn, WlxCaptureOut>>,
|
||||||
) -> ScreenRenderer {
|
) -> Self {
|
||||||
ScreenRenderer {
|
Self {
|
||||||
name,
|
name,
|
||||||
capture,
|
capture,
|
||||||
pipeline: None,
|
pipeline: None,
|
||||||
@@ -286,11 +287,11 @@ impl ScreenRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "wayland")]
|
#[cfg(feature = "wayland")]
|
||||||
pub fn new_wlr_dmabuf(output: &WlxOutput) -> Option<ScreenRenderer> {
|
pub fn new_wlr_dmabuf(output: &WlxOutput) -> Option<Self> {
|
||||||
let client = WlxClient::new()?;
|
let client = WlxClient::new()?;
|
||||||
let capture = WlrDmabufCapture::new(client, output.id);
|
let capture = WlrDmabufCapture::new(client, output.id);
|
||||||
|
|
||||||
Some(ScreenRenderer {
|
Some(Self {
|
||||||
name: output.name.clone(),
|
name: output.name.clone(),
|
||||||
capture: Box::new(capture),
|
capture: Box::new(capture),
|
||||||
pipeline: None,
|
pipeline: None,
|
||||||
@@ -300,11 +301,11 @@ impl ScreenRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "wayland")]
|
#[cfg(feature = "wayland")]
|
||||||
pub fn new_wlr_screencopy(output: &WlxOutput) -> Option<ScreenRenderer> {
|
pub fn new_wlr_screencopy(output: &WlxOutput) -> Option<Self> {
|
||||||
let client = WlxClient::new()?;
|
let client = WlxClient::new()?;
|
||||||
let capture = WlrScreencopyCapture::new(client, output.id);
|
let capture = WlrScreencopyCapture::new(client, output.id);
|
||||||
|
|
||||||
Some(ScreenRenderer {
|
Some(Self {
|
||||||
name: output.name.clone(),
|
name: output.name.clone(),
|
||||||
capture: Box::new(capture),
|
capture: Box::new(capture),
|
||||||
pipeline: None,
|
pipeline: None,
|
||||||
@@ -318,10 +319,7 @@ impl ScreenRenderer {
|
|||||||
output: &WlxOutput,
|
output: &WlxOutput,
|
||||||
token: Option<&str>,
|
token: Option<&str>,
|
||||||
session: &AppSession,
|
session: &AppSession,
|
||||||
) -> anyhow::Result<(
|
) -> anyhow::Result<(Self, Option<String> /* pipewire restore token */)> {
|
||||||
ScreenRenderer,
|
|
||||||
Option<String>, /* pipewire restore token */
|
|
||||||
)> {
|
|
||||||
let name = output.name.clone();
|
let name = output.name.clone();
|
||||||
let embed_mouse = !session.config.double_cursor_fix;
|
let embed_mouse = !session.config.double_cursor_fix;
|
||||||
|
|
||||||
@@ -346,7 +344,7 @@ impl ScreenRenderer {
|
|||||||
let capture = PipewireCapture::new(name, node_id);
|
let capture = PipewireCapture::new(name, node_id);
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
ScreenRenderer {
|
Self {
|
||||||
name: output.name.clone(),
|
name: output.name.clone(),
|
||||||
capture: Box::new(capture),
|
capture: Box::new(capture),
|
||||||
pipeline: None,
|
pipeline: None,
|
||||||
@@ -358,10 +356,10 @@ impl ScreenRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "x11")]
|
#[cfg(feature = "x11")]
|
||||||
pub fn new_xshm(screen: Arc<XshmScreen>) -> ScreenRenderer {
|
pub fn new_xshm(screen: Arc<XshmScreen>) -> Self {
|
||||||
let capture = XshmCapture::new(screen.clone());
|
let capture = XshmCapture::new(screen.clone());
|
||||||
|
|
||||||
ScreenRenderer {
|
Self {
|
||||||
name: screen.name.clone(),
|
name: screen.name.clone(),
|
||||||
capture: Box::new(capture),
|
capture: Box::new(capture),
|
||||||
pipeline: None,
|
pipeline: None,
|
||||||
@@ -384,6 +382,39 @@ pub struct WlxCaptureOut {
|
|||||||
mouse: Option<MouseMeta>,
|
mouse: Option<MouseMeta>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn upload_image(
|
||||||
|
me: &WlxCaptureIn,
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
format: Format,
|
||||||
|
data: &[u8],
|
||||||
|
) -> Option<Arc<Image>> {
|
||||||
|
let mut upload = match me
|
||||||
|
.graphics
|
||||||
|
.create_command_buffer(CommandBufferUsage::OneTimeSubmit)
|
||||||
|
{
|
||||||
|
Ok(x) => x,
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("{}: Could not create vkCommandBuffer: {:?}", me.name, e);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let image = match upload.texture2d_raw(width, height, format, data) {
|
||||||
|
Ok(x) => x,
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("{}: Could not create vkImage: {:?}", me.name, e);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(e) = upload.build_and_execute_now() {
|
||||||
|
log::error!("{}: Could not execute upload: {:?}", me.name, e);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(image)
|
||||||
|
}
|
||||||
|
|
||||||
fn receive_callback(me: &WlxCaptureIn, frame: wlx_frame::WlxFrame) -> Option<WlxCaptureOut> {
|
fn receive_callback(me: &WlxCaptureIn, frame: wlx_frame::WlxFrame) -> Option<WlxCaptureOut> {
|
||||||
match frame {
|
match frame {
|
||||||
WlxFrame::Dmabuf(frame) => {
|
WlxFrame::Dmabuf(frame) => {
|
||||||
@@ -400,11 +431,7 @@ fn receive_callback(me: &WlxCaptureIn, frame: wlx_frame::WlxFrame) -> Option<Wlx
|
|||||||
mouse: None,
|
mouse: None,
|
||||||
}),
|
}),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!(
|
log::error!("{}: Failed to create DMA-buf vkImage: {}", me.name, e);
|
||||||
"{}: Failed to create DMA-buf vkImage: {}",
|
|
||||||
me.name,
|
|
||||||
e.to_string()
|
|
||||||
);
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -424,7 +451,7 @@ fn receive_callback(me: &WlxCaptureIn, frame: wlx_frame::WlxFrame) -> Option<Wlx
|
|||||||
};
|
};
|
||||||
|
|
||||||
let len = frame.plane.stride as usize * frame.format.height as usize;
|
let len = frame.plane.stride as usize * frame.format.height as usize;
|
||||||
let offset = frame.plane.offset as i64;
|
let offset = i64::from(frame.plane.offset);
|
||||||
|
|
||||||
let map = unsafe {
|
let map = unsafe {
|
||||||
libc::mmap(
|
libc::mmap(
|
||||||
@@ -437,35 +464,15 @@ fn receive_callback(me: &WlxCaptureIn, frame: wlx_frame::WlxFrame) -> Option<Wlx
|
|||||||
)
|
)
|
||||||
} as *const u8;
|
} as *const u8;
|
||||||
|
|
||||||
let pixels = unsafe { slice::from_raw_parts(map, len) };
|
let data = unsafe { slice::from_raw_parts(map, len) };
|
||||||
|
|
||||||
let mut upload = match me
|
let image = {
|
||||||
.graphics
|
let maybe_image =
|
||||||
.create_command_buffer(CommandBufferUsage::OneTimeSubmit)
|
upload_image(me, frame.format.width, frame.format.height, format, data);
|
||||||
{
|
|
||||||
Ok(x) => x,
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("{}: Could not create vkCommandBuffer: {:?}", me.name, e);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let image =
|
|
||||||
match upload.texture2d_raw(frame.format.width, frame.format.height, format, pixels)
|
|
||||||
{
|
|
||||||
Ok(x) => x,
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("{}: Could not create vkImage: {:?}", me.name, e);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Err(e) = upload.build_and_execute_now() {
|
|
||||||
log::error!("{}: Could not execute upload: {:?}", me.name, e);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe { libc::munmap(map as *mut _, len) };
|
unsafe { libc::munmap(map as *mut _, len) };
|
||||||
|
maybe_image
|
||||||
|
}?;
|
||||||
|
|
||||||
Some(WlxCaptureOut {
|
Some(WlxCaptureOut {
|
||||||
image,
|
image,
|
||||||
@@ -484,33 +491,8 @@ fn receive_callback(me: &WlxCaptureIn, frame: wlx_frame::WlxFrame) -> Option<Wlx
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut upload = match me
|
let data = unsafe { slice::from_raw_parts(frame.ptr as *const u8, frame.size) };
|
||||||
.graphics
|
let image = upload_image(me, frame.format.width, frame.format.height, format, data)?;
|
||||||
.create_command_buffer(CommandBufferUsage::OneTimeSubmit)
|
|
||||||
{
|
|
||||||
Ok(x) => x,
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("{}: Could not create vkCommandBuffer: {:?}", me.name, e);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let pixels = unsafe { slice::from_raw_parts(frame.ptr as *const u8, frame.size) };
|
|
||||||
|
|
||||||
let image =
|
|
||||||
match upload.texture2d_raw(frame.format.width, frame.format.height, format, pixels)
|
|
||||||
{
|
|
||||||
Ok(x) => x,
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("{}: Could not create vkImage: {:?}", me.name, e);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Err(e) = upload.build_and_execute_now() {
|
|
||||||
log::error!("{}: Could not execute upload: {:?}", me.name, e);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(WlxCaptureOut {
|
Some(WlxCaptureOut {
|
||||||
image,
|
image,
|
||||||
@@ -547,7 +529,7 @@ impl OverlayRenderer for ScreenRenderer {
|
|||||||
return vec![];
|
return vec![];
|
||||||
}
|
}
|
||||||
if !allow_dmabuf {
|
if !allow_dmabuf {
|
||||||
log::info!("Not using DMA-buf capture due to {}", capture_method);
|
log::info!("Not using DMA-buf capture due to {capture_method}");
|
||||||
return vec![];
|
return vec![];
|
||||||
}
|
}
|
||||||
log::warn!("Using DMA-buf capture. If screens are blank for you, switch to SHM using:");
|
log::warn!("Using DMA-buf capture. If screens are blank for you, switch to SHM using:");
|
||||||
@@ -604,7 +586,7 @@ impl OverlayRenderer for ScreenRenderer {
|
|||||||
return Ok(ShouldRender::Unable);
|
return Ok(ShouldRender::Unable);
|
||||||
}
|
}
|
||||||
|
|
||||||
for frame in self.capture.receive().into_iter() {
|
if let Some(frame) = self.capture.receive() {
|
||||||
self.cur_frame = Some(frame);
|
self.cur_frame = Some(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -623,7 +605,7 @@ impl OverlayRenderer for ScreenRenderer {
|
|||||||
upload.build_and_execute_now()?;
|
upload.build_and_execute_now()?;
|
||||||
pipeline
|
pipeline
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
if self.cur_frame.is_some() {
|
if self.cur_frame.is_some() {
|
||||||
Ok(ShouldRender::Should)
|
Ok(ShouldRender::Should)
|
||||||
@@ -669,6 +651,7 @@ impl OverlayRenderer for ScreenRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "wayland")]
|
#[cfg(feature = "wayland")]
|
||||||
|
#[allow(clippy::useless_let_if_seq)]
|
||||||
pub fn create_screen_renderer_wl(
|
pub fn create_screen_renderer_wl(
|
||||||
output: &WlxOutput,
|
output: &WlxOutput,
|
||||||
has_wlr_dmabuf: bool,
|
has_wlr_dmabuf: bool,
|
||||||
@@ -690,17 +673,15 @@ pub fn create_screen_renderer_wl(
|
|||||||
if capture.is_none() {
|
if capture.is_none() {
|
||||||
log::info!("{}: Using Pipewire capture", &output.name);
|
log::info!("{}: Using Pipewire capture", &output.name);
|
||||||
|
|
||||||
let display_name = output.name.deref();
|
let display_name = &*output.name;
|
||||||
|
|
||||||
// Find existing token by display
|
// Find existing token by display
|
||||||
let token = pw_token_store.arc_get(display_name).map(|s| s.as_str());
|
let token = pw_token_store
|
||||||
|
.arc_get(display_name)
|
||||||
|
.map(std::string::String::as_str);
|
||||||
|
|
||||||
if let Some(t) = token {
|
if let Some(t) = token {
|
||||||
log::info!(
|
log::info!("Found existing Pipewire token for display {display_name}: {t}");
|
||||||
"Found existing Pipewire token for display {}: {}",
|
|
||||||
display_name,
|
|
||||||
t
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match ScreenRenderer::new_pw(output, token, session) {
|
match ScreenRenderer::new_pw(output, token, session) {
|
||||||
@@ -709,7 +690,7 @@ pub fn create_screen_renderer_wl(
|
|||||||
|
|
||||||
if let Some(token) = restore_token {
|
if let Some(token) = restore_token {
|
||||||
if pw_token_store.arc_set(display_name.into(), token.clone()) {
|
if pw_token_store.arc_set(display_name.into(), token.clone()) {
|
||||||
log::info!("Adding Pipewire token {}", token);
|
log::info!("Adding Pipewire token {token}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -773,7 +754,7 @@ fn create_screen_state(
|
|||||||
};
|
};
|
||||||
|
|
||||||
OverlayState {
|
OverlayState {
|
||||||
name: name.clone(),
|
name,
|
||||||
keyboard_focus: Some(KeyboardFocus::PhysicalScreen),
|
keyboard_focus: Some(KeyboardFocus::PhysicalScreen),
|
||||||
grabbable: true,
|
grabbable: true,
|
||||||
recenter: true,
|
recenter: true,
|
||||||
@@ -816,23 +797,19 @@ pub fn load_pw_token_config() -> Result<PwTokenMap, Box<dyn Error>> {
|
|||||||
Ok(conf.pw_tokens)
|
Ok(conf.pw_tokens)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct ScreenCreateData {
|
pub struct ScreenCreateData {
|
||||||
pub screens: Vec<(ScreenMeta, OverlayState, Box<SplitOverlayBackend>)>,
|
pub screens: Vec<(ScreenMeta, OverlayState, Box<SplitOverlayBackend>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "wayland"))]
|
#[cfg(not(feature = "wayland"))]
|
||||||
pub fn create_screens_wayland(
|
pub fn create_screens_wayland(_wl: &mut WlxClientAlias, _app: &AppState) -> ScreenCreateData {
|
||||||
_wl: &mut WlxClientAlias,
|
ScreenCreateData {
|
||||||
_app: &AppState,
|
screens: Vec::default(),
|
||||||
) -> anyhow::Result<ScreenCreateData> {
|
}
|
||||||
anyhow::bail!("Wayland support not enabled")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "wayland")]
|
#[cfg(feature = "wayland")]
|
||||||
pub fn create_screens_wayland(
|
pub fn create_screens_wayland(wl: &mut WlxClientAlias, app: &mut AppState) -> ScreenCreateData {
|
||||||
wl: &mut WlxClientAlias,
|
|
||||||
app: &mut AppState,
|
|
||||||
) -> anyhow::Result<ScreenCreateData> {
|
|
||||||
let mut screens = vec![];
|
let mut screens = vec![];
|
||||||
|
|
||||||
// Load existing Pipewire tokens from file
|
// Load existing Pipewire tokens from file
|
||||||
@@ -842,7 +819,7 @@ pub fn create_screens_wayland(
|
|||||||
let has_wlr_dmabuf = wl.maybe_wlr_dmabuf_mgr.is_some();
|
let has_wlr_dmabuf = wl.maybe_wlr_dmabuf_mgr.is_some();
|
||||||
let has_wlr_screencopy = wl.maybe_wlr_screencopy_mgr.is_some();
|
let has_wlr_screencopy = wl.maybe_wlr_screencopy_mgr.is_some();
|
||||||
|
|
||||||
for (id, output) in wl.outputs.iter() {
|
for (id, output) in &wl.outputs {
|
||||||
if app.screens.iter().any(|s| s.name == output.name) {
|
if app.screens.iter().any(|s| s.name == output.name) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -886,7 +863,7 @@ pub fn create_screens_wayland(
|
|||||||
if pw_tokens_copy != pw_tokens {
|
if pw_tokens_copy != pw_tokens {
|
||||||
// Token list changed, re-create token config file
|
// Token list changed, re-create token config file
|
||||||
if let Err(err) = save_pw_token_config(pw_tokens) {
|
if let Err(err) = save_pw_token_config(pw_tokens) {
|
||||||
log::error!("Failed to save Pipewire token config: {}", err);
|
log::error!("Failed to save Pipewire token config: {err}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -898,7 +875,7 @@ pub fn create_screens_wayland(
|
|||||||
app.hid_provider
|
app.hid_provider
|
||||||
.set_desktop_origin(vec2(origin.0 as f32, origin.1 as f32));
|
.set_desktop_origin(vec2(origin.0 as f32, origin.1 as f32));
|
||||||
|
|
||||||
Ok(ScreenCreateData { screens })
|
ScreenCreateData { screens }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "x11"))]
|
#[cfg(not(feature = "x11"))]
|
||||||
@@ -918,7 +895,7 @@ pub fn create_screens_x11pw(app: &mut AppState) -> anyhow::Result<ScreenCreateDa
|
|||||||
// Load existing Pipewire tokens from file
|
// Load existing Pipewire tokens from file
|
||||||
let mut pw_tokens: PwTokenMap = load_pw_token_config().unwrap_or_default();
|
let mut pw_tokens: PwTokenMap = load_pw_token_config().unwrap_or_default();
|
||||||
let pw_tokens_copy = pw_tokens.clone();
|
let pw_tokens_copy = pw_tokens.clone();
|
||||||
let token = pw_tokens.arc_get("x11").map(|s| s.as_str());
|
let token = pw_tokens.arc_get("x11").map(std::string::String::as_str);
|
||||||
let embed_mouse = !app.session.config.double_cursor_fix;
|
let embed_mouse = !app.session.config.double_cursor_fix;
|
||||||
|
|
||||||
let select_screen_result = select_pw_screen(
|
let select_screen_result = select_pw_screen(
|
||||||
@@ -932,13 +909,13 @@ pub fn create_screens_x11pw(app: &mut AppState) -> anyhow::Result<ScreenCreateDa
|
|||||||
|
|
||||||
if let Some(restore_token) = select_screen_result.restore_token {
|
if let Some(restore_token) = select_screen_result.restore_token {
|
||||||
if pw_tokens.arc_set("x11".into(), restore_token.clone()) {
|
if pw_tokens.arc_set("x11".into(), restore_token.clone()) {
|
||||||
log::info!("Adding Pipewire token {}", restore_token);
|
log::info!("Adding Pipewire token {restore_token}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if pw_tokens_copy != pw_tokens {
|
if pw_tokens_copy != pw_tokens {
|
||||||
// Token list changed, re-create token config file
|
// Token list changed, re-create token config file
|
||||||
if let Err(err) = save_pw_token_config(pw_tokens) {
|
if let Err(err) = save_pw_token_config(pw_tokens) {
|
||||||
log::error!("Failed to save Pipewire token config: {}", err);
|
log::error!("Failed to save Pipewire token config: {err}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1064,6 +1041,7 @@ pub enum Transform {
|
|||||||
_90,
|
_90,
|
||||||
_180,
|
_180,
|
||||||
_270,
|
_270,
|
||||||
|
Flipped,
|
||||||
Flipped90,
|
Flipped90,
|
||||||
Flipped180,
|
Flipped180,
|
||||||
Flipped270,
|
Flipped270,
|
||||||
@@ -1071,17 +1049,16 @@ pub enum Transform {
|
|||||||
|
|
||||||
#[cfg(feature = "wayland")]
|
#[cfg(feature = "wayland")]
|
||||||
impl From<wl_output::Transform> for Transform {
|
impl From<wl_output::Transform> for Transform {
|
||||||
fn from(t: wl_output::Transform) -> Transform {
|
fn from(t: wl_output::Transform) -> Self {
|
||||||
match t {
|
match t {
|
||||||
wl_output::Transform::Normal => Transform::Normal,
|
wl_output::Transform::_90 => Self::_90,
|
||||||
wl_output::Transform::_90 => Transform::_90,
|
wl_output::Transform::_180 => Self::_180,
|
||||||
wl_output::Transform::_180 => Transform::_180,
|
wl_output::Transform::_270 => Self::_270,
|
||||||
wl_output::Transform::_270 => Transform::_270,
|
wl_output::Transform::Flipped => Self::Flipped,
|
||||||
wl_output::Transform::Flipped => Transform::Flipped180,
|
wl_output::Transform::Flipped90 => Self::Flipped90,
|
||||||
wl_output::Transform::Flipped90 => Transform::Flipped90,
|
wl_output::Transform::Flipped180 => Self::Flipped180,
|
||||||
wl_output::Transform::Flipped180 => Transform::Flipped180,
|
wl_output::Transform::Flipped270 => Self::Flipped270,
|
||||||
wl_output::Transform::Flipped270 => Transform::Flipped270,
|
_ => Self::Normal,
|
||||||
_ => Transform::Normal,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1093,7 +1070,7 @@ fn extent_from_format(fmt: FrameFormat, config: &GeneralConfig) -> [u32; 3] {
|
|||||||
fn extent_from_res(width: u32, height: u32, config: &GeneralConfig) -> [u32; 3] {
|
fn extent_from_res(width: u32, height: u32, config: &GeneralConfig) -> [u32; 3] {
|
||||||
// screens above a certain resolution will have severe aliasing
|
// screens above a certain resolution will have severe aliasing
|
||||||
let height_limit = if config.screen_render_down {
|
let height_limit = if config.screen_render_down {
|
||||||
config.screen_max_height.min(2560) as u32
|
u32::from(config.screen_max_height.min(2560))
|
||||||
} else {
|
} else {
|
||||||
2560
|
2560
|
||||||
};
|
};
|
||||||
@@ -1111,7 +1088,6 @@ fn affine_from_format(format: &FrameFormat) -> Affine3A {
|
|||||||
};
|
};
|
||||||
|
|
||||||
match format.transform {
|
match format.transform {
|
||||||
wlx_frame::Transform::Normal => Affine3A::IDENTITY,
|
|
||||||
wlx_frame::Transform::Rotated90 => Affine3A::from_rotation_z(-PI / 2.0),
|
wlx_frame::Transform::Rotated90 => Affine3A::from_rotation_z(-PI / 2.0),
|
||||||
wlx_frame::Transform::Rotated180 => Affine3A::from_rotation_z(PI),
|
wlx_frame::Transform::Rotated180 => Affine3A::from_rotation_z(PI),
|
||||||
wlx_frame::Transform::Rotated270 => Affine3A::from_rotation_z(PI / 2.0),
|
wlx_frame::Transform::Rotated270 => Affine3A::from_rotation_z(PI / 2.0),
|
||||||
@@ -1125,7 +1101,7 @@ fn affine_from_format(format: &FrameFormat) -> Affine3A {
|
|||||||
wlx_frame::Transform::Flipped270 => {
|
wlx_frame::Transform::Flipped270 => {
|
||||||
Affine3A::from_scale(FLIP_X) * Affine3A::from_rotation_z(PI / 2.0)
|
Affine3A::from_scale(FLIP_X) * Affine3A::from_rotation_z(PI / 2.0)
|
||||||
}
|
}
|
||||||
wlx_frame::Transform::Undefined => Affine3A::IDENTITY,
|
_ => Affine3A::IDENTITY,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1141,9 +1117,9 @@ fn best_match<'a>(
|
|||||||
return best;
|
return best;
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut best_dist = best
|
let mut best_dist = best.map_or(i32::MAX, |b| {
|
||||||
.map(|b| (b.monitor.x() - position.0).abs() + (b.monitor.y() - position.1).abs())
|
(b.monitor.x() - position.0).abs() + (b.monitor.y() - position.1).abs()
|
||||||
.unwrap_or(i32::MAX);
|
});
|
||||||
for stream in streams {
|
for stream in streams {
|
||||||
log::debug!("checking: {:?}", stream.monitor);
|
log::debug!("checking: {:?}", stream.monitor);
|
||||||
let dist =
|
let dist =
|
||||||
@@ -1158,6 +1134,7 @@ fn best_match<'a>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "pipewire")]
|
#[cfg(feature = "pipewire")]
|
||||||
|
#[allow(clippy::fn_params_excessive_bools)]
|
||||||
fn select_pw_screen(
|
fn select_pw_screen(
|
||||||
instructions: &str,
|
instructions: &str,
|
||||||
token: Option<&str>,
|
token: Option<&str>,
|
||||||
@@ -1181,7 +1158,7 @@ fn select_pw_screen(
|
|||||||
task::Poll::Ready(result) => return result,
|
task::Poll::Ready(result) => return result,
|
||||||
task::Poll::Pending => {
|
task::Poll::Pending => {
|
||||||
if Instant::now() >= print_at {
|
if Instant::now() >= print_at {
|
||||||
log::info!("{}", instructions);
|
log::info!("{instructions}");
|
||||||
if let Ok(sender) = DbusNotificationSender::new() {
|
if let Ok(sender) = DbusNotificationSender::new() {
|
||||||
if let Ok(id) = sender.notify_send(instructions, "", 2, 0, 0, true) {
|
if let Ok(id) = sender.notify_send(instructions, "", 2, 0, 0, true) {
|
||||||
notify = Some((sender, id));
|
notify = Some((sender, id));
|
||||||
@@ -1193,7 +1170,6 @@ fn select_pw_screen(
|
|||||||
std::thread::sleep(Duration::from_millis(10));
|
std::thread::sleep(Duration::from_millis(10));
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,8 +46,8 @@ pub struct Toast {
|
|||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
impl Toast {
|
impl Toast {
|
||||||
pub fn new(topic: ToastTopic, title: Arc<str>, body: Arc<str>) -> Self {
|
pub const fn new(topic: ToastTopic, title: Arc<str>, body: Arc<str>) -> Self {
|
||||||
Toast {
|
Self {
|
||||||
title,
|
title,
|
||||||
body,
|
body,
|
||||||
opacity: 1.0,
|
opacity: 1.0,
|
||||||
@@ -56,15 +56,15 @@ impl Toast {
|
|||||||
topic,
|
topic,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn with_timeout(mut self, timeout: f32) -> Self {
|
pub const fn with_timeout(mut self, timeout: f32) -> Self {
|
||||||
self.timeout = timeout;
|
self.timeout = timeout;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
pub fn with_opacity(mut self, opacity: f32) -> Self {
|
pub const fn with_opacity(mut self, opacity: f32) -> Self {
|
||||||
self.opacity = opacity;
|
self.opacity = opacity;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
pub fn with_sound(mut self, sound: bool) -> Self {
|
pub const fn with_sound(mut self, sound: bool) -> Self {
|
||||||
self.sound = sound;
|
self.sound = sound;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@@ -93,7 +93,7 @@ impl Toast {
|
|||||||
// frame, only the first one gets created
|
// frame, only the first one gets created
|
||||||
app.tasks.enqueue_at(
|
app.tasks.enqueue_at(
|
||||||
TaskType::CreateOverlay(
|
TaskType::CreateOverlay(
|
||||||
selector.clone(),
|
selector,
|
||||||
Box::new(move |app| {
|
Box::new(move |app| {
|
||||||
let mut maybe_toast = new_toast(self, app);
|
let mut maybe_toast = new_toast(self, app);
|
||||||
if let Some((state, _)) = maybe_toast.as_mut() {
|
if let Some((state, _)) = maybe_toast.as_mut() {
|
||||||
@@ -139,13 +139,19 @@ fn new_toast(toast: Toast, app: &mut AppState) -> Option<(OverlayState, Box<dyn
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let title = if !toast.title.is_empty() {
|
let title = if toast.title.is_empty() {
|
||||||
toast.title
|
|
||||||
} else {
|
|
||||||
"Notification".into()
|
"Notification".into()
|
||||||
|
} else {
|
||||||
|
toast.title
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut size = if !toast.body.is_empty() {
|
let mut size = if toast.body.is_empty() {
|
||||||
|
let (w, h) = app
|
||||||
|
.fc
|
||||||
|
.get_text_size(&title, FONT_SIZE, app.graphics.clone())
|
||||||
|
.ok()?;
|
||||||
|
(w, h + 20.)
|
||||||
|
} else {
|
||||||
let (w0, _) = app
|
let (w0, _) = app
|
||||||
.fc
|
.fc
|
||||||
.get_text_size(&title, FONT_SIZE, app.graphics.clone())
|
.get_text_size(&title, FONT_SIZE, app.graphics.clone())
|
||||||
@@ -155,12 +161,6 @@ fn new_toast(toast: Toast, app: &mut AppState) -> Option<(OverlayState, Box<dyn
|
|||||||
.get_text_size(&toast.body, FONT_SIZE, app.graphics.clone())
|
.get_text_size(&toast.body, FONT_SIZE, app.graphics.clone())
|
||||||
.ok()?;
|
.ok()?;
|
||||||
(w0.max(w1), h1 + 50.)
|
(w0.max(w1), h1 + 50.)
|
||||||
} else {
|
|
||||||
let (w, h) = app
|
|
||||||
.fc
|
|
||||||
.get_text_size(&title, FONT_SIZE, app.graphics.clone())
|
|
||||||
.ok()?;
|
|
||||||
(w, h + 20.)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let og_width = size.0;
|
let og_width = size.0;
|
||||||
@@ -180,15 +180,15 @@ fn new_toast(toast: Toast, app: &mut AppState) -> Option<(OverlayState, Box<dyn
|
|||||||
canvas.bg_color = color_parse("#1e2030").unwrap(); // want panic
|
canvas.bg_color = color_parse("#1e2030").unwrap(); // want panic
|
||||||
canvas.panel(0., 0., size.0, size.1, 16.);
|
canvas.panel(0., 0., size.0, size.1, 16.);
|
||||||
|
|
||||||
if !toast.body.is_empty() {
|
if toast.body.is_empty() {
|
||||||
|
canvas.label_centered(PADDING.0, 0., og_width, size.1, 16., title);
|
||||||
|
} else {
|
||||||
canvas.label(PADDING.0, 54., og_width, size.1 - 54., 3., toast.body);
|
canvas.label(PADDING.0, 54., og_width, size.1 - 54., 3., toast.body);
|
||||||
|
|
||||||
canvas.fg_color = color_parse("#b8c0e0").unwrap(); // want panic
|
canvas.fg_color = color_parse("#b8c0e0").unwrap(); // want panic
|
||||||
canvas.bg_color = color_parse("#24273a").unwrap(); // want panic
|
canvas.bg_color = color_parse("#24273a").unwrap(); // want panic
|
||||||
canvas.panel(0., 0., size.0, 30., 16.);
|
canvas.panel(0., 0., size.0, 30., 16.);
|
||||||
canvas.label_centered(PADDING.0, 16., og_width, FONT_SIZE as f32 + 2., 16., title);
|
canvas.label_centered(PADDING.0, 16., og_width, FONT_SIZE as f32 + 2., 16., title);
|
||||||
} else {
|
|
||||||
canvas.label_centered(PADDING.0, 0., og_width, size.1, 16., title);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let state = OverlayState {
|
let state = OverlayState {
|
||||||
@@ -218,13 +218,13 @@ pub fn error_toast<ErrorType>(app: &mut AppState, title: &str, err: ErrorType)
|
|||||||
where
|
where
|
||||||
ErrorType: std::fmt::Display + std::fmt::Debug,
|
ErrorType: std::fmt::Display + std::fmt::Debug,
|
||||||
{
|
{
|
||||||
log::error!("{}: {:?}", title, err); // More detailed version (use Debug)
|
log::error!("{title}: {err:?}"); // More detailed version (use Debug)
|
||||||
|
|
||||||
// Brief version (use Display)
|
// Brief version (use Display)
|
||||||
msg_err(app, &format!("{}: {}", title, err));
|
msg_err(app, &format!("{title}: {err}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn error_toast_str(app: &mut AppState, message: &str) {
|
pub fn error_toast_str(app: &mut AppState, message: &str) {
|
||||||
log::error!("{}", message);
|
log::error!("{message}");
|
||||||
msg_err(app, message);
|
msg_err(app, message);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ where
|
|||||||
spawn_scale: config.width,
|
spawn_scale: config.width,
|
||||||
spawn_point: state.session.config.watch_pos,
|
spawn_point: state.session.config.watch_pos,
|
||||||
spawn_rotation: state.session.config.watch_rot,
|
spawn_rotation: state.session.config.watch_rot,
|
||||||
interaction_transform: ui_transform(&config.size),
|
interaction_transform: ui_transform(config.size),
|
||||||
relative_to,
|
relative_to,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
@@ -44,7 +44,7 @@ pub fn create_watch_canvas(
|
|||||||
) -> anyhow::Result<Canvas<(), ModularData>> {
|
) -> anyhow::Result<Canvas<(), ModularData>> {
|
||||||
let config = config.unwrap_or_else(|| load_known_yaml::<ModularUiConfig>(ConfigType::Watch));
|
let config = config.unwrap_or_else(|| load_known_yaml::<ModularUiConfig>(ConfigType::Watch));
|
||||||
|
|
||||||
modular_canvas(&config.size, &config.elements, state)
|
modular_canvas(config.size, &config.elements, state)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn watch_fade<D>(app: &mut AppState, watch: &mut OverlayData<D>)
|
pub fn watch_fade<D>(app: &mut AppState, watch: &mut OverlayData<D>)
|
||||||
|
|||||||
@@ -41,14 +41,11 @@ pub struct WayVRContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl WayVRContext {
|
impl WayVRContext {
|
||||||
pub fn new(
|
pub const fn new(wvr: Rc<RefCell<WayVRData>>, display: wayvr::display::DisplayHandle) -> Self {
|
||||||
wvr: Rc<RefCell<WayVRData>>,
|
Self {
|
||||||
display: wayvr::display::DisplayHandle,
|
wayvr: wvr,
|
||||||
) -> anyhow::Result<Self> {
|
|
||||||
Ok(Self {
|
|
||||||
wayvr: wvr.clone(),
|
|
||||||
display,
|
display,
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,7 +64,7 @@ pub struct WayVRData {
|
|||||||
impl WayVRData {
|
impl WayVRData {
|
||||||
pub fn new(config: wayvr::Config) -> anyhow::Result<Self> {
|
pub fn new(config: wayvr::Config) -> anyhow::Result<Self> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
display_handle_map: Default::default(),
|
display_handle_map: HashMap::default(),
|
||||||
data: WayVR::new(config)?,
|
data: WayVR::new(config)?,
|
||||||
overlays_to_create: Vec::new(),
|
overlays_to_create: Vec::new(),
|
||||||
dashboard_executed: false,
|
dashboard_executed: false,
|
||||||
@@ -87,7 +84,7 @@ impl WayVRData {
|
|||||||
.any(|d| d.obj.name == candidate)
|
.any(|d| d.obj.name == candidate)
|
||||||
{
|
{
|
||||||
if num > 0 {
|
if num > 0 {
|
||||||
candidate = format!("{} ({})", candidate, num);
|
candidate = format!("{candidate} ({num})");
|
||||||
}
|
}
|
||||||
num += 1;
|
num += 1;
|
||||||
}
|
}
|
||||||
@@ -102,7 +99,7 @@ pub struct WayVRInteractionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl WayVRInteractionHandler {
|
impl WayVRInteractionHandler {
|
||||||
pub fn new(context: Rc<RefCell<WayVRContext>>, mouse_transform: Affine2) -> Self {
|
pub const fn new(context: Rc<RefCell<WayVRContext>>, mouse_transform: Affine2) -> Self {
|
||||||
Self {
|
Self {
|
||||||
context,
|
context,
|
||||||
mouse_transform,
|
mouse_transform,
|
||||||
@@ -122,8 +119,8 @@ impl InteractionHandler for WayVRInteractionHandler {
|
|||||||
|
|
||||||
if let Some(disp) = wayvr.state.displays.get(&ctx.display) {
|
if let Some(disp) = wayvr.state.displays.get(&ctx.display) {
|
||||||
let pos = self.mouse_transform.transform_point2(hit.uv);
|
let pos = self.mouse_transform.transform_point2(hit.uv);
|
||||||
let x = ((pos.x * disp.width as f32) as i32).max(0);
|
let x = ((pos.x * f32::from(disp.width)) as i32).max(0);
|
||||||
let y = ((pos.y * disp.height as f32) as i32).max(0);
|
let y = ((pos.y * f32::from(disp.height)) as i32).max(0);
|
||||||
|
|
||||||
let ctx = self.context.borrow();
|
let ctx = self.context.borrow();
|
||||||
wayvr.state.send_mouse_move(ctx.display, x as u32, y as u32);
|
wayvr.state.send_mouse_move(ctx.display, x as u32, y as u32);
|
||||||
@@ -151,7 +148,7 @@ impl InteractionHandler for WayVRInteractionHandler {
|
|||||||
if pressed {
|
if pressed {
|
||||||
wayvr.state.send_mouse_down(ctx.display, index);
|
wayvr.state.send_mouse_down(ctx.display, index);
|
||||||
} else {
|
} else {
|
||||||
wayvr.state.send_mouse_up(ctx.display, index);
|
wayvr.state.send_mouse_up(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -168,7 +165,7 @@ impl InteractionHandler for WayVRInteractionHandler {
|
|||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.data
|
.data
|
||||||
.state
|
.state
|
||||||
.send_mouse_scroll(ctx.display, delta_y, delta_x);
|
.send_mouse_scroll(delta_y, delta_x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,7 +196,7 @@ impl WayVRRenderer {
|
|||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
pipeline,
|
pipeline,
|
||||||
context: Rc::new(RefCell::new(WayVRContext::new(wvr, display)?)),
|
context: Rc::new(RefCell::new(WayVRContext::new(wvr, display))),
|
||||||
vk_image: None,
|
vk_image: None,
|
||||||
vk_image_view: None,
|
vk_image_view: None,
|
||||||
graphics: app.graphics.clone(),
|
graphics: app.graphics.clone(),
|
||||||
@@ -220,10 +217,7 @@ fn get_or_create_display_by_name(
|
|||||||
.session
|
.session
|
||||||
.wayvr_config
|
.wayvr_config
|
||||||
.get_display(disp_name)
|
.get_display(disp_name)
|
||||||
.ok_or(anyhow::anyhow!(
|
.ok_or_else(|| anyhow::anyhow!("Cannot find display named \"{}\"", disp_name))?
|
||||||
"Cannot find display named \"{}\"",
|
|
||||||
disp_name
|
|
||||||
))?
|
|
||||||
.clone();
|
.clone();
|
||||||
|
|
||||||
let disp_handle = wayvr.data.state.create_display(
|
let disp_handle = wayvr.data.state.create_display(
|
||||||
@@ -302,6 +296,7 @@ where
|
|||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
overlay.state.curvature = Some(0.15);
|
||||||
overlay.state.want_visible = true;
|
overlay.state.want_visible = true;
|
||||||
overlay.state.spawn_scale = 2.0;
|
overlay.state.spawn_scale = 2.0;
|
||||||
overlay.state.spawn_point = vec3a(0.0, -0.35, -1.75);
|
overlay.state.spawn_point = vec3a(0.0, -0.35, -1.75);
|
||||||
@@ -312,25 +307,17 @@ where
|
|||||||
unreachable!(); /* safe, not possible to trigger */
|
unreachable!(); /* safe, not possible to trigger */
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME: overlay curvature needs to be dispatched for some unknown reason, this value is not set otherwise
|
|
||||||
app.tasks.enqueue(TaskType::Overlay(
|
|
||||||
OverlaySelector::Id(overlay.state.id),
|
|
||||||
Box::new(move |_app, o| {
|
|
||||||
o.curvature = Some(0.15);
|
|
||||||
}),
|
|
||||||
));
|
|
||||||
|
|
||||||
overlays.add(overlay);
|
overlays.add(overlay);
|
||||||
|
|
||||||
let args_vec = match &conf_dash.args {
|
let args_vec = &conf_dash
|
||||||
Some(args) => gen_args_vec(args),
|
.args
|
||||||
None => vec![],
|
.as_ref()
|
||||||
};
|
.map_or_else(Vec::new, |args| gen_args_vec(args.as_str()));
|
||||||
|
|
||||||
let env_vec = match &conf_dash.env {
|
let env_vec = &conf_dash
|
||||||
Some(env) => gen_env_vec(env),
|
.env
|
||||||
None => vec![],
|
.as_ref()
|
||||||
};
|
.map_or_else(Vec::new, |env| gen_env_vec(env));
|
||||||
|
|
||||||
let mut userdata = HashMap::new();
|
let mut userdata = HashMap::new();
|
||||||
userdata.insert(String::from("type"), String::from("dashboard"));
|
userdata.insert(String::from("type"), String::from("dashboard"));
|
||||||
@@ -339,8 +326,8 @@ where
|
|||||||
let _process_handle_unused = wayvr.data.state.spawn_process(
|
let _process_handle_unused = wayvr.data.state.spawn_process(
|
||||||
disp_handle,
|
disp_handle,
|
||||||
&conf_dash.exec,
|
&conf_dash.exec,
|
||||||
&args_vec,
|
args_vec,
|
||||||
&env_vec,
|
env_vec,
|
||||||
userdata,
|
userdata,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@@ -446,6 +433,7 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_lines)]
|
||||||
pub fn tick_events<O>(app: &mut AppState, overlays: &mut OverlayContainer<O>) -> anyhow::Result<()>
|
pub fn tick_events<O>(app: &mut AppState, overlays: &mut OverlayContainer<O>) -> anyhow::Result<()>
|
||||||
where
|
where
|
||||||
O: Default,
|
O: Default,
|
||||||
@@ -490,36 +478,42 @@ where
|
|||||||
|
|
||||||
for result in res {
|
for result in res {
|
||||||
match result {
|
match result {
|
||||||
wayvr::TickTask::NewExternalProcess(req) => {
|
wayvr::TickTask::NewExternalProcess(request) => {
|
||||||
let config = &app.session.wayvr_config;
|
let config = &app.session.wayvr_config;
|
||||||
|
|
||||||
let disp_name = if let Some(display_name) = req.env.display_name {
|
let disp_name = request.env.display_name.map_or_else(
|
||||||
config
|
|| {
|
||||||
.get_display(display_name.as_str())
|
|
||||||
.map(|_| display_name)
|
|
||||||
} else {
|
|
||||||
config
|
config
|
||||||
.get_default_display()
|
.get_default_display()
|
||||||
.map(|(display_name, _)| display_name)
|
.map(|(display_name, _)| display_name)
|
||||||
};
|
},
|
||||||
|
|display_name| {
|
||||||
|
config
|
||||||
|
.get_display(display_name.as_str())
|
||||||
|
.map(|_| display_name)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
if let Some(disp_name) = disp_name {
|
if let Some(disp_name) = disp_name {
|
||||||
let mut wayvr = r_wayvr.borrow_mut();
|
let mut wayvr = r_wayvr.borrow_mut();
|
||||||
|
|
||||||
log::info!("Registering external process with PID {}", req.pid);
|
log::info!("Registering external process with PID {}", request.pid);
|
||||||
|
|
||||||
let disp_handle = get_or_create_display_by_name(app, &mut wayvr, &disp_name)?;
|
let disp_handle = get_or_create_display_by_name(app, &mut wayvr, &disp_name)?;
|
||||||
|
|
||||||
wayvr.data.state.add_external_process(disp_handle, req.pid);
|
wayvr
|
||||||
|
.data
|
||||||
|
.state
|
||||||
|
.add_external_process(disp_handle, request.pid);
|
||||||
|
|
||||||
wayvr
|
wayvr
|
||||||
.data
|
.data
|
||||||
.state
|
.state
|
||||||
.manager
|
.manager
|
||||||
.add_client(wayvr::client::WayVRClient {
|
.add_client(wayvr::client::WayVRClient {
|
||||||
client: req.client,
|
client: request.client,
|
||||||
display_handle: disp_handle,
|
display_handle: disp_handle,
|
||||||
pid: req.pid,
|
pid: request.pid,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -576,8 +570,8 @@ impl WayVRRenderer {
|
|||||||
.create_command_buffer(CommandBufferUsage::OneTimeSubmit)?;
|
.create_command_buffer(CommandBufferUsage::OneTimeSubmit)?;
|
||||||
|
|
||||||
let tex = upload.texture2d_raw(
|
let tex = upload.texture2d_raw(
|
||||||
data.width as u32,
|
u32::from(data.width),
|
||||||
data.height as u32,
|
u32::from(data.height),
|
||||||
vulkano::format::Format::R8G8B8A8_UNORM,
|
vulkano::format::Format::R8G8B8A8_UNORM,
|
||||||
&data.data,
|
&data.data,
|
||||||
)?;
|
)?;
|
||||||
@@ -615,8 +609,8 @@ impl WayVRRenderer {
|
|||||||
|
|
||||||
let frame = DmabufFrame {
|
let frame = DmabufFrame {
|
||||||
format: FrameFormat {
|
format: FrameFormat {
|
||||||
width: disp.width as u32,
|
width: u32::from(disp.width),
|
||||||
height: disp.height as u32,
|
height: u32::from(disp.height),
|
||||||
fourcc: FourCC {
|
fourcc: FourCC {
|
||||||
value: data.mod_info.fourcc,
|
value: data.mod_info.fourcc,
|
||||||
},
|
},
|
||||||
@@ -674,7 +668,7 @@ impl OverlayRenderer for WayVRRenderer {
|
|||||||
let redrawn = match wayvr.data.tick_display(ctx.display) {
|
let redrawn = match wayvr.data.tick_display(ctx.display) {
|
||||||
Ok(r) => r,
|
Ok(r) => r,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("tick_display failed: {}", e);
|
log::error!("tick_display failed: {e}");
|
||||||
return Ok(ShouldRender::Unable);
|
return Ok(ShouldRender::Unable);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -699,7 +693,7 @@ impl OverlayRenderer for WayVRRenderer {
|
|||||||
.data
|
.data
|
||||||
.state
|
.state
|
||||||
.get_render_data(ctx.display)
|
.get_render_data(ctx.display)
|
||||||
.ok_or(anyhow::anyhow!("Failed to fetch render data"))?
|
.ok_or_else(|| anyhow::anyhow!("Failed to fetch render data"))?
|
||||||
.clone();
|
.clone();
|
||||||
|
|
||||||
drop(wayvr);
|
drop(wayvr);
|
||||||
@@ -712,7 +706,7 @@ impl OverlayRenderer for WayVRRenderer {
|
|||||||
}
|
}
|
||||||
wayvr::egl_data::RenderData::Software(data) => {
|
wayvr::egl_data::RenderData::Software(data) => {
|
||||||
if let Some(new_frame) = &data {
|
if let Some(new_frame) = &data {
|
||||||
self.ensure_software_data(new_frame)?
|
self.ensure_software_data(new_frame)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -762,10 +756,10 @@ pub fn create_wayvr_display_overlay<O>(
|
|||||||
where
|
where
|
||||||
O: Default,
|
O: Default,
|
||||||
{
|
{
|
||||||
let transform = ui_transform(&[display_width as u32, display_height as u32]);
|
let transform = ui_transform([u32::from(display_width), u32::from(display_height)]);
|
||||||
|
|
||||||
let state = OverlayState {
|
let state = OverlayState {
|
||||||
name: format!("WayVR - {}", name).into(),
|
name: format!("WayVR - {name}").into(),
|
||||||
keyboard_focus: Some(KeyboardFocus::WayVR),
|
keyboard_focus: Some(KeyboardFocus::WayVR),
|
||||||
want_visible: true,
|
want_visible: true,
|
||||||
interactable: true,
|
interactable: true,
|
||||||
@@ -817,16 +811,13 @@ fn action_app_click<O>(
|
|||||||
where
|
where
|
||||||
O: Default,
|
O: Default,
|
||||||
{
|
{
|
||||||
let wayvr = app.get_wayvr()?.clone();
|
let wayvr = app.get_wayvr()?;
|
||||||
|
|
||||||
let catalog = app
|
let catalog = app
|
||||||
.session
|
.session
|
||||||
.wayvr_config
|
.wayvr_config
|
||||||
.get_catalog(catalog_name)
|
.get_catalog(catalog_name)
|
||||||
.ok_or(anyhow::anyhow!(
|
.ok_or_else(|| anyhow::anyhow!("Failed to get catalog \"{}\"", catalog_name))?
|
||||||
"Failed to get catalog \"{}\"",
|
|
||||||
catalog_name
|
|
||||||
))?
|
|
||||||
.clone();
|
.clone();
|
||||||
|
|
||||||
if let Some(app_entry) = catalog.get_app(app_name) {
|
if let Some(app_entry) = catalog.get_app(app_name) {
|
||||||
@@ -838,22 +829,22 @@ where
|
|||||||
&app_entry.target_display.to_lowercase(),
|
&app_entry.target_display.to_lowercase(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let args_vec = match &app_entry.args {
|
let args_vec = &app_entry
|
||||||
Some(args) => gen_args_vec(args),
|
.args
|
||||||
None => vec![],
|
.as_ref()
|
||||||
};
|
.map_or_else(Vec::new, |args| gen_args_vec(args.as_str()));
|
||||||
|
|
||||||
let env_vec = match &app_entry.env {
|
let env_vec = &app_entry
|
||||||
Some(env) => gen_env_vec(env),
|
.env
|
||||||
None => vec![],
|
.as_ref()
|
||||||
};
|
.map_or_else(Vec::new, |env| gen_env_vec(env));
|
||||||
|
|
||||||
// Terminate existing process if required
|
// Terminate existing process if required
|
||||||
if let Some(process_handle) =
|
if let Some(process_handle) =
|
||||||
wayvr
|
wayvr
|
||||||
.data
|
.data
|
||||||
.state
|
.state
|
||||||
.process_query(disp_handle, &app_entry.exec, &args_vec, &env_vec)
|
.process_query(disp_handle, &app_entry.exec, args_vec, env_vec)
|
||||||
{
|
{
|
||||||
// Terminate process
|
// Terminate process
|
||||||
wayvr.data.terminate_process(process_handle);
|
wayvr.data.terminate_process(process_handle);
|
||||||
@@ -862,9 +853,9 @@ where
|
|||||||
wayvr.data.state.spawn_process(
|
wayvr.data.state.spawn_process(
|
||||||
disp_handle,
|
disp_handle,
|
||||||
&app_entry.exec,
|
&app_entry.exec,
|
||||||
&args_vec,
|
args_vec,
|
||||||
&env_vec,
|
env_vec,
|
||||||
Default::default(),
|
HashMap::default(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
show_display::<O>(&mut wayvr, overlays, app_entry.target_display.as_str());
|
show_display::<O>(&mut wayvr, overlays, app_entry.target_display.as_str());
|
||||||
|
|||||||
26
src/state.rs
26
src/state.rs
@@ -118,12 +118,12 @@ impl AppState {
|
|||||||
#[cfg(feature = "osc")]
|
#[cfg(feature = "osc")]
|
||||||
let osc_sender = crate::backend::osc::OscSender::new(session.config.osc_out_port).ok();
|
let osc_sender = crate::backend::osc::OscSender::new(session.config.osc_out_port).ok();
|
||||||
|
|
||||||
let toast_sound_wav = AppState::try_load_bytes(
|
let toast_sound_wav = Self::try_load_bytes(
|
||||||
&session.config.notification_sound,
|
&session.config.notification_sound,
|
||||||
include_bytes!("res/557297.wav"),
|
include_bytes!("res/557297.wav"),
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(AppState {
|
Ok(Self {
|
||||||
fc: FontCache::new(session.config.primary_font.clone())?,
|
fc: FontCache::new(session.config.primary_font.clone())?,
|
||||||
session,
|
session,
|
||||||
tasks,
|
tasks,
|
||||||
@@ -167,16 +167,16 @@ impl AppState {
|
|||||||
let real_path = config_io::get_config_root().join(path);
|
let real_path = config_io::get_config_root().join(path);
|
||||||
|
|
||||||
if std::fs::File::open(real_path.clone()).is_err() {
|
if std::fs::File::open(real_path.clone()).is_err() {
|
||||||
log::warn!("Could not open file at: {}", path);
|
log::warn!("Could not open file at: {path}");
|
||||||
return fallback_data;
|
return fallback_data;
|
||||||
};
|
}
|
||||||
|
|
||||||
match std::fs::read(real_path.clone()) {
|
match std::fs::read(real_path) {
|
||||||
// Box is used here to work around `f`'s limited lifetime
|
// Box is used here to work around `f`'s limited lifetime
|
||||||
Ok(f) => Box::leak(Box::new(f)).as_slice(),
|
Ok(f) => Box::leak(Box::new(f)).as_slice(),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::warn!("Failed to read file at: {}", path);
|
log::warn!("Failed to read file at: {path}");
|
||||||
log::warn!("{:?}", e);
|
log::warn!("{e:?}");
|
||||||
fallback_data
|
fallback_data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -195,7 +195,7 @@ pub struct AppSession {
|
|||||||
impl AppSession {
|
impl AppSession {
|
||||||
pub fn load() -> Self {
|
pub fn load() -> Self {
|
||||||
let config_root_path = config_io::ConfigRoot::Generic.ensure_dir();
|
let config_root_path = config_io::ConfigRoot::Generic.ensure_dir();
|
||||||
log::info!("Config root path: {:?}", config_root_path);
|
log::info!("Config root path: {config_root_path:?}");
|
||||||
let config = GeneralConfig::load_from_disk();
|
let config = GeneralConfig::load_from_disk();
|
||||||
|
|
||||||
let mut toast_topics = IdMap::new();
|
let mut toast_topics = IdMap::new();
|
||||||
@@ -210,11 +210,11 @@ impl AppSession {
|
|||||||
#[cfg(feature = "wayvr")]
|
#[cfg(feature = "wayvr")]
|
||||||
let wayvr_config = config_wayvr::load_wayvr();
|
let wayvr_config = config_wayvr::load_wayvr();
|
||||||
|
|
||||||
AppSession {
|
Self {
|
||||||
config,
|
config,
|
||||||
toast_topics,
|
|
||||||
#[cfg(feature = "wayvr")]
|
#[cfg(feature = "wayvr")]
|
||||||
wayvr_config,
|
wayvr_config,
|
||||||
|
toast_topics,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -225,8 +225,8 @@ pub struct AudioOutput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AudioOutput {
|
impl AudioOutput {
|
||||||
pub fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
AudioOutput {
|
Self {
|
||||||
audio_stream: None,
|
audio_stream: None,
|
||||||
first_try: true,
|
first_try: true,
|
||||||
}
|
}
|
||||||
@@ -253,7 +253,7 @@ impl AudioOutput {
|
|||||||
let source = match Decoder::new_wav(cursor) {
|
let source = match Decoder::new_wav(cursor) {
|
||||||
Ok(source) => source,
|
Ok(source) => source,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("Failed to play sound: {:?}", e);
|
log::error!("Failed to play sound: {e:?}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user