fix tray backend on MacOS - #34
Merged
MasonRemaley merged 1 commit intoSep 24, 2026
Merged
Conversation
This revision fixes an issue where the Unix tray backend is compiled for MacOS builds, so creating a tray fails with "Could not load AppIndicator libraries" and no tray icon ever appears. Unlike tray/cocoa/SDL_tray.m (`#ifdef SDL_PLATFORM_MACOS`) and tray/dummy/SDL_tray.c (`#ifdef SDL_TRAY_DUMMY`), tray/unix/SDL_tray.c carries no platform guard, so it provides SDL_CreateTray unconditionally wherever it is listed. Listing it in the `unix` source group therefore makes it the implementation MacOS gets, and the cocoa backend was not listed in any group at all. This fix adds SDL_tray.m to the `cocoa` source group and adds a new `unix_tray` source group to contain the unix tray backend, mirroring the `unix_dialog` split in allyourcodebase#32. Verified on MacOS: a real NSStatusItem appears in the menu bar, its menu entries fire their callbacks, and SDL_HasActiveTrays correctly suppresses the quit-on-last-window-close behaviour so an app can outlive its window.
syke99
added a commit
to natyv-io/core
that referenced
this pull request
Sep 24, 2026
SDL3 ships a cross-platform tray API and natyv exposed none of it -- the last of the three hard gaps from the 2026-09-20 capability audit that were host-level features rather than widget composition. Three files, following the Persist.zig/PersistStore.zig split: - TrayRegistry.zig state, plus a FIFO of not-yet-applied operations - capabilities/Tray.zig nine guest-facing host functions, pure JSON glue - TrayDrain.zig the only file in this codebase that calls SDL_Tray* Every SDL_Tray* call is documented main-thread-only while every host function runs on the dispatch worker, so operations are queued and drained once per frame -- the same hand-off pending_file_dialog_request and pending_window_requests already established. FIFO order is load-bearing, not incidental: a submenu's entries are queued behind the submenu entry that owns them, and applying out of order would target a handle that does not exist yet. Ids come from the new WidgetHost.reserveId, sharing the widget id space deliberately. Dispatch never validates a widget_id against the registry, so a private counter would eventually hand a tray entry the same number as a real widget and route one's clicks to the other's handler. Sharing makes that structurally impossible rather than unlikely -- and OnClick then works on a tray entry exactly as it does on a Button, for free. Checkbox state is mirrored host-side. SDL flips a checkbox itself when the user clicks it, so the host cannot just remember what the guest last set, and reading it back is main-thread-only -- the callback is already on the main thread, so it reads and records there, and the guest's Checked() answers from the mirror with no round trip. The icon reuses conf.natyv.json's existing `icon` rather than adding a tray-specific setting: an app shipping a tray already ships an app icon, and SDL takes a decoded surface either way. Staged through the same file-swap choreography as -Dapp-font and -Dwindow-style. The lifecycle half, natyv_set_window_visible and natyv_set_quit_on_last_window_close, is not tray-specific but exists because of it -- a tray is usually there so an app can keep running with nothing on screen. Hiding is not closing: the window keeps its widgets, scroll positions and text. The startup window has no root_widget_id, so there was nobody to notify and quitting was the only option; a guest now nominates a widget id it already owns. That id may not be 0, because Dispatch already pushes synthetic no-op events there on the documented assumption that no real app registers a handler for id 0, and honouring 0 would quietly deliver those to a guest's close handler. quit=false with no notify id is rejected outright rather than producing a close button that does nothing and no way to quit. A quit-path trace sits behind NATYV_STARTUP_TRACE. Once an app can outlive its own window, a vetoed close, SDL's own quit-on-last-window-close and a real Cmd+Q are indistinguishable from outside -- added after exactly that ambiguity cost a debugging round. build.zig.zon now pins natyv-io/SDL, a fork of allyourcodebase/SDL, for one four-line fix. tray/unix/SDL_tray.c carries no platform guard, unlike the cocoa and dummy backends, and upstream lists it in the shared `unix` source group that macos.zig also compiles while listing tray/cocoa/SDL_tray.m nowhere at all -- so SDL_CreateTray on macOS ran the Linux AppIndicator backend and always failed. Submitted upstream as allyourcodebase/SDL#34, mirroring their own PR #32 which fixed the identical bug for file dialogs. Re-pin to a release tag and drop the fork once it merges; until then the fork needs upstream merged into it periodically, since nothing automates that. Verified live on macOS: the icon renders in the menu bar, a menu click travels SDL callback to EventQueue to worker dispatch to guest handler and back through a host call to mutate a real Label on screen, and hide, show and a vetoed window close all work with zero SDL_EVENT_QUIT. Windows and Linux use upstream's own unmodified backends and have not been run. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Contributor
|
Thanks for the PR! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This revision fixes an issue where the Unix tray backend is compiled for MacOS builds, so
SDL_CreateTrayfails with "Could not load AppIndicator libraries" and no tray icon ever appears.Unlike
tray/cocoa/SDL_tray.m(#ifdef SDL_PLATFORM_MACOS) andtray/dummy/SDL_tray.c(#ifdef SDL_TRAY_DUMMY),tray/unix/SDL_tray.ccarries no platform guard, so it providesSDL_CreateTrayunconditionally wherever it is listed. Listing it in theunixsource group therefore makes it the implementation MacOS gets, and the cocoa backend was not listed in any group at all.This fix adds
SDL_tray.mto thecocoasource group and adds a newunix_traysource group to contain the unix tray backend, mirroring theunix_dialogsplit in #32 — same class of bug, same shape of fix.Verified on MacOS (aarch64, Zig 0.16.0, SDL 3.4.14): a real
NSStatusItemappears in the menu bar with its icon, menu entries fire theirSDL_SetTrayEntryCallbackcallbacks, andSDL_HasActiveTraysthen correctly suppresses the quit-on-last-window-close behaviour inSDL_windowevents.c, so an app can outlive its own window — which it could not before, since no tray was ever registered.