[empathy] Implement avatar support.



commit 48a9944fd9f3b4461a239d2da490fba24874df80
Author: Travis Reitter <treitter gmail com>
Date:   Fri Jun 11 13:22:38 2010 -0700

    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 cadebc8..dc849eb 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 4fed77a..0e3dd25 100644
--- a/libempathy-gtk/empathy-individual-store.c
+++ b/libempathy-gtk/empathy-individual-store.c
@@ -528,6 +528,24 @@ individual_store_contact_active_cb (ShowActiveData *data)
 }
 
 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 93c08d1..83fbc63 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 3032aea..3e9a843 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);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]