struct wl_buffer *buffer;
int hotspot_x, hotspot_y;
+ uint32_t tag;
+ const char *drag_type;
};
struct item {
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
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
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 = {
drag_offer,
drag_motion,
drag_target,
- drag_finish,
- drag_data
+ drag_drop,
+ drag_finish
};
static void
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:
drag->pointer_focus = &surface->base;
+ drag->target = NULL;
}
static void
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;
}
}
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)
{
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
<!-- 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">