Skip to content

Commit

Permalink
input: Propagate modifiers to clients with only pointer focus
Browse files Browse the repository at this point in the history
When focus_follows_mouse is off, it is possible to hover and/or scroll
windows without giving them keyboard focus.  However, attempts to use
Ctrl+scroll on such clients will not work correctly because the keyboard
modifiers are not available.  This patch propagates modifier state to
the client with pointer focus when it gains focus and when the state
changes.

https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/259
discusses permitting this behavior at the protocol level.
  • Loading branch information
danieldg committed Jan 23, 2024
1 parent e8c421e commit 0f879e3
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 1 deletion.
2 changes: 2 additions & 0 deletions include/sway/input/seat.h
Expand Up @@ -256,6 +256,8 @@ void drag_icons_update_position(struct sway_seat *seat);
enum wlr_edges find_resize_edge(struct sway_container *cont,
struct wlr_surface *surface, struct sway_cursor *cursor);

void seat_sync_modifiers(struct sway_seat *seat);

void seatop_begin_default(struct sway_seat *seat);

void seatop_begin_down(struct sway_seat *seat, struct sway_container *con,
Expand Down
4 changes: 3 additions & 1 deletion sway/input/keyboard.c
Expand Up @@ -659,10 +659,12 @@ static void handle_modifier_event(struct sway_keyboard *keyboard) {
wlr_input_method_keyboard_grab_v2_send_modifiers(kb_grab,
&keyboard->wlr->modifiers);
} else {
struct wlr_seat *wlr_seat = keyboard->seat_device->sway_seat->wlr_seat;
struct sway_seat *seat = keyboard->seat_device->sway_seat;
struct wlr_seat *wlr_seat = seat->wlr_seat;
wlr_seat_set_keyboard(wlr_seat, keyboard->wlr);
wlr_seat_keyboard_notify_modifiers(wlr_seat,
&keyboard->wlr->modifiers);
seat_sync_modifiers(seat);
}

uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard->wlr);
Expand Down
18 changes: 18 additions & 0 deletions sway/input/seat.c
Expand Up @@ -504,6 +504,24 @@ static void collect_focus_container_iter(struct sway_container *container,
collect_focus_iter(&container->node, data);
}

void seat_sync_modifiers(struct sway_seat *seat) {
struct wlr_seat *wlr_seat = seat->wlr_seat;
struct wlr_seat_client *kbd_focus = wlr_seat->keyboard_state.focused_client;
struct wlr_seat_client *ptr_focus = wlr_seat->pointer_state.focused_client;

struct wl_client *kbd_client = kbd_focus ? kbd_focus->client : NULL;
struct wl_client *ptr_client = ptr_focus ? ptr_focus->client : NULL;

// Don't send modifiers if the client already has keyboard focus
if (kbd_client == ptr_client)
return;

// Switch keyboard focus temporarily to send the modifiers to the pointer's client
wlr_seat->keyboard_state.focused_client = ptr_focus;
wlr_seat_keyboard_send_modifiers(wlr_seat, &wlr_seat->keyboard_state.keyboard->modifiers);
wlr_seat->keyboard_state.focused_client = kbd_focus;
}

struct sway_seat *seat_create(const char *seat_name) {
struct sway_seat *seat = calloc(1, sizeof(struct sway_seat));
if (!seat) {
Expand Down
13 changes: 13 additions & 0 deletions sway/input/seatop_default.c
Expand Up @@ -609,15 +609,28 @@ static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec) {
double sx, sy;
struct sway_node *node = node_at_coords(seat,
cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy);
struct wlr_seat_client *prev_focus_seat_client;
struct wlr_seat_client *curr_focus_seat_client;
struct wl_client *prev_focus_client;
struct wl_client *curr_focus_client;

if (config->focus_follows_mouse != FOLLOWS_NO) {
check_focus_follows_mouse(seat, e, node);
}

if (surface) {
if (seat_is_input_allowed(seat, surface)) {
prev_focus_seat_client = seat->wlr_seat->pointer_state.focused_client;
prev_focus_client = prev_focus_seat_client ? prev_focus_seat_client->client : NULL;

wlr_seat_pointer_notify_enter(seat->wlr_seat, surface, sx, sy);
wlr_seat_pointer_notify_motion(seat->wlr_seat, time_msec, sx, sy);

curr_focus_seat_client = seat->wlr_seat->pointer_state.focused_client;
curr_focus_client = curr_focus_seat_client ? curr_focus_seat_client->client : NULL;

if (prev_focus_client != curr_focus_client)
seat_sync_modifiers(seat);
}
} else {
cursor_update_image(cursor, node);
Expand Down

0 comments on commit 0f879e3

Please sign in to comment.