[epiphany/carlosgc/automation-mode] Add automation mode



commit c44da44bc8d6e4d7f8e471fa258f365574801e7a
Author: Carlos Garcia Campos <cgarcia igalia com>
Date:   Thu Jan 3 15:25:46 2019 +0100

    Add automation mode

 data/epiphany.1                        |  3 ++
 embed/ephy-embed-container.c           | 19 ++++++++++
 embed/ephy-embed-container.h           |  3 ++
 embed/ephy-embed-shell.c               | 35 ++++++++++++------
 embed/ephy-embed-shell.h               |  3 +-
 embed/ephy-embed.c                     | 14 +++++++
 embed/ephy-web-view.c                  |  6 ++-
 meson.build                            |  5 +++
 src/ephy-lockdown.c                    |  3 +-
 src/ephy-main.c                        | 20 ++++++++--
 src/ephy-shell.c                       | 46 ++++++++++++++++++++++-
 src/ephy-window.c                      | 39 +++++++++++++++++++-
 src/resources/themes/Adwaita.css       | 42 +++++++++++++++++++++
 src/resources/themes/Adwaita.scss      | 67 +++++++++++++++++++++++++++++++++-
 src/resources/themes/_definitions.scss |  5 ++-
 src/resources/themes/shared.css        |  2 +
 src/resources/themes/shared.scss       |  8 ++++
 17 files changed, 295 insertions(+), 25 deletions(-)
---
diff --git a/data/epiphany.1 b/data/epiphany.1
index 1b835b981..8cfb374d9 100644
--- a/data/epiphany.1
+++ b/data/epiphany.1
@@ -37,6 +37,9 @@ Start a private instance (temporary profile directory, not private browsing mode
 \fB\-\-incognito\-mode\fR
 Start a private instance in incognito mode
 .TP
+\fB\-\-automation\-mode\fR
+Start the browser in automation mode, for WebDriver control
+.TP
 \fB\-\-profile\fR=\fIFILE\fR
 Profile directory to use in the private instance
 .TP
diff --git a/embed/ephy-embed-container.c b/embed/ephy-embed-container.c
index addf0aa63..cbd66e19e 100644
--- a/embed/ephy-embed-container.c
+++ b/embed/ephy-embed-container.c
@@ -165,3 +165,22 @@ ephy_embed_container_get_is_popup (EphyEmbedContainer *container)
   iface = EPHY_EMBED_CONTAINER_GET_IFACE (container);
   return iface->get_is_popup (container);
 }
+
+/**
+ * ephy_embed_container_get_n_children:
+ * @container: a #EphyEmbedContainer
+ *
+ * Returns the number of #EphyEmbed:s in the container.
+ *
+ * Returns: the number of children
+ */
+guint
+ephy_embed_container_get_n_children (EphyEmbedContainer *container)
+{
+  EphyEmbedContainerInterface *iface;
+
+  g_assert (EPHY_IS_EMBED_CONTAINER (container));
+
+  iface = EPHY_EMBED_CONTAINER_GET_IFACE (container);
+  return iface->get_n_children (container);
+}
diff --git a/embed/ephy-embed-container.h b/embed/ephy-embed-container.h
index 596b0e68e..18b8ee01a 100644
--- a/embed/ephy-embed-container.h
+++ b/embed/ephy-embed-container.h
@@ -52,6 +52,8 @@ struct _EphyEmbedContainerInterface
   GList * (* get_children)         (EphyEmbedContainer *container);
 
   gboolean (* get_is_popup)        (EphyEmbedContainer *container);
+
+  guint (* get_n_children)         (EphyEmbedContainer *container);
 };
 
 gint              ephy_embed_container_add_child        (EphyEmbedContainer *container,
@@ -65,5 +67,6 @@ void              ephy_embed_container_remove_child     (EphyEmbedContainer *con
 EphyEmbed *       ephy_embed_container_get_active_child (EphyEmbedContainer *container);
 GList *           ephy_embed_container_get_children     (EphyEmbedContainer *container);
 gboolean          ephy_embed_container_get_is_popup     (EphyEmbedContainer *container);
+guint             ephy_embed_container_get_n_children   (EphyEmbedContainer *container);
 
 G_END_DECLS
diff --git a/embed/ephy-embed-shell.c b/embed/ephy-embed-shell.c
index b798fbecd..d2e9d2d8a 100644
--- a/embed/ephy-embed-shell.c
+++ b/embed/ephy-embed-shell.c
@@ -756,6 +756,7 @@ ephy_embed_shell_get_global_history_service (EphyEmbedShell *shell)
     EphySQLiteConnectionMode mode;
 
     if (priv->mode == EPHY_EMBED_SHELL_MODE_INCOGNITO ||
+        priv->mode == EPHY_EMBED_SHELL_MODE_AUTOMATION ||
         priv->mode == EPHY_EMBED_SHELL_MODE_SEARCH_PROVIDER)
       mode = EPHY_SQLITE_CONNECTION_MODE_READ_ONLY;
     else
@@ -958,7 +959,7 @@ initialize_web_extensions (WebKitWebContext *web_context,
 
   address = priv->dbus_server ? g_dbus_server_get_client_address (priv->dbus_server) : NULL;
 
-  private_profile = priv->mode == EPHY_EMBED_SHELL_MODE_PRIVATE || priv->mode == 
EPHY_EMBED_SHELL_MODE_INCOGNITO;
+  private_profile = priv->mode == EPHY_EMBED_SHELL_MODE_PRIVATE || priv->mode == 
EPHY_EMBED_SHELL_MODE_INCOGNITO || priv->mode == EPHY_EMBED_SHELL_MODE_AUTOMATION;
   browser_mode = priv->mode == EPHY_EMBED_SHELL_MODE_BROWSER;
   user_data = g_variant_new ("(smsssbb)",
                              priv->guid,
@@ -1101,6 +1102,12 @@ ephy_embed_shell_create_web_context (EphyEmbedShell *shell)
     return;
   }
 
+  if (priv->mode == EPHY_EMBED_SHELL_MODE_AUTOMATION) {
+    priv->web_context = webkit_web_context_new_ephemeral ();
+    webkit_web_context_set_automation_allowed (priv->web_context, TRUE);
+    return;
+  }
+
   data_dir = g_build_filename (priv->mode == EPHY_EMBED_SHELL_MODE_PRIVATE ?
                                ephy_dot_dir () : g_get_user_data_dir (),
                                g_get_prgname (), NULL);
@@ -1258,17 +1265,21 @@ ephy_embed_shell_startup (GApplication *application)
 
   priv->password_manager = ephy_password_manager_new ();
 
-  /* Favicon Database */
-  if (priv->mode == EPHY_EMBED_SHELL_MODE_PRIVATE)
-    favicon_db_path = g_build_filename (ephy_dot_dir (), "icondatabase", NULL);
-  else
-    favicon_db_path = g_build_filename (g_get_user_cache_dir (), "epiphany", "icondatabase", NULL);
-  webkit_web_context_set_favicon_database_directory (priv->web_context, favicon_db_path);
-  g_free (favicon_db_path);
-
-  /* Do not ignore TLS errors. */
-  webkit_web_context_set_tls_errors_policy (priv->web_context, WEBKIT_TLS_ERRORS_POLICY_FAIL);
+  /* Do not cache favicons in automation mode. Don't change the TLS policy either, since that's
+   * handled by session capabilities in automation mode.
+   */
+  if (priv->mode != EPHY_EMBED_SHELL_MODE_AUTOMATION) {
+    /* Favicon Database */
+    if (priv->mode == EPHY_EMBED_SHELL_MODE_PRIVATE)
+      favicon_db_path = g_build_filename (ephy_dot_dir (), "icondatabase", NULL);
+    else
+      favicon_db_path = g_build_filename (g_get_user_cache_dir (), "epiphany", "icondatabase", NULL);
+    webkit_web_context_set_favicon_database_directory (priv->web_context, favicon_db_path);
+    g_free (favicon_db_path);
 
+    /* Do not ignore TLS errors. */
+    webkit_web_context_set_tls_errors_policy (priv->web_context, WEBKIT_TLS_ERRORS_POLICY_FAIL);
+  }
 
   /* about: URIs handler */
   priv->about_handler = ephy_about_handler_new ();
@@ -1299,7 +1310,7 @@ ephy_embed_shell_startup (GApplication *application)
 
   /* Store cookies in moz-compatible SQLite format */
   cookie_manager = webkit_web_context_get_cookie_manager (priv->web_context);
-  if (priv->mode != EPHY_EMBED_SHELL_MODE_INCOGNITO) {
+  if (!webkit_web_context_is_ephemeral (priv->web_context)) {
     filename = g_build_filename (ephy_dot_dir (), "cookies.sqlite", NULL);
     webkit_cookie_manager_set_persistent_storage (cookie_manager, filename,
                                                   WEBKIT_COOKIE_PERSISTENT_STORAGE_SQLITE);
diff --git a/embed/ephy-embed-shell.h b/embed/ephy-embed-shell.h
index cf7cf557b..3319dfcf1 100644
--- a/embed/ephy-embed-shell.h
+++ b/embed/ephy-embed-shell.h
@@ -46,7 +46,8 @@ typedef enum
   EPHY_EMBED_SHELL_MODE_INCOGNITO,
   EPHY_EMBED_SHELL_MODE_APPLICATION,
   EPHY_EMBED_SHELL_MODE_TEST,
-  EPHY_EMBED_SHELL_MODE_SEARCH_PROVIDER
+  EPHY_EMBED_SHELL_MODE_SEARCH_PROVIDER,
+  EPHY_EMBED_SHELL_MODE_AUTOMATION
 } EphyEmbedShellMode;
 
 struct _EphyEmbedShellClass
diff --git a/embed/ephy-embed.c b/embed/ephy-embed.c
index 1a3f3c278..b56fe9155 100644
--- a/embed/ephy-embed.c
+++ b/embed/ephy-embed.c
@@ -808,6 +808,20 @@ ephy_embed_constructed (GObject *object)
   g_signal_connect (inspector, "closed",
                     G_CALLBACK (ephy_embed_close_inspector_cb),
                     embed);
+
+  if (webkit_web_view_is_controlled_by_automation (embed->web_view)) {
+    GtkWidget *info_bar;
+    GtkWidget *label;
+
+    info_bar = gtk_info_bar_new ();
+    gtk_info_bar_set_message_type (GTK_INFO_BAR (info_bar), GTK_MESSAGE_INFO);
+    label = gtk_label_new (_("Web is being controlled by automation"));
+    gtk_box_pack_start (GTK_BOX (gtk_info_bar_get_content_area (GTK_INFO_BAR (info_bar))), label, FALSE, 
FALSE, 0);
+    gtk_widget_show (label);
+
+    ephy_embed_add_top_widget (embed, info_bar, EPHY_EMBED_TOP_WIDGET_POLICY_RETAIN_ON_TRANSITION);
+    gtk_widget_show (info_bar);
+  }
 }
 
 static void
diff --git a/embed/ephy-web-view.c b/embed/ephy-web-view.c
index ca58dca8c..a3c9fa9e9 100644
--- a/embed/ephy-web-view.c
+++ b/embed/ephy-web-view.c
@@ -2900,6 +2900,7 @@ ephy_web_view_new (void)
                        "web-context", ephy_embed_shell_get_web_context (shell),
                        "user-content-manager", ephy_embed_shell_get_user_content_manager (shell),
                        "settings", ephy_embed_prefs_get_settings (),
+                       "is-controlled-by-automation", ephy_embed_shell_get_mode (shell) == 
EPHY_EMBED_SHELL_MODE_AUTOMATION,
                        NULL);
 }
 
@@ -3687,7 +3688,8 @@ ephy_web_view_load_homepage (EphyWebView *view)
   shell = ephy_embed_shell_get_default ();
   mode = ephy_embed_shell_get_mode (shell);
 
-  if (mode == EPHY_EMBED_SHELL_MODE_INCOGNITO) {
+  if (mode == EPHY_EMBED_SHELL_MODE_INCOGNITO ||
+      mode == EPHY_EMBED_SHELL_MODE_AUTOMATION) {
     ephy_web_view_load_new_tab_page (view);
     return;
   }
@@ -3718,6 +3720,8 @@ ephy_web_view_load_new_tab_page (EphyWebView *view)
   ephy_web_view_set_visit_type (view, EPHY_PAGE_VISIT_HOMEPAGE);
   if (mode == EPHY_EMBED_SHELL_MODE_INCOGNITO)
     ephy_web_view_load_url (view, "about:incognito");
+  else if (mode == EPHY_EMBED_SHELL_MODE_AUTOMATION)
+    ephy_web_view_load_url (view, "about:blank");
   else
     ephy_web_view_load_url (view, "about:overview");
 }
diff --git a/meson.build b/meson.build
index 29e266b27..b50bb4f40 100644
--- a/meson.build
+++ b/meson.build
@@ -49,6 +49,11 @@ conf.set10('TECH_PREVIEW', tech_preview)
 
 conf.set_quoted('VERSION', meson.project_version())
 
+version_array = meson.project_version().split('.')
+conf.set('EPHY_MAJOR_VERSION', version_array[0].to_int())
+conf.set('EPHY_MINOR_VERSION', version_array[1].to_int())
+conf.set('EPHY_MICRO_VERSION', version_array[2].to_int())
+
 configure_file(
   output: 'config.h',
   configuration: conf
diff --git a/src/ephy-lockdown.c b/src/ephy-lockdown.c
index 3e968822c..43f311386 100644
--- a/src/ephy-lockdown.c
+++ b/src/ephy-lockdown.c
@@ -252,7 +252,8 @@ window_added_cb (GtkApplication *application,
   g_settings_bind_writable (settings, "picture-filename",
                             action, "enabled", FALSE);
 
-  if (mode != EPHY_EMBED_SHELL_MODE_APPLICATION) {
+  if (mode != EPHY_EMBED_SHELL_MODE_APPLICATION &&
+      mode != EPHY_EMBED_SHELL_MODE_AUTOMATION) {
     location_controller = ephy_window_get_location_controller (EPHY_WINDOW (window));
     bind_location_controller (EPHY_SETTINGS_LOCKDOWN, location_controller);
   }
diff --git a/src/ephy-main.c b/src/ephy-main.c
index 18bb07e37..654a10c96 100644
--- a/src/ephy-main.c
+++ b/src/ephy-main.c
@@ -57,6 +57,7 @@ static char *application_to_delete = NULL;
 static gboolean private_instance = FALSE;
 static gboolean incognito_mode = FALSE;
 static gboolean application_mode = FALSE;
+static gboolean automation_mode = FALSE;
 static char *desktop_file_basename = NULL;
 static char *profile_directory = NULL;
 
@@ -128,6 +129,8 @@ static const GOptionEntry option_entries[] =
   { "application-mode", 'a', G_OPTION_FLAG_FILENAME | G_OPTION_FLAG_OPTIONAL_ARG,
     G_OPTION_ARG_CALLBACK, application_mode_cb,
     N_("Start the browser in application mode"), NULL },
+  { "automation-mode", 0, 0, G_OPTION_ARG_NONE, &automation_mode,
+    N_("Start an instance in automation mode"), NULL },
   { "profile", 0, 0, G_OPTION_ARG_STRING, &profile_directory,
     N_("Profile directory to use in the private instance"), N_("DIR") },
   { G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_FILENAME_ARRAY, &arguments,
@@ -306,6 +309,11 @@ main (int   argc,
     exit (1);
   }
 
+  if (automation_mode && (private_instance || incognito_mode || application_mode || profile_directory)) {
+    g_print ("Cannot use --automation-mode and --private-instance, --incognito-mode, --application-mode or 
--profile at the same time\n");
+    exit (1);
+  }
+
   if (application_mode && profile_directory && !g_file_test (profile_directory, G_FILE_TEST_IS_DIR)) {
     g_print ("--profile must be an existing directory when --application-mode is requested\n");
     exit (1);
@@ -336,7 +344,7 @@ main (int   argc,
   /* Start our services */
   flags = !application_mode ? EPHY_FILE_HELPERS_ENSURE_EXISTS : 0;
 
-  if (incognito_mode || private_instance || application_mode)
+  if (incognito_mode || private_instance || application_mode || automation_mode)
     flags |= EPHY_FILE_HELPERS_PRIVATE_PROFILE;
   if (incognito_mode)
     flags |= EPHY_FILE_HELPERS_STEAL_DATA;
@@ -349,8 +357,8 @@ main (int   argc,
 
   /* Run the migration in all cases, except when running a private
      instance without a given profile directory or running in
-     incognito mode. */
-  if (!(private_instance && profile_directory == NULL) && incognito_mode == FALSE) {
+     incognito or automation mode. */
+  if (!(private_instance && profile_directory == NULL) && !incognito_mode && !automation_mode) {
     /* If the migration fails we don't really want to continue. */
     if (!ephy_profile_utils_do_migration ((const char *)profile_directory, -1, FALSE)) {
       g_print ("Failed to run the migrator process, Web will now abort.\n");
@@ -358,6 +366,10 @@ main (int   argc,
     }
   }
 
+  /* Ignore arguments in automation mode */
+  if (automation_mode)
+    g_clear_pointer (&arguments, g_strfreev);
+
   arbitrary_url = g_settings_get_boolean (EPHY_SETTINGS_LOCKDOWN,
                                           EPHY_PREFS_LOCKDOWN_ARBITRARY_URL);
 
@@ -397,6 +409,8 @@ main (int   argc,
     startup_flags |= EPHY_STARTUP_NEW_TAB;
   } else if (incognito_mode) {
     mode = EPHY_EMBED_SHELL_MODE_INCOGNITO;
+  } else if (automation_mode) {
+    mode = EPHY_EMBED_SHELL_MODE_AUTOMATION;
   } else if (application_mode) {
     mode = EPHY_EMBED_SHELL_MODE_APPLICATION;
 
diff --git a/src/ephy-shell.c b/src/ephy-shell.c
index 716cf4214..3b254a069 100644
--- a/src/ephy-shell.c
+++ b/src/ephy-shell.c
@@ -372,7 +372,8 @@ ephy_shell_startup (GApplication *application)
                                      app_entries, G_N_ELEMENTS (app_entries),
                                      application);
 
-    if (mode != EPHY_EMBED_SHELL_MODE_INCOGNITO) {
+    if (mode != EPHY_EMBED_SHELL_MODE_INCOGNITO &&
+        mode != EPHY_EMBED_SHELL_MODE_AUTOMATION) {
       g_action_map_add_action_entries (G_ACTION_MAP (application),
                                        non_incognito_extra_app_entries, G_N_ELEMENTS 
(non_incognito_extra_app_entries),
                                        application);
@@ -409,6 +410,41 @@ ephy_shell_startup (GApplication *application)
   set_accel_for_action (shell, "app.quit", "<Primary>q");
 }
 
+static GtkWidget *
+create_web_view_for_automation_cb (WebKitAutomationSession *session,
+                                   EphyShell               *shell)
+{
+  EphyEmbed *embed;
+  EphyWindow *window;
+  EphyWebView *web_view;
+  guint n_embeds;
+
+  window = EPHY_WINDOW (gtk_application_get_active_window (GTK_APPLICATION (shell)));
+  embed = ephy_embed_container_get_active_child (EPHY_EMBED_CONTAINER (window));
+  n_embeds = ephy_embed_container_get_n_children (EPHY_EMBED_CONTAINER (window));
+  web_view = ephy_embed_get_web_view (embed);
+  if (n_embeds == 1 && ephy_web_view_get_visit_type (web_view) == EPHY_PAGE_VISIT_HOMEPAGE)
+    return GTK_WIDGET (web_view);
+
+  embed = ephy_shell_new_tab (shell, window, NULL, EPHY_NEW_TAB_JUMP);
+  return GTK_WIDGET (ephy_embed_get_web_view (embed));
+}
+
+static void
+automation_started_cb (WebKitWebContext        *web_context,
+                       WebKitAutomationSession *session,
+                       EphyShell               *shell)
+{
+  WebKitApplicationInfo *info = webkit_application_info_new ();
+  webkit_application_info_set_name (info, "Epiphany");
+  webkit_application_info_set_version (info, EPHY_MAJOR_VERSION, EPHY_MINOR_VERSION, EPHY_MICRO_VERSION);
+  webkit_automation_session_set_application_info (session, info);
+  webkit_application_info_unref (info);
+
+  g_signal_connect (session, "create-web-view", G_CALLBACK (create_web_view_for_automation_cb), shell);
+}
+
+
 static void
 session_load_cb (GObject      *object,
                  GAsyncResult *result,
@@ -425,6 +461,12 @@ static void
 ephy_shell_activate (GApplication *application)
 {
   EphyShell *shell = EPHY_SHELL (application);
+  EphyEmbedShell *embed_shell = EPHY_EMBED_SHELL (shell);
+
+  if (ephy_embed_shell_get_mode (embed_shell) == EPHY_EMBED_SHELL_MODE_AUTOMATION) {
+    WebKitWebContext *web_context = ephy_embed_shell_get_web_context (embed_shell);
+    g_signal_connect (web_context, "automation-started", G_CALLBACK(automation_started_cb), shell);
+  }
 
   if (shell->remote_startup_context == NULL) {
     EphySession *session = ephy_shell_get_session (shell);
@@ -819,7 +861,7 @@ ephy_shell_get_session (EphyShell *shell)
   g_assert (EPHY_IS_SHELL (shell));
 
   mode = ephy_embed_shell_get_mode (EPHY_EMBED_SHELL (shell));
-  if (mode ==  EPHY_EMBED_SHELL_MODE_APPLICATION || mode == EPHY_EMBED_SHELL_MODE_INCOGNITO)
+  if (mode ==  EPHY_EMBED_SHELL_MODE_APPLICATION || mode == EPHY_EMBED_SHELL_MODE_INCOGNITO || mode == 
EPHY_EMBED_SHELL_MODE_AUTOMATION)
     return NULL;
 
   if (shell->session == NULL)
diff --git a/src/ephy-window.c b/src/ephy-window.c
index f9a25b0df..7ce2fc301 100644
--- a/src/ephy-window.c
+++ b/src/ephy-window.c
@@ -312,6 +312,26 @@ impl_get_is_popup (EphyEmbedContainer *container)
   return EPHY_WINDOW (container)->is_popup;
 }
 
+static void
+count_children (GtkWidget *widget,
+                guint     *n_children)
+{
+  (*n_children)++;
+}
+
+static guint
+impl_get_n_children (EphyEmbedContainer *container)
+{
+  EphyWindow *window = EPHY_WINDOW (container);
+  guint n_children = 0;
+
+  gtk_container_foreach (GTK_CONTAINER (window->notebook),
+                         (GtkCallback)count_children,
+                         &n_children);
+
+  return n_children;
+}
+
 static void
 ephy_window_embed_container_iface_init (EphyEmbedContainerInterface *iface)
 {
@@ -321,6 +341,7 @@ ephy_window_embed_container_iface_init (EphyEmbedContainerInterface *iface)
   iface->get_active_child = impl_get_active_child;
   iface->get_children = impl_get_children;
   iface->get_is_popup = impl_get_is_popup;
+  iface->get_n_children = impl_get_n_children;
 }
 
 static EphyEmbed *
@@ -1159,6 +1180,7 @@ sync_tab_bookmarked_status (EphyWebView   *view,
 {
   EphyBookmarksManager *manager = ephy_shell_get_bookmarks_manager (ephy_shell_get_default ());
   EphyEmbedShell *shell = ephy_embed_shell_get_default ();
+  EphyEmbedShellMode mode;
   EphyLocationEntryBookmarkIconState state;
   GtkWidget *widget;
   EphyBookmark *bookmark;
@@ -1170,10 +1192,12 @@ sync_tab_bookmarked_status (EphyWebView   *view,
     return;
 
   address = ephy_web_view_get_address (view);
+  mode = ephy_embed_shell_get_mode (shell);
 
   if (!address ||
       ephy_embed_utils_is_no_show_address (address) ||
-      ephy_embed_shell_get_mode (shell) == EPHY_EMBED_SHELL_MODE_INCOGNITO) {
+      mode == EPHY_EMBED_SHELL_MODE_INCOGNITO ||
+      mode == EPHY_EMBED_SHELL_MODE_AUTOMATION) {
     state = EPHY_LOCATION_ENTRY_BOOKMARK_ICON_HIDDEN;
   } else {
     bookmark = ephy_bookmarks_manager_get_bookmark_by_url (manager, address);
@@ -2688,7 +2712,9 @@ ephy_window_close_tab (EphyWindow *window,
     return;
 
   web_view = ephy_embed_get_web_view (tab);
-  if (gtk_notebook_get_n_pages (window->notebook) > 1 || ephy_web_view_is_overview (web_view)) {
+  if (gtk_notebook_get_n_pages (window->notebook) > 1 ||
+      ephy_web_view_is_overview (web_view) ||
+      ephy_embed_shell_get_mode (ephy_embed_shell_get_default ()) == EPHY_EMBED_SHELL_MODE_AUTOMATION) {
     g_object_set_data (G_OBJECT (tab), "ephy-window-close-tab-closed", GINT_TO_POINTER (TRUE));
     gtk_widget_destroy (GTK_WIDGET (tab));
 
@@ -2778,6 +2804,11 @@ notebook_page_close_request_cb (EphyNotebook *notebook,
       return;
     }
 
+    if (ephy_embed_shell_get_mode (ephy_embed_shell_get_default ()) == EPHY_EMBED_SHELL_MODE_AUTOMATION) {
+      /* Never prompt the user before closing in automation mode */
+      ephy_window_close_tab (window, embed);
+    }
+
     /* Last window, check ongoing downloads before closing the tab */
     if (ephy_shell_get_n_windows (ephy_shell_get_default ()) == 1) {
       EphyDownloadsManager *manager = ephy_embed_shell_get_downloads_manager (EPHY_EMBED_SHELL 
(ephy_shell_get_default ()));
@@ -3384,6 +3415,8 @@ ephy_window_constructed (GObject *object)
   mode = ephy_embed_shell_get_mode (ephy_embed_shell_get_default ());
   if (mode == EPHY_EMBED_SHELL_MODE_INCOGNITO)
     gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (window)), "incognito-mode");
+  else if (mode == EPHY_EMBED_SHELL_MODE_AUTOMATION)
+    gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (window)), "automation-mode");
 
   /* Setup the toolbar. */
   window->header_bar = setup_header_bar (window);
@@ -3455,6 +3488,8 @@ ephy_window_constructed (GObject *object)
     action = g_action_map_lookup_action (G_ACTION_MAP (action_group), "context-bookmark-page");
     ephy_action_change_sensitivity_flags (G_SIMPLE_ACTION (action),
                                           SENS_FLAG_CHROME, TRUE);
+  } else if (mode == EPHY_EMBED_SHELL_MODE_AUTOMATION) {
+    g_object_set (window->location_controller, "editable", FALSE, NULL);
   }
 
   window->mouse_gesture_controller = ephy_mouse_gesture_controller_new (window);
diff --git a/src/resources/themes/Adwaita.css b/src/resources/themes/Adwaita.css
index aad2aa95e..f641f3baa 100644
--- a/src/resources/themes/Adwaita.css
+++ b/src/resources/themes/Adwaita.css
@@ -41,6 +41,48 @@
 
 .incognito-mode headerbar entry:backdrop { box-shadow: none; }
 
+.automation-mode headerbar { background: #ff9600 linear-gradient(to top, #bd6f00, #f59000 2px, #ff9600 3px); 
box-shadow: inset 0 1px #ffb142; border-color: #995a00; color: rgba(46, 52, 54, 0.2); }
+
+.automation-mode headerbar > * { color: #2e3436; }
+
+.automation-mode headerbar > *:backdrop { color: #929595; }
+
+.automation-mode headerbar:backdrop { box-shadow: inset 0 1px #ffb142; color: rgba(146, 149, 149, 0.1); }
+
+.automation-mode headerbar button { color: #2e3436; outline-color: rgba(46, 52, 54, 0.3); border-color: 
#995a00; border-bottom-color: #663c00; background-image: linear-gradient(to bottom, #ff9600, #eb8a00 95%, 
#db8100 1px); text-shadow: 0 1px rgba(255, 255, 255, 0.769231); -gtk-icon-shadow: 0 1px rgba(255, 255, 255, 
0.769231); box-shadow: inset 0 1px rgba(255, 255, 255, 0.2); }
+
+.automation-mode headerbar button.flat, .automation-mode headerbar button.titlebutton { border-color: 
transparent; background-color: transparent; background-image: none; box-shadow: inset 0 1px rgba(255, 255, 
255, 0); text-shadow: none; -gtk-icon-shadow: none; }
+
+.automation-mode headerbar button.titlebutton { text-shadow: 0 1px rgba(255, 255, 255, 0.769231); 
-gtk-icon-shadow: 0 1px rgba(255, 255, 255, 0.769231); }
+
+.automation-mode headerbar button:hover { color: #2e3436; outline-color: rgba(46, 52, 54, 0.3); 
border-color: #995a00; border-bottom-color: #663c00; text-shadow: 0 1px rgba(255, 255, 255, 0.769231); 
-gtk-icon-shadow: 0 1px rgba(255, 255, 255, 0.769231); box-shadow: inset 0 1px rgba(255, 255, 255, 0.4); 
background-image: linear-gradient(to bottom, #ffa31f, #ff9600 95%, #db8100 1px); }
+
+.automation-mode headerbar button:active, .automation-mode headerbar button:checked { color: #2e3436; 
outline-color: rgba(46, 52, 54, 0.3); border-color: #995a00; background-image: image(#e08400); box-shadow: 
inset 0 1px rgba(255, 255, 255, 0); text-shadow: none; -gtk-icon-shadow: none; }
+
+.automation-mode headerbar button:disabled { border-color: #995a00; background-image: image(#ffa626); 
text-shadow: none; -gtk-icon-shadow: none; box-shadow: inset 0 1px rgba(255, 255, 255, 0); }
+
+.automation-mode headerbar button:disabled label, .automation-mode headerbar button:disabled { color: 
#929595; }
+
+.automation-mode headerbar button:backdrop { border-color: #ff9600; background-image: image(#ff9600); 
text-shadow: none; -gtk-icon-shadow: none; box-shadow: inset 0 1px rgba(255, 255, 255, 0); border-color: 
#995a00; }
+
+.automation-mode headerbar button:backdrop label, .automation-mode headerbar button:backdrop { color: 
#929595; }
+
+.automation-mode headerbar button:backdrop:active { border-color: #fc9500; background-image: image(#fc9500); 
box-shadow: inset 0 1px rgba(255, 255, 255, 0); border-color: #995a00; }
+
+.automation-mode headerbar button:backdrop:active label, .automation-mode headerbar button:backdrop:active { 
color: #929595; }
+
+.automation-mode headerbar button:backdrop:disabled { border-color: #ffa626; background-image: 
image(#ffa626); text-shadow: none; -gtk-icon-shadow: none; box-shadow: inset 0 1px rgba(255, 255, 255, 0); 
border-color: #995a00; }
+
+.automation-mode headerbar button:backdrop:disabled label, .automation-mode headerbar 
button:backdrop:disabled { color: #b67e2c; }
+
+.automation-mode headerbar button.flat:backdrop, .automation-mode headerbar button.titlebutton:backdrop { 
border-color: transparent; background-color: transparent; background-image: none; box-shadow: inset 0 1px 
rgba(255, 255, 255, 0); text-shadow: none; -gtk-icon-shadow: none; }
+
+.automation-mode headerbar entry { border-color: #995a00; }
+
+.automation-mode headerbar entry:focus { border-color: #3584e4; box-shadow: inset 0 0 0 1px #3584e4; }
+
+.automation-mode headerbar entry:backdrop { box-shadow: none; }
+
 .bookmark-tag-widget { background-color: #cfcfcd; }
 
 .bookmark-tag-widget image, .bookmark-tag-widget label { color: #2e3436; }
diff --git a/src/resources/themes/Adwaita.scss b/src/resources/themes/Adwaita.scss
index 0c1a69cce..e92db8481 100644
--- a/src/resources/themes/Adwaita.scss
+++ b/src/resources/themes/Adwaita.scss
@@ -6,7 +6,7 @@
 
 .incognito-mode {
   headerbar {
-    @include headerbar_fill($incognito_color, $edge_color, -gtk-icontheme($incognito_icon) 160px 0 / 64px 
64px no-repeat);
+    @include headerbar_fill($incognito_color, $incognito_edge_color, -gtk-icontheme($incognito_icon) 160px 0 
/ 64px 64px no-repeat);
 
     border-color: _border_color($incognito_color);
 
@@ -20,7 +20,7 @@
 
     &:backdrop {
       background-image: -gtk-icontheme($incognito_icon), image($incognito_color);
-      box-shadow: inset 0 1px $edge_color;
+      box-shadow: inset 0 1px $incognito_edge_color;
       color: transparentize($backdrop_fg_color, 0.9); // color of the overlayed icon in backdrop
     }
 
@@ -68,6 +68,69 @@
   }
 }
 
+.automation-mode {
+  headerbar {
+    @include headerbar_fill($automation_color, $automation_edge_color);
+
+    border-color: _border_color($automation_color);
+
+    color: transparentize($fg_color, 0.8); // this is the color of the overlayed icon
+
+    > * {
+      color: $fg_color;
+
+      &:backdrop { color: $backdrop_fg_color }
+    }
+
+    &:backdrop {
+//      background-image: -gtk-icontheme($incognito_icon), image($incognito_color);
+      box-shadow: inset 0 1px $automation_edge_color;
+      color: transparentize($backdrop_fg_color, 0.9); // color of the overlayed icon in backdrop
+    }
+
+    button { // changing the headerbar background color requires changing widget borders accordingly
+      @include button(normal, $automation_color);
+
+      &.flat, &.titlebutton { @include button(undecorated); }
+
+      &.titlebutton { @include _button_text_shadow($fg_color, $automation_color); }
+
+      &:hover { @include button(hover, $automation_color); }
+
+      &:active, &:checked { @include button(active, $automation_color); }
+
+      &:disabled { @include button(insensitive, $automation_color); }
+
+      &:backdrop {
+        @include button(backdrop, $automation_color);
+        border-color: _border_color($automation_color);
+
+        &:active {
+          @include button(backdrop-active, $automation_color);
+          border-color: _border_color($automation_color);
+        }
+
+        &:disabled {
+          @include button(backdrop-insensitive, $automation_color);
+          border-color: _border_color($automation_color);
+        }
+      }
+
+      &.flat:backdrop, &.titlebutton:backdrop { @include button(undecorated); }
+    }
+
+    entry {
+      border-color: _border_color($automation_color);
+
+      &:focus {
+        border-color: entry_focus_border($selected_bg_color);
+        box-shadow: entry_focus_shadow($selected_bg_color);
+      }
+
+      &:backdrop { box-shadow: none; }
+    }
+  }
+}
 
 $close_button_fg_color: lighten($fg_color, 10%);
 .bookmark-tag-widget {
diff --git a/src/resources/themes/_definitions.scss b/src/resources/themes/_definitions.scss
index 05f103d33..2e6cd4936 100644
--- a/src/resources/themes/_definitions.scss
+++ b/src/resources/themes/_definitions.scss
@@ -3,8 +3,11 @@
 //$incognito_color: #c5cfd8;
 $incognito_color: #cbd2d9;
 $incognito_icon: 'user-not-tracked-symbolic';
-$edge_color: lighten($incognito_color, 13%);
+$incognito_edge_color: lighten($incognito_color, 13%);
 
+// automation mode
+$automation_color: #ff9600;
+$automation_edge_color: lighten($automation_color, 13%);
 
 // utility function/macros and imports from the base GTK+ theme.
 
diff --git a/src/resources/themes/shared.css b/src/resources/themes/shared.css
index 67b30cb92..a64e4d8de 100644
--- a/src/resources/themes/shared.css
+++ b/src/resources/themes/shared.css
@@ -8,6 +8,8 @@
 
 .incognito-mode headerbar { background-image: -gtk-icontheme("user-not-tracked-symbolic"); 
background-repeat: no-repeat; background-position: 157px 0; background-size: 64px 64px; color: rgba(0, 0, 0, 
0.35); }
 
+.automation-mode headerbar { background-color: #ff9600; color: rgba(0, 0, 0, 0.35); }
+
 .entry_icon { color: mix(@theme_fg_color, @theme_base_color, 0.2); }
 
 .entry_icon:hover { color: @theme_fg_color; }
diff --git a/src/resources/themes/shared.scss b/src/resources/themes/shared.scss
index 9058c2d7c..84f339b9c 100644
--- a/src/resources/themes/shared.scss
+++ b/src/resources/themes/shared.scss
@@ -35,6 +35,14 @@
   }
 }
 
+// automation mode
+.automation-mode {
+  headerbar {
+    background-color: $automation_color;
+    color: rgba(0, 0, 0, 0.35);
+  }
+}
+
 // entry icons colors
 .entry_icon {
   color: #{"mix(" + themecolor(theme_fg_color) + ", " + themecolor(theme_base_color) + ", 0.2)"};


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