1/* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1999 Peter Mattis, Spencer Kimball and Josh MacDonald
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18/*
19 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
20 * file for a list of people on the GTK+ Team. See the ChangeLog
21 * files for a list of changes. These files are distributed with
22 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
23 */
24
25#include "config.h"
26
27#include "gtkdroptargetasync.h"
28
29#include "gtkdropprivate.h"
30#include "gtkeventcontrollerprivate.h"
31#include "gtkintl.h"
32#include "gtkmarshalers.h"
33#include "gtknative.h"
34#include "gtktypebuiltins.h"
35
36
37/**
38 * GtkDropTargetAsync:
39 *
40 * `GtkDropTargetAsync` is an event controller to receive Drag-and-Drop
41 * operations, asynchronously.
42 *
43 * It is the more complete but also more complex method of handling drop
44 * operations compared to [class@Gtk.DropTarget], and you should only use
45 * it if `GtkDropTarget` doesn't provide all the features you need.
46 *
47 * To use a `GtkDropTargetAsync` to receive drops on a widget, you create
48 * a `GtkDropTargetAsync` object, configure which data formats and actions
49 * you support, connect to its signals, and then attach it to the widget
50 * with [method@Gtk.Widget.add_controller].
51 *
52 * During a drag operation, the first signal that a `GtkDropTargetAsync`
53 * emits is [signal@Gtk.DropTargetAsync::accept], which is meant to determine
54 * whether the target is a possible drop site for the ongoing drop. The
55 * default handler for the ::accept signal accepts the drop if it finds
56 * a compatible data format and an action that is supported on both sides.
57 *
58 * If it is, and the widget becomes a target, you will receive a
59 * [signal@Gtk.DropTargetAsync::drag-enter] signal, followed by
60 * [signal@Gtk.DropTargetAsync::drag-motion] signals as the pointer moves,
61 * optionally a [signal@Gtk.DropTargetAsync::drop] signal when a drop happens,
62 * and finally a [signal@Gtk.DropTargetAsync::drag-leave] signal when the
63 * pointer moves off the widget.
64 *
65 * The ::drag-enter and ::drag-motion handler return a `GdkDragAction`
66 * to update the status of the ongoing operation. The ::drop handler
67 * should decide if it ultimately accepts the drop and if it does, it
68 * should initiate the data transfer and finish the operation by calling
69 * [method@Gdk.Drop.finish].
70 *
71 * Between the ::drag-enter and ::drag-leave signals the widget is a
72 * current drop target, and will receive the %GTK_STATE_FLAG_DROP_ACTIVE
73 * state, which can be used by themes to style the widget as a drop target.
74 */
75
76struct _GtkDropTargetAsync
77{
78 GtkEventController parent_object;
79
80 GdkContentFormats *formats;
81 GdkDragAction actions;
82
83 GdkDrop *drop;
84 gboolean rejected;
85};
86
87struct _GtkDropTargetAsyncClass
88{
89 GtkEventControllerClass parent_class;
90
91 gboolean (* accept) (GtkDropTargetAsync *self,
92 GdkDrop *drop);
93 GdkDragAction (* drag_enter) (GtkDropTargetAsync *self,
94 GdkDrop *drop,
95 double x,
96 double y);
97 GdkDragAction (* drag_motion) (GtkDropTargetAsync *self,
98 GdkDrop *drop,
99 double x,
100 double y);
101 void (* drag_leave) (GtkDropTargetAsync *self,
102 GdkDrop *drop);
103 gboolean (* drop) (GtkDropTargetAsync *self,
104 GdkDrop *drop,
105 double x,
106 double y);
107};
108
109enum {
110 PROP_0,
111 PROP_ACTIONS,
112 PROP_FORMATS,
113 NUM_PROPERTIES
114};
115
116static GParamSpec *properties[NUM_PROPERTIES];
117
118enum {
119 ACCEPT,
120 DRAG_ENTER,
121 DRAG_MOTION,
122 DRAG_LEAVE,
123 DROP,
124 NUM_SIGNALS
125};
126
127static guint signals[NUM_SIGNALS];
128
129G_DEFINE_TYPE (GtkDropTargetAsync, gtk_drop_target_async, GTK_TYPE_EVENT_CONTROLLER);
130
131static gboolean
132gtk_drop_target_async_accept (GtkDropTargetAsync *self,
133 GdkDrop *drop)
134{
135 if ((gdk_drop_get_actions (self: drop) & self->actions) == 0)
136 return FALSE;
137
138 if (self->formats == NULL)
139 return TRUE;
140
141 return gdk_content_formats_match (first: self->formats, second: gdk_drop_get_formats (self: drop));
142}
143
144static GdkDragAction
145make_action_unique (GdkDragAction actions)
146{
147 if (actions & GDK_ACTION_COPY)
148 return GDK_ACTION_COPY;
149
150 if (actions & GDK_ACTION_MOVE)
151 return GDK_ACTION_MOVE;
152
153 if (actions & GDK_ACTION_LINK)
154 return GDK_ACTION_LINK;
155
156 return 0;
157}
158
159static GdkDragAction
160gtk_drop_target_async_drag_enter (GtkDropTargetAsync *self,
161 GdkDrop *drop,
162 double x,
163 double y)
164{
165 return make_action_unique (actions: self->actions & gdk_drop_get_actions (self: drop));
166}
167
168static GdkDragAction
169gtk_drop_target_async_drag_motion (GtkDropTargetAsync *self,
170 GdkDrop *drop,
171 double x,
172 double y)
173{
174 return make_action_unique (actions: self->actions & gdk_drop_get_actions (self: drop));
175}
176
177static gboolean
178gtk_drop_target_async_drop (GtkDropTargetAsync *self,
179 GdkDrop *drop,
180 double x,
181 double y)
182{
183 return FALSE;
184}
185
186static gboolean
187gtk_drop_target_async_filter_event (GtkEventController *controller,
188 GdkEvent *event)
189{
190 switch ((int)gdk_event_get_event_type (event))
191 {
192 case GDK_DRAG_ENTER:
193 case GDK_DRAG_LEAVE:
194 case GDK_DRAG_MOTION:
195 case GDK_DROP_START:
196 return GTK_EVENT_CONTROLLER_CLASS (gtk_drop_target_async_parent_class)->filter_event (controller, event);
197
198 default:;
199 }
200
201 return TRUE;
202}
203
204static gboolean
205gtk_drop_target_async_handle_event (GtkEventController *controller,
206 GdkEvent *event,
207 double x,
208 double y)
209{
210 GtkDropTargetAsync *self = GTK_DROP_TARGET_ASYNC (controller);
211 GdkDrop *drop;
212
213 switch ((int) gdk_event_get_event_type (event))
214 {
215 case GDK_DRAG_MOTION:
216 {
217 GtkWidget *widget = gtk_event_controller_get_widget (controller);
218 GdkDragAction preferred_action;
219
220 drop = gdk_dnd_event_get_drop (event);
221 /* sanity check */
222 g_return_val_if_fail (self->drop == drop, FALSE);
223 if (self->rejected)
224 return FALSE;
225
226 g_signal_emit (instance: self, signal_id: signals[DRAG_MOTION], detail: 0, drop, x, y, &preferred_action);
227 if (preferred_action &&
228 gtk_drop_status (drop: self->drop, actions: self->actions, preferred_action))
229 {
230 gtk_widget_set_state_flags (widget, flags: GTK_STATE_FLAG_DROP_ACTIVE, FALSE);
231 }
232 else
233 {
234 gtk_widget_unset_state_flags (widget, flags: GTK_STATE_FLAG_DROP_ACTIVE);
235 }
236 }
237 return FALSE;
238
239 case GDK_DROP_START:
240 {
241 gboolean handled;
242
243 drop = gdk_dnd_event_get_drop (event);
244 /* sanity check */
245 g_return_val_if_fail (self->drop == drop, FALSE);
246 if (self->rejected)
247 return FALSE;
248
249 g_signal_emit (instance: self, signal_id: signals[DROP], detail: 0, self->drop, x, y, &handled);
250 return handled;
251 }
252
253 default:
254 return FALSE;
255 }
256}
257
258static void
259gtk_drop_target_async_handle_crossing (GtkEventController *controller,
260 const GtkCrossingData *crossing,
261 double x,
262 double y)
263{
264 GtkDropTargetAsync *self = GTK_DROP_TARGET_ASYNC (controller);
265 GtkWidget *widget = gtk_event_controller_get_widget (controller);
266
267 if (crossing->type != GTK_CROSSING_DROP)
268 return;
269
270 /* sanity check */
271 g_warn_if_fail (self->drop == NULL || self->drop == crossing->drop);
272
273 if (crossing->direction == GTK_CROSSING_IN)
274 {
275 gboolean accept = FALSE;
276 GdkDragAction preferred_action;
277
278 if (self->drop != NULL)
279 return;
280
281 self->drop = g_object_ref (crossing->drop);
282
283 g_signal_emit (instance: self, signal_id: signals[ACCEPT], detail: 0, self->drop, &accept);
284 self->rejected = !accept;
285 if (self->rejected)
286 return;
287
288 g_signal_emit (instance: self, signal_id: signals[DRAG_ENTER], detail: 0, self->drop, x, y, &preferred_action);
289 if (preferred_action &&
290 gtk_drop_status (drop: self->drop, actions: self->actions, preferred_action))
291 {
292 gtk_widget_set_state_flags (widget, flags: GTK_STATE_FLAG_DROP_ACTIVE, FALSE);
293 }
294 }
295 else
296 {
297 if (crossing->new_descendent != NULL ||
298 crossing->new_target == widget)
299 return;
300
301 g_signal_emit (instance: self, signal_id: signals[DRAG_LEAVE], detail: 0, self->drop);
302 g_clear_object (&self->drop);
303 gtk_widget_unset_state_flags (widget, flags: GTK_STATE_FLAG_DROP_ACTIVE);
304 }
305}
306
307static void
308gtk_drop_target_async_finalize (GObject *object)
309{
310 GtkDropTargetAsync *self = GTK_DROP_TARGET_ASYNC (object);
311
312 g_clear_pointer (&self->formats, gdk_content_formats_unref);
313
314 G_OBJECT_CLASS (gtk_drop_target_async_parent_class)->finalize (object);
315}
316
317static void
318gtk_drop_target_async_set_property (GObject *object,
319 guint prop_id,
320 const GValue *value,
321 GParamSpec *pspec)
322{
323 GtkDropTargetAsync *self = GTK_DROP_TARGET_ASYNC (object);
324
325 switch (prop_id)
326 {
327 case PROP_ACTIONS:
328 gtk_drop_target_async_set_actions (self, actions: g_value_get_flags (value));
329 break;
330
331 case PROP_FORMATS:
332 gtk_drop_target_async_set_formats (self, formats: g_value_get_boxed (value));
333 break;
334
335 default:
336 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
337 }
338}
339
340static void
341gtk_drop_target_async_get_property (GObject *object,
342 guint prop_id,
343 GValue *value,
344 GParamSpec *pspec)
345{
346 GtkDropTargetAsync *self = GTK_DROP_TARGET_ASYNC (object);
347
348 switch (prop_id)
349 {
350 case PROP_ACTIONS:
351 g_value_set_flags (value, v_flags: gtk_drop_target_async_get_actions (self));
352 break;
353
354 case PROP_FORMATS:
355 g_value_set_boxed (value, v_boxed: gtk_drop_target_async_get_formats (self));
356 break;
357
358 default:
359 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
360 }
361}
362
363static void
364gtk_drop_target_async_class_init (GtkDropTargetAsyncClass *class)
365{
366 GObjectClass *object_class = G_OBJECT_CLASS (class);
367 GtkEventControllerClass *controller_class = GTK_EVENT_CONTROLLER_CLASS (class);
368
369 object_class->finalize = gtk_drop_target_async_finalize;
370 object_class->set_property = gtk_drop_target_async_set_property;
371 object_class->get_property = gtk_drop_target_async_get_property;
372
373 controller_class->handle_event = gtk_drop_target_async_handle_event;
374 controller_class->filter_event = gtk_drop_target_async_filter_event;
375 controller_class->handle_crossing = gtk_drop_target_async_handle_crossing;
376
377 class->accept = gtk_drop_target_async_accept;
378 class->drag_enter = gtk_drop_target_async_drag_enter;
379 class->drag_motion = gtk_drop_target_async_drag_motion;
380 class->drop = gtk_drop_target_async_drop;
381
382 /**
383 * GtkDropTargetAsync:actions: (attributes org.gtk.Property.get=gtk_drop_target_async_get_actions org.gtk.Property.set=gtk_drop_target_async_set_actions)
384 *
385 * The `GdkDragActions` that this drop target supports.
386 */
387 properties[PROP_ACTIONS] =
388 g_param_spec_flags (name: "actions", P_("Actions"), P_("Actions"),
389 flags_type: GDK_TYPE_DRAG_ACTION, default_value: 0,
390 flags: G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
391
392 /**
393 * GtkDropTargetAsync:formats: (attributes org.gtk.Property.get=gtk_drop_target_async_get_formats org.gtk.Property.set=gtk_drop_target_async_set_formats)
394 *
395 * The `GdkContentFormats` that determines the supported data formats.
396 */
397 properties[PROP_FORMATS] =
398 g_param_spec_boxed (name: "formats", P_("Formats"), P_("Formats"),
399 GDK_TYPE_CONTENT_FORMATS,
400 flags: G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
401
402 g_object_class_install_properties (oclass: object_class, n_pspecs: NUM_PROPERTIES, pspecs: properties);
403
404 /**
405 * GtkDropTargetAsync::accept:
406 * @self: the `GtkDropTargetAsync`
407 * @drop: the `GdkDrop`
408 *
409 * Emitted on the drop site when a drop operation is about to begin.
410 *
411 * If the drop is not accepted, %FALSE will be returned and the drop target
412 * will ignore the drop. If %TRUE is returned, the drop is accepted for now
413 * but may be rejected later via a call to [method@Gtk.DropTargetAsync.reject_drop]
414 * or ultimately by returning %FALSE from a [signal@Gtk.DropTargetAsync::drop]
415 * handler.
416 *
417 * The default handler for this signal decides whether to accept the drop
418 * based on the formats provided by the @drop.
419 *
420 * If the decision whether the drop will be accepted or rejected needs
421 * further processing, such as inspecting the data, this function should
422 * return %TRUE and proceed as is @drop was accepted and if it decides to
423 * reject the drop later, it should call [method@Gtk.DropTargetAsync.reject_drop].
424 *
425 * Returns: %TRUE if @drop is accepted
426 */
427 signals[ACCEPT] =
428 g_signal_new (I_("accept"),
429 G_TYPE_FROM_CLASS (class),
430 signal_flags: G_SIGNAL_RUN_LAST,
431 G_STRUCT_OFFSET (GtkDropTargetAsyncClass, accept),
432 accumulator: g_signal_accumulator_first_wins, NULL,
433 NULL,
434 G_TYPE_BOOLEAN, n_params: 1,
435 GDK_TYPE_DROP);
436
437 /**
438 * GtkDropTargetAsync::drag-enter:
439 * @self: the `GtkDropTargetAsync`
440 * @drop: the `GdkDrop`
441 * @x: the x coordinate of the current pointer position
442 * @y: the y coordinate of the current pointer position
443 *
444 * Emitted on the drop site when the pointer enters the widget.
445 *
446 * It can be used to set up custom highlighting.
447 *
448 * Returns: Preferred action for this drag operation.
449 */
450 signals[DRAG_ENTER] =
451 g_signal_new (I_("drag-enter"),
452 G_TYPE_FROM_CLASS (class),
453 signal_flags: G_SIGNAL_RUN_LAST,
454 G_STRUCT_OFFSET (GtkDropTargetAsyncClass, drag_enter),
455 accumulator: g_signal_accumulator_first_wins, NULL,
456 NULL,
457 return_type: GDK_TYPE_DRAG_ACTION, n_params: 3,
458 GDK_TYPE_DROP, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
459
460 /**
461 * GtkDropTargetAsync::drag-motion:
462 * @self: the `GtkDropTargetAsync`
463 * @drop: the `GdkDrop`
464 * @x: the x coordinate of the current pointer position
465 * @y: the y coordinate of the current pointer position
466 *
467 * Emitted while the pointer is moving over the drop target.
468 *
469 * Returns: Preferred action for this drag operation.
470 */
471 signals[DRAG_MOTION] =
472 g_signal_new (I_("drag-motion"),
473 G_TYPE_FROM_CLASS (class),
474 signal_flags: G_SIGNAL_RUN_LAST,
475 G_STRUCT_OFFSET (GtkDropTargetAsyncClass, drag_motion),
476 accumulator: g_signal_accumulator_first_wins, NULL,
477 NULL,
478 return_type: GDK_TYPE_DRAG_ACTION, n_params: 3,
479 GDK_TYPE_DROP, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
480
481 /**
482 * GtkDropTargetAsync::drag-leave:
483 * @self: the `GtkDropTargetAsync`
484 * @drop: the `GdkDrop`
485 *
486 * Emitted on the drop site when the pointer leaves the widget.
487 *
488 * Its main purpose it to undo things done in
489 * `GtkDropTargetAsync`::drag-enter.
490 */
491 signals[DRAG_LEAVE] =
492 g_signal_new (I_("drag-leave"),
493 G_TYPE_FROM_CLASS (class),
494 signal_flags: G_SIGNAL_RUN_LAST,
495 G_STRUCT_OFFSET (GtkDropTargetAsyncClass, drag_leave),
496 NULL, NULL,
497 NULL,
498 G_TYPE_NONE, n_params: 1,
499 GDK_TYPE_DROP);
500
501 /**
502 * GtkDropTargetAsync::drop:
503 * @self: the `GtkDropTargetAsync`
504 * @drop: the `GdkDrop`
505 * @x: the x coordinate of the current pointer position
506 * @y: the y coordinate of the current pointer position
507 *
508 * Emitted on the drop site when the user drops the data onto the widget.
509 *
510 * The signal handler must determine whether the pointer position is in a
511 * drop zone or not. If it is not in a drop zone, it returns %FALSE and no
512 * further processing is necessary.
513 *
514 * Otherwise, the handler returns %TRUE. In this case, this handler will
515 * accept the drop. The handler must ensure that [method@Gdk.Drop.finish]
516 * is called to let the source know that the drop is done. The call to
517 * [method@Gdk.Drop.finish] must only be done when all data has been received.
518 *
519 * To receive the data, use one of the read functions provided by
520 * [class@Gdk.Drop] such as [method@Gdk.Drop.read_async] or
521 * [method@Gdk.Drop.read_value_async].
522 *
523 * Returns: whether the drop is accepted at the given pointer position
524 */
525 signals[DROP] =
526 g_signal_new (I_("drop"),
527 G_TYPE_FROM_CLASS (class),
528 signal_flags: G_SIGNAL_RUN_LAST,
529 class_offset: 0,
530 accumulator: g_signal_accumulator_first_wins, NULL,
531 NULL,
532 G_TYPE_BOOLEAN, n_params: 3,
533 GDK_TYPE_DROP, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
534}
535
536static void
537gtk_drop_target_async_init (GtkDropTargetAsync *self)
538{
539}
540
541/**
542 * gtk_drop_target_async_new:
543 * @formats: (nullable) (transfer full): the supported data formats
544 * @actions: the supported actions
545 *
546 * Creates a new `GtkDropTargetAsync` object.
547 *
548 * Returns: the new `GtkDropTargetAsync`
549 */
550GtkDropTargetAsync *
551gtk_drop_target_async_new (GdkContentFormats *formats,
552 GdkDragAction actions)
553{
554 GtkDropTargetAsync *result;
555
556 result = g_object_new (GTK_TYPE_DROP_TARGET_ASYNC,
557 first_property_name: "formats", formats,
558 "actions", actions,
559 NULL);
560
561 g_clear_pointer (&formats, gdk_content_formats_unref);
562
563 return result;
564}
565
566/**
567 * gtk_drop_target_async_set_formats: (attributes org.gtk.Method.set_property=formats)
568 * @self: a `GtkDropTargetAsync`
569 * @formats: (nullable): the supported data formats or %NULL for any format
570 *
571 * Sets the data formats that this drop target will accept.
572 */
573void
574gtk_drop_target_async_set_formats (GtkDropTargetAsync *self,
575 GdkContentFormats *formats)
576{
577 g_return_if_fail (GTK_IS_DROP_TARGET_ASYNC (self));
578
579 if (self->formats == formats)
580 return;
581
582 if (self->formats)
583 gdk_content_formats_unref (formats: self->formats);
584
585 self->formats = formats;
586
587 if (self->formats)
588 gdk_content_formats_ref (formats: self->formats);
589
590 g_object_notify_by_pspec (G_OBJECT (self), pspec: properties[PROP_FORMATS]);
591}
592
593/**
594 * gtk_drop_target_async_get_formats: (attributes org.gtk.Method.get_property=formats)
595 * @self: a `GtkDropTargetAsync`
596 *
597 * Gets the data formats that this drop target accepts.
598 *
599 * If the result is %NULL, all formats are expected to be supported.
600 *
601 * Returns: (nullable): the supported data formats
602 */
603GdkContentFormats *
604gtk_drop_target_async_get_formats (GtkDropTargetAsync *self)
605{
606 g_return_val_if_fail (GTK_IS_DROP_TARGET_ASYNC (self), NULL);
607
608 return self->formats;
609}
610
611/**
612 * gtk_drop_target_async_set_actions: (attributes org.gtk.Method.set_property=actions)
613 * @self: a `GtkDropTargetAsync`
614 * @actions: the supported actions
615 *
616 * Sets the actions that this drop target supports.
617 */
618void
619gtk_drop_target_async_set_actions (GtkDropTargetAsync *self,
620 GdkDragAction actions)
621{
622 g_return_if_fail (GTK_IS_DROP_TARGET_ASYNC (self));
623
624 if (self->actions == actions)
625 return;
626
627 self->actions = actions;
628
629 g_object_notify_by_pspec (G_OBJECT (self), pspec: properties[PROP_ACTIONS]);
630}
631
632/**
633 * gtk_drop_target_async_get_actions: (attributes org.gtk.Method.get_property=actions)
634 * @self: a `GtkDropTargetAsync`
635 *
636 * Gets the actions that this drop target supports.
637 *
638 * Returns: the actions that this drop target supports
639 */
640GdkDragAction
641gtk_drop_target_async_get_actions (GtkDropTargetAsync *self)
642{
643 g_return_val_if_fail (GTK_IS_DROP_TARGET_ASYNC (self), 0);
644
645 return self->actions;
646}
647
648/**
649 * gtk_drop_target_async_reject_drop:
650 * @self: a `GtkDropTargetAsync`
651 * @drop: the `GdkDrop` of an ongoing drag operation
652 *
653 * Sets the @drop as not accepted on this drag site.
654 *
655 * This function should be used when delaying the decision
656 * on whether to accept a drag or not until after reading
657 * the data.
658 */
659void
660gtk_drop_target_async_reject_drop (GtkDropTargetAsync *self,
661 GdkDrop *drop)
662{
663 g_return_if_fail (GTK_IS_DROP_TARGET_ASYNC (self));
664 g_return_if_fail (GDK_IS_DROP (drop));
665 g_return_if_fail (self->drop == drop);
666
667 if (self->rejected)
668 return;
669
670 self->rejected = TRUE;
671 gtk_widget_unset_state_flags (widget: gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (self)),
672 flags: GTK_STATE_FLAG_DROP_ACTIVE);
673}
674

source code of gtk/gtk/gtkdroptargetasync.c