diff --git a/.evolution.metadata b/.evolution.metadata
new file mode 100644
index 0000000..fa4f215
--- /dev/null
+++ b/.evolution.metadata
@@ -0,0 +1 @@
+797aa0a263e5f92079e20d3f5e9aa52dc58baccf SOURCES/evolution-3.22.6.tar.xz
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..4a44df2
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+SOURCES/evolution-3.22.6.tar.xz
diff --git a/README.md b/README.md
deleted file mode 100644
index 0e7897f..0000000
--- a/README.md
+++ /dev/null
@@ -1,5 +0,0 @@
-The master branch has no content
-
-Look at the c7 branch if you are working with CentOS-7, or the c4/c5/c6 branch for CentOS-4, 5 or 6
-
-If you find this file in a distro specific branch, it means that no content has been checked in yet
diff --git a/SOURCES/evolution-3.22.6-calendar-print-action.patch b/SOURCES/evolution-3.22.6-calendar-print-action.patch
new file mode 100644
index 0000000..867f87f
--- /dev/null
+++ b/SOURCES/evolution-3.22.6-calendar-print-action.patch
@@ -0,0 +1,12 @@
+diff -up evolution-3.22.6/modules/calendar/e-cal-shell-view-actions.c.calendar-print-action evolution-3.22.6/modules/calendar/e-cal-shell-view-actions.c
+--- evolution-3.22.6/modules/calendar/e-cal-shell-view-actions.c.calendar-print-action 2016-03-21 09:07:26.000000000 +0100
++++ evolution-3.22.6/modules/calendar/e-cal-shell-view-actions.c 2017-04-19 09:33:29.144300407 +0200
+@@ -235,7 +235,7 @@ static void
+ action_calendar_print_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+ {
+- cal_shell_view_actions_print_or_preview (cal_shell_view, GTK_PRINT_OPERATION_ACTION_PRINT);
++ cal_shell_view_actions_print_or_preview (cal_shell_view, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG);
+ }
+
+ static void
diff --git a/SOURCES/evolution-3.22.6-comp-editor-changed.patch b/SOURCES/evolution-3.22.6-comp-editor-changed.patch
new file mode 100644
index 0000000..498c7bb
--- /dev/null
+++ b/SOURCES/evolution-3.22.6-comp-editor-changed.patch
@@ -0,0 +1,20 @@
+diff -up evolution-3.22.6/calendar/gui/e-comp-editor.c.comp-editor-changed evolution-3.22.6/calendar/gui/e-comp-editor.c
+--- evolution-3.22.6/calendar/gui/e-comp-editor.c.comp-editor-changed 2016-09-19 10:22:58.000000000 +0200
++++ evolution-3.22.6/calendar/gui/e-comp-editor.c 2017-04-27 17:09:51.444757546 +0200
+@@ -1021,12 +1021,16 @@ open_target_client_data_free (gpointer p
+ if (otc) {
+ if (otc->comp_editor) {
+ if (otc->client) {
++ gboolean previous_changed = e_comp_editor_get_changed (otc->comp_editor);
++
+ e_comp_editor_set_alarm_email_address (otc->comp_editor, otc->alarm_email_address);
+ e_comp_editor_set_cal_email_address (otc->comp_editor, otc->cal_email_address);
+ e_comp_editor_set_target_client (otc->comp_editor, E_CAL_CLIENT (otc->client));
+
+ if (otc->is_target_client_change)
+ e_comp_editor_set_changed (otc->comp_editor, TRUE);
++ else
++ e_comp_editor_set_changed (otc->comp_editor, previous_changed);
+ }
+
+ if (otc->comp_editor->priv->activity_bar && otc->activity) {
diff --git a/SOURCES/evolution-3.22.6-composer-dnd.patch b/SOURCES/evolution-3.22.6-composer-dnd.patch
new file mode 100644
index 0000000..2dcd001
--- /dev/null
+++ b/SOURCES/evolution-3.22.6-composer-dnd.patch
@@ -0,0 +1,160 @@
+diff -up evolution-3.22.6/composer/e-msg-composer.c.composer-dnd evolution-3.22.6/composer/e-msg-composer.c
+--- evolution-3.22.6/composer/e-msg-composer.c.composer-dnd 2017-04-13 14:06:08.863067766 +0200
++++ evolution-3.22.6/composer/e-msg-composer.c 2017-04-13 14:06:08.878067765 +0200
+@@ -1867,6 +1867,16 @@ msg_composer_drag_drop_cb (GtkWidget *wi
+ }
+
+ static void
++msg_composer_drop_handled_cb (EContentEditor *cnt_editor,
++ EMsgComposer *composer)
++{
++ if (composer->priv->drag_data_received_handler_id != 0) {
++ g_signal_handler_disconnect (cnt_editor, composer->priv->drag_data_received_handler_id);
++ composer->priv->drag_data_received_handler_id = 0;
++ }
++}
++
++static void
+ msg_composer_drag_begin_cb (GtkWidget *widget,
+ GdkDragContext *context,
+ EMsgComposer *composer)
+@@ -2272,6 +2282,10 @@ msg_composer_constructed (GObject *objec
+ G_CALLBACK (msg_composer_drag_begin_cb), composer);
+
+ g_signal_connect (
++ cnt_editor, "drop-handled",
++ G_CALLBACK (msg_composer_drop_handled_cb), composer);
++
++ g_signal_connect (
+ composer->priv->gallery_icon_view, "drag-data-get",
+ G_CALLBACK (msg_composer_gallery_drag_data_get), NULL);
+
+diff -up evolution-3.22.6/e-util/e-content-editor.c.composer-dnd evolution-3.22.6/e-util/e-content-editor.c
+--- evolution-3.22.6/e-util/e-content-editor.c.composer-dnd 2016-11-30 20:06:07.000000000 +0100
++++ evolution-3.22.6/e-util/e-content-editor.c 2017-04-13 14:06:08.878067765 +0200
+@@ -36,6 +36,7 @@ enum {
+ CONTEXT_MENU_REQUESTED,
+ FIND_DONE,
+ REPLACE_ALL_DONE,
++ DROP_HANDLED,
+ LAST_SIGNAL
+ };
+
+@@ -509,6 +510,20 @@ e_content_editor_default_init (EContentE
+ NULL,
+ G_TYPE_NONE, 1,
+ G_TYPE_UINT);
++
++ /**
++ * EContentEditor:drop-handled
++ *
++ * Emitted when the content editor successfully handled the drop operation.
++ */
++ signals[DROP_HANDLED] = g_signal_new (
++ "drop-handled",
++ E_TYPE_CONTENT_EDITOR,
++ G_SIGNAL_RUN_LAST,
++ G_STRUCT_OFFSET (EContentEditorInterface, drop_handled),
++ NULL, NULL,
++ NULL,
++ G_TYPE_NONE, 0);
+ }
+
+ ESpellChecker *
+@@ -3581,3 +3596,11 @@ e_content_editor_emit_replace_all_done (
+
+ g_signal_emit (editor, signals[REPLACE_ALL_DONE], 0, replaced_count);
+ }
++
++void
++e_content_editor_emit_drop_handled (EContentEditor *editor)
++{
++ g_return_if_fail (E_IS_CONTENT_EDITOR (editor));
++
++ g_signal_emit (editor, signals[DROP_HANDLED], 0);
++}
+diff -up evolution-3.22.6/e-util/e-content-editor.h.composer-dnd evolution-3.22.6/e-util/e-content-editor.h
+--- evolution-3.22.6/e-util/e-content-editor.h.composer-dnd 2016-09-19 10:22:58.000000000 +0200
++++ evolution-3.22.6/e-util/e-content-editor.h 2017-04-13 14:06:08.878067765 +0200
+@@ -437,6 +437,7 @@ struct _EContentEditorInterface {
+ guint match_count);
+ void (*replace_all_done) (EContentEditor *editor,
+ guint replaced_count);
++ void (*drop_handled) (EContentEditor *editor);
+ };
+
+ /* Properties */
+@@ -1015,6 +1016,8 @@ void e_content_editor_emit_find_done (E
+ void e_content_editor_emit_replace_all_done
+ (EContentEditor *editor,
+ guint replaced_count);
++void e_content_editor_emit_drop_handled
++ (EContentEditor *editor);
+
+ G_END_DECLS
+
+diff -up evolution-3.22.6/modules/webkit-editor/e-webkit-editor.c.composer-dnd evolution-3.22.6/modules/webkit-editor/e-webkit-editor.c
+--- evolution-3.22.6/modules/webkit-editor/e-webkit-editor.c.composer-dnd 2017-04-13 14:06:08.875067765 +0200
++++ evolution-3.22.6/modules/webkit-editor/e-webkit-editor.c 2017-04-13 14:06:28.256067497 +0200
+@@ -5913,10 +5913,16 @@ webkit_editor_drag_data_received_cb (Gtk
+ info == E_DND_TARGET_TYPE_UTF8_STRING || info == E_DND_TARGET_TYPE_STRING ||
+ info == E_DND_TARGET_TYPE_TEXT_PLAIN || info == E_DND_TARGET_TYPE_TEXT_PLAIN_UTF8) {
+ gdk_drag_status (context, gdk_drag_context_get_selected_action(context), time);
+- GTK_WIDGET_CLASS (e_webkit_editor_parent_class)->drag_drop (widget, context, x, y, time);
+- g_signal_stop_emission_by_name (widget, "drag-data-received");
+- if (!is_move)
+- webkit_editor_call_simple_extension_function (wk_editor, "DOMLastDropOperationDidCopy");
++ if (!GTK_WIDGET_CLASS (e_webkit_editor_parent_class)->drag_drop (widget, context, x, y, time)) {
++ g_warning ("Drop failed in WebKit");
++ goto process_ourselves;
++ } else {
++ GTK_WIDGET_CLASS (e_webkit_editor_parent_class)->drag_leave(widget, context, time);
++ g_signal_stop_emission_by_name (widget, "drag-data-received");
++ if (!is_move)
++ webkit_editor_call_simple_extension_function (wk_editor, "DOMLastDropOperationDidCopy");
++ e_content_editor_emit_drop_handled (E_CONTENT_EDITOR (widget));
++ }
+ return;
+ }
+
+@@ -5926,6 +5932,7 @@ webkit_editor_drag_data_received_cb (Gtk
+ gint list_len, len;
+ gchar *text;
+
++ process_ourselves:
+ data = gtk_selection_data_get_data (selection);
+ length = gtk_selection_data_get_length (selection);
+
+@@ -5949,10 +5956,21 @@ webkit_editor_drag_data_received_cb (Gtk
+
+ gtk_drag_finish (context, TRUE, is_move, time);
+ g_signal_stop_emission_by_name (widget, "drag-data-received");
++ e_content_editor_emit_drop_handled (E_CONTENT_EDITOR (widget));
+ return;
+ }
+ }
+
++static void
++webkit_editor_drag_leave_cb (EWebKitEditor *wk_editor,
++ GdkDragContext *context,
++ guint time)
++{
++ /* Don't pass drag-leave to WebKit otherwise the drop won't be handled by it.
++ * We will emit it later when WebKit is expecting it. */
++ g_signal_stop_emission_by_name (GTK_WIDGET (wk_editor), "drag-leave");
++}
++
+ static gboolean
+ webkit_editor_drag_drop_cb (EWebKitEditor *wk_editor,
+ GdkDragContext *context,
+@@ -6255,6 +6273,10 @@ e_webkit_editor_init (EWebKitEditor *wk_
+ G_CALLBACK (webkit_editor_drag_end_cb), NULL);
+
+ g_signal_connect (
++ wk_editor, "drag-leave",
++ G_CALLBACK (webkit_editor_drag_leave_cb), NULL);
++
++ g_signal_connect (
+ wk_editor, "drag-drop",
+ G_CALLBACK (webkit_editor_drag_drop_cb), NULL);
+
diff --git a/SOURCES/evolution-3.22.6-composer-font-color.patch b/SOURCES/evolution-3.22.6-composer-font-color.patch
new file mode 100644
index 0000000..e04217a
--- /dev/null
+++ b/SOURCES/evolution-3.22.6-composer-font-color.patch
@@ -0,0 +1,85 @@
+diff -up evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-dom-functions.c.composer-font-color evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-dom-functions.c
+--- evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-dom-functions.c.composer-font-color 2017-03-24 13:43:34.992659166 +0100
++++ evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-dom-functions.c 2017-03-24 13:43:34.997659165 +0100
+@@ -2834,6 +2834,8 @@ body_keypress_event_cb (WebKitDOMElement
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
++ e_editor_page_set_is_processing_keypress_event (editor_page, TRUE);
++
+ document = webkit_dom_node_get_owner_document (WEBKIT_DOM_NODE (element));
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+@@ -3583,7 +3585,13 @@ body_input_event_cb (WebKitDOMElement *e
+ {
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+- e_editor_dom_body_input_event_process (editor_page, event);
++ /* Only process the input event if it was triggered by the key press
++ * and not i.e. by exexCommand. This behavior changed when the support
++ * for beforeinput event was introduced in WebKit. */
++ if (e_editor_page_is_processing_keypress_event (editor_page))
++ e_editor_dom_body_input_event_process (editor_page, event);
++
++ e_editor_page_set_is_processing_keypress_event (editor_page, FALSE);
+ }
+
+ void
+diff -up evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-page.c.composer-font-color evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-page.c
+--- evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-page.c.composer-font-color 2017-02-07 17:48:51.000000000 +0100
++++ evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-page.c 2017-03-24 13:43:34.997659165 +0100
+@@ -64,6 +64,7 @@ struct _EEditorPagePrivate {
+ gboolean pasting_content_from_itself;
+ gboolean renew_history_after_coordinates;
+ gboolean allow_top_signature;
++ gboolean processing_keypress_event;
+
+ GHashTable *inline_images;
+
+@@ -246,6 +247,7 @@ e_editor_page_init (EEditorPage *editor_
+ editor_page->priv->block_format = E_CONTENT_EDITOR_BLOCK_FORMAT_PARAGRAPH;
+ editor_page->priv->force_image_load = FALSE;
+ editor_page->priv->html_mode = TRUE;
++ editor_page->priv->processing_keypress_event = FALSE;
+ editor_page->priv->return_key_pressed = FALSE;
+ editor_page->priv->space_key_pressed = FALSE;
+ editor_page->priv->smiley_written = FALSE;
+@@ -559,6 +561,23 @@ e_editor_page_set_alignment (EEditorPage
+ }
+
+ gboolean
++e_editor_page_is_processing_keypress_event (EEditorPage *editor_page)
++{
++ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
++
++ return editor_page->priv->processing_keypress_event;
++}
++
++void
++e_editor_page_set_is_processing_keypress_event (EEditorPage *editor_page,
++ gboolean processing_keypress_event)
++{
++ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
++
++ editor_page->priv->processing_keypress_event = processing_keypress_event;
++}
++
++gboolean
+ e_editor_page_get_return_key_pressed (EEditorPage *editor_page)
+ {
+ g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+diff -up evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-page.h.composer-font-color evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-page.h
+--- evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-page.h.composer-font-color 2017-02-07 17:48:51.000000000 +0100
++++ evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-page.h 2017-03-24 13:43:34.997659165 +0100
+@@ -112,6 +112,11 @@ void e_editor_page_set_alignment (EEdit
+ EContentEditorAlignment value);
+ gint e_editor_page_get_word_wrap_length
+ (EEditorPage *editor_page);
++gboolean e_editor_page_is_processing_keypress_event
++ (EEditorPage *editor_page);
++void e_editor_page_set_is_processing_keypress_event
++ (EEditorPage *editor_page,
++ gboolean processing_keypress_event);
+ gboolean e_editor_page_get_return_key_pressed
+ (EEditorPage *editor_page);
+ void e_editor_page_set_return_key_pressed
diff --git a/SOURCES/evolution-3.22.6-composer-image-insert-undo.patch b/SOURCES/evolution-3.22.6-composer-image-insert-undo.patch
new file mode 100644
index 0000000..0a6a6db
--- /dev/null
+++ b/SOURCES/evolution-3.22.6-composer-image-insert-undo.patch
@@ -0,0 +1,3086 @@
+diff -up evolution-3.22.6/composer/e-composer-private.c.composer-image-insert-undo evolution-3.22.6/composer/e-composer-private.c
+--- evolution-3.22.6/composer/e-composer-private.c.composer-image-insert-undo 2016-09-19 10:22:58.000000000 +0200
++++ evolution-3.22.6/composer/e-composer-private.c 2017-03-24 15:12:21.893422514 +0100
+@@ -134,8 +134,6 @@ e_composer_private_constructed (EMsgComp
+ priv->disable_signature = FALSE;
+ priv->busy = FALSE;
+ priv->saved_editable = FALSE;
+- priv->drop_occured = FALSE;
+- priv->dnd_is_uri = FALSE;
+ priv->dnd_history_saved = FALSE;
+ priv->check_if_signature_is_changed = FALSE;
+ priv->ignore_next_signature_change = FALSE;
+diff -up evolution-3.22.6/composer/e-composer-private.h.composer-image-insert-undo evolution-3.22.6/composer/e-composer-private.h
+--- evolution-3.22.6/composer/e-composer-private.h.composer-image-insert-undo 2016-09-19 10:22:58.000000000 +0200
++++ evolution-3.22.6/composer/e-composer-private.h 2017-03-24 15:12:21.893422514 +0100
+@@ -100,8 +100,6 @@ struct _EMsgComposerPrivate {
+ * This is used to restore the previous editable state. */
+ gboolean saved_editable;
+ gboolean set_signature_from_message;
+- gboolean drop_occured;
+- gboolean dnd_is_uri;
+ gboolean is_sending_message;
+ gboolean dnd_history_saved;
+ gboolean check_if_signature_is_changed;
+@@ -119,6 +117,8 @@ struct _EMsgComposerPrivate {
+ gulong notify_signature_uid_handler;
+ gulong notify_subject_handler;
+ gulong notify_subject_changed_handler;
++
++ gulong drag_data_received_handler_id;
+ };
+
+ void e_composer_private_constructed (EMsgComposer *composer);
+diff -up evolution-3.22.6/composer/e-msg-composer.c.composer-image-insert-undo evolution-3.22.6/composer/e-msg-composer.c
+--- evolution-3.22.6/composer/e-msg-composer.c.composer-image-insert-undo 2016-11-30 20:06:07.000000000 +0100
++++ evolution-3.22.6/composer/e-msg-composer.c 2017-03-24 15:12:21.894422514 +0100
+@@ -105,24 +105,14 @@ enum {
+ LAST_SIGNAL
+ };
+
+-enum DndTargetType {
+- DND_TARGET_TYPE_TEXT_URI_LIST,
+- DND_TARGET_TYPE_MOZILLA_URL,
+- DND_TARGET_TYPE_TEXT_HTML,
+- DND_TARGET_TYPE_UTF8_STRING,
+- DND_TARGET_TYPE_TEXT_PLAIN,
+- DND_TARGET_TYPE_STRING,
+- DND_TARGET_TYPE_TEXT_PLAIN_UTF8
+-};
+-
+ static GtkTargetEntry drag_dest_targets[] = {
+- { (gchar *) "text/uri-list", 0, DND_TARGET_TYPE_TEXT_URI_LIST },
+- { (gchar *) "_NETSCAPE_URL", 0, DND_TARGET_TYPE_MOZILLA_URL },
+- { (gchar *) "text/html", 0, DND_TARGET_TYPE_TEXT_HTML },
+- { (gchar *) "UTF8_STRING", 0, DND_TARGET_TYPE_UTF8_STRING },
+- { (gchar *) "text/plain", 0, DND_TARGET_TYPE_TEXT_PLAIN },
+- { (gchar *) "STRING", 0, DND_TARGET_TYPE_STRING },
+- { (gchar *) "text/plain;charset=utf-8", 0, DND_TARGET_TYPE_TEXT_PLAIN_UTF8 },
++ { (gchar *) "text/uri-list", 0, E_DND_TARGET_TYPE_TEXT_URI_LIST },
++ { (gchar *) "_NETSCAPE_URL", 0, E_DND_TARGET_TYPE_MOZILLA_URL },
++ { (gchar *) "text/html", 0, E_DND_TARGET_TYPE_TEXT_HTML },
++ { (gchar *) "UTF8_STRING", 0, E_DND_TARGET_TYPE_UTF8_STRING },
++ { (gchar *) "text/plain", 0, E_DND_TARGET_TYPE_TEXT_PLAIN },
++ { (gchar *) "STRING", 0, E_DND_TARGET_TYPE_STRING },
++ { (gchar *) "text/plain;charset=utf-8", 0, E_DND_TARGET_TYPE_TEXT_PLAIN_UTF8 },
+ };
+
+ static guint signals[LAST_SIGNAL];
+@@ -1784,160 +1774,6 @@ msg_composer_paste_clipboard_cb (EConten
+
+ return TRUE;
+ }
+-#if 0 /* FIXME WK2 */
+-static gboolean
+-msg_composer_drag_motion_cb (GtkWidget *widget,
+- GdkDragContext *context,
+- gint x,
+- gint y,
+- guint time,
+- EMsgComposer *composer)
+-{
+- GtkWidget *source_widget;
+- EHTMLEditor *editor = e_msg_composer_get_editor (composer);
+- EHTMLEditorView *editor_view = e_html_editor_get_view (editor);
+-
+- source_widget = gtk_drag_get_source_widget (context);
+- /* When we are doind DnD just inside the web view, the DnD is supposed
+- * to move things around. */
+- if (E_IS_HTML_EDITOR_VIEW (source_widget)) {
+- if ((gpointer) editor_view == (gpointer) source_widget) {
+- gdk_drag_status (context, GDK_ACTION_MOVE, time);
+-
+- return FALSE;
+- }
+- }
+-
+- gdk_drag_status (context, GDK_ACTION_COPY, time);
+-
+- return FALSE;
+-}
+-
+-static gboolean
+-msg_composer_drag_drop_cb (GtkWidget *widget,
+- GdkDragContext *context,
+- gint x,
+- gint y,
+- guint time,
+- EMsgComposer *composer)
+-{
+- GdkAtom target;
+- GtkWidget *source_widget;
+-
+- /* When we are doing DnD just inside the web view, the DnD is supposed
+- * to move things around. */
+- source_widget = gtk_drag_get_source_widget (context);
+- if (E_IS_HTML_EDITOR_VIEW (source_widget)) {
+- EHTMLEditor *editor = e_msg_composer_get_editor (composer);
+- EHTMLEditorView *editor_view = e_html_editor_get_view (editor);
+-
+- if ((gpointer) editor_view == (gpointer) source_widget) {
+- GDBusProxy *web_extension;
+-
+- web_extension = e_html_editor_view_get_web_extension_proxy (editor_view);
+- if (web_extension) {
+- e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
+- web_extension,
+- "DOMSaveDragAndDropHistory",
+- g_variant_new (
+- "(t)",
+- webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (editor_view))),
+- NULL);
+- }
+- return FALSE;
+- }
+- }
+-
+- target = gtk_drag_dest_find_target (widget, context, NULL);
+- if (target == GDK_NONE)
+- gdk_drag_status (context, 0, time);
+- else {
+- /* Prevent WebKit from pasting the URI of file into the view. Also
+- * prevent it from inserting the text/plain or text/html content as we
+- * want to insert it ourselves. */
+- if (composer->priv->dnd_is_uri || !E_IS_HTML_EDITOR_VIEW (source_widget))
+- g_signal_stop_emission_by_name (widget, "drag-drop");
+-
+- composer->priv->dnd_is_uri = FALSE;
+-
+- if (E_IS_HTML_EDITOR_VIEW (source_widget))
+- gdk_drag_status (context, GDK_ACTION_MOVE, time);
+- else
+- gdk_drag_status (context, GDK_ACTION_COPY, time);
+-
+- composer->priv->drop_occured = TRUE;
+- gtk_drag_get_data (widget, context, target, time);
+-
+- return TRUE;
+- }
+-
+- return FALSE;
+-}
+-
+-static void
+-msg_composer_drag_data_received_after_cb (GtkWidget *widget,
+- GdkDragContext *context,
+- gint x,
+- gint y,
+- GtkSelectionData *selection,
+- guint info,
+- guint time,
+- EMsgComposer *composer)
+-{
+- EHTMLEditor *editor;
+- EHTMLEditorView *view;
+- GDBusProxy *web_extension;
+-
+- if (!composer->priv->drop_occured)
+- goto out;
+-
+- /* Save just history for events handled by WebKit. */
+- if (composer->priv->dnd_history_saved)
+- goto out;
+-
+- editor = e_msg_composer_get_editor (composer);
+- view = e_html_editor_get_view (editor);
+- web_extension = e_html_editor_view_get_web_extension_proxy (view);
+- if (!web_extension)
+- goto out;
+-
+- e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
+- web_extension,
+- "DOMCleanAfterDragAndDrop",
+- g_variant_new (
+- "(t)",
+- webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (view))),
+- NULL);
+-
+- out:
+- composer->priv->drop_occured = FALSE;
+- composer->priv->dnd_history_saved = FALSE;
+-}
+-
+-static gchar *
+-next_uri (guchar **uri_list,
+- gint *len,
+- gint *list_len)
+-{
+- guchar *uri, *begin;
+-
+- begin = *uri_list;
+- *len = 0;
+- while (**uri_list && **uri_list != '\n' && **uri_list != '\r' && *list_len) {
+- (*uri_list) ++;
+- (*len) ++;
+- (*list_len) --;
+- }
+-
+- uri = (guchar *) g_strndup ((gchar *) begin, *len);
+-
+- while ((!**uri_list || **uri_list == '\n' || **uri_list == '\r') && *list_len) {
+- (*uri_list) ++;
+- (*list_len) --;
+- }
+-
+- return (gchar *) uri;
+-}
+
+ static void
+ msg_composer_drag_data_received_cb (GtkWidget *widget,
+@@ -1951,90 +1787,16 @@ msg_composer_drag_data_received_cb (GtkW
+ {
+ EHTMLEditor *editor;
+ EContentEditor *cnt_editor;
+- gboolean html_mode, same_widget = FALSE;
+- GtkWidget *source_widget;
++ gboolean html_mode, is_move;
+
+ editor = e_msg_composer_get_editor (composer);
+ cnt_editor = e_html_editor_get_content_editor (editor);
+ html_mode = e_content_editor_get_html_mode (cnt_editor);
+
+- composer->priv->dnd_history_saved = TRUE;
+-
+- /* When we are doing DnD just inside the web view, the DnD is supposed
+- * to move things around. */
+- source_widget = gtk_drag_get_source_widget (context);
+- if (E_IS_CONTENT_EDITOR (source_widget) &&
+- ((gpointer) cnt_editor == (gpointer) source_widget))
+- same_widget = TRUE;
+-
+- /* Leave DnD inside the view on WebKit. */
+- if (composer->priv->drop_occured && same_widget) {
+- gdk_drag_status (context, 0, time);
+- return;
+- }
+-
+- if (!composer->priv->drop_occured) {
+- if (!same_widget) {
+- /* Check if we are DnD'ing some URI, if so WebKit will
+- * insert the URI into the view and we have to prevent it
+- * from doing that. */
+- if (info == DND_TARGET_TYPE_TEXT_URI_LIST) {
+- gchar **uris;
+-
+- uris = gtk_selection_data_get_uris (selection);
+- /* I don't know what regressed outside of Evo, but
+- * this is called twice. Firstly with uris set
+- * following by one with uris not set. */
+- if (!composer->priv->dnd_is_uri)
+- composer->priv->dnd_is_uri = uris != NULL;
+- g_strfreev (uris);
+- }
+- }
+- return;
+- }
++ g_signal_handler_disconnect (cnt_editor, composer->priv->drag_data_received_handler_id);
++ composer->priv->drag_data_received_handler_id = 0;
+
+- composer->priv->dnd_is_uri = FALSE;
+-
+- /* Leave the text on WebKit to handle it. */
+- if (info == DND_TARGET_TYPE_UTF8_STRING ||
+- info == DND_TARGET_TYPE_STRING ||
+- info == DND_TARGET_TYPE_TEXT_PLAIN ||
+- info == DND_TARGET_TYPE_TEXT_PLAIN_UTF8) {
+- composer->priv->dnd_history_saved = FALSE;
+- gdk_drag_status (context, 0, time);
+- return;
+- }
+-
+- if (info == DND_TARGET_TYPE_TEXT_HTML) {
+- const guchar *data;
+- gint length;
+- gint list_len, len;
+- gchar *text;
+-
+- data = gtk_selection_data_get_data (selection);
+- length = gtk_selection_data_get_length (selection);
+-
+- if (!data || length < 0) {
+- gtk_drag_finish (context, FALSE, FALSE, time);
+- return;
+- }
+-
+- e_content_editor_move_caret_on_coordinates (cnt_editor, x, y, FALSE);
+-
+- list_len = length;
+- do {
+- text = next_uri ((guchar **) &data, &len, &list_len);
+- e_content_editor_insert_content (
+- cnt_editor,
+- text,
+- E_CONTENT_EDITOR_INSERT_TEXT_HTML);
+- g_free (text);
+- } while (list_len);
+-
+- gtk_drag_finish (context, TRUE, FALSE, time);
+-
+- return;
+- }
++ is_move = gdk_drag_context_get_selected_action (context) == GDK_ACTION_MOVE;
+
+ /* HTML mode has a few special cases for drops... */
+ /* If we're receiving URIs and -all- the URIs point to
+@@ -2060,12 +1822,12 @@ msg_composer_drag_data_received_cb (GtkW
+
+ list_len = length;
+ do {
+- uri = next_uri ((guchar **) &data, &len, &list_len);
++ uri = e_util_next_uri_from_uri_list ((guchar **) &data, &len, &list_len);
+ e_content_editor_insert_image (cnt_editor, uri);
+ g_free (uri);
+ } while (list_len);
+
+- gtk_drag_finish (context, TRUE, FALSE, time);
++ gtk_drag_finish (context, TRUE, is_move, time);
+ } else {
+ EAttachmentView *attachment_view =
+ e_msg_composer_get_attachment_view (composer);
+@@ -2078,7 +1840,43 @@ msg_composer_drag_data_received_cb (GtkW
+ context, x, y, selection, info, time);
+ }
+ }
+-#endif
++
++static gboolean
++msg_composer_drag_drop_cb (GtkWidget *widget,
++ GdkDragContext *context,
++ gint x,
++ gint y,
++ guint time,
++ EMsgComposer *composer)
++{
++ GdkAtom target = gtk_drag_dest_find_target (widget, context, NULL);
++
++ if (target == GDK_NONE) {
++ gdk_drag_status (context, 0, time);
++ } else {
++ composer->priv->drag_data_received_handler_id = g_signal_connect (
++ E_CONTENT_EDITOR (widget), "drag-data-received",
++ G_CALLBACK (msg_composer_drag_data_received_cb), composer);
++
++ gtk_drag_get_data (widget, context, target, time);
++
++ return TRUE;
++ }
++
++ return FALSE;
++}
++
++static void
++msg_composer_drag_begin_cb (GtkWidget *widget,
++ GdkDragContext *context,
++ EMsgComposer *composer)
++{
++ if (composer->priv->drag_data_received_handler_id != 0) {
++ g_signal_handler_disconnect (E_CONTENT_EDITOR( widget), composer->priv->drag_data_received_handler_id);
++ composer->priv->drag_data_received_handler_id = 0;
++ }
++}
++
+ static void
+ msg_composer_notify_header_cb (EMsgComposer *composer)
+ {
+@@ -2465,28 +2263,14 @@ msg_composer_constructed (GObject *objec
+ G_CALLBACK (msg_composer_paste_primary_clipboard_cb), composer);
+
+ /* Drag-and-Drop Support */
+-#if 0 /* FIXME WK2 */
+- EHTMLEditorView *view;
+-
+- view = e_html_editor_get_view (editor);
+-
+ g_signal_connect (
+- view, "drag-motion",
+- G_CALLBACK (msg_composer_drag_motion_cb), composer);
+-
+- g_signal_connect (
+- view, "drag-drop",
++ cnt_editor, "drag-drop",
+ G_CALLBACK (msg_composer_drag_drop_cb), composer);
+
+ g_signal_connect (
+- view, "drag-data-received",
+- G_CALLBACK (msg_composer_drag_data_received_cb), composer);
++ cnt_editor, "drag-begin",
++ G_CALLBACK (msg_composer_drag_begin_cb), composer);
+
+- /* Used for fixing various stuff after WebKit processed the DnD data. */
+- g_signal_connect_after (
+- view, "drag-data-received",
+- G_CALLBACK (msg_composer_drag_data_received_after_cb), composer);
+-#endif
+ g_signal_connect (
+ composer->priv->gallery_icon_view, "drag-data-get",
+ G_CALLBACK (msg_composer_gallery_drag_data_get), NULL);
+@@ -5531,8 +5315,6 @@ e_msg_composer_restore_focus_on_composer
+
+ if (E_IS_CONTENT_EDITOR (widget)) {
+ EContentEditor *cnt_editor = E_CONTENT_EDITOR (widget);
+- /* FIXME WK2
+- e_html_editor_view_force_spell_check (view);*/
+ e_content_editor_selection_restore (cnt_editor);
+ }
+
+diff -up evolution-3.22.6/e-util/e-attachment-view.c.composer-image-insert-undo evolution-3.22.6/e-util/e-attachment-view.c
+--- evolution-3.22.6/e-util/e-attachment-view.c.composer-image-insert-undo 2016-09-19 10:22:58.000000000 +0200
++++ evolution-3.22.6/e-util/e-attachment-view.c 2017-03-24 15:12:21.894422514 +0100
+@@ -39,6 +39,7 @@ enum {
+
+ /* Note: Do not use the info field. */
+ static GtkTargetEntry target_table[] = {
++ { (gchar *) "text/uri-list", 0, 0 },
+ { (gchar *) "_NETSCAPE_URL", 0, 0 }
+ };
+
+@@ -428,6 +429,125 @@ attachment_view_netscape_url (EAttachmen
+ }
+
+ static void
++attachment_view_uri_list (EAttachmentView *view,
++ GdkDragContext *drag_context,
++ gint x,
++ gint y,
++ GtkSelectionData *selection_data,
++ guint info,
++ guint time)
++{
++ static GdkAtom atom = GDK_NONE;
++ EAttachmentStore *store;
++ EAttachment *attachment;
++ const gchar *data;
++ gpointer parent;
++ gint length = 0, list_length = 0, uri_length = 0;
++ gchar *uri;
++
++
++ if (G_UNLIKELY (atom == GDK_NONE))
++ atom = gdk_atom_intern_static_string ("text/uri-list");
++
++ if (gtk_selection_data_get_target (selection_data) != atom)
++ return;
++
++ g_signal_stop_emission_by_name (view, "drag-data-received");
++
++ data = (const gchar *) gtk_selection_data_get_data (selection_data);
++ length = gtk_selection_data_get_length (selection_data);
++
++ if (!data || length < 0) {
++ gtk_drag_finish (drag_context, FALSE, FALSE, time);
++ return;
++ }
++
++ store = e_attachment_view_get_store (view);
++
++ parent = gtk_widget_get_toplevel (GTK_WIDGET (view));
++ parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
++
++ list_length = length;
++ do {
++ uri = e_util_next_uri_from_uri_list ((guchar **) &data, &uri_length, &list_length);
++
++ if (strstr (uri, ";base64,")) {
++ /* base64 encoded data */
++ CamelMimePart *mime_part;
++ gchar *mime_type = NULL, *filename = NULL;
++ guchar *base64_data;
++ gsize base64_data_length;
++
++ if (g_str_has_prefix (uri, "data:")) {
++ const gchar *base64 = strstr (uri, ";") + 1;
++ /* strlen ("data:") == 5 */
++ mime_type = g_strndup (uri + 5, base64 - uri - 5 - 1);
++
++ base64 = strstr (base64, ",") + 1;
++ base64_data = g_base64_decode (base64, &base64_data_length);
++ } else if (strstr (uri, ";data")) {
++ /* CID attachment from mail preview that has
++ * the filename prefixed before the base64 data -
++ * see EMailDisplay. */
++ const gchar *base64 = strstr (uri, ";") + 1;
++ glong filename_length, mime_type_length, base64_length;
++
++ base64_length = g_utf8_strlen (base64, -1);
++
++ filename_length = uri_length - base64_length - 1;
++ filename = g_strndup (uri, filename_length);
++
++ /* strlen ("data:") == 5 */
++ mime_type_length = base64_length - g_utf8_strlen (strstr (base64, ";"), -1) - 5;
++ mime_type = g_strndup (uri + filename_length + 5 + 1, mime_type_length);
++
++ base64 = strstr (base64, ",") + 1;
++ base64_data = g_base64_decode (base64, &base64_data_length);
++ } else {
++ g_free (uri);
++ gtk_drag_finish (drag_context, FALSE, FALSE, time);
++ return;
++ }
++
++ mime_part = camel_mime_part_new ();
++
++ camel_mime_part_set_content (mime_part, (const gchar *) base64_data, base64_data_length, mime_type);
++ camel_mime_part_set_disposition (mime_part, "inline");
++ if (filename && *filename)
++ camel_mime_part_set_filename (mime_part, filename);
++ camel_mime_part_set_encoding (mime_part, CAMEL_TRANSFER_ENCODING_BASE64);
++
++ attachment = e_attachment_new ();
++ e_attachment_set_mime_part (attachment, mime_part);
++ e_attachment_store_add_attachment (store, attachment);
++ e_attachment_load_async (
++ attachment, (GAsyncReadyCallback)
++ call_attachment_load_handle_error, parent ? g_object_ref (parent) : NULL);
++
++ g_object_unref (attachment);
++ g_object_unref (mime_part);
++ if (mime_type)
++ g_free (mime_type);
++ if (filename)
++ g_free (filename);
++ g_free (base64_data);
++ } else {
++ /* regular URIs */
++ attachment = e_attachment_new_for_uri (uri);
++ e_attachment_store_add_attachment (store, attachment);
++ e_attachment_load_async (
++ attachment, (GAsyncReadyCallback)
++ call_attachment_load_handle_error, parent ? g_object_ref (parent) : NULL);
++ g_object_unref (attachment);
++ }
++
++ g_free (uri);
++ } while (list_length);
++
++ gtk_drag_finish (drag_context, TRUE, FALSE, time);
++}
++
++static void
+ attachment_view_text_calendar (EAttachmentView *view,
+ GdkDragContext *drag_context,
+ gint x,
+@@ -809,6 +929,10 @@ e_attachment_view_init (EAttachmentView
+
+ g_signal_connect (
+ view, "drag-data-received",
++ G_CALLBACK (attachment_view_uri_list), NULL);
++
++ g_signal_connect (
++ view, "drag-data-received",
+ G_CALLBACK (attachment_view_text_x_vcard), NULL);
+
+ g_signal_connect (
+diff -up evolution-3.22.6/e-util/e-html-editor-dialog.h.composer-image-insert-undo evolution-3.22.6/e-util/e-html-editor-dialog.h
+--- evolution-3.22.6/e-util/e-html-editor-dialog.h.composer-image-insert-undo 2016-09-19 10:22:58.000000000 +0200
++++ evolution-3.22.6/e-util/e-html-editor-dialog.h 2017-03-24 15:12:21.894422514 +0100
+@@ -62,16 +62,6 @@ struct _EHTMLEditorDialogClass {
+ GtkWindowClass parent_class;
+ };
+
+-#if 0 /* FIXME WK2 */
+-struct _EContentEditorDialogInterface {
+- GTypeInterface parent_interface;
+-
+- void (*dialog_opened) (EContentEditorDialog *dialog);
+-
+- void (*dialog_closed) (EContentEditorDialog *dialog);
+-};
+-#endif
+-
+ GType e_html_editor_dialog_get_type (void) G_GNUC_CONST;
+ EHTMLEditor * e_html_editor_dialog_get_editor (EHTMLEditorDialog *dialog);
+ GtkBox * e_html_editor_dialog_get_button_box
+diff -up evolution-3.22.6/e-util/e-misc-utils.c.composer-image-insert-undo evolution-3.22.6/e-util/e-misc-utils.c
+--- evolution-3.22.6/e-util/e-misc-utils.c.composer-image-insert-undo 2017-01-18 11:36:05.000000000 +0100
++++ evolution-3.22.6/e-util/e-misc-utils.c 2017-03-24 15:12:21.894422514 +0100
+@@ -3908,3 +3908,38 @@ e_util_get_webkit_developer_mode_enabled
+
+ return enabled != 0;
+ }
++
++/**
++ * e_util_next_uri_from_uri_list:
++ * @uri_list: array of URIs separated by new lines
++ * @len: (out): a length of the found URI
++ * @list_len: (out): a length of the array
++ *
++ * Returns: A newly allocated string with found URI.
++ *
++ * Since: 3.26
++ **/
++gchar *
++e_util_next_uri_from_uri_list (guchar **uri_list,
++ gint *len,
++ gint *list_len)
++{
++ guchar *uri, *begin;
++
++ begin = *uri_list;
++ *len = 0;
++ while (**uri_list && **uri_list != '\n' && **uri_list != '\r' && *list_len) {
++ (*uri_list) ++;
++ (*len) ++;
++ (*list_len) --;
++ }
++
++ uri = (guchar *) g_strndup ((gchar *) begin, *len);
++
++ while ((!**uri_list || **uri_list == '\n' || **uri_list == '\r') && *list_len) {
++ (*uri_list) ++;
++ (*list_len) --;
++ }
++
++ return (gchar *) uri;
++}
+diff -up evolution-3.22.6/e-util/e-misc-utils.h.composer-image-insert-undo evolution-3.22.6/e-util/e-misc-utils.h
+--- evolution-3.22.6/e-util/e-misc-utils.h.composer-image-insert-undo 2017-01-18 11:36:05.000000000 +0100
++++ evolution-3.22.6/e-util/e-misc-utils.h 2017-03-24 15:12:21.894422514 +0100
+@@ -332,6 +332,9 @@ void e_util_save_file_chooser_folder (G
+ void e_util_load_file_chooser_folder (GtkFileChooser *file_chooser);
+ gboolean e_util_get_webkit_developer_mode_enabled
+ (void);
++gchar * e_util_next_uri_from_uri_list (guchar **uri_list,
++ gint *len,
++ gint *list_len);
+
+ G_END_DECLS
+
+diff -up evolution-3.22.6/e-util/e-util-enums.h.composer-image-insert-undo evolution-3.22.6/e-util/e-util-enums.h
+--- evolution-3.22.6/e-util/e-util-enums.h.composer-image-insert-undo 2016-11-28 16:56:59.000000000 +0100
++++ evolution-3.22.6/e-util/e-util-enums.h 2017-03-24 15:12:21.894422514 +0100
+@@ -548,6 +548,30 @@ typedef enum {
+ E_CLIPBOARD_CAN_PASTE = 1 << 2 */
+ } EClipboardFlags;
+
++/**
++ * EDnDTargetType:
++ * DND_TARGET_TYPE_TEXT_URI_LIST: text/uri-list
++ * DND_TARGET_TYPE_MOZILLA_URL: _NETSCAPE_URL
++ * DND_TARGET_TYPE_TEXT_HTML: text/html
++ * DND_TARGET_TYPE_UTF8_STRING: UTF8_STRING
++ * DND_TARGET_TYPE_TEXT_PLAIN: text/plain
++ * DND_TARGET_TYPE_STRING: STRING
++ * DND_TARGET_TYPE_TEXT_PLAIN_UTF8: text/plain;charser=utf-8
++ *
++ * Drag and drop targets supported by EContentEditor.
++ *
++ * Since: 3.26
++ **/
++typedef enum {
++ E_DND_TARGET_TYPE_TEXT_URI_LIST = 0,
++ E_DND_TARGET_TYPE_MOZILLA_URL,
++ E_DND_TARGET_TYPE_TEXT_HTML,
++ E_DND_TARGET_TYPE_UTF8_STRING,
++ E_DND_TARGET_TYPE_TEXT_PLAIN,
++ E_DND_TARGET_TYPE_STRING,
++ E_DND_TARGET_TYPE_TEXT_PLAIN_UTF8
++} EDnDTargetType;
++
+ G_END_DECLS
+
+ #endif /* E_UTIL_ENUMS_H */
+diff -up evolution-3.22.6/e-util/e-web-view.c.composer-image-insert-undo evolution-3.22.6/e-util/e-web-view.c
+--- evolution-3.22.6/e-util/e-web-view.c.composer-image-insert-undo 2017-01-27 12:06:11.000000000 +0100
++++ evolution-3.22.6/e-util/e-web-view.c 2017-03-24 15:12:21.895422514 +0100
+@@ -2386,11 +2386,7 @@ e_web_view_init (EWebView *web_view)
+ g_signal_connect (
+ web_view, "load-changed",
+ G_CALLBACK (web_view_load_changed_cb), NULL);
+-/* FIXME WK2
+- g_signal_connect (
+- web_view, "document-load-finished",
+- G_CALLBACK (style_updated_cb), NULL);
+-*/
++
+ g_signal_connect (
+ web_view, "style-updated",
+ G_CALLBACK (style_updated_cb), NULL);
+diff -up evolution-3.22.6/e-util/test-html-editor-units.c.composer-image-insert-undo evolution-3.22.6/e-util/test-html-editor-units.c
+--- evolution-3.22.6/e-util/test-html-editor-units.c.composer-image-insert-undo 2017-03-24 15:12:21.888422514 +0100
++++ evolution-3.22.6/e-util/test-html-editor-units.c 2017-03-24 15:12:21.895422514 +0100
+@@ -978,6 +978,8 @@ test_image_insert (TestFixture *fixture)
+ /* Mimic what the action:insert-image does, without invoking the image chooser dialog */
+ cnt_editor = e_html_editor_get_content_editor (fixture->editor);
+ e_content_editor_insert_image (cnt_editor, uri);
++ /* Wait some time until the operation is finished */
++ test_utils_wait_milliseconds (500);
+
+ g_free (uri);
+
+@@ -991,6 +993,10 @@ test_image_insert (TestFixture *fixture)
+ g_free (image_data);
+
+ if (!test_utils_run_simple_test (fixture,
++ "undo:save\n" /* 1 */
++ "undo:undo\n"
++ "undo:redo\n"
++ "undo:test:1\n"
+ "type:+after\n",
+ expected_html,
+ "before*+after"))
+@@ -2663,6 +2669,48 @@ test_delete_after_quoted (TestFixture *f
+ g_test_fail ();
+ }
+
++static void
++test_replace_dialog (TestFixture *fixture)
++{
++ if (!test_utils_run_simple_test (fixture,
++ "mode:plain\n"
++ "type:text to replace\n"
++ "undo:save\n" /* 1 */
++ "seq:h\n"
++ "action:show-replace\n"
++ "type:to\t2\n"
++ "type:\t\t\t\t\t\t\n" /* Jump to 'Replace' */
++ "seq:n\n" /* Press it */
++ "seq:^\n" /* Close the dialog */
++ "undo:undo\n"
++ "undo:test:1\n"
++ "undo:redo\n",
++ HTML_PREFIX "
text 2 replace
" HTML_SUFFIX,
++ "text 2 replace"))
++ g_test_fail ();
++}
++
++static void
++test_replace_dialog_all (TestFixture *fixture)
++{
++ if (!test_utils_run_simple_test (fixture,
++ "mode:plain\n"
++ "type:text to replace\n"
++ "undo:save\n" /* 1 */
++ "seq:h\n"
++ "action:show-replace\n"
++ "type:e\t3\n"
++ "type:\t\t\t\t\t\t\t\n" /* Jump to 'Replace All' */
++ "seq:n\n" /* Press it */
++ "seq:^\n" /* Close the dialog */
++ "undo:undo\n"
++ "undo:test:1\n"
++ "undo:redo\n",
++ HTML_PREFIX "t3xt to r3plac3
" HTML_SUFFIX,
++ "t3xt to r3plac3"))
++ g_test_fail ();
++}
++
+ gint
+ main (gint argc,
+ gchar *argv[])
+@@ -2824,6 +2872,8 @@ main (gint argc,
+ test_utils_add_test ("/undo/link-paste/plain", test_undo_link_paste_plain);
+ test_utils_add_test ("/delete/quoted", test_delete_quoted);
+ test_utils_add_test ("/delete/after-quoted", test_delete_after_quoted);
++ test_utils_add_test ("/replace/dialog", test_replace_dialog);
++ test_utils_add_test ("/replace-all/dialog", test_replace_dialog_all);
+
+ test_add_html_editor_bug_tests ();
+
+diff -up evolution-3.22.6/mail/e-mail-display.c.composer-image-insert-undo evolution-3.22.6/mail/e-mail-display.c
+--- evolution-3.22.6/mail/e-mail-display.c.composer-image-insert-undo 2017-03-24 15:12:21.888422514 +0100
++++ evolution-3.22.6/mail/e-mail-display.c 2017-03-24 15:12:21.895422514 +0100
+@@ -1768,7 +1768,6 @@ mail_display_uri_requested_cb (EWebView
+ }
+ }
+
+-#if 0 /* FIXME WK2 */
+ static CamelMimePart *
+ camel_mime_part_from_cid (EMailDisplay *display,
+ const gchar *uri)
+@@ -1876,7 +1875,6 @@ mail_display_drag_data_get (GtkWidget *w
+ out:
+ g_free (uri);
+ }
+-#endif
+
+ static void
+ e_mail_display_test_change_and_update_fonts_cb (EMailDisplay *mail_display,
+@@ -1922,9 +1920,7 @@ e_mail_display_class_init (EMailDisplayC
+ widget_class->button_press_event = mail_display_button_press_event;
+
+ web_view_class = E_WEB_VIEW_CLASS (class);
+-#if 0 /* FIXME WK2 */
+ web_view_class->suggest_filename = mail_display_suggest_filename;
+-#endif
+ web_view_class->set_fonts = mail_display_set_fonts;
+
+ g_object_class_install_property (
+@@ -2054,11 +2050,11 @@ e_mail_display_init (EMailDisplay *displ
+ g_signal_connect (
+ display, "process-mailto",
+ G_CALLBACK (mail_display_process_mailto), NULL);
+-#if 0 /* FIXME WK2 */
++
+ g_signal_connect_after (
+ display, "drag-data-get",
+ G_CALLBACK (mail_display_drag_data_get), display);
+-#endif
++
+ display->priv->settings = e_util_ref_settings ("org.gnome.evolution.mail");
+ g_signal_connect_swapped (
+ display->priv->settings , "changed::monospace-font",
+diff -up evolution-3.22.6/modules/webkit-editor/e-webkit-editor.c.composer-image-insert-undo evolution-3.22.6/modules/webkit-editor/e-webkit-editor.c
+--- evolution-3.22.6/modules/webkit-editor/e-webkit-editor.c.composer-image-insert-undo 2017-03-24 15:12:21.889422514 +0100
++++ evolution-3.22.6/modules/webkit-editor/e-webkit-editor.c 2017-03-24 15:13:40.145419038 +0100
+@@ -131,6 +131,10 @@ struct _EWebKitEditorPrivate {
+ gchar *replace_with;
+ gulong found_text_handler_id;
+ gulong failed_to_find_text_handler_id;
++ gboolean current_text_not_found;
++
++ gboolean performing_drag;
++ gulong drag_data_received_handler_id;
+
+ gchar *last_hover_uri;
+ };
+@@ -386,6 +390,9 @@ web_extension_selection_changed_cb (GDBu
+ }
+ g_free (font_color);
+
++ g_object_notify (G_OBJECT (wk_editor), "can-undo");
++ g_object_notify (G_OBJECT (wk_editor), "can-redo");
++
+ g_object_notify (G_OBJECT (wk_editor), "alignment");
+ g_object_notify (G_OBJECT (wk_editor), "block-format");
+ g_object_notify (G_OBJECT (wk_editor), "indented");
+@@ -2468,7 +2475,7 @@ webkit_editor_replace_caret_word (EConte
+ return;
+ }
+
+- e_util_invoke_g_dbus_proxy_call_with_error_check (
++ e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
+ wk_editor->priv->web_extension,
+ "DOMReplaceCaretWord",
+ g_variant_new ("(ts)", current_page_id (wk_editor), replacement),
+@@ -2521,10 +2528,39 @@ find_flags_to_webkit_find_options (guint
+ }
+
+ static void
++webkit_editor_replace (EContentEditor *editor,
++ const gchar *replacement)
++{
++ EWebKitEditor *wk_editor;
++
++ wk_editor = E_WEBKIT_EDITOR (editor);
++ if (!wk_editor->priv->web_extension) {
++ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
++ return;
++ }
++
++ e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
++ wk_editor->priv->web_extension,
++ "DOMSelectionReplace",
++ g_variant_new ("(ts)", current_page_id (wk_editor), replacement),
++ wk_editor->priv->cancellable);
++}
++
++static gboolean
++search_next_on_idle (EWebKitEditor *wk_editor)
++{
++ webkit_find_controller_search_next (wk_editor->priv->find_controller);
++
++ return G_SOURCE_REMOVE;
++}
++
++static void
+ webkit_find_controller_found_text_cb (WebKitFindController *find_controller,
+ guint match_count,
+ EWebKitEditor *wk_editor)
+ {
++ wk_editor->priv->current_text_not_found = FALSE;
++
+ if (wk_editor->priv->performing_replace_all) {
+ if (!wk_editor->priv->replaced_count)
+ wk_editor->priv->replaced_count = match_count;
+@@ -2532,12 +2568,13 @@ webkit_find_controller_found_text_cb (We
+ /* Repeatedly search for 'word', then replace selection by
+ * 'replacement'. Repeat until there's at least one occurrence of
+ * 'word' in the document */
+- e_content_editor_insert_content (
+- E_CONTENT_EDITOR (wk_editor),
+- wk_editor->priv->replace_with,
+- E_CONTENT_EDITOR_INSERT_TEXT_PLAIN);
++ e_util_invoke_g_dbus_proxy_call_with_error_check (
++ wk_editor->priv->web_extension,
++ "DOMSelectionReplace",
++ g_variant_new ("(ts)", current_page_id (wk_editor), wk_editor->priv->replace_with),
++ wk_editor->priv->cancellable);
+
+- webkit_find_controller_search_next (find_controller);
++ g_idle_add ((GSourceFunc) search_next_on_idle, wk_editor);
+ } else {
+ e_content_editor_emit_find_done (E_CONTENT_EDITOR (wk_editor), match_count);
+ }
+@@ -2547,9 +2584,26 @@ static void
+ webkit_find_controller_failed_to_find_text_cb (WebKitFindController *find_controller,
+ EWebKitEditor *wk_editor)
+ {
++ wk_editor->priv->current_text_not_found = TRUE;
++
+ if (wk_editor->priv->performing_replace_all) {
+ guint replaced_count = wk_editor->priv->replaced_count;
+
++ if (replaced_count > 0) {
++ if (!wk_editor->priv->web_extension) {
++ g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
++ } else {
++ e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
++ wk_editor->priv->web_extension,
++ "DOMInsertReplaceAllHistoryEvent",
++ g_variant_new ("(tss)",
++ current_page_id (wk_editor),
++ webkit_find_controller_get_search_text (find_controller),
++ wk_editor->priv->replace_with),
++ NULL);
++ }
++ }
++
+ webkit_editor_finish_search (wk_editor);
+ e_content_editor_emit_replace_all_done (E_CONTENT_EDITOR (wk_editor), replaced_count);
+ } else {
+@@ -2575,6 +2629,7 @@ webkit_editor_prepare_find_controller (E
+
+ wk_editor->priv->performing_replace_all = FALSE;
+ wk_editor->priv->replaced_count = 0;
++ wk_editor->priv->current_text_not_found = FALSE;
+ g_free (wk_editor->priv->replace_with);
+ wk_editor->priv->replace_with = NULL;
+ }
+@@ -2613,25 +2668,6 @@ webkit_editor_find (EContentEditor *edit
+ }
+
+ static void
+-webkit_editor_replace (EContentEditor *editor,
+- const gchar *replacement)
+-{
+- EWebKitEditor *wk_editor;
+-
+- wk_editor = E_WEBKIT_EDITOR (editor);
+- if (!wk_editor->priv->web_extension) {
+- g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
+- return;
+- }
+-
+- e_util_invoke_g_dbus_proxy_call_with_error_check (
+- wk_editor->priv->web_extension,
+- "DOMSelectionReplace",
+- g_variant_new ("(ts)", current_page_id (wk_editor), replacement),
+- wk_editor->priv->cancellable);
+-}
+-
+-static void
+ webkit_editor_replace_all (EContentEditor *editor,
+ guint32 flags,
+ const gchar *find_text,
+@@ -2647,6 +2683,11 @@ webkit_editor_replace_all (EContentEdito
+ wk_editor = E_WEBKIT_EDITOR (editor);
+ wk_options = find_flags_to_webkit_find_options (flags);
+
++ wk_options |= WEBKIT_FIND_OPTIONS_WRAP_AROUND;
++
++ if (wk_editor->priv->current_text_not_found)
++ return;
++
+ if (!wk_editor->priv->find_controller)
+ webkit_editor_prepare_find_controller (wk_editor);
+
+@@ -5770,17 +5811,111 @@ webkit_editor_context_menu_cb (EWebKitEd
+ }
+
+ static void
++webkit_editor_drag_begin_cb (EWebKitEditor *wk_editor,
++ GdkDragContext *context)
++{
++ wk_editor->priv->performing_drag = TRUE;
++}
++
++static void
++webkit_editor_drag_failed_cb (EWebKitEditor *wk_editor,
++ GdkDragContext *context,
++ GtkDragResult result)
++{
++ wk_editor->priv->performing_drag = FALSE;
++}
++
++static void
+ webkit_editor_drag_end_cb (EWebKitEditor *wk_editor,
+ GdkDragContext *context)
+ {
+- webkit_editor_call_simple_extension_function (wk_editor, "DOMDragAndDropEnd");
++ wk_editor->priv->performing_drag = FALSE;
++}
++
++static void
++webkit_editor_drag_data_received_cb (GtkWidget *widget,
++ GdkDragContext *context,
++ gint x,
++ gint y,
++ GtkSelectionData *selection,
++ guint info,
++ guint time)
++{
++ EWebKitEditor *wk_editor = E_WEBKIT_EDITOR (widget);
++ gboolean is_move = FALSE;
++
++ g_signal_handler_disconnect (wk_editor, wk_editor->priv->drag_data_received_handler_id);
++ wk_editor->priv->drag_data_received_handler_id = 0;
++
++ is_move = gdk_drag_context_get_selected_action(context) == GDK_ACTION_MOVE;
++
++ /* Leave DnD inside the view on WebKit */
++ /* Leave the text on WebKit to handle it. */
++ if (wk_editor->priv->performing_drag ||
++ info == E_DND_TARGET_TYPE_UTF8_STRING || info == E_DND_TARGET_TYPE_STRING ||
++ info == E_DND_TARGET_TYPE_TEXT_PLAIN || info == E_DND_TARGET_TYPE_TEXT_PLAIN_UTF8) {
++ gdk_drag_status (context, gdk_drag_context_get_selected_action(context), time);
++ GTK_WIDGET_CLASS (e_webkit_editor_parent_class)->drag_drop (widget, context, x, y, time);
++ g_signal_stop_emission_by_name (widget, "drag-data-received");
++ if (!is_move)
++ webkit_editor_call_simple_extension_function (wk_editor, "DOMLastDropOperationDidCopy");
++ return;
++ }
++
++ if (info == E_DND_TARGET_TYPE_TEXT_HTML) {
++ const guchar *data;
++ gint length;
++ gint list_len, len;
++ gchar *text;
++
++ data = gtk_selection_data_get_data (selection);
++ length = gtk_selection_data_get_length (selection);
++
++ if (!data || length < 0) {
++ gtk_drag_finish (context, FALSE, is_move, time);
++ g_signal_stop_emission_by_name (widget, "drag-data-received");
++ return;
++ }
++
++ webkit_editor_move_caret_on_coordinates (E_CONTENT_EDITOR (widget), x, y, FALSE);
++
++ list_len = length;
++ do {
++ text = e_util_next_uri_from_uri_list ((guchar **) &data, &len, &list_len);
++ webkit_editor_insert_content (
++ E_CONTENT_EDITOR (wk_editor),
++ text,
++ E_CONTENT_EDITOR_INSERT_TEXT_HTML);
++ g_free (text);
++ } while (list_len);
++
++ gtk_drag_finish (context, TRUE, is_move, time);
++ g_signal_stop_emission_by_name (widget, "drag-data-received");
++ return;
++ }
++}
++
++static gboolean
++webkit_editor_drag_drop_cb (EWebKitEditor *wk_editor,
++ GdkDragContext *context,
++ gint x,
++ gint y,
++ guint time)
++{
++ wk_editor->priv->drag_data_received_handler_id = g_signal_connect (
++ wk_editor, "drag-data-received",
++ G_CALLBACK (webkit_editor_drag_data_received_cb), NULL);
++
++ webkit_editor_set_changed (wk_editor, TRUE);
++
++ return FALSE;
+ }
+
+ static void
+ webkit_editor_web_process_crashed_cb (EWebKitEditor *wk_editor)
+ {
+ g_warning (
+- "WebKitWebProcess (page id %ld) for EWebKitEditor crashed",
++ "WebKitWebProcess (page id %" G_GUINT64_FORMAT ") for EWebKitEditor crashed",
+ webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (wk_editor)));
+ }
+
+@@ -6050,10 +6185,22 @@ e_webkit_editor_init (EWebKitEditor *wk_
+ G_CALLBACK (webkit_editor_mouse_target_changed_cb), NULL);
+
+ g_signal_connect (
++ wk_editor, "drag-begin",
++ G_CALLBACK (webkit_editor_drag_begin_cb), NULL);
++
++ g_signal_connect (
++ wk_editor, "drag-failed",
++ G_CALLBACK (webkit_editor_drag_failed_cb), NULL);
++
++ g_signal_connect (
+ wk_editor, "drag-end",
+ G_CALLBACK (webkit_editor_drag_end_cb), NULL);
+
+ g_signal_connect (
++ wk_editor, "drag-drop",
++ G_CALLBACK (webkit_editor_drag_drop_cb), NULL);
++
++ g_signal_connect (
+ wk_editor, "web-process-crashed",
+ G_CALLBACK (webkit_editor_web_process_crashed_cb), NULL);
+
+diff -up evolution-3.22.6/modules/webkit-editor/web-extension/e-composer-dom-functions.c.composer-image-insert-undo evolution-3.22.6/modules/webkit-editor/web-extension/e-composer-dom-functions.c
+--- evolution-3.22.6/modules/webkit-editor/web-extension/e-composer-dom-functions.c.composer-image-insert-undo 2017-02-07 17:48:51.000000000 +0100
++++ evolution-3.22.6/modules/webkit-editor/web-extension/e-composer-dom-functions.c 2017-03-24 15:12:21.896422514 +0100
+@@ -591,247 +591,3 @@ e_composer_dom_get_raw_body_content (EEd
+
+ return webkit_dom_html_element_get_inner_text (body);
+ }
+-
+-static void
+-insert_nbsp_history_event (WebKitDOMDocument *document,
+- EEditorUndoRedoManager *manager,
+- gboolean delete,
+- guint x,
+- guint y)
+-{
+- EEditorHistoryEvent *event;
+- WebKitDOMDocumentFragment *fragment;
+-
+- event = g_new0 (EEditorHistoryEvent, 1);
+- event->type = HISTORY_AND;
+- e_editor_undo_redo_manager_insert_history_event (manager, event);
+-
+- fragment = webkit_dom_document_create_document_fragment (document);
+- webkit_dom_node_append_child (
+- WEBKIT_DOM_NODE (fragment),
+- WEBKIT_DOM_NODE (
+- webkit_dom_document_create_text_node (document, UNICODE_NBSP)),
+- NULL);
+-
+- event = g_new0 (EEditorHistoryEvent, 1);
+- event->type = HISTORY_DELETE;
+-
+- if (delete)
+- g_object_set_data (G_OBJECT (fragment), "history-delete-key", GINT_TO_POINTER (1));
+-
+- event->data.fragment = fragment;
+-
+- event->before.start.x = x;
+- event->before.start.y = y;
+- event->before.end.x = x;
+- event->before.end.y = y;
+-
+- event->after.start.x = x;
+- event->after.start.y = y;
+- event->after.end.x = x;
+- event->after.end.y = y;
+-
+- e_editor_undo_redo_manager_insert_history_event (manager, event);
+-}
+-
+-void
+-e_composer_dom_save_drag_and_drop_history (EEditorPage *editor_page)
+-{
+- WebKitDOMDocument *document;
+- WebKitDOMDocumentFragment *fragment;
+- WebKitDOMDOMSelection *dom_selection = NULL;
+- WebKitDOMDOMWindow *dom_window = NULL;
+- WebKitDOMRange *beginning_of_line = NULL;
+- WebKitDOMRange *range = NULL, *range_clone = NULL;
+- EEditorHistoryEvent *event;
+- EEditorUndoRedoManager *manager;
+- gboolean start_to_start, end_to_end;
+- gchar *range_text;
+- guint x, y;
+-
+- g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+-
+- document = e_editor_page_get_document (editor_page);
+- manager = e_editor_page_get_undo_redo_manager (editor_page);
+-
+- if (!(dom_window = webkit_dom_document_get_default_view (document)))
+- return;
+-
+- if (!(dom_selection = webkit_dom_dom_window_get_selection (dom_window))) {
+- g_clear_object (&dom_window);
+- return;
+- }
+-
+- g_clear_object (&dom_window);
+-
+- if (webkit_dom_dom_selection_get_range_count (dom_selection) < 1) {
+- g_clear_object (&dom_selection);
+- return;
+- }
+-
+- /* Obtain the dragged content. */
+- range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+- range_clone = webkit_dom_range_clone_range (range, NULL);
+-
+- /* Create the history event for the content that will
+- * be removed by DnD. */
+- event = g_new0 (EEditorHistoryEvent, 1);
+- event->type = HISTORY_DELETE;
+-
+- e_editor_dom_selection_get_coordinates (editor_page,
+- &event->before.start.x,
+- &event->before.start.y,
+- &event->before.end.x,
+- &event->before.end.y);
+-
+- x = event->before.start.x;
+- y = event->before.start.y;
+-
+- event->after.start.x = x;
+- event->after.start.y = y;
+- event->after.end.x = x;
+- event->after.end.y = y;
+-
+- /* Save the content that will be removed. */
+- fragment = webkit_dom_range_clone_contents (range_clone, NULL);
+-
+- /* Extend the cloned range to point one character after
+- * the selection ends to later check if there is a whitespace
+- * after it. */
+- webkit_dom_range_set_end (
+- range_clone,
+- webkit_dom_range_get_end_container (range_clone, NULL),
+- webkit_dom_range_get_end_offset (range_clone, NULL) + 1,
+- NULL);
+- range_text = webkit_dom_range_get_text (range_clone);
+-
+- /* Check if the current selection starts on the beginning
+- * of line. */
+- webkit_dom_dom_selection_modify (
+- dom_selection, "extend", "left", "lineboundary");
+- beginning_of_line = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+- start_to_start = webkit_dom_range_compare_boundary_points (
+- beginning_of_line, 0 /* START_TO_START */, range, NULL) == 0;
+-
+- /* Restore the selection to state before the check. */
+- webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+- webkit_dom_dom_selection_add_range (dom_selection, range);
+- g_clear_object (&beginning_of_line);
+-
+- /* Check if the current selection end on the end of the line. */
+- webkit_dom_dom_selection_modify (
+- dom_selection, "extend", "right", "lineboundary");
+- beginning_of_line = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+- end_to_end = webkit_dom_range_compare_boundary_points (
+- beginning_of_line, 2 /* END_TO_END */, range, NULL) == 0;
+-
+- /* Dragging the whole line. */
+- if (start_to_start && end_to_end) {
+- WebKitDOMNode *container, *actual_block, *tmp_block;
+-
+- /* Select the whole line (to the beginning of the next
+- * one so we can reuse the undo code while undoing this.
+- * Because of this we need to special mark the event
+- * with history-drag-and-drop to correct the selection
+- * after undoing it (otherwise the beginning of the next
+- * line will be selected as well. */
+- webkit_dom_dom_selection_modify (
+- dom_selection, "extend", "right", "character");
+- g_clear_object (&beginning_of_line);
+- beginning_of_line = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+-
+- container = webkit_dom_range_get_end_container (range, NULL);
+- actual_block = e_editor_dom_get_parent_block_node_from_child (container);
+-
+- tmp_block = webkit_dom_range_get_end_container (beginning_of_line, NULL);
+- if ((tmp_block = e_editor_dom_get_parent_block_node_from_child (tmp_block))) {
+- e_editor_dom_selection_get_coordinates (editor_page,
+- &event->before.start.x,
+- &event->before.start.y,
+- &event->before.end.x,
+- &event->before.end.y);
+-
+- /* Create the right content for the history event. */
+- fragment = webkit_dom_document_create_document_fragment (document);
+- /* The removed line. */
+- webkit_dom_node_append_child (
+- WEBKIT_DOM_NODE (fragment),
+- webkit_dom_node_clone_node_with_error (actual_block, TRUE, NULL),
+- NULL);
+- /* The following block, but empty. */
+- webkit_dom_node_append_child (
+- WEBKIT_DOM_NODE (fragment),
+- webkit_dom_node_clone_node_with_error (tmp_block, FALSE, NULL),
+- NULL);
+- g_object_set_data (
+- G_OBJECT (fragment),
+- "history-drag-and-drop",
+- GINT_TO_POINTER (1));
+- /* It should act as a Delete key press. */
+- g_object_set_data (
+- G_OBJECT (fragment),
+- "history-delete-key",
+- GINT_TO_POINTER (1));
+- }
+- }
+-
+- event->data.fragment = fragment;
+- e_editor_undo_redo_manager_insert_history_event (manager, event);
+-
+- /* Selection is ending on the end of the line, check if
+- * there is a space before the selection start. If so, it
+- * will be removed and we need create the history event
+- * for it. */
+- if (end_to_end) {
+- gchar *range_text_start;
+- glong start_offset;
+-
+- start_offset = webkit_dom_range_get_start_offset (range_clone, NULL);
+- webkit_dom_range_set_start (
+- range_clone,
+- webkit_dom_range_get_start_container (range_clone, NULL),
+- start_offset > 0 ? start_offset - 1 : 0,
+- NULL);
+-
+- range_text_start = webkit_dom_range_get_text (range_clone);
+- if (g_str_has_prefix (range_text_start, " ") ||
+- g_str_has_prefix (range_text_start, UNICODE_NBSP))
+- insert_nbsp_history_event (document, manager, FALSE, x, y);
+-
+- g_free (range_text_start);
+- }
+-
+- /* WebKit removes the space (if presented) after selection and
+- * we need to create a new history event for it. */
+- if (g_str_has_suffix (range_text, " ") ||
+- g_str_has_suffix (range_text, UNICODE_NBSP))
+- insert_nbsp_history_event (document, manager, TRUE, x, y);
+-
+- g_free (range_text);
+-
+- /* Restore the selection to original state. */
+- webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+- webkit_dom_dom_selection_add_range (dom_selection, range);
+- g_clear_object (&beginning_of_line);
+-
+- /* All the things above were about removing the content,
+- * create an AND event to continue later with inserting
+- * the dropped content. */
+- event = g_new0 (EEditorHistoryEvent, 1);
+- event->type = HISTORY_AND;
+- e_editor_undo_redo_manager_insert_history_event (manager, event);
+-
+- g_clear_object (&dom_selection);
+-
+- g_clear_object (&range);
+- g_clear_object (&range_clone);
+-}
+-
+-void
+-e_composer_dom_clean_after_drag_and_drop (EEditorPage *editor_page)
+-{
+- g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+-
+- e_editor_dom_save_history_for_drop (editor_page);
+- e_editor_dom_check_magic_links (editor_page, FALSE);
+-}
+diff -up evolution-3.22.6/modules/webkit-editor/web-extension/e-composer-dom-functions.h.composer-image-insert-undo evolution-3.22.6/modules/webkit-editor/web-extension/e-composer-dom-functions.h
+--- evolution-3.22.6/modules/webkit-editor/web-extension/e-composer-dom-functions.h.composer-image-insert-undo 2016-09-19 10:22:58.000000000 +0200
++++ evolution-3.22.6/modules/webkit-editor/web-extension/e-composer-dom-functions.h 2017-03-24 15:12:21.896422514 +0100
+@@ -38,10 +38,6 @@ gchar * e_composer_dom_get_raw_body_con
+ (EEditorPage *editor_page);
+ gchar * e_composer_dom_get_raw_body_content
+ (EEditorPage *editor_page);
+-void e_composer_dom_save_drag_and_drop_history
+- (EEditorPage *editor_page);
+-void e_composer_dom_clean_after_drag_and_drop
+- (EEditorPage *editor_page);
+
+ G_END_DECLS
+
+diff -up evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-dom-functions.c.composer-image-insert-undo evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-dom-functions.c
+--- evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-dom-functions.c.composer-image-insert-undo 2017-03-24 15:12:21.891422514 +0100
++++ evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-dom-functions.c 2017-03-24 15:13:16.839420073 +0100
+@@ -3408,6 +3408,7 @@ e_editor_dom_body_input_event_process (E
+ }
+
+ if (WEBKIT_DOM_IS_TEXT (node)) {
++ WebKitDOMElement *parent;
+ gchar *text;
+
+ text = webkit_dom_node_get_text_content (node);
+@@ -3429,6 +3430,43 @@ e_editor_dom_body_input_event_process (E
+ e_editor_dom_check_magic_links (editor_page, FALSE);
+ }
+ }
++
++ parent = webkit_dom_node_get_parent_element (node);
++ if (element_has_class (parent, "-x-evo-resizable-wrapper") ||
++ element_has_class (parent, "-x-evo-smiley-wrapper")) {
++ WebKitDOMDOMWindow *dom_window = NULL;
++ WebKitDOMDOMSelection *dom_selection = NULL;
++ WebKitDOMNode *prev_sibling;
++ gboolean writing_before = TRUE;
++
++ dom_window = webkit_dom_document_get_default_view (document);
++ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
++
++ prev_sibling = webkit_dom_node_get_previous_sibling (node);
++ if (prev_sibling && WEBKIT_DOM_IS_HTML_IMAGE_ELEMENT (prev_sibling))
++ writing_before = FALSE;
++
++ webkit_dom_node_insert_before (
++ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (parent)),
++ node,
++ writing_before ?
++ WEBKIT_DOM_NODE (parent) :
++ webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (parent)),
++ NULL);
++
++ g_clear_object (&range);
++
++ range = webkit_dom_document_create_range (document);
++ webkit_dom_range_select_node_contents (range, node, NULL);
++ webkit_dom_range_collapse (range, FALSE, NULL);
++
++ webkit_dom_dom_selection_remove_all_ranges (dom_selection);
++ webkit_dom_dom_selection_add_range (dom_selection, range);
++
++ g_clear_object (&dom_window);
++ g_clear_object (&dom_selection);
++ }
++
+ g_free (text);
+ }
+ }
+@@ -5751,6 +5789,94 @@ body_compositionend_event_cb (WebKitDOME
+ }
+
+ static void
++body_drop_event_cb (WebKitDOMElement *element,
++ WebKitDOMUIEvent *event,
++ EEditorPage *editor_page)
++{
++ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
++
++ if (e_editor_page_is_pasting_content_from_itself (editor_page)) {
++ EEditorUndoRedoManager *manager;
++ EEditorHistoryEvent *and_event, *event = NULL;
++
++ /* There is a weird thing going on and I still don't know if it's
++ * caused by WebKit or Evolution. If dragging content around the
++ * editor sometimes the current selection is changed. The problem
++ * is that if moving the content, then WebKit is removing the
++ * currently selected content and at that point it could be a
++ * different one from the dragged one. So before the drop is
++ * performed we restore the selection to the state when the
++ * drag was initiated. */
++ manager = e_editor_page_get_undo_redo_manager (editor_page);
++ and_event = e_editor_undo_redo_manager_get_current_history_event (manager);
++ while (and_event && and_event->type == HISTORY_AND) {
++ event = e_editor_undo_redo_manager_get_next_history_event_for (manager, and_event);
++ and_event = e_editor_undo_redo_manager_get_next_history_event_for (manager, event);
++ }
++
++ if (event)
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, event->before);
++
++ e_editor_dom_save_history_for_drop (editor_page);
++ }
++}
++
++static void
++body_dragstart_event_cb (WebKitDOMElement *element,
++ WebKitDOMUIEvent *event,
++ EEditorPage *editor_page)
++{
++ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
++
++ e_editor_dom_remove_input_event_listener_from_body (editor_page);
++ e_editor_page_set_pasting_content_from_itself (editor_page, TRUE);
++ e_editor_dom_save_history_for_drag (editor_page);
++}
++
++static void
++body_dragend_event_cb (WebKitDOMElement *element,
++ WebKitDOMUIEvent *event,
++ EEditorPage *editor_page)
++{
++ EEditorHistoryEvent *ev;
++ EEditorUndoRedoManager *manager;
++
++ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
++
++ manager = e_editor_page_get_undo_redo_manager (editor_page);
++ if (e_editor_page_is_pasting_content_from_itself (editor_page) &&
++ (ev = e_editor_undo_redo_manager_get_current_history_event (manager))) {
++ if (ev->type == HISTORY_INSERT_HTML &&
++ ev->after.start.x == 0 && ev->after.start.y == 0 &&
++ ev->after.end.x == 0 && ev->after.end.y == 0) {
++ e_editor_dom_selection_get_coordinates (editor_page,
++ &ev->after.start.x,
++ &ev->after.start.y,
++ &ev->after.end.x,
++ &ev->after.end.y);
++ ev->before.start.x = ev->after.start.x;
++ ev->before.start.y = ev->after.start.y;
++ ev->before.end.x = ev->after.start.x;
++ ev->before.end.y = ev->after.start.y;
++ e_editor_dom_force_spell_check_in_viewport (editor_page);
++ } else {
++ /* Drag and Drop was cancelled */
++ while (ev && ev->type == HISTORY_AND) {
++ e_editor_undo_redo_manager_remove_current_history_event (manager);
++ ev = e_editor_undo_redo_manager_get_current_history_event (manager);
++ /* Basically the same as in body_drop_event_cb(). See the comment there. */
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, ev->before);
++ e_editor_undo_redo_manager_remove_current_history_event (manager);
++ ev = e_editor_undo_redo_manager_get_current_history_event (manager);
++ }
++ }
++ }
++
++ e_editor_page_set_pasting_content_from_itself (editor_page, FALSE);
++ e_editor_dom_register_input_event_listener_on_body (editor_page);
++}
++
++static void
+ register_html_events_handlers (EEditorPage *editor_page,
+ WebKitDOMHTMLElement *body)
+ {
+@@ -5790,6 +5916,27 @@ register_html_events_handlers (EEditorPa
+ G_CALLBACK (body_compositionend_event_cb),
+ FALSE,
+ editor_page);
++
++ webkit_dom_event_target_add_event_listener (
++ WEBKIT_DOM_EVENT_TARGET (body),
++ "drop",
++ G_CALLBACK (body_drop_event_cb),
++ FALSE,
++ editor_page);
++
++ webkit_dom_event_target_add_event_listener (
++ WEBKIT_DOM_EVENT_TARGET (body),
++ "dragstart",
++ G_CALLBACK (body_dragstart_event_cb),
++ FALSE,
++ editor_page);
++
++ webkit_dom_event_target_add_event_listener (
++ WEBKIT_DOM_EVENT_TARGET (body),
++ "dragend",
++ G_CALLBACK (body_dragend_event_cb),
++ FALSE,
++ editor_page);
+ }
+
+ void
+@@ -8523,11 +8670,25 @@ e_editor_dom_process_content_after_load
+
+ if (e_editor_page_get_convert_in_situ (editor_page)) {
+ e_editor_dom_convert_content (editor_page, NULL);
++ /* The BODY could be replaced during the conversion */
++ body = webkit_dom_document_get_body (document);
+ /* Make the quote marks non-selectable. */
+ e_editor_dom_disable_quote_marks_select (editor_page);
+ dom_set_links_active (document, FALSE);
+ e_editor_page_set_convert_in_situ (editor_page, FALSE);
+
++ /* The composer body could be empty in some case (loading an empty string
++ * or empty HTML). In that case create the initial paragraph. */
++ if (!webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body))) {
++ WebKitDOMElement *paragraph;
++
++ paragraph = e_editor_dom_prepare_paragraph (editor_page, TRUE);
++ webkit_dom_element_set_id (paragraph, "-x-evo-input-start");
++ webkit_dom_node_append_child (
++ WEBKIT_DOM_NODE (body), WEBKIT_DOM_NODE (paragraph), NULL);
++ e_editor_dom_selection_restore (editor_page);
++ }
++
+ goto out;
+ }
+
+@@ -8933,35 +9094,6 @@ e_editor_dom_insert_html (EEditorPage *e
+ if (strstr (html_text, "id=\"-x-evo-selection-start-marker\""))
+ e_editor_dom_selection_restore (editor_page);
+
+- if (!html_mode) {
+- WebKitDOMNodeList *list = NULL;
+- gint ii, length;
+-
+- list = webkit_dom_document_query_selector_all (
+- document, "span[style^=font-family]", NULL);
+- length = webkit_dom_node_list_get_length (list);
+- if (length > 0)
+- e_editor_dom_selection_save (editor_page);
+-
+- for (ii = length; ii--;) {
+- WebKitDOMNode *span, *child;
+-
+- span = webkit_dom_node_list_item (list, ii);
+- while ((child = webkit_dom_node_get_first_child (span)))
+- webkit_dom_node_insert_before (
+- webkit_dom_node_get_parent_node (span),
+- child,
+- span,
+- NULL);
+-
+- remove_node (span);
+- }
+- g_clear_object (&list);
+-
+- if (length > 0)
+- e_editor_dom_selection_restore (editor_page);
+- }
+-
+ e_editor_dom_check_magic_links (editor_page, FALSE);
+ e_editor_dom_scroll_to_caret (editor_page);
+ e_editor_dom_force_spell_check_in_viewport (editor_page);
+@@ -10833,6 +10965,240 @@ e_editor_dom_get_caret_position (EEditor
+ return ret_val;
+ }
+
++static void
++insert_nbsp_history_event (WebKitDOMDocument *document,
++ EEditorUndoRedoManager *manager,
++ gboolean delete,
++ guint x,
++ guint y)
++{
++ EEditorHistoryEvent *event;
++ WebKitDOMDocumentFragment *fragment;
++
++ event = g_new0 (EEditorHistoryEvent, 1);
++ event->type = HISTORY_AND;
++ e_editor_undo_redo_manager_insert_history_event (manager, event);
++
++ fragment = webkit_dom_document_create_document_fragment (document);
++ webkit_dom_node_append_child (
++ WEBKIT_DOM_NODE (fragment),
++ WEBKIT_DOM_NODE (
++ webkit_dom_document_create_text_node (document, UNICODE_NBSP)),
++ NULL);
++
++ event = g_new0 (EEditorHistoryEvent, 1);
++ event->type = HISTORY_DELETE;
++
++ if (delete)
++ g_object_set_data (G_OBJECT (fragment), "history-delete-key", GINT_TO_POINTER (1));
++
++ event->data.fragment = fragment;
++
++ event->before.start.x = x;
++ event->before.start.y = y;
++ event->before.end.x = x;
++ event->before.end.y = y;
++
++ event->after.start.x = x;
++ event->after.start.y = y;
++ event->after.end.x = x;
++ event->after.end.y = y;
++
++ e_editor_undo_redo_manager_insert_history_event (manager, event);
++}
++void
++e_editor_dom_save_history_for_drag (EEditorPage *editor_page)
++{
++ WebKitDOMDocument *document;
++ WebKitDOMDocumentFragment *fragment;
++ WebKitDOMDOMSelection *dom_selection = NULL;
++ WebKitDOMDOMWindow *dom_window = NULL;
++ WebKitDOMRange *beginning_of_line = NULL;
++ WebKitDOMRange *range = NULL, *range_clone = NULL;
++ EEditorHistoryEvent *event;
++ EEditorUndoRedoManager *manager;
++ gboolean start_to_start = FALSE, end_to_end = FALSE;
++ gchar *range_text;
++ guint x, y;
++
++ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
++
++ document = e_editor_page_get_document (editor_page);
++ manager = e_editor_page_get_undo_redo_manager (editor_page);
++
++ if (!(dom_window = webkit_dom_document_get_default_view (document)))
++ return;
++
++ if (!(dom_selection = webkit_dom_dom_window_get_selection (dom_window))) {
++ g_clear_object (&dom_window);
++ return;
++ }
++
++ g_clear_object (&dom_window);
++
++ if (webkit_dom_dom_selection_get_range_count (dom_selection) < 1) {
++ g_clear_object (&dom_selection);
++ return;
++ }
++
++ /* Obtain the dragged content. */
++ range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
++ range_clone = webkit_dom_range_clone_range (range, NULL);
++
++ /* Create the history event for the content that will
++ * be removed by DnD. */
++ event = g_new0 (EEditorHistoryEvent, 1);
++ event->type = HISTORY_DELETE;
++
++ e_editor_dom_selection_get_coordinates (editor_page,
++ &event->before.start.x,
++ &event->before.start.y,
++ &event->before.end.x,
++ &event->before.end.y);
++
++ x = event->before.start.x;
++ y = event->before.start.y;
++
++ event->after.start.x = x;
++ event->after.start.y = y;
++ event->after.end.x = x;
++ event->after.end.y = y;
++
++ /* Save the content that will be removed. */
++ fragment = webkit_dom_range_clone_contents (range_clone, NULL);
++
++ /* Extend the cloned range to point one character after
++ * the selection ends to later check if there is a whitespace
++ * after it. */
++ webkit_dom_range_set_end (
++ range_clone,
++ webkit_dom_range_get_end_container (range_clone, NULL),
++ webkit_dom_range_get_end_offset (range_clone, NULL) + 1,
++ NULL);
++ range_text = webkit_dom_range_get_text (range_clone);
++
++ /* Check if the current selection starts on the beginning of line. */
++ webkit_dom_dom_selection_modify (
++ dom_selection, "extend", "left", "lineboundary");
++ beginning_of_line = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
++ start_to_start = webkit_dom_range_compare_boundary_points (
++ beginning_of_line, WEBKIT_DOM_RANGE_START_TO_START, range, NULL) == 0;
++
++ /* Restore the selection to state before the check. */
++ webkit_dom_dom_selection_remove_all_ranges (dom_selection);
++ webkit_dom_dom_selection_add_range (dom_selection, range);
++ g_clear_object (&beginning_of_line);
++
++ /* Check if the current selection end on the end of the line. */
++ webkit_dom_dom_selection_modify (
++ dom_selection, "extend", "right", "lineboundary");
++ beginning_of_line = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
++ end_to_end = webkit_dom_range_compare_boundary_points (
++ beginning_of_line, WEBKIT_DOM_RANGE_END_TO_END, range, NULL) == 0;
++
++ /* Dragging the whole line. */
++ if (start_to_start && end_to_end) {
++ WebKitDOMNode *container, *actual_block, *tmp_block;
++
++ /* Select the whole line (to the beginning of the next
++ * one so we can reuse the undo code while undoing this.
++ * Because of this we need to special mark the event
++ * with history-drag-and-drop to correct the selection
++ * after undoing it (otherwise the beginning of the next
++ * line will be selected as well. */
++ webkit_dom_dom_selection_modify (
++ dom_selection, "extend", "right", "character");
++ g_clear_object (&beginning_of_line);
++ beginning_of_line = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
++
++ container = webkit_dom_range_get_end_container (range, NULL);
++ actual_block = e_editor_dom_get_parent_block_node_from_child (container);
++
++ tmp_block = webkit_dom_range_get_end_container (beginning_of_line, NULL);
++ if ((tmp_block = e_editor_dom_get_parent_block_node_from_child (tmp_block))) {
++ e_editor_dom_selection_get_coordinates (editor_page,
++ &event->before.start.x,
++ &event->before.start.y,
++ &event->before.end.x,
++ &event->before.end.y);
++
++ /* Create the right content for the history event. */
++ fragment = webkit_dom_document_create_document_fragment (document);
++ /* The removed line. */
++ webkit_dom_node_append_child (
++ WEBKIT_DOM_NODE (fragment),
++ webkit_dom_node_clone_node_with_error (actual_block, TRUE, NULL),
++ NULL);
++ /* The following block, but empty. */
++ webkit_dom_node_append_child (
++ WEBKIT_DOM_NODE (fragment),
++ webkit_dom_node_clone_node_with_error (tmp_block, FALSE, NULL),
++ NULL);
++ g_object_set_data (
++ G_OBJECT (fragment),
++ "history-drag-and-drop",
++ GINT_TO_POINTER (1));
++ }
++ }
++ /* It should act as a Delete key press. */
++ g_object_set_data (G_OBJECT (fragment), "history-delete-key", GINT_TO_POINTER (1));
++
++ event->data.fragment = fragment;
++ e_editor_undo_redo_manager_insert_history_event (manager, event);
++
++ /* WebKit removes the space (if presented) after selection and
++ * we need to create a new history event for it. */
++ if (g_str_has_suffix (range_text, " ") ||
++ g_str_has_suffix (range_text, UNICODE_NBSP))
++ insert_nbsp_history_event (document, manager, TRUE, x, y);
++ else {
++ /* If there is a space before the selection WebKit will remove
++ * it as well unless there is a space after the selection. */
++ gchar *range_text_start;
++ glong start_offset;
++
++ start_offset = webkit_dom_range_get_start_offset (range_clone, NULL);
++ webkit_dom_range_set_start (
++ range_clone,
++ webkit_dom_range_get_start_container (range_clone, NULL),
++ start_offset > 0 ? start_offset - 1 : 0,
++ NULL);
++
++ range_text_start = webkit_dom_range_get_text (range_clone);
++ if (g_str_has_prefix (range_text_start, " ") ||
++ g_str_has_prefix (range_text_start, UNICODE_NBSP)) {
++ if (!end_to_end) {
++ webkit_dom_dom_selection_collapse_to_start (dom_selection, NULL);
++ webkit_dom_dom_selection_modify (
++ dom_selection, "move", "backward", "character");
++ e_editor_dom_selection_get_coordinates (editor_page, &x, &y, &x, &y);
++ }
++ insert_nbsp_history_event (document, manager, TRUE, x, y);
++ }
++
++ g_free (range_text_start);
++ }
++
++ g_free (range_text);
++
++ /* Restore the selection to original state. */
++ webkit_dom_dom_selection_remove_all_ranges (dom_selection);
++ webkit_dom_dom_selection_add_range (dom_selection, range);
++ g_clear_object (&beginning_of_line);
++
++ /* All the things above were about removing the content,
++ * create an AND event to continue later with inserting
++ * the dropped content. */
++ event = g_new0 (EEditorHistoryEvent, 1);
++ event->type = HISTORY_AND;
++ e_editor_undo_redo_manager_insert_history_event (manager, event);
++
++ g_clear_object (&dom_selection);
++
++ g_clear_object (&range);
++ g_clear_object (&range_clone);
++}
++
+ void
+ e_editor_dom_save_history_for_drop (EEditorPage *editor_page)
+ {
+@@ -10880,14 +11246,6 @@ e_editor_dom_save_history_for_drop (EEdi
+
+ range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+
+- /* Remove the last inserted history event as this one was inserted in
+- * body_input_event_cb and is wrong as its type is HISTORY_INPUT. */
+- /* FIXME we could probably disable the HTML input event callback while
+- * doing DnD within the view */
+- event = e_editor_undo_redo_manager_get_current_history_event (manager);
+- if (event && event->type == HISTORY_INPUT)
+- e_editor_undo_redo_manager_remove_current_history_event (manager);
+-
+ event = g_new0 (EEditorHistoryEvent, 1);
+ event->type = HISTORY_INSERT_HTML;
+
+@@ -10897,68 +11255,12 @@ e_editor_dom_save_history_for_drop (EEdi
+ /* Get the HTML content of the dropped content. */
+ event->data.string.to = dom_get_node_inner_html (WEBKIT_DOM_NODE (fragment));
+
+- e_editor_dom_selection_get_coordinates (editor_page,
+- &event->before.start.x,
+- &event->before.start.y,
+- &event->before.end.x,
+- &event->before.end.y);
+-
+- event->before.end.x = event->before.start.x;
+- event->before.end.y = event->before.start.y;
+-
+- if (length > 0)
+- webkit_dom_dom_selection_collapse_to_start (dom_selection, NULL);
+- else
+- webkit_dom_dom_selection_collapse_to_end (dom_selection, NULL);
+-
+- e_editor_dom_selection_get_coordinates (editor_page,
+- &event->after.start.x,
+- &event->after.start.y,
+- &event->after.end.x,
+- &event->after.end.y);
+-
+ e_editor_undo_redo_manager_insert_history_event (manager, event);
+
+- if (!e_editor_page_get_html_mode (editor_page)) {
+- list = webkit_dom_document_query_selector_all (
+- document, "span[style^=font-family]", NULL);
+- length = webkit_dom_node_list_get_length (list);
+- if (length > 0)
+- e_editor_dom_selection_save (editor_page);
+-
+- for (ii = length; ii--;) {
+- WebKitDOMNode *span, *child;
+-
+- span = webkit_dom_node_list_item (list, ii);
+- while ((child = webkit_dom_node_get_first_child (span)))
+- webkit_dom_node_insert_before (
+- webkit_dom_node_get_parent_node (span),
+- child,
+- span,
+- NULL);
+-
+- remove_node (span);
+- }
+- g_clear_object (&list);
+-
+- if (length > 0)
+- e_editor_dom_selection_restore (editor_page);
+- }
+-
+- e_editor_dom_force_spell_check_in_viewport (editor_page);
+-
+ g_clear_object (&range);
+ g_clear_object (&dom_selection);
+ }
+
+-void
+-e_editor_dom_drag_and_drop_end (EEditorPage *editor_page)
+-{
+- g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+-
+- e_editor_dom_save_history_for_drop (editor_page);
+-}
+-
+ static void
+ dom_set_link_color_in_document (EEditorPage *editor_page,
+ const gchar *color,
+@@ -17086,6 +17388,28 @@ e_editor_dom_selection_set_alignment (EE
+ e_editor_page_emit_content_changed (editor_page);
+ }
+
++void
++e_editor_dom_insert_replace_all_history_event (EEditorPage *editor_page,
++ const gchar *search_text,
++ const gchar *replacement)
++{
++ EEditorUndoRedoManager *manager;
++
++ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
++
++ manager = e_editor_page_get_undo_redo_manager (editor_page);
++
++ if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
++ EEditorHistoryEvent *ev = g_new0 (EEditorHistoryEvent, 1);
++ ev->type = HISTORY_REPLACE_ALL;
++
++ ev->data.string.from = g_strdup (search_text);
++ ev->data.string.to = g_strdup (replacement);
++
++ e_editor_undo_redo_manager_insert_history_event (manager, ev);
++ }
++}
++
+ /*
+ * e_html_editor_selection_replace:
+ * @selection: an #EEditorSelection
+@@ -17099,14 +17423,17 @@ e_editor_dom_selection_replace (EEditorP
+ {
+ EEditorHistoryEvent *ev = NULL;
+ EEditorUndoRedoManager *manager;
++ WebKitDOMRange *range = NULL;
+
+ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+
+- if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+- WebKitDOMRange *range = NULL;
++ if (!(range = e_editor_dom_get_current_range (editor_page)) ||
++ e_editor_dom_selection_is_collapsed (editor_page))
++ return;
+
++ if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_REPLACE;
+
+@@ -17116,14 +17443,12 @@ e_editor_dom_selection_replace (EEditorP
+ &ev->before.end.x,
+ &ev->before.end.y);
+
+- range = e_editor_dom_get_current_range (editor_page);
+-
+ ev->data.string.from = webkit_dom_range_get_text (range);
+ ev->data.string.to = g_strdup (replacement);
+-
+- g_clear_object (&range);
+ }
+
++ g_clear_object (&range);
++
+ e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_INSERT_TEXT, replacement);
+
+ if (ev) {
+@@ -17382,3 +17707,98 @@ e_editor_dom_selection_get_coordinates (
+ *start_y += 1;
+ *end_y += 1;
+ }
++
++WebKitDOMRange *
++e_editor_dom_get_range_for_point (WebKitDOMDocument *document,
++ EEditorSelectionPoint point)
++{
++ glong scroll_left, scroll_top;
++ WebKitDOMHTMLElement *body;
++ WebKitDOMRange *range = NULL;
++
++ body = webkit_dom_document_get_body (document);
++ scroll_left = webkit_dom_element_get_scroll_left (WEBKIT_DOM_ELEMENT (body));
++ scroll_top = webkit_dom_element_get_scroll_top (WEBKIT_DOM_ELEMENT (body));
++
++ range = webkit_dom_document_caret_range_from_point (
++ document, point.x - scroll_left, point.y - scroll_top);
++
++ /* The point is outside the viewport, scroll to it. */
++ if (!range) {
++ WebKitDOMDOMWindow *dom_window = NULL;
++
++ dom_window = webkit_dom_document_get_default_view (document);
++ webkit_dom_dom_window_scroll_to (dom_window, point.x, point.y);
++
++ scroll_left = webkit_dom_element_get_scroll_left (WEBKIT_DOM_ELEMENT (body));
++ scroll_top = webkit_dom_element_get_scroll_top (WEBKIT_DOM_ELEMENT (body));
++ range = webkit_dom_document_caret_range_from_point (
++ document, point.x - scroll_left, point.y - scroll_top);
++ g_clear_object (&dom_window);
++ }
++
++ return range;
++}
++
++void
++e_editor_dom_selection_restore_to_history_event_state (EEditorPage *editor_page,
++ EEditorSelection selection_state)
++{
++ WebKitDOMDocument *document;
++ WebKitDOMDOMWindow *dom_window = NULL;
++ WebKitDOMDOMSelection *dom_selection = NULL;
++ WebKitDOMElement *element, *tmp;
++ WebKitDOMRange *range = NULL;
++ gboolean was_collapsed = FALSE;
++
++ g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
++
++ document = e_editor_page_get_document (editor_page);
++ dom_window = webkit_dom_document_get_default_view (document);
++ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
++ g_clear_object (&dom_window);
++
++ /* Restore the selection how it was before the event occured. */
++ range = e_editor_dom_get_range_for_point (document, selection_state.start);
++ webkit_dom_dom_selection_remove_all_ranges (dom_selection);
++ webkit_dom_dom_selection_add_range (dom_selection, range);
++ g_clear_object (&range);
++
++ was_collapsed = selection_state.start.x == selection_state.end.x;
++ was_collapsed = was_collapsed && selection_state.start.y == selection_state.end.y;
++ if (was_collapsed) {
++ g_clear_object (&dom_selection);
++ return;
++ }
++
++ e_editor_dom_selection_save (editor_page);
++
++ element = webkit_dom_document_get_element_by_id (
++ document, "-x-evo-selection-end-marker");
++
++ remove_node (WEBKIT_DOM_NODE (element));
++
++ element = webkit_dom_document_get_element_by_id (
++ document, "-x-evo-selection-start-marker");
++
++ webkit_dom_element_remove_attribute (element, "id");
++
++ range = e_editor_dom_get_range_for_point (document, selection_state.end);
++ webkit_dom_dom_selection_remove_all_ranges (dom_selection);
++ webkit_dom_dom_selection_add_range (dom_selection, range);
++ g_clear_object (&range);
++
++ e_editor_dom_selection_save (editor_page);
++
++ tmp = webkit_dom_document_get_element_by_id (
++ document, "-x-evo-selection-start-marker");
++
++ remove_node (WEBKIT_DOM_NODE (tmp));
++
++ webkit_dom_element_set_id (
++ element, "-x-evo-selection-start-marker");
++
++ e_editor_dom_selection_restore (editor_page);
++
++ g_clear_object (&dom_selection);
++}
+diff -up evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-dom-functions.h.composer-image-insert-undo evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-dom-functions.h
+--- evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-dom-functions.h.composer-image-insert-undo 2016-09-19 10:22:58.000000000 +0200
++++ evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-dom-functions.h 2017-03-24 15:12:21.898422514 +0100
+@@ -24,6 +24,7 @@
+ #undef E_UTIL_INCLUDE_WITHOUT_WEBKIT
+
+ #include "e-editor-page.h"
++#include "e-editor-undo-redo-manager.h"
+
+ /* stephenhay from https://mathiasbynens.be/demo/url-regex */
+ #define URL_PROTOCOLS "news|telnet|nntp|file|https?|s?ftp|webcal|localhost|ssh"
+@@ -158,7 +159,6 @@ void e_editor_dom_process_content_after
+ (EEditorPage *editor_page);
+ guint e_editor_dom_get_caret_offset (EEditorPage *editor_page);
+ guint e_editor_dom_get_caret_position (EEditorPage *editor_page);
+-void e_editor_dom_drag_and_drop_end (EEditorPage *editor_page);
+ void e_editor_dom_set_link_color (EEditorPage *editor_page,
+ const gchar *color);
+ void e_editor_dom_set_visited_link_color
+@@ -208,6 +208,8 @@ WebKitDOMElement *
+ WebKitDOMElement *element);
+ gint e_editor_dom_get_citation_level (WebKitDOMNode *node,
+ gboolean set_plaintext_quoted);
++void e_editor_dom_save_history_for_drag
++ (EEditorPage *editor_page);
+ void e_editor_dom_save_history_for_drop
+ (EEditorPage *editor_page);
+ void e_editor_dom_fix_file_uri_images
+@@ -347,6 +349,10 @@ EContentEditorAlignment
+ void e_editor_dom_selection_set_alignment
+ (EEditorPage *editor_page,
+ EContentEditorAlignment alignment);
++void e_editor_dom_insert_replace_all_history_event
++ (EEditorPage *editor_page,
++ const gchar *search_text,
++ const gchar *replacement);
+ void e_editor_dom_selection_replace (EEditorPage *editor_page,
+ const gchar *replacement);
+ void e_editor_dom_replace_caret_word (EEditorPage *editor_page,
+@@ -370,7 +376,13 @@ void e_editor_dom_selection_get_coordin
+ guint *end_y);
+ gboolean e_editor_dom_is_selection_position_node
+ (WebKitDOMNode *node);
+-
++WebKitDOMRange *
++ e_editor_dom_get_range_for_point
++ (WebKitDOMDocument *document,
++ EEditorSelectionPoint point);
++void e_editor_dom_selection_restore_to_history_event_state
++ (EEditorPage *editor_page,
++ EEditorSelection selection_state);
+ G_END_DECLS
+
+ #endif /* E_EDITOR_DOM_FUNCTIONS_H */
+diff -up evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.c.composer-image-insert-undo evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.c
+--- evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.c.composer-image-insert-undo 2017-03-24 15:12:21.891422514 +0100
++++ evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.c 2017-03-24 15:12:21.899422514 +0100
+@@ -113,114 +113,19 @@ editor_undo_redo_manager_ref_editor_page
+ return g_weak_ref_get (&manager->priv->editor_page);
+ }
+
+-static WebKitDOMRange *
+-get_range_for_point (WebKitDOMDocument *document,
+- EEditorSelectionPoint point)
+-{
+- glong scroll_left, scroll_top;
+- WebKitDOMHTMLElement *body;
+- WebKitDOMRange *range = NULL;
+-
+- body = webkit_dom_document_get_body (document);
+- scroll_left = webkit_dom_element_get_scroll_left (WEBKIT_DOM_ELEMENT (body));
+- scroll_top = webkit_dom_element_get_scroll_top (WEBKIT_DOM_ELEMENT (body));
+-
+- range = webkit_dom_document_caret_range_from_point (
+- document, point.x - scroll_left, point.y - scroll_top);
+-
+- /* The point is outside the viewport, scroll to it. */
+- if (!range) {
+- WebKitDOMDOMWindow *dom_window = NULL;
+-
+- dom_window = webkit_dom_document_get_default_view (document);
+- webkit_dom_dom_window_scroll_to (dom_window, point.x, point.y);
+-
+- scroll_left = webkit_dom_element_get_scroll_left (WEBKIT_DOM_ELEMENT (body));
+- scroll_top = webkit_dom_element_get_scroll_top (WEBKIT_DOM_ELEMENT (body));
+- range = webkit_dom_document_caret_range_from_point (
+- document, point.x - scroll_left, point.y - scroll_top);
+- g_clear_object (&dom_window);
+- }
+-
+- return range;
+-}
+-
+-static void
+-restore_selection_to_history_event_state (EEditorPage *editor_page,
+- EEditorSelection selection_state)
+-{
+- WebKitDOMDocument *document;
+- WebKitDOMDOMWindow *dom_window = NULL;
+- WebKitDOMDOMSelection *dom_selection = NULL;
+- WebKitDOMElement *element, *tmp;
+- WebKitDOMRange *range = NULL;
+- gboolean was_collapsed = FALSE;
+-
+- g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+-
+- document = e_editor_page_get_document (editor_page);
+- dom_window = webkit_dom_document_get_default_view (document);
+- dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+- g_clear_object (&dom_window);
+-
+- /* Restore the selection how it was before the event occured. */
+- range = get_range_for_point (document, selection_state.start);
+- webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+- webkit_dom_dom_selection_add_range (dom_selection, range);
+- g_clear_object (&range);
+-
+- was_collapsed = selection_state.start.x == selection_state.end.x;
+- was_collapsed = was_collapsed && selection_state.start.y == selection_state.end.y;
+- if (was_collapsed) {
+- g_clear_object (&dom_selection);
+- return;
+- }
+-
+- e_editor_dom_selection_save (editor_page);
+-
+- element = webkit_dom_document_get_element_by_id (
+- document, "-x-evo-selection-end-marker");
+-
+- remove_node (WEBKIT_DOM_NODE (element));
+-
+- element = webkit_dom_document_get_element_by_id (
+- document, "-x-evo-selection-start-marker");
+-
+- webkit_dom_element_remove_attribute (element, "id");
+-
+- range = get_range_for_point (document, selection_state.end);
+- webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+- webkit_dom_dom_selection_add_range (dom_selection, range);
+- g_clear_object (&range);
+-
+- e_editor_dom_selection_save (editor_page);
+-
+- tmp = webkit_dom_document_get_element_by_id (
+- document, "-x-evo-selection-start-marker");
+-
+- remove_node (WEBKIT_DOM_NODE (tmp));
+-
+- webkit_dom_element_set_id (
+- element, "-x-evo-selection-start-marker");
+-
+- e_editor_dom_selection_restore (editor_page);
+-
+- g_clear_object (&dom_selection);
+-}
+-
+ static void
+ print_node_inner_html (WebKitDOMNode *node)
+ {
+ gchar *inner_html;
+
+ if (!node) {
+- printf (" none\n");
++ printf (" content: none\n");
+ return;
+ }
+
+ inner_html = dom_get_node_inner_html (node);
+
+- printf (" '%s'\n", inner_html);
++ printf (" content: '%s'\n", inner_html);
+
+ g_free (inner_html);
+ }
+@@ -230,14 +135,22 @@ print_history_event (EEditorHistoryEvent
+ {
+ if (event->type != HISTORY_START && event->type != HISTORY_AND) {
+ printf (" %s\n", event_type_string[event->type]);
+- printf (" before: start_x: %u ; start_y: %u ; end_x: %u ; end_y: %u ;\n",
++ printf (" before: start_x: %u ; start_y: %u ; end_x: %u ; end_y: %u\n",
+ event->before.start.x, event->before.start.y, event->before.end.x, event->before.end.y);
+- printf (" after: start_x: %u ; start_y: %u ; end_x: %u ; end_y: %u ;\n",
++ printf (" after: start_x: %u ; start_y: %u ; end_x: %u ; end_y: %u\n",
+ event->after.start.x, event->after.start.y, event->after.end.x, event->after.end.y);
+ }
+ switch (event->type) {
+ case HISTORY_DELETE:
++ if (g_object_get_data (G_OBJECT (event->data.fragment), "history-delete-key")) {
++ printf (" type: delete\n");
++ } else
++ printf (" type: backspace\n");
++ if (g_object_get_data (G_OBJECT (event->data.fragment), "history-control-key"))
++ printf (" control\n");
+ case HISTORY_INPUT:
++ if (g_object_get_data (G_OBJECT (event->data.fragment), "history-return-key"))
++ printf (" type: return\n");
+ case HISTORY_REMOVE_LINK:
+ case HISTORY_SMILEY:
+ case HISTORY_IMAGE:
+@@ -254,13 +167,13 @@ print_history_event (EEditorHistoryEvent
+ case HISTORY_UNDERLINE:
+ case HISTORY_STRIKETHROUGH:
+ case HISTORY_WRAP:
+- printf (" from %d to %d ;\n", event->data.style.from, event->data.style.to);
++ printf (" from %d to %d\n", event->data.style.from, event->data.style.to);
+ break;
+ case HISTORY_PASTE:
+ case HISTORY_PASTE_AS_TEXT:
+ case HISTORY_PASTE_QUOTED:
+ case HISTORY_INSERT_HTML:
+- printf (" pasting: '%s' ; \n", event->data.string.to);
++ printf (" pasting: '%s' \n", event->data.string.to);
+ break;
+ case HISTORY_HRULE_DIALOG:
+ case HISTORY_IMAGE_DIALOG:
+@@ -275,7 +188,7 @@ print_history_event (EEditorHistoryEvent
+ case HISTORY_FONT_COLOR:
+ case HISTORY_REPLACE:
+ case HISTORY_REPLACE_ALL:
+- printf (" from '%s' to '%s';\n", event->data.string.from, event->data.string.to);
++ printf (" from '%s' to '%s'\n", event->data.string.from, event->data.string.to);
+ break;
+ case HISTORY_START:
+ printf (" HISTORY START\n");
+@@ -454,7 +367,7 @@ undo_delete (EEditorPage *editor_page,
+ g_object_get_data (G_OBJECT (event->data.fragment), "history-concatenating-blocks")) {
+ WebKitDOMNode *node, *block;
+
+- range = get_range_for_point (document, event->after.start);
++ range = e_editor_dom_get_range_for_point (document, event->after.start);
+ webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+ webkit_dom_dom_selection_add_range (dom_selection, range);
+
+@@ -528,7 +441,7 @@ undo_delete (EEditorPage *editor_page,
+ g_clear_object (&range);
+ g_clear_object (&dom_selection);
+
+- restore_selection_to_history_event_state (editor_page, event->before);
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, event->before);
+
+ e_editor_dom_force_spell_check_in_viewport (editor_page);
+
+@@ -544,7 +457,7 @@ undo_delete (EEditorPage *editor_page,
+ WebKitDOMElement *element;
+ WebKitDOMNode *next_sibling;
+
+- range = get_range_for_point (document, event->before.start);
++ range = e_editor_dom_get_range_for_point (document, event->before.start);
+ webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+ webkit_dom_dom_selection_add_range (dom_selection, range);
+ g_clear_object (&range);
+@@ -598,7 +511,7 @@ undo_delete (EEditorPage *editor_page,
+ WebKitDOMNode *node, *current_block, *last_child;
+ WebKitDOMNode *next_block, *insert_before;
+
+- range = get_range_for_point (document, event->after.start);
++ range = e_editor_dom_get_range_for_point (document, event->after.start);
+ webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+ webkit_dom_dom_selection_add_range (dom_selection, range);
+ g_clear_object (&range);
+@@ -698,7 +611,7 @@ undo_delete (EEditorPage *editor_page,
+
+ dom_remove_selection_markers (document);
+
+- restore_selection_to_history_event_state (editor_page, event->before);
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, event->before);
+
+ e_editor_dom_force_spell_check_in_viewport (editor_page);
+
+@@ -794,9 +707,9 @@ undo_delete (EEditorPage *editor_page,
+
+ /* Create temporary node on the selection where the delete occured. */
+ if (webkit_dom_document_fragment_query_selector (event->data.fragment, ".Apple-tab-span", NULL))
+- range = get_range_for_point (document, event->before.start);
++ range = e_editor_dom_get_range_for_point (document, event->before.start);
+ else
+- range = get_range_for_point (document, event->after.start);
++ range = e_editor_dom_get_range_for_point (document, event->after.start);
+
+ /* If redoing an INPUT event that was done in the middle of the
+ * text we need to move one character backward as the range is
+@@ -940,7 +853,7 @@ undo_delete (EEditorPage *editor_page,
+ if (webkit_dom_document_fragment_query_selector (event->data.fragment, "span#-x-evo-selection-start-marker", NULL))
+ e_editor_dom_selection_restore (editor_page);
+ else
+- restore_selection_to_history_event_state (editor_page, event->before);
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, event->before);
+
+ if (event->type != HISTORY_INPUT) {
+ if (e_editor_page_get_magic_smileys_enabled (editor_page))
+@@ -966,7 +879,7 @@ redo_delete (EEditorPage *editor_page,
+ gint ii;
+
+ manager = e_editor_page_get_undo_redo_manager (editor_page);
+- restore_selection_to_history_event_state (editor_page, event->before);
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, event->before);
+
+ delete_key = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (event->data.fragment), "history-delete-key"));
+ control_key = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (event->data.fragment), "history-control-key"));
+@@ -1048,7 +961,7 @@ redo_delete (EEditorPage *editor_page,
+ e_editor_dom_body_key_up_event_process_backspace_or_delete (editor_page, delete_key);
+ e_editor_page_set_renew_history_after_coordinates (editor_page, TRUE);
+
+- restore_selection_to_history_event_state (editor_page, event->after);
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, event->after);
+
+ e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+ }
+@@ -1091,11 +1004,11 @@ undo_redo_style_change (EEditorPage *edi
+ return;
+ }
+
+- restore_selection_to_history_event_state (editor_page, undo ? event->after : event->before);
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->after : event->before);
+
+ func (editor_page, undo ? event->data.style.from : event->data.style.to);
+
+- restore_selection_to_history_event_state (editor_page, undo ? event->before : event->after);
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->before : event->after);
+ }
+
+ static void
+@@ -1105,7 +1018,7 @@ undo_redo_indent (EEditorPage *editor_pa
+ {
+ gboolean was_indent = FALSE;
+
+- restore_selection_to_history_event_state (editor_page, undo ? event->after : event->before);
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->after : event->before);
+
+ was_indent = event->data.style.from && event->data.style.to;
+
+@@ -1114,7 +1027,7 @@ undo_redo_indent (EEditorPage *editor_pa
+ else
+ e_editor_dom_selection_indent (editor_page);
+
+- restore_selection_to_history_event_state (editor_page, undo ? event->before : event->after);
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->before : event->after);
+ }
+
+ static void
+@@ -1122,13 +1035,13 @@ undo_redo_font_color (EEditorPage *edito
+ EEditorHistoryEvent *event,
+ gboolean undo)
+ {
+- restore_selection_to_history_event_state (editor_page, undo ? event->after : event->before);
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->after : event->before);
+
+ e_editor_dom_exec_command (editor_page,
+ E_CONTENT_EDITOR_COMMAND_FORE_COLOR,
+ undo ? event->data.string.from : event->data.string.to);
+
+- restore_selection_to_history_event_state (editor_page, undo ? event->before : event->after);
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->before : event->after);
+ }
+
+ static void
+@@ -1136,7 +1049,7 @@ undo_redo_wrap (EEditorPage *editor_page
+ EEditorHistoryEvent *event,
+ gboolean undo)
+ {
+- restore_selection_to_history_event_state (editor_page, undo ? event->after : event->before);
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->after : event->before);
+
+ if (undo) {
+ WebKitDOMNode *node;
+@@ -1154,7 +1067,7 @@ undo_redo_wrap (EEditorPage *editor_page
+ } else
+ e_editor_dom_selection_wrap (editor_page);
+
+- restore_selection_to_history_event_state (editor_page, undo ? event->before : event->after);
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->before : event->after);
+ }
+
+ static void
+@@ -1170,7 +1083,7 @@ undo_redo_page_dialog (EEditorPage *edit
+ document = e_editor_page_get_document (editor_page);
+ body = webkit_dom_document_get_body (document);
+
+- restore_selection_to_history_event_state (editor_page, undo ? event->after : event->before);
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->after : event->before);
+
+ if (undo) {
+ attributes = webkit_dom_element_get_attributes (WEBKIT_DOM_ELEMENT (body));
+@@ -1249,7 +1162,7 @@ undo_redo_page_dialog (EEditorPage *edit
+ g_clear_object (&attributes);
+ g_clear_object (&attributes_history);
+
+- restore_selection_to_history_event_state (editor_page, undo ? event->before : event->after);
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->before : event->after);
+ }
+
+ static void
+@@ -1262,7 +1175,7 @@ undo_redo_hrule_dialog (EEditorPage *edi
+
+ document = e_editor_page_get_document (editor_page);
+
+- restore_selection_to_history_event_state (editor_page, undo ? event->after : event->before);
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->after : event->before);
+
+ e_editor_dom_selection_save (editor_page);
+ element = webkit_dom_document_get_element_by_id (
+@@ -1314,7 +1227,7 @@ undo_redo_hrule_dialog (EEditorPage *edi
+
+ if (undo) {
+ dom_remove_selection_markers (document);
+- restore_selection_to_history_event_state (editor_page, event->before);
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, event->before);
+ } else
+ e_editor_dom_selection_restore (editor_page);
+ }
+@@ -1330,7 +1243,7 @@ undo_redo_image_dialog (EEditorPage *edi
+
+ document = e_editor_page_get_document (editor_page);
+
+- restore_selection_to_history_event_state (editor_page, undo ? event->after : event->before);
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->after : event->before);
+
+ e_editor_dom_selection_save (editor_page);
+ element = webkit_dom_document_get_element_by_id (
+@@ -1364,7 +1277,7 @@ undo_redo_image_dialog (EEditorPage *edi
+ NULL);
+
+ if (undo)
+- restore_selection_to_history_event_state (editor_page, event->before);
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, event->before);
+ else
+ e_editor_dom_selection_restore (editor_page);
+ }
+@@ -1379,7 +1292,7 @@ undo_redo_link_dialog (EEditorPage *edit
+
+ document = e_editor_page_get_document (editor_page);
+
+- restore_selection_to_history_event_state (editor_page, undo ? event->after : event->before);
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->after : event->before);
+
+ e_editor_dom_selection_save (editor_page);
+
+@@ -1425,7 +1338,7 @@ undo_redo_link_dialog (EEditorPage *edit
+ }
+
+ if (undo)
+- restore_selection_to_history_event_state (editor_page, event->before);
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, event->before);
+ else
+ e_editor_dom_selection_restore (editor_page);
+ }
+@@ -1440,7 +1353,7 @@ undo_redo_table_dialog (EEditorPage *edi
+
+ document = e_editor_page_get_document (editor_page);
+
+- restore_selection_to_history_event_state (editor_page, undo ? event->after : event->before);
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->after : event->before);
+
+ e_editor_dom_selection_save (editor_page);
+ element = webkit_dom_document_get_element_by_id (document, "-x-evo-selection-start-marker");
+@@ -1459,7 +1372,7 @@ undo_redo_table_dialog (EEditorPage *edi
+ webkit_dom_node_clone_node_with_error (undo ? event->data.dom.from : event->data.dom.to, TRUE, NULL),
+ WEBKIT_DOM_NODE (parent),
+ NULL);
+- restore_selection_to_history_event_state (editor_page, event->before);
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, event->before);
+ return;
+ } else
+ return;
+@@ -1486,7 +1399,7 @@ undo_redo_table_dialog (EEditorPage *edi
+ }
+
+ if (undo)
+- restore_selection_to_history_event_state (editor_page, event->before);
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, event->before);
+ else
+ e_editor_dom_selection_restore (editor_page);
+ }
+@@ -1505,7 +1418,7 @@ undo_redo_table_input (EEditorPage *edit
+
+ document = e_editor_page_get_document (editor_page);
+
+- restore_selection_to_history_event_state (editor_page, undo ? event->after : event->before);
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->after : event->before);
+
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+@@ -1554,7 +1467,7 @@ undo_redo_paste (EEditorPage *editor_pag
+ WebKitDOMElement *tmp;
+ WebKitDOMNode *parent;
+
+- restore_selection_to_history_event_state (editor_page, event->after);
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, event->after);
+
+ e_editor_dom_selection_save (editor_page);
+ tmp = webkit_dom_document_get_element_by_id (
+@@ -1573,7 +1486,9 @@ undo_redo_paste (EEditorPage *editor_pag
+ NULL);
+
+ e_editor_dom_selection_restore (editor_page);
+- } else {
++ } else if (event->after.start.x == event->after.end.x &&
++ event->after.start.y == event->after.end.y) {
++ /* Selection was collapsed after the event */
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+ WebKitDOMElement *element, *tmp;
+@@ -1583,8 +1498,8 @@ undo_redo_paste (EEditorPage *editor_pag
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+ g_clear_object (&dom_window);
+
+- /* Restore the selection how it was before the event occured. */
+- range = get_range_for_point (document, event->before.start);
++ /* Restore the selection how it was before the event occurred. */
++ range = e_editor_dom_get_range_for_point (document, event->before.start);
+ webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+ webkit_dom_dom_selection_add_range (dom_selection, range);
+ g_clear_object (&range);
+@@ -1601,7 +1516,7 @@ undo_redo_paste (EEditorPage *editor_pag
+
+ webkit_dom_element_remove_attribute (element, "id");
+
+- range = get_range_for_point (document, event->after.start);
++ range = e_editor_dom_get_range_for_point (document, event->after.start);
+ webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+ webkit_dom_dom_selection_add_range (dom_selection, range);
+ g_clear_object (&range);
+@@ -1622,9 +1537,15 @@ undo_redo_paste (EEditorPage *editor_pag
+ e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_DELETE, NULL);
+
+ e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
++ } else {
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, event->after);
++
++ e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_DELETE, NULL);
++
++ e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+ }
+ } else {
+- restore_selection_to_history_event_state (editor_page, event->before);
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, event->before);
+
+ if (event->type == HISTORY_PASTE)
+ e_editor_dom_convert_and_insert_html_into_selection (editor_page, event->data.string.to, FALSE);
+@@ -1635,6 +1556,8 @@ undo_redo_paste (EEditorPage *editor_pag
+ else
+ e_editor_dom_convert_and_insert_html_into_selection (editor_page, event->data.string.to, FALSE);
+ /* e_editor_selection_insert_as_text (selection, event->data.string.to); */
++
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, event->after);
+ }
+ }
+
+@@ -1657,7 +1580,7 @@ undo_redo_image (EEditorPage *editor_pag
+ WebKitDOMElement *element;
+ WebKitDOMNode *node;
+
+- range = get_range_for_point (document, event->before.start);
++ range = e_editor_dom_get_range_for_point (document, event->before.start);
+ webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+ webkit_dom_dom_selection_add_range (dom_selection, range);
+ g_clear_object (&range);
+@@ -1668,15 +1591,24 @@ undo_redo_image (EEditorPage *editor_pag
+
+ node = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (element));
+
+- if (WEBKIT_DOM_IS_ELEMENT (node))
++ if (WEBKIT_DOM_IS_ELEMENT (node)) {
+ if (element_has_class (WEBKIT_DOM_ELEMENT (node), "-x-evo-resizable-wrapper") ||
+ element_has_class (WEBKIT_DOM_ELEMENT (node), "-x-evo-smiley-wrapper"))
+ remove_node (node);
++ else if (WEBKIT_DOM_IS_HTML_IMAGE_ELEMENT (node)) {
++ WebKitDOMNode *parent;
++
++ parent = webkit_dom_node_get_parent_node (node);
++ if (element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-resizable-wrapper") ||
++ element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-smiley-wrapper"))
++ remove_node (parent);
++ }
++ }
+ e_editor_dom_selection_restore (editor_page);
+ } else {
+ WebKitDOMElement *element;
+
+- range = get_range_for_point (document, event->before.start);
++ range = e_editor_dom_get_range_for_point (document, event->before.start);
+ /* Create temporary node on the selection where the delete occured. */
+ webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+ webkit_dom_dom_selection_add_range (dom_selection, range);
+@@ -1709,9 +1641,10 @@ undo_redo_replace (EEditorPage *editor_p
+
+ document = e_editor_page_get_document (editor_page);
+
+- restore_selection_to_history_event_state (editor_page, undo ? event->after : event->before);
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->after : event->before);
+
+ if (undo) {
++ gint ii = 0;
+ WebKitDOMDOMWindow *dom_window = NULL;
+ WebKitDOMDOMSelection *dom_selection = NULL;
+
+@@ -1719,7 +1652,9 @@ undo_redo_replace (EEditorPage *editor_p
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+ g_clear_object (&dom_window);
+
+- webkit_dom_dom_selection_modify (dom_selection, "extend", "left", "word");
++ for (ii = g_utf8_strlen (event->data.string.to, -1); ii--;)
++ webkit_dom_dom_selection_modify (dom_selection, "extend", "left", "character");
++
+ g_clear_object (&dom_selection);
+ }
+
+@@ -1729,7 +1664,7 @@ undo_redo_replace (EEditorPage *editor_p
+
+ e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+
+- restore_selection_to_history_event_state (editor_page, undo ? event->before : event->after);
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->before : event->after);
+ }
+
+ static void
+@@ -1828,7 +1763,7 @@ undo_redo_remove_link (EEditorPage *edit
+
+ document = e_editor_page_get_document (editor_page);
+
+- restore_selection_to_history_event_state (editor_page, undo ? event->after : event->before);
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->after : event->before);
+
+ if (undo) {
+ WebKitDOMDOMWindow *dom_window = NULL;
+@@ -1857,7 +1792,7 @@ undo_redo_remove_link (EEditorPage *edit
+ } else
+ e_editor_dom_selection_unlink (editor_page);
+
+- restore_selection_to_history_event_state (editor_page, undo ? event->before : event->after);
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->before : event->after);
+ }
+
+ static void
+@@ -1916,7 +1851,7 @@ undo_return_press_after_h_rule (EEditorP
+ WEBKIT_DOM_IS_HTML_HR_ELEMENT (node)) {
+
+ remove_node_if_empty (WEBKIT_DOM_NODE (block));
+- restore_selection_to_history_event_state (editor_page, event->before);
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, event->before);
+
+ return TRUE;
+ }
+@@ -1939,7 +1874,7 @@ undo_input (EEditorUndoRedoManager *mana
+ dom_window = webkit_dom_document_get_default_view (document);
+ dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+
+- restore_selection_to_history_event_state (editor_page, event->after);
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, event->after);
+
+ /* Undoing Return press after the HR element */
+ if (e_editor_page_get_html_mode (editor_page) &&
+@@ -2053,7 +1988,7 @@ undo_redo_citation_split (EEditorPage *e
+ WebKitDOMElement *selection_start, *parent;
+ WebKitDOMNode *citation_before, *citation_after, *child, *last_child, *tmp;
+
+- restore_selection_to_history_event_state (editor_page, event->after);
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, event->after);
+
+ e_editor_dom_selection_save (editor_page);
+ selection_start = webkit_dom_document_get_element_by_id (
+@@ -2137,11 +2072,11 @@ undo_redo_citation_split (EEditorPage *e
+ out:
+ e_editor_dom_merge_siblings_if_necessary (editor_page, NULL);
+
+- restore_selection_to_history_event_state (editor_page, event->before);
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, event->before);
+
+ e_editor_dom_force_spell_check_in_viewport (editor_page);
+ } else {
+- restore_selection_to_history_event_state (editor_page, event->before);
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, event->before);
+
+ if (in_situ) {
+ WebKitDOMElement *selection_start_marker;
+@@ -2176,7 +2111,7 @@ undo_redo_unquote (EEditorPage *editor_p
+
+ document = e_editor_page_get_document (editor_page);
+
+- restore_selection_to_history_event_state (editor_page, undo ? event->after : event->before);
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->after : event->before);
+
+ e_editor_dom_selection_save (editor_page);
+ element = webkit_dom_document_get_element_by_id (
+@@ -2221,7 +2156,7 @@ undo_redo_unquote (EEditorPage *editor_p
+ if (undo)
+ e_editor_dom_selection_restore (editor_page);
+ else
+- restore_selection_to_history_event_state (editor_page, event->after);
++ e_editor_dom_selection_restore_to_history_event_state (editor_page, event->after);
+
+ e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+ }
+@@ -2366,6 +2301,21 @@ e_editor_undo_redo_manager_get_current_h
+ return NULL;
+ }
+
++EEditorHistoryEvent *
++e_editor_undo_redo_manager_get_next_history_event_for (EEditorUndoRedoManager *manager,
++ EEditorHistoryEvent *event)
++{
++ g_return_val_if_fail (E_IS_EDITOR_UNDO_REDO_MANAGER (manager), NULL);
++
++ if (manager->priv->history) {
++ GList *item = g_list_find (manager->priv->history, event);
++ if (item && item->next)
++ return item->next->data;
++ }
++
++ return NULL;
++}
++
+ void
+ e_editor_undo_redo_manager_remove_current_history_event (EEditorUndoRedoManager *manager)
+ {
+@@ -2458,6 +2408,85 @@ e_editor_undo_redo_manager_insert_dash_h
+ }
+
+ g_object_unref (editor_page);
++}
++
++static void
++copy_event_coordinates_to_event (EEditorHistoryEvent *source,
++ EEditorHistoryEvent *target)
++{
++ target->before.start.x = source->before.start.x;
++ target->before.start.y = source->before.start.y;
++ target->before.end.x = source->before.end.x;
++ target->before.end.y = source->before.end.y;
++ target->after.start.x = source->after.start.x;
++ target->after.start.y = source->after.start.y;
++ target->after.end.x = source->after.end.x;
++ target->after.end.y = source->after.end.y;
++}
++
++void
++e_editor_undo_redo_manager_last_drop_operation_did_copy (EEditorUndoRedoManager *manager)
++{
++ EEditorPage *editor_page;
++ GList *history;
++
++ g_return_if_fail (E_IS_EDITOR_UNDO_REDO_MANAGER (manager));
++
++ editor_page = editor_undo_redo_manager_ref_editor_page (manager);
++ g_return_if_fail (editor_page != NULL);
++
++ history = manager->priv->history;
++ if (history) {
++ GList *history_and, *history_delete;
++ EEditorHistoryEvent *original_insert, *item;
++ WebKitDOMDocumentFragment *fragment;
++
++ /* When a drag operation within an editor is performed, we save
++ * the history for it. We always assume that the drop will move
++ * the content (the default action) and not copy it, thus the
++ * history contains one delete item and one 'and' item. If the
++ * action is changed to copy (by holding the Control key during
++ * drop) there is not content deleted, but we saved it to the
++ * history. What this function does is that it changes the
++ * history to not delete any content, but to only insert the
++ * dropped one. */
++ original_insert = history->data;
++ if (original_insert->type != HISTORY_INSERT_HTML || !history->next) {
++ g_object_unref (editor_page);
++ return;
++ }
++
++ history_and = history->next;
++ item = history_and->data;
++ if (item->type != HISTORY_AND || !history_and->next) {
++ g_object_unref (editor_page);
++ return;
++ }
++
++ history_delete = history_and->next;
++ item = history_delete->data;
++ if (item->type != HISTORY_DELETE) {
++ g_object_unref (editor_page);
++ return;
++ }
++
++ /* Change the history type from 'Delete' to 'Insert' */
++ item->type = HISTORY_INSERT_HTML;
++ copy_event_coordinates_to_event (original_insert, item);
++
++ /* Copy the content */
++ fragment = item->data.fragment;
++ item->data.fragment = NULL;
++ item->data.string.to = dom_get_node_inner_html (WEBKIT_DOM_NODE (fragment));
++ g_clear_object (&fragment);
++
++ /* Remove the old insert event */
++ remove_history_event (manager, manager->priv->history);
++ /* And the 'AND' event */
++ remove_history_event (manager, manager->priv->history);
++ }
++
++ g_object_unref (editor_page);
+ }
+
+ gboolean
+diff -up evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.h.composer-image-insert-undo evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.h
+--- evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.h.composer-image-insert-undo 2016-09-19 10:22:58.000000000 +0200
++++ evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.h 2017-03-24 15:12:21.899422514 +0100
+@@ -151,12 +151,21 @@ void e_editor_undo_redo_manager_insert_
+ EEditorHistoryEvent *
+ e_editor_undo_redo_manager_get_current_history_event
+ (EEditorUndoRedoManager *manager);
++
++EEditorHistoryEvent *
++ e_editor_undo_redo_manager_get_next_history_event_for
++ (EEditorUndoRedoManager *manager,
++ EEditorHistoryEvent *event);
++
+ void e_editor_undo_redo_manager_remove_current_history_event
+ (EEditorUndoRedoManager *manager);
+
+ void e_editor_undo_redo_manager_insert_dash_history_event
+ (EEditorUndoRedoManager *manager);
+
++void e_editor_undo_redo_manager_last_drop_operation_did_copy
++ (EEditorUndoRedoManager *manager);
++
+ gboolean e_editor_undo_redo_manager_can_undo
+ (EEditorUndoRedoManager *manager);
+
+diff -up evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-web-extension.c.composer-image-insert-undo evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-web-extension.c
+--- evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-web-extension.c.composer-image-insert-undo 2017-03-13 11:24:55.000000000 +0100
++++ evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-web-extension.c 2017-03-24 15:13:16.839420073 +0100
+@@ -480,9 +480,6 @@ static const gchar *introspection_xml =
+ " "
+ " "
+ " "
+-" "
+-" "
+-" "
+ " "
+ " "
+ " "
+@@ -493,6 +490,9 @@ static const gchar *introspection_xml =
+ " "
+ " "
+ " "
++" "
++" "
++" "
+ ""
+ ""
+ ""
+@@ -503,6 +503,11 @@ static const gchar *introspection_xml =
+ " "
+ " "
+ " "
++" "
++" "
++" "
++" "
++" "
+ " "
+ " "
+ " "
+@@ -581,12 +586,6 @@ static const gchar *introspection_xml =
+ " "
+ " "
+ " "
+-" "
+-" "
+-" "
+-" "
+-" "
+-" "
+ " "
+ " "
+ " "
+@@ -1859,15 +1858,6 @@ handle_method_call (GDBusConnection *con
+ e_editor_dom_replace_image_src (editor_page, selector, uri);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+- } else if (g_strcmp0 (method_name, "DOMDragAndDropEnd") == 0) {
+- g_variant_get (parameters, "(t)", &page_id);
+-
+- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+- if (!editor_page)
+- goto error;
+-
+- e_editor_dom_drag_and_drop_end (editor_page);
+- g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMInsertSmiley") == 0) {
+ const gchar *smiley_name;
+
+@@ -1935,6 +1925,17 @@ handle_method_call (GDBusConnection *con
+ e_editor_dom_insert_image (editor_page, uri);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
++ } else if (g_strcmp0 (method_name, "DOMInsertReplaceAllHistoryEvent") == 0) {
++ const gchar *replacement, *search_text;
++
++ g_variant_get (parameters, "(t&s&s)", &page_id, &search_text, &replacement);
++
++ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
++ if (!editor_page)
++ goto error;
++
++ e_editor_dom_insert_replace_all_history_event (editor_page, search_text, replacement);
++ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMSelectionReplace") == 0) {
+ const gchar *replacement;
+
+@@ -2155,28 +2156,6 @@ handle_method_call (GDBusConnection *con
+ ignore_next_signature_change));
+
+ g_free (new_signature_id);
+- } else if (g_strcmp0 (method_name, "DOMSaveDragAndDropHistory") == 0) {
+- g_variant_get (
+- parameters, "(t)", &page_id);
+-
+- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+- if (!editor_page)
+- goto error;
+-
+- e_composer_dom_save_drag_and_drop_history (editor_page);
+-
+- g_dbus_method_invocation_return_value (invocation, NULL);
+- } else if (g_strcmp0 (method_name, "DOMCleanAfterDragAndDrop") == 0) {
+- g_variant_get (
+- parameters, "(t)", &page_id);
+-
+- editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+- if (!editor_page)
+- goto error;
+-
+- e_composer_dom_clean_after_drag_and_drop (editor_page);
+-
+- g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMGetActiveSignatureUid") == 0) {
+ gchar *value;
+
+@@ -2194,6 +2173,20 @@ handle_method_call (GDBusConnection *con
+ "(@s)",
+ g_variant_new_take_string (
+ value ? value : g_strdup (""))));
++ } else if (g_strcmp0 (method_name, "DOMLastDropOperationDidCopy") == 0) {
++ EEditorUndoRedoManager *manager;
++
++ g_variant_get (parameters, "(t)", &page_id);
++
++ editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
++ if (!editor_page)
++ goto error;
++
++ manager = e_editor_page_get_undo_redo_manager (editor_page);
++ if (manager)
++ e_editor_undo_redo_manager_last_drop_operation_did_copy (manager);
++
++ g_dbus_method_invocation_return_value (invocation, NULL);
+ } else if (g_strcmp0 (method_name, "DOMGetCaretPosition") == 0) {
+ guint32 value;
+
+@@ -2243,7 +2236,7 @@ handle_method_call (GDBusConnection *con
+ return;
+
+ error:
+- g_warning ("Cannot obtain WebKitWebPage for '%ld'", page_id);
++ g_warning ("Cannot obtain WebKitWebPage for '%" G_GUINT64_FORMAT "'", page_id);
+ }
+
+ static void
diff --git a/SOURCES/evolution-3.22.6-coverity-scan-issues.patch b/SOURCES/evolution-3.22.6-coverity-scan-issues.patch
new file mode 100644
index 0000000..328aa15
--- /dev/null
+++ b/SOURCES/evolution-3.22.6-coverity-scan-issues.patch
@@ -0,0 +1,356 @@
+diff --git a/calendar/gui/itip-utils.c b/calendar/gui/itip-utils.c
+index 1d9091a..fefde1f 100644
+--- a/calendar/gui/itip-utils.c
++++ b/calendar/gui/itip-utils.c
+@@ -2316,8 +2316,6 @@ reply_to_calendar_comp (ESourceRegistry *registry,
+
+ cleanup:
+
+- if (comp != NULL)
+- g_object_unref (comp);
+ if (top_level != NULL)
+ icalcomponent_free (top_level);
+
+diff --git a/e-util/e-color-chooser-widget.c b/e-util/e-color-chooser-widget.c
+index 530f199..2ebd044 100644
+--- a/e-util/e-color-chooser-widget.c
++++ b/e-util/e-color-chooser-widget.c
+@@ -203,6 +203,9 @@ find_swatch (GtkContainer *container)
+ GtkWidget *widget = child->data;
+ GtkWidget *swatch;
+
++ if (!widget)
++ continue;
++
+ if (GTK_IS_CONTAINER (widget)) {
+ swatch = find_swatch (GTK_CONTAINER (widget));
+
+diff --git a/e-util/test-html-editor-units.c b/e-util/test-html-editor-units.c
+index 4de3c7e..cfaff58 100644
+--- a/e-util/test-html-editor-units.c
++++ b/e-util/test-html-editor-units.c
+@@ -955,6 +955,7 @@ test_image_insert (TestFixture *fixture)
+ gchar *image_data;
+ gchar *image_data_base64;
+ gsize image_data_length;
++ gboolean success;
+ GError *error = NULL;
+
+ if (!test_utils_process_commands (fixture,
+@@ -968,8 +969,9 @@ test_image_insert (TestFixture *fixture)
+ uri = g_filename_to_uri (filename, NULL, &error);
+ g_assert_no_error (error);
+
+- g_file_get_contents (filename, &image_data, &image_data_length, &error);
++ success = g_file_get_contents (filename, &image_data, &image_data_length, &error);
+ g_assert_no_error (error);
++ g_assert (success);
+
+ g_free (filename);
+
+diff --git a/mail/e-mail-display.c b/mail/e-mail-display.c
+index 957b3dd..e536898 100644
+--- a/mail/e-mail-display.c
++++ b/mail/e-mail-display.c
+@@ -525,15 +525,15 @@ headers_collapsed_signal_cb (GDBusConnection *connection,
+ GVariant *parameters,
+ EMailDisplay *display)
+ {
+- gboolean expanded;
++ gboolean collapsed = FALSE;
+
+ if (g_strcmp0 (signal_name, "HeadersCollapsed") != 0)
+ return;
+
+ if (parameters)
+- g_variant_get (parameters, "(b)", &expanded);
++ g_variant_get (parameters, "(b)", &collapsed);
+
+- e_mail_display_set_headers_collapsed (display, expanded);
++ e_mail_display_set_headers_collapsed (display, collapsed);
+ }
+
+ static void
+diff --git a/mail/e-mail-free-form-exp.c b/mail/e-mail-free-form-exp.c
+index 39af793..da4bb6a 100644
+--- a/mail/e-mail-free-form-exp.c
++++ b/mail/e-mail-free-form-exp.c
+@@ -76,12 +76,9 @@ mail_ffe_build_header_sexp (const gchar *word,
+ camel_sexp_encode_string (encoded_word, word);
+
+ if (!header_names[1]) {
+- if (!sexp)
+- sexp = g_string_new ("");
+- } else if (!sexp) {
+- sexp = g_string_new ("(or ");
++ sexp = g_string_new ("");
+ } else {
+- g_string_append (sexp, "(or ");
++ sexp = g_string_new ("(or ");
+ }
+
+ for (ii = 0; header_names[ii]; ii++) {
+diff --git a/modules/calendar/e-cal-attachment-handler.c b/modules/calendar/e-cal-attachment-handler.c
+index ef28ddd..02aff51 100644
+--- a/modules/calendar/e-cal-attachment-handler.c
++++ b/modules/calendar/e-cal-attachment-handler.c
+@@ -347,7 +347,7 @@ attachment_handler_run_dialog (GtkWindow *parent,
+ break;
+ default:
+ g_warn_if_reached ();
+- return;
++ goto exit;
+ }
+
+ shell_view = e_shell_window_get_shell_view (shell_window,
+diff --git a/modules/calendar/e-cal-shell-content.c b/modules/calendar/e-cal-shell-content.c
+index 1feb1b8..594890a 100644
+--- a/modules/calendar/e-cal-shell-content.c
++++ b/modules/calendar/e-cal-shell-content.c
+@@ -2225,7 +2225,7 @@ e_cal_shell_content_update_filters (ECalShellContent *cal_shell_content,
+ hide_completed_tasks_sexp = calendar_config_get_hide_completed_tasks_sexp (FALSE);
+
+ if (hide_completed_tasks_sexp != NULL) {
+- if (cal_filter != NULL) {
++ if (*cal_filter) {
+ gchar *filter;
+
+ filter = g_strdup_printf ("(and %s %s)", hide_completed_tasks_sexp, cal_filter);
+@@ -2235,7 +2235,7 @@ e_cal_shell_content_update_filters (ECalShellContent *cal_shell_content,
+ cal_shell_content_update_model_filter (data_model, model, hide_completed_tasks_sexp, 0, 0);
+ }
+ } else {
+- cal_shell_content_update_model_filter (data_model, model, cal_filter ? cal_filter : "#t", 0, 0);
++ cal_shell_content_update_model_filter (data_model, model, *cal_filter ? cal_filter : "#t", 0, 0);
+ }
+
+ g_free (hide_completed_tasks_sexp);
+@@ -2275,7 +2275,7 @@ e_cal_shell_content_update_filters (ECalShellContent *cal_shell_content,
+ "(and (or (not (has-start?)) "
+ "(occur-in-time-range? (make-time \"%s\") "
+ "(make-time \"%s\") \"%s\")) %s)",
+- iso_start, iso_end, default_tzloc, cal_filter ? cal_filter : "");
++ iso_start, iso_end, default_tzloc, cal_filter);
+
+ cal_shell_content_update_model_filter (data_model, model, filter, 0, 0);
+
+@@ -2283,7 +2283,7 @@ e_cal_shell_content_update_filters (ECalShellContent *cal_shell_content,
+ g_free (iso_start);
+ g_free (iso_end);
+ } else {
+- cal_shell_content_update_model_filter (data_model, model, cal_filter ? cal_filter : "#t", 0, 0);
++ cal_shell_content_update_model_filter (data_model, model, *cal_filter ? cal_filter : "#t", 0, 0);
+ }
+ }
+ }
+diff --git a/modules/webkit-editor/e-webkit-editor.c b/modules/webkit-editor/e-webkit-editor.c
+index 9fb3060..4b56adf 100644
+--- a/modules/webkit-editor/e-webkit-editor.c
++++ b/modules/webkit-editor/e-webkit-editor.c
+@@ -1781,8 +1781,7 @@ webkit_editor_insert_content (EContentEditor *editor,
+ }
+
+ if (strstr (content, "data-evo-draft") && !(wk_editor->priv->html_mode)) {
+- if (content && *content)
+- set_convert_in_situ (wk_editor, TRUE);
++ set_convert_in_situ (wk_editor, TRUE);
+ wk_editor->priv->reload_in_progress = TRUE;
+ webkit_web_view_load_html (WEBKIT_WEB_VIEW (wk_editor), content, "file://");
+ return;
+@@ -1799,8 +1798,7 @@ webkit_editor_insert_content (EContentEditor *editor,
+ return;
+ }
+ }
+- if (content && *content)
+- set_convert_in_situ (wk_editor, TRUE);
++ set_convert_in_situ (wk_editor, TRUE);
+ }
+
+ wk_editor->priv->reload_in_progress = TRUE;
+diff --git a/modules/webkit-editor/web-extension/e-editor-dom-functions.c b/modules/webkit-editor/web-extension/e-editor-dom-functions.c
+index b79ea50..0eb29bd 100644
+--- a/modules/webkit-editor/web-extension/e-editor-dom-functions.c
++++ b/modules/webkit-editor/web-extension/e-editor-dom-functions.c
+@@ -2722,12 +2722,9 @@ save_history_before_event_in_table (EEditorPage *editor_page,
+ ev = g_new0 (EEditorHistoryEvent, 1);
+ ev->type = HISTORY_TABLE_INPUT;
+
+- if (block) {
+- e_editor_dom_selection_save (editor_page);
+- ev->data.dom.from = g_object_ref (webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (block), TRUE, NULL));
+- e_editor_dom_selection_restore (editor_page);
+- } else
+- ev->data.dom.from = NULL;
++ e_editor_dom_selection_save (editor_page);
++ ev->data.dom.from = g_object_ref (webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (block), TRUE, NULL));
++ e_editor_dom_selection_restore (editor_page);
+
+ e_editor_dom_selection_get_coordinates (editor_page,
+ &ev->before.start.x,
+@@ -5252,7 +5249,7 @@ parse_html_into_blocks (EEditorPage *editor_page,
+ if (camel_debug ("webkit") || camel_debug ("webkit:editor"))
+ printf ("\tto_process: '%s'\n", to_process);
+
+- if (!*to_process && processing_last) {
++ if (to_process && !*to_process && processing_last) {
+ g_free (to_process);
+ to_process = g_strdup (next_token);
+ next_token = NULL;
+@@ -15303,7 +15300,6 @@ e_editor_dom_selection_set_monospace (EEditorPage *editor_page,
+ } else {
+ gboolean is_bold = FALSE, is_italic = FALSE;
+ gboolean is_underline = FALSE, is_strikethrough = FALSE;
+- guint font_size = 0;
+ WebKitDOMElement *tt_element;
+ WebKitDOMNode *node;
+
+@@ -16142,7 +16138,7 @@ process_block_to_block (EEditorPage *editor_page,
+
+ word_wrap_length =
+ e_editor_page_get_word_wrap_length (editor_page);
+- quote = citation_level ? citation_level * 2 : 0;
++ quote = citation_level * 2;
+
+ element = e_editor_dom_wrap_paragraph_length (
+ editor_page, element, word_wrap_length - quote);
+@@ -16487,8 +16483,7 @@ format_change_list_from_list (EEditorPage *editor_page,
+ WEBKIT_DOM_ELEMENT (item), new_list, to);
+
+ webkit_dom_node_append_child (
+- after_selection_end ?
+- source_list_clone : WEBKIT_DOM_NODE (new_list),
++ WEBKIT_DOM_NODE (new_list),
+ WEBKIT_DOM_NODE (processed_list),
+ NULL);
+ } else if (node_is_list (item) && !after_selection_end) {
+@@ -16510,10 +16505,7 @@ format_change_list_from_list (EEditorPage *editor_page,
+ WEBKIT_DOM_NODE (new_list), FALSE, NULL);
+
+ webkit_dom_node_append_child (
+- after_selection_end ?
+- source_list_clone : WEBKIT_DOM_NODE (new_list),
+- clone,
+- NULL);
++ WEBKIT_DOM_NODE (new_list), clone, NULL);
+
+ while ((child = webkit_dom_node_get_first_child (item))) {
+ webkit_dom_node_append_child (clone, child, NULL);
+@@ -16523,10 +16515,7 @@ format_change_list_from_list (EEditorPage *editor_page,
+
+ if (webkit_dom_node_get_first_child (item))
+ webkit_dom_node_append_child (
+- after_selection_end ?
+- source_list_clone : WEBKIT_DOM_NODE (new_list),
+- item,
+- NULL);
++ WEBKIT_DOM_NODE (new_list), item, NULL);
+ else
+ remove_node (item);
+ } else {
+@@ -17351,10 +17340,8 @@ e_editor_dom_selection_get_coordinates (EEditorPage *editor_page,
+ parent = webkit_dom_element_get_offset_parent (parent);
+ }
+
+- if (start_x)
+- *start_x = local_x;
+- if (start_y)
+- *start_y = local_y;
++ *start_x = local_x;
++ *start_y = local_y;
+
+ if (e_editor_dom_selection_is_collapsed (editor_page)) {
+ *end_x = local_x;
+@@ -17379,10 +17366,8 @@ e_editor_dom_selection_get_coordinates (EEditorPage *editor_page,
+ parent = webkit_dom_element_get_offset_parent (parent);
+ }
+
+- if (end_x)
+- *end_x = local_x;
+- if (end_y)
+- *end_y = local_y;
++ *end_x = local_x;
++ *end_y = local_y;
+
+ if (created_selection_markers)
+ e_editor_dom_selection_restore (editor_page);
+diff --git a/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.c b/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.c
+index 5853f0b..1bd5fe9 100644
+--- a/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.c
++++ b/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.c
+@@ -1810,11 +1810,12 @@ undo_redo_replace_all (EEditorUndoRedoManager *manager,
+ if (prev_event->type == HISTORY_REPLACE) {
+ undo_redo_replace (editor_page, prev_event, undo);
+ prev_item = prev_item->prev;
+- } else
++ } else {
++ manager->priv->history = prev_item->next;
+ break;
++ }
+ }
+
+- manager->priv->history = prev_item->next;
+ }
+ }
+
+@@ -2724,7 +2725,7 @@ e_editor_undo_redo_manager_redo (EEditorUndoRedoManager *manager)
+ return;
+ }
+
+- if (history->prev && history->prev->prev) {
++ if (history->prev->prev) {
+ event = history->prev->prev->data;
+ if (event->type == HISTORY_AND) {
+ manager->priv->history = manager->priv->history->prev->prev;
+diff --git a/plugins/mail-notification/mail-notification.c b/plugins/mail-notification/mail-notification.c
+index 5edbdb3..89c6a71 100644
+--- a/plugins/mail-notification/mail-notification.c
++++ b/plugins/mail-notification/mail-notification.c
+@@ -327,7 +327,10 @@ notify_default_action_cb (NotifyNotification *notification,
+ if (!list)
+ list = fallback;
+
+- g_return_if_fail (list != NULL);
++ if (!list) {
++ g_warn_if_reached ();
++ return;
++ }
+
+ /* Present the shell window. */
+ shell_window = E_SHELL_WINDOW (list->data);
+diff --git a/smime/lib/e-cert-db.c b/smime/lib/e-cert-db.c
+index 237c912..2775cf8 100644
+--- a/smime/lib/e-cert-db.c
++++ b/smime/lib/e-cert-db.c
+@@ -413,6 +413,9 @@ p12u_ucs2_ascii_conversion_function(PRBool toUnicode,
+ it.data = inBuf;
+ it.len = inBufLen;
+ dup = SECITEM_DupItem(&it);
++ if (!dup)
++ return PR_FALSE;
++
+ /* If converting Unicode to ASCII, swap bytes before conversion
+ * as neccessary.
+ */
+@@ -425,8 +428,7 @@ p12u_ucs2_ascii_conversion_function(PRBool toUnicode,
+ /* Perform the conversion. */
+ ret = PORT_UCS2_UTF8Conversion (toUnicode, dup->data, dup->len,
+ outBuf, maxOutBufLen, outBufLen);
+- if (dup)
+- SECITEM_ZfreeItem(dup, PR_TRUE);
++ SECITEM_ZfreeItem(dup, PR_TRUE);
+
+ #ifdef DEBUG_CONVERSION
+ if (pk12_debugging) {
+diff --git a/web-extensions/e-dom-utils.c b/web-extensions/e-dom-utils.c
+index 28ac97e..c4f7d61 100644
+--- a/web-extensions/e-dom-utils.c
++++ b/web-extensions/e-dom-utils.c
+@@ -522,7 +522,7 @@ add_css_rule_into_style_sheet (WebKitDOMDocument *document,
+ rule_text = webkit_dom_css_rule_get_css_text (rule);
+
+ /* Find the start of the style => end of the selector */
+- if (rule_text && selector && g_str_has_prefix (rule_text, selector) &&
++ if (rule_text && g_str_has_prefix (rule_text, selector) &&
+ rule_text[selector_length] == ' ' && rule_text[selector_length + 1] == '{') {
+ /* If exists remove it */
+ webkit_dom_css_style_sheet_remove_rule (
diff --git a/SOURCES/evolution-3.22.6-folder-changed-blocked.patch b/SOURCES/evolution-3.22.6-folder-changed-blocked.patch
new file mode 100644
index 0000000..37ca009
--- /dev/null
+++ b/SOURCES/evolution-3.22.6-folder-changed-blocked.patch
@@ -0,0 +1,122 @@
+diff -up evolution-3.22.6/libemail-engine/mail-folder-cache.c.folder-changed-blocked evolution-3.22.6/libemail-engine/mail-folder-cache.c
+--- evolution-3.22.6/libemail-engine/mail-folder-cache.c.folder-changed-blocked 2016-09-19 10:22:58.000000000 +0200
++++ evolution-3.22.6/libemail-engine/mail-folder-cache.c 2017-05-29 23:35:00.143560314 +0200
+@@ -93,6 +93,12 @@ enum {
+
+ static guint signals[LAST_SIGNAL];
+
++typedef enum {
++ E_FIRST_UPDATE_RUNNING,
++ E_FIRST_UPDATE_FAILED,
++ E_FIRST_UPDATE_DONE
++} EFirstUpdateState;
++
+ struct _StoreInfo {
+ volatile gint ref_count;
+
+@@ -107,7 +113,7 @@ struct _StoreInfo {
+ gulong folder_unsubscribed_handler_id;
+
+ GHashTable *folder_info_ht; /* by full_name */
+- gboolean first_update; /* TRUE, then FALSE forever */
++ EFirstUpdateState first_update;
+ GSList *pending_folder_notes; /* Gather note_folder calls during first_update period */
+
+ /* Hold a reference to keep them alive. */
+@@ -261,7 +267,7 @@ store_info_new (CamelStore *store)
+ store_info = g_slice_new0 (StoreInfo);
+ store_info->ref_count = 1;
+ store_info->store = g_object_ref (store);
+- store_info->first_update = TRUE;
++ store_info->first_update = E_FIRST_UPDATE_RUNNING;
+
+ store_info->folder_info_ht = g_hash_table_new_full (
+ (GHashFunc) g_str_hash,
+@@ -1964,7 +1970,7 @@ mail_folder_cache_first_update (MailFold
+ g_object_unref (session);
+
+ g_mutex_lock (&store_info->lock);
+- store_info->first_update = FALSE;
++ store_info->first_update = E_FIRST_UPDATE_DONE;
+ folders = store_info->pending_folder_notes;
+ store_info->pending_folder_notes = NULL;
+ g_mutex_unlock (&store_info->lock);
+@@ -1988,6 +1994,7 @@ mail_folder_cache_note_store_thread (GSi
+ StoreInfo *store_info;
+ GQueue result_queue = G_QUEUE_INIT;
+ AsyncContext *async_context;
++ gboolean success = FALSE;
+ GError *local_error = NULL;
+
+ cache = MAIL_FOLDER_CACHE (source_object);
+@@ -2060,17 +2067,22 @@ mail_folder_cache_note_store_thread (GSi
+
+ /* Do some extra work for the first update. */
+ g_mutex_lock (&store_info->lock);
+- if (store_info->first_update) {
++ if (store_info->first_update != E_FIRST_UPDATE_DONE) {
+ g_mutex_unlock (&store_info->lock);
+ mail_folder_cache_first_update (cache, store_info);
+ } else {
+ g_mutex_unlock (&store_info->lock);
+ }
+
++ success = TRUE;
+ exit:
+ /* We don't want finish() functions being invoked while holding a
+ * locked mutex, so flush the StoreInfo's queue to a local queue. */
+ g_mutex_lock (&store_info->lock);
++
++ if (store_info->first_update != E_FIRST_UPDATE_DONE)
++ store_info->first_update = success ? E_FIRST_UPDATE_DONE : E_FIRST_UPDATE_FAILED;
++
+ e_queue_transfer (&store_info->folderinfo_updates, &result_queue);
+ g_mutex_unlock (&store_info->lock);
+
+@@ -2130,6 +2142,9 @@ mail_folder_cache_note_store (MailFolder
+
+ g_mutex_lock (&store_info->lock);
+
++ if (store_info->first_update != E_FIRST_UPDATE_DONE)
++ store_info->first_update = E_FIRST_UPDATE_RUNNING;
++
+ g_queue_push_tail (
+ &store_info->folderinfo_updates,
+ g_object_ref (simple));
+@@ -2211,18 +2226,23 @@ mail_folder_cache_note_folder (MailFolde
+ * warnings on startup which might be worth tracking down. */
+ if (folder_info == NULL) {
+ StoreInfo *store_info;
+- gboolean retry = FALSE;
++ gboolean retry = FALSE, renote_store = FALSE;
+
+ store_info = mail_folder_cache_ref_store_info (cache, parent_store);
+ if (!store_info)
+ return;
+
+ g_mutex_lock (&store_info->lock);
+- if (store_info->first_update) {
++ if (store_info->first_update != E_FIRST_UPDATE_DONE) {
+ /* The first update did not finish yet, thus add this as a pending
+ folder to be noted once the first update finishes */
+ store_info->pending_folder_notes = g_slist_prepend (
+ store_info->pending_folder_notes, g_object_ref (folder));
++
++ if (store_info->first_update == E_FIRST_UPDATE_FAILED) {
++ store_info->first_update = E_FIRST_UPDATE_RUNNING;
++ renote_store = TRUE;
++ }
+ } else {
+ /* It can be that certain threading interleaving made
+ the first store update finished before we reached
+@@ -2233,7 +2253,9 @@ mail_folder_cache_note_folder (MailFolde
+
+ store_info_unref (store_info);
+
+- if (retry)
++ if (renote_store)
++ mail_folder_cache_note_store (cache, parent_store, NULL, NULL, NULL);
++ else if (retry)
+ folder_info = mail_folder_cache_ref_folder_info (
+ cache, parent_store, full_name);
+
diff --git a/SOURCES/evolution-3.22.6-gtype-init-workaround.patch b/SOURCES/evolution-3.22.6-gtype-init-workaround.patch
new file mode 100644
index 0000000..a51e644
--- /dev/null
+++ b/SOURCES/evolution-3.22.6-gtype-init-workaround.patch
@@ -0,0 +1,30 @@
+diff -up evolution-3.22.6/calendar/alarm-notify/notify-main.c.gtype-init-workaround evolution-3.22.6/calendar/alarm-notify/notify-main.c
+--- evolution-3.22.6/calendar/alarm-notify/notify-main.c.gtype-init-workaround 2017-11-14 11:55:40.525214399 +0100
++++ evolution-3.22.6/calendar/alarm-notify/notify-main.c 2017-11-14 11:56:58.471213321 +0100
+@@ -68,6 +68,11 @@ main (gint argc,
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+
++ /* Workaround https://bugzilla.gnome.org/show_bug.cgi?id=674885 */
++ g_type_ensure (G_TYPE_DBUS_CONNECTION);
++ g_type_ensure (G_TYPE_DBUS_PROXY);
++ g_type_ensure (G_BUS_TYPE_SESSION);
++
+ gtk_init (&argc, &argv);
+
+ alarm_notify_service = alarm_notify_new (NULL, &error);
+diff -up evolution-3.22.6/shell/main.c.gtype-init-workaround evolution-3.22.6/shell/main.c
+--- evolution-3.22.6/shell/main.c.gtype-init-workaround 2017-11-14 11:55:40.525214399 +0100
++++ evolution-3.22.6/shell/main.c 2017-11-14 11:57:34.104212829 +0100
+@@ -459,6 +459,11 @@ main (gint argc,
+ /* Initialize timezone specific global variables */
+ tzset ();
+
++ /* Workaround https://bugzilla.gnome.org/show_bug.cgi?id=674885 */
++ g_type_ensure (G_TYPE_DBUS_CONNECTION);
++ g_type_ensure (G_TYPE_DBUS_PROXY);
++ g_type_ensure (G_BUS_TYPE_SESSION);
++
+ /* The contact maps feature uses clutter-gtk. */
+ #ifdef WITH_CONTACT_MAPS
+ success = gtk_clutter_init_with_args (
diff --git a/SOURCES/evolution-3.22.6-hide-menu-option.patch b/SOURCES/evolution-3.22.6-hide-menu-option.patch
new file mode 100644
index 0000000..891848c
--- /dev/null
+++ b/SOURCES/evolution-3.22.6-hide-menu-option.patch
@@ -0,0 +1,425 @@
+From 439bf03a5120db0ab3bff9958721297b4c32aa71 Mon Sep 17 00:00:00 2001
+From: Milan Crha
+Date: Fri, 7 Oct 2016 13:24:43 +0200
+Subject: Bug 772175 - Allow hiding menu bar (and show it via alt)
+
+---
+ data/org.gnome.evolution.shell.gschema.xml.in | 10 +++
+ shell/e-shell-window-actions.c | 25 +++++++
+ shell/e-shell-window-actions.h | 2 +
+ shell/e-shell-window-private.c | 90 ++++++++++++++++++++++++++
+ shell/e-shell-window-private.h | 3 +
+ shell/e-shell-window.c | 93 ++++++++++++++++++++++++++-
+ shell/e-shell-window.h | 5 ++
+ ui/evolution-shell.ui | 1 +
+ 8 files changed, 228 insertions(+), 1 deletion(-)
+
+diff --git a/data/org.gnome.evolution.shell.gschema.xml.in b/data/org.gnome.evolution.shell.gschema.xml.in
+index 02a5a18..13b3b36 100644
+--- a/data/org.gnome.evolution.shell.gschema.xml.in
++++ b/data/org.gnome.evolution.shell.gschema.xml.in
+@@ -60,6 +60,16 @@
+ <_summary>Window button style
+ <_description>The style of the window buttons. Can be "text", "icons", "both", "toolbar". If "toolbar" is set, the style of the buttons is determined by the GNOME toolbar setting.
+
++
++ true
++ <_summary>Menubar is visible
++ <_description>Whether the menubar should be visible.
++
++
++ true
++ <_summary>Menubar is visible
++ <_description>Whether the menubar should be visible.
++
+
+ true
+ <_summary>Toolbar is visible
+diff --git a/shell/e-shell-window-actions.c b/shell/e-shell-window-actions.c
+index 5665821..c1db9c6 100644
+--- a/shell/e-shell-window-actions.c
++++ b/shell/e-shell-window-actions.c
+@@ -522,6 +522,17 @@ action_search_save_cb (GtkAction *action,
+ }
+
+ /**
++ * E_SHELL_WINDOW_ACTION_SHOW_MENUBAR:
++ * @window: an #EShellWindow
++ *
++ * This toggle action controls whether the menu bar is visible.
++ *
++ * Main menu item: View -> Layout -> Show Menu Bar
++ *
++ * Since: 3.24
++ **/
++
++/**
+ * E_SHELL_WINDOW_ACTION_SHOW_SIDEBAR:
+ * @window: an #EShellWindow
+ *
+@@ -1022,6 +1033,14 @@ static EPopupActionEntry shell_popup_entries[] = {
+
+ static GtkToggleActionEntry shell_toggle_entries[] = {
+
++ { "show-menubar",
++ NULL,
++ N_("Show _Menu Bar"),
++ NULL,
++ N_("Show the menu bar"),
++ NULL,
++ TRUE },
++
+ { "show-sidebar",
+ NULL,
+ N_("Show Side _Bar"),
+@@ -1272,6 +1291,12 @@ e_shell_window_actions_init (EShellWindow *shell_window)
+ e_shell_utils_is_quick_reference_available (e_shell_window_get_shell (shell_window)));
+
+ e_binding_bind_property (
++ shell_window, "menubar-visible",
++ ACTION (SHOW_MENUBAR), "active",
++ G_BINDING_BIDIRECTIONAL |
++ G_BINDING_SYNC_CREATE);
++
++ e_binding_bind_property (
+ shell_window, "sidebar-visible",
+ ACTION (SHOW_SIDEBAR), "active",
+ G_BINDING_BIDIRECTIONAL |
+diff --git a/shell/e-shell-window-actions.h b/shell/e-shell-window-actions.h
+index 09682c4..b3e37fb 100644
+--- a/shell/e-shell-window-actions.h
++++ b/shell/e-shell-window-actions.h
+@@ -74,6 +74,8 @@
+ E_SHELL_WINDOW_ACTION ((window), "search-save")
+ #define E_SHELL_WINDOW_ACTION_SELECT_ALL(window) \
+ E_SHELL_WINDOW_ACTION ((window), "select-all")
++#define E_SHELL_WINDOW_ACTION_SHOW_MENUBAR(window) \
++ E_SHELL_WINDOW_ACTION ((window), "show-menubar")
+ #define E_SHELL_WINDOW_ACTION_SHOW_SIDEBAR(window) \
+ E_SHELL_WINDOW_ACTION ((window), "show-sidebar")
+ #define E_SHELL_WINDOW_ACTION_SHOW_SWITCHER(window) \
+diff --git a/shell/e-shell-window-private.c b/shell/e-shell-window-private.c
+index f9e21b1..2de82b6 100644
+--- a/shell/e-shell-window-private.c
++++ b/shell/e-shell-window-private.c
+@@ -247,6 +247,77 @@ e_shell_window_private_init (EShellWindow *shell_window)
+ }
+
+ static gboolean
++delayed_menubar_show_cb (gpointer user_data)
++{
++ EShellWindow *shell_window = user_data;
++
++ g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), FALSE);
++
++ shell_window->priv->delayed_menubar_show_id = 0;
++
++ if (!e_shell_window_get_menubar_visible (shell_window)) {
++ GtkWidget *main_menu;
++
++ main_menu = e_shell_window_get_managed_widget (shell_window, "/main-menu");
++
++ gtk_widget_show (main_menu);
++ gtk_widget_grab_focus (main_menu);
++ }
++
++ return FALSE;
++}
++
++static void
++e_shell_window_event_after_cb (EShellWindow *shell_window,
++ GdkEvent *event)
++{
++ GtkWidget *main_menu;
++
++ g_return_if_fail (event != NULL);
++
++ if (event->type != GDK_KEY_PRESS &&
++ event->type != GDK_KEY_RELEASE &&
++ event->type != GDK_BUTTON_RELEASE &&
++ event->type != GDK_FOCUS_CHANGE)
++ return;
++
++ g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));
++
++ if (e_shell_window_get_menubar_visible (shell_window))
++ return;
++
++ main_menu = e_shell_window_get_managed_widget (shell_window, "/main-menu");
++
++ if (event->type == GDK_KEY_PRESS) {
++ GdkEventKey *key_event;
++
++ key_event = (GdkEventKey *) event;
++
++ if ((key_event->keyval == GDK_KEY_Alt_L || key_event->keyval == GDK_KEY_Alt_R) &&
++ !(key_event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_SUPER_MASK | GDK_HYPER_MASK | GDK_META_MASK))) {
++ if (shell_window->priv->delayed_menubar_show_id) {
++ g_source_remove (shell_window->priv->delayed_menubar_show_id);
++ shell_window->priv->delayed_menubar_show_id = 0;
++
++ delayed_menubar_show_cb (shell_window);
++ } else {
++ /* To not flash when using Alt+Tab or similar system-wide shortcuts */
++ shell_window->priv->delayed_menubar_show_id =
++ e_named_timeout_add (250, delayed_menubar_show_cb, shell_window);
++ }
++ }
++ } else if (event->type != GDK_BUTTON_RELEASE || !(event->button.state & GDK_MOD1_MASK)) {
++ if (shell_window->priv->delayed_menubar_show_id) {
++ g_source_remove (shell_window->priv->delayed_menubar_show_id);
++ shell_window->priv->delayed_menubar_show_id = 0;
++ }
++
++ if (gtk_widget_get_visible (main_menu))
++ gtk_widget_hide (main_menu);
++ }
++}
++
++static gboolean
+ shell_window_check_is_main_instance (GtkApplication *application,
+ GtkWindow *window)
+ {
+@@ -444,6 +515,11 @@ e_shell_window_private_constructed (EShellWindow *shell_window)
+ G_SETTINGS_BIND_DEFAULT);
+
+ g_settings_bind (
++ settings, "menubar-visible",
++ shell_window, "menubar-visible",
++ G_SETTINGS_BIND_DEFAULT);
++
++ g_settings_bind (
+ settings, "sidebar-visible",
+ shell_window, "sidebar-visible",
+ G_SETTINGS_BIND_DEFAULT);
+@@ -464,6 +540,12 @@ e_shell_window_private_constructed (EShellWindow *shell_window)
+ G_SETTINGS_BIND_DEFAULT);
+ } else {
+ g_settings_bind (
++ settings, "menubar-visible-sub",
++ shell_window, "menubar-visible",
++ G_SETTINGS_BIND_DEFAULT |
++ G_SETTINGS_BIND_GET_NO_CHANGES);
++
++ g_settings_bind (
+ settings, "folder-bar-width-sub",
+ priv->content_pane, "position",
+ G_SETTINGS_BIND_DEFAULT |
+@@ -521,6 +603,9 @@ e_shell_window_private_constructed (EShellWindow *shell_window)
+ gtk_application_add_window (GTK_APPLICATION (shell), window);
+
+ g_object_unref (settings);
++
++ g_signal_connect (shell_window, "event-after",
++ G_CALLBACK (e_shell_window_event_after_cb), NULL);
+ }
+
+ void
+@@ -528,6 +613,11 @@ e_shell_window_private_dispose (EShellWindow *shell_window)
+ {
+ EShellWindowPrivate *priv = shell_window->priv;
+
++ if (priv->delayed_menubar_show_id) {
++ g_source_remove (priv->delayed_menubar_show_id);
++ priv->delayed_menubar_show_id = 0;
++ }
++
+ /* Need to disconnect handlers before we unref the shell. */
+ if (priv->signal_handler_ids != NULL) {
+ GArray *array = priv->signal_handler_ids;
+diff --git a/shell/e-shell-window-private.h b/shell/e-shell-window-private.h
+index 0ef85d5..f761fb8 100644
+--- a/shell/e-shell-window-private.h
++++ b/shell/e-shell-window-private.h
+@@ -90,11 +90,14 @@ struct _EShellWindowPrivate {
+
+ guint destroyed : 1; /* XXX Do we still need this? */
+ guint safe_mode : 1;
++ guint menubar_visible : 1;
+ guint sidebar_visible : 1;
+ guint switcher_visible : 1;
+ guint taskbar_visible : 1;
+ guint toolbar_visible : 1;
+ guint is_main_instance : 1;
++
++ gulong delayed_menubar_show_id;
+ };
+
+ void e_shell_window_private_init (EShellWindow *shell_window);
+diff --git a/shell/e-shell-window.c b/shell/e-shell-window.c
+index 6d3b3c5..0fe229f 100644
+--- a/shell/e-shell-window.c
++++ b/shell/e-shell-window.c
+@@ -38,6 +38,7 @@ enum {
+ PROP_GEOMETRY,
+ PROP_SAFE_MODE,
+ PROP_SHELL,
++ PROP_MENUBAR_VISIBLE,
+ PROP_SIDEBAR_VISIBLE,
+ PROP_SWITCHER_VISIBLE,
+ PROP_TASKBAR_VISIBLE,
+@@ -322,6 +323,12 @@ shell_window_set_property (GObject *object,
+ g_value_get_object (value));
+ return;
+
++ case PROP_MENUBAR_VISIBLE:
++ e_shell_window_set_menubar_visible (
++ E_SHELL_WINDOW (object),
++ g_value_get_boolean (value));
++ return;
++
+ case PROP_SIDEBAR_VISIBLE:
+ e_shell_window_set_sidebar_visible (
+ E_SHELL_WINDOW (object),
+@@ -387,6 +394,12 @@ shell_window_get_property (GObject *object,
+ E_SHELL_WINDOW (object)));
+ return;
+
++ case PROP_MENUBAR_VISIBLE:
++ g_value_set_boolean (
++ value, e_shell_window_get_menubar_visible (
++ E_SHELL_WINDOW (object)));
++ return;
++
+ case PROP_SIDEBAR_VISIBLE:
+ g_value_set_boolean (
+ value, e_shell_window_get_sidebar_visible (
+@@ -507,6 +520,18 @@ shell_window_close_alert (EShellWindow *shell_window)
+ }
+ }
+
++static void
++shell_window_menubar_deactivate_cb (GtkWidget *main_menu,
++ gpointer user_data)
++{
++ EShellWindow *shell_window = user_data;
++
++ g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));
++
++ if (!e_shell_window_get_menubar_visible (shell_window))
++ gtk_widget_hide (main_menu);
++}
++
+ static GtkWidget *
+ shell_window_construct_menubar (EShellWindow *shell_window)
+ {
+@@ -514,7 +539,14 @@ shell_window_construct_menubar (EShellWindow *shell_window)
+
+ main_menu = e_shell_window_get_managed_widget (
+ shell_window, "/main-menu");
+- gtk_widget_show (main_menu);
++
++ g_signal_connect (main_menu, "deactivate",
++ G_CALLBACK (shell_window_menubar_deactivate_cb), shell_window);
++
++ e_binding_bind_property (
++ shell_window, "menubar-visible",
++ main_menu, "visible",
++ G_BINDING_SYNC_CREATE);
+
+ e_signal_connect_notify (
+ shell_window, "notify::active-view",
+@@ -994,6 +1026,24 @@ e_shell_window_class_init (EShellWindowClass *class)
+ G_PARAM_STATIC_STRINGS));
+
+ /**
++ * EShellWindow:menubar-visible
++ *
++ * Whether the shell window's menu bar is visible.
++ *
++ * Since: 3.24
++ **/
++ g_object_class_install_property (
++ object_class,
++ PROP_MENUBAR_VISIBLE,
++ g_param_spec_boolean (
++ "menubar-visible",
++ "Menubar Visible",
++ "Whether the shell window's menu bar is visible",
++ TRUE,
++ G_PARAM_READWRITE |
++ G_PARAM_STATIC_STRINGS));
++
++ /**
+ * EShellWindow:sidebar-visible
+ *
+ * Whether the shell window's side bar is visible.
+@@ -1565,6 +1615,47 @@ e_shell_window_add_action_group (EShellWindow *shell_window,
+ }
+
+ /**
++ * e_shell_window_get_menubar_visible:
++ * @shell_window: an #EShellWindow
++ *
++ * Returns %TRUE if @shell_window's menu bar is visible.
++ *
++ * Returns: %TRUE is the menu bar is visible
++ *
++ * Since: 3.24
++ **/
++gboolean
++e_shell_window_get_menubar_visible (EShellWindow *shell_window)
++{
++ g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), FALSE);
++
++ return shell_window->priv->menubar_visible;
++}
++
++/**
++ * e_shell_window_set_menubar_visible:
++ * @shell_window: an #EShellWindow
++ * @menubar_visible: whether the menu bar should be visible
++ *
++ * Makes @shell_window's menu bar visible or invisible.
++ *
++ * Since: 3.24
++ **/
++void
++e_shell_window_set_menubar_visible (EShellWindow *shell_window,
++ gboolean menubar_visible)
++{
++ g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));
++
++ if (shell_window->priv->menubar_visible == menubar_visible)
++ return;
++
++ shell_window->priv->menubar_visible = menubar_visible;
++
++ g_object_notify (G_OBJECT (shell_window), "menubar-visible");
++}
++
++/**
+ * e_shell_window_get_sidebar_visible:
+ * @shell_window: an #EShellWindow
+ *
+diff --git a/shell/e-shell-window.h b/shell/e-shell-window.h
+index c67c1ea..1c6c9a5 100644
+--- a/shell/e-shell-window.h
++++ b/shell/e-shell-window.h
+@@ -115,6 +115,11 @@ void e_shell_window_set_safe_mode (EShellWindow *shell_window,
+ gboolean safe_mode);
+ void e_shell_window_add_action_group (EShellWindow *shell_window,
+ const gchar *group_name);
++gboolean e_shell_window_get_menubar_visible
++ (EShellWindow *shell_window);
++void e_shell_window_set_menubar_visible
++ (EShellWindow *shell_window,
++ gboolean menubar_visible);
+ gboolean e_shell_window_get_sidebar_visible
+ (EShellWindow *shell_window);
+ void e_shell_window_set_sidebar_visible
+diff --git a/ui/evolution-shell.ui b/ui/evolution-shell.ui
+index bc7e349..9035fb2 100644
+--- a/ui/evolution-shell.ui
++++ b/ui/evolution-shell.ui
+@@ -43,6 +43,7 @@
+
+
+