[PR #5691] [client] Fix Exit Node submenu separator accumulation on Windows #23661

Closed
opened 2026-08-05 06:07:36 -04:00 by saavagebueno · 0 comments
Owner

Original Pull Request: https://github.com/netbirdio/netbird/pull/5691

State: closed
Merged: Yes


Problem

Fixes #4702

On Windows, the tray app uses a 10-second background poller to refresh the Exit Node menu (because TrayOpenedCh is not supported on Windows). Every poll cycle that finds a selected exit node calls s.mExitNode.AddSeparator() before adding the "Deselect All" item.

AddSeparator() returns no handle, so the separator is never removed in the cleanup pass of recreateExitNodeMenu(). All other items — exit node checkboxes and "Deselect All" — are properly tracked and removed each cycle. The separator is not.

After the client has been running for a while with an exit node selected, hundreds of separator lines stack up in the submenu, filling the full screen height with blank entries.

On Linux/FreeBSD this doesn't manifest because the parent mExitNode item itself is removed and recreated each cycle (to work around a different systray limitation), which wipes all children including the orphaned separators.

Fix

Replace the untracked AddSeparator() call with a regular disabled sub-menu item. This gives us a handle that can be stored in mExitNodeSeparator and removed at the start of each recreateExitNodeMenu() call, alongside the existing mExitNodeDeselectAll cleanup.

// Before
s.mExitNode.AddSeparator()

// After
sep := s.mExitNode.AddSubMenuItem("───────────────", "")
sep.Disable()
s.mExitNodeSeparator = sep

The visual result is equivalent on Windows (a greyed-out, unclickable divider row), and the item is now properly cleaned up on every menu refresh.

Test

Run the Windows client with an exit node selected and leave it running for several minutes. Open the Exit Node submenu — previously it would grow with each poll; with this fix the menu stays clean regardless of uptime.

Documentation

Select exactly one:

  • I added/updated documentation for this change
  • Documentation is not needed for this change (explain why)

Docs PR URL (required if "docs added" is checked)

Paste the PR link from https://github.com/netbirdio/docs here:

https://github.com/netbirdio/docs/pull/__

Summary by CodeRabbit

  • Refactor
    • Improved exit-node menu behavior: the separator now persists correctly across menu updates and the "Deselect All" option has been reorganized for more reliable presentation and interaction, reducing visual flicker and improving menu stability.
**Original Pull Request:** https://github.com/netbirdio/netbird/pull/5691 **State:** closed **Merged:** Yes --- ## Problem Fixes #4702 On Windows, the tray app uses a 10-second background poller to refresh the Exit Node menu (because `TrayOpenedCh` is not supported on Windows). Every poll cycle that finds a selected exit node calls `s.mExitNode.AddSeparator()` before adding the "Deselect All" item. `AddSeparator()` returns no handle, so the separator is never removed in the cleanup pass of `recreateExitNodeMenu()`. All other items — exit node checkboxes and "Deselect All" — are properly tracked and removed each cycle. The separator is not. After the client has been running for a while with an exit node selected, hundreds of separator lines stack up in the submenu, filling the full screen height with blank entries. On Linux/FreeBSD this doesn't manifest because the parent `mExitNode` item itself is removed and recreated each cycle (to work around a different systray limitation), which wipes all children including the orphaned separators. ## Fix Replace the untracked `AddSeparator()` call with a regular disabled sub-menu item. This gives us a handle that can be stored in `mExitNodeSeparator` and removed at the start of each `recreateExitNodeMenu()` call, alongside the existing `mExitNodeDeselectAll` cleanup. ```go // Before s.mExitNode.AddSeparator() // After sep := s.mExitNode.AddSubMenuItem("───────────────", "") sep.Disable() s.mExitNodeSeparator = sep ``` The visual result is equivalent on Windows (a greyed-out, unclickable divider row), and the item is now properly cleaned up on every menu refresh. ## Test Run the Windows client with an exit node selected and leave it running for several minutes. Open the Exit Node submenu — previously it would grow with each poll; with this fix the menu stays clean regardless of uptime. ## Documentation Select exactly one: - [ ] I added/updated documentation for this change - [x] Documentation is **not needed** for this change (explain why) ### Docs PR URL (required if "docs added" is checked) Paste the PR link from https://github.com/netbirdio/docs here: https://github.com/netbirdio/docs/pull/__ <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Improved exit-node menu behavior: the separator now persists correctly across menu updates and the "Deselect All" option has been reorganized for more reliable presentation and interaction, reducing visual flicker and improving menu stability. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
saavagebueno added the pull-request label 2026-08-05 06:07:36 -04:00
Sign in to join this conversation.
No Label pull-request
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: DYNR/netbird#23661