]> Pileus Git - ~andy/gtk/blob - modules/printbackends/lpr/gtkprintbackendlpr.c
Merge the gtk-printing branch. For more detailed ChangeLog entries, see
[~andy/gtk] / modules / printbackends / lpr / gtkprintbackendlpr.c
1 /* GTK - The GIMP Toolkit
2  * gtkprintbackendlpr.c: Default implementation of GtkPrintBackend 
3  * for printing to lpr 
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-ps.h>
33
34 #include <glib/gi18n-lib.h>
35
36 #include "gtkprintoperation.h"
37
38 #include "gtkprintbackendlpr.h"
39
40 #include "gtkprinter.h"
41
42 typedef struct _GtkPrintBackendLprClass GtkPrintBackendLprClass;
43
44 #define GTK_PRINT_BACKEND_LPR_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PRINT_BACKEND_LPR, GtkPrintBackendLprClass))
45 #define GTK_IS_PRINT_BACKEND_LPR_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PRINT_BACKEND_LPR))
46 #define GTK_PRINT_BACKEND_LPR_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PRINT_BACKEND_LPR, GtkPrintBackendLprClass))
47
48 #define _LPR_MAX_CHUNK_SIZE 8192
49
50 static GType print_backend_lpr_type = 0;
51
52 struct _GtkPrintBackendLprClass
53 {
54   GObjectClass parent_class;
55 };
56
57 struct _GtkPrintBackendLpr
58 {
59   GObject parent_instance;
60
61   GtkPrinter *printer;
62
63   GHashTable *printers;
64 };
65
66 static GObjectClass *backend_parent_class;
67
68 static void                 gtk_print_backend_lpr_class_init      (GtkPrintBackendLprClass *class);
69 static void                 gtk_print_backend_lpr_iface_init      (GtkPrintBackendIface    *iface);
70 static void                 gtk_print_backend_lpr_init            (GtkPrintBackendLpr      *impl);
71 static void                 gtk_print_backend_lpr_finalize        (GObject                 *object);
72 static GList *              lpr_request_printer_list              (GtkPrintBackend         *print_backend);
73 static void                 lpr_printer_get_settings_from_options (GtkPrinter              *printer,
74                                                                    GtkPrinterOptionSet     *options,
75                                                                    GtkPrintSettings        *settings);
76 static gboolean             lpr_printer_mark_conflicts            (GtkPrinter              *printer,
77                                                                    GtkPrinterOptionSet     *options);
78 static GtkPrinterOptionSet *lpr_printer_get_options               (GtkPrinter              *printer,
79                                                                    GtkPrintSettings        *settings,
80                                                                    GtkPageSetup            *page_setup);
81 static void                 lpr_printer_prepare_for_print         (GtkPrinter              *printer,
82                                                                    GtkPrintJob             *print_job,
83                                                                    GtkPrintSettings        *settings,
84                                                                    GtkPageSetup            *page_setup);
85 static void                 lpr_printer_get_hard_margins          (GtkPrinter              *printer,
86                                                                    double                  *top,
87                                                                    double                  *bottom,
88                                                                    double                  *left,
89                                                                    double                  *right);
90 static void                 lpr_printer_request_details           (GtkPrinter              *printer);
91 static GList *              lpr_printer_list_papers               (GtkPrinter              *printer);
92
93 static void
94 gtk_print_backend_lpr_register_type (GTypeModule *module)
95 {
96   if (!print_backend_lpr_type)
97     {
98       static const GTypeInfo print_backend_lpr_info =
99       {
100         sizeof (GtkPrintBackendLprClass),
101         NULL,           /* base_init */
102         NULL,           /* base_finalize */
103         (GClassInitFunc) gtk_print_backend_lpr_class_init,
104         NULL,           /* class_finalize */
105         NULL,           /* class_data */
106         sizeof (GtkPrintBackendLpr),
107         0,              /* n_preallocs */
108         (GInstanceInitFunc) gtk_print_backend_lpr_init,
109       };
110
111       static const GInterfaceInfo print_backend_info =
112       {
113         (GInterfaceInitFunc) gtk_print_backend_lpr_iface_init, /* interface_init */
114         NULL,                                                 /* interface_finalize */
115         NULL                                                  /* interface_data */
116       };
117
118       print_backend_lpr_type = g_type_module_register_type (module,
119                                                              G_TYPE_OBJECT,
120                                                              "GtkPrintBackendLpr",
121                                                              &print_backend_lpr_info, 0);
122       g_type_module_add_interface (module,
123                                    print_backend_lpr_type,
124                                    GTK_TYPE_PRINT_BACKEND,
125                                    &print_backend_info);
126     }
127
128
129 }
130
131 G_MODULE_EXPORT void 
132 pb_module_init (GTypeModule *module)
133 {
134   gtk_print_backend_lpr_register_type (module);
135 }
136
137 G_MODULE_EXPORT void 
138 pb_module_exit (void)
139 {
140
141 }
142   
143 G_MODULE_EXPORT GtkPrintBackend * 
144 pb_module_create (void)
145 {
146   return gtk_print_backend_lpr_new ();
147 }
148
149 /*
150  * GtkPrintBackendLpr
151  */
152 GType
153 gtk_print_backend_lpr_get_type (void)
154 {
155   return print_backend_lpr_type;
156 }
157
158 /**
159  * gtk_print_backend_lpr_new:
160  *
161  * Creates a new #GtkPrintBackendLpr object. #GtkPrintBackendLpr
162  * implements the #GtkPrintBackend interface with direct access to
163  * the filesystem using Unix/Linux API calls
164  *
165  * Return value: the new #GtkPrintBackendLpr object
166  **/
167 GtkPrintBackend *
168 gtk_print_backend_lpr_new (void)
169 {
170   return g_object_new (GTK_TYPE_PRINT_BACKEND_LPR, NULL);
171 }
172
173 static void
174 gtk_print_backend_lpr_class_init (GtkPrintBackendLprClass *class)
175 {
176   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
177
178   backend_parent_class = g_type_class_peek_parent (class);
179
180   gobject_class->finalize = gtk_print_backend_lpr_finalize;
181 }
182
183 static cairo_status_t
184 _cairo_write (void *cache_fd_as_pointer,
185               const unsigned char *data,
186               unsigned int         length)
187 {
188   cairo_status_t result;
189   gint cache_fd;
190   cache_fd = GPOINTER_TO_INT (cache_fd_as_pointer);
191   
192   result = CAIRO_STATUS_WRITE_ERROR;
193   
194   /* write out the buffer */
195   if (write (cache_fd, data, length) != -1)
196       result = CAIRO_STATUS_SUCCESS;
197    
198   return result;
199 }
200
201
202 static cairo_surface_t *
203 lpr_printer_create_cairo_surface (GtkPrinter *printer,
204                                    gdouble width, 
205                                    gdouble height,
206                                    gint cache_fd)
207 {
208   cairo_surface_t *surface;
209   
210   surface = cairo_ps_surface_create_for_stream  (_cairo_write, GINT_TO_POINTER (cache_fd), width, height);
211
212   /* TODO: DPI from settings object? */
213   cairo_ps_surface_set_dpi (surface, 300, 300);
214
215   return surface;
216 }
217
218 static GtkPrinter *
219 gtk_print_backend_lpr_find_printer (GtkPrintBackend *print_backend,
220                                      const gchar *printer_name)
221 {
222   GtkPrintBackendLpr *lpr_print_backend;
223   GtkPrinter *printer;
224
225   lpr_print_backend = GTK_PRINT_BACKEND_LPR (print_backend);
226   
227   printer = NULL;
228   if (strcmp (gtk_printer_get_name (lpr_print_backend->printer), printer_name) == 0)
229     printer = lpr_print_backend->printer;
230
231   return printer; 
232 }
233
234 typedef struct {
235   GtkPrintBackend *backend;
236   GtkPrintJobCompleteFunc callback;
237   GtkPrintJob *job;
238   gpointer user_data;
239   GDestroyNotify dnotify;
240
241   gint in;
242   gint out;
243   gint err;
244
245 } _PrintStreamData;
246
247 static void
248 lpr_print_cb (GtkPrintBackendLpr *print_backend,
249               GError *error,
250               gpointer user_data)
251 {
252   _PrintStreamData *ps = (_PrintStreamData *) user_data;
253
254   if (ps->in > 0)
255     close (ps->in);
256
257   if (ps->out > 0)
258     close (ps->out);
259
260   if (ps->err > 0)
261     close (ps->err);
262
263   if (ps->callback)
264     ps->callback (ps->job, ps->user_data, error);
265
266   if (ps->dnotify)
267     ps->dnotify (ps->user_data);
268
269   gtk_print_job_set_status (ps->job,
270                             (error != NULL)?GTK_PRINT_STATUS_FINISHED_ABORTED:GTK_PRINT_STATUS_FINISHED);
271
272   if (ps->job)
273     g_object_unref (ps->job);
274   
275   g_free (ps);
276 }
277
278 static gboolean
279 lpr_write (GIOChannel *source,
280            GIOCondition con,
281            gpointer user_data)
282 {
283   gchar buf[_LPR_MAX_CHUNK_SIZE];
284   gsize bytes_read;
285   GError *error;
286   _PrintStreamData *ps = (_PrintStreamData *) user_data;
287   gint source_fd;
288
289   error = NULL;
290
291   source_fd = g_io_channel_unix_get_fd (source);
292
293   bytes_read = read (source_fd,
294                      buf,
295                      _LPR_MAX_CHUNK_SIZE);
296
297   if (bytes_read > 0)
298     {
299       if (write (ps->in, buf, bytes_read) == -1)
300         {
301           error = g_error_new (GTK_PRINT_ERROR,
302                            GTK_PRINT_ERROR_INTERNAL_ERROR, 
303                            g_strerror (errno));
304         }
305     }
306   else if (bytes_read == -1)
307     {
308       error = g_error_new (GTK_PRINT_ERROR,
309                            GTK_PRINT_ERROR_INTERNAL_ERROR, 
310                            g_strerror (errno));
311     }
312
313   if (bytes_read == 0 || error != NULL)
314     {
315       lpr_print_cb (GTK_PRINT_BACKEND_LPR (ps->backend), error, user_data);
316
317       return FALSE;
318     }
319
320   return TRUE;
321 }
322
323 #define LPR_COMMAND "lpr"
324
325 static void
326 gtk_print_backend_lpr_print_stream (GtkPrintBackend *print_backend,
327                                     GtkPrintJob *job,
328                                     gint data_fd,
329                                     GtkPrintJobCompleteFunc callback,
330                                     gpointer user_data,
331                                     GDestroyNotify dnotify)
332 {
333   GError *error;
334   GtkPrinter *printer;
335   _PrintStreamData *ps;
336   GtkPrintSettings *settings;
337   GIOChannel *send_channel;
338   gint argc;  
339   gchar **argv;
340   const char *cmd_line;
341
342   printer = gtk_print_job_get_printer (job);
343   settings = gtk_print_job_get_settings (job);
344
345   error = NULL;
346
347   cmd_line = gtk_print_settings_get (settings, "lpr-commandline");
348   if (cmd_line == NULL)
349     cmd_line = LPR_COMMAND;
350   
351   ps = g_new0 (_PrintStreamData, 1);
352   ps->callback = callback;
353   ps->user_data = user_data;
354   ps->dnotify = dnotify;
355   ps->job = g_object_ref (job);
356   ps->in = 0;
357   ps->out = 0;
358   ps->err = 0;
359
360  /* spawn lpr with pipes and pipe ps file to lpr */
361   if (!g_shell_parse_argv (cmd_line,
362                            &argc,
363                            &argv,
364                            &error))
365     {
366       lpr_print_cb (GTK_PRINT_BACKEND_LPR (print_backend),
367                     error, ps);
368       return;
369     }
370
371   if (!g_spawn_async_with_pipes (NULL,
372                                  argv,
373                                  NULL,
374                                  G_SPAWN_SEARCH_PATH,
375                                  NULL,
376                                  NULL,
377                                  NULL,
378                                  &ps->in,
379                                  &ps->out,
380                                  &ps->err,
381                                  &error))
382     {
383        lpr_print_cb (GTK_PRINT_BACKEND_LPR (print_backend),
384                      error, ps);
385
386       goto out;
387
388     }
389
390   send_channel = g_io_channel_unix_new (data_fd);
391  
392   g_io_add_watch (send_channel, 
393                   G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP,
394                   (GIOFunc) lpr_write,
395                   ps);
396
397  out:
398   g_strfreev (argv);
399 }
400
401
402 static void
403 gtk_print_backend_lpr_iface_init (GtkPrintBackendIface *iface)
404 {
405   iface->get_printer_list = lpr_request_printer_list;
406   iface->find_printer = gtk_print_backend_lpr_find_printer;
407   iface->print_stream = gtk_print_backend_lpr_print_stream;
408   iface->printer_request_details = lpr_printer_request_details;
409   iface->printer_create_cairo_surface = lpr_printer_create_cairo_surface;
410   iface->printer_get_options = lpr_printer_get_options;
411   iface->printer_mark_conflicts = lpr_printer_mark_conflicts;
412   iface->printer_get_settings_from_options = lpr_printer_get_settings_from_options;
413   iface->printer_prepare_for_print = lpr_printer_prepare_for_print;
414   iface->printer_list_papers = lpr_printer_list_papers;
415   iface->printer_get_hard_margins = lpr_printer_get_hard_margins;
416 }
417
418 static GList *
419 lpr_request_printer_list (GtkPrintBackend *backend)
420 {
421   GList *l;
422   GtkPrintBackendLpr *lpr_backend;
423
424   l = NULL;
425
426   lpr_backend = GTK_PRINT_BACKEND_LPR (backend);
427   
428   if (lpr_backend->printer)
429     l = g_list_append (l, lpr_backend->printer);
430
431   return l; 
432 }
433
434 static void
435 gtk_print_backend_lpr_init (GtkPrintBackendLpr *backend_lpr)
436 {
437   GtkPrinter *printer;
438
439   printer = gtk_printer_new (_("Print to LPR"),
440                              GTK_PRINT_BACKEND (backend_lpr),
441                              TRUE); 
442   gtk_printer_set_has_details (printer, TRUE);
443   gtk_printer_set_icon_name (printer, "printer");
444   gtk_printer_set_is_active (printer, TRUE);
445   
446   backend_lpr->printer = printer;
447 }
448
449 static void
450 gtk_print_backend_lpr_finalize (GObject *object)
451 {
452   GtkPrintBackendLpr *backend_lpr;
453
454   backend_lpr = GTK_PRINT_BACKEND_LPR (object);
455
456   g_object_unref (backend_lpr->printer);
457
458   backend_parent_class->finalize (object);
459 }
460
461 static void
462 lpr_printer_request_details (GtkPrinter *printer)
463 {
464 }
465
466 static GtkPrinterOptionSet *
467 lpr_printer_get_options (GtkPrinter *printer,
468                          GtkPrintSettings *settings,
469                          GtkPageSetup *page_setup)
470 {
471   GtkPrinterOptionSet *set;
472   GtkPrinterOption *option;
473   const char *command;
474   char *n_up[] = {"1", "2", "4", "6", "9", "16" };
475
476   set = gtk_printer_option_set_new ();
477
478   option = gtk_printer_option_new ("gtk-n-up", _("Pages Per Sheet"), GTK_PRINTER_OPTION_TYPE_PICKONE);
479   gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (n_up),
480                                          n_up, n_up);
481   gtk_printer_option_set (option, "1");
482   gtk_printer_option_set_add (set, option);
483   g_object_unref (option);
484
485   option = gtk_printer_option_new ("gtk-main-page-custom-input", _("Command Line"), GTK_PRINTER_OPTION_TYPE_STRING);
486   option->group = g_strdup ("GtkPrintDialogExtention");
487   if (settings != NULL &&
488       (command = gtk_print_settings_get (settings, "lpr-commandline"))!= NULL)
489     gtk_printer_option_set (option, command);
490   else
491     gtk_printer_option_set (option, LPR_COMMAND);
492   gtk_printer_option_set_add (set, option);
493     
494   return set;
495 }
496
497
498 static gboolean
499 lpr_printer_mark_conflicts  (GtkPrinter          *printer,
500                              GtkPrinterOptionSet *options)
501 {
502   return FALSE;
503 }
504
505 static void
506 lpr_printer_get_settings_from_options (GtkPrinter *printer,
507                                        GtkPrinterOptionSet *options,
508                                        GtkPrintSettings *settings)
509 {
510   GtkPrinterOption *option;
511
512   option = gtk_printer_option_set_lookup (options, "gtk-main-page-custom-input");
513   gtk_print_settings_set (settings, "lpr-commandline", option->value);
514 }
515
516 static void
517 lpr_printer_prepare_for_print (GtkPrinter *printer,
518                                GtkPrintJob *print_job,
519                                GtkPrintSettings *settings,
520                                GtkPageSetup *page_setup)
521 {
522   double scale;
523
524   print_job->print_pages = gtk_print_settings_get_print_pages (settings);
525   print_job->page_ranges = NULL;
526   print_job->num_page_ranges = 0;
527   
528   if (print_job->print_pages == GTK_PRINT_PAGES_RANGES)
529     print_job->page_ranges =
530       gtk_print_settings_get_page_ranges (settings,
531                                           &print_job->num_page_ranges);
532   
533   print_job->collate = gtk_print_settings_get_collate (settings);
534   print_job->reverse = gtk_print_settings_get_reverse (settings);
535   print_job->num_copies = gtk_print_settings_get_num_copies (settings);
536
537   scale = gtk_print_settings_get_scale (settings);
538   if (scale != 100.0)
539     print_job->scale = scale/100.0;
540
541   print_job->page_set = gtk_print_settings_get_page_set (settings);
542   print_job->rotate_to_orientation = TRUE;
543 }
544
545 static void
546 lpr_printer_get_hard_margins (GtkPrinter *printer,
547                               double *top,
548                               double *bottom,
549                               double *left,
550                               double *right)
551 {
552   *top = 0;
553   *bottom = 0;
554   *left = 0;
555   *right = 0;
556 }
557
558 static GList *
559 lpr_printer_list_papers (GtkPrinter *printer)
560 {
561   return NULL;
562 }