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::webxr::{GlWindowDiscovery, WebXrRegistry};
11#[cfg(target_os = "windows")]
12use servo::webxr::{OpenXrAppInfo, OpenXrDiscovery};
13use servo::{Preferences, pref, prefs};
14use winit::event_loop::ActiveEventLoop;
15
16use crate::window::PlatformWindow;
17
18enum XrDiscovery {
19    GlWindow(GlWindowDiscovery),
20    #[cfg(target_os = "windows")]
21    OpenXr(OpenXrDiscovery),
22}
23
24pub(crate) struct XrDiscoveryWebXrRegistry {
25    xr_discovery: RefCell<Option<XrDiscovery>>,
26}
27
28impl XrDiscoveryWebXrRegistry {
29    pub(crate) fn new_boxed(
30        window: Rc<dyn PlatformWindow>,
31        event_loop: Option<&ActiveEventLoop>,
32        preferences: &Preferences,
33    ) -> Box<Self> {
34        let Some(event_loop) = event_loop else {
35            return Box::new(Self {
36                xr_discovery: RefCell::new(None),
37            });
38        };
39
40        let xr_discovery = if preferences.dom_webxr_openxr_enabled {
41            #[cfg(target_os = "windows")]
42            {
43                let app_info = OpenXrAppInfo::new("Servoshell", 0, "Servo", 0);
44                Some(XrDiscovery::OpenXr(OpenXrDiscovery::new(None, app_info)))
45            }
46            #[cfg(not(target_os = "windows"))]
47            None
48        } else if preferences.dom_webxr_glwindow_enabled {
49            let window = window.new_glwindow(event_loop);
50            Some(XrDiscovery::GlWindow(GlWindowDiscovery::new(window)))
51        } else {
52            None
53        };
54
55        Box::new(Self {
56            xr_discovery: RefCell::new(xr_discovery),
57        })
58    }
59}
60
61struct XrPrefObserver(Arc<AtomicBool>);
62
63impl prefs::PreferencesObserver for XrPrefObserver {
64    fn prefs_changed(&self, changes: &[(&'static str, prefs::PrefValue)]) {
65        if let Some((_, value)) = changes.iter().find(|(name, _)| *name == "dom_webxr_test") {
66            let prefs::PrefValue::Bool(value) = value else {
67                return;
68            };
69            self.0.store(*value, Ordering::Relaxed);
70        }
71    }
72}
73
74impl WebXrRegistry for XrDiscoveryWebXrRegistry {
75    fn register(&self, xr: &mut servo::webxr::MainThreadRegistry) {
76        use servo::webxr::HeadlessMockDiscovery;
77
78        let mock_enabled = Arc::new(AtomicBool::new(pref!(dom_webxr_test)));
79        xr.register_mock(HeadlessMockDiscovery::new(mock_enabled.clone()));
80        prefs::add_observer(Box::new(XrPrefObserver(mock_enabled)));
81
82        if let Some(xr_discovery) = self.xr_discovery.take() {
83            match xr_discovery {
84                XrDiscovery::GlWindow(discovery) => xr.register(discovery),
85                #[cfg(target_os = "windows")]
86                XrDiscovery::OpenXr(discovery) => xr.register(discovery),
87            }
88        }
89    }
90}