[evolution-data-server] [Camel] Introduce camel_operation_new_proxy()
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server] [Camel] Introduce camel_operation_new_proxy()
- Date: Tue, 29 Nov 2016 09:14:37 +0000 (UTC)
commit 5297c58cdad4a041c4b0a443d901f0aeca3382c3
Author: Milan Crha <mcrha redhat com>
Date: Tue Nov 29 10:07:41 2016 +0100
[Camel] Introduce camel_operation_new_proxy()
It creates a new CamelOperation, which listens for 'cancelled' signal
of the original operation, but not the other way around. That allows
to cancel the operation without influencing the passed-in cancellable.
Other CamelOperation changes (push/pop message and progress) are also
passed to the original cancellable, being it a CamelOperation as well.
That's because there could happen that for example CamelService's
connect and disconnect do cancel the passed-in cancellable on its own,
but that's wrong, because it can cancel any larger operation to which
it belongs, like when going online or offline from UI, on user's request.
src/camel/camel-operation.c | 86 ++++++++++++++++++--
src/camel/camel-operation.h | 1 +
src/camel/camel-service.c | 10 +--
.../providers/imapx/camel-imapx-conn-manager.c | 6 +-
4 files changed, 84 insertions(+), 19 deletions(-)
---
diff --git a/src/camel/camel-operation.c b/src/camel/camel-operation.c
index b160c90..7cd5d3b 100644
--- a/src/camel/camel-operation.c
+++ b/src/camel/camel-operation.c
@@ -46,6 +46,8 @@ struct _StatusNode {
struct _CamelOperationPrivate {
GQueue status_stack;
+ GCancellable *proxying;
+ gulong proxying_handler_id;
};
enum {
@@ -137,6 +139,15 @@ operation_emit_status_cb (gpointer user_data)
}
static void
+proxying_cancellable_cancelled_cb (GCancellable *cancellable,
+ GCancellable *operation)
+{
+ g_return_if_fail (CAMEL_IS_OPERATION (operation));
+
+ g_cancellable_cancel (operation);
+}
+
+static void
operation_finalize (GObject *object)
{
CamelOperationPrivate *priv;
@@ -145,6 +156,13 @@ operation_finalize (GObject *object)
LOCK ();
+ if (priv->proxying && priv->proxying_handler_id) {
+ g_cancellable_disconnect (priv->proxying, priv->proxying_handler_id);
+ priv->proxying_handler_id = 0;
+ }
+
+ g_clear_object (&priv->proxying);
+
g_queue_remove (&operation_list, object);
/* Because each StatusNode holds a reference to its
@@ -211,6 +229,8 @@ camel_operation_init (CamelOperation *operation)
operation->priv = CAMEL_OPERATION_GET_PRIVATE (operation);
g_queue_init (&operation->priv->status_stack);
+ operation->priv->proxying = NULL;
+ operation->priv->proxying_handler_id = 0;
LOCK ();
g_queue_push_tail (&operation_list, operation);
@@ -226,7 +246,7 @@ camel_operation_init (CamelOperation *operation)
* operations and to obtain notification messages of the internal
* status of messages.
*
- * Returns: A new operation handle.
+ * Returns: (transfer full): A new operation handle.
**/
GCancellable *
camel_operation_new (void)
@@ -235,6 +255,50 @@ camel_operation_new (void)
}
/**
+ * camel_operation_new_proxy:
+ * @cancellable: (nullable): a #GCancellable to proxy
+ *
+ * Proxies the @cancellable in a way that if it is cancelled,
+ * then the returned cancellable is also cancelled, but when
+ * the returned cancellable is cancelled, then it doesn't
+ * influence the original cancellable. Other CamelOperation
+ * actions being done on the returned cancellable are also
+ * propagated to the @cancellable.
+ *
+ * The passed-in @cancellable can be %NULL, in which case
+ * a plain CamelOperation is returned.
+ *
+ * This is useful when some operation can be cancelled from
+ * elsewhere (like by a user), but also by the code on its own,
+ * when it doesn't make sense to cancel also any larger operation
+ * to which the passed-in cancellable belongs.
+ *
+ * Returns: (transfer full): A new operation handle, proxying @cancellable.
+ *
+ * Since: 3.24
+ **/
+GCancellable *
+camel_operation_new_proxy (GCancellable *cancellable)
+{
+ GCancellable *operation;
+ CamelOperationPrivate *priv;
+
+ operation = camel_operation_new ();
+
+ if (!G_IS_CANCELLABLE (cancellable))
+ return operation;
+
+ priv = CAMEL_OPERATION_GET_PRIVATE (operation);
+ g_return_val_if_fail (priv != NULL, operation);
+
+ priv->proxying = g_object_ref (cancellable);
+ priv->proxying_handler_id = g_cancellable_connect (cancellable,
+ G_CALLBACK (proxying_cancellable_cancelled_cb), operation, NULL);
+
+ return operation;
+}
+
+/**
* camel_operation_cancel_all:
*
* Cancel all outstanding operations.
@@ -294,11 +358,14 @@ camel_operation_push_message (GCancellable *cancellable,
message = g_strdup_vprintf (format, ap);
va_end (ap);
+ operation = CAMEL_OPERATION (cancellable);
+
g_signal_emit (cancellable, signals[PUSH_MESSAGE], 0, message);
- LOCK ();
+ if (operation->priv->proxying)
+ camel_operation_push_message (operation->priv->proxying, "%s", message);
- operation = CAMEL_OPERATION (cancellable);
+ LOCK ();
node = status_node_new ();
node->message = message; /* takes ownership */
@@ -350,11 +417,15 @@ camel_operation_pop_message (GCancellable *cancellable)
g_return_if_fail (CAMEL_IS_OPERATION (cancellable));
+ operation = CAMEL_OPERATION (cancellable);
+
g_signal_emit (cancellable, signals[POP_MESSAGE], 0);
+ if (operation->priv->proxying)
+ camel_operation_pop_message (operation->priv->proxying);
+
LOCK ();
- operation = CAMEL_OPERATION (cancellable);
node = g_queue_pop_head (&operation->priv->status_stack);
if (node != NULL) {
@@ -411,11 +482,15 @@ camel_operation_progress (GCancellable *cancellable,
g_return_if_fail (CAMEL_IS_OPERATION (cancellable));
+ operation = CAMEL_OPERATION (cancellable);
+
g_signal_emit (cancellable, signals[PROGRESS], 0, percent);
+ if (operation->priv->proxying)
+ camel_operation_progress (operation->priv->proxying, percent);
+
LOCK ();
- operation = CAMEL_OPERATION (cancellable);
node = g_queue_peek_head (&operation->priv->status_stack);
if (node != NULL) {
@@ -436,4 +511,3 @@ camel_operation_progress (GCancellable *cancellable,
UNLOCK ();
}
-
diff --git a/src/camel/camel-operation.h b/src/camel/camel-operation.h
index 1452470..691edfd 100644
--- a/src/camel/camel-operation.h
+++ b/src/camel/camel-operation.h
@@ -68,6 +68,7 @@ struct _CamelOperationClass {
GType camel_operation_get_type (void);
GCancellable * camel_operation_new (void);
+GCancellable * camel_operation_new_proxy (GCancellable *cancellable);
void camel_operation_cancel_all (void);
/* Since Camel methods pass around GCancellable pointers instead of
diff --git a/src/camel/camel-service.c b/src/camel/camel-service.c
index e53f7d1..4e202dc 100644
--- a/src/camel/camel-service.c
+++ b/src/camel/camel-service.c
@@ -1810,10 +1810,7 @@ camel_service_connect (CamelService *service,
g_return_if_fail (CAMEL_IS_SERVICE (service));
- if (cancellable)
- g_object_ref (cancellable);
- else
- cancellable = g_cancellable_new ();
+ cancellable = camel_operation_new_proxy (cancellable);
task = g_task_new (service, cancellable, callback, user_data);
g_task_set_source_tag (task, camel_service_connect);
@@ -1982,10 +1979,7 @@ camel_service_disconnect (CamelService *service,
g_return_if_fail (CAMEL_IS_SERVICE (service));
- if (cancellable)
- g_object_ref (cancellable);
- else
- cancellable = g_cancellable_new ();
+ cancellable = camel_operation_new_proxy (cancellable);
task = g_task_new (service, cancellable, callback, user_data);
g_task_set_source_tag (task, camel_service_disconnect);
diff --git a/src/camel/providers/imapx/camel-imapx-conn-manager.c
b/src/camel/providers/imapx/camel-imapx-conn-manager.c
index e82de56..8eea37b 100644
--- a/src/camel/providers/imapx/camel-imapx-conn-manager.c
+++ b/src/camel/providers/imapx/camel-imapx-conn-manager.c
@@ -857,11 +857,7 @@ camel_imapx_conn_manager_ref_connection (CamelIMAPXConnManager *conn_man,
session && camel_session_get_online (session)) {
g_mutex_lock (&conn_man->priv->pending_connections_lock);
- if (cancellable) {
- g_object_ref (cancellable);
- } else {
- cancellable = g_cancellable_new ();
- }
+ cancellable = camel_operation_new_proxy (cancellable);
conn_man->priv->pending_connections = g_slist_prepend (conn_man->priv->pending_connections,
cancellable);
g_mutex_unlock (&conn_man->priv->pending_connections_lock);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]