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