ui

package
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Oct 1, 2026 License: GPL-3.0 Imports: 28 Imported by: 0

Documentation

Overview

Package ui owns the immediate-mode frame tree, controls, editors, input routing and the Wayland run loop behind the public nefergui facade.

Index

Constants

This section is empty.

Variables

View Source
var ErrLockFinished = errors.New("nefergui: session lock finished by the compositor")

ErrLockFinished reports that the compositor refused the session lock or ended it (ext_session_lock_v1.finished). NeferGUI never unlocks in response.

Functions

func Run

func Run[T any](ctx context.Context, model *T, view func(*Frame, *T), options ...WindowOption) error

Run builds and presents an immediate view on the Wayland session owner loop.

func RunFrames

func RunFrames[T any](ctx context.Context, frames int, model *T, view func(*Frame, *T), committed func(uint64) error, options ...WindowOption) error

RunFrames is a deterministic harness entry: each commit requests a redraw.

func RunLock added in v0.3.0

func RunLock(ctx context.Context, cfg LockConfig) (err error)

RunLock acquires ext-session-lock on one connection and shows opaque black on every output through the regular Vulkan/DMA-BUF/explicit-sync path. Outputs added or removed later gain or lose a lock surface. Keyboard input feeds cfg.Secret only through the secret keyboard path. RunLock returns nil after an unlock requested through cfg.Unlock, ErrLockFinished (wrapped) when the compositor ends or refuses the lock, or the first failure; it never unlocks on failure or cancellation (closing the connection keeps the session locked).

Types

type Anchor added in v0.2.0

type Anchor uint8

Anchor is a bit set of output edges a layer surface attaches to.

const (
	AnchorTop Anchor = 1 << iota
	AnchorBottom
	AnchorLeft
	AnchorRight
)

type ButtonEvent

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

Control event values are immutable snapshots; querying them never consumes events.

func (ButtonEvent) Activated

func (e ButtonEvent) Activated() bool

type ButtonOption

type ButtonOption interface {
	// contains filtered or unexported methods
}

type ChangeEvent

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

func (ChangeEvent) Changed

func (e ChangeEvent) Changed() bool

type CommonOption

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

CommonOption is the concrete type of Key, ID, Class and Inline; it belongs to every option family. It is exported only so the root facade can return it.

func Class

func Class(class string) CommonOption

func ID

func ID(id string) CommonOption

func Inline

func Inline(src string) CommonOption

func Key

func Key(key string) CommonOption

type ContainerOption

type ContainerOption interface {
	// contains filtered or unexported methods
}

ContainerOption, ButtonOption and EditOption are separate option families.

type DisabledOption

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

DisabledOption is the concrete type of Disabled. It applies to every interactive control (buttons, value controls and editors) but not to containers or headings. Exported only so the root facade can return it.

func Disabled

func Disabled(v bool) DisabledOption

Disabled blocks focus and interaction on an interactive control.

type EditEvent

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

func (EditEvent) Changed

func (e EditEvent) Changed() bool

func (EditEvent) Submitted

func (e EditEvent) Submitted() bool

type EditOption

type EditOption interface {
	// contains filtered or unexported methods
}

func Password

func Password(v bool) EditOption

func Placeholder

func Placeholder(v string) EditOption

type Frame

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

Frame is valid only during one call to the view function.

func (*Frame) Diagnostics

func (f *Frame) Diagnostics() []string

Diagnostics returns a copy of frame diagnostics (populated with -tags nefergui_debug).

func (*Frame) Root

func (f *Frame) Root(options ...ContainerOption) Node

func (*Frame) SetInputRects added in v0.2.0

func (f *Frame) SetInputRects(rects []Rect) error

SetInputRects stages the input region for the surface: pointer input outside the rectangles passes through. It is applied after the view returns and and committed together with the frame's buffer, with no extra commit. nil restores the whole surface, and a non-nil empty slice makes the surface click-through. Rects need positive size. The slice is copied, so callers may reuse it; an unchanged region costs nothing. If the view never calls it, the Layer config's InputRects stay in effect.

func (*Frame) Size added in v0.2.0

func (f *Frame) Size() (width, height float64)

Size is the logical surface size this frame is laid out against.

type HeadingOption

type HeadingOption interface {
	// contains filtered or unexported methods
}

HeadingOption accepts common CSS options and Level, but not control options.

func Level

func Level(level int) HeadingOption

Level sets the accessibility heading level (1 through 6).

type InputEvent added in v0.2.0

type InputEvent struct {
	Kind      InputKind
	X, Y      float64
	DX, DY    float64
	Button    uint32
	Pressed   bool
	Repeat    bool
	KeyName   string
	Text      string
	Modifiers Modifiers
}

InputEvent is a raw platform event, delivered on the owner loop before the normal control routing. Coordinates are logical, surface-local pixels. Size changes are not input; use OnResize and Frame.Size. Which fields are set depends on Kind:

pointer motion/press/release/axis: X, Y; press/release: Button (evdev code)
and Pressed; axis: DX, DY
key: KeyName, Text, Modifiers, Pressed, Repeat

type InputKind added in v0.2.0

type InputKind uint8

InputKind classifies an InputEvent.

const (
	InputPointerMotion InputKind = iota + 1
	InputPointerPress
	InputPointerRelease
	InputPointerAxis
	InputPointerLeave
	InputKey
	InputFocusIn
	InputFocusOut
	InputReset // platform dropped queued input; treat held state as released
)

type KeyboardMode added in v0.2.0

type KeyboardMode uint8

KeyboardMode is the layer surface keyboard interactivity. The zero value is KeyboardNone: the surface never takes keyboard focus. KeyboardOnDemand needs layer-shell version 4.

const (
	KeyboardNone KeyboardMode = iota
	KeyboardExclusive
	KeyboardOnDemand
)

type LayerConfig added in v0.2.0

type LayerConfig struct {
	Output string // output name; empty lets the compositor choose
	// AllOutputs puts one surface on every output, including outputs added
	// while Run is running; removed outputs lose theirs. Every surface shows
	// the same view and model, laid out at its own size and scale. Run then
	// returns only on cancellation or failure. It excludes Output, keyboard
	// interactivity, OnSurface, OnResize and RunFrames.
	AllOutputs    bool
	Namespace     string // defaults to "nefergui"
	Level         LayerLevel
	Anchors       Anchor
	Keyboard      KeyboardMode
	ExclusiveZone int32
	Margin        [4]int32 // top, right, bottom, left
	// InputRects, when non-nil, restricts pointer input to these rectangles.
	// An empty non-nil slice makes the surface fully click-through. Rects need
	// positive width and height.
	InputRects []Rect
}

LayerConfig requests a wlr-layer-shell surface instead of an xdg toplevel. Size still gives the initial logical size; an axis anchored to both opposite edges is sized by the compositor and reported through OnResize and Frame.Size. ExclusiveZone > 0 asks the compositor to reserve that many logical pixels from an anchored edge (only for one edge, or one edge plus both perpendicular edges); 0 reserves nothing and asks to avoid other surfaces' positive zones; -1 ignores other exclusive zones and extends to the anchored output edges.

type LayerLevel added in v0.2.0

type LayerLevel uint8

LayerLevel is the wlr-layer-shell stacking layer. The zero value is invalid, so a surface never silently lands below every window.

const (
	LayerBackground LayerLevel = iota + 1
	LayerBottom
	LayerTop
	LayerOverlay
)

type LockConfig added in v0.3.0

type LockConfig struct {
	// Display is the Wayland socket name; empty uses the environment.
	Display string
	// Styles is an optional author stylesheet path, as for the Styles option.
	Styles string
	// Secret receives typed input. Required.
	Secret *SecretBuffer
	// View builds the content of the one output that hosts it (the output whose
	// surface has keyboard focus, initially the first). Required. Other outputs
	// show plain opaque black.
	View func(*Frame, LockState)
	// OnLocked runs once on the owner loop when the compositor sends locked.
	OnLocked func()
	// OnSubmit runs on the owner loop when Enter is pressed after locked. It
	// must not block: verification is asynchronous. secret aliases Secret's
	// memory and is valid only during the call; it is wiped right after it
	// returns, so the callee copies or consumes it before returning.
	OnSubmit func(secret []byte)
	// Unlock, when it receives a value, asks RunLock to send
	// unlock_and_destroy, roundtrip and return nil. This is the only unlock
	// path: it is the caller's explicit request after its own verification. A
	// request received before the locked event is held until locked; closing
	// the channel is not a request. A nil channel never unlocks.
	Unlock <-chan struct{}
	// Status delivers the state shown as LockState.Status; each received value
	// schedules a redraw. Optional.
	Status <-chan LockStatus
	// Wake requests a redraw for each received value.
	Wake <-chan struct{}
	// OnOutputError reports an output added after acquisition that could not
	// get a lock surface; the compositor keeps it black. Optional, owner loop.
	OnOutputError func(output string, err error)
}

LockConfig configures RunLock.

type LockState added in v0.3.0

type LockState struct {
	Mask          int        // typed code points, for a mask of that many bullets
	Locked        bool       // the compositor confirmed the lock (locked event)
	Status        LockStatus // latest value received on LockConfig.Status
	Width, Height int        // logical size of the surface hosting the view
}

LockState is what the lock view may know: never the secret itself.

func (LockState) Bullets added in v0.3.0

func (s LockState) Bullets() string

Bullets returns Mask bullet characters.

type LockStatus added in v0.3.0

type LockStatus uint8

LockStatus is an opaque caller-driven state shown by the view, for example while an authentication attempt runs. NeferGUI attaches no meaning to it.

const (
	LockIdle   LockStatus = iota // ready for input
	LockBusy                     // an attempt is being verified
	LockFailed                   // the last attempt was rejected
)

type Modifiers added in v0.2.0

type Modifiers uint8

Modifiers is a bit set of keyboard modifiers held during a key event.

const (
	ModShift Modifiers = 1 << iota
	ModCtrl
)

type Node

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

Node is an ephemeral handle into the current frame. Do not retain it between frames.

func (Node) Aside

func (n Node) Aside(options ...ContainerOption) Node

func (Node) Box

func (n Node) Box(options ...ContainerOption) Node

func (Node) Button

func (n Node) Button(label string, options ...ButtonOption) ButtonEvent

func (Node) Checkbox

func (n Node) Checkbox(label string, value *bool, options ...ButtonOption) ChangeEvent

func (Node) Column

func (n Node) Column(options ...ContainerOption) Node

func (Node) Element

func (n Node) Element(typ string, options ...ContainerOption) Node

func (Node) Footer

func (n Node) Footer(options ...ContainerOption) Node

func (Node) Header

func (n Node) Header(options ...ContainerOption) Node

func (Node) Heading

func (n Node) Heading(text string, options ...HeadingOption)

func (Node) Icon

func (n Node) Icon(name string, options ...ContainerOption)

func (Node) Image

func (n Node) Image(img image.Image, options ...ContainerOption)

Image borrows a decoded Go image. Treat its pixels as immutable while passed to Image; pass a new image value to change pixels. Renderer cache identity requires a comparable image.Image value (for example, *image.RGBA).

func (Node) Input

func (n Node) Input(label string, value *string, options ...EditOption) EditEvent

func (Node) Main

func (n Node) Main(options ...ContainerOption) Node

func (Node) Nav

func (n Node) Nav(options ...ContainerOption) Node

func (Node) Radio

func (n Node) Radio(label, option string, selected *string, options ...ButtonOption) ChangeEvent

func (Node) Rect added in v0.2.0

func (n Node) Rect(x, y, w, h float64) Node

Rect positions the node at x, y with size w, h in logical pixels, relative to the content box of its Stack parent, without CSS parsing or per-frame strings or style copies. The geometry is border-box and overrides authored width, height and margin. Rect is valid only on a direct child of Stack; elsewhere it is ignored, keeping normal flex and block layout, and debug builds (-tags nefergui_debug) report it through Frame.Diagnostics.

func (Node) Row

func (n Node) Row(options ...ContainerOption) Node

func (Node) Scroll

func (n Node) Scroll(options ...ContainerOption) Node

func (Node) Section

func (n Node) Section(options ...ContainerOption) Node

func (Node) Separator

func (n Node) Separator(options ...ContainerOption)

func (Node) Slider

func (n Node) Slider(label string, value *float64, min, max, step float64, options ...ValueOption) ChangeEvent

func (Node) Spacer

func (n Node) Spacer(options ...ContainerOption)

func (Node) Stack

func (n Node) Stack(options ...ContainerOption) Node

func (Node) Text

func (n Node) Text(text string, options ...ContainerOption)

func (Node) Textarea

func (n Node) Textarea(label string, value *string, options ...EditOption) EditEvent

type Rect added in v0.2.0

type Rect struct{ X, Y, Width, Height int32 }

Rect is an integer logical-pixel rectangle in surface coordinates.

type SecretBuffer added in v0.3.0

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

SecretBuffer is a caller-owned fixed-capacity byte buffer for typed secret input. Typed bytes never become a Go string and are never stored in the model, tree or render text; the view only sees Len. Bytes beyond the capacity are dropped. It is used from the lock owner loop only.

func NewSecretBuffer added in v0.3.0

func NewSecretBuffer(capacity int) *SecretBuffer

NewSecretBuffer allocates a buffer holding at most capacity bytes (1..4096).

func (*SecretBuffer) Bytes added in v0.3.0

func (b *SecretBuffer) Bytes() []byte

Bytes returns the typed bytes. The slice aliases the buffer: do not retain it past the next edit or Wipe, and never convert it to a string.

func (*SecretBuffer) Len added in v0.3.0

func (b *SecretBuffer) Len() int

Len is the number of typed code points (the mask count).

func (*SecretBuffer) Wipe added in v0.3.0

func (b *SecretBuffer) Wipe()

Wipe zeroes the buffer. The caller may call it at any time on the owner loop.

type ValueOption

type ValueOption interface {
	// contains filtered or unexported methods
}

ValueOption accepts CSS options and Disabled for pointer-backed controls.

type WaylandSurface added in v0.2.0

type WaylandSurface struct {
	Display *wl.Display
	Surface *core.Surface
}

WaylandSurface exposes the window's Wayland connection and wl_surface so an integrator can register extra protocol objects on the same client, such as clipboard or surface-marking extensions. It is the escape hatch to the underlying wlturbo objects; it does not add any protocol itself.

The values are owned by NeferGUI and valid until Run returns. Do not close the Display, destroy the Surface or attach buffers. Events for objects the callback creates are dispatched on the owner goroutine while requests such as roundtrips run before the event reader starts, and on NeferGUI's reader goroutine afterwards, so handlers must synchronize any state they share.

type WindowOption

type WindowOption interface {
	// contains filtered or unexported methods
}

func Layer added in v0.2.0

func Layer(c LayerConfig) WindowOption

Layer selects a wlr-layer-shell surface for the window.

func OnInput added in v0.2.0

func OnInput(fn func(InputEvent) bool) WindowOption

OnInput delivers every raw input event to fn on the session owner loop, before the event reaches NeferGUI controls; controls still receive it. fn may mutate the model the view reads. It returns true when it changed state the view shows, which schedules a redraw; a false return costs no frame, so pointer motion does not force a build. A nil fn is ignored. fn must not block.

func OnResize added in v0.2.0

func OnResize(fn func(width, height int, scale float64)) WindowOption

OnResize reports the logical size and scale once at start and again only when one of them changes; a change always schedules a redraw. It runs on the owner loop before the frame is built. A nil fn is ignored.

func OnSurface added in v0.2.0

func OnSurface(fn func(context.Context, WaylandSurface) error) WindowOption

OnSurface calls fn once on the owner goroutine, after the surface has its role (xdg toplevel or layer surface) and its first configure, and before the first buffer is attached, so the window is not yet visible. ctx is the Run context: if it is cancelled while fn runs, NeferGUI closes the display so blocking protocol calls fail, and Run returns ctx.Err() (joined with any other error fn returned). A non-nil error aborts Run and closes the session. A nil fn is ignored.

func Size

func Size(w, h int) WindowOption

func Styles

func Styles(s string) WindowOption

func Title

func Title(s string) WindowOption

func Transparent

func Transparent() WindowOption

Transparent requests an alpha-capable Wayland surface (opaque by default).

func Wake added in v0.2.0

func Wake(ch <-chan struct{}) WindowOption

Wake requests a redraw whenever a value arrives on ch, so a view can react to state changed by other goroutines. The caller synchronizes such state; the view still runs only on the owner loop. Closing ch stops forwarding. A nil ch is ignored.

Jump to

Keyboard shortcuts

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