on ~eliasnaur/gio
Thank you for the report, ~ajstarks. I've fixed the issue on the branch.
I've also re-added
app.Main
, pending a decision on https://github.com/golang/go/issues/64755 .
Comment by ~ajstarks on ~eliasnaur/gio
System: Fedora 39, UM690 (32Gb RAM, AMD Ryzen™ 9 6900HX with Radeon™ Graphics × 16)
$ go version -m ./hello ./hello: go1.21.6 path github.com/ajstarks/giocanvas/hello mod github.com/ajstarks/giocanvas (devel) dep gioui.org v0.4.2-0.20231221171002-cb8efefa839a h1:QBZFhRotXHnB+Nq2iGfIZoinKbZRjEPTnA+9ReOj2LI= dep gioui.org/cpu v0.0.0-20210817075930-8d6a761490d2 h1:AGDDxsJE1RpcXTAxPG2B4jrwVUJGFDjINIPi1jtO6pc= dep gioui.org/shader v1.0.8 h1:6ks0o/A+b0ne7RzEqRZK5f4Gboz2CfG+mVliciy6+qA= dep github.com/go-text/typesetting v0.0.0-20230803102845-24e03d8b5372 h1:FQivqchis6bE2/9uF70M2gmmLpe82esEm2QadL0TEJo= dep golang.org/x/exp v0.0.0-20221012211006-4de253d81b95 h1:sBdrWpxhGDdTAYNqbgBLAR+ULAPPhfgncLr1X0lyWtg= dep golang.org/x/exp/shiny v0.0.0-20220827204233-334a2380cb91 h1:ryT6Nf0R83ZgD8WnFFdfI8wCeyqgdXWN4+CkFVNPAT0= dep golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4= dep golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= dep golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
I converted all giocanvas clients to this new API, and all run fine on X11 as well as Mac OS (11.7.9, MacBook Pro 2.3 GHz Quad-Core Intel Core i7). If I switch to Wayland on Fedora, the same binary crashes: (See:
https://gist.github.com/ajstarks/080972af9bf905ffe595e14009e8e471
Here is the "hello" program that crashed:
// hello is the giocanvas hello, world package main import ( "flag" "image/color" "io" "os" "gioui.org/app" "gioui.org/unit" "github.com/ajstarks/giocanvas" ) func main() { var cw, ch int flag.IntVar(&cw, "width", 1000, "canvas width") flag.IntVar(&ch, "height", 1000, "canvas height") flag.Parse() width := float32(cw) height := float32(ch) w := &app.Window{} w.Option(app.Title("hello"), app.Size(unit.Dp(width), unit.Dp(height))) if err := hello(w, width, height); err != nil { io.WriteString(os.Stderr, "Cannot create the window\n") os.Exit(1) } os.Exit(0) } func hello(w *app.Window, width, height float32) error { for { ev := w.Event() switch e := ev.(type) { case app.DestroyEvent: return e.Err case app.FrameEvent: canvas := giocanvas.NewCanvas(float32(e.Size.X), float32(e.Size.Y), app.FrameEvent{}) canvas.CenterRect(50, 50, 100, 100, color.NRGBA{0, 0, 0, 255}) canvas.Circle(50, 0, 50, color.NRGBA{0, 0, 255, 255}) canvas.TextMid(50, 20, 10, "hello, world", color.NRGBA{255, 255, 255, 255}) canvas.CenterImage("earth.jpg", 50, 70, 1000, 1000, 30) e.Frame(canvas.Context.Ops) } } } '''
Comment by ~ajstarks on ~eliasnaur/gio
~eliasnaur, the use of Optional works fine. thanks. Giocanvas and its clients are now converted. Overall the new API seems at bit cleaner and more straightforward.
New: https://gist.github.com/ajstarks/ef633da557c4f90429990d66f0f6c7c6
Old: https://gist.github.com/ajstarks/9224ad09306ecb240c6618bf32da45e6
Diff:
2c2 < func kbpointer(q event.Queue, cfg config) { --- > func kbpointer(q input.Source, cfg config) { 6,9c6,18 < for _, ev := range q.Events(pressed) { < // keyboard events < if k, ok := ev.(key.Event); ok { < switch k.State { --- > for { > e, ok := q.Event( > key.Filter{Optional: key.ModCtrl}, > pointer.Filter{Kinds: pointer.Press | pointer.Move | pointer.Release}, > ) > if !ok { > break > } > switch e := e.(type) { > > case key.Event: // keyboard events > > switch e.State { 11c20 < switch k.Name { --- > switch e.Name { 31c40 < switch k.Modifiers { --- > switch e.Modifiers { 38c47 < switch k.Modifiers { --- > switch e.Modifiers { 45c54 < switch k.Modifiers { --- > switch e.Modifiers { 52c61 < switch k.Modifiers { --- > switch e.Modifiers { 62,65c71,74 < } < // pointer events < if p, ok := ev.(pointer.Event); ok { < switch p.Kind { --- > > case pointer.Event: // pointer events > > switch e.Kind { 67c76 < mouseX, mouseY = pctcoord(p.Position.X, p.Position.Y, width, height) --- > mouseX, mouseY = pctcoord(e.Position.X, e.Position.Y, width, height) 69c78 < switch p.Buttons { --- > switch e.Buttons { 71c80 < bx, by = pctcoord(p.Position.X, p.Position.Y, width, height) --- > bx, by = pctcoord(e.Position.X, e.Position.Y, width, height) 73c82 < ex, ey = pctcoord(p.Position.X, p.Position.Y, width, height) --- > ex, ey = pctcoord(e.Position.X, e.Position.Y, width, height) 77d85 < pressed = true 96c104 < case system.DestroyEvent: --- > case app.DestroyEvent: 100,103c108,109 < case system.FrameEvent: < canvas := giocanvas.NewCanvas(float32(e.Size.X), float32(e.Size.Y), system.FrameEvent{}) < key.InputOp{Tag: pressed}.Add(canvas.Context.Ops) < pointer.InputOp{Tag: pressed, Grab: false, Kinds: pointer.Press | pointer.Move}.Add(canvas.Context.Ops) --- > case app.FrameEvent: > canvas := giocanvas.NewCanvas(float32(e.Size.X), float32(e.Size.Y), app.FrameEvent{}) 143c149 < kbpointer(e.Queue, cfg) --- > kbpointer(e.Source, cfg)
also in giocanvas abs.go, changed
op.InvalidateOp{}.Add(ops)
to
c.Context.Execute(op.InvalidateCmd{})
on ~eliasnaur/gio
~ajstarks: use the
Optional
field ofkey.Filter
instead ofRequired
.
Comment by ~ajstarks on ~eliasnaur/gio
@eliasnaur: thanks for the pointers. I have it mostly working now with a slight correction:
kbpointer(e.Source) ... // handle kb and pointer func kbpointer(q input.Source) { for { e, ok := q.Event( // q.Event, not e.Event key.Filter{}, pointer.Filter{Target: pressed, Kinds: pointer.Press | pointer.Move | pointer.Release}, ) if !ok { break } switch e := e.(type) { case key.Event: // handle kb case pointer.Event: // handle pointer } } }
One issue: I cannot turning on modifiers for the key events:
key.Filter{Required: key.ModCtrl}
disables all keyboard events.
Comment by ~ajstarks on ~eliasnaur/gio
Previously I did this:
var pressed bool for { ev := w.NextEvent() switch e := ev.(type) { case app.FrameEvent: .... kbpointer(e.Queue) // handle key and pointer events e.Frame(....) } } // handle kb and pointer func kbpointer(q event.Queue) { for _, ev := range q.Events(pressed) { if k, ok := ev.(key.Event); ok { ... } // handle kb if p, ok := ev.(pointer.Event); ok { ...} // handle pointer } }
What is the best re-factor?
on ~eliasnaur/gio
~beikege: thank you, I've updated the branch to fix
widget.List
. Usego get gioui.org@cf3e0c744246b4ae
to get around the Go proxy caching of the branch.~gedw99: yes, code will need refactoring, but mostly in low-level widget code. I'm using the kitchen example for testing:
diff --git a/kitchen/kitchen.go b/kitchen/kitchen.go index 10d4c05..da8d2f0 100644 --- a/kitchen/kitchen.go +++ b/kitchen/kitchen.go @@ -22,8 +22,7 @@ import ( "gioui.org/font/gofont" "gioui.org/gpu/headless" "gioui.org/io/event" - "gioui.org/io/router" - "gioui.org/io/system" + "gioui.org/io/input" "gioui.org/layout" "gioui.org/op" "gioui.org/op/clip" @@ -96,7 +95,7 @@ func saveScreenshot(f string) error { PxPerSp: scale, }, Constraints: layout.Exact(sz), - Queue: new(router.Router), + Source: input.Source{}, } th := material.NewTheme() th.Shaper = text.NewShaper(text.WithCollection(gofont.Collection())) @@ -126,7 +125,7 @@ func loop(w *app.Window) error { ev := w.NextEvent() events <- ev <-acks - if _, ok := ev.(system.DestroyEvent); ok { + if _, ok := ev.(app.DestroyEvent); ok { return } } @@ -137,11 +136,11 @@ func loop(w *app.Window) error { select { case e := <-events: switch e := e.(type) { - case system.DestroyEvent: + case app.DestroyEvent: acks <- struct{}{} return e.Err - case system.FrameEvent: - gtx := layout.NewContext(&ops, e) + case app.FrameEvent: + gtx := app.NewContext(&ops, e) if *disable { gtx = gtx.Disabled() } @@ -170,7 +169,7 @@ func transformedKitchen(gtx layout.Context, th *material.Theme) layout.Dimension if !transformTime.IsZero() { dt := float32(gtx.Now.Sub(transformTime).Seconds()) angle := dt * .1 - op.InvalidateOp{}.Add(gtx.Ops) + gtx.Execute(op.InvalidateCmd{}) tr := f32.Affine2D{} tr = tr.Rotate(f32.Pt(300, 20), -angle) scale := 1.0 - dt*.5 @@ -332,7 +331,7 @@ func kitchen(gtx layout.Context, th *material.Theme) layout.Dimensions { return material.Clickable(gtx, flatBtn, func(gtx C) D { return layout.UniformInset(unit.Dp(12)).Layout(gtx, func(gtx C) D { flatBtnText := material.Body1(th, "Flat") - if gtx.Queue == nil { + if !gtx.Enabled() { flatBtnText.Color.A = 150 } return layout.Center.Layout(gtx, flatBtnText.Layout)
~ajstarks: I believe this is what you want:
case app.FrameEvent: canvas := giocanvas.NewCanvas(float32(e.Size.X), float32(e.Size.Y), app.FrameEvent{}) event.Op{Tag: pressed}.Add(canvas.Context.Ops)
The
pointer.InputOp
kinds are replaced with filters at your event handling:for { e, ok := gtx.Event(pointer.Filter{Target: pressed, Kinds: pointer.Press | pointer.Move}) if !ok { break } }
Comment by ~ajstarks on ~eliasnaur/gio
I updated giocanvas with the new event handling system, (many thanks for the gofmt commands from @egonelbre) and some clients work as expected (modulo the still existing bug #542). I'm not clear on the proper refactoring for clients with more extensive event handling. For example, is the best way to refactor:
case app.FrameEvent: canvas := giocanvas.NewCanvas(float32(e.Size.X), float32(e.Size.Y), app.FrameEvent{}) key.InputOp{Tag: pressed}.Add(canvas.Context.Ops) pointer.InputOp{Tag: pressed, Grab: false, Kinds: pointer.Press | pointer.Move}.Add(canvas.Context.Ops)
This:
case app.FrameEvent: canvas := giocanvas.NewCanvas(float32(e.Size.X), float32(e.Size.Y), app.FrameEvent{}) canvas.Context.Execute(key.FocusCmd{Tag: pressed}) canvas.Context.Event(pointer.Filter{Kinds: pointer.Press | pointer.Move})
Comment by ~ajstarks on ~eliasnaur/gio
It appears to still be broken with v0.3.3-0.20231116145621-35cdcbe4d4b6
go run gioui.org/example/hello@latest # works go run gioui.org/example/hello@main # breaks
Also shows with giocanvas clients built with v0.3.2-0.20231125175025-f39245df99bf
Comment by ~ajstarks on ~eliasnaur/gio
Yes, the hello example shows the bug. Here is a pointer to a demo of the bug: https://gophers.slack.com/archives/CM87SNCGM/p1697120564422829?thread_ts=1696868667.083419&cid=CM87SNCGM