tray
StatusNotifierItem: registered tray items with artwork, status and menus.
list {
direction = "Horizontal",
spacing = 4,
source = mantle.tray:map(function(tray)
return tray and tray.items or {}
end),
key = function(item) return item.id end,
itemfn = function(item)
return button {
on_click = function(_, which)
if which == "left" and not item.item_is_menu then
mantle.tray:activate(item.id, 0, 0) -- screen x, y; most apps ignore them
end
end,
children = { icon { name = item.icon_name or item.icon_path or "", size = 16 } },
}
end,
}
State
mantle.tray:get() returns TrayState, nil before the first push. A field marked ? may be absent.
| Field | Type | Description |
|---|---|---|
items | TrayItem[] | Registered items in registration order, oldest first; updates never reorder them. |
MenuItem
One tray.items[].menu entry.
| Field | Type | Description |
|---|---|---|
children | MenuItem[] | Submenu entries, empty for a leaf. An app that fills submenus lazily sends them only after menu_will_show. |
enabled | boolean | false for a greyed-out entry; draw it, but clicking does nothing. |
icon_name? | string | Theme icon name, or nil. Icon pixmaps are not carried. |
id | integer | DBusMenu id, the second argument of activate_menu_item and menu_will_show. |
label? | string | Entry text as sent, or nil. _ mnemonic markers remain ("_Quit"); strip them to draw. |
menu_type | string | "standard" (the default) or "separator", as the application sent it. |
toggle_state? | integer | 0 off, 1 on, -1 indeterminate or unreported; nil exactly when toggle_type is. |
toggle_type? | string | "checkmark", "radio", or nil for an entry that is not a toggle. |
TrayItem
| Field | Type | Description |
|---|---|---|
attention_icon_name? | string | Artwork to draw while status == "NeedsAttention", paired with attention_icon_path like the base icon; both nil when unset. |
attention_icon_path? | string | File half of the attention artwork. |
icon_name? | string | Theme icon name for icon { name = ... }. At most one of it and icon_path is set. |
icon_path? | string | Icon file for image { source = ... }: one from the item’s IconThemePath, or its pixmap spooled to a PNG. |
id | string | Item identity for every tray action, e.g. "1.234/StatusNotifierItem". Opaque. |
item_is_menu | boolean | Left click should open menu instead of activate. |
menu? | MenuItem[] | Top-level menu entries, or nil when the item exports no DBusMenu or its first fetch failed. |
name | string | SNI Title, or its Id when the title is empty. |
overlay_icon_name? | string | Badge to draw over the icon’s corner, paired with overlay_icon_path; both nil when unset. |
overlay_icon_path? | string | File half of the badge. |
status | string | "Active", "Passive" (the item asks to be hidden) or "NeedsAttention", as the item sent it. |
tooltip? | string | Tooltip title and text joined by a newline, or nil when both are empty. |
Actions
Call each as mantle.tray:<action>(arguments...); ? marks an argument you may omit.
| Action | Arguments | Description |
|---|---|---|
activate | id: string, x: integer, y: integer | Left-click activation at screen coordinates x, y; a no-op when item_is_menu. |
secondary_activate | id: string, x: integer, y: integer | Middle-click activation at screen coordinates x, y. |
scroll | id: string, delta: integer, orientation: string | Scrolls the icon by delta; orientation is "vertical" or "horizontal", passed verbatim. |
activate_menu_item | id: string, menu_item_id: integer | Clicks the item’s MenuItem.id. |
menu_will_show | id: string, submenu_id: integer | Tells the application submenu submenu_id is opening, then refetches the menu unless it answers that nothing changed. |
Backend
Mantle hosts org.kde.StatusNotifierWatcher at /StatusNotifierWatcher on the session bus and
registers itself as a host.
| Contract | Behavior |
|---|---|
| Name | Requested without DoNotQueue: if another watcher owns it, Mantle queues behind it |
| Adoption | At start, adopts items already on the bus at /StatusNotifierItem, /StatusNotifierItem/1 or /org/chromium/StatusNotifierItem/1, for apps that never re-register |
| Removal | An item leaves, and its spooled PNGs are deleted, when its bus name loses its owner |
| Icon | IconName found in the item’s IconThemePath, then IconName as a theme name, then the largest valid pixmap: square, 1 to 128 px, exactly w × h × 4 ARGB bytes, spooled as a PNG under tray/ |
| Bounds | Strings 256 bytes; menus 1024 nodes, depth 32 |
| Menus | com.canonical.dbusmenu. menu_will_show sends AboutToShow, activate_menu_item sends Event("clicked") |
Gotchas
| Trap | Fix |
|---|---|
activate does nothing on some items | The item set item_is_menu, and Mantle skips Activate for it. Open menu on left click |
| A submenu is empty | Some apps fill submenus only after AboutToShow. Send menu_will_show with the submenu’s id before drawing it |
See also: System tray with menu recipe.