]> Pileus Git - ~andy/gtk/blob - gtk/gtkprintoperation-unix.c
Mark preview filename as translatable.
[~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 "gtkprintoperation-private.h"
34 #include "gtkmarshal.h"
35 #include "gtkmessagedialog.h"
36
37 #include <cairo-pdf.h>
38 #include <cairo-ps.h>
39 #include "gtkprintunixdialog.h"
40 #include "gtkpagesetupunixdialog.h"
41 #include "gtkprintbackend.h"
42 #include "gtkprinter.h"
43 #include "gtkprinter-private.h"
44 #include "gtkprintjob.h"
45 #include "gtklabel.h"
46 #include "gtkalias.h"
47 #include "gtkintl.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 (type == CAIRO_SURFACE_TYPE_PS)
90     cairo_ps_surface_set_size (op_unix->surface, w, h);
91   else if (type == CAIRO_SURFACE_TYPE_PDF)
92     cairo_pdf_surface_set_size (op_unix->surface, w, h);
93 }
94
95 static void
96 unix_end_page (GtkPrintOperation *op,
97                GtkPrintContext   *print_context)
98 {
99   cairo_t *cr;
100
101   cr = gtk_print_context_get_cairo_context (print_context);
102   cairo_show_page (cr);
103 }
104
105 static void
106 op_unix_free (GtkPrintOperationUnix *op_unix)
107 {
108   if (op_unix->job)
109     {
110       g_signal_handler_disconnect (op_unix->job,
111                                    op_unix->job_status_changed_tag);
112       g_object_unref (op_unix->job);
113     }
114
115   g_free (op_unix);
116 }
117
118 static gchar *
119 shell_command_substitute_file (const gchar *cmd,
120                                const gchar *filename)
121 {
122   const gchar *inptr, *start;
123   gchar *result;
124   GString *final;
125
126   g_return_val_if_fail (cmd != NULL, NULL);
127   g_return_val_if_fail (filename != NULL, NULL);
128
129   result = NULL;
130   final = g_string_new (NULL);
131
132   start = inptr = cmd;
133
134   while ((inptr = strchr (inptr, '%')) != NULL) 
135     {
136       g_string_append_len (final, start, inptr - start);
137       inptr++;
138       switch (*inptr) 
139         {
140           case 'f':
141             g_string_append (final, filename ? filename : "");
142             break;
143
144           case '%':
145             g_string_append_c (final, '%');
146             break;
147
148           default:
149             g_string_append_c (final, '%');
150             if (*inptr)
151               g_string_append_c (final, *inptr);
152             break;
153         }
154       if (*inptr)
155         inptr++;
156       start = inptr;
157     }
158   g_string_append (final, start);
159
160   result = final->str;
161
162   g_string_free (final, FALSE);
163
164   return result;
165 }
166
167 void
168 _gtk_print_operation_platform_backend_launch_preview (GtkPrintOperation *op,
169                                                       cairo_surface_t   *surface,
170                                                       GtkWindow         *parent,
171                                                       const gchar       *filename)
172 {
173   gint argc;
174   gchar **argv;
175   gchar *cmd;
176   gchar *preview_cmd;
177   GtkSettings *settings;
178   gchar *quoted_filename;
179   GdkScreen *screen;
180   GError *error = NULL;
181
182   cairo_surface_destroy (surface);
183  
184   settings = gtk_settings_get_default ();
185   g_object_get (settings, "gtk-print-preview-command", &preview_cmd, NULL);
186
187   quoted_filename = g_shell_quote (filename);
188   cmd = shell_command_substitute_file (preview_cmd, quoted_filename);
189   g_shell_parse_argv (cmd, &argc, &argv, &error);
190
191   if (error != NULL)
192     goto out;
193
194   if (parent)
195     screen = gtk_window_get_screen (parent);
196   else
197     screen = gdk_screen_get_default ();
198   
199   gdk_spawn_on_screen (screen, NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &error);
200
201  out:
202   if (error != NULL)
203     {
204       GtkWidget *edialog;
205       edialog = gtk_message_dialog_new (parent, 
206                                         GTK_DIALOG_DESTROY_WITH_PARENT,
207                                         GTK_MESSAGE_ERROR,
208                                         GTK_BUTTONS_CLOSE,
209                                         _("Error launching preview") /* FIXME better text */);
210       gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (edialog),
211                                                 "%s", error->message);
212       gtk_window_set_modal (GTK_WINDOW (edialog), TRUE);
213       g_signal_connect (edialog, "response",
214                         G_CALLBACK (gtk_widget_destroy), NULL);
215
216       gtk_window_present (GTK_WINDOW (edialog));
217
218       g_error_free (error); 
219    } 
220
221   g_free (cmd);
222   g_free (quoted_filename);
223   g_free (preview_cmd);
224   g_strfreev (argv);
225 }
226
227 static void
228 unix_finish_send  (GtkPrintJob *job,
229                    gpointer     user_data, 
230                    GError      *error)
231 {
232   GtkPrintOperationUnix *op_unix;
233
234   op_unix = (GtkPrintOperationUnix *) user_data;
235
236   if (error != NULL)
237     {
238       GtkWidget *edialog;
239       edialog = gtk_message_dialog_new (op_unix->parent, 
240                                         GTK_DIALOG_DESTROY_WITH_PARENT,
241                                         GTK_MESSAGE_ERROR,
242                                         GTK_BUTTONS_CLOSE,
243                                         _("Error printing") /* FIXME better text */);
244       gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (edialog),
245                                                 "%s", error->message);
246       gtk_window_set_modal (GTK_WINDOW (edialog), TRUE);
247       g_signal_connect (edialog, "response",
248                         G_CALLBACK (gtk_widget_destroy), NULL);
249
250       gtk_window_present (GTK_WINDOW (edialog));
251     }
252
253   op_unix->data_sent = TRUE;
254
255   if (op_unix->loop)
256     g_main_loop_quit (op_unix->loop);
257 }
258
259 static void
260 unix_end_run (GtkPrintOperation *op,
261               gboolean           wait,
262               gboolean           cancelled)
263 {
264   GtkPrintOperationUnix *op_unix = op->priv->platform_data;
265
266   cairo_surface_finish (op_unix->surface);
267   
268   if (cancelled)
269     return;
270
271   if (wait)
272     op_unix->loop = g_main_loop_new (NULL, FALSE);
273   
274   /* TODO: Check for error */
275   if (op_unix->job != NULL)
276     gtk_print_job_send (op_unix->job,
277                         unix_finish_send, 
278                         op_unix, NULL,
279                         NULL);
280
281   if (wait)
282     {
283       if (!op_unix->data_sent)
284         {
285           GDK_THREADS_LEAVE ();  
286           g_main_loop_run (op_unix->loop);
287           GDK_THREADS_ENTER ();  
288         }
289       g_main_loop_unref (op_unix->loop);
290     }
291 }
292
293 static void
294 job_status_changed_cb (GtkPrintJob       *job, 
295                        GtkPrintOperation *op)
296 {
297   _gtk_print_operation_set_status (op, gtk_print_job_get_status (job), NULL);
298 }
299
300
301 static GtkWidget *
302 get_print_dialog (GtkPrintOperation *op,
303                   GtkWindow         *parent)
304 {
305   GtkPrintOperationPrivate *priv = op->priv;
306   GtkWidget *pd, *label;
307   GtkPageSetup *page_setup;
308   const gchar *custom_tab_label;
309
310   pd = gtk_print_unix_dialog_new (NULL, parent);
311
312   gtk_print_unix_dialog_set_manual_capabilities (GTK_PRINT_UNIX_DIALOG (pd),
313                                                  GTK_PRINT_CAPABILITY_PAGE_SET |
314                                                  GTK_PRINT_CAPABILITY_COPIES |
315                                                  GTK_PRINT_CAPABILITY_COLLATE |
316                                                  GTK_PRINT_CAPABILITY_REVERSE |
317                                                  GTK_PRINT_CAPABILITY_SCALE |
318                                                  GTK_PRINT_CAPABILITY_GENERATE_PDF);
319
320   if (priv->print_settings)
321     gtk_print_unix_dialog_set_settings (GTK_PRINT_UNIX_DIALOG (pd),
322                                         priv->print_settings);
323   if (priv->default_page_setup)
324     page_setup = gtk_page_setup_copy (priv->default_page_setup);
325   else
326     page_setup = gtk_page_setup_new ();
327
328   gtk_print_unix_dialog_set_page_setup (GTK_PRINT_UNIX_DIALOG (pd), 
329                                         page_setup);
330   g_object_unref (page_setup);
331
332   g_signal_emit_by_name (op, "create-custom-widget",
333                          &priv->custom_widget);
334
335   if (priv->custom_widget) 
336     {
337       custom_tab_label = priv->custom_tab_label;
338       
339       if (custom_tab_label == NULL)
340         {
341           custom_tab_label = g_get_application_name ();
342           if (custom_tab_label == NULL)
343             custom_tab_label = _("Application");
344         }
345
346       label = gtk_label_new (custom_tab_label);
347       
348       gtk_print_unix_dialog_add_custom_tab (GTK_PRINT_UNIX_DIALOG (pd),
349                                             priv->custom_widget, label);
350     }
351   
352   return pd;
353 }
354   
355 typedef struct 
356 {
357   GtkPrintOperation           *op;
358   gboolean                     do_print;
359   gboolean                     do_preview;
360   GtkPrintOperationResult      result;
361   GtkPrintOperationPrintFunc   print_cb;
362   GDestroyNotify               destroy;
363   GtkWindow                   *parent;
364   GMainLoop                   *loop;
365 } PrintResponseData;
366
367 static void
368 print_response_data_free (gpointer data)
369 {
370   PrintResponseData *rdata = data;
371
372   g_object_unref (rdata->op);
373   g_free (rdata);
374 }
375
376 static void
377 finish_print (PrintResponseData *rdata,
378               GtkPrinter        *printer,
379               GtkPageSetup      *page_setup,
380               GtkPrintSettings  *settings)
381 {
382   GtkPrintOperation *op = rdata->op;
383   GtkPrintOperationPrivate *priv = op->priv;
384   GtkPrintJob *job;
385   
386   if (rdata->do_print)
387     {
388       gtk_print_operation_set_print_settings (op, settings);
389       priv->print_context = _gtk_print_context_new (op);
390       _gtk_print_context_set_page_setup (priv->print_context, page_setup);
391
392       if (!rdata->do_preview)
393         {
394           GtkPrintOperationUnix *op_unix;
395           cairo_t *cr;
396           
397           op_unix = g_new0 (GtkPrintOperationUnix, 1);
398           priv->platform_data = op_unix;
399           priv->free_platform_data = (GDestroyNotify) op_unix_free;
400           op_unix->parent = rdata->parent;
401           
402           priv->start_page = unix_start_page;
403           priv->end_page = unix_end_page;
404           priv->end_run = unix_end_run;
405           
406           job = gtk_print_job_new (priv->job_name, printer, settings, page_setup);
407           op_unix->job = job;
408           gtk_print_job_set_track_print_status (job, priv->track_print_status);
409           
410           op_unix->surface = gtk_print_job_get_surface (job, &priv->error);
411           if (op_unix->surface == NULL) 
412             {
413               rdata->result = GTK_PRINT_OPERATION_RESULT_ERROR;
414               rdata->do_print = FALSE;
415               goto out;
416             }
417           
418           cr = cairo_create (op_unix->surface);
419           gtk_print_context_set_cairo_context (priv->print_context, cr, 72, 72);
420           cairo_destroy (cr);
421
422           _gtk_print_operation_set_status (op, gtk_print_job_get_status (job), NULL);
423           
424           op_unix->job_status_changed_tag =
425             g_signal_connect (job, "status-changed",
426                               G_CALLBACK (job_status_changed_cb), op);
427           
428           priv->print_pages = job->print_pages;
429           priv->page_ranges = job->page_ranges;
430           priv->num_page_ranges = job->num_page_ranges;
431           
432           priv->manual_num_copies = job->num_copies;
433           priv->manual_collation = job->collate;
434           priv->manual_reverse = job->reverse;
435           priv->manual_page_set = job->page_set;
436           priv->manual_scale = job->scale;
437           priv->manual_orientation = job->rotate_to_orientation;
438         }
439     } 
440  out:
441   if (rdata->print_cb)
442     rdata->print_cb (op, rdata->parent, rdata->do_print, rdata->result); 
443
444   if (rdata->destroy)
445     rdata->destroy (rdata);
446 }
447
448 static void 
449 handle_print_response (GtkWidget *dialog,
450                        gint       response,
451                        gpointer   data)
452 {
453   GtkPrintUnixDialog *pd = GTK_PRINT_UNIX_DIALOG (dialog);
454   PrintResponseData *rdata = data;
455   GtkPrintSettings *settings = NULL;
456   GtkPageSetup *page_setup = NULL;
457   GtkPrinter *printer = NULL;
458
459   if (response == GTK_RESPONSE_OK)
460     {
461       printer = gtk_print_unix_dialog_get_selected_printer (GTK_PRINT_UNIX_DIALOG (pd));
462
463       rdata->result = GTK_PRINT_OPERATION_RESULT_APPLY;
464       rdata->do_preview = FALSE;
465       if (printer != NULL)
466         rdata->do_print = TRUE;
467     } 
468   else if (response == GTK_RESPONSE_APPLY)
469     {
470       /* print preview */
471       rdata->result = GTK_PRINT_OPERATION_RESULT_APPLY;
472       rdata->do_preview = TRUE;
473       rdata->do_print = TRUE;
474     }
475
476   if (rdata->do_print)
477     {
478       settings = gtk_print_unix_dialog_get_settings (GTK_PRINT_UNIX_DIALOG (pd));
479       page_setup = gtk_print_unix_dialog_get_page_setup (GTK_PRINT_UNIX_DIALOG (pd));
480       
481       g_signal_emit_by_name (rdata->op, "custom-widget-apply", rdata->op->priv->custom_widget);
482     }
483   
484   finish_print (rdata, printer, page_setup, settings);
485
486   if (settings)
487     g_object_unref (settings);
488     
489   gtk_widget_destroy (GTK_WIDGET (pd));
490  
491 }
492
493
494 static void
495 found_printer (GtkPrinter        *printer,
496                PrintResponseData *rdata)
497 {
498   GtkPrintOperation *op = rdata->op;
499   GtkPrintOperationPrivate *priv = op->priv;
500   GtkPrintSettings *settings = NULL;
501   GtkPageSetup *page_setup = NULL;
502   
503   if (rdata->loop)
504     g_main_loop_quit (rdata->loop);
505
506   if (printer != NULL) 
507     {
508       rdata->result = GTK_PRINT_OPERATION_RESULT_APPLY;
509
510       rdata->do_print = TRUE;
511
512       if (priv->print_settings)
513         settings = gtk_print_settings_copy (priv->print_settings);
514       else
515         settings = gtk_print_settings_new ();
516
517       gtk_print_settings_set_printer (settings,
518                                       gtk_printer_get_name (printer));
519       
520       if (priv->default_page_setup)
521         page_setup = gtk_page_setup_copy (priv->default_page_setup);
522       else
523         page_setup = gtk_page_setup_new ();
524   }
525   
526   finish_print (rdata, printer, page_setup, settings);
527
528   if (settings)
529     g_object_unref (settings);
530   
531   if (page_setup)
532     g_object_unref (page_setup);
533 }
534
535 void
536 _gtk_print_operation_platform_backend_run_dialog_async (GtkPrintOperation          *op,
537                                                         gboolean                    show_dialog,
538                                                         GtkWindow                  *parent,
539                                                         GtkPrintOperationPrintFunc  print_cb)
540 {
541   GtkWidget *pd;
542   PrintResponseData *rdata;
543   const gchar *printer_name;
544
545   rdata = g_new (PrintResponseData, 1);
546   rdata->op = g_object_ref (op);
547   rdata->do_print = FALSE;
548   rdata->result = GTK_PRINT_OPERATION_RESULT_CANCEL;
549   rdata->print_cb = print_cb;
550   rdata->parent = parent;
551   rdata->loop = NULL;
552   rdata->destroy = print_response_data_free;
553   
554   if (show_dialog)
555     {
556       pd = get_print_dialog (op, parent);
557       gtk_window_set_modal (GTK_WINDOW (pd), TRUE);
558
559       g_signal_connect (pd, "response", 
560                         G_CALLBACK (handle_print_response), rdata);
561       
562       gtk_window_present (GTK_WINDOW (pd));
563     }
564   else
565     {
566       printer_name = NULL;
567       if (op->priv->print_settings)
568         printer_name = gtk_print_settings_get_printer (op->priv->print_settings);
569       
570       find_printer (printer_name, (GFunc) found_printer, rdata);
571     }
572 }
573
574 cairo_surface_t *
575 _gtk_print_operation_platform_backend_create_preview_surface (GtkPrintOperation *op,
576                                                               GtkPageSetup      *page_setup,
577                                                               gdouble           *dpi_x,
578                                                               gdouble           *dpi_y,
579                                                               gchar            **target)
580 {
581   gchar *tmp_dir, *dir_template, *preview_filename;
582   GtkPaperSize *paper_size;
583   gdouble w, h;
584   
585   dir_template = g_build_filename (g_get_tmp_dir (), "print-preview-XXXXXX", NULL);
586
587   /* use temp dirs because apps like evince need to have extensions
588    * to determine the mime type 
589    */
590   tmp_dir = mkdtemp (dir_template);
591   /* print preview pdf filename (please leave the trailing .pdf in place) */
592   preview_filename = g_build_filename (tmp_dir, 
593                                        _("Print Preview.pdf"),
594                                        NULL);
595   g_free (dir_template);
596   *target = preview_filename;
597   
598   paper_size = gtk_page_setup_get_paper_size (page_setup);
599   w = gtk_paper_size_get_width (paper_size, GTK_UNIT_POINTS);
600   h = gtk_paper_size_get_height (paper_size, GTK_UNIT_POINTS);
601     
602   *dpi_x = *dpi_y = 72;
603   return cairo_pdf_surface_create (preview_filename, w, h);
604 }
605
606 void
607 _gtk_print_operation_platform_backend_preview_start_page (GtkPrintOperation *op,
608                                                           cairo_surface_t   *surface,
609                                                           cairo_t           *cr)
610 {
611 }
612
613 void
614 _gtk_print_operation_platform_backend_preview_end_page (GtkPrintOperation *op,
615                                                         cairo_surface_t   *surface,
616                                                         cairo_t           *cr)
617 {
618   cairo_show_page (cr);
619 }
620
621 void
622 _gtk_print_operation_platform_backend_resize_preview_surface (GtkPrintOperation *op,
623                                                               GtkPageSetup      *page_setup,
624                                                               cairo_surface_t   *surface)
625 {
626   GtkPaperSize *paper_size;
627   gdouble w, h;
628   
629   paper_size = gtk_page_setup_get_paper_size (page_setup);
630   w = gtk_paper_size_get_width (paper_size, GTK_UNIT_POINTS);
631   h = gtk_paper_size_get_height (paper_size, GTK_UNIT_POINTS);
632   cairo_pdf_surface_set_size (surface, w, h);
633 }
634
635
636 GtkPrintOperationResult
637 _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op,
638                                                   gboolean           show_dialog,
639                                                   GtkWindow         *parent,
640                                                   gboolean          *do_print)
641  {
642   GtkWidget *pd;
643   PrintResponseData rdata;
644   gint response;  
645   const gchar *printer_name;
646    
647   rdata.op = op;
648   rdata.do_print = FALSE;
649   rdata.result = GTK_PRINT_OPERATION_RESULT_CANCEL;
650   rdata.print_cb = NULL;
651   rdata.destroy = NULL;
652   rdata.parent = parent;
653   rdata.loop = NULL;
654
655   if (show_dialog)
656     {
657       pd = get_print_dialog (op, parent);
658
659       response = gtk_dialog_run (GTK_DIALOG (pd));
660       handle_print_response (pd, response, &rdata);
661     }
662   else
663     {
664       printer_name = NULL;
665       if (op->priv->print_settings)
666         printer_name = gtk_print_settings_get_printer (op->priv->print_settings);
667       
668       rdata.loop = g_main_loop_new (NULL, FALSE);
669       find_printer (printer_name,
670                     (GFunc) found_printer, &rdata);
671
672       GDK_THREADS_LEAVE ();  
673       g_main_loop_run (rdata.loop);
674       GDK_THREADS_ENTER ();  
675
676       g_main_loop_unref (rdata.loop);
677       rdata.loop = NULL;
678     }
679
680   *do_print = rdata.do_print;
681   
682   return rdata.result;
683 }
684
685
686 typedef struct 
687 {
688   GtkPageSetup         *page_setup;
689   GtkPageSetupDoneFunc  done_cb;
690   gpointer              data;
691   GDestroyNotify        destroy;
692 } PageSetupResponseData;
693
694 static void
695 page_setup_data_free (gpointer data)
696 {
697   PageSetupResponseData *rdata = data;
698
699   if (rdata->page_setup)
700     g_object_unref (rdata->page_setup);
701
702   g_free (rdata);
703 }
704
705 static void
706 handle_page_setup_response (GtkWidget *dialog,
707                             gint       response,
708                             gpointer   data)
709 {
710   GtkPageSetupUnixDialog *psd;
711   PageSetupResponseData *rdata = data;
712
713   psd = GTK_PAGE_SETUP_UNIX_DIALOG (dialog);
714   if (response == GTK_RESPONSE_OK)
715     rdata->page_setup = gtk_page_setup_unix_dialog_get_page_setup (psd);
716
717   gtk_widget_destroy (dialog);
718
719   if (rdata->done_cb)
720     rdata->done_cb (rdata->page_setup, rdata->data);
721
722   if (rdata->destroy)
723     rdata->destroy (rdata);
724 }
725
726 static GtkWidget *
727 get_page_setup_dialog (GtkWindow        *parent,
728                        GtkPageSetup     *page_setup,
729                        GtkPrintSettings *settings)
730 {
731   GtkWidget *dialog;
732
733   dialog = gtk_page_setup_unix_dialog_new (NULL, parent);
734   if (page_setup)
735     gtk_page_setup_unix_dialog_set_page_setup (GTK_PAGE_SETUP_UNIX_DIALOG (dialog),
736                                                page_setup);
737   gtk_page_setup_unix_dialog_set_print_settings (GTK_PAGE_SETUP_UNIX_DIALOG (dialog),
738                                                  settings);
739
740   return dialog;
741 }
742
743 /**
744  * gtk_print_run_page_setup_dialog:
745  * @parent: transient parent, or %NULL
746  * @page_setup: an existing #GtkPageSetup, or %NULL
747  * @settings: a #GtkPrintSettings
748  * 
749  * Runs a page setup dialog, letting the user modify the values from 
750  * @page_setup. If the user cancels the dialog, the returned #GtkPageSetup 
751  * is identical to the passed in @page_setup, otherwise it contains the 
752  * modifications done in the dialog.
753  *
754  * Note that this function may use a recursive mainloop to show the page
755  * setup dialog. See gtk_print_run_page_setup_dialog_async() if this is 
756  * a problem.
757  * 
758  * Return value: a new #GtkPageSetup
759  *
760  * Since: 2.10
761  */
762 GtkPageSetup *
763 gtk_print_run_page_setup_dialog (GtkWindow        *parent,
764                                  GtkPageSetup     *page_setup,
765                                  GtkPrintSettings *settings)
766 {
767   GtkWidget *dialog;
768   gint response;
769   PageSetupResponseData rdata;  
770   
771   rdata.page_setup = NULL;
772   rdata.done_cb = NULL;
773   rdata.data = NULL;
774   rdata.destroy = NULL;
775
776   dialog = get_page_setup_dialog (parent, page_setup, settings);
777   response = gtk_dialog_run (GTK_DIALOG (dialog));
778   handle_page_setup_response (dialog, response, &rdata);
779  
780   if (rdata.page_setup)
781     return rdata.page_setup;
782   else if (page_setup)
783     return gtk_page_setup_copy (page_setup);
784   else
785     return gtk_page_setup_new ();
786 }
787
788 /**
789  * gtk_print_run_page_setup_dialog_async:
790  * @parent: transient parent, or %NULL
791  * @page_setup: an existing #GtkPageSetup, or %NULL
792  * @settings: a #GtkPrintSettings
793  * @done_cb: a function to call when the user saves the modified page setup
794  * @data: user data to pass to @done_cb
795  * 
796  * Runs a page setup dialog, letting the user modify the values from @page_setup. 
797  *
798  * In contrast to gtk_print_run_page_setup_dialog(), this function  returns after 
799  * showing the page setup dialog on platforms that support this, and calls @done_cb 
800  * from a signal handler for the ::response signal of the dialog.
801  *
802  * Since: 2.10
803  */
804 void
805 gtk_print_run_page_setup_dialog_async (GtkWindow            *parent,
806                                        GtkPageSetup         *page_setup,
807                                        GtkPrintSettings     *settings,
808                                        GtkPageSetupDoneFunc  done_cb,
809                                        gpointer              data)
810 {
811   GtkWidget *dialog;
812   PageSetupResponseData *rdata;
813   
814   dialog = get_page_setup_dialog (parent, page_setup, settings);
815   gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
816   
817   rdata = g_new (PageSetupResponseData, 1);
818   rdata->page_setup = NULL;
819   rdata->done_cb = done_cb;
820   rdata->data = data;
821   rdata->destroy = page_setup_data_free;
822
823   g_signal_connect (dialog, "response",
824                     G_CALLBACK (handle_page_setup_response), rdata);
825  
826   gtk_window_present (GTK_WINDOW (dialog));
827  }
828
829 struct _PrinterFinder 
830 {
831   gboolean found_printer;
832   GFunc func;
833   gpointer data;
834   gchar *printer_name;
835   GList *backends;
836   guint timeout_tag;
837   GtkPrinter *printer;
838   GtkPrinter *default_printer;
839   GtkPrinter *first_printer;
840 };
841
842 static gboolean
843 find_printer_idle (gpointer data)
844 {
845   PrinterFinder *finder = data;
846   GtkPrinter *printer;
847
848   if (finder->printer != NULL)
849     printer = finder->printer;
850   else if (finder->default_printer != NULL)
851     printer = finder->default_printer;
852   else if (finder->first_printer != NULL)
853     printer = finder->first_printer;
854   else
855     printer = NULL;
856
857   finder->func (printer, finder->data);
858   
859   printer_finder_free (finder);
860
861   return FALSE;
862 }
863
864 static void
865 printer_added_cb (GtkPrintBackend *backend, 
866                   GtkPrinter      *printer, 
867                   PrinterFinder   *finder)
868 {
869   if (finder->found_printer)
870     return;
871
872   /* FIXME this skips "Print to PDF" - is this intentional ? */
873   if (gtk_printer_is_virtual (printer))
874     return;
875
876   if (finder->printer_name != NULL &&
877       strcmp (gtk_printer_get_name (printer), finder->printer_name) == 0)
878     {
879       finder->printer = g_object_ref (printer);
880       finder->found_printer = TRUE;
881     }
882   else if (finder->default_printer == NULL &&
883            gtk_printer_is_default (printer))
884     {
885       finder->default_printer = g_object_ref (printer);
886       if (finder->printer_name == NULL)
887         finder->found_printer = TRUE;
888     }
889   else
890     if (finder->first_printer == NULL)
891       finder->first_printer = g_object_ref (printer);
892   
893   if (finder->found_printer)
894     g_idle_add (find_printer_idle, finder);
895 }
896
897 static void
898 printer_list_done_cb (GtkPrintBackend *backend, 
899                       PrinterFinder   *finder)
900 {
901   finder->backends = g_list_remove (finder->backends, backend);
902   
903   g_signal_handlers_disconnect_by_func (backend, printer_added_cb, finder);
904   g_signal_handlers_disconnect_by_func (backend, printer_list_done_cb, finder);
905   
906   gtk_print_backend_destroy (backend);
907   g_object_unref (backend);
908
909   if (finder->backends == NULL && !finder->found_printer)
910     g_idle_add (find_printer_idle, finder);
911 }
912
913 static void
914 find_printer_init (PrinterFinder   *finder,
915                    GtkPrintBackend *backend)
916 {
917   GList *list;
918   GList *node;
919
920   list = gtk_print_backend_get_printer_list (backend);
921
922   node = list;
923   while (node != NULL)
924     {
925       printer_added_cb (backend, node->data, finder);
926       node = node->next;
927
928       if (finder->found_printer)
929         break;
930     }
931
932   g_list_free (list);
933
934   if (gtk_print_backend_printer_list_is_done (backend))
935     {
936       finder->backends = g_list_remove (finder->backends, backend);
937       gtk_print_backend_destroy (backend);
938       g_object_unref (backend);
939     }
940   else
941     {
942       g_signal_connect (backend, "printer-added", 
943                         (GCallback) printer_added_cb, 
944                         finder);
945       g_signal_connect (backend, "printer-list-done", 
946                         (GCallback) printer_list_done_cb, 
947                         finder);
948     }
949
950 }
951
952 static void
953 printer_finder_free (PrinterFinder *finder)
954 {
955   GList *l;
956   
957   g_free (finder->printer_name);
958   
959   if (finder->printer)
960     g_object_unref (finder->printer);
961   
962   if (finder->default_printer)
963     g_object_unref (finder->default_printer);
964   
965   if (finder->first_printer)
966     g_object_unref (finder->first_printer);
967
968   for (l = finder->backends; l != NULL; l = l->next)
969     {
970       GtkPrintBackend *backend = l->data;
971       g_signal_handlers_disconnect_by_func (backend, printer_added_cb, finder);
972       g_signal_handlers_disconnect_by_func (backend, printer_list_done_cb, finder);
973       gtk_print_backend_destroy (backend);
974       g_object_unref (backend);
975     }
976   
977   g_list_free (finder->backends);
978   
979   g_free (finder);
980 }
981
982 static void 
983 find_printer (const gchar *printer,
984               GFunc        func,
985               gpointer     data)
986 {
987   GList *node, *next;
988   PrinterFinder *finder;
989
990   finder = g_new0 (PrinterFinder, 1);
991
992   finder->printer_name = g_strdup (printer);
993   finder->func = func;
994   finder->data = data;
995   
996   finder->backends = NULL;
997   if (g_module_supported ())
998     finder->backends = gtk_print_backend_load_modules ();
999
1000   for (node = finder->backends; !finder->found_printer && node != NULL; node = next)
1001     {
1002       next = node->next;
1003       find_printer_init (finder, GTK_PRINT_BACKEND (node->data));
1004     }
1005
1006   if (finder->backends == NULL && !finder->found_printer)
1007     g_idle_add (find_printer_idle, finder);
1008 }
1009
1010 #define __GTK_PRINT_OPERATION_UNIX_C__
1011 #include "gtkaliasdef.c"