[evolution-data-server] Recast CamelOperation as a GCancellable subclass.
- From: Matthew Barnes <mbarnes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server] Recast CamelOperation as a GCancellable subclass.
- Date: Wed, 15 Sep 2010 03:47:04 +0000 (UTC)
commit b79c2433782e07bba3024d10779f36e28b8070ff
Author: Matthew Barnes <mbarnes redhat com>
Date: Tue Sep 14 23:04:18 2010 -0400
Recast CamelOperation as a GCancellable subclass.
CamelOperation is now a subclass of GCancellable. Instead of taking a
status update callback at creation time, it now emits a "status" signal
from an idle callback.
Several functions have been modified or removed:
camel_operation_new() No longer takes any arguments.
camel_operation_unregister() No longer takes any arguments
(and never used it when it did).
camel_operation_ref() Gone. Use g_object_ref() instead.
camel_operation_unref() Gone. Use g_object_unref() instead.
camel_operation_mute() Gone. Disconnect your signal handler.
camel/camel-marshal.list | 1 +
camel/camel-operation.c | 748 +++++++++-----------
camel/camel-operation.h | 88 ++-
camel/camel-service.c | 12 +-
camel/camel-session.c | 10 +-
camel/providers/imapx/camel-imapx-server.c | 12 +-
configure.ac | 2 +-
docs/reference/camel/camel-sections.txt | 5 -
.../reference/camel/tmpl/camel-cipher-context.sgml | 4 +
docs/reference/camel/tmpl/camel-operation.sgml | 66 +--
docs/reference/camel/tmpl/camel-unused.sgml | 39 +
11 files changed, 483 insertions(+), 504 deletions(-)
---
diff --git a/camel/camel-marshal.list b/camel/camel-marshal.list
index b02c3c0..daee534 100644
--- a/camel/camel-marshal.list
+++ b/camel/camel-marshal.list
@@ -1 +1,2 @@
+NONE:STRING,INT
NONE:STRING,POINTER
diff --git a/camel/camel-operation.c b/camel/camel-operation.c
index 8a5738a..028ee29 100644
--- a/camel/camel-operation.c
+++ b/camel/camel-operation.c
@@ -1,28 +1,23 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
- * Authors: Michael Zucchi <NotZed ximian com>
+ * camel-operation.c
*
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA.
*/
-#ifdef HAVE_CONFIG_H
#include <config.h>
-#endif
#include <stdio.h>
#include <unistd.h>
@@ -32,96 +27,218 @@
#include <nspr.h>
#endif
-#include "camel-list-utils.h"
-#include "camel-operation.h"
+#include "camel-marshal.h"
#include "camel-msgport.h"
+#include "camel-operation.h"
-#define d(x)
+#define CAMEL_OPERATION_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), CAMEL_TYPE_OPERATION, CamelOperationPrivate))
-/* ********************************************************************** */
+typedef struct _StatusNode StatusNode;
-struct _status_stack {
- guint32 flags;
+struct _StatusNode {
+ gboolean transient;
gchar *msg;
- gint pc; /* last pc reported */
- guint stamp; /* last stamp reported */
+ gint pc; /* last percentage reported */
+ guint stamp; /* last time stamp reported */
};
-struct _CamelOperation {
- struct _CamelOperation *next;
- struct _CamelOperation *prev;
+struct _CamelOperationPrivate {
+ guint status_idle_id;
- GThread *thread; /* running thread */
- guint32 flags; /* cancelled ? */
- gint blocked; /* cancellation blocked depth */
- gint refcount;
+ /* For the next 'status' signal. */
+ gchar *status_msg;
+ gint status_pc;
- CamelOperationStatusFunc status;
- gpointer status_data;
guint status_update;
- /* stack of status messages (struct _status_stack *) */
- GSList *status_stack;
- struct _status_stack *lastreport;
+ GQueue status_stack;
CamelMsgPort *cancel_port;
- gint cancel_fd;
#ifdef CAMEL_HAVE_NSS
PRFileDesc *cancel_prfd;
#endif
};
-#define CAMEL_OPERATION_CANCELLED (1<<0)
-#define CAMEL_OPERATION_TRANSIENT (1<<1)
+enum {
+ STATUS,
+ LAST_SIGNAL
+};
/* Delay before a transient operation has any effect on the status */
#define CAMEL_OPERATION_TRANSIENT_DELAY (5)
-static GStaticMutex operation_lock = G_STATIC_MUTEX_INIT;
-#define LOCK() g_static_mutex_lock(&operation_lock)
-#define UNLOCK() g_static_mutex_unlock(&operation_lock)
+static GStaticRecMutex operation_lock = G_STATIC_REC_MUTEX_INIT;
+#define LOCK() g_static_rec_mutex_lock (&operation_lock)
+#define UNLOCK() g_static_rec_mutex_unlock (&operation_lock)
-static guint stamp (void);
-static CamelDList operation_list = CAMEL_DLIST_INITIALISER (operation_list);
+static GQueue operation_list = G_QUEUE_INIT;
static GStaticPrivate operation_key = G_STATIC_PRIVATE_INIT;
-typedef struct _CamelOperationMsg {
- CamelMsg msg;
-} CamelOperationMsg;
+static guint signals[LAST_SIGNAL];
+
+G_DEFINE_TYPE (CamelOperation, camel_operation, G_TYPE_CANCELLABLE)
+
+static StatusNode *
+status_node_new (CamelOperation *operation)
+{
+ StatusNode *node;
+
+ node = g_slice_new0 (StatusNode);
+ g_queue_push_head (&operation->priv->status_stack, node);
+
+ return node;
+}
+
+static void
+status_node_free (StatusNode *node)
+{
+ g_free (node->msg);
+ g_slice_free (StatusNode, node);
+}
static CamelOperation *
co_getcc (void)
{
- return (CamelOperation *)g_static_private_get (&operation_key);
+ return (CamelOperation *) g_static_private_get (&operation_key);
+}
+
+static guint
+stamp (void)
+{
+ GTimeVal tv;
+
+ g_get_current_time (&tv);
+ /* update 4 times/second */
+ return (tv.tv_sec * 4) + tv.tv_usec / (1000000/4);
+}
+
+static gboolean
+operation_idle_cb (CamelOperation *operation)
+{
+ gchar *msg;
+ gint pc;
+
+ LOCK ();
+
+ msg = operation->priv->status_msg;
+ operation->priv->status_msg = NULL;
+
+ pc = operation->priv->status_pc;
+
+ operation->priv->status_idle_id = 0;
+
+ UNLOCK ();
+
+ if (msg != NULL) {
+ g_signal_emit (operation, signals[STATUS], 0, msg, pc);
+ g_free (msg);
+ }
+
+ return FALSE;
}
static void
-clear_status_stack (CamelOperation *cc, gboolean claim_not_empty)
+operation_queue_status_update (CamelOperation *operation,
+ StatusNode *node)
{
- g_return_if_fail (cc != NULL);
+ LOCK ();
+
+ if (operation->priv->status_idle_id == 0)
+ operation->priv->status_idle_id = g_idle_add (
+ (GSourceFunc) operation_idle_cb, operation);
- if (claim_not_empty && cc->status_stack != NULL)
- g_debug ("%p CamelOperation status stack non-empty", cc);
+ g_free (operation->priv->status_msg);
+ operation->priv->status_msg = g_strdup (node->msg);
- while (cc->status_stack != NULL) {
- struct _status_stack *status;
+ operation->priv->status_pc = node->pc;
- status = cc->status_stack->data;
- if (claim_not_empty && status->msg != NULL)
- g_debug ("%p Status was \"%s\"", cc, status->msg);
- g_free (status->msg);
- g_free (status);
+ UNLOCK ();
+}
+
+static void
+operation_flush_msgport (CamelOperation *operation)
+{
+ CamelOperationPrivate *priv = operation->priv;
+ CamelMsg *msg;
- cc->status_stack = g_slist_delete_link (
- cc->status_stack, cc->status_stack);
+ LOCK ();
+
+ while ((msg = camel_msgport_try_pop (priv->cancel_port)) != NULL)
+ g_free (msg);
+
+ UNLOCK ();
+}
+
+static void
+operation_finalize (GObject *object)
+{
+ CamelOperationPrivate *priv;
+ StatusNode *node;
+
+ priv = CAMEL_OPERATION_GET_PRIVATE (object);
+
+ LOCK ();
+
+ g_queue_remove (&operation_list, object);
+
+ if (priv->status_idle_id > 0)
+ g_source_remove (priv->status_idle_id);
+
+ operation_flush_msgport (CAMEL_OPERATION (object));
+ camel_msgport_destroy (priv->cancel_port);
+
+ while ((node = g_queue_pop_head (&priv->status_stack)) != NULL) {
+ g_warning (
+ "CamelOperation status stack non-empty: %s",
+ node->msg);
+ status_node_free (node);
}
+
+ UNLOCK ();
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (camel_operation_parent_class)->finalize (object);
+}
+
+static void
+camel_operation_class_init (CamelOperationClass *class)
+{
+ GObjectClass *object_class;
+
+ g_type_class_add_private (class, sizeof (CamelOperationPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->finalize = operation_finalize;
+
+ signals[STATUS] = g_signal_new (
+ "status",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (CamelOperationClass, status),
+ NULL, NULL,
+ camel_marshal_VOID__STRING_INT,
+ G_TYPE_NONE, 2,
+ G_TYPE_STRING,
+ G_TYPE_INT);
+}
+
+static void
+camel_operation_init (CamelOperation *operation)
+{
+ operation->priv = CAMEL_OPERATION_GET_PRIVATE (operation);
+
+ g_queue_init (&operation->priv->status_stack);
+ operation->priv->cancel_port = camel_msgport_new ();
+
+ LOCK ();
+ g_queue_push_tail (&operation_list, operation);
+ UNLOCK ();
}
/**
* camel_operation_new:
- * @status: Callback for receiving status messages. This will always
- * be called with an internal lock held.
- * @status_data: User data.
*
* Create a new camel operation handle. Camel operation handles can
* be used in a multithreaded application (or a single operation
@@ -132,42 +249,9 @@ clear_status_stack (CamelOperation *cc, gboolean claim_not_empty)
* Returns: A new operation handle.
**/
CamelOperation *
-camel_operation_new (CamelOperationStatusFunc status, gpointer status_data)
-{
- CamelOperation *cc;
-
- cc = g_malloc0 (sizeof (*cc));
-
- cc->flags = 0;
- cc->blocked = 0;
- cc->refcount = 1;
- cc->status = status;
- cc->status_data = status_data;
- cc->cancel_port = camel_msgport_new ();
- cc->cancel_fd = -1;
-
- LOCK ();
- camel_dlist_addtail (&operation_list, (CamelDListNode *)cc);
- UNLOCK ();
-
- return cc;
-}
-
-/**
- * camel_operation_mute:
- * @cc:
- *
- * mutes a camel operation permanently. from this point on you will never
- * receive operation updates, even if more are sent.
- **/
-void
-camel_operation_mute (CamelOperation *cc)
+camel_operation_new (void)
{
- LOCK ();
- cc->status = NULL;
- cc->status_data = NULL;
- clear_status_stack (cc, FALSE);
- UNLOCK ();
+ return g_object_new (CAMEL_TYPE_OPERATION, NULL);
}
/**
@@ -178,102 +262,63 @@ camel_operation_mute (CamelOperation *cc)
CamelOperation *
camel_operation_registered (void)
{
- CamelOperation *cc = co_getcc ();
+ CamelOperation *operation = co_getcc ();
- if (cc)
- camel_operation_ref (cc);
+ if (operation != NULL)
+ g_object_ref (operation);
- return cc;
+ return operation;
}
/**
- * camel_operation_ref:
- * @cc: operation context
+ * camel_operation_cancel:
+ * @operation: a #CamelOperation
*
- * Add a reference to the CamelOperation @cc.
+ * Cancel a given operation. If @operation is %NULL then all outstanding
+ * operations are cancelled.
**/
void
-camel_operation_ref (CamelOperation *cc)
+camel_operation_cancel (CamelOperation *operation)
{
- g_assert (cc->refcount > 0);
-
- LOCK ();
- cc->refcount++;
- UNLOCK ();
-}
+ if (operation != NULL) {
+ CamelMsg *msg;
-/**
- * camel_operation_unref:
- * @cc: operation context
- *
- * Unref and potentially free @cc.
- **/
-void
-camel_operation_unref (CamelOperation *cc)
-{
- g_assert (cc->refcount > 0);
+ g_return_if_fail (CAMEL_IS_OPERATION (operation));
- LOCK ();
- if (cc->refcount == 1) {
- CamelOperationMsg *msg;
+ LOCK ();
- camel_dlist_remove ((CamelDListNode *)cc);
+ msg = g_malloc0 (sizeof (CamelMsg));
+ camel_msgport_push (operation->priv->cancel_port, msg);
- while ((msg = (CamelOperationMsg *)camel_msgport_try_pop (cc->cancel_port)))
- g_free (msg);
+ UNLOCK ();
- camel_msgport_destroy (cc->cancel_port);
+ g_cancellable_cancel (G_CANCELLABLE (operation));
- clear_status_stack (cc, TRUE);
- g_free (cc);
} else {
- cc->refcount--;
- }
- UNLOCK ();
-}
+ GList *link;
-/**
- * camel_operation_cancel:
- * @cc: operation context
- *
- * Cancel a given operation. If @cc is NULL then all outstanding
- * operations are cancelled.
- **/
-void
-camel_operation_cancel (CamelOperation *cc)
-{
- CamelOperationMsg *msg;
+ LOCK ();
- LOCK ();
+ link = g_queue_peek_head_link (&operation_list);
+
+ while (link != NULL) {
+ operation = link->data;
+
+ if (operation != NULL)
+ camel_operation_cancel (operation);
- if (cc == NULL) {
- CamelOperation *cn;
-
- cc = (CamelOperation *)operation_list.head;
- cn = cc->next;
- while (cn) {
- cc->flags |= CAMEL_OPERATION_CANCELLED;
- msg = g_malloc0 (sizeof (*msg));
- camel_msgport_push (cc->cancel_port, (CamelMsg *)msg);
- cc = cn;
- cn = cn->next;
+ link = g_list_next (link);
}
- } else if ((cc->flags & CAMEL_OPERATION_CANCELLED) == 0) {
- d(printf("cancelling thread %d\n", cc->id));
- cc->flags |= CAMEL_OPERATION_CANCELLED;
- msg = g_malloc0 (sizeof (*msg));
- camel_msgport_push (cc->cancel_port, (CamelMsg *)msg);
+ UNLOCK ();
}
-
- UNLOCK ();
}
/**
* camel_operation_uncancel:
- * @cc: operation context
+ * @operation: a #CamelOperation
*
- * Uncancel a cancelled operation. If @cc is NULL then the current
+ * Uncancel a cancelled operation. If @operation is %NULL then the current
* operation is uncancelled.
*
* This is useful, if e.g. you need to do some cleaning up where a
@@ -281,96 +326,78 @@ camel_operation_cancel (CamelOperation *cc)
* processing.
**/
void
-camel_operation_uncancel (CamelOperation *cc)
+camel_operation_uncancel (CamelOperation *operation)
{
- if (cc == NULL)
- cc = co_getcc ();
-
- if (cc) {
- CamelOperationMsg *msg;
-
- LOCK ();
- while ((msg = (CamelOperationMsg *)camel_msgport_try_pop (cc->cancel_port)))
- g_free (msg);
+ if (operation == NULL)
+ operation = co_getcc ();
- cc->flags &= ~CAMEL_OPERATION_CANCELLED;
- UNLOCK ();
+ if (operation != NULL) {
+ g_return_if_fail (CAMEL_IS_OPERATION (operation));
+ operation_flush_msgport (operation);
+ g_cancellable_reset (G_CANCELLABLE (operation));
}
}
/**
* camel_operation_register:
- * @cc: operation context
+ * @operation: a #CamelOperation
*
- * Register a thread or the main thread for cancellation through @cc.
- * If @cc is NULL, then a new cancellation is created for this thread.
+ * Register a thread or the main thread for cancellation through @operation.
+ * If @operation is NULL, then a new cancellation is created for this thread.
*
- * All calls to operation_register() should save their value and call
- * operation_register again with that, to automatically stack
- * registrations.
+ * All calls to camel_operation_register() should save their value and
+ * call * camel_operation_register() again with that, to automatically
+ * stack * registrations.
*
* Returns: the previously registered operatoin.
- *
**/
CamelOperation *
-camel_operation_register (CamelOperation *cc)
+camel_operation_register (CamelOperation *operation)
{
- CamelOperation *oldcc = co_getcc ();
+ CamelOperation *old_operation = co_getcc ();
- g_static_private_set (&operation_key, cc, NULL);
+ g_static_private_set (&operation_key, operation, NULL);
- return oldcc;
+ return old_operation;
}
/**
* camel_operation_unregister:
- * @cc: operation context
*
* Unregister the current thread for all cancellations.
**/
void
-camel_operation_unregister (CamelOperation *cc)
+camel_operation_unregister (void)
{
g_static_private_set (&operation_key, NULL, NULL);
}
/**
* camel_operation_cancel_check:
- * @cc: operation context
+ * @operation: a #CamelOperation
*
- * Check if cancellation has been applied to @cc. If @cc is NULL,
- * then the CamelOperation registered for the current thread is used.
+ * Check if cancellation has been applied to @operation. If @operation is
+ * %NULL, then the #CamelOperation registered for the current thread is used.
*
- * Returns: TRUE if the operation has been cancelled.
+ * Returns: %TRUE if the operation has been cancelled
**/
gboolean
-camel_operation_cancel_check (CamelOperation *cc)
+camel_operation_cancel_check (CamelOperation *operation)
{
- CamelOperationMsg *msg;
- gint cancelled;
+ gboolean cancelled;
- d(printf("checking for cancel in thread %p\n", g_thread_self()));
+ if (operation == NULL)
+ operation = co_getcc ();
- if (cc == NULL)
- cc = co_getcc ();
+ if (operation == NULL)
+ return FALSE;
LOCK ();
- if (cc == NULL || cc->blocked > 0) {
- d(printf("ahah! cancellation is blocked\n"));
- cancelled = FALSE;
- } else if (cc->flags & CAMEL_OPERATION_CANCELLED) {
- d(printf("previously cancelled\n"));
- cancelled = TRUE;
- } else if ((msg = (CamelOperationMsg *)camel_msgport_try_pop (cc->cancel_port))) {
- d(printf("Got cancellation message\n"));
- do {
- g_free (msg);
- } while ((msg = (CamelOperationMsg *)camel_msgport_try_pop (cc->cancel_port)));
- cc->flags |= CAMEL_OPERATION_CANCELLED;
- cancelled = TRUE;
- } else
- cancelled = FALSE;
+ cancelled = g_cancellable_is_cancelled (G_CANCELLABLE (operation));
+
+ if (cancelled)
+ operation_flush_msgport (operation);
UNLOCK ();
@@ -379,67 +406,64 @@ camel_operation_cancel_check (CamelOperation *cc)
/**
* camel_operation_cancel_fd:
- * @cc: operation context
+ * @operation: a #CamelOperation
*
* Retrieve a file descriptor that can be waited on (select, or poll)
* for read, to asynchronously detect cancellation.
*
- * Returns: The fd, or -1 if cancellation is not available
- * (blocked, or has not been registered for this thread).
+ * Returns: The fd, or -1 if cancellation has not been registered
+ * for this thread.
**/
gint
-camel_operation_cancel_fd (CamelOperation *cc)
+camel_operation_cancel_fd (CamelOperation *operation)
{
- if (cc == NULL)
- cc = co_getcc ();
+ if (operation == NULL)
+ operation = co_getcc ();
- if (cc == NULL || cc->blocked)
+ if (operation == NULL)
return -1;
- LOCK ();
-
- if (cc->cancel_fd == -1)
- cc->cancel_fd = camel_msgport_fd (cc->cancel_port);
-
- UNLOCK ();
-
- return cc->cancel_fd;
+ return g_cancellable_get_fd (G_CANCELLABLE (operation));
}
#ifdef CAMEL_HAVE_NSS
/**
* camel_operation_cancel_prfd:
- * @cc: operation context
+ * @operation: a #CamelOperation
*
* Retrieve a file descriptor that can be waited on (select, or poll)
* for read, to asynchronously detect cancellation.
*
- * Returns: The fd, or NULL if cancellation is not available
- * (blocked, or has not been registered for this thread).
+ * Returns: The fd, or %NULL if cancellation has not been registered
+ * for this thread.
**/
PRFileDesc *
-camel_operation_cancel_prfd (CamelOperation *cc)
+camel_operation_cancel_prfd (CamelOperation *operation)
{
- if (cc == NULL)
- cc = co_getcc ();
+ CamelOperationPrivate *priv;
+
+ if (operation == NULL)
+ operation = co_getcc ();
- if (cc == NULL || cc->blocked)
+ if (operation == NULL)
return NULL;
LOCK ();
- if (cc->cancel_prfd == NULL)
- cc->cancel_prfd = camel_msgport_prfd (cc->cancel_port);
+ priv = operation->priv;
+
+ if (priv->cancel_prfd == NULL)
+ priv->cancel_prfd = camel_msgport_prfd (priv->cancel_port);
UNLOCK ();
- return cc->cancel_prfd;
+ return priv->cancel_prfd;
}
#endif /* CAMEL_HAVE_NSS */
/**
* camel_operation_start:
- * @cc: operation context
+ * @operation: a #CamelOperation
* @what: action being performed (printf-style format string)
* @Varargs: varargs
*
@@ -447,51 +471,41 @@ camel_operation_cancel_prfd (CamelOperation *cc)
* similar end operations.
**/
void
-camel_operation_start (CamelOperation *cc, const gchar *what, ...)
+camel_operation_start (CamelOperation *operation,
+ const gchar *what, ...)
{
+ const guint signal_id = signals[STATUS];
+ StatusNode *node;
va_list ap;
- gchar *msg;
- struct _status_stack *s;
- CamelOperationStatusFunc status_func;
- gpointer status_data;
- if (cc == NULL)
- cc = co_getcc ();
+ if (operation == NULL)
+ operation = co_getcc ();
- if (cc == NULL)
+ if (operation == NULL)
+ return;
+
+ if (!g_signal_has_handler_pending (operation, signal_id, 0, TRUE))
return;
LOCK ();
- if (cc->status == NULL) {
- UNLOCK ();
- return;
- }
+ operation->priv->status_update = 0;
va_start (ap, what);
- msg = g_strdup_vprintf (what, ap);
- va_end (ap);
- cc->status_update = 0;
- s = g_malloc0 (sizeof (*s));
- s->msg = msg;
- s->flags = 0;
- cc->lastreport = s;
- cc->status_stack = g_slist_prepend (cc->status_stack, s);
- /* This avoids a race with camel_operation_mute() after we unlock. */
- status_func = cc->status;
- status_data = cc->status_data;
+ node = status_node_new (operation);
+ node->msg = g_strdup_vprintf (what, ap);
- UNLOCK ();
+ va_end (ap);
- status_func (cc, msg, CAMEL_OPERATION_START, status_data);
+ operation_queue_status_update (operation, node);
- d(printf("start '%s'\n", msg, pc));
+ UNLOCK ();
}
/**
* camel_operation_start_transient:
- * @cc: operation context
+ * @operation: a #CamelOperation
* @what: printf-style format string describing the action being performed
* @Varargs: varargs
*
@@ -500,193 +514,129 @@ camel_operation_start (CamelOperation *cc, const gchar *what, ...)
* previous state when finished.
**/
void
-camel_operation_start_transient (CamelOperation *cc, const gchar *what, ...)
+camel_operation_start_transient (CamelOperation *operation,
+ const gchar *what, ...)
{
- if (cc == NULL)
- cc = co_getcc ();
+ StatusNode *node;
+ va_list ap;
+
+ if (operation == NULL)
+ operation = co_getcc ();
- if (cc == NULL)
+ if (operation == NULL)
return;
LOCK ();
- if (cc->status == NULL) {
- UNLOCK ();
- return;
- }
+ operation->priv->status_update = 0;
- cc->status_update = 0;
- if (cc->status) {
- va_list ap;
- gchar *msg;
- struct _status_stack *s;
-
- va_start (ap, what);
- msg = g_strdup_vprintf (what, ap);
- va_end (ap);
- s = g_malloc0 (sizeof (*s));
- s->msg = msg;
- s->flags = CAMEL_OPERATION_TRANSIENT;
- s->stamp = stamp ();
- cc->status_stack = g_slist_prepend (cc->status_stack, s);
- }
- d(printf("start '%s'\n", msg, pc));
+ va_start (ap, what);
- UNLOCK ();
-}
+ node = status_node_new (operation);
+ node->msg = g_strdup_vprintf (what, ap);
+ node->stamp = stamp ();
+ node->transient = TRUE;
-static guint stamp (void)
-{
- GTimeVal tv;
+ va_end (ap);
- g_get_current_time (&tv);
- /* update 4 times/second */
- return (tv.tv_sec * 4) + tv.tv_usec / (1000000/4);
+ UNLOCK ();
}
/**
* camel_operation_progress:
- * @cc: Operation to report to.
+ * @operation: a #CamelOperation
* @pc: Percent complete, 0 to 100.
*
- * Report progress on the current operation. If @cc is NULL, then the
- * currently registered operation is used. @pc reports the current
+ * Report progress on the current operation. If @operation is %NULL, then
+ * the currently registered operation is used. @pc reports the current
* percentage of completion, which should be in the range of 0 to 100.
*
* If the total percentage is not know, then use
* camel_operation_progress_count().
**/
void
-camel_operation_progress (CamelOperation *cc, gint pc)
+camel_operation_progress (CamelOperation *operation,
+ gint pc)
{
+ const guint signal_id = signals[STATUS];
+ CamelOperationPrivate *priv;
guint now;
- struct _status_stack *s;
- gchar *msg = NULL;
- CamelOperationStatusFunc status_func;
- gpointer status_data;
+ StatusNode *node;
+
+ if (operation == NULL)
+ operation = co_getcc ();
- if (cc == NULL)
- cc = co_getcc ();
+ if (operation == NULL)
+ return;
- if (cc == NULL)
+ if (!g_signal_has_handler_pending (operation, signal_id, 0, TRUE))
return;
LOCK ();
- if (cc->status == NULL || cc->status_stack == NULL) {
+ priv = operation->priv;
+
+ if (g_queue_is_empty (&priv->status_stack)) {
UNLOCK ();
return;
}
- s = cc->status_stack->data;
- s->pc = pc;
+ node = g_queue_peek_head (&priv->status_stack);
+ node->pc = pc;
/* Transient messages dont start updating till 4 seconds after
they started, then they update every second */
now = stamp ();
- if (cc->status_update == now) {
- UNLOCK ();
- return;
- } else if (s->flags & CAMEL_OPERATION_TRANSIENT) {
- if (s->stamp + CAMEL_OPERATION_TRANSIENT_DELAY > now) {
- UNLOCK ();
- return;
+ if (priv->status_update == now) {
+ operation = NULL;
+ } else if (node->transient) {
+ if (node->stamp + CAMEL_OPERATION_TRANSIENT_DELAY > now) {
+ operation = NULL;
} else {
- cc->status_update = now;
- cc->lastreport = s;
- msg = g_strdup (s->msg);
+ priv->status_update = now;
}
} else {
- s->stamp = cc->status_update = now;
- cc->lastreport = s;
- msg = g_strdup (s->msg);
+ node->stamp = priv->status_update = now;
}
- /* This avoids a race with camel_operation_mute() after we unlock. */
- status_func = cc->status;
- status_data = cc->status_data;
+ if (operation != NULL)
+ operation_queue_status_update (operation, node);
UNLOCK ();
-
- status_func (cc, msg, pc, status_data);
-
- g_free (msg);
}
/**
* camel_operation_end:
- * @cc: operation context
+ * @operation: a #CamelOperation
*
- * Report the end of an operation. If @cc is NULL, then the currently
- * registered operation is notified.
+ * Report the end of an operation. If @operation is %NULL, then the
+ * currently registered operation is notified.
**/
void
-camel_operation_end (CamelOperation *cc)
+camel_operation_end (CamelOperation *operation)
{
- struct _status_stack *s, *p;
- guint now;
- gchar *msg = NULL;
- gint pc = 0;
- CamelOperationStatusFunc status_func;
- gpointer status_data;
+ const guint signal_id = signals[STATUS];
+ GQueue *status_stack;
+ StatusNode *node;
+
+ if (operation == NULL)
+ operation = co_getcc ();
- if (cc == NULL)
- cc = co_getcc ();
+ if (operation == NULL)
+ return;
- if (cc == NULL)
+ if (!g_signal_has_handler_pending (operation, signal_id, 0, TRUE))
return;
LOCK ();
- if (cc->status == NULL || cc->status_stack == NULL) {
- UNLOCK ();
- return;
- }
+ status_stack = &operation->priv->status_stack;
- /* so what we do here is this. If the operation that just
- * ended was transient, see if we have any other transient
- * messages that haven't been updated yet above us, otherwise,
- * re-update as a non-transient at the last reported pc */
- now = stamp ();
- s = cc->status_stack->data;
- if (s->flags & CAMEL_OPERATION_TRANSIENT) {
- if (cc->lastreport == s) {
- GSList *l = cc->status_stack->next;
- while (l) {
- p = l->data;
- if (p->flags & CAMEL_OPERATION_TRANSIENT) {
- if (p->stamp + CAMEL_OPERATION_TRANSIENT_DELAY < now) {
- msg = g_strdup (p->msg);
- pc = p->pc;
- cc->lastreport = p;
- break;
- }
- } else {
- msg = g_strdup (p->msg);
- pc = p->pc;
- cc->lastreport = p;
- break;
- }
- l = l->next;
- }
- }
- g_free (s->msg);
- } else {
- msg = s->msg;
- pc = CAMEL_OPERATION_END;
- cc->lastreport = s;
+ if ((node = g_queue_pop_head (status_stack)) != NULL) {
+ node->pc = 100;
+ operation_queue_status_update (operation, node);
+ status_node_free (node);
}
- g_free (s);
- cc->status_stack = g_slist_delete_link (cc->status_stack, cc->status_stack);
-
- /* This avoids a race with camel_operation_mute() after we unlock. */
- status_func = cc->status;
- status_data = cc->status_data;
UNLOCK ();
-
- if (msg) {
- status_func (cc, msg, pc, status_data);
- g_free (msg);
- }
}
diff --git a/camel/camel-operation.h b/camel/camel-operation.h
index 3bc080a..ec35a4f 100644
--- a/camel/camel-operation.h
+++ b/camel/camel-operation.h
@@ -1,8 +1,5 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
- *
- * Authors: Michael Zucchi <NotZed Ximian com>
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+/*
+ * camel-operation.h
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU Lesser General Public
@@ -26,45 +23,78 @@
#ifndef CAMEL_OPERATION_H
#define CAMEL_OPERATION_H
-#include <glib.h>
+#include <gio/gio.h>
-G_BEGIN_DECLS
+/* Standard GObject macros */
+#define CAMEL_TYPE_OPERATION \
+ (camel_operation_get_type ())
+#define CAMEL_OPERATION(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), CAMEL_TYPE_OPERATION, CamelOperation))
+#define CAMEL_OPERATION_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), CAMEL_TYPE_OPERATION, CamelOperationClass))
+#define CAMEL_IS_OPERATION(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), CAMEL_TYPE_OPERATION))
+#define CAMEL_IS_OPERATION_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), CAMEL_TYPE_OPERATION))
+#define CAMEL_OPERATION_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), CAMEL_TYPE_OPERATION, CamelOperationClass))
-/* cancellation helper stuff, not yet finalized */
+G_BEGIN_DECLS
typedef struct _CamelOperation CamelOperation;
+typedef struct _CamelOperationClass CamelOperationClass;
+typedef struct _CamelOperationPrivate CamelOperationPrivate;
-typedef void (*CamelOperationStatusFunc)(struct _CamelOperation *op, const gchar *what, gint pc, gpointer data);
+struct _CamelOperation {
+ GCancellable parent;
+ CamelOperationPrivate *priv;
+};
-typedef enum _camel_operation_status_t {
- CAMEL_OPERATION_START = -1,
- CAMEL_OPERATION_END = -2
-} camel_operation_status_t;
+struct _CamelOperationClass {
+ GCancellableClass parent_class;
+
+ /* Signals */
+ void (*status) (CamelOperation *operation,
+ const gchar *what,
+ gint pc);
+};
+
+GType camel_operation_get_type (void);
/* main thread functions */
-CamelOperation *camel_operation_new (CamelOperationStatusFunc status, gpointer status_data);
-void camel_operation_mute (CamelOperation *cc);
-void camel_operation_ref (CamelOperation *cc);
-void camel_operation_unref (CamelOperation *cc);
-void camel_operation_cancel (CamelOperation *cc);
-void camel_operation_uncancel (CamelOperation *cc);
+CamelOperation *camel_operation_new (void);
+void camel_operation_cancel (CamelOperation *operation);
+void camel_operation_uncancel (CamelOperation *operation);
+
/* subthread functions */
-CamelOperation *camel_operation_register (CamelOperation *cc);
-void camel_operation_unregister (CamelOperation *cc);
+CamelOperation *camel_operation_register (CamelOperation *operation);
+void camel_operation_unregister (void);
/* called internally by camel, for the current thread */
-gint camel_operation_cancel_check (CamelOperation *cc);
-gint camel_operation_cancel_fd (CamelOperation *cc);
+gboolean camel_operation_cancel_check (CamelOperation *operation);
+gint camel_operation_cancel_fd (CamelOperation *operation);
#ifdef CAMEL_HAVE_NSS
-struct PRFileDesc *camel_operation_cancel_prfd (CamelOperation *cc);
+struct PRFileDesc *
+ camel_operation_cancel_prfd (CamelOperation *operation);
#endif
+
/* return the registered operation for this thread, if there is one */
-CamelOperation *camel_operation_registered (void);
+CamelOperation *camel_operation_registered (void);
-void camel_operation_start (CamelOperation *cc, const gchar *what, ...);
-void camel_operation_start_transient (CamelOperation *cc, const gchar *what, ...);
-void camel_operation_progress (CamelOperation *cc, gint pc);
-void camel_operation_end (CamelOperation *cc);
+void camel_operation_start (CamelOperation *cc,
+ const gchar *what,
+ ...) G_GNUC_PRINTF (2, 3);
+void camel_operation_start_transient (CamelOperation *cc,
+ const gchar *what,
+ ...) G_GNUC_PRINTF (2, 3);
+void camel_operation_progress (CamelOperation *operation,
+ gint pc);
+void camel_operation_end (CamelOperation *operation);
G_END_DECLS
diff --git a/camel/camel-service.c b/camel/camel-service.c
index 03d1f2d..b767db5 100644
--- a/camel/camel-service.c
+++ b/camel/camel-service.c
@@ -315,7 +315,7 @@ camel_service_connect (CamelService *service,
camel_service_lock (service, CAMEL_SERVICE_CONNECT_OP_LOCK);
service->connect_op = camel_operation_registered ();
if (!service->connect_op) {
- service->connect_op = camel_operation_new (NULL, NULL);
+ service->connect_op = camel_operation_new ();
camel_operation_register (service->connect_op);
unreg = TRUE;
}
@@ -330,9 +330,9 @@ camel_service_connect (CamelService *service,
camel_service_lock (service, CAMEL_SERVICE_CONNECT_OP_LOCK);
if (connect_op) {
if (unreg && service->connect_op)
- camel_operation_unregister (connect_op);
+ camel_operation_unregister ();
- camel_operation_unref (connect_op);
+ g_object_unref (connect_op);
service->connect_op = NULL;
}
camel_service_unlock (service, CAMEL_SERVICE_CONNECT_OP_LOCK);
@@ -374,7 +374,7 @@ camel_service_disconnect (CamelService *service,
camel_service_lock (service, CAMEL_SERVICE_CONNECT_OP_LOCK);
service->connect_op = camel_operation_registered ();
if (!service->connect_op) {
- service->connect_op = camel_operation_new (NULL, NULL);
+ service->connect_op = camel_operation_new ();
camel_operation_register (service->connect_op);
unreg = TRUE;
}
@@ -387,9 +387,9 @@ camel_service_disconnect (CamelService *service,
camel_service_lock (service, CAMEL_SERVICE_CONNECT_OP_LOCK);
if (unreg)
- camel_operation_unregister (service->connect_op);
+ camel_operation_unregister ();
- camel_operation_unref (service->connect_op);
+ g_object_unref (service->connect_op);
service->connect_op = NULL;
camel_service_unlock (service, CAMEL_SERVICE_CONNECT_OP_LOCK);
}
diff --git a/camel/camel-session.c b/camel/camel-session.c
index 47f570e..8a08fbe 100644
--- a/camel/camel-session.c
+++ b/camel/camel-session.c
@@ -86,9 +86,8 @@ static void
cs_thread_status (CamelOperation *op,
const gchar *what,
gint pc,
- gpointer data)
+ CamelSessionThreadMsg *msg)
{
- CamelSessionThreadMsg *msg = data;
CamelSessionClass *class;
class = CAMEL_SESSION_GET_CLASS (msg->session);
@@ -277,7 +276,10 @@ session_thread_msg_new (CamelSession *session,
m = g_malloc0 (size);
m->ops = ops;
m->session = g_object_ref (session);
- m->op = camel_operation_new (cs_thread_status, m);
+ m->op = camel_operation_new ();
+ g_signal_connect (
+ m->op, "status",
+ G_CALLBACK (cs_thread_status), m);
camel_session_lock (session, CAMEL_SESSION_THREAD_LOCK);
m->id = session->priv->thread_id++;
g_hash_table_insert (session->priv->thread_active, GINT_TO_POINTER (m->id), m);
@@ -304,7 +306,7 @@ session_thread_msg_free (CamelSession *session,
if (msg->ops->free)
msg->ops->free (session, msg);
if (msg->op)
- camel_operation_unref (msg->op);
+ g_object_unref (msg->op);
g_clear_error (&msg->error);
g_object_unref (msg->session);
g_free (msg);
diff --git a/camel/providers/imapx/camel-imapx-server.c b/camel/providers/imapx/camel-imapx-server.c
index 941f500..8ce7111 100644
--- a/camel/providers/imapx/camel-imapx-server.c
+++ b/camel/providers/imapx/camel-imapx-server.c
@@ -3816,7 +3816,7 @@ exception:
camel_folder_change_info_free (ic->job->u.refresh_info.changes);
if (ic->job->op)
- camel_operation_unref (ic->job->op);
+ g_object_unref (ic->job->op);
imapx_job_done (is, ic->job);
camel_imapx_command_free (ic);
@@ -4602,7 +4602,7 @@ imapx_parser_thread (gpointer d)
CamelOperation *op;
GError *local_error = NULL;
- op = camel_operation_new (NULL, NULL);
+ op = camel_operation_new ();
op = camel_operation_register (op);
is->op = op;
@@ -4684,8 +4684,8 @@ imapx_parser_thread (gpointer d)
g_clear_error (&local_error);
if (op) {
- camel_operation_unregister (op);
- camel_operation_unref (op);
+ camel_operation_unregister ();
+ g_object_unref (op);
}
is->op = NULL;
@@ -4990,7 +4990,7 @@ camel_imapx_server_get_message (CamelIMAPXServer *is, CamelFolder *folder, const
stream = imapx_server_get_message (is, folder, op, uid, IMAPX_PRIORITY_GET_MESSAGE, error);
if (op)
- camel_operation_unref (op);
+ g_object_unref (op);
return stream;
}
@@ -5170,7 +5170,7 @@ camel_imapx_server_refresh_info (CamelIMAPXServer *is, CamelFolder *folder, GErr
camel_folder_change_info_free (job->u.refresh_info.changes);
if (job->op)
- camel_operation_unref (job->op);
+ g_object_unref (job->op);
g_free (job);
return success;
diff --git a/configure.ac b/configure.ac
index c7e85f9..3975275 100644
--- a/configure.ac
+++ b/configure.ac
@@ -113,7 +113,7 @@ LIBEGROUPWISE_CURRENT=13
LIBEGROUPWISE_REVISION=1
LIBEGROUPWISE_AGE=0
-LIBCAMEL_CURRENT=19
+LIBCAMEL_CURRENT=20
LIBCAMEL_REVISION=0
LIBCAMEL_AGE=0
diff --git a/docs/reference/camel/camel-sections.txt b/docs/reference/camel/camel-sections.txt
index e374972..05afb38 100644
--- a/docs/reference/camel/camel-sections.txt
+++ b/docs/reference/camel/camel-sections.txt
@@ -2826,12 +2826,7 @@ camel_movemail
<SECTION>
<FILE>camel-operation</FILE>
CamelOperation
-CamelOperationStatusFunc
-camel_operation_status_t
camel_operation_new
-camel_operation_mute
-camel_operation_ref
-camel_operation_unref
camel_operation_cancel
camel_operation_uncancel
camel_operation_register
diff --git a/docs/reference/camel/tmpl/camel-cipher-context.sgml b/docs/reference/camel/tmpl/camel-cipher-context.sgml
index 1e79cc0..3598217 100644
--- a/docs/reference/camel/tmpl/camel-cipher-context.sgml
+++ b/docs/reference/camel/tmpl/camel-cipher-context.sgml
@@ -474,6 +474,10 @@ CamelCipherContext
@gpointer cert_data:
@gpointer cert_data:
@gpointer cert_data:
+ gpointer cert_data:
+ gpointer cert_data:
+ gpointer cert_data:
+ gpointer cert_data:
@gpointer cert_data:
diff --git a/docs/reference/camel/tmpl/camel-operation.sgml b/docs/reference/camel/tmpl/camel-operation.sgml
index 642452b..a2fdedc 100644
--- a/docs/reference/camel/tmpl/camel-operation.sgml
+++ b/docs/reference/camel/tmpl/camel-operation.sgml
@@ -25,66 +25,24 @@ camel-operation
</para>
-
-<!-- ##### USER_FUNCTION CamelOperationStatusFunc ##### -->
-<para>
-
-</para>
-
- op:
- what:
- pc:
- data:
-
-
-<!-- ##### ENUM camel_operation_status_t ##### -->
-<para>
-
-</para>
-
- CAMEL_OPERATION_START:
- CAMEL_OPERATION_END:
+ parent:
+ priv:
<!-- ##### FUNCTION camel_operation_new ##### -->
<para>
</para>
- status:
- status_data:
+ void:
@Returns:
-<!-- ##### FUNCTION camel_operation_mute ##### -->
-<para>
-
-</para>
-
- cc:
-
-
-<!-- ##### FUNCTION camel_operation_ref ##### -->
-<para>
-
-</para>
-
- cc:
-
-
-<!-- ##### FUNCTION camel_operation_unref ##### -->
-<para>
-
-</para>
-
- cc:
-
-
<!-- ##### FUNCTION camel_operation_cancel ##### -->
<para>
</para>
- cc:
+ operation:
<!-- ##### FUNCTION camel_operation_uncancel ##### -->
@@ -92,7 +50,7 @@ camel-operation
</para>
- cc:
+ operation:
<!-- ##### FUNCTION camel_operation_register ##### -->
@@ -100,7 +58,7 @@ camel-operation
</para>
- cc:
+ operation:
@Returns:
@@ -109,7 +67,7 @@ camel-operation
</para>
- cc:
+ void:
<!-- ##### FUNCTION camel_operation_cancel_check ##### -->
@@ -117,7 +75,7 @@ camel-operation
</para>
- cc:
+ operation:
@Returns:
@@ -126,7 +84,7 @@ camel-operation
</para>
- cc:
+ operation:
@Returns:
@@ -135,7 +93,7 @@ camel-operation
</para>
- cc:
+ operation:
@Returns:
@@ -173,7 +131,7 @@ camel-operation
</para>
- cc:
+ operation:
@pc:
@@ -182,6 +140,6 @@ camel-operation
</para>
- cc:
+ operation:
diff --git a/docs/reference/camel/tmpl/camel-unused.sgml b/docs/reference/camel/tmpl/camel-unused.sgml
index edfab65..5f8af4f 100644
--- a/docs/reference/camel/tmpl/camel-unused.sgml
+++ b/docs/reference/camel/tmpl/camel-unused.sgml
@@ -3728,6 +3728,16 @@ streams
@CAMEL_IMAP_JOURNAL_ENTRY_APPEND:
@CAMEL_IMAP_JOURNAL_ENTRY_TRANSFER:
+<!-- ##### USER_FUNCTION CamelOperationStatusFunc ##### -->
+<para>
+
+</para>
+
+ op:
+ what:
+ pc:
+ data:
+
<!-- ##### STRUCT CamelPOP3Command ##### -->
<para>
@@ -7286,6 +7296,13 @@ streams
@cc:
+<!-- ##### FUNCTION camel_operation_mute ##### -->
+<para>
+
+</para>
+
+ cc:
+
<!-- ##### FUNCTION camel_operation_progress_count ##### -->
<para>
@@ -7294,6 +7311,28 @@ streams
@cc:
@sofar:
+<!-- ##### FUNCTION camel_operation_ref ##### -->
+<para>
+
+</para>
+
+ cc:
+
+<!-- ##### ENUM camel_operation_status_t ##### -->
+<para>
+
+</para>
+
+ CAMEL_OPERATION_START:
+ CAMEL_OPERATION_END:
+
+<!-- ##### FUNCTION camel_operation_unref ##### -->
+<para>
+
+</para>
+
+ cc:
+
<!-- ##### FUNCTION camel_partition_table_get_type ##### -->
<para>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]