[evolution/wip-webkit2] Avoid race condition while asking for the name of HTML element that currently has focus.



commit 4005293662b7363fd3fb57a74ffa5483e18df833
Author: Tomas Popela <tpopela redhat com>
Date:   Thu Dec 5 14:28:08 2013 +0100

    Avoid race condition while asking for the name of HTML element that currently has focus.

 e-util/e-dom-utils.c                     |  121 +++++++++++++++++++++++++++++-
 e-util/e-dom-utils.h                     |    3 +
 e-util/e-web-view.c                      |    1 -
 mail/e-mail-reader.c                     |   24 +-----
 modules/mail/e-mail-shell-view-private.c |   62 ++-------------
 web-extensions/evolution-web-extension.c |   64 +++++++++++++++-
 6 files changed, 198 insertions(+), 77 deletions(-)
---
diff --git a/e-util/e-dom-utils.c b/e-util/e-dom-utils.c
index 658578a..552943d 100644
--- a/e-util/e-dom-utils.c
+++ b/e-util/e-dom-utils.c
@@ -527,7 +527,7 @@ toggle_headers_visibility (WebKitDOMElement *button,
 static void
 toggle_address_visibility (WebKitDOMElement *button,
                            WebKitDOMEvent *event,
-                          GDBusConnection *connection)
+                           GDBusConnection *connection)
 {
        WebKitDOMElement *full_addr, *ellipsis;
        WebKitDOMElement *parent;
@@ -618,6 +618,125 @@ e_dom_utils_bind_dom (WebKitDOMDocument *document,
        }
 }
 
+static void
+e_dom_utils_bind_elements_recursively (WebKitDOMDocument *document,
+                                       const gchar *selector,
+                                       const gchar *event,
+                                       gpointer callback,
+                                       gpointer user_data)
+{
+       WebKitDOMNodeList *nodes;
+       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);
+       }
+
+       nodes = webkit_dom_document_query_selector_all (document, "iframe", NULL);
+       length = webkit_dom_node_list_get_length (nodes);
+
+       /* Add rules to every sub document */
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMDocument *content_document = NULL;
+               WebKitDOMNode *node;
+
+               node = webkit_dom_node_list_item (nodes, 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);
+       }
+}
+
+static void
+element_focus_cb (WebKitDOMElement *element,
+                  WebKitDOMEvent *event,
+                 GDBusConnection *connection)
+{
+       g_dbus_connection_call (
+               connection,
+               "org.gnome.Evolution.WebExtension",
+               "/org/gnome/Evolution/WebExtension",
+               "org.freedesktop.DBus.Properties",
+               "Set",
+               g_variant_new (
+                       "(ssv)",
+                       "org.gnome.Evolution.WebExtension",
+                       "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,
+               "org.gnome.Evolution.WebExtension",
+               "/org/gnome/Evolution/WebExtension",
+               "org.freedesktop.DBus.Properties",
+               "Set",
+               g_variant_new (
+                       "(ssv)",
+                       "org.gnome.Evolution.WebExtension",
+                       "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/e-util/e-dom-utils.h b/e-util/e-dom-utils.h
index 56916da..6803951 100644
--- a/e-util/e-dom-utils.h
+++ b/e-util/e-dom-utils.h
@@ -48,6 +48,9 @@ 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/e-util/e-web-view.c b/e-util/e-web-view.c
index 253e6bd..ef833ae 100644
--- a/e-util/e-web-view.c
+++ b/e-util/e-web-view.c
@@ -1156,7 +1156,6 @@ web_extension_appeared_cb (GDBusConnection *connection,
        g_dbus_proxy_new (
                connection,
                G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START |
-               G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
                G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
                NULL,
                name,
diff --git a/mail/e-mail-reader.c b/mail/e-mail-reader.c
index 167d2ed..68f2d1e 100644
--- a/mail/e-mail-reader.c
+++ b/mail/e-mail-reader.c
@@ -2469,30 +2469,14 @@ mail_reader_key_press_event_cb (EMailReader *reader,
                web_extension = e_web_view_get_web_extension_proxy (E_WEB_VIEW (display));
                if (web_extension) {
                        GVariant *result;
-                       const gchar *element_name = NULL;
-
-                       result = g_dbus_proxy_call_sync (
-                                       web_extension,
-                                       "GetActiveElementName",
-                                       g_variant_new (
-                                               "(t)",
-                                               webkit_web_view_get_page_id (
-                                                       WEBKIT_WEB_VIEW (display))),
-                                       G_DBUS_CALL_FLAGS_NONE,
-                                       -1,
-                                       NULL,
-                                       NULL);
 
+                       result = g_dbus_proxy_get_cached_property (web_extension, "NeedInput");
                        if (result) {
-                               g_variant_get (result, "(&s)", &element_name);
+                               gboolean need_input = g_variant_get_boolean (result);
                                g_variant_unref (result);
 
-                               if (element_name && *element_name) {
-                                       if (g_strcmp0 (element_name, "input") == 0 ||
-                                                       g_strcmp0 (element_name, "textarea") == 0) {
-                                               return FALSE;
-                                       }
-                               }
+                               if (need_input)
+                                       return FALSE;
                        }
                }
        }
diff --git a/modules/mail/e-mail-shell-view-private.c b/modules/mail/e-mail-shell-view-private.c
index 2a6e6be..14fd7af 100644
--- a/modules/mail/e-mail-shell-view-private.c
+++ b/modules/mail/e-mail-shell-view-private.c
@@ -256,39 +256,24 @@ 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,
-                                        gboolean with_input)
+                                        EMailDisplay *mail_display)
 {
        if (gtk_widget_has_focus (GTK_WIDGET (mail_display))) {
                GDBusProxy *web_extension;
 
-               web_extension = e_mail_shell_view_get_web_extension_proxy (mail_shell_view);
+               /* Intentionally use Evolution Web Extension */
+               web_extension = e_web_view_get_web_extension_proxy (E_WEB_VIEW (mail_display));
                if (web_extension) {
                        GVariant *result;
-                       const gchar *element_name = NULL;
-
-                       result = g_dbus_proxy_call_sync (
-                                       web_extension,
-                                       "GetActiveElementName",
-                                       g_variant_new (
-                                               "(t)",
-                                               webkit_web_view_get_page_id (
-                                                       WEBKIT_WEB_VIEW (mail_display))),
-                                       G_DBUS_CALL_FLAGS_NONE,
-                                       -1,
-                                       NULL,
-                                       NULL);
 
+                       result = g_dbus_proxy_get_cached_property (web_extension, "NeedInput");
                        if (result) {
-                               element_name = g_variant_get_string (result, NULL);
+                               gboolean need_input;
+
+                               need_input = g_variant_get_boolean (result);
                                g_variant_unref (result);
 
-                               if (element_name && *element_name) {
-                                       if ((with_input && g_strcmp0 (element_name, "input") == 0) ||
-                                           g_strcmp0 (element_name, "textarea") == 0) {
-                                               return TRUE;
-                                       }
-                               }
+                               return need_input;
                        }
                }
        }
@@ -327,40 +312,11 @@ mail_shell_view_key_press_event_cb (EMailShellView *mail_shell_view,
                        action = ACTION (MAIL_SMART_BACKWARD);
                        break;
 
-               case GDK_KEY_Home:
-               case GDK_KEY_Left:
-               case GDK_KEY_Up:
-               case GDK_KEY_Right:
-               case GDK_KEY_Down:
-               case GDK_KEY_Prior:
-               case GDK_KEY_Next:
-               case GDK_KEY_End:
-               case GDK_KEY_Begin:
-#if 0
-                       if (!mail_shell_view_mail_display_needs_key (mail_shell_view, mail_display, FALSE) &&
-                           webkit_web_view_get_main_frame (WEBKIT_WEB_VIEW (mail_display)) !=
-                           webkit_web_view_get_focused_frame (WEBKIT_WEB_VIEW (mail_display))) {
-                               WebKitDOMDocument *document;
-                               WebKitDOMDOMWindow *window;
-
-                               document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (mail_display));
-                               window = webkit_dom_document_get_default_view (document);
-
-                               /* Workaround WebKit bug for key navigation, when inner IFRAME is focused.
-                                * EMailView's inner IFRAMEs have disabled scrolling, but WebKit doesn't post
-                                * key navigation events to parent's frame, thus the view doesn't scroll.
-                                * This is a poor workaround for this issue, the main frame is focused,
-                                * which has scrolling enabled.
-                               */
-                               webkit_dom_dom_window_focus (window);
-                       }
-#endif
-                       return FALSE;
                default:
                        return FALSE;
        }
 
-       if (mail_shell_view_mail_display_needs_key (mail_shell_view, mail_display, TRUE))
+       if (mail_shell_view_mail_display_needs_key (mail_shell_view, mail_display))
                return FALSE;
 
        gtk_action_activate (action);
diff --git a/web-extensions/evolution-web-extension.c b/web-extensions/evolution-web-extension.c
index 26c205b..02fa3ba 100644
--- a/web-extensions/evolution-web-extension.c
+++ b/web-extensions/evolution-web-extension.c
@@ -30,6 +30,7 @@
 
 /* FIXME Clean it */
 static GDBusConnection *dbus_connection;
+static gboolean need_input = FALSE;
 
 static const char introspection_xml[] =
 "<node>"
@@ -103,6 +104,7 @@ static const char introspection_xml[] =
 "      <arg type='s' name='button_id' direction='in'/>"
 "      <arg type='s' name='src' direction='in'/>"
 "    </method>"
+"    <property type='b' name='NeedInput' access='readwrite'/>"
 "  </interface>"
 "</node>";
 
@@ -301,6 +303,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);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "ElementExists") == 0) {
@@ -389,10 +392,67 @@ handle_method_call (GDBusConnection *connection,
        }
 }
 
+static GVariant *
+handle_get_property (GDBusConnection *connection,
+                     const gchar *sender,
+                     const gchar *object_path,
+                     const gchar *interface_name,
+                     const gchar *property_name,
+                     GError **error,
+                     gpointer user_data)
+{
+       GVariant *variant;
+
+       if (g_strcmp0 (property_name, "NeedInput") == 0) {
+               variant = g_variant_new_boolean (need_input);
+       }
+
+       return variant;
+}
+
+static gboolean
+handle_set_property (GDBusConnection *connection,
+                     const gchar *sender,
+                     const gchar *object_path,
+                     const gchar *interface_name,
+                     const gchar *property_name,
+                     GVariant *variant,
+                     GError **error,
+                     gpointer user_data)
+{
+       if (need_input != g_variant_get_boolean (variant)) {
+               GVariantBuilder *builder;
+               GError *local_error;
+
+               need_input = g_variant_get_boolean (variant);
+
+               local_error = NULL;
+               builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
+               g_variant_builder_add (builder,
+                               "{sv}",
+                               "NeedInput",
+                               g_variant_new_boolean (need_input));
+               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);
+               g_assert_no_error (local_error);
+       }
+
+       return TRUE;
+}
+
 static const GDBusInterfaceVTable interface_vtable = {
        handle_method_call,
-       NULL,
-       NULL
+       handle_get_property,
+       handle_set_property
 };
 
 static void


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