[evolution/wip/mcrha/webkit-jsc-api] Implement and use GetElementFromPoint



commit 5dc032928ce16730256f4d774c47dc147b043e6c
Author: Milan Crha <mcrha redhat com>
Date:   Wed Oct 2 12:50:46 2019 +0200

    Implement and use GetElementFromPoint

 src/e-util/e-web-view-jsc-utils.c |  82 +++++++++++++++++
 src/e-util/e-web-view-jsc-utils.h |  14 +++
 src/e-util/e-web-view.c           | 100 +++++++++++++++++----
 src/e-util/e-web-view.h           |   5 ++
 src/e-util/test-web-view.c        | 180 ++++++++++++++++++++++++++++++++++++--
 src/mail/e-mail-display.c         |  41 ++++-----
 src/web-extensions/ext-utils.js   |  72 ++++++++++++++-
 7 files changed, 445 insertions(+), 49 deletions(-)
---
diff --git a/src/e-util/e-web-view-jsc-utils.c b/src/e-util/e-web-view-jsc-utils.c
index 9930195ead..6bb72f82e9 100644
--- a/src/e-util/e-web-view-jsc-utils.c
+++ b/src/e-util/e-web-view-jsc-utils.c
@@ -551,3 +551,85 @@ e_web_view_jsc_get_element_content_finish (WebKitWebView *web_view,
 
        return ewv_jsc_get_content_finish (web_view, result, out_texts, error);
 }
+
+void
+e_web_view_jsc_get_element_from_point (WebKitWebView *web_view,
+                                      gint xx,
+                                      gint yy,
+                                      GCancellable *cancellable,
+                                      GAsyncReadyCallback callback,
+                                      gpointer user_data)
+{
+       gchar *script;
+
+       g_return_if_fail (WEBKIT_IS_WEB_VIEW (web_view));
+
+       script = e_web_view_jsc_printf_script ("Evo.GetElementFromPoint(%d,%d)", xx, yy);
+
+       webkit_web_view_run_javascript (web_view, script, cancellable, callback, user_data);
+
+       g_free (script);
+}
+
+/* Can return TRUE, but set all out parameters to NULL */
+gboolean
+e_web_view_jsc_get_element_from_point_finish (WebKitWebView *web_view,
+                                             GAsyncResult *result,
+                                             gchar **out_iframe_src,
+                                             gchar **out_iframe_id,
+                                             gchar **out_element_id,
+                                             GError **error)
+{
+       WebKitJavascriptResult *js_result;
+       GError *local_error = NULL;
+
+       g_return_val_if_fail (WEBKIT_IS_WEB_VIEW (web_view), FALSE);
+       g_return_val_if_fail (result != NULL, FALSE);
+
+       if (out_iframe_src)
+               *out_iframe_src = NULL;
+       if (out_iframe_id)
+               *out_iframe_id = NULL;
+       if (out_element_id)
+               *out_element_id = NULL;
+
+       js_result = webkit_web_view_run_javascript_finish (web_view, result, &local_error);
+
+       if (local_error) {
+               g_propagate_error (error, local_error);
+
+               if (js_result)
+                       webkit_javascript_result_unref (js_result);
+
+               return FALSE;
+       }
+
+       if (js_result) {
+               JSCException *exception;
+               JSCValue *value;
+
+               value = webkit_javascript_result_get_js_value (js_result);
+               exception = jsc_context_get_exception (jsc_value_get_context (value));
+
+               if (exception) {
+                       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Call failed: %s", 
jsc_exception_get_message (exception));
+                       webkit_javascript_result_unref (js_result);
+                       return FALSE;
+               }
+
+               if (jsc_value_is_object (value)) {
+                       if (out_iframe_src)
+                               *out_iframe_src = e_web_view_jsc_get_object_property_string (value, 
"iframe-src", NULL);
+                       if (out_iframe_id)
+                               *out_iframe_id = e_web_view_jsc_get_object_property_string (value, 
"iframe-id", NULL);
+                       if (out_element_id)
+                               *out_element_id = e_web_view_jsc_get_object_property_string (value, 
"elem-id", NULL);
+               } else if (!jsc_value_is_null (value)) {
+                       g_warn_if_reached ();
+               }
+
+               webkit_javascript_result_unref (js_result);
+       }
+
+       return TRUE;
+}
diff --git a/src/e-util/e-web-view-jsc-utils.h b/src/e-util/e-web-view-jsc-utils.h
index 104895dde5..c9d8eda02e 100644
--- a/src/e-util/e-web-view-jsc-utils.h
+++ b/src/e-util/e-web-view-jsc-utils.h
@@ -139,6 +139,20 @@ gboolean   e_web_view_jsc_get_element_content_finish
                                                 GAsyncResult *result,
                                                 GSList **out_texts,
                                                 GError **error);
+void           e_web_view_jsc_get_element_from_point
+                                               (WebKitWebView *web_view,
+                                                gint xx,
+                                                gint yy,
+                                                GCancellable *cancellable,
+                                                GAsyncReadyCallback callback,
+                                                gpointer user_data);
+gboolean       e_web_view_jsc_get_element_from_point_finish
+                                               (WebKitWebView *web_view,
+                                                GAsyncResult *result,
+                                                gchar **out_iframe_src,
+                                                gchar **out_iframe_id,
+                                                gchar **out_element_id,
+                                                GError **error);
 
 G_END_DECLS
 
diff --git a/src/e-util/e-web-view.c b/src/e-util/e-web-view.c
index 76dcfa566a..0b97041dbb 100644
--- a/src/e-util/e-web-view.c
+++ b/src/e-util/e-web-view.c
@@ -102,6 +102,11 @@ struct _EWebViewPrivate {
        gboolean need_input;
 
        GCancellable *load_cancellable;
+
+       gchar *last_popup_iframe_src;
+       gchar *last_popup_iframe_id;
+       gchar *last_popup_element_id;
+       gchar *last_popup_link_uri;
 };
 
 struct _AsyncContext {
@@ -593,6 +598,43 @@ web_view_connect_proxy_cb (EWebView *web_view,
                G_CALLBACK (web_view_menu_item_deselect_cb), web_view);
 }
 
+static void
+web_view_got_elem_from_point_for_popup_event_cb (GObject *source_object,
+                                                GAsyncResult *result,
+                                                gpointer user_data)
+{
+       EWebView *web_view;
+       GdkEvent *event = user_data;
+       GError *error = NULL;
+
+       g_return_if_fail (E_IS_WEB_VIEW (source_object));
+
+       web_view = E_WEB_VIEW (source_object);
+
+       g_clear_pointer (&web_view->priv->last_popup_iframe_src, g_free);
+       g_clear_pointer (&web_view->priv->last_popup_iframe_id, g_free);
+       g_clear_pointer (&web_view->priv->last_popup_element_id, g_free);
+
+       if (!e_web_view_jsc_get_element_from_point_finish (WEBKIT_WEB_VIEW (web_view), result,
+               &web_view->priv->last_popup_iframe_src,
+               &web_view->priv->last_popup_iframe_id,
+               &web_view->priv->last_popup_element_id,
+               &error)) {
+               g_warning ("%s: Failed to get element from point: %s", G_STRFUNC, error ? error->message : 
"Unknown error");
+       }
+
+       if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+               gboolean handled = FALSE;
+
+               g_signal_emit (web_view, signals[POPUP_EVENT], 0,
+                       web_view->priv->last_popup_link_uri, event, &handled);
+       }
+
+       if (event)
+               gdk_event_free (event);
+       g_clear_error (&error);
+}
+
 static gboolean
 web_view_context_menu_cb (WebKitWebView *webkit_web_view,
                           WebKitContextMenu *context_menu,
@@ -602,15 +644,18 @@ web_view_context_menu_cb (WebKitWebView *webkit_web_view,
 {
        WebKitHitTestResultContext context;
        EWebView *web_view;
-       gboolean event_handled = FALSE;
        gchar *link_uri = NULL;
+       gdouble xx, yy;
 
        web_view = E_WEB_VIEW (webkit_web_view);
 
-       g_free (web_view->priv->cursor_image_src);
-       web_view->priv->cursor_image_src = NULL;
+       g_clear_pointer (&web_view->priv->cursor_image_src, g_free);
+       g_clear_pointer (&web_view->priv->last_popup_iframe_src, g_free);
+       g_clear_pointer (&web_view->priv->last_popup_iframe_id, g_free);
+       g_clear_pointer (&web_view->priv->last_popup_element_id, g_free);
+       g_clear_pointer (&web_view->priv->last_popup_link_uri, g_free);
 
-       if (hit_test_result == NULL)
+       if (!hit_test_result)
                return FALSE;
 
        context = webkit_hit_test_result_get_context (hit_test_result);
@@ -620,23 +665,23 @@ web_view_context_menu_cb (WebKitWebView *webkit_web_view,
 
                g_object_get (hit_test_result, "image-uri", &image_uri, NULL);
 
-               if (image_uri != NULL) {
-                       g_free (web_view->priv->cursor_image_src);
-                       web_view->priv->cursor_image_src = image_uri;
-               }
+               web_view->priv->cursor_image_src = image_uri;
        }
 
        if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK)
                g_object_get (hit_test_result, "link-uri", &link_uri, NULL);
 
-       g_signal_emit (
-               web_view,
-               signals[POPUP_EVENT], 0,
-               link_uri, event, &event_handled);
+       web_view->priv->last_popup_link_uri = link_uri;
+
+       if (!gdk_event_get_coords (event, &xx, &yy)) {
+               xx = 1;
+               yy = 1;
+       }
 
-       g_free (link_uri);
+       e_web_view_jsc_get_element_from_point (WEBKIT_WEB_VIEW (web_view), xx, yy, 
web_view->priv->load_cancellable,
+               web_view_got_elem_from_point_for_popup_event_cb, event ? gdk_event_copy (event) : NULL);
 
-       return event_handled;
+       return TRUE;
 }
 
 static void
@@ -1112,6 +1157,10 @@ web_view_finalize (GObject *object)
 
        priv = E_WEB_VIEW_GET_PRIVATE (object);
 
+       g_clear_pointer (&priv->last_popup_iframe_src, g_free);
+       g_clear_pointer (&priv->last_popup_iframe_id, g_free);
+       g_clear_pointer (&priv->last_popup_element_id, g_free);
+       g_clear_pointer (&priv->last_popup_link_uri, g_free);
        g_free (priv->selected_uri);
        g_free (priv->cursor_image_src);
 
@@ -1129,7 +1178,6 @@ web_view_finalize (GObject *object)
        G_OBJECT_CLASS (e_web_view_parent_class)->finalize (object);
 }
 
-
 static void
 web_view_uri_request_done_cb (GObject *source_object,
                              GAsyncResult *result,
@@ -2987,6 +3035,28 @@ e_web_view_set_save_as_proxy (EWebView *web_view,
        g_object_notify (G_OBJECT (web_view), "save-as-proxy");
 }
 
+void
+e_web_view_get_last_popup_place (EWebView *web_view,
+                                gchar **out_iframe_src,
+                                gchar **out_iframe_id,
+                                gchar **out_element_id,
+                                gchar **out_link_uri)
+{
+       g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+       if (out_iframe_src)
+               *out_iframe_src = g_strdup (web_view->priv->last_popup_iframe_src);
+
+       if (out_iframe_id)
+               *out_iframe_id = g_strdup (web_view->priv->last_popup_iframe_id);
+
+       if (out_element_id)
+               *out_element_id = g_strdup (web_view->priv->last_popup_element_id);
+
+       if (out_link_uri)
+               *out_link_uri = g_strdup (web_view->priv->last_popup_link_uri);
+}
+
 void
 e_web_view_add_highlight (EWebView *web_view,
                           const gchar *highlight)
diff --git a/src/e-util/e-web-view.h b/src/e-util/e-web-view.h
index e0cc5cd45a..871f848ed2 100644
--- a/src/e-util/e-web-view.h
+++ b/src/e-util/e-web-view.h
@@ -187,6 +187,11 @@ void               e_web_view_set_print_proxy      (EWebView *web_view,
 GtkAction *    e_web_view_get_save_as_proxy    (EWebView *web_view);
 void           e_web_view_set_save_as_proxy    (EWebView *web_view,
                                                 GtkAction *save_as_proxy);
+void           e_web_view_get_last_popup_place (EWebView *web_view,
+                                                gchar **out_iframe_src,
+                                                gchar **out_iframe_id,
+                                                gchar **out_element_id,
+                                                gchar **out_link_uri);
 void           e_web_view_add_highlight        (EWebView *web_view,
                                                 const gchar *highlight);
 void           e_web_view_clear_highlights     (EWebView *web_view);
diff --git a/src/e-util/test-web-view.c b/src/e-util/test-web-view.c
index 6033164f08..655e23ab9e 100644
--- a/src/e-util/test-web-view.c
+++ b/src/e-util/test-web-view.c
@@ -134,7 +134,7 @@ test_utils_fixture_set_up (TestFixture *fixture,
 
        fixture->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
-       gtk_window_set_default_size (GTK_WINDOW (fixture->window), 1280, 600);
+       gtk_window_set_default_size (GTK_WINDOW (fixture->window), 320, 240);
 
        fixture->web_view = WEBKIT_WEB_VIEW (e_web_view_new ());
        g_object_set (G_OBJECT (fixture->web_view),
@@ -223,7 +223,10 @@ test_utils_jsc_call_done_cb (GObject *source_object,
        js_result = webkit_web_view_run_javascript_finish (WEBKIT_WEB_VIEW (source_object), result, &error);
 
        if (error) {
-               if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+               if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) &&
+                   (!g_error_matches (error, WEBKIT_JAVASCRIPT_ERROR, WEBKIT_JAVASCRIPT_ERROR_SCRIPT_FAILED) 
||
+                    /* WebKit can return empty error message, thus ignore those. */
+                    (error->message && *(error->message))))
                        g_warning ("Failed to call '%s' function: %s", script, error->message);
                g_clear_error (&error);
        }
@@ -264,7 +267,10 @@ test_utils_jsc_call_sync_done_cb (GObject *source_object,
        js_result = webkit_web_view_run_javascript_finish (WEBKIT_WEB_VIEW (source_object), result, &error);
 
        if (error) {
-               if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+               if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) &&
+                   (!g_error_matches (error, WEBKIT_JAVASCRIPT_ERROR, WEBKIT_JAVASCRIPT_ERROR_SCRIPT_FAILED) 
||
+                    /* WebKit can return empty error message, thus ignore those. */
+                    (error->message && *(error->message))))
                        g_warning ("Failed to call '%s': %s", jcd->script, error->message);
                g_clear_error (&error);
        }
@@ -480,8 +486,8 @@ test_utils_load_body (TestFixture *fixture,
                        "<html><body>"
                        "Top<br>"
                        "<input id=\"btn1\" class=\"cbtn1\" type=\"button\" value=\"Button1\"><br>"
-                       "<iframe id=\"frm1\" src=\"empty:///\"></iframe><br>"
-                       "<iframe id=\"frm2\" src=\"empty:///\"></iframe><br>"
+                       "<iframe id=\"frm1\" src=\"empty:///frm1\"></iframe><br>"
+                       "<iframe id=\"frm2\" src=\"empty:///frm2\"></iframe><br>"
                        "<input id=\"btn3\" class=\"cbtn3\" type=\"button\" value=\"Button3\">"
                        "<a name=\"dots\" id=\"dots1\" class=\"cdots\">...</a>"
                        "</body></html>");
@@ -491,7 +497,7 @@ test_utils_load_body (TestFixture *fixture,
                test_utils_load_iframe_content (fixture, "frm1",
                        "<html><body>"
                        "frm1<br>"
-                       "<iframe id=\"frm1_1\" src=\"empty:///\"></iframe><br>"
+                       "<iframe id=\"frm1_1\" src=\"empty:///frm1_1\"></iframe><br>"
                        "<input id=\"btn1\" class=\"cbtn1\" type=\"button\" value=\"Button1\">"
                        "</body></html>");
        }
@@ -1388,7 +1394,7 @@ test_get_element_content_ready_cb (GObject *source_object,
        g_assert (WEBKIT_IS_WEB_VIEW (source_object));
        g_assert_nonnull (gcd);
 
-       success = e_web_view_jsc_get_document_content_finish (WEBKIT_WEB_VIEW (source_object), result, 
&texts, &error);
+       success = e_web_view_jsc_get_element_content_finish (WEBKIT_WEB_VIEW (source_object), result, &texts, 
&error);
 
        g_assert_no_error (error);
        g_assert (success);
@@ -1550,6 +1556,165 @@ test_get_content (TestFixture *fixture)
        test_get_element_content_verify (fixture, "frm1", "frm1p", TRUE, expect_plain, expect_html);
 }
 
+typedef struct _GetElementFromPoint {
+       TestFixture *fixture;
+       const gchar *expect_iframe_src;
+       const gchar *expect_iframe_id;
+       const gchar *expect_element_id;
+} GetElementFromPoint;
+
+static void
+test_get_element_from_point_ready_cb (GObject *source_object,
+                                     GAsyncResult *result,
+                                     gpointer user_data)
+{
+       GetElementFromPoint *gefp = user_data;
+       gchar *iframe_src = NULL, *iframe_id = NULL, *element_id = NULL;
+       gboolean success;
+       GError *error = NULL;
+
+       g_assert (WEBKIT_IS_WEB_VIEW (source_object));
+       g_assert_nonnull (gefp);
+
+       success = e_web_view_jsc_get_element_from_point_finish (WEBKIT_WEB_VIEW (source_object), result, 
&iframe_src, &iframe_id, &element_id, &error);
+
+       g_assert_no_error (error);
+       g_assert (success);
+
+       g_assert_cmpstr (iframe_src, ==, gefp->expect_iframe_src);
+       g_assert_cmpstr (iframe_id, ==, gefp->expect_iframe_id);
+       g_assert_cmpstr (element_id, ==, gefp->expect_element_id);
+
+       g_free (iframe_src);
+       g_free (iframe_id);
+       g_free (element_id);
+
+       test_flag_set (gefp->fixture->flag);
+}
+
+static void
+test_utils_verify_get_element_from_point (TestFixture *fixture,
+                                         gint xx,
+                                         gint yy,
+                                         const gchar *expect_iframe_src,
+                                         const gchar *expect_iframe_id,
+                                         const gchar *expect_element_id)
+{
+       GetElementFromPoint gefp;
+
+       gefp.fixture = fixture;
+       gefp.expect_iframe_src = expect_iframe_src;
+       gefp.expect_iframe_id = expect_iframe_id;
+       gefp.expect_element_id = expect_element_id;
+
+       e_web_view_jsc_get_element_from_point (fixture->web_view, xx, yy, NULL, 
test_get_element_from_point_ready_cb, &gefp);
+
+       test_utils_wait (fixture);
+}
+
+static void
+window_size_allocated_cb (GtkWidget *widget,
+                         GdkRectangle *allocation,
+                         gpointer user_data)
+{
+       TestFixture *fixture = user_data;
+
+       test_flag_set (fixture->flag);
+}
+
+static void
+test_get_element_from_point (TestFixture *fixture)
+{
+       struct _elems {
+               const gchar *iframe_src;
+               const gchar *iframe_id;
+               const gchar *elem_id;
+       } elems[] = {
+               { NULL, "", "btn1" },
+               { NULL, "", "btn3" },
+               { NULL, "", "dots1" },
+               { "empty:///frm1", "frm1", "btn1" },
+               { "empty:///frm1_1", "frm1_1", "btn1" },
+               { "empty:///frm1_1", "frm1_1", "dots2" },
+               { "empty:///frm1_1", "frm1_1", "btn2" },
+               { "empty:///frm2", "frm2", "btn1" },
+               { "empty:///frm2", "frm2", "btn2" }
+       };
+       gint ii;
+
+       test_utils_load_body (fixture, LOAD_ALL);
+
+       ii = test_utils_jsc_call_int32_sync (fixture,
+               "function TestGetPosition(iframe_id, elem_id)\n"
+               "{\n"
+               "       var elem = Evo.findElement(iframe_id, elem_id);\n"
+               "       var xx = 0, yy = 0, off_elem, check_elem;\n"
+               "       for (check_elem = elem; check_elem; check_elem = 
check_elem.ownerDocument.defaultView.frameElement) {\n"
+               "               for (ii = check_elem; ii; ii = ii.parentOffset) {\n"
+               "                       xx += ii.offsetLeft - ii.scrollLeft;\n"
+               "                       yy += ii.offsetTop - ii.scrollTop;\n"
+               "               }\n"
+               "       }\n"
+               "       var res = [];\n"
+               "       res[\"left\"] = xx + (elem.offsetWidth / 2);\n"
+               "       res[\"top\"] = yy + (elem.offsetHeight / 2);\n"
+               "       return res;"
+               "}\n"
+               "\n"
+               /* To not scroll in the frm1 */
+               "document.getElementById(\"frm1\").height = 
document.getElementById(\"frm1\").contentDocument.getElementById(\"btn1\").offsetTop + "
+               "2 * 
document.getElementById(\"frm1\").contentDocument.getElementById(\"btn1\").offsetHeight;\n"
+               "\n"
+               "document.body.scrollHeight;\n");
+
+       /* To not scroll in the overall document */
+       gtk_widget_set_size_request (fixture->window, -1, ii);
+
+       /* Window/widget resize is done asynchronously, thus wait for it */
+       g_signal_connect (fixture->window, "size-allocate",
+               G_CALLBACK (window_size_allocated_cb), fixture);
+
+       test_utils_wait (fixture);
+
+       g_signal_handlers_disconnect_by_func (fixture->window, G_CALLBACK (window_size_allocated_cb), 
fixture);
+
+       for (ii = 0; ii < G_N_ELEMENTS (elems); ii++) {
+               const gchar *iframe_src;
+               gchar *script;
+               JSCValue *value;
+               gint left, top;
+
+               script = e_web_view_jsc_printf_script ("TestGetPosition(%s, %s);", elems[ii].iframe_id, 
elems[ii].elem_id);
+
+               test_utils_jsc_call_sync (fixture, script, &value);
+
+               g_assert_nonnull (value);
+               g_assert (jsc_value_is_object (value));
+
+               left = e_web_view_jsc_get_object_property_int32 (value, "left", -1);
+               top = e_web_view_jsc_get_object_property_int32 (value, "top", -1);
+
+               g_assert_cmpint (left, >, -1);
+               g_assert_cmpint (top, >, -1);
+
+               g_clear_object (&value);
+               g_free (script);
+
+               iframe_src = elems[ii].iframe_src;
+
+               if (!iframe_src)
+                       iframe_src = webkit_web_view_get_uri (fixture->web_view);
+
+               test_utils_verify_get_element_from_point (fixture, left, top, iframe_src, 
elems[ii].iframe_id, elems[ii].elem_id);
+       }
+
+       test_utils_verify_get_element_from_point (fixture, -1, -1, webkit_web_view_get_uri 
(fixture->web_view), "", "");
+
+       test_utils_jsc_call_sync (fixture, "Evo.findIFrameDocument(\"\").getElementById(\"btn3\").focus();", 
NULL);
+
+       test_utils_verify_get_element_from_point (fixture, -1, -1, webkit_web_view_get_uri 
(fixture->web_view), "", "btn3");
+}
+
 gint
 main (gint argc,
       gchar *argv[])
@@ -1575,6 +1740,7 @@ main (gint argc,
        test_utils_add_test ("/EWebView/NeedInputChanged", test_need_input_changed);
        test_utils_add_test ("/EWebView/Selection", test_selection);
        test_utils_add_test ("/EWebView/GetContent", test_get_content);
+       test_utils_add_test ("/EWebView/GetElementFromPoint", test_get_element_from_point);
 
        res = g_test_run ();
 
diff --git a/src/mail/e-mail-display.c b/src/mail/e-mail-display.c
index b0c4a365bc..9f0b55e9ab 100644
--- a/src/mail/e-mail-display.c
+++ b/src/mail/e-mail-display.c
@@ -1653,37 +1653,32 @@ mail_display_style_updated (GtkWidget *widget)
 }
 
 static gboolean
-mail_display_button_press_event (GtkWidget *widget,
-                                 GdkEventButton *event)
+mail_display_popup_event (EWebView *web_view,
+                         const gchar *uri,
+                         GdkEvent *event)
 {
-       if (event->button == 3) {
-               EWebView *web_view = E_WEB_VIEW (widget);
-               gchar *popup_document_uri;
-               GList *list, *link;
+       gchar *popup_document_uri;
+       GList *list, *link;
 
-               popup_document_uri = e_web_view_get_document_uri_from_point (web_view, event->x, event->y);
+       e_web_view_get_last_popup_place (web_view, &popup_document_uri, NULL, NULL, NULL);
 
-               list = e_extensible_list_extensions (
-                       E_EXTENSIBLE (web_view), E_TYPE_EXTENSION);
-               for (link = list; link != NULL; link = g_list_next (link)) {
-                       EExtension *extension = link->data;
+       list = e_extensible_list_extensions (E_EXTENSIBLE (web_view), E_TYPE_EXTENSION);
 
-                       if (!E_IS_MAIL_DISPLAY_POPUP_EXTENSION (extension))
-                               continue;
+       for (link = list; link; link = g_list_next (link)) {
+               EExtension *extension = link->data;
 
-                       e_mail_display_popup_extension_update_actions (
-                               E_MAIL_DISPLAY_POPUP_EXTENSION (extension), popup_document_uri);
-               }
+               if (!E_IS_MAIL_DISPLAY_POPUP_EXTENSION (extension))
+                       continue;
 
-               g_list_free (list);
-               g_free (popup_document_uri);
+               e_mail_display_popup_extension_update_actions (E_MAIL_DISPLAY_POPUP_EXTENSION (extension), 
popup_document_uri);
        }
 
-       /* Chain up to parent's button_press_event() method. */
-       return GTK_WIDGET_CLASS (e_mail_display_parent_class)->
-               button_press_event (widget, event);
-}
+       g_free (popup_document_uri);
+       g_list_free (list);
 
+       /* Chain up to parent's method. */
+       return E_WEB_VIEW_CLASS (e_mail_display_parent_class)->popup_event (web_view, uri, event);
+}
 
 static gboolean
 mail_display_image_exists_in_cache (const gchar *image_uri)
@@ -2131,11 +2126,11 @@ e_mail_display_class_init (EMailDisplayClass *class)
        widget_class = GTK_WIDGET_CLASS (class);
        widget_class->realize = mail_display_realize;
        widget_class->style_updated = mail_display_style_updated;
-       widget_class->button_press_event = mail_display_button_press_event;
 
        web_view_class = E_WEB_VIEW_CLASS (class);
        web_view_class->suggest_filename = mail_display_suggest_filename;
        web_view_class->set_fonts = mail_display_set_fonts;
+       web_view_class->popup_event = mail_display_popup_event;
 
        g_object_class_install_property (
                object_class,
diff --git a/src/web-extensions/ext-utils.js b/src/web-extensions/ext-utils.js
index 29fd86eb81..7c8b4d5b48 100644
--- a/src/web-extensions/ext-utils.js
+++ b/src/web-extensions/ext-utils.js
@@ -382,9 +382,9 @@ Evo.checkAnyParentIsPre = function(node)
                return false;
 
        while (node = node.parentElement, node) {
-               if (node instanceof HTMLPreElement)
+               if (/* node instanceof HTMLPreElement */ node.tagName.toUpperCase() == "PRE")
                        return true;
-               if (node instanceof HTMLIFrameElement)
+               if (/* node instanceof HTMLIFrameElement */ node.tagName.toUpperCase() == "IFRAME")
                        break;
        }
 
@@ -497,11 +497,76 @@ Evo.GetElementContent = function(iframe_id, element_id, format, use_outer_html)
        return Evo.getElementContent(elem, format, use_outer_html);
 }
 
+Evo.findElementFromPoint = function(doc, xx, yy, parent_elem)
+{
+       var elem;
+
+       if (!parent_elem) {
+               elem = doc.elementFromPoint(xx, yy);
+       } else {
+               var left_offset = 0, top_offset = 0, offset_parent, use_parent;
+
+               for (use_parent = parent_elem; use_parent; use_parent = 
use_parent.ownerDocument.defaultView.window.frameElement) {
+                       offset_parent = use_parent;
+                       do {
+                               left_offset += offset_parent.offsetLeft - offset_parent.scrollLeft;
+                               top_offset += offset_parent.offsetTop - offset_parent.scrollTop;
+
+                               offset_parent = offset_parent.offsetParent;
+                       } while (offset_parent);
+               }
+
+               elem = doc.elementFromPoint(xx - left_offset, yy - top_offset);
+       }
+
+       if (!elem)
+               return parent_elem;
+
+       if (/* !(elem instanceof HTMLIFrameElement) */ elem.tagName.toUpperCase() != "IFRAME") {
+               return elem;
+       }
+
+       if (parent_elem && parent_elem.isEqualNode(elem)) {
+               return parent_elem;
+       }
+
+       var iframedoc = elem.contentDocument;
+
+       if (!iframedoc) {
+               return parent_elem;
+       }
+
+       return Evo.findElementFromPoint(iframedoc, xx, yy, elem);
+}
+
+Evo.GetElementFromPoint = function(xx, yy)
+{
+       var elem;
+
+       if (xx == -1 && yy == -1)
+               elem = document.activeElement;
+       else
+               elem = Evo.findElementFromPoint(document, xx, yy, null);
+
+       if (!elem)
+               return null;
+
+       var res = [], iframe;
+
+       iframe = elem.ownerDocument.defaultView.frameElement;
+
+       res["iframe-src"] = iframe ? iframe.src : document.documentURI;
+       res["iframe-id"] = iframe ? iframe.id : "";
+       res["elem-id"] = elem.id;
+
+       return res;
+}
+
 Evo.Initialize = function(elem)
 {
        var doc, elems, ii;
 
-       if (elem && elem instanceof HTMLIFrameElement && elem.contentDocument)
+       if (elem && /*elem instanceof HTMLIFrameElement*/ elem.tagName.toUpperCase() == "IFRAME" && 
elem.contentDocument)
                doc = elem.contentDocument;
        else
                doc = document;
@@ -544,7 +609,6 @@ Evo.InitializeAndPostContentLoaded = function(elem)
        window.webkit.messageHandlers.contentLoaded.postMessage(iframe_id);
 }
 
-
 if (this instanceof Window && this.document) {
        this.document.onload = function() { Evo.InitializeAndPostContentLoaded(this); };
 


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