nautilus-3.6.3/src/nautilus-shell-search-provider.c

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,
Value stored to 'pix' is never read
(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 }