[gnome-control-center] search: use g_get_system_data_dirs() to discover providers



commit 0a7b552d936fef90111dfb69c112fcf2a8add8ca
Author: Cosimo Cecchi <cosimo endlessm com>
Date:   Fri Oct 24 12:55:48 2014 -0700

    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

 panels/search/cc-search-panel.c |  169 +++++++++++++++++++++++++-------------
 1 files changed, 111 insertions(+), 58 deletions(-)
---
diff --git a/panels/search/cc-search-panel.c b/panels/search/cc-search-panel.c
index 717c3e7..d2a0f3b 100644
--- a/panels/search/cc-search-panel.c
+++ b/panels/search/cc-search-panel.c
@@ -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_error_free (error);
+      return;
+    }
 
-      g_warning ("Error reading from %s: %s - search providers might be missing from the panel",
-                 path, error->message);
+  g_clear_object (&self->priv->load_cancellable);
 
-      g_error_free (error);
-      g_free (path);
+  if (providers == NULL)
+    {
+      search_panel_set_no_providers (self);
+      return;
     }
 
-  if (files != NULL)
+  for (l = providers; l != NULL; l = l->next)
     {
-      provider = g_file_get_child (providers_location, g_file_info_get_name (files->data));
+      provider = l->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);
+  /* 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 void
-enumerate_search_providers_ready (GObject *source,
-                                  GAsyncResult *res,
-                                  gpointer user_data)
+static GList *
+search_providers_discover_one_directory (const gchar *system_dir,
+                                         GCancellable *cancellable)
 {
-  CcSearchPanel *self = user_data;
+  GList *providers = NULL;
+  gchar *providers_path;
+  GFile *providers_location, *provider;
+  GFileInfo *info;
   GFileEnumerator *enumerator;
   GError *error = NULL;
-  gchar *path;
 
-  enumerator = g_file_enumerate_children_finish (G_FILE (source), res, &error);
+  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)
     {
-      path = g_file_get_path (G_FILE (source));
-
-      if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
+      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",
-                   path, error->message);
+                   providers_path, error->message);
+      g_clear_error (&error);
 
-      search_panel_set_no_providers (self);
-      g_error_free (error);
-      return;
+      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_file_enumerator_next_files_async (enumerator, 1,
-                                      G_PRIORITY_DEFAULT, NULL,
-                                      next_search_provider_ready, self);
-  g_object_unref (enumerator);
+  g_task_return_pointer (task, providers, NULL);
 }
 
 static void
 populate_search_providers (CcSearchPanel *self)
 {
-  GFile *providers_location;
-
-  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);
+  GTask *task;
+
+  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));


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]