diff --git a/assets/assets.go b/assets/assets.go index 0587a9e..33f1247 100644 --- a/assets/assets.go +++ b/assets/assets.go @@ -6,25 +6,87 @@ import ( "fyne.io/fyne/v2" ) -// The application icon is 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. +// 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. // -// The blank import enables the compiler directive below; no runtime package -// initialization from embed is required. +// # 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 { - // Fyne accepts resources from memory, so the same embedded PNG can be used - // for the window icon and tray icon. The Windows Explorer icon is still added - // by the build script through the .ico resource, because Explorer reads PE - // resources rather than Fyne runtime state. 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...) } diff --git a/assets/gosentry-icon-16x16.ico b/assets/gosentry-icon-16x16.ico new file mode 100644 index 0000000..ddc5bca Binary files /dev/null and b/assets/gosentry-icon-16x16.ico differ diff --git a/assets/gosentry-icon-16x16.png b/assets/gosentry-icon-16x16.png index df836f0..b093cae 100644 Binary files a/assets/gosentry-icon-16x16.png and b/assets/gosentry-icon-16x16.png differ diff --git a/assets/gosentry-icon-big.png b/assets/gosentry-icon-big.png index bcc1ddd..4afe3fe 100644 Binary files a/assets/gosentry-icon-big.png and b/assets/gosentry-icon-big.png differ diff --git a/assets/gosentry.ico b/assets/gosentry.ico index 8eb98bc..1f788ac 100644 Binary files a/assets/gosentry.ico and b/assets/gosentry.ico differ diff --git a/go.mod b/go.mod index c8d8a0a..671cbc3 100644 --- a/go.mod +++ b/go.mod @@ -3,38 +3,40 @@ module gitea.mixdep.ru/mix/gosentry go 1.22 require ( - fyne.io/fyne/v2 v2.6.3 + fyne.io/fyne/v2 v2.7.4 github.com/robfig/cron/v3 v3.0.1 go.yaml.in/yaml/v4 v4.0.0-rc.5 ) require ( - fyne.io/systray v1.11.0 // indirect - github.com/BurntSushi/toml v1.4.0 // indirect + fyne.io/systray v1.12.1 // indirect + github.com/BurntSushi/toml v1.5.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/fredbi/uri v1.1.0 // indirect + github.com/fredbi/uri v1.1.1 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/fyne-io/gl-js v0.2.0 // indirect github.com/fyne-io/glfw-js v0.3.0 // indirect github.com/fyne-io/image v0.1.1 // indirect - github.com/fyne-io/oksvg v0.1.0 // indirect + github.com/fyne-io/oksvg v0.2.0 // indirect github.com/go-gl/gl v0.0.0-20231021071112-07e5d0ea2e71 // indirect github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a // indirect - github.com/go-text/render v0.2.0 // indirect - github.com/go-text/typesetting v0.2.1 // indirect + github.com/go-text/render v0.2.1 // indirect + github.com/go-text/typesetting v0.3.4 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/hack-pad/go-indexeddb v0.3.2 // indirect github.com/hack-pad/safejs v0.1.0 // indirect github.com/jeandeaual/go-locale v0.0.0-20250612000132-0ef82f21eade // indirect github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25 // indirect github.com/kr/text v0.2.0 // indirect + github.com/mattn/go-runewidth v0.0.17 // indirect github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect github.com/nicksnyder/go-i18n/v2 v2.5.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/rymdport/portal v0.4.1 // indirect + github.com/rivo/uniseg v0.2.0 // indirect + github.com/rymdport/portal v0.4.2 // indirect github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c // indirect github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef // indirect - github.com/stretchr/testify v1.10.0 // indirect + github.com/stretchr/testify v1.11.1 // indirect github.com/yuin/goldmark v1.7.8 // indirect golang.org/x/image v0.24.0 // indirect golang.org/x/net v0.35.0 // indirect diff --git a/go.sum b/go.sum index e2f2a00..8d938b0 100644 --- a/go.sum +++ b/go.sum @@ -1,16 +1,16 @@ -fyne.io/fyne/v2 v2.6.3 h1:cvtM2KHeRuH+WhtHiA63z5wJVBkQ9+Ay0UMl9PxFHyA= -fyne.io/fyne/v2 v2.6.3/go.mod h1:NGSurpRElVoI1G3h+ab2df3O5KLGh1CGbsMMcX0bPIs= -fyne.io/systray v1.11.0 h1:D9HISlxSkx+jHSniMBR6fCFOUjk1x/OOOJLa9lJYAKg= -fyne.io/systray v1.11.0/go.mod h1:RVwqP9nYMo7h5zViCBHri2FgjXF7H2cub7MAq4NSoLs= -github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= -github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +fyne.io/fyne/v2 v2.7.4 h1:OVCI5mT+Onb2kA4wlmGA5pLCqKik9f4NDb5jiR1OMTc= +fyne.io/fyne/v2 v2.7.4/go.mod h1:ZD1mmhBY75mSa97IXl3MPlICd1uNHfCXYh5hKIlVOII= +fyne.io/systray v1.12.1 h1:ygBD6aZXwiOmZoY5N+ukbH9pih0Kq6fYgVeMYbr5skQ= +fyne.io/systray v1.12.1/go.mod h1:RVwqP9nYMo7h5zViCBHri2FgjXF7H2cub7MAq4NSoLs= +github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= +github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g= github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw= -github.com/fredbi/uri v1.1.0 h1:OqLpTXtyRg9ABReqvDGdJPqZUxs8cyBDOMXBbskCaB8= -github.com/fredbi/uri v1.1.0/go.mod h1:aYTUoAXBOq7BLfVJ8GnKmfcuURosB1xyHDIfWeC/iW4= +github.com/fredbi/uri v1.1.1 h1:xZHJC08GZNIUhbP5ImTHnt5Ya0T8FI2VAwI/37kh2Ko= +github.com/fredbi/uri v1.1.1/go.mod h1:4+DZQ5zBjEwQCDmXW5JdIjz0PUA+yJbvtBv+u+adr5o= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fyne-io/gl-js v0.2.0 h1:+EXMLVEa18EfkXBVKhifYB6OGs3HwKO3lUElA0LlAjs= @@ -19,18 +19,18 @@ github.com/fyne-io/glfw-js v0.3.0 h1:d8k2+Y7l+zy2pc7wlGRyPfTgZoqDf3AI4G+2zOWhWUk github.com/fyne-io/glfw-js v0.3.0/go.mod h1:Ri6te7rdZtBgBpxLW19uBpp3Dl6K9K/bRaYdJ22G8Jk= github.com/fyne-io/image v0.1.1 h1:WH0z4H7qfvNUw5l4p3bC1q70sa5+YWVt6HCj7y4VNyA= github.com/fyne-io/image v0.1.1/go.mod h1:xrfYBh6yspc+KjkgdZU/ifUC9sPA5Iv7WYUBzQKK7JM= -github.com/fyne-io/oksvg v0.1.0 h1:7EUKk3HV3Y2E+qypp3nWqMXD7mum0hCw2KEGhI1fnBw= -github.com/fyne-io/oksvg v0.1.0/go.mod h1:dJ9oEkPiWhnTFNCmRgEze+YNprJF7YRbpjgpWS4kzoI= +github.com/fyne-io/oksvg v0.2.0 h1:mxcGU2dx6nwjJsSA9PCYZDuoAcsZ/OuJlvg/Q9Njfo8= +github.com/fyne-io/oksvg v0.2.0/go.mod h1:dJ9oEkPiWhnTFNCmRgEze+YNprJF7YRbpjgpWS4kzoI= github.com/go-gl/gl v0.0.0-20231021071112-07e5d0ea2e71 h1:5BVwOaUSBTlVZowGO6VZGw2H/zl9nrd3eCZfYV+NfQA= github.com/go-gl/gl v0.0.0-20231021071112-07e5d0ea2e71/go.mod h1:9YTyiznxEY1fVinfM7RvRcjRHbw2xLBJ3AAGIT0I4Nw= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a h1:vxnBhFDDT+xzxf1jTJKMKZw3H0swfWk9RpWbBbDK5+0= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-text/render v0.2.0 h1:LBYoTmp5jYiJ4NPqDc2pz17MLmA3wHw1dZSVGcOdeAc= -github.com/go-text/render v0.2.0/go.mod h1:CkiqfukRGKJA5vZZISkjSYrcdtgKQWRa2HIzvwNN5SU= -github.com/go-text/typesetting v0.2.1 h1:x0jMOGyO3d1qFAPI0j4GSsh7M0Q3Ypjzr4+CEVg82V8= -github.com/go-text/typesetting v0.2.1/go.mod h1:mTOxEwasOFpAMBjEQDhdWRckoLLeI/+qrQeBCTGEt6M= -github.com/go-text/typesetting-utils v0.0.0-20241103174707-87a29e9e6066 h1:qCuYC+94v2xrb1PoS4NIDe7DGYtLnU2wWiQe9a1B1c0= -github.com/go-text/typesetting-utils v0.0.0-20241103174707-87a29e9e6066/go.mod h1:DDxDdQEnB70R8owOx3LVpEFvpMK9eeH1o2r0yZhFI9o= +github.com/go-text/render v0.2.1 h1:qwHhxqGUjjg4L0XyJWj7M7bpY75NZM+kBpv2Yfw5mcg= +github.com/go-text/render v0.2.1/go.mod h1:HCCAq8MUlm/WRcXshBb4K/n+IkjeXQ1c2Ba+yICSm0A= +github.com/go-text/typesetting v0.3.4 h1:YYurUOtEb9kGSOz4uE3k4OpBGsp1dDL8+fjCeaFamAU= +github.com/go-text/typesetting v0.3.4/go.mod h1:4qZCQphq4KSgGTAeI0uMEkVbROgfah8BuyF5LRYr7XY= +github.com/go-text/typesetting-utils v0.0.0-20260223113751-2d88ac90dae3 h1:drBZzMgdYPbmyXqOto4YhhJGrFIQCX94FpR4MzTCsos= +github.com/go-text/typesetting-utils v0.0.0-20260223113751-2d88ac90dae3/go.mod h1:3/62I4La/HBRX9TcTpBj4eipLiwzf+vhI+7whTc9V7o= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/google/pprof v0.0.0-20211214055906-6f57359322fd h1:1FjCyPC+syAzJ5/2S8fqdZK1R22vvA0J7JZKcuOIQ7Y= @@ -45,6 +45,8 @@ github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25 h1:YLvr1eE6cdCqjOe9 github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25/go.mod h1:kLgvv7o6UM+0QSf0QjAse3wReFDsb9qbZJdfexWlrQw= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mattn/go-runewidth v0.0.17 h1:78v8ZlW0bP43XfmAfPsdXcoNCelfMHsDmd/pkENfrjQ= +github.com/mattn/go-runewidth v0.0.17/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= github.com/nicksnyder/go-i18n/v2 v2.5.1 h1:IxtPxYsR9Gp60cGXjfuR/llTqV8aYMsC472zD0D1vHk= @@ -55,16 +57,18 @@ github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA= github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= -github.com/rymdport/portal v0.4.1 h1:2dnZhjf5uEaeDjeF/yBIeeRo6pNI2QAKm7kq1w/kbnA= -github.com/rymdport/portal v0.4.1/go.mod h1:kFF4jslnJ8pD5uCi17brj/ODlfIidOxlgUDTO5ncnC4= +github.com/rymdport/portal v0.4.2 h1:7jKRSemwlTyVHHrTGgQg7gmNPJs88xkbKcIL3NlcmSU= +github.com/rymdport/portal v0.4.2/go.mod h1:kFF4jslnJ8pD5uCi17brj/ODlfIidOxlgUDTO5ncnC4= github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c h1:km8GpoQut05eY3GiYWEedbTT0qnSxrCjsVbb7yKY1KE= github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c/go.mod h1:cNQ3dwVJtS5Hmnjxy6AgTPd0Inb3pW05ftPSX7NZO7Q= github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef h1:Ch6Q+AZUxDBCVqdkI8FSpFyZDtCVBc2VmejdNrm5rRQ= github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef/go.mod h1:nXTWP6+gD5+LUJ8krVhhoeHjvHTutPxMYl5SvkcnJNE= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic= github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= go.yaml.in/yaml/v4 v4.0.0-rc.5 h1:JVliQq9EGOYaTgMi+k8BhUJyqcGk4ZqeuiN1Cirba9c= diff --git a/packaging/windows/gosentry.rc b/packaging/windows/gosentry.rc index 18ded26..9a64b5c 100644 --- a/packaging/windows/gosentry.rc +++ b/packaging/windows/gosentry.rc @@ -1 +1,10 @@ +// The same multi-size .ico is embedded under two resource names on purpose: +// IDI_ICON1 - the lowest-id icon, which Windows Explorer / shortcuts use for the +// executable's file icon. +// GLFW_ICON - the name GLFW looks up to icon the window. Because run.go does NOT +// call a.SetIcon on Windows, GLFW falls back to this resource and +// selects the right frame per size (hand-tuned 16 for the titlebar, +// a larger frame for the taskbar). See assets/assets.go for the full +// cross-platform icon strategy. IDI_ICON1 ICON "assets/gosentry.ico" +GLFW_ICON ICON "assets/gosentry.ico" diff --git a/src/ui/run.go b/src/ui/run.go index f087f82..a1de1e9 100644 --- a/src/ui/run.go +++ b/src/ui/run.go @@ -1,6 +1,7 @@ package ui import ( + "runtime" "time" "gitea.mixdep.ru/mix/gosentry/assets" @@ -30,7 +31,20 @@ func Run(startInTray bool) { // A stable app ID lets Fyne persist desktop preferences consistently across // launches and gives tray/window integration a predictable identity. a := fyneapp.NewWithID(appID) - a.SetIcon(loadAppIcon()) + // On Windows the multi-resolution gosentry.ico (embedded under the GLFW_ICON + // resource name) drives the window: GLFW picks the hand-tuned 16x16 for the + // titlebar and the large artwork for the bigger taskbar icon — size-appropriate + // in a way a single Fyne SetIcon resource cannot be, since one PNG would be + // scaled to both sizes. + // + // Other platforms have no PE icon. Fyne's single SetIcon resource feeds + // _NET_WM_ICON, which the window manager renders small (~16px) in the titlebar, + // so use the hand-tuned small icon there to keep it crisp. The larger + // dock/launcher icon comes from the .desktop entry installed by + // InstallDesktopIcon, which uses the big artwork. + if runtime.GOOS != "windows" { + a.SetIcon(assets.IconSmall()) + } w := a.NewWindow("GoSentry " + app.Version) configureSystemTray(a, w) @@ -54,7 +68,3 @@ func Run(startInTray bool) { recordStartup(time.Since(started), true) a.Run() } - -func loadAppIcon() fyne.Resource { - return assets.Icon() -} diff --git a/src/ui/tray.go b/src/ui/tray.go index 012e5e7..cc70413 100644 --- a/src/ui/tray.go +++ b/src/ui/tray.go @@ -1,6 +1,10 @@ package ui import ( + "runtime" + + "gitea.mixdep.ru/mix/gosentry/assets" + "fyne.io/fyne/v2" fynedesktop "fyne.io/fyne/v2/driver/desktop" ) @@ -13,6 +17,17 @@ func configureSystemTray(a fyne.App, w fyne.Window) { return } + // The tray icon is platform-specific. The Windows notification area is + // ICO-native and renders at 16-24px, so a single 16x16 .ico frame keeps the + // hand-tuned glyph crisp with correct alpha. Linux/macOS trays + // (StatusNotifierItem) render much larger (22-48px) and take a PNG, so the + // full-size artwork scales down cleanly instead of upscaling the tiny 16x16. + if runtime.GOOS == "windows" { + desk.SetSystemTrayIcon(assets.IconSmallICO()) + } else { + desk.SetSystemTrayIcon(assets.Icon()) + } + // IsQuit marks this as the tray's quit item. Without it Fyne's // addMissingQuitForMenu appends a second, localized Quit (e.g. "Выход" on a // Russian system) because it only recognizes an existing quit by matching the