Commit 044418f5 authored by Benjamin Berg's avatar Benjamin Berg

Add new API to allow automatic server side deletion of client

If gclue_client_proxy_create_full is called with the corresponding flag
set, then the newly created GClueClientProxy will be set up so that
DeleteClient is automatically called on the server when the object is
destroyed.

See #102
parent b3fe46d4
......@@ -58,6 +58,9 @@ gclue_client_complete_stop
gclue_client_proxy_create
gclue_client_proxy_create_finish
gclue_client_proxy_create_sync
gclue_client_proxy_create_full
gclue_client_proxy_create_full_finish
gclue_client_proxy_create_full_sync
gclue_client_proxy_new
gclue_client_proxy_new_finish
gclue_client_proxy_new_sync
......@@ -85,6 +88,9 @@ GClueClientProxyPrivate
GClueAccuracyLevel
GCLUE_TYPE_ACCURACY_LEVEL
gclue_accuracy_level_get_type
GClueClientProxyCreateFlags
GCLUE_TYPE_CLIENT_PROXY_CREATE_FLAGS
gclue_client_proxy_create_flags_get_type
<SUBSECTION Private>
gclue_accuracy_level_build_string_from_mask
gclue_accuracy_level_get_string
......
......@@ -35,20 +35,29 @@
*/
typedef struct {
char *desktop_id;
GClueAccuracyLevel accuracy_level;
char *desktop_id;
GClueAccuracyLevel accuracy_level;
GClueClientProxyCreateFlags flags;
GClueManager *manager;
gulong notify_id;
} ClientCreateData;
typedef struct {
GClueManager *manager;
char *client_path;
} ClientDestroyData;
static ClientCreateData *
client_create_data_new (const char *desktop_id,
GClueAccuracyLevel accuracy_level)
client_create_data_new (const char *desktop_id,
GClueAccuracyLevel accuracy_level,
GClueClientProxyCreateFlags flags)
{
ClientCreateData *data = g_slice_new0 (ClientCreateData);
data->desktop_id = g_strdup (desktop_id);
data->accuracy_level = accuracy_level;
data->flags = flags;
return data;
}
......@@ -56,10 +65,58 @@ client_create_data_new (const char *desktop_id,
static void
client_create_data_free (ClientCreateData *data)
{
g_clear_object (&data->manager);
g_free (data->desktop_id);
g_slice_free (ClientCreateData, data);
}
static ClientDestroyData *
client_destroy_data_new (GClueManager *manager,
const char *client_path)
{
ClientDestroyData *data = g_slice_new0 (ClientDestroyData);
if (manager)
data->manager = g_object_ref (manager);
data->client_path = g_strdup (client_path);
return data;
}
static void
on_delete_client_finished (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
g_autoptr(GError) error = NULL;
ClientDestroyData *data = user_data;
if (!gclue_manager_call_delete_client_finish (
GCLUE_MANAGER (source_object),
res,
&error)) {
g_warning ("GClue: Failed to automatically delete client: %s",
error->message);
}
g_clear_object (&data->manager);
g_clear_pointer (&data->client_path, g_free);
g_slice_free (ClientDestroyData, data);
}
static void
on_client_destroyed (gpointer data,
GObject *where_the_object_was)
{
ClientDestroyData *destroy_data = data;
gclue_manager_call_delete_client (destroy_data->manager,
destroy_data->client_path,
NULL,
on_delete_client_finished,
destroy_data);
}
static void
on_client_proxy_ready (GObject *source_object,
GAsyncResult *res,
......@@ -67,6 +124,7 @@ on_client_proxy_ready (GObject *source_object,
{
GTask *task = G_TASK (user_data);
ClientCreateData *data;
ClientDestroyData *destroy;
GClueClient *client;
GError *error = NULL;
......@@ -82,6 +140,16 @@ on_client_proxy_ready (GObject *source_object,
gclue_client_set_desktop_id (client, data->desktop_id);
gclue_client_set_requested_accuracy_level (client, data->accuracy_level);
if (data->flags & GCLUE_CLIENT_PROXY_CREATE_AUTO_DELETE) {
destroy = client_destroy_data_new (
data->manager,
g_dbus_proxy_get_object_path (
G_DBUS_PROXY (client)));
g_object_weak_ref (G_OBJECT (client),
on_client_destroyed,
destroy);
}
g_task_return_pointer (task, client, g_object_unref);
g_object_unref (task);
}
......@@ -124,6 +192,7 @@ on_manager_proxy_ready (GObject *source_object,
gpointer user_data)
{
GTask *task = G_TASK (user_data);
ClientCreateData *data;
GClueManager *manager;
GError *error = NULL;
......@@ -135,12 +204,30 @@ on_manager_proxy_ready (GObject *source_object,
return;
}
data = g_task_get_task_data (task);
data->manager = g_object_ref (manager);
gclue_manager_call_get_client (manager,
g_task_get_cancellable (task),
on_get_client_ready,
task);
}
static void
on_client_proxy_full_finished (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
g_autoptr(GTask) task = user_data;
GClueClient *client;
GError *error = NULL;
client = gclue_client_proxy_create_finish (res, &error);
if (!client)
g_task_return_error (task, error);
else
g_task_return_pointer (task, client, g_object_unref);
}
/**
* gclue_client_proxy_create:
* @desktop_id: The desktop file id (the basename of the desktop file).
......@@ -150,7 +237,11 @@ on_manager_proxy_ready (GObject *source_object,
* @user_data: User data to pass to @callback.
*
* A utility function to create a #GClueClientProxy without having to deal with
* a #GClueManager.
* a #GClueManager. See also gclue_client_proxy_create_full() which improves
* resource management.
*
* This is identitcal to calling gclue_client_proxy_create_full() without any
* flags set.
*
* See #gclue_client_proxy_create_sync() for the synchronous, blocking version
* of this function.
......@@ -163,11 +254,102 @@ gclue_client_proxy_create (const char *desktop_id,
gpointer user_data)
{
GTask *task;
task = g_task_new (NULL, cancellable, callback, user_data);
gclue_client_proxy_create_full (desktop_id,
accuracy_level,
GCLUE_CLIENT_PROXY_CREATE_NONE,
cancellable,
on_client_proxy_full_finished,
task);
}
/**
* gclue_client_proxy_create_finish:
* @result: The #GAsyncResult obtained from the #GAsyncReadyCallback passed to
* gclue_client_proxy_create().
* @error: Return location for error or %NULL.
*
* Finishes an operation started with gclue_client_proxy_create().
*
* Returns: (transfer full) (type GClueClientProxy): The constructed proxy
* object or %NULL if @error is set.
*/
GClueClient *
gclue_client_proxy_create_finish (GAsyncResult *result,
GError **error)
{
g_return_val_if_fail (g_task_is_valid (result, NULL), NULL);
return g_task_propagate_pointer (G_TASK (result), error);
}
/**
* gclue_client_proxy_create_sync:
* @desktop_id: The desktop file id (the basename of the desktop file).
* @accuracy_level: The requested accuracy level as #GClueAccuracyLevel.
* @cancellable: (allow-none): A #GCancellable or %NULL.
* @error: Return location for error or %NULL.
*
* The synchronous and blocking version of #gclue_client_proxy_create().
* See also gclue_client_proxy_create_full_sync() which improves resource
* management.
*
* This function is identical to calling gclue_client_proxy_create_full_sync()
* without any flags set.
*
* Returns: (transfer full) (type GClueClientProxy): The constructed proxy
* object or %NULL if @error is set.
*/
GClueClient *
gclue_client_proxy_create_sync (const char *desktop_id,
GClueAccuracyLevel accuracy_level,
GCancellable *cancellable,
GError **error)
{
return gclue_client_proxy_create_full_sync (
desktop_id,
accuracy_level,
GCLUE_CLIENT_PROXY_CREATE_NONE,
cancellable,
error);
}
/**
* gclue_client_proxy_create_full:
* @desktop_id: The desktop file id (the basename of the desktop file).
* @accuracy_level: The requested accuracy level as #GClueAccuracyLevel.
* @flags: #GClueClientProxyCreateFlags to modify the creation.
* @cancellable: (allow-none): A #GCancellable or %NULL.
* @callback: A #GAsyncReadyCallback to call when the results are ready.
* @user_data: User data to pass to @callback.
*
* A utility function to create a #GClueClientProxy without having to deal with
* a #GClueManager.
*
* By setting the #GCLUE_CLIENT_PROXY_CREATE_AUTO_DELETE flag you can ensure
* that the client will be deleted again from the geoclue service when
* it is destroyed. This flag should be used unless you are doing explicit
* resource management.
*
* See #gclue_client_proxy_create_full_sync() for the synchronous, blocking
* version of this function.
*/
void
gclue_client_proxy_create_full (const char *desktop_id,
GClueAccuracyLevel accuracy_level,
GClueClientProxyCreateFlags flags,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GTask *task;
ClientCreateData *data;
task = g_task_new (NULL, cancellable, callback, user_data);
data = client_create_data_new (desktop_id, accuracy_level);
data = client_create_data_new (desktop_id, accuracy_level, flags);
g_task_set_task_data (task,
data,
(GDestroyNotify) client_create_data_free);
......@@ -182,19 +364,19 @@ gclue_client_proxy_create (const char *desktop_id,
}
/**
* gclue_client_proxy_create_finish:
* gclue_client_proxy_create_full_finish:
* @result: The #GAsyncResult obtained from the #GAsyncReadyCallback passed to
* gclue_client_proxy_create().
* @error: Return location for error or %NULL.
*
* Finishes an operation started with gclue_client_proxy_create().
* Finishes an operation started with gclue_client_proxy_create_full().
*
* Returns: (transfer full) (type GClueClientProxy): The constructed proxy
* object or %NULL if @error is set.
*/
GClueClient *
gclue_client_proxy_create_finish (GAsyncResult *result,
GError **error)
gclue_client_proxy_create_full_finish (GAsyncResult *result,
GError **error)
{
g_return_val_if_fail (g_task_is_valid (result, NULL), NULL);
......@@ -221,22 +403,29 @@ on_client_proxy_created (GObject *source_object,
}
/**
* gclue_client_proxy_create_sync:
* gclue_client_proxy_create_full_sync:
* @desktop_id: The desktop file id (the basename of the desktop file).
* @accuracy_level: The requested accuracy level as #GClueAccuracyLevel.
* @flags: #GClueClientProxyCreateFlags to modify the creation.
* @cancellable: (allow-none): A #GCancellable or %NULL.
* @error: Return location for error or %NULL.
*
* The synchronous and blocking version of #gclue_client_proxy_create().
* The synchronous and blocking version of #gclue_client_proxy_create_full().
*
* By setting the #GCLUE_CLIENT_PROXY_CREATE_AUTO_DELETE flag you can ensure
* that the client will be deleted again from the geoclue service when
* it is destroyed. This flag should be used unless you are doing explicit
* resource management.
*
* Returns: (transfer full) (type GClueClientProxy): The constructed proxy
* object or %NULL if @error is set.
*/
GClueClient *
gclue_client_proxy_create_sync (const char *desktop_id,
GClueAccuracyLevel accuracy_level,
GCancellable *cancellable,
GError **error)
gclue_client_proxy_create_full_sync (const char *desktop_id,
GClueAccuracyLevel accuracy_level,
GClueClientProxyCreateFlags flags,
GCancellable *cancellable,
GError **error)
{
GClueClient *client;
ClientCreateSyncData *data = g_slice_new0 (ClientCreateSyncData);
......
......@@ -42,6 +42,20 @@ GClueClient * gclue_client_proxy_create_sync (const char *desktop_id
GCancellable *cancellable,
GError **error);
void gclue_client_proxy_create_full (const char *desktop_id,
GClueAccuracyLevel accuracy_level,
GClueClientProxyCreateFlags flags,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GClueClient * gclue_client_proxy_create_full_finish (GAsyncResult *result,
GError **error);
GClueClient * gclue_client_proxy_create_full_sync (const char *desktop_id,
GClueAccuracyLevel accuracy_level,
GClueClientProxyCreateFlags flags,
GCancellable *cancellable,
GError **error);
G_END_DECLS
#endif /* #ifndef __GCLUE_HELPERS_H__*/
......@@ -49,6 +49,18 @@ typedef enum {/*< underscore_name=gclue_accuracy_level>*/
const char *gclue_accuracy_level_get_string (GClueAccuracyLevel val);
/**
* GClueClientProxyCreateFlags:
* @GCLUE_CLIENT_PROXY_CREATE_NONE: Empty set of create flags
* @GCLUE_CLIENT_PROXY_CREATE_AUTO_DELETE:
* Automatically delete the client from the server when the #GClueClient is
* destroyed. This flag should usually be set.
**/
typedef enum {/*< underscore_name=gclue_client_proxy_create_flags>*/
GCLUE_CLIENT_PROXY_CREATE_NONE = 0,
GCLUE_CLIENT_PROXY_CREATE_AUTO_DELETE = 1 << 0,
} GClueClientProxyCreateFlags;
G_END_DECLS
#endif /* GCLUE_ENUMS_H */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment