Commit 4b670ee
Fix Linux WebView first-paint and Wayland-session GTK init (#5)
Two related fixes for the same broken-on-Linux symptom — both contained
inside the package, both no-op on platforms that already work.
1. Layout participation for the inner NativeControlHost
NativeWebView is a Control (not a NativeControlHost) that adds its
inner NativeWebViewControlHost to VisualChildren after async adapter
creation. In Avalonia, adding to VisualChildren puts a control in the
visual tree but does NOT make it a layout participant — the parent
must explicitly Measure/Arrange visual children from
MeasureOverride/ArrangeOverride.
NativeWebView previously did neither, so the inner NativeControlHost's
Bounds stayed default(Rect) and the cross-platform NativeControlHost
flow's `if (bounds.Width == 0 && bounds.Height == 0) return false`
guard in TryUpdateNativeControlPosition silently skipped the call to
ShowInBounds. On Win32/macOS this is invisible because their holder
windows are visible-by-default; on X11 the holder stays 1×1 IsUnMapped,
the reparented WebKit GTK toplevel is IsUnviewable, and navigation
completes ok=True with zero pixels visible.
xwininfo on the broken case:
Avalonia toplevel (window size) IsViewable
Native-host slot 1×1 IsUnMapped <-- bug
Reparented GTK 200×200 IsUnviewable <-- bug
Fix:
- NativeWebView.MeasureOverride now drives Measure() on each
Layoutable in VisualChildren with the size it returns.
- A new NativeWebView.ArrangeOverride drives Arrange() on each
Layoutable in VisualChildren to the final size.
- InvalidateMeasure() is called immediately after
VisualChildren.Add((Control)controlHostImpl) so the layout pass
actually re-runs for the freshly-added child (VisualChildren.Add
does not itself invalidate layout).
The bug was reproduced in a standalone Avalonia Sandbox without
WebView — a plain Control adding a NativeControlHost to VisualChildren
without measure/arrange, which produces the same 1×1 IsUnMapped slot
xwininfo signature. The Measure/Arrange + InvalidateMeasure shape was
verified to fix the symptom there before being applied here. xwininfo
on the Avalonia.Controls.WebView.Samples.Desktop app with this fix:
slot is the parent's bounds, IsViewable, GTK toplevel matches.
WPF code paths (Avalonia.Xpf.Controls.WebView) are unchanged — every
addition is gated behind #if AVALONIA. Verified to compile clean for
net8.0-windows / net10.0-windows.
2. Override GDK_BACKEND=x11 around GTK init
Both GtkX11WebViewAdapter and GtkOffscreenAvaloniaWebViewAdapter use
Avalonia's GTK bridge (Avalonia.X11.NativeDialogs.Gtk.StartGtk) to
initialize GTK, and both rely on X11/GDK-X11-only entry points. Under a
Wayland session the desktop typically pre-sets GDK_BACKEND=wayland, so
the bridge's gtk_init picks the Wayland backend and fails with "Unable
to initialize GTK". Consumers previously had to set GDK_BACKEND=x11 in
the shell before launching.
Add a shared helper AvaloniaGtk.EnsureX11GdkBackendForGtkInit() that
overrides GDK_BACKEND for the duration of the bridge call, then
restores the previous value. Used via `using var _ = ...` at the top
of each adapter's CreateBuilder so the override is visible at the call
site and tightly scoped to GTK init.
Notes:
- Only overrides the unset case and the implicit "wayland" case (the
default under a Wayland session). If the user has explicitly set
some other backend like "broadway", that's a deliberate choice in
conflict with loading an X11-only adapter and we let gtk_init fail
with its own error rather than silently override.
- Concurrent CreateBuilder calls share a single override window via
refcounting: first call captures the previous env value and applies
the override, subsequent overlapping calls only refcount, and the
override is restored when the last scope is disposed. Without
refcounting, two concurrent calls could each snapshot the other's
already-overridden value and leave the env stuck at "x11".
- Environment.SetEnvironmentVariable is not sufficient on Linux: it
updates the .NET managed env cache but does not propagate to libc's
environ, which is what gtk_init reads via getenv. A direct libc
setenv call is required (verified empirically — setting only the
managed value left gtk_init still failing despite the C# side
reading "x11"). gdk_set_allowed_backends was tried first as the
GTK-blessed alternative but the call returned cleanly without
constraining Avalonia's GTK init helper in practice.
Verified on KDE Neon 24.04 (Plasma 5 / X11) and Arch Linux + KDE
Plasma 6 (Wayland session, XWayland for X11) using a minimal Avalonia
12 standalone repro app: stock 12.0.0 paints blank with the slot/GTK
state above, with this PR paints first-show without any consumer-side
GDK_BACKEND=x11 in the environment.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent 45d9086 commit 4b670ee
4 files changed
Lines changed: 143 additions & 5 deletions
File tree
- src
- Avalonia.Controls.WebView.Core/Gtk
- Avalonia.Controls.WebView
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
| 9 | + | |
9 | 10 | | |
10 | 11 | | |
11 | 12 | | |
12 | 13 | | |
13 | 14 | | |
14 | | - | |
| 15 | + | |
15 | 16 | | |
16 | 17 | | |
17 | 18 | | |
| |||
63 | 64 | | |
64 | 65 | | |
65 | 66 | | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
66 | 166 | | |
67 | 167 | | |
68 | 168 | | |
| |||
Lines changed: 1 addition & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
34 | 34 | | |
35 | 35 | | |
36 | 36 | | |
| 37 | + | |
37 | 38 | | |
38 | 39 | | |
39 | 40 | | |
| |||
Lines changed: 1 addition & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
28 | 28 | | |
29 | 29 | | |
30 | 30 | | |
| 31 | + | |
31 | 32 | | |
32 | 33 | | |
33 | 34 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
466 | 466 | | |
467 | 467 | | |
468 | 468 | | |
| 469 | + | |
| 470 | + | |
| 471 | + | |
| 472 | + | |
| 473 | + | |
| 474 | + | |
469 | 475 | | |
470 | 476 | | |
471 | 477 | | |
| |||
507 | 513 | | |
508 | 514 | | |
509 | 515 | | |
| 516 | + | |
| 517 | + | |
510 | 518 | | |
511 | 519 | | |
512 | | - | |
| 520 | + | |
| 521 | + | |
| 522 | + | |
| 523 | + | |
| 524 | + | |
| 525 | + | |
| 526 | + | |
| 527 | + | |
| 528 | + | |
| 529 | + | |
| 530 | + | |
| 531 | + | |
| 532 | + | |
| 533 | + | |
| 534 | + | |
| 535 | + | |
| 536 | + | |
| 537 | + | |
513 | 538 | | |
514 | 539 | | |
515 | | - | |
516 | | - | |
517 | | - | |
| 540 | + | |
518 | 541 | | |
519 | 542 | | |
| 543 | + | |
| 544 | + | |
| 545 | + | |
| 546 | + | |
| 547 | + | |
| 548 | + | |
| 549 | + | |
| 550 | + | |
| 551 | + | |
| 552 | + | |
| 553 | + | |
| 554 | + | |
| 555 | + | |
520 | 556 | | |
521 | 557 | | |
522 | 558 | | |
| |||
0 commit comments