Commit eaefa9a
authored
fix(ui): use a template tray icon on macOS (#202)
Makes the macOS menu-bar icon a proper **template** image, so the OS
tints it
for light/dark/selected like every other menu-bar extra instead of it
sitting
there as the one coloured blob.
**Verified visually on macOS 26 hardware** (see Verification).
Scope note: this PR originally also carried a Dock-icon change. That
half was
**dropped** on review because it could not be demonstrated - the
findings are
preserved as documentation instead (DESIGN 8.1.1). See "Dock icon"
below.
## The config was a red herring
`tauri.conf.json` already had `trayIcon.iconAsTemplate: true`, but that
never
reaches the live icon: `tray.rs::build()` calls
`remove_tray_by_id("main")` and
replaces the config-defined tray with a runtime-generated
`"driven-main"` one,
built from `include_bytes!("icons/64x64.png")` (a white glyph on
**opaque
teal**) with `set_icon_as_template(false)` forced at four sites -
including one
inside the spinner animation task, which is the easy one to miss.
**Flipping that flag would have made it worse, not better.** macOS
template
images are alpha-only: AppKit discards the RGB and tints every pixel by
its
alpha. Handing it the opaque brand PNG renders a **solid black square**.
## What this does instead
- **New asset** `src-tauri/icons/tray-template.png` - 64x64, black on
transparency. Rasterised from the already-committed `icons/tray.svg`
(which
was always monochrome template art) with a throwaway supersampling
script; it
is just the union of that SVG's 4 circles, 1 rect and 1 polygon, so it
can be
regenerated from the SVG with any rasteriser.
- **`TrayIcon::template_rgba_frame`** paints in *alpha*: the badge's
contrast
band is punched fully transparent (a template has no second ink, so a
hole is
the only way to separate the badge from the mark behind it), and each
state's
glyph is cut **out** of the badge disc.
- The holes are cut with the **same glyph painters as the colour path**
-
rendered into a scratch buffer and inverted into alpha - so the
platforms
cannot drift apart in shape, and the spinner's comet-tail fade (and
therefore
its frame-to-frame distinctness) survives.
- `set_template_mode()` replaces all four hardcoded `false` calls, so
the flag
can never disagree with the pixels just handed over. If the template PNG
ever
fails to decode it falls back to the colour path with template **off** -
never
"opaque pixels declared as a template".
- Windows/Linux are unchanged.
## Deliberate divergence from DESIGN 8.1 - please sanity-check
**On macOS the tray state is now carried by SHAPE only; there is no
yellow or
red.** A template cannot express colour. This is sound because the badge
glyphs
(spinner / pause bars / `!` / `X`) were already designed to be readable
without
colour, and it is what `SPEC.md:1579`'s `iconAsTemplate` for macOS asks
for -
but it does contradict DESIGN 8.1's colour table, so `design/DESIGN.md`
now
carries an explicit macOS carve-out telling future readers not to revert
it.
The template badge is drawn larger than the colour one
(`BADGE_R_TEMPLATE` 0.28
vs `BADGE_R_COLOUR` 0.24, centre pulled in to 0.66) so the punched holes
survive
being scaled to a 22pt menu bar. An earlier attempt at 0.32 **overflowed
the
64px canvas and clipped flat against the edges** - caught by rendering
the
states and looking at them, and now guarded by a
`template_badge_fits_in_the_canvas` test.
## Dock icon: documented, not fixed (DESIGN 8.1.1)
`cargo tauri dev` shows the generic green "exec" icon. This is a
**dev-run
cosmetic artifact, not a shipped-product defect**, and after
investigation it is
deliberately not fixed in code:
- **Release bundles were never affected** - `icons/icon.icns` is in
`bundle.icon` and is a valid 1024px multi-rep icns, so `Driven.app` has
always
had the right Dock icon.
- **Tauri already performs the only available runtime fix**: the icns is
genuinely embedded in the dev binary (verified by byte-searching it) and
`setApplicationIconImage` is already called at `RunEvent::Ready`.
Re-applying
it is a re-run of a mechanism that is already executing.
- **That API cannot fix the surface most likely being seen anyway**:
status
bars / window switchers read `NSRunningApplication.icon()`, which
returns the
static **LaunchServices file-type** icon. Confirmed with a control
experiment -
a bundle-less process that successfully sets its own icon still reports
the
generic one through that API.
- **The only real fix for an unbundled run is to run a bundled `.app`.**
All of the above is now written down in `DESIGN.md` 8.1.1 so nobody
re-derives
it. If the generic icon is ever reported against a *release* build, that
is a
different bug with different evidence.
## Verification
**Confirmed visually on hardware.** Built and ran the app, then captured
the
real menu bar: the Driven icon (cloud + up-chevron) renders in exactly
the same
single-colour tint and weight as its neighbouring template icons - the
reported
coloured blob is gone.
All five states were additionally rendered to PNG and inspected at
**22px and
44px** in simulated **light and dark** menu bars: idle / spinner /
pause-bars /
`!` / `X` stay mutually distinguishable by shape at menu-bar size.
## Gates
- `cargo clippy --workspace --all-targets -- -D warnings` - clean
- `cargo fmt --all -- --check` - clean
- `SQLX_OFFLINE=true cargo test --workspace` - green (37 suites, 0
failures)
- No `ui/` files touched, so the pnpm gates do not apply.
- Diff is 3 files: `tray.rs`, the new PNG, and `DESIGN.md`. No
dependency or
lockfile changes.
New tests: seven macOS-gated tray tests asserting on the **alpha**
channel (the
only channel macOS reads), including `template_source_is_alpha_shaped`
as the
explicit guard against the solid-black-square regression.1 parent 18b0d43 commit eaefa9a
3 files changed
Lines changed: 477 additions & 45 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1398 | 1398 | | |
1399 | 1399 | | |
1400 | 1400 | | |
| 1401 | + | |
| 1402 | + | |
| 1403 | + | |
| 1404 | + | |
| 1405 | + | |
| 1406 | + | |
| 1407 | + | |
| 1408 | + | |
| 1409 | + | |
| 1410 | + | |
| 1411 | + | |
| 1412 | + | |
| 1413 | + | |
| 1414 | + | |
| 1415 | + | |
| 1416 | + | |
| 1417 | + | |
| 1418 | + | |
| 1419 | + | |
| 1420 | + | |
| 1421 | + | |
| 1422 | + | |
| 1423 | + | |
| 1424 | + | |
| 1425 | + | |
| 1426 | + | |
| 1427 | + | |
| 1428 | + | |
| 1429 | + | |
| 1430 | + | |
| 1431 | + | |
| 1432 | + | |
| 1433 | + | |
| 1434 | + | |
| 1435 | + | |
| 1436 | + | |
| 1437 | + | |
| 1438 | + | |
| 1439 | + | |
| 1440 | + | |
| 1441 | + | |
| 1442 | + | |
| 1443 | + | |
| 1444 | + | |
| 1445 | + | |
| 1446 | + | |
| 1447 | + | |
| 1448 | + | |
| 1449 | + | |
| 1450 | + | |
| 1451 | + | |
| 1452 | + | |
| 1453 | + | |
1401 | 1454 | | |
1402 | 1455 | | |
1403 | 1456 | | |
| |||
Loading
0 commit comments