Location | Tool | Test ID | Function | Issue |
---|---|---|---|---|
nautilus-shell-search-provider.c:561:5 | clang-analyzer | Value stored to 'pix' is never read |
1 /*
2 * nautilus-shell-search-provider.c - Implementation of a GNOME Shell
3 * search provider
4 *
5 * Copyright (C) 2012 Red Hat, Inc.
6 *
7 * Nautilus is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
11 *
12 * Nautilus is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 * Authors: Cosimo Cecchi <cosimoc@gnome.org>
22 *
23 */
24
25 #include <config.h>
26
27 #include <gio/gio.h>
28 #include <string.h>
29 #include <glib/gi18n.h>
30 #include <gdk/gdkx.h>
31
32 #include <libnautilus-private/nautilus-file.h>
33 #include <libnautilus-private/nautilus-file-utilities.h>
34 #include <libnautilus-private/nautilus-search-engine.h>
35 #include <libnautilus-private/nautilus-search-provider.h>
36 #include <libnautilus-private/nautilus-ui-utilities.h>
37
38 #include "nautilus-bookmark-list.h"
39 #include "nautilus-shell-search-provider-generated.h"
40
41 #define SEARCH_PROVIDER_INACTIVITY_TIMEOUT 12000 /* milliseconds */
42
43 typedef GApplicationClass NautilusShellSearchProviderAppClass;
44 typedef struct _NautilusShellSearchProviderApp NautilusShellSearchProviderApp;
45
46 typedef struct {
47 NautilusShellSearchProviderApp *self;
48
49 NautilusSearchEngine *engine;
50 NautilusQuery *query;
51
52 GHashTable *hits;
53 GDBusMethodInvocation *invocation;
54
55 gint64 start_time;
56 } PendingSearch;
57
58 struct _NautilusShellSearchProviderApp {
59 GApplication parent;
60
61 guint name_owner_id;
62 GDBusObjectManagerServer *object_manager;
63 NautilusShellSearchProvider *skeleton;
64
65 PendingSearch *current_search;
66
67 GHashTable *metas_cache;
68
69 NautilusBookmarkList *bookmarks;
70 GVolumeMonitor *volumes;
71 };
72
73 GType nautilus_shell_search_provider_app_get_type (void);
74
75 #define NAUTILUS_TYPE_SHELL_SEARCH_PROVIDER_APP nautilus_shell_search_provider_app_get_type()
76 #define NAUTILUS_SHELL_SEARCH_PROVIDER_APP(obj) \
77 (G_TYPE_CHECK_INSTANCE_CAST ((obj), NAUTILUS_TYPE_SHELL_SEARCH_PROVIDER_APP, NautilusShellSearchProviderApp))
78
79 G_DEFINE_TYPE (NautilusShellSearchProviderApp, nautilus_shell_search_provider_app, G_TYPE_APPLICATION)
80
81 static GVariant *
82 variant_from_pixbuf (GdkPixbuf *pixbuf)
83 {
84 GVariant *variant;
85 guchar *data;
86 guint length;
87
88 data = gdk_pixbuf_get_pixels_with_length (pixbuf, &length);
89 variant = g_variant_new ("(iiibii@ay)",
90 gdk_pixbuf_get_width (pixbuf),
91 gdk_pixbuf_get_height (pixbuf),
92 gdk_pixbuf_get_rowstride (pixbuf),
93 gdk_pixbuf_get_has_alpha (pixbuf),
94 gdk_pixbuf_get_bits_per_sample (pixbuf),
95 gdk_pixbuf_get_n_channels (pixbuf),
96 g_variant_new_from_data (G_VARIANT_TYPE_BYTESTRING,
97 data, length, TRUE,
98 (GDestroyNotify)g_object_unref,
99 g_object_ref (pixbuf)));
100 return variant;
101 }
102
103 static gchar *
104 get_display_name (NautilusShellSearchProviderApp *self,
105 NautilusFile *file)
106 {
107 gchar *uri;
108 NautilusBookmark *bookmark;
109
110 uri = nautilus_file_get_uri (file);
111 bookmark = nautilus_bookmark_list_item_with_uri (self->bookmarks, uri);
112 g_free (uri);
113
114 if (bookmark)
115 return g_strdup (nautilus_bookmark_get_name (bookmark));
116 else
117 return nautilus_file_get_display_name (file);
118 }
119
120 static GIcon *
121 get_gicon (NautilusShellSearchProviderApp *self,
122 NautilusFile *file)
123 {
124 gchar *uri;
125 NautilusBookmark *bookmark;
126
127 uri = nautilus_file_get_uri (file);
128 bookmark = nautilus_bookmark_list_item_with_uri (self->bookmarks, uri);
129 g_free (uri);
130
131 if (bookmark)
132 return nautilus_bookmark_get_icon (bookmark);
133 else
134 return nautilus_file_get_gicon (file, 0);
135 }
136
137 static void
138 pending_search_free (PendingSearch *search)
139 {
140 g_hash_table_destroy (search->hits);
141 g_clear_object (&search->query);
142 g_clear_object (&search->engine);
143 g_clear_object (&search->invocation);
144
145 g_slice_free (PendingSearch, search);
146 }
147
148 static void
149 pending_search_finish (PendingSearch *search,
150 GDBusMethodInvocation *invocation,
151 GVariant *result)
152 {
153 NautilusShellSearchProviderApp *self = search->self;
154
155 g_dbus_method_invocation_return_value (invocation, result);
156
157 if (search == self->current_search)
158 self->current_search = NULL;
159
160 g_application_release (G_APPLICATION (self));
161 pending_search_free (search);
162 }
163
164 static void
165 cancel_current_search (NautilusShellSearchProviderApp *self)
166 {
167 if (self->current_search != NULL)
168 nautilus_search_provider_stop (NAUTILUS_SEARCH_PROVIDER (self->current_search->engine));
169 }
170
171 static void
172 search_hits_added_cb (NautilusSearchEngine *engine,
173 GList *hits,
174 gpointer user_data)
175
176 {
177 PendingSearch *search = user_data;
178 GList *l;
179 NautilusSearchHit *hit;
180 const gchar *hit_uri;
181
182 g_debug ("*** Search engine hits added");
183
184 for (l = hits; l != NULL; l = l->next) {
185 hit = l->data;
186 nautilus_search_hit_compute_scores (hit, search->query);
187 hit_uri = nautilus_search_hit_get_uri (hit);
188 g_debug (" %s", hit_uri);
189
190 g_hash_table_replace (search->hits, g_strdup (hit_uri), g_object_ref (hit));
191 }
192 }
193
194 static gint
195 search_hit_compare_relevance (gconstpointer a,
196 gconstpointer b)
197 {
198 NautilusSearchHit *hit_a, *hit_b;
199 gdouble relevance_a, relevance_b;
200
201 hit_a = NAUTILUS_SEARCH_HIT (a);
202 hit_b = NAUTILUS_SEARCH_HIT (b);
203
204 relevance_a = nautilus_search_hit_get_relevance (hit_a);
205 relevance_b = nautilus_search_hit_get_relevance (hit_b);
206
207 if (relevance_a > relevance_b)
208 return -1;
209 else if (relevance_a == relevance_b)
210 return 0;
211
212 return 1;
213 }
214
215 static void
216 search_finished_cb (NautilusSearchEngine *engine,
217 gpointer user_data)
218 {
219 PendingSearch *search = user_data;
220 GList *hits, *l;
221 NautilusSearchHit *hit;
222 GVariantBuilder builder;
223 gint64 current_time;
224
225 current_time = g_get_monotonic_time ();
226 g_debug ("*** Search engine search finished - time elapsed %dms",
227 (gint) ((current_time - search->start_time) / 1000));
228
229 hits = g_hash_table_get_values (search->hits);
230 hits = g_list_sort (hits, search_hit_compare_relevance);
231
232 g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
233
234 for (l = hits; l != NULL; l = l->next) {
235 hit = l->data;
236 g_variant_builder_add (&builder, "s", nautilus_search_hit_get_uri (hit));
237 }
238
239 g_list_free (hits);
240 pending_search_finish (search, search->invocation,
241 g_variant_new ("(as)", &builder));
242 }
243
244 static void
245 search_error_cb (NautilusSearchEngine *engine,
246 const gchar *error_message,
247 gpointer user_data)
248 {
249 NautilusShellSearchProviderApp *self = user_data;
250 PendingSearch *search = self->current_search;
251
252 g_debug ("*** Search engine search error");
253 pending_search_finish (search, search->invocation,
254 g_variant_new ("(as)", NULL));
255 }
256
257 typedef struct {
258 gchar *uri;
259 gchar *string_for_compare;
260 } SearchHitCandidate;
261
262 static void
263 search_hit_candidate_free (SearchHitCandidate *candidate)
264 {
265 g_free (candidate->uri);
266 g_free (candidate->string_for_compare);
267
268 g_slice_free (SearchHitCandidate, candidate);
269 }
270
271 static SearchHitCandidate *
272 search_hit_candidate_new (const gchar *uri,
273 const gchar *name)
274 {
275 SearchHitCandidate *candidate = g_slice_new0 (SearchHitCandidate);
276
277 candidate->uri = g_strdup (uri);
278 candidate->string_for_compare = g_strdup (name);
279
280 return candidate;
281 }
282
283 static void
284 search_add_volumes_and_bookmarks (PendingSearch *search)
285 {
286 NautilusSearchHit *hit;
287 NautilusBookmark *bookmark;
288 const gchar *name;
289 gint length, idx;
290 gchar *string, *uri;
291 gdouble match;
292 GList *l, *m, *drives, *volumes, *mounts, *mounts_to_check, *candidates;
293 GDrive *drive;
294 GVolume *volume;
295 GMount *mount;
296 GFile *location;
297 SearchHitCandidate *candidate;
298
299 candidates = NULL;
300
301 /* first add bookmarks */
302 length = nautilus_bookmark_list_length (search->self->bookmarks);
303 for (idx = 0; idx < length; idx++) {
304 bookmark = nautilus_bookmark_list_item_at (search->self->bookmarks, idx);
305
306 name = nautilus_bookmark_get_name (bookmark);
307 if (name == NULL)
308 continue;
309
310 uri = nautilus_bookmark_get_uri (bookmark);
311 candidate = search_hit_candidate_new (uri, name);
312 candidates = g_list_prepend (candidates, candidate);
313
314 g_free (uri);
315 }
316
317 /* home dir */
318 uri = nautilus_get_home_directory_uri ();
319 candidate = search_hit_candidate_new (uri, _("Home"));
320 candidates = g_list_prepend (candidates, candidate);
321 g_free (uri);
322
323 /* trash */
324 candidate = search_hit_candidate_new ("trash:///", _("Trash"));
325 candidates = g_list_prepend (candidates, candidate);
326
327 /* now add mounts */
328 mounts_to_check = NULL;
329
330 /* first check all connected drives */
331 drives = g_volume_monitor_get_connected_drives (search->self->volumes);
332 for (l = drives; l != NULL; l = l->next) {
333 drive = l->data;
334 volumes = g_drive_get_volumes (drive);
335
336 for (m = volumes; m != NULL; m = m->next) {
337 volume = m->data;
338 mount = g_volume_get_mount (volume);
339 if (mount != NULL) {
340 mounts_to_check = g_list_prepend (mounts_to_check, mount);
341 }
342 }
343
344 g_list_free_full (volumes, g_object_unref);
345 }
346 g_list_free_full (drives, g_object_unref);
347
348 /* then volumes that don't have a drive */
349 volumes = g_volume_monitor_get_volumes (search->self->volumes);
350 for (l = volumes; l != NULL; l = l->next) {
351 volume = l->data;
352 drive = g_volume_get_drive (volume);
353
354 if (drive == NULL) {
355 mount = g_volume_get_mount (volume);
356 if (mount != NULL) {
357 mounts_to_check = g_list_prepend (mounts_to_check, mount);
358 }
359 }
360 g_clear_object (&drive);
361 }
362 g_list_free_full (volumes, g_object_unref);
363
364 /* then mounts that have no volume */
365 mounts = g_volume_monitor_get_mounts (search->self->volumes);
366 for (l = mounts; l != NULL; l = l->next) {
367 mount = l->data;
368
369 if (g_mount_is_shadowed (mount))
370 continue;
371
372 volume = g_mount_get_volume (mount);
373 if (volume == NULL)
374 mounts_to_check = g_list_prepend (mounts_to_check, g_object_ref (mount));
375 g_clear_object (&volume);
376 }
377 g_list_free_full (mounts, g_object_unref);
378
379 /* actually add mounts to candidates */
380 for (l = mounts_to_check; l != NULL; l = l->next) {
381 mount = l->data;
382
383 string = g_mount_get_name (mount);
384 if (string == NULL)
385 continue;
386
387 location = g_mount_get_default_location (mount);
388 uri = g_file_get_uri (location);
389 candidate = search_hit_candidate_new (uri, string);
390 candidates = g_list_prepend (candidates, candidate);
391
392 g_free (uri);
393 g_free (string);
394 g_object_unref (location);
395 }
396 g_list_free_full (mounts_to_check, g_object_unref);
397
398 /* now do the actual string matching */
399 candidates = g_list_reverse (candidates);
400
401 for (l = candidates; l != NULL; l = l->next) {
402 candidate = l->data;
403 match = nautilus_query_matches_string (search->query,
404 candidate->string_for_compare);
405
406 if (match > -1) {
407 hit = nautilus_search_hit_new (candidate->uri);
408 nautilus_search_hit_set_fts_rank (hit, match);
409 nautilus_search_hit_compute_scores (hit, search->query);
410 g_hash_table_replace (search->hits, g_strdup (candidate->uri), hit);
411 }
412 }
413 g_list_free_full (candidates, (GDestroyNotify) search_hit_candidate_free);
414 }
415
416 static void
417 execute_search (NautilusShellSearchProviderApp *self,
418 GDBusMethodInvocation *invocation,
419 gchar **terms)
420 {
421 gchar *terms_joined, *home_uri;
422 NautilusQuery *query;
423 PendingSearch *pending_search;
424
425 cancel_current_search (self);
426
427 /* don't attempt searches for a single character */
428 if (g_strv_length (terms) == 1 &&
429 g_utf8_strlen (terms[0], -1) == 1) {
430 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(as)", NULL));
431 return;
432 }
433
434 terms_joined = g_strjoinv (" ", terms);
435 home_uri = nautilus_get_home_directory_uri ();
436
437 query = nautilus_query_new ();
438 nautilus_query_set_show_hidden_files (query, FALSE);
439 nautilus_query_set_text (query, terms_joined);
440 nautilus_query_set_location (query, home_uri);
441
442 pending_search = g_slice_new0 (PendingSearch);
443 pending_search->invocation = g_object_ref (invocation);
444 pending_search->hits = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
445 pending_search->query = query;
446 pending_search->engine = nautilus_search_engine_new ();
447 pending_search->start_time = g_get_monotonic_time ();
448 pending_search->self = self;
449
450 g_signal_connect (pending_search->engine, "hits-added",
451 G_CALLBACK (search_hits_added_cb), pending_search);
452 g_signal_connect (pending_search->engine, "finished",
453 G_CALLBACK (search_finished_cb), pending_search);
454 g_signal_connect (pending_search->engine, "error",
455 G_CALLBACK (search_error_cb), pending_search);
456
457 self->current_search = pending_search;
458 g_application_hold (G_APPLICATION (self));
459
460 search_add_volumes_and_bookmarks (pending_search);
461
462 /* start searching */
463 g_debug ("*** Search engine search started");
464 nautilus_search_provider_set_query (NAUTILUS_SEARCH_PROVIDER (pending_search->engine),
465 query);
466 nautilus_search_provider_start (NAUTILUS_SEARCH_PROVIDER (pending_search->engine));
467
468 g_free (home_uri);
469 g_free (terms_joined);
470 }
471
472 static void
473 handle_get_initial_result_set (NautilusShellSearchProvider *skeleton,
474 GDBusMethodInvocation *invocation,
475 gchar **terms,
476 gpointer user_data)
477 {
478 NautilusShellSearchProviderApp *self = user_data;
479
480 g_debug ("****** GetInitialResultSet");
481 execute_search (self, invocation, terms);
482 }
483
484 static void
485 handle_get_subsearch_result_set (NautilusShellSearchProvider *skeleton,
486 GDBusMethodInvocation *invocation,
487 gchar **previous_results,
488 gchar **terms,
489 gpointer user_data)
490 {
491 NautilusShellSearchProviderApp *self = user_data;
492
493 g_debug ("****** GetSubSearchResultSet");
494 execute_search (self, invocation, terms);
495 }
496
497 typedef struct {
498 NautilusShellSearchProviderApp *self;
499
500 gint64 start_time;
501 GDBusMethodInvocation *invocation;
502
503 gchar **uris;
504 } ResultMetasData;
505
506 static void
507 result_metas_data_free (ResultMetasData *data)
508 {
509 g_clear_object (&data->self);
510 g_clear_object (&data->invocation);
511 g_strfreev (data->uris);
512
513 g_slice_free (ResultMetasData, data);
514 }
515
516 static void
517 result_metas_return_from_cache (ResultMetasData *data)
518 {
519 GVariantBuilder builder;
520 GVariant *meta;
521 gint64 current_time;
522 gint idx;
523
524 g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}"));
525
526 for (idx = 0; data->uris[idx] != NULL; idx++) {
527 meta = g_hash_table_lookup (data->self->metas_cache,
528 data->uris[idx]);
529 g_variant_builder_add_value (&builder, meta);
530 }
531
532 current_time = g_get_monotonic_time ();
533 g_debug ("*** GetResultMetas completed - time elapsed %dms",
534 (gint) ((current_time - data->start_time) / 1000));
535
536 g_dbus_method_invocation_return_value (data->invocation,
537 g_variant_new ("(aa{sv})", &builder));
538 }
539
540 static void
541 result_list_attributes_ready_cb (GList *file_list,
542 gpointer user_data)
543 {
544 ResultMetasData *data = user_data;
545 GVariantBuilder meta;
546 NautilusFile *file;
547 GList *l;
548 gchar *uri, *display_name;
549 GdkPixbuf *pix;
550 gchar *thumbnail_path, *gicon_str;
551 GIcon *gicon;
552 GFile *location;
553 GVariant *meta_variant;
554
555 for (l = file_list; l != NULL; l = l->next) {
556 file = l->data;
557 g_variant_builder_init (&meta, G_VARIANT_TYPE ("a{sv}"));
558
559 uri = nautilus_file_get_uri (file);
560 display_name = get_display_name (data->self, file);
561 pix = nautilus_file_get_icon_pixbuf (file, 128, TRUE,
(emitted by clang-analyzer)TODO: a detailed trace is available in the data model (not yet rendered in this report)
562 NAUTILUS_FILE_ICON_FLAGS_USE_THUMBNAILS);
563
564 g_variant_builder_add (&meta, "{sv}",
565 "id", g_variant_new_string (uri));
566 g_variant_builder_add (&meta, "{sv}",
567 "name", g_variant_new_string (display_name));
568
569 gicon = NULL;
570 thumbnail_path = nautilus_file_get_thumbnail_path (file);
571
572 if (thumbnail_path != NULL) {
573 location = g_file_new_for_path (thumbnail_path);
574 gicon = g_file_icon_new (location);
575
576 g_free (thumbnail_path);
577 g_object_unref (location);
578 } else {
579 gicon = get_gicon (data->self, file);
580 }
581
582 if (gicon != NULL) {
583 gicon_str = g_icon_to_string (gicon);
584 g_variant_builder_add (&meta, "{sv}",
585 "gicon", g_variant_new_string (gicon_str));
586
587 g_free (gicon_str);
588 g_object_unref (gicon);
589 } else {
590 pix = nautilus_file_get_icon_pixbuf (file, 128, TRUE,
591 NAUTILUS_FILE_ICON_FLAGS_USE_THUMBNAILS);
592
593 g_variant_builder_add (&meta, "{sv}",
594 "icon-data", variant_from_pixbuf (pix));
595 g_object_unref (pix);
596 }
597
598 meta_variant = g_variant_builder_end (&meta);
599 g_hash_table_insert (data->self->metas_cache,
600 g_strdup (uri), g_variant_ref_sink (meta_variant));
601
602 g_free (display_name);
603 g_free (uri);
604 }
605
606 result_metas_return_from_cache (data);
607 result_metas_data_free (data);
608 }
609
610 static void
611 handle_get_result_metas (NautilusShellSearchProvider *skeleton,
612 GDBusMethodInvocation *invocation,
613 gchar **results,
614 gpointer user_data)
615 {
616 NautilusShellSearchProviderApp *self = user_data;
617 GList *missing_files = NULL;
618 const gchar *uri;
619 ResultMetasData *data;
620 gint idx;
621
622 g_debug ("****** GetResultMetas");
623
624 for (idx = 0; results[idx] != NULL; idx++) {
625 uri = results[idx];
626
627 if (!g_hash_table_lookup (self->metas_cache, uri)) {
628 missing_files = g_list_prepend (missing_files, nautilus_file_get_by_uri (uri));
629 }
630 }
631
632 data = g_slice_new0 (ResultMetasData);
633 data->self = g_object_ref (self);
634 data->invocation = g_object_ref (invocation);
635 data->start_time = g_get_monotonic_time ();
636 data->uris = g_strdupv (results);
637
638 if (missing_files == NULL) {
639 result_metas_return_from_cache (data);
640 result_metas_data_free (data);
641 return;
642 }
643
644 nautilus_file_list_call_when_ready (missing_files,
645 NAUTILUS_FILE_ATTRIBUTES_FOR_ICON,
646 NULL,
647 result_list_attributes_ready_cb,
648 data);
649 nautilus_file_list_free (missing_files);
650 }
651
652 /* taken from Epiphany's ephy-main.c */
653 static Time
654 slowly_and_stupidly_obtain_timestamp (Display *xdisplay)
655 {
656 Window xwindow;
657 XEvent event;
658
659 {
660 XSetWindowAttributes attrs;
661 Atom atom_name;
662 Atom atom_type;
663 char* name;
664
665 attrs.override_redirect = True;
666 attrs.event_mask = PropertyChangeMask | StructureNotifyMask;
667
668 xwindow =
669 XCreateWindow (xdisplay,
670 RootWindow (xdisplay, 0),
671 -100, -100, 1, 1,
672 0,
673 CopyFromParent,
674 CopyFromParent,
675 CopyFromParent,
676 CWOverrideRedirect | CWEventMask,
677 &attrs);
678
679 atom_name = XInternAtom (xdisplay, "WM_NAME", TRUE);
680 g_assert (atom_name != None);
681 atom_type = XInternAtom (xdisplay, "STRING", TRUE);
682 g_assert (atom_type != None);
683
684 name = "Fake Window";
685 XChangeProperty (xdisplay,
686 xwindow, atom_name,
687 atom_type,
688 8, PropModeReplace, (unsigned char *)name, strlen (name));
689 }
690
691 XWindowEvent (xdisplay,
692 xwindow,
693 PropertyChangeMask,
694 &event);
695
696 XDestroyWindow(xdisplay, xwindow);
697
698 return event.xproperty.time;
699 }
700
701 static void
702 handle_activate_result (NautilusShellSearchProvider *skeleton,
703 GDBusMethodInvocation *invocation,
704 gchar *result,
705 gpointer user_data)
706 {
707 GError *error = NULL;
708 guint32 timestamp;
709
710 /* We need a timestamp here to get the correct WM focus.
711 * Ideally this would be given to us by the caller, but since it
712 * is not, get it ourselves.
713 */
714 timestamp = slowly_and_stupidly_obtain_timestamp (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()));
715 gtk_show_uri (NULL, result, timestamp, &error);
716
717 if (error != NULL) {
718 g_warning ("Unable to activate %s: %s", result, error->message);
719 g_error_free (error);
720 }
721 }
722
723 static void
724 search_provider_name_acquired_cb (GDBusConnection *connection,
725 const gchar *name,
726 gpointer user_data)
727 {
728 g_debug ("Search provider name acquired: %s\n", name);
729 }
730
731 static void
732 search_provider_name_lost_cb (GDBusConnection *connection,
733 const gchar *name,
734 gpointer user_data)
735 {
736 g_debug ("Search provider name lost: %s\n", name);
737 }
738
739 static void
740 search_provider_bus_acquired_cb (GDBusConnection *connection,
741 const gchar *name,
742 gpointer user_data)
743 {
744 NautilusShellSearchProviderApp *self = user_data;
745
746 self->object_manager = g_dbus_object_manager_server_new ("/org/gnome/Nautilus/SearchProvider");
747 self->skeleton = nautilus_shell_search_provider_skeleton_new ();
748
749 g_signal_connect (self->skeleton, "handle-get-initial-result-set",
750 G_CALLBACK (handle_get_initial_result_set), self);
751 g_signal_connect (self->skeleton, "handle-get-subsearch-result-set",
752 G_CALLBACK (handle_get_subsearch_result_set), self);
753 g_signal_connect (self->skeleton, "handle-get-result-metas",
754 G_CALLBACK (handle_get_result_metas), self);
755 g_signal_connect (self->skeleton, "handle-activate-result",
756 G_CALLBACK (handle_activate_result), self);
757
758 g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (self->skeleton),
759 connection,
760 "/org/gnome/Nautilus/SearchProvider", NULL);
761 g_dbus_object_manager_server_set_connection (self->object_manager, connection);
762 }
763
764 static void
765 search_provider_app_dispose (GObject *obj)
766 {
767 NautilusShellSearchProviderApp *self = NAUTILUS_SHELL_SEARCH_PROVIDER_APP (obj);
768
769 if (self->name_owner_id != 0) {
770 g_bus_unown_name (self->name_owner_id);
771 self->name_owner_id = 0;
772 }
773
774 if (self->skeleton != NULL) {
775 g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (self->skeleton));
776 g_clear_object (&self->skeleton);
777 }
778
779 g_clear_object (&self->object_manager);
780 g_hash_table_destroy (self->metas_cache);
781 cancel_current_search (self);
782
783 g_clear_object (&self->bookmarks);
784 g_clear_object (&self->volumes);
785
786 G_OBJECT_CLASS (nautilus_shell_search_provider_app_parent_class)->dispose (obj);
787 }
788
789 static void
790 search_provider_app_startup (GApplication *app)
791 {
792 NautilusShellSearchProviderApp *self = NAUTILUS_SHELL_SEARCH_PROVIDER_APP (app);
793
794 G_APPLICATION_CLASS (nautilus_shell_search_provider_app_parent_class)->startup (app);
795
796 /* hold indefinitely if we're asked to persist */
797 if (g_getenv ("NAUTILUS_SEARCH_PROVIDER_PERSIST") != NULL)
798 g_application_hold (app);
799
800 self->name_owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
801 "org.gnome.Nautilus.SearchProvider",
802 G_BUS_NAME_OWNER_FLAGS_NONE,
803 search_provider_bus_acquired_cb,
804 search_provider_name_acquired_cb,
805 search_provider_name_lost_cb,
806 app, NULL);
807 }
808
809 static void
810 nautilus_shell_search_provider_app_init (NautilusShellSearchProviderApp *self)
811 {
812 GApplication *app = G_APPLICATION (self);
813
814 g_application_set_inactivity_timeout (app, SEARCH_PROVIDER_INACTIVITY_TIMEOUT);
815 g_application_set_application_id (app, "org.gnome.Nautilus.SearchProvider");
816 g_application_set_flags (app, G_APPLICATION_IS_SERVICE);
817
818 self->metas_cache = g_hash_table_new_full (g_str_hash, g_str_equal,
819 g_free, (GDestroyNotify) g_variant_unref);
820 self->bookmarks = nautilus_bookmark_list_new ();
821 self->volumes = g_volume_monitor_get ();
822 }
823
824 static void
825 nautilus_shell_search_provider_app_class_init (NautilusShellSearchProviderAppClass *klass)
826 {
827 GApplicationClass *aclass = G_APPLICATION_CLASS (klass);
828 GObjectClass *oclass = G_OBJECT_CLASS (klass);
829
830 aclass->startup = search_provider_app_startup;
831 oclass->dispose = search_provider_app_dispose;
832 }
833
834 static GApplication *
835 nautilus_shell_search_provider_app_new (void)
836 {
837 g_type_init ();
838
839 return g_object_new (nautilus_shell_search_provider_app_get_type (),
840 NULL);
841 }
842
843 int
844 main (int argc,
845 char *argv[])
846 {
847 GApplication *app;
848 gint res;
849
850 gtk_init (&argc, &argv);
851
852 app = nautilus_shell_search_provider_app_new ();
853 res = g_application_run (app, argc, argv);
854 g_object_unref (app);
855
856 return res;
857 }