data_device: Start implementing drag and drop 20/279820/1
authorSeunghun <chwila927@gmail.com>
Tue, 9 Aug 2022 10:49:54 +0000 (19:49 +0900)
committerTizen Window System <tizen.windowsystem@gmail.com>
Thu, 18 Aug 2022 07:37:50 +0000 (16:37 +0900)
This patch introduces ds_drag and ds_drag_icon to handle drag and drop
operation.

Change-Id: Icfeedc47fba42f77fa632e186379373b925d9f44

include/libds/data_device.h
src/data_device/data_device.c
src/data_device/data_device_private.h
src/data_device/drag.c [new file with mode: 0644]
src/data_device/manager.c
src/data_device/meson.build

index f4956a2..4401002 100644 (file)
@@ -33,6 +33,8 @@ struct ds_data_source;
  */
 struct ds_data_offer;
 
+struct ds_drag;
+
 struct ds_event_request_set_selection
 {
     struct ds_seat *seat;
@@ -40,6 +42,14 @@ struct ds_event_request_set_selection
     uint32_t serial;
 };
 
+struct ds_event_request_start_drag
+{
+    struct ds_seat *seat;
+    struct ds_surface *origin;
+    struct ds_drag *drag;
+    uint32_t serial;
+};
+
 struct ds_event_request_data_offer_receive
 {
     struct ds_data_offer *offer;
@@ -56,12 +66,17 @@ void ds_data_device_manager_add_destroy_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_start_drag_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);
 
+void ds_drag_destroy(struct ds_drag *drag);
+
 #ifdef __cplusplus
 }
 #endif
index 267f662..b85a9bf 100644 (file)
@@ -1,5 +1,6 @@
 #include <stdlib.h>
 
+#include "libds/log.h"
 #include "data_device_private.h"
 
 static const struct wl_data_device_interface data_device_iface;
@@ -131,12 +132,36 @@ data_device_handle_start_drag(struct wl_client *client,
         uint32_t serial)
 {
     struct ds_data_device *data_device;
+    struct ds_data_source_client *source_client = NULL;
+    struct ds_data_source *source = NULL;
+    struct ds_drag *drag;
 
     data_device = wl_resource_get_user_data(resource);
-    if (!data_device)
+    if (!data_device || !data_device->seat_client)
+        return;
+
+    if (source_resource) {
+        source_client = wl_resource_get_user_data(source_resource);
+        source = &source_client->base;
+    }
+
+    drag = create_drag(data_device->seat_client, source, icon_resource);
+    if (!drag) {
+        ds_err("Could not create ds_drag");
+        wl_resource_post_no_memory(resource);
         return;
+    }
+
+    if (source_client)
+        source_client->finalized = true;
 
-    // TODO
+    struct ds_event_request_start_drag event = {
+        .seat = data_device->seat,
+        .drag = drag,
+        .origin = ds_surface_from_resource(origin_resource),
+        .serial = serial,
+    };
+    wl_signal_emit(&data_device->manager->events.request_start_drag, &event);
 }
 
 static void
index 0ea1752..5cd1c4d 100644 (file)
@@ -22,6 +22,7 @@ struct ds_data_device_manager
     struct {
         struct wl_signal destroy;
         struct wl_signal request_set_selection;
+        struct wl_signal request_start_drag;
         struct wl_signal request_data_offer_receive;
     } events;
 };
@@ -64,6 +65,45 @@ struct ds_data_offer
     struct wl_listener source_destroy;
 };
 
+struct ds_drag_icon;
+
+struct ds_drag
+{
+    struct ds_seat_keyboard_grab keyboard_grab;
+    struct ds_seat_pointer_grab pointer_grab;
+    struct ds_seat_touch_grab touch_grab;
+
+    struct ds_seat *seat;
+    struct ds_seat_client *seat_client;
+    struct ds_seat_client *focused_client;
+
+    struct ds_drag_icon *icon;
+    struct ds_data_source *source;
+
+    struct wl_listener icon_destroy;
+    struct wl_listener source_destroy;
+
+    struct {
+        struct wl_signal destroy;
+    } events;
+};
+
+struct ds_drag_icon
+{
+    struct ds_drag *drag;
+    struct ds_surface *surface;
+
+    struct wl_listener surface_destroy;
+
+    struct {
+        struct wl_signal destroy;
+        struct wl_signal map;
+        struct wl_signal unmap;
+    } events;
+
+    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);
@@ -77,4 +117,7 @@ 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_drag *create_drag(struct ds_seat_client *seat_client,
+        struct ds_data_source *source, struct wl_resource *icon_resource);
+
 #endif
diff --git a/src/data_device/drag.c b/src/data_device/drag.c
new file mode 100644 (file)
index 0000000..d0a3402
--- /dev/null
@@ -0,0 +1,173 @@
+#include <stdlib.h>
+#include "data_device_private.h"
+
+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_icon_destroy(struct ds_drag_icon *icon);
+
+WL_EXPORT void
+ds_drag_destroy(struct ds_drag *drag)
+{
+    drag_destroy(drag);
+}
+
+struct ds_drag *
+create_drag(struct ds_seat_client *seat_client, struct ds_data_source *source,
+        struct wl_resource *icon_resource)
+{
+    struct ds_drag *drag;
+
+    drag = calloc(1, sizeof *drag);
+    if (!drag)
+        return NULL;
+
+    drag->seat = ds_seat_client_get_seat(seat_client);
+    drag->seat_client = seat_client;
+
+    // FIXME ds_seat_client_add_destroy_listener()?
+
+    if (icon_resource) {
+        drag->icon = create_drag_icon(drag, icon_resource);
+        if (!drag->icon) {
+            free(drag);
+            return NULL;
+        }
+
+        drag->icon_destroy.notify = drag_handle_icon_destroy;
+        wl_signal_add(&drag->icon->events.destroy, &drag->icon_destroy);
+    }
+
+    if (source) {
+        drag->source = source;
+
+        drag->source_destroy.notify = drag_handle_source_destroy;
+        wl_signal_add(&source->events.destroy, &drag->source_destroy);
+    }
+
+    // TODO Add grab interface
+
+    return drag;
+}
+
+static void
+drag_destroy(struct ds_drag *drag)
+{
+    wl_signal_emit(&drag->events.destroy, drag);
+
+    if (drag->source)
+        wl_list_remove(&drag->source_destroy.link);
+
+    if (drag->icon) {
+        wl_list_remove(&drag->icon_destroy.link);
+        drag_icon_destroy(drag->icon);
+    }
+
+    free(drag);
+}
+
+static void
+drag_handle_icon_destroy(struct wl_listener *listener, void *data)
+{
+    struct ds_drag *drag;
+
+    drag = wl_container_of(listener, drag, icon_destroy);
+    drag->icon = NULL;
+}
+
+static void
+drag_handle_source_destroy(struct wl_listener *listener, void *data)
+{
+    struct ds_drag *drag;
+
+    drag = wl_container_of(listener, drag, source_destroy);
+    drag_destroy(drag);
+}
+
+const struct ds_surface_role drag_icon_surface_role;
+
+static void drag_icon_handle_surface_destroy(struct wl_listener *listener,
+        void *data);
+static void drag_icon_set_mapped(struct ds_drag_icon *icon, bool mapped);
+
+static struct ds_drag_icon *
+create_drag_icon(struct ds_drag *drag, struct wl_resource *icon_resource)
+{
+    struct ds_drag_icon *icon;
+
+    icon = calloc(1, sizeof *icon);
+    if (!icon)
+        return NULL;
+
+    icon->drag = drag;
+
+    wl_signal_init(&icon->events.destroy);
+    wl_signal_init(&icon->events.map);
+    wl_signal_init(&icon->events.unmap);
+
+    icon->surface = ds_surface_from_resource(icon_resource);
+    if (!ds_surface_set_role(icon->surface, &drag_icon_surface_role, icon,
+                icon_resource, WL_DATA_DEVICE_ERROR_ROLE)) {
+        free(icon);
+        return NULL;
+    }
+
+    icon->surface_destroy.notify = drag_icon_handle_surface_destroy;
+    ds_surface_add_destroy_listener(icon->surface, &icon->surface_destroy);
+
+    if (ds_surface_has_buffer(icon->surface))
+        drag_icon_set_mapped(icon, true);
+
+    return icon;
+}
+
+static void
+drag_icon_destroy(struct ds_drag_icon *icon)
+{
+    drag_icon_set_mapped(icon, false);
+    wl_signal_emit(&icon->events.destroy, icon);
+    wl_list_remove(&icon->surface_destroy.link);
+    ds_surface_reset_role_data(icon->surface);
+    free(icon);
+}
+
+static void drag_icon_set_mapped(struct ds_drag_icon *icon, bool mapped)
+{
+    if (mapped && !icon->mapped) {
+        icon->mapped = true;
+        wl_signal_emit(&icon->events.map, icon);
+    }
+    else if (!mapped && icon->mapped) {
+        wl_signal_emit(&icon->events.unmap, icon);
+        icon->mapped = false;
+    }
+}
+
+static void
+drag_icon_surface_role_commit(struct ds_surface *surface)
+{
+    struct ds_drag_icon *icon;
+
+    icon = ds_surface_get_role_data(surface);
+    if (!icon)
+        return;
+
+    drag_icon_set_mapped(icon, ds_surface_has_buffer(surface));
+}
+
+const struct ds_surface_role drag_icon_surface_role = {
+    .name = "wl_data_device-icon",
+    .commit = drag_icon_surface_role_commit,
+};
+
+static void
+drag_icon_handle_surface_destroy(struct wl_listener *listener, void *data)
+{
+    struct ds_drag_icon *icon;
+
+    icon = wl_container_of(listener, icon, surface_destroy);
+    drag_icon_destroy(icon);
+}
index ed79be3..abf6ff8 100644 (file)
@@ -28,6 +28,7 @@ ds_data_device_manager_create(struct wl_display *display)
 
     wl_signal_init(&manager->events.destroy);
     wl_signal_init(&manager->events.request_set_selection);
+    wl_signal_init(&manager->events.request_start_drag);
     wl_signal_init(&manager->events.request_data_offer_receive);
 
     manager->global = wl_global_create(display,
index cc438f6..a508673 100644 (file)
@@ -4,4 +4,5 @@ libds_files += files(
   'data_source.c',
   'data_source_client.c',
   'data_offer.c',
+  'drag.c',
 )