mirror of
https://github.com/belsabbagh/dotfiles.git
synced 2026-04-11 09:36:46 +00:00
168 lines
4.6 KiB
QML
168 lines
4.6 KiB
QML
pragma Singleton
|
|
import QtQuick
|
|
import Quickshell
|
|
import qs.modules.functions
|
|
import qs.config
|
|
|
|
/*
|
|
This registry is only used to get app details for wm classes.
|
|
*/
|
|
|
|
Singleton {
|
|
id: registry
|
|
|
|
property var apps: []
|
|
property var classToIcon: ({})
|
|
property var desktopIdToIcon: ({})
|
|
property var nameToIcon: ({})
|
|
|
|
signal ready()
|
|
|
|
function iconForDesktopIcon(icon) {
|
|
if (!icon) return ""
|
|
|
|
// If it's already a URL, keep it
|
|
if (icon.startsWith("file://") || icon.startsWith("qrc:/"))
|
|
return icon
|
|
|
|
// Absolute filesystem path → convert to file URL
|
|
if (icon.startsWith("/"))
|
|
return "file://" + icon
|
|
|
|
// Otherwise treat as theme icon name
|
|
return Quickshell.iconPath(icon)
|
|
}
|
|
|
|
// Try very aggressive matching so the running app always gets the same icon as launcher
|
|
function iconForClass(id) {
|
|
if (!id) return ""
|
|
|
|
const lower = id.toLowerCase()
|
|
|
|
// direct hits first
|
|
if (classToIcon[lower])
|
|
return iconForDesktopIcon(classToIcon[lower])
|
|
|
|
if (desktopIdToIcon[lower])
|
|
return iconForDesktopIcon(desktopIdToIcon[lower])
|
|
|
|
if (nameToIcon[lower])
|
|
return iconForDesktopIcon(nameToIcon[lower])
|
|
|
|
// fuzzy contains match against wmClass map
|
|
for (let key in classToIcon) {
|
|
if (lower.includes(key) || key.includes(lower))
|
|
return iconForDesktopIcon(classToIcon[key])
|
|
}
|
|
|
|
// fuzzy against desktop ids
|
|
for (let key in desktopIdToIcon) {
|
|
if (lower.includes(key) || key.includes(lower))
|
|
return iconForDesktopIcon(desktopIdToIcon[key])
|
|
}
|
|
|
|
// fuzzy against names
|
|
for (let key in nameToIcon) {
|
|
if (lower.includes(key) || key.includes(lower))
|
|
return iconForDesktopIcon(nameToIcon[key])
|
|
}
|
|
|
|
// final fallback to theme resolution
|
|
const resolved = FileUtils.resolveIcon(id)
|
|
return iconForDesktopIcon(resolved)
|
|
}
|
|
|
|
// Extra helper: resolve icon using any metadata we might have (Hyprland, Niri, etc.)
|
|
function iconForAppMeta(meta) {
|
|
if (!meta) return Quickshell.iconPath("application-x-executable")
|
|
|
|
const candidates = [
|
|
meta.appId,
|
|
meta.class,
|
|
meta.initialClass,
|
|
meta.desktopId,
|
|
meta.title,
|
|
meta.name
|
|
]
|
|
|
|
for (let c of candidates) {
|
|
const icon = iconForClass(c)
|
|
if (icon !== "")
|
|
return icon
|
|
}
|
|
|
|
// fallback: try compositor provided icon name
|
|
if (meta.icon)
|
|
return iconForDesktopIcon(meta.icon)
|
|
|
|
// hard fallback icons (guaranteed to exist in most themes)
|
|
const fallbacks = [
|
|
"application-x-executable",
|
|
"application-default-icon",
|
|
"window"
|
|
]
|
|
|
|
for (let f of fallbacks) {
|
|
const resolved = Quickshell.iconPath(f)
|
|
if (resolved)
|
|
return resolved
|
|
}
|
|
|
|
return ""
|
|
}
|
|
|
|
function registerApp(displayName, comment, icon, exec, wmClass, desktopId) {
|
|
const entry = {
|
|
name: displayName,
|
|
comment: comment,
|
|
icon: icon,
|
|
exec: exec,
|
|
wmClass: wmClass,
|
|
desktopId: desktopId
|
|
}
|
|
|
|
apps.push(entry)
|
|
|
|
if (wmClass)
|
|
classToIcon[wmClass.toLowerCase()] = icon
|
|
|
|
if (desktopId)
|
|
desktopIdToIcon[desktopId.toLowerCase()] = icon
|
|
|
|
if (displayName)
|
|
nameToIcon[displayName.toLowerCase()] = icon
|
|
|
|
// Hard aliases for apps with messy WM_CLASS values
|
|
if (displayName.toLowerCase().includes("visual studio code") ||
|
|
icon.toLowerCase().includes("code")) {
|
|
|
|
classToIcon["code"] = icon
|
|
classToIcon["code-oss"] = icon
|
|
classToIcon["code-url-handler"] = icon
|
|
desktopIdToIcon["code.desktop"] = icon
|
|
desktopIdToIcon["code-oss.desktop"] = icon
|
|
}
|
|
}
|
|
|
|
function buildRegistry() {
|
|
const entries = DesktopEntries.applications.values
|
|
|
|
for (let entry of entries) {
|
|
if (entry.noDisplay)
|
|
continue
|
|
|
|
registry.registerApp(
|
|
entry.name || "",
|
|
entry.comment || "",
|
|
entry.icon || "",
|
|
entry.execString || "",
|
|
entry.startupWMClass || "",
|
|
entry.id || ""
|
|
)
|
|
}
|
|
|
|
registry.ready()
|
|
}
|
|
|
|
Component.onCompleted: buildRegistry()
|
|
} |