diff --git a/include/types/wlr_seat.h b/include/types/wlr_seat.h index b76525ec..15f1dc38 100644 --- a/include/types/wlr_seat.h +++ b/include/types/wlr_seat.h @@ -10,11 +10,14 @@ const struct wlr_touch_grab_interface default_touch_grab_impl; void seat_client_create_pointer(struct wlr_seat_client *seat_client, uint32_t version, uint32_t id); +void seat_client_destroy_pointer(struct wl_resource *resource); void seat_client_create_keyboard(struct wlr_seat_client *seat_client, uint32_t version, uint32_t id); +void seat_client_destroy_keyboard(struct wl_resource *resource); void seat_client_create_touch(struct wlr_seat_client *seat_client, uint32_t version, uint32_t id); +void seat_client_destroy_touch(struct wl_resource *resource); #endif diff --git a/types/seat/wlr_seat.c b/types/seat/wlr_seat.c index dc876f04..4a680157 100644 --- a/types/seat/wlr_seat.c +++ b/types/seat/wlr_seat.c @@ -12,11 +12,15 @@ #include "types/wlr_seat.h" #include "util/signal.h" +#define SEAT_VERSION 6 + static void seat_handle_get_pointer(struct wl_client *client, struct wl_resource *seat_resource, uint32_t id) { struct wlr_seat_client *seat_client = wlr_seat_client_from_resource(seat_resource); if (!(seat_client->seat->capabilities & WL_SEAT_CAPABILITY_POINTER)) { + wlr_log(L_ERROR, "Client sent get_pointer on seat without the " + "pointer capability"); return; } @@ -29,6 +33,8 @@ static void seat_handle_get_keyboard(struct wl_client *client, struct wlr_seat_client *seat_client = wlr_seat_client_from_resource(seat_resource); if (!(seat_client->seat->capabilities & WL_SEAT_CAPABILITY_KEYBOARD)) { + wlr_log(L_ERROR, "Client sent get_keyboard on seat without the " + "keyboard capability"); return; } @@ -41,6 +47,8 @@ static void seat_handle_get_touch(struct wl_client *client, struct wlr_seat_client *seat_client = wlr_seat_client_from_resource(seat_resource); if (!(seat_client->seat->capabilities & WL_SEAT_CAPABILITY_TOUCH)) { + wlr_log(L_ERROR, "Client sent get_touch on seat without the " + "touch capability"); return; } @@ -48,7 +56,8 @@ static void seat_handle_get_touch(struct wl_client *client, seat_client_create_touch(seat_client, version, id); } -static void seat_client_resource_destroy(struct wl_resource *seat_resource) { +static void seat_client_handle_resource_destroy( + struct wl_resource *seat_resource) { struct wlr_seat_client *client = wlr_seat_client_from_resource(seat_resource); wlr_signal_emit_safe(&client->events.destroy, client); @@ -120,7 +129,7 @@ static void seat_handle_bind(struct wl_client *client, void *_wlr_seat, wl_list_init(&seat_client->data_devices); wl_list_init(&seat_client->primary_selection_devices); wl_resource_set_implementation(seat_client->wl_resource, &seat_impl, - seat_client, seat_client_resource_destroy); + seat_client, seat_client_handle_resource_destroy); wl_list_insert(&wlr_seat->clients, &seat_client->link); if (version >= WL_SEAT_NAME_SINCE_VERSION) { wl_seat_send_name(seat_client->wl_resource, wlr_seat->name); @@ -170,41 +179,41 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) { } struct wlr_seat *wlr_seat_create(struct wl_display *display, const char *name) { - struct wlr_seat *wlr_seat = calloc(1, sizeof(struct wlr_seat)); - if (!wlr_seat) { + struct wlr_seat *seat = calloc(1, sizeof(struct wlr_seat)); + if (!seat) { return NULL; } // pointer state - wlr_seat->pointer_state.seat = wlr_seat; - wl_list_init(&wlr_seat->pointer_state.surface_destroy.link); + seat->pointer_state.seat = seat; + wl_list_init(&seat->pointer_state.surface_destroy.link); struct wlr_seat_pointer_grab *pointer_grab = calloc(1, sizeof(struct wlr_seat_pointer_grab)); if (!pointer_grab) { - free(wlr_seat); + free(seat); return NULL; } pointer_grab->interface = &default_pointer_grab_impl; - pointer_grab->seat = wlr_seat; - wlr_seat->pointer_state.default_grab = pointer_grab; - wlr_seat->pointer_state.grab = pointer_grab; + pointer_grab->seat = seat; + seat->pointer_state.default_grab = pointer_grab; + seat->pointer_state.grab = pointer_grab; // keyboard state struct wlr_seat_keyboard_grab *keyboard_grab = calloc(1, sizeof(struct wlr_seat_keyboard_grab)); if (!keyboard_grab) { free(pointer_grab); - free(wlr_seat); + free(seat); return NULL; } keyboard_grab->interface = &default_keyboard_grab_impl; - keyboard_grab->seat = wlr_seat; - wlr_seat->keyboard_state.default_grab = keyboard_grab; - wlr_seat->keyboard_state.grab = keyboard_grab; + keyboard_grab->seat = seat; + seat->keyboard_state.default_grab = keyboard_grab; + seat->keyboard_state.grab = keyboard_grab; - wlr_seat->keyboard_state.seat = wlr_seat; - wl_list_init(&wlr_seat->keyboard_state.surface_destroy.link); + seat->keyboard_state.seat = seat; + wl_list_init(&seat->keyboard_state.surface_destroy.link); // touch state struct wlr_seat_touch_grab *touch_grab = @@ -212,57 +221,58 @@ struct wlr_seat *wlr_seat_create(struct wl_display *display, const char *name) { if (!touch_grab) { free(pointer_grab); free(keyboard_grab); - free(wlr_seat); + free(seat); return NULL; } touch_grab->interface = &default_touch_grab_impl; - touch_grab->seat = wlr_seat; - wlr_seat->touch_state.default_grab = touch_grab; - wlr_seat->touch_state.grab = touch_grab; + touch_grab->seat = seat; + seat->touch_state.default_grab = touch_grab; + seat->touch_state.grab = touch_grab; - wlr_seat->touch_state.seat = wlr_seat; - wl_list_init(&wlr_seat->touch_state.touch_points); + seat->touch_state.seat = seat; + wl_list_init(&seat->touch_state.touch_points); - struct wl_global *wl_global = wl_global_create(display, - &wl_seat_interface, 6, wlr_seat, seat_handle_bind); - if (!wl_global) { - free(wlr_seat); + seat->wl_global = wl_global_create(display, &wl_seat_interface, + SEAT_VERSION, seat, seat_handle_bind); + if (seat->wl_global == NULL) { + free(touch_grab); + free(pointer_grab); + free(keyboard_grab); + free(seat); return NULL; } - wlr_seat->wl_global = wl_global; - wlr_seat->display = display; - wlr_seat->name = strdup(name); - wl_list_init(&wlr_seat->clients); - wl_list_init(&wlr_seat->drag_icons); + seat->display = display; + seat->name = strdup(name); + wl_list_init(&seat->clients); + wl_list_init(&seat->drag_icons); - wl_signal_init(&wlr_seat->events.start_drag); - wl_signal_init(&wlr_seat->events.new_drag_icon); + wl_signal_init(&seat->events.start_drag); + wl_signal_init(&seat->events.new_drag_icon); - wl_signal_init(&wlr_seat->events.request_set_cursor); + wl_signal_init(&seat->events.request_set_cursor); - wl_signal_init(&wlr_seat->events.selection); - wl_signal_init(&wlr_seat->events.primary_selection); + wl_signal_init(&seat->events.selection); + wl_signal_init(&seat->events.primary_selection); - wl_signal_init(&wlr_seat->events.pointer_grab_begin); - wl_signal_init(&wlr_seat->events.pointer_grab_end); + wl_signal_init(&seat->events.pointer_grab_begin); + wl_signal_init(&seat->events.pointer_grab_end); - wl_signal_init(&wlr_seat->events.keyboard_grab_begin); - wl_signal_init(&wlr_seat->events.keyboard_grab_end); + wl_signal_init(&seat->events.keyboard_grab_begin); + wl_signal_init(&seat->events.keyboard_grab_end); - wl_signal_init(&wlr_seat->events.touch_grab_begin); - wl_signal_init(&wlr_seat->events.touch_grab_end); + wl_signal_init(&seat->events.touch_grab_begin); + wl_signal_init(&seat->events.touch_grab_end); - wl_signal_init(&wlr_seat->events.destroy); + wl_signal_init(&seat->events.destroy); - wlr_seat->display_destroy.notify = handle_display_destroy; - wl_display_add_destroy_listener(display, &wlr_seat->display_destroy); + seat->display_destroy.notify = handle_display_destroy; + wl_display_add_destroy_listener(display, &seat->display_destroy); - return wlr_seat; + return seat; } struct wlr_seat_client *wlr_seat_client_for_wl_client(struct wlr_seat *wlr_seat, struct wl_client *wl_client) { - assert(wlr_seat); struct wlr_seat_client *seat_client; wl_list_for_each(seat_client, &wlr_seat->clients, link) { if (seat_client->client == wl_client) { @@ -275,8 +285,29 @@ struct wlr_seat_client *wlr_seat_client_for_wl_client(struct wlr_seat *wlr_seat, void wlr_seat_set_capabilities(struct wlr_seat *wlr_seat, uint32_t capabilities) { wlr_seat->capabilities = capabilities; + struct wlr_seat_client *client; wl_list_for_each(client, &wlr_seat->clients, link) { + // Make resources inert if necessary + if ((capabilities & WL_SEAT_CAPABILITY_POINTER) == 0) { + 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) { + 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); + } + } + wl_seat_send_capabilities(client->wl_resource, capabilities); } } diff --git a/types/seat/wlr_seat_keyboard.c b/types/seat/wlr_seat_keyboard.c index 975b195c..77fda68f 100644 --- a/types/seat/wlr_seat_keyboard.c +++ b/types/seat/wlr_seat_keyboard.c @@ -48,8 +48,16 @@ static const struct wl_keyboard_interface keyboard_impl = { .release = keyboard_release, }; +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); +} + static void keyboard_handle_resource_destroy(struct wl_resource *resource) { wl_list_remove(wl_resource_get_link(resource)); + seat_client_destroy_keyboard(resource); } @@ -63,6 +71,10 @@ void wlr_seat_keyboard_send_key(struct wlr_seat *wlr_seat, uint32_t time, uint32_t serial = wl_display_next_serial(wlr_seat->display); struct wl_resource *resource; wl_resource_for_each(resource, &client->keyboards) { + if (seat_client_from_keyboard_resource(resource) == NULL) { + continue; + } + wl_keyboard_send_key(resource, serial, time, key, state); } } @@ -188,6 +200,10 @@ void wlr_seat_keyboard_send_modifiers(struct wlr_seat *seat, uint32_t serial = wl_display_next_serial(seat->display); struct wl_resource *resource; wl_resource_for_each(resource, &client->keyboards) { + if (seat_client_from_keyboard_resource(resource) == NULL) { + continue; + } + if (modifiers == NULL) { wl_keyboard_send_modifiers(resource, serial, 0, 0, 0, 0); } else { @@ -223,6 +239,9 @@ void wlr_seat_keyboard_enter(struct wlr_seat *seat, uint32_t serial = wl_display_next_serial(seat->display); struct wl_resource *resource; wl_resource_for_each(resource, &focused_client->keyboards) { + if (seat_client_from_keyboard_resource(resource) == NULL) { + continue; + } wl_keyboard_send_leave(resource, serial, focused_surface->resource); } } @@ -243,6 +262,9 @@ void wlr_seat_keyboard_enter(struct wlr_seat *seat, uint32_t serial = wl_display_next_serial(seat->display); struct wl_resource *resource; wl_resource_for_each(resource, &client->keyboards) { + if (seat_client_from_keyboard_resource(resource) == NULL) { + continue; + } wl_keyboard_send_enter(resource, serial, surface->resource, &keys); } wl_array_release(&keys); @@ -312,6 +334,10 @@ static void seat_client_send_keymap(struct wlr_seat_client *client, // keyboard struct wl_resource *resource; wl_resource_for_each(resource, &client->keyboards) { + if (seat_client_from_keyboard_resource(resource) == NULL) { + continue; + } + wl_keyboard_send_keymap(resource, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, keyboard->keymap_fd, keyboard->keymap_size); @@ -326,6 +352,10 @@ static void seat_client_send_repeat_info(struct wlr_seat_client *client, struct wl_resource *resource; wl_resource_for_each(resource, &client->keyboards) { + if (seat_client_from_keyboard_resource(resource) == NULL) { + continue; + } + if (wl_resource_get_version(resource) >= WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION) { wl_keyboard_send_repeat_info(resource, @@ -343,7 +373,7 @@ void seat_client_create_keyboard(struct wlr_seat_client *seat_client, return; } wl_resource_set_implementation(resource, &keyboard_impl, seat_client, - &keyboard_handle_resource_destroy); + keyboard_handle_resource_destroy); wl_list_insert(&seat_client->keyboards, wl_resource_get_link(resource)); struct wlr_keyboard *keyboard = seat_client->seat->keyboard_state.keyboard; @@ -353,3 +383,12 @@ void seat_client_create_keyboard(struct wlr_seat_client *seat_client, // TODO possibly handle the case where this keyboard needs an enter // right away } + +void seat_client_destroy_keyboard(struct wl_resource *resource) { + struct wlr_seat_client *seat_client = + seat_client_from_keyboard_resource(resource); + if (seat_client == NULL) { + return; + } + wl_resource_set_user_data(resource, NULL); +} diff --git a/types/seat/wlr_seat_pointer.c b/types/seat/wlr_seat_pointer.c index 344597b5..4a0bcef1 100644 --- a/types/seat/wlr_seat_pointer.c +++ b/types/seat/wlr_seat_pointer.c @@ -64,30 +64,27 @@ static void pointer_set_cursor(struct wl_client *client, int32_t hotspot_x, int32_t hotspot_y) { struct wlr_seat_client *seat_client = seat_client_from_pointer_resource(pointer_resource); + if (seat_client == NULL) { + return; + } + struct wlr_surface *surface = NULL; if (surface_resource != NULL) { surface = wlr_surface_from_resource(surface_resource); - if (wlr_surface_set_role(surface, "wl_pointer-cursor", surface_resource, WL_POINTER_ERROR_ROLE) < 0) { return; } } - struct wlr_seat_pointer_request_set_cursor_event *event = - calloc(1, sizeof(struct wlr_seat_pointer_request_set_cursor_event)); - if (event == NULL) { - return; - } - event->seat_client = seat_client; - event->surface = surface; - event->serial = serial; - event->hotspot_x = hotspot_x; - event->hotspot_y = hotspot_y; - - wlr_signal_emit_safe(&seat_client->seat->events.request_set_cursor, event); - - free(event); + struct wlr_seat_pointer_request_set_cursor_event event = { + .seat_client = seat_client, + .surface = surface, + .serial = serial, + .hotspot_x = hotspot_x, + .hotspot_y = hotspot_y, + }; + wlr_signal_emit_safe(&seat_client->seat->events.request_set_cursor, &event); } static void pointer_release(struct wl_client *client, @@ -102,6 +99,7 @@ static const struct wl_pointer_interface pointer_impl = { static void pointer_handle_resource_destroy(struct wl_resource *resource) { wl_list_remove(wl_resource_get_link(resource)); + seat_client_destroy_pointer(resource); } @@ -112,8 +110,8 @@ bool wlr_seat_pointer_surface_has_focus(struct wlr_seat *wlr_seat, static void seat_pointer_handle_surface_destroy(struct wl_listener *listener, void *data) { - struct wlr_seat_pointer_state *state = wl_container_of( - listener, state, surface_destroy); + struct wlr_seat_pointer_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_pointer_clear_focus(state->seat); @@ -121,8 +119,6 @@ static void seat_pointer_handle_surface_destroy(struct wl_listener *listener, void wlr_seat_pointer_enter(struct wlr_seat *wlr_seat, struct wlr_surface *surface, double sx, double sy) { - assert(wlr_seat); - if (wlr_seat->pointer_state.focused_surface == surface) { // this surface already got an enter notify return; @@ -144,6 +140,10 @@ void wlr_seat_pointer_enter(struct wlr_seat *wlr_seat, uint32_t serial = wl_display_next_serial(wlr_seat->display); struct wl_resource *resource; wl_resource_for_each(resource, &focused_client->pointers) { + if (seat_client_from_pointer_resource(resource) == NULL) { + continue; + } + wl_pointer_send_leave(resource, serial, focused_surface->resource); pointer_send_frame(resource); } @@ -154,6 +154,10 @@ void wlr_seat_pointer_enter(struct wlr_seat *wlr_seat, uint32_t serial = wl_display_next_serial(wlr_seat->display); struct wl_resource *resource; wl_resource_for_each(resource, &client->pointers) { + if (seat_client_from_pointer_resource(resource) == NULL) { + continue; + } + wl_pointer_send_enter(resource, serial, surface->resource, wl_fixed_from_double(sx), wl_fixed_from_double(sy)); pointer_send_frame(resource); @@ -189,6 +193,10 @@ void wlr_seat_pointer_send_motion(struct wlr_seat *wlr_seat, uint32_t time, struct wl_resource *resource; wl_resource_for_each(resource, &client->pointers) { + if (seat_client_from_pointer_resource(resource) == NULL) { + continue; + } + wl_pointer_send_motion(resource, time, wl_fixed_from_double(sx), wl_fixed_from_double(sy)); pointer_send_frame(resource); @@ -205,6 +213,10 @@ uint32_t wlr_seat_pointer_send_button(struct wlr_seat *wlr_seat, uint32_t time, uint32_t serial = wl_display_next_serial(wlr_seat->display); struct wl_resource *resource; wl_resource_for_each(resource, &client->pointers) { + if (seat_client_from_pointer_resource(resource) == NULL) { + continue; + } + wl_pointer_send_button(resource, serial, time, button, state); pointer_send_frame(resource); } @@ -220,6 +232,10 @@ void wlr_seat_pointer_send_axis(struct wlr_seat *wlr_seat, uint32_t time, struct wl_resource *resource; wl_resource_for_each(resource, &client->pointers) { + if (seat_client_from_pointer_resource(resource) == NULL) { + continue; + } + if (value) { wl_pointer_send_axis(resource, time, orientation, wl_fixed_from_double(value)); @@ -235,7 +251,6 @@ void wlr_seat_pointer_start_grab(struct wlr_seat *wlr_seat, struct wlr_seat_pointer_grab *grab) { assert(wlr_seat); grab->seat = wlr_seat; - assert(grab->seat); wlr_seat->pointer_state.grab = grab; wlr_signal_emit_safe(&wlr_seat->events.pointer_grab_begin, grab); @@ -312,3 +327,12 @@ void seat_client_create_pointer(struct wlr_seat_client *seat_client, &pointer_handle_resource_destroy); wl_list_insert(&seat_client->pointers, wl_resource_get_link(resource)); } + +void seat_client_destroy_pointer(struct wl_resource *resource) { + struct wlr_seat_client *seat_client = + seat_client_from_pointer_resource(resource); + if (seat_client == NULL) { + return; + } + wl_resource_set_user_data(resource, NULL); +} diff --git a/types/seat/wlr_seat_touch.c b/types/seat/wlr_seat_touch.c index a81369df..489882ba 100644 --- a/types/seat/wlr_seat_touch.c +++ b/types/seat/wlr_seat_touch.c @@ -9,8 +9,8 @@ #include "types/wlr_seat.h" #include "util/signal.h" -static uint32_t default_touch_down(struct wlr_seat_touch_grab *grab, uint32_t time, - struct wlr_touch_point *point) { +static uint32_t default_touch_down(struct wlr_seat_touch_grab *grab, + uint32_t time, struct wlr_touch_point *point) { return wlr_seat_touch_send_down(grab->seat, point->surface, time, point->touch_id, point->sx, point->sy); } @@ -57,6 +57,14 @@ static const struct wl_touch_interface touch_impl = { static void touch_handle_resource_destroy(struct wl_resource *resource) { wl_list_remove(wl_resource_get_link(resource)); + seat_client_destroy_touch(resource); +} + +static struct wlr_seat_client *seat_client_from_touch_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, &wl_touch_interface, + &touch_impl)); + return wl_resource_get_user_data(resource); } @@ -273,6 +281,9 @@ uint32_t wlr_seat_touch_send_down(struct wlr_seat *seat, uint32_t serial = wl_display_next_serial(seat->display); struct wl_resource *resource; wl_resource_for_each(resource, &point->client->touches) { + if (seat_client_from_touch_resource(resource) == NULL) { + continue; + } wl_touch_send_down(resource, serial, time, surface->resource, touch_id, wl_fixed_from_double(sx), wl_fixed_from_double(sy)); wl_touch_send_frame(resource); @@ -291,6 +302,9 @@ void wlr_seat_touch_send_up(struct wlr_seat *seat, uint32_t time, int32_t touch_ uint32_t serial = wl_display_next_serial(seat->display); struct wl_resource *resource; wl_resource_for_each(resource, &point->client->touches) { + if (seat_client_from_touch_resource(resource) == NULL) { + continue; + } wl_touch_send_up(resource, serial, time, touch_id); wl_touch_send_frame(resource); } @@ -306,6 +320,9 @@ void wlr_seat_touch_send_motion(struct wlr_seat *seat, uint32_t time, int32_t to struct wl_resource *resource; wl_resource_for_each(resource, &point->client->touches) { + if (seat_client_from_touch_resource(resource) == NULL) { + continue; + } wl_touch_send_motion(resource, time, touch_id, wl_fixed_from_double(sx), wl_fixed_from_double(sy)); wl_touch_send_frame(resource); @@ -333,3 +350,12 @@ void seat_client_create_touch(struct wlr_seat_client *seat_client, &touch_handle_resource_destroy); wl_list_insert(&seat_client->touches, wl_resource_get_link(resource)); } + +void seat_client_destroy_touch(struct wl_resource *resource) { + struct wlr_seat_client *seat_client = + seat_client_from_touch_resource(resource); + if (seat_client == NULL) { + return; + } + wl_resource_set_user_data(resource, NULL); +}