feat(linux): CGO-free Linux backend via purego (GTK4 + WebKitGTK 6.0)#5715
feat(linux): CGO-free Linux backend via purego (GTK4 + WebKitGTK 6.0)#5715taliesin-ai wants to merge 2 commits into
Conversation
Revives Linux purego support (removed in #5661) rebuilt from scratch against the current GTK4/webkitgtk-6.0 cgo backend, selected with -tags purego and CGO_ENABLED=0. Libraries are dlopen'ed at runtime with per-distro soname fallbacks and actionable install-hint errors; version-dependent symbols are resolved optionally and guarded at runtime (e.g. gdk_monitor_get_scale with scale-factor fallback on GTK < 4.14). - linux_purego_lib.go: dlopen layer + full C function registry - linux_purego_callbacks.go: pure-Go port of linux_cgo.c (signal trampolines, GAction menus, GTK4 dialogs, DND, clipboard, X11 helpers, SA_ONSTACK signal fix incl. the #5527 SIGUSR1 exemption) - linux_purego.go: port of the linux_cgo.go shim surface - application_linux_purego.go: GApplication lifecycle twin - global_shortcut_linux_x11_purego.go: XGrabKey shortcuts via dlopen'd libX11 - internal/assetserver/webview/*_linux_purego.go: URI-scheme request plumbing preserving the #5631/#5668 main-thread confinement - internal/operatingsystem/webkit_linux_purego.go: doctor version info - dbus theme monitor, portal shortcuts, permissions and the (previously accidentally cgo-only) system tray are now shared via (cgo || purego) tags Known cgo bugs were fixed rather than ported and are catalogued in pkg/application/BUGS_FOUND.md; design notes in pkg/application/PUREGO_LINUX.md.
…l); document runtime validation g_strstrip/g_strsplit/g_strfreev were registered but unused (pattern splitting is done in Go) and g_strstrip is a macro over g_strchug/g_strchomp, so resolving it failed on every system. Caught by the loader's own missing-symbol report on first run — the aggregate error path worked as designed. Also records the runtime validation results (Ubuntu 26.04, GTK 4.22.2, WebKitGTK 2.52.3, Xvfb): window + menus + accelerators render, JS→Go bridge round-trips (setPos moved the window via XMoveWindow), child windows create via GMenu actions, main-window close exits cleanly; and documents the child-window-close BadDrawable crash on DRI-less Xvfb as present identically in the cgo backend (upstream WebKitGTK, not a port regression).
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Follow-up: the 8 cgo-backend defects catalogued in |
…rego port (#5718) The purego Linux port (#5715) translated linux_cgo.go/linux_cgo.c line by line and surfaced the following defects, catalogued in that PR's BUGS_FOUND.md. This applies the same fixes to the cgo backend: 1. appName() freed the GLib-owned string returned by g_get_application_name() (undefined behaviour; GLib returns the same pointer on the next call) and could pass NULL to GoString. Copy, never free, nil-check. 2. getWindows() dereferenced the GList head before the nil check, crashing on App.Hide()/Show()/isVisible() when no windows exist. Standard nil-checked loop. 3. clipboard_get_text_sync() parked its result in static globals while spinning a nested g_main_context_iteration loop; a second read dispatched by that loop clobbered the first (wrong text or infinite spin). Per-call stack-allocated state. 4. gtkSignalToMenuItem was written from menu-building goroutines and read on the GTK main thread with no synchronisation (fatal concurrent map access). RWMutex. 5. menuItemActions/menuItemActionCounter likewise unguarded between generateActionName (menu construction) and setChecked/setDisabled/accelerator reads from API goroutines. RWMutex + lookupActionName helper. 6. fileDialogCallback ran on the GTK main thread and sent each selected path into a channel with a fixed buffer of 100; selecting >100 files blocked the main loop permanently. Copy paths, deliver from a goroutine. 7. systemtray_linux.go carried a vestigial `import "C"` with zero C usages, silently making the pure-Go dbus tray cgo-only. 8. on_message_dialog_close returned TRUE from close-request after freeing MessageDialogData: GTK4 treats TRUE as "don't close", leaving a zombie dialog whose buttons pointed at freed memory. Return FALSE so the default handler destroys the window. Verified on Ubuntu 26.04 (GTK 4.22.2 / WebKitGTK 2.52.3): go build ./..., go test ./pkg/application, go vet, gtk3-tagged build, and a headless run of examples/window all pass. Co-authored-by: taliesin-ai <lea.anthony@gmail.com>
What
Revives CGO-free Linux support (removed as unmaintained in #5661), rebuilt from scratch against the current GTK4 + WebKitGTK 6.0 cgo backend. Build with:
The
puregotag selects the new backend; the default cgo backend (and the gtk3 variant) are unchanged and mutually exclusive via!puregotags. Cross-compiling Linux GUI apps from any host now works, since no C toolchain is involved.Design
linux_purego_lib.go— dlopen layer with per-distro soname fallbacks and one aggregate, actionable error when libraries/symbols are missing (package names per distro instead of a linker one-liner). Full typed function registry for GLib/GObject/Gio/GTK4/WebKitGTK-6.0/JSC/libsoup.gdk_monitor_get_scale(GTK 4.14+) falls back togdk_monitor_get_scale_factoron older GTK4, where the cgo build won't even start; GDK X11 symbols are optional so Wayland-only GTK builds work.linux_purego_callbacks.go— pure-Go port oflinux_cgo.c: a fixed set ofpurego.NewCallbacktrampolines (never per-window/item), GAction menus, GTK4 dialogs, DND, clipboard, X11 helpers viadlsym(RTLD_DEFAULT), and the [v3] Freezes with open inspector on linux. #5527 SA_ONSTACK signal fix (incl. the SIGUSR1/JSC exemption) via libcsigaction.internal/assetserver/webview/*_linux_purego.go— preserves the Linux: repeated SIGABRT/SIGSEGV in WebKitGTK/JSC main loop on v3.0.0-alpha2.103 #5631/fix(v3/linux): confine remaining WebKit request ops to the GTK main thread (#5631) #5668 main-thread confinement design exactly (atomic enabled-check + schedule, inline-after-shutdown).(cgo || purego)tags. X11 global shortcuts (XGrabKey) ported against dlopen'd libX11.v3/pkg/application/BUGS_FOUND.md(invalid free of a GLib-owned string, NULL GList deref, clipboard reentrancy, unsynchronised menu maps, >100-file dialog deadlock, message-dialog zombie/UAF, vestigialimport "C"that made the tray cgo-only). Design notes:v3/pkg/application/PUREGO_LINUX.md.Verified
GOOS=linux GOARCH=amd64|arm64 CGO_ENABLED=0 go build -tags purego ./...(alsopurego,production/purego,devtools), vet clean apart from the standard purego unsafeptr idiom notices.examples/windowbuilt CGO-free runs on a real X server — native window + GTK4 menu bar render, popover menus with registered accelerators work, a menu action creates a second window, thewails://scheme serves assets, and the JS→Go bridge round-trips (clicking the page'ssetPosmoved the native window via XMoveWindow, verified with xdotool). Main-window close exits 0.go test ./pkg/applicationpasses.BadDrawable— reproduced byte-identically with the cgo binary, so it's upstream WebKitGTK software-rendering teardown, not a port regression.🤖 Generated with Claude Code