Index: gtk2_ardour/draginfo.h
===================================================================
--- gtk2_ardour/draginfo.h	(revision 2563)
+++ gtk2_ardour/draginfo.h	(working copy)
@@ -49,6 +49,8 @@
     double cumulative_y_drag;
     double current_pointer_x;
     double current_pointer_y;
+    double last_pointer_x;
+    double last_pointer_y;
     void (Editor::*motion_callback)(ArdourCanvas::Item*, GdkEvent*);
     void (Editor::*finished_callback)(ArdourCanvas::Item*, GdkEvent*);
     TimeAxisView* last_trackview;
Index: gtk2_ardour/editor_mouse.cc
===================================================================
--- gtk2_ardour/editor_mouse.cc	(revision 2563)
+++ gtk2_ardour/editor_mouse.cc	(working copy)
@@ -1461,6 +1461,8 @@
 	}
 
 	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);
 
@@ -1647,6 +1649,8 @@
 	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;
@@ -1705,6 +1709,8 @@
 	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);
 	}
 
@@ -2569,12 +2575,17 @@
 {
 	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;
 
-	drag_info.cumulative_x_drag = cx - drag_info.grab_x ;
-	drag_info.cumulative_y_drag = cy - drag_info.grab_y ;
+	if (event->button.state & Keyboard::Alt) {
+		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;
+
 	if (drag_info.x_constrained) {
 		cx = drag_info.grab_x;
 	}
@@ -2582,6 +2593,9 @@
 		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);
@@ -2596,7 +2610,7 @@
 	}
 
 	float fraction = 1.0 - (cy / cp->line.height());
-	
+
 	bool push;
 
 	if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
@@ -2699,11 +2713,23 @@
 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::Alt) {
+		dy *= 0.1;
+	}
+
 	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;
 
+	drag_info.cumulative_y_drag = cy - drag_info.grab_y;
+
 	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());
 
