diff --git a/clients/dnd.c b/clients/dnd.c
index 3df1202d..07b80535 100644
--- a/clients/dnd.c
+++ b/clients/dnd.c
@@ -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 void
-drag_finish(void *data, struct wl_drag *drag)
+static gboolean
+drop_io_func(GIOChannel *source, GIOCondition condition, gpointer data)
{
- fprintf(stderr, "drag finish\n");
- struct wl_array a;
- char text[] = "[drop data]";
+ struct dnd *dnd = data;
+ char buffer[256];
+ int fd;
+ unsigned int len;
+ GError *err = NULL;
- a.data = text;
- a.size = sizeof text;
+ 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);
- wl_drag_send(drag, &a);
+ g_io_channel_unref(source);
+
+ return TRUE;
}
static void
-drag_data(void *data,
- struct wl_drag *drag, struct wl_array *contents)
+drag_drop(void *data, struct wl_drag *drag)
{
- fprintf(stderr, "drag drop, data %s\n", (char *) contents->data);
+ struct dnd *dnd = data;
+ int p[2];
+ GIOChannel *channel;
+
+ if (!dnd->drag_type) {
+ fprintf(stderr, "got 'drop', but no target\n");
+ return;
+ }
+
+ 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_finish(void *data, struct wl_drag *drag, int fd)
+{
+ 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
diff --git a/clients/window.c b/clients/window.c
index 7c2579d8..24f1a70a 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -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
diff --git a/compositor.c b/compositor.c
index 09c77ca3..4f82f5be 100644
--- a/compositor.c
+++ b/compositor.c
@@ -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;
}
@@ -1131,14 +1133,6 @@ drag_cancel(struct wl_client *client, struct wl_drag *drag)
wlsc_input_device_end_grab(device, get_time());
}
-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
diff --git a/protocol.xml b/protocol.xml
index 01d8a73e..390fb232 100644
--- a/protocol.xml
+++ b/protocol.xml
@@ -115,17 +115,19 @@
-
-
-
-
-
+
+
+
+
+
@@ -167,18 +169,23 @@
-
-
+
+
-
-
-
+
+
+
+