fix(desktop): show macOS tray icon in bundled .app launched via Finder#35626
fix(desktop): show macOS tray icon in bundled .app launched via Finder#35626yyq1025 wants to merge 3 commits into
Conversation
The bundled .app's CFBundleExecutable was a shell script that exec'd the laufey backend with `--runtime`. Under LaunchServices (open / Finder / double-click) that exec breaks the app's foreground-GUI registration, so an NSStatusItem (Deno.Tray) is created but never attaches to the menu bar. Windows are unaffected, and the tray works under `--hmr` and direct-exec, which is why this only shows up for bundled tray apps. Make the laufey backend binary the bundle's CFBundleExecutable directly (no shell-script exec) and copy the runtime dylib as Contents/MacOS/libruntime.dylib, a path laufey already resolves via [NSBundle mainBundle]. This is relocation-safe and needs no `--runtime` argument, so the GUI process is the one LaunchServices launches. Fixes denoland#35619 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Deno Individual Contributor License AgreementAll contributors have signed the CLA. Thank you! This is an automated message from CLA Assistant |
|
Reviewed the diff. Nice root-cause writeup — making the backend the 1. Dropping 2. 3. Stale doc comment. |
…tion Address review feedback on denoland#35626: - The cef backend resolves the runtime dylib as <executable>.dylib next to the binary (LaufeyFindColocatedRuntime), not the hardcoded libruntime.dylib the webview backend searches via [NSBundle mainBundle]. Name the dylib per backend through the new macos_runtime_dylib_name helper so `--backend cef` bundles can find their runtime; add a unit test. - Restore validate_launcher_name(&app_name): it was removed together with the shell launcher, but app_name still flows unescaped into the Info.plist XML (CFBundleName, the NS*UsageDescription strings) and the synthesized bundle id, so an out-of-charset name now yields a clear error instead of a malformed plist that fails to launch. - Update the stale bundle-structure doc comment (no launcher script; the dylib is libruntime.dylib / <backend>.dylib, not libapp.dylib). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Thanks for the review — pushed fixes for all three:
(2) --runtime dropped for all backends (only verified on webview) — this is the substantive one, and it turned out deeper than a naming gate. CEF needs the same launcher-free treatment (the tray-registration bug isn't backend-specific); it resolves the runtime via laufey's co-located discovery (littledivy/laufey#15). The catch: #15 only exists at laufey API 27, while we pin laufey 0.4.1 (API 26) — so a launcher-free CEF bundle loads the dylib but then fails to init against the pinned runtime (API version mismatch: expected 26, got 27). Locally I confirmed the co-located path does find and load the runtime launcher-free (laufey logs Runtime loaded successfully from …laufey.dylib), and the tray code is shared with the webview backend (working launcher-free here) — so I expect CEF to work once both sides are on API 27, but it can't be fully verified on the current pin. Given that, I'd suggest holding this PR until we bump the laufey crate to an API-27 release that includes #15 — then I'll rebase, verify CEF end-to-end, and it can land as one complete fix rather than a webview-only partial. |
|
Update on the CEF backend now that we're on laufey 0.5.0: Tray — works on both backends now. 0.5.0 ships the co-located runtime Window content (separate, pre-existing laufey bug) — CEF windows that load Fixed upstream in littledivy/laufey#34. This is independent of this PR: it's a laufey-side sub-process IPC bug, unrelated to the launcher change here (which only affects how the main process registers with LaunchServices, not CEF's browser↔sub-process Mojo). |
Problem
A
deno desktopapp that creates aDeno.Trayshows its menu-bar icon under--hmr, but the same app bundled with--outputand launched via Finder /openshows no tray icon. Windows work in both cases — only the tray is affected.Reproduces on the official
crowlKats/deno-desktop-matrix-clientexample:Fixes #35619.
Root cause
The bundled
.app'sCFBundleExecutableis a POSIX shell script thatexecs the laufey backend:Under LaunchServices the
/bin/shprocess receives the foreground-GUI check-in and thenexecslaufey_webview. The backend ends up only half-registered: windows still work (they get their own WindowServer connection), but the status bar (SystemUIServer) never accepts theNSStatusItem, so the tray icon is created but never placed in the menu bar. This is why a window-only app is unaffected, and why--hmr/ direct-exec (no LaunchServicesexecindirection) work.Evidence — logging
trayId+getBounds():trayIdgetBounds()--hmr/ direct-exec{x: 1045, y: 6}— menu bar ✅open(LaunchServices){x: 8, y: 1096}— unanchored default ❌The item is created both ways; under
openit just never attaches to the menu bar.Fix
Make the laufey backend binary the bundle's
CFBundleExecutabledirectly (no shell-scriptexec), and copy the runtime dylib asContents/MacOS/libruntime.dylib— a path laufey already resolves via[NSBundle mainBundle](webview/src/main_mac.mm). That makes runtime discovery relocation-safe and removes the need for a--runtimeargument, so the process LaunchServices launches is the GUI process.chmodrender_macos_info_plistnow setsCFBundleExecutableto the backend binaryContents/MacOS/)Test
cargo test macos_info_plist_includes— added an assertion thatCFBundleExecutableis the backend binary, not an app-named launcher.open MatrixClient.app→ tray icon now appears in the menu bar. ✅