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

View File

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

View File

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

View File

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

View File

@@ -43,7 +43,7 @@ impl WaylandEnv {
pub struct WayVR {
time_start: u64,
gles_renderer: GlesRenderer,
displays: display::DisplayVec,
pub displays: display::DisplayVec,
manager: client::WayVRManager,
wm: Rc<RefCell<window::WindowManager>>,
egl_data: Rc<egl_data::EGLData>,
@@ -102,13 +102,19 @@ impl WayVR {
pub fn tick_display(&mut self, display: display::DisplayHandle) -> anyhow::Result<()> {
// millis since the start of wayvr
let time_ms = get_millis() - self.time_start;
let display = self
.displays
.get(&display)
.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)?;
Ok(())
@@ -172,6 +178,12 @@ impl WayVR {
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> {
self.displays
.get(&display)
@@ -188,14 +200,6 @@ impl WayVR {
}
None
}
pub fn get_display_by_handle(
&self,
display: display::DisplayHandle,
) -> Option<&display::Display> {
self.displays.get(&display)
}
pub fn create_display(
&mut self,
width: u32,

View File

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

View File

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

View File

@@ -12,6 +12,9 @@ use crate::{
graphics::dds::WlxCommandBufferDds, state::AppState,
};
#[cfg(feature = "wayvr")]
use crate::overlays::wayvr::{WayVRAction, WayVRDisplayClickAction};
use self::{
button::{modular_button_init, ButtonAction, ButtonData, OverlayAction},
label::{modular_label_init, LabelContent, LabelData},
@@ -119,6 +122,14 @@ pub enum ModularElement {
bg_color: 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)]
@@ -440,10 +451,10 @@ pub fn modular_canvas(
);
let data = ButtonData {
click_down: Some(vec![ButtonAction::WayVR {
click_up: Some(vec![ButtonAction::WayVR(WayVRAction::AppClick {
catalog_name: catalog_name.clone(),
app_name: Arc::from(app.name.as_str()),
}]),
})]),
..Default::default()
};
@@ -456,7 +467,60 @@ pub fn modular_canvas(
}
#[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 serde::Deserialize;
use std::{cell::RefCell, rc::Rc, sync::Arc};
use vulkano::image::SubresourceLayout;
use wlx_capture::frame::{DmabufFrame, FourCC, FrameFormat, FramePlane};
use crate::{
backend::{
common::OverlayContainer,
input::{self, InteractionHandler},
overlay::{ui_transform, OverlayData, OverlayRenderer, OverlayState, SplitOverlayBackend},
wayvr,
@@ -53,7 +55,7 @@ impl InteractionHandler for WayVRInteractionHandler {
let ctx = self.context.borrow();
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 x = ((pos.x * disp.width 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 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 {
format: FrameFormat {
width: disp.width,
@@ -175,10 +177,16 @@ impl OverlayRenderer for WayVRRenderer {
}
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(())
}
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(())
}
@@ -212,17 +220,18 @@ impl OverlayRenderer for WayVRRenderer {
#[allow(dead_code)]
pub fn create_wayvr<O>(
app: &mut state::AppState,
display: &wayvr::display::Display,
display_width: u32,
display_height: u32,
display_handle: wayvr::display::DisplayHandle,
display_scale: f32,
) -> anyhow::Result<OverlayData<O>>
where
O: Default,
{
let transform = ui_transform(&[display.width, display.height]);
let transform = ui_transform(&[display_width, display_height]);
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),
want_visible: 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>,
app_name: &Arc<str>,
app: &mut AppState,
) -> anyhow::Result<Option<OverlayData<O>>>
where
O: Default,
@@ -294,13 +321,19 @@ where
conf_display.height,
&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,
display,
conf_display.width,
conf_display.height,
display_handle,
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
};
@@ -327,22 +360,70 @@ where
Ok(created_overlay)
}
// Returns newly created overlay (if needed)
pub fn action_wayvr<O>(
catalog_name: &Arc<str>,
app_name: &Arc<str>,
pub fn action_display_click<O>(
app: &mut AppState,
) -> Option<OverlayData<O>>
overlays: &mut OverlayContainer<O>,
display_name: &Arc<str>,
action: &WayVRDisplayClickAction,
) -> anyhow::Result<()>
where
O: Default,
{
match action_wayvr_internal(catalog_name, app_name, app) {
Ok(res) => res,
let wayvr = app.get_wayvr()?;
let mut wayvr = wayvr.borrow_mut();
if let Some(handle) = wayvr.get_display_by_name(display_name) {
if let Some(display) = wayvr.displays.get_mut(&handle) {
if let Some(overlay_id) = display.overlay_id {
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_wayvr failed: {}", e);
None
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
displays:
disp_square:
width: 500
height: 350
scale: 1.0
disp_term:
Disp1:
width: 640
height: 480
scale: 1.25
disp_browser:
width: 1280
height: 720
scale: 2.0
disp_plasma:
Disp2:
width: 1280
height: 720
scale: 2.0
@@ -27,21 +19,17 @@ catalogs:
default_catalog:
apps:
- name: "Calc"
target_display: "disp_square"
target_display: "Disp1"
exec: "kcalc"
env: ["FOO=bar"]
- name: "Terminal"
target_display: "disp_term"
- name: "htop"
target_display: "Disp1"
exec: "konsole"
args: "-e htop"
- name: "Browser"
target_display: "disp_browser"
target_display: "Disp2"
exec: "cage"
args: "chromium -- --incognito"
- name: "Plasma"
target_display: "disp_plasma"
exec: "cage"
args: "dbus-run-session -- kwin_wayland --xwayland plasmashell"