diff --git a/cmd/pad/main.go b/cmd/pad/main.go index 0186f7a..0711f90 100644 --- a/cmd/pad/main.go +++ b/cmd/pad/main.go @@ -3,6 +3,7 @@ package main import ( "log" "os" + "sync" "gioui.org/app" "gioui.org/op" @@ -31,41 +32,81 @@ func run(w *app.Window) error { shaper := text.NewShaper() renderer := ui.New(ui.Theme{FontSize: 14}, shaper) - // Channel for window configuration events (resize, orientation) + // Channels for communication between goroutines configChan := make(chan ui.ConfigEvent) + frameChan := make(chan []ui.Element) + inputChan := make(chan []ui.InputEvent) + + // Shared state protected by mutex + var mu sync.Mutex + var elems []ui.Element // Initial screen size screenWidth := unit.Dp(390) screenHeight := unit.Dp(844) // Compute initial elements - elems := ui.EditorLayout(screenWidth, screenHeight) + elems = ui.EditorLayout(screenWidth, screenHeight) + // Start logic goroutine + go logic(w, shaper, screenWidth, screenHeight, configChan, frameChan, inputChan) + + // Start frame receiver goroutine + go frameReceiver(w, &mu, &elems, frameChan) + + // Main event loop for { switch e := w.Event().(type) { case app.DestroyEvent: return e.Err case app.ConfigEvent: - // Send config event to logic goroutine (here, the main goroutine) + // Send config event to logic goroutine configChan <- ui.ConfigEvent{ Width: unit.Dp(e.Config.Size.X), Height: unit.Dp(e.Config.Size.Y), } case app.FrameEvent: - // Process any pending config events - select { - case cfg := <-configChan: - // Update screen size and recompute layout - screenWidth = cfg.Width - screenHeight = cfg.Height - elems = ui.EditorLayout(screenWidth, screenHeight) - default: - // No config event, use existing elements - } + // Acquire mutex, read frame, draw, release mutex + mu.Lock() + currentElems := elems + mu.Unlock() gtx := app.NewContext(&ops, e) - renderer.Draw(gtx, elems) + renderer.Draw(gtx, currentElems) e.Frame(&ops) } } } + +// logic runs in a separate goroutine and owns all application state. +func logic(w *app.Window, shaper *text.Shaper, screenWidth, screenHeight unit.Dp, + configChan <-chan ui.ConfigEvent, frameChan chan<- []ui.Element, inputChan <-chan []ui.InputEvent) { + + // Initial elements + elems := ui.EditorLayout(screenWidth, screenHeight) + + for { + select { + case cfg := <-configChan: + // Update screen size and recompute layout + screenWidth = cfg.Width + screenHeight = cfg.Height + elems = ui.EditorLayout(screenWidth, screenHeight) + frameChan <- elems + case <-inputChan: + // Process input (not implemented in mockup) + frameChan <- elems + } + } +} + +// frameReceiver runs in a separate goroutine and bridges frameChan to the main loop. +func frameReceiver(w *app.Window, mu *sync.Mutex, elems *[]ui.Element, frameChan <-chan []ui.Element) { + for { + frame := <-frameChan + mu.Lock() + *elems = frame + w.Invalidate() + mu.Unlock() + } +} diff --git a/pad b/pad index b784a88..25078ce 100755 Binary files a/pad and b/pad differ