diff options
-rw-r--r-- | components/script/dom/xr.rs | 4 | ||||
-rw-r--r-- | components/script/dom/xrinputsourcearray.rs | 34 | ||||
-rw-r--r-- | components/script/dom/xrsession.rs | 33 |
3 files changed, 47 insertions, 24 deletions
diff --git a/components/script/dom/xr.rs b/components/script/dom/xr.rs index 00f86203b26..1006fd20e65 100644 --- a/components/script/dom/xr.rs +++ b/components/script/dom/xr.rs @@ -284,7 +284,6 @@ impl XR { return; }, }; - let session = XRSession::new(&self.global(), session, mode, frame_receiver); if mode == XRSessionMode::Inline { self.active_inline_sessions @@ -294,6 +293,9 @@ impl XR { self.set_active_immersive_session(&session); } promise.resolve_native(&session); + // https://github.com/immersive-web/webxr/issues/961 + // This must be called _after_ the promise is resolved + session.setup_initial_inputs(); } pub fn get_displays(&self) -> Result<Vec<DomRoot<VRDisplay>>, ()> { diff --git a/components/script/dom/xrinputsourcearray.rs b/components/script/dom/xrinputsourcearray.rs index 86a107bcd27..99db386050b 100644 --- a/components/script/dom/xrinputsourcearray.rs +++ b/components/script/dom/xrinputsourcearray.rs @@ -38,30 +38,22 @@ impl XRInputSourceArray { ) } - pub fn set_initial_inputs(&self, session: &XRSession) { + pub fn add_input_sources(&self, session: &XRSession, inputs: &[InputSource]) { let mut input_sources = self.input_sources.borrow_mut(); let global = self.global(); - session.with_session(|sess| { - for info in sess.initial_inputs() { - // XXXManishearth we should be able to listen for updates - // to the input sources - let input = XRInputSource::new(&global, &session, info.clone()); - input_sources.push(Dom::from_ref(&input)); - } - }); - } - pub fn add_input_source(&self, session: &XRSession, info: InputSource) { - let mut input_sources = self.input_sources.borrow_mut(); - let global = self.global(); - debug_assert!( - input_sources.iter().find(|i| i.id() == info.id).is_none(), - "Should never add a duplicate input id!" - ); - let input = XRInputSource::new(&global, &session, info); - input_sources.push(Dom::from_ref(&input)); - - let added = [input]; + let mut added = vec![]; + for info in inputs { + // This is quadratic, but won't be a problem for the only case + // where we add multiple input sources (the initial input sources case) + debug_assert!( + input_sources.iter().find(|i| i.id() == info.id).is_none(), + "Should never add a duplicate input id!" + ); + let input = XRInputSource::new(&global, &session, info.clone()); + input_sources.push(Dom::from_ref(&input)); + added.push(input); + } let event = XRInputSourcesChangeEvent::new( &global, diff --git a/components/script/dom/xrsession.rs b/components/script/dom/xrsession.rs index 4814eb379ff..89c430044df 100644 --- a/components/script/dom/xrsession.rs +++ b/components/script/dom/xrsession.rs @@ -136,7 +136,6 @@ impl XRSession { global, XRSessionBinding::Wrap, ); - input_sources.set_initial_inputs(&ret); ret.attach_event_handler(); ret.setup_raf_loop(frame_receiver); ret @@ -208,6 +207,36 @@ impl XRSession { self.session.borrow_mut().set_event_dest(sender); } + // Must be called after the promise for session creation is resolved + // https://github.com/immersive-web/webxr/issues/961 + // + // This enables content that assumes all input sources are accompanied + // by an inputsourceschange event to work properly. Without + pub fn setup_initial_inputs(&self) { + let initial_inputs = self.session.borrow().initial_inputs().to_owned(); + + if initial_inputs.is_empty() { + // do not fire an empty event + return; + } + + let global = self.global(); + let window = global.as_window(); + let (task_source, canceller) = window + .task_manager() + .dom_manipulation_task_source_with_canceller(); + let this = Trusted::new(self); + // Queue a task so that it runs after resolve()'s microtasks complete + // so that content has a chance to attach a listener for inputsourceschange + let _ = task_source.queue_with_canceller( + task!(session_initial_inputs: move || { + let this = this.root(); + this.input_sources.add_input_sources(&this, &initial_inputs); + }), + &canceller, + ); + } + fn event_callback(&self, event: XREvent) { match event { XREvent::SessionEnd => { @@ -290,7 +319,7 @@ impl XRSession { event.upcast::<Event>().fire(self.upcast()); }, XREvent::AddInput(info) => { - self.input_sources.add_input_source(self, info); + self.input_sources.add_input_sources(self, &[info]); }, XREvent::RemoveInput(id) => { self.input_sources.remove_input_source(self, id); |