search: use g_get_system_data_dirs() to discover providers
Currently, the search panel looks for search providers in DATADIR/gnome-shell/search-providers. This won't work when providers are located in a different directory which is still part of XDG_DATA_DIRS, which is a valid use case and supported by gnome-shell. This commit refactors the loader code to scan all the directories upfront in a separate thread. https://bugzilla.gnome.org/show_bug.cgi?id=739148
This commit is contained in:
parent
3e89996908
commit
0a7b552d93
1 changed files with 127 additions and 74 deletions
|
@ -36,6 +36,7 @@ struct _CcSearchPanelPrivate
|
|||
GtkWidget *up_button;
|
||||
GtkWidget *down_button;
|
||||
|
||||
GCancellable *load_cancellable;
|
||||
GSettings *search_settings;
|
||||
GHashTable *sort_order;
|
||||
|
||||
|
@ -545,95 +546,146 @@ search_panel_add_one_provider (CcSearchPanel *self,
|
|||
}
|
||||
|
||||
static void
|
||||
next_search_provider_ready (GObject *source,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
search_providers_discover_ready (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
CcSearchPanel *self = user_data;
|
||||
GFile *providers_location, *provider;
|
||||
GList *files;
|
||||
GList *providers, *l;
|
||||
GFile *provider;
|
||||
CcSearchPanel *self = CC_SEARCH_PANEL (source);
|
||||
GError *error = NULL;
|
||||
gchar *path;
|
||||
|
||||
files = g_file_enumerator_next_files_finish (G_FILE_ENUMERATOR (source),
|
||||
res, &error);
|
||||
providers_location = g_file_enumerator_get_container (G_FILE_ENUMERATOR (source));
|
||||
providers = g_task_propagate_pointer (G_TASK (result), &error);
|
||||
|
||||
if (error != NULL)
|
||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
{
|
||||
path = g_file_get_path (providers_location);
|
||||
|
||||
g_warning ("Error reading from %s: %s - search providers might be missing from the panel",
|
||||
path, error->message);
|
||||
|
||||
g_error_free (error);
|
||||
g_free (path);
|
||||
}
|
||||
|
||||
if (files != NULL)
|
||||
{
|
||||
provider = g_file_get_child (providers_location, g_file_info_get_name (files->data));
|
||||
search_panel_add_one_provider (self, provider);
|
||||
g_object_unref (provider);
|
||||
|
||||
g_file_enumerator_next_files_async (G_FILE_ENUMERATOR (source), 1,
|
||||
G_PRIORITY_DEFAULT, NULL,
|
||||
next_search_provider_ready, self);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* propagate a write to GSettings, to make sure we always have
|
||||
* all the providers in the list.
|
||||
*/
|
||||
search_panel_propagate_sort_order (self);
|
||||
}
|
||||
|
||||
g_list_free_full (files, g_object_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
enumerate_search_providers_ready (GObject *source,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
CcSearchPanel *self = user_data;
|
||||
GFileEnumerator *enumerator;
|
||||
GError *error = NULL;
|
||||
gchar *path;
|
||||
|
||||
enumerator = g_file_enumerate_children_finish (G_FILE (source), res, &error);
|
||||
if (error != NULL)
|
||||
{
|
||||
path = g_file_get_path (G_FILE (source));
|
||||
|
||||
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
|
||||
g_warning ("Error opening %s: %s - search provider configuration won't be possible",
|
||||
path, error->message);
|
||||
|
||||
search_panel_set_no_providers (self);
|
||||
g_error_free (error);
|
||||
return;
|
||||
}
|
||||
|
||||
g_file_enumerator_next_files_async (enumerator, 1,
|
||||
G_PRIORITY_DEFAULT, NULL,
|
||||
next_search_provider_ready, self);
|
||||
g_object_unref (enumerator);
|
||||
g_clear_object (&self->priv->load_cancellable);
|
||||
|
||||
if (providers == NULL)
|
||||
{
|
||||
search_panel_set_no_providers (self);
|
||||
return;
|
||||
}
|
||||
|
||||
for (l = providers; l != NULL; l = l->next)
|
||||
{
|
||||
provider = l->data;
|
||||
search_panel_add_one_provider (self, provider);
|
||||
g_object_unref (provider);
|
||||
}
|
||||
|
||||
/* propagate a write to GSettings, to make sure we always have
|
||||
* all the providers in the list.
|
||||
*/
|
||||
search_panel_propagate_sort_order (self);
|
||||
g_list_free (providers);
|
||||
}
|
||||
|
||||
static GList *
|
||||
search_providers_discover_one_directory (const gchar *system_dir,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
GList *providers = NULL;
|
||||
gchar *providers_path;
|
||||
GFile *providers_location, *provider;
|
||||
GFileInfo *info;
|
||||
GFileEnumerator *enumerator;
|
||||
GError *error = NULL;
|
||||
|
||||
providers_path = g_build_filename (system_dir, "gnome-shell", "search-providers", NULL);
|
||||
providers_location = g_file_new_for_path (providers_path);
|
||||
|
||||
enumerator = g_file_enumerate_children (providers_location,
|
||||
"standard::type,standard::name,standard::content-type",
|
||||
G_FILE_QUERY_INFO_NONE,
|
||||
cancellable, &error);
|
||||
|
||||
if (error != NULL)
|
||||
{
|
||||
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) &&
|
||||
!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
g_warning ("Error opening %s: %s - search provider configuration won't be possible",
|
||||
providers_path, error->message);
|
||||
g_clear_error (&error);
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
while ((info = g_file_enumerator_next_file (enumerator, cancellable, &error)) != NULL)
|
||||
{
|
||||
provider = g_file_get_child (providers_location, g_file_info_get_name (info));
|
||||
providers = g_list_prepend (providers, provider);
|
||||
g_object_unref (info);
|
||||
}
|
||||
|
||||
if (error != NULL)
|
||||
{
|
||||
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
g_warning ("Error reading from %s: %s - search providers might be missing from the panel",
|
||||
providers_path, error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
|
||||
out:
|
||||
g_clear_object (&enumerator);
|
||||
g_clear_object (&providers_location);
|
||||
g_free (providers_path);
|
||||
|
||||
return providers;
|
||||
}
|
||||
|
||||
static void
|
||||
search_providers_discover_thread (GTask *task,
|
||||
gpointer source_object,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
GList *providers = NULL;
|
||||
const gchar * const *system_data_dirs;
|
||||
int idx;
|
||||
|
||||
system_data_dirs = g_get_system_data_dirs ();
|
||||
for (idx = 0; system_data_dirs[idx] != NULL; idx++)
|
||||
{
|
||||
providers = g_list_concat (search_providers_discover_one_directory (system_data_dirs[idx], cancellable),
|
||||
providers);
|
||||
|
||||
if (g_task_return_error_if_cancelled (task))
|
||||
{
|
||||
g_list_free_full (providers, g_object_unref);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
g_task_return_pointer (task, providers, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
populate_search_providers (CcSearchPanel *self)
|
||||
{
|
||||
GFile *providers_location;
|
||||
GTask *task;
|
||||
|
||||
providers_location = g_file_new_for_path (DATADIR "/gnome-shell/search-providers");
|
||||
g_file_enumerate_children_async (providers_location,
|
||||
"standard::type,standard::name,standard::content-type",
|
||||
G_FILE_QUERY_INFO_NONE,
|
||||
G_PRIORITY_DEFAULT,
|
||||
NULL,
|
||||
enumerate_search_providers_ready, self);
|
||||
g_object_unref (providers_location);
|
||||
self->priv->load_cancellable = g_cancellable_new ();
|
||||
task = g_task_new (self, self->priv->load_cancellable,
|
||||
search_providers_discover_ready, self);
|
||||
g_task_run_in_thread (task, search_providers_discover_thread);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
cc_search_panel_dispose (GObject *object)
|
||||
{
|
||||
CcSearchPanelPrivate *priv = CC_SEARCH_PANEL (object)->priv;
|
||||
|
||||
if (priv->load_cancellable != NULL)
|
||||
g_cancellable_cancel (priv->load_cancellable);
|
||||
g_clear_object (&priv->load_cancellable);
|
||||
|
||||
G_OBJECT_CLASS (cc_search_panel_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -752,6 +804,7 @@ cc_search_panel_class_init (CcSearchPanelClass *klass)
|
|||
GObjectClass *oclass = G_OBJECT_CLASS (klass);
|
||||
|
||||
oclass->constructed = cc_search_panel_constructed;
|
||||
oclass->dispose = cc_search_panel_dispose;
|
||||
oclass->finalize = cc_search_panel_finalize;
|
||||
|
||||
g_type_class_add_private (klass, sizeof (CcSearchPanelPrivate));
|
||||
|
|
Loading…
Add table
Reference in a new issue