app

package
v0.1.10 Latest Latest
Warning

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

Go to latest
Published: Apr 7, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package app provides the bridge between the UI widget tree and the windowing system.

The app package connects gogpu/ui widgets to a real window via gpucontext interfaces (WindowProvider, PlatformProvider, EventSource). This enables dependency inversion: ui depends on gpucontext interfaces, while gogpu implements those interfaces.

Architecture

App is the main entry point. It holds a Window, theme, and scheduler. Window manages the widget tree and coordinates layout, draw, and event dispatch. EventBridge translates platform-level events from gpucontext into ui/event types that widgets understand.

user code
   |
   v
app.New(opts...)  -->  App  -->  Window  -->  widget tree
                        |            |
                     Theme      EventBridge
                        |            |
                     Scheduler   gpucontext.EventSource

Usage

Create an App with functional options, set a root widget, and let the host application (gogpu.App) drive the render loop:

// In the host application (e.g., gogpu.App's draw callback):
uiApp := app.New(
    app.WithWindowProvider(wp),
    app.WithPlatformProvider(pp),
    app.WithEventSource(es),
)
uiApp.SetRoot(myRootWidget)

// Each frame, the host calls:
uiApp.Frame()

Headless Mode

When no providers are supplied, the App operates in headless mode. This is useful for testing and batch processing:

uiApp := app.New() // headless, no window
uiApp.SetRoot(myWidget)
uiApp.Frame() // performs layout and draw with defaults

Thread Safety

App and Window are NOT safe for concurrent access. All operations must occur on the main/UI thread. This matches the single-threaded event loop model of windowing systems.

Design Principles

  • Dependency inversion: ui imports gpucontext interfaces, not gogpu
  • No goroutines: everything runs on the caller's thread
  • No global state: App is instance-based
  • Testable: mock providers enable isolated testing
  • Composable: functional options for configuration

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type App

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

App is the main entry point for the UI framework.

App bridges the widget tree with the windowing system through gpucontext interfaces. It manages the Window, theme, and scheduler.

Create an App with New and functional options.

func New

func New(opts ...Option) *App

New creates a new App with the given options.

When no options are provided, the App operates in headless mode with default settings suitable for testing.

func (*App) Frame

func (a *App) Frame()

Frame performs one complete frame: layout, draw, and state management.

This method should be called by the host application's render loop (e.g., gogpu.App's draw callback).

func (*App) HandleEvent

func (a *App) HandleEvent(e event.Event)

HandleEvent dispatches a single event to the widget tree.

This method is an alternative to using an EventSource. It allows the host application to push events manually.

func (*App) Scheduler

func (a *App) Scheduler() *state.Scheduler

Scheduler returns the App's state scheduler.

func (*App) SetFrameCallback

func (a *App) SetFrameCallback(cb FrameCallback)

SetFrameCallback sets a callback that is invoked after each Frame call with timing statistics.

Set to nil to disable statistics tracking. The callback is called synchronously on the same goroutine as Frame().

func (*App) SetRoot

func (a *App) SetRoot(root widget.Widget)

SetRoot sets the root widget for the App's window.

The root widget forms the top of the widget tree. It receives layout constraints matching the window size and is drawn to fill the window.

func (*App) SetTheme

func (a *App) SetTheme(t *theme.Theme)

SetTheme changes the App's theme.

This updates both the App and Window theme and triggers a full redraw.

func (*App) Theme

func (a *App) Theme() *theme.Theme

Theme returns the App's current theme.

func (*App) Window

func (a *App) Window() *Window

Window returns the App's Window.

type FrameCallback

type FrameCallback func(stats FrameStats)

FrameCallback is called after each frame completes with timing statistics.

This is useful for frame time monitoring and adaptive rendering. The callback is invoked synchronously at the end of each Frame() call.

type FrameStats

type FrameStats struct {
	// FrameStart is the time when Frame() was called.
	FrameStart time.Time

	// LayoutDuration is how long the layout pass took.
	// Zero if layout was not performed this frame.
	LayoutDuration time.Duration

	// DrawDuration is how long the draw pass took.
	DrawDuration time.Duration

	// TotalDuration is the total time spent in Frame().
	TotalDuration time.Duration

	// LayoutPerformed indicates whether layout was recalculated this frame.
	LayoutPerformed bool

	// DrawSkipped indicates that the draw pass was skipped because no
	// widgets in the tree needed re-rendering. When true, the host
	// application can reuse the previous frame's GPU framebuffer output.
	//
	// This is the primary retained-mode optimization: idle UIs skip
	// rendering entirely, consuming zero CPU for the draw phase.
	DrawSkipped bool

	// DrawStats provides per-widget statistics from the draw traversal.
	//
	// When DrawSkipped is true, DrawStats is zero-valued (no traversal
	// was performed). When DrawSkipped is false, DrawStats shows how many
	// widgets were drawn, how many were dirty vs clean, and how many were
	// skipped due to invisibility.
	//
	// This is primarily useful for performance monitoring and for
	// validating that the retained-mode dirty-tracking system is
	// working correctly.
	DrawStats widget.DrawStats
}

FrameStats holds timing information for a single frame.

This is useful for performance monitoring and debugging. FrameStats is passed to the FrameCallback after each call to App.Frame or Window.Frame.

type Option

type Option func(*appConfig)

Option configures an App during creation.

func WithEventSource

func WithEventSource(es gpucontext.EventSource) Option

WithEventSource sets the event source for the App.

The EventSource delivers input events (keyboard, mouse, scroll, resize, focus) from the host application. When nil, no events are delivered.

func WithPlatformProvider

func WithPlatformProvider(pp gpucontext.PlatformProvider) Option

WithPlatformProvider sets the platform provider for the App.

The PlatformProvider provides OS integration features such as clipboard, cursor management, and accessibility preferences. When nil, these features are unavailable.

func WithTheme

func WithTheme(t *theme.Theme) Option

WithTheme sets the theme for the App.

When nil, the default light theme is used.

func WithWindowProvider

func WithWindowProvider(wp gpucontext.WindowProvider) Option

WithWindowProvider sets the window provider for the App.

The WindowProvider provides window geometry (Size, ScaleFactor) and the ability to request redraws. When nil, the App operates in headless mode with a default 800x600 window at 1x scale.

type Window

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

func (*Window) Context

func (w *Window) Context() *widget.ContextImpl

Context returns the widget context used for layout, draw, and events.

func (*Window) DrawTo

func (w *Window) DrawTo(canvas widget.Canvas) bool

DrawTo performs the draw pass using the provided canvas.

This method is called by the host application when it has a canvas ready for drawing. It draws the root widget tree and then all overlays on top.

With retained-mode rendering, DrawTo checks whether any widget in the tree actually needs re-rendering. If not, it returns false to indicate that the host application can skip uploading the canvas to the GPU (the previous frame's output is still valid).

Returns true if rendering was performed, false if the draw was skipped because no widgets changed since the last draw.

func (*Window) FocusManager

func (w *Window) FocusManager() *ifocus.Manager

FocusManager returns the window's focus manager.

The focus manager handles Tab/Shift+Tab navigation between focusable widgets and supports registering global keyboard shortcuts.

func (*Window) Frame

func (w *Window) Frame()

Frame performs one complete frame cycle.

The frame cycle consists of:

  1. Update time tracking
  2. Flush pending scheduler updates
  3. Perform layout if needed
  4. Draw the widget tree
  5. Sync cursor state to platform
  6. Clear invalidation flags

Frame is a no-op if there is no root widget.

func (*Window) HandleEvent

func (w *Window) HandleEvent(e event.Event)

HandleEvent dispatches a single event to the widget tree.

Events are first offered to the overlay stack (top overlay has priority). If no overlay consumes the event (and no modal overlay blocks it), key events are offered to the focus manager for Tab/Shift+Tab navigation and registered shortcuts. Finally, unconsumed events are propagated to the root widget.

func (*Window) HandleFocusChange

func (w *Window) HandleFocusChange(focused bool)

HandleFocusChange processes a window focus change.

func (*Window) HandleResize

func (w *Window) HandleResize(width, height int)

HandleResize processes a window resize.

This updates the window size and marks layout as needing recalculation.

func (*Window) HoveredWidget

func (w *Window) HoveredWidget() widget.Widget

HoveredWidget returns the widget currently under the mouse pointer, or nil if no widget is hovered.

func (*Window) LastDrawStats

func (w *Window) LastDrawStats() widget.DrawStats

LastDrawStats returns the per-widget statistics from the most recent draw traversal (either via Window.DrawTo or the headless draw path inside Window.Frame).

When the last frame was skipped (no dirty widgets), the returned stats are zero-valued.

func (*Window) NeedsLayout

func (w *Window) NeedsLayout() bool

NeedsLayout returns true if layout needs recalculation.

func (*Window) NeedsRedraw

func (w *Window) NeedsRedraw() bool

NeedsRedraw reports whether any widget in the tree needs re-rendering.

When this returns false, the host application can skip calling Window.DrawTo and reuse the previous frame's output from the GPU framebuffer. This is the primary optimization of retained-mode rendering: idle UIs consume zero CPU for rendering.

func (*Window) Overlays

func (w *Window) Overlays() *overlay.Stack

Overlays returns the window's overlay stack.

func (*Window) Root

func (w *Window) Root() widget.Widget

Root returns the current root widget, or nil if none is set.

func (*Window) SetRoot

func (w *Window) SetRoot(root widget.Widget)

SetRoot sets the root widget for this window.

Setting a new root triggers a full layout on the next Frame call. The old root tree is unmounted and the new root tree is mounted, which triggers signal binding setup/teardown via widget.Lifecycle.

func (*Window) Theme

func (w *Window) Theme() *theme.Theme

Theme returns the window's current theme.

func (*Window) WindowSize

func (w *Window) WindowSize() geometry.Size

WindowSize returns the current window size in logical pixels.

Jump to

Keyboard shortcuts

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