| /* 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 dom_struct::dom_struct; |
| use webxr_api::{InputId, InputSource}; |
| |
| use crate::dom::bindings::cell::DomRefCell; |
| use crate::dom::bindings::codegen::Bindings::XRInputSourceArrayBinding::XRInputSourceArrayMethods; |
| use crate::dom::bindings::inheritance::Castable; |
| use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object}; |
| use crate::dom::bindings::root::{Dom, DomRoot}; |
| use crate::dom::event::Event; |
| use crate::dom::window::Window; |
| use crate::dom::xrinputsource::XRInputSource; |
| use crate::dom::xrinputsourceschangeevent::XRInputSourcesChangeEvent; |
| use crate::dom::xrsession::XRSession; |
| use crate::script_runtime::CanGc; |
| |
| #[dom_struct] |
| pub(crate) struct XRInputSourceArray { |
| reflector_: Reflector, |
| input_sources: DomRefCell<Vec<Dom<XRInputSource>>>, |
| } |
| |
| impl XRInputSourceArray { |
| fn new_inherited() -> XRInputSourceArray { |
| XRInputSourceArray { |
| reflector_: Reflector::new(), |
| input_sources: DomRefCell::new(vec![]), |
| } |
| } |
| |
| pub(crate) fn new(window: &Window, can_gc: CanGc) -> DomRoot<XRInputSourceArray> { |
| reflect_dom_object( |
| Box::new(XRInputSourceArray::new_inherited()), |
| window, |
| can_gc, |
| ) |
| } |
| |
| pub(crate) fn add_input_sources( |
| &self, |
| session: &XRSession, |
| inputs: &[InputSource], |
| can_gc: CanGc, |
| ) { |
| let global = self.global(); |
| let window = global.as_window(); |
| |
| 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!( |
| !self |
| .input_sources |
| .borrow() |
| .iter() |
| .any(|i| i.id() == info.id), |
| "Should never add a duplicate input id!" |
| ); |
| let input = XRInputSource::new(window, session, info.clone(), can_gc); |
| self.input_sources.borrow_mut().push(Dom::from_ref(&input)); |
| added.push(input); |
| } |
| |
| let event = XRInputSourcesChangeEvent::new( |
| window, |
| atom!("inputsourceschange"), |
| false, |
| true, |
| session, |
| &added, |
| &[], |
| can_gc, |
| ); |
| event.upcast::<Event>().fire(session.upcast(), can_gc); |
| } |
| |
| pub(crate) fn remove_input_source(&self, session: &XRSession, id: InputId, can_gc: CanGc) { |
| let global = self.global(); |
| let window = global.as_window(); |
| let removed = if let Some(i) = self.input_sources.borrow().iter().find(|i| i.id() == id) { |
| i.gamepad().update_connected(false, false, can_gc); |
| [DomRoot::from_ref(&**i)] |
| } else { |
| return; |
| }; |
| |
| let event = XRInputSourcesChangeEvent::new( |
| window, |
| atom!("inputsourceschange"), |
| false, |
| true, |
| session, |
| &[], |
| &removed, |
| can_gc, |
| ); |
| self.input_sources.borrow_mut().retain(|i| i.id() != id); |
| event.upcast::<Event>().fire(session.upcast(), can_gc); |
| } |
| |
| pub(crate) fn add_remove_input_source( |
| &self, |
| session: &XRSession, |
| id: InputId, |
| info: InputSource, |
| can_gc: CanGc, |
| ) { |
| let global = self.global(); |
| let window = global.as_window(); |
| let root; |
| let removed = if let Some(i) = self.input_sources.borrow().iter().find(|i| i.id() == id) { |
| i.gamepad().update_connected(false, false, can_gc); |
| root = [DomRoot::from_ref(&**i)]; |
| &root as &[_] |
| } else { |
| warn!("Could not find removed input source with id {:?}", id); |
| &[] |
| }; |
| self.input_sources.borrow_mut().retain(|i| i.id() != id); |
| let input = XRInputSource::new(window, session, info, can_gc); |
| self.input_sources.borrow_mut().push(Dom::from_ref(&input)); |
| |
| let added = [input]; |
| |
| let event = XRInputSourcesChangeEvent::new( |
| window, |
| atom!("inputsourceschange"), |
| false, |
| true, |
| session, |
| &added, |
| removed, |
| can_gc, |
| ); |
| event.upcast::<Event>().fire(session.upcast(), can_gc); |
| } |
| |
| pub(crate) fn find(&self, id: InputId) -> Option<DomRoot<XRInputSource>> { |
| self.input_sources |
| .borrow() |
| .iter() |
| .find(|x| x.id() == id) |
| .map(|x| DomRoot::from_ref(&**x)) |
| } |
| } |
| |
| impl XRInputSourceArrayMethods<crate::DomTypeHolder> for XRInputSourceArray { |
| /// <https://immersive-web.github.io/webxr/#dom-xrinputsourcearray-length> |
| fn Length(&self) -> u32 { |
| self.input_sources.borrow().len() as u32 |
| } |
| |
| /// <https://immersive-web.github.io/webxr/#xrinputsourcearray> |
| fn IndexedGetter(&self, n: u32) -> Option<DomRoot<XRInputSource>> { |
| self.input_sources |
| .borrow() |
| .get(n as usize) |
| .map(|x| DomRoot::from_ref(&**x)) |
| } |
| } |