2018-05-02 11:03:26 +02:00
|
|
|
#define _POSIX_C_SOURCE 200809L
|
|
|
|
#include <assert.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <time.h>
|
2019-07-27 10:53:54 +02:00
|
|
|
#include <wayland-server-core.h>
|
2018-05-02 11:03:26 +02:00
|
|
|
#include <wlr/types/wlr_data_device.h>
|
2018-11-28 16:37:35 +01:00
|
|
|
#include <wlr/types/wlr_primary_selection.h>
|
2018-05-02 11:03:26 +02:00
|
|
|
#include <wlr/types/wlr_seat.h>
|
2022-04-16 18:59:22 +02:00
|
|
|
#include <wlr/types/wlr_compositor.h>
|
2018-05-02 11:03:26 +02:00
|
|
|
#include <wlr/util/log.h>
|
|
|
|
#include "types/wlr_seat.h"
|
2020-02-03 16:42:36 +01:00
|
|
|
#include "util/global.h"
|
2018-05-02 11:03:26 +02:00
|
|
|
|
2022-03-27 19:04:45 +02:00
|
|
|
#define SEAT_VERSION 8
|
2018-05-03 23:03:44 +02:00
|
|
|
|
2018-05-02 11:03:26 +02:00
|
|
|
static void seat_handle_get_pointer(struct wl_client *client,
|
|
|
|
struct wl_resource *seat_resource, uint32_t id) {
|
2023-04-06 12:49:30 +02:00
|
|
|
uint32_t version = wl_resource_get_version(seat_resource);
|
2018-05-02 11:03:26 +02:00
|
|
|
struct wlr_seat_client *seat_client =
|
|
|
|
wlr_seat_client_from_resource(seat_resource);
|
2023-04-02 12:18:28 +02:00
|
|
|
if (!seat_client) {
|
2023-04-06 12:49:30 +02:00
|
|
|
// The client still needs a resource, so here's a dummy:
|
|
|
|
seat_client_create_inert_pointer(client, version, id);
|
2023-04-02 12:18:28 +02:00
|
|
|
return;
|
|
|
|
}
|
2020-05-28 00:24:50 +02:00
|
|
|
if (!(seat_client->seat->accumulated_capabilities & WL_SEAT_CAPABILITY_POINTER)) {
|
2020-06-05 11:42:36 +02:00
|
|
|
wl_resource_post_error(seat_resource, WL_SEAT_ERROR_MISSING_CAPABILITY,
|
2020-05-28 00:24:50 +02:00
|
|
|
"wl_seat.get_pointer called when no pointer capability has existed");
|
2018-05-02 11:03:26 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
seat_client_create_pointer(seat_client, version, id);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void seat_handle_get_keyboard(struct wl_client *client,
|
|
|
|
struct wl_resource *seat_resource, uint32_t id) {
|
2023-04-06 12:49:30 +02:00
|
|
|
uint32_t version = wl_resource_get_version(seat_resource);
|
2018-05-02 11:03:26 +02:00
|
|
|
struct wlr_seat_client *seat_client =
|
|
|
|
wlr_seat_client_from_resource(seat_resource);
|
2023-04-02 12:18:28 +02:00
|
|
|
if (!seat_client) {
|
2023-04-06 12:49:30 +02:00
|
|
|
seat_client_create_inert_keyboard(client, version, id);
|
2023-04-02 12:18:28 +02:00
|
|
|
return;
|
|
|
|
}
|
2020-05-28 00:24:50 +02:00
|
|
|
if (!(seat_client->seat->accumulated_capabilities & WL_SEAT_CAPABILITY_KEYBOARD)) {
|
2020-06-05 11:42:36 +02:00
|
|
|
wl_resource_post_error(seat_resource, WL_SEAT_ERROR_MISSING_CAPABILITY,
|
2020-05-28 00:24:50 +02:00
|
|
|
"wl_seat.get_keyboard called when no keyboard capability has existed");
|
2018-05-02 11:03:26 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
seat_client_create_keyboard(seat_client, version, id);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void seat_handle_get_touch(struct wl_client *client,
|
|
|
|
struct wl_resource *seat_resource, uint32_t id) {
|
2023-04-06 12:49:30 +02:00
|
|
|
uint32_t version = wl_resource_get_version(seat_resource);
|
2018-05-02 11:03:26 +02:00
|
|
|
struct wlr_seat_client *seat_client =
|
|
|
|
wlr_seat_client_from_resource(seat_resource);
|
2023-04-02 12:18:28 +02:00
|
|
|
if (!seat_client) {
|
2023-04-06 12:49:30 +02:00
|
|
|
seat_client_create_inert_touch(client, version, id);
|
2023-04-02 12:18:28 +02:00
|
|
|
return;
|
|
|
|
}
|
2020-05-28 00:24:50 +02:00
|
|
|
if (!(seat_client->seat->accumulated_capabilities & WL_SEAT_CAPABILITY_TOUCH)) {
|
2020-06-05 11:42:36 +02:00
|
|
|
wl_resource_post_error(seat_resource, WL_SEAT_ERROR_MISSING_CAPABILITY,
|
2020-05-28 00:24:50 +02:00
|
|
|
"wl_seat.get_touch called when no touch capability has existed");
|
2018-05-02 11:03:26 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
seat_client_create_touch(seat_client, version, id);
|
|
|
|
}
|
|
|
|
|
2023-04-02 12:18:28 +02:00
|
|
|
static void seat_client_destroy(struct wlr_seat_client *client) {
|
2022-08-18 13:16:16 +02:00
|
|
|
wl_signal_emit_mutable(&client->events.destroy, client);
|
2018-05-02 11:03:26 +02:00
|
|
|
|
|
|
|
if (client == client->seat->pointer_state.focused_client) {
|
|
|
|
client->seat->pointer_state.focused_client = NULL;
|
|
|
|
}
|
|
|
|
if (client == client->seat->keyboard_state.focused_client) {
|
|
|
|
client->seat->keyboard_state.focused_client = NULL;
|
|
|
|
}
|
|
|
|
|
2022-11-15 02:00:27 +01:00
|
|
|
if (client->seat->drag && client == client->seat->drag->seat_client) {
|
|
|
|
client->seat->drag->seat_client = NULL;
|
|
|
|
}
|
|
|
|
|
2018-05-02 11:03:26 +02:00
|
|
|
struct wl_resource *resource, *tmp;
|
|
|
|
wl_resource_for_each_safe(resource, tmp, &client->pointers) {
|
2023-04-02 12:18:28 +02:00
|
|
|
seat_client_destroy_pointer(resource);
|
2018-05-02 11:03:26 +02:00
|
|
|
}
|
|
|
|
wl_resource_for_each_safe(resource, tmp, &client->keyboards) {
|
2023-04-02 12:18:28 +02:00
|
|
|
seat_client_destroy_keyboard(resource);
|
2018-05-02 11:03:26 +02:00
|
|
|
}
|
|
|
|
wl_resource_for_each_safe(resource, tmp, &client->touches) {
|
2023-04-02 12:18:28 +02:00
|
|
|
seat_client_destroy_touch(resource);
|
2018-05-02 11:03:26 +02:00
|
|
|
}
|
|
|
|
wl_resource_for_each_safe(resource, tmp, &client->data_devices) {
|
2018-12-09 16:58:31 +01:00
|
|
|
// Make the data device inert
|
2023-04-02 12:18:28 +02:00
|
|
|
wl_list_remove(wl_resource_get_link(resource));
|
|
|
|
wl_list_init(wl_resource_get_link(resource));
|
|
|
|
wl_resource_set_user_data(resource, NULL);
|
|
|
|
}
|
|
|
|
wl_resource_for_each_safe(resource, tmp, &client->resources) {
|
|
|
|
// Make the seat resource inert
|
|
|
|
wl_list_remove(wl_resource_get_link(resource));
|
|
|
|
wl_list_init(wl_resource_get_link(resource));
|
2018-12-09 16:58:31 +01:00
|
|
|
wl_resource_set_user_data(resource, NULL);
|
2018-05-02 11:03:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
wl_list_remove(&client->link);
|
|
|
|
free(client);
|
|
|
|
}
|
|
|
|
|
2023-04-02 12:18:28 +02:00
|
|
|
static void seat_client_handle_resource_destroy(
|
|
|
|
struct wl_resource *seat_resource) {
|
|
|
|
struct wlr_seat_client *client =
|
|
|
|
wlr_seat_client_from_resource(seat_resource);
|
|
|
|
if (!client) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
wl_list_remove(wl_resource_get_link(seat_resource));
|
|
|
|
if (!wl_list_empty(&client->resources)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
seat_client_destroy(client);
|
|
|
|
}
|
|
|
|
|
2018-05-02 11:03:26 +02:00
|
|
|
static void seat_handle_release(struct wl_client *client,
|
|
|
|
struct wl_resource *resource) {
|
|
|
|
wl_resource_destroy(resource);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct wl_seat_interface seat_impl = {
|
|
|
|
.get_pointer = seat_handle_get_pointer,
|
|
|
|
.get_keyboard = seat_handle_get_keyboard,
|
|
|
|
.get_touch = seat_handle_get_touch,
|
|
|
|
.release = seat_handle_release,
|
|
|
|
};
|
|
|
|
|
2023-04-02 11:37:38 +02:00
|
|
|
static struct wlr_seat_client *seat_client_create(struct wlr_seat *wlr_seat,
|
|
|
|
struct wl_client *client, struct wl_resource *wl_resource) {
|
2023-10-03 07:51:07 +02:00
|
|
|
struct wlr_seat_client *seat_client = calloc(1, sizeof(*seat_client));
|
2023-04-02 11:37:38 +02:00
|
|
|
if (!seat_client) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
seat_client->client = client;
|
|
|
|
seat_client->seat = wlr_seat;
|
|
|
|
wl_list_init(&seat_client->resources);
|
|
|
|
wl_list_init(&seat_client->pointers);
|
|
|
|
wl_list_init(&seat_client->keyboards);
|
|
|
|
wl_list_init(&seat_client->touches);
|
|
|
|
wl_list_init(&seat_client->data_devices);
|
|
|
|
wl_signal_init(&seat_client->events.destroy);
|
|
|
|
|
|
|
|
wl_list_insert(&wlr_seat->clients, &seat_client->link);
|
|
|
|
|
|
|
|
struct wlr_surface *pointer_focus =
|
|
|
|
wlr_seat->pointer_state.focused_surface;
|
|
|
|
if (pointer_focus != NULL &&
|
|
|
|
wl_resource_get_client(pointer_focus->resource) == client) {
|
|
|
|
wlr_seat->pointer_state.focused_client = seat_client;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct wlr_surface *keyboard_focus =
|
|
|
|
wlr_seat->keyboard_state.focused_surface;
|
|
|
|
if (keyboard_focus != NULL &&
|
|
|
|
wl_resource_get_client(keyboard_focus->resource) == client) {
|
|
|
|
wlr_seat->keyboard_state.focused_client = seat_client;
|
|
|
|
}
|
|
|
|
|
|
|
|
return seat_client;
|
|
|
|
}
|
|
|
|
|
2018-05-02 11:03:26 +02:00
|
|
|
static void seat_handle_bind(struct wl_client *client, void *_wlr_seat,
|
|
|
|
uint32_t version, uint32_t id) {
|
2023-06-01 09:05:46 +02:00
|
|
|
// `wlr_seat` can be NULL if the seat global is being destroyed
|
2018-05-02 11:03:26 +02:00
|
|
|
struct wlr_seat *wlr_seat = _wlr_seat;
|
2023-06-01 09:05:46 +02:00
|
|
|
assert(client);
|
2018-05-02 11:03:26 +02:00
|
|
|
|
2018-06-04 01:31:27 +02:00
|
|
|
struct wl_resource *wl_resource =
|
2018-05-02 11:03:26 +02:00
|
|
|
wl_resource_create(client, &wl_seat_interface, version, id);
|
2018-06-04 01:31:27 +02:00
|
|
|
if (wl_resource == NULL) {
|
2018-05-02 11:03:26 +02:00
|
|
|
wl_client_post_no_memory(client);
|
|
|
|
return;
|
|
|
|
}
|
2023-06-01 09:05:46 +02:00
|
|
|
wl_resource_set_implementation(wl_resource, &seat_impl, NULL,
|
|
|
|
seat_client_handle_resource_destroy);
|
|
|
|
wl_list_init(wl_resource_get_link(wl_resource));
|
|
|
|
if (wlr_seat == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
2018-06-04 01:31:27 +02:00
|
|
|
|
|
|
|
struct wlr_seat_client *seat_client =
|
|
|
|
wlr_seat_client_for_wl_client(wlr_seat, client);
|
2023-04-02 11:37:38 +02:00
|
|
|
if (!seat_client) {
|
|
|
|
seat_client = seat_client_create(wlr_seat, client, wl_resource);
|
|
|
|
}
|
|
|
|
|
2018-06-04 01:31:27 +02:00
|
|
|
if (seat_client == NULL) {
|
2023-04-02 11:37:38 +02:00
|
|
|
wl_resource_destroy(wl_resource);
|
|
|
|
wl_client_post_no_memory(client);
|
|
|
|
return;
|
2018-06-04 01:31:27 +02:00
|
|
|
}
|
|
|
|
|
2023-06-01 09:05:46 +02:00
|
|
|
wl_resource_set_user_data(wl_resource, seat_client);
|
2018-07-08 20:21:31 +02:00
|
|
|
wl_list_insert(&seat_client->resources, wl_resource_get_link(wl_resource));
|
2018-05-02 11:03:26 +02:00
|
|
|
if (version >= WL_SEAT_NAME_SINCE_VERSION) {
|
2018-06-04 01:31:27 +02:00
|
|
|
wl_seat_send_name(wl_resource, wlr_seat->name);
|
2018-05-02 11:03:26 +02:00
|
|
|
}
|
2018-06-04 01:31:27 +02:00
|
|
|
wl_seat_send_capabilities(wl_resource, wlr_seat->capabilities);
|
2018-05-02 11:03:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void wlr_seat_destroy(struct wlr_seat *seat) {
|
|
|
|
if (!seat) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-12-28 16:10:42 +01:00
|
|
|
wlr_seat_pointer_clear_focus(seat);
|
|
|
|
wlr_seat_keyboard_clear_focus(seat);
|
|
|
|
|
2022-11-29 21:21:18 +01:00
|
|
|
wlr_seat_set_keyboard(seat, NULL);
|
|
|
|
|
2020-12-28 16:10:42 +01:00
|
|
|
struct wlr_touch_point *point;
|
|
|
|
wl_list_for_each(point, &seat->touch_state.touch_points, link) {
|
|
|
|
wlr_seat_touch_point_clear_focus(seat, 0, point->touch_id);
|
|
|
|
}
|
|
|
|
|
2022-08-18 13:16:16 +02:00
|
|
|
wl_signal_emit_mutable(&seat->events.destroy, seat);
|
2018-05-02 11:03:26 +02:00
|
|
|
|
|
|
|
wl_list_remove(&seat->display_destroy.link);
|
|
|
|
|
2018-12-09 16:45:31 +01:00
|
|
|
wlr_data_source_destroy(seat->selection_source);
|
|
|
|
wlr_primary_selection_source_destroy(seat->primary_selection_source);
|
2018-11-28 16:37:35 +01:00
|
|
|
|
2018-05-02 11:03:26 +02:00
|
|
|
struct wlr_seat_client *client, *tmp;
|
|
|
|
wl_list_for_each_safe(client, tmp, &seat->clients, link) {
|
2023-04-02 12:18:28 +02:00
|
|
|
seat_client_destroy(client);
|
2018-05-02 11:03:26 +02:00
|
|
|
}
|
|
|
|
|
2021-06-29 19:12:50 +02:00
|
|
|
wlr_global_destroy_safe(seat->global);
|
2018-05-02 11:03:26 +02:00
|
|
|
free(seat->pointer_state.default_grab);
|
|
|
|
free(seat->keyboard_state.default_grab);
|
|
|
|
free(seat->touch_state.default_grab);
|
|
|
|
free(seat->name);
|
|
|
|
free(seat);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void handle_display_destroy(struct wl_listener *listener, void *data) {
|
|
|
|
struct wlr_seat *seat =
|
|
|
|
wl_container_of(listener, seat, display_destroy);
|
|
|
|
wlr_seat_destroy(seat);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct wlr_seat *wlr_seat_create(struct wl_display *display, const char *name) {
|
2023-10-03 07:51:07 +02:00
|
|
|
struct wlr_seat *seat = calloc(1, sizeof(*seat));
|
2018-05-03 23:03:44 +02:00
|
|
|
if (!seat) {
|
2018-05-02 11:03:26 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// pointer state
|
2018-05-03 23:03:44 +02:00
|
|
|
seat->pointer_state.seat = seat;
|
|
|
|
wl_list_init(&seat->pointer_state.surface_destroy.link);
|
2018-05-02 11:03:26 +02:00
|
|
|
|
2023-10-03 07:51:07 +02:00
|
|
|
struct wlr_seat_pointer_grab *pointer_grab = calloc(1, sizeof(*pointer_grab));
|
2018-05-02 11:03:26 +02:00
|
|
|
if (!pointer_grab) {
|
2018-05-03 23:03:44 +02:00
|
|
|
free(seat);
|
2018-05-02 11:03:26 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
pointer_grab->interface = &default_pointer_grab_impl;
|
2018-05-03 23:03:44 +02:00
|
|
|
pointer_grab->seat = seat;
|
|
|
|
seat->pointer_state.default_grab = pointer_grab;
|
|
|
|
seat->pointer_state.grab = pointer_grab;
|
2018-05-02 11:03:26 +02:00
|
|
|
|
2018-08-04 23:22:21 +02:00
|
|
|
wl_signal_init(&seat->pointer_state.events.focus_change);
|
|
|
|
|
2018-05-02 11:03:26 +02:00
|
|
|
// keyboard state
|
2023-10-03 07:51:07 +02:00
|
|
|
struct wlr_seat_keyboard_grab *keyboard_grab = calloc(1, sizeof(*keyboard_grab));
|
2018-05-02 11:03:26 +02:00
|
|
|
if (!keyboard_grab) {
|
|
|
|
free(pointer_grab);
|
2018-05-03 23:03:44 +02:00
|
|
|
free(seat);
|
2018-05-02 11:03:26 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
keyboard_grab->interface = &default_keyboard_grab_impl;
|
2018-05-03 23:03:44 +02:00
|
|
|
keyboard_grab->seat = seat;
|
|
|
|
seat->keyboard_state.default_grab = keyboard_grab;
|
|
|
|
seat->keyboard_state.grab = keyboard_grab;
|
2018-05-02 11:03:26 +02:00
|
|
|
|
2018-05-03 23:03:44 +02:00
|
|
|
seat->keyboard_state.seat = seat;
|
|
|
|
wl_list_init(&seat->keyboard_state.surface_destroy.link);
|
2018-05-02 11:03:26 +02:00
|
|
|
|
2018-11-27 18:41:46 +01:00
|
|
|
wl_signal_init(&seat->keyboard_state.events.focus_change);
|
|
|
|
|
2018-05-02 11:03:26 +02:00
|
|
|
// touch state
|
2023-10-03 07:51:07 +02:00
|
|
|
struct wlr_seat_touch_grab *touch_grab = calloc(1, sizeof(*touch_grab));
|
2018-05-02 11:03:26 +02:00
|
|
|
if (!touch_grab) {
|
|
|
|
free(pointer_grab);
|
|
|
|
free(keyboard_grab);
|
2018-05-03 23:03:44 +02:00
|
|
|
free(seat);
|
2018-05-02 11:03:26 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
touch_grab->interface = &default_touch_grab_impl;
|
2018-05-03 23:03:44 +02:00
|
|
|
touch_grab->seat = seat;
|
|
|
|
seat->touch_state.default_grab = touch_grab;
|
|
|
|
seat->touch_state.grab = touch_grab;
|
2018-05-02 11:03:26 +02:00
|
|
|
|
2018-05-03 23:03:44 +02:00
|
|
|
seat->touch_state.seat = seat;
|
|
|
|
wl_list_init(&seat->touch_state.touch_points);
|
2018-05-02 11:03:26 +02:00
|
|
|
|
2018-07-08 20:21:31 +02:00
|
|
|
seat->global = wl_global_create(display, &wl_seat_interface,
|
2019-04-27 16:38:20 +02:00
|
|
|
SEAT_VERSION, seat, seat_handle_bind);
|
2018-07-08 20:21:31 +02:00
|
|
|
if (seat->global == NULL) {
|
2018-05-03 23:03:44 +02:00
|
|
|
free(touch_grab);
|
|
|
|
free(pointer_grab);
|
|
|
|
free(keyboard_grab);
|
|
|
|
free(seat);
|
2018-05-02 11:03:26 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
2018-05-03 23:03:44 +02:00
|
|
|
seat->display = display;
|
|
|
|
seat->name = strdup(name);
|
|
|
|
wl_list_init(&seat->clients);
|
2018-12-09 17:35:11 +01:00
|
|
|
wl_list_init(&seat->selection_offers);
|
|
|
|
wl_list_init(&seat->drag_offers);
|
2018-05-02 11:03:26 +02:00
|
|
|
|
2019-01-30 18:36:19 +01:00
|
|
|
wl_signal_init(&seat->events.request_start_drag);
|
2018-05-03 23:03:44 +02:00
|
|
|
wl_signal_init(&seat->events.start_drag);
|
2018-05-02 11:03:26 +02:00
|
|
|
|
2018-05-03 23:03:44 +02:00
|
|
|
wl_signal_init(&seat->events.request_set_cursor);
|
2018-05-02 11:03:26 +02:00
|
|
|
|
2018-11-29 19:30:04 +01:00
|
|
|
wl_signal_init(&seat->events.request_set_selection);
|
|
|
|
wl_signal_init(&seat->events.set_selection);
|
|
|
|
wl_signal_init(&seat->events.request_set_primary_selection);
|
|
|
|
wl_signal_init(&seat->events.set_primary_selection);
|
2018-05-02 11:03:26 +02:00
|
|
|
|
2018-05-03 23:03:44 +02:00
|
|
|
wl_signal_init(&seat->events.pointer_grab_begin);
|
|
|
|
wl_signal_init(&seat->events.pointer_grab_end);
|
2018-05-02 11:03:26 +02:00
|
|
|
|
2018-05-03 23:03:44 +02:00
|
|
|
wl_signal_init(&seat->events.keyboard_grab_begin);
|
|
|
|
wl_signal_init(&seat->events.keyboard_grab_end);
|
2018-05-02 11:03:26 +02:00
|
|
|
|
2018-05-03 23:03:44 +02:00
|
|
|
wl_signal_init(&seat->events.touch_grab_begin);
|
|
|
|
wl_signal_init(&seat->events.touch_grab_end);
|
2018-05-02 11:03:26 +02:00
|
|
|
|
2018-05-03 23:03:44 +02:00
|
|
|
wl_signal_init(&seat->events.destroy);
|
2018-05-02 11:03:26 +02:00
|
|
|
|
2018-05-03 23:03:44 +02:00
|
|
|
seat->display_destroy.notify = handle_display_destroy;
|
|
|
|
wl_display_add_destroy_listener(display, &seat->display_destroy);
|
2018-05-02 11:03:26 +02:00
|
|
|
|
2018-05-03 23:03:44 +02:00
|
|
|
return seat;
|
2018-05-02 11:03:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
struct wlr_seat_client *wlr_seat_client_for_wl_client(struct wlr_seat *wlr_seat,
|
|
|
|
struct wl_client *wl_client) {
|
|
|
|
struct wlr_seat_client *seat_client;
|
|
|
|
wl_list_for_each(seat_client, &wlr_seat->clients, link) {
|
|
|
|
if (seat_client->client == wl_client) {
|
|
|
|
return seat_client;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void wlr_seat_set_capabilities(struct wlr_seat *wlr_seat,
|
|
|
|
uint32_t capabilities) {
|
2020-05-29 07:32:03 +02:00
|
|
|
// if the capabilities haven't changed (i.e a redundant mouse was removed),
|
|
|
|
// we don't actually have to do anything
|
|
|
|
if (capabilities == wlr_seat->capabilities) {
|
|
|
|
return;
|
|
|
|
}
|
2018-05-02 11:03:26 +02:00
|
|
|
wlr_seat->capabilities = capabilities;
|
2020-05-28 00:24:50 +02:00
|
|
|
wlr_seat->accumulated_capabilities |= capabilities;
|
2018-05-03 23:03:44 +02:00
|
|
|
|
2018-05-02 11:03:26 +02:00
|
|
|
struct wlr_seat_client *client;
|
|
|
|
wl_list_for_each(client, &wlr_seat->clients, link) {
|
2018-05-03 23:03:44 +02:00
|
|
|
// Make resources inert if necessary
|
|
|
|
if ((capabilities & WL_SEAT_CAPABILITY_POINTER) == 0) {
|
2020-03-13 23:38:33 +01:00
|
|
|
struct wlr_seat_client *focused_client =
|
|
|
|
wlr_seat->pointer_state.focused_client;
|
|
|
|
struct wlr_surface *focused_surface =
|
|
|
|
wlr_seat->pointer_state.focused_surface;
|
|
|
|
|
|
|
|
if (focused_client != NULL && focused_surface != NULL) {
|
|
|
|
seat_client_send_pointer_leave_raw(focused_client, focused_surface);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Note: we don't set focused client/surface to NULL since we need
|
|
|
|
// them to send the enter event if the pointer is recreated
|
|
|
|
|
2018-05-03 23:03:44 +02:00
|
|
|
struct wl_resource *resource, *tmp;
|
|
|
|
wl_resource_for_each_safe(resource, tmp, &client->pointers) {
|
|
|
|
seat_client_destroy_pointer(resource);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((capabilities & WL_SEAT_CAPABILITY_KEYBOARD) == 0) {
|
2020-03-13 20:22:59 +01:00
|
|
|
struct wlr_seat_client *focused_client =
|
|
|
|
wlr_seat->keyboard_state.focused_client;
|
|
|
|
struct wlr_surface *focused_surface =
|
|
|
|
wlr_seat->keyboard_state.focused_surface;
|
|
|
|
|
|
|
|
if (focused_client != NULL && focused_surface != NULL) {
|
|
|
|
seat_client_send_keyboard_leave_raw(focused_client,
|
|
|
|
focused_surface);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Note: we don't set focused client/surface to NULL since we need
|
|
|
|
// them to send the enter event if the keyboard is recreated
|
|
|
|
|
2018-05-03 23:03:44 +02:00
|
|
|
struct wl_resource *resource, *tmp;
|
|
|
|
wl_resource_for_each_safe(resource, tmp, &client->keyboards) {
|
|
|
|
seat_client_destroy_keyboard(resource);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((capabilities & WL_SEAT_CAPABILITY_TOUCH) == 0) {
|
|
|
|
struct wl_resource *resource, *tmp;
|
|
|
|
wl_resource_for_each_safe(resource, tmp, &client->touches) {
|
|
|
|
seat_client_destroy_touch(resource);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-04 01:31:27 +02:00
|
|
|
struct wl_resource *resource;
|
2018-07-08 20:21:31 +02:00
|
|
|
wl_resource_for_each(resource, &client->resources) {
|
2018-06-04 01:31:27 +02:00
|
|
|
wl_seat_send_capabilities(resource, capabilities);
|
|
|
|
}
|
2018-05-02 11:03:26 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void wlr_seat_set_name(struct wlr_seat *wlr_seat, const char *name) {
|
|
|
|
free(wlr_seat->name);
|
|
|
|
wlr_seat->name = strdup(name);
|
|
|
|
struct wlr_seat_client *client;
|
|
|
|
wl_list_for_each(client, &wlr_seat->clients, link) {
|
2018-06-04 01:31:27 +02:00
|
|
|
struct wl_resource *resource;
|
2018-07-08 20:21:31 +02:00
|
|
|
wl_resource_for_each(resource, &client->resources) {
|
2018-06-04 01:31:27 +02:00
|
|
|
wl_seat_send_name(resource, name);
|
|
|
|
}
|
2018-05-02 11:03:26 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct wlr_seat_client *wlr_seat_client_from_resource(
|
|
|
|
struct wl_resource *resource) {
|
|
|
|
assert(wl_resource_instance_of(resource, &wl_seat_interface,
|
|
|
|
&seat_impl));
|
|
|
|
return wl_resource_get_user_data(resource);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool wlr_seat_validate_grab_serial(struct wlr_seat *seat, uint32_t serial) {
|
|
|
|
// TODO
|
|
|
|
//return serial == seat->pointer_state.grab_serial ||
|
|
|
|
// serial == seat->touch_state.grab_serial;
|
|
|
|
return true;
|
|
|
|
}
|
2019-06-27 21:43:58 +02:00
|
|
|
|
2019-06-29 15:15:23 +02:00
|
|
|
uint32_t wlr_seat_client_next_serial(struct wlr_seat_client *client) {
|
|
|
|
uint32_t serial = wl_display_next_serial(wl_client_get_display(client->client));
|
|
|
|
struct wlr_serial_ringset *set = &client->serials;
|
|
|
|
|
2019-06-30 02:40:45 +02:00
|
|
|
if (set->count == 0) {
|
|
|
|
set->data[0].min_incl = serial;
|
|
|
|
set->data[0].max_incl = serial;
|
|
|
|
set->count = 1;
|
|
|
|
set->end = 0;
|
|
|
|
} else if (set->data[set->end].max_incl + 1 != serial) {
|
2019-06-29 15:15:23 +02:00
|
|
|
if (set->count < WLR_SERIAL_RINGSET_SIZE) {
|
|
|
|
set->count++;
|
2019-06-27 21:43:58 +02:00
|
|
|
}
|
|
|
|
set->end = (set->end + 1) % WLR_SERIAL_RINGSET_SIZE;
|
|
|
|
set->data[set->end].min_incl = serial;
|
|
|
|
set->data[set->end].max_incl = serial;
|
|
|
|
} else {
|
|
|
|
set->data[set->end].max_incl = serial;
|
|
|
|
}
|
2019-06-29 15:15:23 +02:00
|
|
|
|
|
|
|
return serial;
|
2019-06-27 21:43:58 +02:00
|
|
|
}
|
|
|
|
|
2019-06-29 15:15:23 +02:00
|
|
|
bool wlr_seat_client_validate_event_serial(struct wlr_seat_client *client, uint32_t serial) {
|
|
|
|
uint32_t cur = wl_display_get_serial(wl_client_get_display(client->client));
|
|
|
|
struct wlr_serial_ringset *set = &client->serials;
|
|
|
|
uint32_t rev_dist = cur - serial;
|
|
|
|
|
|
|
|
if (rev_dist >= UINT32_MAX / 2) {
|
|
|
|
// serial is closer to being 'newer' instead of 'older' than
|
|
|
|
// the current serial, so it's either invalid or incredibly old
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-06-27 21:43:58 +02:00
|
|
|
for (int i = 0; i < set->count; i++) {
|
|
|
|
int j = (set->end - i + WLR_SERIAL_RINGSET_SIZE) % WLR_SERIAL_RINGSET_SIZE;
|
2019-06-29 15:15:23 +02:00
|
|
|
if (rev_dist < cur - set->data[j].max_incl) {
|
2019-06-27 21:43:58 +02:00
|
|
|
return false;
|
|
|
|
}
|
2019-06-29 15:15:23 +02:00
|
|
|
if (rev_dist <= cur - set->data[j].min_incl) {
|
2019-06-27 21:43:58 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-29 15:15:23 +02:00
|
|
|
// Iff the set is full, then `rev_dist` is large enough that serial
|
|
|
|
// could already have been recycled out of the set.
|
|
|
|
return set->count == WLR_SERIAL_RINGSET_SIZE;
|
2019-06-27 21:43:58 +02:00
|
|
|
}
|