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
|
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?
|
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)
|
- copy-n-paste, store data in server (only one mime-type available)
|
||||||
or do X style (content mime-type negotiation, but data goes away
|
or do X style (content mime-type negotiation, but data goes away
|
||||||
when client quits).
|
when client quits).
|
||||||
|
@ -206,6 +206,82 @@ dnd_get_item(struct dnd *dnd, int32_t x, int32_t y)
|
|||||||
return NULL;
|
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
|
static void
|
||||||
dnd_button_handler(struct window *window,
|
dnd_button_handler(struct window *window,
|
||||||
struct input *input, uint32_t time,
|
struct input *input, uint32_t time,
|
||||||
@ -352,6 +428,8 @@ main(int argc, char *argv[])
|
|||||||
|
|
||||||
d = display_create(&argc, &argv, option_entries);
|
d = display_create(&argc, &argv, option_entries);
|
||||||
|
|
||||||
|
display_add_drag_listener(d, &drag_listener, d);
|
||||||
|
|
||||||
dnd = dnd_create (d);
|
dnd = dnd_create (d);
|
||||||
|
|
||||||
display_run(d);
|
display_run(d);
|
||||||
|
@ -57,7 +57,6 @@ struct display {
|
|||||||
struct wl_shell *shell;
|
struct wl_shell *shell;
|
||||||
struct wl_drm *drm;
|
struct wl_drm *drm;
|
||||||
struct wl_output *output;
|
struct wl_output *output;
|
||||||
struct wl_drag *drag;
|
|
||||||
struct rectangle screen_allocation;
|
struct rectangle screen_allocation;
|
||||||
int authenticated;
|
int authenticated;
|
||||||
EGLDisplay dpy;
|
EGLDisplay dpy;
|
||||||
@ -718,6 +717,17 @@ input_get_position(struct input *input, int32_t *x, int32_t *y)
|
|||||||
*y = input->sy;
|
*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
|
void
|
||||||
window_start_drag(struct window *window, struct input *input, uint32_t time,
|
window_start_drag(struct window *window, struct input *input, uint32_t time,
|
||||||
struct wl_buffer *buffer, int32_t x, int32_t y)
|
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 = wl_input_device_get_user_data(device);
|
||||||
input->drag = drag;
|
input->drag = drag;
|
||||||
|
wl_drag_set_user_data(drag, input);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1081,14 +1091,12 @@ 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)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "drag pointer focus %p\n", surface);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
drag_offer(void *data,
|
drag_offer(void *data,
|
||||||
struct wl_drag *drag, const char *type)
|
struct wl_drag *drag, const char *type)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "drag offer %s\n", type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1097,7 +1105,6 @@ 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1109,7 +1116,6 @@ drag_target(void *data,
|
|||||||
static void
|
static void
|
||||||
drag_finish(void *data, struct wl_drag *drag)
|
drag_finish(void *data, struct wl_drag *drag)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "drag finish\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1133,6 +1139,7 @@ display_handle_global(struct wl_display *display, uint32_t id,
|
|||||||
const char *interface, uint32_t version, void *data)
|
const char *interface, uint32_t version, void *data)
|
||||||
{
|
{
|
||||||
struct display *d = data;
|
struct display *d = data;
|
||||||
|
struct wl_drag *drag;
|
||||||
|
|
||||||
if (strcmp(interface, "compositor") == 0) {
|
if (strcmp(interface, "compositor") == 0) {
|
||||||
d->compositor = wl_compositor_create(display, id);
|
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);
|
d->drm = wl_drm_create(display, id);
|
||||||
wl_drm_add_listener(d->drm, &drm_listener, d);
|
wl_drm_add_listener(d->drm, &drm_listener, d);
|
||||||
} else if (strcmp(interface, "drag") == 0) {
|
} else if (strcmp(interface, "drag") == 0) {
|
||||||
d->drag = wl_drag_create(display, id);
|
drag = wl_drag_create(display, id);
|
||||||
wl_drag_add_listener(d->drag, &drag_listener, d);
|
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 *width, int *height,
|
||||||
int *hotspot_x, int *hotspot_y);
|
int *hotspot_x, int *hotspot_y);
|
||||||
|
|
||||||
|
void
|
||||||
|
display_add_drag_listener(struct display *display,
|
||||||
|
const struct wl_drag_listener *drag_listener,
|
||||||
|
void *data);
|
||||||
|
|
||||||
void
|
void
|
||||||
display_run(struct display *d);
|
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,
|
struct wlsc_surface *surface, uint32_t time,
|
||||||
int32_t x, int32_t y, int32_t sx, int32_t sy)
|
int32_t x, int32_t y, int32_t sx, int32_t sy)
|
||||||
{
|
{
|
||||||
|
char **p, **end;
|
||||||
|
|
||||||
if (drag->pointer_focus == &surface->base)
|
if (drag->pointer_focus == &surface->base)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -1009,13 +1011,21 @@ wl_drag_set_pointer_focus(struct wl_drag *drag,
|
|||||||
&drag->base,
|
&drag->base,
|
||||||
WL_DRAG_POINTER_FOCUS,
|
WL_DRAG_POINTER_FOCUS,
|
||||||
time, NULL, 0, 0, 0, 0);
|
time, NULL, 0, 0, 0, 0);
|
||||||
if (surface)
|
if (surface) {
|
||||||
wl_surface_post_event(&surface->base,
|
wl_surface_post_event(&surface->base,
|
||||||
&drag->base,
|
&drag->base,
|
||||||
WL_DRAG_POINTER_FOCUS,
|
WL_DRAG_POINTER_FOCUS,
|
||||||
time, &surface->base,
|
time, &surface->base,
|
||||||
x, y, sx, sy);
|
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;
|
drag->pointer_focus = &surface->base;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1133,6 +1143,26 @@ drag_accept(struct wl_client *client,
|
|||||||
{
|
{
|
||||||
char **p, **end;
|
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)
|
if (drag->pointer_focus->client != client)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user