don't show options that are incompatible

This commit is contained in:
galister 2026-07-30 20:24:30 +09:00
parent 395e9d1919
commit 7efc4bb0fc
24 changed files with 130 additions and 82 deletions

View File

@ -1,6 +1,6 @@
use std::rc::Rc;
use crate::tab::settings::{self, SettingType, Task, horiz_cell, mount_requires_restart};
use crate::tab::settings::{self, horiz_cell, mount_requires_restart, SettingType, Task};
use wgui::{
components::{
button::{ButtonClickEvent, ComponentButton},
@ -13,7 +13,7 @@ use wgui::{
widget::label::WidgetLabel,
windowing::context_menu,
};
use wlx_common::config::GeneralConfig;
use wlx_common::{config::GeneralConfig, dash_interface::InterfaceFeats, DesktopBackend, XrBackend};
pub fn options_category(
mp: &mut MacroParams,
@ -272,6 +272,7 @@ where
let btn = mp.parser_state.fetch_component_as::<ComponentButton>(&id)?;
btn.on_click(Rc::new({
let feats = mp.feats;
let tasks = mp.tasks.clone();
move |_common, e: ButtonClickEvent| {
tasks.push(Task::OpenContextMenu(
@ -282,6 +283,18 @@ where
if item.get_bool("Hidden").unwrap_or(false) {
return None;
}
if item
.get_str("Backend")
.is_some_and(|x| XrBackend::try_from(x).unwrap() != feats.xr_backend)
{
return None;
}
if item
.get_str("Desktop")
.is_some_and(|x| DesktopBackend::try_from(x).unwrap() != feats.desktop_backend)
{
return None;
}
let value = item.as_ref();
let title = SettingType::get_enum_title_inner(*item);
@ -404,4 +417,5 @@ pub struct MacroParams<'a> {
pub config: &'a mut GeneralConfig,
pub tasks: Tasks<settings::Task>,
pub idx: usize,
pub feats: InterfaceFeats,
}

View File

@ -680,6 +680,7 @@ impl<T> TabSettings<T> {
config: frontend.interface.general_config(data),
tasks: self.tasks.clone(),
idx: 9001,
feats,
};
let settings_mount_params = SettingsMountParams {
@ -733,7 +734,7 @@ impl<T> TabSettings<T> {
let tasks = Tasks::default();
let tabs = parser_state.fetch_component_as::<ComponentTabs>("tabs")?;
if !frontend.interface.get_feats(data).openxr {
if !frontend.interface.get_feats(data).xr_backend.is_open_xr() {
let skybox_btn = tabs.get_tab_button("skybox").unwrap();
frontend
.layout

View File

@ -92,7 +92,7 @@ impl State {
"APP_SETTINGS.CONTROLS",
"dashboard/controller.svg",
)?;
if par.feats.openxr {
if par.feats.xr_backend.is_open_xr() {
create_input_profiles_button(par.mp, c, tasks.clone(), &popup)?;
}
options_dropdown::<wlx_common::config::AltModifier>(par.mp, c, &SettingType::KeyboardMiddleClick)?;
@ -107,7 +107,7 @@ impl State {
options_slider_f32(par.mp, c, SettingType::LongPressDuration, 0.1, 2.0, 0.1)?;
options_slider_f32(par.mp, c, SettingType::SnapAngleDeg, 0., 45., 5.)?;
if par.feats.openxr {
if par.feats.xr_backend.is_open_xr() {
options_slider_f32(par.mp, c, SettingType::PointerLerpFactor, 0.1, 1.0, 0.1)?;
}

View File

@ -152,7 +152,7 @@ impl State {
options_checkbox(par.mp, c, SettingType::NotificationsEnabled)?;
options_checkbox(par.mp, c, SettingType::NotificationsSoundEnabled)?;
options_checkbox(par.mp, c, SettingType::KeyboardSoundEnabled)?;
if !par.feats.openxr || par.feats.monado {
if par.feats.xr_backend.is_open_vr() || par.feats.monado {
// monado or openvr
options_checkbox(par.mp, c, SettingType::BlockGameInput)?;
options_checkbox(par.mp, c, SettingType::BlockGameInputIgnoreWatch)?;

View File

@ -54,7 +54,7 @@ impl State {
let id_gravity_enabled_parent = tab_state.get_widget_id("gravity_enabled_parent")?;
let id_space_gravity_parent = tab_state.get_widget_id("space_gravity_parent")?;
if !par.feats.openxr || par.feats.monado {
if par.feats.xr_backend.is_open_vr() || par.feats.monado {
// monado or openvr
options_button(

View File

@ -172,8 +172,8 @@
<cell translation="BAR.HANDSFREE.NONE" _press="::HandsfreeMode None" _press2="::ContextMenuClose" />
<cell translation="BAR.HANDSFREE.HMD" _press="::HandsfreeMode Hmd" _press2="::ContextMenuClose" />
<cell translation="BAR.HANDSFREE.HMD_ONLY" _press="::HandsfreeMode HmdOnly" _press2="::ContextMenuClose" />
<cell translation="BAR.HANDSFREE.EYE_TRACKING" _press="::HandsfreeMode EyeTracking" _press2="::ContextMenuClose" />
<cell translation="BAR.HANDSFREE.EYE_ONLY" _press="::HandsfreeMode EyeTrackingOnly" _press2="::ContextMenuClose" />
<cell translation="BAR.HANDSFREE.EYE_TRACKING" _press="::HandsfreeMode EyeTracking" _press2="::ContextMenuClose" skip="~openvr" />
<cell translation="BAR.HANDSFREE.EYE_ONLY" _press="::HandsfreeMode EyeTrackingOnly" _press2="::ContextMenuClose" skip="~openvr" />
</context_menu>
</blueprint>
@ -181,8 +181,8 @@
<context_menu >
<cell translation="BAR.EDIT_MODE_TOGGLE" _press="::EditToggle" _press2="::ContextMenuClose" />
<cell translation="BAR.HANDSFREE.TITLE" _press="::ContextMenuOpen menu_handsfree" />
<cell translation="BAR.ADD_MIRROR" _press="::NewMirror" />
<cell translation="BAR.ADD_PASSTHRU" _press="::NewPassthru" />
<cell translation="BAR.ADD_MIRROR" _press="::NewMirror" skip="~not_wayland" />
<cell translation="BAR.ADD_PASSTHRU" _press="::NewPassthru" skip="~openvr" />
<cell translation="BAR.ADD_NEW_SET" _press="::AddSet" />
<cell translation="BAR.DELETE_CURRENT_SET" _press="::DeleteSet" />
</context_menu>

View File

@ -15,12 +15,6 @@ pub mod task;
use thiserror::Error;
#[derive(Clone, Copy)]
pub enum XrBackend {
OpenXR,
OpenVR,
}
#[derive(Error, Debug)]
pub enum BackendError {
#[error("backend not supported")]

View File

@ -15,9 +15,9 @@ use vulkano::{Handle, VulkanObject, device::physical::PhysicalDevice};
use wlx_common::overlays::ToastTopic;
use crate::{
Args, FRAME_COUNTER, RUNNING,
Args, FRAME_COUNTER, RUNNING, XrBackend,
backend::{
BackendError, XrBackend,
BackendError,
input::interact,
openvr::{
helpers::adjust_gain,

View File

@ -13,9 +13,9 @@ use vulkano::{Handle, VulkanObject};
use wlx_common::overlays::{StereoMode, ToastTopic};
use crate::{
Args, FRAME_COUNTER, RUNNING,
Args, FRAME_COUNTER, RUNNING, XrBackend,
backend::{
BackendError, XrBackend,
BackendError,
input::interact,
openxr::{helpers::try_apply_chroma_key, lines::LinePool, overlay::OpenXrOverlayData},
task::{OpenXrTask, OverlayTask, TaskType},
@ -88,11 +88,9 @@ pub fn openxr_run(args: &Args) -> Result<(), BackendError> {
app.late_init();
let mut playspace_mover = app.monado_state.as_mut().and_then(|m| {
playspace::PlayspaceMover::new()
.map_err(|e| log::warn!("Will not use Monado playspace mover: {e}"))
.ok()
});
let mut playspace_mover = playspace::PlayspaceMover::new()
.map_err(|e| log::warn!("Will not use Monado playspace mover: {e}"))
.ok();
let mut blocker = app
.monado_state

View File

@ -44,7 +44,8 @@ use sysinfo::Pid;
use tracing::level_filters::LevelFilter;
use tracing_subscriber::{EnvFilter, layer::SubscriberExt, util::SubscriberInitExt};
use crate::{backend::XrBackend, subsystem::dbus::DbusConnector};
use crate::subsystem::dbus::DbusConnector;
use wlx_common::XrBackend;
pub static FRAME_COUNTER: AtomicUsize = AtomicUsize::new(0);
pub static RUNNING: AtomicBool = AtomicBool::new(true);

View File

@ -35,7 +35,6 @@ use libmonado::{ClientLogic, DeviceLogic};
use crate::{
RESTART, RUNNING,
backend::{
XrBackend,
input::{Haptics, HoverResult, PointerHit, PointerMode},
task::{GlobalChange, OverlayTask, PlayspaceTask, TaskType, ToggleMode},
wayvr::{
@ -92,7 +91,7 @@ impl DashFrontend {
interface: Box::new(interface),
lang_provider: &WayVRLangProvider::from_config(&app.session.config),
show_welcome: tutorial,
has_monado: matches!(app.xr_backend, XrBackend::OpenXR),
has_monado: app.xr_backend.is_open_xr(),
theme: app.wgui_theme.clone(),
color_palette: &*app.session.config.color_palette,
executor: app.executor.clone(),
@ -580,7 +579,8 @@ impl DashInterface<AppState> for DashInterfaceLive {
fn get_feats(&mut self, data: &mut AppState) -> dash_interface::InterfaceFeats {
dash_interface::InterfaceFeats {
openxr: matches!(data.xr_backend, XrBackend::OpenXR),
xr_backend: data.xr_backend,
desktop_backend: data.desktop_backend,
#[cfg(feature = "openxr")]
monado: data.monado_state.is_some(),
#[cfg(not(feature = "openxr"))]

View File

@ -46,6 +46,10 @@ fn new_doc_params(panel: &mut GuiPanel<KeyboardState>) -> ParseDocumentParams<'s
}
}
fn bool_to_rc_str(val: bool) -> Rc<str> {
if val { "1" } else { "0" }.into()
}
#[allow(clippy::too_many_lines, clippy::significant_drop_tightening)]
pub(super) fn create_keyboard_panel(
app: &mut AppState,
@ -53,6 +57,15 @@ pub(super) fn create_keyboard_panel(
state: KeyboardState,
layout: &layout::Layout,
) -> anyhow::Result<GuiPanel<KeyboardState>> {
let mut params = NewGuiPanelParams::<AppState>::default();
params
.extra_vars
.insert("openvr".into(), bool_to_rc_str(app.xr_backend.is_open_vr()));
params.extra_vars.insert(
"not_wayland".into(),
bool_to_rc_str(!app.desktop_backend.is_wayland()),
);
let mut panel =
GuiPanel::new_from_template(app, "gui/keyboard.xml", state, NewGuiPanelParams::default())?;

View File

@ -49,7 +49,7 @@ pub const KEYBOARD_NAME: &str = "kbd";
const AUTO_RELEASE_MODS: [KeyModifier; 5] = [SHIFT, CTRL, ALT, SUPER, ALTGR];
const SYSTEM_LAYOUT_ALIASES: [&str; 5] = ["mozc", "pinyin", "hangul", "sayura", "unikey"];
pub fn create_keyboard(app: &mut AppState, wayland: bool) -> anyhow::Result<OverlayWindowConfig> {
pub fn create_keyboard(app: &mut AppState) -> anyhow::Result<OverlayWindowConfig> {
let layout = layout::Layout::load_from_disk();
let default_state = KeyboardState {
modifiers: 0,
@ -70,7 +70,7 @@ pub fn create_keyboard(app: &mut AppState, wayland: bool) -> anyhow::Result<Over
active_layout: KeyboardPanelKey::default(),
default_state,
wlx_layout: layout,
wayland,
wayland: app.desktop_backend.is_wayland(),
re_fcitx: Regex::new(r"^keyboard-([^-]+)(?:-([^-]+))?$").unwrap(),
};

View File

@ -7,10 +7,8 @@ use glam::{Affine2, DVec2, Vec2, vec2};
use wlx_capture::{WlxCapture, frame::Transform};
use crate::{
backend::{
XrBackend,
input::{self, HoverResult, PointerHit, PointerMode},
},
XrBackend,
backend::input::{HoverResult, PointerHit, PointerMode},
overlays::screen::capture::MyFirstDmaExporter,
state::AppState,
subsystem::{
@ -82,11 +80,7 @@ impl ScreenBackend {
meta: None,
mouse_transform: Affine2::ZERO,
interaction_transform: None,
stereo: if matches!(xr_backend, XrBackend::OpenXR) {
Some(StereoMode::None)
} else {
None
},
stereo: xr_backend.is_open_xr().then_some(StereoMode::None),
stereo_full_frame: false,
stereo_adjust_mouse: false,
logical_pos: Vec2::ZERO,

View File

@ -12,6 +12,7 @@ use crate::{
window::{OverlayCategory, OverlayWindowConfig},
},
};
use wlx_common::DesktopBackend;
pub mod backend;
pub mod capture;
@ -65,14 +66,17 @@ pub struct ScreenCreateData {
pub screens: Vec<(ScreenMeta, OverlayWindowConfig)>,
}
pub fn create_screens(app: &mut AppState) -> anyhow::Result<(ScreenCreateData, bool)> {
pub fn create_screens(app: &mut AppState) -> anyhow::Result<(ScreenCreateData, DesktopBackend)> {
app.screens.clear();
#[cfg(feature = "wayland")]
{
if let Some(mut wl) = wlx_capture::wayland::WlxClient::new() {
log::info!("Wayland detected.");
return Ok((wl::create_screens_wayland(&mut wl, app)?, true));
return Ok((
wl::create_screens_wayland(&mut wl, app)?,
DesktopBackend::Wayland,
));
}
log::info!("Wayland not detected, assuming X11.");
}
@ -81,11 +85,11 @@ pub fn create_screens(app: &mut AppState) -> anyhow::Result<(ScreenCreateData, b
{
#[cfg(feature = "pipewire")]
match x11::create_screens_x11pw(app) {
Ok(data) => return Ok((data, false)),
Ok(data) => return Ok((data, DesktopBackend::X11)),
Err(e) => log::info!("Will not use X11 PipeWire capture: {e:?}"),
}
Ok((x11::create_screens_xshm(app)?, false))
return Ok((x11::create_screens_xshm(app)?, DesktopBackend::X11));
}
#[cfg(not(feature = "x11"))]
anyhow::bail!("No backends left to try.")

View File

@ -36,7 +36,6 @@ use wlx_common::{
use crate::{
backend::{
XrBackend,
input::{self, HoverResult},
task::{OverlayTask, TaskType},
wayvr::{
@ -249,11 +248,7 @@ impl WvrWindowBackend {
just_resumed: false,
meta: None,
mouse: None,
stereo: if matches!(app.xr_backend, XrBackend::OpenXR) {
Some(StereoMode::None)
} else {
None
},
stereo: app.xr_backend.is_open_xr().then_some(StereoMode::None),
stereo_full_frame: false,
stereo_adjust_mouse: false,
cur_image: None,

View File

@ -37,6 +37,8 @@ use crate::{
window::{OverlayCategory, OverlayWindowConfig},
},
};
#[cfg(feature = "wayland")]
use wlx_common::DesktopBackend;
const WHISPER_NAME: &str = "whisper";
@ -69,19 +71,15 @@ impl WhisperState {
}
}
pub fn create_whisper(
app: &mut AppState,
headless: bool,
wayland: bool,
) -> anyhow::Result<OverlayWindowConfig> {
let clipboard_provider: Option<Box<dyn ClipboardProvider>> = match (headless, wayland) {
pub fn create_whisper(app: &mut AppState) -> anyhow::Result<OverlayWindowConfig> {
let clipboard_provider: Option<Box<dyn ClipboardProvider>> = match app.desktop_backend {
#[cfg(feature = "wayland")]
(false, true) => clipboard::wl::Provider::new()
DesktopBackend::Wayland => clipboard::wl::Provider::new()
.log_err("Could not create Wayland clipboard provider")
.ok()
.map(|p| Box::new(p) as Box<dyn ClipboardProvider>),
#[cfg(feature = "x11")]
(false, false) => clipboard::x11::Provider::new()
DesktopBackend::X11 => clipboard::x11::Provider::new()
.log_err("Could not create X11 clipboard provider")
.ok()
.map(|p| Box::new(p) as Box<dyn ClipboardProvider>),

View File

@ -27,6 +27,7 @@ use wlx_common::{
#[cfg(feature = "openxr")]
use crate::backend;
use crate::backend::wayvr::WvrServerState;
use wlx_common::DesktopBackend;
use crate::subsystem::notifications::NotificationManager;
#[cfg(feature = "osc")]
@ -35,7 +36,8 @@ use crate::subsystem::osc::OscSender;
#[cfg(feature = "whisper")]
use crate::subsystem::whisper_stt::WhisperStt;
use crate::{
backend::{XrBackend, input::InputState, task::TaskContainer},
XrBackend,
backend::{input::InputState, task::TaskContainer},
config::load_general_config,
graphics::WGfxExtras,
gui,
@ -71,6 +73,7 @@ pub struct AppState {
pub dbus: DbusConnector,
pub xr_backend: XrBackend,
pub desktop_backend: DesktopBackend,
pub ipc_server: ipc_server::WayVRServer,
pub wayvr_signals: SyncEventQueue<WayVRSignal>,
@ -218,6 +221,7 @@ impl AppState {
xr_backend,
ipc_server,
wayvr_signals: wvr_signals,
desktop_backend: DesktopBackend::Headless, // set by OverlayWindowManager
desktop_finder,
notifications: NotificationManager::new(),
@ -249,7 +253,7 @@ impl AppState {
self.notifications.run_udp();
#[cfg(feature = "openxr")]
if matches!(self.xr_backend, XrBackend::OpenXR) {
if self.xr_backend.is_open_xr() {
use crate::backend::openxr::monado_state::MonadoState;
log::debug!("Connecting to Monado IPC");

View File

@ -81,8 +81,6 @@ where
initialized: false,
};
let mut wayland = false;
if headless {
log::info!("Running in headless mode; keyboard will be en-US");
} else {
@ -90,7 +88,8 @@ where
// this is the default and would be overwritten by
// OverlayWindowManager::restore_layout down below
match create_screens(app) {
Ok((data, is_wayland)) => {
Ok((data, backend)) => {
app.desktop_backend = backend;
let last_idx = data.screens.len() - 1;
for (idx, (meta, mut config)) in data.screens.into_iter().enumerate() {
config.show_on_spawn = true;
@ -102,14 +101,12 @@ where
}
app.screens.push(meta);
}
wayland = is_wayland;
}
Err(e) => log::error!("Unable to initialize screens: {e:?}"),
}
}
let mut keyboard = OverlayWindowData::from_config(create_keyboard(app, wayland)?);
let mut keyboard = OverlayWindowData::from_config(create_keyboard(app)?);
keyboard.config.show_on_spawn = true;
me.keyboard_id = me.add(keyboard, app);
@ -145,7 +142,7 @@ where
#[cfg(feature = "whisper")]
{
use crate::overlays::whisper::create_whisper;
let whisper = OverlayWindowData::from_config(create_whisper(app, headless, wayland)?);
let whisper = OverlayWindowData::from_config(create_whisper(app)?);
me.add(whisper, app);
}

View File

@ -353,7 +353,7 @@ impl ParserState {
"tooltip_str" => tooltip = Some(Translation::from_raw_text(value)),
"action" => action_name = Some(value.into()),
other => {
if !other.starts_with('_') {
if !other.starts_with('_') && other != "skip" {
anyhow::bail!("unexpected \"{other}\" attribute");
}
attribs.push(AttribPair::new(key, replace_vars(value, template_params)));
@ -986,7 +986,8 @@ fn parse_child<'a>(
) -> anyhow::Result<()> {
let tag_name = child_node.tag_name().name();
match child_node.attribute("skip") {
Some("1") => {
Some(val) => {
// TODO: need to resolve variables in val
return Ok(()); // do not parse this element
}
_ => {}

View File

@ -25,18 +25,34 @@ pub enum CaptureMethod {
Auto,
#[serde(alias = "pipewire")]
#[strum(props(Text = "PipeWire GPU", Tooltip = "APP_SETTINGS.OPTION.PIPEWIRE_HELP"))]
#[strum(props(
Text = "PipeWire GPU",
Tooltip = "APP_SETTINGS.OPTION.PIPEWIRE_HELP",
Desktop = "Wayland"
))]
PipeWire,
#[strum(props(Text = "ScreenCopy GPU", Tooltip = "APP_SETTINGS.OPTION.SCREENCOPY_GPU_HELP"))]
#[strum(props(
Text = "ScreenCopy GPU",
Tooltip = "APP_SETTINGS.OPTION.SCREENCOPY_GPU_HELP",
Desktop = "Wayland"
))]
ScreenCopyGpu,
#[serde(alias = "pw-fallback")]
#[strum(props(Text = "PipeWire CPU", Tooltip = "APP_SETTINGS.OPTION.PW_FALLBACK_HELP"))]
#[strum(props(
Text = "PipeWire CPU",
Tooltip = "APP_SETTINGS.OPTION.PW_FALLBACK_HELP",
Desktop = "Wayland"
))]
PipeWireCpu,
#[serde(alias = "screencopy")]
#[strum(props(Text = "ScreenCopy CPU", Tooltip = "APP_SETTINGS.OPTION.SCREENCOPY_HELP"))]
#[strum(props(
Text = "ScreenCopy CPU",
Tooltip = "APP_SETTINGS.OPTION.SCREENCOPY_HELP",
Desktop = "Wayland"
))]
ScreenCopyCpu,
}
@ -51,7 +67,8 @@ pub enum InputEmulationMethod {
#[strum(props(
Translation = "APP_SETTINGS.OPTION.WL_VIRTUAL",
Tooltip = "APP_SETTINGS.OPTION.WL_VIRTUAL_HELP"
Tooltip = "APP_SETTINGS.OPTION.WL_VIRTUAL_HELP",
Desktop = "Wayland"
))]
WlVirtual,
@ -97,9 +114,9 @@ pub enum HandsfreePointer {
Hmd,
#[strum(props(Translation = "APP_SETTINGS.OPTION.HMD_ONLY"))]
HmdOnly,
#[strum(props(Translation = "APP_SETTINGS.OPTION.EYE_PINCH"))]
#[strum(props(Translation = "APP_SETTINGS.OPTION.EYE_PINCH", Backend = "OpenXR"))]
EyeTracking,
#[strum(props(Translation = "APP_SETTINGS.OPTION.EYE_ONLY"))]
#[strum(props(Translation = "APP_SETTINGS.OPTION.EYE_ONLY", Backend = "OpenXR"))]
EyeTrackingOnly,
}
@ -108,7 +125,7 @@ pub enum HandsfreeAltTab {
#[strum(props(Translation = "APP_SETTINGS.OPTION.HMD_ONLY"))]
#[default]
Hmd,
#[strum(props(Translation = "APP_SETTINGS.OPTION.EYE_ONLY"))]
#[strum(props(Translation = "APP_SETTINGS.OPTION.EYE_ONLY", Backend = "OpenXR"))]
EyeTracking,
}

View File

@ -3,7 +3,7 @@ use wayvr_ipc::{
packet_server::{WvrProcess, WvrProcessHandle, WvrWindow, WvrWindowHandle},
};
use crate::{config::GeneralConfig, desktop_finder::DesktopFinder};
use crate::{DesktopBackend, XrBackend, config::GeneralConfig, desktop_finder::DesktopFinder};
#[derive(Clone)]
pub struct MonadoClient {
@ -47,7 +47,8 @@ pub enum DashPlayspaceTask {
#[derive(Clone, Copy)]
pub struct InterfaceFeats {
pub openxr: bool,
pub xr_backend: XrBackend,
pub desktop_backend: DesktopBackend,
pub monado: bool,
pub whisper: bool,
}

View File

@ -1,4 +1,4 @@
use slotmap::{DenseSlotMap, new_key_type};
use slotmap::{new_key_type, DenseSlotMap};
use wayvr_ipc::{
packet_client::WvrProcessLaunchParams,
packet_server::{WvrProcess, WvrProcessHandle, WvrWindow, WvrWindowHandle},
@ -235,7 +235,8 @@ impl DashInterface<()> for DashInterfaceEmulated {
fn get_feats(&mut self, _data: &mut ()) -> dash_interface::InterfaceFeats {
dash_interface::InterfaceFeats {
openxr: true,
xr_backend: crate::XrBackend::OpenXR,
desktop_backend: crate::DesktopBackend::Wayland,
monado: true,
whisper: true,
}

View File

@ -1,3 +1,5 @@
use strum::{EnumIs, EnumString};
pub mod astr_containers;
pub mod async_executor;
pub mod audio;
@ -17,3 +19,16 @@ pub mod overlays;
pub mod palette;
pub mod timestep;
pub mod windowing;
#[derive(Clone, Copy, EnumIs, EnumString, PartialEq, Eq)]
pub enum XrBackend {
OpenXR,
OpenVR,
}
#[derive(Clone, Copy, EnumIs, EnumString, PartialEq, Eq)]
pub enum DesktopBackend {
Headless,
Wayland,
X11,
}