[gtk+/wip/garnacho/dnd-grab: 1/4] wayland: Implement DnD actions as per wl_data_device v3



commit 2d691a04a40a3d636fe24467061f5554cd25c939
Author: Carlos Garnacho <carlosg gnome org>
Date:   Wed Jan 13 21:00:34 2016 +0100

    wayland: Implement DnD actions as per wl_data_device v3
    
    Implement as a managed GdkDragContext, which actually fits nicely
    with the drag-and-drop model in wayland.

 gdk/wayland/gdkdevice-wayland.c    |   69 ++------------
 gdk/wayland/gdkdisplay-wayland.c   |    2 +-
 gdk/wayland/gdkdnd-wayland.c       |  134 +++++++++++++++++++++++---
 gdk/wayland/gdkprivate-wayland.h   |    4 +-
 gdk/wayland/gdkselection-wayland.c |  188 +++++++++++++++++++++++++++++-------
 gtk/gtkdnd.c                       |   11 ++-
 6 files changed, 294 insertions(+), 114 deletions(-)
---
diff --git a/gdk/wayland/gdkdevice-wayland.c b/gdk/wayland/gdkdevice-wayland.c
index 43a8690..fd2925c 100644
--- a/gdk/wayland/gdkdevice-wayland.c
+++ b/gdk/wayland/gdkdevice-wayland.c
@@ -883,16 +883,10 @@ data_device_drop (void                  *data,
                   struct wl_data_device *data_device)
 {
   GdkWaylandDeviceData *device = (GdkWaylandDeviceData *) data;
-  GdkWindow *local_dnd_owner;
 
   GDK_NOTE (EVENTS,
             g_message ("data device drop, data device %p", data_device));
 
-  local_dnd_owner = gdk_selection_owner_get_for_display (device->display, gdk_drag_get_selection 
(device->drop_context));
-
-  if (local_dnd_owner)
-    gdk_wayland_device_unset_grab (device->master_pointer);
-
   _gdk_wayland_drag_context_emit_event (device->drop_context,
                                         GDK_DROP_START, GDK_CURRENT_TIME);
 }
@@ -3105,61 +3099,6 @@ gdk_wayland_device_set_selection (GdkDevice             *gdk_device,
                                 _gdk_wayland_display_get_serial (display_wayland));
 }
 
-void
-gdk_wayland_device_unset_grab (GdkDevice *gdk_device)
-{
-  GdkWaylandDeviceData *device;
-  GdkEventSequence *sequence;
-  GdkModifierType state;
-  GdkEvent *event;
-  guint button;
-  gdouble x, y;
-
-  device = GDK_WAYLAND_DEVICE (gdk_device)->device;
-  _gdk_wayland_device_get_last_implicit_grab_serial (GDK_WAYLAND_DEVICE (gdk_device), &sequence);
-  gdk_window_get_device_position_double (device->pointer_grab_window,
-                                         gdk_device, &x, &y, &state);
-
-  if (sequence)
-    {
-      event = gdk_event_new (GDK_TOUCH_END);
-      event->touch.window = g_object_ref (device->pointer_grab_window);
-      event->touch.send_event = TRUE;
-      event->touch.sequence = sequence;
-      event->touch.time = GDK_CURRENT_TIME;
-      event->touch.x = event->touch.x_root = x;
-      event->touch.y = event->touch.y_root = y;
-    }
-  else if (state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK))
-    {
-      if (state & GDK_BUTTON1_MASK)
-        button = 1;
-      else if (state & GDK_BUTTON2_MASK)
-        button = 2;
-      else if (state & GDK_BUTTON3_MASK)
-        button = 3;
-      else
-        return;
-
-      event = gdk_event_new (GDK_BUTTON_RELEASE);
-      event->button.window = g_object_ref (device->pointer_grab_window);
-      event->button.send_event = TRUE;
-      event->button.button = button;
-      event->button.time = GDK_CURRENT_TIME;
-      event->button.x = event->button.x_root = x;
-      event->button.y = event->button.y_root = y;
-    }
-  else
-    return;
-
-  device->button_modifiers = 0;
-  gdk_event_set_device (event, gdk_device);
-  gdk_event_set_source_device (event, gdk_device);
-  gdk_event_set_seat (event, gdk_device_get_seat (gdk_device));
-
-  _gdk_wayland_display_deliver_event (gdk_device_get_display (gdk_device), event);
-}
-
 struct wl_seat *
 gdk_wayland_seat_get_wl_seat (GdkSeat *seat)
 {
@@ -3167,3 +3106,11 @@ gdk_wayland_seat_get_wl_seat (GdkSeat *seat)
 
   return GDK_WAYLAND_SEAT (seat)->wl_seat;
 }
+
+GdkDragContext *
+gdk_wayland_device_get_drop_context (GdkDevice *device)
+{
+  GdkSeat *seat = gdk_device_get_seat (device);
+
+  return GDK_WAYLAND_SEAT (seat)->drop_context;
+}
diff --git a/gdk/wayland/gdkdisplay-wayland.c b/gdk/wayland/gdkdisplay-wayland.c
index 53e26ae..24a4ce2 100644
--- a/gdk/wayland/gdkdisplay-wayland.c
+++ b/gdk/wayland/gdkdisplay-wayland.c
@@ -315,7 +315,7 @@ gdk_registry_handle_global (void               *data,
   else if (strcmp (interface, "wl_data_device_manager") == 0)
     {
       display_wayland->data_device_manager =
-        wl_registry_bind (display_wayland->wl_registry, id, &wl_data_device_manager_interface, 1);
+        wl_registry_bind (display_wayland->wl_registry, id, &wl_data_device_manager_interface, 3);
     }
   else if (strcmp (interface, "wl_subcompositor") == 0)
     {
diff --git a/gdk/wayland/gdkdnd-wayland.c b/gdk/wayland/gdkdnd-wayland.c
index 8eb8688..8402b0d 100644
--- a/gdk/wayland/gdkdnd-wayland.c
+++ b/gdk/wayland/gdkdnd-wayland.c
@@ -24,6 +24,7 @@
 #include "gdkproperty.h"
 #include "gdkprivate-wayland.h"
 #include "gdkdisplay-wayland.h"
+#include "gdkseat-wayland.h"
 
 #include "gdkdeviceprivate.h"
 
@@ -45,6 +46,7 @@ struct _GdkWaylandDragContext
   GdkWindow *dnd_window;
   struct wl_surface *dnd_surface;
   struct wl_data_source *data_source;
+  GdkDragAction selected_action;
   uint32_t serial;
   gdouble x;
   gdouble y;
@@ -82,6 +84,8 @@ gdk_wayland_drag_context_finalize (GObject *object)
       selection_owner = gdk_selection_owner_get_for_display (display, selection);
       if (selection_owner == context->source_window)
         gdk_wayland_selection_unset_data_source (display, selection);
+
+      gdk_drag_context_set_cursor (context, NULL);
     }
 
   if (wayland_context->data_source)
@@ -157,6 +161,21 @@ gdk_wayland_drag_context_find_window (GdkDragContext  *context,
   return NULL;
 }
 
+static inline uint32_t
+gdk_to_wl_actions (GdkDragAction action)
+{
+  uint32_t dnd_actions = 0;
+
+  if (action & (GDK_ACTION_COPY | GDK_ACTION_LINK | GDK_ACTION_PRIVATE))
+    dnd_actions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
+  if (action & GDK_ACTION_MOVE)
+    dnd_actions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
+  if (action & GDK_ACTION_ASK)
+    dnd_actions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
+
+  return dnd_actions;
+}
+
 void
 gdk_wayland_drag_context_set_action (GdkDragContext *context,
                                      GdkDragAction   action)
@@ -208,6 +227,9 @@ gdk_wayland_drop_context_set_status (GdkDragContext *context,
   GdkDisplay *display;
   struct wl_data_offer *wl_offer;
 
+  if (!context->dest_window)
+    return;
+
   context_wayland = GDK_WAYLAND_DRAG_CONTEXT (context);
 
   display = gdk_device_get_display (gdk_drag_context_get_device (context));
@@ -241,11 +263,32 @@ gdk_wayland_drop_context_set_status (GdkDragContext *context,
 }
 
 static void
+gdk_wayland_drag_context_commit_status (GdkDragContext *context)
+{
+  GdkWaylandDragContext *wayland_context;
+  GdkDisplay *display;
+  uint32_t dnd_actions;
+
+  wayland_context = GDK_WAYLAND_DRAG_CONTEXT (context);
+  display = gdk_device_get_display (gdk_drag_context_get_device (context));
+
+  dnd_actions = gdk_to_wl_actions (wayland_context->selected_action);
+  gdk_wayland_selection_set_current_offer_actions (display, dnd_actions);
+
+  gdk_wayland_drop_context_set_status (context, wayland_context->selected_action != 0);
+}
+
+static void
 gdk_wayland_drag_context_drag_status (GdkDragContext *context,
                                      GdkDragAction   action,
                                      guint32         time_)
 {
-  gdk_wayland_drop_context_set_status (context, action != 0);
+  GdkWaylandDragContext *wayland_context;
+
+  wayland_context = GDK_WAYLAND_DRAG_CONTEXT (context);
+  wayland_context->selected_action = action;
+
+  gdk_wayland_drag_context_commit_status (context);
 }
 
 static void
@@ -263,12 +306,20 @@ gdk_wayland_drag_context_drop_finish (GdkDragContext *context,
                                      guint32         time)
 {
   GdkDisplay *display = gdk_device_get_display (gdk_drag_context_get_device (context));
+  GdkWaylandDragContext *wayland_context;
+  struct wl_data_offer *wl_offer;
   GdkAtom selection;
 
+  wayland_context = GDK_WAYLAND_DRAG_CONTEXT (context);
   selection = gdk_drag_get_selection (context);
+  wl_offer = gdk_wayland_selection_get_offer (display, selection);
 
-  if (gdk_selection_owner_get_for_display (display, selection))
-    gdk_wayland_selection_unset_data_source (display, selection);
+  if (success && wayland_context->selected_action &&
+      wayland_context->selected_action != GDK_ACTION_ASK)
+    {
+      gdk_wayland_drag_context_commit_status (context);
+      wl_data_offer_finish (wl_offer);
+    }
 
   gdk_wayland_selection_set_offer (display, selection, NULL);
 }
@@ -325,6 +376,67 @@ gdk_wayland_drag_context_set_hotspot (GdkDragContext *context,
   gdk_window_invalidate_rect (context_wayland->dnd_window, &damage_rect, FALSE);
 }
 
+static gboolean
+gdk_wayland_drag_context_manage_dnd (GdkDragContext *context,
+                                     GdkWindow      *ipc_window,
+                                     GdkDragAction   actions)
+{
+  GdkWaylandDragContext *context_wayland;
+  GdkWaylandDisplay *display_wayland;
+  GdkDevice *device;
+  GdkWindow *toplevel;
+
+  device = gdk_drag_context_get_device (context);
+  display_wayland = GDK_WAYLAND_DISPLAY (gdk_device_get_display (device));
+  toplevel = _gdk_device_window_at_position (device, NULL, NULL, NULL, TRUE);
+
+  context_wayland = GDK_WAYLAND_DRAG_CONTEXT (context);
+  wl_data_source_set_actions (context_wayland->data_source,
+                              gdk_to_wl_actions (actions));
+
+  wl_data_device_start_drag (gdk_wayland_device_get_data_device (device),
+                             context_wayland->data_source,
+                             gdk_wayland_window_get_wl_surface (toplevel),
+                            context_wayland->dnd_surface,
+                             _gdk_wayland_display_get_serial (display_wayland));
+
+  gdk_seat_ungrab (gdk_device_get_seat (device));
+
+  return TRUE;
+}
+
+static void
+gdk_wayland_drag_context_set_cursor (GdkDragContext *context,
+                                     GdkCursor      *cursor)
+{
+  GdkDevice *device = gdk_drag_context_get_device (context);
+
+  gdk_wayland_seat_set_global_cursor (gdk_device_get_seat (device), cursor);
+}
+
+static void
+gdk_wayland_drag_context_action_changed (GdkDragContext *context,
+                                         GdkDragAction   action)
+{
+  GdkCursor *cursor;
+
+  cursor = gdk_drag_get_cursor (action);
+  gdk_drag_context_set_cursor (context, cursor);
+}
+
+static void
+gdk_wayland_drag_context_drop_performed (GdkDragContext *context,
+                                         guint32         time_)
+{
+  gdk_drag_context_set_cursor (context, NULL);
+}
+
+static void
+gdk_wayland_drag_context_cancel (GdkDragContext *context)
+{
+  gdk_drag_context_set_cursor (context, NULL);
+}
+
 static void
 gdk_wayland_drag_context_class_init (GdkWaylandDragContextClass *klass)
 {
@@ -344,6 +456,11 @@ gdk_wayland_drag_context_class_init (GdkWaylandDragContextClass *klass)
   context_class->get_selection = gdk_wayland_drag_context_get_selection;
   context_class->get_drag_window = gdk_wayland_drag_context_get_drag_window;
   context_class->set_hotspot = gdk_wayland_drag_context_set_hotspot;
+  context_class->manage_dnd = gdk_wayland_drag_context_manage_dnd;
+  context_class->set_cursor = gdk_wayland_drag_context_set_cursor;
+  context_class->action_changed = gdk_wayland_drag_context_action_changed;
+  context_class->drop_performed = gdk_wayland_drag_context_drop_performed;
+  context_class->cancel = gdk_wayland_drag_context_cancel;
 }
 
 GdkDragProtocol
@@ -383,13 +500,9 @@ _gdk_wayland_window_drag_begin (GdkWindow *window,
                                 gint       y_root)
 {
   GdkWaylandDragContext *context_wayland;
-  GdkWaylandDisplay *display_wayland;
   GdkDragContext *context;
-  GdkWindow *toplevel;
   GList *l;
 
-  toplevel = _gdk_device_window_at_position (device, NULL, NULL, NULL, TRUE);
-
   context_wayland = g_object_new (GDK_TYPE_WAYLAND_DRAG_CONTEXT, NULL);
   context = GDK_DRAG_CONTEXT (context_wayland);
   context->source_window = g_object_ref (window);
@@ -397,7 +510,6 @@ _gdk_wayland_window_drag_begin (GdkWindow *window,
   context->targets = g_list_copy (targets);
 
   gdk_drag_context_set_device (context, device);
-  display_wayland = GDK_WAYLAND_DISPLAY (gdk_device_get_display (device));
 
   context_wayland->dnd_window = create_dnd_window (gdk_window_get_screen (window));
   context_wayland->dnd_surface = gdk_wayland_window_get_wl_surface (context_wayland->dnd_window);
@@ -413,12 +525,6 @@ _gdk_wayland_window_drag_begin (GdkWindow *window,
       g_free (mimetype);
     }
 
-  wl_data_device_start_drag (gdk_wayland_device_get_data_device (device),
-                             context_wayland->data_source,
-                             gdk_wayland_window_get_wl_surface (toplevel),
-                            context_wayland->dnd_surface,
-                             _gdk_wayland_display_get_serial (display_wayland));
-
   return context;
 }
 
diff --git a/gdk/wayland/gdkprivate-wayland.h b/gdk/wayland/gdkprivate-wayland.h
index 23125cb..9e51517 100644
--- a/gdk/wayland/gdkprivate-wayland.h
+++ b/gdk/wayland/gdkprivate-wayland.h
@@ -188,7 +188,7 @@ struct wl_data_device * gdk_wayland_device_get_data_device (GdkDevice *gdk_devic
 void gdk_wayland_device_set_selection (GdkDevice             *gdk_device,
                                        struct wl_data_source *source);
 
-void gdk_wayland_device_unset_grab       (GdkDevice        *device);
+GdkDragContext * gdk_wayland_device_get_drop_context (GdkDevice *gdk_device);
 
 void gdk_wayland_device_unset_touch_grab (GdkDevice        *device,
                                           GdkEventSequence *sequence);
@@ -258,6 +258,8 @@ void     gdk_wayland_selection_store   (GdkWindow    *window,
 struct wl_data_source * gdk_wayland_selection_get_data_source (GdkWindow *owner,
                                                                GdkAtom    selection);
 void gdk_wayland_selection_unset_data_source (GdkDisplay *display, GdkAtom selection);
+gboolean gdk_wayland_selection_set_current_offer_actions (GdkDisplay *display,
+                                                          uint32_t    actions);
 
 EGLSurface gdk_wayland_window_get_egl_surface (GdkWindow *window,
                                                EGLConfig config);
diff --git a/gdk/wayland/gdkselection-wayland.c b/gdk/wayland/gdkselection-wayland.c
index 1c83c8f..24a4e37 100644
--- a/gdk/wayland/gdkselection-wayland.c
+++ b/gdk/wayland/gdkselection-wayland.c
@@ -350,8 +350,69 @@ data_offer_offer (void                 *data,
   info->targets = g_list_prepend (info->targets, atom);
 }
 
+static inline GdkDragAction
+_wl_to_gdk_actions (uint32_t dnd_actions)
+{
+  GdkDragAction actions = 0;
+
+  if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY)
+    actions |= GDK_ACTION_COPY;
+  if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE)
+    actions |= GDK_ACTION_MOVE;
+  if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK)
+    actions |= GDK_ACTION_ASK;
+
+  return actions;
+}
+
+static void
+data_offer_source_actions (void                 *data,
+                           struct wl_data_offer *wl_data_offer,
+                           uint32_t              source_actions)
+{
+  GdkDragContext *drop_context;
+  GdkDisplay *display;
+  GdkDevice *device;
+  GdkSeat *seat;
+
+  display = gdk_display_get_default ();
+  seat = gdk_display_get_default_seat (display);
+  device = gdk_seat_get_pointer (seat);
+  drop_context = gdk_wayland_device_get_drop_context (device);
+
+  drop_context->actions = _wl_to_gdk_actions (source_actions);
+
+  if (gdk_drag_context_get_dest_window (drop_context))
+    _gdk_wayland_drag_context_emit_event (drop_context, GDK_DRAG_MOTION,
+                                          GDK_CURRENT_TIME);
+}
+
+static void
+data_offer_action (void                 *data,
+                   struct wl_data_offer *wl_data_offer,
+                   uint32_t              action)
+{
+  GdkDragContext *drop_context;
+  GdkDisplay *display;
+  GdkDevice *device;
+  GdkSeat *seat;
+
+  display = gdk_display_get_default ();
+  seat = gdk_display_get_default_seat (display);
+  device = gdk_seat_get_pointer (seat);
+  drop_context = gdk_wayland_device_get_drop_context (device);
+
+  drop_context->action = _wl_to_gdk_actions (action);
+
+  if (gdk_drag_context_get_dest_window (drop_context))
+    _gdk_wayland_drag_context_emit_event (drop_context, GDK_DRAG_MOTION,
+                                          GDK_CURRENT_TIME);
+}
+
 static const struct wl_data_offer_listener data_offer_listener = {
   data_offer_offer,
+  data_offer_source_actions,
+  data_offer_action
 };
 
 DataOfferData *
@@ -569,6 +630,9 @@ gdk_wayland_selection_store (GdkWindow    *window,
   GdkWaylandSelection *selection = gdk_wayland_display_get_selection (display);
   GArray *array;
 
+  if (type == gdk_atom_intern_static_string ("NULL"))
+    return;
+
   array = g_array_new (TRUE, FALSE, sizeof (guchar));
   g_array_append_vals (array, data, len);
 
@@ -701,32 +765,16 @@ data_source_target (void                  *data,
                     const char            *mime_type)
 {
   GdkWaylandSelection *wayland_selection = data;
-  GdkDragContext *context = NULL;
   GdkWindow *window = NULL;
 
   g_debug (G_STRLOC ": %s source = %p, mime_type = %s",
            G_STRFUNC, source, mime_type);
 
-  context = gdk_wayland_drag_context_lookup_by_data_source (source);
-
   if (!mime_type)
-    {
-      if (context)
-        {
-          gdk_wayland_drag_context_set_action (context, 0);
-          _gdk_wayland_drag_context_emit_event (context, GDK_DRAG_STATUS,
-                                                GDK_CURRENT_TIME);
-        }
-      return;
-    }
+    return;
 
   if (source == wayland_selection->dnd_source)
-    {
-      window = wayland_selection->dnd_owner;
-      gdk_wayland_drag_context_set_action (context, GDK_ACTION_COPY);
-      _gdk_wayland_drag_context_emit_event (context, GDK_DRAG_STATUS,
-                                            GDK_CURRENT_TIME);
-    }
+    window = wayland_selection->dnd_owner;
   else if (source == wayland_selection->clipboard_source)
     window = wayland_selection->clipboard_owner;
 
@@ -745,7 +793,6 @@ data_source_send (void                  *data,
                   int32_t                fd)
 {
   GdkWaylandSelection *wayland_selection = data;
-  GdkDragContext *context;
   GdkWindow *window;
 
   g_debug (G_STRLOC ": %s source = %p, mime_type = %s, fd = %d",
@@ -757,8 +804,6 @@ data_source_send (void                  *data,
       return;
     }
 
-  context = gdk_wayland_drag_context_lookup_by_data_source (source);
-
   if (source == wayland_selection->dnd_source)
     window = wayland_selection->dnd_owner;
   else if (source == wayland_selection->clipboard_source)
@@ -776,13 +821,6 @@ data_source_send (void                  *data,
                                              gdk_atom_intern (mime_type, FALSE),
                                              fd))
     gdk_wayland_selection_check_write (wayland_selection);
-
-  if (context)
-    {
-      _gdk_wayland_drag_context_emit_event (context, GDK_DROP_FINISHED,
-                                            GDK_CURRENT_TIME);
-      gdk_wayland_device_unset_grab (gdk_drag_context_get_device (context));
-    }
 }
 
 static void
@@ -806,22 +844,79 @@ data_source_cancelled (void                  *data,
   else
     return;
 
-  gdk_wayland_selection_unset_data_source (display, atom);
+  context = gdk_wayland_drag_context_lookup_by_data_source (source);
+
+  if (context)
+    gdk_drag_context_cancel (context);
+
   gdk_selection_owner_set (NULL, atom, GDK_CURRENT_TIME, TRUE);
+  gdk_wayland_selection_unset_data_source (display, atom);
+}
 
-  if (source == wayland_selection->dnd_source)
-    {
-      context = gdk_wayland_drag_context_lookup_by_data_source (source);
+static void
+data_source_dnd_drop_performed (void                  *data,
+                                struct wl_data_source *source)
+{
+  GdkDragContext *context;
+
+  context = gdk_wayland_drag_context_lookup_by_data_source (source);
+
+  if (!context)
+    return;
+
+  g_signal_emit_by_name (context, "drop-performed", GDK_CURRENT_TIME);
+}
+
+static void
+data_source_dnd_finished (void                  *data,
+                          struct wl_data_source *source)
+{
+  GdkDisplay *display = gdk_display_get_default ();
+  GdkDragContext *context;
+
+  context = gdk_wayland_drag_context_lookup_by_data_source (source);
+
+  if (!context)
+    return;
 
-      if (context)
-        gdk_wayland_device_unset_grab (gdk_drag_context_get_device (context));
+  if (context->action == GDK_ACTION_MOVE)
+    {
+      gdk_wayland_selection_emit_request (context->source_window,
+                                          atoms[ATOM_DND],
+                                          gdk_atom_intern_static_string ("DELETE"));
     }
+
+  g_signal_emit_by_name (context, "dnd-finished");
+  gdk_selection_owner_set (NULL, atoms[ATOM_DND], GDK_CURRENT_TIME, TRUE);
+  gdk_wayland_selection_unset_data_source (display, atoms[ATOM_DND]);
+}
+
+static void
+data_source_action (void                  *data,
+                    struct wl_data_source *source,
+                    uint32_t               action)
+{
+  GdkDragContext *context;
+
+  g_debug (G_STRLOC ": %s source = %p action=%x",
+           G_STRFUNC, source, action);
+
+  context = gdk_wayland_drag_context_lookup_by_data_source (source);
+
+  if (!context)
+    return;
+
+  context->action = _wl_to_gdk_actions (action);
+  g_signal_emit_by_name (context, "action-changed", context->action);
 }
 
 static const struct wl_data_source_listener data_source_listener = {
   data_source_target,
   data_source_send,
-  data_source_cancelled
+  data_source_cancelled,
+  data_source_dnd_drop_performed,
+  data_source_dnd_finished,
+  data_source_action,
 };
 
 struct wl_data_source *
@@ -1009,7 +1104,7 @@ _gdk_wayland_display_convert_selection (GdkDisplay *display,
   offer = gdk_wayland_selection_get_offer (display, selection);
   target_list = gdk_wayland_selection_get_targets (display, selection);
 
-  if (!offer)
+  if (!offer || target == gdk_atom_intern_static_string ("DELETE"))
     {
       GdkEvent *event;
 
@@ -1185,3 +1280,24 @@ gdk_wayland_selection_clear_targets (GdkDisplay *display,
   g_array_set_size (wayland_selection->source_targets, 0);
   gdk_wayland_selection_unset_data_source (display, selection);
 }
+
+gboolean
+gdk_wayland_selection_set_current_offer_actions (GdkDisplay *display,
+                                                 uint32_t    action)
+{
+  struct wl_data_offer *offer;
+  uint32_t all_actions = 0;
+
+  offer = gdk_wayland_selection_get_offer (display, atoms[ATOM_DND]);
+
+  if (!offer)
+    return FALSE;
+
+  if (action != 0)
+    all_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY |
+      WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE |
+      WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
+
+  wl_data_offer_set_actions (offer, all_actions, action);
+  return TRUE;
+}
diff --git a/gtk/gtkdnd.c b/gtk/gtkdnd.c
index 3748112..6c60fed 100644
--- a/gtk/gtkdnd.c
+++ b/gtk/gtkdnd.c
@@ -42,6 +42,10 @@
 #endif
 #endif
 
+#ifdef GDK_WINDOWING_WAYLAND
+#include <gdk/wayland/gdkwayland.h>
+#endif
+
 #include "gtkgesturedrag.h"
 #include "gtkgesturesingle.h"
 #include "gtkicontheme.h"
@@ -2174,9 +2178,14 @@ gtk_drag_begin_internal (GtkWidget          *widget,
   GdkAtom selection;
   gboolean managed = FALSE;
 
+  managed =
 #ifdef GDK_WINDOWING_X11
-  managed = GDK_IS_X11_DISPLAY (gtk_widget_get_display (widget));
+    GDK_IS_X11_DISPLAY (gtk_widget_get_display (widget)) ||
+#endif
+#ifdef GDK_WINDOWING_WAYLAND
+    GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (widget)) ||
 #endif
+    FALSE;
 
   pointer = keyboard = NULL;
   ipc_widget = gtk_drag_get_ipc_widget (widget);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]