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