use bevy_app::prelude::*;
use bevy_ecs::{prelude::*, system::SystemParam};
#[derive(Resource, Clone, Debug, Default)]
pub struct IosSafeAreaResource {
pub top: f32,
pub bottom: f32,
pub left: f32,
pub right: f32,
}
#[derive(SystemParam)]
pub struct IosSafeArea<'w> {
resource: Option<Res<'w, IosSafeAreaResource>>,
}
impl IosSafeArea<'_> {
pub fn top(&self) -> f32 {
self.resource.as_ref().map(|r| r.top).unwrap_or(0.)
}
pub fn bottom(&self) -> f32 {
self.resource.as_ref().map(|r| r.bottom).unwrap_or(0.)
}
pub fn left(&self) -> f32 {
self.resource.as_ref().map(|r| r.left).unwrap_or(0.)
}
pub fn right(&self) -> f32 {
self.resource.as_ref().map(|r| r.right).unwrap_or(0.)
}
}
#[derive(Default)]
pub struct IosSafeAreaPlugin;
impl Plugin for IosSafeAreaPlugin {
#[cfg_attr(not(target_os = "ios"), allow(unused_variables))]
fn build(&self, app: &mut App) {
#[cfg(target_os = "ios")]
app.add_systems(Update, init);
}
}
#[cfg(target_os = "ios")]
fn init(
_non_send_marker: bevy_ecs::system::NonSendMarker,
mut window_created: MessageReader<bevy_window::WindowCreated>,
window: Single<Entity, With<bevy_window::PrimaryWindow>>,
mut commands: Commands,
) {
use bevy_log::tracing;
use winit::raw_window_handle::HasWindowHandle;
if !window_created
.read()
.any(|created| created.window == *window)
{
return;
}
tracing::debug!("safe area updating");
let insets = bevy_winit::WINIT_WINDOWS.with_borrow(|windows| {
let Some(raw_window) = windows.get_window(*window) else {
return None;
};
let Ok(handle) = raw_window.window_handle() else {
return None;
};
if let winit::raw_window_handle::RawWindowHandle::UiKit(handle) = handle.as_raw() {
let ui_view: *mut std::ffi::c_void = handle.ui_view.as_ptr();
let (top, bottom, left, right) = unsafe {
(
crate::native::swift_safearea_top(ui_view),
crate::native::swift_safearea_bottom(ui_view),
crate::native::swift_safearea_left(ui_view),
crate::native::swift_safearea_right(ui_view),
)
};
Some(IosSafeAreaResource {
top,
bottom,
left,
right,
})
} else {
None
}
});
if let Some(safe_area) = insets {
tracing::debug!("safe area updated: {:?}", safe_area);
commands.insert_resource(safe_area);
}
}