Skip to content

fix(tray): stop padding every menubar style to the provider text width - #25

Open
Abhijith14 wants to merge 1 commit into
openusage-community:mainfrom
Abhijith14:fix/tray-icon-width-linux
Open

fix(tray): stop padding every menubar style to the provider text width#25
Abhijith14 wants to merge 1 commit into
openusage-community:mainfrom
Abhijith14:fix/tray-icon-width-linux

Conversation

@Abhijith14

Copy link
Copy Markdown

Problem

renderTrayBarsIcon pads the canvas of every style to getStableTrayImageWidthPx(), which is the width of a provider layout containing "100%":

const canvasWidth = Math.max(layout.width, getStableTrayImageWidthPx(sizePx))

At sizePx: 36 (dpr 2) that is 36 + 3 + 73 + 3 = 115, so all three styles publish a 115x36 image. Measured directly from the PNG the tray publishes (/run/user/1000/tray-icon/*.png) on GNOME 49 + Wayland with the AppIndicator/KStatusNotifier extension:

Style Image Aspect
provider 115 x 36 3.2 : 1
donut 115 x 36 3.2 : 1
bars 115 x 36 3.2 : 1

Panels scale tray icons by height and preserve aspect ratio, so a 3.2:1 image occupies roughly 3x the width of neighbouring icons. bars is the clearest case: its own layout is sizePx (square), and it is padded out to 115 purely to match a text width it never renders.

Change

donut and bars render no percent text, so their natural width is already constant. Only provider varies with content, so the stabilisation is scoped to it — preserving the stable anchor width added in #2 for the style that actually needs it.

Glyph metrics were also tuned for a much wider canvas:

  • fontSize 0.72 -> 0.48 of sizePx — 72% of icon height dominated the strip
  • pad 0.08 -> 0.06, textGap 0.08 -> 0.03
  • dropped the Math.round(sizePx * 1.5) floor on textAreaWidth, which reserved 54px for text measuring ~46px
  • donut draws logo and ring at 72% with a 12% gap, instead of two full sizePx cells that left the glyphs touching
  • bars gap 0.03 -> 0.08 with a 2px floor (see below)

Resulting widths at dpr 2: provider 115 -> 88, donut 115 -> 60, bars 115 -> 36.

Before / after

Rendered from both versions at real panel scale (24px), zoomed 250%. The shaded box is each image's actual bounds — transparent in reality — which is what makes the stock padding visible:

tray icon before and after

The bars gap

Separate from width: gap was Math.max(1, Math.round(sizePx * 0.03)) = 1px at sizePx 36. Scaled to a 24px panel that is 0.67px, so the bars visually merge into a block. Raising it to 0.08 with a 2px floor gives 5px bars separated by 3px gaps (2px on the panel):

bars gap before and after

Verified in the published PNG — four 5px bands with clean 3px gaps inside 36x36.

Known limitation

Changing the menubar icon style now requires an app restart to display correctly on GNOME. Because each style has a different width, the image dimensions change when the style changes, and the AppIndicator extension keeps showing the previous icon until the StatusNotifierItem is recreated. The published PNG is correct immediately; only the panel's rendering is stale.

Stock behaviour hid this by making every style the same width, which is also what made the icon oversized. I could not find an app-side way to force the panel to re-read within a session. Happy to take direction here — options might be recreating the tray item on style change, or keeping a uniform width behind a setting so users who prefer correct sizing can opt in.

Not affected in normal use: width only changes when the user changes style.

Testing

  • bun run build clean, full suite 1155 passed / 66 files
  • Existing width test rewritten: provider still stable across "9%" and "100%", while donut/bars assert their natural widths
  • Built and installed the RPM on Fedora 44 / GNOME 49 / Wayland and measured the published PNG for all three styles

Environment

OpenUsage 0.6.38, Fedora 44, GNOME Shell 49, Wayland, AppIndicator/KStatusNotifier, 1920x1080 @ scale 1.

renderTrayBarsIcon padded the canvas of every style to
getStableTrayImageWidthPx(), which is the width of a "provider" layout holding
"100%". On a GNOME/KStatusNotifier panel that made all three styles a 115x36
image at dpr 2 (measured from the PNG the tray publishes), i.e. a 3.2:1 strip
that renders roughly 3x wider than neighbouring tray icons, since panels scale
icons by height and preserve aspect ratio.

"donut" and "bars" render no percent text, so their natural width is already
constant; padding them to the provider width only made them wide. Scope the
stabilisation to "provider", the one style whose width varies with content, so
it keeps the stable anchor width added in openusage-community#2.

Also tighten the glyph metrics, which were sized for a much wider canvas:

- fontSize 0.72 -> 0.48 of sizePx (72% of icon height was dominating the strip)
- pad 0.08 -> 0.06, textGap 0.08 -> 0.03
- drop the Math.round(sizePx * 1.5) floor on textAreaWidth, which reserved
  54px for text that measures ~46px
- donut draws logo and ring at 72% with a 12% gap instead of two full sizePx
  cells, so the glyphs no longer touch
- bars gap 0.03 -> 0.08 with a 2px floor: at sizePx 36 the old 1px gap became
  0.67px once scaled to a 24px panel, so the bars visually merged

Resulting widths at dpr 2: provider 115 -> 88, donut 115 -> 60, bars 115 -> 36.
@github-actions github-actions Bot added the core label Jul 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant