1package app
2
3import (
4 "context"
5 "fmt"
6 "os"
7 "path/filepath"
8
9 "github.com/bnema/neferwl/internal/adapters/headless"
10 "github.com/bnema/neferwl/internal/ports"
11 "github.com/bnema/zerowrap"
12)
13
14// runHeadless drives one virtual output per size, named HEADLESS-1, -2, ...
15// With several outputs, screenshots go to a subdirectory per output.
16func runHeadless(ctx context.Context, sizes [][2]int, shots string, events chan<- ports.OutputEvent, scenes <-chan []ports.Scene, contents <-chan ports.SurfaceContent, cursorChanges <-chan ports.CursorChange, presented chan<- ports.OutputPresented, curs *cursors, newRenderer func(w, h int) (ports.Renderer, error), log zerowrap.Logger) error {
17 set := newOutputSet()
18 for i, size := range sizes {
19 name := fmt.Sprintf("HEADLESS-%d", i+1)
20 dir := shots
21 if dir != "" && len(sizes) > 1 {
22 dir = filepath.Join(shots, name)
23 if err := os.MkdirAll(dir, 0o755); err != nil {
24 return err
25 }
26 }
27 cur := &headless.Cursor{}
28 curs.set(name, cur)
29 opts := headless.Options{Cursor: cur, LoadCursor: loadCursor, Width: size[0], Height: size[1], ScreenshotDir: dir, Log: log, NewRenderer: newRenderer, Name: name, Presented: presented}
30 set.start(ctx, name, func(octx context.Context, sc <-chan ports.Scene, cc <-chan ports.SurfaceContent, cu <-chan ports.CursorChange) error {
31 return headless.Run(octx, opts, sc, cc, cu)
32 })
33 select {
34 case events <- ports.OutputAdded{Info: ports.OutputInfo{Name: name, Width: size[0], Height: size[1]}}:
35 case <-ctx.Done():
36 return set.wait()
37 }
38 }
39 // The pointer starts centred on the first output, like libinput's.
40 curs.move("HEADLESS-1", float64(sizes[0][0])/2, float64(sizes[0][1])/2)
41 for {
42 select {
43 case <-ctx.Done():
44 return set.wait()
45 case s := <-scenes:
46 set.scenes(s)
47 case c := <-contents:
48 set.content(c)
49 case c := <-cursorChanges:
50 set.setCursor(c)
51 case name := <-set.stopped:
52 // A headless output only stops on error: the run ends.
53 err := set.finish(name)
54 return joinErr(err, set.wait())
55 }
56 }
57}
58
59func joinErr(a, b error) error {
60 if a != nil {
61 return a
62 }
63 return b
64}