[epiphany] Add support for using multiple web processes



commit 31bc1fe6ccbe53dfd14822d44fc9563a32799316
Author: Carlos Garcia Campos <cgarcia igalia com>
Date:   Thu Jan 30 17:02:05 2014 +0100

    Add support for using multiple web processes
    
    There's now a setting to set the process model.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=723302

 data/org.gnome.epiphany.gschema.xml      |    5 +
 embed/Makefile.am                        |    4 +-
 embed/ephy-embed-shell.c                 |  237 +++++++++++-------
 embed/ephy-embed-shell.h                 |    1 -
 embed/ephy-web-extension-proxy.c         |  400 ++++++++++++++++++++++++++++++
 embed/ephy-web-extension-proxy.h         |  100 ++++++++
 embed/ephy-web-view.c                    |  249 +++++++++++++++----
 embed/ephy-web-view.h                    |   17 ++
 embed/web-extension/ephy-web-extension.c |   64 +++++-
 lib/ephy-prefs.h                         |    7 +
 src/window-commands.c                    |   98 +-------
 11 files changed, 957 insertions(+), 225 deletions(-)
---
diff --git a/data/org.gnome.epiphany.gschema.xml b/data/org.gnome.epiphany.gschema.xml
index f03cfef..af140a7 100644
--- a/data/org.gnome.epiphany.gschema.xml
+++ b/data/org.gnome.epiphany.gschema.xml
@@ -66,6 +66,11 @@
                         <summary>Whether to delay loading of tabs that are not immediately visible on 
session restore</summary>
                         <description>When this option is set to true, tabs will not start loading until the 
user switches to them, upon session restore.</description>
                 </key>
+                <key name="process-model" enum="org.gnome.Epiphany.EphyPrefsProcessModel">
+                        <default>'shared-secondary-process'</default>
+                        <summary>Process model</summary>
+                        <description>This option allows to set the process model used. Use 
'shared-secondary-process' to use a single web process shared by all the tabs and 
'one-secondary-process-per-web-view' to use a different web process for each tab.</description>
+                </key>
        </schema>
        <schema path="/org/gnome/epiphany/ui/" id="org.gnome.Epiphany.ui">
                <key name="toolbar-style" enum="org.gnome.Epiphany.EphyPrefsUIToolbarStyle">
diff --git a/embed/Makefile.am b/embed/Makefile.am
index 5f6fec3..4e79e2e 100644
--- a/embed/Makefile.am
+++ b/embed/Makefile.am
@@ -22,7 +22,8 @@ INST_H_FILES = \
        ephy-embed-utils.h              \
        ephy-find-toolbar.h             \
        ephy-overview.h                 \
-       ephy-web-view.h
+       ephy-web-view.h                 \
+       ephy-web-extension-proxy.h
 
 
 BUILT_SOURCES = \
@@ -45,6 +46,7 @@ libephyembed_la_SOURCES = \
        ephy-overview.c                 \
        ephy-embed-prefs.c              \
        ephy-web-view.c                 \
+       ephy-web-extension-proxy.c      \
        $(INST_H_FILES)                 \
        $(NOINST_H_FILES)
 
diff --git a/embed/ephy-embed-shell.c b/embed/ephy-embed-shell.c
index 67dbcea..42e967f 100644
--- a/embed/ephy-embed-shell.c
+++ b/embed/ephy-embed-shell.c
@@ -34,6 +34,7 @@
 #include "ephy-settings.h"
 #include "ephy-snapshot-service.h"
 #include "ephy-web-extension.h"
+#include "ephy-web-extension-proxy.h"
 
 #include <glib/gi18n.h>
 #include <gtk/gtk.h>
@@ -53,9 +54,10 @@ struct _EphyEmbedShellPrivate
   EphyEmbedShellMode mode;
   EphyFrecentStore *frecent_store;
   EphyAboutHandler *about_handler;
-  GDBusProxy *web_extension;
-  guint web_extension_watch_name_id;
-  guint web_extension_form_auth_save_signal_id;
+  GDBusConnection *bus;
+  GList *web_extensions;
+  guint web_extensions_page_created_signal_id;
+  guint web_extensions_form_auth_save_signal_id;
 };
 
 enum
@@ -63,7 +65,7 @@ enum
   PREPARE_CLOSE,
   RESTORED_WINDOW,
   WEB_VIEW_CREATED,
-  FORM_AUTH_DATA_SAVE_REQUESTED,
+  PAGE_CREATED,
 
   LAST_SIGNAL
 };
@@ -98,6 +100,24 @@ ephy_embed_shell_dispose (GObject *object)
   G_OBJECT_CLASS (ephy_embed_shell_parent_class)->dispose (object);
 }
 
+static gint
+web_extension_compare (EphyWebExtensionProxy *proxy,
+                       const char *name_owner)
+{
+  return g_strcmp0 (ephy_web_extension_proxy_get_name_owner (proxy), name_owner);
+}
+
+static EphyWebExtensionProxy *
+ephy_embed_shell_find_web_extension (EphyEmbedShell *shell,
+                                     const char *name_owner)
+{
+  GList *l;
+
+  l = g_list_find_custom (shell->priv->web_extensions, name_owner, (GCompareFunc)web_extension_compare);
+
+  return l ? EPHY_WEB_EXTENSION_PROXY (l->data) : NULL;
+}
+
 static void
 web_extension_form_auth_save_requested (GDBusConnection *connection,
                                         const char *sender_name,
@@ -107,85 +127,70 @@ web_extension_form_auth_save_requested (GDBusConnection *connection,
                                         GVariant *parameters,
                                         EphyEmbedShell *shell)
 {
+  EphyWebExtensionProxy *web_extension;
   guint request_id;
   guint64 page_id;
   const char *hostname;
   const char *username;
 
   g_variant_get (parameters, "(ut&s&s)", &request_id, &page_id, &hostname, &username);
-  g_signal_emit (shell, signals[FORM_AUTH_DATA_SAVE_REQUESTED], 0,
-                 request_id, page_id, hostname, username);
+  web_extension = ephy_embed_shell_find_web_extension (shell, sender_name);
+  if (!web_extension)
+    return;
+  ephy_web_extension_proxy_form_auth_save_requested (web_extension, request_id, page_id, hostname, username);
 }
 
 static void
-web_extension_proxy_created_cb (GDBusProxy *proxy,
-                                GAsyncResult *result,
-                                EphyEmbedShell *shell)
-{
-  GError *error = NULL;
+web_extension_page_created (GDBusConnection *connection,
+                            const char *sender_name,
+                            const char *object_path,
+                            const char *interface_name,
+                            const char *signal_name,
+                            GVariant *parameters,
+                            EphyEmbedShell *shell)
+{
+  EphyWebExtensionProxy *web_extension;
+  guint64 page_id;
 
-  shell->priv->web_extension = g_dbus_proxy_new_finish (result, &error);
-  if (!shell->priv->web_extension) {
-    g_warning ("Error creating web extension proxy: %s\n", error->message);
-    g_error_free (error);
-  } else {
-    shell->priv->web_extension_form_auth_save_signal_id =
-      g_dbus_connection_signal_subscribe (g_dbus_proxy_get_connection (shell->priv->web_extension),
-                                          g_dbus_proxy_get_name (shell->priv->web_extension),
-                                          EPHY_WEB_EXTENSION_INTERFACE,
-                                         "FormAuthDataSaveConfirmationRequired",
-                                          EPHY_WEB_EXTENSION_OBJECT_PATH,
-                                          NULL,
-                                          G_DBUS_SIGNAL_FLAGS_NONE,
-                                          (GDBusSignalCallback)web_extension_form_auth_save_requested,
-                                          shell,
-                                          NULL);
-  }
-}
+  g_variant_get (parameters, "(t)", &page_id);
 
-static void
-web_extension_appeared_cb (GDBusConnection *connection,
-                           const gchar *name,
-                           const gchar *name_owner,
-                           EphyEmbedShell *shell)
-{
-  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,
-                    EPHY_WEB_EXTENSION_OBJECT_PATH,
-                    EPHY_WEB_EXTENSION_INTERFACE,
-                    NULL,
-                    (GAsyncReadyCallback)web_extension_proxy_created_cb,
-                    shell);
+  web_extension = ephy_embed_shell_find_web_extension (shell, sender_name);
+  if (!web_extension)
+    return;
+  g_signal_emit (shell, signals[PAGE_CREATED], 0, page_id, web_extension);
 }
 
 static void
-web_extension_vanished_cb (GDBusConnection *connection,
-                           const gchar *name,
-                           EphyEmbedShell *shell)
+web_extension_destroyed (EphyEmbedShell *shell,
+                         GObject *web_extension)
 {
-  g_clear_object (&shell->priv->web_extension);
+  shell->priv->web_extensions = g_list_remove (shell->priv->web_extensions, web_extension);
 }
 
 static void
-ephy_embed_shell_watch_web_extension (EphyEmbedShell *shell)
+ephy_embed_shell_watch_web_extension (EphyEmbedShell *shell,
+                                      const char *web_extension_id)
 {
+  EphyWebExtensionProxy *web_extension;
   char *service_name;
 
-  service_name = g_strdup_printf ("%s-%u", EPHY_WEB_EXTENSION_SERVICE_NAME, getpid ());
-  shell->priv->web_extension_watch_name_id =
-    g_bus_watch_name (G_BUS_TYPE_SESSION,
-                      service_name,
-                      G_BUS_NAME_WATCHER_FLAGS_NONE,
-                      (GBusNameAppearedCallback) web_extension_appeared_cb,
-                      (GBusNameVanishedCallback) web_extension_vanished_cb,
-                      shell, NULL);
+  if (!shell->priv->bus)
+    return;
+
+  service_name = g_strdup_printf ("%s-%s", EPHY_WEB_EXTENSION_SERVICE_NAME, web_extension_id);
+  web_extension = ephy_web_extension_proxy_new (shell->priv->bus, service_name);
+  shell->priv->web_extensions = g_list_prepend (shell->priv->web_extensions, web_extension);
+  g_object_weak_ref (G_OBJECT (web_extension), (GWeakNotify)web_extension_destroyed, shell);
   g_free (service_name);
 }
 
+static void
+ephy_embed_shell_unwatch_web_extension (EphyWebExtensionProxy *web_extension,
+                                        EphyEmbedShell *shell)
+{
+  g_object_weak_unref (G_OBJECT (web_extension), (GWeakNotify)web_extension_destroyed, shell);
+}
+
 /**
  * ephy_embed_shell_get_global_history_service:
  * @shell: the #EphyEmbedShell
@@ -304,16 +309,73 @@ initialize_web_extensions (WebKitWebContext* web_context,
 {
   GVariant *user_data;
   gboolean private_profile;
+  char *web_extension_id;
+  static guint web_extension_count = 0;
 
   webkit_web_context_set_web_extensions_directory (web_context, EPHY_WEB_EXTENSIONS_DIR);
-  ephy_embed_shell_watch_web_extension (shell);
+
+  web_extension_id = g_strdup_printf ("%u-%u", getpid (), ++web_extension_count);
+  ephy_embed_shell_watch_web_extension (shell, web_extension_id);
 
   private_profile = EPHY_EMBED_SHELL_MODE_HAS_PRIVATE_PROFILE (shell->priv->mode);
-  user_data = g_variant_new ("(usb)", getpid (), ephy_dot_dir (), private_profile);
+  user_data = g_variant_new ("(ssb)", web_extension_id, ephy_dot_dir (), private_profile);
   webkit_web_context_set_web_extensions_initialization_user_data (web_context, user_data);
 }
 
 static void
+ephy_embed_shell_setup_web_extensions_connection (EphyEmbedShell *shell)
+{
+  GError *error = NULL;
+
+  shell->priv->bus = g_application_get_dbus_connection (G_APPLICATION (shell));
+  if (!shell->priv->bus) {
+    g_warning ("Application not connected to session bus: %s\n", error->message);
+    g_error_free (error);
+    return;
+  }
+
+  shell->priv->web_extensions_page_created_signal_id =
+    g_dbus_connection_signal_subscribe (shell->priv->bus,
+                                        NULL,
+                                        EPHY_WEB_EXTENSION_INTERFACE,
+                                        "PageCreated",
+                                        EPHY_WEB_EXTENSION_OBJECT_PATH,
+                                        NULL,
+                                        G_DBUS_SIGNAL_FLAGS_NONE,
+                                        (GDBusSignalCallback)web_extension_page_created,
+                                        shell,
+                                        NULL);
+  shell->priv->web_extensions_form_auth_save_signal_id =
+    g_dbus_connection_signal_subscribe (shell->priv->bus,
+                                        NULL,
+                                        EPHY_WEB_EXTENSION_INTERFACE,
+                                        "FormAuthDataSaveConfirmationRequired",
+                                        EPHY_WEB_EXTENSION_OBJECT_PATH,
+                                        NULL,
+                                        G_DBUS_SIGNAL_FLAGS_NONE,
+                                        (GDBusSignalCallback)web_extension_form_auth_save_requested,
+                                        shell,
+                                        NULL);
+}
+
+static void
+ephy_embed_shell_setup_process_model (EphyEmbedShell *shell,
+                                      WebKitWebContext *web_context)
+{
+  EphyPrefsProcessModel process_model;
+
+  process_model = g_settings_get_enum (EPHY_SETTINGS_MAIN, EPHY_PREFS_PROCESS_MODEL);
+  switch (process_model) {
+  case EPHY_PREFS_PROCESS_MODEL_SHARED_SECONDARY_PROCESS:
+    webkit_web_context_set_process_model (web_context, WEBKIT_PROCESS_MODEL_SHARED_SECONDARY_PROCESS);
+    break;
+  case EPHY_PREFS_PROCESS_MODEL_ONE_SECONDARY_PROCESS_PER_WEB_VIEW:
+    webkit_web_context_set_process_model (web_context, 
WEBKIT_PROCESS_MODEL_ONE_SECONDARY_PROCESS_PER_WEB_VIEW);
+    break;
+  }
+}
+
+static void
 ephy_embed_shell_startup (GApplication* application)
 {
   EphyEmbedShell *shell = EPHY_EMBED_SHELL (application);
@@ -328,7 +390,11 @@ ephy_embed_shell_startup (GApplication* application)
 
   /* We're not remoting, setup the Web Context. */
   mode = shell->priv->mode;
+
+  ephy_embed_shell_setup_web_extensions_connection (shell);
+
   web_context = webkit_web_context_get_default ();
+  ephy_embed_shell_setup_process_model (shell, web_context);
   g_signal_connect (web_context, "initialize-web-extensions",
                     G_CALLBACK (initialize_web_extensions),
                     shell);
@@ -369,18 +435,17 @@ ephy_embed_shell_shutdown (GApplication* application)
 
   G_APPLICATION_CLASS (ephy_embed_shell_parent_class)->shutdown (application);
 
-  if (priv->web_extension_watch_name_id > 0) {
-    g_bus_unwatch_name (priv->web_extension_watch_name_id);
-    priv->web_extension_watch_name_id = 0;
+  if (priv->web_extensions_page_created_signal_id > 0) {
+    g_dbus_connection_signal_unsubscribe (priv->bus, priv->web_extensions_page_created_signal_id);
+    priv->web_extensions_page_created_signal_id = 0;
   }
 
-  if (priv->web_extension_form_auth_save_signal_id > 0) {
-    g_dbus_connection_signal_unsubscribe (g_dbus_proxy_get_connection (priv->web_extension),
-                                          priv->web_extension_form_auth_save_signal_id);
-    priv->web_extension_form_auth_save_signal_id = 0;
+  if (priv->web_extensions_form_auth_save_signal_id > 0) {
+    g_dbus_connection_signal_unsubscribe (priv->bus, priv->web_extensions_form_auth_save_signal_id);
+    priv->web_extensions_form_auth_save_signal_id = 0;
   }
 
-  g_clear_object (&priv->web_extension);
+  g_list_foreach (priv->web_extensions, (GFunc)ephy_embed_shell_unwatch_web_extension, application);
 
   ephy_embed_prefs_shutdown ();
 }
@@ -507,29 +572,23 @@ ephy_embed_shell_class_init (EphyEmbedShellClass *klass)
                   G_TYPE_NONE, 1,
                   EPHY_TYPE_WEB_VIEW);
 
-  /*
-   * EphyEmbedShell::form-auth-data-save-requested:
+  /**
+   * EphyEmbedShell::page-created:
    * @shell: the #EphyEmbedShell
-   * @request_id: the identifier of the request
-   * @page_id: the identifier of the web page
-   * @hostname: the hostname
-   * @username: the username
+   * @page_id: the identifier of the web page created
+   * @web_extension: the #EphyWebExtensionProxy
    *
-   * Emitted when a web page requests confirmation to save
-   * the form authentication data for the given @hostname and
-   * @username
-   **/
-  signals[FORM_AUTH_DATA_SAVE_REQUESTED] =
-    g_signal_new ("form-auth-data-save-requested",
+   * Emitted when a web page is created in the web process.
+   */
+  signals[PAGE_CREATED] =
+    g_signal_new ("page-created",
                   EPHY_TYPE_EMBED_SHELL,
                   G_SIGNAL_RUN_FIRST,
                   0, NULL, NULL,
                   g_cclosure_marshal_generic,
-                  G_TYPE_NONE, 4,
-                  G_TYPE_UINT,
+                  G_TYPE_NONE, 2,
                   G_TYPE_UINT64,
-                  G_TYPE_STRING,
-                  G_TYPE_STRING);
+                  EPHY_TYPE_WEB_EXTENSION_PROXY);
 
   g_type_class_add_private (object_class, sizeof (EphyEmbedShellPrivate));
 }
@@ -728,14 +787,6 @@ ephy_embed_shell_launch_handler (EphyEmbedShell *shell,
   return ret;
 }
 
-GDBusProxy *
-ephy_embed_shell_get_web_extension_proxy (EphyEmbedShell *shell)
-{
-  g_return_val_if_fail (EPHY_IS_EMBED_SHELL (shell), NULL);
-
-  return shell->priv->web_extension;
-}
-
 /**
  * ephy_embed_shell_clear_cache:
  * @shell: an #EphyEmbedShell
diff --git a/embed/ephy-embed-shell.h b/embed/ephy-embed-shell.h
index 02016c8..f488640 100644
--- a/embed/ephy-embed-shell.h
+++ b/embed/ephy-embed-shell.h
@@ -89,7 +89,6 @@ gboolean           ephy_embed_shell_launch_handler             (EphyEmbedShell
                                                                 const char       *mime_type,
                                                                 guint32           user_time);
 void               ephy_embed_shell_clear_cache                (EphyEmbedShell *shell);
-GDBusProxy        *ephy_embed_shell_get_web_extension_proxy    (EphyEmbedShell   *shell);
 
 G_END_DECLS
 
diff --git a/embed/ephy-web-extension-proxy.c b/embed/ephy-web-extension-proxy.c
new file mode 100644
index 0000000..dc67723
--- /dev/null
+++ b/embed/ephy-web-extension-proxy.c
@@ -0,0 +1,400 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ *  Copyright © 2014 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-proxy.h"
+
+#include "ephy-web-extension.h"
+
+struct _EphyWebExtensionProxyPrivate
+{
+  GDBusProxy *proxy;
+  gchar *name_owner;
+  guint watch_name_id;
+  guint form_auth_save_signal_id;
+};
+
+enum
+{
+  FORM_AUTH_DATA_SAVE_REQUESTED,
+
+  LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+G_DEFINE_TYPE (EphyWebExtensionProxy, ephy_web_extension_proxy, G_TYPE_OBJECT)
+
+static void
+ephy_web_extension_proxy_finalize (GObject *object)
+{
+  EphyWebExtensionProxyPrivate *priv = EPHY_WEB_EXTENSION_PROXY (object)->priv;
+
+  g_clear_object (&priv->proxy);
+
+  G_OBJECT_CLASS (ephy_web_extension_proxy_parent_class)->finalize (object);
+}
+
+static void
+ephy_web_extension_proxy_dispose (GObject *object)
+{
+  EphyWebExtensionProxyPrivate *priv = EPHY_WEB_EXTENSION_PROXY (object)->priv;
+
+  if (priv->watch_name_id > 0) {
+    g_bus_unwatch_name (priv->watch_name_id);
+    priv->watch_name_id = 0;
+  }
+
+  g_clear_pointer (&priv->name_owner, g_free);
+
+  G_OBJECT_CLASS (ephy_web_extension_proxy_parent_class)->dispose (object);
+}
+
+static void
+ephy_web_extension_proxy_init (EphyWebExtensionProxy *web_extension)
+{
+  web_extension->priv = G_TYPE_INSTANCE_GET_PRIVATE (web_extension, EPHY_TYPE_WEB_EXTENSION_PROXY, 
EphyWebExtensionProxyPrivate);
+}
+
+static void
+ephy_web_extension_proxy_class_init (EphyWebExtensionProxyClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = ephy_web_extension_proxy_finalize;
+  object_class->dispose = ephy_web_extension_proxy_dispose;
+
+  /**
+   * EphyWebExtensionProxy::form-auth-data-save-requested:
+   * @web_extension: the #EphyWebExtensionProxy
+   * @request_id: the identifier of the request
+   * @page_id: the identifier of the web page
+   * @hostname: the hostname
+   * @username: the username
+   *
+   * Emitted when a web page requests confirmation to save
+   * the form authentication data for the given @hostname and
+   * @username
+   **/
+  signals[FORM_AUTH_DATA_SAVE_REQUESTED] =
+    g_signal_new ("form-auth-data-save-requested",
+                  EPHY_TYPE_WEB_EXTENSION_PROXY,
+                  G_SIGNAL_RUN_FIRST,
+                  0, NULL, NULL,
+                  g_cclosure_marshal_generic,
+                  G_TYPE_NONE, 4,
+                  G_TYPE_UINT,
+                  G_TYPE_UINT64,
+                  G_TYPE_STRING,
+                  G_TYPE_STRING);
+
+  g_type_class_add_private (object_class, sizeof (EphyWebExtensionProxyPrivate));
+}
+
+static void
+web_extension_proxy_created_cb (GDBusProxy *proxy,
+                                GAsyncResult *result,
+                                EphyWebExtensionProxy *web_extension)
+{
+  GError *error = NULL;
+
+  web_extension->priv->proxy = g_dbus_proxy_new_finish (result, &error);
+  if (!web_extension->priv->proxy) {
+    g_warning ("Error creating web extension proxy: %s\n", error->message);
+    g_error_free (error);
+  }
+}
+
+static void
+web_extension_appeared_cb (GDBusConnection *connection,
+                           const gchar *name,
+                           const gchar *name_owner,
+                           EphyWebExtensionProxy *web_extension)
+{
+  web_extension->priv->name_owner = g_strdup (name_owner);
+  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,
+                    EPHY_WEB_EXTENSION_OBJECT_PATH,
+                    EPHY_WEB_EXTENSION_INTERFACE,
+                    NULL,
+                    (GAsyncReadyCallback)web_extension_proxy_created_cb,
+                    web_extension);
+}
+
+static void
+ephy_web_extension_proxy_watch_name (EphyWebExtensionProxy *web_extension,
+                                     GDBusConnection* bus,
+                                     const char *service_name)
+{
+  EphyWebExtensionProxyPrivate *priv = web_extension->priv;
+
+  priv->watch_name_id =
+    g_bus_watch_name_on_connection (bus,
+                                    service_name,
+                                    G_BUS_NAME_WATCHER_FLAGS_NONE,
+                                    (GBusNameAppearedCallback)web_extension_appeared_cb,
+                                    NULL,
+                                    web_extension,
+                                    (GDestroyNotify)g_object_unref);
+}
+
+EphyWebExtensionProxy *
+ephy_web_extension_proxy_new (GDBusConnection *bus,
+                              const char *service_name)
+{
+  EphyWebExtensionProxy *web_extension;
+
+  g_return_val_if_fail (G_IS_DBUS_CONNECTION (bus), NULL);
+  g_return_val_if_fail (service_name != NULL, NULL);
+
+  web_extension = g_object_new (EPHY_TYPE_WEB_EXTENSION_PROXY, NULL);
+  ephy_web_extension_proxy_watch_name (web_extension, bus, service_name);
+
+  return web_extension;
+}
+
+const char *
+ephy_web_extension_proxy_get_name_owner (EphyWebExtensionProxy *web_extension)
+{
+  g_return_val_if_fail (EPHY_IS_WEB_EXTENSION_PROXY (web_extension), NULL);
+
+  return web_extension->priv->name_owner;
+}
+
+void
+ephy_web_extension_proxy_form_auth_save_requested (EphyWebExtensionProxy *web_extension,
+                                                   guint request_id,
+                                                   guint64 page_id,
+                                                   const char *hostname,
+                                                   const char *username)
+{
+  g_return_if_fail (EPHY_IS_WEB_EXTENSION_PROXY (web_extension));
+
+  g_signal_emit (web_extension, signals[FORM_AUTH_DATA_SAVE_REQUESTED], 0,
+                 request_id, page_id, hostname, username);
+}
+
+void
+ephy_web_extension_proxy_form_auth_data_save_confirmation_response (EphyWebExtensionProxy *web_extension,
+                                                                    guint request_id,
+                                                                    gboolean response)
+{
+  g_return_if_fail (EPHY_IS_WEB_EXTENSION_PROXY (web_extension));
+
+  if (!web_extension->priv->proxy)
+    return;
+
+  g_dbus_proxy_call (web_extension->priv->proxy,
+                     "FormAuthDataSaveConfirmationResponse",
+                     g_variant_new ("(ub)", request_id, response),
+                     G_DBUS_CALL_FLAGS_NONE,
+                     -1, NULL, NULL, NULL);
+}
+
+static void
+has_modified_forms_cb (GDBusProxy *proxy,
+                       GAsyncResult *result,
+                       GTask *task)
+{
+  GVariant *return_value;
+  gboolean retval = FALSE;
+
+  return_value = g_dbus_proxy_call_finish (proxy, result, NULL);
+  if (return_value) {
+    g_variant_get (return_value, "(b)", &retval);
+    g_variant_unref (return_value);
+  }
+
+  g_task_return_boolean (task, retval);
+  g_object_unref (task);
+}
+
+void
+ephy_web_extension_proxy_web_page_has_modified_forms (EphyWebExtensionProxy *web_extension,
+                                                      guint64 page_id,
+                                                      GCancellable *cancellable,
+                                                      GAsyncReadyCallback callback,
+                                                      gpointer user_data)
+{
+  GTask *task;
+
+  g_return_if_fail (EPHY_IS_WEB_EXTENSION_PROXY (web_extension));
+
+  task = g_task_new (web_extension, cancellable, callback, user_data);
+
+  if (web_extension->priv->proxy) {
+    g_dbus_proxy_call (web_extension->priv->proxy,
+                       "HasModifiedForms",
+                       g_variant_new ("(t)", page_id),
+                       G_DBUS_CALL_FLAGS_NONE,
+                       -1,
+                       cancellable,
+                       (GAsyncReadyCallback)has_modified_forms_cb,
+                       g_object_ref (task));
+  } else {
+    g_task_return_boolean (task, FALSE);
+  }
+
+  g_object_unref (task);
+}
+
+gboolean
+ephy_web_extension_proxy_web_page_has_modified_forms_finish (EphyWebExtensionProxy *web_extension,
+                                                             GAsyncResult *result,
+                                                             GError **error)
+{
+  g_return_val_if_fail (g_task_is_valid (result, web_extension), FALSE);
+
+  return g_task_propagate_boolean (G_TASK (result), error);
+}
+
+static void
+get_best_web_app_icon_cb (GDBusProxy *proxy,
+                          GAsyncResult *result,
+                          GTask *task)
+{
+  GVariant *retval;
+  GError *error = NULL;
+
+  retval = g_dbus_proxy_call_finish (proxy, result, &error);
+  if (!retval) {
+    g_task_return_error (task, error);
+  } else {
+    g_task_return_pointer (task, retval, (GDestroyNotify)g_variant_unref);
+  }
+  g_object_unref (task);
+}
+
+void
+ephy_web_extension_proxy_get_best_web_app_icon (EphyWebExtensionProxy *web_extension,
+                                                guint64 page_id,
+                                                const char *base_uri,
+                                                GCancellable *cancellable,
+                                                GAsyncReadyCallback callback,
+                                                gpointer user_data)
+{
+  GTask *task;
+
+  g_return_if_fail (EPHY_IS_WEB_EXTENSION_PROXY (web_extension));
+
+  task = g_task_new (web_extension, cancellable, callback, user_data);
+
+  if (web_extension->priv->proxy) {
+    g_dbus_proxy_call (web_extension->priv->proxy,
+                       "GetBestWebAppIcon",
+                       g_variant_new("(ts)", page_id, base_uri),
+                       G_DBUS_CALL_FLAGS_NONE,
+                       -1,
+                       cancellable,
+                       (GAsyncReadyCallback)get_best_web_app_icon_cb,
+                       g_object_ref (task));
+  } else {
+    g_task_return_boolean (task, FALSE);
+  }
+
+  g_object_unref (task);
+}
+
+gboolean
+ephy_web_extension_proxy_get_best_web_app_icon_finish (EphyWebExtensionProxy *web_extension,
+                                                       GAsyncResult *result,
+                                                       gboolean *icon_result,
+                                                       char **icon_uri,
+                                                       char **icon_color,
+                                                       GError **error)
+{
+  GVariant *variant;
+  GTask *task = G_TASK (result);
+
+  g_return_val_if_fail (g_task_is_valid (result, web_extension), FALSE);
+
+  variant = g_task_propagate_pointer (task, error);
+  if (!variant)
+    return FALSE;
+
+  g_variant_get (variant, "(bss)", icon_result, icon_uri, icon_color);
+  g_variant_unref (variant);
+
+  return TRUE;
+}
+
+static void
+get_web_app_title_cb (GDBusProxy *proxy,
+                      GAsyncResult *result,
+                      GTask *task)
+{
+  GVariant *retval;
+  GError *error = NULL;
+
+  retval = g_dbus_proxy_call_finish (proxy, result, &error);
+  if (!retval) {
+    g_task_return_error (task, error);
+  } else {
+    char *title;
+
+    g_variant_get (retval, "(s)", &title);
+    g_task_return_pointer (task, title, (GDestroyNotify)g_free);
+    g_variant_unref (retval);
+  }
+  g_object_unref (task);
+}
+
+void
+ephy_web_extension_proxy_get_web_app_title (EphyWebExtensionProxy *web_extension,
+                                            guint64 page_id,
+                                            GCancellable *cancellable,
+                                            GAsyncReadyCallback callback,
+                                            gpointer user_data)
+{
+  GTask *task;
+
+  g_return_if_fail (EPHY_IS_WEB_EXTENSION_PROXY (web_extension));
+
+  task = g_task_new (web_extension, cancellable, callback, user_data);
+
+  if (web_extension->priv->proxy) {
+    g_dbus_proxy_call (web_extension->priv->proxy,
+                       "GetWebAppTitle",
+                       g_variant_new("(t)", page_id),
+                       G_DBUS_CALL_FLAGS_NONE,
+                       -1,
+                       NULL,
+                       (GAsyncReadyCallback)get_web_app_title_cb,
+                       g_object_ref (task));
+  } else {
+    g_task_return_pointer (task, NULL, NULL);
+  }
+
+  g_object_unref (task);
+}
+
+char *
+ephy_web_extension_proxy_get_web_app_title_finish (EphyWebExtensionProxy *web_extension,
+                                                   GAsyncResult *result,
+                                                   GError **error)
+{
+  g_return_val_if_fail (g_task_is_valid (result, web_extension), FALSE);
+
+  return g_task_propagate_pointer (G_TASK (result), error);
+}
diff --git a/embed/ephy-web-extension-proxy.h b/embed/ephy-web-extension-proxy.h
new file mode 100644
index 0000000..fef44d2
--- /dev/null
+++ b/embed/ephy-web-extension-proxy.h
@@ -0,0 +1,100 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ *  Copyright © 2014 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.
+ *
+ */
+
+#if !defined (__EPHY_EPIPHANY_H_INSIDE__) && !defined (EPIPHANY_COMPILATION)
+#error "Only <epiphany/epiphany.h> can be included directly."
+#endif
+
+#ifndef EPHY_WEB_EXTENSION_PROXY_H
+#define EPHY_WEB_EXTENSION_PROXY_H
+
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define EPHY_TYPE_WEB_EXTENSION_PROXY         (ephy_web_extension_proxy_get_type ())
+#define EPHY_WEB_EXTENSION_PROXY(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), 
EPHY_TYPE_WEB_EXTENSION_PROXY, EphyWebExtensionProxy))
+#define EPHY_IS_WEB_EXTENSION_PROXY(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), 
EPHY_TYPE_WEB_EXTENSION_PROXY))
+#define EPHY_WEB_EXTENSION_PROXY_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), EPHY_TYPE_WEB_EXTENSION_PROXY, 
EphyWebExtensionProxyClass))
+#define EPHY_IS_WEB_EXTENSION_PROXY_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), EPHY_TYPE_WEB_EXTENSION_PROXY))
+#define EPHY_WEB_EXTENSION_PROXY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), 
EPHY_TYPE_WEB_EXTENSION_PROXY, EphyWebExtensionProxyClass))
+
+typedef struct _EphyWebExtensionProxyClass   EphyWebExtensionProxyClass;
+typedef struct _EphyWebExtensionProxy        EphyWebExtensionProxy;
+typedef struct _EphyWebExtensionProxyPrivate EphyWebExtensionProxyPrivate;
+
+struct _EphyWebExtensionProxy
+{
+  GObject parent;
+
+  /*< private >*/
+  EphyWebExtensionProxyPrivate *priv;
+};
+
+struct _EphyWebExtensionProxyClass
+{
+  GObjectClass parent_class;
+};
+
+GType                  ephy_web_extension_proxy_get_type                                  (void);
+
+EphyWebExtensionProxy *ephy_web_extension_proxy_new                                       (GDBusConnection   
    *bus,
+                                                                                           const char        
    *service_name);
+const char *           ephy_web_extension_proxy_get_name_owner                            
(EphyWebExtensionProxy *web_extension);
+void                   ephy_web_extension_proxy_form_auth_save_requested                  
(EphyWebExtensionProxy *web_extension,
+                                                                                           guint             
     request_id,
+                                                                                           guint64           
     page_id,
+                                                                                           const char        
    *hostname,
+                                                                                           const char        
    *username);
+void                   ephy_web_extension_proxy_form_auth_data_save_confirmation_response 
(EphyWebExtensionProxy *web_extension,
+                                                                                           guint             
     request_id,
+                                                                                           gboolean          
     response);
+void                   ephy_web_extension_proxy_web_page_has_modified_forms               
(EphyWebExtensionProxy *web_extension,
+                                                                                           guint64           
     page_id,
+                                                                                           GCancellable      
    *cancellable,
+                                                                                           
GAsyncReadyCallback    callback,
+                                                                                           gpointer          
     user_data);
+gboolean               ephy_web_extension_proxy_web_page_has_modified_forms_finish        
(EphyWebExtensionProxy *web_extension,
+                                                                                           GAsyncResult      
    *result,
+                                                                                           GError            
   **error);
+void                   ephy_web_extension_proxy_get_best_web_app_icon                     
(EphyWebExtensionProxy *web_extension,
+                                                                                           guint64           
     page_id,
+                                                                                           const char        
    *base_uri,
+                                                                                           GCancellable      
    *cancellable,
+                                                                                           
GAsyncReadyCallback    callback,
+                                                                                           gpointer          
     user_data);
+gboolean               ephy_web_extension_proxy_get_best_web_app_icon_finish              
(EphyWebExtensionProxy *web_extension,
+                                                                                           GAsyncResult      
    *result,
+                                                                                           gboolean          
    *icon_result,
+                                                                                           char              
   **icon_uri,
+                                                                                           char              
   **icon_color,
+                                                                                           GError            
   **error);
+void                   ephy_web_extension_proxy_get_web_app_title                         
(EphyWebExtensionProxy *web_extension,
+                                                                                           guint64           
     page_id,
+                                                                                           GCancellable      
    *cancellable,
+                                                                                           
GAsyncReadyCallback    callback,
+                                                                                           gpointer          
     user_data);
+char                  *ephy_web_extension_proxy_get_web_app_title_finish                  
(EphyWebExtensionProxy *web_extension,
+                                                                                           GAsyncResult      
    *result,
+                                                                                           GError            
   **error);
+
+G_END_DECLS
+
+#endif /* !EPHY_WEB_EXTENSION_PROXY_H */
diff --git a/embed/ephy-web-view.c b/embed/ephy-web-view.c
index f50d5c5..26ac211 100644
--- a/embed/ephy-web-view.c
+++ b/embed/ephy-web-view.c
@@ -43,6 +43,7 @@
 #include "ephy-string.h"
 #include "ephy-web-app-utils.h"
 #include "ephy-web-dom-utils.h"
+#include "ephy-web-extension-proxy.h"
 #include "ephy-zoom.h"
 
 #include <gio/gio.h>
@@ -111,6 +112,9 @@ struct _EphyWebViewPrivate {
   /* TLS information. */
   GTlsCertificate *certificate;
   GTlsCertificateFlags tls_errors;
+
+  /* Web Extension */
+  EphyWebExtensionProxy *web_extension;
 };
 
 typedef struct {
@@ -607,50 +611,71 @@ icon_changed_cb (EphyWebView *view,
   _ephy_web_view_update_icon (view);
 }
 
+typedef struct {
+  EphyWebView *web_view;
+  guint request_id;
+} FormAuthRequestData;
+
 static void
 form_auth_data_save_confirmation_response (GtkInfoBar *info_bar,
                                            gint response_id,
-                                           gpointer user_data)
+                                           FormAuthRequestData *data)
 {
-  GDBusProxy *web_extension;
-  guint request_id = GPOINTER_TO_INT (user_data);
-
   gtk_widget_destroy (GTK_WIDGET (info_bar));
 
-  web_extension = ephy_embed_shell_get_web_extension_proxy (ephy_embed_shell_get_default ());
-  if (!web_extension)
-    return;
+  if (data->web_view->priv->web_extension) {
+    ephy_web_extension_proxy_form_auth_data_save_confirmation_response (data->web_view->priv->web_extension,
+                                                                        data->request_id,
+                                                                        response_id == GTK_RESPONSE_YES);
+  }
 
-  g_dbus_proxy_call (web_extension,
-                     "FormAuthDataSaveConfirmationResponse",
-                     g_variant_new ("(ub)", request_id, response_id == GTK_RESPONSE_YES),
-                     G_DBUS_CALL_FLAGS_NONE,
-                     -1, NULL, NULL, NULL);
+  g_slice_free (FormAuthRequestData, data);
 }
 
 static void
-form_auth_data_save_requested (EphyEmbedShell *shell,
+form_auth_data_save_requested (EphyWebExtensionProxy *web_extension,
                                guint request_id,
                                guint64 page_id,
                                const char *hostname,
                                const char *username,
-                               WebKitWebView *web_view)
+                               EphyWebView *web_view)
 {
   GtkWidget *info_bar;
+  FormAuthRequestData *data;
 
-  if (webkit_web_view_get_page_id (web_view) != page_id)
-    return;
+  g_assert (webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view)) == page_id);
 
-  info_bar = ephy_web_view_create_form_auth_save_confirmation_info_bar (EPHY_WEB_VIEW (web_view),
-                                                                        hostname, username);
+  info_bar = ephy_web_view_create_form_auth_save_confirmation_info_bar (web_view, hostname, username);
+  data = g_slice_new (FormAuthRequestData);
+  data->web_view = web_view;
+  data->request_id = request_id;
   g_signal_connect (info_bar, "response",
                     G_CALLBACK (form_auth_data_save_confirmation_response),
-                    GINT_TO_POINTER (request_id));
+                    data);
 
   gtk_widget_show (info_bar);
 }
 
 static void
+page_created_cb (EphyEmbedShell *shell,
+                 guint64 page_id,
+                 EphyWebExtensionProxy *web_extension,
+                 EphyWebView *web_view)
+{
+  EphyWebViewPrivate *priv = web_view->priv;
+
+  if (webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (web_view)) != page_id)
+    return;
+
+  priv->web_extension = web_extension;
+  g_object_add_weak_pointer (G_OBJECT (priv->web_extension), (gpointer *)&priv->web_extension);
+
+  g_signal_connect (priv->web_extension, "form-auth-data-save-requested",
+                    G_CALLBACK (form_auth_data_save_requested),
+                    web_view);
+}
+
+static void
 ephy_web_view_dispose (GObject *object)
 {
   EphyWebViewPrivate *priv = EPHY_WEB_VIEW (object)->priv;
@@ -2001,8 +2026,8 @@ ephy_web_view_init (EphyWebView *web_view)
                     G_CALLBACK (ge_popup_blocked_cb),
                     NULL);
 
-  g_signal_connect (ephy_embed_shell_get_default (), "form-auth-data-save-requested",
-                    G_CALLBACK (form_auth_data_save_requested),
+  g_signal_connect (ephy_embed_shell_get_default (), "page-created",
+                    G_CALLBACK (page_created_cb),
                     web_view);
 }
 
@@ -2575,19 +2600,13 @@ ephy_web_view_set_typed_address (EphyWebView *view,
 }
 
 static void
-has_modified_forms_cb (GDBusProxy *web_extension,
+has_modified_forms_cb (EphyWebExtensionProxy *web_extension,
                        GAsyncResult *result,
                        GTask *task)
 {
-  GVariant *return_value;
-  gboolean retval = FALSE;
-
-  return_value = g_dbus_proxy_call_finish (web_extension, result, NULL);
-  if (return_value) {
-    g_variant_get (return_value, "(b)", &retval);
-    g_variant_unref (return_value);
-  }
+  gboolean retval;
 
+  retval = ephy_web_extension_proxy_web_page_has_modified_forms_finish (web_extension, result, NULL);
   g_task_return_boolean (task, retval);
   g_object_unref (task);
 }
@@ -2612,19 +2631,18 @@ ephy_web_view_has_modified_forms (EphyWebView *view,
                                   GAsyncReadyCallback callback,
                                   gpointer user_data)
 {
-  GTask *task = g_task_new (view, cancellable, callback, user_data);
-  GDBusProxy *web_extension;
-
-  web_extension = ephy_embed_shell_get_web_extension_proxy (ephy_embed_shell_get_default ());
-  if (web_extension) {
-    g_dbus_proxy_call (web_extension,
-                       "HasModifiedForms",
-                       g_variant_new ("(t)", webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (view))),
-                       G_DBUS_CALL_FLAGS_NONE,
-                       -1,
-                       cancellable,
-                       (GAsyncReadyCallback)has_modified_forms_cb,
-                       g_object_ref (task));
+  GTask *task;
+
+  g_return_if_fail (EPHY_IS_WEB_VIEW (view));
+
+  task = g_task_new (view, cancellable, callback, user_data);
+
+  if (view->priv->web_extension) {
+    ephy_web_extension_proxy_web_page_has_modified_forms (view->priv->web_extension,
+                                                          webkit_web_view_get_page_id (WEBKIT_WEB_VIEW 
(view)),
+                                                          cancellable,
+                                                          (GAsyncReadyCallback)has_modified_forms_cb,
+                                                          g_object_ref (task));
   } else {
     g_task_return_boolean (task, FALSE);
   }
@@ -2642,6 +2660,151 @@ ephy_web_view_has_modified_forms_finish (EphyWebView *view,
   return g_task_propagate_boolean (G_TASK (result), error);
 }
 
+typedef struct {
+  gboolean icon_result;
+  char *icon_uri;
+  char *icon_color;
+} GetBestWebAppIconAsyncData;
+
+static void
+get_best_web_app_icon_async_data_free (GetBestWebAppIconAsyncData *data)
+{
+  g_free (data->icon_uri);
+  g_free (data->icon_color);
+
+  g_slice_free (GetBestWebAppIconAsyncData, data);
+}
+
+static void
+get_best_web_app_icon_cb (EphyWebExtensionProxy *web_extension,
+                          GAsyncResult *result,
+                          GTask *task)
+{
+  gboolean retval = FALSE;
+  char *uri = NULL;
+  char *color = NULL;
+  GError *error = NULL;
+
+  if (!ephy_web_extension_proxy_get_best_web_app_icon_finish (web_extension, result, &retval, &uri, &color, 
&error)) {
+    g_task_return_error (task, error);
+  } else {
+    GetBestWebAppIconAsyncData *data = g_slice_new0 (GetBestWebAppIconAsyncData);
+
+    data->icon_result = retval;
+    data->icon_uri = uri;
+    data->icon_color = color;
+    g_task_return_pointer (task, data, (GDestroyNotify)get_best_web_app_icon_async_data_free);
+  }
+  g_object_unref (task);
+}
+
+void
+ephy_web_view_get_best_web_app_icon (EphyWebView *view,
+                                     GCancellable *cancellable,
+                                     GAsyncReadyCallback callback,
+                                     gpointer user_data)
+{
+  GTask *task;
+
+  g_return_if_fail (EPHY_IS_WEB_VIEW (view));
+
+  task = g_task_new (view, cancellable, callback, user_data);
+
+  if (view->priv->web_extension) {
+    ephy_web_extension_proxy_get_best_web_app_icon (view->priv->web_extension,
+                                                    webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (view)),
+                                                    webkit_web_view_get_uri (WEBKIT_WEB_VIEW (view)),
+                                                    cancellable,
+                                                    (GAsyncReadyCallback)get_best_web_app_icon_cb,
+                                                    g_object_ref (task));
+  } else {
+    g_task_return_boolean (task, FALSE);
+  }
+
+  g_object_unref (task);
+}
+
+gboolean
+ephy_web_view_get_best_web_app_icon_finish (EphyWebView *view,
+                                            GAsyncResult *result,
+                                            gboolean *icon_result,
+                                            char **icon_uri,
+                                            GdkRGBA *icon_color,
+                                            GError **error)
+{
+  GetBestWebAppIconAsyncData *data;
+  GTask *task = G_TASK (result);
+
+  g_return_val_if_fail (g_task_is_valid (result, view), FALSE);
+
+  data = g_task_propagate_pointer (task, error);
+  if (!data)
+    return FALSE;
+
+  if (data->icon_uri != NULL && data->icon_uri[0] != '\0') {
+    *icon_uri = data->icon_uri;
+    data->icon_uri = NULL;
+  }
+
+  if (data->icon_color != NULL && data->icon_color[0] != '\0')
+    gdk_rgba_parse (icon_color, data->icon_color);
+
+  get_best_web_app_icon_async_data_free (data);
+
+  return TRUE;
+}
+
+static void
+get_web_app_title_cb (EphyWebExtensionProxy *web_extension,
+                      GAsyncResult *result,
+                      GTask *task)
+{
+  char *retval;
+  GError *error = NULL;
+
+  retval = ephy_web_extension_proxy_get_web_app_title_finish (web_extension, result, &error);
+  if (!retval)
+    g_task_return_error (task, error);
+  else
+    g_task_return_pointer (task, retval, (GDestroyNotify)g_free);
+  g_object_unref (task);
+}
+
+void
+ephy_web_view_get_web_app_title (EphyWebView *view,
+                                 GCancellable *cancellable,
+                                 GAsyncReadyCallback callback,
+                                 gpointer user_data)
+{
+  GTask *task;
+
+  g_return_if_fail (EPHY_IS_WEB_VIEW (view));
+
+  task = g_task_new (view, cancellable, callback, user_data);
+
+  if (view->priv->web_extension) {
+    ephy_web_extension_proxy_get_web_app_title (view->priv->web_extension,
+                                                webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (view)),
+                                                cancellable,
+                                                (GAsyncReadyCallback)get_web_app_title_cb,
+                                                g_object_ref (task));
+  } else {
+    g_task_return_pointer (task, NULL, NULL);
+  }
+
+  g_object_unref (task);
+}
+
+char *
+ephy_web_view_get_web_app_title_finish (EphyWebView *view,
+                                        GAsyncResult *result,
+                                        GError **error)
+{
+  g_return_val_if_fail (g_task_is_valid (result, view), NULL);
+
+  return g_task_propagate_pointer (G_TASK (result), error);
+}
+
 /**
  * ephy_web_view_get_security_level:
  * @view: an #EphyWebView
diff --git a/embed/ephy-web-view.h b/embed/ephy-web-view.h
index 500aaab..5c817eb 100644
--- a/embed/ephy-web-view.h
+++ b/embed/ephy-web-view.h
@@ -160,6 +160,23 @@ void                       ephy_web_view_load_error_page          (EphyWebView
                                                                    const char                *uri,
                                                                    EphyWebViewErrorPage       page,
                                                                    GError                    *error);
+void                       ephy_web_view_get_best_web_app_icon    (EphyWebView               *view,
+                                                                   GCancellable              *cancellable,
+                                                                   GAsyncReadyCallback        callback,
+                                                                   gpointer                   user_data);
+gboolean               ephy_web_view_get_best_web_app_icon_finish (EphyWebView               *view,
+                                                                   GAsyncResult              *result,
+                                                                   gboolean                  *icon_result,
+                                                                   char                     **icon_uri,
+                                                                   GdkRGBA                   *icon_color,
+                                                                   GError                   **error);
+void                       ephy_web_view_get_web_app_title        (EphyWebView               *view,
+                                                                   GCancellable              *cancellable,
+                                                                   GAsyncReadyCallback        callback,
+                                                                   gpointer                   user_data);
+char                      *ephy_web_view_get_web_app_title_finish (EphyWebView               *view,
+                                                                   GAsyncResult              *result,
+                                                                   GError                   **error);
 
 G_END_DECLS
 
diff --git a/embed/web-extension/ephy-web-extension.c b/embed/web-extension/ephy-web-extension.c
index fae0849..d6c051f 100644
--- a/embed/web-extension/ephy-web-extension.c
+++ b/embed/web-extension/ephy-web-extension.c
@@ -40,10 +40,14 @@
 static UriTester *uri_tester;
 static EphyFormAuthDataCache *form_auth_data_cache;
 static GDBusConnection *dbus_connection;
+static GArray *page_created_signals_pending;
 
 static const char introspection_xml[] =
   "<node>"
   " <interface name='org.gnome.Epiphany.WebExtension'>"
+  "  <signal name='PageCreated'>"
+  "   <arg type='t' name='page_id' direction='out'/>"
+  "  </signal>"
   "  <method name='HasModifiedForms'>"
   "   <arg type='t' name='page_id' direction='in'/>"
   "   <arg type='b' name='has_modified_forms' direction='out'/>"
@@ -945,10 +949,63 @@ web_page_document_loaded (WebKitWebPage *web_page,
 }
 
 static void
+emit_page_created (guint64 page_id)
+{
+  GError *error = NULL;
+
+  g_dbus_connection_emit_signal (dbus_connection,
+                                 NULL,
+                                 EPHY_WEB_EXTENSION_OBJECT_PATH,
+                                 EPHY_WEB_EXTENSION_INTERFACE,
+                                 "PageCreated",
+                                 g_variant_new ("(t)", page_id),
+                                 &error);
+  if (error) {
+    g_warning ("Error emitting signal PageCreated: %s\n", error->message);
+    g_error_free (error);
+  }
+}
+
+static void
+emit_page_created_signals_pending (void)
+{
+  guint i;
+
+  if (!page_created_signals_pending)
+    return;
+
+  for (i = 0; i < page_created_signals_pending->len; i++) {
+    guint64 page_id;
+
+    page_id = g_array_index (page_created_signals_pending, guint64, i);
+    emit_page_created (page_id);
+  }
+
+  g_array_free (page_created_signals_pending, TRUE);
+  page_created_signals_pending = NULL;
+}
+
+static void
+queue_page_created_signal_emission (guint64 page_id)
+{
+  if (!page_created_signals_pending)
+    page_created_signals_pending = g_array_new (FALSE, FALSE, sizeof (guint64));
+  page_created_signals_pending = g_array_append_val (page_created_signals_pending, page_id);
+}
+
+static void
 web_page_created_callback (WebKitWebExtension *extension,
                            WebKitWebPage *web_page,
                            gpointer user_data)
 {
+  guint64 page_id;
+
+  page_id = webkit_web_page_get_id (web_page);
+  if (dbus_connection)
+    emit_page_created (page_id);
+  else
+    queue_page_created_signal_emission (page_id);
+
   g_signal_connect_object (web_page, "send-request",
                            G_CALLBACK (web_page_send_request),
                            NULL, 0);
@@ -1090,6 +1147,7 @@ bus_acquired_cb (GDBusConnection *connection,
   } else {
     dbus_connection = connection;
     g_object_add_weak_pointer (G_OBJECT (connection), (gpointer *)&dbus_connection);
+    emit_page_created_signals_pending ();
   }
 }
 
@@ -1098,11 +1156,11 @@ webkit_web_extension_initialize_with_user_data (WebKitWebExtension *extension,
                                                 GVariant *user_data)
 {
   char *service_name;
-  guint extension_id;
+  const char *extension_id;
   const char *dot_dir;
   gboolean private_profile;
 
-  g_variant_get (user_data, "(u&sb)", &extension_id, &dot_dir, &private_profile);
+  g_variant_get (user_data, "(&s&sb)", &extension_id, &dot_dir, &private_profile);
 
   ephy_debug_init ();
   uri_tester = uri_tester_new (dot_dir);
@@ -1113,7 +1171,7 @@ webkit_web_extension_initialize_with_user_data (WebKitWebExtension *extension,
                     G_CALLBACK (web_page_created_callback),
                     NULL);
 
-  service_name = g_strdup_printf ("%s-%u", EPHY_WEB_EXTENSION_SERVICE_NAME, extension_id);
+  service_name = g_strdup_printf ("%s-%s", EPHY_WEB_EXTENSION_SERVICE_NAME, extension_id);
   g_bus_own_name (G_BUS_TYPE_SESSION,
                   service_name,
                   G_BUS_NAME_OWNER_FLAGS_NONE,
diff --git a/lib/ephy-prefs.h b/lib/ephy-prefs.h
index 5c6afb0..cf39c1b 100644
--- a/lib/ephy-prefs.h
+++ b/lib/ephy-prefs.h
@@ -67,6 +67,12 @@ typedef enum
   EPHY_PREFS_STATE_HISTORY_DATE_FILTER_EVER,
 } EphyPrefsStateHistoryDateFilter;
 
+typedef enum
+{
+  EPHY_PREFS_PROCESS_MODEL_SHARED_SECONDARY_PROCESS,
+  EPHY_PREFS_PROCESS_MODEL_ONE_SECONDARY_PROCESS_PER_WEB_VIEW
+} EphyPrefsProcessModel;
+
 #define EPHY_PREFS_UI_SCHEMA                     "org.gnome.Epiphany.ui"
 #define EPHY_PREFS_UI_ALWAYS_SHOW_TABS_BAR       "always-show-tabs-bar"
 #define EPHY_PREFS_UI_TOOLBAR_STYLE              "toolbar-style"
@@ -123,6 +129,7 @@ typedef enum
 #define EPHY_PREFS_INTERNAL_VIEW_SOURCE           "internal-view-source"
 #define EPHY_PREFS_RESTORE_SESSION_POLICY         "restore-session-policy"
 #define EPHY_PREFS_RESTORE_SESSION_DELAYING_LOADS "restore-session-delaying-loads"
+#define EPHY_PREFS_PROCESS_MODEL                  "process-model"
 
 #define EPHY_PREFS_LOCKDOWN_SCHEMA            "org.gnome.Epiphany.lockdown"
 #define EPHY_PREFS_LOCKDOWN_FULLSCREEN        "disable-fullscreen"
diff --git a/src/window-commands.c b/src/window-commands.c
index 78e1952..ed95c3f 100644
--- a/src/window-commands.c
+++ b/src/window-commands.c
@@ -571,26 +571,19 @@ download_icon_and_set_image (EphyApplicationDialogData *data)
 }
 
 static void
-download_icon_or_take_snapshot (EphyApplicationDialogData *data,
-                               gboolean res,
-                               char *uri,
-                               char *color)
+fill_default_application_image_cb (GObject *source,
+                                  GAsyncResult *async_result,
+                                  gpointer user_data)
 {
-       if (uri != NULL && uri[0] != '\0')
-               data->icon_href = uri;
+       EphyApplicationDialogData *data = user_data;
+       char *uri = NULL;
+       GdkRGBA color = { 0.5, 0.5, 0.5, 0.3 };
+       gboolean res = FALSE;
 
-       if (color != NULL && color[0] != '\0')
-       {
-               gdk_rgba_parse (&data->icon_rgba, color);
-       }
-       else
-       {
-               data->icon_rgba.red = 0.5;
-               data->icon_rgba.green = 0.5;
-               data->icon_rgba.blue = 0.5;
-               data->icon_rgba.alpha = 0.3;
-       }
+       ephy_web_view_get_best_web_app_icon_finish (EPHY_WEB_VIEW (source), async_result, &res, &uri, &color, 
NULL);
 
+       data->icon_href = uri;
+       data->icon_rgba = color;
        if (res)
        {
                download_icon_and_set_image (data);
@@ -603,49 +596,9 @@ download_icon_or_take_snapshot (EphyApplicationDialogData *data,
 }
 
 static void
-fill_default_application_image_cb (GObject *source,
-                                  GAsyncResult *async_result,
-                                  gpointer user_data)
-{
-       EphyApplicationDialogData *data = user_data;
-       GVariant *result;
-       char *uri = NULL;
-       char *color = NULL;
-       gboolean res = FALSE;
-
-       result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source),
-                                          async_result,
-                                          NULL);
-
-       if (result)
-       {
-               g_variant_get (result, "(bss)", &res, &uri, &color);
-               g_variant_unref (result);
-       }
-
-       download_icon_or_take_snapshot (data, res, uri, color);
-}
-
-static void
 fill_default_application_image (EphyApplicationDialogData *data)
 {
-       const char *base_uri;
-       GDBusProxy *web_extension;
-
-       base_uri = webkit_web_view_get_uri (WEBKIT_WEB_VIEW (data->view));
-
-       web_extension = ephy_embed_shell_get_web_extension_proxy (ephy_embed_shell_get_default ());
-       if (web_extension)
-               g_dbus_proxy_call (web_extension,
-                                  "GetBestWebAppIcon",
-                                  g_variant_new("(ts)", webkit_web_view_get_page_id (WEBKIT_WEB_VIEW 
(data->view)), base_uri),
-                                  G_DBUS_CALL_FLAGS_NONE,
-                                  -1,
-                                  NULL,
-                                  fill_default_application_image_cb,
-                                  data);
-       else
-               download_icon_or_take_snapshot (data, FALSE, NULL, NULL);
+       ephy_web_view_get_best_web_app_icon (data->view, NULL, fill_default_application_image_cb, data);
 }
 
 typedef struct {
@@ -720,39 +673,16 @@ fill_default_application_title_cb (GObject *source,
                                   gpointer user_data)
 {
        EphyApplicationDialogData *data = user_data;
-       GVariant *result;
-       char *title = NULL;
-
-       result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source),
-                                          async_result,
-                                          NULL);
-
-       if (result)
-       {
-               g_variant_get (result, "(s)", &title);
-               g_variant_unref (result);
-       }
+       char *title;
 
+       title = ephy_web_view_get_web_app_title_finish (EPHY_WEB_VIEW (source), async_result, NULL);
        set_default_application_title (data, title);
 }
 
 static void
 fill_default_application_title (EphyApplicationDialogData *data)
 {
-       GDBusProxy *web_extension;
-
-       web_extension = ephy_embed_shell_get_web_extension_proxy (ephy_embed_shell_get_default ());
-       if (web_extension)
-               g_dbus_proxy_call (web_extension,
-                                  "GetWebAppTitle",
-                                  g_variant_new("(t)", webkit_web_view_get_page_id (WEBKIT_WEB_VIEW 
(data->view))),
-                                  G_DBUS_CALL_FLAGS_NONE,
-                                  -1,
-                                  NULL,
-                                  fill_default_application_title_cb,
-                                  data);
-       else
-               set_default_application_title (data, NULL);
+       ephy_web_view_get_web_app_title (data->view, NULL, fill_default_application_title_cb, data);
 }
 
 static void


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