fyne-io / fyne

Cross platform GUI toolkit in Go inspired by Material Design
https://fyne.io/
Other
24.86k stars 1.38k forks source link

Resolve data races in widgets, internal/widgets, and friends #2509

Open changkun opened 3 years ago

changkun commented 3 years ago

Describe the bug:

Run fyne_demo with -race flag:

go run -race main.go Output
$ go run -race main.go
==================
WARNING: DATA RACE
Write at 0x00c00010c2c0 by goroutine 31:
  fyne.io/fyne/v2/widget.(*Label).createListener.func1()
      /Users/changkun/dev/changkun.de/fyne/widget/label.go:154 +0x7b
  fyne.io/fyne/v2/data/binding.(*listener).DataChanged()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:55 +0x3d
  fyne.io/fyne/v2/data/binding.DataListener.DataChanged-fm()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:40 +0x48
  fyne.io/fyne/v2/data/binding.queueItem.func1.1()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:19 +0x74

Previous read at 0x00c00010c2c0 by main goroutine:
  fyne.io/fyne/v2/widget.(*Label).syncSegments()
      /Users/changkun/dev/changkun.de/fyne/widget/label.go:169 +0x1f8
  fyne.io/fyne/v2/widget.(*Label).CreateRenderer()
      /Users/changkun/dev/changkun.de/fyne/widget/label.go:64 +0xbc
  fyne.io/fyne/v2/internal/cache.Renderer()
      /Users/changkun/dev/changkun.de/fyne/internal/cache/widget.go:33 +0x174
  fyne.io/fyne/v2/widget.(*Label).MinSize()
      /Users/changkun/dev/changkun.de/fyne/widget/label.go:86 +0x69
  fyne.io/fyne/v2/layout.(*gridLayout).MinSize()
      /Users/changkun/dev/changkun.de/fyne/layout/gridlayout.go:135 +0x3eb
  fyne.io/fyne/v2.NewContainerWithLayout()
      /Users/changkun/dev/changkun.de/fyne/container.go:47 +0x162
  fyne.io/fyne/v2/container.NewGridWithColumns()
      /Users/changkun/dev/changkun.de/fyne/container/layouts.go:51 +0x3db
  fyne.io/fyne/v2/cmd/fyne_demo/tutorials.bindingScreen()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/tutorials/bind.go:17 +0x2e2
  main.main.func1()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:52 +0x4fd
  main.makeNav.func5()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:177 +0x1b5
  fyne.io/fyne/v2/widget.(*Tree).Select()
      /Users/changkun/dev/changkun.de/fyne/widget/tree.go:242 +0x1f4
  main.makeNav()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:184 +0x326
  main.main()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:61 +0x5c7

Goroutine 31 (running) created at:
  fyne.io/fyne/v2/data/binding.queueItem.func1()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:17 +0x6b
  sync.(*Once).doSlow()
      /Users/changkun/goes/go/src/sync/once.go:68 +0x127
  sync.(*Once).Do()
      /Users/changkun/goes/go/src/sync/once.go:59 +0x46
  fyne.io/fyne/v2/data/binding.queueItem()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:15 +0x37
  fyne.io/fyne/v2/data/binding.(*base).AddListener()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:69 +0x249
  fyne.io/fyne/v2/data/binding.(*boundExternalFloat).AddListener()
      :1 +0x4b
  fyne.io/fyne/v2/data/binding.FloatToStringWithFormat()
      /Users/changkun/dev/changkun.de/fyne/data/binding/convert.go:129 +0x204
  fyne.io/fyne/v2/cmd/fyne_demo/tutorials.bindingScreen()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/tutorials/bind.go:15 +0x1c5
  main.main.func1()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:52 +0x4fd
  main.makeNav.func5()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:177 +0x1b5
  fyne.io/fyne/v2/widget.(*Tree).Select()
      /Users/changkun/dev/changkun.de/fyne/widget/tree.go:242 +0x1f4
  main.makeNav()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:184 +0x326
  main.main()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:61 +0x5c7
==================
==================
WARNING: DATA RACE
Read at 0x00c0000e4058 by main goroutine:
  fyne.io/fyne/v2/widget.(*checkRenderer).updateResource()
      /Users/changkun/dev/changkun.de/fyne/widget/check.go:77 +0x73
  fyne.io/fyne/v2/widget.(*Check).CreateRenderer()
      /Users/changkun/dev/changkun.de/fyne/widget/check.go:223 +0x611
  fyne.io/fyne/v2/internal/cache.Renderer()
      /Users/changkun/dev/changkun.de/fyne/internal/cache/widget.go:33 +0x174
  fyne.io/fyne/v2/widget.(*BaseWidget).MinSize()
      /Users/changkun/dev/changkun.de/fyne/widget/widget.go:85 +0x33
  fyne.io/fyne/v2/widget.(*Check).MinSize()
      /Users/changkun/dev/changkun.de/fyne/widget/check.go:200 +0x44
  fyne.io/fyne/v2/layout.(*gridLayout).MinSize()
      /Users/changkun/dev/changkun.de/fyne/layout/gridlayout.go:135 +0x3eb
  fyne.io/fyne/v2.NewContainerWithLayout()
      /Users/changkun/dev/changkun.de/fyne/container.go:47 +0x162
  fyne.io/fyne/v2/container.NewGridWithColumns()
      /Users/changkun/dev/changkun.de/fyne/container/layouts.go:51 +0x1089
  fyne.io/fyne/v2/cmd/fyne_demo/tutorials.bindingScreen()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/tutorials/bind.go:41 +0xf41
  main.main.func1()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:52 +0x4fd
  main.makeNav.func5()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:177 +0x1b5
  fyne.io/fyne/v2/widget.(*Tree).Select()
      /Users/changkun/dev/changkun.de/fyne/widget/tree.go:242 +0x1f4
  main.makeNav()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:184 +0x326
  main.main()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:61 +0x5c7

Previous write at 0x00c0000e4058 by goroutine 31:
  fyne.io/fyne/v2/widget.(*Check).Bind.func1()
      /Users/changkun/dev/changkun.de/fyne/widget/check.go:128 +0x65
  fyne.io/fyne/v2/data/binding.(*listener).DataChanged()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:55 +0x3d
  fyne.io/fyne/v2/data/binding.DataListener.DataChanged-fm()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:40 +0x48
  fyne.io/fyne/v2/data/binding.queueItem.func1.1()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:19 +0x74

Goroutine 31 (running) created at:
  fyne.io/fyne/v2/data/binding.queueItem.func1()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:17 +0x6b
  sync.(*Once).doSlow()
      /Users/changkun/goes/go/src/sync/once.go:68 +0x127
  sync.(*Once).Do()
      /Users/changkun/goes/go/src/sync/once.go:59 +0x46
  fyne.io/fyne/v2/data/binding.queueItem()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:15 +0x37
  fyne.io/fyne/v2/data/binding.(*base).AddListener()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:69 +0x249
  fyne.io/fyne/v2/data/binding.(*boundExternalFloat).AddListener()
      :1 +0x4b
  fyne.io/fyne/v2/data/binding.FloatToStringWithFormat()
      /Users/changkun/dev/changkun.de/fyne/data/binding/convert.go:129 +0x204
  fyne.io/fyne/v2/cmd/fyne_demo/tutorials.bindingScreen()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/tutorials/bind.go:15 +0x1c5
  main.main.func1()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:52 +0x4fd
  main.makeNav.func5()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:177 +0x1b5
  fyne.io/fyne/v2/widget.(*Tree).Select()
      /Users/changkun/dev/changkun.de/fyne/widget/tree.go:242 +0x1f4
  main.makeNav()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:184 +0x326
  main.main()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:61 +0x5c7
==================
==================
WARNING: DATA RACE
Write at 0x00c000210048 by goroutine 31:
  fyne.io/fyne/v2/widget.(*entryContentRenderer).updateScrollDirections()
      /Users/changkun/dev/changkun.de/fyne/widget/entry.go:1657 +0x5ad
  fyne.io/fyne/v2/widget.(*entryContent).CreateRenderer()
      /Users/changkun/dev/changkun.de/fyne/widget/entry.go:1410 +0x4b7
  fyne.io/fyne/v2/internal/cache.Renderer()
      /Users/changkun/dev/changkun.de/fyne/internal/cache/widget.go:33 +0x174
  fyne.io/fyne/v2/widget.(*entryRenderer).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/entry.go:1371 +0xcb4
  fyne.io/fyne/v2/widget.(*entryRenderer).ensureValidationSetup()
      /Users/changkun/dev/changkun.de/fyne/widget/entry.go:1383 +0x374
  fyne.io/fyne/v2/widget.(*entryRenderer).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/entry.go:1365 +0xb99
  fyne.io/fyne/v2/widget.(*BaseWidget).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/widget.go:138 +0x41
  fyne.io/fyne/v2/widget.(*Entry).Bind.func2()
      /Users/changkun/dev/changkun.de/fyne/widget/entry.go:156 +0x144
  fyne.io/fyne/v2/data/binding.(*listener).DataChanged()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:55 +0x3d
  fyne.io/fyne/v2/data/binding.DataListener.DataChanged-fm()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:40 +0x48
  fyne.io/fyne/v2/data/binding.queueItem.func1.1()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:19 +0x74

Previous read at 0x00c000210048 by main goroutine:
  fyne.io/fyne/v2/internal/widget.(*scrollContainerRenderer).updatePosition()
      /Users/changkun/dev/changkun.de/fyne/internal/widget/scroller.go:350 +0x655
  fyne.io/fyne/v2/internal/widget.(*scrollContainerRenderer).layoutBars()
      /Users/changkun/dev/changkun.de/fyne/internal/widget/scroller.go:269 +0x3ee
  fyne.io/fyne/v2/internal/widget.(*scrollContainerRenderer).Layout()
      /Users/changkun/dev/changkun.de/fyne/internal/widget/scroller.go:276 +0xea
  fyne.io/fyne/v2/internal/widget.(*scrollContainerRenderer).Refresh()
      /Users/changkun/dev/changkun.de/fyne/internal/widget/scroller.go:295 +0x404
  fyne.io/fyne/v2/internal/widget.(*Base).Refresh()
      /Users/changkun/dev/changkun.de/fyne/internal/widget/base.go:136 +0x41
  fyne.io/fyne/v2/internal/widget.(*Scroll).refreshWithoutOffsetUpdate()
      /Users/changkun/dev/changkun.de/fyne/internal/widget/scroller.go:456 +0x44
  fyne.io/fyne/v2/internal/widget.(*Scroll).Refresh()
      /Users/changkun/dev/changkun.de/fyne/internal/widget/scroller.go:442 +0x3c
  fyne.io/fyne/v2/internal/widget.(*Scroll).Resize()
      /Users/changkun/dev/changkun.de/fyne/internal/widget/scroller.go:452 +0x9c
  fyne.io/fyne/v2/widget.(*entryRenderer).Layout()
      /Users/changkun/dev/changkun.de/fyne/widget/entry.go:1271 +0x791
  fyne.io/fyne/v2/widget.(*BaseWidget).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/widget.go:61 +0x139
  fyne.io/fyne/v2/widget.(*Entry).Resize()
      :1 +0x4f
  fyne.io/fyne/v2/layout.(*gridLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/gridlayout.go:102 +0x33e
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x23a
  fyne.io/fyne/v2.NewContainerWithLayout()
      /Users/changkun/dev/changkun.de/fyne/container.go:48 +0x198
  fyne.io/fyne/v2/container.NewGridWithColumns()
      /Users/changkun/dev/changkun.de/fyne/container/layouts.go:51 +0x1089
  fyne.io/fyne/v2/cmd/fyne_demo/tutorials.bindingScreen()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/tutorials/bind.go:41 +0xf41
  main.main.func1()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:52 +0x4fd
  main.makeNav.func5()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:177 +0x1b5
  fyne.io/fyne/v2/widget.(*Tree).Select()
      /Users/changkun/dev/changkun.de/fyne/widget/tree.go:242 +0x1f4
  main.makeNav()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:184 +0x326
  main.main()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:61 +0x5c7

Goroutine 31 (running) created at:
  fyne.io/fyne/v2/data/binding.queueItem.func1()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:17 +0x6b
  sync.(*Once).doSlow()
      /Users/changkun/goes/go/src/sync/once.go:68 +0x127
  sync.(*Once).Do()
      /Users/changkun/goes/go/src/sync/once.go:59 +0x46
  fyne.io/fyne/v2/data/binding.queueItem()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:15 +0x37
  fyne.io/fyne/v2/data/binding.(*base).AddListener()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:69 +0x249
  fyne.io/fyne/v2/data/binding.(*boundExternalFloat).AddListener()
      :1 +0x4b
  fyne.io/fyne/v2/data/binding.FloatToStringWithFormat()
      /Users/changkun/dev/changkun.de/fyne/data/binding/convert.go:129 +0x204
  fyne.io/fyne/v2/cmd/fyne_demo/tutorials.bindingScreen()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/tutorials/bind.go:15 +0x1c5
  main.main.func1()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:52 +0x4fd
  main.makeNav.func5()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:177 +0x1b5
  fyne.io/fyne/v2/widget.(*Tree).Select()
      /Users/changkun/dev/changkun.de/fyne/widget/tree.go:242 +0x1f4
  main.makeNav()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:184 +0x326
  main.main()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:61 +0x5c7
==================
==================
WARNING: DATA RACE
Write at 0x00c00011a748 by main goroutine:
  fyne.io/fyne/v2.(*Container).Move()
      /Users/changkun/dev/changkun.de/fyne/container.go:84 +0x44
  fyne.io/fyne/v2/internal/widget.(*scrollContainerRenderer).updatePosition()
      /Users/changkun/dev/changkun.de/fyne/internal/widget/scroller.go:329 +0x1d3
  fyne.io/fyne/v2/internal/widget.(*scrollContainerRenderer).layoutBars()
      /Users/changkun/dev/changkun.de/fyne/internal/widget/scroller.go:269 +0x3ee
  fyne.io/fyne/v2/internal/widget.(*scrollContainerRenderer).Layout()
      /Users/changkun/dev/changkun.de/fyne/internal/widget/scroller.go:276 +0xea
  fyne.io/fyne/v2/internal/widget.(*Base).Resize()
      /Users/changkun/dev/changkun.de/fyne/internal/widget/base.go:59 +0x145
  fyne.io/fyne/v2/internal/widget.(*Scroll).Resize()
      /Users/changkun/dev/changkun.de/fyne/internal/widget/scroller.go:451 +0x92
  fyne.io/fyne/v2/widget.(*listRenderer).Layout()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:230 +0x58
  fyne.io/fyne/v2/widget.(*BaseWidget).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/widget.go:61 +0x139
  fyne.io/fyne/v2/widget.(*List).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:113 +0x4a
  fyne.io/fyne/v2/layout.(*borderLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/borderlayout.go:56 +0x72b
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x23a
  fyne.io/fyne/v2.NewContainerWithLayout()
      /Users/changkun/dev/changkun.de/fyne/container.go:48 +0x198
  fyne.io/fyne/v2/container.NewBorder()
      /Users/changkun/dev/changkun.de/fyne/container/layouts.go:36 +0x4cd
  fyne.io/fyne/v2/cmd/fyne_demo/tutorials.bindingScreen()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/tutorials/bind.go:78 +0x184b
  main.main.func1()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:52 +0x4fd
  main.makeNav.func5()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:177 +0x1b5
  fyne.io/fyne/v2/widget.(*Tree).Select()
      /Users/changkun/dev/changkun.de/fyne/widget/tree.go:242 +0x1f4
  main.makeNav()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:184 +0x326
  main.main()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:61 +0x5c7

Previous write at 0x00c00011a748 by goroutine 31:
  fyne.io/fyne/v2.(*Container).Move()
      /Users/changkun/dev/changkun.de/fyne/container.go:84 +0x44
  fyne.io/fyne/v2/internal/widget.(*scrollContainerRenderer).updatePosition()
      /Users/changkun/dev/changkun.de/fyne/internal/widget/scroller.go:329 +0x1d3
  fyne.io/fyne/v2/internal/widget.(*scrollContainerRenderer).layoutBars()
      /Users/changkun/dev/changkun.de/fyne/internal/widget/scroller.go:269 +0x3ee
  fyne.io/fyne/v2/internal/widget.(*scrollContainerRenderer).Layout()
      /Users/changkun/dev/changkun.de/fyne/internal/widget/scroller.go:276 +0xea
  fyne.io/fyne/v2/internal/widget.(*scrollContainerRenderer).Refresh()
      /Users/changkun/dev/changkun.de/fyne/internal/widget/scroller.go:295 +0x404
  fyne.io/fyne/v2/internal/widget.(*Base).Refresh()
      /Users/changkun/dev/changkun.de/fyne/internal/widget/base.go:136 +0x41
  fyne.io/fyne/v2/internal/widget.(*Scroll).refreshWithoutOffsetUpdate()
      /Users/changkun/dev/changkun.de/fyne/internal/widget/scroller.go:456 +0x44
  fyne.io/fyne/v2/internal/widget.(*Scroll).Refresh()
      /Users/changkun/dev/changkun.de/fyne/internal/widget/scroller.go:442 +0x3c
  fyne.io/fyne/v2/widget.(*listRenderer).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:242 +0x23c
  fyne.io/fyne/v2/widget.(*BaseWidget).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/widget.go:138 +0x41
  fyne.io/fyne/v2/widget.(*BaseWidget).Refresh-fm()
      /Users/changkun/dev/changkun.de/fyne/widget/widget.go:131 +0x39
  fyne.io/fyne/v2/data/binding.(*listener).DataChanged()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:55 +0x3d
  fyne.io/fyne/v2/data/binding.DataListener.DataChanged-fm()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:40 +0x48
  fyne.io/fyne/v2/data/binding.queueItem.func1.1()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:19 +0x74

Goroutine 31 (running) created at:
  fyne.io/fyne/v2/data/binding.queueItem.func1()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:17 +0x6b
  sync.(*Once).doSlow()
      /Users/changkun/goes/go/src/sync/once.go:68 +0x127
  sync.(*Once).Do()
      /Users/changkun/goes/go/src/sync/once.go:59 +0x46
  fyne.io/fyne/v2/data/binding.queueItem()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:15 +0x37
  fyne.io/fyne/v2/data/binding.(*base).AddListener()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:69 +0x249
  fyne.io/fyne/v2/data/binding.(*boundExternalFloat).AddListener()
      :1 +0x4b
  fyne.io/fyne/v2/data/binding.FloatToStringWithFormat()
      /Users/changkun/dev/changkun.de/fyne/data/binding/convert.go:129 +0x204
  fyne.io/fyne/v2/cmd/fyne_demo/tutorials.bindingScreen()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/tutorials/bind.go:15 +0x1c5
  main.main.func1()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:52 +0x4fd
  main.makeNav.func5()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:177 +0x1b5
  fyne.io/fyne/v2/widget.(*Tree).Select()
      /Users/changkun/dev/changkun.de/fyne/widget/tree.go:242 +0x1f4
  main.makeNav()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:184 +0x326
  main.main()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:61 +0x5c7
==================
==================
WARNING: DATA RACE
Read at 0x00c00010c7f8 by goroutine 31:
  fyne.io/fyne/v2/widget.(*Label).createListener.func1()
      /Users/changkun/dev/changkun.de/fyne/widget/label.go:144 +0x3a
  fyne.io/fyne/v2/data/binding.(*listener).DataChanged()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:55 +0x3d
  fyne.io/fyne/v2/data/binding.DataListener.DataChanged-fm()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:40 +0x48
  fyne.io/fyne/v2/data/binding.queueItem.func1.1()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:19 +0x74

Previous write at 0x00c00010c7f8 by main goroutine:
  fyne.io/fyne/v2/widget.(*Label).Unbind()
      /Users/changkun/dev/changkun.de/fyne/widget/label.go:135 +0xad
  fyne.io/fyne/v2/widget.(*Label).Bind()
      /Users/changkun/dev/changkun.de/fyne/widget/label.go:54 +0x3d
  fyne.io/fyne/v2/cmd/fyne_demo/tutorials.bindingScreen.func7()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/tutorials/bind.go:58 +0xf8
  fyne.io/fyne/v2/widget.NewListWithData.func1()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:66 +0xed
  fyne.io/fyne/v2/widget.(*listLayout).setupListItem()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:411 +0x19b
  fyne.io/fyne/v2/widget.(*listLayout).updateList()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:456 +0x66f
  fyne.io/fyne/v2/widget.(*List).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:114 +0xc4
  fyne.io/fyne/v2/layout.(*borderLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/borderlayout.go:56 +0x72b
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/layout.(*gridLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/gridlayout.go:102 +0x33e
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x23a
  fyne.io/fyne/v2.NewContainerWithLayout()
      /Users/changkun/dev/changkun.de/fyne/container.go:48 +0x198
  fyne.io/fyne/v2/container.NewGridWithColumns()
      /Users/changkun/dev/changkun.de/fyne/container/layouts.go:51 +0x1952
  fyne.io/fyne/v2/cmd/fyne_demo/tutorials.bindingScreen()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/tutorials/bind.go:79 +0x1854
  main.main.func1()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:52 +0x4fd
  main.makeNav.func5()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:177 +0x1b5
  fyne.io/fyne/v2/widget.(*Tree).Select()
      /Users/changkun/dev/changkun.de/fyne/widget/tree.go:242 +0x1f4
  main.makeNav()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:184 +0x326
  main.main()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:61 +0x5c7

Goroutine 31 (running) created at:
  fyne.io/fyne/v2/data/binding.queueItem.func1()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:17 +0x6b
  sync.(*Once).doSlow()
      /Users/changkun/goes/go/src/sync/once.go:68 +0x127
  sync.(*Once).Do()
      /Users/changkun/goes/go/src/sync/once.go:59 +0x46
  fyne.io/fyne/v2/data/binding.queueItem()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:15 +0x37
  fyne.io/fyne/v2/data/binding.(*base).AddListener()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:69 +0x249
  fyne.io/fyne/v2/data/binding.(*boundExternalFloat).AddListener()
      :1 +0x4b
  fyne.io/fyne/v2/data/binding.FloatToStringWithFormat()
      /Users/changkun/dev/changkun.de/fyne/data/binding/convert.go:129 +0x204
  fyne.io/fyne/v2/cmd/fyne_demo/tutorials.bindingScreen()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/tutorials/bind.go:15 +0x1c5
  main.main.func1()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:52 +0x4fd
  main.makeNav.func5()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:177 +0x1b5
  fyne.io/fyne/v2/widget.(*Tree).Select()
      /Users/changkun/dev/changkun.de/fyne/widget/tree.go:242 +0x1f4
  main.makeNav()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:184 +0x326
  main.main()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:61 +0x5c7
==================
==================
WARNING: DATA RACE
Read at 0x00c00007eae0 by goroutine 31:
  fyne.io/fyne/v2/data/binding.(*stringFromFloat).Get()
      /Users/changkun/dev/changkun.de/fyne/data/binding/convert.go:134 +0x44
  fyne.io/fyne/v2/widget.(*Label).createListener.func1()
      /Users/changkun/dev/changkun.de/fyne/widget/label.go:148 +0x59
  fyne.io/fyne/v2/data/binding.(*listener).DataChanged()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:55 +0x3d
  fyne.io/fyne/v2/data/binding.DataListener.DataChanged-fm()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:40 +0x48
  fyne.io/fyne/v2/data/binding.queueItem.func1.1()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:19 +0x74

Previous write at 0x00c00007eae0 by main goroutine:
  fyne.io/fyne/v2/data/binding.FloatToStringWithFormat()
      /Users/changkun/dev/changkun.de/fyne/data/binding/convert.go:128 +0x135
  fyne.io/fyne/v2/cmd/fyne_demo/tutorials.bindingScreen.func7()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/tutorials/bind.go:58 +0xe8
  fyne.io/fyne/v2/widget.NewListWithData.func1()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:66 +0xed
  fyne.io/fyne/v2/widget.(*listLayout).setupListItem()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:411 +0x19b
  fyne.io/fyne/v2/widget.(*listLayout).updateList()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:456 +0x66f
  fyne.io/fyne/v2/widget.(*List).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:114 +0xc4
  fyne.io/fyne/v2/layout.(*borderLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/borderlayout.go:56 +0x72b
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/layout.(*gridLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/gridlayout.go:102 +0x33e
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x23a
  fyne.io/fyne/v2.NewContainerWithLayout()
      /Users/changkun/dev/changkun.de/fyne/container.go:48 +0x198
  fyne.io/fyne/v2/container.NewGridWithColumns()
      /Users/changkun/dev/changkun.de/fyne/container/layouts.go:51 +0x1952
  fyne.io/fyne/v2/cmd/fyne_demo/tutorials.bindingScreen()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/tutorials/bind.go:79 +0x1854
  main.main.func1()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:52 +0x4fd
  main.makeNav.func5()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:177 +0x1b5
  fyne.io/fyne/v2/widget.(*Tree).Select()
      /Users/changkun/dev/changkun.de/fyne/widget/tree.go:242 +0x1f4
  main.makeNav()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:184 +0x326
  main.main()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:61 +0x5c7

Goroutine 31 (running) created at:
  fyne.io/fyne/v2/data/binding.queueItem.func1()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:17 +0x6b
  sync.(*Once).doSlow()
      /Users/changkun/goes/go/src/sync/once.go:68 +0x127
  sync.(*Once).Do()
      /Users/changkun/goes/go/src/sync/once.go:59 +0x46
  fyne.io/fyne/v2/data/binding.queueItem()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:15 +0x37
  fyne.io/fyne/v2/data/binding.(*base).AddListener()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:69 +0x249
  fyne.io/fyne/v2/data/binding.(*boundExternalFloat).AddListener()
      :1 +0x4b
  fyne.io/fyne/v2/data/binding.FloatToStringWithFormat()
      /Users/changkun/dev/changkun.de/fyne/data/binding/convert.go:129 +0x204
  fyne.io/fyne/v2/cmd/fyne_demo/tutorials.bindingScreen()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/tutorials/bind.go:15 +0x1c5
  main.main.func1()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:52 +0x4fd
  main.makeNav.func5()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:177 +0x1b5
  fyne.io/fyne/v2/widget.(*Tree).Select()
      /Users/changkun/dev/changkun.de/fyne/widget/tree.go:242 +0x1f4
  main.makeNav()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:184 +0x326
  main.main()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:61 +0x5c7
==================
==================
WARNING: DATA RACE
Write at 0x00c00020b8d0 by main goroutine:
  fyne.io/fyne/v2/widget.(*TextSegment).Update()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext_objects.go:360 +0x86
  fyne.io/fyne/v2/widget.(*textRenderer).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:579 +0x941
  fyne.io/fyne/v2/widget.(*BaseWidget).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/widget.go:138 +0x41
  fyne.io/fyne/v2/widget.(*RichText).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:91 +0x3a
  fyne.io/fyne/v2/widget.(*RichText).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:111 +0x104
  fyne.io/fyne/v2/widget.(*Label).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/label.go:110 +0x8d
  fyne.io/fyne/v2/layout.(*borderLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/borderlayout.go:56 +0x72b
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/widget.(*listItemRenderer).Layout()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:332 +0xc3
  fyne.io/fyne/v2/widget.(*BaseWidget).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/widget.go:61 +0x139
  fyne.io/fyne/v2/widget.(*listLayout).updateList()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:454 +0x64c
  fyne.io/fyne/v2/widget.(*listLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:369 +0x33
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/internal/widget.(*scrollContainerRenderer).Layout()
      /Users/changkun/dev/changkun.de/fyne/internal/widget/scroller.go:274 +0xd4
  fyne.io/fyne/v2/internal/widget.(*Base).Resize()
      /Users/changkun/dev/changkun.de/fyne/internal/widget/base.go:59 +0x145
  fyne.io/fyne/v2/internal/widget.(*Scroll).Resize()
      /Users/changkun/dev/changkun.de/fyne/internal/widget/scroller.go:451 +0x92
  fyne.io/fyne/v2/widget.(*listRenderer).Layout()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:230 +0x58
  fyne.io/fyne/v2/widget.(*BaseWidget).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/widget.go:61 +0x139
  fyne.io/fyne/v2/widget.(*List).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:113 +0x4a
  fyne.io/fyne/v2/layout.(*borderLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/borderlayout.go:56 +0x72b
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/layout.(*gridLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/gridlayout.go:102 +0x33e
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/layout.(*borderLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/borderlayout.go:56 +0x72b
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x23a
  fyne.io/fyne/v2.NewContainerWithLayout()
      /Users/changkun/dev/changkun.de/fyne/container.go:48 +0x198
  fyne.io/fyne/v2/container.NewBorder()
      /Users/changkun/dev/changkun.de/fyne/container/layouts.go:36 +0x4cd
  fyne.io/fyne/v2/cmd/fyne_demo/tutorials.bindingScreen()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/tutorials/bind.go:79 +0x19d5
  main.main.func1()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:52 +0x4fd
  main.makeNav.func5()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:177 +0x1b5
  fyne.io/fyne/v2/widget.(*Tree).Select()
      /Users/changkun/dev/changkun.de/fyne/widget/tree.go:242 +0x1f4
  main.makeNav()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:184 +0x326
  main.main()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:61 +0x5c7

Previous read at 0x00c00020b8d0 by goroutine 31:
  fyne.io/fyne/v2/canvas.(*Text).MinSize()
      /Users/changkun/dev/changkun.de/fyne/canvas/text.go:28 +0x36
  fyne.io/fyne/v2/widget.(*textRenderer).layoutRow()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:621 +0x18d
  fyne.io/fyne/v2/widget.(*textRenderer).Layout()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:483 +0x98a
  fyne.io/fyne/v2/widget.(*textRenderer).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:613 +0x755
  fyne.io/fyne/v2/widget.(*BaseWidget).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/widget.go:138 +0x41
  fyne.io/fyne/v2/widget.(*RichText).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:91 +0x3a
  fyne.io/fyne/v2/widget.(*Label).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/label.go:100 +0x29c
  fyne.io/fyne/v2/widget.(*Label).createListener.func1()
      /Users/changkun/dev/changkun.de/fyne/widget/label.go:156 +0xc6
  fyne.io/fyne/v2/data/binding.(*listener).DataChanged()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:55 +0x3d
  fyne.io/fyne/v2/data/binding.DataListener.DataChanged-fm()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:40 +0x48
  fyne.io/fyne/v2/data/binding.queueItem.func1.1()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:19 +0x74

Goroutine 31 (running) created at:
  fyne.io/fyne/v2/data/binding.queueItem.func1()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:17 +0x6b
  sync.(*Once).doSlow()
      /Users/changkun/goes/go/src/sync/once.go:68 +0x127
  sync.(*Once).Do()
      /Users/changkun/goes/go/src/sync/once.go:59 +0x46
  fyne.io/fyne/v2/data/binding.queueItem()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:15 +0x37
  fyne.io/fyne/v2/data/binding.(*base).AddListener()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:69 +0x249
  fyne.io/fyne/v2/data/binding.(*boundExternalFloat).AddListener()
      :1 +0x4b
  fyne.io/fyne/v2/data/binding.FloatToStringWithFormat()
      /Users/changkun/dev/changkun.de/fyne/data/binding/convert.go:129 +0x204
  fyne.io/fyne/v2/cmd/fyne_demo/tutorials.bindingScreen()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/tutorials/bind.go:15 +0x1c5
  main.main.func1()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:52 +0x4fd
  main.makeNav.func5()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:177 +0x1b5
  fyne.io/fyne/v2/widget.(*Tree).Select()
      /Users/changkun/dev/changkun.de/fyne/widget/tree.go:242 +0x1f4
  main.makeNav()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:184 +0x326
  main.main()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:61 +0x5c7
==================
==================
WARNING: DATA RACE
Write at 0x00c00020b8e8 by main goroutine:
  fyne.io/fyne/v2/widget.(*TextSegment).Update()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext_objects.go:363 +0x195
  fyne.io/fyne/v2/widget.(*textRenderer).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:579 +0x941
  fyne.io/fyne/v2/widget.(*BaseWidget).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/widget.go:138 +0x41
  fyne.io/fyne/v2/widget.(*RichText).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:91 +0x3a
  fyne.io/fyne/v2/widget.(*RichText).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:111 +0x104
  fyne.io/fyne/v2/widget.(*Label).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/label.go:110 +0x8d
  fyne.io/fyne/v2/layout.(*borderLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/borderlayout.go:56 +0x72b
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/widget.(*listItemRenderer).Layout()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:332 +0xc3
  fyne.io/fyne/v2/widget.(*BaseWidget).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/widget.go:61 +0x139
  fyne.io/fyne/v2/widget.(*listLayout).updateList()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:454 +0x64c
  fyne.io/fyne/v2/widget.(*listLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:369 +0x33
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/internal/widget.(*scrollContainerRenderer).Layout()
      /Users/changkun/dev/changkun.de/fyne/internal/widget/scroller.go:274 +0xd4
  fyne.io/fyne/v2/internal/widget.(*Base).Resize()
      /Users/changkun/dev/changkun.de/fyne/internal/widget/base.go:59 +0x145
  fyne.io/fyne/v2/internal/widget.(*Scroll).Resize()
      /Users/changkun/dev/changkun.de/fyne/internal/widget/scroller.go:451 +0x92
  fyne.io/fyne/v2/widget.(*listRenderer).Layout()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:230 +0x58
  fyne.io/fyne/v2/widget.(*BaseWidget).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/widget.go:61 +0x139
  fyne.io/fyne/v2/widget.(*List).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:113 +0x4a
  fyne.io/fyne/v2/layout.(*borderLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/borderlayout.go:56 +0x72b
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/layout.(*gridLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/gridlayout.go:102 +0x33e
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/layout.(*borderLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/borderlayout.go:56 +0x72b
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x23a
  fyne.io/fyne/v2.NewContainerWithLayout()
      /Users/changkun/dev/changkun.de/fyne/container.go:48 +0x198
  fyne.io/fyne/v2/container.NewBorder()
      /Users/changkun/dev/changkun.de/fyne/container/layouts.go:36 +0x4cd
  fyne.io/fyne/v2/cmd/fyne_demo/tutorials.bindingScreen()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/tutorials/bind.go:79 +0x19d5
  main.main.func1()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:52 +0x4fd
  main.makeNav.func5()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:177 +0x1b5
  fyne.io/fyne/v2/widget.(*Tree).Select()
      /Users/changkun/dev/changkun.de/fyne/widget/tree.go:242 +0x1f4
  main.makeNav()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:184 +0x326
  main.main()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:61 +0x5c7

Previous read at 0x00c00020b8e8 by goroutine 31:
  runtime.racereadrange()
      :1 +0x1b
  fyne.io/fyne/v2/widget.(*textRenderer).layoutRow()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:621 +0x18d
  fyne.io/fyne/v2/widget.(*textRenderer).Layout()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:483 +0x98a
  fyne.io/fyne/v2/widget.(*textRenderer).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:613 +0x755
  fyne.io/fyne/v2/widget.(*BaseWidget).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/widget.go:138 +0x41
  fyne.io/fyne/v2/widget.(*RichText).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:91 +0x3a
  fyne.io/fyne/v2/widget.(*Label).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/label.go:100 +0x29c
  fyne.io/fyne/v2/widget.(*Label).createListener.func1()
      /Users/changkun/dev/changkun.de/fyne/widget/label.go:156 +0xc6
  fyne.io/fyne/v2/data/binding.(*listener).DataChanged()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:55 +0x3d
  fyne.io/fyne/v2/data/binding.DataListener.DataChanged-fm()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:40 +0x48
  fyne.io/fyne/v2/data/binding.queueItem.func1.1()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:19 +0x74

Goroutine 31 (running) created at:
  fyne.io/fyne/v2/data/binding.queueItem.func1()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:17 +0x6b
  sync.(*Once).doSlow()
      /Users/changkun/goes/go/src/sync/once.go:68 +0x127
  sync.(*Once).Do()
      /Users/changkun/goes/go/src/sync/once.go:59 +0x46
  fyne.io/fyne/v2/data/binding.queueItem()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:15 +0x37
  fyne.io/fyne/v2/data/binding.(*base).AddListener()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:69 +0x249
  fyne.io/fyne/v2/data/binding.(*boundExternalFloat).AddListener()
      :1 +0x4b
  fyne.io/fyne/v2/data/binding.FloatToStringWithFormat()
      /Users/changkun/dev/changkun.de/fyne/data/binding/convert.go:129 +0x204
  fyne.io/fyne/v2/cmd/fyne_demo/tutorials.bindingScreen()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/tutorials/bind.go:15 +0x1c5
  main.main.func1()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:52 +0x4fd
  main.makeNav.func5()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:177 +0x1b5
  fyne.io/fyne/v2/widget.(*Tree).Select()
      /Users/changkun/dev/changkun.de/fyne/widget/tree.go:242 +0x1f4
  main.makeNav()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:184 +0x326
  main.main()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:61 +0x5c7
==================
==================
WARNING: DATA RACE
Write at 0x00c00020b8e0 by main goroutine:
  fyne.io/fyne/v2/widget.(*TextSegment).Update()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext_objects.go:364 +0x1d9
  fyne.io/fyne/v2/widget.(*textRenderer).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:579 +0x941
  fyne.io/fyne/v2/widget.(*BaseWidget).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/widget.go:138 +0x41
  fyne.io/fyne/v2/widget.(*RichText).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:91 +0x3a
  fyne.io/fyne/v2/widget.(*RichText).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:111 +0x104
  fyne.io/fyne/v2/widget.(*Label).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/label.go:110 +0x8d
  fyne.io/fyne/v2/layout.(*borderLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/borderlayout.go:56 +0x72b
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/widget.(*listItemRenderer).Layout()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:332 +0xc3
  fyne.io/fyne/v2/widget.(*BaseWidget).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/widget.go:61 +0x139
  fyne.io/fyne/v2/widget.(*listLayout).updateList()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:454 +0x64c
  fyne.io/fyne/v2/widget.(*listLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:369 +0x33
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/internal/widget.(*scrollContainerRenderer).Layout()
      /Users/changkun/dev/changkun.de/fyne/internal/widget/scroller.go:274 +0xd4
  fyne.io/fyne/v2/internal/widget.(*Base).Resize()
      /Users/changkun/dev/changkun.de/fyne/internal/widget/base.go:59 +0x145
  fyne.io/fyne/v2/internal/widget.(*Scroll).Resize()
      /Users/changkun/dev/changkun.de/fyne/internal/widget/scroller.go:451 +0x92
  fyne.io/fyne/v2/widget.(*listRenderer).Layout()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:230 +0x58
  fyne.io/fyne/v2/widget.(*BaseWidget).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/widget.go:61 +0x139
  fyne.io/fyne/v2/widget.(*List).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:113 +0x4a
  fyne.io/fyne/v2/layout.(*borderLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/borderlayout.go:56 +0x72b
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/layout.(*gridLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/gridlayout.go:102 +0x33e
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/layout.(*borderLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/borderlayout.go:56 +0x72b
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x23a
  fyne.io/fyne/v2.NewContainerWithLayout()
      /Users/changkun/dev/changkun.de/fyne/container.go:48 +0x198
  fyne.io/fyne/v2/container.NewBorder()
      /Users/changkun/dev/changkun.de/fyne/container/layouts.go:36 +0x4cd
  fyne.io/fyne/v2/cmd/fyne_demo/tutorials.bindingScreen()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/tutorials/bind.go:79 +0x19d5
  main.main.func1()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:52 +0x4fd
  main.makeNav.func5()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:177 +0x1b5
  fyne.io/fyne/v2/widget.(*Tree).Select()
      /Users/changkun/dev/changkun.de/fyne/widget/tree.go:242 +0x1f4
  main.makeNav()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:184 +0x326
  main.main()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:61 +0x5c7

Previous read at 0x00c00020b8e0 by goroutine 31:
  fyne.io/fyne/v2/canvas.(*Text).MinSize()
      /Users/changkun/dev/changkun.de/fyne/canvas/text.go:28 +0x56
  fyne.io/fyne/v2/widget.(*textRenderer).layoutRow()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:621 +0x18d
  fyne.io/fyne/v2/widget.(*textRenderer).Layout()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:483 +0x98a
  fyne.io/fyne/v2/widget.(*textRenderer).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:613 +0x755
  fyne.io/fyne/v2/widget.(*BaseWidget).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/widget.go:138 +0x41
  fyne.io/fyne/v2/widget.(*RichText).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:91 +0x3a
  fyne.io/fyne/v2/widget.(*Label).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/label.go:100 +0x29c
  fyne.io/fyne/v2/widget.(*Label).createListener.func1()
      /Users/changkun/dev/changkun.de/fyne/widget/label.go:156 +0xc6
  fyne.io/fyne/v2/data/binding.(*listener).DataChanged()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:55 +0x3d
  fyne.io/fyne/v2/data/binding.DataListener.DataChanged-fm()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:40 +0x48
  fyne.io/fyne/v2/data/binding.queueItem.func1.1()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:19 +0x74

Goroutine 31 (running) created at:
  fyne.io/fyne/v2/data/binding.queueItem.func1()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:17 +0x6b
  sync.(*Once).doSlow()
      /Users/changkun/goes/go/src/sync/once.go:68 +0x127
  sync.(*Once).Do()
      /Users/changkun/goes/go/src/sync/once.go:59 +0x46
  fyne.io/fyne/v2/data/binding.queueItem()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:15 +0x37
  fyne.io/fyne/v2/data/binding.(*base).AddListener()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:69 +0x249
  fyne.io/fyne/v2/data/binding.(*boundExternalFloat).AddListener()
      :1 +0x4b
  fyne.io/fyne/v2/data/binding.FloatToStringWithFormat()
      /Users/changkun/dev/changkun.de/fyne/data/binding/convert.go:129 +0x204
  fyne.io/fyne/v2/cmd/fyne_demo/tutorials.bindingScreen()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/tutorials/bind.go:15 +0x1c5
  main.main.func1()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:52 +0x4fd
  main.makeNav.func5()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:177 +0x1b5
  fyne.io/fyne/v2/widget.(*Tree).Select()
      /Users/changkun/dev/changkun.de/fyne/widget/tree.go:242 +0x1f4
  main.makeNav()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:184 +0x326
  main.main()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:61 +0x5c7
==================
==================
WARNING: DATA RACE
Read at 0x00c0000ccf78 by goroutine 31:
  fyne.io/fyne/v2/widget.(*Label).createListener.func1()
      /Users/changkun/dev/changkun.de/fyne/widget/label.go:144 +0x3a
  fyne.io/fyne/v2/data/binding.(*listener).DataChanged()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:55 +0x3d
  fyne.io/fyne/v2/data/binding.DataListener.DataChanged-fm()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:40 +0x48
  fyne.io/fyne/v2/data/binding.queueItem.func1.1()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:19 +0x74

Previous write at 0x00c0000ccf78 by main goroutine:
  [failed to restore the stack]

Goroutine 31 (running) created at:
  fyne.io/fyne/v2/data/binding.queueItem.func1()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:17 +0x6b
  sync.(*Once).doSlow()
      /Users/changkun/goes/go/src/sync/once.go:68 +0x127
  sync.(*Once).Do()
      /Users/changkun/goes/go/src/sync/once.go:59 +0x46
  fyne.io/fyne/v2/data/binding.queueItem()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:15 +0x37
  fyne.io/fyne/v2/data/binding.(*base).AddListener()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:69 +0x249
  fyne.io/fyne/v2/data/binding.(*boundExternalFloat).AddListener()
      :1 +0x4b
  fyne.io/fyne/v2/data/binding.FloatToStringWithFormat()
      /Users/changkun/dev/changkun.de/fyne/data/binding/convert.go:129 +0x204
  fyne.io/fyne/v2/cmd/fyne_demo/tutorials.bindingScreen()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/tutorials/bind.go:15 +0x1c5
  main.main.func1()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:52 +0x4fd
  main.makeNav.func5()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:177 +0x1b5
  fyne.io/fyne/v2/widget.(*Tree).Select()
      /Users/changkun/dev/changkun.de/fyne/widget/tree.go:242 +0x1f4
  main.makeNav()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:184 +0x326
  main.main()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:61 +0x5c7
==================
==================
WARNING: DATA RACE
Read at 0x00c000292b18 by goroutine 31:
  fyne.io/fyne/v2/widget.(*Label).createListener.func1()
      /Users/changkun/dev/changkun.de/fyne/widget/label.go:144 +0x3a
  fyne.io/fyne/v2/data/binding.(*listener).DataChanged()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:55 +0x3d
  fyne.io/fyne/v2/data/binding.DataListener.DataChanged-fm()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:40 +0x48
  fyne.io/fyne/v2/data/binding.queueItem.func1.1()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:19 +0x74

Previous write at 0x00c000292b18 by main goroutine:
  fyne.io/fyne/v2/widget.(*Label).Unbind()
      /Users/changkun/dev/changkun.de/fyne/widget/label.go:135 +0xad
  fyne.io/fyne/v2/widget.(*Label).Bind()
      /Users/changkun/dev/changkun.de/fyne/widget/label.go:54 +0x3d
  fyne.io/fyne/v2/cmd/fyne_demo/tutorials.bindingScreen.func7()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/tutorials/bind.go:58 +0xf8
  fyne.io/fyne/v2/widget.NewListWithData.func1()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:66 +0xed
  fyne.io/fyne/v2/widget.(*listLayout).setupListItem()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:411 +0x19b
  fyne.io/fyne/v2/widget.(*listLayout).updateList()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:456 +0x66f
  fyne.io/fyne/v2/widget.(*List).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:114 +0xc4
  fyne.io/fyne/v2/layout.(*borderLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/borderlayout.go:56 +0x72b
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/layout.(*gridLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/gridlayout.go:102 +0x33e
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/layout.(*borderLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/borderlayout.go:56 +0x72b
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/layout.(*maxLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/maxlayout.go:22 +0xa1
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/layout.(*borderLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/borderlayout.go:56 +0x72b
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/container.(*splitContainerRenderer).Layout()
      /Users/changkun/dev/changkun.de/fyne/container/split.go:126 +0x3f2
  fyne.io/fyne/v2/widget.(*BaseWidget).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/widget.go:61 +0x139
  fyne.io/fyne/v2/container.(*Split).Resize()
      :1 +0x4f
  fyne.io/fyne/v2/internal/driver/glfw.(*glCanvas).SetContent()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/canvas.go:143 +0xf8
  fyne.io/fyne/v2/internal/driver/glfw.(*window).SetContent()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/window.go:489 +0xeb
  main.main()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:63 +0x621

Goroutine 31 (running) created at:
  fyne.io/fyne/v2/data/binding.queueItem.func1()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:17 +0x6b
  sync.(*Once).doSlow()
      /Users/changkun/goes/go/src/sync/once.go:68 +0x127
  sync.(*Once).Do()
      /Users/changkun/goes/go/src/sync/once.go:59 +0x46
  fyne.io/fyne/v2/data/binding.queueItem()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:15 +0x37
  fyne.io/fyne/v2/data/binding.(*base).AddListener()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:69 +0x249
  fyne.io/fyne/v2/data/binding.(*boundExternalFloat).AddListener()
      :1 +0x4b
  fyne.io/fyne/v2/data/binding.FloatToStringWithFormat()
      /Users/changkun/dev/changkun.de/fyne/data/binding/convert.go:129 +0x204
  fyne.io/fyne/v2/cmd/fyne_demo/tutorials.bindingScreen()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/tutorials/bind.go:15 +0x1c5
  main.main.func1()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:52 +0x4fd
  main.makeNav.func5()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:177 +0x1b5
  fyne.io/fyne/v2/widget.(*Tree).Select()
      /Users/changkun/dev/changkun.de/fyne/widget/tree.go:242 +0x1f4
  main.makeNav()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:184 +0x326
  main.main()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:61 +0x5c7
==================
==================
WARNING: DATA RACE
Read at 0x00c0000cd1f8 by goroutine 31:
  fyne.io/fyne/v2/widget.(*Label).createListener.func1()
      /Users/changkun/dev/changkun.de/fyne/widget/label.go:144 +0x3a
  fyne.io/fyne/v2/data/binding.(*listener).DataChanged()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:55 +0x3d
  fyne.io/fyne/v2/data/binding.DataListener.DataChanged-fm()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:40 +0x48
  fyne.io/fyne/v2/data/binding.queueItem.func1.1()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:19 +0x74

Previous write at 0x00c0000cd1f8 by main goroutine:
  fyne.io/fyne/v2/widget.(*Label).Unbind()
      /Users/changkun/dev/changkun.de/fyne/widget/label.go:135 +0xad
  fyne.io/fyne/v2/widget.(*Label).Bind()
      /Users/changkun/dev/changkun.de/fyne/widget/label.go:54 +0x3d
  fyne.io/fyne/v2/cmd/fyne_demo/tutorials.bindingScreen.func7()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/tutorials/bind.go:58 +0xf8
  fyne.io/fyne/v2/widget.NewListWithData.func1()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:66 +0xed
  fyne.io/fyne/v2/widget.(*listLayout).setupListItem()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:411 +0x19b
  fyne.io/fyne/v2/widget.(*listLayout).updateList()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:456 +0x66f
  fyne.io/fyne/v2/widget.(*List).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:114 +0xc4
  fyne.io/fyne/v2/layout.(*borderLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/borderlayout.go:56 +0x72b
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/layout.(*gridLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/gridlayout.go:102 +0x33e
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/layout.(*borderLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/borderlayout.go:56 +0x72b
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/layout.(*maxLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/maxlayout.go:22 +0xa1
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/layout.(*borderLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/borderlayout.go:56 +0x72b
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/container.(*splitContainerRenderer).Layout()
      /Users/changkun/dev/changkun.de/fyne/container/split.go:126 +0x3f2
  fyne.io/fyne/v2/widget.(*BaseWidget).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/widget.go:61 +0x139
  fyne.io/fyne/v2/container.(*Split).Resize()
      :1 +0x4f
  fyne.io/fyne/v2/internal/driver/glfw.(*glCanvas).Resize()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/canvas.go:123 +0x110
  fyne.io/fyne/v2/internal/driver/glfw.(*glCanvas).SetContent()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/canvas.go:148 +0x1ba
  fyne.io/fyne/v2/internal/driver/glfw.(*window).SetContent()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/window.go:489 +0xeb
  main.main()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:63 +0x621

Goroutine 31 (running) created at:
  fyne.io/fyne/v2/data/binding.queueItem.func1()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:17 +0x6b
  sync.(*Once).doSlow()
      /Users/changkun/goes/go/src/sync/once.go:68 +0x127
  sync.(*Once).Do()
      /Users/changkun/goes/go/src/sync/once.go:59 +0x46
  fyne.io/fyne/v2/data/binding.queueItem()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:15 +0x37
  fyne.io/fyne/v2/data/binding.(*base).AddListener()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:69 +0x249
  fyne.io/fyne/v2/data/binding.(*boundExternalFloat).AddListener()
      :1 +0x4b
  fyne.io/fyne/v2/data/binding.FloatToStringWithFormat()
      /Users/changkun/dev/changkun.de/fyne/data/binding/convert.go:129 +0x204
  fyne.io/fyne/v2/cmd/fyne_demo/tutorials.bindingScreen()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/tutorials/bind.go:15 +0x1c5
  main.main.func1()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:52 +0x4fd
  main.makeNav.func5()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:177 +0x1b5
  fyne.io/fyne/v2/widget.(*Tree).Select()
      /Users/changkun/dev/changkun.de/fyne/widget/tree.go:242 +0x1f4
  main.makeNav()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:184 +0x326
  main.main()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:61 +0x5c7
==================
2021/09/28 10:47:45 Lifecycle: Started
==================
WARNING: DATA RACE
Write at 0x00c000529750 by main goroutine:
  fyne.io/fyne/v2/widget.(*TextSegment).Update()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext_objects.go:360 +0x86
  fyne.io/fyne/v2/widget.(*textRenderer).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:579 +0x941
  fyne.io/fyne/v2/widget.(*BaseWidget).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/widget.go:138 +0x41
  fyne.io/fyne/v2/widget.(*RichText).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:91 +0x3a
  fyne.io/fyne/v2/widget.(*RichText).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:111 +0x104
  fyne.io/fyne/v2/widget.(*Label).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/label.go:110 +0x8d
  fyne.io/fyne/v2/layout.(*borderLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/borderlayout.go:56 +0x72b
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/widget.(*listItemRenderer).Layout()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:332 +0xc3
  fyne.io/fyne/v2/widget.(*BaseWidget).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/widget.go:61 +0x139
  fyne.io/fyne/v2/widget.(*listLayout).updateList()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:454 +0x64c
  fyne.io/fyne/v2/widget.(*listLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:369 +0x33
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/internal/widget.(*scrollContainerRenderer).Layout()
      /Users/changkun/dev/changkun.de/fyne/internal/widget/scroller.go:274 +0xd4
  fyne.io/fyne/v2/internal/widget.(*Base).Resize()
      /Users/changkun/dev/changkun.de/fyne/internal/widget/base.go:59 +0x145
  fyne.io/fyne/v2/internal/widget.(*Scroll).Resize()
      /Users/changkun/dev/changkun.de/fyne/internal/widget/scroller.go:451 +0x92
  fyne.io/fyne/v2/widget.(*listRenderer).Layout()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:230 +0x58
  fyne.io/fyne/v2/widget.(*BaseWidget).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/widget.go:61 +0x139
  fyne.io/fyne/v2/widget.(*List).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:113 +0x4a
  fyne.io/fyne/v2/layout.(*borderLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/borderlayout.go:56 +0x72b
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/layout.(*gridLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/gridlayout.go:102 +0x33e
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/layout.(*borderLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/borderlayout.go:56 +0x72b
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/layout.(*maxLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/maxlayout.go:22 +0xa1
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/layout.(*borderLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/borderlayout.go:56 +0x72b
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/container.(*splitContainerRenderer).Layout()
      /Users/changkun/dev/changkun.de/fyne/container/split.go:126 +0x3f2
  fyne.io/fyne/v2/widget.(*BaseWidget).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/widget.go:61 +0x139
  fyne.io/fyne/v2/container.(*Split).Resize()
      :1 +0x4f
  fyne.io/fyne/v2/internal/driver/glfw.(*glCanvas).Resize()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/canvas.go:123 +0x110
  fyne.io/fyne/v2/internal/driver/glfw.(*window).resized()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/window.go:546 +0x1d6
  fyne.io/fyne/v2/internal/driver/glfw.(*window).resized-fm()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/window.go:538 +0x57
  github.com/go-gl/glfw/v3.3/glfw.goWindowSizeCB()
      /Users/changkun/dev/changkun.de/fyne/vendor/github.com/go-gl/glfw/v3.3/glfw/window.go:213 +0x70
  _cgoexp_d63f5f7b2d6a_goWindowSizeCB()
      _cgo_gotypes.go:2638 +0x71
  runtime.cgocallbackg1()
      /Users/changkun/goes/go/src/runtime/cgocall.go:306 +0x2ab
  github.com/go-gl/glfw/v3.3/glfw.(*Window).SetSize.func1()
      /Users/changkun/dev/changkun.de/fyne/vendor/github.com/go-gl/glfw/v3.3/glfw/window.go:496 +0x84
  github.com/go-gl/glfw/v3.3/glfw.(*Window).SetSize()
      /Users/changkun/dev/changkun.de/fyne/vendor/github.com/go-gl/glfw/v3.3/glfw/window.go:496 +0x44
  fyne.io/fyne/v2/internal/driver/glfw.(*window).Resize.func1()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/window.go:198 +0x1ca
  fyne.io/fyne/v2/internal/driver/glfw.(*window).create.func3()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/window.go:1471 +0x6dd
  fyne.io/fyne/v2/internal/driver/glfw.(*gLDriver).runGL()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/loop.go:104 +0x226
  fyne.io/fyne/v2/internal/driver/glfw.(*gLDriver).Run()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/driver.go:83 +0x39
  fyne.io/fyne/v2/internal/driver/glfw.(*window).ShowAndRun()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/window.go:461 +0x55
  main.main()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:66 +0x654

Previous read at 0x00c000529750 by goroutine 31:
  fyne.io/fyne/v2/canvas.(*Text).MinSize()
      /Users/changkun/dev/changkun.de/fyne/canvas/text.go:28 +0x36
  fyne.io/fyne/v2/widget.(*textRenderer).layoutRow()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:621 +0x18d
  fyne.io/fyne/v2/widget.(*textRenderer).Layout()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:483 +0x98a
  fyne.io/fyne/v2/widget.(*textRenderer).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:613 +0x755
  fyne.io/fyne/v2/widget.(*BaseWidget).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/widget.go:138 +0x41
  fyne.io/fyne/v2/widget.(*RichText).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:91 +0x3a
  fyne.io/fyne/v2/widget.(*Label).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/label.go:100 +0x29c
  fyne.io/fyne/v2/widget.(*Label).createListener.func1()
      /Users/changkun/dev/changkun.de/fyne/widget/label.go:156 +0xc6
  fyne.io/fyne/v2/data/binding.(*listener).DataChanged()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:55 +0x3d
  fyne.io/fyne/v2/data/binding.DataListener.DataChanged-fm()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:40 +0x48
  fyne.io/fyne/v2/data/binding.queueItem.func1.1()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:19 +0x74

Goroutine 31 (running) created at:
  fyne.io/fyne/v2/data/binding.queueItem.func1()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:17 +0x6b
  sync.(*Once).doSlow()
      /Users/changkun/goes/go/src/sync/once.go:68 +0x127
  sync.(*Once).Do()
      /Users/changkun/goes/go/src/sync/once.go:59 +0x46
  fyne.io/fyne/v2/data/binding.queueItem()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:15 +0x37
  fyne.io/fyne/v2/data/binding.(*base).AddListener()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:69 +0x249
  fyne.io/fyne/v2/data/binding.(*boundExternalFloat).AddListener()
      :1 +0x4b
  fyne.io/fyne/v2/data/binding.FloatToStringWithFormat()
      /Users/changkun/dev/changkun.de/fyne/data/binding/convert.go:129 +0x204
  fyne.io/fyne/v2/cmd/fyne_demo/tutorials.bindingScreen()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/tutorials/bind.go:15 +0x1c5
  main.main.func1()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:52 +0x4fd
  main.makeNav.func5()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:177 +0x1b5
  fyne.io/fyne/v2/widget.(*Tree).Select()
      /Users/changkun/dev/changkun.de/fyne/widget/tree.go:242 +0x1f4
  main.makeNav()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:184 +0x326
  main.main()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:61 +0x5c7
==================
==================
WARNING: DATA RACE
Write at 0x00c000529768 by main goroutine:
  fyne.io/fyne/v2/widget.(*TextSegment).Update()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext_objects.go:363 +0x195
  fyne.io/fyne/v2/widget.(*textRenderer).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:579 +0x941
  fyne.io/fyne/v2/widget.(*BaseWidget).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/widget.go:138 +0x41
  fyne.io/fyne/v2/widget.(*RichText).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:91 +0x3a
  fyne.io/fyne/v2/widget.(*RichText).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:111 +0x104
  fyne.io/fyne/v2/widget.(*Label).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/label.go:110 +0x8d
  fyne.io/fyne/v2/layout.(*borderLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/borderlayout.go:56 +0x72b
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/widget.(*listItemRenderer).Layout()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:332 +0xc3
  fyne.io/fyne/v2/widget.(*BaseWidget).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/widget.go:61 +0x139
  fyne.io/fyne/v2/widget.(*listLayout).updateList()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:454 +0x64c
  fyne.io/fyne/v2/widget.(*listLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:369 +0x33
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/internal/widget.(*scrollContainerRenderer).Layout()
      /Users/changkun/dev/changkun.de/fyne/internal/widget/scroller.go:274 +0xd4
  fyne.io/fyne/v2/internal/widget.(*Base).Resize()
      /Users/changkun/dev/changkun.de/fyne/internal/widget/base.go:59 +0x145
  fyne.io/fyne/v2/internal/widget.(*Scroll).Resize()
      /Users/changkun/dev/changkun.de/fyne/internal/widget/scroller.go:451 +0x92
  fyne.io/fyne/v2/widget.(*listRenderer).Layout()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:230 +0x58
  fyne.io/fyne/v2/widget.(*BaseWidget).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/widget.go:61 +0x139
  fyne.io/fyne/v2/widget.(*List).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:113 +0x4a
  fyne.io/fyne/v2/layout.(*borderLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/borderlayout.go:56 +0x72b
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/layout.(*gridLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/gridlayout.go:102 +0x33e
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/layout.(*borderLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/borderlayout.go:56 +0x72b
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/layout.(*maxLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/maxlayout.go:22 +0xa1
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/layout.(*borderLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/borderlayout.go:56 +0x72b
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/container.(*splitContainerRenderer).Layout()
      /Users/changkun/dev/changkun.de/fyne/container/split.go:126 +0x3f2
  fyne.io/fyne/v2/widget.(*BaseWidget).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/widget.go:61 +0x139
  fyne.io/fyne/v2/container.(*Split).Resize()
      :1 +0x4f
  fyne.io/fyne/v2/internal/driver/glfw.(*glCanvas).Resize()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/canvas.go:123 +0x110
  fyne.io/fyne/v2/internal/driver/glfw.(*window).resized()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/window.go:546 +0x1d6
  fyne.io/fyne/v2/internal/driver/glfw.(*window).resized-fm()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/window.go:538 +0x57
  github.com/go-gl/glfw/v3.3/glfw.goWindowSizeCB()
      /Users/changkun/dev/changkun.de/fyne/vendor/github.com/go-gl/glfw/v3.3/glfw/window.go:213 +0x70
  _cgoexp_d63f5f7b2d6a_goWindowSizeCB()
      _cgo_gotypes.go:2638 +0x71
  runtime.cgocallbackg1()
      /Users/changkun/goes/go/src/runtime/cgocall.go:306 +0x2ab
  github.com/go-gl/glfw/v3.3/glfw.(*Window).SetSize.func1()
      /Users/changkun/dev/changkun.de/fyne/vendor/github.com/go-gl/glfw/v3.3/glfw/window.go:496 +0x84
  github.com/go-gl/glfw/v3.3/glfw.(*Window).SetSize()
      /Users/changkun/dev/changkun.de/fyne/vendor/github.com/go-gl/glfw/v3.3/glfw/window.go:496 +0x44
  fyne.io/fyne/v2/internal/driver/glfw.(*window).Resize.func1()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/window.go:198 +0x1ca
  fyne.io/fyne/v2/internal/driver/glfw.(*window).create.func3()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/window.go:1471 +0x6dd
  fyne.io/fyne/v2/internal/driver/glfw.(*gLDriver).runGL()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/loop.go:104 +0x226
  fyne.io/fyne/v2/internal/driver/glfw.(*gLDriver).Run()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/driver.go:83 +0x39
  fyne.io/fyne/v2/internal/driver/glfw.(*window).ShowAndRun()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/window.go:461 +0x55
  main.main()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:66 +0x654

Previous read at 0x00c000529768 by goroutine 31:
  runtime.racereadrange()
      :1 +0x1b
  fyne.io/fyne/v2/widget.(*textRenderer).layoutRow()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:621 +0x18d
  fyne.io/fyne/v2/widget.(*textRenderer).Layout()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:483 +0x98a
  fyne.io/fyne/v2/widget.(*textRenderer).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:613 +0x755
  fyne.io/fyne/v2/widget.(*BaseWidget).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/widget.go:138 +0x41
  fyne.io/fyne/v2/widget.(*RichText).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:91 +0x3a
  fyne.io/fyne/v2/widget.(*Label).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/label.go:100 +0x29c
  fyne.io/fyne/v2/widget.(*Label).createListener.func1()
      /Users/changkun/dev/changkun.de/fyne/widget/label.go:156 +0xc6
  fyne.io/fyne/v2/data/binding.(*listener).DataChanged()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:55 +0x3d
  fyne.io/fyne/v2/data/binding.DataListener.DataChanged-fm()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:40 +0x48
  fyne.io/fyne/v2/data/binding.queueItem.func1.1()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:19 +0x74

Goroutine 31 (running) created at:
  fyne.io/fyne/v2/data/binding.queueItem.func1()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:17 +0x6b
  sync.(*Once).doSlow()
      /Users/changkun/goes/go/src/sync/once.go:68 +0x127
  sync.(*Once).Do()
      /Users/changkun/goes/go/src/sync/once.go:59 +0x46
  fyne.io/fyne/v2/data/binding.queueItem()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:15 +0x37
  fyne.io/fyne/v2/data/binding.(*base).AddListener()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:69 +0x249
  fyne.io/fyne/v2/data/binding.(*boundExternalFloat).AddListener()
      :1 +0x4b
  fyne.io/fyne/v2/data/binding.FloatToStringWithFormat()
      /Users/changkun/dev/changkun.de/fyne/data/binding/convert.go:129 +0x204
  fyne.io/fyne/v2/cmd/fyne_demo/tutorials.bindingScreen()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/tutorials/bind.go:15 +0x1c5
  main.main.func1()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:52 +0x4fd
  main.makeNav.func5()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:177 +0x1b5
  fyne.io/fyne/v2/widget.(*Tree).Select()
      /Users/changkun/dev/changkun.de/fyne/widget/tree.go:242 +0x1f4
  main.makeNav()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:184 +0x326
  main.main()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:61 +0x5c7
==================
==================
WARNING: DATA RACE
Write at 0x00c000529760 by main goroutine:
  fyne.io/fyne/v2/widget.(*TextSegment).Update()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext_objects.go:364 +0x1d9
  fyne.io/fyne/v2/widget.(*textRenderer).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:579 +0x941
  fyne.io/fyne/v2/widget.(*BaseWidget).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/widget.go:138 +0x41
  fyne.io/fyne/v2/widget.(*RichText).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:91 +0x3a
  fyne.io/fyne/v2/widget.(*RichText).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:111 +0x104
  fyne.io/fyne/v2/widget.(*Label).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/label.go:110 +0x8d
  fyne.io/fyne/v2/layout.(*borderLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/borderlayout.go:56 +0x72b
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/widget.(*listItemRenderer).Layout()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:332 +0xc3
  fyne.io/fyne/v2/widget.(*BaseWidget).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/widget.go:61 +0x139
  fyne.io/fyne/v2/widget.(*listLayout).updateList()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:454 +0x64c
  fyne.io/fyne/v2/widget.(*listLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:369 +0x33
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/internal/widget.(*scrollContainerRenderer).Layout()
      /Users/changkun/dev/changkun.de/fyne/internal/widget/scroller.go:274 +0xd4
  fyne.io/fyne/v2/internal/widget.(*Base).Resize()
      /Users/changkun/dev/changkun.de/fyne/internal/widget/base.go:59 +0x145
  fyne.io/fyne/v2/internal/widget.(*Scroll).Resize()
      /Users/changkun/dev/changkun.de/fyne/internal/widget/scroller.go:451 +0x92
  fyne.io/fyne/v2/widget.(*listRenderer).Layout()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:230 +0x58
  fyne.io/fyne/v2/widget.(*BaseWidget).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/widget.go:61 +0x139
  fyne.io/fyne/v2/widget.(*List).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:113 +0x4a
  fyne.io/fyne/v2/layout.(*borderLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/borderlayout.go:56 +0x72b
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/layout.(*gridLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/gridlayout.go:102 +0x33e
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/layout.(*borderLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/borderlayout.go:56 +0x72b
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/layout.(*maxLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/maxlayout.go:22 +0xa1
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/layout.(*borderLayout).Layout()
      /Users/changkun/dev/changkun.de/fyne/layout/borderlayout.go:56 +0x72b
  fyne.io/fyne/v2.(*Container).layout()
      /Users/changkun/dev/changkun.de/fyne/container.go:168 +0x155
  fyne.io/fyne/v2.(*Container).Resize()
      /Users/changkun/dev/changkun.de/fyne/container.go:99 +0xaa
  fyne.io/fyne/v2/container.(*splitContainerRenderer).Layout()
      /Users/changkun/dev/changkun.de/fyne/container/split.go:126 +0x3f2
  fyne.io/fyne/v2/widget.(*BaseWidget).Resize()
      /Users/changkun/dev/changkun.de/fyne/widget/widget.go:61 +0x139
  fyne.io/fyne/v2/container.(*Split).Resize()
      :1 +0x4f
  fyne.io/fyne/v2/internal/driver/glfw.(*glCanvas).Resize()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/canvas.go:123 +0x110
  fyne.io/fyne/v2/internal/driver/glfw.(*window).resized()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/window.go:546 +0x1d6
  fyne.io/fyne/v2/internal/driver/glfw.(*window).resized-fm()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/window.go:538 +0x57
  github.com/go-gl/glfw/v3.3/glfw.goWindowSizeCB()
      /Users/changkun/dev/changkun.de/fyne/vendor/github.com/go-gl/glfw/v3.3/glfw/window.go:213 +0x70
  _cgoexp_d63f5f7b2d6a_goWindowSizeCB()
      _cgo_gotypes.go:2638 +0x71
  runtime.cgocallbackg1()
      /Users/changkun/goes/go/src/runtime/cgocall.go:306 +0x2ab
  github.com/go-gl/glfw/v3.3/glfw.(*Window).SetSize.func1()
      /Users/changkun/dev/changkun.de/fyne/vendor/github.com/go-gl/glfw/v3.3/glfw/window.go:496 +0x84
  github.com/go-gl/glfw/v3.3/glfw.(*Window).SetSize()
      /Users/changkun/dev/changkun.de/fyne/vendor/github.com/go-gl/glfw/v3.3/glfw/window.go:496 +0x44
  fyne.io/fyne/v2/internal/driver/glfw.(*window).Resize.func1()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/window.go:198 +0x1ca
  fyne.io/fyne/v2/internal/driver/glfw.(*window).create.func3()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/window.go:1471 +0x6dd
  fyne.io/fyne/v2/internal/driver/glfw.(*gLDriver).runGL()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/loop.go:104 +0x226
  fyne.io/fyne/v2/internal/driver/glfw.(*gLDriver).Run()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/driver.go:83 +0x39
  fyne.io/fyne/v2/internal/driver/glfw.(*window).ShowAndRun()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/window.go:461 +0x55
  main.main()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:66 +0x654

Previous read at 0x00c000529760 by goroutine 31:
  fyne.io/fyne/v2/canvas.(*Text).MinSize()
      /Users/changkun/dev/changkun.de/fyne/canvas/text.go:28 +0x56
  fyne.io/fyne/v2/widget.(*textRenderer).layoutRow()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:621 +0x18d
  fyne.io/fyne/v2/widget.(*textRenderer).Layout()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:483 +0x98a
  fyne.io/fyne/v2/widget.(*textRenderer).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:613 +0x755
  fyne.io/fyne/v2/widget.(*BaseWidget).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/widget.go:138 +0x41
  fyne.io/fyne/v2/widget.(*RichText).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:91 +0x3a
  fyne.io/fyne/v2/widget.(*Label).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/label.go:100 +0x29c
  fyne.io/fyne/v2/widget.(*Label).createListener.func1()
      /Users/changkun/dev/changkun.de/fyne/widget/label.go:156 +0xc6
  fyne.io/fyne/v2/data/binding.(*listener).DataChanged()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:55 +0x3d
  fyne.io/fyne/v2/data/binding.DataListener.DataChanged-fm()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:40 +0x48
  fyne.io/fyne/v2/data/binding.queueItem.func1.1()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:19 +0x74

Goroutine 31 (running) created at:
  fyne.io/fyne/v2/data/binding.queueItem.func1()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:17 +0x6b
  sync.(*Once).doSlow()
      /Users/changkun/goes/go/src/sync/once.go:68 +0x127
  sync.(*Once).Do()
      /Users/changkun/goes/go/src/sync/once.go:59 +0x46
  fyne.io/fyne/v2/data/binding.queueItem()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:15 +0x37
  fyne.io/fyne/v2/data/binding.(*base).AddListener()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:69 +0x249
  fyne.io/fyne/v2/data/binding.(*boundExternalFloat).AddListener()
      :1 +0x4b
  fyne.io/fyne/v2/data/binding.FloatToStringWithFormat()
      /Users/changkun/dev/changkun.de/fyne/data/binding/convert.go:129 +0x204
  fyne.io/fyne/v2/cmd/fyne_demo/tutorials.bindingScreen()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/tutorials/bind.go:15 +0x1c5
  main.main.func1()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:52 +0x4fd
  main.makeNav.func5()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:177 +0x1b5
  fyne.io/fyne/v2/widget.(*Tree).Select()
      /Users/changkun/dev/changkun.de/fyne/widget/tree.go:242 +0x1f4
  main.makeNav()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:184 +0x326
  main.main()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:61 +0x5c7
==================
==================
WARNING: DATA RACE
Write at 0x00c0004643c8 by goroutine 31:
  fyne.io/fyne/v2/widget.(*Label).syncSegments()
      /Users/changkun/dev/changkun.de/fyne/widget/label.go:162 +0x86
  fyne.io/fyne/v2/widget.(*Label).Refresh()
      /Users/changkun/dev/changkun.de/fyne/widget/label.go:99 +0x4c
  fyne.io/fyne/v2/widget.(*Label).createListener.func1()
      /Users/changkun/dev/changkun.de/fyne/widget/label.go:156 +0xc6
  fyne.io/fyne/v2/data/binding.(*listener).DataChanged()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:55 +0x3d
  fyne.io/fyne/v2/data/binding.DataListener.DataChanged-fm()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:40 +0x48
  fyne.io/fyne/v2/data/binding.queueItem.func1.1()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:19 +0x74

Previous read at 0x00c0004643c8 by goroutine 14:
  fyne.io/fyne/v2/widget.(*textRenderer).MinSize()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:499 +0xe7
  fyne.io/fyne/v2/widget.(*BaseWidget).MinSize()
      /Users/changkun/dev/changkun.de/fyne/widget/widget.go:90 +0x41
  fyne.io/fyne/v2/widget.(*RichText).MinSize()
      /Users/changkun/dev/changkun.de/fyne/widget/richtext.go:82 +0x44
  fyne.io/fyne/v2/widget.(*Label).MinSize()
      /Users/changkun/dev/changkun.de/fyne/widget/label.go:89 +0x84
  fyne.io/fyne/v2/layout.(*borderLayout).MinSize()
      /Users/changkun/dev/changkun.de/fyne/layout/borderlayout.go:74 +0x633
  fyne.io/fyne/v2.(*Container).MinSize()
      /Users/changkun/dev/changkun.de/fyne/container.go:71 +0xf3
  fyne.io/fyne/v2/widget.(*listItemRenderer).MinSize()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:326 +0x62
  fyne.io/fyne/v2/widget.(*BaseWidget).MinSize()
      /Users/changkun/dev/changkun.de/fyne/widget/widget.go:90 +0x41
  fyne.io/fyne/v2/widget.(*listItem).MinSize()
      /Users/changkun/dev/changkun.de/fyne/widget/list.go:286 +0x44
  fyne.io/fyne/v2/internal/driver/common.(*Canvas).EnsureMinSize.func1()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/common/canvas.go:79 +0x104
  fyne.io/fyne/v2/internal/driver/common.(*Canvas).walkTree.func2()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/common/canvas.go:433 +0x1c8
  fyne.io/fyne/v2/internal/driver.walkObjectTree()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/util.go:197 +0x3a1
  fyne.io/fyne/v2/internal/driver.walkObjectTree.func1()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/util.go:176 +0x454
  fyne.io/fyne/v2/internal/driver.walkObjectTree()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/util.go:190 +0x460
  fyne.io/fyne/v2/internal/driver.walkObjectTree.func1()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/util.go:176 +0x454
  fyne.io/fyne/v2/internal/driver.walkObjectTree()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/util.go:190 +0x460
  fyne.io/fyne/v2/internal/driver.walkObjectTree.func1()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/util.go:176 +0x454
  fyne.io/fyne/v2/internal/driver.walkObjectTree()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/util.go:190 +0x460
  fyne.io/fyne/v2/internal/driver.walkObjectTree.func1()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/util.go:176 +0x454
  fyne.io/fyne/v2/internal/driver.walkObjectTree()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/util.go:190 +0x460
  fyne.io/fyne/v2/internal/driver.walkObjectTree.func1()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/util.go:176 +0x454
  fyne.io/fyne/v2/internal/driver.walkObjectTree()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/util.go:190 +0x460
  fyne.io/fyne/v2/internal/driver.walkObjectTree.func1()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/util.go:176 +0x454
  fyne.io/fyne/v2/internal/driver.walkObjectTree()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/util.go:190 +0x460
  fyne.io/fyne/v2/internal/driver.walkObjectTree.func1()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/util.go:176 +0x454
  fyne.io/fyne/v2/internal/driver.walkObjectTree()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/util.go:190 +0x460
  fyne.io/fyne/v2/internal/driver.walkObjectTree.func1()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/util.go:176 +0x454
  fyne.io/fyne/v2/internal/driver.walkObjectTree()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/util.go:190 +0x460
  fyne.io/fyne/v2/internal/driver.walkObjectTree.func1()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/util.go:176 +0x454
  fyne.io/fyne/v2/internal/driver.walkObjectTree()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/util.go:190 +0x460
  fyne.io/fyne/v2/internal/driver.WalkVisibleObjectTree()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/util.go:134 +0x7d
  fyne.io/fyne/v2/internal/driver/common.(*Canvas).walkTree()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/common/canvas.go:439 +0x211
  fyne.io/fyne/v2/internal/driver/common.(*Canvas).WalkTrees()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/common/canvas.go:351 +0x67
  fyne.io/fyne/v2/internal/driver/common.(*Canvas).EnsureMinSize()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/common/canvas.go:102 +0x152
  fyne.io/fyne/v2/internal/driver/glfw.(*gLDriver).repaintWindow.func1()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/loop.go:166 +0x54
  fyne.io/fyne/v2/internal/driver/glfw.(*window).RunWithContext()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/window.go:1330 +0x6e
  fyne.io/fyne/v2/internal/driver/glfw.(*gLDriver).repaintWindow()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/loop.go:165 +0x6c
  fyne.io/fyne/v2/internal/driver/glfw.(*gLDriver).startDrawThread.func1()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/loop.go:228 +0x3e4

Goroutine 31 (running) created at:
  fyne.io/fyne/v2/data/binding.queueItem.func1()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:17 +0x6b
  sync.(*Once).doSlow()
      /Users/changkun/goes/go/src/sync/once.go:68 +0x127
  sync.(*Once).Do()
      /Users/changkun/goes/go/src/sync/once.go:59 +0x46
  fyne.io/fyne/v2/data/binding.queueItem()
      /Users/changkun/dev/changkun.de/fyne/data/binding/queue.go:15 +0x37
  fyne.io/fyne/v2/data/binding.(*base).AddListener()
      /Users/changkun/dev/changkun.de/fyne/data/binding/binding.go:69 +0x249
  fyne.io/fyne/v2/data/binding.(*boundExternalFloat).AddListener()
      :1 +0x4b
  fyne.io/fyne/v2/data/binding.FloatToStringWithFormat()
      /Users/changkun/dev/changkun.de/fyne/data/binding/convert.go:129 +0x204
  fyne.io/fyne/v2/cmd/fyne_demo/tutorials.bindingScreen()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/tutorials/bind.go:15 +0x1c5
  main.main.func1()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:52 +0x4fd
  main.makeNav.func5()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:177 +0x1b5
  fyne.io/fyne/v2/widget.(*Tree).Select()
      /Users/changkun/dev/changkun.de/fyne/widget/tree.go:242 +0x1f4
  main.makeNav()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:184 +0x326
  main.main()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:61 +0x5c7

Goroutine 14 (running) created at:
  fyne.io/fyne/v2/internal/driver/glfw.(*gLDriver).startDrawThread()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/loop.go:192 +0x158
  fyne.io/fyne/v2/internal/driver/glfw.(*gLDriver).initGLFW.func1()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/loop.go:83 +0x65
  sync.(*Once).doSlow()
      /Users/changkun/goes/go/src/sync/once.go:68 +0x127
  sync.(*Once).Do()
      /Users/changkun/goes/go/src/sync/once.go:59 +0x46
  fyne.io/fyne/v2/internal/driver/glfw.(*gLDriver).initGLFW()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/loop.go:75 +0x5d
  fyne.io/fyne/v2/internal/driver/glfw.(*gLDriver).createWindow.func1()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/window.go:1384 +0x6e
  fyne.io/fyne/v2/internal/driver/glfw.runOnMain()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/loop.go:55 +0x17a
  fyne.io/fyne/v2/internal/driver/glfw.(*gLDriver).createWindow()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/window.go:1383 +0x1ae
  fyne.io/fyne/v2/internal/driver/glfw.(*gLDriver).CreateWindow()
      /Users/changkun/dev/changkun.de/fyne/internal/driver/glfw/window.go:1375 +0x45
  fyne.io/fyne/v2/app.(*fyneApp).NewWindow()
      /Users/changkun/dev/changkun.de/fyne/app/app.go:57 +0x57
  main.main()
      /Users/changkun/dev/changkun.de/fyne/cmd/fyne_demo/main.go:27 +0xb5
==================
2021/09/28 10:47:46 Lifecycle: Entered Foreground
2021/09/28 10:47:47 Lifecycle: Exited Foreground

We should enable data race detection in the tests.

Device (please complete the following information):

simonlingoogle commented 1 year ago

I am new to fyne and was working on some UI project using fyne, where I came across a lot of data race problems. I don't think it's easy or even feasible to make all public methods/fields concurrent safe. What I need is simply a RunInUIThread(callback func ()) method that allows me to run all UI related code to the UI goroutine. I think it's a very common pattern in UI frameworks? Why doesn't fyne have that?

andydotxyz commented 1 year ago

I don't think it's easy or even feasible to make all public methods/fields concurrent safe.

Methods yes, fields maybe not - but we are working hard on this. The idea is that the toolkit does all the hard work so that developers don't have to!

I think it's a very common pattern in UI frameworks? Why doesn't fyne have that?

Basically because it's a horrible pattern that feels like a workaround - and certainly not very clear to people learning to code an app. In the cases where it is impossible to avoid a race without it we may have to consider something (discussions have been going on for a long time about how best to do so).

dweymouth commented 1 year ago

I was reading through the discussions on thread safety and I think that with the current API design it is impossible to make access to some public fields free of race conditions - though the chance that such race conditions can occur can be made "negligible". All public string fields for instance cannot even be copied in a race-free way since a string is two machine words long (a pointer and a size). However for the race to occur a user goroutine would need to assign to the field in between when the length and pointer values of the string were copied.

It may be worth thinking about deprecating public fields (at least string fields) on widgets/CanvasObjects and forcing all user access to go through getters/setters. Unfortunately it makes the API a little verbose and is a large breaking change (since the way extended widgets are initialized would need to change). Another option would be to add getters and setters for all the public fields but leave them exported, with a comment specifying that they should only be directly accessed on widget construction. Though we are definitely OK with deferring these considerations for quite awhile as the chance that this kind of data race would occur is very very small.

Edit: bluebugs' WidgetState proposal above might work, and the signature of the Update function could possibly be simplified just to Update(FooWidgetState state), the internal implementation would acquire locks as appropriate to set the private widget state in a race-free manner

andydotxyz commented 1 year ago

It may be worth thinking about deprecating public fields (at least string fields) on widgets/CanvasObjects and forcing all user access to go through getters/setters. Unfortunately it makes the API a little verbose and is a large breaking change (since the way extended widgets are initialized would need to change).

This is indeed one of the discussions about how we would "completely fix" races and for the reasons you state it's being considered for the v3 API.

Edit: bluebugs' WidgetState proposal above might work, and the signature of the Update function could possibly be simplified just to Update(FooWidgetState state), the internal implementation would acquire locks as appropriate to set the private widget state in a race-free manner

Agreed, this simplified version could be a good approach as well.

I am considering exposing some internal lock handling (UpdateFieldsAndRefresh and maybe GetFields) which would allow people to safely use fields if it really matters to their code. That could tide us over and then we could concentrate on eliminating the internal issues that are more pressing.

mpkondrashin commented 7 months ago

I am not a Professional programmer, but I see another solution to the race conditions. In case fyne internal race conditions are fixed, it should not be allowed to update content from other goroutines. And this is it. For dynamical content update user should be able to define function that would be triggered synchronously by fyne. If user has some goroutines generating actual content, they can share it through channels with this special function.