diff options
author | Matthew Barnes <mbarnes@redhat.com> | 2013-05-24 03:44:03 +0800 |
---|---|---|
committer | Matthew Barnes <mbarnes@redhat.com> | 2013-05-24 04:36:02 +0800 |
commit | 749dabd02565e285ceef8e1dad9ba35b48b2fbaf (patch) | |
tree | 6fa141cb53de01be94cd209efca749592f9ad6c9 /e-util | |
parent | 9058c6f85dc49f9500e7e67819acfd8c0d2d369c (diff) | |
download | gsoc2013-evolution-749dabd02565e285ceef8e1dad9ba35b48b2fbaf.tar.gz gsoc2013-evolution-749dabd02565e285ceef8e1dad9ba35b48b2fbaf.tar.zst gsoc2013-evolution-749dabd02565e285ceef8e1dad9ba35b48b2fbaf.zip |
Make EAttachment column updates thread-safe.
EAttachment updates its tree model row directly in response to property
change notifications, but now change notifications can come from worker
threads whereas the tree model row should only be updated from the main
thread. To compensate, respond to notifications by adding idle sources
to the default context. The idle callback will update the row from the
appropriate thread.
Diffstat (limited to 'e-util')
-rw-r--r-- | e-util/e-attachment.c | 133 |
1 files changed, 125 insertions, 8 deletions
diff --git a/e-util/e-attachment.c b/e-util/e-attachment.c index 10f251379e..e068b13a90 100644 --- a/e-util/e-attachment.c +++ b/e-util/e-attachment.c @@ -82,6 +82,13 @@ struct _EAttachmentPrivate { * If we are removed from the store, we lazily free the * reference when it is found to be to be invalid. */ GtkTreeRowReference *reference; + + /* These are IDs for idle callbacks, + * protected by the idle_lock mutex. */ + GMutex idle_lock; + guint update_icon_column_idle_id; + guint update_progress_columns_idle_id; + guint update_file_info_columns_idle_id; }; enum { @@ -195,9 +202,10 @@ attachment_get_default_charset (void) return charset; } -static void -attachment_update_file_info_columns (EAttachment *attachment) +static gboolean +attachment_update_file_info_columns_idle_cb (gpointer weak_ref) { + EAttachment *attachment; GtkTreeRowReference *reference; GtkTreeModel *model; GtkTreePath *path; @@ -211,13 +219,21 @@ attachment_update_file_info_columns (EAttachment *attachment) gchar *caption; goffset size; + attachment = g_weak_ref_get (weak_ref); + if (attachment == NULL) + goto exit; + + g_mutex_lock (&attachment->priv->idle_lock); + attachment->priv->update_file_info_columns_idle_id = 0; + g_mutex_unlock (&attachment->priv->idle_lock); + reference = e_attachment_get_reference (attachment); if (!gtk_tree_row_reference_valid (reference)) - return; + goto exit; file_info = e_attachment_ref_file_info (attachment); if (file_info == NULL) - return; + goto exit; model = gtk_tree_row_reference_get_model (reference); path = gtk_tree_row_reference_get_path (reference); @@ -257,11 +273,36 @@ attachment_update_file_info_columns (EAttachment *attachment) g_free (caption); g_clear_object (&file_info); + +exit: + g_clear_object (&attachment); + + return FALSE; } static void -attachment_update_icon_column (EAttachment *attachment) +attachment_update_file_info_columns (EAttachment *attachment) +{ + g_mutex_lock (&attachment->priv->idle_lock); + + if (attachment->priv->update_file_info_columns_idle_id == 0) { + guint idle_id; + + idle_id = g_idle_add_full ( + G_PRIORITY_HIGH_IDLE, + attachment_update_file_info_columns_idle_cb, + e_weak_ref_new (attachment), + (GDestroyNotify) e_weak_ref_free); + attachment->priv->update_file_info_columns_idle_id = idle_id; + } + + g_mutex_unlock (&attachment->priv->idle_lock); +} + +static gboolean +attachment_update_icon_column_idle_cb (gpointer weak_ref) { + EAttachment *attachment; GtkTreeRowReference *reference; GtkTreeModel *model; GtkTreePath *path; @@ -272,9 +313,17 @@ attachment_update_icon_column (EAttachment *attachment) const gchar *emblem_name = NULL; const gchar *thumbnail_path = NULL; + attachment = g_weak_ref_get (weak_ref); + if (attachment == NULL) + goto exit; + + g_mutex_lock (&attachment->priv->idle_lock); + attachment->priv->update_icon_column_idle_id = 0; + g_mutex_unlock (&attachment->priv->idle_lock); + reference = e_attachment_get_reference (attachment); if (!gtk_tree_row_reference_valid (reference)) - return; + goto exit; model = gtk_tree_row_reference_get_model (reference); path = gtk_tree_row_reference_get_path (reference); @@ -387,11 +436,36 @@ attachment_update_icon_column (EAttachment *attachment) g_object_notify (G_OBJECT (attachment), "icon"); g_clear_object (&file_info); + +exit: + g_clear_object (&attachment); + + return FALSE; } static void -attachment_update_progress_columns (EAttachment *attachment) +attachment_update_icon_column (EAttachment *attachment) { + g_mutex_lock (&attachment->priv->idle_lock); + + if (attachment->priv->update_icon_column_idle_id == 0) { + guint idle_id; + + idle_id = g_idle_add_full ( + G_PRIORITY_HIGH_IDLE, + attachment_update_icon_column_idle_cb, + e_weak_ref_new (attachment), + (GDestroyNotify) e_weak_ref_free); + attachment->priv->update_icon_column_idle_id = idle_id; + } + + g_mutex_unlock (&attachment->priv->idle_lock); +} + +static gboolean +attachment_update_progress_columns_idle_cb (gpointer weak_ref) +{ + EAttachment *attachment; GtkTreeRowReference *reference; GtkTreeModel *model; GtkTreePath *path; @@ -400,9 +474,17 @@ attachment_update_progress_columns (EAttachment *attachment) gboolean saving; gint percent; + attachment = g_weak_ref_get (weak_ref); + if (attachment == NULL) + goto exit; + + g_mutex_lock (&attachment->priv->idle_lock); + attachment->priv->update_progress_columns_idle_id = 0; + g_mutex_unlock (&attachment->priv->idle_lock); + reference = e_attachment_get_reference (attachment); if (!gtk_tree_row_reference_valid (reference)) - return; + goto exit; model = gtk_tree_row_reference_get_model (reference); path = gtk_tree_row_reference_get_path (reference); @@ -420,6 +502,30 @@ attachment_update_progress_columns (EAttachment *attachment) E_ATTACHMENT_STORE_COLUMN_PERCENT, percent, E_ATTACHMENT_STORE_COLUMN_SAVING, saving, -1); + +exit: + g_clear_object (&attachment); + + return FALSE; +} + +static void +attachment_update_progress_columns (EAttachment *attachment) +{ + g_mutex_lock (&attachment->priv->idle_lock); + + if (attachment->priv->update_progress_columns_idle_id == 0) { + guint idle_id; + + idle_id = g_idle_add_full ( + G_PRIORITY_HIGH_IDLE, + attachment_update_progress_columns_idle_cb, + e_weak_ref_new (attachment), + (GDestroyNotify) e_weak_ref_free); + attachment->priv->update_progress_columns_idle_id = idle_id; + } + + g_mutex_unlock (&attachment->priv->idle_lock); } static void @@ -706,7 +812,17 @@ attachment_finalize (GObject *object) priv = E_ATTACHMENT_GET_PRIVATE (object); + if (priv->update_icon_column_idle_id > 0) + g_source_remove (priv->update_icon_column_idle_id); + + if (priv->update_progress_columns_idle_id > 0) + g_source_remove (priv->update_progress_columns_idle_id); + + if (priv->update_file_info_columns_idle_id > 0) + g_source_remove (priv->update_file_info_columns_idle_id); + g_mutex_clear (&priv->property_lock); + g_mutex_clear (&priv->idle_lock); g_free (priv->disposition); @@ -881,6 +997,7 @@ e_attachment_init (EAttachment *attachment) attachment->priv->signed_ = CAMEL_CIPHER_VALIDITY_SIGN_NONE; g_mutex_init (&attachment->priv->property_lock); + g_mutex_init (&attachment->priv->idle_lock); g_signal_connect ( attachment, "notify::encrypted", |