1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#[cfg(target_os = "ios")]
pub use ios::get_safe_area_insets;
#[cfg(target_os = "ios")]
mod ios {
use egui::{SafeAreaInsets, epaint::MarginF32};
use objc2::{ClassType, rc::Retained};
use objc2_foundation::{MainThreadMarker, NSObjectProtocol};
use objc2_ui_kit::{UIApplication, UISceneActivationState, UIWindowScene};
/// Gets the ios safe area insets.
///
/// A safe area defines the area within a view that isn’t covered by a navigation bar, tab bar,
/// toolbar, or other views a window might provide. Safe areas are essential for avoiding a
/// device’s interactive and display features, like Dynamic Island on iPhone or the camera
/// housing on some Mac models.
///
/// Once winit v0.31 has been released this can be removed in favor of
/// `winit::Window::safe_area`.
pub fn get_safe_area_insets() -> SafeAreaInsets {
let Some(main_thread_marker) = MainThreadMarker::new() else {
log::error!("Getting safe area insets needs to be performed on the main thread");
return SafeAreaInsets::default();
};
let app = UIApplication::sharedApplication(main_thread_marker);
#[allow(unsafe_code)]
unsafe {
// Look for the first window scene that's in the foreground
for scene in app.connectedScenes() {
if scene.isKindOfClass(UIWindowScene::class())
&& matches!(
scene.activationState(),
UISceneActivationState::ForegroundActive
| UISceneActivationState::ForegroundInactive
)
{
// Safe to cast, the class kind was checked above
let window_scene = Retained::cast::<UIWindowScene>(scene.clone());
if let Some(window) = window_scene.keyWindow() {
let insets = window.safeAreaInsets();
return SafeAreaInsets(MarginF32 {
top: insets.top as f32,
left: insets.left as f32,
right: insets.right as f32,
bottom: insets.bottom as f32,
});
}
}
}
}
SafeAreaInsets::default()
}
}