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 *up_button;
|
||||||
GtkWidget *down_button;
|
GtkWidget *down_button;
|
||||||
|
|
||||||
|
GCancellable *load_cancellable;
|
||||||
GSettings *search_settings;
|
GSettings *search_settings;
|
||||||
GHashTable *sort_order;
|
GHashTable *sort_order;
|
||||||
|
|
||||||
|
@ -545,95 +546,146 @@ search_panel_add_one_provider (CcSearchPanel *self,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
next_search_provider_ready (GObject *source,
|
search_providers_discover_ready (GObject *source,
|
||||||
GAsyncResult *res,
|
GAsyncResult *result,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
CcSearchPanel *self = user_data;
|
GList *providers, *l;
|
||||||
GFile *providers_location, *provider;
|
GFile *provider;
|
||||||
GList *files;
|
CcSearchPanel *self = CC_SEARCH_PANEL (source);
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
gchar *path;
|
|
||||||
|
|
||||||
files = g_file_enumerator_next_files_finish (G_FILE_ENUMERATOR (source),
|
providers = g_task_propagate_pointer (G_TASK (result), &error);
|
||||||
res, &error);
|
|
||||||
providers_location = g_file_enumerator_get_container (G_FILE_ENUMERATOR (source));
|
|
||||||
|
|
||||||
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);
|
g_error_free (error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_file_enumerator_next_files_async (enumerator, 1,
|
g_clear_object (&self->priv->load_cancellable);
|
||||||
G_PRIORITY_DEFAULT, NULL,
|
|
||||||
next_search_provider_ready, self);
|
if (providers == NULL)
|
||||||
g_object_unref (enumerator);
|
{
|
||||||
|
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
|
static void
|
||||||
populate_search_providers (CcSearchPanel *self)
|
populate_search_providers (CcSearchPanel *self)
|
||||||
{
|
{
|
||||||
GFile *providers_location;
|
GTask *task;
|
||||||
|
|
||||||
providers_location = g_file_new_for_path (DATADIR "/gnome-shell/search-providers");
|
self->priv->load_cancellable = g_cancellable_new ();
|
||||||
g_file_enumerate_children_async (providers_location,
|
task = g_task_new (self, self->priv->load_cancellable,
|
||||||
"standard::type,standard::name,standard::content-type",
|
search_providers_discover_ready, self);
|
||||||
G_FILE_QUERY_INFO_NONE,
|
g_task_run_in_thread (task, search_providers_discover_thread);
|
||||||
G_PRIORITY_DEFAULT,
|
g_object_unref (task);
|
||||||
NULL,
|
}
|
||||||
enumerate_search_providers_ready, self);
|
|
||||||
g_object_unref (providers_location);
|
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
|
static void
|
||||||
|
@ -752,6 +804,7 @@ cc_search_panel_class_init (CcSearchPanelClass *klass)
|
||||||
GObjectClass *oclass = G_OBJECT_CLASS (klass);
|
GObjectClass *oclass = G_OBJECT_CLASS (klass);
|
||||||
|
|
||||||
oclass->constructed = cc_search_panel_constructed;
|
oclass->constructed = cc_search_panel_constructed;
|
||||||
|
oclass->dispose = cc_search_panel_dispose;
|
||||||
oclass->finalize = cc_search_panel_finalize;
|
oclass->finalize = cc_search_panel_finalize;
|
||||||
|
|
||||||
g_type_class_add_private (klass, sizeof (CcSearchPanelPrivate));
|
g_type_class_add_private (klass, sizeof (CcSearchPanelPrivate));
|
||||||
|
|
Loading…
Add table
Reference in a new issue