[gtk+] Add ability to print in number-up mode for file backend and lpr backend



commit 91190ce281b562d0f37d8181d9766e09e3c57558
Author: Marek Kasik <mkasik redhat com>
Date:   Wed May 13 18:28:42 2009 +0200

    Add ability to print in number-up mode for file backend and lpr backend
    
    GtkPrintOperation is now able to render multiple pages per sheet by its
    own. The most important changes are in these functions:
      * increment_page_sequence
      * prepare_data
      * common_render_page
      * print_pages_idle
    Patch also changes set of choices for 2 pages per sheet mode when
    landscape orientation is used to "Top to bottom" and "Bottom to top".
---
 gtk/gtkprintjob.c                                |    2 +
 gtk/gtkprintjob.h                                |    2 +
 gtk/gtkprintoperation-private.h                  |    5 +
 gtk/gtkprintoperation-unix.c                     |   24 +-
 gtk/gtkprintoperation-win32.c                    |    4 +
 gtk/gtkprintoperation.c                          |  415 ++++++++++++++++++----
 gtk/gtkprintunixdialog.c                         |   72 ++++-
 modules/printbackends/cups/gtkcupsutils.c        |    3 +-
 modules/printbackends/file/gtkprintbackendfile.c |    6 +
 modules/printbackends/lpr/gtkprintbackendlpr.c   |   13 +-
 10 files changed, 463 insertions(+), 83 deletions(-)

diff --git a/gtk/gtkprintjob.c b/gtk/gtkprintjob.c
index c59a27a..51d41d1 100644
--- a/gtk/gtkprintjob.c
+++ b/gtk/gtkprintjob.c
@@ -205,6 +205,8 @@ gtk_print_job_init (GtkPrintJob *job)
   job->scale = 1.0;
   job->page_set = GTK_PAGE_SET_ALL;
   job->rotate_to_orientation = FALSE;
+  job->number_up = 1;
+  job->number_up_layout = GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM;
 }
 
 
diff --git a/gtk/gtkprintjob.h b/gtk/gtkprintjob.h
index 71ddfdc..fd82184 100644
--- a/gtk/gtkprintjob.h
+++ b/gtk/gtkprintjob.h
@@ -66,6 +66,8 @@ struct _GtkPrintJob
   guint GSEAL (rotate_to_orientation) : 1;
   guint GSEAL (collate)               : 1;
   guint GSEAL (reverse)               : 1;
+  guint GSEAL (number_up);
+  GtkNumberUpLayout GSEAL (number_up_layout);
 };
 
 struct _GtkPrintJobClass
diff --git a/gtk/gtkprintoperation-private.h b/gtk/gtkprintoperation-private.h
index 0e5f606..718f16d 100644
--- a/gtk/gtkprintoperation-private.h
+++ b/gtk/gtkprintoperation-private.h
@@ -43,6 +43,8 @@ struct _GtkPrintOperationPrivate
   GtkPrintSettings *print_settings;
   gchar *job_name;
   gint nr_of_pages;
+  gint nr_of_pages_to_print;
+  gint page_position;
   gint current_page;
   GtkUnit unit;
   gchar *export_filename;
@@ -70,6 +72,9 @@ struct _GtkPrintOperationPrivate
   guint manual_orientation : 1;
   double manual_scale;
   GtkPageSet manual_page_set;
+  guint manual_number_up;
+  GtkNumberUpLayout manual_number_up_layout;
+
   GtkWidget *custom_widget;
   gchar *custom_tab_label;
   
diff --git a/gtk/gtkprintoperation-unix.c b/gtk/gtkprintoperation-unix.c
index bec565c..ad8bc12 100644
--- a/gtk/gtkprintoperation-unix.c
+++ b/gtk/gtkprintoperation-unix.c
@@ -87,10 +87,14 @@ unix_start_page (GtkPrintOperation *op,
   
   type = cairo_surface_get_type (op_unix->surface);
 
-  if (type == CAIRO_SURFACE_TYPE_PS)
-    cairo_ps_surface_set_size (op_unix->surface, w, h);
-  else if (type == CAIRO_SURFACE_TYPE_PDF)
-    cairo_pdf_surface_set_size (op_unix->surface, w, h);
+  if ((op->priv->manual_number_up < 2) ||
+      (op->priv->page_position % op->priv->manual_number_up == 0))
+    {
+      if (type == CAIRO_SURFACE_TYPE_PS)
+        cairo_ps_surface_set_size (op_unix->surface, w, h);
+      else if (type == CAIRO_SURFACE_TYPE_PDF)
+        cairo_pdf_surface_set_size (op_unix->surface, w, h);
+    }
 }
 
 static void
@@ -100,7 +104,11 @@ unix_end_page (GtkPrintOperation *op,
   cairo_t *cr;
 
   cr = gtk_print_context_get_cairo_context (print_context);
-  cairo_show_page (cr);
+
+  if ((op->priv->manual_number_up < 2) ||
+      ((op->priv->page_position + 1) % op->priv->manual_number_up == 0) ||
+      (op->priv->page_position == op->priv->nr_of_pages_to_print - 1))
+    cairo_show_page (cr);
 }
 
 static void
@@ -399,7 +407,9 @@ get_print_dialog (GtkPrintOperation *op,
 						 GTK_PRINT_CAPABILITY_COLLATE |
 						 GTK_PRINT_CAPABILITY_REVERSE |
 						 GTK_PRINT_CAPABILITY_SCALE |
-						 GTK_PRINT_CAPABILITY_PREVIEW);
+						 GTK_PRINT_CAPABILITY_PREVIEW |
+						 GTK_PRINT_CAPABILITY_NUMBER_UP |
+						 GTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT);
 
   if (priv->print_settings)
     gtk_print_unix_dialog_set_settings (GTK_PRINT_UNIX_DIALOG (pd),
@@ -523,6 +533,8 @@ finish_print (PrintResponseData *rdata,
           priv->manual_page_set = job->page_set;
           priv->manual_scale = job->scale;
           priv->manual_orientation = job->rotate_to_orientation;
+          priv->manual_number_up = job->number_up;
+          priv->manual_number_up_layout = job->number_up_layout;
         }
     } 
  out:
diff --git a/gtk/gtkprintoperation-win32.c b/gtk/gtkprintoperation-win32.c
index 7a9b559..3da48cb 100644
--- a/gtk/gtkprintoperation-win32.c
+++ b/gtk/gtkprintoperation-win32.c
@@ -1598,6 +1598,8 @@ gtk_print_operation_run_without_dialog (GtkPrintOperation *op,
   op->priv->manual_orientation = FALSE;
   op->priv->manual_scale = 1.0;
   op->priv->manual_page_set = GTK_PAGE_SET_ALL;
+  op->priv->manual_number_up = 1;
+  op->priv->manual_number_up_layout = GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM;
 
   op->priv->start_page = win32_start_page;
   op->priv->end_page = win32_end_page;
@@ -1821,6 +1823,8 @@ gtk_print_operation_run_with_dialog (GtkPrintOperation *op,
       op->priv->manual_orientation = FALSE;
       op->priv->manual_scale = 1.0;
       op->priv->manual_page_set = GTK_PAGE_SET_ALL;
+      op->priv->manual_number_up = 1;
+      op->priv->manual_number_up_layout = GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM;
     }
 
   op->priv->start_page = win32_start_page;
diff --git a/gtk/gtkprintoperation.c b/gtk/gtkprintoperation.c
index 4240546..bc0a5e5 100644
--- a/gtk/gtkprintoperation.c
+++ b/gtk/gtkprintoperation.c
@@ -22,6 +22,7 @@
 
 #include <errno.h>
 #include <stdlib.h>       
+#include <math.h>
 
 #include <string.h>
 #include "gtkprintoperation-private.h"
@@ -154,6 +155,8 @@ gtk_print_operation_init (GtkPrintOperation *operation)
   priv->default_page_setup = NULL;
   priv->print_settings = NULL;
   priv->nr_of_pages = -1;
+  priv->nr_of_pages_to_print = -1;
+  priv->page_position = -1;
   priv->current_page = -1;
   priv->use_full_page = FALSE;
   priv->show_progress = FALSE;
@@ -1832,7 +1835,11 @@ pdf_end_page (GtkPrintOperation *op,
   cairo_t *cr;
 
   cr = gtk_print_context_get_cairo_context (print_context);
-  cairo_show_page (cr);
+
+  if ((op->priv->manual_number_up < 2) ||
+      ((op->priv->page_position + 1) % op->priv->manual_number_up == 0) ||
+      (op->priv->page_position == op->priv->nr_of_pages_to_print - 1))
+    cairo_show_page (cr);
 }
 
 static void
@@ -1906,6 +1913,8 @@ run_pdf (GtkPrintOperation  *op,
   priv->manual_page_set = GTK_PAGE_SET_ALL;
   priv->manual_scale = 1.0;
   priv->manual_orientation = TRUE;
+  priv->manual_number_up = 1;
+  priv->manual_number_up_layout = GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM;
   
   *do_print = TRUE;
   
@@ -1927,7 +1936,12 @@ typedef struct
   GtkPageRange *ranges;
   GtkPageRange one_range;
 
-  gint page, start, end, inc;
+  gint page;
+  gint sheet;
+  gint first_position, last_position;
+  gint first_sheet;
+  gint num_of_sheets;
+  gint *pages;
 
   GtkWidget *progress;
  
@@ -1936,25 +1950,6 @@ typedef struct
 } PrintPagesData;
 
 static void
-find_range (PrintPagesData *data)
-{
-  GtkPageRange *range;
-
-  range = &data->ranges[data->range];
-
-  if (data->inc < 0)
-    {
-      data->start = range->end;
-      data->end = range->start - 1;
-    }
-  else
-    {
-      data->start = range->start;
-      data->end = range->end + 1;
-    }
-}
-
-static void
 clamp_page_ranges (PrintPagesData *data)
 {
   GtkPrintOperationPrivate *priv; 
@@ -1998,26 +1993,78 @@ static gboolean
 increment_page_sequence (PrintPagesData *data)
 {
   GtkPrintOperationPrivate *priv = data->op->priv;
+  gint inc;
 
-  do {
-    data->page += data->inc;
-    if (data->page == data->end)
-      {
-	data->range += data->inc;
-	if (data->range == -1 || data->range == data->num_ranges)
-	  {
-	    data->uncollated++;
-	    if (data->uncollated == data->uncollated_copies)
-	      return FALSE;
-
-	    data->range = data->inc < 0 ? data->num_ranges - 1 : 0;
-	  }
-	find_range (data);
-	data->page = data->start;
-      }
-  }
-  while ((priv->manual_page_set == GTK_PAGE_SET_EVEN && data->page % 2 == 0) ||
-	 (priv->manual_page_set == GTK_PAGE_SET_ODD && data->page % 2 == 1));
+  /* check whether we reached last position */
+  if (priv->page_position == data->last_position &&
+      !(data->collated_copies > 1 && data->collated < (data->collated_copies - 1)))
+    {
+      if (data->uncollated_copies > 1 && data->uncollated < (data->uncollated_copies - 1))
+        {
+          priv->page_position = data->first_position;
+          data->sheet = data->first_sheet;
+          data->uncollated++;
+        }
+      else
+        return FALSE;
+    }
+  else
+    {
+      if (priv->manual_reverse)
+        inc = -1;
+      else
+        inc = 1;
+
+      /* changing sheet */
+      if ((priv->page_position + 1) % priv->manual_number_up == 0 ||
+          priv->page_position == data->last_position ||
+          priv->page_position == priv->nr_of_pages_to_print - 1)
+        {
+          /* check whether to print the same sheet again */
+          if (data->collated_copies > 1)
+            {
+              if (data->collated < (data->collated_copies - 1))
+                {
+                  data->collated++;
+                  data->total++;
+                  priv->page_position = data->sheet * priv->manual_number_up;
+
+                  if (priv->page_position < 0 ||
+                      priv->page_position >= priv->nr_of_pages_to_print ||
+                      data->sheet < 0 ||
+                      data->sheet >= data->num_of_sheets)
+                    return FALSE;
+                  else
+                    data->page = data->pages[priv->page_position];
+
+                  return TRUE;
+                }
+              else
+                data->collated = 0;
+            }
+
+          if (priv->manual_page_set == GTK_PAGE_SET_ODD ||
+              priv->manual_page_set == GTK_PAGE_SET_EVEN)
+            data->sheet += 2 * inc;
+          else
+            data->sheet += inc;
+
+          priv->page_position = data->sheet * priv->manual_number_up;
+        }
+      else
+        priv->page_position += 1;
+    }
+
+  /* general check */
+  if (priv->page_position < 0 ||
+      priv->page_position >= priv->nr_of_pages_to_print ||
+      data->sheet < 0 ||
+      data->sheet >= data->num_of_sheets)
+    return FALSE;
+  else
+    data->page = data->pages[priv->page_position];
+
+  data->total++;
 
   return TRUE;
 }
@@ -2052,6 +2099,7 @@ print_pages_idle_done (gpointer user_data)
 		   GTK_PRINT_OPERATION_RESULT_APPLY);
   
   g_object_unref (data->op);
+  g_free (data->pages);
   g_free (data);
 }
 
@@ -2073,7 +2121,7 @@ update_progress (PrintPagesData *data)
 	    text = g_strdup (_("Preparing"));
 	}
       else if (priv->status == GTK_PRINT_STATUS_GENERATING_DATA)
-	text = g_strdup_printf (_("Printing %d"), data->total);
+	text = g_strdup_printf (_("Printing %d"), data->total - 1);
       
       if (text)
 	{
@@ -2164,16 +2212,193 @@ common_render_page (GtkPrintOperation *op,
   cr = gtk_print_context_get_cairo_context (print_context);
   
   cairo_save (cr);
-  if (priv->manual_scale != 1.0)
+  if (priv->manual_scale != 1.0 && priv->manual_number_up <= 1)
     cairo_scale (cr,
 		 priv->manual_scale,
 		 priv->manual_scale);
   
   if (priv->manual_orientation)
     _gtk_print_context_rotate_according_to_orientation (print_context);
-  
-  if (!priv->use_full_page)
-    _gtk_print_context_translate_into_margin (print_context);
+
+  if (priv->manual_number_up > 1)
+    {
+      GtkPageOrientation  orientation;
+      GtkPageSetup       *page_setup;
+      gdouble             paper_width, paper_height;
+      gdouble             page_width, page_height;
+      gdouble             context_width, context_height;
+      gdouble             bottom_margin, top_margin, left_margin, right_margin;
+      gdouble             x_step, y_step;
+      gdouble             x_scale, y_scale, scale;
+      gdouble             horizontal_offset = 0.0, vertical_offset = 0.0;
+      gint                columns, rows, x, y, tmp_length;
+
+      page_setup = gtk_print_context_get_page_setup (print_context);
+      orientation = gtk_page_setup_get_orientation (page_setup);
+
+      top_margin = gtk_page_setup_get_top_margin (page_setup, GTK_UNIT_POINTS);
+      bottom_margin = gtk_page_setup_get_bottom_margin (page_setup, GTK_UNIT_POINTS);
+      left_margin = gtk_page_setup_get_left_margin (page_setup, GTK_UNIT_POINTS);
+      right_margin = gtk_page_setup_get_right_margin (page_setup, GTK_UNIT_POINTS);
+
+      paper_width = gtk_page_setup_get_paper_width (page_setup, GTK_UNIT_POINTS);
+      paper_height = gtk_page_setup_get_paper_height (page_setup, GTK_UNIT_POINTS);
+
+      context_width = gtk_print_context_get_width (print_context);
+      context_height = gtk_print_context_get_height (print_context);
+
+      if (orientation == GTK_PAGE_ORIENTATION_PORTRAIT ||
+          orientation == GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT)
+        {
+          page_width = paper_width - (left_margin + right_margin);
+          page_height = paper_height - (top_margin + bottom_margin);
+        }
+      else
+        {
+          page_width = paper_width - (top_margin + bottom_margin);
+          page_height = paper_height - (left_margin + right_margin);
+        }
+
+      if (orientation == GTK_PAGE_ORIENTATION_PORTRAIT ||
+          orientation == GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT)
+        cairo_translate (cr, left_margin, top_margin);
+      else
+        cairo_translate (cr, top_margin, left_margin);
+
+      switch (priv->manual_number_up)
+        {
+          default:
+            columns = 1;
+            rows = 1;
+            break;
+          case 2:
+            columns = 2;
+            rows = 1;
+            break;
+          case 4:
+            columns = 2;
+            rows = 2;
+            break;
+          case 6:
+            columns = 3;
+            rows = 2;
+            break;
+          case 9:
+            columns = 3;
+            rows = 3;
+            break;
+          case 16:
+            columns = 4;
+            rows = 4;
+            break;
+        }
+
+      if (orientation == GTK_PAGE_ORIENTATION_LANDSCAPE ||
+          orientation == GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE)
+        {
+          tmp_length = columns;
+          columns = rows;
+          rows = tmp_length;
+        }
+
+      switch (priv->manual_number_up_layout)
+        {
+          case GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM:
+            x = priv->page_position % columns;
+            y = (priv->page_position / columns) % rows;
+            break;
+          case GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_BOTTOM_TO_TOP:
+            x = priv->page_position % columns;
+            y = rows - 1 - (priv->page_position / columns) % rows;
+            break;
+          case GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_TOP_TO_BOTTOM:
+            x = columns - 1 - priv->page_position % columns;
+            y = (priv->page_position / columns) % rows;
+            break;
+          case GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_BOTTOM_TO_TOP:
+            x = columns - 1 - priv->page_position % columns;
+            y = rows - 1 - (priv->page_position / columns) % rows;
+            break;
+          case GTK_NUMBER_UP_LAYOUT_TOP_TO_BOTTOM_LEFT_TO_RIGHT:
+            x = (priv->page_position / rows) % columns;
+            y = priv->page_position % rows;
+            break;
+          case GTK_NUMBER_UP_LAYOUT_TOP_TO_BOTTOM_RIGHT_TO_LEFT:
+            x = columns - 1 - (priv->page_position / rows) % columns;
+            y = priv->page_position % rows;
+            break;
+          case GTK_NUMBER_UP_LAYOUT_BOTTOM_TO_TOP_LEFT_TO_RIGHT:
+            x = (priv->page_position / rows) % columns;
+            y = rows - 1 - priv->page_position % rows;
+            break;
+          case GTK_NUMBER_UP_LAYOUT_BOTTOM_TO_TOP_RIGHT_TO_LEFT:
+            x = columns - 1 - (priv->page_position / rows) % columns;
+            y = rows - 1 - priv->page_position % rows;
+            break;
+        }
+
+      if (priv->manual_number_up == 4 || priv->manual_number_up == 9 || priv->manual_number_up == 16)
+        {
+          x_scale = page_width / (columns * paper_width);
+          y_scale = page_height / (rows * paper_height);
+
+          scale = x_scale < y_scale ? x_scale : y_scale;
+
+          x_step = paper_width * (x_scale / scale);
+          y_step = paper_height * (y_scale / scale);
+
+          if ((left_margin + right_margin) > 0)
+            {
+              horizontal_offset = left_margin * (x_step - context_width) / (left_margin + right_margin);
+              vertical_offset = top_margin * (y_step - context_height) / (top_margin + bottom_margin);
+            }
+          else
+            {
+              horizontal_offset = (x_step - context_width) / 2.0;
+              vertical_offset = (y_step - context_height) / 2.0;
+            }
+
+          cairo_scale (cr, scale, scale);
+
+          cairo_translate (cr,
+                           x * x_step + horizontal_offset,
+                           y * y_step + vertical_offset);
+
+          if (priv->manual_scale != 1.0)
+            cairo_scale (cr, priv->manual_scale, priv->manual_scale);
+        }
+
+      if (priv->manual_number_up == 2 || priv->manual_number_up == 6)
+        {
+          x_scale = page_height / (columns * paper_width);
+          y_scale = page_width / (rows * paper_height);
+
+          scale = x_scale < y_scale ? x_scale : y_scale;
+
+          horizontal_offset = (paper_width * (x_scale / scale) - paper_width) / 2.0 * columns;
+          vertical_offset = (paper_height * (y_scale / scale) - paper_height) / 2.0 * rows;
+
+          if (!priv->use_full_page)
+            {
+              horizontal_offset -= right_margin;
+              vertical_offset += top_margin;
+            }
+
+          cairo_scale (cr, scale, scale);
+
+          cairo_translate (cr,
+                           y * paper_height + vertical_offset,
+                           (columns - x) * paper_width + horizontal_offset);
+
+          if (priv->manual_scale != 1.0)
+            cairo_scale (cr, priv->manual_scale, priv->manual_scale);
+
+          cairo_rotate (cr, - M_PI / 2);
+        }
+    }
+  else
+    if (!priv->use_full_page)
+      _gtk_print_context_translate_into_margin (print_context);
   
   priv->page_drawing_state = GTK_PAGE_DRAWING_STATE_DRAWING;
 
@@ -2189,7 +2414,7 @@ prepare_data (PrintPagesData *data)
 {
   GtkPrintOperationPrivate *priv;
   GtkPageSetup             *page_setup;
-  gint                      i;
+  gint                      i, j, counter;
 
   priv = data->op->priv;
 
@@ -2267,21 +2492,85 @@ prepare_data (PrintPagesData *data)
       return;
     }
 
+  priv->nr_of_pages_to_print = 0;
+  for (i = 0; i < data->num_ranges; i++)
+    priv->nr_of_pages_to_print += data->ranges[i].end - data->ranges[i].start + 1;
+
+  data->pages = g_new (gint, priv->nr_of_pages_to_print);
+  counter = 0;
+  for (i = 0; i < data->num_ranges; i++)
+    for (j = data->ranges[i].start; j <= data->ranges[i].end; j++)
+      {
+        data->pages[counter] = j;
+        counter++;
+      }
+
+  data->total = 0;
+  data->collated = 0;
+  data->uncollated = 0;
+
+  if (priv->nr_of_pages_to_print % priv->manual_number_up == 0)
+    data->num_of_sheets = priv->nr_of_pages_to_print / priv->manual_number_up;
+  else
+    data->num_of_sheets = priv->nr_of_pages_to_print / priv->manual_number_up + 1;
+
   if (priv->manual_reverse)
     {
-      data->range = data->num_ranges - 1;
-      data->inc = -1;      
+      /* data->sheet is 0-based */
+      if (priv->manual_page_set == GTK_PAGE_SET_ODD)
+        data->sheet = (data->num_of_sheets - 1) - (data->num_of_sheets - 1) % 2;
+      else if (priv->manual_page_set == GTK_PAGE_SET_EVEN)
+        data->sheet = (data->num_of_sheets - 1) - (1 - (data->num_of_sheets - 1) % 2);
+      else
+        data->sheet = data->num_of_sheets - 1;
     }
   else
     {
-      data->range = 0;
-      data->inc = 1;      
+      /* data->sheet is 0-based */
+      if (priv->manual_page_set == GTK_PAGE_SET_ODD)
+        data->sheet = 0;
+      else if (priv->manual_page_set == GTK_PAGE_SET_EVEN)
+        {
+          if (data->num_of_sheets > 1)
+            data->sheet = 1;
+          else
+            data->sheet = -1;
+        }
+      else
+        data->sheet = 0;
+    }
+
+  priv->page_position = data->sheet * priv->manual_number_up;
+
+  if (priv->page_position < 0 || priv->page_position >= priv->nr_of_pages_to_print)
+    {
+      priv->cancelled = TRUE;
+      return;
+    }
+
+  data->page = data->pages[priv->page_position];
+  data->first_position = priv->page_position;
+  data->first_sheet = data->sheet;
+
+  if (priv->manual_reverse)
+    {
+      if (priv->manual_page_set == GTK_PAGE_SET_ODD)
+        data->last_position = MIN (priv->manual_number_up - 1, priv->nr_of_pages_to_print - 1);
+      else if (priv->manual_page_set == GTK_PAGE_SET_EVEN)
+        data->last_position = MIN (2 * priv->manual_number_up - 1, priv->nr_of_pages_to_print - 1);
+      else
+        data->last_position = MIN (priv->manual_number_up - 1, priv->nr_of_pages_to_print - 1);
+    }
+  else
+    {
+      if (priv->manual_page_set == GTK_PAGE_SET_ODD)
+        data->last_position = MIN (((data->num_of_sheets - 1) - ((data->num_of_sheets - 1) % 2)) * priv->manual_number_up - 1, priv->nr_of_pages_to_print - 1);
+      else if (priv->manual_page_set == GTK_PAGE_SET_EVEN)
+        data->last_position = MIN (((data->num_of_sheets - 1) - (1 - (data->num_of_sheets - 1) % 2)) * priv->manual_number_up - 1, priv->nr_of_pages_to_print - 1);
+      else
+        data->last_position = priv->nr_of_pages_to_print - 1;
     }
-  find_range (data);
 
-  /* go back one page, since we preincrement below */
-  data->page = data->start - data->inc;
-  data->collated = data->collated_copies - 1;
 
   _gtk_print_operation_set_status (data->op, 
                                    GTK_PRINT_STATUS_GENERATING_DATA, 
@@ -2306,19 +2595,6 @@ print_pages_idle (gpointer user_data)
           goto out;
         }
 
-      data->total++;
-      data->collated++;
-      if (data->collated == data->collated_copies)
-        {
-          data->collated = 0;
-          if (!increment_page_sequence (data))
-            {
-              done = TRUE;
-
-              goto out;
-            }
-        }
-
       if (data->is_preview && !priv->cancelled)
         {
           done = TRUE;
@@ -2329,6 +2605,9 @@ print_pages_idle (gpointer user_data)
 
       common_render_page (data->op, data->page);
 
+      if (!increment_page_sequence (data))
+        done = TRUE;
+
  out:
 
       if (priv->cancelled)
@@ -2468,6 +2747,8 @@ print_pages (GtkPrintOperation       *op,
       priv->manual_page_set = GTK_PAGE_SET_ALL;
       priv->manual_scale = 1.0;
       priv->manual_orientation = TRUE;
+      priv->manual_number_up = 1;
+      priv->manual_number_up_layout = GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM;
     }
   
   priv->print_pages_idle_id = gdk_threads_add_idle_full (G_PRIORITY_DEFAULT_IDLE + 10,
diff --git a/gtk/gtkprintunixdialog.c b/gtk/gtkprintunixdialog.c
index fbb2d40..92c93e9 100644
--- a/gtk/gtkprintunixdialog.c
+++ b/gtk/gtkprintunixdialog.c
@@ -2428,6 +2428,7 @@ update_number_up_layout (GtkPrintUnixDialog *dialog)
   GtkNumberUpLayout          layout;
   GtkPrinterOption          *option;
   GtkPrinterOption          *old_option;
+  GtkPageOrientation         page_orientation;
 
   set = priv->options;
 
@@ -2438,17 +2439,64 @@ update_number_up_layout (GtkPrintUnixDialog *dialog)
       if (priv->number_up_layout_n_option == NULL)
         {
           priv->number_up_layout_n_option = gtk_printer_option_set_lookup (set, "gtk-n-up-layout");
+          if (priv->number_up_layout_n_option == NULL)
+            {
+              char *n_up_layout[] = { "lrtb", "lrbt", "rltb", "rlbt", "tblr", "tbrl", "btlr", "btrl" };
+               /* Translators: These strings name the possible arrangements of
+                * multiple pages on a sheet when printing (same as in gtkprintbackendcups.c)
+                */
+              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") };
+              int i;
+
+              priv->number_up_layout_n_option = gtk_printer_option_new ("gtk-n-up-layout",
+                                                                        _("Page Ordering"),
+                                                                        GTK_PRINTER_OPTION_TYPE_PICKONE);
+              gtk_printer_option_allocate_choices (priv->number_up_layout_n_option, 8);
+
+              for (i = 0; i < G_N_ELEMENTS (n_up_layout_display); i++)
+                {
+                  priv->number_up_layout_n_option->choices[i] = g_strdup (n_up_layout[i]);
+                  priv->number_up_layout_n_option->choices_display[i] = g_strdup (_(n_up_layout_display[i]));
+                }
+            }
           g_object_ref (priv->number_up_layout_n_option);
 
           priv->number_up_layout_2_option = gtk_printer_option_new ("gtk-n-up-layout",
                                                                     _("Page Ordering"),
                                                                     GTK_PRINTER_OPTION_TYPE_PICKONE);
           gtk_printer_option_allocate_choices (priv->number_up_layout_2_option, 2);
+        }
 
-          priv->number_up_layout_2_option->choices[0] = priv->number_up_layout_n_option->choices[0];
-          priv->number_up_layout_2_option->choices[1] = priv->number_up_layout_n_option->choices[2];
-          priv->number_up_layout_2_option->choices_display[0] = g_strdup ( _("Left to right"));
-          priv->number_up_layout_2_option->choices_display[1] = g_strdup ( _("Right to left"));
+      page_orientation = gtk_page_setup_get_orientation (priv->page_setup);
+      if (page_orientation == GTK_PAGE_ORIENTATION_PORTRAIT ||
+          page_orientation == GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT)
+        {
+          if (! (priv->number_up_layout_2_option->choices[0] == priv->number_up_layout_n_option->choices[0] &&
+                 priv->number_up_layout_2_option->choices[1] == priv->number_up_layout_n_option->choices[2]))
+            {
+              g_free (priv->number_up_layout_2_option->choices_display[0]);
+              g_free (priv->number_up_layout_2_option->choices_display[1]);
+              priv->number_up_layout_2_option->choices[0] = priv->number_up_layout_n_option->choices[0];
+              priv->number_up_layout_2_option->choices[1] = priv->number_up_layout_n_option->choices[2];
+              priv->number_up_layout_2_option->choices_display[0] = g_strdup ( _("Left to right"));
+              priv->number_up_layout_2_option->choices_display[1] = g_strdup ( _("Right to left"));
+            }
+        }
+      else
+        {
+          if (! (priv->number_up_layout_2_option->choices[0] == priv->number_up_layout_n_option->choices[0] &&
+                 priv->number_up_layout_2_option->choices[1] == priv->number_up_layout_n_option->choices[1]))
+            {
+              g_free (priv->number_up_layout_2_option->choices_display[0]);
+              g_free (priv->number_up_layout_2_option->choices_display[1]);
+              priv->number_up_layout_2_option->choices[0] = priv->number_up_layout_n_option->choices[0];
+              priv->number_up_layout_2_option->choices[1] = priv->number_up_layout_n_option->choices[1];
+              priv->number_up_layout_2_option->choices_display[0] = g_strdup ( _("Top to bottom"));
+              priv->number_up_layout_2_option->choices_display[1] = g_strdup ( _("Bottom to top"));
+            }
         }
 
       layout = dialog_get_number_up_layout (dialog);
@@ -2468,12 +2516,20 @@ update_number_up_layout (GtkPrintUnixDialog *dialog)
               option = priv->number_up_layout_2_option;
 
               if (layout == GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM ||
-                  layout == GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_BOTTOM_TO_TOP ||
-                  layout == GTK_NUMBER_UP_LAYOUT_TOP_TO_BOTTOM_LEFT_TO_RIGHT ||
-                  layout == GTK_NUMBER_UP_LAYOUT_BOTTOM_TO_TOP_LEFT_TO_RIGHT)
+                  layout == GTK_NUMBER_UP_LAYOUT_TOP_TO_BOTTOM_LEFT_TO_RIGHT)
                 enum_value = g_enum_get_value (enum_class, GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM);
-              else
+
+              if (layout == GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_BOTTOM_TO_TOP ||
+                  layout == GTK_NUMBER_UP_LAYOUT_BOTTOM_TO_TOP_LEFT_TO_RIGHT)
+                enum_value = g_enum_get_value (enum_class, GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_BOTTOM_TO_TOP);
+
+              if (layout == GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_TOP_TO_BOTTOM ||
+                  layout == GTK_NUMBER_UP_LAYOUT_TOP_TO_BOTTOM_RIGHT_TO_LEFT)
                 enum_value = g_enum_get_value (enum_class, GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_TOP_TO_BOTTOM);
+
+              if (layout == GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_BOTTOM_TO_TOP ||
+                  layout == GTK_NUMBER_UP_LAYOUT_BOTTOM_TO_TOP_RIGHT_TO_LEFT)
+                enum_value = g_enum_get_value (enum_class, GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_BOTTOM_TO_TOP);
             }
           else
             {
diff --git a/modules/printbackends/cups/gtkcupsutils.c b/modules/printbackends/cups/gtkcupsutils.c
index 7ef202c..af6e8d5 100644
--- a/modules/printbackends/cups/gtkcupsutils.c
+++ b/modules/printbackends/cups/gtkcupsutils.c
@@ -383,7 +383,8 @@ static const ipp_option_t ipp_options[] = {
   { "saturation",		IPP_TAG_INTEGER },
   { "scaling",			IPP_TAG_INTEGER },
   { "sides",			IPP_TAG_KEYWORD },
-  { "wrap",			IPP_TAG_BOOLEAN }
+  { "wrap",			IPP_TAG_BOOLEAN },
+  { "number-up-layout",		IPP_TAG_INTEGER }
 };
 
 
diff --git a/modules/printbackends/file/gtkprintbackendfile.c b/modules/printbackends/file/gtkprintbackendfile.c
index c44c24c..7bdaaa7 100644
--- a/modules/printbackends/file/gtkprintbackendfile.c
+++ b/modules/printbackends/file/gtkprintbackendfile.c
@@ -647,6 +647,10 @@ file_printer_get_settings_from_options (GtkPrinter          *printer,
   option = gtk_printer_option_set_lookup (options, "gtk-n-up");
   if (option)
     gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_NUMBER_UP, option->value);
+
+  option = gtk_printer_option_set_lookup (options, "gtk-n-up-layout");
+  if (option)
+    gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_NUMBER_UP_LAYOUT, option->value);
 }
 
 static void
@@ -669,6 +673,8 @@ file_printer_prepare_for_print (GtkPrinter       *printer,
   print_job->collate = gtk_print_settings_get_collate (settings);
   print_job->reverse = gtk_print_settings_get_reverse (settings);
   print_job->num_copies = gtk_print_settings_get_n_copies (settings);
+  print_job->number_up = gtk_print_settings_get_number_up (settings);
+  print_job->number_up_layout = gtk_print_settings_get_number_up_layout (settings);
 
   scale = gtk_print_settings_get_scale (settings);
   if (scale != 100.0)
diff --git a/modules/printbackends/lpr/gtkprintbackendlpr.c b/modules/printbackends/lpr/gtkprintbackendlpr.c
index fa6196d..9d9c932 100644
--- a/modules/printbackends/lpr/gtkprintbackendlpr.c
+++ b/modules/printbackends/lpr/gtkprintbackendlpr.c
@@ -450,7 +450,16 @@ lpr_printer_get_settings_from_options (GtkPrinter          *printer,
   GtkPrinterOption *option;
 
   option = gtk_printer_option_set_lookup (options, "gtk-main-page-custom-input");
-  gtk_print_settings_set (settings, "lpr-commandline", option->value);
+  if (option)
+    gtk_print_settings_set (settings, "lpr-commandline", option->value);
+
+  option = gtk_printer_option_set_lookup (options, "gtk-n-up");
+  if (option)
+    gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_NUMBER_UP, option->value);
+
+  option = gtk_printer_option_set_lookup (options, "gtk-n-up-layout");
+  if (option)
+    gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_NUMBER_UP_LAYOUT, option->value);
 }
 
 static void
@@ -473,6 +482,8 @@ lpr_printer_prepare_for_print (GtkPrinter       *printer,
   print_job->collate = gtk_print_settings_get_collate (settings);
   print_job->reverse = gtk_print_settings_get_reverse (settings);
   print_job->num_copies = gtk_print_settings_get_n_copies (settings);
+  print_job->number_up = gtk_print_settings_get_number_up (settings);
+  print_job->number_up_layout = gtk_print_settings_get_number_up_layout (settings);
 
   scale = gtk_print_settings_get_scale (settings);
   if (scale != 100.0)



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]