Files
talk/internal/icon/icon.go
T
m3ta-chironandClaude Fable 5.1 2e77cf0a11 feat(icon): app icon with embedded PNG, Windows .ico and resource objects
One SVG source (assets/icon/talk.svg: speech bubble with level bars).
assets/icon/gen.go renders it with inkscape into the embedded PNG
(internal/icon, installed next to the config for notifications), the
multi-size talk.ico and the COFF .rsrc objects for windows/amd64 and
arm64 that give talk.exe its icon. The generator writes the resource
objects itself, so no resource compiler is needed; everything it
produces is committed and a plain go build picks it up.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-25 12:43:14 +01:00

40 lines
1.1 KiB
Go

// Package icon carries the talk icon for the desktop: the PNG is embedded
// in the binary and written next to the config so the OS can show it in
// notifications (Windows toast identity, freedesktop app_icon). The source
// is assets/icon/talk.svg; `go run assets/icon/gen.go` renders it, the
// Windows .ico and the resource objects for talk.exe.
package icon
import (
"bytes"
_ "embed"
"errors"
"os"
"path/filepath"
)
//go:embed talk.png
var PNG []byte
// FileName is the icon's name in the config directory.
const FileName = "talk.png"
// Install writes the icon into dir (if missing or outdated) and returns its
// path. Idempotent: an unchanged file is not touched.
func Install(dir string) (string, error) {
if dir == "" {
return "", errors.New("icon: no directory")
}
path := filepath.Join(dir, FileName)
if cur, err := os.ReadFile(path); err == nil && bytes.Equal(cur, PNG) {
return path, nil
}
if err := os.MkdirAll(dir, 0o755); err != nil {
return "", err
}
if err := os.WriteFile(path, PNG, 0o644); err != nil {
return "", err
}
return path, nil
}