fix: resolve Flatpak exported application icons dynamically via AppLauncherService iconMap
This commit is contained in:
parent
8efe6d5198
commit
15d126780f
@ -368,7 +368,15 @@ Item {
|
|||||||
if (name.startsWith("file://")) return name
|
if (name.startsWith("file://")) return name
|
||||||
if (name.startsWith("/")) return "file://" + name
|
if (name.startsWith("/")) return "file://" + name
|
||||||
|
|
||||||
let clean = name.toLowerCase()
|
let clean = name.toLowerCase().replace(/\.desktop$/, "")
|
||||||
|
|
||||||
|
// 1. Dynamic lookup in AppLauncherService iconMap (resolves Flatpak & native app icons dynamically!)
|
||||||
|
if (AppLauncherService.iconMap && AppLauncherService.iconMap[clean]) {
|
||||||
|
let mapped = AppLauncherService.iconMap[clean]
|
||||||
|
return mapped.startsWith("file://") ? mapped : "file://" + mapped
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Hardcoded fallback overrides for common system apps
|
||||||
let themeDir = Theme.iconTheme
|
let themeDir = Theme.iconTheme
|
||||||
if (clean.includes("alacritty")) return "file:///usr/share/icons/" + themeDir + "/32x32/apps/Alacritty.svg"
|
if (clean.includes("alacritty")) return "file:///usr/share/icons/" + themeDir + "/32x32/apps/Alacritty.svg"
|
||||||
if (clean.includes("dolphin")) return "file:///usr/share/icons/" + themeDir + "/32x32/apps/org.kde.dolphin.svg"
|
if (clean.includes("dolphin")) return "file:///usr/share/icons/" + themeDir + "/32x32/apps/org.kde.dolphin.svg"
|
||||||
|
|||||||
@ -97,6 +97,7 @@ Item {
|
|||||||
|
|
||||||
// Fallback icon path from active system icon theme
|
// Fallback icon path from active system icon theme
|
||||||
property string fallbackIconPath: ""
|
property string fallbackIconPath: ""
|
||||||
|
property var iconMap: ({})
|
||||||
|
|
||||||
Process { id: launchProc }
|
Process { id: launchProc }
|
||||||
|
|
||||||
@ -111,7 +112,23 @@ Item {
|
|||||||
let parsed = JSON.parse(data.trim())
|
let parsed = JSON.parse(data.trim())
|
||||||
if (parsed && typeof parsed === "object") {
|
if (parsed && typeof parsed === "object") {
|
||||||
if (parsed.fallback) root.fallbackIconPath = parsed.fallback
|
if (parsed.fallback) root.fallbackIconPath = parsed.fallback
|
||||||
if (parsed.apps && Array.isArray(parsed.apps)) root.allApps = parsed.apps
|
if (parsed.apps && Array.isArray(parsed.apps)) {
|
||||||
|
root.allApps = parsed.apps
|
||||||
|
let newMap = {}
|
||||||
|
for (let i = 0; i < parsed.apps.length; i++) {
|
||||||
|
let a = parsed.apps[i]
|
||||||
|
if (a.icon) {
|
||||||
|
if (a.id) newMap[a.id.toLowerCase()] = a.icon
|
||||||
|
if (a.id) newMap[a.id.replace(/\.desktop$/, "").toLowerCase()] = a.icon
|
||||||
|
if (a.name) newMap[a.name.toLowerCase()] = a.icon
|
||||||
|
if (a.exec) {
|
||||||
|
let cleanExec = a.exec.replace(/%[a-zA-Z]/g, "").trim().split(/\s+/)[0]
|
||||||
|
newMap[cleanExec.toLowerCase()] = a.icon
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
root.iconMap = newMap
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -55,11 +55,16 @@ def parse_desktop_apps():
|
|||||||
if fallback_theme not in themes_to_search:
|
if fallback_theme not in themes_to_search:
|
||||||
themes_to_search.append(fallback_theme)
|
themes_to_search.append(fallback_theme)
|
||||||
|
|
||||||
search_dirs = []
|
bases = [
|
||||||
bases = [os.path.expanduser('~/.local/share/icons'), '/usr/share/icons']
|
os.path.expanduser('~/.local/share/icons'),
|
||||||
|
os.path.expanduser('~/.local/share/flatpak/exports/share/icons'),
|
||||||
|
'/var/lib/flatpak/exports/share/icons',
|
||||||
|
'/usr/local/share/icons',
|
||||||
|
'/usr/share/icons'
|
||||||
|
]
|
||||||
subdirs = [
|
subdirs = [
|
||||||
'64x64/apps', '48x48/apps', 'scalable/apps', '128x128/apps', '256x256/apps', '32x32/apps',
|
'64x64/apps', '48x48/apps', 'scalable/apps', '128x128/apps', '256x256/apps', '32x32/apps',
|
||||||
'64x64@2x/apps', '48x48@2x/apps', 'apps/64', 'apps/48', 'apps/scalable', 'apps'
|
'64x64@2x/apps', '48x48@2x/apps', 'apps/64', 'apps/48', 'apps/scalable', 'apps', ''
|
||||||
]
|
]
|
||||||
|
|
||||||
for t in themes_to_search:
|
for t in themes_to_search:
|
||||||
@ -69,7 +74,19 @@ def parse_desktop_apps():
|
|||||||
if os.path.exists(d) and d not in search_dirs:
|
if os.path.exists(d) and d not in search_dirs:
|
||||||
search_dirs.append(d)
|
search_dirs.append(d)
|
||||||
|
|
||||||
search_dirs.append('/usr/share/pixmaps')
|
# Also add direct Flatpak export directories without subdirs
|
||||||
|
for fp_dir in [
|
||||||
|
os.path.expanduser('~/.local/share/flatpak/exports/share/icons/hicolor/scalable/apps'),
|
||||||
|
os.path.expanduser('~/.local/share/flatpak/exports/share/icons/hicolor/128x128/apps'),
|
||||||
|
os.path.expanduser('~/.local/share/flatpak/exports/share/icons/hicolor/64x64/apps'),
|
||||||
|
'/var/lib/flatpak/exports/share/icons/hicolor/scalable/apps',
|
||||||
|
'/var/lib/flatpak/exports/share/icons/hicolor/128x128/apps',
|
||||||
|
'/var/lib/flatpak/exports/share/icons/hicolor/64x64/apps',
|
||||||
|
'/usr/share/pixmaps'
|
||||||
|
]:
|
||||||
|
if os.path.exists(fp_dir) and fp_dir not in search_dirs:
|
||||||
|
search_dirs.append(fp_dir)
|
||||||
|
|
||||||
EXTS = ['.svg', '.png', '.xpm']
|
EXTS = ['.svg', '.png', '.xpm']
|
||||||
|
|
||||||
def resolve_fallback():
|
def resolve_fallback():
|
||||||
@ -88,6 +105,7 @@ def parse_desktop_apps():
|
|||||||
return fallback_path
|
return fallback_path
|
||||||
if os.path.isabs(name) and os.path.exists(name):
|
if os.path.isabs(name) and os.path.exists(name):
|
||||||
return name
|
return name
|
||||||
|
|
||||||
for d in search_dirs:
|
for d in search_dirs:
|
||||||
for ext in EXTS:
|
for ext in EXTS:
|
||||||
p = os.path.join(d, name + ext)
|
p = os.path.join(d, name + ext)
|
||||||
@ -97,6 +115,23 @@ def parse_desktop_apps():
|
|||||||
p2 = os.path.join(d, name)
|
p2 = os.path.join(d, name)
|
||||||
if os.path.exists(p2):
|
if os.path.exists(p2):
|
||||||
return p2
|
return p2
|
||||||
|
|
||||||
|
# Substring / Desktop ID matching fallback (essential for Flatpak icons like io.github.zen_browser.zen)
|
||||||
|
clean_name = name.lower()
|
||||||
|
if clean_name.endswith('.png') or clean_name.endswith('.svg') or clean_name.endswith('.xpm'):
|
||||||
|
clean_name = os.path.splitext(clean_name)[0]
|
||||||
|
|
||||||
|
for d in search_dirs:
|
||||||
|
if not os.path.exists(d):
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
for f in os.scandir(d):
|
||||||
|
fn_lower = f.name.lower()
|
||||||
|
if clean_name in fn_lower or fn_lower.startswith(clean_name):
|
||||||
|
return f.path
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
return fallback_path
|
return fallback_path
|
||||||
|
|
||||||
def parse_desktop(f):
|
def parse_desktop(f):
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user