]> Pileus Git - ~andy/gtk/blob - modules/printbackends/lpr/gtkprintbackendlpr.c
Remove sealed members from GtkPrintJob
[~andy/gtk] / modules / printbackends / lpr / gtkprintbackendlpr.c
1 /* GTK - The GIMP Toolkit
2  * gtkprintbackendlpr.c: LPR implementation of GtkPrintBackend 
3  * for printing to lpr 
4  * Copyright (C) 2006, 2007 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 #include <unistd.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include <errno.h>
31 #include <cairo.h>
32 #include <cairo-ps.h>
33
34 #include <glib/gi18n-lib.h>
35
36 #include <gtk/gtk.h>
37 #include "gtkprinter-private.h"
38
39 #include "gtkprintbackendlpr.h"
40
41 typedef struct _GtkPrintBackendLprClass GtkPrintBackendLprClass;
42
43 #define GTK_PRINT_BACKEND_LPR_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PRINT_BACKEND_LPR, GtkPrintBackendLprClass))
44 #define GTK_IS_PRINT_BACKEND_LPR_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PRINT_BACKEND_LPR))
45 #define GTK_PRINT_BACKEND_LPR_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PRINT_BACKEND_LPR, GtkPrintBackendLprClass))
46
47 #define _LPR_MAX_CHUNK_SIZE 8192
48
49 static GType print_backend_lpr_type = 0;
50
51 struct _GtkPrintBackendLprClass
52 {
53   GtkPrintBackendClass parent_class;
54 };
55
56 struct _GtkPrintBackendLpr
57 {
58   GtkPrintBackend parent_instance;
59 };
60
61 static GObjectClass *backend_parent_class;
62
63 static void                 gtk_print_backend_lpr_class_init      (GtkPrintBackendLprClass *class);
64 static void                 gtk_print_backend_lpr_init            (GtkPrintBackendLpr      *impl);
65 static void                 lpr_printer_get_settings_from_options (GtkPrinter              *printer,
66                                                                    GtkPrinterOptionSet     *options,
67                                                                    GtkPrintSettings        *settings);
68 static GtkPrinterOptionSet *lpr_printer_get_options               (GtkPrinter              *printer,
69                                                                    GtkPrintSettings        *settings,
70                                                                    GtkPageSetup            *page_setup,
71                                                                    GtkPrintCapabilities     capabilities);
72 static void                 lpr_printer_prepare_for_print         (GtkPrinter              *printer,
73                                                                    GtkPrintJob             *print_job,
74                                                                    GtkPrintSettings        *settings,
75                                                                    GtkPageSetup            *page_setup);
76 static cairo_surface_t *    lpr_printer_create_cairo_surface      (GtkPrinter              *printer,
77                                                                    GtkPrintSettings        *settings,
78                                                                    gdouble                  width,
79                                                                    gdouble                  height,
80                                                                    GIOChannel              *cache_io);
81 static void                 gtk_print_backend_lpr_print_stream    (GtkPrintBackend         *print_backend,
82                                                                    GtkPrintJob             *job,
83                                                                    GIOChannel              *data_io,
84                                                                    GtkPrintJobCompleteFunc  callback,
85                                                                    gpointer                 user_data,
86                                                                    GDestroyNotify           dnotify);
87
88 static void
89 gtk_print_backend_lpr_register_type (GTypeModule *module)
90 {
91   const GTypeInfo print_backend_lpr_info =
92   {
93     sizeof (GtkPrintBackendLprClass),
94     NULL,               /* base_init */
95     NULL,               /* base_finalize */
96     (GClassInitFunc) gtk_print_backend_lpr_class_init,
97     NULL,               /* class_finalize */
98     NULL,               /* class_data */
99     sizeof (GtkPrintBackendLpr),
100     0,          /* n_preallocs */
101     (GInstanceInitFunc) gtk_print_backend_lpr_init,
102   };
103
104   print_backend_lpr_type = g_type_module_register_type (module,
105                                                         GTK_TYPE_PRINT_BACKEND,
106                                                         "GtkPrintBackendLpr",
107                                                         &print_backend_lpr_info, 0);
108 }
109
110 G_MODULE_EXPORT void 
111 pb_module_init (GTypeModule *module)
112 {
113   gtk_print_backend_lpr_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_lpr_new ();
126 }
127
128 /*
129  * GtkPrintBackendLpr
130  */
131 GType
132 gtk_print_backend_lpr_get_type (void)
133 {
134   return print_backend_lpr_type;
135 }
136
137 /**
138  * gtk_print_backend_lpr_new:
139  *
140  * Creates a new #GtkPrintBackendLpr object. #GtkPrintBackendLpr
141  * implements the #GtkPrintBackend interface with direct access to
142  * the filesystem using Unix/Linux API calls
143  *
144  * Return value: the new #GtkPrintBackendLpr object
145  **/
146 GtkPrintBackend *
147 gtk_print_backend_lpr_new (void)
148 {
149   return g_object_new (GTK_TYPE_PRINT_BACKEND_LPR, NULL);
150 }
151
152 static void
153 gtk_print_backend_lpr_class_init (GtkPrintBackendLprClass *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_lpr_print_stream;
160   backend_class->printer_create_cairo_surface = lpr_printer_create_cairo_surface;
161   backend_class->printer_get_options = lpr_printer_get_options;
162   backend_class->printer_get_settings_from_options = lpr_printer_get_settings_from_options;
163   backend_class->printer_prepare_for_print = lpr_printer_prepare_for_print;
164 }
165
166 static cairo_status_t
167 _cairo_write (void                *closure,
168               const unsigned char *data,
169               unsigned int         length)
170 {
171   GIOChannel *io = (GIOChannel *)closure;
172   gsize written;
173   GError *error;
174
175   error = NULL;
176
177   GTK_NOTE (PRINTING,
178             g_print ("LPR Backend: Writting %i byte chunk to temp file\n", length));
179
180   while (length > 0) 
181     {
182       g_io_channel_write_chars (io, (const gchar*)data, length, &written, &error);
183
184       if (error != NULL)
185         {
186           GTK_NOTE (PRINTING,
187                      g_print ("LPR Backend: Error writting to temp file, %s\n", error->message));
188
189           g_error_free (error);
190           return CAIRO_STATUS_WRITE_ERROR;
191         }    
192
193       GTK_NOTE (PRINTING,
194                 g_print ("LPR Backend: Wrote %" G_GSIZE_FORMAT " bytes to temp file\n", written));
195
196       data += written;
197       length -= written;
198     }
199
200   return CAIRO_STATUS_SUCCESS;
201 }
202
203 static cairo_surface_t *
204 lpr_printer_create_cairo_surface (GtkPrinter       *printer,
205                                   GtkPrintSettings *settings,
206                                   gdouble           width, 
207                                   gdouble           height,
208                                   GIOChannel       *cache_io)
209 {
210   cairo_surface_t *surface;
211   
212   surface = cairo_ps_surface_create_for_stream (_cairo_write, cache_io, width, height);
213
214   cairo_surface_set_fallback_resolution (surface,
215                                          2.0 * gtk_print_settings_get_printer_lpi (settings),
216                                          2.0 * gtk_print_settings_get_printer_lpi (settings));
217
218   return surface;
219 }
220
221 typedef struct {
222   GtkPrintBackend *backend;
223   GtkPrintJobCompleteFunc callback;
224   GtkPrintJob *job;
225   gpointer user_data;
226   GDestroyNotify dnotify;
227
228   GIOChannel *in;
229 } _PrintStreamData;
230
231 static void
232 lpr_print_cb (GtkPrintBackendLpr *print_backend,
233               GError             *error,
234               gpointer            user_data)
235 {
236   _PrintStreamData *ps = (_PrintStreamData *) user_data;
237
238   if (ps->in != NULL) 
239     g_io_channel_unref (ps->in);
240
241   if (ps->callback)
242     ps->callback (ps->job, ps->user_data, error);
243
244   if (ps->dnotify)
245     ps->dnotify (ps->user_data);
246
247   gtk_print_job_set_status (ps->job, 
248                             error ? GTK_PRINT_STATUS_FINISHED_ABORTED 
249                                   : GTK_PRINT_STATUS_FINISHED);
250
251   if (ps->job)
252     g_object_unref (ps->job);
253   
254   g_free (ps);
255 }
256
257 static gboolean
258 lpr_write (GIOChannel   *source,
259            GIOCondition  con,
260            gpointer      user_data)
261 {
262   gchar buf[_LPR_MAX_CHUNK_SIZE];
263   gsize bytes_read;
264   GError *error;
265   GIOStatus status;
266   _PrintStreamData *ps = (_PrintStreamData *) user_data;
267
268   error = NULL;
269
270   status = 
271     g_io_channel_read_chars (source,
272                              buf,
273                              _LPR_MAX_CHUNK_SIZE,
274                              &bytes_read,
275                              &error);
276
277   if (status != G_IO_STATUS_ERROR)
278     {
279       gsize bytes_written;
280
281       g_io_channel_write_chars (ps->in,
282                                 buf, 
283                                 bytes_read, 
284                                 &bytes_written, 
285                                 &error);
286     }
287
288   if (error != NULL || status == G_IO_STATUS_EOF)
289     {
290       lpr_print_cb (GTK_PRINT_BACKEND_LPR (ps->backend), 
291                     error, user_data);
292
293
294       if (error != NULL)
295         {
296           GTK_NOTE (PRINTING,
297                     g_print ("LPR Backend: %s\n", error->message));
298
299           g_error_free (error);
300         } 
301
302       return FALSE;
303     }
304
305   GTK_NOTE (PRINTING,
306             g_print ("LPR Backend: Writting %" G_GSIZE_FORMAT " byte chunk to lpr pipe\n", bytes_read));
307
308
309   return TRUE;
310 }
311
312 #define LPR_COMMAND "lpr"
313
314 static void
315 gtk_print_backend_lpr_print_stream (GtkPrintBackend        *print_backend,
316                                     GtkPrintJob            *job,
317                                     GIOChannel             *data_io,
318                                     GtkPrintJobCompleteFunc callback,
319                                     gpointer                user_data,
320                                     GDestroyNotify          dnotify)
321 {
322   GError *print_error = NULL;
323   _PrintStreamData *ps;
324   GtkPrintSettings *settings;
325   gint argc;
326   gint in_fd;
327   gchar **argv = NULL;
328   const char *cmd_line;
329
330   settings = gtk_print_job_get_settings (job);
331
332   cmd_line = gtk_print_settings_get (settings, "lpr-commandline");
333   if (cmd_line == NULL)
334     cmd_line = LPR_COMMAND;
335
336   ps = g_new0 (_PrintStreamData, 1);
337   ps->callback = callback;
338   ps->user_data = user_data;
339   ps->dnotify = dnotify;
340   ps->job = g_object_ref (job);
341   ps->in = NULL;
342
343  /* spawn lpr with pipes and pipe ps file to lpr */
344   if (!g_shell_parse_argv (cmd_line, &argc, &argv, &print_error))
345     goto out;
346
347   if (!g_spawn_async_with_pipes (NULL,
348                                  argv,
349                                  NULL,
350                                  G_SPAWN_SEARCH_PATH,
351                                  NULL,
352                                  NULL,
353                                  NULL,
354                                  &in_fd,
355                                  NULL,
356                                  NULL,
357                                  &print_error))
358       goto out;
359
360   ps->in = g_io_channel_unix_new (in_fd);
361
362   g_io_channel_set_encoding (ps->in, NULL, &print_error);
363   if (print_error != NULL)
364     {
365       if (ps->in != NULL)
366         g_io_channel_unref (ps->in);
367
368       goto out;
369     }
370
371   g_io_channel_set_close_on_unref (ps->in, TRUE);
372
373   g_io_add_watch (data_io,
374                   G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP,
375                   (GIOFunc) lpr_write,
376                   ps);
377
378  out:
379   if (argv != NULL)
380     g_strfreev (argv);
381
382   if (print_error != NULL)
383     {
384       lpr_print_cb (GTK_PRINT_BACKEND_LPR (print_backend),
385                     print_error, ps);
386       g_error_free (print_error);
387     }
388 }
389
390 static void
391 gtk_print_backend_lpr_init (GtkPrintBackendLpr *backend)
392 {
393   GtkPrinter *printer;
394
395   printer = gtk_printer_new (_("Print to LPR"),
396                              GTK_PRINT_BACKEND (backend),
397                              TRUE); 
398   gtk_printer_set_has_details (printer, TRUE);
399   gtk_printer_set_icon_name (printer, "printer");
400   gtk_printer_set_is_active (printer, TRUE);
401   gtk_printer_set_is_default (printer, TRUE);
402
403   gtk_print_backend_add_printer (GTK_PRINT_BACKEND (backend), printer);
404   g_object_unref (printer);
405   gtk_print_backend_set_list_done (GTK_PRINT_BACKEND (backend));
406 }
407
408 static GtkPrinterOptionSet *
409 lpr_printer_get_options (GtkPrinter           *printer,
410                          GtkPrintSettings     *settings,
411                          GtkPageSetup         *page_setup,
412                          GtkPrintCapabilities  capabilities)
413 {
414   GtkPrinterOptionSet *set;
415   GtkPrinterOption *option;
416   const char *command;
417   char *n_up[] = {"1", "2", "4", "6", "9", "16" };
418
419   set = gtk_printer_option_set_new ();
420
421   option = gtk_printer_option_new ("gtk-n-up", _("Pages Per Sheet"), GTK_PRINTER_OPTION_TYPE_PICKONE);
422   gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (n_up),
423                                          n_up, n_up);
424   gtk_printer_option_set (option, "1");
425   gtk_printer_option_set_add (set, option);
426   g_object_unref (option);
427
428   option = gtk_printer_option_new ("gtk-main-page-custom-input", _("Command Line"), GTK_PRINTER_OPTION_TYPE_STRING);
429   gtk_printer_option_set_activates_default (option, TRUE);
430   option->group = g_strdup ("GtkPrintDialogExtension");
431   if (settings != NULL &&
432       (command = gtk_print_settings_get (settings, "lpr-commandline"))!= NULL)
433     gtk_printer_option_set (option, command);
434   else
435     gtk_printer_option_set (option, LPR_COMMAND);
436   gtk_printer_option_set_add (set, option);
437     
438   return set;
439 }
440
441 static void
442 lpr_printer_get_settings_from_options (GtkPrinter          *printer,
443                                        GtkPrinterOptionSet *options,
444                                        GtkPrintSettings    *settings)
445 {
446   GtkPrinterOption *option;
447
448   option = gtk_printer_option_set_lookup (options, "gtk-main-page-custom-input");
449   if (option)
450     gtk_print_settings_set (settings, "lpr-commandline", option->value);
451
452   option = gtk_printer_option_set_lookup (options, "gtk-n-up");
453   if (option)
454     gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_NUMBER_UP, option->value);
455
456   option = gtk_printer_option_set_lookup (options, "gtk-n-up-layout");
457   if (option)
458     gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_NUMBER_UP_LAYOUT, option->value);
459 }
460
461 static void
462 lpr_printer_prepare_for_print (GtkPrinter       *printer,
463                                GtkPrintJob      *print_job,
464                                GtkPrintSettings *settings,
465                                GtkPageSetup     *page_setup)
466 {
467   double scale;
468   GtkPrintPages pages;
469   GtkPageRange *ranges;
470   gint n_ranges;
471
472   pages = gtk_print_settings_get_print_pages (settings);
473   gtk_print_job_set_pages (print_job, pages);
474
475   if (pages == GTK_PRINT_PAGES_RANGES)
476     ranges = gtk_print_settings_get_page_ranges (settings, &n_ranges);
477   else
478     {
479       ranges = NULL;
480       n_ranges = 0;
481     }
482
483   gtk_print_job_set_page_ranges (print_job, ranges, n_ranges);
484   gtk_print_job_set_collate (print_job, gtk_print_settings_get_collate (settings));
485   gtk_print_job_set_reverse (print_job, gtk_print_settings_get_reverse (settings));
486   gtk_print_job_set_num_copies (print_job, gtk_print_settings_get_n_copies (settings));
487   gtk_print_job_set_n_up (print_job, gtk_print_settings_get_number_up (settings));
488   gtk_print_job_set_n_up_layout (print_job, gtk_print_settings_get_number_up_layout (settings));
489
490   scale = gtk_print_settings_get_scale (settings);
491   if (scale != 100.0)
492     gtk_print_job_set_scale (print_job, scale / 100.0);
493
494   gtk_print_job_set_page_set (print_job, gtk_print_settings_get_page_set (settings));
495   gtk_print_job_set_rotate (print_job, TRUE);
496 }