diff options
Diffstat (limited to 'internal/notify/classify.go')
| -rw-r--r-- | internal/notify/classify.go | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/internal/notify/classify.go b/internal/notify/classify.go new file mode 100644 index 0000000..c7e0dc8 --- /dev/null +++ b/internal/notify/classify.go @@ -0,0 +1,58 @@ +// Copyright (C) 2026 Danilo M. <danix@danix.xyz> +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +package notify + +import ( + "image" + _ "image/gif" + _ "image/jpeg" + _ "image/png" + "os" + "path/filepath" + "strings" +) + +// IconMaxPixels is the long-side bound below which a content image is treated +// as an icon rather than a preview. A screenshot is far larger; a themed icon +// or an application logo is not. +const IconMaxPixels = 128 + +// IsIconImage reports whether a content image should fill the app-icon slot +// instead of the large preview. Clients disagree about where the icon goes: +// kitty, mail and opencode send it through the content-image hint, while a +// screenshot uses the same hint. The hint is one of the icon forms when the +// client sent a theme name, when the resolved file is an SVG, or when a raster +// is small on both sides. raw is the value before ResolveIcon; resolved is the +// path it resolved to. +func IsIconImage(raw, resolved string) bool { + if raw != "" && !strings.Contains(raw, "/") && !strings.HasPrefix(raw, "file:") { + return true + } + if resolved == "" { + return false + } + if strings.EqualFold(filepath.Ext(resolved), ".svg") { + return true + } + f, err := os.Open(resolved) + if err != nil { + return false + } + defer f.Close() + cfg, _, err := image.DecodeConfig(f) + if err != nil { + // A format without a registered decoder is not something we can size, + // so it stays a preview rather than being silently dropped. + return false + } + return cfg.Width <= IconMaxPixels && cfg.Height <= IconMaxPixels +} |
