The jump list wears each profile's own icon
Explore this workspace.
Technical background
Upstream already offers your profiles when you right-click Tabby in the taskbar, but gave every entry the app's own icon, so it was a column of identical logos that told you nothing about what you were about to open. Font Awesome glyphs and inline SVG icons are rasterised into real .ico files the shell can read, and an entry is never blank and never dropped.
The problem
Right-clicking Tabby in the taskbar or the Start menu offers your profiles, and every entry carried the app's own icon — a column of identical Tabby logos that told you nothing about what you were about to open.
How it works
A profile icon is a Font Awesome class or an inline SVG document, and Windows' iconPath takes neither — it wants a file plus an index. So they are rasterised: the same conclusion the Windows Terminal maintainers reached, except that here the renderer already is a text-and-SVG rasterizer, so a canvas does it with no native code and no new dependency. .ico is written by hand, as a directory plus one PNG per size (16/24/32/48), which has been legal since Vista.
Details
- The glyph comes out of the stylesheet, not a table of codepoints. A probe element gets the class and
getComputedStyle(el, '::before').contentanswers with the character. That covers solid, regular and brands at once, survives a Font Awesome bump, and a class that resolves to no icon font is how an unknown one is detected. - The blank check is the only honest test. A font that had not loaded, an SVG whose paths fall outside its viewBox and a mistyped class all produce a perfectly well-formed file full of nothing. The canvas is scanned for a non-transparent pixel before anything is written. An entry is never dropped and never blank.
- The webfont has to be waited for.
font-display: blockmeans the CSS knows the family long before the file arrives, and a canvas silently substitutes rather than waiting — so the first rebuild after a cold start drew tofu. - An empty custom category makes the shell reject the whole call, not just that category — so on a profile where nothing had been opened yet, upstream's list was refused entire and no profiles appeared at all.
profile "<name>"was interpolated, not quoted. Profile names are free text; one containing a quote produced an entry that opened the wrong profile or none.- The colour is Windows'
SystemUsesLightTheme, notAppsUseLightThemeand not Tabby's own scheme — the jump list is taskbar chrome, and a monochrome glyph baked in the wrong colour is invisible against the flyout, which looks exactly like the blank tile this set out to fix. - Measured on the renderer thread, 28 profiles: a cold pass draws 15 distinct icons in about 1.1s (0.3s once the webfonts are warm), a warm pass draws none and costs nothing. The loop awaits I/O between icons, so that is not 1.1s of blocked event loop.
What this does not claim
- The jump list itself is upstream's.
dockMenu.service.tsalready built it and already calledsetJumpList; what every entry got wasiconPath: process.execPath. This is a fix to that call plus two add-only services, not a new feature. - Only one packaged Tabby has a jump list file on this machine, and its entries point at the fork's own slot rather than the installed app. Either the two share an app identity and the slot wrote last, or the installed app's write never landed. Not resolved — worth knowing before trusting a jump list to belong to the build you think it does.
- Dev-build entries are dead either way:
electron.exe profile "X"has no app path, so it starts nothing. Left alone, since it is upstream's shape and it now lands on an identity nothing else uses. - The reference fork's profile-icon caching does not apply here and was skipped deliberately: Tabby has no URL profile icons to cache.