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:
@@ -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,
|
||||
|
||||
@@ -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 *
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user