Skip to content

Repository files navigation

application — cross-platform application lifecycle for go-widgets

CI Go Reference License: BSD-3-Clause

The layer above go-widgets/window: where window presents a single surface, application owns the whole app lifecycle. It opens the native OS window, drives its run loop, blits the handler's own RGBA framebuffer into it, composes a system-tray / menu-bar icon alongside the window (via go-widgets/tray), threads the live system appearance (dark/light, accent, system font) into the handler, translates native input into the toolkit's event vocabulary, publishes an accessibility tree, and fires a ready callback once the first frame is on screen. No WebKit, no wasm, no HTTP — every widget is drawn by the framework and the window is just a bitmap surface plus a native event source. Everything is CGO_ENABLED=0.

Opening a real OS window and pumping its event loop is a launch-verified boundary, so the native Run path is excluded from the coverage gate (like the wasm glue elsewhere); the contract, the event translation, the present gating, the appearance pump, the launch-height seam and the ready-after-first-frame counter are all unit-tested to 100%.

platform native window (go-widgets/window) native tray (go-widgets/tray)
darwin Cocoa / NSWindow (purego + the Obj-C runtime) NSStatusItem + NSMenu
windows win32 (golang.org/x/sys/windows syscalls) Shell_NotifyIcon + TrackPopupMenu
linux X11 / Wayland (pure-Go wire protocols) StatusNotifierItem over DBus

The tray's native backends are opt-in via the tray_native build tag; without it the tray is a harmless no-op and the window still runs, so a headless build or a platform without native tray support degrades gracefully.

Usage

package main

import (
	"github.com/go-widgets/application"
	"github.com/go-widgets/tray"
)

func main() {
	spec := application.Spec{
		Name:       "News Reader",
		Identifier: "com.example.reader",
		Version:    "1.0.0",
		Icon:       iconPNG, // []byte, optional
		Tray: func() *tray.Menu { // optional
			return tray.NewMenu().Add(
				tray.Item("Refresh", func() { app.Refresh() }),
				tray.Item("Quit", func() { app.Quit() }),
			)
		},
	}

	cfg := application.Config{Title: "News Reader", Width: 1200, Height: 800}

	// handler renders the app's own framebuffer and takes its input; onReady
	// fires once, after the first frame is visible.
	err := application.Run(spec, cfg, handler, func() {
		log.Println("first frame is on screen")
	})
	if err != nil {
		log.Fatal(err)
	}
}

handler implements application.Handler (Frame / Resize / MouseDown / MouseMove / MouseUp / Scroll / Key). It may additionally implement any of the optional capability interfaces — AppearanceSink, ShortcutSink, SecondaryClicker, ContextMenuHost, ClipboardController, Accessible — and the run loop, which never wraps the handler, will honour each one it finds.

For a non-window host (a desktop shell, wasmdesk, a tab in something larger), Bind(handler, scale) and BindScaled(handler, scaleOf) return a *toolkit.Surface wired to the same handler without opening a window.

License

BSD-3-Clause. See LICENSE.

About

Cross-platform application lifecycle for go-widgets: window run loop + system tray + ready hook, CGO-free

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages