From 9dd13980a85e12fc2bbea67b2e7d56a3cf416eb4 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Mon, 1 Aug 2022 18:38:24 +0900 Subject: [PATCH] data_device: Add clipboard functionality This patch implements ds_data_device_manager to handle wl_data_device_manager. Change-Id: If29715d88273dc1c892f15bb837080b41e9499ae --- include/libds/data_device.h | 50 +++++++- src/data_device.h | 38 +++++++ src/data_device/data_device.c | 208 ++++++++++++++++++++++++++++++++++ src/data_device/data_device.h | 6 - src/data_device/data_device_private.h | 80 +++++++++++++ src/data_device/data_offer.c | 162 ++++++++++++++++++++++++++ src/data_device/data_source.c | 39 +++++++ src/data_device/data_source_client.c | 163 ++++++++++++++++++++++++++ src/data_device/manager.c | 38 +++++-- src/data_device/meson.build | 4 + src/seat/seat.c | 6 +- 11 files changed, 771 insertions(+), 23 deletions(-) create mode 100644 src/data_device.h create mode 100644 src/data_device/data_device.c delete mode 100644 src/data_device/data_device.h create mode 100644 src/data_device/data_device_private.h create mode 100644 src/data_device/data_offer.c create mode 100644 src/data_device/data_source.c create mode 100644 src/data_device/data_source_client.c diff --git a/include/libds/data_device.h b/include/libds/data_device.h index 3513017..f4956a2 100644 --- a/include/libds/data_device.h +++ b/include/libds/data_device.h @@ -2,18 +2,66 @@ #define LIBDS_DATA_DEVICE_H #include +#include #ifdef __cplusplus extern "C" { #endif +/** + * An opaque handle for accessing ds_data_device_manager. + * This abstracts wayland data device. + */ struct ds_data_device_manager; +/** + * An object represening a wayland client's wl_source_data. + * + * The request_set_selection event introduces a new ds_data_source object. + * You may make this source being a selection of seat by calling + * ds_seat_set_selection(). This way, the source will be advertised to the + * client that has keyboard focuse of seat. + */ struct ds_data_source; -struct ds_data_deivce_manager * +/** + * An object represening a wayland client's wl_data_offer. + * + * This object will be introduced by the event request_data_offer_receive. + * You may call ds_data_offer_send() with event data to request for data + * from the source client. + */ +struct ds_data_offer; + +struct ds_event_request_set_selection +{ + struct ds_seat *seat; + struct ds_data_source *source; + uint32_t serial; +}; + +struct ds_event_request_data_offer_receive +{ + struct ds_data_offer *offer; + const char *mime_type; + int32_t fd; +}; + +struct ds_data_device_manager * ds_data_device_manager_create(struct wl_display *display); +void ds_data_device_manager_add_destroy_listener( + struct ds_data_device_manager *manager, struct wl_listener *listener); + +void ds_data_device_manager_add_request_set_selection_listener( + struct ds_data_device_manager *manager, struct wl_listener *listener); + +void ds_data_device_manager_add_request_data_offer_receive_listener( + struct ds_data_device_manager *manager, struct wl_listener *listener); + +void ds_data_offer_send(struct ds_data_offer *offer, const char *mime_type, + int32_t fd); + #ifdef __cplusplus } #endif diff --git a/src/data_device.h b/src/data_device.h new file mode 100644 index 0000000..0295fb3 --- /dev/null +++ b/src/data_device.h @@ -0,0 +1,38 @@ +#ifndef DS_DATA_DEVICE_H +#define DS_DATA_DEVICE_H + +#include + +#include "libds/data_device.h" +#include "surface.h" + +struct ds_data_source_interface { + void (*destroy)(struct ds_data_source *source); + void (*send)(struct ds_data_source *source, const char *mime_type, + int32_t fd); + void (*accept)(struct ds_data_source *source, uint32_t serial, + const char *mime_type); +}; + +struct ds_data_source +{ + const struct ds_data_source_interface *iface; + + struct wl_array mime_types; + + struct { + struct wl_signal destroy; + } events; + + bool accepted; +}; + +void ds_data_source_init(struct ds_data_source *source, + const struct ds_data_source_interface *iface); + +void ds_data_source_destroy(struct ds_data_source *source); + +void ds_data_source_send(struct ds_data_source *source, const char *mime_type, + int32_t fd); + +#endif diff --git a/src/data_device/data_device.c b/src/data_device/data_device.c new file mode 100644 index 0000000..267f662 --- /dev/null +++ b/src/data_device/data_device.c @@ -0,0 +1,208 @@ +#include + +#include "data_device_private.h" + +static const struct wl_data_device_interface data_device_iface; + +static void data_device_handle_resource_destroy(struct wl_resource *resource); +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, + void *data); +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); + +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; + + data_device = calloc(1, sizeof *data_device); + if (!data_device) + return NULL; + + data_device->resource = wl_resource_create(client, + &wl_data_device_interface, version, id); + if (!data_device->resource) { + wl_client_post_no_memory(client); + return NULL; + } + + wl_resource_set_implementation(data_device->resource, &data_device_iface, + data_device, data_device_handle_resource_destroy); + + data_device->manager = manager; + data_device->seat_client = ds_seat_client_from_resource(seat_resource); + data_device->seat = ds_seat_client_get_seat(data_device->seat_client); + + data_device->seat_client_destroy.notify = + data_device_handle_seat_client_destroy; + ds_seat_client_add_destroy_listener(data_device->seat_client, + &data_device->seat_client_destroy); + + data_device->seat_set_selection.notify = + data_device_handle_seat_set_selection; + ds_seat_add_set_selection_listener(data_device->seat, + &data_device->seat_set_selection); + + 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); + + wl_list_insert(&manager->data_devices, &data_device->link); + + return data_device; +} + +void +data_device_destroy(struct ds_data_device *data_device) +{ + wl_list_remove(&data_device->link); + + 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_resource_set_user_data(data_device->resource, NULL); + + free(data_device); +} + +static void +data_device_handle_resource_destroy(struct wl_resource *resource) +{ + struct ds_data_device *data_device; + + data_device = wl_resource_get_user_data(resource); + if (!data_device) + return; + + data_device_destroy(data_device); +} + +static void +data_device_handle_seat_client_destroy(struct wl_listener *listener, + void *data) +{ + 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; +} + +static void +data_device_handle_seat_set_selection(struct wl_listener *listener, void *data) +{ + struct ds_data_device *data_device; + + data_device = wl_container_of(listener, data_device, seat_set_selection); + data_device_update_selection(data_device); +} + +static void +data_device_handle_keyboard_focus_change(struct wl_listener *listener, + void *data) +{ + struct ds_data_device *data_device; + + data_device = wl_container_of(listener, data_device, + keyboard_focus_change); + data_device_update_selection(data_device); +} + +static void +data_device_handle_start_drag(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *source_resource, + struct wl_resource *origin_resource, struct wl_resource *icon_resource, + uint32_t serial) +{ + struct ds_data_device *data_device; + + data_device = wl_resource_get_user_data(resource); + if (!data_device) + return; + + // TODO +} + +static void +data_device_handle_set_selection(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *source_resource, + uint32_t serial) +{ + struct ds_data_device *data_device; + struct ds_data_source_client *source = NULL; + + data_device = wl_resource_get_user_data(resource); + if (!data_device || !data_device->seat_client) + return; + + if (source_resource) { + source = wl_resource_get_user_data(source_resource); + + if (source) + source->finalized = true; + } + + struct ds_event_request_set_selection event = { + .seat = data_device->seat, + .source = &source->base, + .serial = serial, + }; + wl_signal_emit(&data_device->manager->events.request_set_selection, + &event); +} + +static void +data_device_handle_release(struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static const struct wl_data_device_interface data_device_iface = { + .start_drag = data_device_handle_start_drag, + .set_selection = data_device_handle_set_selection, + .release = data_device_handle_release, +}; + +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; + + focused_client = ds_seat_keyboard_get_focused_client(data_device->seat); + if (data_device->seat_client != focused_client) + return; + + source = ds_seat_get_selection(data_device->seat); + if (source) { + offer = create_data_offer(data_device, source, + DS_DATA_OFFER_SELECTION); + if (!offer) { + wl_resource_post_no_memory(data_device->resource); + return; + } + + wl_data_device_send_selection(data_device->resource, offer->resource); + } + else { + wl_data_device_send_selection(data_device->resource, NULL); + } +} diff --git a/src/data_device/data_device.h b/src/data_device/data_device.h deleted file mode 100644 index 97c915a..0000000 --- a/src/data_device/data_device.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef DS_DATA_DEVICE_H -#define DS_DATA_DEVICE_H - - - -#endif diff --git a/src/data_device/data_device_private.h b/src/data_device/data_device_private.h new file mode 100644 index 0000000..0ea1752 --- /dev/null +++ b/src/data_device/data_device_private.h @@ -0,0 +1,80 @@ +#ifndef DS_DATA_DEVICE_PRIVATE_H +#define DS_DATA_DEVICE_PRIVATE_H + +#include + +#include "data_device.h" +#include "seat.h" + +enum ds_data_offer_type +{ + DS_DATA_OFFER_SELECTION, +}; + +struct ds_data_device_manager +{ + struct wl_global *global; + + struct wl_list data_devices; // ds_data_device.link + + struct wl_listener display_destroy; + + struct { + struct wl_signal destroy; + struct wl_signal request_set_selection; + struct wl_signal request_data_offer_receive; + } events; +}; + +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 selection_offers; // ds_data_offer.link + struct wl_list link; // ds_data_device_manager.data_devices + + struct wl_listener seat_client_destroy; + struct wl_listener seat_set_selection; + struct wl_listener keyboard_focus_change; +}; + +struct ds_data_source_client +{ + struct ds_data_source base; + struct ds_data_source_interface iface; + struct wl_resource *resource; + + bool finalized; +}; + +struct ds_data_offer +{ + struct wl_resource *resource; + struct ds_data_device *data_device; + struct ds_data_source *source; + enum ds_data_offer_type type; + + uint32_t actions; + + struct wl_list link; // ds_data_device.data_offers + + struct wl_listener source_destroy; +}; + +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); + +void data_device_destroy(struct ds_data_device *data_device); + +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, + struct ds_data_source *source, enum ds_data_offer_type type); + +#endif diff --git a/src/data_device/data_offer.c b/src/data_device/data_offer.c new file mode 100644 index 0000000..4c1395b --- /dev/null +++ b/src/data_device/data_offer.c @@ -0,0 +1,162 @@ +#include + +#include "data_device_private.h" + +static const struct wl_data_offer_interface data_offer_iface; + +static void data_offer_handle_resource_destroy(struct wl_resource *resource); +static void data_offer_handle_source_destroy(struct wl_listener *listener, + void *data); + +WL_EXPORT void +ds_data_offer_send(struct ds_data_offer *offer, const char *mime_type, + int32_t fd) +{ + ds_data_source_send(offer->source, mime_type, fd); +} + +struct ds_data_offer * +create_data_offer(struct ds_data_device *data_device, + 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); + if (!offer) + return NULL; + + offer->source = source; + offer->data_device = data_device; + offer->type = type; + + client = wl_resource_get_client(data_device->resource); + version = wl_resource_get_version(data_device->resource); + offer->resource = wl_resource_create(client, &wl_data_offer_interface, + version, 0); + if (!offer->resource) { + free(offer); + return NULL; + } + + wl_resource_set_implementation(offer->resource, &data_offer_iface, offer, + data_offer_handle_resource_destroy); + + 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_array_for_each(p, &source->mime_types) + wl_data_offer_send_offer(offer->resource, *p); + + return offer; +} + +static void +data_offer_destroy(struct ds_data_offer *offer) +{ + wl_list_remove(&offer->source_destroy.link); + + wl_resource_set_user_data(offer->resource, NULL); + + free(offer); +} + +static void +data_offer_handle_resource_destroy(struct wl_resource *resource) +{ + struct ds_data_offer *offer; + + offer = wl_resource_get_user_data(resource); + if (!offer) + return; + + data_offer_destroy(offer); +} + +static void data_offer_handle_source_destroy(struct wl_listener *listener, + void *data) +{ + struct ds_data_offer *offer; + + offer = wl_container_of(listener, offer, source_destroy); + data_offer_destroy(offer); +} + +static void +data_offer_handle_accept(struct wl_client *client, + struct wl_resource *resource, uint32_t serial, const char *mime_type) +{ + struct ds_data_offer *offer; + + offer = wl_resource_get_user_data(resource); + if (!offer) + return; + + // TODO +} + +static void +data_offer_handle_receive(struct wl_client *client, + struct wl_resource *resource, const char *mime_type, int32_t fd) +{ + struct ds_data_offer *offer; + + offer = wl_resource_get_user_data(resource); + if (!offer) + return; + + struct ds_event_request_data_offer_receive event = { + .offer = offer, + .mime_type = mime_type, + .fd = fd, + }; + wl_signal_emit( + &offer->data_device->manager->events.request_data_offer_receive, + &event); +} + +static void +data_offer_handle_destroy(struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static void +data_offer_handle_finish(struct wl_client *client, + struct wl_resource *resource) +{ + struct ds_data_offer *offer; + + offer = wl_resource_get_user_data(resource); + if (!offer) + return; + + // TODO +} + +static void +data_offer_handle_set_actions(struct wl_client *client, + struct wl_resource *resource, uint32_t actions, + uint32_t preferred_action) +{ + struct ds_data_offer *offer; + + offer = wl_resource_get_user_data(resource); + if (!offer) + return; + + // TODO +} + +static const struct wl_data_offer_interface data_offer_iface = { + .accept = data_offer_handle_accept, + .receive = data_offer_handle_receive, + .destroy = data_offer_handle_destroy, + .finish = data_offer_handle_finish, + .set_actions = data_offer_handle_set_actions, +}; diff --git a/src/data_device/data_source.c b/src/data_device/data_source.c new file mode 100644 index 0000000..5f52ad5 --- /dev/null +++ b/src/data_device/data_source.c @@ -0,0 +1,39 @@ +#include +#include + +#include "data_device_private.h" + +void +ds_data_source_init(struct ds_data_source *source, + const struct ds_data_source_interface *iface) +{ + assert(iface->send); + + source->iface = iface; + wl_array_init(&source->mime_types); + wl_signal_init(&source->events.destroy); +} + +void +ds_data_source_destroy(struct ds_data_source *source) +{ + char **p; + + wl_signal_emit(&source->events.destroy, source); + + wl_array_for_each(p, &source->mime_types) + free(*p); + wl_array_release(&source->mime_types); + + if (source->iface->destroy) + source->iface->destroy(source); + else + free(source); +} + +void +ds_data_source_send(struct ds_data_source *source, const char *mime_type, + int32_t fd) +{ + source->iface->send(source, mime_type, fd); +} diff --git a/src/data_device/data_source_client.c b/src/data_device/data_source_client.c new file mode 100644 index 0000000..11501f8 --- /dev/null +++ b/src/data_device/data_source_client.c @@ -0,0 +1,163 @@ +#include +#include + +#include "libds/log.h" +#include "data_device_private.h" + +static const struct wl_data_source_interface wl_data_source_iface; + +static void data_source_client_handle_resource_destroy( + struct wl_resource *resource); +static void data_source_client_iface_accept(struct ds_data_source *source, + uint32_t serial, const char *mime_type); +static void data_handle_client_iface_send(struct ds_data_source *source, + const char *mime_type, int32_t fd); +static void data_source_client_iface_destroy(struct ds_data_source *source); + +struct ds_data_source_client * +create_data_source_client(struct wl_client *client, uint32_t version, + uint32_t id) +{ + struct ds_data_source_client *source; + + source = calloc(1, sizeof *source); + if (!source) + return NULL; + + source->resource = wl_resource_create(client, &wl_data_source_interface, + version, id); + if (!source->resource) { + wl_client_post_no_memory(client); + free(source); + return NULL; + } + + wl_resource_set_implementation(source->resource, &wl_data_source_iface, + source, data_source_client_handle_resource_destroy); + + source->iface.accept = data_source_client_iface_accept; + source->iface.send = data_handle_client_iface_send; + source->iface.destroy = data_source_client_iface_destroy; + + ds_data_source_init(&source->base, &source->iface); + + return source; +}; + +static void +data_source_client_handle_resource_destroy(struct wl_resource *resource) +{ + struct ds_data_source_client *source; + + source = wl_resource_get_user_data(resource); + if (!source) + return; + + ds_data_source_destroy(&source->base); +} + +static void +data_source_client_handle_destroy(struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static void +data_source_client_handle_offer(struct wl_client *client, + struct wl_resource *resource, const char *mime_type) +{ + struct ds_data_source_client *source; + const char **mime_type_ptr; + char *dup_mime_type; + char **p; + + source = wl_resource_get_user_data(resource); + if (!source) + return; + + if (source->finalized) { + ds_err("Offering additional MIME type after " + "wl_data_device.set_selection"); + } + + wl_array_for_each(mime_type_ptr, &source->base.mime_types) { + if (strcmp(*mime_type_ptr, mime_type) == 0) { + ds_dbg("Ignoring duplicate MIME type offer %s", mime_type); + return; + } + } + + dup_mime_type = strdup(mime_type); + if (!dup_mime_type) { + wl_resource_post_no_memory(resource); + return; + } + + p = wl_array_add(&source->base.mime_types, sizeof *p); + if (!p) { + free(dup_mime_type); + wl_resource_post_no_memory(resource); + return; + } + + *p = dup_mime_type; +} + +static void +data_source_client_handle_set_actions(struct wl_client *client, + struct wl_resource *resource, uint32_t dnd_actions) +{ + struct ds_data_source_client *source; + + source = wl_resource_get_user_data(resource); + if (!source) + return; + + // TODO +} + +static const struct wl_data_source_interface wl_data_source_iface = { + .destroy = data_source_client_handle_destroy, + .offer = data_source_client_handle_offer, + .set_actions = data_source_client_handle_set_actions, +}; + +static struct ds_data_source_client * +data_source_client_from_data_source(struct ds_data_source *ds_source) +{ + assert(ds_source->iface->accept == data_source_client_iface_accept); + return (struct ds_data_source_client *)ds_source; +} + +static void +data_source_client_iface_accept(struct ds_data_source *ds_source, + uint32_t serial, const char *mime_type) +{ + struct ds_data_source_client *source; + + source = data_source_client_from_data_source(ds_source); + wl_data_source_send_target(source->resource, mime_type); +} + +static void +data_handle_client_iface_send(struct ds_data_source *ds_source, + const char *mime_type, int32_t fd) +{ + struct ds_data_source_client *source; + + source = data_source_client_from_data_source(ds_source); + wl_data_source_send_send(source->resource, mime_type, fd); + close(fd); +} + +static void +data_source_client_iface_destroy(struct ds_data_source *ds_source) +{ + struct ds_data_source_client *source; + + source = data_source_client_from_data_source(ds_source); + wl_data_source_send_cancelled(source->resource); + wl_resource_set_user_data(source->resource, NULL); + free(source); +} diff --git a/src/data_device/manager.c b/src/data_device/manager.c index 85b6473..ed79be3 100644 --- a/src/data_device/manager.c +++ b/src/data_device/manager.c @@ -2,20 +2,10 @@ #include #include "libds/log.h" +#include "data_device_private.h" #define DATA_DEVICE_MANAGER_VERSION 3 -struct ds_data_device_manager -{ - struct wl_global *global; - - struct wl_listener display_destroy; - - struct { - struct wl_signal destroy; - } events; -}; - static void data_device_manager_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id); @@ -34,7 +24,11 @@ ds_data_device_manager_create(struct wl_display *display) return NULL; } + wl_list_init(&manager->data_devices); + wl_signal_init(&manager->events.destroy); + wl_signal_init(&manager->events.request_set_selection); + wl_signal_init(&manager->events.request_data_offer_receive); manager->global = wl_global_create(display, &wl_data_device_manager_interface, DATA_DEVICE_MANAGER_VERSION, @@ -60,6 +54,20 @@ ds_data_device_manager_add_destroy_listener( wl_signal_add(&manager->events.destroy, listener); } +WL_EXPORT void +ds_data_device_manager_add_request_set_selection_listener( + struct ds_data_device_manager *manager, struct wl_listener *listener) +{ + wl_signal_add(&manager->events.request_set_selection, listener); +} + +WL_EXPORT void +ds_data_device_manager_add_request_data_offer_receive_listener( + struct ds_data_device_manager *manager, struct wl_listener *listener) +{ + wl_signal_add(&manager->events.request_data_offer_receive, listener); +} + static const struct wl_data_device_manager_interface data_device_manager_iface; static void @@ -97,12 +105,20 @@ static void data_device_manager_handle_create_data_source( struct wl_client *client, struct wl_resource *resource, uint32_t id) { + create_data_source_client(client, wl_resource_get_version(resource), id); } static void data_device_manager_handle_get_data_device( struct wl_client *client, struct wl_resource *resource, 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); } static const struct wl_data_device_manager_interface diff --git a/src/data_device/meson.build b/src/data_device/meson.build index da71c4c..cc438f6 100644 --- a/src/data_device/meson.build +++ b/src/data_device/meson.build @@ -1,3 +1,7 @@ libds_files += files( 'manager.c', + 'data_device.c', + 'data_source.c', + 'data_source_client.c', + 'data_offer.c', ) diff --git a/src/seat/seat.c b/src/seat/seat.c index 52a0d8d..09fbb51 100644 --- a/src/seat/seat.c +++ b/src/seat/seat.c @@ -7,6 +7,7 @@ #include #include "libds/log.h" +#include "data_device.h" #include "seat_private.h" #define SEAT_VERSION 7 @@ -186,22 +187,17 @@ ds_seat_set_selection(struct ds_seat *seat, struct ds_data_source *source, return; if (seat->selection_source) { - /* TODO wl_list_remove(&seat->selection_source_destroy.link); ds_data_source_destroy(seat->selection_source); - */ seat->selection_source = NULL; } if (source) { - /* TODO seat->selection_source_destroy.notify = seat_handle_selection_source_destroy; wl_signal_add(&source->events.destroy, &seat->selection_source_destroy); - */ - seat->selection_source = source; } -- 2.7.4