Skip to content

fix(linux): keep tray menu labels from rendering blank - #574

Merged
xiufengsun merged 1 commit into
xiufengsun:mainfrom
csmashe:fix/linux-tray-menu-labels
Sep 4, 2026
Merged

fix(linux): keep tray menu labels from rendering blank#574
xiufengsun merged 1 commit into
xiufengsun:mainfrom
csmashe:fix/linux-tray-menu-labels

Conversation

@csmashe

@csmashe csmashe commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Problem

On Linux the tray menu intermittently renders as blank rows — the two entries are there, correctly sized, with no text. Restarting the app sometimes fixes it, sometimes not.

Measured on GNOME 50.3 / Wayland / Fedora, with dbus-monitor on interface='com.canonical.dbusmenu': 5 of 6 launches never fetched the labels at all.

Cause

Two independent halves that combine badly.

Our side — libappindicator exports the menu in two passes: the structure first, then the item properties ~47ms later as ItemsPropertiesUpdated plus a second LayoutUpdated. This happens on every launch, once the GTK main loop starts:

854.154899  LayoutUpdated            <- pass 1, structure
854.186861  GetLayout                <- shell reads it
854.201529  ItemsPropertiesUpdated   <- pass 2, the labels
854.201543  LayoutUpdated
854.203867  GetLayout                <- shell reads it again
            (no GetGroupProperties — labels never fetched)

The extension side (appindicatorsupport@rgcjonas.gmail.com/dbusMenu.js) cannot absorb that:

  • GetLayout deliberately requests only type and children-display, never label. Labels come from a separate GetGroupProperties scheduled on an idle callback.
  • A new LayoutUpdated cancels the previous update's cancellable (_layoutUpdateUpdateAsync), killing that pending fetch.
  • The re-run finds the item ids already in this._items and early-returns before _requestProperties (line 420).
  • The ItemsPropertiesUpdated that did carry the labels arrived before the extension had created those items, so _onPropertiesUpdated dropped it (if (!item) return).

The label property therefore never reaches the shell, and its default is '' — blank rows. Whether a given launch wins or loses the race is what makes it intermittent.

Fix

Publish a freshly built menu 1.5s after startup, once the export storm is over. A new menu gets new dbusmenu item ids, so the extension has to create the items from scratch and fetch their properties, and nothing is racing the request that time.

This is a mitigation for a race in the GNOME extension, not a fix for the extension itself — but it is the only side we control.

Testing

  • cargo test, cargo fmt --check — pass.
  • Instrumented 6 unpatched launches (5/6 blank) and 8 patched launches on the same machine, comparing the dbusmenu traffic.
  • Ran the patched build interactively on GNOME 50 / Wayland: the menu has not come up blank since.

Summary by CodeRabbit

  • Bug Fixes
    • Improved tray menu reliability on GNOME-based Linux desktops.
    • Prevented tray menu labels from appearing blank after the application starts.
    • Refined tray menu refresh behavior to ensure labels are displayed correctly.

libappindicator exports the menu in two passes: the structure first,
then the item properties ~50ms later as `ItemsPropertiesUpdated` plus a
second `LayoutUpdated`. GNOME's AppIndicator extension cannot absorb
that. Its `GetLayout` deliberately asks for `type`/`children-display`
only and fetches labels separately on an idle callback; the second
`LayoutUpdated` cancels that pending fetch, and the re-run finds the
item ids already known and skips re-requesting them. The signal that
did carry the labels arrived before the extension had created those
items, so it was dropped. The labels then keep the extension's default
empty string and the menu renders as blank rows — 5 of 6 launches on a
GNOME 50 / Wayland box.

Publish a freshly built menu once startup has quiesced. New item ids
force the extension to create the items again and fetch their
properties, with nothing racing the request that time.
@csmashe
csmashe requested a review from xiufengsun as a code owner September 3, 2026 15:58
@coderabbitai

coderabbitai Bot commented Sep 3, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Team

Run ID: 75c7aac5-f262-450e-83ad-682570e18f9c

📥 Commits

Reviewing files that changed from the base of the PR and between 13bca6e and 54f6485.

📒 Files selected for processing (1)
  • TokenTrackerLinux/src-tauri/src/tray.rs

Included review availability: Your plan provides up to 4 included reviews per hour; 2 remain after this review.


📝 Walkthrough

Walkthrough

The tray module now centralizes menu construction, assigns a named tray identifier, and republishes a rebuilt menu after a 1500 ms delay through the main thread.

Changes

Tray menu republishing

Layer / File(s) Summary
Menu construction and republish helpers
TokenTrackerLinux/src-tauri/src/tray.rs
The module defines shared tray constants, builds menu items through build_menu, and republishes the menu after a background delay.
Tray installation integration
TokenTrackerLinux/src-tauri/src/tray.rs
install uses build_menu, assigns TRAY_ID, and calls republish_menu after creating the tray icon.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to 54f64

This change rebuilds and republishes the Linux tray menu shortly after startup to prevent blank menu labels. No current merge-blocking risk remains.

Sequence Diagram(s)

sequenceDiagram
  participant install
  participant republish_menu
  participant BackgroundThread
  participant MainThread
  participant TrayIcon
  install->>republish_menu: schedule menu republish
  republish_menu->>BackgroundThread: sleep 1500 ms
  BackgroundThread->>MainThread: dispatch menu refresh
  MainThread->>TrayIcon: rebuild and set menu
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 1 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the Linux tray menu label fix, which is the main change in the pull request.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@xiufengsun xiufengsun left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed at exact head 54f6485. The delayed menu rebuild is scoped to the Linux tray startup race, preserves the existing item handlers, integrates cleanly with current main, and the exact-head Linux/full CI and CodeQL checks are green.

@xiufengsun
xiufengsun merged commit 7a7e491 into xiufengsun:main Sep 4, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants