fix(tray): apply menu property updates and activate the correct radio item - #1583
Conversation
|
PR description written using AI, but I've analysed and tested the code myself. |
|
Pushed one more commit: While soak-testing this branch as my daily bar I found Measured with a scripted SNI app emitting 6000 toggle-state property updates (each one a rebuild): pre-fix RSS grew ~11 MB and accelerating; with the fix it stays flat (+0.17 MB total). |
|
The repo's AI policy clearly disallows vibe coding, and I would say this definitely qualifies as that. Since the damage is already done, I'm not going to close it and I'll look to merge this. Just don't expect a quick review because I've got to unpick a lot of fluff, and don't expect to credited. |
|
Fair - and to be fully straight: yes, the code was AI-assisted. For what it's worth: I'd already fixed this for my own use - upstreaming it was meant as a thank-you for Ironbar, not a demand on your time. I tried to put more effort into the PR than the review would cost; I can see the extra prose achieved the opposite, and that's mine to fix. The diagnosis and testing were mine and I can answer for every line, so one ask: judge the code as code, at whatever pace suits you, or not at all - no obligation. If it helps, I'll strip the comments and tests down to house style and split the leak fix into its own PR - say the word. No expectations on credit either. |
3748b4c to
fddd193
Compare
|
This PR has been automatically detected as being AI slop. If you believe this is incorrect, please reply and it will be manually reviewed. |
|
Cool, that works |
Two related tray menu fixes which together make menus with radio groups work
end-to-end. The first implements the menu update bug you diagnosed in #1538;
the second fixes a wrong-id activation bug in the radio path that the first
fix made observable.
1. Apply
MenuDiffupdates so menus repaint after a clickThe tray interface handled
UpdateEvent::Menu(full replace) andMenuConnect, but onlytrace!'dUpdateEvent::MenuDiffand dropped it.MenuDiffis how the standardcom.canonical.dbusmenuItemsPropertiesUpdatedsignal reaches the module, so every post-clickproperty change — a moved radio toggle-state, a refreshed label, an
enabled/disabled entry — was discarded and the widget kept rendering the
previous state. This is the case you described in #1538:
It affects any conforming tray implementation, not one toolkit: Qt,
libdbusmenu and ksni all report property-only changes this way and only
escalate to
LayoutUpdatedwhen the structure changes.Why apply the diffs in ironbar rather than in
system-tray: the crate'sown
apply_menu_diffswalks only the top-level submenus and consumes diffspositionally (
next_if(|d| d.id == item.id)), so nested groups are neverpatched — but fixing that alone wouldn't be enough, because ironbar dropped
the event before the widget could repaint. The widget side needs a retained
menu model and a rebuild regardless, so
TrayMenunow keeps the last fullmenu model and applies diffs itself, matching by global item id at any depth
(
src/modules/tray/diff.rs, unit-tested including the nested-radio case).Happy to send a recursion fix for the crate's
apply_menu_diffsas afollow-up if you'd take it.
2. Activate the clicked radio item, not the group's first
Clicking any radio item sent one fixed dbusmenu id, so the application either
did nothing or silently re-applied a setting it already had. Two defects
combined:
as_menunumbered radio groups with a counterlocal to the function, but recursed into each submenu carrying the same
SimpleActionGroup. The counter restarted per submenu while the namespacedid not, so every submenu's first group was named
action_radio_1—and
ActionMap::add_actionreplaces on a duplicate name, leaving onesurviving action driven by every radio item in the menu.
whole group, so the clicked option is identified only by the target string
in the new state. The handler was
move |_, _| activate(.., id), using anid captured at build time — the group's first item. On its own this breaks
every group of more than one option, even without collisions.
The fix names the action from the group's first dbusmenu id (unique
menu-wide, so collision-free by construction) and reads the clicked id back
out of the change-state payload. The group's state is also parked on the item
the application reports as selected, so the radio mark renders on the actually
active option instead of always the first.
Standard and checkmark items were never affected — they use the globally
unique
action_{id}path — which is why tray menus looked mostly functionaland only radio groups misbehaved.
Testing
update, unknown-id no-op) and for the radio action contract (action-name
uniqueness across groups, target string round-tripping the item id).
submenus. Before: every click in every group sent id 19 (confirmed via
busctl … GetLayoutagainst the app's real menu ids plus trace logging ofthe outgoing
ActivateRequest). After: the sent id varies per click,selections apply across different groups and both options within a group,
and the menu repaints to show the moved selection without reopening.
cargo fmt --check,cargo clippy --all-targets(0 warnings), builds with--no-default-features,cargo testall pass.Refs #1538 — this implements the menu update part; the scroll-event and
libappindicator points from that issue are out of scope here.