data_device: Add clipboard functionality 71/279271/1
authorSeunghun Lee <shiin.lee@samsung.com>
Mon, 1 Aug 2022 09:38:24 +0000 (18:38 +0900)
committerTizen Window System <tizen.windowsystem@gmail.com>
Fri, 5 Aug 2022 01:14:05 +0000 (10:14 +0900)
This patch implements ds_data_device_manager to handle
wl_data_device_manager.

Change-Id: If29715d88273dc1c892f15bb837080b41e9499ae

include/libds/data_device.h
src/data_device.h [new file with mode: 0644]
src/data_device/data_device.c [new file with mode: 0644]
src/data_device/data_device.h [deleted file]
src/data_device/data_device_private.h [new file with mode: 0644]
src/data_device/data_offer.c [new file with mode: 0644]
src/data_device/data_source.c [new file with mode: 0644]
src/data_device/data_source_client.c [new file with mode: 0644]
src/data_device/manager.c
src/data_device/meson.build
src/seat/seat.c

index 3513017..f4956a2 100644 (file)
@@ -2,18 +2,66 @@
 #define LIBDS_DATA_DEVICE_H
 
 #include <wayland-server.h>
+#include <libds/surface.h>
 
 #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 (file)
index 0000000..0295fb3
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef DS_DATA_DEVICE_H
+#define DS_DATA_DEVICE_H
+
+#include <wayland-server.h>
+
+#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 (file)
index 0000000..267f662
--- /dev/null
@@ -0,0 +1,208 @@
+#include <stdlib.h>
+
+#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 (file)
index 97c915a..0000000
+++ /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 (file)
index 0000000..0ea1752
--- /dev/null
@@ -0,0 +1,80 @@
+#ifndef DS_DATA_DEVICE_PRIVATE_H
+#define DS_DATA_DEVICE_PRIVATE_H
+
+#include <wayland-server.h>
+
+#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 (file)
index 0000000..4c1395b
--- /dev/null
@@ -0,0 +1,162 @@
+#include <stdlib.h>
+
+#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 (file)
index 0000000..5f52ad5
--- /dev/null
@@ -0,0 +1,39 @@
+#include <assert.h>
+#include <stdlib.h>
+
+#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 (file)
index 0000000..11501f8
--- /dev/null
@@ -0,0 +1,163 @@
+#include <assert.h>
+#include <stdlib.h>
+
+#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);
+}
index 85b6473..ed79be3 100644 (file)
@@ -2,20 +2,10 @@
 #include <wayland-server.h>
 
 #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
index da71c4c..cc438f6 100644 (file)
@@ -1,3 +1,7 @@
 libds_files += files(
   'manager.c',
+  'data_device.c',
+  'data_source.c',
+  'data_source_client.c',
+  'data_offer.c',
 )
index 52a0d8d..09fbb51 100644 (file)
@@ -7,6 +7,7 @@
 #include <string.h>
 
 #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;
     }