chromiumembedded / cef

Chromium Embedded Framework (CEF). A simple framework for embedding Chromium-based browsers in other applications.
https://bitbucket.org/chromiumembedded/cef/
Other
3.38k stars 467 forks source link

Entering text in in text controls doesn't work under Ubuntu 24.04 when using external message pump #3782

Open vadz opened 2 months ago

vadz commented 2 months ago

Describe the bug It's impossible to enter any text into any text control on the page under Ubuntu 24.04 when using native windows and external message pump.

To Reproduce Steps to reproduce the behavior:

  1. Run cefclient --external-message-pump --use-alloy-style --use-native
  2. Optionally accept/reject the cookies dialog.
  3. Focus the "Search" text control on the opened page.
  4. Try entering any text into it — nothing happens.

Expected behavior Entering text should work.

Versions (please complete the following information):

Additional context Removing any of the 3 command line options above makes things work, although there are still some weird problems with focus not always getting to the text entry with just --use-native — but you can manage to enter the text when using it with some effort while with the options listed above I can't find any way to make it work at all.

AFAICS the focus never gets to the inner child and, at least according to xev, no key events are generated at all.

I had created a topic on the forums about the same problem, but I'm not sure if it was noticed there, so I'm creating this issue too, sorry if it's superfluous.

vadz commented 2 months ago

To give some more information: using this simple helper I see that normally cefclient gets XCB_KEY_{PRESS,RELEASE} events but that when running it with the 3 options above it doesn't get them any more and seems to be getting XCB_GE_GENERIC events instead. I have no idea if this is normal/expected, as the applications seem to be always getting XCB_GE_GENERIC for the mouse events, and things still work fine for them, even though we never get any XCB_BUTTON_{PRESS,RELEASE}, so it looks like Chrome has the code to deal with whatever extension is used for the mouse input (XInput?), but it doesn't work for the keyboard ones.

The most puzzling question still is what can possibly specifying the 3 options together change for mutter (?) to start sending different events for the application. If anybody has any hints about this, they would be very welcome!

vadz commented 2 months ago

After learning more about XCB, XInput2 etc than I ever wished to know, I've finally realized what is going on here (spoiler: it has nothing to do with any of those) and found a possible workaround: the problem is that CEF and GTK use different X connections, but they share the same focus at the server level, as they use the same window. CEF tries to set the focus using XInput2, which works fine, but either it results in WM_TAKE_FOCUS being sent to the client or maybe WM_TAKE_FOCUS gets sent independently of it (this is something I'm still not 100% sure about) and GTK handles it in _gdk_wm_protocols_filter() by calling XSetInputFocus() to switch focus to its own dummy "focus" window which it creates when create_focus_window() is called from setup_toplevel_window() and so takes it away from the browser window, which explains why text entry doesn't work.

In an ideal world it would be possible to somehow tell GTK that we have a foreign window which already takes focus and prevent it from doing this, but I don't see how to do it, so for now the only way to prevent this from happening that I found is to forcefully remove WM_TAKE_FOCUS from the list of supported WM protocols, i.e. do the equivalent of

        GdkWindow* window = gtk_widget_get_window(GetHandle());
        GdkDisplay *display = gdk_window_get_display (window);
        Atom protocols[3];
        protocols[0] = gdk_x11_get_xatom_by_name_for_display (display, "WM_DELETE_WINDOW");
        protocols[1] = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_PING");
        protocols[2] = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_SYNC_REQUEST");

        XSetWMProtocols (GDK_DISPLAY_XDISPLAY(display), GDK_WINDOW_XID(window), protocols, 3);

after the window is realized, which is exactly the same thing as GTK set_wm_protocols() does except it omits "take focus" support.

This is ugly and not supporting "take focus" might result in other problems (although I haven't see any yet), but this is the only way I could find to make the text entry to work at all.

I'd love to see a better fix in CEF itself, but I'm not sure what could it do. I could find — only after finding the problem myself, of course — that it's a known problem as there is a reference to it here: https://github.com/chromiumembedded/cef/blob/8c6f8dd404394cc36b6f1d1aff3dd593054d1b0c/tests/cefclient/browser/root_window_gtk.cc#L894-L896

but there is still no hint about how to solve it. Maybe CEF should also handle WM_TAKE_FOCUS and set the focus to the correct window? Except that I'm not sure that it would get it before GTK and I don't think we can rely on the relative order of messages on two different connections even it does work now.

magreenblatt commented 1 month ago

May be related to #3304 and #2026. You could try the PR linked from #2026 to see if that helps.