aboutsummaryrefslogtreecommitdiffstats
path: root/libempathy-gtk/empathy-individual-store.c
diff options
context:
space:
mode:
authorPhilip Withnall <philip.withnall@collabora.co.uk>2010-08-19 01:13:02 +0800
committerPhilip Withnall <philip.withnall@collabora.co.uk>2010-08-19 01:55:09 +0800
commit015070caec0ec80ac53127c619bde516081670e6 (patch)
treefce9210305d5bd92578d85196671bdfb65cf93dc /libempathy-gtk/empathy-individual-store.c
parent41c88d2a8b3670901473061dd53eb83e6f7ad34c (diff)
downloadgsoc2013-empathy-015070caec0ec80ac53127c619bde516081670e6.tar
gsoc2013-empathy-015070caec0ec80ac53127c619bde516081670e6.tar.gz
gsoc2013-empathy-015070caec0ec80ac53127c619bde516081670e6.tar.bz2
gsoc2013-empathy-015070caec0ec80ac53127c619bde516081670e6.tar.lz
gsoc2013-empathy-015070caec0ec80ac53127c619bde516081670e6.tar.xz
gsoc2013-empathy-015070caec0ec80ac53127c619bde516081670e6.tar.zst
gsoc2013-empathy-015070caec0ec80ac53127c619bde516081670e6.zip
Allow cancellation of avatar load operations
Automatically cancel all pending avatar load operations when disposing of an EmpathyIndividualStore. This prevents crashes when linking individuals in the case that the EmpathyIndividualStore in the linking dialogue gets notified of the new linked individual just before it's destroyed.
Diffstat (limited to 'libempathy-gtk/empathy-individual-store.c')
-rw-r--r--libempathy-gtk/empathy-individual-store.c57
1 files changed, 48 insertions, 9 deletions
diff --git a/libempathy-gtk/empathy-individual-store.c b/libempathy-gtk/empathy-individual-store.c
index 161787299..26b56954e 100644
--- a/libempathy-gtk/empathy-individual-store.c
+++ b/libempathy-gtk/empathy-individual-store.c
@@ -71,6 +71,8 @@ typedef struct
guint setup_idle_id;
gboolean dispose_has_run;
GHashTable *status_icons;
+ /* List of owned GCancellables for each pending avatar load operation */
+ GList *avatar_cancellables;
} EmpathyIndividualStorePriv;
typedef struct
@@ -552,13 +554,16 @@ individual_store_contact_active_cb (ShowActiveData *data)
return FALSE;
}
+typedef struct {
+ EmpathyIndividualStore *store; /* weak */
+ GCancellable *cancellable; /* owned */
+} LoadAvatarData;
+
static void
-individual_avatar_pixbuf_received_cb (GObject *object,
+individual_avatar_pixbuf_received_cb (FolksIndividual *individual,
GAsyncResult *result,
- gpointer user_data)
+ LoadAvatarData *data)
{
- FolksIndividual *individual = FOLKS_INDIVIDUAL (object);
- EmpathyIndividualStore *self = user_data;
GError *error = NULL;
GdkPixbuf *pixbuf;
@@ -572,18 +577,32 @@ individual_avatar_pixbuf_received_cb (GObject *object,
error->message);
g_clear_error (&error);
}
- else
+ else if (data->store != NULL)
{
GList *iters, *l;
- iters = individual_store_find_contact (self, individual);
+ iters = individual_store_find_contact (data->store, individual);
for (l = iters; l; l = l->next)
{
- gtk_tree_store_set (GTK_TREE_STORE (self), l->data,
+ gtk_tree_store_set (GTK_TREE_STORE (data->store), l->data,
EMPATHY_INDIVIDUAL_STORE_COL_PIXBUF_AVATAR, pixbuf,
-1);
}
}
+
+ /* Free things */
+ if (data->store != NULL)
+ {
+ EmpathyIndividualStorePriv *priv = GET_PRIV (data->store);
+
+ g_object_remove_weak_pointer (G_OBJECT (data->store),
+ (gpointer *) &data->store);
+ priv->avatar_cancellables = g_list_remove (priv->avatar_cancellables,
+ data->cancellable);
+ }
+
+ g_object_unref (data->cancellable);
+ g_slice_free (LoadAvatarData, data);
}
static void
@@ -604,6 +623,7 @@ individual_store_contact_update (EmpathyIndividualStore *self,
gboolean do_set_refresh = FALSE;
gboolean show_avatar = FALSE;
GdkPixbuf *pixbuf_status;
+ LoadAvatarData *load_avatar_data;
priv = GET_PRIV (self);
@@ -678,8 +698,19 @@ individual_store_contact_update (EmpathyIndividualStore *self,
show_avatar = TRUE;
}
- empathy_pixbuf_avatar_from_individual_scaled_async (individual,
- individual_avatar_pixbuf_received_cb, 32, 32, self);
+ /* Load the avatar asynchronously */
+ load_avatar_data = g_slice_new (LoadAvatarData);
+ load_avatar_data->store = self;
+ g_object_add_weak_pointer (G_OBJECT (self),
+ (gpointer *) &load_avatar_data->store);
+ load_avatar_data->cancellable = g_cancellable_new ();
+
+ priv->avatar_cancellables = g_list_prepend (priv->avatar_cancellables,
+ load_avatar_data->cancellable);
+ empathy_pixbuf_avatar_from_individual_scaled_async (individual, 32, 32,
+ load_avatar_data->cancellable,
+ (GAsyncReadyCallback) individual_avatar_pixbuf_received_cb,
+ load_avatar_data);
pixbuf_status =
empathy_individual_store_get_individual_status_icon (self, individual);
@@ -957,6 +988,14 @@ individual_store_dispose (GObject *object)
return;
priv->dispose_has_run = TRUE;
+ /* Cancel any pending avatar load operations */
+ for (l = priv->avatar_cancellables; l != NULL; l = l->next)
+ {
+ /* The cancellables are freed in individual_avatar_pixbuf_received_cb() */
+ g_cancellable_cancel (G_CANCELLABLE (l->data));
+ }
+ g_list_free (priv->avatar_cancellables);
+
contacts = empathy_individual_manager_get_members (priv->manager);
for (l = contacts; l; l = l->next)
{