[epiphany] embed: Implement unsubmitted modified forms warning in WebKit2



commit 86615e3298fa53736a6a2b722be7d45ecffd36db
Author: Carlos Garcia Campos <cgarcia igalia com>
Date:   Fri Dec 28 17:39:40 2012 +0100

    embed: Implement unsubmitted modified forms warning in WebKit2
    
    Installing a web extension to access the DOM.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=684437

 configure.ac                             |    7 +-
 embed/Makefile.am                        |   15 ++-
 embed/ephy-embed-shell.c                 |   33 ++++++
 embed/ephy-embed-shell.h                 |    3 +
 embed/ephy-web-view.c                    |   20 +++-
 embed/web-extension/Makefile.am          |   20 ++++
 embed/web-extension/ephy-web-extension.c |  169 ++++++++++++++++++++++++++++++
 embed/web-extension/ephy-web-extension.h |   26 +++++
 src/Makefile.am                          |    1 +
 src/ephy-main.c                          |    6 +
 10 files changed, 292 insertions(+), 8 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index aa5fb3b..bb13d62 100644
--- a/configure.ac
+++ b/configure.ac
@@ -83,7 +83,7 @@ GLIB_REQUIRED=2.35.6
 GTK_REQUIRED=3.5.4
 LIBXML_REQUIRED=2.6.12
 LIBXSLT_REQUIRED=1.1.7
-WEBKIT_GTK_REQUIRED=1.11.2
+WEBKIT_GTK_REQUIRED=1.11.5
 LIBSOUP_REQUIRED=2.41.3
 GNOME_DESKTOP_REQUIRED=2.91.2
 GNOME_KEYRING_REQUIRED=2.26.0
@@ -137,6 +137,10 @@ PKG_CHECK_MODULES([DEPENDENCIES], [
                  avahi-client >= $AVAHI_REQUIRED
                  ])
 
+PKG_CHECK_MODULES(WEB_EXTENSION, [$WEBKIT_GTK_PC_NAME >= $WEBKIT_GTK_REQUIRED])
+AC_SUBST(WEB_EXTENSION_CFLAGS)
+AC_SUBST(WEB_EXTENSION_LIBS)
+
 # ******************
 # Portability checks
 # ******************
@@ -255,6 +259,7 @@ lib/egg/Makefile
 lib/history/Makefile
 lib/widgets/Makefile
 embed/Makefile
+embed/web-extension/Makefile
 src/Makefile
 src/bookmarks/Makefile
 po/Makefile.in
diff --git a/embed/Makefile.am b/embed/Makefile.am
index 2df1622..467cc54 100644
--- a/embed/Makefile.am
+++ b/embed/Makefile.am
@@ -1,5 +1,9 @@
 NULL =
 
+if WITH_WEBKIT2
+SUBDIRS = web-extension
+endif
+
 noinst_LTLIBRARIES = libephyembed.la
 
 NOINST_H_FILES = \
@@ -58,11 +62,12 @@ nodist_libephyembed_la_SOURCES = \
        $(BUILT_SOURCES)
 
 libephyembed_la_CPPFLAGS = \
-       -I$(top_builddir)/lib           \
-       -I$(top_srcdir)/lib             \
-       -I$(top_srcdir)/lib/egg         \
-       -I$(top_srcdir)/lib/history     \
-       -I$(top_srcdir)/lib/widgets     \
+       -I$(top_srcdir)/embed/web-extension \
+       -I$(top_builddir)/lib               \
+       -I$(top_srcdir)/lib                 \
+       -I$(top_srcdir)/lib/egg             \
+       -I$(top_srcdir)/lib/history         \
+       -I$(top_srcdir)/lib/widgets         \
        $(AM_CPPFLAGS)
 
 if WITH_WEBKIT2
diff --git a/embed/ephy-embed-shell.c b/embed/ephy-embed-shell.c
index b4366b2..7f48f7c 100644
--- a/embed/ephy-embed-shell.c
+++ b/embed/ephy-embed-shell.c
@@ -33,6 +33,9 @@
 #include "ephy-history-service.h"
 #include "ephy-profile-utils.h"
 #include "ephy-snapshot-service.h"
+#ifdef HAVE_WEBKIT2
+#include "ephy-web-extension.h"
+#endif
 
 #include <glib/gi18n.h>
 #include <gtk/gtk.h>
@@ -55,6 +58,9 @@ struct _EphyEmbedShellPrivate
   EphyEmbedShellMode mode;
   EphyFrecentStore *frecent_store;
   guint single_initialised : 1;
+#ifdef HAVE_WEBKIT2
+  GDBusProxy *web_extension;
+#endif
 };
 
 enum
@@ -93,6 +99,9 @@ ephy_embed_shell_dispose (GObject *object)
   g_clear_object (&priv->global_history_service);
   g_clear_object (&priv->embed_single);
   g_clear_object (&priv->adblock_manager);
+#ifdef HAVE_WEBKIT2
+  g_clear_object (&priv->web_extension);
+#endif
 
   G_OBJECT_CLASS (ephy_embed_shell_parent_class)->dispose (object);
 }
@@ -677,3 +686,27 @@ ephy_embed_shell_launch_handler (EphyEmbedShell *shell,
 
   return ret;
 }
+
+#ifdef HAVE_WEBKIT2
+GDBusProxy *
+ephy_embed_shell_get_web_extension_proxy (EphyEmbedShell *shell)
+{
+  EphyEmbedShellPrivate *priv;
+
+  g_return_val_if_fail (EPHY_IS_EMBED_SHELL (shell), NULL);
+
+  priv = shell->priv;
+  if (!priv->web_extension) {
+    priv->web_extension = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
+                                                         G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
+                                                         NULL,
+                                                         EPHY_WEB_EXTENSION_SERVICE_NAME,
+                                                         EPHY_WEB_EXTENSION_OBJECT_PATH,
+                                                         EPHY_WEB_EXTENSION_INTERFACE,
+                                                         NULL,
+                                                         NULL);
+  }
+
+  return priv->web_extension;
+}
+#endif
diff --git a/embed/ephy-embed-shell.h b/embed/ephy-embed-shell.h
index 45261e9..85e7df5 100644
--- a/embed/ephy-embed-shell.h
+++ b/embed/ephy-embed-shell.h
@@ -102,6 +102,9 @@ gboolean           ephy_embed_shell_launch_handler             (EphyEmbedShell
                                                                 GFile            *file,
                                                                 const char       *mime_type,
                                                                 guint32           user_time);
+#ifdef HAVE_WEBKIT2
+GDBusProxy        *ephy_embed_shell_get_web_extension_proxy    (EphyEmbedShell   *shell);
+#endif
 
 G_END_DECLS
 
diff --git a/embed/ephy-web-view.c b/embed/ephy-web-view.c
index e653580..eced9f1 100644
--- a/embed/ephy-web-view.c
+++ b/embed/ephy-web-view.c
@@ -3417,7 +3417,23 @@ gboolean
 ephy_web_view_has_modified_forms (EphyWebView *view)
 {
 #ifdef HAVE_WEBKIT2
-  /* TODO: DOM Bindings */
+  GVariant *result;
+  gboolean retval = FALSE;
+
+  /* FIXME: This should be async */
+  result = g_dbus_proxy_call_sync (ephy_embed_shell_get_web_extension_proxy (ephy_embed_shell_get_default 
()),
+                                   "HasModifiedForms",
+                                   g_variant_new("(t)", webkit_web_view_get_page_id (WEBKIT_WEB_VIEW 
(view))),
+                                   G_DBUS_CALL_FLAGS_NONE,
+                                   -1,
+                                   NULL,
+                                   NULL);
+
+
+  g_variant_get (result, "(b)", &retval);
+  g_variant_unref (result);
+
+  return retval;
 #else
   WebKitDOMHTMLCollection *forms = NULL;
   WebKitDOMDocument *document = NULL;
@@ -3472,8 +3488,8 @@ ephy_web_view_has_modified_forms (EphyWebView *view)
         }
     }
   }
-#endif
   return FALSE;
+#endif
 }
 
 /**
diff --git a/embed/web-extension/Makefile.am b/embed/web-extension/Makefile.am
new file mode 100644
index 0000000..fe72772
--- /dev/null
+++ b/embed/web-extension/Makefile.am
@@ -0,0 +1,20 @@
+webextension_LTLIBRARIES = libephywebextension.la
+
+webextensiondir = \
+       $(libdir)/epiphany/$(EPIPHANY_MAJOR)/web-extensions
+
+libephywebextension_la_SOURCES = \
+       ephy-web-extension.c \
+       ephy-web-extension.h
+
+libephywebextension_la_CPPFLAG = \
+       $(AM_CPPFLAGS)
+
+libephywebextension_la_CFLAGS = \
+       $(WEB_EXTENSION_CFLAGS)
+
+libephywebextension_la_LIBADD = \
+       $(WEB_EXTENSION_LIBS)
+
+libephywebextension_la_LDFLAGS = \
+       -module -avoid-version -no-undefined
diff --git a/embed/web-extension/ephy-web-extension.c b/embed/web-extension/ephy-web-extension.c
new file mode 100644
index 0000000..1650026
--- /dev/null
+++ b/embed/web-extension/ephy-web-extension.c
@@ -0,0 +1,169 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ *  Copyright © 2012 Igalia S.L.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "ephy-web-extension.h"
+
+#include <gio/gio.h>
+#include <webkit2/webkit-web-extension.h>
+
+static const char introspection_xml[] =
+  "<node>"
+  " <interface name='org.gnome.Epiphany.WebExtension'>"
+  "  <method name='HasModifiedForms'>"
+  "   <arg type='t' name='page_id' direction='in'/>"
+  "   <arg type='b' name='has_modified_forms' direction='out'/>"
+  "  </method>"
+  " </interface>"
+  "</node>";
+
+#define MIN_INPUT_LENGTH 50
+
+static gboolean
+ephy_web_extension_page_has_modified_forms (WebKitWebPage *web_page)
+{
+  WebKitDOMHTMLCollection *forms = NULL;
+  WebKitDOMDocument *document = NULL;
+  gulong forms_n;
+  int i;
+
+  document = webkit_web_page_get_dom_document (web_page);
+  forms = webkit_dom_document_get_forms (document);
+  forms_n = webkit_dom_html_collection_get_length (forms);
+
+  for (i = 0; i < forms_n; i++) {
+    WebKitDOMHTMLCollection *elements;
+    WebKitDOMNode *form_element = webkit_dom_html_collection_item (forms, i);
+    gulong elements_n;
+    int j;
+    gboolean modified_input_element = FALSE;
+
+    elements = webkit_dom_html_form_element_get_elements (WEBKIT_DOM_HTML_FORM_ELEMENT (form_element));
+    elements_n = webkit_dom_html_collection_get_length (elements);
+
+    for (j = 0; j < elements_n; j++) {
+      WebKitDOMNode *element;
+
+      element = webkit_dom_html_collection_item (elements, j);
+
+      if (WEBKIT_DOM_IS_HTML_TEXT_AREA_ELEMENT (element))
+        if (webkit_dom_html_text_area_element_is_edited (WEBKIT_DOM_HTML_TEXT_AREA_ELEMENT (element)))
+          return TRUE;
+
+      if (WEBKIT_DOM_IS_HTML_INPUT_ELEMENT (element))
+        if (webkit_dom_html_input_element_is_edited (WEBKIT_DOM_HTML_INPUT_ELEMENT (element))) {
+          glong length;
+          char *text;
+
+          /* A small heuristic here. If there's only one input element
+           * modified and it does not have a lot of text the user is
+           * likely not very interested in saving this work, so do
+           * nothing (eg, google search input). */
+          if (modified_input_element)
+            return TRUE;
+
+          modified_input_element = TRUE;
+
+          text = webkit_dom_html_input_element_get_value (WEBKIT_DOM_HTML_INPUT_ELEMENT (element));
+          length = g_utf8_strlen (text, -1);
+          g_free (text);
+
+          if (length > MIN_INPUT_LENGTH)
+            return TRUE;
+        }
+    }
+  }
+
+  return FALSE;
+}
+
+static void
+handle_method_call (GDBusConnection *connection,
+                    const char *sender,
+                    const char *object_path,
+                    const char *interface_name,
+                    const char *method_name,
+                    GVariant *parameters,
+                    GDBusMethodInvocation *invocation,
+                    gpointer user_data)
+{
+  WebKitWebExtension *web_extension = WEBKIT_WEB_EXTENSION (user_data);
+  WebKitWebPage *web_page;
+  guint64 page_id;
+
+  if (g_strcmp0 (interface_name, EPHY_WEB_EXTENSION_INTERFACE) != 0)
+    return;
+
+  g_variant_get(parameters, "(t)", &page_id);
+  web_page = webkit_web_extension_get_page (web_extension, page_id);
+  if (!web_page) {
+    g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+                                           "Invalid page ID: %"G_GUINT64_FORMAT, page_id);
+    return;
+  }
+
+  if (g_strcmp0 (method_name, "HasModifiedForms") == 0) {
+    gboolean has_modifed_forms;
+
+    has_modifed_forms = ephy_web_extension_page_has_modified_forms (web_page);
+    g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", has_modifed_forms));
+  }
+}
+
+static const GDBusInterfaceVTable interface_vtable = {
+  handle_method_call,
+  NULL,
+  NULL
+};
+
+static void
+bus_acquired_cb (GDBusConnection *connection,
+                 const char *name,
+                 gpointer user_data)
+{
+  guint registration_id;
+  GError *error = NULL;
+  static GDBusNodeInfo *introspection_data = NULL;
+  if (!introspection_data)
+    introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
+
+  registration_id = g_dbus_connection_register_object (connection,
+                                                       EPHY_WEB_EXTENSION_OBJECT_PATH,
+                                                       introspection_data->interfaces[0],
+                                                       &interface_vtable,
+                                                       g_object_ref (user_data),
+                                                       (GDestroyNotify)g_object_unref,
+                                                       &error);
+  if (!registration_id) {
+    g_warning ("Failed to register object: %s\n", error->message);
+    g_error_free (error);
+  }
+}
+
+G_MODULE_EXPORT void
+webkit_web_extension_initialize (WebKitWebExtension *extension)
+{
+  g_bus_own_name (G_BUS_TYPE_SESSION,
+                  EPHY_WEB_EXTENSION_SERVICE_NAME,
+                  G_BUS_NAME_OWNER_FLAGS_NONE,
+                  bus_acquired_cb,
+                  NULL, NULL,
+                  g_object_ref (extension),
+                  (GDestroyNotify)g_object_unref);
+}
diff --git a/embed/web-extension/ephy-web-extension.h b/embed/web-extension/ephy-web-extension.h
new file mode 100644
index 0000000..7792480
--- /dev/null
+++ b/embed/web-extension/ephy-web-extension.h
@@ -0,0 +1,26 @@
+/*
+ *  Copyright © 2012 Igalia S.L.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef EPHY_WEB_EXTENSION_H
+#define EPHY_WEB_EXTENSION_H
+
+#define EPHY_WEB_EXTENSION_SERVICE_NAME "org.gnome.Epiphany.WebExtension"
+#define EPHY_WEB_EXTENSION_OBJECT_PATH  "/org/gnome/Epiphany/WebExtension"
+#define EPHY_WEB_EXTENSION_INTERFACE    "org.gnome.Epiphany.WebExtension"
+
+#endif /* EPHY_WEB_EXTENSION_H */
diff --git a/src/Makefile.am b/src/Makefile.am
index 910851b..a901b8b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -140,6 +140,7 @@ epiphany_CPPFLAGS = \
        -I$(top_srcdir)/src/bookmarks   \
        -DDATADIR=\""$(datadir)"\"      \
        -DGNOMELOCALEDIR=\"$(datadir)/locale\"  \
+       -DEPHY_WEB_EXTENSIONS_DIR=\""$(libdir)/epiphany/$(EPIPHANY_MAJOR)/web-extensions"\" \
        $(INCINTL)                      \
        $(AM_CPPFLAGS)
 
diff --git a/src/ephy-main.c b/src/ephy-main.c
index 3a464e4..7c38fd9 100644
--- a/src/ephy-main.c
+++ b/src/ephy-main.c
@@ -458,6 +458,12 @@ main (int argc,
     gtk_window_set_default_icon_name ("web-browser");
   }
 
+#ifdef HAVE_WEBKIT2
+  /* Set the web extensions dir ASAP before the process is launched */
+  webkit_web_context_set_web_extensions_directory (webkit_web_context_get_default (),
+                                                   EPHY_WEB_EXTENSIONS_DIR);
+#endif
+
   ephy_embed_prefs_init ();
   _ephy_shell_create_instance (mode);
 


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