Skip to content

Commit 3c095d5

Browse files
committed
fix(jni): resolve GraalVM method lookup via FindClass on interfaces instead of GetObjectClass
1 parent 5525156 commit 3c095d5

3 files changed

Lines changed: 42 additions & 8 deletions

File tree

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,18 @@ bin/
4040

4141
### Mac OS ###
4242
.DS_Store
43+
local.properties
4344

4445
### Runtime ###
4546
tray_position.properties
4647

4748
### Native libraries (built on CI via build-natives.yaml) ###
4849
**/src/jvmMain/resources/composetray/native/
4950

50-
### MSVC build artifacts ###
51+
### Native compilation artifacts ###
5152
*.obj
5253
*.exp
54+
*.o
5355

5456
### Native build directories ###
5557
src/native/windows/build-x64/

src/jvmMain/kotlin/com/kdroid/composetray/lib/mac/MacOSMenuBarThemeDetector.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ object MacOSMenuBarThemeDetector {
1212
Thread(r, "MacOS MenuBar Theme Detector Thread").apply { isDaemon = true }
1313
}
1414

15-
private val themeChangedCallback = object : MacNativeBridge.ThemeChangeCallback {
15+
private class ThemeCallback : MacNativeBridge.ThemeChangeCallback {
1616
override fun onThemeChanged(isDark: Int) {
1717
callbackExecutor.execute {
1818
val dark = isDark != 0
@@ -21,6 +21,8 @@ object MacOSMenuBarThemeDetector {
2121
}
2222
}
2323

24+
private val themeChangedCallback = ThemeCallback()
25+
2426
init {
2527
MacNativeBridge.nativeSetThemeCallback(themeChangedCallback)
2628
}

src/native/macos/MacTrayBridge.m

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -123,14 +123,44 @@ static void clearAllCallbacks(CallbackEntry **list) {
123123
/* C callback trampolines */
124124
/* ========================================================================== */
125125

126+
/*
127+
* Cached method IDs — resolved once via the interface class so that
128+
* GraalVM native-image only needs the interface registered for JNI,
129+
* not every lambda / anonymous class that implements it.
130+
*/
131+
static jmethodID g_runMethodID = NULL;
132+
static jmethodID g_onThemeChangedMethodID = NULL;
133+
134+
static jmethodID getRunnableRunMethod(JNIEnv *env) {
135+
if (g_runMethodID == NULL) {
136+
jclass cls = (*env)->FindClass(env, "java/lang/Runnable");
137+
if (cls) {
138+
g_runMethodID = (*env)->GetMethodID(env, cls, "run", "()V");
139+
(*env)->DeleteLocalRef(env, cls);
140+
}
141+
}
142+
return g_runMethodID;
143+
}
144+
145+
static jmethodID getThemeChangedMethod(JNIEnv *env) {
146+
if (g_onThemeChangedMethodID == NULL) {
147+
jclass cls = (*env)->FindClass(env, "com/kdroid/composetray/lib/mac/MacNativeBridge$ThemeChangeCallback");
148+
if (cls) {
149+
g_onThemeChangedMethodID = (*env)->GetMethodID(env, cls, "onThemeChanged", "(I)V");
150+
(*env)->DeleteLocalRef(env, cls);
151+
}
152+
}
153+
return g_onThemeChangedMethodID;
154+
}
155+
126156
/* Called by the Swift tray_callback when the tray icon is left-clicked */
127157
static void trayCbTrampoline(struct tray *t) {
128158
JNIEnv *env = getJNIEnv();
129159
if (!env) return;
130160
jobject runnable = findCallback(g_trayCallbacks, t);
131161
if (!runnable) return;
132-
jclass cls = (*env)->GetObjectClass(env, runnable);
133-
jmethodID run = (*env)->GetMethodID(env, cls, "run", "()V");
162+
jmethodID run = getRunnableRunMethod(env);
163+
if (!run) return;
134164
(*env)->CallVoidMethod(env, runnable, run);
135165
if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env);
136166
}
@@ -141,8 +171,8 @@ static void menuItemCbTrampoline(struct tray_menu_item *item) {
141171
if (!env) return;
142172
jobject runnable = findCallback(g_menuCallbacks, item);
143173
if (!runnable) return;
144-
jclass cls = (*env)->GetObjectClass(env, runnable);
145-
jmethodID run = (*env)->GetMethodID(env, cls, "run", "()V");
174+
jmethodID run = getRunnableRunMethod(env);
175+
if (!run) return;
146176
(*env)->CallVoidMethod(env, runnable, run);
147177
if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env);
148178
}
@@ -154,8 +184,8 @@ static void themeCbTrampoline(int isDark) {
154184
if (!g_themeCallback) return;
155185
jobject cb = g_themeCallback->globalRef;
156186
if (!cb) return;
157-
jclass cls = (*env)->GetObjectClass(env, cb);
158-
jmethodID method = (*env)->GetMethodID(env, cls, "onThemeChanged", "(I)V");
187+
jmethodID method = getThemeChangedMethod(env);
188+
if (!method) return;
159189
(*env)->CallVoidMethod(env, cb, method, (jint)isDark);
160190
if ((*env)->ExceptionCheck(env)) (*env)->ExceptionClear(env);
161191
}

0 commit comments

Comments
 (0)