]> Pileus Git - ~andy/gtk/blobdiff - modules/printbackends/cups/gtkprintbackendcups.c
Replace a lot of idle and timeout calls by the new gdk_threads api.
[~andy/gtk] / modules / printbackends / cups / gtkprintbackendcups.c
index 3380d8970d039f802a46259391143123f35d7809..5aab327f47f02c4ce39b76e7e938d5db39c22d58 100644 (file)
 #include <gtk/gtkprintsettings.h>
 #include <gtk/gtkprintbackend.h>
 #include <gtk/gtkprinter.h>
+#include <gtk/gtkprinter-private.h>
 
 #include "gtkprintbackendcups.h"
 #include "gtkprintercups.h"
 
 #include "gtkcupsutils.h"
+#include "gtkdebug.h"
 
 
 typedef struct _GtkPrintBackendCupsClass GtkPrintBackendCupsClass;
@@ -63,8 +65,8 @@ typedef struct _GtkPrintBackendCupsClass GtkPrintBackendCupsClass;
 static GType print_backend_cups_type = 0;
 
 typedef void (* GtkPrintCupsResponseCallbackFunc) (GtkPrintBackend *print_backend,
-                                                   GtkCupsResult *result, 
-                                                   gpointer user_data);
+                                                   GtkCupsResult   *result, 
+                                                   gpointer         user_data);
 
 typedef enum 
 {
@@ -100,7 +102,7 @@ struct _GtkPrintBackendCups
   
   guint list_printers_poll;
   guint list_printers_pending : 1;
-  guint got_default_printer : 1;
+  guint got_default_printer   : 1;
 };
 
 static GObjectClass *backend_parent_class;
@@ -114,8 +116,7 @@ static void                 cups_request_execute                   (GtkPrintBack
                                                                    GtkCupsRequest                    *request,
                                                                    GtkPrintCupsResponseCallbackFunc   callback,
                                                                    gpointer                           user_data,
-                                                                   GDestroyNotify                     notify,
-                                                                   GError                           **err);
+                                                                   GDestroyNotify                     notify);
 static void                 cups_printer_get_settings_from_options (GtkPrinter                        *printer,
                                                                    GtkPrinterOptionSet               *options,
                                                                    GtkPrintSettings                  *settings);
@@ -123,7 +124,8 @@ static gboolean             cups_printer_mark_conflicts            (GtkPrinter
                                                                    GtkPrinterOptionSet               *options);
 static GtkPrinterOptionSet *cups_printer_get_options               (GtkPrinter                        *printer,
                                                                    GtkPrintSettings                  *settings,
-                                                                   GtkPageSetup                      *page_setup);
+                                                                   GtkPageSetup                      *page_setup,
+                                                                    GtkPrintCapabilities               capabilities);
 static void                 cups_printer_prepare_for_print         (GtkPrinter                        *printer,
                                                                    GtkPrintJob                       *print_job,
                                                                    GtkPrintSettings                  *settings,
@@ -137,6 +139,7 @@ static void                 cups_printer_get_hard_margins          (GtkPrinter
                                                                    double                            *bottom,
                                                                    double                            *left,
                                                                    double                            *right);
+static GtkPrintCapabilities cups_printer_get_capabilities          (GtkPrinter                        *printer);
 static void                 set_option_from_settings               (GtkPrinterOption                  *option,
                                                                    GtkPrintSettings                  *setting);
 static void                 cups_begin_polling_info                (GtkPrintBackendCups               *print_backend,
@@ -145,14 +148,15 @@ static void                 cups_begin_polling_info                (GtkPrintBack
 static gboolean             cups_job_info_poll_timeout             (gpointer                           user_data);
 static void                 gtk_print_backend_cups_print_stream    (GtkPrintBackend                   *backend,
                                                                    GtkPrintJob                       *job,
-                                                                   gint                               data_fd,
+                                                                   GIOChannel                        *data_io,
                                                                    GtkPrintJobCompleteFunc            callback,
                                                                    gpointer                           user_data,
                                                                    GDestroyNotify                     dnotify);
 static cairo_surface_t *    cups_printer_create_cairo_surface      (GtkPrinter                        *printer,
+                                                                   GtkPrintSettings                  *settings,
                                                                    gdouble                            width,
                                                                    gdouble                            height,
-                                                                   gint                               cache_fd);
+                                                                   GIOChannel                        *cache_io);
 
 
 static void
@@ -167,7 +171,7 @@ gtk_print_backend_cups_register_type (GTypeModule *module)
     NULL,              /* class_finalize */
     NULL,              /* class_data */
     sizeof (GtkPrintBackendCups),
-    0,         /* n_preallocs */
+    0,                 /* n_preallocs */
     (GInstanceInitFunc) gtk_print_backend_cups_init
   };
 
@@ -180,6 +184,9 @@ gtk_print_backend_cups_register_type (GTypeModule *module)
 G_MODULE_EXPORT void 
 pb_module_init (GTypeModule *module)
 {
+  GTK_NOTE (PRINTING,
+            g_print ("CUPS Backend: Initializing the CUPS print backend module\n")); 
+
   gtk_print_backend_cups_register_type (module);
   gtk_printer_cups_register_type (module);
 }
@@ -213,10 +220,13 @@ gtk_print_backend_cups_get_type (void)
  * the filesystem using Unix/Linux API calls
  *
  * Return value: the new #GtkPrintBackendCups object
- **/
+ */
 GtkPrintBackend *
 gtk_print_backend_cups_new (void)
 {
+  GTK_NOTE (PRINTING,
+            g_print ("CUPS Backend: Creating a new CUPS print backend object\n"));
+
   return g_object_new (GTK_TYPE_PRINT_BACKEND_CUPS, NULL);
 }
 
@@ -241,41 +251,61 @@ gtk_print_backend_cups_class_init (GtkPrintBackendCupsClass *class)
   backend_class->printer_prepare_for_print = cups_printer_prepare_for_print;
   backend_class->printer_list_papers = cups_printer_list_papers;
   backend_class->printer_get_hard_margins = cups_printer_get_hard_margins;
+  backend_class->printer_get_capabilities = cups_printer_get_capabilities;
 }
 
 static cairo_status_t
-_cairo_write_to_cups (void *cache_fd_as_pointer,
+_cairo_write_to_cups (void                *closure,
                       const unsigned char *data,
                       unsigned int         length)
 {
-  cairo_status_t result;
-  gint cache_fd;
-  cache_fd = GPOINTER_TO_INT (cache_fd_as_pointer);
+  GIOChannel *io = (GIOChannel *)closure;
+  gsize written;
+  GError *error;
 
-  result = CAIRO_STATUS_WRITE_ERROR;
-  
-  /* write out the buffer */
-  if (write (cache_fd, data, length) != -1)
-      result = CAIRO_STATUS_SUCCESS;
-   
-  return result;
-}
+  error = NULL;
+
+  GTK_NOTE (PRINTING,
+            g_print ("CUPS Backend: Writting %i byte chunk to temp file\n", length));
+
+  while (length > 0) 
+    {
+      g_io_channel_write_chars (io, data, length, &written, &error);
+
+      if (error != NULL)
+       {
+         GTK_NOTE (PRINTING,
+                    g_print ("CUPS Backend: Error writting to temp file, %s\n", error->message));
+
+          g_error_free (error);
+         return CAIRO_STATUS_WRITE_ERROR;
+       }    
 
+      GTK_NOTE (PRINTING,
+                g_print ("CUPS Backend: Wrote %i bytes to temp file\n", written));
+
+      data += written;
+      length -= written;
+    }
+
+  return CAIRO_STATUS_SUCCESS;
+}
 
 static cairo_surface_t *
-cups_printer_create_cairo_surface (GtkPrinter *printer,
-                                  gdouble width, 
-                                  gdouble height,
-                                  gint cache_fd)
+cups_printer_create_cairo_surface (GtkPrinter       *printer,
+                                  GtkPrintSettings *settings,
+                                  gdouble           width, 
+                                  gdouble           height,
+                                  GIOChannel       *cache_io)
 {
   cairo_surface_t *surface; 
  
   /* TODO: check if it is a ps or pdf printer */
   
-  surface = cairo_ps_surface_create_for_stream  (_cairo_write_to_cups, GINT_TO_POINTER (cache_fd), width, height);
+  surface = cairo_ps_surface_create_for_stream  (_cairo_write_to_cups, cache_io, width, height);
 
   /* TODO: DPI from settings object? */
-  cairo_ps_surface_set_dpi (surface, 300, 300);
+  cairo_surface_set_fallback_resolution (surface, 300, 300);
 
   return surface;
 }
@@ -290,6 +320,9 @@ typedef struct {
 static void
 cups_free_print_stream_data (CupsPrintStreamData *data)
 {
+  GTK_NOTE (PRINTING,
+            g_print ("CUPS Backend: %s\n", G_STRFUNC));
+
   if (data->dnotify)
     data->dnotify (data->user_data);
   g_object_unref (data->job);
@@ -298,12 +331,15 @@ cups_free_print_stream_data (CupsPrintStreamData *data)
 
 static void
 cups_print_cb (GtkPrintBackendCups *print_backend,
-               GtkCupsResult *result,
-               gpointer user_data)
+               GtkCupsResult       *result,
+               gpointer             user_data)
 {
   GError *error = NULL;
   CupsPrintStreamData *ps = user_data;
 
+  GTK_NOTE (PRINTING,
+            g_print ("CUPS Backend: %s\n", G_STRFUNC)); 
+
   if (gtk_cups_result_is_error (result))
     error = g_error_new_literal (gtk_print_error_quark (),
                                  GTK_PRINT_ERROR_INTERNAL_ERROR,
@@ -318,18 +354,17 @@ cups_print_cb (GtkPrintBackendCups *print_backend,
       ipp_attribute_t *attr;           /* IPP job-id attribute */
       ipp_t *response = gtk_cups_result_get_response (result);
 
-      if ((attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) != NULL)
+      if ((attr = ippFindAttribute (response, "job-id", IPP_TAG_INTEGER)) != NULL)
        job_id = attr->values[0].integer;
 
-
-        if (job_id == 0)
-         gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_FINISHED);
-       else
-         {
-           gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_PENDING);
-           cups_begin_polling_info (print_backend, ps->job, job_id);
-         }
-    }
+      if (!gtk_print_job_get_track_print_status (ps->job) || job_id == 0)
+       gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_FINISHED);
+      else
+       {
+         gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_PENDING);
+         cups_begin_polling_info (print_backend, ps->job, job_id);
+       }
+    } 
   else
     gtk_print_job_set_status (ps->job, GTK_PRINT_STATUS_FINISHED_ABORTED);
 
@@ -340,9 +375,9 @@ cups_print_cb (GtkPrintBackendCups *print_backend,
 }
 
 static void
-add_cups_options (const char *key,
-                 const char *value,
-                 gpointer  user_data)
+add_cups_options (const gchar *key,
+                 const gchar *value,
+                 gpointer     user_data)
 {
   GtkCupsRequest *request = user_data;
 
@@ -352,35 +387,35 @@ add_cups_options (const char *key,
   if (strcmp (value, "gtk-ignore-value") == 0)
     return;
   
-  key = key + strlen("cups-");
+  key = key + strlen ("cups-");
 
   gtk_cups_request_encode_option (request, key, value);
 }
 
 static void
-gtk_print_backend_cups_print_stream (GtkPrintBackend *print_backend,
-                                     GtkPrintJob *job,
-                                    gint data_fd,
-                                    GtkPrintJobCompleteFunc callback,
-                                    gpointer user_data,
-                                    GDestroyNotify dnotify)
+gtk_print_backend_cups_print_stream (GtkPrintBackend         *print_backend,
+                                     GtkPrintJob             *job,
+                                    GIOChannel              *data_io,
+                                    GtkPrintJobCompleteFunc  callback,
+                                    gpointer                 user_data,
+                                    GDestroyNotify           dnotify)
 {
-  GError *error;
   GtkPrinterCups *cups_printer;
   CupsPrintStreamData *ps;
   GtkCupsRequest *request;
   GtkPrintSettings *settings;
   const gchar *title;
 
+  GTK_NOTE (PRINTING,
+            g_print ("CUPS Backend: %s\n", G_STRFUNC));   
+
   cups_printer = GTK_PRINTER_CUPS (gtk_print_job_get_printer (job));
   settings = gtk_print_job_get_settings (job);
 
-  error = NULL;
-
   request = gtk_cups_request_new (NULL,
                                   GTK_CUPS_POST,
                                   IPP_PRINT_JOB,
-                                 data_fd,
+                                 data_io,
                                  NULL,
                                  cups_printer->device_uri);
 
@@ -407,15 +442,15 @@ gtk_print_backend_cups_print_stream (GtkPrintBackend *print_backend,
                         request,
                         (GtkPrintCupsResponseCallbackFunc) cups_print_cb,
                         ps,
-                        (GDestroyNotify)cups_free_print_stream_data,
-                        &error);
+                        (GDestroyNotify)cups_free_print_stream_data);
 }
 
 
 static void
 gtk_print_backend_cups_init (GtkPrintBackendCups *backend_cups)
 {
-  backend_cups->list_printers_poll = 0;  
+  backend_cups->list_printers_poll = FALSE;  
+  backend_cups->got_default_printer = FALSE;  
   backend_cups->list_printers_pending = FALSE;
 
   cups_request_default_printer (backend_cups);
@@ -425,6 +460,9 @@ static void
 gtk_print_backend_cups_finalize (GObject *object)
 {
   GtkPrintBackendCups *backend_cups;
+  
+  GTK_NOTE (PRINTING,
+            g_print ("CUPS Backend: finalizing CUPS backend module\n"));
 
   backend_cups = GTK_PRINT_BACKEND_CUPS (object);
 
@@ -439,6 +477,9 @@ gtk_print_backend_cups_dispose (GObject *object)
 {
   GtkPrintBackendCups *backend_cups;
 
+  GTK_NOTE (PRINTING,
+            g_print ("CUPS Backend: %s\n", G_STRFUNC));
+
   backend_cups = GTK_PRINT_BACKEND_CUPS (object);
 
   if (backend_cups->list_printers_poll > 0)
@@ -456,6 +497,9 @@ cups_dispatch_watch_check (GSource *source)
   GtkCupsPollState poll_state;
   gboolean result;
 
+  GTK_NOTE (PRINTING,
+            g_print ("CUPS Backend: %s <source %p>\n", G_STRFUNC, source)); 
+
   dispatch = (GtkPrintCupsDispatchWatch *) source;
 
   poll_state = gtk_cups_request_get_poll_state (dispatch->request);
@@ -499,21 +543,24 @@ cups_dispatch_watch_check (GSource *source)
 
 static gboolean
 cups_dispatch_watch_prepare (GSource *source,
-                            gint *timeout_)
+                            gint    *timeout_)
 {
   GtkPrintCupsDispatchWatch *dispatch;
 
   dispatch = (GtkPrintCupsDispatchWatch *) source;
+
+  GTK_NOTE (PRINTING,
+            g_print ("CUPS Backend: %s <source %p>\n", G_STRFUNC, source));
+
   *timeout_ = -1;
   
   return gtk_cups_request_read_write (dispatch->request);
 }
 
 static gboolean
-cups_dispatch_watch_dispatch (GSource *source,
-                             GSourceFunc callback,
-                             gpointer user_data)
+cups_dispatch_watch_dispatch (GSource     *source,
+                             GSourceFunc  callback,
+                             gpointer     user_data)
 {
   GtkPrintCupsDispatchWatch *dispatch;
   GtkPrintCupsResponseCallbackFunc ep_callback;  
@@ -527,8 +574,11 @@ cups_dispatch_watch_dispatch (GSource *source,
 
   result = gtk_cups_request_get_result (dispatch->request);
 
+  GTK_NOTE (PRINTING,
+            g_print ("CUPS Backend: %s <source %p>\n", G_STRFUNC, source));
+
   if (gtk_cups_result_is_error (result))
-    g_warning (gtk_cups_result_get_error_string (result));
+    g_warning ("Error result: %s", gtk_cups_result_get_error_string (result));
 
   ep_callback (GTK_PRINT_BACKEND (dispatch->backend), result, user_data);
 
@@ -540,6 +590,9 @@ cups_dispatch_watch_finalize (GSource *source)
 {
   GtkPrintCupsDispatchWatch *dispatch;
 
+  GTK_NOTE (PRINTING,
+            g_print ("CUPS Backend: %s <source %p>\n", G_STRFUNC, source));
+
   dispatch = (GtkPrintCupsDispatchWatch *) source;
 
   gtk_cups_request_free (dispatch->request);
@@ -547,10 +600,15 @@ cups_dispatch_watch_finalize (GSource *source)
   if (dispatch->backend)
     {
       /* We need to unref this at idle time, because it might be the
-        last reference to this module causing the code to be
-        unloaded (including this particular function!)
-      */
-      gtk_print_backend_unref_at_idle (GTK_PRINT_BACKEND (dispatch->backend));
+       * last reference to this module causing the code to be
+       * unloaded (including this particular function!)
+       * Update: Doing this at idle caused a deadlock taking the
+       * mainloop context lock while being in a GSource callout for
+       * multithreaded apps. So, for now we just disable unloading
+       * of print backends. See _gtk_print_backend_create for the
+       * disabling.
+       */
+      g_object_unref (dispatch->backend);
       dispatch->backend = NULL;
     }
 
@@ -567,18 +625,20 @@ static GSourceFuncs _cups_dispatch_watch_funcs = {
 
 
 static void
-cups_request_execute (GtkPrintBackendCups *print_backend,
-                      GtkCupsRequest *request,
-                      GtkPrintCupsResponseCallbackFunc callback,
-                      gpointer user_data,
-                      GDestroyNotify notify,
-                      GError **err)
+cups_request_execute (GtkPrintBackendCups              *print_backend,
+                      GtkCupsRequest                   *request,
+                      GtkPrintCupsResponseCallbackFunc  callback,
+                      gpointer                          user_data,
+                      GDestroyNotify                    notify)
 {
   GtkPrintCupsDispatchWatch *dispatch;
 
   dispatch = (GtkPrintCupsDispatchWatch *) g_source_new (&_cups_dispatch_watch_funcs, 
                                                          sizeof (GtkPrintCupsDispatchWatch));
 
+  GTK_NOTE (PRINTING,
+            g_print ("CUPS Backend: %s <source %p> - Executing cups request on server '%s' and resource '%s'\n", G_STRFUNC, dispatch, request->server, request->resource));
+
   dispatch->request = request;
   dispatch->backend = g_object_ref (print_backend);
   dispatch->data_poll = NULL;
@@ -591,8 +651,8 @@ cups_request_execute (GtkPrintBackendCups *print_backend,
 
 static void
 cups_request_printer_info_cb (GtkPrintBackendCups *backend,
-                              GtkCupsResult *result,
-                              gpointer user_data)
+                              GtkCupsResult       *result,
+                              gpointer             user_data)
 {
   ipp_attribute_t *attr;
   ipp_t *response;
@@ -611,8 +671,15 @@ cups_request_printer_info_cb (GtkPrintBackendCups *backend,
   printer = gtk_print_backend_find_printer (GTK_PRINT_BACKEND (backend),
                                            printer_name);
 
+  GTK_NOTE (PRINTING,
+            g_print ("CUPS Backend: %s - Got printer info for printer '%s'\n", G_STRFUNC, printer_name));
+
   if (!printer)
-    return;
+    {
+      GTK_NOTE (PRINTING,
+            g_print ("CUPS Backend: Could not find printer called '%s'\n", printer_name));
+      return;
+    }
 
   cups_printer = GTK_PRINTER_CUPS (printer);
   
@@ -631,7 +698,7 @@ cups_request_printer_info_cb (GtkPrintBackendCups *backend,
   response = gtk_cups_result_get_response (result);
 
   /* TODO: determine printer type and use correct icon */
-  gtk_printer_set_icon_name (printer, "printer");
+  gtk_printer_set_icon_name (printer, "gtk-print");
  
   state_msg = "";
   loc = "";
@@ -662,9 +729,8 @@ cups_request_printer_info_cb (GtkPrintBackendCups *backend,
 
 static void
 cups_request_printer_info (GtkPrintBackendCups *print_backend,
-                           const gchar *printer_name)
+                           const gchar         *printer_name)
 {
-  GError *error;
   GtkCupsRequest *request;
   gchar *printer_uri;
   static const char * const pattrs[] = /* Attributes we're interested in */
@@ -676,12 +742,10 @@ cups_request_printer_info (GtkPrintBackendCups *print_backend,
       "queued-job-count"
     };
 
-  error = NULL;
-
   request = gtk_cups_request_new (NULL,
                                   GTK_CUPS_POST,
                                   IPP_GET_PRINTER_ATTRIBUTES,
-                                 0,
+                                 NULL,
                                  NULL,
                                  NULL);
 
@@ -690,6 +754,9 @@ cups_request_printer_info (GtkPrintBackendCups *print_backend,
   gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI,
                                    "printer-uri", NULL, printer_uri);
 
+  GTK_NOTE (PRINTING,
+            g_print ("CUPS Backend: %s - Requesting printer info for URI '%s'\n", G_STRFUNC, printer_uri));
+
   g_free (printer_uri);
 
   gtk_cups_request_ipp_add_strings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
@@ -700,9 +767,7 @@ cups_request_printer_info (GtkPrintBackendCups *print_backend,
                         request,
                         (GtkPrintCupsResponseCallbackFunc) cups_request_printer_info_cb,
                         g_strdup (printer_name),
-                        (GDestroyNotify) g_free,
-                        &error);
+                        (GDestroyNotify) g_free);
 }
 
 
@@ -714,7 +779,7 @@ typedef struct {
 } CupsJobPollData;
 
 static void
-job_object_died        (gpointer user_data,
+job_object_died        (gpointer  user_data,
                 GObject  *where_the_object_was)
 {
   CupsJobPollData *data = user_data;
@@ -732,8 +797,8 @@ cups_job_poll_data_free (CupsJobPollData *data)
 
 static void
 cups_request_job_info_cb (GtkPrintBackendCups *print_backend,
-                         GtkCupsResult *result,
-                         gpointer user_data)
+                         GtkCupsResult       *result,
+                         gpointer             user_data)
 {
   CupsJobPollData *data = user_data;
   ipp_attribute_t *attr;
@@ -808,16 +873,13 @@ cups_request_job_info_cb (GtkPrintBackendCups *print_backend,
 static void
 cups_request_job_info (CupsJobPollData *data)
 {
-  GError *error;
   GtkCupsRequest *request;
   gchar *printer_uri;
 
-  
-  error = NULL;
   request = gtk_cups_request_new (NULL,
                                   GTK_CUPS_POST,
                                   IPP_GET_JOB_ATTRIBUTES,
-                                 0,
+                                 NULL,
                                  NULL,
                                  NULL);
 
@@ -830,8 +892,7 @@ cups_request_job_info (CupsJobPollData *data)
                         request,
                         (GtkPrintCupsResponseCallbackFunc) cups_request_job_info_cb,
                         data,
-                        NULL,
-                        &error);
+                        NULL);
 }
 
 static gboolean
@@ -849,8 +910,8 @@ cups_job_info_poll_timeout (gpointer user_data)
 
 static void
 cups_begin_polling_info (GtkPrintBackendCups *print_backend,
-                        GtkPrintJob *job,
-                        int job_id)
+                        GtkPrintJob         *job,
+                        gint                 job_id)
 {
   CupsJobPollData *data;
 
@@ -867,18 +928,18 @@ cups_begin_polling_info (GtkPrintBackendCups *print_backend,
 }
 
 static void
-mark_printer_inactive (GtkPrinter *printer, 
+mark_printer_inactive (GtkPrinter      *printer, 
                        GtkPrintBackend *backend)
 {
   gtk_printer_set_is_active (printer, FALSE);
-  g_signal_emit_by_name (backend,
-                        "printer-removed", printer);
+  g_signal_emit_by_name (backend, "printer-removed", printer);
 }
 
 static gint
-find_printer (GtkPrinter *printer, const char *find_name)
+find_printer (GtkPrinter  *printer, 
+             const gchar *find_name)
 {
-  const char *printer_name;
+  const gchar *printer_name;
 
   printer_name = gtk_printer_get_name (printer);
   return g_ascii_strcasecmp (printer_name, find_name);
@@ -886,9 +947,10 @@ find_printer (GtkPrinter *printer, const char *find_name)
 
 static void
 cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
-                              GtkCupsResult *result,
-                              gpointer user_data)
+                              GtkCupsResult       *result,
+                              gpointer             user_data)
 {
+  GtkPrintBackend *backend = GTK_PRINT_BACKEND (cups_backend);
   ipp_attribute_t *attr;
   ipp_t *response;
   gboolean list_has_changed;
@@ -896,34 +958,35 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
 
   list_has_changed = FALSE;
 
-  g_assert (GTK_IS_PRINT_BACKEND_CUPS (cups_backend));
+  GTK_NOTE (PRINTING,
+            g_print ("CUPS Backend: %s\n", G_STRFUNC));
 
   cups_backend->list_printers_pending = FALSE;
 
   if (gtk_cups_result_is_error (result))
     {
       g_warning ("Error getting printer list: %s", gtk_cups_result_get_error_string (result));
-      return;
+
+      goto done;
     }
   
-  /* gether the names of the printers in the current queue
-     so we may check to see if they were removed */
-  removed_printer_checklist = gtk_print_backend_get_printer_list (GTK_PRINT_BACKEND (cups_backend));
+  /* Gather the names of the printers in the current queue
+   * so we may check to see if they were removed 
+   */
+  removed_printer_checklist = gtk_print_backend_get_printer_list (backend);
                                                                  
   response = gtk_cups_result_get_response (result);
 
-
   for (attr = response->attrs; attr != NULL; attr = attr->next)
     {
       GtkPrinter *printer;
       const gchar *printer_name;
-      const char *printer_uri;
-      const char *member_uris;
+      const gchar *printer_uri;
+      const gchar *member_uris;
       GList *node;
       
-      /*
-      * Skip leading attributes until we hit a printer...
-      */
+      /* Skip leading attributes until we hit a printer...
+       */
       while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
         attr = attr->next;
 
@@ -935,15 +998,20 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
       member_uris = NULL;
       while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
       {
-        if (!strcmp(attr->name, "printer-name") &&
+        if (!strcmp (attr->name, "printer-name") &&
            attr->value_tag == IPP_TAG_NAME)
          printer_name = attr->values[0].string.text;
-       else if (!strcmp(attr->name, "printer-uri-supported") &&
+       else if (!strcmp (attr->name, "printer-uri-supported") &&
                 attr->value_tag == IPP_TAG_URI)
          printer_uri = attr->values[0].string.text;
-       else if (!strcmp(attr->name, "member-uris") &&
+       else if (!strcmp (attr->name, "member-uris") &&
                 attr->value_tag == IPP_TAG_URI)
          member_uris = attr->values[0].string.text;
+        else
+         {
+           GTK_NOTE (PRINTING,
+                      g_print ("CUPS Backend: Attribute %s ignored", attr->name));
+         }
 
         attr = attr->next;
       }
@@ -961,29 +1029,36 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
       node = g_list_find_custom (removed_printer_checklist, printer_name, (GCompareFunc) find_printer);
       removed_printer_checklist = g_list_delete_link (removed_printer_checklist, node);
  
-      printer = gtk_print_backend_find_printer (GTK_PRINT_BACKEND (cups_backend), printer_name);
+      printer = gtk_print_backend_find_printer (backend, printer_name);
       if (!printer)
         {
          GtkPrinterCups *cups_printer;
-         char uri[HTTP_MAX_URI],       /* Printer URI */
-           method[HTTP_MAX_URI],       /* Method/scheme name */
-           username[HTTP_MAX_URI],     /* Username:password */
-           hostname[HTTP_MAX_URI],     /* Hostname */
-           resource[HTTP_MAX_URI];     /* Resource name */
+         char uri[HTTP_MAX_URI];       /* Printer URI */
+         char method[HTTP_MAX_URI];    /* Method/scheme name */
+         char username[HTTP_MAX_URI];  /* Username:password */
+         char hostname[HTTP_MAX_URI];  /* Hostname */
+         char resource[HTTP_MAX_URI];  /* Resource name */
          int  port;                    /* Port number */
          
           list_has_changed = TRUE;
-         cups_printer = gtk_printer_cups_new (printer_name,
-                                              GTK_PRINT_BACKEND (cups_backend));
+         cups_printer = gtk_printer_cups_new (printer_name, backend);
 
          cups_printer->device_uri = g_strdup_printf ("/printers/%s", printer_name);
 
+          /* Check to see if we are looking at a class */
          if (member_uris)
            {
              cups_printer->printer_uri = g_strdup (member_uris);
+             /* TODO if member_uris is a class we need to recursivly find a printer */
+             GTK_NOTE (PRINTING,
+                        g_print ("CUPS Backend: Found class with printer %s\n", member_uris));
            }
          else
-           cups_printer->printer_uri = g_strdup (printer_uri);
+           {
+             cups_printer->printer_uri = g_strdup (printer_uri);
+              GTK_NOTE (PRINTING,
+                        g_print ("CUPS Backend: Found printer %s\n", printer_uri));
+            }
 
 #if (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR >= 2) || CUPS_VERSION_MAJOR > 1
          httpSeparateURI (HTTP_URI_CODING_ALL, cups_printer->printer_uri, 
@@ -1002,9 +1077,16 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
                        resource);
 #endif
 
-         gethostname(uri, sizeof(uri));
-         if (strcasecmp(uri, hostname) == 0)
-           strcpy(hostname, "localhost");
+          if (!strncmp (resource, "/printers/", 10))
+           {
+             cups_printer->ppd_name = g_strdup (resource + 10);
+              GTK_NOTE (PRINTING,
+                        g_print ("CUPS Backend: Setting ppd name '%s' for printer/class '%s'\n", cups_printer->ppd_name, printer_name));
+            }
+
+         gethostname (uri, sizeof(uri));
+         if (strcasecmp (uri, hostname) == 0)
+           strcpy (hostname, "localhost");
 
          cups_printer->hostname = g_strdup (hostname);
          cups_printer->port = port;
@@ -1016,7 +1098,7 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
            gtk_printer_set_is_default (printer, TRUE);
 
          
-         gtk_print_backend_add_printer (GTK_PRINT_BACKEND (cups_backend), printer);
+         gtk_print_backend_add_printer (backend, printer);
         }
       else
        g_object_ref (printer);
@@ -1030,9 +1112,7 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
 
       if (gtk_printer_is_new (printer))
         {
-           g_signal_emit_by_name (GTK_PRINT_BACKEND (cups_backend), 
-                                  "printer-added",
-                                  printer);
+         g_signal_emit_by_name (backend, "printer-added", printer);
 
          gtk_printer_set_is_new (printer, FALSE);
         }
@@ -1051,22 +1131,21 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
      as inactive if it is in the list, emitting a printer_removed signal */
   if (removed_printer_checklist != NULL)
     {
-      g_list_foreach (removed_printer_checklist, (GFunc) mark_printer_inactive,
-                     GTK_PRINT_BACKEND (cups_backend));
+      g_list_foreach (removed_printer_checklist, (GFunc) mark_printer_inactive, backend);
       g_list_free (removed_printer_checklist);
       list_has_changed = TRUE;
     }
   
+done:
   if (list_has_changed)
-    g_signal_emit_by_name (GTK_PRINT_BACKEND (cups_backend), "printer-list-changed");
+    g_signal_emit_by_name (backend, "printer-list-changed");
   
-  gtk_print_backend_set_list_done (GTK_PRINT_BACKEND (cups_backend));
+  gtk_print_backend_set_list_done (backend);
 }
 
 static gboolean
 cups_request_printer_list (GtkPrintBackendCups *cups_backend)
 {
-  GError *error;
   GtkCupsRequest *request;
   static const char * const pattrs[] = /* Attributes we're interested in */
     {
@@ -1079,14 +1158,15 @@ cups_request_printer_list (GtkPrintBackendCups *cups_backend)
       !cups_backend->got_default_printer)
     return TRUE;
 
-  cups_backend->list_printers_pending = TRUE;
+  g_object_ref (cups_backend);
+  GDK_THREADS_LEAVE ();
 
-  error = NULL;
+  cups_backend->list_printers_pending = TRUE;
 
   request = gtk_cups_request_new (NULL,
                                   GTK_CUPS_POST,
                                   CUPS_GET_PRINTERS,
-                                 0,
+                                 NULL,
                                  NULL,
                                  NULL);
 
@@ -1098,9 +1178,9 @@ cups_request_printer_list (GtkPrintBackendCups *cups_backend)
                         request,
                         (GtkPrintCupsResponseCallbackFunc) cups_request_printer_list_cb,
                        request,
-                       NULL,
-                        &error);
-
+                       NULL);
+  GDK_THREADS_ENTER ();
+  g_object_unref (cups_backend);
 
   return TRUE;
 }
@@ -1114,7 +1194,7 @@ cups_get_printer_list (GtkPrintBackend *backend)
   if (cups_backend->list_printers_poll == 0)
     {
       cups_request_printer_list (cups_backend);
-      cups_backend->list_printers_poll = g_timeout_add (3000 * 100000,
+      cups_backend->list_printers_poll = gdk_threads_add_timeout (3000,
                                                         (GSourceFunc) cups_request_printer_list,
                                                         backend);
     }
@@ -1122,124 +1202,153 @@ cups_get_printer_list (GtkPrintBackend *backend)
 
 typedef struct {
   GtkPrinterCups *printer;
-  gint ppd_fd;
-  gchar *ppd_filename;
+  GIOChannel *ppd_io;
 } GetPPDData;
 
 static void
 get_ppd_data_free (GetPPDData *data)
 {
-  close (data->ppd_fd);
-  unlink (data->ppd_filename);
-  g_free (data->ppd_filename);
+  GTK_NOTE (PRINTING,
+            g_print ("CUPS Backend: %s\n", G_STRFUNC));
+
+  g_io_channel_unref (data->ppd_io);
   g_object_unref (data->printer);
   g_free (data);
 }
 
 static void
 cups_request_ppd_cb (GtkPrintBackendCups *print_backend,
-                     GtkCupsResult *result,
-                     GetPPDData *data)
+                     GtkCupsResult       *result,
+                     GetPPDData          *data)
 {
   ipp_t *response;
   GtkPrinter *printer;
 
+  GTK_NOTE (PRINTING,
+            g_print ("CUPS Backend: %s\n", G_STRFUNC));
+
   printer = GTK_PRINTER (data->printer);
   GTK_PRINTER_CUPS (printer)->reading_ppd = FALSE;
 
   if (gtk_cups_result_is_error (result))
     {
-      g_signal_emit_by_name (printer, "details-acquired", printer, FALSE);
+      g_signal_emit_by_name (printer, "details-acquired", FALSE);
       return;
     }
 
   response = gtk_cups_result_get_response (result);
 
-  data->printer->ppd_file = ppdOpenFile (data->ppd_filename);
+  /* let ppdOpenFd take over the ownership of the open file */
+  g_io_channel_seek_position (data->ppd_io, 0, G_SEEK_SET, NULL);
+  data->printer->ppd_file = ppdOpenFd (dup (g_io_channel_unix_get_fd (data->ppd_io)));
+  
   gtk_printer_set_has_details (printer, TRUE);
-  g_signal_emit_by_name (printer, "details-acquired", printer, TRUE);
+  g_signal_emit_by_name (printer, "details-acquired", TRUE);
 }
 
 static void
-cups_request_ppd (GtkPrinter      *printer)
+cups_request_ppd (GtkPrinter *printer)
 {
   GError *error;
   GtkPrintBackend *print_backend;
   GtkPrinterCups *cups_printer;
   GtkCupsRequest *request;
+  char *ppd_filename;
   gchar *resource;
   http_t *http;
   GetPPDData *data;
-  
+  int fd;
+
   cups_printer = GTK_PRINTER_CUPS (printer);
 
   error = NULL;
 
-  http = httpConnectEncrypt(cups_printer->hostname, 
-                            cups_printer->port,
-                            cupsEncryption());
+  GTK_NOTE (PRINTING,
+            g_print ("CUPS Backend: %s\n", G_STRFUNC));
+
+  /* FIXME this can return NULL! */
+  http = httpConnectEncrypt (cups_printer->hostname, 
+                            cups_printer->port,
+                            cupsEncryption ());
 
   data = g_new0 (GetPPDData, 1);
 
-  data->ppd_fd = g_file_open_tmp ("gtkprint_ppd_XXXXXX", 
-                                  &data->ppd_filename, 
-                                  &error);
+  fd = g_file_open_tmp ("gtkprint_ppd_XXXXXX", 
+                        &ppd_filename, 
+                        &error);
+
+#ifdef G_ENABLE_DEBUG 
+  /* If we are debugging printing don't delete the tmp files */
+  if (!(gtk_debug_flags & GTK_DEBUG_PRINTING))
+    unlink (ppd_filename);
+#else
+  unlink (ppd_filename);
+#endif /* G_ENABLE_DEBUG */
 
   if (error != NULL)
     {
       g_warning ("%s", error->message);
       g_error_free (error);
       httpClose (http);
+      g_free (ppd_filename);
       g_free (data);
 
-      g_signal_emit_by_name (printer, "details-acquired", printer, FALSE);
+      g_signal_emit_by_name (printer, "details-acquired", FALSE);
       return;
     }
     
-  fchmod (data->ppd_fd, S_IRUSR | S_IWUSR);
+  fchmod (fd, S_IRUSR | S_IWUSR);
+  data->ppd_io = g_io_channel_unix_new (fd);
+  g_io_channel_set_encoding (data->ppd_io, NULL, NULL);
+  g_io_channel_set_close_on_unref (data->ppd_io, TRUE);
 
   data->printer = g_object_ref (printer);
 
-  resource = g_strdup_printf ("/printers/%s.ppd", gtk_printer_get_name (printer));
+  resource = g_strdup_printf ("/printers/%s.ppd", 
+                              gtk_printer_cups_get_ppd_name (GTK_PRINTER_CUPS(printer)));
   request = gtk_cups_request_new (http,
                                   GTK_CUPS_GET,
                                  0,
-                                  data->ppd_fd,
+                                  data->ppd_io,
                                  cups_printer->hostname,
                                  resource);
 
+  GTK_NOTE (PRINTING,
+            g_print ("CUPS Backend: Requesting resource %s to be written to temp file %s\n", resource, ppd_filename));
+
   g_free (resource);
+  g_free (ppd_filename);
+
   cups_printer->reading_ppd = TRUE;
 
   print_backend = gtk_printer_get_backend (printer);
+
   cups_request_execute (GTK_PRINT_BACKEND_CUPS (print_backend),
                         request,
                         (GtkPrintCupsResponseCallbackFunc) cups_request_ppd_cb,
                         data,
-                        (GDestroyNotify)get_ppd_data_free,
-                        &error);
+                        (GDestroyNotify)get_ppd_data_free);
 }
 
 
 static void
 cups_request_default_printer_cb (GtkPrintBackendCups *print_backend,
-                                GtkCupsResult *result,
-                                gpointer user_data)
+                                GtkCupsResult       *result,
+                                gpointer             user_data)
 {
   ipp_t *response;
   ipp_attribute_t *attr;
 
   response = gtk_cups_result_get_response (result);
   
-  if ((attr = ippFindAttribute(response, "printer-name", IPP_TAG_NAME)) != NULL)
+  if ((attr = ippFindAttribute (response, "printer-name", IPP_TAG_NAME)) != NULL)
     print_backend->default_printer = g_strdup (attr->values[0].string.text);
 
   print_backend->got_default_printer = TRUE;
 
-  /* Make sure to kick off get_printers if we are polling it, as we could
-     have blocked this reading the default printer */
+  /* Make sure to kick off get_printers if we are polling it, 
+   * as we could have blocked this reading the default printer 
+   */
   if (print_backend->list_printers_poll != 0)
     cups_request_printer_list (print_backend);
 }
@@ -1247,20 +1356,17 @@ cups_request_default_printer_cb (GtkPrintBackendCups *print_backend,
 static void
 cups_request_default_printer (GtkPrintBackendCups *print_backend)
 {
-  GError *error;
   GtkCupsRequest *request;
   const char *str;
 
-  error = NULL;
-
-  if ((str = getenv("LPDEST")) != NULL)
+  if ((str = g_getenv ("LPDEST")) != NULL)
     {
       print_backend->default_printer = g_strdup (str);
       print_backend->got_default_printer = TRUE;
       return;
     }
-  else if ((str = getenv("PRINTER")) != NULL &&
-          strcmp(str, "lp") != 0)
+  else if ((str = g_getenv ("PRINTER")) != NULL &&
+          strcmp (str, "lp") != 0)
     {
       print_backend->default_printer = g_strdup (str);
       print_backend->got_default_printer = TRUE;
@@ -1270,7 +1376,7 @@ cups_request_default_printer (GtkPrintBackendCups *print_backend)
   request = gtk_cups_request_new (NULL,
                                   GTK_CUPS_POST,
                                   CUPS_GET_DEFAULT,
-                                 0,
+                                 NULL,
                                  NULL,
                                  NULL);
   
@@ -1278,11 +1384,9 @@ cups_request_default_printer (GtkPrintBackendCups *print_backend)
                         request,
                         (GtkPrintCupsResponseCallbackFunc) cups_request_default_printer_cb,
                        g_object_ref (print_backend),
-                       g_object_unref,
-                        &error);
+                       g_object_unref);
 }
 
-
 static void
 cups_printer_request_details (GtkPrinter *printer)
 {
@@ -1295,7 +1399,8 @@ cups_printer_request_details (GtkPrinter *printer)
 }
 
 static char *
-ppd_text_to_utf8 (ppd_file_t *ppd_file, const char *text)
+ppd_text_to_utf8 (ppd_file_t *ppd_file, 
+                 const char *text)
 {
   const char *encoding = NULL;
   char *res;
@@ -1489,7 +1594,8 @@ static const char *cups_option_blacklist[] = {
 };
 
 static char *
-get_option_text (ppd_file_t *ppd_file, ppd_option_t *option)
+get_option_text (ppd_file_t   *ppd_file, 
+                ppd_option_t *option)
 {
   int i;
   char *utf8;
@@ -1509,7 +1615,8 @@ get_option_text (ppd_file_t *ppd_file, ppd_option_t *option)
 }
 
 static char *
-get_choice_text (ppd_file_t *ppd_file, ppd_choice_t *choice)
+get_choice_text (ppd_file_t   *ppd_file, 
+                ppd_choice_t *choice)
 {
   int i;
   ppd_option_t *option = choice->option;
@@ -1525,7 +1632,8 @@ get_choice_text (ppd_file_t *ppd_file, ppd_choice_t *choice)
 }
 
 static gboolean
-group_has_option (ppd_group_t *group, ppd_option_t *option)
+group_has_option (ppd_group_t  *group, 
+                 ppd_option_t *option)
 {
   int i;
 
@@ -1562,15 +1670,25 @@ value_is_off (const char *value)
           strcasecmp (value, "False") == 0);
 }
 
+static char *
+ppd_group_name (ppd_group_t *group)
+{
+#if CUPS_VERSION_MAJOR > 1 || (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR > 1) || (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR == 1 && CUPS_VERSION_PATCH >= 18) 
+  return group->name;
+#else
+  return group->text;
+#endif
+}
+
 static int
-available_choices (ppd_file_t *ppd,
-                  ppd_option_t *option,
+available_choices (ppd_file_t     *ppd,
+                  ppd_option_t   *option,
                   ppd_choice_t ***available,
-                  gboolean keep_if_only_one_option)
+                  gboolean        keep_if_only_one_option)
 {
   ppd_option_t *other_option;
   int i, j;
-  char *conflicts;
+  gchar *conflicts;
   ppd_const_t *constraint;
   const char *choice, *other_choice;
   ppd_option_t *option1, *option2;
@@ -1587,7 +1705,10 @@ available_choices (ppd_file_t *ppd,
   installed_options = NULL;
   for (i = 0; i < ppd->num_groups; i++)
     {
-      if (strcmp (ppd->groups[i].name, "InstallableOptions") == 0)
+      char *name; 
+
+      name = ppd_group_name (&ppd->groups[i]);
+      if (strcmp (name, "InstallableOptions") == 0)
        {
          installed_options = &ppd->groups[i];
          break;
@@ -1672,13 +1793,13 @@ available_choices (ppd_file_t *ppd,
 
 
   /* Some ppds don't have a "use printer default" option for
-     InputSlot. This means you always have to select a particular slot,
-     and you can't auto-pick source based on the paper size. To support
-     this we always add an auto option if there isn't one already. If
-     the user chooses the generated option we don't send any InputSlot
-     value when printing. The way we detect existing auto-cases is based
-     on feedback from Michael Sweet of cups fame.
-  */
+   * InputSlot. This means you always have to select a particular slot,
+   * and you can't auto-pick source based on the paper size. To support
+   * this we always add an auto option if there isn't one already. If
+   * the user chooses the generated option we don't send any InputSlot
+   * value when printing. The way we detect existing auto-cases is based
+   * on feedback from Michael Sweet of cups fame.
+   */
   add_auto = 0;
   if (strcmp (option->keyword, "InputSlot") == 0)
     {
@@ -1726,15 +1847,18 @@ available_choices (ppd_file_t *ppd,
 }
 
 static GtkPrinterOption *
-create_pickone_option (ppd_file_t *ppd_file,
+create_pickone_option (ppd_file_t   *ppd_file,
                       ppd_option_t *ppd_option,
-                      const char *gtk_name)
+                      const gchar  *gtk_name)
 {
   GtkPrinterOption *option;
   ppd_choice_t **available;
   char *label;
   int n_choices;
   int i;
+#ifdef HAVE_CUPS_API_1_2
+  ppd_coption_t *coption;
+#endif
 
   g_assert (ppd_option->ui == PPD_UI_PICKONE);
   
@@ -1743,9 +1867,65 @@ create_pickone_option (ppd_file_t *ppd_file,
   n_choices = available_choices (ppd_file, ppd_option, &available, g_str_has_prefix (gtk_name, "gtk-"));
   if (n_choices > 0)
     {
+      
+      /* right now only support one parameter per custom option 
+       * if more than one print warning and only offer the default choices
+       */
+
       label = get_option_text (ppd_file, ppd_option);
-      option = gtk_printer_option_new (gtk_name, label,
-                                      GTK_PRINTER_OPTION_TYPE_PICKONE);
+
+#ifdef HAVE_CUPS_API_1_2
+      coption = ppdFindCustomOption (ppd_file, ppd_option->keyword);
+
+      if (coption)
+        {
+         ppd_cparam_t *cparam;
+
+          cparam = ppdFirstCustomParam (coption);
+
+          if (ppdNextCustomParam (coption) == NULL)
+           {
+              switch (cparam->type)
+               {
+                case PPD_CUSTOM_INT:
+                 option = gtk_printer_option_new (gtk_name, label,
+                                        GTK_PRINTER_OPTION_TYPE_PICKONE_INT);
+                 break;
+                case PPD_CUSTOM_PASSCODE:
+                 option = gtk_printer_option_new (gtk_name, label,
+                                        GTK_PRINTER_OPTION_TYPE_PICKONE_PASSCODE);
+                 break;
+                case PPD_CUSTOM_PASSWORD:
+                   option = gtk_printer_option_new (gtk_name, label,
+                                        GTK_PRINTER_OPTION_TYPE_PICKONE_PASSWORD);
+                 break;
+               case PPD_CUSTOM_REAL:
+                   option = gtk_printer_option_new (gtk_name, label,
+                                        GTK_PRINTER_OPTION_TYPE_PICKONE_REAL);
+                 break;
+                case PPD_CUSTOM_STRING:
+                 option = gtk_printer_option_new (gtk_name, label,
+                                        GTK_PRINTER_OPTION_TYPE_PICKONE_STRING);
+                 break;
+                case PPD_CUSTOM_POINTS: 
+                 g_warning ("Not Supported: PPD Custom Points Option");
+                 break;
+                case PPD_CUSTOM_CURVE:
+                  g_warning ("Not Supported: PPD Custom Curve Option");
+                 break;
+                case PPD_CUSTOM_INVCURVE:      
+                 g_warning ("Not Supported: PPD Custom Inverse Curve Option");
+                 break;
+               }
+           }
+         else
+           g_warning ("Not Supported: PPD Custom Option has more than one parameter");
+       }
+#endif /* HAVE_CUPS_API_1_2 */
+
+      if (!option)
+        option = gtk_printer_option_new (gtk_name, label,
+                                        GTK_PRINTER_OPTION_TYPE_PICKONE);
       g_free (label);
       
       gtk_printer_option_allocate_choices (option, n_choices);
@@ -1775,9 +1955,9 @@ create_pickone_option (ppd_file_t *ppd_file,
 }
 
 static GtkPrinterOption *
-create_boolean_option (ppd_file_t *ppd_file,
+create_boolean_option (ppd_file_t   *ppd_file,
                       ppd_option_t *ppd_option,
-                      const char *gtk_name)
+                      const gchar  *gtk_name)
 {
   GtkPrinterOption *option;
   ppd_choice_t **available;
@@ -1793,14 +1973,14 @@ create_boolean_option (ppd_file_t *ppd_file,
     {
       label = get_option_text (ppd_file, ppd_option);
       option = gtk_printer_option_new (gtk_name, label,
-                                              GTK_PRINTER_OPTION_TYPE_BOOLEAN);
+                                      GTK_PRINTER_OPTION_TYPE_BOOLEAN);
       g_free (label);
       
       gtk_printer_option_allocate_choices (option, 2);
       option->choices[0] = g_strdup ("True");
       option->choices_display[0] = g_strdup ("True");
-      option->choices[1] = g_strdup ("True");
-      option->choices_display[1] = g_strdup ("True");
+      option->choices[1] = g_strdup ("False");
+      option->choices_display[1] = g_strdup ("False");
       
       gtk_printer_option_set (option, ppd_option->defchoice);
     }
@@ -1813,8 +1993,8 @@ create_boolean_option (ppd_file_t *ppd_file,
   return option;
 }
 
-static char *
-get_option_name (const char *keyword)
+static gchar *
+get_option_name (const gchar *keyword)
 {
   int i;
 
@@ -1826,7 +2006,8 @@ get_option_name (const char *keyword)
 }
 
 static int
-strptr_cmp (const void *a, const void *b)
+strptr_cmp (const void *a, 
+           const void *b)
 {
   char **aa = (char **)a;
   char **bb = (char **)b;
@@ -1835,7 +2016,9 @@ strptr_cmp (const void *a, const void *b)
 
 
 static gboolean
-string_in_table (char *str, const char *table[], int table_len)
+string_in_table (gchar       *str, 
+                const gchar *table[], 
+                gint         table_len)
 {
   return bsearch (&str, table, table_len, sizeof (char *), (void *)strptr_cmp) != NULL;
 }
@@ -1844,17 +2027,17 @@ string_in_table (char *str, const char *table[], int table_len)
 
 static void
 handle_option (GtkPrinterOptionSet *set,
-              ppd_file_t *ppd_file,
-              ppd_option_t *ppd_option,
-              ppd_group_t *toplevel_group,
-              GtkPrintSettings *settings)
+              ppd_file_t          *ppd_file,
+              ppd_option_t        *ppd_option,
+              ppd_group_t         *toplevel_group,
+              GtkPrintSettings    *settings)
 {
   GtkPrinterOption *option;
   char *name;
 
   if (STRING_IN_TABLE (ppd_option->keyword, cups_option_blacklist))
     return;
-  
+
   name = get_option_name (ppd_option->keyword);
 
   option = NULL;
@@ -1872,21 +2055,24 @@ handle_option (GtkPrinterOptionSet *set,
   
   if (option)
     {
-      if (STRING_IN_TABLE (toplevel_group->name,
+      char *name;
+
+      name = ppd_group_name (toplevel_group);
+      if (STRING_IN_TABLE (name,
                           color_group_whitelist) ||
          STRING_IN_TABLE (ppd_option->keyword,
                           color_option_whitelist))
        {
          option->group = g_strdup ("ColorPage");
        }
-      else if (STRING_IN_TABLE (toplevel_group->name,
+      else if (STRING_IN_TABLE (name,
                                image_quality_group_whitelist) ||
               STRING_IN_TABLE (ppd_option->keyword,
                                image_quality_option_whitelist))
        {
          option->group = g_strdup ("ImageQualityPage");
        }
-      else if (STRING_IN_TABLE (toplevel_group->name,
+      else if (STRING_IN_TABLE (name,
                                finishing_group_whitelist) ||
               STRING_IN_TABLE (ppd_option->keyword,
                                finishing_option_whitelist))
@@ -1908,15 +2094,17 @@ handle_option (GtkPrinterOptionSet *set,
 
 static void
 handle_group (GtkPrinterOptionSet *set,
-             ppd_file_t *ppd_file,
-             ppd_group_t *group,
-             ppd_group_t *toplevel_group,
-             GtkPrintSettings *settings)
+             ppd_file_t          *ppd_file,
+             ppd_group_t         *group,
+             ppd_group_t         *toplevel_group,
+             GtkPrintSettings    *settings)
 {
-  int i;
-
+  gint i;
+  gchar *name;
+  
   /* Ignore installable options */
-  if (strcmp (toplevel_group->name, "InstallableOptions") == 0)
+  name = ppd_group_name (toplevel_group);
+  if (strcmp (name, "InstallableOptions") == 0)
     return;
   
   for (i = 0; i < group->num_options; i++)
@@ -1928,9 +2116,10 @@ handle_group (GtkPrinterOptionSet *set,
 }
 
 static GtkPrinterOptionSet *
-cups_printer_get_options (GtkPrinter *printer,
-                         GtkPrintSettings                  *settings,
-                         GtkPageSetup                      *page_setup)
+cups_printer_get_options (GtkPrinter           *printer,
+                         GtkPrintSettings     *settings,
+                         GtkPageSetup         *page_setup,
+                         GtkPrintCapabilities  capabilities)
 {
   GtkPrinterOptionSet *set;
   GtkPrinterOption *option;
@@ -2012,14 +2201,27 @@ cups_printer_get_options (GtkPrinter *printer,
     {
       GtkPaperSize *paper_size;
       ppd_option_t *option;
-      
+      const gchar  *ppd_name;
+
       ppdMarkDefaults (ppd_file);
 
       paper_size = gtk_page_setup_get_paper_size (page_setup);
 
-      option = ppdFindOption(ppd_file, "PageSize");
-      strncpy (option->defchoice, gtk_paper_size_get_ppd_name (paper_size),
-              PPD_MAX_NAME);
+      option = ppdFindOption (ppd_file, "PageSize");
+      ppd_name = gtk_paper_size_get_ppd_name (paper_size);
+      
+      if (ppd_name)
+       strncpy (option->defchoice, ppd_name, PPD_MAX_NAME);
+      else
+        {
+          gchar *custom_name;
+
+         custom_name = g_strdup_printf (_("Custom.%2fx%.2f"),
+                                        gtk_paper_size_get_width (paper_size, GTK_UNIT_POINTS),
+                                        gtk_paper_size_get_height (paper_size, GTK_UNIT_POINTS));
+          strncpy (option->defchoice, custom_name, PPD_MAX_NAME);
+          g_free (custom_name);
+        }
 
       for (i = 0; i < ppd_file->num_groups; i++)
         handle_group (set, ppd_file, &ppd_file->groups[i], &ppd_file->groups[i], settings);
@@ -2031,8 +2233,8 @@ cups_printer_get_options (GtkPrinter *printer,
 
 static void
 mark_option_from_set (GtkPrinterOptionSet *set,
-                     ppd_file_t *ppd_file,
-                     ppd_option_t *ppd_option)
+                     ppd_file_t          *ppd_file,
+                     ppd_option_t        *ppd_option)
 {
   GtkPrinterOption *option;
   char *name = get_option_name (ppd_option->keyword);
@@ -2048,8 +2250,8 @@ mark_option_from_set (GtkPrinterOptionSet *set,
 
 static void
 mark_group_from_set (GtkPrinterOptionSet *set,
-                    ppd_file_t *ppd_file,
-                    ppd_group_t *group)
+                    ppd_file_t          *ppd_file,
+                    ppd_group_t         *group)
 {
   int i;
 
@@ -2062,11 +2264,12 @@ mark_group_from_set (GtkPrinterOptionSet *set,
 
 static void
 set_conflicts_from_option (GtkPrinterOptionSet *set,
-                          ppd_file_t *ppd_file,
-                          ppd_option_t *ppd_option)
+                          ppd_file_t          *ppd_file,
+                          ppd_option_t        *ppd_option)
 {
   GtkPrinterOption *option;
   char *name;
+
   if (ppd_option->conflicted)
     {
       name = get_option_name (ppd_option->keyword);
@@ -2083,8 +2286,8 @@ set_conflicts_from_option (GtkPrinterOptionSet *set,
 
 static void
 set_conflicts_from_group (GtkPrinterOptionSet *set,
-                         ppd_file_t *ppd_file,
-                         ppd_group_t *group)
+                         ppd_file_t          *ppd_file,
+                         ppd_group_t         *group)
 {
   int i;
 
@@ -2096,8 +2299,8 @@ set_conflicts_from_group (GtkPrinterOptionSet *set,
 }
 
 static gboolean
-cups_printer_mark_conflicts  (GtkPrinter          *printer,
-                             GtkPrinterOptionSet *options)
+cups_printer_mark_conflicts (GtkPrinter          *printer,
+                            GtkPrinterOptionSet *options)
 {
   ppd_file_t *ppd_file;
   int num_conflicts;
@@ -2137,12 +2340,12 @@ typedef struct {
 } NameMapping;
 
 static void
-map_settings_to_option (GtkPrinterOption *option,
-                       const NameMapping table[],
-                       int n_elements,
-                       GtkPrintSettings *settings,
-                       const char *standard_name,
-                       const char *cups_name)
+map_settings_to_option (GtkPrinterOption  *option,
+                       const NameMapping  table[],
+                       gint               n_elements,
+                       GtkPrintSettings  *settings,
+                       const gchar       *standard_name,
+                       const gchar       *cups_name)
 {
   int i;
   char *name;
@@ -2150,15 +2353,15 @@ map_settings_to_option (GtkPrinterOption *option,
   const char *standard_value;
 
   /* If the cups-specific setting is set, always use that */
-
   name = g_strdup_printf ("cups-%s", cups_name);
   cups_value = gtk_print_settings_get (settings, name);
   g_free (name);
   
-  if (cups_value != NULL) {
-    gtk_printer_option_set (option, cups_value);
-    return;
-  }
+  if (cups_value != NULL) 
+    {
+      gtk_printer_option_set (option, cups_value);
+      return;
+    }
 
   /* Otherwise we try to convert from the general setting */
   standard_value = gtk_print_settings_get (settings, standard_name);
@@ -2187,12 +2390,12 @@ map_settings_to_option (GtkPrinterOption *option,
 }
 
 static void
-map_option_to_settings (const char *value,
-                       const NameMapping table[],
-                       int n_elements,
-                       GtkPrintSettings *settings,
-                       const char *standard_name,
-                       const char *cups_name)
+map_option_to_settings (const gchar       *value,
+                       const NameMapping  table[],
+                       gint               n_elements,
+                       GtkPrintSettings  *settings,
+                       const gchar       *standard_name,
+                       const gchar       *cups_name)
 {
   int i;
   char *name;
@@ -2367,7 +2570,7 @@ set_option_from_settings (GtkPrinterOption *option,
 }
 
 static void
-foreach_option_get_settings (GtkPrinterOption  *option,
+foreach_option_get_settings (GtkPrinterOption *option,
                             gpointer          user_data)
 {
   struct OptionData *data = user_data;
@@ -2419,9 +2622,9 @@ foreach_option_get_settings (GtkPrinterOption  *option,
 }
 
 static void
-cups_printer_get_settings_from_options (GtkPrinter *printer,
+cups_printer_get_settings_from_options (GtkPrinter          *printer,
                                        GtkPrinterOptionSet *options,
-                                       GtkPrintSettings *settings)
+                                       GtkPrintSettings    *settings)
 {
   struct OptionData data;
   const char *print_at, *print_at_time;
@@ -2456,10 +2659,10 @@ cups_printer_get_settings_from_options (GtkPrinter *printer,
 }
 
 static void
-cups_printer_prepare_for_print (GtkPrinter *printer,
-                               GtkPrintJob *print_job,
+cups_printer_prepare_for_print (GtkPrinter       *printer,
+                               GtkPrintJob      *print_job,
                                GtkPrintSettings *settings,
-                               GtkPageSetup *page_setup)
+                               GtkPageSetup     *page_setup)
 {
   GtkPageSet page_set;
   GtkPaperSize *paper_size;
@@ -2540,10 +2743,10 @@ cups_printer_list_papers (GtkPrinter *printer)
       size = &ppd_file->sizes[i];
 
       display_name = NULL;
-      option = ppdFindOption(ppd_file, "PageSize");
+      option = ppdFindOption (ppd_file, "PageSize");
       if (option)
        {
-         choice = ppdFindChoice(option, size->name);
+         choice = ppdFindChoice (option, size->name);
          if (choice)
            display_name = ppd_text_to_utf8 (ppd_file, choice->text);
        }
@@ -2573,10 +2776,10 @@ cups_printer_list_papers (GtkPrinter *printer)
 
 static void
 cups_printer_get_hard_margins (GtkPrinter *printer,
-                              double     *top,
-                              double     *bottom,
-                              double     *left,
-                              double     *right)
+                              gdouble    *top,
+                              gdouble    *bottom,
+                              gdouble    *left,
+                              gdouble    *right)
 {
   ppd_file_t *ppd_file;
 
@@ -2589,3 +2792,12 @@ cups_printer_get_hard_margins (GtkPrinter *printer,
   *right = ppd_file->custom_margins[2];
   *top = ppd_file->custom_margins[3];
 }
+
+static GtkPrintCapabilities
+cups_printer_get_capabilities (GtkPrinter *printer)
+{
+  return
+    GTK_PRINT_CAPABILITY_COPIES |
+    GTK_PRINT_CAPABILITY_COLLATE |
+    GTK_PRINT_CAPABILITY_REVERSE;
+}