[evolution] Simplify EActivity.



commit c881b5bc5e61d04b18d4ab46ad70533e7340d15b
Author: Matthew Barnes <mbarnes redhat com>
Date:   Thu Oct 21 16:21:19 2010 -0400

    Simplify EActivity.
    
    With unintrusive error dialogs gone, we can cut some unnecessary bits
    out of EActivity.
    
    I'm also adding a new enum property called "state", which is one of:
    
        E_ACTIVITY_RUNNING
        E_ACTIVITY_WAITING
        E_ACTIVITY_CANCELLED
        E_ACTIVITY_COMPLETED
    
    The state of an activity must be explicitly changed.  In particular,
    when the user cancels an activity the state should be set only after
    confirming the operation has been cancelled and not when cancellation
    is requested (e.g. after receiving a G_IO_ERROR_CANCELLED, not when
    the GCancellable emits "cancelled").  EActivityBar and EActivityProxy
    widgets have been updated to make this distinction clearer in the UI.
    
    E_ACTIVITY_WAITING will be used when activities have to be queued and
    dispatched in sequence, which I haven't written yet.

 addressbook/gui/widgets/e-addressbook-view.c     |    8 +-
 composer/e-msg-composer.c                        |   18 --
 doc/reference/shell/eshell-sections.txt          |    9 +-
 doc/reference/shell/tmpl/e-activity.sgml         |   67 +-----
 doc/reference/shell/tmpl/eshell-unused.sgml      |   70 ++++++
 e-util/Makefile.am                               |   18 +-
 e-util/e-activity.c                              |  277 +++++----------------
 e-util/e-activity.h                              |   24 +--
 e-util/e-file-utils.c                            |   78 ++++--
 e-util/e-io-activity.c                           |  191 --------------
 e-util/e-io-activity.h                           |   72 ------
 e-util/e-util-enums.h                            |   35 +++
 e-util/e-util.h                                  |    1 +
 mail/e-mail-session.c                            |   30 ++-
 mail/em-composer-utils.c                         |   14 +-
 mail/em-folder-tree.c                            |   32 ++-
 mail/em-folder-utils.c                           |   49 ++--
 mail/em-format-html.c                            |   22 +-
 mail/importers/elm-importer.c                    |    4 +-
 mail/importers/mail-importer.c                   |   22 +-
 mail/importers/pine-importer.c                   |    4 +-
 mail/mail-folder-cache.c                         |    7 +-
 mail/mail-mt.c                                   |   96 +++++---
 mail/mail-mt.h                                   |   17 +-
 mail/mail-ops.c                                  |  243 ++++++++++--------
 mail/mail-send-recv.c                            |    8 +-
 mail/mail-vfolder.c                              |   13 +-
 mail/message-list.c                              |   31 ++-
 modules/calendar/e-cal-shell-view-memopad.c      |    6 +-
 modules/calendar/e-cal-shell-view-private.c      |   15 +-
 modules/calendar/e-cal-shell-view-taskpad.c      |    6 +-
 modules/calendar/e-memo-shell-view-private.c     |   10 +-
 modules/calendar/e-task-shell-view-private.c     |   10 +-
 modules/mail/e-mail-shell-view.c                 |    4 +-
 plugins/dbx-import/dbx-importer.c                |   13 +-
 plugins/groupwise-features/share-folder-common.c |    9 +-
 plugins/itip-formatter/itip-formatter.c          |    4 +-
 plugins/pst-import/pst-importer.c                |   18 +-
 shell/e-shell-backend.c                          |   21 ++-
 shell/e-shell-taskbar.c                          |   76 +++---
 shell/e-shell-view.c                             |    2 +-
 shell/e-shell.c                                  |   12 +-
 shell/test/e-test-shell-view.c                   |    2 +-
 widgets/misc/e-activity-bar.c                    |  107 +++++----
 widgets/misc/e-activity-proxy.c                  |  289 +++++++++++++---------
 widgets/misc/e-activity-proxy.h                  |    2 +
 46 files changed, 942 insertions(+), 1124 deletions(-)
---
diff --git a/addressbook/gui/widgets/e-addressbook-view.c b/addressbook/gui/widgets/e-addressbook-view.c
index fac9723..fcf4dd3 100644
--- a/addressbook/gui/widgets/e-addressbook-view.c
+++ b/addressbook/gui/widgets/e-addressbook-view.c
@@ -517,7 +517,7 @@ addressbook_view_dispose (GObject *object)
 
 	if (priv->activity != NULL) {
 		/* XXX Activity is not cancellable. */
-		e_activity_complete (priv->activity);
+		e_activity_set_state (priv->activity, E_ACTIVITY_COMPLETED);
 		g_object_unref (priv->activity);
 		priv->activity = NULL;
 	}
@@ -1075,7 +1075,7 @@ status_message (EAddressbookView *view,
 
 	if (status == NULL || *status == '\0') {
 		if (activity != NULL) {
-			e_activity_complete (activity);
+			e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
 			g_object_unref (activity);
 			view->priv->activity = NULL;
 		}
@@ -1083,11 +1083,11 @@ status_message (EAddressbookView *view,
 	} else if (activity == NULL) {
 		activity = e_activity_new ();
 		view->priv->activity = activity;
-		e_activity_set_primary_text (activity, status);
+		e_activity_set_text (activity, status);
 		e_shell_backend_add_activity (shell_backend, activity);
 
 	} else
-		e_activity_set_primary_text (activity, status);
+		e_activity_set_text (activity, status);
 }
 
 static void
diff --git a/composer/e-msg-composer.c b/composer/e-msg-composer.c
index a30a482..34cf705 100644
--- a/composer/e-msg-composer.c
+++ b/composer/e-msg-composer.c
@@ -3533,11 +3533,9 @@ void
 e_msg_composer_send (EMsgComposer *composer)
 {
 	AsyncContext *context;
-	GtkAction *action;
 	EActivityBar *activity_bar;
 	GCancellable *cancellable;
 	gboolean proceed_with_send = TRUE;
-	const gchar *icon_name;
 
 	g_return_if_fail (E_IS_MSG_COMPOSER (composer));
 
@@ -3554,10 +3552,6 @@ e_msg_composer_send (EMsgComposer *composer)
 	e_activity_set_cancellable (context->activity, cancellable);
 	g_object_unref (cancellable);
 
-	action = ACTION (SEND);
-	icon_name = gtk_action_get_icon_name (action);
-	e_activity_set_icon_name (context->activity, icon_name);
-
 	activity_bar = E_ACTIVITY_BAR (composer->priv->activity_bar);
 	e_activity_bar_set_activity (activity_bar, context->activity);
 
@@ -3623,10 +3617,8 @@ void
 e_msg_composer_save_draft (EMsgComposer *composer)
 {
 	AsyncContext *context;
-	GtkAction *action;
 	EActivityBar *activity_bar;
 	GCancellable *cancellable;
-	const gchar *icon_name;
 
 	g_return_if_fail (E_IS_MSG_COMPOSER (composer));
 
@@ -3637,10 +3629,6 @@ e_msg_composer_save_draft (EMsgComposer *composer)
 	e_activity_set_cancellable (context->activity, cancellable);
 	g_object_unref (cancellable);
 
-	action = ACTION (SAVE_DRAFT);
-	icon_name = gtk_action_get_icon_name (action);
-	e_activity_set_icon_name (context->activity, icon_name);
-
 	activity_bar = E_ACTIVITY_BAR (composer->priv->activity_bar);
 	e_activity_bar_set_activity (activity_bar, context->activity);
 
@@ -3703,10 +3691,8 @@ e_msg_composer_print (EMsgComposer *composer,
                       GtkPrintOperationAction print_action)
 {
 	AsyncContext *context;
-	GtkAction *action;
 	EActivityBar *activity_bar;
 	GCancellable *cancellable;
-	const gchar *icon_name;
 
 	g_return_if_fail (E_IS_MSG_COMPOSER (composer));
 
@@ -3718,10 +3704,6 @@ e_msg_composer_print (EMsgComposer *composer,
 	e_activity_set_cancellable (context->activity, cancellable);
 	g_object_unref (cancellable);
 
-	action = ACTION (PRINT);
-	icon_name = gtk_action_get_icon_name (action);
-	e_activity_set_icon_name (context->activity, icon_name);
-
 	activity_bar = E_ACTIVITY_BAR (composer->priv->activity_bar);
 	e_activity_bar_set_activity (activity_bar, context->activity);
 
diff --git a/doc/reference/shell/eshell-sections.txt b/doc/reference/shell/eshell-sections.txt
index 07ee9b4..63a8578 100644
--- a/doc/reference/shell/eshell-sections.txt
+++ b/doc/reference/shell/eshell-sections.txt
@@ -471,21 +471,16 @@ EActivity
 e_activity_new
 e_activity_newv
 e_activity_complete
-e_activity_clicked
 e_activity_describe
 e_activity_is_completed
 e_activity_get_cancellable
 e_activity_set_cancellable
-e_activity_get_clickable
-e_activity_set_clickable
 e_activity_get_icon_name
 e_activity_set_icon_name
 e_activity_get_percent
 e_activity_set_percent
-e_activity_get_primary_text
-e_activity_set_primary_text
-e_activity_get_secondary_text
-e_activity_set_secondary_text
+e_activity_get_text
+e_activity_set_text
 <SUBSECTION Standard>
 E_ACTIVITY
 E_IS_ACTIVITY
diff --git a/doc/reference/shell/tmpl/e-activity.sgml b/doc/reference/shell/tmpl/e-activity.sgml
index 871758f..1d4d1b3 100644
--- a/doc/reference/shell/tmpl/e-activity.sgml
+++ b/doc/reference/shell/tmpl/e-activity.sgml
@@ -45,22 +45,6 @@ e-activity
 @Returns: 
 
 
-<!-- ##### FUNCTION e_activity_complete ##### -->
-<para>
-
-</para>
-
- activity: 
-
-
-<!-- ##### FUNCTION e_activity_clicked ##### -->
-<para>
-
-</para>
-
- activity: 
-
-
 <!-- ##### FUNCTION e_activity_describe ##### -->
 <para>
 
@@ -70,15 +54,6 @@ e-activity
 @Returns: 
 
 
-<!-- ##### FUNCTION e_activity_is_completed ##### -->
-<para>
-
-</para>
-
- activity: 
- Returns: 
-
-
 <!-- ##### FUNCTION e_activity_get_cancellable ##### -->
 <para>
 
@@ -97,24 +72,6 @@ e-activity
 @cancellable: 
 
 
-<!-- ##### FUNCTION e_activity_get_clickable ##### -->
-<para>
-
-</para>
-
- activity: 
- Returns: 
-
-
-<!-- ##### FUNCTION e_activity_set_clickable ##### -->
-<para>
-
-</para>
-
- activity: 
- clickable: 
-
-
 <!-- ##### FUNCTION e_activity_get_icon_name ##### -->
 <para>
 
@@ -151,25 +108,7 @@ e-activity
 @percent: 
 
 
-<!-- ##### FUNCTION e_activity_get_primary_text ##### -->
-<para>
-
-</para>
-
- activity: 
- Returns: 
-
-
-<!-- ##### FUNCTION e_activity_set_primary_text ##### -->
-<para>
-
-</para>
-
- activity: 
- primary_text: 
-
-
-<!-- ##### FUNCTION e_activity_get_secondary_text ##### -->
+<!-- ##### FUNCTION e_activity_get_text ##### -->
 <para>
 
 </para>
@@ -178,12 +117,12 @@ e-activity
 @Returns: 
 
 
-<!-- ##### FUNCTION e_activity_set_secondary_text ##### -->
+<!-- ##### FUNCTION e_activity_set_text ##### -->
 <para>
 
 </para>
 
 @activity: 
- secondary_text: 
+ text: 
 
 
diff --git a/doc/reference/shell/tmpl/eshell-unused.sgml b/doc/reference/shell/tmpl/eshell-unused.sgml
index e60ce12..4c9b60d 100644
--- a/doc/reference/shell/tmpl/eshell-unused.sgml
+++ b/doc/reference/shell/tmpl/eshell-unused.sgml
@@ -245,6 +245,20 @@ e-shell-window.sgml
 
 @activity: 
 
+<!-- ##### FUNCTION e_activity_clicked ##### -->
+<para>
+
+</para>
+
+ activity: 
+
+<!-- ##### FUNCTION e_activity_complete ##### -->
+<para>
+
+</para>
+
+ activity: 
+
 <!-- ##### FUNCTION e_activity_get_allow_cancel ##### -->
 <para>
 
@@ -253,6 +267,30 @@ e-shell-window.sgml
 @activity: 
 @Returns: 
 
+<!-- ##### FUNCTION e_activity_get_clickable ##### -->
+<para>
+
+</para>
+
+ activity: 
+ Returns: 
+
+<!-- ##### FUNCTION e_activity_get_primary_text ##### -->
+<para>
+
+</para>
+
+ activity: 
+ Returns: 
+
+<!-- ##### FUNCTION e_activity_get_secondary_text ##### -->
+<para>
+
+</para>
+
+ activity: 
+ Returns: 
+
 <!-- ##### FUNCTION e_activity_is_cancelled ##### -->
 <para>
 
@@ -261,6 +299,14 @@ e-shell-window.sgml
 @activity: 
 @Returns: 
 
+<!-- ##### FUNCTION e_activity_is_completed ##### -->
+<para>
+
+</para>
+
+ activity: 
+ Returns: 
+
 <!-- ##### FUNCTION e_activity_set_allow_cancel ##### -->
 <para>
 
@@ -269,6 +315,30 @@ e-shell-window.sgml
 @activity: 
 @allow_cancel: 
 
+<!-- ##### FUNCTION e_activity_set_clickable ##### -->
+<para>
+
+</para>
+
+ activity: 
+ clickable: 
+
+<!-- ##### FUNCTION e_activity_set_primary_text ##### -->
+<para>
+
+</para>
+
+ activity: 
+ primary_text: 
+
+<!-- ##### FUNCTION e_activity_set_secondary_text ##### -->
+<para>
+
+</para>
+
+ activity: 
+ secondary_text: 
+
 <!-- ##### FUNCTION e_alert_dialog_count_buttons ##### -->
 <para>
 
diff --git a/e-util/Makefile.am b/e-util/Makefile.am
index d96b2b0..3f4388e 100644
--- a/e-util/Makefile.am
+++ b/e-util/Makefile.am
@@ -2,6 +2,14 @@ eutilincludedir = $(privincludedir)/e-util
 ecpsdir = $(privdatadir)/ecps
 ruledir = $(privdatadir)
 
+include $(top_srcdir)/glib-gen.mak
+glib_enum_headers=e-util-enums.h
+glib_enum_define=E
+glib_enum_prefix=e
+
+ENUM_GENERATED = e-util-enumtypes.h e-util-enumtypes.c
+MARSHAL_GENERATED = e-marshal.c e-marshal.h
+
 if OS_WIN32
 PLATFORM_SOURCES = e-win32-reloc.c e-win32-defaults.c e-win32-defaults.h
 endif
@@ -28,7 +36,6 @@ eutilinclude_HEADERS = 				\
 	e-html-utils.h				\
 	e-icon-factory.h			\
 	e-import.h				\
-	e-io-activity.h				\
 	e-marshal.h				\
 	e-mktemp.h				\
 	e-module.h				\
@@ -49,6 +56,8 @@ eutilinclude_HEADERS = 				\
 	e-text-event-processor.h		\
 	e-ui-manager.h				\
 	e-util.h				\
+	e-util-enums.h				\
+	e-util-enumtypes.h			\
 	e-unicode.h				\
 	e-xml-utils.h				\
 	gconf-bridge.h
@@ -103,7 +112,6 @@ libeutil_la_SOURCES =				\
 	e-html-utils.c				\
 	e-icon-factory.c			\
 	e-import.c				\
-	e-io-activity.c				\
 	e-marshal.c				\
 	e-mktemp.c				\
 	e-module.c				\
@@ -124,15 +132,13 @@ libeutil_la_SOURCES =				\
 	e-ui-manager.c				\
 	e-util.c				\
 	e-unicode.c				\
+	e-util-enumtypes.c			\
 	e-util-private.h			\
 	e-xml-utils.c				\
 	gconf-bridge.c				\
 	gtk-compat.h				\
 	$(PLATFORM_SOURCES)
 
-MARSHAL_GENERATED = e-marshal.c e-marshal.h
- EVO_MARSHAL_RULE@
-
 libeutil_la_LDFLAGS = $(NO_UNDEFINED)
 
 libeutil_la_LIBADD = 		\
@@ -149,7 +155,7 @@ EXTRA_DIST =				\
 	e-system.error.xml		\
 	e-marshal.list
 
-BUILT_SOURCES = $(MARSHAL_GENERATED) $(error_DATA)
+BUILT_SOURCES = $(ENUM_GENERATED) $(MARSHAL_GENERATED) $(error_DATA)
 CLEANFILES    = $(BUILT_SOURCES)
 
 dist-hook:
diff --git a/e-util/e-activity.c b/e-util/e-activity.c
index 38196e8..7e0cb1c 100644
--- a/e-util/e-activity.c
+++ b/e-util/e-activity.c
@@ -26,6 +26,7 @@
 #include <camel/camel.h>
 
 #include "e-util/e-util.h"
+#include "e-util/e-util-enumtypes.h"
 
 #define E_ACTIVITY_GET_PRIVATE(obj) \
 	(G_TYPE_INSTANCE_GET_PRIVATE \
@@ -33,36 +34,22 @@
 
 struct _EActivityPrivate {
 	GCancellable *cancellable;
+	EActivityState state;
 
 	gchar *icon_name;
-	gchar *primary_text;
-	gchar *secondary_text;
+	gchar *text;
 	gdouble percent;
-
-	guint clickable		: 1;
-	guint completed		: 1;
 };
 
 enum {
 	PROP_0,
 	PROP_CANCELLABLE,
-	PROP_CLICKABLE,
 	PROP_ICON_NAME,
 	PROP_PERCENT,
-	PROP_PRIMARY_TEXT,
-	PROP_SECONDARY_TEXT
+	PROP_STATE,
+	PROP_TEXT
 };
 
-enum {
-	CANCELLED,
-	CLICKED,
-	COMPLETED,
-	DESCRIBE,
-	LAST_SIGNAL
-};
-
-static gulong signals[LAST_SIGNAL];
-
 G_DEFINE_TYPE (
 	EActivity,
 	e_activity,
@@ -78,29 +65,7 @@ activity_camel_status_cb (EActivity *activity,
 
 	g_object_set (
 		activity, "percent", (gdouble) percent,
-		"primary-text", description, NULL);
-}
-
-static gboolean
-activity_describe_accumulator (GSignalInvocationHint *ihint,
-                               GValue *return_accu,
-                               const GValue *handler_return,
-                               gpointer accu_data)
-{
-	const gchar *string;
-
-	string = g_value_get_string (handler_return);
-	g_value_set_string (return_accu, string);
-
-	return (string == NULL);
-}
-
-static void
-activity_emit_cancelled (EActivity *activity)
-{
-	/* This signal should only be emitted via our GCancellable,
-	 * which is why we don't expose this function publicly. */
-	g_signal_emit (activity, signals[CANCELLED], 0);
+		"text", description, NULL);
 }
 
 static void
@@ -116,12 +81,6 @@ activity_set_property (GObject *object,
 				g_value_get_object (value));
 			return;
 
-		case PROP_CLICKABLE:
-			e_activity_set_clickable (
-				E_ACTIVITY (object),
-				g_value_get_boolean (value));
-			return;
-
 		case PROP_ICON_NAME:
 			e_activity_set_icon_name (
 				E_ACTIVITY (object),
@@ -134,14 +93,14 @@ activity_set_property (GObject *object,
 				g_value_get_double (value));
 			return;
 
-		case PROP_PRIMARY_TEXT:
-			e_activity_set_primary_text (
+		case PROP_STATE:
+			e_activity_set_state (
 				E_ACTIVITY (object),
-				g_value_get_string (value));
+				g_value_get_enum (value));
 			return;
 
-		case PROP_SECONDARY_TEXT:
-			e_activity_set_secondary_text (
+		case PROP_TEXT:
+			e_activity_set_text (
 				E_ACTIVITY (object),
 				g_value_get_string (value));
 			return;
@@ -163,12 +122,6 @@ activity_get_property (GObject *object,
 				E_ACTIVITY (object)));
 			return;
 
-		case PROP_CLICKABLE:
-			g_value_set_boolean (
-				value, e_activity_get_clickable (
-				E_ACTIVITY (object)));
-			return;
-
 		case PROP_ICON_NAME:
 			g_value_set_string (
 				value, e_activity_get_icon_name (
@@ -181,15 +134,15 @@ activity_get_property (GObject *object,
 				E_ACTIVITY (object)));
 			return;
 
-		case PROP_PRIMARY_TEXT:
-			g_value_set_string (
-				value, e_activity_get_primary_text (
+		case PROP_STATE:
+			g_value_set_enum (
+				value, e_activity_get_state (
 				E_ACTIVITY (object)));
 			return;
 
-		case PROP_SECONDARY_TEXT:
+		case PROP_TEXT:
 			g_value_set_string (
-				value, e_activity_get_secondary_text (
+				value, e_activity_get_text (
 				E_ACTIVITY (object)));
 			return;
 	}
@@ -225,55 +178,51 @@ activity_finalize (GObject *object)
 	priv = E_ACTIVITY_GET_PRIVATE (object);
 
 	g_free (priv->icon_name);
-	g_free (priv->primary_text);
-	g_free (priv->secondary_text);
+	g_free (priv->text);
 
 	/* Chain up to parent's finalize() method. */
 	G_OBJECT_CLASS (e_activity_parent_class)->finalize (object);
 }
 
-static void
-activity_completed (EActivity *activity)
-{
-	activity->priv->completed = TRUE;
-}
-
-static void
-activity_clicked (EActivity *activity)
-{
-	/* Allow subclasses to safely chain up. */
-}
-
 static gchar *
 activity_describe (EActivity *activity)
 {
 	GString *string;
 	GCancellable *cancellable;
+	EActivityState state;
 	const gchar *text;
 	gdouble percent;
 
 	string = g_string_sized_new (256);
 	cancellable = e_activity_get_cancellable (activity);
-	text = e_activity_get_primary_text (activity);
 	percent = e_activity_get_percent (activity);
+	state = e_activity_get_state (activity);
+	text = e_activity_get_text (activity);
 
 	if (text == NULL)
 		return NULL;
 
-	if (g_cancellable_is_cancelled (cancellable)) {
+	if (state == E_ACTIVITY_CANCELLED) {
 		/* Translators: This is a cancelled activity. */
 		g_string_printf (string, _("%s (cancelled)"), text);
-	} else if (e_activity_is_completed (activity)) {
+	} else if (state == E_ACTIVITY_COMPLETED) {
 		/* Translators: This is a completed activity. */
 		g_string_printf (string, _("%s (completed)"), text);
+	} else if (state == E_ACTIVITY_WAITING) {
+		/* Translators: This is an activity waiting to run. */
+		g_string_printf (string, _("%s (waiting)"), text);
+	} else if (g_cancellable_is_cancelled (cancellable)) {
+		/* Translators: This is a running activity which
+		 *              the user has requested to cancel. */
+		g_string_printf (string, _("%s (cancelling)"), text);
 	} else if (percent <= 0.0) {
 		g_string_printf (string, _("%s"), text);
 	} else {
-		/* Translators: This is an activity whose percent
-		 * complete is known. */
+		/* Translators: This is a running activity whose
+		 *              percent complete is known. */
 		g_string_printf (
-			string, _("%s (%d%% complete)"), text,
-			(gint) (percent));
+			string, _("%s (%d%% complete)"),
+			text, (gint) (percent));
 	}
 
 	return g_string_free (string, FALSE);
@@ -292,8 +241,6 @@ e_activity_class_init (EActivityClass *class)
 	object_class->dispose = activity_dispose;
 	object_class->finalize = activity_finalize;
 
-	class->completed = activity_completed;
-	class->clicked = activity_clicked;
 	class->describe = activity_describe;
 
 	g_object_class_install_property (
@@ -309,17 +256,6 @@ e_activity_class_init (EActivityClass *class)
 
 	g_object_class_install_property (
 		object_class,
-		PROP_CLICKABLE,
-		g_param_spec_boolean (
-			"clickable",
-			NULL,
-			NULL,
-			FALSE,
-			G_PARAM_READWRITE |
-			G_PARAM_CONSTRUCT));
-
-	g_object_class_install_property (
-		object_class,
 		PROP_ICON_NAME,
 		g_param_spec_string (
 			"icon-name",
@@ -344,61 +280,26 @@ e_activity_class_init (EActivityClass *class)
 
 	g_object_class_install_property (
 		object_class,
-		PROP_PRIMARY_TEXT,
-		g_param_spec_string (
-			"primary-text",
-			NULL,
+		PROP_STATE,
+		g_param_spec_enum (
+			"state",
 			NULL,
 			NULL,
+			E_TYPE_ACTIVITY_STATE,
+			E_ACTIVITY_RUNNING,
 			G_PARAM_READWRITE |
 			G_PARAM_CONSTRUCT));
 
 	g_object_class_install_property (
 		object_class,
-		PROP_SECONDARY_TEXT,
+		PROP_TEXT,
 		g_param_spec_string (
-			"secondary-text",
+			"text",
 			NULL,
 			NULL,
 			NULL,
 			G_PARAM_READWRITE |
 			G_PARAM_CONSTRUCT));
-
-	signals[CANCELLED] = g_signal_new (
-		"cancelled",
-		G_OBJECT_CLASS_TYPE (object_class),
-		G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
-		G_STRUCT_OFFSET (EActivityClass, cancelled),
-		NULL, NULL,
-		g_cclosure_marshal_VOID__VOID,
-		G_TYPE_NONE, 0);
-
-	signals[CLICKED] = g_signal_new (
-		"clicked",
-		G_OBJECT_CLASS_TYPE (object_class),
-		G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
-		G_STRUCT_OFFSET (EActivityClass, clicked),
-		NULL, NULL,
-		g_cclosure_marshal_VOID__VOID,
-		G_TYPE_NONE, 0);
-
-	signals[COMPLETED] = g_signal_new (
-		"completed",
-		G_OBJECT_CLASS_TYPE (object_class),
-		G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
-		G_STRUCT_OFFSET (EActivityClass, completed),
-		NULL, NULL,
-		g_cclosure_marshal_VOID__VOID,
-		G_TYPE_NONE, 0);
-
-	signals[DESCRIBE] = g_signal_new (
-		"describe",
-		G_OBJECT_CLASS_TYPE (object_class),
-		G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
-		G_STRUCT_OFFSET (EActivityClass, describe),
-		activity_describe_accumulator, NULL,
-		e_marshal_STRING__VOID,
-		G_TYPE_STRING, 0);
 }
 
 static void
@@ -417,46 +318,20 @@ EActivity *
 e_activity_newv (const gchar *format, ...)
 {
 	EActivity *activity;
-	gchar *primary_text;
+	gchar *text;
 	va_list args;
 
 	activity = e_activity_new ();
 
 	va_start (args, format);
-	primary_text = g_strdup_vprintf (format, args);
-	e_activity_set_primary_text (activity, primary_text);
-	g_free (primary_text);
+	text = g_strdup_vprintf (format, args);
+	e_activity_set_text (activity, text);
+	g_free (text);
 	va_end (args);
 
 	return activity;
 }
 
-void
-e_activity_complete (EActivity *activity)
-{
-	GCancellable *cancellable;
-
-	g_return_if_fail (E_IS_ACTIVITY (activity));
-
-	cancellable = e_activity_get_cancellable (activity);
-
-	if (g_cancellable_is_cancelled (cancellable))
-		return;
-
-	if (activity->priv->completed)
-		return;
-
-	g_signal_emit (activity, signals[COMPLETED], 0);
-}
-
-void
-e_activity_clicked (EActivity *activity)
-{
-	g_return_if_fail (E_IS_ACTIVITY (activity));
-
-	g_signal_emit (activity, signals[CLICKED], 0);
-}
-
 gchar *
 e_activity_describe (EActivity *activity)
 {
@@ -470,14 +345,6 @@ e_activity_describe (EActivity *activity)
 	return class->describe (activity);
 }
 
-gboolean
-e_activity_is_completed (EActivity *activity)
-{
-	g_return_val_if_fail (E_IS_ACTIVITY (activity), FALSE);
-
-	return activity->priv->completed;
-}
-
 GCancellable *
 e_activity_get_cancellable (EActivity *activity)
 {
@@ -506,11 +373,6 @@ e_activity_set_cancellable (EActivity *activity,
 
 	activity->priv->cancellable = cancellable;
 
-	if (G_IS_CANCELLABLE (cancellable))
-		g_signal_connect_swapped (
-			cancellable, "cancelled",
-			G_CALLBACK (activity_emit_cancelled), activity);
-
 	/* If this is a CamelOperation, listen for status updates
 	 * from it and propagate them to our own status properties. */
 	if (CAMEL_IS_OPERATION (cancellable))
@@ -521,25 +383,6 @@ e_activity_set_cancellable (EActivity *activity,
 	g_object_notify (G_OBJECT (activity), "cancellable");
 }
 
-gboolean
-e_activity_get_clickable (EActivity *activity)
-{
-	g_return_val_if_fail (E_IS_ACTIVITY (activity), FALSE);
-
-	return activity->priv->clickable;
-}
-
-void
-e_activity_set_clickable (EActivity *activity,
-                          gboolean clickable)
-{
-	g_return_if_fail (E_IS_ACTIVITY (activity));
-
-	activity->priv->clickable = clickable;
-
-	g_object_notify (G_OBJECT (activity), "clickable");
-}
-
 const gchar *
 e_activity_get_icon_name (EActivity *activity)
 {
@@ -579,42 +422,42 @@ e_activity_set_percent (EActivity *activity,
 	g_object_notify (G_OBJECT (activity), "percent");
 }
 
-const gchar *
-e_activity_get_primary_text (EActivity *activity)
+EActivityState
+e_activity_get_state (EActivity *activity)
 {
-	g_return_val_if_fail (E_IS_ACTIVITY (activity), NULL);
+	g_return_val_if_fail (E_IS_ACTIVITY (activity), 0);
 
-	return activity->priv->primary_text;
+	return activity->priv->state;
 }
 
 void
-e_activity_set_primary_text (EActivity *activity,
-                             const gchar *primary_text)
+e_activity_set_state (EActivity *activity,
+                      EActivityState state)
 {
 	g_return_if_fail (E_IS_ACTIVITY (activity));
 
-	g_free (activity->priv->primary_text);
-	activity->priv->primary_text = g_strdup (primary_text);
+	activity->priv->state = state;
 
-	g_object_notify (G_OBJECT (activity), "primary-text");
+	g_object_notify (G_OBJECT (activity), "state");
 }
 
 const gchar *
-e_activity_get_secondary_text (EActivity *activity)
+e_activity_get_text (EActivity *activity)
 {
 	g_return_val_if_fail (E_IS_ACTIVITY (activity), NULL);
 
-	return activity->priv->secondary_text;
+	return activity->priv->text;
 }
 
 void
-e_activity_set_secondary_text (EActivity *activity,
-                               const gchar *secondary_text)
+e_activity_set_text (EActivity *activity,
+                     const gchar *text)
 {
 	g_return_if_fail (E_IS_ACTIVITY (activity));
 
-	g_free (activity->priv->secondary_text);
-	activity->priv->secondary_text = g_strdup (secondary_text);
+	g_free (activity->priv->text);
+	activity->priv->text = g_strdup (text);
 
-	g_object_notify (G_OBJECT (activity), "secondary-text");
+	g_object_notify (G_OBJECT (activity), "text");
 }
+
diff --git a/e-util/e-activity.h b/e-util/e-activity.h
index 4573fad..63195b7 100644
--- a/e-util/e-activity.h
+++ b/e-util/e-activity.h
@@ -23,6 +23,7 @@
 #define E_ACTIVITY_H
 
 #include <gtk/gtk.h>
+#include <e-util/e-util-enums.h>
 
 /* Standard GObject macros */
 #define E_TYPE_ACTIVITY \
@@ -57,10 +58,7 @@ struct _EActivity {
 struct _EActivityClass {
 	GObjectClass parent_class;
 
-	/* Signals */
-	void		(*cancelled)		(EActivity *activity);
-	void		(*completed)		(EActivity *activity);
-	void		(*clicked)		(EActivity *activity);
+	/* Methods */
 	gchar *		(*describe)		(EActivity *activity);
 };
 
@@ -68,28 +66,22 @@ GType		e_activity_get_type		(void);
 EActivity *	e_activity_new			(void);
 EActivity *	e_activity_newv			(const gchar *format,
 						 ...) G_GNUC_PRINTF (1, 2);
-void		e_activity_complete		(EActivity *activity);
-void		e_activity_clicked		(EActivity *activity);
 gchar *		e_activity_describe		(EActivity *activity);
-gboolean	e_activity_is_completed		(EActivity *activity);
 GCancellable *	e_activity_get_cancellable	(EActivity *activity);
 void		e_activity_set_cancellable	(EActivity *activity,
 						 GCancellable *cancellable);
-gboolean	e_activity_get_clickable	(EActivity *activity);
-void		e_activity_set_clickable	(EActivity *activity,
-						 gboolean clickable);
 const gchar *	e_activity_get_icon_name	(EActivity *activity);
 void		e_activity_set_icon_name	(EActivity *activity,
 						 const gchar *icon_name);
 gdouble		e_activity_get_percent		(EActivity *activity);
 void		e_activity_set_percent		(EActivity *activity,
 						 gdouble percent);
-const gchar *	e_activity_get_primary_text	(EActivity *activity);
-void		e_activity_set_primary_text	(EActivity *activity,
-						 const gchar *primary_text);
-const gchar *	e_activity_get_secondary_text	(EActivity *activity);
-void		e_activity_set_secondary_text	(EActivity *activity,
-						 const gchar *secondary_text);
+EActivityState	e_activity_get_state		(EActivity *activity);
+void		e_activity_set_state		(EActivity *activity,
+						 EActivityState state);
+const gchar *	e_activity_get_text		(EActivity *activity);
+void		e_activity_set_text		(EActivity *activity,
+						 const gchar *text);
 
 G_END_DECLS
 
diff --git a/e-util/e-file-utils.c b/e-util/e-file-utils.c
index e647b8d..2d5ff30 100644
--- a/e-util/e-file-utils.c
+++ b/e-util/e-file-utils.c
@@ -51,40 +51,56 @@
 #include <glib/gstdio.h>
 #include <glib/gi18n-lib.h>
 
+#include "e-activity.h"
 #include "e-file-utils.h"
-#include "e-io-activity.h"
+
+typedef struct _AsyncContext AsyncContext;
+
+struct _AsyncContext {
+	EActivity *activity;
+	gchar *new_etag;
+};
+
+static void
+async_context_free (AsyncContext *context)
+{
+	if (context->activity != NULL)
+		g_object_unref (context->activity);
+
+	g_free (context->new_etag);
+
+	g_slice_free (AsyncContext, context);
+}
 
 static void
 file_replace_contents_cb (GFile *file,
                           GAsyncResult *result,
-                          EActivity *activity)
+                          GSimpleAsyncResult *simple)
 {
-	gchar *new_etag;
-	gboolean success;
+	AsyncContext *context;
+	gchar *new_etag = NULL;
 	GError *error = NULL;
 
-	success = g_file_replace_contents_finish (
-		file, result, &new_etag, &error);
+	context = g_simple_async_result_get_op_res_gpointer (simple);
 
-	result = e_io_activity_get_async_result (E_IO_ACTIVITY (activity));
+	g_file_replace_contents_finish (file, result, &new_etag, &error);
 
-	if (error == NULL) {
-		g_object_set_data_full (
-			G_OBJECT (result),
-			"__new_etag__", new_etag,
-			(GDestroyNotify) g_free);
-	} else {
-		g_simple_async_result_set_from_error (
-			G_SIMPLE_ASYNC_RESULT (result), error);
+	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+		e_activity_set_state (context->activity, E_ACTIVITY_CANCELLED);
+	else
+		e_activity_set_state (context->activity, E_ACTIVITY_COMPLETED);
+
+	if (error == NULL)
+		context->new_etag = new_etag;
+	else {
+		g_warn_if_fail (new_etag == NULL);
+		g_simple_async_result_set_from_error (simple, error);
 		g_error_free (error);
 	}
 
-	g_simple_async_result_set_op_res_gboolean (
-		G_SIMPLE_ASYNC_RESULT (result), success);
-
-	e_activity_complete (activity);
+	g_simple_async_result_complete (simple);
 
-	g_object_unref (activity);
+	g_object_unref (simple);
 }
 
 /**
@@ -115,9 +131,9 @@ e_file_replace_contents_async (GFile *file,
                                GAsyncReadyCallback callback,
                                gpointer user_data)
 {
-	EActivity *activity;
 	GSimpleAsyncResult *simple;
 	GCancellable *cancellable;
+	AsyncContext *context;
 	const gchar *format;
 	gchar *description;
 	gchar *basename;
@@ -148,21 +164,26 @@ e_file_replace_contents_async (GFile *file,
 
 	cancellable = g_cancellable_new ();
 
+	context = g_slice_new0 (AsyncContext);
+	context->activity = e_activity_new ();
+
+	e_activity_set_text (context->activity, description);
+	e_activity_set_cancellable (context->activity, cancellable);
+
 	simple = g_simple_async_result_new (
 		G_OBJECT (file), callback, user_data,
 		e_file_replace_contents_async);
 
-	activity = e_io_activity_new (
-		description, G_ASYNC_RESULT (simple), cancellable);
+	g_simple_async_result_set_op_res_gpointer (
+		simple, context, (GDestroyNotify) async_context_free);
 
 	g_file_replace_contents_async (
 		file, contents, length, etag,
 		make_backup, flags, cancellable,
 		(GAsyncReadyCallback) file_replace_contents_cb,
-		activity);
+		simple);
 
 	g_object_unref (cancellable);
-	g_object_unref (simple);
 
 	g_free (description);
 	g_free (basename);
@@ -170,7 +191,7 @@ e_file_replace_contents_async (GFile *file,
 	g_free (hostname);
 	g_free (uri);
 
-	return activity;
+	return context->activity;
 }
 
 /**
@@ -194,18 +215,19 @@ e_file_replace_contents_finish (GFile *file,
                                 GError **error)
 {
 	GSimpleAsyncResult *simple;
+	AsyncContext *context;
 
 	g_return_val_if_fail (G_IS_FILE (file), FALSE);
 	g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE);
 
 	simple = G_SIMPLE_ASYNC_RESULT (result);
+	context = g_simple_async_result_get_op_res_gpointer (simple);
 
 	if (g_simple_async_result_propagate_error (simple, error))
 		return FALSE;
 
 	if (new_etag != NULL)
-		*new_etag = g_object_steal_data (
-			G_OBJECT (result), "__new_etag__");
+		*new_etag = g_strdup (context->new_etag);
 
 	return TRUE;
 }
diff --git a/e-util/e-util-enums.h b/e-util/e-util-enums.h
new file mode 100644
index 0000000..bcf214e
--- /dev/null
+++ b/e-util/e-util-enums.h
@@ -0,0 +1,35 @@
+/*
+ * e-util-enums.h
+ *
+ * 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) version 3.
+ *
+ * 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 the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_UTIL_ENUMS_H
+#define E_UTIL_ENUMS_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+	E_ACTIVITY_RUNNING,
+	E_ACTIVITY_WAITING,
+	E_ACTIVITY_CANCELLED,
+	E_ACTIVITY_COMPLETED
+} EActivityState;
+
+G_END_DECLS
+
+#endif /* E_UTIL_ENUMS_H */
diff --git a/e-util/e-util.h b/e-util/e-util.h
index 9aa24f3..d4f29c9 100644
--- a/e-util/e-util.h
+++ b/e-util/e-util.h
@@ -29,6 +29,7 @@
 #include <gconf/gconf-client.h>
 
 #include <e-util/e-marshal.h>
+#include <e-util/e-util-enums.h>
 
 /* e_get_user_data_dir() used to live here, so #include its new home
  * for backward-compatibility (not that we really care about that). */
diff --git a/mail/e-mail-session.c b/mail/e-mail-session.c
index 2307680..7b726cf 100644
--- a/mail/e-mail-session.c
+++ b/mail/e-mail-session.c
@@ -96,7 +96,9 @@ enum {
 static gchar *mail_data_dir;
 static gchar *mail_config_dir;
 
+#if 0
 static MailMsgInfo ms_thread_info_dummy = { sizeof (MailMsg) };
+#endif
 
 G_DEFINE_TYPE (
 	EMailSession,
@@ -120,7 +122,9 @@ struct _user_message_msg {
 	guint ismain:1;
 };
 
-static void user_message_exec (struct _user_message_msg *m);
+static void user_message_exec (struct _user_message_msg *m,
+                               GCancellable *cancellable,
+                               GError **error);
 
 static void
 user_message_response_free (GtkDialog *dialog,
@@ -133,8 +137,11 @@ user_message_response_free (GtkDialog *dialog,
 
 	/* check for pendings */
 	if (!g_queue_is_empty (&user_message_queue)) {
+		GCancellable *cancellable;
+
 		m = g_queue_pop_head (&user_message_queue);
-		user_message_exec (m);
+		cancellable = e_activity_get_cancellable (m->base.activity);
+		user_message_exec (m, cancellable, &m->base.error);
 		mail_msg_unref (m);
 	}
 }
@@ -155,7 +162,9 @@ user_message_response (GtkDialog *dialog,
 }
 
 static void
-user_message_exec (struct _user_message_msg *m)
+user_message_exec (struct _user_message_msg *m,
+                   GCancellable *cancellable,
+                   GError **error)
 {
 	GtkWindow *parent;
 	const gchar *error_type;
@@ -716,6 +725,7 @@ mail_session_alert_user (CamelSession *session,
                          gboolean cancel)
 {
 	struct _user_message_msg *m;
+	GCancellable *cancellable;
 	gboolean result = TRUE;
 
 	m = mail_msg_new (&user_message_info);
@@ -728,8 +738,10 @@ mail_session_alert_user (CamelSession *session,
 	if (cancel)
 		mail_msg_ref (m);
 
+	cancellable = e_activity_get_cancellable (m->base.activity);
+
 	if (m->ismain)
-		user_message_exec (m);
+		user_message_exec (m, cancellable, &m->base.error);
 	else
 		mail_msg_main_loop_push (m);
 
@@ -788,6 +800,7 @@ mail_session_thread_msg_new (CamelSession *session,
 	session_class = CAMEL_SESSION_CLASS (e_mail_session_parent_class);
 	msg = session_class->thread_msg_new (session, ops, size);
 
+#if 0
 	/* We create a dummy mail_msg, and then copy its cancellation
 	 * port over to ours, so we get cancellation and progress in
 	 * common with hte existing mail code, for free. */
@@ -795,9 +808,10 @@ mail_session_thread_msg_new (CamelSession *session,
 		MailMsg *m = mail_msg_new (&ms_thread_info_dummy);
 
 		msg->data = m;
-		g_object_unref (msg->cancellable);
-		msg->cancellable = g_object_ref (m->cancellable);
+		e_activity_set_cancellable (
+			m->activity, msg->cancellable);
 	}
+#endif
 
 	return msg;
 }
@@ -808,7 +822,9 @@ mail_session_thread_msg_free (CamelSession *session,
 {
 	CamelSessionClass *session_class;
 
+#if 0
 	mail_msg_unref (msg->data);
+#endif
 
 	/* Chain up to parent's thread_msg_free() method. */
 	session_class = CAMEL_SESSION_CLASS (e_mail_session_parent_class);
@@ -821,8 +837,6 @@ mail_session_thread_status (CamelSession *session,
                             const gchar *text,
                             gint pc)
 {
-	/* This should never be called since we bypass it in alloc! */
-	g_warn_if_reached ();
 }
 
 static gboolean
diff --git a/mail/em-composer-utils.c b/mail/em-composer-utils.c
index 704bd2b..f084155 100644
--- a/mail/em-composer-utils.c
+++ b/mail/em-composer-utils.c
@@ -482,6 +482,7 @@ composer_send_completed (EMailSession *session,
 
 	/* Ignore cancellations. */
 	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+		e_activity_set_state (context->activity, E_ACTIVITY_CANCELLED);
 		g_error_free (error);
 		goto exit;
 	}
@@ -495,7 +496,7 @@ composer_send_completed (EMailSession *session,
 		goto exit;
 	}
 
-	e_activity_complete (context->activity);
+	e_activity_set_state (context->activity, E_ACTIVITY_COMPLETED);
 
 	/* Wait for the EActivity's completion message to
 	 * time out and then destroy the composer window. */
@@ -625,13 +626,16 @@ composer_save_draft_complete (EMailSession *session,
 
 	e_mail_session_handle_draft_headers_finish (session, result, &error);
 
-	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+		e_activity_set_state (context->activity, E_ACTIVITY_CANCELLED);
 		g_error_free (error);
 
-	else if (error != NULL) {
+	} else if (error != NULL) {
 		g_warning ("%s", error->message);
 		g_error_free (error);
-	}
+
+	} else
+		e_activity_set_state (context->activity, E_ACTIVITY_COMPLETED);
 
 	/* Encode the draft message we just saved into the EMsgComposer
 	 * as X-Evolution-Draft headers.  The message will be marked for
@@ -641,8 +645,6 @@ composer_save_draft_complete (EMailSession *session,
 		context->composer, context->folder_uri,
 		context->message_uid);
 
-	e_activity_complete (context->activity);
-
 	async_context_free (context);
 }
 
diff --git a/mail/em-folder-tree.c b/mail/em-folder-tree.c
index 15cf4a5..b08da8c 100644
--- a/mail/em-folder-tree.c
+++ b/mail/em-folder-tree.c
@@ -204,20 +204,24 @@ folder_tree_get_folder_info__desc (struct _EMFolderTreeGetFolderInfo *m)
 }
 
 static void
-folder_tree_get_folder_info__exec (struct _EMFolderTreeGetFolderInfo *m)
+folder_tree_get_folder_info__exec (struct _EMFolderTreeGetFolderInfo *m,
+                                   GCancellable *cancellable,
+                                   GError **error)
 {
 	guint32 flags = m->flags | CAMEL_STORE_FOLDER_INFO_SUBSCRIBED;
+	GError *local_error = NULL;
 
 	m->fi = camel_store_get_folder_info_sync (
-		m->store, m->top, flags,
-		m->base.cancellable, &m->base.error);
+		m->store, m->top, flags, cancellable, &local_error);
 
 	/* XXX POP3 stores always return an error because they have
 	 *     no folder hierarchy to scan.  Clear that error so the
 	 *     user doesn't see it. */
-	if (g_error_matches (m->base.error,
+	if (g_error_matches (local_error,
 		CAMEL_STORE_ERROR, CAMEL_STORE_ERROR_NO_FOLDER))
-		g_clear_error (&m->base.error);
+		g_error_free (local_error);
+	else if (local_error != NULL)
+		g_propagate_error (error, local_error);
 }
 
 static void
@@ -1741,6 +1745,7 @@ folder_tree_drop_folder (struct _DragDataReceivedAsync *m)
 {
 	CamelFolder *folder;
 	CamelStore *parent_store;
+	GCancellable *cancellable;
 	const gchar *full_name;
 	const guchar *data;
 
@@ -1748,9 +1753,11 @@ folder_tree_drop_folder (struct _DragDataReceivedAsync *m)
 
 	d(printf(" * Drop folder '%s' onto '%s'\n", data, m->full_name));
 
+	cancellable = e_activity_get_cancellable (m->base.activity);
+
 	folder = e_mail_session_uri_to_folder_sync (
 		m->session, (gchar *) data, 0,
-		m->base.cancellable, &m->base.error);
+		cancellable, &m->base.error);
 	if (folder == NULL)
 		return;
 
@@ -1801,7 +1808,9 @@ folder_tree_drop_async__desc (struct _DragDataReceivedAsync *m)
 }
 
 static void
-folder_tree_drop_async__exec (struct _DragDataReceivedAsync *m)
+folder_tree_drop_async__exec (struct _DragDataReceivedAsync *m,
+                              GCancellable *cancellable,
+                              GError **error)
 {
 	CamelFolder *folder;
 
@@ -1811,19 +1820,18 @@ folder_tree_drop_async__exec (struct _DragDataReceivedAsync *m)
 		folder_tree_drop_folder (m);
 	} else if (m->full_name == NULL) {
 		g_set_error (
-			&m->base.error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
+			error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
 			_("Cannot drop message(s) into toplevel store"));
 	} else if ((folder = camel_store_get_folder_sync (
-		m->store, m->full_name, 0,
-		m->base.cancellable, &m->base.error))) {
+		m->store, m->full_name, 0, cancellable, error))) {
 
 		switch (m->info) {
 		case DND_DROP_TYPE_UID_LIST:
 			/* import a list of uids from another evo folder */
 			em_utils_selection_get_uidlist (
 				m->selection, m->session, folder, m->move,
-				m->base.cancellable, &m->base.error);
-			m->moved = m->move && (m->base.error == NULL);
+				cancellable, error);
+			m->moved = m->move && (error == NULL);
 			break;
 		case DND_DROP_TYPE_MESSAGE_RFC822:
 			/* import a message/rfc822 stream */
diff --git a/mail/em-folder-utils.c b/mail/em-folder-utils.c
index 82f3de6..d457e90 100644
--- a/mail/em-folder-utils.c
+++ b/mail/em-folder-utils.c
@@ -93,18 +93,23 @@ emft_copy_folders__desc (struct _EMCopyFolders *m, gint complete)
 }
 
 static void
-emft_copy_folders__exec (struct _EMCopyFolders *m)
+emft_copy_folders__exec (struct _EMCopyFolders *m,
+                         GCancellable *cancellable,
+                         GError **error)
 {
-	guint32 flags = CAMEL_STORE_FOLDER_INFO_FAST | CAMEL_STORE_FOLDER_INFO_RECURSIVE | CAMEL_STORE_FOLDER_INFO_SUBSCRIBED;
+	guint32 flags;
 	GList *pending = NULL, *deleting = NULL, *l;
 	GString *fromname, *toname;
 	CamelFolderInfo *fi;
 	const gchar *tmp;
 	gint fromlen;
 
+	flags = CAMEL_STORE_FOLDER_INFO_FAST |
+		CAMEL_STORE_FOLDER_INFO_RECURSIVE |
+		CAMEL_STORE_FOLDER_INFO_SUBSCRIBED;
+
 	fi = camel_store_get_folder_info_sync (
-		m->fromstore, m->frombase, flags,
-		m->base.cancellable, &m->base.error);
+		m->fromstore, m->frombase, flags, cancellable, error);
 	if (fi == NULL)
 		return;
 
@@ -147,8 +152,8 @@ emft_copy_folders__exec (struct _EMCopyFolders *m)
 				if (m->tostore == m->fromstore && m->delete) {
 					camel_store_rename_folder_sync (
 						m->fromstore, info->full_name, toname->str,
-						m->base.cancellable, &m->base.error);
-					if (m->base.error != NULL)
+						cancellable, error);
+					if (error != NULL)
 						goto exception;
 
 					/* this folder no longer exists, unsubscribe it */
@@ -160,15 +165,14 @@ emft_copy_folders__exec (struct _EMCopyFolders *m)
 				} else {
 					fromfolder = camel_store_get_folder_sync (
 						m->fromstore, info->full_name, 0,
-						m->base.cancellable, &m->base.error);
+						cancellable, error);
 					if (fromfolder == NULL)
 						goto exception;
 
 					tofolder = camel_store_get_folder_sync (
 						m->tostore, toname->str,
 						CAMEL_STORE_FOLDER_CREATE,
-						m->base.cancellable,
-						&m->base.error);
+						cancellable, error);
 					if (tofolder == NULL) {
 						g_object_unref (fromfolder);
 						goto exception;
@@ -178,11 +182,10 @@ emft_copy_folders__exec (struct _EMCopyFolders *m)
 					camel_folder_transfer_messages_to_sync (
 						fromfolder, uids, tofolder,
 						m->delete, NULL,
-						m->base.cancellable,
-						&m->base.error);
+						cancellable, error);
 					camel_folder_free_uids (fromfolder, uids);
 
-					if (m->delete && m->base.error == NULL)
+					if (m->delete && error == NULL)
 						camel_folder_synchronize_sync (
 							fromfolder, TRUE,
 							NULL, NULL);
@@ -192,7 +195,7 @@ emft_copy_folders__exec (struct _EMCopyFolders *m)
 				}
 			}
 
-			if (m->base.error != NULL)
+			if (error != NULL)
 				goto exception;
 			else if (m->delete && !deleted)
 				deleting = g_list_prepend (deleting, info);
@@ -569,18 +572,17 @@ emfu_create_folder__desc (struct _EMCreateFolder *m)
 }
 
 static void
-emfu_create_folder__exec (struct _EMCreateFolder *m)
+emfu_create_folder__exec (struct _EMCreateFolder *m,
+                          GCancellable *cancellable,
+                          GError **error)
 {
-	d(printf ("creating folder parent='%s' name='%s' full_name='%s'\n", m->parent, m->name, m->full_name));
-
 	if ((m->fi = camel_store_create_folder_sync (
-		m->store, m->parent, m->name,
-		m->base.cancellable, &m->base.error))) {
+		m->store, m->parent, m->name, cancellable, error))) {
 
 		if (camel_store_supports_subscriptions (m->store))
 			camel_store_subscribe_folder_sync (
 				m->store, m->full_name,
-				m->base.cancellable, &m->base.error);
+				cancellable, error);
 	}
 }
 
@@ -766,7 +768,9 @@ emfu_unsubscribe_folder__desc (struct _folder_unsub_t *msg)
 }
 
 static void
-emfu_unsubscribe_folder__exec (struct _folder_unsub_t *msg)
+emfu_unsubscribe_folder__exec (struct _folder_unsub_t *msg,
+                               GCancellable *cancellable,
+                               GError **error)
 {
 	CamelStore *store;
 	CamelURL *url;
@@ -775,7 +779,7 @@ emfu_unsubscribe_folder__exec (struct _folder_unsub_t *msg)
 
 	store = camel_session_get_store (
 		CAMEL_SESSION (msg->session),
-		msg->folder_uri, &msg->base.error);
+		msg->folder_uri, error);
 	if (store == NULL)
 		return;
 
@@ -789,8 +793,7 @@ emfu_unsubscribe_folder__exec (struct _folder_unsub_t *msg)
 
 	if (path != NULL)
 		camel_store_unsubscribe_folder_sync (
-			store, path, msg->base.cancellable,
-			&msg->base.error);
+			store, path, cancellable, error);
 
 	camel_url_free (url);
 }
diff --git a/mail/em-format-html.c b/mail/em-format-html.c
index 1e3c6b9..de8c0b5 100644
--- a/mail/em-format-html.c
+++ b/mail/em-format-html.c
@@ -166,7 +166,9 @@ efh_format_desc (struct _format_msg *m)
 }
 
 static void
-efh_format_exec (struct _format_msg *m)
+efh_format_exec (struct _format_msg *m,
+                 GCancellable *cancellable,
+                 GError **error)
 {
 	EMFormat *format;
 	struct _EMFormatHTMLJob *job;
@@ -195,7 +197,7 @@ efh_format_exec (struct _format_msg *m)
 	if (format->mode == EM_FORMAT_MODE_SOURCE) {
 		em_format_format_source (
 			format, (CamelStream *) m->estream,
-			(CamelMimePart *) m->message, m->base.cancellable);
+			(CamelMimePart *) m->message, cancellable);
 	} else {
 		const EMFormatHandler *handle;
 		const gchar *mime_type;
@@ -207,7 +209,7 @@ efh_format_exec (struct _format_msg *m)
 			handle->handler (
 				format, CAMEL_STREAM (m->estream),
 				CAMEL_MIME_PART (m->message), handle,
-				m->base.cancellable, FALSE);
+				cancellable, FALSE);
 
 		mime_type = "x-evolution/message/rfc822";
 		handle = em_format_find_handler (format, mime_type);
@@ -216,10 +218,10 @@ efh_format_exec (struct _format_msg *m)
 			handle->handler (
 				format, CAMEL_STREAM (m->estream),
 				CAMEL_MIME_PART (m->message), handle,
-				m->base.cancellable, FALSE);
+				cancellable, FALSE);
 	}
 
-	camel_stream_flush ((CamelStream *)m->estream, m->base.cancellable, NULL);
+	camel_stream_flush ((CamelStream *)m->estream, cancellable, NULL);
 
 	puri_level = format->pending_uri_level;
 	base = format->base;
@@ -232,13 +234,13 @@ efh_format_exec (struct _format_msg *m)
 
 			/* This is an implicit check to see if the gtkhtml has been destroyed */
 			if (m->format->priv->web_view == NULL)
-				g_cancellable_cancel (m->base.cancellable);
+				g_cancellable_cancel (cancellable);
 
 			/* call jobs even if cancelled, so they can clean up resources */
 			format->pending_uri_level = job->puri_level;
 			if (job->base)
 				format->base = job->base;
-			job->callback (job, m->base.cancellable);
+			job->callback (job, cancellable);
 			format->base = base;
 
 			/* clean up the job */
@@ -257,8 +259,8 @@ efh_format_exec (struct _format_msg *m)
 			d(printf("out of jobs, closing root stream\n"));
 			camel_stream_write_string (
 				(CamelStream *) m->estream,
-				"</body>\n</html>\n", m->base.cancellable, NULL);
-			camel_stream_close ((CamelStream *)m->estream, m->base.cancellable, NULL);
+				"</body>\n</html>\n", cancellable, NULL);
+			camel_stream_close ((CamelStream *)m->estream, cancellable, NULL);
 			g_object_unref (m->estream);
 			m->estream = NULL;
 		}
@@ -287,7 +289,7 @@ efh_format_free (struct _format_msg *m)
 	d(printf("formatter freed\n"));
 	g_object_unref (m->format);
 	if (m->estream) {
-		camel_stream_close ((CamelStream *)m->estream, m->base.cancellable, NULL);
+		camel_stream_close ((CamelStream *)m->estream, NULL, NULL);
 		g_object_unref (m->estream);
 	}
 	if (m->folder)
diff --git a/mail/importers/elm-importer.c b/mail/importers/elm-importer.c
index 18548fc..292d7c3 100644
--- a/mail/importers/elm-importer.c
+++ b/mail/importers/elm-importer.c
@@ -184,7 +184,9 @@ static MailImporterSpecial elm_special_folders[] = {
 };
 
 static void
-elm_import_exec (struct _elm_import_msg *m)
+elm_import_exec (struct _elm_import_msg *m,
+                 GCancellable *cancellable,
+                 GError **error)
 {
 	EShell *shell;
 	EShellBackend *shell_backend;
diff --git a/mail/importers/mail-importer.c b/mail/importers/mail-importer.c
index b4fb3c0..7eaed47 100644
--- a/mail/importers/mail-importer.c
+++ b/mail/importers/mail-importer.c
@@ -107,7 +107,9 @@ decode_mozilla_status (const gchar *tmp)
 }
 
 static void
-import_mbox_exec (struct _import_mbox_msg *m)
+import_mbox_exec (struct _import_mbox_msg *m,
+                  GCancellable *cancellable,
+                  GError **error)
 {
 	CamelFolder *folder;
 	CamelMimeParser *mp = NULL;
@@ -125,7 +127,7 @@ import_mbox_exec (struct _import_mbox_msg *m)
 	else
 		folder = e_mail_session_uri_to_folder_sync (
 			m->session, m->uri, CAMEL_STORE_FOLDER_CREATE,
-			m->base.cancellable, &m->base.error);
+			cancellable, error);
 
 	if (folder == NULL)
 		return;
@@ -144,7 +146,7 @@ import_mbox_exec (struct _import_mbox_msg *m)
 		}
 
 		camel_operation_push_message (
-			m->base.cancellable, _("Importing '%s'"),
+			cancellable, _("Importing '%s'"),
 			camel_folder_get_full_name (folder));
 		camel_folder_freeze (folder);
 		while (camel_mime_parser_step (mp, NULL, NULL) == CAMEL_MIME_PARSER_STATE_FROM) {
@@ -155,7 +157,7 @@ import_mbox_exec (struct _import_mbox_msg *m)
 
 			if (st.st_size > 0)
 				pc = (gint)(100.0 * ((double)camel_mime_parser_tell (mp) / (double)st.st_size));
-			camel_operation_progress (m->base.cancellable, pc);
+			camel_operation_progress (cancellable, pc);
 
 			msg = camel_mime_message_new ();
 			if (!camel_mime_part_construct_from_parser_sync (
@@ -180,11 +182,11 @@ import_mbox_exec (struct _import_mbox_msg *m)
 			camel_message_info_set_flags (info, flags, ~0);
 			camel_folder_append_message_sync (
 				folder, msg, info, NULL,
-				m->base.cancellable, &m->base.error);
+				cancellable, error);
 			camel_message_info_free (info);
 			g_object_unref (msg);
 
-			if (m->base.error != NULL)
+			if (error != NULL)
 				break;
 
 			camel_mime_parser_step (mp, NULL, NULL);
@@ -192,7 +194,7 @@ import_mbox_exec (struct _import_mbox_msg *m)
 		/* FIXME Not passing a GCancellable or GError here. */
 		camel_folder_synchronize_sync (folder, FALSE, NULL, NULL);
 		camel_folder_thaw (folder);
-		camel_operation_pop_message (m->base.cancellable);
+		camel_operation_pop_message (cancellable);
 		/* TODO: these api's are a bit weird, registering the old is the same as deregistering */
 	fail2:
 		g_object_unref (mp);
@@ -267,9 +269,11 @@ mail_importer_import_mbox_sync (EMailSession *session,
 	m->path = g_strdup (path);
 	m->uri = g_strdup (folderuri);
 	if (cancellable)
-		m->cancellable = g_object_ref (cancellable);
+		e_activity_set_cancellable (m->base.activity, cancellable);
+
+	cancellable = e_activity_get_cancellable (m->base.activity);
 
-	import_mbox_exec (m);
+	import_mbox_exec (m, cancellable, &m->base.error);
 	import_mbox_done (m);
 	mail_msg_unref (m);
 }
diff --git a/mail/importers/pine-importer.c b/mail/importers/pine-importer.c
index 26a37b8..e7ace0b 100644
--- a/mail/importers/pine-importer.c
+++ b/mail/importers/pine-importer.c
@@ -230,7 +230,9 @@ static MailImporterSpecial pine_special_folders[] = {
 };
 
 static void
-pine_import_exec (struct _pine_import_msg *m)
+pine_import_exec (struct _pine_import_msg *m,
+                  GCancellable *cancellable,
+                  GError **error)
 {
 	EShell *shell;
 	EShellBackend *shell_backend;
diff --git a/mail/mail-folder-cache.c b/mail/mail-folder-cache.c
index 85b60ad..8b19da4 100644
--- a/mail/mail-folder-cache.c
+++ b/mail/mail-folder-cache.c
@@ -795,7 +795,9 @@ ping_store_desc (struct _ping_store_msg *m)
 }
 
 static void
-ping_store_exec (struct _ping_store_msg *m)
+ping_store_exec (struct _ping_store_msg *m,
+                 GCancellable *cancellable,
+                 GError **error)
 {
 	gboolean online = FALSE;
 
@@ -810,8 +812,7 @@ ping_store_exec (struct _ping_store_msg *m)
 			online = TRUE;
 	}
 	if (online)
-		camel_store_noop_sync (
-			m->store, m->base.cancellable, &m->base.error);
+		camel_store_noop_sync (m->store, cancellable, error);
 }
 
 static void
diff --git a/mail/mail-mt.c b/mail/mail-mt.c
index 907d579..8e507e4 100644
--- a/mail/mail-mt.c
+++ b/mail/mail-mt.c
@@ -38,11 +38,6 @@
  *     to rework or get rid of the functions that use this. */
 const gchar *shell_builtin_backend = "mail";
 
-/* background operation status stuff */
-struct _MailMsgPrivate {
-	EActivity *activity;
-};
-
 static guint mail_msg_seq; /* sequence number of each message */
 
 /* Table of active messages.  Must hold mail_msg_lock to access. */
@@ -76,6 +71,7 @@ gpointer
 mail_msg_new (MailMsgInfo *info)
 {
 	MailMsg *msg;
+	GCancellable *cancellable;
 
 	g_mutex_lock (mail_msg_lock);
 
@@ -83,22 +79,20 @@ mail_msg_new (MailMsgInfo *info)
 	msg->info = info;
 	msg->ref_count = 1;
 	msg->seq = mail_msg_seq++;
-	msg->cancellable = camel_operation_new ();
-
-	msg->priv = g_slice_new0 (MailMsgPrivate);
-	msg->priv->activity = e_activity_new ();
+	msg->activity = e_activity_new ();
 
-	e_activity_set_percent (msg->priv->activity, 0.0);
+	cancellable = camel_operation_new ();
 
-	e_activity_set_cancellable (
-		msg->priv->activity,
-		G_CANCELLABLE (msg->cancellable));
+	e_activity_set_percent (msg->activity, 0.0);
+	e_activity_set_cancellable (msg->activity, cancellable);
 
 	g_signal_connect (
-		msg->cancellable, "cancelled",
+		cancellable, "cancelled",
 		G_CALLBACK (mail_msg_cancelled),
 		GINT_TO_POINTER (msg->seq));
 
+	g_object_unref (cancellable);
+
 	g_hash_table_insert (
 		mail_msg_active_table, GINT_TO_POINTER (msg->seq), msg);
 
@@ -145,18 +139,12 @@ mail_msg_free (MailMsg *mail_msg)
 	shell_backend = e_shell_get_backend_by_name (
 		shell, shell_builtin_backend);
 
-	if (mail_msg->priv->activity != NULL) {
-		e_activity_complete (mail_msg->priv->activity);
-		g_object_unref (mail_msg->priv->activity);
-	}
-
-	if (mail_msg->cancellable != NULL)
-		g_object_unref (mail_msg->cancellable);
+	if (mail_msg->activity != NULL)
+		g_object_unref (mail_msg->activity);
 
 	if (mail_msg->error != NULL)
 		g_error_free (mail_msg->error);
 
-	g_slice_free (MailMsgPrivate, mail_msg->priv);
 	g_slice_free1 (mail_msg->info->size, mail_msg);
 
 	return FALSE;
@@ -226,9 +214,21 @@ mail_msg_check_error (gpointer msg)
 	checkmem (m->priv);
 #endif
 
-	if (m->error == NULL
-	    || g_error_matches (m->error, G_IO_ERROR, G_IO_ERROR_CANCELLED)
-	    || g_error_matches (m->error, CAMEL_FOLDER_ERROR, CAMEL_FOLDER_ERROR_INVALID_UID))
+	if (g_error_matches (m->error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+		e_activity_set_state (m->activity, E_ACTIVITY_CANCELLED);
+		return;
+	}
+
+	e_activity_set_state (m->activity, E_ACTIVITY_COMPLETED);
+
+	if (m->error == NULL)
+		return;
+
+	/* XXX Hmm, no explanation of why this is needed.  It looks like
+	 *     a lame hack and will be removed at some point, if only to
+	 *     reintroduce whatever issue made this necessary so we can
+	 *     document it the source code this time. */
+	if (g_error_matches (m->error, CAMEL_FOLDER_ERROR, CAMEL_FOLDER_ERROR_INVALID_UID))
 		return;
 
 	shell = e_shell_get_default ();
@@ -250,8 +250,7 @@ mail_msg_check_error (gpointer msg)
 		shell_window, shell_builtin_backend);
 	shell_content = e_shell_view_get_shell_content (shell_view);
 
-	if (m->info->desc
-	    && (what = m->info->desc (m))) {
+	if (m->info->desc && (what = m->info->desc (m))) {
 		e_alert_submit (
 			GTK_WIDGET (shell_content),
 			"mail:async-error", what,
@@ -277,8 +276,13 @@ mail_msg_cancel (guint msgid)
 
 	/* Hold a reference to the GCancellable so it doesn't finalize
 	 * itself on us between unlocking the mutex and cancelling. */
-	if (msg != NULL && !g_cancellable_is_cancelled (msg->cancellable))
-		cancellable = g_object_ref (msg->cancellable);
+	if (msg != NULL) {
+		cancellable = e_activity_get_cancellable (msg->activity);
+		if (g_cancellable_is_cancelled (cancellable))
+			cancellable = NULL;
+		else
+			g_object_ref (cancellable);
+	}
 
 	g_mutex_unlock (mail_msg_lock);
 
@@ -368,13 +372,17 @@ mail_msg_idle_cb (void)
 	G_UNLOCK (idle_source_id);
 	/* check the main loop queue */
 	while ((msg = g_async_queue_try_pop (main_loop_queue)) != NULL) {
+		GCancellable *cancellable;
+
+		cancellable = e_activity_get_cancellable (msg->activity);
+
 		g_idle_add_full (
 			G_PRIORITY_DEFAULT,
 			(GSourceFunc) mail_msg_submit,
-			g_object_ref (msg->priv->activity),
+			g_object_ref (msg->activity),
 			(GDestroyNotify) g_object_unref);
 		if (msg->info->exec != NULL)
-			msg->info->exec (msg);
+			msg->info->exec (msg, cancellable, &msg->error);
 		if (msg->info->done != NULL)
 			msg->info->done (msg);
 		mail_msg_unref (msg);
@@ -393,23 +401,27 @@ mail_msg_idle_cb (void)
 static void
 mail_msg_proxy (MailMsg *msg)
 {
+	GCancellable *cancellable;
+
+	cancellable = e_activity_get_cancellable (msg->activity);
+
 	if (msg->info->desc != NULL) {
 		gchar *text = msg->info->desc (msg);
-		camel_operation_push_message (msg->cancellable, "%s", text);
+		camel_operation_push_message (cancellable, "%s", text);
 		g_free (text);
 	}
 
 	g_idle_add_full (
 		G_PRIORITY_DEFAULT,
 		(GSourceFunc) mail_msg_submit,
-		g_object_ref (msg->priv->activity),
+		g_object_ref (msg->activity),
 		(GDestroyNotify) g_object_unref);
 
 	if (msg->info->exec != NULL)
-		msg->info->exec (msg);
+		msg->info->exec (msg, cancellable, &msg->error);
 
 	if (msg->info->desc != NULL)
-		camel_operation_pop_message (msg->cancellable);
+		camel_operation_pop_message (cancellable);
 
 	g_async_queue_push (msg_reply_queue, msg);
 
@@ -522,7 +534,9 @@ struct _call_msg {
 };
 
 static void
-do_call (struct _call_msg *m)
+do_call (struct _call_msg *m,
+         GCancellable *cancellable,
+         GError **error)
 {
 	gpointer p1, *p2, *p3, *p4, *p5;
 	gint i1;
@@ -572,6 +586,11 @@ do_call (struct _call_msg *m)
 		break;
 	}
 
+	e_activity_set_state (
+		m->base.activity,
+		g_cancellable_is_cancelled (cancellable) ?
+		E_ACTIVITY_CANCELLED : E_ACTIVITY_COMPLETED);
+
 	if (m->done != NULL)
 		e_flag_set (m->done);
 }
@@ -587,6 +606,7 @@ static MailMsgInfo mail_call_info = {
 gpointer
 mail_call_main (mail_call_t type, MailMainFunc func, ...)
 {
+	GCancellable *cancellable;
 	struct _call_msg *m;
 	gpointer ret;
 	va_list ap;
@@ -598,8 +618,10 @@ mail_call_main (mail_call_t type, MailMainFunc func, ...)
 	m->func = func;
 	G_VA_COPY (m->ap, ap);
 
+	cancellable = e_activity_get_cancellable (m->base.activity);
+
 	if (mail_in_main_thread ())
-		do_call (m);
+		do_call (m, cancellable, &m->base.error);
 	else {
 		mail_msg_ref (m);
 		m->done = e_flag_new ();
diff --git a/mail/mail-mt.h b/mail/mail-mt.h
index 1225191..0b59507 100644
--- a/mail/mail-mt.h
+++ b/mail/mail-mt.h
@@ -24,25 +24,26 @@
 #define _MAIL_MT
 
 #include <camel/camel.h>
+#include <e-util/e-activity.h>
 
 typedef struct _MailMsg MailMsg;
 typedef struct _MailMsgInfo MailMsgInfo;
-typedef struct _MailMsgPrivate MailMsgPrivate;
 
-typedef gchar *	(*MailMsgDescFunc)	(MailMsg *msg);
-typedef void	(*MailMsgExecFunc)	(MailMsg *msg);
-typedef void	(*MailMsgDoneFunc)	(MailMsg *msg);
-typedef void	(*MailMsgFreeFunc)	(MailMsg *msg);
-typedef void	(*MailMsgDispatchFunc)	(gpointer msg);
+typedef gchar *	(*MailMsgDescFunc)		(MailMsg *msg);
+typedef void	(*MailMsgExecFunc)		(MailMsg *msg,
+						 GCancellable *cancellable,
+						 GError **error);
+typedef void	(*MailMsgDoneFunc)		(MailMsg *msg);
+typedef void	(*MailMsgFreeFunc)		(MailMsg *msg);
+typedef void	(*MailMsgDispatchFunc)		(gpointer msg);
 
 struct _MailMsg {
 	MailMsgInfo *info;
 	volatile gint ref_count;
 	guint seq;			/* seq number for synchronisation */
 	gint priority;			/* priority (default = 0) */
-	GCancellable *cancellable;	/* a cancellation/status handle */
+	EActivity *activity;
 	GError *error;			/* up to the caller to use this */
-	MailMsgPrivate *priv;
 };
 
 struct _MailMsgInfo {
diff --git a/mail/mail-ops.c b/mail/mail-ops.c
index 2cdce4c..ce219ed 100644
--- a/mail/mail-ops.c
+++ b/mail/mail-ops.c
@@ -88,7 +88,9 @@ em_filter_folder_element_desc (struct _filter_mail_msg *m)
 /* filter a folder, or a subset thereof, uses source_folder/source_uids */
 /* this is shared with fetch_mail */
 static void
-em_filter_folder_element_exec (struct _filter_mail_msg *m)
+em_filter_folder_element_exec (struct _filter_mail_msg *m,
+                               GCancellable *cancellable,
+                               GError **error)
 {
 	CamelFolder *folder;
 	GPtrArray *uids, *folder_uids = NULL;
@@ -112,8 +114,8 @@ em_filter_folder_element_exec (struct _filter_mail_msg *m)
 
 	camel_filter_driver_filter_folder (
 		m->driver, folder, m->cache, uids, m->delete,
-		m->base.cancellable, &m->base.error);
-	camel_filter_driver_flush (m->driver, &m->base.error);
+		cancellable, error);
+	camel_filter_driver_flush (m->driver, error);
 
 	if (folder_uids)
 		camel_folder_free_uids (folder, folder_uids);
@@ -121,7 +123,7 @@ em_filter_folder_element_exec (struct _filter_mail_msg *m)
 	/* sync our source folder */
 	if (!m->cache)
 		camel_folder_synchronize_sync (
-			folder, FALSE, m->base.cancellable, &m->base.error);
+			folder, FALSE, cancellable, error);
 	camel_folder_thaw (folder);
 
 	if (m->destination)
@@ -225,7 +227,9 @@ fetch_mail_desc (struct _fetch_mail_msg *m)
 }
 
 static void
-fetch_mail_exec (struct _fetch_mail_msg *m)
+fetch_mail_exec (struct _fetch_mail_msg *m,
+                 GCancellable *cancellable,
+                 GError **error)
 {
 	struct _filter_mail_msg *fm = (struct _filter_mail_msg *)m;
 	gint i;
@@ -238,18 +242,18 @@ fetch_mail_exec (struct _fetch_mail_msg *m)
 	/* FIXME: this should support keep_on_server too, which would then perform a spool
 	   access thingy, right?  problem is matching raw messages to uid's etc. */
 	if (!strncmp (m->source_uri, "mbox:", 5)) {
-		gchar *path = mail_tool_do_movemail (m->source_uri, &fm->base.error);
+		gchar *path = mail_tool_do_movemail (m->source_uri, error);
 
-		if (path && fm->base.error == NULL) {
+		if (path && error == NULL) {
 			camel_folder_freeze (fm->destination);
 			camel_filter_driver_set_default_folder (
 				fm->driver, fm->destination);
 			camel_filter_driver_filter_mbox (
 				fm->driver, path, m->source_uri,
-				fm->base.cancellable, &fm->base.error);
+				cancellable, error);
 			camel_folder_thaw (fm->destination);
 
-			if (fm->base.error == NULL)
+			if (error == NULL)
 				g_unlink (path);
 		}
 		g_free (path);
@@ -259,7 +263,7 @@ fetch_mail_exec (struct _fetch_mail_msg *m)
 		folder = fm->source_folder =
 			e_mail_session_get_inbox_sync (
 				fm->session, m->source_uri,
-				fm->base.cancellable, &fm->base.error);
+				cancellable, error);
 
 		if (folder) {
 			/* this handles 'keep on server' stuff, if we have any new uid's to copy
@@ -287,7 +291,7 @@ fetch_mail_exec (struct _fetch_mail_msg *m)
 					camel_uid_cache_free_uids (cache_uids);
 
 					fm->cache = cache;
-					em_filter_folder_element_exec (fm);
+					em_filter_folder_element_exec (fm, cancellable, error);
 
 					/* need to uncancel so writes/etc. don't fail */
 					if (g_cancellable_is_cancelled (m->cancellable))
@@ -297,7 +301,7 @@ fetch_mail_exec (struct _fetch_mail_msg *m)
 					camel_uid_cache_save (cache);
 				}
 
-				if (fm->delete && fm->base.error == NULL) {
+				if (fm->delete && error == NULL) {
 					/* not keep on server - just delete all the actual messages on the server */
 					for (i=0;i<folder_uids->len;i++) {
 						d(printf("force delete uid '%s'\n", (gchar *)folder_uids->pdata[i]));
@@ -305,7 +309,7 @@ fetch_mail_exec (struct _fetch_mail_msg *m)
 					}
 				}
 
-				if ((fm->delete || cache_uids) && fm->base.error == NULL) {
+				if ((fm->delete || cache_uids) && error == NULL) {
 					/* expunge messages (downloaded so far) */
 					/* FIXME Not passing a GCancellable or GError here. */
 					camel_folder_synchronize_sync (
@@ -315,7 +319,7 @@ fetch_mail_exec (struct _fetch_mail_msg *m)
 				camel_uid_cache_destroy (cache);
 				camel_folder_free_uids (folder, folder_uids);
 			} else {
-				em_filter_folder_element_exec (fm);
+				em_filter_folder_element_exec (fm, cancellable, error);
 			}
 
 			/* we unref the source folder here since we
@@ -444,7 +448,6 @@ struct _send_queue_msg {
 	gchar *destination;
 
 	CamelFilterDriver *driver;
-	GCancellable *cancellable;
 
 	/* we use camelfilterstatusfunc, even though its not the filter doing it */
 	CamelFilterStatusFunc *status;
@@ -732,7 +735,9 @@ report_status (struct _send_queue_msg *m, enum camel_filter_status_t status, gin
 }
 
 static void
-send_queue_exec (struct _send_queue_msg *m)
+send_queue_exec (struct _send_queue_msg *m,
+                 GCancellable *cancellable,
+                 GError **error)
 {
 	CamelFolder *sent_folder;
 	GPtrArray *uids, *send_uids = NULL;
@@ -766,7 +771,7 @@ send_queue_exec (struct _send_queue_msg *m)
 		return;
 	}
 
-	camel_operation_push_message (m->cancellable, _("Sending message"));
+	camel_operation_push_message (cancellable, _("Sending message"));
 
 	/* NB: This code somewhat abuses the 'exception' stuff.  Apart from
 	 *     fatal problems, it is also used as a mechanism to accumualte
@@ -780,13 +785,12 @@ send_queue_exec (struct _send_queue_msg *m)
 			_("Sending message %d of %d"), i+1,
 			send_uids->len);
 
-		if (!m->cancellable)
-			camel_operation_progress (
-				m->cancellable, (i+1) * 100 / send_uids->len);
+		camel_operation_progress (
+			cancellable, (i+1) * 100 / send_uids->len);
 
 		mail_send_message (
 			m, m->queue, send_uids->pdata[i], m->destination,
-			m->driver, m->base.cancellable, &local_error);
+			m->driver, cancellable, &local_error);
 		if (local_error != NULL) {
 			if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
 				/* merge exceptions into one */
@@ -846,7 +850,7 @@ send_queue_exec (struct _send_queue_msg *m)
 	if (sent_folder)
 		camel_folder_synchronize_sync (sent_folder, FALSE, NULL, NULL);
 
-	camel_operation_pop_message (m->cancellable);
+	camel_operation_pop_message (cancellable);
 }
 
 static void
@@ -871,8 +875,6 @@ send_queue_free (struct _send_queue_msg *m)
 		g_object_unref (m->driver);
 	g_object_unref (m->queue);
 	g_free (m->destination);
-	if (m->cancellable)
-		g_object_unref (m->cancellable);
 }
 
 static MailMsgInfo send_queue_info = {
@@ -903,11 +905,8 @@ mail_send_queue (EMailSession *session,
 	m->session = g_object_ref (session);
 	m->queue = g_object_ref (queue);
 	m->destination = g_strdup (destination);
-	if (G_IS_CANCELLABLE (cancellable)) {
-		m->cancellable = g_object_ref (cancellable);
-		g_object_unref (m->base.cancellable);
-		m->base.cancellable = NULL;
-	}
+	if (G_IS_CANCELLABLE (cancellable))
+		e_activity_set_cancellable (m->base.activity, cancellable);
 	m->status = status;
 	m->status_data = status_data;
 	m->done = done;
@@ -941,7 +940,9 @@ append_mail_desc (struct _append_msg *m)
 }
 
 static void
-append_mail_exec (struct _append_msg *m)
+append_mail_exec (struct _append_msg *m,
+                  GCancellable *cancellable,
+                  GError **error)
 {
 	camel_mime_message_set_date (
 		m->message, CAMEL_MESSAGE_DATE_CURRENT, 0);
@@ -949,7 +950,7 @@ append_mail_exec (struct _append_msg *m)
 	camel_folder_append_message_sync (
 		m->folder, m->message,
 		m->info, &m->appended_uid,
-		m->base.cancellable, &m->base.error);
+		cancellable, error);
 }
 
 static void
@@ -1029,13 +1030,15 @@ transfer_messages_desc (struct _transfer_msg *m)
 }
 
 static void
-transfer_messages_exec (struct _transfer_msg *m)
+transfer_messages_exec (struct _transfer_msg *m,
+                        GCancellable *cancellable,
+                        GError **error)
 {
 	CamelFolder *dest;
 
 	dest = e_mail_session_uri_to_folder_sync (
 		m->session, m->dest_uri, m->dest_flags,
-		m->base.cancellable, &m->base.error);
+		cancellable, error);
 	if (dest == NULL)
 		return;
 
@@ -1050,7 +1053,7 @@ transfer_messages_exec (struct _transfer_msg *m)
 
 	camel_folder_transfer_messages_to_sync (
 		m->source, m->uids, dest, m->delete, NULL,
-		m->base.cancellable, &m->base.error);
+		cancellable, error);
 
 	/* make sure all deleted messages are marked as seen */
 
@@ -1148,13 +1151,19 @@ get_folderinfo_desc (struct _get_folderinfo_msg *m)
 }
 
 static void
-get_folderinfo_exec (struct _get_folderinfo_msg *m)
+get_folderinfo_exec (struct _get_folderinfo_msg *m,
+                     GCancellable *cancellable,
+                     GError **error)
 {
-	guint32 flags = CAMEL_STORE_FOLDER_INFO_RECURSIVE|CAMEL_STORE_FOLDER_INFO_FAST | CAMEL_STORE_FOLDER_INFO_SUBSCRIBED;
+	guint32 flags;
+
+	flags = CAMEL_STORE_FOLDER_INFO_RECURSIVE |
+		CAMEL_STORE_FOLDER_INFO_FAST |
+		CAMEL_STORE_FOLDER_INFO_SUBSCRIBED;
 
 	m->info = camel_store_get_folder_info_sync (
 		m->store, NULL, flags,
-		m->base.cancellable, &m->base.error);
+		cancellable, error);
 }
 
 static void
@@ -1201,10 +1210,8 @@ mail_get_folderinfo (CamelStore *store,
 	gint id;
 
 	m = mail_msg_new (&get_folderinfo_info);
-	if (G_IS_CANCELLABLE (cancellable)) {
-		g_object_unref (m->base.cancellable);
-		m->base.cancellable = g_object_ref (cancellable);
-	}
+	if (G_IS_CANCELLABLE (cancellable))
+		e_activity_set_cancellable (m->base.activity, cancellable);
 	m->store = store;
 	g_object_ref (store);
 	m->done = done;
@@ -1300,11 +1307,13 @@ get_folder_desc (struct _get_folder_msg *m)
 }
 
 static void
-get_folder_exec (struct _get_folder_msg *m)
+get_folder_exec (struct _get_folder_msg *m,
+                 GCancellable *cancellable,
+                 GError **error)
 {
 	m->folder = e_mail_session_uri_to_folder_sync (
 		m->session, m->uri, m->flags,
-		m->base.cancellable, &m->base.error);
+		cancellable, error);
 }
 
 static void
@@ -1373,7 +1382,9 @@ get_quota_desc (struct _get_quota_msg *m)
 }
 
 static void
-get_quota_exec (struct _get_quota_msg *m)
+get_quota_exec (struct _get_quota_msg *m,
+                GCancellable *cancellable,
+                GError **error)
 {
 	m->quota = camel_folder_get_quota_info (m->folder);
 }
@@ -1446,13 +1457,15 @@ get_store_desc (struct _get_store_msg *m)
 }
 
 static void
-get_store_exec (struct _get_store_msg *m)
+get_store_exec (struct _get_store_msg *m,
+                GCancellable *cancellable,
+                GError **error)
 {
 	/*camel_session_get_store connects us, which we don't want to do on startup. */
 
 	m->store = (CamelStore *) camel_session_get_service (
 		CAMEL_SESSION (m->session), m->uri,
-		CAMEL_PROVIDER_STORE, &m->base.error);
+		CAMEL_PROVIDER_STORE, error);
 }
 
 static void
@@ -1490,10 +1503,8 @@ mail_get_store (EMailSession *session,
 	gint id;
 
 	m = mail_msg_new (&get_store_info);
-	if (G_IS_CANCELLABLE (cancellable)) {
-		g_object_unref (m->base.cancellable);
-		m->base.cancellable = g_object_ref (cancellable);
-	}
+	if (G_IS_CANCELLABLE (cancellable))
+		e_activity_set_cancellable (m->base.activity, cancellable);
 	m->session = g_object_ref (session);
 	m->uri = g_strdup (uri);
 	m->data = data;
@@ -1579,7 +1590,9 @@ remove_folder_rec (CamelStore *store,
 }
 
 static void
-remove_folder_exec (struct _remove_folder_msg *m)
+remove_folder_exec (struct _remove_folder_msg *m,
+                    GCancellable *cancellable,
+                    GError **error)
 {
 	CamelFolderInfo *fi;
 	CamelStore *parent_store;
@@ -1595,13 +1608,12 @@ remove_folder_exec (struct _remove_folder_msg *m)
 		CAMEL_STORE_FOLDER_INFO_RECURSIVE |
 		CAMEL_STORE_FOLDER_INFO_FAST |
 		CAMEL_STORE_FOLDER_INFO_SUBSCRIBED,
-		m->base.cancellable,
-		&m->base.error);
+		cancellable, error);
 	if (fi == NULL)
 		return;
 
 	m->removed = remove_folder_rec (
-		parent_store, fi, m->base.cancellable, &m->base.error);
+		parent_store, fi, cancellable, error);
 	camel_store_free_folder_info (parent_store, fi);
 }
 
@@ -1660,10 +1672,12 @@ sync_folder_desc (struct _sync_folder_msg *m)
 }
 
 static void
-sync_folder_exec (struct _sync_folder_msg *m)
+sync_folder_exec (struct _sync_folder_msg *m,
+                  GCancellable *cancellable,
+                  GError **error)
 {
 	camel_folder_synchronize_sync (
-		m->folder, FALSE, m->base.cancellable, &m->base.error);
+		m->folder, FALSE, cancellable, error);
 }
 
 static void
@@ -1728,11 +1742,13 @@ sync_store_desc (struct _sync_store_msg *m)
 }
 
 static void
-sync_store_exec (struct _sync_store_msg *m)
+sync_store_exec (struct _sync_store_msg *m,
+                 GCancellable *cancellable,
+                 GError **error)
 {
 	camel_store_synchronize_sync (
 		m->store, m->expunge,
-		m->base.cancellable, &m->base.error);
+		cancellable, error);
 }
 
 static void
@@ -1780,10 +1796,12 @@ refresh_folder_desc (struct _sync_folder_msg *m)
 }
 
 static void
-refresh_folder_exec (struct _sync_folder_msg *m)
+refresh_folder_exec (struct _sync_folder_msg *m,
+                     GCancellable *cancellable,
+                     GError **error)
 {
 	camel_folder_refresh_info_sync (
-		m->folder, m->base.cancellable, &m->base.error);
+		m->folder, cancellable, error);
 }
 
 /* we just use the sync stuff where we can, since it would be the same */
@@ -1818,10 +1836,11 @@ expunge_folder_desc (struct _sync_folder_msg *m)
 }
 
 static void
-expunge_folder_exec (struct _sync_folder_msg *m)
+expunge_folder_exec (struct _sync_folder_msg *m,
+                     GCancellable *cancellable,
+                     GError **error)
 {
-	camel_folder_expunge_sync (
-		m->folder, m->base.cancellable, &m->base.error);
+	camel_folder_expunge_sync (m->folder, cancellable, error);
 }
 
 /* we just use the sync stuff where we can, since it would be the same */
@@ -1866,28 +1885,28 @@ empty_trash_desc (struct _empty_trash_msg *m)
 }
 
 static void
-empty_trash_exec (struct _empty_trash_msg *m)
+empty_trash_exec (struct _empty_trash_msg *m,
+                  GCancellable *cancellable,
+                  GError **error)
 {
-	const gchar *data_dir;
 	CamelFolder *trash;
+	const gchar *data_dir;
 	gchar *uri;
 
 	if (m->account) {
 		trash = e_mail_session_get_trash_sync (
 			m->session, m->account->source->url,
-			m->base.cancellable, &m->base.error);
+			cancellable, error);
 	} else {
 		data_dir = mail_session_get_data_dir ();
 		uri = g_strdup_printf ("mbox:%s/local", data_dir);
 		trash = e_mail_session_get_trash_sync (
-			m->session, uri,
-			m->base.cancellable, &m->base.error);
+			m->session, uri, cancellable, error);
 		g_free (uri);
 	}
 
 	if (trash) {
-		camel_folder_expunge_sync (
-			trash, m->base.cancellable, &m->base.error);
+		camel_folder_expunge_sync (trash, cancellable, error);
 		g_object_unref (trash);
 	}
 }
@@ -1955,14 +1974,15 @@ get_message_desc (struct _get_message_msg *m)
 }
 
 static void
-get_message_exec (struct _get_message_msg *m)
+get_message_exec (struct _get_message_msg *m,
+                  GCancellable *cancellable,
+                  GError **error)
 {
-	if (g_cancellable_is_cancelled (m->base.cancellable))
+	if (g_cancellable_is_cancelled (cancellable))
 		m->message = NULL;
 	else
 		m->message = camel_folder_get_message_sync (
-			m->folder, m->uid,
-			m->base.cancellable, &m->base.error);
+			m->folder, m->uid, cancellable, error);
 }
 
 static void
@@ -2090,7 +2110,9 @@ get_messages_desc (struct _get_messages_msg *m)
 }
 
 static void
-get_messages_exec (struct _get_messages_msg *m)
+get_messages_exec (struct _get_messages_msg *m,
+                   GCancellable *cancellable,
+                   GError **error)
 {
 	gint i;
 	CamelMimeMessage *message;
@@ -2100,9 +2122,8 @@ get_messages_exec (struct _get_messages_msg *m)
 
 		message = camel_folder_get_message_sync (
 			m->folder, m->uids->pdata[i],
-			m->base.cancellable, &m->base.error);
-		camel_operation_progress (
-			m->base.cancellable, pc);
+			cancellable, error);
+		camel_operation_progress (cancellable, pc);
 		if (message == NULL)
 			break;
 
@@ -2214,7 +2235,9 @@ save_prepare_part (CamelMimePart *mime_part)
 }
 
 static void
-save_messages_exec (struct _save_messages_msg *m)
+save_messages_exec (struct _save_messages_msg *m,
+                    GCancellable *cancellable,
+                    GError **error)
 {
 	CamelStream *filtered_stream;
 	CamelMimeFilter *from_filter;
@@ -2243,9 +2266,8 @@ save_messages_exec (struct _save_messages_msg *m)
 
 		message = camel_folder_get_message_sync (
 			m->folder, m->uids->pdata[i],
-			m->base.cancellable, &m->base.error);
-		camel_operation_progress (
-			m->base.cancellable, pc);
+			cancellable, error);
+		camel_operation_progress (cancellable, pc);
 		if (message == NULL)
 			break;
 
@@ -2255,24 +2277,23 @@ save_messages_exec (struct _save_messages_msg *m)
 		from = camel_mime_message_build_mbox_from (message);
 		if (camel_stream_write_string (
 			stream, from,
-			m->base.cancellable, &m->base.error) == -1
+			cancellable, error) == -1
 		    || camel_stream_flush (
-			stream, m->base.cancellable, &m->base.error) == -1
+			stream, cancellable, error) == -1
 		    || camel_data_wrapper_write_to_stream_sync (
 			(CamelDataWrapper *) message,
 			(CamelStream *)filtered_stream,
-			m->base.cancellable, &m->base.error) == -1
+			cancellable, error) == -1
 		    || camel_stream_flush (
 			(CamelStream *)filtered_stream,
-			m->base.cancellable, &m->base.error) == -1
+			cancellable, error) == -1
 		    || camel_stream_write_string (
 			stream, "\n",
-			m->base.cancellable, &m->base.error) == -1
+			cancellable, error) == -1
 		    || camel_stream_flush (stream,
-			m->base.cancellable, &m->base.error) == -1) {
+			cancellable, error) == -1) {
 			g_prefix_error (
-				&m->base.error,
-				_("Error saving messages to: %s:\n"),
+				error, _("Error saving messages to: %s:\n"),
 				m->path);
 			g_free (from);
 			g_object_unref ((CamelObject *)message);
@@ -2343,22 +2364,24 @@ struct _prep_offline_msg {
 };
 
 static void
-prep_offline_exec (struct _prep_offline_msg *m)
+prep_offline_exec (struct _prep_offline_msg *m,
+                   GCancellable *cancellable,
+                   GError **error)
 {
 	CamelFolder *folder;
 
 	folder = e_mail_session_uri_to_folder_sync (
 		m->session, m->uri, 0,
-		m->base.cancellable, &m->base.error);
+		cancellable, error);
 	if (folder) {
 		if (CAMEL_IS_DISCO_FOLDER (folder)) {
 			camel_disco_folder_prepare_for_offline (
 				CAMEL_DISCO_FOLDER (folder),
-				"(match-all)", m->cancel, &m->base.error);
+				"(match-all)", m->cancel, error);
 		} else if (CAMEL_IS_OFFLINE_FOLDER (folder)) {
 			camel_offline_folder_downsync_sync (
 				CAMEL_OFFLINE_FOLDER (folder),
-				"(match-all)", m->cancel, &m->base.error);
+				"(match-all)", m->cancel, error);
 		}
 		/* prepare_for_offline should do this? */
 		/* of course it should all be atomic, but ... */
@@ -2436,35 +2459,34 @@ set_offline_desc (struct _set_offline_msg *m)
 }
 
 static void
-set_offline_exec (struct _set_offline_msg *m)
+set_offline_exec (struct _set_offline_msg *m,
+                  GCancellable *cancellable,
+                  GError **error)
 {
 	if (CAMEL_IS_DISCO_STORE (m->store)) {
 		if (!m->offline) {
 			camel_disco_store_set_status (
 				CAMEL_DISCO_STORE (m->store),
 				CAMEL_DISCO_STORE_ONLINE,
-				m->base.cancellable,
-				&m->base.error);
+				cancellable, error);
 			return;
 		} else if (camel_disco_store_can_work_offline (CAMEL_DISCO_STORE (m->store))) {
 			camel_disco_store_set_status (
 				CAMEL_DISCO_STORE (m->store),
 				CAMEL_DISCO_STORE_OFFLINE,
-				m->base.cancellable,
-				&m->base.error);
+				cancellable, error);
 			return;
 		}
 	} else if (CAMEL_IS_OFFLINE_STORE (m->store)) {
 		camel_offline_store_set_online_sync (
 			CAMEL_OFFLINE_STORE (m->store),
-			!m->offline, m->base.cancellable,
-			&m->base.error);
+			!m->offline, cancellable, error);
 		return;
 	}
 
 	if (m->offline)
 		camel_service_disconnect_sync (
-			CAMEL_SERVICE (m->store), TRUE, &m->base.error);
+			CAMEL_SERVICE (m->store), TRUE, error);
 }
 
 static void
@@ -2530,16 +2552,18 @@ prepare_offline_desc (struct _set_offline_msg *m)
 }
 
 static void
-prepare_offline_exec (struct _set_offline_msg *m)
+prepare_offline_exec (struct _set_offline_msg *m,
+                      GCancellable *cancellable,
+                      GError **error)
 {
 	if (CAMEL_IS_DISCO_STORE (m->store)) {
 		camel_disco_store_prepare_for_offline (
 			CAMEL_DISCO_STORE (m->store),
-			m->base.cancellable, &m->base.error);
+			cancellable, error);
 	} else if (CAMEL_IS_OFFLINE_STORE (m->store)) {
 		camel_offline_store_prepare_for_offline_sync (
 			CAMEL_OFFLINE_STORE (m->store),
-			m->base.cancellable, &m->base.error);
+			cancellable, error);
 	}
 }
 
@@ -2616,18 +2640,19 @@ check_service_desc (struct _check_msg *m)
 }
 
 static void
-check_service_exec (struct _check_msg *m)
+check_service_exec (struct _check_msg *m,
+                    GCancellable *cancellable,
+                    GError **error)
 {
 	CamelService *service;
 
 	service = camel_session_get_service (
-		CAMEL_SESSION (m->session), m->url,
-		m->type, &m->base.error);
+		CAMEL_SESSION (m->session), m->url, m->type, error);
 	if (!service)
 		return;
 
 	m->authtypes = camel_service_query_auth_types_sync (
-		service, m->base.cancellable, &m->base.error);
+		service, cancellable, error);
 	g_object_unref (service);
 }
 
diff --git a/mail/mail-send-recv.c b/mail/mail-send-recv.c
index 3d30387..63cc283 100644
--- a/mail/mail-send-recv.c
+++ b/mail/mail-send-recv.c
@@ -903,10 +903,12 @@ refresh_folders_desc (struct _refresh_folders_msg *m)
 }
 
 static void
-refresh_folders_exec (struct _refresh_folders_msg *m)
+refresh_folders_exec (struct _refresh_folders_msg *m,
+                      GCancellable *cancellable,
+                      GError **error)
 {
-	gint i;
 	CamelFolder *folder;
+	gint i;
 	GError *local_error = NULL;
 
 	get_folders (m->store, m->folders, m->finfo);
@@ -915,7 +917,7 @@ refresh_folders_exec (struct _refresh_folders_msg *m)
 		folder = e_mail_session_uri_to_folder_sync (
 			m->info->session,
 			m->folders->pdata[i], 0,
-			m->base.cancellable, &local_error);
+			cancellable, &local_error);
 		if (folder) {
 			/* FIXME Not passing a GCancellable or GError here. */
 			camel_folder_synchronize_sync (
diff --git a/mail/mail-vfolder.c b/mail/mail-vfolder.c
index eb447ea..6ed6a61 100644
--- a/mail/mail-vfolder.c
+++ b/mail/mail-vfolder.c
@@ -88,7 +88,9 @@ vfolder_setup_desc (struct _setup_msg *m)
 }
 
 static void
-vfolder_setup_exec (struct _setup_msg *m)
+vfolder_setup_exec (struct _setup_msg *m,
+                    GCancellable *cancellable,
+                    GError **error)
 {
 	GList *l, *list = NULL;
 	CamelFolder *folder;
@@ -243,7 +245,9 @@ vfolder_adduri_desc (struct _adduri_msg *m)
 }
 
 static void
-vfolder_adduri_exec (struct _adduri_msg *m)
+vfolder_adduri_exec (struct _adduri_msg *m,
+                     GCancellable *cancellable,
+                     GError **error)
 {
 	GList *l;
 	CamelFolder *folder = NULL;
@@ -252,8 +256,6 @@ vfolder_adduri_exec (struct _adduri_msg *m)
 	if (vfolder_shutdown)
 		return;
 
-	d(printf("%s uri to vfolder: %s\n", m->remove?"Removing":"Adding", m->uri));
-
 	folder_cache = e_mail_session_get_folder_cache (m->session);
 
 	/* we dont try lookup the cache if we are removing it, its no longer there */
@@ -266,8 +268,7 @@ vfolder_adduri_exec (struct _adduri_msg *m)
 
 	if (folder == NULL)
 		folder = e_mail_session_uri_to_folder_sync (
-			m->session, m->uri, 0,
-			m->base.cancellable, &m->base.error);
+			m->session, m->uri, 0, cancellable, error);
 
 	if (folder != NULL) {
 		l = m->folders;
diff --git a/mail/message-list.c b/mail/message-list.c
index 974eb1c..68e05fc 100644
--- a/mail/message-list.c
+++ b/mail/message-list.c
@@ -2218,7 +2218,9 @@ ml_drop_async_desc (struct _drop_msg *m)
 }
 
 static void
-ml_drop_async_exec (struct _drop_msg *m)
+ml_drop_async_exec (struct _drop_msg *m,
+                    GCancellable *cancellable,
+                    GError **error)
 {
 	EMailBackend *backend;
 	EMailSession *session;
@@ -2231,8 +2233,7 @@ ml_drop_async_exec (struct _drop_msg *m)
 		em_utils_selection_get_uidlist (
 			m->selection, session, m->folder,
 			m->action == GDK_ACTION_MOVE,
-			m->base.cancellable,
-			&m->base.error);
+			cancellable, error);
 		break;
 	case DND_MESSAGE_RFC822:
 		em_utils_selection_get_message (m->selection, m->folder);
@@ -4461,7 +4462,9 @@ regen_list_desc (struct _regen_list_msg *m)
 }
 
 static void
-regen_list_exec (struct _regen_list_msg *m)
+regen_list_exec (struct _regen_list_msg *m,
+                 GCancellable *cancellable,
+                 GError **error)
 {
 	GPtrArray *uids, *searchuids = NULL;
 	CamelMessageInfo *info;
@@ -4469,6 +4472,7 @@ regen_list_exec (struct _regen_list_msg *m)
 	ETree *tree;
 	gint i;
 	gchar *expr = NULL;
+	GError *local_error = NULL;
 
 	if (m->folder != m->ml->folder)
 		return;
@@ -4516,7 +4520,7 @@ regen_list_exec (struct _regen_list_msg *m)
 		gboolean store_has_vjunk = folder_store_supports_vjunk_folder (m->folder);
 
 		searchuids = uids = camel_folder_search_by_expression (
-			m->folder, expr, &m->base.error);
+			m->folder, expr, &local_error);
 		/* If m->changes is not NULL, then it means we are called from folder_changed event,
 		   thus we will keep the selected message to be sure it doesn't disappear because
 		   it no longer belong to our search filter. */
@@ -4554,13 +4558,15 @@ regen_list_exec (struct _regen_list_msg *m)
 		}
 	}
 
-	if (m->base.error != NULL)
+	if (local_error != NULL) {
+		g_propagate_error (error, local_error);
 		return;
+	}
 
 	e_profile_event_emit("list.threaduids", m->folder->full_name, 0);
 
 	/* camel_folder_summary_prepare_fetch_all (m->folder->summary, NULL); */
-	if (!g_cancellable_is_cancelled (m->base.cancellable)) {
+	if (!g_cancellable_is_cancelled (cancellable)) {
 		/* update/build a new tree */
 		if (m->dotree) {
 			ml_sort_uids_by_tree (m->ml, uids);
@@ -4596,6 +4602,9 @@ static void
 regen_list_done (struct _regen_list_msg *m)
 {
 	ETree *tree;
+	GCancellable *cancellable;
+
+	cancellable = e_activity_get_cancellable (m->base.activity);
 
 	if (m->ml->priv->destroyed)
 		return;
@@ -4603,7 +4612,7 @@ regen_list_done (struct _regen_list_msg *m)
 	if (!m->complete)
 		return;
 
-	if (g_cancellable_is_cancelled (m->base.cancellable))
+	if (g_cancellable_is_cancelled (cancellable))
 		return;
 
 	if (m->ml->folder != m->folder)
@@ -4789,10 +4798,12 @@ mail_regen_cancel (MessageList *ml)
 		l = ml->regen;
 		while (l) {
 			MailMsg *mm = l->data;
+			GCancellable *cancellable;
 
-			if (mm->cancellable)
+			cancellable = e_activity_get_cancellable (mm->activity);
+			if (CAMEL_IS_OPERATION (cancellable))
 				camel_operation_cancel (
-					CAMEL_OPERATION (mm->cancellable));
+					CAMEL_OPERATION (cancellable));
 			l = l->next;
 		}
 
diff --git a/modules/calendar/e-cal-shell-view-memopad.c b/modules/calendar/e-cal-shell-view-memopad.c
index e88aa3a..11e1bcd 100644
--- a/modules/calendar/e-cal-shell-view-memopad.c
+++ b/modules/calendar/e-cal-shell-view-memopad.c
@@ -429,7 +429,7 @@ e_cal_shell_view_memopad_set_status_message (ECalShellView *cal_shell_view,
 
 	if (status_message == NULL || *status_message == '\0') {
 		if (activity != NULL) {
-			e_activity_complete (activity);
+			e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
 			g_object_unref (activity);
 			activity = NULL;
 		}
@@ -437,12 +437,12 @@ e_cal_shell_view_memopad_set_status_message (ECalShellView *cal_shell_view,
 	} else if (activity == NULL) {
 		activity = e_activity_new ();
 		e_activity_set_percent (activity, percent);
-		e_activity_set_primary_text (activity, status_message);
+		e_activity_set_text (activity, status_message);
 		e_shell_backend_add_activity (shell_backend, activity);
 
 	} else {
 		e_activity_set_percent (activity, percent);
-		e_activity_set_primary_text (activity, status_message);
+		e_activity_set_text (activity, status_message);
 	}
 
 	cal_shell_view->priv->memopad_activity = activity;
diff --git a/modules/calendar/e-cal-shell-view-private.c b/modules/calendar/e-cal-shell-view-private.c
index 29c7d1e..2dd1fdc 100644
--- a/modules/calendar/e-cal-shell-view-private.c
+++ b/modules/calendar/e-cal-shell-view-private.c
@@ -705,21 +705,24 @@ e_cal_shell_view_private_dispose (ECalShellView *cal_shell_view)
 
 	if (priv->calendar_activity != NULL) {
 		/* XXX Activity is not cancellable. */
-		e_activity_complete (priv->calendar_activity);
+		e_activity_set_state (
+			priv->calendar_activity, E_ACTIVITY_COMPLETED);
 		g_object_unref (priv->calendar_activity);
 		priv->calendar_activity = NULL;
 	}
 
 	if (priv->memopad_activity != NULL) {
 		/* XXX Activity is not cancellable. */
-		e_activity_complete (priv->memopad_activity);
+		e_activity_set_state (
+			priv->memopad_activity, E_ACTIVITY_COMPLETED);
 		g_object_unref (priv->memopad_activity);
 		priv->memopad_activity = NULL;
 	}
 
 	if (priv->taskpad_activity != NULL) {
 		/* XXX Activity is not cancellable. */
-		e_activity_complete (priv->taskpad_activity);
+		e_activity_set_state (
+			priv->taskpad_activity, E_ACTIVITY_COMPLETED);
 		g_object_unref (priv->taskpad_activity);
 		priv->taskpad_activity = NULL;
 	}
@@ -808,18 +811,18 @@ e_cal_shell_view_set_status_message (ECalShellView *cal_shell_view,
 
 	if (status_message == NULL || *status_message == '\0') {
 		if (activity != NULL) {
-			e_activity_complete (activity);
+			e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
 			g_object_unref (activity);
 			activity = NULL;
 		}
 	} else if (activity == NULL) {
 		activity = e_activity_new ();
 		e_activity_set_percent (activity, percent);
-		e_activity_set_primary_text (activity, status_message);
+		e_activity_set_text (activity, status_message);
 		e_shell_backend_add_activity (shell_backend, activity);
 	} else {
 		e_activity_set_percent (activity, percent);
-		e_activity_set_primary_text (activity, status_message);
+		e_activity_set_text (activity, status_message);
 	}
 
 	cal_shell_view->priv->calendar_activity = activity;
diff --git a/modules/calendar/e-cal-shell-view-taskpad.c b/modules/calendar/e-cal-shell-view-taskpad.c
index b1eb390..6dae144 100644
--- a/modules/calendar/e-cal-shell-view-taskpad.c
+++ b/modules/calendar/e-cal-shell-view-taskpad.c
@@ -556,7 +556,7 @@ e_cal_shell_view_taskpad_set_status_message (ECalShellView *cal_shell_view,
 
 	if (status_message == NULL || *status_message == '\0') {
 		if (activity != NULL) {
-			e_activity_complete (activity);
+			e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
 			g_object_unref (activity);
 			activity = NULL;
 		}
@@ -564,12 +564,12 @@ e_cal_shell_view_taskpad_set_status_message (ECalShellView *cal_shell_view,
 	} else if (activity == NULL) {
 		activity = e_activity_new ();
 		e_activity_set_percent (activity, percent);
-		e_activity_set_primary_text (activity, status_message);
+		e_activity_set_text (activity, status_message);
 		e_shell_backend_add_activity (shell_backend, activity);
 
 	} else {
 		e_activity_set_percent (activity, percent);
-		e_activity_set_primary_text (activity, status_message);
+		e_activity_set_text (activity, status_message);
 	}
 
 	cal_shell_view->priv->taskpad_activity = activity;
diff --git a/modules/calendar/e-memo-shell-view-private.c b/modules/calendar/e-memo-shell-view-private.c
index 8c83619..4fe6a25 100644
--- a/modules/calendar/e-memo-shell-view-private.c
+++ b/modules/calendar/e-memo-shell-view-private.c
@@ -296,7 +296,9 @@ e_memo_shell_view_private_dispose (EMemoShellView *memo_shell_view)
 
 	if (memo_shell_view->priv->activity != NULL) {
 		/* XXX Activity is not cancellable. */
-		e_activity_complete (memo_shell_view->priv->activity);
+		e_activity_set_state (
+			memo_shell_view->priv->activity,
+			E_ACTIVITY_COMPLETED);
 		g_object_unref (memo_shell_view->priv->activity);
 		memo_shell_view->priv->activity = NULL;
 	}
@@ -370,7 +372,7 @@ e_memo_shell_view_set_status_message (EMemoShellView *memo_shell_view,
 
 	if (status_message == NULL || *status_message == '\0') {
 		if (activity != NULL) {
-			e_activity_complete (activity);
+			e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
 			g_object_unref (activity);
 			activity = NULL;
 		}
@@ -378,12 +380,12 @@ e_memo_shell_view_set_status_message (EMemoShellView *memo_shell_view,
 	} else if (activity == NULL) {
 		activity = e_activity_new ();
 		e_activity_set_percent (activity, percent);
-		e_activity_set_primary_text (activity, status_message);
+		e_activity_set_text (activity, status_message);
 		e_shell_backend_add_activity (shell_backend, activity);
 
 	} else {
 		e_activity_set_percent (activity, percent);
-		e_activity_set_primary_text (activity, status_message);
+		e_activity_set_text (activity, status_message);
 	}
 
 	memo_shell_view->priv->activity = activity;
diff --git a/modules/calendar/e-task-shell-view-private.c b/modules/calendar/e-task-shell-view-private.c
index f0e8cbf..9f833e9 100644
--- a/modules/calendar/e-task-shell-view-private.c
+++ b/modules/calendar/e-task-shell-view-private.c
@@ -377,7 +377,9 @@ e_task_shell_view_private_dispose (ETaskShellView *task_shell_view)
 
 	if (task_shell_view->priv->activity != NULL) {
 		/* XXX Activity is not cancellable. */
-		e_activity_complete (task_shell_view->priv->activity);
+		e_activity_set_state (
+			task_shell_view->priv->activity,
+			E_ACTIVITY_COMPLETED);
 		g_object_unref (task_shell_view->priv->activity);
 		task_shell_view->priv->activity = NULL;
 	}
@@ -521,7 +523,7 @@ e_task_shell_view_set_status_message (ETaskShellView *task_shell_view,
 
 	if (status_message == NULL || *status_message == '\0') {
 		if (activity != NULL) {
-			e_activity_complete (activity);
+			e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
 			g_object_unref (activity);
 			activity = NULL;
 		}
@@ -529,12 +531,12 @@ e_task_shell_view_set_status_message (ETaskShellView *task_shell_view,
 	} else if (activity == NULL) {
 		activity = e_activity_new ();
 		e_activity_set_percent (activity, percent);
-		e_activity_set_primary_text (activity, status_message);
+		e_activity_set_text (activity, status_message);
 		e_shell_backend_add_activity (shell_backend, activity);
 
 	} else {
 		e_activity_set_percent (activity, percent);
-		e_activity_set_primary_text (activity, status_message);
+		e_activity_set_text (activity, status_message);
 	}
 
 	task_shell_view->priv->activity = activity;
diff --git a/modules/mail/e-mail-shell-view.c b/modules/mail/e-mail-shell-view.c
index 557d206..8d5a568 100644
--- a/modules/mail/e-mail-shell-view.c
+++ b/modules/mail/e-mail-shell-view.c
@@ -55,7 +55,9 @@ search_results_desc (SearchResultsMsg *msg)
 }
 
 static void
-search_results_exec (SearchResultsMsg *msg)
+search_results_exec (SearchResultsMsg *msg,
+                     GCancellable *cancellable,
+                     GError **error)
 {
 	GList *copied_list;
 
diff --git a/plugins/dbx-import/dbx-importer.c b/plugins/dbx-import/dbx-importer.c
index 28db6b1..0105dfe 100644
--- a/plugins/dbx-import/dbx-importer.c
+++ b/plugins/dbx-import/dbx-importer.c
@@ -546,6 +546,7 @@ dbx_import_file (DbxImporter *m)
 	EShell *shell;
 	EShellBackend *shell_backend;
 	EMailSession *session;
+	GCancellable *cancellable;
 	gchar *filename;
 	CamelFolder *folder;
 	gint tmpfile;
@@ -555,6 +556,8 @@ dbx_import_file (DbxImporter *m)
 	filename = g_filename_from_uri (((EImportTargetURI *)m->target)->uri_src, NULL, NULL);
 	m->parent_uri = g_strdup (((EImportTargetURI *)m->target)->uri_dest); /* Destination folder, was set in our widget */
 
+	cancellable = e_activity_get_cancellable (m->base.activity);
+
 	/* XXX Dig up the EMailSession from the default EShell.
 	 *     Since the EImport framework doesn't allow for user
 	 *     data, I don't see how else to get to it. */
@@ -565,7 +568,7 @@ dbx_import_file (DbxImporter *m)
 	camel_operation_push_message (NULL, _("Importing '%s'"), filename);
 	folder = e_mail_session_uri_to_folder_sync (
 		session, m->parent_uri, CAMEL_STORE_FOLDER_CREATE,
-		m->base.cancellable, &m->base.error);
+		cancellable, &m->base.error);
 	if (!folder)
 		return;
 	d(printf("importing to %s\n", camel_folder_get_full_name(folder)));
@@ -603,7 +606,7 @@ dbx_import_file (DbxImporter *m)
 		gboolean success;
 
 		camel_operation_progress (NULL, 100 * i / m->index_count);
-		camel_operation_progress (m->cancellable, 100 * i / m->index_count);
+		camel_operation_progress (cancellable, 100 * i / m->index_count);
 
 		if (!dbx_read_email (m, m->indices[i], tmpfile, &dbx_flags)) {
 			d(printf("Cannot read email index %d at %x\n",
@@ -638,7 +641,7 @@ dbx_import_file (DbxImporter *m)
 		camel_message_info_set_flags (info, flags, ~0);
 		success = camel_folder_append_message_sync (
 			folder, msg, info, NULL,
-			m->base.cancellable, &m->base.error);
+			cancellable, &m->base.error);
 		camel_message_info_free (info);
 		g_object_unref (msg);
 
@@ -667,7 +670,9 @@ dbx_import_file (DbxImporter *m)
 }
 
 static void
-dbx_import_import (DbxImporter *m)
+dbx_import_import (DbxImporter *m,
+                   GCancellable *cancellable,
+                   GError **error)
 {
 	dbx_import_file (m);
 }
diff --git a/plugins/groupwise-features/share-folder-common.c b/plugins/groupwise-features/share-folder-common.c
index 61cace9..4a4e57a 100644
--- a/plugins/groupwise-features/share-folder-common.c
+++ b/plugins/groupwise-features/share-folder-common.c
@@ -139,18 +139,19 @@ create_folder_desc (struct _EMCreateFolder *m)
 }
 
 static void
-create_folder_exec (struct _EMCreateFolder *m)
+create_folder_exec (struct _EMCreateFolder *m,
+                    GCancellable *cancellable,
+                    GError **error)
 {
 	d(printf ("creating folder parent='%s' name='%s' full_name='%s'\n", m->parent, m->name, m->full_name));
 
 	if ((m->fi = camel_store_create_folder_sync (
-		m->store, m->parent, m->name,
-		m->base.cancellable, &m->base.error))) {
+		m->store, m->parent, m->name, cancellable, error))) {
 
 		if (camel_store_supports_subscriptions (m->store))
 			camel_store_subscribe_folder_sync (
 				m->store, m->full_name,
-				m->base.cancellable, &m->base.error);
+				cancellable, error);
 	}
 }
 
diff --git a/plugins/itip-formatter/itip-formatter.c b/plugins/itip-formatter/itip-formatter.c
index d8ff9b9..79d0bd1 100644
--- a/plugins/itip-formatter/itip-formatter.c
+++ b/plugins/itip-formatter/itip-formatter.c
@@ -1943,7 +1943,9 @@ open_calendar__desc (struct _opencal_msg *m, gint complete)
 }
 
 static void
-open_calendar__exec (struct _opencal_msg *m)
+open_calendar__exec (struct _opencal_msg *m,
+                     GCancellable *cancellable,
+                     GError **error)
 {
 	if (!g_spawn_command_line_async (m->command, NULL)) {
 		g_warning ("Could not launch %s", m->command);
diff --git a/plugins/pst-import/pst-importer.c b/plugins/pst-import/pst-importer.c
index 2e994f7..d0a69dd 100644
--- a/plugins/pst-import/pst-importer.c
+++ b/plugins/pst-import/pst-importer.c
@@ -121,7 +121,6 @@ struct _PstImporter {
 
 	pst_file pst;
 
-	GCancellable *cancellable;
 	CamelFolder *folder;
 	gchar *parent_uri;
 	gchar *folder_name;
@@ -394,7 +393,9 @@ open_ecal (ECalSourceType type, const gchar *name)
 }
 
 static void
-pst_import_import (PstImporter *m)
+pst_import_import (PstImporter *m,
+                   GCancellable *cancellable,
+                   GError **error)
 {
 	if (GPOINTER_TO_INT (g_datalist_get_data (&m->target->data, "pst-do-addr"))) {
 		/* Hack - grab the first address book we can find
@@ -456,11 +457,14 @@ pst_import_file (PstImporter *m)
 	EShell *shell;
 	EShellBackend *shell_backend;
 	EMailSession *session;
+	GCancellable *cancellable;
 	gint ret;
 	gchar *filename;
 	pst_item *item = NULL;
 	pst_desc_tree *d_ptr;
 
+	cancellable = e_activity_get_cancellable (m->base.activity);
+
 	/* XXX Dig up the EMailSession from the default EShell.
 	 *     Since the EImport framework doesn't allow for user
 	 *     data, I don't see how else to get to it. */
@@ -476,7 +480,7 @@ pst_import_file (PstImporter *m)
 	if (GPOINTER_TO_INT (g_datalist_get_data (&m->target->data, "pst-do-mail"))) {
 		e_mail_session_uri_to_folder_sync (
 			session, m->parent_uri, CAMEL_STORE_FOLDER_CREATE,
-			m->base.cancellable, &m->base.error);
+			cancellable, &m->base.error);
 	}
 
 	ret = pst_init (&m->pst, filename);
@@ -710,10 +714,13 @@ pst_create_folder (PstImporter *m)
 	EShell *shell;
 	EShellBackend *shell_backend;
 	EMailSession *session;
+	GCancellable *cancellable;
 	const gchar *parent;
 	gchar *dest, *dest_end, *pos;
 	gint dest_len;
 
+	cancellable = e_activity_get_cancellable (m->base.activity);
+
 	/* XXX Dig up the EMailSession from the default EShell.
 	 *     Since the EImport framework doesn't allow for user
 	 *     data, I don't see how else to get to it. */
@@ -740,7 +747,7 @@ pst_create_folder (PstImporter *m)
 
 			folder = e_mail_session_uri_to_folder_sync (
 				session, dest, CAMEL_STORE_FOLDER_CREATE,
-				m->base.cancellable, &m->base.error);
+				cancellable, &m->base.error);
 			g_object_unref (folder);
 			*pos = '/';
 		}
@@ -754,7 +761,7 @@ pst_create_folder (PstImporter *m)
 
 	m->folder = e_mail_session_uri_to_folder_sync (
 		session, m->folder_uri, CAMEL_STORE_FOLDER_CREATE,
-		m->base.cancellable, &m->base.error);
+		cancellable, &m->base.error);
 }
 
 /**
@@ -1659,7 +1666,6 @@ pst_import (EImport *ei, EImportTarget *target)
 	m->status_timeout_id = g_timeout_add (100, pst_status_timeout, m);
 	/*m->status_timeout_id = NULL;*/
 	m->status_lock = g_mutex_new ();
-	m->cancellable = camel_operation_new ();
 
 	g_signal_connect (
 		m->status, "status",
diff --git a/shell/e-shell-backend.c b/shell/e-shell-backend.c
index 0d7ff02..c2abb47 100644
--- a/shell/e-shell-backend.c
+++ b/shell/e-shell-backend.c
@@ -398,19 +398,30 @@ void
 e_shell_backend_add_activity (EShellBackend *shell_backend,
                               EActivity *activity)
 {
-	GCancellable *cancellable;
+	EActivityState state;
 
 	g_return_if_fail (E_IS_SHELL_BACKEND (shell_backend));
 	g_return_if_fail (E_IS_ACTIVITY (activity));
 
-	cancellable = e_activity_get_cancellable (activity);
+	state = e_activity_get_state (activity);
 
-	/* Skip cancelled activities. */
-	if (g_cancellable_is_cancelled (cancellable))
+	/* Disregard cancelled or completed activities. */
+
+	if (state == E_ACTIVITY_CANCELLED)
+		return;
+
+	if (state == E_ACTIVITY_COMPLETED)
 		return;
 
 	g_queue_push_tail (shell_backend->priv->activities, activity);
 
+	/* Emit the "activity-added" signal before adding a weak reference
+	 * to the EActivity because EShellTaskbar's signal handler also adds
+	 * a weak reference to the EActivity, and we want its GWeakNotify
+	 * to run before ours, since ours may destroy the EShellTaskbar
+	 * during application shutdown. */
+	g_signal_emit (shell_backend, signals[ACTIVITY_ADDED], 0, activity);
+
 	/* We reference the backend on every activity to
 	 * guarantee the backend outlives the activity. */
 	g_object_weak_ref (
@@ -418,8 +429,6 @@ e_shell_backend_add_activity (EShellBackend *shell_backend,
 		shell_backend_activity_finalized_cb,
 		g_object_ref (shell_backend));
 
-	g_signal_emit (shell_backend, signals[ACTIVITY_ADDED], 0, activity);
-
 	/* Only emit "notify::busy" when switching from idle to busy. */
 	if (g_queue_get_length (shell_backend->priv->activities) == 1)
 		g_object_notify (G_OBJECT (shell_backend), "busy");
diff --git a/shell/e-shell-taskbar.c b/shell/e-shell-taskbar.c
index 47f900a..9be7c15 100644
--- a/shell/e-shell-taskbar.c
+++ b/shell/e-shell-taskbar.c
@@ -64,8 +64,8 @@ G_DEFINE_TYPE_WITH_CODE (
 		E_TYPE_EXTENSIBLE, NULL))
 
 static void
-shell_taskbar_activity_remove (EShellTaskbar *shell_taskbar,
-                               EActivity *activity)
+shell_taskbar_weak_notify_cb (EShellTaskbar *shell_taskbar,
+                              GObject *where_the_activity_was)
 {
 	GtkWidget *proxy;
 	GtkContainer *container;
@@ -73,11 +73,10 @@ shell_taskbar_activity_remove (EShellTaskbar *shell_taskbar,
 	GList *children;
 
 	proxy_table = shell_taskbar->priv->proxy_table;
-	proxy = g_hash_table_lookup (proxy_table, activity);
+	proxy = g_hash_table_lookup (proxy_table, where_the_activity_was);
+	g_hash_table_remove (proxy_table, where_the_activity_was);
 	g_return_if_fail (proxy != NULL);
 
-	g_hash_table_remove (proxy_table, activity);
-
 	container = GTK_CONTAINER (shell_taskbar->priv->hbox);
 	gtk_container_remove (container, proxy);
 
@@ -95,6 +94,17 @@ shell_taskbar_activity_add (EShellTaskbar *shell_taskbar,
 {
 	GtkBox *box;
 	GtkWidget *proxy;
+	EActivityState state;
+	GHashTable *proxy_table;
+
+	/* Sanity check the activity state. */
+	state = e_activity_get_state (activity);
+	g_return_if_fail (state == E_ACTIVITY_RUNNING);
+
+	/* Make sure it hasn't already been added. */
+	proxy_table = shell_taskbar->priv->proxy_table;
+	proxy = g_hash_table_lookup (proxy_table, activity);
+	g_return_if_fail (proxy == NULL);
 
 	/* Proxy widgets manage their own visibility.
 	 * Don't call gtk_widget_show() on it here. */
@@ -104,17 +114,28 @@ shell_taskbar_activity_add (EShellTaskbar *shell_taskbar,
 	gtk_box_reorder_child (box, proxy, 0);
 	gtk_widget_show (GTK_WIDGET (box));
 
-	g_hash_table_insert (
-		shell_taskbar->priv->proxy_table,
-		g_object_ref (activity), g_object_ref (proxy));
+	/* The proxy widget also holds a weak reference to the activity,
+	 * so the activity should get finalized in the normal course of
+	 * operation.  When that happens we remove the corresponding
+	 * proxy widget from the taskbar. */
 
-	g_signal_connect_swapped (
-		activity, "cancelled",
-		G_CALLBACK (shell_taskbar_activity_remove), shell_taskbar);
+	g_object_weak_ref (
+		G_OBJECT (activity), (GWeakNotify)
+		shell_taskbar_weak_notify_cb, shell_taskbar);
 
-	g_signal_connect_swapped (
-		activity, "completed",
-		G_CALLBACK (shell_taskbar_activity_remove), shell_taskbar);
+	g_hash_table_insert (proxy_table, activity, proxy);
+}
+
+static gboolean
+shell_taskbar_weak_unref (EActivity *activity,
+                          EActivityProxy *proxy,
+                          EShellTaskbar *shell_taskbar)
+{
+	g_object_weak_unref (
+		G_OBJECT (activity), (GWeakNotify)
+		shell_taskbar_weak_notify_cb, shell_taskbar);
+
+	return TRUE;
 }
 
 static void
@@ -176,18 +197,6 @@ shell_taskbar_get_property (GObject *object,
 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 }
 
-static gboolean
-disconnect_remove (EActivity *activity,
-                   EActivityProxy *proxy,
-                   EShellTaskbar *shell_taskbar)
-{
-	g_signal_handlers_disconnect_matched (
-		activity, G_SIGNAL_MATCH_DATA,
-		0, 0, NULL, NULL, shell_taskbar);
-
-	return TRUE;
-}
-
 static void
 shell_taskbar_dispose (GObject *object)
 {
@@ -195,6 +204,10 @@ shell_taskbar_dispose (GObject *object)
 
 	priv = E_SHELL_TASKBAR_GET_PRIVATE (object);
 
+	g_hash_table_foreach_remove (
+		priv->proxy_table, (GHRFunc)
+		shell_taskbar_weak_unref, object);
+
 	if (priv->shell_view != NULL) {
 		g_object_remove_weak_pointer (
 			G_OBJECT (priv->shell_view), &priv->shell_view);
@@ -219,9 +232,6 @@ shell_taskbar_dispose (GObject *object)
 		priv->hbox = NULL;
 	}
 
-	g_hash_table_foreach_remove (
-		priv->proxy_table, (GHRFunc) disconnect_remove, object);
-
 	/* Chain up to parent's dispose() method. */
 	G_OBJECT_CLASS (e_shell_taskbar_parent_class)->dispose (object);
 }
@@ -315,16 +325,10 @@ static void
 e_shell_taskbar_init (EShellTaskbar *shell_taskbar)
 {
 	GtkWidget *widget;
-	GHashTable *proxy_table;
 	gint height;
 
-	proxy_table = g_hash_table_new_full (
-		g_direct_hash, g_direct_equal,
-		(GDestroyNotify) g_object_unref,
-		(GDestroyNotify) g_object_unref);
-
 	shell_taskbar->priv = E_SHELL_TASKBAR_GET_PRIVATE (shell_taskbar);
-	shell_taskbar->priv->proxy_table = proxy_table;
+	shell_taskbar->priv->proxy_table = g_hash_table_new (NULL, NULL);
 
 	gtk_box_set_spacing (GTK_BOX (shell_taskbar), 12);
 
diff --git a/shell/e-shell-view.c b/shell/e-shell-view.c
index 18300c4..e07b762 100644
--- a/shell/e-shell-view.c
+++ b/shell/e-shell-view.c
@@ -293,7 +293,7 @@ shell_view_save_state (EShellView *shell_view)
 		FALSE, G_FILE_CREATE_PRIVATE, (GAsyncReadyCallback)
 		shell_view_save_state_done_cb, data);
 
-	e_activity_set_primary_text (
+	e_activity_set_text (
 		activity, (_("Saving user interface state")));
 
 	e_shell_backend_add_activity (shell_backend, activity);
diff --git a/shell/e-shell.c b/shell/e-shell.c
index 62cae09..b983b18 100644
--- a/shell/e-shell.c
+++ b/shell/e-shell.c
@@ -221,7 +221,7 @@ shell_ready_for_offline (EShell *shell,
 	 * a signal without triggering the toggle reference. */
 	g_object_ref (activity);
 
-	e_activity_complete (activity);
+	e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
 
 	g_object_remove_toggle_ref (
 		G_OBJECT (activity), (GToggleNotify)
@@ -243,7 +243,7 @@ shell_prepare_for_offline (EShell *shell)
 
 	shell->priv->preparing_for_line_change = e_activity_new ();
 
-	e_activity_set_primary_text (
+	e_activity_set_text (
 		shell->priv->preparing_for_line_change,
 		_("Preparing to go offline..."));
 
@@ -274,7 +274,7 @@ shell_ready_for_online (EShell *shell,
 	 * a signal without triggering the toggle reference. */
 	g_object_ref (activity);
 
-	e_activity_complete (activity);
+	e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
 
 	g_object_remove_toggle_ref (
 		G_OBJECT (activity), (GToggleNotify)
@@ -296,7 +296,7 @@ shell_prepare_for_online (EShell *shell)
 
 	shell->priv->preparing_for_line_change = e_activity_new ();
 
-	e_activity_set_primary_text (
+	e_activity_set_text (
 		shell->priv->preparing_for_line_change,
 		_("Preparing to go online..."));
 
@@ -329,7 +329,7 @@ shell_ready_for_quit (EShell *shell,
 	 * a signal without triggering the toggle reference. */
 	g_object_ref (activity);
 
-	e_activity_complete (activity);
+	e_activity_set_state (activity, E_ACTIVITY_COMPLETED);
 
 	g_object_remove_toggle_ref (
 		G_OBJECT (activity), (GToggleNotify)
@@ -358,7 +358,7 @@ shell_prepare_for_quit (EShell *shell)
 
 	shell->priv->preparing_for_quit = e_activity_new ();
 
-	e_activity_set_primary_text (
+	e_activity_set_text (
 		shell->priv->preparing_for_quit,
 		_("Preparing to quit..."));
 
diff --git a/shell/test/e-test-shell-view.c b/shell/test/e-test-shell-view.c
index 4ecda30..924f989 100644
--- a/shell/test/e-test-shell-view.c
+++ b/shell/test/e-test-shell-view.c
@@ -98,7 +98,7 @@ test_shell_view_constructed (GObject *object)
 	activity = e_activity_new ();
 	cancellable = g_cancellable_new ();
 	e_activity_set_cancellable (activity, cancellable);
-	e_activity_set_primary_text (activity, "Test Activity");
+	e_activity_set_text (activity, "Test Activity");
 	e_shell_backend_add_activity (shell_backend, activity);
 	g_object_unref (cancellable);
 	priv->activity = activity;
diff --git a/widgets/misc/e-activity-bar.c b/widgets/misc/e-activity-bar.c
index 0337822..a86e37c 100644
--- a/widgets/misc/e-activity-bar.c
+++ b/widgets/misc/e-activity-bar.c
@@ -23,12 +23,14 @@
 	((obj), E_TYPE_ACTIVITY_BAR, EActivityBarPrivate))
 
 #define FEEDBACK_PERIOD		1 /* seconds */
+#define COMPLETED_ICON_NAME	"emblem-default"
 
 struct _EActivityBarPrivate {
 	EActivity *activity;	/* weak reference */
 	GtkWidget *image;	/* not referenced */
 	GtkWidget *label;	/* not referenced */
 	GtkWidget *cancel;	/* not referenced */
+	GtkWidget *spinner;	/* not referenced */
 
 	/* If the user clicks the Cancel button, keep the cancelled
 	 * EActivity object alive for a short duration so the user
@@ -47,13 +49,35 @@ G_DEFINE_TYPE (
 	GTK_TYPE_INFO_BAR)
 
 static void
+activity_bar_feedback (EActivityBar *bar)
+{
+	EActivity *activity;
+	EActivityState state;
+
+	activity = e_activity_bar_get_activity (bar);
+	g_return_if_fail (E_IS_ACTIVITY (activity));
+
+	state = e_activity_get_state (activity);
+	if (state != E_ACTIVITY_CANCELLED && state != E_ACTIVITY_COMPLETED)
+		return;
+
+	if (bar->priv->timeout_id > 0)
+		g_source_remove (bar->priv->timeout_id);
+
+	/* Hold a reference on the EActivity for a short
+	 * period so the activity bar stays visible. */
+	bar->priv->timeout_id = g_timeout_add_seconds_full (
+		G_PRIORITY_LOW, FEEDBACK_PERIOD, (GSourceFunc) gtk_false,
+		g_object_ref (activity), (GDestroyNotify) g_object_unref);
+}
+
+static void
 activity_bar_update (EActivityBar *bar)
 {
 	EActivity *activity;
+	EActivityState state;
 	GCancellable *cancellable;
 	const gchar *icon_name;
-	gboolean cancelled;
-	gboolean completed;
 	gboolean sensitive;
 	gboolean visible;
 	gchar *description;
@@ -66,14 +90,13 @@ activity_bar_update (EActivityBar *bar)
 	}
 
 	cancellable = e_activity_get_cancellable (activity);
-	cancelled = g_cancellable_is_cancelled (cancellable);
-	completed = e_activity_is_completed (activity);
 	icon_name = e_activity_get_icon_name (activity);
+	state = e_activity_get_state (activity);
 
 	description = e_activity_describe (activity);
 	gtk_label_set_text (GTK_LABEL (bar->priv->label), description);
 
-	if (cancelled) {
+	if (state == E_ACTIVITY_CANCELLED) {
 		PangoAttribute *attr;
 		PangoAttrList *attr_list;
 
@@ -90,25 +113,27 @@ activity_bar_update (EActivityBar *bar)
 		gtk_label_set_attributes (
 			GTK_LABEL (bar->priv->label), NULL);
 
-	if (cancelled)
+	if (state == E_ACTIVITY_COMPLETED)
+		icon_name = COMPLETED_ICON_NAME;
+
+	if (state == E_ACTIVITY_CANCELLED) {
 		gtk_image_set_from_stock (
 			GTK_IMAGE (bar->priv->image),
 			GTK_STOCK_CANCEL, GTK_ICON_SIZE_BUTTON);
-	else {
-		if (completed)
-			icon_name = "emblem-default";
+		gtk_widget_show (bar->priv->image);
+	} else if (icon_name != NULL) {
 		gtk_image_set_from_icon_name (
 			GTK_IMAGE (bar->priv->image),
 			icon_name, GTK_ICON_SIZE_BUTTON);
+		gtk_widget_show (bar->priv->image);
+	} else {
+		gtk_widget_hide (bar->priv->image);
 	}
 
-	visible = (icon_name != NULL);
-	gtk_widget_set_visible (bar->priv->image, visible);
-
 	visible = (cancellable != NULL);
 	gtk_widget_set_visible (bar->priv->cancel, visible);
 
-	sensitive = !cancelled && !completed;
+	sensitive = (state == E_ACTIVITY_RUNNING);
 	gtk_widget_set_sensitive (bar->priv->cancel, sensitive);
 
 	visible = (description != NULL && *description != '\0');
@@ -128,30 +153,16 @@ activity_bar_cancel (EActivityBar *bar)
 
 	cancellable = e_activity_get_cancellable (activity);
 	g_cancellable_cancel (cancellable);
-}
-
-static void
-activity_bar_feedback (EActivityBar *bar)
-{
-	EActivity *activity;
-
-	activity = e_activity_bar_get_activity (bar);
-	g_return_if_fail (E_IS_ACTIVITY (activity));
 
-	if (bar->priv->timeout_id > 0)
-		g_source_remove (bar->priv->timeout_id);
-
-	/* Hold a reference on the EActivity for a short
-	 * period so the activity bar stays visible. */
-	bar->priv->timeout_id = g_timeout_add_seconds_full (
-		G_PRIORITY_LOW, FEEDBACK_PERIOD, (GSourceFunc) gtk_false,
-		g_object_ref (activity), (GDestroyNotify) g_object_unref);
+	activity_bar_update (bar);
 }
 
 static void
 activity_bar_weak_notify_cb (EActivityBar *bar,
                              GObject *where_the_object_was)
 {
+	g_return_if_fail (E_IS_ACTIVITY_BAR (bar));
+
 	bar->priv->activity = NULL;
 	e_activity_bar_set_activity (bar, NULL);
 }
@@ -259,7 +270,19 @@ e_activity_bar_init (EActivityBar *bar)
 	widget = gtk_image_new ();
 	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
 	bar->priv->image = widget;
-	gtk_widget_show (widget);
+
+	widget = gtk_spinner_new ();
+	gtk_spinner_start (GTK_SPINNER (widget));
+	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+	bar->priv->spinner = widget;
+
+	/* The spinner is only visible when the image is not. */
+	g_object_bind_property (
+		bar->priv->image, "visible",
+		bar->priv->spinner, "visible",
+		G_BINDING_BIDIRECTIONAL |
+		G_BINDING_SYNC_CREATE |
+		G_BINDING_INVERT_BOOLEAN);
 
 	widget = gtk_label_new (NULL);
 	gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
@@ -300,12 +323,8 @@ e_activity_bar_set_activity (EActivityBar *bar,
 {
 	g_return_if_fail (E_IS_ACTIVITY_BAR (bar));
 
-	if (activity != NULL) {
+	if (activity != NULL)
 		g_return_if_fail (E_IS_ACTIVITY (activity));
-		g_object_weak_ref (
-			G_OBJECT (activity), (GWeakNotify)
-			activity_bar_weak_notify_cb, bar);
-	}
 
 	if (bar->priv->timeout_id > 0) {
 		g_source_remove (bar->priv->timeout_id);
@@ -324,23 +343,15 @@ e_activity_bar_set_activity (EActivityBar *bar,
 	bar->priv->activity = activity;
 
 	if (activity != NULL) {
-		g_signal_connect_swapped (
-			activity, "cancelled",
-			G_CALLBACK (activity_bar_feedback), bar);
+		g_object_weak_ref (
+			G_OBJECT (activity), (GWeakNotify)
+			activity_bar_weak_notify_cb, bar);
 
 		g_signal_connect_swapped (
-			activity, "completed",
+			activity, "notify::state",
 			G_CALLBACK (activity_bar_feedback), bar);
 
 		g_signal_connect_swapped (
-			activity, "cancelled",
-			G_CALLBACK (activity_bar_update), bar);
-
-		g_signal_connect_swapped (
-			activity, "completed",
-			G_CALLBACK (activity_bar_update), bar);
-
-		g_signal_connect_swapped (
 			activity, "notify",
 			G_CALLBACK (activity_bar_update), bar);
 	}
diff --git a/widgets/misc/e-activity-proxy.c b/widgets/misc/e-activity-proxy.c
index 26d5d30..aea025d 100644
--- a/widgets/misc/e-activity-proxy.c
+++ b/widgets/misc/e-activity-proxy.c
@@ -27,13 +27,20 @@
 	(G_TYPE_INSTANCE_GET_PRIVATE \
 	((obj), E_TYPE_ACTIVITY_PROXY, EActivityProxyPrivate))
 
+#define FEEDBACK_PERIOD		1 /* seconds */
+#define COMPLETED_ICON_NAME	"emblem-default"
+
 struct _EActivityProxyPrivate {
-	EActivity *activity;
-	GtkWidget *button;
-	GtkWidget *image;
-	GtkWidget *label;
-	GtkWidget *cancel;
-	GtkWidget *spinner;
+	EActivity *activity;	/* weak reference */
+	GtkWidget *image;	/* not referenced */
+	GtkWidget *label;	/* not referenced */
+	GtkWidget *cancel;	/* not referenced */
+	GtkWidget *spinner;	/* not referenced */
+
+	/* If the user clicks the Cancel button, keep the cancelled
+	 * EActivity object alive for a short duration so the user
+	 * gets some visual feedback that cancellation worked. */
+	guint timeout_id;
 };
 
 enum {
@@ -47,82 +54,123 @@ G_DEFINE_TYPE (
 	GTK_TYPE_EVENT_BOX)
 
 static void
-activity_proxy_cancel (EActivity *activity)
+activity_proxy_feedback (EActivityProxy *proxy)
 {
-	GCancellable *cancellable;
+	EActivity *activity;
+	EActivityState state;
 
-	/* We shouldn't get here unless the EActivity has a GCancellable,
-	 * since otherwise the cancel button is invisible and unclickable.
-	 * g_cancellable_cancel() will emit a warning if this breaks. */
+	activity = e_activity_proxy_get_activity (proxy);
+	g_return_if_fail (E_IS_ACTIVITY (activity));
 
-	cancellable = e_activity_get_cancellable (activity);
-	g_cancellable_cancel (cancellable);
+	state = e_activity_get_state (activity);
+	if (state != E_ACTIVITY_CANCELLED)
+		return;
+
+	if (proxy->priv->timeout_id > 0)
+		g_source_remove (proxy->priv->timeout_id);
+
+	/* Hold a reference on the EActivity for a short
+	 * period so the activity proxy stays visible. */
+	proxy->priv->timeout_id = g_timeout_add_seconds_full (
+		G_PRIORITY_LOW, FEEDBACK_PERIOD, (GSourceFunc) gtk_false,
+		g_object_ref (activity), (GDestroyNotify) g_object_unref);
 }
 
 static void
 activity_proxy_update (EActivityProxy *proxy)
 {
 	EActivity *activity;
+	EActivityState state;
 	GCancellable *cancellable;
 	const gchar *icon_name;
-	gboolean cancelled;
-	gboolean clickable;
-	gboolean completed;
 	gboolean sensitive;
 	gboolean visible;
 	gchar *description;
 
-	activity = proxy->priv->activity;
+	activity = e_activity_proxy_get_activity (proxy);
+
+	if (activity == NULL) {
+		gtk_widget_hide (GTK_WIDGET (proxy));
+		return;
+	}
+
 	cancellable = e_activity_get_cancellable (activity);
-	cancelled = g_cancellable_is_cancelled (cancellable);
-	clickable = e_activity_get_clickable (activity);
-	completed = e_activity_is_completed (activity);
 	icon_name = e_activity_get_icon_name (activity);
+	state = e_activity_get_state (activity);
 
 	description = e_activity_describe (activity);
 	gtk_widget_set_tooltip_text (GTK_WIDGET (proxy), description);
 	gtk_label_set_text (GTK_LABEL (proxy->priv->label), description);
-	gtk_widget_set_visible (GTK_WIDGET (proxy), (description != NULL));
-	g_free (description);
 
-	/* Note, an activity requires an icon name in order to
-	 * be clickable.  We don't support spinner buttons. */
-	if (icon_name != NULL) {
+	if (state == E_ACTIVITY_CANCELLED) {
+		PangoAttribute *attr;
+		PangoAttrList *attr_list;
+
+		attr_list = pango_attr_list_new ();
+
+		attr = pango_attr_strikethrough_new (TRUE);
+		pango_attr_list_insert (attr_list, attr);
+
+		gtk_label_set_attributes (
+			GTK_LABEL (proxy->priv->label), attr_list);
+
+		pango_attr_list_unref (attr_list);
+	} else
+		gtk_label_set_attributes (
+			GTK_LABEL (proxy->priv->label), NULL);
+
+	if (state == E_ACTIVITY_COMPLETED)
+		icon_name = COMPLETED_ICON_NAME;
+
+	if (state == E_ACTIVITY_CANCELLED) {
+		gtk_image_set_from_stock (
+			GTK_IMAGE (proxy->priv->image),
+			GTK_STOCK_CANCEL, GTK_ICON_SIZE_BUTTON);
+		gtk_widget_show (proxy->priv->image);
+	} else if (icon_name != NULL) {
 		gtk_image_set_from_icon_name (
 			GTK_IMAGE (proxy->priv->image),
 			icon_name, GTK_ICON_SIZE_MENU);
-		gtk_button_set_image (
-			GTK_BUTTON (proxy->priv->button),
-			gtk_image_new_from_icon_name (
-			icon_name, GTK_ICON_SIZE_MENU));
-		gtk_widget_hide (proxy->priv->spinner);
-		if (clickable) {
-			gtk_widget_show (proxy->priv->button);
-			gtk_widget_hide (proxy->priv->image);
-		} else {
-			gtk_widget_hide (proxy->priv->button);
-			gtk_widget_show (proxy->priv->image);
-		}
+		gtk_widget_show (proxy->priv->image);
 	} else {
-		gtk_widget_show (proxy->priv->spinner);
-		gtk_widget_hide (proxy->priv->button);
 		gtk_widget_hide (proxy->priv->image);
 	}
 
 	visible = (cancellable != NULL);
 	gtk_widget_set_visible (proxy->priv->cancel, visible);
 
-	sensitive = !(cancelled || completed);
+	sensitive = (state == E_ACTIVITY_RUNNING);
 	gtk_widget_set_sensitive (proxy->priv->cancel, sensitive);
+
+	visible = (description != NULL && *description != '\0');
+	gtk_widget_set_visible (GTK_WIDGET (proxy), visible);
+
+	g_free (description);
 }
 
 static void
-activity_proxy_set_activity (EActivityProxy *proxy,
-                             EActivity *activity)
+activity_proxy_cancel (EActivityProxy *proxy)
 {
-	g_return_if_fail (proxy->priv->activity == NULL);
+	EActivity *activity;
+	GCancellable *cancellable;
+
+	activity = e_activity_proxy_get_activity (proxy);
+	g_return_if_fail (E_IS_ACTIVITY (activity));
+
+	cancellable = e_activity_get_cancellable (activity);
+	g_cancellable_cancel (cancellable);
+
+	activity_proxy_update (proxy);
+}
+
+static void
+activity_proxy_weak_notify_cb (EActivityProxy *proxy,
+                               GObject *where_the_object_was)
+{
+	g_return_if_fail (E_IS_ACTIVITY_PROXY (proxy));
 
-	proxy->priv->activity = g_object_ref (activity);
+	proxy->priv->activity = NULL;
+	e_activity_proxy_set_activity (proxy, NULL);
 }
 
 static void
@@ -133,7 +181,7 @@ activity_proxy_set_property (GObject *object,
 {
 	switch (property_id) {
 		case PROP_ACTIVITY:
-			activity_proxy_set_activity (
+			e_activity_proxy_set_activity (
 				E_ACTIVITY_PROXY (object),
 				g_value_get_object (value));
 			return;
@@ -166,74 +214,26 @@ activity_proxy_dispose (GObject *object)
 
 	priv = E_ACTIVITY_PROXY_GET_PRIVATE (object);
 
+	if (priv->timeout_id > 0) {
+		g_source_remove (priv->timeout_id);
+		priv->timeout_id = 0;
+	}
+
 	if (priv->activity != NULL) {
 		g_signal_handlers_disconnect_matched (
-			priv->activity, G_SIGNAL_MATCH_FUNC, 0, 0,
-			NULL, activity_proxy_update, NULL);
-		g_object_unref (priv->activity);
+			priv->activity, G_SIGNAL_MATCH_DATA,
+			0, 0, NULL, NULL, object);
+		g_object_weak_unref (
+			G_OBJECT (priv->activity), (GWeakNotify)
+			activity_proxy_weak_notify_cb, object);
 		priv->activity = NULL;
 	}
 
-	if (priv->button != NULL) {
-		g_object_unref (priv->button);
-		priv->button = NULL;
-	}
-
-	if (priv->image != NULL) {
-		g_object_unref (priv->image);
-		priv->image = NULL;
-	}
-
-	if (priv->label != NULL) {
-		g_object_unref (priv->label);
-		priv->label = NULL;
-	}
-
-	if (priv->cancel != NULL) {
-		g_object_unref (priv->cancel);
-		priv->cancel = NULL;
-	}
-
-	if (priv->spinner != NULL) {
-		g_object_unref (priv->spinner);
-		priv->spinner = NULL;
-	}
-
 	/* Chain up to parent's dispose() method. */
 	G_OBJECT_CLASS (e_activity_proxy_parent_class)->dispose (object);
 }
 
 static void
-activity_proxy_constructed (GObject *object)
-{
-	EActivityProxy *proxy;
-
-	proxy = E_ACTIVITY_PROXY (object);
-
-	g_signal_connect_swapped (
-		proxy->priv->button, "clicked",
-		G_CALLBACK (e_activity_clicked), proxy->priv->activity);
-
-	g_signal_connect_swapped (
-		proxy->priv->cancel, "clicked",
-		G_CALLBACK (activity_proxy_cancel), proxy->priv->activity);
-
-	g_signal_connect_swapped (
-		proxy->priv->activity, "cancelled",
-		G_CALLBACK (activity_proxy_update), proxy);
-
-	g_signal_connect_swapped (
-		proxy->priv->activity, "completed",
-		G_CALLBACK (activity_proxy_update), proxy);
-
-	g_signal_connect_swapped (
-		proxy->priv->activity, "notify",
-		G_CALLBACK (activity_proxy_update), proxy);
-
-	activity_proxy_update (proxy);
-}
-
-static void
 e_activity_proxy_class_init (EActivityProxyClass *class)
 {
 	GObjectClass *object_class;
@@ -244,7 +244,6 @@ e_activity_proxy_class_init (EActivityProxyClass *class)
 	object_class->set_property = activity_proxy_set_property;
 	object_class->get_property = activity_proxy_get_property;
 	object_class->dispose = activity_proxy_dispose;
-	object_class->constructed = activity_proxy_constructed;
 
 	g_object_class_install_property (
 		object_class,
@@ -255,7 +254,7 @@ e_activity_proxy_class_init (EActivityProxyClass *class)
 			NULL,
 			E_TYPE_ACTIVITY,
 			G_PARAM_READWRITE |
-			G_PARAM_CONSTRUCT_ONLY));
+			G_PARAM_CONSTRUCT));
 }
 
 static void
@@ -283,37 +282,42 @@ e_activity_proxy_init (EActivityProxy *proxy)
 
 	widget = gtk_image_new ();
 	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
-	proxy->priv->image = g_object_ref (widget);
-	gtk_widget_hide (widget);
-
-	widget = gtk_button_new ();
-	gtk_button_set_relief (GTK_BUTTON (widget), GTK_RELIEF_NONE);
-	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
-	proxy->priv->button = g_object_ref (widget);
-	gtk_widget_hide (widget);
+	proxy->priv->image = widget;
 
 	widget = gtk_spinner_new ();
 	gtk_spinner_start (GTK_SPINNER (widget));
 	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 3);
-	proxy->priv->spinner = g_object_ref (widget);
-	gtk_widget_show (widget);
+	proxy->priv->spinner = widget;
+
+	/* The spinner is only visible when the image is not. */
+	g_object_bind_property (
+		proxy->priv->image, "visible",
+		proxy->priv->spinner, "visible",
+		G_BINDING_BIDIRECTIONAL |
+		G_BINDING_SYNC_CREATE |
+		G_BINDING_INVERT_BOOLEAN);
 
 	widget = gtk_label_new (NULL);
-	gtk_label_set_ellipsize (GTK_LABEL (widget), PANGO_ELLIPSIZE_END);
 	gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
+	gtk_label_set_ellipsize (GTK_LABEL (widget), PANGO_ELLIPSIZE_END);
 	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
-	proxy->priv->label = g_object_ref (widget);
+	proxy->priv->label = widget;
 	gtk_widget_show (widget);
 
+	/* This is only shown if the EActivity has a GCancellable. */
 	widget = gtk_button_new ();
 	gtk_button_set_image (
 		GTK_BUTTON (widget), gtk_image_new_from_stock (
-		GTK_STOCK_STOP, GTK_ICON_SIZE_MENU));
+		GTK_STOCK_CANCEL, GTK_ICON_SIZE_MENU));
 	gtk_button_set_relief (GTK_BUTTON (widget), GTK_RELIEF_NONE);
 	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
 	gtk_widget_set_tooltip_text (widget, _("Cancel"));
-	proxy->priv->cancel = g_object_ref (widget);
+	proxy->priv->cancel = widget;
 	gtk_widget_show (widget);
+
+	g_signal_connect_swapped (
+		widget, "clicked",
+		G_CALLBACK (activity_proxy_cancel), proxy);
 }
 
 GtkWidget *
@@ -322,8 +326,7 @@ e_activity_proxy_new (EActivity *activity)
 	g_return_val_if_fail (E_IS_ACTIVITY (activity), NULL);
 
 	return g_object_new (
-		E_TYPE_ACTIVITY_PROXY,
-		"activity", activity, NULL);
+		E_TYPE_ACTIVITY_PROXY, "activity", activity, NULL);
 }
 
 EActivity *
@@ -333,3 +336,47 @@ e_activity_proxy_get_activity (EActivityProxy *proxy)
 
 	return proxy->priv->activity;
 }
+
+void
+e_activity_proxy_set_activity (EActivityProxy *proxy,
+                               EActivity *activity)
+{
+	g_return_if_fail (E_IS_ACTIVITY_PROXY (proxy));
+
+	if (activity != NULL)
+		g_return_if_fail (E_IS_ACTIVITY (activity));
+
+	if (proxy->priv->timeout_id > 0) {
+		g_source_remove (proxy->priv->timeout_id);
+		proxy->priv->timeout_id = 0;
+	}
+
+	if (proxy->priv->activity != NULL) {
+		g_signal_handlers_disconnect_matched (
+			proxy->priv->activity, G_SIGNAL_MATCH_DATA,
+			0, 0, NULL, NULL, proxy);
+		g_object_weak_unref (
+			G_OBJECT (proxy->priv->activity),
+			(GWeakNotify) activity_proxy_weak_notify_cb, proxy);
+	}
+
+	proxy->priv->activity = activity;
+
+	if (activity != NULL) {
+		g_object_weak_ref (
+			G_OBJECT (activity), (GWeakNotify)
+			activity_proxy_weak_notify_cb, proxy);
+
+		g_signal_connect_swapped (
+			activity, "notify::state",
+			G_CALLBACK (activity_proxy_feedback), proxy);
+
+		g_signal_connect_swapped (
+			activity, "notify",
+			G_CALLBACK (activity_proxy_update), proxy);
+	}
+
+	activity_proxy_update (proxy);
+
+	g_object_notify (G_OBJECT (proxy), "activity");
+}
diff --git a/widgets/misc/e-activity-proxy.h b/widgets/misc/e-activity-proxy.h
index 8844988..cb44d6b 100644
--- a/widgets/misc/e-activity-proxy.h
+++ b/widgets/misc/e-activity-proxy.h
@@ -62,6 +62,8 @@ struct _EActivityProxyClass {
 GType		e_activity_proxy_get_type	(void);
 GtkWidget *	e_activity_proxy_new		(EActivity *activity);
 EActivity *	e_activity_proxy_get_activity	(EActivityProxy *proxy);
+void		e_activity_proxy_set_activity	(EActivityProxy *proxy,
+						 EActivity *activity);
 
 G_END_DECLS
 



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