2 * printing.c - this file is part of Geany, a fast and lightweight IDE
4 * Copyright 2007-2010 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
5 * Copyright 2007-2010 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26 * GTK 2.10 printing support
27 * (basic code layout were adopted from Sylpheed's printing implementation, thanks)
37 #include "sciwrappers.h"
39 #include "sciwrappers.h"
45 #include "msgwindow.h"
48 PrintingPrefs printing_prefs
;
51 #if GTK_CHECK_VERSION(2, 10, 0)
54 #define ROTATE_RGB(color) \
55 (((color) & 0xFF0000) >> 16) + ((color) & 0x00FF00) + (((color) & 0x0000FF) << 16)
56 #define ADD_ATTR(l, a) \
57 pango_attr_list_insert((l), (a)); \
58 (a)->start_index = 0; \
72 /* document-related variables */
80 gint max_line_number_margin
;
83 gint styles
[STYLE_MAX
+ 1][MAX_TYPES
];
85 /* whether we have a wrapped line on page end to take care of on next page */
87 /* set in begin_print() to hold the time when printing was started to ensure all printed
88 * pages have the same date and time (in case of slow machines and many pages where rendering
89 * takes more than a second) */
91 PangoLayout
*layout
; /* commonly used layout object */
94 /* widget references for the custom widget in the print dialog */
97 GtkWidget
*check_print_linenumbers
;
98 GtkWidget
*check_print_pagenumbers
;
99 GtkWidget
*check_print_pageheader
;
100 GtkWidget
*check_print_basename
;
101 GtkWidget
*entry_print_dateformat
;
105 static GtkPrintSettings
*settings
= NULL
;
106 static GtkPageSetup
*page_setup
= NULL
;
110 /* returns the "width" (count of needed characters) for the given number */
111 static gint
get_line_numbers_arity(gint x
)
114 while ((x
/= 10) != 0)
120 /* split a RGB colour into the three colour components */
121 static void get_rgb_values(gint c
, gint
*r
, gint
*g
, gint
*b
)
124 if (interface_prefs
.highlighting_invert_all
)
125 c
= utils_invert_color(c
);
128 *g
= (c
& - 16711936) / 256;
129 *b
= (c
& 0xff0000) / 65536;
137 /* creates a commonly used layout object from the given context for use in get_page_count and
139 static PangoLayout
*setup_pango_layout(GtkPrintContext
*context
, PangoFontDescription
*desc
)
143 layout
= gtk_print_context_create_pango_layout(context
);
144 pango_layout_set_wrap(layout
, PANGO_WRAP_WORD_CHAR
);
145 pango_layout_set_spacing(layout
, 0);
146 pango_layout_set_attributes(layout
, NULL
);
147 pango_layout_set_font_description(layout
, desc
);
153 static gboolean
utils_font_desc_check_monospace(PangoContext
*pc
, PangoFontDescription
*desc
)
155 PangoFontFamily
**families
;
160 font
= pango_font_description_get_family(desc
);
161 pango_context_list_families(pc
, &families
, &n_families
);
162 for (i
= 0; i
< n_families
; i
++)
164 if (utils_str_equal(font
, pango_font_family_get_name(families
[i
])))
166 if (!pango_font_family_is_monospace(families
[i
]))
177 /* We don't support variable width fonts (yet) */
178 static gint
get_font_width(GtkPrintContext
*context
, PangoFontDescription
*desc
)
181 PangoFontMetrics
*metrics
;
184 pc
= gtk_print_context_create_pango_context(context
);
186 if (!utils_font_desc_check_monospace(pc
, desc
))
187 dialogs_show_msgbox_with_secondary(GTK_MESSAGE_WARNING
,
188 _("The editor font is not a monospaced font!"),
189 _("Text will be wrongly spaced."));
191 metrics
= pango_context_get_metrics(pc
, desc
, pango_context_get_language(pc
));
192 /** TODO is this the best result we can get? */
193 /* digit and char width are mostly equal for monospace fonts, char width might be
194 * for dual width characters(e.g. Japanese) so use digit width to get sure we get the width
195 * for one character */
196 width
= pango_font_metrics_get_approximate_digit_width(metrics
) / PANGO_SCALE
;
198 pango_font_metrics_unref(metrics
);
205 static gint
get_page_count(GtkPrintContext
*context
, DocInfo
*dinfo
)
207 gdouble width
, height
;
209 gint i
, j
, lines_left
;
215 width
= gtk_print_context_get_width(context
);
216 height
= gtk_print_context_get_height(context
);
218 if (printing_prefs
.print_line_numbers
)
219 /* remove line number margin space from overall width */
220 width
-= dinfo
->max_line_number_margin
* dinfo
->font_width
;
222 pango_layout_set_width(dinfo
->layout
, width
* PANGO_SCALE
);
224 /* add test text to get line height */
225 pango_layout_set_text(dinfo
->layout
, "Test 1", -1);
226 pango_layout_get_size(dinfo
->layout
, NULL
, &layout_h
);
229 geany_debug("Invalid layout_h (%d). Falling back to default height (%d)",
230 layout_h
, 100 * PANGO_SCALE
);
231 layout_h
= 100 * PANGO_SCALE
;
233 dinfo
->line_height
= (gdouble
)layout_h
/ PANGO_SCALE
;
234 dinfo
->lines_per_page
= ceil((height
- dinfo
->line_height
) / dinfo
->line_height
);
235 #ifdef GEANY_PRINT_DEBUG
236 geany_debug("max lines_per_page: %d", dinfo
->lines_per_page
);
238 if (printing_prefs
.print_page_numbers
)
239 dinfo
->lines_per_page
-= 2;
240 if (printing_prefs
.print_page_header
)
241 dinfo
->lines_per_page
-= 3;
243 lines_left
= dinfo
->lines_per_page
;
246 for (j
= 0; j
< dinfo
->lines
; j
++)
251 line_buf
= sci_get_line(dinfo
->doc
->editor
->sci
, j
);
252 line_width
= (g_utf8_strlen(line_buf
, -1) + 1) * dinfo
->font_width
;
253 if (line_width
> width
)
254 lines
= ceil(line_width
/ width
);
255 #ifdef GEANY_PRINT_DEBUG
256 if (lines
!= 1) geany_debug("%d %d", j
+1, lines
);
259 while (lines_left
< lines
)
262 lines_left
= dinfo
->lines_per_page
;
273 static void add_page_header(DocInfo
*dinfo
, cairo_t
*cr
, gint width
, gint page_nr
)
275 gint ph_height
= dinfo
->line_height
* 3;
278 gchar
*tmp_file_name
= (dinfo
->doc
->file_name
!= NULL
) ?
279 dinfo
->doc
->file_name
: GEANY_STRING_UNTITLED
;
280 gchar
*file_name
= (printing_prefs
.page_header_basename
) ?
281 g_path_get_basename(tmp_file_name
) : g_strdup(tmp_file_name
);
282 PangoLayout
*layout
= dinfo
->layout
;
285 cairo_set_line_width(cr
, 0.3);
286 cairo_set_source_rgb(cr
, 0, 0, 0);
287 cairo_rectangle(cr
, 2, 2, width
- 4, ph_height
- 4);
290 /* width - 8: 2px between doc border and frame border, 2px between frame border and text
291 * and this on left and right side, so (2 + 2) * 2 */
292 pango_layout_set_width(layout
, (width
- 8) * PANGO_SCALE
);
294 if ((g_utf8_strlen(file_name
, -1) * dinfo
->font_width
) >= ((width
- 4) - (dinfo
->font_width
* 2)))
295 /* if the filename is wider than the available space on the line, skip parts of it */
296 pango_layout_set_ellipsize(layout
, PANGO_ELLIPSIZE_MIDDLE
);
298 data
= g_strdup_printf("<b>%s</b>", file_name
);
299 pango_layout_set_markup(layout
, data
, -1);
300 pango_layout_set_alignment(layout
, PANGO_ALIGN_LEFT
);
301 cairo_move_to(cr
, 4, dinfo
->line_height
* 0.5);
302 pango_cairo_show_layout(cr
, layout
);
306 data
= g_strdup_printf(_("<b>Page %d of %d</b>"), page_nr
+ 1, dinfo
->n_pages
);
307 pango_layout_set_markup(layout
, data
, -1);
308 pango_layout_set_alignment(layout
, PANGO_ALIGN_LEFT
);
309 cairo_move_to(cr
, 4, dinfo
->line_height
* 1.5);
310 pango_cairo_show_layout(cr
, layout
);
313 datetime
= utils_get_date_time(printing_prefs
.page_header_datefmt
, &(dinfo
->print_time
));
316 data
= g_strdup_printf("<b>%s</b>", datetime
);
317 pango_layout_set_markup(layout
, data
, -1);
318 pango_layout_set_alignment(layout
, PANGO_ALIGN_RIGHT
);
319 cairo_move_to(cr
, 2, dinfo
->line_height
* 1.5);
320 pango_cairo_show_layout(cr
, layout
);
325 /* reset layout and re-position cairo context */
326 pango_layout_set_alignment(layout
, PANGO_ALIGN_LEFT
);
327 pango_layout_set_ellipsize(layout
, FALSE
);
328 pango_layout_set_justify(layout
, FALSE
);
329 pango_layout_set_width(layout
, width
* PANGO_SCALE
);
330 cairo_move_to(cr
, 0, dinfo
->line_height
* 3);
334 static void custom_widget_apply(GtkPrintOperation
*operation
, GtkWidget
*widget
, gpointer user_data
)
336 PrintWidgets
*w
= user_data
;
338 printing_prefs
.print_line_numbers
=
339 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w
->check_print_linenumbers
));
341 printing_prefs
.print_page_numbers
=
342 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w
->check_print_pagenumbers
));
344 printing_prefs
.print_page_header
=
345 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w
->check_print_pageheader
));
347 printing_prefs
.page_header_basename
=
348 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w
->check_print_basename
));
350 g_free(printing_prefs
.page_header_datefmt
);
351 printing_prefs
.page_header_datefmt
=
352 g_strdup(gtk_entry_get_text(GTK_ENTRY(w
->entry_print_dateformat
)));
356 static void on_page_header_toggled(GtkToggleButton
*togglebutton
, gpointer user_data
)
358 gboolean sens
= gtk_toggle_button_get_active(togglebutton
);
359 PrintWidgets
*w
= user_data
;
361 gtk_widget_set_sensitive(w
->check_print_basename
, sens
);
362 gtk_widget_set_sensitive(w
->entry_print_dateformat
, sens
);
366 static GtkWidget
*create_custom_widget(GtkPrintOperation
*operation
, gpointer user_data
)
367 { /* copied from interface.c */
370 GtkWidget
*alignment36
;
374 PrintWidgets
*w
= user_data
;
376 gtk_print_operation_set_custom_tab_label(operation
, _("Document Setup"));
378 page
= gtk_vbox_new(FALSE
, 0);
379 gtk_container_set_border_width(GTK_CONTAINER(page
), 5);
381 w
->check_print_linenumbers
= gtk_check_button_new_with_mnemonic(_("Print line numbers"));
382 gtk_box_pack_start(GTK_BOX(page
), w
->check_print_linenumbers
, FALSE
, FALSE
, 0);
383 ui_widget_set_tooltip_text(w
->check_print_linenumbers
, _("Add line numbers to the printed page"));
384 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w
->check_print_linenumbers
), printing_prefs
.print_line_numbers
);
386 w
->check_print_pagenumbers
= gtk_check_button_new_with_mnemonic(_("Print page numbers"));
387 gtk_box_pack_start(GTK_BOX(page
), w
->check_print_pagenumbers
, FALSE
, FALSE
, 0);
388 ui_widget_set_tooltip_text(w
->check_print_pagenumbers
, _("Add page numbers at the bottom of each page. It takes 2 lines of the page."));
389 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w
->check_print_pagenumbers
), printing_prefs
.print_page_numbers
);
391 w
->check_print_pageheader
= gtk_check_button_new_with_mnemonic(_("Print page header"));
392 gtk_box_pack_start(GTK_BOX(page
), w
->check_print_pageheader
, FALSE
, FALSE
, 0);
393 ui_widget_set_tooltip_text(w
->check_print_pageheader
, _("Add a little header to every page containing the page number, the filename and the current date (see below). It takes 3 lines of the page."));
394 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w
->check_print_pageheader
), printing_prefs
.print_page_header
);
395 g_signal_connect(w
->check_print_pageheader
, "toggled", G_CALLBACK(on_page_header_toggled
), w
);
397 frame33
= gtk_frame_new(NULL
);
398 gtk_box_pack_start(GTK_BOX(page
), frame33
, FALSE
, FALSE
, 0);
399 gtk_frame_set_label_align(GTK_FRAME(frame33
), 0, 0);
400 gtk_frame_set_shadow_type(GTK_FRAME(frame33
), GTK_SHADOW_NONE
);
402 alignment36
= gtk_alignment_new(0, 0.5, 1, 1);
403 gtk_container_add(GTK_CONTAINER(frame33
), alignment36
);
404 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment36
), 0, 0, 12, 0);
406 vbox30
= gtk_vbox_new(FALSE
, 1);
407 gtk_container_add(GTK_CONTAINER(alignment36
), vbox30
);
409 w
->check_print_basename
= gtk_check_button_new_with_mnemonic(_("Use the basename of the printed file"));
410 gtk_box_pack_start(GTK_BOX(vbox30
), w
->check_print_basename
, FALSE
, FALSE
, 0);
411 ui_widget_set_tooltip_text(w
->check_print_basename
, _("Print only the basename(without the path) of the printed file"));
412 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w
->check_print_basename
), printing_prefs
.page_header_basename
);
414 hbox10
= gtk_hbox_new(FALSE
, 5);
415 gtk_box_pack_start(GTK_BOX(vbox30
), hbox10
, TRUE
, TRUE
, 0);
417 label203
= gtk_label_new(_("Date format:"));
418 gtk_box_pack_start(GTK_BOX(hbox10
), label203
, FALSE
, FALSE
, 0);
420 w
->entry_print_dateformat
= gtk_entry_new();
421 ui_entry_add_clear_icon(GTK_ENTRY(w
->entry_print_dateformat
));
422 gtk_box_pack_start(GTK_BOX(hbox10
), w
->entry_print_dateformat
, TRUE
, TRUE
, 0);
423 ui_widget_set_tooltip_text(w
->entry_print_dateformat
, _("Specify a format for the date and time stamp which is added to the page header on each page. You can use any conversion specifiers which can be used with the ANSI C strftime function."));
424 gtk_entry_set_text(GTK_ENTRY(w
->entry_print_dateformat
), printing_prefs
.page_header_datefmt
);
426 on_page_header_toggled(GTK_TOGGLE_BUTTON(w
->check_print_pageheader
), w
);
427 gtk_widget_show_all(page
);
432 static void end_print(GtkPrintOperation
*operation
, GtkPrintContext
*context
, gpointer user_data
)
434 DocInfo
*dinfo
= user_data
;
439 gtk_widget_hide(main_widgets
.progressbar
);
440 g_object_unref(dinfo
->layout
);
444 static void begin_print(GtkPrintOperation
*operation
, GtkPrintContext
*context
, gpointer user_data
)
446 DocInfo
*dinfo
= user_data
;
447 PangoFontDescription
*desc
;
454 gtk_widget_show(main_widgets
.progressbar
);
456 desc
= pango_font_description_from_string(interface_prefs
.editor_font
);
458 /* init dinfo fields */
459 dinfo
->lines
= sci_get_line_count(dinfo
->doc
->editor
->sci
);
460 dinfo
->lines_per_page
= 0;
463 dinfo
->long_line
= FALSE
;
464 dinfo
->print_time
= time(NULL
);
465 dinfo
->max_line_number_margin
= get_line_numbers_arity(dinfo
->lines
) + 1;
466 /* increase font width by 1 (looks better) */
467 dinfo
->font_width
= get_font_width(context
, desc
) + 1;
468 /* create a PangoLayout to be commonly used in get_page_count and draw_page */
469 dinfo
->layout
= setup_pango_layout(context
, desc
);
470 /* this is necessary because of possible line breaks on the printed page and then
471 * lines_per_page differs from document line count */
472 dinfo
->n_pages
= get_page_count(context
, dinfo
);
474 /* read all styles from Scintilla */
475 style_max
= pow(2, scintilla_send_message(dinfo
->doc
->editor
->sci
, SCI_GETSTYLEBITS
, 0, 0));
476 /* if the lexer uses only the first 32 styles(style bits = 5),
477 * we need to add the pre-defined styles */
479 style_max
= STYLE_LASTPREDEFINED
;
480 for (i
= 0; i
< style_max
; i
++)
482 dinfo
->styles
[i
][FORE
] = ROTATE_RGB(scintilla_send_message(
483 dinfo
->doc
->editor
->sci
, SCI_STYLEGETFORE
, i
, 0));
484 if (i
== STYLE_LINENUMBER
)
485 { /* ignore background colour for line number margin to avoid trouble with wrapped lines */
486 dinfo
->styles
[STYLE_LINENUMBER
][BACK
] = ROTATE_RGB(scintilla_send_message(
487 dinfo
->doc
->editor
->sci
, SCI_STYLEGETBACK
, STYLE_DEFAULT
, 0));
491 dinfo
->styles
[i
][BACK
] = ROTATE_RGB(scintilla_send_message(
492 dinfo
->doc
->editor
->sci
, SCI_STYLEGETBACK
, i
, 0));
494 /* use white background color unless foreground is white to save ink */
495 if (dinfo
->styles
[i
][FORE
] != 0xffffff)
496 dinfo
->styles
[i
][BACK
] = 0xffffff;
497 dinfo
->styles
[i
][BOLD
] =
498 scintilla_send_message(dinfo
->doc
->editor
->sci
, SCI_STYLEGETBOLD
, i
, 0);
499 dinfo
->styles
[i
][ITALIC
] =
500 scintilla_send_message(dinfo
->doc
->editor
->sci
, SCI_STYLEGETITALIC
, i
, 0);
503 if (dinfo
->n_pages
>= 0)
504 gtk_print_operation_set_n_pages(operation
, dinfo
->n_pages
);
506 pango_font_description_free(desc
);
510 static void draw_page(GtkPrintOperation
*operation
, GtkPrintContext
*context
,
511 gint page_nr
, gpointer user_data
)
513 DocInfo
*dinfo
= user_data
;
516 gdouble width
, height
;
522 if (dinfo
== NULL
|| page_nr
>= dinfo
->n_pages
)
525 editor
= dinfo
->doc
->editor
;
527 if (dinfo
->n_pages
> 0)
529 gdouble fraction
= (page_nr
+ 1) / (gdouble
) dinfo
->n_pages
;
530 gchar
*text
= g_strdup_printf(_("Page %d of %d"), page_nr
, dinfo
->n_pages
);
531 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(main_widgets
.progressbar
), fraction
);
532 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(main_widgets
.progressbar
), text
);
536 #ifdef GEANY_PRINT_DEBUG
537 geany_debug("draw_page = %d, pages = %d, (real) lines_per_page = %d",
538 page_nr
, dinfo
->n_pages
, dinfo
->lines_per_page
);
541 str
= g_string_sized_new(256);
542 cr
= gtk_print_context_get_cairo_context(context
);
543 width
= gtk_print_context_get_width(context
);
544 height
= gtk_print_context_get_height(context
);
546 cairo_set_source_rgb(cr
, 0, 0, 0);
547 #ifdef GEANY_PRINT_DEBUG
548 cairo_set_line_width(cr
, 0.2);
549 cairo_rectangle(cr
, 0, 0, width
, height
);
552 cairo_move_to(cr
, 0, 0);
554 pango_layout_set_width(dinfo
->layout
, width
* PANGO_SCALE
);
555 pango_layout_set_alignment(dinfo
->layout
, PANGO_ALIGN_LEFT
);
556 pango_layout_set_ellipsize(dinfo
->layout
, FALSE
);
557 pango_layout_set_justify(dinfo
->layout
, FALSE
);
559 if (printing_prefs
.print_page_header
)
560 add_page_header(dinfo
, cr
, width
, page_nr
);
562 count
= 0; /* the actual line counter for the current page, might be different from
563 * dinfo->cur_line due to possible line breaks */
564 while (count
< dinfo
->lines_per_page
)
568 PangoAttrList
*layout_attr
;
569 PangoAttribute
*attr
;
570 gint colours
[3] = { 0 };
571 gboolean add_linenumber
= TRUE
;
574 while (count
< dinfo
->lines_per_page
&& c
!= '\0')
578 g_string_erase(str
, 0, str
->len
); /* clear the string */
581 if (printing_prefs
.print_line_numbers
&& add_linenumber
)
583 /* if we had a wrapped line on the last page which needs to be continued, don't
584 * add a line number */
585 if (dinfo
->long_line
)
587 add_linenumber
= FALSE
;
591 gchar
*line_number
= NULL
;
592 gint cur_line_number_margin
= get_line_numbers_arity(dinfo
->cur_line
+ 1);
593 gchar
*fill
= g_strnfill(
594 dinfo
->max_line_number_margin
- cur_line_number_margin
- 1, ' ');
596 line_number
= g_strdup_printf("%s%d ", fill
, dinfo
->cur_line
+ 1);
597 g_string_append(str
, line_number
);
598 dinfo
->cur_line
++; /* increase document line */
599 add_linenumber
= FALSE
;
600 style
= STYLE_LINENUMBER
;
601 c
= 'a'; /* dummy value */
609 style
= sci_get_style_at(dinfo
->doc
->editor
->sci
, dinfo
->cur_pos
);
610 c
= sci_get_char_at(dinfo
->doc
->editor
->sci
, dinfo
->cur_pos
);
611 if (c
== '\0' || style
== -1)
612 { /* if c gets 0, we are probably out of document boundaries,
613 * so stop to break out of outer loop */
614 count
= dinfo
->lines_per_page
;
619 /* convert tabs to spaces which seems to be better than using Pango tabs */
622 gint tab_width
= sci_get_tab_width(editor
->sci
);
623 gchar
*s
= g_strnfill(tab_width
, ' ');
624 g_string_append(str
, s
);
627 /* don't add line breaks, they are handled manually below */
628 else if (c
== '\r' || c
== '\n')
630 gchar c_next
= sci_get_char_at(dinfo
->doc
->editor
->sci
, dinfo
->cur_pos
);
632 if (c
== '\r' && c_next
== '\n')
633 dinfo
->cur_pos
++; /* skip LF part of CR/LF */
637 g_string_append_c(str
, c
); /* finally add the character */
639 /* handle UTF-8: since we add char by char (better: byte by byte), we need to
640 * keep UTF-8 characters together(e.g. two bytes for one character)
641 * the input is always UTF-8 and c is signed, so all non-Ascii
642 * characters are less than 0 and consist of all bytes less than 0.
643 * style doesn't change since it is only one character with multiple bytes. */
646 c
= sci_get_char_at(dinfo
->doc
->editor
->sci
, dinfo
->cur_pos
);
648 { /* only add the byte when it is part of the UTF-8 character
649 * otherwise we could add e.g. a '\n' and it won't be visible in the
650 * printed document */
651 g_string_append_c(str
, c
);
661 pango_layout_set_text(dinfo
->layout
, str
->str
, -1);
663 layout_attr
= pango_attr_list_new();
664 /* foreground colour */
665 get_rgb_values(dinfo
->styles
[style
][FORE
], &colours
[0], &colours
[1], &colours
[2]);
666 attr
= pango_attr_foreground_new(colours
[0], colours
[1], colours
[2]);
667 ADD_ATTR(layout_attr
, attr
);
668 /* background colour */
669 get_rgb_values(dinfo
->styles
[style
][BACK
], &colours
[0], &colours
[1], &colours
[2]);
670 attr
= pango_attr_background_new(colours
[0], colours
[1], colours
[2]);
671 ADD_ATTR(layout_attr
, attr
);
673 if (dinfo
->styles
[style
][BOLD
])
675 attr
= pango_attr_weight_new(PANGO_WEIGHT_BOLD
);
676 ADD_ATTR(layout_attr
, attr
);
679 if (dinfo
->styles
[style
][ITALIC
])
681 attr
= pango_attr_style_new(PANGO_STYLE_ITALIC
);
682 ADD_ATTR(layout_attr
, attr
);
684 pango_layout_set_attributes(dinfo
->layout
, layout_attr
);
685 pango_layout_context_changed(dinfo
->layout
);
686 pango_attr_list_unref(layout_attr
);
689 cairo_get_current_point(cr
, &x
, &y
);
692 /* normal line break at eol character in document */
695 /*pango_layout_get_size(dinfo->layout, NULL, &layout_h);*/
696 /*cairo_move_to(cr, 0, y + (gdouble)layout_h / PANGO_SCALE);*/
697 cairo_move_to(cr
, 0, y
+ dinfo
->line_height
);
700 /* we added a new document line so request a new line number */
701 add_linenumber
= TRUE
;
706 /* maybe we need to force a line break because of too long line */
707 if (x
>= (width
- dinfo
->font_width
))
709 /* don't start the line at horizontal origin because we need to skip the
710 * line number margin */
711 if (printing_prefs
.print_line_numbers
)
713 x_offset
= (dinfo
->max_line_number_margin
+ 1) * dinfo
->font_width
;
716 /*pango_layout_get_size(dinfo->layout, NULL, &layout_h);*/
717 /*cairo_move_to(cr, x_offset, y + (gdouble)layout_h / PANGO_SCALE);*/
718 /* this is faster but not exactly the same as above */
719 cairo_move_to(cr
, x_offset
, y
+ dinfo
->line_height
);
720 cairo_get_current_point(cr
, &x
, &y
);
723 if (count
< dinfo
->lines_per_page
)
725 /* str->len is counted in bytes not characters, so use g_utf8_strlen() */
726 x_offset
= (g_utf8_strlen(str
->str
, -1) * dinfo
->font_width
);
728 if (dinfo
->long_line
&& count
== 0)
730 x_offset
= (dinfo
->max_line_number_margin
+ 1) * dinfo
->font_width
;
731 dinfo
->long_line
= FALSE
;
734 pango_cairo_show_layout(cr
, dinfo
->layout
);
735 cairo_move_to(cr
, x
+ x_offset
, y
);
738 /* we are on a wrapped line but we are out of lines on this page, so continue
739 * the current line on the next page and remember to continue in current line */
740 dinfo
->long_line
= TRUE
;
745 if (printing_prefs
.print_line_numbers
)
746 { /* print a thin line between the line number margin and the data */
749 if (printing_prefs
.print_page_header
)
750 y_start
= (dinfo
->line_height
* 3) - 2; /* "- 2": to connect the line number line to
751 * the page header frame */
753 cairo_set_line_width(cr
, 0.3);
754 cairo_move_to(cr
, (dinfo
->max_line_number_margin
* dinfo
->font_width
) + 1, y_start
);
755 cairo_line_to(cr
, (dinfo
->max_line_number_margin
* dinfo
->font_width
) + 1,
756 y
+ dinfo
->line_height
); /* y is last added line, we reuse it */
760 if (printing_prefs
.print_page_numbers
)
762 gchar
*line
= g_strdup_printf("<small>- %d -</small>", page_nr
+ 1);
763 pango_layout_set_markup(dinfo
->layout
, line
, -1);
764 pango_layout_set_alignment(dinfo
->layout
, PANGO_ALIGN_CENTER
);
765 cairo_move_to(cr
, 0, height
- dinfo
->line_height
);
766 pango_cairo_show_layout(cr
, dinfo
->layout
);
769 #ifdef GEANY_PRINT_DEBUG
770 cairo_set_line_width(cr
, 0.3);
771 cairo_move_to(cr
, 0, height
- (1.25 * dinfo
->line_height
));
772 cairo_line_to(cr
, width
- 1, height
- (1.25 * dinfo
->line_height
));
776 g_string_free(str
, TRUE
);
780 static void status_changed(GtkPrintOperation
*op
, gpointer data
)
782 gchar
*filename
= (data
!= NULL
) ? data
: GEANY_STRING_UNTITLED
;
783 if (gtk_print_operation_get_status(op
) == GTK_PRINT_STATUS_FINISHED_ABORTED
)
784 msgwin_status_add(_("Did not send document %s to the printing subsystem."), filename
);
785 else if (gtk_print_operation_get_status(op
) == GTK_PRINT_STATUS_FINISHED
)
786 msgwin_status_add(_("Document %s was sent to the printing subsystem."), filename
);
790 static void printing_print_gtk(GeanyDocument
*doc
)
792 GtkPrintOperation
*op
;
793 GtkPrintOperationResult res
= GTK_PRINT_OPERATION_RESULT_ERROR
;
794 GError
*error
= NULL
;
796 PrintWidgets
*widgets
;
798 /** TODO check for monospace font, detect the widest character in the font and
799 * use it at font_width */
801 widgets
= g_new0(PrintWidgets
, 1);
802 dinfo
= g_new0(DocInfo
, 1);
803 /* all other fields are initialised in begin_print() */
806 op
= gtk_print_operation_new();
808 gtk_print_operation_set_unit(op
, GTK_UNIT_POINTS
);
809 gtk_print_operation_set_show_progress(op
, TRUE
);
810 #if GTK_CHECK_VERSION(2, 18, 0)
811 gtk_print_operation_set_embed_page_setup(op
, TRUE
);
814 g_signal_connect(op
, "begin-print", G_CALLBACK(begin_print
), dinfo
);
815 g_signal_connect(op
, "end-print", G_CALLBACK(end_print
), dinfo
);
816 g_signal_connect(op
, "draw-page", G_CALLBACK(draw_page
), dinfo
);
817 g_signal_connect(op
, "status-changed", G_CALLBACK(status_changed
), doc
->file_name
);
818 g_signal_connect(op
, "create-custom-widget", G_CALLBACK(create_custom_widget
), widgets
);
819 g_signal_connect(op
, "custom-widget-apply", G_CALLBACK(custom_widget_apply
), widgets
);
821 if (settings
!= NULL
)
822 gtk_print_operation_set_print_settings(op
, settings
);
823 if (page_setup
!= NULL
)
824 gtk_print_operation_set_default_page_setup(op
, page_setup
);
826 res
= gtk_print_operation_run(
827 op
, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG
, GTK_WINDOW(main_widgets
.window
), &error
);
829 if (res
== GTK_PRINT_OPERATION_RESULT_APPLY
)
831 if (settings
!= NULL
)
832 g_object_unref(settings
);
833 settings
= g_object_ref(gtk_print_operation_get_print_settings(op
));
834 /* status message is printed in the status-changed handler */
836 else if (res
== GTK_PRINT_OPERATION_RESULT_ERROR
)
838 dialogs_show_msgbox(GTK_MESSAGE_ERROR
, _("Printing of %s failed (%s)."),
839 doc
->file_name
, error
->message
);
849 void printing_page_setup_gtk(void)
851 GtkPageSetup
*new_page_setup
;
853 if (settings
== NULL
)
854 settings
= gtk_print_settings_new();
856 new_page_setup
= gtk_print_run_page_setup_dialog(
857 GTK_WINDOW(main_widgets
.window
), page_setup
, settings
);
859 if (page_setup
!= NULL
)
860 g_object_unref(page_setup
);
862 page_setup
= new_page_setup
;
864 #endif /* GTK 2.10 */
867 /* simple file print using an external tool */
868 static void print_external(GeanyDocument
*doc
)
872 if (doc
->file_name
== NULL
)
875 if (! NZV(printing_prefs
.external_print_cmd
))
877 dialogs_show_msgbox(GTK_MESSAGE_ERROR
,
878 _("Please set a print command in the preferences dialog first."));
882 cmdline
= g_strdup(printing_prefs
.external_print_cmd
);
883 utils_str_replace_all(&cmdline
, "%f", doc
->file_name
);
885 if (dialogs_show_question(
886 _("The file \"%s\" will be printed with the following command:\n\n%s"),
887 doc
->file_name
, cmdline
))
889 GError
*error
= NULL
;
892 gchar
*tmp_cmdline
= g_strdup(cmdline
);
894 /* /bin/sh -c emulates the system() call and makes complex commands possible
895 * but only needed on non-win32 systems due to the lack of win32's shell capabilities */
896 gchar
*tmp_cmdline
= g_strconcat("/bin/sh -c \"", cmdline
, "\"", NULL
);
899 if (! g_spawn_command_line_async(tmp_cmdline
, &error
))
901 dialogs_show_msgbox(GTK_MESSAGE_ERROR
,
902 _("Printing of \"%s\" failed (return code: %s)."),
903 doc
->file_name
, error
->message
);
908 msgwin_status_add(_("File %s printed."), doc
->file_name
);
916 void printing_print_doc(GeanyDocument
*doc
)
921 #if GTK_CHECK_VERSION(2, 10, 0)
922 if (gtk_check_version(2, 10, 0) == NULL
&& printing_prefs
.use_gtk_printing
)
923 printing_print_gtk(doc
);