summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TODO13
-rw-r--r--clients/dnd.c78
-rw-r--r--clients/window.c23
-rw-r--r--clients/window.h5
-rw-r--r--compositor.c32
5 files changed, 142 insertions, 9 deletions
diff --git a/TODO b/TODO
index 5cb6ab4..601a97e 100644
--- a/TODO
+++ b/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).
diff --git a/clients/dnd.c b/clients/dnd.c
index 5772e8e..0557ed9 100644
--- a/clients/dnd.c
+++ b/clients/dnd.c
@@ -207,6 +207,82 @@ dnd_get_item(struct dnd *dnd, int32_t x, int32_t y)
}
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,
int button, int state, void *data)
@@ -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);
diff --git a/clients/window.c b/clients/window.c
index 994c8a8..a56bcfa 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -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;
@@ -719,6 +718,17 @@ input_get_position(struct input *input, int32_t *x, int32_t *y)
}
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);
}
}
diff --git a/clients/window.h b/clients/window.h
index ab17417..2c0b49b 100644
--- a/clients/window.h
+++ b/clients/window.h
@@ -60,6 +60,11 @@ display_get_pointer_surface(struct display *display, int pointer,
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);
enum {
diff --git a/compositor.c b/compositor.c
index 93aad96..9c5ee9b 100644
--- a/compositor.c
+++ b/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;