WayVR: WayVRDisplayList ui type, toggle display visibility and pause rendering of them

This commit is contained in:
Aleksander
2024-10-20 11:54:38 +02:00
committed by galister
parent 79d91e3d02
commit 07d7afa96f
10 changed files with 218 additions and 95 deletions

View File

@@ -43,7 +43,7 @@ use crate::{
}; };
#[cfg(feature = "wayvr")] #[cfg(feature = "wayvr")]
use crate::overlays::wayvr::action_wayvr; use crate::overlays::wayvr::wayvr_action;
pub mod helpers; pub mod helpers;
pub mod input; pub mod input;
@@ -266,12 +266,8 @@ pub fn openvr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
} }
}, },
#[cfg(feature = "wayvr")] #[cfg(feature = "wayvr")]
TaskType::WayVR(task) => { TaskType::WayVR(action) => {
if let Some(overlay) = wayvr_action(&mut state, &mut overlays, &action);
action_wayvr(&task.catalog_name, &task.app_name, &mut state)
{
overlays.add(overlay);
}
} }
} }
} }

View File

@@ -32,7 +32,7 @@ use crate::{
}; };
#[cfg(feature = "wayvr")] #[cfg(feature = "wayvr")]
use crate::overlays::wayvr::action_wayvr; use crate::overlays::wayvr::wayvr_action;
mod helpers; mod helpers;
mod input; mod input;
@@ -491,12 +491,8 @@ pub fn openxr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
_ => {} _ => {}
}, },
#[cfg(feature = "wayvr")] #[cfg(feature = "wayvr")]
TaskType::WayVR(task) => { TaskType::WayVR(action) => {
if let Some(overlay) = wayvr_action(&mut app_state, &mut overlays, &action);
action_wayvr(&task.catalog_name, &task.app_name, &mut app_state)
{
overlays.add(overlay);
}
} }
} }
} }

View File

@@ -5,13 +5,13 @@ use std::{
time::Instant, time::Instant,
}; };
#[cfg(feature = "wayvr")]
use std::sync::Arc;
use serde::Deserialize; use serde::Deserialize;
use crate::state::AppState; use crate::state::AppState;
#[cfg(feature = "wayvr")]
use crate::overlays::wayvr::WayVRAction;
use super::{ use super::{
common::OverlaySelector, common::OverlaySelector,
overlay::{OverlayBackend, OverlayState}, overlay::{OverlayBackend, OverlayState},
@@ -52,12 +52,6 @@ pub enum SystemTask {
ShowHide, ShowHide,
} }
#[cfg(feature = "wayvr")]
pub struct WayVRTask {
pub catalog_name: Arc<str>,
pub app_name: Arc<str>,
}
pub type OverlayTask = dyn FnOnce(&mut AppState, &mut OverlayState) + Send; pub type OverlayTask = dyn FnOnce(&mut AppState, &mut OverlayState) + Send;
pub type CreateOverlayTask = pub type CreateOverlayTask =
dyn FnOnce(&mut AppState) -> Option<(OverlayState, Box<dyn OverlayBackend>)> + Send; dyn FnOnce(&mut AppState) -> Option<(OverlayState, Box<dyn OverlayBackend>)> + Send;
@@ -69,7 +63,7 @@ pub enum TaskType {
DropOverlay(OverlaySelector), DropOverlay(OverlaySelector),
System(SystemTask), System(SystemTask),
#[cfg(feature = "wayvr")] #[cfg(feature = "wayvr")]
WayVR(WayVRTask), WayVR(WayVRAction),
} }
#[derive(Deserialize, Clone, Copy)] #[derive(Deserialize, Clone, Copy)]

View File

@@ -15,7 +15,7 @@ use smithay::{
wayland::shell::xdg::ToplevelSurface, wayland::shell::xdg::ToplevelSurface,
}; };
use crate::gen_id; use crate::{backend::overlay::OverlayID, gen_id};
use super::{ use super::{
client::WayVRManager, comp::send_frames_surface_tree, egl_data, smithay_wrapper, window, client::WayVRManager, comp::send_frames_surface_tree, egl_data, smithay_wrapper, window,
@@ -47,6 +47,8 @@ pub struct Display {
pub width: u32, pub width: u32,
pub height: u32, pub height: u32,
pub name: String, pub name: String,
pub visible: bool,
pub overlay_id: Option<OverlayID>,
wm: Rc<RefCell<window::WindowManager>>, wm: Rc<RefCell<window::WindowManager>>,
displayed_windows: Vec<DisplayWindow>, displayed_windows: Vec<DisplayWindow>,
wayland_env: super::WaylandEnv, wayland_env: super::WaylandEnv,
@@ -112,6 +114,8 @@ impl Display {
gles_texture, gles_texture,
wayland_env, wayland_env,
processes: Vec::new(), processes: Vec::new(),
visible: true,
overlay_id: None,
}) })
} }
@@ -216,6 +220,11 @@ impl Display {
None None
} }
pub fn set_visible(&mut self, visible: bool) {
log::info!("Display \"{}\" visible: {}", self.name.as_str(), visible);
self.visible = visible;
}
pub fn send_mouse_move(&self, manager: &mut WayVRManager, x: u32, y: u32) { pub fn send_mouse_move(&self, manager: &mut WayVRManager, x: u32, y: u32) {
if let Some(window_handle) = self.get_hovered_window(x, y) { if let Some(window_handle) = self.get_hovered_window(x, y) {
let wm = self.wm.borrow(); let wm = self.wm.borrow();

View File

@@ -43,7 +43,7 @@ impl WaylandEnv {
pub struct WayVR { pub struct WayVR {
time_start: u64, time_start: u64,
gles_renderer: GlesRenderer, gles_renderer: GlesRenderer,
displays: display::DisplayVec, pub displays: display::DisplayVec,
manager: client::WayVRManager, manager: client::WayVRManager,
wm: Rc<RefCell<window::WindowManager>>, wm: Rc<RefCell<window::WindowManager>>,
egl_data: Rc<egl_data::EGLData>, egl_data: Rc<egl_data::EGLData>,
@@ -102,13 +102,19 @@ impl WayVR {
pub fn tick_display(&mut self, display: display::DisplayHandle) -> anyhow::Result<()> { pub fn tick_display(&mut self, display: display::DisplayHandle) -> anyhow::Result<()> {
// millis since the start of wayvr // millis since the start of wayvr
let time_ms = get_millis() - self.time_start;
let display = self let display = self
.displays .displays
.get(&display) .get(&display)
.ok_or(anyhow::anyhow!("Invalid display handle"))?; .ok_or(anyhow::anyhow!("Invalid display handle"))?;
let time_ms = get_millis() - self.time_start;
if !display.visible {
// Display is invisible, do not render
return Ok(());
}
display.tick_render(&mut self.gles_renderer, time_ms)?; display.tick_render(&mut self.gles_renderer, time_ms)?;
Ok(()) Ok(())
@@ -172,6 +178,12 @@ impl WayVR {
self.manager.send_key(virtual_key, down); self.manager.send_key(virtual_key, down);
} }
pub fn set_display_visible(&mut self, display: display::DisplayHandle, visible: bool) {
if let Some(display) = self.displays.get_mut(&display) {
display.set_visible(visible);
}
}
pub fn get_dmabuf_data(&self, display: display::DisplayHandle) -> Option<egl_data::DMAbufData> { pub fn get_dmabuf_data(&self, display: display::DisplayHandle) -> Option<egl_data::DMAbufData> {
self.displays self.displays
.get(&display) .get(&display)
@@ -188,14 +200,6 @@ impl WayVR {
} }
None None
} }
pub fn get_display_by_handle(
&self,
display: display::DisplayHandle,
) -> Option<&display::Display> {
self.displays.get(&display)
}
pub fn create_display( pub fn create_display(
&mut self, &mut self,
width: u32, width: u32,

View File

@@ -1,7 +1,7 @@
#[cfg(not(feature = "wayvr"))] #[cfg(not(feature = "wayvr"))]
compile_error!("WayVR feature is not enabled"); compile_error!("WayVR feature is not enabled");
use std::collections::HashMap; use std::collections::{BTreeMap, HashMap};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@@ -38,7 +38,7 @@ impl WayVRCatalog {
pub struct WayVRConfig { pub struct WayVRConfig {
pub version: u32, pub version: u32,
pub catalogs: HashMap<String, WayVRCatalog>, pub catalogs: HashMap<String, WayVRCatalog>,
pub displays: HashMap<String, WayVRDisplay>, pub displays: BTreeMap<String, WayVRDisplay>, // sorted alphabetically
} }
impl WayVRConfig { impl WayVRConfig {

View File

@@ -26,7 +26,7 @@ use crate::{
}; };
#[cfg(feature = "wayvr")] #[cfg(feature = "wayvr")]
use crate::backend::task::WayVRTask; use crate::overlays::wayvr::WayVRAction;
use super::{ExecArgs, ModularControl, ModularData}; use super::{ExecArgs, ModularControl, ModularData};
@@ -138,10 +138,7 @@ pub enum ButtonAction {
action: OverlayAction, action: OverlayAction,
}, },
#[cfg(feature = "wayvr")] #[cfg(feature = "wayvr")]
WayVR { WayVR(WayVRAction),
catalog_name: Arc<str>,
app_name: Arc<str>,
},
Window { Window {
target: Arc<str>, target: Arc<str>,
action: WindowAction, action: WindowAction,
@@ -336,14 +333,8 @@ fn handle_action(action: &ButtonAction, press: &mut PressData, app: &mut AppStat
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),
#[cfg(feature = "wayvr")] #[cfg(feature = "wayvr")]
ButtonAction::WayVR { ButtonAction::WayVR(action) => {
catalog_name, app.tasks.enqueue(TaskType::WayVR(action.clone()));
app_name,
} => {
app.tasks.enqueue(TaskType::WayVR(WayVRTask {
catalog_name: catalog_name.clone(),
app_name: app_name.clone(),
}));
} }
ButtonAction::VirtualKey { keycode, action } => app ButtonAction::VirtualKey { keycode, action } => app
.hid_provider .hid_provider

View File

@@ -12,6 +12,9 @@ use crate::{
graphics::dds::WlxCommandBufferDds, state::AppState, graphics::dds::WlxCommandBufferDds, state::AppState,
}; };
#[cfg(feature = "wayvr")]
use crate::overlays::wayvr::{WayVRAction, WayVRDisplayClickAction};
use self::{ use self::{
button::{modular_button_init, ButtonAction, ButtonData, OverlayAction}, button::{modular_button_init, ButtonAction, ButtonData, OverlayAction},
label::{modular_label_init, LabelContent, LabelData}, label::{modular_label_init, LabelContent, LabelData},
@@ -119,6 +122,14 @@ pub enum ModularElement {
bg_color: Arc<str>, bg_color: Arc<str>,
catalog_name: Arc<str>, catalog_name: Arc<str>,
}, },
// Ignored if "wayvr" feature is not enabled
WayVRDisplayList {
rect: [f32; 4],
corner_radius: Option<f32>,
font_size: isize,
fg_color: Arc<str>,
bg_color: Arc<str>,
},
} }
#[derive(Deserialize, Clone)] #[derive(Deserialize, Clone)]
@@ -440,10 +451,10 @@ pub fn modular_canvas(
); );
let data = ButtonData { let data = ButtonData {
click_down: Some(vec![ButtonAction::WayVR { click_up: Some(vec![ButtonAction::WayVR(WayVRAction::AppClick {
catalog_name: catalog_name.clone(), catalog_name: catalog_name.clone(),
app_name: Arc::from(app.name.as_str()), app_name: Arc::from(app.name.as_str()),
}]), })]),
..Default::default() ..Default::default()
}; };
@@ -456,7 +467,60 @@ pub fn modular_canvas(
} }
#[cfg(not(feature = "wayvr"))] #[cfg(not(feature = "wayvr"))]
{ {
log::error!("WayVR feature is not available, ignoring"); log::error!("WayVR feature is not enabled, ignoring");
}
}
#[allow(unused_variables)]
ModularElement::WayVRDisplayList {
rect: [x, y, w, h],
corner_radius,
font_size,
fg_color,
bg_color,
} => {
#[cfg(feature = "wayvr")]
{
let mut button_x = *x;
let button_y = *y;
let displays = &state.session.wayvr_config.displays;
for (display_name, display) in displays {
let button_w: f32 = (*w / displays.len() as f32).min(80.0);
let button_h: f32 = *h;
canvas.bg_color = color_parse(bg_color).unwrap_or(*FALLBACK_COLOR);
canvas.fg_color = color_parse(fg_color).unwrap_or(*FALLBACK_COLOR);
canvas.font_size = *font_size;
let button = canvas.button(
button_x + 2.,
button_y + 2.,
button_w - 4.,
button_h - 4.,
corner_radius.unwrap_or_default(),
Arc::from(display_name.as_str()),
);
let data = ButtonData {
click_up: Some(vec![ButtonAction::WayVR(WayVRAction::DisplayClick {
display_name: Arc::from(display_name.as_str()),
action: WayVRDisplayClickAction::ToggleVisibility,
})]),
long_click_up: Some(vec![ButtonAction::WayVR(
WayVRAction::DisplayClick {
display_name: Arc::from(display_name.as_str()),
action: WayVRDisplayClickAction::Reset,
},
)]),
..Default::default()
};
modular_button_init(button, &data);
button_x += button_w;
}
}
#[cfg(not(feature = "wayvr"))]
{
log::error!("WayVR feature is not enabled, ignoring")
} }
} }
} }

View File

@@ -1,10 +1,12 @@
use glam::{vec3a, Affine2}; use glam::{vec3a, Affine2};
use serde::Deserialize;
use std::{cell::RefCell, rc::Rc, sync::Arc}; use std::{cell::RefCell, rc::Rc, sync::Arc};
use vulkano::image::SubresourceLayout; use vulkano::image::SubresourceLayout;
use wlx_capture::frame::{DmabufFrame, FourCC, FrameFormat, FramePlane}; use wlx_capture::frame::{DmabufFrame, FourCC, FrameFormat, FramePlane};
use crate::{ use crate::{
backend::{ backend::{
common::OverlayContainer,
input::{self, InteractionHandler}, input::{self, InteractionHandler},
overlay::{ui_transform, OverlayData, OverlayRenderer, OverlayState, SplitOverlayBackend}, overlay::{ui_transform, OverlayData, OverlayRenderer, OverlayState, SplitOverlayBackend},
wayvr, wayvr,
@@ -53,7 +55,7 @@ impl InteractionHandler for WayVRInteractionHandler {
let ctx = self.context.borrow(); let ctx = self.context.borrow();
let mut wayvr = ctx.wayvr.borrow_mut(); let mut wayvr = ctx.wayvr.borrow_mut();
if let Some(disp) = wayvr.get_display_by_handle(ctx.display) { if let Some(disp) = wayvr.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 * disp.width as f32) as i32).max(0);
let y = ((pos.y * disp.height as f32) as i32).max(0); let y = ((pos.y * disp.height as f32) as i32).max(0);
@@ -128,7 +130,7 @@ impl WayVRRenderer {
let ctx = self.context.borrow_mut(); let ctx = self.context.borrow_mut();
let wayvr = ctx.wayvr.borrow_mut(); let wayvr = ctx.wayvr.borrow_mut();
if let Some(disp) = wayvr.get_display_by_handle(ctx.display) { if let Some(disp) = wayvr.displays.get(&ctx.display) {
let frame = DmabufFrame { let frame = DmabufFrame {
format: FrameFormat { format: FrameFormat {
width: disp.width, width: disp.width,
@@ -175,10 +177,16 @@ impl OverlayRenderer for WayVRRenderer {
} }
fn pause(&mut self, _app: &mut state::AppState) -> anyhow::Result<()> { fn pause(&mut self, _app: &mut state::AppState) -> anyhow::Result<()> {
let ctx = self.context.borrow_mut();
let mut wayvr = ctx.wayvr.borrow_mut();
wayvr.set_display_visible(ctx.display, false);
Ok(()) Ok(())
} }
fn resume(&mut self, _app: &mut state::AppState) -> anyhow::Result<()> { fn resume(&mut self, _app: &mut state::AppState) -> anyhow::Result<()> {
let ctx = self.context.borrow_mut();
let mut wayvr = ctx.wayvr.borrow_mut();
wayvr.set_display_visible(ctx.display, true);
Ok(()) Ok(())
} }
@@ -212,17 +220,18 @@ impl OverlayRenderer for WayVRRenderer {
#[allow(dead_code)] #[allow(dead_code)]
pub fn create_wayvr<O>( pub fn create_wayvr<O>(
app: &mut state::AppState, app: &mut state::AppState,
display: &wayvr::display::Display, display_width: u32,
display_height: u32,
display_handle: wayvr::display::DisplayHandle, display_handle: wayvr::display::DisplayHandle,
display_scale: f32, display_scale: f32,
) -> anyhow::Result<OverlayData<O>> ) -> anyhow::Result<OverlayData<O>>
where where
O: Default, O: Default,
{ {
let transform = ui_transform(&[display.width, display.height]); let transform = ui_transform(&[display_width, display_height]);
let state = OverlayState { let state = OverlayState {
name: format!("WayVR Screen ({}x{})", display.width, display.height).into(), name: format!("WayVR Screen ({}x{})", display_width, display_height).into(),
keyboard_focus: Some(KeyboardFocus::WayVR), keyboard_focus: Some(KeyboardFocus::WayVR),
want_visible: true, want_visible: true,
interactable: true, interactable: true,
@@ -250,10 +259,28 @@ where
}) })
} }
fn action_wayvr_internal<O>( #[derive(Deserialize, Clone)]
pub enum WayVRDisplayClickAction {
ToggleVisibility,
Reset,
}
#[derive(Deserialize, Clone)]
pub enum WayVRAction {
AppClick {
catalog_name: Arc<str>,
app_name: Arc<str>,
},
DisplayClick {
display_name: Arc<str>,
action: WayVRDisplayClickAction,
},
}
fn action_app_click<O>(
app: &mut AppState,
catalog_name: &Arc<str>, catalog_name: &Arc<str>,
app_name: &Arc<str>, app_name: &Arc<str>,
app: &mut AppState,
) -> anyhow::Result<Option<OverlayData<O>>> ) -> anyhow::Result<Option<OverlayData<O>>>
where where
O: Default, O: Default,
@@ -294,13 +321,19 @@ where
conf_display.height, conf_display.height,
&app_entry.target_display, &app_entry.target_display,
)?; )?;
let display = wayvr.get_display_by_handle(display_handle).unwrap(); // Never fails
created_overlay = Some(create_wayvr::<O>( let overlay = create_wayvr::<O>(
app, app,
display, conf_display.width,
conf_display.height,
display_handle, display_handle,
conf_display.scale, conf_display.scale,
)?); )?;
let display = wayvr.displays.get_mut(&display_handle).unwrap(); // Never fails
display.overlay_id = Some(overlay.state.id);
created_overlay = Some(overlay);
display_handle display_handle
}; };
@@ -327,22 +360,70 @@ where
Ok(created_overlay) Ok(created_overlay)
} }
// Returns newly created overlay (if needed) pub fn action_display_click<O>(
pub fn action_wayvr<O>(
catalog_name: &Arc<str>,
app_name: &Arc<str>,
app: &mut AppState, app: &mut AppState,
) -> Option<OverlayData<O>> overlays: &mut OverlayContainer<O>,
display_name: &Arc<str>,
action: &WayVRDisplayClickAction,
) -> anyhow::Result<()>
where where
O: Default, O: Default,
{ {
match action_wayvr_internal(catalog_name, app_name, app) { let wayvr = app.get_wayvr()?;
Ok(res) => res, let mut wayvr = wayvr.borrow_mut();
Err(e) => {
// Happens if something went wrong with initialization if let Some(handle) = wayvr.get_display_by_name(display_name) {
// or input exec path is invalid. Do nothing, just print an error if let Some(display) = wayvr.displays.get_mut(&handle) {
log::error!("action_wayvr failed: {}", e); if let Some(overlay_id) = display.overlay_id {
None if let Some(overlay) = overlays.mut_by_id(overlay_id) {
match action {
WayVRDisplayClickAction::ToggleVisibility => {
// Toggle visibility
overlay.state.want_visible = !overlay.state.want_visible;
}
WayVRDisplayClickAction::Reset => {
// Show it at the front
overlay.state.want_visible = true;
overlay.state.reset(app, true);
}
}
}
}
}
}
Ok(())
}
pub fn wayvr_action<O>(app: &mut AppState, overlays: &mut OverlayContainer<O>, action: &WayVRAction)
where
O: Default,
{
match action {
WayVRAction::AppClick {
catalog_name,
app_name,
} => {
match action_app_click(app, catalog_name, app_name) {
Ok(res) => {
if let Some(created_overlay) = res {
overlays.add(created_overlay);
}
}
Err(e) => {
// Happens if something went wrong with initialization
// or input exec path is invalid. Do nothing, just print an error
log::error!("action_app_click failed: {}", e);
}
}
}
WayVRAction::DisplayClick {
display_name,
action,
} => {
if let Err(e) = action_display_click::<O>(app, overlays, display_name, action) {
log::error!("action_display_click failed: {}", e);
}
} }
} }
} }

View File

@@ -6,19 +6,11 @@
version: 1 version: 1
displays: displays:
disp_square: Disp1:
width: 500
height: 350
scale: 1.0
disp_term:
width: 640 width: 640
height: 480 height: 480
scale: 1.25 scale: 1.25
disp_browser: Disp2:
width: 1280
height: 720
scale: 2.0
disp_plasma:
width: 1280 width: 1280
height: 720 height: 720
scale: 2.0 scale: 2.0
@@ -27,21 +19,17 @@ catalogs:
default_catalog: default_catalog:
apps: apps:
- name: "Calc" - name: "Calc"
target_display: "disp_square" target_display: "Disp1"
exec: "kcalc" exec: "kcalc"
env: ["FOO=bar"] env: ["FOO=bar"]
- name: "Terminal" - name: "htop"
target_display: "disp_term" target_display: "Disp1"
exec: "konsole" exec: "konsole"
args: "-e htop"
- name: "Browser" - name: "Browser"
target_display: "disp_browser" target_display: "Disp2"
exec: "cage" exec: "cage"
args: "chromium -- --incognito" args: "chromium -- --incognito"
- name: "Plasma"
target_display: "disp_plasma"
exec: "cage"
args: "dbus-run-session -- kwin_wayland --xwayland plasmashell"