Fix Fyne threading errors in queue callbacks and setContent

The queue callback was triggering showMainMenu() from a goroutine (the
job processor) without marshaling to the main thread. This caused the
threading error "should have been called in fyne.Do[AndWait]".

Changes:
1. Queue callback now wraps all UI updates in app.Driver().DoFromGoroutine()
   to safely marshal calls from the job processor goroutine to the main thread
2. setContent() now always uses DoFromGoroutine() to ensure thread safety
   regardless of caller context. This prevents errors when called from
   callbacks or other goroutines.
3. Added fallback for early initialization when app driver isn't ready yet

This ensures all UI updates happen on the main Fyne event loop thread.

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Stu Leak 2025-11-27 00:20:39 -05:00
parent 27f80cb056
commit fb472bc677

43
main.go
View File

@ -308,11 +308,26 @@ func (s *appState) applyInverseDefaults(src *videoSource) {
func (s *appState) setContent(body fyne.CanvasObject) {
bg := canvas.NewRectangle(backgroundColor)
// Don't set a minimum size - let content determine layout naturally
if body == nil {
s.window.SetContent(bg)
return
// Always use DoFromGoroutine to ensure we're on the main thread
// This is safe even when already on the main thread
app := fyne.CurrentApp()
if app != nil && app.Driver() != nil {
app.Driver().DoFromGoroutine(func() {
if body == nil {
s.window.SetContent(bg)
} else {
s.window.SetContent(container.NewMax(bg, body))
}
}, false)
} else {
// Fallback if app not ready yet (during initialization)
if body == nil {
s.window.SetContent(bg)
} else {
s.window.SetContent(container.NewMax(bg, body))
}
}
s.window.SetContent(container.NewMax(bg, body))
}
// showErrorWithCopy displays an error dialog with a "Copy Error" button
@ -1086,13 +1101,21 @@ func runGUI() {
go func() {
time.Sleep(100 * time.Millisecond)
state.jobQueue.SetChangeCallback(func() {
// Update stats bar
state.updateStatsBar()
// Refresh UI when queue changes
if state.active == "" {
state.showMainMenu()
// Queue callbacks come from goroutines, so wrap UI calls
app := fyne.CurrentApp()
if app == nil || app.Driver() == nil {
return
}
app.Driver().DoFromGoroutine(func() {
// Update stats bar
state.updateStatsBar()
// Refresh UI when queue changes
if state.active == "" {
state.showMainMenu()
}
}, false)
})
}()