From 766d55e75dea4580a2623b67a6b3236c7f2b2be1 Mon Sep 17 00:00:00 2001 From: Michael James Gratton Date: Sun, 27 Nov 2016 11:24:09 +1100 Subject: [PATCH] Reimplement selection_changed signal for WK2. Add a "has_selection" param to avoid a second round-trip to the web process to determine that. * src/client/components/client-web-view.vala (ClientWebView): Add a selection_changed signal, register a JS message handler for the JS equivalent hook up firing the signal. * src/client/web-process/web-process-extension.vala (GearyWebExtension): Send a JS selectionChanged message when the page's selection changes. * src/client/composer/composer-widget.vala, src/client/conversation-viewer/conversation-email.vala, src/client/conversation-viewer/conversation-message.vala: Uncomment code that relied on the WK1 selection_changed signal, use signal param rather than DOM calls. * ui/client-web-view.js: Implement sending the selectionChanged message. --- src/client/components/client-web-view.vala | 24 ++++++++++++++++++- src/client/composer/composer-widget.vala | 9 +++---- .../conversation-email.vala | 16 ++++++------- .../conversation-message.vala | 13 ++++------ .../web-process/web-process-extension.vala | 9 +++++++ ui/client-web-view.js | 4 ++++ 6 files changed, 53 insertions(+), 22 deletions(-) diff --git a/src/client/components/client-web-view.vala b/src/client/components/client-web-view.vala index 38303191..2a49b8e8 100644 --- a/src/client/components/client-web-view.vala +++ b/src/client/components/client-web-view.vala @@ -16,6 +16,8 @@ public class ClientWebView : WebKit.WebView { private const string PREFERRED_HEIGHT_MESSAGE = "preferredHeightChanged"; private const string REMOTE_IMAGE_LOAD_BLOCKED_MESSAGE = "remoteImageLoadBlocked"; + private const string SELECTION_CHANGED_MESSAGE = "selectionChanged"; + private const double ZOOM_DEFAULT = 1.0; private const double ZOOM_FACTOR = 0.1; @@ -81,6 +83,14 @@ public class ClientWebView : WebKit.WebView { ); } + protected static bool get_bool_result(WebKit.JavascriptResult result) + throws JSError { + JS.GlobalContext context = result.get_global_context(); + JS.Value value = result.get_value(); + return context.to_boolean(value); + // XXX unref result? + } + protected static int get_int_result(WebKit.JavascriptResult result) throws JSError { JS.GlobalContext context = result.get_global_context(); @@ -90,7 +100,7 @@ public class ClientWebView : WebKit.WebView { } JS.Value? err = null; return (int) context.to_number(value, out err); - // XXX unref result + // XXX unref result? } private static inline uint to_wk2_font_size(Pango.FontDescription font) { @@ -144,6 +154,9 @@ public class ClientWebView : WebKit.WebView { private int preferred_height = 0; + /** Emitted when the web view's selection has changed. */ + public signal void selection_changed(bool has_selection); + /** Emitted when a user clicks a link in this web view. */ public signal void link_activated(string uri); @@ -198,9 +211,18 @@ public class ClientWebView : WebKit.WebView { (result) => { remote_image_load_blocked(); }); + content_manager.script_message_received[SELECTION_CHANGED_MESSAGE].connect( + (result) => { + try { + selection_changed(get_bool_result(result)); + } catch (JSError err) { + debug("Could not get selection content: %s", err.message); + } + }); register_message_handler(PREFERRED_HEIGHT_MESSAGE); register_message_handler(REMOTE_IMAGE_LOAD_BLOCKED_MESSAGE); + register_message_handler(SELECTION_CHANGED_MESSAGE); GearyApplication.instance.config.bind(Configuration.CONVERSATION_VIEWER_ZOOM_KEY, this, "zoom_level"); this.scroll_event.connect(on_scroll_event); diff --git a/src/client/composer/composer-widget.vala b/src/client/composer/composer-widget.vala index fc794afd..66823729 100644 --- a/src/client/composer/composer-widget.vala +++ b/src/client/composer/composer-widget.vala @@ -518,7 +518,7 @@ public class ComposerWidget : Gtk.EventBox { // this.editor.paste_clipboard.connect(update_actions); // this.editor.undo.connect(update_actions); // this.editor.redo.connect(update_actions); - // this.editor.selection_changed.connect(update_actions); + this.editor.selection_changed.connect(update_actions); this.editor.key_press_event.connect(on_editor_key_press); //this.editor.user_changed_contents.connect(reset_draft_timer); @@ -861,9 +861,10 @@ public class ComposerWidget : Gtk.EventBox { this.actions.change_action_state(ACTION_COMPOSE_AS_HTML, GearyApplication.instance.config.compose_as_html); - // XXX - // if (can_delete_quote) - // this.editor.selection_changed.connect(() => { this.can_delete_quote = false; }); + if (can_delete_quote) + this.editor.selection_changed.connect( + () => { this.can_delete_quote = false; } + ); } private void show_attachment_overlay(bool visible) { diff --git a/src/client/conversation-viewer/conversation-email.vala b/src/client/conversation-viewer/conversation-email.vala index 99921ccb..30bc0bc9 100644 --- a/src/client/conversation-viewer/conversation-email.vala +++ b/src/client/conversation-viewer/conversation-email.vala @@ -630,9 +630,9 @@ public class ConversationEmail : Gtk.Box { this.message_bodies_loaded = true; } }); - // view.web_view.selection_changed.connect(() => { - // on_message_selection_changed(view); - // }); + view.web_view.selection_changed.connect(() => { + on_message_selection_changed(view); + }); } private void update_email_state() { @@ -766,11 +766,11 @@ public class ConversationEmail : Gtk.Box { contact_store.mark_contacts_async.begin(contact_list, flags, null); } - // private void on_message_selection_changed(ConversationMessage view) { - // bool has_selection = view.web_view.has_selection(); - // this.body_selection_message = has_selection ? view : null; - // body_selection_changed(has_selection); - // } + private void on_message_selection_changed(ConversationMessage view) { + bool has_selection = view.web_view.has_selection(); + this.body_selection_message = has_selection ? view : null; + body_selection_changed(has_selection); + } [GtkCallback] private void on_attachments_child_activated(Gtk.FlowBox view, diff --git a/src/client/conversation-viewer/conversation-message.vala b/src/client/conversation-viewer/conversation-message.vala index e945efd3..df824411 100644 --- a/src/client/conversation-viewer/conversation-message.vala +++ b/src/client/conversation-viewer/conversation-message.vala @@ -380,7 +380,7 @@ public class ConversationMessage : Gtk.Grid { this.web_view.remote_image_load_blocked.connect(() => { this.remote_images_infobar.show(); }); - //this.web_view.selection_changed.connect(on_selection_changed); + this.web_view.selection_changed.connect(on_selection_changed); this.web_view.show(); this.body.set_has_tooltip(true); // Used to show link URLs @@ -940,14 +940,9 @@ public class ConversationMessage : Gtk.Grid { return Gdk.EVENT_PROPAGATE; } - // private void on_selection_changed() { - // bool has_selection = false; - // if (web_view.has_selection()) { - // WebKit.DOM.Document document = web_view.get_dom_document(); - // has_selection = !document.default_view.get_selection().is_collapsed; - // } - // set_action_enabled(ACTION_COPY_SELECTION, has_selection); - // } + private void on_selection_changed(bool has_selection) { + set_action_enabled(ACTION_COPY_SELECTION, has_selection); + } [GtkCallback] private void on_remote_images_response(Gtk.InfoBar info_bar, int response_id) { diff --git a/src/client/web-process/web-process-extension.vala b/src/client/web-process/web-process-extension.vala index c3daf529..5b2a61e4 100644 --- a/src/client/web-process/web-process-extension.vala +++ b/src/client/web-process/web-process-extension.vala @@ -41,6 +41,9 @@ public class GearyWebExtension : Object { // XXX Re-enable when we can depend on WK2 2.12 // web_page.console_message_sent.connect(on_console_message); web_page.send_request.connect(on_send_request); + web_page.get_editor().selection_changed.connect(() => { + selection_changed(web_page); + }); }); } @@ -94,6 +97,12 @@ public class GearyWebExtension : Object { execute_script(context, "geary.remoteImageLoadBlocked();"); } + private void selection_changed(WebKit.WebPage page) { + WebKit.Frame frame = page.get_main_frame(); + JS.Context context = frame.get_javascript_global_context(); + execute_script(context, "geary.selectionChanged();"); + } + private JS.Value execute_script(JS.Context context, string script) { JS.String js_script = new JS.String.create_with_utf8_cstring(script); // XXX check err here, log it diff --git a/ui/client-web-view.js b/ui/client-web-view.js index 89c47f0d..f4105f92 100644 --- a/ui/client-web-view.js +++ b/ui/client-web-view.js @@ -45,6 +45,10 @@ PageState.prototype = { height ); } + }, + selectionChanged: function() { + var has_selection = !window.getSelection().isCollapsed; + window.webkit.messageHandlers.selectionChanged.postMessage(has_selection); } };