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
->row_draggable
!= NULL
, FALSE
);
121 g_return_val_if_fail (path_list
!= NULL
, FALSE
);
123 if (iface
->row_draggable
)
124 return (* iface
->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
->drag_data_delete
!= NULL
, FALSE
);
151 g_return_val_if_fail (path_list
!= NULL
, FALSE
);
153 return (* iface
->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
->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
->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
->drag_data_received
!= NULL
, FALSE
);
224 g_return_val_if_fail (selection_data
!= NULL
, FALSE
);
226 return (* iface
->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
->drag_data_received
!= NULL
, FALSE
);
241 g_return_val_if_fail (selection_data
!= NULL
, FALSE
);
243 return (* iface
->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
->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
->row_drop_position
) (drag_dest
, dest_path
, targets
, pos
);
264 init_rb_tree_dnd_data (GtkWidget
*widget
)
266 RbTreeDndData
*priv_data
;
268 priv_data
= g_object_get_data (G_OBJECT (widget
), RB_TREE_DND_STRING
);
269 if (priv_data
== NULL
)
271 priv_data
= g_new0 (RbTreeDndData
, 1);
272 priv_data
->pending_event
= FALSE
;
273 g_object_set_data (G_OBJECT (widget
), RB_TREE_DND_STRING
, priv_data
);
274 priv_data
->drag_motion_handler
= 0;
275 priv_data
->drag_leave_handler
= 0;
276 priv_data
->button_press_event_handler
= 0;
277 priv_data
->scroll_timeout
= 0;
278 priv_data
->previous_dest_path
= NULL
;
279 priv_data
->select_on_drag_timeout
= 0;
286 stop_drag_check (GtkWidget
*widget
)
288 RbTreeDndData
*priv_data
;
291 priv_data
= g_object_get_data (G_OBJECT (widget
), RB_TREE_DND_STRING
);
293 for (l
= priv_data
->event_list
; l
!= NULL
; l
= l
->next
)
294 gdk_event_free (l
->data
);
296 g_slist_free (priv_data
->event_list
);
297 priv_data
->event_list
= NULL
;
298 priv_data
->pending_event
= FALSE
;
299 g_signal_handler_disconnect (widget
, priv_data
->motion_notify_handler
);
300 g_signal_handler_disconnect (widget
, priv_data
->button_release_handler
);
305 rb_tree_dnd_button_release_event_cb (GtkWidget
*widget
,
306 GdkEventButton
*event
,
309 RbTreeDndData
*priv_data
;
312 priv_data
= g_object_get_data (G_OBJECT (widget
), RB_TREE_DND_STRING
);
314 for (l
= priv_data
->event_list
; l
!= NULL
; l
= l
->next
)
315 gtk_propagate_event (widget
, l
->data
);
317 stop_drag_check (widget
);
324 selection_foreach (GtkTreeModel
*model
,
331 list_ptr
= (GList
**) data
;
332 *list_ptr
= g_list_prepend (*list_ptr
, gtk_tree_row_reference_new (model
, path
));
337 path_list_free (GList
*path_list
)
339 g_list_foreach (path_list
, (GFunc
) gtk_tree_row_reference_free
, NULL
);
340 g_list_free (path_list
);
344 set_context_data (GdkDragContext
*context
,
347 g_object_set_data_full (G_OBJECT (context
),
348 "rb-tree-view-multi-source-row",
350 (GDestroyNotify
) path_list_free
);
352 rb_debug ("Setting path_list: index=%i", gtk_tree_path_get_indices(path_list
->data
)[0]);
356 get_context_data (GdkDragContext
*context
)
358 return g_object_get_data (G_OBJECT (context
), "rb-tree-view-multi-source-row");
362 filter_drop_position (GtkWidget
*widget
, GdkDragContext
*context
, GtkTreePath
*path
, GtkTreeViewDropPosition
*pos
)
364 GtkTreeView
*tree_view
= GTK_TREE_VIEW (widget
);
365 GtkTreeModel
*model
= gtk_tree_view_get_model (tree_view
);
366 RbTreeDndData
*priv_data
= g_object_get_data (G_OBJECT (widget
), RB_TREE_DND_STRING
);
369 if (!(priv_data
->dest_flags
& RB_TREE_DEST_CAN_DROP_INTO
)) {
370 if (*pos
== GTK_TREE_VIEW_DROP_INTO_OR_BEFORE
)
371 *pos
= GTK_TREE_VIEW_DROP_BEFORE
;
372 else if (*pos
== GTK_TREE_VIEW_DROP_INTO_OR_AFTER
)
373 *pos
= GTK_TREE_VIEW_DROP_AFTER
;
374 } else if (!(priv_data
->dest_flags
& RB_TREE_DEST_CAN_DROP_BETWEEN
)) {
375 if (*pos
== GTK_TREE_VIEW_DROP_BEFORE
)
376 *pos
= GTK_TREE_VIEW_DROP_INTO_OR_BEFORE
;
377 else if (*pos
== GTK_TREE_VIEW_DROP_AFTER
)
378 *pos
= GTK_TREE_VIEW_DROP_INTO_OR_AFTER
;
381 ret
= rb_tree_drag_dest_row_drop_position (RB_TREE_DRAG_DEST (model
),
386 rb_debug ("filtered drop position: %s", ret
? "TRUE" : "FALSE");
391 /* Scroll function taken/adapted from gtktreeview.c */
393 scroll_row_timeout (gpointer data
)
395 GtkTreeView
*tree_view
= data
;
396 GdkRectangle visible_rect
;
401 RbTreeDndData
*priv_data
;
403 GDK_THREADS_ENTER ();
405 priv_data
= g_object_get_data (G_OBJECT (tree_view
), RB_TREE_DND_STRING
);
406 g_return_val_if_fail(priv_data
!= NULL
, TRUE
);
408 gdk_window_get_pointer (gtk_tree_view_get_bin_window (tree_view
), &x
, &y
, NULL
);
409 gtk_tree_view_widget_to_tree_coords (tree_view
, x
, y
, &x
, &y
);
410 gtk_tree_view_get_visible_rect (tree_view
, &visible_rect
);
412 /* see if we are near the edge. */
413 if (x
< visible_rect
.x
&& x
> visible_rect
.x
+ visible_rect
.width
)
415 GDK_THREADS_LEAVE ();
416 priv_data
->scroll_timeout
= 0;
420 offset
= y
- (visible_rect
.y
+ 2 * SCROLL_EDGE_SIZE
);
423 offset
= y
- (visible_rect
.y
+ visible_rect
.height
- 2 * SCROLL_EDGE_SIZE
);
426 GDK_THREADS_LEAVE ();
427 priv_data
->scroll_timeout
= 0;
432 vadj
= gtk_tree_view_get_vadjustment (tree_view
);
433 value
= CLAMP (vadj
->value
+ offset
, vadj
->lower
, vadj
->upper
- vadj
->page_size
);
434 gtk_adjustment_set_value (vadj
, value
);
436 remove_select_on_drag_timeout(tree_view
);
438 GDK_THREADS_LEAVE ();
445 select_on_drag_timeout (gpointer data
)
447 GtkTreeView
*tree_view
= data
;
448 GtkTreeSelection
*selection
;
449 RbTreeDndData
*priv_data
;
451 GDK_THREADS_ENTER ();
453 priv_data
= g_object_get_data (G_OBJECT (tree_view
), RB_TREE_DND_STRING
);
454 g_return_val_if_fail(priv_data
!= NULL
, FALSE
);
455 g_return_val_if_fail(priv_data
->previous_dest_path
!= NULL
, FALSE
);
457 selection
= gtk_tree_view_get_selection(tree_view
);
458 if (!gtk_tree_selection_path_is_selected(selection
,priv_data
->previous_dest_path
)) {
459 rb_debug("Changing selection because of drag timeout");
460 gtk_tree_view_set_cursor(tree_view
,priv_data
->previous_dest_path
,NULL
,FALSE
);
463 priv_data
->select_on_drag_timeout
= 0;
464 gtk_tree_path_free(priv_data
->previous_dest_path
);
465 priv_data
->previous_dest_path
= NULL
;
467 GDK_THREADS_LEAVE ();
473 remove_scroll_timeout (GtkTreeView
*tree_view
)
475 RbTreeDndData
*priv_data
;
477 priv_data
= g_object_get_data (G_OBJECT (tree_view
), RB_TREE_DND_STRING
);
478 g_return_if_fail(priv_data
!= NULL
);
480 if (priv_data
->scroll_timeout
!= 0)
482 g_source_remove (priv_data
->scroll_timeout
);
483 priv_data
->scroll_timeout
= 0;
489 remove_select_on_drag_timeout (GtkTreeView
*tree_view
)
491 RbTreeDndData
*priv_data
;
493 priv_data
= g_object_get_data (G_OBJECT (tree_view
), RB_TREE_DND_STRING
);
494 g_return_if_fail(priv_data
!= NULL
);
496 if (priv_data
->select_on_drag_timeout
!= 0) {
497 rb_debug("Removing the select on drag timeout");
498 g_source_remove (priv_data
->select_on_drag_timeout
);
499 priv_data
->select_on_drag_timeout
= 0;
501 if (priv_data
->previous_dest_path
!= NULL
) {
502 gtk_tree_path_free(priv_data
->previous_dest_path
);
503 priv_data
->previous_dest_path
= NULL
;
509 rb_tree_dnd_drag_data_delete_cb (GtkWidget
*widget
,
510 GdkDragContext
*drag_context
,
514 GtkTreeModel
*model
= gtk_tree_view_get_model (GTK_TREE_VIEW(widget
));
516 path_list
= get_context_data (drag_context
);
517 rb_tree_drag_source_drag_data_delete (RB_TREE_DRAG_SOURCE (model
),
520 g_signal_stop_emission_by_name (widget
, "drag_data_delete");
526 rb_tree_dnd_drag_data_get_cb (GtkWidget
*widget
,
527 GdkDragContext
*context
,
528 GtkSelectionData
*selection_data
,
532 GtkTreeView
*tree_view
;
536 tree_view
= GTK_TREE_VIEW (widget
);
537 model
= gtk_tree_view_get_model (tree_view
);
542 path_list
= get_context_data (context
);
544 if (path_list
== NULL
)
547 /* We can implement the GTK_TREE_MODEL_ROW target generically for
548 * any model; for DragSource models there are some other targets
551 if (RB_IS_TREE_DRAG_SOURCE (model
))
553 rb_tree_drag_source_drag_data_get (RB_TREE_DRAG_SOURCE (model
),
561 rb_tree_dnd_motion_notify_event_cb (GtkWidget
*widget
,
562 GdkEventMotion
*event
,
565 RbTreeDndData
*priv_data
;
567 priv_data
= g_object_get_data (G_OBJECT (widget
), RB_TREE_DND_STRING
);
569 if (gtk_drag_check_threshold (widget
,
575 GList
*path_list
= NULL
;
576 GtkTreeSelection
*selection
;
578 GdkDragContext
*context
;
580 selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (widget
));
581 stop_drag_check (widget
);
582 gtk_tree_selection_selected_foreach (selection
, selection_foreach
, &path_list
);
583 path_list
= g_list_reverse (path_list
);
584 model
= gtk_tree_view_get_model (GTK_TREE_VIEW (widget
));
586 if (rb_tree_drag_source_row_draggable (RB_TREE_DRAG_SOURCE (model
), path_list
))
588 rb_debug ("drag begin");
589 context
= gtk_drag_begin (widget
,
590 priv_data
->source_target_list
,
591 priv_data
->source_actions
,
592 priv_data
->pressed_button
,
594 set_context_data (context
, path_list
);
595 gtk_drag_set_icon_default (context
);
598 path_list_free (path_list
);
606 rb_tree_dnd_drag_motion_cb (GtkWidget
*widget
,
607 GdkDragContext
*context
,
612 GtkTreeView
*tree_view
;
613 GtkTreePath
*path
= NULL
;
615 GtkTreeViewDropPosition pos
;
616 RbTreeDndData
*priv_data
;
617 GdkDragAction action
;
619 rb_debug ("drag and drop motion: (%i,%i)", x
, y
);
621 tree_view
= GTK_TREE_VIEW (widget
);
622 model
= gtk_tree_view_get_model (tree_view
);
624 priv_data
= g_object_get_data (G_OBJECT (widget
), RB_TREE_DND_STRING
);
626 gtk_tree_view_get_dest_row_at_pos (tree_view
, x
, y
, &path
, &pos
);
628 if ((priv_data
->previous_dest_path
== NULL
)
630 || gtk_tree_path_compare(path
,priv_data
->previous_dest_path
)) {
631 remove_select_on_drag_timeout(tree_view
);
636 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget
),
638 GTK_TREE_VIEW_DROP_BEFORE
);
640 if (!(priv_data
->dest_flags
& RB_TREE_DEST_EMPTY_VIEW_DROP
)) {
641 /* Can't drop here. */
642 gdk_drag_status (context
, 0, time
);
645 } else if (!filter_drop_position (widget
, context
, path
, &pos
)) {
646 gdk_drag_status (context
, 0, time
);
652 if (!filter_drop_position (widget
, context
, path
, &pos
)) {
653 gdk_drag_status (context
, 0, time
);
657 if (priv_data
->scroll_timeout
== 0)
659 priv_data
->scroll_timeout
= g_timeout_add (150, scroll_row_timeout
, tree_view
);
663 if (GTK_WIDGET (tree_view
) == gtk_drag_get_source_widget (context
) &&
664 context
->actions
& GDK_ACTION_MOVE
)
665 action
= GDK_ACTION_MOVE
;
667 action
= context
->suggested_action
;
670 gtk_tree_view_set_drag_dest_row (tree_view
, path
, pos
);
671 if (priv_data
->dest_flags
& RB_TREE_DEST_SELECT_ON_DRAG_TIMEOUT
) {
672 if (priv_data
->previous_dest_path
!= NULL
) {
673 gtk_tree_path_free (priv_data
->previous_dest_path
);
675 priv_data
->previous_dest_path
= path
;
676 if (priv_data
->select_on_drag_timeout
== 0) {
677 rb_debug("Setting up a new select on drag timeout");
678 priv_data
->select_on_drag_timeout
= g_timeout_add (2000, select_on_drag_timeout
, tree_view
);
681 gtk_tree_path_free (path
);
685 gdk_drag_status (context
, action
, time
);
692 rb_tree_dnd_drag_leave_cb (GtkWidget
*widget
,
693 GdkDragContext
*context
,
698 remove_select_on_drag_timeout(GTK_TREE_VIEW (widget
));
703 rb_tree_dnd_drag_drop_cb (GtkWidget
*widget
,
704 GdkDragContext
*context
,
709 GtkTreeView
*tree_view
;
712 GtkTreeViewDropPosition pos
;
713 RbTreeDndData
*priv_data
;
715 tree_view
= GTK_TREE_VIEW (widget
);
716 model
= gtk_tree_view_get_model (tree_view
);
717 priv_data
= g_object_get_data (G_OBJECT (widget
), RB_TREE_DND_STRING
);
718 gtk_tree_view_get_dest_row_at_pos (tree_view
, x
, y
, &path
, &pos
);
720 remove_scroll_timeout (tree_view
);
722 /* Unset this thing */
723 gtk_tree_view_set_drag_dest_row (tree_view
,
725 GTK_TREE_VIEW_DROP_BEFORE
);
727 if (path
|| priv_data
->dest_flags
& RB_TREE_DEST_EMPTY_VIEW_DROP
) {
730 RbTreeDragDestIface
*iface
= RB_TREE_DRAG_DEST_GET_IFACE (model
);
731 if (iface
->get_drag_target
) {
732 RbTreeDragDest
*dest
= RB_TREE_DRAG_DEST (model
);
733 target
= (* iface
->get_drag_target
) (dest
, widget
,
735 priv_data
->dest_target_list
);
737 target
= gtk_drag_dest_find_target (widget
, context
,
738 priv_data
->dest_target_list
);
742 gtk_tree_path_free (path
);
744 if (target
!= GDK_NONE
) {
745 gtk_drag_get_data (widget
, context
, target
, time
);
755 rb_tree_dnd_drag_data_received_cb (GtkWidget
*widget
,
756 GdkDragContext
*context
,
759 GtkSelectionData
*selection_data
,
763 GtkTreeView
*tree_view
;
765 GtkTreePath
*dest_row
;
766 GtkTreeViewDropPosition pos
;
767 gboolean filtered
= TRUE
;
768 gboolean accepted
= FALSE
;
770 tree_view
= GTK_TREE_VIEW (widget
);
771 model
= gtk_tree_view_get_model (tree_view
);
773 gtk_tree_view_get_dest_row_at_pos (tree_view
, x
, y
, &dest_row
, &pos
);
776 if (!filter_drop_position (widget
, context
, dest_row
, &pos
))
779 if (filtered
&& selection_data
->length
>= 0)
781 if (rb_tree_drag_dest_drag_data_received (RB_TREE_DRAG_DEST (model
),
788 gtk_drag_finish (context
,
790 (context
->action
== GDK_ACTION_MOVE
),
794 gtk_tree_path_free (dest_row
);
796 g_signal_stop_emission_by_name (widget
, "drag_data_received");
802 rb_tree_dnd_button_press_event_cb (GtkWidget
*widget
,
803 GdkEventButton
*event
,
806 GtkTreeView
*tree_view
;
807 GtkTreePath
*path
= NULL
;
808 GtkTreeViewColumn
*column
= NULL
;
810 GtkTreeSelection
*selection
;
811 RbTreeDndData
*priv_data
;
813 if (event
->button
== 3)
816 tree_view
= GTK_TREE_VIEW (widget
);
817 if (event
->window
!= gtk_tree_view_get_bin_window (tree_view
))
820 priv_data
= g_object_get_data (G_OBJECT (tree_view
), RB_TREE_DND_STRING
);
821 if (priv_data
== NULL
)
823 priv_data
= g_new0 (RbTreeDndData
, 1);
824 priv_data
->pending_event
= FALSE
;
825 g_object_set_data (G_OBJECT (tree_view
), RB_TREE_DND_STRING
, priv_data
);
828 if (g_slist_find (priv_data
->event_list
, event
))
831 if (priv_data
->pending_event
)
833 /* save the event to be propagated in order */
834 priv_data
->event_list
= g_slist_append (priv_data
->event_list
, gdk_event_copy ((GdkEvent
*)event
));
838 if (event
->type
== GDK_2BUTTON_PRESS
)
841 gtk_tree_view_get_path_at_pos (tree_view
,
846 selection
= gtk_tree_view_get_selection (tree_view
);
850 gboolean call_parent
= (event
->state
& (GDK_CONTROL_MASK
| GDK_SHIFT_MASK
) ||
851 !gtk_tree_selection_path_is_selected (selection
, path
) ||
855 (GTK_WIDGET_GET_CLASS (tree_view
))->button_press_event (widget
, event
);
857 if (gtk_tree_selection_path_is_selected (selection
, path
))
859 priv_data
->pressed_button
= event
->button
;
860 priv_data
->x
= event
->x
;
861 priv_data
->y
= event
->y
;
863 priv_data
->pending_event
= TRUE
;
866 priv_data
->event_list
= g_slist_append (priv_data
->event_list
,
867 gdk_event_copy ((GdkEvent
*)event
));
869 priv_data
->motion_notify_handler
= g_signal_connect (G_OBJECT (tree_view
),
870 "motion_notify_event",
871 G_CALLBACK (rb_tree_dnd_motion_notify_event_cb
),
873 priv_data
->button_release_handler
= g_signal_connect (G_OBJECT (tree_view
),
874 "button_release_event",
875 G_CALLBACK (rb_tree_dnd_button_release_event_cb
),
880 gtk_tree_path_free (path
);
881 /* We called the default handler so we don't let the default handler run */
890 rb_tree_dnd_add_drag_source_support (GtkTreeView
*tree_view
,
891 GdkModifierType start_button_mask
,
892 const GtkTargetEntry
*targets
,
894 GdkDragAction actions
)
896 RbTreeDndData
*priv_data
= NULL
;
897 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view
));
899 priv_data
= init_rb_tree_dnd_data (GTK_WIDGET(tree_view
));
901 if (!priv_data
->button_press_event_handler
) {
903 priv_data
->source_target_list
= gtk_target_list_new (targets
, n_targets
);
904 priv_data
->source_actions
= actions
;
905 priv_data
->start_button_mask
= start_button_mask
;
907 priv_data
->button_press_event_handler
= g_signal_connect (G_OBJECT (tree_view
),
908 "button_press_event",
909 G_CALLBACK (rb_tree_dnd_button_press_event_cb
),
911 priv_data
->drag_data_get_handler
= g_signal_connect (G_OBJECT (tree_view
),
913 G_CALLBACK (rb_tree_dnd_drag_data_get_cb
),
915 priv_data
->drag_data_delete_handler
= g_signal_connect (G_OBJECT (tree_view
),
917 G_CALLBACK (rb_tree_dnd_drag_data_delete_cb
),
927 rb_tree_dnd_add_drag_dest_support (GtkTreeView
*tree_view
,
928 RbTreeDestFlag flags
,
929 const GtkTargetEntry
*targets
,
931 GdkDragAction actions
)
933 RbTreeDndData
*priv_data
= NULL
;
934 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view
));
936 priv_data
= init_rb_tree_dnd_data (GTK_WIDGET(tree_view
));
938 if (!priv_data
->drag_motion_handler
) {
940 priv_data
->dest_target_list
= gtk_target_list_new (targets
, n_targets
);
941 priv_data
->dest_actions
= actions
;
942 priv_data
->dest_flags
= flags
;
944 gtk_drag_dest_set (GTK_WIDGET (tree_view
),
950 priv_data
->drag_motion_handler
= g_signal_connect (G_OBJECT (tree_view
),
952 G_CALLBACK (rb_tree_dnd_drag_motion_cb
),
954 priv_data
->drag_leave_handler
= g_signal_connect (G_OBJECT (tree_view
),
956 G_CALLBACK (rb_tree_dnd_drag_leave_cb
),
958 priv_data
->drag_drop_handler
= g_signal_connect (G_OBJECT (tree_view
),
960 G_CALLBACK (rb_tree_dnd_drag_drop_cb
),
962 priv_data
->drag_data_received_handler
= g_signal_connect (G_OBJECT (tree_view
),
963 "drag_data_received",
964 G_CALLBACK (rb_tree_dnd_drag_data_received_cb
), NULL
);