From 5776c4924d346ca9f721ce2efda7b48d734e5ac4 Mon Sep 17 00:00:00 2001 From: Hisham Aburaqibah Date: Mon, 7 Sep 2026 20:27:00 +0200 Subject: [PATCH] fix: don't start the app from main() on android; use the real inset retry main() must not run real_main on android. The library's DT_INIT points at Odin's _odin_entry_point, which the loader runs the moment NativeActivity dlopens libmain.so -- before the glue calls android_main, so context.user_ptr is nil and backend_init faults writing app.onAppCmd. The proc still has to exist: package main requires it and it is the desktop entry point. The insets retry now uses request_render_at. A plain request_render made before the build is consumed by the frame it is running in, so it schedules nothing and the loop parks with insets unresolved; it only appeared to work because the first frames redraw anyway while the tree settles. Guards the JNI-only paths (show_toast, refresh_insets) behind the android subtarget so the shared real_main is usable on desktop. refresh_insets returns true there rather than false: zero insets are correct where there are no system bars, and returning false would retry every frame forever. Also declares appCategory=game, and enables the engine's frame timings. Co-Authored-By: Claude Opus 5 --- android/AndroidManifest.xml | 3 +- main.odin | 61 +++++++++++++++++++++++++++++-------- 2 files changed, 50 insertions(+), 14 deletions(-) diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index 0c31aeb..4987ca7 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -13,10 +13,11 @@ + android:debuggable="true"> Window -> decor View -> WindowInsets. Returns false while // the decor view is still unattached, which is normal for the first few frames. refresh_insets :: proc() -> bool { + // Returning true, not false: zero insets are the correct answer where there + // are no system bars, and the caller retries every frame until this succeeds + // -- requesting a render each time. Failing here would pin the desktop loop + // awake forever, which is exactly what render_on_change is meant to avoid. + when ODIN_PLATFORM_SUBTARGET != .Android { + return true + } + // This runs every frame until it succeeds, and each call below returns a // local ref. Without a frame to scope them the ref table fills and aborts. env := jni.env()