2 * Copyright (C) 2001 Red Hat, Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library 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.
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 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301 USA.
21 #include <gtk/gtktreeselection.h>
22 #include <gtk/gtksignal.h>
23 #include <gtk/gtkwidget.h>
24 #include <gtk/gtkmain.h>
25 #include <gtk/gtktreednd.h>
26 #include "rb-tree-dnd.h"
30 #define RB_TREE_DND_STRING "RbTreeDndString"
31 /* must be the same value as in gtk_tree_view.c */
32 #define SCROLL_EDGE_SIZE 15
39 guint button_press_event_handler
;
40 guint motion_notify_handler
;
41 guint button_release_handler
;
42 guint drag_data_get_handler
;
43 guint drag_data_delete_handler
;
44 guint drag_motion_handler
;
45 guint drag_leave_handler
;
46 guint drag_drop_handler
;
47 guint drag_data_received_handler
;
49 gboolean pending_event
;
51 GtkTargetList
*dest_target_list
;
52 GdkDragAction dest_actions
;
53 RbTreeDestFlag dest_flags
;
55 GtkTargetList
*source_target_list
;
56 GdkDragAction source_actions
;
57 GdkModifierType start_button_mask
;
59 /* Scroll timeout (e.g. during dnd) */
62 /* Select on drag timeout */
63 GtkTreePath
* previous_dest_path
;
64 guint select_on_drag_timeout
;
67 RbTreeDndData
*init_rb_tree_dnd_data (GtkWidget
*widget
);
68 GList
* get_context_data (GdkDragContext
*context
);
69 static gboolean
filter_drop_position (GtkWidget
*widget
, GdkDragContext
*context
, GtkTreePath
*path
, GtkTreeViewDropPosition
*pos
);
70 static gint
scroll_row_timeout (gpointer data
);
71 static gboolean
select_on_drag_timeout (gpointer data
);
72 static void remove_scroll_timeout (GtkTreeView
*tree_view
);
73 static void remove_select_on_drag_timeout (GtkTreeView
*tree_view
);
76 rb_tree_drag_source_get_type (void)
78 static GType our_type
= 0;
82 static const GTypeInfo our_info
=
84 sizeof (RbTreeDragSourceIface
), /* class_size */
86 NULL
, /* base_finalize */
88 NULL
, /* class_finalize */
89 NULL
, /* class_data */
95 our_type
= g_type_register_static (G_TYPE_INTERFACE
, "RbTreeDragSource", &our_info
, 0);
103 * rb_tree_drag_source_row_draggable:
104 * @drag_source: a #EggTreeMultiDragSource
105 * @path: row on which user is initiating a drag
107 * Asks the #EggTreeMultiDragSource whether a particular row can be used as
108 * the source of a DND operation. If the source doesn't implement
109 * this interface, the row is assumed draggable.
111 * Return value: %TRUE if the row can be dragged
114 rb_tree_drag_source_row_draggable (RbTreeDragSource
*drag_source
,
117 RbTreeDragSourceIface
*iface
= RB_TREE_DRAG_SOURCE_GET_IFACE (drag_source
);
119 g_return_val_if_fail (RB_IS_TREE_DRAG_SOURCE (drag_source
), FALSE
);
120 g_return_val_if_fail (iface
->rb_row_draggable
!= NULL
, FALSE
);
121 g_return_val_if_fail (path_list
!= NULL
, FALSE
);
123 if (iface
->rb_row_draggable
)
124 return (* iface
->rb_row_draggable
) (drag_source
, path_list
);
131 * rb_tree_drag_source_drag_data_delete:
132 * @drag_source: a #EggTreeMultiDragSource
133 * @path: row that was being dragged
135 * Asks the #EggTreeMultiDragSource to delete the row at @path, because
136 * it was moved somewhere else via drag-and-drop. Returns %FALSE
137 * if the deletion fails because @path no longer exists, or for
138 * some model-specific reason. Should robustly handle a @path no
139 * longer found in the model!
141 * Return value: %TRUE if the row was successfully deleted
144 rb_tree_drag_source_drag_data_delete (RbTreeDragSource
*drag_source
,
147 RbTreeDragSourceIface
*iface
= RB_TREE_DRAG_SOURCE_GET_IFACE (drag_source
);
149 g_return_val_if_fail (RB_IS_TREE_DRAG_SOURCE (drag_source
), FALSE
);
150 g_return_val_if_fail (iface
->rb_drag_data_delete
!= NULL
, FALSE
);
151 g_return_val_if_fail (path_list
!= NULL
, FALSE
);
153 return (* iface
->rb_drag_data_delete
) (drag_source
, path_list
);
157 * rb_tree_drag_source_drag_data_get:
158 * @drag_source: a #EggTreeMultiDragSource
159 * @path: row that was dragged
160 * @selection_data: a #EggSelectionData to fill with data from the dragged row
162 * Asks the #EggTreeMultiDragSource to fill in @selection_data with a
163 * representation of the row at @path. @selection_data->target gives
164 * the required type of the data. Should robustly handle a @path no
165 * longer found in the model!
167 * Return value: %TRUE if data of the required type was provided
170 rb_tree_drag_source_drag_data_get (RbTreeDragSource
*drag_source
,
172 GtkSelectionData
*selection_data
)
174 RbTreeDragSourceIface
*iface
= RB_TREE_DRAG_SOURCE_GET_IFACE (drag_source
);
176 g_return_val_if_fail (RB_IS_TREE_DRAG_SOURCE (drag_source
), FALSE
);
177 g_return_val_if_fail (iface
->rb_drag_data_get
!= NULL
, FALSE
);
178 g_return_val_if_fail (path_list
!= NULL
, FALSE
);
179 g_return_val_if_fail (selection_data
!= NULL
, FALSE
);
181 return (* iface
->rb_drag_data_get
) (drag_source
, path_list
, selection_data
);
187 rb_tree_drag_dest_get_type (void)
189 static GType our_type
= 0;
193 static const GTypeInfo our_info
=
195 sizeof (RbTreeDragDestIface
), /* class_size */
196 NULL
, /* base_init */
197 NULL
, /* base_finalize */
199 NULL
, /* class_finalize */
200 NULL
, /* class_data */
206 our_type
= g_type_register_static (G_TYPE_INTERFACE
, "RbTreeDragDest", &our_info
, 0);
215 rb_tree_drag_dest_drag_data_received (RbTreeDragDest
*drag_dest
,
217 GtkTreeViewDropPosition pos
,
218 GtkSelectionData
*selection_data
)
220 RbTreeDragDestIface
*iface
= RB_TREE_DRAG_DEST_GET_IFACE (drag_dest
);
222 g_return_val_if_fail (RB_IS_TREE_DRAG_DEST (drag_dest
), FALSE
);
223 g_return_val_if_fail (iface
->rb_drag_data_received
!= NULL
, FALSE
);
224 g_return_val_if_fail (selection_data
!= NULL
, FALSE
);
226 return (* iface
->rb_drag_data_received
) (drag_dest
, dest
, pos
, selection_data
);
232 rb_tree_drag_dest_row_drop_possible (RbTreeDragDest
*drag_dest
,
233 GtkTreePath
*dest_path
,
234 GtkTreeViewDropPosition pos
,
235 GtkSelectionData
*selection_data
)
237 RbTreeDragDestIface
*iface
= RB_TREE_DRAG_DEST_GET_IFACE (drag_dest
);
239 g_return_val_if_fail (RB_IS_TREE_DRAG_DEST (drag_dest
), FALSE
);
240 g_return_val_if_fail (iface
->rb_row_drop_possible
!= NULL
, FALSE
);
241 g_return_val_if_fail (selection_data
!= NULL
, FALSE
);
243 return (* iface
->rb_row_drop_possible
) (drag_dest
, dest_path
, pos
, selection_data
);
248 rb_tree_drag_dest_row_drop_position (RbTreeDragDest
*drag_dest
,
249 GtkTreePath
*dest_path
,
251 GtkTreeViewDropPosition
*pos
)
253 RbTreeDragDestIface
*iface
= RB_TREE_DRAG_DEST_GET_IFACE (drag_dest
);
255 g_return_val_if_fail (RB_IS_TREE_DRAG_DEST (drag_dest
), FALSE
);
256 g_return_val_if_fail (iface
->rb_row_drop_position
!= NULL
, FALSE
);
257 g_return_val_if_fail (targets
!= NULL
, FALSE
);
258 g_return_val_if_fail (pos
!= NULL
, FALSE
);
260 return (* iface
->rb_row_drop_position
) (drag_dest
, dest_path
, targets
, pos
);
264 rb_tree_dnd_data_free (gpointer data
)
266 RbTreeDndData
*priv_data
= data
;
268 gtk_target_list_unref (priv_data
->source_target_list
);
274 init_rb_tree_dnd_data (GtkWidget
*widget
)
276 RbTreeDndData
*priv_data
;
278 priv_data
= g_object_get_data (G_OBJECT (widget
), RB_TREE_DND_STRING
);
279 if (priv_data
== NULL
)
281 priv_data
= g_new0 (RbTreeDndData
, 1);
282 priv_data
->pending_event
= FALSE
;
283 g_object_set_data_full (G_OBJECT (widget
), RB_TREE_DND_STRING
, priv_data
, rb_tree_dnd_data_free
);
284 priv_data
->drag_motion_handler
= 0;
285 priv_data
->drag_leave_handler
= 0;
286 priv_data
->button_press_event_handler
= 0;
287 priv_data
->scroll_timeout
= 0;
288 priv_data
->previous_dest_path
= NULL
;
289 priv_data
->select_on_drag_timeout
= 0;
296 stop_drag_check (GtkWidget
*widget
)
298 RbTreeDndData
*priv_data
;
301 priv_data
= g_object_get_data (G_OBJECT (widget
), RB_TREE_DND_STRING
);
303 for (l
= priv_data
->event_list
; l
!= NULL
; l
= l
->next
)
304 gdk_event_free (l
->data
);
306 g_slist_free (priv_data
->event_list
);
307 priv_data
->event_list
= NULL
;
308 priv_data
->pending_event
= FALSE
;
309 g_signal_handler_disconnect (widget
, priv_data
->motion_notify_handler
);
310 g_signal_handler_disconnect (widget
, priv_data
->button_release_handler
);
315 rb_tree_dnd_button_release_event_cb (GtkWidget
*widget
,
316 GdkEventButton
*event
,
319 RbTreeDndData
*priv_data
;
322 priv_data
= g_object_get_data (G_OBJECT (widget
), RB_TREE_DND_STRING
);
324 for (l
= priv_data
->event_list
; l
!= NULL
; l
= l
->next
)
325 gtk_propagate_event (widget
, l
->data
);
327 stop_drag_check (widget
);
334 selection_foreach (GtkTreeModel
*model
,
341 list_ptr
= (GList
**) data
;
342 *list_ptr
= g_list_prepend (*list_ptr
, gtk_tree_row_reference_new (model
, path
));
347 path_list_free (GList
*path_list
)
349 g_list_foreach (path_list
, (GFunc
) gtk_tree_row_reference_free
, NULL
);
350 g_list_free (path_list
);
354 set_context_data (GdkDragContext
*context
,
357 g_object_set_data_full (G_OBJECT (context
),
358 "rb-tree-view-multi-source-row",
360 (GDestroyNotify
) path_list_free
);
362 rb_debug ("Setting path_list: index=%i", gtk_tree_path_get_indices(path_list
->data
)[0]);
366 get_context_data (GdkDragContext
*context
)
368 return g_object_get_data (G_OBJECT (context
), "rb-tree-view-multi-source-row");
372 filter_drop_position (GtkWidget
*widget
, GdkDragContext
*context
, GtkTreePath
*path
, GtkTreeViewDropPosition
*pos
)
374 GtkTreeView
*tree_view
= GTK_TREE_VIEW (widget
);
375 GtkTreeModel
*model
= gtk_tree_view_get_model (tree_view
);
376 RbTreeDndData
*priv_data
= g_object_get_data (G_OBJECT (widget
), RB_TREE_DND_STRING
);
379 if (!(priv_data
->dest_flags
& RB_TREE_DEST_CAN_DROP_INTO
)) {
380 if (*pos
== GTK_TREE_VIEW_DROP_INTO_OR_BEFORE
)
381 *pos
= GTK_TREE_VIEW_DROP_BEFORE
;
382 else if (*pos
== GTK_TREE_VIEW_DROP_INTO_OR_AFTER
)
383 *pos
= GTK_TREE_VIEW_DROP_AFTER
;
384 } else if (!(priv_data
->dest_flags
& RB_TREE_DEST_CAN_DROP_BETWEEN
)) {
385 if (*pos
== GTK_TREE_VIEW_DROP_BEFORE
)
386 *pos
= GTK_TREE_VIEW_DROP_INTO_OR_BEFORE
;
387 else if (*pos
== GTK_TREE_VIEW_DROP_AFTER
)
388 *pos
= GTK_TREE_VIEW_DROP_INTO_OR_AFTER
;
391 ret
= rb_tree_drag_dest_row_drop_position (RB_TREE_DRAG_DEST (model
),
396 rb_debug ("filtered drop position: %s", ret
? "TRUE" : "FALSE");
401 /* Scroll function taken/adapted from gtktreeview.c */
403 scroll_row_timeout (gpointer data
)
405 GtkTreeView
*tree_view
= data
;
406 GdkRectangle visible_rect
;
411 RbTreeDndData
*priv_data
;
413 GDK_THREADS_ENTER ();
415 priv_data
= g_object_get_data (G_OBJECT (tree_view
), RB_TREE_DND_STRING
);
416 g_return_val_if_fail(priv_data
!= NULL
, TRUE
);
418 gdk_window_get_pointer (gtk_tree_view_get_bin_window (tree_view
), &x
, &y
, NULL
);
419 gtk_tree_view_widget_to_tree_coords (tree_view
, x
, y
, &x
, &y
);
420 gtk_tree_view_get_visible_rect (tree_view
, &visible_rect
);
422 /* see if we are near the edge. */
423 if (x
< visible_rect
.x
&& x
> visible_rect
.x
+ visible_rect
.width
)
425 GDK_THREADS_LEAVE ();
426 priv_data
->scroll_timeout
= 0;
430 offset
= y
- (visible_rect
.y
+ 2 * SCROLL_EDGE_SIZE
);
433 offset
= y
- (visible_rect
.y
+ visible_rect
.height
- 2 * SCROLL_EDGE_SIZE
);
436 GDK_THREADS_LEAVE ();
437 priv_data
->scroll_timeout
= 0;
442 vadj
= gtk_tree_view_get_vadjustment (tree_view
);
443 value
= CLAMP (vadj
->value
+ offset
, vadj
->lower
, vadj
->upper
- vadj
->page_size
);
444 gtk_adjustment_set_value (vadj
, value
);
446 /* don't remove it if we're on the edge and not scrolling */
447 if (ABS (vadj
->value
- value
) > 0.0001)
448 remove_select_on_drag_timeout(tree_view
);
450 GDK_THREADS_LEAVE ();
457 select_on_drag_timeout (gpointer data
)
459 GtkTreeView
*tree_view
= data
;
460 GtkTreeSelection
*selection
;
461 RbTreeDndData
*priv_data
;
463 GDK_THREADS_ENTER ();
465 priv_data
= g_object_get_data (G_OBJECT (tree_view
), RB_TREE_DND_STRING
);
466 g_return_val_if_fail(priv_data
!= NULL
, FALSE
);
467 g_return_val_if_fail(priv_data
->previous_dest_path
!= NULL
, FALSE
);
469 selection
= gtk_tree_view_get_selection(tree_view
);
470 if (!gtk_tree_selection_path_is_selected(selection
,priv_data
->previous_dest_path
)) {
471 rb_debug("Changing selection because of drag timeout");
472 gtk_tree_view_set_cursor(tree_view
,priv_data
->previous_dest_path
,NULL
,FALSE
);
475 priv_data
->select_on_drag_timeout
= 0;
476 gtk_tree_path_free(priv_data
->previous_dest_path
);
477 priv_data
->previous_dest_path
= NULL
;
479 GDK_THREADS_LEAVE ();
485 remove_scroll_timeout (GtkTreeView
*tree_view
)
487 RbTreeDndData
*priv_data
;
489 priv_data
= g_object_get_data (G_OBJECT (tree_view
), RB_TREE_DND_STRING
);
490 g_return_if_fail(priv_data
!= NULL
);
492 if (priv_data
->scroll_timeout
!= 0)
494 g_source_remove (priv_data
->scroll_timeout
);
495 priv_data
->scroll_timeout
= 0;
501 remove_select_on_drag_timeout (GtkTreeView
*tree_view
)
503 RbTreeDndData
*priv_data
;
505 priv_data
= g_object_get_data (G_OBJECT (tree_view
), RB_TREE_DND_STRING
);
506 g_return_if_fail(priv_data
!= NULL
);
508 if (priv_data
->select_on_drag_timeout
!= 0) {
509 rb_debug("Removing the select on drag timeout");
510 g_source_remove (priv_data
->select_on_drag_timeout
);
511 priv_data
->select_on_drag_timeout
= 0;
513 if (priv_data
->previous_dest_path
!= NULL
) {
514 gtk_tree_path_free(priv_data
->previous_dest_path
);
515 priv_data
->previous_dest_path
= NULL
;
521 rb_tree_dnd_drag_data_delete_cb (GtkWidget
*widget
,
522 GdkDragContext
*drag_context
,
526 GtkTreeModel
*model
= gtk_tree_view_get_model (GTK_TREE_VIEW(widget
));
528 path_list
= get_context_data (drag_context
);
529 rb_tree_drag_source_drag_data_delete (RB_TREE_DRAG_SOURCE (model
),
532 g_signal_stop_emission_by_name (widget
, "drag_data_delete");
538 rb_tree_dnd_drag_data_get_cb (GtkWidget
*widget
,
539 GdkDragContext
*context
,
540 GtkSelectionData
*selection_data
,
544 GtkTreeView
*tree_view
;
548 tree_view
= GTK_TREE_VIEW (widget
);
549 model
= gtk_tree_view_get_model (tree_view
);
554 path_list
= get_context_data (context
);
556 if (path_list
== NULL
)
559 /* We can implement the GTK_TREE_MODEL_ROW target generically for
560 * any model; for DragSource models there are some other targets
563 if (RB_IS_TREE_DRAG_SOURCE (model
))
565 rb_tree_drag_source_drag_data_get (RB_TREE_DRAG_SOURCE (model
),
573 rb_tree_dnd_motion_notify_event_cb (GtkWidget
*widget
,
574 GdkEventMotion
*event
,
577 RbTreeDndData
*priv_data
;
579 priv_data
= g_object_get_data (G_OBJECT (widget
), RB_TREE_DND_STRING
);
581 if (gtk_drag_check_threshold (widget
,
587 GList
*path_list
= NULL
;
588 GtkTreeSelection
*selection
;
590 GdkDragContext
*context
;
592 selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (widget
));
593 stop_drag_check (widget
);
594 gtk_tree_selection_selected_foreach (selection
, selection_foreach
, &path_list
);
595 path_list
= g_list_reverse (path_list
);
596 model
= gtk_tree_view_get_model (GTK_TREE_VIEW (widget
));
598 if (rb_tree_drag_source_row_draggable (RB_TREE_DRAG_SOURCE (model
), path_list
))
600 rb_debug ("drag begin");
601 context
= gtk_drag_begin (widget
,
602 priv_data
->source_target_list
,
603 priv_data
->source_actions
,
604 priv_data
->pressed_button
,
606 set_context_data (context
, path_list
);
607 gtk_drag_set_icon_default (context
);
610 path_list_free (path_list
);
618 rb_tree_dnd_drag_motion_cb (GtkWidget
*widget
,
619 GdkDragContext
*context
,
624 GtkTreeView
*tree_view
;
625 GtkTreePath
*path
= NULL
;
627 GtkTreeViewDropPosition pos
;
628 RbTreeDndData
*priv_data
;
629 GdkDragAction action
;
631 rb_debug ("drag and drop motion: (%i,%i)", x
, y
);
633 tree_view
= GTK_TREE_VIEW (widget
);
634 model
= gtk_tree_view_get_model (tree_view
);
636 priv_data
= g_object_get_data (G_OBJECT (widget
), RB_TREE_DND_STRING
);
638 gtk_tree_view_get_dest_row_at_pos (tree_view
, x
, y
, &path
, &pos
);
640 if ((priv_data
->previous_dest_path
== NULL
)
642 || gtk_tree_path_compare(path
,priv_data
->previous_dest_path
)) {
643 remove_select_on_drag_timeout(tree_view
);
648 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget
),
650 GTK_TREE_VIEW_DROP_BEFORE
);
652 if (!(priv_data
->dest_flags
& RB_TREE_DEST_EMPTY_VIEW_DROP
)) {
653 /* Can't drop here. */
654 gdk_drag_status (context
, 0, time
);
657 } else if (!filter_drop_position (widget
, context
, path
, &pos
)) {
658 gdk_drag_status (context
, 0, time
);
664 if (!filter_drop_position (widget
, context
, path
, &pos
)) {
665 gdk_drag_status (context
, 0, time
);
669 if (priv_data
->scroll_timeout
== 0)
671 priv_data
->scroll_timeout
= g_timeout_add (150, scroll_row_timeout
, tree_view
);
675 if (GTK_WIDGET (tree_view
) == gtk_drag_get_source_widget (context
) &&
676 context
->actions
& GDK_ACTION_MOVE
)
677 action
= GDK_ACTION_MOVE
;
679 action
= context
->suggested_action
;
682 gtk_tree_view_set_drag_dest_row (tree_view
, path
, pos
);
683 if (priv_data
->dest_flags
& RB_TREE_DEST_SELECT_ON_DRAG_TIMEOUT
) {
684 if (priv_data
->previous_dest_path
!= NULL
) {
685 gtk_tree_path_free (priv_data
->previous_dest_path
);
687 priv_data
->previous_dest_path
= path
;
688 if (priv_data
->select_on_drag_timeout
== 0) {
689 rb_debug("Setting up a new select on drag timeout");
690 priv_data
->select_on_drag_timeout
= g_timeout_add (2000, select_on_drag_timeout
, tree_view
);
693 gtk_tree_path_free (path
);
697 gdk_drag_status (context
, action
, time
);
704 rb_tree_dnd_drag_leave_cb (GtkWidget
*widget
,
705 GdkDragContext
*context
,
710 remove_select_on_drag_timeout(GTK_TREE_VIEW (widget
));
715 rb_tree_dnd_drag_drop_cb (GtkWidget
*widget
,
716 GdkDragContext
*context
,
721 GtkTreeView
*tree_view
;
724 GtkTreeViewDropPosition pos
;
725 RbTreeDndData
*priv_data
;
727 tree_view
= GTK_TREE_VIEW (widget
);
728 model
= gtk_tree_view_get_model (tree_view
);
729 priv_data
= g_object_get_data (G_OBJECT (widget
), RB_TREE_DND_STRING
);
730 gtk_tree_view_get_dest_row_at_pos (tree_view
, x
, y
, &path
, &pos
);
732 remove_scroll_timeout (tree_view
);
734 /* Unset this thing */
735 gtk_tree_view_set_drag_dest_row (tree_view
,
737 GTK_TREE_VIEW_DROP_BEFORE
);
739 if (path
|| priv_data
->dest_flags
& RB_TREE_DEST_EMPTY_VIEW_DROP
) {
742 RbTreeDragDestIface
*iface
= RB_TREE_DRAG_DEST_GET_IFACE (model
);
743 if (iface
->rb_get_drag_target
) {
744 RbTreeDragDest
*dest
= RB_TREE_DRAG_DEST (model
);
745 target
= (* iface
->rb_get_drag_target
) (dest
, widget
,
747 priv_data
->dest_target_list
);
749 target
= gtk_drag_dest_find_target (widget
, context
,
750 priv_data
->dest_target_list
);
754 gtk_tree_path_free (path
);
756 if (target
!= GDK_NONE
) {
757 gtk_drag_get_data (widget
, context
, target
, time
);
767 rb_tree_dnd_drag_data_received_cb (GtkWidget
*widget
,
768 GdkDragContext
*context
,
771 GtkSelectionData
*selection_data
,
775 GtkTreeView
*tree_view
;
777 GtkTreePath
*dest_row
;
778 GtkTreeViewDropPosition pos
;
779 gboolean filtered
= TRUE
;
780 gboolean accepted
= FALSE
;
782 tree_view
= GTK_TREE_VIEW (widget
);
783 model
= gtk_tree_view_get_model (tree_view
);
785 gtk_tree_view_get_dest_row_at_pos (tree_view
, x
, y
, &dest_row
, &pos
);
788 if (!filter_drop_position (widget
, context
, dest_row
, &pos
))
791 if (filtered
&& selection_data
->length
>= 0)
793 if (rb_tree_drag_dest_drag_data_received (RB_TREE_DRAG_DEST (model
),
800 gtk_drag_finish (context
,
802 (context
->action
== GDK_ACTION_MOVE
),
806 gtk_tree_path_free (dest_row
);
808 g_signal_stop_emission_by_name (widget
, "drag_data_received");
814 rb_tree_dnd_button_press_event_cb (GtkWidget
*widget
,
815 GdkEventButton
*event
,
818 GtkTreeView
*tree_view
;
819 GtkTreePath
*path
= NULL
;
820 GtkTreeViewColumn
*column
= NULL
;
822 GtkTreeSelection
*selection
;
823 RbTreeDndData
*priv_data
;
825 if (event
->button
== 3)
828 tree_view
= GTK_TREE_VIEW (widget
);
829 if (event
->window
!= gtk_tree_view_get_bin_window (tree_view
))
832 priv_data
= g_object_get_data (G_OBJECT (tree_view
), RB_TREE_DND_STRING
);
833 if (priv_data
== NULL
)
835 priv_data
= g_new0 (RbTreeDndData
, 1);
836 priv_data
->pending_event
= FALSE
;
837 g_object_set_data (G_OBJECT (tree_view
), RB_TREE_DND_STRING
, priv_data
);
840 if (g_slist_find (priv_data
->event_list
, event
))
843 if (priv_data
->pending_event
)
845 /* save the event to be propagated in order */
846 priv_data
->event_list
= g_slist_append (priv_data
->event_list
, gdk_event_copy ((GdkEvent
*)event
));
850 if (event
->type
== GDK_2BUTTON_PRESS
)
853 gtk_tree_view_get_path_at_pos (tree_view
,
858 selection
= gtk_tree_view_get_selection (tree_view
);
862 gboolean call_parent
= (event
->state
& (GDK_CONTROL_MASK
| GDK_SHIFT_MASK
) ||
863 !gtk_tree_selection_path_is_selected (selection
, path
) ||
867 (GTK_WIDGET_GET_CLASS (tree_view
))->button_press_event (widget
, event
);
869 if (gtk_tree_selection_path_is_selected (selection
, path
))
871 priv_data
->pressed_button
= event
->button
;
872 priv_data
->x
= event
->x
;
873 priv_data
->y
= event
->y
;
875 priv_data
->pending_event
= TRUE
;
878 priv_data
->event_list
= g_slist_append (priv_data
->event_list
,
879 gdk_event_copy ((GdkEvent
*)event
));
881 priv_data
->motion_notify_handler
= g_signal_connect (G_OBJECT (tree_view
),
882 "motion_notify_event",
883 G_CALLBACK (rb_tree_dnd_motion_notify_event_cb
),
885 priv_data
->button_release_handler
= g_signal_connect (G_OBJECT (tree_view
),
886 "button_release_event",
887 G_CALLBACK (rb_tree_dnd_button_release_event_cb
),
892 gtk_tree_path_free (path
);
893 /* We called the default handler so we don't let the default handler run */
902 rb_tree_dnd_add_drag_source_support (GtkTreeView
*tree_view
,
903 GdkModifierType start_button_mask
,
904 const GtkTargetEntry
*targets
,
906 GdkDragAction actions
)
908 RbTreeDndData
*priv_data
= NULL
;
909 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view
));
911 priv_data
= init_rb_tree_dnd_data (GTK_WIDGET(tree_view
));
913 if (!priv_data
->button_press_event_handler
) {
915 priv_data
->source_target_list
= gtk_target_list_new (targets
, n_targets
);
916 priv_data
->source_actions
= actions
;
917 priv_data
->start_button_mask
= start_button_mask
;
919 priv_data
->button_press_event_handler
= g_signal_connect (G_OBJECT (tree_view
),
920 "button_press_event",
921 G_CALLBACK (rb_tree_dnd_button_press_event_cb
),
923 priv_data
->drag_data_get_handler
= g_signal_connect (G_OBJECT (tree_view
),
925 G_CALLBACK (rb_tree_dnd_drag_data_get_cb
),
927 priv_data
->drag_data_delete_handler
= g_signal_connect (G_OBJECT (tree_view
),
929 G_CALLBACK (rb_tree_dnd_drag_data_delete_cb
),
939 rb_tree_dnd_add_drag_dest_support (GtkTreeView
*tree_view
,
940 RbTreeDestFlag flags
,
941 const GtkTargetEntry
*targets
,
943 GdkDragAction actions
)
945 RbTreeDndData
*priv_data
= NULL
;
946 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view
));
948 priv_data
= init_rb_tree_dnd_data (GTK_WIDGET(tree_view
));
950 if (!priv_data
->drag_motion_handler
) {
952 priv_data
->dest_target_list
= gtk_target_list_new (targets
, n_targets
);
953 priv_data
->dest_actions
= actions
;
954 priv_data
->dest_flags
= flags
;
956 gtk_drag_dest_set (GTK_WIDGET (tree_view
),
962 priv_data
->drag_motion_handler
= g_signal_connect (G_OBJECT (tree_view
),
964 G_CALLBACK (rb_tree_dnd_drag_motion_cb
),
966 priv_data
->drag_leave_handler
= g_signal_connect (G_OBJECT (tree_view
),
968 G_CALLBACK (rb_tree_dnd_drag_leave_cb
),
970 priv_data
->drag_drop_handler
= g_signal_connect (G_OBJECT (tree_view
),
972 G_CALLBACK (rb_tree_dnd_drag_drop_cb
),
974 priv_data
->drag_data_received_handler
= g_signal_connect (G_OBJECT (tree_view
),
975 "drag_data_received",
976 G_CALLBACK (rb_tree_dnd_drag_data_received_cb
), NULL
);