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
|
|
@ -157,6 +157,41 @@ function pack_probe_src() -> pointer {
|
|||
return s
|
||||
}
|
||||
|
||||
# App.set_icon: the Dock tile for a binary with no bundle around it. The tile itself
|
||||
# cannot be asserted from a test process, so what is checked is the part that can go
|
||||
# wrong silently - that it compiles and runs in a windowed build, that a missing or
|
||||
# unreadable image is a no-op rather than a crash or a cleared icon, and that a headless
|
||||
# build (which has no AppKit linked at all) compiles it away to nothing.
|
||||
function app_icon_case() -> void {
|
||||
let lbl = "App.set_icon -> an icon for a binary with no bundle, and nothing headless"
|
||||
if not is_darwin() { skip(lbl); return }
|
||||
let work = `{tmp_dir()}/appicon`
|
||||
let root = capture_line("pwd")
|
||||
run(`rm -rf {work} && mkdir -p {work}`)
|
||||
# a real PNG to set, made the same way the bundle test makes its icon
|
||||
run(`sips -s format png --resampleHeightWidth 64 64 /System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/GenericApplicationIcon.icns --out {work}/icon.png > /dev/null 2>&1`)
|
||||
var src = "program IconSet {" + nl()
|
||||
src = src + " entry {" + nl()
|
||||
src = src + " App.set_icon(\"icon.png\")" + nl()
|
||||
src = src + " App.set_icon(\"nope.png\")" + nl() # missing: must not crash
|
||||
src = src + " print(\"ok\")" + nl()
|
||||
src = src + " }" + nl()
|
||||
src = src + "}" + nl()
|
||||
write_file(`{work}/i.ludic`, src)
|
||||
if not shq(`cd {work} && {root}/bin/ludicc i.ludic -o i > cc.out 2>&1`) {
|
||||
bad2(lbl, capture_line(`tail -1 {work}/cc.out`)); return
|
||||
}
|
||||
let got = s_trim(capture(`cd {work} && ./i 2>&1`))
|
||||
if got != "ok" { bad2(lbl, `windowed build printed [{got}]`); return }
|
||||
# headless links no AppKit: it has to compile and run just the same
|
||||
if not shq(`cd {work} && {root}/bin/ludicc i.ludic --headless -o ih > hh.out 2>&1`) {
|
||||
bad2(lbl, capture_line(`tail -1 {work}/hh.out`)); return
|
||||
}
|
||||
let goth = s_trim(capture(`cd {work} && ./ih 2>&1`))
|
||||
if goth != "ok" { bad2(lbl, `headless build printed [{goth}]`); return }
|
||||
ok(lbl)
|
||||
}
|
||||
|
||||
# Os.save_dir / config_dir / cache_dir have to name the directory the PLATFORM keeps
|
||||
# those things in - that is the entire reason a program calls them instead of building a
|
||||
# path. They were the macOS layout on every platform, so a game built on Linux wrote its
|
||||
|
|
@ -719,6 +754,7 @@ function cmd_dev_test() -> int {
|
|||
pack_roundtrip_case()
|
||||
packignore_case()
|
||||
os_dirs_case()
|
||||
app_icon_case()
|
||||
bundle_case()
|
||||
|
||||
# install.sh is what the landing page tells people to pipe into sh, and it is
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue