Implement full architecture scaffolding with logic and frame receiver goroutines
- Logic goroutine: receives config events, recomputes layout, sends frames - Frame receiver goroutine: reads frames, stores under mutex, calls w.Invalidate() - Main event loop: renders frames under mutex, sends config events to logic - Proper channel topology: configChan, frameChan, inputChan - Mutex around elems shared between goroutines - Window resize triggers layout recomputation in logic goroutine Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
parent
869f0b13ac
commit
556f72643f
|
|
@ -3,6 +3,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"gioui.org/app"
|
"gioui.org/app"
|
||||||
"gioui.org/op"
|
"gioui.org/op"
|
||||||
|
|
@ -31,41 +32,81 @@ func run(w *app.Window) error {
|
||||||
shaper := text.NewShaper()
|
shaper := text.NewShaper()
|
||||||
renderer := ui.New(ui.Theme{FontSize: 14}, shaper)
|
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)
|
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
|
// Initial screen size
|
||||||
screenWidth := unit.Dp(390)
|
screenWidth := unit.Dp(390)
|
||||||
screenHeight := unit.Dp(844)
|
screenHeight := unit.Dp(844)
|
||||||
|
|
||||||
// Compute initial elements
|
// 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 {
|
for {
|
||||||
switch e := w.Event().(type) {
|
switch e := w.Event().(type) {
|
||||||
case app.DestroyEvent:
|
case app.DestroyEvent:
|
||||||
return e.Err
|
return e.Err
|
||||||
case app.ConfigEvent:
|
case app.ConfigEvent:
|
||||||
// Send config event to logic goroutine (here, the main goroutine)
|
// Send config event to logic goroutine
|
||||||
configChan <- ui.ConfigEvent{
|
configChan <- ui.ConfigEvent{
|
||||||
Width: unit.Dp(e.Config.Size.X),
|
Width: unit.Dp(e.Config.Size.X),
|
||||||
Height: unit.Dp(e.Config.Size.Y),
|
Height: unit.Dp(e.Config.Size.Y),
|
||||||
}
|
}
|
||||||
case app.FrameEvent:
|
case app.FrameEvent:
|
||||||
// Process any pending config events
|
// Acquire mutex, read frame, draw, release mutex
|
||||||
|
mu.Lock()
|
||||||
|
currentElems := elems
|
||||||
|
mu.Unlock()
|
||||||
|
|
||||||
|
gtx := app.NewContext(&ops, e)
|
||||||
|
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 {
|
select {
|
||||||
case cfg := <-configChan:
|
case cfg := <-configChan:
|
||||||
// Update screen size and recompute layout
|
// Update screen size and recompute layout
|
||||||
screenWidth = cfg.Width
|
screenWidth = cfg.Width
|
||||||
screenHeight = cfg.Height
|
screenHeight = cfg.Height
|
||||||
elems = ui.EditorLayout(screenWidth, screenHeight)
|
elems = ui.EditorLayout(screenWidth, screenHeight)
|
||||||
default:
|
frameChan <- elems
|
||||||
// No config event, use existing elements
|
case <-inputChan:
|
||||||
}
|
// Process input (not implemented in mockup)
|
||||||
|
frameChan <- elems
|
||||||
gtx := app.NewContext(&ops, e)
|
|
||||||
renderer.Draw(gtx, elems)
|
|
||||||
e.Frame(&ops)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user