aboutsummaryrefslogtreecommitdiffstats
path: root/shell/e-shell-backend.c
diff options
context:
space:
mode:
authorMatthew Barnes <mbarnes@redhat.com>2010-10-14 03:37:12 +0800
committerMatthew Barnes <mbarnes@redhat.com>2010-10-14 04:00:03 +0800
commit3fbcc8ef800b2c0ef74fcdea17f6a1e5ec01cdff (patch)
tree173d8c8619a817a2fae8bea469e0fad179b2f8a5 /shell/e-shell-backend.c
parent3f529345a9711a3462525619c024b8344f81e356 (diff)
downloadgsoc2013-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.c155
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);
+ }
}
/**