app: [macOS] ensure only one redraw request is in flight at any time

After 34f10d9cbb, the display link callback
will never block. However, if the main thread is blocked for another reason,
say a bug in the user program, callback requests will pile up as blocked
goroutines.

This change ensures that a redraw request is queued only if no other request
is pending.

References: https://todo.sr.ht/~eliasnaur/gio/370
Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2022-03-10 10:25:08 +01:00
parent cf787a1a8c
commit 083d407b47
+16 -3
View File
@@ -205,7 +205,10 @@ type window struct {
w *callbacks
stage system.Stage
displayLink *displayLink
cursor pointer.Cursor
// redraw is a single entry channel for making sure only one
// display link redraw request is in flight.
redraw chan struct{}
cursor pointer.Cursor
scale float32
config Config
@@ -667,6 +670,10 @@ func gio_firstRectForCharacterRange(view C.CFTypeRef, crng C.NSRange, actual C.N
}
func (w *window) draw() {
select {
case <-w.redraw:
default:
}
w.scale = float32(C.getViewBackingScale(w.view))
wf, hf := float32(C.viewWidth(w.view)), float32(C.viewHeight(w.view))
sz := image.Point{
@@ -792,10 +799,16 @@ func newOSWindow() (*window, error) {
}
scale := float32(C.getViewBackingScale(view))
w := &window{
view: view,
scale: scale,
view: view,
scale: scale,
redraw: make(chan struct{}, 1),
}
dl, err := NewDisplayLink(func() {
select {
case w.redraw <- struct{}{}:
default:
return
}
w.runOnMain(func() {
C.setNeedsDisplay(w.view)
})