keyboard: broadcast modifiers

...to all clients rather than just the one with keyboard focus on keyboard
enter/create, modifer press/release and wlr_seat_set_keyboard().

This enables:

- Clients such as panels to display the current keyboard layout without
  introducing new wayland protocols or other IPC.

- Unfocused xdg-shell clients to understand button press with keyboard
  modifiers for example Ctrl+click.

The keymap is forwarded to all clients in wlr_seat_set_keyboard(). When a
keymap contains multiple layouts, the selection is made via modifiers,
which previously were only sent to the client with keyboard focus.

Tested with: https://github.com/johanmalm/keyboard-layout

Ref: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4496

Fixes: #2271
This commit is contained in:
Johan Malm 2024-10-27 11:54:06 +00:00 committed by Johan Malm
parent ad2d24fb42
commit 3b00aabd93

View file

@ -80,6 +80,43 @@ end_cycling(struct server *server)
should_cancel_cycling_on_next_key_release = false;
}
static struct wlr_seat_client *
seat_client_from_keyboard_resource(struct wl_resource *resource)
{
return wl_resource_get_user_data(resource);
}
static void
broadcast_modifiers_to_unfocused_clients(struct wlr_seat *seat,
const struct wlr_keyboard_modifiers *modifiers)
{
struct wlr_seat_client *client;
wl_list_for_each(client, &seat->clients, link) {
if (client == seat->keyboard_state.focused_client) {
/*
* We've already notified the focused client by calling
* wlr_seat_keyboard_notify_modifiers()
*/
continue;
}
uint32_t serial = wlr_seat_client_next_serial(client);
struct wl_resource *resource;
wl_resource_for_each(resource, &client->keyboards) {
if (!seat_client_from_keyboard_resource(resource)) {
continue;
}
if (!modifiers) {
wl_keyboard_send_modifiers(resource, serial, 0,
0, 0, 0);
} else {
wl_keyboard_send_modifiers(resource, serial,
modifiers->depressed, modifiers->latched,
modifiers->locked, modifiers->group);
}
}
}
}
static void
keyboard_modifiers_notify(struct wl_listener *listener, void *data)
{
@ -112,8 +149,31 @@ keyboard_modifiers_notify(struct wl_listener *listener, void *data)
}
if (!input_method_keyboard_grab_forward_modifiers(keyboard)) {
/* Send modifiers to focused client */
wlr_seat_keyboard_notify_modifiers(seat->seat,
&wlr_keyboard->modifiers);
/*
* Also broadcast them to non-keyboard-focused clients.
*
* The Wayland protocol does not specify that modifiers are
* broadcast, so this is not something clients can rely on in
* other compositors.
*
* Sway used to broadcast modifiers but stopped doing so to
* avoid waking up all clients when the modifiers change.
*
* By testing with foot and Ctrl+scroll to change font size, it
* appears that Mutter does not pass modifiers to unfocused
* clients, whereas KWin and Weston pass modifiers to clients
* with pointer-focus.
*
* This could be made configurable if there are unintended
* consequences. If so, modifiers ought to still be passed to
* clients with pointer-focus (see issue #2271)
*/
broadcast_modifiers_to_unfocused_clients(seat->seat,
&wlr_keyboard->modifiers);
}
}