Skip to content

Put the Windows tray on NotifyIconTray - #1013

Merged
SimonCropp merged 2 commits into
mainfrom
windows-tray-on-notifyicon
Nov 1, 2026
Merged

SimonCropp merged 2 commits into
mainfrom
windows-tray-on-notifyicon

Conversation

@SimonCropp

Copy link
Copy Markdown
Member

The Windows tray head drew its own NotifyIcon and built its menu itself: the fixed items kept, the tracked ones built on every open. The macOS and Linux heads hand a model to PlatformHeads' tray every tenth of a second, so the menu was shown by two implementations. This needs PlatformHeads 0.10.0 (SimonCropp/PlatformHeads#10) for LeftClickOpensMenu, NotifyIconTray.Handle and TrayNotificationKind.Warning, so all seven pins move to it. 0.10.0 also moves its reusable build-native workflow's macOS job from macos-14, which GitHub retires on November 2, to macos-15 (SimonCropp/PlatformHeads#11). So the next build-native run here builds the Swift libraries on macOS 15.

The change.

  • The tray: the Windows head's tray is now NotifyIconTray<TrayIcon>, which makes the menu from the last model each time it opens.

  • The turns: TrayTurns (new, in the core) is the turn every head takes. It applies a model of both halves, and does a click on the menus it was chosen from, which it also answers tips from. TrayLoop runs it for Linux and macOS. On Windows a System.Windows.Forms.Timer runs it on the message loop, where the icon's events are raised.

  • MenuBuilder is now only how the menu looks, as NotifyIconOptions:

    • the glyphs and the icon pictures;
    • Theme: the menu's font and opening direction;
    • Style: the tips and the submenus' direction;
    • LeftClickOpensMenu.

    Extensions.Handle and the ShowContextMenu accessor are gone, since PlatformHeads does both now.

  • What stays the same:

    • hot keys are registered against tray.Handle;
    • balloons are Warning, and the update report is Info or Warning;
    • the icon shows its picture at once;
    • the active icon is the tracker's callbacks setting what the next turn shows.
  • The cost: an open menu can be up to a tenth of a second behind the tracker, which the ids make safe. And the menu is built ten times a second while the tray is idle, as on Linux. The tracker's lists are cached, so nothing asks a socket or the disk to build it.

  • Docs: CLAUDE.md. It also drops a stale mention of a macos-14 CI job; the macOS build is the unix job's macos-latest leg.

Tests.

  • MenuBuilderTest shows the menu through MenuTray, a stand-in ITray that makes it as NotifyIconTray does, with the head's real options and turns and no icon in the notification area.
  • Empty, Full, FullGrouped and SnapshotThatWasNotWrittenDropDown pass against their existing images, unchanged.
  • AClickDoesWhatItsItemDoes now clicks and then takes a turn.
  • A_group_named_after_a_fixed_item_is_removed_with_the_rest and Tracked_items_are_disposed_by_the_next_open are removed. No item is kept now, and MenuOnOpeningTests in PlatformHeads covers what's left of that.

Locally on Windows, against the published 0.10.0 packages, a Release build had no errors:

  • DiffEngineTray.Tests passed 104.
  • DiffEngineTray.Core.Tests passed 321, with 4 skipped.
  • DiffEngineViewer.Tests passed 871, with 25 skipped.
  • Packaging.Tests passed 53.

Not seen working. I didn't run the tray itself: one was already running on this machine, holding the mutex a second one exits on.

SimonCropp and others added 2 commits November 1, 2026 17:32
The Windows head drew its own NotifyIcon, built the tracked half of its
menu on every open beside fixed items it kept, opened the menu on a left
click through NotifyIcon's ShowContextMenu, and registered hot keys
against the icon's window. The macOS and Linux heads hand a model to
PlatformHeads' tray every tenth of a second, so the menu was two
implementations.

Now the Windows head's tray is PlatformHeads' NotifyIconTray, which makes
the menu from the last model as it opens. The turns every head takes are
TrayTurns, which TrayLoop runs for the other two and a WinForms timer
runs here, on the message loop the icon's events are raised on.
MenuBuilder is only how the menu looks: the font, the directions, the
tips and the glyphs, and LeftClickOpensMenu. Hot keys go to the tray's
Handle, and balloons are TrayNotificationKind.Warning, as they were.

A menu can now be a turn behind the tracker, which the ids make safe:
a click is done on the menus it was chosen from.

MenuBuilderTest shows the menu through MenuTray, which makes it as
NotifyIconTray does with no icon in the notification area, and its
images are unchanged. The two tests of rebuilding around kept items go,
since there are none now, and MenuOnOpening's own tests in PlatformHeads
hold to what is left of that.

All seven PlatformHeads pins move to 0.10.0, which has NotifyIconTray's
additions and runs build-native's macOS job on macos-15, since GitHub
retires macos-14 on November 2.
Co-authored-by: SimonCropp <122666+SimonCropp@users.noreply.github.com>
@SimonCropp
SimonCropp merged commit 8d55e97 into main Nov 1, 2026
18 checks passed
@SimonCropp
SimonCropp deleted the windows-tray-on-notifyicon branch November 1, 2026 09:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant