ldtray
Cross-platform tray icons for Rust that are never linked against any GUI or platform library at compile time.
Every platform toolkit — libdbus on Linux, shell32/user32 on Windows,
AppKit/objc on macOS — is resolved at runtime through
libloading. The result: one daemon binary runs
everywhere. On a headless server the only failure is a clean Err from
Tray::new ("the tray library could not be loaded") — never a link error, never
a crash. Ignore the error and your program keeps running without a tray.
Features
- Tray icon from raw RGBA pixels
- Click triggers: left / right / middle / double click
- Context menu with buttons, checkboxes, separators, and submenus
- Desktop notifications
- Update icon, tooltip, and menu live from any thread via a
Send + Synchandle - Blocking
run()(main-thread-correct, works on macOS) or backgroundspawn()(Linux/Windows)
Status
All three backends implement the full feature set — tray icon, left/right/middle/ double-click triggers, context menu, and notifications:
| Platform | Mechanism | Validation |
|---|---|---|
| Linux | StatusNotifierItem + dbusmenu over D-Bus | end-to-end incl. clicks/menu/notify (KDE) |
| Windows | Shell_NotifyIcon + hidden window |
build + clippy + runtime smoke on CI |
| macOS | NSStatusItem via the Obj-C runtime |
build + clippy + runtime smoke on CI |
Every backend is exercised at runtime by examples/smoke.rs, which CI runs on
the Windows and macOS GUI runners (and Linux): it creates the tray, pumps the
loop, updates icon/tooltip/menu, fires a notification and quits — so wrong FFI
struct layouts or message signatures fail the build. Synthetic click delivery
still needs a real interactive desktop; only the Linux triggers/menu are
verified against a live host end-to-end.
Usage
use ;
let icon = from_rgba?;
let menu = new
.item
.item
.item;
let tray = match new ;
let handle = tray.handle;
tray.run?;
Run the bundled example:
Design
The whole crate compiles with a single non-platform dependency (libloading).
Platform symbols are hand-bound FFI declarations resolved from a dlopen'd
library the first time a Tray is created. See src/platform/ for the
per-OS backends and docs/source comments for the wire-level details.
License
MIT © Karpelès Lab Inc.