diff --git a/mono/Assistance/Assistance.csproj b/mono/Assistance/Assistance.csproj
index c23bc66..b98c551 100644
--- a/mono/Assistance/Assistance.csproj
+++ b/mono/Assistance/Assistance.csproj
@@ -64,11 +64,7 @@
   <ItemGroup>
     <Reference Include="System" />
     <Reference Include="System.Core" />
-    <Reference Include="glib-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f">
-      <Private>False</Private>
-      <Package>glib-sharp-2.0</Package>
-    </Reference>
-    <Reference Include="gtk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f">
+    <Reference Include="atk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f">
       <Private>False</Private>
       <Package>gtk-sharp-2.0</Package>
     </Reference>
@@ -76,10 +72,14 @@
       <Private>False</Private>
       <Package>gtk-sharp-2.0</Package>
     </Reference>
-    <Reference Include="Mono.Cairo" />
-    <Reference Include="atk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f">
+    <Reference Include="glib-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f">
+      <Private>False</Private>
+      <Package>glib-sharp-2.0</Package>
+    </Reference>
+    <Reference Include="gtk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f">
       <Private>False</Private>
       <Package>gtk-sharp-2.0</Package>
     </Reference>
+    <Reference Include="Mono.Cairo" />
   </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/mono/Assistance/Drawing.cs b/mono/Assistance/Drawing.cs
index fa3f972..5e9e171 100644
--- a/mono/Assistance/Drawing.cs
+++ b/mono/Assistance/Drawing.cs
@@ -4,13 +4,13 @@ namespace Assistance {
 	namespace Drawing {
 		public class Helper {
 			public static Rectangle getBounds(Cairo.Context context) {
-				double w = 1.0;
-				double h = 1.0;
-				if (context.GetTarget() is Cairo.ImageSurface) {
-					Cairo.ImageSurface surface = (Cairo.ImageSurface)context.GetTarget();
-					w = surface.Width;
-					h = surface.Height;
-				}
+				double w = 2000;
+				double h = 1500;
+				//if (context.GetTarget() is Cairo.ImageSurface) {
+				//	Cairo.ImageSurface surface = (Cairo.ImageSurface)context.GetTarget();
+				//	w = surface.Width;
+				//	h = surface.Height;
+				//}
 				
 				Point[] corners = new Point[] {
 					new Point(0.0, 0.0),
diff --git a/mono/Assistance/DynamicSurface.cs b/mono/Assistance/DynamicSurface.cs
index 9655b9d..20fdbd8 100644
--- a/mono/Assistance/DynamicSurface.cs
+++ b/mono/Assistance/DynamicSurface.cs
@@ -8,6 +8,7 @@ namespace Assistance {
 		private int offsetX;
 		private int offsetY;
 		private Cairo.ImageSurface surface;
+		private Cairo.Context privateContext;
 		
 		public DynamicSurface(double incrementScale = 1.2)
 			{ this.incrementScale = incrementScale; }
@@ -24,21 +25,20 @@ namespace Assistance {
 		public int height
 			{ get { return isEmpty ? 0 : surface.Height; } }
 		
+		public Cairo.Context context
+			{ get { return privateContext; } }
+
 		public Rectangle getBounds() {
 			return isEmpty ? new Rectangle()
 			     : new Rectangle((double)offsetX, (double)offsetY, (double)(offsetX + surface.Width), (double)(offsetY + surface.Height));
 		}
 
-		public Cairo.Context getContext() {
-			if (isEmpty) return null;
-			Cairo.Context context = new Cairo.Context(surface);
-			context.Antialias = Cairo.Antialias.Gray;
-			context.Translate(-offsetX, -offsetY);
-			return context;
-		}
+		public void flush()
+			{ if (surface != null) surface.Flush(); }
 
 		public void draw(Cairo.Context context, double alpha = 1.0) {
 			if (isEmpty) return;
+			flush();
 			context.Save();
 			context.Translate(offsetX, offsetY);
 			context.SetSource(surface);
@@ -49,15 +49,19 @@ namespace Assistance {
 
 		public void clear() {
 			if (isEmpty) return;
+			privateContext.Dispose();
+			privateContext = null;
 			surface.Dispose();
 			surface = null;
-		}
+        }
 
-		private bool doExpand(Rectangle rect, bool noScale) {
+		public bool expand(Rectangle rect, bool noScale = false) {
+			rect = new Rectangle(rect.p0).expand(rect.p1);
+		
 			int rl = (int)Math.Floor(rect.x0 + Geometry.precision);
 			int rt = (int)Math.Floor(rect.y0 + Geometry.precision);
-			int rr = Math.Max(rl, (int)Math.Ceiling(rect.x1 - Geometry.precision));
-			int rb = Math.Max(rt, (int)Math.Ceiling(rect.y1 - Geometry.precision));
+			int rr = Math.Max(rl, (int)Math.Ceiling(rect.x1 - Geometry.precision)) + 1;
+			int rb = Math.Max(rt, (int)Math.Ceiling(rect.y1 - Geometry.precision)) + 1;
 		    
 		    int l, t, r, b;
 		    if (surface == null) {
@@ -81,46 +85,30 @@ namespace Assistance {
 		    int h = b - t;
 		    if (surface != null && l == offsetX && t == offsetY && w == surface.Width && h == surface.Height)
 		    	return false;
-
+		    if (w <= 0 || h <= 0)
+		    	return false;
+			
 			Cairo.ImageSurface newSurface = new Cairo.ImageSurface(Cairo.Format.ARGB32, w, h);
-	    	Cairo.Context context = new Cairo.Context(newSurface);
-	    	if (surface != null) {
-		    	context.Translate(offsetX - l, offsetY - t);
-		    	context.SetSource(surface);
-		    	context.Paint();
-				context.GetTarget().Flush();
-				context.Dispose();
+			Cairo.Context newContext = new Cairo.Context(newSurface);
+	    	if (!isEmpty) {
+	    		flush();
+	    		newContext.Save();
+		    	newContext.Translate(offsetX - l, offsetY - t);
+		    	newContext.SetSource(surface);
+		    	newContext.Paint();
+		    	newContext.Restore();
+				clear();
 			}
-			
 			offsetX = l;
 			offsetY = t;
 			surface = newSurface;
+			privateContext = newContext;
+			privateContext.Antialias = Cairo.Antialias.Gray;
+			privateContext.Translate(-offsetX, -offsetY);
 			
 			return true;
 		}
 
-		public bool expand(Rectangle rect, bool noScale = false) {
-			Cairo.Surface surface = this.surface;
-			if (doExpand(rect, noScale)) {
-				if (surface != null) surface.Dispose();
-				return true;
-			}
-			return false;
-		}
-		
-		public bool expandContext(ref Cairo.Context context, Rectangle rect, bool noScale = false) {
-			Cairo.Surface surface = this.surface;
-			if (context != null) context.GetTarget().Flush();
-			if (doExpand(rect, noScale)) {
-				Cairo.Context oldContext = context;
-				context = getContext();
-				if (oldContext != null) oldContext.Dispose();
-				surface.Dispose();
-				return true;
-			}
-			return false;
-		}
-
 		public void Dispose()
 			{ Dispose(true); GC.SuppressFinalize(this); }
 		protected virtual void Dispose(bool disposing)
diff --git a/mono/Assistance/Geometry.cs b/mono/Assistance/Geometry.cs
index e2da322..ce67232 100644
--- a/mono/Assistance/Geometry.cs
+++ b/mono/Assistance/Geometry.cs
@@ -10,14 +10,14 @@ namespace Assistance {
 		
 		public static bool isEqual(double a, double b)
 			{ return Math.Abs(b - a) <= precision; }
-		public static bool isGreaterOrEqual(double a, double b)
-			{ return b - a <= precision; }
-		public static bool isLessOrEqual(double a, double b)
-			{ return isGreaterOrEqual(b, a); }
 		public static bool isLess(double a, double b)
-			{ return !isGreaterOrEqual(a, b); }
+			{ return b - a > precision; }
 		public static bool isGreater(double a, double b)
-			{ return !isGreaterOrEqual(b, a); }
+			{ return a - b > precision; }
+		public static bool isLessOrEqual(double a, double b)
+			{ return a - b <= precision; }
+		public static bool isGreaterOrEqual(double a, double b)
+			{ return b - a <= precision; }
 		
 		public static double logNormalDistribuitionUnscaled(double x, double x0, double w) {
 			return Math.Exp(-0.5*Math.Pow(Math.Log(x/x0)/w, 2.0))/x;
@@ -113,5 +113,21 @@ namespace Assistance {
 			     + t0*( 3.0*ll - 4.0*l + 1.0)
 			     + t1*( 3.0*ll - 2.0*l      );
         }
+
+		public static Track.Point interpolationSpline(Track.Point p0, Track.Point p1, Track.Point t0, Track.Point t1, double l) {
+			double ll = l*l;
+			double lll = ll*l;
+			return p0*( 2.0*lll - 3.0*ll + 1.0)
+			     + p1*(-2.0*lll + 3.0*ll      )
+			     + t0*(     lll - 2.0*ll + l  )
+			     + t1*(     lll - 1.0*ll      );
+        }
+
+		public static Track.Point interpolationSplineTangent(Track.Point p0, Track.Point p1, Track.Point t0, Track.Point t1, double l) {
+			double ll = l*l;
+			return (p0 - p1)*6.0*(ll - l)
+			     + t0*( 3.0*ll - 4.0*l + 1.0)
+			     + t1*( 3.0*ll - 2.0*l      );
+        }
 	}
 }
diff --git a/mono/Assistance/Guideline.cs b/mono/Assistance/Guideline.cs
index d224c70..b90545a 100644
--- a/mono/Assistance/Guideline.cs
+++ b/mono/Assistance/Guideline.cs
@@ -8,7 +8,7 @@ namespace Assistance {
 		public static readonly Pen penActive = new Pen("Deep Sky Blue");
 		public static readonly double snapLenght = 20.0;
 		public static readonly double snapScale = 1.0;
-		public static readonly double maxLenght = 2.0*snapLenght*snapScale;
+		public static readonly double maxLenght = 20.0*snapLenght*snapScale;
 	
 		public virtual Track.WayPoint transformPoint(Track.WayPoint point)
 			{ return point; }
@@ -48,11 +48,11 @@ namespace Assistance {
 		}
 
 		public static Guideline findBest(List<Guideline> guidelines, Track track) {
-			double bestWeight = double.PositiveInfinity;
+			double bestWeight = 0.0;
 			Guideline best = null;
 			foreach(Guideline guideline in guidelines) {
 				double weight = guideline.calcTrackWeight(track);
-				if (weight < bestWeight) {
+				if (best == null || weight < bestWeight) {
 					bestWeight = weight;
 					best = guideline;
 				}
diff --git a/mono/Assistance/InputManager.cs b/mono/Assistance/InputManager.cs
index dff039c..1049d36 100644
--- a/mono/Assistance/InputManager.cs
+++ b/mono/Assistance/InputManager.cs
@@ -3,7 +3,7 @@ using System.Collections.Generic;
 
 namespace Assistance {
 	public class InputManager: Track.IOwner {
-		public static readonly Drawing.Pen penPreview = new Drawing.Pen("Dark Green", 1.0, 0.25);
+		public static readonly Drawing.Pen penPreview = new Drawing.Pen("Dark Green", 3.0, 0.25);
 		public static readonly double levelAlpha = 0.8;
 
 		public class TrackHandler: Track.Handler {
@@ -55,7 +55,7 @@ namespace Assistance {
 		public interface IModifier: Track.IOwner {
 			void activate();
 			void modify(List<Track> tracks, KeyPoint keyPoint, List<Track> outTracks);
-			void draw(Cairo.Context context, List<Track> tracks);
+			void draw(Cairo.Context context, List<Track> tracks, List<Point> hovers);
 			void deactivate();
 		}
 
@@ -64,9 +64,12 @@ namespace Assistance {
 			public virtual void modify(Track track, KeyPoint keyPoint, List<Track> outTracks) { }
 			public virtual void modify(List<Track> tracks, KeyPoint keyPoint, List<Track> outTracks)
 				{ foreach(Track track in tracks) modify(track, keyPoint, outTracks); }
-			public virtual void draw(Cairo.Context context, Track tracks) { }
-			public virtual void draw(Cairo.Context context, List<Track> tracks)
-				{ foreach(Track track in tracks) draw(context, track); }
+			public virtual void drawHover(Cairo.Context context, Point hover) { }
+			public virtual void drawTrack(Cairo.Context context, Track track) { }
+			public virtual void draw(Cairo.Context context, List<Track> tracks, List<Point> hovers) {
+				foreach(Track track in tracks) drawTrack(context, track);
+				foreach(Point hover in hovers) drawHover(context, hover);
+			}
 			public virtual void deactivate() { }
 		}
 
@@ -91,7 +94,7 @@ namespace Assistance {
 		private void paintRollbackTo(int keyIndex, List<Track> subTracks) {
 			if (keyIndex >= keyPoints.Count)
 				return;
-			
+
 			int level = keyIndex + 1;
 			if (level <= keyPointsSent) {
 				if (level < keyPointsSent)
@@ -114,34 +117,33 @@ namespace Assistance {
 		private void paintApply(int count, List<Track> subTracks) {
 			if (count <= 0)
 				return;
-			
+				
 			int level = keyPoints.Count - count;
+			bool resend = true;
 			
 			if (level < keyPointsSent) {
 				// apply
 				int applied = tool.paintApply(keyPointsSent - level);
 				applied = Math.Max(0, Math.Min(keyPointsSent - level, applied));
 				keyPointsSent -= applied;
-				foreach(Track track in subTracks) {
-					TrackHandler handler = (TrackHandler)track.handler;
-					handler.keys.RemoveRange(keyPointsSent, handler.keys.Count - keyPointsSent);
-				}
+				if (keyPointsSent == level) resend = false;
 			}
-
+			
 			if (level < keyPointsSent) {
 				// rollback
 				tool.paintPop(keyPointsSent - level);
 				keyPointsSent = level;
-				foreach(Track track in subTracks) {
-					TrackHandler handler = (TrackHandler)track.handler;
-					int cnt = handler.keys[keyPointsSent];
-					handler.keys.RemoveRange(keyPointsSent, handler.keys.Count - keyPointsSent);
-					track.wayPointsRemoved = 0;
-					track.wayPointsAdded = track.points.Count - cnt;
-				}
 			}
 
 			// remove keypoints
+			foreach(Track track in subTracks) {
+				TrackHandler handler = (TrackHandler)track.handler;
+				if (resend) {
+					track.wayPointsRemoved = 0;
+					track.wayPointsAdded = track.points.Count - handler.keys[keyPointsSent];
+				}
+				handler.keys.RemoveRange(level, handler.keys.Count - level);
+			}
 			for(int i = level; i < keyPoints.Count; ++i) keyPoints[i].available = false;
 			keyPoints.RemoveRange(level, keyPoints.Count - level);
 		}
@@ -171,7 +173,7 @@ namespace Assistance {
 					int rollbackIndex = keyPoints.Count;
 					foreach(Track track in subTracks) {
 						if (track.wayPointsRemoved > 0) {
-							int count = track.points.Count - track.wayPointsAdded + track.wayPointsRemoved;
+							int count = track.points.Count - track.wayPointsAdded;
 							TrackHandler handler = (TrackHandler)track.handler;
 							while(rollbackIndex > 0 && (rollbackIndex >= keyPoints.Count || handler.keys[rollbackIndex] > count))
 								--rollbackIndex;
@@ -189,6 +191,10 @@ namespace Assistance {
 				// send to tool
 				if (keyPointsSent == keyPoints.Count && subTracks.Count > 0)
 					tool.paintTracks(subTracks);
+				foreach(Track track in subTracks) {
+					track.wayPointsRemoved = 0;
+					track.wayPointsAdded = 0;
+				}
 				
 				// is paint finished?
 				if (newKeyPoint.isFree) {
@@ -206,11 +212,15 @@ namespace Assistance {
 				foreach(Track track in subTracks)
 					((TrackHandler)track.handler).keys.Add(track.points.Count);
 			}
+
 		}
-		
+
+		private long getDeviceId(Gdk.Device device)
+			{ return device == null ? 0 : device.Handle.ToInt64(); }
+				
 		private int trackCompare(Track track, Gdk.Device device, long touchId) {
-			if (track.device.Handle.ToInt64() < device.Handle.ToInt64()) return -1;
-			if (track.device.Handle.ToInt64() > device.Handle.ToInt64()) return 1;
+			if (getDeviceId(track.device) < getDeviceId(device)) return -1;
+			if (getDeviceId(track.device) > getDeviceId(device)) return 1;
 			if (track.touchId < touchId) return -1;
 			if (track.touchId > touchId) return 1;
 			return 0;
@@ -227,6 +237,8 @@ namespace Assistance {
 		}
 		
 		private Track getTrack(Gdk.Device device, long touchId, long ticks) {
+			if (tracks[0].Count == 0)
+				return createTrack(0, device, touchId, ticks);
 			int cmp;
 			
 			int a = 0;
@@ -234,7 +246,7 @@ namespace Assistance {
 			if (cmp == 0) return tracks[0][a];
 			if (cmp < 0) return createTrack(a, device, touchId, ticks);
 			
-			int b = tracks.Count - 1;
+			int b = tracks[0].Count - 1;
 			cmp = trackCompare(tracks[0][b], device, touchId);
 			if (cmp == 0) return tracks[0][b];
 			if (cmp > 0) return createTrack(b+1, device, touchId, ticks);
@@ -343,7 +355,7 @@ namespace Assistance {
 			{ return tool; }
 		
 		public void setTool(Tool tool) {
-			if (this.tool == tool) {
+			if (this.tool != tool) {
 				if (actualActive) {
 					finishTracks();
 					this.tool.deactivate();
@@ -395,14 +407,20 @@ namespace Assistance {
 		}
 	
 		
-		public void draw(Cairo.Context context) {
+		public void draw(Cairo.Context context, List<Point> hovers) {
+			if (!isActive()) return;
+
+			// paint tool
+			tool.draw(context);
+			
 			// paint not sent sub-tracks
 			if (keyPointsSent < keyPoints.Count) {
 				context.Save();
 				penPreview.apply(context);
 				foreach(Track track in getOutputTracks()) {
 					TrackHandler handler = (TrackHandler)track.handler;
-					int start = handler.keys[keyPointsSent];
+					int start = handler.keys[keyPointsSent] - 1;
+					if (start < 0) start = 0;
 					if (start < track.points.Count) {
 						Drawing.Color color = penPreview.color;
 						int level = keyPointsSent;
@@ -427,7 +445,7 @@ namespace Assistance {
 			
 			// paint modifiers
 			for(int i = 0; i < modifiers.Count; ++i)
-				modifiers[i].draw(context, tracks[i]);
+				modifiers[i].draw(context, tracks[i], hovers);
 		}
 	}
 }
diff --git a/mono/Assistance/InputModifierAssistants.cs b/mono/Assistance/InputModifierAssistants.cs
index 43a7841..915af47 100644
--- a/mono/Assistance/InputModifierAssistants.cs
+++ b/mono/Assistance/InputModifierAssistants.cs
@@ -6,7 +6,8 @@ namespace Assistance {
 	public class InputModifierAssistants: InputModifierTangents {
 		public readonly Workarea workarea;
 		public readonly bool defaultTangents;
-		
+		public readonly List<Guideline> shownGuidelines = new List<Guideline>();
+				
 		public InputModifierAssistants(Workarea workarea, bool defaultTangents = false) {
 			this.workarea = workarea;
 			this.defaultTangents = defaultTangents;
@@ -18,7 +19,6 @@ namespace Assistance {
 			
 			public InputManager.KeyPoint.Holder holder = null;
 			public List<Guideline> guidelines = new List<Guideline>();
-			public List<Guideline> hintGuidelines = new List<Guideline>();
 			
 			public override Track.WayPoint calcWayPoint(double originalIndex) {
 				Track.WayPoint p = original.calcWayPoint(originalIndex);
@@ -35,7 +35,7 @@ namespace Assistance {
 					return;
 
 				Track.Handler handler = new Track.Handler(this, track);
-				modifier = new Modifier(track.handler);
+				modifier = new Modifier(handler);
 				workarea.getGuidelines(modifier.guidelines, track.points[0].point.position);
 				if (defaultTangents && modifier.guidelines.Count == 0)
 					{ base.modify(track, keyPoint, outTracks); return; }
@@ -65,18 +65,18 @@ namespace Assistance {
 			int start = track.points.Count - track.wayPointsAdded;
 			if (start < 0) start = 0;
 			if (subTrack.points.Count < start) {
-				subTrack.points.RemoveRange(start, subTrack.points.Count - start);
 				subTrack.wayPointsRemoved += subTrack.points.Count - start;
+				subTrack.points.RemoveRange(start, subTrack.points.Count - start);
 			}
 			
-			bool trackIsLong = track.points.Count > 0 && track.getLast().length >= Guideline.maxLenght;
+			bool trackIsLong = track.points.Count > 0 && (track.getLast().length >= Guideline.maxLenght || track.isFinished());
 			if (!trackIsLong && modifier.holder != null && !modifier.holder.isHolded && modifier.holder.available)
 				modifier.holder.reuse();
 			
 			// select guideline
 			if (modifier.holder != null && modifier.holder.isHolded) {
 				Guideline guideline = Guideline.findBest(modifier.guidelines, track);
-				if (guideline != modifier.guidelines[0]) {
+				if (guideline != null && guideline != modifier.guidelines[0]) {
 					modifier.guidelines[ modifier.guidelines.IndexOf(guideline) ] = modifier.guidelines[0];
 					modifier.guidelines[0] = guideline;
 					start = 0;
@@ -91,20 +91,23 @@ namespace Assistance {
 			for(int i = start; i < track.points.Count; ++i)
 				subTrack.points.Add(modifier.calcWayPoint(i));
 			subTrack.wayPointsAdded = subTrack.points.Count - start;
+			
+			track.wayPointsRemoved = 0;
+			track.wayPointsAdded = 0;
 		}
-		
-		public override void draw(Cairo.Context context, Track track) {
+
+		public override void drawHover(Cairo.Context context, Point hover) {
+			workarea.getGuidelines(shownGuidelines, hover);
+			foreach(Guideline guideline in shownGuidelines)
+				guideline.draw(context);
+			shownGuidelines.Clear();
+		}
+				
+		public override void drawTrack(Cairo.Context context, Track track) {
 			if (track.handler == null) return;
 			Track subTrack = track.handler.tracks[0];
-			if (!(subTrack.modifier is Modifier))
-				{ base.draw(context, track); return; }
-			Modifier modifier = (Modifier)subTrack.modifier;
-			if (modifier.guidelines.Count > 0 && subTrack.points.Count > 0) {
-				workarea.getGuidelines(modifier.hintGuidelines, subTrack.points[0].point.position);
-				foreach(Guideline gl in modifier.hintGuidelines)
-					gl.draw(context);
-				modifier.hintGuidelines.Clear();
-			}
+			if (subTrack.points.Count > 0)
+				drawHover(context, subTrack.getLast().point.position);
 		}
 	}
 }
diff --git a/mono/Assistance/InputModifierInterpolation.cs b/mono/Assistance/InputModifierInterpolation.cs
index bcd4b60..4d896a0 100644
--- a/mono/Assistance/InputModifierInterpolation.cs
+++ b/mono/Assistance/InputModifierInterpolation.cs
@@ -3,6 +3,8 @@ using System.Collections.Generic;
 
 namespace Assistance {
 	public class InputModifierInterpolation: InputManager.Modifier {
+		public static readonly int maxRecursion = 8;
+	
 		public readonly double precision;
 		public readonly double precisionSqr;
 		
@@ -11,12 +13,12 @@ namespace Assistance {
 			this.precisionSqr = this.precision*this.precision;
 		}
 	
-		public void addSegment(Track track, Track.WayPoint p0, Track.WayPoint p1) {
-			if ((p1.point.position - p0.point.position).lenSqr() <= precisionSqr)
+		public void addSegment(Track track, Track.WayPoint p0, Track.WayPoint p1, int level = 0) {
+			if (level >= maxRecursion || (p1.point.position - p0.point.position).lenSqr() <= precisionSqr)
 				{ track.points.Add(p1); return; }
 			Track.WayPoint p = track.modifier.calcWayPoint(0.5*(p0.originalIndex + p1.originalIndex));
-			addSegment(track, p0, p);
-			addSegment(track, p, p1);
+			addSegment(track, p0, p, level + 1);
+			addSegment(track, p, p1, level + 1);
 		}
 	
 		public override void modify(Track track, InputManager.KeyPoint keyPoint, List<Track> outTracks) {
@@ -35,9 +37,11 @@ namespace Assistance {
 			int start = track.points.Count - track.wayPointsAdded;
 			if (start < 0) start = 0;
 			int subStart = subTrack.floorIndex(subTrack.indexByOriginalIndex(start));
-			if (subTrack.points.Count < subStart) {
-				subTrack.points.RemoveRange(subStart, subTrack.points.Count - subStart);
+			if (subStart < 0) subStart = 0;
+			
+			if (subStart < subTrack.points.Count) {
 				subTrack.wayPointsRemoved += subTrack.points.Count - subStart;
+				subTrack.points.RemoveRange(subStart, subTrack.points.Count - subStart);
 			}
 			
 			// add points
@@ -48,6 +52,9 @@ namespace Assistance {
 				p0 = p1;
 			}
 			subTrack.wayPointsAdded += subTrack.points.Count - subStart;
+			
+			track.wayPointsRemoved = 0;
+			track.wayPointsAdded = 0;
 		}
 	}
 }
diff --git a/mono/Assistance/InputModifierTangents.cs b/mono/Assistance/InputModifierTangents.cs
index 360448f..6725912 100644
--- a/mono/Assistance/InputModifierTangents.cs
+++ b/mono/Assistance/InputModifierTangents.cs
@@ -49,11 +49,11 @@ namespace Assistance {
 				int start = track.points.Count - track.wayPointsAdded;
 				if (start < 0) start = 0;
 				if (start > 1) --start;
-				if (subTrack.points.Count < start) {
-					subTrack.points.RemoveRange(start, subTrack.points.Count - start);
+				if (start < subTrack.points.Count) {
 					subTrack.wayPointsRemoved += subTrack.points.Count - start;
+					subTrack.points.RemoveRange(start, subTrack.points.Count - start);
 				}
-				if (modifier.tangents.Count < start)
+				if (start < modifier.tangents.Count)
 					modifier.tangents.RemoveRange(start, modifier.tangents.Count - start);
 				
 				// add first point
diff --git a/mono/Assistance/KeyHistory.cs b/mono/Assistance/KeyHistory.cs
index ef5a0b3..5dae8fd 100644
--- a/mono/Assistance/KeyHistory.cs
+++ b/mono/Assistance/KeyHistory.cs
@@ -63,8 +63,9 @@ namespace Assistance {
 		
 		private int findLock(long ticks) {
 			// locks[a] <= ticks < locks[b]
+			if (locks.Count == 0) return -1;
 			int a = 0;
-			int b = states.Count - 1;
+			int b = locks.Count - 1;
 			if (locks[a] < ticks) return -1;
 			if (ticks >= locks[b]) return b;
 			while(true) {
diff --git a/mono/Assistance/MainWindow.cs b/mono/Assistance/MainWindow.cs
index 8a3d7ea..7e38d8a 100644
--- a/mono/Assistance/MainWindow.cs
+++ b/mono/Assistance/MainWindow.cs
@@ -10,9 +10,7 @@ namespace Assistance {
 			win.Maximize();
         	Gtk.Application.Run();
         }
-
-		Cairo.ImageSurface surface = new Cairo.ImageSurface(Cairo.Format.ARGB32, 1, 1);
-
+		
 		Workarea workarea = new Workarea();
 		ToolFull toolFull;
 		
@@ -22,6 +20,7 @@ namespace Assistance {
 
 		Point offset;
 		Point cursor;
+		List<Point> hovers = new List<Point>();
 		
 		long touchId;
 		long ticksStart = 0;
@@ -47,48 +46,41 @@ namespace Assistance {
 			workarea.setTool(toolFull);
         }
         
+        private bool refreshOnIdle()
+        	{ QueueDraw(); return false; }
+        private void Refresh()
+        	{ GLib.Idle.Add(refreshOnIdle); }
+        
         protected override bool OnDeleteEvent(Gdk.Event e) {
 			Gtk.Application.Quit();
-			return true;
-		}
-
-		protected override void OnSizeAllocated(Gdk.Rectangle allocation) {
-			if ( surface.Width != allocation.Width
-	          || surface.Height != allocation.Height )
-	        {
-	        	surface.Dispose();
-	        	surface = new Cairo.ImageSurface(Cairo.Format.ARGB32, allocation.Width, allocation.Height);
-	       	}
-			base.OnSizeAllocated(allocation);
+			return false;
 		}
 
 		protected override bool OnExposeEvent(Gdk.EventExpose e) {
-			Cairo.Context context = new Cairo.Context(surface);
-        	context.Antialias = Cairo.Antialias.Gray;
-        	
+            Cairo.Context context = Gdk.CairoHelper.Create(e.Window);
+
         	context.Save();
         	context.SetSourceRGBA(1.0, 1.0, 1.0, 1.0);
-        	context.Rectangle(0, 0, surface.Width, surface.Height);
+        	context.Rectangle(0, 0, Allocation.Width, Allocation.Height);
         	context.Fill();
         	context.Restore();
-            
+        	
+        	context.Save();
+			context.Antialias = Cairo.Antialias.Gray;
             draw(context);
-            context.Dispose();
+        	context.Restore();
             
-            context = Gdk.CairoHelper.Create(GdkWindow);
-            context.SetSource(surface);
-            context.Paint();
             context.Dispose();
-
-			return true;
+            
+			return false;
 		}
 
 		public Point windowToWorkarea(Point p) {
-			return new Point(p.x - surface.Width/2.0, p.y - surface.Height/2.0);
+			return new Point(p.x - Allocation.Width/2.0, p.y - Allocation.Height/2.0);
 		}
 
 		public Point workareaToWindow(Point p) {
-			return new Point(p.x + surface.Width/2.0, p.y + surface.Height/2.0);
+			return new Point(p.x + Allocation.Width/2.0, p.y + Allocation.Height/2.0);
 		}
 
 		private void beginDrag() {
@@ -103,6 +95,7 @@ namespace Assistance {
 			++touchId;
 			ticksStart = Timer.ticks();
 			this.timeStart = timeStart;
+			painting = true;
 		}
 
 		private void endDragAndTrack() {
@@ -140,7 +133,7 @@ namespace Assistance {
 				workarea.inputManager.keyEvent(true, e.Key, Timer.ticks());
 				break;
 			}
-			QueueDraw();
+			Refresh();
 			return base.OnKeyPressEvent(e);
 		}
 		
@@ -159,13 +152,12 @@ namespace Assistance {
 			point.tilt = tilt;	
 			
 			long ticks = ticksStart + (long)Math.Round((time - timeStart)*Timer.frequency);
-			
 			workarea.inputManager.trackEvent(device, touchId, point, final, ticks);
 		}
 
 		void addTrackPoint(double x, double y, uint t, Gdk.Device device, double[] axes, bool final) {
 			Point point = windowToWorkarea(new Point(x, y));
-			double time = (double)(t - timeStart)*0.001;
+			double time = (double)t*0.001;
 			double pressure = 0.5;
 			Point tilt = new Point(0.0, 0.0);
 			if (device != null && axes != null) {
@@ -189,7 +181,6 @@ namespace Assistance {
 			cursor = windowToWorkarea(new Point(e.X, e.Y));
 			workarea.inputManager.buttonEvent(true, e.Device, e.Button, Timer.ticks());
 			if (e.Button == 1) {
-				timeStart = e.Time;
 				activePoint = workarea.findPoint(cursor);
 				if (activePoint != null) {
 					beginDrag();
@@ -198,8 +189,8 @@ namespace Assistance {
 					addTrackPoint(e, true);
 				}
 			}
-			QueueDraw();
-			return true;
+			Refresh();
+			return false;
 		}
 
 		protected override bool OnButtonReleaseEvent(Gdk.EventButton e) {
@@ -212,8 +203,8 @@ namespace Assistance {
 				if (!dragging && !painting)
 					activePoint = workarea.findPoint(cursor);
 			}
-			QueueDraw();
-			return true;
+			Refresh();
+			return false;
 		}
 
 		protected override bool OnMotionNotifyEvent(Gdk.EventMotion e) {
@@ -226,13 +217,15 @@ namespace Assistance {
 			} else {
 				activePoint = workarea.findPoint(cursor);
 			}
-			QueueDraw();
-			return true;
+			Refresh();
+			return false;
 		}
 
         public void draw(Cairo.Context context) {
-        	context.Translate(surface.Width/2, surface.Height/2);
-			workarea.draw(context, activePoint);
+        	context.Translate(Allocation.Width/2, Allocation.Height/2);
+        	hovers.Clear();
+        	if (!painting) hovers.Add(cursor);
+			workarea.draw(context, hovers, activePoint);
         }
     }
 }
diff --git a/mono/Assistance/Modifier.cs b/mono/Assistance/Modifier.cs
index 9bc55d0..7452399 100644
--- a/mono/Assistance/Modifier.cs
+++ b/mono/Assistance/Modifier.cs
@@ -8,11 +8,13 @@ namespace Assistance {
 
 		public Modifier(Document document): base(document) {
 			document.modifiers.Add(this);
+			document.workarea.updateModifiers();
 		}
 
 		public override void remove() {
 			base.remove();
 			document.modifiers.Remove(this);
+			document.workarea.updateModifiers();
 		}
 
 		public override void bringToFront() {
@@ -24,9 +26,12 @@ namespace Assistance {
 		public virtual void modify(Track track, InputManager.KeyPoint keyPoint, List<Track> outTracks) { }
 		public virtual void modify(List<Track> tracks, InputManager.KeyPoint keyPoint, List<Track> outTracks)
 			{ foreach(Track track in tracks) modify(track, keyPoint, outTracks); }
-		public virtual void draw(Cairo.Context context, Track track) { }
-		public virtual void draw(Cairo.Context context, List<Track> tracks)
-			{ foreach(Track track in tracks) draw(context, track); }
+		public virtual void drawHover(Cairo.Context context, Point hover) { }
+		public virtual void drawTrack(Cairo.Context context, Track track) { }
+		public virtual void draw(Cairo.Context context, List<Track> tracks, List<Point> hovers) {
+			foreach(Track track in tracks) drawTrack(context, track);
+			foreach(Point hover in hovers) drawHover(context, hover);
+		}
 		public virtual void deactivate() { }
 
 		public virtual void draw(Cairo.Context context) { }
diff --git a/mono/Assistance/ModifierSnowflake.cs b/mono/Assistance/ModifierSnowflake.cs
index d174366..ea9b338 100644
--- a/mono/Assistance/ModifierSnowflake.cs
+++ b/mono/Assistance/ModifierSnowflake.cs
@@ -71,16 +71,19 @@ namespace Assistance {
 			if (start < 0) start = 0;
 			foreach(Track subTrack in track.handler.tracks) {
 				// remove points
-				if (subTrack.points.Count < start) {
-					subTrack.points.RemoveRange(start, subTrack.points.Count - start);
+				if (start < subTrack.points.Count) {
 					subTrack.wayPointsRemoved += subTrack.points.Count - start;
+					subTrack.points.RemoveRange(start, subTrack.points.Count - start);
 				}
 				
 				// add points
 				for(int i = start; i < track.points.Count; ++i)
-					subTrack.points.Add( subTrack.calcWayPoint(i) );
+					subTrack.points.Add( subTrack.modifier.calcWayPoint(i) );
 				subTrack.wayPointsAdded += subTrack.points.Count - start;
 			}
+			
+			track.wayPointsRemoved = 0;
+			track.wayPointsAdded = 0;
 		}
 	}
 }
diff --git a/mono/Assistance/ToolFull.cs b/mono/Assistance/ToolFull.cs
index d9ea6b1..d1872c7 100644
--- a/mono/Assistance/ToolFull.cs
+++ b/mono/Assistance/ToolFull.cs
@@ -3,7 +3,7 @@ using System.Collections.Generic;
 
 namespace Assistance {
 	public class ToolFull: Tool {
-		public static readonly Drawing.Pen pen = new Drawing.Pen("Dark Green", 10.0);
+		public static readonly Drawing.Pen pen = new Drawing.Pen("Dark Green", 3.0);
 		public static readonly double levelAlpha = 0.8;
 	
 		
@@ -25,32 +25,36 @@ namespace Assistance {
 			return true;
 		}
 
-		private void paintPoint(DynamicSurface surface, Cairo.Context context, Track.WayPoint point) {
+		private void paintPoint(DynamicSurface surface, Track.WayPoint point) {
 			Point p = point.point.position;
 			double r = pen.width*point.point.pressure;
+			Drawing.Color color = pen.color;
+			if (r < 0.01) r = 0.01;
+			if (r > Geometry.precision && r < 0.5)
+				{ color.a *= r/0.5; r = 0.5; }
 			double rr = r + 1.0;
 			
-			surface.expandContext(ref context, new Rectangle(p.x - rr, p.y - rr, p.x + rr, p.y + rr));
+			surface.expand(new Rectangle(p.x - rr, p.y - rr, p.x + rr, p.y + rr));
 
-			context.Save();
-			pen.apply(context);
-			context.Arc(p.x, p.y, r, 0.0, 2.0*Math.PI);
-			context.Fill();
-			context.Restore();
+			surface.context.Save();
+			pen.apply(surface.context);
+			color.apply(surface.context);
+			surface.context.Arc(p.x, p.y, r, 0.0, 2.0*Math.PI);
+			surface.context.Fill();
+			surface.context.Restore();
 		}
 
 		public override void paintTracks(List<Track> tracks) {
 			DynamicSurface surface = getSurface();
-			Cairo.Context context = surface.getContext();
 			while(true) {
 				Track track = null;
-				long minTicks = long.MaxValue;
+				long minTicks = 0;
 				double minTimeOffset = 0.0;
 				foreach(Track t in tracks) {
 					if (t.wayPointsAdded > 0) {
 						long ticks = t.ticks;
 						double timeOffset = t.timeOffset + t.points[t.points.Count - t.wayPointsAdded].time;
-						if ((ticks - minTicks)*Timer.frequency + timeOffset - minTimeOffset < 0.0) {
+						if (track == null || (ticks - minTicks)*Timer.frequency + timeOffset - minTimeOffset < 0.0) {
 							track = t;
 							minTicks = ticks;
 							minTimeOffset = timeOffset;
@@ -58,23 +62,18 @@ namespace Assistance {
 					}
 				}
 				if (track == null) break;
-				paintPoint(surface, context, track.points[track.points.Count - track.wayPointsAdded]);
+				paintPoint(surface, track.points[track.points.Count - track.wayPointsAdded]);
 				--track.wayPointsAdded;
 			}
-			context.GetTarget().Flush();
-			context.Dispose();
 		}
 		
 		public override int paintApply(int count) {
 			int level = stack.Count - count;
 			DynamicSurface surface = getSurface(level);
-			Cairo.Context context = surface.getContext();
 			for(int i = level; i < stack.Count; ++i) {
-				surface.expandContext(ref context, stack[i].getBounds(), true);
-				stack[i].draw(context);
+				surface.expand(stack[i].getBounds(), true);
+				stack[i].draw(surface.context);
 			}
-			context.GetTarget().Flush();
-			context.Dispose();
 			paintPop(count);
 			return count;
 		}
diff --git a/mono/Assistance/Track.cs b/mono/Assistance/Track.cs
index 93f0b3d..feaf1a8 100644
--- a/mono/Assistance/Track.cs
+++ b/mono/Assistance/Track.cs
@@ -154,7 +154,7 @@ namespace Assistance {
 		public WayPoint getLast()
 			{ return getWayPoint(points.Count - 1); }
 		public bool isFinished()
-			{ return getLast().final; }
+			{ return points.Count > 0 && getLast().final; }
 		
 		public int clampIndex(int index)
 			{ return Math.Min(Math.Max(index, 0), points.Count - 1); }
@@ -181,7 +181,7 @@ namespace Assistance {
 		public WayPoint floorWayPoint(double index)
 			{ return getWayPoint(floorIndex(index)); }
 		public WayPoint ceilWayPoint(double index)
-			{ return getWayPoint(floorIndex(index)); }
+			{ return getWayPoint(ceilIndex(index)); }
 		
 		private delegate double WayPointFieldGetter(WayPoint p);
 		private double binarySearch(double value, WayPointFieldGetter getter) {
@@ -190,7 +190,7 @@ namespace Assistance {
 			if (points.Count <= 0) return 0.0;
 			int a = 0;
 			double aa = getter(points[a]);
-			if (Geometry.isLess(aa, value)) return 0.0;
+			if (Geometry.isLess(value, aa)) return 0.0;
 
 			int b = points.Count - 1;
 			double bb = getter(points[b]);
@@ -247,8 +247,8 @@ namespace Assistance {
 			if (l <= Geometry.precision) return p0;
 			if (l >= 1.0 - Geometry.precision) return p1;
 			return new WayPoint(
-				Geometry.Interpolation<Point>.spline(p0.point, p1.point, p0.tangent, p1.tangent, l),
-				Geometry.Interpolation<Point>.splineTangent(p0.point, p1.point, p0.tangent, p1.tangent, l),
+				Geometry.interpolationSpline(p0.point, p1.point, p0.tangent, p1.tangent, l),
+				Geometry.interpolationSplineTangent(p0.point, p1.point, p0.tangent, p1.tangent, l),
 				Geometry.interpolationLinear(p0.originalIndex, p1.originalIndex, l),
 				Geometry.interpolationLinear(p0.time, p1.time, l),
 				Geometry.interpolationLinear(p0.length, p1.length, l),
diff --git a/mono/Assistance/Workarea.cs b/mono/Assistance/Workarea.cs
index 4850dff..9fbd20b 100644
--- a/mono/Assistance/Workarea.cs
+++ b/mono/Assistance/Workarea.cs
@@ -47,6 +47,9 @@ namespace Assistance {
 				inputManager.activate();
 			}
 		}
+		
+		public void updateModifiers()
+			{ setTool(getTool(), true); }
 
 		public ActivePoint findPoint(Point position) {
 			foreach(ActivePoint point in document.points.Reverse<ActivePoint>())
@@ -60,12 +63,12 @@ namespace Assistance {
 				assistant.getGuidelines(outGuidelines, target);
 		}
 
-		public void draw(Cairo.Context context, ActivePoint activePoint) {
+		public void draw(Cairo.Context context, List<Point> hovers, ActivePoint activePoint) {
 			// canvas
 			document.canvas.draw(context);
 
 			// input manager
-			inputManager.draw(context);
+			inputManager.draw(context, hovers);
 			
 			// modifiers
 			foreach(Modifier modifier in document.modifiers)