Comment by ~andybalholm on ~eliasnaur/gio
Yes, that works well. Probably the only change that's needed is better documentation…
Comment by ~andybalholm on ~eliasnaur/gio
To avoid blocking clicks that should go to the widget's children, the whole-widget event.Op would need to be called before drawing the children. But the correct dimensions to set for its clip area aren't known till afterward, because they are the return value of the Layout method.
Comment by ~andybalholm on ~eliasnaur/gio
The widget is definitely visible, and contains many clickable areas. But it's not useful for it to be clickable as a whole; the clicks need to be passed through to the content.
(It's a table with clickable rows. The keyboard focus is to allow selecting a row with the arrow keys and activating it with enter instead of clicking on it.)
Comment by ~andybalholm on ~eliasnaur/gio
Do you mean that if we set the focus to a tag that doesn't have an event.Op, it will receive key events?
Anyway, I do want the user to be able to tab to the widget. I solved the issue by setting a zero-sized rectangle as the clip area. But it still seems rather counter-intuitive, even though it's perfectly logical considering how all the parts are defined.
Comment by ~andybalholm on ~eliasnaur/gio
Ticket created by ~andybalholm on ~eliasnaur/gio
When I call
event.Op
without specifying a clipping area, no previously-declared event handlers can receive mouse events, because it creates a click-receiving area that covers the whole window—even if I don't intend to handle any mouse events with this tag.In the real program where I ran into this, I had a complex widget wrapping some other widgets. I wanted the complex widget as a whole to be able to receive keyboard focus and respond to key presses, but mouse input to go directly to some clickable areas within the widget. But as soon as I registered the event handler for the keyboard events, the mouse clicks didn't work any more.
This is an unfortunate result of unifying
pointer.InputOp
andkey.InputOp
intoevent.Op
. (So now registering for events registers for both mouse and keyboard events by default.) All the parts make sense in isolation, but in combination, the result is surprising and can be difficult to debug. (The solution was to set an empty clipping area before callingevent.Op
.)Here is an example program that reproduces the problem. In this example, I don't actually handle any events from the tag that I registered, for simplicity:
package main import ( "log" "os" "gioui.org/app" "gioui.org/io/event" "gioui.org/layout" "gioui.org/op" "gioui.org/widget" "gioui.org/widget/material" ) // This program demonstrates a Gio event-routing issue where // an event handler without a clipping area swallows all clicks. var th = material.NewTheme() func main() { go func() { var w app.Window w.Option(app.Title("Click Swallower")) w.Option(app.Size(640, 480)) Home(&w) }() app.Main() } func exit(e app.DestroyEvent) { if e.Err != nil { log.Fatal(e.Err) } os.Exit(0) } func Home(w *app.Window) { var quitButton widget.Clickable var ops op.Ops for { switch e := w.Event().(type) { case app.DestroyEvent: exit(e) case app.FrameEvent: gtx := app.NewContext(&ops, e) if quitButton.Clicked(gtx) { os.Exit(0) } layout.UniformInset(20).Layout(gtx, material.Button(th, &quitButton, "Quit").Layout, ) event.Op(gtx.Ops, 0) e.Frame(gtx.Ops) } } }
on ~eliasnaur/gio
~andybalholm, can you provide a small example of the issue, preferably in a new TODO? I'd like to fix the event logic if there's a bug here.
Comment by ~andybalholm on ~eliasnaur/gio
Nothing in my code was asking for pointer events directly. But when I called
event.Op
without setting a clipping area, the buttons on the screen didn't respond to clicks. I think what was happening was that all the click events were being tagged with the tag from myevent.Op
call instead of the tags they would normally have had. So when the buttons set event filters, the clicks didn't match.
Comment by ~andybalholm on ~eliasnaur/gio
I guess that's one drawback to the new event filter API. When you call
event.Op
, you can't specify whether you want keyboard events, mouse events, or both. I just ran into the other side of the issue today: I wanted a widget to handle certain keyboard events, but no mouse events; I accidentally made it silently swallow all mouse events, so none of the other widgets in the window worked. (The fix was pretty simple once I figured it out: set an empty clip region before callingevent.Op
.)
Ticket created by ~andybalholm on ~eliasnaur/gio
I've noticed that when Gio draws the window decorations, the buttons in the title bar are included in the tab order for keyboard focus: After cycling through the widgets in the content of the window, pressing tab goes to the minimize, maximize, and close buttons before returning to the regular widgets.
@whereswaldon suggested: I think we'd just need a way to mark a given gesture.Click and/or widget.Clickable as ineligible for keyboard focus, and we could then use that in the implementation of widget.Decorations