Fix SetApplicationIconImage: resolve NSImage after AppKit is loaded - #18
Merged
Merged
Conversation
SetApplicationIconImage called ClassID("NSData")/ClassID("NSImage")
BEFORE ever calling App() — the only thing that triggers AppKit's
lazy load (appKitOnce.Do). For a caller where this is the FIRST
AppKit-touching call in the process (exactly the case it exists for:
a menu-bar app's own startup, before any window or tray call), NSImage
resolves to a nil class, alloc/initWithData: are Objective-C's
well-defined "message to nil" no-op, and img == 0 silently short-
circuits the whole function. App()'s own doc comment already
describes this exact failure mode for a caller who forgets to load
AppKit first — this function made the same mistake internally.
The on-device test suite didn't catch it: objc_darwin_test.go's own
init() pre-loads Foundation+AppKit for every test in the binary,
which is precisely the condition that hides this bug. Found by
building a real, single-purpose standalone program that calls
SetApplicationIconImage as its first-ever AppKit interaction (go
test's shared test binary can't reproduce that "first call" state
by construction) — confirmed via go-aiquota/tray's real menu-bar app,
which hit this exact ordering on every real launch.
Fix: call App() first, use its return for the final assignment.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2 tasks
tannevaled
added a commit
to go-aiquota/tray
that referenced
this pull request
Sep 9, 2026
Live user request: "il faudrait avoir une icon dock pour la fenetre d'history" — this otherwise menu-bar-only (accessory-policy) process already switches to Regular activation policy while a real window (the history chart) is open, per go-widgets/tray's own RunAppLoop/window.Open dance — so the Dock tile itself already appears, but an unsigned binary with no Info.plist icon resource got no image for it, not merely a generic one. Embeds the org's own brand PNG (go-aiquota/brand/png/color/1024) and sets it via go-macos/objc.SetApplicationIconImage once at startup. Needed a real fix upstream first (go-macos/objc#18, v0.10.1): SetApplicationIconImage resolved NSImage before ever loading AppKit, so calling it as the FIRST AppKit interaction in a process — exactly this app's own startup — silently no-opped. Confirmed root cause with a standalone diagnostic (go test's shared test binary structurally can't reproduce "first AppKit call in the process"). Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This was referenced Sep 9, 2026
tannevaled
added a commit
that referenced
this pull request
Sep 9, 2026
) Live bug report, after the icon finally started appearing (#18): it rendered visibly larger than every sibling Dock tile. An NSImage built via alloc/initWithData: takes its .size from the bitmap's own PIXEL count when no DPI metadata says otherwise — a crisp 1024x1024 source PNG (what a real Retina-ready brand asset actually is) reported an image AppKit's layout treats as 1024 POINTS across, not a normal app icon's size. go-widgets/tray already solved the identical problem for its own menu-bar/menu-row icons (nsImageFromPNG) — same fix here: an explicit setSize: call at dockIconPoints (128, macOS's own "large icon" convention), preserving aspect ratio. Turns the extra pixels into resolution instead of dimensions. Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
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.
Summary
SetApplicationIconImage(#17) calledClassID("NSData")/ClassID("NSImage")before ever callingApp()— the only thing that triggers AppKit's lazy load (appKitOnce.Do). For a caller where this is the first AppKit-touching call in the process — exactly the case it exists for, a menu-bar app's own startup, before any window or tray call —NSImageresolves to a nil class,alloc/initWithData:are Objective-C's well-defined "message to nil" no-op, andimg == 0silently short-circuits the whole function.App()'s own doc comment already describes this exact failure mode for a caller who forgets to load AppKit first; this function made the same mistake internally.The on-device test suite didn't catch it:
objc_darwin_test.go's owninit()pre-loads Foundation+AppKit for every test in the shared binary, which is precisely the condition that hides this bug — no test in that binary is ever the "first AppKit call" in its process by construction.Found live: go-aiquota/tray's real menu-bar app called
SetApplicationIconImageas its first-ever AppKit interaction on every real launch, and the Dock icon never appeared. Confirmed root cause with a standalone single-purpose program (notgo test, which structurally can't reproduce "first call in the process").Fix: call
App()first, use its return value for the final assignment.Test plan
go build ./...,CGO_ENABLED=0 go vet ./...,gofmt -l .cleanCGO_ENABLED=0 go test ./...green on darwinSetApplicationIconImageas the first AppKit call in the process — nil image before the fix, correct 1024×1024 image after🤖 Generated with Claude Code