talons

Fork of Claws Mail https://www.claws-mail
Log | Files | Refs | README | LICENSE

commit fe0b6200d2abb92370931abb5a87f5f4c8f531f8
parent 51556209cc8d88ff51665e7a824fe622704e4802
Author: Colin Leroy <colin@colino.net>
Date:   Thu,  9 Oct 2008 17:02:02 +0000

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.

Diffstat:
MChangeLog | 23+++++++++++++++++++++++
MPATCHSETS | 1+
Mconfigure.ac | 31++++++++++++++++++++++++++++++-
Msrc/Makefile.am | 4++++
Msrc/crash.c | 3+++
Asrc/gedit-print.c | 463+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/gedit-print.h | 41+++++++++++++++++++++++++++++++++++++++++
Msrc/gtk/Makefile.am | 4++++
Msrc/gtk/about.c | 12+++++++++++-
Asrc/gtk/gtksourceprintjob.c | 3242+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/gtk/gtksourceprintjob.h | 168+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/main.c | 6++++++
Msrc/mainwindow.c | 8++++----
Msrc/messageview.c | 22++++++++++++++--------
Msrc/prefs_ext_prog.c | 4++--
Msrc/prefs_fonts.c | 10+++++-----
Msrc/prefs_image_viewer.c | 2+-
Msrc/printing.c | 2+-
Msrc/printing.h | 2+-
Msrc/summaryview.c | 5+++--
20 files changed, 4027 insertions(+), 26 deletions(-)

diff --git 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 diff --git a/PATCHSETS b/PATCHSETS @@ -3576,3 +3576,4 @@ ( 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 diff --git a/configure.ac b/configure.ac @@ -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" diff --git a/src/Makefile.am b/src/Makefile.am @@ -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) \ diff --git a/src/crash.c b/src/crash.c @@ -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 @@ -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 @@ -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__ */ diff --git a/src/gtk/Makefile.am b/src/gtk/Makefile.am @@ -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 diff --git a/src/gtk/about.c b/src/gtk/about.c @@ -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 @@ -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 @@ -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 diff --git a/src/main.c b/src/main.c @@ -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"); diff --git a/src/mainwindow.c b/src/mainwindow.c @@ -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; diff --git a/src/messageview.c b/src/messageview.c @@ -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)"), diff --git a/src/prefs_ext_prog.c b/src/prefs_ext_prog.c @@ -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, diff --git a/src/prefs_fonts.c b/src/prefs_fonts.c @@ -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))); diff --git a/src/prefs_image_viewer.c b/src/prefs_image_viewer.c @@ -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, diff --git a/src/printing.c b/src/printing.c @@ -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" diff --git a/src/printing.h b/src/printing.h @@ -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; diff --git a/src/summaryview.c b/src/summaryview.c @@ -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)"),