nautilus-shell-search-provider.c 24.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 * nautilus-shell-search-provider.c - Implementation of a GNOME Shell
 *   search provider
 *
 * Copyright (C) 2012 Red Hat, Inc.
 *
 * Nautilus is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * Nautilus 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
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
19 20 21 22 23 24 25 26
 *
 * Authors: Cosimo Cecchi <cosimoc@gnome.org>
 *
 */

#include <config.h>

#include <gio/gio.h>
27
#include <string.h>
28
#include <glib/gi18n.h>
29
#include <gdk/gdkx.h>
30

31 32 33 34 35
#include "nautilus-file.h"
#include "nautilus-file-utilities.h"
#include "nautilus-search-engine.h"
#include "nautilus-search-provider.h"
#include "nautilus-ui-utilities.h"
36

37
#include "nautilus-application.h"
38
#include "nautilus-bookmark-list.h"
39
#include "nautilus-shell-search-provider-generated.h"
40
#include "nautilus-shell-search-provider.h"
41

42 43 44
typedef struct
{
    NautilusShellSearchProvider *self;
45

46 47
    NautilusSearchEngine *engine;
    NautilusQuery *query;
48

49 50
    GHashTable *hits;
    GDBusMethodInvocation *invocation;
51

52
    gint64 start_time;
53 54
} PendingSearch;

55 56 57
struct _NautilusShellSearchProvider
{
    GObject parent;
58

59
    NautilusShellSearchProvider2 *skeleton;
60

61
    PendingSearch *current_search;
62

63
    GHashTable *metas_cache;
64
};
65

66
G_DEFINE_TYPE (NautilusShellSearchProvider, nautilus_shell_search_provider, G_TYPE_OBJECT)
67

68
static gchar *
69
get_display_name (NautilusShellSearchProvider *self,
70
                  NautilusFile                *file)
71
{
72 73 74
    GFile *location;
    NautilusBookmark *bookmark;
    NautilusBookmarkList *bookmarks;
75

76
    bookmarks = nautilus_application_get_bookmarks (NAUTILUS_APPLICATION (g_application_get_default ()));
77

78 79 80
    location = nautilus_file_get_location (file);
    bookmark = nautilus_bookmark_list_item_with_location (bookmarks, location, NULL);
    g_object_unref (location);
81

82 83 84 85 86 87 88 89
    if (bookmark)
    {
        return g_strdup (nautilus_bookmark_get_name (bookmark));
    }
    else
    {
        return nautilus_file_get_display_name (file);
    }
90 91 92
}

static GIcon *
93
get_gicon (NautilusShellSearchProvider *self,
94
           NautilusFile                *file)
95
{
96 97 98
    GFile *location;
    NautilusBookmark *bookmark;
    NautilusBookmarkList *bookmarks;
99

100
    bookmarks = nautilus_application_get_bookmarks (NAUTILUS_APPLICATION (g_application_get_default ()));
101

102 103 104
    location = nautilus_file_get_location (file);
    bookmark = nautilus_bookmark_list_item_with_location (bookmarks, location, NULL);
    g_object_unref (location);
105

106 107 108 109 110 111 112 113
    if (bookmark)
    {
        return nautilus_bookmark_get_icon (bookmark);
    }
    else
    {
        return nautilus_file_get_gicon (file, 0);
    }
114 115
}

116
static void
117
pending_search_free (PendingSearch *search)
118
{
119 120 121 122
    g_hash_table_destroy (search->hits);
    g_clear_object (&search->query);
    g_clear_object (&search->engine);
    g_clear_object (&search->invocation);
123

124
    g_slice_free (PendingSearch, search);
125 126 127
}

static void
128 129 130
pending_search_finish (PendingSearch         *search,
                       GDBusMethodInvocation *invocation,
                       GVariant              *result)
131
{
132
    NautilusShellSearchProvider *self = search->self;
133

134
    g_dbus_method_invocation_return_value (invocation, result);
135

136 137 138 139
    if (search == self->current_search)
    {
        self->current_search = NULL;
    }
140

141 142
    g_application_release (g_application_get_default ());
    pending_search_free (search);
143 144 145
}

static void
146
cancel_current_search (NautilusShellSearchProvider *self)
147
{
148 149 150 151
    if (self->current_search != NULL)
    {
        nautilus_search_provider_stop (NAUTILUS_SEARCH_PROVIDER (self->current_search->engine));
    }
152 153 154 155 156 157 158
}

static void
search_hits_added_cb (NautilusSearchEngine *engine,
                      GList                *hits,
                      gpointer              user_data)
{
159 160 161 162
    PendingSearch *search = user_data;
    GList *l;
    NautilusSearchHit *hit;
    const gchar *hit_uri;
163

164
    g_debug ("*** Search engine hits added");
165

166 167 168 169 170 171
    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);
172

173 174
        g_hash_table_replace (search->hits, g_strdup (hit_uri), g_object_ref (hit));
    }
175 176
}

177 178 179 180
static gint
search_hit_compare_relevance (gconstpointer a,
                              gconstpointer b)
{
181 182
    NautilusSearchHit *hit_a, *hit_b;
    gdouble relevance_a, relevance_b;
183

184 185
    hit_a = NAUTILUS_SEARCH_HIT ((gpointer) a);
    hit_b = NAUTILUS_SEARCH_HIT ((gpointer) b);
186

187 188
    relevance_a = nautilus_search_hit_get_relevance (hit_a);
    relevance_b = nautilus_search_hit_get_relevance (hit_b);
189

190 191 192 193 194 195 196 197
    if (relevance_a > relevance_b)
    {
        return -1;
    }
    else if (relevance_a == relevance_b)
    {
        return 0;
    }
198

199
    return 1;
200 201 202
}

static void
203 204 205
search_finished_cb (NautilusSearchEngine         *engine,
                    NautilusSearchProviderStatus  status,
                    gpointer                      user_data)
206
{
207 208 209 210 211
    PendingSearch *search = user_data;
    GList *hits, *l;
    NautilusSearchHit *hit;
    GVariantBuilder builder;
    gint64 current_time;
212

213 214 215
    current_time = g_get_monotonic_time ();
    g_debug ("*** Search engine search finished - time elapsed %dms",
             (gint) ((current_time - search->start_time) / 1000));
216

217 218
    hits = g_hash_table_get_values (search->hits);
    hits = g_list_sort (hits, search_hit_compare_relevance);
219

220
    g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
221

222 223 224 225 226
    for (l = hits; l != NULL; l = l->next)
    {
        hit = l->data;
        g_variant_builder_add (&builder, "s", nautilus_search_hit_get_uri (hit));
    }
227

228 229 230
    g_list_free (hits);
    pending_search_finish (search, search->invocation,
                           g_variant_new ("(as)", &builder));
231 232 233 234 235 236 237
}

static void
search_error_cb (NautilusSearchEngine *engine,
                 const gchar          *error_message,
                 gpointer              user_data)
{
238 239
    NautilusShellSearchProvider *self = user_data;
    PendingSearch *search = self->current_search;
240

241 242 243
    g_debug ("*** Search engine search error");
    pending_search_finish (search, search->invocation,
                           g_variant_new ("(as)", NULL));
244 245
}

246 247 248 249
typedef struct
{
    gchar *uri;
    gchar *string_for_compare;
250 251 252 253 254
} SearchHitCandidate;

static void
search_hit_candidate_free (SearchHitCandidate *candidate)
{
255 256
    g_free (candidate->uri);
    g_free (candidate->string_for_compare);
257

258
    g_slice_free (SearchHitCandidate, candidate);
259 260 261 262 263 264
}

static SearchHitCandidate *
search_hit_candidate_new (const gchar *uri,
                          const gchar *name)
{
265
    SearchHitCandidate *candidate = g_slice_new0 (SearchHitCandidate);
266

267 268
    candidate->uri = g_strdup (uri);
    candidate->string_for_compare = g_strdup (name);
269

270
    return candidate;
271 272
}

273
static void
274
search_add_volumes_and_bookmarks (PendingSearch *search)
275
{
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
    NautilusSearchHit *hit;
    NautilusBookmark *bookmark;
    const gchar *name;
    gchar *string, *uri;
    gdouble match;
    GList *l, *m, *drives, *volumes, *mounts, *mounts_to_check, *candidates;
    GDrive *drive;
    GVolume *volume;
    GMount *mount;
    GFile *location;
    SearchHitCandidate *candidate;
    NautilusBookmarkList *bookmarks;
    GList *all_bookmarks;
    GVolumeMonitor *volume_monitor;

    bookmarks = nautilus_application_get_bookmarks (NAUTILUS_APPLICATION (g_application_get_default ()));
    all_bookmarks = nautilus_bookmark_list_get_all (bookmarks);
    volume_monitor = g_volume_monitor_get ();
    candidates = NULL;

    /* first add bookmarks */
    for (l = all_bookmarks; l != NULL; l = l->next)
    {
        bookmark = NAUTILUS_BOOKMARK (l->data);
        name = nautilus_bookmark_get_name (bookmark);
        if (name == NULL)
        {
            continue;
        }

        uri = nautilus_bookmark_get_uri (bookmark);
        candidate = search_hit_candidate_new (uri, name);
        candidates = g_list_prepend (candidates, candidate);

        g_free (uri);
    }
312

313 314 315 316
    /* home dir */
    uri = nautilus_get_home_directory_uri ();
    candidate = search_hit_candidate_new (uri, _("Home"));
    candidates = g_list_prepend (candidates, candidate);
317
    g_free (uri);
318

319 320
    /* trash */
    candidate = search_hit_candidate_new ("trash:///", _("Trash"));
321 322
    candidates = g_list_prepend (candidates, candidate);

323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
    /* now add mounts */
    mounts_to_check = NULL;

    /* first check all connected drives */
    drives = g_volume_monitor_get_connected_drives (volume_monitor);
    for (l = drives; l != NULL; l = l->next)
    {
        drive = l->data;
        volumes = g_drive_get_volumes (drive);

        for (m = volumes; m != NULL; m = m->next)
        {
            volume = m->data;
            mount = g_volume_get_mount (volume);
            if (mount != NULL)
            {
                mounts_to_check = g_list_prepend (mounts_to_check, mount);
            }
        }

        g_list_free_full (volumes, g_object_unref);
    }
    g_list_free_full (drives, g_object_unref);

    /* then volumes that don't have a drive */
    volumes = g_volume_monitor_get_volumes (volume_monitor);
    for (l = volumes; l != NULL; l = l->next)
    {
        volume = l->data;
        drive = g_volume_get_drive (volume);

        if (drive == NULL)
        {
            mount = g_volume_get_mount (volume);
            if (mount != NULL)
            {
                mounts_to_check = g_list_prepend (mounts_to_check, mount);
            }
        }
        g_clear_object (&drive);
    }
    g_list_free_full (volumes, g_object_unref);

    /* then mounts that have no volume */
    mounts = g_volume_monitor_get_mounts (volume_monitor);
    for (l = mounts; l != NULL; l = l->next)
    {
        mount = l->data;

        if (g_mount_is_shadowed (mount))
        {
            continue;
        }

        volume = g_mount_get_volume (mount);
        if (volume == NULL)
        {
            mounts_to_check = g_list_prepend (mounts_to_check, g_object_ref (mount));
        }
        g_clear_object (&volume);
383
    }
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
    g_list_free_full (mounts, g_object_unref);

    /* actually add mounts to candidates */
    for (l = mounts_to_check; l != NULL; l = l->next)
    {
        mount = l->data;

        string = g_mount_get_name (mount);
        if (string == NULL)
        {
            continue;
        }

        location = g_mount_get_default_location (mount);
        uri = g_file_get_uri (location);
        candidate = search_hit_candidate_new (uri, string);
        candidates = g_list_prepend (candidates, candidate);

        g_free (uri);
        g_free (string);
        g_object_unref (location);
    }
    g_list_free_full (mounts_to_check, g_object_unref);

    /* now do the actual string matching */
    candidates = g_list_reverse (candidates);

    for (l = candidates; l != NULL; l = l->next)
    {
        candidate = l->data;
        match = nautilus_query_matches_string (search->query,
                                               candidate->string_for_compare);

        if (match > -1)
        {
            hit = nautilus_search_hit_new (candidate->uri);
            nautilus_search_hit_set_fts_rank (hit, match);
            nautilus_search_hit_compute_scores (hit, search->query);
            g_hash_table_replace (search->hits, g_strdup (candidate->uri), hit);
        }
    }
    g_list_free_full (candidates, (GDestroyNotify) search_hit_candidate_free);
    g_object_unref (volume_monitor);
427 428
}

429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445
static NautilusQuery*
shell_query_new (gchar **terms)
{
    NautilusQuery *query;
    g_autoptr (GFile) home = NULL;
    g_autofree gchar *terms_joined = NULL;

    terms_joined = g_strjoinv (" ", terms);
    home = g_file_new_for_path (g_get_home_dir ());

    query = nautilus_query_new ();
    nautilus_query_set_text (query, terms_joined);
    nautilus_query_set_location (query, home);

    return query;
}

446
static void
447 448 449
execute_search (NautilusShellSearchProvider  *self,
                GDBusMethodInvocation        *invocation,
                gchar                       **terms)
450
{
451 452 453 454 455 456 457 458 459 460 461 462 463
    NautilusQuery *query;
    PendingSearch *pending_search;

    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)
    {
        g_dbus_method_invocation_return_value (invocation, g_variant_new ("(as)", NULL));
        return;
    }

464
    query = shell_query_new (terms);
465
    nautilus_query_set_recursive (query, NAUTILUS_QUERY_RECURSIVE_INDEXED_ONLY);
466
    nautilus_query_set_show_hidden_files (query, FALSE);
467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492

    pending_search = g_slice_new0 (PendingSearch);
    pending_search->invocation = g_object_ref (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 ();
    pending_search->self = self;

    g_signal_connect (pending_search->engine, "hits-added",
                      G_CALLBACK (search_hits_added_cb), pending_search);
    g_signal_connect (pending_search->engine, "finished",
                      G_CALLBACK (search_finished_cb), pending_search);
    g_signal_connect (pending_search->engine, "error",
                      G_CALLBACK (search_error_cb), pending_search);

    self->current_search = pending_search;
    g_application_hold (g_application_get_default ());

    search_add_volumes_and_bookmarks (pending_search);

    /* 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));
493 494
}

495
static gboolean
496 497 498 499
handle_get_initial_result_set (NautilusShellSearchProvider2  *skeleton,
                               GDBusMethodInvocation         *invocation,
                               gchar                        **terms,
                               gpointer                       user_data)
500
{
501
    NautilusShellSearchProvider *self = user_data;
502

503 504 505
    g_debug ("****** GetInitialResultSet");
    execute_search (self, invocation, terms);
    return TRUE;
506 507
}

508
static gboolean
509 510 511 512 513
handle_get_subsearch_result_set (NautilusShellSearchProvider2  *skeleton,
                                 GDBusMethodInvocation         *invocation,
                                 gchar                        **previous_results,
                                 gchar                        **terms,
                                 gpointer                       user_data)
514
{
515
    NautilusShellSearchProvider *self = user_data;
516

517 518 519
    g_debug ("****** GetSubSearchResultSet");
    execute_search (self, invocation, terms);
    return TRUE;
520 521
}

522 523 524
typedef struct
{
    NautilusShellSearchProvider *self;
525

526 527
    gint64 start_time;
    GDBusMethodInvocation *invocation;
528

529
    gchar **uris;
530 531 532 533 534
} ResultMetasData;

static void
result_metas_data_free (ResultMetasData *data)
{
535 536 537
    g_clear_object (&data->self);
    g_clear_object (&data->invocation);
    g_strfreev (data->uris);
538

539
    g_slice_free (ResultMetasData, data);
540 541
}

542 543 544
static void
result_metas_return_from_cache (ResultMetasData *data)
{
545 546 547 548 549 550 551 552 553 554 555 556 557
    GVariantBuilder builder;
    GVariant *meta;
    gint64 current_time;
    gint idx;

    g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}"));

    for (idx = 0; data->uris[idx] != NULL; idx++)
    {
        meta = g_hash_table_lookup (data->self->metas_cache,
                                    data->uris[idx]);
        g_variant_builder_add_value (&builder, meta);
    }
558

559 560 561
    current_time = g_get_monotonic_time ();
    g_debug ("*** GetResultMetas completed - time elapsed %dms",
             (gint) ((current_time - data->start_time) / 1000));
562

563 564
    g_dbus_method_invocation_return_value (data->invocation,
                                           g_variant_new ("(aa{sv})", &builder));
565 566
}

567 568 569 570
static void
result_list_attributes_ready_cb (GList    *file_list,
                                 gpointer  user_data)
{
571 572 573 574 575 576
    ResultMetasData *data = user_data;
    GVariantBuilder meta;
    NautilusFile *file;
    GFile *file_location;
    GList *l;
    gchar *uri, *display_name;
577
    gchar *path, *description;
578 579 580 581 582 583
    gchar *thumbnail_path;
    GIcon *gicon;
    GFile *location;
    GVariant *meta_variant;
    gint icon_scale;

584
    icon_scale = gdk_monitor_get_scale_factor (gdk_display_get_monitor (gdk_display_get_default (), 0));
585 586 587 588 589 590 591 592 593

    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 = get_display_name (data->self, file);
        file_location = nautilus_file_get_location (file);
594 595
        path = g_file_get_path (file_location);
        description = path ? g_path_get_dirname (path) : NULL;
596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636

        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));
        /* Some backends like trash:/// don't have a path, so we show the uri itself. */
        g_variant_builder_add (&meta, "{sv}",
                               "description", g_variant_new_string (description ? description : uri));

        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 = get_gicon (data->self, file);
        }

        if (gicon == NULL)
        {
            gicon = G_ICON (nautilus_file_get_icon_pixbuf (file, 128, TRUE,
                                                           icon_scale,
                                                           NAUTILUS_FILE_ICON_FLAGS_USE_THUMBNAILS));
        }

        g_variant_builder_add (&meta, "{sv}",
                               "icon", g_icon_serialize (gicon));
        g_object_unref (gicon);

        meta_variant = g_variant_builder_end (&meta);
        g_hash_table_insert (data->self->metas_cache,
                             g_strdup (uri), g_variant_ref_sink (meta_variant));

        g_free (display_name);
637
        g_free (path);
638 639
        g_free (description);
        g_free (uri);
640 641
    }

642 643
    result_metas_return_from_cache (data);
    result_metas_data_free (data);
644 645
}

646
static gboolean
647 648 649 650
handle_get_result_metas (NautilusShellSearchProvider2  *skeleton,
                         GDBusMethodInvocation         *invocation,
                         gchar                        **results,
                         gpointer                       user_data)
651
{
652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667
    NautilusShellSearchProvider *self = user_data;
    GList *missing_files = NULL;
    const gchar *uri;
    ResultMetasData *data;
    gint idx;

    g_debug ("****** GetResultMetas");

    for (idx = 0; results[idx] != NULL; idx++)
    {
        uri = results[idx];

        if (!g_hash_table_lookup (self->metas_cache, uri))
        {
            missing_files = g_list_prepend (missing_files, nautilus_file_get_by_uri (uri));
        }
668
    }
669

670 671 672 673 674 675 676 677 678 679 680 681
    data = g_slice_new0 (ResultMetasData);
    data->self = g_object_ref (self);
    data->invocation = g_object_ref (invocation);
    data->start_time = g_get_monotonic_time ();
    data->uris = g_strdupv (results);

    if (missing_files == NULL)
    {
        result_metas_return_from_cache (data);
        result_metas_data_free (data);
        return TRUE;
    }
682

683 684 685 686 687 688
    nautilus_file_list_call_when_ready (missing_files,
                                        NAUTILUS_FILE_ATTRIBUTES_FOR_ICON,
                                        NULL,
                                        result_list_attributes_ready_cb,
                                        data);
    nautilus_file_list_free (missing_files);
689
    return TRUE;
690 691
}

692
static gboolean
693 694 695 696 697 698
handle_activate_result (NautilusShellSearchProvider2  *skeleton,
                        GDBusMethodInvocation         *invocation,
                        gchar                         *result,
                        gchar                        **terms,
                        guint32                        timestamp,
                        gpointer                       user_data)
699
{
700 701
    gboolean res;
    GFile *file;
702

703
    res = gtk_show_uri_on_window (NULL, result, timestamp, NULL);
704

705 706 707 708 709 710
    if (!res)
    {
        file = g_file_new_for_uri (result);
        g_application_open (g_application_get_default (), &file, 1, "");
        g_object_unref (file);
    }
711

712 713
    nautilus_shell_search_provider2_complete_activate_result (skeleton, invocation);
    return TRUE;
714 715
}

716
static gboolean
717 718 719 720 721
handle_launch_search (NautilusShellSearchProvider2  *skeleton,
                      GDBusMethodInvocation         *invocation,
                      gchar                        **terms,
                      guint32                        timestamp,
                      gpointer                       user_data)
722
{
723
    GApplication *app = g_application_get_default ();
724
    g_autoptr (NautilusQuery) query = shell_query_new (terms);
725

726 727 728 729 730 731 732 733 734 735 736 737 738 739
    if (location_settings_search_get_recursive () == NAUTILUS_QUERY_RECURSIVE_NEVER)
    {
        /*
         * If no recursive search is enabled, we still want to be able to
         * show the same results we presented in the overview when nautilus
         * is explicitly launched to access to more results, and thus we perform
         * a query showing results coming from index-based search engines.
         * Otherwise we just respect the user settings.
         * See: https://gitlab.gnome.org/GNOME/nautilus/merge_requests/249
         */
        nautilus_query_set_recursive (query,
                                      NAUTILUS_QUERY_RECURSIVE_INDEXED_ONLY);
    }

740
    nautilus_application_search (NAUTILUS_APPLICATION (app), query);
741

742 743
    nautilus_shell_search_provider2_complete_launch_search (skeleton, invocation);
    return TRUE;
744 745 746
}

static void
747
search_provider_dispose (GObject *obj)
748
{
749
    NautilusShellSearchProvider *self = NAUTILUS_SHELL_SEARCH_PROVIDER (obj);
750

751 752 753
    g_clear_object (&self->skeleton);
    g_hash_table_destroy (self->metas_cache);
    cancel_current_search (self);
754

755
    G_OBJECT_CLASS (nautilus_shell_search_provider_parent_class)->dispose (obj);
756 757 758
}

static void
759
nautilus_shell_search_provider_init (NautilusShellSearchProvider *self)
760
{
761 762 763 764 765 766 767 768 769 770 771 772 773 774 775
    self->metas_cache = g_hash_table_new_full (g_str_hash, g_str_equal,
                                               g_free, (GDestroyNotify) g_variant_unref);

    self->skeleton = nautilus_shell_search_provider2_skeleton_new ();

    g_signal_connect (self->skeleton, "handle-get-initial-result-set",
                      G_CALLBACK (handle_get_initial_result_set), self);
    g_signal_connect (self->skeleton, "handle-get-subsearch-result-set",
                      G_CALLBACK (handle_get_subsearch_result_set), self);
    g_signal_connect (self->skeleton, "handle-get-result-metas",
                      G_CALLBACK (handle_get_result_metas), self);
    g_signal_connect (self->skeleton, "handle-activate-result",
                      G_CALLBACK (handle_activate_result), self);
    g_signal_connect (self->skeleton, "handle-launch-search",
                      G_CALLBACK (handle_launch_search), self);
776 777 778
}

static void
779
nautilus_shell_search_provider_class_init (NautilusShellSearchProviderClass *klass)
780
{
781
    GObjectClass *oclass = G_OBJECT_CLASS (klass);
782

783
    oclass->dispose = search_provider_dispose;
784 785
}

786 787
NautilusShellSearchProvider *
nautilus_shell_search_provider_new (void)
788
{
789 790
    return g_object_new (nautilus_shell_search_provider_get_type (),
                         NULL);
791
}
792 793

gboolean
794 795 796
nautilus_shell_search_provider_register (NautilusShellSearchProvider  *self,
                                         GDBusConnection              *connection,
                                         GError                      **error)
797
{
798 799
    return g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (self->skeleton),
                                             connection,
800
                                             "/org/gnome/Nautilus" PROFILE "/SearchProvider", error);
801 802 803 804 805
}

void
nautilus_shell_search_provider_unregister (NautilusShellSearchProvider *self)
{
806
    g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (self->skeleton));
807
}