fix: resolve Flatpak exported application icons dynamically via AppLauncherService iconMap

This commit is contained in:
Sho 2026-08-01 23:36:21 +09:00
parent 8efe6d5198
commit 15d126780f
3 changed files with 66 additions and 6 deletions

View File

@ -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"

View File

@ -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) {}
} }

View File

@ -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):