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;
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,
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
{
GdkWaylandSeat *seat = data;
GdkSurface *dest_surface, *dnd_owner;
+ GdkContentFormats *formats;
GdkDevice *device;
dest_surface = wl_surface_get_user_data (surface);
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));
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;
_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
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));
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,
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;
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;
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);
}
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
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;
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);
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);
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;
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,
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 *
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,
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,
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);
#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)
{
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)
{
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,
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;
-}