diff options
author | Matthew Barnes <mbarnes@redhat.com> | 2010-10-14 03:37:12 +0800 |
---|---|---|
committer | Matthew Barnes <mbarnes@redhat.com> | 2010-10-14 04:00:03 +0800 |
commit | 3fbcc8ef800b2c0ef74fcdea17f6a1e5ec01cdff (patch) | |
tree | 173d8c8619a817a2fae8bea469e0fad179b2f8a5 /shell/e-shell-backend.c | |
parent | 3f529345a9711a3462525619c024b8344f81e356 (diff) | |
download | gsoc2013-evolution-3fbcc8ef800b2c0ef74fcdea17f6a1e5ec01cdff.tar.gz gsoc2013-evolution-3fbcc8ef800b2c0ef74fcdea17f6a1e5ec01cdff.tar.zst gsoc2013-evolution-3fbcc8ef800b2c0ef74fcdea17f6a1e5ec01cdff.zip |
EShellBackend: Respond to EShell::prepare-for-quit signals.
Listen for "prepare-for-quit" signals from the shell and inhibit
shutdown until all the activities we're tracking are finalized.
Also, add a couple supporting functions:
gboolean e_shell_backend_is_busy (EShellBackend *shell_backend);
void e_shell_backend_cancel_all (EShellBackend *shell_backend);
These will eventually replace mail_msg_active() and mail_cancel_all().
Diffstat (limited to 'shell/e-shell-backend.c')
-rw-r--r-- | shell/e-shell-backend.c | 155 |
1 files changed, 147 insertions, 8 deletions
diff --git a/shell/e-shell-backend.c b/shell/e-shell-backend.c index d679c05ed5..0d7ff020c7 100644 --- a/shell/e-shell-backend.c +++ b/shell/e-shell-backend.c @@ -59,6 +59,11 @@ struct _EShellBackendPrivate { }; enum { + PROP_0, + PROP_BUSY +}; + +enum { ACTIVITY_ADDED, ACTIVITY_REMOVED, LAST_SIGNAL @@ -73,36 +78,95 @@ shell_backend_activity_finalized_cb (EShellBackend *shell_backend, EActivity *finalized_activity) { g_queue_remove (shell_backend->priv->activities, finalized_activity); + + /* Only emit "notify::busy" when switching from busy to idle. */ + if (g_queue_is_empty (shell_backend->priv->activities)) + g_object_notify (G_OBJECT (shell_backend), "busy"); + g_object_unref (shell_backend); } +static void +shell_backend_notify_busy_cb (EShellBackend *shell_backend, + GParamSpec *pspec, + EActivity *activity) +{ + /* Unreferencing the EActivity allows the shell to + * proceed with shutdown. */ + if (!e_shell_backend_is_busy (shell_backend)) { + g_signal_handlers_disconnect_by_func ( + shell_backend, + shell_backend_notify_busy_cb, + activity); + g_object_unref (activity); + } +} + +static void +shell_backend_prepare_for_quit_cb (EShell *shell, + EActivity *activity, + EShellBackend *shell_backend) +{ + /* Referencing the EActivity delays shutdown; the + * reference count acts like a counting semaphore. */ + if (e_shell_backend_is_busy (shell_backend)) + g_signal_connect ( + shell_backend, "notify::busy", + G_CALLBACK (shell_backend_notify_busy_cb), + g_object_ref (activity)); +} + static GObject * shell_backend_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { - EShellBackendPrivate *priv; + EShellBackend *shell_backend; EShellBackendClass *class; EShellViewClass *shell_view_class; + EShell *shell; GObject *object; /* Chain up to parent's construct() method. */ object = G_OBJECT_CLASS (e_shell_backend_parent_class)->constructor ( type, n_construct_properties, construct_properties); - class = E_SHELL_BACKEND_GET_CLASS (object); - priv = E_SHELL_BACKEND_GET_PRIVATE (object); + shell_backend = E_SHELL_BACKEND (object); + shell = e_shell_backend_get_shell (shell_backend); /* Install a reference to ourselves in the * corresponding EShellViewClass structure. */ + class = E_SHELL_BACKEND_GET_CLASS (shell_backend); shell_view_class = g_type_class_ref (class->shell_view_type); - shell_view_class->shell_backend = g_object_ref (object); - priv->shell_view_class = shell_view_class; + shell_view_class->shell_backend = g_object_ref (shell_backend); + shell_backend->priv->shell_view_class = shell_view_class; + + g_signal_connect ( + shell, "prepare-for-quit", + G_CALLBACK (shell_backend_prepare_for_quit_cb), + shell_backend); return object; } static void +shell_backend_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_BUSY: + g_value_set_boolean ( + value, e_shell_backend_is_busy ( + E_SHELL_BACKEND (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void shell_backend_dispose (GObject *object) { EShellBackendPrivate *priv; @@ -185,6 +249,7 @@ e_shell_backend_class_init (EShellBackendClass *class) object_class = G_OBJECT_CLASS (class); object_class->constructor = shell_backend_constructor; + object_class->get_property = shell_backend_get_property; object_class->dispose = shell_backend_dispose; object_class->finalize = shell_backend_finalize; @@ -195,6 +260,21 @@ e_shell_backend_class_init (EShellBackendClass *class) class->get_data_dir = shell_backend_get_data_dir; /** + * EShellBackend:busy + * + * Whether any activities are still in progress. + **/ + g_object_class_install_property ( + object_class, + PROP_BUSY, + g_param_spec_boolean ( + "busy", + "Busy", + "Whether any activities are still in progress", + FALSE, + G_PARAM_READABLE)); + + /** * EShellBackend::activity-added * @shell_backend: the #EShellBackend that emitted the signal * @activity: an #EActivity @@ -311,17 +391,22 @@ e_shell_backend_get_shell (EShellBackend *shell_backend) * @shell_backend: an #EShellBackend * @activity: an #EActivity * - * Emits an #EShellBackend::activity-added signal. + * Emits an #EShellBackend::activity-added signal and tracks the @activity + * until it is finalized. **/ void e_shell_backend_add_activity (EShellBackend *shell_backend, EActivity *activity) { + GCancellable *cancellable; + g_return_if_fail (E_IS_SHELL_BACKEND (shell_backend)); g_return_if_fail (E_IS_ACTIVITY (activity)); - /* skip already cancelled activities */ - if (g_cancellable_is_cancelled (e_activity_get_cancellable (activity))) + cancellable = e_activity_get_cancellable (activity); + + /* Skip cancelled activities. */ + if (g_cancellable_is_cancelled (cancellable)) return; g_queue_push_tail (shell_backend->priv->activities, activity); @@ -334,6 +419,60 @@ e_shell_backend_add_activity (EShellBackend *shell_backend, 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"); +} + +/** + * e_shell_backend_is_busy: + * @shell_backend: an #EShellBackend + * + * Returns %TRUE if any activities passed to e_shell_backend_add_activity() + * are still in progress, %FALSE if the @shell_backend is currently idle. + * + * Returns: %TRUE if activities are still in progress + **/ +gboolean +e_shell_backend_is_busy (EShellBackend *shell_backend) +{ + g_return_val_if_fail (E_IS_SHELL_BACKEND (shell_backend), FALSE); + + return !g_queue_is_empty (shell_backend->priv->activities); +} + +/** + * e_shell_backend_cancel_all: + * @shell_backend: an #EShellBackend + * + * Cancels all activities passed to e_shell_backend_add_activity() that + * have not already been finalized. Note that an #EActivity can only be + * cancelled if it was given a #GCancellable object. + * + * Also, assuming all activities are cancellable, there may still be a + * delay before e_shell_backend_is_busy() returns %FALSE, because some + * activities may not be able to respond to the cancellation request + * immediately. Connect to the "notify::busy" signal if you need + * notification of @shell_backend becoming idle. + **/ +void +e_shell_backend_cancel_all (EShellBackend *shell_backend) +{ + GList *list, *iter; + + g_return_if_fail (E_IS_SHELL_BACKEND (shell_backend)); + + list = g_queue_peek_head_link (shell_backend->priv->activities); + + for (iter = list; iter != NULL; iter = g_list_next (iter)) { + EActivity *activity; + GCancellable *cancellable; + + activity = E_ACTIVITY (iter->data); + cancellable = e_activity_get_cancellable (activity); + g_cancellable_cancel (cancellable); + } } /** |