@@ -98,6 +98,8 @@ struct NemoListViewDetails {
9898 gboolean menus_ready ;
9999 gboolean active ;
100100
101+ gboolean rubber_banding ;
102+
101103 GHashTable * columns ;
102104 GtkWidget * column_editor ;
103105
@@ -581,9 +583,9 @@ motion_notify_callback (GtkWidget *widget,
581583
582584 view = NEMO_LIST_VIEW (callback_data );
583585
584- if (event -> window != gtk_tree_view_get_bin_window (GTK_TREE_VIEW (widget ))) {
585- return FALSE ;
586- }
586+ if (event -> window != gtk_tree_view_get_bin_window (GTK_TREE_VIEW (widget ))) {
587+ return GDK_EVENT_PROPAGATE ;
588+ }
587589
588590 if (get_click_policy () == NEMO_CLICK_POLICY_SINGLE ) {
589591 GtkTreePath * old_hover_path ;
@@ -607,27 +609,68 @@ motion_notify_callback (GtkWidget *widget,
607609 }
608610 }
609611
610- if (view -> details -> drag_button != 0 ) {
611- if (!source_target_list ) {
612- source_target_list = nemo_list_model_get_drag_target_list ();
613- }
612+ /* If we're already rubber-banding, we can skip all of this logic and just let the parent
613+ * class continue to handle selection */
614+ if (view -> details -> drag_button != 0 && !view -> details -> rubber_banding ) {
615+ GtkTreePath * path ;
616+ GtkTreeSelection * selection ;
617+ gboolean is_new_self_selection ;
614618
615- if (gtk_drag_check_threshold (widget ,
616- view -> details -> drag_x ,
617- view -> details -> drag_y ,
618- event -> x ,
619- event -> y )) {
620- gtk_drag_begin
621- (widget ,
622- source_target_list ,
623- GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK | GDK_ACTION_ASK ,
624- view -> details -> drag_button ,
625- (GdkEvent * )event );
626- }
627- return TRUE;
628- }
619+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget ));
629620
630- return FALSE;
621+ gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget ),
622+ event -> x , event -> y ,
623+ & path ,
624+ NULL , NULL , NULL );
625+
626+ /* This looks complicated but it's just verbose: We'll only consider allowing rubber-banding
627+ * to begin if the following are TRUE: a) The current row is the only row currently selected,
628+ * and b) This is the first click that's been made on this row - meaning, the button-press-event
629+ * that preceded this motion-event was the one that caused this row to be selected. */
630+ is_new_self_selection = gtk_tree_selection_count_selected_rows (selection ) == 1 &&
631+ gtk_tree_selection_path_is_selected (selection , path ) &&
632+ (!view -> details -> double_click_path [1 ] ||
633+ (view -> details -> double_click_path [1 ] &&
634+ gtk_tree_path_compare (view -> details -> double_click_path [0 ],
635+ view -> details -> double_click_path [1 ]) != 0 ));
636+
637+ gtk_tree_path_free (path );
638+
639+ /* We also want to further restrict rubber-banding to be initiated only in blank areas of the row.
640+ * This allows DnD to operate on a new selection like before, when the motion begins over text or
641+ * icons */
642+ if (is_new_self_selection && gtk_tree_view_is_blank_at_pos (GTK_TREE_VIEW (widget ),
643+ event -> x , event -> y ,
644+ NULL , NULL , NULL , NULL )) {
645+ /* If this is a candidate for rubber-banding, track that state in the view, and allow the event
646+ * to continue into Gtk (which handles rubber-band selection for us) */
647+ view -> details -> rubber_banding = TRUE;
648+
649+ return GDK_EVENT_PROPAGATE ;
650+ }
651+
652+ /* All other cases, allow DnD to potentially begin */
653+ if (!source_target_list ) {
654+ source_target_list = nemo_list_model_get_drag_target_list ();
655+ }
656+
657+ if (gtk_drag_check_threshold (widget ,
658+ view -> details -> drag_x ,
659+ view -> details -> drag_y ,
660+ event -> x ,
661+ event -> y )) {
662+ gtk_drag_begin (widget ,
663+ source_target_list ,
664+ GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK | GDK_ACTION_ASK ,
665+ view -> details -> drag_button ,
666+ (GdkEvent * ) event );
667+ }
668+
669+ /* The event is handled by the DnD begin, don't propagate further */
670+ return GDK_EVENT_STOP ;
671+ }
672+
673+ return GDK_EVENT_PROPAGATE ;
631674}
632675
633676static gboolean
@@ -1177,6 +1220,8 @@ button_release_callback (GtkWidget *widget,
11771220
11781221 view = NEMO_LIST_VIEW (callback_data );
11791222
1223+ view -> details -> rubber_banding = FALSE;
1224+
11801225 if (event -> button == view -> details -> drag_button ) {
11811226 stop_drag_check (view );
11821227 if (!view -> details -> drag_started &&
@@ -2103,6 +2148,9 @@ create_and_set_up_tree_view (NemoListView *view)
21032148 gchar * * default_column_order , * * default_visible_columns ;
21042149
21052150 view -> details -> tree_view = GTK_TREE_VIEW (gtk_tree_view_new ());
2151+
2152+ gtk_tree_view_set_rubber_banding (GTK_TREE_VIEW (view -> details -> tree_view ), TRUE);
2153+
21062154 view -> details -> columns = g_hash_table_new_full (g_str_hash ,
21072155 g_str_equal ,
21082156 (GDestroyNotify ) g_free ,
0 commit comments