diff options
author | Carlos Garnacho <carlosg@gnome.org> | 2020-05-17 00:04:56 +0200 |
---|---|---|
committer | Carlos Garnacho <carlosg@gnome.org> | 2020-05-19 22:03:39 +0200 |
commit | ae776046fc94cb755294bbe7d9cc838c57d37477 (patch) | |
tree | 884a006078f7e148050a3478f994e1e5e3637bc1 | |
parent | 5858f7c5bd48de5cd7b951be1460b23f5e43b657 (diff) | |
download | gtk+-ae776046fc94cb755294bbe7d9cc838c57d37477.tar.gz |
gtksearchengine: Add tracker3 search engine
Make this dependency optional at build time, and prefer it over
the old tracker <= 2.x implementation.
-rw-r--r-- | config.h.meson | 3 | ||||
-rw-r--r-- | gtk/gtksearchengine.c | 23 | ||||
-rw-r--r-- | gtk/gtksearchenginetracker3.c | 383 | ||||
-rw-r--r-- | gtk/gtksearchenginetracker3.h | 45 | ||||
-rw-r--r-- | gtk/meson.build | 8 | ||||
-rw-r--r-- | meson.build | 10 | ||||
-rw-r--r-- | meson_options.txt | 2 |
7 files changed, 469 insertions, 5 deletions
diff --git a/config.h.meson b/config.h.meson index 480f5689eb..2af55473fc 100644 --- a/config.h.meson +++ b/config.h.meson @@ -281,3 +281,6 @@ #mesondefine GTK_LOCALEDIR #mesondefine ISO_CODES_PREFIX + +/* Define if tracker3 is available */ +#mesondefine HAVE_TRACKER3
\ No newline at end of file diff --git a/gtk/gtksearchengine.c b/gtk/gtksearchengine.c index b30bc4c38e..49ae39ce32 100644 --- a/gtk/gtksearchengine.c +++ b/gtk/gtksearchengine.c @@ -22,17 +22,19 @@ #include "config.h" #include "gtksearchengine.h" #include "gtksearchenginesimple.h" -#include "gtksearchenginetracker.h" #include "gtksearchenginemodel.h" #include "gtksearchenginequartz.h" #include "gtkintl.h" -#include <gdk/gdk.h> /* for GDK_WINDOWING_QUARTZ */ - -#ifndef G_OS_WIN32 /* No tracker on Windows */ +#if defined(HAVE_TRACKER3) +#include "gtksearchenginetracker3.h" +#elif !defined G_OS_WIN32 /* No tracker on windows */ +#include "gtksearchenginetracker.h" #define HAVE_TRACKER 1 #endif +#include <gdk/gdk.h> /* for GDK_WINDOWING_QUARTZ */ + struct _GtkSearchEnginePrivate { GtkSearchEngine *native; gboolean native_running; @@ -372,7 +374,18 @@ _gtk_search_engine_new (void) g_debug ("Using simple search engine"); connect_engine_signals (engine->priv->simple, engine); -#ifdef HAVE_TRACKER +#if defined(HAVE_TRACKER3) + engine->priv->native = gtk_search_engine_tracker3_new (); + if (engine->priv->native) + { + g_debug ("Using Tracker3 search engine"); + connect_engine_signals (engine->priv->native, engine); + _gtk_search_engine_simple_set_indexed_cb (GTK_SEARCH_ENGINE_SIMPLE (engine->priv->simple), + gtk_search_engine_tracker3_is_indexed, + g_object_ref (engine->priv->native), + g_object_unref); + } +#elif defined(HAVE_TRACKER) engine->priv->native = _gtk_search_engine_tracker_new (); if (engine->priv->native) { diff --git a/gtk/gtksearchenginetracker3.c b/gtk/gtksearchenginetracker3.c new file mode 100644 index 0000000000..7221cd6c1c --- /dev/null +++ b/gtk/gtksearchenginetracker3.c @@ -0,0 +1,383 @@ +/* + * Copyright (C) 2020 Red Hat Inc + * Copyright (C) 2009-2011 Nokia <ivan.frade@nokia.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Authors: Carlos Garnacho <carlosg@gnome.org> + * Jürg Billeter <juerg.billeter@codethink.co.uk> + * Martyn Russell <martyn@lanedo.com> + * + * Based on nautilus-search-engine-tracker.c + */ + +#include "config.h" + +#include <string.h> + +#include <gio/gio.h> +#include <gmodule.h> +#include <gdk/gdk.h> +#include <gtk/gtk.h> +#include <libtracker-sparql/tracker-sparql.h> + +#include "gtksearchenginetracker3.h" + +#define MINER_FS_BUS_NAME "org.freedesktop.Tracker3.Miner.Files" + +#define SEARCH_QUERY_BASE(__PATTERN__) \ + "SELECT ?url " \ + "FROM tracker:FileSystem " \ + "WHERE {" \ + " ?urn a nfo:FileDataObject ;" \ + " nie:url ?url ; " \ + " fts:match ~match . " \ + __PATTERN__ \ + "} " \ + "ORDER BY DESC(fts:rank(?urn)) DESC(?url)" + +#define SEARCH_QUERY SEARCH_QUERY_BASE("") +#define SEARCH_RECURSIVE_QUERY SEARCH_QUERY_BASE("?urn (nfo:belongsToContainer/nie:isStoredAs)+/nie:url ~location") +#define SEARCH_LOCATION_QUERY SEARCH_QUERY_BASE("?urn nfo:belongsToContainer/nie:isStoredAs/nie:url ~location") +#define FILE_CHECK_QUERY "ASK { ?urn nie:url ~url }" + +struct _GtkSearchEngineTracker3 +{ + GtkSearchEngine parent; + TrackerSparqlConnection *sparql_conn; + TrackerSparqlStatement *search_query; + TrackerSparqlStatement *search_recursive_query; + TrackerSparqlStatement *search_location_query; + TrackerSparqlStatement *file_check_query; + GCancellable *cancellable; + GtkQuery *query; + gboolean query_pending; +}; + +struct _GtkSearchEngineTracker3Class +{ + GtkSearchEngineClass parent_class; +}; + +static void gtk_search_engine_tracker3_initable_iface_init (GInitableIface *iface); + +G_DEFINE_TYPE_WITH_CODE (GtkSearchEngineTracker3, + gtk_search_engine_tracker3, + GTK_TYPE_SEARCH_ENGINE, + G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, + gtk_search_engine_tracker3_initable_iface_init)) + +static void +finalize (GObject *object) +{ + GtkSearchEngineTracker3 *engine; + + g_debug ("Finalizing GtkSearchEngineTracker3"); + + engine = GTK_SEARCH_ENGINE_TRACKER3 (object); + + if (engine->cancellable) + { + g_cancellable_cancel (engine->cancellable); + g_object_unref (engine->cancellable); + } + + g_clear_object (&engine->search_query); + g_clear_object (&engine->search_location_query); + g_clear_object (&engine->file_check_query); + tracker_sparql_connection_close (engine->sparql_conn); + g_clear_object (&engine->sparql_conn); + + G_OBJECT_CLASS (gtk_search_engine_tracker3_parent_class)->finalize (object); +} + +static void +free_hit (gpointer data) +{ + GtkSearchHit *hit = data; + + g_clear_object (&hit->file); + g_clear_object (&hit->info); + g_slice_free (GtkSearchHit, hit); +} + +static void +query_callback (TrackerSparqlStatement *statement, + GAsyncResult *res, + gpointer user_data) +{ + GtkSearchEngineTracker3 *engine; + TrackerSparqlCursor *cursor; + GList *hits = NULL; + GError *error = NULL; + GtkSearchHit *hit; + + engine = GTK_SEARCH_ENGINE_TRACKER3 (user_data); + + engine->query_pending = FALSE; + + cursor = tracker_sparql_statement_execute_finish (statement, res, &error); + + if (!cursor) + { + _gtk_search_engine_error (GTK_SEARCH_ENGINE (engine), error->message); + g_error_free (error); + g_object_unref (engine); + return; + } + + while (tracker_sparql_cursor_next (cursor, NULL, NULL)) + { + const gchar *url; + + url = tracker_sparql_cursor_get_string (cursor, 0, NULL); + hit = g_slice_new0 (GtkSearchHit); + hit->file = g_file_new_for_uri (url); + hits = g_list_prepend (hits, hit); + } + + tracker_sparql_cursor_close (cursor); + + _gtk_search_engine_hits_added (GTK_SEARCH_ENGINE (engine), hits); + _gtk_search_engine_finished (GTK_SEARCH_ENGINE (engine), hits != NULL); + + g_list_free_full (hits, free_hit); + g_object_unref (engine); + g_object_unref (cursor); +} + +static void +gtk_search_engine_tracker3_start (GtkSearchEngine *engine) +{ + GtkSearchEngineTracker3 *tracker; + TrackerSparqlStatement *statement; + const gchar *search_text; + gboolean recursive; + gchar *match; + GFile *location; + + tracker = GTK_SEARCH_ENGINE_TRACKER3 (engine); + + if (tracker->query_pending) + { + g_debug ("Attempt to start a new search while one is pending, doing nothing"); + return; + } + + if (tracker->query == NULL) + { + g_debug ("Attempt to start a new search with no GtkQuery, doing nothing"); + return; + } + + tracker->query_pending = TRUE; + search_text = gtk_query_get_text (tracker->query); + location = gtk_query_get_location (tracker->query); + recursive = _gtk_search_engine_get_recursive (engine); + + if (location) + { + gchar *location_uri = g_file_get_uri (location); + + if (recursive) + { + g_debug ("Recursive search query in location: %s", location_uri); + statement = tracker->search_recursive_query; + } + else + { + g_debug ("Search query in location: %s", location_uri); + statement = tracker->search_location_query; + } + + tracker_sparql_statement_bind_string (statement, + "location", + location_uri); + g_free (location_uri); + } + else + { + g_debug ("Search query"); + statement = tracker->search_query; + } + + match = g_strdup_printf ("%s*", search_text); + tracker_sparql_statement_bind_string (statement, "match", match); + g_debug ("search text: %s\n", match); + tracker_sparql_statement_execute_async (statement, tracker->cancellable, + (GAsyncReadyCallback) query_callback, + g_object_ref (tracker)); + g_free (match); +} + +static void +gtk_search_engine_tracker3_stop (GtkSearchEngine *engine) +{ + GtkSearchEngineTracker3 *tracker; + + tracker = GTK_SEARCH_ENGINE_TRACKER3 (engine); + + if (tracker->query && tracker->query_pending) + { + g_cancellable_cancel (tracker->cancellable); + tracker->query_pending = FALSE; + } +} + +static void +gtk_search_engine_tracker3_set_query (GtkSearchEngine *engine, + GtkQuery *query) +{ + GtkSearchEngineTracker3 *tracker; + + tracker = GTK_SEARCH_ENGINE_TRACKER3 (engine); + + if (query) + g_object_ref (query); + + if (tracker->query) + g_object_unref (tracker->query); + + tracker->query = query; +} + +static void +gtk_search_engine_tracker3_class_init (GtkSearchEngineTracker3Class *class) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (class); + GtkSearchEngineClass *engine_class = GTK_SEARCH_ENGINE_CLASS (class); + + gobject_class->finalize = finalize; + + engine_class->set_query = gtk_search_engine_tracker3_set_query; + engine_class->start = gtk_search_engine_tracker3_start; + engine_class->stop = gtk_search_engine_tracker3_stop; +} + +static void +gtk_search_engine_tracker3_init (GtkSearchEngineTracker3 *engine) +{ + engine->cancellable = g_cancellable_new (); + engine->query_pending = FALSE; +} + +static gboolean +gtk_search_engine_tracker3_initable_init (GInitable *initable, + GCancellable *cancellable, + GError **error) +{ + GtkSearchEngineTracker3 *engine; + + engine = GTK_SEARCH_ENGINE_TRACKER3 (initable); + + engine->sparql_conn = tracker_sparql_connection_bus_new (MINER_FS_BUS_NAME, + NULL, NULL, + error); + if (!engine->sparql_conn) + return FALSE; + + engine->search_query = + tracker_sparql_connection_query_statement (engine->sparql_conn, + SEARCH_QUERY, + cancellable, + error); + if (!engine->search_query) + return FALSE; + + engine->search_recursive_query = + tracker_sparql_connection_query_statement (engine->sparql_conn, + SEARCH_RECURSIVE_QUERY, + cancellable, + error); + if (!engine->search_recursive_query) + return FALSE; + + engine->search_location_query = + tracker_sparql_connection_query_statement (engine->sparql_conn, + SEARCH_LOCATION_QUERY, + cancellable, + error); + if (!engine->search_location_query) + return FALSE; + + engine->file_check_query = + tracker_sparql_connection_query_statement (engine->sparql_conn, + FILE_CHECK_QUERY, + cancellable, + error); + if (!engine->file_check_query) + return FALSE; + + return TRUE; +} + +static void +gtk_search_engine_tracker3_initable_iface_init (GInitableIface *iface) +{ + iface->init = gtk_search_engine_tracker3_initable_init; +} + +GtkSearchEngine * +gtk_search_engine_tracker3_new (void) +{ + GtkSearchEngineTracker3 *engine; + GError *error = NULL; + + g_debug ("Creating GtkSearchEngineTracker3..."); + + engine = g_initable_new (GTK_TYPE_SEARCH_ENGINE_TRACKER3, + NULL, &error, NULL); + if (!engine) + { + g_critical ("Could not init tracker3 search engine: %s", + error->message); + g_error_free (error); + } + + return GTK_SEARCH_ENGINE (engine); +} + +gboolean +gtk_search_engine_tracker3_is_indexed (GFile *location, + gpointer data) +{ + GtkSearchEngineTracker3 *engine = data; + TrackerSparqlCursor *cursor; + GError *error = NULL; + gboolean indexed; + gchar *uri; + + uri = g_file_get_uri (location); + tracker_sparql_statement_bind_string (engine->file_check_query, + "url", uri); + cursor = tracker_sparql_statement_execute (engine->file_check_query, + engine->cancellable, &error); + g_free (uri); + + if (!cursor || + !tracker_sparql_cursor_next (cursor, NULL, NULL)) + { + g_warning ("Error checking indexed file '%s': %s", + uri, error->message); + g_error_free (error); + g_free (uri); + return FALSE; + } + + indexed = tracker_sparql_cursor_get_boolean (cursor, 0); + tracker_sparql_cursor_close (cursor); + g_object_unref (cursor); + + return indexed; +} diff --git a/gtk/gtksearchenginetracker3.h b/gtk/gtksearchenginetracker3.h new file mode 100644 index 0000000000..76a181bec2 --- /dev/null +++ b/gtk/gtksearchenginetracker3.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2020 Red Hat Inc + * 2005 Mr Jamie McCracken + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Carlos Garnacho <carlosg@gnome.org> + * Jamie McCracken (jamiemcc@gnome.org) + * + * Based on nautilus-search-engine-tracker.h + */ + +#ifndef __GTK_SEARCH_ENGINE_TRACKER3_H__ +#define __GTK_SEARCH_ENGINE_TRACKER3_H__ + +#include "gtksearchengine.h" + +G_BEGIN_DECLS + +#define GTK_TYPE_SEARCH_ENGINE_TRACKER3 (gtk_search_engine_tracker3_get_type ()) +G_DECLARE_FINAL_TYPE (GtkSearchEngineTracker3, + gtk_search_engine_tracker3, + GTK, SEARCH_ENGINE_TRACKER3, + GtkSearchEngine) + +GType gtk_search_engine_tracker3_get_type (void); + +GtkSearchEngine* gtk_search_engine_tracker3_new (void); + +gboolean gtk_search_engine_tracker3_is_indexed (GFile *file, + gpointer data); +G_END_DECLS + +#endif /* __GTK_SEARCH_ENGINE_TRACKER3_H__ */ diff --git a/gtk/meson.build b/gtk/meson.build index 5a0b1547d8..2a72b91047 100644 --- a/gtk/meson.build +++ b/gtk/meson.build @@ -655,6 +655,10 @@ gtk_unix_sources = files( 'gtksearchenginetracker.c', ) +if os_unix and tracker3_enabled + gtk_unix_sources += 'gtksearchenginetracker3.c' +endif + if os_unix gtk_sources += gtk_unix_sources endif @@ -916,6 +920,10 @@ if cloudproviders_enabled gtk_deps += cloudproviders_dep endif +if os_unix and tracker3_enabled + gtk_deps += tracker3_dep +endif + # Unconditional. If libintl isn't found, # the object just does nothing being in the deplist gtk_deps += libintl_dep diff --git a/meson.build b/meson.build index ee0cae773b..415a66c732 100644 --- a/meson.build +++ b/meson.build @@ -478,6 +478,16 @@ if require_harfbuzz and not harfbuzz_dep.found() fallback: ['harfbuzz', 'libharfbuzz_dep']) endif +tracker3_enabled = get_option('tracker3') +if tracker3_enabled + tracker3_dep = dependency('tracker-sparql-3.0', required: false) + if tracker3_dep.found() + cdata.set('HAVE_TRACKER3', tracker3_dep.found()) + else + error('Tracker3 not found, but was explicitly requested.') + endif +endif + if iso_codes_dep.found() cdata.set_quoted('ISO_CODES_PREFIX', iso_codes_dep.get_pkgconfig_variable('prefix')) else diff --git a/meson_options.txt b/meson_options.txt index 7544389345..4f605b41ba 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -17,6 +17,8 @@ option('cloudproviders', type: 'boolean', value: false, description : 'Enable the cloudproviders support') option('profiler', type: 'boolean', value: false, description : 'Enable profiler support') +option('tracker3', type: 'boolean', value: false, + description : 'Enable Tracker3 filechooser search') # Print backends option('print_backends', type : 'string', value : 'auto', |