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.
274280func (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
388393func (c * callbacks ) ProcessFrame (frame * op.Ops , ack chan <- struct {}) {
@@ -550,8 +555,9 @@ func (c *callbacks) Invalidate() {
550555
551556func (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+
579604func (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.
690714func (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
697721func (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