feat(app): App.set_icon, so a game without a bundle still has an icon
`ludic bundle` builds an AppIcon.icns and macOS reads it out of the .app, so a shipped game has an icon. `ludic build` produces a bare executable: no bundle, no CFBundleIconFile, and so no icon at all - macOS draws the generic green "exec" tile. That is the build a developer runs every day, which is why "the game has no icon" can be true for months while the bundle is perfect. It was here: the .app's icns validated against iconutil, the plist was right, the signature was right, and NSWorkspace rendered the artwork - and the binary beside it still had the exec tile. App.set_icon(path) takes the bytes through lp_pak_open, so a packed path and a loose one both work and this does not repeat Audio.load's trick of taking a filesystem path only. NSData copies them, so the buffer goes straight back. A missing or undecodable image leaves the existing icon alone rather than clearing it; a bundled app is unaffected; headless links no AppKit and compiles it away. Verified the Cocoa sequence against an ObjC twin doing the same message sends: before, a bare binary's applicationIconImage is the generic 128x128 tile; after, it is the 1024x1024 artwork. Backend change, so selfhost/ludicc.seed.ll is reseeded: the bootstrap fixpoint and the C-free rebuild from the seed both pass.
This commit is contained in:
parent
925d133466
commit
38b6b81cd7
7 changed files with 34345 additions and 34143 deletions
19
changes/app-set-icon.md
Normal file
19
changes/app-set-icon.md
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
bump: minor
|
||||
type: feat
|
||||
**`App.set_icon(path)`** — an icon for a binary that has no bundle to take one from.
|
||||
|
||||
`ludic bundle` builds an `AppIcon.icns` and macOS reads it from the `.app`, so a
|
||||
shipped game has an icon. `ludic build` produces a bare executable, which has no
|
||||
bundle, no `CFBundleIconFile` and therefore no icon at all — macOS draws the generic
|
||||
green "exec" tile in the Dock. That is the build a developer runs all day and the one
|
||||
they see every session, so "my game has no icon" is true long before it ships.
|
||||
|
||||
```ludic
|
||||
App.set_icon("assets/app/icon.png")
|
||||
```
|
||||
|
||||
The path resolves through the pack first and the filesystem second, like every other
|
||||
asset, so the same call works packed and unpacked — it does not repeat `Audio.load`'s
|
||||
trick of taking a filesystem path only. An image that cannot be found or decoded
|
||||
leaves the current icon alone rather than clearing it, calling it in a bundled app is
|
||||
a harmless no-op, and a headless build compiles it away to nothing.
|
||||
Loading…
Add table
Add a link
Reference in a new issue