tray

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 5, 2026 License: BSD-3-Clause Imports: 6 Imported by: 0

README

tray — cross-platform system tray for go-widgets

A system-tray / menu-bar icon with menus, submenus, checkboxes and separators. A tray is OS-integration, not a pixel-blitted widget, so it lives outside the pure-blitting toolkit and drives the native APIs through a small Backend interface — all CGO_ENABLED=0:

platform native API mechanism
darwin NSStatusItem + NSMenu/NSMenuItem purego + the Objective-C runtime
windows Shell_NotifyIcon + TrackPopupMenu golang.org/x/sys/windows syscalls
linux StatusNotifierItem + com.canonical.dbusmenu pure-Go DBus

Usage

menu := tray.NewMenu().Add(
    tray.Item("Open", func() { open() }),
    tray.Checkbox("Notifications", true, func(on bool) { setNotify(on) }),
    tray.SubMenu("Recent", tray.NewMenu().Add(tray.Item("file.txt", nil))),
    tray.Separator(),
    tray.Item("Quit", func() { t.Quit() }),
)

t := tray.New(iconPNG).SetTooltip("My App").SetMenu(menu)
t.OnReady(func() { /* live */ })
t.Run() // blocks on the platform event loop until Quit

Status

  • Core (Tray, Menu, MenuItem, item activation/toggle, Backend interface, headless backend) — done, 100% covered, builds on every arch.
  • Native backends are opt-in via the tray_native build tag, so the core keeps its 100% coverage gate while the native code is compile-verified per-OS in CI. A tray can only be runtime-verified on a live desktop session.
    • darwin — implemented: NSStatusItem+NSMenu via ebitengine/purego, CGO=0. Compile-verified; runtime confirmation on a real macOS session is pending. Build/run your app with -tags tray_native.
    • windows / linux — next increments (currently nil under the tag → ErrNoBackend).

Without the tag (or a native backend for the OS), Run returns ErrNoBackend; supply one — including the headless backend — via WithBackend.

go run -tags tray_native ./cmd/yourapp   # link the macOS NSStatusItem backend

BSD-3-Clause. Copyright the go-widgets authors.

Documentation

Overview

Package tray is a cross-platform system-tray (menu-bar) widget for go-widgets.

A tray icon is OS-integration, not a pixel-blitted widget, so it cannot live in the pure-blitting toolkit. This package models the tray, its menu and menu items in a platform-agnostic core, and drives them through a small Backend interface implemented per-OS:

  • darwin: NSStatusItem + NSMenu via purego + the Objective-C runtime
  • windows: Shell_NotifyIcon + TrackPopupMenu via x/sys/windows
  • linux: StatusNotifierItem + com.canonical.dbusmenu over DBus

All CGO_ENABLED=0. A headless backend backs tests and display-less CI.

Index

Constants

This section is empty.

Variables

View Source
var ErrNoBackend = errors.New("tray: no backend for this platform")

ErrNoBackend is returned by Run when no platform backend has been set (and none was selected for the current OS).

Functions

This section is empty.

Types

type Backend

type Backend interface {
	// Run shows the tray and blocks on the platform event loop until Quit.
	Run(t *Tray) error
	// Refresh re-applies the tray's icon, tooltip and menu after a change.
	Refresh(t *Tray)
	// Quit stops the event loop started by Run.
	Quit()
}

Backend drives a Tray on a specific platform.

type Headless

type Headless struct {
	Started   bool
	Refreshes int
	LastIcon  []byte
	LastTip   string
	LastMenu  *Menu
	// contains filtered or unexported fields
}

Headless is a display-less Backend for tests and CI. It records the tray state applied to it and blocks Run until Quit, so a tray can be exercised end-to-end without a real desktop session.

func NewHeadless

func NewHeadless() *Headless

NewHeadless returns a ready headless backend.

func (*Headless) Quit

func (h *Headless) Quit()

Quit unblocks Run (idempotent).

func (*Headless) Refresh

func (h *Headless) Refresh(t *Tray)

Refresh snapshots the tray's current state.

func (*Headless) Run

func (h *Headless) Run(t *Tray) error

Run marks the tray started, snapshots its state, signals readiness and blocks until Quit.

type Menu struct {
	Items []*MenuItem
}

Menu is an ordered list of items.

func NewMenu

func NewMenu() *Menu

NewMenu returns an empty menu.

func (m *Menu) Add(items ...*MenuItem) *Menu

Add appends items and returns the menu for chaining.

func (m *Menu) Find(path ...int) *MenuItem

Find returns the item at the given path of indices (descending into submenus), or nil if the path is invalid.

type MenuItem struct {
	Label     string
	Tooltip   string
	Checked   bool
	Disabled  bool
	Separator bool
	// OnClick is invoked when the item is activated. For a checkbox item the
	// Checked field is toggled before OnClick runs.
	OnClick func()
	// Submenu, when non-nil, makes this item open a nested menu (its OnClick is
	// then ignored).
	Submenu *Menu
	// contains filtered or unexported fields
}

MenuItem is one entry in a tray menu.

func Checkbox

func Checkbox(label string, checked bool, onToggle func(bool)) *MenuItem

Checkbox is a toggleable item; onToggle receives the new checked state.

func Item

func Item(label string, onClick func()) *MenuItem

Item is a plain clickable menu item.

func Separator

func Separator() *MenuItem

Separator is a divider line.

func SubMenu(label string, sub *Menu) *MenuItem

SubMenu is an item that opens a nested menu.

func (it *MenuItem) Activate()

Activate dispatches a click on the item: it flips a checkbox's state and invokes the appropriate callback. Separators, disabled items and submenu parents do nothing. Backends call this when the user picks an item.

type Tray

type Tray struct {
	// contains filtered or unexported fields
}

Tray is a system-tray icon with a tooltip and a menu.

func New

func New(iconPNG []byte) *Tray

New creates a tray showing iconPNG (PNG-encoded bytes). The platform backend is selected automatically; use WithBackend to override (eg. for tests).

func (*Tray) Attach

func (t *Tray) Attach() error

Attach shows the tray inside a host-owned event loop and returns immediately, instead of Run's block-until-Quit. Use it from an application that already drives the platform's main run loop (its own window): Run would try to start a second loop, whereas Attach just registers the tray with the running one. It must be called on the platform's main/UI thread. Returns ErrNoBackend when the active backend does not support attaching.

func (*Tray) Icon

func (t *Tray) Icon() []byte

Accessors used by backends.

func (*Tray) Menu

func (t *Tray) Menu() *Menu

func (*Tray) OnReady

func (t *Tray) OnReady(fn func()) *Tray

OnReady registers a callback run once the tray is live (after Run starts).

func (*Tray) Quit

func (t *Tray) Quit()

Quit stops the tray's event loop.

func (*Tray) Run

func (t *Tray) Run() error

Run shows the tray and blocks until Quit. It errors if no backend is set.

func (*Tray) SetIcon

func (t *Tray) SetIcon(iconPNG []byte) *Tray

SetIcon replaces the icon (PNG bytes) and refreshes if running.

func (*Tray) SetMenu

func (t *Tray) SetMenu(m *Menu) *Tray

SetMenu sets the tray menu and refreshes if running.

func (*Tray) SetTooltip

func (t *Tray) SetTooltip(s string) *Tray

SetTooltip sets the hover tooltip and refreshes if running.

func (*Tray) Tooltip

func (t *Tray) Tooltip() string

func (*Tray) WithBackend

func (t *Tray) WithBackend(b Backend) *Tray

WithBackend overrides the platform backend and returns the tray.

Directories

Path Synopsis
examples
traydemo command
Command traydemo is a runnable go-widgets/tray example.
Command traydemo is a runnable go-widgets/tray example.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL