bar/wayland: multi-seat support

We only care about the mouse. We now track per-seat cursor positions
and cursor themes.

Any enter/leave/motion/button event will call the bar on_mouse()
method using the coordinates from the "current" seat.

Since the bar framework doesn't deal with multi-seats at all, we
internally, in the backend, track the currently active seat. This is
the seat which we last saw any kind of events from.

This is used in e.g. set_cursor(), which is called from the bar.
This commit is contained in:
Daniel Eklöf 2020-07-07 14:06:43 +02:00
parent 6433373f93
commit 6f22edaba6
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F

View file

@ -54,16 +54,8 @@ struct monitor {
int scale;
};
struct wayland_backend {
struct bar *bar;
struct wl_display *display;
struct wl_registry *registry;
struct wl_compositor *compositor;
struct wl_surface *surface;
struct zwlr_layer_shell_v1 *layer_shell;
struct zwlr_layer_surface_v1 *layer_surface;
struct wl_shm *shm;
struct seat {
struct wayland_backend *backend;
struct wl_seat *seat;
struct {
@ -77,6 +69,21 @@ struct wayland_backend {
struct wl_cursor_theme *theme;
struct wl_cursor *cursor;
} pointer;
};
struct wayland_backend {
struct bar *bar;
struct wl_display *display;
struct wl_registry *registry;
struct wl_compositor *compositor;
struct wl_surface *surface;
struct zwlr_layer_shell_v1 *layer_shell;
struct zwlr_layer_surface_v1 *layer_surface;
struct wl_shm *shm;
tll(struct seat) seats;
struct seat *active_seat;
tll(struct monitor) monitors;
const struct monitor *monitor;
@ -119,28 +126,28 @@ static const struct wl_shm_listener shm_listener = {
};
static void
update_cursor_surface(struct wayland_backend *backend)
update_cursor_surface(struct wayland_backend *backend, struct seat *seat)
{
if (backend->pointer.cursor == NULL)
if (seat->pointer.cursor == NULL)
return;
struct wl_cursor_image *image = backend->pointer.cursor->images[0];
struct wl_cursor_image *image = seat->pointer.cursor->images[0];
wl_surface_set_buffer_scale(backend->pointer.surface, backend->scale);
wl_surface_set_buffer_scale(seat->pointer.surface, backend->scale);
wl_surface_attach(
backend->pointer.surface, wl_cursor_image_get_buffer(image), 0, 0);
seat->pointer.surface, wl_cursor_image_get_buffer(image), 0, 0);
wl_pointer_set_cursor(
backend->pointer.pointer, backend->pointer.serial,
backend->pointer.surface,
seat->pointer.pointer, seat->pointer.serial,
seat->pointer.surface,
image->hotspot_x / backend->scale, image->hotspot_y / backend->scale);
wl_surface_damage_buffer(
backend->pointer.surface, 0, 0, INT32_MAX, INT32_MAX);
seat->pointer.surface, 0, 0, INT32_MAX, INT32_MAX);
wl_surface_commit(backend->pointer.surface);
wl_surface_commit(seat->pointer.surface);
wl_display_flush(backend->display);
}
@ -149,31 +156,41 @@ wl_pointer_enter(void *data, struct wl_pointer *wl_pointer,
uint32_t serial, struct wl_surface *surface,
wl_fixed_t surface_x, wl_fixed_t surface_y)
{
struct wayland_backend *backend = data;
backend->pointer.serial = serial;
backend->pointer.x = wl_fixed_to_int(surface_x) * backend->scale;
backend->pointer.y = wl_fixed_to_int(surface_y) * backend->scale;
struct seat *seat = data;
struct wayland_backend *backend = seat->backend;
update_cursor_surface(backend);
seat->pointer.serial = serial;
seat->pointer.x = wl_fixed_to_int(surface_x) * backend->scale;
seat->pointer.y = wl_fixed_to_int(surface_y) * backend->scale;
backend->active_seat = seat;
update_cursor_surface(backend, seat);
}
static void
wl_pointer_leave(void *data, struct wl_pointer *wl_pointer,
uint32_t serial, struct wl_surface *surface)
{
struct seat *seat = data;
struct wayland_backend *backend = seat->backend;
if (backend->active_seat == seat)
backend->active_seat = NULL;
}
static void
wl_pointer_motion(void *data, struct wl_pointer *wl_pointer,
uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y)
{
struct wayland_backend *backend = data;
struct seat *seat = data;
struct wayland_backend *backend = seat->backend;
backend->pointer.x = wl_fixed_to_int(surface_x) * backend->scale;
backend->pointer.y = wl_fixed_to_int(surface_y) * backend->scale;
seat->pointer.x = wl_fixed_to_int(surface_x) * backend->scale;
seat->pointer.y = wl_fixed_to_int(surface_y) * backend->scale;
backend->active_seat = seat;
backend->bar_on_mouse(
backend->bar, ON_MOUSE_MOTION, backend->pointer.x, backend->pointer.y);
backend->bar, ON_MOUSE_MOTION, seat->pointer.x, seat->pointer.y);
}
static void
@ -183,9 +200,12 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
if (state != WL_POINTER_BUTTON_STATE_PRESSED)
return;
struct wayland_backend *backend = data;
struct seat *seat = data;
struct wayland_backend *backend = seat->backend;
backend->active_seat = seat;
backend->bar_on_mouse(
backend->bar, ON_MOUSE_CLICK, backend->pointer.x, backend->pointer.y);
backend->bar, ON_MOUSE_CLICK, seat->pointer.x, seat->pointer.y);
}
static void
@ -233,18 +253,69 @@ static void
seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
enum wl_seat_capability caps)
{
struct wayland_backend *backend = data;
struct seat *seat = data;
struct wayland_backend *backend = seat->backend;
if (caps & WL_SEAT_CAPABILITY_POINTER) {
if (backend->pointer.pointer == NULL) {
backend->pointer.pointer = wl_seat_get_pointer(wl_seat);
wl_pointer_add_listener(backend->pointer.pointer, &pointer_listener, backend);
if (seat->pointer.pointer == NULL) {
struct wl_surface *surf = wl_compositor_create_surface(backend->compositor);
if (surf == NULL) {
LOG_ERR(
"seat %p: failed to create pointer surface for seat",
wl_seat);
return;
}
unsigned cursor_size = 24;
const char *cursor_theme = getenv("XCURSOR_THEME");
{
const char *env_cursor_size = getenv("XCURSOR_SIZE");
if (env_cursor_size != NULL) {
unsigned size;
if (sscanf(env_cursor_size, "%u", &size) == 1)
cursor_size = size;
}
}
LOG_INFO("seat %p: cursor theme: %s, size: %u",
wl_seat, cursor_theme, cursor_size);
assert(backend->shm);
LOG_INFO("SCALE: %d", backend->scale);
struct wl_cursor_theme *theme = wl_cursor_theme_load(
cursor_theme, cursor_size * backend->scale, backend->shm);
if (theme == NULL) {
LOG_ERR("seat %p: failed to load cursor theme", wl_seat);
wl_surface_destroy(surf);
return;
}
seat->pointer.pointer = wl_seat_get_pointer(wl_seat);
seat->pointer.surface = surf;
seat->pointer.theme = theme;
seat->pointer.cursor = NULL;
wl_pointer_add_listener(
seat->pointer.pointer, &pointer_listener, seat);
}
} else {
if (backend->pointer.pointer != NULL) {
wl_pointer_release(backend->pointer.pointer);
backend->pointer.pointer = NULL;
}
if (seat->pointer.pointer != NULL)
wl_pointer_release(seat->pointer.pointer);
//if (seat->pointer.cursor != NULL)
//wl_cursor_destroy(seat->pointer.cursor);
if (seat->pointer.theme != NULL)
wl_cursor_theme_destroy(seat->pointer.theme);
if (seat->pointer.surface != NULL)
wl_surface_destroy(seat->pointer.surface);
seat->pointer.pointer = NULL;
seat->pointer.cursor = NULL;
seat->pointer.theme = NULL;
seat->pointer.surface = NULL;
}
}
@ -376,7 +447,7 @@ handle_global(void *data, struct wl_registry *registry,
backend->shm = wl_registry_bind(
registry, name, &wl_shm_interface, required);
wl_shm_add_listener(backend->shm, &shm_listener, backend);
wl_display_roundtrip(backend->display);
//wl_display_roundtrip(backend->display);
}
else if (strcmp(interface, wl_output_interface.name) == 0) {
@ -407,7 +478,7 @@ handle_global(void *data, struct wl_registry *registry,
zxdg_output_v1_add_listener(mon->xdg, &xdg_output_listener, mon);
}
wl_display_roundtrip(backend->display);
//wl_display_roundtrip(backend->display);
}
else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) {
@ -424,9 +495,15 @@ handle_global(void *data, struct wl_registry *registry,
if (!verify_iface_version(interface, version, required))
return;
backend->seat = wl_registry_bind(registry, name, &wl_seat_interface, required);
wl_seat_add_listener(backend->seat, &seat_listener, backend);
wl_display_roundtrip(backend->display);
struct wl_seat *seat = wl_registry_bind(
registry, name, &wl_seat_interface, required);
assert(seat != NULL);
tll_push_back(
backend->seats, ((struct seat){.backend = backend, .seat = seat}));
wl_seat_add_listener(seat, &seat_listener, &tll_back(backend->seats));
//wl_display_roundtrip(backend->display);
}
else if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0) {
@ -443,6 +520,8 @@ static void
handle_global_remove(void *data, struct wl_registry *registry, uint32_t name)
{
LOG_WARN("global removed: 0x%08x", name);
/* TODO: need to handle displays and seats */
}
static const struct wl_registry_listener registry_listener = {
@ -668,6 +747,7 @@ setup(struct bar *_bar)
return false;
}
#if 0
backend->pointer.surface = wl_compositor_create_surface(backend->compositor);
if (backend->pointer.surface == NULL) {
LOG_ERR("failed to create cursor surface");
@ -694,6 +774,7 @@ setup(struct bar *_bar)
LOG_ERR("failed to load cursor theme");
return false;
}
#endif
backend->layer_surface = zwlr_layer_shell_v1_get_layer_surface(
backend->layer_shell, backend->surface,
@ -803,20 +884,25 @@ cleanup(struct bar *_bar)
/* TODO: move to bar */
free(bar->cursor_name);
tll_foreach(backend->seats, it) {
struct seat *seat = &it->item;
if (seat->pointer.theme != NULL)
wl_cursor_theme_destroy(seat->pointer.theme);
if (seat->pointer.pointer != NULL)
wl_pointer_destroy(seat->pointer.pointer);
if (seat->pointer.surface != NULL)
wl_surface_destroy(seat->pointer.surface);
if (seat->seat != NULL)
wl_seat_destroy(seat->seat);
}
tll_free(backend->seats);
if (backend->layer_surface != NULL)
zwlr_layer_surface_v1_destroy(backend->layer_surface);
if (backend->layer_shell != NULL)
zwlr_layer_shell_v1_destroy(backend->layer_shell);
if (backend->pointer.theme != NULL)
wl_cursor_theme_destroy(backend->pointer.theme);
if (backend->pointer.pointer != NULL)
wl_pointer_destroy(backend->pointer.pointer);
if (backend->pointer.surface != NULL)
wl_surface_destroy(backend->pointer.surface);
if (backend->surface != NULL)
wl_surface_destroy(backend->surface);
if (backend->seat != NULL)
wl_seat_destroy(backend->seat);
if (backend->compositor != NULL)
wl_compositor_destroy(backend->compositor);
if (backend->shm != NULL)
@ -991,10 +1077,14 @@ set_cursor(struct bar *_bar, const char *cursor)
struct private *bar = _bar->private;
struct wayland_backend *backend = bar->backend.data;
backend->pointer.cursor = wl_cursor_theme_get_cursor(
backend->pointer.theme, cursor);
struct seat *seat = backend->active_seat;
if (seat == NULL)
return;
update_cursor_surface(backend);
seat->pointer.cursor = wl_cursor_theme_get_cursor(
seat->pointer.theme, cursor);
update_cursor_surface(backend, seat);
}
const struct backend wayland_backend_iface = {