More work on dnd
This commit is contained in:
parent
041d63e3ee
commit
506e20eed9
13
TODO
13
TODO
@ -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).
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
32
compositor.c
32
compositor.c
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user