1 | /* GTK - The GIMP Toolkit |
2 | * gtkprintbackendfile.c: Default implementation of GtkPrintBackend |
3 | * for printing to a file |
4 | * Copyright (C) 2003, Red Hat, Inc. |
5 | * |
6 | * This library is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU Lesser General Public |
8 | * License as published by the Free Software Foundation; either |
9 | * version 2 of the License, or (at your option) any later version. |
10 | * |
11 | * This library is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | * Lesser General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU Lesser General Public |
17 | * License along with this library. If not, see <http://www.gnu.org/licenses/>. |
18 | */ |
19 | |
20 | #include "config.h" |
21 | |
22 | #include <unistd.h> |
23 | #include <sys/types.h> |
24 | #include <sys/stat.h> |
25 | #include <fcntl.h> |
26 | #include <stdlib.h> |
27 | #include <string.h> |
28 | |
29 | #include <errno.h> |
30 | #include <cairo.h> |
31 | #include <cairo-pdf.h> |
32 | #include <cairo-ps.h> |
33 | #include <cairo-svg.h> |
34 | |
35 | #include <glib/gi18n-lib.h> |
36 | |
37 | #include "gtk/gtk.h" |
38 | #include "gtk/gtkprinterprivate.h" |
39 | |
40 | #include "gtkprintbackendfile.h" |
41 | |
42 | typedef struct _GtkPrintBackendFileClass GtkPrintBackendFileClass; |
43 | |
44 | #define GTK_PRINT_BACKEND_FILE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PRINT_BACKEND_FILE, GtkPrintBackendFileClass)) |
45 | #define GTK_IS_PRINT_BACKEND_FILE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PRINT_BACKEND_FILE)) |
46 | #define GTK_PRINT_BACKEND_FILE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PRINT_BACKEND_FILE, GtkPrintBackendFileClass)) |
47 | |
48 | #define _STREAM_MAX_CHUNK_SIZE 8192 |
49 | |
50 | struct _GtkPrintBackendFileClass |
51 | { |
52 | GtkPrintBackendClass parent_class; |
53 | }; |
54 | |
55 | struct _GtkPrintBackendFile |
56 | { |
57 | GtkPrintBackend parent_instance; |
58 | }; |
59 | |
60 | typedef enum |
61 | { |
62 | FORMAT_PDF, |
63 | FORMAT_PS, |
64 | FORMAT_SVG, |
65 | N_FORMATS |
66 | } OutputFormat; |
67 | |
68 | static const char * formats[N_FORMATS] = |
69 | { |
70 | "pdf" , |
71 | "ps" , |
72 | "svg" |
73 | }; |
74 | |
75 | static GObjectClass *backend_parent_class; |
76 | |
77 | static void file_printer_get_settings_from_options (GtkPrinter *printer, |
78 | GtkPrinterOptionSet *options, |
79 | GtkPrintSettings *settings); |
80 | static GtkPrinterOptionSet *file_printer_get_options (GtkPrinter *printer, |
81 | GtkPrintSettings *settings, |
82 | GtkPageSetup *page_setup, |
83 | GtkPrintCapabilities capabilities); |
84 | static void file_printer_prepare_for_print (GtkPrinter *printer, |
85 | GtkPrintJob *print_job, |
86 | GtkPrintSettings *settings, |
87 | GtkPageSetup *page_setup); |
88 | static void gtk_print_backend_file_print_stream (GtkPrintBackend *print_backend, |
89 | GtkPrintJob *job, |
90 | GIOChannel *data_io, |
91 | GtkPrintJobCompleteFunc callback, |
92 | gpointer user_data, |
93 | GDestroyNotify dnotify); |
94 | static cairo_surface_t * file_printer_create_cairo_surface (GtkPrinter *printer, |
95 | GtkPrintSettings *settings, |
96 | double width, |
97 | double height, |
98 | GIOChannel *cache_io); |
99 | |
100 | static GList * file_printer_list_papers (GtkPrinter *printer); |
101 | static GtkPageSetup * file_printer_get_default_page_size (GtkPrinter *printer); |
102 | |
103 | G_DEFINE_DYNAMIC_TYPE(GtkPrintBackendFile, gtk_print_backend_file, GTK_TYPE_PRINT_BACKEND) |
104 | |
105 | void |
106 | g_io_module_load (GIOModule *module) |
107 | { |
108 | g_type_module_use (G_TYPE_MODULE (module)); |
109 | |
110 | gtk_print_backend_file_register_type (G_TYPE_MODULE (module)); |
111 | |
112 | g_io_extension_point_implement (GTK_PRINT_BACKEND_EXTENSION_POINT_NAME, |
113 | GTK_TYPE_PRINT_BACKEND_FILE, |
114 | extension_name: "file" , |
115 | priority: 10); |
116 | } |
117 | |
118 | void |
119 | g_io_module_unload (GIOModule *module) |
120 | { |
121 | } |
122 | |
123 | char ** |
124 | g_io_module_query (void) |
125 | { |
126 | char *eps[] = { |
127 | (char *)GTK_PRINT_BACKEND_EXTENSION_POINT_NAME, |
128 | NULL |
129 | }; |
130 | |
131 | return g_strdupv (str_array: eps); |
132 | } |
133 | |
134 | /** |
135 | * gtk_print_backend_file_new: |
136 | * |
137 | * Creates a new #GtkPrintBackendFile object. #GtkPrintBackendFile |
138 | * implements the #GtkPrintBackend interface with direct access to |
139 | * the filesystem using Unix/Linux API calls |
140 | * |
141 | * Returns: the new #GtkPrintBackendFile object |
142 | **/ |
143 | GtkPrintBackend * |
144 | gtk_print_backend_file_new (void) |
145 | { |
146 | return g_object_new (GTK_TYPE_PRINT_BACKEND_FILE, NULL); |
147 | } |
148 | |
149 | static void |
150 | gtk_print_backend_file_class_init (GtkPrintBackendFileClass *class) |
151 | { |
152 | GtkPrintBackendClass *backend_class = GTK_PRINT_BACKEND_CLASS (class); |
153 | |
154 | backend_parent_class = g_type_class_peek_parent (g_class: class); |
155 | |
156 | backend_class->print_stream = gtk_print_backend_file_print_stream; |
157 | backend_class->printer_create_cairo_surface = file_printer_create_cairo_surface; |
158 | backend_class->printer_get_options = file_printer_get_options; |
159 | backend_class->printer_get_settings_from_options = file_printer_get_settings_from_options; |
160 | backend_class->printer_prepare_for_print = file_printer_prepare_for_print; |
161 | backend_class->printer_list_papers = file_printer_list_papers; |
162 | backend_class->printer_get_default_page_size = file_printer_get_default_page_size; |
163 | } |
164 | |
165 | static void |
166 | gtk_print_backend_file_class_finalize (GtkPrintBackendFileClass *class) |
167 | { |
168 | } |
169 | |
170 | /* return N_FORMATS if no explicit format in the settings */ |
171 | static OutputFormat |
172 | format_from_settings (GtkPrintSettings *settings) |
173 | { |
174 | const char *value; |
175 | int i; |
176 | |
177 | if (settings == NULL) |
178 | return N_FORMATS; |
179 | |
180 | value = gtk_print_settings_get (settings, |
181 | GTK_PRINT_SETTINGS_OUTPUT_FILE_FORMAT); |
182 | if (value == NULL) |
183 | return N_FORMATS; |
184 | |
185 | for (i = 0; i < N_FORMATS; ++i) |
186 | if (strcmp (s1: value, s2: formats[i]) == 0) |
187 | break; |
188 | |
189 | g_assert (i < N_FORMATS); |
190 | |
191 | return (OutputFormat) i; |
192 | } |
193 | |
194 | static char * |
195 | output_file_from_settings (GtkPrintSettings *settings, |
196 | const char *default_format) |
197 | { |
198 | char *uri = NULL; |
199 | |
200 | if (settings) |
201 | uri = g_strdup (str: gtk_print_settings_get (settings, GTK_PRINT_SETTINGS_OUTPUT_URI)); |
202 | |
203 | if (uri == NULL) |
204 | { |
205 | const char *extension, *basename = NULL, *output_dir = NULL; |
206 | char *name, *locale_name, *path; |
207 | |
208 | if (default_format) |
209 | extension = default_format; |
210 | else |
211 | { |
212 | OutputFormat format; |
213 | |
214 | format = format_from_settings (settings); |
215 | switch (format) |
216 | { |
217 | default: |
218 | case N_FORMATS: |
219 | case FORMAT_PDF: |
220 | extension = "pdf" ; |
221 | break; |
222 | case FORMAT_PS: |
223 | extension = "ps" ; |
224 | break; |
225 | case FORMAT_SVG: |
226 | extension = "svg" ; |
227 | break; |
228 | } |
229 | } |
230 | |
231 | if (settings) |
232 | basename = gtk_print_settings_get (settings, GTK_PRINT_SETTINGS_OUTPUT_BASENAME); |
233 | if (basename == NULL) |
234 | basename = _("output" ); |
235 | |
236 | name = g_strconcat (string1: basename, "." , extension, NULL); |
237 | |
238 | locale_name = g_filename_from_utf8 (utf8string: name, len: -1, NULL, NULL, NULL); |
239 | g_free (mem: name); |
240 | |
241 | if (locale_name != NULL) |
242 | { |
243 | if (settings) |
244 | output_dir = gtk_print_settings_get (settings, GTK_PRINT_SETTINGS_OUTPUT_DIR); |
245 | if (output_dir == NULL) |
246 | { |
247 | const char *document_dir = g_get_user_special_dir (directory: G_USER_DIRECTORY_DOCUMENTS); |
248 | |
249 | if (document_dir == NULL) |
250 | { |
251 | char *current_dir = g_get_current_dir (); |
252 | path = g_build_filename (first_element: current_dir, locale_name, NULL); |
253 | g_free (mem: current_dir); |
254 | } |
255 | else |
256 | path = g_build_filename (first_element: document_dir, locale_name, NULL); |
257 | |
258 | uri = g_filename_to_uri (filename: path, NULL, NULL); |
259 | } |
260 | else |
261 | { |
262 | path = g_build_filename (first_element: output_dir, locale_name, NULL); |
263 | uri = g_filename_to_uri (filename: path, NULL, NULL); |
264 | } |
265 | |
266 | g_free (mem: path); |
267 | g_free (mem: locale_name); |
268 | } |
269 | } |
270 | |
271 | return uri; |
272 | } |
273 | |
274 | static cairo_status_t |
275 | _cairo_write (void *closure, |
276 | const unsigned char *data, |
277 | unsigned int length) |
278 | { |
279 | GIOChannel *io = (GIOChannel *)closure; |
280 | gsize written = 0; |
281 | GError *error; |
282 | |
283 | error = NULL; |
284 | |
285 | GTK_NOTE (PRINTING, |
286 | g_print ("FILE Backend: Writing %u byte chunk to temp file\n" , length)); |
287 | |
288 | while (length > 0) |
289 | { |
290 | GIOStatus status; |
291 | |
292 | status = g_io_channel_write_chars (channel: io, buf: (const char *) data, count: length, bytes_written: &written, error: &error); |
293 | |
294 | if (status == G_IO_STATUS_ERROR) |
295 | { |
296 | if (error != NULL) |
297 | { |
298 | GTK_NOTE (PRINTING, |
299 | g_print ("FILE Backend: Error writing to temp file, %s\n" , error->message)); |
300 | |
301 | g_error_free (error); |
302 | } |
303 | |
304 | return CAIRO_STATUS_WRITE_ERROR; |
305 | } |
306 | |
307 | GTK_NOTE (PRINTING, |
308 | g_print ("FILE Backend: Wrote %zd bytes to temp file\n" , written)); |
309 | |
310 | data += written; |
311 | length -= written; |
312 | } |
313 | |
314 | return CAIRO_STATUS_SUCCESS; |
315 | } |
316 | |
317 | |
318 | static cairo_surface_t * |
319 | file_printer_create_cairo_surface (GtkPrinter *printer, |
320 | GtkPrintSettings *settings, |
321 | double width, |
322 | double height, |
323 | GIOChannel *cache_io) |
324 | { |
325 | cairo_surface_t *surface; |
326 | OutputFormat format; |
327 | const cairo_svg_version_t *versions; |
328 | int num_versions = 0; |
329 | |
330 | format = format_from_settings (settings); |
331 | |
332 | switch (format) |
333 | { |
334 | default: |
335 | case N_FORMATS: |
336 | case FORMAT_PDF: |
337 | surface = cairo_pdf_surface_create_for_stream (write_func: _cairo_write, closure: cache_io, width_in_points: width, height_in_points: height); |
338 | break; |
339 | case FORMAT_PS: |
340 | surface = cairo_ps_surface_create_for_stream (write_func: _cairo_write, closure: cache_io, width_in_points: width, height_in_points: height); |
341 | break; |
342 | case FORMAT_SVG: |
343 | surface = cairo_svg_surface_create_for_stream (write_func: _cairo_write, closure: cache_io, width_in_points: width, height_in_points: height); |
344 | cairo_svg_get_versions (versions: &versions, num_versions: &num_versions); |
345 | if (num_versions > 0) |
346 | cairo_svg_surface_restrict_to_version (surface, version: versions[num_versions - 1]); |
347 | break; |
348 | } |
349 | |
350 | cairo_surface_set_fallback_resolution (surface, |
351 | x_pixels_per_inch: 2.0 * gtk_print_settings_get_printer_lpi (settings), |
352 | y_pixels_per_inch: 2.0 * gtk_print_settings_get_printer_lpi (settings)); |
353 | |
354 | return surface; |
355 | } |
356 | |
357 | typedef struct { |
358 | GtkPrintBackend *backend; |
359 | GtkPrintJobCompleteFunc callback; |
360 | GtkPrintJob *job; |
361 | GFileOutputStream *target_io_stream; |
362 | gpointer user_data; |
363 | GDestroyNotify dnotify; |
364 | } _PrintStreamData; |
365 | |
366 | static void |
367 | file_print_cb (GtkPrintBackendFile *print_backend, |
368 | GError *error, |
369 | gpointer user_data) |
370 | { |
371 | char *uri; |
372 | |
373 | _PrintStreamData *ps = (_PrintStreamData *) user_data; |
374 | GtkRecentManager *recent_manager; |
375 | |
376 | if (ps->target_io_stream != NULL) |
377 | (void)g_output_stream_close (G_OUTPUT_STREAM (ps->target_io_stream), NULL, NULL); |
378 | |
379 | if (ps->callback) |
380 | ps->callback (ps->job, ps->user_data, error); |
381 | |
382 | if (ps->dnotify) |
383 | ps->dnotify (ps->user_data); |
384 | |
385 | gtk_print_job_set_status (job: ps->job, |
386 | status: (error != NULL) |
387 | ? GTK_PRINT_STATUS_FINISHED_ABORTED |
388 | : GTK_PRINT_STATUS_FINISHED); |
389 | |
390 | recent_manager = gtk_recent_manager_get_default (); |
391 | uri = output_file_from_settings (settings: gtk_print_job_get_settings (job: ps->job), NULL); |
392 | gtk_recent_manager_add_item (manager: recent_manager, uri); |
393 | g_free (mem: uri); |
394 | |
395 | if (ps->job) |
396 | g_object_unref (object: ps->job); |
397 | |
398 | g_free (mem: ps); |
399 | } |
400 | |
401 | static gboolean |
402 | file_write (GIOChannel *source, |
403 | GIOCondition con, |
404 | gpointer user_data) |
405 | { |
406 | char buf[_STREAM_MAX_CHUNK_SIZE]; |
407 | gsize bytes_read; |
408 | GError *error; |
409 | GIOStatus read_status; |
410 | _PrintStreamData *ps = (_PrintStreamData *) user_data; |
411 | |
412 | error = NULL; |
413 | |
414 | read_status = |
415 | g_io_channel_read_chars (channel: source, |
416 | buf, |
417 | _STREAM_MAX_CHUNK_SIZE, |
418 | bytes_read: &bytes_read, |
419 | error: &error); |
420 | |
421 | if (read_status != G_IO_STATUS_ERROR) |
422 | { |
423 | gsize bytes_written; |
424 | |
425 | g_output_stream_write_all (G_OUTPUT_STREAM (ps->target_io_stream), |
426 | buffer: buf, |
427 | count: bytes_read, |
428 | bytes_written: &bytes_written, |
429 | NULL, |
430 | error: &error); |
431 | } |
432 | |
433 | if (error != NULL || read_status == G_IO_STATUS_EOF) |
434 | { |
435 | file_print_cb (GTK_PRINT_BACKEND_FILE (ps->backend), error, user_data); |
436 | |
437 | if (error != NULL) |
438 | { |
439 | GTK_NOTE (PRINTING, |
440 | g_print ("FILE Backend: %s\n" , error->message)); |
441 | |
442 | g_error_free (error); |
443 | } |
444 | |
445 | return FALSE; |
446 | } |
447 | |
448 | GTK_NOTE (PRINTING, |
449 | g_print ("FILE Backend: Writing %" G_GSIZE_FORMAT" byte chunk to target file\n" , bytes_read)); |
450 | |
451 | return TRUE; |
452 | } |
453 | |
454 | static void |
455 | gtk_print_backend_file_print_stream (GtkPrintBackend *print_backend, |
456 | GtkPrintJob *job, |
457 | GIOChannel *data_io, |
458 | GtkPrintJobCompleteFunc callback, |
459 | gpointer user_data, |
460 | GDestroyNotify dnotify) |
461 | { |
462 | GError *internal_error = NULL; |
463 | _PrintStreamData *ps; |
464 | GtkPrintSettings *settings; |
465 | char *uri; |
466 | GFile *file = NULL; |
467 | |
468 | settings = gtk_print_job_get_settings (job); |
469 | |
470 | ps = g_new0 (_PrintStreamData, 1); |
471 | ps->callback = callback; |
472 | ps->user_data = user_data; |
473 | ps->dnotify = dnotify; |
474 | ps->job = g_object_ref (job); |
475 | ps->backend = print_backend; |
476 | |
477 | internal_error = NULL; |
478 | uri = output_file_from_settings (settings, NULL); |
479 | |
480 | if (uri == NULL) |
481 | goto error; |
482 | |
483 | file = g_file_new_for_uri (uri); |
484 | ps->target_io_stream = g_file_replace (file, NULL, FALSE, flags: G_FILE_CREATE_NONE, NULL, error: &internal_error); |
485 | |
486 | g_object_unref (object: file); |
487 | g_free (mem: uri); |
488 | |
489 | error: |
490 | if (internal_error != NULL) |
491 | { |
492 | file_print_cb (GTK_PRINT_BACKEND_FILE (print_backend), |
493 | error: internal_error, user_data: ps); |
494 | |
495 | g_error_free (error: internal_error); |
496 | return; |
497 | } |
498 | |
499 | g_io_add_watch (channel: data_io, |
500 | condition: G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, |
501 | func: (GIOFunc) file_write, |
502 | user_data: ps); |
503 | } |
504 | |
505 | static void |
506 | gtk_print_backend_file_init (GtkPrintBackendFile *backend) |
507 | { |
508 | GtkPrinter *printer; |
509 | |
510 | printer = g_object_new (GTK_TYPE_PRINTER, |
511 | first_property_name: "name" , _("Print to File" ), |
512 | "backend" , backend, |
513 | "is-virtual" , TRUE, |
514 | "accepts-pdf" , TRUE, |
515 | NULL); |
516 | |
517 | gtk_printer_set_has_details (printer, TRUE); |
518 | gtk_printer_set_icon_name (printer, icon: "document-save" ); |
519 | gtk_printer_set_is_active (printer, TRUE); |
520 | |
521 | gtk_print_backend_add_printer (GTK_PRINT_BACKEND (backend), printer); |
522 | g_object_unref (object: printer); |
523 | |
524 | gtk_print_backend_set_list_done (GTK_PRINT_BACKEND (backend)); |
525 | } |
526 | |
527 | typedef struct { |
528 | GtkPrinter *printer; |
529 | GtkPrinterOptionSet *set; |
530 | } _OutputFormatChangedData; |
531 | |
532 | static void |
533 | set_printer_format_from_option_set (GtkPrinter *printer, |
534 | GtkPrinterOptionSet *set) |
535 | { |
536 | GtkPrinterOption *format_option; |
537 | const char *value; |
538 | int i; |
539 | |
540 | format_option = gtk_printer_option_set_lookup (set, name: "output-file-format" ); |
541 | if (format_option && format_option->value) |
542 | { |
543 | value = format_option->value; |
544 | if (value) |
545 | { |
546 | for (i = 0; i < N_FORMATS; ++i) |
547 | if (strcmp (s1: value, s2: formats[i]) == 0) |
548 | break; |
549 | |
550 | g_assert (i < N_FORMATS); |
551 | |
552 | switch (i) |
553 | { |
554 | case FORMAT_PDF: |
555 | gtk_printer_set_accepts_pdf (printer, TRUE); |
556 | gtk_printer_set_accepts_ps (printer, FALSE); |
557 | break; |
558 | case FORMAT_PS: |
559 | gtk_printer_set_accepts_pdf (printer, FALSE); |
560 | gtk_printer_set_accepts_ps (printer, TRUE); |
561 | break; |
562 | case FORMAT_SVG: |
563 | default: |
564 | gtk_printer_set_accepts_pdf (printer, FALSE); |
565 | gtk_printer_set_accepts_ps (printer, FALSE); |
566 | break; |
567 | } |
568 | } |
569 | } |
570 | } |
571 | |
572 | static void |
573 | file_printer_output_file_format_changed (GtkPrinterOption *format_option, |
574 | gpointer user_data) |
575 | { |
576 | GtkPrinterOption *uri_option; |
577 | char *base = NULL; |
578 | _OutputFormatChangedData *data = (_OutputFormatChangedData *) user_data; |
579 | |
580 | if (! format_option->value) |
581 | return; |
582 | |
583 | uri_option = gtk_printer_option_set_lookup (set: data->set, |
584 | name: "gtk-main-page-custom-input" ); |
585 | |
586 | if (uri_option && uri_option->value) |
587 | { |
588 | const char *uri = uri_option->value; |
589 | const char *dot = strrchr (s: uri, c: '.'); |
590 | |
591 | if (dot) |
592 | { |
593 | int i; |
594 | |
595 | /* check if the file extension matches one of the known ones */ |
596 | for (i = 0; i < N_FORMATS; i++) |
597 | if (strcmp (s1: dot + 1, s2: formats[i]) == 0) |
598 | break; |
599 | |
600 | if (i < N_FORMATS && strcmp (s1: formats[i], s2: format_option->value)) |
601 | { |
602 | /* the file extension is known but doesn't match the |
603 | * selected one, strip it away |
604 | */ |
605 | base = g_strndup (str: uri, n: dot - uri); |
606 | } |
607 | } |
608 | else |
609 | { |
610 | /* there's no file extension */ |
611 | base = g_strdup (str: uri); |
612 | } |
613 | } |
614 | |
615 | if (base) |
616 | { |
617 | char *tmp = g_strdup_printf (format: "%s.%s" , base, format_option->value); |
618 | |
619 | gtk_printer_option_set (option: uri_option, value: tmp); |
620 | g_free (mem: tmp); |
621 | g_free (mem: base); |
622 | } |
623 | |
624 | set_printer_format_from_option_set (printer: data->printer, set: data->set); |
625 | } |
626 | |
627 | static GtkPrinterOptionSet * |
628 | file_printer_get_options (GtkPrinter *printer, |
629 | GtkPrintSettings *settings, |
630 | GtkPageSetup *page_setup, |
631 | GtkPrintCapabilities capabilities) |
632 | { |
633 | GtkPrinterOptionSet *set; |
634 | GtkPrinterOption *option; |
635 | const char *n_up[] = {"1" , "2" , "4" , "6" , "9" , "16" }; |
636 | const char *pages_per_sheet = NULL; |
637 | const char *format_names[N_FORMATS] = { N_("PDF" ), N_("PostScript" ), N_("SVG" ) }; |
638 | const char *supported_formats[N_FORMATS]; |
639 | const char *display_format_names[N_FORMATS]; |
640 | int n_formats = 0; |
641 | OutputFormat format; |
642 | char *uri; |
643 | int current_format = 0; |
644 | _OutputFormatChangedData *format_changed_data; |
645 | |
646 | format = format_from_settings (settings); |
647 | |
648 | set = gtk_printer_option_set_new (); |
649 | |
650 | option = gtk_printer_option_new (name: "gtk-n-up" , _("Pages per _sheet:" ), type: GTK_PRINTER_OPTION_TYPE_PICKONE); |
651 | gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (n_up), |
652 | choices: n_up, choices_display: n_up /* FIXME i18n (localised digits)! */); |
653 | if (settings) |
654 | pages_per_sheet = gtk_print_settings_get (settings, GTK_PRINT_SETTINGS_NUMBER_UP); |
655 | if (pages_per_sheet) |
656 | gtk_printer_option_set (option, value: pages_per_sheet); |
657 | else |
658 | gtk_printer_option_set (option, value: "1" ); |
659 | gtk_printer_option_set_add (set, option); |
660 | g_object_unref (object: option); |
661 | |
662 | if (capabilities & (GTK_PRINT_CAPABILITY_GENERATE_PDF | GTK_PRINT_CAPABILITY_GENERATE_PS)) |
663 | { |
664 | if (capabilities & GTK_PRINT_CAPABILITY_GENERATE_PDF) |
665 | { |
666 | if (format == FORMAT_PDF || format == N_FORMATS) |
667 | { |
668 | format = FORMAT_PDF; |
669 | current_format = n_formats; |
670 | } |
671 | supported_formats[n_formats] = formats[FORMAT_PDF]; |
672 | display_format_names[n_formats] = _(format_names[FORMAT_PDF]); |
673 | n_formats++; |
674 | } |
675 | if (capabilities & GTK_PRINT_CAPABILITY_GENERATE_PS) |
676 | { |
677 | if (format == FORMAT_PS || format == N_FORMATS) |
678 | current_format = n_formats; |
679 | supported_formats[n_formats] = formats[FORMAT_PS]; |
680 | display_format_names[n_formats] = _(format_names[FORMAT_PS]); |
681 | n_formats++; |
682 | } |
683 | } |
684 | else |
685 | { |
686 | switch (format) |
687 | { |
688 | default: |
689 | case N_FORMATS: |
690 | case FORMAT_PDF: |
691 | current_format = FORMAT_PDF; |
692 | break; |
693 | case FORMAT_PS: |
694 | current_format = FORMAT_PS; |
695 | break; |
696 | case FORMAT_SVG: |
697 | current_format = FORMAT_SVG; |
698 | break; |
699 | } |
700 | |
701 | for (n_formats = 0; n_formats < N_FORMATS; ++n_formats) |
702 | { |
703 | supported_formats[n_formats] = formats[n_formats]; |
704 | display_format_names[n_formats] = _(format_names[n_formats]); |
705 | } |
706 | } |
707 | |
708 | uri = output_file_from_settings (settings, default_format: supported_formats[current_format]); |
709 | |
710 | option = gtk_printer_option_new (name: "gtk-main-page-custom-input" , _("File" ), |
711 | type: GTK_PRINTER_OPTION_TYPE_FILESAVE); |
712 | gtk_printer_option_set_activates_default (option, TRUE); |
713 | gtk_printer_option_set (option, value: uri); |
714 | g_free (mem: uri); |
715 | option->group = g_strdup (str: "GtkPrintDialogExtension" ); |
716 | gtk_printer_option_set_add (set, option); |
717 | |
718 | if (n_formats > 1) |
719 | { |
720 | option = gtk_printer_option_new (name: "output-file-format" , _("_Output format" ), |
721 | type: GTK_PRINTER_OPTION_TYPE_ALTERNATIVE); |
722 | option->group = g_strdup (str: "GtkPrintDialogExtension" ); |
723 | |
724 | gtk_printer_option_choices_from_array (option, num_choices: n_formats, |
725 | choices: supported_formats, |
726 | choices_display: display_format_names); |
727 | gtk_printer_option_set (option, value: supported_formats[current_format]); |
728 | gtk_printer_option_set_add (set, option); |
729 | |
730 | set_printer_format_from_option_set (printer, set); |
731 | format_changed_data = g_new (_OutputFormatChangedData, 1); |
732 | format_changed_data->printer = printer; |
733 | format_changed_data->set = set; |
734 | g_signal_connect_data (instance: option, detailed_signal: "changed" , |
735 | G_CALLBACK (file_printer_output_file_format_changed), |
736 | data: format_changed_data, destroy_data: (GClosureNotify)g_free, connect_flags: 0); |
737 | |
738 | g_object_unref (object: option); |
739 | } |
740 | |
741 | return set; |
742 | } |
743 | |
744 | static void |
745 | file_printer_get_settings_from_options (GtkPrinter *printer, |
746 | GtkPrinterOptionSet *options, |
747 | GtkPrintSettings *settings) |
748 | { |
749 | GtkPrinterOption *option; |
750 | |
751 | option = gtk_printer_option_set_lookup (set: options, name: "gtk-main-page-custom-input" ); |
752 | gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_OUTPUT_URI, value: option->value); |
753 | |
754 | option = gtk_printer_option_set_lookup (set: options, name: "output-file-format" ); |
755 | if (option) |
756 | gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_OUTPUT_FILE_FORMAT, value: option->value); |
757 | |
758 | option = gtk_printer_option_set_lookup (set: options, name: "gtk-n-up" ); |
759 | if (option) |
760 | gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_NUMBER_UP, value: option->value); |
761 | |
762 | option = gtk_printer_option_set_lookup (set: options, name: "gtk-n-up-layout" ); |
763 | if (option) |
764 | gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_NUMBER_UP_LAYOUT, value: option->value); |
765 | } |
766 | |
767 | static void |
768 | file_printer_prepare_for_print (GtkPrinter *printer, |
769 | GtkPrintJob *print_job, |
770 | GtkPrintSettings *settings, |
771 | GtkPageSetup *page_setup) |
772 | { |
773 | double scale; |
774 | GtkPrintPages pages; |
775 | GtkPageRange *ranges; |
776 | int n_ranges; |
777 | OutputFormat format; |
778 | |
779 | pages = gtk_print_settings_get_print_pages (settings); |
780 | gtk_print_job_set_pages (job: print_job, pages); |
781 | |
782 | if (pages == GTK_PRINT_PAGES_RANGES) |
783 | ranges = gtk_print_settings_get_page_ranges (settings, num_ranges: &n_ranges); |
784 | else |
785 | { |
786 | ranges = NULL; |
787 | n_ranges = 0; |
788 | } |
789 | |
790 | gtk_print_job_set_page_ranges (job: print_job, ranges, n_ranges); |
791 | gtk_print_job_set_collate (job: print_job, collate: gtk_print_settings_get_collate (settings)); |
792 | gtk_print_job_set_reverse (job: print_job, reverse: gtk_print_settings_get_reverse (settings)); |
793 | gtk_print_job_set_num_copies (job: print_job, num_copies: gtk_print_settings_get_n_copies (settings)); |
794 | gtk_print_job_set_n_up (job: print_job, n_up: gtk_print_settings_get_number_up (settings)); |
795 | gtk_print_job_set_n_up_layout (job: print_job, layout: gtk_print_settings_get_number_up_layout (settings)); |
796 | |
797 | scale = gtk_print_settings_get_scale (settings); |
798 | if (scale != 100.0) |
799 | gtk_print_job_set_scale (job: print_job, scale: scale / 100.0); |
800 | |
801 | gtk_print_job_set_page_set (job: print_job, page_set: gtk_print_settings_get_page_set (settings)); |
802 | |
803 | format = format_from_settings (settings); |
804 | switch (format) |
805 | { |
806 | case FORMAT_PDF: |
807 | case N_FORMATS: |
808 | gtk_print_job_set_rotate (job: print_job, FALSE); |
809 | break; |
810 | default: |
811 | case FORMAT_PS: |
812 | case FORMAT_SVG: |
813 | gtk_print_job_set_rotate (job: print_job, TRUE); |
814 | break; |
815 | } |
816 | } |
817 | |
818 | static GList * |
819 | file_printer_list_papers (GtkPrinter *printer) |
820 | { |
821 | GList *result = NULL; |
822 | GList *papers, *p; |
823 | GtkPageSetup *page_setup; |
824 | |
825 | papers = gtk_paper_size_get_paper_sizes (FALSE); |
826 | |
827 | for (p = papers; p; p = p->next) |
828 | { |
829 | GtkPaperSize *paper_size = p->data; |
830 | |
831 | page_setup = gtk_page_setup_new (); |
832 | gtk_page_setup_set_paper_size (setup: page_setup, size: paper_size); |
833 | gtk_paper_size_free (size: paper_size); |
834 | result = g_list_prepend (list: result, data: page_setup); |
835 | } |
836 | |
837 | g_list_free (list: papers); |
838 | |
839 | return g_list_reverse (list: result); |
840 | } |
841 | |
842 | static GtkPageSetup * |
843 | file_printer_get_default_page_size (GtkPrinter *printer) |
844 | { |
845 | GtkPageSetup *result = NULL; |
846 | |
847 | return result; |
848 | } |
849 | |