import Apps from "gi://AstalApps"; const app_icons = new Apps.Apps().list.reduce( (acc, app) => { // keys from AstalApps entries are typically wm_class (snake_case) or name const key = app.wm_class ?? app.name; if (key) { acc.classOrNames[key] = app.icon_name; } if (app.executable) { acc.executables[app.executable] = app.icon_name; } return acc; }, { classOrNames: {} as Record, executables: {} as Record }, ); export function getIconName(app_id: string | null | undefined, title: string | null | undefined) { if (!app_id && !title) return ""; // try fields matching Niri outputs const possibleKeys = [ app_id, title ].filter(Boolean) as string[]; // 1) direct exact match for (const k of possibleKeys) { const icon = app_icons.classOrNames[k] ?? app_icons.executables[k]; if (icon) { // cache the mapping const cacheKey = app_id ?? title ?? k; app_icons.classOrNames[cacheKey] = icon; return icon; } } // 2) fuzzy match: see if any stored key includes any of the client strings (title, name, etc.) for (const s of possibleKeys) { const matchKey = Object.keys(app_icons.classOrNames).find((key) => key.includes(s)); if (matchKey) { const icon = app_icons.classOrNames[matchKey]; const cacheKey = app_id ?? title ?? s; app_icons.classOrNames[cacheKey] = icon; return icon; } } // nothing found — cache empty string so we don't repeat work const cacheKey = app_id ?? title ?? ""; if (cacheKey) app_icons.classOrNames[cacheKey] = ""; return ""; }