1/* GTK - The GIMP Toolkit
2 * gtkprintoperation-unix.c: Print Operation Details for Unix
3 * and Unix-like platforms
4 * Copyright (C) 2006, 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#ifdef HAVE_UNISTD_H
22#include <unistd.h>
23#endif
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <string.h>
27#include <errno.h>
28#include <stdlib.h>
29#include <fcntl.h>
30
31#include <glib/gstdio.h>
32#include "gtkprintoperation-private.h"
33#include "gtkprintoperation-portal.h"
34#include "gtkmessagedialog.h"
35
36#include <cairo-pdf.h>
37#include <cairo-ps.h>
38#include "gtkprivate.h"
39#include "gtkprintunixdialog.h"
40#include "gtkpagesetupunixdialog.h"
41#include "gtkprintbackendprivate.h"
42#include "gtkprinter.h"
43#include "gtkprintjob.h"
44#include "gtklabel.h"
45#include "gtkintl.h"
46
47
48typedef struct
49{
50 GtkWindow *parent; /* just in case we need to throw error dialogs */
51 GMainLoop *loop;
52 gboolean data_sent;
53
54 /* Real printing (not preview) */
55 GtkPrintJob *job; /* the job we are sending to the printer */
56 cairo_surface_t *surface;
57 gulong job_status_changed_tag;
58
59
60} GtkPrintOperationUnix;
61
62typedef struct _PrinterFinder PrinterFinder;
63
64static void printer_finder_free (PrinterFinder *finder);
65static void find_printer (const char *printer,
66 GFunc func,
67 gpointer data);
68
69static void
70unix_start_page (GtkPrintOperation *op,
71 GtkPrintContext *print_context,
72 GtkPageSetup *page_setup)
73{
74 GtkPrintOperationUnix *op_unix;
75 GtkPaperSize *paper_size;
76 cairo_surface_type_t type;
77 double w, h;
78
79 op_unix = op->priv->platform_data;
80
81 paper_size = gtk_page_setup_get_paper_size (setup: page_setup);
82
83 w = gtk_paper_size_get_width (size: paper_size, unit: GTK_UNIT_POINTS);
84 h = gtk_paper_size_get_height (size: paper_size, unit: GTK_UNIT_POINTS);
85
86 type = cairo_surface_get_type (surface: op_unix->surface);
87
88 if ((op->priv->manual_number_up < 2) ||
89 (op->priv->page_position % op->priv->manual_number_up == 0))
90 {
91 if (type == CAIRO_SURFACE_TYPE_PS)
92 {
93 cairo_ps_surface_set_size (surface: op_unix->surface, width_in_points: w, height_in_points: h);
94 cairo_ps_surface_dsc_begin_page_setup (surface: op_unix->surface);
95 switch (gtk_page_setup_get_orientation (setup: page_setup))
96 {
97 case GTK_PAGE_ORIENTATION_PORTRAIT:
98 case GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT:
99 cairo_ps_surface_dsc_comment (surface: op_unix->surface, comment: "%%PageOrientation: Portrait");
100 break;
101
102 case GTK_PAGE_ORIENTATION_LANDSCAPE:
103 case GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE:
104 cairo_ps_surface_dsc_comment (surface: op_unix->surface, comment: "%%PageOrientation: Landscape");
105 break;
106 default:
107 break;
108 }
109 }
110 else if (type == CAIRO_SURFACE_TYPE_PDF)
111 {
112 if (!op->priv->manual_orientation)
113 {
114 w = gtk_page_setup_get_paper_width (setup: page_setup, unit: GTK_UNIT_POINTS);
115 h = gtk_page_setup_get_paper_height (setup: page_setup, unit: GTK_UNIT_POINTS);
116 }
117 cairo_pdf_surface_set_size (surface: op_unix->surface, width_in_points: w, height_in_points: h);
118 }
119 }
120}
121
122static void
123unix_end_page (GtkPrintOperation *op,
124 GtkPrintContext *print_context)
125{
126 cairo_t *cr;
127
128 cr = gtk_print_context_get_cairo_context (context: print_context);
129
130 if ((op->priv->manual_number_up < 2) ||
131 ((op->priv->page_position + 1) % op->priv->manual_number_up == 0) ||
132 (op->priv->page_position == op->priv->nr_of_pages_to_print - 1))
133 cairo_show_page (cr);
134}
135
136static void
137op_unix_free (GtkPrintOperationUnix *op_unix)
138{
139 if (op_unix->job)
140 {
141 if (op_unix->job_status_changed_tag > 0)
142 g_signal_handler_disconnect (instance: op_unix->job,
143 handler_id: op_unix->job_status_changed_tag);
144 g_object_unref (object: op_unix->job);
145 }
146
147 g_free (mem: op_unix);
148}
149
150static char *
151shell_command_substitute_file (const char *cmd,
152 const char *pdf_filename,
153 const char *settings_filename,
154 gboolean *pdf_filename_replaced,
155 gboolean *settings_filename_replaced)
156{
157 const char *inptr, *start;
158 GString *final;
159
160 g_return_val_if_fail (cmd != NULL, NULL);
161 g_return_val_if_fail (pdf_filename != NULL, NULL);
162 g_return_val_if_fail (settings_filename != NULL, NULL);
163
164 final = g_string_new (NULL);
165
166 *pdf_filename_replaced = FALSE;
167 *settings_filename_replaced = FALSE;
168
169 start = inptr = cmd;
170 while ((inptr = strchr (s: inptr, c: '%')) != NULL)
171 {
172 g_string_append_len (string: final, val: start, len: inptr - start);
173 inptr++;
174 switch (*inptr)
175 {
176 case 'f':
177 g_string_append (string: final, val: pdf_filename);
178 *pdf_filename_replaced = TRUE;
179 break;
180
181 case 's':
182 g_string_append (string: final, val: settings_filename);
183 *settings_filename_replaced = TRUE;
184 break;
185
186 case '%':
187 g_string_append_c (final, '%');
188 break;
189
190 default:
191 g_string_append_c (final, '%');
192 if (*inptr)
193 g_string_append_c (final, *inptr);
194 break;
195 }
196 if (*inptr)
197 inptr++;
198 start = inptr;
199 }
200 g_string_append (string: final, val: start);
201
202 return g_string_free (string: final, FALSE);
203}
204
205static void
206gtk_print_operation_unix_launch_preview (GtkPrintOperation *op,
207 cairo_surface_t *surface,
208 GtkWindow *parent,
209 const char *filename)
210{
211 GAppInfo *appinfo;
212 GdkAppLaunchContext *context;
213 char *cmd;
214 char *preview_cmd;
215 GtkSettings *settings;
216 GtkPrintSettings *print_settings = NULL;
217 GtkPageSetup *page_setup;
218 GKeyFile *key_file = NULL;
219 char *data = NULL;
220 gsize data_len;
221 char *settings_filename = NULL;
222 char *quoted_filename;
223 char *quoted_settings_filename;
224 gboolean filename_used = FALSE;
225 gboolean settings_used = FALSE;
226 GdkDisplay *display;
227 GError *error = NULL;
228 int fd;
229 gboolean retval;
230
231 cairo_surface_destroy (surface);
232
233 if (parent)
234 display = gtk_widget_get_display (GTK_WIDGET (parent));
235 else
236 display = gdk_display_get_default ();
237
238 fd = g_file_open_tmp (tmpl: "settingsXXXXXX.ini", name_used: &settings_filename, error: &error);
239 if (fd < 0)
240 goto out;
241
242 key_file = g_key_file_new ();
243
244 print_settings = gtk_print_settings_copy (other: gtk_print_operation_get_print_settings (op));
245
246 if (print_settings != NULL)
247 {
248 gtk_print_settings_set_reverse (settings: print_settings, FALSE);
249 gtk_print_settings_set_page_set (settings: print_settings, page_set: GTK_PAGE_SET_ALL);
250 gtk_print_settings_set_scale (settings: print_settings, scale: 1.0);
251 gtk_print_settings_set_number_up (settings: print_settings, number_up: 1);
252 gtk_print_settings_set_number_up_layout (settings: print_settings, number_up_layout: GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM);
253
254 /* These removals are necessary because cups-* settings have higher priority
255 * than normal settings.
256 */
257 gtk_print_settings_unset (settings: print_settings, key: "cups-reverse");
258 gtk_print_settings_unset (settings: print_settings, key: "cups-page-set");
259 gtk_print_settings_unset (settings: print_settings, key: "cups-scale");
260 gtk_print_settings_unset (settings: print_settings, key: "cups-number-up");
261 gtk_print_settings_unset (settings: print_settings, key: "cups-number-up-layout");
262
263 gtk_print_settings_to_key_file (settings: print_settings, key_file, NULL);
264 g_object_unref (object: print_settings);
265 }
266
267 page_setup = gtk_print_context_get_page_setup (context: op->priv->print_context);
268 gtk_page_setup_to_key_file (setup: page_setup, key_file, NULL);
269
270 g_key_file_set_string (key_file, group_name: "Print Job", key: "title", string: op->priv->job_name);
271
272 data = g_key_file_to_data (key_file, length: &data_len, error: &error);
273 if (!data)
274 goto out;
275
276 retval = g_file_set_contents (filename: settings_filename, contents: data, length: data_len, error: &error);
277 if (!retval)
278 goto out;
279
280 settings = gtk_settings_get_for_display (display);
281 g_object_get (object: settings, first_property_name: "gtk-print-preview-command", &preview_cmd, NULL);
282
283 quoted_filename = g_shell_quote (unquoted_string: filename);
284 quoted_settings_filename = g_shell_quote (unquoted_string: settings_filename);
285 cmd = shell_command_substitute_file (cmd: preview_cmd, pdf_filename: quoted_filename, settings_filename: quoted_settings_filename, pdf_filename_replaced: &filename_used, settings_filename_replaced: &settings_used);
286
287 appinfo = g_app_info_create_from_commandline (commandline: cmd,
288 application_name: "Print Preview",
289 flags: G_APP_INFO_CREATE_NONE,
290 error: &error);
291
292 g_free (mem: preview_cmd);
293 g_free (mem: quoted_filename);
294 g_free (mem: quoted_settings_filename);
295 g_free (mem: cmd);
296
297 if (error != NULL)
298 goto out;
299
300 context = gdk_display_get_app_launch_context (display);
301 g_app_info_launch (appinfo, NULL, G_APP_LAUNCH_CONTEXT (context), error: &error);
302
303 g_object_unref (object: context);
304 g_object_unref (object: appinfo);
305
306 if (error != NULL)
307 {
308 char * uri;
309
310 g_warning ("Error launching preview: %s", error->message);
311
312 g_error_free (error);
313 error = NULL;
314 uri = g_filename_to_uri (filename, NULL, NULL);
315 gtk_show_uri (parent, uri, GDK_CURRENT_TIME);
316 g_free (mem: uri);
317 }
318
319 out:
320 if (error != NULL)
321 {
322 if (op->priv->error == NULL)
323 op->priv->error = error;
324 else
325 g_error_free (error);
326
327 filename_used = FALSE;
328 settings_used = FALSE;
329 }
330
331 if (!filename_used)
332 g_unlink (filename);
333
334 if (!settings_used)
335 g_unlink (filename: settings_filename);
336
337 if (fd > 0)
338 close (fd: fd);
339
340 if (key_file)
341 g_key_file_free (key_file);
342 g_free (mem: data);
343 g_free (mem: settings_filename);
344}
345
346static void
347unix_finish_send (GtkPrintJob *job,
348 gpointer user_data,
349 const GError *error)
350{
351 GtkPrintOperation *op = (GtkPrintOperation *) user_data;
352 GtkPrintOperationUnix *op_unix = op->priv->platform_data;
353
354 if (error != NULL && op->priv->error == NULL)
355 op->priv->error = g_error_copy (error);
356
357 op_unix->data_sent = TRUE;
358
359 if (op_unix->loop)
360 g_main_loop_quit (loop: op_unix->loop);
361
362 g_object_unref (object: op);
363}
364
365static void
366unix_end_run (GtkPrintOperation *op,
367 gboolean wait,
368 gboolean cancelled)
369{
370 GtkPrintOperationUnix *op_unix = op->priv->platform_data;
371
372 cairo_surface_finish (surface: op_unix->surface);
373
374 if (cancelled)
375 return;
376
377 if (wait)
378 op_unix->loop = g_main_loop_new (NULL, FALSE);
379
380 /* TODO: Check for error */
381 if (op_unix->job != NULL)
382 {
383 g_object_ref (op);
384 gtk_print_job_send (job: op_unix->job,
385 callback: unix_finish_send,
386 user_data: op, NULL);
387 }
388
389 if (wait)
390 {
391 g_object_ref (op);
392 if (!op_unix->data_sent)
393 g_main_loop_run (loop: op_unix->loop);
394 g_main_loop_unref (loop: op_unix->loop);
395 op_unix->loop = NULL;
396 g_object_unref (object: op);
397 }
398}
399
400static void
401job_status_changed_cb (GtkPrintJob *job,
402 GtkPrintOperation *op)
403{
404 _gtk_print_operation_set_status (op, status: gtk_print_job_get_status (job), NULL);
405}
406
407
408static void
409print_setup_changed_cb (GtkPrintUnixDialog *print_dialog,
410 GParamSpec *pspec,
411 gpointer user_data)
412{
413 GtkPageSetup *page_setup;
414 GtkPrintSettings *print_settings;
415 GtkPrintOperation *op = user_data;
416 GtkPrintOperationPrivate *priv = op->priv;
417
418 page_setup = gtk_print_unix_dialog_get_page_setup (dialog: print_dialog);
419 print_settings = gtk_print_unix_dialog_get_settings (dialog: print_dialog);
420
421 g_signal_emit_by_name (instance: op,
422 detailed_signal: "update-custom-widget",
423 priv->custom_widget,
424 page_setup,
425 print_settings);
426}
427
428static GtkWidget *
429get_print_dialog (GtkPrintOperation *op,
430 GtkWindow *parent)
431{
432 GtkPrintOperationPrivate *priv = op->priv;
433 GtkWidget *pd, *label;
434 const char *custom_tab_label;
435
436 pd = gtk_print_unix_dialog_new (NULL, parent);
437
438 gtk_print_unix_dialog_set_manual_capabilities (GTK_PRINT_UNIX_DIALOG (pd),
439 capabilities: GTK_PRINT_CAPABILITY_PAGE_SET |
440 GTK_PRINT_CAPABILITY_COPIES |
441 GTK_PRINT_CAPABILITY_COLLATE |
442 GTK_PRINT_CAPABILITY_REVERSE |
443 GTK_PRINT_CAPABILITY_SCALE |
444 GTK_PRINT_CAPABILITY_PREVIEW |
445 GTK_PRINT_CAPABILITY_NUMBER_UP |
446 GTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT);
447
448 if (priv->print_settings)
449 gtk_print_unix_dialog_set_settings (GTK_PRINT_UNIX_DIALOG (pd),
450 settings: priv->print_settings);
451
452 if (priv->default_page_setup)
453 gtk_print_unix_dialog_set_page_setup (GTK_PRINT_UNIX_DIALOG (pd),
454 page_setup: priv->default_page_setup);
455
456 gtk_print_unix_dialog_set_embed_page_setup (GTK_PRINT_UNIX_DIALOG (pd),
457 embed: priv->embed_page_setup);
458
459 gtk_print_unix_dialog_set_current_page (GTK_PRINT_UNIX_DIALOG (pd),
460 current_page: priv->current_page);
461
462 gtk_print_unix_dialog_set_support_selection (GTK_PRINT_UNIX_DIALOG (pd),
463 support_selection: priv->support_selection);
464
465 gtk_print_unix_dialog_set_has_selection (GTK_PRINT_UNIX_DIALOG (pd),
466 has_selection: priv->has_selection);
467
468 g_signal_emit_by_name (instance: op, detailed_signal: "create-custom-widget",
469 &priv->custom_widget);
470
471 if (priv->custom_widget)
472 {
473 custom_tab_label = priv->custom_tab_label;
474
475 if (custom_tab_label == NULL)
476 {
477 custom_tab_label = g_get_application_name ();
478 if (custom_tab_label == NULL)
479 custom_tab_label = _("Application");
480 }
481
482 label = gtk_label_new (str: custom_tab_label);
483
484 gtk_print_unix_dialog_add_custom_tab (GTK_PRINT_UNIX_DIALOG (pd),
485 child: priv->custom_widget, tab_label: label);
486
487 g_signal_connect (pd, "notify::selected-printer", (GCallback) print_setup_changed_cb, op);
488 g_signal_connect (pd, "notify::page-setup", (GCallback) print_setup_changed_cb, op);
489 }
490
491 return pd;
492}
493
494typedef struct
495{
496 GtkPrintOperation *op;
497 gboolean do_print;
498 gboolean do_preview;
499 GtkPrintOperationResult result;
500 GtkPrintOperationPrintFunc print_cb;
501 GDestroyNotify destroy;
502 GtkWindow *parent;
503 GMainLoop *loop;
504} PrintResponseData;
505
506static void
507print_response_data_free (gpointer data)
508{
509 PrintResponseData *rdata = data;
510
511 g_object_unref (object: rdata->op);
512 g_free (mem: rdata);
513}
514
515static void
516finish_print (PrintResponseData *rdata,
517 GtkPrinter *printer,
518 GtkPageSetup *page_setup,
519 GtkPrintSettings *settings,
520 gboolean page_setup_set)
521{
522 GtkPrintOperation *op = rdata->op;
523 GtkPrintOperationPrivate *priv = op->priv;
524 GtkPrintJob *job;
525 double top, bottom, left, right;
526
527 if (rdata->do_print)
528 {
529 gtk_print_operation_set_print_settings (op, print_settings: settings);
530 priv->print_context = _gtk_print_context_new (op);
531
532 if (gtk_print_settings_get_number_up (settings) < 2)
533 {
534 if (printer && (gtk_printer_get_hard_margins_for_paper_size (printer, paper_size: gtk_page_setup_get_paper_size (setup: page_setup), top: &top, bottom: &bottom, left: &left, right: &right) ||
535 gtk_printer_get_hard_margins (printer, top: &top, bottom: &bottom, left: &left, right: &right)))
536 _gtk_print_context_set_hard_margins (context: priv->print_context, top, bottom, left, right);
537 }
538 else
539 {
540 /* Pages do not have any unprintable area when printing n-up as each page on the
541 * sheet has been scaled down and translated to a position within the printable
542 * area of the sheet.
543 */
544 _gtk_print_context_set_hard_margins (context: priv->print_context, top: 0, bottom: 0, left: 0, right: 0);
545 }
546
547 if (page_setup != NULL &&
548 (gtk_print_operation_get_default_page_setup (op) == NULL ||
549 page_setup_set))
550 gtk_print_operation_set_default_page_setup (op, default_page_setup: page_setup);
551
552 _gtk_print_context_set_page_setup (context: priv->print_context, page_setup);
553
554 if (!rdata->do_preview)
555 {
556 GtkPrintOperationUnix *op_unix;
557 cairo_t *cr;
558
559 op_unix = g_new0 (GtkPrintOperationUnix, 1);
560 priv->platform_data = op_unix;
561 priv->free_platform_data = (GDestroyNotify) op_unix_free;
562 op_unix->parent = rdata->parent;
563
564 priv->start_page = unix_start_page;
565 priv->end_page = unix_end_page;
566 priv->end_run = unix_end_run;
567
568 job = gtk_print_job_new (title: priv->job_name, printer, settings, page_setup);
569 op_unix->job = job;
570 gtk_print_job_set_track_print_status (job, track_status: priv->track_print_status);
571
572 op_unix->surface = gtk_print_job_get_surface (job, error: &priv->error);
573 if (op_unix->surface == NULL)
574 {
575 rdata->result = GTK_PRINT_OPERATION_RESULT_ERROR;
576 rdata->do_print = FALSE;
577 goto out;
578 }
579
580 cr = cairo_create (target: op_unix->surface);
581 gtk_print_context_set_cairo_context (context: priv->print_context, cr, dpi_x: 72, dpi_y: 72);
582 cairo_destroy (cr);
583
584 _gtk_print_operation_set_status (op, status: gtk_print_job_get_status (job), NULL);
585
586 op_unix->job_status_changed_tag =
587 g_signal_connect (job, "status-changed",
588 G_CALLBACK (job_status_changed_cb), op);
589
590 priv->print_pages = gtk_print_job_get_pages (job);
591 priv->page_ranges = gtk_print_job_get_page_ranges (job, n_ranges: &priv->num_page_ranges);
592 priv->manual_num_copies = gtk_print_job_get_num_copies (job);
593 priv->manual_collation = gtk_print_job_get_collate (job);
594 priv->manual_reverse = gtk_print_job_get_reverse (job);
595 priv->manual_page_set = gtk_print_job_get_page_set (job);
596 priv->manual_scale = gtk_print_job_get_scale (job);
597 priv->manual_orientation = gtk_print_job_get_rotate (job);
598 priv->manual_number_up = gtk_print_job_get_n_up (job);
599 priv->manual_number_up_layout = gtk_print_job_get_n_up_layout (job);
600 }
601 }
602 out:
603 if (rdata->print_cb)
604 rdata->print_cb (op, rdata->parent, rdata->do_print, rdata->result);
605
606 if (rdata->destroy)
607 rdata->destroy (rdata);
608}
609
610static void
611handle_print_response (GtkWidget *dialog,
612 int response,
613 gpointer data)
614{
615 GtkPrintUnixDialog *pd = GTK_PRINT_UNIX_DIALOG (dialog);
616 PrintResponseData *rdata = data;
617 GtkPrintSettings *settings = NULL;
618 GtkPageSetup *page_setup = NULL;
619 GtkPrinter *printer = NULL;
620 gboolean page_setup_set = FALSE;
621
622 if (response == GTK_RESPONSE_OK)
623 {
624 printer = gtk_print_unix_dialog_get_selected_printer (GTK_PRINT_UNIX_DIALOG (pd));
625
626 rdata->result = GTK_PRINT_OPERATION_RESULT_APPLY;
627 rdata->do_preview = FALSE;
628 if (printer != NULL)
629 rdata->do_print = TRUE;
630 }
631 else if (response == GTK_RESPONSE_APPLY)
632 {
633 /* print preview */
634 rdata->result = GTK_PRINT_OPERATION_RESULT_APPLY;
635 rdata->do_preview = TRUE;
636 rdata->do_print = TRUE;
637
638 rdata->op->priv->action = GTK_PRINT_OPERATION_ACTION_PREVIEW;
639 }
640
641 if (rdata->do_print)
642 {
643 settings = gtk_print_unix_dialog_get_settings (GTK_PRINT_UNIX_DIALOG (pd));
644 page_setup = gtk_print_unix_dialog_get_page_setup (GTK_PRINT_UNIX_DIALOG (pd));
645 page_setup_set = gtk_print_unix_dialog_get_page_setup_set (GTK_PRINT_UNIX_DIALOG (pd));
646
647 /* Set new print settings now so that custom-widget options
648 * can be added to the settings in the callback
649 */
650 gtk_print_operation_set_print_settings (op: rdata->op, print_settings: settings);
651 g_signal_emit_by_name (instance: rdata->op, detailed_signal: "custom-widget-apply", rdata->op->priv->custom_widget);
652 }
653
654 if (rdata->loop)
655 g_main_loop_quit (loop: rdata->loop);
656
657 finish_print (rdata, printer, page_setup, settings, page_setup_set);
658
659 if (settings)
660 g_object_unref (object: settings);
661
662 gtk_window_destroy (GTK_WINDOW (pd));
663}
664
665
666static void
667found_printer (GtkPrinter *printer,
668 PrintResponseData *rdata)
669{
670 GtkPrintOperation *op = rdata->op;
671 GtkPrintOperationPrivate *priv = op->priv;
672 GtkPrintSettings *settings = NULL;
673 GtkPageSetup *page_setup = NULL;
674
675 if (rdata->loop)
676 g_main_loop_quit (loop: rdata->loop);
677
678 if (printer != NULL)
679 {
680 rdata->result = GTK_PRINT_OPERATION_RESULT_APPLY;
681
682 rdata->do_print = TRUE;
683
684 if (priv->print_settings)
685 settings = gtk_print_settings_copy (other: priv->print_settings);
686 else
687 settings = gtk_print_settings_new ();
688
689 gtk_print_settings_set_printer (settings,
690 printer: gtk_printer_get_name (printer));
691
692 if (priv->default_page_setup)
693 page_setup = gtk_page_setup_copy (other: priv->default_page_setup);
694 else
695 page_setup = gtk_page_setup_new ();
696 }
697
698 finish_print (rdata, printer, page_setup, settings, FALSE);
699
700 if (settings)
701 g_object_unref (object: settings);
702
703 if (page_setup)
704 g_object_unref (object: page_setup);
705}
706
707static void
708gtk_print_operation_unix_run_dialog_async (GtkPrintOperation *op,
709 gboolean show_dialog,
710 GtkWindow *parent,
711 GtkPrintOperationPrintFunc print_cb)
712{
713 GtkWidget *pd;
714 PrintResponseData *rdata;
715 const char *printer_name;
716
717 rdata = g_new (PrintResponseData, 1);
718 rdata->op = g_object_ref (op);
719 rdata->do_print = FALSE;
720 rdata->do_preview = FALSE;
721 rdata->result = GTK_PRINT_OPERATION_RESULT_CANCEL;
722 rdata->print_cb = print_cb;
723 rdata->parent = parent;
724 rdata->loop = NULL;
725 rdata->destroy = print_response_data_free;
726
727 if (show_dialog)
728 {
729 pd = get_print_dialog (op, parent);
730 gtk_window_set_modal (GTK_WINDOW (pd), TRUE);
731
732 g_signal_connect (pd, "response",
733 G_CALLBACK (handle_print_response), rdata);
734
735 gtk_window_present (GTK_WINDOW (pd));
736 }
737 else
738 {
739 printer_name = NULL;
740 if (op->priv->print_settings)
741 printer_name = gtk_print_settings_get_printer (settings: op->priv->print_settings);
742
743 find_printer (printer: printer_name, func: (GFunc) found_printer, data: rdata);
744 }
745}
746
747static cairo_status_t
748write_preview (void *closure,
749 const unsigned char *data,
750 unsigned int length)
751{
752 int fd = GPOINTER_TO_INT (closure);
753 gssize written;
754
755 while (length > 0)
756 {
757 written = write (fd: fd, buf: data, n: length);
758
759 if (written == -1)
760 {
761 if (errno == EAGAIN || errno == EINTR)
762 continue;
763
764 return CAIRO_STATUS_WRITE_ERROR;
765 }
766
767 data += written;
768 length -= written;
769 }
770
771 return CAIRO_STATUS_SUCCESS;
772}
773
774static void
775close_preview (void *data)
776{
777 int fd = GPOINTER_TO_INT (data);
778
779 close (fd: fd);
780}
781
782static cairo_surface_t *
783gtk_print_operation_unix_create_preview_surface (GtkPrintOperation *op,
784 GtkPageSetup *page_setup,
785 double *dpi_x,
786 double *dpi_y,
787 char **target)
788{
789 char *filename;
790 int fd;
791 GtkPaperSize *paper_size;
792 double w, h;
793 cairo_surface_t *surface;
794 static cairo_user_data_key_t key;
795
796 filename = g_build_filename (first_element: g_get_tmp_dir (), "previewXXXXXX.pdf", NULL);
797 fd = g_mkstemp (tmpl: filename);
798
799 if (fd < 0)
800 {
801 g_free (mem: filename);
802 return NULL;
803 }
804
805 *target = filename;
806
807 paper_size = gtk_page_setup_get_paper_size (setup: page_setup);
808 w = gtk_paper_size_get_width (size: paper_size, unit: GTK_UNIT_POINTS);
809 h = gtk_paper_size_get_height (size: paper_size, unit: GTK_UNIT_POINTS);
810
811 *dpi_x = *dpi_y = 72;
812 surface = cairo_pdf_surface_create_for_stream (write_func: write_preview, GINT_TO_POINTER (fd), width_in_points: w, height_in_points: h);
813
814 cairo_surface_set_user_data (surface, key: &key, GINT_TO_POINTER (fd), destroy: close_preview);
815
816 return surface;
817}
818
819static void
820gtk_print_operation_unix_preview_start_page (GtkPrintOperation *op,
821 cairo_surface_t *surface,
822 cairo_t *cr)
823{
824}
825
826static void
827gtk_print_operation_unix_preview_end_page (GtkPrintOperation *op,
828 cairo_surface_t *surface,
829 cairo_t *cr)
830{
831 cairo_show_page (cr);
832}
833
834static void
835gtk_print_operation_unix_resize_preview_surface (GtkPrintOperation *op,
836 GtkPageSetup *page_setup,
837 cairo_surface_t *surface)
838{
839 double w, h;
840
841 w = gtk_page_setup_get_paper_width (setup: page_setup, unit: GTK_UNIT_POINTS);
842 h = gtk_page_setup_get_paper_height (setup: page_setup, unit: GTK_UNIT_POINTS);
843 cairo_pdf_surface_set_size (surface, width_in_points: w, height_in_points: h);
844}
845
846static GtkPrintOperationResult
847gtk_print_operation_unix_run_dialog (GtkPrintOperation *op,
848 gboolean show_dialog,
849 GtkWindow *parent,
850 gboolean *do_print)
851 {
852 GtkWidget *pd;
853 PrintResponseData rdata;
854 const char *printer_name;
855
856 rdata.op = op;
857 rdata.do_print = FALSE;
858 rdata.do_preview = FALSE;
859 rdata.result = GTK_PRINT_OPERATION_RESULT_CANCEL;
860 rdata.print_cb = NULL;
861 rdata.destroy = NULL;
862 rdata.parent = parent;
863 rdata.loop = NULL;
864
865 if (show_dialog)
866 {
867 pd = get_print_dialog (op, parent);
868 gtk_window_set_modal (GTK_WINDOW (pd), TRUE);
869
870 g_signal_connect (pd, "response",
871 G_CALLBACK (handle_print_response), &rdata);
872
873 gtk_window_present (GTK_WINDOW (pd));
874
875 rdata.loop = g_main_loop_new (NULL, FALSE);
876 g_main_loop_run (loop: rdata.loop);
877 g_main_loop_unref (loop: rdata.loop);
878 rdata.loop = NULL;
879 }
880 else
881 {
882 printer_name = NULL;
883 if (op->priv->print_settings)
884 printer_name = gtk_print_settings_get_printer (settings: op->priv->print_settings);
885
886 rdata.loop = g_main_loop_new (NULL, FALSE);
887 find_printer (printer: printer_name,
888 func: (GFunc) found_printer, data: &rdata);
889
890 g_main_loop_run (loop: rdata.loop);
891 g_main_loop_unref (loop: rdata.loop);
892 rdata.loop = NULL;
893 }
894
895 *do_print = rdata.do_print;
896
897 return rdata.result;
898}
899
900
901typedef struct
902{
903 GtkPageSetup *page_setup;
904 GtkPageSetupDoneFunc done_cb;
905 gpointer data;
906 GDestroyNotify destroy;
907 GMainLoop *loop;
908} PageSetupResponseData;
909
910static void
911page_setup_data_free (gpointer data)
912{
913 PageSetupResponseData *rdata = data;
914
915 if (rdata->page_setup)
916 g_object_unref (object: rdata->page_setup);
917
918 g_free (mem: rdata);
919}
920
921static void
922handle_page_setup_response (GtkWidget *dialog,
923 int response,
924 gpointer data)
925{
926 GtkPageSetupUnixDialog *psd;
927 PageSetupResponseData *rdata = data;
928
929 if (rdata->loop)
930 g_main_loop_quit (loop: rdata->loop);
931
932 psd = GTK_PAGE_SETUP_UNIX_DIALOG (dialog);
933 if (response == GTK_RESPONSE_OK)
934 rdata->page_setup = gtk_page_setup_unix_dialog_get_page_setup (dialog: psd);
935
936 gtk_window_destroy (GTK_WINDOW (dialog));
937
938 if (rdata->done_cb)
939 rdata->done_cb (rdata->page_setup, rdata->data);
940
941 if (rdata->destroy)
942 rdata->destroy (rdata);
943}
944
945static GtkWidget *
946get_page_setup_dialog (GtkWindow *parent,
947 GtkPageSetup *page_setup,
948 GtkPrintSettings *settings)
949{
950 GtkWidget *dialog;
951
952 dialog = gtk_page_setup_unix_dialog_new (NULL, parent);
953 if (page_setup)
954 gtk_page_setup_unix_dialog_set_page_setup (GTK_PAGE_SETUP_UNIX_DIALOG (dialog),
955 page_setup);
956 gtk_page_setup_unix_dialog_set_print_settings (GTK_PAGE_SETUP_UNIX_DIALOG (dialog),
957 print_settings: settings);
958
959 return dialog;
960}
961
962/**
963 * gtk_print_run_page_setup_dialog:
964 * @parent: (nullable): transient parent
965 * @page_setup: (nullable): an existing `GtkPageSetup`
966 * @settings: a `GtkPrintSettings`
967 *
968 * Runs a page setup dialog, letting the user modify the values from
969 * @page_setup. If the user cancels the dialog, the returned `GtkPageSetup`
970 * is identical to the passed in @page_setup, otherwise it contains the
971 * modifications done in the dialog.
972 *
973 * Note that this function may use a recursive mainloop to show the page
974 * setup dialog. See gtk_print_run_page_setup_dialog_async() if this is
975 * a problem.
976 *
977 * Returns: (transfer full): a new `GtkPageSetup`
978 */
979GtkPageSetup *
980gtk_print_run_page_setup_dialog (GtkWindow *parent,
981 GtkPageSetup *page_setup,
982 GtkPrintSettings *settings)
983{
984 GtkWidget *dialog;
985 PageSetupResponseData rdata;
986
987 rdata.page_setup = NULL;
988 rdata.done_cb = NULL;
989 rdata.data = NULL;
990 rdata.destroy = NULL;
991 rdata.loop = g_main_loop_new (NULL, FALSE);
992
993 dialog = get_page_setup_dialog (parent, page_setup, settings);
994
995 g_signal_connect (dialog, "response",
996 G_CALLBACK (handle_page_setup_response),
997 &rdata);
998
999 gtk_window_present (GTK_WINDOW (dialog));
1000
1001 g_main_loop_run (loop: rdata.loop);
1002 g_main_loop_unref (loop: rdata.loop);
1003 rdata.loop = NULL;
1004
1005 if (rdata.page_setup)
1006 return rdata.page_setup;
1007 else if (page_setup)
1008 return gtk_page_setup_copy (other: page_setup);
1009 else
1010 return gtk_page_setup_new ();
1011}
1012
1013/**
1014 * gtk_print_run_page_setup_dialog_async:
1015 * @parent: (nullable): transient parent
1016 * @page_setup: (nullable): an existing `GtkPageSetup`
1017 * @settings: a `GtkPrintSettings`
1018 * @done_cb: (scope async): a function to call when the user saves
1019 * the modified page setup
1020 * @data: user data to pass to @done_cb
1021 *
1022 * Runs a page setup dialog, letting the user modify the values from @page_setup.
1023 *
1024 * In contrast to gtk_print_run_page_setup_dialog(), this function returns after
1025 * showing the page setup dialog on platforms that support this, and calls @done_cb
1026 * from a signal handler for the ::response signal of the dialog.
1027 */
1028void
1029gtk_print_run_page_setup_dialog_async (GtkWindow *parent,
1030 GtkPageSetup *page_setup,
1031 GtkPrintSettings *settings,
1032 GtkPageSetupDoneFunc done_cb,
1033 gpointer data)
1034{
1035 GtkWidget *dialog;
1036 PageSetupResponseData *rdata;
1037
1038 dialog = get_page_setup_dialog (parent, page_setup, settings);
1039 gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
1040
1041 rdata = g_new (PageSetupResponseData, 1);
1042 rdata->page_setup = NULL;
1043 rdata->done_cb = done_cb;
1044 rdata->data = data;
1045 rdata->destroy = page_setup_data_free;
1046 rdata->loop = NULL;
1047
1048 g_signal_connect (dialog, "response",
1049 G_CALLBACK (handle_page_setup_response), rdata);
1050
1051 gtk_window_present (GTK_WINDOW (dialog));
1052 }
1053
1054struct _PrinterFinder
1055{
1056 gboolean found_printer;
1057 GFunc func;
1058 gpointer data;
1059 char *printer_name;
1060 GList *backends;
1061 guint timeout_tag;
1062 GtkPrinter *printer;
1063 GtkPrinter *default_printer;
1064 GtkPrinter *first_printer;
1065};
1066
1067static gboolean
1068find_printer_idle (gpointer data)
1069{
1070 PrinterFinder *finder = data;
1071 GtkPrinter *printer;
1072
1073 if (finder->printer != NULL)
1074 printer = finder->printer;
1075 else if (finder->default_printer != NULL)
1076 printer = finder->default_printer;
1077 else if (finder->first_printer != NULL)
1078 printer = finder->first_printer;
1079 else
1080 printer = NULL;
1081
1082 finder->func (printer, finder->data);
1083
1084 printer_finder_free (finder);
1085
1086 return G_SOURCE_REMOVE;
1087}
1088
1089static void
1090printer_added_cb (GtkPrintBackend *backend,
1091 GtkPrinter *printer,
1092 PrinterFinder *finder)
1093{
1094 if (finder->found_printer)
1095 return;
1096
1097 /* FIXME this skips "Print to PDF" - is this intentional ? */
1098 if (gtk_printer_is_virtual (printer))
1099 return;
1100
1101 if (finder->printer_name != NULL &&
1102 strcmp (s1: gtk_printer_get_name (printer), s2: finder->printer_name) == 0)
1103 {
1104 finder->printer = g_object_ref (printer);
1105 finder->found_printer = TRUE;
1106 }
1107 else if (finder->default_printer == NULL &&
1108 gtk_printer_is_default (printer))
1109 {
1110 finder->default_printer = g_object_ref (printer);
1111 if (finder->printer_name == NULL)
1112 finder->found_printer = TRUE;
1113 }
1114 else
1115 {
1116 if (finder->first_printer == NULL)
1117 finder->first_printer = g_object_ref (printer);
1118 }
1119
1120 if (finder->found_printer)
1121 g_idle_add (function: find_printer_idle, data: finder);
1122}
1123
1124static void
1125printer_list_done_cb (GtkPrintBackend *backend,
1126 PrinterFinder *finder)
1127{
1128 finder->backends = g_list_remove (list: finder->backends, data: backend);
1129
1130 g_signal_handlers_disconnect_by_func (backend, printer_added_cb, finder);
1131 g_signal_handlers_disconnect_by_func (backend, printer_list_done_cb, finder);
1132
1133 gtk_print_backend_destroy (print_backend: backend);
1134 g_object_unref (object: backend);
1135
1136 if (finder->backends == NULL)
1137 g_idle_add (function: find_printer_idle, data: finder);
1138}
1139
1140static void
1141find_printer_init (PrinterFinder *finder,
1142 GtkPrintBackend *backend)
1143{
1144 GList *list;
1145 GList *node;
1146
1147 list = gtk_print_backend_get_printer_list (print_backend: backend);
1148
1149 node = list;
1150 while (node != NULL)
1151 {
1152 printer_added_cb (backend, printer: node->data, finder);
1153 node = node->next;
1154
1155 if (finder->found_printer)
1156 break;
1157 }
1158
1159 g_list_free (list);
1160
1161 if (gtk_print_backend_printer_list_is_done (print_backend: backend))
1162 {
1163 finder->backends = g_list_remove (list: finder->backends, data: backend);
1164 gtk_print_backend_destroy (print_backend: backend);
1165 g_object_unref (object: backend);
1166 }
1167 else
1168 {
1169 g_signal_connect (backend, "printer-added",
1170 (GCallback) printer_added_cb,
1171 finder);
1172 g_signal_connect (backend, "printer-list-done",
1173 (GCallback) printer_list_done_cb,
1174 finder);
1175 }
1176
1177}
1178
1179static void
1180printer_finder_free (PrinterFinder *finder)
1181{
1182 GList *l;
1183
1184 g_free (mem: finder->printer_name);
1185
1186 if (finder->printer)
1187 g_object_unref (object: finder->printer);
1188
1189 if (finder->default_printer)
1190 g_object_unref (object: finder->default_printer);
1191
1192 if (finder->first_printer)
1193 g_object_unref (object: finder->first_printer);
1194
1195 for (l = finder->backends; l != NULL; l = l->next)
1196 {
1197 GtkPrintBackend *backend = l->data;
1198 g_signal_handlers_disconnect_by_func (backend, printer_added_cb, finder);
1199 g_signal_handlers_disconnect_by_func (backend, printer_list_done_cb, finder);
1200 gtk_print_backend_destroy (print_backend: backend);
1201 g_object_unref (object: backend);
1202 }
1203
1204 g_list_free (list: finder->backends);
1205
1206 g_free (mem: finder);
1207}
1208
1209static void
1210find_printer (const char *printer,
1211 GFunc func,
1212 gpointer data)
1213{
1214 GList *node, *next;
1215 PrinterFinder *finder;
1216
1217 finder = g_new0 (PrinterFinder, 1);
1218
1219 finder->printer_name = g_strdup (str: printer);
1220 finder->func = func;
1221 finder->data = data;
1222
1223 finder->backends = NULL;
1224 if (g_module_supported ())
1225 finder->backends = gtk_print_backend_load_modules ();
1226
1227 for (node = finder->backends; !finder->found_printer && node != NULL; node = next)
1228 {
1229 next = node->next;
1230 find_printer_init (finder, GTK_PRINT_BACKEND (node->data));
1231 }
1232
1233 if (finder->backends == NULL)
1234 g_idle_add (function: find_printer_idle, data: finder);
1235}
1236
1237
1238GtkPrintOperationResult
1239_gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op,
1240 gboolean show_dialog,
1241 GtkWindow *parent,
1242 gboolean *do_print)
1243{
1244 if (gdk_should_use_portal ())
1245 return gtk_print_operation_portal_run_dialog (op, show_dialog, parent, do_print);
1246 else
1247 return gtk_print_operation_unix_run_dialog (op, show_dialog, parent, do_print);
1248}
1249void
1250_gtk_print_operation_platform_backend_run_dialog_async (GtkPrintOperation *op,
1251 gboolean show_dialog,
1252 GtkWindow *parent,
1253 GtkPrintOperationPrintFunc print_cb)
1254{
1255 if (gdk_should_use_portal ())
1256 gtk_print_operation_portal_run_dialog_async (op, show_dialog, parent, print_cb);
1257 else
1258 gtk_print_operation_unix_run_dialog_async (op, show_dialog, parent, print_cb);
1259}
1260
1261void
1262_gtk_print_operation_platform_backend_launch_preview (GtkPrintOperation *op,
1263 cairo_surface_t *surface,
1264 GtkWindow *parent,
1265 const char *filename)
1266{
1267 if (gdk_should_use_portal ())
1268 gtk_print_operation_portal_launch_preview (op, surface, parent, filename);
1269 else
1270 gtk_print_operation_unix_launch_preview (op, surface, parent, filename);
1271}
1272
1273cairo_surface_t *
1274_gtk_print_operation_platform_backend_create_preview_surface (GtkPrintOperation *op,
1275 GtkPageSetup *page_setup,
1276 double *dpi_x,
1277 double *dpi_y,
1278 char **target)
1279{
1280 return gtk_print_operation_unix_create_preview_surface (op, page_setup, dpi_x, dpi_y, target);
1281}
1282
1283void
1284_gtk_print_operation_platform_backend_resize_preview_surface (GtkPrintOperation *op,
1285 GtkPageSetup *page_setup,
1286 cairo_surface_t *surface)
1287{
1288 gtk_print_operation_unix_resize_preview_surface (op, page_setup, surface);
1289}
1290
1291void
1292_gtk_print_operation_platform_backend_preview_start_page (GtkPrintOperation *op,
1293 cairo_surface_t *surface,
1294 cairo_t *cr)
1295{
1296 gtk_print_operation_unix_preview_start_page (op, surface, cr);
1297}
1298
1299void
1300_gtk_print_operation_platform_backend_preview_end_page (GtkPrintOperation *op,
1301 cairo_surface_t *surface,
1302 cairo_t *cr)
1303{
1304 gtk_print_operation_unix_preview_end_page (op, surface, cr);
1305}
1306

source code of gtk/gtk/gtkprintoperation-unix.c