script/dom/webxr/
xrinputsourcearray.rs1use dom_struct::dom_struct;
6use js::context::JSContext;
7use script_bindings::cell::DomRefCell;
8use script_bindings::reflector::{Reflector, reflect_dom_object};
9use webxr_api::{InputId, InputSource};
10
11use crate::dom::bindings::codegen::Bindings::XRInputSourceArrayBinding::XRInputSourceArrayMethods;
12use crate::dom::bindings::inheritance::Castable;
13use crate::dom::bindings::reflector::DomGlobal;
14use crate::dom::bindings::root::{Dom, DomRoot};
15use crate::dom::event::Event;
16use crate::dom::window::Window;
17use crate::dom::xrinputsource::XRInputSource;
18use crate::dom::xrinputsourceschangeevent::XRInputSourcesChangeEvent;
19use crate::dom::xrsession::XRSession;
20use crate::script_runtime::CanGc;
21
22#[dom_struct]
23pub(crate) struct XRInputSourceArray {
24 reflector_: Reflector,
25 input_sources: DomRefCell<Vec<Dom<XRInputSource>>>,
26}
27
28impl XRInputSourceArray {
29 fn new_inherited() -> XRInputSourceArray {
30 XRInputSourceArray {
31 reflector_: Reflector::new(),
32 input_sources: DomRefCell::new(vec![]),
33 }
34 }
35
36 pub(crate) fn new(window: &Window, can_gc: CanGc) -> DomRoot<XRInputSourceArray> {
37 reflect_dom_object(
38 Box::new(XRInputSourceArray::new_inherited()),
39 window,
40 can_gc,
41 )
42 }
43
44 pub(crate) fn add_input_sources(
45 &self,
46 cx: &mut JSContext,
47 session: &XRSession,
48 inputs: &[InputSource],
49 ) {
50 let global = self.global();
51 let window = global.as_window();
52
53 let mut added = vec![];
54 for info in inputs {
55 debug_assert!(
58 !self
59 .input_sources
60 .borrow()
61 .iter()
62 .any(|i| i.id() == info.id),
63 "Should never add a duplicate input id!"
64 );
65 let input = XRInputSource::new(cx, window, session, info.clone());
66 self.input_sources.borrow_mut().push(Dom::from_ref(&input));
67 added.push(input);
68 }
69
70 let event = XRInputSourcesChangeEvent::new(
71 window,
72 atom!("inputsourceschange"),
73 false,
74 true,
75 session,
76 &added,
77 &[],
78 CanGc::from_cx(cx),
79 );
80 event.upcast::<Event>().fire(cx, session.upcast());
81 }
82
83 pub(crate) fn remove_input_source(&self, cx: &mut JSContext, session: &XRSession, id: InputId) {
84 let global = self.global();
85 let window = global.as_window();
86 let removed = if let Some(i) = self.input_sources.borrow().iter().find(|i| i.id() == id) {
87 i.gamepad().update_connected(false);
88 [DomRoot::from_ref(&**i)]
89 } else {
90 return;
91 };
92
93 let event = XRInputSourcesChangeEvent::new(
94 window,
95 atom!("inputsourceschange"),
96 false,
97 true,
98 session,
99 &[],
100 &removed,
101 CanGc::from_cx(cx),
102 );
103 self.input_sources.borrow_mut().retain(|i| i.id() != id);
104 event.upcast::<Event>().fire(cx, session.upcast());
105 }
106
107 pub(crate) fn add_remove_input_source(
108 &self,
109 cx: &mut JSContext,
110 session: &XRSession,
111 id: InputId,
112 info: InputSource,
113 ) {
114 let global = self.global();
115 let window = global.as_window();
116 let root;
117 let removed = if let Some(i) = self.input_sources.borrow().iter().find(|i| i.id() == id) {
118 i.gamepad().update_connected(false);
119 root = [DomRoot::from_ref(&**i)];
120 &root as &[_]
121 } else {
122 warn!("Could not find removed input source with id {:?}", id);
123 &[]
124 };
125 self.input_sources.borrow_mut().retain(|i| i.id() != id);
126 let input = XRInputSource::new(cx, window, session, info);
127 self.input_sources.borrow_mut().push(Dom::from_ref(&input));
128
129 let added = [input];
130
131 let event = XRInputSourcesChangeEvent::new(
132 window,
133 atom!("inputsourceschange"),
134 false,
135 true,
136 session,
137 &added,
138 removed,
139 CanGc::from_cx(cx),
140 );
141 event.upcast::<Event>().fire(cx, session.upcast());
142 }
143
144 pub(crate) fn find(&self, id: InputId) -> Option<DomRoot<XRInputSource>> {
145 self.input_sources
146 .borrow()
147 .iter()
148 .find(|x| x.id() == id)
149 .map(|x| DomRoot::from_ref(&**x))
150 }
151}
152
153impl XRInputSourceArrayMethods<crate::DomTypeHolder> for XRInputSourceArray {
154 fn Length(&self) -> u32 {
156 self.input_sources.borrow().len() as u32
157 }
158
159 fn IndexedGetter(&self, n: u32) -> Option<DomRoot<XRInputSource>> {
161 self.input_sources
162 .borrow()
163 .get(n as usize)
164 .map(|x| DomRoot::from_ref(&**x))
165 }
166}