WayVR: Initial GUI integration

The format of the wayvr.yaml configuration file is subject to change at any time.
This commit is contained in:
Aleksander
2024-10-19 20:39:54 +02:00
committed by galister
parent edfa77e07c
commit d9dddbad11
17 changed files with 453 additions and 89 deletions

View File

@@ -0,0 +1,28 @@
name: Check Wayland+OpenXR+OpenVR+WayVR
on:
pull_request:
#branches: [ "main" ]
env:
CARGO_TERM_COLOR: always
SCCACHE_GHA_ENABLED: "true"
RUSTC_WRAPPER: "sccache"
jobs:
build:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Setup sccache
uses: mozilla-actions/sccache-action@v0.0.3
- name: Prepare Environment
run: |
sudo add-apt-repository -syn universe
sudo add-apt-repository -syn ppa:pipewire-debian/pipewire-upstream || sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 25088A0359807596
sudo apt-get update -y
sudo apt-get install -y fuse cmake pkg-config fontconfig libasound2-dev libxkbcommon-dev libxkbcommon-x11-0 libxkbcommon-x11-dev libopenxr-dev libfontconfig-dev libdbus-1-dev libpipewire-0.3-0 libpipewire-0.3-dev libspa-0.2-dev libx11-6 libxext6 libxrandr2 libx11-dev libxext-dev libxrandr-dev libopenvr-dev libopenvr-api1
- name: Build
run: cargo build --verbose --no-default-features --features=wayland,openxr,openvr,wayvr
- name: Run tests
run: cargo test --verbose --no-default-features --features=wayland,openxr,openvr,wayvr

View File

@@ -86,7 +86,7 @@ wayland-egl = { version = "0.32.4", optional = true }
regex = { version = "*" }
[features]
default = ["openxr", "openvr", "osc", "x11", "wayland"]
default = ["openxr", "openvr", "osc", "x11", "wayland", "wayvr"]
openvr = ["dep:ovr_overlay", "dep:json"]
openxr = ["dep:openxr", "dep:libmonado-rs"]
osc = ["dep:rosc"]

View File

@@ -42,6 +42,9 @@ use crate::{
state::AppState,
};
#[cfg(feature = "wayvr")]
use crate::overlays::wayvr::action_wayvr;
pub mod helpers;
pub mod input;
pub mod lines;
@@ -262,6 +265,14 @@ pub fn openvr_run(running: Arc<AtomicBool>, show_by_default: bool) -> Result<(),
overlays.show_hide(&mut state);
}
},
#[cfg(feature = "wayvr")]
TaskType::WayVR(task) => {
if let Some(overlay) =
action_wayvr(&task.catalog_name, &task.app_name, &mut state)
{
overlays.add(overlay);
}
}
}
}

View File

@@ -31,6 +31,9 @@ use crate::{
state::AppState,
};
#[cfg(feature = "wayvr")]
use crate::overlays::wayvr::action_wayvr;
mod helpers;
mod input;
mod lines;
@@ -487,6 +490,14 @@ 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);
}
}
}
}

View File

@@ -5,6 +5,9 @@ use std::{
time::Instant,
};
#[cfg(feature = "wayvr")]
use std::sync::Arc;
use serde::Deserialize;
use crate::state::AppState;
@@ -49,6 +52,12 @@ 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;
@@ -59,6 +68,8 @@ pub enum TaskType {
CreateOverlay(OverlaySelector, Box<CreateOverlayTask>),
DropOverlay(OverlaySelector),
System(SystemTask),
#[cfg(feature = "wayvr")]
WayVR(WayVRTask),
}
#[derive(Deserialize, Clone, Copy)]

View File

@@ -30,7 +30,7 @@
- Due to unknown circumstances, dma-buf textures may display various graphical glitches due to invalid dma-buf tiling modifier. Please report your GPU model when filing an issue. Alternatively, you can run wlx-overlay-s with `LIBGL_ALWAYS_SOFTWARE=1` to mitigate that (only the Smithay compositor will run in software renderer mode, wlx will still be accelerated).
- Potential data race in the rendering pipeline - A texture could be displayed during the clear-and-blit process in the compositor, causing minor artifacts (no fence sync support yet).
- ~~Potential data race in the rendering pipeline - A texture could be displayed during the clear-and-blit process in the compositor, causing minor artifacts (no fence sync support yet).~~ happens on all overlays on a simulated Monado driver
- Even though some applications support Wayland, some still check for the `DISPLAY` environment variable and an available X11 server, throwing an error. This can be fixed by running `cage`.

View File

@@ -46,6 +46,7 @@ pub struct Display {
// Display info stuff
pub width: u32,
pub height: u32,
pub name: String,
wm: Rc<RefCell<window::WindowManager>>,
displayed_windows: Vec<DisplayWindow>,
wayland_env: super::WaylandEnv,
@@ -76,6 +77,7 @@ impl Display {
wayland_env: super::WaylandEnv,
width: u32,
height: u32,
name: &str,
) -> anyhow::Result<Self> {
let tex_format = ffi::RGBA;
let internal_format = ffi::RGBA8;
@@ -102,6 +104,7 @@ impl Display {
wm,
width,
height,
name: String::from(name),
displayed_windows: Vec::new(),
egl_data,
dmabuf_data,

View File

@@ -178,10 +178,29 @@ impl WayVR {
.map(|display| display.dmabuf_data.clone())
}
pub fn get_display_by_name(&self, name: &str) -> Option<display::DisplayHandle> {
for (idx, cell) in self.displays.vec.iter().enumerate() {
if let Some(cell) = cell {
if cell.obj.name == name {
return Some(DisplayVec::get_handle(cell, idx));
}
}
}
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,
height: u32,
name: &str,
) -> anyhow::Result<display::DisplayHandle> {
let display = display::Display::new(
self.wm.clone(),
@@ -190,6 +209,7 @@ impl WayVR {
self.manager.wayland_env.clone(),
width,
height,
name,
)?;
Ok(self.displays.add(display))
}

View File

@@ -297,18 +297,20 @@ impl GeneralConfig {
}
}
const FALLBACKS: [&str; 4] = [
const FALLBACKS: [&str; 5] = [
include_str!("res/keyboard.yaml"),
include_str!("res/watch.yaml"),
include_str!("res/settings.yaml"),
include_str!("res/anchor.yaml"),
include_str!("res/wayvr.yaml"),
];
const FILES: [&str; 4] = [
const FILES: [&str; 5] = [
"keyboard.yaml",
"watch.yaml",
"settings.yaml",
"anchor.yaml",
"wayvr.yaml",
];
#[derive(Clone, Copy)]
@@ -318,6 +320,8 @@ pub enum ConfigType {
Watch,
Settings,
Anchor,
#[allow(dead_code)]
WayVR,
}
pub fn load_known_yaml<T>(config_type: ConfigType) -> T

60
src/config_wayvr.rs Normal file
View File

@@ -0,0 +1,60 @@
#[cfg(not(feature = "wayvr"))]
compile_error!("WayVR feature is not enabled");
use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use crate::config::{load_known_yaml, ConfigType};
#[derive(Clone, Deserialize, Serialize)]
pub struct WayVRAppEntry {
pub name: String,
pub target_display: String,
pub exec: String,
pub args: Option<String>,
pub env: Option<Vec<String>>,
}
#[derive(Clone, Deserialize, Serialize)]
pub struct WayVRDisplay {
pub width: u32,
pub height: u32,
pub scale: f32,
}
#[derive(Clone, Deserialize, Serialize)]
pub struct WayVRCatalog {
pub apps: Vec<WayVRAppEntry>,
}
impl WayVRCatalog {
pub fn get_app(&self, name: &str) -> Option<&WayVRAppEntry> {
self.apps.iter().find(|&app| app.name.as_str() == name)
}
}
#[derive(Deserialize, Serialize)]
pub struct WayVRConfig {
pub version: u32,
pub catalogs: HashMap<String, WayVRCatalog>,
pub displays: HashMap<String, WayVRDisplay>,
}
impl WayVRConfig {
pub fn get_catalog(&self, name: &str) -> Option<&WayVRCatalog> {
self.catalogs.get(name)
}
pub fn get_display(&self, name: &str) -> Option<&WayVRDisplay> {
self.displays.get(name)
}
}
pub fn load_wayvr() -> WayVRConfig {
let config = load_known_yaml::<WayVRConfig>(ConfigType::WayVR);
if config.version != 1 {
panic!("WayVR config version {} is not supported", config.version);
}
config
}

View File

@@ -25,6 +25,9 @@ use crate::{
state::AppState,
};
#[cfg(feature = "wayvr")]
use crate::backend::task::WayVRTask;
use super::{ExecArgs, ModularControl, ModularData};
#[derive(Deserialize, Clone)]
@@ -134,6 +137,11 @@ pub enum ButtonAction {
target: OverlaySelector,
action: OverlayAction,
},
#[cfg(feature = "wayvr")]
WayVR {
catalog_name: Arc<str>,
app_name: Arc<str>,
},
Window {
target: Arc<str>,
action: WindowAction,
@@ -327,6 +335,16 @@ fn handle_action(action: &ButtonAction, press: &mut PressData, app: &mut AppStat
ButtonAction::Watch { action } => run_watch(action, app),
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::VirtualKey { keycode, action } => app
.hid_provider
.send_key(*keycode, matches!(*action, PressRelease::Press)),

View File

@@ -110,6 +110,15 @@ pub enum ModularElement {
#[serde(flatten)]
template: Box<OverlayListTemplate>,
},
// Ignored if "wayvr" feature is not enabled
WayVRLauncher {
rect: [f32; 4],
corner_radius: Option<f32>,
font_size: isize,
fg_color: Arc<str>,
bg_color: Arc<str>,
catalog_name: Arc<str>,
},
}
#[derive(Deserialize, Clone)]
@@ -398,6 +407,58 @@ pub fn modular_canvas(
};
}
}
#[allow(unused_variables)] // needed in case if wayvr feature is not enabled
ModularElement::WayVRLauncher {
rect: [x, y, w, h],
corner_radius,
font_size,
fg_color,
bg_color,
catalog_name,
} => {
#[cfg(feature = "wayvr")]
{
if let Some(catalog) = state.session.wayvr_config.get_catalog(catalog_name) {
let mut button_x = *x;
let button_y = *y;
for app in &catalog.apps {
let button_w: f32 = *w / catalog.apps.len() as f32;
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(app.name.as_str()),
);
let data = ButtonData {
click_down: Some(vec![ButtonAction::WayVR {
catalog_name: catalog_name.clone(),
app_name: Arc::from(app.name.as_str()),
}]),
..Default::default()
};
modular_button_init(button, &data);
button_x += button_w;
}
} else {
log::error!("WayVR catalog \"{}\" not found", catalog_name);
}
}
#[cfg(not(feature = "wayvr"))]
{
log::error!("WayVR feature is not available, ignoring");
}
}
}
}
Ok(canvas.build())

View File

@@ -9,6 +9,9 @@ mod overlays;
mod shaders;
mod state;
#[cfg(feature = "wayvr")]
mod config_wayvr;
use std::{
path::PathBuf,
sync::{

View File

@@ -10,43 +10,22 @@ use crate::{
wayvr,
},
graphics::WlxGraphics,
state::{self, KeyboardFocus},
state::{self, AppState, KeyboardFocus},
};
pub struct WayVRContext {
wayvr: Rc<RefCell<wayvr::WayVR>>,
display: wayvr::display::DisplayHandle,
width: u32,
height: u32,
}
#[derive(Default)]
pub struct WayVRProcess<'a> {
pub exec_path: &'a str,
pub args: &'a [&'a str],
pub env: &'a [(&'a str, &'a str)],
}
impl WayVRContext {
pub fn new(
wvr: Rc<RefCell<wayvr::WayVR>>,
width: u32,
height: u32,
processes: &[WayVRProcess],
display: wayvr::display::DisplayHandle,
) -> anyhow::Result<Self> {
let mut wayvr = wvr.borrow_mut();
let display = wayvr.create_display(width, height)?;
for process in processes {
wayvr.spawn_process(display, process.exec_path, process.args, process.env)?;
}
Ok(Self {
wayvr: wvr.clone(),
display,
width,
height,
})
}
}
@@ -73,14 +52,15 @@ impl InteractionHandler for WayVRInteractionHandler {
) -> Option<input::Haptics> {
let ctx = self.context.borrow();
let pos = self.mouse_transform.transform_point2(hit.uv);
let x = ((pos.x * ctx.width as f32) as i32).max(0);
let y = ((pos.y * ctx.height as f32) as i32).max(0);
let mut wayvr = ctx.wayvr.borrow_mut();
if let Some(disp) = wayvr.get_display_by_handle(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);
let ctx = self.context.borrow();
ctx.wayvr
.borrow_mut()
.send_mouse_move(ctx.display, x as u32, y as u32);
let ctx = self.context.borrow();
wayvr.send_mouse_move(ctx.display, x as u32, y as u32);
}
None
}
@@ -120,24 +100,16 @@ pub struct WayVRRenderer {
view: Option<Arc<vulkano::image::view::ImageView>>,
context: Rc<RefCell<WayVRContext>>,
graphics: Arc<WlxGraphics>,
width: u32,
height: u32,
}
impl WayVRRenderer {
pub fn new(
app: &mut state::AppState,
wvr: Rc<RefCell<wayvr::WayVR>>,
width: u32,
height: u32,
processes: &[WayVRProcess],
display: wayvr::display::DisplayHandle,
) -> anyhow::Result<Self> {
Ok(Self {
context: Rc::new(RefCell::new(WayVRContext::new(
wvr, width, height, processes,
)?)),
width,
height,
context: Rc::new(RefCell::new(WayVRContext::new(wvr, display)?)),
dmabuf_image: None,
view: None,
graphics: app.graphics.clone(),
@@ -154,35 +126,43 @@ impl WayVRRenderer {
planes[0].offset = data.offset as u32;
planes[0].stride = data.stride;
let frame = DmabufFrame {
format: FrameFormat {
width: self.width,
height: self.height,
fourcc: FourCC {
value: data.mod_info.fourcc,
let ctx = self.context.borrow_mut();
let wayvr = ctx.wayvr.borrow_mut();
if let Some(disp) = wayvr.get_display_by_handle(ctx.display) {
let frame = DmabufFrame {
format: FrameFormat {
width: disp.width,
height: disp.height,
fourcc: FourCC {
value: data.mod_info.fourcc,
},
modifier: data.mod_info.modifiers[0], /* possibly not proper? */
},
modifier: data.mod_info.modifiers[0], /* possibly not proper? */
},
num_planes: 1,
planes,
};
num_planes: 1,
planes,
};
let layouts: Vec<SubresourceLayout> = vec![SubresourceLayout {
offset: data.offset as _,
size: 0,
row_pitch: data.stride as _,
array_pitch: None,
depth_pitch: None,
}];
drop(wayvr);
let tex = self.graphics.dmabuf_texture_ex(
frame,
vulkano::image::ImageTiling::DrmFormatModifier,
layouts,
data.mod_info.modifiers,
)?;
self.dmabuf_image = Some(tex.clone());
self.view = Some(vulkano::image::view::ImageView::new_default(tex).unwrap());
let layouts: Vec<SubresourceLayout> = vec![SubresourceLayout {
offset: data.offset as _,
size: 0,
row_pitch: data.stride as _,
array_pitch: None,
depth_pitch: None,
}];
let tex = self.graphics.dmabuf_texture_ex(
frame,
vulkano::image::ImageTiling::DrmFormatModifier,
layouts,
data.mod_info.modifiers,
)?;
self.dmabuf_image = Some(tex.clone());
self.view = Some(vulkano::image::view::ImageView::new_default(tex).unwrap());
} else {
anyhow::bail!("Failed to fetch WayVR display")
}
}
Ok(())
@@ -232,31 +212,30 @@ impl OverlayRenderer for WayVRRenderer {
#[allow(dead_code)]
pub fn create_wayvr<O>(
app: &mut state::AppState,
width: u32,
height: u32,
processes: &[WayVRProcess],
display: &wayvr::display::Display,
display_handle: wayvr::display::DisplayHandle,
display_scale: f32,
) -> anyhow::Result<OverlayData<O>>
where
O: Default,
{
let transform = ui_transform(&[width, height]);
let transform = ui_transform(&[display.width, display.height]);
let state = OverlayState {
name: format!("WayVR Screen ({}x{})", width, height).into(),
name: format!("WayVR Screen ({}x{})", display.width, display.height).into(),
keyboard_focus: Some(KeyboardFocus::WayVR),
want_visible: true,
interactable: true,
recenter: true,
grabbable: true,
spawn_scale: 1.0,
spawn_point: vec3a(0.0, -0.5, 0.0),
spawn_scale: display_scale,
spawn_point: vec3a(0.0, -0.1, -1.0),
interaction_transform: transform,
..Default::default()
};
let wayvr = app.get_wayvr()?;
let renderer = WayVRRenderer::new(app, wayvr, width, height, processes)?;
let renderer = WayVRRenderer::new(app, wayvr, display_handle)?;
let context = renderer.context.clone();
let backend = Box::new(SplitOverlayBackend {
@@ -270,3 +249,100 @@ where
..Default::default()
})
}
fn action_wayvr_internal<O>(
catalog_name: &Arc<str>,
app_name: &Arc<str>,
app: &mut AppState,
) -> anyhow::Result<Option<OverlayData<O>>>
where
O: Default,
{
use crate::overlays::wayvr::create_wayvr;
let mut created_overlay: Option<OverlayData<O>> = None;
let wayvr = app.get_wayvr()?.clone();
let catalog = app
.session
.wayvr_config
.get_catalog(catalog_name)
.ok_or(anyhow::anyhow!(
"Failed to get catalog \"{}\"",
catalog_name
))?
.clone();
if let Some(app_entry) = catalog.get_app(app_name) {
let mut wayvr = wayvr.borrow_mut();
let disp_handle = if let Some(disp) = wayvr.get_display_by_name(&app_entry.target_display) {
disp
} else {
let conf_display = app
.session
.wayvr_config
.get_display(&app_entry.target_display)
.ok_or(anyhow::anyhow!(
"Cannot find display named \"{}\"",
app_entry.target_display
))?;
let display_handle = wayvr.create_display(
conf_display.width,
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>(
app,
display,
display_handle,
conf_display.scale,
)?);
display_handle
};
// Parse additional args
let args_vec: Vec<&str> = if let Some(args) = &app_entry.args {
args.as_str().split_whitespace().collect()
} else {
vec![]
};
// Parse additional env
let env_vec: Vec<(&str, &str)> = if let Some(env) = &app_entry.env {
// splits "FOO=BAR=TEST,123" into (&"foo", &"bar=test,123")
env.iter()
.filter_map(|e| e.as_str().split_once('='))
.collect()
} else {
vec![]
};
wayvr.spawn_process(disp_handle, &app_entry.exec, &args_vec, &env_vec)?
}
Ok(created_overlay)
}
// Returns newly created overlay (if needed)
pub fn action_wayvr<O>(
catalog_name: &Arc<str>,
app_name: &Arc<str>,
app: &mut AppState,
) -> Option<OverlayData<O>>
where
O: Default,
{
match action_wayvr_internal(catalog_name, app_name, app) {
Ok(res) => res,
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
}
}
}

View File

@@ -1,4 +1,4 @@
# looking to make changes?
# looking to make changes?
# drop me in ~/.config/wlxoverlay/watch.yaml
#
@@ -24,7 +24,7 @@ elements:
- type: Window
target: settings
action: ShowUi # only triggers if not exists
- type: Window
- type: Window
target: settings
action: Destroy # only triggers if exists since before current frame
@@ -55,12 +55,12 @@ elements:
scroll_up:
- type: Overlay
target: "kbd"
action:
action:
Opacity: { delta: 0.025 }
scroll_down:
- type: Overlay
target: "kbd"
action:
action:
Opacity: { delta: -0.025 }
# bottom row, of keyboard + overlays
@@ -75,9 +75,9 @@ elements:
long_click_up: Reset
right_up: ToggleImmovable
middle_up: ToggleInteraction
scroll_up:
scroll_up:
Opacity: { delta: 0.025 }
scroll_down:
scroll_down:
Opacity: { delta: -0.025 }
# local clock
@@ -89,7 +89,7 @@ elements:
source: Clock
format: "%H:%M" # 23:59
#format: "%I:%M %p" # 11:59 PM
# local date
- type: Label
rect: [20, 117, 200, 20]
@@ -126,7 +126,7 @@ elements:
fg_color: "#8bd5ca"
source: Static
text: "Tokyo" # change TZ1 label here
# alt clock 2
- type: Label
rect: [210, 150, 200, 50]
@@ -167,7 +167,7 @@ elements:
text: "Vol +"
click_down:
- type: Exec
command: [ "pactl", "set-sink-volume", "@DEFAULT_SINK@", "+5%" ]
command: ["pactl", "set-sink-volume", "@DEFAULT_SINK@", "+5%"]
- type: Button
rect: [315, 116, 70, 32]
corner_radius: 4
@@ -177,4 +177,4 @@ elements:
text: "Vol -"
click_down:
- type: Exec
command: [ "pactl", "set-sink-volume", "@DEFAULT_SINK@", "-5%" ]
command: ["pactl", "set-sink-volume", "@DEFAULT_SINK@", "-5%"]

47
src/res/wayvr.yaml Normal file
View File

@@ -0,0 +1,47 @@
# This is an example WayVR panel configuration. It demonstrates all the capabilities of this module.
# looking to make changes?
# drop me in ~/.config/wlxoverlay/wayvr.yaml
#
version: 1
displays:
disp_square:
width: 500
height: 350
scale: 1.0
disp_term:
width: 640
height: 480
scale: 1.25
disp_browser:
width: 1280
height: 720
scale: 2.0
disp_plasma:
width: 1280
height: 720
scale: 2.0
catalogs:
default_catalog:
apps:
- name: "Calc"
target_display: "disp_square"
exec: "kcalc"
env: ["FOO=bar"]
- name: "Terminal"
target_display: "disp_term"
exec: "konsole"
- name: "Browser"
target_display: "disp_browser"
exec: "cage"
args: "chromium -- --incognito"
- name: "Plasma"
target_display: "disp_plasma"
exec: "cage"
args: "dbus-run-session -- kwin_wayland --xwayland plasmashell"

View File

@@ -13,6 +13,9 @@ use std::{cell::RefCell, rc::Rc};
#[cfg(feature = "wayvr")]
use crate::backend::wayvr::WayVR;
#[cfg(feature = "wayvr")]
use crate::config_wayvr::{self, WayVRConfig};
use crate::{
backend::{input::InputState, overlay::OverlayID, task::TaskContainer},
config::{AStrMap, GeneralConfig},
@@ -125,6 +128,9 @@ impl AppState {
pub struct AppSession {
pub config: GeneralConfig,
#[cfg(feature = "wayvr")]
pub wayvr_config: WayVRConfig,
pub toast_topics: IdMap<ToastTopic, DisplayMethod>,
}
@@ -143,9 +149,14 @@ impl AppSession {
toast_topics.insert(*k, *v);
});
#[cfg(feature = "wayvr")]
let wayvr_config = config_wayvr::load_wayvr();
AppSession {
config,
toast_topics,
#[cfg(feature = "wayvr")]
wayvr_config,
}
}
}