random-apps/shared/window.go
2025-02-04 17:54:24 +01:00

65 lines
1.7 KiB
Go

package shared
import (
"context"
"sync"
"gioui.org/app"
"gioui.org/io/event"
"gioui.org/widget/material"
"github.com/rs/zerolog/log"
)
type GlobalState struct {
Window *app.Window
Theme *material.Theme
state WindowState
}
func Run(ctx context.Context, window *app.Window, initialState WindowState) error {
// Set up global data first
state := GlobalState{}
theme := material.NewTheme()
theme.Bg = BackgroundColor
theme.Fg = TextColor
state.Theme = theme
state.Window = window
state.state = initialState
// Then start showing the window and polling for events
// Though technically, I don't think window.Event will cause the window to display yet
// since what should it display? It doesn't have anything to display. So first display happens at event.Frame
eventChan := make(chan event.Event)
go func() {
for {
eventChan <- window.Event()
if ctx.Err() != nil {
return
}
}
}()
for {
select {
case <-ctx.Done():
log.Info().Msg("Context cancelled, preparing shutdown")
// Force one update for polling goroutine to exit
state.Window.Invalidate()
// Then keep awaiting more events. Since quit is just another event
// and the event channel is unbuffered, at least one more event has to be read for the poller to exit
case e := <-eventChan:
// Let the current view handle the event, then update accordingly
newState := state.state.Run(&state, e)
if newState.NextState != nil {
state.state = newState.NextState
}
if newState.ExitCode != nil {
log.Info().Msg("Received shutdown request from window")
wg := sync.WaitGroup{}
wg.Add(1)
go state.state.Exit(&state, &wg)
wg.Wait()
log.Info().Msg("Shutdown of window complete")
return nil
}
}
}
}