protected sealed override void PaintSurface (DockySurface surface)
		{
			surface.Clear ();
			
			lock (buffers) {
				if (slideCounter > 0 && slideCounter < slideSteps) {
					double offset = Allocation.Width * Math.Log (slideCounter) / Math.Log (slideSteps);
					
					if (MovedLeft) {
						ShowBuffer (surface, Page, offset - Allocation.Width);
						ShowBuffer (surface, LastPage, offset);
					} else {
						ShowBuffer (surface, Page, Allocation.Width - offset);
						ShowBuffer (surface, LastPage, -offset);
					}
					
					// fade out the edges during a slide
					Gradient linpat = new LinearGradient (0, surface.Height / 2, surface.Width, surface.Height / 2);
					linpat.AddColorStop (0, new Color(1, 1, 1, 1));
					linpat.AddColorStop (2 * (double) BUTTON_SIZE / surface.Width, new Color(1, 1, 1, 0));
					linpat.AddColorStop (1 - 2 * (double) BUTTON_SIZE / surface.Width, new Color(1, 1, 1, 0));
					linpat.AddColorStop (1, new Color(1, 1, 1, 1));
						
					surface.Context.Save ();
					surface.Context.Operator = Operator.Source;
					surface.Context.Color = new Cairo.Color (0, 0, 0, 0);
					surface.Context.Mask (linpat);
					surface.Context.PaintWithAlpha (0);
					surface.Context.Restore ();
					linpat.Destroy ();
				} else {
					ShowBuffer (surface, Page, 0);
				}
			}
			
			// overlay the prev/next arrow buttons
			if (buttonBuffer != null && (buttonBuffer.Width != surface.Width || buttonBuffer.Height != surface.Height))
				ResetButtons ();
			
			if (buttonBuffer == null) {
				buttonBuffer = new DockySurface (surface.Width, surface.Height, surface);
				DrawButtonsBuffer ();
			}
			
			buttonBuffer.Internal.Show (surface.Context, 0, 0);
		}
		DockySurface CreateUrgentGlowBuffer ()
		{
			// FIXME: create gconf value
			Gdk.Color gdkColor = Style.Backgrounds [(int) StateType.Selected].SetMinimumValue (90);
			Cairo.Color color = new Cairo.Color ((double) gdkColor.Red / ushort.MaxValue,
											(double) gdkColor.Green / ushort.MaxValue,
											(double) gdkColor.Blue / ushort.MaxValue,
											1.0);
			color = color.AddHue (DockServices.Theme.UrgentHueShift).SetSaturation (1);
			
			int size = (int) 2.5 * IconSize;
			
			DockySurface surface = new DockySurface (size, size, background_buffer);
			surface.Clear ();
			
			Cairo.Context cr = surface.Context;
			
			double x = size / 2;
			double y = x;
				
			cr.MoveTo (x, y);
			cr.Arc (x, y, size / 2, 0, Math.PI * 2);
				
			RadialGradient rg = new RadialGradient (x, y, 0, x, y, size / 2);
			rg.AddColorStop (0, new Cairo.Color (1, 1, 1, 1));
			rg.AddColorStop (.33, color.SetAlpha (.66));
			rg.AddColorStop (.66, color.SetAlpha (.33));
			rg.AddColorStop (1.0, color.SetAlpha (0.0));
			
			cr.Pattern = rg;
			cr.Fill ();
			rg.Destroy ();
			
			return surface;
		}
		DockySurface CreateWaitBuffer ()
		{
			DockySurface surface = new DockySurface (IconSize, IconSize, background_buffer);
			surface.Clear ();
			
			surface.Context.Color = new Cairo.Color (0, 0, 0, 0);
			surface.Context.Operator = Operator.Source;
			surface.Context.PaintWithAlpha (0.5);
			
			double baseLog = Math.Log (WaitArmsPerGroup + 1);
			int size = Math.Min (surface.Width, surface.Height);
			
			// Ensure that LineWidth is a multiple of 2 for nice drawing
			surface.Context.LineWidth = (int) Math.Max (1, size / 40.0);
			surface.Context.LineCap = LineCap.Round;
			
			surface.Context.Translate (surface.Width / 2, surface.Height / 2);
			
			if (surface.Context.LineWidth % 2 == 1)
				surface.Context.Translate (.5, .5);
			
			Gdk.Color color = Style.Backgrounds [(int) Gtk.StateType.Selected].SetMinimumValue (100);
			Cairo.Color baseColor = new Cairo.Color ((double) color.Red / ushort.MaxValue,
										(double) color.Green / ushort.MaxValue,
										(double) color.Blue / ushort.MaxValue,
										1);
			
			for (int i = 0; i < WaitArmsPerGroup * WaitGroups; i++) {
				int position = 1 + (i % WaitArmsPerGroup);
				surface.Context.Color = baseColor.SetAlpha (1 - Math.Log (position) / baseLog);
				surface.Context.MoveTo (0, size / 8);
				surface.Context.LineTo (0, size / 4);
				surface.Context.Rotate (-2 * Math.PI / (WaitArmsPerGroup * WaitGroups));
				surface.Context.Stroke ();
			}
			
			return surface;
		}
		DockySurface CreateIndicatorBuffer (int size, Cairo.Color color)
		{
			DockySurface surface = new DockySurface (size, size, background_buffer);
			surface.Clear ();
			
			Cairo.Context cr = surface.Context;
			
			double x = size / 2;
			double y = x;
				
			cr.MoveTo (x, y);
			cr.Arc (x, y, size / 2, 0, Math.PI * 2);
				
			RadialGradient rg = new RadialGradient (x, y, 0, x, y, size / 2);
			rg.AddColorStop (0, new Cairo.Color (1, 1, 1, 1));
			rg.AddColorStop (.10, color.SetAlpha (1.0));
			rg.AddColorStop (.20, color.SetAlpha (.60));
			rg.AddColorStop (.25, color.SetAlpha (.25));
			rg.AddColorStop (.50, color.SetAlpha (.15));
			rg.AddColorStop (1.0, color.SetAlpha (0.0));
			
			cr.Pattern = rg;
			cr.Fill ();
			rg.Destroy ();
			
			return surface;
		}
		void DrawDock (DockySurface surface)
		{
			surface.Clear ();
			
			UpdateDrawRegionsForSurface (surface);
			
			Gdk.Rectangle dockArea, cursorArea;
			GetDockAreaOnSurface (surface, out dockArea, out cursorArea);
			
			if (Preferences.PanelMode) {
				Gdk.Rectangle panelArea = dockArea;
				if (PanelModeToggleProgress == 1) {
					if (Preferences.IsVertical) {
						panelArea.Y = -100;
						panelArea.Height = Height + 200;
					} else {
						panelArea.X = -100;
						panelArea.Width = Width + 200;
					}
				}
				DrawDockBackground (surface, panelArea);
			} else {
				DrawDockBackground (surface, dockArea);
			}
				
			double painterVisibility = PainterOpacity;
			if (painterVisibility < 1) {
			
				if (icon_buffer == null || icon_buffer.Width != surface.Width || icon_buffer.Height != surface.Height) {
					if (icon_buffer != null)
						icon_buffer.Dispose ();
					icon_buffer = new DockySurface (surface.Width, surface.Height, surface);
				}
				
				icon_buffer.Clear ();
				foreach (AbstractDockItem adi in Items)
					DrawItem (icon_buffer, dockArea, adi);
			
				surface.Context.SetSource (icon_buffer.Internal, 0, 0);
				surface.Context.PaintWithAlpha (1 - painterVisibility);
			
			} 
			
			if (Painter != null && painterVisibility > 0)
				DrawPainter (surface, dockArea);
			
			if (ActiveGlow) {
				Gdk.Color color = Style.BaseColors[(int) Gtk.StateType.Selected];
				
				Gdk.Rectangle extents;
				using (DockySurface tmp = surface.CreateMask (0, out extents)) {
					extents.Inflate (GlowSize * 2, GlowSize * 2);
					tmp.ExponentialBlur (GlowSize, extents);
					tmp.Context.Color = new Cairo.Color (
						(double) color.Red / ushort.MaxValue, 
						(double) color.Green / ushort.MaxValue, 
						(double) color.Blue / ushort.MaxValue, 
						.90).SetValue (1).MultiplySaturation (4);
					tmp.Context.Operator = Operator.Atop;
					tmp.Context.Paint ();
				
					surface.Context.Operator = Operator.DestOver;
					surface.Context.SetSource (tmp.Internal);
					surface.Context.Paint ();
					surface.Context.Operator = Operator.Over;
				}
			}
			
			if (DockOpacity < 1)
				SetDockOpacity (surface);
			
			// Draw UrgentGlow which is visible when Docky is hidden and an item need attention
			if (AutohideManager.Hidden && !ConfigurationMode && (!Preferences.FadeOnHide || Preferences.FadeOpacity == 0)) {
				foreach (AbstractDockItem adi in Items) {
					double diff = (render_time - adi.StateSetTime (ItemState.Urgent)).TotalMilliseconds;
					if (adi.Indicator != ActivityIndicator.None && (adi.State & ItemState.Urgent) == ItemState.Urgent &&
					    (DockServices.Theme.GlowTime.Days > 0 || diff < DockServices.Theme.GlowTime.TotalMilliseconds)) {
						
						if (urgent_glow_buffer == null)
							urgent_glow_buffer = CreateUrgentGlowBuffer ();
		
						DrawValue val = DrawValues [adi];
						DrawValue glowloc;
						if (Preferences.FadeOnHide)
							glowloc = val.MoveIn (Position, -urgent_glow_buffer.Height / 2 + DockHeightBuffer);
						else
							glowloc = val.MoveIn (Position, -urgent_glow_buffer.Height / 2 + DockHeightBuffer + ZoomedDockHeight);

						double opacity = 0.2 + (0.75 * (Math.Sin (diff / PulseTime.TotalMilliseconds * 2 * Math.PI) + 1) / 2);
						
						urgent_glow_buffer.ShowWithOptions (surface, glowloc.Center, 1, 0, opacity);
					}
				}
			}
			
			SetInputMask (cursorArea);
			
			Gdk.Rectangle staticArea = StaticDockArea (surface);
			staticArea.X += window_position.X;
			staticArea.Y += window_position.Y;
			staticArea.Intersect (monitor_geo);
			AutohideManager.SetIntersectArea (staticArea);
			
			cursorArea.X += window_position.X;
			cursorArea.Y += window_position.Y;
			AutohideManager.SetCursorArea (cursorArea);
		}