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:
Cosimo Cecchi 2014-10-24 12:55:48 -07:00 committed by Cosimo Cecchi
parent 3e89996908
commit 0a7b552d93

View file

@ -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));