diff options
-rw-r--r-- | mail/e-mail-printer.c | 474 | ||||
-rw-r--r-- | mail/e-mail-printer.h | 13 | ||||
-rw-r--r-- | mail/e-mail-reader-utils.c | 78 | ||||
-rw-r--r-- | mail/em-composer-utils.c | 25 | ||||
-rw-r--r-- | mail/em-utils.c | 8 |
5 files changed, 349 insertions, 249 deletions
diff --git a/mail/e-mail-printer.c b/mail/e-mail-printer.c index e10ef34ffb..a084ec2635 100644 --- a/mail/e-mail-printer.c +++ b/mail/e-mail-printer.c @@ -50,6 +50,8 @@ enum { BUTTONS_COUNT }; +typedef struct _AsyncContext AsyncContext; + struct _EMailPrinterPrivate { EMailFormatter *formatter; EMailPartList *part_list; @@ -67,14 +69,20 @@ struct _EMailPrinterPrivate { GtkPrintOperationAction print_action; }; -enum { - PROP_0, - PROP_PART_LIST +struct _AsyncContext { + WebKitWebView *web_view; + gulong load_status_handler_id; + + GCancellable *cancellable; + GMainContext *main_context; + + GtkPrintOperationAction print_action; + GtkPrintOperationResult print_result; }; enum { - SIGNAL_DONE, - LAST_SIGNAL + PROP_0, + PROP_PART_LIST }; enum { @@ -85,13 +93,27 @@ enum { LAST_COLUMN }; -static guint signals[LAST_SIGNAL]; - G_DEFINE_TYPE ( EMailPrinter, e_mail_printer, G_TYPE_OBJECT); +static void +async_context_free (AsyncContext *async_context) +{ + if (async_context->load_status_handler_id > 0) + g_signal_handler_disconnect ( + async_context->web_view, + async_context->load_status_handler_id); + + g_clear_object (&async_context->web_view); + g_clear_object (&async_context->cancellable); + + g_main_context_unref (async_context->main_context); + + g_slice_free (AsyncContext, async_context); +} + static gint mail_printer_header_name_equal (const EMailFormatterHeader *h1, const EMailFormatterHeader *h2) @@ -145,141 +167,6 @@ mail_printer_draw_footer_cb (GtkPrintOperation *operation, } static void -mail_printer_printing_done_cb (GtkPrintOperation *operation, - GtkPrintOperationResult result, - EMailPrinter *printer) -{ - g_signal_emit (printer, signals[SIGNAL_DONE], 0, operation, result); -} - -static gboolean -mail_printer_start_printing_timeout_cb (gpointer user_data) -{ - EMailPrinter *printer; - WebKitWebFrame *frame; - - printer = E_MAIL_PRINTER (user_data); - frame = webkit_web_view_get_main_frame (printer->priv->webview); - - webkit_web_frame_print_full ( - frame, printer->priv->operation, - printer->priv->print_action, NULL); - - return FALSE; -} - -static void -mail_printer_start_printing (GObject *object, - GParamSpec *pspec, - EMailPrinter *printer) -{ - WebKitWebView *web_view; - WebKitLoadStatus load_status; - - web_view = WEBKIT_WEB_VIEW (object); - load_status = webkit_web_view_get_load_status (web_view); - - if (load_status != WEBKIT_LOAD_FINISHED) - return; - - /* WebKit reloads the page once more right before starting to print, so - * disconnect this handler after the first time, so that we don't start - * another printing operation */ - g_signal_handlers_disconnect_by_func ( - object, mail_printer_start_printing, printer); - - if (printer->priv->print_action == GTK_PRINT_OPERATION_ACTION_EXPORT) - gtk_print_operation_set_export_filename ( - printer->priv->operation, - printer->priv->export_filename); - - /* Give WebKit some time to perform layouting and rendering before - * we start printing. 500ms should be enough in most cases... */ - g_timeout_add_full ( - G_PRIORITY_DEFAULT, 500, - mail_printer_start_printing_timeout_cb, - g_object_ref (printer), - (GDestroyNotify) g_object_unref); -} - -static void -mail_printer_run_print_operation (EMailPrinter *printer, - EMailFormatter *formatter) -{ - EMailPartList *part_list; - CamelFolder *folder; - const gchar *message_uid; - const gchar *charset = NULL; - const gchar *default_charset = NULL; - gchar *mail_uri; - - part_list = printer->priv->part_list; - folder = e_mail_part_list_get_folder (part_list); - message_uid = e_mail_part_list_get_message_uid (part_list); - - if (formatter != NULL) { - charset = e_mail_formatter_get_charset (formatter); - default_charset = e_mail_formatter_get_default_charset (formatter); - } - - if (charset == NULL) - charset = ""; - if (default_charset == NULL) - default_charset = ""; - - mail_uri = e_mail_part_build_uri ( - folder, message_uid, - "__evo-load-image", G_TYPE_BOOLEAN, TRUE, - "mode", G_TYPE_INT, E_MAIL_FORMATTER_MODE_PRINTING, - "formatter_default_charset", G_TYPE_STRING, default_charset, - "formatter_charset", G_TYPE_STRING, charset, - NULL); - - /* Print_layout is a special EMPart created by EMFormatHTMLPrint */ - if (printer->priv->webview == NULL) { - EMailFormatter *emp_formatter; - - printer->priv->webview = g_object_new ( - E_TYPE_MAIL_DISPLAY, - "mode", E_MAIL_FORMATTER_MODE_PRINTING, NULL); - e_web_view_set_enable_frame_flattening ( - E_WEB_VIEW (printer->priv->webview), FALSE); - e_mail_display_set_force_load_images ( - E_MAIL_DISPLAY (printer->priv->webview), TRUE); - - emp_formatter = e_mail_display_get_formatter ( - E_MAIL_DISPLAY (printer->priv->webview)); - if (default_charset != NULL && *default_charset != '\0') - e_mail_formatter_set_default_charset ( - emp_formatter, default_charset); - if (charset != NULL && *charset != '\0') - e_mail_formatter_set_charset (emp_formatter, charset); - - g_object_ref_sink (printer->priv->webview); - g_signal_connect ( - printer->priv->webview, "notify::load-status", - G_CALLBACK (mail_printer_start_printing), printer); - - w ({ - GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - GtkWidget *sw = gtk_scrolled_window_new (NULL, NULL); - gtk_container_add (GTK_CONTAINER (window), sw); - gtk_container_add ( - GTK_CONTAINER (sw), - GTK_WIDGET (printer->priv->webview)); - gtk_widget_show_all (window); - }); - } - - e_mail_display_set_parts_list ( - E_MAIL_DISPLAY (printer->priv->webview), - printer->priv->part_list); - webkit_web_view_load_uri (printer->priv->webview, mail_uri); - - g_free (mail_uri); -} - -static void set_header_visible (EMailPrinter *emp, EMailFormatterHeader *header, gint index, @@ -656,6 +543,158 @@ emp_create_headers_tab (GtkPrintOperation *operation, return hbox; } +static gboolean +mail_printer_print_timeout_cb (gpointer user_data) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; + GCancellable *cancellable; + GtkPrintOperation *print_operation; + GtkPrintOperationAction print_action; + EMailPrinter *printer; + WebKitWebFrame *web_frame; + gulong create_custom_widget_handler_id; + gulong draw_page_handler_id; + GError *error = NULL; + + simple = G_SIMPLE_ASYNC_RESULT (user_data); + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + cancellable = async_context->cancellable; + print_action = async_context->print_action; + + /* Check for cancellation one last time before printing. */ + if (g_cancellable_set_error_if_cancelled (cancellable, &error)) + goto exit; + + /* This returns a new reference. */ + printer = (EMailPrinter *) g_async_result_get_source_object ( + G_ASYNC_RESULT (simple)); + + print_operation = e_print_operation_new (); + gtk_print_operation_set_show_progress (print_operation, TRUE); + gtk_print_operation_set_unit (print_operation, GTK_UNIT_PIXEL); + + if (async_context->print_action == GTK_PRINT_OPERATION_ACTION_EXPORT) { + const gchar *export_filename; + + export_filename = + e_mail_printer_get_export_filename (printer); + gtk_print_operation_set_export_filename ( + print_operation, export_filename); + } + + create_custom_widget_handler_id = g_signal_connect ( + print_operation, "create-custom-widget", + G_CALLBACK (emp_create_headers_tab), printer); + + draw_page_handler_id = g_signal_connect ( + print_operation, "draw-page", + G_CALLBACK (mail_printer_draw_footer_cb), + async_context->cancellable); + + web_frame = webkit_web_view_get_main_frame (async_context->web_view); + + async_context->print_result = webkit_web_frame_print_full ( + web_frame, print_operation, print_action, &error); + + /* Sanity check. */ + switch (async_context->print_result) { + case GTK_PRINT_OPERATION_RESULT_ERROR: + if (error == NULL) + g_warning ( + "WebKit print operation returned " + "ERROR result without settings a " + "GError"); + break; + case GTK_PRINT_OPERATION_RESULT_APPLY: + if (error != NULL) + g_warning ( + "WebKit print operation returned " + "APPLY result but also set a GError"); + case GTK_PRINT_OPERATION_RESULT_CANCEL: + if (error != NULL) + g_warning ( + "WebKit print operation returned " + "CANCEL result but also set a GError"); + break; + default: + g_warn_if_reached (); + } + + g_signal_handler_disconnect ( + print_operation, create_custom_widget_handler_id); + + g_signal_handler_disconnect ( + print_operation, draw_page_handler_id); + + g_object_unref (print_operation); + + g_object_unref (printer); + +exit: + if (error != NULL) + g_simple_async_result_take_error (simple, error); + + g_simple_async_result_complete_in_idle (simple); + + return FALSE; +} + +static void +mail_printer_load_status_cb (WebKitWebView *web_view, + GParamSpec *pspec, + GSimpleAsyncResult *simple) +{ + AsyncContext *async_context; + WebKitLoadStatus load_status; + GCancellable *cancellable; + GError *error = NULL; + + /* Note: we disregard WEBKIT_LOAD_FAILED and print what we can. */ + load_status = webkit_web_view_get_load_status (web_view); + if (load_status != WEBKIT_LOAD_FINISHED) + return; + + /* Signal handlers are holding the only GSimpleAsyncResult + * references. This is to avoid finalizing it prematurely. */ + g_object_ref (simple); + + async_context = g_simple_async_result_get_op_res_gpointer (simple); + cancellable = async_context->cancellable; + + /* WebKit reloads the page once more right before starting to print, + * so disconnect this handler after the first time to avoid starting + * another print operation. */ + g_signal_handler_disconnect ( + async_context->web_view, + async_context->load_status_handler_id); + async_context->load_status_handler_id = 0; + + /* Check if we've been cancelled. */ + if (g_cancellable_set_error_if_cancelled (cancellable, &error)) { + g_simple_async_result_take_error (simple, error); + g_simple_async_result_complete_in_idle (simple); + + /* Give WebKit some time to perform layouting and rendering before + * we start printing. 500ms should be enough in most cases. */ + } else { + GSource *timeout_source; + + timeout_source = g_timeout_source_new (500); + g_source_set_callback ( + timeout_source, + mail_printer_print_timeout_cb, + g_object_ref (simple), + (GDestroyNotify) g_object_unref); + g_source_attach ( + timeout_source, async_context->main_context); + g_source_unref (timeout_source); + } + + g_object_unref (simple); +} + static void mail_printer_build_model (EMailPrinter *printer, EMailPartList *part_list) @@ -724,6 +763,28 @@ mail_printer_build_model (EMailPrinter *printer, camel_medium_free_headers (CAMEL_MEDIUM (message), headers); } +static WebKitWebView * +mail_printer_new_web_view (const gchar *charset, + const gchar *default_charset) +{ + WebKitWebView *web_view; + EMailFormatter *formatter; + + web_view = g_object_new ( + E_TYPE_MAIL_DISPLAY, + "mode", E_MAIL_FORMATTER_MODE_PRINTING, NULL); + e_web_view_set_enable_frame_flattening (E_WEB_VIEW (web_view), FALSE); + e_mail_display_set_force_load_images (E_MAIL_DISPLAY (web_view), TRUE); + + formatter = e_mail_display_get_formatter (E_MAIL_DISPLAY (web_view)); + if (charset != NULL && *charset != '\0') + e_mail_formatter_set_charset (formatter, charset); + if (default_charset != NULL && *default_charset != '\0') + e_mail_formatter_set_default_charset (formatter, default_charset); + + return web_view; +} + static void mail_printer_set_part_list (EMailPrinter *printer, EMailPartList *part_list) @@ -859,16 +920,6 @@ e_mail_printer_class_init (EMailPrinterClass *class) E_TYPE_MAIL_PART_LIST, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - signals[SIGNAL_DONE] = g_signal_new ( - "done", - G_TYPE_FROM_CLASS (class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (EMailPrinterClass, done), - NULL, NULL, NULL, - G_TYPE_NONE, 2, - GTK_TYPE_PRINT_OPERATION, - GTK_TYPE_PRINT_OPERATION_RESULT); } static void @@ -901,34 +952,109 @@ void e_mail_printer_print (EMailPrinter *printer, GtkPrintOperationAction action, EMailFormatter *formatter, - GCancellable *cancellable) + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { + GSimpleAsyncResult *simple; + AsyncContext *async_context; + WebKitWebView *web_view; + EMailPartList *part_list; + CamelFolder *folder; + const gchar *message_uid; + const gchar *charset = NULL; + const gchar *default_charset = NULL; + gchar *mail_uri; + gulong handler_id; + g_return_if_fail (E_IS_MAIL_PRINTER (printer)); + /* EMailFormatter can be NULL. */ - if (printer->priv->operation) - g_object_unref (printer->priv->operation); - printer->priv->operation = e_print_operation_new (); - printer->priv->print_action = action; - gtk_print_operation_set_unit (printer->priv->operation, GTK_UNIT_PIXEL); + async_context = g_slice_new0 (AsyncContext); + async_context->print_action = action; + async_context->main_context = g_main_context_ref_thread_default (); - gtk_print_operation_set_show_progress (printer->priv->operation, TRUE); - g_signal_connect ( - printer->priv->operation, "create-custom-widget", - G_CALLBACK (emp_create_headers_tab), printer); - g_signal_connect ( - printer->priv->operation, "done", - G_CALLBACK (mail_printer_printing_done_cb), printer); - g_signal_connect ( - printer->priv->operation, "draw-page", - G_CALLBACK (mail_printer_draw_footer_cb), NULL); + if (G_IS_CANCELLABLE (cancellable)) + async_context->cancellable = g_object_ref (cancellable); + + part_list = e_mail_printer_ref_part_list (printer); + folder = e_mail_part_list_get_folder (part_list); + message_uid = e_mail_part_list_get_message_uid (part_list); + + if (formatter != NULL) { + charset = + e_mail_formatter_get_charset (formatter); + default_charset = + e_mail_formatter_get_default_charset (formatter); + } + + if (charset == NULL) + charset = ""; + if (default_charset == NULL) + default_charset = ""; + + simple = g_simple_async_result_new ( + G_OBJECT (printer), callback, + user_data, e_mail_printer_print); + + g_simple_async_result_set_check_cancellable (simple, cancellable); + + g_simple_async_result_set_op_res_gpointer ( + simple, async_context, (GDestroyNotify) async_context_free); + + web_view = mail_printer_new_web_view (charset, default_charset); + e_mail_display_set_parts_list (E_MAIL_DISPLAY (web_view), part_list); + + async_context->web_view = g_object_ref_sink (web_view); + + handler_id = g_signal_connect_data ( + web_view, "notify::load-status", + G_CALLBACK (mail_printer_load_status_cb), + g_object_ref (simple), + (GClosureNotify) g_object_unref, 0); + async_context->load_status_handler_id = handler_id; + + mail_uri = e_mail_part_build_uri ( + folder, message_uid, + "__evo-load-image", G_TYPE_BOOLEAN, TRUE, + "mode", G_TYPE_INT, E_MAIL_FORMATTER_MODE_PRINTING, + "formatter_default_charset", G_TYPE_STRING, default_charset, + "formatter_charset", G_TYPE_STRING, charset, + NULL); + + webkit_web_view_load_uri (web_view, mail_uri); + + g_free (mail_uri); + + g_object_unref (simple); + + g_object_unref (part_list); +} + +GtkPrintOperationResult +e_mail_printer_print_finish (EMailPrinter *printer, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + AsyncContext *async_context; + + g_return_val_if_fail ( + g_simple_async_result_is_valid ( + result, G_OBJECT (printer), e_mail_printer_print), + GTK_PRINT_OPERATION_RESULT_ERROR); + + simple = G_SIMPLE_ASYNC_RESULT (result); + async_context = g_simple_async_result_get_op_res_gpointer (simple); + + if (g_simple_async_result_propagate_error (simple, error)) + return GTK_PRINT_OPERATION_RESULT_ERROR; - if (cancellable) - g_signal_connect_swapped ( - cancellable, "cancelled", - G_CALLBACK (gtk_print_operation_cancel), - printer->priv->operation); + g_warn_if_fail ( + async_context->print_result != + GTK_PRINT_OPERATION_RESULT_ERROR); - mail_printer_run_print_operation (printer, formatter); + return async_context->print_result; } const gchar * diff --git a/mail/e-mail-printer.h b/mail/e-mail-printer.h index d38bf34d1d..b5a79d5a1b 100644 --- a/mail/e-mail-printer.h +++ b/mail/e-mail-printer.h @@ -55,11 +55,6 @@ struct _EMailPrinter { struct _EMailPrinterClass { GObjectClass parent_class; - - void (*done) (EMailPrinter *printer, - GtkPrintOperation *operation, - GtkPrintOperationResult result, - gpointer user_data); }; GType e_mail_printer_get_type (void) G_GNUC_CONST; @@ -68,7 +63,13 @@ EMailPartList * e_mail_printer_ref_part_list (EMailPrinter *printer); void e_mail_printer_print (EMailPrinter *printer, GtkPrintOperationAction action, EMailFormatter *formatter, - GCancellable *cancellable); + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +GtkPrintOperationResult + e_mail_printer_print_finish (EMailPrinter *printer, + GAsyncResult *result, + GError **error); const gchar * e_mail_printer_get_export_filename (EMailPrinter *printer); void e_mail_printer_set_export_filename diff --git a/mail/e-mail-reader-utils.c b/mail/e-mail-reader-utils.c index c4a6ac09b9..9ef55e022e 100644 --- a/mail/e-mail-reader-utils.c +++ b/mail/e-mail-reader-utils.c @@ -864,56 +864,38 @@ e_mail_reader_open_selected (EMailReader *reader) return ii; } -static gboolean -destroy_printing_activity (EActivity *activity) -{ - g_object_unref (activity); - - return FALSE; -} - static void -printing_done_cb (EMailPrinter *printer, - GtkPrintOperation *operation, - GtkPrintOperationResult result, - gpointer user_data) +mail_reader_print_message_done_cb (GObject *source_object, + GAsyncResult *result, + gpointer user_data) { - EActivity *activity = user_data; + EActivity *activity; + EAlertSink *alert_sink; + GError *error = NULL; - if (result == GTK_PRINT_OPERATION_RESULT_ERROR) { + activity = E_ACTIVITY (user_data); + alert_sink = e_activity_get_alert_sink (activity); - EAlertSink *alert_sink; - GError *error = NULL; + e_mail_printer_print_finish ( + E_MAIL_PRINTER (source_object), result, &error); - alert_sink = e_activity_get_alert_sink (activity); - gtk_print_operation_get_error (operation, &error); + if (e_activity_handle_cancellation (activity, error)) { + g_error_free (error); - if (error != NULL) { - e_alert_submit ( - alert_sink, "mail:printing-failed", - error->message, NULL); - g_error_free (error); - } + } else if (error != NULL) { + e_alert_submit ( + alert_sink, "mail:printing-failed", + error->message, NULL); + g_error_free (error); - g_object_unref (activity); - g_object_unref (printer); - return; + } else { + /* Set activity as completed, and keep it displayed for a few + * seconds so that user can actually see the the printing was + * successfully finished. */ + e_activity_set_state (activity, E_ACTIVITY_COMPLETED); } - /* Set activity as completed, and keep it displayed for a few seconds - * so that user can actually see the the printing was sucesfully finished. */ - e_activity_set_state (activity, E_ACTIVITY_COMPLETED); - - /* We can't destroy the printer and associated WebKitWebView directly from - * here, because this callback is a handler of a WebKit's signal. This - * will destroy the printer later, together with the activity */ - g_object_set_data_full ( - G_OBJECT (activity), - "printer", printer, (GDestroyNotify) g_object_unref); - - g_timeout_add_seconds_full ( - G_PRIORITY_DEFAULT, 3, - (GSourceFunc) destroy_printing_activity, activity, NULL); + g_object_unref (activity); } struct _MessagePrintingContext { @@ -947,6 +929,7 @@ mail_reader_do_print_message (GObject *object, { EMailReader *reader = E_MAIL_READER (object); EMailDisplay *mail_display; + EMailFormatter *formatter; EActivity *activity; GCancellable *cancellable; EMailPrinter *printer; @@ -961,16 +944,17 @@ mail_reader_do_print_message (GObject *object, part_list = e_mail_reader_parse_message_finish (reader, result); printer = e_mail_printer_new (part_list); - g_signal_connect ( - printer, "done", - G_CALLBACK (printing_done_cb), activity); mail_display = e_mail_reader_get_mail_display (reader); + formatter = e_mail_display_get_formatter (mail_display); e_mail_printer_print ( - printer, context->action, - e_mail_display_get_formatter (mail_display), - cancellable); + printer, context->action, formatter, cancellable, + mail_reader_print_message_done_cb, + g_object_ref (activity)); + + g_object_unref (activity); + g_object_unref (printer); free_message_printing_context (context); } diff --git a/mail/em-composer-utils.c b/mail/em-composer-utils.c index 5d6ba26c5f..0f801b4266 100644 --- a/mail/em-composer-utils.c +++ b/mail/em-composer-utils.c @@ -958,38 +958,27 @@ em_utils_composer_save_to_outbox_cb (EMsgComposer *composer, } static void -composer_print_done_cb (EMailPrinter *emp, - GtkPrintOperation *operation, - GtkPrintOperationResult result, - gpointer user_data) -{ - g_object_unref (emp); -} - -static void em_utils_composer_print_cb (EMsgComposer *composer, GtkPrintOperationAction action, CamelMimeMessage *message, EActivity *activity, EMailSession *session) { - EMailPrinter *emp; EMailParser *parser; EMailPartList *parts; + EMailPrinter *printer; const gchar *message_id; parser = e_mail_parser_new (CAMEL_SESSION (session)); message_id = camel_mime_message_get_message_id (message); - parts = e_mail_parser_parse_sync (parser, NULL, g_strdup (message_id), message, NULL); - - /* Use EMailPrinter and WebKit to print the message */ - emp = e_mail_printer_new (parts); - g_signal_connect ( - emp, "done", - G_CALLBACK (composer_print_done_cb), NULL); + parts = e_mail_parser_parse_sync ( + parser, NULL, g_strdup (message_id), message, NULL); - e_mail_printer_print (emp, action, NULL, NULL); + /* FIXME Show an alert on error. */ + printer = e_mail_printer_new (parts); + e_mail_printer_print (printer, action, NULL, NULL, NULL, NULL); + g_object_unref (printer); g_object_unref (parts); } diff --git a/mail/em-utils.c b/mail/em-utils.c index 994a029a5f..a293efabf8 100644 --- a/mail/em-utils.c +++ b/mail/em-utils.c @@ -592,12 +592,12 @@ do_print_msg_to_file (GObject *source, printer = e_mail_printer_new (parts_list); e_mail_printer_set_export_filename (printer, filename); - g_signal_connect_swapped ( - printer, "done", - G_CALLBACK (g_object_unref), printer); - e_mail_printer_print (printer, GTK_PRINT_OPERATION_ACTION_EXPORT, NULL, NULL); + e_mail_printer_print ( + printer, GTK_PRINT_OPERATION_ACTION_EXPORT, + NULL, NULL, NULL, NULL); + g_object_unref (printer); g_object_unref (parser); } |