diff --git a/cmd/gogio/e2e_test.go b/cmd/gogio/e2e_test.go index eb542cf4..e2ee5646 100644 --- a/cmd/gogio/e2e_test.go +++ b/cmd/gogio/e2e_test.go @@ -21,7 +21,7 @@ type TestDriver interface { // white. // // When the function returns, the gio app must be ready to use on the - // platform. + // platform, with its initial frame fully drawn. // // The returned cleanup funcs must be run in reverse order, to mimic // deferred funcs. @@ -32,7 +32,8 @@ type TestDriver interface { Screenshot() image.Image // Click performs a pointer click at the specified coordinates, - // including both press and release. + // including both press and release. It returns when the next frame is + // fully drawn. Click(x, y int) } diff --git a/cmd/gogio/testdata/red.go b/cmd/gogio/testdata/red.go index 0450cf3b..9e59e1d0 100644 --- a/cmd/gogio/testdata/red.go +++ b/cmd/gogio/testdata/red.go @@ -4,9 +4,11 @@ package main import ( + "fmt" "image" "image/color" "log" + "runtime" "gioui.org/app" "gioui.org/f32" @@ -26,6 +28,18 @@ func main() { app.Main() } +type notifyFrame int + +const ( + notifyNone notifyFrame = iota + notifyInvalidate + notifyPrint +) + +// notify keeps track of whether we want to print to stdout to notify the user +// when a frame is ready. Initially we want to notify about the first frame. +var notify = notifyInvalidate + func loop(w *app.Window) error { topLeft := quarterWidget{ color: color.RGBA{R: 0xde, G: 0xad, B: 0xbe, A: 0xff}, @@ -67,6 +81,22 @@ func loop(w *app.Window) error { rows.Layout(gtx, r1, r2) e.Frame(gtx.Ops) + + if runtime.GOOS == "js" { + // TODO(mvdan): Unfortunately, printing to + // stdout crashes the js/wasm port. Use the + // prints once the issue is fixed: + // https://github.com/golang/go/issues/35256 + break + } + switch notify { + case notifyInvalidate: + notify = notifyPrint + w.Invalidate() + case notifyPrint: + notify = notifyNone + fmt.Println("frame ready") + } } } } @@ -100,6 +130,8 @@ func (w *quarterWidget) Layout(gtx *layout.Context) { for _, e := range gtx.Events(w) { if e, ok := e.(pointer.Event); ok && e.Type == pointer.Press { w.clicked = !w.clicked + // notify when we're done updating the frame. + notify = notifyInvalidate } } } diff --git a/cmd/gogio/x11_test.go b/cmd/gogio/x11_test.go index 72113b0b..5b772312 100644 --- a/cmd/gogio/x11_test.go +++ b/cmd/gogio/x11_test.go @@ -7,6 +7,7 @@ package main_test import ( + "bufio" "bytes" "context" "fmt" @@ -26,10 +27,13 @@ import ( type X11TestDriver struct { t *testing.T + frameNotifs chan bool + display string } func (d *X11TestDriver) Start(t_ *testing.T, path string, width, height int) (cleanups []func()) { + d.frameNotifs = make(chan bool, 1) d.t = t_ // Pick a random display number between 1 and 100,000. Most machines @@ -125,10 +129,14 @@ func (d *X11TestDriver) Start(t_ *testing.T, path string, width, height int) (cl { ctx, cancel := context.WithCancel(context.Background()) cmd := exec.CommandContext(ctx, bin) - out := &bytes.Buffer{} cmd.Env = []string{"DISPLAY=" + d.display} - cmd.Stdout = out - cmd.Stderr = out + stdout, err := cmd.StdoutPipe() + if err != nil { + d.t.Fatal(err) + } + stderr := &bytes.Buffer{} + cmd.Stderr = stderr + if err := cmd.Start(); err != nil { d.t.Fatal(err) } @@ -136,17 +144,26 @@ func (d *X11TestDriver) Start(t_ *testing.T, path string, width, height int) (cl wg.Add(1) go func() { if err := cmd.Wait(); err != nil && ctx.Err() == nil { - // Print all output and error. - io.Copy(os.Stdout, out) + // Print stderr and error. + io.Copy(os.Stdout, stderr) d.t.Error(err) } wg.Done() }() + go func() { + scanner := bufio.NewScanner(stdout) + for scanner.Scan() { + line := scanner.Text() + if line == "frame ready" { + d.frameNotifs <- true + } + } + }() + } // Wait for the gio app to render. - // TODO(mvdan): synchronize with the app instead - time.Sleep(400 * time.Millisecond) + <-d.frameNotifs return cleanups } @@ -183,8 +200,7 @@ func (d *X11TestDriver) Click(x, y int) { d.xdotool("mousemove", x, y) d.xdotool("click", "1") - // TODO(mvdan): synchronize with the app instead - time.Sleep(200 * time.Millisecond) + <-d.frameNotifs } func TestX11(t *testing.T) {