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
gtk_print_backend_lpr_register_type(GTypeModule * module)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
pb_module_init(GTypeModule * module)111 pb_module_init (GTypeModule *module)
112 {
113 gtk_print_backend_lpr_register_type (module);
114 }
115
116 G_MODULE_EXPORT void
pb_module_exit(void)117 pb_module_exit (void)
118 {
119
120 }
121
122 G_MODULE_EXPORT GtkPrintBackend *
pb_module_create(void)123 pb_module_create (void)
124 {
125 return gtk_print_backend_lpr_new ();
126 }
127
128 /*
129 * GtkPrintBackendLpr
130 */
131 GType
gtk_print_backend_lpr_get_type(void)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 *
gtk_print_backend_lpr_new(void)147 gtk_print_backend_lpr_new (void)
148 {
149 return g_object_new (GTK_TYPE_PRINT_BACKEND_LPR, NULL);
150 }
151
152 static void
gtk_print_backend_lpr_class_init(GtkPrintBackendLprClass * class)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
_cairo_write(void * closure,const unsigned char * data,unsigned int length)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 *
lpr_printer_create_cairo_surface(GtkPrinter * printer,GtkPrintSettings * settings,gdouble width,gdouble height,GIOChannel * cache_io)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
lpr_print_cb(GtkPrintBackendLpr * print_backend,GError * error,gpointer user_data)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
lpr_write(GIOChannel * source,GIOCondition con,gpointer user_data)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
gtk_print_backend_lpr_print_stream(GtkPrintBackend * print_backend,GtkPrintJob * job,GIOChannel * data_io,GtkPrintJobCompleteFunc callback,gpointer user_data,GDestroyNotify dnotify)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
gtk_print_backend_lpr_init(GtkPrintBackendLpr * backend)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, "gtk-print");
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 *
lpr_printer_get_options(GtkPrinter * printer,GtkPrintSettings * settings,GtkPageSetup * page_setup,GtkPrintCapabilities capabilities)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
lpr_printer_get_settings_from_options(GtkPrinter * printer,GtkPrinterOptionSet * options,GtkPrintSettings * settings)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
lpr_printer_prepare_for_print(GtkPrinter * printer,GtkPrintJob * print_job,GtkPrintSettings * settings,GtkPageSetup * page_setup)462 lpr_printer_prepare_for_print (GtkPrinter *printer,
463 GtkPrintJob *print_job,
464 GtkPrintSettings *settings,
465 GtkPageSetup *page_setup)
466 {
467 double scale;
468
469 print_job->print_pages = gtk_print_settings_get_print_pages (settings);
470 print_job->page_ranges = NULL;
471 print_job->num_page_ranges = 0;
472
473 if (print_job->print_pages == GTK_PRINT_PAGES_RANGES)
474 print_job->page_ranges =
475 gtk_print_settings_get_page_ranges (settings,
476 &print_job->num_page_ranges);
477
478 print_job->collate = gtk_print_settings_get_collate (settings);
479 print_job->reverse = gtk_print_settings_get_reverse (settings);
480 print_job->num_copies = gtk_print_settings_get_n_copies (settings);
481 print_job->number_up = gtk_print_settings_get_number_up (settings);
482 print_job->number_up_layout = gtk_print_settings_get_number_up_layout (settings);
483
484 scale = gtk_print_settings_get_scale (settings);
485 if (scale != 100.0)
486 print_job->scale = scale/100.0;
487
488 print_job->page_set = gtk_print_settings_get_page_set (settings);
489 print_job->rotate_to_orientation = TRUE;
490 }
491