[gtk/dnd-gestures-2: 31/66] Add a GtkDropTarget object
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/dnd-gestures-2: 31/66] Add a GtkDropTarget object
- Date: Sat, 4 Jan 2020 14:29:58 +0000 (UTC)
commit 032ba316859816d628c5672aa66d05a67f5ba53f
Author: Matthias Clasen <mclasen redhat com>
Date: Tue Dec 31 01:54:43 2019 -0500
Add a GtkDropTarget object
Add an explicit GtkDropTarget object, and move the destination-side
DND signals here. The object is used by connecting to its signals
and attaching it to a widget with gtk_drop_target_attach().
gtk/gtkdnd.c | 89 +++---
gtk/gtkdndprivate.h | 4 +-
gtk/gtkdragdest.c | 699 ++++++++++++++++++++++++++++++++++++++++++++---
gtk/gtkdragdest.h | 69 ++++-
gtk/gtkdragdestprivate.h | 46 ++++
gtk/gtkdragsource.c | 10 +-
6 files changed, 838 insertions(+), 79 deletions(-)
---
diff --git a/gtk/gtkdnd.c b/gtk/gtkdnd.c
index 20bcb774e1..dc6e5d8cfe 100644
--- a/gtk/gtkdnd.c
+++ b/gtk/gtkdnd.c
@@ -26,7 +26,7 @@
#include "gtkdndprivate.h"
-#include "gtkdragdest.h"
+#include "gtkdragdestprivate.h"
#include "gtkimageprivate.h"
#include "gtkintl.h"
#include "gtkmain.h"
@@ -111,6 +111,7 @@ static GtkDragDestInfo * gtk_drag_get_dest_info (GdkDrop *drop,
* Destination side *
********************/
+
typedef struct {
GdkDrop *drop;
GtkWidget *widget;
@@ -124,6 +125,9 @@ gtk_drag_get_data_finish (GtkDragGetData *data,
{
GtkDragDestSite *site;
GtkSelectionData sdata;
+ GdkContentFormats *target_list = NULL;
+ GdkDragAction actions = 0;
+ GtkDestDefaults flags = 0;
site = g_object_get_data (G_OBJECT (data->widget), "gtk-drag-dest");
@@ -133,30 +137,30 @@ gtk_drag_get_data_finish (GtkDragGetData *data,
sdata.length = size;
sdata.data = bytes ? bytes : (guchar *)g_strdup ("");
sdata.display = gtk_widget_get_display (data->widget);
-
- if (site && site->target_list)
+
+ if (site)
+ {
+ target_list = gtk_drop_target_get_formats (site->dest);
+ actions = gtk_drop_target_get_actions (site->dest);
+ flags = gtk_drop_target_get_defaults (site->dest);
+ }
+
+ if (target_list)
{
- if (gdk_content_formats_contain_mime_type (site->target_list, data->mime_type))
+ if (gdk_content_formats_contain_mime_type (target_list, data->mime_type))
{
- if (!(site->flags & GTK_DEST_DEFAULT_DROP) ||
- size >= 0)
- g_signal_emit_by_name (data->widget,
- "drag-data-received",
- data->drop,
- &sdata);
+ if (!(flags & GTK_DEST_DEFAULT_DROP) || size >= 0)
+ gtk_drop_target_emit_drag_data_received (site->dest, data->drop, &sdata);
}
}
else
{
- g_signal_emit_by_name (data->widget,
- "drag-data-received",
- data->drop,
- &sdata);
+ gtk_drop_target_emit_drag_data_received (site->dest, data->drop, &sdata);
}
- if (site && site->flags & GTK_DEST_DEFAULT_DROP)
+ if (flags & GTK_DEST_DEFAULT_DROP)
{
- GdkDragAction action = site->actions & gdk_drop_get_actions (data->drop);
+ GdkDragAction action = actions & gdk_drop_get_actions (data->drop);
if (size == 0)
action = 0;
@@ -535,16 +539,20 @@ gtk_drag_dest_leave (GtkWidget *widget,
guint time)
{
GtkDragDestSite *site;
+ GtkDestDefaults flags;
+ gboolean track_motion;
site = g_object_get_data (G_OBJECT (widget), "gtk-drag-dest");
g_return_if_fail (site != NULL);
- if ((site->flags & GTK_DEST_DEFAULT_HIGHLIGHT) && site->have_drag)
+ flags = gtk_drop_target_get_defaults (site->dest);
+ track_motion = gtk_drop_target_get_track_motion (site->dest);
+
+ if ((flags & GTK_DEST_DEFAULT_HIGHLIGHT) && site->have_drag)
gtk_drag_unhighlight (widget);
- if (!(site->flags & GTK_DEST_DEFAULT_MOTION) || site->have_drag ||
- site->track_motion)
- g_signal_emit_by_name (widget, "drag-leave", drop, time);
+ if (!(flags & GTK_DEST_DEFAULT_MOTION) || site->have_drag || track_motion)
+ gtk_drop_target_emit_drag_leave (site->dest, drop, time);
site->have_drag = FALSE;
}
@@ -557,43 +565,52 @@ gtk_drag_dest_motion (GtkWidget *widget,
guint time)
{
GtkDragDestSite *site;
+ GdkDragAction dest_actions;
+ GtkDestDefaults flags;
+ gboolean track_motion;
gboolean retval;
site = g_object_get_data (G_OBJECT (widget), "gtk-drag-dest");
g_return_val_if_fail (site != NULL, FALSE);
- if (site->track_motion || site->flags & GTK_DEST_DEFAULT_MOTION)
+ dest_actions = gtk_drop_target_get_actions (site->dest);
+ flags = gtk_drop_target_get_defaults (site->dest);
+ track_motion = gtk_drop_target_get_track_motion (site->dest);
+
+ if (track_motion || flags & GTK_DEST_DEFAULT_MOTION)
{
GdkDragAction actions;
+ GdkAtom target;
actions = gdk_drop_get_actions (drop);
- if ((actions & site->actions) == 0)
+ if ((dest_actions & actions) == 0)
actions = 0;
- if (actions && gtk_drag_dest_find_target (widget, drop, NULL))
+ target = gtk_drop_target_match (site->dest, drop);
+
+ if (actions && target)
{
if (!site->have_drag)
{
site->have_drag = TRUE;
- if (site->flags & GTK_DEST_DEFAULT_HIGHLIGHT)
+ if (flags & GTK_DEST_DEFAULT_HIGHLIGHT)
gtk_drag_highlight (widget);
}
- gdk_drop_status (drop, site->actions);
+ gdk_drop_status (drop, dest_actions);
}
else
{
gdk_drop_status (drop, 0);
- if (!site->track_motion)
+ if (!track_motion)
return TRUE;
}
}
- g_signal_emit_by_name (widget, "drag-motion",
- drop, x, y, &retval);
+ retval = gtk_drop_target_emit_drag_motion (site->dest, drop, x, y);
- return (site->flags & GTK_DEST_DEFAULT_MOTION) ? TRUE : retval;
+ return (flags & GTK_DEST_DEFAULT_MOTION) ? TRUE : retval;
}
static gboolean
@@ -605,17 +622,22 @@ gtk_drag_dest_drop (GtkWidget *widget,
{
GtkDragDestSite *site;
GtkDragDestInfo *info;
+ GtkDestDefaults flags;
gboolean retval;
site = g_object_get_data (G_OBJECT (widget), "gtk-drag-dest");
g_return_val_if_fail (site != NULL, FALSE);
+ flags = gtk_drop_target_get_defaults (site->dest);
+
info = gtk_drag_get_dest_info (drop, FALSE);
g_return_val_if_fail (info != NULL, FALSE);
- if (site->flags & GTK_DEST_DEFAULT_DROP)
+ if (flags & GTK_DEST_DEFAULT_DROP)
{
- GdkAtom target = gtk_drag_dest_find_target (widget, drop, NULL);
+ GdkAtom target;
+
+ target = gtk_drop_target_match (site->dest, drop);
if (target == NULL)
{
@@ -626,8 +648,7 @@ gtk_drag_dest_drop (GtkWidget *widget,
gtk_drag_get_data (widget, drop, target);
}
- g_signal_emit_by_name (widget, "drag-drop",
- drop, x, y, &retval);
+ retval = gtk_drop_target_emit_drag_drop (site->dest, drop, x, y);
- return (site->flags & GTK_DEST_DEFAULT_DROP) ? TRUE : retval;
+ return (flags & GTK_DEST_DEFAULT_DROP) ? TRUE : retval;
}
diff --git a/gtk/gtkdndprivate.h b/gtk/gtkdndprivate.h
index 45448a17e2..65dce27d7e 100644
--- a/gtk/gtkdndprivate.h
+++ b/gtk/gtkdndprivate.h
@@ -29,13 +29,11 @@
typedef struct _GtkDragDestSite GtkDragDestSite;
struct _GtkDragDestSite
{
+ GtkDropTarget *dest;
GtkDestDefaults flags;
- GdkContentFormats *target_list;
- GdkDragAction actions;
guint do_proxy : 1;
guint proxy_coords : 1;
guint have_drag : 1;
- guint track_motion : 1;
};
G_BEGIN_DECLS
diff --git a/gtk/gtkdragdest.c b/gtk/gtkdragdest.c
index da2205e09d..f158b3acf2 100644
--- a/gtk/gtkdragdest.c
+++ b/gtk/gtkdragdest.c
@@ -25,11 +25,15 @@
#include "config.h"
#include "gtkdragdest.h"
+#include "gtkdragdestprivate.h"
#include "gtkdnd.h"
#include "gtkdndprivate.h"
#include "gtkintl.h"
#include "gtknative.h"
+#include "gtktypebuiltins.h"
+#include "gtkeventcontroller.h"
+#include "gtkmarshalers.h"
static void
@@ -56,8 +60,7 @@ gtk_drag_dest_site_destroy (gpointer data)
{
GtkDragDestSite *site = data;
- if (site->target_list)
- gdk_content_formats_unref (site->target_list);
+ g_clear_object (&site->dest);
g_slice_free (GtkDragDestSite, site);
}
@@ -71,23 +74,16 @@ gtk_drag_dest_set_internal (GtkWidget *widget,
old_site = g_object_get_data (G_OBJECT (widget), I_("gtk-drag-dest"));
if (old_site)
{
- g_signal_handlers_disconnect_by_func (widget,
- gtk_drag_dest_realized,
- old_site);
- g_signal_handlers_disconnect_by_func (widget,
- gtk_drag_dest_hierarchy_changed,
- old_site);
-
- site->track_motion = old_site->track_motion;
+ g_signal_handlers_disconnect_by_func (widget, gtk_drag_dest_realized, old_site);
+ g_signal_handlers_disconnect_by_func (widget, gtk_drag_dest_hierarchy_changed, old_site);
+ gtk_drop_target_set_track_motion (site->dest, gtk_drop_target_get_track_motion (old_site->dest));
}
if (gtk_widget_get_realized (widget))
gtk_drag_dest_realized (widget);
- g_signal_connect (widget, "realize",
- G_CALLBACK (gtk_drag_dest_realized), site);
- g_signal_connect (widget, "notify::root",
- G_CALLBACK (gtk_drag_dest_hierarchy_changed), site);
+ g_signal_connect (widget, "realize", G_CALLBACK (gtk_drag_dest_realized), site);
+ g_signal_connect (widget, "notify::root", G_CALLBACK (gtk_drag_dest_hierarchy_changed), site);
g_object_set_data_full (G_OBJECT (widget), I_("gtk-drag-dest"),
site, gtk_drag_dest_site_destroy);
@@ -142,7 +138,7 @@ gtk_drag_dest_set_internal (GtkWidget *widget,
* }
* ]|
*/
-void
+GtkDropTarget *
gtk_drag_dest_set (GtkWidget *widget,
GtkDestDefaults flags,
GdkContentFormats *targets,
@@ -150,20 +146,16 @@ gtk_drag_dest_set (GtkWidget *widget,
{
GtkDragDestSite *site;
- g_return_if_fail (GTK_IS_WIDGET (widget));
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
site = g_slice_new0 (GtkDragDestSite);
- site->flags = flags;
+ site->dest = gtk_drop_target_new (flags, targets, actions);
site->have_drag = FALSE;
- if (targets)
- site->target_list = gdk_content_formats_ref (targets);
- else
- site->target_list = NULL;
- site->actions = actions;
- site->track_motion = FALSE;
gtk_drag_dest_set_internal (widget, site);
+
+ return site->dest;
}
/**
@@ -213,7 +205,7 @@ gtk_drag_dest_get_target_list (GtkWidget *widget)
site = g_object_get_data (G_OBJECT (widget), I_("gtk-drag-dest"));
- return site ? site->target_list : NULL;
+ return site ? gtk_drop_target_get_formats (site->dest) : NULL;
}
/**
@@ -242,13 +234,7 @@ gtk_drag_dest_set_target_list (GtkWidget *widget,
return;
}
- if (target_list)
- gdk_content_formats_ref (target_list);
-
- if (site->target_list)
- gdk_content_formats_unref (site->target_list);
-
- site->target_list = target_list;
+ gtk_drop_target_set_formats (site->dest, target_list);
}
/**
@@ -350,7 +336,7 @@ gtk_drag_dest_set_track_motion (GtkWidget *widget,
g_return_if_fail (site != NULL);
- site->track_motion = track_motion != FALSE;
+ gtk_drop_target_set_track_motion (site->dest, track_motion);
}
/**
@@ -373,7 +359,7 @@ gtk_drag_dest_get_track_motion (GtkWidget *widget)
site = g_object_get_data (G_OBJECT (widget), I_("gtk-drag-dest"));
if (site)
- return site->track_motion;
+ return gtk_drop_target_get_track_motion (site->dest);
return FALSE;
}
@@ -414,3 +400,650 @@ gtk_drag_dest_find_target (GtkWidget *widget,
gdk_drop_get_formats (drop));
}
+
+/**
+ * SECTION:gtkdragdest
+ * @Short_description: An object to receive DND drops
+ * @Title: GtkDropTarget
+ *
+ * GtkDropTarget is an auxiliary object that is used to receive
+ * Drag-and-Drop operations.
+ *
+ * To use a GtkDropTarget to receive drops on a widget, you create
+ * a GtkDropTarget object, connect to its signals, and then attach
+ * it to the widgtet with gtk_drop_target_attach().
+ */
+
+struct _GtkDropTarget
+{
+ GObject parent_instance;
+
+ GdkContentFormats *formats;
+ GdkDragAction actions;
+ GtkDestDefaults defaults;
+ gboolean track_motion;
+
+ GtkWidget *widget;
+ GdkDrop *drop;
+};
+
+struct _GtkDropTargetClass
+{
+ GObjectClass parent_class;
+};
+
+enum {
+ PROP_FORMATS = 1,
+ PROP_ACTIONS,
+ PROP_DEFAULTS,
+ PROP_TRACK_MOTION,
+ NUM_PROPERTIES
+};
+
+static GParamSpec *properties[NUM_PROPERTIES];
+
+enum {
+ DRAG_LEAVE,
+ DRAG_MOTION,
+ DRAG_DROP,
+ DRAG_DATA_RECEIVED,
+ NUM_SIGNALS
+};
+
+static guint signals[NUM_SIGNALS];
+
+G_DEFINE_TYPE (GtkDropTarget, gtk_drop_target, G_TYPE_OBJECT);
+
+static void
+gtk_drop_target_init (GtkDropTarget *dest)
+{
+ dest->defaults = GTK_DEST_DEFAULT_ALL;
+}
+
+static void
+gtk_drop_target_finalize (GObject *object)
+{
+ GtkDropTarget *dest = GTK_DROP_TARGET (object);
+
+ g_clear_pointer (&dest->formats, gdk_content_formats_unref);
+
+ G_OBJECT_CLASS (gtk_drop_target_parent_class)->finalize (object);
+}
+
+static void
+gtk_drop_target_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GtkDropTarget *dest = GTK_DROP_TARGET (object);
+
+ switch (prop_id)
+ {
+ case PROP_FORMATS:
+ gtk_drop_target_set_formats (dest, g_value_get_boxed (value));
+ break;
+
+ case PROP_ACTIONS:
+ gtk_drop_target_set_actions (dest, g_value_get_flags (value));
+ break;
+
+ case PROP_DEFAULTS:
+ gtk_drop_target_set_defaults (dest, g_value_get_flags (value));
+ break;
+
+ case PROP_TRACK_MOTION:
+ gtk_drop_target_set_track_motion (dest, g_value_get_boolean (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gtk_drop_target_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GtkDropTarget *dest = GTK_DROP_TARGET (object);
+
+ switch (prop_id)
+ {
+ case PROP_FORMATS:
+ g_value_set_boxed (value, gtk_drop_target_get_formats (dest));
+ break;
+
+ case PROP_ACTIONS:
+ g_value_set_flags (value, gtk_drop_target_get_actions (dest));
+ break;
+
+ case PROP_DEFAULTS:
+ g_value_set_flags (value, gtk_drop_target_get_defaults (dest));
+ break;
+
+ case PROP_TRACK_MOTION:
+ g_value_set_boolean (value, gtk_drop_target_get_track_motion (dest));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gtk_drop_target_class_init (GtkDropTargetClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_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;
+
+ /**
+ * GtkDropTarget:formats:
+ *
+ * The #GdkContentFormats that determines the supported data formats
+ */
+ properties[PROP_FORMATS] =
+ g_param_spec_boxed ("formats", P_("Formats"), P_("Formats"),
+ GDK_TYPE_CONTENT_FORMATS,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
+ /**
+ * GtkDropTarget:actions:
+ *
+ * The #GdkDragActions that this drop are supported
+ */
+ properties[PROP_ACTIONS] =
+ g_param_spec_flags ("actions", P_("Actions"), P_("Actions"),
+ GDK_TYPE_DRAG_ACTION, 0,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
+ /**
+ * GtkDropTargets:defaults:
+ *
+ * Flags that determine the default behavior
+ */
+ properties[PROP_DEFAULTS] =
+ g_param_spec_flags ("defaults", P_("Defaults"), P_("Defaults"),
+ GTK_TYPE_DEST_DEFAULTS, GTK_DEST_DEFAULT_ALL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
+ /**
+ * GtkDropTarget:track-motion:
+ *
+ * Whether the drop target should emit #GtkDropTarget::drag-motion signals
+ * unconditionally
+ */
+ properties[PROP_TRACK_MOTION] =
+ g_param_spec_boolean ("track-motion", P_("Track motion"), P_("Track motion"),
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
+ g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
+
+ /**
+ * GtkDropTarget::drag-leave:
+ * @dest: the #GtkDropTarget
+ *
+ * The ::drag-leave signal is emitted on the drop site when the cursor
+ * leaves the widget. A typical reason to connect to this signal is to
+ * undo things done in #GtkDropTarget::drag-motion, e.g. undo highlighting.
+ *
+ * Likewise, the #GtkWidget::drag-leave signal is also emitted before the
+ * #GtkDropTarget::drag-drop signal, for instance to allow cleaning up of
+ * a preview item created in the #GtkDropTarget::drag-motion signal handler.
+ */
+ signals[DRAG_LEAVE] =
+ g_signal_new (I_("drag-leave"),
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE, 0);
+
+ /**
+ * GtkWidget::drag-motion:
+ * @dest: the #GtkDropTarget
+ * @x: the x coordinate of the current cursor position
+ * @y: the y coordinate of the current cursor position
+ *
+ * The ::drag-motion signal is emitted on the drop site when the user
+ * moves the cursor over the widget during a drag. The signal handler
+ * must determine whether the cursor position is in a drop zone or not.
+ * If it is not in a drop zone, it returns %FALSE and no further processing
+ * is necessary. Otherwise, the handler returns %TRUE. In this case, the
+ * handler is responsible for providing the necessary information for
+ * displaying feedback to the user, by calling gdk_drag_status().
+ *
+ * If the decision whether the drop will be accepted or rejected can't be
+ * made based solely on the cursor position and the type of the data, the
+ * handler may inspect the dragged data by calling one of the #GdkDrop
+ * read functions, and defer the gdk_drag_status() call to when it has
+ * received th data.
+ *
+ * Note that you must pass #GTK_DEST_DEFAULT_DROP,
+ * #GTK_DEST_DEFAULT_MOTION or #GTK_DEST_DEFAULT_ALL to gtk_drag_dest_set()
+ * when using the ::drag-motion signal that way.
+ *
+ * Also note that there is no drag-enter signal. The drag receiver has to
+ * keep track of whether he has received any drag-motion signals since the
+ * last #GtkWidget::drag-leave and if not, treat the drag-motion signal as
+ * an "enter" signal. Upon an "enter", the handler will typically highlight
+ * the drop site with gtk_drag_highlight().
+ *
+ * Returns: whether the cursor position is in a drop zone
+ */
+ signals[DRAG_MOTION] =
+ g_signal_new (I_("drag-motion"),
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ NULL,
+ G_TYPE_BOOLEAN, 2,
+ G_TYPE_INT, G_TYPE_INT);
+
+ /**
+ * GtkDropTarget::drag-drop:
+ * @dest: the #GtkDropTarget
+ * @x: the x coordinate of the current cursor position
+ * @y: the y coordinate of the current cursor position
+ *
+ * The ::drag-drop signal is emitted on the drop site when the user drops
+ * the data onto the widget. The signal handler must determine whether
+ * the cursor position is in a drop zone or not. If it is not in a drop
+ * zone, it returns %FALSE and no further processing is necessary.
+ *
+ * Otherwise, the handler returns %TRUE. In this case, the handler must
+ * ensure that gdk_drop_finish() is called to let the source know that
+ * the drop is done. The call to gtk_drag_finish() can be done either
+ * directly or after receiving the data.
+ *
+ * Returns: whether the cursor position is in a drop zone
+ */
+ signals[DRAG_DROP] =
+ g_signal_new (I_("drag-drop"),
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ NULL,
+ G_TYPE_BOOLEAN, 2,
+ G_TYPE_INT, G_TYPE_INT);
+
+ signals[DRAG_DATA_RECEIVED] =
+ g_signal_new (I_("drag-data-received"),
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ _gtk_marshal_VOID__BOXED,
+ G_TYPE_NONE, 1,
+ GTK_TYPE_SELECTION_DATA | G_SIGNAL_TYPE_STATIC_SCOPE);
+ g_signal_set_va_marshaller (signals[DRAG_DATA_RECEIVED],
+ G_TYPE_FROM_CLASS (class),
+ _gtk_marshal_VOID__BOXEDv);
+}
+
+/**
+ * gtk_drop_target_new:
+ * @defaults: flags determining the default behaviour
+ * @formats: (nullable): the supported data formats
+ * @actions: the supported actions
+ *
+ * Creates a new #GtkDropTarget object
+ *
+ * Returns: the new #GtkDropTarget
+ */
+GtkDropTarget *
+gtk_drop_target_new (GtkDestDefaults defaults,
+ GdkContentFormats *formats,
+ GdkDragAction actions)
+{
+ return g_object_new (GTK_TYPE_DROP_TARGET,
+ "defaults", defaults,
+ "formats", formats,
+ "actions", actions,
+ NULL);
+}
+
+/**
+ * gtk_drop_target_set_formats:
+ * @dest: a #GtkDropTarget
+ * @formats: (nullable): the supported data formats
+ *
+ * Sets th data formats that this drop target will accept.
+ */
+void
+gtk_drop_target_set_formats (GtkDropTarget *dest,
+ GdkContentFormats *formats)
+{
+ g_return_if_fail (GTK_IS_DROP_TARGET (dest));
+
+ if (dest->formats == formats)
+ return;
+
+ if (dest->formats)
+ gdk_content_formats_unref (dest->formats);
+
+ dest->formats = formats;
+
+ if (dest->formats)
+ gdk_content_formats_ref (dest->formats);
+
+ g_object_notify_by_pspec (G_OBJECT (dest), properties[PROP_FORMATS]);
+}
+
+/**
+ * gtk_drop_target_get_formats:
+ * @dest: a #GtkDropTarget
+ *
+ * Gets the data formats that this drop target accepts.
+ *
+ * Returns: the supported data formats
+ */
+GdkContentFormats *
+gtk_drop_target_get_formats (GtkDropTarget *dest)
+{
+ g_return_val_if_fail (GTK_IS_DROP_TARGET (dest), NULL);
+
+ return dest->formats;
+}
+
+/**
+ * gtk_drop_target_set_actions:
+ * @dest: a #GtkDropTarget
+ * @actions: the supported actions
+ *
+ * Sets the actions that this drop target supports.
+ */
+void
+gtk_drop_target_set_actions (GtkDropTarget *dest,
+ GdkDragAction actions)
+{
+ g_return_if_fail (GTK_IS_DROP_TARGET (dest));
+
+ if (dest->actions == actions)
+ return;
+
+ dest->actions = actions;
+
+ g_object_notify_by_pspec (G_OBJECT (dest), properties[PROP_ACTIONS]);
+}
+
+/**
+ * gtk_drop_target_get_actions:
+ * @dst: a #GtkDropTarget
+ *
+ * Gets the actions that this drop target supports.
+ *
+ * Returns: the actions that this drop target supports
+ */
+GdkDragAction
+gtk_drop_target_get_actions (GtkDropTarget *dest)
+{
+ g_return_val_if_fail (GTK_IS_DROP_TARGET (dest), 0);
+
+ return dest->actions;
+}
+
+/**
+ * gtk_drop_target_set_defaults:
+ * @dest: a #GtkDropTarget
+ * @defaults: flags determining the default behaviour
+ *
+ * Sets the flags determining the behavior of the drop target.
+ */
+void
+gtk_drop_target_set_defaults (GtkDropTarget *dest,
+ GtkDestDefaults defaults)
+{
+ g_return_if_fail (GTK_IS_DROP_TARGET (dest));
+
+ if (dest->defaults == defaults)
+ return;
+
+ dest->defaults = defaults;
+
+ g_object_notify_by_pspec (G_OBJECT (dest), properties[PROP_DEFAULTS]);
+}
+
+/**
+ * gtk_drop_target_get_defaults:
+ * @dest: a #GtkDropTarget
+ *
+ * Gets the flags determining the behavior of the drop target.
+ *
+ * Returns: flags determining the behaviour of the drop target
+ */
+GtkDestDefaults
+gtk_drop_target_get_defaults (GtkDropTarget *dest)
+{
+ g_return_val_if_fail (GTK_IS_DROP_TARGET (dest), GTK_DEST_DEFAULT_ALL);
+
+ return dest->defaults;
+}
+
+/**
+ * gtk_drop_target_set_track_motion:
+ * @dest: a #GtkDropTarget
+ * @track_motion: whether to accept all targets
+ *
+ * Tells the drop target to emit #GtkDropTarget::drag-motion and
+ * #GtkDropTarget::drag-leave events regardless of the targets and
+ * the %GTK_DEST_DEFAULT_MOTION flag.
+ *
+ * This may be used when a drop target wants to do generic
+ * actions regardless of the targets that the source offers.
+ */
+void
+gtk_drop_target_set_track_motion (GtkDropTarget *dest,
+ gboolean track_motion)
+{
+ g_return_if_fail (GTK_IS_DROP_TARGET (dest));
+
+ if (dest->track_motion == track_motion)
+ return;
+
+ dest->track_motion = track_motion;
+
+ g_object_notify_by_pspec (G_OBJECT (dest), properties[PROP_TRACK_MOTION]);
+}
+
+/**
+ * gtk_drop_target_get_track_motion:
+ * @dest: a #GtkDropTarget
+ *
+ * Gets the value of the #GtkDropTarget::track-motion property.
+ *
+ * Returns: whether to accept all targets
+ */
+gboolean
+gtk_drop_target_get_track_motion (GtkDropTarget *dest)
+{
+ g_return_val_if_fail (GTK_IS_DROP_TARGET (dest), FALSE);
+
+ return dest->track_motion;
+}
+
+/**
+ * gtk_drop_target_attach:
+ * @dest: (transfer full): a #GtkDropTarget
+ * @widget the widget to attach @dest to
+ *
+ * Attaches the @dest to widget and makes it accept drops
+ * on the widgets.
+ *
+ * To undo the effect of this call, use gtk_drop_target_detach().
+ */
+void
+gtk_drop_target_attach (GtkDropTarget *dest,
+ GtkWidget *widget)
+{
+ GtkDragDestSite *site;
+
+ g_return_if_fail (GTK_IS_DROP_TARGET (dest));
+ g_return_if_fail (dest->widget == NULL);
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+ dest->widget = widget;
+
+ site = g_slice_new0 (GtkDragDestSite);
+
+ site->dest = dest;
+ site->have_drag = FALSE;
+
+ gtk_drag_dest_set_internal (widget, site);
+}
+
+/**
+ * gtk_drop_target_detach:
+ * @dest: a #GtkDropTarget
+ *
+ * Undoes the effect of a prior gtk_drop_target_attach() call.
+ */
+void
+gtk_drop_target_detach (GtkDropTarget *dest)
+{
+ g_return_if_fail (GTK_IS_DROP_TARGET (dest));
+
+ if (dest->widget)
+ {
+ gtk_drag_dest_unset (dest->widget);
+ dest->widget = NULL;
+ }
+}
+
+/**
+ * gtk_drop_target_get_target:
+ * @dest: a #GtkDropTarget
+ *
+ * Gts the widget that the drop target is attached to.
+ *
+ * Returns: (nullable): get the widget that @dest is attached to
+ */
+GtkWidget *
+gtk_drop_target_get_target (GtkDropTarget *dest)
+{
+ g_return_val_if_fail (GTK_IS_DROP_TARGET (dest), NULL);
+
+ return dest->widget;
+}
+
+/**
+ * gtk_drop_target_get_drop:
+ * @dest: a #GtkDropTarget
+ *
+ * Returns the underlying #GtkDrop object for an ongoing drag.
+ *
+ * Returns: (nullable): the #GtkDrop of the current drag operation, or %NULL
+ */
+GdkDrop *
+gtk_drop_target_get_drop (GtkDropTarget *dest)
+{
+ g_return_val_if_fail (GTK_IS_DROP_TARGET (dest), NULL);
+
+ return dest->drop;
+}
+
+const char *
+gtk_drop_target_match (GtkDropTarget *dest,
+ GdkDrop *drop)
+{
+ GdkContentFormats *formats;
+ const char *match;
+
+ formats = gdk_content_formats_ref (dest->formats);
+ formats = gdk_content_formats_union_deserialize_mime_types (formats);
+
+ match = gdk_content_formats_match_mime_type (formats, gdk_drop_get_formats (drop));
+
+ gdk_content_formats_unref (formats);
+
+ return match;
+}
+
+/**
+ * gtk_drop_target_find_mimetype:
+ * @dest: a #GtkDropTarget
+ *
+ * Returns a mimetype that is supported both by @dest and the ongoing
+ * drag.
+ *
+ * Returns: (nullable): a matching mimetype for the ongoing drag, or %NULL
+ */
+const char *
+gtk_drop_target_find_mimetype (GtkDropTarget *dest)
+{
+ if (!dest->drop)
+ return NULL;
+
+ return gtk_drop_target_match (dest, dest->drop);
+}
+
+static void
+set_drop (GtkDropTarget *dest,
+ GdkDrop *drop)
+{
+ if (dest->drop == drop)
+ return;
+
+ if (dest->drop)
+ g_object_remove_weak_pointer (G_OBJECT (dest->drop), (gpointer *)&dest->drop);
+
+ dest->drop = drop;
+
+ if (dest->drop)
+ g_object_add_weak_pointer (G_OBJECT (dest->drop), (gpointer *)&dest->drop);
+}
+
+void
+gtk_drop_target_emit_drag_leave (GtkDropTarget *dest,
+ GdkDrop *drop,
+ guint time)
+{
+ set_drop (dest, drop);
+ g_signal_emit (dest, signals[DRAG_LEAVE], 0, time);
+ set_drop (dest, NULL);
+}
+
+gboolean
+gtk_drop_target_emit_drag_motion (GtkDropTarget *dest,
+ GdkDrop *drop,
+ int x,
+ int y)
+{
+ gboolean result = FALSE;
+
+ set_drop (dest, drop);
+ g_signal_emit (dest, signals[DRAG_MOTION], 0, x, y, &result);
+
+ return result;
+}
+
+gboolean
+gtk_drop_target_emit_drag_drop (GtkDropTarget *dest,
+ GdkDrop *drop,
+ int x,
+ int y)
+{
+ gboolean result = FALSE;
+
+ set_drop (dest, drop);
+ g_signal_emit (dest, signals[DRAG_DROP], 0, x, y, &result);
+
+ return result;
+}
+
+void
+gtk_drop_target_emit_drag_data_received (GtkDropTarget *dest,
+ GdkDrop *drop,
+ GtkSelectionData *sdata)
+{
+ set_drop (dest, drop);
+ g_signal_emit (dest, signals[DRAG_DATA_RECEIVED], 0, sdata);
+}
diff --git a/gtk/gtkdragdest.h b/gtk/gtkdragdest.h
index f241f514a7..e126298bf9 100644
--- a/gtk/gtkdragdest.h
+++ b/gtk/gtkdragdest.h
@@ -37,6 +37,8 @@
G_BEGIN_DECLS
+typedef struct _GtkDropTarget GtkDropTarget;
+
/**
* GtkDestDefaults:
* @GTK_DEST_DEFAULT_MOTION: If set for a widget, GTK+, during a drag over this
@@ -46,7 +48,7 @@ G_BEGIN_DECLS
* @GTK_DEST_DEFAULT_HIGHLIGHT: If set for a widget, GTK+ will draw a highlight on
* this widget as long as a drag is over this widget and the widget drag format
* and action are acceptable.
- * @GTK_DEST_DEFAULT_DROP: If set for a widget, when a drop occurs, GTK+ will
+ * @GTK_DEST_DEFAULT_OP: If set for a widget, when a drop occurs, GTK+ will
* will check if the drag matches this widget’s list of possible formats and
* actions. If so, GTK+ will call gtk_drag_get_data() on behalf of the widget.
* Whether or not the drop is successful, GTK+ will call gdk_drag_finish(). If
@@ -67,10 +69,10 @@ typedef enum {
} GtkDestDefaults;
GDK_AVAILABLE_IN_ALL
-void gtk_drag_dest_set (GtkWidget *widget,
- GtkDestDefaults flags,
- GdkContentFormats *targets,
- GdkDragAction actions);
+GtkDropTarget *gtk_drag_dest_set (GtkWidget *widget,
+ GtkDestDefaults flags,
+ GdkContentFormats *targets,
+ GdkDragAction actions);
GDK_AVAILABLE_IN_ALL
void gtk_drag_dest_unset (GtkWidget *widget);
@@ -98,6 +100,63 @@ GDK_AVAILABLE_IN_ALL
gboolean gtk_drag_dest_get_track_motion (GtkWidget *widget);
+#define GTK_TYPE_DROP_TARGET (gtk_drop_target_get_type ())
+#define GTK_DROP_TARGET(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_DROP_TARGET, GtkDropTarget))
+#define GTK_DROP_TARGET_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_DROP_TARGET,
GtkDropTargetClass))
+#define GTK_IS_DROP_TARGET(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_DROP_TARGET))
+#define GTK_IS_DROP_TARGET_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_DROP_TARGET))
+#define GTK_DROP_TARGET_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_DROP_TARGET,
GtkDropTargetClass))
+
+typedef struct _GtkDropTargetClass GtkDropTargetClass;
+
+GDK_AVAILABLE_IN_ALL
+GType gtk_drop_target_get_type (void) G_GNUC_CONST;
+
+GDK_AVAILABLE_IN_ALL
+GtkDropTarget *gtk_drop_target_new (GtkDestDefaults defaults,
+ GdkContentFormats *formats,
+ GdkDragAction actions);
+
+GDK_AVAILABLE_IN_ALL
+void gtk_drop_target_set_formats (GtkDropTarget *dest,
+ GdkContentFormats *formats);
+GDK_AVAILABLE_IN_ALL
+GdkContentFormats *gtk_drop_target_get_formats (GtkDropTarget *dest);
+
+GDK_AVAILABLE_IN_ALL
+void gtk_drop_target_set_actions (GtkDropTarget *dest,
+ GdkDragAction actions);
+GDK_AVAILABLE_IN_ALL
+GdkDragAction gtk_drop_target_get_actions (GtkDropTarget *dest);
+
+GDK_AVAILABLE_IN_ALL
+void gtk_drop_target_set_defaults (GtkDropTarget *dest,
+ GtkDestDefaults defaults);
+GDK_AVAILABLE_IN_ALL
+GtkDestDefaults gtk_drop_target_get_defaults (GtkDropTarget *dest);
+
+GDK_AVAILABLE_IN_ALL
+void gtk_drop_target_set_track_motion (GtkDropTarget *dest,
+ gboolean track_motion);
+GDK_AVAILABLE_IN_ALL
+gboolean gtk_drop_target_get_track_motion (GtkDropTarget *dest);
+
+GDK_AVAILABLE_IN_ALL
+void gtk_drop_target_attach (GtkDropTarget *dest,
+ GtkWidget *widget);
+GDK_AVAILABLE_IN_ALL
+void gtk_drop_target_detach (GtkDropTarget *dest);
+
+GDK_AVAILABLE_IN_ALL
+GdkDrop *gtk_drop_target_get_drop (GtkDropTarget *dest);
+
+GDK_AVAILABLE_IN_ALL
+GtkWidget *gtk_drop_target_get_target (GtkDropTarget *dest);
+
+GDK_AVAILABLE_IN_ALL
+const char *gtk_drop_target_find_mimetype (GtkDropTarget *dest);
+
+
G_END_DECLS
#endif /* __GTK_DRAG_DEST_H__ */
diff --git a/gtk/gtkdragdestprivate.h b/gtk/gtkdragdestprivate.h
new file mode 100644
index 0000000000..deb772763f
--- /dev/null
+++ b/gtk/gtkdragdestprivate.h
@@ -0,0 +1,46 @@
+
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2020 Matthias Clasen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GTK_DRAG_DEST_PRIVATE_H__
+#define __GTK_DRAG_DEST_PRIVATE_H__
+
+#include "gtkdragdest.h"
+
+G_BEGIN_DECLS
+
+void gtk_drop_target_emit_drag_data_received (GtkDropTarget *dest,
+ GdkDrop *drop,
+ GtkSelectionData *sdata);
+void gtk_drop_target_emit_drag_leave (GtkDropTarget *dest,
+ GdkDrop *drop,
+ guint time);
+gboolean gtk_drop_target_emit_drag_motion (GtkDropTarget *dest,
+ GdkDrop *drop,
+ int x,
+ int y);
+gboolean gtk_drop_target_emit_drag_drop (GtkDropTarget *dest,
+ GdkDrop *drop,
+ int x,
+ int y);
+
+const char * gtk_drop_target_match (GtkDropTarget *dest,
+ GdkDrop *drop);
+
+G_END_DECLS
+
+#endif
diff --git a/gtk/gtkdragsource.c b/gtk/gtkdragsource.c
index 1f4930b3a9..653f112b68 100644
--- a/gtk/gtkdragsource.c
+++ b/gtk/gtkdragsource.c
@@ -310,7 +310,8 @@ static void gtk_drag_source_cancel_cb (GdkDrag *drag,
GtkDragSource *source);
static void
-drag_end (GtkDragSource *source)
+drag_end (GtkDragSource *source,
+ gboolean success)
{
g_signal_handlers_disconnect_by_func (source->drag, gtk_drag_source_drop_performed_cb, source);
g_signal_handlers_disconnect_by_func (source->drag, gtk_drag_source_dnd_finished_cb, source);
@@ -318,6 +319,8 @@ drag_end (GtkDragSource *source)
g_signal_emit (source, signals[DRAG_END], 0);
+ gdk_drag_drop_done (source->drag, success);
+
g_object_set_data (G_OBJECT (source->drag), I_("gtk-drag-source"), NULL);
g_clear_object (&source->drag);
source->widget = NULL;
@@ -330,8 +333,7 @@ gtk_drag_source_dnd_finished_cb (GdkDrag *drag,
{
if (gdk_drag_get_selected_action (drag) == GDK_ACTION_MOVE)
g_signal_emit (source, signals[DRAG_DATA_DELETE], 0);
-
- drag_end (source);
+ drag_end (source, TRUE);
}
static void
@@ -342,7 +344,7 @@ gtk_drag_source_cancel_cb (GdkDrag *drag,
gboolean success = FALSE;
g_signal_emit (source, signals[DRAG_FAILED], 0, reason, &success);
- drag_end (source);
+ drag_end (source, FALSE);
}
static void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]