aboutsummaryrefslogtreecommitdiffstats
path: root/internal/notify/icons.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/notify/icons.go')
-rw-r--r--internal/notify/icons.go96
1 files changed, 82 insertions, 14 deletions
diff --git a/internal/notify/icons.go b/internal/notify/icons.go
index b874581..d68c171 100644
--- a/internal/notify/icons.go
+++ b/internal/notify/icons.go
@@ -95,22 +95,12 @@ func lookupThemeIcon(name, theme string) string {
return ""
}
-// findInTheme prefers scalable then the largest raster under apps/.
+// findInTheme prefers scalable, then the largest raster. It searches both the
+// KDE/Papirus apps/<size> layout and the freedesktop <size>/apps layout.
func findInTheme(base, name string) string {
- sizes := []string{"scalable"}
- matches, _ := filepath.Glob(filepath.Join(base, "apps", "[0-9]*"))
- for _, m := range matches {
- sizes = append(sizes, filepath.Base(m))
- }
- numeric := sizes[1:]
- sort.Slice(numeric, func(i, j int) bool {
- a, _ := strconv.Atoi(strings.TrimSuffix(numeric[i], "@2x"))
- b, _ := strconv.Atoi(strings.TrimSuffix(numeric[j], "@2x"))
- return a > b
- })
- for _, size := range sizes {
+ for _, dir := range themeSizeDirs(base) {
for _, ext := range []string{"svg", "png", "xpm"} {
- p := filepath.Join(base, "apps", size, name+"."+ext)
+ p := filepath.Join(dir, name+"."+ext)
if fileExists(p) {
return p
}
@@ -119,6 +109,84 @@ func findInTheme(base, name string) string {
return ""
}
+// sizeDir is one candidate icon directory inside a theme.
+type sizeDir struct {
+ path string
+ scalable bool
+ size int
+ name string
+}
+
+// themeSizeDirs lists a theme's candidate directories, scalable first, then
+// rasters by effective pixel size descending, name as a deterministic
+// tie-break. Both icon layouts are covered.
+func themeSizeDirs(base string) []string {
+ var found []sizeDir
+ add := func(name, path string) {
+ if name == "scalable" {
+ found = append(found, sizeDir{path: path, scalable: true, name: name})
+ return
+ }
+ if n, ok := pixelSize(name); ok {
+ found = append(found, sizeDir{path: path, size: n, name: name})
+ }
+ }
+ // KDE/Papirus: apps/<size>/
+ if entries, err := os.ReadDir(filepath.Join(base, "apps")); err == nil {
+ for _, e := range entries {
+ if e.IsDir() {
+ add(e.Name(), filepath.Join(base, "apps", e.Name()))
+ }
+ }
+ }
+ // freedesktop: <size>/apps/
+ if entries, err := os.ReadDir(base); err == nil {
+ for _, e := range entries {
+ if !e.IsDir() {
+ continue
+ }
+ apps := filepath.Join(base, e.Name(), "apps")
+ if info, err := os.Stat(apps); err == nil && info.IsDir() {
+ add(e.Name(), apps)
+ }
+ }
+ }
+ sort.Slice(found, func(i, j int) bool {
+ a, b := found[i], found[j]
+ if a.scalable != b.scalable {
+ return a.scalable
+ }
+ if a.size != b.size {
+ return a.size > b.size
+ }
+ return a.name < b.name
+ })
+ dirs := make([]string, len(found))
+ for i, d := range found {
+ dirs[i] = d.path
+ }
+ return dirs
+}
+
+// pixelSize turns a size directory name into its effective pixel size. "48"
+// and "48x48" styles are recognised, and a trailing @2x doubles the size.
+func pixelSize(name string) (int, bool) {
+ s := name
+ mult := 1
+ if strings.HasSuffix(s, "@2x") {
+ s = strings.TrimSuffix(s, "@2x")
+ mult = 2
+ }
+ if i := strings.IndexByte(s, 'x'); i >= 0 {
+ s = s[:i]
+ }
+ n, err := strconv.Atoi(s)
+ if err != nil {
+ return 0, false
+ }
+ return n * mult, true
+}
+
func inheritsOf(base string) string {
v := iniValue(filepath.Join(base, "index.theme"), "Inherits")
if i := strings.IndexByte(v, ','); i >= 0 {