Update drag protocol to use fd passing for data transfer

dev
Kristian Høgsberg 14 years ago
parent aebeee0bbf
commit 4eb536091a
  1. 75
      clients/dnd.c
  2. 9
      clients/window.c
  3. 32
      compositor.c
  4. 39
      protocol.xml

@ -47,6 +47,8 @@ struct dnd {
struct wl_buffer *buffer; struct wl_buffer *buffer;
int hotspot_x, hotspot_y; int hotspot_x, hotspot_y;
uint32_t tag;
const char *drag_type;
}; };
struct item { struct item {
@ -221,9 +223,20 @@ drag_pointer_focus(void *data,
uint32_t time, struct wl_surface *surface, uint32_t time, struct wl_surface *surface,
int32_t x, int32_t y, int32_t surface_x, int32_t surface_y) 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); fprintf(stderr, "drag pointer focus %p\n", surface);
if (surface) {
wl_drag_accept(drag, "text/plain"); wl_drag_accept(drag, "text/plain");
dnd->drag_type = "text/plain";
} else {
dnd->drag_type = NULL;
}
} }
static void static void
@ -239,13 +252,14 @@ drag_motion(void *data,
uint32_t time, uint32_t time,
int32_t x, int32_t y, int32_t surface_x, int32_t surface_y) 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. /* FIXME: Need to correlate this with the offer event.
* Problem is, we don't know when we've seen that last offer * 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 * event, and we might need to look at all of them before we
* can decide which one to go with. */ * can decide which one to go with. */
wl_drag_accept(drag, "text/plain"); wl_drag_accept(drag, "text/plain");
dnd->drag_type = "text/plain";
} }
static void static void
@ -256,32 +270,63 @@ drag_target(void *data,
struct input *input; struct input *input;
struct wl_input_device *device; struct wl_input_device *device;
fprintf(stderr, "target %s\n", mime_type);
input = wl_drag_get_user_data(drag); input = wl_drag_get_user_data(drag);
device = input_get_input_device(input); device = input_get_input_device(input);
wl_input_device_attach(device, dnd->buffer, wl_input_device_attach(device, dnd->buffer,
dnd->hotspot_x, dnd->hotspot_y); 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 static void
drag_finish(void *data, struct wl_drag *drag) drag_drop(void *data, struct wl_drag *drag)
{ {
fprintf(stderr, "drag finish\n"); struct dnd *dnd = data;
struct wl_array a; int p[2];
char text[] = "[drop data]"; 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");
a.data = text; pipe(p);
a.size = sizeof text; wl_drag_receive(drag, p[1]);
close(p[1]);
wl_drag_send(drag, &a); channel = g_io_channel_unix_new(p[0]);
dnd->tag = g_io_add_watch(channel, G_IO_IN, drop_io_func, dnd);
} }
static void static void
drag_data(void *data, drag_finish(void *data, struct wl_drag *drag, int fd)
struct wl_drag *drag, struct wl_array *contents)
{ {
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 = { static const struct wl_drag_listener drag_listener = {
@ -290,8 +335,8 @@ static const struct wl_drag_listener drag_listener = {
drag_offer, drag_offer,
drag_motion, drag_motion,
drag_target, drag_target,
drag_finish, drag_drop,
drag_data drag_finish
}; };
static void static void

@ -1120,13 +1120,12 @@ drag_target(void *data,
} }
static void static void
drag_finish(void *data, struct wl_drag *drag) drag_drop(void *data, struct wl_drag *drag)
{ {
} }
static void static void
drag_data(void *data, drag_finish(void *data, struct wl_drag *drag, int fd)
struct wl_drag *drag, struct wl_array *contents)
{ {
} }
@ -1136,8 +1135,8 @@ static const struct wl_drag_listener drag_listener = {
drag_offer, drag_offer,
drag_motion, drag_motion,
drag_target, drag_target,
drag_finish, drag_drop,
drag_data drag_finish
}; };
static void static void

@ -823,9 +823,10 @@ wlsc_input_device_end_grab(struct wlsc_input_device *device, uint32_t time)
switch (device->grab) { switch (device->grab) {
case WLSC_DEVICE_GRAB_DRAG: 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_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); wl_drag_reset(drag);
break; break;
default: default:
@ -1030,6 +1031,7 @@ wl_drag_set_pointer_focus(struct wl_drag *drag,
drag->pointer_focus = &surface->base; drag->pointer_focus = &surface->base;
drag->target = NULL;
} }
static void static void
@ -1043,12 +1045,12 @@ wl_drag_reset(struct wl_drag *drag)
wl_array_release(&drag->types); wl_array_release(&drag->types);
wl_array_init(&drag->types); wl_array_init(&drag->types);
drag->source = NULL;
/* FIXME: We need to reset drag->target too, but can't right /* FIXME: We need to reset drag->target too, but can't right
* now because we need it for send/drop. * now because we need it for send/drop.
* *
* drag->target = NULL; */ * drag->target = NULL;
* drag->source = NULL;
*/
drag->time = 0; drag->time = 0;
drag->pointer_focus = NULL; 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()); 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 static void
drag_accept(struct wl_client *client, drag_accept(struct wl_client *client,
struct wl_drag *drag, const char *type) struct wl_drag *drag, const char *type)
@ -1181,13 +1175,21 @@ drag_accept(struct wl_client *client,
WL_DRAG_TARGET, drag->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 = { static const struct wl_drag_interface drag_interface = {
drag_prepare, drag_prepare,
drag_offer, drag_offer,
drag_activate, drag_activate,
drag_cancel, drag_cancel,
drag_send, drag_accept,
drag_accept drag_receive
}; };
static void static void

@ -115,17 +115,19 @@
<!-- Cancel the drag. --> <!-- Cancel the drag. -->
<request name="cancel"/> <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 <!-- Called by the drag target to accept the offer of the given
type --> type -->
<request name="accept"> <request name="accept">
<arg name="type" type="string"/> <arg name="type" type="string"/>
</request> </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 --> <!-- Sent at connect time to announce the association -->
<event name="device"> <event name="device">
<arg name="device" type="object" interface="input_device"/> <arg name="device" type="object" interface="input_device"/>
@ -167,18 +169,23 @@
<arg name="mime_type" type="string"/> <arg name="mime_type" type="string"/>
</event> </event>
<!-- Sent to drag originator when the drag is finished. It's also <!-- Sent to target, to indicate that the drag is finishing. The
sent in case an originator tries to activate a drag after the last motion/pointer_focus event gives the location of the
grab was released. If the originator didn't receive a drop. Target must respond with the 'receive' request, which
'target' event before receiving the 'finish' event, no drag sends an fd to the source for writing the drag data. -->
target was found and the originator should not send data. --> <event name="drop"/>
<event name="finish"/>
<!-- Sent to drag source when the drag is finished. The final
<!-- Sent to target, contains dragged data. Ends transaction on mime type is that of the last target event. If that was
the target side. --> NULL, no drag target was valid when the drag finished, fd is
<event name="drop"> undefined and the source should not send data. The event is
<arg name="contents" type="array"/> 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> </event>
</interface> </interface>
<interface name="surface" version="1"> <interface name="surface" version="1">

Loading…
Cancel
Save