data_device: Add start drag operation 26/279826/1
authorSeunghun Lee <shiin.lee@samsung.com>
Tue, 16 Aug 2022 10:11:42 +0000 (19:11 +0900)
committerTizen Window System <tizen.windowsystem@gmail.com>
Thu, 18 Aug 2022 07:37:50 +0000 (16:37 +0900)
Change-Id: I70007fd98a9e64653bb06a14e16ec5dc21b05b7c

include/libds/data_device.h
src/data_device.h
src/data_device/data_device.c
src/data_device/data_device_private.h
src/data_device/data_offer.c
src/data_device/data_source.c
src/data_device/data_source_client.c
src/data_device/drag.c
src/data_device/manager.c

index 4401002..d11f1c2 100644 (file)
@@ -57,6 +57,17 @@ struct ds_event_request_data_offer_receive
     int32_t fd;
 };
 
+struct ds_event_drag_motion {
+    struct ds_drag *drag;
+    uint32_t time;
+    double sx, sy;
+};
+
+struct ds_event_drag_drop {
+    struct ds_drag *drag;
+    uint32_t time;
+};
+
 struct ds_data_device_manager *
 ds_data_device_manager_create(struct wl_display *display);
 
@@ -77,6 +88,20 @@ void ds_data_offer_send(struct ds_data_offer *offer, const char *mime_type,
 
 void ds_drag_destroy(struct ds_drag *drag);
 
+void ds_drag_start_pointer_drag(struct ds_drag *drag, uint32_t serial);
+
+void ds_drag_add_destroy_listener(struct ds_drag *drag,
+        struct wl_listener *listener);
+
+void ds_drag_add_focus_listener(struct ds_drag *drag,
+        struct wl_listener *listener);
+
+void ds_drag_add_motion_listener(struct ds_drag *drag,
+        struct wl_listener *listener);
+
+void ds_drag_add_drop_listener(struct ds_drag *drag,
+        struct wl_listener *listener);
+
 #ifdef __cplusplus
 }
 #endif
index de09eeb..3c8827c 100644 (file)
@@ -40,6 +40,9 @@ void ds_data_source_init(struct ds_data_source *source,
 
 void ds_data_source_destroy(struct ds_data_source *source);
 
+void ds_data_source_add_destroy_listener(struct ds_data_source *source,
+        struct wl_listener *listener);
+
 void ds_data_source_send(struct ds_data_source *source, const char *mime_type,
         int32_t fd);
 
index 24f8032..ef2a89e 100644 (file)
@@ -85,6 +85,7 @@ create_data_device(struct ds_data_device_manager *manager,
 
     wl_list_init(&data_device->resources);
     wl_list_init(&data_device->selection_offers);
+    wl_list_init(&data_device->drag_offers);
 
     data_device->manager = manager;
     data_device->seat_client = seat_client;
@@ -124,6 +125,9 @@ data_device_destroy(struct ds_data_device *data_device)
         data_offer_destroy(offer);
     }
 
+    wl_list_for_each_safe(offer, offer_tmp, &data_device->drag_offers, link)
+        data_offer_destroy(offer);
+
     wl_resource_for_each_safe(resource, resource_tmp,
             &data_device->resources) {
         wl_list_remove(wl_resource_get_link(resource));
@@ -213,7 +217,7 @@ data_device_handle_start_drag(struct wl_client *client,
         source = &source_client->base;
     }
 
-    drag = create_drag(data_device->seat_client, source, icon_resource);
+    drag = create_drag(data_device, source, icon_resource);
     if (!drag) {
         ds_err("Could not create ds_drag");
         wl_resource_post_no_memory(resource);
@@ -311,8 +315,6 @@ data_device_send_selection(struct ds_data_device *data_device,
             return;
         }
 
-        wl_list_insert(&data_device->selection_offers, &offer->link);
-
         wl_data_device_send_selection(device_resource, offer->resource);
     }
     else {
index e86d5c7..26b0b91 100644 (file)
@@ -16,9 +16,17 @@ enum ds_data_offer_type
     DS_DATA_OFFER_DRAG,
 };
 
+enum ds_drag_grab_type
+{
+    DS_DRAG_GRAB_KEYBOARD,
+    DS_DRAG_GRAB_KEYBOARD_POINTER,
+    DS_DRAG_GRAB_KEYBOARD_TOUCH,
+};
+
 struct ds_data_device_manager
 {
     struct wl_global *global;
+    struct wl_display *display;
 
     struct wl_list data_devices; // ds_data_device.link
 
@@ -40,6 +48,7 @@ struct ds_data_device
 
     struct wl_list resources;
     struct wl_list selection_offers; // ds_data_offer.link
+    struct wl_list drag_offers; // ds_data_offer.link
     struct wl_list link; // ds_data_device_manager.data_devices
 
     struct wl_listener manager_destroy;
@@ -80,19 +89,29 @@ struct ds_drag
     struct ds_seat_pointer_grab pointer_grab;
     struct ds_seat_touch_grab touch_grab;
 
+    struct ds_data_device *data_device;
     struct ds_seat *seat;
     struct ds_seat_client *seat_client;
     struct ds_seat_client *focused_client;
 
     struct ds_drag_icon *icon;
+    struct ds_surface *focused_surface;
     struct ds_data_source *source;
 
+    enum ds_drag_grab_type grab_type;
+
     struct wl_listener icon_destroy;
     struct wl_listener source_destroy;
+    struct wl_listener seat_client_destroy;
 
     struct {
         struct wl_signal destroy;
+        struct wl_signal focus;
+        struct wl_signal motion;
+        struct wl_signal drop;
     } events;
+
+    bool started, dropped, cancelling;
 };
 
 struct ds_drag_icon
@@ -128,7 +147,9 @@ create_data_offer(struct wl_resource *device_resource,
 
 void data_offer_destroy(struct ds_data_offer *offer);
 
-struct ds_drag *create_drag(struct ds_seat_client *seat_client,
+void data_offer_update_action(struct ds_data_offer *offer);
+
+struct ds_drag *create_drag(struct ds_data_device *data_device,
         struct ds_data_source *source, struct wl_resource *icon_resource);
 
 #endif
index 46b0ac4..955fd0e 100644 (file)
@@ -25,15 +25,18 @@ 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 ds_data_device *data_device;
     struct wl_client *client;
     char **p;
 
+    data_device = wl_resource_get_user_data(device_resource);
+
     offer = calloc(1, sizeof *offer);
     if (!offer)
         return NULL;
 
     offer->source = source;
-    offer->data_device = wl_resource_get_user_data(device_resource);
+    offer->data_device = data_device;
     offer->type = type;
 
     client = wl_resource_get_client(device_resource);
@@ -47,6 +50,18 @@ create_data_offer(struct wl_resource *device_resource,
     wl_resource_set_implementation(offer->resource, &data_offer_iface, offer,
             data_offer_handle_resource_destroy);
 
+    switch (type) {
+        case DS_DATA_OFFER_SELECTION:
+            wl_list_insert(&data_device->selection_offers, &offer->link);
+            break;
+        case DS_DATA_OFFER_DRAG:
+            wl_list_insert(&data_device->drag_offers, &offer->link);
+            break;
+        default:
+            assert(0 && "cannot reach here");
+            break;
+    }
+
     offer->source_destroy.notify = data_offer_handle_source_destroy;
     wl_signal_add(&source->events.destroy, &offer->source_destroy);
 
@@ -230,6 +245,8 @@ data_offer_handle_set_actions(struct wl_client *client,
 
     offer->actions = actions;
     offer->preferred_action = preferred_action;
+
+    data_offer_update_action(offer);
 }
 
 static const struct wl_data_offer_interface data_offer_iface = {
@@ -261,6 +278,7 @@ data_offer_choose_action(struct ds_data_offer *offer)
         source_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
 
     available_actions = offer_actions & source_actions;
+
     if (!available_actions)
         return WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
 
index 198d0c0..afecbbc 100644 (file)
@@ -10,6 +10,7 @@ ds_data_source_init(struct ds_data_source *source,
     assert(iface->send);
 
     source->iface = iface;
+    source->actions = -1;
     wl_array_init(&source->mime_types);
     wl_signal_init(&source->events.destroy);
 }
@@ -32,6 +33,13 @@ ds_data_source_destroy(struct ds_data_source *source)
 }
 
 void
+ds_data_source_add_destroy_listener(struct ds_data_source *source,
+        struct wl_listener *listener)
+{
+    wl_signal_add(&source->events.destroy, listener);
+}
+
+void
 ds_data_source_send(struct ds_data_source *source, const char *mime_type,
         int32_t fd)
 {
index 3fa1225..60aafeb 100644 (file)
@@ -236,5 +236,5 @@ data_source_client_iface_dnd_action(struct ds_data_source *ds_source,
     source = data_source_client_from_data_source(ds_source);
     assert(wl_resource_get_version(source->resource) >=
             WL_DATA_SOURCE_ACTION_SINCE_VERSION);
-    wl_data_source_send_dnd_finished(source->resource);
+    wl_data_source_send_action(source->resource, action);
 }
index d0a3402..9baf351 100644 (file)
@@ -1,12 +1,22 @@
+#include <assert.h>
 #include <stdlib.h>
 #include "data_device_private.h"
 
+static const struct ds_pointer_grab_interface drag_pointer_grab_iface;
+static const struct ds_keyboard_grab_interface drag_keyboard_grab_iface;
+
 static void drag_destroy(struct ds_drag *drag);
 static struct ds_drag_icon *create_drag_icon(struct ds_drag *drag,
         struct wl_resource *icon_resource);
 static void drag_handle_icon_destroy(struct wl_listener *listener, void *data);
 static void drag_handle_source_destroy(struct wl_listener *listener,
         void *data);
+static void drag_handle_seat_client_destroy(struct wl_listener *listener,
+        void *data);
+static void drag_start(struct ds_drag *drag, uint32_t serial);
+static void drag_set_focus(struct ds_drag *drag, struct ds_surface *surface,
+        double sx, double sy);
+static void drag_drop(struct ds_drag *drag, uint32_t time);
 static void drag_icon_destroy(struct ds_drag_icon *icon);
 
 WL_EXPORT void
@@ -15,8 +25,58 @@ ds_drag_destroy(struct ds_drag *drag)
     drag_destroy(drag);
 }
 
+WL_EXPORT void
+ds_drag_start_pointer_drag(struct ds_drag *drag, uint32_t serial)
+{
+    drag->grab_type = DS_DRAG_GRAB_KEYBOARD_POINTER;
+
+    ds_seat_pointer_clear_focus(drag->seat);
+    ds_seat_pointer_start_grab(drag->seat, &drag->pointer_grab);
+
+    drag_start(drag, serial);
+}
+
+WL_EXPORT void
+ds_drag_start_touch_drag(struct ds_drag *drag, uint32_t serial)
+{
+    drag->grab_type = DS_DRAG_GRAB_KEYBOARD_TOUCH;
+
+    // TODO
+}
+
+WL_EXPORT void
+ds_drag_add_destroy_listener(struct ds_drag *drag,
+        struct wl_listener *listener)
+{
+    wl_signal_add(&drag->events.destroy, listener);
+}
+
+WL_EXPORT void
+ds_drag_add_focus_listener(struct ds_drag *drag, struct wl_listener *listener)
+{
+    wl_signal_add(&drag->events.focus, listener);
+}
+
+WL_EXPORT void
+ds_drag_add_motion_listener(struct ds_drag *drag, struct wl_listener *listener)
+{
+    wl_signal_add(&drag->events.motion, listener);
+}
+
+WL_EXPORT void
+ds_drag_add_drop_listener(struct ds_drag *drag, struct wl_listener *listener)
+{
+    wl_signal_add(&drag->events.drop, listener);
+}
+
+struct ds_data_source *
+ds_drag_get_source(struct ds_drag *drag)
+{
+    return drag->source;
+}
+
 struct ds_drag *
-create_drag(struct ds_seat_client *seat_client, struct ds_data_source *source,
+create_drag(struct ds_data_device *data_device, struct ds_data_source *source,
         struct wl_resource *icon_resource)
 {
     struct ds_drag *drag;
@@ -25,8 +85,14 @@ create_drag(struct ds_seat_client *seat_client, struct ds_data_source *source,
     if (!drag)
         return NULL;
 
-    drag->seat = ds_seat_client_get_seat(seat_client);
-    drag->seat_client = seat_client;
+    wl_signal_init(&drag->events.destroy);
+    wl_signal_init(&drag->events.focus);
+    wl_signal_init(&drag->events.motion);
+    wl_signal_init(&drag->events.drop);
+
+    drag->data_device = data_device;
+    drag->seat_client = data_device->seat_client;
+    drag->seat = ds_seat_client_get_seat(drag->seat_client);
 
     // FIXME ds_seat_client_add_destroy_listener()?
 
@@ -48,7 +114,13 @@ create_drag(struct ds_seat_client *seat_client, struct ds_data_source *source,
         wl_signal_add(&source->events.destroy, &drag->source_destroy);
     }
 
-    // TODO Add grab interface
+    drag->pointer_grab.data = drag;
+    drag->pointer_grab.iface = &drag_pointer_grab_iface;
+
+    drag->keyboard_grab.data = drag;
+    drag->keyboard_grab.iface = &drag_keyboard_grab_iface;
+
+    // TODO Add touch grab
 
     return drag;
 }
@@ -56,8 +128,31 @@ create_drag(struct ds_seat_client *seat_client, struct ds_data_source *source,
 static void
 drag_destroy(struct ds_drag *drag)
 {
+    if (drag->cancelling)
+        return;
+
+    drag->cancelling = true;
+
+    if (drag->started) {
+        ds_seat_keyboard_end_grab(drag->seat);
+        switch (drag->grab_type) {
+            case DS_DRAG_GRAB_KEYBOARD_POINTER:
+                ds_seat_pointer_end_grab(drag->seat);
+                break;
+            case DS_DRAG_GRAB_KEYBOARD_TOUCH:
+                // TODO
+                break;
+            default:
+            case DS_DRAG_GRAB_KEYBOARD:
+                break;
+        }
+    }
+
     wl_signal_emit(&drag->events.destroy, drag);
 
+    if (drag->started)
+        drag_set_focus(drag, NULL, 0, 0);
+
     if (drag->source)
         wl_list_remove(&drag->source_destroy.link);
 
@@ -171,3 +266,298 @@ drag_icon_handle_surface_destroy(struct wl_listener *listener, void *data)
     icon = wl_container_of(listener, icon, surface_destroy);
     drag_icon_destroy(icon);
 }
+
+static void
+drag_pointer_grab_iface_enter(struct ds_seat_pointer_grab *grab,
+        struct ds_surface *surface, double sx, double sy)
+{
+    struct ds_drag *drag = grab->data;
+    drag_set_focus(drag, surface, sx, sy);
+}
+
+static void
+drag_pointer_grab_iface_clear_focus(struct ds_seat_pointer_grab *grab)
+{
+    struct ds_drag *drag = grab->data;
+    drag_set_focus(drag, NULL, 0, 0);
+}
+
+static void
+drag_pointer_grab_iface_motion(struct ds_seat_pointer_grab *grab,
+        uint32_t time, double sx, double sy)
+{
+    struct ds_drag *drag = grab->data;
+    struct ds_data_device *data_device;
+    struct wl_resource *resource;
+
+    if (!drag->focused_surface || !drag->focused_client)
+        return;
+
+    data_device = data_device_for_seat_client(drag->data_device->manager,
+            drag->focused_client);
+    if (data_device) {
+        wl_resource_for_each(resource, &data_device->resources) {
+            wl_data_device_send_motion(resource, time,
+                    wl_fixed_from_double(sx), wl_fixed_from_double(sy));
+        }
+    }
+
+    struct ds_event_drag_motion event = {
+        .drag = drag,
+        .time = time,
+        .sx = sx,
+        .sy = sy,
+    };
+    wl_signal_emit(&drag->events.motion, &event);
+}
+
+static uint32_t
+drag_pointer_grab_iface_button(struct ds_seat_pointer_grab *grab,
+        uint32_t time, uint32_t button, uint32_t state)
+{
+    struct ds_drag *drag = grab->data;
+    uint32_t grab_button;
+    size_t grab_button_count;
+
+    grab_button = ds_seat_pointer_get_grab_button(grab->seat);
+    if (drag->source && grab_button == button &&
+            state == WL_POINTER_BUTTON_STATE_RELEASED) {
+        if (drag->focused_client && drag->source->current_dnd_action &&
+                drag->source->accepted) {
+            drag_drop(drag, time);
+        }
+        else if (drag->source->iface->dnd_finish) {
+            ds_data_source_destroy(drag->source);
+            return 0;
+        }
+    }
+
+    grab_button_count = ds_seat_pointer_get_grab_button(drag->seat);
+    if (grab_button_count == 0 &&
+            state == WL_POINTER_BUTTON_STATE_RELEASED) {
+        drag_destroy(drag);
+    }
+
+    return 0;
+}
+
+static void
+drag_pointer_grab_iface_axis(struct ds_seat_pointer_grab *grab,
+        uint32_t time, enum ds_axis_orientation orientation, double value,
+        int32_t value_discrete, enum ds_axis_source source)
+{
+    // This space is intentionally left blank
+}
+
+static void
+drag_pointer_grab_iface_cancel(struct ds_seat_pointer_grab *grab)
+{
+    struct ds_drag *drag = grab->data;
+
+    drag_destroy(drag);
+}
+
+static const struct ds_pointer_grab_interface drag_pointer_grab_iface = {
+    .enter = drag_pointer_grab_iface_enter,
+    .clear_focus = drag_pointer_grab_iface_clear_focus,
+    .motion = drag_pointer_grab_iface_motion,
+    .button = drag_pointer_grab_iface_button,
+    .axis = drag_pointer_grab_iface_axis,
+    .cancel = drag_pointer_grab_iface_cancel,
+};
+
+static void
+drag_keyboard_grab_iface_enter(struct ds_seat_keyboard_grab *grab,
+        struct ds_surface *surface, uint32_t keycodes[], size_t num_keycodes,
+        struct ds_keyboard_modifiers *modifiers)
+{
+    // nothing has keyboard focus during drags
+}
+
+static void
+drag_keyboard_grab_iface_clear_focus(struct ds_seat_keyboard_grab *grab)
+{
+    // nothing has keyboard focus during drags
+}
+
+static void
+drag_keyboard_grab_iface_key(struct ds_seat_keyboard_grab *grab,
+        uint32_t time, uint32_t key, uint32_t state)
+{
+    // no keyboard input during drags
+}
+
+static void
+drag_keyboard_grab_iface_modifiers(struct ds_seat_keyboard_grab *grab,
+        struct ds_keyboard_modifiers *modifiers)
+{
+    // TODO change the dnd action based on what modifier is passed on the
+    // keyboard
+}
+
+static void
+drag_keyboard_grab_iface_cancel(struct ds_seat_keyboard_grab *grab)
+{
+    struct ds_drag *drag = grab->data;
+
+    drag_destroy(drag);
+}
+
+static const struct ds_keyboard_grab_interface drag_keyboard_grab_iface = {
+    .enter = drag_keyboard_grab_iface_enter,
+    .clear_focus = drag_keyboard_grab_iface_clear_focus,
+    .key = drag_keyboard_grab_iface_key,
+    .modifiers = drag_keyboard_grab_iface_modifiers,
+    .cancel = drag_keyboard_grab_iface_cancel,
+};
+
+static void
+drag_start(struct ds_drag *drag, uint32_t serial)
+{
+    assert(!drag->started);
+    drag->started = true;
+
+    ds_seat_keyboard_start_grab(drag->seat, &drag->keyboard_grab);
+
+    ds_seat_start_drag(drag->seat, drag->source, serial);
+}
+
+static void
+drag_set_focus(struct ds_drag *drag, struct ds_surface *surface,
+        double sx, double sy)
+{
+    struct ds_seat_client *focused_client;
+    struct ds_data_device *data_device;
+    struct wl_resource *device_resource, *surface_resource;
+    struct ds_data_offer *offer, *tmp;
+    uint32_t serial;
+
+    if (drag->focused_surface == surface)
+        return;
+
+    if (drag->focused_client) {
+        wl_list_remove(&drag->seat_client_destroy.link);
+
+        wl_list_for_each(data_device,
+                &drag->data_device->manager->data_devices, link) {
+            if (data_device->seat !=
+                    ds_seat_client_get_seat(drag->focused_client))
+                continue;
+
+            wl_list_for_each_safe(offer, tmp,
+                    &data_device->drag_offers, link) {
+                if (!drag->dropped &&
+                        offer->source == drag->source &&
+                        (wl_resource_get_client(offer->resource) ==
+                         ds_seat_client_get_wl_client(drag->focused_client))) {
+                    offer->source = NULL;
+                    data_offer_destroy(offer);
+                }
+            }
+        }
+
+        data_device = data_device_for_seat_client(drag->data_device->manager,
+                drag->focused_client);
+        if (data_device) {
+            wl_resource_for_each(device_resource, &data_device->resources)
+                wl_data_device_send_leave(device_resource);
+        }
+
+        drag->focused_client = NULL;
+        drag->focused_surface = NULL;
+    }
+
+    if (!surface)
+        goto out;
+
+    surface_resource = ds_surface_get_wl_resource(surface);
+
+    focused_client = ds_seat_client_for_wl_client(drag->seat,
+            wl_resource_get_client(surface_resource));
+    if (!focused_client)
+        goto out;
+
+    if (!drag->source) {
+        if (wl_resource_get_client(surface_resource) !=
+                ds_seat_client_get_wl_client(drag->seat_client))
+            goto out;
+    }
+    else {
+        drag->source->accepted = false;
+
+        data_device = data_device_for_seat_client(drag->data_device->manager,
+                focused_client);
+        if (data_device) {
+            wl_resource_for_each(device_resource, &data_device->resources) {
+                offer = create_data_offer(device_resource, drag->source,
+                        DS_DATA_OFFER_DRAG);
+                if (!offer) {
+                    wl_resource_post_no_memory(device_resource);
+                    return;
+                }
+
+                data_offer_update_action(offer);
+
+                if (wl_resource_get_version(offer->resource) >=
+                        WL_DATA_OFFER_SOURCE_ACTIONS_SINCE_VERSION) {
+                    wl_data_offer_send_source_actions(offer->resource,
+                            drag->source->actions);
+                }
+
+                serial = wl_display_next_serial(
+                        drag->data_device->manager->display);
+                wl_data_device_send_enter(device_resource, serial,
+                        surface_resource,
+                        wl_fixed_from_double(sx), wl_fixed_from_double(sy),
+                        offer->resource);
+            }
+        }
+    }
+
+    drag->focused_surface = surface;
+    drag->focused_client = focused_client;
+    drag->seat_client_destroy.notify = drag_handle_seat_client_destroy;
+    ds_seat_client_add_destroy_listener(focused_client,
+            &drag->seat_client_destroy);
+
+out:
+    wl_signal_emit(&drag->events.focus, drag);
+}
+
+static void
+drag_drop(struct ds_drag *drag, uint32_t time)
+{
+    struct ds_data_device *data_device;
+    struct wl_resource *resource;
+
+    assert(drag->focused_client);
+
+    drag->dropped = true;
+
+    data_device = data_device_for_seat_client(drag->data_device->manager,
+            drag->focused_client);
+    if (data_device) {
+        wl_resource_for_each(resource, &data_device->resources)
+            wl_data_device_send_drop(resource);
+    }
+
+    if (drag->source)
+        ds_data_source_dnd_drop(drag->source);
+
+    struct ds_event_drag_drop event = {
+        .drag = drag,
+        .time = time,
+    };
+    wl_signal_emit(&drag->events.drop, &event);
+}
+
+static void
+drag_handle_seat_client_destroy(struct wl_listener *listener, void *data)
+{
+    struct ds_drag *drag;
+
+    drag = wl_container_of(listener, drag, seat_client_destroy);
+
+    drag->focused_client = NULL;
+    wl_list_remove(&drag->seat_client_destroy.link);
+}
index 61300ce..79ccc7f 100644 (file)
@@ -24,6 +24,8 @@ ds_data_device_manager_create(struct wl_display *display)
         return NULL;
     }
 
+    manager->display = display;
+
     wl_list_init(&manager->data_devices);
 
     wl_signal_init(&manager->events.destroy);
@@ -63,6 +65,13 @@ ds_data_device_manager_add_request_set_selection_listener(
 }
 
 WL_EXPORT void
+ds_data_device_manager_add_request_start_drag_listener(
+        struct ds_data_device_manager *manager, struct wl_listener *listener)
+{
+    wl_signal_add(&manager->events.request_start_drag, listener);
+}
+
+WL_EXPORT void
 ds_data_device_manager_add_request_data_offer_receive_listener(
         struct ds_data_device_manager *manager, struct wl_listener *listener)
 {