~eliasnaur/gio#605: 
gtx.Disabled() breaks all animations (InvalidateCmd doesn't execute)

This might very well be intended behaviour, however it doesn't match prior versions of Gio. If it's intended feel free to close the ticket.

In short: gtx.Disabled() has typically been used to block user input. However in the current version of Gio it will block all animations as well, since gtx.Execute(op.InvalidateCmd{}) is not processed on a disabled gtx.

Here's a minimal reproducer:

package main

import (
	"log"
	"os"

	"gioui.org/app"
	"gioui.org/layout"
	"gioui.org/op"
	"gioui.org/widget/material"
)

func main() {
	go func() {
		w := new(app.Window)
		w.Option(app.Title("playground"))

		if err := run(w); err != nil {
			log.Fatal(err)
		}

		os.Exit(0)
	}()

	app.Main()
}

func run(w *app.Window) error {
	var (
		th  = material.NewTheme()
		ops op.Ops
	)
	for {
		switch ev := w.Event().(type) {
		case app.DestroyEvent:
			return ev.Err
		case app.FrameEvent:
			gtx := app.NewContext(&ops, ev)
			frame(gtx, th)
			ev.Frame(gtx.Ops)
		}
	}
}

type (
	C = layout.Context
	D = layout.Dimensions
)

func frame(gtx C, th *material.Theme) D {
	return layout.Center.Layout(gtx, func(gtx C) D {
		gtx = gtx.Disabled()
		return material.Loader(th).Layout(gtx)
	})
}
Status
RESOLVED FIXED
Submitter
~jackmordaunt
Assigned to
No-one
Submitted
2 months ago
Updated
2 months ago
Labels
No labels applied.

~whereswaldon 2 months ago

I've countered some trouble from this as well. Originally I rationalized this change as reasonable because disabling a widget could be thought of as "not allowing the widget layout to interact with the Gio window/event system at all," but after further thought I don't like that approach.

Disabled widgets aren't supposed to accept input events, but they may be disabled while waiting for an event or during an animation, both of which require scheduling future invalidation.

More generally, is there any real problem with allowing disabled widgets to issue arbitrary commands? They aren't receiving input events from users, so their only input is their current state. Their behavior should be pretty simple to reason about in the absence of input events, and thus buggy widgets issuing incorrect commands should be easy to catch. I think the potential harm of allowing command execution on a disabled context is low, and the benefits are real.

I can see that the issue with enabling this is in the implementation though. The gtx.Source is zeroed to disable the context, but the Source is also the thing responsible for handling commands. Without changing this implementation, we cannot disentangle the above behavior. Disabling the context inherently disables command execution by removing the type that actually executes commands.

~eliasnaur 2 months ago

I'm tempted to agree that allowing commands on a disabled gtx is a good idea. The implementation would be to replace the nil'ing of Context.Source with adding a Source.Disabled that tracks the enabled-ness of the Source.

~eliasnaur REPORTED FIXED 2 months ago

Elias Naur referenced this ticket in commit d9ddbe6.

Register here or Log in to comment, or comment via email.