Visitar URL original
fix(tray): only rebuild the Linux tray menu when its content changed by EagleEyeElite · Pull Request #11023 · nextcloud/desktop · GitHub
Skip to content

fix(tray): only rebuild the Linux tray menu when its content changed - #11023

Open
EagleEyeElite wants to merge 1 commit into
nextcloud:masterfrom
EagleEyeElite:fix/tray-menu-rebuild
Open

EagleEyeElite wants to merge 1 commit into
nextcloud:masterfrom
EagleEyeElite:fix/tray-menu-rebuild

Conversation

@EagleEyeElite

@EagleEyeElite EagleEyeElite commented Oct 6, 2026 •

Copy link
Copy Markdown

Resolves

Refs #10586 (defect 2: the whole tray menu is rebuilt and renumbered)

Summary

On Linux the tray context menu is cleared and rebuilt on every aboutToShow (setupQtTrayContextMenu() → populateTrayMenu() → clearDynamicMenu()), even when nothing in it changed. Over the D-Bus tray menu every removed and re-added action is its own com.canonical.dbusmenu.LayoutUpdated with new item ids, so tray hosts tear the open menu down and build it up again. In GNOME (AppIndicator extension) the menu briefly shows up empty and refills entry by entry.

The fix keeps the rebuild, but skips it while nothing the menu shows has changed. trayMenuState() builds a snapshot (QVariantList) of:

  • every account's UserModel data (all roles: status, notifications, recent activities, alerts, …) and its apps,
  • the sync control state and whether accounts can be added,
  • the icon palette and size.

On aboutToShow the menu is only rebuilt when that snapshot differs from the one taken at the last build. It is compared with QVariant::operator==, so a value that cannot be compared causes a rebuild rather than a stale menu. The snapshot covers all account data on purpose: since #10646 the account submenu on GNOME only gets new content from this rebuild.

Measured with one AboutToShow(0) on /MenuBar (GNOME 50.5 + AppIndicator v64, Qt 6.11.2):

LayoutUpdated per opening item ids
before (34.0.3) 38 all new each time
after 0 (5 openings in a row) unchanged

The account submenu stays complete (user status, local folder, search, apps, recent activity). Built and tested on 34.0.3 and 34.0.5; built and unit tested on master.

Re-measured after switching the state comparison from JSON to QVariant (34.0.4, same GNOME setup, one offline account): before 13 LayoutUpdated per opening with new item ids each time; after 0 over 5 openings, item ids unchanged, account submenu complete.

Before / after (34.0.5, plain NixOS + GNOME VMs side by side, window titles say which is which):

nextcloud-tray-menu-before-after.mp4

Tests

Two tests added to test/testtrayaccountmenuqt.cpp:

  • openingUnchangedMenuKeepsActions: opening the menu again without changes keeps the same actions (none deleted).
  • openingAfterAccountChangeRebuildsMenu: after the account goes from offline to connected, the next opening rebuilds the menu and the hidden account submenu shows the connected entries (the fix(tray): GNOME + AppIndicator compatibility #10646 case). It also passes without the fix: it guards against the state check skipping a rebuild that is needed, rather than reproducing the bug.

TrayAccountMenuQtTest on master, without and with the fix:

openingUnchangedMenuKeepsActions openingAfterAccountChangeRebuildsMenu existing tests total
without fix FAIL ('firstAction' returned FALSE, line 198) PASS PASS 7 passed, 1 failed
with fix PASS PASS PASS 8 passed, 0 failed

Checklist

AI (if applicable)

How AI was used: root cause analysis, the patch, the tests and the measurements were done with Claude Code; I reviewed, built and tested it myself on my machine and in the VMs shown above.

@github-actions

Copy link
Copy Markdown
Contributor

Hello there,
Thank you so much for taking the time and effort to create a pull request to our Nextcloud project.

We hope that the review process is going smooth and is helpful for you. We want to ensure your pull request is reviewed to your satisfaction. If you have a moment, our community management team would very much appreciate your feedback on your experience with this PR review process.

Your feedback is valuable to us as we continuously strive to improve our community developer experience. Please take a moment to complete our short survey by clicking on the following link: https://cloud.nextcloud.com/apps/forms/s/i9Ago4EQRZ7TWxjfmeEpPkf6

Thank you for contributing to Nextcloud and we hope to hear from you soon!

(If you believe you should not receive this message, you can add yourself to the blocklist.)

@maksimtech

Copy link
Copy Markdown

I reproduced the before/after table independently (Qt 6.10.2, CI container, offscreen):

  • pr-11023 (b924956): 8 passed, 0 failed.
  • master (ea11deb) with only the PR's test file applied: 7 passed, 1 failed — openingUnchangedMenuKeepsActions fails at 'firstAction' returned FALSE (testtrayaccountmenuqt.cpp:198), matching the description.

So the regression test fails before and passes after, as claimed. Note that openingAfterAccountChangeRebuildsMenu passes on master too: it is a guard against skipping a needed rebuild, not a red test. That's fine, but it is worth saying so in the description.

One non-blocking observation from reading the code (not covered by a test I ran): trayMenuStateKey() serializes every role with QJsonDocument::fromVariant, which silently turns types it cannot represent (e.g. a future QImage/QIcon role) into null, so such a change would not invalidate the key. All current roles I looked at are strings/URLs/bools, so it works today.

(Run with Claude Code assistance; results reviewed by me.)

The tray context menu was cleared and rebuilt on every aboutToShow, even
when nothing in it had changed. Over the D-Bus tray menu each removed and
re-added action is its own com.canonical.dbusmenu LayoutUpdated with new
item ids, so tray hosts such as GNOME's AppIndicator extension tore the
open menu down and built it up again entry by entry.

Rebuild only when a snapshot of everything the menu shows differs from
the one taken at the last build. It covers all UserModel data of every
account, because on GNOME the account submenus only get new content from
this rebuild (see nextcloud#10646), plus their apps, the sync control state,
add-account, and the icon palette and size. The snapshot is compared as
QVariant, so a value that cannot be compared causes a rebuild rather than
a stale menu.

Assisted-by: ClaudeCode:claude-opus-5-5
Signed-off-by: Conrad Klaus <conrad.klaus@outlook.de>
@EagleEyeElite

Copy link
Copy Markdown
Author

@maksimtech Thanks for taking the time and reproducing it! Both points are addressed in the updated commit (ce6d797):

  • The description now says openingAfterAccountChangeRebuildsMenu is a guard against skipping a needed rebuild, not a red test (also noted in the test).
  • The state is no longer serialized to JSON. trayMenuState() keeps it as a QVariantList and compares it with QVariant::operator==, like ActivityListModel::refreshPreviewData() does. A value whose type can't be compared now never compares equal, so it causes a rebuild instead of a stale menu, and openingUnchangedMenuKeepsActions would catch that in CI.

Re-ran TrayAccountMenuQtTest on the new commit (Qt 6.11.2): 8 passed, 0 failed. Re-measured in the GNOME VM (34.0.4, AppIndicator v64): still 0 LayoutUpdated per opening, item ids unchanged.

(Changes made with Claude Code assistance; reviewed and tested by me.)

@maksimtech

maksimtech commented Oct 23, 2026 •

Copy link
Copy Markdown

Which Model of Claude Code you use? I use Opus 5.5. @EagleEyeElite

@EagleEyeElite

Copy link
Copy Markdown
Author

@maksimtech Yes, I use Opus 5.5 as well. It's also in the commit's Assisted-by trailer.

@maksimtech

Copy link
Copy Markdown

@EagleEyeElite is written only Claude Code without model used

@EagleEyeElite

EagleEyeElite commented Oct 23, 2026 •

Copy link
Copy Markdown
Author

@maksimtech Not sure if we talk past each other. I mean the commit message itself in ce6d797

**fix(tray): only rebuild the Linux tray menu when its content changed**
...

Assisted-by: ClaudeCode:claude-opus-5-5
Signed-off-by: Conrad Klaus <conrad.klaus@outlook.de>

I am not sure if it's mandatory or advised to write the used model in the PR itself as well.
If I am missing something, I am glad to update the PR.

Thanks!

@camilasan camilasan self-assigned this Oct 26, 2026
@camilasan

Copy link
Copy Markdown
Member

I am not sure if it's mandatory or advised to write the used model in the PR itself as well.

it is mandatory.
how you did it is correct, thank you :)

@camilasan camilasan added this to the 35.0.2 milestone Oct 27, 2026
@nilsding nilsding modified the milestones: 35.0.2, 35.0.3 Oct 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants