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