wayland: Redo DND offer handling

Instead of tracking offers in GdkWaylandSelection objects, track the
pending offer in the GdkWaylandSeat and pass it to the GdkDragContext
once we get an enter event.
This commit is contained in:
Benjamin Otte
2018-05-06 02:06:53 +02:00
parent 03a85ff2a0
commit 7f8a8f221d
4 changed files with 184 additions and 327 deletions

View File

@@ -229,6 +229,11 @@ struct _GdkWaylandSeat
uint32_t server_repeat_rate;
uint32_t server_repeat_delay;
struct wl_data_offer *pending_offer;
GdkContentFormatsBuilder *pending_builder;
GdkDragAction pending_source_actions;
GdkDragAction pending_action;
struct wl_callback *repeat_callback;
guint32 repeat_timer;
guint32 repeat_key;
@@ -1055,6 +1060,111 @@ _gdk_wayland_device_get_keymap (GdkDevice *device)
return seat->keymap;
}
static void
gdk_wayland_seat_discard_pending_offer (GdkWaylandSeat *seat)
{
if (seat->pending_builder)
{
GdkContentFormats *ignore = gdk_content_formats_builder_free_to_formats (seat->pending_builder);
gdk_content_formats_unref (ignore);
seat->pending_builder = NULL;
}
g_clear_pointer (&seat->pending_offer, (GDestroyNotify) wl_data_offer_destroy);
seat->pending_source_actions = 0;
seat->pending_action = 0;
}
static inline GdkDragAction
gdk_wayland_actions_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_offer (void *data,
struct wl_data_offer *offer,
const char *type)
{
GdkWaylandSeat *seat = data;
if (seat->pending_offer != offer)
{
GDK_DISPLAY_NOTE (gdk_seat_get_display (GDK_SEAT (seat)), EVENTS,
g_message ("%p: offer for unknown offer %p of %s",
seat, offer, type));
return;
}
gdk_content_formats_builder_add_mime_type (seat->pending_builder, type);
}
static void
data_offer_source_actions (void *data,
struct wl_data_offer *offer,
uint32_t source_actions)
{
GdkWaylandSeat *seat = data;
GdkDragContext *drop_context;
GdkDevice *device;
if (offer == seat->pending_offer)
{
seat->pending_source_actions = gdk_wayland_actions_to_gdk_actions (source_actions);
return;
}
device = gdk_seat_get_pointer (GDK_SEAT (seat));
drop_context = gdk_wayland_device_get_drop_context (device);
if (drop_context == NULL)
return;
drop_context->actions = gdk_wayland_actions_to_gdk_actions (source_actions);
_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 *offer,
uint32_t action)
{
GdkWaylandSeat *seat = data;
GdkDragContext *drop_context;
GdkDevice *device;
if (offer == seat->pending_offer)
{
seat->pending_action = gdk_wayland_actions_to_gdk_actions (action);
return;
}
device = gdk_seat_get_pointer (GDK_SEAT (seat));
drop_context = gdk_wayland_device_get_drop_context (device);
if (drop_context == NULL)
return;
drop_context->action = gdk_wayland_actions_to_gdk_actions (action);
_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
};
static void
data_device_data_offer (void *data,
struct wl_data_device *data_device,
@@ -1066,7 +1176,16 @@ data_device_data_offer (void *data,
g_message ("data device data offer, data device %p, offer %p",
data_device, offer));
gdk_wayland_selection_ensure_offer (seat->display, offer);
gdk_wayland_seat_discard_pending_offer (seat);
seat->pending_offer = offer;
wl_data_offer_add_listener (offer,
&data_offer_listener,
seat);
seat->pending_builder = gdk_content_formats_builder_new ();
seat->pending_source_actions = 0;
seat->pending_action = 0;
}
static void
@@ -1080,6 +1199,7 @@ data_device_enter (void *data,
{
GdkWaylandSeat *seat = data;
GdkSurface *dest_surface, *dnd_owner;
GdkContentFormats *formats;
GdkDevice *device;
dest_surface = wl_surface_get_user_data (surface);
@@ -1087,6 +1207,14 @@ data_device_enter (void *data,
if (!GDK_IS_SURFACE (dest_surface))
return;
if (offer != seat->pending_offer)
{
GDK_DISPLAY_NOTE (gdk_seat_get_display (GDK_SEAT (seat)), EVENTS,
g_message ("%p: enter event for unknown offer %p, expected %p",
seat, offer, seat->pending_offer));
return;
}
GDK_DISPLAY_NOTE (seat->display, EVENTS,
g_message ("data device enter, data device %p serial %u, surface %p, x %f y %f, offer %p",
data_device, serial, surface, wl_fixed_to_double (x), wl_fixed_to_double (y), offer));
@@ -1105,10 +1233,12 @@ data_device_enter (void *data,
g_warning ("No device for DND enter, ignoring.");
return;
}
seat->drop_context = _gdk_wayland_drop_context_new (device,
seat->data_device);
gdk_wayland_drop_context_update_targets (seat->drop_context);
formats = gdk_content_formats_builder_free_to_formats (seat->pending_builder);
seat->pending_builder = NULL;
seat->pending_offer = NULL;
seat->drop_context = _gdk_wayland_drop_context_new (device, formats, offer);
dnd_owner = seat->foreign_dnd_surface;
@@ -1119,10 +1249,11 @@ data_device_enter (void *data,
_gdk_wayland_drag_context_set_coords (seat->drop_context,
wl_fixed_to_double (x),
wl_fixed_to_double (y));
gdk_wayland_seat_discard_pending_offer (seat);
_gdk_wayland_drag_context_emit_event (seat->drop_context, GDK_DRAG_ENTER,
GDK_CURRENT_TIME);
gdk_wayland_selection_set_offer (seat->display, offer);
}
static void
@@ -1168,7 +1299,6 @@ data_device_motion (void *data,
seat->pointer_info.surface_x = wl_fixed_to_double (x);
seat->pointer_info.surface_y = wl_fixed_to_double (y);
gdk_wayland_drop_context_update_targets (seat->drop_context);
_gdk_wayland_drag_context_set_coords (seat->drop_context,
wl_fixed_to_double (x),
wl_fixed_to_double (y));
@@ -1198,9 +1328,25 @@ data_device_selection (void *data,
GdkContentFormats *formats;
if (offer)
formats = gdk_wayland_selection_steal_offer (seat->display, offer);
{
if (offer == seat->pending_offer)
{
formats = gdk_content_formats_builder_free_to_formats (seat->pending_builder);
seat->pending_builder = NULL;
seat->pending_offer = NULL;
}
else
{
formats = gdk_content_formats_new (NULL, 0);
offer = NULL;
}
gdk_wayland_seat_discard_pending_offer (seat);
}
else
formats = gdk_content_formats_new (NULL, 0);
{
formats = gdk_content_formats_new (NULL, 0);
}
gdk_wayland_clipboard_claim_remote (GDK_WAYLAND_CLIPBOARD (seat->clipboard),
offer,

View File

@@ -50,6 +50,7 @@ struct _GdkWaylandDragContext
GdkSurface *dnd_surface;
struct wl_surface *dnd_wl_surface;
struct wl_data_source *data_source;
struct wl_data_offer *offer;
GdkDragAction selected_action;
uint32_t serial;
gdouble x;
@@ -170,21 +171,11 @@ static void
gdk_wayland_drop_context_set_status (GdkDragContext *context,
gboolean accepted)
{
GdkWaylandDragContext *context_wayland;
GdkDisplay *display;
struct wl_data_offer *wl_offer;
GdkWaylandDragContext *context_wayland = GDK_WAYLAND_DRAG_CONTEXT (context);
if (!context->dest_surface)
return;
context_wayland = GDK_WAYLAND_DRAG_CONTEXT (context);
display = gdk_device_get_display (gdk_drag_context_get_device (context));
wl_offer = gdk_wayland_selection_get_offer (display);
if (!wl_offer)
return;
if (accepted)
{
const char *const *mimetypes;
@@ -199,26 +190,33 @@ gdk_wayland_drop_context_set_status (GdkDragContext *context,
if (i < n_mimetypes)
{
wl_data_offer_accept (wl_offer, context_wayland->serial, mimetypes[i]);
wl_data_offer_accept (context_wayland->offer, context_wayland->serial, mimetypes[i]);
return;
}
}
wl_data_offer_accept (wl_offer, context_wayland->serial, NULL);
wl_data_offer_accept (context_wayland->offer, context_wayland->serial, NULL);
}
static void
gdk_wayland_drag_context_commit_status (GdkDragContext *context)
{
GdkWaylandDragContext *wayland_context;
GdkWaylandDragContext *wayland_context = GDK_WAYLAND_DRAG_CONTEXT (context);
GdkDisplay *display;
uint32_t dnd_actions;
uint32_t dnd_actions, all_actions = 0;
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);
if (dnd_actions != 0)
all_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY |
WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE |
WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
if (GDK_WAYLAND_DISPLAY (display)->data_device_manager_version >=
WL_DATA_OFFER_SET_ACTIONS_SINCE_VERSION)
wl_data_offer_set_actions (wayland_context->offer, all_actions, dnd_actions);
gdk_wayland_drop_context_set_status (context, wayland_context->selected_action != 0);
}
@@ -239,25 +237,19 @@ gdk_wayland_drag_context_drop_finish (GdkDragContext *context,
gboolean success,
guint32 time)
{
GdkWaylandDragContext *wayland_context = GDK_WAYLAND_DRAG_CONTEXT (context);
GdkDisplay *display = gdk_device_get_display (gdk_drag_context_get_device (context));
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
GdkWaylandDragContext *wayland_context;
struct wl_data_offer *wl_offer;
wayland_context = GDK_WAYLAND_DRAG_CONTEXT (context);
wl_offer = gdk_wayland_selection_get_offer (display);
if (wl_offer && success && wayland_context->selected_action &&
if (success && wayland_context->selected_action &&
wayland_context->selected_action != GDK_ACTION_ASK)
{
gdk_wayland_drag_context_commit_status (context);
if (display_wayland->data_device_manager_version >=
WL_DATA_OFFER_FINISH_SINCE_VERSION)
wl_data_offer_finish (wl_offer);
wl_data_offer_finish (wayland_context->offer);
}
gdk_wayland_selection_set_offer (display, NULL);
}
static void
@@ -268,10 +260,9 @@ gdk_wayland_drag_context_read_async (GdkDragContext *context,
GAsyncReadyCallback callback,
gpointer user_data)
{
GdkWaylandDragContext *wayland_context = GDK_WAYLAND_DRAG_CONTEXT (context);
GdkDisplay *display;
GdkContentFormats *dnd_formats;
GInputStream *stream;
struct wl_data_offer *offer;
const char *mime_type;
int pipe_fd[2];
GError *error = NULL;
@@ -285,17 +276,14 @@ gdk_wayland_drag_context_read_async (GdkDragContext *context,
GDK_DISPLAY_NOTE (display, DND, char *s = gdk_content_formats_to_string (formats);
g_message ("%p: read for %s", context, s);
g_free (s); );
dnd_formats = gdk_wayland_selection_get_targets (display);
mime_type = gdk_content_formats_match_mime_type (formats, dnd_formats);
mime_type = gdk_content_formats_match_mime_type (formats,
gdk_drag_context_get_formats (context));
if (mime_type == NULL)
{
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
_("No compatible transfer format found"));
return;
}
/* offer formats should be empty if we have no offer */
offer = gdk_wayland_selection_get_offer (display);
g_assert (offer);
g_task_set_task_data (task, (gpointer) mime_type, NULL);
@@ -305,10 +293,7 @@ gdk_wayland_drag_context_read_async (GdkDragContext *context,
return;
}
wl_data_offer_accept (offer,
_gdk_wayland_display_get_serial (GDK_WAYLAND_DISPLAY (display)),
mime_type);
wl_data_offer_receive (offer, mime_type, pipe_fd[1]);
wl_data_offer_receive (wayland_context->offer, mime_type, pipe_fd[1]);
stream = g_unix_input_stream_new (pipe_fd[0], TRUE);
close (pipe_fd[1]);
g_task_return_pointer (task, stream, g_object_unref);
@@ -515,8 +500,9 @@ _gdk_wayland_surface_drag_begin (GdkSurface *surface,
GdkDragContext *
_gdk_wayland_drop_context_new (GdkDevice *device,
struct wl_data_device *data_device)
_gdk_wayland_drop_context_new (GdkDevice *device,
GdkContentFormats *formats,
struct wl_data_offer *offer)
{
GdkWaylandDragContext *context_wayland;
GdkDragContext *context;
@@ -526,27 +512,12 @@ _gdk_wayland_drop_context_new (GdkDevice *device,
NULL);
context = GDK_DRAG_CONTEXT (context_wayland);
context->is_source = FALSE;
context->formats = gdk_content_formats_new (NULL, 0);
context->formats = formats;
context_wayland->offer = offer;
return context;
}
void
gdk_wayland_drop_context_update_targets (GdkDragContext *context)
{
GdkDisplay *display;
GdkDevice *device;
device = gdk_drag_context_get_device (context);
display = gdk_device_get_display (device);
gdk_content_formats_unref (context->formats);
context->formats = gdk_wayland_selection_get_targets (display);
if (context->formats)
gdk_content_formats_ref (context->formats);
else
context->formats = gdk_content_formats_new (NULL, 0);
}
void
_gdk_wayland_drag_context_set_coords (GdkDragContext *context,
gdouble x,
@@ -579,7 +550,6 @@ _gdk_wayland_drag_context_set_dest_surface (GdkDragContext *context,
context->dest_surface = dest_surface ? g_object_ref (dest_surface) : NULL;
GDK_WAYLAND_DRAG_CONTEXT (context)->serial = serial;
gdk_wayland_drop_context_update_targets (context);
}
GdkDragContext *

View File

@@ -105,7 +105,8 @@ void _gdk_wayland_surface_offset_next_wl_buffer (GdkSurface *surface,
int x,
int y);
GdkDragContext * _gdk_wayland_drop_context_new (GdkDevice *device,
struct wl_data_device *data_device);
GdkContentFormats *formats,
struct wl_data_offer *offer);
void _gdk_wayland_drag_context_set_source_surface (GdkDragContext *context,
GdkSurface *surface);
void _gdk_wayland_drag_context_set_dest_surface (GdkDragContext *context,
@@ -125,8 +126,6 @@ GdkDragContext * gdk_wayland_drag_context_lookup_by_data_source (struct wl_dat
GdkDragContext * gdk_wayland_drag_context_lookup_by_source_surface (GdkSurface *surface);
struct wl_data_source * gdk_wayland_drag_context_get_data_source (GdkDragContext *context);
void gdk_wayland_drop_context_update_targets (GdkDragContext *context);
void _gdk_wayland_display_create_surface_impl (GdkDisplay *display,
GdkSurface *surface,
GdkSurface *real_parent,
@@ -198,21 +197,8 @@ GdkWaylandSelection * gdk_wayland_selection_new (void);
void gdk_wayland_selection_free (GdkWaylandSelection *selection);
void gdk_wayland_selection_ensure_offer (GdkDisplay *display,
struct wl_data_offer *wl_offer);
void gdk_wayland_selection_ensure_primary_offer (GdkDisplay *display,
struct gtk_primary_selection_offer *wp_offer);
GdkContentFormats *gdk_wayland_selection_steal_offer (GdkDisplay *display, gpointer wl_offer);
void gdk_wayland_selection_set_offer (GdkDisplay *display,
gpointer offer);
gpointer gdk_wayland_selection_get_offer (GdkDisplay *display);
GdkContentFormats *gdk_wayland_selection_get_targets (GdkDisplay *display);
struct wl_data_source * gdk_wayland_selection_get_data_source (GdkSurface *owner);
void gdk_wayland_selection_unset_data_source (GdkDisplay *display);
gboolean gdk_wayland_selection_set_current_offer_actions (GdkDisplay *display,
uint32_t actions);
EGLSurface gdk_wayland_surface_get_egl_surface (GdkSurface *surface,
EGLConfig config);

View File

@@ -33,52 +33,11 @@
#include <string.h>
typedef struct _SelectionData SelectionData;
typedef struct _DataOfferData DataOfferData;
struct _DataOfferData
{
GDestroyNotify destroy_notify;
gpointer offer_data;
GdkContentFormats *targets;
};
struct _SelectionData
{
DataOfferData *offer;
};
struct _GdkWaylandSelection
{
/* Destination-side data */
SelectionData selection;
GHashTable *offers; /* Currently alive offers, Hashtable of wl_data_offer->DataOfferData */
struct wl_data_source *dnd_source; /* Owned by the GdkDragContext */
};
static DataOfferData *
data_offer_data_new (gpointer offer,
GDestroyNotify destroy_notify)
{
DataOfferData *info;
info = g_slice_new0 (DataOfferData);
info->offer_data = offer;
info->destroy_notify = destroy_notify;
info->targets = gdk_content_formats_new (NULL, 0);
return info;
}
static void
data_offer_data_free (DataOfferData *info)
{
info->destroy_notify (info->offer_data);
gdk_content_formats_unref (info->targets);
g_slice_free (DataOfferData, info);
}
GdkWaylandSelection *
gdk_wayland_selection_new (void)
{
@@ -86,47 +45,18 @@ gdk_wayland_selection_new (void)
selection = g_new0 (GdkWaylandSelection, 1);
selection->offers =
g_hash_table_new_full (NULL, NULL, NULL,
(GDestroyNotify) data_offer_data_free);
return selection;
}
void
gdk_wayland_selection_free (GdkWaylandSelection *selection)
{
g_hash_table_destroy (selection->offers);
if (selection->dnd_source)
wl_data_source_destroy (selection->dnd_source);
g_free (selection);
}
static void
data_offer_offer (void *data,
struct wl_data_offer *wl_data_offer,
const char *type)
{
GdkWaylandSelection *selection = data;
GdkContentFormatsBuilder *builder;
DataOfferData *info;
info = g_hash_table_lookup (selection->offers, wl_data_offer);
if (!info || gdk_content_formats_contain_mime_type (info->targets, type))
return;
GDK_NOTE (EVENTS,
g_message ("data offer offer, offer %p, type = %s", wl_data_offer, type));
builder = gdk_content_formats_builder_new ();
gdk_content_formats_builder_add_formats (builder, info->targets);
gdk_content_formats_builder_add_mime_type (builder, type);
gdk_content_formats_unref (info->targets);
info->targets = gdk_content_formats_builder_free_to_formats (builder);
}
static inline GdkDragAction
_wl_to_gdk_actions (uint32_t dnd_actions)
{
@@ -142,158 +72,6 @@ _wl_to_gdk_actions (uint32_t dnd_actions)
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);
if (drop_context == NULL)
return;
drop_context->actions = _wl_to_gdk_actions (source_actions);
GDK_DISPLAY_NOTE (display, EVENTS,
g_message ("data offer source actions, offer %p, actions %d", wl_data_offer, source_actions));
_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);
if (drop_context == NULL)
return;
drop_context->action = _wl_to_gdk_actions (action);
_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
};
static SelectionData *
selection_lookup_offer_by_atom (GdkWaylandSelection *selection)
{
return &selection->selection;
}
void
gdk_wayland_selection_ensure_offer (GdkDisplay *display,
struct wl_data_offer *wl_offer)
{
GdkWaylandSelection *selection = gdk_wayland_display_get_selection (display);
DataOfferData *info;
info = g_hash_table_lookup (selection->offers, wl_offer);
if (!info)
{
info = data_offer_data_new (wl_offer,
(GDestroyNotify) wl_data_offer_destroy);
g_hash_table_insert (selection->offers, wl_offer, info);
wl_data_offer_add_listener (wl_offer,
&data_offer_listener,
selection);
}
}
GdkContentFormats *
gdk_wayland_selection_steal_offer (GdkDisplay *display,
gpointer wl_offer)
{
GdkWaylandSelection *selection = gdk_wayland_display_get_selection (display);
GdkContentFormats *formats;
DataOfferData *info;
info = g_hash_table_lookup (selection->offers, wl_offer);
if (info == NULL)
return NULL;
g_hash_table_steal (selection->offers, wl_offer);
formats = info->targets;
g_slice_free (DataOfferData, info);
return formats;
}
void
gdk_wayland_selection_set_offer (GdkDisplay *display,
gpointer wl_offer)
{
GdkWaylandSelection *selection = gdk_wayland_display_get_selection (display);
struct wl_data_offer *prev_offer;
SelectionData *selection_data;
DataOfferData *info;
info = g_hash_table_lookup (selection->offers, wl_offer);
prev_offer = gdk_wayland_selection_get_offer (display);
if (prev_offer)
g_hash_table_remove (selection->offers, prev_offer);
selection_data = selection_lookup_offer_by_atom (selection);
if (selection_data)
{
selection_data->offer = info;
}
}
gpointer
gdk_wayland_selection_get_offer (GdkDisplay *display)
{
GdkWaylandSelection *selection = gdk_wayland_display_get_selection (display);
const SelectionData *data;
data = selection_lookup_offer_by_atom (selection);
if (data && data->offer)
return data->offer->offer_data;
return NULL;
}
GdkContentFormats *
gdk_wayland_selection_get_targets (GdkDisplay *display)
{
GdkWaylandSelection *selection = gdk_wayland_display_get_selection (display);
const SelectionData *data;
data = selection_lookup_offer_by_atom (selection);
if (data && data->offer)
return data->offer->targets;
return NULL;
}
static void
data_source_target (void *data,
struct wl_data_source *source,
@@ -565,26 +343,3 @@ _gdk_wayland_display_utf8_to_string_target (GdkDisplay *display,
return sanitize_utf8 (str, TRUE);
}
gboolean
gdk_wayland_selection_set_current_offer_actions (GdkDisplay *display,
uint32_t action)
{
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
struct wl_data_offer *offer;
uint32_t all_actions = 0;
offer = gdk_wayland_selection_get_offer (display);
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;
if (display_wayland->data_device_manager_version >=
WL_DATA_OFFER_SET_ACTIONS_SINCE_VERSION)
wl_data_offer_set_actions (offer, all_actions, action);
return TRUE;
}