73 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
			
		
		
	
	
			73 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
import Apps from "gi://AstalApps";
 | 
						|
import AstalHyprland from "gi://AstalHyprland";
 | 
						|
 | 
						|
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<string, string>, executables: {} as Record<string, string> },
 | 
						|
);
 | 
						|
 | 
						|
export function getIconName(client: AstalHyprland.Client | null | undefined) {
 | 
						|
    if (!client) return "";
 | 
						|
 | 
						|
    // try a bunch of fields (snake_case and camelCase variants)
 | 
						|
    const possibleKeys = [
 | 
						|
        // common client properties (snake_case)
 | 
						|
        (client as any).wm_class,
 | 
						|
        (client as any).initial_class,
 | 
						|
        (client as any).executable,
 | 
						|
        // camelCase variants (some bindings expose these)
 | 
						|
        (client as any).class,
 | 
						|
        (client as any).initialClass,
 | 
						|
        (client as any).initialTitle,
 | 
						|
        (client as any).title,
 | 
						|
        (client as any).name,
 | 
						|
    ].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 for this client's canonical class (prefer wm_class or class)
 | 
						|
            const cacheKey = (client as any).wm_class ?? (client as any).class ?? (client as any).name ?? 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.)
 | 
						|
    const searchStrings = [
 | 
						|
        (client as any).title,
 | 
						|
        (client as any).initialTitle,
 | 
						|
        (client as any).initial_class,
 | 
						|
        (client as any).initialClass,
 | 
						|
        (client as any).wm_class,
 | 
						|
        (client as any).class,
 | 
						|
        (client as any).name,
 | 
						|
    ].filter(Boolean) as string[];
 | 
						|
 | 
						|
    for (const s of searchStrings) {
 | 
						|
        const matchKey = Object.keys(app_icons.classOrNames).find((key) => key.includes(s));
 | 
						|
        if (matchKey) {
 | 
						|
            const icon = app_icons.classOrNames[matchKey];
 | 
						|
            const cacheKey = (client as any).wm_class ?? (client as any).class ?? (client as any).name ?? s;
 | 
						|
            app_icons.classOrNames[cacheKey] = icon;
 | 
						|
            return icon;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    // nothing found — cache empty string so we don't repeat work
 | 
						|
    const cacheKey = (client as any).wm_class ?? (client as any).class ?? (client as any).name ?? "";
 | 
						|
    if (cacheKey) app_icons.classOrNames[cacheKey] = "";
 | 
						|
    return "";
 | 
						|
}
 |