Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

tray

StatusNotifierItem: registered tray items with artwork, status and menus.

list {
    direction = "horizontal",
    spacing = 4,
    items = mantle.tray:map(function(tray)
        return tray.items
    end),
    key = function(item) return item.id end,
    each = function(item)
        return rect {
            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.

FieldTypeDescription
itemsTrayItem[]Registered items in registration order, oldest first; updates never reorder them.

One tray.items[].menu entry.

FieldTypeDescription
childrenMenuItem[]Submenu entries, empty for a leaf. An app that fills submenus lazily sends them only after menu_will_show.
enabledbooleanfalse for a greyed-out entry; draw it, but clicking does nothing.
icon_name?stringTheme icon name, a spooled PNG path from raw icon-data, or nil.
idintegerDBusMenu id, the second argument of activate_menu_item and menu_will_show.
label?stringEntry text as sent, or nil. _ mnemonic markers remain ("_Quit"); strip them to draw.
menu_typeMenuType
toggle_state?integer0 off, 1 on, -1 indeterminate or unreported; nil exactly when toggle_type is.
toggle_type?ToggleTypenil for an entry that is not a toggle.

tray.items[].menu[].menu_type.

ValueDescription
"standard"An ordinary entry; also any type outside the spec.
"separator"A divider line; it has no label and does nothing.

ToggleType

tray.items[].menu[].toggle_type.

ValueDescription
"checkmark"A check box.
"radio"One of a group of mutually exclusive entries.

TrayItem

FieldTypeDescription
attention_icon_name?stringArtwork to draw while status == "needs_attention", paired with attention_icon_path like the base icon; both nil when unset.
attention_icon_path?stringFile half of the attention artwork.
icon_name?stringTheme icon name for icon { name = ... }. At most one of it and icon_path is set.
icon_path?stringIcon file for image { source = ... }: one from the item’s IconThemePath, or its pixmap spooled to a PNG.
idstringItem identity for every tray action, e.g. "1.234/StatusNotifierItem". Opaque.
item_is_menubooleanLeft 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.
namestringSNI Title, or its Id when the title is empty.
overlay_icon_name?stringBadge to draw over the icon’s corner, paired with overlay_icon_path; both nil when unset.
overlay_icon_path?stringFile half of the badge.
statusTrayStatusSNI Status.
tooltip?stringTooltip title and text joined by a newline, or nil when both are empty.

TrayStatus

SNI Status.

ValueDescription
"active"Normal; also any value outside the spec, or none.
"passive"The item asks to be hidden.
"needs_attention"The item wants attention; draw its attention artwork if set.

Actions

Call each as mantle.tray:<action>(arguments...); ? marks an argument you may omit.

ActionArgumentsDescription
activateid: string, x: integer, y: integerLeft-click activation at screen coordinates x, y; a no-op when item_is_menu.
context_menuid: string, x: integer, y: integerContext-menu activation at screen coordinates x, y.
secondary_activateid: string, x: integer, y: integerMiddle-click activation at screen coordinates x, y.
scrollid: string, delta: integer, orientation: ScrollOrientationScrolls the icon by delta along orientation.
activate_menu_itemid: string, menu_item_id: integerClicks the item’s MenuItem.id.
menu_will_showid: string, submenu_id: integerTells the application submenu submenu_id is opening, then refetches the menu unless it answers that nothing changed.

ScrollOrientation

The tray:scroll axis, sent to the item as spelled.

One of "vertical", "horizontal".

Backend

Mantle hosts org.kde.StatusNotifierWatcher at /StatusNotifierWatcher on the session bus and registers itself as a host.

ContractBehavior
NameRequested without DoNotQueue: if another watcher owns it, Mantle queues behind it
AdoptionAt start, adopts items already on the bus at /StatusNotifierItem, /StatusNotifierItem/1 or /org/chromium/StatusNotifierItem/1, for apps that never re-register
RemovalAn item leaves, and its spooled PNGs are deleted, when its bus name loses its owner
IconIconName 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/
BoundsStrings 256 bytes; menus 1024 nodes, depth 32
Menuscom.canonical.dbusmenu. Drops items with visible = false. Spools raw PNG icon-data (up to 512 KB) to shared memory as icon_name. menu_will_show sends AboutToShow, activate_menu_item sends Event("clicked")

Gotchas

TrapFix
activate does nothing on some itemsThe item set item_is_menu, and Mantle skips Activate for it. Open menu on left click
A dynamic menu or submenu is emptySome apps fill menus only after AboutToShow. Send menu_will_show(item.id, 0) when opening the root menu, and with submenu_id when expanding a submenu
Right-clicking an item with no menu does nothingThe app provides no DBusMenu. Call mantle.tray:context_menu(item.id, x, y) on right click to trigger its native popup

See also: System tray with menu recipe.

Source: supervisor/src/capabilities/tray/