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