]> Pileus Git - ~andy/gtk/blob - gtk/gtkprintoperation-unix.c
Added new symbols
[~andy/gtk] / gtk / gtkprintoperation-unix.c
1 /* GTK - The GIMP Toolkit
2  * gtkprintoperation-unix.c: Print Operation Details for Unix and Unix like platforms
3  * Copyright (C) 2006, Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 #include "config.h"
22 #ifdef HAVE_UNISTD_H
23 #include <unistd.h>
24 #endif
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <string.h>
28
29 #include "gtkprintoperation-private.h"
30 #include "gtkmarshal.h"
31 #include "gtkmessagedialog.h"
32
33 #include "gtkprintunixdialog.h"
34 #include "gtkpagesetupunixdialog.h"
35 #include "gtkprintbackend.h"
36 #include "gtkprinter.h"
37 #include "gtkprintjob.h"
38 #include "gtkalias.h"
39 #include "gtkintl.h"
40
41 typedef struct {
42   GtkPrintJob *job;         /* the job we are sending to the printer */
43   gulong job_status_changed_tag;
44   GtkWindow *parent;        /* just in case we need to throw error dialogs */
45   GMainLoop *loop;
46   gboolean data_sent;
47 } GtkPrintOperationUnix;
48
49 typedef struct _PrinterFinder PrinterFinder;
50
51 static void printer_finder_free (PrinterFinder *finder);
52 static void find_printer        (const char    *printer,
53                                  GFunc          func,
54                                  gpointer       data);
55
56 static void
57 unix_start_page (GtkPrintOperation *op,
58                  GtkPrintContext   *print_context,
59                  GtkPageSetup      *page_setup)
60 {
61
62 }
63
64 static void
65 unix_end_page (GtkPrintOperation *op,
66                GtkPrintContext   *print_context)
67 {
68   cairo_t *cr;
69
70   cr = gtk_print_context_get_cairo (print_context);
71   cairo_show_page (cr);
72 }
73
74 static void
75 op_unix_free (GtkPrintOperationUnix *op_unix)
76 {
77   if (op_unix->job)
78     {
79       g_signal_handler_disconnect (op_unix->job,
80                                    op_unix->job_status_changed_tag);
81       g_object_unref (op_unix->job);
82     }
83
84   g_free (op_unix);
85 }
86
87 static void
88 unix_finish_send  (GtkPrintJob *job,
89                    void        *user_data, 
90                    GError      *error)
91 {
92   GtkPrintOperationUnix *op_unix;
93
94   op_unix = (GtkPrintOperationUnix *) user_data;
95
96   if (error != NULL)
97     {
98       GtkWidget *edialog;
99       edialog = gtk_message_dialog_new (op_unix->parent, 
100                                         GTK_DIALOG_DESTROY_WITH_PARENT,
101                                         GTK_MESSAGE_ERROR,
102                                         GTK_BUTTONS_CLOSE,
103                                         _("Error printing") /* FIXME better text */);
104       gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (edialog),
105                                                 "%s", error->message);
106       gtk_window_set_modal (GTK_WINDOW (edialog), TRUE);
107       g_signal_connect (edialog, "response",
108                         G_CALLBACK (gtk_widget_destroy), NULL);
109
110       gtk_window_present (GTK_WINDOW (edialog));
111     }
112
113   op_unix->data_sent = TRUE;
114   if (op_unix->loop)
115     g_main_loop_quit (op_unix->loop);
116 }
117
118 static void
119 unix_end_run (GtkPrintOperation *op,
120               gboolean wait)
121 {
122   GtkPrintOperationUnix *op_unix = op->priv->platform_data;
123
124   if (wait)
125     op_unix->loop = g_main_loop_new (NULL, FALSE);
126   
127   /* TODO: Check for error */
128   gtk_print_job_send (op_unix->job,
129                       unix_finish_send, 
130                       op_unix, NULL,
131                       NULL);
132
133   if (wait)
134     {
135       if (!op_unix->data_sent)
136         {
137           GDK_THREADS_LEAVE ();  
138           g_main_loop_run (op_unix->loop);
139           GDK_THREADS_ENTER ();  
140         }
141       g_main_loop_unref (op_unix->loop);
142     }
143 }
144
145 static void
146 job_status_changed_cb (GtkPrintJob       *job, 
147                        GtkPrintOperation *op)
148 {
149   _gtk_print_operation_set_status (op, gtk_print_job_get_status (job), NULL);
150 }
151
152
153 static GtkWidget *
154 get_print_dialog (GtkPrintOperation *op,
155                   GtkWindow         *parent)
156 {
157   GtkPrintOperationPrivate *priv = op->priv;
158   GtkWidget *pd;
159   GtkPageSetup *page_setup;
160
161   pd = gtk_print_unix_dialog_new (NULL, parent);
162
163   if (priv->print_settings)
164     gtk_print_unix_dialog_set_settings (GTK_PRINT_UNIX_DIALOG (pd),
165                                         priv->print_settings);
166   if (priv->default_page_setup)
167     page_setup = gtk_page_setup_copy (priv->default_page_setup);
168   else
169     page_setup = gtk_page_setup_new ();
170
171   gtk_print_unix_dialog_set_page_setup (GTK_PRINT_UNIX_DIALOG (pd), 
172                                         page_setup);
173   g_object_unref (page_setup);
174
175   return pd;
176 }
177   
178 typedef struct {
179   GtkPrintOperation           *op;
180   gboolean                     do_print;
181   GError                     **error;
182   GtkPrintOperationResult      result;
183   GtkPrintOperationPrintFunc   print_cb;
184   GDestroyNotify               destroy;
185   GtkWindow                   *parent;
186   GMainLoop                   *loop;
187 } PrintResponseData;
188
189 static void
190 print_response_data_free (gpointer data)
191 {
192   PrintResponseData *rdata = data;
193
194   g_object_unref (rdata->op);
195   g_free (rdata);
196 }
197
198 static void
199 finish_print (PrintResponseData *rdata,
200               GtkPrinter *printer,
201               GtkPageSetup *page_setup,
202               GtkPrintSettings *settings)
203 {
204   GtkPrintOperation *op = rdata->op;
205   GtkPrintOperationPrivate *priv = op->priv;
206
207   priv->start_page = unix_start_page;
208   priv->end_page = unix_end_page;
209   priv->end_run = unix_end_run;
210   
211   if (rdata->do_print)
212     {
213       GtkPrintOperationUnix *op_unix;
214
215       gtk_print_operation_set_print_settings (op, settings);
216       
217       op_unix = g_new0 (GtkPrintOperationUnix, 1);
218       op_unix->job = gtk_print_job_new (priv->job_name,
219                                         printer,
220                                         settings,
221                                         page_setup);
222   
223       rdata->op->priv->surface = gtk_print_job_get_surface (op_unix->job, rdata->error);
224       if (op->priv->surface == NULL)
225         {
226           rdata->do_print = FALSE;
227           op_unix_free (op_unix);
228           rdata->result = GTK_PRINT_OPERATION_RESULT_ERROR;
229           goto out;
230         }
231
232       _gtk_print_operation_set_status (op, gtk_print_job_get_status (op_unix->job), NULL);
233       op_unix->job_status_changed_tag =
234         g_signal_connect (op_unix->job, "status_changed",
235                           G_CALLBACK (job_status_changed_cb), op);
236       
237       op_unix->parent = rdata->parent;
238
239       priv->dpi_x = 72;
240       priv->dpi_y = 72;
241  
242       priv->platform_data = op_unix;
243       priv->free_platform_data = (GDestroyNotify) op_unix_free;
244
245       priv->print_pages = op_unix->job->print_pages;
246       priv->page_ranges = op_unix->job->page_ranges;
247       priv->num_page_ranges = op_unix->job->num_page_ranges;
248   
249       priv->manual_num_copies = op_unix->job->num_copies;
250       priv->manual_collation = op_unix->job->collate;
251       priv->manual_reverse = op_unix->job->reverse;
252       priv->manual_page_set = op_unix->job->page_set;
253       priv->manual_scale = op_unix->job->scale;
254       priv->manual_orientation = op_unix->job->rotate_to_orientation;
255     } 
256
257  out:  
258   if (rdata->print_cb)
259     {
260       if (rdata->do_print)
261         rdata->print_cb (op, FALSE); 
262       else
263        _gtk_print_operation_set_status (op, GTK_PRINT_STATUS_FINISHED_ABORTED, NULL); 
264     }
265
266   if (rdata->destroy)
267     rdata->destroy (rdata);
268 }
269
270 static void
271 handle_print_response (GtkWidget *dialog,
272                        gint       response,
273                        gpointer   data)
274 {
275   GtkPrintUnixDialog *pd = GTK_PRINT_UNIX_DIALOG (dialog);
276   PrintResponseData *rdata = data;
277   GtkPrintSettings *settings = NULL;
278   GtkPageSetup *page_setup = NULL;
279   GtkPrinter *printer = NULL;
280
281   if (response == GTK_RESPONSE_OK)
282     {
283       rdata->result = GTK_PRINT_OPERATION_RESULT_APPLY;
284
285       printer = gtk_print_unix_dialog_get_selected_printer (GTK_PRINT_UNIX_DIALOG (pd));
286       if (printer == NULL)
287         goto out;
288       
289       rdata->do_print = TRUE;
290
291       settings = gtk_print_unix_dialog_get_settings (GTK_PRINT_UNIX_DIALOG (pd));
292       page_setup = gtk_print_unix_dialog_get_page_setup (GTK_PRINT_UNIX_DIALOG (pd));
293     } 
294
295  out:  
296   finish_print (rdata, printer, page_setup, settings);
297
298   if (settings)
299     g_object_unref (settings);
300   
301   gtk_widget_destroy (GTK_WIDGET (pd));
302 }
303
304
305 static void
306 found_printer (GtkPrinter *printer,
307                PrintResponseData *rdata)
308 {
309   GtkPrintOperation *op = rdata->op;
310   GtkPrintOperationPrivate *priv = op->priv;
311   GtkPrintSettings *settings = NULL;
312   GtkPageSetup *page_setup = NULL;
313   
314   if (rdata->loop)
315     g_main_loop_quit (rdata->loop);
316
317   if (printer != NULL) {
318       rdata->result = GTK_PRINT_OPERATION_RESULT_APPLY;
319
320       rdata->do_print = TRUE;
321
322       if (priv->print_settings)
323         settings = gtk_print_settings_copy (priv->print_settings);
324       else
325         settings = gtk_print_settings_new ();
326
327       gtk_print_settings_set_printer (settings,
328                                       gtk_printer_get_name (printer));
329       
330       if (priv->default_page_setup)
331         page_setup = gtk_page_setup_copy (priv->default_page_setup);
332       else
333         page_setup = gtk_page_setup_new ();
334   }
335   
336   finish_print (rdata, printer, page_setup, settings);
337
338   if (settings)
339     g_object_unref (settings);
340   
341   if (page_setup)
342     g_object_unref (page_setup);
343 }
344
345 void
346 _gtk_print_operation_platform_backend_run_dialog_async (GtkPrintOperation          *op,
347                                                         GtkWindow                  *parent,
348                                                         GtkPrintOperationPrintFunc  print_cb)
349 {
350   GtkWidget *pd;
351   PrintResponseData *rdata;
352   const char *printer_name;
353
354   rdata = g_new (PrintResponseData, 1);
355   rdata->op = g_object_ref (op);
356   rdata->do_print = FALSE;
357   rdata->result = GTK_PRINT_OPERATION_RESULT_CANCEL;
358   rdata->error = NULL;
359   rdata->print_cb = print_cb;
360   rdata->parent = parent;
361   rdata->loop = NULL;
362   rdata->destroy = print_response_data_free;
363   
364   if (op->priv->show_dialog)
365     {
366       pd = get_print_dialog (op, parent);
367       gtk_window_set_modal (GTK_WINDOW (pd), TRUE);
368
369       g_signal_connect (pd, "response", 
370                         G_CALLBACK (handle_print_response), rdata);
371       
372       gtk_window_present (GTK_WINDOW (pd));
373     }
374   else
375     {
376       printer_name = NULL;
377       if (op->priv->print_settings)
378         printer_name = gtk_print_settings_get_printer (op->priv->print_settings);
379       
380       find_printer (printer_name,
381                     (GFunc) found_printer, rdata);
382     }
383 }
384
385 GtkPrintOperationResult
386 _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op,
387                                                   GtkWindow         *parent,
388                                                   gboolean          *do_print,
389                                                   GError           **error)
390  {
391   GtkWidget *pd;
392   PrintResponseData rdata;
393   gint response;  
394   const char *printer_name;
395    
396   rdata.op = op;
397   rdata.do_print = FALSE;
398   rdata.result = GTK_PRINT_OPERATION_RESULT_CANCEL;
399   rdata.error = error;
400   rdata.print_cb = NULL;
401   rdata.destroy = NULL;
402   rdata.parent = parent;
403   rdata.loop = NULL;
404
405   if (op->priv->show_dialog)
406     {
407       pd = get_print_dialog (op, parent);
408       response = gtk_dialog_run (GTK_DIALOG (pd));
409       handle_print_response (pd, response, &rdata);
410     }
411   else
412     {
413       printer_name = NULL;
414       if (op->priv->print_settings)
415         printer_name = gtk_print_settings_get_printer (op->priv->print_settings);
416       
417       rdata.loop = g_main_loop_new (NULL, FALSE);
418       find_printer (printer_name,
419                     (GFunc) found_printer, &rdata);
420
421       GDK_THREADS_LEAVE ();  
422       g_main_loop_run (rdata.loop);
423       GDK_THREADS_ENTER ();  
424
425       g_main_loop_unref (rdata.loop);
426     }
427
428   *do_print = rdata.do_print;
429   
430   return rdata.result;
431 }
432
433
434 typedef struct {
435   GtkPageSetup         *page_setup;
436   GtkPageSetupDoneFunc  done_cb;
437   gpointer              data;
438   GDestroyNotify        destroy;
439 } PageSetupResponseData;
440
441 static void
442 page_setup_data_free (gpointer data)
443 {
444   PageSetupResponseData *rdata = data;
445
446   g_object_unref (rdata->page_setup);
447   g_free (rdata);
448 }
449
450 static void
451 handle_page_setup_response (GtkWidget *dialog,
452                             gint       response,
453                             gpointer   data)
454 {
455   GtkPageSetupUnixDialog *psd;
456   PageSetupResponseData *rdata = data;
457
458   psd = GTK_PAGE_SETUP_UNIX_DIALOG (dialog);
459   if (response == GTK_RESPONSE_OK)
460     rdata->page_setup = gtk_page_setup_unix_dialog_get_page_setup (psd);
461
462   gtk_widget_destroy (dialog);
463
464   if (rdata->done_cb)
465     rdata->done_cb (rdata->page_setup, rdata->data);
466
467   if (rdata->destroy)
468     rdata->destroy (rdata);
469 }
470
471 static GtkWidget *
472 get_page_setup_dialog (GtkWindow        *parent,
473                        GtkPageSetup     *page_setup,
474                        GtkPrintSettings *settings)
475 {
476   GtkWidget *dialog;
477
478   dialog = gtk_page_setup_unix_dialog_new (NULL, parent);
479   if (page_setup)
480     gtk_page_setup_unix_dialog_set_page_setup (GTK_PAGE_SETUP_UNIX_DIALOG (dialog),
481                                                page_setup);
482   gtk_page_setup_unix_dialog_set_print_settings (GTK_PAGE_SETUP_UNIX_DIALOG (dialog),
483                                                  settings);
484
485   return dialog;
486 }
487
488 /**
489  * gtk_print_run_page_setup_dialog:
490  * @parent: transient parent, or %NULL
491  * @page_setup: an existing #GtkPageSetup, or %NULL
492  * @settings: a #GtkPrintSettings
493  * 
494  * Runs a page setup dialog, letting the user modify the values from 
495  * @page_setup. If the user cancels the dialog, the returned #GtkPageSetup 
496  * is identical to the passed in @page_setup, otherwise it contains the 
497  * modifications done in the dialog.
498  *
499  * Note that this function may use a recursive mainloop to show the page
500  * setup dialog. See gtk_print_run_page_setup_dialog_async() if this is 
501  * a problem.
502  * 
503  * Return value: a new #GtkPageSetup
504  *
505  * Since: 2.10
506  */
507 GtkPageSetup *
508 gtk_print_run_page_setup_dialog (GtkWindow        *parent,
509                                  GtkPageSetup     *page_setup,
510                                  GtkPrintSettings *settings)
511 {
512   GtkWidget *dialog;
513   gint response;
514   PageSetupResponseData rdata;  
515   
516   rdata.page_setup = NULL;
517   rdata.done_cb = NULL;
518   rdata.data = NULL;
519   rdata.destroy = NULL;
520
521   dialog = get_page_setup_dialog (parent, page_setup, settings);
522   response = gtk_dialog_run (GTK_DIALOG (dialog));
523   handle_page_setup_response (dialog, response, &rdata);
524  
525   if (rdata.page_setup)
526     return rdata.page_setup;
527   else if (page_setup)
528     return gtk_page_setup_copy (page_setup);
529   else
530     return gtk_page_setup_new ();
531 }
532
533 /**
534  * gtk_print_run_page_setup_dialog_async:
535  * @parent: transient parent, or %NULL
536  * @page_setup: an existing #GtkPageSetup, or %NULL
537  * @settings: a #GtkPrintSettings
538  * @done_cb: a function to call when the user saves the modified page setup
539  * @data: user data to pass to @done_cb
540  * 
541  * Runs a page setup dialog, letting the user modify the values from @page_setup. 
542  *
543  * In contrast to gtk_print_run_page_setup_dialog(), this function  returns after 
544  * showing the page setup dialog on platforms that support this, and calls @done_cb 
545  * from a signal handler for the ::response signal of the dialog.
546  *
547  * Since: 2.10
548  */
549 void
550 gtk_print_run_page_setup_dialog_async (GtkWindow            *parent,
551                                        GtkPageSetup         *page_setup,
552                                        GtkPrintSettings     *settings,
553                                        GtkPageSetupDoneFunc  done_cb,
554                                        gpointer              data)
555 {
556   GtkWidget *dialog;
557   PageSetupResponseData *rdata;
558   
559   dialog = get_page_setup_dialog (parent, page_setup, settings);
560   gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
561   
562   rdata = g_new (PageSetupResponseData, 1);
563   rdata->page_setup = NULL;
564   rdata->done_cb = done_cb;
565   rdata->data = data;
566   rdata->destroy = page_setup_data_free;
567
568   g_signal_connect (dialog, "response",
569                     G_CALLBACK (handle_page_setup_response), rdata);
570  
571   gtk_window_present (GTK_WINDOW (dialog));
572  }
573
574 struct _PrinterFinder {
575   gboolean found_printer;
576   GFunc func;
577   gpointer data;
578   char *printer_name;
579   GList *backends;
580   guint timeout_tag;
581   GtkPrinter *printer;
582   GtkPrinter *default_printer;
583   GtkPrinter *first_printer;
584 };
585
586 static gboolean
587 find_printer_idle (gpointer data)
588 {
589   PrinterFinder *finder = data;
590   GtkPrinter *printer;
591
592   if (finder->printer != NULL)
593     printer = finder->printer;
594   else if (finder->default_printer != NULL)
595     printer = finder->default_printer;
596   else if (finder->first_printer != NULL)
597     printer = finder->first_printer;
598   else
599     printer = NULL;
600
601   finder->func (printer, finder->data);
602   
603   printer_finder_free (finder);
604
605   return FALSE;
606 }
607
608 static void
609 printer_added_cb (GtkPrintBackend *backend, 
610                   GtkPrinter      *printer, 
611                   PrinterFinder   *finder)
612 {
613   if (gtk_printer_is_virtual (printer) ||
614       finder->found_printer)
615     return;
616
617   if (finder->printer_name != NULL &&
618       strcmp (gtk_printer_get_name (printer), finder->printer_name) == 0)
619     {
620       finder->printer = g_object_ref (printer);
621       finder->found_printer = TRUE;
622     }
623   else if (finder->default_printer == NULL &&
624            gtk_printer_is_default (printer))
625     {
626       finder->default_printer = g_object_ref (printer);
627       if (finder->printer_name == NULL)
628         finder->found_printer = TRUE;
629     }
630   else
631     if (finder->first_printer == NULL)
632       finder->first_printer = g_object_ref (printer);
633   
634   if (finder->found_printer)
635     g_idle_add (find_printer_idle, finder);
636 }
637
638 static void
639 printer_list_done_cb (GtkPrintBackend *backend, 
640                       PrinterFinder   *finder)
641 {
642   finder->backends = g_list_remove (finder->backends, backend);
643   
644   g_signal_handlers_disconnect_by_func (backend, printer_added_cb, finder);
645   g_signal_handlers_disconnect_by_func (backend, printer_list_done_cb, finder);
646   
647   gtk_print_backend_destroy (backend);
648   g_object_unref (backend);
649
650   if (finder->backends == NULL && !finder->found_printer)
651     g_idle_add (find_printer_idle, finder);
652 }
653
654 static void
655 find_printer_init (PrinterFinder *finder,
656                    GtkPrintBackend *backend)
657 {
658   GList *list;
659   GList *node;
660
661   list = gtk_print_backend_get_printer_list (backend);
662
663   node = list;
664   while (node != NULL)
665     {
666       printer_added_cb (backend, node->data, finder);
667       node = node->next;
668
669       if (finder->found_printer)
670         break;
671     }
672
673   g_list_free (list);
674
675   if (gtk_print_backend_printer_list_is_done (backend))
676     {
677       finder->backends = g_list_remove (finder->backends, backend);
678       gtk_print_backend_destroy (backend);
679       g_object_unref (backend);
680     }
681   else
682     {
683       g_signal_connect (backend, 
684                         "printer-added", 
685                         (GCallback) printer_added_cb, 
686                         finder);
687       g_signal_connect (backend, 
688                         "printer-list-done", 
689                         (GCallback) printer_list_done_cb, 
690                         finder);
691     }
692
693 }
694
695 static void
696 printer_finder_free (PrinterFinder *finder)
697 {
698   GList *l;
699   
700   g_free (finder->printer_name);
701   
702   if (finder->printer)
703     g_object_unref (finder->printer);
704   
705   if (finder->default_printer)
706     g_object_unref (finder->default_printer);
707   
708   if (finder->first_printer)
709     g_object_unref (finder->first_printer);
710
711   for (l = finder->backends; l != NULL; l = l->next)
712     {
713       GtkPrintBackend *backend = l->data;
714       g_signal_handlers_disconnect_by_func (backend, printer_added_cb, finder);
715       g_signal_handlers_disconnect_by_func (backend, printer_list_done_cb, finder);
716       gtk_print_backend_destroy (backend);
717       g_object_unref (backend);
718     }
719   
720   g_list_free (finder->backends);
721   
722   g_free (finder);
723 }
724
725 static void 
726 find_printer (const char *printer,
727               GFunc func,
728               gpointer data)
729 {
730   GList *node, *next;
731   PrinterFinder *finder;
732
733   finder = g_new0 (PrinterFinder, 1);
734
735   finder->printer_name = g_strdup (printer);
736   finder->func = func;
737   finder->data = data;
738   
739   finder->backends = NULL;
740   if (g_module_supported ())
741     finder->backends = gtk_print_backend_load_modules ();
742
743   for (node = finder->backends; !finder->found_printer && node != NULL; node = next)
744     {
745       next = node->next;
746       find_printer_init (finder, GTK_PRINT_BACKEND (node->data));
747     }
748
749   if (finder->backends == NULL && !finder->found_printer)
750     g_idle_add (find_printer_idle, finder);
751 }
752
753 #define __GTK_PRINT_OPERATION_UNIX_C__
754 #include "gtkaliasdef.c"