Update HACKING for changed doc generation instructions
[geany-mirror.git] / src / printing.c
blobd954da682025718764e2ce0183732143fb8a3e9b
1 /*
2 * printing.c - this file is part of Geany, a fast and lightweight IDE
4 * Copyright 2007-2012 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
5 * Copyright 2007-2012 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
6 * Copyright 2012 Colomban Wendling <ban(at)herbesfolles(dot)org>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 * GTK printing support
26 * (basic code layout were adopted from Sylpheed's printing implementation, thanks)
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
33 #include "printing.h"
35 #include "app.h"
36 #include "dialogs.h"
37 #include "document.h"
38 #include "geany.h"
39 #include "highlighting.h"
40 #include "msgwindow.h"
41 #include "sciwrappers.h"
42 #include "support.h"
43 #include "utils.h"
44 #include "ui_utils.h"
46 #include <math.h>
47 #include <time.h>
48 #include <string.h>
51 PrintingPrefs printing_prefs;
54 /* document-related variables */
55 typedef struct
57 GeanyDocument *doc;
58 ScintillaObject *sci;
59 gdouble margin_width;
60 gdouble line_height;
61 /* set in begin_print() to hold the time when printing was started to ensure all printed
62 * pages have the same date and time (in case of slow machines and many pages where rendering
63 * takes more than a second) */
64 time_t print_time;
65 PangoLayout *layout; /* commonly used layout object */
66 gdouble sci_scale;
68 struct Sci_RangeToFormat fr;
69 GArray *pages;
70 } DocInfo;
72 /* widget references for the custom widget in the print dialog */
73 typedef struct
75 GtkWidget *check_print_linenumbers;
76 GtkWidget *check_print_pagenumbers;
77 GtkWidget *check_print_pageheader;
78 GtkWidget *check_print_basename;
79 GtkWidget *entry_print_dateformat;
80 } PrintWidgets;
83 static GtkPrintSettings *settings = NULL;
84 static GtkPageSetup *page_setup = NULL;
88 /* creates a commonly used layout object from the given context for use in get_page_count and
89 * draw_page */
90 static PangoLayout *setup_pango_layout(GtkPrintContext *context, PangoFontDescription *desc)
92 PangoLayout *layout;
94 layout = gtk_print_context_create_pango_layout(context);
95 pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
96 pango_layout_set_spacing(layout, 0);
97 pango_layout_set_attributes(layout, NULL);
98 pango_layout_set_font_description(layout, desc);
100 return layout;
104 static void get_text_dimensions(PangoLayout *layout, const gchar *text, gdouble *width, gdouble *height)
106 gint layout_w, layout_h;
108 pango_layout_set_text(layout, text, -1);
109 pango_layout_get_size(layout, &layout_w, &layout_h);
110 if (layout_w <= 0)
112 gint default_w = 50 * strlen(text) * PANGO_SCALE;
114 geany_debug("Invalid layout_w (%d). Falling back to default width (%d)",
115 layout_w, default_w);
116 layout_w = default_w;
118 if (layout_h <= 0)
120 gint default_h = 100 * PANGO_SCALE;
122 geany_debug("Invalid layout_h (%d). Falling back to default height (%d)",
123 layout_h, default_h);
124 layout_h = default_h;
127 if (width)
128 *width = (gdouble)layout_w / PANGO_SCALE;
129 if (height)
130 *height = (gdouble)layout_h / PANGO_SCALE;
134 static void add_page_header(DocInfo *dinfo, cairo_t *cr, gint width, gint page_nr)
136 gint ph_height = dinfo->line_height * 3;
137 gchar *data;
138 gchar *datetime;
139 const gchar *tmp_file_name = DOC_FILENAME(dinfo->doc);
140 gchar *file_name = (printing_prefs.page_header_basename) ?
141 g_path_get_basename(tmp_file_name) : g_strdup(tmp_file_name);
142 PangoLayout *layout = dinfo->layout;
144 /* draw the frame */
145 cairo_set_line_width(cr, 0.3);
146 cairo_set_source_rgb(cr, 0, 0, 0);
147 cairo_rectangle(cr, 2, 2, width - 4, ph_height - 4);
148 cairo_stroke(cr);
150 /* width - 8: 2px between doc border and frame border, 2px between frame border and text
151 * and this on left and right side, so (2 + 2) * 2 */
152 pango_layout_set_width(layout, (width - 8) * PANGO_SCALE);
153 pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_MIDDLE);
155 data = g_strdup_printf("<b>%s</b>", file_name);
156 pango_layout_set_markup(layout, data, -1);
157 pango_layout_set_alignment(layout, PANGO_ALIGN_LEFT);
158 cairo_move_to(cr, 4, dinfo->line_height * 0.5);
159 pango_cairo_show_layout(cr, layout);
160 g_free(data);
161 g_free(file_name);
163 data = g_strdup_printf(_("<b>Page %d of %d</b>"), page_nr + 1, dinfo->pages->len);
164 pango_layout_set_markup(layout, data, -1);
165 pango_layout_set_alignment(layout, PANGO_ALIGN_LEFT);
166 cairo_move_to(cr, 4, dinfo->line_height * 1.5);
167 pango_cairo_show_layout(cr, layout);
168 g_free(data);
170 datetime = utils_get_date_time(printing_prefs.page_header_datefmt, &(dinfo->print_time));
171 if (G_LIKELY(!EMPTY(datetime)))
173 data = g_strdup_printf("<b>%s</b>", datetime);
174 pango_layout_set_markup(layout, data, -1);
175 pango_layout_set_alignment(layout, PANGO_ALIGN_RIGHT);
176 cairo_move_to(cr, 2, dinfo->line_height * 1.5);
177 pango_cairo_show_layout(cr, layout);
178 g_free(data);
180 g_free(datetime);
182 /* reset layout and re-position cairo context */
183 pango_layout_set_alignment(layout, PANGO_ALIGN_LEFT);
184 pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE);
185 pango_layout_set_justify(layout, FALSE);
186 pango_layout_set_width(layout, width * PANGO_SCALE);
187 cairo_move_to(cr, 0, dinfo->line_height * 3);
191 static void custom_widget_apply(GtkPrintOperation *operation, GtkWidget *widget, gpointer user_data)
193 PrintWidgets *w = user_data;
195 printing_prefs.print_line_numbers =
196 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w->check_print_linenumbers));
198 printing_prefs.print_page_numbers =
199 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w->check_print_pagenumbers));
201 printing_prefs.print_page_header =
202 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w->check_print_pageheader));
204 printing_prefs.page_header_basename =
205 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w->check_print_basename));
207 g_free(printing_prefs.page_header_datefmt);
208 printing_prefs.page_header_datefmt =
209 g_strdup(gtk_entry_get_text(GTK_ENTRY(w->entry_print_dateformat)));
213 static void on_page_header_toggled(GtkToggleButton *togglebutton, gpointer user_data)
215 gboolean sens = gtk_toggle_button_get_active(togglebutton);
216 PrintWidgets *w = user_data;
218 gtk_widget_set_sensitive(w->check_print_basename, sens);
219 gtk_widget_set_sensitive(w->entry_print_dateformat, sens);
223 static GtkWidget *create_custom_widget(GtkPrintOperation *operation, gpointer user_data)
224 { /* copied from interface.c */
225 GtkWidget *page;
226 GtkWidget *frame33;
227 GtkWidget *alignment36;
228 GtkWidget *vbox30;
229 GtkWidget *hbox10;
230 GtkWidget *label203;
231 PrintWidgets *w = user_data;
233 gtk_print_operation_set_custom_tab_label(operation, _("Document Setup"));
235 page = gtk_vbox_new(FALSE, 0);
236 gtk_container_set_border_width(GTK_CONTAINER(page), 5);
238 w->check_print_linenumbers = gtk_check_button_new_with_mnemonic(_("Print line numbers"));
239 gtk_box_pack_start(GTK_BOX(page), w->check_print_linenumbers, FALSE, FALSE, 0);
240 gtk_widget_set_tooltip_text(w->check_print_linenumbers, _("Add line numbers to the printed page"));
241 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w->check_print_linenumbers), printing_prefs.print_line_numbers);
243 w->check_print_pagenumbers = gtk_check_button_new_with_mnemonic(_("Print page numbers"));
244 gtk_box_pack_start(GTK_BOX(page), w->check_print_pagenumbers, FALSE, FALSE, 0);
245 gtk_widget_set_tooltip_text(w->check_print_pagenumbers, _("Add page numbers at the bottom of each page. It takes 2 lines of the page."));
246 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w->check_print_pagenumbers), printing_prefs.print_page_numbers);
248 w->check_print_pageheader = gtk_check_button_new_with_mnemonic(_("Print page header"));
249 gtk_box_pack_start(GTK_BOX(page), w->check_print_pageheader, FALSE, FALSE, 0);
250 gtk_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."));
251 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w->check_print_pageheader), printing_prefs.print_page_header);
252 g_signal_connect(w->check_print_pageheader, "toggled", G_CALLBACK(on_page_header_toggled), w);
254 frame33 = gtk_frame_new(NULL);
255 gtk_box_pack_start(GTK_BOX(page), frame33, FALSE, FALSE, 0);
256 gtk_frame_set_label_align(GTK_FRAME(frame33), 0, 0);
257 gtk_frame_set_shadow_type(GTK_FRAME(frame33), GTK_SHADOW_NONE);
259 alignment36 = gtk_alignment_new(0, 0.5, 1, 1);
260 gtk_container_add(GTK_CONTAINER(frame33), alignment36);
261 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment36), 0, 0, 12, 0);
263 vbox30 = gtk_vbox_new(FALSE, 1);
264 gtk_container_add(GTK_CONTAINER(alignment36), vbox30);
266 w->check_print_basename = gtk_check_button_new_with_mnemonic(_("Use the basename of the printed file"));
267 gtk_box_pack_start(GTK_BOX(vbox30), w->check_print_basename, FALSE, FALSE, 0);
268 gtk_widget_set_tooltip_text(w->check_print_basename, _("Print only the basename(without the path) of the printed file"));
269 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w->check_print_basename), printing_prefs.page_header_basename);
271 hbox10 = gtk_hbox_new(FALSE, 5);
272 gtk_box_pack_start(GTK_BOX(vbox30), hbox10, TRUE, TRUE, 0);
274 label203 = gtk_label_new(_("Date format:"));
275 gtk_box_pack_start(GTK_BOX(hbox10), label203, FALSE, FALSE, 0);
277 w->entry_print_dateformat = gtk_entry_new();
278 ui_entry_add_clear_icon(GTK_ENTRY(w->entry_print_dateformat));
279 gtk_box_pack_start(GTK_BOX(hbox10), w->entry_print_dateformat, TRUE, TRUE, 0);
280 gtk_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."));
281 gtk_entry_set_text(GTK_ENTRY(w->entry_print_dateformat), printing_prefs.page_header_datefmt);
283 on_page_header_toggled(GTK_TOGGLE_BUTTON(w->check_print_pageheader), w);
284 gtk_widget_show_all(page);
285 return page;
289 static void end_print(GtkPrintOperation *operation, GtkPrintContext *context, gpointer user_data)
291 DocInfo *dinfo = user_data;
293 if (dinfo == NULL)
294 return;
296 gtk_widget_hide(main_widgets.progressbar);
297 g_object_unref(dinfo->sci);
298 g_object_unref(dinfo->layout);
299 g_array_free(dinfo->pages, TRUE);
303 static void setup_range(DocInfo *dinfo, GtkPrintContext *ctx)
305 dinfo->fr.hdc = dinfo->fr.hdcTarget = gtk_print_context_get_cairo_context(ctx);
307 dinfo->fr.rcPage.left = 0;
308 dinfo->fr.rcPage.top = 0;
309 dinfo->fr.rcPage.right = gtk_print_context_get_width(ctx);
310 dinfo->fr.rcPage.bottom = gtk_print_context_get_height(ctx);
312 dinfo->fr.rc.left = dinfo->fr.rcPage.left;
313 dinfo->fr.rc.top = dinfo->fr.rcPage.top;
314 dinfo->fr.rc.right = dinfo->fr.rcPage.right;
315 dinfo->fr.rc.bottom = dinfo->fr.rcPage.bottom;
317 if (printing_prefs.print_page_header)
318 dinfo->fr.rc.top += dinfo->line_height * 3; /* header height */
319 if (printing_prefs.print_page_numbers)
320 dinfo->fr.rc.bottom -= dinfo->line_height * 1; /* footer height */
322 dinfo->fr.rcPage.left /= dinfo->sci_scale;
323 dinfo->fr.rcPage.top /= dinfo->sci_scale;
324 dinfo->fr.rcPage.right /= dinfo->sci_scale;
325 dinfo->fr.rcPage.bottom /= dinfo->sci_scale;
326 dinfo->fr.rc.left /= dinfo->sci_scale;
327 dinfo->fr.rc.top /= dinfo->sci_scale;
328 dinfo->fr.rc.right /= dinfo->sci_scale;
329 dinfo->fr.rc.bottom /= dinfo->sci_scale;
331 dinfo->fr.chrg.cpMin = 0;
332 dinfo->fr.chrg.cpMax = sci_get_length(dinfo->sci);
336 static void begin_print(GtkPrintOperation *operation, GtkPrintContext *context, gpointer user_data)
338 DocInfo *dinfo = user_data;
339 PangoContext *pango_ctx, *widget_pango_ctx;
340 PangoFontDescription *desc;
341 gdouble pango_res, widget_res;
343 if (dinfo == NULL)
344 return;
346 gtk_widget_show(main_widgets.progressbar);
348 /* init dinfo fields */
350 /* setup printing scintilla object */
351 dinfo->sci = editor_create_widget(dinfo->doc->editor);
352 /* since we won't add the widget to any container, assume it's ownership */
353 g_object_ref_sink(dinfo->sci);
354 scintilla_send_message(dinfo->sci, SCI_SETDOCPOINTER, 0,
355 scintilla_send_message(dinfo->doc->editor->sci, SCI_GETDOCPOINTER, 0, 0));
356 highlighting_set_styles(dinfo->sci, dinfo->doc->file_type);
357 sci_set_line_numbers(dinfo->sci, printing_prefs.print_line_numbers);
358 scintilla_send_message(dinfo->sci, SCI_SETVIEWWS, SCWS_INVISIBLE, 0);
359 scintilla_send_message(dinfo->sci, SCI_SETVIEWEOL, FALSE, 0);
360 scintilla_send_message(dinfo->sci, SCI_SETEDGEMODE, EDGE_NONE, 0);
361 scintilla_send_message(dinfo->sci, SCI_SETPRINTCOLOURMODE, SC_PRINT_COLOURONWHITE, 0);
363 /* Scintilla doesn't respect the context resolution, so we'll scale ourselves.
364 * Actually Scintilla simply doesn't know about the resolution since it creates its own
365 * Pango context out of the Cairo target, and the resolution is in the GtkPrintOperation's
366 * Pango context */
367 pango_ctx = gtk_print_context_create_pango_context(context);
368 pango_res = pango_cairo_context_get_resolution(pango_ctx);
369 g_object_unref(pango_ctx);
370 widget_pango_ctx = gtk_widget_get_pango_context(GTK_WIDGET(dinfo->sci));
371 widget_res = pango_cairo_context_get_resolution(widget_pango_ctx);
372 /* On Windows, for some reason the widget's resolution is -1, so follow
373 * Pango docs and peek the font map's one. */
374 if (widget_res < 0)
376 widget_res = pango_cairo_font_map_get_resolution(
377 (PangoCairoFontMap*) pango_context_get_font_map(widget_pango_ctx));
379 dinfo->sci_scale = pango_res / widget_res;
381 dinfo->pages = g_array_new(FALSE, FALSE, sizeof(gint));
383 dinfo->print_time = time(NULL);
384 /* create a PangoLayout to be commonly used in add_page_header() and draw_page() */
385 desc = pango_font_description_from_string(interface_prefs.editor_font);
386 dinfo->layout = setup_pango_layout(context, desc);
387 pango_font_description_free(desc);
388 get_text_dimensions(dinfo->layout, "|XMfjgq_" /* reasonably representative character set */,
389 NULL, &dinfo->line_height);
390 get_text_dimensions(dinfo->layout, "99999 " /* Scintilla resets the margin to the width of "99999" when printing */,
391 &dinfo->margin_width, NULL);
392 /* setup dinfo->fr */
393 setup_range(dinfo, context);
397 static gint format_range(DocInfo *dinfo, gboolean draw)
399 gint pos;
401 cairo_save(dinfo->fr.hdc);
402 cairo_scale(dinfo->fr.hdc, dinfo->sci_scale, dinfo->sci_scale);
403 pos = (gint) scintilla_send_message(dinfo->sci, SCI_FORMATRANGE, draw, (sptr_t) &dinfo->fr);
404 cairo_restore(dinfo->fr.hdc);
406 return pos;
410 static gboolean paginate(GtkPrintOperation *operation, GtkPrintContext *context, gpointer user_data)
412 DocInfo *dinfo = user_data;
414 /* for whatever reason we get called one more time after we returned TRUE, so avoid adding
415 * an empty page at the end */
416 if (dinfo->fr.chrg.cpMin >= dinfo->fr.chrg.cpMax)
417 return TRUE;
419 gtk_progress_bar_pulse(GTK_PROGRESS_BAR(main_widgets.progressbar));
420 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(main_widgets.progressbar), _("Paginating"));
422 g_array_append_val(dinfo->pages, dinfo->fr.chrg.cpMin);
423 dinfo->fr.chrg.cpMin = format_range(dinfo, FALSE);
425 gtk_print_operation_set_n_pages(operation, dinfo->pages->len);
427 return dinfo->fr.chrg.cpMin >= dinfo->fr.chrg.cpMax;
431 static void draw_page(GtkPrintOperation *operation, GtkPrintContext *context,
432 gint page_nr, gpointer user_data)
434 DocInfo *dinfo = user_data;
435 cairo_t *cr;
436 gdouble width, height;
438 g_return_if_fail(dinfo != NULL);
439 g_return_if_fail((guint)page_nr < dinfo->pages->len);
441 if (dinfo->pages->len > 0)
443 gdouble fraction = (page_nr + 1) / (gdouble) dinfo->pages->len;
444 gchar *text = g_strdup_printf(_("Page %d of %d"), page_nr + 1, dinfo->pages->len);
445 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(main_widgets.progressbar), fraction);
446 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(main_widgets.progressbar), text);
447 g_free(text);
450 cr = gtk_print_context_get_cairo_context(context);
451 width = gtk_print_context_get_width(context);
452 height = gtk_print_context_get_height(context);
454 if (printing_prefs.print_page_header)
455 add_page_header(dinfo, cr, width, page_nr);
457 dinfo->fr.chrg.cpMin = g_array_index(dinfo->pages, gint, page_nr);
458 if ((guint)page_nr + 1 < dinfo->pages->len)
459 dinfo->fr.chrg.cpMax = g_array_index(dinfo->pages, gint, page_nr + 1) - 1;
460 else /* it's the last page, print 'til the end */
461 dinfo->fr.chrg.cpMax = sci_get_length(dinfo->sci);
463 format_range(dinfo, TRUE);
465 /* reset color */
466 cairo_set_source_rgb(cr, 0, 0, 0);
468 if (printing_prefs.print_line_numbers)
469 { /* print a thin line between the line number margin and the data */
470 gdouble y1 = dinfo->fr.rc.top * dinfo->sci_scale;
471 gdouble y2 = dinfo->fr.rc.bottom * dinfo->sci_scale;
472 gdouble x = dinfo->fr.rc.left * dinfo->sci_scale + dinfo->margin_width;
474 if (printing_prefs.print_page_header)
475 y1 -= 2 - 0.3; /* to connect the line number line to the page header frame,
476 * 2 is the border, and 0.3 the line width */
478 cairo_set_line_width(cr, 0.3);
479 cairo_move_to(cr, x, y1);
480 cairo_line_to(cr, x, y2);
481 cairo_stroke(cr);
484 if (printing_prefs.print_page_numbers)
486 gchar *line = g_strdup_printf("<small>- %d -</small>", page_nr + 1);
487 pango_layout_set_markup(dinfo->layout, line, -1);
488 pango_layout_set_alignment(dinfo->layout, PANGO_ALIGN_CENTER);
489 cairo_move_to(cr, 0, height - dinfo->line_height);
490 pango_cairo_show_layout(cr, dinfo->layout);
491 g_free(line);
496 static void status_changed(GtkPrintOperation *op, gpointer data)
498 gchar *filename = (data != NULL) ? data : GEANY_STRING_UNTITLED;
499 if (gtk_print_operation_get_status(op) == GTK_PRINT_STATUS_FINISHED_ABORTED)
500 msgwin_status_add(_("Did not send document %s to the printing subsystem."), filename);
501 else if (gtk_print_operation_get_status(op) == GTK_PRINT_STATUS_FINISHED)
502 msgwin_status_add(_("Document %s was sent to the printing subsystem."), filename);
506 static void printing_print_gtk(GeanyDocument *doc)
508 GtkPrintOperation *op;
509 GtkPrintOperationResult res = GTK_PRINT_OPERATION_RESULT_ERROR;
510 GError *error = NULL;
511 static const DocInfo dinfo0;
512 DocInfo dinfo = dinfo0;
513 PrintWidgets *widgets;
515 /** TODO check for monospace font, detect the widest character in the font and
516 * use it at font_width */
518 widgets = g_new0(PrintWidgets, 1);
519 /* all other fields are initialised in begin_print() */
520 dinfo.doc = doc;
522 op = gtk_print_operation_new();
524 gtk_print_operation_set_unit(op, GTK_UNIT_POINTS);
525 gtk_print_operation_set_show_progress(op, TRUE);
526 #if GTK_CHECK_VERSION(2, 18, 0)
527 gtk_print_operation_set_embed_page_setup(op, TRUE);
528 #endif
530 g_signal_connect(op, "begin-print", G_CALLBACK(begin_print), &dinfo);
531 g_signal_connect(op, "end-print", G_CALLBACK(end_print), &dinfo);
532 g_signal_connect(op, "paginate", G_CALLBACK(paginate), &dinfo);
533 g_signal_connect(op, "draw-page", G_CALLBACK(draw_page), &dinfo);
534 g_signal_connect(op, "status-changed", G_CALLBACK(status_changed), doc->file_name);
535 g_signal_connect(op, "create-custom-widget", G_CALLBACK(create_custom_widget), widgets);
536 g_signal_connect(op, "custom-widget-apply", G_CALLBACK(custom_widget_apply), widgets);
538 if (settings != NULL)
539 gtk_print_operation_set_print_settings(op, settings);
540 if (page_setup != NULL)
541 gtk_print_operation_set_default_page_setup(op, page_setup);
543 res = gtk_print_operation_run(
544 op, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG, GTK_WINDOW(main_widgets.window), &error);
546 if (res == GTK_PRINT_OPERATION_RESULT_APPLY)
548 if (settings != NULL)
549 g_object_unref(settings);
550 settings = g_object_ref(gtk_print_operation_get_print_settings(op));
551 /* status message is printed in the status-changed handler */
553 else if (res == GTK_PRINT_OPERATION_RESULT_ERROR)
555 dialogs_show_msgbox(GTK_MESSAGE_ERROR, _("Printing of %s failed (%s)."),
556 doc->file_name, error->message);
557 g_error_free(error);
560 g_object_unref(op);
561 g_free(widgets);
565 void printing_page_setup_gtk(void)
567 GtkPageSetup *new_page_setup;
569 if (settings == NULL)
570 settings = gtk_print_settings_new();
572 new_page_setup = gtk_print_run_page_setup_dialog(
573 GTK_WINDOW(main_widgets.window), page_setup, settings);
575 if (page_setup != NULL)
576 g_object_unref(page_setup);
578 page_setup = new_page_setup;
582 /* simple file print using an external tool */
583 static void print_external(GeanyDocument *doc)
585 gchar *cmdline;
587 if (doc->file_name == NULL)
588 return;
590 if (EMPTY(printing_prefs.external_print_cmd))
592 dialogs_show_msgbox(GTK_MESSAGE_ERROR,
593 _("Please set a print command in the preferences dialog first."));
594 return;
597 cmdline = g_strdup(printing_prefs.external_print_cmd);
598 utils_str_replace_all(&cmdline, "%f", doc->file_name);
600 if (dialogs_show_question(
601 _("The file \"%s\" will be printed with the following command:\n\n%s"),
602 doc->file_name, cmdline))
604 GError *error = NULL;
606 #ifdef G_OS_WIN32
607 gchar *tmp_cmdline = g_strdup(cmdline);
608 #else
609 /* /bin/sh -c emulates the system() call and makes complex commands possible
610 * but only needed on non-win32 systems due to the lack of win32's shell capabilities */
611 gchar *tmp_cmdline = g_strconcat("/bin/sh -c \"", cmdline, "\"", NULL);
612 #endif
614 if (! g_spawn_command_line_async(tmp_cmdline, &error))
616 dialogs_show_msgbox(GTK_MESSAGE_ERROR,
617 _("Printing of \"%s\" failed (return code: %s)."),
618 doc->file_name, error->message);
619 g_error_free(error);
621 else
623 msgwin_status_add(_("File %s printed."), doc->file_name);
625 g_free(tmp_cmdline);
627 g_free(cmdline);
631 void printing_print_doc(GeanyDocument *doc)
633 g_return_if_fail(DOC_VALID(doc));
635 if (printing_prefs.use_gtk_printing)
636 printing_print_gtk(doc);
637 else
638 print_external(doc);