ohos-xcomponent-binding 0.2.0

OpenHarmony's xcomponent binding for rust
#![allow(clippy::missing_safety_doc)]

use std::mem::MaybeUninit;

use ohos_xcomponent_sys::{
    OH_NativeXComponent, OH_NativeXComponent_GetKeyEvent, OH_NativeXComponent_GetKeyEventAction,
    OH_NativeXComponent_GetKeyEventCode, OH_NativeXComponent_GetKeyEventDeviceId,
    OH_NativeXComponent_GetKeyEventSourceType, OH_NativeXComponent_GetKeyEventTimestamp,
    OH_NativeXComponent_GetTouchEvent, OH_NativeXComponent_GetTouchPointToolType,
    OH_NativeXComponent_TouchEvent,
};

use crate::{Action, EventSource, KeyCode, KeyEventData, WindowRaw, XComponentRaw};

use super::{RawWindow, TouchEventData, RAW_WINDOW};

#[cfg(not(feature = "multi_mode"))]
use super::X_COMPONENT_CALLBACKS;

#[cfg(feature = "multi_mode")]
use super::X_COMPONENT_CALLBACKS_MAP;
#[cfg(feature = "multi_mode")]
use crate::tool::resolve_id;

pub unsafe extern "C" fn on_surface_created(
    xcomponent: *mut OH_NativeXComponent,
    window: *mut std::os::raw::c_void,
) {
    let window = WindowRaw(window);
    let xcomponent = XComponentRaw(xcomponent);

    {
        let mut guard = (*RAW_WINDOW).write().expect("read raw window failed");
        guard.replace(RawWindow::new(window.0));
    }

    #[cfg(not(feature = "multi_mode"))]
    {
        let callback = X_COMPONENT_CALLBACKS.with_borrow(|cb| cb.clone());

        if let Some(callback) = &callback.on_surface_created {
            callback(xcomponent, window).unwrap();
        }
    }

    #[cfg(feature = "multi_mode")]
    {
        let cb = X_COMPONENT_CALLBACKS_MAP.with_borrow(|cb| cb.clone());

        let id = resolve_id(xcomponent.0).unwrap();
        if let Some(callback) = cb.get(&id) {
            if let Some(callback) = &callback.on_surface_created {
                callback(xcomponent, window).unwrap();
            }
        }
    }
}

pub unsafe extern "C" fn on_surface_changed(
    xcomponent: *mut OH_NativeXComponent,
    window: *mut std::os::raw::c_void,
) {
    let window = WindowRaw(window);
    let xcomponent = XComponentRaw(xcomponent);

    {
        let mut guard = (*RAW_WINDOW).write().expect("read raw window failed");
        guard.replace(RawWindow::new(window.0));
    }

    #[cfg(not(feature = "multi_mode"))]
    {
        let callback = X_COMPONENT_CALLBACKS.with_borrow(|cb| cb.clone());
        if let Some(callback) = &callback.on_surface_changed {
            callback(xcomponent, window).unwrap();
        }
    }

    #[cfg(feature = "multi_mode")]
    {
        let cb = X_COMPONENT_CALLBACKS_MAP.with_borrow(|cb| cb.clone());

        let id = resolve_id(xcomponent.0).unwrap();
        if let Some(callback) = cb.get(&id) {
            if let Some(callback) = &callback.on_surface_changed {
                callback(xcomponent, window).unwrap();
            }
        }
    }
}

pub unsafe extern "C" fn on_surface_destroyed(
    xcomponent: *mut OH_NativeXComponent,
    window: *mut std::os::raw::c_void,
) {
    let window = WindowRaw(window);
    let xcomponent = XComponentRaw(xcomponent);

    {
        let mut guard = (*RAW_WINDOW).write().expect("read raw window failed");
        *guard = None;
    }

    #[cfg(not(feature = "multi_mode"))]
    {
        let cb = X_COMPONENT_CALLBACKS.with_borrow(|cb| cb.clone());
        if let Some(callback) = &cb.on_surface_destroyed {
            callback(xcomponent, window).unwrap();
        }
    }

    #[cfg(feature = "multi_mode")]
    {
        let cb = X_COMPONENT_CALLBACKS_MAP.with_borrow(|cb| cb.clone());

        let id = resolve_id(xcomponent.0).unwrap();
        if let Some(callback) = cb.get(&id) {
            if let Some(callback) = &callback.on_surface_destroyed {
                callback(xcomponent, window).unwrap();
            }
        }
    }
}

pub unsafe extern "C" fn dispatch_touch_event(
    xcomponent: *mut OH_NativeXComponent,
    window: *mut std::os::raw::c_void,
) {
    let mut touch_event = MaybeUninit::<OH_NativeXComponent_TouchEvent>::uninit();
    let ret = OH_NativeXComponent_GetTouchEvent(xcomponent, window, touch_event.as_mut_ptr());
    assert!(ret == 0, "Get touch event failed");

    let touch_event_data = touch_event.assume_init();
    let mut data = TouchEventData::from(touch_event_data);

    data.touch_points.iter_mut().for_each(|point| {
        let mut tool = 0;
        let ret = OH_NativeXComponent_GetTouchPointToolType(xcomponent, point.id as _, &mut tool);
        assert!(ret == 0, "Get touch point tool type failed");
        point.event_tool_type = tool.into();
    });

    let window = WindowRaw(window);
    let xcomponent = XComponentRaw(xcomponent);

    #[cfg(not(feature = "multi_mode"))]
    {
        let cb = X_COMPONENT_CALLBACKS.with_borrow(|cb| cb.clone());
        if let Some(callback) = &cb.dispatch_touch_event {
            callback(xcomponent, window, data).unwrap();
        }
    }

    #[cfg(feature = "multi_mode")]
    {
        let cb = X_COMPONENT_CALLBACKS_MAP.with_borrow(|cb| cb.clone());

        let id = resolve_id(xcomponent.0).unwrap();
        if let Some(callback) = cb.get(&id) {
            if let Some(callback) = &callback.dispatch_touch_event {
                callback(xcomponent, window, data).unwrap();
            }
        }
    }
}

pub unsafe extern "C" fn on_frame_change(
    xcomponent: *mut OH_NativeXComponent,
    timestamp: u64,
    target_timestamp: u64,
) {
    let xcomponent = XComponentRaw(xcomponent);

    #[cfg(not(feature = "multi_mode"))]
    {
        let cb = X_COMPONENT_CALLBACKS.with_borrow(|cb| cb.clone());
        if let Some(callback) = &cb.on_frame_change {
            callback(xcomponent, timestamp, target_timestamp).unwrap();
        }
    }

    #[cfg(feature = "multi_mode")]
    {
        let cb = X_COMPONENT_CALLBACKS_MAP.with_borrow(|cb| cb.clone());

        let id = resolve_id(xcomponent.0).unwrap();
        if let Some(callback) = cb.get(&id) {
            if let Some(callback) = &callback.on_frame_change {
                callback(xcomponent, timestamp, target_timestamp).unwrap();
            }
        }
    }
}

pub unsafe extern "C" fn key_event(
    xcomponent: *mut OH_NativeXComponent,
    window: *mut std::os::raw::c_void,
) {
    let mut event = std::ptr::null_mut();
    let ret = OH_NativeXComponent_GetKeyEvent(xcomponent, &mut event);
    assert!(ret == 0, "Get key event failed");

    let mut action = 0;
    let ret = OH_NativeXComponent_GetKeyEventAction(event, &mut action);
    assert!(ret == 0, "Get key event action failed");

    let mut code = 0;
    let ret = OH_NativeXComponent_GetKeyEventCode(event, &mut code);
    assert!(ret == 0, "Get key event code failed");

    let mut device_id = 0;
    let ret = OH_NativeXComponent_GetKeyEventDeviceId(event, &mut device_id);
    assert!(ret == 0, "Get key event device id failed");

    let mut source = 0;
    let ret = OH_NativeXComponent_GetKeyEventSourceType(event, &mut source);
    assert!(ret == 0, "Get key event source type failed");

    let mut timestamp = 0;
    let ret = OH_NativeXComponent_GetKeyEventTimestamp(event, &mut timestamp);
    assert!(ret == 0, "Get key event timestamp failed");

    let window = WindowRaw(window);
    let xcomponent = XComponentRaw(xcomponent);

    let key_event_data = KeyEventData {
        code: KeyCode::from(code),
        action: Action::from(action),
        device_id,
        source: EventSource::from(source),
        timestamp,
    };

    #[cfg(not(feature = "multi_mode"))]
    {
        let cb = X_COMPONENT_CALLBACKS.with_borrow(|cb| cb.clone());
        if let Some(callback) = &cb.on_key_event {
            callback(xcomponent, window, key_event_data).unwrap();
        }
    }

    #[cfg(feature = "multi_mode")]
    {
        let cb = X_COMPONENT_CALLBACKS_MAP.with_borrow(|cb| cb.clone());

        let id = resolve_id(xcomponent.0).unwrap();
        if let Some(callback) = cb.get(&id) {
            if let Some(callback) = &callback.on_key_event {
                callback(xcomponent, window, key_event_data).unwrap();
            }
        }
    }
}