Help us shape the future of Go! Take the 2026 Go Developer Survey

tray

package
v0.37.1 Latest Latest
Warning

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

Go to latest
Published: Oct 21, 2026 License: MIT Imports: 34 Imported by: 0

Documentation

Overview

Package tray is bentoo-tray's event loop and its notification and icon policy.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrAlreadyRunning is returned by Run when another process owns the
	// session bus name.
	ErrAlreadyRunning = errors.New("another bentoo-tray instance owns the session bus name")
	// ErrBusLost is returned by Run when the session bus connection is lost
	// while running.
	ErrBusLost = errors.New("the session bus connection was lost")
)

Functions

This section is empty.

Types

type App

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

App is bentoo-tray's event loop. All of its fields belong to the goroutine running Run. The only other goroutines it starts are the URL openings and the update checks, which report back over a channel, and the bounded release of the bus name at a stop; none touches a field.

func New

func New(d Deps) *App

New returns an App over d.

func (*App) Run

func (a *App) Run(ctx context.Context) error

Run owns the bus name, loads the state, starts the icon and runs the loop until ctx is done, the user quits or the bus is lost. A stop saves the state and releases the name, returning nil; a lost bus saves and returns ErrBusLost; another owner of the name is ErrAlreadyRunning. Any other error is a startup failure.

type BusOwner

type BusOwner interface {
	Acquire(ctx context.Context) (acquired bool, err error)
	Release() error
	Lost() <-chan struct{}
}

BusOwner owns the session bus name; *dbusx.Owner implements it.

type Clock

type Clock interface {
	Now() time.Time
	After(d time.Duration) <-chan time.Time
}

Clock is the App's source of time. After is used for every schedule, so a test can drive the loop with a manual clock.

type Deps

type Deps struct {
	Log    *slog.Logger
	Clock  Clock
	Rand   func() float64
	Config config.TrayConfig
	Feed   FeedFetcher
	News   NewsReader
	Pkgs   InstalledReader
	Notify Notifier
	Icon   TrayIcon
	Open   Opener
	Net    NetworkMonitor
	Store  StateStore
	Bus    BusOwner

	Sys       SystemReader
	DiskPaths []string
	Monitors  *config.Monitors

	Emerge            EmergeReader
	EmergeStartFailed bool
	Mounts            MountReader
	PortageTmp        string

	SystemUnits            UnitMonitor
	SystemUnitsProbeFailed bool
	UserUnits              UnitMonitor
	UserUnitsProbeFailed   bool
	Smart                  SmartMonitor
	SmartProbeFailed       bool

	Updates       *pending.Command
	GLSA          *pending.Command
	Repos         []news.Repo
	RepoRevisions string
	EmergeRunning func() (bool, error)
	Run           func(context.Context, pending.Command) (pending.Result, error)
	SyncTime      func(location string) (time.Time, bool, error)
}

Deps is everything the App talks to. Feed is nil when the feed URL was refused: the App then runs on the offline news alone. A nil Log discards, a nil Clock is the SystemClock, a nil Rand is math/rand/v2's Float64 and a nil Net behaves as netmon.Absent(). A nil Sys turns the disk, memory and CPU monitors off; DiskPaths are the watched paths, and a nil Monitors is resolved from Config. A nil Emerge or Mounts turns the emerge or the read-only monitor off; PortageTmp is PORTAGE_TMPDIR, empty when unknown, and EmergeStartFailed reports that the emerge log could not be opened at start-up, a failure the caller has logged already. A nil SystemUnits or UserUnits leaves that systemd manager unwatched, and a nil Smart turns the SMART monitor off; SystemUnitsProbeFailed, UserUnitsProbeFailed and SmartProbeFailed report that the caller's start-up question to that monitor failed and was logged already. A nil Updates or GLSA leaves that update check unrun (the caller found no such command); Repos are the repositories whose sync age is watched, RepoRevisions the stamp every sync rewrites ("" watches none), and EmergeRunning the emerge scan the update check uses when Sys is nil. Run and SyncTime are pending.Run and news.SyncTime when nil. Every other field is required.

type EmergeReader added in v0.37.0

type EmergeReader interface {
	Read() ([]sysmon.EmergeEvent, error)
}

EmergeReader returns the emerge log events appended since its last read; *sysmon.EmergeFollower implements it.

type FeedFetcher

type FeedFetcher interface {
	Fetch(ctx context.Context, etag string) (feed.Result, error)
}

FeedFetcher fetches the notices feed; *feed.Fetcher implements it.

type InstalledReader

type InstalledReader interface {
	Installed(ctx context.Context) (pkgs []pkgdb.Package, skipped int, err error)
}

InstalledReader lists the installed packages; pkgdb.Reader implements it.

type MountReader added in v0.37.0

type MountReader interface {
	Mounts() ([]sysmon.Mount, error)
}

MountReader reads the mount table; sysmon.Reader implements it.

type NetworkMonitor

type NetworkMonitor interface {
	Allowed(ctx context.Context) (netmon.Verdict, error)
	Changed() <-chan struct{}
}

NetworkMonitor reports NetworkManager's view of the network; *netmon.Monitor implements it.

type NewsReader

type NewsReader interface {
	Unread(ctx context.Context) ([]notices.Notice, error)
	Changed() <-chan struct{}
}

NewsReader reads the bentoo repository's unread news; *news.Reader implements it. Items returned together with an error are a partial result. Changed fires when the unread list changed.

type Notifier

type Notifier interface {
	Send(ctx context.Context, m notify.Message) (uint32, error)
	Close(ctx context.Context, id uint32, key string) error
	Events() <-chan notify.Event
}

Notifier sends desktop notifications, withdraws the system ones and reports the actions taken on them; *notify.Notifier implements it. Close withdraws the notification Send returned as id for the condition key.

type Opener

type Opener interface {
	Open(ctx context.Context, url, activationToken string) error
}

Opener opens a notice URL; *portal.Opener implements it.

type SmartMonitor added in v0.37.0

type SmartMonitor interface {
	Drives(ctx context.Context) ([]smartmon.Drive, error)
	Changed() <-chan struct{}
}

SmartMonitor lists udisks2's drives with their SMART verdict; *smartmon.Monitor implements it. Drives returns the well-formed drives together with an error for the malformed ones. Changed fires when a verdict may have changed or a drive came or went, and is closed when the system bus connection is lost.

type StateStore

type StateStore interface {
	Load() (state.State, error)
	Save(st state.State) error
}

StateStore loads and saves the state file; *state.Store implements it.

type SystemClock

type SystemClock struct {
	Done <-chan struct{}
}

SystemClock is the wall clock. Its timers keep wall-clock deadlines: Go's runtime timers count CLOCK_MONOTONIC, which stops while the machine is suspended, so a plain time.After(d) armed at 22:00 for "until 08:00" would fire hours late after a night in suspend. A SystemClock timer fires at most wallPoll after its wall-clock deadline, suspend or not.

Each pending timer is a goroutine that exits when it fires or when Done is closed; a nil Done keeps abandoned timers alive until their deadline.

func (SystemClock) After

func (c SystemClock) After(d time.Duration) <-chan time.Time

After returns a channel that receives the time once the wall clock has reached now + d.

func (SystemClock) Now

func (SystemClock) Now() time.Time

Now returns time.Now().

type SystemReader added in v0.37.0

type SystemReader interface {
	Memory() (sysmon.Memory, error)
	Pressure(resource string) (sysmon.Pressure, error)
	Disk(path string) (sysmon.Disk, error)
	EmergeRunning() (bool, error)
}

SystemReader reads the host figures the health monitors watch; sysmon.Reader implements it. Its reads take no context: each is a short procfs or statfs call.

type TrayIcon

type TrayIcon interface {
	Start(ctx context.Context) error
	SetState(v sni.View)
	Events() <-chan sni.Event
}

TrayIcon is the StatusNotifierItem; *sni.Item implements it. The context given to Start bounds the item's lifetime, not only the call.

type UnitMonitor added in v0.37.0

type UnitMonitor interface {
	Failed(ctx context.Context) ([]unitmon.Unit, error)
	Changed() <-chan struct{}
}

UnitMonitor lists the failed units of one systemd manager; *unitmon.Monitor implements it. Changed fires when a unit's state may have changed, and is closed when the manager's bus connection is lost.

Directories

Path Synopsis
Package feed fetches the bentoo notices feed over HTTPS with ETag revalidation, a body size cap and a request deadline.
Package feed fetches the bentoo notices feed over HTTPS with ETag revalidation, a body size cap and a request deadline.
Package icons holds the tray icon as SNI pixmaps.
Package icons holds the tray icon as SNI pixmaps.
Package messages is bentoo-tray's message catalog: every menu label, notification text and summary format the tray shows, in English, in one place.
Package messages is bentoo-tray's message catalog: every menu label, notification text and summary format the tray shows, in English, in one place.
Package schedule holds the pure timing functions of bentoo-tray: the startup delay, the jittered check interval and the failure backoff.
Package schedule holds the pure timing functions of bentoo-tray: the startup delay, the jittered check interval and the failure backoff.
Package state persists bentoo-tray's state: the feed ETag and serial, the read state and source of every notice, the pause end, the backoff and the earliest next fetch.
Package state persists bentoo-tray's state: the feed ETag and serial, the read state and source of every notice, the pause end, the backoff and the earliest next fetch.
Package version is bentoo-tray's own version, independent of the bentoolkit release it ships in.
Package version is bentoo-tray's own version, independent of the bentoolkit release it ships in.

Jump to

Keyboard shortcuts

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