Repository navigation
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
WalkthroughAdds a macOS tray menu controller that displays and updates tray icons, builds menus with actions, separators, and submenus, and registers a before-open listener. The Objective-C JNI implementation performs native operations on the main thread and invokes Java callbacks. The module registers the controller as a Priority: ➖ Normal Estimated code review effort: 4 (Complex) | ~45 minutes Change: Feature Suggested reviewers: Merge Risk: ⚪ Minimal · up to
|
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/main/java/org/cryptomator/macos/tray/MacTrayMenuController.java`:
- Around line 49-53: The loadPng method can return null if the provided
iconLoader never invokes the TrayIconLoader.PngData consumer; after calling
iconLoader.accept(...) check holder[0] and if it is null return an empty byte[]
(or otherwise non-null sentinel) instead of null to avoid passing a null array
to native code that calls GetArrayLength; update loadPng (and its single-use
holder/consumer logic) to ensure it always returns a non-null byte[].
- Around line 29-31: The native implementation drops the Java Runnable passed
from MacTrayMenuController.showTrayIcon (Native.showTrayIcon) so clicks do
nothing; update
Java_org_cryptomator_macos_tray_MacTrayMenuController_00024Native_showTrayIcon
to store the passed defaultAction (Runnable) in a global/reference table, set
gStatusItem.button.target and action to a native selector that, when invoked on
click, looks up that stored Runnable and calls its run method via JNI; ensure
you retain a global JNI globalRef to the Runnable and release it when removing
the tray icon or on shutdown, and use the existing gStatusItem.button,
Java_org_cryptomator_macos_tray_MacTrayMenuController_00024Native_showTrayIcon
symbol names to locate where to add the storage, selector hookup, and JNI
invocation.
In `@src/main/native/org_cryptomator_macos_tray_MacTrayMenuController_Native.m`:
- Around line 89-114: The native showTrayIcon currently ignores the
defaultAction jobject; capture and store it as a JNI global reference (e.g.,
create a static jobject gDefaultAction via (*env)->NewGlobalRef(env,
defaultAction)) so it can be invoked later, and ensure you ReleaseGlobalRef when
replacing/removing the tray (cleanup). Also wire gStatusItem.button.action and
.target to an Objective‑C selector (e.g., -handleDefaultAction:) implemented in
the same file that obtains a JNIEnv, finds the Java callback method (or
Runnable.run) and calls it on gDefaultAction; keep gRootMenu and gMenuDelegate
behavior but change menu presentation so left-click triggers the selector
(invoke defaultAction) and show the menu manually (popUpMenu:forEvent: or on
right/Ctrl-click) if you want both menu and defaultAction to work.
- Around line 22-27: callRunnable currently invokes Runnable.run via
CallVoidMethod but never checks for a pending Java exception; update
callRunnable to, immediately after CallVoidMethod, check for exceptions with
ExceptionCheck/ExceptionOccurred, clear the pending exception, rethrow the same
exception back into the JVM with Throw (and delete any local refs), so that a
Java exception from Runnable.run is not left pending and is propagated
correctly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 5a07322f-1f0f-4204-97eb-ef3ef09071e0
📒 Files selected for processing (6)
.gitignoresrc/main/headers/org_cryptomator_macos_tray_MacTrayMenuController_Native.hsrc/main/java/module-info.javasrc/main/java/org/cryptomator/macos/tray/MacTrayMenuController.javasrc/main/native/Integrations.xcodeproj/project.pbxprojsrc/main/native/org_cryptomator_macos_tray_MacTrayMenuController_Native.m
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
|
@overheadhunter |
|
What about this PR? |
overheadhunter
left a comment
There was a problem hiding this comment.
Sorry, lost this PR out of sight.
Two general remarks concerning the ObjC implementation:
- In JNI calls, add
@autoreleasepool {...}where you use autoreleased object (like[NSData dataWithBytes:...]) - all the tray menu APIs must be called on the main thread. Add some check like
if (NSThread.isMainThread) { ... } else { dispatch_sync(dispatch_get_main_queue(), ...) }. The calling java thread should be the main thread, but this not guaranteed by the API contract.
|
Thank you for taking the time to review this PR! This is really great for learning (since I'm at my current job in a Jr. position I take all the feedback and learning opportunities I can get 🙏) No worries I got time, but I thought I did something wrong 🥲 Regarding 1: I added the Towards 2: I added this helper function 🐙 |
overheadhunter
left a comment
There was a problem hiding this comment.
we're mostly there, but I believe not all the autoreleasepools are really needed. I'm not an ObjC expert any more, so please double check when an object is allocated/retained/released/autoreleased. (this is worth learning about 😉)
…-menu-controller # Conflicts: # .gitignore
- Use alloc/init when converting Java strings/arrays so no autoreleased objects are created on Java threads; keep @autoreleasepool only around AppKit convenience constructors (statusItemWithLength:, separatorItem) - Create the root menu once, so building the menu before showTrayIcon no longer hands out dangling submenu handles - Rebuild the whole menu within a single main thread hop - Guard getEnv, JNI strings/arrays and null actions; use JNI_VERSION_10 - Throw TrayMenuException/IllegalStateException as the SPI specifies and log callback exceptions via slf4j - Invoke the before-open listener from menuNeedsUpdate:, where AppKit allows modifying the menu - Add SPI loading test, file header; drop unrelated .gitignore change
|
@overheadhunter Thanks, and you were right: I hadn't actually checked ownership; I'd just wrapped everything in pools. 🙈 The rule I follow now (the file is compiled with ARC): objects returned by So instead of adding pools on the calling Java thread, I now convert Java strings/arrays with
All other main-thread work already runs within the run loop's / main queue's pool. While double-checking, I also fixed a few more things:
I smoke-tested it by building Cryptomator against this snapshot (macOS 27, arm64): icon, menu, submenus (they stay open now), actions, the vault state refresh when opening the menu, and quit all work. |
✅ Action performedReview finished.
|
What
Adds a native macOS implementation of the
TrayMenuControllerSPI, backed byNSStatusItem/NSMenu, replacing the AWT-based tray menu on macOS.Why
The AWT tray menu has long-standing rendering and behavior issues on macOS (cryptomator/cryptomator#1977); e.g. clicking a submenu closes the whole tray menu. A native AppKit menu fixes these.
How
MacTrayMenuController(Java) implementsTrayMenuControllerand is registered viaprovidesinmodule-info.org_cryptomator_macos_tray_MacTrayMenuController_Native.m) drivesNSStatusItemandNSMenudirectly, supporting:menuNeedsUpdate:)TrayMenuExceptionif the icon cannot be added,IllegalStateExceptionfor icon updates/listeners before the icon exists. Callback exceptions are logged via slf4j.Testing
TrayMenuController.get().Notes
defaultActionis ignored: clicking a macOS status item always opens its menu.MACOSX_DEPLOYMENT_TARGET(currently 10.13; Xcode 27 supports 12.0+).🤖 Generated with Claude Code