]> Pileus Git - ~andy/gtk/blobdiff - modules/printbackends/cups/gtkprintbackendcups.c
Bug 535158 – can't rearrange the order of multi pages per side
[~andy/gtk] / modules / printbackends / cups / gtkprintbackendcups.c
index 12288710d2dd02c89f3a6f42ac943ce7755e4f51..96dd2daf3fbb0ee607aa4dadd53049918c706450 100644 (file)
@@ -1,7 +1,7 @@
 /* GTK - The GIMP Toolkit
  * gtkprintbackendcups.h: Default implementation of GtkPrintBackend 
  * for the Common Unix Print System (CUPS)
- * Copyright (C) 2003, Red Hat, Inc.
+ * Copyright (C) 2006, 2007 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * Boston, MA 02111-1307, USA.
  */
 
+#include "config.h"
+#include <ctype.h>
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <stdlib.h>
 
-#include <config.h>
 #include <cups/cups.h>
 #include <cups/language.h>
 #include <cups/http.h>
 #include <cairo-pdf.h>
 #include <cairo-ps.h>
 
+#include <glib/gstdio.h>
 #include <glib/gi18n-lib.h>
 #include <gmodule.h>
 
-#include <gtk/gtkprintoperation.h>
-#include <gtk/gtkprintsettings.h>
+#include <gtk/gtk.h>
 #include <gtk/gtkprintbackend.h>
-#include <gtk/gtkprinter.h>
+#include <gtk/gtkunixprint.h>
 #include <gtk/gtkprinter-private.h>
 
 #include "gtkprintbackendcups.h"
 #include "gtkprintercups.h"
 
 #include "gtkcupsutils.h"
-#include "gtkdebug.h"
 
 
 typedef struct _GtkPrintBackendCupsClass GtkPrintBackendCupsClass;
@@ -59,6 +59,9 @@ typedef struct _GtkPrintBackendCupsClass GtkPrintBackendCupsClass;
 #define _CUPS_MAX_ATTEMPTS 10 
 #define _CUPS_MAX_CHUNK_SIZE 8192
 
+/* define this to see warnings about ignored ppd options */
+#undef PRINT_IGNORED_OPTIONS
+
 #define _CUPS_MAP_ATTR_INT(attr, v, a) {if (!g_ascii_strcasecmp (attr->name, (a))) v = attr->values[0].integer;}
 #define _CUPS_MAP_ATTR_STR(attr, v, a) {if (!g_ascii_strcasecmp (attr->name, (a))) v = attr->values[0].string.text;}
 
@@ -103,6 +106,13 @@ struct _GtkPrintBackendCups
   guint list_printers_poll;
   guint list_printers_pending : 1;
   guint got_default_printer   : 1;
+  guint default_printer_poll;
+  GtkCupsConnectionTest *default_printer_connection_test;
+
+  char **covers;
+  char  *default_cover_before;
+  char  *default_cover_after;
+  int    number_of_covers;
 };
 
 static GObjectClass *backend_parent_class;
@@ -112,6 +122,7 @@ static void                 gtk_print_backend_cups_init            (GtkPrintBack
 static void                 gtk_print_backend_cups_finalize        (GObject                           *object);
 static void                 gtk_print_backend_cups_dispose         (GObject                           *object);
 static void                 cups_get_printer_list                  (GtkPrintBackend                   *print_backend);
+static void                 cups_get_default_printer               (GtkPrintBackendCups               *print_backend);
 static void                 cups_request_execute                   (GtkPrintBackendCups               *print_backend,
                                                                    GtkCupsRequest                    *request,
                                                                    GtkPrintCupsResponseCallbackFunc   callback,
@@ -131,8 +142,9 @@ static void                 cups_printer_prepare_for_print         (GtkPrinter
                                                                    GtkPrintSettings                  *settings,
                                                                    GtkPageSetup                      *page_setup);
 static GList *              cups_printer_list_papers               (GtkPrinter                        *printer);
+static GtkPageSetup *       cups_printer_get_default_page_size     (GtkPrinter                        *printer);
 static void                 cups_printer_request_details           (GtkPrinter                        *printer);
-static void                 cups_request_default_printer           (GtkPrintBackendCups               *print_backend);
+static gboolean             cups_request_default_printer           (GtkPrintBackendCups               *print_backend);
 static void                 cups_request_ppd                       (GtkPrinter                        *printer);
 static void                 cups_printer_get_hard_margins          (GtkPrinter                        *printer,
                                                                    double                            *top,
@@ -250,6 +262,7 @@ gtk_print_backend_cups_class_init (GtkPrintBackendCupsClass *class)
   backend_class->printer_get_settings_from_options = cups_printer_get_settings_from_options;
   backend_class->printer_prepare_for_print = cups_printer_prepare_for_print;
   backend_class->printer_list_papers = cups_printer_list_papers;
+  backend_class->printer_get_default_page_size = cups_printer_get_default_page_size;
   backend_class->printer_get_hard_margins = cups_printer_get_hard_margins;
   backend_class->printer_get_capabilities = cups_printer_get_capabilities;
 }
@@ -266,16 +279,17 @@ _cairo_write_to_cups (void                *closure,
   error = NULL;
 
   GTK_NOTE (PRINTING,
-            g_print ("CUPS Backend: Writting %i byte chunk to temp file\n", length));
+            g_print ("CUPS Backend: Writing %i byte chunk to temp file\n", length));
 
   while (length > 0) 
     {
-      g_io_channel_write_chars (io, data, length, &written, &error);
+      g_io_channel_write_chars (io, (gchar *)data, length, &written, &error);
 
       if (error != NULL)
        {
          GTK_NOTE (PRINTING,
-                    g_print ("CUPS Backend: Error writting to temp file, %s\n", error->message));
+                    g_print ("CUPS Backend: Error writing to temp file, %s\n", 
+                             error->message));
 
           g_error_free (error);
          return CAIRO_STATUS_WRITE_ERROR;
@@ -299,11 +313,30 @@ cups_printer_create_cairo_surface (GtkPrinter       *printer,
                                   GIOChannel       *cache_io)
 {
   cairo_surface_t *surface; 
+  ppd_file_t      *ppd_file = NULL;
+  ppd_attr_t      *ppd_attr = NULL;
+  int              level = 2;
  
   /* TODO: check if it is a ps or pdf printer */
   
   surface = cairo_ps_surface_create_for_stream  (_cairo_write_to_cups, cache_io, width, height);
 
+  ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
+
+  if (ppd_file != NULL)
+    {
+      ppd_attr = ppdFindAttr (ppd_file, "LanguageLevel", NULL);
+
+      if (ppd_attr != NULL)
+        level = atoi (ppd_attr->value);
+    }
+
+  if (level == 2)
+    cairo_ps_surface_restrict_to_level (surface, CAIRO_PS_LEVEL_2);
+
+  if (level == 3)
+    cairo_ps_surface_restrict_to_level (surface, CAIRO_PS_LEVEL_3);
+
   /* TODO: DPI from settings object? */
   cairo_surface_set_fallback_resolution (surface, 300, 300);
 
@@ -337,6 +370,8 @@ cups_print_cb (GtkPrintBackendCups *print_backend,
   GError *error = NULL;
   CupsPrintStreamData *ps = user_data;
 
+  GDK_THREADS_ENTER ();
+
   GTK_NOTE (PRINTING,
             g_print ("CUPS Backend: %s\n", G_STRFUNC)); 
 
@@ -371,7 +406,8 @@ cups_print_cb (GtkPrintBackendCups *print_backend,
   
   if (error)
     g_error_free (error);
-  
+
+  GDK_THREADS_LEAVE ();  
 }
 
 static void
@@ -405,6 +441,7 @@ gtk_print_backend_cups_print_stream (GtkPrintBackend         *print_backend,
   GtkCupsRequest *request;
   GtkPrintSettings *settings;
   const gchar *title;
+  char  printer_absolute_uri[HTTP_MAX_URI];
 
   GTK_NOTE (PRINTING,
             g_print ("CUPS Backend: %s\n", G_STRFUNC));   
@@ -416,19 +453,36 @@ gtk_print_backend_cups_print_stream (GtkPrintBackend         *print_backend,
                                   GTK_CUPS_POST,
                                   IPP_PRINT_JOB,
                                  data_io,
-                                 NULL,
+                                 NULL, 
                                  cups_printer->device_uri);
 
-  gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
-                                   NULL, cups_printer->printer_uri);
+#if (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR >= 2) || CUPS_VERSION_MAJOR > 1
+  httpAssembleURIf (HTTP_URI_CODING_ALL,
+                    printer_absolute_uri,
+                    sizeof (printer_absolute_uri),
+                    "ipp",
+                    NULL,
+                    "localhost",
+                    ippPort (),
+                    "/printers/%s",
+                    gtk_printer_get_name (gtk_print_job_get_printer (job)));
+#else
+  g_snprintf (printer_absolute_uri,
+              sizeof (printer_absolute_uri),
+              "ipp://localhost:%d/printers/%s",
+              ippPort (),
+              gtk_printer_get_name (gtk_print_job_get_printer (job)));
+#endif
 
-  gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
-                                   NULL, cupsUser());
+  gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, 
+                                   IPP_TAG_URI, "printer-uri",
+                                   NULL, printer_absolute_uri);
 
   title = gtk_print_job_get_title (job);
   if (title)
-    gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
-                                     title);
+    gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, 
+                                     IPP_TAG_NAME, "job-name", 
+                                     NULL, title);
 
   gtk_print_settings_foreach (settings, add_cups_options, request);
   
@@ -453,7 +507,15 @@ gtk_print_backend_cups_init (GtkPrintBackendCups *backend_cups)
   backend_cups->got_default_printer = FALSE;  
   backend_cups->list_printers_pending = FALSE;
 
-  cups_request_default_printer (backend_cups);
+  backend_cups->covers = NULL;
+  backend_cups->default_cover_before = NULL;
+  backend_cups->default_cover_after = NULL;
+  backend_cups->number_of_covers = 0;
+
+  backend_cups->default_printer_poll = 0;
+  backend_cups->default_printer_connection_test = NULL;
+
+  cups_get_default_printer (backend_cups);
 }
 
 static void
@@ -468,6 +530,14 @@ gtk_print_backend_cups_finalize (GObject *object)
 
   g_free (backend_cups->default_printer);
   backend_cups->default_printer = NULL;
+
+  g_strfreev (backend_cups->covers);
+  backend_cups->number_of_covers = 0;
+
+  g_free (backend_cups->default_cover_before);
+  g_free (backend_cups->default_cover_after);
+
+  gtk_cups_connection_test_free (backend_cups->default_printer_connection_test);
   
   backend_parent_class->finalize (object);
 }
@@ -486,6 +556,10 @@ gtk_print_backend_cups_dispose (GObject *object)
     g_source_remove (backend_cups->list_printers_poll);
   backend_cups->list_printers_poll = 0;
   
+  if (backend_cups->default_printer_poll > 0)
+    g_source_remove (backend_cups->default_printer_poll);
+  backend_cups->default_printer_poll = 0;
+
   backend_parent_class->dispose (object);
 }
 
@@ -503,27 +577,29 @@ cups_dispatch_watch_check (GSource *source)
   dispatch = (GtkPrintCupsDispatchWatch *) source;
 
   poll_state = gtk_cups_request_get_poll_state (dispatch->request);
-  
-  if (dispatch->data_poll == NULL && 
-      dispatch->request->http != NULL)
-    {
-      dispatch->data_poll = g_new0 (GPollFD, 1);
-      dispatch->data_poll->fd = dispatch->request->http->fd;
 
-      g_source_add_poll (source, dispatch->data_poll);
-    }
-            
-  if (dispatch->data_poll != NULL && dispatch->request->http != NULL)
+  if (dispatch->request->http != NULL)
     {
-      if (dispatch->data_poll->fd != dispatch->request->http->fd)
-        dispatch->data_poll->fd = dispatch->request->http->fd;
-
-      if (poll_state == GTK_CUPS_HTTP_READ)
-        dispatch->data_poll->events = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI;
-      else if (poll_state == GTK_CUPS_HTTP_WRITE)
-        dispatch->data_poll->events = G_IO_OUT | G_IO_ERR;
+      if (dispatch->data_poll == NULL)
+       {
+         dispatch->data_poll = g_new0 (GPollFD, 1);
+         g_source_add_poll (source, dispatch->data_poll);
+       }
       else
-        dispatch->data_poll->events = 0;
+       {
+         if (poll_state == GTK_CUPS_HTTP_READ)
+           dispatch->data_poll->events = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI;
+         else if (poll_state == GTK_CUPS_HTTP_WRITE)
+           dispatch->data_poll->events = G_IO_OUT | G_IO_ERR;
+         else
+           dispatch->data_poll->events = 0;
+       }
+
+#ifdef HAVE_CUPS_API_1_2
+      dispatch->data_poll->fd = httpGetFd (dispatch->request->http);
+#else
+      dispatch->data_poll->fd = dispatch->request->http->fd;
+#endif
     }
     
   if (poll_state != GTK_CUPS_HTTP_IDLE)  
@@ -578,10 +654,17 @@ cups_dispatch_watch_dispatch (GSource     *source,
             g_print ("CUPS Backend: %s <source %p>\n", G_STRFUNC, source));
 
   if (gtk_cups_result_is_error (result))
-    g_warning ("Error result: %s", gtk_cups_result_get_error_string (result));
+    {
+      GTK_NOTE (PRINTING, 
+                g_print("Error result: %s (type %i, status %i, code %i)\n", 
+                        gtk_cups_result_get_error_string (result),
+                        gtk_cups_result_get_error_type (result),
+                        gtk_cups_result_get_error_status (result),
+                        gtk_cups_result_get_error_code (result)));
+     }
 
   ep_callback (GTK_PRINT_BACKEND (dispatch->backend), result, user_data);
-
+    
   return FALSE;
 }
 
@@ -612,8 +695,7 @@ cups_dispatch_watch_finalize (GSource *source)
       dispatch->backend = NULL;
     }
 
-  if (dispatch->data_poll != NULL)
-    g_free (dispatch->data_poll);
+  g_free (dispatch->data_poll);
 }
 
 static GSourceFuncs _cups_dispatch_watch_funcs = {
@@ -649,6 +731,7 @@ cups_request_execute (GtkPrintBackendCups              *print_backend,
   g_source_unref ((GSource *) dispatch);
 }
 
+#if 0
 static void
 cups_request_printer_info_cb (GtkPrintBackendCups *backend,
                               GtkCupsResult       *result,
@@ -739,7 +822,9 @@ cups_request_printer_info (GtkPrintBackendCups *print_backend,
       "printer-info",
       "printer-state-message",
       "printer-state",
-      "queued-job-count"
+      "queued-job-count",
+      "job-sheets-supported",
+      "job-sheets-default"
     };
 
   request = gtk_cups_request_new (NULL,
@@ -769,7 +854,7 @@ cups_request_printer_info (GtkPrintBackendCups *print_backend,
                         g_strdup (printer_name),
                         (GDestroyNotify) g_free);
 }
-
+#endif
 
 typedef struct {
   GtkPrintBackendCups *print_backend;
@@ -806,10 +891,12 @@ cups_request_job_info_cb (GtkPrintBackendCups *print_backend,
   int state;
   gboolean done;
 
+  GDK_THREADS_ENTER ();
+
   if (data->job == NULL)
     {
       cups_job_poll_data_free (data);
-      return;
+      goto done;
     }
 
   data->counter++;
@@ -868,13 +955,16 @@ cups_request_job_info_cb (GtkPrintBackendCups *print_backend,
     }
   else
     cups_job_poll_data_free (data);    
+
+done:
+  GDK_THREADS_LEAVE ();
 }
 
 static void
 cups_request_job_info (CupsJobPollData *data)
 {
   GtkCupsRequest *request;
-  gchar *printer_uri;
+  gchar *job_uri;
 
   request = gtk_cups_request_new (NULL,
                                   GTK_CUPS_POST,
@@ -883,10 +973,10 @@ cups_request_job_info (CupsJobPollData *data)
                                  NULL,
                                  NULL);
 
-  printer_uri = g_strdup_printf ("ipp://localhost/jobs/%d", data->job_id);
+  job_uri = g_strdup_printf ("ipp://localhost/jobs/%d", data->job_id);
   gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_URI,
-                                   "job-uri", NULL, printer_uri);
-  g_free (printer_uri);
+                                   "job-uri", NULL, job_uri);
+  g_free (job_uri);
 
   cups_request_execute (data->print_backend,
                         request,
@@ -956,6 +1046,8 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
   gboolean list_has_changed;
   GList *removed_printer_checklist;
 
+  GDK_THREADS_ENTER ();
+
   list_has_changed = FALSE;
 
   GTK_NOTE (PRINTING,
@@ -965,7 +1057,9 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
 
   if (gtk_cups_result_is_error (result))
     {
-      g_warning ("Error getting printer list: %s", gtk_cups_result_get_error_string (result));
+      GTK_NOTE (PRINTING, 
+                g_warning ("CUPS Backend: Error getting printer list: %s", 
+                          gtk_cups_result_get_error_string (result)));
 
       goto done;
     }
@@ -980,10 +1074,62 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
   for (attr = response->attrs; attr != NULL; attr = attr->next)
     {
       GtkPrinter *printer;
-      const gchar *printer_name;
-      const gchar *printer_uri;
-      const gchar *member_uris;
+      const gchar *printer_name = NULL;
+      const gchar *printer_uri = NULL;
+      const gchar *member_uris = NULL;
+      const gchar *location = NULL;
+      const gchar *description = NULL;
+      const gchar *state_msg = NULL;
+      gint state = 0;
+      gint job_count = 0;
+      gboolean status_changed = FALSE;
       GList *node;
+      gint i,j;
+      const gchar *reason_msg = NULL;
+      gchar *reason_msg_desc = NULL;
+      gchar *tmp_msg = NULL;
+      gchar *tmp_msg2 = NULL;
+      gint printer_state_reason_level = 0; /* 0 - none, 1 - report, 2 - warning, 3 - error */
+      gboolean interested_in = FALSE;
+      gboolean found = FALSE;
+      static const char * const reasons[] =    /* Reasons we're interested in */
+        {
+          "toner-low",
+          "toner-empty",
+          "developer-low",
+          "developer-empty",
+          "marker-supply-low",
+          "marker-supply-empty",
+          "cover-open",
+          "door-open",
+          "media-low",
+          "media-empty",
+          "offline",
+          "connecting-to-device",
+          "other"
+        };
+      static const char * reasons_descs[] =
+        {
+          N_("Printer '%s' is low on toner."),
+          N_("Printer '%s' has no toner left."),
+          /* Translators: "Developer" like on photo development context */
+          N_("Printer '%s' is low on developer."),
+          /* Translators: "Developer" like on photo development context */
+          N_("Printer '%s' is out of developer."),
+          /* Translators: "marker" is one color bin of the printer */
+          N_("Printer '%s' is low on at least one marker supply."),
+          /* Translators: "marker" is one color bin of the printer */
+          N_("Printer '%s' is out of at least one marker supply."),
+          N_("The cover is open on printer '%s'."),
+          N_("The door is open on printer '%s'."),
+          N_("Printer '%s' is low on paper."),
+          N_("Printer '%s' is out of paper."),
+          N_("Printer '%s' is currently off-line."),
+          N_("Printer '%s' may not be connected."),
+          N_("There is a problem on printer '%s'.")
+        };
+      gboolean is_paused = FALSE;
+      gboolean is_accepting_jobs = TRUE;
       
       /* Skip leading attributes until we hit a printer...
        */
@@ -993,20 +1139,107 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
       if (attr == NULL)
         break;
 
-      printer_name = NULL;
-      printer_uri = NULL;
-      member_uris = NULL;
       while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
       {
-        if (!strcmp (attr->name, "printer-name") &&
+        if (strcmp (attr->name, "printer-name") == 0 &&
            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") == 0 &&
                 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") == 0 &&
                 attr->value_tag == IPP_TAG_URI)
          member_uris = attr->values[0].string.text;
+        else if (strcmp (attr->name, "printer-location") == 0)
+          location = attr->values[0].string.text;
+        else if (strcmp (attr->name, "printer-info") == 0)
+          description = attr->values[0].string.text;
+        else if (strcmp (attr->name, "printer-state-message") == 0)
+          state_msg = attr->values[0].string.text;
+        else if (strcmp (attr->name, "printer-state-reasons") == 0)
+          /* Store most important reason to reason_msg and set
+             its importance at printer_state_reason_level */
+          {
+            for (i = 0; i < attr->num_values; i++)
+              {
+                if (strcmp (attr->values[i].string.text, "none") != 0)
+                  {
+                    /* Sets is_paused flag for paused printer. */
+                    if (strcmp (attr->values[i].string.text, "paused") == 0)
+                      {
+                        is_paused = TRUE;
+                      }
+
+                    interested_in = FALSE;
+                    for (j = 0; j < G_N_ELEMENTS (reasons); j++)
+                        if (strncmp (attr->values[i].string.text, reasons[j], strlen (reasons[j])) == 0)
+                          {
+                            interested_in = TRUE;
+                            break;
+                          }
+
+                    if (interested_in)
+                      {
+                        if (g_str_has_suffix (attr->values[i].string.text, "-report"))
+                          {
+                            if (printer_state_reason_level <= 1)
+                              {
+                                reason_msg = attr->values[i].string.text;
+                                printer_state_reason_level = 1;
+                              }
+                          }
+                        else if (g_str_has_suffix (attr->values[i].string.text, "-warning"))
+                          {
+                            if (printer_state_reason_level <= 2)
+                              {
+                                reason_msg = attr->values[i].string.text;
+                                printer_state_reason_level = 2;
+                              }
+                          }
+                        else  /* It is error in the case of no suffix. */
+                          {
+                            reason_msg = attr->values[i].string.text;
+                            printer_state_reason_level = 3;
+                          }
+                      }
+                  }
+              }
+          }
+        else if (strcmp (attr->name, "printer-state") == 0)
+          state = attr->values[0].integer;
+        else if (strcmp (attr->name, "queued-job-count") == 0)
+          job_count = attr->values[0].integer;
+        else if (strcmp (attr->name, "printer-is-accepting-jobs") == 0)
+          {
+            if (attr->values[0].boolean == 1)
+              is_accepting_jobs = TRUE;
+            else
+              is_accepting_jobs = FALSE;
+          }
+        else if (strcmp (attr->name, "job-sheets-supported") == 0)
+          {
+            if (cups_backend->covers == NULL)
+              {
+                cups_backend->number_of_covers = attr->num_values;
+                cups_backend->covers = g_new (char *, cups_backend->number_of_covers + 1);
+
+                for (i = 0; i < cups_backend->number_of_covers; i++)
+                  cups_backend->covers[i] = g_strdup (attr->values[i].string.text);
+
+                cups_backend->covers[cups_backend->number_of_covers] = NULL;
+              }
+          }
+        else if (strcmp (attr->name, "job-sheets-default") == 0)
+          {
+            if ( (cups_backend->default_cover_before == NULL) && (cups_backend->default_cover_after == NULL))
+              {
+                if (attr->num_values == 2)
+                  {
+                    cups_backend->default_cover_before = g_strdup (attr->values[0].string.text);
+                    cups_backend->default_cover_after = g_strdup (attr->values[1].string.text);
+                  }
+              }
+          }
         else
          {
            GTK_NOTE (PRINTING,
@@ -1077,14 +1310,14 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
                        resource);
 #endif
 
-          if (!strncmp (resource, "/printers/", 10))
+          if (strncmp (resource, "/printers/", 10) == 0)
            {
              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));
+         gethostname (uri, sizeof (uri));
          if (strcasecmp (uri, hostname) == 0)
            strcpy (hostname, "localhost");
 
@@ -1103,6 +1336,9 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
       else
        g_object_ref (printer);
 
+      gtk_printer_set_is_paused (printer, is_paused);
+      gtk_printer_set_is_accepting_jobs (printer, is_accepting_jobs);
+
       if (!gtk_printer_is_active (printer))
         {
          gtk_printer_set_is_active (printer, TRUE);
@@ -1117,11 +1353,91 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
          gtk_printer_set_is_new (printer, FALSE);
         }
 
+#if 0
+      /* Getting printer info with separate requests overwhelms cups
+       * when the printer list has more than a handful of printers.
+       */
       cups_request_printer_info (cups_backend, gtk_printer_get_name (printer));
+#endif
+
+      GTK_PRINTER_CUPS (printer)->state = state;
+      status_changed = gtk_printer_set_job_count (printer, job_count);
+      status_changed |= gtk_printer_set_location (printer, location);
+      status_changed |= gtk_printer_set_description (printer, description);
+
+      if (state_msg != NULL && strlen (state_msg) == 0)
+        {
+          if (is_paused && !is_accepting_jobs)
+                 /* Translators: this is a printer status. */
+            tmp_msg2 = g_strdup ( N_("Paused ; Rejecting Jobs"));
+          if (is_paused && is_accepting_jobs)
+                 /* Translators: this is a printer status. */
+            tmp_msg2 = g_strdup ( N_("Paused"));
+          if (!is_paused && !is_accepting_jobs)
+                 /* Translators: this is a printer status. */
+            tmp_msg2 = g_strdup ( N_("Rejecting Jobs"));
+
+          if (tmp_msg2 != NULL)
+            state_msg = tmp_msg2;
+        }
+
+      /* Set description of the reason and combine it with printer-state-message. */
+      if ( (reason_msg != NULL))
+        {
+          for (i = 0; i < G_N_ELEMENTS (reasons); i++)
+            {
+              if (strncmp (reason_msg, reasons[i], strlen (reasons[i])) == 0)
+                {
+                  reason_msg_desc = g_strdup_printf (reasons_descs[i], printer_name);
+                  found = TRUE;
+                  break;
+                }
+            }
+
+          if (!found)
+            printer_state_reason_level = 0;
+
+          if (printer_state_reason_level >= 2)
+            {
+              if (strlen (state_msg) == 0)
+                state_msg = reason_msg_desc;
+              else
+                {
+                  tmp_msg = g_strjoin (" ; ", state_msg, reason_msg_desc, NULL);
+                  state_msg = tmp_msg;
+                }
+            }
+        }
+
+      status_changed |= gtk_printer_set_state_message (printer, state_msg);
+      status_changed |= gtk_printer_set_is_accepting_jobs (printer, is_accepting_jobs);
+
+      if (tmp_msg != NULL)
+        g_free (tmp_msg);
+
+      if (tmp_msg2 != NULL)
+        g_free (tmp_msg2);
+
+      if (reason_msg_desc != NULL)
+        g_free (reason_msg_desc);
+
+      /* Set printer icon according to importance
+         (none, report, warning, error - report is omitted). */
+      if (printer_state_reason_level == 3)
+        gtk_printer_set_icon_name (printer, "gtk-print-error");
+      else if (printer_state_reason_level == 2)
+        gtk_printer_set_icon_name (printer, "gtk-print-warning");
+      else if (gtk_printer_is_paused (printer))
+        gtk_printer_set_icon_name (printer, "gtk-print-paused");
+      else
+        gtk_printer_set_icon_name (printer, "gtk-print");
+
+      if (status_changed)
+        g_signal_emit_by_name (GTK_PRINT_BACKEND (backend),
+                               "printer-status-changed", printer);
 
       /* The ref is held by GtkPrintBackend, in add_printer() */
       g_object_unref (printer);
-
       
       if (attr == NULL)
         break;
@@ -1141,6 +1457,8 @@ done:
     g_signal_emit_by_name (backend, "printer-list-changed");
   
   gtk_print_backend_set_list_done (backend);
+
+  GDK_THREADS_LEAVE ();
 }
 
 static gboolean
@@ -1151,7 +1469,16 @@ cups_request_printer_list (GtkPrintBackendCups *cups_backend)
     {
       "printer-name",
       "printer-uri-supported",
-      "member-uris"
+      "member-uris",
+      "printer-location",
+      "printer-info",
+      "printer-state-message",
+      "printer-state-reasons",
+      "printer-state",
+      "queued-job-count",
+      "printer-is-accepting-jobs",
+      "job-sheets-supported",
+      "job-sheets-default"
     };
  
   if (cups_backend->list_printers_pending ||
@@ -1189,7 +1516,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,
+      cups_backend->list_printers_poll = gdk_threads_add_timeout (3000,
                                                         (GSourceFunc) cups_request_printer_list,
                                                         backend);
     }
@@ -1198,6 +1525,7 @@ cups_get_printer_list (GtkPrintBackend *backend)
 typedef struct {
   GtkPrinterCups *printer;
   GIOChannel *ppd_io;
+  http_t *http;
 } GetPPDData;
 
 static void
@@ -1205,7 +1533,7 @@ get_ppd_data_free (GetPPDData *data)
 {
   GTK_NOTE (PRINTING,
             g_print ("CUPS Backend: %s\n", G_STRFUNC));
-
+  httpClose (data->http);
   g_io_channel_unref (data->ppd_io);
   g_object_unref (data->printer);
   g_free (data);
@@ -1219,6 +1547,8 @@ cups_request_ppd_cb (GtkPrintBackendCups *print_backend,
   ipp_t *response;
   GtkPrinter *printer;
 
+  GDK_THREADS_ENTER ();
+
   GTK_NOTE (PRINTING,
             g_print ("CUPS Backend: %s\n", G_STRFUNC));
 
@@ -1227,8 +1557,19 @@ cups_request_ppd_cb (GtkPrintBackendCups *print_backend,
 
   if (gtk_cups_result_is_error (result))
     {
-      g_signal_emit_by_name (printer, "details-acquired", FALSE);
-      return;
+      gboolean success = FALSE;
+
+      /* if we get a 404 then it is just a raw printer without a ppd
+         and not an error */
+      if ((gtk_cups_result_get_error_type (result) == GTK_CUPS_ERROR_HTTP) &&
+          (gtk_cups_result_get_error_status (result) == HTTP_NOT_FOUND))
+        {
+          gtk_printer_set_has_details (printer, TRUE);
+          success = TRUE;
+        } 
+        
+      g_signal_emit_by_name (printer, "details-acquired", success);
+      goto done;
     }
 
   response = gtk_cups_result_get_response (result);
@@ -1236,9 +1577,14 @@ cups_request_ppd_cb (GtkPrintBackendCups *print_backend,
   /* 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)));
+
+  ppdMarkDefaults (data->printer->ppd_file);
   
   gtk_printer_set_has_details (printer, TRUE);
   g_signal_emit_by_name (printer, "details-acquired", TRUE);
+
+done:
+  GDK_THREADS_LEAVE ();
 }
 
 static void
@@ -1261,11 +1607,10 @@ cups_request_ppd (GtkPrinter *printer)
   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);
 
   fd = g_file_open_tmp ("gtkprint_ppd_XXXXXX", 
@@ -1282,7 +1627,9 @@ cups_request_ppd (GtkPrinter *printer)
 
   if (error != NULL)
     {
-      g_warning ("%s", error->message);
+      GTK_NOTE (PRINTING, 
+                g_warning ("CUPS Backend: Failed to create temp file, %s\n", 
+                           error->message));
       g_error_free (error);
       httpClose (http);
       g_free (ppd_filename);
@@ -1292,6 +1639,7 @@ cups_request_ppd (GtkPrinter *printer)
       return;
     }
     
+  data->http = http;
   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);
@@ -1300,8 +1648,9 @@ cups_request_ppd (GtkPrinter *printer)
   data->printer = g_object_ref (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_printer_cups_get_ppd_name (GTK_PRINTER_CUPS (printer)));
+
+  request = gtk_cups_request_new (data->http,
                                   GTK_CUPS_GET,
                                  0,
                                   data->ppd_io,
@@ -1325,6 +1674,179 @@ cups_request_ppd (GtkPrinter *printer)
                         (GDestroyNotify)get_ppd_data_free);
 }
 
+/* Ordering matters for default preference */
+static const char *lpoptions_locations[] = {
+  "/etc/cups/lpoptions",
+  ".lpoptions", 
+  ".cups/lpoptions"
+};
+
+static void
+cups_parse_user_default_printer (const char  *filename,
+                                 char       **printer_name)
+{
+  FILE *fp;
+  char line[1024], *lineptr, *defname = NULL;
+  
+  if ((fp = g_fopen (filename, "r")) == NULL)
+    return;
+
+  while (fgets (line, sizeof (line), fp) != NULL)
+    {
+      if (strncasecmp (line, "default", 7) != 0 || !isspace (line[7]))
+        continue;
+
+      lineptr = line + 8;
+      while (isspace (*lineptr))
+        lineptr++;
+
+      if (!*lineptr)
+        continue;
+
+      defname = lineptr;
+      while (!isspace (*lineptr) && *lineptr && *lineptr != '/')
+        lineptr++;
+
+      *lineptr = '\0';
+
+      if (*printer_name != NULL)
+        g_free (*printer_name);
+
+      *printer_name = g_strdup (defname);
+    }
+
+  fclose (fp);
+}
+
+static void
+cups_get_user_default_printer (char **printer_name)
+{
+  int i;
+
+  for (i = 0; i < G_N_ELEMENTS (lpoptions_locations); i++)
+    {
+      if (g_path_is_absolute (lpoptions_locations[i]))
+        {
+          cups_parse_user_default_printer (lpoptions_locations[i],
+                                           printer_name);
+        }
+      else 
+        {
+          char *filename;
+
+          filename = g_build_filename (g_get_home_dir (), 
+                                       lpoptions_locations[i], NULL);
+          cups_parse_user_default_printer (filename, printer_name);
+          g_free (filename);
+        }
+    }
+}
+
+static int
+cups_parse_user_options (const char     *filename,
+                         const char     *printer_name,
+                         int             num_options,
+                         cups_option_t **options)
+{
+  FILE *fp;
+  gchar line[1024], *lineptr, *name;
+
+  if ((fp = g_fopen (filename, "r")) == NULL)
+    return num_options;
+
+  while (fgets (line, sizeof (line), fp) != NULL)
+    {
+      if (strncasecmp (line, "dest", 4) == 0 && isspace (line[4]))
+        lineptr = line + 4;
+      else if (strncasecmp (line, "default", 7) == 0 && isspace (line[7]))
+        lineptr = line + 7;
+      else
+        continue;
+
+      /* Skip leading whitespace */
+      while (isspace (*lineptr))
+        lineptr++;
+
+      if (!*lineptr)
+        continue;
+
+      /* NUL-terminate the name, stripping the instance name */
+      name = lineptr;
+      while (!isspace (*lineptr) && *lineptr)
+        {
+          if (*lineptr == '/')
+            *lineptr = '\0';
+          lineptr++;
+        }
+
+      if (!*lineptr)
+        continue;
+
+      *lineptr++ = '\0';
+
+      if (strncasecmp (name, printer_name, strlen (printer_name)) != 0)
+          continue;
+
+      /* We found our printer, parse the options */
+      num_options = cupsParseOptions (lineptr, num_options, options);
+    }
+
+  fclose (fp);
+
+  return num_options;
+}
+
+static int
+cups_get_user_options (const char     *printer_name,
+                       int             num_options,
+                       cups_option_t **options)
+{
+  int i;
+
+  for (i = 0; i < G_N_ELEMENTS (lpoptions_locations); i++)
+    {
+      if (g_path_is_absolute (lpoptions_locations[i]))
+        { 
+           num_options = cups_parse_user_options (lpoptions_locations[i],
+                                                  printer_name,
+                                                  num_options,
+                                                  options);
+        }
+      else
+        {
+          char *filename;
+
+          filename = g_build_filename (g_get_home_dir (), 
+                                       lpoptions_locations[i], NULL);
+          num_options = cups_parse_user_options (filename, printer_name,
+                                                 num_options, options);
+          g_free (filename);
+        }
+    }
+
+  return num_options;
+}
+
+/* This function requests default printer from a CUPS server in regular intervals.
+ * In the case of unreachable CUPS server the request is repeated later.
+ * The default printer is not requested in the case of previous success.
+ */
+static void
+cups_get_default_printer (GtkPrintBackendCups *backend)
+{
+  GtkPrintBackendCups *cups_backend;
+
+  cups_backend = backend;
+
+  cups_backend->default_printer_connection_test = gtk_cups_connection_test_new (NULL);
+  if (cups_backend->default_printer_poll == 0)
+    {
+      if (cups_request_default_printer (cups_backend))
+        cups_backend->default_printer_poll = gdk_threads_add_timeout_seconds (1,
+                                                                              (GSourceFunc) cups_request_default_printer,
+                                                                              backend);
+    }
+}
 
 static void
 cups_request_default_printer_cb (GtkPrintBackendCups *print_backend,
@@ -1334,6 +1856,8 @@ cups_request_default_printer_cb (GtkPrintBackendCups *print_backend,
   ipp_t *response;
   ipp_attribute_t *attr;
 
+  GDK_THREADS_ENTER ();
+
   response = gtk_cups_result_get_response (result);
   
   if ((attr = ippFindAttribute (response, "printer-name", IPP_TAG_NAME)) != NULL)
@@ -1346,28 +1870,46 @@ cups_request_default_printer_cb (GtkPrintBackendCups *print_backend,
    */
   if (print_backend->list_printers_poll != 0)
     cups_request_printer_list (print_backend);
+
+  GDK_THREADS_LEAVE ();
 }
 
-static void
+static gboolean
 cups_request_default_printer (GtkPrintBackendCups *print_backend)
 {
   GtkCupsRequest *request;
   const char *str;
+  char *name = NULL;
+
+  if (!gtk_cups_connection_test_is_server_available (print_backend->default_printer_connection_test))
+    return TRUE;
+
+  gtk_cups_connection_test_free (print_backend->default_printer_connection_test);
+  print_backend->default_printer_connection_test = NULL;
 
   if ((str = g_getenv ("LPDEST")) != NULL)
     {
       print_backend->default_printer = g_strdup (str);
       print_backend->got_default_printer = TRUE;
-      return;
+      return FALSE;
     }
   else if ((str = g_getenv ("PRINTER")) != NULL &&
           strcmp (str, "lp") != 0)
     {
       print_backend->default_printer = g_strdup (str);
       print_backend->got_default_printer = TRUE;
-      return;
+      return FALSE;
     }
   
+  /* Figure out user setting for default printer */  
+  cups_get_user_default_printer (&name);
+  if (name != NULL)
+    {
+       print_backend->default_printer = name;
+       print_backend->got_default_printer = TRUE;
+       return FALSE;
+    }
+
   request = gtk_cups_request_new (NULL,
                                   GTK_CUPS_POST,
                                   CUPS_GET_DEFAULT,
@@ -1380,6 +1922,8 @@ cups_request_default_printer (GtkPrintBackendCups *print_backend)
                         (GtkPrintCupsResponseCallbackFunc) cups_request_default_printer_cb,
                        g_object_ref (print_backend),
                        g_object_unref);
+
+  return FALSE;
 }
 
 static void
@@ -1438,7 +1982,8 @@ ppd_text_to_utf8 (ppd_file_t *ppd_file,
 
   if (res == NULL)
     {
-      g_warning ("unable to convert PPD text");
+      GTK_NOTE (PRINTING,
+                g_warning ("CUPS Backend: Unable to convert PPD text\n"));
       res = g_strdup ("???");
     }
   
@@ -1464,11 +2009,17 @@ static const struct {
   const char *translation;
 } cups_choice_translations[] = {
   { "Duplex", "None", N_("One Sided") },
+  /* Translators: this is an option of "Paper Source" */
   { "InputSlot", "Auto", N_("Auto Select") },
+  /* Translators: this is an option of "Paper Source" */
   { "InputSlot", "AutoSelect", N_("Auto Select") },
+  /* Translators: this is an option of "Paper Source" */
   { "InputSlot", "Default", N_("Printer Default") },
+  /* Translators: this is an option of "Paper Source" */
   { "InputSlot", "None", N_("Printer Default") },
+  /* Translators: this is an option of "Paper Source" */
   { "InputSlot", "PrinterDefault", N_("Printer Default") },
+  /* Translators: this is an option of "Paper Source" */
   { "InputSlot", "Unspecified", N_("Auto Select") },
 };
 
@@ -1780,12 +2331,13 @@ available_choices (ppd_file_t     *ppd,
        all_default = FALSE;
     }
 
-  if (all_default && !keep_if_only_one_option)
-    return 0;
-  
-  if (num_conflicts == option->num_choices)
-    return 0;
+  if ((all_default && !keep_if_only_one_option) ||
+      (num_conflicts == option->num_choices))
+    {
+      g_free (conflicts);
 
+      return 0;
+    }
 
   /* Some ppds don't have a "use printer default" option for
    * InputSlot. This means you always have to select a particular slot,
@@ -1824,7 +2376,6 @@ available_choices (ppd_file_t     *ppd,
   
   if (available)
     {
-      
       *available = g_new (ppd_choice_t *, option->num_choices - num_conflicts + add_auto);
 
       i = 0;
@@ -1837,6 +2388,8 @@ available_choices (ppd_file_t     *ppd,
       if (add_auto) 
        (*available)[i++] = NULL;
     }
+
+  g_free (conflicts);
   
   return option->num_choices - num_conflicts + add_auto;
 }
@@ -1902,19 +2455,25 @@ create_pickone_option (ppd_file_t   *ppd_file,
                  option = gtk_printer_option_new (gtk_name, label,
                                         GTK_PRINTER_OPTION_TYPE_PICKONE_STRING);
                  break;
+#ifdef PRINT_IGNORED_OPTIONS
                 case PPD_CUSTOM_POINTS: 
-                 g_warning ("Not Supported: PPD Custom Points Option");
+                 g_warning ("CUPS Backend: PPD Custom Points Option not supported");
                  break;
                 case PPD_CUSTOM_CURVE:
-                  g_warning ("Not Supported: PPD Custom Curve Option");
+                  g_warning ("CUPS Backend: PPD Custom Curve Option not supported");
                  break;
                 case PPD_CUSTOM_INVCURVE:      
-                 g_warning ("Not Supported: PPD Custom Inverse Curve Option");
+                 g_warning ("CUPS Backend: PPD Custom Inverse Curve Option not supported");
                  break;
+#endif
+                default: 
+                  break;
                }
            }
+#ifdef PRINT_IGNORED_OPTIONS
          else
-           g_warning ("Not Supported: PPD Custom Option has more than one parameter");
+           g_warning ("CUPS Backend: Multi-parameter PPD Custom Option not supported");
+#endif
        }
 #endif /* HAVE_CUPS_API_1_2 */
 
@@ -1942,7 +2501,7 @@ create_pickone_option (ppd_file_t   *ppd_file,
     }
 #ifdef PRINT_IGNORED_OPTIONS
   else
-    g_warning ("Ignoring pickone %s\n", ppd_option->text);
+    g_warning ("CUPS Backend: Ignoring pickone %s\n", ppd_option->text);
 #endif
   g_free (available);
 
@@ -1981,7 +2540,7 @@ create_boolean_option (ppd_file_t   *ppd_file,
     }
 #ifdef PRINT_IGNORED_OPTIONS
   else
-    g_warning ("Ignoring boolean %s\n", ppd_option->text);
+    g_warning ("CUPS Backend: Ignoring boolean %s\n", ppd_option->text);
 #endif
   g_free (available);
 
@@ -2044,9 +2603,10 @@ handle_option (GtkPrinterOptionSet *set,
     {
       option = create_boolean_option (ppd_file, ppd_option, name);
     }
+#ifdef PRINT_IGNORED_OPTIONS
   else
-    g_warning ("Ignored pickmany setting %s\n", ppd_option->text);
-  
+    g_warning ("CUPS Backend: Ignoring pickmany setting %s\n", ppd_option->text);
+#endif  
   
   if (option)
     {
@@ -2124,15 +2684,23 @@ cups_printer_get_options (GtkPrinter           *printer,
   char *n_up[] = {"1", "2", "4", "6", "9", "16" };
   char *prio[] = {"100", "80", "50", "30" };
   char *prio_display[] = {N_("Urgent"), N_("High"), N_("Medium"), N_("Low") };
-  char *cover[] = {"none", "classified", "confidential", "secret", "standard", "topsecret", "unclassified" };
-  char *cover_display[] = {N_("None"), N_("Classified"), N_("Confidential"), N_("Secret"), N_("Standard"), N_("Top Secret"), N_("Unclassified"),};
+  char *n_up_layout[] = { "lrtb", "lrbt", "rltb", "rlbt", "tblr", "tbrl", "btlr", "btrl" };
+  char *n_up_layout_display[] = { N_("Left to right, top to bottom"), N_("Left to right, bottom to top"), 
+                                  N_("Right to left, top to bottom"), N_("Right to left, bottom to top"), 
+                                  N_("Top to bottom, left to right"), N_("Top to bottom, right to left"), 
+                                  N_("Bottom to top, left to right"), N_("Bottom to top, right to left") };
+  char *name;
+  int num_opts;
+  cups_option_t *opts = NULL;
+  GtkPrintBackendCups *backend;
+  GtkTextDirection text_direction;
 
 
   set = gtk_printer_option_set_new ();
 
   /* Cups specific, non-ppd related settings */
 
-  option = gtk_printer_option_new ("gtk-n-up", "Pages Per Sheet", GTK_PRINTER_OPTION_TYPE_PICKONE);
+  option = gtk_printer_option_new ("gtk-n-up", _("Pages Per Sheet"), GTK_PRINTER_OPTION_TYPE_PICKONE);
   gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (n_up),
                                         n_up, n_up);
   gtk_printer_option_set (option, "1");
@@ -2140,10 +2708,30 @@ cups_printer_get_options (GtkPrinter           *printer,
   gtk_printer_option_set_add (set, option);
   g_object_unref (option);
 
+  if (cups_printer_get_capabilities (printer) & GTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT)
+    {
+      for (i = 0; i < G_N_ELEMENTS (n_up_layout_display); i++)
+        n_up_layout_display[i] = _(n_up_layout_display[i]);
+  
+      option = gtk_printer_option_new ("gtk-n-up-layout", _("Page Ordering"), GTK_PRINTER_OPTION_TYPE_PICKONE);
+      gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (n_up_layout),
+                                             n_up_layout, n_up_layout_display);
+
+      text_direction = gtk_widget_get_default_direction ();
+      if (text_direction == GTK_TEXT_DIR_LTR)
+        gtk_printer_option_set (option, "lrtb");
+      else
+        gtk_printer_option_set (option, "rltb");
+
+      set_option_from_settings (option, settings);
+      gtk_printer_option_set_add (set, option);
+      g_object_unref (option);
+    }
+
   for (i = 0; i < G_N_ELEMENTS(prio_display); i++)
     prio_display[i] = _(prio_display[i]);
   
-  option = gtk_printer_option_new ("gtk-job-prio", "Job Priority", GTK_PRINTER_OPTION_TYPE_PICKONE);
+  option = gtk_printer_option_new ("gtk-job-prio", _("Job Priority"), GTK_PRINTER_OPTION_TYPE_PICKONE);
   gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (prio),
                                         prio, prio_display);
   gtk_printer_option_set (option, "50");
@@ -2151,32 +2739,78 @@ cups_printer_get_options (GtkPrinter           *printer,
   gtk_printer_option_set_add (set, option);
   g_object_unref (option);
 
-  option = gtk_printer_option_new ("gtk-billing-info", "Billing Info", GTK_PRINTER_OPTION_TYPE_STRING);
+  option = gtk_printer_option_new ("gtk-billing-info", _("Billing Info"), GTK_PRINTER_OPTION_TYPE_STRING);
   gtk_printer_option_set (option, "");
   set_option_from_settings (option, settings);
   gtk_printer_option_set_add (set, option);
   g_object_unref (option);
 
-  for (i = 0; i < G_N_ELEMENTS(cover_display); i++)
-    cover_display[i] = _(cover_display[i]);
+  backend = GTK_PRINT_BACKEND_CUPS (gtk_printer_get_backend (printer));
+
+  if (backend != NULL)
+    {
+      char *cover_default[] = {"none", "classified", "confidential", "secret", "standard", "topsecret", "unclassified" };
+      char *cover_display_default[] = {N_("None"), N_("Classified"), N_("Confidential"), N_("Secret"), N_("Standard"), N_("Top Secret"), N_("Unclassified"),};
+      char **cover = NULL;
+      char **cover_display = NULL;
+      char **cover_display_translated = NULL;
+      gint num_of_covers = 0;
+      gpointer value;
+      gint j;
+
+      num_of_covers = backend->number_of_covers;
+      cover = g_new (char *, num_of_covers + 1);
+      cover[num_of_covers] = NULL;
+      cover_display = g_new (char *, num_of_covers + 1);
+      cover_display[num_of_covers] = NULL;
+      cover_display_translated = g_new (char *, num_of_covers + 1);
+      cover_display_translated[num_of_covers] = NULL;
+
+      for (i = 0; i < num_of_covers; i++)
+        {
+          cover[i] = g_strdup (backend->covers[i]);
+          value = NULL;
+          for (j = 0; j < G_N_ELEMENTS (cover_default); j++)
+            if (strcmp (cover_default[j], cover[i]) == 0)
+              {
+                value = cover_display_default[j];
+                break;
+              }
+          cover_display[i] = (value != NULL) ? g_strdup (value) : g_strdup (backend->covers[i]);
+        }
+
+      for (i = 0; i < num_of_covers; i++)
+        cover_display_translated[i] = _(cover_display[i]);
   
-  option = gtk_printer_option_new ("gtk-cover-before", "Before", GTK_PRINTER_OPTION_TYPE_PICKONE);
-  gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (cover),
-                                        cover, cover_display);
-  gtk_printer_option_set (option, "none");
-  set_option_from_settings (option, settings);
-  gtk_printer_option_set_add (set, option);
-  g_object_unref (option);
+      option = gtk_printer_option_new ("gtk-cover-before", _("Before"), GTK_PRINTER_OPTION_TYPE_PICKONE);
+      gtk_printer_option_choices_from_array (option, num_of_covers,
+                                        cover, cover_display_translated);
 
-  option = gtk_printer_option_new ("gtk-cover-after", "After", GTK_PRINTER_OPTION_TYPE_PICKONE);
-  gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (cover),
-                                        cover, cover_display);
-  gtk_printer_option_set (option, "none");
-  set_option_from_settings (option, settings);
-  gtk_printer_option_set_add (set, option);
-  g_object_unref (option);
+      if (backend->default_cover_before != NULL)
+        gtk_printer_option_set (option, backend->default_cover_before);
+      else
+        gtk_printer_option_set (option, "none");
+      set_option_from_settings (option, settings);
+      gtk_printer_option_set_add (set, option);
+      g_object_unref (option);
 
-  option = gtk_printer_option_new ("gtk-print-time", "Print at", GTK_PRINTER_OPTION_TYPE_PICKONE);
+      option = gtk_printer_option_new ("gtk-cover-after", _("After"), GTK_PRINTER_OPTION_TYPE_PICKONE);
+      gtk_printer_option_choices_from_array (option, num_of_covers,
+                                        cover, cover_display_translated);
+      if (backend->default_cover_after != NULL)
+        gtk_printer_option_set (option, backend->default_cover_after);
+      else
+        gtk_printer_option_set (option, "none");
+      set_option_from_settings (option, settings);
+      gtk_printer_option_set_add (set, option);
+      g_object_unref (option);
+
+      g_strfreev (cover);
+      g_strfreev (cover_display);
+      g_free (cover_display_translated);
+    }
+
+  option = gtk_printer_option_new ("gtk-print-time", _("Print at"), GTK_PRINTER_OPTION_TYPE_PICKONE);
   gtk_printer_option_choices_from_array (option, G_N_ELEMENTS (print_at),
                                         print_at, print_at);
   gtk_printer_option_set (option, "now");
@@ -2184,7 +2818,7 @@ cups_printer_get_options (GtkPrinter           *printer,
   gtk_printer_option_set_add (set, option);
   g_object_unref (option);
   
-  option = gtk_printer_option_new ("gtk-print-time-text", "Print at time", GTK_PRINTER_OPTION_TYPE_STRING);
+  option = gtk_printer_option_new ("gtk-print-time-text", _("Print at time"), GTK_PRINTER_OPTION_TYPE_STRING);
   gtk_printer_option_set (option, "");
   set_option_from_settings (option, settings);
   gtk_printer_option_set_add (set, option);
@@ -2210,10 +2844,12 @@ cups_printer_get_options (GtkPrinter           *printer,
       else
         {
           gchar *custom_name;
+         char width[G_ASCII_DTOSTR_BUF_SIZE];
+         char height[G_ASCII_DTOSTR_BUF_SIZE];
 
-         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));
+         g_ascii_formatd (width, sizeof (width), "%.2f", gtk_paper_size_get_width (paper_size, GTK_UNIT_POINTS));
+         g_ascii_formatd (height, sizeof (height), "%.2f", gtk_paper_size_get_height (paper_size, GTK_UNIT_POINTS));
+         custom_name = g_strdup_printf (_("Custom %sx%s"), width, height);
           strncpy (option->defchoice, custom_name, PPD_MAX_NAME);
           g_free (custom_name);
         }
@@ -2222,6 +2858,23 @@ cups_printer_get_options (GtkPrinter           *printer,
         handle_group (set, ppd_file, &ppd_file->groups[i], &ppd_file->groups[i], settings);
     }
 
+  /* Now honor the user set defaults for this printer */
+  num_opts = cups_get_user_options (gtk_printer_get_name (printer), 0, &opts);
+
+  for (i = 0; i < num_opts; i++)
+    {
+      if (STRING_IN_TABLE (opts[i].name, cups_option_blacklist))
+        continue;
+
+      name = get_option_name (opts[i].name);
+      option = gtk_printer_option_set_lookup (set, name);
+      if (option)
+        gtk_printer_option_set (option, opts[i].value);
+      g_free (name);
+    }
+
+  cupsFreeOptions (num_opts, opts);
+
   return set;
 }
 
@@ -2272,8 +2925,10 @@ set_conflicts_from_option (GtkPrinterOptionSet *set,
 
       if (option)
        gtk_printer_option_set_has_conflict (option, TRUE);
+#ifdef PRINT_IGNORED_OPTIONS
       else
-       g_warning ("conflict for option %s ignored", ppd_option->keyword);
+       g_warning ("CUPS Backend: Ignoring conflict for option %s", ppd_option->keyword);
+#endif
       
       g_free (name);
     }
@@ -2520,6 +3175,11 @@ set_option_from_settings (GtkPrinterOption *option,
       map_settings_to_option (option, all_map, G_N_ELEMENTS (all_map),
                              settings, GTK_PRINT_SETTINGS_NUMBER_UP, "number-up");
     }
+  else if (strcmp (option->name, "gtk-n-up-layout") == 0)
+    {
+      map_settings_to_option (option, all_map, G_N_ELEMENTS (all_map),
+                             settings, GTK_PRINT_SETTINGS_NUMBER_UP_LAYOUT, "number-up-layout");
+    }
   else if (strcmp (option->name, "gtk-billing-info") == 0)
     {
       cups_value = gtk_print_settings_get (settings, "cups-job-billing");
@@ -2600,6 +3260,9 @@ foreach_option_get_settings (GtkPrinterOption *option,
   else if (strcmp (option->name, "gtk-n-up") == 0)
     map_option_to_settings (value, all_map, G_N_ELEMENTS (all_map),
                            settings, GTK_PRINT_SETTINGS_NUMBER_UP, "number-up");
+  else if (strcmp (option->name, "gtk-n-up-layout") == 0)
+    map_option_to_settings (value, all_map, G_N_ELEMENTS (all_map),
+                           settings, GTK_PRINT_SETTINGS_NUMBER_UP_LAYOUT, "number-up-layout");
   else if (strcmp (option->name, "gtk-billing-info") == 0 && strlen (value) > 0)
     gtk_print_settings_set (settings, "cups-job-billing", value);
   else if (strcmp (option->name, "gtk-job-prio") == 0)
@@ -2704,9 +3367,13 @@ cups_printer_prepare_for_print (GtkPrinter       *printer,
     gtk_print_settings_set (settings, "cups-PageSize", ppd_paper_name);
   else
     {
-      char *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));
+      char width[G_ASCII_DTOSTR_BUF_SIZE];
+      char height[G_ASCII_DTOSTR_BUF_SIZE];
+      char *custom_name;
+
+      g_ascii_formatd (width, sizeof (width), "%.2f", gtk_paper_size_get_width (paper_size, GTK_UNIT_POINTS));
+      g_ascii_formatd (height, sizeof (height), "%.2f", gtk_paper_size_get_height (paper_size, GTK_UNIT_POINTS));
+      custom_name = g_strdup_printf (("Custom.%sx%s"), width, height);
       gtk_print_settings_set (settings, "cups-PageSize", custom_name);
       g_free (custom_name);
     }
@@ -2714,16 +3381,52 @@ cups_printer_prepare_for_print (GtkPrinter       *printer,
   print_job->rotate_to_orientation = TRUE;
 }
 
+static GtkPageSetup *
+create_page_setup (ppd_file_t *ppd_file,
+                  ppd_size_t *size)
+ {
+   char *display_name;
+   GtkPageSetup *page_setup;
+   GtkPaperSize *paper_size;
+   ppd_option_t *option;
+   ppd_choice_t *choice;
+
+  display_name = NULL;
+  option = ppdFindOption (ppd_file, "PageSize");
+  if (option)
+    {
+      choice = ppdFindChoice (option, size->name);
+      if (choice)
+       display_name = ppd_text_to_utf8 (ppd_file, choice->text);
+    }
+
+  if (display_name == NULL)
+    display_name = g_strdup (size->name);
+  
+  page_setup = gtk_page_setup_new ();
+  paper_size = gtk_paper_size_new_from_ppd (size->name,
+                                           display_name,
+                                           size->width,
+                                           size->length);
+  gtk_page_setup_set_paper_size (page_setup, paper_size);
+  gtk_paper_size_free (paper_size);
+  
+  gtk_page_setup_set_top_margin (page_setup, size->length - size->top, GTK_UNIT_POINTS);
+  gtk_page_setup_set_bottom_margin (page_setup, size->bottom, GTK_UNIT_POINTS);
+  gtk_page_setup_set_left_margin (page_setup, size->left, GTK_UNIT_POINTS);
+  gtk_page_setup_set_right_margin (page_setup, size->width - size->right, GTK_UNIT_POINTS);
+  
+  g_free (display_name);
+
+  return page_setup;
+}
+
 static GList *
 cups_printer_list_papers (GtkPrinter *printer)
 {
   ppd_file_t *ppd_file;
   ppd_size_t *size;
-  char *display_name;
   GtkPageSetup *page_setup;
-  GtkPaperSize *paper_size;
-  ppd_option_t *option;
-  ppd_choice_t *choice;
   GList *l;
   int i;
 
@@ -2735,33 +3438,9 @@ cups_printer_list_papers (GtkPrinter *printer)
   
   for (i = 0; i < ppd_file->num_sizes; i++)
     {
-      size = &ppd_file->sizes[i];
+      size = &ppd_file->sizes[i];      
 
-      display_name = NULL;
-      option = ppdFindOption (ppd_file, "PageSize");
-      if (option)
-       {
-         choice = ppdFindChoice (option, size->name);
-         if (choice)
-           display_name = ppd_text_to_utf8 (ppd_file, choice->text);
-       }
-      if (display_name == NULL)
-       display_name = g_strdup (size->name);
-
-      page_setup = gtk_page_setup_new ();
-      paper_size = gtk_paper_size_new_from_ppd (size->name,
-                                               display_name,
-                                               size->width,
-                                               size->length);
-      gtk_page_setup_set_paper_size (page_setup, paper_size);
-      gtk_paper_size_free (paper_size);
-
-      gtk_page_setup_set_top_margin (page_setup, size->length - size->top, GTK_UNIT_POINTS);
-      gtk_page_setup_set_bottom_margin (page_setup, size->bottom, GTK_UNIT_POINTS);
-      gtk_page_setup_set_left_margin (page_setup, size->left, GTK_UNIT_POINTS);
-      gtk_page_setup_set_right_margin (page_setup, size->width - size->right, GTK_UNIT_POINTS);
-       
-      g_free (display_name);
+      page_setup = create_page_setup (ppd_file, size);
 
       l = g_list_prepend (l, page_setup);
     }
@@ -2769,6 +3448,24 @@ cups_printer_list_papers (GtkPrinter *printer)
   return g_list_reverse (l);
 }
 
+static GtkPageSetup *
+cups_printer_get_default_page_size (GtkPrinter *printer)
+{
+  ppd_file_t *ppd_file;
+  ppd_size_t *size;
+  ppd_option_t *option;
+
+
+  ppd_file = gtk_printer_cups_get_ppd (GTK_PRINTER_CUPS (printer));
+  if (ppd_file == NULL)
+    return NULL;
+
+  option = ppdFindOption (ppd_file, "PageSize");
+  size = ppdPageSize (ppd_file, option->defchoice); 
+
+  return create_page_setup (ppd_file, size);
+}
+
 static void
 cups_printer_get_hard_margins (GtkPrinter *printer,
                               gdouble    *top,
@@ -2794,5 +3491,9 @@ cups_printer_get_capabilities (GtkPrinter *printer)
   return
     GTK_PRINT_CAPABILITY_COPIES |
     GTK_PRINT_CAPABILITY_COLLATE |
-    GTK_PRINT_CAPABILITY_REVERSE;
+    GTK_PRINT_CAPABILITY_REVERSE |
+#if (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR >= 1 && CUPS_VERSION_PATCH >= 15) || (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR > 1) || CUPS_VERSION_MAJOR > 1
+    GTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT |
+#endif
+    GTK_PRINT_CAPABILITY_NUMBER_UP;
 }