Index: Tomboy/Addins/PrintNotes/PrintNotesNoteAddin.cs
===================================================================
--- Tomboy/Addins/PrintNotes/PrintNotesNoteAddin.cs	(revision 2302)
+++ Tomboy/Addins/PrintNotes/PrintNotesNoteAddin.cs	(working copy)
@@ -1,49 +1,238 @@
-
 using System;
-using System.Runtime.InteropServices;
+using System.Collections.Generic;
 using Mono.Unix;
 
-using Gtk;
-
-using Tomboy;
-
 namespace Tomboy.PrintNotes
 {
 	public class PrintNotesNoteAddin : NoteAddin
 	{
-		Gtk.ImageMenuItem item;
-
+		private Gtk.ImageMenuItem item;	
+		private List<int> page_breaks;
+		private Pango.Layout layout;
+	
 		public override void Initialize ()
-		{
+		{	
 		}
 
 		public override void Shutdown ()
 		{
-			// Disconnect the event handlers so
-			// there aren't any memory leaks.
 			if (item != null)
-				item.Activated -= PrintButtonClicked;
+				item.Activated -= PrintButtonClicked;			
 		}
-
+		
 		public override void OnNoteOpened ()
 		{
 			item = new Gtk.ImageMenuItem (Catalog.GetString ("Print"));
 			item.Image = new Gtk.Image (Gtk.Stock.Print, Gtk.IconSize.Menu);
-			item.Activated += PrintButtonClicked;
+			item.Activated += PrintButtonClicked;			
+			item.AddAccelerator ("activate", Window.AccelGroup,
+				(uint) Gdk.Key.p, Gdk.ModifierType.ControlMask,
+				Gtk.AccelFlags.Visible);
 			item.Show ();
 			AddPluginMenuItem (item);
+		}	
+
+		private void PrintButtonClicked (object sender, EventArgs args)
+		{
+			Gtk.PrintOperation op = new Gtk.PrintOperation ();
+			op.JobName = Note.Title;
+
+			op.BeginPrint += OnBeginPrint;
+			op.DrawPage += OnDrawPage;
+			op.EndPrint += OnEndPrint;
+			
+			op.Run (Gtk.PrintOperationAction.PrintDialog, Window);
 		}
 
-		[DllImport("libprintnotes")]
-		static extern void gedit_print (IntPtr text_view_handle);
+		private Pango.FontDescription GetFontDescription ()
+		{
+			if ((bool) Preferences.Get ((Preferences.ENABLE_CUSTOM_FONT)))
+			{
+				string font_string = (string) Preferences.Get (Preferences.CUSTOM_FONT_FACE);
+				return Pango.FontDescription.FromString (font_string);
+			}
+			return Window.Editor.Style.FontDesc;
+		}		
 
-		//
-		// Handle Print menu item Click
-		//
+		private static IEnumerable<Pango.Attribute> GetSegmentAttributes (ref Gtk.TextIter iter, Gtk.TextIter limit)
+		{
+			IList<Pango.Attribute> attributes = new List<Pango.Attribute> ();
 
-		void PrintButtonClicked (object sender, EventArgs args)
+			Gtk.TextTag [] tags = iter.Tags;
+			iter.ForwardToTagToggle (null);
+
+			if (iter.Compare (limit) > 0) iter = limit;
+
+			foreach (Gtk.TextTag tag in tags)
+			{
+				if (!(tag is NoteTag)) continue;
+
+				if (tag.BackgroundSet)
+				{
+					Gdk.Color color = tag.BackgroundGdk;
+					attributes.Add (new Pango.AttrBackground (color.Red, color.Green, color.Blue));
+				}
+				if (tag.ForegroundSet)
+				{
+					Gdk.Color color = tag.ForegroundGdk;
+					attributes.Add (new Pango.AttrForeground (color.Red, color.Green, color.Blue));
+				}
+				if (tag.FontDesc != null)
+				{
+					attributes.Add (new Pango.AttrFontDesc (tag.FontDesc));
+				}
+				if (tag.FamilySet)
+				{
+					attributes.Add (new Pango.AttrFamily (tag.Family));
+				}
+				if (tag.SizeSet)
+				{
+					attributes.Add (new Pango.AttrSize (tag.Size));
+				}				
+				if (tag.StyleSet)
+				{
+					attributes.Add (new Pango.AttrStyle (tag.Style));
+				}
+				if (tag.UnderlineSet)
+				{
+					attributes.Add (new Pango.AttrUnderline (tag.Underline));
+				}
+				if (tag.WeightSet)
+				{
+					attributes.Add (new Pango.AttrWeight (tag.Weight));
+				}
+				if (tag.StrikethroughSet)
+				{
+					attributes.Add (new Pango.AttrStrikethrough (tag.Strikethrough));
+				}
+				if (tag.RiseSet)
+				{
+					attributes.Add (new Pango.AttrRise (tag.Rise));
+				}
+				if (tag.ScaleSet)
+				{
+					attributes.Add (new Pango.AttrScale (tag.Scale));
+				}
+				if (tag.StretchSet)
+				{
+					attributes.Add (new Pango.AttrStretch(tag.Stretch));
+				}
+			}
+
+			return attributes;
+		}
+
+		private static Pango.AttrList LayoutParagraph (Pango.AttrList attr_list, Gtk.TextIter line_start, Gtk.TextIter line_end)
+		{			
+			if (attr_list == null)
+				attr_list = new Pango.AttrList ();
+
+			Gtk.TextIter segm_start = line_start;
+			Gtk.TextIter segm_end;
+
+			while (segm_start.Compare (line_end) < 0)
+			{
+				segm_end = segm_start;
+				IEnumerable<Pango.Attribute> attrs = GetSegmentAttributes (ref segm_end, line_end);
+				foreach (Pango.Attribute a in attrs)
+				{
+					a.StartIndex = (uint)segm_start.Offset;
+					a.EndIndex = (uint)segm_end.Offset;
+					attr_list.Insert (a);
+				}				
+				segm_start = segm_end;
+			}
+			return attr_list;
+		}
+
+		private void OnBeginPrint (object sender, Gtk.BeginPrintArgs args)
+		{						
+			Gtk.PrintContext context = args.Context;
+			layout = context.CreatePangoLayout ();
+			layout.Width = Pango.Units.FromDouble (context.Width);
+
+			layout.FontDescription = GetFontDescription ();			
+
+			Gtk.TextIter start_iter;
+			Gtk.TextIter end_iter;
+			Buffer.GetBounds (out start_iter, out end_iter);
+
+			layout.SetText (Buffer.GetSlice (start_iter, end_iter, false));			
+
+			double height = Pango.Units.FromDouble (context.Height);			
+			double page_height = 0;
+
+			page_breaks = new List<int> ();
+
+			bool done = start_iter.Compare(end_iter) >= 0;
+			while (!done)
+			{
+				int line_number = start_iter.Line;
+				Pango.Rectangle ink_rect = Pango.Rectangle.Zero;
+				Pango.Rectangle logical_rect = Pango.Rectangle.Zero;
+
+				Gtk.TextIter line_end = start_iter;
+				if (!line_end.EndsLine ())
+					line_end.ForwardToLineEnd ();
+
+				layout.Attributes = LayoutParagraph (layout.Attributes, start_iter, line_end);				
+				Pango.LayoutLine layout_line = layout.GetLine (line_number);
+				layout_line.GetExtents (ref ink_rect, ref logical_rect);
+
+				if (page_height + logical_rect.Height > height)
+				{
+					page_breaks.Add (line_number);
+					page_height = 0;
+				}
+				page_height += logical_rect.Height;
+
+				start_iter.ForwardLine ();
+				done = start_iter.Compare (end_iter) >= 0;
+			}
+						
+			Gtk.PrintOperation op = (Gtk.PrintOperation) sender;
+			op.NPages = page_breaks.Count + 1;
+		}
+		
+		public void OnDrawPage (object sender, Gtk.DrawPageArgs args)
 		{
-			gedit_print (Note.Window.Editor.Handle);
+			Cairo.Context cr = args.Context.CairoContext;
+			cr.MoveTo(0, 0);
+
+			int start = 0;
+			if (args.PageNr != 0)
+				start = page_breaks [args.PageNr - 1];
+
+			int end;
+			if (page_breaks.Count <= args.PageNr)
+				end = layout.LineCount;
+			else
+				end = page_breaks [args.PageNr];
+
+			int line_count = layout.LineCount;
+			for (int line_number = start; line_number < end && line_number < line_count; line_number++)
+			{
+				Pango.LayoutLine line = layout.Lines [line_number];
+				Pango.Rectangle logicalRect = Pango.Rectangle.Zero;
+				Pango.Rectangle dummyRect = Pango.Rectangle.Zero;
+
+				line.GetExtents (ref dummyRect, ref logicalRect);
+
+				int line_height = (int) (logicalRect.Height /
+					       Pango.Scale.PangoScale);
+
+				Cairo.PointD new_line_point = new Cairo.PointD(
+					0, cr.CurrentPoint.Y + line_height);
+				Pango.CairoHelper.ShowLayoutLine (cr, line);
+				cr.MoveTo (new_line_point);
+			}			
 		}
+		
+		private void OnEndPrint (object sender, Gtk.EndPrintArgs args)
+		{
+			layout.Dispose ();
+			layout = null;
+			page_breaks.Clear ();			
+		}
 	}
-}
+}
\ No newline at end of file
