xwayland: add wlr_xwayland_surface_offer_focus()

In labwc, we have had trouble with XWayland windows using the Globally
Active input model (see wlr_xwayland_icccm_input_model()). Under
traditional X11, these windows do not expect to be given focus directly
by the window manager; rather, the WM sends them a WM_TAKE_FOCUS message
prompting the client to take focus voluntarily.

Currently, these clients are difficult to support with wlroots, because
wlr_xwayland_surface_activate() assumes the client window will always
accept the keyboard focus after being sent WM_TAKE_FOCUS. Some Globally
Active client windows (e.g. panels/toolbars) don't want to be focused.
It's useless at best to focus them, and might even make them misbehave.
Others do need keyboard focus to be functional -- and there doesn't seem
to be any reliable way to know this in advance.

Adding wlr_xwayland_surface_offer_focus() allows the compositor to send
WM_TAKE_FOCUS to a client window supporting it and then see whether the
client accepts or ignores the offer. If it accepts, the surface will emit
the focus_in signal notifying the compositor that it has received focus.

This is entirely opt-in. A compositor that doesn't want to use the new
function can continue to call wlr_xwayland_surface_activate() directly
just as before.
This commit is contained in:
John Lindgren 2024-02-14 06:05:04 -05:00 committed by Kirill Primak
parent eb5312022a
commit 5083efe18b
3 changed files with 47 additions and 4 deletions

View file

@ -278,6 +278,18 @@ void wlr_xwayland_set_seat(struct wlr_xwayland *xwayland,
struct wlr_xwayland_surface *wlr_xwayland_surface_try_from_wlr_surface(
struct wlr_surface *surface);
/**
* Offer focus by sending WM_TAKE_FOCUS to a client window supporting it.
* The client may accept or ignore the offer. If it accepts, the surface will
* emit the focus_in signal notifying the compositor that it has received focus.
*
* This is a more compatible method of giving focus to windows using the
* Globally Active input model (see wlr_xwayland_icccm_input_model()) than
* calling wlr_xwayland_surface_activate() unconditionally, since there is no
* reliable way to know in advance whether these windows want to be focused.
*/
void wlr_xwayland_surface_offer_focus(struct wlr_xwayland_surface *xsurface);
void wlr_xwayland_surface_ping(struct wlr_xwayland_surface *surface);
/** Metric to guess if an OR window should "receive" focus