[libsecret] Accept NULL as a SecretService parameter for many methods



commit 600021a30b9266ebf805e86ac3520570ad8c9d56
Author: Stef Walter <stefw gnome org>
Date:   Thu Jul 5 23:14:50 2012 +0200

    Accept NULL as a SecretService parameter for many methods
    
     * We use secret_service_get() to lookup the default
       SecretService in these cases.
     * Use this functionality in the secret_password_xxx()
       functions to greatly simplify them.

 library/secret-collection.c     |  168 +++++++++--
 library/secret-item.c           |   76 ++++-
 library/secret-methods.c        |  665 +++++++++++++++++++++++++++++----------
 library/secret-password.c       |  312 ++-----------------
 library/secret-service.c        |   51 ++--
 library/secret-service.h        |   84 +++---
 library/tests/test-collection.c |    1 +
 library/tests/test-item.c       |    1 +
 library/tests/test-methods.c    |    1 +
 library/tests/test-password.c   |    1 +
 library/tests/test-paths.c      |    1 +
 library/tests/test-prompt.c     |    1 +
 library/tests/test-service.c    |   11 +-
 library/tests/test-session.c    |    1 +
 14 files changed, 820 insertions(+), 554 deletions(-)
---
diff --git a/library/secret-collection.c b/library/secret-collection.c
index cdf87b2..94d606f 100644
--- a/library/secret-collection.c
+++ b/library/secret-collection.c
@@ -139,6 +139,23 @@ on_set_label (GObject *source,
 }
 
 static void
+collection_take_service (SecretCollection *self,
+                         SecretService *service)
+{
+	if (service == NULL)
+		return;
+
+	g_return_if_fail (self->pv->service == NULL);
+
+	self->pv->service = service;
+	g_object_add_weak_pointer (G_OBJECT (self->pv->service),
+	                           (gpointer *)&self->pv->service);
+
+	/* Yes, we expect that the service will stay around */
+	g_object_unref (service);
+}
+
+static void
 secret_collection_set_property (GObject *obj,
                                 guint prop_id,
                                 const GValue *value,
@@ -148,11 +165,7 @@ secret_collection_set_property (GObject *obj,
 
 	switch (prop_id) {
 	case PROP_SERVICE:
-		g_return_if_fail (self->pv->service == NULL);
-		self->pv->service = g_value_get_object (value);
-		if (self->pv->service)
-			g_object_add_weak_pointer (G_OBJECT (self->pv->service),
-			                           (gpointer *)&self->pv->service);
+		collection_take_service (self, g_value_dup_object (value));
 		break;
 	case PROP_FLAGS:
 		self->pv->init_flags = g_value_get_flags (value);
@@ -494,6 +507,7 @@ secret_collection_initable_init (GInitable *initable,
                                  GError **error)
 {
 	SecretCollection *self;
+	SecretService *service;
 	GDBusProxy *proxy;
 
 	if (!secret_collection_initable_parent_iface->init (initable, cancellable, error))
@@ -510,6 +524,14 @@ secret_collection_initable_init (GInitable *initable,
 
 	self = SECRET_COLLECTION (initable);
 
+	if (self->pv->service == NULL) {
+		service = secret_service_get_sync (SECRET_SERVICE_NONE, cancellable, error);
+		if (service == NULL)
+			return FALSE;
+		else
+			collection_take_service (self, service);
+	}
+
 	if (self->pv->init_flags & SECRET_COLLECTION_LOAD_ITEMS) {
 		if (!secret_collection_load_items_sync (self, cancellable, error))
 			return FALSE;
@@ -556,13 +578,52 @@ on_init_items (GObject *source,
 }
 
 static void
+collection_ensure_for_flags_async (SecretCollection *self,
+                                   SecretCollectionFlags flags,
+                                   GSimpleAsyncResult *async)
+{
+	InitClosure *init = g_simple_async_result_get_op_res_gpointer (async);
+
+	if (flags & SECRET_COLLECTION_LOAD_ITEMS)
+		secret_collection_load_items (self, init->cancellable,
+		                              on_init_items, g_object_ref (async));
+
+	else
+		g_simple_async_result_complete (async);
+}
+
+static void
+on_init_service (GObject *source,
+                 GAsyncResult *result,
+                 gpointer user_data)
+{
+	GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
+	SecretCollection *self = SECRET_COLLECTION (g_async_result_get_source_object (user_data));
+	SecretService *service;
+	GError *error = NULL;
+
+	service = secret_service_get_finish (result, &error);
+	if (error == NULL) {
+		collection_take_service (self, service);
+		collection_ensure_for_flags_async (self, self->pv->init_flags, async);
+
+	} else {
+		g_simple_async_result_take_error (async, error);
+		g_simple_async_result_complete (async);
+	}
+
+	g_object_unref (self);
+	g_object_unref (async);
+}
+
+static void
 on_init_base (GObject *source,
               GAsyncResult *result,
               gpointer user_data)
 {
 	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
 	SecretCollection *self = SECRET_COLLECTION (source);
-	InitClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	InitClosure *init = g_simple_async_result_get_op_res_gpointer (res);
 	GDBusProxy *proxy = G_DBUS_PROXY (self);
 	GError *error = NULL;
 
@@ -577,12 +638,12 @@ on_init_base (GObject *source,
 		                                 g_dbus_proxy_get_object_path (proxy));
 		g_simple_async_result_complete (res);
 
-	} else if (self->pv->init_flags & SECRET_COLLECTION_LOAD_ITEMS) {
-		secret_collection_load_items (self, closure->cancellable,
-		                              on_init_items, g_object_ref (res));
+	} else if (self->pv->service == NULL) {
+		secret_service_get (SECRET_SERVICE_NONE, init->cancellable,
+		                    on_init_service, g_object_ref (res));
 
 	} else {
-		g_simple_async_result_complete (res);
+		collection_ensure_for_flags_async (self, self->pv->init_flags, res);
 	}
 
 	g_object_unref (res);
@@ -640,7 +701,7 @@ secret_collection_async_initable_iface (GAsyncInitableIface *iface)
 
 /**
  * secret_collection_new:
- * @service: a secret service object
+ * @service: (allow-none): a secret service object
  * @collection_path: the D-Bus path of the collection
  * @flags: options for the collection initialization
  * @cancellable: optional cancellation object
@@ -649,6 +710,9 @@ secret_collection_async_initable_iface (GAsyncInitableIface *iface)
  *
  * Get a new collection proxy for a collection in the secret service.
  *
+ * If @service is NULL, then secret_service_get() will be called to get
+ * the default #SecretService proxy.
+ *
  * This method will return immediately and complete asynchronously.
  */
 void
@@ -661,7 +725,7 @@ secret_collection_new (SecretService *service,
 {
 	GDBusProxy *proxy;
 
-	g_return_if_fail (SECRET_IS_SERVICE (service));
+	g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service));
 	g_return_if_fail (collection_path != NULL);
 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
 
@@ -714,7 +778,7 @@ secret_collection_new_finish (GAsyncResult *result,
 
 /**
  * secret_collection_new_sync:
- * @service: a secret service object
+ * @service: (allow-none): a secret service object
  * @collection_path: the D-Bus path of the collection
  * @flags: options for the collection initialization
  * @cancellable: optional cancellation object
@@ -722,6 +786,9 @@ secret_collection_new_finish (GAsyncResult *result,
  *
  * Get a new collection proxy for a collection in the secret service.
  *
+ * If @service is NULL, then secret_service_get_sync() will be called to get
+ * the default #SecretService proxy.
+ *
  * This method may block indefinitely and should not be used in user interface
  * threads.
  *
@@ -737,7 +804,7 @@ secret_collection_new_sync (SecretService *service,
 {
 	GDBusProxy *proxy;
 
-	g_return_val_if_fail (SECRET_IS_SERVICE (service), NULL);
+	g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), NULL);
 	g_return_val_if_fail (collection_path != NULL, NULL);
 	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
 	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
@@ -988,6 +1055,8 @@ secret_collection_refresh (SecretCollection *self)
 typedef struct {
 	GCancellable *cancellable;
 	SecretCollection *collection;
+	GHashTable *properties;
+	gchar *alias;
 } CreateClosure;
 
 static void
@@ -996,6 +1065,8 @@ create_closure_free (gpointer data)
 	CreateClosure *closure = data;
 	g_clear_object (&closure->cancellable);
 	g_clear_object (&closure->collection);
+	g_hash_table_unref (closure->properties);
+	g_free (closure->alias);
 	g_slice_free (CreateClosure, closure);
 }
 
@@ -1040,6 +1111,31 @@ on_create_path (GObject *source,
 	g_object_unref (res);
 }
 
+static void
+on_create_service (GObject *source,
+                   GAsyncResult *result,
+                   gpointer user_data)
+{
+	GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
+	CreateClosure *create = g_simple_async_result_get_op_res_gpointer (async);
+	GError *error = NULL;
+	SecretService *service;
+
+	service = secret_service_get_finish (result, &error);
+	if (error == NULL) {
+		secret_service_create_collection_path (service, create->properties,
+		                                       create->alias, create->cancellable,
+		                                       on_create_path, g_object_ref (async));
+		g_object_unref (service);
+
+	} else {
+		g_simple_async_result_take_error (async, error);
+		g_simple_async_result_complete (async);
+	}
+
+	g_object_unref (async);
+}
+
 static GHashTable *
 collection_properties_new (const gchar *label)
 {
@@ -1058,7 +1154,7 @@ collection_properties_new (const gchar *label)
 
 /**
  * secret_collection_create:
- * @service: a secret service object
+ * @service: (allow-none): a secret service object
  * @label: label for the new collection
  * @alias: (allow-none): alias to assign to the collection
  * @cancellable: optional cancellation object
@@ -1076,6 +1172,10 @@ collection_properties_new (const gchar *label)
  * easily identify and share a collection. If you specify an @alias, and a
  * collection with that alias already exists, then a new collection will not
  * be created. The previous one will be returned instead.
+ *
+ * If @service is NULL, then secret_service_get() will be called to get
+ * the default #SecretService proxy.
+ *
  */
 void
 secret_collection_create (SecretService *service,
@@ -1087,9 +1187,8 @@ secret_collection_create (SecretService *service,
 {
 	GSimpleAsyncResult *res;
 	CreateClosure *closure;
-	GHashTable *properties;
 
-	g_return_if_fail (SECRET_IS_SERVICE (service));
+	g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service));
 	g_return_if_fail (label != NULL);
 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
 
@@ -1097,14 +1196,20 @@ secret_collection_create (SecretService *service,
 	                                 secret_collection_create);
 	closure = g_slice_new0 (CreateClosure);
 	closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+	closure->properties = collection_properties_new (label);
+	closure->alias = g_strdup (alias);
 	g_simple_async_result_set_op_res_gpointer (res, closure, create_closure_free);
 
-	properties = collection_properties_new (label);
+	if (service == NULL) {
+		secret_service_get (SECRET_SERVICE_NONE, cancellable,
+		                    on_create_service, g_object_ref (res));
 
-	secret_service_create_collection_path (service, properties, alias, cancellable,
-	                                       on_create_path, g_object_ref (res));
+	} else {
+		secret_service_create_collection_path (service, closure->properties,
+		                                       closure->alias, closure->cancellable,
+		                                       on_create_path, g_object_ref (res));
+	}
 
-	g_hash_table_unref (properties);
 	g_object_unref (res);
 }
 
@@ -1143,7 +1248,7 @@ secret_collection_create_finish (GAsyncResult *result,
 
 /**
  * secret_collection_create_sync:
- * @service: a secret service object
+ * @service: (allow-none): a secret service object
  * @label: label for the new collection
  * @alias: (allow-none): alias to assign to the collection
  * @cancellable: optional cancellation object
@@ -1161,6 +1266,9 @@ secret_collection_create_finish (GAsyncResult *result,
  * collection with that alias already exists, then a new collection will not
  * be created. The previous one will be returned instead.
  *
+ * If @service is NULL, then secret_service_get_sync() will be called to get
+ * the default #SecretService proxy.
+ *
  * Returns: (transfer full): the new collection, which should be unreferenced
  *          with g_object_unref()
  */
@@ -1175,11 +1283,19 @@ secret_collection_create_sync (SecretService *service,
 	GHashTable *properties;
 	gchar *path;
 
-	g_return_val_if_fail (SECRET_IS_SERVICE (service), NULL);
+	g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), NULL);
 	g_return_val_if_fail (label != NULL, NULL);
 	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
 	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
 
+	if (service == NULL) {
+		service = secret_service_get_sync (SECRET_SERVICE_NONE, cancellable, error);
+		if (service == NULL)
+			return NULL;
+	} else {
+		g_object_ref (service);
+	}
+
 	properties = collection_properties_new (label);
 
 	path = secret_service_create_collection_path_sync (service, properties, alias,
@@ -1187,12 +1303,16 @@ secret_collection_create_sync (SecretService *service,
 
 	g_hash_table_unref (properties);
 
-	if (path == NULL)
+	if (path == NULL) {
+		g_object_unref (service);
 		return NULL;
+	}
 
 	collection = secret_collection_new_sync (service, path,
 	                                         SECRET_COLLECTION_LOAD_ITEMS,
 	                                         cancellable, error);
+
+	g_object_unref (service);
 	g_free (path);
 
 	return collection;
diff --git a/library/secret-item.c b/library/secret-item.c
index 3c5d876..5219092 100644
--- a/library/secret-item.c
+++ b/library/secret-item.c
@@ -152,6 +152,24 @@ on_set_label (GObject *source,
 	g_object_unref (self);
 }
 
+
+static void
+item_take_service (SecretItem *self,
+                   SecretService *service)
+{
+	if (service == NULL)
+		return;
+
+	g_return_if_fail (self->pv->service == NULL);
+
+	self->pv->service = service;
+	g_object_add_weak_pointer (G_OBJECT (self->pv->service),
+	                           (gpointer *)&self->pv->service);
+
+	/* Yes, we expect that the service will stay around */
+	g_object_unref (service);
+}
+
 static void
 secret_item_set_property (GObject *obj,
                           guint prop_id,
@@ -162,11 +180,7 @@ secret_item_set_property (GObject *obj,
 
 	switch (prop_id) {
 	case PROP_SERVICE:
-		g_return_if_fail (self->pv->service == NULL);
-		self->pv->service = g_value_get_object (value);
-		if (self->pv->service)
-			g_object_add_weak_pointer (G_OBJECT (self->pv->service),
-			                           (gpointer *)&self->pv->service);
+		item_take_service (self, g_value_dup_object (value));
 		break;
 	case PROP_FLAGS:
 		self->pv->init_flags = g_value_get_flags (value);
@@ -444,6 +458,7 @@ secret_item_initable_init (GInitable *initable,
                            GError **error)
 {
 	SecretItem *self;
+	SecretService *service;
 	GDBusProxy *proxy;
 
 	if (!secret_item_initable_parent_iface->init (initable, cancellable, error))
@@ -459,6 +474,14 @@ secret_item_initable_init (GInitable *initable,
 	}
 
 	self = SECRET_ITEM (initable);
+	if (!self->pv->service) {
+		service = secret_service_get_sync (SECRET_SERVICE_NONE, cancellable, error);
+		if (service == NULL)
+			return FALSE;
+		else
+			item_take_service (self, service);
+	}
+
 	return item_ensure_for_flags_sync (self, self->pv->init_flags, cancellable, error);
 }
 
@@ -471,11 +494,36 @@ secret_item_initable_iface (GInitableIface *iface)
 }
 
 static void
+on_init_service (GObject *source,
+                 GAsyncResult *result,
+                 gpointer user_data)
+{
+	GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
+	SecretItem *self = SECRET_ITEM (g_async_result_get_source_object (user_data));
+	SecretService *service;
+	GError *error = NULL;
+
+	service = secret_service_get_finish (result, &error);
+	if (error == NULL) {
+		item_take_service (self, service);
+		item_ensure_for_flags_async (self, self->pv->init_flags, async);
+
+	} else {
+		g_simple_async_result_take_error (async, error);
+		g_simple_async_result_complete (async);
+	}
+
+	g_object_unref (self);
+	g_object_unref (async);
+}
+
+static void
 on_init_base (GObject *source,
               GAsyncResult *result,
               gpointer user_data)
 {
 	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	InitClosure *init = g_simple_async_result_get_op_res_gpointer (res);
 	SecretItem *self = SECRET_ITEM (source);
 	GDBusProxy *proxy = G_DBUS_PROXY (self);
 	GError *error = NULL;
@@ -491,6 +539,10 @@ on_init_base (GObject *source,
 		                                 g_dbus_proxy_get_object_path (proxy));
 		g_simple_async_result_complete (res);
 
+	} else if (self->pv->service == NULL) {
+		secret_service_get (SECRET_SERVICE_NONE, init->cancellable,
+		                    on_init_service, g_object_ref (res));
+
 	} else {
 		item_ensure_for_flags_async (self, self->pv->init_flags, res);
 	}
@@ -547,7 +599,7 @@ secret_item_async_initable_iface (GAsyncInitableIface *iface)
 
 /**
  * secret_item_new:
- * @service: a secret service object
+ * @service: (allow-none): a secret service object
  * @item_path: the D-Bus path of the collection
  * @flags: initialization flags for the new item
  * @cancellable: optional cancellation object
@@ -556,6 +608,9 @@ secret_item_async_initable_iface (GAsyncInitableIface *iface)
  *
  * Get a new item proxy for a secret item in the secret service.
  *
+ * If @service is NULL, then secret_service_get() will be called to get
+ * the default #SecretService proxy.
+ *
  * This method will return immediately and complete asynchronously.
  */
 void
@@ -568,7 +623,7 @@ secret_item_new (SecretService *service,
 {
 	GDBusProxy *proxy;
 
-	g_return_if_fail (SECRET_IS_SERVICE (service));
+	g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service));
 	g_return_if_fail (item_path != NULL);
 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
 
@@ -618,7 +673,7 @@ secret_item_new_finish (GAsyncResult *result,
 
 /**
  * secret_item_new_sync:
- * @service: a secret service object
+ * @service: (allow-none): a secret service object
  * @item_path: the D-Bus path of the item
  * @flags: initialization flags for the new item
  * @cancellable: optional cancellation object
@@ -626,6 +681,9 @@ secret_item_new_finish (GAsyncResult *result,
  *
  * Get a new item proxy for a secret item in the secret service.
  *
+ * If @service is NULL, then secret_service_get_sync() will be called to get
+ * the default #SecretService proxy.
+ *
  * This method may block indefinitely and should not be used in user interface
  * threads.
  *
@@ -641,7 +699,7 @@ secret_item_new_sync (SecretService *service,
 {
 	GDBusProxy *proxy;
 
-	g_return_val_if_fail (SECRET_IS_SERVICE (service), NULL);
+	g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), NULL);
 	g_return_val_if_fail (item_path != NULL, NULL);
 	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
 	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
diff --git a/library/secret-methods.c b/library/secret-methods.c
index d0e2558..2a5b467 100644
--- a/library/secret-methods.c
+++ b/library/secret-methods.c
@@ -32,6 +32,7 @@ typedef struct {
 	gchar **locked;
 	guint loading;
 	SecretSearchFlags flags;
+	GVariant *attributes;
 } SearchClosure;
 
 static void
@@ -41,6 +42,7 @@ search_closure_free (gpointer data)
 	g_object_unref (closure->service);
 	g_clear_object (&closure->cancellable);
 	g_hash_table_unref (closure->items);
+	g_variant_unref (closure->attributes);
 	g_strfreev (closure->unlocked);
 	g_strfreev (closure->locked);
 	g_slice_free (SearchClosure, closure);
@@ -212,9 +214,32 @@ on_search_paths (GObject *source,
 	g_object_unref (res);
 }
 
+static void
+on_search_service (GObject *source,
+                   GAsyncResult *result,
+                   gpointer user_data)
+{
+	GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
+	SearchClosure *search = g_simple_async_result_get_op_res_gpointer (async);
+	GError *error = NULL;
+
+	search->service = secret_service_get_finish (result, &error);
+	if (error == NULL) {
+		_secret_service_search_for_paths_variant (search->service, search->attributes,
+		                                          search->cancellable, on_search_paths,
+		                                          g_object_ref (async));
+
+	} else {
+		g_simple_async_result_take_error (async, error);
+		g_simple_async_result_complete (async);
+	}
+
+	g_object_unref (async);
+}
+
 /**
  * secret_service_search:
- * @self: the secret service
+ * @service: (allow-none): the secret service
  * @schema: (allow-none): the schema for the attributes
  * @attributes: (element-type utf8 utf8): search for items matching these attributes
  * @flags: search option flags
@@ -225,6 +250,9 @@ on_search_paths (GObject *source,
  * Search for items matching the @attributes. All collections are searched.
  * The @attributes should be a table of string keys and string values.
  *
+ * If @service is NULL, then secret_service_get() will be called to get
+ * the default #SecretService proxy.
+ *
  * If %SECRET_SEARCH_ALL is set in @flags, then all the items matching the
  * search will be returned. Otherwise only the first item will be returned.
  * This is almost always the unlocked item that was most recently stored.
@@ -239,7 +267,7 @@ on_search_paths (GObject *source,
  * This function returns immediately and completes asynchronously.
  */
 void
-secret_service_search (SecretService *self,
+secret_service_search (SecretService *service,
                        const SecretSchema *schema,
                        GHashTable *attributes,
                        SecretSearchFlags flags,
@@ -249,8 +277,9 @@ secret_service_search (SecretService *self,
 {
 	GSimpleAsyncResult *res;
 	SearchClosure *closure;
+	const gchar *schema_name = NULL;
 
-	g_return_if_fail (SECRET_IS_SERVICE (self));
+	g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service));
 	g_return_if_fail (attributes != NULL);
 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
 
@@ -258,24 +287,36 @@ secret_service_search (SecretService *self,
 	if (schema != NULL && !_secret_attributes_validate (schema, attributes))
 		return;
 
-	res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
+	if (schema != NULL && !(schema->flags & SECRET_SCHEMA_DONT_MATCH_NAME))
+		schema_name = schema->name;
+
+	res = g_simple_async_result_new (G_OBJECT (service), callback, user_data,
 	                                 secret_service_search);
 	closure = g_slice_new0 (SearchClosure);
-	closure->service = g_object_ref (self);
 	closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
 	closure->items = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref);
 	closure->flags = flags;
+	closure->attributes = _secret_attributes_to_variant (attributes, schema_name);
+	g_variant_ref_sink (closure->attributes);
 	g_simple_async_result_set_op_res_gpointer (res, closure, search_closure_free);
 
-	secret_service_search_for_paths (self, schema, attributes, cancellable,
-	                                 on_search_paths, g_object_ref (res));
+	if (service) {
+		closure->service = g_object_ref (service);
+		_secret_service_search_for_paths_variant (closure->service, closure->attributes,
+		                                          closure->cancellable, on_search_paths,
+		                                          g_object_ref (res));
+
+	} else {
+		secret_service_get (SECRET_SERVICE_NONE, cancellable,
+		                    on_search_service, g_object_ref (res));
+	}
 
 	g_object_unref (res);
 }
 
 /**
  * secret_service_search_finish:
- * @self: the secret service
+ * @service: (allow-none): the secret service
  * @result: asynchronous result passed to callback
  * @error: location to place error on failure
  *
@@ -285,7 +326,7 @@ secret_service_search (SecretService *self,
  *          a list of items that matched the search
  */
 GList *
-secret_service_search_finish (SecretService *self,
+secret_service_search_finish (SecretService *service,
                               GAsyncResult *result,
                               GError **error)
 {
@@ -293,9 +334,9 @@ secret_service_search_finish (SecretService *self,
 	SearchClosure *closure;
 	GList *items;
 
-	g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE);
+	g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), FALSE);
 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (service),
 	                      secret_service_search), FALSE);
 
 	res = G_SIMPLE_ASYNC_RESULT (result);
@@ -312,7 +353,7 @@ secret_service_search_finish (SecretService *self,
 }
 
 static gboolean
-service_load_items_sync (SecretService *self,
+service_load_items_sync (SecretService *service,
                          GCancellable *cancellable,
                          gchar **paths,
                          GList **items,
@@ -324,9 +365,9 @@ service_load_items_sync (SecretService *self,
 	guint i;
 
 	for (i = 0; *have < want && paths[i] != NULL; i++) {
-		item = _secret_service_find_item_instance (self, paths[i]);
+		item = _secret_service_find_item_instance (service, paths[i]);
 		if (item == NULL)
-			item = secret_item_new_sync (self, paths[i], SECRET_ITEM_NONE,
+			item = secret_item_new_sync (service, paths[i], SECRET_ITEM_NONE,
 			                             cancellable, error);
 		if (item == NULL) {
 			return FALSE;
@@ -342,7 +383,7 @@ service_load_items_sync (SecretService *self,
 
 /**
  * secret_service_search_sync:
- * @self: the secret service
+ * @service: (allow-none): the secret service
  * @schema: (allow-none): the schema for the attributes
  * @attributes: (element-type utf8 utf8): search for items matching these attributes
  * @flags: search option flags
@@ -352,6 +393,9 @@ service_load_items_sync (SecretService *self,
  * Search for items matching the @attributes. All collections are searched.
  * The @attributes should be a table of string keys and string values.
  *
+ * If @service is NULL, then secret_service_get_sync() will be called to get
+ * the default #SecretService proxy.
+ *
  * If %SECRET_SEARCH_ALL is set in @flags, then all the items matching the
  * search will be returned. Otherwise only the first item will be returned.
  * This is almost always the unlocked item that was most recently stored.
@@ -372,7 +416,7 @@ service_load_items_sync (SecretService *self,
  *          a list of items that matched the search
  */
 GList *
-secret_service_search_sync (SecretService *self,
+secret_service_search_sync (SecretService *service,
                             const SecretSchema *schema,
                             GHashTable *attributes,
                             SecretSearchFlags flags,
@@ -388,7 +432,7 @@ secret_service_search_sync (SecretService *self,
 	gint want;
 	gint have;
 
-	g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
+	g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), NULL);
 	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
 	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
 
@@ -396,9 +440,19 @@ secret_service_search_sync (SecretService *self,
 	if (schema != NULL && !_secret_attributes_validate (schema, attributes))
 		return NULL;
 
-	if (!secret_service_search_for_paths_sync (self, schema, attributes, cancellable,
-	                                           &unlocked_paths, &locked_paths, error))
+	if (service == NULL) {
+		service = secret_service_get_sync (SECRET_SERVICE_NONE, cancellable, error);
+		if (service == NULL)
+			return NULL;
+	} else {
+		g_object_ref (service);
+	}
+
+	if (!secret_service_search_for_paths_sync (service, schema, attributes, cancellable,
+	                                           &unlocked_paths, &locked_paths, error)) {
+		g_object_unref (service);
 		return NULL;
+	}
 
 	ret = TRUE;
 
@@ -410,12 +464,12 @@ secret_service_search_sync (SecretService *self,
 	/* Remember, we're adding to the list backwards */
 
 	if (unlocked_paths) {
-		ret = service_load_items_sync (self, cancellable, unlocked_paths,
+		ret = service_load_items_sync (service, cancellable, unlocked_paths,
 		                               &unlocked, want, &have, error);
 	}
 
 	if (ret && locked_paths) {
-		ret = service_load_items_sync (self, cancellable, locked_paths,
+		ret = service_load_items_sync (service, cancellable, locked_paths,
 		                               &locked, want, &have, error);
 	}
 
@@ -425,6 +479,7 @@ secret_service_search_sync (SecretService *self,
 	if (!ret) {
 		g_list_free_full (unlocked, g_object_unref);
 		g_list_free_full (locked, g_object_unref);
+		g_object_unref (service);
 		return NULL;
 	}
 
@@ -434,13 +489,14 @@ secret_service_search_sync (SecretService *self,
 	items = g_list_reverse (items);
 
 	if (flags & SECRET_SEARCH_UNLOCK)
-		secret_service_unlock_sync (self, locked, cancellable, NULL, NULL);
+		secret_service_unlock_sync (service, locked, cancellable, NULL, NULL);
 
 	if (flags & SECRET_SEARCH_LOAD_SECRETS)
 		secret_item_load_secrets_sync (items, NULL, NULL);
 
 	g_list_free (locked);
 	g_list_free (unlocked);
+	g_object_unref (service);
 	return items;
 }
 
@@ -490,6 +546,8 @@ _secret_service_decode_get_secrets_all (SecretService *self,
 }
 
 typedef struct {
+	GCancellable *cancellable;
+	GPtrArray *paths;
 	GHashTable *objects;
 	gchar **xlocked;
 	guint count;
@@ -500,6 +558,9 @@ static void
 xlock_closure_free (gpointer data)
 {
 	XlockClosure *closure = data;
+	if (closure->cancellable)
+		g_object_unref (closure->cancellable);
+	g_ptr_array_free (closure->paths, TRUE);
 	g_strfreev (closure->xlocked);
 	g_hash_table_unref (closure->objects);
 	g_slice_free (XlockClosure, closure);
@@ -544,7 +605,33 @@ on_xlock_paths (GObject *source,
 }
 
 static void
-service_xlock_async (SecretService *self,
+on_xlock_service (GObject *source,
+                  GAsyncResult *result,
+                  gpointer user_data)
+{
+	GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
+	XlockClosure *xlock = g_simple_async_result_get_op_res_gpointer (async);
+	GError *error = NULL;
+	SecretService *service;
+
+	service = secret_service_get_finish (result, &error);
+	if (error == NULL) {
+		_secret_service_xlock_paths_async (service, xlock->locking ? "Lock" : "Unlock",
+		                                   (const gchar **)xlock->paths->pdata,
+		                                   xlock->cancellable, on_xlock_paths,
+		                                   g_object_ref (async));
+		g_object_unref (service);
+
+	} else {
+		g_simple_async_result_take_error (async, error);
+		g_simple_async_result_complete (async);
+	}
+
+	g_object_unref (async);
+}
+
+static void
+service_xlock_async (SecretService *service,
                      gboolean locking,
                      GList *objects,
                      GCancellable *cancellable,
@@ -553,37 +640,41 @@ service_xlock_async (SecretService *self,
 {
 	GSimpleAsyncResult *async;
 	XlockClosure *xlock;
-	GPtrArray *paths;
 	const gchar *path;
 	GList *l;
 
-	async = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
+	async = g_simple_async_result_new (G_OBJECT (service), callback, user_data,
 	                                   service_xlock_async);
 	xlock = g_slice_new0 (XlockClosure);
 	xlock->objects = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
 	xlock->locking = locking;
+	xlock->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+	xlock->paths = g_ptr_array_new ();
 
-	paths = g_ptr_array_new ();
 	for (l = objects; l != NULL; l = g_list_next (l)) {
 		path = g_dbus_proxy_get_object_path (l->data);
-		g_ptr_array_add (paths, (gpointer)path);
+		g_ptr_array_add (xlock->paths, (gpointer)path);
 		g_hash_table_insert (xlock->objects, g_strdup (path), g_object_ref (l->data));
 	}
-	g_ptr_array_add (paths, NULL);
+	g_ptr_array_add (xlock->paths, NULL);
 
 	g_simple_async_result_set_op_res_gpointer (async, xlock, xlock_closure_free);
 
-	_secret_service_xlock_paths_async (self, locking ? "Lock" : "Unlock",
-	                                   (const gchar **)paths->pdata,
-	                                   cancellable, on_xlock_paths,
-	                                   g_object_ref (async));
+	if (service == NULL) {
+		secret_service_get (SECRET_SERVICE_NONE, cancellable,
+		                    on_xlock_service, g_object_ref (async));
+	} else {
+		_secret_service_xlock_paths_async (service, xlock->locking ? "Lock" : "Unlock",
+		                                   (const gchar **)xlock->paths->pdata,
+		                                   xlock->cancellable, on_xlock_paths,
+		                                   g_object_ref (async));
+	}
 
-	g_ptr_array_free (paths, TRUE);
 	g_object_unref (async);
 }
 
 static gint
-service_xlock_finish (SecretService *self,
+service_xlock_finish (SecretService *service,
                       GAsyncResult *result,
                       GList **xlocked,
                       GError **error)
@@ -593,7 +684,8 @@ service_xlock_finish (SecretService *self,
 	GDBusProxy *object;
 	gint i;
 
-	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self), service_xlock_async), -1);
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (service),
+	                                                      service_xlock_async), -1);
 
 	async = G_SIMPLE_ASYNC_RESULT (result);
 	if (g_simple_async_result_propagate_error (async, error))
@@ -614,7 +706,7 @@ service_xlock_finish (SecretService *self,
 
 /**
  * secret_service_lock:
- * @self: the secret service
+ * @service: (allow-none): the secret service
  * @objects: (element-type GLib.DBusProxy): the items or collections to lock
  * @cancellable: optional cancellation object
  * @callback: called when the operation completes
@@ -629,26 +721,29 @@ service_xlock_finish (SecretService *self,
  * The secret service may not be able to lock items individually, and may
  * lock an entire collection instead.
  *
+ * If @service is NULL, then secret_service_get() will be called to get
+ * the default #SecretService proxy.
+ *
  * This method returns immediately and completes asynchronously. The secret
  * service may prompt the user. secret_service_prompt() will be used to handle
  * any prompts that show up.
  */
 void
-secret_service_lock (SecretService *self,
+secret_service_lock (SecretService *service,
                      GList *objects,
                      GCancellable *cancellable,
                      GAsyncReadyCallback callback,
                      gpointer user_data)
 {
-	g_return_if_fail (SECRET_IS_SERVICE (self));
+	g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service));
 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
 
-	service_xlock_async (self, TRUE, objects, cancellable, callback, user_data);
+	service_xlock_async (service, TRUE, objects, cancellable, callback, user_data);
 }
 
 /**
  * secret_service_lock_finish:
- * @self: the secret service
+ * @service: (allow-none): the secret service
  * @result: asynchronous result passed to the callback
  * @locked: (out) (element-type GLib.DBusProxy) (transfer full) (allow-none):
  *          location to place list of items or collections that were locked
@@ -663,20 +758,20 @@ secret_service_lock (SecretService *self,
  * Returns: the number of items or collections that were locked
  */
 gint
-secret_service_lock_finish (SecretService *self,
+secret_service_lock_finish (SecretService *service,
                             GAsyncResult *result,
                             GList **locked,
                             GError **error)
 {
-	g_return_val_if_fail (SECRET_IS_SERVICE (self), -1);
+	g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), -1);
 	g_return_val_if_fail (error == NULL || *error == NULL, -1);
 
-	return service_xlock_finish (self, result, locked, error);
+	return service_xlock_finish (service, result, locked, error);
 }
 
 /**
  * secret_service_lock_sync:
- * @self: the secret service
+ * @service: (allow-none): the secret service
  * @objects: (element-type GLib.DBusProxy): the items or collections to lock
  * @cancellable: optional cancellation object
  * @locked: (out) (element-type GLib.DBusProxy) (transfer full) (allow-none):
@@ -692,6 +787,9 @@ secret_service_lock_finish (SecretService *self,
  * The secret service may not be able to lock items individually, and may
  * lock an entire collection instead.
  *
+ * If @service is NULL, then secret_service_get_sync() will be called to get
+ * the default #SecretService proxy.
+ *
  * This method may block indefinitely and should not be used in user
  * interface threads. The secret service may prompt the user.
  * secret_service_prompt() will be used to handle any prompts that show up.
@@ -699,7 +797,7 @@ secret_service_lock_finish (SecretService *self,
  * Returns: the number of items or collections that were locked
  */
 gint
-secret_service_lock_sync (SecretService *self,
+secret_service_lock_sync (SecretService *service,
                           GList *objects,
                           GCancellable *cancellable,
                           GList **locked,
@@ -708,19 +806,19 @@ secret_service_lock_sync (SecretService *self,
 	SecretSync *sync;
 	gint count;
 
-	g_return_val_if_fail (SECRET_IS_SERVICE (self), -1);
+	g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), -1);
 	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), -1);
 	g_return_val_if_fail (error == NULL || *error == NULL, -1);
 
 	sync = _secret_sync_new ();
 	g_main_context_push_thread_default (sync->context);
 
-	secret_service_lock (self, objects, cancellable,
-	                      _secret_sync_on_result, sync);
+	secret_service_lock (service, objects, cancellable,
+	                     _secret_sync_on_result, sync);
 
 	g_main_loop_run (sync->loop);
 
-	count = secret_service_lock_finish (self, sync->result, locked, error);
+	count = secret_service_lock_finish (service, sync->result, locked, error);
 
 	g_main_context_pop_thread_default (sync->context);
 	_secret_sync_free (sync);
@@ -730,7 +828,7 @@ secret_service_lock_sync (SecretService *self,
 
 /**
  * secret_service_unlock:
- * @self: the secret service
+ * @service: (allow-none): the secret service
  * @objects: (element-type GLib.DBusProxy): the items or collections to unlock
  * @cancellable: optional cancellation object
  * @callback: called when the operation completes
@@ -745,26 +843,29 @@ secret_service_lock_sync (SecretService *self,
  * The secret service may not be able to unlock items individually, and may
  * unlock an entire collection instead.
  *
+ * If @service is NULL, then secret_service_get() will be called to get
+ * the default #SecretService proxy.
+ *
  * This method may block indefinitely and should not be used in user
  * interface threads. The secret service may prompt the user.
  * secret_service_prompt() will be used to handle any prompts that show up.
  */
 void
-secret_service_unlock (SecretService *self,
+secret_service_unlock (SecretService *service,
                        GList *objects,
                        GCancellable *cancellable,
                        GAsyncReadyCallback callback,
                        gpointer user_data)
 {
-	g_return_if_fail (SECRET_IS_SERVICE (self));
+	g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service));
 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
 
-	service_xlock_async (self, FALSE, objects, cancellable, callback, user_data);
+	service_xlock_async (service, FALSE, objects, cancellable, callback, user_data);
 }
 
 /**
  * secret_service_unlock_finish:
- * @self: the secret service
+ * @service: (allow-none): the secret service
  * @result: asynchronous result passed to the callback
  * @unlocked: (out) (element-type GLib.DBusProxy) (transfer full) (allow-none):
  *            location to place list of items or collections that were unlocked
@@ -779,20 +880,20 @@ secret_service_unlock (SecretService *self,
  * Returns: the number of items or collections that were unlocked
  */
 gint
-secret_service_unlock_finish (SecretService *self,
+secret_service_unlock_finish (SecretService *service,
                               GAsyncResult *result,
                               GList **unlocked,
                               GError **error)
 {
-	g_return_val_if_fail (SECRET_IS_SERVICE (self), -1);
+	g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), -1);
 	g_return_val_if_fail (error == NULL || *error == NULL, -1);
 
-	return service_xlock_finish (self, result, unlocked, error);
+	return service_xlock_finish (service, result, unlocked, error);
 }
 
 /**
  * secret_service_unlock_sync:
- * @self: the secret service
+ * @service: (allow-none): the secret service
  * @objects: (element-type GLib.DBusProxy): the items or collections to unlock
  * @cancellable: optional cancellation object
  * @unlocked: (out) (element-type GLib.DBusProxy) (transfer full) (allow-none):
@@ -808,6 +909,9 @@ secret_service_unlock_finish (SecretService *self,
  * The secret service may not be able to unlock items individually, and may
  * unlock an entire collection instead.
  *
+ * If @service is NULL, then secret_service_get_sync() will be called to get
+ * the default #SecretService proxy.
+ *
  * This method may block indefinitely and should not be used in user
  * interface threads. The secret service may prompt the user.
  * secret_service_prompt() will be used to handle any prompts that show up.
@@ -815,7 +919,7 @@ secret_service_unlock_finish (SecretService *self,
  * Returns: the number of items or collections that were unlocked
  */
 gint
-secret_service_unlock_sync (SecretService *self,
+secret_service_unlock_sync (SecretService *service,
                             GList *objects,
                             GCancellable *cancellable,
                             GList **unlocked,
@@ -824,20 +928,19 @@ secret_service_unlock_sync (SecretService *self,
 	SecretSync *sync;
 	gint count;
 
-	g_return_val_if_fail (SECRET_IS_SERVICE (self), -1);
+	g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), -1);
 	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), -1);
 	g_return_val_if_fail (error == NULL || *error == NULL, -1);
 
 	sync = _secret_sync_new ();
 	g_main_context_push_thread_default (sync->context);
 
-	secret_service_unlock (self, objects, cancellable,
-	                        _secret_sync_on_result, sync);
+	secret_service_unlock (service, objects, cancellable,
+	                       _secret_sync_on_result, sync);
 
 	g_main_loop_run (sync->loop);
 
-	count = secret_service_unlock_finish (self, sync->result,
-	                                       unlocked, error);
+	count = secret_service_unlock_finish (service, sync->result, unlocked, error);
 
 	g_main_context_pop_thread_default (sync->context);
 	_secret_sync_free (sync);
@@ -845,9 +948,72 @@ secret_service_unlock_sync (SecretService *self,
 	return count;
 }
 
+typedef struct {
+	GCancellable *cancellable;
+	gchar *collection_path;
+	SecretValue *value;
+	GHashTable *properties;
+} StoreClosure;
+
+static void
+store_closure_free (gpointer data)
+{
+	StoreClosure *store = data;
+	if (store->cancellable)
+		g_object_unref (store->cancellable);
+	g_free (store->collection_path);
+	secret_value_unref (store->value);
+	g_hash_table_unref (store->properties);
+	g_slice_free (StoreClosure, store);
+}
+
+static void
+on_store_create (GObject *source,
+                 GAsyncResult *result,
+                 gpointer user_data)
+{
+	GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
+	GError *error = NULL;
+	gchar *path;
+
+	path = secret_service_create_item_path_finish (SECRET_SERVICE (source), result, &error);
+	if (error != NULL)
+		g_simple_async_result_take_error (async, error);
+	g_free (path);
+
+	g_simple_async_result_complete (async);
+	g_object_unref (async);
+}
+
+static void
+on_store_service (GObject *source,
+                  GAsyncResult *result,
+                  gpointer user_data)
+{
+	GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
+	StoreClosure *store = g_simple_async_result_get_op_res_gpointer (async);
+	SecretService *service;
+	GError *error = NULL;
+
+	service = secret_service_get_finish (result, &error);
+	if (error == NULL) {
+		secret_service_create_item_path (service, store->collection_path,
+		                                 store->properties, store->value,
+		                                 TRUE, store->cancellable,
+		                                 on_store_create, g_object_ref (async));
+		g_object_unref (service);
+
+	} else {
+		g_simple_async_result_take_error (async, error);
+		g_simple_async_result_complete (async);
+	}
+
+	g_object_unref (async);
+}
+
 /**
  * secret_service_store:
- * @self: the secret service
+ * @service: (allow-none): the secret service
  * @schema: (allow-none): the schema to use to check attributes
  * @attributes: (element-type utf8 utf8): the attribute keys and values
  * @collection_path: (allow-none): the D-Bus path to the collection where to store the secret
@@ -864,6 +1030,9 @@ secret_service_unlock_sync (SecretService *self,
  * If the attributes match a secret item already stored in the collection, then
  * the item will be updated with these new values.
  *
+ * If @service is NULL, then secret_service_get() will be called to get
+ * the default #SecretService proxy.
+ *
  * If @collection_path is not specified, then the default collection will be
  * used. Use #SECRET_COLLECTION_SESSION to store the password in the session
  * collection, which doesn't get stored across login sessions.
@@ -871,7 +1040,7 @@ secret_service_unlock_sync (SecretService *self,
  * This method will return immediately and complete asynchronously.
  */
 void
-secret_service_store (SecretService *self,
+secret_service_store (SecretService *service,
                       const SecretSchema *schema,
                       GHashTable *attributes,
                       const gchar *collection_path,
@@ -881,11 +1050,12 @@ secret_service_store (SecretService *self,
                       GAsyncReadyCallback callback,
                       gpointer user_data)
 {
+	GSimpleAsyncResult *async;
+	StoreClosure *store;
 	const gchar *schema_name;
-	GHashTable *properties;
 	GVariant *propval;
 
-	g_return_if_fail (SECRET_IS_SERVICE (self));
+	g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service));
 	g_return_if_fail (attributes != NULL);
 	g_return_if_fail (label != NULL);
 	g_return_if_fail (value != NULL);
@@ -895,30 +1065,46 @@ secret_service_store (SecretService *self,
 	if (schema != NULL && !_secret_attributes_validate (schema, attributes))
 		return;
 
-	properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL,
-	                                    (GDestroyNotify)g_variant_unref);
+	async = g_simple_async_result_new  (G_OBJECT (service), callback, user_data,
+	                                    secret_service_store);
+	store = g_slice_new0 (StoreClosure);
+	store->collection_path = g_strdup (collection_path);
+	store->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+	store->value = secret_value_ref (value);
+	store->properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL,
+	                                           (GDestroyNotify)g_variant_unref);
 
 	propval = g_variant_new_string (label);
-	g_hash_table_insert (properties,
+	g_hash_table_insert (store->properties,
 	                     SECRET_ITEM_INTERFACE ".Label",
 	                     g_variant_ref_sink (propval));
 
 	/* Always store the schema name in the attributes */
 	schema_name = (schema == NULL) ? NULL : schema->name;
 	propval = _secret_attributes_to_variant (attributes, schema_name);
-	g_hash_table_insert (properties,
+	g_hash_table_insert (store->properties,
 	                     SECRET_ITEM_INTERFACE ".Attributes",
 	                     g_variant_ref_sink (propval));
 
-	secret_service_create_item_path (self, collection_path, properties, value,
-	                                 TRUE, cancellable, callback, user_data);
+	g_simple_async_result_set_op_res_gpointer (async, store, store_closure_free);
 
-	g_hash_table_unref (properties);
+	if (service == NULL) {
+		secret_service_get (SECRET_SERVICE_OPEN_SESSION, cancellable,
+		                    on_store_service, g_object_ref (async));
+
+	} else {
+		secret_service_create_item_path (service, store->collection_path,
+		                                 store->properties, store->value,
+		                                 TRUE, store->cancellable,
+		                                 on_store_create, g_object_ref (async));
+	}
+
+	g_object_unref (async);
 }
 
 /**
  * secret_service_store_finish:
- * @self: the secret service
+ * @service: (allow-none): the secret service
  * @result: the asynchronous result passed to the callback
  * @error: location to place an error on failure
  *
@@ -927,24 +1113,24 @@ secret_service_store (SecretService *self,
  * Returns: whether the storage was successful or not
  */
 gboolean
-secret_service_store_finish (SecretService *self,
+secret_service_store_finish (SecretService *service,
                              GAsyncResult *result,
                              GError **error)
 {
-	gchar *path;
-
-	g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE);
+	g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), FALSE);
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (service),
+	                                                      secret_service_store), FALSE);
 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-	path = secret_service_create_item_path_finish (self, result, error);
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return FALSE;
 
-	g_free (path);
-	return path != NULL;
+	return TRUE;
 }
 
 /**
  * secret_service_store_sync:
- * @self: the secret service
+ * @service: (allow-none): the secret service
  * @schema: (allow-none): the schema for the attributes
  * @attributes: (element-type utf8 utf8): the attribute keys and values
  * @collection_path: (allow-none): the D-Bus path to the collection where to store the secret
@@ -964,13 +1150,16 @@ secret_service_store_finish (SecretService *self,
  * used. Use #SECRET_COLLECTION_SESSION to store the password in the session
  * collection, which doesn't get stored across login sessions.
  *
+ * If @service is NULL, then secret_service_get_sync() will be called to get
+ * the default #SecretService proxy.
+ *
  * This method may block indefinitely and should not be used in user interface
  * threads.
  *
  * Returns: whether the storage was successful or not
  */
 gboolean
-secret_service_store_sync (SecretService *self,
+secret_service_store_sync (SecretService *service,
                            const SecretSchema *schema,
                            GHashTable *attributes,
                            const gchar *collection_path,
@@ -982,7 +1171,7 @@ secret_service_store_sync (SecretService *self,
 	SecretSync *sync;
 	gboolean ret;
 
-	g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE);
+	g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), FALSE);
 	g_return_val_if_fail (attributes != NULL, FALSE);
 	g_return_val_if_fail (label != NULL, FALSE);
 	g_return_val_if_fail (value != NULL, FALSE);
@@ -996,12 +1185,12 @@ secret_service_store_sync (SecretService *self,
 	sync = _secret_sync_new ();
 	g_main_context_push_thread_default (sync->context);
 
-	secret_service_store (self, schema, attributes, collection_path,
-	                       label, value, cancellable, _secret_sync_on_result, sync);
+	secret_service_store (service, schema, attributes, collection_path,
+	                      label, value, cancellable, _secret_sync_on_result, sync);
 
 	g_main_loop_run (sync->loop);
 
-	ret = secret_service_store_finish (self, sync->result, error);
+	ret = secret_service_store_finish (service, sync->result, error);
 
 	g_main_context_pop_thread_default (sync->context);
 	_secret_sync_free (sync);
@@ -1010,6 +1199,7 @@ secret_service_store_sync (SecretService *self,
 }
 
 typedef struct {
+	GVariant *attributes;
 	SecretValue *value;
 	GCancellable *cancellable;
 } LookupClosure;
@@ -1018,6 +1208,7 @@ static void
 lookup_closure_free (gpointer data)
 {
 	LookupClosure *closure = data;
+	g_variant_unref (closure->attributes);
 	if (closure->value)
 		secret_value_unref (closure->value);
 	g_clear_object (&closure->cancellable);
@@ -1112,9 +1303,34 @@ on_lookup_searched (GObject *source,
 	g_object_unref (res);
 }
 
+static void
+on_lookup_service (GObject *source,
+                   GAsyncResult *result,
+                   gpointer user_data)
+{
+	GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
+	LookupClosure *lookup = g_simple_async_result_get_op_res_gpointer (async);
+	SecretService *service;
+	GError *error = NULL;
+
+	service = secret_service_get_finish (result, &error);
+	if (error == NULL) {
+		_secret_service_search_for_paths_variant (service, lookup->attributes,
+		                                          lookup->cancellable,
+		                                          on_lookup_searched, g_object_ref (async));
+		g_object_unref (service);
+
+	} else {
+		g_simple_async_result_take_error (async, error);
+		g_simple_async_result_complete (async);
+	}
+
+	g_object_unref (async);
+}
+
 /**
  * secret_service_lookup:
- * @self: the secret service
+ * @service: (allow-none): the secret service
  * @schema: (allow-none): the schema for the attributes
  * @attributes: (element-type utf8 utf8): the attribute keys and values
  * @cancellable: optional cancellation object
@@ -1125,10 +1341,13 @@ on_lookup_searched (GObject *source,
  *
  * The @attributes should be a set of key and value string pairs.
  *
+ * If @service is NULL, then secret_service_get() will be called to get
+ * the default #SecretService proxy.
+ *
  * This method will return immediately and complete asynchronously.
  */
 void
-secret_service_lookup (SecretService *self,
+secret_service_lookup (SecretService *service,
                        const SecretSchema *schema,
                        GHashTable *attributes,
                        GCancellable *cancellable,
@@ -1138,9 +1357,8 @@ secret_service_lookup (SecretService *self,
 	const gchar *schema_name = NULL;
 	GSimpleAsyncResult *res;
 	LookupClosure *closure;
-	GVariant *variant;
 
-	g_return_if_fail (SECRET_IS_SERVICE (self));
+	g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service));
 	g_return_if_fail (attributes != NULL);
 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
 
@@ -1148,25 +1366,32 @@ secret_service_lookup (SecretService *self,
 	if (schema != NULL && !_secret_attributes_validate (schema, attributes))
 		return;
 
-	res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
+	if (schema != NULL && !(schema->flags & SECRET_SCHEMA_DONT_MATCH_NAME))
+		schema_name = schema->name;
+
+	res = g_simple_async_result_new (G_OBJECT (service), callback, user_data,
 	                                 secret_service_lookup);
 	closure = g_slice_new0 (LookupClosure);
 	closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+	closure->attributes = _secret_attributes_to_variant (attributes, schema_name);
+	g_variant_ref_sink (closure->attributes);
 	g_simple_async_result_set_op_res_gpointer (res, closure, lookup_closure_free);
 
-	if (schema != NULL && !(schema->flags & SECRET_SCHEMA_DONT_MATCH_NAME))
-		schema_name = schema->name;
-	variant = _secret_attributes_to_variant (attributes, schema_name);
-
-	_secret_service_search_for_paths_variant (self, variant, cancellable,
-	                                          on_lookup_searched, g_object_ref (res));
+	if (service == NULL) {
+		secret_service_get (SECRET_SERVICE_OPEN_SESSION, cancellable,
+		                    on_lookup_service, g_object_ref (res));
+	} else {
+		_secret_service_search_for_paths_variant (service, closure->attributes,
+		                                          closure->cancellable,
+		                                          on_lookup_searched, g_object_ref (res));
+	}
 
 	g_object_unref (res);
 }
 
 /**
  * secret_service_lookup_finish:
- * @self: the secret service
+ * @service: (allow-none): the secret service
  * @result: the asynchronous result passed to the callback
  * @error: location to place an error on failure
  *
@@ -1178,7 +1403,7 @@ secret_service_lookup (SecretService *self,
  *          released with secret_value_unref(), or %NULL if no secret found
  */
 SecretValue *
-secret_service_lookup_finish (SecretService *self,
+secret_service_lookup_finish (SecretService *service,
                               GAsyncResult *result,
                               GError **error)
 {
@@ -1186,9 +1411,9 @@ secret_service_lookup_finish (SecretService *self,
 	LookupClosure *closure;
 	SecretValue *value;
 
-	g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
+	g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), NULL);
 	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
-	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (service),
 	                      secret_service_lookup), NULL);
 
 	res = G_SIMPLE_ASYNC_RESULT (result);
@@ -1203,7 +1428,7 @@ secret_service_lookup_finish (SecretService *self,
 
 /**
  * secret_service_lookup_sync:
- * @self: the secret service
+ * @service: (allow-none): the secret service
  * @schema: (allow-none): the schema for the attributes
  * @attributes: (element-type utf8 utf8): the attribute keys and values
  * @cancellable: optional cancellation object
@@ -1213,6 +1438,9 @@ secret_service_lookup_finish (SecretService *self,
  *
  * The @attributes should be a set of key and value string pairs.
  *
+ * If @service is NULL, then secret_service_get_sync() will be called to get
+ * the default #SecretService proxy.
+ *
  * This method may block indefinitely and should not be used in user interface
  * threads.
  *
@@ -1220,7 +1448,7 @@ secret_service_lookup_finish (SecretService *self,
  *          released with secret_value_unref(), or %NULL if no secret found
  */
 SecretValue *
-secret_service_lookup_sync (SecretService *self,
+secret_service_lookup_sync (SecretService *service,
                             const SecretSchema *schema,
                             GHashTable *attributes,
                             GCancellable *cancellable,
@@ -1229,7 +1457,7 @@ secret_service_lookup_sync (SecretService *self,
 	SecretSync *sync;
 	SecretValue *value;
 
-	g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
+	g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), NULL);
 	g_return_val_if_fail (attributes != NULL, NULL);
 	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
 
@@ -1240,12 +1468,12 @@ secret_service_lookup_sync (SecretService *self,
 	sync = _secret_sync_new ();
 	g_main_context_push_thread_default (sync->context);
 
-	secret_service_lookup (self, schema, attributes, cancellable,
+	secret_service_lookup (service, schema, attributes, cancellable,
 	                       _secret_sync_on_result, sync);
 
 	g_main_loop_run (sync->loop);
 
-	value = secret_service_lookup_finish (self, sync->result, error);
+	value = secret_service_lookup_finish (service, sync->result, error);
 
 	g_main_context_pop_thread_default (sync->context);
 	_secret_sync_free (sync);
@@ -1255,6 +1483,8 @@ secret_service_lookup_sync (SecretService *self,
 
 typedef struct {
 	GCancellable *cancellable;
+	SecretService *service;
+	GVariant *attributes;
 	SecretPrompt *prompt;
 	gboolean deleted;
 } DeleteClosure;
@@ -1263,6 +1493,9 @@ static void
 delete_closure_free (gpointer data)
 {
 	DeleteClosure *closure = data;
+	if (closure->service)
+		g_object_unref (closure->service);
+	g_variant_unref (closure->attributes);
 	g_clear_object (&closure->prompt);
 	g_clear_object (&closure->cancellable);
 	g_slice_free (DeleteClosure, closure);
@@ -1274,34 +1507,31 @@ on_delete_password_complete (GObject *source,
                              gpointer user_data)
 {
 	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
-	SecretService *self = SECRET_SERVICE (g_async_result_get_source_object (user_data));
 	DeleteClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
 	GError *error = NULL;
 
-	closure->deleted = secret_service_delete_path_finish (self, result, &error);
+	closure->deleted = secret_service_delete_path_finish (SECRET_SERVICE (source), result, &error);
 	if (error != NULL)
 		g_simple_async_result_take_error (res, error);
 
 	g_simple_async_result_complete (res);
 
-	g_object_unref (self);
 	g_object_unref (res);
 }
 
 static void
-on_search_delete_password (GObject *source,
-                           GAsyncResult *result,
-                           gpointer user_data)
+on_delete_searched (GObject *source,
+                    GAsyncResult *result,
+                    gpointer user_data)
 {
 	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
 	DeleteClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
-	SecretService *self = SECRET_SERVICE (g_async_result_get_source_object (user_data));
 	const gchar *path = NULL;
 	GError *error = NULL;
 	gchar **locked;
 	gchar **unlocked;
 
-	secret_service_search_for_paths_finish (self, result, &unlocked, &locked, &error);
+	secret_service_search_for_paths_finish (SECRET_SERVICE (source), result, &unlocked, &locked, &error);
 	if (error != NULL) {
 		g_simple_async_result_take_error (res, error);
 		g_simple_async_result_complete (res);
@@ -1321,7 +1551,7 @@ on_search_delete_password (GObject *source,
 		/* Delete the first path */
 		} else {
 			closure->deleted = TRUE;
-			_secret_service_delete_path (self, path, TRUE,
+			_secret_service_delete_path (closure->service, path, TRUE,
 			                             closure->cancellable,
 			                             on_delete_password_complete,
 			                             g_object_ref (res));
@@ -1330,13 +1560,35 @@ on_search_delete_password (GObject *source,
 
 	g_strfreev (locked);
 	g_strfreev (unlocked);
-	g_object_unref (self);
 	g_object_unref (res);
 }
 
+static void
+on_delete_service (GObject *source,
+                   GAsyncResult *result,
+                   gpointer user_data)
+{
+	GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
+	DeleteClosure *closure = g_simple_async_result_get_op_res_gpointer (async);
+	GError *error = NULL;
+
+	closure->service = secret_service_get_finish (result, &error);
+	if (error == NULL) {
+		_secret_service_search_for_paths_variant (closure->service, closure->attributes,
+		                                          closure->cancellable,
+		                                          on_delete_searched, g_object_ref (async));
+
+	} else {
+		g_simple_async_result_take_error (async, error);
+		g_simple_async_result_complete (async);
+	}
+
+	g_object_unref (async);
+}
+
 /**
  * secret_service_remove:
- * @self: the secret service
+ * @service: (allow-none): the secret service
  * @schema: (allow-none): the schema for the attributes
  * @attributes: (element-type utf8 utf8): the attribute keys and values
  * @cancellable: optional cancellation object
@@ -1349,10 +1601,13 @@ on_search_delete_password (GObject *source,
  *
  * If multiple items match the attributes, then only one will be deleted.
  *
+ * If @service is NULL, then secret_service_get() will be called to get
+ * the default #SecretService proxy.
+ *
  * This method will return immediately and complete asynchronously.
  */
 void
-secret_service_remove (SecretService *self,
+secret_service_remove (SecretService *service,
                        const SecretSchema *schema,
                        GHashTable *attributes,
                        GCancellable *cancellable,
@@ -1362,9 +1617,8 @@ secret_service_remove (SecretService *self,
 	const gchar *schema_name = NULL;
 	GSimpleAsyncResult *res;
 	DeleteClosure *closure;
-	GVariant *variant;
 
-	g_return_if_fail (SECRET_SERVICE (self));
+	g_return_if_fail (service == NULL || SECRET_SERVICE (service));
 	g_return_if_fail (attributes != NULL);
 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
 
@@ -1372,25 +1626,33 @@ secret_service_remove (SecretService *self,
 	if (schema != NULL && !_secret_attributes_validate (schema, attributes))
 		return;
 
-	res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
+	if (schema != NULL && !(schema->flags & SECRET_SCHEMA_DONT_MATCH_NAME))
+		schema_name = schema->name;
+
+	res = g_simple_async_result_new (G_OBJECT (service), callback, user_data,
 	                                 secret_service_remove);
 	closure = g_slice_new0 (DeleteClosure);
 	closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+	closure->attributes = _secret_attributes_to_variant (attributes, schema_name);
+	g_variant_ref_sink (closure->attributes);
 	g_simple_async_result_set_op_res_gpointer (res, closure, delete_closure_free);
 
-	if (schema != NULL && !(schema->flags & SECRET_SCHEMA_DONT_MATCH_NAME))
-		schema_name = schema->name;
-	variant = _secret_attributes_to_variant (attributes, schema_name);
-
-	_secret_service_search_for_paths_variant (self, variant, cancellable,
-	                                          on_search_delete_password, g_object_ref (res));
+	if (service == NULL) {
+		secret_service_get (SECRET_SERVICE_NONE, cancellable,
+		                    on_delete_service, g_object_ref (res));
+	} else {
+		closure->service = g_object_ref (service);
+		_secret_service_search_for_paths_variant (closure->service, closure->attributes,
+		                                          closure->cancellable,
+		                                          on_delete_searched, g_object_ref (res));
+	}
 
 	g_object_unref (res);
 }
 
 /**
  * secret_service_remove_finish:
- * @self: the secret service
+ * @service: (allow-none): the secret service
  * @result: the asynchronous result passed to the callback
  * @error: location to place an error on failure
  *
@@ -1400,16 +1662,16 @@ secret_service_remove (SecretService *self,
  * Returns: whether the removal was successful or not
  */
 gboolean
-secret_service_remove_finish (SecretService *self,
+secret_service_remove_finish (SecretService *service,
                               GAsyncResult *result,
                               GError **error)
 {
 	GSimpleAsyncResult *res;
 	DeleteClosure *closure;
 
-	g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE);
+	g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), FALSE);
 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (service),
 	                      secret_service_remove), FALSE);
 
 	res = G_SIMPLE_ASYNC_RESULT (result);
@@ -1422,7 +1684,7 @@ secret_service_remove_finish (SecretService *self,
 
 /**
  * secret_service_remove_sync:
- * @self: the secret service
+ * @service: (allow-none): the secret service
  * @schema: (allow-none): the schema for the attributes
  * @attributes: (element-type utf8 utf8): the attribute keys and values
  * @cancellable: optional cancellation object
@@ -1434,13 +1696,16 @@ secret_service_remove_finish (SecretService *self,
  *
  * If multiple items match the attributes, then only one will be deleted.
  *
+ * If @service is NULL, then secret_service_get_sync() will be called to get
+ * the default #SecretService proxy.
+ *
  * This method may block indefinitely and should not be used in user interface
  * threads.
  *
  * Returns: whether the removal was successful or not
  */
 gboolean
-secret_service_remove_sync (SecretService *self,
+secret_service_remove_sync (SecretService *service,
                             const SecretSchema *schema,
                             GHashTable *attributes,
                             GCancellable *cancellable,
@@ -1449,7 +1714,7 @@ secret_service_remove_sync (SecretService *self,
 	SecretSync *sync;
 	gboolean result;
 
-	g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE);
+	g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), FALSE);
 	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
@@ -1460,12 +1725,12 @@ secret_service_remove_sync (SecretService *self,
 	sync = _secret_sync_new ();
 	g_main_context_push_thread_default (sync->context);
 
-	secret_service_remove (self, schema, attributes, cancellable,
+	secret_service_remove (service, schema, attributes, cancellable,
 	                       _secret_sync_on_result, sync);
 
 	g_main_loop_run (sync->loop);
 
-	result = secret_service_remove_finish (self, sync->result, error);
+	result = secret_service_remove_finish (service, sync->result, error);
 
 	g_main_context_pop_thread_default (sync->context);
 	_secret_sync_free (sync);
@@ -1475,6 +1740,7 @@ secret_service_remove_sync (SecretService *self,
 
 typedef struct {
 	GCancellable *cancellable;
+	gchar *alias;
 	SecretCollection *collection;
 } ReadClosure;
 
@@ -1482,6 +1748,7 @@ static void
 read_closure_free (gpointer data)
 {
 	ReadClosure *read = data;
+	g_free (read->alias);
 	if (read->collection)
 		g_object_unref (read->collection);
 	if (read->cancellable)
@@ -1547,9 +1814,33 @@ on_read_alias_path (GObject *source,
 	g_object_unref (async);
 }
 
+static void
+on_read_alias_service (GObject *source,
+                       GAsyncResult *result,
+                       gpointer user_data)
+{
+	GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
+	ReadClosure *read = g_simple_async_result_get_op_res_gpointer (async);
+	SecretService *service;
+	GError *error = NULL;
+
+	service = secret_service_get_finish (result, &error);
+	if (error == NULL) {
+		secret_service_read_alias_path (service, read->alias, read->cancellable,
+		                                on_read_alias_path, g_object_ref (async));
+		g_object_unref (service);
+
+	} else {
+		g_simple_async_result_take_error (async, error);
+		g_simple_async_result_complete (async);
+	}
+
+	g_object_unref (async);
+}
+
 /**
  * secret_service_read_alias:
- * @self: a secret service object
+ * @service: (allow-none): a secret service object
  * @alias: the alias to lookup
  * @cancellable: (allow-none): optional cancellation object
  * @callback: called when the operation completes
@@ -1558,10 +1849,13 @@ on_read_alias_path (GObject *source,
  * Lookup which collection is assigned to this alias. Aliases help determine
  * well known collections, such as 'default'.
  *
+ * If @service is NULL, then secret_service_get() will be called to get
+ * the default #SecretService proxy.
+ *
  * This method will return immediately and complete asynchronously.
  */
 void
-secret_service_read_alias (SecretService *self,
+secret_service_read_alias (SecretService *service,
                            const gchar *alias,
                            GCancellable *cancellable,
                            GAsyncReadyCallback callback,
@@ -1570,25 +1864,31 @@ secret_service_read_alias (SecretService *self,
 	GSimpleAsyncResult *async;
 	ReadClosure *read;
 
-	g_return_if_fail (SECRET_IS_SERVICE (self));
+	g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service));
 	g_return_if_fail (alias != NULL);
 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
 
-	async = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
+	async = g_simple_async_result_new (G_OBJECT (service), callback, user_data,
 	                                   secret_service_read_alias);
 	read = g_slice_new0 (ReadClosure);
 	read->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+	read->alias = g_strdup (alias);
 	g_simple_async_result_set_op_res_gpointer (async, read, read_closure_free);
 
-	secret_service_read_alias_path (self, alias, cancellable,
-	                                on_read_alias_path, g_object_ref (async));
+	if (service == NULL) {
+		secret_service_get (SECRET_SERVICE_NONE, cancellable,
+		                    on_read_alias_service, g_object_ref (async));
+	} else {
+		secret_service_read_alias_path (service, read->alias, read->cancellable,
+		                                on_read_alias_path, g_object_ref (async));
+	}
 
 	g_object_unref (async);
 }
 
 /**
  * secret_service_read_alias_finish:
- * @self: a secret service object
+ * @service: (allow-none): a secret service object
  * @result: asynchronous result passed to callback
  * @error: location to place error on failure
  *
@@ -1598,15 +1898,15 @@ secret_service_read_alias (SecretService *self,
  * Returns: (transfer full): the collection, or %NULL if none assigned to the alias
  */
 SecretCollection *
-secret_service_read_alias_finish (SecretService *self,
+secret_service_read_alias_finish (SecretService *service,
                                   GAsyncResult *result,
                                   GError **error)
 {
 	GSimpleAsyncResult *async;
 	ReadClosure *read;
 
-	g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
-	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
+	g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), NULL);
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (service),
 	                      secret_service_read_alias), NULL);
 	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
 
@@ -1621,7 +1921,7 @@ secret_service_read_alias_finish (SecretService *self,
 
 /**
  * secret_service_read_alias_sync:
- * @self: a secret service object
+ * @service: (allow-none): a secret service object
  * @alias: the alias to lookup
  * @cancellable: (allow-none): optional cancellation object
  * @error: location to place error on failure
@@ -1629,12 +1929,15 @@ secret_service_read_alias_finish (SecretService *self,
  * Lookup which collection is assigned to this alias. Aliases help determine
  * well known collections, such as 'default'.
  *
+ * If @service is NULL, then secret_service_get_sync() will be called to get
+ * the default #SecretService proxy.
+ *
  * This method may block and should not be used in user interface threads.
  *
  * Returns: (transfer full): the collection, or %NULL if none assigned to the alias
  */
 SecretCollection *
-secret_service_read_alias_sync (SecretService *self,
+secret_service_read_alias_sync (SecretService *service,
                                 const gchar *alias,
                                 GCancellable *cancellable,
                                 GError **error)
@@ -1642,12 +1945,12 @@ secret_service_read_alias_sync (SecretService *self,
 	SecretCollection *collection;
 	gchar *collection_path;
 
-	g_return_val_if_fail (SECRET_IS_SERVICE (self), NULL);
+	g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), NULL);
 	g_return_val_if_fail (alias != NULL, NULL);
 	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
 	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
 
-	collection_path = secret_service_read_alias_path_sync (self, alias,
+	collection_path = secret_service_read_alias_path_sync (service, alias,
 	                                                       cancellable, error);
 	if (collection_path == NULL)
 		return NULL;
@@ -1657,12 +1960,12 @@ secret_service_read_alias_sync (SecretService *self,
 		collection = NULL;
 
 	} else {
-		collection = _secret_service_find_collection_instance (self,
+		collection = _secret_service_find_collection_instance (service,
 		                                                       collection_path);
 
 		/* No collection loaded, but valid path, load */
 		if (collection == NULL) {
-			collection = secret_collection_new_sync (self, collection_path,
+			collection = secret_collection_new_sync (service, collection_path,
 			                                         SECRET_COLLECTION_LOAD_ITEMS,
 			                                         cancellable, error);
 		}
@@ -1674,7 +1977,7 @@ secret_service_read_alias_sync (SecretService *self,
 
 /**
  * secret_service_set_alias:
- * @self: a secret service object
+ * @service: (allow-none): a secret service object
  * @alias: the alias to assign the collection to
  * @collection: (allow-none): the collection to assign to the alias
  * @cancellable: (allow-none): optional cancellation object
@@ -1684,10 +1987,13 @@ secret_service_read_alias_sync (SecretService *self,
  * Assign a collection to this alias. Aliases help determine
  * well known collections, such as 'default'.
  *
+ * If @service is NULL, then secret_collection_get_service() will be called to get
+ * a #SecretService proxy.
+ *
  * This method will return immediately and complete asynchronously.
  */
 void
-secret_service_set_alias (SecretService *self,
+secret_service_set_alias (SecretService *service,
                           const gchar *alias,
                           SecretCollection *collection,
                           GCancellable *cancellable,
@@ -1696,7 +2002,7 @@ secret_service_set_alias (SecretService *self,
 {
 	const gchar *collection_path;
 
-	g_return_if_fail (SECRET_IS_SERVICE (self));
+	g_return_if_fail (service == NULL || SECRET_IS_SERVICE (service));
 	g_return_if_fail (alias != NULL);
 	g_return_if_fail (collection == NULL || SECRET_IS_COLLECTION (collection));
 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
@@ -1708,13 +2014,22 @@ secret_service_set_alias (SecretService *self,
 		collection_path = NULL;
 	}
 
-	secret_service_set_alias_path (self, alias, collection_path, cancellable,
+	if (service == NULL) {
+		service = secret_collection_get_service (collection);
+		g_return_if_fail (service != NULL);
+	} else {
+		g_object_ref (service);
+	}
+
+	secret_service_set_alias_path (service, alias, collection_path, cancellable,
 	                               callback, user_data);
+
+	g_object_unref (service);
 }
 
 /**
  * secret_service_set_alias_finish:
- * @self: a secret service object
+ * @service: (allow-none): a secret service object
  * @result: asynchronous result passed to callback
  * @error: location to place error on failure
  *
@@ -1723,19 +2038,30 @@ secret_service_set_alias (SecretService *self,
  * Returns: %TRUE if successful
  */
 gboolean
-secret_service_set_alias_finish (SecretService *self,
+secret_service_set_alias_finish (SecretService *service,
                                  GAsyncResult *result,
                                  GError **error)
 {
-	g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE);
+	gboolean ret;
+
+	g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), FALSE);
 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-	return secret_service_set_alias_path_finish (self, result, error);
+	if (service == NULL)
+		service = SECRET_SERVICE (g_async_result_get_source_object (result));
+	else
+		g_object_ref (service);
+
+	ret = secret_service_set_alias_path_finish (service, result, error);
+
+	g_object_unref (service);
+
+	return ret;
 }
 
 /**
  * secret_service_set_alias_sync:
- * @self: a secret service object
+ * @service: (allow-none): a secret service object
  * @alias: the alias to assign the collection to
  * @collection: (allow-none): the collection to assign to the alias
  * @cancellable: (allow-none): optional cancellation object
@@ -1744,12 +2070,15 @@ secret_service_set_alias_finish (SecretService *self,
  * Assign a collection to this alias. Aliases help determine
  * well known collections, such as 'default'.
  *
+ * If @service is NULL, then secret_service_get_sync() will be called to get
+ * the default #SecretService proxy.
+ *
  * This method may block and should not be used in user interface threads.
  *
  * Returns: %TRUE if successful
  */
 gboolean
-secret_service_set_alias_sync (SecretService *self,
+secret_service_set_alias_sync (SecretService *service,
                                const gchar *alias,
                                SecretCollection *collection,
                                GCancellable *cancellable,
@@ -1758,7 +2087,7 @@ secret_service_set_alias_sync (SecretService *self,
 	SecretSync *sync;
 	gboolean ret;
 
-	g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE);
+	g_return_val_if_fail (service == NULL || SECRET_IS_SERVICE (service), FALSE);
 	g_return_val_if_fail (alias != NULL, FALSE);
 	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
@@ -1766,12 +2095,12 @@ secret_service_set_alias_sync (SecretService *self,
 	sync = _secret_sync_new ();
 	g_main_context_push_thread_default (sync->context);
 
-	secret_service_set_alias (self, alias, collection, cancellable,
+	secret_service_set_alias (service, alias, collection, cancellable,
 	                          _secret_sync_on_result, sync);
 
 	g_main_loop_run (sync->loop);
 
-	ret = secret_service_set_alias_finish (self, sync->result, error);
+	ret = secret_service_set_alias_finish (service, sync->result, error);
 
 	g_main_context_pop_thread_default (sync->context);
 	_secret_sync_free (sync);
diff --git a/library/secret-password.c b/library/secret-password.c
index 0f34010..b27c44e 100644
--- a/library/secret-password.c
+++ b/library/secret-password.c
@@ -42,76 +42,6 @@
  * Stability: Stable
  */
 
-typedef struct {
-	const SecretSchema *schema;
-	GHashTable *attributes;
-	gchar *collection_path;
-	gchar *label;
-	SecretValue *value;
-	GCancellable *cancellable;
-	gboolean created;
-} StoreClosure;
-
-static void
-store_closure_free (gpointer data)
-{
-	StoreClosure *closure = data;
-	_secret_schema_unref_if_nonstatic (closure->schema);
-	g_hash_table_unref (closure->attributes);
-	g_free (closure->collection_path);
-	g_free (closure->label);
-	secret_value_unref (closure->value);
-	g_clear_object (&closure->cancellable);
-	g_slice_free (StoreClosure, closure);
-}
-
-static void
-on_store_complete (GObject *source,
-                   GAsyncResult *result,
-                   gpointer user_data)
-{
-	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
-	StoreClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
-	GError *error = NULL;
-
-	closure->created = secret_service_store_finish (SECRET_SERVICE (source),
-	                                                result, &error);
-	if (error != NULL)
-		g_simple_async_result_take_error (res, error);
-
-	g_simple_async_result_complete (res);
-	g_object_unref (res);
-}
-
-static void
-on_store_connected (GObject *source,
-                    GAsyncResult *result,
-                    gpointer user_data)
-{
-	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
-	StoreClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
-	SecretService *service;
-	GError *error = NULL;
-
-	service = secret_service_get_finish (result, &error);
-	if (error == NULL) {
-		secret_service_store (service, closure->schema,
-		                      closure->attributes,
-		                      closure->collection_path,
-		                      closure->label, closure->value,
-		                      closure->cancellable,
-		                      on_store_complete,
-		                      g_object_ref (res));
-		g_object_unref (service);
-
-	} else {
-		g_simple_async_result_take_error (res, error);
-		g_simple_async_result_complete (res);
-	}
-
-	g_object_unref (res);
-}
-
 /**
  * secret_password_store: (skip)
  * @schema: the schema for attributes
@@ -203,8 +133,7 @@ secret_password_storev (const SecretSchema *schema,
                         GAsyncReadyCallback callback,
                         gpointer user_data)
 {
-	GSimpleAsyncResult *res;
-	StoreClosure *closure;
+	SecretValue *value;
 
 	g_return_if_fail (schema != NULL);
 	g_return_if_fail (label != NULL);
@@ -216,21 +145,12 @@ secret_password_storev (const SecretSchema *schema,
 	if (!_secret_attributes_validate (schema, attributes))
 		return;
 
-	res = g_simple_async_result_new (NULL, callback, user_data,
-	                                 secret_password_storev);
-	closure = g_slice_new0 (StoreClosure);
-	closure->schema = _secret_schema_ref_if_nonstatic (schema);
-	closure->collection_path = g_strdup (collection_path);
-	closure->label = g_strdup (label);
-	closure->value = secret_value_new (password, -1, "text/plain");
-	closure->attributes = _secret_attributes_copy (attributes);
-	closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
-	g_simple_async_result_set_op_res_gpointer (res, closure, store_closure_free);
-
-	secret_service_get (SECRET_SERVICE_OPEN_SESSION, cancellable,
-	                    on_store_connected, g_object_ref (res));
-
-	g_object_unref (res);
+	value = secret_value_new (password, -1, "text/plain");
+
+	secret_service_store (NULL, schema, attributes, collection_path,
+	                      label, value, cancellable, callback, user_data);
+
+	secret_value_unref (value);
 }
 
 /**
@@ -246,19 +166,8 @@ gboolean
 secret_password_store_finish (GAsyncResult *result,
                               GError **error)
 {
-	GSimpleAsyncResult *res;
-	StoreClosure *closure;
-
 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-	g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL,
-	                      secret_password_storev), FALSE);
-
-	res = G_SIMPLE_ASYNC_RESULT (result);
-	if (g_simple_async_result_propagate_error (res, error))
-		return FALSE;
-
-	closure = g_simple_async_result_get_op_res_gpointer (res);
-	return closure->created;
+	return secret_service_store_finish (NULL, result, error);
 }
 
 /**
@@ -387,25 +296,6 @@ secret_password_storev_sync (const SecretSchema *schema,
 	return ret;
 }
 
-typedef struct {
-	GCancellable *cancellable;
-	GHashTable *attributes;
-	SecretValue *value;
-	const SecretSchema *schema;
-} LookupClosure;
-
-static void
-lookup_closure_free (gpointer data)
-{
-	LookupClosure *closure = data;
-	_secret_schema_unref_if_nonstatic (closure->schema);
-	g_clear_object (&closure->cancellable);
-	g_hash_table_unref (closure->attributes);
-	if (closure->value)
-		secret_value_unref (closure->value);
-	g_slice_free (LookupClosure, closure);
-}
-
 /**
  * secret_password_lookup: (skip)
  * @schema: the schema for the attributes
@@ -448,50 +338,6 @@ secret_password_lookup (const SecretSchema *schema,
 	g_hash_table_unref (attributes);
 }
 
-static void
-on_lookup_complete (GObject *source,
-                    GAsyncResult *result,
-                    gpointer user_data)
-{
-	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
-	LookupClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
-	GError *error = NULL;
-
-	closure->value = secret_service_lookup_finish (SECRET_SERVICE (source),
-	                                               result, &error);
-
-	if (error != NULL)
-		g_simple_async_result_take_error (res, error);
-
-	g_simple_async_result_complete (res);
-	g_object_unref (res);
-}
-
-static void
-on_lookup_connected (GObject *source,
-                     GAsyncResult *result,
-                     gpointer user_data)
-{
-	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
-	LookupClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
-	SecretService *service;
-	GError *error = NULL;
-
-	service = secret_service_get_finish (result, &error);
-	if (error != NULL) {
-		g_simple_async_result_take_error (res, error);
-		g_simple_async_result_complete (res);
-
-	} else {
-		secret_service_lookup (service, closure->schema, closure->attributes,
-		                       closure->cancellable, on_lookup_complete,
-		                       g_object_ref (res));
-		g_object_unref (service);
-	}
-
-	g_object_unref (res);
-}
-
 /**
  * secret_password_lookupv:
  * @schema: the schema for attributes
@@ -517,9 +363,6 @@ secret_password_lookupv (const SecretSchema *schema,
                          GAsyncReadyCallback callback,
                          gpointer user_data)
 {
-	GSimpleAsyncResult *res;
-	LookupClosure *closure;
-
 	g_return_if_fail (schema != NULL);
 	g_return_if_fail (attributes != NULL);
 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
@@ -528,18 +371,8 @@ secret_password_lookupv (const SecretSchema *schema,
 	if (!_secret_attributes_validate (schema, attributes))
 		return;
 
-	res = g_simple_async_result_new (NULL, callback, user_data,
-	                                 secret_password_lookupv);
-	closure = g_slice_new0 (LookupClosure);
-	closure->schema = _secret_schema_ref_if_nonstatic (schema);
-	closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
-	closure->attributes = _secret_attributes_copy (attributes);
-	g_simple_async_result_set_op_res_gpointer (res, closure, lookup_closure_free);
-
-	secret_service_get (SECRET_SERVICE_OPEN_SESSION, cancellable,
-	                    on_lookup_connected, g_object_ref (res));
-
-	g_object_unref (res);
+	secret_service_lookup (NULL, schema, attributes,
+	                       cancellable, callback, user_data);
 }
 
 /**
@@ -556,25 +389,15 @@ gchar *
 secret_password_lookup_nonpageable_finish (GAsyncResult *result,
                                            GError **error)
 {
-	GSimpleAsyncResult *res;
-	LookupClosure *closure;
-	gchar *password = NULL;
+	SecretValue *value;
 
 	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
-	g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL,
-	                      secret_password_lookupv), NULL);
-
-	res = G_SIMPLE_ASYNC_RESULT (result);
-	if (g_simple_async_result_propagate_error (res, error))
-		return NULL;
 
-	closure = g_simple_async_result_get_op_res_gpointer (res);
-	if (closure->value == NULL)
+	value = secret_service_lookup_finish (NULL, result, error);
+	if (value == NULL)
 		return NULL;
 
-	password = _secret_value_unref_to_password (closure->value);
-	closure->value = NULL;
-	return password;
+	return _secret_value_unref_to_password (value);
 }
 
 /**
@@ -591,25 +414,15 @@ gchar *
 secret_password_lookup_finish (GAsyncResult *result,
                                GError **error)
 {
-	GSimpleAsyncResult *res;
-	LookupClosure *closure;
-	gchar *string = NULL;
+	SecretValue *value;
 
 	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
-	g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL,
-	                      secret_password_lookupv), NULL);
-
-	res = G_SIMPLE_ASYNC_RESULT (result);
-	if (g_simple_async_result_propagate_error (res, error))
-		return NULL;
 
-	closure = g_simple_async_result_get_op_res_gpointer (res);
-	if (closure->value == NULL)
+	value = secret_service_lookup_finish (NULL, result, error);
+	if (value == NULL)
 		return NULL;
 
-	string = _secret_value_unref_to_string (closure->value);
-	closure->value = NULL;
-	return string;
+	return _secret_value_unref_to_string (value);
 }
 
 /**
@@ -816,23 +629,6 @@ secret_password_lookupv_sync (const SecretSchema *schema,
 	return string;
 }
 
-typedef struct {
-	GCancellable *cancellable;
-	GHashTable *attributes;
-	gboolean deleted;
-	const SecretSchema *schema;
-} DeleteClosure;
-
-static void
-delete_closure_free (gpointer data)
-{
-	DeleteClosure *closure = data;
-	g_clear_object (&closure->cancellable);
-	g_hash_table_unref (closure->attributes);
-	_secret_schema_unref_if_nonstatic (closure->schema);
-	g_slice_free (DeleteClosure, closure);
-}
-
 /**
  * secret_password_remove:
  * @schema: the schema for the attributes
@@ -875,48 +671,6 @@ secret_password_remove (const SecretSchema *schema,
 	g_hash_table_unref (attributes);
 }
 
-static void
-on_delete_complete (GObject *source,
-                    GAsyncResult *result,
-                    gpointer user_data)
-{
-	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
-	DeleteClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
-	GError *error = NULL;
-
-	closure->deleted = secret_service_remove_finish (SECRET_SERVICE (source),
-	                                                 result, &error);
-	if (error != NULL)
-		g_simple_async_result_take_error (res, error);
-	g_simple_async_result_complete (res);
-
-	g_object_unref (res);
-}
-
-static void
-on_delete_connect (GObject *source,
-                   GAsyncResult *result,
-                   gpointer user_data)
-{
-	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
-	DeleteClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
-	SecretService *service;
-	GError *error = NULL;
-
-	service = secret_service_get_finish (result, &error);
-	if (error == NULL) {
-		secret_service_remove (service, closure->schema, closure->attributes,
-		                       closure->cancellable, on_delete_complete,
-		                       g_object_ref (res));
-		g_object_unref (service);
-
-	} else {
-		g_simple_async_result_take_error (res, error);
-		g_simple_async_result_complete (res);
-	}
-
-	g_object_unref (res);
-}
 
 /**
  * secret_password_removev:
@@ -943,9 +697,6 @@ secret_password_removev (const SecretSchema *schema,
                          GAsyncReadyCallback callback,
                          gpointer user_data)
 {
-	GSimpleAsyncResult *res;
-	DeleteClosure *closure;
-
 	g_return_if_fail (schema != NULL);
 	g_return_if_fail (attributes != NULL);
 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
@@ -954,18 +705,8 @@ secret_password_removev (const SecretSchema *schema,
 	if (!_secret_attributes_validate (schema, attributes))
 		return;
 
-	res = g_simple_async_result_new (NULL, callback, user_data,
-	                                 secret_password_removev);
-	closure = g_slice_new0 (DeleteClosure);
-	closure->schema = _secret_schema_ref_if_nonstatic (schema);
-	closure->attributes = _secret_attributes_copy (attributes);
-	closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
-	g_simple_async_result_set_op_res_gpointer (res, closure, delete_closure_free);
-
-	secret_service_get (SECRET_SERVICE_NONE, cancellable,
-	                    on_delete_connect, g_object_ref (res));
-
-	g_object_unref (res);
+	secret_service_remove (NULL, schema, attributes,
+	                       cancellable, callback, user_data);
 }
 
 /**
@@ -982,19 +723,8 @@ gboolean
 secret_password_remove_finish (GAsyncResult *result,
                                GError **error)
 {
-	DeleteClosure *closure;
-	GSimpleAsyncResult *res;
-
 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-	g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL,
-	                      secret_password_removev), FALSE);
-
-	res = G_SIMPLE_ASYNC_RESULT (result);
-	if (g_simple_async_result_propagate_error (res, error))
-		return FALSE;
-
-	closure = g_simple_async_result_get_op_res_gpointer (res);
-	return closure->deleted;
+	return secret_service_remove_finish (NULL, result, error);
 }
 
 /**
diff --git a/library/secret-service.c b/library/secret-service.c
index 4a2a273..c073f6b 100644
--- a/library/secret-service.c
+++ b/library/secret-service.c
@@ -653,18 +653,6 @@ _secret_service_set_default_bus_name (const gchar *bus_name)
 	default_bus_name = bus_name;
 }
 
-static void
-on_service_instance_gone (gpointer user_data,
-                          GObject *where_the_object_was)
-{
-	G_LOCK (service_instance);
-
-		g_assert (service_instance == where_the_object_was);
-		service_instance = NULL;
-
-	G_UNLOCK (service_instance);
-}
-
 /**
  * secret_service_get:
  * @flags: flags for which service functionality to ensure is initialized
@@ -758,10 +746,8 @@ secret_service_get_finish (GAsyncResult *result,
 
 		if (service) {
 			G_LOCK (service_instance);
-			if (service_instance == NULL) {
-				service_instance = service;
-				g_object_weak_ref (G_OBJECT (service), on_service_instance_gone, NULL);
-			}
+			if (service_instance == NULL)
+				service_instance = g_object_ref (service);
 			G_UNLOCK (service_instance);
 		}
 	}
@@ -818,10 +804,8 @@ secret_service_get_sync (SecretServiceFlags flags,
 
 		if (service != NULL) {
 			G_LOCK (service_instance);
-			if (service_instance == NULL) {
-				service_instance = service;
-				g_object_weak_ref (G_OBJECT (service), on_service_instance_gone, NULL);
-			}
+			if (service_instance == NULL)
+				service_instance = g_object_ref (service);
 			G_UNLOCK (service_instance);
 		}
 
@@ -836,6 +820,33 @@ secret_service_get_sync (SecretServiceFlags flags,
 }
 
 /**
+ * secret_service_disconnect:
+ *
+ * Disconnect the default #SecretService proxy returned by secret_service_get()
+ * and secret_service_get_sync().
+ *
+ * It is not necessary to call this function, but you may choose to do so at
+ * program exit. It is useful for testing that memory is not leaked.
+ *
+ * This function is safe to call at any time. But if other objects in this
+ * library are still referenced, then this will not result in all memory
+ * being freed.
+ */
+void
+secret_service_disconnect (void)
+{
+	SecretService *instance;
+
+	G_LOCK (service_instance);
+	instance = service_instance;
+	service_instance = NULL;
+	G_UNLOCK (service_instance);
+
+	if (instance != NULL)
+		g_object_unref (instance);
+}
+
+/**
  * secret_service_new:
  * @service_gtype: the GType of the new secret service
  * @service_bus_name: (allow-none): the D-Bus service name of the secret service
diff --git a/library/secret-service.h b/library/secret-service.h
index 6fae768..b4626be 100644
--- a/library/secret-service.h
+++ b/library/secret-service.h
@@ -100,6 +100,8 @@ SecretService *      secret_service_get_sync                      (SecretService
                                                                    GCancellable *cancellable,
                                                                    GError **error);
 
+void                 secret_service_disconnect                    (void);
+
 void                 secret_service_new                           (GType service_gtype,
                                                                    const gchar *service_bus_name,
                                                                    SecretServiceFlags flags,
@@ -150,7 +152,24 @@ gboolean             secret_service_load_collections_sync         (SecretService
                                                                    GCancellable *cancellable,
                                                                    GError **error);
 
-void                 secret_service_search                        (SecretService *self,
+GVariant *           secret_service_prompt_sync                   (SecretService *self,
+                                                                   SecretPrompt *prompt,
+                                                                   GCancellable *cancellable,
+                                                                   const GVariantType *return_type,
+                                                                   GError **error);
+
+void                 secret_service_prompt                        (SecretService *self,
+                                                                   SecretPrompt *prompt,
+                                                                   GCancellable *cancellable,
+                                                                   GAsyncReadyCallback callback,
+                                                                   gpointer user_data);
+
+GVariant *           secret_service_prompt_finish                 (SecretService *self,
+                                                                   GAsyncResult *result,
+                                                                   const GVariantType *return_type,
+                                                                   GError **error);
+
+void                 secret_service_search                        (SecretService *service,
                                                                    const SecretSchema *schema,
                                                                    GHashTable *attributes,
                                                                    SecretSearchFlags flags,
@@ -158,69 +177,52 @@ void                 secret_service_search                        (SecretService
                                                                    GAsyncReadyCallback callback,
                                                                    gpointer user_data);
 
-GList *              secret_service_search_finish                 (SecretService *self,
+GList *              secret_service_search_finish                 (SecretService *service,
                                                                    GAsyncResult *result,
                                                                    GError **error);
 
-GList *              secret_service_search_sync                   (SecretService *self,
+GList *              secret_service_search_sync                   (SecretService *service,
                                                                    const SecretSchema *schema,
                                                                    GHashTable *attributes,
                                                                    SecretSearchFlags flags,
                                                                    GCancellable *cancellable,
                                                                    GError **error);
 
-void                 secret_service_lock                          (SecretService *self,
+void                 secret_service_lock                          (SecretService *service,
                                                                    GList *objects,
                                                                    GCancellable *cancellable,
                                                                    GAsyncReadyCallback callback,
                                                                    gpointer user_data);
 
-gint                 secret_service_lock_finish                   (SecretService *self,
+gint                 secret_service_lock_finish                   (SecretService *service,
                                                                    GAsyncResult *result,
                                                                    GList **locked,
                                                                    GError **error);
 
-gint                 secret_service_lock_sync                     (SecretService *self,
+gint                 secret_service_lock_sync                     (SecretService *service,
                                                                    GList *objects,
                                                                    GCancellable *cancellable,
                                                                    GList **locked,
                                                                    GError **error);
 
-void                 secret_service_unlock                        (SecretService *self,
+void                 secret_service_unlock                        (SecretService *service,
                                                                    GList *objects,
                                                                    GCancellable *cancellable,
                                                                    GAsyncReadyCallback callback,
                                                                    gpointer user_data);
 
-gint                 secret_service_unlock_finish                 (SecretService *self,
+gint                 secret_service_unlock_finish                 (SecretService *service,
                                                                    GAsyncResult *result,
                                                                    GList **unlocked,
                                                                    GError **error);
 
-gint                 secret_service_unlock_sync                   (SecretService *self,
+gint                 secret_service_unlock_sync                   (SecretService *service,
                                                                    GList *objects,
                                                                    GCancellable *cancellable,
                                                                    GList **unlocked,
                                                                    GError **error);
 
-GVariant *           secret_service_prompt_sync                   (SecretService *self,
-                                                                   SecretPrompt *prompt,
-                                                                   GCancellable *cancellable,
-                                                                   const GVariantType *return_type,
-                                                                   GError **error);
-
-void                 secret_service_prompt                        (SecretService *self,
-                                                                   SecretPrompt *prompt,
-                                                                   GCancellable *cancellable,
-                                                                   GAsyncReadyCallback callback,
-                                                                   gpointer user_data);
-
-GVariant *           secret_service_prompt_finish                 (SecretService *self,
-                                                                   GAsyncResult *result,
-                                                                   const GVariantType *return_type,
-                                                                   GError **error);
-
-void                 secret_service_store                         (SecretService *self,
+void                 secret_service_store                         (SecretService *service,
                                                                    const SecretSchema *schema,
                                                                    GHashTable *attributes,
                                                                    const gchar *collection_path,
@@ -230,11 +232,11 @@ void                 secret_service_store                         (SecretService
                                                                    GAsyncReadyCallback callback,
                                                                    gpointer user_data);
 
-gboolean             secret_service_store_finish                  (SecretService *self,
+gboolean             secret_service_store_finish                  (SecretService *service,
                                                                    GAsyncResult *result,
                                                                    GError **error);
 
-gboolean             secret_service_store_sync                    (SecretService *self,
+gboolean             secret_service_store_sync                    (SecretService *service,
                                                                    const SecretSchema *schema,
                                                                    GHashTable *attributes,
                                                                    const gchar *collection_path,
@@ -243,67 +245,67 @@ gboolean             secret_service_store_sync                    (SecretService
                                                                    GCancellable *cancellable,
                                                                    GError **error);
 
-void                 secret_service_lookup                        (SecretService *self,
+void                 secret_service_lookup                        (SecretService *service,
                                                                    const SecretSchema *schema,
                                                                    GHashTable *attributes,
                                                                    GCancellable *cancellable,
                                                                    GAsyncReadyCallback callback,
                                                                    gpointer user_data);
 
-SecretValue *        secret_service_lookup_finish                 (SecretService *self,
+SecretValue *        secret_service_lookup_finish                 (SecretService *service,
                                                                    GAsyncResult *result,
                                                                    GError **error);
 
-SecretValue *        secret_service_lookup_sync                   (SecretService *self,
+SecretValue *        secret_service_lookup_sync                   (SecretService *service,
                                                                    const SecretSchema *schema,
                                                                    GHashTable *attributes,
                                                                    GCancellable *cancellable,
                                                                    GError **error);
 
-void                 secret_service_remove                        (SecretService *self,
+void                 secret_service_remove                        (SecretService *service,
                                                                    const SecretSchema *schema,
                                                                    GHashTable *attributes,
                                                                    GCancellable *cancellable,
                                                                    GAsyncReadyCallback callback,
                                                                    gpointer user_data);
 
-gboolean             secret_service_remove_finish                 (SecretService *self,
+gboolean             secret_service_remove_finish                 (SecretService *service,
                                                                    GAsyncResult *result,
                                                                    GError **error);
 
-gboolean             secret_service_remove_sync                   (SecretService *self,
+gboolean             secret_service_remove_sync                   (SecretService *service,
                                                                    const SecretSchema *schema,
                                                                    GHashTable *attributes,
                                                                    GCancellable *cancellable,
                                                                    GError **error);
 
-void                 secret_service_read_alias                    (SecretService *self,
+void                 secret_service_read_alias                    (SecretService *service,
                                                                    const gchar *alias,
                                                                    GCancellable *cancellable,
                                                                    GAsyncReadyCallback callback,
                                                                    gpointer user_data);
 
-SecretCollection *   secret_service_read_alias_finish             (SecretService *self,
+SecretCollection *   secret_service_read_alias_finish             (SecretService *service,
                                                                    GAsyncResult *result,
                                                                    GError **error);
 
-SecretCollection *   secret_service_read_alias_sync               (SecretService *self,
+SecretCollection *   secret_service_read_alias_sync               (SecretService *service,
                                                                    const gchar *alias,
                                                                    GCancellable *cancellable,
                                                                    GError **error);
 
-void                 secret_service_set_alias                     (SecretService *self,
+void                 secret_service_set_alias                     (SecretService *service,
                                                                    const gchar *alias,
                                                                    SecretCollection *collection,
                                                                    GCancellable *cancellable,
                                                                    GAsyncReadyCallback callback,
                                                                    gpointer user_data);
 
-gboolean             secret_service_set_alias_finish              (SecretService *self,
+gboolean             secret_service_set_alias_finish              (SecretService *service,
                                                                    GAsyncResult *result,
                                                                    GError **error);
 
-gboolean             secret_service_set_alias_sync                (SecretService *self,
+gboolean             secret_service_set_alias_sync                (SecretService *service,
                                                                    const gchar *alias,
                                                                    SecretCollection *collection,
                                                                    GCancellable *cancellable,
diff --git a/library/tests/test-collection.c b/library/tests/test-collection.c
index 85acf8c..70e3998 100644
--- a/library/tests/test-collection.c
+++ b/library/tests/test-collection.c
@@ -51,6 +51,7 @@ teardown (Test *test,
           gconstpointer unused)
 {
 	g_object_unref (test->service);
+	secret_service_disconnect ();
 	egg_assert_not_object (test->service);
 
 	mock_service_stop ();
diff --git a/library/tests/test-item.c b/library/tests/test-item.c
index d0c55c0..1a58907 100644
--- a/library/tests/test-item.c
+++ b/library/tests/test-item.c
@@ -52,6 +52,7 @@ teardown (Test *test,
           gconstpointer unused)
 {
 	g_object_unref (test->service);
+	secret_service_disconnect ();
 	egg_assert_not_object (test->service);
 
 	mock_service_stop ();
diff --git a/library/tests/test-methods.c b/library/tests/test-methods.c
index 0cefcd4..b000b56 100644
--- a/library/tests/test-methods.c
+++ b/library/tests/test-methods.c
@@ -99,6 +99,7 @@ teardown (Test *test,
 	egg_test_wait_idle ();
 
 	g_object_unref (test->service);
+	secret_service_disconnect ();
 	egg_assert_not_object (test->service);
 
 	teardown_mock (test, unused);
diff --git a/library/tests/test-password.c b/library/tests/test-password.c
index d5829df..d541daf 100644
--- a/library/tests/test-password.c
+++ b/library/tests/test-password.c
@@ -74,6 +74,7 @@ static void
 teardown (Test *test,
           gconstpointer unused)
 {
+	secret_service_disconnect ();
 	mock_service_stop ();
 }
 
diff --git a/library/tests/test-paths.c b/library/tests/test-paths.c
index b29ab3e..2a6f04d 100644
--- a/library/tests/test-paths.c
+++ b/library/tests/test-paths.c
@@ -99,6 +99,7 @@ teardown (Test *test,
 	egg_test_wait_idle ();
 
 	g_object_unref (test->service);
+	secret_service_disconnect ();
 	egg_assert_not_object (test->service);
 
 	teardown_mock (test, unused);
diff --git a/library/tests/test-prompt.c b/library/tests/test-prompt.c
index 9a7fd29..0bc03dd 100644
--- a/library/tests/test-prompt.c
+++ b/library/tests/test-prompt.c
@@ -52,6 +52,7 @@ teardown (Test *test,
           gconstpointer unused)
 {
 	g_object_unref (test->service);
+	secret_service_disconnect ();
 	egg_assert_not_object (test->service);
 
 	mock_service_stop ();
diff --git a/library/tests/test-service.c b/library/tests/test-service.c
index e78fbe6..85820e4 100644
--- a/library/tests/test-service.c
+++ b/library/tests/test-service.c
@@ -84,14 +84,16 @@ test_get_sync (void)
 	g_assert (G_IS_OBJECT (service1));
 
 	g_object_unref (service2);
+	secret_service_disconnect ();
 	egg_assert_not_object (service2);
 
-	/* Services were unreffed, so this should create a new one */
+	/* Services were disconnected, so this should create a new one */
 	service3 = secret_service_get_sync (SECRET_SERVICE_NONE, NULL, &error);
 	g_assert (SECRET_IS_SERVICE (service3));
 	g_assert_no_error (error);
 
 	g_object_unref (service3);
+	secret_service_disconnect ();
 	egg_assert_not_object (service3);
 }
 
@@ -127,6 +129,7 @@ test_get_async (void)
 	g_assert (G_IS_OBJECT (service1));
 
 	g_object_unref (service2);
+	secret_service_disconnect ();
 	egg_assert_not_object (service2);
 
 	/* Services were unreffed, so this should create a new one */
@@ -138,6 +141,7 @@ test_get_async (void)
 	g_clear_object (&result);
 
 	g_object_unref (service3);
+	secret_service_disconnect ();
 	egg_assert_not_object (service3);
 }
 
@@ -179,6 +183,7 @@ test_get_more_sync (Test *test,
 	g_object_unref (service2);
 
 	g_object_unref (service);
+	secret_service_disconnect ();
 	egg_assert_not_object (service);
 }
 
@@ -211,6 +216,7 @@ test_get_more_async (Test *test,
 	g_list_free_full (collections, g_object_unref);
 
 	g_object_unref (service);
+	secret_service_disconnect ();
 	egg_assert_not_object (service);
 
 	/* Now get a session with just collections */
@@ -233,6 +239,7 @@ test_get_more_async (Test *test,
 	g_list_free_full (collections, g_object_unref);
 
 	g_object_unref (service);
+	secret_service_disconnect ();
 	egg_assert_not_object (service);
 }
 
@@ -430,6 +437,7 @@ test_connect_async (Test *test,
 	g_assert (path == NULL);
 
 	g_object_unref (service);
+	secret_service_disconnect ();
 	egg_assert_not_object (service);
 }
 
@@ -457,6 +465,7 @@ test_connect_ensure_async (Test *test,
 	g_assert (path != NULL);
 
 	g_object_unref (service);
+	secret_service_disconnect ();
 	egg_assert_not_object (service);
 }
 
diff --git a/library/tests/test-session.c b/library/tests/test-session.c
index 6599ae4..0439e1b 100644
--- a/library/tests/test-session.c
+++ b/library/tests/test-session.c
@@ -49,6 +49,7 @@ teardown (Test *test,
           gconstpointer unused)
 {
 	g_object_unref (test->service);
+	secret_service_disconnect ();
 	egg_assert_not_object (test->service);
 
 	mock_service_stop ();



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