wlroots-hyprland/types/seat/wlr_seat_keyboard.c

479 lines
15 KiB
C
Raw Normal View History

2018-05-02 11:03:26 +02:00
#include <assert.h>
2023-05-10 20:43:25 +02:00
#include <fcntl.h>
2018-05-02 11:03:26 +02:00
#include <stdlib.h>
#include <time.h>
2023-05-10 20:43:25 +02:00
#include <unistd.h>
#include <wayland-server-core.h>
2022-01-13 09:55:09 +01:00
#include <wlr/types/wlr_compositor.h>
2018-05-02 11:03:26 +02:00
#include <wlr/types/wlr_data_device.h>
#include <wlr/util/log.h>
#include "types/wlr_data_device.h"
2018-05-02 11:03:26 +02:00
#include "types/wlr_seat.h"
static void default_keyboard_enter(struct wlr_seat_keyboard_grab *grab,
struct wlr_surface *surface, const uint32_t keycodes[], size_t num_keycodes,
const struct wlr_keyboard_modifiers *modifiers) {
2018-05-02 11:03:26 +02:00
wlr_seat_keyboard_enter(grab->seat, surface, keycodes, num_keycodes, modifiers);
}
static void default_keyboard_clear_focus(struct wlr_seat_keyboard_grab *grab) {
wlr_seat_keyboard_clear_focus(grab->seat);
}
2018-05-02 11:03:26 +02:00
static void default_keyboard_key(struct wlr_seat_keyboard_grab *grab,
uint32_t time, uint32_t key, uint32_t state) {
wlr_seat_keyboard_send_key(grab->seat, time, key, state);
}
static void default_keyboard_modifiers(struct wlr_seat_keyboard_grab *grab,
const struct wlr_keyboard_modifiers *modifiers) {
2018-05-02 11:03:26 +02:00
wlr_seat_keyboard_send_modifiers(grab->seat, modifiers);
}
static void default_keyboard_cancel(struct wlr_seat_keyboard_grab *grab) {
// cannot be cancelled
}
const struct wlr_keyboard_grab_interface default_keyboard_grab_impl = {
.enter = default_keyboard_enter,
.clear_focus = default_keyboard_clear_focus,
2018-05-02 11:03:26 +02:00
.key = default_keyboard_key,
.modifiers = default_keyboard_modifiers,
.cancel = default_keyboard_cancel,
};
static void keyboard_release(struct wl_client *client,
struct wl_resource *resource) {
wl_resource_destroy(resource);
}
static const struct wl_keyboard_interface keyboard_impl = {
.release = keyboard_release,
};
2018-05-03 23:03:44 +02:00
static struct wlr_seat_client *seat_client_from_keyboard_resource(
struct wl_resource *resource) {
assert(wl_resource_instance_of(resource, &wl_keyboard_interface,
&keyboard_impl));
return wl_resource_get_user_data(resource);
}
2018-05-02 11:03:26 +02:00
static void keyboard_handle_resource_destroy(struct wl_resource *resource) {
2018-05-03 23:03:44 +02:00
seat_client_destroy_keyboard(resource);
2018-05-02 11:03:26 +02:00
}
void wlr_seat_keyboard_send_key(struct wlr_seat *wlr_seat, uint32_t time,
uint32_t key, uint32_t state) {
struct wlr_seat_client *client = wlr_seat->keyboard_state.focused_client;
if (!client) {
return;
}
uint32_t serial = wlr_seat_client_next_serial(client);
2018-05-02 11:03:26 +02:00
struct wl_resource *resource;
wl_resource_for_each(resource, &client->keyboards) {
2018-05-03 23:03:44 +02:00
if (seat_client_from_keyboard_resource(resource) == NULL) {
continue;
}
2018-05-02 11:03:26 +02:00
wl_keyboard_send_key(resource, serial, time, key, state);
}
}
static void seat_client_send_keymap(struct wlr_seat_client *client,
struct wlr_keyboard *keyboard);
static void handle_keyboard_keymap(struct wl_listener *listener, void *data) {
struct wlr_seat_keyboard_state *state =
wl_container_of(listener, state, keyboard_keymap);
struct wlr_seat_client *client;
struct wlr_keyboard *keyboard = data;
if (keyboard == state->keyboard) {
wl_list_for_each(client, &state->seat->clients, link) {
seat_client_send_keymap(client, state->keyboard);
}
}
}
static void seat_client_send_repeat_info(struct wlr_seat_client *client,
struct wlr_keyboard *keyboard);
static void handle_keyboard_repeat_info(struct wl_listener *listener,
void *data) {
struct wlr_seat_keyboard_state *state =
wl_container_of(listener, state, keyboard_repeat_info);
struct wlr_seat_client *client;
wl_list_for_each(client, &state->seat->clients, link) {
seat_client_send_repeat_info(client, state->keyboard);
}
}
static void handle_keyboard_destroy(struct wl_listener *listener, void *data) {
struct wlr_seat_keyboard_state *state =
wl_container_of(listener, state, keyboard_destroy);
wlr_seat_set_keyboard(state->seat, NULL);
2018-05-02 11:03:26 +02:00
}
void wlr_seat_set_keyboard(struct wlr_seat *seat,
struct wlr_keyboard *keyboard) {
2018-05-02 11:03:26 +02:00
// TODO call this on device key event before the event reaches the
// compositor and set a pending keyboard and then send the new keyboard
// state on the next keyboard notify event.
if (seat->keyboard_state.keyboard == keyboard) {
return;
}
if (seat->keyboard_state.keyboard) {
wl_list_remove(&seat->keyboard_state.keyboard_destroy.link);
wl_list_remove(&seat->keyboard_state.keyboard_keymap.link);
wl_list_remove(&seat->keyboard_state.keyboard_repeat_info.link);
seat->keyboard_state.keyboard = NULL;
}
if (keyboard) {
seat->keyboard_state.keyboard = keyboard;
wl_signal_add(&keyboard->base.events.destroy,
2018-05-02 11:03:26 +02:00
&seat->keyboard_state.keyboard_destroy);
seat->keyboard_state.keyboard_destroy.notify = handle_keyboard_destroy;
wl_signal_add(&keyboard->events.keymap,
2018-05-02 11:03:26 +02:00
&seat->keyboard_state.keyboard_keymap);
seat->keyboard_state.keyboard_keymap.notify = handle_keyboard_keymap;
wl_signal_add(&keyboard->events.repeat_info,
2018-05-02 11:03:26 +02:00
&seat->keyboard_state.keyboard_repeat_info);
seat->keyboard_state.keyboard_repeat_info.notify =
handle_keyboard_repeat_info;
struct wlr_seat_client *client;
wl_list_for_each(client, &seat->clients, link) {
seat_client_send_keymap(client, keyboard);
seat_client_send_repeat_info(client, keyboard);
}
wlr_seat_keyboard_send_modifiers(seat, &keyboard->modifiers);
} else {
seat->keyboard_state.keyboard = NULL;
}
}
struct wlr_keyboard *wlr_seat_get_keyboard(struct wlr_seat *seat) {
return seat->keyboard_state.keyboard;
}
void wlr_seat_keyboard_start_grab(struct wlr_seat *wlr_seat,
struct wlr_seat_keyboard_grab *grab) {
grab->seat = wlr_seat;
wlr_seat->keyboard_state.grab = grab;
2022-08-18 13:16:16 +02:00
wl_signal_emit_mutable(&wlr_seat->events.keyboard_grab_begin, grab);
2018-05-02 11:03:26 +02:00
}
void wlr_seat_keyboard_end_grab(struct wlr_seat *wlr_seat) {
struct wlr_seat_keyboard_grab *grab = wlr_seat->keyboard_state.grab;
if (grab != wlr_seat->keyboard_state.default_grab) {
wlr_seat->keyboard_state.grab = wlr_seat->keyboard_state.default_grab;
2022-08-18 13:16:16 +02:00
wl_signal_emit_mutable(&wlr_seat->events.keyboard_grab_end, grab);
2018-05-02 11:03:26 +02:00
if (grab->interface->cancel) {
grab->interface->cancel(grab);
}
}
}
static void seat_keyboard_handle_surface_destroy(struct wl_listener *listener,
void *data) {
struct wlr_seat_keyboard_state *state = wl_container_of(
listener, state, surface_destroy);
wl_list_remove(&state->surface_destroy.link);
wl_list_init(&state->surface_destroy.link);
wlr_seat_keyboard_clear_focus(state->seat);
}
void wlr_seat_keyboard_send_modifiers(struct wlr_seat *seat,
const struct wlr_keyboard_modifiers *modifiers) {
2018-05-02 11:03:26 +02:00
struct wlr_seat_client *client = seat->keyboard_state.focused_client;
if (client == NULL) {
return;
}
uint32_t serial = wlr_seat_client_next_serial(client);
2018-05-02 11:03:26 +02:00
struct wl_resource *resource;
wl_resource_for_each(resource, &client->keyboards) {
2018-05-03 23:03:44 +02:00
if (seat_client_from_keyboard_resource(resource) == NULL) {
continue;
}
2018-05-02 11:03:26 +02:00
if (modifiers == NULL) {
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);
}
}
}
void seat_client_send_keyboard_leave_raw(struct wlr_seat_client *seat_client,
struct wlr_surface *surface) {
uint32_t serial = wlr_seat_client_next_serial(seat_client);
struct wl_resource *resource;
wl_resource_for_each(resource, &seat_client->keyboards) {
if (seat_client_from_keyboard_resource(resource) == NULL) {
continue;
}
wl_keyboard_send_leave(resource, serial, surface->resource);
}
}
2018-05-02 11:03:26 +02:00
void wlr_seat_keyboard_enter(struct wlr_seat *seat,
struct wlr_surface *surface, const uint32_t keycodes[], size_t num_keycodes,
const struct wlr_keyboard_modifiers *modifiers) {
2018-05-02 11:03:26 +02:00
if (seat->keyboard_state.focused_surface == surface) {
// this surface already got an enter notify
return;
}
struct wlr_seat_client *client = NULL;
if (surface) {
struct wl_client *wl_client = wl_resource_get_client(surface->resource);
client = wlr_seat_client_for_wl_client(seat, wl_client);
}
struct wlr_seat_client *focused_client =
seat->keyboard_state.focused_client;
struct wlr_surface *focused_surface =
seat->keyboard_state.focused_surface;
// leave the previously entered surface
if (focused_client != NULL && focused_surface != NULL) {
seat_client_send_keyboard_leave_raw(focused_client, focused_surface);
2018-05-02 11:03:26 +02:00
}
// enter the current surface
if (client != NULL) {
struct wl_array keys = {
.data = (void *)keycodes,
.size = num_keycodes * sizeof(keycodes[0]),
};
uint32_t serial = wlr_seat_client_next_serial(client);
2018-05-02 11:03:26 +02:00
struct wl_resource *resource;
wl_resource_for_each(resource, &client->keyboards) {
2018-05-03 23:03:44 +02:00
if (seat_client_from_keyboard_resource(resource) == NULL) {
continue;
}
2018-05-02 11:03:26 +02:00
wl_keyboard_send_enter(resource, serial, surface->resource, &keys);
}
}
// reinitialize the focus destroy events
wl_list_remove(&seat->keyboard_state.surface_destroy.link);
wl_list_init(&seat->keyboard_state.surface_destroy.link);
if (surface) {
wl_signal_add(&surface->events.destroy,
&seat->keyboard_state.surface_destroy);
seat->keyboard_state.surface_destroy.notify =
seat_keyboard_handle_surface_destroy;
}
seat->keyboard_state.focused_client = client;
seat->keyboard_state.focused_surface = surface;
if (client != NULL) {
// tell new client about any modifier change last,
// as it targets seat->keyboard_state.focused_client
wlr_seat_keyboard_send_modifiers(seat, modifiers);
seat_client_send_selection(client);
2018-05-02 11:03:26 +02:00
}
gtk-primary-selection: refactor everything, untie from seat This commits completely refactors wlr_gtk_primary_selection. The goal is to remove gtk-primary-selection state from the seat and better handle inert resources where it makes sense. wlr_seat_client.primary_selection_devices has been removed and replaced by wlr_gtk_primary_selection_device. This allows us to make offers inert when the current selection is replaced. wlr_seat_set_primary_selection has been removed because it relied on wlr_seat instead of wlr_gtk_primary_selection_device_manager. A new function, wlr_gtk_primary_selection_device_manager_set_selection (candidate for the longest function name in wlroots) has been added. It doesn't take a serial anymore as serial checking only makes sense for set_selection requests coming from Wayland clients (serial checking is now done in the Wayland interface implementation). Since wlr_gtk_primary_selection_device_manager is now required to set the selection, a new function wlr_xwayland_set_gtk_primary_selection_device_manager (candidate number two for longest function name) has been added. Devices are now made inert when the seat goes away. Future work includes removing the last primary selection bits from the seat, mainly wlr_seat.primary_selection_source and wlr_seat.events.primary_selection, replacing those with new fields in wlr_gtk_primary_selection_device. Or maybe we could keep those in the seat and replace them with a re-usable interface (for future zwp_primary_selection_v1 support). We need to think how we'll sync these three protocols (GTK, X11 and wayland-protocols). See https://github.com/swaywm/wlroots/issues/1388
2018-11-27 18:41:46 +01:00
struct wlr_seat_keyboard_focus_change_event event = {
.seat = seat,
.old_surface = focused_surface,
.new_surface = surface,
};
2022-08-18 13:16:16 +02:00
wl_signal_emit_mutable(&seat->keyboard_state.events.focus_change, &event);
2018-05-02 11:03:26 +02:00
}
void wlr_seat_keyboard_notify_enter(struct wlr_seat *seat,
struct wlr_surface *surface, const uint32_t keycodes[], size_t num_keycodes,
const struct wlr_keyboard_modifiers *modifiers) {
// NULL surfaces are prohibited in the grab-compatible API. Use
// wlr_seat_keyboard_notify_clear_focus() instead.
assert(surface);
2018-05-02 11:03:26 +02:00
struct wlr_seat_keyboard_grab *grab = seat->keyboard_state.grab;
grab->interface->enter(grab, surface, keycodes, num_keycodes, modifiers);
}
void wlr_seat_keyboard_clear_focus(struct wlr_seat *seat) {
wlr_seat_keyboard_enter(seat, NULL, NULL, 0, NULL);
}
void wlr_seat_keyboard_notify_clear_focus(struct wlr_seat *seat) {
struct wlr_seat_keyboard_grab *grab = seat->keyboard_state.grab;
grab->interface->clear_focus(grab);
}
2018-05-02 11:03:26 +02:00
bool wlr_seat_keyboard_has_grab(struct wlr_seat *seat) {
return seat->keyboard_state.grab->interface != &default_keyboard_grab_impl;
}
void wlr_seat_keyboard_notify_modifiers(struct wlr_seat *seat,
const struct wlr_keyboard_modifiers *modifiers) {
2018-05-02 11:03:26 +02:00
clock_gettime(CLOCK_MONOTONIC, &seat->last_event);
struct wlr_seat_keyboard_grab *grab = seat->keyboard_state.grab;
grab->interface->modifiers(grab, modifiers);
}
void wlr_seat_keyboard_notify_key(struct wlr_seat *seat, uint32_t time,
uint32_t key, uint32_t state) {
clock_gettime(CLOCK_MONOTONIC, &seat->last_event);
struct wlr_seat_keyboard_grab *grab = seat->keyboard_state.grab;
grab->interface->key(grab, time, key, state);
}
static void seat_client_send_keymap(struct wlr_seat_client *client,
struct wlr_keyboard *keyboard) {
if (!keyboard) {
return;
}
2023-05-10 20:43:25 +02:00
enum wl_keyboard_keymap_format format;
int fd, devnull = -1;
uint32_t size;
if (keyboard->keymap != NULL) {
format = WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1;
fd = keyboard->keymap_fd;
size = keyboard->keymap_size;
} else {
format = WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP;
devnull = open("/dev/null", O_RDONLY | O_CLOEXEC);
if (devnull < 0) {
wlr_log_errno(WLR_ERROR, "Failed to open /dev/null");
return;
}
fd = devnull;
size = 0;
}
2018-05-02 11:03:26 +02:00
// TODO: We should probably lift all of the keys set by the other
// keyboard
struct wl_resource *resource;
wl_resource_for_each(resource, &client->keyboards) {
2018-05-03 23:03:44 +02:00
if (seat_client_from_keyboard_resource(resource) == NULL) {
continue;
}
2023-05-10 20:43:25 +02:00
wl_keyboard_send_keymap(resource, format, fd, size);
}
if (devnull >= 0) {
close(devnull);
2018-05-02 11:03:26 +02:00
}
}
static void seat_client_send_repeat_info(struct wlr_seat_client *client,
struct wlr_keyboard *keyboard) {
if (!keyboard) {
return;
}
struct wl_resource *resource;
wl_resource_for_each(resource, &client->keyboards) {
2018-05-03 23:03:44 +02:00
if (seat_client_from_keyboard_resource(resource) == NULL) {
continue;
}
2018-05-02 11:03:26 +02:00
if (wl_resource_get_version(resource) >=
WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION) {
wl_keyboard_send_repeat_info(resource,
keyboard->repeat_info.rate, keyboard->repeat_info.delay);
}
}
}
void seat_client_create_keyboard(struct wlr_seat_client *seat_client,
uint32_t version, uint32_t id) {
struct wl_resource *resource = wl_resource_create(seat_client->client,
&wl_keyboard_interface, version, id);
if (resource == NULL) {
wl_client_post_no_memory(seat_client->client);
return;
}
wl_resource_set_implementation(resource, &keyboard_impl, seat_client,
2018-05-03 23:03:44 +02:00
keyboard_handle_resource_destroy);
2018-05-02 11:03:26 +02:00
wl_list_insert(&seat_client->keyboards, wl_resource_get_link(resource));
if ((seat_client->seat->capabilities & WL_SEAT_CAPABILITY_KEYBOARD) == 0) {
wl_resource_set_user_data(resource, NULL);
return;
}
2018-05-02 11:03:26 +02:00
struct wlr_keyboard *keyboard = seat_client->seat->keyboard_state.keyboard;
if (keyboard == NULL) {
return;
}
2018-05-02 11:03:26 +02:00
seat_client_send_keymap(seat_client, keyboard);
seat_client_send_repeat_info(seat_client, keyboard);
struct wlr_seat_client *focused_client =
seat_client->seat->keyboard_state.focused_client;
struct wlr_surface *focused_surface =
seat_client->seat->keyboard_state.focused_surface;
// Send an enter event if there is a focused client/surface stored
if (focused_client == seat_client && focused_surface != NULL) {
uint32_t *keycodes = keyboard->keycodes;
size_t num_keycodes = keyboard->num_keycodes;
struct wl_array keys;
wl_array_init(&keys);
for (size_t i = 0; i < num_keycodes; ++i) {
uint32_t *p = wl_array_add(&keys, sizeof(uint32_t));
if (!p) {
2020-06-04 14:33:32 +02:00
wlr_log(WLR_ERROR, "Cannot allocate memory, skipping keycode: %" PRIu32 "\n",
keycodes[i]);
continue;
}
*p = keycodes[i];
}
uint32_t serial = wlr_seat_client_next_serial(focused_client);
struct wl_resource *resource;
wl_resource_for_each(resource, &focused_client->keyboards) {
if (wl_resource_get_id(resource) == id) {
if (seat_client_from_keyboard_resource(resource) == NULL) {
continue;
}
wl_keyboard_send_enter(resource, serial,
focused_surface->resource, &keys);
}
}
wl_array_release(&keys);
wlr_seat_keyboard_send_modifiers(seat_client->seat,
&keyboard->modifiers);
}
2018-05-02 11:03:26 +02:00
}
2018-05-03 23:03:44 +02:00
void seat_client_create_inert_keyboard(struct wl_client *client,
uint32_t version, uint32_t id) {
struct wl_resource *resource =
wl_resource_create(client, &wl_keyboard_interface, version, id);
if (!resource) {
wl_client_post_no_memory(client);
return;
}
wl_resource_set_implementation(resource, &keyboard_impl, NULL, NULL);
}
2018-05-03 23:03:44 +02:00
void seat_client_destroy_keyboard(struct wl_resource *resource) {
wl_list_remove(wl_resource_get_link(resource));
wl_list_init(wl_resource_get_link(resource));
2018-05-03 23:03:44 +02:00
wl_resource_set_user_data(resource, NULL);
}