systray

package module
v0.2.1-easyss.1 Latest Latest
Warning

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

Go to latest
Published: Jul 31, 2026 License: MIT Imports: 1 Imported by: 0

README

GoGPU Logo

systray

Pure Go system tray library for Windows, macOS, and Linux
Zero CGO. Cross-platform. Multiple trays. Context menus. Notifications.

CI Coverage Go Reference Go Report Card License Zero CGO


Features

  • Pure Go — zero CGO on all platforms. Single binary, easy cross-compilation
  • Multiple trays — create as many tray icons as you need
  • Context menus — nested menus with checkboxes, separators, icons, and submenus
  • Notifications — balloon tips (Windows), notification center (macOS), D-Bus notifications (Linux)
  • Dark mode — automatic icon switching for light/dark themes (Windows)
  • Template icons — macOS-native monochrome icons that adapt to system theme
  • Builder pattern — fluent API for clean, readable code
  • Message loop — built-in Run() blocks and pumps the platform event loop
  • Standalone — no dependency on gogpu framework. Use in any Go application

Platform Implementation

Platform API Dependency Status
Windows Shell_NotifyIconW (shell32.dll) golang.org/x/sys/windows Implemented
macOS NSStatusBar / NSStatusItem (AppKit) github.com/go-webgpu/goffi Implemented
Linux StatusNotifierItem (D-Bus SNI) github.com/godbus/dbus/v5 Implemented

All platform implementations use Pure Go FFI — no C compiler required.

Installation

go get github.com/gogpu/systray

Requirements: Go 1.25+

Quick Start

package main

import (
    "fmt"
    "os"

    "github.com/gogpu/systray"
)

func main() {
    tray := systray.New()

    // Build context menu
    menu := systray.NewMenu()
    menu.Add("Hello", func() { fmt.Println("Hello clicked!") })
    menu.Add("Show Notification", func() {
        tray.ShowNotification("My App", "Hello from systray!")
    })
    menu.AddSeparator()
    menu.AddCheckbox("Check me", false, func() { fmt.Println("Toggled") })
    menu.AddSeparator()
    menu.Add("Quit", func() {
        tray.Remove()
        os.Exit(0)
    })

    // Configure and show
    tray.SetIcon(iconPNG).
        SetTooltip("My Application").
        SetMenu(menu)
    tray.OnClick(func() { fmt.Println("Left click!") })
    tray.Show()

    // Run the platform message loop (blocks until Quit)
    if err := tray.Run(); err != nil {
        fmt.Println("error:", err)
    }
}

API Reference

SystemTray

// Create and lifecycle
tray := systray.New()              // Create a new system tray icon
tray.Show()                        // Show tray icon
tray.Hide()                        // Hide tray icon (without removing)
tray.Run()                         // Block and pump the platform message loop
tray.Remove()                      // Destroy tray icon and release resources

// Icon management
tray.SetIcon(png []byte)           // Set tray icon (PNG format)
tray.SetDarkModeIcon(png []byte)   // Auto-switch in dark mode (Windows)
tray.SetTemplateIcon(png []byte)   // macOS template image (monochrome)

// Text and menu
tray.SetTooltip(text string)       // Hover tooltip
tray.SetMenu(menu *Menu)           // Attach context menu

// Events
tray.OnClick(fn func())            // Left click handler
tray.OnDoubleClick(fn func())      // Double click handler
tray.OnRightClick(fn func())       // Right click handler

// Notifications
tray.ShowNotification(title, message string)  // OS-level notification

// Position (for window placement near tray)
x, y, w, h := tray.Bounds()       // Tray icon screen position

All setter methods return *SystemTray for fluent chaining:

tray.SetIcon(icon).SetTooltip("Ready").SetMenu(menu).Show()

Menu

menu := systray.NewMenu()

item := menu.Add("Label", onClick)                   // Normal item → *MenuItem
check := menu.AddCheckbox("Toggle", checked, onChange) // Checkbox → *MenuItem
menu.AddSeparator()                                    // Separator → *Menu (chaining)
sub := menu.AddSubmenu("More", submenu)                // Submenu → *MenuItem
icon := menu.AddWithIcon("Save", iconPNG, onClick)     // With icon → *MenuItem

Add, AddCheckbox, AddSubmenu, AddWithIcon return *MenuItem for dynamic updates. AddSeparator returns *Menu for chaining.

Dynamic Menu Updates

Update menu items at runtime from any goroutine — thread-safe, changes are applied in-place via native platform APIs (no menu rebuild). On macOS, updates are automatically dispatched to the main thread:

item.SetLabel("New Label")     // Change display text
check.SetChecked(false)        // Change checked state
sub.SetDisabled(true)          // Disable/enable
icon.SetIcon(newIconPNG)       // Change icon

Multiple Trays

// Each tray is independent with its own icon, menu, and handlers
mainTray := systray.New().SetIcon(appIcon).SetMenu(mainMenu).Show()
statusTray := systray.New().SetIcon(statusIcon).SetTooltip("Status: OK").Show()

Dark Mode

systray supports automatic icon switching based on the system theme.

Windows — Use SetDarkModeIcon() to provide an alternative icon for dark mode. The library detects theme changes via WM_SETTINGCHANGE with "ImmersiveColorSet" and switches icons automatically:

tray.SetIcon(lightIcon).SetDarkModeIcon(darkIcon)

macOS — Use SetTemplateIcon() with a monochrome PNG. macOS renders template images with the correct color for the current menu bar appearance (light or dark). Only the alpha channel matters:

tray.SetTemplateIcon(monochromeIcon)

Linux — The SNI protocol delivers the icon pixmap to the desktop environment, which handles theme adaptation. No special API is needed.

Notifications

ShowNotification sends an OS-level notification from the tray icon:

tray.ShowNotification("Update Available", "Version 2.0 is ready to install.")
Platform Mechanism Notes
Windows Balloon tip (Shell_NotifyIconW + NIF_INFO) Appears near the tray icon
macOS NSUserNotification / Notification Center Requires notification permission on macOS 13+
Linux org.freedesktop.Notifications D-Bus Works on GNOME, KDE, XFCE, and other FreeDesktop-compliant DEs

Icon Guidelines

Platform Recommended Size Format Notes
Windows 16x16, 32x32 PNG Provide both sizes for standard and HiDPI
macOS 22x22, 44x44 (@2x) PNG Must be monochrome (template) for proper theme adaptation
Linux 22x22, 24x24 PNG SNI spec recommends 22x22

Input format: PNG bytes ([]byte). The library handles conversion to native format (HICON, NSImage, ARGB pixmap) internally.

For macOS, use SetTemplateIcon() with a monochrome PNG (only alpha channel matters). The system automatically adjusts the icon color for light/dark menu bar.

Architecture

systray.New()  ->  SystemTray (public API)
                       |
                  PlatformTray (internal interface)
                       |
          +------------+------------+
          |            |            |
     Win32 impl   macOS impl   Linux impl
     Shell_Notify  NSStatusBar   D-Bus SNI
     IconW         NSStatusItem  StatusNotifierItem

Follows the Qt6 QPlatformSystemTrayIcon three-layer pattern. Each platform implementation is isolated in its own file with build constraints.

Usage with gogpu

While systray is fully standalone, it integrates seamlessly with the gogpu application framework:

import (
    "github.com/gogpu/gogpu"
    "github.com/gogpu/systray"
)

app := gogpu.NewApp(config)

// Create tray through the app (lifecycle managed automatically)
tray := systray.New()
tray.SetIcon(icon).SetMenu(menu).Show()

// Minimize to tray pattern
app.SetQuitBehavior(gogpu.QuitOnExplicitQuit)
app.OnClose(func() bool {
    app.Hide()       // hide window instead of closing
    return false     // reject close
})
tray.OnClick(func() {
    app.Show()       // restore window on tray click
})

Comparison with Alternatives

Feature gogpu/systray getlantern/systray fyne-io/systray
Pure Go (zero CGO) Yes No (CGO on macOS/Linux) No (CGO on macOS/Linux)
Multiple trays Yes No (single global) No (single global)
Dark mode icons Yes No No
Template icons (macOS) Yes No Yes
Nested menus Yes Yes Yes
Menu item icons Yes No No
Notifications Yes No No
Builder pattern Yes No No
Built-in message loop Yes Yes Yes
Wayland support Yes (D-Bus SNI) No Partial

Contributing

We welcome contributions! See CONTRIBUTING.md for guidelines.

Part of the GoGPU Ecosystem

systray is part of the GoGPU ecosystem — 790K+ lines of Pure Go, zero CGO. A GPU computing platform with a WebGPU implementation, shader compiler, 2D graphics library, and GUI toolkit.

Library Purpose
gogpu Application framework, windowing
wgpu Pure Go WebGPU (Vulkan/Metal/DX12/GLES)
naga Shader compiler (WGSL to SPIR-V/MSL/GLSL/HLSL/DXIL)
gg 2D graphics with GPU acceleration
ui GUI toolkit (22+ widgets, 4 themes)
systray System tray (this library)

License

MIT License — see LICENSE for details.

Documentation

Overview

Package systray provides a cross-platform system tray (notification area) library for Go applications. It supports Windows, macOS, and Linux with zero CGO dependencies.

Key features:

  • Multiple independent tray icons per application
  • Context menus with nested submenus, checkboxes, and separators
  • OS-level notifications (balloon tips, notification center, D-Bus)
  • Dark mode icon switching and macOS template images
  • Builder pattern for fluent API

Platform implementations:

  • Windows: Shell_NotifyIconW via golang.org/x/sys/windows
  • macOS: NSStatusBar/NSStatusItem via go-webgpu/goffi ObjC runtime
  • Linux: StatusNotifierItem (SNI) via godbus/dbus D-Bus protocol

Quick start:

tray := systray.New()
tray.SetIcon(iconPNG).SetTooltip("My App").SetMenu(menu).Show()

Part of the GoGPU ecosystem: https://github.com/gogpu

Index

Constants

View Source
const (
	MenuItemNormal    = internal.MenuItemNormal
	MenuItemCheckbox  = internal.MenuItemCheckbox
	MenuItemSeparator = internal.MenuItemSeparator
	MenuItemSubmenu   = internal.MenuItemSubmenu
)

Variables

This section is empty.

Functions

This section is empty.

Types

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

Menu represents a context menu for a system tray icon.

func NewMenu

func NewMenu() *Menu

NewMenu creates an empty context menu.

func (m *Menu) Add(label string, onClick func()) *MenuItem

Add appends a normal menu item and returns it for dynamic updates.

func (m *Menu) AddCheckbox(label string, checked bool, onClick func()) *MenuItem

AddCheckbox appends a checkbox menu item and returns it for dynamic updates.

func (m *Menu) AddSeparator() *Menu

AddSeparator appends a visual separator.

func (m *Menu) AddSubmenu(label string, submenu *Menu) *MenuItem

AddSubmenu appends a nested submenu and returns the item for dynamic updates.

func (m *Menu) AddWithIcon(label string, icon []byte, onClick func()) *MenuItem

AddWithIcon appends a normal menu item with a PNG icon.

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

MenuItem represents a single item in a context menu. Use SetLabel, SetChecked, SetDisabled, SetIcon for dynamic updates.

func (item *MenuItem) SetChecked(checked bool)

SetChecked changes the checked state.

func (item *MenuItem) SetDisabled(disabled bool)

SetDisabled changes the enabled/disabled state.

func (item *MenuItem) SetIcon(png []byte)

SetIcon changes the menu item icon.

func (item *MenuItem) SetLabel(label string)

SetLabel changes the display text and updates the native menu item.

type MenuItemType = internal.MenuItemType

MenuItemType identifies the kind of menu item.

type SystemTray

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

SystemTray represents a system tray icon with context menu. Create with New(). All setter methods return *SystemTray for chaining.

func New

func New() *SystemTray

New creates a new system tray icon.

func (*SystemTray) Bounds

func (t *SystemTray) Bounds() (x, y, w, h int)

Bounds returns the tray icon's screen position (x, y, width, height).

func (*SystemTray) Hide

func (t *SystemTray) Hide() *SystemTray

Hide makes the tray icon invisible without removing it.

func (*SystemTray) ID

func (t *SystemTray) ID() TrayID

ID returns the unique identifier for this tray icon.

func (*SystemTray) OnClick

func (t *SystemTray) OnClick(fn func()) *SystemTray

OnClick registers a left-click handler.

func (*SystemTray) OnDoubleClick

func (t *SystemTray) OnDoubleClick(fn func()) *SystemTray

OnDoubleClick registers a double-click handler.

func (*SystemTray) OnRightClick

func (t *SystemTray) OnRightClick(fn func()) *SystemTray

OnRightClick registers a right-click handler.

func (*SystemTray) Remove

func (t *SystemTray) Remove()

Remove destroys the tray icon and releases all resources.

func (*SystemTray) Run

func (t *SystemTray) Run() error

Run blocks the calling goroutine, pumping the platform message loop. Call from main() after Show(). Returns when Quit() is called.

func (*SystemTray) SetDarkModeIcon

func (t *SystemTray) SetDarkModeIcon(png []byte) *SystemTray

SetDarkModeIcon sets an alternative icon for dark mode (Windows). When set, the tray automatically switches between the light and dark icons based on the system theme. On Windows, theme changes are detected via WM_SETTINGCHANGE with "ImmersiveColorSet".

func (*SystemTray) SetIcon

func (t *SystemTray) SetIcon(png []byte) *SystemTray

SetIcon sets the tray icon from PNG bytes.

func (*SystemTray) SetMenu

func (t *SystemTray) SetMenu(menu *Menu) *SystemTray

SetMenu attaches a context menu to the tray icon.

func (*SystemTray) SetTemplateIcon

func (t *SystemTray) SetTemplateIcon(png []byte) *SystemTray

SetTemplateIcon sets a macOS template image (monochrome, adapts to theme).

func (*SystemTray) SetTooltip

func (t *SystemTray) SetTooltip(text string) *SystemTray

SetTooltip sets the hover tooltip text.

func (*SystemTray) Show

func (t *SystemTray) Show() *SystemTray

Show makes the tray icon visible.

func (*SystemTray) ShowNotification

func (t *SystemTray) ShowNotification(title, message string) *SystemTray

ShowNotification displays an OS-level notification.

type TrayID

type TrayID uint32

TrayID uniquely identifies a system tray icon. Zero is invalid.

Directories

Path Synopsis
examples
basic command
multi-tray command
Example multi-tray demonstrates running two independent system tray icons simultaneously within the same application.
Example multi-tray demonstrates running two independent system tray icons simultaneously within the same application.
notification command
Example notification demonstrates OS-level notifications from a system tray icon.
Example notification demonstrates OS-level notifications from a system tray icon.
darwin
Package darwin provides a minimal Objective-C runtime wrapper for the systray package.
Package darwin provides a minimal Objective-C runtime wrapper for the systray package.

Jump to

Keyboard shortcuts

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