From 4f0443a3447b7f27da36c5b0e638c0619da1f273 Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 16 Dec 2017 13:53:39 +0100 Subject: [PATCH 1/5] Support multiple resources per seat client for pointer, keyboard, touch --- include/wlr/types/wlr_seat.h | 8 +- types/wlr_data_device.c | 4 +- types/wlr_seat.c | 263 +++++++++++++++++++---------------- 3 files changed, 148 insertions(+), 127 deletions(-) diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h index 00fd8da1..2084d8f7 100644 --- a/include/wlr/types/wlr_seat.h +++ b/include/wlr/types/wlr_seat.h @@ -16,9 +16,11 @@ struct wlr_seat_client { struct wl_client *client; struct wlr_seat *seat; - struct wl_resource *pointer; - struct wl_resource *keyboard; - struct wl_resource *touch; + // lists of wl_resource + struct wl_list pointers; + struct wl_list keyboards; + struct wl_list touches; + struct wl_resource *data_device; struct { diff --git a/types/wlr_data_device.c b/types/wlr_data_device.c index dacb2a45..9a942f46 100644 --- a/types/wlr_data_device.c +++ b/types/wlr_data_device.c @@ -687,13 +687,13 @@ static bool seat_client_start_drag(struct wlr_seat_client *client, drag->seat = client->seat; - drag->is_pointer_grab = client->pointer != NULL && + drag->is_pointer_grab = !wl_list_empty(&client->pointers) && client->seat->pointer_state.button_count == 1 && client->seat->pointer_state.grab_serial == serial && client->seat->pointer_state.focused_surface && client->seat->pointer_state.focused_surface == origin; - bool is_touch_grab = client->touch && + bool is_touch_grab = !wl_list_empty(&client->touches) && wlr_seat_touch_num_points(client->seat) == 1 && client->seat->touch_state.grab_serial == serial; diff --git a/types/wlr_seat.c b/types/wlr_seat.c index 84a7045d..4f775da7 100644 --- a/types/wlr_seat.c +++ b/types/wlr_seat.c @@ -55,14 +55,11 @@ static void wl_pointer_set_cursor(struct wl_client *client, static const struct wl_pointer_interface wl_pointer_impl = { .set_cursor = wl_pointer_set_cursor, - .release = resource_destroy + .release = resource_destroy, }; static void wl_pointer_destroy(struct wl_resource *resource) { - struct wlr_seat_client *client = wl_resource_get_user_data(resource); - if (client->pointer) { - client->pointer = NULL; - } + wl_list_remove(wl_resource_get_link(resource)); } static void wl_seat_get_pointer(struct wl_client *client, @@ -72,55 +69,55 @@ static void wl_seat_get_pointer(struct wl_client *client, if (!(seat_client->seat->capabilities & WL_SEAT_CAPABILITY_POINTER)) { return; } - if (seat_client->pointer) { - // TODO: this is probably a protocol violation but it simplifies our - // code and it'd be stupid for clients to create several pointers for - // the same seat - wl_resource_destroy(seat_client->pointer); - } - seat_client->pointer = wl_resource_create(client, &wl_pointer_interface, - wl_resource_get_version(seat_resource), id); - if (seat_client->pointer == NULL) { + + struct wl_resource *resource = wl_resource_create(client, + &wl_pointer_interface, wl_resource_get_version(seat_resource), id); + if (resource == NULL) { wl_resource_post_no_memory(seat_resource); return; } - wl_resource_set_implementation(seat_client->pointer, &wl_pointer_impl, - seat_client, &wl_pointer_destroy); + wl_resource_set_implementation(resource, &wl_pointer_impl, seat_client, + &wl_pointer_destroy); + wl_list_insert(&seat_client->pointers, wl_resource_get_link(resource)); } static const struct wl_keyboard_interface wl_keyboard_impl = { - .release = resource_destroy + .release = resource_destroy, }; static void wl_keyboard_destroy(struct wl_resource *resource) { - struct wlr_seat_client *client = wl_resource_get_user_data(resource); - if (client->keyboard) { - client->keyboard = NULL; - } + wl_list_remove(wl_resource_get_link(resource)); } static void seat_client_send_keymap(struct wlr_seat_client *client, struct wlr_keyboard *keyboard) { - if (!keyboard || !client->keyboard) { + if (!keyboard) { return; } + // TODO: We should probably lift all of the keys set by the other // keyboard - wl_keyboard_send_keymap(client->keyboard, - WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, keyboard->keymap_fd, - keyboard->keymap_size); + struct wl_resource *resource; + wl_resource_for_each(resource, &client->keyboards) { + wl_keyboard_send_keymap(resource, + WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, keyboard->keymap_fd, + keyboard->keymap_size); + } } static void seat_client_send_repeat_info(struct wlr_seat_client *client, struct wlr_keyboard *keyboard) { - if (!keyboard || !client->keyboard) { + if (!keyboard) { return; } - if (wl_resource_get_version(client->keyboard) >= - WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION) { - wl_keyboard_send_repeat_info(client->keyboard, - keyboard->repeat_info.rate, keyboard->repeat_info.delay); + struct wl_resource *resource; + wl_resource_for_each(resource, &client->keyboards) { + 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); + } } } @@ -131,20 +128,16 @@ static void wl_seat_get_keyboard(struct wl_client *client, if (!(seat_client->seat->capabilities & WL_SEAT_CAPABILITY_KEYBOARD)) { return; } - if (seat_client->keyboard) { - // TODO: this is probably a protocol violation but it simplifies our - // code and it'd be stupid for clients to create several keyboards for - // the same seat - wl_resource_destroy(seat_client->keyboard); - } - seat_client->keyboard = wl_resource_create(client, &wl_keyboard_interface, - wl_resource_get_version(seat_resource), id); - if (seat_client->keyboard == NULL) { + + struct wl_resource *resource = wl_resource_create(client, + &wl_keyboard_interface, wl_resource_get_version(seat_resource), id); + if (resource == NULL) { wl_resource_post_no_memory(seat_resource); return; } - wl_resource_set_implementation(seat_client->keyboard, &wl_keyboard_impl, - seat_client, &wl_keyboard_destroy); + wl_resource_set_implementation(resource, &wl_keyboard_impl, seat_client, + &wl_keyboard_destroy); + wl_list_insert(&seat_client->keyboards, wl_resource_get_link(resource)); struct wlr_keyboard *keyboard = seat_client->seat->keyboard_state.keyboard; seat_client_send_keymap(seat_client, keyboard); @@ -155,14 +148,11 @@ static void wl_seat_get_keyboard(struct wl_client *client, } static const struct wl_touch_interface wl_touch_impl = { - .release = resource_destroy + .release = resource_destroy, }; static void wl_touch_destroy(struct wl_resource *resource) { - struct wlr_seat_client *client = wl_resource_get_user_data(resource); - if (client->touch) { - client->touch = NULL; - } + wl_list_remove(wl_resource_get_link(resource)); } static void wl_seat_get_touch(struct wl_client *client, @@ -172,24 +162,20 @@ static void wl_seat_get_touch(struct wl_client *client, if (!(seat_client->seat->capabilities & WL_SEAT_CAPABILITY_TOUCH)) { return; } - if (seat_client->touch) { - // TODO: this is probably a protocol violation but it simplifies our - // code and it'd be stupid for clients to create several pointers for - // the same seat - wl_resource_destroy(seat_client->touch); - } - seat_client->touch = wl_resource_create(client, &wl_touch_interface, - wl_resource_get_version(seat_resource), id); - if (seat_client->touch == NULL) { + + struct wl_resource *resource = wl_resource_create(client, + &wl_touch_interface, wl_resource_get_version(seat_resource), id); + if (resource == NULL) { wl_resource_post_no_memory(seat_resource); return; } - wl_resource_set_implementation(seat_client->touch, &wl_touch_impl, - seat_client, &wl_touch_destroy); + wl_resource_set_implementation(resource, &wl_touch_impl, seat_client, + &wl_touch_destroy); + wl_list_insert(&seat_client->touches, wl_resource_get_link(resource)); } -static void wlr_seat_client_resource_destroy(struct wl_resource *resource) { - struct wlr_seat_client *client = wl_resource_get_user_data(resource); +static void wlr_seat_client_resource_destroy(struct wl_resource *seat_resource) { + struct wlr_seat_client *client = wl_resource_get_user_data(seat_resource); wl_signal_emit(&client->events.destroy, client); if (client == client->seat->pointer_state.focused_client) { @@ -199,15 +185,17 @@ static void wlr_seat_client_resource_destroy(struct wl_resource *resource) { client->seat->keyboard_state.focused_client = NULL; } - if (client->pointer) { - wl_resource_destroy(client->pointer); + struct wl_resource *resource, *tmp; + wl_resource_for_each_safe(resource, tmp, &client->pointers) { + wl_resource_destroy(resource); } - if (client->keyboard) { - wl_resource_destroy(client->keyboard); + wl_resource_for_each_safe(resource, tmp, &client->keyboards) { + wl_resource_destroy(resource); } - if (client->touch) { - wl_resource_destroy(client->touch); + wl_resource_for_each_safe(resource, tmp, &client->touches) { + wl_resource_destroy(resource); } + if (client->data_device) { wl_resource_destroy(client->data_device); } @@ -219,7 +207,7 @@ struct wl_seat_interface wl_seat_impl = { .get_pointer = wl_seat_get_pointer, .get_keyboard = wl_seat_get_keyboard, .get_touch = wl_seat_get_touch, - .release = resource_destroy + .release = resource_destroy, }; static void wl_seat_bind(struct wl_client *client, void *_wlr_seat, @@ -242,6 +230,9 @@ static void wl_seat_bind(struct wl_client *client, void *_wlr_seat, } seat_client->client = client; seat_client->seat = wlr_seat; + wl_list_init(&seat_client->pointers); + wl_list_init(&seat_client->keyboards); + wl_list_init(&seat_client->touches); wl_resource_set_implementation(seat_client->wl_resource, &wl_seat_impl, seat_client, wlr_seat_client_resource_destroy); wl_list_insert(&wlr_seat->clients, &seat_client->link); @@ -253,7 +244,7 @@ static void wl_seat_bind(struct wl_client *client, void *_wlr_seat, } static void default_pointer_enter(struct wlr_seat_pointer_grab *grab, - struct wlr_surface *surface, double sx, double sy) { + struct wlr_surface *surface, double sx, double sy) { wlr_seat_pointer_enter(grab->seat, surface, sx, sy); } @@ -516,7 +507,7 @@ static void pointer_resource_destroy_notify(struct wl_listener *listener, static bool wlr_seat_pointer_has_focus_resource(struct wlr_seat *wlr_seat) { return wlr_seat->pointer_state.focused_client && - wlr_seat->pointer_state.focused_client->pointer; + !wl_list_empty(&wlr_seat->pointer_state.focused_client->pointers); } void wlr_seat_pointer_enter(struct wlr_seat *wlr_seat, @@ -541,19 +532,24 @@ void wlr_seat_pointer_enter(struct wlr_seat *wlr_seat, wlr_seat->pointer_state.focused_surface; // leave the previously entered surface - if (focused_client && focused_client->pointer && focused_surface) { + if (focused_client != NULL && focused_surface != NULL) { uint32_t serial = wl_display_next_serial(wlr_seat->display); - wl_pointer_send_leave(focused_client->pointer, serial, - focused_surface->resource); - pointer_send_frame(focused_client->pointer); + struct wl_resource *resource; + wl_resource_for_each(resource, &focused_client->pointers) { + wl_pointer_send_leave(resource, serial, focused_surface->resource); + pointer_send_frame(resource); + } } // enter the current surface - if (client && client->pointer) { + if (client != NULL) { uint32_t serial = wl_display_next_serial(wlr_seat->display); - wl_pointer_send_enter(client->pointer, serial, surface->resource, - wl_fixed_from_double(sx), wl_fixed_from_double(sy)); - pointer_send_frame(client->pointer); + struct wl_resource *resource; + wl_resource_for_each(resource, &client->pointers) { + wl_pointer_send_enter(resource, serial, surface->resource, + wl_fixed_from_double(sx), wl_fixed_from_double(sy)); + pointer_send_frame(resource); + } } // reinitialize the focus destroy events @@ -588,9 +584,13 @@ void wlr_seat_pointer_send_motion(struct wlr_seat *wlr_seat, uint32_t time, return; } - wl_pointer_send_motion(wlr_seat->pointer_state.focused_client->pointer, - time, wl_fixed_from_double(sx), wl_fixed_from_double(sy)); - pointer_send_frame(wlr_seat->pointer_state.focused_client->pointer); + struct wl_resource *resource; + wl_resource_for_each(resource, + &wlr_seat->pointer_state.focused_client->pointers) { + wl_pointer_send_motion(resource, time, wl_fixed_from_double(sx), + wl_fixed_from_double(sy)); + pointer_send_frame(resource); + } } uint32_t wlr_seat_pointer_send_button(struct wlr_seat *wlr_seat, uint32_t time, @@ -600,9 +600,12 @@ 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); - wl_pointer_send_button(wlr_seat->pointer_state.focused_client->pointer, - serial, time, button, state); - pointer_send_frame(wlr_seat->pointer_state.focused_client->pointer); + struct wl_resource *resource; + wl_resource_for_each(resource, + &wlr_seat->pointer_state.focused_client->pointers) { + wl_pointer_send_button(resource, serial, time, button, state); + pointer_send_frame(resource); + } return serial; } @@ -612,18 +615,18 @@ void wlr_seat_pointer_send_axis(struct wlr_seat *wlr_seat, uint32_t time, return; } - struct wl_resource *pointer = - wlr_seat->pointer_state.focused_client->pointer; - - if (value) { - wl_pointer_send_axis(pointer, time, orientation, - wl_fixed_from_double(value)); - } else if (wl_resource_get_version(pointer) >= - WL_POINTER_AXIS_STOP_SINCE_VERSION) { - wl_pointer_send_axis_stop(pointer, time, orientation); + struct wl_resource *resource; + wl_resource_for_each(resource, + &wlr_seat->pointer_state.focused_client->pointers) { + if (value) { + wl_pointer_send_axis(resource, time, orientation, + wl_fixed_from_double(value)); + } else if (wl_resource_get_version(resource) >= + WL_POINTER_AXIS_STOP_SINCE_VERSION) { + wl_pointer_send_axis_stop(resource, time, orientation); + } + pointer_send_frame(resource); } - - pointer_send_frame(pointer); } void wlr_seat_pointer_start_grab(struct wlr_seat *wlr_seat, @@ -697,13 +700,15 @@ bool wlr_seat_pointer_has_grab(struct wlr_seat *seat) { 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 || !client->keyboard) { + if (!client) { return; } uint32_t serial = wl_display_next_serial(wlr_seat->display); - wl_keyboard_send_key(client->keyboard, serial, - time, key, state); + struct wl_resource *resource; + wl_resource_for_each(resource, &client->keyboards) { + wl_keyboard_send_key(resource, serial, time, key, state); + } } static void handle_keyboard_keymap(struct wl_listener *listener, void *data) { @@ -811,19 +816,22 @@ static void keyboard_resource_destroy_notify(struct wl_listener *listener, void wlr_seat_keyboard_send_modifiers(struct wlr_seat *seat) { struct wlr_seat_client *client = seat->keyboard_state.focused_client; - if (!client || !client->keyboard) { + if (client == NULL) { return; } struct wlr_keyboard *keyboard = seat->keyboard_state.keyboard; - if (!keyboard) { + if (keyboard == NULL) { return; } uint32_t serial = wl_display_next_serial(seat->display); - wl_keyboard_send_modifiers(client->keyboard, serial, - keyboard->modifiers.depressed, keyboard->modifiers.latched, - keyboard->modifiers.locked, keyboard->modifiers.group); + struct wl_resource *resource; + wl_resource_for_each(resource, &client->keyboards) { + wl_keyboard_send_modifiers(resource, serial, + keyboard->modifiers.depressed, keyboard->modifiers.latched, + keyboard->modifiers.locked, keyboard->modifiers.group); + } } void wlr_seat_keyboard_enter(struct wlr_seat *seat, @@ -846,29 +854,31 @@ void wlr_seat_keyboard_enter(struct wlr_seat *seat, seat->keyboard_state.focused_surface; // leave the previously entered surface - if (focused_client && focused_client->keyboard && focused_surface) { + if (focused_client != NULL && focused_surface != NULL) { uint32_t serial = wl_display_next_serial(seat->display); - wl_keyboard_send_leave(focused_client->keyboard, serial, - focused_surface->resource); + struct wl_resource *resource; + wl_resource_for_each(resource, &focused_client->keyboards) { + wl_keyboard_send_leave(resource, serial, focused_surface->resource); + } } // enter the current surface - if (client && client->keyboard && seat->keyboard_state.keyboard) { + if (client != NULL && seat->keyboard_state.keyboard != NULL) { struct wlr_keyboard *keyboard = seat->keyboard_state.keyboard; struct wl_array keys; wl_array_init(&keys); - size_t n = 0; for (size_t i = 0; i < WLR_KEYBOARD_KEYS_CAP; ++i) { if (keyboard->keycodes[i] != 0) { - wl_array_add(&keys, sizeof(uint32_t)); - ((uint32_t *)keys.data)[n] = keyboard->keycodes[i]; - n++; + uint32_t *p = wl_array_add(&keys, sizeof(uint32_t)); + *p = keyboard->keycodes[i]; } } uint32_t serial = wl_display_next_serial(seat->display); - wl_keyboard_send_enter(client->keyboard, serial, - surface->resource, &keys); + struct wl_resource *resource; + wl_resource_for_each(resource, &client->keyboards) { + wl_keyboard_send_enter(resource, serial, surface->resource, &keys); + } wl_array_release(&keys); wlr_seat_client_send_selection(client); @@ -893,7 +903,7 @@ void wlr_seat_keyboard_enter(struct wlr_seat *seat, seat->keyboard_state.focused_client = client; seat->keyboard_state.focused_surface = surface; - if (client && client->keyboard && seat->keyboard_state.keyboard) { + if (client != NULL && seat->keyboard_state.keyboard != NULL) { // tell new client about any modifier change last, // as it targets seat->keyboard_state.focused_client wlr_seat_keyboard_send_modifiers(seat); @@ -986,7 +996,7 @@ static struct wlr_touch_point *touch_point_create( struct wl_client *wl_client = wl_resource_get_client(surface->resource); struct wlr_seat_client *client = wlr_seat_client_for_wl_client(seat, wl_client); - if (!client || !client->touch) { + if (client == NULL || wl_list_empty(&client->touches)) { // touch points are not valid without a connected client with touch return NULL; } @@ -1101,7 +1111,7 @@ static void touch_point_set_focus(struct wlr_touch_point *point, wlr_seat_client_for_wl_client(point->client->seat, wl_resource_get_client(surface->resource)); - if (client && client->touch) { + if (client && !wl_list_empty(&client->touches)) { wl_signal_add(&surface->events.destroy, &point->focus_surface_destroy); point->focus_surface_destroy.notify = handle_point_focus_destroy; point->focus_surface = surface; @@ -1151,9 +1161,12 @@ uint32_t wlr_seat_touch_send_down(struct wlr_seat *seat, } uint32_t serial = wl_display_next_serial(seat->display); - wl_touch_send_down(point->client->touch, serial, time, surface->resource, - touch_id, wl_fixed_from_double(sx), wl_fixed_from_double(sy)); - wl_touch_send_frame(point->client->touch); + struct wl_resource *resource; + wl_resource_for_each(resource, &point->client->touches) { + 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); + } return serial; } @@ -1166,8 +1179,11 @@ 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); - wl_touch_send_up(point->client->touch, serial, time, touch_id); - wl_touch_send_frame(point->client->touch); + struct wl_resource *resource; + wl_resource_for_each(resource, &point->client->touches) { + wl_touch_send_up(resource, serial, time, touch_id); + wl_touch_send_frame(resource); + } } void wlr_seat_touch_send_motion(struct wlr_seat *seat, uint32_t time, int32_t touch_id, @@ -1178,9 +1194,12 @@ void wlr_seat_touch_send_motion(struct wlr_seat *seat, uint32_t time, int32_t to return; } - wl_touch_send_motion(point->client->touch, time, touch_id, - wl_fixed_from_double(sx), wl_fixed_from_double(sy)); - wl_touch_send_frame(point->client->touch); + struct wl_resource *resource; + wl_resource_for_each(resource, &point->client->touches) { + wl_touch_send_motion(resource, time, touch_id, wl_fixed_from_double(sx), + wl_fixed_from_double(sy)); + wl_touch_send_frame(resource); + } } int wlr_seat_touch_num_points(struct wlr_seat *seat) { From 8af6fbd7a0cfc663b61f084583b800abf6de40e3 Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 16 Dec 2017 14:22:59 +0100 Subject: [PATCH 2/5] Support multiple resources per seat client for data_device --- include/wlr/types/wlr_seat.h | 3 +- types/wlr_data_device.c | 137 ++++++++++++++++++++--------------- types/wlr_seat.c | 7 +- 3 files changed, 82 insertions(+), 65 deletions(-) diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h index 2084d8f7..dea9a9d0 100644 --- a/include/wlr/types/wlr_seat.h +++ b/include/wlr/types/wlr_seat.h @@ -20,8 +20,7 @@ struct wlr_seat_client { struct wl_list pointers; struct wl_list keyboards; struct wl_list touches; - - struct wl_resource *data_device; + struct wl_list data_devices; struct { struct wl_signal destroy; diff --git a/types/wlr_data_device.c b/types/wlr_data_device.c index 9a942f46..e0053399 100644 --- a/types/wlr_data_device.c +++ b/types/wlr_data_device.c @@ -231,28 +231,31 @@ static void handle_offer_source_destroyed(struct wl_listener *listener, static struct wlr_data_offer *wlr_data_source_send_offer( struct wlr_data_source *source, - struct wl_resource *target) { + struct wlr_seat_client *target) { struct wlr_data_offer *offer = calloc(1, sizeof(struct wlr_data_offer)); - if (offer == NULL) { + if (offer == NULL || wl_list_empty(&target->data_devices)) { return NULL; } - offer->resource = - wl_resource_create(wl_resource_get_client(target), - &wl_data_offer_interface, - wl_resource_get_version(target), 0); + uint32_t version = wl_resource_get_version( + wl_resource_from_link(target->data_devices.next)); + offer->resource = wl_resource_create(target->client, + &wl_data_offer_interface, version, 0); if (offer->resource == NULL) { free(offer); return NULL; } - wl_resource_set_implementation(offer->resource, &data_offer_impl, offer, data_offer_resource_destroy); offer->source_destroy.notify = handle_offer_source_destroyed; wl_signal_add(&source->events.destroy, &offer->source_destroy); - wl_data_device_send_data_offer(target, offer->resource); + struct wl_resource *target_resource; + wl_resource_for_each(target_resource, &target->data_devices) { + wl_data_device_send_data_offer(target_resource, offer->resource); + } + char **p; wl_array_for_each(p, &source->mime_types) { wl_data_offer_send_offer(offer->resource, *p); @@ -265,20 +268,20 @@ static struct wlr_data_offer *wlr_data_source_send_offer( return offer; } - void wlr_seat_client_send_selection(struct wlr_seat_client *seat_client) { - if (!seat_client->data_device) { - return; - } - if (seat_client->seat->selection_source) { - struct wlr_data_offer *offer = - wlr_data_source_send_offer(seat_client->seat->selection_source, - seat_client->data_device); - wl_data_device_send_selection(seat_client->data_device, - offer->resource); + struct wlr_data_offer *offer = wlr_data_source_send_offer( + seat_client->seat->selection_source, seat_client); + + struct wl_resource *resource; + wl_resource_for_each(resource, &seat_client->data_devices) { + wl_data_device_send_selection(resource, offer->resource); + } } else { - wl_data_device_send_selection(seat_client->data_device, NULL); + struct wl_resource *resource; + wl_resource_for_each(resource, &seat_client->data_devices) { + wl_data_device_send_selection(resource, NULL); + } } } @@ -286,12 +289,13 @@ static void seat_client_selection_data_source_destroy( struct wl_listener *listener, void *data) { struct wlr_seat *seat = wl_container_of(listener, seat, selection_data_source_destroy); + struct wlr_seat_client *seat_client = seat->keyboard_state.focused_client; - if (seat->keyboard_state.focused_client && - seat->keyboard_state.focused_surface && - seat->keyboard_state.focused_client->data_device) { - wl_data_device_send_selection( - seat->keyboard_state.focused_client->data_device, NULL); + if (seat_client && seat->keyboard_state.focused_surface) { + struct wl_resource *resource; + wl_resource_for_each(resource, &seat_client->data_devices) { + wl_data_device_send_selection(resource, NULL); + } } seat->selection_source = NULL; @@ -367,9 +371,14 @@ static void wlr_drag_set_focus(struct wlr_drag *drag, return; } - if (drag->focus_client && drag->focus_client->data_device) { + if (drag->focus_client) { wl_list_remove(&drag->seat_client_destroy.link); - wl_data_device_send_leave(drag->focus_client->data_device); + + struct wl_resource *resource; + wl_resource_for_each(resource, &drag->focus_client->data_devices) { + wl_data_device_send_leave(resource); + } + drag->focus_client = NULL; drag->focus = NULL; } @@ -395,15 +404,15 @@ static void wlr_drag_set_focus(struct wlr_drag *drag, wlr_seat_client_for_wl_client(drag->seat_client->seat, wl_resource_get_client(surface->resource)); - if (!focus_client || !focus_client->data_device) { + if (!focus_client || wl_list_empty(&focus_client->data_devices)) { return; } struct wl_resource *offer_resource = NULL; if (drag->source) { drag->source->accepted = false; - struct wlr_data_offer *offer = - wlr_data_source_send_offer(drag->source, focus_client->data_device); + struct wlr_data_offer *offer = wlr_data_source_send_offer(drag->source, + focus_client); if (offer == NULL) { return; } @@ -421,10 +430,11 @@ static void wlr_drag_set_focus(struct wlr_drag *drag, uint32_t serial = wl_display_next_serial(drag->seat_client->seat->display); - - wl_data_device_send_enter(focus_client->data_device, serial, - surface->resource, wl_fixed_from_double(sx), - wl_fixed_from_double(sy), offer_resource); + struct wl_resource *resource; + wl_resource_for_each(resource, &focus_client->data_devices) { + wl_data_device_send_enter(resource, serial, surface->resource, + wl_fixed_from_double(sx), wl_fixed_from_double(sy), offer_resource); + } drag->focus = surface; drag->focus_client = focus_client; @@ -467,9 +477,12 @@ static void pointer_drag_enter(struct wlr_seat_pointer_grab *grab, static void pointer_drag_motion(struct wlr_seat_pointer_grab *grab, uint32_t time, double sx, double sy) { struct wlr_drag *drag = grab->data; - if (drag->focus && drag->focus_client && drag->focus_client->data_device) { - wl_data_device_send_motion(drag->focus_client->data_device, time, - wl_fixed_from_double(sx), wl_fixed_from_double(sy)); + if (drag->focus != NULL&& drag->focus_client != NULL) { + struct wl_resource *resource; + wl_resource_for_each(resource, &drag->focus_client->data_devices) { + wl_data_device_send_motion(resource, time, wl_fixed_from_double(sx), + wl_fixed_from_double(sy)); + } } } @@ -480,14 +493,16 @@ static uint32_t pointer_drag_button(struct wlr_seat_pointer_grab *grab, if (drag->source && grab->seat->pointer_state.grab_button == button && state == WL_POINTER_BUTTON_STATE_RELEASED) { - if (drag->focus_client && drag->focus_client->data_device && - drag->source->current_dnd_action && + if (drag->focus_client && drag->source->current_dnd_action && drag->source->accepted) { - wl_data_device_send_drop(drag->focus_client->data_device); + struct wl_resource *resource; + wl_resource_for_each(resource, &drag->focus_client->data_devices) { + wl_data_device_send_drop(resource); + } if (wl_resource_get_version(drag->source->resource) >= WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION) { wl_data_source_send_dnd_drop_performed( - drag->source->resource); + drag->source->resource); } drag->source->offer->in_ask = @@ -538,8 +553,11 @@ static void touch_drag_up(struct wlr_seat_touch_grab *grab, uint32_t time, return; } - if (drag->focus_client && drag->focus_client->data_device) { - wl_data_device_send_drop(drag->focus_client->data_device); + if (drag->focus_client) { + struct wl_resource *resource; + wl_resource_for_each(resource, &drag->focus_client->data_devices) { + wl_data_device_send_drop(resource); + } } wlr_drag_end(drag); @@ -548,9 +566,13 @@ static void touch_drag_up(struct wlr_seat_touch_grab *grab, uint32_t time, static void touch_drag_motion(struct wlr_seat_touch_grab *grab, uint32_t time, struct wlr_touch_point *point) { struct wlr_drag *drag = grab->data; - if (drag->focus && drag->focus_client && drag->focus_client->data_device) { - wl_data_device_send_motion(drag->focus_client->data_device, time, - wl_fixed_from_double(point->sx), wl_fixed_from_double(point->sy)); + if (drag->focus && drag->focus_client) { + struct wl_resource *resource; + wl_resource_for_each(resource, &drag->focus_client->data_devices) { + wl_data_device_send_motion(resource, time, + wl_fixed_from_double(point->sx), + wl_fixed_from_double(point->sy)); + } } } @@ -800,31 +822,26 @@ static const struct wl_data_device_interface data_device_impl = { .release = data_device_release, }; +static void data_device_destroy(struct wl_resource *resource) { + wl_list_remove(wl_resource_get_link(resource)); +} + void data_device_manager_get_data_device(struct wl_client *client, struct wl_resource *manager_resource, uint32_t id, struct wl_resource *seat_resource) { struct wlr_seat_client *seat_client = wl_resource_get_user_data(seat_resource); - struct wl_resource *resource = - wl_resource_create(client, - &wl_data_device_interface, - wl_resource_get_version(manager_resource), id); + struct wl_resource *resource = wl_resource_create(client, + &wl_data_device_interface, wl_resource_get_version(manager_resource), + id); if (resource == NULL) { wl_resource_post_no_memory(manager_resource); return; } - - if (seat_client->data_device != NULL) { - // XXX this is probably a protocol violation, but it simplfies our code - // and it's stupid to create several data devices for the same seat. - wl_resource_destroy(seat_client->data_device); - } - - seat_client->data_device = resource; - - wl_resource_set_implementation(resource, &data_device_impl, - seat_client, NULL); + wl_resource_set_implementation(resource, &data_device_impl, seat_client, + &data_device_destroy); + wl_list_insert(&seat_client->data_devices, wl_resource_get_link(resource)); } static void data_source_resource_destroy(struct wl_resource *resource) { diff --git a/types/wlr_seat.c b/types/wlr_seat.c index 4f775da7..325c3ab3 100644 --- a/types/wlr_seat.c +++ b/types/wlr_seat.c @@ -195,10 +195,10 @@ static void wlr_seat_client_resource_destroy(struct wl_resource *seat_resource) wl_resource_for_each_safe(resource, tmp, &client->touches) { wl_resource_destroy(resource); } - - if (client->data_device) { - wl_resource_destroy(client->data_device); + wl_resource_for_each_safe(resource, tmp, &client->data_devices) { + wl_resource_destroy(resource); } + wl_list_remove(&client->link); free(client); } @@ -233,6 +233,7 @@ static void wl_seat_bind(struct wl_client *client, void *_wlr_seat, 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_resource_set_implementation(seat_client->wl_resource, &wl_seat_impl, seat_client, wlr_seat_client_resource_destroy); wl_list_insert(&wlr_seat->clients, &seat_client->link); From 9310d101bc81da28dbb02aac46a4c8ccb0721436 Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 16 Dec 2017 16:16:29 +0100 Subject: [PATCH 3/5] Fix potential segfault --- types/wlr_data_device.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/types/wlr_data_device.c b/types/wlr_data_device.c index e0053399..bd7665cf 100644 --- a/types/wlr_data_device.c +++ b/types/wlr_data_device.c @@ -269,9 +269,16 @@ static struct wlr_data_offer *wlr_data_source_send_offer( } void wlr_seat_client_send_selection(struct wlr_seat_client *seat_client) { + if (wl_list_empty(&seat_client->data_devices)) { + return; + } + if (seat_client->seat->selection_source) { struct wlr_data_offer *offer = wlr_data_source_send_offer( seat_client->seat->selection_source, seat_client); + if (offer == NULL) { + return; + } struct wl_resource *resource; wl_resource_for_each(resource, &seat_client->data_devices) { From 9e345f0f98804646f080acde3f576e314f2a73bb Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 16 Dec 2017 17:17:07 +0100 Subject: [PATCH 4/5] Simplify seat pointer functions --- types/wlr_data_device.c | 2 -- types/wlr_seat.c | 28 +++++++++++----------------- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/types/wlr_data_device.c b/types/wlr_data_device.c index bd7665cf..7cd9c6ba 100644 --- a/types/wlr_data_device.c +++ b/types/wlr_data_device.c @@ -728,7 +728,6 @@ static bool seat_client_start_drag(struct wlr_seat_client *client, // set in the iteration struct wlr_touch_point *point = NULL; - if (is_touch_grab) { wl_list_for_each(point, &client->seat->touch_state.touch_points, link) { is_touch_grab = point->surface && point->surface == origin; @@ -746,7 +745,6 @@ static bool seat_client_start_drag(struct wlr_seat_client *client, struct wlr_drag_icon *icon = wlr_drag_icon_create(icon_surface, client, drag->is_pointer_grab, touch_id); - if (!icon) { free(drag); return false; diff --git a/types/wlr_seat.c b/types/wlr_seat.c index 325c3ab3..2a931241 100644 --- a/types/wlr_seat.c +++ b/types/wlr_seat.c @@ -506,11 +506,6 @@ static void pointer_resource_destroy_notify(struct wl_listener *listener, wlr_seat_pointer_clear_focus(state->seat); } -static bool wlr_seat_pointer_has_focus_resource(struct wlr_seat *wlr_seat) { - return wlr_seat->pointer_state.focused_client && - !wl_list_empty(&wlr_seat->pointer_state.focused_client->pointers); -} - void wlr_seat_pointer_enter(struct wlr_seat *wlr_seat, struct wlr_surface *surface, double sx, double sy) { assert(wlr_seat); @@ -521,7 +516,6 @@ void wlr_seat_pointer_enter(struct wlr_seat *wlr_seat, } 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(wlr_seat, wl_client); @@ -543,7 +537,7 @@ void wlr_seat_pointer_enter(struct wlr_seat *wlr_seat, } // enter the current surface - if (client != NULL) { + if (client != NULL && surface != NULL) { uint32_t serial = wl_display_next_serial(wlr_seat->display); struct wl_resource *resource; wl_resource_for_each(resource, &client->pointers) { @@ -558,7 +552,7 @@ void wlr_seat_pointer_enter(struct wlr_seat *wlr_seat, wl_list_init(&wlr_seat->pointer_state.surface_destroy.link); wl_list_remove(&wlr_seat->pointer_state.resource_destroy.link); wl_list_init(&wlr_seat->pointer_state.resource_destroy.link); - if (surface) { + if (surface != NULL) { wl_signal_add(&surface->events.destroy, &wlr_seat->pointer_state.surface_destroy); wl_resource_add_destroy_listener(surface->resource, @@ -581,13 +575,13 @@ void wlr_seat_pointer_clear_focus(struct wlr_seat *wlr_seat) { void wlr_seat_pointer_send_motion(struct wlr_seat *wlr_seat, uint32_t time, double sx, double sy) { - if (!wlr_seat_pointer_has_focus_resource(wlr_seat)) { + struct wlr_seat_client *client = wlr_seat->pointer_state.focused_client; + if (client == NULL) { return; } struct wl_resource *resource; - wl_resource_for_each(resource, - &wlr_seat->pointer_state.focused_client->pointers) { + wl_resource_for_each(resource, &client->pointers) { wl_pointer_send_motion(resource, time, wl_fixed_from_double(sx), wl_fixed_from_double(sy)); pointer_send_frame(resource); @@ -596,14 +590,14 @@ void wlr_seat_pointer_send_motion(struct wlr_seat *wlr_seat, uint32_t time, uint32_t wlr_seat_pointer_send_button(struct wlr_seat *wlr_seat, uint32_t time, uint32_t button, uint32_t state) { - if (!wlr_seat_pointer_has_focus_resource(wlr_seat)) { + struct wlr_seat_client *client = wlr_seat->pointer_state.focused_client; + if (client == NULL) { return 0; } uint32_t serial = wl_display_next_serial(wlr_seat->display); struct wl_resource *resource; - wl_resource_for_each(resource, - &wlr_seat->pointer_state.focused_client->pointers) { + wl_resource_for_each(resource, &client->pointers) { wl_pointer_send_button(resource, serial, time, button, state); pointer_send_frame(resource); } @@ -612,13 +606,13 @@ uint32_t wlr_seat_pointer_send_button(struct wlr_seat *wlr_seat, uint32_t time, void wlr_seat_pointer_send_axis(struct wlr_seat *wlr_seat, uint32_t time, enum wlr_axis_orientation orientation, double value) { - if (!wlr_seat_pointer_has_focus_resource(wlr_seat)) { + struct wlr_seat_client *client = wlr_seat->pointer_state.focused_client; + if (client == NULL) { return; } struct wl_resource *resource; - wl_resource_for_each(resource, - &wlr_seat->pointer_state.focused_client->pointers) { + wl_resource_for_each(resource, &client->pointers) { if (value) { wl_pointer_send_axis(resource, time, orientation, wl_fixed_from_double(value)); From 50d91bd260efb767a35697ce016dbb415893c1a3 Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 16 Dec 2017 17:46:07 +0100 Subject: [PATCH 5/5] Fix potential memory leak --- types/wlr_data_device.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/types/wlr_data_device.c b/types/wlr_data_device.c index 7cd9c6ba..b8177137 100644 --- a/types/wlr_data_device.c +++ b/types/wlr_data_device.c @@ -232,8 +232,12 @@ static void handle_offer_source_destroyed(struct wl_listener *listener, static struct wlr_data_offer *wlr_data_source_send_offer( struct wlr_data_source *source, struct wlr_seat_client *target) { + if (wl_list_empty(&target->data_devices)) { + return NULL; + } + struct wlr_data_offer *offer = calloc(1, sizeof(struct wlr_data_offer)); - if (offer == NULL || wl_list_empty(&target->data_devices)) { + if (offer == NULL) { return NULL; }