Skip to content

Commit df060c1

Browse files
tmmampagent
andauthored
feat(zbugs): app icons with framework badges, and app bundles for the Rust apps (#182)
zbugs-gpui and zbugs-rune ran as bare executables, so the Dock showed the generic "exec" icon. On macOS, `cargo run` now runs each from inside an app bundle (bundle.sh, Cargo's runner there) with an Icon Composer icon compiled by actool: zbugs-swift's icon with GPUI's or Rune's logo as a badge in the bottom-right corner. zbugs-swift's icon gets Swift's logo the same way. Amp-Thread-ID: https://ampcode.com/threads/T-01a1d0e5-95f4-73e5-8d5d-9db8bfed7733 Co-authored-by: Amp <amp@ampcode.com>
1 parent 4f67dad commit df060c1

15 files changed

Lines changed: 384 additions & 1 deletion

File tree

‎apps/zbugs-gpui/.cargo/config.toml‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# `cargo run` on macOS runs the app from inside an app bundle with its icon
2+
# (bundle.sh), rather than as a bare executable.
3+
[target.'cfg(target_os = "macos")']
4+
runner = "./bundle.sh"
Lines changed: 9 additions & 0 deletions
Loading
Lines changed: 4 additions & 0 deletions
Loading
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
{
2+
"fill-specializations": [
3+
{
4+
"value": {
5+
"solid": "srgb:1.00000,1.00000,1.00000,1.00000"
6+
}
7+
},
8+
{
9+
"appearance": "dark",
10+
"value": {
11+
"solid": "srgb:0.00000,0.00000,0.00000,1.00000"
12+
}
13+
},
14+
{
15+
"appearance": "tinted",
16+
"value": {
17+
"solid": "srgb:0.00000,0.00000,0.00000,1.00000"
18+
}
19+
}
20+
],
21+
"groups": [
22+
{
23+
"layers": [
24+
{
25+
"image-name": "gpui.svg",
26+
"name": "gpui",
27+
"position": {
28+
"scale": 1,
29+
"translation-in-points": [255, 255]
30+
}
31+
}
32+
],
33+
"shadow": {
34+
"kind": "neutral",
35+
"opacity": 0.5
36+
},
37+
"translucency": {
38+
"enabled": false,
39+
"value": 0.5
40+
}
41+
},
42+
{
43+
"layers": [
44+
{
45+
"fill-specializations": [
46+
{
47+
"value": {
48+
"solid": "srgb:0.11765,0.11765,0.11765,1.00000"
49+
}
50+
},
51+
{
52+
"appearance": "dark",
53+
"value": {
54+
"solid": "srgb:0.88235,0.88235,0.88235,1.00000"
55+
}
56+
},
57+
{
58+
"appearance": "tinted",
59+
"value": {
60+
"solid": "srgb:1.00000,1.00000,1.00000,1.00000"
61+
}
62+
}
63+
],
64+
"image-name": "zero.svg",
65+
"name": "zero"
66+
}
67+
],
68+
"shadow": {
69+
"kind": "neutral",
70+
"opacity": 0.5
71+
},
72+
"translucency": {
73+
"enabled": false,
74+
"value": 0.5
75+
}
76+
}
77+
],
78+
"supported-platforms": {
79+
"squares": "shared"
80+
}
81+
}

‎apps/zbugs-gpui/README.md‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,15 @@ ZBUGS_TOKEN=<token> cargo run
3737
`ZBUGS_CACHE_URL` (default `http://127.0.0.1:4848`) and `ZBUGS_API_URL`
3838
(default `http://127.0.0.1:5173`) point it elsewhere. Each is also read from
3939
a file of that name (`token`, `cache-url`, `api-url`) in the app's directory.
40+
41+
On macOS, `cargo run` runs the app as an app: `bundle.sh`, Cargo's runner
42+
there (`.cargo/config.toml`), makes `ZBugs GPUI.app` beside the executable
43+
(`target/debug`, or `target/release` with `--release`) and runs the app from
44+
inside it, so the Dock and the app switcher show its icon. The environment
45+
and the output are as before. The bundle stays, to open from Finder or keep
46+
in the Dock; it reads the token and the servers from the files above. The
47+
icon is compiled with Xcode's `actool`, which needs Xcode 26 or later.
48+
49+
The icon (`AppIcon.icon`, an Icon Composer file) is zbugs-swift's with
50+
GPUI's logo as a badge, the mark from [gpui.rs](https://www.gpui.rs). GPUI
51+
and its logo are Zed Industries'.

‎apps/zbugs-gpui/bundle.sh‎

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#!/bin/sh
2+
# Cargo's runner on macOS (.cargo/config.toml): runs zbugs-gpui from inside
3+
# an app bundle, `ZBugs GPUI.app` beside the executable, so it launches as
4+
# an app with its icon (AppIcon.icon) in the Dock and the app switcher. The
5+
# bundle stays, to open from Finder. Tests and other executables run as
6+
# they are.
7+
set -eu
8+
exe=$1
9+
shift
10+
[ "$(basename "$exe")" = zbugs-gpui ] || exec "$exe" "$@"
11+
12+
here=$(cd "$(dirname "$0")" && pwd)
13+
# Absolute: actool takes relative paths from a directory of its own.
14+
app="$(cd "$(dirname "$exe")" && pwd)/ZBugs GPUI.app"
15+
res="$app/Contents/Resources"
16+
mkdir -p "$app/Contents/MacOS" "$res"
17+
18+
# The icon, through Xcode's actool, when it changed: Assets.car for macOS 26
19+
# and later, AppIcon.icns for earlier ones.
20+
if [ ! -e "$res/Assets.car" ] || [ -n "$(find "$here/AppIcon.icon" -newer "$res/Assets.car")" ]; then
21+
partial=$(mktemp)
22+
out=$(xcrun actool "$here/AppIcon.icon" --compile "$res" --platform macosx \
23+
--minimum-deployment-target 11.0 --app-icon AppIcon \
24+
--output-partial-info-plist "$partial" --output-format human-readable-text) ||
25+
{ echo "$out" >&2; exit 1; }
26+
rm -f "$partial"
27+
fi
28+
29+
cat > "$app/Contents/Info.plist" <<'EOF'
30+
<?xml version="1.0" encoding="UTF-8"?>
31+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
32+
<plist version="1.0">
33+
<dict>
34+
<key>CFBundleExecutable</key>
35+
<string>zbugs-gpui</string>
36+
<key>CFBundleIdentifier</key>
37+
<string>dev.rocicorp.zbugs-gpui</string>
38+
<key>CFBundleName</key>
39+
<string>ZBugs GPUI</string>
40+
<key>CFBundlePackageType</key>
41+
<string>APPL</string>
42+
<key>CFBundleIconFile</key>
43+
<string>AppIcon</string>
44+
<key>CFBundleIconName</key>
45+
<string>AppIcon</string>
46+
<key>LSApplicationCategoryType</key>
47+
<string>public.app-category.developer-tools</string>
48+
<key>NSHighResolutionCapable</key>
49+
<true/>
50+
</dict>
51+
</plist>
52+
EOF
53+
54+
# A hard link, not a copy: the executable can be large in a debug build.
55+
ln -f "$exe" "$app/Contents/MacOS/zbugs-gpui"
56+
# LaunchServices can see the bundle before it's whole, as when actool runs,
57+
# and the Dock then shows the app as broken: register it as it is now.
58+
/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister \
59+
-f "$app"
60+
exec "$app/Contents/MacOS/zbugs-gpui" "$@"

‎apps/zbugs-rune/.cargo/config.toml‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# `cargo run` on macOS runs the app from inside an app bundle with its icon
2+
# (bundle.sh), rather than as a bare executable.
3+
[target.'cfg(target_os = "macos")']
4+
runner = "./bundle.sh"
Lines changed: 27 additions & 0 deletions
Loading
Lines changed: 4 additions & 0 deletions
Loading
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
{
2+
"fill-specializations": [
3+
{
4+
"value": {
5+
"solid": "srgb:1.00000,1.00000,1.00000,1.00000"
6+
}
7+
},
8+
{
9+
"appearance": "dark",
10+
"value": {
11+
"solid": "srgb:0.00000,0.00000,0.00000,1.00000"
12+
}
13+
},
14+
{
15+
"appearance": "tinted",
16+
"value": {
17+
"solid": "srgb:0.00000,0.00000,0.00000,1.00000"
18+
}
19+
}
20+
],
21+
"groups": [
22+
{
23+
"layers": [
24+
{
25+
"image-name": "rune.svg",
26+
"name": "rune",
27+
"position": {
28+
"scale": 1,
29+
"translation-in-points": [255, 255]
30+
}
31+
}
32+
],
33+
"shadow": {
34+
"kind": "neutral",
35+
"opacity": 0.5
36+
},
37+
"translucency": {
38+
"enabled": false,
39+
"value": 0.5
40+
}
41+
},
42+
{
43+
"layers": [
44+
{
45+
"fill-specializations": [
46+
{
47+
"value": {
48+
"solid": "srgb:0.11765,0.11765,0.11765,1.00000"
49+
}
50+
},
51+
{
52+
"appearance": "dark",
53+
"value": {
54+
"solid": "srgb:0.88235,0.88235,0.88235,1.00000"
55+
}
56+
},
57+
{
58+
"appearance": "tinted",
59+
"value": {
60+
"solid": "srgb:1.00000,1.00000,1.00000,1.00000"
61+
}
62+
}
63+
],
64+
"image-name": "zero.svg",
65+
"name": "zero"
66+
}
67+
],
68+
"shadow": {
69+
"kind": "neutral",
70+
"opacity": 0.5
71+
},
72+
"translucency": {
73+
"enabled": false,
74+
"value": 0.5
75+
}
76+
}
77+
],
78+
"supported-platforms": {
79+
"squares": "shared"
80+
}
81+
}

0 commit comments

Comments
 (0)