]> Pileus Git - ~andy/gtk/blob - gtk/gtkprintoperation-unix.c
Refactor the gtk_print_operation_run() code and add an _async version.
[~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
40 typedef struct {
41   GtkPrintJob *job;         /* the job we are sending to the printer */
42   gulong job_status_changed_tag;
43   GtkWindow *parent;        /* just in case we need to throw error dialogs */
44 } GtkPrintOperationUnix;
45
46 static void
47 unix_start_page (GtkPrintOperation *op,
48                  GtkPrintContext   *print_context,
49                  GtkPageSetup      *page_setup)
50 {
51
52 }
53
54 static void
55 unix_end_page (GtkPrintOperation *op,
56                GtkPrintContext   *print_context)
57 {
58   cairo_t *cr;
59
60   cr = gtk_print_context_get_cairo (print_context);
61   cairo_show_page (cr);
62 }
63
64 static void
65 op_unix_free (GtkPrintOperationUnix *op_unix)
66 {
67   if (op_unix->job)
68     {
69       g_signal_handler_disconnect (op_unix->job,
70                                    op_unix->job_status_changed_tag);
71       g_object_unref (op_unix->job);
72     }
73
74   g_free (op_unix);
75 }
76
77 static void
78 unix_finish_send  (GtkPrintJob *job,
79                    void        *user_data, 
80                    GError      *error)
81 {
82   GtkPrintOperationUnix *op_unix;
83   GtkWindow *parent;
84
85   op_unix = (GtkPrintOperationUnix *) user_data;
86
87   parent = op_unix->parent;
88
89   if (error != NULL)
90     {
91       GtkWidget *edialog;
92       edialog = gtk_message_dialog_new (parent, 
93                                         GTK_DIALOG_DESTROY_WITH_PARENT,
94                                         GTK_MESSAGE_ERROR,
95                                         GTK_BUTTONS_CLOSE,
96                                         "Error printing: %s",
97                                         error->message);
98
99       gtk_dialog_run (GTK_DIALOG (edialog));
100       gtk_widget_destroy (edialog);
101     }
102 }
103
104 static void
105 unix_end_run (GtkPrintOperation *op)
106 {
107   GtkPrintOperationUnix *op_unix = op->priv->platform_data;
108  
109   /* TODO: Check for error */
110   gtk_print_job_send (op_unix->job,
111                       unix_finish_send, 
112                       op_unix, NULL,
113                       NULL);
114 }
115
116 static void
117 job_status_changed_cb (GtkPrintJob       *job, 
118                        GtkPrintOperation *op)
119 {
120   _gtk_print_operation_set_status (op, gtk_print_job_get_status (job), NULL);
121 }
122
123
124 static GtkWidget *
125 get_print_dialog (GtkPrintOperation *op,
126                   GtkWindow         *parent)
127 {
128   GtkWidget *pd;
129   GtkPageSetup *page_setup;
130
131   pd = gtk_print_unix_dialog_new (NULL, parent);
132
133   if (op->priv->print_settings)
134     gtk_print_unix_dialog_set_settings (GTK_PRINT_UNIX_DIALOG (pd),
135                                         op->priv->print_settings);
136   if (op->priv->default_page_setup)
137     page_setup = gtk_page_setup_copy (op->priv->default_page_setup);
138   else
139     page_setup = gtk_page_setup_new ();
140
141   gtk_print_unix_dialog_set_page_setup (GTK_PRINT_UNIX_DIALOG (pd), 
142                                         page_setup);
143   g_object_unref (page_setup);
144
145   return pd;
146 }
147   
148 typedef struct {
149   GtkPrintOperation           *op;
150   gboolean                     do_print;
151   GError                     **error;
152   GtkPrintOperationResult      result;
153   GtkPrintOperationPrintFunc   print_cb;
154   GDestroyNotify               destroy;
155 } PrintResponseData;
156
157 static void
158 print_response_data_free (gpointer data)
159 {
160   PrintResponseData *rdata = data;
161
162   g_object_unref (rdata->op);
163   g_free (rdata);
164 }
165
166 static void
167 handle_print_response (GtkWidget *dialog,
168                        gint       response,
169                        gpointer   data)
170 {
171   GtkPrintUnixDialog *pd = GTK_PRINT_UNIX_DIALOG (dialog);
172   PrintResponseData *rdata = data;
173   GtkPrintOperation *op = rdata->op;
174
175   if (response == GTK_RESPONSE_OK)
176     {
177       GtkPrintOperationUnix *op_unix;
178       GtkPrinter *printer;
179       GtkPrintSettings *settings;
180       GtkPageSetup *page_setup;
181
182       rdata->result = GTK_PRINT_OPERATION_RESULT_APPLY;
183
184       printer = gtk_print_unix_dialog_get_selected_printer (GTK_PRINT_UNIX_DIALOG (pd));
185       if (printer == NULL)
186         goto out;
187       
188       rdata->do_print = TRUE;
189
190       settings = gtk_print_unix_dialog_get_settings (GTK_PRINT_UNIX_DIALOG (pd));
191       page_setup = gtk_print_unix_dialog_get_page_setup (GTK_PRINT_UNIX_DIALOG (pd));
192
193       gtk_print_operation_set_print_settings (op, settings);
194
195       op_unix = g_new0 (GtkPrintOperationUnix, 1);
196       op_unix->job = gtk_print_job_new (op->priv->job_name,
197                                         printer,
198                                         settings,
199                                         page_setup);
200       g_object_unref (settings);
201   
202       rdata->op->priv->surface = gtk_print_job_get_surface (op_unix->job, rdata->error);
203       if (op->priv->surface == NULL)
204         {
205           rdata->do_print = FALSE;
206           op_unix_free (op_unix);
207           rdata->result = GTK_PRINT_OPERATION_RESULT_ERROR;
208           goto out;
209         }
210
211       _gtk_print_operation_set_status (op, gtk_print_job_get_status (op_unix->job), NULL);
212       op_unix->job_status_changed_tag =
213         g_signal_connect (op_unix->job, "status_changed",
214                           G_CALLBACK (job_status_changed_cb), op);
215       
216       op_unix->parent = gtk_window_get_transient_for (GTK_WINDOW (pd));
217
218       op->priv->dpi_x = 72;
219       op->priv->dpi_y = 72;
220  
221       op->priv->platform_data = op_unix;
222       op->priv->free_platform_data = (GDestroyNotify) op_unix_free;
223
224       op->priv->print_pages = op_unix->job->print_pages;
225       op->priv->page_ranges = op_unix->job->page_ranges;
226       op->priv->num_page_ranges = op_unix->job->num_page_ranges;
227   
228       op->priv->manual_num_copies = op_unix->job->num_copies;
229       op->priv->manual_collation = op_unix->job->collate;
230       op->priv->manual_reverse = op_unix->job->reverse;
231       op->priv->manual_page_set = op_unix->job->page_set;
232       op->priv->manual_scale = op_unix->job->scale;
233       op->priv->manual_orientation = op_unix->job->rotate_to_orientation;
234     } 
235
236   op->priv->start_page = unix_start_page;
237   op->priv->end_page = unix_end_page;
238   op->priv->end_run = unix_end_run;
239
240  out:  
241   gtk_widget_destroy (GTK_WIDGET (pd));
242
243   if (rdata->print_cb)
244     {
245       if (rdata->do_print)
246         rdata->print_cb (op); 
247       else
248        _gtk_print_operation_set_status (op, GTK_PRINT_STATUS_FINISHED_ABORTED, NULL); 
249     }
250
251   if (rdata->destroy)
252     rdata->destroy (rdata);
253 }
254
255 void
256 _gtk_print_operation_platform_backend_run_dialog_async (GtkPrintOperation          *op,
257                                                         GtkWindow                  *parent,
258                                                         GtkPrintOperationPrintFunc  print_cb)
259 {
260   GtkWidget *pd;
261   PrintResponseData *rdata;
262
263   rdata = g_new (PrintResponseData, 1);
264   rdata->op = g_object_ref (op);
265   rdata->do_print = FALSE;
266   rdata->result = GTK_PRINT_OPERATION_RESULT_CANCEL;
267   rdata->error = NULL;
268   rdata->print_cb = print_cb;
269   rdata->destroy = print_response_data_free;
270   
271   pd = get_print_dialog (op, parent);
272   gtk_window_set_modal (GTK_WINDOW (pd), TRUE);
273
274   g_signal_connect (pd, "response", 
275                     G_CALLBACK (handle_print_response), rdata);
276
277   gtk_window_present (GTK_WINDOW (pd));
278 }
279
280 GtkPrintOperationResult
281 _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op,
282                                                   GtkWindow         *parent,
283                                                   gboolean          *do_print,
284                                                   GError           **error)
285  {
286   GtkWidget *pd;
287   PrintResponseData rdata;
288   gint response;  
289    
290   rdata.op = op;
291   rdata.do_print = FALSE;
292   rdata.result = GTK_PRINT_OPERATION_RESULT_CANCEL;
293   rdata.error = error;
294   rdata.print_cb = NULL;
295   rdata.destroy = NULL;
296
297   pd = get_print_dialog (op, parent);
298
299   response = gtk_dialog_run (GTK_DIALOG (pd));
300   handle_print_response (pd, response, &rdata);
301
302   *do_print = rdata.do_print;
303
304   return rdata.result;
305 }
306
307
308 typedef struct {
309   GtkPageSetup  *page_setup;
310   GFunc          done_cb;
311   gpointer       data;
312   GDestroyNotify destroy;
313 } PageSetupResponseData;
314
315 static void
316 page_setup_data_free (gpointer data)
317 {
318   PageSetupResponseData *rdata = data;
319
320   g_object_unref (rdata->page_setup);
321   g_free (rdata);
322 }
323
324 static void
325 handle_page_setup_response (GtkWidget *dialog,
326                             gint       response,
327                             gpointer   data)
328 {
329   GtkPageSetupUnixDialog *psd;
330   PageSetupResponseData *rdata = data;
331
332   psd = GTK_PAGE_SETUP_UNIX_DIALOG (dialog);
333   if (response == GTK_RESPONSE_OK)
334     rdata->page_setup = gtk_page_setup_unix_dialog_get_page_setup (psd);
335
336   gtk_widget_destroy (dialog);
337
338   if (rdata->done_cb)
339     rdata->done_cb (rdata->page_setup, rdata->data);
340
341   if (rdata->destroy)
342     rdata->destroy (rdata);
343 }
344
345 static GtkWidget *
346 get_page_setup_dialog (GtkWindow        *parent,
347                        GtkPageSetup     *page_setup,
348                        GtkPrintSettings *settings)
349 {
350   GtkWidget *dialog;
351
352   dialog = gtk_page_setup_unix_dialog_new (NULL, parent);
353   if (page_setup)
354     gtk_page_setup_unix_dialog_set_page_setup (GTK_PAGE_SETUP_UNIX_DIALOG (dialog),
355                                                page_setup);
356   gtk_page_setup_unix_dialog_set_print_settings (GTK_PAGE_SETUP_UNIX_DIALOG (dialog),
357                                                  settings);
358
359   return dialog;
360 }
361
362 /**
363  * gtk_print_run_page_setup_dialog:
364  * @parent: transient parent, or %NULL
365  * @page_setup: an existing #GtkPageSetup, or %NULL
366  * @settings: a #GtkPrintSettings
367  * 
368  * Runs a page setup dialog, letting the user modify the values from 
369  * @page_setup. If the user cancels the dialog, the returned #GtkPageSetup 
370  * is identical to the passed in @page_setup, otherwise it contains the 
371  * modifications done in the dialog.
372  *
373  * Note that this function may use a recursive mainloop to show the page
374  * setup dialog. See gtk_print_run_page_setup_dialog_async() if this is 
375  * a problem.
376  * 
377  * Return value: a new #GtkPageSetup
378  *
379  * Since: 2.10
380  */
381 GtkPageSetup *
382 gtk_print_run_page_setup_dialog (GtkWindow        *parent,
383                                  GtkPageSetup     *page_setup,
384                                  GtkPrintSettings *settings)
385 {
386   GtkWidget *dialog;
387   gint response;
388   PageSetupResponseData rdata;  
389   
390   rdata.page_setup = NULL;
391   rdata.done_cb = NULL;
392   rdata.data = NULL;
393   rdata.destroy = NULL;
394
395   dialog = get_page_setup_dialog (parent, page_setup, settings);
396   response = gtk_dialog_run (GTK_DIALOG (dialog));
397   handle_page_setup_response (dialog, response, &rdata);
398  
399   if (rdata.page_setup)
400     return rdata.page_setup;
401   else if (page_setup)
402     return gtk_page_setup_copy (page_setup);
403   else
404     return gtk_page_setup_new ();
405 }
406
407 /**
408  * gtk_print_run_page_setup_dialog_async:
409  * @parent: transient parent, or %NULL
410  * @page_setup: an existing #GtkPageSetup, or %NULL
411  * @settings: a #GtkPrintSettings
412  * @done_cb: a function to call when the user saves the modified page setup
413  * @data: user data to pass to @done_cb
414  * 
415  * Runs a page setup dialog, letting the user modify the values from 
416  * @page_setup. 
417  *
418  * In contrast to gtk_print_run_page_setup_dialog(), this function
419  * returns after showing the page setup dialog on platforms that support
420  * this, and calls @done_cb from a signal handler for the ::response
421  * signal of the dialog.
422  *
423  * Since: 2.10
424  */
425 void
426 gtk_print_run_page_setup_dialog_async (GtkWindow            *parent,
427                                        GtkPageSetup         *page_setup,
428                                        GtkPrintSettings     *settings,
429                                        GtkPageSetupDoneFunc  done_cb,
430                                        gpointer              data)
431 {
432   GtkWidget *dialog;
433   PageSetupResponseData *rdata;
434   
435   dialog = get_page_setup_dialog (parent, page_setup, settings);
436   gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
437   
438   rdata = g_new (PageSetupResponseData, 1);
439   rdata->page_setup = NULL;
440   rdata->done_cb = done_cb;
441   rdata->data = data;
442   rdata->destroy = page_setup_data_free;
443
444   g_signal_connect (dialog, "response",
445                     G_CALLBACK (handle_page_setup_response), rdata);
446  
447   gtk_window_present (GTK_WINDOW (dialog));
448  }
449
450
451 #define __GTK_PRINT_OPERATION_UNIX_C__
452 #include "gtkaliasdef.c"