]> Pileus Git - ~andy/gtk/blob - modules/printbackends/test/gtkprintbackendtest.c
Use G_SOURCE_CONTINUE/REMOVE
[~andy/gtk] / modules / printbackends / test / gtkprintbackendtest.c
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
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 
130 pb_module_init (GTypeModule *module)
131 {
132   gtk_print_backend_test_register_type (module);
133 }
134
135 G_MODULE_EXPORT void 
136 pb_module_exit (void)
137 {
138
139 }
140   
141 G_MODULE_EXPORT GtkPrintBackend * 
142 pb_module_create (void)
143 {
144   return gtk_print_backend_test_new ();
145 }
146
147 /*
148  * GtkPrintBackendTest
149  */
150 GType
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 *
166 gtk_print_backend_test_new (void)
167 {
168   return g_object_new (GTK_TYPE_PRINT_BACKEND_TEST, NULL);
169 }
170
171 static void
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
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 *
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
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 *
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
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
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
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
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, "edit-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 *
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
514 test_printer_get_settings_from_options (GtkPrinter          *printer,
515                                         GtkPrinterOptionSet *options,
516                                         GtkPrintSettings    *settings)
517 {
518 }
519
520 static void
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   gtk_print_job_set_pages (print_job, gtk_print_settings_get_print_pages (settings));
529   gtk_print_job_set_page_ranges (print_job, NULL, 0);
530   
531   if (gtk_print_job_get_pages (print_job) == GTK_PRINT_PAGES_RANGES)
532     {
533       GtkPageRange *page_ranges;
534       gint num_page_ranges;
535       page_ranges = gtk_print_settings_get_page_ranges (settings, &num_page_ranges);
536       gtk_print_job_set_page_ranges (print_job, page_ranges, num_page_ranges);
537     }
538
539   gtk_print_job_set_collate (print_job, gtk_print_settings_get_collate (settings));
540   gtk_print_job_set_reverse (print_job, gtk_print_settings_get_reverse (settings));
541   gtk_print_job_set_num_copies (print_job, gtk_print_settings_get_n_copies (settings));
542
543   scale = gtk_print_settings_get_scale (settings);
544   if (scale != 100.0)
545     gtk_print_job_set_scale (print_job, scale/100.0);
546
547   gtk_print_job_set_page_set (print_job, gtk_print_settings_get_page_set (settings));
548   gtk_print_job_set_rotate (print_job, TRUE);
549 }
550
551 static gboolean
552 test_printer_details_acquired_cb (GtkPrinter *printer)
553 {
554   gboolean success;
555   gint weight;
556
557   /* weight towards success */
558   weight = g_random_int_range (0, 100);
559
560   success = FALSE;
561   if (weight < 75)
562     success = TRUE;
563
564   g_message ("success %i", success);
565   gtk_printer_set_has_details (printer, success);
566   g_signal_emit_by_name (printer, "details-acquired", success);
567
568   return G_SOURCE_REMOVE;
569 }
570
571 static void
572 test_printer_request_details (GtkPrinter *printer)
573 {
574   gint weight;
575   gint time;
576   /* set the timer to succeed or fail at a random time interval */
577   /* weight towards the shorter end */
578   weight = g_random_int_range (0, 100);
579   if (weight < 50)
580     time = g_random_int_range (0, 2);
581   else if (weight < 75)
582     time = g_random_int_range (1, 5);
583   else
584     time = g_random_int_range (1, 10);
585
586   g_message ("Gathering details in %i seconds", time);
587
588   if (time == 0)
589     time = 10;
590   else
591     time *= 1000;
592
593   g_timeout_add (time, (GSourceFunc) test_printer_details_acquired_cb, printer);
594 }
595
596