[seahorse] Add a shell search provider for passwords and keys



commit 6c43f3db2016e4e81c315d0834669b39e09bad2f
Author: Giovanni Campagna <gcampagna src gnome org>
Date:   Sun Feb 24 18:38:24 2013 +0100

    Add a shell search provider for passwords and keys
    
    Turn the seahorse application into a dbus activate service, and install
    a handler for the search provider interface. This will allow to search
    passwords from the overview, which is useful when using seahorse to
    store personal passwords not created by applications.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=694606

 data/.gitignore                                |   1 +
 data/Makefile.am                               |  11 +-
 data/org.gnome.seahorse.Application.service.in |   3 +
 data/seahorse-search-provider.ini              |   5 +
 libseahorse/.gitignore                         |   2 +
 libseahorse/Makefile.am                        |  19 +-
 libseahorse/org.gnome.ShellSearchProvider2.xml |  87 +++++
 libseahorse/seahorse-application.c             |  99 +++++-
 libseahorse/seahorse-search-provider.c         | 449 +++++++++++++++++++++++++
 libseahorse/seahorse-search-provider.h         |  51 +++
 src/seahorse-key-manager.xml                   |   1 +
 11 files changed, 725 insertions(+), 3 deletions(-)
---
diff --git a/data/.gitignore b/data/.gitignore
index b83c2e7..bc4f24d 100644
--- a/data/.gitignore
+++ b/data/.gitignore
@@ -2,3 +2,4 @@
 /Makefile.in
 /seahorse.desktop
 /seahorse.schemas
+/org.gnome.seahorse.Application.service
diff --git a/data/Makefile.am b/data/Makefile.am
index 2ac0da6..1203e08 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -15,6 +15,15 @@ convert_DATA = \
 convertdir = \
        $(datarootdir)/GConf/gsettings
 
+servicedir = $(datadir)/dbus-1/services
+service_DATA = $(service_in_files:.service.in=.service)
+service_in_files =                             \
+       org.gnome.seahorse.Application.service.in
+
+searchproviderdir = $(datadir)/gnome-shell/search-providers
+dist_searchprovider_DATA = seahorse-search-provider.ini
+
 EXTRA_DIST = \
        $(convert_DATA) \
-       $(gsettings_SCHEMAS)
\ No newline at end of file
+       $(gsettings_SCHEMAS) \
+       $(service_in_files)
diff --git a/data/org.gnome.seahorse.Application.service.in b/data/org.gnome.seahorse.Application.service.in
new file mode 100644
index 0000000..977ce64
--- /dev/null
+++ b/data/org.gnome.seahorse.Application.service.in
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=org.gnome.seahorse.Application
+Exec= bindir@/seahorse --no-window
diff --git a/data/seahorse-search-provider.ini b/data/seahorse-search-provider.ini
new file mode 100644
index 0000000..03c6b2b
--- /dev/null
+++ b/data/seahorse-search-provider.ini
@@ -0,0 +1,5 @@
+[Shell Search Provider]
+DesktopId=seahorse.desktop
+BusName=org.gnome.seahorse.Application
+ObjectPath=/org/gnome/seahorse/Application
+Version=2
diff --git a/libseahorse/.gitignore b/libseahorse/.gitignore
index 5bd42a5..7401788 100644
--- a/libseahorse/.gitignore
+++ b/libseahorse/.gitignore
@@ -16,3 +16,5 @@
 /xloadimage
 /seahorse-ssh-askpass
 /*.loT
+/seahorse-shell-search-provider-generated.c
+/seahorse-shell-search-provider-generated.h
diff --git a/libseahorse/Makefile.am b/libseahorse/Makefile.am
index a90e81b..400d248 100644
--- a/libseahorse/Makefile.am
+++ b/libseahorse/Makefile.am
@@ -13,10 +13,24 @@ INCLUDES = -I$(top_builddir) \
        -DLOCALEDIR=\"$(localedir)\" \
        -DEXECDIR=\""$(seahorselibexecbindir)"\"
 
+dbus_shell_search_provider_built_sources =     \
+       seahorse-shell-search-provider-generated.c      \
+       seahorse-shell-search-provider-generated.h
+
+# The upstream for the DBus interface definition is
+# at http://git.gnome.org/browse/gnome-shell/plain/data/org.gnome.ShellSearchProvider2.xml
+$(dbus_shell_search_provider_built_sources) : Makefile.am $(srcdir)/org.gnome.ShellSearchProvider2.xml
+       gdbus-codegen                                                           \
+               --interface-prefix org.gnome.                                   \
+               --c-namespace Seahorse                                          \
+               --generate-c-code seahorse-shell-search-provider-generated      \
+               $(srcdir)/org.gnome.ShellSearchProvider2.xml
+
 MARSHAL_SRCS = \
        seahorse-marshal.c seahorse-marshal.h
 
 BUILT_SOURCES = \
+       $(dbus_shell_search_provider_built_sources) \
        $(MARSHAL_SRCS)
 
 noinst_LTLIBRARIES = libseahorse.la
@@ -56,12 +70,14 @@ libseahorse_la_SOURCES = \
        seahorse-prefs.c seahorse-prefs.h \
        seahorse-progress.c seahorse-progress.h \
        seahorse-registry.c seahorse-registry.h \
+       seahorse-search-provider.c seahorse-search-provider.h \
        seahorse-servers.c seahorse-servers.h \
        seahorse-types.c seahorse-types.h \
        seahorse-util.c seahorse-util.h \
        seahorse-validity.c seahorse-validity.h \
        seahorse-viewable.c seahorse-viewable.h \
        seahorse-widget.c seahorse-widget.h \
+       $(dbus_shell_search_provider_built_sources) \
        $(MARSHAL_SRCS) \
        $(KEYSERVER_SRCS)
 
@@ -79,4 +95,5 @@ ui_DATA = \
        seahorse.css
 
 EXTRA_DIST = $(ui_DATA) \
-       seahorse-marshal.list
+       seahorse-marshal.list \
+       org.gnome.ShellSearchProvider2.xml
diff --git a/libseahorse/org.gnome.ShellSearchProvider2.xml b/libseahorse/org.gnome.ShellSearchProvider2.xml
new file mode 100644
index 0000000..7947d03
--- /dev/null
+++ b/libseahorse/org.gnome.ShellSearchProvider2.xml
@@ -0,0 +1,87 @@
+<!DOCTYPE node PUBLIC
+'-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'
+'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>
+<node>
+
+  <!--
+      org.gnome.Shell.SearchProvider2:
+      @short_description: Search provider interface
+
+      The interface used for integrating into GNOME Shell's search
+      interface (version 2).
+  -->
+  <interface name="org.gnome.Shell.SearchProvider2">
+
+    <!--
+        GetInitialResultSet:
+        @terms: Array of search terms, which the provider should treat as logical AND.
+        @results: An array of result identifier strings representing items which match the given search 
terms. Identifiers must be unique within the provider's domain, but other than that may be chosen freely by 
the provider.
+
+        Called when the user first begins a search.
+    -->
+    <method name="GetInitialResultSet">
+      <arg type="as" name="terms" direction="in" />
+      <arg type="as" name="results" direction="out" />
+    </method>
+
+    <!--
+        GetSubsearchResultSet:
+        @previous_results: Array of results previously returned by GetInitialResultSet().
+        @terms: Array of updated search terms, which the provider should treat as logical AND.
+        @results: An array of result identifier strings representing items which match the given search 
terms. Identifiers must be unique within the provider's domain, but other than that may be chosen freely by 
the provider.
+
+        Called when a search is performed which is a "subsearch" of
+        the previous search, e.g. the method may return less results, but
+        not more or different results.
+
+        This allows search providers to only search through the previous
+        result set, rather than possibly performing a full re-query.
+    -->
+    <method name="GetSubsearchResultSet">
+      <arg type="as" name="previous_results" direction="in" />
+      <arg type="as" name="terms" direction="in" />
+      <arg type="as" name="results" direction="out" />
+    </method>
+
+    <!--
+        GetResultMetas:
+        @identifiers: An array of result identifiers as returned by GetInitialResultSet() or 
GetSubsearchResultSet()
+        @metas: A dictionary describing the given search result, containing a human-readable 'name' 
(string), along with the result identifier this meta is for, 'id' (string). Optionally, either 'gicon' (a 
serialized GIcon) or 'icon-data' (raw image data as (iiibiiay) - width, height, rowstride, has-alpha, bits 
per sample, channels, data) can be specified if the result can be better served with a thumbnail of the 
content (such as with images). A 'description' field (string) may also be specified if more context would 
help the user find the desired result.
+
+        Return an array of meta data used to display each given result
+    -->
+    <method name="GetResultMetas">
+      <arg type="as" name="identifiers" direction="in" />
+      <arg type="aa{sv}" name="metas" direction="out" />
+    </method>
+
+    <!--
+        ActivateResult:
+        @identifier: A result identifier as returned by GetInitialResultSet() or GetSubsearchResultSet()
+        @terms: Array of search terms, which the provider should treat as logical AND.
+        @timestamp: A timestamp of the user interaction that triggered this call
+
+        Called when the users chooses a given result. The result should
+        be displayed in the application associated with the corresponding
+        provider. The provided search terms can be used to allow launching a full search in
+        the application.
+    -->
+    <method name="ActivateResult">
+      <arg type="s" name="identifier" direction="in" />
+      <arg type="as" name="terms" direction="in" />
+      <arg type="u" name="timestamp" direction="in" />
+    </method>
+
+    <!--
+        LaunchSearch:
+        @terms: Array of search terms, which the provider should treat as logical AND.
+        @timestamp: A timestamp of the user interaction that triggered this call
+
+        Asks the search provider to launch a full search in the application for the provided terms.
+    -->
+    <method name="LaunchSearch">
+      <arg type="as" name="terms" direction="in" />
+      <arg type="u" name="timestamp" direction="in" />
+    </method>
+  </interface>
+</node>
diff --git a/libseahorse/seahorse-application.c b/libseahorse/seahorse-application.c
index 6bbc70a..a799cad 100644
--- a/libseahorse/seahorse-application.c
+++ b/libseahorse/seahorse-application.c
@@ -32,6 +32,8 @@
 #include "ssh/seahorse-ssh.h"
 #include "pkcs11/seahorse-pkcs11.h"
 
+#include "seahorse-search-provider.h"
+
 #include <gtk/gtk.h>
 
 #include <glib/gi18n.h>
@@ -40,12 +42,16 @@ struct _SeahorseApplication {
        GtkApplication parent;
        GSettings *seahorse_settings;
        GSettings *crypto_pgp_settings;
+
+       SeahorseSearchProvider *search_provider;
 };
 
 struct _SeahorseApplicationClass {
        GtkApplicationClass parent_class;
 };
 
+#define INACTIVITY_TIMEOUT 60 * 1000 /* One minute, in milliseconds */
+
 G_DEFINE_TYPE (SeahorseApplication, seahorse_application, GTK_TYPE_APPLICATION);
 
 static SeahorseApplication *the_application = NULL;
@@ -80,6 +86,8 @@ seahorse_application_finalize (GObject *gobject)
 #endif
        g_clear_object (&self->seahorse_settings);
 
+       g_clear_object (&self->search_provider);
+
        G_OBJECT_CLASS (seahorse_application_parent_class)->finalize (gobject);
 }
 
@@ -101,6 +109,12 @@ seahorse_application_startup (GApplication *application)
 #endif
        seahorse_gkr_backend_initialize ();
 
+       seahorse_search_provider_initialize (SEAHORSE_APPLICATION (application)->search_provider);
+
+       /* HACK: get the inactivity timeout started */
+       g_application_hold (application);
+       g_application_release (application);
+
        G_APPLICATION_CLASS (seahorse_application_parent_class)->startup (application);
 }
 
@@ -122,6 +136,7 @@ seahorse_application_local_command_line (GApplication *application,
        argc = g_strv_length (*arguments);
 
        context = g_option_context_new (N_("- System Settings"));
+       g_option_context_set_ignore_unknown_options (context, TRUE);
        g_option_context_add_main_entries (context, options, GETTEXT_PACKAGE);
        g_option_context_set_translation_domain(context, GETTEXT_PACKAGE);
        g_option_context_add_group (context, gtk_get_option_group (TRUE));
@@ -148,6 +163,83 @@ seahorse_application_local_command_line (GApplication *application,
        return G_APPLICATION_CLASS (seahorse_application_parent_class)->local_command_line (application, 
arguments, exit_status);
 }
 
+static int
+seahorse_application_command_line (GApplication            *application,
+                                  GApplicationCommandLine *command_line)
+{
+       GOptionContext *context;
+       gboolean no_window = FALSE;
+       char **arguments;
+       GError *error = NULL;
+       int ret;
+       int argc;
+
+       GOptionEntry options[] = {
+               { "no-window", 0, 0, G_OPTION_ARG_NONE, &no_window, N_("Don't display a window"), NULL },
+               { NULL, 0, 0, 0, NULL, NULL, NULL }
+       };
+
+       context = g_option_context_new (N_("- System Settings"));
+       g_option_context_set_ignore_unknown_options (context, TRUE);
+       g_option_context_add_main_entries (context, options, GETTEXT_PACKAGE);
+       g_option_context_set_translation_domain(context, GETTEXT_PACKAGE);
+
+       arguments = g_application_command_line_get_arguments (command_line, &argc);
+       if (g_option_context_parse (context, &argc, &arguments, &error) == FALSE) {
+               g_warning ("seahorse: %s\n", error->message);
+               g_error_free (error);
+               ret = 1;
+       } else if (no_window) {
+               g_application_hold (application);
+               g_application_set_inactivity_timeout (application, INACTIVITY_TIMEOUT);
+               g_application_release (application);
+               ret = 0;
+       } else {
+               g_application_activate (application);
+               ret = 0;
+       }
+
+       g_strfreev (arguments);
+       g_option_context_free (context);
+       return ret;
+}
+
+static gboolean
+seahorse_application_dbus_register (GApplication    *application,
+                                    GDBusConnection *connection,
+                                    const gchar     *object_path,
+                                    GError         **error)
+{
+       SeahorseApplication *self;
+
+       if (!G_APPLICATION_CLASS (seahorse_application_parent_class)->dbus_register (application,
+                                                                                    connection,
+                                                                                    object_path,
+                                                                                    error))
+               return FALSE;
+
+       self = SEAHORSE_APPLICATION (application);
+
+       return seahorse_search_provider_dbus_register (self->search_provider, connection,
+                                                      object_path, error);
+}
+
+static void
+seahorse_application_dbus_unregister (GApplication    *application,
+                                        GDBusConnection *connection,
+                                        const gchar     *object_path)
+{
+       SeahorseApplication *self;
+
+       self = SEAHORSE_APPLICATION (application);
+       if (self->search_provider)
+               seahorse_search_provider_dbus_unregister (self->search_provider, connection, object_path);
+
+       G_APPLICATION_CLASS (seahorse_application_parent_class)->dbus_unregister (application,
+                                                                                 connection,
+                                                                                 object_path);
+}
+
 static void
 seahorse_application_class_init (SeahorseApplicationClass *klass)
 {
@@ -159,12 +251,16 @@ seahorse_application_class_init (SeahorseApplicationClass *klass)
 
        application_class->startup = seahorse_application_startup;
        application_class->local_command_line = seahorse_application_local_command_line;
+       application_class->command_line = seahorse_application_command_line;
+
+       application_class->dbus_register = seahorse_application_dbus_register;
+       application_class->dbus_unregister = seahorse_application_dbus_unregister;
 }
 
 static void
 seahorse_application_init (SeahorseApplication *self)
 {
-
+       self->search_provider = seahorse_search_provider_new ();
 }
 
 GtkApplication *
@@ -172,6 +268,7 @@ seahorse_application_new (void)
 {
        return g_object_new (SEAHORSE_TYPE_APPLICATION,
                             "application-id", "org.gnome.seahorse.Application",
+                            "flags", G_APPLICATION_HANDLES_COMMAND_LINE,
                             NULL);
 }
 
diff --git a/libseahorse/seahorse-search-provider.c b/libseahorse/seahorse-search-provider.c
new file mode 100644
index 0000000..4729e3e
--- /dev/null
+++ b/libseahorse/seahorse-search-provider.c
@@ -0,0 +1,449 @@
+/*
+ * Seahorse
+ *
+ * Copyright (C) 2013 Giovanni Campagna <scampa giovanni gmail com>
+ *
+ * This program 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.
+ *
+ * This program 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
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include <string.h>
+
+#include <gcr/gcr.h>
+#define SECRET_API_SUBJECT_TO_CHANGE
+#include <libsecret/secret.h>
+
+#include "seahorse-backend.h"
+#include "seahorse-predicate.h"
+#include "seahorse-viewable.h"
+#include "seahorse-widget.h"
+#include "seahorse-collection.h"
+
+#include "seahorse-shell-search-provider-generated.h"
+#include "seahorse-search-provider.h"
+
+struct _SeahorseSearchProvider {
+       SeahorseShellSearchProvider2Skeleton parent;
+
+       GcrUnionCollection *union_collection;
+
+       SeahorsePredicate base_predicate;
+       GcrCollection *collection;
+};
+
+struct _SeahorseSearchProviderClass {
+       SeahorseShellSearchProvider2SkeletonClass parent_class;
+};
+
+static void seahorse_shell_search_provider2_iface_init (SeahorseShellSearchProvider2Iface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (SeahorseSearchProvider, seahorse_search_provider, 
SEAHORSE_TYPE_SHELL_SEARCH_PROVIDER2_SKELETON,
+                         G_IMPLEMENT_INTERFACE (SEAHORSE_TYPE_SHELL_SEARCH_PROVIDER2, 
seahorse_shell_search_provider2_iface_init))
+
+/* Search through row for text */
+static gboolean
+object_contains_filtered_text (GObject     *object,
+                              const gchar *text)
+{
+       gchar* name = NULL;
+       gchar* description = NULL;
+       gchar* lower;
+       gboolean ret = FALSE;
+
+       g_object_get (object, "label", &name, NULL);
+       if (name != NULL) {
+               lower = g_utf8_strdown (name, -1);
+               if (strstr (lower, text))
+                       ret = TRUE;
+               g_free (lower);
+               g_free (name);
+       }
+
+       if (!ret && g_object_class_find_property (G_OBJECT_GET_CLASS (object), "description")) {
+               g_object_get (object, "description", &description, NULL);
+               if (description != NULL) {
+                       lower = g_utf8_strdown (description, -1);
+                       if (strstr (lower, text))
+                               ret = TRUE;
+                       g_free (lower);
+                       g_free (description);
+               }
+       }
+
+       return ret;
+}
+
+static gboolean
+object_matches_search (GObject     *object,
+                      gpointer     user_data)
+{
+       char **terms = user_data;
+       int i;
+
+       for (i = 0; terms[i]; i++) {
+               if (!object_contains_filtered_text (object, terms[i]))
+                       return FALSE;
+       }
+
+       return TRUE;
+}
+
+static void
+init_predicate (SeahorsePredicate  *predicate,
+                char              **terms)
+{
+       memset(predicate, 0, sizeof(SeahorsePredicate));
+
+       predicate->custom = object_matches_search;
+       predicate->custom_target = terms;
+}
+
+static gboolean
+handle_get_initial_result_set (SeahorseShellSearchProvider2 *skeleton,
+                               GDBusMethodInvocation        *invocation,
+                               const char * const           *terms)
+{
+       SeahorseSearchProvider *self = SEAHORSE_SEARCH_PROVIDER (skeleton);
+       SeahorsePredicate   predicate;
+       GPtrArray *array;
+       GList *objects, *l;
+       char **results;
+
+       init_predicate (&predicate, (char **) terms);
+
+       array = g_ptr_array_new ();
+       objects = gcr_collection_get_objects (self->collection);
+
+       for (l = objects; l; l = l->next) {
+               if (seahorse_predicate_match (&predicate, l->data)) {
+                       char *str = g_strdup_printf("%p", l->data);
+
+                       g_ptr_array_add (array, str);
+               }
+       }
+
+       g_list_free (objects);
+       g_ptr_array_add (array, NULL);
+       results = (char **) g_ptr_array_free (array, FALSE);
+
+       seahorse_shell_search_provider2_complete_get_initial_result_set (skeleton,
+                                                                        invocation,
+                                                                        (const char* const*) results);
+
+       g_strfreev (results);
+       return TRUE;
+}
+
+static gboolean
+handle_get_subsearch_result_set (SeahorseShellSearchProvider2 *skeleton,
+                                 GDBusMethodInvocation        *invocation,
+                                 const char * const           *previous_results,
+                                 const char * const           *terms)
+{
+       SeahorseSearchProvider *self = SEAHORSE_SEARCH_PROVIDER (skeleton);
+       SeahorsePredicate   predicate;
+       GPtrArray *array;
+       int i;
+       char **results;
+
+       init_predicate (&predicate, (char **) terms);
+
+       array = g_ptr_array_new ();
+
+       for (i = 0; previous_results[i]; i++) {
+               GObject *object;
+
+               sscanf (previous_results[i], "%p", &object);
+
+               if (!gcr_collection_contains (self->collection, object)) {
+                       /* Bogus value */
+                       continue;
+               }
+
+               if (seahorse_predicate_match (&predicate, object)) {
+                       g_ptr_array_add (array, (char*) previous_results[i]);
+               }
+       }
+
+       g_ptr_array_add (array, NULL);
+       results = (char **) g_ptr_array_free (array, FALSE);
+
+       seahorse_shell_search_provider2_complete_get_subsearch_result_set (skeleton,
+                                                                          invocation,
+                                                                          (const char* const*) results);
+
+       /* g_free, not g_strfreev, because we don't duplicate result strings */
+       g_free (results);
+       return TRUE;
+}
+
+static gboolean
+handle_get_result_metas (SeahorseShellSearchProvider2 *skeleton,
+                         GDBusMethodInvocation        *invocation,
+                         const char * const           *results)
+{
+       SeahorseSearchProvider *self = SEAHORSE_SEARCH_PROVIDER (skeleton);
+       int i;
+       GVariantBuilder builder;
+       char *name, *description, *escaped_description, *icon_string;
+       GIcon *icon;
+
+       g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}"));
+
+       for (i = 0; results[i]; i++) {
+               GObject *object;
+
+               sscanf (results[i], "%p", &object);
+
+               if (!gcr_collection_contains (self->collection, object)) {
+                       /* Bogus value */
+                       continue;
+               }
+
+               g_object_get (object,
+                             "label", &name,
+                             "icon", &icon,
+                             "description", &description,
+                             NULL);
+
+               g_variant_builder_open (&builder, G_VARIANT_TYPE ("a{sv}"));
+               g_variant_builder_add (&builder, "{sv}",
+                                      "id", g_variant_new_string (results[i]));
+               if (name) {
+                       g_variant_builder_add (&builder, "{sv}",
+                                              "name", g_variant_new_string (name));
+                       g_free (name);
+               }
+               if (icon) {
+                       icon_string = g_icon_to_string (icon);
+                       g_variant_builder_add (&builder, "{sv}",
+                                              "gicon",
+                                              icon_string ? g_variant_new_string (icon_string) : NULL);
+                       g_free (icon_string);
+                       g_object_unref (icon);
+               }
+               if (description) {
+                       escaped_description = description ? g_markup_escape_text (description, -1) : NULL;
+                       g_variant_builder_add (&builder, "{sv}",
+                                              "description",
+                                              escaped_description ? g_variant_new_string (description) : 
NULL);
+                       g_free (escaped_description);
+                       g_free (description);
+               }
+
+               g_variant_builder_close (&builder);
+       }
+
+       seahorse_shell_search_provider2_complete_get_result_metas (skeleton,
+                                                                  invocation,
+                                                                  g_variant_builder_end (&builder));
+       return TRUE;
+}
+
+static gboolean
+handle_activate_result (SeahorseShellSearchProvider2 *skeleton,
+                        GDBusMethodInvocation        *invocation,
+                        const char                   *identifier,
+                        const char * const           *results,
+                        guint                         timestamp)
+{
+       SeahorseSearchProvider *self = SEAHORSE_SEARCH_PROVIDER (skeleton);
+       GObject *object;
+       SeahorseWidget *key_manager;
+       GtkWindow *window;
+
+       sscanf (identifier, "%p", &object);
+
+       if (!gcr_collection_contains (self->collection, object) ||
+           !SEAHORSE_IS_VIEWABLE (object)) {
+               /* Bogus value */
+               return TRUE;
+       }
+
+       key_manager = seahorse_widget_find ("key-manager");
+       if (key_manager == NULL) {
+               GtkApplication *app;
+
+               app = seahorse_application_get ();
+               g_application_activate (G_APPLICATION (app));
+
+               key_manager = seahorse_widget_find ("key-manager");
+       }
+
+       window = GTK_WINDOW (seahorse_widget_get_widget (key_manager, key_manager->name));
+       gtk_window_present_with_time (window, timestamp);
+
+       seahorse_viewable_show_viewer (SEAHORSE_VIEWABLE (object), window);
+
+       seahorse_shell_search_provider2_complete_activate_result (skeleton,
+                                                                 invocation);
+
+       return TRUE;
+}
+
+static gboolean
+handle_launch_search (SeahorseShellSearchProvider2  *skeleton,
+                      GDBusMethodInvocation         *invocation,
+                      const char * const            *terms,
+                      guint                          timestamp)
+{
+       /* TODO */
+       return FALSE;
+}
+
+static void
+on_place_added (GcrCollection *places,
+                GObject       *place,
+                gpointer       user_data)
+{
+       SeahorseSearchProvider *self = SEAHORSE_SEARCH_PROVIDER (user_data);
+
+       if (!gcr_union_collection_have (self->union_collection,
+                                       GCR_COLLECTION (place)))
+               gcr_union_collection_add (self->union_collection,
+                                         GCR_COLLECTION (place));
+}
+
+static void
+on_place_removed (GcrCollection *places,
+                  GObject       *place,
+                  gpointer       user_data)
+{
+       SeahorseSearchProvider *self = SEAHORSE_SEARCH_PROVIDER (user_data);
+
+       if (gcr_union_collection_have (self->union_collection,
+                                      GCR_COLLECTION (place)))
+               gcr_union_collection_remove (self->union_collection,
+                                            GCR_COLLECTION (place));
+}
+
+void
+seahorse_search_provider_initialize (SeahorseSearchProvider *self)
+{
+       GList *backends, *l;
+       GList *places, *p;
+
+       backends = seahorse_backend_get_registered ();
+       for (l = backends; l != NULL; l = g_list_next (l)) {
+               g_signal_connect_object (l->data, "added", G_CALLBACK (on_place_added), self, 0);
+               g_signal_connect_object (l->data, "removed", G_CALLBACK (on_place_removed), self, 0);
+
+               places = gcr_collection_get_objects (l->data);
+               for (p = places; p != NULL; p = g_list_next (p))
+                       on_place_added (l->data, p->data, self);
+               g_list_free (places);
+       }
+       g_list_free (backends);
+}
+
+static gboolean
+check_object_type (GObject  *object,
+                  gpointer  user_data)
+{
+       if (!SEAHORSE_IS_VIEWABLE (object))
+               return FALSE;
+
+       if (SECRET_IS_ITEM (object)) {
+               const char *schema_name;
+
+               schema_name = secret_item_get_schema_name (SECRET_ITEM (object));
+               if (g_strcmp0 (schema_name, "org.gnome.keyring.Note") != 0)
+                       return FALSE;
+       }
+
+       return TRUE;
+}
+
+static void
+seahorse_shell_search_provider2_iface_init (SeahorseShellSearchProvider2Iface *iface)
+{
+       iface->handle_get_initial_result_set = handle_get_initial_result_set;
+       iface->handle_get_subsearch_result_set = handle_get_subsearch_result_set;
+       iface->handle_get_result_metas = handle_get_result_metas;
+       iface->handle_activate_result = handle_activate_result;
+       iface->handle_launch_search = handle_launch_search;
+}
+
+static void
+seahorse_search_provider_init (SeahorseSearchProvider *self)
+{
+       SeahorseCollection *filtered;
+       GcrCollection *base;
+
+       base = gcr_union_collection_new ();
+       self->union_collection = GCR_UNION_COLLECTION (base);
+
+       self->base_predicate.flags = SEAHORSE_FLAG_PERSONAL;
+       self->base_predicate.custom = check_object_type;
+
+       filtered = seahorse_collection_new_for_predicate (base,
+                                                         &self->base_predicate, NULL);
+       self->collection = GCR_COLLECTION (filtered);
+}
+
+gboolean
+seahorse_search_provider_dbus_register (SeahorseSearchProvider  *self,
+                                       GDBusConnection         *connection,
+                                       const gchar             *object_path,
+                                       GError                 **error)
+{
+       GDBusInterfaceSkeleton *skeleton;
+
+       skeleton = G_DBUS_INTERFACE_SKELETON (self);
+
+       return g_dbus_interface_skeleton_export (skeleton, connection, object_path, error);
+}
+
+void
+seahorse_search_provider_dbus_unregister (SeahorseSearchProvider *self,
+                                         GDBusConnection        *connection,
+                                         const gchar            *object_path)
+{
+       GDBusInterfaceSkeleton *skeleton;
+
+       skeleton = G_DBUS_INTERFACE_SKELETON (self);
+
+       if (g_dbus_interface_skeleton_has_connection (skeleton, connection))
+               g_dbus_interface_skeleton_unexport_from_connection (skeleton, connection);
+}
+
+static void
+seahorse_search_provider_dispose (GObject *object)
+{
+       SeahorseSearchProvider *self;
+
+       self = SEAHORSE_SEARCH_PROVIDER (object);
+
+       g_clear_object (&self->collection);
+
+       G_OBJECT_CLASS (seahorse_search_provider_parent_class)->dispose (object);
+}
+
+static void
+seahorse_search_provider_class_init (SeahorseSearchProviderClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+       object_class->dispose = seahorse_search_provider_dispose;
+}
+
+SeahorseSearchProvider *
+seahorse_search_provider_new (void)
+{
+       return g_object_new (SEAHORSE_TYPE_SEARCH_PROVIDER, NULL);
+}
+
diff --git a/libseahorse/seahorse-search-provider.h b/libseahorse/seahorse-search-provider.h
new file mode 100644
index 0000000..fa3d217
--- /dev/null
+++ b/libseahorse/seahorse-search-provider.h
@@ -0,0 +1,51 @@
+/*
+ * Seahorse
+ *
+ * Copyright (C) 2013 Giovanni Campagna <scampa giovanni gmail com>
+ *
+ * This program 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.
+ *
+ * This program 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
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __SEAHORSE_SEARCH_PROVIDER_H__
+#define __SEAHORSE_SEARCH_PROVIDER_H__
+
+#include <gio/gio.h>
+
+#define SEAHORSE_TYPE_SEARCH_PROVIDER                   (seahorse_search_provider_get_type ())
+#define SEAHORSE_SEARCH_PROVIDER(obj)                   (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
SEAHORSE_TYPE_SEARCH_PROVIDER, SeahorseSearchProvider))
+#define SEAHORSE_SEARCH_PROVIDER_CLASS(klass)           (G_TYPE_CHECK_CLASS_CAST ((klass), 
SEAHORSE_TYPE_SEARCH_PROVIDER, SeahorseSearchProviderClass))
+#define SEAHORSE_IS_SEARCH_PROVIDER(obj)                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), 
SEAHORSE_TYPE_SEARCH_PROVIDER))
+#define SEAHORSE_IS_SEARCH_PROVIDER_CLASS(klass)        (G_TYPE_CHECK_CLASS_TYPE ((klass), 
SEAHORSE_TYPE_SEARCH_PROVIDER))
+#define SEAHORSE_SEARCH_PROVIDER_GET_CLASS(obj)         (G_TYPE_INSTANCE_GET_CLASS ((obj), 
SEAHORSE_TYPE_SEARCH_PROVIDER, SeahorseSearchProviderClass))
+
+typedef struct _SeahorseSearchProvider SeahorseSearchProvider;
+typedef struct _SeahorseSearchProviderClass SeahorseSearchProviderClass;
+
+GType                    seahorse_search_provider_get_type           (void);
+
+SeahorseSearchProvider * seahorse_search_provider_new                (void);
+
+gboolean                 seahorse_search_provider_dbus_register      (SeahorseSearchProvider  *provider,
+                                                                      GDBusConnection         *connection,
+                                                                      const char              *object_path,
+                                                                      GError                 **error);
+void                     seahorse_search_provider_dbus_unregister    (SeahorseSearchProvider  *provider,
+                                                                      GDBusConnection         *connection,
+                                                                      const char              *object_path);
+
+void                     seahorse_search_provider_initialize         (SeahorseSearchProvider  *provider);
+
+#endif /* __SEAHORSE_SEARCH_PROVIDER_H__ */
diff --git a/src/seahorse-key-manager.xml b/src/seahorse-key-manager.xml
index 30460de..ea8f3d5 100644
--- a/src/seahorse-key-manager.xml
+++ b/src/seahorse-key-manager.xml
@@ -6,6 +6,7 @@
     <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | 
GDK_BUTTON_RELEASE_MASK</property>
     <property name="default_width">640</property>
     <property name="default_height">476</property>
+    <signal name="delete-event" handler="on_widget_delete_event" swapped="no"/>
     <child>
       <object class="GtkVBox" id="vbox1">
         <property name="visible">True</property>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]