]> 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 3c5e1844a27b6e22cb499aa9f8883cb6eb9cf6c6..96dd2daf3fbb0ee607aa4dadd53049918c706450 100644 (file)
@@ -19,7 +19,7 @@
  * Boston, MA 02111-1307, USA.
  */
 
-#include <config.h>
+#include "config.h"
 #include <ctype.h>
 #include <unistd.h>
 #include <sys/types.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;
@@ -108,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;
@@ -117,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,
@@ -136,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,
@@ -255,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;
 }
@@ -305,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);
 
@@ -414,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));   
@@ -425,12 +453,30 @@ gtk_print_backend_cups_print_stream (GtkPrintBackend         *print_backend,
                                   GTK_CUPS_POST,
                                   IPP_PRINT_JOB,
                                  data_io,
-                                 NULL,
+                                 NULL, 
                                  cups_printer->device_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_URI, "printer-uri",
-                                   NULL, cups_printer->printer_uri);
+                                   NULL, printer_absolute_uri);
 
   title = gtk_print_job_get_title (job);
   if (title)
@@ -461,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
@@ -476,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);
 }
@@ -494,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);
 }
 
@@ -756,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,
@@ -1016,6 +1084,52 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
       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...
        */
@@ -1042,10 +1156,90 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
           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,
@@ -1142,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);
@@ -1167,7 +1364,73 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
       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),
@@ -1210,8 +1473,12 @@ cups_request_printer_list (GtkPrintBackendCups *cups_backend)
       "printer-location",
       "printer-info",
       "printer-state-message",
+      "printer-state-reasons",
       "printer-state",
-      "queued-job-count"
+      "queued-job-count",
+      "printer-is-accepting-jobs",
+      "job-sheets-supported",
+      "job-sheets-default"
     };
  
   if (cups_backend->list_printers_pending ||
@@ -1310,6 +1577,8 @@ 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);
@@ -1558,6 +1827,27 @@ cups_get_user_options (const char     *printer_name,
   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,
                                 GtkCupsResult       *result,
@@ -1566,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)
@@ -1578,27 +1870,35 @@ 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 */  
@@ -1607,7 +1907,7 @@ cups_request_default_printer (GtkPrintBackendCups *print_backend)
     {
        print_backend->default_printer = name;
        print_backend->got_default_printer = TRUE;
-       return;
+       return FALSE;
     }
 
   request = gtk_cups_request_new (NULL,
@@ -1622,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
@@ -1707,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") },
 };
 
@@ -2376,18 +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");
@@ -2395,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");
@@ -2406,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-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);
+  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");
@@ -2439,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);
@@ -2796,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");
@@ -2876,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)
@@ -2994,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;
 
@@ -3015,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);
     }
@@ -3049,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,
@@ -3075,5 +3492,8 @@ cups_printer_get_capabilities (GtkPrinter *printer)
     GTK_PRINT_CAPABILITY_COPIES |
     GTK_PRINT_CAPABILITY_COLLATE |
     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;
 }