Keep Linux WebViews on one persistent GTK UI thread

This commit is contained in:
Levi committed 2026-09-15 00:52:05 +08:00
1 parent a5eaa6b528
commit e2601ea9fa
3 files changed
+60 -2

No files matched your search

@@ -0,0 +1,47 @@
//go:build linux && cgo
package goprovider
/*
#cgo pkg-config: gtk+-3.0
#include <gtk/gtk.h>
static void pumpGTK(void) {
// Bound each batch so Go creation/removal requests cannot be starved.
for (int i = 0; i < 64 && g_main_context_pending(NULL); ++i)
g_main_context_iteration(NULL, FALSE);
}
*/
import "C"
import (
"runtime"
"sync"
"time"
)
var gtkThreadOnce sync.Once
var gtkThreadTasks = make(chan func())
func RunMainThreadLoop(run func() int) int { return run() }
func postMainThreadTask(task func()) bool {
gtkThreadOnce.Do(func() {
go func() {
runtime.LockOSThread()
// WebKit must always use its original UI thread, including after
// the last page closes. A page cannot stop this shared event loop.
ticker := time.NewTicker(10 * time.Millisecond)
defer ticker.Stop()
for {
select {
case task := <-gtkThreadTasks:
task()
case <-ticker.C:
}
C.pumpGTK()
}
}()
})
gtkThreadTasks <- task
return true
}
@@ -1,4 +1,4 @@
//go:build !darwin
//go:build !darwin && (!linux || !cgo)
package goprovider
+12 -1
View File
@@ -135,12 +135,18 @@ func (p *pageWrapper) start() error {
if err := w.Bind(p.callbackName, func(payload string) error {
return p.handleCallback(payload)
}); err != nil {
w.Destroy()
p.ready <- err
close(p.done)
return
}
applyWindowOptions(w, p.opts)
w.SetHtml(buildBootstrapHTML(p.callbackName, p.readyID))
if runtimepkg.GOOS == "linux" {
// All GTK pages share the process-wide event loop below.
return
}
w.Run()
w.Destroy()
close(p.done)
@@ -326,7 +332,12 @@ func (p *pageWrapper) Close() error {
// the quit message lands on the correct queue.
terminateDone := make(chan struct{})
w.Dispatch(func() {
w.Terminate()
if runtimepkg.GOOS == "linux" {
w.Destroy()
close(p.done)
} else {
w.Terminate()
}
close(terminateDone)
})
<-terminateDone