From a98c07a569292fa66f91d3fa4bd32f32adff1880 Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Sat, 18 Sep 2010 15:57:27 -0400 Subject: Add a GCancellable to EActivity. EActivity now uses a GCancellable to manage cancellations, instead of having its own redundant cancellation API. API changes are as follows: + e_activity_get_cancellable() + e_activity_set_cancellable() - e_activity_cancel() - e_activity_is_cancelled() - e_activity_get_allow_cancel() - e_activity_set_allow_cancel() EActivity's "cancelled" signal remains, but only as a repeater for GCancellable::cancelled signals. It should not be emitted directly. The presence of a GCancellable implies that cancellation is allowed. EActivity does not create its own default GCancellable, it has to be given one. If a CamelOperation (cast as a GCancellable) is given, EActivity will configure itself to listen for status updates from the CamelOperation and propagate the information to its own "primary-text" and "percent" properties. These changes allowed me to start cleaning up some of the incredibly convoluted logic in mail-mt.c -- in particular, mail_operation_status() is completely gone now. mail-mt.c is still in a transitional state -- much more significant changes coming soon. --- addressbook/gui/widgets/e-addressbook-view.c | 3 +- doc/reference/shell/eshell-sections.txt | 6 +- doc/reference/shell/tmpl/e-activity.sgml | 25 +-- doc/reference/shell/tmpl/eshell-unused.sgml | 31 +++ e-util/e-activity.c | 170 +++++++++------ e-util/e-activity.h | 10 +- e-util/e-io-activity.c | 82 +------- e-util/e-io-activity.h | 3 - e-util/e-timeout-activity.c | 2 +- mail/mail-mt.c | 296 ++++++++------------------- modules/calendar/e-cal-shell-view-memopad.c | 3 +- modules/calendar/e-cal-shell-view-private.c | 3 +- modules/calendar/e-cal-shell-view-taskpad.c | 3 +- modules/calendar/e-memo-shell-view-private.c | 3 +- modules/calendar/e-task-shell-view-private.c | 3 +- shell/e-shell-taskbar.c | 21 +- shell/e-shell.c | 21 +- widgets/misc/e-activity-proxy.c | 27 ++- 18 files changed, 288 insertions(+), 424 deletions(-) diff --git a/addressbook/gui/widgets/e-addressbook-view.c b/addressbook/gui/widgets/e-addressbook-view.c index bb6e58f7b6..957d85e30f 100644 --- a/addressbook/gui/widgets/e-addressbook-view.c +++ b/addressbook/gui/widgets/e-addressbook-view.c @@ -1082,8 +1082,9 @@ status_message (EAddressbookView *view, } } else if (activity == NULL) { - activity = e_activity_new (status); + activity = e_activity_new (); view->priv->activity = activity; + e_activity_set_primary_text (activity, status); e_shell_backend_add_activity (shell_backend, activity); } else diff --git a/doc/reference/shell/eshell-sections.txt b/doc/reference/shell/eshell-sections.txt index 05ac15878e..d8b8a5cbd5 100644 --- a/doc/reference/shell/eshell-sections.txt +++ b/doc/reference/shell/eshell-sections.txt @@ -461,14 +461,12 @@ EActionComboBoxPrivate EActivity e_activity_new e_activity_newv -e_activity_cancel e_activity_complete e_activity_clicked e_activity_describe -e_activity_is_cancelled e_activity_is_completed -e_activity_get_allow_cancel -e_activity_set_allow_cancel +e_activity_get_cancellable +e_activity_set_cancellable e_activity_get_clickable e_activity_set_clickable e_activity_get_icon_name diff --git a/doc/reference/shell/tmpl/e-activity.sgml b/doc/reference/shell/tmpl/e-activity.sgml index d56bd0776a..871758fb5e 100644 --- a/doc/reference/shell/tmpl/e-activity.sgml +++ b/doc/reference/shell/tmpl/e-activity.sgml @@ -31,7 +31,7 @@ e-activity -@primary_text: +@void: @Returns: @@ -45,14 +45,6 @@ e-activity @Returns: - - - - - -@activity: - - @@ -78,15 +70,6 @@ e-activity @Returns: - - - - - -@activity: -@Returns: - - @@ -96,7 +79,7 @@ e-activity @Returns: - + @@ -105,13 +88,13 @@ e-activity @Returns: - + @activity: -@allow_cancel: +@cancellable: diff --git a/doc/reference/shell/tmpl/eshell-unused.sgml b/doc/reference/shell/tmpl/eshell-unused.sgml index 15c9658da6..59aed5d191 100644 --- a/doc/reference/shell/tmpl/eshell-unused.sgml +++ b/doc/reference/shell/tmpl/eshell-unused.sgml @@ -95,6 +95,37 @@ e-shell-window.sgml @window: + + + + + +@activity: + + + + + + +@activity: +@Returns: + + + + + + +@activity: +@Returns: + + + + + + +@activity: +@allow_cancel: + diff --git a/e-util/e-activity.c b/e-util/e-activity.c index 631915db89..f90361d7f2 100644 --- a/e-util/e-activity.c +++ b/e-util/e-activity.c @@ -23,6 +23,7 @@ #include #include +#include #include "e-util/e-util.h" @@ -31,20 +32,20 @@ ((obj), E_TYPE_ACTIVITY, EActivityPrivate)) struct _EActivityPrivate { + GCancellable *cancellable; + gchar *icon_name; gchar *primary_text; gchar *secondary_text; gdouble percent; - guint allow_cancel : 1; - guint cancelled : 1; guint clickable : 1; guint completed : 1; }; enum { PROP_0, - PROP_ALLOW_CANCEL, + PROP_CANCELLABLE, PROP_CLICKABLE, PROP_ICON_NAME, PROP_PERCENT, @@ -67,6 +68,19 @@ G_DEFINE_TYPE ( e_activity, G_TYPE_OBJECT) +static void +activity_camel_status_cb (EActivity *activity, + const gchar *description, + gint percent) +{ + /* CamelOperation::status signals are always emitted from idle + * callbacks, so we don't have to screw around with locking. */ + + g_object_set ( + activity, "percent", (gdouble) percent, + "primary-text", description, NULL); +} + static gboolean activity_describe_accumulator (GSignalInvocationHint *ihint, GValue *return_accu, @@ -81,6 +95,14 @@ activity_describe_accumulator (GSignalInvocationHint *ihint, 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); +} + static void activity_set_property (GObject *object, guint property_id, @@ -88,10 +110,10 @@ activity_set_property (GObject *object, GParamSpec *pspec) { switch (property_id) { - case PROP_ALLOW_CANCEL: - e_activity_set_allow_cancel ( + case PROP_CANCELLABLE: + e_activity_set_cancellable ( E_ACTIVITY (object), - g_value_get_boolean (value)); + g_value_get_object (value)); return; case PROP_CLICKABLE: @@ -135,9 +157,9 @@ activity_get_property (GObject *object, GParamSpec *pspec) { switch (property_id) { - case PROP_ALLOW_CANCEL: - g_value_set_boolean ( - value, e_activity_get_allow_cancel ( + case PROP_CANCELLABLE: + g_value_set_object ( + value, e_activity_get_cancellable ( E_ACTIVITY (object))); return; @@ -175,6 +197,26 @@ activity_get_property (GObject *object, G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } +static void +activity_dispose (GObject *object) +{ + EActivityPrivate *priv; + + priv = E_ACTIVITY_GET_PRIVATE (object); + + if (priv->cancellable != NULL) { + g_signal_handlers_disconnect_matched ( + priv->cancellable, + G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, object); + g_object_unref (priv->cancellable); + priv->cancellable = NULL; + } + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (e_activity_parent_class)->dispose (object); +} + static void activity_finalize (GObject *object) { @@ -190,12 +232,6 @@ activity_finalize (GObject *object) G_OBJECT_CLASS (e_activity_parent_class)->finalize (object); } -static void -activity_cancelled (EActivity *activity) -{ - activity->priv->cancelled = TRUE; -} - static void activity_completed (EActivity *activity) { @@ -212,21 +248,22 @@ static gchar * activity_describe (EActivity *activity) { GString *string; + GCancellable *cancellable; const gchar *text; - gboolean cancelled; - gboolean completed; gdouble percent; string = g_string_sized_new (256); + cancellable = e_activity_get_cancellable (activity); text = e_activity_get_primary_text (activity); - cancelled = e_activity_is_cancelled (activity); - completed = e_activity_is_completed (activity); percent = e_activity_get_percent (activity); - if (cancelled) { + if (text == NULL) + return NULL; + + if (g_cancellable_is_cancelled (cancellable)) { /* Translators: This is a cancelled activity. */ g_string_printf (string, _("%s (cancelled)"), text); - } else if (completed) { + } else if (e_activity_is_completed (activity)) { /* Translators: This is a completed activity. */ g_string_printf (string, _("%s (completed)"), text); } else if (percent < 0.0) { @@ -254,21 +291,21 @@ e_activity_class_init (EActivityClass *class) object_class = G_OBJECT_CLASS (class); object_class->set_property = activity_set_property; object_class->get_property = activity_get_property; + object_class->dispose = activity_dispose; object_class->finalize = activity_finalize; - class->cancelled = activity_cancelled; class->completed = activity_completed; class->clicked = activity_clicked; class->describe = activity_describe; g_object_class_install_property ( object_class, - PROP_ALLOW_CANCEL, - g_param_spec_boolean ( - "allow-cancel", + PROP_CANCELLABLE, + g_param_spec_object ( + "cancellable", NULL, NULL, - FALSE, + G_TYPE_CANCELLABLE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); @@ -373,11 +410,9 @@ e_activity_init (EActivity *activity) } EActivity * -e_activity_new (const gchar *primary_text) +e_activity_new (void) { - return g_object_new ( - E_TYPE_ACTIVITY, - "primary-text", primary_text, NULL); + return g_object_new (E_TYPE_ACTIVITY, NULL); } EActivity * @@ -387,38 +422,27 @@ e_activity_newv (const gchar *format, ...) gchar *primary_text; va_list args; + activity = e_activity_new (); + va_start (args, format); primary_text = g_strdup_vprintf (format, args); - activity = e_activity_new (primary_text); + e_activity_set_primary_text (activity, primary_text); g_free (primary_text); va_end (args); return activity; } -void -e_activity_cancel (EActivity *activity) -{ - g_return_if_fail (E_IS_ACTIVITY (activity)); - - if (!activity->priv->allow_cancel) - return; - - if (activity->priv->cancelled) - return; - - if (activity->priv->completed) - return; - - g_signal_emit (activity, signals[CANCELLED], 0); -} - void e_activity_complete (EActivity *activity) { + GCancellable *cancellable; + g_return_if_fail (E_IS_ACTIVITY (activity)); - if (activity->priv->cancelled) + cancellable = e_activity_get_cancellable (activity); + + if (g_cancellable_is_cancelled (cancellable)) return; if (activity->priv->completed) @@ -448,14 +472,6 @@ e_activity_describe (EActivity *activity) return class->describe (activity); } -gboolean -e_activity_is_cancelled (EActivity *activity) -{ - g_return_val_if_fail (E_IS_ACTIVITY (activity), FALSE); - - return activity->priv->cancelled; -} - gboolean e_activity_is_completed (EActivity *activity) { @@ -464,23 +480,47 @@ e_activity_is_completed (EActivity *activity) return activity->priv->completed; } -gboolean -e_activity_get_allow_cancel (EActivity *activity) +GCancellable * +e_activity_get_cancellable (EActivity *activity) { - g_return_val_if_fail (E_IS_ACTIVITY (activity), FALSE); + g_return_val_if_fail (E_IS_ACTIVITY (activity), NULL); - return activity->priv->allow_cancel; + return activity->priv->cancellable; } void -e_activity_set_allow_cancel (EActivity *activity, - gboolean allow_cancel) +e_activity_set_cancellable (EActivity *activity, + GCancellable *cancellable) { g_return_if_fail (E_IS_ACTIVITY (activity)); - activity->priv->allow_cancel = allow_cancel; + if (cancellable != NULL) { + g_return_if_fail (G_IS_CANCELLABLE (cancellable)); + g_object_ref (cancellable); + } + + if (activity->priv->cancellable != NULL) { + g_signal_handlers_disconnect_matched ( + activity->priv->cancellable, + G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, activity); + g_object_unref (activity->priv->cancellable); + } + + 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)) + g_signal_connect_swapped ( + cancellable, "status", + G_CALLBACK (activity_camel_status_cb), activity); - g_object_notify (G_OBJECT (activity), "allow-cancel"); + g_object_notify (G_OBJECT (activity), "cancellable"); } gboolean diff --git a/e-util/e-activity.h b/e-util/e-activity.h index b396e3a630..4573fada57 100644 --- a/e-util/e-activity.h +++ b/e-util/e-activity.h @@ -65,18 +65,16 @@ struct _EActivityClass { }; GType e_activity_get_type (void); -EActivity * e_activity_new (const gchar *primary_text); +EActivity * e_activity_new (void); EActivity * e_activity_newv (const gchar *format, ...) G_GNUC_PRINTF (1, 2); -void e_activity_cancel (EActivity *activity); void e_activity_complete (EActivity *activity); void e_activity_clicked (EActivity *activity); gchar * e_activity_describe (EActivity *activity); -gboolean e_activity_is_cancelled (EActivity *activity); gboolean e_activity_is_completed (EActivity *activity); -gboolean e_activity_get_allow_cancel (EActivity *activity); -void e_activity_set_allow_cancel (EActivity *activity, - gboolean allow_cancel); +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); diff --git a/e-util/e-io-activity.c b/e-util/e-io-activity.c index c8eb761708..e519fea18b 100644 --- a/e-util/e-io-activity.c +++ b/e-util/e-io-activity.c @@ -27,13 +27,11 @@ struct _EIOActivityPrivate { GAsyncResult *async_result; - GCancellable *cancellable; }; enum { PROP_0, - PROP_ASYNC_RESULT, - PROP_CANCELLABLE + PROP_ASYNC_RESULT }; G_DEFINE_TYPE ( @@ -53,12 +51,6 @@ io_activity_set_property (GObject *object, E_IO_ACTIVITY (object), g_value_get_object (value)); return; - - case PROP_CANCELLABLE: - e_io_activity_set_cancellable ( - E_IO_ACTIVITY (object), - g_value_get_object (value)); - return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -76,12 +68,6 @@ io_activity_get_property (GObject *object, value, e_io_activity_get_async_result ( E_IO_ACTIVITY (object))); return; - - case PROP_CANCELLABLE: - g_value_set_object ( - value, e_io_activity_get_cancellable ( - E_IO_ACTIVITY (object))); - return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -99,31 +85,10 @@ io_activity_dispose (GObject *object) priv->async_result = NULL; } - if (priv->cancellable != NULL) { - g_object_unref (priv->cancellable); - priv->cancellable = NULL; - } - /* Chain up to parent's dispose() method. */ G_OBJECT_CLASS (e_io_activity_parent_class)->dispose (object); } -static void -io_activity_cancelled (EActivity *activity) -{ - EIOActivity *io_activity; - GCancellable *cancellable; - - /* Chain up to parent's cancelled() method. */ - E_ACTIVITY_CLASS (e_io_activity_parent_class)->cancelled (activity); - - io_activity = E_IO_ACTIVITY (activity); - cancellable = e_io_activity_get_cancellable (io_activity); - - if (cancellable != NULL) - g_cancellable_cancel (cancellable); -} - static void io_activity_completed (EActivity *activity) { @@ -158,7 +123,6 @@ e_io_activity_class_init (EIOActivityClass *class) object_class->dispose = io_activity_dispose; activity_class = E_ACTIVITY_CLASS (class); - activity_class->cancelled = io_activity_cancelled; activity_class->completed = io_activity_completed; g_object_class_install_property ( @@ -171,17 +135,6 @@ e_io_activity_class_init (EIOActivityClass *class) G_TYPE_ASYNC_RESULT, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - - g_object_class_install_property ( - object_class, - PROP_CANCELLABLE, - g_param_spec_object ( - "cancellable", - "Cancellable", - NULL, - G_TYPE_CANCELLABLE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT)); } static void @@ -236,36 +189,3 @@ e_io_activity_set_async_result (EIOActivity *io_activity, g_object_notify (G_OBJECT (io_activity), "async-result"); } -GCancellable * -e_io_activity_get_cancellable (EIOActivity *io_activity) -{ - g_return_val_if_fail (E_IS_IO_ACTIVITY (io_activity), NULL); - - return io_activity->priv->cancellable; -} - -void -e_io_activity_set_cancellable (EIOActivity *io_activity, - GCancellable *cancellable) -{ - g_return_if_fail (E_IS_IO_ACTIVITY (io_activity)); - - if (cancellable != NULL) { - g_return_if_fail (G_IS_CANCELLABLE (cancellable)); - g_object_ref (cancellable); - } - - if (io_activity->priv->cancellable != NULL) - g_object_unref (io_activity->priv->cancellable); - - io_activity->priv->cancellable = cancellable; - - g_object_freeze_notify (G_OBJECT (io_activity)); - - e_activity_set_allow_cancel ( - E_ACTIVITY (io_activity), (cancellable != NULL)); - - g_object_notify (G_OBJECT (io_activity), "cancellable"); - - g_object_thaw_notify (G_OBJECT (io_activity)); -} diff --git a/e-util/e-io-activity.h b/e-util/e-io-activity.h index 773417472d..20a7a06082 100644 --- a/e-util/e-io-activity.h +++ b/e-util/e-io-activity.h @@ -66,9 +66,6 @@ EActivity * e_io_activity_new (const gchar *primary_text, GAsyncResult * e_io_activity_get_async_result (EIOActivity *io_activity); void e_io_activity_set_async_result (EIOActivity *io_activity, GAsyncResult *async_result); -GCancellable * e_io_activity_get_cancellable (EIOActivity *io_activity); -void e_io_activity_set_cancellable (EIOActivity *io_activity, - GCancellable *cancellable); G_END_DECLS diff --git a/e-util/e-timeout-activity.c b/e-util/e-timeout-activity.c index 4ddf39f89c..b5a48f0520 100644 --- a/e-util/e-timeout-activity.c +++ b/e-util/e-timeout-activity.c @@ -168,7 +168,7 @@ e_timeout_activity_set_timeout (ETimeoutActivity *timeout_activity, g_return_if_fail (E_IS_TIMEOUT_ACTIVITY (timeout_activity)); if (timeout_activity->priv->timeout_id > 0) - e_activity_cancel (E_ACTIVITY (timeout_activity)); + g_source_remove (timeout_activity->priv->timeout_id); timeout_activity->priv->timeout_id = g_timeout_add_seconds ( seconds, (GSourceFunc) timeout_activity_cb, timeout_activity); diff --git a/mail/mail-mt.c b/mail/mail-mt.c index ce26572756..76e2629121 100644 --- a/mail/mail-mt.c +++ b/mail/mail-mt.c @@ -40,16 +40,8 @@ * to rework or get rid of the functions that use this. */ const gchar *shell_builtin_backend = "mail"; -static void mail_operation_status (CamelOperation *op, - const gchar *what, - gint pc, - gpointer data); - /* background operation status stuff */ struct _MailMsgPrivate { - /* XXX We need to keep track of the state external to the - * pointer itself for locking/race conditions. */ - gint activity_state; EActivity *activity; GtkWidget *error; gboolean cancelable; @@ -64,6 +56,28 @@ static GCond *mail_msg_cond; MailAsyncEvent *mail_async_event; +static void +mail_msg_cancelled (CamelOperation *operation, + gpointer user_data) +{ + mail_msg_cancel (GPOINTER_TO_UINT (user_data)); +} + +static gboolean +mail_msg_submit (EActivity *activity) +{ + EShell *shell; + EShellBackend *shell_backend; + + shell = e_shell_get_default (); + shell_backend = e_shell_get_backend_by_name ( + shell, shell_builtin_backend); + + e_shell_backend_add_activity (shell_backend, activity); + + return FALSE; +} + gpointer mail_msg_new (MailMsgInfo *info) { @@ -78,14 +92,22 @@ mail_msg_new (MailMsgInfo *info) msg->cancel = camel_operation_new (); msg->priv = g_slice_new0 (MailMsgPrivate); + msg->priv->activity = e_activity_new (); msg->priv->cancelable = TRUE; + e_activity_set_percent (msg->priv->activity, 0.0); + + e_activity_set_cancellable ( + msg->priv->activity, + G_CANCELLABLE (msg->cancel)); + g_signal_connect ( - msg->cancel, "status", - G_CALLBACK (mail_operation_status), + msg->cancel, "cancelled", + G_CALLBACK (mail_msg_cancelled), GINT_TO_POINTER (msg->seq)); - g_hash_table_insert (mail_msg_active_table, GINT_TO_POINTER (msg->seq), msg); + g_hash_table_insert ( + mail_msg_active_table, GINT_TO_POINTER (msg->seq), msg); d(printf("New message %p\n", msg)); @@ -94,28 +116,6 @@ mail_msg_new (MailMsgInfo *info) return msg; } -static void -end_event_callback (CamelObject *o, EActivity *activity, gpointer error) -{ - EShell *shell; - EShellBackend *shell_backend; - - shell = e_shell_get_default (); - shell_backend = e_shell_get_backend_by_name ( - shell, shell_builtin_backend); - - if (activity != NULL) { - e_activity_complete (activity); - g_object_unref (activity); - } - - if (error != NULL) { - activity = e_alert_activity_new_warning (error); - e_shell_backend_add_activity (shell_backend, activity); - g_object_unref (activity); - } -} - #ifdef MALLOC_CHECK #include @@ -140,11 +140,31 @@ checkmem (gpointer p) } #endif -static void +static gboolean mail_msg_free (MailMsg *mail_msg) { - if (mail_msg->priv->activity != NULL) + EShell *shell; + EShellBackend *shell_backend; + + /* This is an idle callback. */ + + shell = e_shell_get_default (); + shell_backend = e_shell_get_backend_by_name ( + shell, shell_builtin_backend); + + g_mutex_lock (mail_msg_lock); + + g_hash_table_remove ( + mail_msg_active_table, + GINT_TO_POINTER (mail_msg->seq)); + g_cond_broadcast (mail_msg_cond); + + g_mutex_unlock (mail_msg_lock); + + if (mail_msg->priv->activity != NULL) { + e_activity_complete (mail_msg->priv->activity); g_object_unref (mail_msg->priv->activity); + } if (mail_msg->cancel != NULL) g_object_unref (mail_msg->cancel); @@ -152,8 +172,20 @@ mail_msg_free (MailMsg *mail_msg) if (mail_msg->error != NULL) g_error_free (mail_msg->error); + if (mail_msg->priv->error != NULL) { + EActivity *activity; + GtkWidget *widget; + + widget = mail_msg->priv->error; + activity = e_alert_activity_new_warning (widget); + e_shell_backend_add_activity (shell_backend, activity); + g_object_unref (activity); + } + g_slice_free (MailMsgPrivate, mail_msg->priv); g_slice_free1 (mail_msg->info->size, mail_msg); + + return FALSE; } gpointer @@ -172,8 +204,6 @@ void mail_msg_unref (gpointer msg) { MailMsg *mail_msg = msg; - EActivity *activity = NULL; - GtkWidget *error = NULL; g_return_if_fail (mail_msg != NULL); g_return_if_fail (mail_msg->ref_count > 0); @@ -191,36 +221,9 @@ mail_msg_unref (gpointer msg) if (mail_msg->info->free) mail_msg->info->free (mail_msg); - g_mutex_lock (mail_msg_lock); - - g_hash_table_remove ( - mail_msg_active_table, GINT_TO_POINTER (mail_msg->seq)); - g_cond_broadcast (mail_msg_cond); - - /* We need to make sure we dont lose a reference here YUCK YUCK */ - /* This is tightly integrated with the code in do_op_status, - as it closely relates to the CamelOperation setup in msg_new () above */ - if (mail_msg->priv->activity_state == 1) { - /* tell the other to free it itself */ - mail_msg->priv->activity_state = 3; - g_mutex_unlock (mail_msg_lock); - return; - } else { - activity = mail_msg->priv->activity; - if (activity != NULL) - g_object_ref (activity); - error = mail_msg->priv->error; - } - - g_mutex_unlock (mail_msg_lock); - - mail_msg_free (mail_msg); - - if (activity != NULL) - mail_async_event_emit ( - mail_async_event, MAIL_ASYNC_GUI, - (MailAsyncFunc) end_event_callback, - NULL, activity, error); + /* Destroy the message from an idle callback + * so we know we're in the main loop thread. */ + g_idle_add ((GSourceFunc) mail_msg_free, mail_msg); } /* hash table of ops->dialogue of active errors */ @@ -442,6 +445,11 @@ 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) { + g_idle_add_full ( + G_PRIORITY_DEFAULT, + (GSourceFunc) mail_msg_submit, + g_object_ref (msg->priv->activity), + (GDestroyNotify) g_object_unref); if (msg->info->exec != NULL) msg->info->exec (msg); if (msg->info->done != NULL) @@ -469,6 +477,12 @@ mail_msg_proxy (MailMsg *msg) g_free (text); } + g_idle_add_full ( + G_PRIORITY_DEFAULT, + (GSourceFunc) mail_msg_submit, + g_object_ref (msg->priv->activity), + (GDestroyNotify) g_object_unref); + if (msg->info->exec != NULL) msg->info->exec (msg); @@ -840,154 +854,6 @@ mail_call_main (mail_call_t type, MailMainFunc func, ...) return ret; } -/* ******************************************************************************** */ - -struct _op_status_msg { - MailMsg base; - - CamelOperation *op; - gchar *what; - gint pc; - gpointer data; -}; - -static void -op_cancelled_cb (EActivity *activity, - gpointer user_data) -{ - mail_msg_cancel (GPOINTER_TO_UINT (user_data)); -} - -static void -op_status_exec (struct _op_status_msg *m) -{ - EShell *shell; - EShellBackend *shell_backend; - MailMsg *msg; - MailMsgPrivate *data; - gchar *out, *p, *o, c; - gint pc; - - g_return_if_fail (mail_in_main_thread ()); - - shell = e_shell_get_default (); - shell_backend = e_shell_get_backend_by_name ( - shell, shell_builtin_backend); - - g_mutex_lock (mail_msg_lock); - - msg = g_hash_table_lookup (mail_msg_active_table, m->data); - - if (msg == NULL) { - g_mutex_unlock (mail_msg_lock); - return; - } - - data = msg->priv; - - out = g_alloca (strlen (m->what) * 2 + 1); - o = out; - p = m->what; - while ((c = *p++)) { - if (c == '%') - *o++ = '%'; - *o++ = c; - } - *o = 0; - - pc = m->pc; - - if (data->activity == NULL) { - gchar *what; - - /* its being created/removed? well leave it be */ - if (data->activity_state == 1 || data->activity_state == 3) { - g_mutex_unlock (mail_msg_lock); - return; - } else { - data->activity_state = 1; - - g_mutex_unlock (mail_msg_lock); - if (msg->info->desc) - what = msg->info->desc (msg); - else if (m->what) - what = g_strdup (m->what); - /* uncommenting because message is not very useful for a user, see bug 271734*/ - else { - what = g_strdup(""); - } - - data->activity = e_activity_new (what); - e_activity_set_allow_cancel (data->activity, TRUE); - e_activity_set_percent (data->activity, 0.0); - e_shell_backend_add_activity (shell_backend, data->activity); - - g_signal_connect ( - data->activity, "cancelled", - G_CALLBACK (op_cancelled_cb), - GUINT_TO_POINTER (msg->seq)); - - g_free (what); - g_mutex_lock (mail_msg_lock); - if (data->activity_state == 3) { - EActivity *activity; - - activity = g_object_ref (data->activity); - - g_mutex_unlock (mail_msg_lock); - mail_msg_free (msg); - - if (activity != 0) - mail_async_event_emit ( - mail_async_event, MAIL_ASYNC_GUI, (MailAsyncFunc) end_event_callback, - NULL, activity, NULL); - } else { - data->activity_state = 2; - g_mutex_unlock (mail_msg_lock); - } - return; - } - } else if (data->activity != NULL) { - e_activity_set_primary_text (data->activity, out); - e_activity_set_percent (data->activity, pc); - g_mutex_unlock (mail_msg_lock); - } else { - g_mutex_unlock (mail_msg_lock); - } -} - -static void -op_status_free (struct _op_status_msg *m) -{ - g_free (m->what); -} - -static MailMsgInfo op_status_info = { - sizeof (struct _op_status_msg), - (MailMsgDescFunc) NULL, - (MailMsgExecFunc) op_status_exec, - (MailMsgDoneFunc) NULL, - (MailMsgFreeFunc) op_status_free -}; - -static void -mail_operation_status (CamelOperation *op, - const gchar *what, - gint pc, - gpointer data) -{ - struct _op_status_msg *m; - - d(printf("got operation statys: %s %d%%\n", what, pc)); - - m = mail_msg_new (&op_status_info); - m->op = op; - m->what = g_strdup (what); - m->pc = pc; - m->data = data; - mail_msg_main_loop_push (m); -} - void mail_mt_set_backend (gchar *backend) { diff --git a/modules/calendar/e-cal-shell-view-memopad.c b/modules/calendar/e-cal-shell-view-memopad.c index 267f8145f6..7fdf356304 100644 --- a/modules/calendar/e-cal-shell-view-memopad.c +++ b/modules/calendar/e-cal-shell-view-memopad.c @@ -435,8 +435,9 @@ e_cal_shell_view_memopad_set_status_message (ECalShellView *cal_shell_view, } } else if (activity == NULL) { - activity = e_activity_new (status_message); + activity = e_activity_new (); e_activity_set_percent (activity, percent); + e_activity_set_primary_text (activity, status_message); e_shell_backend_add_activity (shell_backend, activity); } else { diff --git a/modules/calendar/e-cal-shell-view-private.c b/modules/calendar/e-cal-shell-view-private.c index a02888db8e..c5a9f22f03 100644 --- a/modules/calendar/e-cal-shell-view-private.c +++ b/modules/calendar/e-cal-shell-view-private.c @@ -810,8 +810,9 @@ e_cal_shell_view_set_status_message (ECalShellView *cal_shell_view, activity = NULL; } } else if (activity == NULL) { - activity = e_activity_new (status_message); + activity = e_activity_new (); e_activity_set_percent (activity, percent); + e_activity_set_primary_text (activity, status_message); e_shell_backend_add_activity (shell_backend, activity); } else { e_activity_set_percent (activity, percent); diff --git a/modules/calendar/e-cal-shell-view-taskpad.c b/modules/calendar/e-cal-shell-view-taskpad.c index c7269bcfd1..a00e630afd 100644 --- a/modules/calendar/e-cal-shell-view-taskpad.c +++ b/modules/calendar/e-cal-shell-view-taskpad.c @@ -562,8 +562,9 @@ e_cal_shell_view_taskpad_set_status_message (ECalShellView *cal_shell_view, } } else if (activity == NULL) { - activity = e_activity_new (status_message); + activity = e_activity_new (); e_activity_set_percent (activity, percent); + e_activity_set_primary_text (activity, status_message); e_shell_backend_add_activity (shell_backend, activity); } else { diff --git a/modules/calendar/e-memo-shell-view-private.c b/modules/calendar/e-memo-shell-view-private.c index 061e3c0170..a33296daf5 100644 --- a/modules/calendar/e-memo-shell-view-private.c +++ b/modules/calendar/e-memo-shell-view-private.c @@ -375,8 +375,9 @@ e_memo_shell_view_set_status_message (EMemoShellView *memo_shell_view, } } else if (activity == NULL) { - activity = e_activity_new (status_message); + activity = e_activity_new (); e_activity_set_percent (activity, percent); + e_activity_set_primary_text (activity, status_message); e_shell_backend_add_activity (shell_backend, activity); } else { diff --git a/modules/calendar/e-task-shell-view-private.c b/modules/calendar/e-task-shell-view-private.c index e5cf75711c..5e1b352ecd 100644 --- a/modules/calendar/e-task-shell-view-private.c +++ b/modules/calendar/e-task-shell-view-private.c @@ -524,8 +524,9 @@ e_task_shell_view_set_status_message (ETaskShellView *task_shell_view, } } else if (activity == NULL) { - activity = e_activity_new (status_message); + activity = e_activity_new (); e_activity_set_percent (activity, percent); + e_activity_set_primary_text (activity, status_message); e_shell_backend_add_activity (shell_backend, activity); } else { diff --git a/shell/e-shell-taskbar.c b/shell/e-shell-taskbar.c index a82d3d6246..47f900ae3e 100644 --- a/shell/e-shell-taskbar.c +++ b/shell/e-shell-taskbar.c @@ -96,12 +96,13 @@ shell_taskbar_activity_add (EShellTaskbar *shell_taskbar, GtkBox *box; GtkWidget *proxy; + /* Proxy widgets manage their own visibility. + * Don't call gtk_widget_show() on it here. */ proxy = e_activity_proxy_new (activity); box = GTK_BOX (shell_taskbar->priv->hbox); gtk_box_pack_start (box, proxy, TRUE, TRUE, 0); gtk_box_reorder_child (box, proxy, 0); gtk_widget_show (GTK_WIDGET (box)); - gtk_widget_show (proxy); g_hash_table_insert ( shell_taskbar->priv->proxy_table, @@ -176,13 +177,14 @@ shell_taskbar_get_property (GObject *object, } static gboolean -disconnect_remove (EActivity *activity, - EActivityProxy *proxy, - EShellTaskbar *shell_taskbar) +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); + g_signal_handlers_disconnect_matched ( + activity, G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, shell_taskbar); + return TRUE; } @@ -217,9 +219,8 @@ shell_taskbar_dispose (GObject *object) priv->hbox = NULL; } - g_hash_table_foreach_remove (priv->proxy_table, - (GHRFunc) disconnect_remove, - object); + 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); diff --git a/shell/e-shell.c b/shell/e-shell.c index 93832ec7fe..28abe028dc 100644 --- a/shell/e-shell.c +++ b/shell/e-shell.c @@ -240,8 +240,11 @@ shell_prepare_for_offline (EShell *shell) if (shell->priv->preparing_for_line_change != NULL) return; - shell->priv->preparing_for_line_change = - e_activity_new (_("Preparing to go offline...")); + shell->priv->preparing_for_line_change = e_activity_new (); + + e_activity_set_primary_text ( + shell->priv->preparing_for_line_change, + _("Preparing to go offline...")); g_object_add_toggle_ref ( G_OBJECT (shell->priv->preparing_for_line_change), @@ -290,8 +293,11 @@ shell_prepare_for_online (EShell *shell) if (shell->priv->preparing_for_line_change != NULL) return; - shell->priv->preparing_for_line_change = - e_activity_new (_("Preparing to go online...")); + shell->priv->preparing_for_line_change = e_activity_new (); + + e_activity_set_primary_text ( + shell->priv->preparing_for_line_change, + _("Preparing to go online...")); g_object_add_toggle_ref ( G_OBJECT (shell->priv->preparing_for_line_change), @@ -349,8 +355,11 @@ shell_prepare_for_quit (EShell *shell) if (shell->priv->preparing_for_quit != NULL) return; - shell->priv->preparing_for_quit = - e_activity_new (_("Preparing to quit...")); + shell->priv->preparing_for_quit = e_activity_new (); + + e_activity_set_primary_text ( + shell->priv->preparing_for_quit, + _("Preparing to quit...")); g_object_add_toggle_ref ( G_OBJECT (shell->priv->preparing_for_quit), diff --git a/widgets/misc/e-activity-proxy.c b/widgets/misc/e-activity-proxy.c index 8e20e67d5d..e96f18ed63 100644 --- a/widgets/misc/e-activity-proxy.c +++ b/widgets/misc/e-activity-proxy.c @@ -46,20 +46,34 @@ G_DEFINE_TYPE ( e_activity_proxy, GTK_TYPE_EVENT_BOX) +static void +activity_proxy_cancel (EActivity *activity) +{ + GCancellable *cancellable; + + /* 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. */ + + cancellable = e_activity_get_cancellable (activity); + g_cancellable_cancel (cancellable); +} + static void activity_proxy_update (EActivityProxy *proxy) { - EActivity *activity = proxy->priv->activity; + EActivity *activity; + GCancellable *cancellable; const gchar *icon_name; - gboolean allow_cancel; gboolean cancelled; gboolean clickable; gboolean completed; gboolean sensitive; gchar *description; - allow_cancel = e_activity_get_allow_cancel (activity); - cancelled = e_activity_is_cancelled (activity); + activity = proxy->priv->activity; + 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); @@ -67,6 +81,7 @@ activity_proxy_update (EActivityProxy *proxy) 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 @@ -93,7 +108,7 @@ activity_proxy_update (EActivityProxy *proxy) gtk_widget_hide (proxy->priv->image); } - if (allow_cancel) + if (cancellable != NULL) gtk_widget_show (proxy->priv->cancel); else gtk_widget_hide (proxy->priv->cancel); @@ -202,7 +217,7 @@ activity_proxy_constructed (GObject *object) g_signal_connect_swapped ( proxy->priv->cancel, "clicked", - G_CALLBACK (e_activity_cancel), proxy->priv->activity); + G_CALLBACK (activity_proxy_cancel), proxy->priv->activity); g_signal_connect_swapped ( proxy->priv->activity, "cancelled", -- cgit