Commit c7730cfe authored by Olivier Fourdan's avatar Olivier Fourdan Committed by Olivier Fourdan
Browse files

xwayland: Translate keyboard grabs on the root window

When an X11 client issues an active grab on the keyboard, Xwayland
forward this to the Wayland compositor using the Xwayland specific
protocol "xwayland-keyboard-grab" if it can find the corresponding
Xwayland window.

Some X11 clients (typically older games) however try to issue the
keyboard grab on the X11 root window, which has obviously no matching
Xwayland window. In such a case, the grab is simply ignored and the game
will not work as expected.

To workaround that issue, if an X11 client issues a keyboard grab on the
root window, Xwayland will search for a toplevel window belonging to the
same X11 client that it can use as the grab window instead.

This way, the grab can be forwarded to the Wayland compositor that can
either grant or deny the request based on the window and its internal

The heuristic picks the first realized toplevel window belonging to the
client so that the Wayland compositor will send it the keyboard events,
and the Xserver grab mechanism will then take care of routing the events
to the expected X11 window by itself.

v2: Make the test more clear (Dor Askayo <>)
Signed-off-by: default avatarOlivier Fourdan <>
Acked-by: Jonas Ådahl's avatarJonas Ådahl <>
parent 520e7a13
Pipeline #265007 passed with stages
in 5 minutes and 54 seconds
......@@ -1120,18 +1120,44 @@ set_grab(struct xwl_seat *xwl_seat, struct xwl_window *xwl_window)
static void
find_toplevel_callback(void *resource, XID id, void *user_data)
WindowPtr window = resource;
WindowPtr *toplevel = user_data;
/* Pick the first realized toplevel we find */
if (*toplevel == NullWindow && window->realized && xwl_window_is_toplevel(window))
*toplevel = window;
static WindowPtr
xwl_keyboard_search_window(ClientPtr client)
WindowPtr window = NullWindow;
FindClientResourcesByType(client, RT_WINDOW, find_toplevel_callback, &window);
return window;
static void
xwl_keyboard_activate_grab(DeviceIntPtr device, GrabPtr grab, TimeStamp time, Bool passive)
struct xwl_seat *xwl_seat = device->public.devicePrivate;
WindowPtr grab_window = grab->window;
/* We are not interested in passive grabs */
if (!passive) {
/* If the device is the MASTER_KEYBOARD, we don't have an xwl_seat */
if (xwl_seat == NULL)
xwl_seat = find_matching_seat(device);
if (xwl_seat)
set_grab(xwl_seat, xwl_window_from_window(grab->window));
if (xwl_seat) {
if (grab_window == xwl_seat->xwl_screen->screen->root)
grab_window = xwl_keyboard_search_window(GetCurrentClient());
if (grab_window)
set_grab(xwl_seat, xwl_window_from_window(grab_window));
ActivateKeyboardGrab(device, grab, time, passive);
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment