2008-08-27 [colin] 3.5.0cvs75
[claws.git] / src / gtk / gtksourceprintjob.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*- */
2 /*
3  * gtksourceprintjob.c
4  * This file is part of GtkSourceView
5  *
6  * Derived from gedit-print.c
7  *
8  * Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
9  * Copyright (C) 2002  Paolo Maggi  
10  * Copyright (C) 2003  Gustavo Giráldez
11  * Copyright (C) 2004  Red Hat, Inc.
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 3 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program. If not, see <http://www.gnu.org/licenses/>.
25  */
26  
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
30
31 #ifdef USE_GNOMEPRINT
32
33 #include <string.h>
34 #include <time.h>
35
36 #include "gtksourceprintjob.h"
37 #include "image_viewer.h"
38
39 #include <glib/gi18n.h>
40 #include <gtk/gtkmain.h>
41 #include <gtk/gtktextview.h>
42 #include <libgnomeprint/gnome-print-pango.h>
43
44 #ifdef ENABLE_PROFILE
45 #define PROFILE(x) x
46 #else
47 #define PROFILE(x)
48 #endif
49
50 #ifdef ENABLE_DEBUG
51 #define DEBUG(x) x
52 #else
53 #define DEBUG(x)
54 #endif
55
56
57 #define DEFAULT_FONT_NAME   "Monospace 10"
58 #define DEFAULT_COLOR       0x000000ff
59
60 #define CM(v) ((v) * 72.0 / 2.54)
61 #define A4_WIDTH (210.0 * 72 / 25.4)
62 #define A4_HEIGHT (297.0 * 72 / 25.4)
63
64 #define NUMBERS_TEXT_SEPARATION CM(0.5)
65
66 #define HEADER_FOOTER_SIZE      2.5
67 #define SEPARATOR_SPACING       1.5
68 #define SEPARATOR_LINE_WIDTH    1.0
69
70
71 typedef struct _TextSegment TextSegment;
72 typedef struct _Paragraph   Paragraph;
73 typedef struct _TextStyle   TextStyle;
74
75 /* a piece of text (within a paragraph) of the same style */
76 struct _TextSegment
77 {
78         TextSegment             *next;
79         TextStyle               *style;
80         gchar                   *text;
81         GdkPixbuf               *image;
82 };
83
84 /* a printable line */
85 struct _Paragraph
86 {
87         guint                    line_number;
88         TextSegment             *segment;
89 };
90
91 /* the style of a TextSegment */
92 struct _TextStyle
93 {
94         PangoFontDescription    *font_desc;
95         GdkColor                *foreground;
96         GdkColor                *background;
97         gdouble                  scale;
98         gboolean                 strikethrough;
99         PangoUnderline           underline;
100 };
101
102
103 struct _GtkSourcePrintJobPrivate
104 {
105         /* General job configuration */
106         GnomePrintConfig        *config;
107         GtkTextBuffer           *buffer;
108         guint                    tabs_width;
109         GtkWrapMode              wrap_mode;
110         gboolean                 highlight;
111         PangoLanguage           *language;
112         PangoFontDescription    *font;
113         PangoFontDescription    *numbers_font;
114         guint                    print_numbers;
115         gdouble                  margin_top;
116         gdouble                  margin_bottom;
117         gdouble                  margin_left;
118         gdouble                  margin_right;
119
120         /* Default header and footer configuration */
121         gboolean                 print_header;
122         gboolean                 print_footer;
123         PangoFontDescription    *header_footer_font;
124         gchar                   *header_format_left;
125         gchar                   *header_format_center;
126         gchar                   *header_format_right;
127         gboolean                 header_separator;
128         gchar                   *footer_format_left;
129         gchar                   *footer_format_center;
130         gchar                   *footer_format_right;
131         gboolean                 footer_separator;
132
133         /* Job data */
134         guint                    first_line_number;
135         guint                    last_line_number;
136         GSList                  *paragraphs;
137
138         /* Job state */
139         gboolean                 printing;
140         guint                    idle_printing_tag;
141         GnomePrintContext       *print_ctxt;
142         GnomePrintJob           *print_job;
143         PangoContext            *pango_context;
144         PangoTabArray           *tab_array;
145         gint                     page;
146         gint                     page_count;
147         gdouble                  available_height;
148         GSList                  *current_paragraph;
149         gint                     current_paragraph_line;
150         guint                    printed_lines;
151
152         /* Cached information - all this information is obtained from
153          * other fields in the configuration */
154         GHashTable              *tag_styles;
155
156         gdouble                  page_width;
157         gdouble                  page_height;
158         /* outer margins */
159         gdouble                  doc_margin_top;
160         gdouble                  doc_margin_left;
161         gdouble                  doc_margin_right;
162         gdouble                  doc_margin_bottom;
163
164         gdouble                  header_height;
165         gdouble                  footer_height;
166         gdouble                  numbers_width;
167
168         /* printable (for the document itself) size */
169         gdouble                  text_width;
170         gdouble                  text_height;
171 };
172
173
174 enum
175 {
176         PROP_0,
177         PROP_CONFIG,
178         PROP_BUFFER,
179         PROP_TABS_WIDTH,
180         PROP_WRAP_MODE,
181         PROP_HIGHLIGHT,
182         PROP_FONT,
183         PROP_FONT_DESC,
184         PROP_NUMBERS_FONT,
185         PROP_NUMBERS_FONT_DESC,
186         PROP_PRINT_NUMBERS,
187         PROP_PRINT_HEADER,
188         PROP_PRINT_FOOTER,
189         PROP_HEADER_FOOTER_FONT,
190         PROP_HEADER_FOOTER_FONT_DESC
191 };
192
193 enum
194 {
195         BEGIN_PAGE = 0,
196         FINISHED,
197         LAST_SIGNAL
198 };
199
200 static GObjectClass *parent_class = NULL;
201 static guint         print_job_signals [LAST_SIGNAL] = { 0 };
202
203 static void     gtk_source_print_job_class_init    (GtkSourcePrintJobClass *klass);
204 static void     gtk_source_print_job_instance_init (GtkSourcePrintJob      *job);
205 static void     gtk_source_print_job_finalize      (GObject                *object);
206 static void     gtk_source_print_job_get_property  (GObject                *object,
207                                                     guint                   property_id,
208                                                     GValue                 *value,
209                                                     GParamSpec             *pspec);
210 static void     gtk_source_print_job_set_property  (GObject                *object,
211                                                     guint                   property_id,
212                                                     const GValue           *value,
213                                                     GParamSpec             *pspec);
214 static void     gtk_source_print_job_begin_page    (GtkSourcePrintJob      *job);
215
216 static void     default_print_header               (GtkSourcePrintJob      *job,
217                                                     gdouble                 x,
218                                                     gdouble                 y);
219 static void     default_print_footer               (GtkSourcePrintJob      *job,
220                                                     gdouble                 x,
221                                                     gdouble                 y);
222
223
224 GType
225 gtk_source_print_job_get_type (void)
226 {
227         static GType our_type = 0;
228
229         if (our_type == 0)
230         {
231                 static const GTypeInfo our_info = {
232                         sizeof (GtkSourcePrintJobClass),
233                         NULL,   /* base_init */
234                         NULL,   /* base_finalize */
235                         (GClassInitFunc) gtk_source_print_job_class_init,
236                         NULL,   /* class_finalize */
237                         NULL,   /* class_data */
238                         sizeof (GtkSourcePrintJob),
239                         0,      /* n_preallocs */
240                         (GInstanceInitFunc) gtk_source_print_job_instance_init
241                 };
242
243                 our_type = g_type_register_static (G_TYPE_OBJECT,
244                                                    "GtkSourcePrintJob",
245                                                    &our_info, 
246                                                    0);
247         }
248         
249         return our_type;
250 }
251         
252 static void
253 gtk_source_print_job_class_init (GtkSourcePrintJobClass *klass)
254 {
255         GObjectClass *object_class;
256
257         object_class = G_OBJECT_CLASS (klass);
258         parent_class = g_type_class_peek_parent (klass);
259                 
260         object_class->finalize     = gtk_source_print_job_finalize;
261         object_class->get_property = gtk_source_print_job_get_property;
262         object_class->set_property = gtk_source_print_job_set_property;
263
264         klass->begin_page = gtk_source_print_job_begin_page;
265         klass->finished = NULL;
266         
267         g_object_class_install_property (object_class,
268                                          PROP_CONFIG,
269                                          g_param_spec_object ("config",
270                                                               _("Configuration"),
271                                                               _("Configuration options for "
272                                                                 "the print job"),
273                                                               GNOME_TYPE_PRINT_CONFIG,
274                                                               G_PARAM_READWRITE));
275         g_object_class_install_property (object_class,
276                                          PROP_BUFFER,
277                                          g_param_spec_object ("buffer",
278                                                               _("Source Buffer"),
279                                                               _("GtkTextBuffer object to print"),
280                                                               GTK_TYPE_TEXT_BUFFER,
281                                                               G_PARAM_READWRITE));
282         g_object_class_install_property (object_class,
283                                          PROP_TABS_WIDTH,
284                                          g_param_spec_uint ("tabs_width",
285                                                             _("Tabs Width"),
286                                                             _("Width in equivalent space "
287                                                               "characters of tabs"),
288                                                             0, 100, 8,
289                                                             G_PARAM_READWRITE));
290         g_object_class_install_property (object_class,
291                                          PROP_WRAP_MODE,
292                                          g_param_spec_enum ("wrap_mode",
293                                                             _("Wrap Mode"),
294                                                             _("Word wrapping mode"),
295                                                             GTK_TYPE_WRAP_MODE,
296                                                             GTK_WRAP_NONE,
297                                                             G_PARAM_READWRITE));
298         g_object_class_install_property (object_class,
299                                          PROP_HIGHLIGHT,
300                                          g_param_spec_boolean ("highlight",
301                                                                _("Highlight"),
302                                                                _("Whether to print the "
303                                                                  "document with highlighted "
304                                                                  "syntax"),
305                                                                TRUE,
306                                                                G_PARAM_READWRITE));
307         g_object_class_install_property (object_class,
308                                          PROP_FONT,
309                                          g_param_spec_string ("font",
310                                                               _("Font"),
311                                                               _("GnomeFont name to use for the "
312                                                                 "document text (deprecated)"),
313                                                               NULL,
314                                                               G_PARAM_READWRITE));
315         g_object_class_install_property (object_class,
316                                          PROP_FONT_DESC,
317                                          g_param_spec_boxed ("font_desc",
318                                                              _("Font Description"),
319                                                              _("Font to use for the document text "
320                                                                "(e.g. \"Monospace 10\")"),
321                                                              PANGO_TYPE_FONT_DESCRIPTION,
322                                                               G_PARAM_READWRITE));
323         g_object_class_install_property (object_class,
324                                          PROP_NUMBERS_FONT,
325                                          g_param_spec_string ("numbers_font",
326                                                               _("Numbers Font"),
327                                                               _("GnomeFont name to use for the "
328                                                                 "line numbers (deprecated)"),
329                                                               NULL,
330                                                               G_PARAM_READWRITE));
331         g_object_class_install_property (object_class,
332                                          PROP_NUMBERS_FONT_DESC,
333                                          g_param_spec_boxed ("numbers_font_desc",
334                                                              _("Numbers Font"),
335                                                              _("Font description to use for the "
336                                                                "line numbers"),
337                                                              PANGO_TYPE_FONT_DESCRIPTION,
338                                                               G_PARAM_READWRITE));
339         g_object_class_install_property (object_class,
340                                          PROP_PRINT_NUMBERS,
341                                          g_param_spec_uint ("print_numbers",
342                                                             _("Print Line Numbers"),
343                                                             _("Interval of printed line numbers "
344                                                               "(0 means no numbers)"),
345                                                             0, 100, 1,
346                                                             G_PARAM_READWRITE));
347         g_object_class_install_property (object_class,
348                                          PROP_PRINT_HEADER,
349                                          g_param_spec_boolean ("print_header",
350                                                                _("Print Header"),
351                                                                _("Whether to print a header "
352                                                                  "in each page"),
353                                                                FALSE,
354                                                                G_PARAM_READWRITE));
355         g_object_class_install_property (object_class,
356                                          PROP_PRINT_FOOTER,
357                                          g_param_spec_boolean ("print_footer",
358                                                                _("Print Footer"),
359                                                                _("Whether to print a footer "
360                                                                  "in each page"),
361                                                                FALSE,
362                                                                G_PARAM_READWRITE));
363         g_object_class_install_property (object_class,
364                                          PROP_HEADER_FOOTER_FONT,
365                                          g_param_spec_string ("header_footer_font",
366                                                               _("Header and Footer Font"),
367                                                               _("GnomeFont name to use for the header "
368                                                                 "and footer (deprecated)"),
369                                                               NULL,
370                                                               G_PARAM_READWRITE));
371         g_object_class_install_property (object_class,
372                                          PROP_HEADER_FOOTER_FONT_DESC,
373                                          g_param_spec_boxed ("header_footer_font_desc",
374                                                              _("Header and Footer Font Description"),
375                                                              _("Font to use for headers and footers "
376                                                                "(e.g. \"Monospace 10\")"),
377                                                              PANGO_TYPE_FONT_DESCRIPTION,
378                                                              G_PARAM_READWRITE));
379         
380         print_job_signals [BEGIN_PAGE] =
381             g_signal_new ("begin_page",
382                           G_OBJECT_CLASS_TYPE (object_class),
383                           G_SIGNAL_RUN_LAST,
384                           G_STRUCT_OFFSET (GtkSourcePrintJobClass, begin_page),
385                           NULL, NULL,
386                           g_cclosure_marshal_VOID__VOID,
387                           G_TYPE_NONE, 
388                           0);
389         print_job_signals [FINISHED] =
390             g_signal_new ("finished",
391                           G_OBJECT_CLASS_TYPE (object_class),
392                           G_SIGNAL_RUN_FIRST,
393                           G_STRUCT_OFFSET (GtkSourcePrintJobClass, finished),
394                           NULL, NULL,
395                           g_cclosure_marshal_VOID__VOID,
396                           G_TYPE_NONE, 
397                           0);
398 }
399
400 static void
401 gtk_source_print_job_instance_init (GtkSourcePrintJob *job)
402 {
403         GtkSourcePrintJobPrivate *priv;
404
405         priv = g_new0 (GtkSourcePrintJobPrivate, 1);
406         job->priv = priv;
407
408         /* default job configuration */
409         priv->config = NULL;
410         priv->buffer = NULL;
411
412         priv->tabs_width = 8;
413         priv->wrap_mode = GTK_WRAP_NONE;
414         priv->highlight = TRUE;
415         priv->language = gtk_get_default_language ();
416         priv->font = NULL;
417         priv->numbers_font = NULL;
418         priv->print_numbers = 1;
419         priv->margin_top = 0.0;
420         priv->margin_bottom = 0.0;
421         priv->margin_left = 0.0;
422         priv->margin_right = 0.0;
423
424         priv->print_header = FALSE;
425         priv->print_footer = FALSE;
426         priv->header_footer_font = NULL;
427         priv->header_format_left = NULL;
428         priv->header_format_center = NULL;
429         priv->header_format_right = NULL;
430         priv->header_separator = FALSE;
431         priv->footer_format_left = NULL;
432         priv->footer_format_center = NULL;
433         priv->footer_format_right = NULL;
434         priv->footer_separator = FALSE;
435
436         /* initial state */
437         priv->printing = FALSE;
438         priv->print_ctxt = NULL;
439         priv->print_job = NULL;
440         priv->page = 0;
441         priv->page_count = 0;
442
443         priv->first_line_number = 0;
444         priv->paragraphs = NULL;
445         priv->tag_styles = NULL;
446
447         /* some default, sane values */
448         priv->page_width = A4_WIDTH;
449         priv->page_height = A4_HEIGHT;
450         priv->doc_margin_top = CM (1);
451         priv->doc_margin_left = CM (1);
452         priv->doc_margin_right = CM (1);
453         priv->doc_margin_bottom = CM (1);
454 }
455
456 static void
457 free_paragraphs (GSList *paras)
458 {
459         while (paras != NULL)
460         {
461                 Paragraph *para = paras->data;
462                 TextSegment *seg =  para->segment;
463                 while (seg != NULL)
464                 {
465                         TextSegment *next = seg->next;
466                         g_free (seg->text);
467                         g_free (seg);
468                         seg = next;
469                 }
470                 g_free (para);
471                 paras = g_slist_delete_link (paras, paras);
472         }
473 }
474
475 static void
476 gtk_source_print_job_finalize (GObject *object)
477 {
478         GtkSourcePrintJob *job;
479         GtkSourcePrintJobPrivate *priv;
480         
481         g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (object));
482         
483         job = GTK_SOURCE_PRINT_JOB (object);
484         priv = job->priv;
485         
486         if (priv != NULL)
487         {
488                 if (priv->config != NULL)
489                         gnome_print_config_unref (priv->config);
490                 if (priv->buffer != NULL)
491                         g_object_unref (priv->buffer);
492                 if (priv->font != NULL)
493                         pango_font_description_free (priv->font);
494                 if (priv->numbers_font != NULL)
495                         pango_font_description_free (priv->numbers_font);
496                 if (priv->header_footer_font != NULL)
497                         pango_font_description_free (priv->header_footer_font);
498                 g_free (priv->header_format_left);
499                 g_free (priv->header_format_right);
500                 g_free (priv->header_format_center);
501                 g_free (priv->footer_format_left);
502                 g_free (priv->footer_format_right);
503                 g_free (priv->footer_format_center);
504                 
505                 if (priv->print_ctxt != NULL)
506                         g_object_unref (priv->print_ctxt);
507                 if (priv->print_job != NULL)
508                         g_object_unref (priv->print_job);
509                 if (priv->pango_context != NULL)
510                         g_object_unref (priv->pango_context);
511                 if (priv->tab_array != NULL)
512                         pango_tab_array_free (priv->tab_array);
513
514                 if (priv->paragraphs != NULL)
515                         free_paragraphs (priv->paragraphs);
516                 if (priv->tag_styles != NULL)
517                         g_hash_table_destroy (priv->tag_styles);
518                 
519                 g_free (priv);
520                 job->priv = NULL;
521         }
522         
523         G_OBJECT_CLASS (parent_class)->finalize (object);
524 }
525
526 static void 
527 gtk_source_print_job_get_property (GObject    *object,
528                                    guint       prop_id,
529                                    GValue     *value,
530                                    GParamSpec *pspec)
531 {
532         GtkSourcePrintJob *job = GTK_SOURCE_PRINT_JOB (object);
533
534         switch (prop_id)
535         {
536                 case PROP_CONFIG:
537                         g_value_set_object (value, job->priv->config);
538                         break;
539                         
540                 case PROP_BUFFER:
541                         g_value_set_object (value, job->priv->buffer);
542                         break;
543
544                 case PROP_TABS_WIDTH:
545                         g_value_set_uint (value, job->priv->tabs_width);
546                         break;
547                         
548                 case PROP_WRAP_MODE:
549                         g_value_set_enum (value, job->priv->wrap_mode);
550                         break;
551
552                 case PROP_HIGHLIGHT:
553                         g_value_set_boolean (value, job->priv->highlight);
554                         break;
555                         
556                 case PROP_FONT:
557                         g_value_take_string (value, gtk_source_print_job_get_font (job));
558                         break;
559                         
560                 case PROP_FONT_DESC:
561                         g_value_set_boxed (value, gtk_source_print_job_get_font_desc (job));
562                         break;
563                         
564                 case PROP_NUMBERS_FONT:
565                         g_value_take_string (value, gtk_source_print_job_get_numbers_font (job));
566                         break;
567                         
568                 case PROP_NUMBERS_FONT_DESC:
569                         g_value_set_boxed (value, gtk_source_print_job_get_numbers_font_desc (job));
570                         break;
571                         
572                 case PROP_PRINT_NUMBERS:
573                         g_value_set_uint (value, job->priv->print_numbers);
574                         break;
575                         
576                 case PROP_PRINT_HEADER:
577                         g_value_set_boolean (value, job->priv->print_header);
578                         break;
579                         
580                 case PROP_PRINT_FOOTER:
581                         g_value_set_boolean (value, job->priv->print_footer);
582                         break;
583                         
584                 case PROP_HEADER_FOOTER_FONT:
585                         g_value_take_string (value,
586                                              gtk_source_print_job_get_header_footer_font (job));
587                         break;
588                         
589                 case PROP_HEADER_FOOTER_FONT_DESC:
590                         g_value_set_boxed (value,
591                                            gtk_source_print_job_get_header_footer_font_desc (job));
592                         break;
593                         
594                 default:
595                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
596                         break;
597         }
598 }
599
600 static void 
601 gtk_source_print_job_set_property (GObject      *object,
602                                    guint         prop_id,
603                                    const GValue *value,
604                                    GParamSpec   *pspec)
605 {
606         GtkSourcePrintJob *job = GTK_SOURCE_PRINT_JOB (object);
607
608         switch (prop_id)
609         {
610                 case PROP_CONFIG:
611                         gtk_source_print_job_set_config (job, g_value_get_object (value));
612                         break;
613                         
614                 case PROP_BUFFER:
615                         gtk_source_print_job_set_buffer (job, g_value_get_object (value));
616                         break;
617                         
618                 case PROP_TABS_WIDTH:
619                         gtk_source_print_job_set_tabs_width (job, g_value_get_uint (value));
620                         break;
621                         
622                 case PROP_WRAP_MODE:
623                         gtk_source_print_job_set_wrap_mode (job, g_value_get_enum (value));
624                         break;
625
626                 case PROP_HIGHLIGHT:
627                         gtk_source_print_job_set_highlight (job, g_value_get_boolean (value));
628                         break;
629
630                 case PROP_FONT:
631                         gtk_source_print_job_set_font (job, g_value_get_string (value));
632                         break;
633
634                 case PROP_FONT_DESC:
635                         gtk_source_print_job_set_font_desc (job, g_value_get_boxed (value));
636                         break;
637                         
638                 case PROP_NUMBERS_FONT:
639                         gtk_source_print_job_set_numbers_font (job, g_value_get_string (value));
640                         break;
641                         
642                 case PROP_NUMBERS_FONT_DESC:
643                         gtk_source_print_job_set_numbers_font_desc (job, g_value_get_boxed (value));
644                         break;
645
646                 case PROP_PRINT_NUMBERS:
647                         gtk_source_print_job_set_print_numbers (job, g_value_get_uint (value));
648                         break;
649                         
650                 case PROP_PRINT_HEADER:
651                         gtk_source_print_job_set_print_header (job, g_value_get_boolean (value));
652                         break;
653
654                 case PROP_PRINT_FOOTER:
655                         gtk_source_print_job_set_print_footer (job, g_value_get_boolean (value));
656                         break;
657
658                 case PROP_HEADER_FOOTER_FONT:
659                         gtk_source_print_job_set_header_footer_font (job,
660                                                                      g_value_get_string (value));
661                         break;
662                         
663                 case PROP_HEADER_FOOTER_FONT_DESC:
664                         gtk_source_print_job_set_header_footer_font_desc (job,
665                                                                           g_value_get_boxed (value));
666                         break;
667
668                 default:
669                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
670                         break;
671         }
672 }
673
674 static void 
675 gtk_source_print_job_begin_page (GtkSourcePrintJob *job)
676 {
677         g_return_if_fail (job->priv->printing);
678         
679         if (job->priv->print_header && job->priv->header_height > 0)
680         {
681                 gdouble x, y;
682
683                 x = job->priv->doc_margin_left + job->priv->margin_left;
684                 y = job->priv->page_height - job->priv->doc_margin_top - job->priv->margin_top;
685                 default_print_header (job, x, y);
686         }
687
688         if (job->priv->print_footer && job->priv->footer_height > 0)
689         {
690                 gdouble x, y;
691
692                 x = job->priv->doc_margin_left + job->priv->margin_left;
693                 y = job->priv->doc_margin_bottom +
694                         job->priv->margin_bottom +
695                         job->priv->footer_height;
696                 default_print_footer (job, x, y);
697         }
698 }
699
700 /* ---- gnome-print / Pango convenience functions */
701
702 /* Gets the width of a layout in gnome-print coordinates */
703 static gdouble
704 get_layout_width (PangoLayout *layout)
705 {
706         gint layout_width;
707
708         pango_layout_get_size (layout, &layout_width, NULL);
709         return (gdouble) layout_width / PANGO_SCALE;
710 }
711
712 /* Gets the ascent/descent of a font in gnome-print coordinates */
713 static void
714 get_font_ascent_descent (GtkSourcePrintJob    *job,
715                          PangoFontDescription *desc,
716                          gdouble              *ascent,
717                          gdouble              *descent)
718 {
719         PangoFontMetrics *metrics;
720         
721         metrics = pango_context_get_metrics (job->priv->pango_context,
722                                              desc,
723                                              job->priv->language);
724
725         if (ascent)
726                 *ascent = (gdouble) pango_font_metrics_get_ascent (metrics) / PANGO_SCALE;
727         if (descent)
728                 *descent = (gdouble) pango_font_metrics_get_descent (metrics) / PANGO_SCALE;
729
730         pango_font_metrics_unref (metrics);
731 }
732
733 /* Draws the first line in a layout; we use this for one-line layouts
734  * to get baseline alignment */
735 static void
736 show_first_layout_line (GnomePrintContext *print_ctxt,
737                         PangoLayout       *layout)
738 {
739         PangoLayoutLine *line;
740
741         line = pango_layout_get_lines (layout)->data;
742         gnome_print_pango_layout_line (print_ctxt, line);
743 }
744
745 static PangoLayout *
746 get_line_number_layout (GtkSourcePrintJob *job,
747                         guint              line_number)
748 {
749         PangoLayout *layout;
750         gchar *num_str;
751
752         num_str = g_strdup_printf ("%d", line_number);
753         layout = pango_layout_new (job->priv->pango_context);
754         pango_layout_set_font_description (layout, job->priv->numbers_font);
755         pango_layout_set_text (layout, num_str, -1);
756         g_free (num_str);
757
758         return layout;
759 }
760
761 /* ---- Configuration functions */
762
763 static void
764 ensure_print_config (GtkSourcePrintJob *job)
765 {
766         if (job->priv->config == NULL)
767                 job->priv->config = gnome_print_config_default ();
768         if (job->priv->font == NULL)
769                 job->priv->font = pango_font_description_from_string (DEFAULT_FONT_NAME);
770 }
771
772 static gboolean
773 update_page_size_and_margins (GtkSourcePrintJob *job)
774 {
775         PangoLayout *layout;
776         gdouble ascent, descent;
777         
778         gnome_print_job_get_page_size_from_config (job->priv->config, 
779                                                    &job->priv->page_width,
780                                                    &job->priv->page_height);
781
782         gnome_print_config_get_length (job->priv->config, GNOME_PRINT_KEY_PAGE_MARGIN_TOP,
783                                        &job->priv->doc_margin_top, NULL);
784         gnome_print_config_get_length (job->priv->config, GNOME_PRINT_KEY_PAGE_MARGIN_BOTTOM,
785                                        &job->priv->doc_margin_bottom, NULL);
786         gnome_print_config_get_length (job->priv->config, GNOME_PRINT_KEY_PAGE_MARGIN_LEFT,
787                                        &job->priv->doc_margin_left, NULL);
788         gnome_print_config_get_length (job->priv->config, GNOME_PRINT_KEY_PAGE_MARGIN_RIGHT,
789                                        &job->priv->doc_margin_right, NULL);
790
791         /* set default fonts for numbers and header/footer */
792         if (job->priv->numbers_font == NULL)
793                 job->priv->numbers_font = pango_font_description_copy (job->priv->font);
794         
795         if (job->priv->header_footer_font == NULL)
796                 job->priv->header_footer_font = pango_font_description_copy (job->priv->font);
797         
798         /* calculate numbers width */
799         if (job->priv->print_numbers > 0)
800         {
801                 layout = get_line_number_layout (job, job->priv->last_line_number);
802                 job->priv->numbers_width = get_layout_width (layout) + NUMBERS_TEXT_SEPARATION;
803                 g_object_unref (layout);
804         }
805         else
806                 job->priv->numbers_width = 0.0;
807
808         get_font_ascent_descent (job, job->priv->header_footer_font, &ascent, &descent);
809
810         /* calculate header/footer height */
811         if (job->priv->print_header &&
812             (job->priv->header_format_left != NULL ||
813              job->priv->header_format_center != NULL ||
814              job->priv->header_format_right != NULL))
815                 job->priv->header_height = HEADER_FOOTER_SIZE * (ascent + descent);
816         else
817                 job->priv->header_height = 0.0;
818
819         if (job->priv->print_footer &&
820             (job->priv->footer_format_left != NULL ||
821              job->priv->footer_format_center != NULL ||
822              job->priv->footer_format_right != NULL))
823                 job->priv->footer_height = HEADER_FOOTER_SIZE * (ascent + descent);
824         else
825                 job->priv->footer_height = 0.0;
826
827         /* verify that the user provided margins are not too excesive
828          * and that we still have room for the text */
829         job->priv->text_width = (job->priv->page_width -
830                                  job->priv->doc_margin_left - job->priv->doc_margin_right -
831                                  job->priv->margin_left - job->priv->margin_right -
832                                  job->priv->numbers_width);
833         
834         job->priv->text_height = (job->priv->page_height -
835                                   job->priv->doc_margin_top - job->priv->doc_margin_bottom -
836                                   job->priv->margin_top - job->priv->margin_bottom -
837                                   job->priv->header_height - job->priv->footer_height);
838
839         /* FIXME: put some saner values than 5cm - Gustavo */
840         g_return_val_if_fail (job->priv->text_width > CM(5.0), FALSE);
841         g_return_val_if_fail (job->priv->text_height > CM(5.0), FALSE);
842
843         return TRUE;
844 }
845
846 /* We want a uniform tab width for the entire job without regard to style
847  * See comments in gtksourceview.c:calculate_real_tab_width
848  */
849 static gint
850 calculate_real_tab_width (GtkSourcePrintJob *job, guint tab_size, gchar c)
851 {
852         PangoLayout *layout;
853         gchar *tab_string;
854         gint tab_width = 0;
855
856         if (tab_size == 0)
857                 return -1;
858
859         tab_string = g_strnfill (tab_size, c);
860         layout = pango_layout_new (job->priv->pango_context);
861         pango_layout_set_text (layout, tab_string, -1);
862         g_free (tab_string);
863
864         pango_layout_get_size (layout, &tab_width, NULL);
865         g_object_unref (G_OBJECT (layout));
866         
867         return tab_width;
868 }
869
870 static gboolean
871 setup_pango_context (GtkSourcePrintJob *job)
872 {
873         PangoFontMap *font_map;
874         gint real_tab_width;
875
876         if (!job->priv->pango_context)
877         {
878                 font_map = gnome_print_pango_get_default_font_map ();
879                 job->priv->pango_context = gnome_print_pango_create_context (font_map);
880         }
881
882         pango_context_set_language (job->priv->pango_context, job->priv->language);
883         pango_context_set_font_description (job->priv->pango_context, job->priv->font);
884
885         if (job->priv->tab_array)
886         {
887                 pango_tab_array_free (job->priv->tab_array);
888                 job->priv->tab_array = NULL;
889         }
890         
891         real_tab_width = calculate_real_tab_width (job, job->priv->tabs_width, ' ');
892         if (real_tab_width > 0)
893         {
894                 job->priv->tab_array = pango_tab_array_new (1, FALSE);
895                 pango_tab_array_set_tab (job->priv->tab_array, 0, PANGO_TAB_LEFT, real_tab_width);
896         }
897         
898         return TRUE;
899 }
900
901 /* ----- Helper functions */
902
903 static gchar * 
904 font_description_to_gnome_font_name (PangoFontDescription *desc)
905 {
906         GnomeFontFace *font_face;
907         gchar *retval;
908
909         /* Will always return some font */
910         font_face = gnome_font_face_find_closest_from_pango_description (desc);
911
912         retval = g_strdup_printf("%s %f",
913                                  gnome_font_face_get_name (font_face),
914                                  (double) pango_font_description_get_size (desc) / PANGO_SCALE);
915         g_object_unref (font_face);
916
917         return retval;
918 }
919
920 /*
921  * The following routines are duplicated in gedit/gedit/gedit-prefs-manager.c
922  */
923
924 /* Do this ourselves since gnome_font_find_closest() doesn't call
925  * gnome_font_face_find_closest() (probably a gnome-print bug)
926  */
927 static void
928 face_and_size_from_full_name (const guchar   *name,
929                               GnomeFontFace **face,
930                               gdouble        *size)
931 {
932         char *copy;
933         char *str_size;
934
935         copy = g_strdup (name);
936         str_size = strrchr (copy, ' ');
937         if (str_size)
938         {
939                 *str_size = 0;
940                 str_size ++;
941                 *size = atof (str_size);
942         }
943         else
944         {
945                 *size = 12;
946         }
947
948         *face = gnome_font_face_find_closest (copy);
949         g_free (copy);
950 }
951
952 static PangoFontDescription *
953 font_description_from_gnome_font_name (const char *font_name)
954 {
955         GnomeFontFace *face;
956         PangoFontDescription *desc;
957         PangoStyle style;
958         PangoWeight weight;
959         gdouble size;
960
961         face_and_size_from_full_name (font_name, &face, &size);
962
963         /* Pango and GnomePrint have basically the same numeric weight values */
964         weight = (PangoWeight) gnome_font_face_get_weight_code (face);
965         style = gnome_font_face_is_italic (face) ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL;
966
967         desc = pango_font_description_new ();
968         pango_font_description_set_family (desc, gnome_font_face_get_family_name (face));
969         pango_font_description_set_weight (desc, weight);
970         pango_font_description_set_style (desc, style);
971         pango_font_description_set_size (desc, size * PANGO_SCALE);
972
973         g_object_unref (face);
974
975         return desc;
976 }
977
978 /* ---- TextStyle functions */
979
980 static TextStyle * 
981 text_style_new (GtkSourcePrintJob *job, GtkTextTag *tag)
982 {
983         TextStyle *style;
984         gboolean bg_set, fg_set;
985         
986         g_return_val_if_fail (tag != NULL && GTK_IS_TEXT_TAG (tag), NULL);
987
988         style = g_new0 (TextStyle, 1);
989
990         g_object_get (G_OBJECT (tag),
991                       "background_set", &bg_set,
992                       "foreground_set", &fg_set,
993                       "font_desc", &style->font_desc,
994                       "scale", &style->scale,
995                       "underline", &style->underline,
996                       "strikethrough", &style->strikethrough,
997                       NULL);
998
999         if (fg_set)
1000                 g_object_get (G_OBJECT (tag), "foreground_gdk", &style->foreground, NULL);
1001
1002         if (bg_set)
1003                 g_object_get (G_OBJECT (tag), "background_gdk", &style->background, NULL);
1004         
1005         return style;
1006 }
1007
1008 static void
1009 text_style_free (TextStyle *style)
1010 {
1011         pango_font_description_free (style->font_desc);
1012         if (style->foreground)
1013                 gdk_color_free (style->foreground);
1014         if (style->background)
1015                 gdk_color_free (style->background);
1016         g_free (style);
1017 }
1018
1019 static TextStyle * 
1020 get_style (GtkSourcePrintJob *job, const GtkTextIter *iter)
1021 {
1022         GSList *tags, *t;
1023         GtkTextTag *tag = NULL;
1024         TextStyle *style = NULL;
1025         
1026         if (job->priv->tag_styles == NULL)
1027         {
1028                 job->priv->tag_styles = g_hash_table_new_full (
1029                         g_direct_hash, g_direct_equal,
1030                         NULL, (GDestroyNotify) text_style_free);
1031         }
1032         
1033         /* get the tags at iter */
1034         tags = gtk_text_iter_get_tags (iter);
1035
1036         /* now find the GtkSourceTag (if any) which applies at iter */
1037         /* FIXME: this makes the assumption that the style at a given
1038          * iter is only determined by one GtkSourceTag (the one with
1039          * highest priority).  This is true for now, but could change
1040          * in the future - Gustavo */
1041         t = tags;
1042         while (t != NULL)
1043         {
1044                 if (GTK_IS_TEXT_TAG (t->data))
1045                         tag = t->data;
1046                 t = g_slist_next (t);
1047         }
1048         g_slist_free (tags);
1049
1050         /* now we lookup the tag style in the cache */
1051         if (tag != NULL)
1052         {
1053                 style = g_hash_table_lookup (job->priv->tag_styles, tag);
1054                 if (style == NULL)
1055                 {
1056                         /* create a style for the tag and cache it */
1057                         style = text_style_new (job, tag);
1058                         g_hash_table_insert (job->priv->tag_styles, tag, style);
1059                 }
1060         }
1061
1062         return style;
1063 }
1064
1065 /* ----- Text fetching functions */
1066
1067 static gboolean 
1068 get_text_simple (GtkSourcePrintJob *job,
1069                  GtkTextIter       *start,
1070                  GtkTextIter       *end)
1071 {
1072         GtkTextIter iter;
1073
1074         while (gtk_text_iter_compare (start, end) < 0)
1075         {
1076                 Paragraph *para;
1077                 TextSegment *seg;
1078                 
1079                 /* get a line of text */
1080                 iter = *start;
1081                 if (!gtk_text_iter_ends_line (&iter))
1082                         gtk_text_iter_forward_to_line_end (&iter);
1083                 
1084                 if (gtk_text_iter_compare (&iter, end) > 0)
1085                         iter = *end;
1086
1087                 
1088                 seg = g_new0 (TextSegment, 1);
1089                 seg->next = NULL;  /* only one segment per line, since there's no style change */
1090                 seg->style = NULL; /* use default style */
1091                 /* FIXME: handle invisible text properly.  This also
1092                  * assumes the text has no embedded images and
1093                  * stuff */
1094                 seg->text = gtk_text_iter_get_slice (start, &iter);
1095
1096                 para = g_new0 (Paragraph, 1);
1097                 para->segment = seg;
1098
1099                 /* add the line of text to the job */
1100                 job->priv->paragraphs = g_slist_prepend (job->priv->paragraphs, para);
1101
1102                 gtk_text_iter_forward_line (&iter);
1103                 
1104                 /* advance to next line */
1105                 *start = iter;
1106         }
1107         job->priv->paragraphs = g_slist_reverse (job->priv->paragraphs);
1108
1109         return TRUE;
1110 }
1111
1112 static gboolean 
1113 get_text_with_style (GtkSourcePrintJob *job,
1114                      GtkTextIter       *start,
1115                      GtkTextIter       *end)
1116 {
1117         GtkTextIter limit, next_toggle;
1118         gboolean have_toggle;
1119         GdkPixbuf *image = NULL;
1120         
1121         /* make sure the region to print is highlighted */
1122         /*_gtk_source_buffer_highlight_region (job->priv->buffer, start, end, TRUE); */
1123
1124         next_toggle = *start;
1125         have_toggle = gtk_text_iter_forward_to_tag_toggle (&next_toggle, NULL);
1126         
1127         /* FIXME: handle invisible text properly.  This also assumes
1128          * the text has no embedded images and stuff */
1129         while (gtk_text_iter_compare (start, end) < 0)
1130         {
1131                 TextStyle *style;
1132                 TextSegment *seg;
1133                 Paragraph *para;
1134                 
1135                 para = g_new0 (Paragraph, 1);
1136
1137                 /* get the style at the start of the line */
1138                 style = get_style (job, start);
1139
1140                 /* get a line of text - limit points to the end of the line */
1141                 limit = *start;
1142                 if (!gtk_text_iter_ends_line (&limit))
1143                         gtk_text_iter_forward_to_line_end (&limit);
1144                 
1145                 if (gtk_text_iter_compare (&limit, end) > 0)
1146                         limit = *end;
1147
1148                 /* create the first segment for the line */
1149                 para->segment = seg = g_new0 (TextSegment, 1);
1150                 seg->style = style;
1151
1152                 /* while the next tag toggle is within the line, we check to see
1153                  * if the style has changed at each tag toggle position, and if so,
1154                  * create new segments */
1155                 while (have_toggle && gtk_text_iter_compare (&next_toggle, &limit) < 0)
1156                 {
1157                         /* check style changes */
1158                         style = get_style (job, &next_toggle);
1159                         if (style != seg->style)
1160                         {
1161                                 TextSegment *new_seg;
1162                                 /* style has changed, thus we need to
1163                                  * create a new segment */
1164                                 /* close the current segment */
1165                                 seg->text = gtk_text_iter_get_slice (start, &next_toggle);
1166                                 if ((image = gtk_text_iter_get_pixbuf(start)) != NULL)
1167                                         seg->image = image;
1168                                 
1169                                 *start = next_toggle;
1170                                 
1171                                 new_seg = g_new0 (TextSegment, 1);
1172                                 seg->next = new_seg;
1173                                 seg = new_seg;
1174                                 seg->style = style;
1175                         }
1176
1177                         have_toggle = gtk_text_iter_forward_to_tag_toggle (&next_toggle, NULL);                 
1178                 }
1179                 
1180                 /* close the line */
1181                 seg->next = NULL;
1182                 seg->text = gtk_text_iter_get_slice (start, &limit);
1183                 if ((image = gtk_text_iter_get_pixbuf(start)) != NULL)
1184                         seg->image = image;
1185
1186                 /* add the line of text to the job */
1187                 job->priv->paragraphs = g_slist_prepend (job->priv->paragraphs, para);
1188
1189                 /* advance to next line */
1190                 *start = limit;
1191                 gtk_text_iter_forward_line (start);
1192
1193                 if (gtk_text_iter_compare (&next_toggle, start) < 0) {
1194                         next_toggle = *start;
1195                         have_toggle = gtk_text_iter_forward_to_tag_toggle (&next_toggle, NULL);
1196                 }
1197         }
1198         job->priv->paragraphs = g_slist_reverse (job->priv->paragraphs);
1199
1200         return TRUE;
1201 }
1202
1203 static gboolean 
1204 get_text_to_print (GtkSourcePrintJob *job,
1205                    const GtkTextIter *start,
1206                    const GtkTextIter *end)
1207 {
1208         GtkTextIter _start, _end;
1209         gboolean retval;
1210         
1211         g_return_val_if_fail (start != NULL && end != NULL, FALSE);
1212         g_return_val_if_fail (job->priv->buffer != NULL, FALSE);
1213
1214         _start = *start;
1215         _end = *end;
1216
1217         /* erase any previous data */
1218         if (job->priv->paragraphs != NULL)
1219         {
1220                 free_paragraphs (job->priv->paragraphs);
1221                 job->priv->paragraphs = NULL;
1222         }
1223         if (job->priv->tag_styles != NULL)
1224         {
1225                 g_hash_table_destroy (job->priv->tag_styles);
1226                 job->priv->tag_styles = NULL;
1227         }
1228
1229         /* provide ordered iters */
1230         gtk_text_iter_order (&_start, &_end);
1231
1232         /* save the first and last line numbers for future reference */
1233         job->priv->first_line_number = gtk_text_iter_get_line (&_start) + 1;
1234         job->priv->last_line_number = gtk_text_iter_get_line (&_end) + 1;
1235
1236         if (!job->priv->highlight)
1237                 retval = get_text_simple (job, &_start, &_end);
1238         else
1239                 retval = get_text_with_style (job, &_start, &_end);
1240
1241         if (retval && job->priv->paragraphs == NULL)
1242         {
1243                 Paragraph *para;
1244                 TextSegment *seg;
1245                 
1246                 /* add an empty line to allow printing empty documents */
1247                 seg = g_new0 (TextSegment, 1);
1248                 seg->next = NULL;
1249                 seg->style = NULL; /* use default style */
1250                 seg->text = g_strdup ("");
1251
1252                 para = g_new0 (Paragraph, 1);
1253                 para->segment = seg;
1254
1255                 job->priv->paragraphs = g_slist_prepend (job->priv->paragraphs, para);
1256         }
1257
1258         return retval;
1259 }
1260
1261 /* ----- Pagination functions */
1262
1263 static void
1264 add_attribute_to_list (PangoAttribute *attr, 
1265                        PangoAttrList  *list,
1266                        guint           index,
1267                        gsize           len)
1268 {
1269         attr->start_index = index;
1270         attr->end_index = index + len;
1271         pango_attr_list_insert (list, attr);
1272 }
1273
1274 static void *
1275 create_layout_for_para (GtkSourcePrintJob *job,
1276                         Paragraph         *para,
1277                         gboolean          *is_image)
1278 {
1279         GString *text;
1280         PangoLayout *layout;
1281         PangoAttrList *attrs;
1282         TextSegment *seg;
1283         gint index;
1284         GdkPixbuf *image = NULL;
1285         text = g_string_new (NULL);
1286         attrs = pango_attr_list_new ();
1287         
1288         seg = para->segment;
1289         index = 0;
1290
1291         while (seg != NULL)
1292         {
1293                 gsize seg_len = strlen (seg->text);
1294                 g_string_append (text, seg->text);
1295
1296                 if (seg->style)
1297                 {
1298                         PangoAttribute *attr;
1299
1300                         attr = pango_attr_font_desc_new (seg->style->font_desc);
1301                         add_attribute_to_list (attr, attrs, index, seg_len);
1302
1303                         if (seg->style->scale != PANGO_SCALE_MEDIUM) 
1304                         {
1305                                 attr = pango_attr_scale_new (seg->style->scale);
1306                                 add_attribute_to_list (attr, attrs, index, seg_len);
1307                         }
1308
1309                         if (seg->style->foreground)
1310                         {
1311                                 attr = pango_attr_foreground_new (seg->style->foreground->red,
1312                                                                   seg->style->foreground->green,
1313                                                                   seg->style->foreground->blue);
1314                                 add_attribute_to_list (attr, attrs, index, seg_len);
1315                         }
1316
1317                         if (seg->style->background)
1318                         {
1319                                 attr = pango_attr_background_new (seg->style->background->red,
1320                                                                   seg->style->background->green,
1321                                                                   seg->style->background->blue);
1322                                 add_attribute_to_list (attr, attrs, index, seg_len);
1323                         }
1324
1325                         if (seg->style->strikethrough)
1326                         {
1327                                 attr = pango_attr_strikethrough_new (TRUE);
1328                                 add_attribute_to_list (attr, attrs, index, seg_len);
1329                         }
1330
1331                         if (seg->style->underline != PANGO_UNDERLINE_NONE)
1332                         {
1333                                 attr = pango_attr_underline_new (seg->style->underline);
1334                                 add_attribute_to_list (attr, attrs, index, seg_len);
1335                         }
1336                 }
1337
1338                 if (seg->image) {
1339                         image = seg->image;
1340                 }
1341
1342                 index += seg_len;
1343                 seg = seg->next;
1344         }
1345
1346         if (image != NULL) {
1347                 *is_image = TRUE;
1348                 return image;
1349         }
1350
1351         layout = pango_layout_new (job->priv->pango_context);
1352         
1353         pango_layout_set_width (layout, job->priv->text_width * PANGO_SCALE);
1354         
1355         switch (job->priv->wrap_mode)   {
1356         case GTK_WRAP_CHAR:
1357                 pango_layout_set_wrap (layout, PANGO_WRAP_CHAR);
1358                 break;
1359         case GTK_WRAP_WORD:
1360                 pango_layout_set_wrap (layout, PANGO_WRAP_WORD);
1361                 break;
1362         case GTK_WRAP_WORD_CHAR:
1363                 pango_layout_set_wrap (layout, PANGO_WRAP_WORD_CHAR);
1364                 break;
1365         case GTK_WRAP_NONE:
1366                 /* FIXME: hack 
1367                  * Ellipsize the paragraph when text wrapping is disabled.
1368                  * Another possibility would be to set the width so the text 
1369                  * breaks into multiple lines, and paginate/render just the 
1370                  * first one.
1371                  * See also Comment #23 by Owen on bug #143874.
1372                  */
1373
1374                 /* orph says to comment this out and commit it.
1375                    PANGO_ELLIPSIZE_END is not available in pango
1376                    1.4.1, at least, and he says this code is never
1377                    used. */
1378                 /*pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END);*/
1379
1380                 break;
1381         }
1382
1383         if (job->priv->tab_array)
1384                 pango_layout_set_tabs (layout, job->priv->tab_array);
1385         
1386         pango_layout_set_text (layout, text->str, text->len);
1387         pango_layout_set_attributes (layout, attrs);
1388         *is_image = FALSE;
1389
1390         /* FIXME: <horrible-hack> 
1391          * For empty paragraphs, pango_layout_iter_get_baseline() returns 0,
1392          * so I check this condition and add a space character to force 
1393          * the calculation of the baseline. I don't like that, but I
1394          * didn't find a better way to do it. Note that a paragraph is 
1395          * considered empty either when it has no characters, or when 
1396          * it only has tabs.
1397          * See comment #22 and #23 on bug #143874.
1398          */
1399         if (job->priv->print_numbers > 0)
1400         {
1401                 PangoLayoutIter *iter;
1402                 iter = pango_layout_get_iter (layout);
1403                 if (pango_layout_iter_get_baseline (iter) == 0)
1404                 {
1405                         g_string_append_c (text, ' ');
1406                         pango_layout_set_text (layout, text->str, text->len);
1407                 }
1408                 pango_layout_iter_free (iter);
1409         }
1410         /* FIXME: </horrible-hack> */
1411         
1412         g_string_free (text, TRUE);
1413         pango_attr_list_unref (attrs);
1414
1415         return layout;
1416 }
1417
1418 /* The break logic in this function needs to match that in print_paragraph */
1419 static void
1420 paginate_paragraph (GtkSourcePrintJob *job,
1421                     Paragraph         *para)
1422 {
1423         PangoLayout *layout;
1424         PangoLayoutIter *iter;
1425         PangoRectangle logical_rect;
1426         gdouble max;
1427         gdouble page_skip;
1428         GdkPixbuf *image;
1429         void *tmp;
1430         gboolean is_image = FALSE;
1431         
1432         tmp = create_layout_for_para (job, para, &is_image);
1433         if (!is_image) {
1434                 layout = (PangoLayout *)tmp;
1435                 image  = NULL;
1436         } else {
1437                 image  = (GdkPixbuf *)tmp;
1438                 layout = NULL;
1439         }
1440
1441         if (image == NULL) {
1442                 iter = pango_layout_get_iter (layout);
1443
1444                 max = 0;
1445                 page_skip = 0;
1446
1447                 do
1448                 {
1449                         pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
1450                         max = (gdouble) (logical_rect.y + logical_rect.height) / PANGO_SCALE;
1451
1452                         if (max - page_skip > job->priv->available_height)
1453                         {
1454                                 /* "create" a new page */
1455                                 job->priv->page_count++;
1456                                 job->priv->available_height = job->priv->text_height;
1457                                 page_skip = (gdouble) logical_rect.y / PANGO_SCALE;
1458                         }
1459
1460                 }
1461                 while (pango_layout_iter_next_line (iter));
1462                 job->priv->available_height -= max - page_skip;
1463                 pango_layout_iter_free (iter);
1464                 g_object_unref (layout);
1465         } else {
1466                 gint max_height = job->priv->available_height;
1467                 gint image_height = gdk_pixbuf_get_height(image);
1468                 gint image_width = gdk_pixbuf_get_width(image);
1469                 gint scaled_height = 0, scaled_width = 0;
1470                 image_viewer_get_resized_size(image_width,
1471                                          image_height,
1472                                          job->priv->text_width, 
1473                                          job->priv->text_height,
1474                                          &scaled_width, &scaled_height);
1475                 if (scaled_height > max_height) {
1476                         job->priv->page_count++;
1477                         job->priv->available_height = job->priv->text_height - scaled_height;
1478                 } else {
1479                         job->priv->available_height -= scaled_height;
1480                 }
1481         }
1482
1483 }
1484
1485 static gboolean 
1486 paginate_text (GtkSourcePrintJob *job)
1487 {
1488         GSList *l;
1489         guint line_number;
1490         
1491         /* set these to zero so the first break_line creates a new page */
1492         job->priv->page_count = 0;
1493         job->priv->available_height = 0;
1494         line_number = job->priv->first_line_number;
1495         l = job->priv->paragraphs;
1496         while (l != NULL)
1497         {
1498                 Paragraph *para = l->data;
1499
1500                 para->line_number = line_number;
1501                 paginate_paragraph (job, para);
1502                 
1503                 line_number++;
1504                 l = g_slist_next (l);
1505         }
1506
1507         /* FIXME: do we have any error condition which can force us to
1508          * return %FALSE? - Gustavo */
1509         return TRUE;
1510 }
1511
1512 /* ---- Printing functions */
1513
1514 static void
1515 begin_page (GtkSourcePrintJob *job)
1516 {
1517         gnome_print_beginpage (job->priv->print_ctxt, NULL);
1518
1519         g_signal_emit (job, print_job_signals [BEGIN_PAGE], 0);
1520 }
1521
1522 static void
1523 end_page (GtkSourcePrintJob *job)
1524 {
1525         gnome_print_showpage (job->priv->print_ctxt);
1526 }
1527
1528 static void 
1529 print_line_number (GtkSourcePrintJob *job,
1530                    guint              line_number,
1531                    gdouble            x,
1532                    gdouble            y)
1533 {
1534         PangoLayout *layout;
1535
1536         layout = get_line_number_layout (job, line_number);
1537
1538         x = x + job->priv->numbers_width - get_layout_width (layout) - NUMBERS_TEXT_SEPARATION;
1539         gnome_print_moveto (job->priv->print_ctxt, x, y);
1540         
1541         show_first_layout_line (job->priv->print_ctxt, layout);
1542         
1543         g_object_unref (layout);
1544 }       
1545
1546 /* The break logic in this function needs to match that in paginate_paragraph
1547  *
1548  * @start_line is the first line in the paragraph to print
1549  * @y is updated to the position after the portion of the paragraph we printed
1550  * @baseline_out is set to the baseline of the first line of the paragraph
1551  *   if we printed it. (And not set otherwise)
1552  * 
1553  * Returns the first unprinted line in the paragraph (unprinted because it
1554  * flowed onto the next page) or -1 if the entire paragraph was printed.
1555  */
1556 static gint
1557 print_paragraph (GtkSourcePrintJob *job,
1558                  Paragraph         *para,
1559                  gint               start_line,
1560                  gdouble            x,
1561                  gdouble           *y,
1562                  gdouble           *baseline_out,
1563                  gboolean           force_fit)
1564 {
1565         PangoLayout *layout;
1566         PangoLayoutIter *iter;
1567         PangoRectangle logical_rect;
1568         int current_line;
1569         gdouble max;
1570         gdouble page_skip;
1571         gdouble baseline;
1572         int result = -1;
1573         GdkPixbuf *image;
1574         void *tmp;
1575         gboolean is_image;
1576
1577         tmp = create_layout_for_para (job, para, &is_image);
1578         if (!is_image) {
1579                 layout = (PangoLayout *)tmp;
1580                 image  = NULL;
1581         } else {
1582                 image  = (GdkPixbuf *)tmp;
1583                 layout = NULL;
1584         }
1585
1586         if (!is_image) {
1587                 iter = pango_layout_get_iter (layout);
1588
1589                 /* Skip over lines already printed on previous page(s) */
1590                 for (current_line = 0; current_line < start_line; current_line++)
1591                         pango_layout_iter_next_line (iter);
1592
1593                 max = 0;
1594                 page_skip = 0;
1595
1596                 do
1597                 {
1598                         pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
1599                         max = (gdouble) (logical_rect.y + logical_rect.height) / PANGO_SCALE;
1600
1601                         if (current_line == start_line)
1602                                 page_skip = (gdouble) logical_rect.y / PANGO_SCALE;
1603
1604                         if (max - page_skip > job->priv->available_height)
1605                         {
1606                                 result = current_line; /* Save position for next page */
1607                                 break;
1608                         }
1609
1610                         baseline = (gdouble) pango_layout_iter_get_baseline (iter) / PANGO_SCALE;
1611                         baseline = *y + page_skip - baseline; /* Adjust to global coordinates */
1612                         if (current_line == 0)
1613                                 *baseline_out = baseline;
1614
1615                         gnome_print_moveto (job->priv->print_ctxt,
1616                                             x + (gdouble) logical_rect.x / PANGO_SCALE,
1617                                             baseline);
1618                         gnome_print_pango_layout_line (job->priv->print_ctxt,
1619                                                        pango_layout_iter_get_line (iter));
1620
1621                         current_line++;
1622                 }
1623                 while (pango_layout_iter_next_line (iter));
1624
1625                 job->priv->available_height -= max - page_skip;
1626                 *y -= max - page_skip;
1627
1628                 pango_layout_iter_free (iter);
1629                 g_object_unref (layout);
1630         } else {
1631                 gint max_height = job->priv->available_height;
1632                 gint image_height = gdk_pixbuf_get_height(image);
1633                 gint image_width = gdk_pixbuf_get_width(image);
1634                 gint scaled_height = 0, scaled_width = 0;
1635                 GdkPixbuf *scaled_image = NULL;
1636                 image_viewer_get_resized_size(image_width,
1637                                          image_height,
1638                                          job->priv->text_width, 
1639                                          job->priv->text_height,
1640                                          &scaled_width, &scaled_height);
1641
1642                 if (scaled_height > max_height) {
1643                         /* next page */
1644                         return 0;
1645                 } else {
1646                         scaled_image = gdk_pixbuf_scale_simple
1647                                         (image, scaled_width, scaled_height, 
1648                                          GDK_INTERP_BILINEAR);
1649
1650                         gnome_print_moveto(job->priv->print_ctxt,
1651                                             x, (gdouble)*y);
1652                         gnome_print_gsave(job->priv->print_ctxt);
1653                         gnome_print_translate(job->priv->print_ctxt, 
1654                                               x, *y - scaled_height);
1655                         gnome_print_scale(job->priv->print_ctxt, 
1656                                           scaled_width,
1657                                           scaled_height);
1658
1659                         if (gdk_pixbuf_get_has_alpha(image))
1660                                 gnome_print_rgbaimage  (job->priv->print_ctxt,
1661                                                         gdk_pixbuf_get_pixels    (scaled_image),
1662                                                         gdk_pixbuf_get_width     (scaled_image),
1663                                                         gdk_pixbuf_get_height    (scaled_image),
1664                                                         gdk_pixbuf_get_rowstride (scaled_image));
1665                         else
1666                                 gnome_print_rgbimage  (job->priv->print_ctxt,
1667                                                        gdk_pixbuf_get_pixels    (scaled_image),
1668                                                        gdk_pixbuf_get_width     (scaled_image),
1669                                                        gdk_pixbuf_get_height    (scaled_image),
1670                                                        gdk_pixbuf_get_rowstride (scaled_image));
1671                         g_object_unref(scaled_image);
1672                         gnome_print_grestore(job->priv->print_ctxt);
1673
1674                         job->priv->available_height -= scaled_height;
1675                         *y -= scaled_height;
1676                         return -1;
1677
1678                 }
1679         }
1680         return result;
1681 }
1682
1683 static void
1684 print_page (GtkSourcePrintJob *job)
1685 {
1686         GSList *l;
1687         gdouble x, y;
1688         gint line;
1689         gboolean force_fit = TRUE;
1690         
1691         job->priv->page++;
1692         
1693         
1694         begin_page (job);
1695         job->priv->available_height = job->priv->text_height;
1696
1697         y = job->priv->page_height -
1698                 job->priv->doc_margin_top - job->priv->margin_top -
1699                 job->priv->header_height;
1700         x = job->priv->doc_margin_left + job->priv->margin_left +
1701                 job->priv->numbers_width;
1702         l = job->priv->current_paragraph;
1703         line = job->priv->current_paragraph_line;
1704
1705         while (l != NULL)
1706         {
1707                 Paragraph *para = l->data;
1708                 gdouble baseline = 0;
1709                 gint last_line = line;
1710                 
1711                 line = print_paragraph (job, para, line, x, &y, &baseline, force_fit);
1712
1713                 if (last_line == 0 && line != 0)
1714                 {
1715                         /* We printed the first line of a paragraph */
1716                         if (job->priv->print_numbers > 0 &&
1717                             ((para->line_number % job->priv->print_numbers) == 0))
1718                                 print_line_number (job,
1719                                                    para->line_number,
1720                                                    job->priv->doc_margin_left +
1721                                                    job->priv->margin_left,
1722                                                    baseline);
1723
1724                         job->priv->printed_lines++;
1725                 }
1726
1727                 if (line >= 0)
1728                         break;  /* Didn't all fit on this page */
1729                 
1730                 l = l->next;
1731                 line = 0;
1732                 force_fit = FALSE;
1733         }
1734         end_page (job);
1735         job->priv->current_paragraph = l;
1736         job->priv->current_paragraph_line = line;
1737 }
1738
1739 static void
1740 setup_for_print (GtkSourcePrintJob *job)
1741 {
1742         job->priv->current_paragraph = job->priv->paragraphs;
1743         job->priv->page = 0;
1744         job->priv->printed_lines = 0;
1745
1746         if (job->priv->print_job != NULL)
1747                 g_object_unref (job->priv->print_job);
1748         if (job->priv->print_ctxt != NULL)
1749                 g_object_unref (job->priv->print_ctxt);
1750         
1751         job->priv->print_job = gnome_print_job_new (job->priv->config);
1752         job->priv->print_ctxt = gnome_print_job_get_context (job->priv->print_job);
1753
1754         gnome_print_pango_update_context (job->priv->pango_context, job->priv->print_ctxt);
1755 }
1756
1757 static void
1758 print_job (GtkSourcePrintJob *job)
1759 {
1760         while (job->priv->current_paragraph != NULL)
1761                 print_page (job);
1762
1763         gnome_print_job_close (job->priv->print_job);
1764 }
1765
1766 static gboolean
1767 idle_printing_handler (GtkSourcePrintJob *job)
1768 {
1769         g_assert (job->priv->current_paragraph != NULL);
1770
1771         print_page (job);
1772
1773         if (job->priv->current_paragraph == NULL)
1774         {
1775                 gnome_print_job_close (job->priv->print_job);
1776                 job->priv->printing = FALSE;
1777                 job->priv->idle_printing_tag = 0;
1778
1779                 g_signal_emit (job, print_job_signals [FINISHED], 0);
1780                 /* after this the print job object is possibly
1781                  * destroyed (common use case) */
1782                 
1783                 return FALSE;
1784         }
1785         return TRUE;
1786 }
1787
1788
1789 /* Public API ------------------- */
1790
1791 /**
1792  * gtk_source_print_job_new:
1793  * @config: an optional #GnomePrintConfig object.
1794  * 
1795  * Creates a new print job object, initially setting the print configuration.
1796  * 
1797  * Return value: the new print job object.
1798  **/
1799 GtkSourcePrintJob *
1800 gtk_source_print_job_new (GnomePrintConfig  *config)
1801 {
1802         GtkSourcePrintJob *job;
1803
1804         g_return_val_if_fail (config == NULL || GNOME_IS_PRINT_CONFIG (config), NULL);
1805
1806         job = GTK_SOURCE_PRINT_JOB (g_object_new (GTK_TYPE_SOURCE_PRINT_JOB, NULL));
1807         if (config != NULL)
1808                 gtk_source_print_job_set_config (job, config);
1809
1810         return job;
1811 }
1812
1813 /**
1814  * gtk_source_print_job_new_with_buffer:
1815  * @config: an optional #GnomePrintConfig.
1816  * @buffer: the #GtkTextBuffer to print (might be %NULL).
1817  * 
1818  * Creates a new print job to print @buffer.
1819  * 
1820  * Return value: a new print job object.
1821  **/
1822 GtkSourcePrintJob *
1823 gtk_source_print_job_new_with_buffer (GnomePrintConfig  *config,
1824                                       GtkTextBuffer   *buffer)
1825 {
1826         GtkSourcePrintJob *job;
1827
1828         g_return_val_if_fail (config == NULL || GNOME_IS_PRINT_CONFIG (config), NULL);
1829         g_return_val_if_fail (buffer == NULL || GTK_IS_TEXT_BUFFER (buffer), NULL);
1830
1831         job = gtk_source_print_job_new (config);
1832         if (buffer != NULL)
1833                 gtk_source_print_job_set_buffer (job, buffer);
1834
1835         return job;
1836 }
1837
1838 /* --- print job basic configuration */
1839
1840 /**
1841  * gtk_source_print_job_set_config:
1842  * @job: a #GtkSourcePrintJob.
1843  * @config: a #GnomePrintConfig object to get printing configuration from.
1844  * 
1845  * Sets the print configuration for the job.  If you don't set a
1846  * configuration object for the print job, when needed one will be
1847  * created with gnome_print_config_default().
1848  **/
1849 void
1850 gtk_source_print_job_set_config (GtkSourcePrintJob *job,
1851                                  GnomePrintConfig  *config)
1852 {
1853         g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
1854         g_return_if_fail (GNOME_IS_PRINT_CONFIG (config));
1855         g_return_if_fail (!job->priv->printing);
1856         
1857         if (config == job->priv->config)
1858                 return;
1859         
1860         if (job->priv->config != NULL)
1861                 gnome_print_config_unref (job->priv->config);
1862
1863         job->priv->config = config;
1864         gnome_print_config_ref (config);
1865
1866         g_object_notify (G_OBJECT (job), "config");
1867 }
1868
1869 /**
1870  * gtk_source_print_job_get_config:
1871  * @job: a #GtkSourcePrintJob.
1872  * 
1873  * Gets the current #GnomePrintConfig the print job will use.  If not
1874  * previously set, this will create a default configuration and return
1875  * it.  The returned object reference is owned by the print job.
1876  * 
1877  * Return value: the #GnomePrintConfig for the print job.
1878  **/
1879 GnomePrintConfig * 
1880 gtk_source_print_job_get_config (GtkSourcePrintJob *job)
1881 {
1882         g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), NULL);
1883
1884         ensure_print_config (job);
1885         
1886         return job->priv->config;
1887 }
1888
1889 /**
1890  * gtk_source_print_job_set_buffer:
1891  * @job: a #GtkSourcePrintJob.
1892  * @buffer: a #GtkTextBuffer.
1893  * 
1894  * Sets the #GtkTextBuffer the print job will print.  You need to
1895  * specify a buffer to print, either by the use of this function or by
1896  * creating the print job with gtk_source_print_job_new_with_buffer().
1897  **/
1898 void 
1899 gtk_source_print_job_set_buffer (GtkSourcePrintJob *job,
1900                                  GtkTextBuffer   *buffer)
1901 {
1902         g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
1903         g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
1904         g_return_if_fail (!job->priv->printing);
1905
1906         if (buffer == job->priv->buffer)
1907                 return;
1908         
1909         if (job->priv->buffer != NULL)
1910                 g_object_unref (job->priv->buffer);
1911
1912         job->priv->buffer = buffer;
1913         g_object_ref (buffer);
1914
1915         g_object_notify (G_OBJECT (job), "buffer");
1916 }
1917
1918 /**
1919  * gtk_source_print_job_get_buffer:
1920  * @job: a #GtkSourcePrintJob.
1921  * 
1922  * Gets the #GtkTextBuffer the print job would print.  The returned
1923  * object reference (if non %NULL) is owned by the job object and
1924  * should not be unreferenced.
1925  * 
1926  * Return value: the #GtkTextBuffer to print.
1927  **/
1928 GtkTextBuffer *
1929 gtk_source_print_job_get_buffer (GtkSourcePrintJob *job)
1930 {
1931         g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), NULL);
1932
1933         return job->priv->buffer;
1934 }
1935
1936 /* --- print job layout and style configuration */
1937
1938 /**
1939  * gtk_source_print_job_set_tabs_width:
1940  * @job: a #GtkSourcePrintJob.
1941  * @tabs_width: the number of equivalent spaces for a tabulation.
1942  * 
1943  * Sets the width (in equivalent spaces) of tabulations for the
1944  * printed text.  The width in printing units will be calculated as
1945  * the width of a string containing @tabs_width spaces of the default
1946  * font.  Tabulation stops are set for the full width of printed text.
1947  **/
1948 void 
1949 gtk_source_print_job_set_tabs_width (GtkSourcePrintJob *job,
1950                                      guint              tabs_width)
1951 {
1952         g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
1953         g_return_if_fail (!job->priv->printing);
1954
1955         if (tabs_width == job->priv->tabs_width)
1956                 return;
1957         
1958         job->priv->tabs_width = tabs_width;
1959
1960         g_object_notify (G_OBJECT (job), "tabs_width");
1961 }
1962
1963 /**
1964  * gtk_source_print_job_get_tabs_width:
1965  * @job: a #GtkSourcePrintJob.
1966  * 
1967  * Determines the configured width (in equivalent spaces) of
1968  * tabulations.  The default value is 8.
1969  * 
1970  * Return value: the width (in equivalent spaces) of a tabulation.
1971  **/
1972 guint 
1973 gtk_source_print_job_get_tabs_width (GtkSourcePrintJob *job)
1974 {
1975         g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), 0);
1976
1977         return job->priv->tabs_width;
1978 }
1979
1980 /**
1981  * gtk_source_print_job_set_wrap_mode:
1982  * @job: a #GtkSourcePrintJob.
1983  * @wrap: the wrap mode.
1984  * 
1985  * Sets the wrap mode for lines of text larger than the printable
1986  * width.  See #GtkWrapMode for a definition of the possible values.
1987  **/
1988 void 
1989 gtk_source_print_job_set_wrap_mode (GtkSourcePrintJob *job,
1990                                     GtkWrapMode        wrap)
1991 {
1992         g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
1993         g_return_if_fail (!job->priv->printing);
1994
1995         if (wrap == job->priv->wrap_mode)
1996                 return;
1997         
1998         job->priv->wrap_mode = wrap;
1999
2000         g_object_notify (G_OBJECT (job), "wrap_mode");
2001 }
2002
2003 /**
2004  * gtk_source_print_job_get_wrap_mode:
2005  * @job: a #GtkSourcePrintJob.
2006  * 
2007  * Determines the wrapping style for text lines wider than the
2008  * printable width.  The default is no wrapping.
2009  * 
2010  * Return value: the current wrapping mode for the print job.
2011  **/
2012 GtkWrapMode 
2013 gtk_source_print_job_get_wrap_mode (GtkSourcePrintJob *job)
2014 {
2015         g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), GTK_WRAP_NONE);
2016
2017         return job->priv->wrap_mode;
2018 }
2019
2020 /**
2021  * gtk_source_print_job_set_highlight:
2022  * @job: a #GtkSourcePrintJob.
2023  * @highlight: %TRUE if the printed text should be highlighted.
2024  * 
2025  * Sets whether the printed text will be highlighted according to the
2026  * buffer rules.  Both color and font style are applied.
2027  **/
2028 void 
2029 gtk_source_print_job_set_highlight (GtkSourcePrintJob *job,
2030                                     gboolean           highlight)
2031 {
2032         g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
2033         g_return_if_fail (!job->priv->printing);
2034
2035         highlight = (highlight != FALSE);
2036         
2037         if (highlight == job->priv->highlight)
2038                 return;
2039         
2040         job->priv->highlight = highlight;
2041
2042         g_object_notify (G_OBJECT (job), "highlight");
2043 }
2044
2045 /**
2046  * gtk_source_print_job_get_highlight:
2047  * @job: a #GtkSourcePrintJob.
2048  * 
2049  * Determines if the job is configured to print the text highlighted
2050  * with colors and font styles.  Note that highlighting will happen
2051  * only if the buffer to print has highlighting activated.
2052  * 
2053  * Return value: %TRUE if the printed output will be highlighted.
2054  **/
2055 gboolean 
2056 gtk_source_print_job_get_highlight (GtkSourcePrintJob *job)
2057 {
2058         g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), FALSE);
2059
2060         return job->priv->highlight;
2061 }
2062
2063 /**
2064  * gtk_source_print_job_set_font_desc:
2065  * @job: a #GtkSourcePrintJob.
2066  * @desc: the #PangoFontDescription for the default font
2067  * 
2068  * Sets the default font for the printed text.
2069  **/
2070 void 
2071 gtk_source_print_job_set_font_desc (GtkSourcePrintJob    *job,
2072                                     PangoFontDescription *desc)
2073 {
2074         g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
2075         g_return_if_fail (desc != NULL);
2076         g_return_if_fail (!job->priv->printing);
2077
2078         desc = pango_font_description_copy (desc);
2079         if (job->priv->font != NULL)
2080                 pango_font_description_free (job->priv->font);
2081         job->priv->font = desc;
2082         g_object_freeze_notify (G_OBJECT (job));
2083         g_object_notify (G_OBJECT (job), "font");
2084         g_object_notify (G_OBJECT (job), "font_desc");
2085         g_object_thaw_notify (G_OBJECT (job));
2086 }
2087
2088 /**
2089  * gtk_source_print_job_set_font:
2090  * @job: a #GtkSourcePrintJob.
2091  * @font_name: the name of the default font.
2092  * 
2093  * Sets the default font for the printed text.  @font_name should be a
2094  * <emphasis>full font name</emphasis> GnomePrint can understand
2095  * (e.g. &quot;Monospace Regular 10.0&quot;).
2096  *
2097  * Note that @font_name is a #GnomeFont name not a Pango font
2098  * description string. This function is deprecated since #GnomeFont is
2099  * no longer used when implementing printing for GtkSourceView; you
2100  * should use gtk_source_print_job_set_font_desc() instead.
2101  **/
2102 void 
2103 gtk_source_print_job_set_font (GtkSourcePrintJob *job,
2104                                const gchar       *font_name)
2105 {
2106         PangoFontDescription *desc;
2107         
2108         g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
2109         g_return_if_fail (font_name != NULL);
2110         g_return_if_fail (!job->priv->printing);
2111
2112         desc = font_description_from_gnome_font_name (font_name);
2113         if (desc)
2114         {
2115                 gtk_source_print_job_set_font_desc (job, desc);
2116                 pango_font_description_free (desc);
2117         }
2118 }
2119
2120 /**
2121  * gtk_source_print_job_get_font_desc:
2122  * @job: a #GtkSourcePrintJob.
2123  * 
2124  * Determines the default font to be used for the printed text.  The
2125  * returned string is of the form &quot;Fontfamily Style Size&quot;,
2126  * for example &quot;Monospace Regular 10.0&quot;.  The returned value
2127  * should be freed when no longer needed.
2128  * 
2129  * Return value: the current text font description. This value is
2130  *  owned by the job and must not be modified or freed.
2131  **/
2132 PangoFontDescription *
2133 gtk_source_print_job_get_font_desc (GtkSourcePrintJob *job)
2134 {
2135         g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), NULL);
2136
2137         ensure_print_config (job);
2138         
2139         return job->priv->font;
2140 }
2141
2142 /**
2143  * gtk_source_print_job_get_font:
2144  * @job: a #GtkSourcePrintJob.
2145  * 
2146  * Determines the default font to be used for the printed text.  The
2147  * returned string is of the form &quot;Fontfamily Style Size&quot;,
2148  * for example &quot;Monospace Regular 10.0&quot;.  The returned value
2149  * should be freed when no longer needed.
2150  * 
2151  * Note that the result is a #GnomeFont name not a Pango font
2152  * description string. This function is deprecated since #GnomeFont is
2153  * no longer used when implementing printing for GtkSourceView; you
2154  * should use gtk_source_print_job_get_font_desc() instead.
2155  *
2156  * Return value: a newly allocated string with the name of the current
2157  * text font.
2158  **/
2159 gchar *
2160 gtk_source_print_job_get_font (GtkSourcePrintJob *job)
2161 {
2162         g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), NULL);
2163
2164         ensure_print_config (job);
2165         
2166         return font_description_to_gnome_font_name (job->priv->font);
2167 }
2168
2169 /**
2170  * gtk_source_print_job_setup_from_view:
2171  * @job: a #GtkSourcePrintJob.
2172  * @view: a #GtkSourceView to get configuration from.
2173  * 
2174  * Convenience function to set several configuration options at once,
2175  * so that the printed output matches @view.  The options set are
2176  * buffer (if not set already), tabs width, highlighting, wrap mode
2177  * and default font.
2178  **/
2179 void 
2180 gtk_source_print_job_setup_from_view (GtkSourcePrintJob *job,
2181                                       GtkTextView       *view)
2182 {
2183         GtkTextBuffer *buffer = NULL;
2184         PangoContext *pango_context;
2185         
2186         g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
2187         g_return_if_fail (!job->priv->printing);
2188
2189         buffer = gtk_text_view_get_buffer (view);
2190         
2191         if (job->priv->buffer == NULL && buffer != NULL)
2192                 gtk_source_print_job_set_buffer (job, buffer);
2193
2194         /* gtk_source_print_job_set_tabs_width (job, gtk_source_view_get_tabs_width (view)); */
2195         gtk_source_print_job_set_highlight (job, TRUE);
2196         gtk_source_print_job_set_wrap_mode (job, gtk_text_view_get_wrap_mode (view));
2197
2198         pango_context = gtk_widget_get_pango_context (GTK_WIDGET (view));
2199         gtk_source_print_job_set_font_desc (job, 
2200                                             pango_context_get_font_description (pango_context));
2201 }
2202
2203 /**
2204  * gtk_source_print_job_set_numbers_font_desc:
2205  * @job: a #GtkSourcePrintJob.
2206  * @desc: the #PangoFontDescription for the font for line numbers, or %NULL
2207  * 
2208  * Sets the font for printing line numbers on the left margin.  If
2209  * NULL is supplied, the default font (i.e. the one being used for the
2210  * text) will be used instead.
2211  **/
2212 void 
2213 gtk_source_print_job_set_numbers_font_desc (GtkSourcePrintJob    *job,
2214                                             PangoFontDescription *desc)
2215 {
2216         g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
2217         g_return_if_fail (!job->priv->printing);
2218         
2219         if (desc)
2220                 desc = pango_font_description_copy (desc);
2221         if (job->priv->numbers_font != NULL)
2222                 pango_font_description_free (job->priv->numbers_font);
2223         job->priv->numbers_font = desc;
2224         g_object_freeze_notify (G_OBJECT (job));
2225         g_object_notify (G_OBJECT (job), "numbers_font");
2226         g_object_notify (G_OBJECT (job), "numbers_font_desc");
2227         g_object_thaw_notify (G_OBJECT (job));
2228 }
2229
2230 /**
2231  * gtk_source_print_job_set_numbers_font:
2232  * @job: a #GtkSourcePrintJob.
2233  * @font_name: the full name of the font for line numbers, or %NULL.
2234  * 
2235  * Sets the font for printing line numbers on the left margin.  If
2236  * %NULL is supplied, the default font (i.e. the one being used for the
2237  * text) will be used instead.
2238  *
2239  * Note that @font_name is a #GnomeFont name not a Pango font
2240  * description string. This function is deprecated since #GnomeFont is
2241  * no longer used when implementing printing for GtkSourceView; you
2242  * should use gtk_source_print_job_set_numbers_font_desc() instead.
2243  **/
2244 void 
2245 gtk_source_print_job_set_numbers_font (GtkSourcePrintJob *job,
2246                                        const gchar       *font_name)
2247 {
2248         PangoFontDescription *desc;
2249         
2250         g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
2251         g_return_if_fail (!job->priv->printing);
2252
2253         if (font_name != NULL)
2254         {
2255                 desc = font_description_from_gnome_font_name (font_name);
2256                 if (desc)
2257                 {
2258                         gtk_source_print_job_set_numbers_font_desc (job, desc);
2259                         pango_font_description_free (desc);
2260                 }
2261         }
2262         else
2263                 gtk_source_print_job_set_numbers_font (job, NULL);
2264 }
2265
2266 /**
2267  * gtk_source_print_job_get_numbers_font_desc:
2268  * @job: a #GtkSourcePrintJob.
2269  * 
2270  * Determines the font to be used for the line numbers. This function
2271  * might return %NULL if a specific font for numbers has not been set.
2272  * 
2273  * Return value: the line numbers font description or %NULL. This value is
2274  * owned by the job and must not be modified or freed.
2275  **/
2276 PangoFontDescription *
2277 gtk_source_print_job_get_numbers_font_desc (GtkSourcePrintJob *job)
2278 {
2279         g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), NULL);
2280
2281         return job->priv->numbers_font;
2282 }
2283
2284 /**
2285  * gtk_source_print_job_get_numbers_font:
2286  * @job: a #GtkSourcePrintJob.
2287  * 
2288  * Determines the font to be used for the line numbers.  The returned
2289  * string is of the form &quot;Fontfamily Style Size&quot;, for
2290  * example &quot;Monospace Regular 10.0&quot;.  The returned value
2291  * should be freed when no longer needed.  This function might return
2292  * %NULL if a specific font for numbers has not been set.
2293  * 
2294  * Note that the result is a #GnomeFont name not a Pango font
2295  * description string. This function is deprecated since #GnomeFont is
2296  * no longer used when implementing printing for GtkSourceView; you
2297  * should use gtk_source_print_job_get_numbers_font_desc() instead.
2298  *
2299  * Return value: a newly allocated string with the name of the current
2300  * line numbers font, or %NULL.
2301  **/
2302 gchar *
2303 gtk_source_print_job_get_numbers_font (GtkSourcePrintJob *job)
2304 {
2305         g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), NULL);
2306
2307         if (job->priv->numbers_font != NULL)
2308                 return font_description_to_gnome_font_name (job->priv->numbers_font);
2309         else
2310                 return NULL;
2311 }
2312
2313 /**
2314  * gtk_source_print_job_set_print_numbers:
2315  * @job: a #GtkSourcePrintJob.
2316  * @interval: interval for printed line numbers.
2317  * 
2318  * Sets the interval for printed line numbers.  If @interval is 0 no
2319  * numbers will be printed.  If greater than 0, a number will be
2320  * printed every @interval lines (i.e. 1 will print all line numbers).
2321  **/
2322 void 
2323 gtk_source_print_job_set_print_numbers (GtkSourcePrintJob *job,
2324                                         guint              interval)
2325 {
2326         g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
2327         g_return_if_fail (!job->priv->printing);
2328
2329         if (interval == job->priv->print_numbers)
2330                 return;
2331         
2332         job->priv->print_numbers = interval;
2333
2334         g_object_notify (G_OBJECT (job), "print_numbers");
2335 }
2336
2337 /**
2338  * gtk_source_print_job_get_print_numbers:
2339  * @job: a #GtkSourcePrintJob.
2340  * 
2341  * Determines the interval used for line number printing.  If the
2342  * value is 0, no line numbers will be printed.  The default value is
2343  * 1 (i.e. numbers printed in all lines).
2344  * 
2345  * Return value: the interval of printed line numbers.
2346  **/
2347 guint 
2348 gtk_source_print_job_get_print_numbers (GtkSourcePrintJob *job)
2349 {
2350         g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), 0);
2351
2352         return job->priv->print_numbers;
2353 }
2354
2355 /**
2356  * gtk_source_print_job_set_text_margins:
2357  * @job: a #GtkSourcePrintJob.
2358  * @top: the top user margin.
2359  * @bottom: the bottom user margin.
2360  * @left: the left user margin.
2361  * @right: the right user margin.
2362  * 
2363  * Sets the four user margins for the print job.  These margins are in
2364  * addition to the document margins provided in the #GnomePrintConfig
2365  * and will not be used for headers, footers or line numbers (those
2366  * are calculated separatedly).  You can print in the space allocated
2367  * by these margins by connecting to the <link
2368  * linkend="GtkSourcePrintJob-begin-page">&quot;begin_page&quot;</link> signal.  The
2369  * space is around the printed text, and inside the margins specified
2370  * in the #GnomePrintConfig.
2371  *
2372  * The margin numbers are given in device units.  If any of the given
2373  * values is less than 0, that particular margin is not altered by
2374  * this function.
2375  **/
2376 void 
2377 gtk_source_print_job_set_text_margins (GtkSourcePrintJob *job,
2378                                        gdouble            top,
2379                                        gdouble            bottom,
2380                                        gdouble            left,
2381                                        gdouble            right)
2382 {
2383         g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
2384         g_return_if_fail (!job->priv->printing);
2385
2386         if (top >= 0)
2387                 job->priv->margin_top = top;
2388         if (bottom >= 0)
2389                 job->priv->margin_bottom = bottom;
2390         if (left >= 0)
2391                 job->priv->margin_left = left;
2392         if (right >= 0)
2393                 job->priv->margin_right = right;
2394 }
2395
2396 /**
2397  * gtk_source_print_job_get_text_margins:
2398  * @job: a #GtkSourcePrintJob.
2399  * @top: a pointer to a #gdouble to return the top margin.
2400  * @bottom: a pointer to a #gdouble to return the bottom margin.
2401  * @left: a pointer to a #gdouble to return the left margin.
2402  * @right: a pointer to a #gdouble to return the right margin.
2403  * 
2404  * Determines the user set margins for the job.  This function
2405  * retrieves the values previously set by
2406  * gtk_source_print_job_set_text_margins().  The default for all four
2407  * margins is 0.  Any of the pointers can be %NULL if you want to
2408  * ignore that value.
2409  **/
2410 void 
2411 gtk_source_print_job_get_text_margins (GtkSourcePrintJob *job,
2412                                        gdouble           *top,
2413                                        gdouble           *bottom,
2414                                        gdouble           *left,
2415                                        gdouble           *right)
2416 {
2417         g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
2418
2419         if (top != NULL)
2420                 *top = job->priv->margin_top;
2421         if (bottom != NULL)
2422                 *bottom = job->priv->margin_bottom;
2423         if (left != NULL)
2424                 *left = job->priv->margin_left;
2425         if (right != NULL)
2426                 *right = job->priv->margin_right;
2427 }
2428
2429 /* --- printing operations */
2430
2431 static gboolean
2432 gtk_source_print_job_prepare (GtkSourcePrintJob *job,
2433                               const GtkTextIter *start,
2434                               const GtkTextIter *end)
2435 {
2436         PROFILE (GTimer *timer);
2437         
2438         g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), FALSE);
2439         g_return_val_if_fail (!job->priv->printing, FALSE);
2440         g_return_val_if_fail (job->priv->buffer != NULL, FALSE);
2441         g_return_val_if_fail (start != NULL && end != NULL, FALSE);
2442
2443         /* make sure we have a sane configuration to start printing */
2444         ensure_print_config (job);
2445
2446         PROFILE (timer = g_timer_new ());
2447
2448         /* get the text to print */
2449         if (!get_text_to_print (job, start, end))
2450                 return FALSE;
2451
2452         PROFILE (g_message ("get_text_to_print: %.2f", g_timer_elapsed (timer, NULL)));
2453
2454         if (!setup_pango_context (job))
2455                 return FALSE;
2456
2457         /* check margins */
2458         if (!update_page_size_and_margins (job))
2459                 return FALSE;
2460
2461         /* split the document in pages */
2462         if (!paginate_text (job))
2463                 return FALSE;
2464
2465         PROFILE ({
2466                 g_message ("paginate_text: %.2f", g_timer_elapsed (timer, NULL));
2467                 g_timer_destroy (timer);
2468         });
2469
2470         return TRUE;
2471 }
2472
2473 /**
2474  * gtk_source_print_job_print:
2475  * @job: a configured #GtkSourcePrintJob.
2476  * 
2477  * Produces a #GnomePrintJob with the printed document.  The whole
2478  * contents of the configured #GtkTextBuffer are printed.  The
2479  * returned job is already closed and ready to be previewed (using
2480  * gnome_print_job_preview_new()) or printed directly.  The caller of
2481  * this function owns a reference to the returned object, so @job can
2482  * be destroyed and the output will still be valid, or the document
2483  * can be printed again with different settings.
2484  * 
2485  * Return value: a closed #GnomePrintJob with the printed document, or
2486  * %NULL if printing could not be completed.
2487  **/
2488 GnomePrintJob *
2489 gtk_source_print_job_print (GtkSourcePrintJob *job)
2490 {
2491         GtkTextIter start, end;
2492
2493         g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), NULL);
2494         g_return_val_if_fail (!job->priv->printing, NULL);
2495         g_return_val_if_fail (job->priv->buffer != NULL, NULL);
2496
2497         gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (job->priv->buffer), &start, &end);
2498
2499         return gtk_source_print_job_print_range (job, &start, &end);
2500 }
2501
2502 /**
2503  * gtk_source_print_job_print_range:
2504  * @job: a configured #GtkSourcePrintJob.
2505  * @start: the start of the region of text to print.
2506  * @end: the end of the region of text to print.
2507  * 
2508  * Similar to gtk_source_print_job_print(), except you can specify a
2509  * range of text to print.  The passed #GtkTextIter values might be
2510  * out of order.
2511  * 
2512  * Return value: a closed #GnomePrintJob with the text from @start to
2513  * @end printed, or %NULL if @job could not print.
2514  **/
2515 GnomePrintJob *
2516 gtk_source_print_job_print_range (GtkSourcePrintJob *job,
2517                                   const GtkTextIter *start,
2518                                   const GtkTextIter *end)
2519 {
2520         g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), NULL);
2521         g_return_val_if_fail (!job->priv->printing, NULL);
2522         g_return_val_if_fail (job->priv->buffer != NULL, NULL);
2523         g_return_val_if_fail (start != NULL && end != NULL, NULL);
2524         g_return_val_if_fail (gtk_text_iter_get_buffer (start) ==
2525                               GTK_TEXT_BUFFER (job->priv->buffer) &&
2526                               gtk_text_iter_get_buffer (end) ==
2527                               GTK_TEXT_BUFFER (job->priv->buffer), NULL);
2528
2529         if (!gtk_source_print_job_prepare (job, start, end))
2530                 return NULL;
2531
2532         /* real work starts here */
2533         setup_for_print (job);
2534
2535         job->priv->printing = TRUE;
2536         print_job (job);
2537         job->priv->printing = FALSE;
2538
2539         g_object_ref (job->priv->print_job);
2540         return job->priv->print_job;
2541 }
2542
2543 /* --- asynchronous printing */
2544
2545 /**
2546  * gtk_source_print_job_print_range_async:
2547  * @job: a configured #GtkSourcePrintJob.
2548  * @start: the start of the region of text to print.
2549  * @end: the end of the region of text to print.
2550  * 
2551  * Starts to print @job asynchronously.  This function will ready the
2552  * @job for printing and install an idle handler that will render one
2553  * page at a time.
2554  *
2555  * This function will not return immediatly, as only page rendering is
2556  * done asynchronously.  Text retrieval and paginating happens within
2557  * this function.  Also, if highlighting is enabled, the whole buffer
2558  * needs to be highlighted first.
2559  *
2560  * To get notification when the job has finished, you must connect to
2561  * the <link
2562  * linkend="GtkSourcePrintJob-finished">&quot;finished&quot;</link>
2563  * signal.  After this signal is emitted you can retrieve the
2564  * resulting #GnomePrintJob with gtk_source_print_job_get_print_job().
2565  * You may cancel the job with gtk_source_print_job_cancel().
2566  *
2567  * Return value: %TRUE if the print started.
2568  **/
2569 gboolean 
2570 gtk_source_print_job_print_range_async (GtkSourcePrintJob *job,
2571                                         const GtkTextIter *start,
2572                                         const GtkTextIter *end)
2573 {
2574         GSource *idle_source;
2575
2576         g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), FALSE);
2577         g_return_val_if_fail (!job->priv->printing, FALSE);
2578         g_return_val_if_fail (job->priv->buffer != NULL, FALSE);
2579         g_return_val_if_fail (start != NULL && end != NULL, FALSE);
2580         g_return_val_if_fail (gtk_text_iter_get_buffer (start) ==
2581                               GTK_TEXT_BUFFER (job->priv->buffer) &&
2582                               gtk_text_iter_get_buffer (end) ==
2583                               GTK_TEXT_BUFFER (job->priv->buffer), FALSE);
2584
2585         if (!gtk_source_print_job_prepare (job, start, end))
2586                 return FALSE;
2587
2588         /* real work starts here */
2589         setup_for_print (job);
2590         if (job->priv->current_paragraph == NULL)
2591                 return FALSE;
2592         
2593         /* setup the idle handler to print each page at a time */
2594         idle_source = g_idle_source_new ();
2595         g_source_set_priority (idle_source, GTK_SOURCE_PRINT_JOB_PRIORITY);
2596         g_source_set_closure (idle_source,
2597                               g_cclosure_new_object ((GCallback) idle_printing_handler,
2598                                                      G_OBJECT (job)));
2599         job->priv->idle_printing_tag = g_source_attach (idle_source, NULL);
2600         g_source_unref (idle_source);
2601
2602         job->priv->printing = TRUE;
2603
2604         return TRUE;
2605 }
2606
2607 /**
2608  * gtk_source_print_job_cancel:
2609  * @job: a #GtkSourcePrintJob.
2610  * 
2611  * Cancels an asynchronous printing operation.  This will remove any
2612  * pending print idle handler and unref the current #GnomePrintJob.
2613  *
2614  * Note that if you got a reference to the job's #GnomePrintJob (using
2615  * gtk_source_print_job_get_print_job()) it will not be destroyed
2616  * (since you hold a reference to it), but it will not be closed
2617  * either.  If you wish to show or print the partially printed
2618  * document you need to close it yourself.
2619  *
2620  * This function has no effect when called from a non-asynchronous
2621  * print operation.
2622  **/
2623 void 
2624 gtk_source_print_job_cancel (GtkSourcePrintJob *job)
2625 {
2626         g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
2627         g_return_if_fail (job->priv->printing);
2628
2629         if (job->priv->idle_printing_tag > 0)
2630         {
2631                 g_source_remove (job->priv->idle_printing_tag);
2632                 job->priv->current_paragraph = NULL;
2633                 job->priv->idle_printing_tag = 0;
2634                 job->priv->printing = FALSE;
2635                 g_object_unref (job->priv->print_job);
2636                 g_object_unref (job->priv->print_ctxt);
2637                 job->priv->print_job = NULL;
2638                 job->priv->print_ctxt = NULL;
2639         }
2640 }
2641
2642 /**
2643  * gtk_source_print_job_get_print_job:
2644  * @job: a #GtkSourcePrintJob.
2645  * 
2646  * Gets a reference to the #GnomePrintJob which the @job is printing
2647  * or has recently finished printing.  You need to unref the returned
2648  * object.
2649  *
2650  * You may call this function in the middle of an asynchronous
2651  * printing operation, but the returned #GnomePrintJob will not be
2652  * closed until the last page is printed and the <link
2653  * linkend="GtkSourcePrintJob-finished">&quot;finished&quot;</link>
2654  * signal is emitted.
2655  * 
2656  * Return value: a new reference to the @job's #GnomePrintJob, or
2657  * %NULL.
2658  **/
2659 GnomePrintJob *
2660 gtk_source_print_job_get_print_job (GtkSourcePrintJob *job)
2661 {
2662         g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), NULL);
2663
2664         if (job->priv->print_job)
2665                 g_object_ref (job->priv->print_job);
2666         
2667         return job->priv->print_job;
2668 }
2669
2670 /* --- information for asynchronous ops and headers and footers callback */
2671
2672 /**
2673  * gtk_source_print_job_get_page:
2674  * @job: a #GtkSourcePrintJob.
2675  * 
2676  * Determines the currently printing page number.  This function is
2677  * only valid while printing (either synchronously or asynchronously).
2678  * 
2679  * Return value: the current page number.
2680  **/
2681 guint 
2682 gtk_source_print_job_get_page (GtkSourcePrintJob *job)
2683 {
2684         g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), 0);
2685         g_return_val_if_fail (job->priv->printing, 0);
2686
2687         return job->priv->page;
2688 }
2689
2690 /**
2691  * gtk_source_print_job_get_page_count:
2692  * @job: a #GtkSourcePrintJob.
2693  * 
2694  * Determines the total number of pages the job will print.  The
2695  * returned value is only meaninful after pagination has finished.  In
2696  * practice, for synchronous printing this means when <link
2697  * linkend="GtkSourcePrintJob-begin-page">&quot;begin_page&quot;</link>
2698  * is emitted, or after gtk_source_print_job_print_range_async() has
2699  * returned.
2700  * 
2701  * Return value: the number of pages of the printed job.
2702  **/
2703 guint 
2704 gtk_source_print_job_get_page_count (GtkSourcePrintJob *job)
2705 {
2706         g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), 0);
2707
2708         return job->priv->page_count;
2709 }
2710
2711 /**
2712  * gtk_source_print_job_get_print_context:
2713  * @job: a printing #GtkSourcePrintJob.
2714  * 
2715  * Determines the #GnomePrintContext of the current job.  This
2716  * function is only valid while printing.  Normally you would use this
2717  * function to print in the margins set by
2718  * gtk_source_print_job_set_margins() in a handler for the <link
2719  * linkend="GtkSourcePrintJob-begin-page">&quot;begin_page&quot;</link>
2720  * signal.
2721  * 
2722  * Return value: the current #GnomePrintContext.  The returned object
2723  * is owned by @job.
2724  **/
2725 GnomePrintContext *
2726 gtk_source_print_job_get_print_context (GtkSourcePrintJob *job)
2727 {
2728         g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), NULL);
2729         g_return_val_if_fail (job->priv->printing, NULL);
2730
2731         return job->priv->print_ctxt;
2732 }
2733
2734 /* ---- Header and footer (default implementation) */
2735
2736 /* Most of this code taken from GLib's g_date_strftime() in gdate.c
2737  * GLIB - Library of useful routines for C programming
2738  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald */
2739
2740 static gchar *
2741 strdup_strftime (const gchar *format, const struct tm *tm)
2742 {
2743         gsize locale_format_len = 0;
2744         gchar *locale_format;
2745         gsize tmplen;
2746         gchar *tmpbuf;
2747         gsize tmpbufsize;
2748         gchar *convbuf;
2749         gsize convlen = 0;
2750         GError *error = NULL;
2751
2752         g_return_val_if_fail (format != NULL, NULL);
2753         g_return_val_if_fail (tm != NULL, NULL);
2754
2755         locale_format = g_locale_from_utf8 (format, -1, NULL, &locale_format_len, &error);
2756
2757         if (error)
2758         {
2759                 g_warning (G_STRLOC "Error converting format to locale encoding: %s",
2760                            error->message);
2761                 g_error_free (error);
2762                 
2763                 return NULL;
2764         }
2765
2766         tmpbufsize = MAX (128, locale_format_len * 2);
2767         while (TRUE)
2768         {
2769                 tmpbuf = g_malloc (tmpbufsize);
2770                 
2771                 /* Set the first byte to something other than '\0', to be able to
2772                  * recognize whether strftime actually failed or just returned "".
2773                  */
2774                 tmpbuf[0] = '\1';
2775                 tmplen = strftime (tmpbuf, tmpbufsize, locale_format, tm);
2776                 
2777                 if (tmplen == 0 && tmpbuf[0] != '\0')
2778                 {
2779                         g_free (tmpbuf);
2780                         tmpbufsize *= 2;
2781                         
2782                         if (tmpbufsize > 65536)
2783                         {
2784                                 g_warning (G_STRLOC "Maximum buffer size for strdup_strftime "
2785                                            "exceeded: giving up");
2786                                 g_free (locale_format);
2787                                 return NULL;
2788                         }
2789                 }
2790                 else
2791                         break;
2792         }
2793         g_free (locale_format);
2794
2795         convbuf = g_locale_to_utf8 (tmpbuf, tmplen, NULL, &convlen, &error);
2796         g_free (tmpbuf);
2797
2798         if (error)
2799         {
2800                 g_warning (G_STRLOC "Error converting results of strftime to UTF-8: %s",
2801                            error->message);
2802                 g_error_free (error);
2803                 
2804                 return NULL;
2805         }
2806
2807         return convbuf;
2808 }
2809
2810 static gchar *
2811 evaluate_format_string (GtkSourcePrintJob *job, const gchar *format)
2812 {
2813         GString *eval;
2814         gchar *eval_str, *retval;
2815         const struct tm *tm;
2816         time_t now;
2817         gunichar ch;
2818         struct tm lt;
2819
2820         /* get time */
2821         time (&now);
2822         tm = localtime_r(&now, &lt);
2823
2824         /* analyze format string and replace the codes we know */
2825         eval = g_string_new_len (NULL, strlen (format));
2826         ch = g_utf8_get_char (format);
2827         while (ch != 0)
2828         {
2829                 if (ch == '%')
2830                 {
2831                         format = g_utf8_next_char (format);
2832                         ch = g_utf8_get_char (format);
2833                         if (ch == 'N')
2834                                 g_string_append_printf (eval, "%d", job->priv->page);
2835                         else if (ch == 'Q')
2836                                 g_string_append_printf (eval, "%d", job->priv->page_count);
2837                         else
2838                         {
2839                                 g_string_append_c (eval, '%');
2840                                 g_string_append_unichar (eval, ch);
2841                         }
2842                 }
2843                 else
2844                         g_string_append_unichar (eval, ch);
2845
2846                 format = g_utf8_next_char (format);
2847                 ch = g_utf8_get_char (format);
2848         }
2849
2850         eval_str = g_string_free (eval, FALSE);
2851         retval = strdup_strftime (eval_str, tm);
2852         g_free (eval_str);
2853
2854         return retval;
2855 }
2856
2857 static void
2858 print_header_footer_string (GtkSourcePrintJob *job,
2859                             const gchar       *format,
2860                             gdouble            x_align,
2861                             gdouble            x,
2862                             gdouble            y)
2863 {
2864         PangoLayout *layout;
2865         gchar *text;
2866         gdouble width;
2867         gdouble xx;
2868         
2869         width = job->priv->text_width + job->priv->numbers_width;
2870         
2871         text = evaluate_format_string (job, format);
2872         if (text != NULL)
2873         {
2874                 layout = pango_layout_new (job->priv->pango_context);
2875                 pango_layout_set_font_description (layout, job->priv->header_footer_font);
2876                 pango_layout_set_text (layout, text, -1);
2877                 
2878                 xx = x + x_align * (width - get_layout_width (layout));
2879                 gnome_print_moveto (job->priv->print_ctxt, xx, y);
2880                 show_first_layout_line (job->priv->print_ctxt, layout);
2881                 
2882                 g_free (text);
2883                 g_object_unref (layout);
2884         }
2885 }
2886
2887 static void 
2888 default_print_header (GtkSourcePrintJob *job,
2889                       gdouble            x,
2890                       gdouble            y)
2891 {
2892         gdouble width;
2893         gdouble yy;
2894         gdouble ascent, descent;
2895         
2896         width = job->priv->text_width + job->priv->numbers_width;
2897
2898         get_font_ascent_descent (job, job->priv->header_footer_font, &ascent, &descent);
2899
2900         yy = y - ascent;
2901
2902         /* left format */
2903         if (job->priv->header_format_left != NULL)
2904                 print_header_footer_string (job, job->priv->header_format_left, 0.0, x, yy);
2905         
2906         /* right format */
2907         if (job->priv->header_format_right != NULL)
2908                 print_header_footer_string (job, job->priv->header_format_right, 1.0, x, yy);
2909
2910         /* center format */
2911         if (job->priv->header_format_center != NULL)
2912                 print_header_footer_string (job, job->priv->header_format_center, 0.5, x, yy);
2913
2914         /* separator */
2915         if (job->priv->header_separator)
2916         {
2917                 yy = y - (SEPARATOR_SPACING * (ascent + descent));
2918                 gnome_print_setlinewidth (job->priv->print_ctxt, SEPARATOR_LINE_WIDTH);
2919                 gnome_print_moveto (job->priv->print_ctxt, x, yy);
2920                 gnome_print_lineto (job->priv->print_ctxt, x + width, yy);
2921                 gnome_print_stroke (job->priv->print_ctxt);
2922         }
2923 }
2924
2925 static void 
2926 default_print_footer (GtkSourcePrintJob *job,
2927                       gdouble            x,
2928                       gdouble            y)
2929 {
2930         gdouble width;
2931         gdouble yy;
2932         gdouble ascent, descent;
2933         
2934         width = job->priv->text_width + job->priv->numbers_width;
2935
2936         get_font_ascent_descent (job, job->priv->header_footer_font, &ascent, &descent);
2937
2938         yy = y - job->priv->footer_height + descent;
2939
2940         /* left format */
2941         if (job->priv->footer_format_left != NULL)
2942                 print_header_footer_string (job, job->priv->footer_format_left, 0.0, x, yy);
2943         
2944         /* right format */
2945         if (job->priv->footer_format_right != NULL)
2946                 print_header_footer_string (job, job->priv->footer_format_right, 1.0, x, yy);
2947
2948         /* center format */
2949         if (job->priv->footer_format_center != NULL)
2950                 print_header_footer_string (job, job->priv->footer_format_center, 0.5, x, yy);
2951
2952         /* separator */
2953         if (job->priv->footer_separator)
2954         {
2955                 yy = y - job->priv->footer_height +
2956                         (SEPARATOR_SPACING * (ascent + descent));
2957                 gnome_print_setlinewidth (job->priv->print_ctxt, SEPARATOR_LINE_WIDTH);
2958                 gnome_print_moveto (job->priv->print_ctxt, x, yy);
2959                 gnome_print_lineto (job->priv->print_ctxt, x + width, yy);
2960                 gnome_print_stroke (job->priv->print_ctxt);
2961         }
2962 }
2963
2964 /**
2965  * gtk_source_print_job_set_print_header:
2966  * @job: a #GtkSourcePrintJob.
2967  * @setting: %TRUE if you want the header to be printed.
2968  * 
2969  * Sets whether you want to print a header in each page.  The default
2970  * header consists of three pieces of text and an optional line
2971  * separator, configurable with
2972  * gtk_source_print_job_set_header_format().
2973  *
2974  * Note that by default the header format is unspecified, and if it's
2975  * empty it will not be printed, regardless of this setting.
2976  **/
2977 void 
2978 gtk_source_print_job_set_print_header (GtkSourcePrintJob *job,
2979                                        gboolean           setting)
2980 {
2981         g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
2982         g_return_if_fail (!job->priv->printing);
2983
2984         setting = (setting != FALSE);
2985         
2986         if (setting == job->priv->print_header)
2987                 return;
2988         
2989         job->priv->print_header = setting;
2990
2991         g_object_notify (G_OBJECT (job), "print_header");
2992 }
2993
2994 /**
2995  * gtk_source_print_job_get_print_header:
2996  * @job: a #GtkSourcePrintJob.
2997  * 
2998  * Determines if a header is set to be printed for each page.  A
2999  * header will be printed if this function returns %TRUE
3000  * <emphasis>and</emphasis> some format strings have been specified
3001  * with gtk_source_print_job_set_header_format().
3002  * 
3003  * Return value: %TRUE if the header is set to be printed.
3004  **/
3005 gboolean 
3006 gtk_source_print_job_get_print_header (GtkSourcePrintJob *job)
3007 {
3008         g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), FALSE);
3009
3010         return job->priv->print_header;
3011 }
3012
3013 /**
3014  * gtk_source_print_job_set_print_footer:
3015  * @job: a #GtkSourcePrintJob.
3016  * @setting: %TRUE if you want the footer to be printed.
3017  * 
3018  * Sets whether you want to print a footer in each page.  The default
3019  * footer consists of three pieces of text and an optional line
3020  * separator, configurable with
3021  * gtk_source_print_job_set_footer_format().
3022  *
3023  * Note that by default the footer format is unspecified, and if it's
3024  * empty it will not be printed, regardless of this setting.
3025  **/
3026 void 
3027 gtk_source_print_job_set_print_footer (GtkSourcePrintJob *job,
3028                                        gboolean           setting)
3029 {
3030         g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
3031         g_return_if_fail (!job->priv->printing);
3032
3033         setting = (setting != FALSE);
3034         
3035         if (setting == job->priv->print_footer)
3036                 return;
3037         
3038         job->priv->print_footer = setting;
3039
3040         g_object_notify (G_OBJECT (job), "print_footer");
3041 }
3042
3043 /**
3044  * gtk_source_print_job_get_print_footer:
3045  * @job: a #GtkSourcePrintJob.
3046  * 
3047  * Determines if a footer is set to be printed for each page.  A
3048  * footer will be printed if this function returns %TRUE
3049  * <emphasis>and</emphasis> some format strings have been specified
3050  * with gtk_source_print_job_set_footer_format().
3051  * 
3052  * Return value: %TRUE if the footer is set to be printed.
3053  **/
3054 gboolean 
3055 gtk_source_print_job_get_print_footer (GtkSourcePrintJob *job)
3056 {
3057         g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), FALSE);
3058
3059         return job->priv->print_footer;
3060 }
3061
3062 /**
3063  * gtk_source_print_job_set_header_footer_font_desc:
3064  * @job: a #GtkSourcePrintJob.
3065  * @desc: the #PangoFontDescription for the font to be used in headers and footers, or %NULL.
3066  * 
3067  * Sets the font for printing headers and footers.  If %NULL is
3068  * supplied, the default font (i.e. the one being used for the text)
3069  * will be used instead.
3070  **/
3071 void 
3072 gtk_source_print_job_set_header_footer_font_desc (GtkSourcePrintJob    *job,
3073                                                   PangoFontDescription *desc)
3074 {
3075         g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
3076         g_return_if_fail (!job->priv->printing);
3077         
3078         if (desc)
3079                 desc = pango_font_description_copy (desc);
3080         if (job->priv->header_footer_font != NULL)
3081                 pango_font_description_free (job->priv->header_footer_font);
3082         job->priv->header_footer_font = desc;
3083         g_object_freeze_notify (G_OBJECT (job));
3084         g_object_notify (G_OBJECT (job), "header_footer_font");
3085         g_object_notify (G_OBJECT (job), "header_footer_font_desc");
3086         g_object_thaw_notify (G_OBJECT (job));
3087 }
3088
3089 /**
3090  * gtk_source_print_job_set_header_footer_font:
3091  * @job: a #GtkSourcePrintJob.
3092  * @font_name: the full name of the font to be used in headers and footers, or %NULL.
3093  * 
3094  * Sets the font for printing headers and footers.  If %NULL is
3095  * supplied, the default font (i.e. the one being used for the text)
3096  * will be used instead.
3097  *
3098  * Note that @font_name is a #GnomeFont name not a Pango font
3099  * description string. This function is deprecated since #GnomeFont is
3100  * no longer used when implementing printing for GtkSourceView; you
3101  * should use gtk_source_print_job_set_header_footer_font_desc() instead.
3102  **/
3103 void 
3104 gtk_source_print_job_set_header_footer_font (GtkSourcePrintJob *job,
3105                                              const gchar       *font_name)
3106 {
3107         PangoFontDescription *desc;
3108         
3109         g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
3110         g_return_if_fail (!job->priv->printing);
3111
3112         if (font_name != NULL)
3113         {
3114                 desc = font_description_from_gnome_font_name (font_name);
3115                 if (desc)
3116                 {
3117                         gtk_source_print_job_set_header_footer_font_desc (job, desc);
3118                         pango_font_description_free (desc);
3119                 }
3120         }
3121         else
3122                 gtk_source_print_job_set_header_footer_font_desc (job, NULL);
3123 }
3124
3125 /**
3126  * gtk_source_print_job_get_header_footer_font_desc:
3127  * @job: a #GtkSourcePrintJob.
3128  * 
3129  * Determines the font to be used for the header and footer.  This function
3130  * might return %NULL if a specific font has not been set.
3131  * 
3132  * Return value: the header and footer font description or %NULL. This value is
3133  * owned by the job and must not be modified or freed.
3134  **/
3135 PangoFontDescription *
3136 gtk_source_print_job_get_header_footer_font_desc (GtkSourcePrintJob *job)
3137 {
3138         g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), NULL);
3139
3140         return job->priv->header_footer_font;
3141 }
3142
3143 /**
3144  * gtk_source_print_job_get_header_footer_font:
3145  * @job: a #GtkSourcePrintJob.
3146  * 
3147  * Determines the font to be used for the header and footer.  The
3148  * returned string is of the form &quot;Fontfamily Style Size&quot;,
3149  * for example &quot;Monospace Regular 10.0&quot;.  The returned value
3150  * should be freed when no longer needed.  This function might return
3151  * %NULL if a specific font has not been set.
3152  * 
3153  * Note that the result is a #GnomeFont name not a Pango font
3154  * description string. This function is deprecated since #GnomeFont is
3155  * no longer used when implementing printing for GtkSourceView; you
3156  * should use gtk_source_print_job_get_header_footer_font_desc() instead.
3157  *
3158  * Return value: a newly allocated string with the name of the current
3159  * header and footer font, or %NULL.
3160  **/
3161 gchar *
3162 gtk_source_print_job_get_header_footer_font (GtkSourcePrintJob *job)
3163 {
3164         g_return_val_if_fail (GTK_IS_SOURCE_PRINT_JOB (job), NULL);
3165
3166         if (job->priv->header_footer_font != NULL)
3167                 return font_description_to_gnome_font_name (job->priv->header_footer_font);
3168         else
3169                 return NULL;
3170 }
3171
3172 /**
3173  * gtk_source_print_job_set_header_format:
3174  * @job: a #GtkSourcePrintJob.
3175  * @left: a format string to print on the left of the header.
3176  * @center: a format string to print on the center of the header.
3177  * @right: a format string to print on the right of the header.
3178  * @separator: %TRUE if you want a separator line to be printed.
3179  * 
3180  * Sets strftime like header format strings, to be printed on the
3181  * left, center and right of the top of each page.  The strings may
3182  * include strftime(3) codes which will be expanded at print time.
3183  * All strftime() codes are accepted, with the addition of %N for the
3184  * page number and %Q for the page count.
3185  *
3186  * @separator specifies if a solid line should be drawn to separate
3187  * the header from the document text.
3188  *
3189  * If %NULL is given for any of the three arguments, that particular
3190  * string will not be printed.  For the header to be printed, in
3191  * addition to specifying format strings, you need to enable header
3192  * printing with gtk_source_print_job_set_print_header().
3193  **/
3194 void 
3195 gtk_source_print_job_set_header_format (GtkSourcePrintJob *job,
3196                                         const gchar       *left,
3197                                         const gchar       *center,
3198                                         const gchar       *right,
3199                                         gboolean           separator)
3200 {
3201         g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
3202         g_return_if_fail (!job->priv->printing);
3203
3204         /* FIXME: validate given strings? */
3205         g_free (job->priv->header_format_left);
3206         g_free (job->priv->header_format_center);
3207         g_free (job->priv->header_format_right);
3208         job->priv->header_format_left = g_strdup (left);
3209         job->priv->header_format_center = g_strdup (center);
3210         job->priv->header_format_right = g_strdup (right);
3211         job->priv->header_separator = separator;
3212 }
3213
3214 /**
3215  * gtk_source_print_job_set_footer_format:
3216  * @job: a #GtkSourcePrintJob.
3217  * @left: a format string to print on the left of the footer.
3218  * @center: a format string to print on the center of the footer.
3219  * @right: a format string to print on the right of the footer.
3220  * @separator: %TRUE if you want a separator line to be printed.
3221  * 
3222  * Like gtk_source_print_job_set_header_format(), but for the footer.
3223  **/
3224 void 
3225 gtk_source_print_job_set_footer_format (GtkSourcePrintJob *job,
3226                                         const gchar       *left,
3227                                         const gchar       *center,
3228                                         const gchar       *right,
3229                                         gboolean           separator)
3230 {
3231         g_return_if_fail (GTK_IS_SOURCE_PRINT_JOB (job));
3232         g_return_if_fail (!job->priv->printing);
3233
3234         /* FIXME: validate given strings? */
3235         g_free (job->priv->footer_format_left);
3236         g_free (job->priv->footer_format_center);
3237         g_free (job->priv->footer_format_right);
3238         job->priv->footer_format_left = g_strdup (left);
3239         job->priv->footer_format_center = g_strdup (center);
3240         job->priv->footer_format_right = g_strdup (right);
3241         job->priv->footer_separator = separator;
3242 }
3243 #endif