More work on dnd

This commit is contained in:
Kristian Høgsberg 2010-08-19 17:26:02 -04:00
parent 041d63e3ee
commit 506e20eed9
5 changed files with 142 additions and 9 deletions

13
TODO
View File

@ -50,6 +50,19 @@ Core wayland protocol
finish event too. Either way, the state of the drag blocks on
the client. What if we drag to a client that doesn't doo dnd?
How do we animate the drag icon back to the drag origin in case of
a failed drag?
How to handle surfaces from clients that don't know about dnd or
don't care? Maybe the dnd object should have a
dnd.register_surface() method so clients can opt-in the surfaces
that will participate in dnd. Or just assume client is not
participating until we receive an accept request.
May need to look at all offer events before we can decide which one
to go with. Problem is, we don't know when we've seen that last
offer event.
- copy-n-paste, store data in server (only one mime-type available)
or do X style (content mime-type negotiation, but data goes away
when client quits).

View File

@ -206,6 +206,82 @@ dnd_get_item(struct dnd *dnd, int32_t x, int32_t y)
return NULL;
}
static void
drag_handle_device(void *data,
struct wl_drag *drag, struct wl_input_device *device)
{
}
static void
drag_pointer_focus(void *data,
struct wl_drag *drag,
uint32_t time, struct wl_surface *surface,
int32_t x, int32_t y, int32_t surface_x, int32_t surface_y)
{
fprintf(stderr, "drag pointer focus %p\n", surface);
wl_drag_accept(drag, "text/plain");
}
static void
drag_offer(void *data,
struct wl_drag *drag, const char *type)
{
fprintf(stderr, "drag offer %s\n", type);
}
static void
drag_motion(void *data,
struct wl_drag *drag,
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);
/* 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");
}
static void
drag_target(void *data,
struct wl_drag *drag, const char *mime_type)
{
fprintf(stderr, "target %s\n", mime_type);
}
static void
drag_finish(void *data, struct wl_drag *drag)
{
fprintf(stderr, "drag finish\n");
struct wl_array a;
char text[] = "[drop data]";
a.data = text;
a.size = sizeof text;
wl_drag_send(drag, &a);
}
static void
drag_data(void *data,
struct wl_drag *drag, struct wl_array *contents)
{
fprintf(stderr, "drag drop, data %s\n", contents->data);
}
static const struct wl_drag_listener drag_listener = {
drag_handle_device,
drag_pointer_focus,
drag_offer,
drag_motion,
drag_target,
drag_finish,
drag_data
};
static void
dnd_button_handler(struct window *window,
struct input *input, uint32_t time,
@ -352,6 +428,8 @@ main(int argc, char *argv[])
d = display_create(&argc, &argv, option_entries);
display_add_drag_listener(d, &drag_listener, d);
dnd = dnd_create (d);
display_run(d);

View File

@ -57,7 +57,6 @@ struct display {
struct wl_shell *shell;
struct wl_drm *drm;
struct wl_output *output;
struct wl_drag *drag;
struct rectangle screen_allocation;
int authenticated;
EGLDisplay dpy;
@ -718,6 +717,17 @@ input_get_position(struct input *input, int32_t *x, int32_t *y)
*y = input->sy;
}
void
display_add_drag_listener(struct display *display,
const struct wl_drag_listener *drag_listener,
void *data)
{
struct input *input;
wl_list_for_each(input, &display->input_list, link)
wl_drag_add_listener(input->drag, drag_listener, data);
}
void
window_start_drag(struct window *window, struct input *input, uint32_t time,
struct wl_buffer *buffer, int32_t x, int32_t y)
@ -1072,7 +1082,7 @@ drag_handle_device(void *data,
input = wl_input_device_get_user_data(device);
input->drag = drag;
wl_drag_set_user_data(drag, input);
}
static void
@ -1081,14 +1091,12 @@ 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)
{
fprintf(stderr, "drag pointer focus %p\n", surface);
}
static void
drag_offer(void *data,
struct wl_drag *drag, const char *type)
{
fprintf(stderr, "drag offer %s\n", type);
}
static void
@ -1097,7 +1105,6 @@ 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);
}
static void
@ -1109,7 +1116,6 @@ drag_target(void *data,
static void
drag_finish(void *data, struct wl_drag *drag)
{
fprintf(stderr, "drag finish\n");
}
static void
@ -1133,6 +1139,7 @@ display_handle_global(struct wl_display *display, uint32_t id,
const char *interface, uint32_t version, void *data)
{
struct display *d = data;
struct wl_drag *drag;
if (strcmp(interface, "compositor") == 0) {
d->compositor = wl_compositor_create(display, id);
@ -1150,8 +1157,8 @@ display_handle_global(struct wl_display *display, uint32_t id,
d->drm = wl_drm_create(display, id);
wl_drm_add_listener(d->drm, &drm_listener, d);
} else if (strcmp(interface, "drag") == 0) {
d->drag = wl_drag_create(display, id);
wl_drag_add_listener(d->drag, &drag_listener, d);
drag = wl_drag_create(display, id);
wl_drag_add_listener(drag, &drag_listener, NULL);
}
}

View File

@ -59,6 +59,11 @@ display_get_pointer_surface(struct display *display, int pointer,
int *width, int *height,
int *hotspot_x, int *hotspot_y);
void
display_add_drag_listener(struct display *display,
const struct wl_drag_listener *drag_listener,
void *data);
void
display_run(struct display *d);

View File

@ -1000,6 +1000,8 @@ wl_drag_set_pointer_focus(struct wl_drag *drag,
struct wlsc_surface *surface, uint32_t time,
int32_t x, int32_t y, int32_t sx, int32_t sy)
{
char **p, **end;
if (drag->pointer_focus == &surface->base)
return;
@ -1009,13 +1011,21 @@ wl_drag_set_pointer_focus(struct wl_drag *drag,
&drag->base,
WL_DRAG_POINTER_FOCUS,
time, NULL, 0, 0, 0, 0);
if (surface)
if (surface) {
wl_surface_post_event(&surface->base,
&drag->base,
WL_DRAG_POINTER_FOCUS,
time, &surface->base,
x, y, sx, sy);
end = drag->types.data + drag->types.size;
for (p = drag->types.data; p < end; p++)
wl_surface_post_event(&surface->base,
&drag->base,
WL_DRAG_OFFER, *p);
}
drag->pointer_focus = &surface->base;
}
@ -1133,6 +1143,26 @@ drag_accept(struct wl_client *client,
{
char **p, **end;
/* If the client responds to drag motion events after the
* pointer has left the surface, we just discard the accept
* requests. The drag source just won't get the corresponding
* 'target' events and the next surface/root will start
* sending events. */
if (drag->pointer_focus == NULL)
return;
/* The accept request may arrive after the pointer has left
* the surface that received the drag motion events that
* triggered the request. But if the pointer re-enters the
* surface (or another surface from the same client) and we
* receive the 'accept' requests from the first visit to the
* surface later, this check will pass. Then we end up
* sending the 'target' event for the old 'accept' requests
* events *after* potentially sending 'target' from the root
* surface, out of order. So we need to track the time of
* pointer_focus and this request needs a time stamp so we can
* compare and reject 'accept' requests that are older than
* the pointer_focus in timestamp. */
if (drag->pointer_focus->client != client)
return;