gtksearchengine: Add tracker3 search engine

Make this dependency optional at build time, and prefer it over
the old tracker <= 2.x implementation.
This commit is contained in:
Carlos Garnacho 2020-05-17 00:04:56 +02:00
parent 5858f7c5bd
commit ae776046fc
7 changed files with 469 additions and 5 deletions

View File

@ -281,3 +281,6 @@
#mesondefine GTK_LOCALEDIR
#mesondefine ISO_CODES_PREFIX
/* Define if tracker3 is available */
#mesondefine HAVE_TRACKER3

View File

@ -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)
{

View File

@ -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;
}

View File

@ -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__ */

View File

@ -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

View File

@ -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

View File

@ -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',