+/**
+ * gtk_print_operation_set_defer_drawing:
+ * @op: a #GtkPrintOperation
+ *
+ * Sets up the #GtkPrintOperation to wait for calling of
+ * gtk_print_operation_draw_page_finish() from application. It can
+ * be used for drawing page in another thread.
+ *
+ * This function must be called in the callback of "draw-page" signal.
+ *
+ * Since: 2.16
+ **/
+void
+gtk_print_operation_set_defer_drawing (GtkPrintOperation *op)
+{
+ GtkPrintOperationPrivate *priv = op->priv;
+
+ g_return_if_fail (priv->page_drawing_state == GTK_PAGE_DRAWING_STATE_DRAWING);
+
+ priv->page_drawing_state = GTK_PAGE_DRAWING_STATE_DEFERRED_DRAWING;
+}
+
+/**
+ * gtk_print_operation_set_embed_page_setup:
+ * @op: a #GtkPrintOperation
+ * @embed: %TRUE to embed page setup selection in the #GtkPrintDialog
+ *
+ * Embed page size combo box and orientation combo box into page setup page.
+ * Selected page setup is stored as default page setup in #GtkPrintOperation.
+ *
+ * Since: 2.18
+ **/
+void
+gtk_print_operation_set_embed_page_setup (GtkPrintOperation *op,
+ gboolean embed)
+{
+ GtkPrintOperationPrivate *priv;
+
+ g_return_if_fail (GTK_IS_PRINT_OPERATION (op));
+
+ priv = op->priv;
+
+ embed = embed != FALSE;
+ if (priv->embed_page_setup != embed)
+ {
+ priv->embed_page_setup = embed;
+ g_object_notify (G_OBJECT (op), "embed-page-setup");
+ }
+}
+
+/**
+ * gtk_print_operation_get_embed_page_setup:
+ * @op: a #GtkPrintOperation
+ *
+ * Gets the value of #GtkPrintOperation::embed-page-setup property.
+ *
+ * Returns: whether page setup selection combos are embedded
+ *
+ * Since: 2.18
+ */
+gboolean
+gtk_print_operation_get_embed_page_setup (GtkPrintOperation *op)
+{
+ g_return_val_if_fail (GTK_IS_PRINT_OPERATION (op), FALSE);
+
+ return op->priv->embed_page_setup;
+}
+
+/**
+ * gtk_print_operation_draw_page_finish:
+ * @op: a #GtkPrintOperation
+ *
+ * Signalize that drawing of particular page is complete.
+ *
+ * It is called after completion of page drawing (e.g. drawing in another
+ * thread).
+ * If gtk_print_operation_set_defer_drawing() was called before, then this function
+ * has to be called by application. In another case it is called by the library
+ * itself.
+ *
+ * Since: 2.16
+ **/
+void
+gtk_print_operation_draw_page_finish (GtkPrintOperation *op)
+{
+ GtkPrintOperationPrivate *priv = op->priv;
+ GtkPageSetup *page_setup;
+ GtkPrintContext *print_context;
+ cairo_t *cr;
+
+ print_context = priv->print_context;
+ page_setup = gtk_print_context_get_page_setup (print_context);
+
+ cr = gtk_print_context_get_cairo_context (print_context);
+
+ priv->end_page (op, print_context);
+
+ cairo_restore (cr);
+
+ g_object_unref (page_setup);
+
+ priv->page_drawing_state = GTK_PAGE_DRAWING_STATE_READY;
+}
+
+static void
+common_render_page (GtkPrintOperation *op,
+ gint page_nr)
+{
+ GtkPrintOperationPrivate *priv = op->priv;
+ GtkPageSetup *page_setup;
+ GtkPrintContext *print_context;
+ cairo_t *cr;
+
+ print_context = priv->print_context;
+
+ page_setup = create_page_setup (op);
+
+ g_signal_emit (op, signals[REQUEST_PAGE_SETUP], 0,
+ print_context, page_nr, page_setup);
+
+ _gtk_print_context_set_page_setup (print_context, page_setup);
+
+ priv->start_page (op, print_context, page_setup);
+
+ cr = gtk_print_context_get_cairo_context (print_context);
+
+ cairo_save (cr);
+ 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->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, - G_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;
+
+ g_signal_emit (op, signals[DRAW_PAGE], 0,
+ print_context, page_nr);
+
+ if (priv->page_drawing_state == GTK_PAGE_DRAWING_STATE_DRAWING)
+ gtk_print_operation_draw_page_finish (op);
+}
+
+static void
+prepare_data (PrintPagesData *data)
+{
+ GtkPrintOperationPrivate *priv;
+ GtkPageSetup *page_setup;
+ gint i, j, counter;
+
+ priv = data->op->priv;
+
+ if (!data->initialized)
+ {
+ data->initialized = TRUE;
+ page_setup = create_page_setup (data->op);
+ _gtk_print_context_set_page_setup (priv->print_context,
+ page_setup);
+ g_object_unref (page_setup);
+
+ g_signal_emit (data->op, signals[BEGIN_PRINT], 0, priv->print_context);
+
+ if (priv->manual_collation)
+ {
+ data->uncollated_copies = priv->manual_num_copies;
+ data->collated_copies = 1;
+ }
+ else
+ {
+ data->uncollated_copies = 1;
+ data->collated_copies = priv->manual_num_copies;
+ }
+
+ return;
+ }
+
+ if (g_signal_has_handler_pending (data->op, signals[PAGINATE], 0, FALSE))
+ {
+ gboolean paginated = FALSE;
+
+ g_signal_emit (data->op, signals[PAGINATE], 0, priv->print_context, &paginated);
+ if (!paginated)
+ return;
+ }
+
+ /* Initialize parts of PrintPagesData that depend on nr_of_pages
+ */