1 /* GTK - The GIMP Toolkit
2 * gtkprintbackendpdf.c: Test implementation of GtkPrintBackend
3 * for printing to a test
4 * Copyright (C) 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
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 #include <cairo-ps.h>
35
36 #include <glib/gi18n-lib.h>
37
38 #include <gtk/gtkprintbackend.h>
39 #include <gtk/gtkunixprint.h>
40 #include <gtk/gtkprinter-private.h>
41
42 #include "gtkprintbackendtest.h"
43
44
45 typedef struct _GtkPrintBackendTestClass GtkPrintBackendTestClass;
46
47 #define GTK_PRINT_BACKEND_TEST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PRINT_BACKEND_TEST, GtkPrintBackendTestClass))
48 #define GTK_IS_PRINT_BACKEND_TEST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PRINT_BACKEND_TEST))
49 #define GTK_PRINT_BACKENDTEST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PRINT_BACKEND_TEST, GtkPrintBackendTestClass))
50
51 #define _STREAM_MAX_CHUNK_SIZE 8192
52
53 static GType print_backend_test_type = 0;
54
55 struct _GtkPrintBackendTestClass
56 {
57 GtkPrintBackendClass parent_class;
58 };
59
60 struct _GtkPrintBackendTest
61 {
62 GtkPrintBackend parent_instance;
63 };
64
65 typedef enum
66 {
67 FORMAT_PDF,
68 FORMAT_PS,
69 N_FORMATS
70 } OutputFormat;
71
72 static const gchar* formats[N_FORMATS] =
73 {
74 "pdf",
75 "ps"
76 };
77
78 static GObjectClass *backend_parent_class;
79
80 static void gtk_print_backend_test_class_init (GtkPrintBackendTestClass *class);
81 static void gtk_print_backend_test_init (GtkPrintBackendTest *impl);
82 static void test_printer_get_settings_from_options (GtkPrinter *printer,
83 GtkPrinterOptionSet *options,
84 GtkPrintSettings *settings);
85 static GtkPrinterOptionSet *test_printer_get_options (GtkPrinter *printer,
86 GtkPrintSettings *settings,
87 GtkPageSetup *page_setup,
88 GtkPrintCapabilities capabilities);
89 static void test_printer_prepare_for_print (GtkPrinter *printer,
90 GtkPrintJob *print_job,
91 GtkPrintSettings *settings,
92 GtkPageSetup *page_setup);
93 static void gtk_print_backend_test_print_stream (GtkPrintBackend *print_backend,
94 GtkPrintJob *job,
95 GIOChannel *data_io,
96 GtkPrintJobCompleteFunc callback,
97 gpointer user_data,
98 GDestroyNotify dnotify);
99 static cairo_surface_t * test_printer_create_cairo_surface (GtkPrinter *printer,
100 GtkPrintSettings *settings,
101 gdouble width,
102 gdouble height,
103 GIOChannel *cache_io);
104
105 static void test_printer_request_details (GtkPrinter *printer);
106
107 static void
gtk_print_backend_test_register_type(GTypeModule * module)108 gtk_print_backend_test_register_type (GTypeModule *module)
109 {
110 const GTypeInfo print_backend_test_info =
111 {
112 sizeof (GtkPrintBackendTestClass),
113 NULL, /* base_init */
114 NULL, /* base_finalize */
115 (GClassInitFunc) gtk_print_backend_test_class_init,
116 NULL, /* class_finalize */
117 NULL, /* class_data */
118 sizeof (GtkPrintBackendTest),
119 0, /* n_preallocs */
120 (GInstanceInitFunc) gtk_print_backend_test_init,
121 };
122
123 print_backend_test_type = g_type_module_register_type (module,
124 GTK_TYPE_PRINT_BACKEND,
125 "GtkPrintBackendTest",
126 &print_backend_test_info, 0);
127 }
128
129 G_MODULE_EXPORT void
pb_module_init(GTypeModule * module)130 pb_module_init (GTypeModule *module)
131 {
132 gtk_print_backend_test_register_type (module);
133 }
134
135 G_MODULE_EXPORT void
pb_module_exit(void)136 pb_module_exit (void)
137 {
138
139 }
140
141 G_MODULE_EXPORT GtkPrintBackend *
pb_module_create(void)142 pb_module_create (void)
143 {
144 return gtk_print_backend_test_new ();
145 }
146
147 /*
148 * GtkPrintBackendTest
149 */
150 GType
gtk_print_backend_test_get_type(void)151 gtk_print_backend_test_get_type (void)
152 {
153 return print_backend_test_type;
154 }
155
156 /**
157 * gtk_print_backend_test_new:
158 *
159 * Creates a new #GtkPrintBackendTest object. #GtkPrintBackendTest
160 * implements the #GtkPrintBackend interface with direct access to
161 * the testsystem using Unix/Linux API calls
162 *
163 * Return value: the new #GtkPrintBackendTest object
164 **/
165 GtkPrintBackend *
gtk_print_backend_test_new(void)166 gtk_print_backend_test_new (void)
167 {
168 return g_object_new (GTK_TYPE_PRINT_BACKEND_TEST, NULL);
169 }
170
171 static void
gtk_print_backend_test_class_init(GtkPrintBackendTestClass * class)172 gtk_print_backend_test_class_init (GtkPrintBackendTestClass *class)
173 {
174 GtkPrintBackendClass *backend_class = GTK_PRINT_BACKEND_CLASS (class);
175
176 backend_parent_class = g_type_class_peek_parent (class);
177
178 backend_class->print_stream = gtk_print_backend_test_print_stream;
179 backend_class->printer_create_cairo_surface = test_printer_create_cairo_surface;
180 backend_class->printer_get_options = test_printer_get_options;
181 backend_class->printer_get_settings_from_options = test_printer_get_settings_from_options;
182 backend_class->printer_prepare_for_print = test_printer_prepare_for_print;
183 backend_class->printer_request_details = test_printer_request_details;
184 }
185
186 /* return N_FORMATS if no explicit format in the settings */
187 static OutputFormat
format_from_settings(GtkPrintSettings * settings)188 format_from_settings (GtkPrintSettings *settings)
189 {
190 const gchar *value;
191 gint i;
192
193 if (settings == NULL)
194 return N_FORMATS;
195
196 value = gtk_print_settings_get (settings, GTK_PRINT_SETTINGS_OUTPUT_FILE_FORMAT);
197 if (value == NULL)
198 return N_FORMATS;
199
200 for (i = 0; i < N_FORMATS; ++i)
201 if (strcmp (value, formats[i]) == 0)
202 break;
203
204 g_assert (i < N_FORMATS);
205
206 return (OutputFormat) i;
207 }
208
209 static gchar *
output_test_from_settings(GtkPrintSettings * settings,const gchar * default_format)210 output_test_from_settings (GtkPrintSettings *settings,
211 const gchar *default_format)
212 {
213 gchar *uri = NULL;
214
215 if (settings)
216 uri = g_strdup (gtk_print_settings_get (settings, GTK_PRINT_SETTINGS_OUTPUT_URI));
217
218 if (uri == NULL)
219 {
220 const gchar *extension;
221 gchar *name, *locale_name, *path;
222
223 if (default_format)
224 extension = default_format;
225 else
226 {
227 OutputFormat format;
228
229 format = format_from_settings (settings);
230 extension = format == FORMAT_PS ? "ps" : "pdf";
231 }
232
233 /* default filename used for print-to-test */
234 name = g_strdup_printf (_("test-output.%s"), extension);
235 locale_name = g_filename_from_utf8 (name, -1, NULL, NULL, NULL);
236 g_free (name);
237
238 if (locale_name != NULL)
239 {
240 gchar *current_dir = g_get_current_dir ();
241 path = g_build_filename (current_dir, locale_name, NULL);
242 g_free (locale_name);
243
244 uri = g_filename_to_uri (path, NULL, NULL);
245 g_free (path);
246 g_free (current_dir);
247 }
248 }
249
250 return uri;
251 }
252
253 static cairo_status_t
_cairo_write(void * closure,const unsigned char * data,unsigned int length)254 _cairo_write (void *closure,
255 const unsigned char *data,
256 unsigned int length)
257 {
258 GIOChannel *io = (GIOChannel *)closure;
259 gsize written;
260 GError *error;
261
262 error = NULL;
263
264 GTK_NOTE (PRINTING,
265 g_print ("TEST Backend: Writing %i byte chunk to temp test\n", length));
266
267 while (length > 0)
268 {
269 g_io_channel_write_chars (io, (const gchar *) data, length, &written, &error);
270
271 if (error != NULL)
272 {
273 GTK_NOTE (PRINTING,
274 g_print ("TEST Backend: Error writing to temp test, %s\n", error->message));
275
276 g_error_free (error);
277 return CAIRO_STATUS_WRITE_ERROR;
278 }
279
280 GTK_NOTE (PRINTING,
281 g_print ("TEST Backend: Wrote %i bytes to temp test\n", (int)written));
282
283 data += written;
284 length -= written;
285 }
286
287 return CAIRO_STATUS_SUCCESS;
288 }
289
290
291 static cairo_surface_t *
test_printer_create_cairo_surface(GtkPrinter * printer,GtkPrintSettings * settings,gdouble width,gdouble height,GIOChannel * cache_io)292 test_printer_create_cairo_surface (GtkPrinter *printer,
293 GtkPrintSettings *settings,
294 gdouble width,
295 gdouble height,
296 GIOChannel *cache_io)
297 {
298 cairo_surface_t *surface;
299 OutputFormat format;
300
301 format = format_from_settings (settings);
302
303 if (format == FORMAT_PS)
304 surface = cairo_ps_surface_create_for_stream (_cairo_write, cache_io, width, height);
305 else
306 surface = cairo_pdf_surface_create_for_stream (_cairo_write, cache_io, width, height);
307
308 cairo_surface_set_fallback_resolution (surface,
309 2.0 * gtk_print_settings_get_printer_lpi (settings),
310 2.0 * gtk_print_settings_get_printer_lpi (settings));
311
312 return surface;
313 }
314
315 typedef struct {
316 GtkPrintBackend *backend;
317 GtkPrintJobCompleteFunc callback;
318 GtkPrintJob *job;
319 GIOChannel *target_io;
320 gpointer user_data;
321 GDestroyNotify dnotify;
322 } _PrintStreamData;
323
324 static void
test_print_cb(GtkPrintBackendTest * print_backend,GError * error,gpointer user_data)325 test_print_cb (GtkPrintBackendTest *print_backend,
326 GError *error,
327 gpointer user_data)
328 {
329 _PrintStreamData *ps = (_PrintStreamData *) user_data;
330
331 if (ps->target_io != NULL)
332 g_io_channel_unref (ps->target_io);
333
334 if (ps->callback)
335 ps->callback (ps->job, ps->user_data, error);
336
337 if (ps->dnotify)
338 ps->dnotify (ps->user_data);
339
340 gtk_print_job_set_status (ps->job,
341 (error != NULL)?GTK_PRINT_STATUS_FINISHED_ABORTED:GTK_PRINT_STATUS_FINISHED);
342
343 if (ps->job)
344 g_object_unref (ps->job);
345
346 g_free (ps);
347 }
348
349 static gboolean
test_write(GIOChannel * source,GIOCondition con,gpointer user_data)350 test_write (GIOChannel *source,
351 GIOCondition con,
352 gpointer user_data)
353 {
354 gchar buf[_STREAM_MAX_CHUNK_SIZE];
355 gsize bytes_read;
356 GError *error;
357 GIOStatus read_status;
358 _PrintStreamData *ps = (_PrintStreamData *) user_data;
359
360 error = NULL;
361
362 read_status =
363 g_io_channel_read_chars (source,
364 buf,
365 _STREAM_MAX_CHUNK_SIZE,
366 &bytes_read,
367 &error);
368
369 if (read_status != G_IO_STATUS_ERROR)
370 {
371 gsize bytes_written;
372
373 g_io_channel_write_chars (ps->target_io,
374 buf,
375 bytes_read,
376 &bytes_written,
377 &error);
378 }
379
380 if (error != NULL || read_status == G_IO_STATUS_EOF)
381 {
382 test_print_cb (GTK_PRINT_BACKEND_TEST (ps->backend), error, user_data);
383
384 if (error != NULL)
385 {
386 GTK_NOTE (PRINTING,
387 g_print ("TEST Backend: %s\n", error->message));
388
389 g_error_free (error);
390 }
391
392 return FALSE;
393 }
394
395 GTK_NOTE (PRINTING,
396 g_print ("TEST Backend: Writing %i byte chunk to target test\n", (int)bytes_read));
397
398 return TRUE;
399 }
400
401 static void
gtk_print_backend_test_print_stream(GtkPrintBackend * print_backend,GtkPrintJob * job,GIOChannel * data_io,GtkPrintJobCompleteFunc callback,gpointer user_data,GDestroyNotify dnotify)402 gtk_print_backend_test_print_stream (GtkPrintBackend *print_backend,
403 GtkPrintJob *job,
404 GIOChannel *data_io,
405 GtkPrintJobCompleteFunc callback,
406 gpointer user_data,
407 GDestroyNotify dnotify)
408 {
409 GError *internal_error = NULL;
410 GtkPrinter *printer;
411 _PrintStreamData *ps;
412 GtkPrintSettings *settings;
413 gchar *uri, *testname;
414
415 printer = gtk_print_job_get_printer (job);
416 settings = gtk_print_job_get_settings (job);
417
418 ps = g_new0 (_PrintStreamData, 1);
419 ps->callback = callback;
420 ps->user_data = user_data;
421 ps->dnotify = dnotify;
422 ps->job = g_object_ref (job);
423 ps->backend = print_backend;
424
425 internal_error = NULL;
426 uri = output_test_from_settings (settings, NULL);
427 testname = g_filename_from_uri (uri, NULL, &internal_error);
428 g_free (uri);
429
430 if (testname == NULL)
431 goto error;
432
433 ps->target_io = g_io_channel_new_file (testname, "w", &internal_error);
434
435 g_free (testname);
436
437 if (internal_error == NULL)
438 g_io_channel_set_encoding (ps->target_io, NULL, &internal_error);
439
440 error:
441 if (internal_error != NULL)
442 {
443 test_print_cb (GTK_PRINT_BACKEND_TEST (print_backend),
444 internal_error, ps);
445
446 g_error_free (internal_error);
447 return;
448 }
449
450 g_io_add_watch (data_io,
451 G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP,
452 (GIOFunc) test_write,
453 ps);
454 }
455
456 static void
gtk_print_backend_test_init(GtkPrintBackendTest * backend)457 gtk_print_backend_test_init (GtkPrintBackendTest *backend)
458 {
459 GtkPrinter *printer;
460 int i;
461
462 /* make 100 of these printers */
463 for (i = 0; i < 100; i++)
464 {
465 char *name;
466
467 name = g_strdup_printf ("%s %i", _("Print to Test Printer"), i);
468 printer = g_object_new (GTK_TYPE_PRINTER,
469 "name", name,
470 "backend", backend,
471 "is-virtual", FALSE, /* treat printer like a real one*/
472 NULL);
473 g_free (name);
474
475 g_message ("TEST Backend: Adding printer %d\n", i);
476
477 gtk_printer_set_has_details (printer, FALSE);
478 gtk_printer_set_icon_name (printer, "gtk-delete"); /* use a delete icon just for fun */
479 gtk_printer_set_is_active (printer, TRUE);
480
481 gtk_print_backend_add_printer (GTK_PRINT_BACKEND (backend), printer);
482 g_object_unref (printer);
483 }
484
485 gtk_print_backend_set_list_done (GTK_PRINT_BACKEND (backend));
486 }
487
488 static GtkPrinterOptionSet *
test_printer_get_options(GtkPrinter * printer,GtkPrintSettings * settings,GtkPageSetup * page_setup,GtkPrintCapabilities capabilities)489 test_printer_get_options (GtkPrinter *printer,
490 GtkPrintSettings *settings,
491 GtkPageSetup *page_setup,
492 GtkPrintCapabilities capabilities)
493 {
494 GtkPrinterOptionSet *set;
495 GtkPrinterOption *option;
496 const gchar *n_up[] = { "1" };
497 OutputFormat format;
498
499 format = format_from_settings (settings);
500
501 set = gtk_printer_option_set_new ();
502
503 option = gtk_printer_option_new ("gtk-n-up", _("Pages per _sheet:"), GTK_PRINTER_OPTION_TYPE_PICKONE);
504 gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (n_up),
505 (char **) n_up, (char **) n_up /* FIXME i18n (localised digits)! */);
506 gtk_printer_option_set (option, "1");
507 gtk_printer_option_set_add (set, option);
508 g_object_unref (option);
509
510 return set;
511 }
512
513 static void
test_printer_get_settings_from_options(GtkPrinter * printer,GtkPrinterOptionSet * options,GtkPrintSettings * settings)514 test_printer_get_settings_from_options (GtkPrinter *printer,
515 GtkPrinterOptionSet *options,
516 GtkPrintSettings *settings)
517 {
518 }
519
520 static void
test_printer_prepare_for_print(GtkPrinter * printer,GtkPrintJob * print_job,GtkPrintSettings * settings,GtkPageSetup * page_setup)521 test_printer_prepare_for_print (GtkPrinter *printer,
522 GtkPrintJob *print_job,
523 GtkPrintSettings *settings,
524 GtkPageSetup *page_setup)
525 {
526 gdouble scale;
527
528 print_job->print_pages = gtk_print_settings_get_print_pages (settings);
529 print_job->page_ranges = NULL;
530 print_job->num_page_ranges = 0;
531
532 if (print_job->print_pages == GTK_PRINT_PAGES_RANGES)
533 print_job->page_ranges =
534 gtk_print_settings_get_page_ranges (settings,
535 &print_job->num_page_ranges);
536
537 print_job->collate = gtk_print_settings_get_collate (settings);
538 print_job->reverse = gtk_print_settings_get_reverse (settings);
539 print_job->num_copies = gtk_print_settings_get_n_copies (settings);
540
541 scale = gtk_print_settings_get_scale (settings);
542 if (scale != 100.0)
543 print_job->scale = scale/100.0;
544
545 print_job->page_set = gtk_print_settings_get_page_set (settings);
546 print_job->rotate_to_orientation = TRUE;
547 }
548
549 static gboolean
test_printer_details_aquired_cb(GtkPrinter * printer)550 test_printer_details_aquired_cb (GtkPrinter *printer)
551 {
552 gboolean success;
553 gint weight;
554
555 /* weight towards success */
556 weight = g_random_int_range (0, 100);
557
558 success = FALSE;
559 if (weight < 75)
560 success = TRUE;
561
562 g_message ("success %i", success);
563 gtk_printer_set_has_details (printer, success);
564 g_signal_emit_by_name (printer, "details-acquired", success);
565
566 return FALSE;
567 }
568
569 static void
test_printer_request_details(GtkPrinter * printer)570 test_printer_request_details (GtkPrinter *printer)
571 {
572 gint weight;
573 gint time;
574 /* set the timer to succeed or fail at a random time interval */
575 /* weight towards the shorter end */
576 weight = g_random_int_range (0, 100);
577 if (weight < 50)
578 time = g_random_int_range (0, 2);
579 else if (weight < 75)
580 time = g_random_int_range (1, 5);
581 else
582 time = g_random_int_range (1, 10);
583
584 g_message ("Gathering details in %i seconds", time);
585
586 if (time == 0)
587 time = 10;
588 else
589 time *= 1000;
590
591 g_timeout_add (time, (GSourceFunc) test_printer_details_aquired_cb, printer);
592 }
593
594
595