包 headless

Package headless operates a Viva application without opening a window.

API 文档由 Go 源码生成,内容为英文。

导入路径: import "github.com/vivaui/viva/headless"

Package headless operates a Viva application without opening a window.

A Session runs the application's real paint, input routing, focus and text-input paths through app.Driver, with an animation clock that only moves when told to, and can turn the current frame into an image. On macOS the image comes from the window's own Metal pipelines and CoreText rasterizers, drawing into a texture instead of a drawable, so a headless screenshot is the pixels the window would show. That renderer is linked only into builds made with -tags vivahead, so release builds carry none of it; without the tag sessions still operate and answer queries and Image reports ErrNoRenderer. Windows (Direct3D 11, GDI text) and Linux (Vulkan, Pango text) draw their screenshots the same way, with their own renderers, in any build that links this package; only the macOS one also draws the text being edited, which the platform's native editor paints over the scene. A session lays the application out with the platform's text engine, as a window does (Options.ReferenceText asks for the platform-independent reference metrics).

session, err := headless.Open(config, nil, headless.Options{})
session.ClickLabel("New Host")
session.Type("example.com")
session.Keys("cmd+c")
text := session.Driver().Clipboard()
session.Screenshot("after.png")

Record plays the animation clock and writes the frames whose pixels changed, so a transition can be reviewed as a sequence rather than a still:

frames, err := session.Record("run/frames", headless.RecordOptions{
	Duration: 700 * time.Millisecond,
})

The PNG files and their lengths in manifest.json are what a video tool needs; frames that repeat are written once, so an application at rest records as one still frame. Recording uses the same offscreen renderers as Image.

A running application can be driven the same way without any change to its code: link package headless/auto (behind a build tag, so release builds never contain it) and start the process with VIVA_HEADLESS=1. RunCanvas then serves the line protocol documented on Serve on standard input and output instead of opening a window.

类型

函数

Run#

func Run(config app.Config, canvas *ui.Canvas) error

Run is the app.UseRunner implementation behind headless/auto: it opens a Session for config and serves the line protocol on standard input and output instead of opening a window. VIVA_HEADLESS_SCALE sets the screenshot scale (default 2).

RunApplication#

func RunApplication(start func(host app.Host) error) error

RunApplication is the app.ApplicationRunner installed by headless/auto. It preserves every window as a separate Driver and exposes explicit selection and close commands while reusing the ordinary single-window protocol.

Serve#

func Serve(session *Session, in io.Reader, out io.Writer) error

Serve runs the line protocol on in and out until "quit" or the end of input. Each request is one line; the reply is zero or more data lines followed by exactly one final line, "ok ..." or "error ...". Arguments are separated by spaces; an argument containing spaces is written in double quotes ("New Host"), with \" and \\ as escapes. Coordinates are logical pixels.

size                       ok 1400x900 scale=2
move X Y | down X Y | up X Y | click X Y | dblclick X Y | rightclick X Y
scroll X Y DX DY [MODIFIERS]  scroll at X,Y; modifiers are shift+ctrl+alt+cmd
drop X Y PATH...           drop files from the system onto the point: ok accepted|refused
dragover X Y | dragleave   the hover of such a drag, and its end
click "Label"              click the center of the control with that label
dblclick "Label"           double-click the center of that control
rightclick "Label"         right-click the center of that control (opens its context menu)
key SPEC...                tab | shift+tab | enter | esc | backspace | left |
                           pageup | f5 | insert | cmd+a | cmd+c | cmd+x | cmd+v | x ...
                           ctrl+c and configured alt+x chords go to a focused terminal
keydown NAME | keyup NAME  hold and release one key: a named key ("left", "f5"), a
                           character, or a modifier (shift ctrl alt cmd, rshift rctrl
                           ralt rcmd). Held modifiers apply to every click, scroll and
                           key until released. A terminal that asked for key releases
                           sees the presses and releases; elsewhere keydown acts as key
blur                       the window loses the keyboard: held keys are released
type TEXT                  insert the rest of the line into the focused field
select START END           select a rune range of the focused field
resize W H
frame                     ok x=.. y=.. w=.. h=.. (the content area on screen)
windowmove X Y            move the window's content area to a screen point, as a drag
                          of the window would, and report its new frame to OnFrameChange
minimize on|off           report the window as minimized or restored, as the window
                          manager would, and call OnMinimize
maximize on|off           report the window as maximized or restored, as the window
                          manager would, and call OnMaximize
wait MS                    advance the animation clock
settle [MS]                apply background work until quiet for MS (default 100)
waitfor "text" [MS]        wait up to MS (default 5000) real ms for text on screen;
                           that time also passes for the app's timers
shot PATH [now]            write a PNG of the interface at rest: transitions in flight
                           (a dialog fading in) are played to their end first. With
                           now, write the current frame as it is, so wait MS; shot
                           PATH now catches an animation MS into it
record DIR MS [FPS]        play MS more of animation and write it to DIR as a PNG
                           sequence and manifest.json, sampling FPS frames a second
                           (default 60); frames that did not change are written once
                           with a longer duration, and ok reports the count
find "label"               ok id=7 x=.. y=.. w=.. h=.. label=".."
hits [filter]              one line per control, then ok
texts [filter]             one line per painted text, then ok
layout                     one line per suspicious spot (text cut off, spilling out of its
                           control, over other text, off the window; focusable controls that
                           cross), then ok N problems; it never fails
focus                      ok id=.. label=".." (id=0 when nothing is focused)
editor                     ok value=".." selection=a,b (no editor: ok none)
appearance [light|dark|unknown]  read or set the system appearance the run reports
clip [TEXT]                read or replace the private clipboard
clipimage [PATH|clear]     read (ok image N bytes | ok none) or replace the private clipboard's image with a PNG file
openedurl                  report the last public OpenURL request
openedpath                 report the last OpenPath request
openfiles PATH...|cancel   queue the next native open-dialog result
opendirectory PATH|cancel  queue the next native directory-dialog result
savefile PATH|cancel       queue the next native save-dialog result
quit

ServeApplication#

func ServeApplication(application *applicationSession, in io.Reader, out io.Writer) error

ServeApplication drives a multi-window headless application. windows lists live windows, window ID selects the target for ordinary commands, and requestclose [ID] sends one window its close button, which an application with an OnCloseRequest may turn into hiding the window. closewindow [ID] closes one window. Closing the final window ends the loop.

变量

var ErrNoRenderer = errors.New("headless: no offscreen renderer on this platform")

ErrNoRenderer is returned by Image and Screenshot on platforms without an offscreen renderer.