Files
gosentry/assets/assets.go
T
mixeme f533739d6e P5: per-platform transparent, size-appropriate window/tray icons
Give the window titlebar, taskbar, and tray a size-appropriate icon with a
transparent boundary on both Windows and Linux, instead of scaling one PNG to
every size.

Assets:
- Regenerate the PNGs and gosentry.ico with feathered color-to-alpha so the
  rounded-tile boundary is transparent; a binary white-key had left an opaque
  halo that read as a border on dark taskbars/trays.
- Rebuild gosentry.ico as multi-size (16 hand-tuned + 32/48/256 from big) and
  add a single-frame 16x16 gosentry-icon-16x16.ico for the Windows tray.
- assets.go: add IconSmall() and IconSmallICO().

Wiring:
- Windows window/taskbar: embed gosentry.ico under the GLFW_ICON resource and
  skip a.SetIcon so GLFW selects the right frame per size (hand-tuned 16 for the
  titlebar, a larger frame for the taskbar).
- Windows tray: SetSystemTrayIcon(IconSmallICO()), a 16x16 ICO frame.
- Linux window titlebar: a.SetIcon(IconSmall()) for a crisp ~16px _NET_WM_ICON;
  tray uses the big PNG since StatusNotifierItem renders larger.

Also bump Fyne 2.6.3 -> 2.7.4 (systray 1.11.0 -> 1.12.1) and document the full
cross-platform icon strategy in assets.go, gosentry.rc, run.go, and tray.go.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 22:09:04 +03:00

93 lines
4.5 KiB
Go

package assets
import (
_ "embed"
"fyne.io/fyne/v2"
)
// Icons are embedded into the binary instead of being loaded from an assets
// directory at runtime. That keeps the Windows/Linux distribution to a single
// executable and avoids the common failure mode where the app starts with a
// generic icon because a sidecar PNG was not copied with the binary. The blank
// "embed" import enables the //go:embed directives below.
//
// # Cross-platform icon strategy
//
// The hard constraint: Fyne's a.SetIcon and SetSystemTrayIcon each take ONE
// image, which the OS then scales to every size it needs — titlebar (~16px),
// taskbar/dock (~32-48px), and tray. Neither source survives that scaling:
// downscaling the 1254px gosentry-icon-big.png to 16px is muddy, and upscaling
// the 16px icon to 32px is blurry. The fix is to feed each surface a
// size-appropriate source — which differs per platform because each platform
// exposes different icon channels.
//
// Source assets (all have a transparent boundary; note that a *binary* white-key
// leaves the anti-aliased edge fully opaque as a light halo that reads as a
// border on a dark taskbar/tray, so the background is removed with feathered
// color-to-alpha instead):
// - gosentry-icon-big.png detailed large artwork (teal rounded-tile emblem)
// - gosentry-icon-16x16.png hand-tuned for legibility at 16px
// - gosentry.ico multi-size 16/32/48/256 (16 = the hand-tuned PNG,
// the rest downscaled from big). Embedded into the PE
// binary by windres (see scripts/build-windows.bat),
// NOT via Go embed.
// - gosentry-icon-16x16.ico single 16px frame, for the Windows tray
//
// Windows:
// - Window titlebar + taskbar: the multi-size gosentry.ico, embedded by the .rc
// under the resource name GLFW_ICON (packaging/windows/gosentry.rc). GLFW uses
// it as the window's default icon and selects the right frame per size — the
// hand-tuned 16 for the titlebar, a larger frame for the taskbar. For this to
// work, src/ui/run.go must NOT call a.SetIcon on Windows: a single SetIcon
// resource overrides GLFW_ICON and would be scaled to both sizes.
// - Tray: SetSystemTrayIcon(IconSmallICO()). The notification area is ICO-native
// and renders at 16-24px; a single-frame 16x16 .ico pins the hand-tuned glyph
// (a multi-size .ico made the tray pick and downscale a larger frame).
//
// Linux / other non-Windows (no PE icon resource exists):
// - Window titlebar: a.SetIcon(IconSmall()) in run.go feeds the resource to
// _NET_WM_ICON, which the window manager renders ~16px in the titlebar, so the
// hand-tuned 16x16 keeps it crisp.
// - Dock/launcher: the larger icon comes from the .desktop entry's Icon=, written
// by InstallDesktopIcon (src/platform/desktop) from the big artwork.
// - Tray: SetSystemTrayIcon(Icon()). StatusNotifierItem renders 22-48px and takes
// a PNG, so the big artwork scales down cleanly (the 16x16 would look tiny).
//go:embed gosentry-icon-16x16.png
var iconSmallBytes []byte
//go:embed gosentry-icon-big.png
var iconBytes []byte
//go:embed gosentry-icon-16x16.ico
var iconSmallICOBytes []byte
// IconSmall returns the hand-tuned 16x16 PNG. It is the Linux window-titlebar
// icon (via a.SetIcon -> _NET_WM_ICON, which the WM renders at ~16px). On Windows
// the titlebar comes from gosentry.ico instead; see the package strategy above.
func IconSmall() fyne.Resource {
return fyne.NewStaticResource("gosentry-icon-16x16.png", iconSmallBytes)
}
// IconSmallICO returns a single-frame 16x16 Windows .ico of the hand-tuned small
// icon, used for the Windows system tray. The notification area is ICO-native, and
// pinning a single 16x16 frame keeps the hand-tuned glyph crisp at tray size — a
// multi-size .ico lets the tray pick and downscale a larger, muddier frame.
func IconSmallICO() fyne.Resource {
return fyne.NewStaticResource("gosentry-icon-16x16.ico", iconSmallICOBytes)
}
// Icon returns the large artwork PNG. It is the Linux tray icon (StatusNotifierItem
// renders 22-48px) and the source for the Linux .desktop dock icon via IconBytes.
// The Windows window/taskbar icon comes from gosentry.ico, not this resource.
func Icon() fyne.Resource {
return fyne.NewStaticResource("gosentry-icon-big.png", iconBytes)
}
// IconBytes is the large artwork as raw PNG bytes for InstallDesktopIcon, which
// writes the Linux .desktop launcher/dock icon.
func IconBytes() []byte {
return append([]byte(nil), iconBytes...)
}