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