public void OnDrawPage (object sender, Gtk.DrawPageArgs args)
		{
			using (Cairo.Context cr = args.Context.CairoContext) {
				cr.MoveTo (margin_left, margin_top);

				PageBreak start;
				if (args.PageNr == 0) {
					start = new PageBreak (0, 0);
				} else {
					start = page_breaks [args.PageNr - 1];
				}				

				PageBreak end;			
				if (args.PageNr < page_breaks.Count) {
					end = page_breaks [args.PageNr];
				} else {
					end = new PageBreak (-1, -1);
				}

				Gtk.PrintContext context = args.Context;
				Gtk.TextIter position;
				Gtk.TextIter end_iter;
				Buffer.GetBounds (out position, out end_iter);

				// Fast-forward to the right starting paragraph
				while (position.Line < start.Paragraph) {
					position.ForwardLine ();
				}
				
				bool done = position.Compare (end_iter) >= 0;
				while (!done) {
					Gtk.TextIter line_end = position;
					if (!line_end.EndsLine ())
						line_end.ForwardToLineEnd ();

					int paragraph_number = position.Line;
					int indentation;
					using (Pango.Layout layout = CreateParagraphLayout (
						context, position, line_end, out indentation)) {
						
						for (int line_number = 0;
						     line_number < layout.LineCount && !done;
						     line_number++) {
							// Skip the lines up to the starting line in the
							// first paragraph on this page
							if ((paragraph_number == start.Paragraph) &&
							    (line_number < start.Line)) {
								continue;
							}

							// Break as soon as we hit the end line
							if ((paragraph_number == end.Paragraph) &&
							    (line_number == end.Line)) {
								done = true;
								break;
							}

							Pango.LayoutLine line = layout.Lines [line_number];
							Pango.Rectangle ink_rect = Pango.Rectangle.Zero;
							Pango.Rectangle logical_rect = Pango.Rectangle.Zero;
							line.GetExtents (ref ink_rect, ref logical_rect);
		
							cr.MoveTo (margin_left + indentation,
								cr.CurrentPoint.Y);
							int line_height = Pango.Units.ToPixels (logical_rect.Height);
							
							Cairo.PointD new_line_point = new Cairo.PointD (
								margin_left + indentation,
								cr.CurrentPoint.Y + line_height);
							
							Pango.CairoHelper.ShowLayoutLine (cr, line);
							cr.MoveTo (new_line_point);
						}
					}
	
					position.ForwardLine ();
					done = done || position.Compare (end_iter) >= 0;
				}				

				int total_height = (int) args.Context.Height;
				int total_width = (int) args.Context.Width; 
				int footer_height = 0;

				Cairo.PointD footer_anchor;
				using (Pango.Layout pages_footer = CreatePagenumbersLayout (
					args.Context, args.PageNr + 1, page_breaks.Count + 1)) {
					Pango.Rectangle ink_footer_rect;
					Pango.Rectangle logical_footer_rect;
					pages_footer.GetExtents (out ink_footer_rect, out logical_footer_rect);

					footer_anchor = new Cairo.PointD (
						CmToPixel (0.5, args.Context.DpiX),
						total_height - margin_bottom);
					footer_height = Pango.Units.ToPixels (logical_footer_rect.Height);
					
					cr.MoveTo (
				           total_width - Pango.Units.ToPixels (logical_footer_rect.Width) -
				           CmToPixel (0.5, args.Context.DpiX),
				           footer_anchor.Y);
				
					Pango.CairoHelper.ShowLayoutLine (cr, pages_footer.Lines [0]);
				}
				
				cr.MoveTo (footer_anchor);
				Pango.CairoHelper.ShowLayoutLine (cr, timestamp_footer.Lines [0]);
				
				cr.MoveTo (CmToPixel (0.5, args.Context.DpiX),
				           total_height - margin_bottom - footer_height);
				cr.LineTo (total_width - CmToPixel (0.5, args.Context.DpiX),
				           total_height - margin_bottom - footer_height);
				cr.Stroke ();
			}
		}
        public void OnDrawPage(object sender, Gtk.DrawPageArgs args)
        {
            using (Cairo.Context cr = args.Context.CairoContext) {
                cr.MoveTo(margin_left, margin_top);

                PageBreak start;
                if (args.PageNr == 0)
                {
                    start = new PageBreak(0, 0);
                }
                else
                {
                    start = page_breaks [args.PageNr - 1];
                }

                PageBreak end;
                if (args.PageNr < page_breaks.Count)
                {
                    end = page_breaks [args.PageNr];
                }
                else
                {
                    end = new PageBreak(-1, -1);
                }

                Gtk.PrintContext context = args.Context;
                Gtk.TextIter     position;
                Gtk.TextIter     end_iter;
                Buffer.GetBounds(out position, out end_iter);

                // Fast-forward to the right starting paragraph
                while (position.Line < start.Paragraph)
                {
                    position.ForwardLine();
                }

                bool done = position.Compare(end_iter) >= 0;
                while (!done)
                {
                    Gtk.TextIter line_end = position;
                    if (!line_end.EndsLine())
                    {
                        line_end.ForwardToLineEnd();
                    }

                    int paragraph_number = position.Line;
                    int indentation;
                    using (Pango.Layout layout = CreateParagraphLayout(
                               context, position, line_end, out indentation)) {
                        for (int line_number = 0;
                             line_number < layout.LineCount && !done;
                             line_number++)
                        {
                            // Skip the lines up to the starting line in the
                            // first paragraph on this page
                            if ((paragraph_number == start.Paragraph) &&
                                (line_number < start.Line))
                            {
                                continue;
                            }

                            // Break as soon as we hit the end line
                            if ((paragraph_number == end.Paragraph) &&
                                (line_number == end.Line))
                            {
                                done = true;
                                break;
                            }

                            Pango.LayoutLine line         = layout.Lines [line_number];
                            Pango.Rectangle  ink_rect     = Pango.Rectangle.Zero;
                            Pango.Rectangle  logical_rect = Pango.Rectangle.Zero;
                            line.GetExtents(ref ink_rect, ref logical_rect);

                            cr.MoveTo(margin_left + indentation,
                                      cr.CurrentPoint.Y);
                            int line_height = Pango.Units.ToPixels(logical_rect.Height);

                            Cairo.PointD new_line_point = new Cairo.PointD(
                                margin_left + indentation,
                                cr.CurrentPoint.Y + line_height);

                            Pango.CairoHelper.ShowLayoutLine(cr, line);
                            cr.MoveTo(new_line_point);
                        }
                    }

                    position.ForwardLine();
                    done = done || position.Compare(end_iter) >= 0;
                }

                int total_height  = (int)args.Context.Height;
                int total_width   = (int)args.Context.Width;
                int footer_height = 0;

                Cairo.PointD footer_anchor;
                using (Pango.Layout pages_footer = CreatePagenumbersLayout(
                           args.Context, args.PageNr + 1, page_breaks.Count + 1)) {
                    Pango.Rectangle ink_footer_rect;
                    Pango.Rectangle logical_footer_rect;
                    pages_footer.GetExtents(out ink_footer_rect, out logical_footer_rect);

                    footer_anchor = new Cairo.PointD(
                        CmToPixel(0.5, args.Context.DpiX),
                        total_height - margin_bottom);
                    footer_height = Pango.Units.ToPixels(logical_footer_rect.Height);

                    cr.MoveTo(
                        total_width - Pango.Units.ToPixels(logical_footer_rect.Width) -
                        CmToPixel(0.5, args.Context.DpiX),
                        footer_anchor.Y);

                    Pango.CairoHelper.ShowLayoutLine(cr, pages_footer.Lines [0]);
                }

                cr.MoveTo(footer_anchor);
                Pango.CairoHelper.ShowLayoutLine(cr, timestamp_footer.Lines [0]);

                cr.MoveTo(CmToPixel(0.5, args.Context.DpiX),
                          total_height - margin_bottom - footer_height);
                cr.LineTo(total_width - CmToPixel(0.5, args.Context.DpiX),
                          total_height - margin_bottom - footer_height);
                cr.Stroke();
            }
        }
		private void OnBeginPrint (object sender, Gtk.BeginPrintArgs args)
		{
			Gtk.PrintOperation op = (Gtk.PrintOperation) sender;			
			Gtk.PrintContext context = args.Context;
			timestamp_footer = CreateTimestampLayout (context);
			
			// FIXME: These should be configurable settings later (UI Change)
			margin_top = CmToPixel (1.5, context.DpiY);
			margin_left = CmToPixel (1, context.DpiX);
			margin_right = CmToPixel (1, context.DpiX);
			margin_bottom = 0;
			double max_height = Pango.Units.FromPixels ((int) context.Height - 
						margin_top - margin_bottom - ComputeFooterHeight (context));
			
			Gtk.TextIter position;
			Gtk.TextIter end_iter;
			Buffer.GetBounds (out position, out end_iter);

			double page_height = 0;
			bool done = position.Compare (end_iter) >= 0;
			while (!done) {
				Gtk.TextIter line_end = position;
				if (!line_end.EndsLine ())
					line_end.ForwardToLineEnd ();
				
				int paragraph_number = position.Line;
				int indentation;
				using (Pango.Layout layout = CreateParagraphLayout (
					context, position, line_end, out indentation)) {

					Pango.Rectangle ink_rect = Pango.Rectangle.Zero;
					Pango.Rectangle logical_rect = Pango.Rectangle.Zero;
					for (int line_in_paragraph = 0; line_in_paragraph < layout.LineCount;
					     line_in_paragraph++) {
						Pango.LayoutLine line = layout.GetLine (line_in_paragraph);
						line.GetExtents (ref ink_rect, ref logical_rect);

						if (page_height + logical_rect.Height >= max_height) {
							PageBreak page_break = new PageBreak (
								paragraph_number, line_in_paragraph);
							page_breaks.Add (page_break);
	
							page_height = 0;
						}
						page_height += logical_rect.Height;
					}

					position.ForwardLine ();
					done = position.Compare (end_iter) >= 0;
				}
			}

			op.NPages = page_breaks.Count + 1;
		}