Remove beat entry from meter dialog (beats are not allowed in API), clean up some...
[ardour.git] / gtk2_ardour / editor_mouse.cc
index 1a9e1161c283d3c16367349f5a2c4e4e06ef0644..b745b93f2cbf332cde95e633000085706bb6a201 100644 (file)
@@ -24,6 +24,7 @@
 #include <set>
 #include <string>
 #include <algorithm>
 #include <set>
 #include <string>
 #include <algorithm>
+#include <sys/time.h>
 
 #include <pbd/error.h>
 #include <gtkmm2ext/utils.h>
 
 #include <pbd/error.h>
 #include <gtkmm2ext/utils.h>
@@ -68,8 +69,46 @@ using namespace sigc;
 using namespace Gtk;
 using namespace Editing;
 
 using namespace Gtk;
 using namespace Editing;
 
-nframes_t
-Editor::event_frame (GdkEvent* event, double* pcx, double* pcy)
+bool
+Editor::mouse_frame (nframes64_t& where, bool& in_track_canvas) const
+{
+       int x, y;
+       double wx, wy;
+       Gdk::ModifierType mask;
+       Glib::RefPtr<Gdk::Window> canvas_window = const_cast<Editor*>(this)->track_canvas.get_window();
+       Glib::RefPtr<const Gdk::Window> pointer_window;
+       
+       pointer_window = canvas_window->get_pointer (x, y, mask);
+
+       if (pointer_window == track_canvas.get_bin_window()) {
+
+               track_canvas.window_to_world (x, y, wx, wy);
+               in_track_canvas = true;
+
+       } else {
+               in_track_canvas = false;
+
+               if (pointer_window == time_canvas.get_bin_window()) {
+                       time_canvas.window_to_world (x, y, wx, wy);
+               } else {
+                       return false;
+               }
+       }
+
+       wx += horizontal_adjustment.get_value();
+       wy += vertical_adjustment.get_value();
+
+       GdkEvent event;
+       event.type = GDK_BUTTON_RELEASE;
+       event.button.x = wx;
+       event.button.y = wy;
+       
+       where = event_frame (&event, 0, 0);
+       return true;
+}
+
+nframes64_t
+Editor::event_frame (GdkEvent* event, double* pcx, double* pcy) const
 {
        double cx, cy;
 
 {
        double cx, cy;
 
@@ -163,6 +202,53 @@ Editor::mouse_mode_toggled (MouseMode m)
        }
 }      
 
        }
 }      
 
+Gdk::Cursor*
+Editor::which_grabber_cursor ()
+{
+       switch (_edit_point) {
+       case EditAtMouse:
+               return grabber_edit_point_cursor;
+               break;
+       default:
+               return grabber_cursor;
+               break;
+       }
+}
+
+void
+Editor::set_canvas_cursor ()
+{
+       switch (mouse_mode) {
+       case MouseRange:
+               current_canvas_cursor = selector_cursor;
+               break;
+
+       case MouseObject:
+               current_canvas_cursor = which_grabber_cursor();
+               break;
+
+       case MouseGain:
+               current_canvas_cursor = cross_hair_cursor;
+               break;
+
+       case MouseZoom:
+               current_canvas_cursor = zoom_cursor;
+               break;
+
+       case MouseTimeFX:
+               current_canvas_cursor = time_fx_cursor; // just use playhead
+               break;
+
+       case MouseAudition:
+               current_canvas_cursor = speaker_cursor;
+               break;
+       }
+
+       if (is_drawable()) {
+               track_canvas.get_window()->set_cursor(*current_canvas_cursor);
+       }
+}
+
 void
 Editor::set_mouse_mode (MouseMode m, bool force)
 {
 void
 Editor::set_mouse_mode (MouseMode m, bool force)
 {
@@ -204,7 +290,7 @@ Editor::set_mouse_mode (MouseMode m, bool force)
                }
        }
 
                }
        }
 
-       /* XXX the hack of unsetting all other buttongs should go 
+       /* XXX the hack of unsetting all other buttons should go 
           away once GTK2 allows us to use regular radio buttons drawn like
           normal buttons, rather than my silly GroupedButton hack.
        */
           away once GTK2 allows us to use regular radio buttons drawn like
           normal buttons, rather than my silly GroupedButton hack.
        */
@@ -214,40 +300,32 @@ Editor::set_mouse_mode (MouseMode m, bool force)
        switch (mouse_mode) {
        case MouseRange:
                mouse_select_button.set_active (true);
        switch (mouse_mode) {
        case MouseRange:
                mouse_select_button.set_active (true);
-               current_canvas_cursor = selector_cursor;
                break;
 
        case MouseObject:
                mouse_move_button.set_active (true);
                break;
 
        case MouseObject:
                mouse_move_button.set_active (true);
-               current_canvas_cursor = grabber_cursor;
                break;
 
        case MouseGain:
                mouse_gain_button.set_active (true);
                break;
 
        case MouseGain:
                mouse_gain_button.set_active (true);
-               current_canvas_cursor = cross_hair_cursor;
                break;
 
        case MouseZoom:
                mouse_zoom_button.set_active (true);
                break;
 
        case MouseZoom:
                mouse_zoom_button.set_active (true);
-               current_canvas_cursor = zoom_cursor;
                break;
 
        case MouseTimeFX:
                mouse_timefx_button.set_active (true);
                break;
 
        case MouseTimeFX:
                mouse_timefx_button.set_active (true);
-               current_canvas_cursor = time_fx_cursor; // just use playhead
                break;
 
        case MouseAudition:
                mouse_audition_button.set_active (true);
                break;
 
        case MouseAudition:
                mouse_audition_button.set_active (true);
-               current_canvas_cursor = speaker_cursor;
                break;
        }
 
        ignore_mouse_mode_toggle = false;
                break;
        }
 
        ignore_mouse_mode_toggle = false;
-
-       if (is_drawable()) {
-               track_canvas.get_window()->set_cursor(*current_canvas_cursor);
-       }
+       
+       set_canvas_cursor ();
 }
 
 void
 }
 
 void
@@ -289,8 +367,6 @@ Editor::step_mouse_mode (bool next)
 void
 Editor::button_selection (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
 {
 void
 Editor::button_selection (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
 {
-       bool commit = false;
-
        /* in object/audition/timefx mode, any button press sets
           the selection if the object can be selected. this is a
           bit of hack, because we want to avoid this if the
        /* in object/audition/timefx mode, any button press sets
           the selection if the object can be selected. this is a
           bit of hack, because we want to avoid this if the
@@ -329,18 +405,18 @@ Editor::button_selection (ArdourCanvas::Item* item, GdkEvent* event, ItemType it
        switch (item_type) {
        case RegionItem:
                if (mouse_mode != MouseRange) {
        switch (item_type) {
        case RegionItem:
                if (mouse_mode != MouseRange) {
-                       commit = set_selected_regionview_from_click (press, op, true);
+                       set_selected_regionview_from_click (press, op, true);
                } else if (event->type == GDK_BUTTON_PRESS) {
                } else if (event->type == GDK_BUTTON_PRESS) {
-                       commit = set_selected_track_from_click (press, op, false);
+                       set_selected_track_as_side_effect ();
                }
                break;
                
        case RegionViewNameHighlight:
        case RegionViewName:
                if (mouse_mode != MouseRange) {
                }
                break;
                
        case RegionViewNameHighlight:
        case RegionViewName:
                if (mouse_mode != MouseRange) {
-                       commit = set_selected_regionview_from_click (press, op, true);
+                       set_selected_regionview_from_click (press, op, true);
                } else if (event->type == GDK_BUTTON_PRESS) {
                } else if (event->type == GDK_BUTTON_PRESS) {
-                       commit = set_selected_track_from_click (press, op, false);
+                       set_selected_track_as_side_effect ();
                }
                break;
 
                }
                break;
 
@@ -349,43 +425,41 @@ Editor::button_selection (ArdourCanvas::Item* item, GdkEvent* event, ItemType it
        case FadeOutHandleItem:
        case FadeOutItem:
                if (mouse_mode != MouseRange) {
        case FadeOutHandleItem:
        case FadeOutItem:
                if (mouse_mode != MouseRange) {
-                       commit = set_selected_regionview_from_click (press, op, true);
+                       set_selected_regionview_from_click (press, op, true);
                } else if (event->type == GDK_BUTTON_PRESS) {
                } else if (event->type == GDK_BUTTON_PRESS) {
-                       commit = set_selected_track_from_click (press, op, false);
+                       set_selected_track_as_side_effect ();
                }
                break;
                
        case GainAutomationControlPointItem:
        case PanAutomationControlPointItem:
        case RedirectAutomationControlPointItem:
                }
                break;
                
        case GainAutomationControlPointItem:
        case PanAutomationControlPointItem:
        case RedirectAutomationControlPointItem:
-               commit = set_selected_track_from_click (press, op, true);
+               set_selected_track_as_side_effect ();
                if (mouse_mode != MouseRange) {
                if (mouse_mode != MouseRange) {
-                       commit |= set_selected_control_point_from_click (op, false);
+                       set_selected_control_point_from_click (op, false);
                }
                break;
                
        case StreamItem:
                /* for context click or range selection, select track */
                if (event->button.button == 3) {
                }
                break;
                
        case StreamItem:
                /* for context click or range selection, select track */
                if (event->button.button == 3) {
-                       commit = set_selected_track_from_click (press, op, true);
+                       set_selected_track_as_side_effect ();
                } else if (event->type == GDK_BUTTON_PRESS && mouse_mode == MouseRange) {
                } else if (event->type == GDK_BUTTON_PRESS && mouse_mode == MouseRange) {
-                       commit = set_selected_track_from_click (press, op, false);
+                       set_selected_track_as_side_effect ();
                }
                break;
                    
        case AutomationTrackItem:
                }
                break;
                    
        case AutomationTrackItem:
-               commit = set_selected_track_from_click (press, op, true);
+               set_selected_track_as_side_effect (true);
                break;
                
        default:
                break;
        }
                break;
                
        default:
                break;
        }
-       
-//     if (commit) {
-//             commit_reversible_command ();
-//     }
 }
 
 }
 
+const static double ZERO_GAIN_FRACTION = gain_to_slider_position(dB_to_coefficient(0.0));
+
 bool
 Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
 {
 bool
 Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
 {
@@ -422,14 +496,12 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp
                        */
                        
                        switch (item_type) {
                        */
                        
                        switch (item_type) {
-                       case EditCursorItem:
                        case PlayheadCursorItem:
                                start_cursor_grab (item, event);
                                return true;
 
                        case MarkerItem:
                        case PlayheadCursorItem:
                                start_cursor_grab (item, event);
                                return true;
 
                        case MarkerItem:
-                               if (Keyboard::modifier_state_equals (event->button.state, 
-                                                                    Keyboard::ModifierMask(Keyboard::Control|Keyboard::Shift))) {
+                               if (Keyboard::modifier_state_equals (event->button.state, Keyboard::ModifierMask(Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
                                        hide_marker (item, event);
                                } else {
                                        start_marker_grab (item, event);
                                        hide_marker (item, event);
                                } else {
                                        start_marker_grab (item, event);
@@ -437,7 +509,7 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp
                                return true;
 
                        case TempoMarkerItem:
                                return true;
 
                        case TempoMarkerItem:
-                               if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
+                               if (Keyboard::modifier_state_contains (event->button.state, Keyboard::CopyModifier)) {
                                        start_tempo_marker_copy_grab (item, event);
                                } else {
                                        start_tempo_marker_grab (item, event);
                                        start_tempo_marker_copy_grab (item, event);
                                } else {
                                        start_tempo_marker_grab (item, event);
@@ -445,7 +517,7 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp
                                return true;
 
                        case MeterMarkerItem:
                                return true;
 
                        case MeterMarkerItem:
-                               if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
+                               if (Keyboard::modifier_state_contains (event->button.state, Keyboard::CopyModifier)) {
                                        start_meter_marker_copy_grab (item, event);
                                } else {
                                        start_meter_marker_grab (item, event);
                                        start_meter_marker_copy_grab (item, event);
                                } else {
                                        start_meter_marker_grab (item, event);
@@ -463,6 +535,11 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp
                                return true;
                                break;
 
                                return true;
                                break;
 
+                       case CdMarkerBarItem:
+                               start_range_markerbar_op (item, event, CreateCDMarker); 
+                               return true;
+                               break;
+
                        case TransportMarkerBarItem:
                                start_range_markerbar_op (item, event, CreateTransportMarker); 
                                return true;
                        case TransportMarkerBarItem:
                                start_range_markerbar_op (item, event, CreateTransportMarker); 
                                return true;
@@ -486,14 +563,13 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp
 
                        case SelectionItem:
                                if (Keyboard::modifier_state_contains 
 
                        case SelectionItem:
                                if (Keyboard::modifier_state_contains 
-                                   (event->button.state, Keyboard::ModifierMask(Keyboard::Alt))) {
+                                   (event->button.state, Keyboard::ModifierMask(Keyboard::SecondaryModifier))) {
                                        // contains and not equals because I can't use alt as a modifier alone.
                                        start_selection_grab (item, event);
                                        // contains and not equals because I can't use alt as a modifier alone.
                                        start_selection_grab (item, event);
-                               } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
+                               } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
                                        /* grab selection for moving */
                                        start_selection_op (item, event, SelectionMove);
                                        /* grab selection for moving */
                                        start_selection_op (item, event, SelectionMove);
-                               }
-                               else {
+                               } else {
                                        /* this was debated, but decided the more common action was to
                                           make a new selection */
                                        start_selection_op (item, event, CreateSelection);
                                        /* this was debated, but decided the more common action was to
                                           make a new selection */
                                        start_selection_op (item, event, CreateSelection);
@@ -507,7 +583,7 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp
                        break;
                        
                case MouseObject:
                        break;
                        
                case MouseObject:
-                       if (Keyboard::modifier_state_contains (event->button.state, Keyboard::ModifierMask(Keyboard::Control|Keyboard::Alt)) &&
+                       if (Keyboard::modifier_state_contains (event->button.state, Keyboard::ModifierMask(Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)) &&
                            event->type == GDK_BUTTON_PRESS) {
                                
                                start_rubberband_select (item, event);
                            event->type == GDK_BUTTON_PRESS) {
                                
                                start_rubberband_select (item, event);
@@ -524,7 +600,7 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp
                                        return true;
 
                                case RegionItem:
                                        return true;
 
                                case RegionItem:
-                                       if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
+                                       if (Keyboard::modifier_state_contains (event->button.state, Keyboard::CopyModifier)) {
                                                start_region_copy_grab (item, event);
                                        } else if (Keyboard::the_keyboard().key_is_down (GDK_b)) {
                                                start_region_brush_grab (item, event);
                                                start_region_copy_grab (item, event);
                                        } else if (Keyboard::the_keyboard().key_is_down (GDK_b)) {
                                                start_region_brush_grab (item, event);
@@ -669,7 +745,13 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp
                        break;
 
                case MouseAudition:
                        break;
 
                case MouseAudition:
-                       /* handled in release */
+                       _scrubbing = true;
+                       scrub_reversals = 0;
+                       scrub_reverse_distance = 0;
+                       last_scrub_x = event->button.x;
+                       scrubbing_direction = 0;
+                       track_canvas.get_window()->set_cursor (*transparent_cursor);
+                       /* rest handled in motion & release */
                        break;
 
                default:
                        break;
 
                default:
@@ -683,13 +765,14 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp
                        if (event->type == GDK_BUTTON_PRESS) {
                                switch (item_type) {
                                case RegionItem:
                        if (event->type == GDK_BUTTON_PRESS) {
                                switch (item_type) {
                                case RegionItem:
-                                       if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
+                                       if (Keyboard::modifier_state_contains (event->button.state, Keyboard::CopyModifier)) {
                                                start_region_copy_grab (item, event);
                                        } else {
                                                start_region_grab (item, event);
                                        }
                                                start_region_copy_grab (item, event);
                                        } else {
                                                start_region_grab (item, event);
                                        }
-                                       
+                                       return true;
                                        break;
                                        break;
+
                                case GainAutomationControlPointItem:
                                case PanAutomationControlPointItem:
                                case RedirectAutomationControlPointItem:
                                case GainAutomationControlPointItem:
                                case PanAutomationControlPointItem:
                                case RedirectAutomationControlPointItem:
@@ -729,7 +812,7 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp
                                        
                                
                case MouseZoom:
                                        
                                
                case MouseZoom:
-                       if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
+                       if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
                                temporal_zoom_session();
                        } else {
                                temporal_zoom_to_frame (true, event_frame(event));
                                temporal_zoom_session();
                        } else {
                                temporal_zoom_to_frame (true, event_frame(event));
@@ -758,6 +841,7 @@ bool
 Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
 {
        nframes_t where = event_frame (event, 0, 0);
 Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
 {
        nframes_t where = event_frame (event, 0, 0);
+       AutomationTimeAxisView* atv = 0;
 
        /* no action if we're recording */
                                                
 
        /* no action if we're recording */
                                                
@@ -842,7 +926,8 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
 
                        case MarkerBarItem: 
                        case RangeMarkerBarItem: 
 
                        case MarkerBarItem: 
                        case RangeMarkerBarItem: 
-                       case TransportMarkerBarItem: 
+                       case TransportMarkerBarItem:
+                       case CdMarkerBarItem:
                        case TempoBarItem:
                        case MeterBarItem:
                                popup_ruler_menu (pixel_to_frame(event->button.x), item_type);
                        case TempoBarItem:
                        case MeterBarItem:
                                popup_ruler_menu (pixel_to_frame(event->button.x), item_type);
@@ -934,7 +1019,6 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
 
                switch (item_type) {
                /* see comments in button_press_handler */
 
                switch (item_type) {
                /* see comments in button_press_handler */
-               case EditCursorItem:
                case PlayheadCursorItem:
                case MarkerItem:
                case GainLineItem:
                case PlayheadCursorItem:
                case MarkerItem:
                case GainLineItem:
@@ -952,6 +1036,14 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
                        mouse_add_new_marker (where);
                        return true;
 
                        mouse_add_new_marker (where);
                        return true;
 
+               case CdMarkerBarItem:
+                       // if we get here then a dragged range wasn't done
+                       if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
+                               snap_to (where, 0, true);
+                       }
+                       mouse_add_new_marker (where, true);
+                       return true;
+
                case TempoBarItem:
                        if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
                                snap_to (where);
                case TempoBarItem:
                        if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
                                snap_to (where);
@@ -972,14 +1064,14 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
                case MouseObject:
                        switch (item_type) {
                        case AutomationTrackItem:
                case MouseObject:
                        switch (item_type) {
                        case AutomationTrackItem:
-                               dynamic_cast<AutomationTimeAxisView*>(clicked_trackview)->add_automation_event 
-                                       (item,
-                                        event,
-                                        where,
-                                        event->button.y);
+                               atv = dynamic_cast<AutomationTimeAxisView*>(clicked_trackview);
+                               if (atv) {
+                                       atv->add_automation_event (item, event, where, event->button.y);
+                               }
                                return true;
                                return true;
+                               
                                break;
                                break;
-
+                               
                        default:
                                break;
                        }
                        default:
                                break;
                        }
@@ -1009,12 +1101,20 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
                        break;
                        
                case MouseAudition:
                        break;
                        
                case MouseAudition:
-                       switch (item_type) {
-                       case RegionItem:
-                               audition_selected_region ();
-                               break;
-                       default:
-                               break;
+                       _scrubbing = false;
+                       track_canvas.get_window()->set_cursor (*current_canvas_cursor);
+                       if (scrubbing_direction == 0) {
+                               /* no drag, just a click */
+                               switch (item_type) {
+                               case RegionItem:
+                                       play_selected_region ();
+                                       break;
+                               default:
+                                       break;
+                               }
+                       } else {
+                               /* make sure we stop */
+                               session->request_transport_speed (0.0);
                        }
                        break;
 
                        }
                        break;
 
@@ -1033,9 +1133,9 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
                case MouseObject:
                        switch (item_type) {
                        case RegionItem:
                case MouseObject:
                        switch (item_type) {
                        case RegionItem:
-                               if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
+                               if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
                                        raise_region ();
                                        raise_region ();
-                               } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::ModifierMask (Keyboard::Shift|Keyboard::Alt))) {
+                               } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::ModifierMask (Keyboard::TertiaryModifier|Keyboard::SecondaryModifier))) {
                                        lower_region ();
                                } else {
                                        // Button2 click is unused
                                        lower_region ();
                                } else {
                                        // Button2 click is unused
@@ -1077,6 +1177,11 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
        Marker * marker;
        double fraction;
        
        Marker * marker;
        double fraction;
        
+       if (last_item_entered != item) {
+               last_item_entered = item;
+               last_item_entered_n = 0;
+       }
+
        switch (item_type) {
        case GainControlPointItem:
                if (mouse_mode == MouseGain) {
        switch (item_type) {
        case GainControlPointItem:
                if (mouse_mode == MouseGain) {
@@ -1092,12 +1197,15 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
 
                        fraction = 1.0 - (cp->get_y() / cp->line.height());
 
 
                        fraction = 1.0 - (cp->get_y() / cp->line.height());
 
-                       set_verbose_canvas_cursor (cp->line.get_verbose_cursor_string (fraction), at_x, at_y);
-                       show_verbose_canvas_cursor ();
-
-                       if (is_drawable()) {
+                       if (is_drawable() && !_scrubbing) {
                                track_canvas.get_window()->set_cursor (*fader_cursor);
                        }
                                track_canvas.get_window()->set_cursor (*fader_cursor);
                        }
+
+                       last_item_entered_n++;
+                       set_verbose_canvas_cursor (cp->line.get_verbose_cursor_string (fraction), at_x, at_y);
+                       if (last_item_entered_n < 10) {
+                               show_verbose_canvas_cursor ();
+                       }
                }
                break;
 
                }
                break;
 
@@ -1130,7 +1238,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
                if (mouse_mode == MouseGain) {
                        ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
                        if (line)
                if (mouse_mode == MouseGain) {
                        ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
                        if (line)
-                               line->property_fill_color_rgba() = color_map[cEnteredGainLine];
+                               line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_EnteredGainLine.get();
                        if (is_drawable()) {
                                track_canvas.get_window()->set_cursor (*fader_cursor);
                        }
                        if (is_drawable()) {
                                track_canvas.get_window()->set_cursor (*fader_cursor);
                        }
@@ -1144,7 +1252,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
                        {
                                ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
                                if (line)
                        {
                                ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
                                if (line)
-                                       line->property_fill_color_rgba() = color_map[cEnteredAutomationLine];
+                                       line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_EnteredAutomationLine.get();
                        }
                        if (is_drawable()) {
                                track_canvas.get_window()->set_cursor (*fader_cursor);
                        }
                        if (is_drawable()) {
                                track_canvas.get_window()->set_cursor (*fader_cursor);
@@ -1172,10 +1280,16 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
                }
                break;
 
                }
                break;
 
-       case EditCursorItem:
        case PlayheadCursorItem:
                if (is_drawable()) {
        case PlayheadCursorItem:
                if (is_drawable()) {
-                       track_canvas.get_window()->set_cursor (*grabber_cursor);
+                       switch (_edit_point) {
+                       case EditAtMouse:
+                               track_canvas.get_window()->set_cursor (*grabber_edit_point_cursor);
+                               break;
+                       default:
+                               track_canvas.get_window()->set_cursor (*grabber_cursor);
+                               break;
+                       }
                }
                break;
 
                }
                break;
 
@@ -1219,6 +1333,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
        case MarkerBarItem:
        case RangeMarkerBarItem:
        case TransportMarkerBarItem:
        case MarkerBarItem:
        case RangeMarkerBarItem:
        case TransportMarkerBarItem:
+       case CdMarkerBarItem:
        case MeterBarItem:
        case TempoBarItem:
                if (is_drawable()) {
        case MeterBarItem:
        case TempoBarItem:
                if (is_drawable()) {
@@ -1230,7 +1345,8 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
                if ((marker = static_cast<Marker *> (item->get_data ("marker"))) == 0) {
                        break;
                }
                if ((marker = static_cast<Marker *> (item->get_data ("marker"))) == 0) {
                        break;
                }
-               marker->set_color_rgba (color_map[cEnteredMarker]);
+               entered_marker = marker;
+               marker->set_color_rgba (ARDOUR_UI::config()->canvasvar_EnteredMarker.get());
                // fall through
        case MeterMarkerItem:
        case TempoMarkerItem:
                // fall through
        case MeterMarkerItem:
        case TempoMarkerItem:
@@ -1313,7 +1429,6 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
        case RegionViewNameHighlight:
        case StartSelectionTrimItem:
        case EndSelectionTrimItem:
        case RegionViewNameHighlight:
        case StartSelectionTrimItem:
        case EndSelectionTrimItem:
-       case EditCursorItem:
        case PlayheadCursorItem:
        /* <CMT Additions> */
        case ImageFrameHandleStartItem:
        case PlayheadCursorItem:
        /* <CMT Additions> */
        case ImageFrameHandleStartItem:
@@ -1352,6 +1467,7 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
 
        case RangeMarkerBarItem:
        case TransportMarkerBarItem:
 
        case RangeMarkerBarItem:
        case TransportMarkerBarItem:
+       case CdMarkerBarItem:
        case MeterBarItem:
        case TempoBarItem:
        case MarkerBarItem:
        case MeterBarItem:
        case TempoBarItem:
        case MarkerBarItem:
@@ -1364,8 +1480,10 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
                if ((marker = static_cast<Marker *> (item->get_data ("marker"))) == 0) {
                        break;
                }
                if ((marker = static_cast<Marker *> (item->get_data ("marker"))) == 0) {
                        break;
                }
-               loc = find_location_from_marker (marker, is_start);
-               if (loc) location_flags_changed (loc, this);
+               entered_marker = 0;
+               if ((loc = find_location_from_marker (marker, is_start)) != 0) {
+                       location_flags_changed (loc, this);
+               }
                // fall through
        case MeterMarkerItem:
        case TempoMarkerItem:
                // fall through
        case MeterMarkerItem:
        case TempoMarkerItem:
@@ -1416,18 +1534,20 @@ Editor::left_automation_track ()
 bool
 Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type, bool from_autoscroll)
 {
 bool
 Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type, bool from_autoscroll)
 {
-       gint x, y;
-       
-       /* We call this so that MOTION_NOTIFY events continue to be
-          delivered to the canvas. We need to do this because we set
-          Gdk::POINTER_MOTION_HINT_MASK on the canvas. This reduces
-          the density of the events, at the expense of a round-trip
-          to the server. Given that this will mostly occur on cases
-          where DISPLAY = :0.0, and given the cost of what the motion
-          event might do, its a good tradeoff.  
-       */
-
-       track_canvas.get_pointer (x, y);
+       if (event->motion.is_hint) {
+               gint x, y;
+               
+               /* We call this so that MOTION_NOTIFY events continue to be
+                  delivered to the canvas. We need to do this because we set
+                  Gdk::POINTER_MOTION_HINT_MASK on the canvas. This reduces
+                  the density of the events, at the expense of a round-trip
+                  to the server. Given that this will mostly occur on cases
+                  where DISPLAY = :0.0, and given the cost of what the motion
+                  event might do, its a good tradeoff.  
+               */
+               
+               track_canvas.get_pointer (x, y);
+       }
 
        if (current_stepping_trackview) {
                /* don't keep the persistent stepped trackview if the mouse moves */
 
        if (current_stepping_trackview) {
                /* don't keep the persistent stepped trackview if the mouse moves */
@@ -1441,17 +1561,103 @@ Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item
        }
 
        drag_info.item_type = item_type;
        }
 
        drag_info.item_type = item_type;
+       drag_info.last_pointer_x = drag_info.current_pointer_x;
+       drag_info.last_pointer_y = drag_info.current_pointer_y;
        drag_info.current_pointer_frame = event_frame (event, &drag_info.current_pointer_x,
                                                       &drag_info.current_pointer_y);
 
        drag_info.current_pointer_frame = event_frame (event, &drag_info.current_pointer_x,
                                                       &drag_info.current_pointer_y);
 
+       switch (mouse_mode) {
+       case MouseAudition:
+               if (_scrubbing) {
+
+                       double delta;
+
+                       if (scrubbing_direction == 0) {
+                               /* first move */
+                               session->request_locate (drag_info.current_pointer_frame, false);
+                               session->request_transport_speed (0.1);
+                               scrubbing_direction = 1;
+
+                       } else {
+                               
+                               if (last_scrub_x > drag_info.current_pointer_x) {
+
+                                       /* pointer moved to the left */
+                                       
+                                       if (scrubbing_direction > 0) {
+
+                                               /* we reversed direction to go backwards */
+
+                                               scrub_reversals++;
+                                               scrub_reverse_distance += (int) (last_scrub_x - drag_info.current_pointer_x);
+
+                                       } else {
+
+                                               /* still moving to the left (backwards) */
+                                               
+                                               scrub_reversals = 0;
+                                               scrub_reverse_distance = 0;
+
+                                               delta = 0.01 * (last_scrub_x - drag_info.current_pointer_x);
+                                               session->request_transport_speed (session->transport_speed() - delta);
+                                       }
+                                       
+                               } else {
+                                       /* pointer moved to the right */
+
+                                       if (scrubbing_direction < 0) {
+                                               /* we reversed direction to go forward */
+
+                                               scrub_reversals++;
+                                               scrub_reverse_distance += (int) (drag_info.current_pointer_x - last_scrub_x);
+
+                                       } else {
+                                               /* still moving to the right */
+
+                                               scrub_reversals = 0;
+                                               scrub_reverse_distance = 0;
+                                               
+                                               delta = 0.01 * (drag_info.current_pointer_x - last_scrub_x);
+                                               session->request_transport_speed (session->transport_speed() + delta);
+                                       }
+                               }
+
+                               /* if there have been more than 2 opposite motion moves detected, or one that moves
+                                  back more than 10 pixels, reverse direction
+                               */
+
+                               if (scrub_reversals >= 2 || scrub_reverse_distance > 10) {
+
+                                       if (scrubbing_direction > 0) {
+                                               /* was forwards, go backwards */
+                                               session->request_transport_speed (-0.1);
+                                               scrubbing_direction = -1;
+                                       } else {
+                                               /* was backwards, go forwards */
+                                               session->request_transport_speed (0.1);
+                                               scrubbing_direction = 1;
+                                       }
+                                       
+                                       scrub_reverse_distance = 0;
+                                       scrub_reversals = 0;
+                               }
+                       }
+
+                       last_scrub_x = drag_info.current_pointer_x;
+               }
+
+       default:
+               break;
+       }
+
        if (!from_autoscroll && drag_info.item) {
                /* item != 0 is the best test i can think of for dragging.
                */
                if (!drag_info.move_threshold_passed) {
 
        if (!from_autoscroll && drag_info.item) {
                /* item != 0 is the best test i can think of for dragging.
                */
                if (!drag_info.move_threshold_passed) {
 
-                       bool x_threshold_passed =  (abs ((int) (drag_info.current_pointer_x - drag_info.grab_x)) > 4);
-                       bool y_threshold_passed =  (abs ((int) (drag_info.current_pointer_y - drag_info.grab_y)) > 4);
-
+                       bool x_threshold_passed =  (::llabs ((nframes64_t) (drag_info.current_pointer_x - drag_info.grab_x)) > 4LL);
+                       bool y_threshold_passed =  (::llabs ((nframes64_t) (drag_info.current_pointer_y - drag_info.grab_y)) > 4LL);
+                       
                        drag_info.move_threshold_passed = (x_threshold_passed || y_threshold_passed);
                        
                        // and change the initial grab loc/frame if this drag info wants us to
                        drag_info.move_threshold_passed = (x_threshold_passed || y_threshold_passed);
                        
                        // and change the initial grab loc/frame if this drag info wants us to
@@ -1468,7 +1674,6 @@ Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item
 
        switch (item_type) {
        case PlayheadCursorItem:
 
        switch (item_type) {
        case PlayheadCursorItem:
-       case EditCursorItem:
        case MarkerItem:
        case GainControlPointItem:
        case RedirectAutomationControlPointItem:
        case MarkerItem:
        case GainControlPointItem:
        case RedirectAutomationControlPointItem:
@@ -1545,13 +1750,13 @@ Editor::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
        }
 
        if (cursor == 0) {
        }
 
        if (cursor == 0) {
-               cursor = grabber_cursor;
+               cursor = which_grabber_cursor ();
        }
 
         // if dragging with button2, the motion is x constrained, with Alt-button2 it is y constrained
 
        if (event->button.button == 2) {
        }
 
         // if dragging with button2, the motion is x constrained, with Alt-button2 it is y constrained
 
        if (event->button.button == 2) {
-               if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Alt)) {
+               if (Keyboard::modifier_state_equals (event->button.state, Keyboard::SecondaryModifier)) {
                        drag_info.y_constrained = true;
                        drag_info.x_constrained = false;
                } else {
                        drag_info.y_constrained = true;
                        drag_info.x_constrained = false;
                } else {
@@ -1563,11 +1768,13 @@ Editor::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
                drag_info.y_constrained = false;
        }
 
                drag_info.y_constrained = false;
        }
 
-       drag_info.grab_frame = event_frame(event, &drag_info.grab_x, &drag_info.grab_y);
+       drag_info.grab_frame = event_frame (event, &drag_info.grab_x, &drag_info.grab_y);
        drag_info.last_pointer_frame = drag_info.grab_frame;
        drag_info.current_pointer_frame = drag_info.grab_frame;
        drag_info.current_pointer_x = drag_info.grab_x;
        drag_info.current_pointer_y = drag_info.grab_y;
        drag_info.last_pointer_frame = drag_info.grab_frame;
        drag_info.current_pointer_frame = drag_info.grab_frame;
        drag_info.current_pointer_x = drag_info.grab_x;
        drag_info.current_pointer_y = drag_info.grab_y;
+       drag_info.last_pointer_x = drag_info.current_pointer_x;
+       drag_info.last_pointer_y = drag_info.current_pointer_y;
        drag_info.cumulative_x_drag = 0;
        drag_info.cumulative_y_drag = 0;
        drag_info.first_move = true;
        drag_info.cumulative_x_drag = 0;
        drag_info.cumulative_y_drag = 0;
        drag_info.first_move = true;
@@ -1606,7 +1813,7 @@ Editor::swap_grab (ArdourCanvas::Item* new_item, Gdk::Cursor* cursor, uint32_t t
        drag_info.item = new_item;
 
        if (cursor == 0) {
        drag_info.item = new_item;
 
        if (cursor == 0) {
-               cursor = grabber_cursor;
+               cursor = which_grabber_cursor ();
        }
 
        drag_info.item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK, *cursor, time);
        }
 
        drag_info.item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK, *cursor, time);
@@ -1620,13 +1827,14 @@ Editor::end_grab (ArdourCanvas::Item* item, GdkEvent* event)
        stop_canvas_autoscroll ();
 
        if (drag_info.item == 0) {
        stop_canvas_autoscroll ();
 
        if (drag_info.item == 0) {
-               cerr << "end grab with no item\n";
                return false;
        }
        
        drag_info.item->ungrab (event->button.time);
 
        if (drag_info.finished_callback) {
                return false;
        }
        
        drag_info.item->ungrab (event->button.time);
 
        if (drag_info.finished_callback) {
+               drag_info.last_pointer_x = drag_info.current_pointer_x;
+               drag_info.last_pointer_y = drag_info.current_pointer_y;
                (this->*(drag_info.finished_callback)) (item, event);
        }
 
                (this->*(drag_info.finished_callback)) (item, event);
        }
 
@@ -1653,35 +1861,6 @@ Editor::end_grab (ArdourCanvas::Item* item, GdkEvent* event)
        return did_drag;
 }
 
        return did_drag;
 }
 
-void
-Editor::set_edit_cursor (GdkEvent* event)
-{
-       nframes_t pointer_frame = event_frame (event);
-
-       if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
-               if (snap_type != SnapToEditCursor) {
-                       snap_to (pointer_frame);
-               }
-       }
-
-       edit_cursor->set_position (pointer_frame);
-       edit_cursor_clock.set (pointer_frame);
-}
-
-void
-Editor::set_playhead_cursor (GdkEvent* event)
-{
-       nframes_t pointer_frame = event_frame (event);
-
-       if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
-               snap_to (pointer_frame);
-       }
-
-       if (session) {
-               session->request_locate (pointer_frame, session->transport_rolling());
-       }
-}
-
 void
 Editor::start_fade_in_grab (ArdourCanvas::Item* item, GdkEvent* event)
 {
 void
 Editor::start_fade_in_grab (ArdourCanvas::Item* item, GdkEvent* event)
 {
@@ -1708,7 +1887,7 @@ Editor::fade_in_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
        nframes_t pos;
        nframes_t fade_length;
 
        nframes_t pos;
        nframes_t fade_length;
 
-       if ((int32_t)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
+       if (drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
                pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
        }
        else {
                pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
        }
        else {
@@ -1753,7 +1932,7 @@ Editor::fade_in_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* even
 
        if (drag_info.first_move) return;
 
 
        if (drag_info.first_move) return;
 
-       if ((int32_t)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
+       if (drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
                pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
        } else {
                pos = 0;
                pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
        } else {
                pos = 0;
@@ -1781,6 +1960,7 @@ Editor::fade_in_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* even
                XMLNode &before = alist.get_state();
 
                tmp->audio_region()->set_fade_in_length (fade_length);
                XMLNode &before = alist.get_state();
 
                tmp->audio_region()->set_fade_in_length (fade_length);
+               tmp->audio_region()->set_fade_in_active (true);
                
                XMLNode &after = alist.get_state();
                session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
                
                XMLNode &after = alist.get_state();
                session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
@@ -1815,10 +1995,9 @@ Editor::fade_out_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event
        nframes_t pos;
        nframes_t fade_length;
 
        nframes_t pos;
        nframes_t fade_length;
 
-       if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
+       if (drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
                pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
                pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
-       }
-       else {
+       } else {
                pos = 0;
        }
 
                pos = 0;
        }
 
@@ -1863,7 +2042,7 @@ Editor::fade_out_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* eve
        nframes_t pos;
        nframes_t fade_length;
 
        nframes_t pos;
        nframes_t fade_length;
 
-       if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
+       if (drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
                pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
        }
        else {
                pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
        }
        else {
@@ -1898,6 +2077,7 @@ Editor::fade_out_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* eve
                XMLNode &before = alist.get_state();
                
                tmp->audio_region()->set_fade_out_length (fade_length);
                XMLNode &before = alist.get_state();
                
                tmp->audio_region()->set_fade_out_length (fade_length);
+               tmp->audio_region()->set_fade_out_active (true);
 
                XMLNode &after = alist.get_state();
                session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
 
                XMLNode &after = alist.get_state();
                session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
@@ -1945,7 +2125,7 @@ Editor::cursor_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
        Cursor* cursor = (Cursor *) drag_info.data;
        nframes_t adjusted_frame;
        
        Cursor* cursor = (Cursor *) drag_info.data;
        nframes_t adjusted_frame;
        
-       if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
+       if (drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
                adjusted_frame = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
        }
        else {
                adjusted_frame = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
        }
        else {
@@ -1953,7 +2133,7 @@ Editor::cursor_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
        }
        
        if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
        }
        
        if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
-               if (cursor != edit_cursor || snap_type != SnapToEditCursor) {
+               if (cursor == playhead_cursor) {
                        snap_to (adjusted_frame);
                }
        }
                        snap_to (adjusted_frame);
                }
        }
@@ -1962,11 +2142,7 @@ Editor::cursor_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
 
        cursor->set_position (adjusted_frame);
        
 
        cursor->set_position (adjusted_frame);
        
-       if (cursor == edit_cursor) {
-               edit_cursor_clock.set (cursor->current_frame);
-       } else {
-               UpdateAllTransportClocks (cursor->current_frame);
-       }
+       UpdateAllTransportClocks (cursor->current_frame);
 
        show_verbose_time_cursor (cursor->current_frame, 10);
 
 
        show_verbose_time_cursor (cursor->current_frame, 10);
 
@@ -1987,9 +2163,6 @@ Editor::cursor_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event
                if (session) {
                        session->request_locate (playhead_cursor->current_frame, drag_info.was_rolling);
                }
                if (session) {
                        session->request_locate (playhead_cursor->current_frame, drag_info.was_rolling);
                }
-       } else if (item == &edit_cursor->canvas_item) {
-               edit_cursor->set_position (edit_cursor->current_frame);
-               edit_cursor_clock.set (edit_cursor->current_frame);
        } 
 }
 
        } 
 }
 
@@ -2031,22 +2204,43 @@ Editor::start_marker_grab (ArdourCanvas::Item* item, GdkEvent* event)
 
        start_grab (event);
 
 
        start_grab (event);
 
+       _dragging_edit_point = true;
+
        drag_info.copied_location = new Location (*location);
        drag_info.pointer_frame_offset = drag_info.grab_frame - (is_start ? location->start() : location->end());       
 
        update_marker_drag_item (location);
 
        if (location->is_mark()) {
        drag_info.copied_location = new Location (*location);
        drag_info.pointer_frame_offset = drag_info.grab_frame - (is_start ? location->start() : location->end());       
 
        update_marker_drag_item (location);
 
        if (location->is_mark()) {
-               marker_drag_line->show();
-               marker_drag_line->raise_to_top();
-       }
-       else {
+               // marker_drag_line->show();
+               // marker_drag_line->raise_to_top();
+       } else {
                range_marker_drag_rect->show();
                range_marker_drag_rect->raise_to_top();
        }
                range_marker_drag_rect->show();
                range_marker_drag_rect->raise_to_top();
        }
-       
-       if (is_start) show_verbose_time_cursor (location->start(), 10);
-       else show_verbose_time_cursor (location->end(), 10);
+
+       if (is_start) {
+               show_verbose_time_cursor (location->start(), 10);
+       } else {
+               show_verbose_time_cursor (location->end(), 10);
+       }
+
+       Selection::Operation op = Keyboard::selection_type (event->button.state);
+
+       switch (op) {
+       case Selection::Toggle:
+               selection->toggle (marker);
+               break;
+       case Selection::Set:
+               selection->set (marker);
+               break;
+       case Selection::Extend:
+               selection->add (marker);
+               break;
+       case Selection::Add:
+               selection->add (marker);
+               break;
+       }
 }
 
 void
 }
 
 void
@@ -2059,12 +2253,10 @@ Editor::marker_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
        bool is_start;
        bool move_both = false;
 
        bool is_start;
        bool move_both = false;
 
-
        nframes_t newframe;
        nframes_t newframe;
-       if (drag_info.pointer_frame_offset <= (long) drag_info.current_pointer_frame) {
+       if (drag_info.pointer_frame_offset <= drag_info.current_pointer_frame) {
                newframe = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
                newframe = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
-       }
-       else {
+       } else {
                newframe = 0;
        }
 
                newframe = 0;
        }
 
@@ -2080,7 +2272,13 @@ Editor::marker_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
 
        /* call this to find out if its the start or end */
        
 
        /* call this to find out if its the start or end */
        
-       real_location = find_location_from_marker (marker, is_start);
+       if ((real_location = find_location_from_marker (marker, is_start)) == 0) {
+               return;
+       }
+
+       if (real_location->locked()) {
+               return;
+       }
 
        /* use the copy that we're "dragging" around */
        
 
        /* use the copy that we're "dragging" around */
        
@@ -2088,7 +2286,7 @@ Editor::marker_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
 
        f_delta = copy_location->end() - copy_location->start();
        
 
        f_delta = copy_location->end() - copy_location->start();
        
-       if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
+       if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
                move_both = true;
        }
 
                move_both = true;
        }
 
@@ -2135,7 +2333,8 @@ Editor::marker_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
 
        LocationMarkers* lm = find_location_markers (real_location);
        lm->set_position (copy_location->start(), copy_location->end());
 
        LocationMarkers* lm = find_location_markers (real_location);
        lm->set_position (copy_location->start(), copy_location->end());
-       
+       edit_point_clock.set (copy_location->start());
+
        show_verbose_time_cursor (newframe, 10);
 }
 
        show_verbose_time_cursor (newframe, 10);
 }
 
@@ -2146,17 +2345,23 @@ Editor::marker_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event
                marker_drag_motion_callback (item, event);
 
        }
                marker_drag_motion_callback (item, event);
 
        }
+
+       _dragging_edit_point = false;
        
        Marker* marker = (Marker *) drag_info.data;
        bool is_start;
 
        
        Marker* marker = (Marker *) drag_info.data;
        bool is_start;
 
-
        begin_reversible_command ( _("move marker") );
        XMLNode &before = session->locations()->get_state();
        
        Location * location = find_location_from_marker (marker, is_start);
        begin_reversible_command ( _("move marker") );
        XMLNode &before = session->locations()->get_state();
        
        Location * location = find_location_from_marker (marker, is_start);
-       
+
        if (location) {
        if (location) {
+
+               if (location->locked()) {
+                       return;
+               }
+
                if (location->is_mark()) {
                        location->set_start (drag_info.copied_location->start());
                } else {
                if (location->is_mark()) {
                        location->set_start (drag_info.copied_location->start());
                } else {
@@ -2192,6 +2397,7 @@ Editor::start_meter_marker_grab (ArdourCanvas::Item* item, GdkEvent* event)
        }
 
        drag_info.item = item;
        }
 
        drag_info.item = item;
+       drag_info.copy = false;
        drag_info.data = marker;
        drag_info.motion_callback = &Editor::meter_marker_drag_motion_callback;
        drag_info.finished_callback = &Editor::meter_marker_drag_finished_callback;
        drag_info.data = marker;
        drag_info.motion_callback = &Editor::meter_marker_drag_motion_callback;
        drag_info.finished_callback = &Editor::meter_marker_drag_finished_callback;
@@ -2220,7 +2426,7 @@ Editor::start_meter_marker_copy_grab (ArdourCanvas::Item* item, GdkEvent* event)
        // The actual copying is not done before we reach the finish callback.
        char name[64];
        snprintf (name, sizeof(name), "%g/%g", meter_marker->meter().beats_per_bar(), meter_marker->meter().note_divisor ());
        // The actual copying is not done before we reach the finish callback.
        char name[64];
        snprintf (name, sizeof(name), "%g/%g", meter_marker->meter().beats_per_bar(), meter_marker->meter().note_divisor ());
-       MeterMarker* new_marker = new MeterMarker(*this, *meter_group, color_map[cMeterMarker], name, 
+       MeterMarker* new_marker = new MeterMarker(*this, *meter_group, ARDOUR_UI::config()->canvasvar_MeterMarker.get(), name, 
                                                  *new MeterSection(meter_marker->meter()));
 
        drag_info.item = &new_marker->the_item();
                                                  *new MeterSection(meter_marker->meter()));
 
        drag_info.item = &new_marker->the_item();
@@ -2242,7 +2448,7 @@ Editor::meter_marker_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* e
        MeterMarker* marker = (MeterMarker *) drag_info.data;
        nframes_t adjusted_frame;
 
        MeterMarker* marker = (MeterMarker *) drag_info.data;
        nframes_t adjusted_frame;
 
-       if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
+       if (drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
                adjusted_frame = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
        }
        else {
                adjusted_frame = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
        }
        else {
@@ -2321,6 +2527,7 @@ Editor::start_tempo_marker_grab (ArdourCanvas::Item* item, GdkEvent* event)
        }
 
        drag_info.item = item;
        }
 
        drag_info.item = item;
+       drag_info.copy = false;
        drag_info.data = marker;
        drag_info.motion_callback = &Editor::tempo_marker_drag_motion_callback;
        drag_info.finished_callback = &Editor::tempo_marker_drag_finished_callback;
        drag_info.data = marker;
        drag_info.motion_callback = &Editor::tempo_marker_drag_motion_callback;
        drag_info.finished_callback = &Editor::tempo_marker_drag_finished_callback;
@@ -2351,7 +2558,7 @@ Editor::start_tempo_marker_copy_grab (ArdourCanvas::Item* item, GdkEvent* event)
        // The actual copying is not done before we reach the finish callback.
        char name[64];
        snprintf (name, sizeof (name), "%.2f", tempo_marker->tempo().beats_per_minute());
        // The actual copying is not done before we reach the finish callback.
        char name[64];
        snprintf (name, sizeof (name), "%.2f", tempo_marker->tempo().beats_per_minute());
-       TempoMarker* new_marker = new TempoMarker(*this, *tempo_group, color_map[cTempoMarker], name, 
+       TempoMarker* new_marker = new TempoMarker(*this, *tempo_group, ARDOUR_UI::config()->canvasvar_TempoMarker.get(), name, 
                                                  *new TempoSection(tempo_marker->tempo()));
 
        drag_info.item = &new_marker->the_item();
                                                  *new TempoSection(tempo_marker->tempo()));
 
        drag_info.item = &new_marker->the_item();
@@ -2373,7 +2580,7 @@ Editor::tempo_marker_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* e
        TempoMarker* marker = (TempoMarker *) drag_info.data;
        nframes_t adjusted_frame;
        
        TempoMarker* marker = (TempoMarker *) drag_info.data;
        nframes_t adjusted_frame;
        
-       if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
+       if (drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
                adjusted_frame = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
        }
        else {
                adjusted_frame = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
        }
        else {
@@ -2479,6 +2686,16 @@ Editor::start_control_point_grab (ArdourCanvas::Item* item, GdkEvent* event)
 
        start_grab (event, fader_cursor);
 
 
        start_grab (event, fader_cursor);
 
+       // start the grab at the center of the control point so
+       // the point doesn't 'jump' to the mouse after the first drag
+       drag_info.grab_x = control_point->get_x();
+       drag_info.grab_y = control_point->get_y();
+       control_point->line.parent_group().i2w(drag_info.grab_x, drag_info.grab_y);
+       track_canvas.w2c(drag_info.grab_x, drag_info.grab_y,
+                                                                        drag_info.grab_x, drag_info.grab_y);
+
+       drag_info.grab_frame = pixel_to_frame(drag_info.grab_x);
+
        control_point->line.start_drag (control_point, drag_info.grab_frame, 0);
 
        float fraction = 1.0 - (control_point->get_y() / control_point->line.height());
        control_point->line.start_drag (control_point, drag_info.grab_frame, 0);
 
        float fraction = 1.0 - (control_point->get_y() / control_point->line.height());
@@ -2493,11 +2710,28 @@ Editor::control_point_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent*
 {
        ControlPoint* cp = reinterpret_cast<ControlPoint *> (drag_info.data);
 
 {
        ControlPoint* cp = reinterpret_cast<ControlPoint *> (drag_info.data);
 
-       double cx = drag_info.current_pointer_x;
-       double cy = drag_info.current_pointer_y;
+       double dx = drag_info.current_pointer_x - drag_info.last_pointer_x;
+       double dy = drag_info.current_pointer_y - drag_info.last_pointer_y;
+
+       if (event->button.state & Keyboard::SecondaryModifier) {
+               dx *= 0.1;
+               dy *= 0.1;
+       }
+
+       double cx = drag_info.grab_x + drag_info.cumulative_x_drag + dx;
+       double cy = drag_info.grab_y + drag_info.cumulative_y_drag + dy;
 
 
-       drag_info.cumulative_x_drag = cx - drag_info.grab_x ;
-       drag_info.cumulative_y_drag = cy - drag_info.grab_y ;
+       // calculate zero crossing point. back off by .01 to stay on the
+       // positive side of zero
+       double _unused = 0;
+       double zero_gain_y = (1.0 - ZERO_GAIN_FRACTION) * cp->line.height() - .01;
+       cp->line.parent_group().i2w(_unused, zero_gain_y);
+
+       // make sure we hit zero when passing through
+       if ((cy < zero_gain_y and (cy - dy) > zero_gain_y)
+                       or (cy > zero_gain_y and (cy - dy) < zero_gain_y)) {
+               cy = zero_gain_y;
+       }
 
        if (drag_info.x_constrained) {
                cx = drag_info.grab_x;
 
        if (drag_info.x_constrained) {
                cx = drag_info.grab_x;
@@ -2506,6 +2740,9 @@ Editor::control_point_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent*
                cy = drag_info.grab_y;
        }
 
                cy = drag_info.grab_y;
        }
 
+       drag_info.cumulative_x_drag = cx - drag_info.grab_x;
+       drag_info.cumulative_y_drag = cy - drag_info.grab_y;
+
        cp->line.parent_group().w2i (cx, cy);
 
        cx = max (0.0, cx);
        cp->line.parent_group().w2i (cx, cy);
 
        cx = max (0.0, cx);
@@ -2520,10 +2757,10 @@ Editor::control_point_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent*
        }
 
        float fraction = 1.0 - (cy / cp->line.height());
        }
 
        float fraction = 1.0 - (cy / cp->line.height());
-       
+
        bool push;
 
        bool push;
 
-       if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
+       if (Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier)) {
                push = true;
        } else {
                push = false;
                push = true;
        } else {
                push = false;
@@ -2545,7 +2782,7 @@ Editor::control_point_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent
 
                /* just a click */
                
 
                /* just a click */
                
-               if ((event->type == GDK_BUTTON_RELEASE) && (event->button.button == 1) && Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
+               if ((event->type == GDK_BUTTON_RELEASE) && (event->button.button == 1) && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
                        reset_point_selection ();
                }
 
                        reset_point_selection ();
                }
 
@@ -2623,17 +2860,41 @@ void
 Editor::line_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
 {
        AutomationLine* line = reinterpret_cast<AutomationLine *> (drag_info.data);
 Editor::line_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
 {
        AutomationLine* line = reinterpret_cast<AutomationLine *> (drag_info.data);
+
+       double dy = drag_info.current_pointer_y - drag_info.last_pointer_y;
+
+       if (event->button.state & Keyboard::SecondaryModifier) {
+               dy *= 0.1;
+       }
+
        double cx = drag_info.current_pointer_x;
        double cx = drag_info.current_pointer_x;
-       double cy = drag_info.current_pointer_y;
+       double cy = drag_info.grab_y + drag_info.cumulative_y_drag + dy;
+
+       // calculate zero crossing point. back off by .01 to stay on the
+       // positive side of zero
+       double _unused = 0;
+       double zero_gain_y = (1.0 - ZERO_GAIN_FRACTION) * line->height() - .01;
+       line->parent_group().i2w(_unused, zero_gain_y);
+
+       // make sure we hit zero when passing through
+       if ((cy < zero_gain_y and (cy - dy) > zero_gain_y)
+                       or (cy > zero_gain_y and (cy - dy) < zero_gain_y)) {
+               cy = zero_gain_y;
+       }
+
+       drag_info.cumulative_y_drag = cy - drag_info.grab_y;
 
        line->parent_group().w2i (cx, cy);
 
        line->parent_group().w2i (cx, cy);
-       
+
+       cy = max (0.0, cy);
+       cy = min ((double) line->height(), cy);
+
        double fraction;
        fraction = 1.0 - (cy / line->height());
 
        bool push;
 
        double fraction;
        fraction = 1.0 - (cy / line->height());
 
        bool push;
 
-       if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
+       if (Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier)) {
                push = false;
        } else {
                push = true;
                push = false;
        } else {
                push = true;
@@ -2662,8 +2923,14 @@ Editor::start_region_grab (ArdourCanvas::Item* item, GdkEvent* event)
        drag_info.copy = false;
        drag_info.item = item;
        drag_info.data = clicked_regionview;
        drag_info.copy = false;
        drag_info.item = item;
        drag_info.data = clicked_regionview;
-       drag_info.motion_callback = &Editor::region_drag_motion_callback;
-       drag_info.finished_callback = &Editor::region_drag_finished_callback;
+
+       if (Config->get_edit_mode() == Splice) {
+               drag_info.motion_callback = &Editor::region_drag_splice_motion_callback;
+               drag_info.finished_callback = &Editor::region_drag_splice_finished_callback;
+       } else {
+               drag_info.motion_callback = &Editor::region_drag_motion_callback;
+               drag_info.finished_callback = &Editor::region_drag_finished_callback;
+       }
 
        start_grab (event);
 
 
        start_grab (event);
 
@@ -2720,7 +2987,7 @@ Editor::start_region_copy_grab (ArdourCanvas::Item* item, GdkEvent* event)
 void
 Editor::start_region_brush_grab (ArdourCanvas::Item* item, GdkEvent* event)
 {
 void
 Editor::start_region_brush_grab (ArdourCanvas::Item* item, GdkEvent* event)
 {
-       if (selection->regions.empty() || clicked_regionview == 0) {
+       if (selection->regions.empty() || clicked_regionview == 0 || Config->get_edit_mode() == Splice) {
                return;
        }
 
                return;
        }
 
@@ -2751,24 +3018,14 @@ Editor::start_region_brush_grab (ArdourCanvas::Item* item, GdkEvent* event)
 }
 
 void
 }
 
 void
-Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
+Editor::possibly_copy_regions_during_grab (GdkEvent* event)
 {
 {
-       double x_delta;
-       double y_delta = 0;
-       RegionView* rv = reinterpret_cast<RegionView*> (drag_info.data); 
-       nframes_t pending_region_position = 0;
-       int32_t pointer_y_span = 0, canvas_pointer_y_span = 0, original_pointer_order;
-       int32_t visible_y_high = 0, visible_y_low = 512;  //high meaning higher numbered.. not the height on the screen
-       bool clamp_y_axis = false;
-       vector<int32_t>  height_list(512) ;
-       vector<int32_t>::iterator j;
-
        if (drag_info.copy && drag_info.move_threshold_passed && drag_info.want_move_threshold) {
 
                drag_info.want_move_threshold = false; // don't copy again
 
                /* duplicate the region(s) */
        if (drag_info.copy && drag_info.move_threshold_passed && drag_info.want_move_threshold) {
 
                drag_info.want_move_threshold = false; // don't copy again
 
                /* duplicate the region(s) */
-               
+
                vector<RegionView*> new_regionviews;
                
                for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
                vector<RegionView*> new_regionviews;
                
                for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
@@ -2797,31 +3054,130 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
                /* reset selection to new regionviews */
                
                selection->set (new_regionviews);
                /* reset selection to new regionviews */
                
                selection->set (new_regionviews);
-               
+
                /* reset drag_info data to reflect the fact that we are dragging the copies */
                
                drag_info.data = new_regionviews.front();
                /* reset drag_info data to reflect the fact that we are dragging the copies */
                
                drag_info.data = new_regionviews.front();
-               
+
                swap_grab (new_regionviews.front()->get_canvas_group (), 0, event->motion.time);
        }
                swap_grab (new_regionviews.front()->get_canvas_group (), 0, event->motion.time);
        }
+}
 
 
+bool
+Editor::check_region_drag_possible (AudioTimeAxisView** tv)
+{
        /* Which trackview is this ? */
 
        TimeAxisView* tvp = trackview_by_y_position (drag_info.current_pointer_y);
        /* Which trackview is this ? */
 
        TimeAxisView* tvp = trackview_by_y_position (drag_info.current_pointer_y);
-       AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
+       (*tv) = dynamic_cast<AudioTimeAxisView*>(tvp);
 
        /* The region motion is only processed if the pointer is over
           an audio track.
        */
        
 
        /* The region motion is only processed if the pointer is over
           an audio track.
        */
        
-       if (!tv || !tv->is_audio_track()) {
+       if (!(*tv) || !(*tv)->is_audio_track()) {
                /* To make sure we hide the verbose canvas cursor when the mouse is 
                   not held over and audiotrack. 
                */
                hide_verbose_canvas_cursor ();
                /* To make sure we hide the verbose canvas cursor when the mouse is 
                   not held over and audiotrack. 
                */
                hide_verbose_canvas_cursor ();
-               return;
+               return false;
        }
        
        }
        
+       return true;
+}
+
+struct RegionSelectionByPosition {
+    bool operator() (RegionView*a, RegionView* b) {
+           return a->region()->position () < b->region()->position();
+    }
+};
+
+void
+Editor::region_drag_splice_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
+{
+       AudioTimeAxisView* tv;
+       
+       if (!check_region_drag_possible (&tv)) {
+               return;
+       }
+
+       if (!drag_info.move_threshold_passed) {
+               return;
+       }
+
+       int dir;
+
+       if (drag_info.current_pointer_x - drag_info.grab_x > 0) {
+               dir = 1;
+       } else {
+               dir = -1;
+       }
+
+       RegionSelection copy (selection->regions);
+
+       RegionSelectionByPosition cmp;
+       copy.sort (cmp);
+
+       for (RegionSelection::iterator i = copy.begin(); i != copy.end(); ++i) {
+
+               AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&(*i)->get_time_axis_view());
+
+               if (!atv) {
+                       continue;
+               }
+
+               boost::shared_ptr<Playlist> playlist;
+
+               if ((playlist = atv->playlist()) == 0) {
+                       continue;
+               }
+
+               if (!playlist->region_is_shuffle_constrained ((*i)->region())) {
+                       continue;
+               } 
+
+               if (dir > 0) {
+                       if (drag_info.current_pointer_frame < (*i)->region()->last_frame() + 1) {
+                               continue;
+                       }
+               } else {
+                       if (drag_info.current_pointer_frame > (*i)->region()->first_frame()) {
+                               continue;
+                       }
+               }
+
+               
+               playlist->shuffle ((*i)->region(), dir);
+
+               drag_info.grab_x = drag_info.current_pointer_x;
+       }
+}
+
+void
+Editor::region_drag_splice_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
+{
+}
+
+void
+Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
+{
+       double x_delta;
+       double y_delta = 0;
+       RegionView* rv = reinterpret_cast<RegionView*> (drag_info.data); 
+       nframes_t pending_region_position = 0;
+       int32_t pointer_y_span = 0, canvas_pointer_y_span = 0, original_pointer_order;
+       int32_t visible_y_high = 0, visible_y_low = 512;  //high meaning higher numbered.. not the height on the screen
+       bool clamp_y_axis = false;
+       vector<int32_t>  height_list(512) ;
+       vector<int32_t>::iterator j;
+       AudioTimeAxisView* tv;
+
+       possibly_copy_regions_during_grab (event);
+
+       if (!check_region_drag_possible (&tv)) {
+               return;
+       }
+
        original_pointer_order = drag_info.last_trackview->order;
                
        /************************************************************
        original_pointer_order = drag_info.last_trackview->order;
                
        /************************************************************
@@ -2833,7 +3189,7 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
                pointer_y_span = 0;
                goto y_axis_done;
        }
                pointer_y_span = 0;
                goto y_axis_done;
        }
-       
+
        if ((pointer_y_span = (drag_info.last_trackview->order - tv->order)) != 0) {
 
                int32_t children = 0, numtracks = 0;
        if ((pointer_y_span = (drag_info.last_trackview->order - tv->order)) != 0) {
 
                int32_t children = 0, numtracks = 0;
@@ -2987,30 +3343,34 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
           the region would be if we moved it by that much.
        */
 
           the region would be if we moved it by that much.
        */
 
-       if (drag_info.move_threshold_passed) {
+       if ( drag_info.move_threshold_passed ) {
 
 
-               if ((int32_t)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
+               if (drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
 
                        nframes_t sync_frame;
                        nframes_t sync_offset;
                        int32_t sync_dir;
 
                        nframes_t sync_frame;
                        nframes_t sync_offset;
                        int32_t sync_dir;
-           
+
                        pending_region_position = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
                        pending_region_position = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
-           
+
                        sync_offset = rv->region()->sync_offset (sync_dir);
                        sync_offset = rv->region()->sync_offset (sync_dir);
-                       sync_frame = rv->region()->adjust_to_sync (pending_region_position);
 
 
-                       /* we snap if the snap modifier is not enabled.
+                       /* we don't handle a sync point that lies before zero.
                         */
                         */
+                       if (sync_dir >= 0 || (sync_dir < 0 && pending_region_position >= sync_offset)) {
+                               sync_frame = pending_region_position + (sync_dir*sync_offset);
+
+                               /* we snap if the snap modifier is not enabled.
+                                */
            
            
-                       if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
-                               snap_to (sync_frame);   
-                       }
+                               if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
+                                       snap_to (sync_frame);   
+                               }
            
            
-                       if (sync_frame - sync_offset <= sync_frame) {
-                               pending_region_position = sync_frame - (sync_dir*sync_offset);
+                               pending_region_position = rv->region()->adjust_to_sync (sync_frame);
+
                        } else {
                        } else {
-                               pending_region_position = 0;
+                               pending_region_position = drag_info.last_frame_position;
                        }
            
                } else {
                        }
            
                } else {
@@ -3023,18 +3383,19 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
          
                // printf ("3: pending_region_position= %lu    %lu\n", pending_region_position, drag_info.last_frame_position );
          
          
                // printf ("3: pending_region_position= %lu    %lu\n", pending_region_position, drag_info.last_frame_position );
          
-               if (pending_region_position != drag_info.last_frame_position && !drag_info.x_constrained) {
+               bool x_move_allowed = ( !drag_info.x_constrained && (Config->get_edit_mode() != Lock)) || ( drag_info.x_constrained && (Config->get_edit_mode() == Lock)) ;
+               if ( pending_region_position != drag_info.last_frame_position && x_move_allowed ) {
 
 
-                       /* now compute the canvas unit distance we need to move the regiondrag_info.last_trackview->order
+                       /* now compute the canvas unit distance we need to move the regionview
                           to make it appear at the new location.
                        */
                           to make it appear at the new location.
                        */
-           
+
                        if (pending_region_position > drag_info.last_frame_position) {
                                x_delta = ((double) (pending_region_position - drag_info.last_frame_position) / frames_per_unit);
                        } else {
                                x_delta = -((double) (drag_info.last_frame_position - pending_region_position) / frames_per_unit);
                        }
                        if (pending_region_position > drag_info.last_frame_position) {
                                x_delta = ((double) (pending_region_position - drag_info.last_frame_position) / frames_per_unit);
                        } else {
                                x_delta = -((double) (drag_info.last_frame_position - pending_region_position) / frames_per_unit);
                        }
-           
+
                        drag_info.last_frame_position = pending_region_position;
            
                } else {
                        drag_info.last_frame_position = pending_region_position;
            
                } else {
@@ -3046,7 +3407,7 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
 
                x_delta = 0;
        }
 
                x_delta = 0;
        }
-
+       
        /*************************************************************
                         PREPARE TO MOVE
        ************************************************************/
        /*************************************************************
                         PREPARE TO MOVE
        ************************************************************/
@@ -3058,6 +3419,7 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
                return;
        } 
 
                return;
        } 
 
+
        if (x_delta < 0) {
                for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
 
        if (x_delta < 0) {
                for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
 
@@ -3096,7 +3458,7 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
 
                pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
                const list<RegionView*>& layered_regions = selection->regions.by_layer();
 
                pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
                const list<RegionView*>& layered_regions = selection->regions.by_layer();
-
+               
                for (list<RegionView*>::const_iterator i = layered_regions.begin(); i != layered_regions.end(); ++i) {
            
                        RegionView* rv = (*i);
                for (list<RegionView*>::const_iterator i = layered_regions.begin(); i != layered_regions.end(); ++i) {
            
                        RegionView* rv = (*i);
@@ -3180,10 +3542,11 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
                                if (-x_delta > ix1) {
                                        x_delta = -ix1;
                                }
                                if (-x_delta > ix1) {
                                        x_delta = -ix1;
                                }
-                       } else if ((x_delta > 0) &&(rv->region()->last_frame() > max_frames - x_delta)) {
+                       } else if ((x_delta > 0) && (rv->region()->last_frame() > max_frames - x_delta)) {
                                x_delta = max_frames - rv->region()->last_frame();
                        }
 
                                x_delta = max_frames - rv->region()->last_frame();
                        }
 
+
                        if (drag_info.first_move) {
 
                                /* hide any dependent views */
                        if (drag_info.first_move) {
 
                                /* hide any dependent views */
@@ -3199,10 +3562,9 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
                                rv->get_canvas_group()->raise_to_top();
                                rv->get_time_axis_view().canvas_display->raise_to_top();
                                cursor_group->raise_to_top();
                                rv->get_canvas_group()->raise_to_top();
                                rv->get_time_axis_view().canvas_display->raise_to_top();
                                cursor_group->raise_to_top();
-
                                rv->fake_set_opaque (true);
                        }
                                rv->fake_set_opaque (true);
                        }
-                       
+
                        if (drag_info.brushing) {
                                mouse_brush_insert_region (rv, pending_region_position);
                        } else {
                        if (drag_info.brushing) {
                                mouse_brush_insert_region (rv, pending_region_position);
                        } else {
@@ -3234,6 +3596,7 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event
        RouteTimeAxisView* atv;
        bool regionview_y_movement;
        bool regionview_x_movement;
        RouteTimeAxisView* atv;
        bool regionview_y_movement;
        bool regionview_x_movement;
+       vector<RegionView*> copies;
 
        /* first_move is set to false if the regionview has been moved in the 
           motion handler. 
 
        /* first_move is set to false if the regionview has been moved in the 
           motion handler. 
@@ -3252,8 +3615,20 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event
 
        region_drag_motion_callback (item, event);
 
 
        region_drag_motion_callback (item, event);
 
+       if (Config->get_edit_mode() == Splice && !pre_drag_region_selection.empty()) {
+               selection->set (pre_drag_region_selection);
+               pre_drag_region_selection.clear ();
+       }
+
        if (drag_info.brushing) {
                /* all changes were made during motion event handlers */
        if (drag_info.brushing) {
                /* all changes were made during motion event handlers */
+               
+               if (drag_info.copy) {
+                       for (list<RegionView*>::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
+                               copies.push_back (*i);
+                       }
+               }
+
                goto out;
        }
 
                goto out;
        }
 
@@ -3296,7 +3671,7 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event
                vector<RegionView*> new_selection;
 
                for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ) {
                vector<RegionView*> new_selection;
 
                for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ) {
-           
+                       
                        RegionView* rv = (*i);              
 
                        double ix1, ix2, iy1, iy2;
                        RegionView* rv = (*i);              
 
                        double ix1, ix2, iy1, iy2;
@@ -3308,7 +3683,7 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event
 
                        boost::shared_ptr<Playlist> from_playlist = rv->region()->playlist();
                        boost::shared_ptr<Playlist> to_playlist = atv2->playlist();
 
                        boost::shared_ptr<Playlist> from_playlist = rv->region()->playlist();
                        boost::shared_ptr<Playlist> to_playlist = atv2->playlist();
-           
+
                        where = (nframes_t) (unit_to_frame (ix1) * speed);
                        boost::shared_ptr<Region> new_region (RegionFactory::create (rv->region()));
 
                        where = (nframes_t) (unit_to_frame (ix1) * speed);
                        boost::shared_ptr<Region> new_region (RegionFactory::create (rv->region()));
 
@@ -3332,9 +3707,15 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event
                                session->add_command (new MementoCommand<Playlist>(*from_playlist, &from_playlist->get_state(), 0));    
                                from_playlist->remove_region ((rv->region()));
                                session->add_command (new MementoCommand<Playlist>(*from_playlist, 0, &from_playlist->get_state()));    
                                session->add_command (new MementoCommand<Playlist>(*from_playlist, &from_playlist->get_state(), 0));    
                                from_playlist->remove_region ((rv->region()));
                                session->add_command (new MementoCommand<Playlist>(*from_playlist, 0, &from_playlist->get_state()));    
+
+                       } else {
+
+                               /* the regionview we dragged around is a temporary copy, queue it for deletion */
+                               
+                               copies.push_back (rv);
                        }
 
                        }
 
-                       latest_regionview = 0;
+                       latest_regionviews.clear ();
                        
                        sigc::connection c = atv2->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
                        session->add_command (new MementoCommand<Playlist>(*to_playlist, &to_playlist->get_state(), 0));        
                        
                        sigc::connection c = atv2->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
                        session->add_command (new MementoCommand<Playlist>(*to_playlist, &to_playlist->get_state(), 0));        
@@ -3342,15 +3723,10 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event
                        session->add_command (new MementoCommand<Playlist>(*to_playlist, 0, &to_playlist->get_state()));        
                        c.disconnect ();
                                                              
                        session->add_command (new MementoCommand<Playlist>(*to_playlist, 0, &to_playlist->get_state()));        
                        c.disconnect ();
                                                              
-                       if (latest_regionview) {
-                               new_selection.push_back (latest_regionview);
+                       if (!latest_regionviews.empty()) {
+                               new_selection.insert (new_selection.end(), latest_regionviews.begin(), latest_regionviews.end());
                        }
 
                        }
 
-                       if (drag_info.copy) {
-                               // get rid of the copy
-                               delete rv;
-                       } 
-
                        /* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region
                           was selected in all of them, then removing it from the playlist will have removed all
                           trace of it from the selection (i.e. there were N regions selected, we removed 1,
                        /* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region
                           was selected in all of them, then removing it from the playlist will have removed all
                           trace of it from the selection (i.e. there were N regions selected, we removed 1,
@@ -3363,12 +3739,19 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event
                           here. if the region selection is not empty, then restart the loop because we know that
                           we must have removed at least the region(view) we've just been working on as well as any
                           that we processed on previous iterations.
                           here. if the region selection is not empty, then restart the loop because we know that
                           we must have removed at least the region(view) we've just been working on as well as any
                           that we processed on previous iterations.
+
+                          EXCEPT .... if we are doing a copy drag, then the selection hasn't been modified and
+                          we can just iterate.
                        */
 
                        */
 
-                       if (selection->regions.empty()) {
-                               break;
-                       } else { 
-                               i = selection->regions.by_layer().begin();
+                       if (drag_info.copy) {
+                               ++i;
+                       } else {
+                               if (selection->regions.empty()) {
+                                       break;
+                               } else { 
+                                       i = selection->regions.by_layer().begin();
+                               }
                        }
                } 
 
                        }
                } 
 
@@ -3435,15 +3818,16 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event
                                }
 
                                /* add it */
                                }
 
                                /* add it */
-                               
-                               latest_regionview = 0;
+
+                               latest_regionviews.clear ();
                                sigc::connection c = atv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
                                to_playlist->add_region (newregion, (nframes_t) (where * atv->get_diskstream()->speed()));
                                c.disconnect ();
                                sigc::connection c = atv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
                                to_playlist->add_region (newregion, (nframes_t) (where * atv->get_diskstream()->speed()));
                                c.disconnect ();
-                               
-                               if (latest_regionview) {
-                                       atv->reveal_dependent_views (*latest_regionview);
-                                       selection->add (latest_regionview);
+
+                               if (!latest_regionviews.empty()) {
+                                       // XXX why just the first one ? we only expect one
+                                       atv->reveal_dependent_views (*latest_regionviews.front());
+                                       selection->add (latest_regionviews);
                                }
                                
                                /* if the original region was locked, we don't care for the new one */
                                }
                                
                                /* if the original region was locked, we don't care for the new one */
@@ -3462,10 +3846,8 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event
 
                        session->add_command (new MementoCommand<Playlist>(*to_playlist, 0, &to_playlist->get_state()));
 
 
                        session->add_command (new MementoCommand<Playlist>(*to_playlist, 0, &to_playlist->get_state()));
 
-                       /* get rid of the copy */
-
                        if (drag_info.copy) {
                        if (drag_info.copy) {
-                               delete rv;
+                               copies.push_back (rv);
                        }
                }
        }
                        }
                }
        }
@@ -3475,6 +3857,10 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event
        if (!nocommit) {
                commit_reversible_command ();
        }
        if (!nocommit) {
                commit_reversible_command ();
        }
+
+       for (vector<RegionView*>::iterator x = copies.begin(); x != copies.end(); ++x) {
+               delete *x;
+       }
 }
 
 void
 }
 
 void
@@ -3484,7 +3870,7 @@ Editor::region_view_item_click (AudioRegionView& rv, GdkEventButton* event)
           this is an alignment click (control used)
        */
        
           this is an alignment click (control used)
        */
        
-       if (Keyboard::modifier_state_contains (event->state, Keyboard::Control)) {
+       if (Keyboard::modifier_state_contains (event->state, Keyboard::PrimaryModifier)) {
                TimeAxisView* tv = &rv.get_time_axis_view();
                AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(tv);
                double speed = 1.0;
                TimeAxisView* tv = &rv.get_time_axis_view();
                AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(tv);
                double speed = 1.0;
@@ -3492,17 +3878,22 @@ Editor::region_view_item_click (AudioRegionView& rv, GdkEventButton* event)
                        speed = atv->get_diskstream()->speed();
                }
 
                        speed = atv->get_diskstream()->speed();
                }
 
-               if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Alt))) {
+               nframes64_t where = get_preferred_edit_position();
 
 
-                       align_region (rv.region(), SyncPoint, (nframes_t) (edit_cursor->current_frame * speed));
+               if (where >= 0) {
 
 
-               } else if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Shift))) {
-
-                       align_region (rv.region(), End, (nframes_t) (edit_cursor->current_frame * speed));
-
-               } else {
-
-                       align_region (rv.region(), Start, (nframes_t) (edit_cursor->current_frame * speed));
+                       if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
+                               
+                               align_region (rv.region(), SyncPoint, (nframes_t) (where * speed));
+                               
+                       } else if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
+                               
+                               align_region (rv.region(), End, (nframes_t) (where * speed));
+                               
+                       } else {
+                               
+                               align_region (rv.region(), Start, (nframes_t) (where * speed));
+                       }
                }
        }
 }
                }
        }
 }
@@ -3634,7 +4025,7 @@ Editor::show_verbose_duration_cursor (nframes_t start, nframes_t end, double off
 void
 Editor::collect_new_region_view (RegionView* rv)
 {
 void
 Editor::collect_new_region_view (RegionView* rv)
 {
-       latest_regionview = rv;
+       latest_regionviews.push_back (rv);
 }
 
 void
 }
 
 void
@@ -3664,7 +4055,7 @@ Editor::start_selection_grab (ArdourCanvas::Item* item, GdkEvent* event)
           set the regionview we want to then drag.
        */
        
           set the regionview we want to then drag.
        */
        
-       latest_regionview = 0;
+       latest_regionviews.clear();
        sigc::connection c = clicked_audio_trackview->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
        
        /* A selection grab currently creates two undo/redo operations, one for 
        sigc::connection c = clicked_audio_trackview->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
        
        /* A selection grab currently creates two undo/redo operations, one for 
@@ -3684,24 +4075,25 @@ Editor::start_selection_grab (ArdourCanvas::Item* item, GdkEvent* event)
        
        c.disconnect ();
        
        
        c.disconnect ();
        
-       if (latest_regionview == 0) {
+       if (latest_regionviews.empty()) {
                /* something went wrong */
                return;
        }
 
        /* we need to deselect all other regionviews, and select this one
                /* something went wrong */
                return;
        }
 
        /* we need to deselect all other regionviews, and select this one
-          i'm ignoring undo stuff, because the region creation will take care of it */
-       selection->set (latest_regionview);
+          i'm ignoring undo stuff, because the region creation will take care of it 
+       */
+       selection->set (latest_regionviews);
        
        
-       drag_info.item = latest_regionview->get_canvas_group();
-       drag_info.data = latest_regionview;
+       drag_info.item = latest_regionviews.front()->get_canvas_group();
+       drag_info.data = latest_regionviews.front();
        drag_info.motion_callback = &Editor::region_drag_motion_callback;
        drag_info.finished_callback = &Editor::region_drag_finished_callback;
 
        start_grab (event);
        
        drag_info.last_trackview = clicked_trackview;
        drag_info.motion_callback = &Editor::region_drag_motion_callback;
        drag_info.finished_callback = &Editor::region_drag_finished_callback;
 
        start_grab (event);
        
        drag_info.last_trackview = clicked_trackview;
-       drag_info.last_frame_position = latest_regionview->region()->position();
+       drag_info.last_frame_position = latest_regionviews.front()->region()->position();
        drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
        
        show_verbose_time_cursor (drag_info.last_frame_position, 10);
        drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
        
        show_verbose_time_cursor (drag_info.last_frame_position, 10);
@@ -3713,10 +4105,8 @@ Editor::cancel_selection ()
         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
                (*i)->hide_selection ();
        }
         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
                (*i)->hide_selection ();
        }
-       begin_reversible_command (_("cancel selection"));
        selection->clear ();
        clicked_selection = 0;
        selection->clear ();
        clicked_selection = 0;
-       commit_reversible_command ();
 }      
 
 void
 }      
 
 void
@@ -3737,7 +4127,7 @@ Editor::start_selection_op (ArdourCanvas::Item* item, GdkEvent* event, Selection
 
        switch (op) {
        case CreateSelection:
 
        switch (op) {
        case CreateSelection:
-               if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
+               if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
                        drag_info.copy = true;
                } else {
                        drag_info.copy = false;
                        drag_info.copy = true;
                } else {
                        drag_info.copy = false;
@@ -3785,10 +4175,9 @@ Editor::drag_selection (ArdourCanvas::Item* item, GdkEvent* event)
        nframes_t length;
        nframes_t pending_position;
 
        nframes_t length;
        nframes_t pending_position;
 
-       if ((int32_t) drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
+       if (drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
                pending_position = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
                pending_position = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
-       }
-       else {
+       } else {
                pending_position = 0;
        }
        
                pending_position = 0;
        }
        
@@ -3953,7 +4342,7 @@ Editor::start_trim (ArdourCanvas::Item* item, GdkEvent* event)
 
        start_grab (event, trimmer_cursor);
        
 
        start_grab (event, trimmer_cursor);
        
-       if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
+       if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
                trim_op = ContentsTrim;
        } else {
                /* These will get overridden for a point trim.*/
                trim_op = ContentsTrim;
        } else {
                /* These will get overridden for a point trim.*/
@@ -4034,7 +4423,7 @@ Editor::trim_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
                begin_reversible_command (trim_type);
 
                for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
                begin_reversible_command (trim_type);
 
                for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
-                       (*i)->fake_set_opaque(false);
+                       (*i)->fake_set_opaque(false);                   
                        (*i)->region()->freeze ();
                
                        AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
                        (*i)->region()->freeze ();
                
                        AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
@@ -4080,7 +4469,7 @@ Editor::trim_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
                {
                        bool swap_direction = false;
 
                {
                        bool swap_direction = false;
 
-                       if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) {
+                       if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
                                swap_direction = true;
                        }
                        
                                swap_direction = true;
                        }
                        
@@ -4221,7 +4610,7 @@ Editor::trim_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
        if (!drag_info.first_move) {
                trim_motion_callback (item, event);
                
        if (!drag_info.first_move) {
                trim_motion_callback (item, event);
                
-               if (!clicked_regionview->get_selected()) {
+               if (!selection->selected (clicked_regionview)) {
                        thaw_region_after_trim (*clicked_regionview);           
                } else {
                        
                        thaw_region_after_trim (*clicked_regionview);           
                } else {
                        
@@ -4263,7 +4652,7 @@ Editor::point_trim (GdkEvent* event)
                trim_op = StartTrim;
                begin_reversible_command (_("Start point trim"));
 
                trim_op = StartTrim;
                begin_reversible_command (_("Start point trim"));
 
-               if (rv->get_selected()) {
+               if (selection->selected (rv)) {
 
                        for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin();
                             i != selection->regions.by_layer().end(); ++i)
 
                        for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin();
                             i != selection->regions.by_layer().end(); ++i)
@@ -4295,7 +4684,7 @@ Editor::point_trim (GdkEvent* event)
                trim_op = EndTrim;
                begin_reversible_command (_("End point trim"));
 
                trim_op = EndTrim;
                begin_reversible_command (_("End point trim"));
 
-               if (rv->get_selected()) {
+               if (selection->selected (rv)) {
                        
                        for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i)
                        {
                        
                        for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i)
                        {
@@ -4381,8 +4770,9 @@ Editor::start_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event, Ran
        switch (op) {
        case CreateRangeMarker:
        case CreateTransportMarker:
        switch (op) {
        case CreateRangeMarker:
        case CreateTransportMarker:
-               
-               if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
+       case CreateCDMarker:
+       
+               if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
                        drag_info.copy = true;
                } else {
                        drag_info.copy = false;
                        drag_info.copy = true;
                } else {
                        drag_info.copy = false;
@@ -4400,7 +4790,23 @@ Editor::drag_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event)
 {
        nframes_t start = 0;
        nframes_t end = 0;
 {
        nframes_t start = 0;
        nframes_t end = 0;
-       ArdourCanvas::SimpleRect *crect = (range_marker_op == CreateRangeMarker) ? range_bar_drag_rect: transport_bar_drag_rect;
+       ArdourCanvas::SimpleRect *crect;
+
+       switch (range_marker_op) {
+       case CreateRangeMarker:
+               crect = range_bar_drag_rect;
+               break;
+       case CreateTransportMarker:
+               crect = transport_bar_drag_rect;
+               break;
+       case CreateCDMarker:
+               crect = cd_marker_bar_drag_rect;
+               break;
+       default:
+               cerr << "Error: unknown range marker op passed to Editor::drag_range_markerbar_op ()" << endl;
+               return;
+               break;
+       }
        
        if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
                snap_to (drag_info.current_pointer_frame);
        
        if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
                snap_to (drag_info.current_pointer_frame);
@@ -4415,6 +4821,7 @@ Editor::drag_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event)
        switch (range_marker_op) {
        case CreateRangeMarker:
        case CreateTransportMarker:
        switch (range_marker_op) {
        case CreateRangeMarker:
        case CreateTransportMarker:
+       case CreateCDMarker:
                if (drag_info.first_move) {
                        snap_to (drag_info.grab_frame);
                }
                if (drag_info.first_move) {
                        snap_to (drag_info.grab_frame);
                }
@@ -4472,23 +4879,32 @@ Editor::end_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event)
 {
        Location * newloc = 0;
        string rangename;
 {
        Location * newloc = 0;
        string rangename;
+       int flags;
        
        if (!drag_info.first_move) {
                drag_range_markerbar_op (item, event);
 
                switch (range_marker_op) {
                case CreateRangeMarker:
        
        if (!drag_info.first_move) {
                drag_range_markerbar_op (item, event);
 
                switch (range_marker_op) {
                case CreateRangeMarker:
+               case CreateCDMarker:
                    {
                        begin_reversible_command (_("new range marker"));
                         XMLNode &before = session->locations()->get_state();
                        session->locations()->next_available_name(rangename,"unnamed");
                    {
                        begin_reversible_command (_("new range marker"));
                         XMLNode &before = session->locations()->get_state();
                        session->locations()->next_available_name(rangename,"unnamed");
-                       newloc = new Location(temp_location->start(), temp_location->end(), rangename, Location::IsRangeMarker);
+                       if (range_marker_op == CreateCDMarker) {
+                               flags =  Location::IsRangeMarker|Location::IsCDMarker;
+                               cd_marker_bar_drag_rect->hide();
+                       }
+                       else {
+                               flags =  Location::IsRangeMarker;
+                               range_bar_drag_rect->hide();
+                       }
+                       newloc = new Location(temp_location->start(), temp_location->end(), rangename, (Location::Flags) flags);
                        session->locations()->add (newloc, true);
                         XMLNode &after = session->locations()->get_state();
                        session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
                        commit_reversible_command ();
                        
                        session->locations()->add (newloc, true);
                         XMLNode &after = session->locations()->get_state();
                        session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
                        commit_reversible_command ();
                        
-                       range_bar_drag_rect->hide();
                        range_marker_drag_rect->hide();
                        break;
                    }
                        range_marker_drag_rect->hide();
                        break;
                    }
@@ -4502,7 +4918,7 @@ Editor::end_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event)
        } else {
                /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
 
        } else {
                /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
 
-               if (Keyboard::no_modifier_keys_pressed (&event->button)) {
+               if (Keyboard::no_modifier_keys_pressed (&event->button) && range_marker_op != CreateCDMarker) {
 
                        nframes_t start;
                        nframes_t end;
 
                        nframes_t start;
                        nframes_t end;
@@ -4521,7 +4937,7 @@ Editor::end_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event)
                        switch (mouse_mode) {
                        case MouseObject:
                                /* find the two markers on either side and then make the selection from it */
                        switch (mouse_mode) {
                        case MouseObject:
                                /* find the two markers on either side and then make the selection from it */
-                               select_all_within (start, end, 0.0f, FLT_MAX, Selection::Set);
+                               select_all_within (start, end, 0.0f, FLT_MAX, track_views, Selection::Set);
                                break;
 
                        case MouseRange:
                                break;
 
                        case MouseRange:
@@ -4654,7 +5070,7 @@ Editor::drag_rubberband_select (ArdourCanvas::Item* item, GdkEvent* event)
                return;
        }
 
                return;
        }
 
-       if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
+       if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier()) && Config->get_rubberbanding_snaps_to_grid()) {
                if (drag_info.first_move) {
                        snap_to (drag_info.grab_frame);
                } 
                if (drag_info.first_move) {
                        snap_to (drag_info.grab_frame);
                } 
@@ -4724,9 +5140,9 @@ Editor::end_rubberband_select (ArdourCanvas::Item* item, GdkEvent* event)
                begin_reversible_command (_("rubberband selection"));
 
                if (drag_info.grab_frame < drag_info.last_pointer_frame) {
                begin_reversible_command (_("rubberband selection"));
 
                if (drag_info.grab_frame < drag_info.last_pointer_frame) {
-                       commit = select_all_within (drag_info.grab_frame, drag_info.last_pointer_frame, y1, y2, op);
+                       commit = select_all_within (drag_info.grab_frame, drag_info.last_pointer_frame, y1, y2, track_views, op);
                } else {
                } else {
-                       commit = select_all_within (drag_info.last_pointer_frame, drag_info.grab_frame, y1, y2, op);
+                       commit = select_all_within (drag_info.last_pointer_frame, drag_info.grab_frame, y1, y2, track_views, op);
                }               
 
                if (commit) {
                }               
 
                if (commit) {
@@ -4761,7 +5177,7 @@ Editor::mouse_rename_region (ArdourCanvas::Item* item, GdkEvent* event)
         string str;
                prompter.get_result(str);
                if (str.length()) {
         string str;
                prompter.get_result(str);
                if (str.length()) {
-               clicked_regionview->region()->set_name (str);
+                       clicked_regionview->region()->set_name (str);
                }
                break;
        }
                }
                break;
        }
@@ -4811,13 +5227,27 @@ Editor::end_time_fx (ArdourCanvas::Item* item, GdkEvent* event)
        if (drag_info.first_move) {
                return;
        }
        if (drag_info.first_move) {
                return;
        }
+
+       if (drag_info.last_pointer_frame < clicked_regionview->region()->position()) {
+               /* backwards drag of the left edge - not usable */
+               return;
+       }
        
        nframes_t newlen = drag_info.last_pointer_frame - clicked_regionview->region()->position();
        
        nframes_t newlen = drag_info.last_pointer_frame - clicked_regionview->region()->position();
+#ifdef USE_RUBBERBAND
+       float percentage = (float) ((double) newlen / (double) clicked_regionview->region()->length());
+#else
        float percentage = (float) ((double) newlen - (double) clicked_regionview->region()->length()) / ((double) newlen) * 100.0f;
        float percentage = (float) ((double) newlen - (double) clicked_regionview->region()->length()) / ((double) newlen) * 100.0f;
-       
+#endif 
+
        begin_reversible_command (_("timestretch"));
 
        begin_reversible_command (_("timestretch"));
 
-       if (run_timestretch (selection->regions, percentage) == 0) {
+       // XXX how do timeFX on multiple regions ?
+
+       RegionSelection rs;
+       rs.add (clicked_regionview);
+
+       if (time_stretch (rs, percentage) == 0) {
                session->commit_reversible_command ();
        }
 }
                session->commit_reversible_command ();
        }
 }
@@ -4839,9 +5269,7 @@ Editor::mouse_brush_insert_region (RegionView* rv, nframes_t pos)
        }
 
        switch (snap_type) {
        }
 
        switch (snap_type) {
-       case SnapToFrame:
        case SnapToMark:
        case SnapToMark:
-       case SnapToEditCursor:
                return;
 
        default:
                return;
 
        default:
@@ -4888,3 +5316,4 @@ Editor::track_height_step_timeout ()
        }
        return true;
 }
        }
        return true;
 }
+