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