[geary/mjog/revert-webkit-shared-process] Revert "Merge branch 'mjog/558-webkit-shared-process' into 'mainline'"



commit 618a470a35bfb9d0f818ac7ff59eef952c25d622
Author: Michael James Gratton <mike vee net>
Date:   Wed Feb 12 16:48:24 2020 +1100

    Revert "Merge branch 'mjog/558-webkit-shared-process' into 'mainline'"
    
    Revert merge request GNOME/geary!374 for now since the shared process
    model breaks old-style WebProcess message handler IPC.
    
    This can be un-reverted when out JS is ported to the new Messages API
    that is landing in WebKitGTK 2.28.
    
    This reverts commit e4a5b85698835549d823d3f501d398b411241a37, reversing
    changes made to 66f65254807668bd258624f3b9f210d67e32ed74.

 desktop/org.gnome.Geary.appdata.xml.in.in          |   1 -
 po/POTFILES.in                                     |   2 +-
 src/client/accounts/accounts-editor-edit-pane.vala |   4 +-
 .../accounts/accounts-signature-web-view.vala      |   4 +-
 src/client/application/application-controller.vala |   5 +-
 src/client/application/main.vala                   |   6 +
 ...mponents-web-view.vala => client-web-view.vala} | 156 ++++++++--------
 src/client/composer/composer-web-view.vala         |   6 +-
 src/client/composer/composer-widget.vala           |   8 +-
 .../conversation-viewer/conversation-email.vala    |  26 +--
 .../conversation-viewer/conversation-list-box.vala |  14 +-
 .../conversation-viewer/conversation-message.vala  | 207 ++++-----------------
 .../conversation-viewer/conversation-viewer.vala   |  24 +--
 .../conversation-viewer/conversation-web-view.vala |  41 +---
 src/client/meson.build                             |  12 +-
 src/client/web-process/web-process-extension.vala  |  43 ++---
 ...st-case.vala => client-web-view-test-case.vala} |  23 +--
 ...eb-view-test.vala => client-web-view-test.vala} |  10 +-
 test/client/composer/composer-web-view-test.vala   |   2 +-
 ...state-test.vala => client-page-state-test.vala} |  16 +-
 test/js/composer-page-state-test.vala              |   2 +-
 test/js/conversation-page-state-test.vala          |   2 +-
 test/meson.build                                   |   6 +-
 test/test-client.vala                              |   6 +-
 ui/client-web-view-allow-remote-images.js          |  11 ++
 ui/{components-web-view.js => client-web-view.js}  |   5 +-
 ui/conversation-message.ui                         |   1 -
 ui/org.gnome.Geary.gresource.xml                   |   3 +-
 28 files changed, 240 insertions(+), 406 deletions(-)
---
diff --git a/desktop/org.gnome.Geary.appdata.xml.in.in b/desktop/org.gnome.Geary.appdata.xml.in.in
index 86dc9491..108db1d9 100644
--- a/desktop/org.gnome.Geary.appdata.xml.in.in
+++ b/desktop/org.gnome.Geary.appdata.xml.in.in
@@ -101,7 +101,6 @@
           <li>Extend undo for email actions such as archiving, marking</li>
           <li>Undo sending, saving and discarding composed email</li>
           <li>Undo editing in text fields, including in the composer</li>
-          <li>Conversation loading performance improvements</li>
           <li>App-wide notification preferences now handled by desktop</li>
           <li>Improved missing attachment detection in composer</li>
           <li>Initial plugin system</li>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 4cf10a10..7c983e35 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -31,6 +31,7 @@ src/client/application/goa-mediator.vala
 src/client/application/main.vala
 src/client/application/secret-mediator.vala
 src/client/client-action.vala
+src/client/components/client-web-view.vala
 src/client/components/components-attachment-pane.vala
 src/client/components/components-entry-undo.vala
 src/client/components/components-in-app-notification.vala
@@ -39,7 +40,6 @@ src/client/components/components-placeholder-pane.vala
 src/client/components/components-preferences-window.vala
 src/client/components/components-search-bar.vala
 src/client/components/components-validator.vala
-src/client/components/components-web-view.vala
 src/client/components/count-badge.vala
 src/client/components/folder-popover.vala
 src/client/components/icon-factory.vala
diff --git a/src/client/accounts/accounts-editor-edit-pane.vala 
b/src/client/accounts/accounts-editor-edit-pane.vala
index 2722db6e..c1df9a95 100644
--- a/src/client/accounts/accounts-editor-edit-pane.vala
+++ b/src/client/accounts/accounts-editor-edit-pane.vala
@@ -718,7 +718,7 @@ internal class Accounts.RemoveMailboxCommand : Application.Command {
 internal class Accounts.SignatureChangedCommand : Application.Command {
 
 
-    private Components.WebView signature_view;
+    private ClientWebView signature_view;
     private Geary.AccountInformation account;
 
     private string old_value;
@@ -728,7 +728,7 @@ internal class Accounts.SignatureChangedCommand : Application.Command {
     private bool new_enabled = false;
 
 
-    public SignatureChangedCommand(Components.WebView signature_view,
+    public SignatureChangedCommand(ClientWebView signature_view,
                                    Geary.AccountInformation account) {
         this.signature_view = signature_view;
         this.account = account;
diff --git a/src/client/accounts/accounts-signature-web-view.vala 
b/src/client/accounts/accounts-signature-web-view.vala
index d424dd64..ca31ad5e 100644
--- a/src/client/accounts/accounts-signature-web-view.vala
+++ b/src/client/accounts/accounts-signature-web-view.vala
@@ -8,14 +8,14 @@
 /**
  * A class for editing signatures in the accounts editor.
  */
-public class Accounts.SignatureWebView : Components.WebView {
+public class Accounts.SignatureWebView : ClientWebView {
 
 
     private static WebKit.UserScript? app_script = null;
 
     public static new void load_resources()
         throws GLib.Error {
-        SignatureWebView.app_script = Components.WebView.load_app_script(
+        SignatureWebView.app_script = ClientWebView.load_app_script(
             "signature-web-view.js"
         );
     }
diff --git a/src/client/application/application-controller.vala 
b/src/client/application/application-controller.vala
index 26c19dca..a4d43b07 100644
--- a/src/client/application/application-controller.vala
+++ b/src/client/application/application-controller.vala
@@ -135,12 +135,13 @@ internal class Application.Controller : Geary.BaseObject {
         this.upgrade_dialog = new UpgradeDialog(application);
 
         // Initialise WebKit and WebViews
-        Components.WebView.init_web_context(
+        ClientWebView.init_web_context(
             this.application.config,
             this.application.get_web_extensions_dir(),
             this.application.get_user_cache_directory().get_child("web-resources")
         );
-        Components.WebView.load_resources(
+
+        ClientWebView.load_resources(
             this.application.get_user_config_directory()
         );
         Composer.WebView.load_resources();
diff --git a/src/client/application/main.vala b/src/client/application/main.vala
index f6f971f3..0df87838 100644
--- a/src/client/application/main.vala
+++ b/src/client/application/main.vala
@@ -20,6 +20,12 @@ int main(string[] args) {
     Environment.set_variable("G_TLS_GNUTLS_PRIORITY", "NORMAL:%COMPAT:!VERS-SSL3.0", false);
 #endif
 
+    // Temporary workaround for WebKitGTK deprecation of the
+    // shared-secondary process model. Pull this out in 3.36 when the
+    // proper fix lands. See GNOME/geary#558.
+    Environment.set_variable("WEBKIT_USE_SINGLE_WEB_PROCESS", "1", true);
+
+
     // Init logging right up front so as to capture as many log
     // messages as possible
     Geary.Logging.init();
diff --git a/src/client/components/components-web-view.vala b/src/client/components/client-web-view.vala
similarity index 92%
rename from src/client/components/components-web-view.vala
rename to src/client/components/client-web-view.vala
index 4bda1c11..b65f2150 100644
--- a/src/client/components/components-web-view.vala
+++ b/src/client/components/client-web-view.vala
@@ -1,6 +1,6 @@
 /*
  * Copyright 2016 Software Freedom Conservancy Inc.
- * Copyright 2016-2019 Michael Gratton <mike vee net>
+ * Copyright 2016 Michael Gratton <mike vee net>
  *
  * This software is licensed under the GNU Lesser General Public License
  * (version 2.1 or later). See the COPYING file in this distribution.
@@ -14,7 +14,7 @@
  * integration, Inspector support, and remote and inline image
  * handling.
  */
-public abstract class Components.WebView : WebKit.WebView, Geary.BaseInterface {
+public abstract class ClientWebView : WebKit.WebView, Geary.BaseInterface {
 
 
     /** URI Scheme and delimiter for internal resource loads. */
@@ -65,6 +65,7 @@ public abstract class Components.WebView : WebKit.WebView, Geary.BaseInterface {
     private static WebKit.UserStyleSheet? user_stylesheet = null;
 
     private static WebKit.UserScript? script = null;
+    private static WebKit.UserScript? allow_remote_images = null;
 
 
     /**
@@ -75,18 +76,23 @@ public abstract class Components.WebView : WebKit.WebView, Geary.BaseInterface {
                                         File cache_dir) {
         WebsiteDataManager data_manager = new WebsiteDataManager(cache_dir.get_path());
         WebKit.WebContext context = new WebKit.WebContext.with_website_data_manager(data_manager);
+#if HAS_WEBKIT_SHARED_PROC
+        // Use a shared process so we don't spawn N WebProcess instances
+        // when showing N messages in a conversation.
+        context.set_process_model(WebKit.ProcessModel.SHARED_SECONDARY_PROCESS);
+#endif
         // Use the doc viewer model since each web view instance only
         // ever shows a single HTML document.
         context.set_cache_model(WebKit.CacheModel.DOCUMENT_VIEWER);
 
         context.register_uri_scheme("cid", (req) => {
-                WebView? view = req.get_web_view() as WebView;
+                ClientWebView? view = req.get_web_view() as ClientWebView;
                 if (view != null) {
                     view.handle_cid_request(req);
                 }
             });
         context.register_uri_scheme("geary", (req) => {
-                WebView? view = req.get_web_view() as WebView;
+                ClientWebView? view = req.get_web_view() as ClientWebView;
                 if (view != null) {
                     view.handle_internal_request(req);
                 }
@@ -107,22 +113,25 @@ public abstract class Components.WebView : WebKit.WebView, Geary.BaseInterface {
                 update_spellcheck(context, config);
             });
 
-        WebView.default_context = context;
+        ClientWebView.default_context = context;
     }
 
     /**
-     * Loads static resources used by WebView.
+     * Loads static resources used by ClientWebView.
      */
     public static void load_resources(GLib.File user_dir)
         throws GLib.Error {
-        WebView.script = load_app_script(
-            "components-web-view.js"
+        ClientWebView.script = load_app_script(
+            "client-web-view.js"
+        );
+        ClientWebView.allow_remote_images = load_app_script(
+            "client-web-view-allow-remote-images.js"
         );
 
         foreach (string name in new string[] { USER_CSS, USER_CSS_LEGACY }) {
             GLib.File stylesheet = user_dir.get_child(name);
             try {
-                WebView.user_stylesheet = load_user_stylesheet(stylesheet);
+                ClientWebView.user_stylesheet = load_user_stylesheet(stylesheet);
                 break;
             } catch (GLib.IOError.NOT_FOUND err) {
                 // All good, try the next one or just exit
@@ -290,9 +299,8 @@ public abstract class Components.WebView : WebKit.WebView, Geary.BaseInterface {
     public signal void remote_image_load_blocked();
 
 
-    protected WebView(Application.Configuration config,
-                      WebKit.UserContentManager? custom_manager = null,
-                      WebView? related = null) {
+    protected ClientWebView(Application.Configuration config,
+                            WebKit.UserContentManager? custom_manager = null) {
         WebKit.Settings setts = new WebKit.Settings();
         setts.allow_modal_dialogs = false;
         setts.default_charset = "UTF-8";
@@ -313,40 +321,62 @@ public abstract class Components.WebView : WebKit.WebView, Geary.BaseInterface {
 
         WebKit.UserContentManager content_manager =
              custom_manager ?? new WebKit.UserContentManager();
-        content_manager.add_script(WebView.script);
-        if (WebView.user_stylesheet != null) {
-            content_manager.add_style_sheet(WebView.user_stylesheet);
+        content_manager.add_script(ClientWebView.script);
+        if (ClientWebView.user_stylesheet != null) {
+            content_manager.add_style_sheet(ClientWebView.user_stylesheet);
         }
 
         Object(
-            settings: setts,
+            web_context: ClientWebView.default_context,
             user_content_manager: content_manager,
-            web_context: WebView.default_context
+            settings: setts
         );
         base_ref();
-        init(config);
-    }
 
-    /**
-     * Constructs a new web view with a new shared WebProcess.
-     *
-     * The new view will use the same WebProcess, settings and content
-     * manager as the given related view's.
-     *
-     * @see WebKit.WebView.with_related_view
-     */
-    protected WebView.with_related_view(Application.Configuration config,
-                                        WebView related) {
-        Object(
-            related_view: related,
-            settings: related.get_settings(),
-            user_content_manager: related.user_content_manager
+        // XXX get the allow prefix from the extension somehow
+
+        this.decide_policy.connect(on_decide_policy);
+        this.web_process_terminated.connect((reason) => {
+                warning("Web process crashed: %s", reason.to_string());
+            });
+
+        register_message_handler(
+            COMMAND_STACK_CHANGED, on_command_stack_changed
         );
-        base_ref();
-        init(config);
+        register_message_handler(
+            CONTENT_LOADED, on_content_loaded
+        );
+        register_message_handler(
+            DOCUMENT_MODIFIED, on_document_modified
+        );
+        register_message_handler(
+            PREFERRED_HEIGHT_CHANGED, on_preferred_height_changed
+        );
+        register_message_handler(
+            REMOTE_IMAGE_LOAD_BLOCKED, on_remote_image_load_blocked
+        );
+        register_message_handler(
+            SELECTION_CHANGED, on_selection_changed
+        );
+
+        // Manage zoom level, ensure it's sane
+        config.bind(Application.Configuration.CONVERSATION_VIEWER_ZOOM_KEY, this, "zoom_level");
+        if (this.zoom_level < ZOOM_MIN) {
+            this.zoom_level = ZOOM_MIN;
+        } else if (this.zoom_level > ZOOM_MAX) {
+            this.zoom_level = ZOOM_MAX;
+        }
+        this.scroll_event.connect(on_scroll_event);
+
+        // Watch desktop font settings
+        Settings system_settings = config.gnome_interface;
+        system_settings.bind("document-font-name", this,
+                             "document-font", SettingsBindFlags.DEFAULT);
+        system_settings.bind("monospace-font-name", this,
+                             "monospace-font", SettingsBindFlags.DEFAULT);
     }
 
-    ~WebView() {
+    ~ClientWebView() {
         base_unref();
     }
 
@@ -403,7 +433,13 @@ public abstract class Components.WebView : WebKit.WebView, Geary.BaseInterface {
      * effect.
      */
     public void allow_remote_image_loading() {
-        this.run_javascript.begin("_gearyAllowRemoteResourceLoads = true", null);
+        // Use a separate script here since we need to update the
+        // value of window.geary.allow_remote_image_loading after it
+        // was first created by client-web-view.js (which is loaded at
+        // the start of page load), but before the page load is
+        // started (so that any remote images present are actually
+        // loaded).
+        this.user_content_manager.add_script(ClientWebView.allow_remote_images);
     }
 
     /**
@@ -479,7 +515,7 @@ public abstract class Components.WebView : WebKit.WebView, Geary.BaseInterface {
                                                    JavaScriptMessageHandler handler) {
         // XXX can't use the delegate directly, see b.g.o Bug
         // 604781. However the workaround below creates a circular
-        // reference, causing WebView instances to leak. So to
+        // reference, causing ClientWebView instances to leak. So to
         // work around that we need to record handler ids and
         // disconnect them when being destroyed.
         ulong id = this.user_content_manager.script_message_received[name].connect(
@@ -491,50 +527,6 @@ public abstract class Components.WebView : WebKit.WebView, Geary.BaseInterface {
         }
     }
 
-    private void init(Application.Configuration config) {
-        // XXX get the allow prefix from the extension somehow
-
-        this.decide_policy.connect(on_decide_policy);
-        this.web_process_terminated.connect((reason) => {
-                warning("Web process crashed: %s", reason.to_string());
-            });
-
-        register_message_handler(
-            COMMAND_STACK_CHANGED, on_command_stack_changed
-        );
-        register_message_handler(
-            CONTENT_LOADED, on_content_loaded
-        );
-        register_message_handler(
-            DOCUMENT_MODIFIED, on_document_modified
-        );
-        register_message_handler(
-            PREFERRED_HEIGHT_CHANGED, on_preferred_height_changed
-        );
-        register_message_handler(
-            REMOTE_IMAGE_LOAD_BLOCKED, on_remote_image_load_blocked
-        );
-        register_message_handler(
-            SELECTION_CHANGED, on_selection_changed
-        );
-
-        // Manage zoom level, ensure it's sane
-        config.bind(Application.Configuration.CONVERSATION_VIEWER_ZOOM_KEY, this, "zoom_level");
-        if (this.zoom_level < ZOOM_MIN) {
-            this.zoom_level = ZOOM_MIN;
-        } else if (this.zoom_level > ZOOM_MAX) {
-            this.zoom_level = ZOOM_MAX;
-        }
-        this.scroll_event.connect(on_scroll_event);
-
-        // Watch desktop font settings
-        Settings system_settings = config.gnome_interface;
-        system_settings.bind("document-font-name", this,
-                             "document-font", SettingsBindFlags.DEFAULT);
-        system_settings.bind("monospace-font-name", this,
-                             "monospace-font", SettingsBindFlags.DEFAULT);
-    }
-
     private void handle_cid_request(WebKit.URISchemeRequest request) {
         if (!handle_internal_response(request)) {
             request.finish_error(new FileError.NOENT("Unknown CID"));
diff --git a/src/client/composer/composer-web-view.vala b/src/client/composer/composer-web-view.vala
index 3dabf7fe..9c78ec75 100644
--- a/src/client/composer/composer-web-view.vala
+++ b/src/client/composer/composer-web-view.vala
@@ -9,7 +9,7 @@
 /**
  * A WebView for editing messages in the composer.
  */
-public class Composer.WebView : Components.WebView {
+public class Composer.WebView : ClientWebView {
 
 
     // WebKit message handler names
@@ -92,10 +92,10 @@ public class Composer.WebView : Components.WebView {
 
     public static new void load_resources()
         throws Error {
-        WebView.app_style = Components.WebView.load_app_stylesheet(
+        WebView.app_style = ClientWebView.load_app_stylesheet(
             "composer-web-view.css"
         );
-        WebView.app_script = Components.WebView.load_app_script(
+        WebView.app_script = ClientWebView.load_app_script(
             "composer-web-view.js"
         );
     }
diff --git a/src/client/composer/composer-widget.vala b/src/client/composer/composer-widget.vala
index 69970b58..73d68a70 100644
--- a/src/client/composer/composer-widget.vala
+++ b/src/client/composer/composer-widget.vala
@@ -1320,7 +1320,7 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
         email.inline_files.set_all(this.inline_files);
         email.cid_files.set_all(this.cid_files);
 
-        email.img_src_prefix = Components.WebView.INTERNAL_URL_PREFIX;
+        email.img_src_prefix = ClientWebView.INTERNAL_URL_PREFIX;
 
         try {
             if (!for_draft) {
@@ -2077,7 +2077,7 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
                         string unique_filename;
                         add_inline_part(byte_buffer, filename, out unique_filename);
                         this.editor.insert_image(
-                            Components.WebView.INTERNAL_URL_PREFIX + unique_filename
+                            ClientWebView.INTERNAL_URL_PREFIX + unique_filename
                         );
                         throw new Geary.EngineError.UNSUPPORTED("Mock method");
                     } catch (Error error) {
@@ -2807,7 +2807,7 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
                     string unique_filename;
                     add_inline_part(file_buffer, path, out unique_filename);
                     this.editor.insert_image(
-                        Components.WebView.INTERNAL_URL_PREFIX + unique_filename
+                        ClientWebView.INTERNAL_URL_PREFIX + unique_filename
                     );
                 } catch (Error err) {
                     attachment_failed(err.message);
@@ -2906,7 +2906,7 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
         }
 
         this.editor.insert_image(
-            Components.WebView.INTERNAL_URL_PREFIX + unique_filename
+            ClientWebView.INTERNAL_URL_PREFIX + unique_filename
         );
     }
 
diff --git a/src/client/conversation-viewer/conversation-email.vala 
b/src/client/conversation-viewer/conversation-email.vala
index 2f2e9006..02ac6096 100644
--- a/src/client/conversation-viewer/conversation-email.vala
+++ b/src/client/conversation-viewer/conversation-email.vala
@@ -479,7 +479,7 @@ public class ConversationEmail : Gtk.Box, Geary.BaseInterface {
         if (this.body_selection_message != null) {
             try {
                 selection =
-                   yield this.body_selection_message.get_selection_for_quoting();
+                   yield this.body_selection_message.web_view.get_selection_for_quoting();
             } catch (Error err) {
                 debug("Failed to get selection for quoting: %s", err.message);
             }
@@ -495,7 +495,7 @@ public class ConversationEmail : Gtk.Box, Geary.BaseInterface {
         if (this.body_selection_message != null) {
             try {
                 selection =
-                   yield this.body_selection_message.get_selection_for_find();
+                   yield this.body_selection_message.web_view.get_selection_for_find();
             } catch (Error err) {
                 debug("Failed to get selection for find: %s", err.message);
             }
@@ -588,10 +588,12 @@ public class ConversationEmail : Gtk.Box, Geary.BaseInterface {
         Json.Generator generator = new Json.Generator();
         generator.set_root(builder.get_root());
         string js = "geary.addPrintHeaders(" + generator.to_data(null) + ");";
-        yield this.primary_message.run_javascript(js, null);
+        yield this.primary_message.web_view.run_javascript(js, null);
 
         Gtk.Window? window = get_toplevel() as Gtk.Window;
-        WebKit.PrintOperation op = this.primary_message.new_print_operation();
+        WebKit.PrintOperation op = new WebKit.PrintOperation(
+            this.primary_message.web_view
+        );
         Gtk.PrintSettings settings = new Gtk.PrintSettings();
 
         if (this.email.subject != null) {
@@ -618,14 +620,14 @@ public class ConversationEmail : Gtk.Box, Geary.BaseInterface {
     }
 
     private void connect_message_view_signals(ConversationMessage view) {
-        view.content_loaded.connect(on_content_loaded);
         view.flag_remote_images.connect(on_flag_remote_images);
         view.internal_link_activated.connect((y) => {
                 internal_link_activated(y);
             });
-        view.internal_resource_loaded.connect(on_resource_loaded);
         view.save_image.connect(on_save_image);
-        view.selection_changed.connect((has_selection) => {
+        view.web_view.internal_resource_loaded.connect(on_resource_loaded);
+        view.web_view.content_loaded.connect(on_content_loaded);
+        view.web_view.selection_changed.connect((has_selection) => {
                 this.body_selection_message = has_selection ? view : null;
                 body_selection_changed(has_selection);
             });
@@ -701,7 +703,7 @@ public class ConversationEmail : Gtk.Box, Geary.BaseInterface {
 
         // Load all messages
 
-        this.primary_message.add_internal_resources(cid_resources);
+        this.primary_message.web_view.add_internal_resources(cid_resources);
         yield this.primary_message.load_message_body(
             message, this.load_cancellable
         );
@@ -719,7 +721,7 @@ public class ConversationEmail : Gtk.Box, Geary.BaseInterface {
                     this.config
                 );
             connect_message_view_signals(attached_message);
-            attached_message.add_internal_resources(cid_resources);
+            attached_message.web_view.add_internal_resources(cid_resources);
             this.sub_messages.add(attached_message);
             this._attached_messages.add(attached_message);
             attached_message.load_contacts.begin(this.load_cancellable);
@@ -906,8 +908,8 @@ public class ConversationEmail : Gtk.Box, Geary.BaseInterface {
                                Geary.Memory.Buffer? content) {
         var main = get_toplevel() as Application.MainWindow;
         if (main != null) {
-            if (uri.has_prefix(Components.WebView.CID_URL_PREFIX)) {
-                string cid = uri.substring(Components.WebView.CID_URL_PREFIX.length);
+            if (uri.has_prefix(ClientWebView.CID_URL_PREFIX)) {
+                string cid = uri.substring(ClientWebView.CID_URL_PREFIX.length);
                 try {
                     Geary.Attachment attachment = this.email.get_attachment_by_content_id(
                         cid
@@ -954,7 +956,7 @@ public class ConversationEmail : Gtk.Box, Geary.BaseInterface {
     private void on_content_loaded() {
         bool all_loaded = true;
         foreach (ConversationMessage message in this) {
-            if (!message.is_content_loaded) {
+            if (!message.web_view.is_content_loaded) {
                 all_loaded = false;
                 break;
             }
diff --git a/src/client/conversation-viewer/conversation-list-box.vala 
b/src/client/conversation-viewer/conversation-list-box.vala
index 8668b59d..4e501aa4 100644
--- a/src/client/conversation-viewer/conversation-list-box.vala
+++ b/src/client/conversation-viewer/conversation-list-box.vala
@@ -898,7 +898,7 @@ public class ConversationListBox : Gtk.ListBox, Geary.BaseInterface {
      */
     public void zoom_in() {
         message_view_iterator().foreach((msg_view) => {
-                msg_view.zoom_in();
+                msg_view.web_view.zoom_in();
                 return true;
             });
     }
@@ -908,7 +908,7 @@ public class ConversationListBox : Gtk.ListBox, Geary.BaseInterface {
      */
     public void zoom_out() {
         message_view_iterator().foreach((msg_view) => {
-                msg_view.zoom_out();
+                msg_view.web_view.zoom_out();
                 return true;
             });
     }
@@ -918,7 +918,7 @@ public class ConversationListBox : Gtk.ListBox, Geary.BaseInterface {
      */
     public void zoom_reset() {
         message_view_iterator().foreach((msg_view) => {
-                msg_view.zoom_reset();
+                msg_view.web_view.zoom_reset();
                 return true;
             });
     }
@@ -1122,7 +1122,8 @@ public class ConversationListBox : Gtk.ListBox, Geary.BaseInterface {
         row.get_allocation(out alloc);
 
         int x = 0, y = 0;
-        row.view.primary_message.web_view_translate_coordinates(row, x, anchor_y, out x, out y);
+        ConversationWebView web_view = row.view.primary_message.web_view;
+        web_view.translate_coordinates(row, x, anchor_y, out x, out y);
 
         Gtk.Adjustment adj = get_adjustment();
         y = alloc.y + y;
@@ -1155,13 +1156,14 @@ public class ConversationListBox : Gtk.ListBox, Geary.BaseInterface {
                 ConversationMessage conversation_message = view.primary_message;
                  int body_top = 0;
                  int body_left = 0;
-                 conversation_message.web_view_translate_coordinates(
+                 ConversationWebView web_view = conversation_message.web_view;
+                 web_view.translate_coordinates(
                      this,
                      0, 0,
                      out body_left, out body_top
                  );
 
-                 int body_height = conversation_message.web_view_get_allocated_height();
+                 int body_height = web_view.get_allocated_height();
                  int body_bottom = body_top + body_height;
 
                  // Only mark the email as read if it's actually visible
diff --git a/src/client/conversation-viewer/conversation-message.vala 
b/src/client/conversation-viewer/conversation-message.vala
index 77c1743d..e6548a6d 100644
--- a/src/client/conversation-viewer/conversation-message.vala
+++ b/src/client/conversation-viewer/conversation-message.vala
@@ -218,19 +218,8 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
     [GtkChild]
     internal Gtk.Grid infobars;
 
-    /**
-     * Emitted when web_view's content has finished loaded.
-     *
-     * See {@link Components.WebView.is_content_loaded} for details.
-     */
-    internal bool is_content_loaded {
-        get {
-            return this.web_view != null && this.web_view.is_content_loaded;
-        }
-    }
-
     /** HTML view that displays the message body. */
-    private ConversationWebView? web_view { get; private set; }
+    internal ConversationWebView web_view { get; private set; }
 
     // The message headers represented by this view
     private Geary.EmailHeaderSet headers;
@@ -346,19 +335,6 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
         string uri, string? alt_text, Geary.Memory.Buffer? buffer
     );
 
-    /** Emitted when web_view has loaded a resource added to it. */
-    public signal void internal_resource_loaded(string name);
-
-    /** Emitted when web_view's selection has changed. */
-    public signal void selection_changed(bool has_selection);
-
-    /**
-     * Emitted when web_view's content has finished loaded.
-     *
-     * See {@link Components.WebView.is_content_loaded} for details.
-     */
-    public signal void content_loaded();
-
 
     /**
      * Constructs a new view from an email's headers and body.
@@ -400,18 +376,6 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
         );
     }
 
-    private void trigger_internal_resource_loaded(string name) {
-        internal_resource_loaded(name);
-    }
-
-    private void trigger_content_loaded() {
-        content_loaded();
-    }
-
-    private void trigger_selection_changed(bool has_selection) {
-        selection_changed(has_selection);
-    }
-
     private ConversationMessage(Geary.EmailHeaderSet headers,
                                 string? preview,
                                 bool load_remote_resources,
@@ -432,10 +396,19 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
             .activate.connect(on_copy_email_address);
         add_action(ACTION_COPY_LINK, true, VariantType.STRING)
             .activate.connect(on_copy_link);
+        add_action(ACTION_COPY_SELECTION, false).activate.connect(() => {
+                web_view.copy_clipboard();
+            });
+        add_action(ACTION_OPEN_INSPECTOR, config.enable_inspector).activate.connect(() => {
+                this.web_view.get_inspector().show();
+            });
         add_action(ACTION_OPEN_LINK, true, VariantType.STRING)
             .activate.connect(on_link_activated);
         add_action(ACTION_SAVE_IMAGE, true, new VariantType("(sms)"))
             .activate.connect(on_save_image);
+        add_action(ACTION_SELECT_ALL, true).activate.connect(() => {
+                web_view.select_all();
+            });
         insert_action_group("msg", message_actions);
 
         // Context menu
@@ -488,37 +461,9 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
             this.subject_searchable = headers.subject.value.casefold();
         }
 
-        this.body_container.set_has_tooltip(true); // Used to show link URLs
-        this.show_progress_timeout = new Geary.TimeoutManager.milliseconds(
-            Util.Gtk.SHOW_PROGRESS_TIMEOUT_MSEC, this.on_show_progress_timeout
-        );
-        this.hide_progress_timeout = new Geary.TimeoutManager.milliseconds(
-            Util.Gtk.HIDE_PROGRESS_TIMEOUT_MSEC, this.on_hide_progress_timeout
-        );
-
-        this.progress_pulse = new Geary.TimeoutManager.milliseconds(
-            Util.Gtk.PROGRESS_PULSE_TIMEOUT_MSEC, this.body_progress.pulse
-        );
-        this.progress_pulse.repetition = FOREVER;
-    }
-
-    private void initialize_web_view() {
-        var viewer = get_ancestor(typeof(ConversationViewer)) as ConversationViewer;
-
-        // Ensure we share the same WebProcess with the last one
-        // constructed if possible.
-        if (viewer != null && viewer.previous_web_view != null) {
-            this.web_view = new ConversationWebView.with_related_view(
-                this.config,
-                viewer.previous_web_view
-            );
-        } else {
-            this.web_view = new ConversationWebView(this.config);
-        }
-        if (viewer != null) {
-            viewer.previous_web_view = this.web_view;
-        }
+        // Web view
 
+        this.web_view = new ConversationWebView(config);
         this.web_view.context_menu.connect(on_context_menu);
         this.web_view.deceptive_link_clicked.connect(on_deceptive_link_clicked);
         this.web_view.link_activated.connect((link) => {
@@ -531,22 +476,23 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
                 this.remote_images_infobar.show();
             });
         this.web_view.selection_changed.connect(on_selection_changed);
-        this.web_view.internal_resource_loaded.connect(trigger_internal_resource_loaded);
-        this.web_view.content_loaded.connect(trigger_content_loaded);
-        this.web_view.selection_changed.connect(trigger_selection_changed);
         this.web_view.set_hexpand(true);
         this.web_view.set_vexpand(true);
         this.web_view.show();
+
+        this.body_container.set_has_tooltip(true); // Used to show link URLs
         this.body_container.add(this.web_view);
-        add_action(ACTION_COPY_SELECTION, false).activate.connect(() => {
-                web_view.copy_clipboard();
-            });
-        add_action(ACTION_OPEN_INSPECTOR, config.enable_inspector).activate.connect(() => {
-                this.web_view.get_inspector().show();
-            });
-        add_action(ACTION_SELECT_ALL, true).activate.connect(() => {
-                web_view.select_all();
-            });
+        this.show_progress_timeout = new Geary.TimeoutManager.milliseconds(
+            Util.Gtk.SHOW_PROGRESS_TIMEOUT_MSEC, this.on_show_progress_timeout
+        );
+        this.hide_progress_timeout = new Geary.TimeoutManager.milliseconds(
+            Util.Gtk.HIDE_PROGRESS_TIMEOUT_MSEC, this.on_hide_progress_timeout
+        );
+
+        this.progress_pulse = new Geary.TimeoutManager.milliseconds(
+            Util.Gtk.PROGRESS_PULSE_TIMEOUT_MSEC, this.body_progress.pulse
+        );
+        this.progress_pulse.repetition = FOREVER;
     }
 
     ~ConversationMessage() {
@@ -562,77 +508,10 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
         base.destroy();
     }
 
-    public async string? get_selection_for_quoting() throws Error {
-        if (this.web_view == null)
-            initialize_web_view();
-        return yield web_view.get_selection_for_quoting();
-    }
-
-    public async string? get_selection_for_find() throws Error {
-        if (this.web_view == null)
-            initialize_web_view();
-        return yield web_view.get_selection_for_find();
-    }
-
-    /**
-     * Adds a set of internal resources to web_view.
-     *
-     * @see add_internal_resource
-     */
-    public void add_internal_resources(Gee.Map<string,Geary.Memory.Buffer> res) {
-        if (this.web_view == null)
-            initialize_web_view();
-        web_view.add_internal_resources(res);
-    }
-
-    public WebKit.PrintOperation new_print_operation() {
-        if (this.web_view == null)
-            initialize_web_view();
-        return new WebKit.PrintOperation(web_view);
-    }
-
-    public async void run_javascript (string script, Cancellable? cancellable) throws Error {
-        if (this.web_view == null)
-            initialize_web_view();
-        yield web_view.run_javascript(script, cancellable);
-    }
-
-    public void zoom_in() {
-        if (this.web_view == null)
-            initialize_web_view();
-        web_view.zoom_in();
-    }
-
-    public void zoom_out() {
-        if (this.web_view == null)
-            initialize_web_view();
-        web_view.zoom_out();
-    }
-
-    public void zoom_reset() {
-        if (this.web_view == null)
-            initialize_web_view();
-        web_view.zoom_reset();
-    }
-
-    public void web_view_translate_coordinates(Gtk.Widget widget, int x, int anchor_y, out int x1, out int 
y1) {
-        if (this.web_view == null)
-            initialize_web_view();
-        web_view.translate_coordinates(widget, x, anchor_y, out x1, out y1);
-    }
-
-    public int web_view_get_allocated_height() {
-        if (this.web_view == null)
-            initialize_web_view();
-        return web_view.get_allocated_height();
-    }
-
     /**
      * Shows the complete message and hides the compact headers.
      */
     public void show_message_body(bool include_transitions=true) {
-        if (this.web_view == null)
-            initialize_web_view();
         set_revealer(this.compact_revealer, false, include_transitions);
         set_revealer(this.header_revealer, true, include_transitions);
         set_revealer(this.body_revealer, true, include_transitions);
@@ -816,10 +695,6 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
             throw new GLib.IOError.CANCELLED("Conversation load cancelled");
         }
 
-        if (this.web_view == null) {
-            initialize_web_view();
-        }
-
         bool contact_load_images = (
             this.primary_contact != null &&
             this.primary_contact.load_remote_resources
@@ -870,8 +745,6 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
             }
         }
 
-        if (this.web_view == null)
-            initialize_web_view();
         uint webkit_found = yield this.web_view.highlight_search_terms(
             search_matches, cancellable
         );
@@ -885,9 +758,7 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
         foreach (ContactFlowBoxChild address in this.searchable_addresses) {
             address.unmark_search_terms();
         }
-
-        if (this.web_view != null)
-            this.web_view.unmark_search_terms();
+        this.web_view.unmark_search_terms();
     }
 
     /**
@@ -1050,8 +921,6 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
     // returns HTML that is placed into the document in the position
     // where the MIME part was found
     private string? inline_image_replacer(Geary.RFC822.Part part) {
-        if (this.web_view == null)
-            initialize_web_view();
         Geary.Mime.ContentType content_type = part.content_type;
         if (content_type.media_type != "image" ||
             !this.web_view.can_show_mime_type(content_type.to_string())) {
@@ -1086,7 +955,7 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
         return "<img alt=\"%s\" class=\"%s\" src=\"%s%s\" />".printf(
             clean_filename,
             REPLACED_IMAGE_CLASS,
-            Components.WebView.CID_URL_PREFIX,
+            ClientWebView.CID_URL_PREFIX,
             Geary.HTML.escape_markup(id)
         );
     }
@@ -1097,9 +966,7 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
         this.load_remote_resources = true;
         this.remote_resources_requested = 0;
         this.remote_resources_loaded = 0;
-        if (this.web_view != null) {
-            this.web_view.load_remote_images();
-        }
+        this.web_view.load_remote_images();
         if (update_email_flag) {
             flag_remote_images();
         }
@@ -1114,13 +981,11 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
 
         if (placeholder != null) {
             this.body_placeholder = placeholder;
-            if (this.web_view != null)
-                this.web_view.hide();
+            this.web_view.hide();
             this.body_container.add(placeholder);
             show_message_body(true);
         } else {
-            if (this.web_view != null)
-                this.web_view.show();
+            this.web_view.show();
         }
     }
 
@@ -1148,12 +1013,10 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
     }
 
     private void on_is_loading_notify() {
-        if (this.web_view != null) {
-            if (this.web_view.is_loading) {
-                start_progress_loading();
-            } else {
-                stop_progress_loading();
-            }
+        if (this.web_view.is_loading) {
+            start_progress_loading();
+        } else {
+            stop_progress_loading();
         }
     }
 
@@ -1388,7 +1251,7 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
             alt_text = (string) alt_maybe;
         }
 
-        if (uri.has_prefix(Components.WebView.CID_URL_PREFIX)) {
+        if (uri.has_prefix(ClientWebView.CID_URL_PREFIX)) {
             // We can get the data directly from the attachment, so
             // don't bother getting it from the web view
             save_image(uri, alt_text, null);
diff --git a/src/client/conversation-viewer/conversation-viewer.vala 
b/src/client/conversation-viewer/conversation-viewer.vala
index 3de7d72a..461c7c94 100644
--- a/src/client/conversation-viewer/conversation-viewer.vala
+++ b/src/client/conversation-viewer/conversation-viewer.vala
@@ -24,14 +24,6 @@ public class ConversationViewer : Gtk.Stack, Geary.BaseInterface {
         get; private set; default = null;
     }
 
-    /**
-     * The most recent web view created in this viewer.
-     *
-     * Keep the last created web view around so others can share the
-     * same WebKitGTK WebProcess.
-     */
-    internal ConversationWebView? previous_web_view { get; set; default = null; }
-
     private Application.Configuration config;
 
     private Gee.Set<Geary.App.Conversation>? selection_while_composing = null;
@@ -254,10 +246,7 @@ public class ConversationViewer : Gtk.Stack, Geary.BaseInterface {
                                         Application.ContactStore contacts,
                                         bool start_mark_timer)
         throws GLib.Error {
-        // Keep the old ScrolledWindow around long enough for its
-        // descendant web views to be kept so their WebProcess can be
-        // re-used.
-        var old_scroller = remove_current_list();
+        remove_current_list();
 
         ConversationListBox new_list = new ConversationListBox(
             conversation,
@@ -303,9 +292,6 @@ public class ConversationViewer : Gtk.Stack, Geary.BaseInterface {
         }
 
         yield new_list.load_conversation(scroll_to, query);
-
-        // Not strictly necessary, but keeps the compiler happy
-        old_scroller.destroy();
     }
 
     // Add a new conversation list to the UI
@@ -325,7 +311,7 @@ public class ConversationViewer : Gtk.Stack, Geary.BaseInterface {
     }
 
     // Remove any existing conversation list, cancelling its loading
-    private Gtk.ScrolledWindow remove_current_list() {
+    private void remove_current_list() {
         if (this.find_cancellable != null) {
             this.find_cancellable.cancel();
             this.find_cancellable = null;
@@ -337,17 +323,15 @@ public class ConversationViewer : Gtk.Stack, Geary.BaseInterface {
             this.current_list = null;
         }
 
-        var old_scroller = this.conversation_scroller;
         // XXX GTK+ Bug 778190 workaround
-        this.conversation_page.remove(old_scroller);
+        this.conversation_scroller.destroy(); // removes the list
         new_conversation_scroller();
-        return old_scroller;
     }
 
     private void new_conversation_scroller() {
         // XXX Work around for GTK+ Bug 778190: Instead of replacing
         // the Viewport that contains the current list, replace the
-        // complete ScrolledWindow. Need to remove this method and
+        // complete ScrolledWindow. Need to put remove this method and
         // put the settings back into conversation-viewer.ui when we
         // can rely on it being fixed again.
         Gtk.ScrolledWindow scroller = new Gtk.ScrolledWindow(null, null);
diff --git a/src/client/conversation-viewer/conversation-web-view.vala 
b/src/client/conversation-viewer/conversation-web-view.vala
index a164c016..d22a836e 100644
--- a/src/client/conversation-viewer/conversation-web-view.vala
+++ b/src/client/conversation-viewer/conversation-web-view.vala
@@ -6,7 +6,7 @@
  * (version 2.1 or later).  See the COPYING file in this distribution.
  */
 
-public class ConversationWebView : Components.WebView {
+public class ConversationWebView : ClientWebView {
 
 
     private const string DECEPTIVE_LINK_CLICKED = "deceptiveLinkClicked";
@@ -41,10 +41,10 @@ public class ConversationWebView : Components.WebView {
 
     public static new void load_resources()
         throws Error {
-        ConversationWebView.app_script = Components.WebView.load_app_script(
+        ConversationWebView.app_script = ClientWebView.load_app_script(
             "conversation-web-view.js"
         );
-        ConversationWebView.app_stylesheet = Components.WebView.load_app_stylesheet(
+        ConversationWebView.app_stylesheet = ClientWebView.load_app_stylesheet(
             "conversation-web-view.css"
         );
     }
@@ -56,33 +56,16 @@ public class ConversationWebView : Components.WebView {
     );
 
 
-    /**
-     * Constructs a new web view for displaying an email message body.
-     *
-     * A new WebKitGTK WebProcess will be constructed for this view.
-     */
     public ConversationWebView(Application.Configuration config) {
         base(config);
-        init();
-
-        // These only need to be added when creating a new WebProcess,
-        // not when sharing one
         this.user_content_manager.add_script(ConversationWebView.app_script);
         this.user_content_manager.add_style_sheet(ConversationWebView.app_stylesheet);
-    }
 
-    /**
-     * Constructs a new web view for displaying an email message body.
-     *
-     * The WebKitGTK WebProcess will be shared with the related view's
-     * process.
-     */
-    internal ConversationWebView.with_related_view(
-        Application.Configuration config,
-        ConversationWebView related
-    ) {
-        base.with_related_view(config, related);
-        init();
+        register_message_handler(
+            DECEPTIVE_LINK_CLICKED, on_deceptive_link_clicked
+        );
+
+        this.notify["preferred-height"].connect(() => queue_resize());
     }
 
     /**
@@ -212,14 +195,6 @@ public class ConversationWebView : Components.WebView {
         minimum_height = natural_height = 0;
     }
 
-    private void init() {
-        register_message_handler(
-            DECEPTIVE_LINK_CLICKED, on_deceptive_link_clicked
-        );
-
-        this.notify["preferred-height"].connect(() => queue_resize());
-    }
-
     private void on_deceptive_link_clicked(WebKit.JavascriptResult result) {
         try {
             JSC.Value object = result.get_js_value();
diff --git a/src/client/meson.build b/src/client/meson.build
index 35c876bf..cf8d8a83 100644
--- a/src/client/meson.build
+++ b/src/client/meson.build
@@ -28,6 +28,7 @@ geary_client_vala_sources = files(
 
   'client-action.vala',
 
+  'components/client-web-view.vala',
   'components/components-attachment-pane.vala',
   'components/components-entry-undo.vala',
   'components/components-inspector.vala',
@@ -40,7 +41,6 @@ geary_client_vala_sources = files(
   'components/components-reflow-box.c',
   'components/components-search-bar.vala',
   'components/components-validator.vala',
-  'components/components-web-view.vala',
   'components/count-badge.vala',
   'components/folder-popover.vala',
   'components/icon-factory.vala',
@@ -142,6 +142,16 @@ geary_client_dependencies = [
 
 geary_client_vala_args = geary_vala_args
 
+# Enable shared shecondary process if available.
+# See issues #558 and #559
+webkit_version = webkit2gtk.version().split('.')
+if webkit_version[0].to_int() <= 2 and webkit_version[1].to_int() <= 24
+  message('Enabling WebKitGTK shared process model')
+  geary_client_vala_args += [
+    '-D', 'HAS_WEBKIT_SHARED_PROC'
+  ]
+endif
+
 # Main client application library
 geary_client_lib = static_library('geary-client',
   geary_client_sources,
diff --git a/src/client/web-process/web-process-extension.vala 
b/src/client/web-process/web-process-extension.vala
index 4bba5154..b2b29bf9 100644
--- a/src/client/web-process/web-process-extension.vala
+++ b/src/client/web-process/web-process-extension.vala
@@ -32,14 +32,22 @@ public class GearyWebExtension : Object {
 
     private const string[] ALLOWED_SCHEMES = { "cid", "geary", "data", "blob" };
 
-    private const string REMOTE_LOAD_VAR = "_gearyAllowRemoteResourceLoads";
-
     private WebKit.WebExtension extension;
 
 
     public GearyWebExtension(WebKit.WebExtension extension) {
         this.extension = extension;
-        extension.page_created.connect(on_page_created);
+        extension.page_created.connect((extension, web_page) => {
+                web_page.console_message_sent.connect(on_console_message);
+                web_page.send_request.connect(on_send_request);
+                // XXX investigate whether the earliest supported
+                // version of WK supports the DOM "selectionchanged"
+                // event, and if so use that rather that doing it in
+                // here in the extension
+                web_page.get_editor().selection_changed.connect(() => {
+                    selection_changed(web_page);
+                });
+            });
     }
 
     // XXX Conditionally enable while we still depend on WK2 <2.12
@@ -81,7 +89,14 @@ public class GearyWebExtension : Object {
         WebKit.Frame frame = page.get_main_frame();
         JSC.Context context = frame.get_js_context();
         try {
-            should_load = Util.JS.to_bool(context.get_value(REMOTE_LOAD_VAR));
+            JSC.Value ret = execute_script(
+                context,
+                "geary.allowRemoteImages",
+                GLib.Log.FILE,
+                GLib.Log.METHOD,
+                GLib.Log.LINE
+            );
+            should_load = Util.JS.to_bool(ret);
         } catch (GLib.Error err) {
             debug(
                 "Error checking PageState::allowRemoteImages: %s",
@@ -139,24 +154,4 @@ public class GearyWebExtension : Object {
         return ret;
     }
 
-    private void on_page_created(WebKit.WebExtension extension,
-                                 WebKit.WebPage page) {
-        WebKit.Frame frame = page.get_main_frame();
-        JSC.Context context = frame.get_js_context();
-        context.set_value(
-            REMOTE_LOAD_VAR,
-            new JSC.Value.boolean(context, false)
-        );
-
-        page.console_message_sent.connect(on_console_message);
-        page.send_request.connect(on_send_request);
-        // XXX investigate whether the earliest supported
-        // version of WK supports the DOM "selectionchanged"
-        // event, and if so use that rather that doing it in
-        // here in the extension
-        page.get_editor().selection_changed.connect(() => {
-                selection_changed(page);
-            });
-    }
-
 }
diff --git a/test/client/components/components-web-view-test-case.vala 
b/test/client/components/client-web-view-test-case.vala
similarity index 75%
rename from test/client/components/components-web-view-test-case.vala
rename to test/client/components/client-web-view-test-case.vala
index 514f9a16..d1212afb 100644
--- a/test/client/components/components-web-view-test-case.vala
+++ b/test/client/components/client-web-view-test-case.vala
@@ -6,42 +6,35 @@
  */
 
 
-public abstract class Components.WebViewTestCase<V> : TestCase {
+public abstract class ClientWebViewTestCase<V> : TestCase {
 
     protected V? test_view = null;
     protected Application.Configuration? config = null;
 
-    protected WebViewTestCase(string name) {
+    protected ClientWebViewTestCase(string name) {
         base(name);
-    }
-
-    public override void set_up() {
         this.config = new Application.Configuration(Application.Client.SCHEMA_ID);
         this.config.enable_debug = true;
-
-        WebView.init_web_context(
+        ClientWebView.init_web_context(
             this.config,
             File.new_for_path(_BUILD_ROOT_DIR).get_child("src"),
             File.new_for_path("/tmp") // XXX use something better here
         );
         try {
-            WebView.load_resources(GLib.File.new_for_path("/tmp"));
+            ClientWebView.load_resources(GLib.File.new_for_path("/tmp"));
         } catch (GLib.Error err) {
             assert_not_reached();
         }
-
-        this.test_view = set_up_test_view();
     }
 
-    protected override void tear_down() {
-        this.config = null;
-        this.test_view = null;
+    public override void set_up() {
+        this.test_view = set_up_test_view();
     }
 
     protected abstract V set_up_test_view();
 
     protected virtual void load_body_fixture(string html = "") {
-        WebView client_view = (WebView) this.test_view;
+        ClientWebView client_view = (ClientWebView) this.test_view;
         client_view.load_html(html);
         while (!client_view.is_content_loaded) {
             Gtk.main_iteration();
@@ -49,7 +42,7 @@ public abstract class Components.WebViewTestCase<V> : TestCase {
     }
 
     protected WebKit.JavascriptResult run_javascript(string command) throws Error {
-        WebView view = (WebView) this.test_view;
+        ClientWebView view = (ClientWebView) this.test_view;
         view.run_javascript.begin(
             command, null, (obj, res) => { async_complete(res); }
         );
diff --git a/test/client/components/components-web-view-test.vala 
b/test/client/components/client-web-view-test.vala
similarity index 79%
rename from test/client/components/components-web-view-test.vala
rename to test/client/components/client-web-view-test.vala
index d3e1037c..d08e5192 100644
--- a/test/client/components/components-web-view-test.vala
+++ b/test/client/components/client-web-view-test.vala
@@ -5,10 +5,10 @@
  * (version 2.1 or later). See the COPYING file in this distribution.
  */
 
-public class Components.WebViewTest : TestCase {
+public class ClientWebViewTest : TestCase {
 
-    public WebViewTest() {
-        base("Components.WebViewTest");
+    public ClientWebViewTest() {
+        base("ClientWebViewTest");
         add_test("init_web_context", init_web_context);
         add_test("load_resources", load_resources);
     }
@@ -18,7 +18,7 @@ public class Components.WebViewTest : TestCase {
             Application.Client.SCHEMA_ID
         );
         config.enable_debug = true;
-        WebView.init_web_context(
+        ClientWebView.init_web_context(
             config,
             File.new_for_path(_BUILD_ROOT_DIR).get_child("src"),
             File.new_for_path("/tmp") // XXX use something better here
@@ -27,7 +27,7 @@ public class Components.WebViewTest : TestCase {
 
     public void load_resources() throws GLib.Error {
         try {
-            WebView.load_resources(GLib.File.new_for_path("/tmp"));
+            ClientWebView.load_resources(GLib.File.new_for_path("/tmp"));
         } catch (GLib.Error err) {
             assert_not_reached();
         }
diff --git a/test/client/composer/composer-web-view-test.vala 
b/test/client/composer/composer-web-view-test.vala
index 97c2af29..bac7e7f0 100644
--- a/test/client/composer/composer-web-view-test.vala
+++ b/test/client/composer/composer-web-view-test.vala
@@ -5,7 +5,7 @@
  * (version 2.1 or later). See the COPYING file in this distribution.
  */
 
-public class Composer.WebViewTest : Components.WebViewTestCase<Composer.WebView> {
+public class Composer.WebViewTest : ClientWebViewTestCase<Composer.WebView> {
 
 
     public WebViewTest() {
diff --git a/test/js/components-page-state-test.vala b/test/js/client-page-state-test.vala
similarity index 73%
rename from test/js/components-page-state-test.vala
rename to test/js/client-page-state-test.vala
index e0f728ce..d763dcc3 100644
--- a/test/js/components-page-state-test.vala
+++ b/test/js/client-page-state-test.vala
@@ -5,24 +5,24 @@
  * (version 2.1 or later). See the COPYING file in this distribution.
  */
 
-class Components.PageStateTest : WebViewTestCase<WebView> {
+class ClientPageStateTest : ClientWebViewTestCase<ClientWebView> {
 
 
-    private class TestWebView : Components.WebView {
+    private class TestClientWebView : ClientWebView {
 
-        public TestWebView(Application.Configuration config) {
+        public TestClientWebView(Application.Configuration config) {
             base(config);
         }
 
     }
 
 
-    public PageStateTest() {
-        base("Components.PageStateTest");
+    public ClientPageStateTest() {
+        base("ClientPageStateTest");
         add_test("content_loaded", content_loaded);
 
         try {
-            WebView.load_resources(GLib.File.new_for_path("/tmp"));
+            ClientWebView.load_resources(GLib.File.new_for_path("/tmp"));
         } catch (GLib.Error err) {
             assert_not_reached();
         }
@@ -45,7 +45,7 @@ class Components.PageStateTest : WebViewTestCase<WebView> {
         assert(content_loaded_triggered);
     }
 
-    protected override WebView set_up_test_view() {
+    protected override ClientWebView set_up_test_view() {
         WebKit.UserScript test_script;
         test_script = new WebKit.UserScript(
             "var geary = new PageState()",
@@ -55,7 +55,7 @@ class Components.PageStateTest : WebViewTestCase<WebView> {
             null
         );
 
-        WebView view = new TestWebView(this.config);
+        ClientWebView view = new TestClientWebView(this.config);
         view.get_user_content_manager().add_script(test_script);
         return view;
     }
diff --git a/test/js/composer-page-state-test.vala b/test/js/composer-page-state-test.vala
index 6228cc68..8e1751b7 100644
--- a/test/js/composer-page-state-test.vala
+++ b/test/js/composer-page-state-test.vala
@@ -5,7 +5,7 @@
  * (version 2.1 or later). See the COPYING file in this distribution.
  */
 
-class Composer.PageStateTest : Components.WebViewTestCase<Composer.WebView> {
+class Composer.PageStateTest : ClientWebViewTestCase<Composer.WebView> {
 
     public const string COMPLETE_BODY_TEMPLATE =
         """<div id="geary-body" dir="auto">%s<div><br></div><div><br></div></div><div id="geary-signature" 
dir="auto"></div>""";
diff --git a/test/js/conversation-page-state-test.vala b/test/js/conversation-page-state-test.vala
index d0b76bc4..ba68cfde 100644
--- a/test/js/conversation-page-state-test.vala
+++ b/test/js/conversation-page-state-test.vala
@@ -5,7 +5,7 @@
  * (version 2.1 or later). See the COPYING file in this distribution.
  */
 
-class ConversationPageStateTest : Components.WebViewTestCase<ConversationWebView> {
+class ConversationPageStateTest : ClientWebViewTestCase<ConversationWebView> {
 
     public ConversationPageStateTest() {
         base("ConversationPageStateTest");
diff --git a/test/meson.build b/test/meson.build
index 89f0cbb8..38a3aae2 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -82,16 +82,16 @@ geary_test_client_sources = [
   'client/accounts/accounts-manager-test.vala',
   'client/application/application-client-test.vala',
   'client/application/application-configuration-test.vala',
+  'client/components/client-web-view-test.vala',
+  'client/components/client-web-view-test-case.vala',
   'client/components/components-validator-test.vala',
-  'client/components/components-web-view-test-case.vala',
-  'client/components/components-web-view-test.vala',
   'client/composer/composer-web-view-test.vala',
   'client/util/util-avatar-test.vala',
   'client/util/util-cache-test.vala',
   'client/util/util-email-test.vala',
   'client/util/util-js-test.vala',
 
-  'js/components-page-state-test.vala',
+  'js/client-page-state-test.vala',
   'js/composer-page-state-test.vala',
   'js/conversation-page-state-test.vala',
 
diff --git a/test/test-client.vala b/test/test-client.vala
index 115eb9e3..1016d2a5 100644
--- a/test/test-client.vala
+++ b/test/test-client.vala
@@ -51,9 +51,9 @@ int main(string[] args) {
     client.add_suite(new Accounts.ManagerTest().get_suite());
     client.add_suite(new Application.ClientTest().get_suite());
     client.add_suite(new Application.ConfigurationTest().get_suite());
-    client.add_suite(new Components.ValidatorTest().get_suite());
-    client.add_suite(new Components.WebViewTest().get_suite());
+    client.add_suite(new ClientWebViewTest().get_suite());
     client.add_suite(new Composer.WebViewTest().get_suite());
+    client.add_suite(new Components.ValidatorTest().get_suite());
     client.add_suite(new Util.Avatar.Test().get_suite());
     client.add_suite(new Util.Cache.Test().get_suite());
     client.add_suite(new Util.Email.Test().get_suite());
@@ -61,7 +61,7 @@ int main(string[] args) {
 
     TestSuite js = new TestSuite("js");
 
-    js.add_suite(new Components.PageStateTest().get_suite());
+    js.add_suite(new ClientPageStateTest().get_suite());
     js.add_suite(new Composer.PageStateTest().get_suite());
     js.add_suite(new ConversationPageStateTest().get_suite());
 
diff --git a/ui/client-web-view-allow-remote-images.js b/ui/client-web-view-allow-remote-images.js
new file mode 100644
index 00000000..1fb05606
--- /dev/null
+++ b/ui/client-web-view-allow-remote-images.js
@@ -0,0 +1,11 @@
+/*
+ * Copyright 2016 Michael Gratton <mike vee net>
+ *
+ * This software is licensed under the GNU Lesser General Public License
+ * (version 2.1 or later). See the COPYING file in this distribution.
+ */
+
+/**
+ * Enables remote image loading in a client web view.
+ */
+geary.allowRemoteImages = true;
diff --git a/ui/components-web-view.js b/ui/client-web-view.js
similarity index 98%
rename from ui/components-web-view.js
rename to ui/client-web-view.js
index 80e86d7c..75bdecf1 100644
--- a/ui/components-web-view.js
+++ b/ui/client-web-view.js
@@ -6,7 +6,7 @@
  */
 
 /**
- * Application logic for Components.WebView and subclasses.
+ * Application logic for ClientWebView and subclasses.
  */
 
 let PageState = function() {
@@ -14,6 +14,7 @@ let PageState = function() {
 };
 PageState.prototype = {
     init: function() {
+        this.allowRemoteImages = false;
         this.isLoaded = false;
         this.undoEnabled = false;
         this.redoEnabled = false;
@@ -107,7 +108,7 @@ PageState.prototype = {
         window.webkit.messageHandlers.contentLoaded.postMessage(null);
     },
     loadRemoteImages: function() {
-        window._gearyAllowRemoteResourceLoads = true;
+        this.allowRemoteImages = true;
         let images = document.getElementsByTagName("IMG");
         for (let i = 0; i < images.length; i++) {
             let img = images.item(i);
diff --git a/ui/conversation-message.ui b/ui/conversation-message.ui
index 3a681f20..ee0a4af0 100644
--- a/ui/conversation-message.ui
+++ b/ui/conversation-message.ui
@@ -473,7 +473,6 @@
       <object class="GtkRevealer" id="body_revealer">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
-        <property name="transition_type">slide-up</property>
         <child>
           <object class="GtkGrid">
             <property name="visible">True</property>
diff --git a/ui/org.gnome.Geary.gresource.xml b/ui/org.gnome.Geary.gresource.xml
index 4f9cc591..f74a48e8 100644
--- a/ui/org.gnome.Geary.gresource.xml
+++ b/ui/org.gnome.Geary.gresource.xml
@@ -9,7 +9,8 @@
     <file compressed="true" preprocess="xml-stripblanks">accounts_editor_servers_pane.ui</file>
     <file compressed="true" preprocess="xml-stripblanks">application-main-window.ui</file>
     <file compressed="true" preprocess="xml-stripblanks">certificate_warning_dialog.glade</file>
-    <file compressed="true">components-web-view.js</file>
+    <file compressed="true">client-web-view.js</file>
+    <file compressed="true">client-web-view-allow-remote-images.js</file>
     <file compressed="true" preprocess="xml-stripblanks">components-attachment-pane.ui</file>
     <file compressed="true" preprocess="xml-stripblanks">components-attachment-pane-menus.ui</file>
     <file compressed="true" preprocess="xml-stripblanks">components-attachment-view.ui</file>


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