From cbe6e0ba9bc7d83a8a6c3eb2372f1c8fefd735b4 Mon Sep 17 00:00:00 2001 From: Michael James Gratton Date: Wed, 12 Feb 2020 16:48:24 +1100 Subject: [PATCH] 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 +- .../accounts/accounts-editor-edit-pane.vala | 4 +- .../accounts/accounts-signature-web-view.vala | 4 +- .../application/application-controller.vala | 5 +- src/client/application/main.vala | 6 + ...nts-web-view.vala => client-web-view.vala} | 156 +++++++------ src/client/composer/composer-web-view.vala | 6 +- src/client/composer/composer-widget.vala | 8 +- .../conversation-email.vala | 26 ++- .../conversation-list-box.vala | 14 +- .../conversation-message.vala | 207 +++--------------- .../conversation-viewer.vala | 24 +- .../conversation-web-view.vala | 41 +--- src/client/meson.build | 12 +- .../web-process/web-process-extension.vala | 43 ++-- ...se.vala => client-web-view-test-case.vala} | 23 +- ...ew-test.vala => client-web-view-test.vala} | 10 +- .../composer/composer-web-view-test.vala | 2 +- ...-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 + ...ponents-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(-) rename src/client/components/{components-web-view.vala => client-web-view.vala} (92%) rename test/client/components/{components-web-view-test-case.vala => client-web-view-test-case.vala} (75%) rename test/client/components/{components-web-view-test.vala => client-web-view-test.vala} (79%) rename test/js/{components-page-state-test.vala => client-page-state-test.vala} (73%) create mode 100644 ui/client-web-view-allow-remote-images.js rename ui/{components-web-view.js => client-web-view.js} (98%) 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 @@
  • Extend undo for email actions such as archiving, marking
  • Undo sending, saving and discarding composed email
  • Undo editing in text fields, including in the composer
  • -
  • Conversation loading performance improvements
  • App-wide notification preferences now handled by desktop
  • Improved missing attachment detection in composer
  • Initial plugin system
  • 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 + * Copyright 2016 Michael Gratton * * 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 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 "\"%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? 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 : TestCase { +public abstract class ClientWebViewTestCase : 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 : 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 { +public class Composer.WebViewTest : ClientWebViewTestCase { 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 { +class ClientPageStateTest : ClientWebViewTestCase { - 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 { 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 { 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 { +class Composer.PageStateTest : ClientWebViewTestCase { public const string COMPLETE_BODY_TEMPLATE = """
    %s


    """; 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 { +class ConversationPageStateTest : ClientWebViewTestCase { 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 + * + * 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 @@ True False - slide-up True 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 @@ accounts_editor_servers_pane.ui application-main-window.ui certificate_warning_dialog.glade - components-web-view.js + client-web-view.js + client-web-view-allow-remote-images.js components-attachment-pane.ui components-attachment-pane-menus.ui components-attachment-view.ui