From 48a9944fd9f3b4461a239d2da490fba24874df80 Mon Sep 17 00:00:00 2001 From: Travis Reitter Date: Fri, 11 Jun 2010 13:22:38 -0700 Subject: [PATCH] Implement avatar support. --- configure.ac | 2 +- libempathy-gtk/empathy-individual-store.c | 33 +++-- libempathy-gtk/empathy-ui-utils.c | 159 +++++++++++++++++++--- libempathy-gtk/empathy-ui-utils.h | 9 ++ 4 files changed, 171 insertions(+), 32 deletions(-) diff --git a/configure.ac b/configure.ac index cadebc86..dc849ebc 100644 --- a/configure.ac +++ b/configure.ac @@ -31,7 +31,7 @@ AC_COPYRIGHT([ # Minimal version required # Hardp deps -FOLKS_REQUIRED=0.1.0 +FOLKS_REQUIRED=0.1.2 GCONF_REQUIRED=1.2.0 GLIB_REQUIRED=2.25.9 GTK_REQUIRED=2.21.2 diff --git a/libempathy-gtk/empathy-individual-store.c b/libempathy-gtk/empathy-individual-store.c index 4fed77aa..0e3dd259 100644 --- a/libempathy-gtk/empathy-individual-store.c +++ b/libempathy-gtk/empathy-individual-store.c @@ -527,6 +527,24 @@ individual_store_contact_active_cb (ShowActiveData *data) return FALSE; } +static void +individual_avatar_pixbuf_received_cb (FolksIndividual *individual, + GdkPixbuf *pixbuf, + gpointer user_data) +{ + EmpathyIndividualStore *self = user_data; + GList *iters, *l; + + iters = individual_store_find_contact (self, individual); + + for (l = iters; l; l = l->next) + { + gtk_tree_store_set (GTK_TREE_STORE (self), l->data, + EMPATHY_INDIVIDUAL_STORE_COL_PIXBUF_AVATAR, pixbuf, + -1); + } +} + static void individual_store_contact_update (EmpathyIndividualStore *self, FolksIndividual *individual) @@ -544,7 +562,6 @@ individual_store_contact_update (EmpathyIndividualStore *self, gboolean do_set_active = FALSE; gboolean do_set_refresh = FALSE; gboolean show_avatar = FALSE; - GdkPixbuf *pixbuf_avatar; GdkPixbuf *pixbuf_status; priv = GET_PRIV (self); @@ -657,17 +674,16 @@ individual_store_contact_update (EmpathyIndividualStore *self, { show_avatar = TRUE; } - /* TODO: implement */ - DEBUG ("avatars unimplemented"); + + empathy_pixbuf_avatar_from_individual_scaled_async (individual, 32, 32, + individual_avatar_pixbuf_received_cb, self); pixbuf_status = empathy_individual_store_get_individual_status_icon (self, individual); - pixbuf_avatar = NULL; for (l = iters; l && set_model; l = l->next) { gtk_tree_store_set (GTK_TREE_STORE (self), l->data, EMPATHY_INDIVIDUAL_STORE_COL_ICON_STATUS, pixbuf_status, - EMPATHY_INDIVIDUAL_STORE_COL_PIXBUF_AVATAR, pixbuf_avatar, EMPATHY_INDIVIDUAL_STORE_COL_PIXBUF_AVATAR_VISIBLE, show_avatar, EMPATHY_INDIVIDUAL_STORE_COL_NAME, folks_individual_get_alias (individual), @@ -687,11 +703,6 @@ individual_store_contact_update (EmpathyIndividualStore *self, EMPATHY_INDIVIDUAL_STORE_COL_IS_SEPARATOR, FALSE, -1); } - if (pixbuf_avatar) - { - g_object_unref (pixbuf_avatar); - } - if (priv->show_active && do_set_active) { individual_store_contact_set_active (self, individual, do_set_active, @@ -731,6 +742,8 @@ static void individual_store_add_individual_and_connect (EmpathyIndividualStore *self, FolksIndividual *individual) { + g_signal_connect (individual, "notify::avatar", + G_CALLBACK (individual_store_contact_updated_cb), self); g_signal_connect (individual, "notify::presence-type", G_CALLBACK (individual_store_contact_updated_cb), self); g_signal_connect (individual, "notify::presence-message", diff --git a/libempathy-gtk/empathy-ui-utils.c b/libempathy-gtk/empathy-ui-utils.c index 93c08d1c..83fbc636 100644 --- a/libempathy-gtk/empathy-ui-utils.c +++ b/libempathy-gtk/empathy-ui-utils.c @@ -436,6 +436,35 @@ empathy_gdk_pixbuf_is_opaque (GdkPixbuf *pixbuf) return TRUE; } +static GdkPixbuf * +avatar_pixbuf_from_loader (GdkPixbufLoader *loader) +{ + GdkPixbuf *pixbuf; + + pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); + if (!gdk_pixbuf_get_has_alpha (pixbuf)) { + GdkPixbuf *rounded_pixbuf; + + rounded_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, + gdk_pixbuf_get_width (pixbuf), + gdk_pixbuf_get_height (pixbuf)); + gdk_pixbuf_copy_area (pixbuf, 0, 0, + gdk_pixbuf_get_width (pixbuf), + gdk_pixbuf_get_height (pixbuf), + rounded_pixbuf, + 0, 0); + pixbuf = rounded_pixbuf; + } else { + g_object_ref (pixbuf); + } + + if (empathy_gdk_pixbuf_is_opaque (pixbuf)) { + empathy_avatar_pixbuf_roundify (pixbuf); + } + + return pixbuf; +} + GdkPixbuf * empathy_pixbuf_from_avatar_scaled (EmpathyAvatar *avatar, gint width, @@ -469,27 +498,7 @@ empathy_pixbuf_from_avatar_scaled (EmpathyAvatar *avatar, } gdk_pixbuf_loader_close (loader, NULL); - - pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); - if (!gdk_pixbuf_get_has_alpha (pixbuf)) { - GdkPixbuf *rounded_pixbuf; - - rounded_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, - gdk_pixbuf_get_width (pixbuf), - gdk_pixbuf_get_height (pixbuf)); - gdk_pixbuf_copy_area (pixbuf, 0, 0, - gdk_pixbuf_get_width (pixbuf), - gdk_pixbuf_get_height (pixbuf), - rounded_pixbuf, - 0, 0); - pixbuf = rounded_pixbuf; - } else { - g_object_ref (pixbuf); - } - - if (empathy_gdk_pixbuf_is_opaque (pixbuf)) { - empathy_avatar_pixbuf_roundify (pixbuf); - } + pixbuf = avatar_pixbuf_from_loader (loader); g_object_unref (loader); @@ -510,6 +519,114 @@ empathy_pixbuf_avatar_from_contact_scaled (EmpathyContact *contact, return empathy_pixbuf_from_avatar_scaled (avatar, width, height); } +typedef struct { + FolksIndividual *individual; + EmpathyPixbufAvatarFromIndividualCb callback; + gpointer user_data; + guint width; + guint height; +} PixbufAvatarFromIndividualClosure; + +static void +pixbuf_avatar_from_individual_closure_free ( + PixbufAvatarFromIndividualClosure *closure) +{ + g_object_unref (closure->individual); + g_free (closure); +} + +static void +avatar_file_load_contents_cb (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + GFile *file = G_FILE (object); + PixbufAvatarFromIndividualClosure *closure = user_data; + char *data; + gsize data_size; + struct SizeData size_data; + GError *error = NULL; + GdkPixbufLoader *loader = NULL; + GdkPixbuf *pixbuf = NULL; + + if (!g_file_load_contents_finish (file, result, &data, &data_size, + NULL, &error)) { + DEBUG ("failed to load avatar from file: %s", + error->message); + goto out; + } + + size_data.width = closure->width; + size_data.height = closure->height; + size_data.preserve_aspect_ratio = TRUE; + + loader = gdk_pixbuf_loader_new (); + + /* XXX: this seems a bit racy, but apparently works well enough */ + g_signal_connect (loader, "size-prepared", + G_CALLBACK (pixbuf_from_avatar_size_prepared_cb), + &size_data); + + if (!gdk_pixbuf_loader_write (loader, (guchar *) data, data_size, + &error)) { + DEBUG ("Failed to write to pixbuf loader: %s", + error ? error->message : "No error given"); + goto out; + } + if (!gdk_pixbuf_loader_close (loader, &error)) { + DEBUG ("Failed to close pixbuf loader: %s", + error ? error->message : "No error given"); + goto out; + } + + pixbuf = avatar_pixbuf_from_loader (loader); + + closure->callback (closure->individual, pixbuf, closure->user_data); + +out: + g_clear_error (&error); + g_free (data); + if (loader != NULL) + g_object_unref (loader); + pixbuf_avatar_from_individual_closure_free (closure); +} + +void +empathy_pixbuf_avatar_from_individual_scaled_async (FolksIndividual *individual, + gint width, + gint height, + EmpathyPixbufAvatarFromIndividualCb callback, + gpointer user_data) +{ + GFile *avatar_file; + PixbufAvatarFromIndividualClosure *closure; + + if (!FOLKS_IS_INDIVIDUAL (individual)) { + DEBUG ("failed assertion: FOLKS_IS_INDIVIDUAL (individual)"); + goto out; + } + + avatar_file = folks_avatar_get_avatar (FOLKS_AVATAR (individual)); + if (avatar_file == NULL) { + goto out; + } + + closure = g_new0 (PixbufAvatarFromIndividualClosure, 1); + closure->individual = g_object_ref (individual); + closure->callback = callback; + closure->user_data = user_data; + closure->width = width; + closure->height = height; + + g_file_load_contents_async (avatar_file, NULL, + avatar_file_load_contents_cb, closure); + + return; + +out: + callback (individual, NULL, user_data); +} + GdkPixbuf * empathy_pixbuf_contact_status_icon (EmpathyContact *contact, gboolean show_protocol) diff --git a/libempathy-gtk/empathy-ui-utils.h b/libempathy-gtk/empathy-ui-utils.h index 3032aea8..3e9a8434 100644 --- a/libempathy-gtk/empathy-ui-utils.h +++ b/libempathy-gtk/empathy-ui-utils.h @@ -49,6 +49,10 @@ G_BEGIN_DECLS (x) < gdk_screen_width () && \ (y) < gdk_screen_height ()) +typedef void (*EmpathyPixbufAvatarFromIndividualCb) (FolksIndividual *individual, + GdkPixbuf *pixbuf, + gpointer user_data); + void empathy_gtk_init (void); /* Glade */ @@ -72,6 +76,11 @@ GdkPixbuf * empathy_pixbuf_from_data (gchar *data, GdkPixbuf * empathy_pixbuf_from_data_and_mime (gchar *data, gsize data_size, gchar **mime_type); +void empathy_pixbuf_avatar_from_individual_scaled_async (FolksIndividual *individual, + gint width, + gint height, + EmpathyPixbufAvatarFromIndividualCb callback, + gpointer user_data); GdkPixbuf * empathy_pixbuf_from_avatar_scaled (EmpathyAvatar *avatar, gint width, gint height); -- 2.39.2