ffi 2D: migrate android.sx safe-insets to declarative #jni_class blocks
`sx_query_safe_insets_jni`'s body — previously seven hand-rolled
`#jni_call` sites with verbose JNI descriptor literals — now uses
four `#jni_class` declarations and the DSL method-call form inside
a `#jni_env(env) { ... }` scope. The new shape:
```
WindowInsets :: #jni_class("android/view/WindowInsets") {
getSystemWindowInsetTop :: (self: *Self) -> s32;
...
}
... Activity / Window / View ...
#jni_env(env) {
window := activity.getWindow();
decor := window.getDecorView();
insets := decor.getRootWindowInsets();
top.* = insets.getSystemWindowInsetTop();
...
}
```
Descriptor derivation happens at lower time (jni_descriptor.zig);
slot interning + vtable dispatch shape match the Phase 1C hand-rolled
form byte-for-byte. The function param signature changes from
`activity: *void` to `activity: *Activity` so the DSL can resolve
method names through `foreign_class_map`; the AndroidPlatform.safe_insets
caller adds an `xx` cast at the call site.
Net body shrinks from 14 dispatch lines to 12 (slightly shorter but
the win is type safety + readability — the foreign descriptor
strings are gone). On-device chess regression is the remaining
verification step (Pixel device with safe-area-driven board layout).
Verified locally: zig build, run_examples (129/129), cross_compile
(3/3 — incl. examples/99-android-egl-clear.sx cross-compile to
android target succeeds and produces a valid .o).
Naming caveat: `Activity` / `Window` / `View` / `WindowInsets` are
now top-level names exported by `modules/platform/android.sx`. User
code that imports this module shouldn't redefine these aliases.
This commit is contained in:
@@ -134,31 +134,56 @@ sx_android_activity_clazz :: (activity: *void) -> *void {
|
||||
sx_load_ptr_at(activity, ANATIVEACTIVITY_CLAZZ_OFFSET);
|
||||
}
|
||||
|
||||
// sx-side reimplementation of the JNI dispatch chain inside
|
||||
// `sx_android_query_safe_insets`. Caller provides an already-attached
|
||||
// `JNIEnv*` and the activity's `clazz` jobject. Outputs physical-pixel
|
||||
// insets just like the C foreign helper above. Eventually replaces
|
||||
// the foreign call once the JavaVM env-attach plumbing has a sx
|
||||
// equivalent or a thinner C shim.
|
||||
sx_query_safe_insets_jni :: (env: *void, activity: *void, top: *s32, left: *s32, bottom: *s32, right: *s32) -> void {
|
||||
// Declarative JNI class bindings for the safe-insets dispatch chain
|
||||
// (Phase 2D migration). Each `#jni_class` declares the sx-side alias,
|
||||
// the JNI class path, and the methods we use — `inst.method(args)`
|
||||
// inside a `#jni_env(env) { ... }` scope lowers to the same JNI vtable
|
||||
// indirection as the hand-rolled `#jni_call` form, with the descriptor
|
||||
// auto-derived from the sx signature (see [src/ir/jni_descriptor.zig]).
|
||||
WindowInsets :: #jni_class("android/view/WindowInsets") {
|
||||
getSystemWindowInsetTop :: (self: *Self) -> s32;
|
||||
getSystemWindowInsetLeft :: (self: *Self) -> s32;
|
||||
getSystemWindowInsetBottom :: (self: *Self) -> s32;
|
||||
getSystemWindowInsetRight :: (self: *Self) -> s32;
|
||||
}
|
||||
|
||||
View :: #jni_class("android/view/View") {
|
||||
getRootWindowInsets :: (self: *Self) -> *WindowInsets;
|
||||
}
|
||||
|
||||
Window :: #jni_class("android/view/Window") {
|
||||
getDecorView :: (self: *Self) -> *View;
|
||||
}
|
||||
|
||||
Activity :: #jni_class("android/app/Activity") {
|
||||
getWindow :: (self: *Self) -> *Window;
|
||||
}
|
||||
|
||||
// sx-side reimplementation of the JNI dispatch chain. Caller provides
|
||||
// an already-attached `JNIEnv*` and the activity's `clazz` jobject
|
||||
// (cast to `*Activity` so the method-call DSL can find it in the
|
||||
// foreign-class registry). Outputs physical-pixel insets.
|
||||
sx_query_safe_insets_jni :: (env: *void, activity: *Activity, top: *s32, left: *s32, bottom: *s32, right: *s32) -> void {
|
||||
inline if OS != .android { return; }
|
||||
|
||||
top.* = 0; left.* = 0; bottom.* = 0; right.* = 0;
|
||||
if activity == null { return; }
|
||||
|
||||
window := #jni_call(*void)(env, activity, "getWindow", "()Landroid/view/Window;");
|
||||
if window == null { return; }
|
||||
#jni_env(env) {
|
||||
window := activity.getWindow();
|
||||
if window == null { return; }
|
||||
|
||||
decor := #jni_call(*void)(env, window, "getDecorView", "()Landroid/view/View;");
|
||||
if decor == null { return; }
|
||||
decor := window.getDecorView();
|
||||
if decor == null { return; }
|
||||
|
||||
insets := #jni_call(*void)(env, decor, "getRootWindowInsets", "()Landroid/view/WindowInsets;");
|
||||
if insets == null { return; }
|
||||
insets := decor.getRootWindowInsets();
|
||||
if insets == null { return; }
|
||||
|
||||
top.* = #jni_call(s32)(env, insets, "getSystemWindowInsetTop", "()I");
|
||||
left.* = #jni_call(s32)(env, insets, "getSystemWindowInsetLeft", "()I");
|
||||
bottom.* = #jni_call(s32)(env, insets, "getSystemWindowInsetBottom", "()I");
|
||||
right.* = #jni_call(s32)(env, insets, "getSystemWindowInsetRight", "()I");
|
||||
top.* = insets.getSystemWindowInsetTop();
|
||||
left.* = insets.getSystemWindowInsetLeft();
|
||||
bottom.* = insets.getSystemWindowInsetBottom();
|
||||
right.* = insets.getSystemWindowInsetRight();
|
||||
}
|
||||
}
|
||||
|
||||
// EGL — display/surface/context/config are opaque to us.
|
||||
@@ -396,7 +421,7 @@ impl Platform for AndroidPlatform {
|
||||
attached : bool = false;
|
||||
env := sx_android_get_env(g_android_activity, @attached);
|
||||
if env != null {
|
||||
clazz := sx_android_activity_clazz(g_android_activity);
|
||||
clazz : *Activity = xx sx_android_activity_clazz(g_android_activity);
|
||||
sx_query_safe_insets_jni(env, clazz, @t, @l, @b, @r);
|
||||
if attached { sx_android_detach_env(g_android_activity); }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user