Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 037391a

Browse files
committedJun 27, 2024
app: ignore Invalidate for Windows not yet created
While here, don't overflow the Windows event queue. Signed-off-by: Elias Naur <[email protected]>
1 parent 42357a2 commit 037391a

File tree

5 files changed

+45
-59
lines changed

5 files changed

+45
-59
lines changed
 

‎app/os.go

+3-9
Original file line numberDiff line numberDiff line change
@@ -173,19 +173,13 @@ type context interface {
173173
Unlock()
174174
}
175175

176-
// basicDriver is the subset of [driver] that may be called even after
177-
// a window is destroyed.
178-
type basicDriver interface {
176+
// driver is the interface for the platform implementation
177+
// of a window.
178+
type driver interface {
179179
// Event blocks until an event is available and returns it.
180180
Event() event.Event
181181
// Invalidate requests a FrameEvent.
182182
Invalidate()
183-
}
184-
185-
// driver is the interface for the platform implementation
186-
// of a window.
187-
type driver interface {
188-
basicDriver
189183
// SetAnimating sets the animation flag. When the window is animating,
190184
// FrameEvents are delivered as fast as the display can handle them.
191185
SetAnimating(anim bool)

‎app/os_wayland.go

+1-11
Original file line numberDiff line numberDiff line change
@@ -217,10 +217,6 @@ type window struct {
217217
wakeups chan struct{}
218218

219219
closing bool
220-
221-
// invMu avoids the race between the destruction of disp and
222-
// Invalidate waking it up.
223-
invMu sync.Mutex
224220
}
225221

226222
type poller struct {
@@ -1369,10 +1365,8 @@ func (w *window) close(err error) {
13691365
w.ProcessEvent(WaylandViewEvent{})
13701366
w.ProcessEvent(DestroyEvent{Err: err})
13711367
w.destroy()
1372-
w.invMu.Lock()
13731368
w.disp.destroy()
13741369
w.disp = nil
1375-
w.invMu.Unlock()
13761370
}
13771371

13781372
func (w *window) dispatch() {
@@ -1416,11 +1410,7 @@ func (w *window) Invalidate() {
14161410
default:
14171411
return
14181412
}
1419-
w.invMu.Lock()
1420-
defer w.invMu.Unlock()
1421-
if w.disp != nil {
1422-
w.disp.wakeup()
1423-
}
1413+
w.disp.wakeup()
14241414
}
14251415

14261416
func (w *window) Run(f func()) {

‎app/os_windows.go

-12
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,6 @@ type window struct {
5454
borderSize image.Point
5555
config Config
5656
loop *eventLoop
57-
58-
// invMu avoids the race between destroying the window and Invalidate.
59-
invMu sync.Mutex
6057
}
6158

6259
const _WM_WAKEUP = windows.WM_USER + iota
@@ -304,10 +301,8 @@ func windowProc(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) uintptr
304301
windows.ReleaseDC(w.hdc)
305302
w.hdc = 0
306303
}
307-
w.invMu.Lock()
308304
// The system destroys the HWND for us.
309305
w.hwnd = 0
310-
w.invMu.Unlock()
311306
windows.PostQuitMessage(0)
312307
case windows.WM_NCCALCSIZE:
313308
if w.config.Decorated {
@@ -620,13 +615,6 @@ func (w *window) Frame(frame *op.Ops) {
620615
}
621616

622617
func (w *window) wakeup() {
623-
w.invMu.Lock()
624-
defer w.invMu.Unlock()
625-
if w.hwnd == 0 {
626-
w.loop.Wakeup()
627-
w.loop.FlushEvents()
628-
return
629-
}
630618
if err := windows.PostMessage(w.hwnd, _WM_WAKEUP, 0, 0); err != nil {
631619
panic(err)
632620
}

‎app/os_x11.go

-10
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,6 @@ type x11Window struct {
113113
wakeups chan struct{}
114114
handler x11EventHandler
115115
buf [100]byte
116-
117-
// invMy avoids the race between destroy and Invalidate.
118-
invMu sync.Mutex
119116
}
120117

121118
var (
@@ -416,11 +413,6 @@ func (w *x11Window) Invalidate() {
416413
case w.wakeups <- struct{}{}:
417414
default:
418415
}
419-
w.invMu.Lock()
420-
defer w.invMu.Unlock()
421-
if w.x == nil {
422-
return
423-
}
424416
if _, err := syscall.Write(w.notify.write, x11OneByte); err != nil && err != syscall.EAGAIN {
425417
panic(fmt.Errorf("failed to write to pipe: %v", err))
426418
}
@@ -509,8 +501,6 @@ func (w *x11Window) dispatch() {
509501
}
510502

511503
func (w *x11Window) destroy() {
512-
w.invMu.Lock()
513-
defer w.invMu.Unlock()
514504
if w.notify.write != 0 {
515505
syscall.Close(w.notify.write)
516506
w.notify.write = 0

‎app/window.go

+41-17
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"image/color"
1010
"reflect"
1111
"runtime"
12+
"sync"
1213
"time"
1314
"unicode/utf8"
1415

@@ -89,8 +90,13 @@ type Window struct {
8990
}
9091
imeState editorState
9192
driver driver
92-
// basic is the driver interface that is needed even after the window is gone.
93-
basic basicDriver
93+
94+
// once initializes pendingInvalidates.
95+
once sync.Once
96+
// pendingInvalidates ensures only one Invalidate may
97+
// be pending at any time.
98+
pendingInvalidates chan struct{}
99+
94100
// coalesced tracks the most recent events waiting to be delivered
95101
// to the client.
96102
coalesced eventSummary
@@ -272,8 +278,10 @@ func (w *Window) updateState() {
272278
//
273279
// Invalidate is safe for concurrent use.
274280
func (w *Window) Invalidate() {
275-
if w.basic != nil {
276-
w.basic.Invalidate()
281+
select {
282+
case <-w.invalidateChan():
283+
w.driver.Invalidate()
284+
default:
277285
}
278286
}
279287

@@ -283,7 +291,7 @@ func (w *Window) Option(opts ...Option) {
283291
if len(opts) == 0 {
284292
return
285293
}
286-
if w.basic == nil {
294+
if w.driver == nil {
287295
w.initialOpts = append(w.initialOpts, opts...)
288296
return
289297
}
@@ -378,11 +386,8 @@ func (w *Window) setNextFrame(at time.Time) {
378386
}
379387
}
380388

381-
func (c *callbacks) SetDriver(d basicDriver) {
382-
c.w.basic = d
383-
if d, ok := d.(driver); ok {
384-
c.w.driver = d
385-
}
389+
func (c *callbacks) SetDriver(d driver) {
390+
c.w.driver = d
386391
}
387392

388393
func (c *callbacks) ProcessFrame(frame *op.Ops, ack chan<- struct{}) {
@@ -550,8 +555,9 @@ func (c *callbacks) Invalidate() {
550555

551556
func (c *callbacks) nextEvent() (event.Event, bool) {
552557
s := &c.w.coalesced
553-
// Every event counts as a wakeup.
554-
defer func() { s.wakeup = false }()
558+
wakeup := s.wakeup
559+
s.wakeup = false
560+
c.w.invalidateOk()
555561
switch {
556562
case s.view != nil:
557563
e := *s.view
@@ -561,6 +567,11 @@ func (c *callbacks) nextEvent() (event.Event, bool) {
561567
e := *s.destroy
562568
// Clear pending events after DestroyEvent is delivered.
563569
*s = eventSummary{}
570+
// Don't allow invalidates from now on.
571+
select {
572+
case <-c.w.invalidateChan():
573+
default:
574+
}
564575
return e, true
565576
case s.cfg != nil:
566577
e := *s.cfg
@@ -570,12 +581,26 @@ func (c *callbacks) nextEvent() (event.Event, bool) {
570581
e := *s.frame
571582
s.frame = nil
572583
return e.FrameEvent, true
573-
case s.wakeup:
584+
case wakeup:
574585
return wakeupEvent{}, true
575586
}
576587
return nil, false
577588
}
578589

590+
func (w *Window) invalidateChan() chan struct{} {
591+
w.once.Do(func() {
592+
w.pendingInvalidates = make(chan struct{}, 1)
593+
})
594+
return w.pendingInvalidates
595+
}
596+
597+
func (w *Window) invalidateOk() {
598+
select {
599+
case w.invalidateChan() <- struct{}{}:
600+
default:
601+
}
602+
}
603+
579604
func (w *Window) processEvent(e event.Event) bool {
580605
switch e2 := e.(type) {
581606
case wakeupEvent:
@@ -617,7 +642,6 @@ func (w *Window) processEvent(e event.Event) bool {
617642
case DestroyEvent:
618643
w.destroyGPU()
619644
w.driver = nil
620-
w.basic = nil
621645
if q := w.timer.quit; q != nil {
622646
q <- struct{}{}
623647
<-q
@@ -688,10 +712,10 @@ func (w *Window) processEvent(e event.Event) bool {
688712
// [FrameEvent], or until [Invalidate] is called. The window is created
689713
// and shown the first time Event is called.
690714
func (w *Window) Event() event.Event {
691-
if w.basic == nil {
715+
if w.driver == nil {
692716
w.init()
693717
}
694-
return w.basic.Event()
718+
return w.driver.Event()
695719
}
696720

697721
func (w *Window) init() {
@@ -832,7 +856,7 @@ func (w *Window) Perform(actions system.Action) {
832856
if acts == 0 {
833857
return
834858
}
835-
if w.basic == nil {
859+
if w.driver == nil {
836860
w.initialActions = append(w.initialActions, acts)
837861
return
838862
}

0 commit comments

Comments
 (0)
Please sign in to comment.