More work on dnd
authorKristian Høgsberg <krh@bitplanet.net>
Thu, 19 Aug 2010 21:26:02 +0000 (17:26 -0400)
committerKristian Høgsberg <krh@bitplanet.net>
Thu, 19 Aug 2010 21:26:02 +0000 (17:26 -0400)
TODO
clients/dnd.c
clients/window.c
clients/window.h
compositor.c

diff --git a/TODO b/TODO
index 5cb6ab4..601a97e 100644 (file)
--- 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).
index 5772e8e..0557ed9 100644 (file)
@@ -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);
index 994c8a8..a56bcfa 100644 (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;
@@ -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);
        }
 }
 
index ab17417..2c0b49b 100644 (file)
@@ -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 {
index 93aad96..9c5ee9b 100644 (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;