[evolution/gnome-3-22] Bug 775656 - Delete key mapping stops working



commit 956b2f3dbdb94f81c2bcff45f3b3a5de107ef1a7
Author: Milan Crha <mcrha redhat com>
Date:   Mon Dec 5 20:14:20 2016 +0100

    Bug 775656 - Delete key mapping stops working

 e-util/e-web-view.c                      |  223 ++++++++++++++++---
 e-util/e-web-view.h                      |    6 +
 mail/e-mail-reader.c                     |   17 +--
 modules/mail/e-mail-shell-view-private.c |   30 +---
 web-extensions/e-dom-utils.c             |  120 ----------
 web-extensions/e-dom-utils.h             |    3 -
 web-extensions/e-web-extension.c         |  363 +++++++++++++++++++++++-------
 7 files changed, 493 insertions(+), 269 deletions(-)
---
diff --git a/e-util/e-web-view.c b/e-util/e-web-view.c
index 9901dd0..cd3633e 100644
--- a/e-util/e-web-view.c
+++ b/e-util/e-web-view.c
@@ -92,6 +92,12 @@ struct _EWebViewPrivate {
 
        GHashTable *element_clicked_cbs; /* gchar *element_class ~> GPtrArray {ElementClickedData} */
        guint web_extension_element_clicked_signal_id;
+
+       guint32 clipboard_flags;
+       guint web_extension_clipboard_flags_changed_signal_id;
+
+       gboolean need_input;
+       guint web_extension_need_input_changed_signal_id;
 };
 
 struct _AsyncContext {
@@ -105,10 +111,12 @@ struct _AsyncContext {
 enum {
        PROP_0,
        PROP_CARET_MODE,
+       PROP_CLIPBOARD_FLAGS,
        PROP_COPY_TARGET_LIST,
        PROP_CURSOR_IMAGE_SRC,
        PROP_DISABLE_PRINTING,
        PROP_DISABLE_SAVE_TO_DISK,
+       PROP_NEED_INPUT,
        PROP_OPEN_PROXY,
        PROP_PASTE_TARGET_LIST,
        PROP_PRINT_PROXY,
@@ -775,6 +783,12 @@ web_view_set_property (GObject *object,
                                g_value_get_boolean (value));
                        return;
 
+               case PROP_CLIPBOARD_FLAGS:
+                       e_web_view_set_clipboard_flags (
+                               E_WEB_VIEW (object),
+                               g_value_get_uint (value));
+                       return;
+
                case PROP_COPY_TARGET_LIST:
                        /* This is a fake property. */
                        g_warning ("%s: EWebView::copy-target-list not used", G_STRFUNC);
@@ -798,6 +812,12 @@ web_view_set_property (GObject *object,
                                g_value_get_boolean (value));
                        return;
 
+               case PROP_NEED_INPUT:
+                       e_web_view_set_need_input (
+                               E_WEB_VIEW (object),
+                               g_value_get_boolean (value));
+                       return;
+
                case PROP_OPEN_PROXY:
                        e_web_view_set_open_proxy (
                                E_WEB_VIEW (object),
@@ -843,6 +863,12 @@ web_view_get_property (GObject *object,
                                E_WEB_VIEW (object)));
                        return;
 
+               case PROP_CLIPBOARD_FLAGS:
+                       g_value_set_uint (
+                               value, e_web_view_get_clipboard_flags (
+                               E_WEB_VIEW (object)));
+                       return;
+
                case PROP_COPY_TARGET_LIST:
                        /* This is a fake property. */
                        g_value_set_boxed (value, NULL);
@@ -866,6 +892,12 @@ web_view_get_property (GObject *object,
                                E_WEB_VIEW (object)));
                        return;
 
+               case PROP_NEED_INPUT:
+                       g_value_set_boolean (
+                               value, e_web_view_get_need_input (
+                               E_WEB_VIEW (object)));
+                       return;
+
                case PROP_OPEN_PROXY:
                        g_value_set_object (
                                value, e_web_view_get_open_proxy (
@@ -947,6 +979,20 @@ web_view_dispose (GObject *object)
                priv->failed_to_find_text_handler_id = 0;
        }
 
+       if (priv->web_extension && priv->web_extension_clipboard_flags_changed_signal_id) {
+               g_dbus_connection_signal_unsubscribe (
+                       g_dbus_proxy_get_connection (priv->web_extension),
+                       priv->web_extension_clipboard_flags_changed_signal_id);
+               priv->web_extension_clipboard_flags_changed_signal_id = 0;
+       }
+
+       if (priv->web_extension && priv->web_extension_need_input_changed_signal_id) {
+               g_dbus_connection_signal_unsubscribe (
+                       g_dbus_proxy_get_connection (priv->web_extension),
+                       priv->web_extension_need_input_changed_signal_id);
+               priv->web_extension_need_input_changed_signal_id = 0;
+       }
+
        if (priv->web_extension && priv->web_extension_element_clicked_signal_id) {
                g_dbus_connection_signal_unsubscribe (
                        g_dbus_proxy_get_connection (priv->web_extension),
@@ -1440,6 +1486,60 @@ web_view_register_element_clicked_hfunc (gpointer key,
 }
 
 static void
+web_view_need_input_changed_signal_cb (GDBusConnection *connection,
+                                      const gchar *sender_name,
+                                      const gchar *object_path,
+                                      const gchar *interface_name,
+                                      const gchar *signal_name,
+                                      GVariant *parameters,
+                                      gpointer user_data)
+{
+       EWebView *web_view = user_data;
+       guint64 page_id = 0;
+       gboolean need_input = FALSE;
+
+       if (g_strcmp0 (signal_name, "NeedInputChanged") != 0)
+               return;
+
+       g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+       if (!parameters)
+               return;
+
+       g_variant_get (parameters, "(tb)", &page_id, &need_input);
+
+       if (page_id == webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view)))
+               e_web_view_set_need_input (web_view, need_input);
+}
+
+static void
+web_view_clipboard_flags_changed_signal_cb (GDBusConnection *connection,
+                                           const gchar *sender_name,
+                                           const gchar *object_path,
+                                           const gchar *interface_name,
+                                           const gchar *signal_name,
+                                           GVariant *parameters,
+                                           gpointer user_data)
+{
+       EWebView *web_view = user_data;
+       guint64 page_id = 0;
+       guint32 clipboard_flags = 0;
+
+       if (g_strcmp0 (signal_name, "ClipboardFlagsChanged") != 0)
+               return;
+
+       g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+       if (!parameters)
+               return;
+
+       g_variant_get (parameters, "(tu)", &page_id, &clipboard_flags);
+
+       if (page_id == webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view)))
+               e_web_view_set_clipboard_flags (web_view, clipboard_flags);
+}
+
+static void
 web_view_element_clicked_signal_cb (GDBusConnection *connection,
                                    const gchar *sender_name,
                                    const gchar *object_path,
@@ -1508,6 +1608,32 @@ web_extension_proxy_created_cb (GDBusProxy *proxy,
                g_warning ("Error creating web extension proxy: %s\n", error->message);
                g_error_free (error);
        } else {
+               web_view->priv->web_extension_clipboard_flags_changed_signal_id =
+                       g_dbus_connection_signal_subscribe (
+                               g_dbus_proxy_get_connection (web_view->priv->web_extension),
+                               g_dbus_proxy_get_name (web_view->priv->web_extension),
+                               E_WEB_EXTENSION_INTERFACE,
+                               "ClipboardFlagsChanged",
+                               E_WEB_EXTENSION_OBJECT_PATH,
+                               NULL,
+                               G_DBUS_SIGNAL_FLAGS_NONE,
+                               web_view_clipboard_flags_changed_signal_cb,
+                               web_view,
+                               NULL);
+
+               web_view->priv->web_extension_need_input_changed_signal_id =
+                       g_dbus_connection_signal_subscribe (
+                               g_dbus_proxy_get_connection (web_view->priv->web_extension),
+                               g_dbus_proxy_get_name (web_view->priv->web_extension),
+                               E_WEB_EXTENSION_INTERFACE,
+                               "NeedInputChanged",
+                               E_WEB_EXTENSION_OBJECT_PATH,
+                               NULL,
+                               G_DBUS_SIGNAL_FLAGS_NONE,
+                               web_view_need_input_changed_signal_cb,
+                               web_view,
+                               NULL);
+
                web_view->priv->web_extension_element_clicked_signal_id =
                        g_dbus_connection_signal_subscribe (
                                g_dbus_proxy_get_connection (web_view->priv->web_extension),
@@ -1602,7 +1728,7 @@ static void
 web_view_update_actions (EWebView *web_view)
 {
        GtkActionGroup *action_group;
-       gboolean can_copy = FALSE;
+       gboolean can_copy;
        gboolean scheme_is_http = FALSE;
        gboolean scheme_is_mailto = FALSE;
        gboolean uri_is_valid = FALSE;
@@ -1610,21 +1736,11 @@ web_view_update_actions (EWebView *web_view)
        const gchar *cursor_image_src;
        const gchar *group_name;
        const gchar *uri;
-       GDBusProxy *web_extension;
-
-       uri = e_web_view_get_selected_uri (web_view);
-       web_extension = e_web_view_get_web_extension_proxy (web_view);
-       if (web_extension) {
-               GVariant *result;
 
-               result = g_dbus_proxy_get_cached_property (web_view->priv->web_extension, "ClipboardFlags");
-               if (result) {
-                       EClipboardFlags clipboard_flags = g_variant_get_uint32 (result);
-                       g_variant_unref (result);
+       g_return_if_fail (E_IS_WEB_VIEW (web_view));
 
-                       can_copy = (clipboard_flags & E_CLIPBOARD_CAN_COPY);
-               }
-       }
+       uri = e_web_view_get_selected_uri (web_view);
+       can_copy = (e_web_view_get_clipboard_flags (web_view) & E_CLIPBOARD_CAN_COPY) != 0;
        cursor_image_src = e_web_view_get_cursor_image_src (web_view);
 
        /* Parse the URI early so we know if the actions will work. */
@@ -1823,24 +1939,13 @@ web_view_selectable_update_actions (ESelectable *selectable,
                                     gint n_clipboard_targets)
 {
        EWebView *web_view;
-       GDBusProxy *web_extension;
        GtkAction *action;
        gboolean can_copy = FALSE;
 
        web_view = E_WEB_VIEW (selectable);
 
-       web_extension = e_web_view_get_web_extension_proxy (web_view);
-       if (web_extension) {
-               GVariant *result;
+       can_copy = (e_web_view_get_clipboard_flags (web_view) & E_CLIPBOARD_CAN_COPY) != 0;
 
-               result = g_dbus_proxy_get_cached_property (web_view->priv->web_extension, "ClipboardFlags");
-               if (result) {
-                       EClipboardFlags clipboard_actions = g_variant_get_uint32 (result);
-                       g_variant_unref (result);
-
-                       can_copy = (clipboard_actions & E_CLIPBOARD_CAN_COPY);
-               }
-       }
        action = e_focus_tracker_get_copy_clipboard_action (focus_tracker);
        gtk_action_set_sensitive (action, can_copy);
        gtk_action_set_tooltip (action, _("Copy the selection"));
@@ -2007,6 +2112,17 @@ e_web_view_class_init (EWebViewClass *class)
                        FALSE,
                        G_PARAM_READWRITE));
 
+       g_object_class_install_property (
+               object_class,
+               PROP_CLIPBOARD_FLAGS,
+               g_param_spec_uint (
+                       "clipboard-flags",
+                       "Clipboard Flags",
+                       NULL,
+                       0, G_MAXUINT, 0,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT));
+
        /* Inherited from ESelectableInterface; just a fake property here */
        g_object_class_override_property (
                object_class,
@@ -2053,6 +2169,17 @@ e_web_view_class_init (EWebViewClass *class)
 
        g_object_class_install_property (
                object_class,
+               PROP_NEED_INPUT,
+               g_param_spec_boolean (
+                       "need-input",
+                       "Need Input",
+                       NULL,
+                       FALSE,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT));
+
+       g_object_class_install_property (
+               object_class,
                PROP_OPEN_PROXY,
                g_param_spec_object (
                        "open-proxy",
@@ -2684,6 +2811,50 @@ e_web_view_set_editable (EWebView *web_view,
        webkit_web_view_set_editable (WEBKIT_WEB_VIEW (web_view), editable);
 }
 
+guint32
+e_web_view_get_clipboard_flags (EWebView *web_view)
+{
+       g_return_val_if_fail (E_IS_WEB_VIEW (web_view), 0);
+
+       return web_view->priv->clipboard_flags;
+}
+
+void
+e_web_view_set_clipboard_flags (EWebView *web_view,
+                               guint32 clipboard_flags)
+{
+       g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+       if (web_view->priv->clipboard_flags == clipboard_flags)
+               return;
+
+       web_view->priv->clipboard_flags = clipboard_flags;
+
+       g_object_notify (G_OBJECT (web_view), "clipboard-flags");
+}
+
+gboolean
+e_web_view_get_need_input (EWebView *web_view)
+{
+       g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
+
+       return web_view->priv->need_input;
+}
+
+void
+e_web_view_set_need_input (EWebView *web_view,
+                          gboolean need_input)
+{
+       g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+       if ((!web_view->priv->need_input) == (!need_input))
+               return;
+
+       web_view->priv->need_input = need_input;
+
+       g_object_notify (G_OBJECT (web_view), "need-input");
+}
+
 const gchar *
 e_web_view_get_selected_uri (EWebView *web_view)
 {
diff --git a/e-util/e-web-view.h b/e-util/e-web-view.h
index 246c289..d06d737 100644
--- a/e-util/e-web-view.h
+++ b/e-util/e-web-view.h
@@ -169,6 +169,12 @@ void               e_web_view_set_disable_save_to_disk
 gboolean       e_web_view_get_editable         (EWebView *web_view);
 void           e_web_view_set_editable         (EWebView *web_view,
                                                 gboolean editable);
+guint32                e_web_view_get_clipboard_flags  (EWebView *web_view);
+void           e_web_view_set_clipboard_flags  (EWebView *web_view,
+                                                guint32 clipboard_flags);
+gboolean       e_web_view_get_need_input       (EWebView *web_view);
+void           e_web_view_set_need_input       (EWebView *web_view,
+                                                gboolean need_input);
 gboolean       e_web_view_get_inline_spelling  (EWebView *web_view);
 void           e_web_view_set_inline_spelling  (EWebView *web_view,
                                                 gboolean inline_spelling);
diff --git a/mail/e-mail-reader.c b/mail/e-mail-reader.c
index 8fe32f4..b001ba4 100644
--- a/mail/e-mail-reader.c
+++ b/mail/e-mail-reader.c
@@ -2680,22 +2680,11 @@ mail_reader_key_press_event_cb (EMailReader *reader,
 
        if (!gtk_widget_has_focus (GTK_WIDGET (reader))) {
                EMailDisplay *display;
-               GDBusProxy *web_extension;
 
                display = e_mail_reader_get_mail_display (reader);
-               web_extension = e_web_view_get_web_extension_proxy (E_WEB_VIEW (display));
-               if (web_extension) {
-                       GVariant *result;
-
-                       result = g_dbus_proxy_get_cached_property (web_extension, "NeedInput");
-                       if (result) {
-                               gboolean need_input = g_variant_get_boolean (result);
-                               g_variant_unref (result);
-
-                               if (need_input)
-                                       return FALSE;
-                       }
-               }
+               if (e_web_view_get_need_input (E_WEB_VIEW (display)) &&
+                   gtk_widget_has_focus (GTK_WIDGET (display)))
+                       return FALSE;
        }
 
        if ((event->state & GDK_CONTROL_MASK) != 0)
diff --git a/modules/mail/e-mail-shell-view-private.c b/modules/mail/e-mail-shell-view-private.c
index 662989f..32a7968 100644
--- a/modules/mail/e-mail-shell-view-private.c
+++ b/modules/mail/e-mail-shell-view-private.c
@@ -250,33 +250,6 @@ mail_shell_view_folder_tree_popup_event_cb (EShellView *shell_view,
 }
 
 static gboolean
-mail_shell_view_mail_display_needs_key (EMailShellView *mail_shell_view,
-                                        EMailDisplay *mail_display)
-{
-       if (gtk_widget_has_focus (GTK_WIDGET (mail_display))) {
-               GDBusProxy *web_extension;
-
-               /* Intentionally use Evolution Web Extension */
-               web_extension = e_web_view_get_web_extension_proxy (E_WEB_VIEW (mail_display));
-               if (web_extension) {
-                       GVariant *result;
-
-                       result = g_dbus_proxy_get_cached_property (web_extension, "NeedInput");
-                       if (result) {
-                               gboolean need_input;
-
-                               need_input = g_variant_get_boolean (result);
-                               g_variant_unref (result);
-
-                               return need_input;
-                       }
-               }
-       }
-
-       return FALSE;
-}
-
-static gboolean
 mail_shell_view_key_press_event_cb (EMailShellView *mail_shell_view,
                                     GdkEventKey *event)
 {
@@ -312,7 +285,8 @@ mail_shell_view_key_press_event_cb (EMailShellView *mail_shell_view,
                        return FALSE;
        }
 
-       if (mail_shell_view_mail_display_needs_key (mail_shell_view, mail_display))
+       if (e_web_view_get_need_input (E_WEB_VIEW (mail_display)) &&
+           gtk_widget_has_focus (GTK_WIDGET (mail_display)))
                return FALSE;
 
        gtk_action_activate (action);
diff --git a/web-extensions/e-dom-utils.c b/web-extensions/e-dom-utils.c
index 5364033..28ac97e 100644
--- a/web-extensions/e-dom-utils.c
+++ b/web-extensions/e-dom-utils.c
@@ -805,126 +805,6 @@ e_dom_utils_bind_dom (WebKitDOMDocument *document,
        g_clear_object (&nodes);
 }
 
-static void
-e_dom_utils_bind_elements_recursively (WebKitDOMDocument *document,
-                                       const gchar *selector,
-                                       const gchar *event,
-                                       gpointer callback,
-                                       gpointer user_data)
-{
-       WebKitDOMNodeList *nodes = NULL;
-       WebKitDOMHTMLCollection *frames = NULL;
-       gulong ii, length;
-
-       nodes = webkit_dom_document_query_selector_all (
-                       document, selector, NULL);
-
-       length = webkit_dom_node_list_get_length (nodes);
-       for (ii = 0; ii < length; ii++) {
-               WebKitDOMNode *node;
-
-               node = webkit_dom_node_list_item (nodes, ii);
-               webkit_dom_event_target_add_event_listener (
-                       WEBKIT_DOM_EVENT_TARGET (node), event,
-                       G_CALLBACK (callback), FALSE, user_data);
-       }
-       g_clear_object (&nodes);
-
-       frames = webkit_dom_document_get_elements_by_tag_name_as_html_collection (document, "iframe");
-       length = webkit_dom_html_collection_get_length (frames);
-
-       /* Add rules to every sub document */
-       for (ii = 0; ii < length; ii++) {
-               WebKitDOMDocument *content_document = NULL;
-               WebKitDOMNode *node;
-
-               node = webkit_dom_html_collection_item (frames, ii);
-               content_document =
-                       webkit_dom_html_iframe_element_get_content_document (
-                               WEBKIT_DOM_HTML_IFRAME_ELEMENT (node));
-
-               if (!content_document)
-                       continue;
-
-               e_dom_utils_bind_elements_recursively (
-                       content_document,
-                       selector,
-                       event,
-                       callback,
-                       user_data);
-       }
-       g_clear_object (&frames);
-}
-
-static void
-element_focus_cb (WebKitDOMElement *element,
-                  WebKitDOMEvent *event,
-                 GDBusConnection *connection)
-{
-       g_dbus_connection_call (
-               connection,
-               E_WEB_EXTENSION_SERVICE_NAME,
-               E_WEB_EXTENSION_OBJECT_PATH,
-               "org.freedesktop.DBus.Properties",
-               "Set",
-               g_variant_new (
-                       "(ssv)",
-                       E_WEB_EXTENSION_INTERFACE,
-                       "NeedInput",
-                       g_variant_new_boolean (TRUE)),
-               NULL,
-               G_DBUS_CALL_FLAGS_NONE,
-               -1,
-               NULL,
-               NULL,
-               NULL);
-}
-
-static void
-element_blur_cb (WebKitDOMElement *element,
-                 WebKitDOMEvent *event,
-                GDBusConnection *connection)
-{
-       g_dbus_connection_call (
-               connection,
-               E_WEB_EXTENSION_SERVICE_NAME,
-               E_WEB_EXTENSION_OBJECT_PATH,
-               "org.freedesktop.DBus.Properties",
-               "Set",
-               g_variant_new (
-                       "(ssv)",
-                       E_WEB_EXTENSION_INTERFACE,
-                       "NeedInput",
-                       g_variant_new_boolean (FALSE)),
-               NULL,
-               G_DBUS_CALL_FLAGS_NONE,
-               -1,
-               NULL,
-               NULL,
-               NULL);
-}
-
-void
-e_dom_utils_bind_focus_on_elements (WebKitDOMDocument *document,
-                                    GDBusConnection *connection)
-{
-       const gchar *elements = "input, textarea, select, button, label";
-
-       e_dom_utils_bind_elements_recursively (
-               document,
-               elements,
-               "focus",
-               element_focus_cb,
-               connection);
-
-       e_dom_utils_bind_elements_recursively (
-               document,
-               elements,
-               "blur",
-               element_blur_cb,
-               connection);
-}
-
 void
 e_dom_utils_e_mail_display_bind_dom (WebKitDOMDocument *document,
                                      GDBusConnection *connection)
diff --git a/web-extensions/e-dom-utils.h b/web-extensions/e-dom-utils.h
index 5f0d503..7b3cbca 100644
--- a/web-extensions/e-dom-utils.h
+++ b/web-extensions/e-dom-utils.h
@@ -55,9 +55,6 @@ void          e_dom_utils_add_css_rule_into_style_sheet
                                                 const gchar *style);
 void           e_dom_utils_eab_contact_formatter_bind_dom
                                                (WebKitDOMDocument *document);
-void           e_dom_utils_bind_focus_on_elements
-                                               (WebKitDOMDocument *document,
-                                                GDBusConnection *connection);
 void           e_dom_utils_e_mail_display_bind_dom
                                                (WebKitDOMDocument *document,
                                                 GDBusConnection *connection);
diff --git a/web-extensions/e-web-extension.c b/web-extensions/e-web-extension.c
index 2a2bb56..b18862b 100644
--- a/web-extensions/e-web-extension.c
+++ b/web-extensions/e-web-extension.c
@@ -42,6 +42,12 @@
        (G_TYPE_INSTANCE_GET_PRIVATE \
        ((obj), E_TYPE_WEB_EXTENSION, EWebExtensionPrivate))
 
+typedef struct _EWebPageData {
+       WebKitWebPage *web_page; /* not referenced */
+       gboolean need_input;
+       guint32 clipboard_flags;
+} EWebPageData;
+
 struct _EWebExtensionPrivate {
        WebKitWebExtension *wk_extension;
 
@@ -50,8 +56,7 @@ struct _EWebExtensionPrivate {
 
        gboolean initialized;
 
-       gboolean need_input;
-       guint32 clipboard_flags;
+       GHashTable *pages; /* guint64 *webpage_id ~> EWebPageData * */
 };
 
 static const char introspection_xml[] =
@@ -180,8 +185,14 @@ static const char introspection_xml[] =
 "      <arg type='b' name='towards_bottom' direction='in'/>"
 "      <arg type='b' name='processed' direction='out'/>"
 "    </method>"
-"    <property type='b' name='NeedInput' access='readwrite'/>"
-"    <property type='u' name='ClipboardFlags' access='readwrite'/>"
+"    <signal name='NeedInputChanged'>"
+"      <arg type='t' name='page_id' direction='out'/>"
+"      <arg type='b' name='need_input' direction='out'/>"
+"    </signal>"
+"    <signal name='ClipboardFlagsChanged'>"
+"      <arg type='t' name='page_id' direction='out'/>"
+"      <arg type='u' name='flags' direction='out'/>"
+"    </signal>"
 "  </interface>"
 "</node>";
 
@@ -327,6 +338,172 @@ web_extension_register_element_clicked_in_document (EWebExtension *extension,
        g_clear_object (&collection);
 }
 
+static guint64
+e_web_extension_find_page_id_from_document (WebKitDOMDocument *document)
+{
+       guint64 *ppage_id;
+
+       g_return_val_if_fail (WEBKIT_DOM_IS_DOCUMENT (document), 0);
+
+       while (document) {
+               WebKitDOMDocument *prev_document = document;
+
+               ppage_id = g_object_get_data (G_OBJECT (document), WEB_EXTENSION_PAGE_ID_KEY);
+               if (ppage_id)
+                       return *ppage_id;
+
+               document = webkit_dom_node_get_owner_document (WEBKIT_DOM_NODE (document));
+               if (prev_document == document)
+                       break;
+       }
+
+       return 0;
+}
+
+static void
+e_web_extension_set_need_input (EWebExtension *extension,
+                               guint64 page_id,
+                               gboolean need_input)
+{
+       EWebPageData *page_data;
+       GError *error = NULL;
+
+       g_return_if_fail (E_IS_WEB_EXTENSION (extension));
+       g_return_if_fail (page_id != 0);
+
+       page_data = g_hash_table_lookup (extension->priv->pages, &page_id);
+
+       if (!page_data || (!page_data->need_input) == (!need_input))
+               return;
+
+       page_data->need_input = need_input;
+
+       g_dbus_connection_emit_signal (
+               extension->priv->dbus_connection,
+               NULL,
+               E_WEB_EXTENSION_OBJECT_PATH,
+               E_WEB_EXTENSION_INTERFACE,
+               "NeedInputChanged",
+               g_variant_new ("(tb)", page_id, need_input),
+               &error);
+
+       if (error) {
+               g_warning ("Error emitting signal NeedInputChanged: %s\n", error->message);
+               g_error_free (error);
+       }
+}
+
+static void
+element_focus_cb (WebKitDOMElement *element,
+                 WebKitDOMEvent *event,
+                 EWebExtension *extension)
+{
+       guint64 *ppage_id;
+
+       g_return_if_fail (E_IS_WEB_EXTENSION (extension));
+
+       ppage_id = g_object_get_data (G_OBJECT (element), WEB_EXTENSION_PAGE_ID_KEY);
+       g_return_if_fail (ppage_id != NULL);
+
+       e_web_extension_set_need_input (extension, *ppage_id, TRUE);
+}
+
+static void
+element_blur_cb (WebKitDOMElement *element,
+                WebKitDOMEvent *event,
+                EWebExtension *extension)
+{
+       guint64 *ppage_id;
+
+       g_return_if_fail (E_IS_WEB_EXTENSION (extension));
+
+       ppage_id = g_object_get_data (G_OBJECT (element), WEB_EXTENSION_PAGE_ID_KEY);
+       g_return_if_fail (ppage_id != NULL);
+
+       e_web_extension_set_need_input (extension, *ppage_id, FALSE);
+}
+
+static void
+e_web_extension_bind_focus_and_blur_recursively (EWebExtension *extension,
+                                                WebKitDOMDocument *document,
+                                                const gchar *selector,
+                                                guint64 page_id)
+{
+       WebKitDOMNodeList *nodes = NULL;
+       WebKitDOMHTMLCollection *frames = NULL;
+       gulong ii, length;
+
+       g_return_if_fail (E_IS_WEB_EXTENSION (extension));
+
+       nodes = webkit_dom_document_query_selector_all (document, selector, NULL);
+
+       length = webkit_dom_node_list_get_length (nodes);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *node;
+               guint64 *ppage_id;
+
+               node = webkit_dom_node_list_item (nodes, ii);
+
+               ppage_id = g_new (guint64, 1);
+               *ppage_id = page_id;
+
+               g_object_set_data_full (G_OBJECT (node), WEB_EXTENSION_PAGE_ID_KEY, ppage_id, g_free);
+
+               webkit_dom_event_target_add_event_listener (
+                       WEBKIT_DOM_EVENT_TARGET (node), "focus",
+                       G_CALLBACK (element_focus_cb), FALSE, extension);
+
+               webkit_dom_event_target_add_event_listener (
+                       WEBKIT_DOM_EVENT_TARGET (node), "blur",
+                       G_CALLBACK (element_blur_cb), FALSE, extension);
+       }
+       g_clear_object (&nodes);
+
+       frames = webkit_dom_document_get_elements_by_tag_name_as_html_collection (document, "iframe");
+       length = webkit_dom_html_collection_get_length (frames);
+
+       /* Add rules to every sub document */
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMDocument *content_document = NULL;
+               WebKitDOMNode *node;
+
+               node = webkit_dom_html_collection_item (frames, ii);
+               content_document =
+                       webkit_dom_html_iframe_element_get_content_document (
+                               WEBKIT_DOM_HTML_IFRAME_ELEMENT (node));
+
+               if (!content_document)
+                       continue;
+
+               e_web_extension_bind_focus_and_blur_recursively (
+                       extension,
+                       content_document,
+                       selector,
+                       page_id);
+       }
+       g_clear_object (&frames);
+}
+
+static void
+e_web_extension_bind_focus_on_elements (EWebExtension *extension,
+                                       WebKitDOMDocument *document)
+{
+       const gchar *elements = "input, textarea, select, button, label";
+       guint64 page_id;
+
+       g_return_if_fail (E_IS_WEB_EXTENSION (extension));
+       g_return_if_fail (WEBKIT_DOM_IS_DOCUMENT (document));
+
+       page_id = e_web_extension_find_page_id_from_document (document);
+       g_return_if_fail (page_id != 0);
+
+       e_web_extension_bind_focus_and_blur_recursively (
+               extension,
+               document,
+               elements,
+               page_id);
+}
+
 static void
 handle_method_call (GDBusConnection *connection,
                     const char *sender,
@@ -640,7 +817,7 @@ handle_method_call (GDBusConnection *connection,
 
                document = webkit_web_page_get_dom_document (web_page);
                e_dom_utils_e_mail_display_bind_dom (document, connection);
-               e_dom_utils_bind_focus_on_elements (document, connection);
+               e_web_extension_bind_focus_on_elements (extension, document);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "ElementExists") == 0) {
@@ -819,13 +996,10 @@ handle_get_property (GDBusConnection *connection,
                      GError **error,
                      gpointer user_data)
 {
-       EWebExtension *extension = E_WEB_EXTENSION (user_data);
+       /* EWebExtension *extension = E_WEB_EXTENSION (user_data); */
        GVariant *variant = NULL;
 
-       if (g_strcmp0 (property_name, "NeedInput") == 0)
-               variant = g_variant_new_boolean (extension->priv->need_input);
-       else if (g_strcmp0 (property_name, "ClipboardFlags") == 0)
-               variant = g_variant_new_uint32 (extension->priv->clipboard_flags);
+       g_warn_if_reached ();
 
        return variant;
 }
@@ -840,54 +1014,9 @@ handle_set_property (GDBusConnection *connection,
                      GError **error,
                      gpointer user_data)
 {
-       EWebExtension *extension = E_WEB_EXTENSION (user_data);
-       GError *local_error = NULL;
-       GVariantBuilder *builder;
-
-       builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
-
-       if (g_strcmp0 (property_name, "NeedInput") == 0) {
-               gboolean value = g_variant_get_boolean (variant);
-
-               if (value == extension->priv->need_input)
-                       goto exit;
-
-               extension->priv->need_input = value;
-
-               g_variant_builder_add (builder,
-                       "{sv}",
-                       "NeedInput",
-                       g_variant_new_boolean (value));
-       } else if (g_strcmp0 (property_name, "ClipboardFlags") == 0) {
-               guint32 value = g_variant_get_uint32 (variant);
-
-               if (value == extension->priv->clipboard_flags)
-                       goto exit;
-
-               extension->priv->clipboard_flags = value;
-
-               g_variant_builder_add (builder,
-                       "{sv}",
-                       "ClipboardFlags",
-                       g_variant_new_uint32 (value));
-       }
-
-       g_dbus_connection_emit_signal (connection,
-               NULL,
-               object_path,
-               "org.freedesktop.DBus.Properties",
-               "PropertiesChanged",
-               g_variant_new (
-                       "(sa{sv}as)",
-                       interface_name,
-                       builder,
-                       NULL),
-               &local_error);
+       /* EWebExtension *extension = E_WEB_EXTENSION (user_data); */
 
-       g_assert_no_error (local_error);
-
- exit:
-       g_variant_builder_unref (builder);
+       g_warn_if_reached ();
 
        return TRUE;
 }
@@ -899,6 +1028,27 @@ static const GDBusInterfaceVTable interface_vtable = {
 };
 
 static void
+web_page_gone_cb (gpointer user_data,
+                  GObject *gone_web_page)
+{
+       EWebExtension *extension = user_data;
+       GHashTableIter iter;
+       gpointer key, value;
+
+       g_return_if_fail (E_IS_WEB_EXTENSION (extension));
+
+       g_hash_table_iter_init (&iter, extension->priv->pages);
+       while (g_hash_table_iter_next (&iter, &key, &value)) {
+               EWebPageData *page_data = value;
+
+               if (page_data->web_page == (gpointer) gone_web_page) {
+                       g_hash_table_remove (extension->priv->pages, key);
+                       break;
+               }
+       }
+}
+
+static void
 e_web_extension_dispose (GObject *object)
 {
        EWebExtension *extension = E_WEB_EXTENSION (object);
@@ -911,19 +1061,35 @@ e_web_extension_dispose (GObject *object)
                extension->priv->dbus_connection = NULL;
        }
 
+       g_hash_table_remove_all (extension->priv->pages);
+
        g_clear_object (&extension->priv->wk_extension);
 
        G_OBJECT_CLASS (e_web_extension_parent_class)->dispose (object);
 }
 
 static void
+e_web_extension_finalize (GObject *object)
+{
+       EWebExtension *extension = E_WEB_EXTENSION (object);
+
+       if (extension->priv->pages) {
+               g_hash_table_destroy (extension->priv->pages);
+               extension->priv->pages = NULL;
+       }
+
+       G_OBJECT_CLASS (e_web_extension_parent_class)->finalize (object);
+}
+
+static void
 e_web_extension_class_init (EWebExtensionClass *class)
 {
        GObjectClass *object_class = G_OBJECT_CLASS (class);
 
-       object_class->dispose = e_web_extension_dispose;
+       g_type_class_add_private (object_class, sizeof (EWebExtensionPrivate));
 
-       g_type_class_add_private (object_class, sizeof(EWebExtensionPrivate));
+       object_class->dispose = e_web_extension_dispose;
+       object_class->finalize = e_web_extension_finalize;
 }
 
 static void
@@ -932,8 +1098,7 @@ e_web_extension_init (EWebExtension *extension)
        extension->priv = G_TYPE_INSTANCE_GET_PRIVATE (extension, E_TYPE_WEB_EXTENSION, EWebExtensionPrivate);
 
        extension->priv->initialized = FALSE;
-       extension->priv->need_input = FALSE;
-       extension->priv->clipboard_flags = 0;
+       extension->priv->pages = g_hash_table_new_full (g_int64_hash, g_int64_equal, g_free, g_free);
 }
 
 static gpointer
@@ -987,9 +1152,15 @@ web_page_document_loaded_cb (WebKitWebPage *web_page,
                              gpointer user_data)
 {
        WebKitDOMDocument *document;
+       guint64 *ppage_id;
 
        document = webkit_web_page_get_dom_document (web_page);
 
+       ppage_id = g_new (guint64, 1);
+       *ppage_id = webkit_web_page_get_id (web_page);
+
+       g_object_set_data_full (G_OBJECT (document), WEB_EXTENSION_PAGE_ID_KEY, ppage_id, g_free);
+
        e_dom_utils_replace_local_image_links (document);
 
        if ((webkit_dom_document_query_selector (
@@ -1008,6 +1179,43 @@ web_page_document_loaded_cb (WebKitWebPage *web_page,
 }
 
 static void
+e_web_extension_set_clipboard_flags (EWebExtension *extension,
+                                    WebKitDOMDocument *document,
+                                    guint32 clipboard_flags)
+{
+       EWebPageData *page_data;
+       guint64 page_id;
+       GError *error = NULL;
+
+       g_return_if_fail (E_IS_WEB_EXTENSION (extension));
+       g_return_if_fail (WEBKIT_DOM_IS_DOCUMENT (document));
+
+       page_id = e_web_extension_find_page_id_from_document (document);
+       g_return_if_fail (page_id != 0);
+
+       page_data = g_hash_table_lookup (extension->priv->pages, &page_id);
+
+       if (!page_data || page_data->clipboard_flags == clipboard_flags)
+               return;
+
+       page_data->clipboard_flags = clipboard_flags;
+
+       g_dbus_connection_emit_signal (
+               extension->priv->dbus_connection,
+               NULL,
+               E_WEB_EXTENSION_OBJECT_PATH,
+               E_WEB_EXTENSION_INTERFACE,
+               "ClipboardFlagsChanged",
+               g_variant_new ("(tu)", page_id, clipboard_flags),
+               &error);
+
+       if (error) {
+               g_warning ("Error emitting signal ClipboardFlagsChanged: %s\n", error->message);
+               g_error_free (error);
+       }
+}
+
+static void
 web_editor_selection_changed_cb (WebKitWebEditor *web_editor,
                                  EWebExtension *extension)
 {
@@ -1022,23 +1230,7 @@ web_editor_selection_changed_cb (WebKitWebEditor *web_editor,
        if (e_dom_utils_document_has_selection (document))
                clipboard_flags |= E_CLIPBOARD_CAN_COPY;
 
-       g_dbus_connection_call (
-               extension->priv->dbus_connection,
-               E_WEB_EXTENSION_SERVICE_NAME,
-               E_WEB_EXTENSION_OBJECT_PATH,
-               "org.freedesktop.DBus.Properties",
-               "Set",
-               g_variant_new (
-                       "(ssv)",
-                       E_WEB_EXTENSION_INTERFACE,
-                       "ClipboardFlags",
-                       g_variant_new_uint32 (clipboard_flags)),
-               NULL,
-               G_DBUS_CALL_FLAGS_NONE,
-               -1,
-               NULL,
-               NULL,
-               NULL);
+       e_web_extension_set_clipboard_flags (extension, document, clipboard_flags);
 }
 
 static void
@@ -1046,6 +1238,21 @@ web_page_created_cb (WebKitWebExtension *wk_extension,
                      WebKitWebPage *web_page,
                      EWebExtension *extension)
 {
+       EWebPageData *page_data;
+       guint64 *ppage_id;
+
+       ppage_id = g_new (guint64, 1);
+       *ppage_id = webkit_web_page_get_id (web_page);
+
+       page_data = g_new0 (EWebPageData, 1);
+       page_data->web_page = web_page;
+       page_data->need_input = FALSE;
+       page_data->clipboard_flags = 0;
+
+       g_hash_table_insert (extension->priv->pages, ppage_id, page_data);
+
+       g_object_weak_ref (G_OBJECT (web_page), web_page_gone_cb, extension);
+
        g_signal_connect_object (
                web_page, "send-request",
                G_CALLBACK (web_page_send_request_cb),


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