Update drag protocol to use fd passing for data transfer
authorKristian Høgsberg <krh@bitplanet.net>
Sat, 28 Aug 2010 00:29:56 +0000 (20:29 -0400)
committerKristian Høgsberg <krh@bitplanet.net>
Sat, 28 Aug 2010 00:30:26 +0000 (20:30 -0400)
clients/dnd.c
clients/window.c
compositor.c
protocol.xml

index 3df1202..07b8053 100644 (file)
@@ -47,6 +47,8 @@ struct dnd {
 
        struct wl_buffer *buffer;
        int hotspot_x, hotspot_y;
+       uint32_t tag;
+       const char *drag_type;
 };
 
 struct item {
@@ -221,9 +223,20 @@ drag_pointer_focus(void *data,
                   uint32_t time, struct wl_surface *surface,
                   int32_t x, int32_t y, int32_t surface_x, int32_t surface_y)
 {
+       struct dnd *dnd = data;
+
+       /* FIXME: We need the offered types before we get the
+        * pointer_focus event so we know which one we want and can
+        * send the accept request back. */
+
        fprintf(stderr, "drag pointer focus %p\n", surface);
 
-       wl_drag_accept(drag, "text/plain");
+       if (surface) {
+               wl_drag_accept(drag, "text/plain");
+               dnd->drag_type = "text/plain";
+       } else {
+               dnd->drag_type = NULL;
+       }
 }
 
 static void
@@ -239,13 +252,14 @@ drag_motion(void *data,
            uint32_t time,
            int32_t x, int32_t y, int32_t surface_x, int32_t surface_y)
 {
-       fprintf(stderr, "drag motion %d,%d\n", surface_x, surface_y);
+       struct dnd *dnd = data;
 
        /* FIXME: Need to correlate this with the offer event.
         * Problem is, we don't know when we've seen that last offer
         * event, and we might need to look at all of them before we
         * can decide which one to go with. */
        wl_drag_accept(drag, "text/plain");
+       dnd->drag_type = "text/plain";
 }
 
 static void
@@ -256,32 +270,63 @@ drag_target(void *data,
        struct input *input;
        struct wl_input_device *device;
 
-       fprintf(stderr, "target %s\n", mime_type);
-
        input = wl_drag_get_user_data(drag);
        device = input_get_input_device(input);
        wl_input_device_attach(device, dnd->buffer,
                               dnd->hotspot_x, dnd->hotspot_y);
 }
 
+static gboolean
+drop_io_func(GIOChannel *source, GIOCondition condition, gpointer data)
+{
+       struct dnd *dnd = data;
+       char buffer[256];
+       int fd;
+       unsigned int len;
+       GError *err = NULL;
+
+       g_io_channel_read_chars(source, buffer, sizeof buffer, &len, &err);
+       fprintf(stderr, "read %d bytes: %s\n", len, buffer);
+       fd = g_io_channel_unix_get_fd(source);
+       close(fd);
+       g_source_remove(dnd->tag);
+
+       g_io_channel_unref(source);
+
+       return TRUE;
+}
+
 static void
-drag_finish(void *data, struct wl_drag *drag)
+drag_drop(void *data, struct wl_drag *drag)
 {
-       fprintf(stderr, "drag finish\n");
-       struct wl_array a;
-       char text[] = "[drop data]";
+       struct dnd *dnd = data;
+       int p[2];
+       GIOChannel *channel;
 
-       a.data = text;
-       a.size = sizeof text;
+       if (!dnd->drag_type) {
+               fprintf(stderr, "got 'drop', but no target\n");
+               return;
+       }
 
-       wl_drag_send(drag, &a);
+       fprintf(stderr, "got 'drop', sending write end of pipe\n");
+
+       pipe(p);
+       wl_drag_receive(drag, p[1]);
+       close(p[1]);
+
+       channel = g_io_channel_unix_new(p[0]);
+       dnd->tag = g_io_add_watch(channel, G_IO_IN, drop_io_func, dnd);
 }
 
 static void
-drag_data(void *data,
-         struct wl_drag *drag, struct wl_array *contents)
+drag_finish(void *data, struct wl_drag *drag, int fd)
 {
-       fprintf(stderr, "drag drop, data %s\n", (char *) contents->data);
+       char text[] = "[drop data]";
+
+       fprintf(stderr, "got 'finish', fd %d, sending message\n", fd);
+
+       write(fd, text, sizeof text);
+       close(fd);
 }
 
 static const struct wl_drag_listener drag_listener = {
@@ -290,8 +335,8 @@ static const struct wl_drag_listener drag_listener = {
        drag_offer,
        drag_motion,
        drag_target,
-       drag_finish,
-       drag_data
+       drag_drop,
+       drag_finish
 };
 
 static void
index 7c2579d..24f1a70 100644 (file)
@@ -1120,13 +1120,12 @@ drag_target(void *data,
 }
 
 static void
-drag_finish(void *data, struct wl_drag *drag)
+drag_drop(void *data, struct wl_drag *drag)
 {
 }
 
 static void
-drag_data(void *data,
-         struct wl_drag *drag, struct wl_array *contents)
+drag_finish(void *data, struct wl_drag *drag, int fd)
 {
 }
 
@@ -1136,8 +1135,8 @@ static const struct wl_drag_listener drag_listener = {
        drag_offer,
        drag_motion,
        drag_target,
-       drag_finish,
-       drag_data
+       drag_drop,
+       drag_finish
 };
 
 static void
index 09c77ca..4f82f5b 100644 (file)
@@ -823,9 +823,10 @@ wlsc_input_device_end_grab(struct wlsc_input_device *device, uint32_t time)
 
        switch (device->grab) {
        case WLSC_DEVICE_GRAB_DRAG:
+               if (drag->target)
+                       wl_client_post_event(drag->target,
+                                            &drag->base, WL_DRAG_DROP);
                wl_drag_set_pointer_focus(drag, NULL, time, 0, 0, 0, 0);
-               wl_surface_post_event(drag->source, &drag->base,
-                                     WL_DRAG_FINISH);
                wl_drag_reset(drag);
                break;
        default:
@@ -1030,6 +1031,7 @@ wl_drag_set_pointer_focus(struct wl_drag *drag,
 
 
        drag->pointer_focus = &surface->base;
+       drag->target = NULL;
 }
 
 static void
@@ -1043,12 +1045,12 @@ wl_drag_reset(struct wl_drag *drag)
        wl_array_release(&drag->types);
        wl_array_init(&drag->types);
 
-       drag->source = NULL;
-
        /* FIXME: We need to reset drag->target too, but can't right
         * now because we need it for send/drop.
         *
-        * drag->target = NULL; */
+        * drag->target = NULL;
+        * drag->source = NULL;
+        */
        drag->time = 0;
        drag->pointer_focus = NULL;
 }
@@ -1132,14 +1134,6 @@ drag_cancel(struct wl_client *client, struct wl_drag *drag)
 }
 
 static void
-drag_send(struct wl_client *client,
-         struct wl_drag *drag, struct wl_array *contents)
-{
-       wl_client_post_event(drag->target,
-                            &drag->base, WL_DRAG_DROP, contents);
-}
-
-static void
 drag_accept(struct wl_client *client,
            struct wl_drag *drag, const char *type)
 {
@@ -1181,13 +1175,21 @@ drag_accept(struct wl_client *client,
                              WL_DRAG_TARGET, drag->type);
 }
 
+static void
+drag_receive(struct wl_client *client,
+            struct wl_drag *drag, int fd)
+{
+       wl_surface_post_event(drag->source, &drag->base, WL_DRAG_FINISH, fd);
+       close(fd);
+}
+
 static const struct wl_drag_interface drag_interface = {
        drag_prepare,
        drag_offer,
        drag_activate,
        drag_cancel,
-       drag_send,
-       drag_accept
+       drag_accept,
+       drag_receive
 };
 
 static void
index 01d8a73..390fb23 100644 (file)
     <!-- Cancel the drag. -->
     <request name="cancel"/>
 
-    <!-- Send the data to the target that accepted the offer -->
-    <request name="send">
-      <arg name="contents" type="array"/>
-    </request>
-
     <!-- Called by the drag target to accept the offer of the given
          type -->
     <request name="accept">
       <arg name="type" type="string"/>
     </request>
 
+    <!-- Called by the drag target to initiate the drag finish
+         sequence.  Send the pipe fd to the compositor, which forwards
+         it to the source in the 'finish' event -->
+    <request name="receive">
+      <arg name="fd" type="fd"/>
+    </request>
+
     <!-- Sent at connect time to announce the association -->
     <event name="device">
       <arg name="device" type="object" interface="input_device"/>
       <arg name="mime_type" type="string"/>
     </event>
 
-    <!-- Sent to drag originator when the drag is finished.  It's also
-        sent in case an originator tries to activate a drag after the
-        grab was released.  If the originator didn't receive a
-        'target' event before receiving the 'finish' event, no drag
-        target was found and the originator should not send data. -->
-    <event name="finish"/>
-
-    <!-- Sent to target, contains dragged data.  Ends transaction on
-        the target side. -->
-    <event name="drop">
-      <arg name="contents" type="array"/>
+    <!-- Sent to target, to indicate that the drag is finishing.  The
+         last motion/pointer_focus event gives the location of the
+         drop.  Target must respond with the 'receive' request, which
+         sends an fd to the source for writing the drag data. -->
+    <event name="drop"/>
+
+    <!-- Sent to drag source when the drag is finished.  The final
+         mime type is that of the last target event.  If that was
+         NULL, no drag target was valid when the drag finished, fd is
+         undefined and the source should not send data.  The event is
+         also sent in case a drag source tries to activate a drag
+         after the grab was released, in which case mime_type will
+         also be NULL. -->
+    <event name="finish">
+      <arg name="fd" type="fd"/>
     </event>
+
   </interface>
 
   <interface name="surface" version="1">