2008-10-09 [colin] 3.6.0cvs20
authorColin Leroy <colin@colino.net>
Thu, 9 Oct 2008 17:02:02 +0000 (17:02 +0000)
committerColin Leroy <colin@colino.net>
Thu, 9 Oct 2008 17:02:02 +0000 (17:02 +0000)
* configure.ac
* src/Makefile.am
* src/crash.c
* src/gedit-print.c
* src/gedit-print.h
* src/main.c
* src/mainwindow.c
* src/messageview.c
* src/prefs_ext_prog.c
* src/prefs_fonts.c
* src/prefs_image_viewer.c
* src/printing.c
* src/printing.h
* src/summaryview.c
* src/gtk/Makefile.am
* src/gtk/about.c
* src/gtk/gtksourceprintjob.c
* src/gtk/gtksourceprintjob.h
Revert previous patch. It'd be better to remove
OpenSSL instead, as GnuTLS works as well.

20 files changed:
ChangeLog
PATCHSETS
configure.ac
src/Makefile.am
src/crash.c
src/gedit-print.c [new file with mode: 0644]
src/gedit-print.h [new file with mode: 0644]
src/gtk/Makefile.am
src/gtk/about.c
src/gtk/gtksourceprintjob.c [new file with mode: 0644]
src/gtk/gtksourceprintjob.h [new file with mode: 0644]
src/main.c
src/mainwindow.c
src/messageview.c
src/prefs_ext_prog.c
src/prefs_fonts.c
src/prefs_image_viewer.c
src/printing.c
src/printing.h
src/summaryview.c

index 9a94751..ade8b3e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,26 @@
+2008-10-09 [colin]     3.6.0cvs20
+
+       * configure.ac
+       * src/Makefile.am
+       * src/crash.c
+       * src/gedit-print.c
+       * src/gedit-print.h
+       * src/main.c
+       * src/mainwindow.c
+       * src/messageview.c
+       * src/prefs_ext_prog.c
+       * src/prefs_fonts.c
+       * src/prefs_image_viewer.c
+       * src/printing.c
+       * src/printing.h
+       * src/summaryview.c
+       * src/gtk/Makefile.am
+       * src/gtk/about.c
+       * src/gtk/gtksourceprintjob.c
+       * src/gtk/gtksourceprintjob.h
+               Revert previous patch. It'd be better to remove
+               OpenSSL instead, as GnuTLS works as well.
+
 2008-10-09 [colin]     3.6.0cvs19
 
        * configure.ac
index ea09b56..e3d2f4f 100644 (file)
--- a/PATCHSETS
+++ b/PATCHSETS
 ( cvs diff -u -r 1.1.4.56 -r 1.1.4.57 src/prefs_filtering_action.c;  cvs diff -u -r 1.43.2.77 -r 1.43.2.78 src/prefs_matcher.c;  ) > 3.6.0cvs17.patchset
 ( cvs diff -u -r 1.654.2.3637 -r 1.654.2.3638 configure.ac;  ) > 3.6.0cvs18.patchset
 ( cvs diff -u -r 1.654.2.3638 -r 1.654.2.3639 configure.ac;  cvs diff -u -r 1.155.2.91 -r 1.155.2.92 src/Makefile.am;  cvs diff -u -r 1.23.2.30 -r 1.23.2.31 src/crash.c;  cvs diff -u -r -1.1.2.11 -r -1.1.2.12 src/gedit-print.c;  cvs diff -u -r -1.1.2.4 -r -1.1.2.5 src/gedit-print.h;  cvs diff -u -r 1.115.2.210 -r 1.115.2.211 src/main.c;  cvs diff -u -r 1.274.2.282 -r 1.274.2.283 src/mainwindow.c;  cvs diff -u -r 1.94.2.189 -r 1.94.2.190 src/messageview.c;  cvs diff -u -r 1.3.2.21 -r 1.3.2.22 src/prefs_ext_prog.c;  cvs diff -u -r 1.4.2.22 -r 1.4.2.23 src/prefs_fonts.c;  cvs diff -u -r 1.1.2.11 -r 1.1.2.12 src/prefs_image_viewer.c;  cvs diff -u -r 1.1.2.16 -r 1.1.2.17 src/printing.c;  cvs diff -u -r 1.1.2.4 -r 1.1.2.5 src/printing.h;  cvs diff -u -r 1.395.2.395 -r 1.395.2.396 src/summaryview.c;  cvs diff -u -r 1.20.2.18 -r 1.20.2.19 src/gtk/Makefile.am;  cvs diff -u -r 1.4.2.67 -r 1.4.2.68 src/gtk/about.c;  cvs diff -u -r -1.1.2.9 -r -1.1.2.10 src/gtk/gtksourceprintjob.c;  cvs diff -u -r -1.1.2.3 -r -1.1.2.4 src/gtk/gtksourceprintjob.h;  ) > 3.6.0cvs19.patchset
+( cvs diff -u -r 1.654.2.3639 -r 1.654.2.3640 configure.ac;  cvs diff -u -r 1.155.2.92 -r 1.155.2.93 src/Makefile.am;  cvs diff -u -r 1.23.2.31 -r 1.23.2.32 src/crash.c;  diff -u /dev/null src/gedit-print.c;  diff -u /dev/null src/gedit-print.h;  cvs diff -u -r 1.115.2.211 -r 1.115.2.212 src/main.c;  cvs diff -u -r 1.274.2.283 -r 1.274.2.284 src/mainwindow.c;  cvs diff -u -r 1.94.2.190 -r 1.94.2.191 src/messageview.c;  cvs diff -u -r 1.3.2.22 -r 1.3.2.23 src/prefs_ext_prog.c;  cvs diff -u -r 1.4.2.23 -r 1.4.2.24 src/prefs_fonts.c;  cvs diff -u -r 1.1.2.12 -r 1.1.2.13 src/prefs_image_viewer.c;  cvs diff -u -r 1.1.2.17 -r 1.1.2.18 src/printing.c;  cvs diff -u -r 1.1.2.5 -r 1.1.2.6 src/printing.h;  cvs diff -u -r 1.395.2.396 -r 1.395.2.397 src/summaryview.c;  cvs diff -u -r 1.20.2.19 -r 1.20.2.20 src/gtk/Makefile.am;  cvs diff -u -r 1.4.2.68 -r 1.4.2.69 src/gtk/about.c;  diff -u /dev/null src/gtk/gtksourceprintjob.c;  diff -u /dev/null src/gtk/gtksourceprintjob.h;  ) > 3.6.0cvs20.patchset
index f153785..73a8005 100644 (file)
@@ -11,7 +11,7 @@ MINOR_VERSION=6
 MICRO_VERSION=0
 INTERFACE_AGE=0
 BINARY_AGE=0
-EXTRA_VERSION=19
+EXTRA_VERSION=20
 EXTRA_RELEASE=
 EXTRA_GTK2_VERSION=
 
@@ -980,6 +980,34 @@ AM_CONDITIONAL(CLAWS_LIBETPAN, test "x$libetpan_result" = "xyes")
 dnl Printing support.
 PKG_CHECK_MODULES(GTK210, gtk+-2.0 >= 2.10, ac_cv_have_gtk210=yes, ac_cv_have_gtk210=no)
 
+AC_MSG_CHECKING([whether to use libgnomeprint])
+AC_ARG_ENABLE(gnomeprint,
+       [  --disable-gnomeprint         disable libgnomeprint support],
+       [ac_cv_enable_gnomeprint=$enableval], [ac_cv_enable_gnomeprint=auto])
+
+if test x$ac_cv_have_gtk210 = xyes; then
+       ac_cv_enable_gnomeprint="no"
+fi
+
+if test x$ac_cv_enable_gnomeprint = xyes \
+       -o \( x$ac_cv_enable_gnomeprint = xauto \
+          -a x$ac_cv_have_gtk210 = xno \); then
+       AC_MSG_RESULT(yes)
+       PKG_CHECK_MODULES(GNOMEPRINT, libgnomeprint-2.2 libgnomeprintui-2.2,
+                         ac_cv_enable_gnomeprint=yes, ac_cv_enable_gnomeprint=no)
+       if test x"$ac_cv_enable_gnomeprint" = xyes; then
+               AC_DEFINE(USE_GNOMEPRINT, 1, Define if you want libgnomeprint support)
+       else
+               AC_MSG_RESULT(not found)
+               AC_MSG_WARN([*** libgnomeprintui wasn't found    ***])
+               AC_MSG_WARN([*** using built-in printing support ***])
+       fi
+else
+       ac_cv_enable_gnomeprint=no
+       AC_MSG_RESULT(no)
+fi
+AM_CONDITIONAL(CLAWS_GNOMEPRINT, test x"$ac_cv_enable_gnomeprint" = x"yes")
+
 AC_MSG_CHECKING([whether to use valgrind])
 AC_ARG_ENABLE(valgrind,
        [  --disable-valgrind           disable valgrind support for debugging],
@@ -1070,6 +1098,7 @@ echo "enchant           : $ac_cv_enable_enchant"
 echo "IMAP4             : $ac_cv_enable_libetpan"
 echo "NNTP              : $ac_cv_enable_libetpan"
 echo "Crash dialog      : $ac_cv_enable_crash_dialog"
+echo "Libgnomeprint     : $ac_cv_enable_gnomeprint"
 echo "GTK+ print support: $ac_cv_have_gtk210"
 echo "LibSM             : $ac_cv_enable_libsm"
 echo "DBUS              : $enable_dbus"
index f2a57ff..a7fb69c 100644 (file)
@@ -76,6 +76,7 @@ claws_mail_SOURCES = \
        foldersel.c \
        folderutils.c \
        folderview.c \
+       gedit-print.c \
        grouplistdialog.c \
        headerview.c \
        html.c \
@@ -224,6 +225,7 @@ claws_mailinclude_HEADERS = \
        foldersel.h \
        folderutils.h \
        folderview.h \
+       gedit-print.h \
        grouplistdialog.h \
        headerview.h \
        html.h \
@@ -522,6 +524,7 @@ claws_mail_LDADD = \
        $(COMPFACE_LIBS) \
        $(JPILOT_LIBS) \
        $(PTHREAD_LIBS) \
+       $(GNOMEPRINT_LIBS) \
        $(SM_LIBS) \
        $(LIBICONV) \
        $(STARTUP_NOTIFICATION_LIBS) \
@@ -545,6 +548,7 @@ AM_CPPFLAGS = \
        $(GTK_CFLAGS) \
        $(GPGME_CFLAGS) \
        $(OPENSSL_CFLAGS) \
+       $(GNOMEPRINT_CFLAGS) \
        $(LIBETPAN_CPPFLAGS) \
        $(STARTUP_NOTIFICATION_CFLAGS) \
        $(MAEMO_CFLAGS) \
index b7e439e..70705b3 100644 (file)
@@ -433,6 +433,9 @@ static const gchar *get_compiled_in_features(void)
 #if HAVE_LIBETPAN
                   " libetpan"
 #endif
+#if USE_GNOMEPRINT
+                  " libgnomeprint"
+#endif
 #if HAVE_LIBSM
                   " libSM"
 #endif
diff --git a/src/gedit-print.c b/src/gedit-print.c
new file mode 100644 (file)
index 0000000..4592fd2
--- /dev/null
@@ -0,0 +1,463 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * gedit-print.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
+ * Copyright (C) 2002  Paolo Maggi  
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*
+ * Modified by the gedit Team, 1998-2002. See the AUTHORS file for a 
+ * list of people on the gedit Team.  
+ * See the ChangeLog files for a list of changes. 
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef USE_GNOMEPRINT
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>    /* For strlen */
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <libgnomeprintui/gnome-print-dialog.h>
+#include <libgnomeprintui/gnome-print-job-preview.h>
+
+#include "gedit-print.h"
+#include "gtk/gtksourceprintjob.h"
+#include "mainwindow.h"
+#include "prefs_common.h"
+
+#ifdef DEBUG
+#  define DEBUG_PRINT "DEBUG_PRINT: %s"
+#  define gedit_debug(x, y) g_warning(x, y)
+#else
+#  define gedit_debug(x, y) do {} while (FALSE);
+#endif
+
+enum
+{
+       PREVIEW_NO,
+       PREVIEW,
+       PREVIEW_FROM_DIALOG
+};
+
+typedef struct _GeditPrintJobInfo      GeditPrintJobInfo;
+
+struct _GeditPrintJobInfo 
+{
+       GtkTextBuffer     *doc;
+       
+       GtkSourcePrintJob *pjob;
+               
+       gint               preview;
+
+       gint               range_type;
+
+       gint               first_line_to_print;
+       gint               last_line_to_print;
+
+       /* Popup dialog */
+       GtkWidget         *dialog;
+       GtkWidget         *label;
+       GtkWidget         *progressbar;
+
+       GtkWindow         *parent;
+       gboolean           done;
+};
+
+static GeditPrintJobInfo* gedit_print_job_info_new     (GtkTextView       *view);
+static void gedit_print_job_info_destroy               (GeditPrintJobInfo *pji, 
+                                                        gboolean           save_config);
+static void gedit_print_real                           (GeditPrintJobInfo *pji, 
+                                                        GtkTextIter       *start, 
+                                                        GtkTextIter       *end, 
+                                                        GtkWindow         *parent);
+static void gedit_print_preview_real                   (GeditPrintJobInfo *pji, 
+                                                        GtkTextIter       *start, 
+                                                        GtkTextIter       *end, 
+                                                        GtkWindow         *parent);
+
+
+static void
+gedit_print_job_info_destroy (GeditPrintJobInfo *pji, gboolean save_config)
+{
+       gedit_debug (DEBUG_PRINT, "");
+
+       g_return_if_fail (pji != NULL);
+
+       if (pji->pjob != NULL)
+               g_object_unref (pji->pjob);
+
+       g_free (pji);
+}
+
+static GtkWidget *
+get_print_dialog (GeditPrintJobInfo *pji, GtkWindow *parent)
+{
+       GtkWidget *dialog;
+       gint selection_flag;
+       gint lines;
+       GnomePrintConfig *config;
+
+       gedit_debug (DEBUG_PRINT, "");
+
+       g_return_val_if_fail (pji != NULL, NULL);
+       
+       if (!gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (pji->doc), NULL, NULL))
+               selection_flag = GNOME_PRINT_RANGE_SELECTION_UNSENSITIVE;
+       else
+               selection_flag = GNOME_PRINT_RANGE_SELECTION;
+       
+       g_return_val_if_fail(pji->pjob != NULL, NULL);
+       config = gtk_source_print_job_get_config (pji->pjob);
+       
+       dialog = g_object_new (GNOME_TYPE_PRINT_DIALOG, "print_config", config, NULL);
+       
+       gnome_print_dialog_construct (GNOME_PRINT_DIALOG (dialog), 
+                                     _("Print"),
+                                     GNOME_PRINT_DIALOG_RANGE | GNOME_PRINT_DIALOG_COPIES);
+
+       lines = gtk_text_buffer_get_line_count (GTK_TEXT_BUFFER (pji->doc));
+
+       gnome_print_dialog_construct_range_any ( GNOME_PRINT_DIALOG (dialog),
+                                                (GNOME_PRINT_RANGE_ALL | selection_flag), 
+                                                NULL, NULL, NULL);
+
+       gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
+
+       gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); 
+       gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
+
+       return dialog;
+}
+
+static void
+gedit_print_dialog_response (GtkWidget *dialog, int response, GeditPrintJobInfo *pji)
+{
+       GtkTextIter start, end;
+
+       pji->range_type = gnome_print_dialog_get_range (GNOME_PRINT_DIALOG (dialog));
+       gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (pji->doc), &start, &end);
+
+       switch (pji->range_type)
+       {
+       case GNOME_PRINT_RANGE_ALL:
+               break;
+
+       case GNOME_PRINT_RANGE_SELECTION:
+               gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (pji->doc),
+                                                     &start, &end);
+               break;
+
+       default:
+               g_return_if_reached ();
+       }
+
+       switch (response)
+       {
+       case GNOME_PRINT_DIALOG_RESPONSE_PRINT:
+               gedit_debug (DEBUG_PRINT, "Print button pressed.");
+               pji->preview = PREVIEW_NO;
+               gedit_print_real (pji, &start, &end, 
+                                 gtk_window_get_transient_for (GTK_WINDOW (dialog)));
+               gtk_widget_destroy (dialog);
+               break;
+
+       case GNOME_PRINT_DIALOG_RESPONSE_PREVIEW:
+               gedit_debug (DEBUG_PRINT, "Preview button pressed.");
+               pji->preview = PREVIEW_FROM_DIALOG;
+               gedit_print_preview_real (pji, &start, &end, GTK_WINDOW (dialog));
+               break;
+
+       default:
+               gtk_widget_destroy (dialog);
+               pji->done = TRUE;
+        }
+} 
+
+static void
+show_printing_dialog (GeditPrintJobInfo *pji, GtkWindow *parent)
+{
+       GtkWidget *window;
+       GtkWidget *frame;
+       GtkWidget *hbox;
+       GtkWidget *image;
+       GtkWidget *vbox;
+       GtkWidget *label;
+       GtkWidget *progressbar;
+
+       window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "gedit-print");
+       gtk_window_set_modal (GTK_WINDOW (window), TRUE);
+       gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
+       gtk_window_set_destroy_with_parent (GTK_WINDOW (window), TRUE);
+       gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER_ON_PARENT);
+               
+       gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
+       gtk_window_set_skip_taskbar_hint (GTK_WINDOW (window), TRUE);
+       gtk_window_set_skip_pager_hint (GTK_WINDOW (window), TRUE);
+       gtk_window_set_transient_for (GTK_WINDOW (window), parent);
+
+       frame = gtk_frame_new (NULL);
+       gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
+       gtk_container_add (GTK_CONTAINER (window), frame);
+
+       hbox = gtk_hbox_new (FALSE, 12);
+       gtk_container_add (GTK_CONTAINER (frame), hbox);
+       gtk_container_set_border_width (GTK_CONTAINER (hbox), 12);
+
+       image = gtk_image_new_from_stock ("gtk-print", GTK_ICON_SIZE_DIALOG);
+       gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
+
+       vbox = gtk_vbox_new (FALSE, 12);
+       gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
+
+       label = gtk_label_new (_("Preparing pages..."));
+       gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+       gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
+       gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
+
+       progressbar = gtk_progress_bar_new ();
+       gtk_box_pack_start (GTK_BOX (vbox), progressbar, FALSE, FALSE, 0);
+       
+       pji->dialog = window;
+       pji->label = label;
+       pji->progressbar = progressbar;
+       
+       gtk_widget_show_all (pji->dialog);
+
+       /* Update UI */
+       while (gtk_events_pending ())
+               gtk_main_iteration ();
+}
+
+static void
+page_cb (GtkSourcePrintJob *job, GeditPrintJobInfo *pji)
+{
+       gchar *str;
+       gint page_num = gtk_source_print_job_get_page (pji->pjob);
+       gint total = gtk_source_print_job_get_page_count (pji->pjob);
+
+       if (pji->preview != PREVIEW_NO)
+               str = g_strdup_printf (_("Rendering page %d of %d..."), page_num, total);
+       else
+               str = g_strdup_printf (_("Printing page %d of %d..."), page_num, total);
+
+       gtk_label_set_label (GTK_LABEL (pji->label), str);
+       g_free (str);
+
+       gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (pji->progressbar), 
+                                      (total == 0) ? 0 : 1.0 * page_num / total);
+
+       /* Update UI */
+       while (gtk_events_pending ())
+               gtk_main_iteration ();
+
+}
+
+static void
+preview_finished_cb (GtkSourcePrintJob *job, GeditPrintJobInfo *pji)
+{
+       GnomePrintJob *gjob;
+       GtkWidget *preview = NULL;
+
+       gjob = gtk_source_print_job_get_print_job (job);
+
+       preview = gnome_print_job_preview_new (gjob, _("Print preview"));
+       if (pji->parent != NULL)
+       {
+               gtk_window_set_transient_for (GTK_WINDOW (preview), pji->parent);
+               gtk_window_set_modal (GTK_WINDOW (preview), TRUE);
+       }
+       
+       g_object_unref (gjob);
+
+       gtk_widget_destroy (pji->dialog);
+
+       if (pji->preview == PREVIEW)
+               pji->done = TRUE;
+       else
+       {
+               g_signal_handlers_disconnect_by_func (pji->pjob, (GCallback) page_cb, pji);
+               g_signal_handlers_disconnect_by_func (pji->pjob, (GCallback) preview_finished_cb, pji);
+       }
+       
+       gtk_widget_show (preview);
+}
+
+static void
+print_finished_cb (GtkSourcePrintJob *job, GeditPrintJobInfo *pji)
+{
+       GnomePrintJob *gjob;
+
+       gjob = gtk_source_print_job_get_print_job (job);
+
+       gnome_print_job_print (gjob);
+       
+       g_object_unref (gjob);
+
+       gtk_widget_destroy (pji->dialog);
+
+       pji->done = TRUE;
+}
+
+void 
+gedit_print (GtkTextView *view)
+{
+       GeditPrintJobInfo *pji;
+       GtkWidget *dialog;
+       GtkWidget *parent;
+
+       gedit_debug (DEBUG_PRINT, "");
+
+       g_return_if_fail (view != NULL);
+
+       pji = gedit_print_job_info_new (view);
+       pji->preview = PREVIEW_NO;
+       
+       parent = gtk_widget_get_toplevel (GTK_WIDGET (view));
+       if (parent == NULL || !GTK_IS_WINDOW(parent))
+               parent = mainwindow_get_mainwindow()->window;
+
+       dialog = get_print_dialog (pji, GTK_WINDOW (parent));
+       
+       g_signal_connect (dialog, "response",
+                         G_CALLBACK (gedit_print_dialog_response),
+                         pji);
+
+       gtk_widget_show (dialog);
+       while (pji->done != TRUE)
+               gtk_main_iteration();
+       gedit_print_job_info_destroy (pji, pji->preview ? FALSE:TRUE);
+       
+}
+
+static void 
+gedit_print_preview_real (GeditPrintJobInfo *pji, 
+                         GtkTextIter       *start, 
+                         GtkTextIter       *end, 
+                         GtkWindow         *parent)
+{
+       show_printing_dialog (pji, parent);
+
+       pji->parent = parent;
+
+       g_signal_connect (pji->pjob, "begin_page", (GCallback) page_cb, pji);
+       g_signal_connect (pji->pjob, "finished", (GCallback) preview_finished_cb, pji);
+
+       if (!gtk_source_print_job_print_range_async (pji->pjob, start, end))
+       {
+               /* FIXME */
+               g_warning ("Async print failed");
+               gtk_widget_destroy (pji->dialog);
+       }
+}
+
+static void 
+gedit_print_real (GeditPrintJobInfo *pji, 
+                 GtkTextIter       *start, 
+                 GtkTextIter       *end, 
+                 GtkWindow         *parent)
+{
+       show_printing_dialog (pji, parent);
+
+       g_signal_connect (pji->pjob, "begin_page", (GCallback) page_cb, pji);
+       g_signal_connect (pji->pjob, "finished", (GCallback) print_finished_cb, pji);
+
+       if (!gtk_source_print_job_print_range_async (pji->pjob, start, end))
+       {
+               /* FIXME */
+               g_warning ("Async print failed");
+               gtk_widget_destroy (pji->dialog);
+       }
+}
+
+static GeditPrintJobInfo *
+gedit_print_job_info_new (GtkTextView* view)
+{      
+       GtkSourcePrintJob *pjob;
+       GnomePrintConfig *config;
+       GeditPrintJobInfo *pji;
+       PangoContext *pango_context;
+       PangoFontDescription *font_desc;
+       GtkTextBuffer *buffer;
+       
+       gedit_debug (DEBUG_PRINT, "");
+       
+       g_return_val_if_fail (view != NULL, NULL);
+
+       buffer = gtk_text_view_get_buffer (view);
+       g_return_val_if_fail (buffer != NULL, NULL);
+
+       config = gnome_print_config_default ();
+       g_return_val_if_fail (config != NULL, NULL);
+
+       gnome_print_config_set_int (config, GNOME_PRINT_KEY_NUM_COPIES, 1);
+       gnome_print_config_set_boolean (config, GNOME_PRINT_KEY_COLLATE, FALSE);
+
+       pjob = gtk_source_print_job_new_with_buffer (config, buffer);
+       gnome_print_config_unref (config);
+
+       gtk_source_print_job_set_highlight (pjob, TRUE);
+       gtk_source_print_job_set_print_numbers (pjob, FALSE);
+       gtk_source_print_job_set_wrap_mode (pjob, gtk_text_view_get_wrap_mode (view));
+       gtk_source_print_job_set_tabs_width (pjob, 8);
+       
+       gtk_source_print_job_set_footer_format (pjob,
+                                               _("Page %N of %Q"), 
+                                               NULL, 
+                                               prefs_common.date_format, 
+                                               TRUE);
+
+       gtk_source_print_job_set_print_header (pjob, FALSE);
+       gtk_source_print_job_set_print_footer (pjob, TRUE);
+
+       pango_context = gtk_widget_get_pango_context (GTK_WIDGET (view));
+       if (prefs_common.use_different_print_font) 
+       {
+               font_desc = pango_font_description_from_string (prefs_common.printfont);
+       }
+       else
+       {
+               font_desc = pango_context_get_font_description (pango_context);
+       }
+
+       gtk_source_print_job_set_font_desc (pjob, font_desc);
+       if (prefs_common.use_different_print_font) 
+       {
+               pango_font_description_free (font_desc);
+       }
+
+       pji = g_new0 (GeditPrintJobInfo, 1);
+
+       pji->pjob = pjob;
+
+       pji->doc = buffer;
+       pji->preview = PREVIEW_NO;
+       pji->range_type = GNOME_PRINT_RANGE_ALL;
+
+       return pji;
+}
+
+#endif
diff --git a/src/gedit-print.h b/src/gedit-print.h
new file mode 100644 (file)
index 0000000..dcc305b
--- /dev/null
@@ -0,0 +1,41 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * gedit-print.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/*
+ * Modified by the gedit Team, 1998-2001. See the AUTHORS file for a 
+ * list of people on the gedit Team.  
+ * See the ChangeLog files for a list of changes. 
+ */
+
+#ifndef __GEDIT_PRINT_H__
+#define __GEDIT_PRINT_H__
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef USE_GNOMEPRINT
+
+#include <gtk/gtk.h>
+
+void gedit_print               (GtkTextView* view);
+
+#endif
+#endif /* __GEDIT_PRINT_H__ */
index fef219d..f2f10a1 100644 (file)
@@ -20,6 +20,7 @@ libclawsgtk_la_SOURCES = \
        gtkcmoptionmenu.c \
        gtkshruler.c \
        gtksctree.c \
+       gtksourceprintjob.c \
        gtkutils.c \
        gtkvscrollbutton.c \
        icon_legend.c \
@@ -50,6 +51,7 @@ clawsgtkinclude_HEADERS = \
        gtkcmoptionmenu.h \
        gtksctree.h \
        gtkshruler.h \
+       gtksourceprintjob.h \
        gtkutils.h \
        gtkvscrollbutton.h \
        headers.h \
@@ -73,6 +75,7 @@ AM_CPPFLAGS = \
        -I$(builddir)/.. \
        $(GTK_CFLAGS) \
        $(OPENSSL_CFLAGS) \
+       $(GNOMEPRINT_CFLAGS) \
        $(MAEMO_CFLAGS) \
        $(ENCHANT_CFLAGS) \
        -DPLUGINDIR=\"$(PLUGINDIR)\" \
@@ -82,6 +85,7 @@ libclawsgtk_la_LIBADD = \
        ../common/libclawscommon.la \
        $(GTK_LIBS) \
        $(ENCHANT_LIBS) \
+       $(GNOMEPRINT_LIBS) \
        $(MAEMO_LIBS)
 
 BUILT_SOURCES=claws-marshal.c claws-marshal.h 
index 85aa283..6f71aeb 100644 (file)
@@ -425,7 +425,7 @@ static GtkWidget *about_create_child_page_features(void)
        gtk_text_buffer_insert(buffer, &iter, 
                (gchar *)Q_("GnuTLS|adds support for encrypted connections to servers\n"), -1);
 
-#if GTK_CHECK_VERSION(2,10,0)
+#if GTK_CHECK_VERSION(2,10,0) && !defined(USE_GNOMEPRINT)
        gtk_text_buffer_insert_pixbuf(buffer, &iter, active_pixbuf);
 #else
        gtk_text_buffer_insert_pixbuf(buffer, &iter, inactive_pixbuf);
@@ -486,6 +486,16 @@ static GtkWidget *about_create_child_page_features(void)
        gtk_text_buffer_insert(buffer, &iter, 
                (gchar *)Q_("libetpan|adds support for IMAP and NNTP servers\n"), -1);
 
+#if USE_GNOMEPRINT
+       gtk_text_buffer_insert_pixbuf(buffer, &iter, active_pixbuf);
+#else
+       gtk_text_buffer_insert_pixbuf(buffer, &iter, inactive_pixbuf);
+#endif
+       gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, (" libgnomeprint "), -1,
+                                                "bold", NULL);
+       gtk_text_buffer_insert(buffer, &iter, 
+               (gchar *)Q_("libgnomeprint|adds support for a complete print dialog\n"), -1);
+
 #if HAVE_LIBSM
        gtk_text_buffer_insert_pixbuf(buffer, &iter, active_pixbuf);
 #else
diff --git a/src/gtk/gtksourceprintjob.c b/src/gtk/gtksourceprintjob.c
new file mode 100644 (file)
index 0000000..e36ef72
--- /dev/null
@@ -0,0 +1,3242 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*- */
+/*
+ * gtksourceprintjob.c
+ * This file is part of GtkSourceView
+ *
+ * Derived from gedit-print.c
+ *
+ * Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
+ * Copyright (C) 2002  Paolo Maggi  
+ * Copyright (C) 2003  Gustavo Giráldez
+ * Copyright (C) 2004  Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef USE_GNOMEPRINT
+
+#include <string.h>
+#include <time.h>
+
+#include "gtksourceprintjob.h"
+#include "image_viewer.h"
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <libgnomeprint/gnome-print-pango.h>
+
+#ifdef ENABLE_PROFILE
+#define PROFILE(x) x
+#else
+#define PROFILE(x)
+#endif
+
+#ifdef ENABLE_DEBUG
+#define DEBUG(x) x
+#else
+#define DEBUG(x)
+#endif
+
+
+#define DEFAULT_FONT_NAME   "Monospace 10"
+#define DEFAULT_COLOR       0x000000ff
+
+#define CM(v) ((v) * 72.0 / 2.54)
+#define A4_WIDTH (210.0 * 72 / 25.4)
+#define A4_HEIGHT (297.0 * 72 / 25.4)
+
+#define NUMBERS_TEXT_SEPARATION CM(0.5)
+
+#define HEADER_FOOTER_SIZE      2.5
+#define SEPARATOR_SPACING       1.5
+#define SEPARATOR_LINE_WIDTH    1.0
+
+
+typedef struct _TextSegment TextSegment;
+typedef struct _Paragraph   Paragraph;
+typedef struct _TextStyle   TextStyle;
+
+/* a piece of text (within a paragraph) of the same style */
+struct _TextSegment
+{
+       TextSegment             *next;
+       TextStyle               *style;
+       gchar                   *text;
+       GdkPixbuf               *image;
+};
+
+/* a printable line */
+struct _Paragraph
+{
+       guint                    line_number;
+       TextSegment             *segment;
+};
+
+/* the style of a TextSegment */
+struct _TextStyle
+{
+       PangoFontDescription    *font_desc;
+       GdkColor                *foreground;
+       GdkColor                *background;
+       gdouble                  scale;
+       gboolean                 strikethrough;
+       PangoUnderline           underline;
+};
+
+
+struct _GtkSourcePrintJobPrivate
+{
+       /* General job configuration */
+       GnomePrintConfig        *config;
+       GtkTextBuffer           *buffer;
+       guint                    tabs_width;
+       GtkWrapMode              wrap_mode;
+       gboolean                 highlight;
+       PangoLanguage           *language;
+       PangoFontDescription    *font;
+       PangoFontDescription    *numbers_font;
+       guint                    print_numbers;
+       gdouble                  margin_top;
+       gdouble                  margin_bottom;
+       gdouble                  margin_left;
+       gdouble                  margin_right;
+
+       /* Default header and footer configuration */
+       gboolean                 print_header;
+       gboolean                 print_footer;
+       PangoFontDescription    *header_footer_font;
+       gchar                   *header_format_left;
+       gchar                   *header_format_center;
+       gchar                   *header_format_right;
+       gboolean                 header_separator;
+       gchar                   *footer_format_left;
+       gchar                   *footer_format_center;
+       gchar                   *footer_format_right;
+       gboolean                 footer_separator;
+
+       /* Job data */
+       guint                    first_line_number;
+       guint                    last_line_number;
+       GSList                  *paragraphs;
+
+       /* Job state */
+       gboolean                 printing;
+       guint                    idle_printing_tag;
+       GnomePrintContext       *print_ctxt;
+       GnomePrintJob           *print_job;
+       PangoContext            *pango_context;
+       PangoTabArray           *tab_array;
+       gint                     page;
+       gint                     page_count;
+       gdouble                  available_height;
+       GSList                  *current_paragraph;
+       gint                     current_paragraph_line;
+       guint                    printed_lines;
+
+       /* Cached information - all this information is obtained from
+        * other fields in the configuration */
+       GHashTable              *tag_styles;
+
+       gdouble                  page_width;
+       gdouble                  page_height;
+       /* outer margins */
+       gdouble                  doc_margin_top;
+       gdouble                  doc_margin_left;
+       gdouble                  doc_margin_right;
+       gdouble                  doc_margin_bottom;
+
+       gdouble                  header_height;
+       gdouble                  footer_height;
+       gdouble                  numbers_width;
+
+       /* printable (for the document itself) size */
+       gdouble                  text_width;
+       gdouble                  text_height;
+};
+
+
+enum
+{
+       PROP_0,
+       PROP_CONFIG,
+       PROP_BUFFER,
+       PROP_TABS_WIDTH,
+       PROP_WRAP_MODE,
+       PROP_HIGHLIGHT,
+       PROP_FONT,
+       PROP_FONT_DESC,
+       PROP_NUMBERS_FONT,
+       PROP_NUMBERS_FONT_DESC,
+       PROP_PRINT_NUMBERS,
+       PROP_PRINT_HEADER,
+       PROP_PRINT_FOOTER,
+       PROP_HEADER_FOOTER_FONT,
+       PROP_HEADER_FOOTER_FONT_DESC
+};
+
+enum
+{
+       BEGIN_PAGE = 0,
+       FINISHED,
+       LAST_SIGNAL
+};
+
+static GObjectClass *parent_class = NULL;
+static guint        print_job_signals [LAST_SIGNAL] = { 0 };
+
+static void     gtk_source_print_job_class_init    (GtkSourcePrintJobClass *klass);
+static void     gtk_source_print_job_instance_init (GtkSourcePrintJob      *job);
+static void     gtk_source_print_job_finalize      (GObject                *object);
+static void     gtk_source_print_job_get_property  (GObject                *object,
+                                                   guint                   property_id,
+                                                   GValue                 *value,
+                                                   GParamSpec             *pspec);
+static void     gtk_source_print_job_set_property  (GObject                *object,
+                                                   guint                   property_id,
+                                                   const GValue           *value,
+                                                   GParamSpec             *pspec);
+static void     gtk_source_print_job_begin_page    (GtkSourcePrintJob      *job);
+
+static void     default_print_header               (GtkSourcePrintJob      *job,
+                                                   gdouble                 x,
+                                                   gdouble                 y);
+static void     default_print_footer               (GtkSourcePrintJob      *job,
+                                                   gdouble                 x,
+                                                   gdouble                 y);
+
+
+GType
+gtk_source_print_job_get_type (void)
+{
+       static GType our_type = 0;
+
+       if (our_type == 0)
+       {
+               static const GTypeInfo our_info = {
+                       sizeof (GtkSourcePrintJobClass),
+                       NULL,   /* base_init */
+                       NULL,   /* base_finalize */
+                       (GClassInitFunc) gtk_source_print_job_class_init,
+                       NULL,   /* class_finalize */
+                       NULL,   /* class_data */
+                       sizeof (GtkSourcePrintJob),
+                       0,      /* n_preallocs */
+                       (GInstanceInitFunc) gtk_source_print_job_instance_init
+               };
+
+               our_type = g_type_register_static (G_TYPE_OBJECT,
+                                                  "GtkSourcePrintJob",
+                                                  &our_info, 
+                                                  0);
+       }
+       
+       return our_type;
+}
+       
+static void
+gtk_source_print_job_class_init (GtkSourcePrintJobClass *klass)
+{
+       GObjectClass *object_class;
+
+       object_class = G_OBJECT_CLASS (klass);
+       parent_class = g_type_class_peek_parent (klass);
+               
+       object_class->finalize     = gtk_source_print_job_finalize;
+       object_class->get_property = gtk_source_print_job_get_property;
+       object_class->set_property = gtk_source_print_job_set_property;
+
+       klass->begin_page = gtk_source_print_job_begin_page;
+       klass->finished = NULL;
+       
+       g_object_class_install_property (object_class,
+                                        PROP_CONFIG,
+                                        g_param_spec_object ("config",
+                                                             _("Configuration"),
+                                                             _("Configuration options for "
+                                                               "the print job"),
+                                                             GNOME_TYPE_PRINT_CONFIG,
+                                                             G_PARAM_READWRITE));
+       g_object_class_install_property (object_class,
+                                        PROP_BUFFER,
+                                        g_param_spec_object ("buffer",
+                                                             _("Source Buffer"),
+                                                             _("GtkTextBuffer object to print"),
+                                                             GTK_TYPE_TEXT_BUFFER,
+                                                             G_PARAM_READWRITE));
+       g_object_class_install_property (object_class,
+                                        PROP_TABS_WIDTH,
+                                        g_param_spec_uint ("tabs_width",
+                                                           _("Tabs Width"),
+                                                           _("Width in equivalent space "
+                                                             "characters of tabs"),
+                                                           0, 100, 8,
+                                                           G_PARAM_READWRITE));
+       g_object_class_install_property (object_class,
+                                        PROP_WRAP_MODE,
+                                        g_param_spec_enum ("wrap_mode",
+                                                           _("Wrap Mode"),
+                                                           _("Word wrapping mode"),
+                                                           GTK_TYPE_WRAP_MODE,
+                                                           GTK_WRAP_NONE,
+                                                           G_PARAM_READWRITE));
+       g_object_class_install_property (object_class,
+                                        PROP_HIGHLIGHT,
+                                        g_param_spec_boolean ("highlight",
+                                                              _("Highlight"),
+                                                              _("Whether to print the "
+                                                                "document with highlighted "
+                                                                "syntax"),
+                                                              TRUE,
+                                                              G_PARAM_READWRITE));
+       g_object_class_install_property (object_class,
+                                        PROP_FONT,
+                                        g_param_spec_string ("font",
+                                                             _("Font"),
+                                                             _("GnomeFont name to use for the "
+                                                               "document text (deprecated)"),
+                                                             NULL,
+                                                             G_PARAM_READWRITE));
+       g_object_class_install_property (object_class,
+                                        PROP_FONT_DESC,
+                                        g_param_spec_boxed ("font_desc",
+                                                            _("Font Description"),
+                                                            _("Font to use for the document text "
+                                                              "(e.g. \"Monospace 10\")"),
+                                                            PANGO_TYPE_FONT_DESCRIPTION,
+                                                             G_PARAM_READWRITE));
+       g_object_class_install_property (object_class,
+                                        PROP_NUMBERS_FONT,
+                                        g_param_spec_string ("numbers_font",
+                                                             _("Numbers Font"),
+                                                             _("GnomeFont name to use for the "
+                                                               "line numbers (deprecated)"),
+                                                             NULL,
+                                                             G_PARAM_READWRITE));
+       g_object_class_install_property (object_class,
+                                        PROP_NUMBERS_FONT_DESC,
+                                        g_param_spec_boxed ("numbers_font_desc",
+                                                            _("Numbers Font"),
+                                                            _("Font description to use for the "
+                                                              "line numbers"),
+                                                            PANGO_TYPE_FONT_DESCRIPTION,
+                                                             G_PARAM_READWRITE));
+       g_object_class_install_property (object_class,
+                                        PROP_PRINT_NUMBERS,
+                                        g_param_spec_uint ("print_numbers",
+                                                           _("Print Line Numbers"),
+                                                           _("Interval of printed line numbers "
+                                                             "(0 means no numbers)"),
+                                                           0, 100, 1,
+                                                           G_PARAM_READWRITE));
+       g_object_class_install_property (object_class,
+                                        PROP_PRINT_HEADER,
+                                        g_param_spec_boolean ("print_header",
+                                                              _("Print Header"),
+                                                              _("Whether to print a header "
+                                                                "in each page"),
+                                                              FALSE,
+                                                              G_PARAM_READWRITE));
+       g_object_class_install_property (object_class,
+                                        PROP_PRINT_FOOTER,
+                                        g_param_spec_boolean ("print_footer",
+                                                              _("Print Footer"),
+                                                              _("Whether to print a footer "
+                                                                "in each page"),
+                                                              FALSE,
+                                                              G_PARAM_READWRITE));
+       g_object_class_install_property (object_class,
+                                        PROP_HEADER_FOOTER_FONT,
+                                        g_param_spec_string ("header_footer_font",
+                                                             _("Header and Footer Font"),
+                                                             _("GnomeFont name to use for the header "
+                                                               "and footer (deprecated)"),
+                                                             NULL,
+                                                             G_PARAM_READWRITE));
+       g_object_class_install_property (object_class,
+                                        PROP_HEADER_FOOTER_FONT_DESC,
+                                        g_param_spec_boxed ("header_footer_font_desc",
+                                                            _("Header and Footer Font Description"),
+                                                            _("Font to use for headers and footers "
+                                                              "(e.g. \"Monospace 10\")"),
+                                                            PANGO_TYPE_FONT_DESCRIPTION,
+                                                            G_PARAM_READWRITE));
+       
+       print_job_signals [BEGIN_PAGE] =
+           g_signal_new ("begin_page",
+                         G_OBJECT_CLASS_TYPE (object_class),
+                         G_SIGNAL_RUN_LAST,
+                         G_STRUCT_OFFSET (GtkSourcePrintJobClass, begin_page),
+                         NULL, NULL,
+                         g_cclosure_marshal_VOID__VOID,
+                         G_TYPE_NONE, 
+                         0);
+       print_job_signals [FINISHED] =
+           g_signal_new ("finished",
+                         G_OBJECT_CLASS_TYPE (object_class),
+                         G_SIGNAL_RUN_FIRST,
+                         G_STRUCT_OFFSET (GtkSourcePrintJobClass, finished),
+                         NULL, NULL,
+                         g_cclosure_marshal_VOID__VOID,
+                         G_TYPE_NONE, 
+                         0);
+}
+
+static void
+gtk_source_print_job_instance_init (GtkSourcePrintJob *job)
+{
+       GtkSourcePrintJobPrivate *priv;
+
+       priv = g_new0 (GtkSourcePrintJobPrivate, 1);
+       job->priv = priv;
+
+       /* default job configuration */
+       priv->config = NULL;
+       priv->buffer = NULL;
+
+       priv->tabs_width = 8;
+       priv->wrap_mode = GTK_WRAP_NONE;
+       priv->highlight = TRUE;
+       priv->language = gtk_get_default_language ();
+       priv->font = NULL;
+       priv->numbers_font = NULL;
+       priv->print_numbers = 1;
+       priv->margin_top = 0.0;
+       priv->margin_bottom = 0.0;
+       priv->margin_left = 0.0;
+       priv->margin_right = 0.0;
+
+       priv->print_header = FALSE;
+       priv->print_footer = FALSE;
+       priv->header_footer_font = NULL;
+       priv->header_format_left = NULL;
+       priv->header_format_center = NULL;
+       priv->header_format_right = NULL;
+       priv->header_separator = FALSE;
+       priv->footer_format_left = NULL;
+       priv->footer_format_center = NULL;
+       priv->footer_format_right = NULL;
+       priv->footer_separator = FALSE;
+
+       /* initial state */
+       priv->printing = FALSE;
+       priv->print_ctxt = NULL;
+       priv->print_job = NULL;
+       priv->page = 0;
+       priv->page_count = 0;
+
+       priv->first_line_number = 0;
+       priv->paragraphs = NULL;
+       priv->tag_styles = NULL;
+
+       /* some default, sane values */
+       priv->page_width = A4_WIDTH;
+       priv->page_height = A4_HEIGHT;
+       priv->doc_margin_top = CM (1);
+       priv->doc_margin_left = CM (1);
+       priv->doc_margin_right = CM (1);
+       priv->doc_margin_bottom = CM (1);
+}
+
+static void
+free_paragraphs (GSList *paras)
+{
+       while (paras != NULL)
+       {
+               Paragraph *para = paras->data;
+               TextSegment *seg =  para->segment;
+               while (seg != NULL)
+               {
+                       TextSegment *next = seg->next;
+                       g_free (seg->text);
+                       g_free (seg);
+                       seg = next;
+               }
+               g_free (para);
+               paras = g_slist_delete_link (paras, paras);
+       }
+}
+
+static void
+gtk_source_print_job_finalize (GObject *object)
+{
+       GtkSourcePrintJob *job;
+       GtkSourcePrintJobPrivate *priv;
+       
+       g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (object));
+       
+       job = GTK_SOURCE_PRINT_JOB (object);
+       priv = job->priv;
+       
+       if (priv != NULL)
+       {
+               if (priv->config != NULL)
+                       gnome_print_config_unref (priv->config);
+               if (priv->buffer != NULL)
+                       g_object_unref (priv->buffer);
+               if (priv->font != NULL)
+                       pango_font_description_free (priv->font);
+               if (priv->numbers_font != NULL)
+                       pango_font_description_free (priv->numbers_font);
+               if (priv->header_footer_font != NULL)
+                       pango_font_description_free (priv->header_footer_font);
+               g_free (priv->header_format_left);
+               g_free (priv->header_format_right);
+               g_free (priv->header_format_center);
+               g_free (priv->footer_format_left);
+               g_free (priv->footer_format_right);
+               g_free (priv->footer_format_center);
+               
+               if (priv->print_ctxt != NULL)
+                       g_object_unref (priv->print_ctxt);
+               if (priv->print_job != NULL)
+                       g_object_unref (priv->print_job);
+               if (priv->pango_context != NULL)
+                       g_object_unref (priv->pango_context);
+               if (priv->tab_array != NULL)
+                       pango_tab_array_free (priv->tab_array);
+
+               if (priv->paragraphs != NULL)
+                       free_paragraphs (priv->paragraphs);
+               if (priv->tag_styles != NULL)
+                       g_hash_table_destroy (priv->tag_styles);
+               
+               g_free (priv);
+               job->priv = NULL;
+       }
+       
+       G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void 
+gtk_source_print_job_get_property (GObject    *object,
+                                  guint       prop_id,
+                                  GValue     *value,
+                                  GParamSpec *pspec)
+{
+       GtkSourcePrintJob *job = GTK_SOURCE_PRINT_JOB (object);
+
+       switch (prop_id)
+       {
+               case PROP_CONFIG:
+                       g_value_set_object (value, job->priv->config);
+                       break;
+                       
+               case PROP_BUFFER:
+                       g_value_set_object (value, job->priv->buffer);
+                       break;
+
+               case PROP_TABS_WIDTH:
+                       g_value_set_uint (value, job->priv->tabs_width);
+                       break;
+                       
+               case PROP_WRAP_MODE:
+                       g_value_set_enum (value, job->priv->wrap_mode);
+                       break;
+
+               case PROP_HIGHLIGHT:
+                       g_value_set_boolean (value, job->priv->highlight);
+                       break;
+                       
+               case PROP_FONT:
+                       g_value_take_string (value, gtk_source_print_job_get_font (job));
+                       break;
+                       
+               case PROP_FONT_DESC:
+                       g_value_set_boxed (value, gtk_source_print_job_get_font_desc (job));
+                       break;
+                       
+               case PROP_NUMBERS_FONT:
+                       g_value_take_string (value, gtk_source_print_job_get_numbers_font (job));
+                       break;
+                       
+               case PROP_NUMBERS_FONT_DESC:
+                       g_value_set_boxed (value, gtk_source_print_job_get_numbers_font_desc (job));
+                       break;
+                       
+               case PROP_PRINT_NUMBERS:
+                       g_value_set_uint (value, job->priv->print_numbers);
+                       break;
+                       
+               case PROP_PRINT_HEADER:
+                       g_value_set_boolean (value, job->priv->print_header);
+                       break;
+                       
+               case PROP_PRINT_FOOTER:
+                       g_value_set_boolean (value, job->priv->print_footer);
+                       break;
+                       
+               case PROP_HEADER_FOOTER_FONT:
+                       g_value_take_string (value,
+                                            gtk_source_print_job_get_header_footer_font (job));
+                       break;
+                       
+               case PROP_HEADER_FOOTER_FONT_DESC:
+                       g_value_set_boxed (value,
+                                          gtk_source_print_job_get_header_footer_font_desc (job));
+                       break;
+                       
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                       break;
+       }
+}
+
+static void 
+gtk_source_print_job_set_property (GObject      *object,
+                                  guint         prop_id,
+                                  const GValue *value,
+                                  GParamSpec   *pspec)
+{
+       GtkSourcePrintJob *job = GTK_SOURCE_PRINT_JOB (object);
+
+       switch (prop_id)
+       {
+               case PROP_CONFIG:
+                       gtk_source_print_job_set_config (job, g_value_get_object (value));
+                       break;
+                       
+               case PROP_BUFFER:
+                       gtk_source_print_job_set_buffer (job, g_value_get_object (value));
+                       break;
+                       
+               case PROP_TABS_WIDTH:
+                       gtk_source_print_job_set_tabs_width (job, g_value_get_uint (value));
+                       break;
+                       
+               case PROP_WRAP_MODE:
+                       gtk_source_print_job_set_wrap_mode (job, g_value_get_enum (value));
+                       break;
+
+               case PROP_HIGHLIGHT:
+                       gtk_source_print_job_set_highlight (job, g_value_get_boolean (value));
+                       break;
+
+               case PROP_FONT:
+                       gtk_source_print_job_set_font (job, g_value_get_string (value));
+                       break;
+
+               case PROP_FONT_DESC:
+                       gtk_source_print_job_set_font_desc (job, g_value_get_boxed (value));
+                       break;
+                       
+               case PROP_NUMBERS_FONT:
+                       gtk_source_print_job_set_numbers_font (job, g_value_get_string (value));
+                       break;
+                       
+               case PROP_NUMBERS_FONT_DESC:
+                       gtk_source_print_job_set_numbers_font_desc (job, g_value_get_boxed (value));
+                       break;
+
+               case PROP_PRINT_NUMBERS:
+                       gtk_source_print_job_set_print_numbers (job, g_value_get_uint (value));
+                       break;
+                       
+               case PROP_PRINT_HEADER:
+                       gtk_source_print_job_set_print_header (job, g_value_get_boolean (value));
+                       break;
+
+               case PROP_PRINT_FOOTER:
+                       gtk_source_print_job_set_print_footer (job, g_value_get_boolean (value));
+                       break;
+
+               case PROP_HEADER_FOOTER_FONT:
+                       gtk_source_print_job_set_header_footer_font (job,
+                                                                    g_value_get_string (value));
+                       break;
+                       
+               case PROP_HEADER_FOOTER_FONT_DESC:
+                       gtk_source_print_job_set_header_footer_font_desc (job,
+                                                                         g_value_get_boxed (value));
+                       break;
+
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                       break;
+       }
+}
+
+static void 
+gtk_source_print_job_begin_page (GtkSourcePrintJob *job)
+{
+       g_return_if_fail (job->priv->printing);
+       
+       if (job->priv->print_header && job->priv->header_height > 0)
+       {
+               gdouble x, y;
+
+               x = job->priv->doc_margin_left + job->priv->margin_left;
+               y = job->priv->page_height - job->priv->doc_margin_top - job->priv->margin_top;
+               default_print_header (job, x, y);
+       }
+
+       if (job->priv->print_footer && job->priv->footer_height > 0)
+       {
+               gdouble x, y;
+
+               x = job->priv->doc_margin_left + job->priv->margin_left;
+               y = job->priv->doc_margin_bottom +
+                       job->priv->margin_bottom +
+                       job->priv->footer_height;
+               default_print_footer (job, x, y);
+       }
+}
+
+/* ---- gnome-print / Pango convenience functions */
+
+/* Gets the width of a layout in gnome-print coordinates */
+static gdouble
+get_layout_width (PangoLayout *layout)
+{
+       gint layout_width;
+
+       pango_layout_get_size (layout, &layout_width, NULL);
+       return (gdouble) layout_width / PANGO_SCALE;
+}
+
+/* Gets the ascent/descent of a font in gnome-print coordinates */
+static void
+get_font_ascent_descent (GtkSourcePrintJob    *job,
+                        PangoFontDescription *desc,
+                        gdouble              *ascent,
+                        gdouble              *descent)
+{
+       PangoFontMetrics *metrics;
+       
+       metrics = pango_context_get_metrics (job->priv->pango_context,
+                                            desc,
+                                            job->priv->language);
+
+       if (ascent)
+               *ascent = (gdouble) pango_font_metrics_get_ascent (metrics) / PANGO_SCALE;
+       if (descent)
+               *descent = (gdouble) pango_font_metrics_get_descent (metrics) / PANGO_SCALE;
+
+       pango_font_metrics_unref (metrics);
+}
+
+/* Draws the first line in a layout; we use this for one-line layouts
+ * to get baseline alignment */
+static void
+show_first_layout_line (GnomePrintContext *print_ctxt,
+                       PangoLayout       *layout)
+{
+       PangoLayoutLine *line;
+
+       line = pango_layout_get_lines (layout)->data;
+       gnome_print_pango_layout_line (print_ctxt, line);
+}
+
+static PangoLayout *
+get_line_number_layout (GtkSourcePrintJob *job,
+                       guint              line_number)
+{
+       PangoLayout *layout;
+       gchar *num_str;
+
+       num_str = g_strdup_printf ("%d", line_number);
+       layout = pango_layout_new (job->priv->pango_context);
+       pango_layout_set_font_description (layout, job->priv->numbers_font);
+       pango_layout_set_text (layout, num_str, -1);
+       g_free (num_str);
+
+       return layout;
+}
+
+/* ---- Configuration functions */
+
+static void
+ensure_print_config (GtkSourcePrintJob *job)
+{
+       if (job->priv->config == NULL)
+               job->priv->config = gnome_print_config_default ();
+       if (job->priv->font == NULL)
+               job->priv->font = pango_font_description_from_string (DEFAULT_FONT_NAME);
+}
+
+static gboolean
+update_page_size_and_margins (GtkSourcePrintJob *job)
+{
+       PangoLayout *layout;
+       gdouble ascent, descent;
+       
+       gnome_print_job_get_page_size_from_config (job->priv->config, 
+                                                  &job->priv->page_width,
+                                                  &job->priv->page_height);
+
+       gnome_print_config_get_length (job->priv->config, GNOME_PRINT_KEY_PAGE_MARGIN_TOP,
+                                      &job->priv->doc_margin_top, NULL);
+       gnome_print_config_get_length (job->priv->config, GNOME_PRINT_KEY_PAGE_MARGIN_BOTTOM,
+                                      &job->priv->doc_margin_bottom, NULL);
+       gnome_print_config_get_length (job->priv->config, GNOME_PRINT_KEY_PAGE_MARGIN_LEFT,
+                                      &job->priv->doc_margin_left, NULL);
+       gnome_print_config_get_length (job->priv->config, GNOME_PRINT_KEY_PAGE_MARGIN_RIGHT,
+                                      &job->priv->doc_margin_right, NULL);
+
+       /* set default fonts for numbers and header/footer */
+       if (job->priv->numbers_font == NULL)
+               job->priv->numbers_font = pango_font_description_copy (job->priv->font);
+       
+       if (job->priv->header_footer_font == NULL)
+               job->priv->header_footer_font = pango_font_description_copy (job->priv->font);
+       
+       /* calculate numbers width */
+       if (job->priv->print_numbers > 0)
+       {
+               layout = get_line_number_layout (job, job->priv->last_line_number);
+               job->priv->numbers_width = get_layout_width (layout) + NUMBERS_TEXT_SEPARATION;
+               g_object_unref (layout);
+       }
+       else
+               job->priv->numbers_width = 0.0;
+
+       get_font_ascent_descent (job, job->priv->header_footer_font, &ascent, &descent);
+
+       /* calculate header/footer height */
+       if (job->priv->print_header &&
+           (job->priv->header_format_left != NULL ||
+            job->priv->header_format_center != NULL ||
+            job->priv->header_format_right != NULL))
+               job->priv->header_height = HEADER_FOOTER_SIZE * (ascent + descent);
+       else
+               job->priv->header_height = 0.0;
+
+       if (job->priv->print_footer &&
+           (job->priv->footer_format_left != NULL ||
+            job->priv->footer_format_center != NULL ||
+            job->priv->footer_format_right != NULL))
+               job->priv->footer_height = HEADER_FOOTER_SIZE * (ascent + descent);
+       else
+               job->priv->footer_height = 0.0;
+
+       /* verify that the user provided margins are not too excesive
+        * and that we still have room for the text */
+       job->priv->text_width = (job->priv->page_width -
+                                job->priv->doc_margin_left - job->priv->doc_margin_right -
+                                job->priv->margin_left - job->priv->margin_right -
+                                job->priv->numbers_width);
+       
+       job->priv->text_height = (job->priv->page_height -
+                                 job->priv->doc_margin_top - job->priv->doc_margin_bottom -
+                                 job->priv->margin_top - job->priv->margin_bottom -
+                                 job->priv->header_height - job->priv->footer_height);
+
+       /* FIXME: put some saner values than 5cm - Gustavo */
+       g_return_val_if_fail (job->priv->text_width > CM(5.0), FALSE);
+       g_return_val_if_fail (job->priv->text_height > CM(5.0), FALSE);
+
+       return TRUE;
+}
+
+/* We want a uniform tab width for the entire job without regard to style
+ * See comments in gtksourceview.c:calculate_real_tab_width
+ */
+static gint
+calculate_real_tab_width (GtkSourcePrintJob *job, guint tab_size, gchar c)
+{
+       PangoLayout *layout;
+       gchar *tab_string;
+       gint tab_width = 0;
+
+       if (tab_size == 0)
+               return -1;
+
+       tab_string = g_strnfill (tab_size, c);
+       layout = pango_layout_new (job->priv->pango_context);
+       pango_layout_set_text (layout, tab_string, -1);
+       g_free (tab_string);
+
+       pango_layout_get_size (layout, &tab_width, NULL);
+       g_object_unref (G_OBJECT (layout));
+       
+       return tab_width;
+}
+
+static gboolean
+setup_pango_context (GtkSourcePrintJob *job)
+{
+       PangoFontMap *font_map;
+       gint real_tab_width;
+
+       if (!job->priv->pango_context)
+       {
+               font_map = gnome_print_pango_get_default_font_map ();
+               job->priv->pango_context = gnome_print_pango_create_context (font_map);
+       }
+
+       pango_context_set_language (job->priv->pango_context, job->priv->language);
+       pango_context_set_font_description (job->priv->pango_context, job->priv->font);
+
+       if (job->priv->tab_array)
+       {
+               pango_tab_array_free (job->priv->tab_array);
+               job->priv->tab_array = NULL;
+       }
+       
+       real_tab_width = calculate_real_tab_width (job, job->priv->tabs_width, ' ');
+       if (real_tab_width > 0)
+       {
+               job->priv->tab_array = pango_tab_array_new (1, FALSE);
+               pango_tab_array_set_tab (job->priv->tab_array, 0, PANGO_TAB_LEFT, real_tab_width);
+       }
+       
+       return TRUE;
+}
+
+/* ----- Helper functions */
+
+static gchar * 
+font_description_to_gnome_font_name (PangoFontDescription *desc)
+{
+       GnomeFontFace *font_face;
+       gchar *retval;
+
+       /* Will always return some font */
+       font_face = gnome_font_face_find_closest_from_pango_description (desc);
+
+       retval = g_strdup_printf("%s %f",
+                                gnome_font_face_get_name (font_face),
+                                (double) pango_font_description_get_size (desc) / PANGO_SCALE);
+       g_object_unref (font_face);
+
+       return retval;
+}
+
+/*
+ * The following routines are duplicated in gedit/gedit/gedit-prefs-manager.c
+ */
+
+/* Do this ourselves since gnome_font_find_closest() doesn't call
+ * gnome_font_face_find_closest() (probably a gnome-print bug)
+ */
+static void
+face_and_size_from_full_name (const guchar   *name,
+                             GnomeFontFace **face,
+                             gdouble        *size)
+{
+       char *copy;
+       char *str_size;
+
+       copy = g_strdup (name);
+       str_size = strrchr (copy, ' ');
+       if (str_size)
+       {
+               *str_size = 0;
+               str_size ++;
+               *size = atof (str_size);
+       }
+       else
+       {
+               *size = 12;
+       }
+
+       *face = gnome_font_face_find_closest (copy);
+       g_free (copy);
+}
+
+static PangoFontDescription *
+font_description_from_gnome_font_name (const char *font_name)
+{
+       GnomeFontFace *face;
+       PangoFontDescription *desc;
+       PangoStyle style;
+       PangoWeight weight;
+       gdouble size;
+
+       face_and_size_from_full_name (font_name, &face, &size);
+
+       /* Pango and GnomePrint have basically the same numeric weight values */
+       weight = (PangoWeight) gnome_font_face_get_weight_code (face);
+       style = gnome_font_face_is_italic (face) ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL;
+
+       desc = pango_font_description_new ();
+       pango_font_description_set_family (desc, gnome_font_face_get_family_name (face));
+       pango_font_description_set_weight (desc, weight);
+       pango_font_description_set_style (desc, style);
+       pango_font_description_set_size (desc, size * PANGO_SCALE);
+
+       g_object_unref (face);
+
+       return desc;
+}
+
+/* ---- TextStyle functions */
+
+static TextStyle * 
+text_style_new (GtkSourcePrintJob *job, GtkTextTag *tag)
+{
+       TextStyle *style;
+       gboolean bg_set, fg_set;
+       
+       g_return_val_if_fail (tag != NULL && GTK_IS_TEXT_TAG (tag), NULL);
+
+       style = g_new0 (TextStyle, 1);
+
+       g_object_get (G_OBJECT (tag),
+                     "background_set", &bg_set,
+                     "foreground_set", &fg_set,
+                     "font_desc", &style->font_desc,
+                     "scale", &style->scale,
+                     "underline", &style->underline,
+                     "strikethrough", &style->strikethrough,
+                     NULL);
+
+       if (fg_set)
+               g_object_get (G_OBJECT (tag), "foreground_gdk", &style->foreground, NULL);
+
+       if (bg_set)
+               g_object_get (G_OBJECT (tag), "background_gdk", &style->background, NULL);
+       
+       return style;
+}
+
+static void
+text_style_free (TextStyle *style)
+{
+       pango_font_description_free (style->font_desc);
+       if (style->foreground)
+               gdk_color_free (style->foreground);
+       if (style->background)
+               gdk_color_free (style->background);
+       g_free (style);
+}
+
+static TextStyle * 
+get_style (GtkSourcePrintJob *job, const GtkTextIter *iter)
+{
+       GSList *tags, *t;
+       GtkTextTag *tag = NULL;
+       TextStyle *style = NULL;
+       
+       if (job->priv->tag_styles == NULL)
+       {
+               job->priv->tag_styles = g_hash_table_new_full (
+                       g_direct_hash, g_direct_equal,
+                       NULL, (GDestroyNotify) text_style_free);
+       }
+       
+       /* get the tags at iter */
+       tags = gtk_text_iter_get_tags (iter);
+
+       /* now find the GtkSourceTag (if any) which applies at iter */
+       /* FIXME: this makes the assumption that the style at a given
+        * iter is only determined by one GtkSourceTag (the one with
+        * highest priority).  This is true for now, but could change
+        * in the future - Gustavo */
+       t = tags;
+       while (t != NULL)
+       {
+               if (GTK_IS_TEXT_TAG (t->data))
+                       tag = t->data;
+               t = g_slist_next (t);
+       }
+       g_slist_free (tags);
+
+       /* now we lookup the tag style in the cache */
+       if (tag != NULL)
+       {
+               style = g_hash_table_lookup (job->priv->tag_styles, tag);
+               if (style == NULL)
+               {
+                       /* create a style for the tag and cache it */
+                       style = text_style_new (job, tag);
+                       g_hash_table_insert (job->priv->tag_styles, tag, style);
+               }
+       }
+
+       return style;
+}
+
+/* ----- Text fetching functions */
+
+static gboolean 
+get_text_simple (GtkSourcePrintJob *job,
+                GtkTextIter       *start,
+                GtkTextIter       *end)
+{
+       GtkTextIter iter;
+
+       while (gtk_text_iter_compare (start, end) < 0)
+       {
+               Paragraph *para;
+               TextSegment *seg;
+               
+               /* get a line of text */
+               iter = *start;
+               if (!gtk_text_iter_ends_line (&iter))
+                       gtk_text_iter_forward_to_line_end (&iter);
+               
+               if (gtk_text_iter_compare (&iter, end) > 0)
+                       iter = *end;
+
+               
+               seg = g_new0 (TextSegment, 1);
+               seg->next = NULL;  /* only one segment per line, since there's no style change */
+               seg->style = NULL; /* use default style */
+               /* FIXME: handle invisible text properly.  This also
+                * assumes the text has no embedded images and
+                * stuff */
+               seg->text = gtk_text_iter_get_slice (start, &iter);
+
+               para = g_new0 (Paragraph, 1);
+               para->segment = seg;
+
+               /* add the line of text to the job */
+               job->priv->paragraphs = g_slist_prepend (job->priv->paragraphs, para);
+
+               gtk_text_iter_forward_line (&iter);
+               
+               /* advance to next line */
+               *start = iter;
+       }
+       job->priv->paragraphs = g_slist_reverse (job->priv->paragraphs);
+
+       return TRUE;
+}
+
+static gboolean 
+get_text_with_style (GtkSourcePrintJob *job,
+                    GtkTextIter       *start,
+                    GtkTextIter       *end)
+{
+       GtkTextIter limit, next_toggle;
+       gboolean have_toggle;
+       GdkPixbuf *image = NULL;
+       
+       /* make sure the region to print is highlighted */
+       /*_gtk_source_buffer_highlight_region (job->priv->buffer, start, end, TRUE); */
+
+       next_toggle = *start;
+       have_toggle = gtk_text_iter_forward_to_tag_toggle (&next_toggle, NULL);
+       
+       /* FIXME: handle invisible text properly.  This also assumes
+        * the text has no embedded images and stuff */
+       while (gtk_text_iter_compare (start, end) < 0)
+       {
+               TextStyle *style;
+               TextSegment *seg;
+               Paragraph *para;
+               
+               para = g_new0 (Paragraph, 1);
+
+               /* get the style at the start of the line */
+               style = get_style (job, start);
+
+               /* get a line of text - limit points to the end of the line */
+               limit = *start;
+               if (!gtk_text_iter_ends_line (&limit))
+                       gtk_text_iter_forward_to_line_end (&limit);
+               
+               if (gtk_text_iter_compare (&limit, end) > 0)
+                       limit = *end;
+
+               /* create the first segment for the line */
+               para->segment = seg = g_new0 (TextSegment, 1);
+               seg->style = style;
+
+               /* while the next tag toggle is within the line, we check to see
+                * if the style has changed at each tag toggle position, and if so,
+                * create new segments */
+               while (have_toggle && gtk_text_iter_compare (&next_toggle, &limit) < 0)
+               {
+                       /* check style changes */
+                       style = get_style (job, &next_toggle);
+                       if (style != seg->style)
+                       {
+                               TextSegment *new_seg;
+                               /* style has changed, thus we need to
+                                * create a new segment */
+                               /* close the current segment */
+                               seg->text = gtk_text_iter_get_slice (start, &next_toggle);
+                               if ((image = gtk_text_iter_get_pixbuf(start)) != NULL)
+                                       seg->image = image;
+                               
+                               *start = next_toggle;
+                               
+                               new_seg = g_new0 (TextSegment, 1);
+                               seg->next = new_seg;
+                               seg = new_seg;
+                               seg->style = style;
+                       }
+
+                       have_toggle = gtk_text_iter_forward_to_tag_toggle (&next_toggle, NULL);                 
+               }
+               
+               /* close the line */
+               seg->next = NULL;
+               seg->text = gtk_text_iter_get_slice (start, &limit);
+               if ((image = gtk_text_iter_get_pixbuf(start)) != NULL)
+                       seg->image = image;
+
+               /* add the line of text to the job */
+               job->priv->paragraphs = g_slist_prepend (job->priv->paragraphs, para);
+
+               /* advance to next line */
+               *start = limit;
+               gtk_text_iter_forward_line (start);
+
+               if (gtk_text_iter_compare (&next_toggle, start) < 0) {
+                       next_toggle = *start;
+                       have_toggle = gtk_text_iter_forward_to_tag_toggle (&next_toggle, NULL);
+               }
+       }
+       job->priv->paragraphs = g_slist_reverse (job->priv->paragraphs);
+
+       return TRUE;
+}
+
+static gboolean 
+get_text_to_print (GtkSourcePrintJob *job,
+                  const GtkTextIter *start,
+                  const GtkTextIter *end)
+{
+       GtkTextIter _start, _end;
+       gboolean retval;
+       
+       g_return_val_if_fail (start != NULL && end != NULL, FALSE);
+       g_return_val_if_fail (job->priv->buffer != NULL, FALSE);
+
+       _start = *start;
+       _end = *end;
+
+       /* erase any previous data */
+       if (job->priv->paragraphs != NULL)
+       {
+               free_paragraphs (job->priv->paragraphs);
+               job->priv->paragraphs = NULL;
+       }
+       if (job->priv->tag_styles != NULL)
+       {
+               g_hash_table_destroy (job->priv->tag_styles);
+               job->priv->tag_styles = NULL;
+       }
+
+       /* provide ordered iters */
+       gtk_text_iter_order (&_start, &_end);
+
+       /* save the first and last line numbers for future reference */
+       job->priv->first_line_number = gtk_text_iter_get_line (&_start) + 1;
+       job->priv->last_line_number = gtk_text_iter_get_line (&_end) + 1;
+
+       if (!job->priv->highlight)
+               retval = get_text_simple (job, &_start, &_end);
+       else
+               retval = get_text_with_style (job, &_start, &_end);
+
+       if (retval && job->priv->paragraphs == NULL)
+       {
+               Paragraph *para;
+               TextSegment *seg;
+               
+               /* add an empty line to allow printing empty documents */
+               seg = g_new0 (TextSegment, 1);
+               seg->next = NULL;
+               seg->style = NULL; /* use default style */
+               seg->text = g_strdup ("");
+
+               para = g_new0 (Paragraph, 1);
+               para->segment = seg;
+
+               job->priv->paragraphs = g_slist_prepend (job->priv->paragraphs, para);
+       }
+
+       return retval;
+}
+
+/* ----- Pagination functions */
+
+static void
+add_attribute_to_list (PangoAttribute *attr, 
+                      PangoAttrList  *list,
+                      guint           index,
+                      gsize           len)
+{
+       attr->start_index = index;
+       attr->end_index = index + len;
+       pango_attr_list_insert (list, attr);
+}
+
+static void *
+create_layout_for_para (GtkSourcePrintJob *job,
+                       Paragraph         *para,
+                       gboolean          *is_image)
+{
+       GString *text;
+       PangoLayout *layout;
+       PangoAttrList *attrs;
+       TextSegment *seg;
+       gint index;
+       GdkPixbuf *image = NULL;
+       text = g_string_new (NULL);
+       attrs = pango_attr_list_new ();
+       
+       seg = para->segment;
+       index = 0;
+
+       while (seg != NULL)
+       {
+               gsize seg_len = strlen (seg->text);
+               g_string_append (text, seg->text);
+
+               if (seg->style)
+               {
+                       PangoAttribute *attr;
+
+                       attr = pango_attr_font_desc_new (seg->style->font_desc);
+                       add_attribute_to_list (attr, attrs, index, seg_len);
+
+                       if (seg->style->scale != PANGO_SCALE_MEDIUM) 
+                       {
+                               attr = pango_attr_scale_new (seg->style->scale);
+                               add_attribute_to_list (attr, attrs, index, seg_len);
+                       }
+
+                       if (seg->style->foreground)
+                       {
+                               attr = pango_attr_foreground_new (seg->style->foreground->red,
+                                                                 seg->style->foreground->green,
+                                                                 seg->style->foreground->blue);
+                               add_attribute_to_list (attr, attrs, index, seg_len);
+                       }
+
+                       if (seg->style->background)
+                       {
+                               attr = pango_attr_background_new (seg->style->background->red,
+                                                                 seg->style->background->green,
+                                                                 seg->style->background->blue);
+                               add_attribute_to_list (attr, attrs, index, seg_len);
+                       }
+
+                       if (seg->style->strikethrough)
+                       {
+                               attr = pango_attr_strikethrough_new (TRUE);
+                               add_attribute_to_list (attr, attrs, index, seg_len);
+                       }
+
+                       if (seg->style->underline != PANGO_UNDERLINE_NONE)
+                       {
+                               attr = pango_attr_underline_new (seg->style->underline);
+                               add_attribute_to_list (attr, attrs, index, seg_len);
+                       }
+               }
+
+               if (seg->image) {
+                       image = seg->image;
+               }
+
+               index += seg_len;
+               seg = seg->next;
+       }
+
+       if (image != NULL) {
+               *is_image = TRUE;
+               return image;
+       }
+
+       layout = pango_layout_new (job->priv->pango_context);
+       
+       pango_layout_set_width (layout, job->priv->text_width * PANGO_SCALE);
+       
+       switch (job->priv->wrap_mode)   {
+       case GTK_WRAP_CHAR:
+               pango_layout_set_wrap (layout, PANGO_WRAP_CHAR);
+               break;
+       case GTK_WRAP_WORD:
+               pango_layout_set_wrap (layout, PANGO_WRAP_WORD);
+               break;
+       case GTK_WRAP_WORD_CHAR:
+               pango_layout_set_wrap (layout, PANGO_WRAP_WORD_CHAR);
+               break;
+       case GTK_WRAP_NONE:
+               /* FIXME: hack 
+                * Ellipsize the paragraph when text wrapping is disabled.
+                * Another possibility would be to set the width so the text 
+                * breaks into multiple lines, and paginate/render just the 
+                * first one.
+                * See also Comment #23 by Owen on bug #143874.
+                */
+
+               /* orph says to comment this out and commit it.
+                  PANGO_ELLIPSIZE_END is not available in pango
+                  1.4.1, at least, and he says this code is never
+                  used. */
+               /*pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END);*/
+
+               break;
+       }
+
+       if (job->priv->tab_array)
+               pango_layout_set_tabs (layout, job->priv->tab_array);
+       
+       pango_layout_set_text (layout, text->str, text->len);
+       pango_layout_set_attributes (layout, attrs);
+       *is_image = FALSE;
+
+       /* FIXME: <horrible-hack> 
+        * For empty paragraphs, pango_layout_iter_get_baseline() returns 0,
+        * so I check this condition and add a space character to force 
+        * the calculation of the baseline. I don't like that, but I
+        * didn't find a better way to do it. Note that a paragraph is 
+        * considered empty either when it has no characters, or when 
+        * it only has tabs.
+        * See comment #22 and #23 on bug #143874.
+        */
+       if (job->priv->print_numbers > 0)
+       {
+               PangoLayoutIter *iter;
+               iter = pango_layout_get_iter (layout);
+               if (pango_layout_iter_get_baseline (iter) == 0)
+               {
+                       g_string_append_c (text, ' ');
+                       pango_layout_set_text (layout, text->str, text->len);
+               }
+               pango_layout_iter_free (iter);
+       }
+       /* FIXME: </horrible-hack> */
+       
+       g_string_free (text, TRUE);
+       pango_attr_list_unref (attrs);
+
+       return layout;
+}
+
+/* The break logic in this function needs to match that in print_paragraph */
+static void
+paginate_paragraph (GtkSourcePrintJob *job,
+                   Paragraph         *para)
+{
+       PangoLayout *layout;
+       PangoLayoutIter *iter;
+       PangoRectangle logical_rect;
+       gdouble max;
+       gdouble page_skip;
+       GdkPixbuf *image;
+       void *tmp;
+       gboolean is_image = FALSE;
+       
+       tmp = create_layout_for_para (job, para, &is_image);
+       if (!is_image) {
+               layout = (PangoLayout *)tmp;
+               image  = NULL;
+       } else {
+               image  = (GdkPixbuf *)tmp;
+               layout = NULL;
+       }
+
+       if (image == NULL) {
+               iter = pango_layout_get_iter (layout);
+
+               max = 0;
+               page_skip = 0;
+
+               do
+               {
+                       pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
+                       max = (gdouble) (logical_rect.y + logical_rect.height) / PANGO_SCALE;
+
+                       if (max - page_skip > job->priv->available_height)
+                       {
+                               /* "create" a new page */
+                               job->priv->page_count++;
+                               job->priv->available_height = job->priv->text_height;
+                               page_skip = (gdouble) logical_rect.y / PANGO_SCALE;
+                       }
+
+               }
+               while (pango_layout_iter_next_line (iter));
+               job->priv->available_height -= max - page_skip;
+               pango_layout_iter_free (iter);
+               g_object_unref (layout);
+       } else {
+               gint max_height = job->priv->available_height;
+               gint image_height = gdk_pixbuf_get_height(image);
+               gint image_width = gdk_pixbuf_get_width(image);
+               gint scaled_height = 0, scaled_width = 0;
+               image_viewer_get_resized_size(image_width,
+                                        image_height,
+                                        job->priv->text_width, 
+                                        job->priv->text_height,
+                                        &scaled_width, &scaled_height);
+               if (scaled_height > max_height) {
+                       job->priv->page_count++;
+                       job->priv->available_height = job->priv->text_height - scaled_height;
+               } else {
+                       job->priv->available_height -= scaled_height;
+               }
+       }
+
+}
+
+static gboolean 
+paginate_text (GtkSourcePrintJob *job)
+{
+       GSList *l;
+       guint line_number;
+       
+       /* set these to zero so the first break_line creates a new page */
+       job->priv->page_count = 0;
+       job->priv->available_height = 0;
+       line_number = job->priv->first_line_number;
+       l = job->priv->paragraphs;
+       while (l != NULL)
+       {
+               Paragraph *para = l->data;
+
+               para->line_number = line_number;
+               paginate_paragraph (job, para);
+               
+               line_number++;
+               l = g_slist_next (l);
+       }
+
+       /* FIXME: do we have any error condition which can force us to
+        * return %FALSE? - Gustavo */
+       return TRUE;
+}
+
+/* ---- Printing functions */
+
+static void
+begin_page (GtkSourcePrintJob *job)
+{
+       gnome_print_beginpage (job->priv->print_ctxt, NULL);
+
+       g_signal_emit (job, print_job_signals [BEGIN_PAGE], 0);
+}
+
+static void
+end_page (GtkSourcePrintJob *job)
+{
+       gnome_print_showpage (job->priv->print_ctxt);
+}
+
+static void 
+print_line_number (GtkSourcePrintJob *job,
+                  guint              line_number,
+                  gdouble            x,
+                  gdouble            y)
+{
+       PangoLayout *layout;
+
+       layout = get_line_number_layout (job, line_number);
+
+       x = x + job->priv->numbers_width - get_layout_width (layout) - NUMBERS_TEXT_SEPARATION;
+       gnome_print_moveto (job->priv->print_ctxt, x, y);
+       
+       show_first_layout_line (job->priv->print_ctxt, layout);
+       
+       g_object_unref (layout);
+}      
+
+/* The break logic in this function needs to match that in paginate_paragraph
+ *
+ * @start_line is the first line in the paragraph to print
+ * @y is updated to the position after the portion of the paragraph we printed
+ * @baseline_out is set to the baseline of the first line of the paragraph
+ *   if we printed it. (And not set otherwise)
+ * 
+ * Returns the first unprinted line in the paragraph (unprinted because it
+ * flowed onto the next page) or -1 if the entire paragraph was printed.
+ */
+static gint
+print_paragraph (GtkSourcePrintJob *job,
+                Paragraph         *para,
+                gint               start_line,
+                gdouble            x,
+                gdouble           *y,
+                gdouble           *baseline_out,
+                gboolean           force_fit)
+{
+       PangoLayout *layout;
+       PangoLayoutIter *iter;
+       PangoRectangle logical_rect;
+       int current_line;
+       gdouble max;
+       gdouble page_skip;
+       gdouble baseline;
+       int result = -1;
+       GdkPixbuf *image;
+       void *tmp;
+       gboolean is_image;
+
+       tmp = create_layout_for_para (job, para, &is_image);
+       if (!is_image) {
+               layout = (PangoLayout *)tmp;
+               image  = NULL;
+       } else {
+               image  = (GdkPixbuf *)tmp;
+               layout = NULL;
+       }
+
+       if (!is_image) {
+               iter = pango_layout_get_iter (layout);
+
+               /* Skip over lines already printed on previous page(s) */
+               for (current_line = 0; current_line < start_line; current_line++)
+                       pango_layout_iter_next_line (iter);
+
+               max = 0;
+               page_skip = 0;
+
+               do
+               {
+                       pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
+                       max = (gdouble) (logical_rect.y + logical_rect.height) / PANGO_SCALE;
+
+                       if (current_line == start_line)
+                               page_skip = (gdouble) logical_rect.y / PANGO_SCALE;
+
+                       if (max - page_skip > job->priv->available_height)
+                       {
+                               result = current_line; /* Save position for next page */
+                               break;
+                       }
+
+                       baseline = (gdouble) pango_layout_iter_get_baseline (iter) / PANGO_SCALE;
+                       baseline = *y + page_skip - baseline; /* Adjust to global coordinates */
+                       if (current_line == 0)
+                               *baseline_out = baseline;
+
+                       gnome_print_moveto (job->priv->print_ctxt,
+                                           x + (gdouble) logical_rect.x / PANGO_SCALE,
+                                           baseline);
+                       gnome_print_pango_layout_line (job->priv->print_ctxt,
+                                                      pango_layout_iter_get_line (iter));
+
+                       current_line++;
+               }
+               while (pango_layout_iter_next_line (iter));
+
+               job->priv->available_height -= max - page_skip;
+               *y -= max - page_skip;
+
+               pango_layout_iter_free (iter);
+               g_object_unref (layout);
+       } else {
+               gint max_height = job->priv->available_height;
+               gint image_height = gdk_pixbuf_get_height(image);
+               gint image_width = gdk_pixbuf_get_width(image);
+               gint scaled_height = 0, scaled_width = 0;
+               GdkPixbuf *scaled_image = NULL;
+               image_viewer_get_resized_size(image_width,
+                                        image_height,
+                                        job->priv->text_width, 
+                                        job->priv->text_height,
+                                        &scaled_width, &scaled_height);
+
+               if (scaled_height > max_height) {
+                       /* next page */
+                       return 0;
+               } else {
+                       scaled_image = gdk_pixbuf_scale_simple
+                                       (image, scaled_width, scaled_height, 
+                                        GDK_INTERP_BILINEAR);
+
+                       gnome_print_moveto(job->priv->print_ctxt,
+                                           x, (gdouble)*y);
+                       gnome_print_gsave(job->priv->print_ctxt);
+                       gnome_print_translate(job->priv->print_ctxt, 
+                                             x, *y - scaled_height);
+                       gnome_print_scale(job->priv->print_ctxt, 
+                                         scaled_width,
+                                         scaled_height);
+
+                       if (gdk_pixbuf_get_has_alpha(image))
+                               gnome_print_rgbaimage  (job->priv->print_ctxt,
+                                                       gdk_pixbuf_get_pixels    (scaled_image),
+                                                       gdk_pixbuf_get_width     (scaled_image),
+                                                       gdk_pixbuf_get_height    (scaled_image),
+                                                       gdk_pixbuf_get_rowstride (scaled_image));
+                       else
+                               gnome_print_rgbimage  (job->priv->print_ctxt,
+                                                      gdk_pixbuf_get_pixels    (scaled_image),
+                                                      gdk_pixbuf_get_width     (scaled_image),
+                                                      gdk_pixbuf_get_height    (scaled_image),
+                                                      gdk_pixbuf_get_rowstride (scaled_image));
+                       g_object_unref(scaled_image);
+                       gnome_print_grestore(job->priv->print_ctxt);
+
+                       job->priv->available_height -= scaled_height;
+                       *y -= scaled_height;
+                       return -1;
+
+               }
+       }
+       return result;
+}
+
+static void
+print_page (GtkSourcePrintJob *job)
+{
+       GSList *l;
+       gdouble x, y;
+       gint line;
+       gboolean force_fit = TRUE;
+       
+       job->priv->page++;
+       
+       
+       begin_page (job);
+       job->priv->available_height = job->priv->text_height;
+
+       y = job->priv->page_height -
+               job->priv->doc_margin_top - job->priv->margin_top -
+               job->priv->header_height;
+       x = job->priv->doc_margin_left + job->priv->margin_left +
+               job->priv->numbers_width;
+       l = job->priv->current_paragraph;
+       line = job->priv->current_paragraph_line;
+
+       while (l != NULL)
+       {
+               Paragraph *para = l->data;
+               gdouble baseline = 0;
+               gint last_line = line;
+               
+               line = print_paragraph (job, para, line, x, &y, &baseline, force_fit);
+
+               if (last_line == 0 && line != 0)
+               {
+                       /* We printed the first line of a paragraph */
+                       if (job->priv->print_numbers > 0 &&
+                           ((para->line_number % job->priv->print_numbers) == 0))
+                               print_line_number (job,
+                                                  para->line_number,
+                                                  job->priv->doc_margin_left +
+                                                  job->priv->margin_left,
+                                                  baseline);
+
+                       job->priv->printed_lines++;
+               }
+
+               if (line >= 0)
+                       break;  /* Didn't all fit on this page */
+               
+               l = l->next;
+               line = 0;
+               force_fit = FALSE;
+       }
+       end_page (job);
+       job->priv->current_paragraph = l;
+       job->priv->current_paragraph_line = line;
+}
+
+static void
+setup_for_print (GtkSourcePrintJob *job)
+{
+       job->priv->current_paragraph = job->priv->paragraphs;
+       job->priv->page = 0;
+       job->priv->printed_lines = 0;
+
+       if (job->priv->print_job != NULL)
+               g_object_unref (job->priv->print_job);
+       if (job->priv->print_ctxt != NULL)
+               g_object_unref (job->priv->print_ctxt);
+       
+       job->priv->print_job = gnome_print_job_new (job->priv->config);
+       job->priv->print_ctxt = gnome_print_job_get_context (job->priv->print_job);
+
+       gnome_print_pango_update_context (job->priv->pango_context, job->priv->print_ctxt);
+}
+
+static void
+print_job (GtkSourcePrintJob *job)
+{
+       while (job->priv->current_paragraph != NULL)
+               print_page (job);
+
+       gnome_print_job_close (job->priv->print_job);
+}
+
+static gboolean
+idle_printing_handler (GtkSourcePrintJob *job)
+{
+       g_assert (job->priv->current_paragraph != NULL);
+
+       print_page (job);
+
+       if (job->priv->current_paragraph == NULL)
+       {
+               gnome_print_job_close (job->priv->print_job);
+               job->priv->printing = FALSE;
+               job->priv->idle_printing_tag = 0;
+
+               g_signal_emit (job, print_job_signals [FINISHED], 0);
+               /* after this the print job object is possibly
+                * destroyed (common use case) */
+               
+               return FALSE;
+       }
+       return TRUE;
+}
+
+
+/* Public API ------------------- */
+
+/**
+ * gtk_source_print_job_new:
+ * @config: an optional #GnomePrintConfig object.
+ * 
+ * Creates a new print job object, initially setting the print configuration.
+ * 
+ * Return value: the new print job object.
+ **/
+GtkSourcePrintJob *
+gtk_source_print_job_new (GnomePrintConfig  *config)
+{
+       GtkSourcePrintJob *job;
+
+       g_return_val_if_fail (config == NULL || GNOME_IS_PRINT_CONFIG (config), NULL);
+
+       job = GTK_SOURCE_PRINT_JOB (g_object_new (GTK_TYPE_SOURCE_PRINT_JOB, NULL));
+       if (config != NULL)
+               gtk_source_print_job_set_config (job, config);
+
+       return job;
+}
+
+/**
+ * gtk_source_print_job_new_with_buffer:
+ * @config: an optional #GnomePrintConfig.
+ * @buffer: the #GtkTextBuffer to print (might be %NULL).
+ * 
+ * Creates a new print job to print @buffer.
+ * 
+ * Return value: a new print job object.
+ **/
+GtkSourcePrintJob *
+gtk_source_print_job_new_with_buffer (GnomePrintConfig  *config,
+                                     GtkTextBuffer   *buffer)
+{
+       GtkSourcePrintJob *job;
+
+       g_return_val_if_fail (config == NULL || GNOME_IS_PRINT_CONFIG (config), NULL);
+       g_return_val_if_fail (buffer == NULL || GTK_IS_TEXT_BUFFER (buffer), NULL);
+
+       job = gtk_source_print_job_new (config);
+       if (buffer != NULL)
+               gtk_source_print_job_set_buffer (job, buffer);
+
+       return job;
+}
+
+/* --- print job basic configuration */
+
+/**
+ * gtk_source_print_job_set_config:
+ * @job: a #GtkSourcePrintJob.
+ * @config: a #GnomePrintConfig object to get printing configuration from.
+ * 
+ * Sets the print configuration for the job.  If you don't set a
+ * configuration object for the print job, when needed one will be
+ * created with gnome_print_config_default().
+ **/
+void
+gtk_source_print_job_set_config (GtkSourcePrintJob *job,
+                                GnomePrintConfig  *config)
+{
+       g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
+       g_return_if_fail (GNOME_IS_PRINT_CONFIG (config));
+       g_return_if_fail (!job->priv->printing);
+       
+       if (config == job->priv->config)
+               return;
+       
+       if (job->priv->config != NULL)
+               gnome_print_config_unref (job->priv->config);
+
+       job->priv->config = config;
+       gnome_print_config_ref (config);
+
+       g_object_notify (G_OBJECT (job), "config");
+}
+
+/**
+ * gtk_source_print_job_get_config:
+ * @job: a #GtkSourcePrintJob.
+ * 
+ * Gets the current #GnomePrintConfig the print job will use.  If not
+ * previously set, this will create a default configuration and return
+ * it.  The returned object reference is owned by the print job.
+ * 
+ * Return value: the #GnomePrintConfig for the print job.
+ **/
+GnomePrintConfig * 
+gtk_source_print_job_get_config (GtkSourcePrintJob *job)
+{
+       g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), NULL);
+
+       ensure_print_config (job);
+       
+       return job->priv->config;
+}
+
+/**
+ * gtk_source_print_job_set_buffer:
+ * @job: a #GtkSourcePrintJob.
+ * @buffer: a #GtkTextBuffer.
+ * 
+ * Sets the #GtkTextBuffer the print job will print.  You need to
+ * specify a buffer to print, either by the use of this function or by
+ * creating the print job with gtk_source_print_job_new_with_buffer().
+ **/
+void 
+gtk_source_print_job_set_buffer (GtkSourcePrintJob *job,
+                                GtkTextBuffer   *buffer)
+{
+       g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
+       g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
+       g_return_if_fail (!job->priv->printing);
+
+       if (buffer == job->priv->buffer)
+               return;
+       
+       if (job->priv->buffer != NULL)
+               g_object_unref (job->priv->buffer);
+
+       job->priv->buffer = buffer;
+       g_object_ref (buffer);
+
+       g_object_notify (G_OBJECT (job), "buffer");
+}
+
+/**
+ * gtk_source_print_job_get_buffer:
+ * @job: a #GtkSourcePrintJob.
+ * 
+ * Gets the #GtkTextBuffer the print job would print.  The returned
+ * object reference (if non %NULL) is owned by the job object and
+ * should not be unreferenced.
+ * 
+ * Return value: the #GtkTextBuffer to print.
+ **/
+GtkTextBuffer *
+gtk_source_print_job_get_buffer (GtkSourcePrintJob *job)
+{
+       g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), NULL);
+
+       return job->priv->buffer;
+}
+
+/* --- print job layout and style configuration */
+
+/**
+ * gtk_source_print_job_set_tabs_width:
+ * @job: a #GtkSourcePrintJob.
+ * @tabs_width: the number of equivalent spaces for a tabulation.
+ * 
+ * Sets the width (in equivalent spaces) of tabulations for the
+ * printed text.  The width in printing units will be calculated as
+ * the width of a string containing @tabs_width spaces of the default
+ * font.  Tabulation stops are set for the full width of printed text.
+ **/
+void 
+gtk_source_print_job_set_tabs_width (GtkSourcePrintJob *job,
+                                    guint              tabs_width)
+{
+       g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
+       g_return_if_fail (!job->priv->printing);
+
+       if (tabs_width == job->priv->tabs_width)
+               return;
+       
+       job->priv->tabs_width = tabs_width;
+
+       g_object_notify (G_OBJECT (job), "tabs_width");
+}
+
+/**
+ * gtk_source_print_job_get_tabs_width:
+ * @job: a #GtkSourcePrintJob.
+ * 
+ * Determines the configured width (in equivalent spaces) of
+ * tabulations.  The default value is 8.
+ * 
+ * Return value: the width (in equivalent spaces) of a tabulation.
+ **/
+guint 
+gtk_source_print_job_get_tabs_width (GtkSourcePrintJob *job)
+{
+       g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), 0);
+
+       return job->priv->tabs_width;
+}
+
+/**
+ * gtk_source_print_job_set_wrap_mode:
+ * @job: a #GtkSourcePrintJob.
+ * @wrap: the wrap mode.
+ * 
+ * Sets the wrap mode for lines of text larger than the printable
+ * width.  See #GtkWrapMode for a definition of the possible values.
+ **/
+void 
+gtk_source_print_job_set_wrap_mode (GtkSourcePrintJob *job,
+                                   GtkWrapMode        wrap)
+{
+       g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
+       g_return_if_fail (!job->priv->printing);
+
+       if (wrap == job->priv->wrap_mode)
+               return;
+       
+       job->priv->wrap_mode = wrap;
+
+       g_object_notify (G_OBJECT (job), "wrap_mode");
+}
+
+/**
+ * gtk_source_print_job_get_wrap_mode:
+ * @job: a #GtkSourcePrintJob.
+ * 
+ * Determines the wrapping style for text lines wider than the
+ * printable width.  The default is no wrapping.
+ * 
+ * Return value: the current wrapping mode for the print job.
+ **/
+GtkWrapMode 
+gtk_source_print_job_get_wrap_mode (GtkSourcePrintJob *job)
+{
+       g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), GTK_WRAP_NONE);
+
+       return job->priv->wrap_mode;
+}
+
+/**
+ * gtk_source_print_job_set_highlight:
+ * @job: a #GtkSourcePrintJob.
+ * @highlight: %TRUE if the printed text should be highlighted.
+ * 
+ * Sets whether the printed text will be highlighted according to the
+ * buffer rules.  Both color and font style are applied.
+ **/
+void 
+gtk_source_print_job_set_highlight (GtkSourcePrintJob *job,
+                                   gboolean           highlight)
+{
+       g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
+       g_return_if_fail (!job->priv->printing);
+
+       highlight = (highlight != FALSE);
+       
+       if (highlight == job->priv->highlight)
+               return;
+       
+       job->priv->highlight = highlight;
+
+       g_object_notify (G_OBJECT (job), "highlight");
+}
+
+/**
+ * gtk_source_print_job_get_highlight:
+ * @job: a #GtkSourcePrintJob.
+ * 
+ * Determines if the job is configured to print the text highlighted
+ * with colors and font styles.  Note that highlighting will happen
+ * only if the buffer to print has highlighting activated.
+ * 
+ * Return value: %TRUE if the printed output will be highlighted.
+ **/
+gboolean 
+gtk_source_print_job_get_highlight (GtkSourcePrintJob *job)
+{
+       g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), FALSE);
+
+       return job->priv->highlight;
+}
+
+/**
+ * gtk_source_print_job_set_font_desc:
+ * @job: a #GtkSourcePrintJob.
+ * @desc: the #PangoFontDescription for the default font
+ * 
+ * Sets the default font for the printed text.
+ **/
+void 
+gtk_source_print_job_set_font_desc (GtkSourcePrintJob    *job,
+                                   PangoFontDescription *desc)
+{
+       g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
+       g_return_if_fail (desc != NULL);
+       g_return_if_fail (!job->priv->printing);
+
+       desc = pango_font_description_copy (desc);
+       if (job->priv->font != NULL)
+               pango_font_description_free (job->priv->font);
+       job->priv->font = desc;
+       g_object_freeze_notify (G_OBJECT (job));
+       g_object_notify (G_OBJECT (job), "font");
+       g_object_notify (G_OBJECT (job), "font_desc");
+       g_object_thaw_notify (G_OBJECT (job));
+}
+
+/**
+ * gtk_source_print_job_set_font:
+ * @job: a #GtkSourcePrintJob.
+ * @font_name: the name of the default font.
+ * 
+ * Sets the default font for the printed text.  @font_name should be a
+ * <emphasis>full font name</emphasis> GnomePrint can understand
+ * (e.g. &quot;Monospace Regular 10.0&quot;).
+ *
+ * Note that @font_name is a #GnomeFont name not a Pango font
+ * description string. This function is deprecated since #GnomeFont is
+ * no longer used when implementing printing for GtkSourceView; you
+ * should use gtk_source_print_job_set_font_desc() instead.
+ **/
+void 
+gtk_source_print_job_set_font (GtkSourcePrintJob *job,
+                              const gchar       *font_name)
+{
+       PangoFontDescription *desc;
+       
+       g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
+       g_return_if_fail (font_name != NULL);
+       g_return_if_fail (!job->priv->printing);
+
+       desc = font_description_from_gnome_font_name (font_name);
+       if (desc)
+       {
+               gtk_source_print_job_set_font_desc (job, desc);
+               pango_font_description_free (desc);
+       }
+}
+
+/**
+ * gtk_source_print_job_get_font_desc:
+ * @job: a #GtkSourcePrintJob.
+ * 
+ * Determines the default font to be used for the printed text.  The
+ * returned string is of the form &quot;Fontfamily Style Size&quot;,
+ * for example &quot;Monospace Regular 10.0&quot;.  The returned value
+ * should be freed when no longer needed.
+ * 
+ * Return value: the current text font description. This value is
+ *  owned by the job and must not be modified or freed.
+ **/
+PangoFontDescription *
+gtk_source_print_job_get_font_desc (GtkSourcePrintJob *job)
+{
+       g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), NULL);
+
+       ensure_print_config (job);
+       
+       return job->priv->font;
+}
+
+/**
+ * gtk_source_print_job_get_font:
+ * @job: a #GtkSourcePrintJob.
+ * 
+ * Determines the default font to be used for the printed text.  The
+ * returned string is of the form &quot;Fontfamily Style Size&quot;,
+ * for example &quot;Monospace Regular 10.0&quot;.  The returned value
+ * should be freed when no longer needed.
+ * 
+ * Note that the result is a #GnomeFont name not a Pango font
+ * description string. This function is deprecated since #GnomeFont is
+ * no longer used when implementing printing for GtkSourceView; you
+ * should use gtk_source_print_job_get_font_desc() instead.
+ *
+ * Return value: a newly allocated string with the name of the current
+ * text font.
+ **/
+gchar *
+gtk_source_print_job_get_font (GtkSourcePrintJob *job)
+{
+       g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), NULL);
+
+       ensure_print_config (job);
+       
+       return font_description_to_gnome_font_name (job->priv->font);
+}
+
+/**
+ * gtk_source_print_job_setup_from_view:
+ * @job: a #GtkSourcePrintJob.
+ * @view: a #GtkSourceView to get configuration from.
+ * 
+ * Convenience function to set several configuration options at once,
+ * so that the printed output matches @view.  The options set are
+ * buffer (if not set already), tabs width, highlighting, wrap mode
+ * and default font.
+ **/
+void 
+gtk_source_print_job_setup_from_view (GtkSourcePrintJob *job,
+                                     GtkTextView       *view)
+{
+       GtkTextBuffer *buffer = NULL;
+       PangoContext *pango_context;
+       
+       g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
+       g_return_if_fail (!job->priv->printing);
+
+       buffer = gtk_text_view_get_buffer (view);
+       
+       if (job->priv->buffer == NULL && buffer != NULL)
+               gtk_source_print_job_set_buffer (job, buffer);
+
+       /* gtk_source_print_job_set_tabs_width (job, gtk_source_view_get_tabs_width (view)); */
+       gtk_source_print_job_set_highlight (job, TRUE);
+       gtk_source_print_job_set_wrap_mode (job, gtk_text_view_get_wrap_mode (view));
+
+       pango_context = gtk_widget_get_pango_context (GTK_WIDGET (view));
+       gtk_source_print_job_set_font_desc (job, 
+                                           pango_context_get_font_description (pango_context));
+}
+
+/**
+ * gtk_source_print_job_set_numbers_font_desc:
+ * @job: a #GtkSourcePrintJob.
+ * @desc: the #PangoFontDescription for the font for line numbers, or %NULL
+ * 
+ * Sets the font for printing line numbers on the left margin.  If
+ * NULL is supplied, the default font (i.e. the one being used for the
+ * text) will be used instead.
+ **/
+void 
+gtk_source_print_job_set_numbers_font_desc (GtkSourcePrintJob    *job,
+                                           PangoFontDescription *desc)
+{
+       g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
+       g_return_if_fail (!job->priv->printing);
+       
+       if (desc)
+               desc = pango_font_description_copy (desc);
+       if (job->priv->numbers_font != NULL)
+               pango_font_description_free (job->priv->numbers_font);
+       job->priv->numbers_font = desc;
+       g_object_freeze_notify (G_OBJECT (job));
+       g_object_notify (G_OBJECT (job), "numbers_font");
+       g_object_notify (G_OBJECT (job), "numbers_font_desc");
+       g_object_thaw_notify (G_OBJECT (job));
+}
+
+/**
+ * gtk_source_print_job_set_numbers_font:
+ * @job: a #GtkSourcePrintJob.
+ * @font_name: the full name of the font for line numbers, or %NULL.
+ * 
+ * Sets the font for printing line numbers on the left margin.  If
+ * %NULL is supplied, the default font (i.e. the one being used for the
+ * text) will be used instead.
+ *
+ * Note that @font_name is a #GnomeFont name not a Pango font
+ * description string. This function is deprecated since #GnomeFont is
+ * no longer used when implementing printing for GtkSourceView; you
+ * should use gtk_source_print_job_set_numbers_font_desc() instead.
+ **/
+void 
+gtk_source_print_job_set_numbers_font (GtkSourcePrintJob *job,
+                                      const gchar       *font_name)
+{
+       PangoFontDescription *desc;
+       
+       g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
+       g_return_if_fail (!job->priv->printing);
+
+       if (font_name != NULL)
+       {
+               desc = font_description_from_gnome_font_name (font_name);
+               if (desc)
+               {
+                       gtk_source_print_job_set_numbers_font_desc (job, desc);
+                       pango_font_description_free (desc);
+               }
+       }
+       else
+               gtk_source_print_job_set_numbers_font (job, NULL);
+}
+
+/**
+ * gtk_source_print_job_get_numbers_font_desc:
+ * @job: a #GtkSourcePrintJob.
+ * 
+ * Determines the font to be used for the line numbers. This function
+ * might return %NULL if a specific font for numbers has not been set.
+ * 
+ * Return value: the line numbers font description or %NULL. This value is
+ * owned by the job and must not be modified or freed.
+ **/
+PangoFontDescription *
+gtk_source_print_job_get_numbers_font_desc (GtkSourcePrintJob *job)
+{
+       g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), NULL);
+
+       return job->priv->numbers_font;
+}
+
+/**
+ * gtk_source_print_job_get_numbers_font:
+ * @job: a #GtkSourcePrintJob.
+ * 
+ * Determines the font to be used for the line numbers.  The returned
+ * string is of the form &quot;Fontfamily Style Size&quot;, for
+ * example &quot;Monospace Regular 10.0&quot;.  The returned value
+ * should be freed when no longer needed.  This function might return
+ * %NULL if a specific font for numbers has not been set.
+ * 
+ * Note that the result is a #GnomeFont name not a Pango font
+ * description string. This function is deprecated since #GnomeFont is
+ * no longer used when implementing printing for GtkSourceView; you
+ * should use gtk_source_print_job_get_numbers_font_desc() instead.
+ *
+ * Return value: a newly allocated string with the name of the current
+ * line numbers font, or %NULL.
+ **/
+gchar *
+gtk_source_print_job_get_numbers_font (GtkSourcePrintJob *job)
+{
+       g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), NULL);
+
+       if (job->priv->numbers_font != NULL)
+               return font_description_to_gnome_font_name (job->priv->numbers_font);
+       else
+               return NULL;
+}
+
+/**
+ * gtk_source_print_job_set_print_numbers:
+ * @job: a #GtkSourcePrintJob.
+ * @interval: interval for printed line numbers.
+ * 
+ * Sets the interval for printed line numbers.  If @interval is 0 no
+ * numbers will be printed.  If greater than 0, a number will be
+ * printed every @interval lines (i.e. 1 will print all line numbers).
+ **/
+void 
+gtk_source_print_job_set_print_numbers (GtkSourcePrintJob *job,
+                                       guint              interval)
+{
+       g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
+       g_return_if_fail (!job->priv->printing);
+
+       if (interval == job->priv->print_numbers)
+               return;
+       
+       job->priv->print_numbers = interval;
+
+       g_object_notify (G_OBJECT (job), "print_numbers");
+}
+
+/**
+ * gtk_source_print_job_get_print_numbers:
+ * @job: a #GtkSourcePrintJob.
+ * 
+ * Determines the interval used for line number printing.  If the
+ * value is 0, no line numbers will be printed.  The default value is
+ * 1 (i.e. numbers printed in all lines).
+ * 
+ * Return value: the interval of printed line numbers.
+ **/
+guint 
+gtk_source_print_job_get_print_numbers (GtkSourcePrintJob *job)
+{
+       g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), 0);
+
+       return job->priv->print_numbers;
+}
+
+/**
+ * gtk_source_print_job_set_text_margins:
+ * @job: a #GtkSourcePrintJob.
+ * @top: the top user margin.
+ * @bottom: the bottom user margin.
+ * @left: the left user margin.
+ * @right: the right user margin.
+ * 
+ * Sets the four user margins for the print job.  These margins are in
+ * addition to the document margins provided in the #GnomePrintConfig
+ * and will not be used for headers, footers or line numbers (those
+ * are calculated separatedly).  You can print in the space allocated
+ * by these margins by connecting to the <link
+ * linkend="GtkSourcePrintJob-begin-page">&quot;begin_page&quot;</link> signal.  The
+ * space is around the printed text, and inside the margins specified
+ * in the #GnomePrintConfig.
+ *
+ * The margin numbers are given in device units.  If any of the given
+ * values is less than 0, that particular margin is not altered by
+ * this function.
+ **/
+void 
+gtk_source_print_job_set_text_margins (GtkSourcePrintJob *job,
+                                      gdouble            top,
+                                      gdouble            bottom,
+                                      gdouble            left,
+                                      gdouble            right)
+{
+       g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
+       g_return_if_fail (!job->priv->printing);
+
+       if (top >= 0)
+               job->priv->margin_top = top;
+       if (bottom >= 0)
+               job->priv->margin_bottom = bottom;
+       if (left >= 0)
+               job->priv->margin_left = left;
+       if (right >= 0)
+               job->priv->margin_right = right;
+}
+
+/**
+ * gtk_source_print_job_get_text_margins:
+ * @job: a #GtkSourcePrintJob.
+ * @top: a pointer to a #gdouble to return the top margin.
+ * @bottom: a pointer to a #gdouble to return the bottom margin.
+ * @left: a pointer to a #gdouble to return the left margin.
+ * @right: a pointer to a #gdouble to return the right margin.
+ * 
+ * Determines the user set margins for the job.  This function
+ * retrieves the values previously set by
+ * gtk_source_print_job_set_text_margins().  The default for all four
+ * margins is 0.  Any of the pointers can be %NULL if you want to
+ * ignore that value.
+ **/
+void 
+gtk_source_print_job_get_text_margins (GtkSourcePrintJob *job,
+                                      gdouble           *top,
+                                      gdouble           *bottom,
+                                      gdouble           *left,
+                                      gdouble           *right)
+{
+       g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
+
+       if (top != NULL)
+               *top = job->priv->margin_top;
+       if (bottom != NULL)
+               *bottom = job->priv->margin_bottom;
+       if (left != NULL)
+               *left = job->priv->margin_left;
+       if (right != NULL)
+               *right = job->priv->margin_right;
+}
+
+/* --- printing operations */
+
+static gboolean
+gtk_source_print_job_prepare (GtkSourcePrintJob *job,
+                             const GtkTextIter *start,
+                             const GtkTextIter *end)
+{
+       PROFILE (GTimer *timer);
+       
+       g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), FALSE);
+       g_return_val_if_fail (!job->priv->printing, FALSE);
+       g_return_val_if_fail (job->priv->buffer != NULL, FALSE);
+       g_return_val_if_fail (start != NULL && end != NULL, FALSE);
+
+       /* make sure we have a sane configuration to start printing */
+       ensure_print_config (job);
+
+       PROFILE (timer = g_timer_new ());
+
+       /* get the text to print */
+       if (!get_text_to_print (job, start, end))
+               return FALSE;
+
+       PROFILE (g_message ("get_text_to_print: %.2f", g_timer_elapsed (timer, NULL)));
+
+       if (!setup_pango_context (job))
+               return FALSE;
+
+       /* check margins */
+       if (!update_page_size_and_margins (job))
+               return FALSE;
+
+       /* split the document in pages */
+       if (!paginate_text (job))
+               return FALSE;
+
+       PROFILE ({
+               g_message ("paginate_text: %.2f", g_timer_elapsed (timer, NULL));
+               g_timer_destroy (timer);
+       });
+
+       return TRUE;
+}
+
+/**
+ * gtk_source_print_job_print:
+ * @job: a configured #GtkSourcePrintJob.
+ * 
+ * Produces a #GnomePrintJob with the printed document.  The whole
+ * contents of the configured #GtkTextBuffer are printed.  The
+ * returned job is already closed and ready to be previewed (using
+ * gnome_print_job_preview_new()) or printed directly.  The caller of
+ * this function owns a reference to the returned object, so @job can
+ * be destroyed and the output will still be valid, or the document
+ * can be printed again with different settings.
+ * 
+ * Return value: a closed #GnomePrintJob with the printed document, or
+ * %NULL if printing could not be completed.
+ **/
+GnomePrintJob *
+gtk_source_print_job_print (GtkSourcePrintJob *job)
+{
+       GtkTextIter start, end;
+
+       g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), NULL);
+       g_return_val_if_fail (!job->priv->printing, NULL);
+       g_return_val_if_fail (job->priv->buffer != NULL, NULL);
+
+       gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (job->priv->buffer), &start, &end);
+
+       return gtk_source_print_job_print_range (job, &start, &end);
+}
+
+/**
+ * gtk_source_print_job_print_range:
+ * @job: a configured #GtkSourcePrintJob.
+ * @start: the start of the region of text to print.
+ * @end: the end of the region of text to print.
+ * 
+ * Similar to gtk_source_print_job_print(), except you can specify a
+ * range of text to print.  The passed #GtkTextIter values might be
+ * out of order.
+ * 
+ * Return value: a closed #GnomePrintJob with the text from @start to
+ * @end printed, or %NULL if @job could not print.
+ **/
+GnomePrintJob *
+gtk_source_print_job_print_range (GtkSourcePrintJob *job,
+                                 const GtkTextIter *start,
+                                 const GtkTextIter *end)
+{
+       g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), NULL);
+       g_return_val_if_fail (!job->priv->printing, NULL);
+       g_return_val_if_fail (job->priv->buffer != NULL, NULL);
+       g_return_val_if_fail (start != NULL && end != NULL, NULL);
+       g_return_val_if_fail (gtk_text_iter_get_buffer (start) ==
+                             GTK_TEXT_BUFFER (job->priv->buffer) &&
+                             gtk_text_iter_get_buffer (end) ==
+                             GTK_TEXT_BUFFER (job->priv->buffer), NULL);
+
+       if (!gtk_source_print_job_prepare (job, start, end))
+               return NULL;
+
+       /* real work starts here */
+       setup_for_print (job);
+
+       job->priv->printing = TRUE;
+       print_job (job);
+       job->priv->printing = FALSE;
+
+       g_object_ref (job->priv->print_job);
+       return job->priv->print_job;
+}
+
+/* --- asynchronous printing */
+
+/**
+ * gtk_source_print_job_print_range_async:
+ * @job: a configured #GtkSourcePrintJob.
+ * @start: the start of the region of text to print.
+ * @end: the end of the region of text to print.
+ * 
+ * Starts to print @job asynchronously.  This function will ready the
+ * @job for printing and install an idle handler that will render one
+ * page at a time.
+ *
+ * This function will not return immediatly, as only page rendering is
+ * done asynchronously.  Text retrieval and paginating happens within
+ * this function.  Also, if highlighting is enabled, the whole buffer
+ * needs to be highlighted first.
+ *
+ * To get notification when the job has finished, you must connect to
+ * the <link
+ * linkend="GtkSourcePrintJob-finished">&quot;finished&quot;</link>
+ * signal.  After this signal is emitted you can retrieve the
+ * resulting #GnomePrintJob with gtk_source_print_job_get_print_job().
+ * You may cancel the job with gtk_source_print_job_cancel().
+ *
+ * Return value: %TRUE if the print started.
+ **/
+gboolean 
+gtk_source_print_job_print_range_async (GtkSourcePrintJob *job,
+                                       const GtkTextIter *start,
+                                       const GtkTextIter *end)
+{
+       GSource *idle_source;
+
+       g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), FALSE);
+       g_return_val_if_fail (!job->priv->printing, FALSE);
+       g_return_val_if_fail (job->priv->buffer != NULL, FALSE);
+       g_return_val_if_fail (start != NULL && end != NULL, FALSE);
+       g_return_val_if_fail (gtk_text_iter_get_buffer (start) ==
+                             GTK_TEXT_BUFFER (job->priv->buffer) &&
+                             gtk_text_iter_get_buffer (end) ==
+                             GTK_TEXT_BUFFER (job->priv->buffer), FALSE);
+
+       if (!gtk_source_print_job_prepare (job, start, end))
+               return FALSE;
+
+       /* real work starts here */
+       setup_for_print (job);
+       if (job->priv->current_paragraph == NULL)
+               return FALSE;
+       
+       /* setup the idle handler to print each page at a time */
+       idle_source = g_idle_source_new ();
+       g_source_set_priority (idle_source, GTK_SOURCE_PRINT_JOB_PRIORITY);
+       g_source_set_closure (idle_source,
+                             g_cclosure_new_object ((GCallback) idle_printing_handler,
+                                                    G_OBJECT (job)));
+       job->priv->idle_printing_tag = g_source_attach (idle_source, NULL);
+       g_source_unref (idle_source);
+
+       job->priv->printing = TRUE;
+
+       return TRUE;
+}
+
+/**
+ * gtk_source_print_job_cancel:
+ * @job: a #GtkSourcePrintJob.
+ * 
+ * Cancels an asynchronous printing operation.  This will remove any
+ * pending print idle handler and unref the current #GnomePrintJob.
+ *
+ * Note that if you got a reference to the job's #GnomePrintJob (using
+ * gtk_source_print_job_get_print_job()) it will not be destroyed
+ * (since you hold a reference to it), but it will not be closed
+ * either.  If you wish to show or print the partially printed
+ * document you need to close it yourself.
+ *
+ * This function has no effect when called from a non-asynchronous
+ * print operation.
+ **/
+void 
+gtk_source_print_job_cancel (GtkSourcePrintJob *job)
+{
+       g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
+       g_return_if_fail (job->priv->printing);
+
+       if (job->priv->idle_printing_tag > 0)
+       {
+               g_source_remove (job->priv->idle_printing_tag);
+               job->priv->current_paragraph = NULL;
+               job->priv->idle_printing_tag = 0;
+               job->priv->printing = FALSE;
+               g_object_unref (job->priv->print_job);
+               g_object_unref (job->priv->print_ctxt);
+               job->priv->print_job = NULL;
+               job->priv->print_ctxt = NULL;
+       }
+}
+
+/**
+ * gtk_source_print_job_get_print_job:
+ * @job: a #GtkSourcePrintJob.
+ * 
+ * Gets a reference to the #GnomePrintJob which the @job is printing
+ * or has recently finished printing.  You need to unref the returned
+ * object.
+ *
+ * You may call this function in the middle of an asynchronous
+ * printing operation, but the returned #GnomePrintJob will not be
+ * closed until the last page is printed and the <link
+ * linkend="GtkSourcePrintJob-finished">&quot;finished&quot;</link>
+ * signal is emitted.
+ * 
+ * Return value: a new reference to the @job's #GnomePrintJob, or
+ * %NULL.
+ **/
+GnomePrintJob *
+gtk_source_print_job_get_print_job (GtkSourcePrintJob *job)
+{
+       g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), NULL);
+
+       if (job->priv->print_job)
+               g_object_ref (job->priv->print_job);
+       
+       return job->priv->print_job;
+}
+
+/* --- information for asynchronous ops and headers and footers callback */
+
+/**
+ * gtk_source_print_job_get_page:
+ * @job: a #GtkSourcePrintJob.
+ * 
+ * Determines the currently printing page number.  This function is
+ * only valid while printing (either synchronously or asynchronously).
+ * 
+ * Return value: the current page number.
+ **/
+guint 
+gtk_source_print_job_get_page (GtkSourcePrintJob *job)
+{
+       g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), 0);
+       g_return_val_if_fail (job->priv->printing, 0);
+
+       return job->priv->page;
+}
+
+/**
+ * gtk_source_print_job_get_page_count:
+ * @job: a #GtkSourcePrintJob.
+ * 
+ * Determines the total number of pages the job will print.  The
+ * returned value is only meaninful after pagination has finished.  In
+ * practice, for synchronous printing this means when <link
+ * linkend="GtkSourcePrintJob-begin-page">&quot;begin_page&quot;</link>
+ * is emitted, or after gtk_source_print_job_print_range_async() has
+ * returned.
+ * 
+ * Return value: the number of pages of the printed job.
+ **/
+guint 
+gtk_source_print_job_get_page_count (GtkSourcePrintJob *job)
+{
+       g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), 0);
+
+       return job->priv->page_count;
+}
+
+/**
+ * gtk_source_print_job_get_print_context:
+ * @job: a printing #GtkSourcePrintJob.
+ * 
+ * Determines the #GnomePrintContext of the current job.  This
+ * function is only valid while printing.  Normally you would use this
+ * function to print in the margins set by
+ * gtk_source_print_job_set_margins() in a handler for the <link
+ * linkend="GtkSourcePrintJob-begin-page">&quot;begin_page&quot;</link>
+ * signal.
+ * 
+ * Return value: the current #GnomePrintContext.  The returned object
+ * is owned by @job.
+ **/
+GnomePrintContext *
+gtk_source_print_job_get_print_context (GtkSourcePrintJob *job)
+{
+       g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), NULL);
+       g_return_val_if_fail (job->priv->printing, NULL);
+
+       return job->priv->print_ctxt;
+}
+
+/* ---- Header and footer (default implementation) */
+
+/* Most of this code taken from GLib's g_date_strftime() in gdate.c
+ * GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald */
+
+static gchar *
+strdup_strftime (const gchar *format, const struct tm *tm)
+{
+       gsize locale_format_len = 0;
+       gchar *locale_format;
+       gsize tmplen;
+       gchar *tmpbuf;
+       gsize tmpbufsize;
+       gchar *convbuf;
+       gsize convlen = 0;
+       GError *error = NULL;
+
+       g_return_val_if_fail (format != NULL, NULL);
+       g_return_val_if_fail (tm != NULL, NULL);
+
+       locale_format = g_locale_from_utf8 (format, -1, NULL, &locale_format_len, &error);
+
+       if (error)
+       {
+               g_warning (G_STRLOC "Error converting format to locale encoding: %s",
+                          error->message);
+               g_error_free (error);
+               
+               return NULL;
+       }
+
+       tmpbufsize = MAX (128, locale_format_len * 2);
+       while (TRUE)
+       {
+               tmpbuf = g_malloc (tmpbufsize);
+               
+               /* Set the first byte to something other than '\0', to be able to
+                * recognize whether strftime actually failed or just returned "".
+                */
+               tmpbuf[0] = '\1';
+               tmplen = strftime (tmpbuf, tmpbufsize, locale_format, tm);
+               
+               if (tmplen == 0 && tmpbuf[0] != '\0')
+               {
+                       g_free (tmpbuf);
+                       tmpbufsize *= 2;
+                       
+                       if (tmpbufsize > 65536)
+                       {
+                               g_warning (G_STRLOC "Maximum buffer size for strdup_strftime "
+                                          "exceeded: giving up");
+                               g_free (locale_format);
+                               return NULL;
+                       }
+               }
+               else
+                       break;
+       }
+       g_free (locale_format);
+
+       convbuf = g_locale_to_utf8 (tmpbuf, tmplen, NULL, &convlen, &error);
+       g_free (tmpbuf);
+
+       if (error)
+       {
+               g_warning (G_STRLOC "Error converting results of strftime to UTF-8: %s",
+                          error->message);
+               g_error_free (error);
+               
+               return NULL;
+       }
+
+       return convbuf;
+}
+
+static gchar *
+evaluate_format_string (GtkSourcePrintJob *job, const gchar *format)
+{
+       GString *eval;
+       gchar *eval_str, *retval;
+       const struct tm *tm;
+       time_t now;
+       gunichar ch;
+       struct tm lt;
+
+       /* get time */
+       time (&now);
+       tm = localtime_r(&now, &lt);
+
+       /* analyze format string and replace the codes we know */
+       eval = g_string_new_len (NULL, strlen (format));
+       ch = g_utf8_get_char (format);
+       while (ch != 0)
+       {
+               if (ch == '%')
+               {
+                       format = g_utf8_next_char (format);
+                       ch = g_utf8_get_char (format);
+                       if (ch == 'N')
+                               g_string_append_printf (eval, "%d", job->priv->page);
+                       else if (ch == 'Q')
+                               g_string_append_printf (eval, "%d", job->priv->page_count);
+                       else
+                       {
+                               g_string_append_c (eval, '%');
+                               g_string_append_unichar (eval, ch);
+                       }
+               }
+               else
+                       g_string_append_unichar (eval, ch);
+
+               format = g_utf8_next_char (format);
+               ch = g_utf8_get_char (format);
+       }
+
+       eval_str = g_string_free (eval, FALSE);
+       retval = strdup_strftime (eval_str, tm);
+       g_free (eval_str);
+
+       return retval;
+}
+
+static void
+print_header_footer_string (GtkSourcePrintJob *job,
+                           const gchar       *format,
+                           gdouble            x_align,
+                           gdouble            x,
+                           gdouble            y)
+{
+       PangoLayout *layout;
+       gchar *text;
+       gdouble width;
+       gdouble xx;
+       
+       width = job->priv->text_width + job->priv->numbers_width;
+       
+       text = evaluate_format_string (job, format);
+       if (text != NULL)
+       {
+               layout = pango_layout_new (job->priv->pango_context);
+               pango_layout_set_font_description (layout, job->priv->header_footer_font);
+               pango_layout_set_text (layout, text, -1);
+               
+               xx = x + x_align * (width - get_layout_width (layout));
+               gnome_print_moveto (job->priv->print_ctxt, xx, y);
+               show_first_layout_line (job->priv->print_ctxt, layout);
+               
+               g_free (text);
+               g_object_unref (layout);
+       }
+}
+
+static void 
+default_print_header (GtkSourcePrintJob *job,
+                     gdouble            x,
+                     gdouble            y)
+{
+       gdouble width;
+       gdouble yy;
+       gdouble ascent, descent;
+       
+       width = job->priv->text_width + job->priv->numbers_width;
+
+       get_font_ascent_descent (job, job->priv->header_footer_font, &ascent, &descent);
+
+       yy = y - ascent;
+
+       /* left format */
+       if (job->priv->header_format_left != NULL)
+               print_header_footer_string (job, job->priv->header_format_left, 0.0, x, yy);
+       
+       /* right format */
+       if (job->priv->header_format_right != NULL)
+               print_header_footer_string (job, job->priv->header_format_right, 1.0, x, yy);
+
+       /* center format */
+       if (job->priv->header_format_center != NULL)
+               print_header_footer_string (job, job->priv->header_format_center, 0.5, x, yy);
+
+       /* separator */
+       if (job->priv->header_separator)
+       {
+               yy = y - (SEPARATOR_SPACING * (ascent + descent));
+               gnome_print_setlinewidth (job->priv->print_ctxt, SEPARATOR_LINE_WIDTH);
+               gnome_print_moveto (job->priv->print_ctxt, x, yy);
+               gnome_print_lineto (job->priv->print_ctxt, x + width, yy);
+               gnome_print_stroke (job->priv->print_ctxt);
+       }
+}
+
+static void 
+default_print_footer (GtkSourcePrintJob *job,
+                     gdouble            x,
+                     gdouble            y)
+{
+       gdouble width;
+       gdouble yy;
+       gdouble ascent, descent;
+       
+       width = job->priv->text_width + job->priv->numbers_width;
+
+       get_font_ascent_descent (job, job->priv->header_footer_font, &ascent, &descent);
+
+       yy = y - job->priv->footer_height + descent;
+
+       /* left format */
+       if (job->priv->footer_format_left != NULL)
+               print_header_footer_string (job, job->priv->footer_format_left, 0.0, x, yy);
+       
+       /* right format */
+       if (job->priv->footer_format_right != NULL)
+               print_header_footer_string (job, job->priv->footer_format_right, 1.0, x, yy);
+
+       /* center format */
+       if (job->priv->footer_format_center != NULL)
+               print_header_footer_string (job, job->priv->footer_format_center, 0.5, x, yy);
+
+       /* separator */
+       if (job->priv->footer_separator)
+       {
+               yy = y - job->priv->footer_height +
+                       (SEPARATOR_SPACING * (ascent + descent));
+               gnome_print_setlinewidth (job->priv->print_ctxt, SEPARATOR_LINE_WIDTH);
+               gnome_print_moveto (job->priv->print_ctxt, x, yy);
+               gnome_print_lineto (job->priv->print_ctxt, x + width, yy);
+               gnome_print_stroke (job->priv->print_ctxt);
+       }
+}
+
+/**
+ * gtk_source_print_job_set_print_header:
+ * @job: a #GtkSourcePrintJob.
+ * @setting: %TRUE if you want the header to be printed.
+ * 
+ * Sets whether you want to print a header in each page.  The default
+ * header consists of three pieces of text and an optional line
+ * separator, configurable with
+ * gtk_source_print_job_set_header_format().
+ *
+ * Note that by default the header format is unspecified, and if it's
+ * empty it will not be printed, regardless of this setting.
+ **/
+void 
+gtk_source_print_job_set_print_header (GtkSourcePrintJob *job,
+                                      gboolean           setting)
+{
+       g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
+       g_return_if_fail (!job->priv->printing);
+
+       setting = (setting != FALSE);
+       
+       if (setting == job->priv->print_header)
+               return;
+       
+       job->priv->print_header = setting;
+
+       g_object_notify (G_OBJECT (job), "print_header");
+}
+
+/**
+ * gtk_source_print_job_get_print_header:
+ * @job: a #GtkSourcePrintJob.
+ * 
+ * Determines if a header is set to be printed for each page.  A
+ * header will be printed if this function returns %TRUE
+ * <emphasis>and</emphasis> some format strings have been specified
+ * with gtk_source_print_job_set_header_format().
+ * 
+ * Return value: %TRUE if the header is set to be printed.
+ **/
+gboolean 
+gtk_source_print_job_get_print_header (GtkSourcePrintJob *job)
+{
+       g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), FALSE);
+
+       return job->priv->print_header;
+}
+
+/**
+ * gtk_source_print_job_set_print_footer:
+ * @job: a #GtkSourcePrintJob.
+ * @setting: %TRUE if you want the footer to be printed.
+ * 
+ * Sets whether you want to print a footer in each page.  The default
+ * footer consists of three pieces of text and an optional line
+ * separator, configurable with
+ * gtk_source_print_job_set_footer_format().
+ *
+ * Note that by default the footer format is unspecified, and if it's
+ * empty it will not be printed, regardless of this setting.
+ **/
+void 
+gtk_source_print_job_set_print_footer (GtkSourcePrintJob *job,
+                                      gboolean           setting)
+{
+       g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
+       g_return_if_fail (!job->priv->printing);
+
+       setting = (setting != FALSE);
+       
+       if (setting == job->priv->print_footer)
+               return;
+       
+       job->priv->print_footer = setting;
+
+       g_object_notify (G_OBJECT (job), "print_footer");
+}
+
+/**
+ * gtk_source_print_job_get_print_footer:
+ * @job: a #GtkSourcePrintJob.
+ * 
+ * Determines if a footer is set to be printed for each page.  A
+ * footer will be printed if this function returns %TRUE
+ * <emphasis>and</emphasis> some format strings have been specified
+ * with gtk_source_print_job_set_footer_format().
+ * 
+ * Return value: %TRUE if the footer is set to be printed.
+ **/
+gboolean 
+gtk_source_print_job_get_print_footer (GtkSourcePrintJob *job)
+{
+       g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), FALSE);
+
+       return job->priv->print_footer;
+}
+
+/**
+ * gtk_source_print_job_set_header_footer_font_desc:
+ * @job: a #GtkSourcePrintJob.
+ * @desc: the #PangoFontDescription for the font to be used in headers and footers, or %NULL.
+ * 
+ * Sets the font for printing headers and footers.  If %NULL is
+ * supplied, the default font (i.e. the one being used for the text)
+ * will be used instead.
+ **/
+void 
+gtk_source_print_job_set_header_footer_font_desc (GtkSourcePrintJob    *job,
+                                                 PangoFontDescription *desc)
+{
+       g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
+       g_return_if_fail (!job->priv->printing);
+       
+       if (desc)
+               desc = pango_font_description_copy (desc);
+       if (job->priv->header_footer_font != NULL)
+               pango_font_description_free (job->priv->header_footer_font);
+       job->priv->header_footer_font = desc;
+       g_object_freeze_notify (G_OBJECT (job));
+       g_object_notify (G_OBJECT (job), "header_footer_font");
+       g_object_notify (G_OBJECT (job), "header_footer_font_desc");
+       g_object_thaw_notify (G_OBJECT (job));
+}
+
+/**
+ * gtk_source_print_job_set_header_footer_font:
+ * @job: a #GtkSourcePrintJob.
+ * @font_name: the full name of the font to be used in headers and footers, or %NULL.
+ * 
+ * Sets the font for printing headers and footers.  If %NULL is
+ * supplied, the default font (i.e. the one being used for the text)
+ * will be used instead.
+ *
+ * Note that @font_name is a #GnomeFont name not a Pango font
+ * description string. This function is deprecated since #GnomeFont is
+ * no longer used when implementing printing for GtkSourceView; you
+ * should use gtk_source_print_job_set_header_footer_font_desc() instead.
+ **/
+void 
+gtk_source_print_job_set_header_footer_font (GtkSourcePrintJob *job,
+                                            const gchar       *font_name)
+{
+       PangoFontDescription *desc;
+       
+       g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
+       g_return_if_fail (!job->priv->printing);
+
+       if (font_name != NULL)
+       {
+               desc = font_description_from_gnome_font_name (font_name);
+               if (desc)
+               {
+                       gtk_source_print_job_set_header_footer_font_desc (job, desc);
+                       pango_font_description_free (desc);
+               }
+       }
+       else
+               gtk_source_print_job_set_header_footer_font_desc (job, NULL);
+}
+
+/**
+ * gtk_source_print_job_get_header_footer_font_desc:
+ * @job: a #GtkSourcePrintJob.
+ * 
+ * Determines the font to be used for the header and footer.  This function
+ * might return %NULL if a specific font has not been set.
+ * 
+ * Return value: the header and footer font description or %NULL. This value is
+ * owned by the job and must not be modified or freed.
+ **/
+PangoFontDescription *
+gtk_source_print_job_get_header_footer_font_desc (GtkSourcePrintJob *job)
+{
+       g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), NULL);
+
+       return job->priv->header_footer_font;
+}
+
+/**
+ * gtk_source_print_job_get_header_footer_font:
+ * @job: a #GtkSourcePrintJob.
+ * 
+ * Determines the font to be used for the header and footer.  The
+ * returned string is of the form &quot;Fontfamily Style Size&quot;,
+ * for example &quot;Monospace Regular 10.0&quot;.  The returned value
+ * should be freed when no longer needed.  This function might return
+ * %NULL if a specific font has not been set.
+ * 
+ * Note that the result is a #GnomeFont name not a Pango font
+ * description string. This function is deprecated since #GnomeFont is
+ * no longer used when implementing printing for GtkSourceView; you
+ * should use gtk_source_print_job_get_header_footer_font_desc() instead.
+ *
+ * Return value: a newly allocated string with the name of the current
+ * header and footer font, or %NULL.
+ **/
+gchar *
+gtk_source_print_job_get_header_footer_font (GtkSourcePrintJob *job)
+{
+       g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), NULL);
+
+       if (job->priv->header_footer_font != NULL)
+               return font_description_to_gnome_font_name (job->priv->header_footer_font);
+       else
+               return NULL;
+}
+
+/**
+ * gtk_source_print_job_set_header_format:
+ * @job: a #GtkSourcePrintJob.
+ * @left: a format string to print on the left of the header.
+ * @center: a format string to print on the center of the header.
+ * @right: a format string to print on the right of the header.
+ * @separator: %TRUE if you want a separator line to be printed.
+ * 
+ * Sets strftime like header format strings, to be printed on the
+ * left, center and right of the top of each page.  The strings may
+ * include strftime(3) codes which will be expanded at print time.
+ * All strftime() codes are accepted, with the addition of %N for the
+ * page number and %Q for the page count.
+ *
+ * @separator specifies if a solid line should be drawn to separate
+ * the header from the document text.
+ *
+ * If %NULL is given for any of the three arguments, that particular
+ * string will not be printed.  For the header to be printed, in
+ * addition to specifying format strings, you need to enable header
+ * printing with gtk_source_print_job_set_print_header().
+ **/
+void 
+gtk_source_print_job_set_header_format (GtkSourcePrintJob *job,
+                                       const gchar       *left,
+                                       const gchar       *center,
+                                       const gchar       *right,
+                                       gboolean           separator)
+{
+       g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
+       g_return_if_fail (!job->priv->printing);
+
+       /* FIXME: validate given strings? */
+       g_free (job->priv->header_format_left);
+       g_free (job->priv->header_format_center);
+       g_free (job->priv->header_format_right);
+       job->priv->header_format_left = g_strdup (left);
+       job->priv->header_format_center = g_strdup (center);
+       job->priv->header_format_right = g_strdup (right);
+       job->priv->header_separator = separator;
+}
+
+/**
+ * gtk_source_print_job_set_footer_format:
+ * @job: a #GtkSourcePrintJob.
+ * @left: a format string to print on the left of the footer.
+ * @center: a format string to print on the center of the footer.
+ * @right: a format string to print on the right of the footer.
+ * @separator: %TRUE if you want a separator line to be printed.
+ * 
+ * Like gtk_source_print_job_set_header_format(), but for the footer.
+ **/
+void 
+gtk_source_print_job_set_footer_format (GtkSourcePrintJob *job,
+                                       const gchar       *left,
+                                       const gchar       *center,
+                                       const gchar       *right,
+                                       gboolean           separator)
+{
+       g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
+       g_return_if_fail (!job->priv->printing);
+
+       /* FIXME: validate given strings? */
+       g_free (job->priv->footer_format_left);
+       g_free (job->priv->footer_format_center);
+       g_free (job->priv->footer_format_right);
+       job->priv->footer_format_left = g_strdup (left);
+       job->priv->footer_format_center = g_strdup (center);
+       job->priv->footer_format_right = g_strdup (right);
+       job->priv->footer_separator = separator;
+}
+#endif
diff --git a/src/gtk/gtksourceprintjob.h b/src/gtk/gtksourceprintjob.h
new file mode 100644 (file)
index 0000000..b000a64
--- /dev/null
@@ -0,0 +1,168 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*- */
+/*
+ * gtksourceprintjob.h
+ * This file is part of GtkSourceView
+ *
+ * Copyright (C) 2003  Gustavo Giráldez
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __GTK_SOURCE_PRINT_JOB_H__
+#define __GTK_SOURCE_PRINT_JOB_H__
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef USE_GNOMEPRINT
+
+#include <libgnomeprint/gnome-print-config.h>
+#include <libgnomeprint/gnome-print-job.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_SOURCE_PRINT_JOB            (gtk_source_print_job_get_type ())
+#define GTK_SOURCE_PRINT_JOB(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SOURCE_PRINT_JOB, GtkSourcePrintJob))
+#define GTK_SOURCE_PRINT_JOB_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_SOURCE_PRINT_JOB, GtkSourcePrintJobClass))
+#define GTK_IS_SOURCE_PRINT_JOB(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_SOURCE_PRINT_JOB))
+#define GTK_IS_SOURCE_PRINT_JOB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_SOURCE_PRINT_JOB))
+#define GTK_SOURCE_PRINT_JOB_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_SOURCE_PRINT_JOB, GtkSourcePrintJobClass))
+
+typedef struct _GtkSourcePrintJob         GtkSourcePrintJob;
+typedef struct _GtkSourcePrintJobClass    GtkSourcePrintJobClass;
+typedef struct _GtkSourcePrintJobPrivate  GtkSourcePrintJobPrivate;
+
+struct _GtkSourcePrintJob
+{
+       GObject parent_instance;
+
+       GtkSourcePrintJobPrivate *priv;
+};
+
+struct _GtkSourcePrintJobClass
+{
+       GObjectClass parent_class;
+
+       void   (* begin_page)    (GtkSourcePrintJob  *job);
+       void   (* finished)      (GtkSourcePrintJob  *job);
+};
+
+/* we want the idle handler to run before the view validation, but do
+ * not interfere with ui updates */
+#define GTK_SOURCE_PRINT_JOB_PRIORITY ((GDK_PRIORITY_REDRAW + GTK_TEXT_VIEW_PRIORITY_VALIDATE) / 2)
+
+GType              gtk_source_print_job_get_type               (void) G_GNUC_CONST;
+
+/* constructor functions */
+GtkSourcePrintJob *gtk_source_print_job_new                    (GnomePrintConfig  *config);
+GtkSourcePrintJob *gtk_source_print_job_new_with_buffer        (GnomePrintConfig  *config,
+                                                               GtkTextBuffer   *buffer);
+/* print job basic configuration */
+void               gtk_source_print_job_set_config             (GtkSourcePrintJob *job,
+                                                               GnomePrintConfig  *config);
+GnomePrintConfig  *gtk_source_print_job_get_config             (GtkSourcePrintJob *job);
+void               gtk_source_print_job_set_buffer             (GtkSourcePrintJob *job,
+                                                               GtkTextBuffer   *buffer);
+GtkTextBuffer   *gtk_source_print_job_get_buffer             (GtkSourcePrintJob *job);
+
+/* print job layout and style configuration */
+//void               gtk_source_print_job_setup_from_view        (GtkSourcePrintJob *job,
+//                                                             GtkSourceView     *view);
+void               gtk_source_print_job_set_tabs_width         (GtkSourcePrintJob *job,
+                                                               guint              tabs_width);
+guint              gtk_source_print_job_get_tabs_width         (GtkSourcePrintJob *job);
+void               gtk_source_print_job_set_wrap_mode          (GtkSourcePrintJob *job,
+                                                               GtkWrapMode        wrap);
+GtkWrapMode        gtk_source_print_job_get_wrap_mode          (GtkSourcePrintJob *job);
+void               gtk_source_print_job_set_highlight          (GtkSourcePrintJob *job,
+                                                               gboolean           highlight);
+gboolean           gtk_source_print_job_get_highlight          (GtkSourcePrintJob *job);
+void               gtk_source_print_job_set_font               (GtkSourcePrintJob *job,
+                                                               const gchar       *font_name);
+gchar             *gtk_source_print_job_get_font               (GtkSourcePrintJob *job);
+void               gtk_source_print_job_set_numbers_font       (GtkSourcePrintJob *job,
+                                                               const gchar       *font_name);
+gchar             *gtk_source_print_job_get_numbers_font       (GtkSourcePrintJob *job);
+void               gtk_source_print_job_set_print_numbers      (GtkSourcePrintJob *job,
+                                                               guint              interval);
+guint              gtk_source_print_job_get_print_numbers      (GtkSourcePrintJob *job);
+void               gtk_source_print_job_set_text_margins       (GtkSourcePrintJob *job,
+                                                               gdouble            top,
+                                                               gdouble            bottom,
+                                                               gdouble            left,
+                                                               gdouble            right);
+void               gtk_source_print_job_get_text_margins       (GtkSourcePrintJob *job,
+                                                               gdouble           *top,
+                                                               gdouble           *bottom,
+                                                               gdouble           *left,
+                                                               gdouble           *right);
+
+/* New non-deprecated font-setting API */
+void                   gtk_source_print_job_set_font_desc               (GtkSourcePrintJob    *job,
+                                                                        PangoFontDescription *desc);
+PangoFontDescription  *gtk_source_print_job_get_font_desc               (GtkSourcePrintJob    *job);
+void                   gtk_source_print_job_set_numbers_font_desc       (GtkSourcePrintJob    *job,
+                                                                        PangoFontDescription *desc);
+PangoFontDescription  *gtk_source_print_job_get_numbers_font_desc       (GtkSourcePrintJob    *job);
+void                   gtk_source_print_job_set_header_footer_font_desc (GtkSourcePrintJob    *job,
+                                                                        PangoFontDescription *desc);
+PangoFontDescription  *gtk_source_print_job_get_header_footer_font_desc (GtkSourcePrintJob    *job);
+
+/* printing operations */
+GnomePrintJob     *gtk_source_print_job_print                  (GtkSourcePrintJob *job);
+GnomePrintJob     *gtk_source_print_job_print_range            (GtkSourcePrintJob *job,
+                                                               const GtkTextIter *start,
+                                                               const GtkTextIter *end);
+
+/* asynchronous printing */
+gboolean           gtk_source_print_job_print_range_async      (GtkSourcePrintJob *job,
+                                                               const GtkTextIter *start,
+                                                               const GtkTextIter *end);
+void               gtk_source_print_job_cancel                 (GtkSourcePrintJob *job);
+GnomePrintJob     *gtk_source_print_job_get_print_job          (GtkSourcePrintJob *job);
+
+/* information for asynchronous ops and headers and footers callback */
+guint              gtk_source_print_job_get_page               (GtkSourcePrintJob *job);
+guint              gtk_source_print_job_get_page_count         (GtkSourcePrintJob *job);
+GnomePrintContext *gtk_source_print_job_get_print_context      (GtkSourcePrintJob *job);
+
+
+/* header and footer */
+void               gtk_source_print_job_set_print_header       (GtkSourcePrintJob *job,
+                                                               gboolean           setting);
+gboolean           gtk_source_print_job_get_print_header       (GtkSourcePrintJob *job);
+void               gtk_source_print_job_set_print_footer       (GtkSourcePrintJob *job,
+                                                               gboolean           setting);
+gboolean           gtk_source_print_job_get_print_footer       (GtkSourcePrintJob *job);
+void               gtk_source_print_job_set_header_footer_font (GtkSourcePrintJob *job,
+                                                               const gchar       *font_name);
+gchar             *gtk_source_print_job_get_header_footer_font (GtkSourcePrintJob *job);
+/* format strings are strftime like */
+void               gtk_source_print_job_set_header_format      (GtkSourcePrintJob *job,
+                                                               const gchar       *left,
+                                                               const gchar       *center,
+                                                               const gchar       *right,
+                                                               gboolean           separator);
+void               gtk_source_print_job_set_footer_format      (GtkSourcePrintJob *job,
+                                                               const gchar       *left,
+                                                               const gchar       *center,
+                                                               const gchar       *right,
+                                                               gboolean           separator);
+
+G_END_DECLS
+
+#endif /* __GTK_SOURCE_PRINT_JOB_H__ */
+#endif
index 0f7e652..6e1a478 100644 (file)
@@ -904,6 +904,12 @@ static void main_dump_features_list(gboolean show_debug_only)
        else
                g_print(" libetpan %d.%d\n", LIBETPAN_VERSION_MAJOR, LIBETPAN_VERSION_MINOR);
 #endif
+#if USE_GNOMEPRINT
+       if (show_debug_only)
+               debug_print(" gnomeprint\n");
+       else
+               g_print(" gnomeprint\n");
+#endif
 #if HAVE_LIBSM
        if (show_debug_only)
                debug_print(" libsm\n");
index 886cbe2..0c5ed63 100644 (file)
@@ -144,7 +144,7 @@ static void empty_trash_cb   (GtkAction     *action,
                                  gpointer       data);
 static void save_as_cb          (GtkAction     *action,
                                  gpointer       data);
-#if GTK_CHECK_VERSION(2,10,0)
+#if GTK_CHECK_VERSION(2,10,0) && !defined(USE_GNOMEPRINT)
 static void page_setup_cb       (GtkAction     *action,
                                  gpointer       data);
 #endif
@@ -482,7 +482,7 @@ static GtkActionEntry mainwin_entries[] =
 
        {"File/SaveAs",                         NULL, N_("_Save as..."), "<control>S", NULL, G_CALLBACK(save_as_cb) },
 
-#if GTK_CHECK_VERSION(2,10,0)
+#if GTK_CHECK_VERSION(2,10,0) && !defined(USE_GNOMEPRINT)
        {"File/PageSetup",                      NULL, N_("Page setup..."), NULL, NULL, G_CALLBACK(page_setup_cb) },
 #endif
        {"File/Print",                          NULL, N_("_Print..."), "<control>P", NULL, G_CALLBACK(print_cb) },
@@ -1603,7 +1603,7 @@ MainWindow *main_window_create()
        MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menu/File", "EmptyTrashes", "File/EmptyTrashes", GTK_UI_MANAGER_MENUITEM)
        MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menu/File", "Separator4", "File/---", GTK_UI_MANAGER_SEPARATOR)
        MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menu/File", "SaveAs", "File/SaveAs", GTK_UI_MANAGER_MENUITEM)
-#if GTK_CHECK_VERSION(2,10,0)
+#if GTK_CHECK_VERSION(2,10,0) && !defined(USE_GNOMEPRINT)
        MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menu/File", "PageSetup", "File/PageSetup", GTK_UI_MANAGER_MENUITEM)
 #endif
        MENUITEM_ADDUI_MANAGER(mainwin->ui_manager, "/Menu/File", "Print", "File/Print", GTK_UI_MANAGER_MENUITEM)
@@ -3955,7 +3955,7 @@ static void print_cb(GtkAction *action, gpointer data)
        summary_print(mainwin->summaryview);
 }
 
-#if GTK_CHECK_VERSION(2,10,0)
+#if GTK_CHECK_VERSION(2,10,0) && !defined(USE_GNOMEPRINT)
 static void page_setup_cb(GtkAction *action, gpointer data)
 {
        MainWindow *mainwin = (MainWindow *)data;
index 603caad..8fdd824 100644 (file)
@@ -58,6 +58,7 @@
 #include "hooks.h"
 #include "filtering.h"
 #include "partial_download.h"
+#include "gedit-print.h"
 #include "uri_opener.h"
 #include "inc.h"
 #include "log.h"
@@ -93,7 +94,7 @@ static void partial_recv_unmark_clicked (NoticeView   *noticeview,
                                          MsgInfo        *msginfo);
 static void save_as_cb                 (GtkAction      *action,
                                         gpointer        data);
-#if GTK_CHECK_VERSION(2,10,0)
+#if GTK_CHECK_VERSION(2,10,0) && !defined(USE_GNOMEPRINT)
 static void page_setup_cb              (GtkAction      *action,
                                         gpointer        data);
 #endif
@@ -192,7 +193,7 @@ static GtkActionEntry msgview_entries[] =
 
 /* File menu */
        {"File/SaveAs",                 NULL, N_("_Save as..."), "<control>S", NULL, G_CALLBACK(save_as_cb) },
-#if GTK_CHECK_VERSION(2,10,0)
+#if GTK_CHECK_VERSION(2,10,0) && !defined(USE_GNOMEPRINT)
        {"File/PageSetup",              NULL, N_("Page setup..."), NULL, NULL, G_CALLBACK(page_setup_cb) },
 #endif
        {"File/Print",                  NULL, N_("_Print..."), "<control>P", NULL, G_CALLBACK(print_cb) },
@@ -453,7 +454,7 @@ static void messageview_add_toolbar(MessageView *msgview, GtkWidget *window)
 
 /* File menu */
        MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/File", "SaveAs", "File/SaveAs", GTK_UI_MANAGER_MENUITEM)
-#if GTK_CHECK_VERSION(2,10,0)
+#if GTK_CHECK_VERSION(2,10,0) && !defined(USE_GNOMEPRINT)
        MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/File", "PageSetup", "File/PageSetup", GTK_UI_MANAGER_MENUITEM)
 #endif
        MENUITEM_ADDUI_MANAGER(msgview->ui_manager, "/Menu/File", "Print", "File/Print", GTK_UI_MANAGER_MENUITEM)
@@ -1934,11 +1935,12 @@ static void save_as_cb(GtkAction *action, gpointer data)
        messageview_save_as(messageview);
 }
 
-#if GTK_CHECK_VERSION(2,10,0)
+#if defined(USE_GNOMEPRINT) || GTK_CHECK_VERSION(2,10,0)
 static void print_mimeview(MimeView *mimeview, gint sel_start, gint sel_end, gint partnum) 
 {
+#if !defined(USE_GNOMEPRINT) && GTK_CHECK_VERSION(2,10,0)
        MainWindow *mainwin;
-
+#endif
        if (!mimeview 
        ||  !mimeview->textview
        ||  !mimeview->textview->text)
@@ -1965,11 +1967,15 @@ static void print_mimeview(MimeView *mimeview, gint sel_start, gint sel_end, gin
                        gtk_text_buffer_get_iter_at_offset(buffer, &end, sel_end);
                        gtk_text_buffer_select_range(buffer, &start, &end);
                }
+#if defined(USE_GNOMEPRINT)
+               gedit_print(GTK_TEXT_VIEW(mimeview->textview->text));
+#else
                /* TODO: Get the real parent window, not the main window */
                mainwin = mainwindow_get_mainwindow();
                printing_print(GTK_TEXT_VIEW(mimeview->textview->text),
                               mainwin ? GTK_WINDOW(mainwin->window) : NULL,
                                sel_start, sel_end);
+#endif
        }
 }
 
@@ -2003,7 +2009,7 @@ void messageview_print(MsgInfo *msginfo, gboolean all_headers,
 }
 #endif
 
-#if GTK_CHECK_VERSION(2,10,0)
+#if GTK_CHECK_VERSION(2,10,0) && !defined(USE_GNOMEPRINT)
 static void page_setup_cb(GtkAction *action, gpointer data)
 {
        MessageView *messageview = (MessageView *)data;
@@ -2015,7 +2021,7 @@ static void page_setup_cb(GtkAction *action, gpointer data)
 static void print_cb(GtkAction *action, gpointer data)
 {
        MessageView *messageview = (MessageView *)data;
-#if !GTK_CHECK_VERSION(2,10,0)
+#if !defined(USE_GNOMEPRINT) && !GTK_CHECK_VERSION(2,10,0)
        gchar *cmdline = NULL;
        gchar *p;
 #else
@@ -2024,7 +2030,7 @@ static void print_cb(GtkAction *action, gpointer data)
 
        if (!messageview->msginfo) return;
 
-#if !GTK_CHECK_VERSION(2,10,0)
+#if !defined(USE_GNOMEPRINT) && !GTK_CHECK_VERSION(2,10,0)
        cmdline = input_dialog(_("Print"),
                               _("Enter the print command line:\n"
                                 "('%s' will be replaced with file name)"),
index cb09300..0fe8213 100644 (file)
@@ -230,7 +230,7 @@ static void prefs_ext_prog_create_widget(PrefsPage *_page, GtkWindow *window,
                           prefs_common.mime_textviewer ? prefs_common.mime_textviewer : "");
 
        printcmd_label = gtk_label_new (_("Print command"));
-#if !GTK_CHECK_VERSION(2,10,0)
+#if !defined(USE_GNOMEPRINT) && !GTK_CHECK_VERSION(2,10,0)
        gtk_widget_show(printcmd_label);
 #endif
        i++;
@@ -241,7 +241,7 @@ static void prefs_ext_prog_create_widget(PrefsPage *_page, GtkWindow *window,
        gtk_misc_set_alignment(GTK_MISC (printcmd_label), 1, 0.5);
 
        printcmd_entry = gtk_entry_new ();
-#if !GTK_CHECK_VERSION(2,10,0)
+#if !defined(USE_GNOMEPRINT) && !GTK_CHECK_VERSION(2,10,0)
        gtk_widget_show(printcmd_entry);
 #endif
        gtk_table_attach(GTK_TABLE (table2), printcmd_entry, 1, 2, i, i+1,
index 3d62b9f..db606b6 100644 (file)
@@ -47,7 +47,7 @@ typedef struct _FontsPage
        GtkWidget *entry_folderview_boldfont;
        GtkWidget *entry_messageviewfont;
        GtkWidget *derive_from_normalfont_checkbutton;
-#if GTK_CHECK_VERSION(2,10,0)
+#if defined(USE_GNOMEPRINT) || GTK_CHECK_VERSION(2,10,0)
        GtkWidget *print_checkbutton;
        GtkWidget *entry_messageprintfont;
 #endif
@@ -64,7 +64,7 @@ static void prefs_fonts_create_widget(PrefsPage *_page, GtkWindow *window,
        GtkWidget *entry_folderview_boldfont;
        GtkWidget *entry_messageviewfont;
        GtkWidget *tmplabel;
-#if GTK_CHECK_VERSION(2,10,0)
+#if defined(USE_GNOMEPRINT) || GTK_CHECK_VERSION(2,10,0)
        GtkWidget *entry_messageprintfont;
        GtkWidget *print_checkbutton;
 #endif
@@ -179,7 +179,7 @@ static void prefs_fonts_create_widget(PrefsPage *_page, GtkWindow *window,
        SET_TOGGLE_SENSITIVITY_REVERSE (derive_from_normalfont_checkbutton, entry_folderview_boldfont);
        row++;
 
-#if GTK_CHECK_VERSION(2,10,0)
+#if defined(USE_GNOMEPRINT) || GTK_CHECK_VERSION(2,10,0)
        /* print check button */
        print_checkbutton = gtk_check_button_new_with_label(_("Use different font for printing"));
        gtk_widget_show(print_checkbutton);
@@ -219,7 +219,7 @@ static void prefs_fonts_create_widget(PrefsPage *_page, GtkWindow *window,
        prefs_fonts->entry_folderview_boldfont   = entry_folderview_boldfont;
        prefs_fonts->entry_messageviewfont      = entry_messageviewfont;
        prefs_fonts->derive_from_normalfont_checkbutton = derive_from_normalfont_checkbutton;
-#if GTK_CHECK_VERSION(2,10,0)
+#if defined(USE_GNOMEPRINT) || GTK_CHECK_VERSION(2,10,0)
        prefs_fonts->entry_messageprintfont     = entry_messageprintfont;
        prefs_fonts->print_checkbutton          = print_checkbutton;
 #endif
@@ -250,7 +250,7 @@ static void prefs_fonts_save(PrefsPage *_page)
        prefs_common.derive_from_normal_font = gtk_toggle_button_get_active
                        (GTK_TOGGLE_BUTTON(fonts->derive_from_normalfont_checkbutton));
 
-#if GTK_CHECK_VERSION(2,10,0)
+#if defined(USE_GNOMEPRINT) || GTK_CHECK_VERSION(2,10,0)
        g_free(prefs_common.printfont);         
        prefs_common.printfont   = g_strdup(gtk_font_button_get_font_name
                (GTK_FONT_BUTTON(fonts->entry_messageprintfont)));
index 98deed8..4f1a31d 100644 (file)
@@ -87,7 +87,7 @@ static void imageviewer_create_widget_func(PrefsPage * _page,
                         (GtkAttachOptions) (0), 0, 0);
        
        print_imgs = gtk_check_button_new_with_label(_("Print images"));
-#if GTK_CHECK_VERSION(2,10,0)
+#if !defined(USE_GNOMEPRINT) && GTK_CHECK_VERSION(2,10,0)
        gtk_widget_show(print_imgs);
 #endif
        gtk_table_attach(GTK_TABLE(table), print_imgs, 0, 1, 3, 4,
index 5f49838..bd35038 100644 (file)
@@ -24,7 +24,7 @@
 #include "printing.h"
 #include "image_viewer.h"
 
-#if GTK_CHECK_VERSION(2,10,0)
+#if GTK_CHECK_VERSION(2,10,0) && !defined(USE_GNOMEPRINT)
 
 #include "gtkutils.h"
 #include "toolbar.h"
index 2b11524..da4e6b3 100644 (file)
@@ -26,7 +26,7 @@
 #  include "config.h"
 #endif
 
-#if GTK_CHECK_VERSION(2,10,0)
+#if GTK_CHECK_VERSION(2,10,0) && !defined(USE_GNOMEPRINT)
 
 typedef struct _PrintData              PrintData;
 
index 7af4201..9d51b97 100644 (file)
@@ -71,6 +71,7 @@
 #include "partial_download.h"
 #include "tags.h"
 #include "timing.h"
+#include "gedit-print.h"
 #include "log.h"
 #include "edittags.h"
 #include "manual.h"
@@ -4802,7 +4803,7 @@ void summary_save_as(SummaryView *summaryview)
 void summary_print(SummaryView *summaryview)
 {
        GtkCMCList *clist = GTK_CMCLIST(summaryview->ctree);
-#if !GTK_CHECK_VERSION(2,10,0)
+#if !defined(USE_GNOMEPRINT) && !GTK_CHECK_VERSION(2,10,0)
        GtkCMCTree *ctree = GTK_CMCTREE(summaryview->ctree);
        MsgInfo *msginfo;
        gchar *cmdline = NULL;
@@ -4822,7 +4823,7 @@ void summary_print(SummaryView *summaryview)
        g_free(msg);
 
        if (clist->selection == NULL) return;
-#if !GTK_CHECK_VERSION(2,10,0)
+#if !defined(USE_GNOMEPRINT) && !GTK_CHECK_VERSION(2,10,0)
        cmdline = input_dialog(_("Print"),
                               _("Enter the print command line:\n"
                                 "('%s' will be replaced with file name)"),