mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-25 21:21:21 +00:00
wayland: Implement drag sources
The wl_data_source is retrieved from the selection object for the DnD selection, and used to initiate a drag. When the drag is finished, a button release or touch end event is synthesized to finish the DnD operation after the compositor grab is gone. https://bugzilla.gnome.org/show_bug.cgi?id=697855
This commit is contained in:
parent
9b0b88d16b
commit
7b85a3417a
@ -523,7 +523,7 @@ data_device_enter (void *data,
|
||||
struct wl_data_offer *offer)
|
||||
{
|
||||
GdkWaylandDeviceData *device = (GdkWaylandDeviceData *)data;
|
||||
GdkWindow *dest_window;
|
||||
GdkWindow *dest_window, *dnd_owner;
|
||||
|
||||
dest_window = wl_surface_get_user_data (surface);
|
||||
|
||||
@ -539,6 +539,12 @@ data_device_enter (void *data,
|
||||
device->surface_y = wl_fixed_to_double (y);
|
||||
|
||||
gdk_wayland_drop_context_update_targets (device->drop_context);
|
||||
|
||||
dnd_owner = gdk_selection_owner_get (gdk_drag_get_selection (device->drop_context));
|
||||
|
||||
if (dnd_owner)
|
||||
_gdk_wayland_drag_context_set_source_window (device->drop_context, dnd_owner);
|
||||
|
||||
_gdk_wayland_drag_context_set_dest_window (device->drop_context,
|
||||
dest_window, serial);
|
||||
_gdk_wayland_drag_context_set_coords (device->drop_context,
|
||||
@ -601,10 +607,21 @@ data_device_drop (void *data,
|
||||
struct wl_data_device *data_device)
|
||||
{
|
||||
GdkWaylandDeviceData *device = (GdkWaylandDeviceData *) data;
|
||||
GdkWindow *local_dnd_owner;
|
||||
|
||||
g_debug (G_STRLOC ": %s data_device = %p",
|
||||
G_STRFUNC, data_device);
|
||||
|
||||
local_dnd_owner = gdk_selection_owner_get (gdk_drag_get_selection (device->drop_context));
|
||||
|
||||
if (local_dnd_owner)
|
||||
{
|
||||
GdkDragContext *source_context;
|
||||
|
||||
source_context = gdk_wayland_drag_context_lookup_by_source_window (local_dnd_owner);
|
||||
gdk_wayland_drag_context_undo_grab (source_context);
|
||||
}
|
||||
|
||||
_gdk_wayland_drag_context_emit_event (device->drop_context,
|
||||
GDK_DROP_START, GDK_CURRENT_TIME);
|
||||
}
|
||||
|
@ -40,6 +40,9 @@ typedef struct _GdkWaylandDragContextClass GdkWaylandDragContextClass;
|
||||
struct _GdkWaylandDragContext
|
||||
{
|
||||
GdkDragContext context;
|
||||
GdkWindow *dnd_window;
|
||||
struct wl_surface *dnd_surface;
|
||||
struct wl_data_source *data_source;
|
||||
struct wl_data_offer *offer;
|
||||
uint32_t serial;
|
||||
gdouble x;
|
||||
@ -63,6 +66,10 @@ gdk_wayland_drag_context_finalize (GObject *object)
|
||||
|
||||
contexts = g_list_remove (contexts, context);
|
||||
|
||||
if (context->is_source &&
|
||||
gdk_selection_owner_get (gdk_drag_get_selection (context)) == context->source_window)
|
||||
gdk_wayland_selection_unset_data_source (gdk_drag_get_selection (context));
|
||||
|
||||
if (wayland_context->data_source)
|
||||
wl_data_source_destroy (wayland_context->data_source);
|
||||
|
||||
@ -232,6 +239,8 @@ gdk_wayland_drag_context_drop_finish (GdkDragContext *context,
|
||||
gboolean success,
|
||||
guint32 time)
|
||||
{
|
||||
if (gdk_selection_owner_get (gdk_drag_get_selection (context)))
|
||||
gdk_wayland_selection_unset_data_source (gdk_drag_get_selection (context));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@ -289,18 +298,63 @@ _gdk_wayland_window_register_dnd (GdkWindow *window)
|
||||
{
|
||||
}
|
||||
|
||||
static GdkWindow *
|
||||
create_dnd_window (void)
|
||||
{
|
||||
GdkWindowAttr attrs;
|
||||
GdkScreen *screen;
|
||||
guint mask;
|
||||
|
||||
screen = gdk_display_get_default_screen (gdk_display_get_default ());
|
||||
|
||||
attrs.x = attrs.y = 0;
|
||||
attrs.width = attrs.height = 100;
|
||||
attrs.wclass = GDK_INPUT_OUTPUT;
|
||||
attrs.window_type = GDK_WINDOW_TEMP;
|
||||
attrs.type_hint = GDK_WINDOW_TYPE_HINT_DND;
|
||||
attrs.visual = gdk_screen_get_system_visual (screen);
|
||||
|
||||
mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_TYPE_HINT;
|
||||
|
||||
return gdk_window_new (gdk_screen_get_root_window (screen), &attrs, mask);
|
||||
}
|
||||
|
||||
GdkDragContext *
|
||||
_gdk_wayland_window_drag_begin (GdkWindow *window,
|
||||
GdkDevice *device,
|
||||
GList *targets)
|
||||
{
|
||||
GdkWaylandDragContext *context_wayland;
|
||||
GdkWaylandDisplay *display_wayland;
|
||||
GdkDragContext *context;
|
||||
GdkWindow *toplevel;
|
||||
GList *l;
|
||||
|
||||
context = (GdkDragContext *) g_object_new (GDK_TYPE_WAYLAND_DRAG_CONTEXT, NULL);
|
||||
context->source_window = window;
|
||||
toplevel = gdk_device_get_window_at_position (device, NULL, NULL);
|
||||
|
||||
context_wayland = g_object_new (GDK_TYPE_WAYLAND_DRAG_CONTEXT, NULL);
|
||||
context = GDK_DRAG_CONTEXT (context_wayland);
|
||||
context->source_window = g_object_ref (window);
|
||||
context->is_source = TRUE;
|
||||
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 ();
|
||||
context_wayland->dnd_surface = gdk_wayland_window_get_wl_surface (context_wayland->dnd_window);
|
||||
context_wayland->data_source =
|
||||
gdk_wayland_selection_get_data_source (window,
|
||||
gdk_wayland_drag_context_get_selection (context));
|
||||
|
||||
for (l = context->targets; l; l = l->next)
|
||||
wl_data_source_offer (context_wayland->data_source, gdk_atom_name (l->data));
|
||||
|
||||
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;
|
||||
}
|
||||
@ -359,3 +413,92 @@ _gdk_wayland_drag_context_set_dest_window (GdkDragContext *context,
|
||||
GDK_WAYLAND_DRAG_CONTEXT (context)->serial = serial;
|
||||
gdk_wayland_drop_context_update_targets (context);
|
||||
}
|
||||
|
||||
GdkDragContext *
|
||||
gdk_wayland_drag_context_lookup_by_data_source (struct wl_data_source *source)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
for (l = contexts; l; l = l->next)
|
||||
{
|
||||
GdkWaylandDragContext *wayland_context = l->data;
|
||||
|
||||
if (wayland_context->data_source == source)
|
||||
return l->data;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GdkDragContext *
|
||||
gdk_wayland_drag_context_lookup_by_source_window (GdkWindow *window)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
for (l = contexts; l; l = l->next)
|
||||
{
|
||||
if (window == gdk_drag_context_get_source_window (l->data))
|
||||
return l->data;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wl_data_source *
|
||||
gdk_wayland_drag_context_get_data_source (GdkDragContext *context)
|
||||
{
|
||||
return GDK_WAYLAND_DRAG_CONTEXT (context)->data_source;
|
||||
}
|
||||
|
||||
void
|
||||
gdk_wayland_drag_context_undo_grab (GdkDragContext *context)
|
||||
{
|
||||
GdkEventSequence *sequence;
|
||||
GdkModifierType state;
|
||||
GdkDevice *device;
|
||||
GdkEvent *event;
|
||||
guint button;
|
||||
gdouble x, y;
|
||||
|
||||
device = gdk_drag_context_get_device (context);
|
||||
_gdk_wayland_device_get_last_implicit_grab_serial (GDK_WAYLAND_DEVICE (device), &sequence);
|
||||
gdk_window_get_device_position_double (gdk_drag_context_get_source_window (context),
|
||||
device, &x, &y, &state);
|
||||
|
||||
if (sequence)
|
||||
{
|
||||
event = gdk_event_new (GDK_TOUCH_END);
|
||||
event->touch.window = g_object_ref (gdk_drag_context_get_source_window (context));
|
||||
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 (gdk_drag_context_get_source_window (context));
|
||||
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.x_root = y;
|
||||
}
|
||||
else
|
||||
return;
|
||||
|
||||
gdk_event_set_device (event, device);
|
||||
gdk_event_set_source_device (event, device);
|
||||
|
||||
_gdk_wayland_display_deliver_event (gdk_device_get_display (device), event);
|
||||
}
|
||||
|
@ -109,6 +109,12 @@ void _gdk_wayland_drag_context_set_coords (GdkDragContext *context,
|
||||
void gdk_wayland_drag_context_set_action (GdkDragContext *context,
|
||||
GdkDragAction action);
|
||||
|
||||
GdkDragContext * gdk_wayland_drag_context_lookup_by_data_source (struct wl_data_source *source);
|
||||
GdkDragContext * gdk_wayland_drag_context_lookup_by_source_window (GdkWindow *window);
|
||||
struct wl_data_source * gdk_wayland_drag_context_get_data_source (GdkDragContext *context);
|
||||
|
||||
void gdk_wayland_drag_context_undo_grab (GdkDragContext *context);
|
||||
|
||||
void gdk_wayland_drop_context_update_targets (GdkDragContext *context);
|
||||
|
||||
void _gdk_wayland_display_create_window_impl (GdkDisplay *display,
|
||||
|
@ -500,17 +500,32 @@ data_source_target (void *data,
|
||||
const char *mime_type)
|
||||
{
|
||||
GdkWaylandSelection *wayland_selection = data;
|
||||
GdkDragContext *context;
|
||||
GdkDragContext *context = NULL;
|
||||
GdkWindow *window;
|
||||
|
||||
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)
|
||||
return;
|
||||
{
|
||||
if (context)
|
||||
{
|
||||
gdk_wayland_drag_context_set_action (context, 0);
|
||||
_gdk_wayland_drag_context_emit_event (context, GDK_DRAG_STATUS,
|
||||
GDK_CURRENT_TIME);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (source == wayland_selection->dnd_source)
|
||||
window = wayland_selection->dnd_owner;
|
||||
{
|
||||
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);
|
||||
}
|
||||
else if (source == wayland_selection->clipboard_source)
|
||||
window = wayland_selection->clipboard_owner;
|
||||
else
|
||||
@ -528,6 +543,7 @@ 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",
|
||||
@ -536,6 +552,8 @@ data_source_send (void *data,
|
||||
if (!mime_type)
|
||||
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)
|
||||
@ -548,6 +566,13 @@ data_source_send (void *data,
|
||||
fd))
|
||||
gdk_wayland_selection_check_write (wayland_selection);
|
||||
|
||||
if (context)
|
||||
{
|
||||
gdk_wayland_drag_context_undo_grab (context);
|
||||
_gdk_wayland_drag_context_emit_event (context, GDK_DROP_FINISHED,
|
||||
GDK_CURRENT_TIME);
|
||||
}
|
||||
|
||||
wayland_selection->source_requested_target = GDK_NONE;
|
||||
}
|
||||
|
||||
@ -556,14 +581,20 @@ data_source_cancelled (void *data,
|
||||
struct wl_data_source *source)
|
||||
{
|
||||
GdkWaylandSelection *wayland_selection = data;
|
||||
GdkDragContext *context;
|
||||
|
||||
g_debug (G_STRLOC ": %s source = %p",
|
||||
G_STRFUNC, source);
|
||||
|
||||
context = gdk_wayland_drag_context_lookup_by_data_source (source);
|
||||
|
||||
if (source == wayland_selection->dnd_source)
|
||||
gdk_wayland_selection_unset_data_source (atoms[ATOM_DND]);
|
||||
else if (source == wayland_selection->clipboard_source)
|
||||
gdk_wayland_selection_unset_data_source (atoms[ATOM_CLIPBOARD]);
|
||||
|
||||
if (context)
|
||||
gdk_wayland_drag_context_undo_grab (context);
|
||||
}
|
||||
|
||||
static const struct wl_data_source_listener data_source_listener = {
|
||||
|
Loading…
Reference in New Issue
Block a user