]> git.0d.be Git - empathy.git/commitdiff
Implement avatar support.
authorTravis Reitter <treitter@gmail.com>
Fri, 11 Jun 2010 20:22:38 +0000 (13:22 -0700)
committerTravis Reitter <treitter@gmail.com>
Tue, 20 Jul 2010 23:12:35 +0000 (16:12 -0700)
configure.ac
libempathy-gtk/empathy-individual-store.c
libempathy-gtk/empathy-ui-utils.c
libempathy-gtk/empathy-ui-utils.h

index cadebc867dcc7500450e9336ac0519a9bc66bddf..dc849ebcdfd732b94e62c13a40e5a03569d199b4 100644 (file)
@@ -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
index 4fed77aaf0aa00a4dbb301c8916ea73737036dc2..0e3dd259ec35931ce62b3a445b41beb0b57a0c4d 100644 (file)
@@ -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",
index 93c08d1c59425e054851929a31d75c9abdf0f1fb..83fbc636e95849b52286a932b66083cec530e9a5 100644 (file)
@@ -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)
index 3032aea84469788f9b98f1b1b092bf6a8b6068bf..3e9a8434eab1a7fd0970a4898f0725926abb687f 100644 (file)
@@ -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);