[gnome-control-center/wip/applications] applications: implement search



commit b8de76448c0ce7b6b24ec98ba1d9e74f91bad8d3
Author: Matthias Clasen <mclasen redhat com>
Date:   Sun Dec 9 16:54:28 2018 -0500

    applications: implement search

 panels/applications/cc-applications-panel.c  | 303 +++++++++++++++++++++++----
 panels/applications/cc-applications-panel.ui |   6 +
 2 files changed, 264 insertions(+), 45 deletions(-)
---
diff --git a/panels/applications/cc-applications-panel.c b/panels/applications/cc-applications-panel.c
index 311077eb2..015254b4d 100644
--- a/panels/applications/cc-applications-panel.c
+++ b/panels/applications/cc-applications-panel.c
@@ -35,7 +35,6 @@
 #include <flatpak/flatpak.h>
 
 /* Todo
- * - search
  *
  * Missing in flatpak:
  * - background
@@ -64,11 +63,13 @@ struct _CcApplicationsPanel
   char *current_app_id;
 
   GHashTable *globs;
+  GHashTable *search_providers;
 
   GDBusProxy *perm_store;
   GSettings *notification_settings;
   GSettings *location_settings;
   GSettings *privacy_settings;
+  GSettings *search_settings;
 
   GtkListBox *stack;
   GtkWidget *permission_section;
@@ -83,13 +84,15 @@ struct _CcApplicationsPanel
   GtkWidget *no_location;
   GtkWidget *microphone;
   GtkWidget *no_microphone;
+  GtkWidget *builtin;
 
   GtkWidget *integration_section;
   GtkWidget *integration_list;
   GtkWidget *notification;
   GtkWidget *sound;
   GtkWidget *no_sound;
-  GtkWidget *builtin;
+  GtkWidget *search;
+  GtkWidget *no_search;
 
   GtkWidget *device_section;
   GtkWidget *device_list;
@@ -146,10 +149,12 @@ cc_applications_panel_finalize (GObject *object)
   g_clear_object (&self->notification_settings);
   g_clear_object (&self->location_settings);
   g_clear_object (&self->privacy_settings);
+  g_clear_object (&self->search_settings);
   g_clear_object (&self->cancellable);
 
   g_free (self->current_app_id);
   g_hash_table_unref (self->globs);
+  g_hash_table_unref (self->search_providers);
 
   G_OBJECT_CLASS (cc_applications_panel_parent_class)->finalize (object);
 }
@@ -226,10 +231,101 @@ set_flatpak_permissions (CcApplicationsPanel *self,
                           0, G_MAXINT, NULL, NULL);
 }
 
+static void
+set_search_enabled (CcApplicationsPanel *self,
+                    const char *app_id,
+                    gboolean enabled)
+{
+  gpointer key, value;
+  gboolean default_disabled;
+  g_auto(GStrv) apps = NULL;
+  g_autoptr(GPtrArray) new_apps = NULL;
+  int i;
+  g_autofree char *desktop_id = g_strconcat (app_id, ".desktop", NULL);
+
+  if (!g_hash_table_lookup_extended (self->search_providers, app_id, &key, &value))
+    {
+      g_warning ("Trying to configure search for a provider-less app - this shouldn't happen");
+      return;
+    }
+
+  default_disabled = GPOINTER_TO_INT (value);
+
+  new_apps = g_ptr_array_new_with_free_func (g_free);
+  if (default_disabled)
+    {
+      apps = g_settings_get_strv (self->search_settings, "enabled");
+      for (i = 0; apps[i]; i++)
+        {
+          if (strcmp (apps[i], desktop_id) != 0)
+            g_ptr_array_add (new_apps, g_strdup (apps[i]));
+        }
+      if (enabled)
+        g_ptr_array_add (new_apps, g_strdup (desktop_id));
+      g_ptr_array_add (new_apps, NULL);
+      g_settings_set_strv (self->search_settings, "enabled",  (const char * const *)new_apps->pdata);
+    }
+  else
+    {
+      apps = g_settings_get_strv (self->search_settings, "disabled");
+      for (i = 0; apps[i]; i++)
+        {
+          if (strcmp (apps[i], desktop_id) != 0)
+            g_ptr_array_add (new_apps, g_strdup (apps[i]));
+        }
+      if (!enabled)
+        g_ptr_array_add (new_apps, g_strdup (desktop_id));
+      g_ptr_array_add (new_apps, NULL);
+      g_settings_set_strv (self->search_settings, "disabled", (const char * const *)new_apps->pdata);
+    }
+}
+
+static gboolean
+search_enabled_for_app (CcApplicationsPanel *self,
+                        const char *app_id)
+{
+  g_autofree char *desktop_id = g_strconcat (app_id, ".desktop", NULL);
+  g_auto(GStrv) apps = g_settings_get_strv (self->search_settings, "enabled");
+  return g_strv_contains ((const char * const *)apps, desktop_id);
+}
+
+static gboolean
+search_disabled_for_app (CcApplicationsPanel *self,
+                         const char *app_id)
+{
+  g_autofree char *desktop_id = g_strconcat (app_id, ".desktop", NULL);
+  g_auto(GStrv) apps = g_settings_get_strv (self->search_settings, "disabled");
+  return g_strv_contains ((const char * const *)apps, desktop_id);
+}
+
+static void
+get_search_enabled (CcApplicationsPanel *self,
+                    const char *app_id,
+                    gboolean *set,
+                    gboolean *enabled)
+{
+  gpointer key, value;
+
+  *enabled = FALSE;
+  *set = g_hash_table_lookup_extended (self->search_providers, app_id, &key, &value);
+  if (!*set)
+    return;
+
+  if (search_enabled_for_app (self, app_id))
+    *enabled = TRUE;
+  else if (search_disabled_for_app (self, app_id))
+    *enabled = FALSE;
+  else
+    *enabled = !GPOINTER_TO_INT (value); 
+}
+
 static void
 search_cb (CcApplicationsPanel *self)
 {
-  g_print ("search not implemented\n");
+  if (self->current_app_id)
+    set_search_enabled (self,
+                        self->current_app_id,
+                        cc_toggle_row_get_allowed (CC_TOGGLE_ROW (self->search)));
 }
 
 static gboolean
@@ -678,6 +774,12 @@ update_integration_section (CcApplicationsPanel *self,
   gboolean set, allowed, disabled;
   gboolean has_any = FALSE;
 
+  disabled = g_settings_get_boolean (self->search_settings, "disable-external");
+  get_search_enabled (self, app_id, &set, &allowed);
+  cc_toggle_row_set_allowed (CC_TOGGLE_ROW (self->search), allowed);
+  gtk_widget_set_visible (self->search, set && !disabled);
+  gtk_widget_set_visible (self->no_search, set && disabled);
+
   if (app_info_is_flatpak (info))
     {
       g_clear_object (&self->notification_settings);
@@ -1322,35 +1424,6 @@ populate_applications (CcApplicationsPanel *self)
   g_list_free_full (infos, g_object_unref);
 }
 
-static void
-prepare_content (CcApplicationsPanel *self)
-{
-  gtk_list_box_set_header_func (GTK_LIST_BOX (self->permission_list),
-                                cc_list_box_update_header_func,
-                                NULL, NULL);
-
-  gtk_list_box_set_header_func (GTK_LIST_BOX (self->integration_list),
-                                cc_list_box_update_header_func,
-                                NULL, NULL);
-
-  gtk_list_box_set_header_func (GTK_LIST_BOX (self->handler_list),
-                                cc_list_box_update_header_func,
-                                NULL, NULL);
-
-  gtk_list_box_set_header_func (GTK_LIST_BOX (self->usage_list),
-                                cc_list_box_update_header_func,
-                                NULL, NULL);
-
-  gtk_list_box_set_header_func (GTK_LIST_BOX (self->builtin_list),
-                                cc_list_box_update_header_func,
-                                NULL, NULL);
-
-  gtk_list_box_set_header_func (GTK_LIST_BOX (self->storage_list),
-                                cc_list_box_update_header_func,
-                                NULL, NULL);
-
-}
-
 static int
 compare_rows (GtkListBoxRow *row1,
               GtkListBoxRow *row2,
@@ -1474,29 +1547,143 @@ cc_applications_panel_set_property (GObject *object,
 static void
 parse_globs (CcApplicationsPanel *self)
 {
-  g_autofree char *contents = NULL;
+  const char * const *dirs;
+  int i;
 
   self->globs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
 
-  if (g_file_get_contents ("/usr/share/mime/globs", &contents, NULL, NULL))
+  dirs = g_get_system_data_dirs ();
+
+  for (i = 0; dirs[i]; i++)
     {
-      g_auto(GStrv) strv = NULL;
-      int i;
+      g_autofree char *globs = g_build_filename (dirs[i], "mime/globs", NULL);
+      g_autofree char *contents = NULL;
 
-      strv = g_strsplit (contents, "\n", 0);
-      for (i = 0; strv[i]; i++)
+      if (g_file_get_contents (globs, &contents, NULL, NULL))
         {
-          g_auto(GStrv) parts = NULL;
+          g_auto(GStrv) strv = NULL;
+          int i;
+
+          strv = g_strsplit (contents, "\n", 0);
+          for (i = 0; strv[i]; i++)
+            {
+              g_auto(GStrv) parts = NULL;
+
+              if (strv[i][0] == '#' || strv[i][0] == '\0')
+                continue;
+
+              parts = g_strsplit (strv[i], ":", 2);
+              g_hash_table_insert (self->globs, g_strdup (parts[0]), g_strdup (parts[1]));
+            }
+        }
+    }
+}
+
+#define SHELL_PROVIDER_GROUP "Shell Search Provider"
+
+static void
+add_one_provider (CcApplicationsPanel *self,
+                  GFile *provider)
+{
+  g_autofree gchar *path = NULL;
+  g_autofree gchar *app_id = NULL;
+  g_autoptr(GKeyFile) keyfile = NULL;
+  g_autoptr(GAppInfo) app_info = NULL;
+  g_autoptr(GError) error = NULL;
+  gboolean default_disabled;
+
+  path = g_file_get_path (provider);
+  keyfile = g_key_file_new ();
+  g_key_file_load_from_file (keyfile, path, G_KEY_FILE_NONE, &error);
+
+  if (error != NULL)
+    {
+      g_warning ("Error loading %s: %s - search provider will be ignored",
+                 path, error->message);
+      return;
+    }
+
+  if (!g_key_file_has_group (keyfile, SHELL_PROVIDER_GROUP))
+    {
+      g_debug ("Shell search provider group missing from '%s', ignoring", path);
+      return;
+    }
 
-          if (strv[i][0] == '#' || strv[i][0] == '\0')
-            continue;
+  app_id = g_key_file_get_string (keyfile, SHELL_PROVIDER_GROUP, "DesktopId", &error);
+
+  if (error != NULL)
+    {
+      g_warning ("Unable to read desktop ID from %s: %s - search provider will be ignored",
+                 path, error->message);
+      return;
+    }
+
+  if (g_str_has_suffix (app_id, ".desktop"))
+    app_id[strlen (app_id) - strlen (".desktop")] = '\0';
+
+  default_disabled = g_key_file_get_boolean (keyfile, SHELL_PROVIDER_GROUP, "DefaultDisabled", NULL);
+
+  g_hash_table_insert (self->search_providers, g_strdup (app_id), GINT_TO_POINTER (default_disabled));
+}
+
+static void
+parse_search_providers_one_dir (CcApplicationsPanel *self,
+                                const char *system_dir)
+{
+  g_autofree char *providers_path = NULL;
+  g_autoptr(GFile) providers_location = NULL;
+  g_autoptr(GFileEnumerator) enumerator = NULL;
+  g_autoptr(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,
+                                          NULL, &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);
+      return;
+    }
 
-          parts = g_strsplit (strv[i], ":", 2);
-          g_hash_table_insert (self->globs, g_strdup (parts[0]), g_strdup (parts[1]));
+  while (TRUE)
+    {
+      GFile *provider = NULL;
+
+      if (!g_file_enumerator_iterate (enumerator, NULL, &provider, NULL, &error))
+        {
+          g_warning ("Error while reading %s: %s - search provider configuration won't be possible",
+                   providers_path, error->message);
+          return;
         }
+
+      if (provider == NULL)
+        break;
+
+      add_one_provider (self, provider);
     }
 }
 
+static void
+parse_search_providers (CcApplicationsPanel *self)
+{
+  const char * const *dirs;
+  int i;
+
+  self->search_providers = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+  dirs = g_get_system_data_dirs ();
+
+  for (i = 0; dirs[i]; i++)
+    parse_search_providers_one_dir (self, dirs[i]);
+}
+
 static void
 cc_applications_panel_class_init (CcApplicationsPanelClass *klass)
 {
@@ -1537,6 +1724,8 @@ cc_applications_panel_class_init (CcApplicationsPanelClass *klass)
   gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, notification);
   gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, sound);
   gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, no_sound);
+  gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, search);
+  gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, no_search);
   gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, device_section);
   gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, device_list);
   gtk_widget_class_bind_template_child (widget_class, CcApplicationsPanel, handler_section);
@@ -1577,6 +1766,30 @@ cc_applications_panel_init (CcApplicationsPanel *self)
 
   gtk_widget_init_template (GTK_WIDGET (self));
 
+  gtk_list_box_set_header_func (GTK_LIST_BOX (self->permission_list),
+                                cc_list_box_update_header_func,
+                                NULL, NULL);
+
+  gtk_list_box_set_header_func (GTK_LIST_BOX (self->integration_list),
+                                cc_list_box_update_header_func,
+                                NULL, NULL);
+
+  gtk_list_box_set_header_func (GTK_LIST_BOX (self->handler_list),
+                                cc_list_box_update_header_func,
+                                NULL, NULL);
+
+  gtk_list_box_set_header_func (GTK_LIST_BOX (self->usage_list),
+                                cc_list_box_update_header_func,
+                                NULL, NULL);
+
+  gtk_list_box_set_header_func (GTK_LIST_BOX (self->builtin_list),
+                                cc_list_box_update_header_func,
+                                NULL, NULL);
+
+  gtk_list_box_set_header_func (GTK_LIST_BOX (self->storage_list),
+                                cc_list_box_update_header_func,
+                                NULL, NULL);
+
   provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
   gtk_css_provider_load_from_resource (GTK_CSS_PROVIDER (provider),
                                        "/org/gnome/control-center/applications/cc-applications-panel.css");
@@ -1593,14 +1806,13 @@ cc_applications_panel_init (CcApplicationsPanel *self)
 
   self->location_settings = g_settings_new ("org.gnome.system.location");
   self->privacy_settings = g_settings_new ("org.gnome.desktop.privacy");
+  self->search_settings = g_settings_new ("org.gnome.desktop.search-providers");
 
   populate_applications (self);
 
   self->monitor = g_app_info_monitor_get ();
   self->monitor_id = g_signal_connect (self->monitor, "changed", G_CALLBACK (apps_changed), self);
 
-  prepare_content (self);
-
   g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
                             G_DBUS_PROXY_FLAGS_NONE,
                             NULL,
@@ -1612,4 +1824,5 @@ cc_applications_panel_init (CcApplicationsPanel *self)
                             self);
 
   parse_globs (self);
+  parse_search_providers (self);
 }
diff --git a/panels/applications/cc-applications-panel.ui b/panels/applications/cc-applications-panel.ui
index 4a02dd052..c7cc3d931 100644
--- a/panels/applications/cc-applications-panel.ui
+++ b/panels/applications/cc-applications-panel.ui
@@ -284,6 +284,12 @@
                                 <signal name="notify::allowed" handler="search_cb" swapped="yes"/>
                               </object>
                             </child>
+                            <child>
+                              <object class="CcInfoRow" id="no_search">
+                                <property name="title" translatable="yes">Search</property>
+                                <property name="info" translatable="yes">Disabled</property>
+                              </object>
+                            </child>
                             <child>
                               <object class="CcToggleRow" id="notification">
                                 <property name="title" translatable="yes">Notifications</property>


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