]> 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 e45decfd5e68eb06b68724e602931e2e1256adc4..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,
@@ -138,7 +144,7 @@ static void                 cups_printer_prepare_for_print         (GtkPrinter
 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,
@@ -307,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);
 
@@ -416,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));   
@@ -427,12 +453,30 @@ gtk_print_backend_cups_print_stream (GtkPrintBackend         *print_backend,
                                   GTK_CUPS_POST,
                                   IPP_PRINT_JOB,
                                  data_io,
-                                 cups_printer->hostname
+                                 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)
@@ -463,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
@@ -478,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);
 }
@@ -496,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);
 }
 
@@ -758,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,
@@ -1022,6 +1088,7 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
       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;
@@ -1045,9 +1112,13 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
         {
           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'."),
@@ -1057,6 +1128,8 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
           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...
        */
@@ -1091,6 +1164,12 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
               {
                 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)
@@ -1130,6 +1209,37 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
           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,
@@ -1226,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);
@@ -1252,6 +1365,22 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
       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))
         {
@@ -1281,10 +1410,14 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
         }
 
       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);
 
@@ -1294,6 +1427,8 @@ cups_request_printer_list_cb (GtkPrintBackendCups *cups_backend,
         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");
 
@@ -1340,7 +1475,10 @@ cups_request_printer_list (GtkPrintBackendCups *cups_backend)
       "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 ||
@@ -1689,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,
@@ -1697,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)
@@ -1709,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 */  
@@ -1738,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,
@@ -1753,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
@@ -1838,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") },
 };
 
@@ -2507,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");
@@ -2526,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");
@@ -2537,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");
@@ -2570,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);
@@ -2927,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");
@@ -3007,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)
@@ -3236,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;
 }