Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions ios/mob_nif.m
Original file line number Diff line number Diff line change
Expand Up @@ -1827,10 +1827,19 @@ static ERL_NIF_TERM nif_device_keep_awake(ErlNifEnv *env, int argc, const ERL_NI
// ── NIF: safe_area/0 ─────────────────────────────────────────────────────────
// Returns {Top, Right, Bottom, Left} in logical points (not pixels).
// Must read UIWindow.safeAreaInsets on the main thread.

//
// Called from Mob.Screen.init/1 — i.e. on the boot path, before the first
// screen ever mounts. A plain dispatch_sync here is a deadlock risk: if the
// main thread hasn't reached an idle run-loop tick yet (observed during
// scene-attachment on iPad, including the compatibility-mode window an
// iPhone-only app runs in there), this blocks the BEAM boot thread forever —
// the app never finishes launching. Bound the wait and fall back to zero
// insets on timeout: a screen with wrong insets once is a far smaller bug
// than an app that never boots.
static ERL_NIF_TERM nif_safe_area(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
__block UIEdgeInsets insets = UIEdgeInsetsZero;
dispatch_sync(dispatch_get_main_queue(), ^{
dispatch_semaphore_t done = dispatch_semaphore_create(0);
dispatch_async(dispatch_get_main_queue(), ^{
UIWindow *window = nil;
for (UIScene *scene in [UIApplication sharedApplication].connectedScenes) {
if ([scene isKindOfClass:[UIWindowScene class]]) {
Expand All @@ -1841,7 +1850,10 @@ static ERL_NIF_TERM nif_safe_area(ErlNifEnv *env, int argc, const ERL_NIF_TERM a
}
if (window)
insets = window.safeAreaInsets;
dispatch_semaphore_signal(done);
});
dispatch_time_t deadline = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC));
dispatch_semaphore_wait(done, deadline);
return enif_make_tuple4(
env, enif_make_double(env, insets.top), enif_make_double(env, insets.right),
enif_make_double(env, insets.bottom), enif_make_double(env, insets.left));
Expand Down Expand Up @@ -6327,7 +6339,7 @@ static ERL_NIF_TERM nif_vendor_usb_close(ErlNifEnv *env, int argc, const ERL_NIF
{"register_tap", 1, nif_register_tap, 0},
{"clear_taps", 0, nif_clear_taps, 0},
{"exit_app", 0, nif_exit_app, 0},
{"safe_area", 0, nif_safe_area, 0},
{"safe_area", 0, nif_safe_area, ERL_NIF_DIRTY_JOB_IO_BOUND},
{"haptic", 1, nif_haptic, 0},
{"torch", 1, nif_torch, 0},
{"clipboard_put", 1, nif_clipboard_put, 0},
Expand Down
Loading