diff options
author | Carlos Garnacho <carlosg@gnome.org> | 2014-08-21 20:20:37 +0200 |
---|---|---|
committer | Carlos Garnacho <carlosg@gnome.org> | 2014-09-01 19:17:53 +0200 |
commit | 9b0b88d16b5fa16b0265e5bbbea97a79a1dd7cf5 (patch) | |
tree | 4e6f90f674e480edcc23fb04771209355d472866 /gdk/wayland/gdkdnd-wayland.c | |
parent | f48b3cce024b04df08ef5fa3d8360688e1f910b7 (diff) | |
download | gtk+-9b0b88d16b5fa16b0265e5bbbea97a79a1dd7cf5.tar.gz |
wayland: Implement the dropping part of DnD
All destination-side events are emitted, and updates to the drop context
are notified through the currently handled wl_data_offer.
https://bugzilla.gnome.org/show_bug.cgi?id=697855
Diffstat (limited to 'gdk/wayland/gdkdnd-wayland.c')
-rw-r--r-- | gdk/wayland/gdkdnd-wayland.c | 184 |
1 files changed, 180 insertions, 4 deletions
diff --git a/gdk/wayland/gdkdnd-wayland.c b/gdk/wayland/gdkdnd-wayland.c index 34ea3cddb5..099a95ae1b 100644 --- a/gdk/wayland/gdkdnd-wayland.c +++ b/gdk/wayland/gdkdnd-wayland.c @@ -40,6 +40,10 @@ typedef struct _GdkWaylandDragContextClass GdkWaylandDragContextClass; struct _GdkWaylandDragContext { GdkDragContext context; + struct wl_data_offer *offer; + uint32_t serial; + gdouble x; + gdouble y; }; struct _GdkWaylandDragContextClass @@ -54,13 +58,58 @@ G_DEFINE_TYPE (GdkWaylandDragContext, gdk_wayland_drag_context, GDK_TYPE_DRAG_CO static void gdk_wayland_drag_context_finalize (GObject *object) { + GdkWaylandDragContext *wayland_context = GDK_WAYLAND_DRAG_CONTEXT (object); GdkDragContext *context = GDK_DRAG_CONTEXT (object); contexts = g_list_remove (contexts, context); + if (wayland_context->data_source) + wl_data_source_destroy (wayland_context->data_source); + + if (wayland_context->dnd_window) + gdk_window_destroy (wayland_context->dnd_window); + G_OBJECT_CLASS (gdk_wayland_drag_context_parent_class)->finalize (object); } +void +_gdk_wayland_drag_context_emit_event (GdkDragContext *context, + GdkEventType type, + guint32 time_) +{ + GdkWindow *window; + GdkEvent *event; + + switch (type) + { + case GDK_DRAG_ENTER: + case GDK_DRAG_LEAVE: + case GDK_DRAG_MOTION: + case GDK_DRAG_STATUS: + case GDK_DROP_START: + case GDK_DROP_FINISHED: + break; + default: + return; + } + + if (context->is_source) + window = gdk_drag_context_get_source_window (context); + else + window = gdk_drag_context_get_dest_window (context); + + event = gdk_event_new (type); + event->dnd.window = g_object_ref (window); + event->dnd.context = g_object_ref (context); + event->dnd.time = time_; + event->dnd.x_root = GDK_WAYLAND_DRAG_CONTEXT (context)->x; + event->dnd.y_root = GDK_WAYLAND_DRAG_CONTEXT (context)->y; + gdk_event_set_device (event, gdk_drag_context_get_device (context)); + + gdk_event_put (event); + gdk_event_free (event); +} + static GdkWindow * gdk_wayland_drag_context_find_window (GdkDragContext *context, GdkWindow *drag_window, @@ -69,9 +118,29 @@ gdk_wayland_drag_context_find_window (GdkDragContext *context, gint y_root, GdkDragProtocol *protocol) { + GdkDevice *device; + GdkWindow *window; + + device = gdk_drag_context_get_device (context); + window = gdk_device_get_window_at_position (device, NULL, NULL); + + if (window) + { + window = gdk_window_get_toplevel (window); + *protocol = GDK_DRAG_PROTO_WAYLAND; + return g_object_ref (window); + } + return NULL; } +void +gdk_wayland_drag_context_set_action (GdkDragContext *context, + GdkDragAction action) +{ + context->suggested_action = context->action = action; +} + static gboolean gdk_wayland_drag_context_drag_motion (GdkDragContext *context, GdkWindow *dest_window, @@ -82,7 +151,16 @@ gdk_wayland_drag_context_drag_motion (GdkDragContext *context, GdkDragAction possible_actions, guint32 time) { - return FALSE; + if (context->dest_window != dest_window) + { + context->dest_window = dest_window ? g_object_ref (dest_window) : NULL; + _gdk_wayland_drag_context_set_coords (context, x_root, y_root); + _gdk_wayland_drag_context_emit_event (context, GDK_DRAG_STATUS, time); + } + + gdk_wayland_drag_context_set_action (context, suggested_action); + + return context->dest_window != NULL; } static void @@ -100,10 +178,45 @@ gdk_wayland_drag_context_drag_drop (GdkDragContext *context, /* Destination side */ static void +gdk_wayland_drop_context_set_status (GdkDragContext *context, + gboolean accepted) +{ + GdkWaylandDragContext *context_wayland; + struct wl_data_offer *wl_offer; + + context_wayland = GDK_WAYLAND_DRAG_CONTEXT (context); + wl_offer = gdk_wayland_selection_get_offer (); + + if (!wl_offer) + return; + + if (accepted) + { + GList *l; + + for (l = context->targets; l; l = l->next) + { + if (l->data != gdk_atom_intern_static_string ("DELETE")) + break; + } + + if (l) + { + wl_data_offer_accept (wl_offer, context_wayland->serial, + gdk_atom_name (l->data)); + return; + } + } + + wl_data_offer_accept (wl_offer, context_wayland->serial, NULL); +} + +static void gdk_wayland_drag_context_drag_status (GdkDragContext *context, GdkDragAction action, guint32 time_) { + gdk_wayland_drop_context_set_status (context, action != 0); } static void @@ -111,6 +224,7 @@ gdk_wayland_drag_context_drop_reply (GdkDragContext *context, gboolean accepted, guint32 time_) { + gdk_wayland_drop_context_set_status (context, accepted); } static void @@ -129,13 +243,20 @@ gdk_wayland_drag_context_drop_status (GdkDragContext *context) static GdkAtom gdk_wayland_drag_context_get_selection (GdkDragContext *context) { - return GDK_NONE; + return gdk_atom_intern_static_string ("GdkWaylandSelection"); } static void -gdk_wayland_drag_context_init (GdkWaylandDragContext *context) +gdk_wayland_drag_context_init (GdkWaylandDragContext *context_wayland) { + GdkDragContext *context; + + context = GDK_DRAG_CONTEXT (context_wayland); contexts = g_list_prepend (contexts, context); + + context->action = GDK_ACTION_COPY; + context->suggested_action = GDK_ACTION_COPY; + context->actions = GDK_ACTION_COPY | GDK_ACTION_MOVE; } static void @@ -160,7 +281,7 @@ gdk_wayland_drag_context_class_init (GdkWaylandDragContextClass *klass) GdkDragProtocol _gdk_wayland_window_get_drag_protocol (GdkWindow *window, GdkWindow **target) { - return 0; + return GDK_DRAG_PROTO_WAYLAND; } void @@ -183,3 +304,58 @@ _gdk_wayland_window_drag_begin (GdkWindow *window, return context; } + +GdkDragContext * +_gdk_wayland_drop_context_new (GdkDevice *device, + struct wl_data_device *data_device) +{ + GdkWaylandDragContext *context_wayland; + GdkDragContext *context; + + context_wayland = g_object_new (GDK_TYPE_WAYLAND_DRAG_CONTEXT, NULL); + context = GDK_DRAG_CONTEXT (context_wayland); + context->is_source = FALSE; + + gdk_drag_context_set_device (context, device); + + return context; +} + +void +gdk_wayland_drop_context_update_targets (GdkDragContext *context) +{ + g_list_free (context->targets); + context->targets = g_list_copy (gdk_wayland_selection_get_targets ()); +} + +void +_gdk_wayland_drag_context_set_coords (GdkDragContext *context, + gdouble x, + gdouble y) +{ + GdkWaylandDragContext *context_wayland; + + context_wayland = GDK_WAYLAND_DRAG_CONTEXT (context); + context_wayland->x = x; + context_wayland->y = y; +} + +void +_gdk_wayland_drag_context_set_source_window (GdkDragContext *context, + GdkWindow *window) +{ + if (context->source_window) + g_object_unref (context->source_window); + + context->source_window = window ? g_object_ref (window) : NULL; +} + +void +_gdk_wayland_drag_context_set_dest_window (GdkDragContext *context, + GdkWindow *dest_window, + uint32_t serial) +{ + context->dest_window = dest_window ? g_object_ref (dest_window) : NULL; + GDK_WAYLAND_DRAG_CONTEXT (context)->serial = serial; + gdk_wayland_drop_context_update_targets (context); +} |