Turn GtkDropTarget into an event controller

We are still propagating the drag events manually,
but we are now calling gtk_widget_run_controllers
to pass them to drop targets.
This commit is contained in:
Matthias Clasen 2020-01-05 22:53:53 -05:00
parent f960eb6ab4
commit dfb2cbdfdb
3 changed files with 176 additions and 156 deletions

View File

@ -63,26 +63,9 @@
*/
typedef struct _GtkDragDestInfo GtkDragDestInfo;
struct _GtkDragDestInfo
{
GtkWidget *widget; /* Widget in which drag is in */
GdkDrop *drop; /* drop */
};
/* Forward declarations */
static GtkWidget *gtk_drop_find_widget (GtkWidget *widget,
static gboolean gtk_drop_find_widget (GtkWidget *widget,
GdkEvent *event);
static void gtk_drag_dest_leave (GtkWidget *widget,
GdkDrop *drop);
static gboolean gtk_drop_target_handle_event (GtkDropTarget *dest,
GdkEvent *event);
static void gtk_drag_dest_set_widget (GtkDragDestInfo *info,
GtkWidget *widget);
static GtkDragDestInfo * gtk_drag_get_dest_info (GdkDrop *drop,
gboolean create);
/*
@ -116,41 +99,17 @@ _gtk_drag_dest_handle_event (GtkWidget *toplevel,
break;
case GDK_DRAG_LEAVE:
if (info->widget)
if (info->dest)
{
gtk_drag_dest_leave (info->widget, drop);
gtk_drag_dest_set_widget (info, NULL);
gtk_drop_target_emit_drag_leave (info->dest, drop);
gtk_drag_dest_set_target (info, NULL);
}
break;
case GDK_DRAG_MOTION:
case GDK_DROP_START:
{
GtkWidget *widget;
if (event_type == GDK_DROP_START)
{
/* We send a leave here so that the widget unhighlights
* properly.
*/
if (info->widget)
{
gtk_drag_dest_leave (info->widget, drop);
gtk_drag_dest_set_widget (info, NULL);
}
}
widget = gtk_drop_find_widget (toplevel, event);
if (info->widget && info->widget != widget)
{
gtk_drag_dest_leave (info->widget, drop);
gtk_drag_dest_set_widget (info, NULL);
}
if (widget)
gtk_drag_dest_set_widget (info, widget);
else
if (!gtk_drop_find_widget (toplevel, event))
gdk_drop_status (drop, 0);
}
break;
@ -160,7 +119,7 @@ _gtk_drag_dest_handle_event (GtkWidget *toplevel,
}
}
static GtkWidget *
static gboolean
gtk_drop_find_widget (GtkWidget *event_widget,
GdkEvent *event)
{
@ -170,26 +129,25 @@ gtk_drop_find_widget (GtkWidget *event_widget,
if (!gtk_widget_get_mapped (event_widget) ||
!gtk_widget_get_sensitive (event_widget))
return NULL;
return FALSE;
gdk_event_get_coords (event, &x, &y);
widget = gtk_widget_pick (event_widget, x, y, GTK_PICK_DEFAULT);
if (!widget)
return NULL;
return FALSE;
gtk_widget_translate_coordinates (event_widget, widget, x, y, &wx, &wy);
while (widget)
{
GtkDropTarget *dest;
GtkWidget *parent;
GList *hierarchy = NULL;
gboolean found = FALSE;
if (!gtk_widget_get_mapped (widget))
return NULL;
return FALSE;
if (gtk_widget_get_state_flags (widget) & GTK_STATE_FLAG_INSENSITIVE)
{
@ -207,17 +165,9 @@ gtk_drop_find_widget (GtkWidget *event_widget,
hierarchy = g_list_prepend (hierarchy, g_object_ref (parent));
}
/* If the current widget is registered as a drop site, check to
* emit "drag-motion" to check if we are actually in a drop
* site.
*/
dest = gtk_drop_target_get (widget);
if (dest)
{
gdk_event_set_coords (event, wx, wy);
found = gtk_drop_target_handle_event (dest, event);
gdk_event_set_coords (event, x, y);
}
gdk_event_set_coords (event, wx, wy);
found = gtk_widget_run_controllers (widget, event, GTK_PHASE_BUBBLE);
gdk_event_set_coords (event, x, y);
if (!found)
{
@ -236,33 +186,33 @@ gtk_drop_find_widget (GtkWidget *event_widget,
g_list_free_full (hierarchy, g_object_unref);
if (found)
return widget;
return TRUE;
if (parent)
g_object_remove_weak_pointer (G_OBJECT (parent), (gpointer *) &parent);
else
return NULL;
return FALSE;
if (!gtk_widget_translate_coordinates (widget, parent, wx, wy, &wx, &wy))
return NULL;
return FALSE;
widget = parent;
}
return NULL;
return FALSE;
}
static void
gtk_drag_dest_set_widget (GtkDragDestInfo *info,
GtkWidget *widget)
void
gtk_drag_dest_set_target (GtkDragDestInfo *info,
GtkDropTarget *dest)
{
if (info->widget)
g_object_remove_weak_pointer (G_OBJECT (info->widget), (gpointer *) &info->widget);
if (info->dest)
g_object_remove_weak_pointer (G_OBJECT (info->dest), (gpointer *) &info->dest);
info->widget = widget;
info->dest = dest;
if (info->widget)
g_object_add_weak_pointer (G_OBJECT (info->widget), (gpointer *) &info->widget);
if (info->dest)
g_object_add_weak_pointer (G_OBJECT (info->dest), (gpointer *) &info->dest);
}
static void
@ -270,12 +220,12 @@ gtk_drag_dest_info_destroy (gpointer data)
{
GtkDragDestInfo *info = (GtkDragDestInfo *)data;
gtk_drag_dest_set_widget (info, NULL);
gtk_drag_dest_set_target (info, NULL);
g_slice_free (GtkDragDestInfo, data);
}
static GtkDragDestInfo *
GtkDragDestInfo *
gtk_drag_get_dest_info (GdkDrop *drop,
gboolean create)
{
@ -295,41 +245,3 @@ gtk_drag_get_dest_info (GdkDrop *drop,
return info;
}
/*
* Default drag handlers
*/
static void
gtk_drag_dest_leave (GtkWidget *widget,
GdkDrop *drop)
{
GtkDropTarget *dest;
dest = gtk_drop_target_get (widget);
g_return_if_fail (dest != NULL);
gtk_drop_target_emit_drag_leave (dest, drop);
}
static gboolean
gtk_drop_target_handle_event (GtkDropTarget *dest,
GdkEvent *event)
{
GdkDrop *drop;
double x, y;
drop = gdk_event_get_drop (event);
gdk_event_get_coords (event, &x, &y);
switch ((int)gdk_event_get_event_type (event))
{
case GDK_DRAG_MOTION:
return gtk_drop_target_emit_drag_motion (dest, drop, x, y);
case GDK_DROP_START:
return gtk_drop_target_emit_drag_drop (dest, drop, x, y);
default:
break;
}
return FALSE;
}

View File

@ -20,6 +20,7 @@
#define __GTK_DND_PRIVATE_H__
#include "gtkwidget.h"
#include "gtkdragdest.h"
G_BEGIN_DECLS
@ -27,6 +28,19 @@ G_BEGIN_DECLS
void _gtk_drag_dest_handle_event (GtkWidget *toplevel,
GdkEvent *event);
typedef struct _GtkDragDestInfo GtkDragDestInfo;
struct _GtkDragDestInfo
{
GtkDropTarget *dest;
GdkDrop *drop; /* drop */
};
GtkDragDestInfo * gtk_drag_get_dest_info (GdkDrop *drop,
gboolean create);
void gtk_drag_dest_set_target (GtkDragDestInfo *info,
GtkDropTarget *dest);
G_END_DECLS
#endif /* __GTK_DND_PRIVATE_H__ */

View File

@ -31,7 +31,7 @@
#include "gtkintl.h"
#include "gtknative.h"
#include "gtktypebuiltins.h"
#include "gtkeventcontroller.h"
#include "gtkeventcontrollerprivate.h"
#include "gtkmarshalers.h"
#include "gtkselectionprivate.h"
@ -51,7 +51,7 @@
struct _GtkDropTarget
{
GObject parent_instance;
GtkEventController parent_object;
GdkContentFormats *formats;
GdkDragAction actions;
@ -64,7 +64,7 @@ struct _GtkDropTarget
struct _GtkDropTargetClass
{
GObjectClass parent_class;
GtkEventControllerClass parent_class;
gboolean (*drag_motion) (GtkDropTarget *dest,
int x,
@ -94,7 +94,15 @@ static gboolean gtk_drop_target_drag_motion (GtkDropTarget *dest,
int x,
int y);
G_DEFINE_TYPE (GtkDropTarget, gtk_drop_target, G_TYPE_OBJECT);
static gboolean gtk_drop_target_handle_event (GtkEventController *controller,
const GdkEvent *event);
static gboolean gtk_drop_target_filter_event (GtkEventController *controller,
const GdkEvent *event);
static void gtk_drop_target_set_widget (GtkEventController *controller,
GtkWidget *widget);
static void gtk_drop_target_unset_widget (GtkEventController *controller);
G_DEFINE_TYPE (GtkDropTarget, gtk_drop_target, GTK_TYPE_EVENT_CONTROLLER);
static void
gtk_drop_target_init (GtkDropTarget *dest)
@ -165,11 +173,17 @@ static void
gtk_drop_target_class_init (GtkDropTargetClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkEventControllerClass *controller_class = GTK_EVENT_CONTROLLER_CLASS (class);
object_class->finalize = gtk_drop_target_finalize;
object_class->set_property = gtk_drop_target_set_property;
object_class->get_property = gtk_drop_target_get_property;
controller_class->handle_event = gtk_drop_target_handle_event;
controller_class->filter_event = gtk_drop_target_filter_event;
controller_class->set_widget = gtk_drop_target_set_widget;
controller_class->unset_widget = gtk_drop_target_unset_widget;
class->drag_motion = gtk_drop_target_drag_motion;
/**
@ -445,28 +459,11 @@ void
gtk_drop_target_attach (GtkDropTarget *dest,
GtkWidget *widget)
{
GtkDropTarget *old_dest;
g_return_if_fail (GTK_IS_DROP_TARGET (dest));
g_return_if_fail (dest->widget == NULL);
g_return_if_fail (GTK_IS_WIDGET (widget));
old_dest = g_object_get_data (G_OBJECT (widget), I_("gtk-drag-dest"));
if (old_dest)
{
g_signal_handlers_disconnect_by_func (widget, gtk_drag_dest_realized, old_dest);
g_signal_handlers_disconnect_by_func (widget, gtk_drag_dest_hierarchy_changed, old_dest);
}
if (gtk_widget_get_realized (widget))
gtk_drag_dest_realized (widget);
dest->widget = widget;
g_signal_connect (widget, "realize", G_CALLBACK (gtk_drag_dest_realized), dest);
g_signal_connect (widget, "notify::root", G_CALLBACK (gtk_drag_dest_hierarchy_changed), dest);
g_object_set_data_full (G_OBJECT (widget), I_("gtk-drag-dest"), dest, g_object_unref);
gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (dest), GTK_PHASE_BUBBLE);
gtk_widget_add_controller (widget, GTK_EVENT_CONTROLLER (dest));
}
/**
@ -478,17 +475,12 @@ gtk_drop_target_attach (GtkDropTarget *dest,
void
gtk_drop_target_detach (GtkDropTarget *dest)
{
GtkWidget *widget;
g_return_if_fail (GTK_IS_DROP_TARGET (dest));
if (dest->widget)
{
g_signal_handlers_disconnect_by_func (dest->widget, gtk_drag_dest_realized, dest);
g_signal_handlers_disconnect_by_func (dest->widget, gtk_drag_dest_hierarchy_changed, dest);
g_object_set_data (G_OBJECT (dest->widget), I_("gtk-drag-dest"), NULL);
dest->widget = NULL;
}
widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
gtk_widget_remove_controller (widget, GTK_EVENT_CONTROLLER (dest));
}
/**
@ -504,7 +496,7 @@ gtk_drop_target_get_target (GtkDropTarget *dest)
{
g_return_val_if_fail (GTK_IS_DROP_TARGET (dest), NULL);
return dest->widget;
return gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
}
/**
@ -650,6 +642,10 @@ void
gtk_drop_target_set_armed (GtkDropTarget *dest,
gboolean armed)
{
GtkWidget *widget;
widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
dest->armed_pending = FALSE;
if (dest->armed == armed)
@ -657,13 +653,10 @@ gtk_drop_target_set_armed (GtkDropTarget *dest,
dest->armed = armed;
if (dest->widget)
{
if (armed)
gtk_drag_highlight (dest->widget);
else
gtk_drag_unhighlight (dest->widget);
}
if (armed)
gtk_drag_highlight (widget);
else
gtk_drag_unhighlight (widget);
g_object_notify_by_pspec (G_OBJECT (dest), properties[PROP_ARMED]);
}
@ -674,6 +667,104 @@ gtk_drop_target_get_armed (GtkDropTarget *dest)
return dest->armed;
}
static gboolean
gtk_drop_target_filter_event (GtkEventController *controller,
const GdkEvent *event)
{
switch ((int)gdk_event_get_event_type (event))
{
case GDK_DRAG_ENTER:
case GDK_DRAG_LEAVE:
case GDK_DRAG_MOTION:
case GDK_DROP_START:
return GTK_EVENT_CONTROLLER_CLASS (gtk_drop_target_parent_class)->filter_event (controller, event);
default:;
}
return TRUE;
}
static gboolean
gtk_drop_target_handle_event (GtkEventController *controller,
const GdkEvent *event)
{
GtkDropTarget *dest = GTK_DROP_TARGET (controller);
GdkDrop *drop;
GtkDragDestInfo *info;
double x, y;
gboolean found = FALSE;
gdk_event_get_coords (event, &x, &y);
drop = gdk_event_get_drop (event);
info = gtk_drag_get_dest_info (drop, TRUE);
switch ((int)gdk_event_get_event_type (event))
{
case GDK_DRAG_MOTION:
found = gtk_drop_target_emit_drag_motion (dest, drop, x, y);
break;
case GDK_DROP_START:
/* We send a leave before the drop so that the widget unhighlights
* properly.
*/
if (info->dest)
{
gtk_drop_target_emit_drag_leave (info->dest, drop);
gtk_drag_dest_set_target (info, NULL);
}
found = gtk_drop_target_emit_drag_drop (dest, drop, x, y);
break;
default:
break;
}
if (found)
{
if (info->dest && info->dest != dest)
{
gtk_drop_target_emit_drag_leave (info->dest, drop);
gtk_drag_dest_set_target (info, NULL);
}
gtk_drag_dest_set_target (info, dest);
}
return found;
}
static void
gtk_drop_target_set_widget (GtkEventController *controller,
GtkWidget *widget)
{
GtkDropTarget *dest = GTK_DROP_TARGET (controller);
GTK_EVENT_CONTROLLER_CLASS (gtk_drop_target_parent_class)->set_widget (controller, widget);
if (gtk_widget_get_realized (widget))
gtk_drag_dest_realized (widget);
g_signal_connect (widget, "realize", G_CALLBACK (gtk_drag_dest_realized), dest);
g_signal_connect (widget, "notify::root", G_CALLBACK (gtk_drag_dest_hierarchy_changed), dest);
}
static void
gtk_drop_target_unset_widget (GtkEventController *controller)
{
GtkWidget *widget;
widget = gtk_event_controller_get_widget (controller);
g_signal_handlers_disconnect_by_func (widget, gtk_drag_dest_realized, controller);
g_signal_handlers_disconnect_by_func (widget, gtk_drag_dest_hierarchy_changed, controller);
GTK_EVENT_CONTROLLER_CLASS (gtk_drop_target_parent_class)->unset_widget (controller);
}
/**
* gtk_drag_highlight: (method)
* @widget: a widget to highlight
@ -810,13 +901,16 @@ gtk_drop_target_read_selection (GtkDropTarget *dest,
gpointer user_data)
{
GTask *task;
GtkWidget *widget;
g_return_if_fail (GTK_IS_DROP_TARGET (dest));
task = g_task_new (dest, NULL, callback, user_data);
g_object_set_data_full (G_OBJECT (task), "drop", g_object_ref (dest->drop), g_object_unref);
if (dest->widget)
g_object_set_data (G_OBJECT (task), "display", gtk_widget_get_display (dest->widget));
widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
if (widget)
g_object_set_data (G_OBJECT (task), "display", gtk_widget_get_display (widget));
gdk_drop_read_async (dest->drop,
(const char *[2]) { target, NULL },