1#![allow(clippy::missing_safety_doc)]
2
3use std::rc::Rc;
4
5use napi_ohos::{Error, Result};
6use ohos_arkui_input_binding::ArkUIInputEvent;
7use ohos_xcomponent_sys::{
8 OH_NativeXComponent, OH_NativeXComponent_Callback, OH_NativeXComponent_ExpectedRateRange,
9 OH_NativeXComponent_MouseEvent_Callback, OH_NativeXComponent_RegisterCallback,
10 OH_NativeXComponent_RegisterKeyEventCallback, OH_NativeXComponent_RegisterMouseEventCallback,
11 OH_NativeXComponent_RegisterOnFrameCallback, OH_NativeXComponent_RegisterUIInputEventCallback,
12 OH_NativeXComponent_SetExpectedFrameRateRange,
13};
14
15use crate::{
16 code::XComponentResultCode, dispatch_touch_event, key_event, on_frame_change, on_hover_event,
17 on_mouse_event, on_surface_changed, on_surface_created, on_surface_destroyed,
18 on_ui_input_event, raw::XComponentRaw, tool::resolve_id, KeyEventData, MouseEventData,
19 RawWindow, TouchEventData, WindowRaw, XComponentOffset, XComponentSize, RAW_WINDOW,
20};
21
22#[cfg(not(feature = "multi_mode"))]
23use crate::X_COMPONENT_CALLBACKS;
24
25#[cfg(feature = "multi_mode")]
26use crate::X_COMPONENT_CALLBACKS_MAP;
27
28#[derive(Debug, Clone)]
29pub struct NativeXComponent {
30 pub raw: XComponentRaw,
31 pub(crate) id: Option<String>,
32}
33
34impl NativeXComponent {
35 pub fn new(raw: XComponentRaw) -> Self {
36 Self { raw, id: None }
37 }
38
39 pub fn with_id(raw: XComponentRaw, id: String) -> Self {
40 Self { raw, id: Some(id) }
41 }
42
43 pub fn id(&self) -> Result<String> {
45 if let Some(id) = &self.id {
46 return Ok(id.clone());
47 }
48 let current_id = resolve_id(self.raw());
49 if let Some(id_str) = current_id {
50 return Ok(id_str);
51 }
52 Err(Error::from_reason("Get XComponent id failed."))
53 }
54
55 pub fn raw(&self) -> *mut OH_NativeXComponent {
57 self.raw.0
58 }
59
60 pub fn native_window(&self) -> Option<RawWindow> {
61 let guard = (*RAW_WINDOW).read();
62 if let Ok(guard) = guard {
63 if let Some(win) = &*guard {
64 return Some(RawWindow::new(win.raw()));
65 }
66 return None;
67 }
68 None
69 }
70
71 #[cfg(feature = "callbacks")]
76 pub fn register_callback(&self) -> Result<()> {
77 let cbs = Box::new(OH_NativeXComponent_Callback {
78 OnSurfaceCreated: Some(on_surface_created),
79 OnSurfaceChanged: Some(on_surface_changed),
80 OnSurfaceDestroyed: Some(on_surface_destroyed),
81 DispatchTouchEvent: Some(dispatch_touch_event),
82 });
83 let ret: XComponentResultCode = unsafe {
84 OH_NativeXComponent_RegisterCallback(self.raw(), Box::leak(cbs) as *mut _).into()
85 };
86 if ret != XComponentResultCode::Success {
87 return Err(Error::from_reason("XComponent register callbacks failed"));
88 }
89 Ok(())
90 }
91
92 pub fn on_surface_changed<T: Fn(XComponentRaw, WindowRaw) -> Result<()> + 'static>(
93 &self,
94 cb: T,
95 ) {
96 #[cfg(not(feature = "multi_mode"))]
97 X_COMPONENT_CALLBACKS.with_borrow_mut(|f| {
98 f.on_surface_changed = Some(Rc::new(cb));
99 });
100
101 #[cfg(feature = "multi_mode")]
102 {
103 let id = self.id().unwrap();
104 X_COMPONENT_CALLBACKS_MAP.with_borrow_mut(|f| {
105 f.entry(id).or_default().on_surface_changed = Some(Rc::new(cb));
106 });
107 }
108 }
109
110 pub fn on_surface_created<T: Fn(XComponentRaw, WindowRaw) -> Result<()> + 'static>(
111 &self,
112 cb: T,
113 ) {
114 #[cfg(not(feature = "multi_mode"))]
115 X_COMPONENT_CALLBACKS.with_borrow_mut(|f| {
116 f.on_surface_created = Some(Rc::new(cb));
117 });
118
119 #[cfg(feature = "multi_mode")]
120 {
121 let id = self.id().unwrap();
122 X_COMPONENT_CALLBACKS_MAP.with_borrow_mut(|f| {
123 f.entry(id).or_default().on_surface_created = Some(Rc::new(cb));
124 });
125 }
126 }
127
128 pub fn on_surface_destroyed<T: Fn(XComponentRaw, WindowRaw) -> Result<()> + 'static>(
129 &self,
130 cb: T,
131 ) {
132 #[cfg(not(feature = "multi_mode"))]
133 X_COMPONENT_CALLBACKS.with_borrow_mut(|f| {
134 f.on_surface_destroyed = Some(Rc::new(cb));
135 });
136
137 #[cfg(feature = "multi_mode")]
138 {
139 let id = self.id().unwrap();
140 X_COMPONENT_CALLBACKS_MAP.with_borrow_mut(|f| {
141 f.entry(id).or_default().on_surface_destroyed = Some(Rc::new(cb));
142 });
143 }
144 }
145
146 pub fn on_touch_event<
147 T: Fn(XComponentRaw, WindowRaw, TouchEventData) -> Result<()> + 'static,
148 >(
149 &self,
150 cb: T,
151 ) {
152 #[cfg(not(feature = "multi_mode"))]
153 X_COMPONENT_CALLBACKS.with_borrow_mut(|f| {
154 f.dispatch_touch_event = Some(Rc::new(cb));
155 });
156
157 #[cfg(feature = "multi_mode")]
158 {
159 let id = self.id().unwrap();
160 X_COMPONENT_CALLBACKS_MAP.with_borrow_mut(|f| {
161 f.entry(id).or_default().dispatch_touch_event = Some(Rc::new(cb));
162 });
163 }
164 }
165
166 pub unsafe fn register_native_callback(
168 &self,
169 callbacks: Box<OH_NativeXComponent_Callback>,
170 ) -> Result<()> {
171 let ret: XComponentResultCode = unsafe {
172 OH_NativeXComponent_RegisterCallback(self.raw(), Box::leak(callbacks) as *mut _).into()
173 };
174 if ret != XComponentResultCode::Success {
175 return Err(Error::from_reason("XComponent register callbacks failed"));
176 }
177 Ok(())
178 }
179
180 pub fn size(&self, window: WindowRaw) -> Result<XComponentSize> {
182 self.raw.size(window)
183 }
184
185 pub fn offset(&self, window: WindowRaw) -> Result<XComponentOffset> {
186 self.raw.offset(window)
187 }
188
189 pub fn set_frame_rate(&self, min: i32, max: i32, expected: i32) -> Result<()> {
190 let mut range = OH_NativeXComponent_ExpectedRateRange { min, max, expected };
191 let ret: XComponentResultCode = unsafe {
192 OH_NativeXComponent_SetExpectedFrameRateRange(self.raw(), &mut range as *mut _).into()
193 };
194 if ret != XComponentResultCode::Success {
195 return Err(Error::from_reason("XComponent set frame rate failed"));
196 }
197 Ok(())
198 }
199
200 pub fn on_frame_callback<T: Fn(XComponentRaw, u64, u64) -> Result<()> + 'static>(
202 &self,
203 cb: T,
204 ) -> Result<()> {
205 #[cfg(not(feature = "multi_mode"))]
206 X_COMPONENT_CALLBACKS.with_borrow_mut(|f| {
207 f.on_frame_change = Some(Rc::new(cb));
208 });
209
210 #[cfg(feature = "multi_mode")]
211 {
212 let id = self.id().unwrap();
213 X_COMPONENT_CALLBACKS_MAP.with_borrow_mut(|f| {
214 f.entry(id).or_default().on_frame_change = Some(Rc::new(cb));
215 });
216 }
217
218 let ret: XComponentResultCode = unsafe {
219 OH_NativeXComponent_RegisterOnFrameCallback(self.raw(), Some(on_frame_change)).into()
220 };
221 if ret != XComponentResultCode::Success {
222 return Err(Error::from_reason(
223 "XComponent register frame callback failed",
224 ));
225 }
226 Ok(())
227 }
228
229 pub fn on_key_event<T: Fn(XComponentRaw, WindowRaw, KeyEventData) -> Result<()> + 'static>(
230 &self,
231 cb: T,
232 ) -> Result<()> {
233 #[cfg(not(feature = "multi_mode"))]
234 X_COMPONENT_CALLBACKS.with_borrow_mut(|f| {
235 f.on_key_event = Some(Rc::new(cb));
236 });
237
238 #[cfg(feature = "multi_mode")]
239 {
240 let id = self.id().unwrap();
241 X_COMPONENT_CALLBACKS_MAP.with_borrow_mut(|f| {
242 f.entry(id).or_default().on_key_event = Some(Rc::new(cb));
243 });
244 }
245
246 let ret: XComponentResultCode = unsafe {
247 OH_NativeXComponent_RegisterKeyEventCallback(self.raw(), Some(key_event)).into()
248 };
249 if ret != XComponentResultCode::Success {
250 return Err(Error::from_reason(
251 "XComponent register key event callback failed",
252 ));
253 }
254 Ok(())
255 }
256
257 pub fn on_hover_event<T: Fn(XComponentRaw, bool) -> Result<()> + 'static>(
258 &self,
259 cb: T,
260 ) -> Result<()> {
261 #[cfg(not(feature = "multi_mode"))]
262 X_COMPONENT_CALLBACKS.with_borrow_mut(|f| {
263 f.on_hover_event = Some(Rc::new(cb));
264 });
265
266 #[cfg(feature = "multi_mode")]
267 {
268 let id = self.id().unwrap();
269 X_COMPONENT_CALLBACKS_MAP.with_borrow_mut(|f| {
270 f.entry(id).or_default().on_hover_event = Some(Rc::new(cb));
271 });
272 }
273 Ok(())
274 }
275
276 pub fn on_mouse_event<
277 T: Fn(XComponentRaw, WindowRaw, MouseEventData) -> Result<()> + 'static,
278 >(
279 &self,
280 cb: T,
281 ) -> Result<()> {
282 #[cfg(not(feature = "multi_mode"))]
283 X_COMPONENT_CALLBACKS.with_borrow_mut(|f| {
284 f.on_mouse_event = Some(Rc::new(cb));
285 });
286
287 #[cfg(feature = "multi_mode")]
288 {
289 let id = self.id().unwrap();
290 X_COMPONENT_CALLBACKS_MAP.with_borrow_mut(|f| {
291 f.entry(id).or_default().on_mouse_event = Some(Rc::new(cb));
292 });
293 }
294 Ok(())
295 }
296
297 pub fn register_mouse_event_callback(&self) -> Result<()> {
298 let callback = Box::new(OH_NativeXComponent_MouseEvent_Callback {
299 DispatchMouseEvent: Some(on_mouse_event),
300 DispatchHoverEvent: Some(on_hover_event),
301 });
302 let ret: XComponentResultCode = unsafe {
303 OH_NativeXComponent_RegisterMouseEventCallback(
304 self.raw(),
305 Box::leak(callback) as *mut _,
306 )
307 .into()
308 };
309 if ret != XComponentResultCode::Success {
310 return Err(Error::from_reason(
311 "XComponent register mouse event callback failed",
312 ));
313 }
314 Ok(())
315 }
316
317 pub fn on_ui_input_event<T: Fn(XComponentRaw, ArkUIInputEvent) -> Result<()> + 'static>(
318 &self,
319 cb: T,
320 ) -> Result<()> {
321 #[cfg(not(feature = "multi_mode"))]
322 X_COMPONENT_CALLBACKS.with_borrow_mut(|f| {
323 f.on_ui_input_event = Some(Rc::new(cb));
324 });
325
326 #[cfg(feature = "multi_mode")]
327 {
328 let id = self.id().unwrap();
329 X_COMPONENT_CALLBACKS_MAP.with_borrow_mut(|f| {
330 f.entry(id).or_default().on_ui_input_event = Some(Rc::new(cb));
331 });
332 }
333 let ret: XComponentResultCode = unsafe {
334 OH_NativeXComponent_RegisterUIInputEventCallback(
335 self.raw(),
336 Some(on_ui_input_event),
337 ohos_arkui_input_binding::UIInputEvent::Axis.into(),
338 )
339 .into()
340 };
341 if ret != XComponentResultCode::Success {
342 return Err(Error::from_reason(
343 "XComponent register ui input event callback failed",
344 ));
345 }
346 Ok(())
347 }
348}