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 ¶
- type App
- func (a *App) Frame()
- func (a *App) HandleEvent(e event.Event)
- func (a *App) Scheduler() *state.Scheduler
- func (a *App) SetFrameCallback(cb FrameCallback)
- func (a *App) SetRoot(root widget.Widget)
- func (a *App) SetTheme(t *theme.Theme)
- func (a *App) Theme() *theme.Theme
- func (a *App) Window() *Window
- type FrameCallback
- type FrameStats
- type Option
- type Window
- func (w *Window) Context() *widget.ContextImpl
- func (w *Window) DrawTo(canvas widget.Canvas) bool
- func (w *Window) FocusManager() *ifocus.Manager
- func (w *Window) Frame()
- func (w *Window) HandleEvent(e event.Event)
- func (w *Window) HandleFocusChange(focused bool)
- func (w *Window) HandleResize(width, height int)
- func (w *Window) HoveredWidget() widget.Widget
- func (w *Window) LastDrawStats() widget.DrawStats
- func (w *Window) NeedsLayout() bool
- func (w *Window) NeedsRedraw() bool
- func (w *Window) Overlays() *overlay.Stack
- func (w *Window) Root() widget.Widget
- func (w *Window) SetRoot(root widget.Widget)
- func (w *Window) Theme() *theme.Theme
- func (w *Window) WindowSize() geometry.Size
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 ¶
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 ¶
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) 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 ¶
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.
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 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 ¶
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 ¶
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:
- Update time tracking
- Flush pending scheduler updates
- Perform layout if needed
- Draw the widget tree
- Sync cursor state to platform
- Clear invalidation flags
Frame is a no-op if there is no root widget.
func (*Window) HandleEvent ¶
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 ¶
HandleFocusChange processes a window focus change.
func (*Window) HandleResize ¶
HandleResize processes a window resize.
This updates the window size and marks layout as needing recalculation.
func (*Window) HoveredWidget ¶
HoveredWidget returns the widget currently under the mouse pointer, or nil if no widget is hovered.
func (*Window) LastDrawStats ¶
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 ¶
NeedsLayout returns true if layout needs recalculation.
func (*Window) NeedsRedraw ¶
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) SetRoot ¶
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) WindowSize ¶
WindowSize returns the current window size in logical pixels.