Draw the third menu level reliably, on every application #16

Closed
geusebio wants to merge 2 commits from fix/third-level-menu-drawing into main
Owner

Fixes the platform's #844 — the third level of the menu (where the deployment gestures live) drew only under the first application; every later application's gesture submenu mapped as an empty strip, so its Activate/Confirm stop could not be clicked or keyboarded.

After — the second application's gesture, the row that used to be unreachable, now drawn (this capture is committed by the suite and is its regression sentinel):

after: Activate main draws under the second application

Before (attached below as before-empty-strip.png): the same walk step photographed the submenu as a ~50×12px empty strip — on gtk-sni-tray and on xfce4-panel, which is the second, real-desktop host #844 asked for before any fix, and what pins the bug on the app side rather than on the harness.

Mechanism

Upstream systray v1.12.2 clamps only the first GetLayout after a reset to depth 1 (its libdbusmenu-gtk3 workaround). That protects the top level and pushes the same race one level down: the full-depth refetch introduces levels two and three in one reply, and GTK hosts silently drop children whose parent GtkMenu containers don't exist yet.

The fix (house patch, marked in the file)

vendor/fyne.io/systray/systray_menu_unix.go: track which node ids the host has received; serve a node's children only once the node itself was served in an earlier reply; schedule a refresh whenever anything was withheld. Upstream's own cadence, per level instead of once. A fully-seen tree serves full-depth in one reply (steady-state retitles cost nothing), and branches appearing later are introduced progressively too. Worth offering upstream — follow-up.

Suite changes the fix unlocks

  • The applications scene photographs both gestures, Activate main under the second application deliberately — if the fix regresses, that walk step fails the run instead of committing a lie.
  • GOTO_DEPTH 2 → 3 (the menu's real depth; still refuses deeper walks).
  • HOST=xfce4-panel stays available as a manual knob for splitting the next drawing bug the same way.
  • Goldens re-blessed, manual regenerated from the run.

Verified

  • Empty strip reproduced on both hosts pre-patch, drawn correctly on both post-patch (same scene, same walk).
  • go vet clean, hack/lint.sh 0 issues, hack/coverage.sh at floors (patch is vendor-only Go; suite/scene changes carry the behavioural proof).
  • Full capture suite run end-to-end: every scene green against re-blessed goldens, manual regenerated with no drift.
Fixes the platform's [#844](https://git.grey.ooo/Grey.ooo/Someones.Computer/issues/844) — the third level of the menu (where the deployment gestures live) drew only under the first application; every later application's gesture submenu mapped as an empty strip, so its `Activate`/`Confirm stop` could not be clicked or keyboarded. **After** — the second application's gesture, the row that used to be unreachable, now drawn (this capture is committed by the suite and is its regression sentinel): ![after: Activate main draws under the second application](https://git.grey.ooo/Grey.ooo/someones.computer_tray/raw/branch/fix/third-level-menu-drawing/docs/images/linux/applications/activate-gesture.png) **Before** (attached below as `before-empty-strip.png`): the same walk step photographed the submenu as a ~50×12px empty strip — on gtk-sni-tray *and* on xfce4-panel, which is the second, real-desktop host #844 asked for before any fix, and what pins the bug on the app side rather than on the harness. ## Mechanism Upstream systray v1.12.2 clamps only the *first* `GetLayout` after a reset to depth 1 (its libdbusmenu-gtk3 workaround). That protects the top level and pushes the same race one level down: the full-depth refetch introduces levels two and three in one reply, and GTK hosts silently drop children whose parent GtkMenu containers don't exist yet. ## The fix (house patch, marked in the file) `vendor/fyne.io/systray/systray_menu_unix.go`: track which node ids the host has received; serve a node's children only once the node itself was served in an earlier reply; schedule a refresh whenever anything was withheld. Upstream's own cadence, per level instead of once. A fully-seen tree serves full-depth in one reply (steady-state retitles cost nothing), and branches appearing later are introduced progressively too. Worth offering upstream — follow-up. ## Suite changes the fix unlocks - The applications scene photographs both gestures, `Activate main` under the **second** application deliberately — if the fix regresses, that walk step fails the run instead of committing a lie. - `GOTO_DEPTH` 2 → 3 (the menu's real depth; still refuses deeper walks). - `HOST=xfce4-panel` stays available as a manual knob for splitting the next drawing bug the same way. - Goldens re-blessed, manual regenerated from the run. ## Verified - Empty strip reproduced on both hosts pre-patch, drawn correctly on both post-patch (same scene, same walk). - `go vet` clean, `hack/lint.sh` 0 issues, `hack/coverage.sh` at floors (patch is vendor-only Go; suite/scene changes carry the behavioural proof). - Full capture suite run end-to-end: every scene green against re-blessed goldens, manual regenerated with no drift.
The third level of the menu — where the deployment gestures live — drew
only under the first application; every later application's gesture
submenu mapped as an empty strip a few pixels tall. Reproduced in the
capture suite on gtk-sni-tray and confirmed on a second, real-desktop
host (xfce4-panel), so it was the app's exported dbusmenu at fault, not
the harness (platform #844's open question, now answered).

Mechanism: upstream systray v1.12.2 clamps only the *first* GetLayout
after a reset to depth 1 — protecting the top level and pushing the same
GTK-host race one level down. The full-depth refetch that follows
introduces levels two and three in one reply, and GTK hosts silently
drop children whose parent GtkMenu containers do not exist yet; which
branches survived was timing.

House patch, marked as such in the file: track which node ids the host
has received, serve a node's children only once the node itself has been
served, and schedule a refresh whenever something was withheld — the
upstream workaround's own cadence, applied per level instead of once. A
fully-seen tree serves at full depth in one reply, so steady-state
retitles cost nothing, and a branch that appears later is introduced
progressively too.
Photograph the deployment gestures, on both applications
All checks were successful
CI / build (pull_request) Successful in 2m21s
CI / captures (pull_request) Successful in 9m56s
d8988bba83
With the dbusmenu house patch in place the third level draws reliably,
so the capture suite stops working around platform #844 and starts
guarding against it:

- The applications scene walks to `Confirm stop main` under the first
  application and `Activate main` under the *second* — the row that used
  to be unreachable. The second-application capture is the regression
  sentinel: if the level-introduction fix ever regresses, that walk step
  fails the suite instead of photographing an empty strip.
- scene.py's GOTO_DEPTH guard rises from 2 to 3 — the menu's real depth —
  and keeps refusing deeper walks, which would photograph the fourth
  level the stack still does not have.
- The harness gains HOST=xfce4-panel, the second real-desktop SNI host
  that pinned #844 on the app side. A manual knob, not a second suite
  run: one host per run, doubled assertion buys nothing.
- Goldens re-blessed and the manual regenerated from the run; the
  limitation paragraph in the applications scene becomes the story of
  the sentinel.
geusebio changed title from WIP: Draw the third menu level reliably, on every application to Draw the third menu level reliably, on every application 2026-08-23 04:36:35 +00:00
geusebio closed this pull request 2026-09-07 16:16:21 +00:00
All checks were successful
CI / build (pull_request) Successful in 2m21s
CI / captures (pull_request) Successful in 9m56s

Pull request closed

Sign in to join this conversation.
No reviewers
No labels
in-progress
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Grey.ooo/someones.computer_tray!16
No description provided.