Skip to main content

basic/
basic.rs

1//! Minimal end-to-end example.
2//!
3//! Shows a red tray icon with a small menu, prints every event, pops a
4//! notification when "Say hi" is clicked, and exits on "Quit". If no tray is
5//! available (headless server, missing libraries) it prints why and exits 0 —
6//! demonstrating the graceful-degradation contract.
7
8use ldtray::{Event, Icon, Menu, MenuItem, Notification, Tray, TrayConfig};
9
10const SAY_HI: u32 = 1;
11const TOGGLE: u32 = 2;
12const QUIT: u32 = 3;
13
14fn main() {
15    // A 16x16 solid red icon.
16    let side = 16u32;
17    let mut rgba = Vec::with_capacity((side * side * 4) as usize);
18    for _ in 0..side * side {
19        rgba.extend_from_slice(&[220, 40, 40, 255]);
20    }
21    let icon = Icon::from_rgba(side, side, rgba).expect("valid icon");
22    let notify_icon = icon.clone();
23
24    let menu = Menu::new()
25        .item(MenuItem::button(SAY_HI, "Say hi"))
26        .item(MenuItem::checkbox(TOGGLE, "Toggle me", false))
27        .item(MenuItem::separator())
28        .item(MenuItem::button(QUIT, "Quit"));
29
30    let config = TrayConfig::new(icon).tooltip("ldtray example").menu(menu);
31
32    let tray = match Tray::new(config) {
33        Ok(tray) => tray,
34        Err(err) => {
35            eprintln!("tray unavailable: {err}");
36            eprintln!("(this is expected on a headless server — exiting cleanly)");
37            return;
38        }
39    };
40
41    let handle = tray.handle();
42    println!("tray is up — right-click it for the menu, or Ctrl-C to abort");
43
44    let result = tray.run(move |event| {
45        println!("event: {event:?}");
46        match event {
47            Event::Menu(id) if id.0 == SAY_HI => {
48                // Actions are shown on Linux; ignored (message still shown)
49                // elsewhere.
50                let _ = handle.notify(
51                    Notification::new("ldtray", "Hello from the tray!")
52                        .with_icon(notify_icon.clone())
53                        .action(100, "Wave back"),
54                );
55            }
56            Event::NotificationAction(action) => {
57                println!("notification action clicked: {}", action.0);
58            }
59            Event::Menu(id) if id.0 == QUIT => {
60                let _ = handle.quit();
61            }
62            _ => {}
63        }
64    });
65
66    if let Err(err) = result {
67        eprintln!("event loop ended with error: {err}");
68    }
69}