Skip to content

linux: send focus changes to the GTK toplevel - #85

Open
sduguay-devolutions wants to merge 6 commits into
AvaloniaUI:mainfrom
Devolutions:fix/offscreen-webview-focus-events
Open

sduguay-devolutions wants to merge 6 commits into
AvaloniaUI:mainfrom
Devolutions:fix/offscreen-webview-focus-events

Conversation

@sduguay-devolutions

@sduguay-devolutions sduguay-devolutions commented Sep 23, 2026 •

Copy link
Copy Markdown

Issue

I've been facing those issues under Wayland with the GTK backend when ExperimentalOffscreen was turned on.

  • text inputs showed no caret
  • no focus rings around selected field

The cause is that an offscreen toplevel is never activated by a window manager. NativeWebView.OnGotFocus does call adapter.Focus(), but the base GTK implementation only does gtk_widget_grab_focus on the web view widget. Nothing tells the toplevel it became active. Therefore the page was considered to belong to an inactive window which is why I was facing those two issues.

The same thing happens with ExperimentalOffscreen disabled with X11. Its toplevel has the same problem for a different reason: it is reparented into the host window, which takes it away from the window manager. On top of that there is no XEmbed handshake, so nothing ever hands it the X input focus. Clicking the page raises no focus-in at all.

Fix

GtkWebViewAdapter now synthesizes the focus change GDK would normally deliver, sending GDK_FOCUS_CHANGE to the host window via gtk_widget_send_focus_change on focus and on resign. This lives in the base class so both adapters share it, each exposing its own toplevel through ToplevelHandle.

For X11 that is not enough on its own, since nothing calls Focus() to begin with. GtkX11WebViewAdapter now takes the button press as the focus gesture the window manager would otherwise have produced, and drives the same path from there. It returns false, so it still handles the click as usual. GTK then emits its own focus-in, which pulls the host's focus across too.

Before:
image

After:
Screencast_20260923_145232

I found that, once the text caret was showing up, it blinked inconsistently like it was skipping frames. The handler's own Invalidate() marks the custom visual dirty without getting the compositor to schedule a frame, so an update was drawn only once something else caused one. Continuous animation hides this, while sparse updates such as a caret blink held each phase for a few milliseconds instead of half a second. Which is why I added an InvalidateVisual() in NativeWebViewCompositorHost

sduguay-devolutions and others added 5 commits September 23, 2026 14:41
The toplevel focus change only ran on the offscreen adapter, and
GtkX11WebViewAdapter is a sibling of it rather than a subclass, so X11
never got it and still drew no caret. Move ToplevelHandle, the focus
change and EventSendState up into GtkWebViewAdapter so both adapters
share them, and drop the ExperimentalOffscreen guard: the condition was
never offscreen-ness but a toplevel that no window manager owns, which
both adapters have.

That alone is not enough on X11. Reparenting the toplevel into the host
window leaves it without a window manager and without an XEmbed
handshake, so nothing ever hands it the X input focus: clicking the page
raises no GTK focus-in at all and Focus() was never called. Take the
button press as the focus gesture instead and drive the same path from
there, returning false so WebKit still handles the click. GTK then
emits its own focus-in, which pulls the host's focus across too.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
An offscreen GdkWindow has no X window behind it. Activating one on the
x11 backend makes GTK and WebKit query the pointer against it, and
XIQueryPointer on a window that does not exist fails with a BadWindow
that takes the whole process down. Reproducible without any pointer
input: focusing the web view is enough.

Leave the toplevel alone in that combination and log once to say why
there is no caret. Wayland is unaffected, since offscreen windows there
never reach XInput, and so is the native x11 adapter, whose toplevel is
a real X window.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@sduguay-devolutions
sduguay-devolutions marked this pull request as ready for review September 23, 2026 21:52
@cristofermartins

Copy link
Copy Markdown

I'm using Avalonia.Controls.WebView Version 12.1.0 and i can confirm the issue.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants