]> Pileus Git - ~andy/gtk/blob - modules/printbackends/pdf/gtkprintbackendpdf.c
Use gtk_printer_accepts_ps here.
[~andy/gtk] / modules / printbackends / pdf / gtkprintbackendpdf.c
1 /* GTK - The GIMP Toolkit
2  * gtkprintbackendpdf.c: Default implementation of GtkPrintBackend 
3  * for printing to PDF files
4  * Copyright (C) 2003, 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 <unistd.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include <config.h>
30 #include <errno.h>
31 #include <cairo.h>
32 #include <cairo-pdf.h>
33
34 #include <glib/gi18n-lib.h>
35
36 #include "gtkprintoperation.h"
37
38 #include "gtkprintbackend.h"
39 #include "gtkprintbackendpdf.h"
40
41 #include "gtkprinter.h"
42
43 typedef struct _GtkPrintBackendPdfClass GtkPrintBackendPdfClass;
44
45 #define GTK_PRINT_BACKEND_PDF_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PRINT_BACKEND_PDF, GtkPrintBackendPdfClass))
46 #define GTK_IS_PRINT_BACKEND_PDF_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PRINT_BACKEND_PDF))
47 #define GTK_PRINT_BACKEND_PDF_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PRINT_BACKEND_PDF, GtkPrintBackendPdfClass))
48
49 #define _PDF_MAX_CHUNK_SIZE 8192
50
51 static GType print_backend_pdf_type = 0;
52
53 struct _GtkPrintBackendPdfClass
54 {
55   GtkPrintBackendClass parent_class;
56 };
57
58 struct _GtkPrintBackendPdf
59 {
60   GtkPrintBackend parent_instance;
61 };
62
63 static GObjectClass *backend_parent_class;
64
65 static void                 gtk_print_backend_pdf_class_init      (GtkPrintBackendPdfClass *class);
66 static void                 gtk_print_backend_pdf_init            (GtkPrintBackendPdf      *impl);
67 static void                 pdf_printer_get_settings_from_options (GtkPrinter              *printer,
68                                                                    GtkPrinterOptionSet     *options,
69                                                                    GtkPrintSettings        *settings);
70 static GtkPrinterOptionSet *pdf_printer_get_options               (GtkPrinter              *printer,
71                                                                    GtkPrintSettings        *settings,
72                                                                    GtkPageSetup            *page_setup);
73 static void                 pdf_printer_prepare_for_print         (GtkPrinter              *printer,
74                                                                    GtkPrintJob             *print_job,
75                                                                    GtkPrintSettings        *settings,
76                                                                    GtkPageSetup            *page_setup);
77 static void                 gtk_print_backend_pdf_print_stream    (GtkPrintBackend         *print_backend,
78                                                                    GtkPrintJob             *job,
79                                                                    gint                     data_fd,
80                                                                    GtkPrintJobCompleteFunc  callback,
81                                                                    gpointer                 user_data,
82                                                                    GDestroyNotify           dnotify);
83 static cairo_surface_t *    pdf_printer_create_cairo_surface      (GtkPrinter              *printer,
84                                                                    gdouble                  width,
85                                                                    gdouble                  height,
86                                                                    gint                     cache_fd);
87
88 static void
89 gtk_print_backend_pdf_register_type (GTypeModule *module)
90 {
91   static const GTypeInfo print_backend_pdf_info =
92   {
93     sizeof (GtkPrintBackendPdfClass),
94     NULL,               /* base_init */
95     NULL,               /* base_finalize */
96     (GClassInitFunc) gtk_print_backend_pdf_class_init,
97     NULL,               /* class_finalize */
98     NULL,               /* class_data */
99     sizeof (GtkPrintBackendPdf),
100     0,          /* n_preallocs */
101     (GInstanceInitFunc) gtk_print_backend_pdf_init,
102   };
103
104   print_backend_pdf_type = g_type_module_register_type (module,
105                                                         GTK_TYPE_PRINT_BACKEND,
106                                                         "GtkPrintBackendPdf",
107                                                         &print_backend_pdf_info, 0);
108 }
109
110 G_MODULE_EXPORT void 
111 pb_module_init (GTypeModule *module)
112 {
113   gtk_print_backend_pdf_register_type (module);
114 }
115
116 G_MODULE_EXPORT void 
117 pb_module_exit (void)
118 {
119
120 }
121   
122 G_MODULE_EXPORT GtkPrintBackend * 
123 pb_module_create (void)
124 {
125   return gtk_print_backend_pdf_new ();
126 }
127
128 /*
129  * GtkPrintBackendPdf
130  */
131 GType
132 gtk_print_backend_pdf_get_type (void)
133 {
134   return print_backend_pdf_type;
135 }
136
137 /**
138  * gtk_print_backend_pdf_new:
139  *
140  * Creates a new #GtkPrintBackendPdf object. #GtkPrintBackendPdf
141  * implements the #GtkPrintBackend interface with direct access to
142  * the filesystem using Unix/Linux API calls
143  *
144  * Return value: the new #GtkPrintBackendPdf object
145  **/
146 GtkPrintBackend *
147 gtk_print_backend_pdf_new (void)
148 {
149   return g_object_new (GTK_TYPE_PRINT_BACKEND_PDF, NULL);
150 }
151
152 static void
153 gtk_print_backend_pdf_class_init (GtkPrintBackendPdfClass *class)
154 {
155   GtkPrintBackendClass *backend_class = GTK_PRINT_BACKEND_CLASS (class);
156
157   backend_parent_class = g_type_class_peek_parent (class);
158
159   backend_class->print_stream = gtk_print_backend_pdf_print_stream;
160   backend_class->printer_create_cairo_surface = pdf_printer_create_cairo_surface;
161   backend_class->printer_get_options = pdf_printer_get_options;
162   backend_class->printer_get_settings_from_options = pdf_printer_get_settings_from_options;
163   backend_class->printer_prepare_for_print = pdf_printer_prepare_for_print;
164 }
165
166 static cairo_status_t
167 _cairo_write (void *cache_fd_as_pointer,
168               const unsigned char *data,
169               unsigned int         length)
170 {
171   cairo_status_t result;
172   gint cache_fd;
173   cache_fd = GPOINTER_TO_INT (cache_fd_as_pointer);
174   
175   result = CAIRO_STATUS_WRITE_ERROR;
176   
177   /* write out the buffer */
178   if (write (cache_fd, data, length) != -1)
179       result = CAIRO_STATUS_SUCCESS;
180    
181   return result;
182 }
183
184
185 static cairo_surface_t *
186 pdf_printer_create_cairo_surface (GtkPrinter *printer,
187                                    gdouble width, 
188                                    gdouble height,
189                                    gint cache_fd)
190 {
191   cairo_surface_t *surface;
192   
193   surface = cairo_pdf_surface_create_for_stream  (_cairo_write, GINT_TO_POINTER (cache_fd), width, height);
194
195   /* TODO: DPI from settings object? */
196   cairo_surface_set_fallback_resolution (surface, 300, 300);
197
198   return surface;
199 }
200
201 typedef struct {
202   GtkPrintBackend *backend;
203   GtkPrintJobCompleteFunc callback;
204   GtkPrintJob *job;
205   gint target_fd;
206   gpointer user_data;
207   GDestroyNotify dnotify;
208 } _PrintStreamData;
209
210 static void
211 pdf_print_cb (GtkPrintBackendPdf *print_backend,
212               GError *error,
213               gpointer user_data)
214 {
215   _PrintStreamData *ps = (_PrintStreamData *) user_data;
216
217   if (ps->target_fd > 0)
218     close (ps->target_fd);
219
220   if (ps->callback)
221     ps->callback (ps->job, ps->user_data, error);
222
223   if (ps->dnotify)
224     ps->dnotify (ps->user_data);
225
226   gtk_print_job_set_status (ps->job,
227                             (error != NULL)?GTK_PRINT_STATUS_FINISHED_ABORTED:GTK_PRINT_STATUS_FINISHED);
228
229   if (ps->job)
230     g_object_unref (ps->job);
231  
232   g_free (ps);
233 }
234
235 static gboolean
236 pdf_write (GIOChannel *source,
237            GIOCondition con,
238            gpointer user_data)
239 {
240   gchar buf[_PDF_MAX_CHUNK_SIZE];
241   gsize bytes_read;
242   GError *error;
243   _PrintStreamData *ps = (_PrintStreamData *) user_data;
244   gint source_fd;
245
246   error = NULL;
247
248   source_fd = g_io_channel_unix_get_fd (source);
249
250   bytes_read = read (source_fd,
251                      buf,
252                      _PDF_MAX_CHUNK_SIZE);
253
254    
255
256   if (bytes_read > 0)
257     {
258       if (write (ps->target_fd, buf, bytes_read) == -1)
259         {
260           error = g_error_new (GTK_PRINT_ERROR,
261                            GTK_PRINT_ERROR_INTERNAL_ERROR, 
262                            g_strerror (errno));
263         }
264     }
265   else if (bytes_read == -1)
266     {
267       error = g_error_new (GTK_PRINT_ERROR,
268                            GTK_PRINT_ERROR_INTERNAL_ERROR, 
269                            g_strerror (errno));
270     }
271
272   if (bytes_read == 0 || error != NULL)
273     {
274       pdf_print_cb (GTK_PRINT_BACKEND_PDF (ps->backend), error, user_data);
275
276       return FALSE;
277     }
278
279   return TRUE;
280 }
281
282 static void
283 gtk_print_backend_pdf_print_stream (GtkPrintBackend *print_backend,
284                                     GtkPrintJob *job,
285                                     gint data_fd,
286                                     GtkPrintJobCompleteFunc callback,
287                                     gpointer user_data,
288                                     GDestroyNotify dnotify)
289 {
290   GError *error;
291   GtkPrinter *printer;
292   _PrintStreamData *ps;
293   GtkPrintSettings *settings;
294   GIOChannel *save_channel;  
295   const char *filename;
296
297   printer = gtk_print_job_get_printer (job);
298   settings = gtk_print_job_get_settings (job);
299
300   error = NULL;
301
302   filename = gtk_print_settings_get (settings, "pdf-filename");
303   if (filename == NULL)
304     filename = "output.pdf";
305   
306   ps = g_new0 (_PrintStreamData, 1);
307   ps->callback = callback;
308   ps->user_data = user_data;
309   ps->dnotify = dnotify;
310   ps->job = g_object_ref (job);
311
312   ps->target_fd = creat (filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
313   ps->backend = print_backend;
314
315   if (ps->target_fd == -1)
316     {
317       error = g_error_new (GTK_PRINT_ERROR,
318                            GTK_PRINT_ERROR_INTERNAL_ERROR, 
319                            g_strerror (errno));
320
321       pdf_print_cb (GTK_PRINT_BACKEND_PDF (print_backend),
322                     error,
323                     ps);
324
325       return;
326     }
327   
328   save_channel = g_io_channel_unix_new (data_fd);
329
330   g_io_add_watch (save_channel, 
331                   G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP,
332                   (GIOFunc) pdf_write,
333                   ps);
334 }
335
336 static void
337 gtk_print_backend_pdf_init (GtkPrintBackendPdf *backend)
338 {
339   GtkPrinter *printer;
340   
341   printer = g_object_new (GTK_TYPE_PRINTER,
342                           "name", _("Print to PDF"),
343                           "backend", backend,
344                           "is-virtual", TRUE,
345                           "accepts-ps", FALSE,
346                           NULL); 
347
348   gtk_printer_set_has_details (printer, TRUE);
349   gtk_printer_set_icon_name (printer, "floppy");
350   gtk_printer_set_is_active (printer, TRUE);
351
352   gtk_print_backend_add_printer (GTK_PRINT_BACKEND (backend), printer);
353   g_object_unref (printer);
354
355   gtk_print_backend_set_list_done (GTK_PRINT_BACKEND (backend));
356 }
357
358 static GtkPrinterOptionSet *
359 pdf_printer_get_options (GtkPrinter *printer,
360                          GtkPrintSettings *settings,
361                          GtkPageSetup *page_setup)
362 {
363   GtkPrinterOptionSet *set;
364   GtkPrinterOption *option;
365   const char *filename;
366   char *n_up[] = {"1" };
367
368   set = gtk_printer_option_set_new ();
369
370   option = gtk_printer_option_new ("gtk-n-up", _("Pages Per Sheet"), GTK_PRINTER_OPTION_TYPE_PICKONE);
371   gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (n_up),
372                                          n_up, n_up);
373   gtk_printer_option_set (option, "1");
374   gtk_printer_option_set_add (set, option);
375   g_object_unref (option);
376
377   option = gtk_printer_option_new ("gtk-main-page-custom-input", _("File"), GTK_PRINTER_OPTION_TYPE_FILESAVE);
378   gtk_printer_option_set (option, "output.pdf");
379   option->group = g_strdup ("GtkPrintDialogExtention");
380   gtk_printer_option_set_add (set, option);
381
382   if (settings != NULL &&
383       (filename = gtk_print_settings_get (settings, "pdf-filename"))!= NULL)
384     gtk_printer_option_set (option, filename);
385
386   return set;
387 }
388
389 static void
390 pdf_printer_get_settings_from_options (GtkPrinter *printer,
391                                        GtkPrinterOptionSet *options,
392                                        GtkPrintSettings *settings)
393 {
394   GtkPrinterOption *option;
395
396   option = gtk_printer_option_set_lookup (options, "gtk-main-page-custom-input");
397   gtk_print_settings_set (settings, "pdf-filename", option->value);
398 }
399
400 static void
401 pdf_printer_prepare_for_print (GtkPrinter *printer,
402                                GtkPrintJob *print_job,
403                                GtkPrintSettings *settings,
404                                GtkPageSetup *page_setup)
405 {
406   double scale;
407
408   print_job->print_pages = gtk_print_settings_get_print_pages (settings);
409   print_job->page_ranges = NULL;
410   print_job->num_page_ranges = 0;
411   
412   if (print_job->print_pages == GTK_PRINT_PAGES_RANGES)
413     print_job->page_ranges =
414       gtk_print_settings_get_page_ranges (settings,
415                                           &print_job->num_page_ranges);
416   
417   print_job->collate = gtk_print_settings_get_collate (settings);
418   print_job->reverse = gtk_print_settings_get_reverse (settings);
419   print_job->num_copies = gtk_print_settings_get_n_copies (settings);
420
421   scale = gtk_print_settings_get_scale (settings);
422   if (scale != 100.0)
423     print_job->scale = scale/100.0;
424
425   print_job->page_set = gtk_print_settings_get_page_set (settings);
426   print_job->rotate_to_orientation = TRUE;
427 }