Windows tray icon that shows whether the WSL2 VM is running and how much CPU and memory it uses, with a menu entry that shuts it down.

It sits next to the clock like the keyboard-layout badge. Grey means the WSL2 VM is off; green, orange or red means it is running and shows how much of the machine it is using.

Left to right: off, running below 50 %, 50–75 %, above 75 %.

Percentages are relative to the whole machine (all logical cores, all physical

RAM), the same way Task Manager reports vmmemWSL. The colour follows whichever

of CPU or memory is higher.

Hover for the numbers:

Click (left or right) for the menu:

Shut down WSL2 runs wsl --shutdown after asking for confirmation.

Start with Windows adds or removes an entry under

HKCU\Software\Microsoft\Windows\CurrentVersion\Run.

The buttons always fetch the latest release. Each

release has

wsl-tray-x64.exe and wsl-tray-arm64.exe attached, with a SHA256SUMS

file. There is nothing to install: put the file somewhere permanent, run it,

and tick Start with Windows in the menu if you want it back after a

reboot. It does not need administrator rights.

On Windows 11 the icon shows up next to the clock on first run (the app sets

its own IsPromoted flag in HKCU\Control Panel\NotifyIconSettings, but only

if you have not already decided about it in Settings › Taskbar).

If wsl-tray is useful to you, you can support its development:

wsl-tray.exe [-poll 5s] [-interval 30s] [-process vmmemWSL] [-log FILE] [-render-test DIR]

Flags follow Go conventions: -poll 10s, -poll=10s and --poll 10s all

work. Durations are written like 30s, 1m30s or 250ms.

Measured on Windows 11 25H2, AMD Ryzen AI MAX+ 395 (32 logical cores, 48 GB), 125 % display scaling, with the release build from this repository.

The only dependency is windows-sys,

which contains nothing but extern declarations. There is no runtime, no COM,

no allocation on the poll path beyond reusing one buffer.

For comparison, the original Go version of this program was a 2.4 MB executable using 16 MB of private memory and 8 threads; the difference is the Go runtime.

Measure it yourself: cargo test --release -- --ignored --nocapture poll_cost

prints the per-poll cost on your machine.

- The VM shows up as a process called vmmemWSL. Its presence is the on/off signal.wsl --list --runningis not used because it says "no running distributions" while the VM is still alive and holding memory.

- CPU and memory come from NtQuerySystemInformation(SystemProcessInformation), the call Task Manager uses. It needs no handle to the process, which matters becausevmmemWSLruns as SYSTEM andOpenProcesson it is denied to a normal user. CPU is the difference in kernel+user time between two samples divided by wall time and the number of logical cores; memory is the process's working set.

- The icon is the Font Awesome "linux" glyph, rasterized once into a small

coverage mask (assets/tux.bin, generated bytools/gentux-rs) and scaled to the taskbar's icon size at run time. No font is involved, so it looks the same on every machine.

- wsl --shutdownis started with- CreateProcessWand an explicit- System32\wsl.exepath, without a console window.

You need a stable Rust toolchain (1.88 or newer) with the MSVC target.

.\build.ps1This runs cargo build --release and copies the result to .\wsl-tray.exe.

Run that copy rather than the one under target\: Windows refuses to

overwrite a running executable, so running from target\release makes the

next build fail while the tray app is open.

The exe icon, the application manifest (per-monitor DPI, common controls v6)

and the version resource are linked from pre-built objects in res\ (one per

architecture), so rc.exe is not needed. To regenerate them after editing

winres\:

go install github.com/tc-hib/go-winres@latest

go-winres make --in winres/winres.json --arch amd64,arm64 --out res/wsl-tray

Move-Item res\wsl-tray_windows_amd64.syso res\wsl-tray-amd64.res.obj -Force

Move-Item res\wsl-tray_windows_arm64.syso res\wsl-tray-arm64.res.obj -ForceTo regenerate the icon mask after changing tools\gentux-rs\linux.svg or the

stroke width:

cd tools\gentux-rs

cargo run --releasecargo test --release runs the unit tests, including one that samples live

processes on the machine. The GitHub Actions workflow builds x64 and ARM64 on

every push, runs the tests and clippy, and attaches both executables to a

release when a v* tag is pushed.

src/main.rs window, tray icon, menu, autostart, Windows 11 promotion

src/monitor.rs process sampling, wsl --shutdown

src/icon.rs mask scaling, HICON creation, PNG output for -render-test

assets/tux.bin icon mask (generated)

res/ resource objects; winres/ has their sources

tools/gentux-rs/ mask generator

docs/ screenshots

Each source file starts with a module comment that explains its part of the

program (the message flow and re-entrancy rules in main.rs, why the

process list is read the way it is in monitor.rs, the icon pipeline in

icon.rs). cargo doc --document-private-items --open renders all of it.

BSD 3-Clause, see LICENSE. The Tux glyph is the "linux" icon from Font Awesome Free, CC BY 4.0; see THIRD_PARTY_NOTICES.md.