From c2a0e15dadbc0d7b4722b7f64afa8a7bb1996dff Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Fri, 12 Aug 2022 11:17:40 +0900 Subject: [PATCH] data_device: Create ds_data_device per seat_client Change-Id: Ib2c74c3f26ca7bead4d707e7b642a8e8d605be7c --- src/data_device/data_device.c | 164 ++++++++++++++++++++++++++-------- src/data_device/data_device_private.h | 17 ++-- src/data_device/data_offer.c | 15 ++-- src/data_device/manager.c | 20 ++++- 4 files changed, 160 insertions(+), 56 deletions(-) diff --git a/src/data_device/data_device.c b/src/data_device/data_device.c index b85a9bf..24f8032 100644 --- a/src/data_device/data_device.c +++ b/src/data_device/data_device.c @@ -5,7 +5,16 @@ static const struct wl_data_device_interface data_device_iface; +static struct ds_data_device * +data_device_get_or_create(struct ds_data_device_manager *manager, + struct ds_seat_client *seat_client); +static struct ds_data_device *create_data_device( + struct ds_data_device_manager *manager, + struct ds_seat_client *seat_client); +static void data_device_destroy(struct ds_data_device *data_device); static void data_device_handle_resource_destroy(struct wl_resource *resource); +static void data_device_handle_manager_destroy(struct wl_listener *listener, + void *data); static void data_device_handle_seat_client_destroy( struct wl_listener *listener, void *data); static void data_device_handle_seat_set_selection(struct wl_listener *listener, @@ -13,32 +22,77 @@ static void data_device_handle_seat_set_selection(struct wl_listener *listener, static void data_device_handle_keyboard_focus_change( struct wl_listener *listener, void *data); static void data_device_update_selection(struct ds_data_device *data_device); +static void data_device_send_selection(struct ds_data_device *data_device, + struct wl_resource *resource); -struct ds_data_device * -create_data_device(struct ds_data_device_manager *manager, +void +create_data_device_resource(struct ds_data_device_manager *manager, struct wl_client *client, uint32_t version, uint32_t id, struct wl_resource *seat_resource) { struct ds_data_device *data_device; + struct ds_seat_client *seat_client, *focused_client; + struct wl_resource *resource; - data_device = calloc(1, sizeof *data_device); - if (!data_device) - return NULL; + seat_client = ds_seat_client_from_resource(seat_resource); + data_device = data_device_get_or_create(manager, seat_client); + if (!data_device) { + ds_err("Could not create data_device"); + wl_client_post_no_memory(client); + return; + } - data_device->resource = wl_resource_create(client, - &wl_data_device_interface, version, id); - if (!data_device->resource) { + resource = wl_resource_create(client, &wl_data_device_interface, + version, id); + if (!resource) { wl_client_post_no_memory(client); - return NULL; + return; } - wl_resource_set_implementation(data_device->resource, &data_device_iface, + wl_resource_set_implementation(resource, &data_device_iface, data_device, data_device_handle_resource_destroy); + wl_list_insert(&data_device->resources, wl_resource_get_link(resource)); + + focused_client = ds_seat_keyboard_get_focused_client(data_device->seat); + if (data_device->seat_client == focused_client) + data_device_send_selection(data_device, resource); +} + +static struct ds_data_device * +data_device_get_or_create(struct ds_data_device_manager *manager, + struct ds_seat_client *seat_client) +{ + struct ds_data_device *data_device; + + data_device = data_device_for_seat_client(manager, seat_client); + if (!data_device) + data_device = create_data_device(manager, seat_client); + + return data_device; +} + +static struct ds_data_device * +create_data_device(struct ds_data_device_manager *manager, + struct ds_seat_client *seat_client) +{ + struct ds_data_device *data_device; + + data_device = calloc(1, sizeof *data_device); + if (!data_device) + return NULL; + + + wl_list_init(&data_device->resources); + wl_list_init(&data_device->selection_offers); + data_device->manager = manager; - data_device->seat_client = ds_seat_client_from_resource(seat_resource); + data_device->seat_client = seat_client; data_device->seat = ds_seat_client_get_seat(data_device->seat_client); + data_device->manager_destroy.notify = data_device_handle_manager_destroy; + wl_signal_add(&manager->events.destroy, &data_device->manager_destroy); + data_device->seat_client_destroy.notify = data_device_handle_seat_client_destroy; ds_seat_client_add_destroy_listener(data_device->seat_client, @@ -52,28 +106,35 @@ create_data_device(struct ds_data_device_manager *manager, data_device->keyboard_focus_change.notify = data_device_handle_keyboard_focus_change; ds_seat_keyboard_add_focus_change_listener(data_device->seat, - &data_device->keyboard_focus_change); - - data_device_update_selection(data_device); + &data_device->keyboard_focus_change); wl_list_insert(&manager->data_devices, &data_device->link); return data_device; } -void +static void data_device_destroy(struct ds_data_device *data_device) { - wl_list_remove(&data_device->link); + struct wl_resource *resource, *resource_tmp; + struct ds_data_offer *offer, *offer_tmp; - if (data_device->seat_client) { - wl_list_remove(&data_device->seat_client_destroy.link); - wl_list_remove(&data_device->seat_set_selection.link); - wl_list_remove(&data_device->keyboard_focus_change.link); + wl_list_for_each_safe(offer, offer_tmp, &data_device->selection_offers, + link) { + data_offer_destroy(offer); } - wl_resource_set_user_data(data_device->resource, NULL); + wl_resource_for_each_safe(resource, resource_tmp, + &data_device->resources) { + wl_list_remove(wl_resource_get_link(resource)); + wl_resource_set_user_data(resource, NULL); + } + wl_list_remove(&data_device->link); + wl_list_remove(&data_device->manager_destroy.link); + wl_list_remove(&data_device->seat_client_destroy.link); + wl_list_remove(&data_device->seat_set_selection.link); + wl_list_remove(&data_device->keyboard_focus_change.link); free(data_device); } @@ -86,6 +147,19 @@ data_device_handle_resource_destroy(struct wl_resource *resource) if (!data_device) return; + wl_list_remove(wl_resource_get_link(resource)); + if (!wl_list_empty(&data_device->resources)) + return; + + data_device_destroy(data_device); +} + +static void data_device_handle_manager_destroy(struct wl_listener *listener, + void *data) +{ + struct ds_data_device *data_device; + + data_device = wl_container_of(listener, data_device, manager_destroy); data_device_destroy(data_device); } @@ -96,13 +170,7 @@ data_device_handle_seat_client_destroy(struct wl_listener *listener, struct ds_data_device *data_device; data_device = wl_container_of(listener, data_device, seat_client_destroy); - - wl_list_remove(&data_device->seat_client_destroy.link); - wl_list_remove(&data_device->seat_set_selection.link); - wl_list_remove(&data_device->keyboard_focus_change.link); - - data_device->seat_client = NULL; - data_device->seat = NULL; + data_device_destroy(data_device); } static void @@ -137,7 +205,7 @@ data_device_handle_start_drag(struct wl_client *client, struct ds_drag *drag; data_device = wl_resource_get_user_data(resource); - if (!data_device || !data_device->seat_client) + if (!data_device) return; if (source_resource) { @@ -173,7 +241,7 @@ data_device_handle_set_selection(struct wl_client *client, struct ds_data_source_client *source = NULL; data_device = wl_resource_get_user_data(resource); - if (!data_device || !data_device->seat_client) + if (!data_device) return; if (source_resource) { @@ -208,26 +276,46 @@ static const struct wl_data_device_interface data_device_iface = { static void data_device_update_selection(struct ds_data_device *data_device) { - struct ds_seat_client *focused_client; struct ds_data_source *source; - struct ds_data_offer *offer; + struct ds_data_offer *offer, *tmp; + struct ds_seat_client *focused_client; + struct wl_resource *resource; + + source = ds_seat_get_selection(data_device->seat); + if (source) + source->accepted = false; + + wl_list_for_each_safe(offer, tmp, &data_device->selection_offers, link) + data_offer_destroy(offer); focused_client = ds_seat_keyboard_get_focused_client(data_device->seat); - if (data_device->seat_client != focused_client) - return; + if (data_device->seat_client == focused_client) { + wl_resource_for_each(resource, &data_device->resources) + data_device_send_selection(data_device, resource); + } +} + +static void +data_device_send_selection(struct ds_data_device *data_device, + struct wl_resource *device_resource) +{ + struct ds_data_source *source; + struct ds_data_offer *offer; source = ds_seat_get_selection(data_device->seat); if (source) { - offer = create_data_offer(data_device, source, + offer = create_data_offer(device_resource, source, DS_DATA_OFFER_SELECTION); if (!offer) { - wl_resource_post_no_memory(data_device->resource); + wl_resource_post_no_memory(device_resource); return; } - wl_data_device_send_selection(data_device->resource, offer->resource); + wl_list_insert(&data_device->selection_offers, &offer->link); + + wl_data_device_send_selection(device_resource, offer->resource); } else { - wl_data_device_send_selection(data_device->resource, NULL); + wl_data_device_send_selection(device_resource, NULL); } } diff --git a/src/data_device/data_device_private.h b/src/data_device/data_device_private.h index e766cd3..e86d5c7 100644 --- a/src/data_device/data_device_private.h +++ b/src/data_device/data_device_private.h @@ -34,14 +34,15 @@ struct ds_data_device_manager struct ds_data_device { - struct wl_resource *resource; struct ds_data_device_manager *manager; struct ds_seat_client *seat_client; struct ds_seat *seat; + struct wl_list resources; struct wl_list selection_offers; // ds_data_offer.link struct wl_list link; // ds_data_device_manager.data_devices + struct wl_listener manager_destroy; struct wl_listener seat_client_destroy; struct wl_listener seat_set_selection; struct wl_listener keyboard_focus_change; @@ -110,19 +111,23 @@ struct ds_drag_icon bool mapped; }; -struct ds_data_device *create_data_device( - struct ds_data_device_manager *manager, struct wl_client *client, - uint32_t version, uint32_t id, struct wl_resource *seat_resource); +struct ds_data_device * +data_device_for_seat_client(struct ds_data_device_manager *manager, + struct ds_seat_client *seat_client); -void data_device_destroy(struct ds_data_device *data_device); +void create_data_device_resource(struct ds_data_device_manager *manager, + struct wl_client *client, uint32_t version, + uint32_t id, struct wl_resource *seat_resource); struct ds_data_source_client *create_data_source_client( struct wl_client *wl_client, uint32_t version, uint32_t id); struct ds_data_offer * -create_data_offer(struct ds_data_device *data_device, +create_data_offer(struct wl_resource *device_resource, struct ds_data_source *source, enum ds_data_offer_type type); +void data_offer_destroy(struct ds_data_offer *offer); + struct ds_drag *create_drag(struct ds_seat_client *seat_client, struct ds_data_source *source, struct wl_resource *icon_resource); diff --git a/src/data_device/data_offer.c b/src/data_device/data_offer.c index 23d71c1..46b0ac4 100644 --- a/src/data_device/data_offer.c +++ b/src/data_device/data_offer.c @@ -21,12 +21,11 @@ ds_data_offer_send(struct ds_data_offer *offer, const char *mime_type, } struct ds_data_offer * -create_data_offer(struct ds_data_device *data_device, +create_data_offer(struct wl_resource *device_resource, struct ds_data_source *source, enum ds_data_offer_type type) { struct ds_data_offer *offer; struct wl_client *client; - uint32_t version; char **p; offer = calloc(1, sizeof *offer); @@ -34,13 +33,12 @@ create_data_offer(struct ds_data_device *data_device, return NULL; offer->source = source; - offer->data_device = data_device; + offer->data_device = wl_resource_get_user_data(device_resource); offer->type = type; - client = wl_resource_get_client(data_device->resource); - version = wl_resource_get_version(data_device->resource); + client = wl_resource_get_client(device_resource); offer->resource = wl_resource_create(client, &wl_data_offer_interface, - version, 0); + wl_resource_get_version(device_resource), 0); if (!offer->resource) { free(offer); return NULL; @@ -52,7 +50,7 @@ create_data_offer(struct ds_data_device *data_device, offer->source_destroy.notify = data_offer_handle_source_destroy; wl_signal_add(&source->events.destroy, &offer->source_destroy); - wl_data_device_send_data_offer(data_device->resource, offer->resource); + wl_data_device_send_data_offer(device_resource, offer->resource); wl_array_for_each(p, &source->mime_types) wl_data_offer_send_offer(offer->resource, *p); @@ -80,9 +78,10 @@ data_offer_update_action(struct ds_data_offer *offer) wl_data_offer_send_action(offer->resource, action); } -static void +void data_offer_destroy(struct ds_data_offer *offer) { + wl_list_remove(&offer->link); wl_list_remove(&offer->source_destroy.link); wl_resource_set_user_data(offer->resource, NULL); diff --git a/src/data_device/manager.c b/src/data_device/manager.c index abf6ff8..61300ce 100644 --- a/src/data_device/manager.c +++ b/src/data_device/manager.c @@ -69,6 +69,20 @@ ds_data_device_manager_add_request_data_offer_receive_listener( wl_signal_add(&manager->events.request_data_offer_receive, listener); } +struct ds_data_device * +data_device_for_seat_client(struct ds_data_device_manager *manager, + struct ds_seat_client *seat_client) +{ + struct ds_data_device *data_device; + + wl_list_for_each(data_device, &manager->data_devices, link) { + if (data_device->seat_client == seat_client) + return data_device; + } + + return NULL; +} + static const struct wl_data_device_manager_interface data_device_manager_iface; static void @@ -114,12 +128,10 @@ static void data_device_manager_handle_get_data_device( uint32_t id, struct wl_resource *seat_resource) { struct ds_data_device_manager *manager; - uint32_t version; manager = wl_resource_get_user_data(resource); - version = wl_resource_get_version(resource); - - create_data_device(manager, client, version, id, seat_resource); + create_data_device_resource(manager, client, + wl_resource_get_version(resource), id, seat_resource); } static const struct wl_data_device_manager_interface -- 2.7.4