fix(icons): resolve window icons via StartupWMClass desktop entry field#175
Open
ImIvanGil wants to merge 1 commit into
Open
fix(icons): resolve window icons via StartupWMClass desktop entry field#175ImIvanGil wants to merge 1 commit into
ImIvanGil wants to merge 1 commit into
Conversation
`getIconFromDesktopEntry()` matched window class against three .desktop
fields — `Exec[0]`, `Name`, and `Keywords` — but ignored `StartupWMClass`,
the field designed precisely for this matching.
Concrete example: Brave (`/usr/share/applications/brave-browser.desktop`)
has:
Name=Brave
Exec=brave %U
StartupWMClass=brave-browser
Icon=brave-desktop
The window's class on Wayland is `brave-browser`. None of the matched
fields equal `brave-browser` (Name=Brave → "brave", Exec[0]="brave"),
so icon resolution fell through to `image-missing`, and Brave showed
a generic icon in the workspace indicator.
Fix: prepend a `app.startupClass === normalizedClassName` check. Quickshell's
DesktopEntry exposes `startupClass` as a first-class property, so this is
trivial.
This is a generic improvement — any .desktop entry that uses
StartupWMClass to disambiguate its window class from its Exec/Name now
resolves correctly. Other affected apps in the wild: Spotify
(`spotify.desktop` → StartupWMClass=Spotify), Steam, Slack, Discord
flatpak variants, and most Electron apps with custom WMClass.
This was referenced May 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Some apps show a generic / missing icon in the workspaces indicator and other icon-resolving widgets, even though their
.desktopfile declares anIcon=correctly. Most visible example: Brave.Why it happens
AppSearch.getIconFromDesktopEntry()matches the window class against three.desktopfields:Exec[0](the executable basename)NameKeywords[]But it does not check
StartupWMClass, which is the field freedesktop defined exactly for this purpose — the bridge between window class and.desktopentry.Brave's
/usr/share/applications/brave-browser.desktop:The window's class on Wayland is
brave-browser. None ofBrave(Name),brave(Exec[0]), orKeywordsequalbrave-browser, so the function returnsnullandguessIconfalls through toimage-missing.Fix
Add
app.startupClass === normalizedClassNameas the first check ingetIconFromDesktopEntry(). Quickshell'sDesktopEntryalready exposesstartupClassas a first-class property — no new dependencies, no schema changes.Impact beyond Brave
Any
.desktopentry that usesStartupWMClassto disambiguate its window class from itsExec/Namenow resolves correctly. Other commonly-affected apps:spotify.desktop→StartupWMClass=Spotify,Exec=spotify)code-url-handlerand friends (also why those have entries insubstitutions)The
substitutionstable inAppSearch.qml(line 107) is a manual workaround that this fix obviates for many of those entries. Could clean some of those up in a follow-up if you want, but kept this PR focused on the root-cause fix.Testing
Before: Brave showed a generic / leaf icon in the workspaces indicator.
After: Brave shows its proper icon (
brave-desktop).GUI apps that don't use
StartupWMClass(or whereStartupWMClassmatches a field already checked) behave identically — the new check is non-destructive and short-circuits to the existing branches when it doesn't match.Diff stats