From 5e1b580cb6a9cb37cadc5e72a8f0e7fb7dc38061 Mon Sep 17 00:00:00 2001 From: oc7o Date: Sun, 24 May 2026 16:04:30 +0200 Subject: [PATCH 1/5] Add native TrayMenuController implementation for macOS --- .gitignore | 3 + ..._macos_tray_MacTrayMenuController_Native.h | 71 +++++++ src/main/java/module-info.java | 5 + .../macos/tray/MacTrayMenuController.java | 91 +++++++++ .../Integrations.xcodeproj/project.pbxproj | 4 + ..._macos_tray_MacTrayMenuController_Native.m | 182 ++++++++++++++++++ 6 files changed, 356 insertions(+) create mode 100644 src/main/headers/org_cryptomator_macos_tray_MacTrayMenuController_Native.h create mode 100644 src/main/java/org/cryptomator/macos/tray/MacTrayMenuController.java create mode 100644 src/main/native/org_cryptomator_macos_tray_MacTrayMenuController_Native.m diff --git a/.gitignore b/.gitignore index b35bb5e..190649d 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,6 @@ pom.xml.versionsBackup .idea/compiler.xml .idea/jarRepositories.xml *.iml + +# MacOS +.DS_Store \ No newline at end of file diff --git a/src/main/headers/org_cryptomator_macos_tray_MacTrayMenuController_Native.h b/src/main/headers/org_cryptomator_macos_tray_MacTrayMenuController_Native.h new file mode 100644 index 0000000..62b411c --- /dev/null +++ b/src/main/headers/org_cryptomator_macos_tray_MacTrayMenuController_Native.h @@ -0,0 +1,71 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class org_cryptomator_macos_tray_MacTrayMenuController_Native */ + +#ifndef _Included_org_cryptomator_macos_tray_MacTrayMenuController_Native +#define _Included_org_cryptomator_macos_tray_MacTrayMenuController_Native +#ifdef __cplusplus +extern "C" { +#endif +#undef org_cryptomator_macos_tray_MacTrayMenuController_Native_ROOT_MENU +#define org_cryptomator_macos_tray_MacTrayMenuController_Native_ROOT_MENU 0LL +/* + * Class: org_cryptomator_macos_tray_MacTrayMenuController_Native + * Method: showTrayIcon + * Signature: ([BLjava/lang/String;Ljava/lang/Runnable;)V + */ +JNIEXPORT void JNICALL Java_org_cryptomator_macos_tray_MacTrayMenuController_00024Native_showTrayIcon + (JNIEnv *, jobject, jbyteArray, jstring, jobject); + +/* + * Class: org_cryptomator_macos_tray_MacTrayMenuController_Native + * Method: updateTrayIcon + * Signature: ([B)V + */ +JNIEXPORT void JNICALL Java_org_cryptomator_macos_tray_MacTrayMenuController_00024Native_updateTrayIcon + (JNIEnv *, jobject, jbyteArray); + +/* + * Class: org_cryptomator_macos_tray_MacTrayMenuController_Native + * Method: clearMenu + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_org_cryptomator_macos_tray_MacTrayMenuController_00024Native_clearMenu + (JNIEnv *, jobject); + +/* + * Class: org_cryptomator_macos_tray_MacTrayMenuController_Native + * Method: addActionItem + * Signature: (JLjava/lang/String;ZLjava/lang/Runnable;)V + */ +JNIEXPORT void JNICALL Java_org_cryptomator_macos_tray_MacTrayMenuController_00024Native_addActionItem + (JNIEnv *, jobject, jlong, jstring, jboolean, jobject); + +/* + * Class: org_cryptomator_macos_tray_MacTrayMenuController_Native + * Method: addSeparator + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_org_cryptomator_macos_tray_MacTrayMenuController_00024Native_addSeparator + (JNIEnv *, jobject, jlong); + +/* + * Class: org_cryptomator_macos_tray_MacTrayMenuController_Native + * Method: addSubMenuItem + * Signature: (JLjava/lang/String;)J + */ +JNIEXPORT jlong JNICALL Java_org_cryptomator_macos_tray_MacTrayMenuController_00024Native_addSubMenuItem + (JNIEnv *, jobject, jlong, jstring); + +/* + * Class: org_cryptomator_macos_tray_MacTrayMenuController_Native + * Method: setBeforeOpenMenuListener + * Signature: (Ljava/lang/Runnable;)V + */ +JNIEXPORT void JNICALL Java_org_cryptomator_macos_tray_MacTrayMenuController_00024Native_setBeforeOpenMenuListener + (JNIEnv *, jobject, jobject); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 25c4ab3..fe760e3 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -2,6 +2,7 @@ import org.cryptomator.integrations.keychain.KeychainAccessProvider; import org.cryptomator.integrations.revealpath.RevealPathService; import org.cryptomator.integrations.tray.TrayIntegrationProvider; +import org.cryptomator.integrations.tray.TrayMenuController; import org.cryptomator.integrations.uiappearance.UiAppearanceProvider; import org.cryptomator.integrations.update.UpdateMechanism; import org.cryptomator.macos.autostart.MacAutoStartProvider; @@ -9,6 +10,7 @@ import org.cryptomator.macos.keychain.TouchIdKeychainAccess; import org.cryptomator.macos.revealpath.OpenCmdRevealPathService; import org.cryptomator.macos.tray.MacTrayIntegrationProvider; +import org.cryptomator.macos.tray.MacTrayMenuController; import org.cryptomator.macos.uiappearance.MacUiAppearanceProvider; import org.cryptomator.macos.update.DmgUpdateMechanism; @@ -16,10 +18,13 @@ requires org.cryptomator.integrations.api; requires org.slf4j; + opens org.cryptomator.macos.tray to org.cryptomator.integrations.api; + provides AutoStartProvider with MacAutoStartProvider; provides KeychainAccessProvider with MacSystemKeychainAccess, TouchIdKeychainAccess; provides RevealPathService with OpenCmdRevealPathService; provides TrayIntegrationProvider with MacTrayIntegrationProvider; + provides TrayMenuController with MacTrayMenuController; provides UiAppearanceProvider with MacUiAppearanceProvider; provides UpdateMechanism with DmgUpdateMechanism; } \ No newline at end of file diff --git a/src/main/java/org/cryptomator/macos/tray/MacTrayMenuController.java b/src/main/java/org/cryptomator/macos/tray/MacTrayMenuController.java new file mode 100644 index 0000000..6381927 --- /dev/null +++ b/src/main/java/org/cryptomator/macos/tray/MacTrayMenuController.java @@ -0,0 +1,91 @@ +package org.cryptomator.macos.tray; + +import org.cryptomator.integrations.common.CheckAvailability; +import org.cryptomator.integrations.common.OperatingSystem; +import org.cryptomator.integrations.common.Priority; +import org.cryptomator.integrations.tray.ActionItem; +import org.cryptomator.integrations.tray.SeparatorItem; +import org.cryptomator.integrations.tray.SubMenuItem; +import org.cryptomator.integrations.tray.TrayIconLoader; +import org.cryptomator.integrations.tray.TrayMenuController; +import org.cryptomator.integrations.tray.TrayMenuException; +import org.cryptomator.integrations.tray.TrayMenuItem; +import org.cryptomator.macos.common.NativeLibLoader; + +import java.util.List; +import java.util.function.Consumer; + +@Priority(1000) +@OperatingSystem(OperatingSystem.Value.MAC) +@CheckAvailability +public class MacTrayMenuController implements TrayMenuController { + + @CheckAvailability + public static boolean isAvailable() { + return MacTrayMenuController.class.getResource("/libIntegrations.dylib") != null; + } + + @Override + public void showTrayIcon(Consumer iconLoader, Runnable defaultAction, String tooltip) throws TrayMenuException { + Native.INSTANCE.showTrayIcon(loadPng(iconLoader), tooltip, defaultAction); + } + + @Override + public void updateTrayIcon(Consumer iconLoader) { + Native.INSTANCE.updateTrayIcon(loadPng(iconLoader)); + } + + @Override + public void updateTrayMenu(List items) { + Native.INSTANCE.clearMenu(); + buildMenu(Native.ROOT_MENU, items); + } + + @Override + public void onBeforeOpenMenu(Runnable listener) { + Native.INSTANCE.setBeforeOpenMenuListener(listener); + } + + private static byte[] loadPng(Consumer iconLoader) { + byte[][] holder = {null}; + iconLoader.accept((TrayIconLoader.PngData) data -> holder[0] = data); + return holder[0]; + } + + private void buildMenu(long menuHandle, List items) { + for (var item : items) { + switch (item) { + case ActionItem a -> Native.INSTANCE.addActionItem(menuHandle, a.title(), a.enabled(), a.action()); + case SeparatorItem ignored -> Native.INSTANCE.addSeparator(menuHandle); + case SubMenuItem s -> { + long submenuHandle = Native.INSTANCE.addSubMenuItem(menuHandle, s.title()); + buildMenu(submenuHandle, s.items()); + } + } + } + } + + private static final class Native { + + static final long ROOT_MENU = 0L; + static final Native INSTANCE = new Native(); + + private Native() { + NativeLibLoader.loadLib(); + } + + native void showTrayIcon(byte[] pngData, String tooltip, Runnable defaultAction); + + native void updateTrayIcon(byte[] pngData); + + native void clearMenu(); + + native void addActionItem(long menuHandle, String title, boolean enabled, Runnable action); + + native void addSeparator(long menuHandle); + + native long addSubMenuItem(long menuHandle, String title); + + native void setBeforeOpenMenuListener(Runnable listener); + } +} diff --git a/src/main/native/Integrations.xcodeproj/project.pbxproj b/src/main/native/Integrations.xcodeproj/project.pbxproj index a1c46cb..23a3751 100644 --- a/src/main/native/Integrations.xcodeproj/project.pbxproj +++ b/src/main/native/Integrations.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 06B9771B2FB9FC7200949F2E /* org_cryptomator_macos_tray_MacTrayMenuController_Native.m in Sources */ = {isa = PBXBuildFile; fileRef = 06B9771A2FB9FC7200949F2E /* org_cryptomator_macos_tray_MacTrayMenuController_Native.m */; }; 74BEF1852C0384FB006731AC /* SKYLaunchService.m in Sources */ = {isa = PBXBuildFile; fileRef = 74BEF1842C0384FB006731AC /* SKYLaunchService.m */; }; 74BEF1862C0384FB006731AC /* SKYLaunchService.h in Headers */ = {isa = PBXBuildFile; fileRef = 74BEF1832C0384FB006731AC /* SKYLaunchService.h */; }; 74CF2E7B254C295A006266D6 /* org_cryptomator_macos_autostart_MacLaunchServices_Native.m in Sources */ = {isa = PBXBuildFile; fileRef = 74CF2E7A254C295A006266D6 /* org_cryptomator_macos_autostart_MacLaunchServices_Native.m */; }; @@ -21,6 +22,7 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 06B9771A2FB9FC7200949F2E /* org_cryptomator_macos_tray_MacTrayMenuController_Native.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = org_cryptomator_macos_tray_MacTrayMenuController_Native.m; sourceTree = ""; }; 74BEF1832C0384FB006731AC /* SKYLaunchService.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SKYLaunchService.h; sourceTree = ""; }; 74BEF1842C0384FB006731AC /* SKYLaunchService.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SKYLaunchService.m; sourceTree = ""; }; 74CF2E7A254C295A006266D6 /* org_cryptomator_macos_autostart_MacLaunchServices_Native.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = org_cryptomator_macos_autostart_MacLaunchServices_Native.m; sourceTree = ""; }; @@ -49,6 +51,7 @@ 9E0819AE1D748ECC000C89E6 = { isa = PBXGroup; children = ( + 06B9771A2FB9FC7200949F2E /* org_cryptomator_macos_tray_MacTrayMenuController_Native.m */, 74CF2E7A254C295A006266D6 /* org_cryptomator_macos_autostart_MacLaunchServices_Native.m */, 9E0819C71D75CABC000C89E6 /* org_cryptomator_macos_keychain_MacKeychain_Native.m */, 9EACB1B325557865000F3214 /* org_cryptomator_macos_tray_ActivationPolicy_Native.m */, @@ -145,6 +148,7 @@ 74BEF1852C0384FB006731AC /* SKYLaunchService.m in Sources */, 9EACB1B425557865000F3214 /* org_cryptomator_macos_tray_ActivationPolicy_Native.m in Sources */, 74CF2E7B254C295A006266D6 /* org_cryptomator_macos_autostart_MacLaunchServices_Native.m in Sources */, + 06B9771B2FB9FC7200949F2E /* org_cryptomator_macos_tray_MacTrayMenuController_Native.m in Sources */, 9E21340C255429CA006EA872 /* SKYAppearanceObserver.m in Sources */, 9E21340025542735006EA872 /* org_cryptomator_macos_uiappearance_AppAppearance_Native.m in Sources */, 9E21341225542ECE006EA872 /* SKYAppearanceNotifier.m in Sources */, diff --git a/src/main/native/org_cryptomator_macos_tray_MacTrayMenuController_Native.m b/src/main/native/org_cryptomator_macos_tray_MacTrayMenuController_Native.m new file mode 100644 index 0000000..cb5b9cd --- /dev/null +++ b/src/main/native/org_cryptomator_macos_tray_MacTrayMenuController_Native.m @@ -0,0 +1,182 @@ +// +// org_cryptomator_macos_tray_MacTrayMenuController_Native.m +// + +#import +#include + +static JavaVM *gJvm = NULL; +static NSStatusItem *gStatusItem = nil; +static NSMenu *gRootMenu = nil; + +// NSMenuItem.target is a weak reference, so action handlers are retained here +// for the menu's lifetime and released in clearMenu(). +static NSMutableArray *gActionHandlers = nil; + +static JNIEnv *getEnv(void) { + JNIEnv *env = NULL; + (*gJvm)->AttachCurrentThread(gJvm, (void **)&env, NULL); + return env; +} + +static void callRunnable(JNIEnv *env, jobject runnable) { + jclass cls = (*env)->FindClass(env, "java/lang/Runnable"); + jmethodID run = (*env)->GetMethodID(env, cls, "run", "()V"); + (*env)->CallVoidMethod(env, runnable, run); + (*env)->DeleteLocalRef(env, cls); +} + +@interface SKYActionHandler : NSObject +- (instancetype)initWithAction:(jobject)action; +- (void)fire:(id)sender; +@end + +@implementation SKYActionHandler { + jobject _action; +} + +- (instancetype)initWithAction:(jobject)action { + self = [super init]; + JNIEnv *env = getEnv(); + _action = (*env)->NewGlobalRef(env, action); + return self; +} + +- (void)dealloc { + JNIEnv *env = getEnv(); + (*env)->DeleteGlobalRef(env, _action); +} + +- (void)fire:(id)sender { + JNIEnv *env = getEnv(); + callRunnable(env, _action); +} + +@end + +@interface SKYMenuDelegate : NSObject +@property (nonatomic) jobject beforeOpenListener; +@end + +@implementation SKYMenuDelegate + +- (void)menuWillOpen:(NSMenu *)menu { + if (self.beforeOpenListener != NULL) { + JNIEnv *env = getEnv(); + callRunnable(env, self.beforeOpenListener); + } +} + +@end + +static SKYMenuDelegate *gMenuDelegate = nil; + +// Menu handles crossing the JNI boundary are raw NSMenu pointers cast to jlong; +// 0 (ROOT_MENU) denotes the status item's root menu. +static NSMenu *menuFromHandle(jlong handle) { + if (handle == 0L) { + return gRootMenu; + } + return (__bridge NSMenu *)(void *)(intptr_t)handle; +} + +JNIEXPORT jint JNI_OnLoad(JavaVM *jvm, void *reserved) { + gJvm = jvm; + gActionHandlers = [NSMutableArray array]; + return JNI_VERSION_1_8; +} + +JNIEXPORT void JNICALL Java_org_cryptomator_macos_tray_MacTrayMenuController_00024Native_showTrayIcon +(JNIEnv *env, jobject obj, jbyteArray pngData, jstring tooltip, jobject defaultAction) { + jsize len = (*env)->GetArrayLength(env, pngData); + jbyte *bytes = (*env)->GetByteArrayElements(env, pngData, NULL); + NSData *imageData = [NSData dataWithBytes:bytes length:len]; + (*env)->ReleaseByteArrayElements(env, pngData, bytes, JNI_ABORT); + + const char *tooltipChars = (*env)->GetStringUTFChars(env, tooltip, NULL); + NSString *tooltipStr = [NSString stringWithUTF8String:tooltipChars]; + (*env)->ReleaseStringUTFChars(env, tooltip, tooltipChars); + + gMenuDelegate = [[SKYMenuDelegate alloc] init]; + + NSImage *image = [[NSImage alloc] initWithData:imageData]; + image.size = NSMakeSize(18, 18); + image.template = YES; + + gRootMenu = [[NSMenu alloc] init]; + [gRootMenu setAutoenablesItems:NO]; + gRootMenu.delegate = gMenuDelegate; + + gStatusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength]; + gStatusItem.button.image = image; + gStatusItem.button.toolTip = tooltipStr; + gStatusItem.menu = gRootMenu; +} + +JNIEXPORT void JNICALL Java_org_cryptomator_macos_tray_MacTrayMenuController_00024Native_updateTrayIcon +(JNIEnv *env, jobject obj, jbyteArray pngData) { + jsize len = (*env)->GetArrayLength(env, pngData); + jbyte *bytes = (*env)->GetByteArrayElements(env, pngData, NULL); + NSData *imageData = [NSData dataWithBytes:bytes length:len]; + (*env)->ReleaseByteArrayElements(env, pngData, bytes, JNI_ABORT); + + NSImage *image = [[NSImage alloc] initWithData:imageData]; + image.size = NSMakeSize(18, 18); + image.template = YES; + gStatusItem.button.image = image; +} + +JNIEXPORT void JNICALL Java_org_cryptomator_macos_tray_MacTrayMenuController_00024Native_clearMenu +(JNIEnv *env, jobject obj) { + [gRootMenu removeAllItems]; + [gActionHandlers removeAllObjects]; +} + +JNIEXPORT void JNICALL Java_org_cryptomator_macos_tray_MacTrayMenuController_00024Native_addActionItem +(JNIEnv *env, jobject obj, jlong menuHandle, jstring title, jboolean enabled, jobject action) { + const char *titleChars = (*env)->GetStringUTFChars(env, title, NULL); + NSString *titleStr = [NSString stringWithUTF8String:titleChars]; + (*env)->ReleaseStringUTFChars(env, title, titleChars); + + SKYActionHandler *handler = [[SKYActionHandler alloc] initWithAction:action]; + [gActionHandlers addObject:handler]; + + NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:titleStr + action:@selector(fire:) + keyEquivalent:@""]; + item.target = handler; + item.enabled = (BOOL)enabled; + [menuFromHandle(menuHandle) addItem:item]; +} + +JNIEXPORT void JNICALL Java_org_cryptomator_macos_tray_MacTrayMenuController_00024Native_addSeparator +(JNIEnv *env, jobject obj, jlong menuHandle) { + [menuFromHandle(menuHandle) addItem:[NSMenuItem separatorItem]]; +} + +JNIEXPORT jlong JNICALL Java_org_cryptomator_macos_tray_MacTrayMenuController_00024Native_addSubMenuItem +(JNIEnv *env, jobject obj, jlong menuHandle, jstring title) { + const char *titleChars = (*env)->GetStringUTFChars(env, title, NULL); + NSString *titleStr = [NSString stringWithUTF8String:titleChars]; + (*env)->ReleaseStringUTFChars(env, title, titleChars); + + NSMenu *submenu = [[NSMenu alloc] initWithTitle:titleStr]; + [submenu setAutoenablesItems:NO]; + submenu.delegate = gMenuDelegate; + + NSMenuItem *parentItem = [[NSMenuItem alloc] initWithTitle:titleStr + action:NULL + keyEquivalent:@""]; + parentItem.submenu = submenu; + [menuFromHandle(menuHandle) addItem:parentItem]; + + return (jlong)(intptr_t)(__bridge void *)submenu; +} + +JNIEXPORT void JNICALL Java_org_cryptomator_macos_tray_MacTrayMenuController_00024Native_setBeforeOpenMenuListener +(JNIEnv *env, jobject obj, jobject listener) { + if (gMenuDelegate.beforeOpenListener != NULL) { + (*env)->DeleteGlobalRef(env, gMenuDelegate.beforeOpenListener); + } + gMenuDelegate.beforeOpenListener = (*env)->NewGlobalRef(env, listener); +} From 0b468072ae45b5d04a00b3bbaeb252cacc0d7db8 Mon Sep 17 00:00:00 2001 From: 0x70 <104923372+oc7o@users.noreply.github.com> Date: Sun, 24 May 2026 17:22:31 +0200 Subject: [PATCH 2/5] Add null guard to loadPng function Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../java/org/cryptomator/macos/tray/MacTrayMenuController.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/org/cryptomator/macos/tray/MacTrayMenuController.java b/src/main/java/org/cryptomator/macos/tray/MacTrayMenuController.java index 6381927..a2057f7 100644 --- a/src/main/java/org/cryptomator/macos/tray/MacTrayMenuController.java +++ b/src/main/java/org/cryptomator/macos/tray/MacTrayMenuController.java @@ -49,6 +49,9 @@ public void onBeforeOpenMenu(Runnable listener) { private static byte[] loadPng(Consumer iconLoader) { byte[][] holder = {null}; iconLoader.accept((TrayIconLoader.PngData) data -> holder[0] = data); + if (holder[0] == null) { + throw new IllegalStateException("Icon loader did not provide PNG data"); + } return holder[0]; } From 7d0af148a790233e06a3be09337565f40dec1fad Mon Sep 17 00:00:00 2001 From: oc7o Date: Sun, 24 May 2026 17:28:57 +0200 Subject: [PATCH 3/5] Add comment explaining why the defaultAction parameter is unused --- .../org_cryptomator_macos_tray_MacTrayMenuController_Native.m | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/native/org_cryptomator_macos_tray_MacTrayMenuController_Native.m b/src/main/native/org_cryptomator_macos_tray_MacTrayMenuController_Native.m index cb5b9cd..b7a45ae 100644 --- a/src/main/native/org_cryptomator_macos_tray_MacTrayMenuController_Native.m +++ b/src/main/native/org_cryptomator_macos_tray_MacTrayMenuController_Native.m @@ -88,6 +88,8 @@ JNIEXPORT jint JNI_OnLoad(JavaVM *jvm, void *reserved) { JNIEXPORT void JNICALL Java_org_cryptomator_macos_tray_MacTrayMenuController_00024Native_showTrayIcon (JNIEnv *env, jobject obj, jbyteArray pngData, jstring tooltip, jobject defaultAction) { + // defaultAction is intentionally unused: this status item always presents its + // menu on click (see gStatusItem.menu below) jsize len = (*env)->GetArrayLength(env, pngData); jbyte *bytes = (*env)->GetByteArrayElements(env, pngData, NULL); NSData *imageData = [NSData dataWithBytes:bytes length:len]; From 54dddd3dd590be8174aebc568da874ea3c55809b Mon Sep 17 00:00:00 2001 From: 0x70 <104923372+oc7o@users.noreply.github.com> Date: Sun, 24 May 2026 17:33:51 +0200 Subject: [PATCH 4/5] Log error to stderr for better debugging Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../org_cryptomator_macos_tray_MacTrayMenuController_Native.m | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/native/org_cryptomator_macos_tray_MacTrayMenuController_Native.m b/src/main/native/org_cryptomator_macos_tray_MacTrayMenuController_Native.m index b7a45ae..5f056d5 100644 --- a/src/main/native/org_cryptomator_macos_tray_MacTrayMenuController_Native.m +++ b/src/main/native/org_cryptomator_macos_tray_MacTrayMenuController_Native.m @@ -24,6 +24,10 @@ static void callRunnable(JNIEnv *env, jobject runnable) { jmethodID run = (*env)->GetMethodID(env, cls, "run", "()V"); (*env)->CallVoidMethod(env, runnable, run); (*env)->DeleteLocalRef(env, cls); + if ((*env)->ExceptionCheck(env)) { + (*env)->ExceptionDescribe(env); // Log to stderr for debugging + (*env)->ExceptionClear(env); + } } @interface SKYActionHandler : NSObject From cd9c43519041fc7416be3fa7ecc3bcb6c6ec4d89 Mon Sep 17 00:00:00 2001 From: oc7o Date: Wed, 27 May 2026 06:29:06 +0200 Subject: [PATCH 5/5] removed obsolete availability check as suggested in PR --- src/main/java/module-info.java | 2 -- .../org/cryptomator/macos/tray/MacTrayMenuController.java | 7 ------- 2 files changed, 9 deletions(-) diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index fe760e3..dc2b4e7 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -18,8 +18,6 @@ requires org.cryptomator.integrations.api; requires org.slf4j; - opens org.cryptomator.macos.tray to org.cryptomator.integrations.api; - provides AutoStartProvider with MacAutoStartProvider; provides KeychainAccessProvider with MacSystemKeychainAccess, TouchIdKeychainAccess; provides RevealPathService with OpenCmdRevealPathService; diff --git a/src/main/java/org/cryptomator/macos/tray/MacTrayMenuController.java b/src/main/java/org/cryptomator/macos/tray/MacTrayMenuController.java index a2057f7..a8f16de 100644 --- a/src/main/java/org/cryptomator/macos/tray/MacTrayMenuController.java +++ b/src/main/java/org/cryptomator/macos/tray/MacTrayMenuController.java @@ -1,6 +1,5 @@ package org.cryptomator.macos.tray; -import org.cryptomator.integrations.common.CheckAvailability; import org.cryptomator.integrations.common.OperatingSystem; import org.cryptomator.integrations.common.Priority; import org.cryptomator.integrations.tray.ActionItem; @@ -17,14 +16,8 @@ @Priority(1000) @OperatingSystem(OperatingSystem.Value.MAC) -@CheckAvailability public class MacTrayMenuController implements TrayMenuController { - @CheckAvailability - public static boolean isAvailable() { - return MacTrayMenuController.class.getResource("/libIntegrations.dylib") != null; - } - @Override public void showTrayIcon(Consumer iconLoader, Runnable defaultAction, String tooltip) throws TrayMenuException { Native.INSTANCE.showTrayIcon(loadPng(iconLoader), tooltip, defaultAction);