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