[nautilus] shell-provider: implement search provider methods
- From: Cosimo Cecchi <cosimoc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [nautilus] shell-provider: implement search provider methods
- Date: Thu, 6 Sep 2012 14:06:52 +0000 (UTC)
commit 320317dc38acaa9bc407975059df29b886dc1e94
Author: Cosimo Cecchi <cosimoc gnome org>
Date: Wed Sep 5 17:23:52 2012 -0400
shell-provider: implement search provider methods
Wire the methods with an implementation that uses NautilusSearchEngine
to get results.
src/nautilus-shell-search-provider.c | 395 +++++++++++++++++++++++++++++++++-
1 files changed, 385 insertions(+), 10 deletions(-)
---
diff --git a/src/nautilus-shell-search-provider.c b/src/nautilus-shell-search-provider.c
index cc626e7..502f65c 100644
--- a/src/nautilus-shell-search-provider.c
+++ b/src/nautilus-shell-search-provider.c
@@ -26,17 +26,33 @@
#include <gio/gio.h>
+#include <libnautilus-private/nautilus-file.h>
+#include <libnautilus-private/nautilus-file-utilities.h>
+#include <libnautilus-private/nautilus-search-engine.h>
+#include <libnautilus-private/nautilus-search-provider.h>
+
#include "nautilus-shell-search-provider-generated.h"
#define SEARCH_PROVIDER_INACTIVITY_TIMEOUT 12000 /* milliseconds */
typedef struct {
+ NautilusSearchEngine *engine;
+ NautilusQuery *query;
+
+ GHashTable *hits;
+ GDBusMethodInvocation *invocation;
+
+ gint64 start_time;
+} PendingSearch;
+
+typedef struct {
GApplication parent;
guint name_owner_id;
-
GDBusObjectManagerServer *object_manager;
NautilusShellSearchProvider *skeleton;
+
+ PendingSearch *current_search;
} NautilusShellSearchProviderApp;
typedef GApplicationClass NautilusShellSearchProviderAppClass;
@@ -49,33 +65,389 @@ GType nautilus_shell_search_provider_app_get_type (void);
G_DEFINE_TYPE (NautilusShellSearchProviderApp, nautilus_shell_search_provider_app, G_TYPE_APPLICATION)
+static GVariant *
+variant_from_pixbuf (GdkPixbuf *pixbuf)
+{
+ GVariant *variant;
+ guchar *data;
+ guint length;
+
+ data = gdk_pixbuf_get_pixels_with_length (pixbuf, &length);
+ variant = g_variant_new ("(iiibii ay)",
+ gdk_pixbuf_get_width (pixbuf),
+ gdk_pixbuf_get_height (pixbuf),
+ gdk_pixbuf_get_rowstride (pixbuf),
+ gdk_pixbuf_get_has_alpha (pixbuf),
+ gdk_pixbuf_get_bits_per_sample (pixbuf),
+ gdk_pixbuf_get_n_channels (pixbuf),
+ g_variant_new_from_data (G_VARIANT_TYPE_BYTESTRING,
+ data, length, TRUE,
+ (GDestroyNotify)g_object_unref,
+ g_object_ref (pixbuf)));
+ return variant;
+}
+
static void
-handle_get_initial_result_set (GDBusMethodInvocation *invocation,
- gchar **terms)
+pending_search_free (PendingSearch *search)
{
+ g_hash_table_destroy (search->hits);
+ g_clear_object (&search->query);
+ g_clear_object (&search->engine);
+ g_slice_free (PendingSearch, search);
}
static void
-handle_get_subsearch_result_set (GDBusMethodInvocation *invocation,
- gchar **previous_results,
- gchar **terms)
+finish_current_search (NautilusShellSearchProviderApp *self,
+ GDBusMethodInvocation *invocation,
+ GVariant *result)
{
+ g_dbus_method_invocation_return_value (invocation, result);
+
+ if (self->current_search != NULL) {
+ g_application_release (G_APPLICATION (self));
+
+ pending_search_free (self->current_search);
+ self->current_search = NULL;
+ }
+}
+
+static void
+cancel_current_search (NautilusShellSearchProviderApp *self)
+{
+ PendingSearch *search = self->current_search;
+
+ if (search == NULL)
+ return;
+
+ nautilus_search_provider_stop (NAUTILUS_SEARCH_PROVIDER (search->engine));
+ finish_current_search (self, search->invocation, g_variant_new ("(as)", NULL));
+}
+
+static void
+search_hits_added_cb (NautilusSearchEngine *engine,
+ GList *hits,
+ gpointer user_data)
+
+{
+ NautilusShellSearchProviderApp *self = user_data;
+ PendingSearch *search = self->current_search;
+ GList *l;
+ NautilusSearchHit *hit;
+ const gchar *hit_uri;
+ g_debug ("*** Search engine hits added");
+
+ for (l = hits; l != NULL; l = l->next) {
+ hit = l->data;
+ nautilus_search_hit_compute_scores (hit, search->query);
+ hit_uri = nautilus_search_hit_get_uri (hit);
+ g_debug (" %s", hit_uri);
+
+ g_hash_table_replace (search->hits, g_strdup (hit_uri), g_object_ref (hit));
+ }
}
static void
-handle_get_result_metas (GDBusMethodInvocation *invocation,
- gchar **results)
+search_hits_subtracted_cb (NautilusSearchEngine *engine,
+ GList *hits,
+ gpointer user_data)
{
+ NautilusShellSearchProviderApp *self = user_data;
+ PendingSearch *search = self->current_search;
+ GList *l;
+ NautilusSearchHit *hit;
+ const gchar *hit_uri;
+ g_debug ("*** Search engine hits subtracted");
+
+ for (l = hits; l != NULL; l = l->next) {
+ hit = l->data;
+ hit_uri = nautilus_search_hit_get_uri (hit);
+ g_debug (" %s", hit_uri);
+
+ g_hash_table_remove (search->hits, hit_uri);
+ }
+}
+
+static gint
+search_hit_compare_relevance (gconstpointer a,
+ gconstpointer b)
+{
+ NautilusSearchHit *hit_a, *hit_b;
+ gdouble relevance_a, relevance_b;
+
+ hit_a = NAUTILUS_SEARCH_HIT (a);
+ hit_b = NAUTILUS_SEARCH_HIT (b);
+
+ relevance_a = nautilus_search_hit_get_relevance (hit_a);
+ relevance_b = nautilus_search_hit_get_relevance (hit_b);
+
+ if (relevance_a > relevance_b)
+ return -1;
+ else if (relevance_a == relevance_b)
+ return 0;
+
+ return 1;
}
static void
-handle_activate_result (GDBusMethodInvocation *invocation,
- gchar *result)
+search_finished_cb (NautilusSearchEngine *engine,
+ gpointer user_data)
{
+ NautilusShellSearchProviderApp *self = user_data;
+ PendingSearch *search = self->current_search;
+ GList *hits, *l;
+ NautilusSearchHit *hit;
+ GVariantBuilder builder;
+ gint64 current_time;
+
+ current_time = g_get_monotonic_time ();
+ g_debug ("*** Search engine search finished - time elapsed %dms",
+ (gint) ((current_time - search->start_time) / 1000));
+
+ hits = g_hash_table_get_values (search->hits);
+ hits = g_list_sort (hits, search_hit_compare_relevance);
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
+
+ for (l = hits; l != NULL; l = l->next) {
+ hit = l->data;
+ g_variant_builder_add (&builder, "s", nautilus_search_hit_get_uri (hit));
+ }
+ g_list_free (hits);
+ finish_current_search (self, search->invocation,
+ g_variant_new ("(as)", &builder));
+}
+
+static void
+search_error_cb (NautilusSearchEngine *engine,
+ const gchar *error_message,
+ gpointer user_data)
+{
+ NautilusShellSearchProviderApp *self = user_data;
+ PendingSearch *search = self->current_search;
+
+ g_debug ("*** Search engine search error");
+ finish_current_search (self, search->invocation, g_variant_new ("(as)", NULL));
+}
+
+static void
+execute_search (NautilusShellSearchProviderApp *self,
+ GDBusMethodInvocation *invocation,
+ gchar **terms)
+{
+ gchar *terms_joined, *home_uri;
+ NautilusQuery *query;
+ PendingSearch *pending_search;
+
+ if (self->current_search != NULL)
+ cancel_current_search (self);
+
+ /* don't attempt searches for a single character */
+ if (g_strv_length (terms) == 1 &&
+ g_utf8_strlen (terms[0], -1) == 1) {
+ finish_current_search (self, invocation,
+ g_variant_new ("(as)", NULL));
+ return;
+ }
+
+ terms_joined = g_strjoinv (" ", terms);
+ home_uri = nautilus_get_home_directory_uri ();
+
+ query = nautilus_query_new ();
+ nautilus_query_set_text (query, terms_joined);
+ nautilus_query_set_location (query, home_uri);
+
+ pending_search = g_slice_new0 (PendingSearch);
+ pending_search->invocation = invocation;
+ pending_search->hits = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
+ pending_search->query = query;
+ pending_search->engine = nautilus_search_engine_new ();
+ pending_search->start_time = g_get_monotonic_time ();
+
+ g_signal_connect (pending_search->engine, "hits-added",
+ G_CALLBACK (search_hits_added_cb), self);
+ g_signal_connect (pending_search->engine, "hits-subtracted",
+ G_CALLBACK (search_hits_subtracted_cb), self);
+ g_signal_connect (pending_search->engine, "finished",
+ G_CALLBACK (search_finished_cb), self);
+ g_signal_connect (pending_search->engine, "error",
+ G_CALLBACK (search_error_cb), self);
+
+ self->current_search = pending_search;
+ g_application_hold (G_APPLICATION (self));
+
+ /* start searching */
+ g_debug ("*** Search engine search started");
+ nautilus_search_provider_set_query (NAUTILUS_SEARCH_PROVIDER (pending_search->engine),
+ query);
+ nautilus_search_provider_start (NAUTILUS_SEARCH_PROVIDER (pending_search->engine));
+
+ g_free (home_uri);
+ g_free (terms_joined);
+}
+
+static void
+handle_get_initial_result_set (NautilusShellSearchProvider *skeleton,
+ GDBusMethodInvocation *invocation,
+ gchar **terms,
+ gpointer user_data)
+{
+ NautilusShellSearchProviderApp *self = user_data;
+
+ g_debug ("****** GetInitialResultSet");
+ execute_search (self, invocation, terms);
+}
+
+static void
+handle_get_subsearch_result_set (NautilusShellSearchProvider *skeleton,
+ GDBusMethodInvocation *invocation,
+ gchar **previous_results,
+ gchar **terms,
+ gpointer user_data)
+{
+ NautilusShellSearchProviderApp *self = user_data;
+
+ g_debug ("****** GetSubSearchResultSet");
+ execute_search (self, invocation, terms);
+}
+
+typedef struct {
+ NautilusShellSearchProviderApp *self;
+
+ gint64 start_time;
+ GDBusMethodInvocation *invocation;
+} ResultMetasData;
+
+static void
+result_metas_data_free (ResultMetasData *data)
+{
+ g_clear_object (&data->self);
+ g_slice_free (ResultMetasData, data);
+}
+
+static void
+result_list_attributes_ready_cb (GList *file_list,
+ gpointer user_data)
+{
+ ResultMetasData *data = user_data;
+ GVariantBuilder builder, meta;
+ NautilusFile *file;
+ GList *l;
+ gchar *uri, *display_name;
+ GdkPixbuf *pix;
+ gint64 current_time;
+ gchar *thumbnail_path, *gicon_str;
+ GIcon *gicon;
+ GFile *location;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}"));
+
+ for (l = file_list; l != NULL; l = l->next) {
+ file = l->data;
+ g_variant_builder_init (&meta, G_VARIANT_TYPE ("a{sv}"));
+
+ uri = nautilus_file_get_uri (file);
+ display_name = nautilus_file_get_display_name (file);
+ pix = nautilus_file_get_icon_pixbuf (file, 128, TRUE,
+ NAUTILUS_FILE_ICON_FLAGS_USE_THUMBNAILS);
+
+ g_variant_builder_add (&meta, "{sv}",
+ "id", g_variant_new_string (uri));
+ g_variant_builder_add (&meta, "{sv}",
+ "name", g_variant_new_string (display_name));
+
+ gicon = NULL;
+ thumbnail_path = nautilus_file_get_thumbnail_path (file);
+
+ if (thumbnail_path != NULL) {
+ location = g_file_new_for_path (thumbnail_path);
+ gicon = g_file_icon_new (location);
+
+ g_free (thumbnail_path);
+ g_object_unref (location);
+ } else {
+ gicon = nautilus_file_get_gicon (file, 0);
+ }
+
+ if (gicon != NULL) {
+ gicon_str = g_icon_to_string (gicon);
+ g_variant_builder_add (&meta, "{sv}",
+ "gicon", g_variant_new_string (gicon_str));
+
+ g_free (gicon_str);
+ g_object_unref (gicon);
+ } else {
+ pix = nautilus_file_get_icon_pixbuf (file, 128, TRUE,
+ NAUTILUS_FILE_ICON_FLAGS_USE_THUMBNAILS);
+
+ g_variant_builder_add (&meta, "{sv}",
+ "icon-data", variant_from_pixbuf (pix));
+ g_object_unref (pix);
+ }
+
+ g_variant_builder_add (&builder, "a{sv}", &meta);
+
+ g_free (display_name);
+ g_free (uri);
+ }
+
+ current_time = g_get_monotonic_time ();
+ g_debug ("*** GetResultMetas completed - time elapsed %dms",
+ (gint) ((current_time - data->start_time) / 1000));
+
+ g_dbus_method_invocation_return_value (data->invocation,
+ g_variant_new ("(aa{sv})", &builder));
+ result_metas_data_free (data);
+}
+
+static void
+handle_get_result_metas (NautilusShellSearchProvider *skeleton,
+ GDBusMethodInvocation *invocation,
+ gchar **results,
+ gpointer user_data)
+{
+ NautilusShellSearchProviderApp *self = user_data;
+ GList *nautilus_files = NULL;
+ const gchar *uri;
+ ResultMetasData *data;
+ gint idx;
+
+ g_debug ("****** GetResultMetas");
+
+ for (idx = 0; results[idx] != NULL; idx++) {
+ uri = results[idx];
+ nautilus_files = g_list_prepend (nautilus_files, nautilus_file_get_by_uri (uri));
+ }
+
+ data = g_slice_new0 (ResultMetasData);
+ data->self = g_object_ref (self);
+ data->invocation = invocation;
+ data->start_time = g_get_monotonic_time ();
+
+ nautilus_file_list_call_when_ready (nautilus_files,
+ NAUTILUS_FILE_ATTRIBUTES_FOR_ICON,
+ NULL,
+ result_list_attributes_ready_cb,
+ data);
+ nautilus_file_list_free (nautilus_files);
+}
+
+static void
+handle_activate_result (NautilusShellSearchProvider *skeleton,
+ GDBusMethodInvocation *invocation,
+ gchar *result,
+ gpointer user_data)
+{
+ GError *error = NULL;
+
+ gtk_show_uri (NULL, result, GDK_CURRENT_TIME, &error);
+ if (error != NULL) {
+ g_warning ("Unable to activate %s: %s", result, error->message);
+ g_error_free (error);
+ }
}
static void
@@ -135,6 +507,7 @@ search_provider_app_dispose (GObject *obj)
}
g_clear_object (&self->object_manager);
+ cancel_current_search (self);
G_OBJECT_CLASS (nautilus_shell_search_provider_app_parent_class)->dispose (obj);
}
@@ -195,6 +568,8 @@ main (int argc,
GApplication *app;
gint res;
+ gtk_init (&argc, &argv);
+
app = nautilus_shell_search_provider_app_new ();
res = g_application_run (app, argc, argv);
g_object_unref (app);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]