diff options
Diffstat (limited to 'gtk/gtkprintoperation.c')
-rw-r--r-- | gtk/gtkprintoperation.c | 472 |
1 files changed, 407 insertions, 65 deletions
diff --git a/gtk/gtkprintoperation.c b/gtk/gtkprintoperation.c index efc211fc5c..d4f8fa25a3 100644 --- a/gtk/gtkprintoperation.c +++ b/gtk/gtkprintoperation.c @@ -19,6 +19,10 @@ */ #include "config.h" + +#include <errno.h> +#include <stdlib.h> + #include <string.h> #include "gtkprintoperation-private.h" #include "gtkmarshalers.h" @@ -41,6 +45,7 @@ enum { STATUS_CHANGED, CREATE_CUSTOM_WIDGET, CUSTOM_WIDGET_APPLY, + PREVIEW, LAST_SIGNAL }; @@ -65,7 +70,15 @@ enum { static guint signals[LAST_SIGNAL] = { 0 }; static int job_nr = 0; -G_DEFINE_TYPE (GtkPrintOperation, gtk_print_operation, G_TYPE_OBJECT) +static void preview_iface_init (GtkPrintOperationPreviewIface *iface); +static GtkPageSetup *create_page_setup (GtkPrintOperation *op); +static void common_render_page (GtkPrintOperation *op, + gint page_nr); + + +G_DEFINE_TYPE_WITH_CODE (GtkPrintOperation, gtk_print_operation, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (GTK_TYPE_PRINT_OPERATION_PREVIEW, + preview_iface_init)) /** * gtk_print_error_quark: @@ -146,6 +159,94 @@ gtk_print_operation_init (GtkPrintOperation *operation) } static void +preview_iface_render_page (GtkPrintOperationPreview *preview, + gint page_nr) +{ + GtkPrintOperation *op; + + op = GTK_PRINT_OPERATION (preview); + common_render_page (op, page_nr); +} + +static void +preview_iface_end_preview (GtkPrintOperationPreview *preview) +{ + GtkPrintOperation *op; + + op = GTK_PRINT_OPERATION (preview); + + g_signal_emit (op, signals[END_PRINT], 0, op->priv->print_context); + + if (op->priv->rloop) + g_main_loop_quit (op->priv->rloop); + + op->priv->end_run (op, op->priv->is_sync, TRUE); +} + +static gboolean +preview_iface_is_selected (GtkPrintOperationPreview *preview, + gint page_nr) +{ + GtkPrintOperation *op; + GtkPrintOperationPrivate *priv; + int i; + + op = GTK_PRINT_OPERATION (preview); + priv = op->priv; + + switch (priv->print_pages) + { + case GTK_PRINT_PAGES_ALL: + return (page_nr >= 0) && (page_nr < priv->nr_of_pages); + case GTK_PRINT_PAGES_CURRENT: + return page_nr == priv->current_page; + case GTK_PRINT_PAGES_RANGES: + for (i = 0; i < priv->num_page_ranges; i++) + { + if (page_nr >= priv->page_ranges[i].start && + page_nr <= priv->page_ranges[i].end) + return TRUE; + } + return FALSE; + } + return FALSE; +} + +static void +preview_iface_init (GtkPrintOperationPreviewIface *iface) +{ + iface->render_page = preview_iface_render_page; + iface->end_preview = preview_iface_end_preview; + iface->is_selected = preview_iface_is_selected; +} + +static void +preview_start_page (GtkPrintOperation *op, + GtkPrintContext *print_context, + GtkPageSetup *page_setup) +{ + g_signal_emit_by_name (op, "got-page-size",print_context, page_setup); +} + +static void +preview_end_page (GtkPrintOperation *op, + GtkPrintContext *print_context) +{ +} + +static void +preview_end_run (GtkPrintOperation *op, + gboolean wait, + gboolean cancelled) +{ + g_free (op->priv->page_ranges); + op->priv->page_ranges = NULL; + + _gtk_print_operation_set_status (op, GTK_PRINT_STATUS_FINISHED, NULL); +} + + +static void gtk_print_operation_set_property (GObject *object, guint prop_id, const GValue *value, @@ -256,6 +357,151 @@ gtk_print_operation_get_property (GObject *object, } } +typedef struct +{ + GtkPrintOperationPreview *preview; + GtkPrintContext *print_context; + GtkWindow *parent; + cairo_surface_t *surface; + gchar *filename; + guint page_nr; + gboolean wait; +} PreviewOp; + +static void +preview_print_idle_done (gpointer data) +{ + GtkPrintOperation *op; + PreviewOp *pop = (PreviewOp *) data; + + GDK_THREADS_ENTER (); + + op = GTK_PRINT_OPERATION (pop->preview); + + _gtk_print_operation_platform_backend_launch_preview (op, + pop->parent, + pop->filename); + + g_free (pop->filename); + cairo_surface_finish (pop->surface); + cairo_surface_destroy (pop->surface); + + gtk_print_operation_preview_end_preview (pop->preview); + g_free (pop); + + GDK_THREADS_LEAVE (); +} + +static gboolean +preview_print_idle (gpointer data) +{ + PreviewOp *pop; + GtkPrintOperation *op; + gboolean retval = TRUE; + cairo_t *cr; + + GDK_THREADS_ENTER (); + + pop = (PreviewOp *) data; + op = GTK_PRINT_OPERATION (pop->preview); + + gtk_print_operation_preview_render_page (pop->preview, pop->page_nr); + + cr = gtk_print_context_get_cairo_context (pop->print_context); + cairo_show_page (cr); + + /* TODO: print out sheets not pages and follow ranges */ + pop->page_nr++; + if (op->priv->nr_of_pages <= pop->page_nr) + retval = FALSE; + + GDK_THREADS_LEAVE (); + + return retval; +} + +static void +preview_got_page_size (GtkPrintOperationPreview *preview, + GtkPrintContext *context, + GtkPageSetup *page_setup, + PreviewOp *pop) +{ + GtkPrintOperation *op = GTK_PRINT_OPERATION (preview); + + _gtk_print_operation_platform_backend_resize_preview_surface (op, page_setup, pop->surface); +} + +static void +preview_ready (GtkPrintOperationPreview *preview, + GtkPrintContext *context, + PreviewOp *pop) +{ + + pop->page_nr = 0; + pop->print_context = context; + + g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, + preview_print_idle, + pop, + preview_print_idle_done); + +} + +/** + * gtk_print_operation_preview_handler: + * + * Default handler for preview operations + **/ +static gboolean +gtk_print_operation_preview_handler (GtkPrintOperation *op, + GtkPrintOperationPreview *preview, + GtkPrintContext *context, + GtkWindow *parent) +{ + gdouble dpi_x, dpi_y; + gchar *tmp_dir; + gchar *dir_template; + gchar *preview_filename; + PreviewOp *pop; + GtkPageSetup *page_setup; + cairo_t *cr; + + dir_template = g_build_filename (g_get_tmp_dir (), "print-preview-XXXXXX", NULL); + + /* use temp dirs because apps like evince need to have extentions + to determine the mine type */ + tmp_dir = mkdtemp(dir_template); + + preview_filename = g_build_filename (tmp_dir, + "Print Preview.pdf", + NULL); + + g_free (dir_template); + + pop = g_new0 (PreviewOp, 1); + pop->filename = preview_filename; + pop->preview = preview; + pop->parent = parent; + + page_setup = gtk_print_context_get_page_setup (context); + + pop->surface = + _gtk_print_operation_platform_backend_create_preview_surface (op, + page_setup, + &dpi_x, &dpi_y, + pop->filename); + + cr = cairo_create (pop->surface); + gtk_print_context_set_cairo_context (op->priv->print_context, cr, + dpi_x, dpi_y); + cairo_destroy (cr); + + g_signal_connect (preview, "ready", (GCallback) preview_ready, pop); + g_signal_connect (preview, "got-page-size", (GCallback) preview_got_page_size, pop); + + return TRUE; +} + static GtkWidget * gtk_print_operation_create_custom_widget (GtkPrintOperation *operation) { @@ -287,7 +533,8 @@ gtk_print_operation_class_init (GtkPrintOperationClass *class) gobject_class->set_property = gtk_print_operation_set_property; gobject_class->get_property = gtk_print_operation_get_property; gobject_class->finalize = gtk_print_operation_finalize; - + + class->preview = gtk_print_operation_preview_handler; class->create_custom_widget = gtk_print_operation_create_custom_widget; g_type_class_add_private (gobject_class, sizeof (GtkPrintOperationPrivate)); @@ -530,6 +777,36 @@ gtk_print_operation_class_init (GtkPrintOperationClass *class) g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GTK_TYPE_WIDGET); + /** + * GtkPrintOperation::preview: + * @operation: the #GtkPrintOperation on which the signal was emitted + * @preview: the #GtkPrintPreviewOperation for the current operation + * @context: the #GtkPrintContext that will be used + * @parent: the #GtkWindow to use as window parent, or NULL + * + * Gets emitted when a preview is requested from the native dialog. + * If you handle this you must set the cairo context on the printing context. + * + * If you don't override this a default implementation using an external + * viewer will be used. + * + * Returns: #TRUE if the listener wants to take over control of the preview + * + * Since: 2.10 + */ + signals[PREVIEW] = + g_signal_new (I_("preview"), + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkPrintOperationClass, preview), + _gtk_boolean_handled_accumulator, NULL, + _gtk_marshal_BOOLEAN__OBJECT_OBJECT_OBJECT, + G_TYPE_BOOLEAN, 3, + GTK_TYPE_PRINT_OPERATION_PREVIEW, + GTK_TYPE_PRINT_CONTEXT, + GTK_TYPE_WINDOW); + + /** * GtkPrintOperation:default-page-setup: * @@ -1436,6 +1713,7 @@ pdf_start_page (GtkPrintOperation *op, GtkPageSetup *page_setup) { GtkPaperSize *paper_size; + cairo_surface_t *surface = op->priv->platform_data; double w, h; paper_size = gtk_page_setup_get_paper_size (page_setup); @@ -1443,7 +1721,7 @@ pdf_start_page (GtkPrintOperation *op, w = gtk_paper_size_get_width (paper_size, GTK_UNIT_POINTS); h = gtk_paper_size_get_height (paper_size, GTK_UNIT_POINTS); - cairo_pdf_surface_set_size (op->priv->surface, w, h); + cairo_pdf_surface_set_size (surface, w, h); } static void @@ -1462,9 +1740,10 @@ pdf_end_run (GtkPrintOperation *op, gboolean cancelled) { GtkPrintOperationPrivate *priv = op->priv; + cairo_surface_t *surface = priv->platform_data; - cairo_surface_destroy (priv->surface); - priv->surface = NULL; + cairo_surface_finish (surface); + cairo_surface_destroy (surface); } static GtkPrintOperationResult @@ -1475,6 +1754,8 @@ run_pdf (GtkPrintOperation *op, { GtkPrintOperationPrivate *priv = op->priv; GtkPageSetup *page_setup; + cairo_surface_t *surface; + cairo_t *cr; double width, height; /* This will be overwritten later by the non-default size, but we need to pass some size: */ @@ -1484,13 +1765,19 @@ run_pdf (GtkPrintOperation *op, height = gtk_page_setup_get_paper_height (page_setup, GTK_UNIT_POINTS); g_object_unref (page_setup); - priv->surface = cairo_pdf_surface_create (priv->pdf_target, - width, height); - cairo_pdf_surface_set_dpi (priv->surface, 300, 300); - - priv->dpi_x = 72; - priv->dpi_y = 72; + surface = cairo_pdf_surface_create (priv->pdf_target, + width, height); + cairo_pdf_surface_set_dpi (surface, 300, 300); + + priv->platform_data = surface; + priv->free_platform_data = (GDestroyNotify) cairo_surface_destroy; + cr = cairo_create (surface); + gtk_print_context_set_cairo_context (op->priv->print_context, + cr, 72, 72); + cairo_destroy (cr); + + priv->print_pages = GTK_PRINT_PAGES_ALL; priv->page_ranges = NULL; priv->num_page_ranges = 0; @@ -1524,10 +1811,11 @@ typedef struct gint page, start, end, inc; - GtkPageSetup *initial_page_setup; - GtkPrintContext *print_context; + gboolean initialized; GtkWidget *progress; + + gboolean is_preview; } PrintPagesData; static void @@ -1599,12 +1887,9 @@ print_pages_idle_done (gpointer user_data) if (data->progress) gtk_widget_destroy (data->progress); - g_object_unref (data->print_context); - g_object_unref (data->initial_page_setup); - g_object_unref (data->op); - if (priv->rloop) + if (priv->rloop && !data->is_preview) g_main_loop_quit (priv->rloop); g_free (data); @@ -1640,13 +1925,56 @@ update_progress (PrintPagesData *data) } } +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) + 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); + + g_signal_emit (op, signals[DRAW_PAGE], 0, + print_context, page_nr); + + priv->end_page (op, print_context); + + cairo_restore (cr); + + g_object_unref (page_setup); +} + static gboolean print_pages_idle (gpointer user_data) { PrintPagesData *data; GtkPrintOperationPrivate *priv; GtkPageSetup *page_setup; - cairo_t *cr; gboolean done = FALSE; GDK_THREADS_ENTER (); @@ -1656,15 +1984,15 @@ print_pages_idle (gpointer user_data) if (priv->status == GTK_PRINT_STATUS_PREPARING) { - if (!data->print_context) + if (!data->initialized) { - data->print_context = _gtk_print_context_new (data->op); - data->initial_page_setup = create_page_setup (data->op); - - _gtk_print_context_set_page_setup (data->print_context, - data->initial_page_setup); + 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, data->print_context); + g_signal_emit (data->op, signals[BEGIN_PRINT], 0, priv->print_context); if (priv->manual_collation) { @@ -1684,7 +2012,7 @@ print_pages_idle (gpointer user_data) { gboolean paginated = FALSE; - g_signal_emit (data->op, signals[PAGINATE], 0, data->print_context, &paginated); + g_signal_emit (data->op, signals[PAGINATE], 0, priv->print_context, &paginated); if (!paginated) goto out; } @@ -1751,36 +2079,18 @@ print_pages_idle (gpointer user_data) goto out; } } + + if (data->is_preview) + { + done = TRUE; - page_setup = gtk_page_setup_copy (data->initial_page_setup); - g_signal_emit (data->op, signals[REQUEST_PAGE_SETUP], 0, - data->print_context, data->page, page_setup); - - _gtk_print_context_set_page_setup (data->print_context, page_setup); - priv->start_page (data->op, data->print_context, page_setup); - - cr = gtk_print_context_get_cairo_context (data->print_context); - - cairo_save (cr); - if (priv->manual_scale != 1.0) - cairo_scale (cr, - priv->manual_scale, - priv->manual_scale); - - if (priv->manual_orientation) - _gtk_print_context_rotate_according_to_orientation (data->print_context); - - if (!priv->use_full_page) - _gtk_print_context_translate_into_margin (data->print_context); - - g_signal_emit (data->op, signals[DRAW_PAGE], 0, - data->print_context, data->page); - - priv->end_page (data->op, data->print_context); - - cairo_restore (cr); - - g_object_unref (page_setup); + g_object_ref (data->op); + + g_signal_emit_by_name (data->op, "ready", priv->print_context); + goto out; + } + + common_render_page (data->op, data->page); out: @@ -1791,11 +2101,9 @@ print_pages_idle (gpointer user_data) done = TRUE; } - if (done) + if (done && !data->is_preview) { - g_signal_emit (data->op, signals[END_PRINT], 0, data->print_context); - - cairo_surface_finish (priv->surface); + g_signal_emit (data->op, signals[END_PRINT], 0, priv->print_context); priv->end_run (data->op, priv->is_sync, priv->cancelled); } @@ -1833,15 +2141,17 @@ show_progress_timeout (PrintPagesData *data) static void print_pages (GtkPrintOperation *op, - GtkWindow *parent) + GtkWindow *parent, + gboolean is_preview) { GtkPrintOperationPrivate *priv = op->priv; PrintPagesData *data; - + _gtk_print_operation_set_status (op, GTK_PRINT_STATUS_PREPARING, NULL); data = g_new0 (PrintPagesData, 1); data->op = g_object_ref (op); + data->is_preview = is_preview; if (priv->show_progress) { @@ -1862,6 +2172,37 @@ print_pages (GtkPrintOperation *op, data->progress = progress; } + if (is_preview) + { + gboolean handled; + + g_signal_emit_by_name (op, "preview", + GTK_PRINT_OPERATION_PREVIEW (op), + op->priv->print_context, + parent, + &handled); + + if (!handled || + gtk_print_context_get_cairo_context (priv->print_context) == NULL) { + /* Programmer error */ + g_error ("You must set a cairo context on the print context"); + } + + priv->start_page = preview_start_page; + priv->end_page = preview_end_page; + priv->end_run = preview_end_run; + + priv->print_pages = gtk_print_settings_get_print_pages (priv->print_settings); + priv->page_ranges = gtk_print_settings_get_page_ranges (priv->print_settings, + &priv->num_page_ranges); + priv->manual_num_copies = 1; + priv->manual_collation = FALSE; + priv->manual_reverse = FALSE; + priv->manual_page_set = GTK_PAGE_SET_ALL; + priv->manual_scale = 1.0; + priv->manual_orientation = TRUE; + } + priv->print_pages_idle_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, print_pages_idle, data, @@ -1877,9 +2218,10 @@ print_pages (GtkPrintOperation *op, GDK_THREADS_LEAVE (); g_main_loop_run (priv->rloop); GDK_THREADS_ENTER (); + + g_main_loop_unref (priv->rloop); + priv->rloop = NULL; } - g_main_loop_unref (priv->rloop); - priv->rloop = NULL; } /** @@ -1964,7 +2306,7 @@ gtk_print_operation_run (GtkPrintOperation *op, &do_print, error); if (do_print) - print_pages (op, parent); + print_pages (op, parent, result == GTK_PRINT_OPERATION_RESULT_PREVIEW); else _gtk_print_operation_set_status (op, GTK_PRINT_STATUS_FINISHED_ABORTED, NULL); @@ -2006,7 +2348,7 @@ gtk_print_operation_run_async (GtkPrintOperation *op, { run_pdf (op, parent, &do_print, NULL); if (do_print) - print_pages (op, parent); + print_pages (op, parent, FALSE); else _gtk_print_operation_set_status (op, GTK_PRINT_STATUS_FINISHED_ABORTED, NULL); } |