aboutsummaryrefslogtreecommitdiffstats
path: root/camel/camel-operation.c
diff options
context:
space:
mode:
Diffstat (limited to 'camel/camel-operation.c')
-rw-r--r--camel/camel-operation.c164
1 files changed, 143 insertions, 21 deletions
diff --git a/camel/camel-operation.c b/camel/camel-operation.c
index c17d24e7a4..4433fa5d1a 100644
--- a/camel/camel-operation.c
+++ b/camel/camel-operation.c
@@ -7,6 +7,9 @@
#include <pthread.h>
#endif
+#include <sys/time.h>
+#include <unistd.h>
+
#include <glib.h>
#include "camel-operation.h"
#include "e-util/e-msgport.h"
@@ -15,6 +18,13 @@
/* ********************************************************************** */
+struct _status_stack {
+ guint32 flags;
+ char *msg;
+ int pc; /* last pc reported */
+ unsigned int stamp; /* last stamp reported */
+};
+
struct _CamelOperation {
pthread_t id; /* id of running thread */
guint32 flags; /* cancelled ? */
@@ -23,10 +33,11 @@ struct _CamelOperation {
CamelOperationStatusFunc status;
void *status_data;
- time_t status_update;
+ unsigned int status_update;
- /* stack of status messages (char *) */
+ /* stack of status messages (struct _status_stack *) */
GSList *status_stack;
+ struct _status_stack *lastreport;
#ifdef ENABLE_THREADS
EMsgPort *cancel_port;
@@ -36,6 +47,7 @@ struct _CamelOperation {
};
#define CAMEL_OPERATION_CANCELLED (1<<0)
+#define CAMEL_OPERATION_TRANSIENT (1<<1)
#ifdef ENABLE_THREADS
#define CAMEL_OPERATION_LOCK(cc) pthread_mutex_lock(&cc->lock)
@@ -405,6 +417,7 @@ void camel_operation_start(CamelOperation *cc, char *what, ...)
{
va_list ap;
char *msg;
+ struct _status_stack *s;
if (operation_active == NULL)
return;
@@ -425,10 +438,67 @@ void camel_operation_start(CamelOperation *cc, char *what, ...)
va_end(ap);
cc->status(cc, msg, CAMEL_OPERATION_START, cc->status_data);
cc->status_update = 0;
- cc->status_stack = g_slist_prepend(cc->status_stack, msg);
+ s = g_malloc0(sizeof(*s));
+ s->msg = msg;
+ s->flags = 0;
+ cc->lastreport = s;
+ cc->status_stack = g_slist_prepend(cc->status_stack, s);
+ d(printf("start '%s'\n", msg, pc));
+}
+
+/**
+ * camel_operation_start_transient:
+ * @cc:
+ * @what:
+ * @:
+ *
+ * Start a transient event. We only update this to the display if it
+ * takes very long to process, and if we do, we then go back to the
+ * previous state when finished.
+ **/
+void camel_operation_start_transient(CamelOperation *cc, char *what, ...)
+{
+ va_list ap;
+ char *msg;
+ struct _status_stack *s;
+
+ if (operation_active == NULL)
+ return;
+
+ if (cc == NULL) {
+ CAMEL_ACTIVE_LOCK();
+ cc = g_hash_table_lookup(operation_active, (void *)pthread_self());
+ CAMEL_ACTIVE_UNLOCK();
+ if (cc == NULL)
+ return;
+ }
+
+ if (cc->status == NULL)
+ return;
+
+ va_start(ap, what);
+ msg = g_strdup_vprintf(what, ap);
+ va_end(ap);
+ /* we dont report it yet */
+ /*cc->status(cc, msg, CAMEL_OPERATION_START, cc->status_data);*/
+ cc->status_update = 0;
+ 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));
}
+static unsigned int stamp(void)
+{
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+ /* update 4 times/second */
+ return (tv.tv_sec * 4) + tv.tv_usec / (1000000/4);
+}
+
/**
* camel_operation_progress:
* @cc: Operation to report to.
@@ -443,8 +513,8 @@ void camel_operation_start(CamelOperation *cc, char *what, ...)
**/
void camel_operation_progress(CamelOperation *cc, int pc)
{
- char *msg;
- time_t now;
+ unsigned int now;
+ struct _status_stack *s;
if (operation_active == NULL)
return;
@@ -463,19 +533,31 @@ void camel_operation_progress(CamelOperation *cc, int pc)
if (cc->status_stack == NULL)
return;
- now = time(0);
+ s = cc->status_stack->data;
+ s->pc = pc;
+
+ now = stamp();
if (cc->status_update != now) {
- msg =cc->status_stack->data;
- cc->status(cc, msg, pc, cc->status_data);
- d(printf("progress '%s' %d %%\n", msg, pc));
- cc->status_update = now;
+ if (s->flags & CAMEL_OPERATION_TRANSIENT) {
+ if (s->stamp/16 < now/16) {
+ s->stamp = now;
+ cc->status(cc, s->msg, pc, cc->status_data);
+ cc->status_update = now;
+ cc->lastreport = s;
+ }
+ } else {
+ cc->status(cc, s->msg, pc, cc->status_data);
+ d(printf("progress '%s' %d %%\n", s->msg, pc));
+ s->stamp = cc->status_update = now;
+ cc->lastreport = s;
+ }
}
}
void camel_operation_progress_count(CamelOperation *cc, int sofar)
{
- char *msg;
- time_t now;
+ unsigned int now;
+ struct _status_stack *s;
if (operation_active == NULL)
return;
@@ -495,12 +577,23 @@ void camel_operation_progress_count(CamelOperation *cc, int sofar)
return;
/* FIXME: generate some meaningful pc value */
- now = time(0);
+ s = cc->status_stack->data;
+ s->pc = sofar;
+ now = stamp();
if (cc->status_update != now) {
- msg =cc->status_stack->data;
- cc->status(cc, msg, sofar, cc->status_data);
- d(printf("progress '%s' %d done\n", msg, sofar));
- cc->status_update = now;
+ if (s->flags & CAMEL_OPERATION_TRANSIENT) {
+ if (s->stamp/16 < now/16) {
+ s->stamp = now;
+ cc->status(cc, s->msg, sofar, cc->status_data);
+ cc->status_update = now;
+ cc->lastreport = s;
+ }
+ } else {
+ cc->status(cc, s->msg, sofar, cc->status_data);
+ d(printf("progress '%s' %d done\n", msg, sofar));
+ s->stamp = cc->status_update = now;
+ cc->lastreport = s;
+ }
}
}
@@ -515,7 +608,8 @@ void camel_operation_progress_count(CamelOperation *cc, int sofar)
**/
void camel_operation_end(CamelOperation *cc)
{
- char *msg;
+ struct _status_stack *s, *p;
+ unsigned int now;
if (operation_active == NULL)
return;
@@ -534,8 +628,36 @@ void camel_operation_end(CamelOperation *cc)
if (cc->status_stack == NULL)
return;
- msg = cc->status_stack->data;
- cc->status(cc, msg, CAMEL_OPERATION_END, cc->status_data);
- g_free(msg);
+ /* 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/16 < now/16) {
+ cc->status(cc, p->msg, p->pc, cc->status_data);
+ cc->lastreport = p;
+ break;
+ }
+ } else {
+ cc->status(cc, p->msg, p->pc, cc->status_data);
+ cc->lastreport = p;
+ break;
+ }
+ l = l->next;
+ }
+ }
+ } else {
+ cc->status(cc, s->msg, CAMEL_OPERATION_END, cc->status_data);
+ cc->lastreport = s;
+ }
+ g_free(s->msg);
+ g_free(s);
cc->status_stack = g_slist_remove_link(cc->status_stack, cc->status_stack);
}