From dfb2cbdfdbea6b0ea1e132fe9f7ca61fe2cb8ce5 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sun, 5 Jan 2020 22:53:53 -0500 Subject: [PATCH] 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. --- gtk/gtkdnd.c | 140 +++++++--------------------------- gtk/gtkdndprivate.h | 14 ++++ gtk/gtkdragdest.c | 178 +++++++++++++++++++++++++++++++++----------- 3 files changed, 176 insertions(+), 156 deletions(-) diff --git a/gtk/gtkdnd.c b/gtk/gtkdnd.c index eda5c11f6f..eff878ed03 100644 --- a/gtk/gtkdnd.c +++ b/gtk/gtkdnd.c @@ -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; -} diff --git a/gtk/gtkdndprivate.h b/gtk/gtkdndprivate.h index ad829e05b7..b316a9fded 100644 --- a/gtk/gtkdndprivate.h +++ b/gtk/gtkdndprivate.h @@ -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__ */ diff --git a/gtk/gtkdragdest.c b/gtk/gtkdragdest.c index 4ad84fbe2f..cd12f995ed 100644 --- a/gtk/gtkdragdest.c +++ b/gtk/gtkdragdest.c @@ -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 },