diff --git a/gtk/gtkdragsource.c b/gtk/gtkdragsource.c index 8cc461464e..5074ab944e 100644 --- a/gtk/gtkdragsource.c +++ b/gtk/gtkdragsource.c @@ -29,8 +29,16 @@ #include "gtkdnd.h" #include "gtkdndprivate.h" #include "gtkgesturedrag.h" +#include "gtkgesturesingleprivate.h" #include "gtkimagedefinitionprivate.h" +#include "gtknative.h" +#include "gtkwidgetprivate.h" #include "gtkintl.h" +#include "gtkstylecontext.h" +#include "gtkimageprivate.h" +#include "gtkdragiconprivate.h" +#include "gtkprivate.h" +#include "gtkmarshalers.h" typedef struct _GtkDragSourceSite GtkDragSourceSite; @@ -117,7 +125,7 @@ gtk_drag_source_site_destroy (gpointer data) * gtk_drag_source_set: (method) * @widget: a #GtkWidget * @start_button_mask: the bitmask of buttons that can start the drag - * @targets: (allow-none): the targets that the drag will support, + * @formats: (allow-none): the formats that the drag will support, * may be %NULL * @actions: the bitmask of possible actions for a drag from this widget * @@ -388,3 +396,745 @@ gtk_drag_source_set_icon_paintable (GtkWidget *widget, site->image_def = gtk_image_definition_new_paintable (paintable); } + +/** + * SECTION:gtkdragsource + * @Short_description: An object to initiate DND operations + * @Title: GtkDragSource + * + * GtkDragSource is an auxiliary object that is used to initiate + * Drag-And-Drop operations. It can be set up with the necessary + * ingredients for a DND operation ahead of time. This includes + * the source for the data that is being transferred, in the form + * of a #GdkContentProvider, the desired action, and the icon to + * use during the drag operation. + * + * GtkDragSource can be used in two ways: + * - for static drag-source configuration + * - for one-off drag operations + * + * To configure a widget as a permanent source for DND operations, + * set up the GtkDragSource, then call gtk_drag_source_attach(). + * This sets up a drag gesture on the widget that will trigger + * DND actions. + * + * To initiate a on-off drag operation, set up the GtkDragSource, + * then call gtk_drag_source_drag_begin(). GTK keeps a reference + * on the drag source until the DND operation is done, so you + * can unref the source after calling drag_being(). + * + * During the DND operation, GtkDragSource emits signals that + * can be used to obtain updates about the status of the operation, + * but it is not normally necessary to connect to any signals, + * except for one case: when the supported actions include + * %GDK_DRAG_MOVE, you need to listen for the + * #GtkDragSource::drag-data-deleted signal and delete the + * drag data after it has been transferred. + */ + +struct _GtkDragSource +{ + GObject parent_instance; + + GdkContentProvider *content; + GdkDragAction actions; + + GtkWidget *icon_window; + GdkPaintable *paintable; + int hot_x; + int hot_y; + + GtkGesture *gesture; + int start_button_mask; + + GdkDrag *drag; + GtkWidget *widget; +}; + +struct _GtkDragSourceClass +{ + GObjectClass parent_class; +}; + +enum { + PROP_CONTENT = 1, + PROP_ACTIONS, + NUM_PROPERTIES +}; + +static GParamSpec *properties[NUM_PROPERTIES]; + +enum { + DRAG_BEGIN, + DRAG_END, + DRAG_FAILED, + DRAG_DATA_DELETE, + NUM_SIGNALS +}; + +static guint signals[NUM_SIGNALS]; + +G_DEFINE_TYPE (GtkDragSource, gtk_drag_source, G_TYPE_OBJECT); + +static void +gtk_drag_source_init (GtkDragSource *source) +{ +} + +static void +gtk_drag_source_finalize (GObject *object) +{ + GtkDragSource *source = GTK_DRAG_SOURCE (object); + + gtk_drag_source_detach (source); + + g_clear_object (&source->content); + g_clear_object (&source->paintable); + g_clear_object (&source->icon_window); + + G_OBJECT_CLASS (gtk_drag_source_parent_class)->finalize (object); +} + +static void +gtk_drag_source_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GtkDragSource *source = GTK_DRAG_SOURCE (object); + + switch (prop_id) + { + case PROP_CONTENT: + gtk_drag_source_set_content (source, g_value_get_object (value)); + break; + + case PROP_ACTIONS: + gtk_drag_source_set_actions (source, g_value_get_flags (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gtk_drag_source_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GtkDragSource *source = GTK_DRAG_SOURCE (object); + + switch (prop_id) + { + case PROP_CONTENT: + g_value_set_object (value, gtk_drag_source_get_content (source)); + break; + + case PROP_ACTIONS: + g_value_set_flags (value, gtk_drag_source_get_actions (source)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gtk_drag_source_class_init (GtkDragSourceClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->finalize = gtk_drag_source_finalize; + object_class->set_property = gtk_drag_source_set_property; + object_class->get_property = gtk_drag_source_get_property; + + /** + * GtkDragSource:content: + * + * The data that is offered by drag operations from this source, + * in the form of a #GdkContentProvider. + */ + properties[PROP_CONTENT] = + g_param_spec_object ("content", + P_("Content"), + P_("The content provider for the dragged data"), + GDK_TYPE_CONTENT_PROVIDER, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + + /** + * GtkDragSource:actions: + * + * The actions that are supported by drag operations from the source. + * + * Note that you must handle the #GtkDragSource::drag-data-deleted signal + * if the actions include %GDK_ACTION_MOVE. + */ + properties[PROP_ACTIONS] = + g_param_spec_flags ("actions", + P_("Actions"), + P_("Supported actions"), + GDK_TYPE_DRAG_ACTION, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + + g_object_class_install_properties (object_class, NUM_PROPERTIES, properties); + + /** + * GtkDragSource::drag-begin: + * @source: the #GtkDragSource + * + * The ::drag-begin signal is emitted on the drag source when a drag + * is started. It can be used to e.g. set a custom drag icon with + * gtk_drag_source_set_icon(). But all of the setup can also be + * done before calling gtk_drag_source_drag_begin(), so this is not + * really necessary. + */ + signals[DRAG_BEGIN] = + g_signal_new (I_("drag-begin"), + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + NULL, + G_TYPE_NONE, 0); + + /** + * GtkDragSource::drag-end: + * @source: the #GtkDragSource + * + * The ::drag-end signal is emitted on the drag source when a drag is + * finished. A typical reason to connect to this signal is to undo + * things done in #GtkDragSource::drag-begin. + */ + signals[DRAG_END] = + g_signal_new (I_("drag-end"), + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + NULL, + G_TYPE_NONE, 0); + + /** + * GtkDragSource::drag-failed: + * @source: the #GtkDragSource + * @reason: information on why the drag failed + * + * The ::drag-failed signal is emitted on the drag source when a drag has + * failed. The signal handler may handle a failed drag operation based on + * the type of error. It should return %TRUE if the failure has been handled + * and the default "drag operation failed" should not be shown. + * + * Returns: %TRUE if the failed drag operation has been already handled + */ + signals[DRAG_FAILED] = + g_signal_new (I_("drag-failed"), + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + 0, + _gtk_boolean_handled_accumulator, NULL, + _gtk_marshal_BOOLEAN__ENUM, + G_TYPE_BOOLEAN, 1, + GDK_TYPE_DRAG_CANCEL_REASON); + + /** + * GtkDragSource::drag-data-delete: + * @source: the #GtkDragSource + * + * The ::drag-data-delete signal is emitted on the drag source when a drag + * with the action %GDK_ACTION_MOVE is successfully completed. The signal + * handler is responsible for deleting the data that has been dropped. What + * "delete" means depends on the context of the drag operation. + */ + signals[DRAG_DATA_DELETE] = + g_signal_new (I_("drag-data-delete"), + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + NULL, + G_TYPE_NONE, 0); +} + +static void gtk_drag_source_dnd_finished_cb (GdkDrag *drag, + GtkDragSource *source); +static void gtk_drag_source_drop_performed_cb (GdkDrag *drag, + GtkDragSource *source); +static void gtk_drag_source_cancel_cb (GdkDrag *drag, + GdkDragCancelReason reason, + GtkDragSource *source); + +static void +drag_end (GtkDragSource *source) +{ + 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); + g_signal_handlers_disconnect_by_func (source->drag, gtk_drag_source_cancel_cb, source); + + g_signal_emit (source, signals[DRAG_END], 0); + + g_object_set_data (G_OBJECT (source->drag), I_("gtk-drag-source"), NULL); + g_clear_object (&source->drag); + source->widget = NULL; + g_object_unref (source); +} + +static void +gtk_drag_source_dnd_finished_cb (GdkDrag *drag, + GtkDragSource *source) +{ + if (gdk_drag_get_selected_action (drag) == GDK_ACTION_MOVE) + g_signal_emit (source, signals[DRAG_DATA_DELETE], 0); + + drag_end (source); +} + +static void +gtk_drag_source_cancel_cb (GdkDrag *drag, + GdkDragCancelReason reason, + GtkDragSource *source) +{ + gboolean success = FALSE; + + g_signal_emit (source, signals[DRAG_FAILED], 0, reason, &success); + drag_end (source); +} + +static void +gtk_drag_source_drop_performed_cb (GdkDrag *drag, + GtkDragSource *source) +{ + if (source->icon_window) + gtk_widget_hide (source->icon_window); +} + +/** + * gtk_drag_source_drag_begin: + * @source: a #GtkDragSource + * @widget: the widget where the drag operation originates + * @device: the device that is driving the drag operation + * @x: start point X coordinate + * @y: start point Y xoordinate + * + * Starts a DND operation with @source. + * + * The start point coordinates are relative to @widget. + * + * GTK keeps a reference on @source for the duration of + * the DND operation, so it is safe to unref @source + * after this call. + */ +void +gtk_drag_source_drag_begin (GtkDragSource *source, + GtkWidget *widget, + GdkDevice *device, + int x, + int y) +{ + GtkNative *native; + GdkSurface *surface; + double px, py; + int dx, dy; + GtkWidget *icon; + + g_return_if_fail (GTK_IS_DRAG_SOURCE (source)); + g_return_if_fail (GTK_IS_WIDGET (widget)); + g_return_if_fail (GDK_IS_DEVICE (device)); + g_return_if_fail (source->content != NULL); + g_return_if_fail (source->actions != 0); + + if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD) + device = gdk_device_get_associated_device (device); + + native = gtk_widget_get_native (widget); + surface = gtk_native_get_surface (native); + + gtk_widget_translate_coordinates (widget, GTK_WIDGET (native), x, y, &x, &y); + gdk_surface_get_device_position (surface, device, &px, &py, NULL); + + dx = round (px) - x; + dy = round (py) - y; + + source->drag = gdk_drag_begin (surface, device, source->content, source->actions, dx, dy); + if (source->drag == NULL) + { + g_print ("no drag :(\n"); + return; + } + + g_object_set_data (G_OBJECT (source->drag), I_("gtk-drag-source"), source); + source->widget = widget; + + gtk_widget_reset_controllers (widget); + + /* We hold a ref until ::drag-end is emitted */ + g_object_ref (source); + + g_signal_emit (source, signals[DRAG_BEGIN], 0); + + if (!source->paintable) + { + GtkIconTheme *theme; + + theme = gtk_icon_theme_get_for_display (gtk_widget_get_display (widget)); + source->paintable = gtk_icon_theme_load_icon (theme, "text-x-generic", 32, 0, NULL); + source->hot_x = 0; + source->hot_y = 0; + } + + gdk_drag_set_hotspot (source->drag, source->hot_x, source->hot_y); + source->icon_window = gtk_drag_icon_new (); + g_object_ref_sink (source->icon_window); + gtk_drag_icon_set_surface (GTK_DRAG_ICON (source->icon_window), + gdk_drag_get_drag_surface (source->drag)); + + icon = gtk_picture_new_for_paintable (source->paintable); + gtk_picture_set_can_shrink (GTK_PICTURE (icon), FALSE); + gtk_drag_icon_set_widget (GTK_DRAG_ICON (source->icon_window), icon); + + gtk_widget_show (source->icon_window); + + g_signal_connect (source->drag, "drop-performed", + G_CALLBACK (gtk_drag_source_drop_performed_cb), source); + g_signal_connect (source->drag, "dnd-finished", + G_CALLBACK (gtk_drag_source_dnd_finished_cb), source); + g_signal_connect (source->drag, "cancel", + G_CALLBACK (gtk_drag_source_cancel_cb), source); +} + +/** + * gtk_drag_source_new: + * @content: (nullable): the #GdkContentProvider to use, or %NULL + * @actions: the actions to offer + * + * Creates a new #GtkDragSource object. + * + * Returns: the new #GtkDragSource + */ +GtkDragSource * +gtk_drag_source_new (GdkContentProvider *content, + GdkDragAction actions) +{ + return g_object_new (GTK_TYPE_DRAG_SOURCE, + "content", content, + "actions", actions, + NULL); +} + +/** + * gtk_drag_source_get_content: + * @source: a #GtkDragSource + * + * Gets the current content provider of a #GtkDragSource. + * + * Returns: the #GtkContentProvider of @source + */ +GdkContentProvider * +gtk_drag_source_get_content (GtkDragSource *source) +{ + g_return_val_if_fail (GTK_IS_DRAG_SOURCE (source), NULL); + + return source->content; +} + +/** + * gtk_drag_source_set_content: + * @source: a #GtkDragSource + * @content: (nullable): a #GtkContntProvider, or %NULL + * + * Sets a content provider on a #GtkDragSource. + * + * When the data is requested in the cause of a + * DND operation, it will be obtained from the + * content provider. + */ +void +gtk_drag_source_set_content (GtkDragSource *source, + GdkContentProvider *content) +{ + g_return_if_fail (GTK_IS_DRAG_SOURCE (source)); + + if (!g_set_object (&source->content, content)) + return; + + g_object_notify_by_pspec (G_OBJECT (source), properties[PROP_CONTENT]); +} + +/** + * gtk_drag_source_get_actions: + * @source: a #GtkDragSource + * + * Gets the actions that are currently set on the #GtkDragSource. + * + * Returns: the actions set on @source + */ +GdkDragAction +gtk_drag_source_get_actions (GtkDragSource *source) +{ + g_return_val_if_fail (GTK_IS_DRAG_SOURCE (source), 0); + + return source->actions; +} + +/** + * gtk_drag_source_set_actions: + * @source: a #GtkDragSource + * @actions: the actions to offer + * + * Sets the actions on the #GtkDragSource. + * + * During a DND operation, the actions are offered + * to potential drop targets. + */ +void +gtk_drag_source_set_actions (GtkDragSource *source, + GdkDragAction actions) +{ + g_return_if_fail (GTK_IS_DRAG_SOURCE (source)); + + if (source->actions == actions) + return; + + source->actions = actions; + + g_object_notify_by_pspec (G_OBJECT (source), properties[PROP_ACTIONS]); +} + +/** + * gtk_drag_source_set_icon: + * @source: a #GtkDragSource + * @paintable: (nullable): the #GtkPaintable to use as icon, or %NULL + * @hot_x: the hotspot X coordinate on the icon + * @hot_y: the hotspot Y coordinate on the icon + * + * Sets a paintable to use as icon during DND operations. + * + * The hotspot coordinates determine the point on the icon + * that gets aligned with the hotspot of the cursor. + * + * If @paintable is %NULL, a default icon is used. + */ +void +gtk_drag_source_set_icon (GtkDragSource *source, + GdkPaintable *paintable, + int hot_x, + int hot_y) +{ + g_return_if_fail (GTK_IS_DRAG_SOURCE (source)); + + g_set_object (&source->paintable, paintable); + + source->hot_x = hot_x; + source->hot_y = hot_y; +} + +static void +source_gesture_begin (GtkGesture *gesture, + GdkEventSequence *sequence, + GtkDragSource *source) +{ + guint button; + + if (gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture))) + button = 1; + else + button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture)); + + g_assert (button >= 1); + + if ((source->start_button_mask & (GDK_BUTTON1_MASK << (button - 1))) == 0) + gtk_gesture_set_state (gesture, GTK_EVENT_SEQUENCE_DENIED); +} + +static void +source_gesture_update (GtkGesture *gesture, + GdkEventSequence *sequence, + GtkDragSource *source) + +{ + gdouble start_x, start_y, offset_x, offset_y; + GtkWidget *widget; + + if (!gtk_gesture_is_recognized (gesture)) + return; + + widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture)); + + gtk_gesture_drag_get_start_point (GTK_GESTURE_DRAG (gesture), &start_x, &start_y); + gtk_gesture_drag_get_offset (GTK_GESTURE_DRAG (gesture), &offset_x, &offset_y); + + if (gtk_drag_check_threshold (widget, + start_x, start_y, + start_x + offset_x, start_y + offset_y)) + { + GdkDevice *device = gtk_gesture_get_device (gesture); + + gtk_drag_source_drag_begin (source, widget, device, start_x, start_y); + } +} + +static void +gesture_removed (gpointer data) +{ + GtkDragSource *source = data; + + /* if we get here, the widget we are attached to was destroyed, + * and removed our gesture. + * + * Clean up, and drop the ref we held for being attached. + */ + + source->gesture = NULL; + g_object_unref (source); +} + +/** + * gtk_drag_source_attach: + * @source: (transfer full): a #GtkDragSource + * @widget: the widget to attach @source to + * @start_button_mask: mask determining which mouse buttons trigger + * + * Attaches the @source to a @widget by creating a drag gesture + * on @widget that will trigger DND operations with @source. + * + * The @start_button_mask determines which mouse buttons trigger + * a DND operation. + * + * To undo the effect of this call, use gtk_drag_source_detach(). + */ +void +gtk_drag_source_attach (GtkDragSource *source, + GtkWidget *widget, + GdkModifierType start_button_mask) +{ + g_return_if_fail (GTK_IS_DRAG_SOURCE (source)); + g_return_if_fail (GTK_IS_WIDGET (widget)); + g_return_if_fail (source->gesture == NULL); + g_return_if_fail (start_button_mask != 0); + g_return_if_fail ((start_button_mask & ~(GDK_BUTTON1_MASK | + GDK_BUTTON2_MASK | + GDK_BUTTON3_MASK | + GDK_BUTTON4_MASK | + GDK_BUTTON5_MASK)) == 0); + + source->gesture = gtk_gesture_drag_new (); + gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (source->gesture), + GTK_PHASE_CAPTURE); + gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (source->gesture), 0); + g_signal_connect (source->gesture, "begin", + G_CALLBACK (source_gesture_begin), source); + g_signal_connect (source->gesture, "update", + G_CALLBACK (source_gesture_update), source); + gtk_widget_add_controller (widget, GTK_EVENT_CONTROLLER (source->gesture)); + + source->start_button_mask = start_button_mask; + + g_object_set_data_full (G_OBJECT (source->gesture), "gtk-drag-source", + source, gesture_removed); +} + +/** + * gtk_drag_source_detach: + * @source: a #GtkDragSource + * + * Undoes the effect of a prior gtk_drag_source_attach() call. + */ +void +gtk_drag_source_detach (GtkDragSource *source) +{ + g_return_if_fail (GTK_IS_DRAG_SOURCE (source)); + + if (source->gesture) + { + GtkWidget *widget; + + g_object_ref (source); + + g_object_set_data (G_OBJECT (source->gesture), "gtk-drag-source", NULL); + widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (source->gesture)); + gtk_widget_remove_controller (widget, GTK_EVENT_CONTROLLER (source->gesture)); + + g_object_unref (source); + } +} + +/** + * gtk_drag_get_source: + * @drag: a #GdkDrag + * + * Obtains the #GtkDragSource from which a #GdkDrag originates. + * + * This function should rarely be needed. Once case where it can + * be used is together with gtk_drop_get_drag(), to determine + * whether a 'local' drag is coming from the same widget. + * + * Returns: (transfer none) (nullable): a #GtkDragSource, or %NULL + */ +GtkDragSource * +gtk_drag_get_source (GdkDrag *drag) +{ + gpointer data; + + g_return_val_if_fail (GDK_IS_DRAG (drag), NULL); + + data = g_object_get_data (G_OBJECT (drag), I_("gtk-drag-source")); + + if (data) + return GTK_DRAG_SOURCE (data); + + return NULL; +} + +/** + * gtk_drag_source_get_origin: + * @source: a #GtkDragSource + * + * Returns the widget that an ongoing drag is started from. + * + * Returns: (nullable): the origin of the current drag operation, or %NULL + */ +GtkWidget * +gtk_drag_source_get_origin (GtkDragSource *source) +{ + g_return_val_if_fail (GTK_IS_DRAG_SOURCE (source), NULL); + + return source->widget; +} + +/** + * gtk_drag_source_get_drag: + * @source: a #GtkDragSource + * + * Returns the underlying #GtkDrag object for an ongoing drag. + * + * Returns: (nullable): the #GdkDrag of the current drag operation, or %NULL + */ +GdkDrag * +gtk_drag_source_get_drag (GtkDragSource *source) +{ + g_return_val_if_fail (GTK_IS_DRAG_SOURCE (source), NULL); + + return source->drag; +} + +/** + * gtk_drag_source_drag_cancel: + * @source: a #GtkDragSource + * + * Cancels a currently ongoing drag operation. + */ +void +gtk_drag_source_drag_cancel (GtkDragSource *source) +{ + g_return_if_fail (GTK_IS_DRAG_SOURCE (source)); + + if (source->drag) + { + gboolean success = FALSE; + + g_signal_emit (source, signals[DRAG_FAILED], 0, GDK_DRAG_CANCEL_ERROR, &success); + + gdk_drag_drop_done (source->drag, success); + } +} diff --git a/gtk/gtkdragsource.h b/gtk/gtkdragsource.h index b77f46db74..22f8c31cd8 100644 --- a/gtk/gtkdragsource.h +++ b/gtk/gtkdragsource.h @@ -69,6 +69,68 @@ void gtk_drag_source_set_icon_paintable (GtkWidget *widget, GdkPaintable *paintable); +#define GTK_TYPE_DRAG_SOURCE (gtk_drag_source_get_type ()) +#define GTK_DRAG_SOURCE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_DRAG_SOURCE, GtkDragSource)) +#define GTK_DRAG_SOURCE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_DRAG_SOURCE, GtkDragSourceClass)) +#define GTK_IS_DRAG_SOURCE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_DRAG_SOURCE)) +#define GTK_IS_DRAG_SOURCE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_DRAG_SOURCE)) +#define GTK_DRAG_SOURCE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_DRAG_SOURCE, GtkDragSourceClass)) + +typedef struct _GtkDragSource GtkDragSource; +typedef struct _GtkDragSourceClass GtkDragSourceClass; + +GDK_AVAILABLE_IN_ALL +GType gtk_drag_source_get_type (void) G_GNUC_CONST; + +GDK_AVAILABLE_IN_ALL +GtkDragSource *gtk_drag_source_new (GdkContentProvider *content, + GdkDragAction actions); + +GDK_AVAILABLE_IN_ALL +void gtk_drag_source_set_content (GtkDragSource *source, + GdkContentProvider *content); +GDK_AVAILABLE_IN_ALL +GdkContentProvider *gtk_drag_source_get_content (GtkDragSource *source); + +GDK_AVAILABLE_IN_ALL +void gtk_drag_source_set_actions (GtkDragSource *source, + GdkDragAction actions); +GDK_AVAILABLE_IN_ALL +GdkDragAction gtk_drag_source_get_actions (GtkDragSource *source); + +GDK_AVAILABLE_IN_ALL +void gtk_drag_source_set_icon (GtkDragSource *source, + GdkPaintable *paintable, + int hot_x, + int hot_y); +GDK_AVAILABLE_IN_ALL +void gtk_drag_source_drag_begin (GtkDragSource *source, + GtkWidget *widget, + GdkDevice *device, + int x, + int y); + +GDK_AVAILABLE_IN_ALL +void gtk_drag_source_drag_cancel (GtkDragSource *sourcei); + +GDK_AVAILABLE_IN_ALL +GtkDragSource * gtk_drag_get_source (GdkDrag *drag); + +GDK_AVAILABLE_IN_ALL +GtkWidget * gtk_drag_source_get_origin (GtkDragSource *source); + +GDK_AVAILABLE_IN_ALL +GdkDrag * gtk_drag_source_get_drag (GtkDragSource *source); + +GDK_AVAILABLE_IN_ALL +void gtk_drag_source_attach (GtkDragSource *source, + GtkWidget *widget, + GdkModifierType start_button_mask); + +GDK_AVAILABLE_IN_ALL +void gtk_drag_source_detach (GtkDragSource *source); + + G_END_DECLS #endif /* __GTK_DRAG_SOURCE_H__ */