use core::sync::atomic::{AtomicBool, AtomicI32, AtomicU32, Ordering};
use std::sync::OnceLock;
static WINDOW_ID: AtomicI32 = AtomicI32::new(-1);
static THEME: AtomicI32 = AtomicI32::new(-1);
static FONT_SCALE_BITS: AtomicU32 = AtomicU32::new(1.0_f32.to_bits());
static SAFE_AREA_SET: AtomicBool = AtomicBool::new(false);
static SAFE_TOP: AtomicU32 = AtomicU32::new(0);
static SAFE_BOTTOM: AtomicU32 = AtomicU32::new(0);
static SAFE_LEFT: AtomicU32 = AtomicU32::new(0);
static SAFE_RIGHT: AtomicU32 = AtomicU32::new(0);
static GENERATION: AtomicU32 = AtomicU32::new(0);
fn bump() {
GENERATION.fetch_add(1, Ordering::Relaxed);
}
#[allow(dead_code)]
pub(crate) fn window_id() -> Option<i32> {
let id = WINDOW_ID.load(Ordering::Relaxed);
(id >= 0).then_some(id)
}
pub(crate) fn theme() -> Option<bool> {
match THEME.load(Ordering::Relaxed) {
1 => Some(true),
0 => Some(false),
_ => None,
}
}
pub(crate) fn font_scale() -> f32 {
f32::from_bits(FONT_SCALE_BITS.load(Ordering::Relaxed))
}
pub(crate) fn safe_area() -> Option<crate::platform::types::SafeAreaInsets> {
if !SAFE_AREA_SET.load(Ordering::Relaxed) {
return None;
}
Some(crate::platform::types::SafeAreaInsets {
top: SAFE_TOP.load(Ordering::Relaxed),
bottom: SAFE_BOTTOM.load(Ordering::Relaxed),
left: SAFE_LEFT.load(Ordering::Relaxed),
right: SAFE_RIGHT.load(Ordering::Relaxed),
})
}
pub(crate) fn generation() -> u64 {
u64::from(GENERATION.load(Ordering::Relaxed))
}
#[no_mangle]
pub extern "C" fn rw_harmony_set_window_id(window_id: i32) -> i32 {
WINDOW_ID.store(window_id, Ordering::Relaxed);
bump();
1
}
#[no_mangle]
pub extern "C" fn rw_harmony_set_theme(dark: i32) -> i32 {
THEME.store(dark.clamp(-1, 1), Ordering::Relaxed);
bump();
1
}
#[no_mangle]
pub extern "C" fn rw_harmony_set_lifecycle(state: i32) -> i32 {
let phase = match state {
0 => crate::platform::MobileLifecycleState::Active,
1 => crate::platform::MobileLifecycleState::Inactive,
2 => crate::platform::MobileLifecycleState::Background,
_ => return 0,
};
bump();
i32::from(crate::platform::lifecycle::set_state(phase))
}
static IME_BRIDGE: OnceLock<crate::platform::ime_macos::MacOsImeBridge> = OnceLock::new();
pub(crate) fn ime_bridge() -> &'static crate::platform::ime_macos::MacOsImeBridge {
IME_BRIDGE.get_or_init(crate::platform::ime_macos::MacOsImeBridge::new)
}
#[no_mangle]
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub extern "C" fn rw_harmony_ime_marked_text(
text: *const core::ffi::c_char,
cursor_utf16: i32,
) -> i32 {
if text.is_null() {
return 0;
}
let value = unsafe { core::ffi::CStr::from_ptr(text) };
let Ok(value) = value.to_str() else {
return 0;
};
ime_bridge().set_marked_text(value, cursor_utf16, cursor_utf16);
1
}
#[no_mangle]
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub extern "C" fn rw_harmony_ime_commit(text: *const core::ffi::c_char) -> i32 {
if text.is_null() {
return 0;
}
let value = unsafe { core::ffi::CStr::from_ptr(text) };
let Ok(value) = value.to_str() else {
return 0;
};
ime_bridge().commit_text(value);
1
}
#[no_mangle]
pub extern "C" fn rw_harmony_set_orientation(rotation: i32) -> i32 {
let accepted = crate::platform::lifecycle::set_rotation(rotation);
if accepted {
bump();
}
i32::from(accepted)
}
#[no_mangle]
pub extern "C" fn rw_harmony_set_font_scale(scale: f32) -> i32 {
if !scale.is_finite() || scale <= 0.0 {
return 0;
}
FONT_SCALE_BITS.store(scale.to_bits(), Ordering::Relaxed);
bump();
1
}
#[no_mangle]
pub extern "C" fn rw_harmony_set_safe_area(top: i32, bottom: i32, left: i32, right: i32) -> i32 {
SAFE_TOP.store(top.max(0) as u32, Ordering::Relaxed);
SAFE_BOTTOM.store(bottom.max(0) as u32, Ordering::Relaxed);
SAFE_LEFT.store(left.max(0) as u32, Ordering::Relaxed);
SAFE_RIGHT.store(right.max(0) as u32, Ordering::Relaxed);
SAFE_AREA_SET.store(true, Ordering::Relaxed);
bump();
1
}