]> Pileus Git - ~andy/gtk/blob - modules/printbackends/cups/gtkprintbackendcups.c
Get the name of the first printer in a class to use when requesting a PPD
[~andy/gtk] / modules / printbackends / cups / gtkprintbackendcups.c
1 /* GTK - The GIMP Toolkit
2  * gtkprintbackendcups.h: Default implementation of GtkPrintBackend 
3  * for the Common Unix Print System (CUPS)
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 <stdlib.h>
26
27 #include <config.h>
28 #include <cups/cups.h>
29 #include <cups/language.h>
30 #include <cups/http.h>
31 #include <cups/ipp.h>
32 #include <errno.h>
33 #include <cairo.h>
34 #include <cairo-pdf.h>
35 #include <cairo-ps.h>
36
37 #include <glib/gi18n-lib.h>
38 #include <gmodule.h>
39
40 #include <gtk/gtkprintoperation.h>
41 #include <gtk/gtkprintsettings.h>
42 #include <gtk/gtkprintbackend.h>
43 #include <gtk/gtkprinter.h>
44 #include <gtk/gtkprinter-private.h>
45
46 #include "gtkprintbackendcups.h"
47 #include "gtkprintercups.h"
48
49 #include "gtkcupsutils.h"
50 #include "gtkdebug.h"
51
52 typedef struct _GtkPrintBackendCupsClass GtkPrintBackendCupsClass;
53
54 #define GTK_PRINT_BACKEND_CUPS_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PRINT_BACKEND_CUPS, GtkPrintBackendCupsClass))
55 #define GTK_IS_PRINT_BACKEND_CUPS_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PRINT_BACKEND_CUPS))
56 #define GTK_PRINT_BACKEND_CUPS_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PRINT_BACKEND_CUPS, GtkPrintBackendCupsClass))
57
58 #define _CUPS_MAX_ATTEMPTS 10 
59 #define _CUPS_MAX_CHUNK_SIZE 8192
60
61 #define _CUPS_MAP_ATTR_INT(attr, v, a) {if (!g_ascii_strcasecmp (attr->name, (a))) v = attr->values[0].integer;}
62 #define _CUPS_MAP_ATTR_STR(attr, v, a) {if (!g_ascii_strcasecmp (attr->name, (a))) v = attr->values[0].string.text;}
63
64 static GType print_backend_cups_type = 0;
65
66 typedef void (* GtkPrintCupsResponseCallbackFunc) (GtkPrintBackend *print_backend,
67                                                    GtkCupsResult   *result, 
68                                                    gpointer         user_data);
69
70 typedef enum 
71 {
72   DISPATCH_SETUP,
73   DISPATCH_REQUEST,
74   DISPATCH_SEND,
75   DISPATCH_CHECK,
76   DISPATCH_READ,
77   DISPATCH_ERROR
78 } GtkPrintCupsDispatchState;
79
80 typedef struct 
81 {
82   GSource source;
83
84   http_t *http;
85   GtkCupsRequest *request;
86   GPollFD *data_poll;
87   GtkPrintBackendCups *backend;
88
89 } GtkPrintCupsDispatchWatch;
90
91 struct _GtkPrintBackendCupsClass
92 {
93   GtkPrintBackendClass parent_class;
94 };
95
96 struct _GtkPrintBackendCups
97 {
98   GtkPrintBackend parent_instance;
99
100   char *default_printer;
101   
102   guint list_printers_poll;
103   guint list_printers_pending : 1;
104   guint got_default_printer   : 1;
105 };
106
107 static GObjectClass *backend_parent_class;
108
109 static void                 gtk_print_backend_cups_class_init      (GtkPrintBackendCupsClass          *class);
110 static void                 gtk_print_backend_cups_init            (GtkPrintBackendCups               *impl);
111 static void                 gtk_print_backend_cups_finalize        (GObject                           *object);
112 static void                 gtk_print_backend_cups_dispose         (GObject                           *object);
113 static void                 cups_get_printer_list                  (GtkPrintBackend                   *print_backend);
114 static void                 cups_request_execute                   (GtkPrintBackendCups               *print_backend,
115                                                                     GtkCupsRequest                    *request,
116                                                                     GtkPrintCupsResponseCallbackFunc   callback,
117                                                                     gpointer                           user_data,
118                                                                     GDestroyNotify                     notify);
119 static void                 cups_printer_get_settings_from_options (GtkPrinter                        *printer,
120                                                                     GtkPrinterOptionSet               *options,
121                                                                     GtkPrintSettings                  *settings);
122 static gboolean             cups_printer_mark_conflicts            (GtkPrinter                        *printer,
123                                                                     GtkPrinterOptionSet               *options);
124 static GtkPrinterOptionSet *cups_printer_get_options               (GtkPrinter                        *printer,
125                                                                     GtkPrintSettings                  *settings,
126                                                                     GtkPageSetup                      *page_setup,
127                                                                     GtkPrintCapabilities               capabilities);
128 static void                 cups_printer_prepare_for_print         (GtkPrinter                        *printer,
129                                                                     GtkPrintJob                       *print_job,
130                                                                     GtkPrintSettings                  *settings,
131                                                                     GtkPageSetup                      *page_setup);
132 static GList *              cups_printer_list_papers               (GtkPrinter                        *printer);
133 static void                 cups_printer_request_details           (GtkPrinter                        *printer);
134 static void                 cups_request_default_printer           (GtkPrintBackendCups               *print_backend);
135 static void                 cups_request_ppd                       (GtkPrinter                        *printer);
136 static void                 cups_printer_get_hard_margins          (GtkPrinter                        *printer,
137                                                                     double                            *top,
138                                                                     double                            *bottom,
139                                                                     double                            *left,
140                                                                     double                            *right);
141 static GtkPrintCapabilities cups_printer_get_capabilities          (GtkPrinter                        *printer);
142 static void                 set_option_from_settings               (GtkPrinterOption                  *option,
143                                                                     GtkPrintSettings                  *setting);
144 static void                 cups_begin_polling_info                (GtkPrintBackendCups               *print_backend,
145                                                                     GtkPrintJob                       *job,
146                                                                     int                                job_id);
147 static gboolean             cups_job_info_poll_timeout             (gpointer                           user_data);
148 static void                 gtk_print_backend_cups_print_stream    (GtkPrintBackend                   *backend,
149                                                                     GtkPrintJob                       *job,
150                                                                     GIOChannel                        *data_io,
151                                                                     GtkPrintJobCompleteFunc            callback,
152                                                                     gpointer                           user_data,
153                                                                     GDestroyNotify                     dnotify);
154 static cairo_surface_t *    cups_printer_create_cairo_surface      (GtkPrinter                        *printer,
155                                                                     GtkPrintSettings                  *settings,
156                                                                     gdouble                            width,
157                                                                     gdouble                            height,
158                                                                     GIOChannel                        *cache_io);
159
160
161 static void
162 gtk_print_backend_cups_register_type (GTypeModule *module)
163 {
164   static const GTypeInfo print_backend_cups_info =
165   {
166     sizeof (GtkPrintBackendCupsClass),
167     NULL,               /* base_init */
168     NULL,               /* base_finalize */
169     (GClassInitFunc) gtk_print_backend_cups_class_init,
170     NULL,               /* class_finalize */
171     NULL,               /* class_data */
172     sizeof (GtkPrintBackendCups),
173     0,                  /* n_preallocs */
174     (GInstanceInitFunc) gtk_print_backend_cups_init
175   };
176
177   print_backend_cups_type = g_type_module_register_type (module,
178                                                          GTK_TYPE_PRINT_BACKEND,
179                                                          "GtkPrintBackendCups",
180                                                          &print_backend_cups_info, 0);
181 }
182
183 G_MODULE_EXPORT void 
184 pb_module_init (GTypeModule *module)
185 {
186   GTK_NOTE (PRINTING,
187             g_print ("CUPS Backend: Initializing the CUPS print backend module\n")); 
188
189   gtk_print_backend_cups_register_type (module);
190   gtk_printer_cups_register_type (module);
191 }
192
193 G_MODULE_EXPORT void 
194 pb_module_exit (void)
195 {
196
197 }
198   
199 G_MODULE_EXPORT GtkPrintBackend * 
200 pb_module_create (void)
201 {
202   return gtk_print_backend_cups_new ();
203 }
204
205 /*
206  * GtkPrintBackendCups
207  */
208 GType
209 gtk_print_backend_cups_get_type (void)
210 {
211   return print_backend_cups_type;
212 }
213
214 /**
215  * gtk_print_backend_cups_new:
216  *
217  * Creates a new #GtkPrintBackendCups object. #GtkPrintBackendCups
218  * implements the #GtkPrintBackend interface with direct access to
219  * the filesystem using Unix/Linux API calls
220  *
221  * Return value: the new #GtkPrintBackendCups object
222  */
223 GtkPrintBackend *
224 gtk_print_backend_cups_new (void)
225 {
226   GTK_NOTE (PRINTING,
227             g_print ("CUPS Backend: Creating a new CUPS print backend object\n"));
228
229   return g_object_new (GTK_TYPE_PRINT_BACKEND_CUPS, NULL);
230 }
231
232 static void
233 gtk_print_backend_cups_class_init (GtkPrintBackendCupsClass *class)
234 {
235   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
236   GtkPrintBackendClass *backend_class = GTK_PRINT_BACKEND_CLASS (class);
237
238   backend_parent_class = g_type_class_peek_parent (class);
239
240   gobject_class->finalize = gtk_print_backend_cups_finalize;
241   gobject_class->dispose = gtk_print_backend_cups_dispose;
242
243   backend_class->request_printer_list = cups_get_printer_list; 
244   backend_class->print_stream = gtk_print_backend_cups_print_stream;
245   backend_class->printer_request_details = cups_printer_request_details;
246   backend_class->printer_create_cairo_surface = cups_printer_create_cairo_surface;
247   backend_class->printer_get_options = cups_printer_get_options;
248   backend_class->printer_mark_conflicts = cups_printer_mark_conflicts;
249   backend_class->printer_get_settings_from_options = cups_printer_get_settings_from_options;
250   backend_class->printer_prepare_for_print = cups_printer_prepare_for_print;
251   backend_class->printer_list_papers = cups_printer_list_papers;
252   backend_class->printer_get_hard_margins = cups_printer_get_hard_margins;
253   backend_class->printer_get_capabilities = cups_printer_get_capabilities;
254 }
255
256 static cairo_status_t
257 _cairo_write_to_cups (void                *closure,
258                       const unsigned char *data,
259                       unsigned int         length)
260 {
261   GIOChannel *io = (GIOChannel *)closure;
262   gsize written;
263   GError *error;
264
265   error = NULL;
266
267   GTK_NOTE (PRINTING,
268             g_print ("CUPS Backend: Writting %i byte chunk to temp file\n", length));
269
270   while (length > 0) 
271     {
272       g_io_channel_write_chars (io, data, length, &written, &error);
273
274       if (error != NULL)
275         {
276           GTK_NOTE (PRINTING,
277                     g_print ("CUPS Backend: Error writting to temp file, %s\n", error->message));
278
279           g_error_free (error);
280           return CAIRO_STATUS_WRITE_ERROR;
281         }    
282
283       GTK_NOTE (PRINTING,
284                 g_print ("CUPS Backend: Wrote %i bytes to temp file\n", written));
285
286       data += written;
287       length -= written;
288     }
289
290   return CAIRO_STATUS_SUCCESS;
291 }
292
293 static cairo_surface_t *
294 cups_printer_create_cairo_surface (GtkPrinter       *printer,
295                                    GtkPrintSettings *settings,
296                                    gdouble           width, 
297                                    gdouble           height,
298                                    GIOChannel       *cache_io)
299 {
300   cairo_surface_t *surface; 
301  
302   /* TODO: check if it is a ps or pdf printer */
303   
304   surface = cairo_ps_surface_create_for_stream  (_cairo_write_to_cups, cache_io, width, height);
305
306   /* TODO: DPI from settings object? */
307   cairo_surface_set_fallback_resolution (surface, 300, 300);
308
309   return surface;
310 }
311
312 typedef struct {
313   GtkPrintJobCompleteFunc callback;
314   GtkPrintJob *job;
315   gpointer user_data;
316   GDestroyNotify dnotify;
317 } CupsPrintStreamData;
318
319 static void
320 cups_free_print_stream_data (CupsPrintStreamData *data)
321 {
322   GTK_NOTE (PRINTING,
323             g_print ("CUPS Backend: %s\n", G_STRFUNC));
324
325   if (data->dnotify)
326     data->dnotify (data->user_data);
327   g_object_unref (data->job);
328   g_free (data);
329 }
330
331 static void
332 cups_print_cb (GtkPrintBackendCups *print_backend,
333                GtkCupsResult       *result,
334                gpointer             user_data)
335 {
336   GError *error = NULL;
337   CupsPrintStreamData *ps = user_data;
338
339   GTK_NOTE (PRINTING,
340             g_print ("CUPS Backend: %s\n", G_STRFUNC)); 
341
342   if (gtk_cups_result_is_error (result))
343     error = g_error_new_literal (gtk_print_error_quark (),
344                                  GTK_PRINT_ERROR_INTERNAL_ERROR,
345                                  gtk_cups_result_get_error_string (result));
346
347   if (ps->callback)
348     ps->callback (ps->job, ps->user_data, error);
349
350   if (error == NULL)
351     {
352       int job_id = 0;
353       ipp_attribute_t *attr;            /* IPP job-id attribute */
354       ipp_t *response = gtk_cups_result_get_response (result);
355
356       if ((attr = ippFindAttribute (response, "job-id", IPP_TAG_INTEGER)) != NULL)
357         job_id = attr->values[0].integer;
358
359       if (!gtk_print_job_get_track_print_status (ps->job) || job_id == 0)
360         gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_FINISHED);
361       else
362         {
363           gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_PENDING);
364           cups_begin_polling_info (print_backend, ps->job, job_id);
365         }
366     } 
367   else
368     gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_FINISHED_ABORTED);
369
370   
371   if (error)
372     g_error_free (error);
373   
374 }
375
376 static void
377 add_cups_options (const gchar *key,
378                   const gchar *value,
379                   gpointer     user_data)
380 {
381   GtkCupsRequest *request = user_data;
382
383   if (!g_str_has_prefix (key, "cups-"))
384     return;
385
386   if (strcmp (value, "gtk-ignore-value") == 0)
387     return;
388   
389   key = key + strlen ("cups-");
390
391   gtk_cups_request_encode_option (request, key, value);
392 }
393
394 static void
395 gtk_print_backend_cups_print_stream (GtkPrintBackend         *print_backend,
396                                      GtkPrintJob             *job,
397                                      GIOChannel              *data_io,
398                                      GtkPrintJobCompleteFunc  callback,
399                                      gpointer                 user_data,
400                                      GDestroyNotify           dnotify)
401 {
402   GtkPrinterCups *cups_printer;
403   CupsPrintStreamData *ps;
404   GtkCupsRequest *request;
405   GtkPrintSettings *settings;
406   const gchar *title;
407
408   GTK_NOTE (PRINTING,
409             g_print ("CUPS Backend: %s\n", G_STRFUNC));   
410
411   cups_printer = GTK_PRINTER_CUPS (gtk_print_job_get_printer (job));
412   settings = gtk_print_job_get_settings (job);
413
414   request = gtk_cups_request_new (NULL,
415                                   GTK_CUPS_POST,
416                                   IPP_PRINT_JOB,
417                                   data_io,
418                                   NULL,
419                                   cups_printer->device_uri);
420
421   gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
422                                    NULL, cups_printer->printer_uri);
423
424   gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
425                                    NULL, cupsUser());
426
427   title = gtk_print_job_get_title (job);
428   if (title)
429     gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
430                                      title);
431
432   gtk_print_settings_foreach (settings, add_cups_options, request);
433   
434   ps = g_new0 (CupsPrintStreamData, 1);
435   ps->callback = callback;
436   ps->user_data = user_data;
437   ps->dnotify = dnotify;
438   ps->job = g_object_ref (job);
439
440   cups_request_execute (GTK_PRINT_BACKEND_CUPS (print_backend),
441                         request,
442                         (GtkPrintCupsResponseCallbackFunc) cups_print_cb,
443                         ps,
444                         (GDestroyNotify)cups_free_print_stream_data);
445 }
446
447
448 static void
449 gtk_print_backend_cups_init (GtkPrintBackendCups *backend_cups)
450 {
451   backend_cups->list_printers_poll = 0;  
452   backend_cups->list_printers_pending = FALSE;
453
454   cups_request_default_printer (backend_cups);
455 }
456
457 static void
458 gtk_print_backend_cups_finalize (GObject *object)
459 {
460   GtkPrintBackendCups *backend_cups;
461   
462   GTK_NOTE (PRINTING,
463             g_print ("CUPS Backend: finalizing CUPS backend module\n"));
464
465   backend_cups = GTK_PRINT_BACKEND_CUPS (object);
466
467   g_free (backend_cups->default_printer);
468   backend_cups->default_printer = NULL;
469   
470   backend_parent_class->finalize (object);
471 }
472
473 static void
474 gtk_print_backend_cups_dispose (GObject *object)
475 {
476   GtkPrintBackendCups *backend_cups;
477
478   GTK_NOTE (PRINTING,
479             g_print ("CUPS Backend: %s\n", G_STRFUNC));
480
481   backend_cups = GTK_PRINT_BACKEND_CUPS (object);
482
483   if (backend_cups->list_printers_poll > 0)
484     g_source_remove (backend_cups->list_printers_poll);
485   backend_cups->list_printers_poll = 0;
486   
487   backend_parent_class->dispose (object);
488 }
489
490
491 static gboolean
492 cups_dispatch_watch_check (GSource *source)
493 {
494   GtkPrintCupsDispatchWatch *dispatch;
495   GtkCupsPollState poll_state;
496   gboolean result;
497
498   GTK_NOTE (PRINTING,
499             g_print ("CUPS Backend: %s <source %p>\n", G_STRFUNC, source)); 
500
501   dispatch = (GtkPrintCupsDispatchWatch *) source;
502
503   poll_state = gtk_cups_request_get_poll_state (dispatch->request);
504   
505   if (dispatch->data_poll == NULL && 
506       dispatch->request->http != NULL)
507     {
508       dispatch->data_poll = g_new0 (GPollFD, 1);
509       dispatch->data_poll->fd = dispatch->request->http->fd;
510
511       g_source_add_poll (source, dispatch->data_poll);
512     }
513             
514   if (dispatch->data_poll != NULL && dispatch->request->http != NULL)
515     {
516       if (dispatch->data_poll->fd != dispatch->request->http->fd)
517         dispatch->data_poll->fd = dispatch->request->http->fd;
518
519       if (poll_state == GTK_CUPS_HTTP_READ)
520         dispatch->data_poll->events = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI;
521       else if (poll_state == GTK_CUPS_HTTP_WRITE)
522         dispatch->data_poll->events = G_IO_OUT | G_IO_ERR;
523       else
524         dispatch->data_poll->events = 0;
525     }
526     
527   if (poll_state != GTK_CUPS_HTTP_IDLE)  
528     if (!(dispatch->data_poll->revents & dispatch->data_poll->events)) 
529        return FALSE;
530   
531   result = gtk_cups_request_read_write (dispatch->request);
532   if (result && dispatch->data_poll != NULL)
533     {
534       g_source_remove_poll (source, dispatch->data_poll);
535       g_free (dispatch->data_poll);
536       dispatch->data_poll = NULL;
537     }
538   
539   return result;
540 }
541
542 static gboolean
543 cups_dispatch_watch_prepare (GSource *source,
544                              gint    *timeout_)
545 {
546   GtkPrintCupsDispatchWatch *dispatch;
547
548   dispatch = (GtkPrintCupsDispatchWatch *) source;
549
550   GTK_NOTE (PRINTING,
551             g_print ("CUPS Backend: %s <source %p>\n", G_STRFUNC, source));
552
553   *timeout_ = -1;
554   
555   return gtk_cups_request_read_write (dispatch->request);
556 }
557
558 static gboolean
559 cups_dispatch_watch_dispatch (GSource     *source,
560                               GSourceFunc  callback,
561                               gpointer     user_data)
562 {
563   GtkPrintCupsDispatchWatch *dispatch;
564   GtkPrintCupsResponseCallbackFunc ep_callback;  
565   GtkCupsResult *result;
566   
567   g_assert (callback != NULL);
568
569   ep_callback = (GtkPrintCupsResponseCallbackFunc) callback;
570   
571   dispatch = (GtkPrintCupsDispatchWatch *) source;
572
573   result = gtk_cups_request_get_result (dispatch->request);
574
575   GTK_NOTE (PRINTING,
576             g_print ("CUPS Backend: %s <source %p>\n", G_STRFUNC, source));
577
578   if (gtk_cups_result_is_error (result))
579     g_warning ("Error result: %s", gtk_cups_result_get_error_string (result));
580
581   ep_callback (GTK_PRINT_BACKEND (dispatch->backend), result, user_data);
582
583   return FALSE;
584 }
585
586 static void
587 cups_dispatch_watch_finalize (GSource *source)
588 {
589   GtkPrintCupsDispatchWatch *dispatch;
590
591   GTK_NOTE (PRINTING,
592             g_print ("CUPS Backend: %s <source %p>\n", G_STRFUNC, source));
593
594   dispatch = (GtkPrintCupsDispatchWatch *) source;
595
596   gtk_cups_request_free (dispatch->request);
597
598   if (dispatch->backend)
599     {
600       /* We need to unref this at idle time, because it might be the
601        * last reference to this module causing the code to be
602        * unloaded (including this particular function!)
603        * Update: Doing this at idle caused a deadlock taking the
604        * mainloop context lock while being in a GSource callout for
605        * multithreaded apps. So, for now we just disable unloading
606        * of print backends. See _gtk_print_backend_create for the
607        * disabling.
608        */
609       g_object_unref (dispatch->backend);
610       dispatch->backend = NULL;
611     }
612
613   if (dispatch->data_poll != NULL)
614     g_free (dispatch->data_poll);
615 }
616
617 static GSourceFuncs _cups_dispatch_watch_funcs = {
618   cups_dispatch_watch_prepare,
619   cups_dispatch_watch_check,
620   cups_dispatch_watch_dispatch,
621   cups_dispatch_watch_finalize
622 };
623
624
625 static void
626 cups_request_execute (GtkPrintBackendCups              *print_backend,
627                       GtkCupsRequest                   *request,
628                       GtkPrintCupsResponseCallbackFunc  callback,
629                       gpointer                          user_data,
630                       GDestroyNotify                    notify)
631 {
632   GtkPrintCupsDispatchWatch *dispatch;
633
634   dispatch = (GtkPrintCupsDispatchWatch *) g_source_new (&_cups_dispatch_watch_funcs, 
635                                                          sizeof (GtkPrintCupsDispatchWatch));
636
637   GTK_NOTE (PRINTING,
638             g_print ("CUPS Backend: %s <source %p> - Executing cups request on server '%s' and resource '%s'\n", G_STRFUNC, dispatch, request->server, request->resource));
639
640   dispatch->request = request;
641   dispatch->backend = g_object_ref (print_backend);
642   dispatch->data_poll = NULL;
643
644   g_source_set_callback ((GSource *) dispatch, (GSourceFunc) callback, user_data, notify);
645
646   g_source_attach ((GSource *) dispatch, NULL);
647   g_source_unref ((GSource *) dispatch);
648 }
649
650 static void
651 cups_request_printer_info_cb (GtkPrintBackendCups *backend,
652                               GtkCupsResult       *result,
653                               gpointer             user_data)
654 {
655   ipp_attribute_t *attr;
656   ipp_t *response;
657   gchar *printer_name;
658   GtkPrinterCups *cups_printer;
659   GtkPrinter *printer;
660   gchar *loc;
661   gchar *desc;
662   gchar *state_msg;
663   int job_count;
664   gboolean status_changed;  
665
666   g_assert (GTK_IS_PRINT_BACKEND_CUPS (backend));
667
668   printer_name = (gchar *)user_data;
669   printer = gtk_print_backend_find_printer (GTK_PRINT_BACKEND (backend),
670                                             printer_name);
671
672   GTK_NOTE (PRINTING,
673             g_print ("CUPS Backend: %s - Got printer info for printer '%s'\n", G_STRFUNC, printer_name));
674
675   if (!printer)
676     {
677       GTK_NOTE (PRINTING,
678             g_print ("CUPS Backend: Could not find printer called '%s'\n", printer_name));
679       return;
680     }
681
682   cups_printer = GTK_PRINTER_CUPS (printer);
683   
684   if (gtk_cups_result_is_error (result))
685     {
686       if (gtk_printer_is_new (printer))
687         {
688           gtk_print_backend_remove_printer (GTK_PRINT_BACKEND (backend),
689                                             printer);
690           return;
691         }
692       else
693         return; /* TODO: mark as inactive printer */
694     }
695
696   response = gtk_cups_result_get_response (result);
697
698   /* TODO: determine printer type and use correct icon */
699   gtk_printer_set_icon_name (printer, "gtk-print");
700  
701   state_msg = "";
702   loc = "";
703   desc = "";
704   job_count = 0;
705   for (attr = response->attrs; attr != NULL; attr = attr->next) 
706     {
707       if (!attr->name)
708         continue;
709
710       _CUPS_MAP_ATTR_STR (attr, loc, "printer-location");
711       _CUPS_MAP_ATTR_STR (attr, desc, "printer-info");
712       _CUPS_MAP_ATTR_STR (attr, state_msg, "printer-state-message");
713       _CUPS_MAP_ATTR_INT (attr, cups_printer->state, "printer-state");
714       _CUPS_MAP_ATTR_INT (attr, job_count, "queued-job-count");
715     }
716
717   status_changed = gtk_printer_set_job_count (printer, job_count);
718   
719   status_changed |= gtk_printer_set_location (printer, loc);
720   status_changed |= gtk_printer_set_description (printer, desc);
721   status_changed |= gtk_printer_set_state_message (printer, state_msg);
722
723   if (status_changed)
724     g_signal_emit_by_name (GTK_PRINT_BACKEND (backend),
725                            "printer-status-changed", printer); 
726 }
727
728 static void
729 cups_request_printer_info (GtkPrintBackendCups *print_backend,
730                            const gchar         *printer_name)
731 {
732   GtkCupsRequest *request;
733   gchar *printer_uri;
734   static const char * const pattrs[] =  /* Attributes we're interested in */
735     {
736       "printer-location",
737       "printer-info",
738       "printer-state-message",
739       "printer-state",
740       "queued-job-count"
741     };
742
743   request = gtk_cups_request_new (NULL,
744                                   GTK_CUPS_POST,
745                                   IPP_GET_PRINTER_ATTRIBUTES,
746                                   NULL,
747                                   NULL,
748                                   NULL);
749
750   printer_uri = g_strdup_printf ("ipp://localhost/printers/%s",
751                                   printer_name);
752   gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI,
753                                    "printer-uri", NULL, printer_uri);
754
755   GTK_NOTE (PRINTING,
756             g_print ("CUPS Backend: %s - Requesting printer info for URI '%s'\n", G_STRFUNC, printer_uri));
757
758   g_free (printer_uri);
759
760   gtk_cups_request_ipp_add_strings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
761                                     "requested-attributes", G_N_ELEMENTS (pattrs),
762                                     NULL, pattrs);
763  
764   cups_request_execute (print_backend,
765                         request,
766                         (GtkPrintCupsResponseCallbackFunc) cups_request_printer_info_cb,
767                         g_strdup (printer_name),
768                         (GDestroyNotify) g_free);
769 }
770
771
772 typedef struct {
773   GtkPrintBackendCups *print_backend;
774   GtkPrintJob *job;
775   int job_id;
776   int counter;
777 } CupsJobPollData;
778
779 static void
780 job_object_died (gpointer  user_data,
781                  GObject  *where_the_object_was)
782 {
783   CupsJobPollData *data = user_data;
784   data->job = NULL;
785 }
786
787 static void
788 cups_job_poll_data_free (CupsJobPollData *data)
789 {
790   if (data->job)
791     g_object_weak_unref (G_OBJECT (data->job), job_object_died, data);
792     
793   g_free (data);
794 }
795
796 static void
797 cups_request_job_info_cb (GtkPrintBackendCups *print_backend,
798                           GtkCupsResult       *result,
799                           gpointer             user_data)
800 {
801   CupsJobPollData *data = user_data;
802   ipp_attribute_t *attr;
803   ipp_t *response;
804   int state;
805   gboolean done;
806
807   if (data->job == NULL)
808     {
809       cups_job_poll_data_free (data);
810       return;
811     }
812
813   data->counter++;
814   
815   response = gtk_cups_result_get_response (result);
816
817   state = 0;
818   for (attr = response->attrs; attr != NULL; attr = attr->next) 
819     {
820       if (!attr->name)
821         continue;
822       
823       _CUPS_MAP_ATTR_INT (attr, state, "job-state");
824     }
825   
826   done = FALSE;
827   switch (state)
828     {
829     case IPP_JOB_PENDING:
830     case IPP_JOB_HELD:
831     case IPP_JOB_STOPPED:
832       gtk_print_job_set_status (data->job,
833                                 GTK_PRINT_STATUS_PENDING);
834       break;
835     case IPP_JOB_PROCESSING:
836       gtk_print_job_set_status (data->job,
837                                 GTK_PRINT_STATUS_PRINTING);
838       break;
839     default:
840     case IPP_JOB_CANCELLED:
841     case IPP_JOB_ABORTED:
842       gtk_print_job_set_status (data->job,
843                                 GTK_PRINT_STATUS_FINISHED_ABORTED);
844       done = TRUE;
845       break;
846     case 0:
847     case IPP_JOB_COMPLETED:
848       gtk_print_job_set_status (data->job,
849                                 GTK_PRINT_STATUS_FINISHED);
850       done = TRUE;
851       break;
852     }
853
854   if (!done && data->job != NULL)
855     {
856       guint32 timeout;
857
858       if (data->counter < 5)
859         timeout = 100;
860       else if (data->counter < 10)
861         timeout = 500;
862       else
863         timeout = 1000;
864       
865       g_timeout_add (timeout, cups_job_info_poll_timeout, data);
866     }
867   else
868     cups_job_poll_data_free (data);    
869 }
870
871 static void
872 cups_request_job_info (CupsJobPollData *data)
873 {
874   GtkCupsRequest *request;
875   gchar *printer_uri;
876
877   request = gtk_cups_request_new (NULL,
878                                   GTK_CUPS_POST,
879                                   IPP_GET_JOB_ATTRIBUTES,
880                                   NULL,
881                                   NULL,
882                                   NULL);
883
884   printer_uri = g_strdup_printf ("ipp://localhost/jobs/%d", data->job_id);
885   gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI,
886                                    "job-uri", NULL, printer_uri);
887   g_free (printer_uri);
888
889   cups_request_execute (data->print_backend,
890                         request,
891                         (GtkPrintCupsResponseCallbackFunc) cups_request_job_info_cb,
892                         data,
893                         NULL);
894 }
895
896 static gboolean
897 cups_job_info_poll_timeout (gpointer user_data)
898 {
899   CupsJobPollData *data = user_data;
900   
901   if (data->job == NULL)
902     cups_job_poll_data_free (data);
903   else
904     cups_request_job_info (data);
905   
906   return FALSE;
907 }
908
909 static void
910 cups_begin_polling_info (GtkPrintBackendCups *print_backend,
911                          GtkPrintJob         *job,
912                          gint                 job_id)
913 {
914   CupsJobPollData *data;
915
916   data = g_new0 (CupsJobPollData, 1);
917
918   data->print_backend = print_backend;
919   data->job = job;
920   data->job_id = job_id;
921   data->counter = 0;
922
923   g_object_weak_ref (G_OBJECT (job), job_object_died, data);
924
925   cups_request_job_info (data);
926 }
927
928 static void
929 mark_printer_inactive (GtkPrinter      *printer, 
930                        GtkPrintBackend *backend)
931 {
932   gtk_printer_set_is_active (printer, FALSE);
933   g_signal_emit_by_name (backend, "printer-removed", printer);
934 }
935
936 static gint
937 find_printer (GtkPrinter  *printer, 
938               const gchar *find_name)
939 {
940   const gchar *printer_name;
941
942   printer_name = gtk_printer_get_name (printer);
943   return g_ascii_strcasecmp (printer_name, find_name);
944 }
945
946 static void
947 cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
948                               GtkCupsResult       *result,
949                               gpointer             user_data)
950 {
951   GtkPrintBackend *backend = GTK_PRINT_BACKEND (cups_backend);
952   ipp_attribute_t *attr;
953   ipp_t *response;
954   gboolean list_has_changed;
955   GList *removed_printer_checklist;
956
957   list_has_changed = FALSE;
958
959   GTK_NOTE (PRINTING,
960             g_print ("CUPS Backend: %s\n", G_STRFUNC));
961
962   cups_backend->list_printers_pending = FALSE;
963
964   if (gtk_cups_result_is_error (result))
965     {
966       g_warning ("Error getting printer list: %s", gtk_cups_result_get_error_string (result));
967       return;
968     }
969   
970   /* Gather the names of the printers in the current queue
971    * so we may check to see if they were removed 
972    */
973   removed_printer_checklist = gtk_print_backend_get_printer_list (backend);
974                                                                   
975   response = gtk_cups_result_get_response (result);
976
977   for (attr = response->attrs; attr != NULL; attr = attr->next)
978     {
979       GtkPrinter *printer;
980       const gchar *printer_name;
981       const gchar *printer_uri;
982       const gchar *member_uris;
983       GList *node;
984       
985       /* Skip leading attributes until we hit a printer...
986        */
987       while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
988         attr = attr->next;
989
990       if (attr == NULL)
991         break;
992
993       printer_name = NULL;
994       printer_uri = NULL;
995       member_uris = NULL;
996       while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
997       {
998         if (!strcmp (attr->name, "printer-name") &&
999             attr->value_tag == IPP_TAG_NAME)
1000           printer_name = attr->values[0].string.text;
1001         else if (!strcmp (attr->name, "printer-uri-supported") &&
1002                  attr->value_tag == IPP_TAG_URI)
1003           printer_uri = attr->values[0].string.text;
1004         else if (!strcmp (attr->name, "member-uris") &&
1005                  attr->value_tag == IPP_TAG_URI)
1006           member_uris = attr->values[0].string.text;
1007         else
1008           {
1009             GTK_NOTE (PRINTING,
1010                       g_print ("CUPS Backend: Attribute %s ignored", attr->name));
1011           }
1012
1013         attr = attr->next;
1014       }
1015
1016       if (printer_name == NULL ||
1017           (printer_uri == NULL && member_uris == NULL))
1018       {
1019         if (attr == NULL)
1020           break;
1021         else
1022           continue;
1023       }
1024    
1025       /* remove name from checklist if it was found */
1026       node = g_list_find_custom (removed_printer_checklist, printer_name, (GCompareFunc) find_printer);
1027       removed_printer_checklist = g_list_delete_link (removed_printer_checklist, node);
1028  
1029       printer = gtk_print_backend_find_printer (backend, printer_name);
1030       if (!printer)
1031         {
1032           GtkPrinterCups *cups_printer;
1033           char uri[HTTP_MAX_URI];       /* Printer URI */
1034           char method[HTTP_MAX_URI];    /* Method/scheme name */
1035           char username[HTTP_MAX_URI];  /* Username:password */
1036           char hostname[HTTP_MAX_URI];  /* Hostname */
1037           char resource[HTTP_MAX_URI];  /* Resource name */
1038           int  port;                    /* Port number */
1039           
1040           list_has_changed = TRUE;
1041           cups_printer = gtk_printer_cups_new (printer_name, backend);
1042
1043           cups_printer->device_uri = g_strdup_printf ("/printers/%s", printer_name);
1044
1045           /* Check to see if we are looking at a class */
1046           if (member_uris)
1047             {
1048               cups_printer->printer_uri = g_strdup (member_uris);
1049               /* TODO if member_uris is a class we need to recursivly find a printer */
1050               GTK_NOTE (PRINTING,
1051                         g_print ("CUPS Backend: Found class with printer %s\n", member_uris));
1052             }
1053           else
1054             {
1055               cups_printer->printer_uri = g_strdup (printer_uri);
1056               GTK_NOTE (PRINTING,
1057                         g_print ("CUPS Backend: Found printer %s\n", printer_uri));
1058             }
1059
1060 #if (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR >= 2) || CUPS_VERSION_MAJOR > 1
1061           httpSeparateURI (HTTP_URI_CODING_ALL, cups_printer->printer_uri, 
1062                            method, sizeof (method), 
1063                            username, sizeof (username),
1064                            hostname, sizeof (hostname),
1065                            &port, 
1066                            resource, sizeof (resource));
1067
1068 #else
1069           httpSeparate (cups_printer->printer_uri, 
1070                         method, 
1071                         username, 
1072                         hostname,
1073                         &port, 
1074                         resource);
1075 #endif
1076
1077           if (member_uris && !strncmp (resource, "/printers/", 10))
1078             {
1079               cups_printer->ppd_name = g_strdup (resource + 10);
1080               GTK_NOTE (PRINTING,
1081                         g_print ("CUPS Backend: Setting ppd name '%s' for printer class '%s'\n", cups_printer->ppd_name, printer_name));
1082             }
1083
1084           gethostname (uri, sizeof(uri));
1085           if (strcasecmp (uri, hostname) == 0)
1086             strcpy (hostname, "localhost");
1087
1088           cups_printer->hostname = g_strdup (hostname);
1089           cups_printer->port = port;
1090           
1091           printer = GTK_PRINTER (cups_printer);
1092           
1093           if (cups_backend->default_printer != NULL &&
1094               strcmp (cups_backend->default_printer, gtk_printer_get_name (printer)) == 0)
1095             gtk_printer_set_is_default (printer, TRUE);
1096
1097           
1098           gtk_print_backend_add_printer (backend, printer);
1099         }
1100       else
1101         g_object_ref (printer);
1102
1103       if (!gtk_printer_is_active (printer))
1104         {
1105           gtk_printer_set_is_active (printer, TRUE);
1106           gtk_printer_set_is_new (printer, TRUE);
1107           list_has_changed = TRUE;
1108         }
1109
1110       if (gtk_printer_is_new (printer))
1111         {
1112           g_signal_emit_by_name (backend, "printer-added", printer);
1113
1114           gtk_printer_set_is_new (printer, FALSE);
1115         }
1116
1117       cups_request_printer_info (cups_backend, gtk_printer_get_name (printer));
1118
1119       /* The ref is held by GtkPrintBackend, in add_printer() */
1120       g_object_unref (printer);
1121
1122       
1123       if (attr == NULL)
1124         break;
1125     }
1126
1127   /* look at the removed printers checklist and mark any printer
1128      as inactive if it is in the list, emitting a printer_removed signal */
1129   if (removed_printer_checklist != NULL)
1130     {
1131       g_list_foreach (removed_printer_checklist, (GFunc) mark_printer_inactive, backend);
1132       g_list_free (removed_printer_checklist);
1133       list_has_changed = TRUE;
1134     }
1135   
1136   if (list_has_changed)
1137     g_signal_emit_by_name (backend, "printer-list-changed");
1138   
1139   gtk_print_backend_set_list_done (backend);
1140 }
1141
1142 static gboolean
1143 cups_request_printer_list (GtkPrintBackendCups *cups_backend)
1144 {
1145   GtkCupsRequest *request;
1146   static const char * const pattrs[] =  /* Attributes we're interested in */
1147     {
1148       "printer-name",
1149       "printer-uri-supported",
1150       "member-uris"
1151     };
1152  
1153   if (cups_backend->list_printers_pending ||
1154       !cups_backend->got_default_printer)
1155     return TRUE;
1156
1157   cups_backend->list_printers_pending = TRUE;
1158
1159   request = gtk_cups_request_new (NULL,
1160                                   GTK_CUPS_POST,
1161                                   CUPS_GET_PRINTERS,
1162                                   NULL,
1163                                   NULL,
1164                                   NULL);
1165
1166   gtk_cups_request_ipp_add_strings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1167                                     "requested-attributes", G_N_ELEMENTS (pattrs),
1168                                     NULL, pattrs);
1169
1170   cups_request_execute (cups_backend,
1171                         request,
1172                         (GtkPrintCupsResponseCallbackFunc) cups_request_printer_list_cb,
1173                         request,
1174                         NULL);
1175
1176   return TRUE;
1177 }
1178
1179 static void
1180 cups_get_printer_list (GtkPrintBackend *backend)
1181 {
1182   GtkPrintBackendCups *cups_backend;
1183
1184   cups_backend = GTK_PRINT_BACKEND_CUPS (backend);
1185   if (cups_backend->list_printers_poll == 0)
1186     {
1187       cups_request_printer_list (cups_backend);
1188       cups_backend->list_printers_poll = g_timeout_add (3000 * 100000,
1189                                                         (GSourceFunc) cups_request_printer_list,
1190                                                         backend);
1191     }
1192 }
1193
1194 typedef struct {
1195   GtkPrinterCups *printer;
1196   GIOChannel *ppd_io;
1197 } GetPPDData;
1198
1199 static void
1200 get_ppd_data_free (GetPPDData *data)
1201 {
1202   GTK_NOTE (PRINTING,
1203             g_print ("CUPS Backend: %s\n", G_STRFUNC));
1204
1205   g_io_channel_unref (data->ppd_io);
1206   g_object_unref (data->printer);
1207   g_free (data);
1208 }
1209
1210 static void
1211 cups_request_ppd_cb (GtkPrintBackendCups *print_backend,
1212                      GtkCupsResult       *result,
1213                      GetPPDData          *data)
1214 {
1215   ipp_t *response;
1216   GtkPrinter *printer;
1217
1218   GTK_NOTE (PRINTING,
1219             g_print ("CUPS Backend: %s\n", G_STRFUNC));
1220
1221   printer = GTK_PRINTER (data->printer);
1222   GTK_PRINTER_CUPS (printer)->reading_ppd = FALSE;
1223
1224   if (gtk_cups_result_is_error (result))
1225     {
1226       g_signal_emit_by_name (printer, "details-acquired", FALSE);
1227       return;
1228     }
1229
1230   response = gtk_cups_result_get_response (result);
1231
1232   /* let ppdOpenFd take over the ownership of the open file */
1233   g_io_channel_seek_position (data->ppd_io, 0, G_SEEK_SET, NULL);
1234   data->printer->ppd_file = ppdOpenFd (dup (g_io_channel_unix_get_fd (data->ppd_io)));
1235   
1236   gtk_printer_set_has_details (printer, TRUE);
1237   g_signal_emit_by_name (printer, "details-acquired", TRUE);
1238 }
1239
1240 static void
1241 cups_request_ppd (GtkPrinter *printer)
1242 {
1243   GError *error;
1244   GtkPrintBackend *print_backend;
1245   GtkPrinterCups *cups_printer;
1246   GtkCupsRequest *request;
1247   char *ppd_filename;
1248   gchar *resource;
1249   http_t *http;
1250   GetPPDData *data;
1251   int fd;
1252
1253   cups_printer = GTK_PRINTER_CUPS (printer);
1254
1255   error = NULL;
1256
1257   GTK_NOTE (PRINTING,
1258             g_print ("CUPS Backend: %s\n", G_STRFUNC));
1259
1260   /* FIXME this can return NULL! */
1261   http = httpConnectEncrypt (cups_printer->hostname, 
1262                              cups_printer->port,
1263                              cupsEncryption ());
1264
1265   data = g_new0 (GetPPDData, 1);
1266
1267   fd = g_file_open_tmp ("gtkprint_ppd_XXXXXX", 
1268                         &ppd_filename, 
1269                         &error);
1270
1271 #ifdef G_ENABLE_DEBUG 
1272   /* If we are debugging printing don't delete the tmp files */
1273   if (!(gtk_debug_flags & GTK_DEBUG_PRINTING))
1274     unlink (ppd_filename);
1275 #else
1276   unlink (ppd_filename);
1277 #endif /* G_ENABLE_DEBUG */
1278
1279   if (error != NULL)
1280     {
1281       g_warning ("%s", error->message);
1282       g_error_free (error);
1283       httpClose (http);
1284       g_free (ppd_filename);
1285       g_free (data);
1286
1287       g_signal_emit_by_name (printer, "details-acquired", FALSE);
1288       return;
1289     }
1290     
1291   fchmod (fd, S_IRUSR | S_IWUSR);
1292   data->ppd_io = g_io_channel_unix_new (fd);
1293   g_io_channel_set_encoding (data->ppd_io, NULL, NULL);
1294   g_io_channel_set_close_on_unref (data->ppd_io, TRUE);
1295
1296   data->printer = g_object_ref (printer);
1297
1298   resource = g_strdup_printf ("/printers/%s.ppd", 
1299                               gtk_printer_cups_get_ppd_name (GTK_PRINTER_CUPS(printer)));
1300   request = gtk_cups_request_new (http,
1301                                   GTK_CUPS_GET,
1302                                   0,
1303                                   data->ppd_io,
1304                                   cups_printer->hostname,
1305                                   resource);
1306
1307   GTK_NOTE (PRINTING,
1308             g_print ("CUPS Backend: Requesting resource %s to be written to temp file %s\n", resource, ppd_filename));
1309
1310   g_free (resource);
1311   g_free (ppd_filename);
1312
1313   cups_printer->reading_ppd = TRUE;
1314
1315   print_backend = gtk_printer_get_backend (printer);
1316
1317   cups_request_execute (GTK_PRINT_BACKEND_CUPS (print_backend),
1318                         request,
1319                         (GtkPrintCupsResponseCallbackFunc) cups_request_ppd_cb,
1320                         data,
1321                         (GDestroyNotify)get_ppd_data_free);
1322 }
1323
1324
1325 static void
1326 cups_request_default_printer_cb (GtkPrintBackendCups *print_backend,
1327                                  GtkCupsResult       *result,
1328                                  gpointer             user_data)
1329 {
1330   ipp_t *response;
1331   ipp_attribute_t *attr;
1332
1333   response = gtk_cups_result_get_response (result);
1334   
1335   if ((attr = ippFindAttribute (response, "printer-name", IPP_TAG_NAME)) != NULL)
1336     print_backend->default_printer = g_strdup (attr->values[0].string.text);
1337
1338   print_backend->got_default_printer = TRUE;
1339
1340   /* Make sure to kick off get_printers if we are polling it, 
1341    * as we could have blocked this reading the default printer 
1342    */
1343   if (print_backend->list_printers_poll != 0)
1344     cups_request_printer_list (print_backend);
1345 }
1346
1347 static void
1348 cups_request_default_printer (GtkPrintBackendCups *print_backend)
1349 {
1350   GtkCupsRequest *request;
1351   const char *str;
1352
1353   if ((str = g_getenv ("LPDEST")) != NULL)
1354     {
1355       print_backend->default_printer = g_strdup (str);
1356       print_backend->got_default_printer = TRUE;
1357       return;
1358     }
1359   else if ((str = g_getenv ("PRINTER")) != NULL &&
1360            strcmp (str, "lp") != 0)
1361     {
1362       print_backend->default_printer = g_strdup (str);
1363       print_backend->got_default_printer = TRUE;
1364       return;
1365     }
1366   
1367   request = gtk_cups_request_new (NULL,
1368                                   GTK_CUPS_POST,
1369                                   CUPS_GET_DEFAULT,
1370                                   NULL,
1371                                   NULL,
1372                                   NULL);
1373   
1374   cups_request_execute (print_backend,
1375                         request,
1376                         (GtkPrintCupsResponseCallbackFunc) cups_request_default_printer_cb,
1377                         g_object_ref (print_backend),
1378                         g_object_unref);
1379 }
1380
1381 static void
1382 cups_printer_request_details (GtkPrinter *printer)
1383 {
1384   GtkPrinterCups *cups_printer;
1385
1386   cups_printer = GTK_PRINTER_CUPS (printer);
1387   if (!cups_printer->reading_ppd && 
1388       gtk_printer_cups_get_ppd (cups_printer) == NULL)
1389     cups_request_ppd (printer); 
1390 }
1391
1392 static char *
1393 ppd_text_to_utf8 (ppd_file_t *ppd_file, 
1394                   const char *text)
1395 {
1396   const char *encoding = NULL;
1397   char *res;
1398   
1399   if (g_ascii_strcasecmp (ppd_file->lang_encoding, "UTF-8") == 0)
1400     {
1401       return g_strdup (text);
1402     }
1403   else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "ISOLatin1") == 0)
1404     {
1405       encoding = "ISO-8859-1";
1406     }
1407   else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "ISOLatin2") == 0)
1408     {
1409       encoding = "ISO-8859-2";
1410     }
1411   else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "ISOLatin5") == 0)
1412     {
1413       encoding = "ISO-8859-5";
1414     }
1415   else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "JIS83-RKSJ") == 0)
1416     {
1417       encoding = "SHIFT-JIS";
1418     }
1419   else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "MacStandard") == 0)
1420     {
1421       encoding = "MACINTOSH";
1422     }
1423   else if (g_ascii_strcasecmp (ppd_file->lang_encoding, "WindowsANSI") == 0)
1424     {
1425       encoding = "WINDOWS-1252";
1426     }
1427   else 
1428     {
1429       /* Fallback, try iso-8859-1... */
1430       encoding = "ISO-8859-1";
1431     }
1432
1433   res = g_convert (text, -1, "UTF-8", encoding, NULL, NULL, NULL);
1434
1435   if (res == NULL)
1436     {
1437       g_warning ("unable to convert PPD text");
1438       res = g_strdup ("???");
1439     }
1440   
1441   return res;
1442 }
1443
1444 /* TODO: Add more translations for common settings here */
1445
1446 static const struct {
1447   const char *keyword;
1448   const char *translation;
1449 } cups_option_translations[] = {
1450   { "Duplex", N_("Two Sided") },
1451   { "MediaType", N_("Paper Type") },
1452   { "InputSlot", N_("Paper Source") },
1453   { "OutputBin", N_("Output Tray") },
1454 };
1455
1456
1457 static const struct {
1458   const char *keyword;
1459   const char *choice;
1460   const char *translation;
1461 } cups_choice_translations[] = {
1462   { "Duplex", "None", N_("One Sided") },
1463   { "InputSlot", "Auto", N_("Auto Select") },
1464   { "InputSlot", "AutoSelect", N_("Auto Select") },
1465   { "InputSlot", "Default", N_("Printer Default") },
1466   { "InputSlot", "None", N_("Printer Default") },
1467   { "InputSlot", "PrinterDefault", N_("Printer Default") },
1468   { "InputSlot", "Unspecified", N_("Auto Select") },
1469 };
1470
1471 static const struct {
1472   const char *ppd_keyword;
1473   const char *name;
1474 } option_names[] = {
1475   {"Duplex", "gtk-duplex" },
1476   {"MediaType", "gtk-paper-type"},
1477   {"InputSlot", "gtk-paper-source"},
1478   {"OutputBin", "gtk-output-tray"},
1479 };
1480
1481 /* keep sorted when changing */
1482 static const char *color_option_whitelist[] = {
1483   "BRColorEnhancement",
1484   "BRColorMatching",
1485   "BRColorMatching",
1486   "BRColorMode",
1487   "BRGammaValue",
1488   "BRImprovedGray",
1489   "BlackSubstitution",
1490   "ColorModel",
1491   "HPCMYKInks",
1492   "HPCSGraphics",
1493   "HPCSImages",
1494   "HPCSText",
1495   "HPColorSmart",
1496   "RPSBlackMode",
1497   "RPSBlackOverPrint",
1498   "Rcmyksimulation",
1499 };
1500
1501 /* keep sorted when changing */
1502 static const char *color_group_whitelist[] = {
1503   "ColorPage",
1504   "FPColorWise1",
1505   "FPColorWise2",
1506   "FPColorWise3",
1507   "FPColorWise4",
1508   "FPColorWise5",
1509   "HPColorOptionsPanel",
1510 };
1511   
1512 /* keep sorted when changing */
1513 static const char *image_quality_option_whitelist[] = {
1514   "BRDocument",
1515   "BRHalfTonePattern",
1516   "BRNormalPrt",
1517   "BRPrintQuality",
1518   "BitsPerPixel",
1519   "Darkness",
1520   "Dithering",
1521   "EconoMode",
1522   "Economode",
1523   "HPEconoMode",
1524   "HPEdgeControl",
1525   "HPGraphicsHalftone",
1526   "HPHalftone",
1527   "HPLJDensity",
1528   "HPPhotoHalftone",
1529   "OutputMode",
1530   "REt",
1531   "RPSBitsPerPixel",
1532   "RPSDitherType",
1533   "Resolution",
1534   "ScreenLock",
1535   "Smoothing",
1536   "TonerSaveMode",
1537   "UCRGCRForImage",
1538 };
1539
1540 /* keep sorted when changing */
1541 static const char *image_quality_group_whitelist[] = {
1542   "FPImageQuality1",
1543   "FPImageQuality2",
1544   "FPImageQuality3",
1545   "ImageQualityPage",
1546 };
1547
1548 /* keep sorted when changing */
1549 static const char * finishing_option_whitelist[] = {
1550   "BindColor",
1551   "BindEdge",
1552   "BindType",
1553   "BindWhen",
1554   "Booklet",
1555   "FoldType",
1556   "FoldWhen",
1557   "HPStaplerOptions",
1558   "Jog",
1559   "Slipsheet",
1560   "Sorter",
1561   "StapleLocation",
1562   "StapleOrientation",
1563   "StapleWhen",
1564   "StapleX",
1565   "StapleY",
1566 };
1567
1568 /* keep sorted when changing */
1569 static const char *finishing_group_whitelist[] = {
1570   "FPFinishing1",
1571   "FPFinishing2",
1572   "FPFinishing3",
1573   "FPFinishing4",
1574   "FinishingPage",
1575   "HPFinishingPanel",
1576 };
1577
1578 /* keep sorted when changing */
1579 static const char *cups_option_blacklist[] = {
1580   "Collate",
1581   "Copies", 
1582   "OutputOrder",
1583   "PageRegion",
1584   "PageSize",
1585 };
1586
1587 static char *
1588 get_option_text (ppd_file_t   *ppd_file, 
1589                  ppd_option_t *option)
1590 {
1591   int i;
1592   char *utf8;
1593   
1594   for (i = 0; i < G_N_ELEMENTS (cups_option_translations); i++)
1595     {
1596       if (strcmp (cups_option_translations[i].keyword, option->keyword) == 0)
1597         return g_strdup (_(cups_option_translations[i].translation));
1598     }
1599
1600   utf8 = ppd_text_to_utf8 (ppd_file, option->text);
1601
1602   /* Some ppd files have spaces in the text before the colon */
1603   g_strchomp (utf8);
1604   
1605   return utf8;
1606 }
1607
1608 static char *
1609 get_choice_text (ppd_file_t   *ppd_file, 
1610                  ppd_choice_t *choice)
1611 {
1612   int i;
1613   ppd_option_t *option = choice->option;
1614   const char *keyword = option->keyword;
1615   
1616   for (i = 0; i < G_N_ELEMENTS (cups_choice_translations); i++)
1617     {
1618       if (strcmp (cups_choice_translations[i].keyword, keyword) == 0 &&
1619           strcmp (cups_choice_translations[i].choice, choice->choice) == 0)
1620         return g_strdup (_(cups_choice_translations[i].translation));
1621     }
1622   return ppd_text_to_utf8 (ppd_file, choice->text);
1623 }
1624
1625 static gboolean
1626 group_has_option (ppd_group_t  *group, 
1627                   ppd_option_t *option)
1628 {
1629   int i;
1630
1631   if (group == NULL)
1632     return FALSE;
1633   
1634   if (group->num_options > 0 &&
1635       option >= group->options && option < group->options + group->num_options)
1636     return TRUE;
1637   
1638   for (i = 0; i < group->num_subgroups; i++)
1639     {
1640       if (group_has_option (&group->subgroups[i],option))
1641         return TRUE;
1642     }
1643   return FALSE;
1644 }
1645
1646 static void
1647 set_option_off (GtkPrinterOption *option)
1648 {
1649   /* Any of these will do, _set only applies the value
1650    * if its allowed of the option */
1651   gtk_printer_option_set (option, "False");
1652   gtk_printer_option_set (option, "Off");
1653   gtk_printer_option_set (option, "None");
1654 }
1655
1656 static gboolean
1657 value_is_off (const char *value)
1658 {
1659   return  (strcasecmp (value, "None") == 0 ||
1660            strcasecmp (value, "Off") == 0 ||
1661            strcasecmp (value, "False") == 0);
1662 }
1663
1664 static int
1665 available_choices (ppd_file_t     *ppd,
1666                    ppd_option_t   *option,
1667                    ppd_choice_t ***available,
1668                    gboolean        keep_if_only_one_option)
1669 {
1670   ppd_option_t *other_option;
1671   int i, j;
1672   gchar *conflicts;
1673   ppd_const_t *constraint;
1674   const char *choice, *other_choice;
1675   ppd_option_t *option1, *option2;
1676   ppd_group_t *installed_options;
1677   int num_conflicts;
1678   gboolean all_default;
1679   int add_auto;
1680
1681   if (available)
1682     *available = NULL;
1683
1684   conflicts = g_new0 (char, option->num_choices);
1685
1686   installed_options = NULL;
1687   for (i = 0; i < ppd->num_groups; i++)
1688     {
1689       if (strcmp (ppd->groups[i].name, "InstallableOptions") == 0)
1690         {
1691           installed_options = &ppd->groups[i];
1692           break;
1693         }
1694     }
1695
1696   for (i = ppd->num_consts, constraint = ppd->consts; i > 0; i--, constraint++)
1697     {
1698       option1 = ppdFindOption (ppd, constraint->option1);
1699       if (option1 == NULL)
1700         continue;
1701
1702       option2 = ppdFindOption (ppd, constraint->option2);
1703       if (option2 == NULL)
1704         continue;
1705
1706       if (option == option1)
1707         {
1708           choice = constraint->choice1;
1709           other_option = option2;
1710           other_choice = constraint->choice2;
1711         }
1712       else if (option == option2)
1713         {
1714           choice = constraint->choice2;
1715           other_option = option1;
1716           other_choice = constraint->choice1;
1717         }
1718       else
1719         continue;
1720
1721       /* We only care of conflicts with installed_options and
1722          PageSize */
1723       if (!group_has_option (installed_options, other_option) &&
1724           (strcmp (other_option->keyword, "PageSize") != 0))
1725         continue;
1726
1727       if (*other_choice == 0)
1728         {
1729           /* Conflict only if the installed option is not off */
1730           if (value_is_off (other_option->defchoice))
1731             continue;
1732         }
1733       /* Conflict if the installed option has the specified default */
1734       else if (strcasecmp (other_choice, other_option->defchoice) != 0)
1735         continue;
1736
1737       if (*choice == 0)
1738         {
1739           /* Conflict with all non-off choices */
1740           for (j = 0; j < option->num_choices; j++)
1741             {
1742               if (!value_is_off (option->choices[j].choice))
1743                 conflicts[j] = 1;
1744             }
1745         }
1746       else
1747         {
1748           for (j = 0; j < option->num_choices; j++)
1749             {
1750               if (strcasecmp (option->choices[j].choice, choice) == 0)
1751                 conflicts[j] = 1;
1752             }
1753         }
1754     }
1755
1756   num_conflicts = 0;
1757   all_default = TRUE;
1758   for (j = 0; j < option->num_choices; j++)
1759     {
1760       if (conflicts[j])
1761         num_conflicts++;
1762       else if (strcmp (option->choices[j].choice, option->defchoice) != 0)
1763         all_default = FALSE;
1764     }
1765
1766   if (all_default && !keep_if_only_one_option)
1767     return 0;
1768   
1769   if (num_conflicts == option->num_choices)
1770     return 0;
1771
1772
1773   /* Some ppds don't have a "use printer default" option for
1774    * InputSlot. This means you always have to select a particular slot,
1775    * and you can't auto-pick source based on the paper size. To support
1776    * this we always add an auto option if there isn't one already. If
1777    * the user chooses the generated option we don't send any InputSlot
1778    * value when printing. The way we detect existing auto-cases is based
1779    * on feedback from Michael Sweet of cups fame.
1780    */
1781   add_auto = 0;
1782   if (strcmp (option->keyword, "InputSlot") == 0)
1783     {
1784       gboolean found_auto = FALSE;
1785       for (j = 0; j < option->num_choices; j++)
1786         {
1787           if (!conflicts[j])
1788             {
1789               if (strcmp (option->choices[j].choice, "Auto") == 0 ||
1790                   strcmp (option->choices[j].choice, "AutoSelect") == 0 ||
1791                   strcmp (option->choices[j].choice, "Default") == 0 ||
1792                   strcmp (option->choices[j].choice, "None") == 0 ||
1793                   strcmp (option->choices[j].choice, "PrinterDefault") == 0 ||
1794                   strcmp (option->choices[j].choice, "Unspecified") == 0 ||
1795                   option->choices[j].code == NULL ||
1796                   option->choices[j].code[0] == 0)
1797                 {
1798                   found_auto = TRUE;
1799                   break;
1800                 }
1801             }
1802         }
1803
1804       if (!found_auto)
1805         add_auto = 1;
1806     }
1807   
1808   if (available)
1809     {
1810       
1811       *available = g_new (ppd_choice_t *, option->num_choices - num_conflicts + add_auto);
1812
1813       i = 0;
1814       for (j = 0; j < option->num_choices; j++)
1815         {
1816           if (!conflicts[j])
1817             (*available)[i++] = &option->choices[j];
1818         }
1819
1820       if (add_auto) 
1821         (*available)[i++] = NULL;
1822     }
1823   
1824   return option->num_choices - num_conflicts + add_auto;
1825 }
1826
1827 static GtkPrinterOption *
1828 create_pickone_option (ppd_file_t   *ppd_file,
1829                        ppd_option_t *ppd_option,
1830                        const gchar  *gtk_name)
1831 {
1832   GtkPrinterOption *option;
1833   ppd_choice_t **available;
1834   char *label;
1835   int n_choices;
1836   int i;
1837
1838   g_assert (ppd_option->ui == PPD_UI_PICKONE);
1839   
1840   option = NULL;
1841
1842   n_choices = available_choices (ppd_file, ppd_option, &available, g_str_has_prefix (gtk_name, "gtk-"));
1843   if (n_choices > 0)
1844     {
1845       label = get_option_text (ppd_file, ppd_option);
1846       option = gtk_printer_option_new (gtk_name, label,
1847                                        GTK_PRINTER_OPTION_TYPE_PICKONE);
1848       g_free (label);
1849       
1850       gtk_printer_option_allocate_choices (option, n_choices);
1851       for (i = 0; i < n_choices; i++)
1852         {
1853           if (available[i] == NULL)
1854             {
1855               /* This was auto-added */
1856               option->choices[i] = g_strdup ("gtk-ignore-value");
1857               option->choices_display[i] = g_strdup (_("Printer Default"));
1858             }
1859           else
1860             {
1861               option->choices[i] = g_strdup (available[i]->choice);
1862               option->choices_display[i] = get_choice_text (ppd_file, available[i]);
1863             }
1864         }
1865       gtk_printer_option_set (option, ppd_option->defchoice);
1866     }
1867 #ifdef PRINT_IGNORED_OPTIONS
1868   else
1869     g_warning ("Ignoring pickone %s\n", ppd_option->text);
1870 #endif
1871   g_free (available);
1872
1873   return option;
1874 }
1875
1876 static GtkPrinterOption *
1877 create_boolean_option (ppd_file_t   *ppd_file,
1878                        ppd_option_t *ppd_option,
1879                        const gchar  *gtk_name)
1880 {
1881   GtkPrinterOption *option;
1882   ppd_choice_t **available;
1883   char *label;
1884   int n_choices;
1885
1886   g_assert (ppd_option->ui == PPD_UI_BOOLEAN);
1887   
1888   option = NULL;
1889
1890   n_choices = available_choices (ppd_file, ppd_option, &available, g_str_has_prefix (gtk_name, "gtk-"));
1891   if (n_choices == 2)
1892     {
1893       label = get_option_text (ppd_file, ppd_option);
1894       option = gtk_printer_option_new (gtk_name, label,
1895                                        GTK_PRINTER_OPTION_TYPE_BOOLEAN);
1896       g_free (label);
1897       
1898       gtk_printer_option_allocate_choices (option, 2);
1899       option->choices[0] = g_strdup ("True");
1900       option->choices_display[0] = g_strdup ("True");
1901       option->choices[1] = g_strdup ("False");
1902       option->choices_display[1] = g_strdup ("False");
1903       
1904       gtk_printer_option_set (option, ppd_option->defchoice);
1905     }
1906 #ifdef PRINT_IGNORED_OPTIONS
1907   else
1908     g_warning ("Ignoring boolean %s\n", ppd_option->text);
1909 #endif
1910   g_free (available);
1911
1912   return option;
1913 }
1914
1915 static gchar *
1916 get_option_name (const gchar *keyword)
1917 {
1918   int i;
1919
1920   for (i = 0; i < G_N_ELEMENTS (option_names); i++)
1921     if (strcmp (option_names[i].ppd_keyword, keyword) == 0)
1922       return g_strdup (option_names[i].name);
1923
1924   return g_strdup_printf ("cups-%s", keyword);
1925 }
1926
1927 static int
1928 strptr_cmp (const void *a, 
1929             const void *b)
1930 {
1931   char **aa = (char **)a;
1932   char **bb = (char **)b;
1933   return strcmp (*aa, *bb);
1934 }
1935
1936
1937 static gboolean
1938 string_in_table (gchar       *str, 
1939                  const gchar *table[], 
1940                  gint         table_len)
1941 {
1942   return bsearch (&str, table, table_len, sizeof (char *), (void *)strptr_cmp) != NULL;
1943 }
1944
1945 #define STRING_IN_TABLE(_str, _table) (string_in_table (_str, _table, G_N_ELEMENTS (_table)))
1946
1947 static void
1948 handle_option (GtkPrinterOptionSet *set,
1949                ppd_file_t          *ppd_file,
1950                ppd_option_t        *ppd_option,
1951                ppd_group_t         *toplevel_group,
1952                GtkPrintSettings    *settings)
1953 {
1954   GtkPrinterOption *option;
1955   char *name;
1956
1957   if (STRING_IN_TABLE (ppd_option->keyword, cups_option_blacklist))
1958     return;
1959   
1960   name = get_option_name (ppd_option->keyword);
1961
1962   option = NULL;
1963   if (ppd_option->ui == PPD_UI_PICKONE)
1964     {
1965       option = create_pickone_option (ppd_file, ppd_option, name);
1966     }
1967   else if (ppd_option->ui == PPD_UI_BOOLEAN)
1968     {
1969       option = create_boolean_option (ppd_file, ppd_option, name);
1970     }
1971   else
1972     g_warning ("Ignored pickmany setting %s\n", ppd_option->text);
1973   
1974   
1975   if (option)
1976     {
1977       if (STRING_IN_TABLE (toplevel_group->name,
1978                            color_group_whitelist) ||
1979           STRING_IN_TABLE (ppd_option->keyword,
1980                            color_option_whitelist))
1981         {
1982           option->group = g_strdup ("ColorPage");
1983         }
1984       else if (STRING_IN_TABLE (toplevel_group->name,
1985                                 image_quality_group_whitelist) ||
1986                STRING_IN_TABLE (ppd_option->keyword,
1987                                 image_quality_option_whitelist))
1988         {
1989           option->group = g_strdup ("ImageQualityPage");
1990         }
1991       else if (STRING_IN_TABLE (toplevel_group->name,
1992                                 finishing_group_whitelist) ||
1993                STRING_IN_TABLE (ppd_option->keyword,
1994                                 finishing_option_whitelist))
1995         {
1996           option->group = g_strdup ("FinishingPage");
1997         }
1998       else
1999         {
2000           option->group = g_strdup (toplevel_group->text);
2001         }
2002
2003       set_option_from_settings (option, settings);
2004       
2005       gtk_printer_option_set_add (set, option);
2006     }
2007   
2008   g_free (name);
2009 }
2010
2011 static void
2012 handle_group (GtkPrinterOptionSet *set,
2013               ppd_file_t          *ppd_file,
2014               ppd_group_t         *group,
2015               ppd_group_t         *toplevel_group,
2016               GtkPrintSettings    *settings)
2017 {
2018   gint i;
2019
2020   /* Ignore installable options */
2021   if (strcmp (toplevel_group->name, "InstallableOptions") == 0)
2022     return;
2023   
2024   for (i = 0; i < group->num_options; i++)
2025     handle_option (set, ppd_file, &group->options[i], toplevel_group, settings);
2026
2027   for (i = 0; i < group->num_subgroups; i++)
2028     handle_group (set, ppd_file, &group->subgroups[i], toplevel_group, settings);
2029
2030 }
2031
2032 static GtkPrinterOptionSet *
2033 cups_printer_get_options (GtkPrinter           *printer,
2034                           GtkPrintSettings     *settings,
2035                           GtkPageSetup         *page_setup,
2036                           GtkPrintCapabilities  capabilities)
2037 {
2038   GtkPrinterOptionSet *set;
2039   GtkPrinterOption *option;
2040   ppd_file_t *ppd_file;
2041   int i;
2042   char *print_at[] = { "now", "at", "on-hold" };
2043   char *n_up[] = {"1", "2", "4", "6", "9", "16" };
2044   char *prio[] = {"100", "80", "50", "30" };
2045   char *prio_display[] = {N_("Urgent"), N_("High"), N_("Medium"), N_("Low") };
2046   char *cover[] = {"none", "classified", "confidential", "secret", "standard", "topsecret", "unclassified" };
2047   char *cover_display[] = {N_("None"), N_("Classified"), N_("Confidential"), N_("Secret"), N_("Standard"), N_("Top Secret"), N_("Unclassified"),};
2048
2049
2050   set = gtk_printer_option_set_new ();
2051
2052   /* Cups specific, non-ppd related settings */
2053
2054   option = gtk_printer_option_new ("gtk-n-up", "Pages Per Sheet", GTK_PRINTER_OPTION_TYPE_PICKONE);
2055   gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (n_up),
2056                                          n_up, n_up);
2057   gtk_printer_option_set (option, "1");
2058   set_option_from_settings (option, settings);
2059   gtk_printer_option_set_add (set, option);
2060   g_object_unref (option);
2061
2062   for (i = 0; i < G_N_ELEMENTS(prio_display); i++)
2063     prio_display[i] = _(prio_display[i]);
2064   
2065   option = gtk_printer_option_new ("gtk-job-prio", "Job Priority", GTK_PRINTER_OPTION_TYPE_PICKONE);
2066   gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (prio),
2067                                          prio, prio_display);
2068   gtk_printer_option_set (option, "50");
2069   set_option_from_settings (option, settings);
2070   gtk_printer_option_set_add (set, option);
2071   g_object_unref (option);
2072
2073   option = gtk_printer_option_new ("gtk-billing-info", "Billing Info", GTK_PRINTER_OPTION_TYPE_STRING);
2074   gtk_printer_option_set (option, "");
2075   set_option_from_settings (option, settings);
2076   gtk_printer_option_set_add (set, option);
2077   g_object_unref (option);
2078
2079   for (i = 0; i < G_N_ELEMENTS(cover_display); i++)
2080     cover_display[i] = _(cover_display[i]);
2081   
2082   option = gtk_printer_option_new ("gtk-cover-before", "Before", GTK_PRINTER_OPTION_TYPE_PICKONE);
2083   gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (cover),
2084                                          cover, cover_display);
2085   gtk_printer_option_set (option, "none");
2086   set_option_from_settings (option, settings);
2087   gtk_printer_option_set_add (set, option);
2088   g_object_unref (option);
2089
2090   option = gtk_printer_option_new ("gtk-cover-after", "After", GTK_PRINTER_OPTION_TYPE_PICKONE);
2091   gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (cover),
2092                                          cover, cover_display);
2093   gtk_printer_option_set (option, "none");
2094   set_option_from_settings (option, settings);
2095   gtk_printer_option_set_add (set, option);
2096   g_object_unref (option);
2097
2098   option = gtk_printer_option_new ("gtk-print-time", "Print at", GTK_PRINTER_OPTION_TYPE_PICKONE);
2099   gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (print_at),
2100                                          print_at, print_at);
2101   gtk_printer_option_set (option, "now");
2102   set_option_from_settings (option, settings);
2103   gtk_printer_option_set_add (set, option);
2104   g_object_unref (option);
2105   
2106   option = gtk_printer_option_new ("gtk-print-time-text", "Print at time", GTK_PRINTER_OPTION_TYPE_STRING);
2107   gtk_printer_option_set (option, "");
2108   set_option_from_settings (option, settings);
2109   gtk_printer_option_set_add (set, option);
2110   g_object_unref (option);
2111   
2112   /* Printer (ppd) specific settings */
2113   ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
2114   if (ppd_file)
2115     {
2116       GtkPaperSize *paper_size;
2117       ppd_option_t *option;
2118
2119       ppdMarkDefaults (ppd_file);
2120
2121       paper_size = gtk_page_setup_get_paper_size (page_setup);
2122
2123       option = ppdFindOption (ppd_file, "PageSize");
2124       strncpy (option->defchoice, gtk_paper_size_get_ppd_name (paper_size),
2125                PPD_MAX_NAME);
2126
2127       for (i = 0; i < ppd_file->num_groups; i++)
2128         handle_group (set, ppd_file, &ppd_file->groups[i], &ppd_file->groups[i], settings);
2129     }
2130
2131   return set;
2132 }
2133
2134
2135 static void
2136 mark_option_from_set (GtkPrinterOptionSet *set,
2137                       ppd_file_t          *ppd_file,
2138                       ppd_option_t        *ppd_option)
2139 {
2140   GtkPrinterOption *option;
2141   char *name = get_option_name (ppd_option->keyword);
2142
2143   option = gtk_printer_option_set_lookup (set, name);
2144
2145   if (option)
2146     ppdMarkOption (ppd_file, ppd_option->keyword, option->value);
2147   
2148   g_free (name);
2149 }
2150
2151
2152 static void
2153 mark_group_from_set (GtkPrinterOptionSet *set,
2154                      ppd_file_t          *ppd_file,
2155                      ppd_group_t         *group)
2156 {
2157   int i;
2158
2159   for (i = 0; i < group->num_options; i++)
2160     mark_option_from_set (set, ppd_file, &group->options[i]);
2161
2162   for (i = 0; i < group->num_subgroups; i++)
2163     mark_group_from_set (set, ppd_file, &group->subgroups[i]);
2164 }
2165
2166 static void
2167 set_conflicts_from_option (GtkPrinterOptionSet *set,
2168                            ppd_file_t          *ppd_file,
2169                            ppd_option_t        *ppd_option)
2170 {
2171   GtkPrinterOption *option;
2172   char *name;
2173
2174   if (ppd_option->conflicted)
2175     {
2176       name = get_option_name (ppd_option->keyword);
2177       option = gtk_printer_option_set_lookup (set, name);
2178
2179       if (option)
2180         gtk_printer_option_set_has_conflict (option, TRUE);
2181       else
2182         g_warning ("conflict for option %s ignored", ppd_option->keyword);
2183       
2184       g_free (name);
2185     }
2186 }
2187
2188 static void
2189 set_conflicts_from_group (GtkPrinterOptionSet *set,
2190                           ppd_file_t          *ppd_file,
2191                           ppd_group_t         *group)
2192 {
2193   int i;
2194
2195   for (i = 0; i < group->num_options; i++)
2196     set_conflicts_from_option (set, ppd_file, &group->options[i]);
2197
2198   for (i = 0; i < group->num_subgroups; i++)
2199     set_conflicts_from_group (set, ppd_file, &group->subgroups[i]);
2200 }
2201
2202 static gboolean
2203 cups_printer_mark_conflicts (GtkPrinter          *printer,
2204                              GtkPrinterOptionSet *options)
2205 {
2206   ppd_file_t *ppd_file;
2207   int num_conflicts;
2208   int i;
2209  
2210   ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
2211
2212   if (ppd_file == NULL)
2213     return FALSE;
2214
2215   ppdMarkDefaults (ppd_file);
2216
2217   for (i = 0; i < ppd_file->num_groups; i++)
2218     mark_group_from_set (options, ppd_file, &ppd_file->groups[i]);
2219
2220   num_conflicts = ppdConflicts (ppd_file);
2221
2222   if (num_conflicts > 0)
2223     {
2224       for (i = 0; i < ppd_file->num_groups; i++)
2225         set_conflicts_from_group (options, ppd_file, &ppd_file->groups[i]);
2226     }
2227  
2228   return num_conflicts > 0;
2229 }
2230
2231 struct OptionData {
2232   GtkPrinter *printer;
2233   GtkPrinterOptionSet *options;
2234   GtkPrintSettings *settings;
2235   ppd_file_t *ppd_file;
2236 };
2237
2238 typedef struct {
2239   const char *cups;
2240   const char *standard;
2241 } NameMapping;
2242
2243 static void
2244 map_settings_to_option (GtkPrinterOption  *option,
2245                         const NameMapping  table[],
2246                         gint               n_elements,
2247                         GtkPrintSettings  *settings,
2248                         const gchar       *standard_name,
2249                         const gchar       *cups_name)
2250 {
2251   int i;
2252   char *name;
2253   const char *cups_value;
2254   const char *standard_value;
2255
2256   /* If the cups-specific setting is set, always use that */
2257   name = g_strdup_printf ("cups-%s", cups_name);
2258   cups_value = gtk_print_settings_get (settings, name);
2259   g_free (name);
2260   
2261   if (cups_value != NULL) 
2262     {
2263       gtk_printer_option_set (option, cups_value);
2264       return;
2265     }
2266
2267   /* Otherwise we try to convert from the general setting */
2268   standard_value = gtk_print_settings_get (settings, standard_name);
2269   if (standard_value == NULL)
2270     return;
2271
2272   for (i = 0; i < n_elements; i++)
2273     {
2274       if (table[i].cups == NULL && table[i].standard == NULL)
2275         {
2276           gtk_printer_option_set (option, standard_value);
2277           break;
2278         }
2279       else if (table[i].cups == NULL &&
2280                strcmp (table[i].standard, standard_value) == 0)
2281         {
2282           set_option_off (option);
2283           break;
2284         }
2285       else if (strcmp (table[i].standard, standard_value) == 0)
2286         {
2287           gtk_printer_option_set (option, table[i].cups);
2288           break;
2289         }
2290     }
2291 }
2292
2293 static void
2294 map_option_to_settings (const gchar       *value,
2295                         const NameMapping  table[],
2296                         gint               n_elements,
2297                         GtkPrintSettings  *settings,
2298                         const gchar       *standard_name,
2299                         const gchar       *cups_name)
2300 {
2301   int i;
2302   char *name;
2303
2304   for (i = 0; i < n_elements; i++)
2305     {
2306       if (table[i].cups == NULL && table[i].standard == NULL)
2307         {
2308           gtk_print_settings_set (settings,
2309                                   standard_name,
2310                                   value);
2311           break;
2312         }
2313       else if (table[i].cups == NULL && table[i].standard != NULL)
2314         {
2315           if (value_is_off (value))
2316             {
2317               gtk_print_settings_set (settings,
2318                                       standard_name,
2319                                       table[i].standard);
2320               break;
2321             }
2322         }
2323       else if (strcmp (table[i].cups, value) == 0)
2324         {
2325           gtk_print_settings_set (settings,
2326                                   standard_name,
2327                                   table[i].standard);
2328           break;
2329         }
2330     }
2331
2332   /* Always set the corresponding cups-specific setting */
2333   name = g_strdup_printf ("cups-%s", cups_name);
2334   gtk_print_settings_set (settings, name, value);
2335   g_free (name);
2336 }
2337
2338
2339 static const NameMapping paper_source_map[] = {
2340   { "Lower", "lower"},
2341   { "Middle", "middle"},
2342   { "Upper", "upper"},
2343   { "Rear", "rear"},
2344   { "Envelope", "envelope"},
2345   { "Cassette", "cassette"},
2346   { "LargeCapacity", "large-capacity"},
2347   { "AnySmallFormat", "small-format"},
2348   { "AnyLargeFormat", "large-format"},
2349   { NULL, NULL}
2350 };
2351
2352 static const NameMapping output_tray_map[] = {
2353   { "Upper", "upper"},
2354   { "Lower", "lower"},
2355   { "Rear", "rear"},
2356   { NULL, NULL}
2357 };
2358
2359 static const NameMapping duplex_map[] = {
2360   { "DuplexTumble", "vertical" },
2361   { "DuplexNoTumble", "horizontal" },
2362   { NULL, "simplex" }
2363 };
2364
2365 static const NameMapping output_mode_map[] = {
2366   { "Standard", "normal" },
2367   { "Normal", "normal" },
2368   { "Draft", "draft" },
2369   { "Fast", "draft" },
2370 };
2371
2372 static const NameMapping media_type_map[] = {
2373   { "Transparency", "transparency"},
2374   { "Standard", "stationery"},
2375   { NULL, NULL}
2376 };
2377
2378 static const NameMapping all_map[] = {
2379   { NULL, NULL}
2380 };
2381
2382
2383 static void
2384 set_option_from_settings (GtkPrinterOption *option,
2385                           GtkPrintSettings *settings)
2386 {
2387   const char *cups_value;
2388   char *value;
2389   
2390   if (settings == NULL)
2391     return;
2392
2393   if (strcmp (option->name, "gtk-paper-source") == 0)
2394     map_settings_to_option (option, paper_source_map, G_N_ELEMENTS (paper_source_map),
2395                              settings, GTK_PRINT_SETTINGS_DEFAULT_SOURCE, "InputSlot");
2396   else if (strcmp (option->name, "gtk-output-tray") == 0)
2397     map_settings_to_option (option, output_tray_map, G_N_ELEMENTS (output_tray_map),
2398                             settings, GTK_PRINT_SETTINGS_OUTPUT_BIN, "OutputBin");
2399   else if (strcmp (option->name, "gtk-duplex") == 0)
2400     map_settings_to_option (option, duplex_map, G_N_ELEMENTS (duplex_map),
2401                             settings, GTK_PRINT_SETTINGS_DUPLEX, "Duplex");
2402   else if (strcmp (option->name, "cups-OutputMode") == 0)
2403     map_settings_to_option (option, output_mode_map, G_N_ELEMENTS (output_mode_map),
2404                             settings, GTK_PRINT_SETTINGS_QUALITY, "OutputMode");
2405   else if (strcmp (option->name, "cups-Resolution") == 0)
2406     {
2407       cups_value = gtk_print_settings_get (settings, option->name);
2408       if (cups_value)
2409         gtk_printer_option_set (option, cups_value);
2410       else
2411         {
2412           int res = gtk_print_settings_get_resolution (settings);
2413           if (res != 0)
2414             {
2415               value = g_strdup_printf ("%ddpi", res);
2416               gtk_printer_option_set (option, value);
2417               g_free (value);
2418             }
2419         }
2420     }
2421   else if (strcmp (option->name, "gtk-paper-type") == 0)
2422     map_settings_to_option (option, media_type_map, G_N_ELEMENTS (media_type_map),
2423                             settings, GTK_PRINT_SETTINGS_MEDIA_TYPE, "MediaType");
2424   else if (strcmp (option->name, "gtk-n-up") == 0)
2425     {
2426       map_settings_to_option (option, all_map, G_N_ELEMENTS (all_map),
2427                               settings, GTK_PRINT_SETTINGS_NUMBER_UP, "number-up");
2428     }
2429   else if (strcmp (option->name, "gtk-billing-info") == 0)
2430     {
2431       cups_value = gtk_print_settings_get (settings, "cups-job-billing");
2432       if (cups_value)
2433         gtk_printer_option_set (option, cups_value);
2434     } 
2435   else if (strcmp (option->name, "gtk-job-prio") == 0)
2436     {
2437       cups_value = gtk_print_settings_get (settings, "cups-job-priority");
2438       if (cups_value)
2439         gtk_printer_option_set (option, cups_value);
2440     } 
2441   else if (strcmp (option->name, "gtk-cover-before") == 0)
2442     {
2443       cups_value = gtk_print_settings_get (settings, "cover-before");
2444       if (cups_value)
2445         gtk_printer_option_set (option, cups_value);
2446     } 
2447   else if (strcmp (option->name, "gtk-cover-after") == 0)
2448     {
2449       cups_value = gtk_print_settings_get (settings, "cover-after");
2450       if (cups_value)
2451         gtk_printer_option_set (option, cups_value);
2452     } 
2453   else if (strcmp (option->name, "gtk-print-time") == 0)
2454     {
2455       cups_value = gtk_print_settings_get (settings, "print-at");
2456       if (cups_value)
2457         gtk_printer_option_set (option, cups_value);
2458     } 
2459   else if (strcmp (option->name, "gtk-print-time-text") == 0)
2460     {
2461       cups_value = gtk_print_settings_get (settings, "print-at-time");
2462       if (cups_value)
2463         gtk_printer_option_set (option, cups_value);
2464     } 
2465   else if (g_str_has_prefix (option->name, "cups-"))
2466     {
2467       cups_value = gtk_print_settings_get (settings, option->name);
2468       if (cups_value)
2469         gtk_printer_option_set (option, cups_value);
2470     } 
2471 }
2472
2473 static void
2474 foreach_option_get_settings (GtkPrinterOption *option,
2475                              gpointer          user_data)
2476 {
2477   struct OptionData *data = user_data;
2478   GtkPrintSettings *settings = data->settings;
2479   const char *value;
2480
2481   value = option->value;
2482
2483   if (strcmp (option->name, "gtk-paper-source") == 0)
2484     map_option_to_settings (value, paper_source_map, G_N_ELEMENTS (paper_source_map),
2485                             settings, GTK_PRINT_SETTINGS_DEFAULT_SOURCE, "InputSlot");
2486   else if (strcmp (option->name, "gtk-output-tray") == 0)
2487     map_option_to_settings (value, output_tray_map, G_N_ELEMENTS (output_tray_map),
2488                             settings, GTK_PRINT_SETTINGS_OUTPUT_BIN, "OutputBin");
2489   else if (strcmp (option->name, "gtk-duplex") == 0)
2490     map_option_to_settings (value, duplex_map, G_N_ELEMENTS (duplex_map),
2491                             settings, GTK_PRINT_SETTINGS_DUPLEX, "Duplex");
2492   else if (strcmp (option->name, "cups-OutputMode") == 0)
2493     map_option_to_settings (value, output_mode_map, G_N_ELEMENTS (output_mode_map),
2494                             settings, GTK_PRINT_SETTINGS_QUALITY, "OutputMode");
2495   else if (strcmp (option->name, "cups-Resolution") == 0)
2496     {
2497       int res = atoi (value);
2498       /* TODO: What if resolution is on XXXxYYYdpi form? */
2499       if (res != 0)
2500         gtk_print_settings_set_resolution (settings, res);
2501       gtk_print_settings_set (settings, option->name, value);
2502     }
2503   else if (strcmp (option->name, "gtk-paper-type") == 0)
2504     map_option_to_settings (value, media_type_map, G_N_ELEMENTS (media_type_map),
2505                             settings, GTK_PRINT_SETTINGS_MEDIA_TYPE, "MediaType");
2506   else if (strcmp (option->name, "gtk-n-up") == 0)
2507     map_option_to_settings (value, all_map, G_N_ELEMENTS (all_map),
2508                             settings, GTK_PRINT_SETTINGS_NUMBER_UP, "number-up");
2509   else if (strcmp (option->name, "gtk-billing-info") == 0 && strlen (value) > 0)
2510     gtk_print_settings_set (settings, "cups-job-billing", value);
2511   else if (strcmp (option->name, "gtk-job-prio") == 0)
2512     gtk_print_settings_set (settings, "cups-job-priority", value);
2513   else if (strcmp (option->name, "gtk-cover-before") == 0)
2514     gtk_print_settings_set (settings, "cover-before", value);
2515   else if (strcmp (option->name, "gtk-cover-after") == 0)
2516     gtk_print_settings_set (settings, "cover-after", value);
2517   else if (strcmp (option->name, "gtk-print-time") == 0)
2518     gtk_print_settings_set (settings, "print-at", value);
2519   else if (strcmp (option->name, "gtk-print-time-text") == 0)
2520     gtk_print_settings_set (settings, "print-at-time", value);
2521   else if (g_str_has_prefix (option->name, "cups-"))
2522     gtk_print_settings_set (settings, option->name, value);
2523 }
2524
2525 static void
2526 cups_printer_get_settings_from_options (GtkPrinter          *printer,
2527                                         GtkPrinterOptionSet *options,
2528                                         GtkPrintSettings    *settings)
2529 {
2530   struct OptionData data;
2531   const char *print_at, *print_at_time;
2532
2533   data.printer = printer;
2534   data.options = options;
2535   data.settings = settings;
2536   data.ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
2537  
2538   if (data.ppd_file != NULL)
2539     {
2540       GtkPrinterOption *cover_before, *cover_after;
2541       
2542       gtk_printer_option_set_foreach (options, foreach_option_get_settings, &data);
2543
2544       cover_before = gtk_printer_option_set_lookup (options, "gtk-cover-before");
2545       cover_after = gtk_printer_option_set_lookup (options, "gtk-cover-after");
2546       if (cover_before && cover_after)
2547         {
2548           char *value = g_strdup_printf ("%s,%s", cover_before->value, cover_after->value);
2549           gtk_print_settings_set (settings, "cups-job-sheets", value);
2550           g_free (value);
2551         }
2552
2553       print_at = gtk_print_settings_get (settings, "print-at");
2554       print_at_time = gtk_print_settings_get (settings, "print-at-time");
2555       if (strcmp (print_at, "at") == 0)
2556         gtk_print_settings_set (settings, "cups-job-hold-until", print_at_time);
2557       else if (strcmp (print_at, "on-hold") == 0)
2558         gtk_print_settings_set (settings, "cups-job-hold-until", "indefinite");
2559     }
2560 }
2561
2562 static void
2563 cups_printer_prepare_for_print (GtkPrinter       *printer,
2564                                 GtkPrintJob      *print_job,
2565                                 GtkPrintSettings *settings,
2566                                 GtkPageSetup     *page_setup)
2567 {
2568   GtkPageSet page_set;
2569   GtkPaperSize *paper_size;
2570   const char *ppd_paper_name;
2571   double scale;
2572
2573   print_job->print_pages = gtk_print_settings_get_print_pages (settings);
2574   print_job->page_ranges = NULL;
2575   print_job->num_page_ranges = 0;
2576   
2577   if (print_job->print_pages == GTK_PRINT_PAGES_RANGES)
2578     print_job->page_ranges =
2579       gtk_print_settings_get_page_ranges (settings,
2580                                           &print_job->num_page_ranges);
2581   
2582   if (gtk_print_settings_get_collate (settings))
2583     gtk_print_settings_set (settings, "cups-Collate", "True");
2584   print_job->collate = FALSE;
2585
2586   if (gtk_print_settings_get_reverse (settings))
2587     gtk_print_settings_set (settings, "cups-OutputOrder", "Reverse");
2588   print_job->reverse = FALSE;
2589
2590   if (gtk_print_settings_get_n_copies (settings) > 1)
2591     gtk_print_settings_set_int (settings, "cups-copies",
2592                                 gtk_print_settings_get_n_copies (settings));
2593   print_job->num_copies = 1;
2594
2595   scale = gtk_print_settings_get_scale (settings);
2596   print_job->scale = 1.0;
2597   if (scale != 100.0)
2598     print_job->scale = scale/100.0;
2599
2600   page_set = gtk_print_settings_get_page_set (settings);
2601   if (page_set == GTK_PAGE_SET_EVEN)
2602     gtk_print_settings_set (settings, "cups-page-set", "even");
2603   else if (page_set == GTK_PAGE_SET_ODD)
2604     gtk_print_settings_set (settings, "cups-page-set", "odd");
2605   print_job->page_set = GTK_PAGE_SET_ALL;
2606
2607   paper_size = gtk_page_setup_get_paper_size (page_setup);
2608   ppd_paper_name = gtk_paper_size_get_ppd_name (paper_size);
2609   if (ppd_paper_name != NULL)
2610     gtk_print_settings_set (settings, "cups-PageSize", ppd_paper_name);
2611   else
2612     {
2613       char *custom_name = g_strdup_printf ("Custom.%2fx%.2f",
2614                                            gtk_paper_size_get_width (paper_size, GTK_UNIT_POINTS),
2615                                            gtk_paper_size_get_height (paper_size, GTK_UNIT_POINTS));
2616       gtk_print_settings_set (settings, "cups-PageSize", custom_name);
2617       g_free (custom_name);
2618     }
2619
2620   print_job->rotate_to_orientation = TRUE;
2621 }
2622
2623 static GList *
2624 cups_printer_list_papers (GtkPrinter *printer)
2625 {
2626   ppd_file_t *ppd_file;
2627   ppd_size_t *size;
2628   char *display_name;
2629   GtkPageSetup *page_setup;
2630   GtkPaperSize *paper_size;
2631   ppd_option_t *option;
2632   ppd_choice_t *choice;
2633   GList *l;
2634   int i;
2635
2636   ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
2637   if (ppd_file == NULL)
2638     return NULL;
2639
2640   l = NULL;
2641   
2642   for (i = 0; i < ppd_file->num_sizes; i++)
2643     {
2644       size = &ppd_file->sizes[i];
2645
2646       display_name = NULL;
2647       option = ppdFindOption (ppd_file, "PageSize");
2648       if (option)
2649         {
2650           choice = ppdFindChoice (option, size->name);
2651           if (choice)
2652             display_name = ppd_text_to_utf8 (ppd_file, choice->text);
2653         }
2654       if (display_name == NULL)
2655         display_name = g_strdup (size->name);
2656
2657       page_setup = gtk_page_setup_new ();
2658       paper_size = gtk_paper_size_new_from_ppd (size->name,
2659                                                 display_name,
2660                                                 size->width,
2661                                                 size->length);
2662       gtk_page_setup_set_paper_size (page_setup, paper_size);
2663       gtk_paper_size_free (paper_size);
2664
2665       gtk_page_setup_set_top_margin (page_setup, size->length - size->top, GTK_UNIT_POINTS);
2666       gtk_page_setup_set_bottom_margin (page_setup, size->bottom, GTK_UNIT_POINTS);
2667       gtk_page_setup_set_left_margin (page_setup, size->left, GTK_UNIT_POINTS);
2668       gtk_page_setup_set_right_margin (page_setup, size->width - size->right, GTK_UNIT_POINTS);
2669         
2670       g_free (display_name);
2671
2672       l = g_list_prepend (l, page_setup);
2673     }
2674
2675   return g_list_reverse (l);
2676 }
2677
2678 static void
2679 cups_printer_get_hard_margins (GtkPrinter *printer,
2680                                gdouble    *top,
2681                                gdouble    *bottom,
2682                                gdouble    *left,
2683                                gdouble    *right)
2684 {
2685   ppd_file_t *ppd_file;
2686
2687   ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
2688   if (ppd_file == NULL)
2689     return;
2690
2691   *left = ppd_file->custom_margins[0];
2692   *bottom = ppd_file->custom_margins[1];
2693   *right = ppd_file->custom_margins[2];
2694   *top = ppd_file->custom_margins[3];
2695 }
2696
2697 static GtkPrintCapabilities
2698 cups_printer_get_capabilities (GtkPrinter *printer)
2699 {
2700   return
2701     GTK_PRINT_CAPABILITY_COPIES |
2702     GTK_PRINT_CAPABILITY_COLLATE |
2703     GTK_PRINT_CAPABILITY_REVERSE;
2704 }