From 28a84367b866dd277d7f3a0f063d20ccef240a4e Mon Sep 17 00:00:00 2001 From: Carlos Garcia Campos Date: Thu, 3 Jan 2019 15:25:46 +0100 Subject: [PATCH] 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 | 23 ++++++++- src/resources/themes/Adwaita.css | 42 ++++++++++++++++ src/resources/themes/Adwaita.scss | 66 +++++++++++++++++++++++++- src/resources/themes/_definitions.scss | 5 +- src/resources/themes/shared.css | 2 + src/resources/themes/shared.scss | 8 ++++ 17 files changed, 279 insertions(+), 24 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..1090d266f 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..1c8e20716 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", "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 e082b9389..956be4cbd 100644 --- a/src/ephy-window.c +++ b/src/ephy-window.c @@ -312,6 +312,14 @@ impl_get_is_popup (EphyEmbedContainer *container) return EPHY_WINDOW (container)->is_popup; } +static guint +impl_get_n_children (EphyEmbedContainer *container) +{ + EphyWindow *window = EPHY_WINDOW (container); + + return gtk_notebook_get_n_pages (window->notebook); +} + static void ephy_window_embed_container_iface_init (EphyEmbedContainerInterface *iface) { @@ -321,6 +329,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 +1168,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 +1180,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); @@ -2771,6 +2783,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 ())); @@ -3377,6 +3394,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); @@ -3448,6 +3467,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..a584b1a47 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,68 @@ } } +.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 { + 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)"}; -- 2.18.1