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