summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan-Michael Brummer <jan.brummer@tabos.org>2021-01-10 16:44:31 +0100
committerJan-Michael Brummer <jan.brummer@tabos.org>2021-01-15 08:33:30 +0000
commita334cad703988767b60222138e3fc5d2461ee988 (patch)
treedec1fc6bc6b628fc364d2039e3913999a68fec17
parentd4e218dbafa22878eb9187f514548e637653d32b (diff)
downloadepiphany-a334cad703988767b60222138e3fc5d2461ee988.tar.gz
Add support for Google Search Suggestions
-rw-r--r--data/org.gnome.epiphany.gschema.xml5
-rw-r--r--lib/ephy-prefs.h1
-rw-r--r--src/ephy-suggestion-model.c214
-rw-r--r--src/preferences/prefs-privacy-page.c15
-rw-r--r--src/resources/gtk/prefs-privacy-page.ui21
5 files changed, 209 insertions, 47 deletions
diff --git a/data/org.gnome.epiphany.gschema.xml b/data/org.gnome.epiphany.gschema.xml
index 5badc3006..99800b3f2 100644
--- a/data/org.gnome.epiphany.gschema.xml
+++ b/data/org.gnome.epiphany.gschema.xml
@@ -33,6 +33,11 @@
<summary>Default search engines.</summary>
<description>List of the default search engines. It is an array in which each search engine is described by a name, an address, and a bang (shortcut).</description>
</key>
+ <key type="b" name="use-google-search-suggestions">
+ <default>false</default>
+ <summary>Enable Google Search Suggestions</summary>
+ <description>Whether to show Google Search Suggestion in url entry popdown.</description>
+ </key>
<key type="b" name="new-windows-in-tabs">
<default>true</default>
<summary>Force new windows to be opened in tabs</summary>
diff --git a/lib/ephy-prefs.h b/lib/ephy-prefs.h
index 9b1a8545c..fb0f37ef8 100644
--- a/lib/ephy-prefs.h
+++ b/lib/ephy-prefs.h
@@ -161,6 +161,7 @@ static const char * const ephy_prefs_web_schema[] = {
#define EPHY_PREFS_ASK_FOR_DEFAULT "ask-for-default"
#define EPHY_PREFS_START_IN_INCOGNITO_MODE "start-in-incognito-mode"
#define EPHY_PREFS_ACTIVE_CLEAR_DATA_ITEMS "active-clear-data-items"
+#define EPHY_PREFS_USE_GOOGLE_SEARCH_SUGGESTIONS "use-google-search-suggestions"
#define EPHY_PREFS_LOCKDOWN_SCHEMA "org.gnome.Epiphany.lockdown"
#define EPHY_PREFS_LOCKDOWN_FULLSCREEN "disable-fullscreen"
diff --git a/src/ephy-suggestion-model.c b/src/ephy-suggestion-model.c
index 106b39c8b..1c5fb6793 100644
--- a/src/ephy-suggestion-model.c
+++ b/src/ephy-suggestion-model.c
@@ -20,8 +20,11 @@
#include "ephy-suggestion-model.h"
#include "ephy-embed-shell.h"
+#include "ephy-prefs.h"
#include "ephy-search-engine-manager.h"
+#include "ephy-settings.h"
#include "ephy-suggestion.h"
+#include "ephy-user-agent.h"
#include "ephy-window.h"
#include <dazzle.h>
@@ -37,6 +40,7 @@ struct _EphySuggestionModel {
GSequence *items;
GCancellable *icon_cancellable;
guint num_custom_entries;
+ SoupSession *session;
};
enum {
@@ -62,6 +66,7 @@ ephy_suggestion_model_finalize (GObject *object)
g_clear_object (&self->history_service);
g_clear_pointer (&self->urls, g_sequence_free);
g_clear_pointer (&self->items, g_sequence_free);
+ g_clear_object (&self->session);
g_cancellable_cancel (self->icon_cancellable);
g_clear_object (&self->icon_cancellable);
@@ -139,6 +144,7 @@ static void
ephy_suggestion_model_init (EphySuggestionModel *self)
{
self->items = g_sequence_new (g_object_unref);
+ self->session = soup_session_new_with_options ("user-agent", ephy_user_agent_get (), NULL);
}
static GType
@@ -283,8 +289,12 @@ static gboolean
append_suggestion (EphySuggestionModel *self,
EphySuggestion *suggestion)
{
+ if (g_sequence_lookup (self->urls, (char *)ephy_suggestion_get_uri (suggestion), (GCompareDataFunc)g_strcmp0, NULL))
+ return FALSE;
+
if (self->num_custom_entries < MAX_URL_ENTRIES) {
- g_sequence_append (self->items, suggestion);
+ g_sequence_append (self->items, g_object_ref (suggestion));
+ load_favicon (self, suggestion, ephy_suggestion_get_uri (suggestion));
self->num_custom_entries++;
return TRUE;
@@ -349,42 +359,6 @@ add_bookmarks (EphySuggestionModel *self,
}
static guint
-add_history (EphySuggestionModel *self,
- GList *urls,
- const char *query)
-{
- guint added = 0;
-
- for (const GList *p = urls; p != NULL; p = p->next) {
- EphyHistoryURL *url = (EphyHistoryURL *)p->data;
- EphySuggestion *suggestion;
- g_autofree gchar *escaped_title = NULL;
- g_autofree gchar *markup = NULL;
- const gchar *title = url->title;
-
- if (g_sequence_lookup (self->urls, url->url, (GCompareDataFunc)g_strcmp0,
- NULL))
- continue;
-
- if (strlen (url->title) == 0)
- title = url->url;
-
- escaped_title = g_markup_escape_text (title, -1);
-
- markup = dzl_fuzzy_highlight (escaped_title, query, FALSE);
- suggestion = ephy_suggestion_new (markup, title, url->url);
- load_favicon (self, suggestion, url->url);
-
- if (append_suggestion (self, suggestion))
- added++;
- else
- break;
- }
-
- return added;
-}
-
-static guint
add_search_engines (EphySuggestionModel *self,
const char *query)
{
@@ -505,6 +479,9 @@ add_tabs (EphySuggestionModel *self,
typedef struct {
char *query;
gboolean include_search_engines;
+ GSequence *history;
+ GSequence *google_suggestions;
+ int active_sources;
} QueryData;
static QueryData *
@@ -516,6 +493,8 @@ query_data_new (const char *query,
data = g_malloc0 (sizeof (QueryData));
data->query = g_strdup (query);
data->include_search_engines = include_search_engines;
+ data->history = g_sequence_new (g_object_unref);
+ data->google_suggestions = g_sequence_new (g_object_unref);
return data;
}
@@ -524,26 +503,27 @@ static void
query_data_free (QueryData *data)
{
g_assert (data != NULL);
+ g_clear_pointer (&data->history, g_sequence_free);
+ g_clear_pointer (&data->google_suggestions, g_sequence_free);
g_free (data->query);
g_free (data);
}
static void
-query_completed_cb (EphyHistoryService *service,
- gboolean success,
- gpointer result_data,
- gpointer user_data)
+query_collection_done (EphySuggestionModel *self,
+ GTask *task)
{
- GTask *task = user_data;
- EphySuggestionModel *self;
QueryData *data;
- GList *urls;
guint removed;
guint added = 0;
self = g_task_get_source_object (task);
data = g_task_get_task_data (task);
- urls = (GList *)result_data;
+
+ if (--data->active_sources) {
+ g_object_unref (task);
+ return;
+ }
g_cancellable_cancel (self->icon_cancellable);
g_clear_object (&self->icon_cancellable);
@@ -560,8 +540,26 @@ query_completed_cb (EphyHistoryService *service,
if (strlen (data->query) > 0) {
added = add_tabs (self, data->query);
+
+ for (GSequenceIter *iter = g_sequence_get_begin_iter (data->google_suggestions); !g_sequence_iter_is_end (iter); iter = g_sequence_iter_next (iter)) {
+ EphySuggestion *tmp = g_sequence_get (iter);
+
+ if (append_suggestion (self, tmp))
+ added++;
+ else
+ break;
+ }
+
added += add_bookmarks (self, data->query);
- added += add_history (self, urls, data->query);
+
+ for (GSequenceIter *iter = g_sequence_get_begin_iter (data->history); !g_sequence_iter_is_end (iter); iter = g_sequence_iter_next (iter)) {
+ EphySuggestion *tmp = g_sequence_get (iter);
+
+ if (append_suggestion (self, tmp))
+ added++;
+ else
+ break;
+ }
if (data->include_search_engines)
added += add_search_engines (self, data->query);
@@ -573,6 +571,119 @@ query_completed_cb (EphyHistoryService *service,
g_object_unref (task);
}
+static void
+history_query_completed_cb (EphyHistoryService *service,
+ gboolean success,
+ gpointer result_data,
+ gpointer user_data)
+{
+ GTask *task = user_data;
+ EphySuggestionModel *self;
+ QueryData *data;
+ GList *urls;
+
+ self = g_task_get_source_object (task);
+ data = g_task_get_task_data (task);
+ urls = (GList *)result_data;
+
+ if (strlen (data->query) > 0) {
+ for (const GList *p = urls; p != NULL; p = p->next) {
+ EphyHistoryURL *url = (EphyHistoryURL *)p->data;
+ EphySuggestion *suggestion;
+ g_autofree gchar *escaped_title = NULL;
+ g_autofree gchar *markup = NULL;
+ const gchar *title = url->title;
+
+ if (strlen (url->title) == 0)
+ title = url->url;
+
+ escaped_title = g_markup_escape_text (title, -1);
+
+ markup = dzl_fuzzy_highlight (escaped_title, data->query, FALSE);
+ suggestion = ephy_suggestion_new (markup, title, url->url);
+
+ g_sequence_append (data->history, g_steal_pointer (&suggestion));
+ }
+ }
+
+ query_collection_done (self, g_steal_pointer (&task));
+}
+
+static void
+google_search_suggestions_cb (SoupSession *session,
+ SoupMessage *msg,
+ gpointer user_data)
+{
+ GTask *task = G_TASK (user_data);
+ EphySuggestionModel *self = g_task_get_source_object (task);
+ EphyEmbedShell *shell;
+ EphySearchEngineManager *manager;
+ QueryData *data;
+ JsonNode *node;
+ JsonArray *array;
+ JsonArray *suggestions;
+ char *engine;
+ int added = 0;
+
+ if (msg->status_code != 200)
+ goto out;
+
+ shell = ephy_embed_shell_get_default ();
+ manager = ephy_embed_shell_get_search_engine_manager (shell);
+ engine = ephy_search_engine_manager_get_default_engine (manager);
+
+ node = json_from_string (msg->response_body->data, NULL);
+ if (!node || !JSON_NODE_HOLDS_ARRAY (node)) {
+ g_warning ("Google search suggestion response is not a valid JSON object: %s", msg->response_body->data);
+ goto out;
+ }
+
+ array = json_node_get_array (node);
+ suggestions = json_array_get_array_element (array, 1);
+ data = g_task_get_task_data (task);
+
+ for (guint i = 0; i < json_array_get_length (suggestions) && added < 5; i++) {
+ EphySuggestion *suggestion;
+ const char *str = json_array_get_string_element (suggestions, i);
+ g_autofree char *address = NULL;
+ g_autofree char *escaped_title = NULL;
+ g_autofree char *markup = NULL;
+
+ address = ephy_search_engine_manager_build_search_address (manager, engine, str);
+ escaped_title = g_markup_escape_text (str, -1);
+ markup = dzl_fuzzy_highlight (escaped_title, str, FALSE);
+ suggestion = ephy_suggestion_new (markup, engine, address);
+
+ g_sequence_append (data->google_suggestions, g_steal_pointer (&suggestion));
+ added++;
+ }
+
+out:
+ query_collection_done (self, g_steal_pointer (&task));
+}
+
+static void
+google_search_suggestions_query (EphySuggestionModel *self,
+ const gchar *query,
+ GTask *task)
+{
+ SoupMessage *msg;
+ g_auto (GStrv) split = g_strsplit (query, " ", -1);
+ g_autofree char *url = NULL;
+ g_autofree char *escaped_query = NULL;
+
+ if (g_strv_length (split) < 2) {
+ query_collection_done (self, g_steal_pointer (&task));
+ return;
+ }
+
+ escaped_query = g_markup_escape_text (query, -1);
+ url = g_strdup_printf ("http://suggestqueries.google.com/complete/search?client=firefox&q=%s", escaped_query);
+ msg = soup_message_new (SOUP_METHOD_GET, url);
+
+ soup_session_queue_message (self->session, g_steal_pointer (&msg), google_search_suggestions_cb, g_steal_pointer (&task));
+}
+
void
ephy_suggestion_model_query_async (EphySuggestionModel *self,
const gchar *query,
@@ -601,13 +712,22 @@ ephy_suggestion_model_query_async (EphySuggestionModel *self,
for (guint i = 0; strings[i]; i++)
qlist = g_list_append (qlist, g_strdup (strings[i]));
+ /* History */
+ data->active_sources = 1;
+
+ /* Google Search Suggestions */
+ if (g_settings_get_boolean (EPHY_SETTINGS_MAIN, EPHY_PREFS_USE_GOOGLE_SEARCH_SUGGESTIONS)) {
+ data->active_sources++;
+ google_search_suggestions_query (self, query, g_object_ref (task));
+ }
+
ephy_history_service_find_urls (self->history_service,
0, 0,
MAX_URL_ENTRIES, 0,
qlist,
EPHY_HISTORY_SORT_MOST_VISITED,
cancellable,
- (EphyHistoryJobCallback)query_completed_cb,
+ (EphyHistoryJobCallback)history_query_completed_cb,
task);
g_strfreev (strings);
diff --git a/src/preferences/prefs-privacy-page.c b/src/preferences/prefs-privacy-page.c
index a5fc7d98c..d8caea0e9 100644
--- a/src/preferences/prefs-privacy-page.c
+++ b/src/preferences/prefs-privacy-page.c
@@ -44,6 +44,9 @@ struct _PrefsPrivacyPage {
GtkWidget *enable_itp_switch;
GtkWidget *enable_website_data_storage_switch;
+ /* Search Suggestions */
+ GtkWidget *enable_google_search_suggestions_switch;
+
/* Passwords */
GtkWidget *remember_passwords_switch;
};
@@ -107,6 +110,15 @@ setup_privacy_page (PrefsPrivacyPage *privacy_page)
privacy_page->remember_passwords_switch,
"active",
G_SETTINGS_BIND_DEFAULT);
+
+ /* ======================================================================== */
+ /* ========================== Search Suggestions ========================== */
+ /* ======================================================================== */
+ g_settings_bind (EPHY_SETTINGS_MAIN,
+ EPHY_PREFS_USE_GOOGLE_SEARCH_SUGGESTIONS,
+ privacy_page->enable_google_search_suggestions_switch,
+ "active",
+ G_SETTINGS_BIND_DEFAULT);
}
static void
@@ -139,6 +151,9 @@ prefs_privacy_page_class_init (PrefsPrivacyPageClass *klass)
gtk_widget_class_bind_template_child (widget_class, PrefsPrivacyPage, enable_itp_switch);
gtk_widget_class_bind_template_child (widget_class, PrefsPrivacyPage, enable_website_data_storage_switch);
+ /* Search Suggestions */
+ gtk_widget_class_bind_template_child (widget_class, PrefsPrivacyPage, enable_google_search_suggestions_switch);
+
/* Passwords */
gtk_widget_class_bind_template_child (widget_class, PrefsPrivacyPage, remember_passwords_switch);
diff --git a/src/resources/gtk/prefs-privacy-page.ui b/src/resources/gtk/prefs-privacy-page.ui
index 8be4e548b..bf61d6b91 100644
--- a/src/resources/gtk/prefs-privacy-page.ui
+++ b/src/resources/gtk/prefs-privacy-page.ui
@@ -62,6 +62,27 @@
</child>
<child>
<object class="HdyPreferencesGroup">
+ <property name="title" translatable="yes">Search Suggestions</property>
+ <property name="visible">True</property>
+ <child>
+ <object class="HdyActionRow">
+ <property name="activatable_widget">enable_google_search_suggestions_switch</property>
+ <property name="subtitle" translatable="yes">Enable search suggestions in the URL entry.</property>
+ <property name="title" translatable="yes">_Google Search Suggestions</property>
+ <property name="use_underline">True</property>
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkSwitch" id="enable_google_search_suggestions_switch">
+ <property name="valign">center</property>
+ <property name="visible">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="HdyPreferencesGroup">
<property name="title" translatable="yes">Personal Data</property>
<property name="visible">True</property>
<child>