servo/ports/servoshell/desktop/webxr.rs
Josh Matthews ed6bf196c9
constellation: Broadcast preference changes to all content processes (#38716)
Building on the preference observer work from #38649, we now
automatically install an observer when multiprocess mode is enabled.
This observer notifies the constellation of updated preferences, which
in turn notifies each content process so the changes will be reflected
into script/layout as expected. There's a unit test that verifies this
works correctly by checking a preference-gated WebIDL property before
and after the preference is toggled.

Testing: New unit test added.
Fixes: #35966

Depends on #38649.

---------

Signed-off-by: Josh Matthews <josh@joshmatthews.net>
2025-08-20 06:43:16 +00:00

92 lines
3 KiB
Rust

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::cell::RefCell;
use std::rc::Rc;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use servo::config::pref;
use servo::config::prefs::{self, Preferences};
use servo::webxr::WebXrRegistry;
use servo::webxr::glwindow::GlWindowDiscovery;
#[cfg(target_os = "windows")]
use servo::webxr::openxr::{AppInfo, OpenXrDiscovery};
use winit::event_loop::ActiveEventLoop;
use super::window_trait::WindowPortsMethods;
enum XrDiscovery {
GlWindow(GlWindowDiscovery),
#[cfg(target_os = "windows")]
OpenXr(OpenXrDiscovery),
}
pub(crate) struct XrDiscoveryWebXrRegistry {
xr_discovery: RefCell<Option<XrDiscovery>>,
}
impl XrDiscoveryWebXrRegistry {
pub(crate) fn new_boxed(
window: Rc<dyn WindowPortsMethods>,
event_loop: Option<&ActiveEventLoop>,
preferences: &Preferences,
) -> Box<Self> {
let Some(event_loop) = event_loop else {
return Box::new(Self {
xr_discovery: RefCell::new(None),
});
};
let xr_discovery = if preferences.dom_webxr_openxr_enabled {
#[cfg(target_os = "windows")]
{
let app_info = AppInfo::new("Servoshell", 0, "Servo", 0);
Some(XrDiscovery::OpenXr(OpenXrDiscovery::new(None, app_info)))
}
#[cfg(not(target_os = "windows"))]
None
} else if preferences.dom_webxr_glwindow_enabled {
let window = window.new_glwindow(event_loop);
Some(XrDiscovery::GlWindow(GlWindowDiscovery::new(window)))
} else {
None
};
Box::new(Self {
xr_discovery: RefCell::new(xr_discovery),
})
}
}
struct XrPrefObserver(Arc<AtomicBool>);
impl prefs::Observer for XrPrefObserver {
fn prefs_changed(&self, changes: &[(&'static str, prefs::PrefValue)]) {
if let Some((_, value)) = changes.iter().find(|(name, _)| *name == "dom_webxr_test") {
let prefs::PrefValue::Bool(value) = value else {
return;
};
self.0.store(*value, Ordering::Relaxed);
}
}
}
impl WebXrRegistry for XrDiscoveryWebXrRegistry {
fn register(&self, xr: &mut servo::webxr::MainThreadRegistry) {
use servo::webxr::headless::HeadlessMockDiscovery;
let mock_enabled = Arc::new(AtomicBool::new(pref!(dom_webxr_test)));
xr.register_mock(HeadlessMockDiscovery::new(mock_enabled.clone()));
prefs::add_observer(Box::new(XrPrefObserver(mock_enabled)));
if let Some(xr_discovery) = self.xr_discovery.take() {
match xr_discovery {
XrDiscovery::GlWindow(discovery) => xr.register(discovery),
#[cfg(target_os = "windows")]
XrDiscovery::OpenXr(discovery) => xr.register(discovery),
}
}
}
}