app/internal/window: [macOS] avoid racy access to window width, height, scale

The macOS redraw callback is not invoked on the main thread, so its
access to window fields must be synchronized.

An alternative would be to schedule the asynchronous redraws on the main
thread, but I believe frame callbacks are performance-sensitive enough
to warrant the extra locking complexity.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2020-05-27 16:12:57 +02:00
parent 5c6ff659bf
commit 33146961f4
+18 -9
View File
@@ -48,9 +48,12 @@ func init() {
}
type window struct {
view C.CFTypeRef
w Callbacks
stage system.Stage
view C.CFTypeRef
w Callbacks
stage system.Stage
// mu protect the following fields
mu sync.Mutex
scale float32
width, height float32
}
@@ -204,8 +207,12 @@ func gio_onMouse(view C.CFTypeRef, cdir C.int, cbtns C.NSUInteger, x, y, dx, dy
//export gio_onDraw
func gio_onDraw(view C.CFTypeRef) {
w := mustView(view)
w.scale = float32(C.gio_getViewBackingScale(w.view))
w.width, w.height = float32(C.gio_viewWidth(w.view)), float32(C.gio_viewHeight(w.view))
scale := float32(C.gio_getViewBackingScale(w.view))
width, height := float32(C.gio_viewWidth(w.view)), float32(C.gio_viewHeight(w.view))
w.mu.Lock()
w.scale = scale
w.width, w.height = width, height
w.mu.Unlock()
w.draw(true)
}
@@ -216,13 +223,15 @@ func gio_onFocus(view C.CFTypeRef, focus C.BOOL) {
}
func (w *window) draw(sync bool) {
wf, hf := w.width, w.height
w.mu.Lock()
wf, hf, scale := w.width, w.height, w.scale
w.mu.Unlock()
if wf == 0 || hf == 0 {
return
}
width := int(wf*w.scale + .5)
height := int(hf*w.scale + .5)
cfg := configFor(w.scale)
width := int(wf*scale + .5)
height := int(hf*scale + .5)
cfg := configFor(scale)
cfg.now = time.Now()
w.setStage(system.StageRunning)
w.w.Event(FrameEvent{