tray
import tray from "tray";
import ui from "ui";
import gfx from "gfx";
fn on_tray(ev: tray.TrayEvent) {
if (ev.kind == tray.TrayEventKind.Click) { ui.show_window(); }
else if (ev.index == 0) { ui.show_window(); } // "Open"
else if (ev.index == 2) { ui.quit(); } // "Quit"
}
component App { view { ui.Column {} } }
fn main() -> i32 {
var small = gfx.new_surface(16, 16, gfx.Format.Argb) or { return 1; };
small.fill_rect(0, 0, 16, 16, #2A7FFFFF);
var icon: tray.Tray = tray.add([small], "Chat", on_tray) or { return 1; };
let items: [3]tray.MenuItem = [
tray.MenuItem { label: "Open"; },
tray.MenuItem { separator: true; },
tray.MenuItem { label: "Quit"; },
];
icon.set_menu(items[0..3]) or {};
// closing the window leaves the program running with its icon
ui.run_window(App {}, ui.Window { title: "Chat"; keep_running: true; }) or { return 1; };
icon.remove();
small.free();
return 0;
}A status icon keeps a program reachable with no window open: a messenger,
a sync tool. Pair it with ui.Window’s keep_running (Running with no
window) so closing the window doesn’t end
the program, and ui.show_window() brings the window back.
Errors
add fails with a TrayError: Unsupported (no status icons on this
platform), NoArea (there are, but this session has nowhere to show
one: no taskbar on Windows, no StatusNotifierWatcher on Linux; go on
without the icon), Failed (the system refused it) or OutOfMemory.
Functions
| Function | Does |
|---|---|
add(icon, tooltip, on_event) -> Tray or TrayError | Puts an icon in the status area; its events go to on_event |
t.set_icon(icon) -> void or TrayError | Another picture (an unread count drawn on it, say) |
t.set_tooltip(text) -> void or TrayError | The text shown when the pointer rests on it |
t.set_menu(items) -> void or TrayError | The menu, replacing the last; no items: none |
t.poll() -> i64 | The icon’s waiting events given to the handler now (the ui loop does this for you) |
t.remove() | Takes the icon away; removing twice does nothing |
icon is one picture in several sizes (16, 20, 24, 32 pixels…), each a
gfx.Surface: the platform shows the one that fits. The pixels are
copied. From 1 to 16 images, each side 1 to 256 pixels; more traps, as
does more than 8 icons at once.
A MenuItem has a label, enabled (default true), checked (a check
mark, default false) and separator (a line; the rest ignored). At most
64 items.
Events
The handler gets a TrayEvent { tray, kind, index } in the ui loop, on
ui.run’s thread, between other events:
kind | When |
|---|---|
Click | The icon was clicked with the left button (or Enter pressed on it) |
Choose | Menu item index (its place in set_menu’s list) was chosen |
The menu opens on the right button by itself; on macOS also on a click with Control held.
Platforms
| Windows | The notification area (Shell_NotifyIconW); NoArea when the session has no taskbar (a service’s). The icon comes back by itself when Explorer restarts. A tooltip longer than 127 UTF-16 units is cut |
| macOS | A status item in the menu bar (NSStatusItem) |
| Linux | A StatusNotifierItem with a dbusmenu menu, over dbus’s shared connection, registered with the StatusNotifierWatcher of KDE Plasma, the GNOME AppIndicator extension, waybar or xfce4-panel; NoArea where none runs (plain GNOME, a bare window manager), Unsupported with no session bus. A removed icon is hidden (its status Passive) until the program ends or adds another icon; the host comes back by itself if the panel restarts |
| Uusi | Unsupported |
Last modified: