servoshell/desktop/
webxr.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use std::cell::RefCell;
6use std::rc::Rc;
7use std::sync::Arc;
8use std::sync::atomic::{AtomicBool, Ordering};
9
10use servo::config::pref;
11use servo::config::prefs::{self, Preferences};
12use servo::webxr::WebXrRegistry;
13use servo::webxr::glwindow::GlWindowDiscovery;
14#[cfg(target_os = "windows")]
15use servo::webxr::openxr::{AppInfo, OpenXrDiscovery};
16use winit::event_loop::ActiveEventLoop;
17
18use super::window_trait::WindowPortsMethods;
19
20enum XrDiscovery {
21    GlWindow(GlWindowDiscovery),
22    #[cfg(target_os = "windows")]
23    OpenXr(OpenXrDiscovery),
24}
25
26pub(crate) struct XrDiscoveryWebXrRegistry {
27    xr_discovery: RefCell<Option<XrDiscovery>>,
28}
29
30impl XrDiscoveryWebXrRegistry {
31    pub(crate) fn new_boxed(
32        window: Rc<dyn WindowPortsMethods>,
33        event_loop: Option<&ActiveEventLoop>,
34        preferences: &Preferences,
35    ) -> Box<Self> {
36        let Some(event_loop) = event_loop else {
37            return Box::new(Self {
38                xr_discovery: RefCell::new(None),
39            });
40        };
41
42        let xr_discovery = if preferences.dom_webxr_openxr_enabled {
43            #[cfg(target_os = "windows")]
44            {
45                let app_info = AppInfo::new("Servoshell", 0, "Servo", 0);
46                Some(XrDiscovery::OpenXr(OpenXrDiscovery::new(None, app_info)))
47            }
48            #[cfg(not(target_os = "windows"))]
49            None
50        } else if preferences.dom_webxr_glwindow_enabled {
51            let window = window.new_glwindow(event_loop);
52            Some(XrDiscovery::GlWindow(GlWindowDiscovery::new(window)))
53        } else {
54            None
55        };
56
57        Box::new(Self {
58            xr_discovery: RefCell::new(xr_discovery),
59        })
60    }
61}
62
63struct XrPrefObserver(Arc<AtomicBool>);
64
65impl prefs::Observer for XrPrefObserver {
66    fn prefs_changed(&self, changes: &[(&'static str, prefs::PrefValue)]) {
67        if let Some((_, value)) = changes.iter().find(|(name, _)| *name == "dom_webxr_test") {
68            let prefs::PrefValue::Bool(value) = value else {
69                return;
70            };
71            self.0.store(*value, Ordering::Relaxed);
72        }
73    }
74}
75
76impl WebXrRegistry for XrDiscoveryWebXrRegistry {
77    fn register(&self, xr: &mut servo::webxr::MainThreadRegistry) {
78        use servo::webxr::headless::HeadlessMockDiscovery;
79
80        let mock_enabled = Arc::new(AtomicBool::new(pref!(dom_webxr_test)));
81        xr.register_mock(HeadlessMockDiscovery::new(mock_enabled.clone()));
82        prefs::add_observer(Box::new(XrPrefObserver(mock_enabled)));
83
84        if let Some(xr_discovery) = self.xr_discovery.take() {
85            match xr_discovery {
86                XrDiscovery::GlWindow(discovery) => xr.register(discovery),
87                #[cfg(target_os = "windows")]
88                XrDiscovery::OpenXr(discovery) => xr.register(discovery),
89            }
90        }
91    }
92}