diff --git a/libempathy-gtk/empathy-avatar-chooser.c b/libempathy-gtk/empathy-avatar-chooser.c
index e7a0d3f..7f4014e 100644
--- a/libempathy-gtk/empathy-avatar-chooser.c
+++ b/libempathy-gtk/empathy-avatar-chooser.c
@@ -1,4 +1,3 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
  * Copyright (C) 2006-2007 Imendio AB.
  * Copyright (C) 2007-2008 Collabora Ltd.
@@ -76,60 +75,27 @@
 #define EMPATHY_AVATAR_CHOOSER_RESPONSE_CANCEL   GTK_RESPONSE_CANCEL
 #define EMPATHY_AVATAR_CHOOSER_RESPONSE_FILE     GTK_RESPONSE_OK
 
+struct _EmpathyAvatarChooserPrivate
+{
+  TpConnection *connection;
+  GtkFileChooser *chooser_dialog;
+
+  gulong ready_handler_id;
+
+  EmpathyAvatar *avatar;
+  GSettings *gsettings_ui;
+};
 
-#define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyAvatarChooser)
-typedef struct {
-	TpConnection            *connection;
-	GtkFileChooser          *chooser_dialog;
-
-	gulong ready_handler_id;
-
-	EmpathyAvatar *avatar;
-	GSettings *gsettings_ui;
-} EmpathyAvatarChooserPriv;
-
-static void       avatar_chooser_finalize              (GObject              *object);
-static void       avatar_chooser_set_connection        (EmpathyAvatarChooser *self,
-							TpConnection         *connection);
-static void       avatar_chooser_set_image             (EmpathyAvatarChooser *chooser,
-							EmpathyAvatar        *avatar,
-							GdkPixbuf            *pixbuf,
-							gboolean              set_locally);
-static gboolean   avatar_chooser_drag_motion_cb        (GtkWidget            *widget,
-							GdkDragContext       *context,
-							gint                  x,
-							gint                  y,
-							guint                 time,
-							EmpathyAvatarChooser *chooser);
-static void       avatar_chooser_drag_leave_cb         (GtkWidget            *widget,
-							GdkDragContext       *context,
-							guint                 time,
-							EmpathyAvatarChooser *chooser);
-static gboolean   avatar_chooser_drag_drop_cb          (GtkWidget            *widget,
-							GdkDragContext       *context,
-							gint                  x,
-							gint                  y,
-							guint                 time,
-							EmpathyAvatarChooser *chooser);
-static void       avatar_chooser_drag_data_received_cb (GtkWidget            *widget,
-							GdkDragContext       *context,
-							gint                  x,
-							gint                  y,
-							GtkSelectionData     *selection_data,
-							guint                 info,
-							guint                 time,
-							EmpathyAvatarChooser *chooser);
-static void       avatar_chooser_clicked_cb            (GtkWidget            *button,
-							EmpathyAvatarChooser *chooser);
-
-enum {
-	CHANGED,
-	LAST_SIGNAL
+enum
+{
+  CHANGED,
+  LAST_SIGNAL
 };
 
-enum {
-	PROP_0,
-	PROP_CONNECTION
+enum
+{
+  PROP_0,
+  PROP_CONNECTION
 };
 
 static guint signals [LAST_SIGNAL];
@@ -141,212 +107,221 @@ G_DEFINE_TYPE (EmpathyAvatarChooser, empathy_avatar_chooser, GTK_TYPE_BUTTON);
  */
 #define URI_LIST_TYPE "text/uri-list"
 
-enum DndTargetType {
-	DND_TARGET_TYPE_URI_LIST
+enum DndTargetType
+{
+  DND_TARGET_TYPE_URI_LIST
 };
 
-static const GtkTargetEntry drop_types[] = {
-	{ URI_LIST_TYPE, 0, DND_TARGET_TYPE_URI_LIST },
+static const GtkTargetEntry drop_types[] =
+{
+  { URI_LIST_TYPE, 0, DND_TARGET_TYPE_URI_LIST },
 };
 
 static void
-avatar_chooser_get_property (GObject    *object,
-			     guint       param_id,
-			     GValue     *value,
-			     GParamSpec *pspec)
+avatar_chooser_get_property (GObject *object,
+    guint param_id,
+    GValue *value,
+    GParamSpec *pspec)
 {
-	EmpathyAvatarChooserPriv *priv = GET_PRIV (object);
-
-	switch (param_id) {
-	case PROP_CONNECTION:
-		g_value_set_object (value, priv->connection);
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
-		break;
-	}
+  EmpathyAvatarChooser *self = (EmpathyAvatarChooser *) object;
+
+  switch (param_id)
+    {
+      case PROP_CONNECTION:
+        g_value_set_object (value, self->priv->connection);
+        break;
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+        break;
+    }
 }
 
 static void
-avatar_chooser_set_property (GObject      *object,
-			     guint         param_id,
-			     const GValue *value,
-			     GParamSpec   *pspec)
+avatar_chooser_set_connection (EmpathyAvatarChooser *self,
+    TpConnection *connection)
 {
-	EmpathyAvatarChooser *self = EMPATHY_AVATAR_CHOOSER (object);
-
-	switch (param_id) {
-	case PROP_CONNECTION:
-		avatar_chooser_set_connection (self, g_value_get_object (value));
-		break;
-	default:
-		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
-		break;
-	}
+  tp_clear_object (&self->priv->connection);
+
+  if (connection != NULL)
+    {
+      GQuark features[] = { TP_CONNECTION_FEATURE_AVATAR_REQUIREMENTS, 0 };
+      self->priv->connection = g_object_ref (connection);
+      tp_proxy_prepare_async (self->priv->connection, features, NULL, NULL);
+    }
 }
 
 static void
-empathy_avatar_chooser_class_init (EmpathyAvatarChooserClass *klass)
+avatar_chooser_set_property (GObject *object,
+    guint param_id,
+    const GValue *value,
+    GParamSpec *pspec)
 {
-	GObjectClass *object_class = G_OBJECT_CLASS (klass);
-	GParamSpec *param_spec;
-
-	object_class->finalize = avatar_chooser_finalize;
-	object_class->get_property = avatar_chooser_get_property;
-	object_class->set_property = avatar_chooser_set_property;
-
-	/**
-	 * EmpathyAvatarChooser::changed:
-	 * @chooser: an #EmpathyAvatarChooser
-	 *
-	 * Emitted when the chosen avatar has changed.
-	 *
-	 */
-	signals[CHANGED] =
-		g_signal_new ("changed",
-			      G_TYPE_FROM_CLASS (klass),
-			      G_SIGNAL_RUN_LAST,
-			      0,
-			      NULL, NULL,
-			      g_cclosure_marshal_VOID__VOID,
-			      G_TYPE_NONE, 0);
-
-	/**
-	 * EmpathyAvatarChooser:connection:
-	 *
-	 * The #TpConnection whose avatar should be shown and modified by
-	 * the #EmpathyAvatarChooser instance.
-	 */
-	param_spec = g_param_spec_object ("connection",
-					  "TpConnection",
-					  "TpConnection whose avatar should be "
-					  "shown and modified by this widget",
-					  TP_TYPE_CONNECTION,
-					  G_PARAM_READWRITE |
-					  G_PARAM_STATIC_STRINGS);
-	g_object_class_install_property (object_class,
-					 PROP_CONNECTION,
-					 param_spec);
-
-	g_type_class_add_private (object_class, sizeof (EmpathyAvatarChooserPriv));
+  EmpathyAvatarChooser *self = EMPATHY_AVATAR_CHOOSER (object);
+
+  switch (param_id)
+    {
+      case PROP_CONNECTION:
+        avatar_chooser_set_connection (self, g_value_get_object (value));
+        break;
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+        break;
+    }
 }
 
 static void
-empathy_avatar_chooser_init (EmpathyAvatarChooser *chooser)
+avatar_chooser_dispose (GObject *object)
 {
-	EmpathyAvatarChooserPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (chooser,
-		EMPATHY_TYPE_AVATAR_CHOOSER, EmpathyAvatarChooserPriv);
-
-	chooser->priv = priv;
-	gtk_drag_dest_set (GTK_WIDGET (chooser),
-			   GTK_DEST_DEFAULT_ALL,
-			   drop_types,
-			   G_N_ELEMENTS (drop_types),
-			   GDK_ACTION_COPY);
-
-	priv->gsettings_ui = g_settings_new (EMPATHY_PREFS_UI_SCHEMA);
-
-	g_signal_connect (chooser, "drag-motion",
-			  G_CALLBACK (avatar_chooser_drag_motion_cb),
-			  chooser);
-	g_signal_connect (chooser, "drag-leave",
-			  G_CALLBACK (avatar_chooser_drag_leave_cb),
-			  chooser);
-	g_signal_connect (chooser, "drag-drop",
-			  G_CALLBACK (avatar_chooser_drag_drop_cb),
-			  chooser);
-	g_signal_connect (chooser, "drag-data-received",
-			  G_CALLBACK (avatar_chooser_drag_data_received_cb),
-			  chooser);
-	g_signal_connect (chooser, "clicked",
-			  G_CALLBACK (avatar_chooser_clicked_cb),
-			  chooser);
-
-	empathy_avatar_chooser_set (chooser, NULL);
+  EmpathyAvatarChooser *self = (EmpathyAvatarChooser *) object;
+
+  tp_clear_object (&self->priv->connection);
+  tp_clear_pointer (&self->priv->avatar, empathy_avatar_unref);
+  tp_clear_object (&self->priv->gsettings_ui);
+
+  G_OBJECT_CLASS (empathy_avatar_chooser_parent_class)->dispose (object);
 }
 
 static void
-avatar_chooser_finalize (GObject *object)
+empathy_avatar_chooser_class_init (EmpathyAvatarChooserClass *klass)
 {
-	EmpathyAvatarChooserPriv *priv;
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GParamSpec *param_spec;
+
+  object_class->dispose = avatar_chooser_dispose;
+  object_class->get_property = avatar_chooser_get_property;
+  object_class->set_property = avatar_chooser_set_property;
+
+  /**
+   * EmpathyAvatarChooser::changed:
+   * @self: an #EmpathyAvatarChooser
+   *
+   * Emitted when the chosen avatar has changed.
+   *
+   */
+  signals[CHANGED] =
+    g_signal_new ("changed",
+            G_TYPE_FROM_CLASS (klass),
+            G_SIGNAL_RUN_LAST,
+            0,
+            NULL, NULL,
+            g_cclosure_marshal_VOID__VOID,
+            G_TYPE_NONE, 0);
+
+  /**
+   * EmpathyAvatarChooser:connection:
+   *
+   * The #TpConnection whose avatar should be shown and modified by
+   * the #EmpathyAvatarChooser instance.
+   */
+  param_spec = g_param_spec_object ("connection",
+            "TpConnection",
+            "TpConnection whose avatar should be "
+            "shown and modified by this widget",
+            TP_TYPE_CONNECTION,
+            G_PARAM_READWRITE |
+            G_PARAM_STATIC_STRINGS);
+  g_object_class_install_property (object_class,
+           PROP_CONNECTION,
+           param_spec);
+
+  g_type_class_add_private (object_class, sizeof (EmpathyAvatarChooserPrivate));
+}
 
-	priv = GET_PRIV (object);
+static gboolean
+avatar_chooser_drag_motion_cb (GtkWidget *widget,
+    GdkDragContext *context,
+    gint x,
+    gint y,
+    guint time_,
+    EmpathyAvatarChooser *self)
+{
+  GList *p;
 
-	avatar_chooser_set_connection (EMPATHY_AVATAR_CHOOSER (object), NULL);
-	g_assert (priv->connection == NULL);
+  for (p = gdk_drag_context_list_targets (context); p != NULL;
+       p = p->next)
+    {
+      gchar *possible_type;
 
-	if (priv->avatar != NULL) {
-		empathy_avatar_unref (priv->avatar);
-	}
+      possible_type = gdk_atom_name (GDK_POINTER_TO_ATOM (p->data));
 
-	g_object_unref (priv->gsettings_ui);
+      if (!strcmp (possible_type, URI_LIST_TYPE))
+        {
+          g_free (possible_type);
+          gdk_drag_status (context, GDK_ACTION_COPY, time_);
 
-	G_OBJECT_CLASS (empathy_avatar_chooser_parent_class)->finalize (object);
-}
+          return TRUE;
+        }
 
-static void
-avatar_chooser_set_connection (EmpathyAvatarChooser *self,
-			       TpConnection         *connection)
-{
-	EmpathyAvatarChooserPriv *priv = GET_PRIV (self);
-
-	if (priv->connection != NULL) {
-		g_object_unref (priv->connection);
-		priv->connection = NULL;
-	}
-
-	if (connection != NULL) {
-		GQuark features[] = { TP_CONNECTION_FEATURE_AVATAR_REQUIREMENTS, 0 };
-		priv->connection = g_object_ref (connection);
-		tp_proxy_prepare_async (priv->connection, features, NULL, NULL);
-	}
+      g_free (possible_type);
+    }
+
+  return FALSE;
 }
 
-static void
-avatar_chooser_error_show (EmpathyAvatarChooser *chooser,
-			   const gchar          *primary_text,
-			   const gchar          *secondary_text)
+static gboolean
+avatar_chooser_drag_drop_cb (GtkWidget *widget,
+    GdkDragContext *context,
+    gint x,
+    gint y,
+    guint time_,
+    EmpathyAvatarChooser *self)
 {
-	GtkWidget *parent;
-	GtkWidget *dialog;
+  GList *p;
 
-	parent = gtk_widget_get_toplevel (GTK_WIDGET (chooser));
-	if (!GTK_IS_WINDOW (parent)) {
-		parent = NULL;
-	}
+  if (gdk_drag_context_list_targets (context) == NULL)
+    return FALSE;
 
-	dialog = gtk_message_dialog_new (parent ? GTK_WINDOW (parent) : NULL,
-					 GTK_DIALOG_MODAL,
-					 GTK_MESSAGE_WARNING,
-					 GTK_BUTTONS_CLOSE,
-					 "%s", primary_text);
+  for (p = gdk_drag_context_list_targets (context);
+       p != NULL; p = p->next)
+    {
+      char *possible_type;
 
-	if (secondary_text != NULL) {
-		gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
-							  "%s", secondary_text);
-	}
+      possible_type = gdk_atom_name (GDK_POINTER_TO_ATOM (p->data));
+      if (!strcmp (possible_type, URI_LIST_TYPE))
+        {
+          g_free (possible_type);
+          gtk_drag_get_data (widget, context,
+                 GDK_POINTER_TO_ATOM (p->data),
+                 time_);
 
-	g_signal_connect (dialog, "response",
-			  G_CALLBACK (gtk_widget_destroy), NULL);
-	gtk_widget_show (dialog);
+          return TRUE;
+        }
 
+      g_free (possible_type);
+    }
+
+  return FALSE;
+}
+
+static void
+avatar_chooser_clear_image (EmpathyAvatarChooser *self)
+{
+  GtkWidget *image;
+
+  tp_clear_pointer (&self->priv->avatar, empathy_avatar_unref);
+
+  image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_AVATAR_DEFAULT,
+    GTK_ICON_SIZE_DIALOG);
+  gtk_button_set_image (GTK_BUTTON (self), image);
+  g_signal_emit (self, signals[CHANGED], 0);
 }
 
 static gboolean
 str_in_strv (const gchar  *str,
-	     gchar **strv)
+    gchar **strv)
 {
-	if (strv == NULL) {
-		return FALSE;
-	}
-
-	while (*strv != NULL) {
-		if (g_str_equal (str, *strv)) {
-			return TRUE;
-		}
-		strv++;
-	}
-	return FALSE;
+  if (strv == NULL)
+    return FALSE;
+
+  while (*strv != NULL)
+    {
+      if (g_str_equal (str, *strv))
+        return TRUE;
+
+      strv++;
+    }
+
+  return FALSE;
 }
 
 /* The caller must free the strings stored in satisfactory_format_name and
@@ -354,752 +329,765 @@ str_in_strv (const gchar  *str,
  */
 static gboolean
 avatar_chooser_need_mime_type_conversion (const gchar *current_mime_type,
-					  gchar      **accepted_mime_types,
-					  gchar      **satisfactory_format_name,
-					  gchar      **satisfactory_mime_type)
-{
-	gchar   *good_mime_types[] = {"image/jpeg", "image/png", NULL};
-	guint    i;
-	GSList  *formats, *l;
-	gboolean found = FALSE;
-
-	*satisfactory_format_name = NULL;
-	*satisfactory_mime_type = NULL;
-
-	/* If there is no accepted format there is nothing we can do */
-	if (accepted_mime_types == NULL || *accepted_mime_types == NULL) {
-		return TRUE;
-	}
-
-	/* If the current mime type is good and accepted, don't change it!
-	 * jpeg is compress better pictures, but png is better for logos and
-	 * could have an alpha layer. */
-	if (str_in_strv (current_mime_type, good_mime_types) &&
-	    str_in_strv (current_mime_type, accepted_mime_types)) {
-		*satisfactory_mime_type = g_strdup (current_mime_type);
-		*satisfactory_format_name = g_strdup (current_mime_type +
-						      strlen ("image/"));
-		return FALSE;
-	}
-
-	/* The current mime type is either not accepted or not good to use.
-	 * Check if one of the good format is supported... */
-	for (i = 0; good_mime_types[i] != NULL;  i++) {
-		if (str_in_strv (good_mime_types[i], accepted_mime_types)) {
-			*satisfactory_mime_type = g_strdup (good_mime_types[i]);
-			*satisfactory_format_name = g_strdup (good_mime_types[i] +
-							      strlen ("image/"));
-			return TRUE;
-		}
-	}
-
-	/* Pick the first supported format we can write */
-	formats = gdk_pixbuf_get_formats ();
-	for (l = formats; !found && l != NULL; l = l->next) {
-		GdkPixbufFormat *format = l->data;
-		gchar **format_mime_types;
-		gchar **iter;
-
-		if (!gdk_pixbuf_format_is_writable (format)) {
-			continue;
-		}
-
-		format_mime_types = gdk_pixbuf_format_get_mime_types (format);
-		for (iter = format_mime_types; *iter != NULL; iter++) {
-			if (str_in_strv (*iter, accepted_mime_types)) {
-				*satisfactory_format_name = gdk_pixbuf_format_get_name (format);
-				*satisfactory_mime_type = g_strdup (*iter);
-				found = TRUE;
-				break;
-			}
-		}
-		g_strfreev (format_mime_types);
-	}
-	g_slist_free (formats);
-
-	return TRUE;
-}
-
-static EmpathyAvatar *
-avatar_chooser_maybe_convert_and_scale (EmpathyAvatarChooser *chooser,
-					GdkPixbuf            *pixbuf,
-					EmpathyAvatar        *avatar)
+    gchar **accepted_mime_types,
+    gchar **satisfactory_format_name,
+    gchar **satisfactory_mime_type)
 {
-	EmpathyAvatarChooserPriv *priv = GET_PRIV (chooser);
-	TpAvatarRequirements     *req;
-	gboolean                  needs_conversion = FALSE;
-	guint                     width, height;
-	gchar                    *new_format_name = NULL;
-	gchar                    *new_mime_type = NULL;
-	gdouble                   min_factor, max_factor;
-	gdouble                   factor;
-	gchar                    *best_image_data = NULL;
-	gsize                     best_image_size = 0;
-	guint                     count = 0;
-
-	req = tp_connection_get_avatar_requirements (priv->connection);
-	if (req == NULL) {
-		DEBUG ("Avatar requirements not ready");
-		return NULL;
-	}
-
-	/* Smaller is the factor, smaller will be the image.
-	 * 0 is an empty image, 1 is the full size. */
-	min_factor = 0;
-	max_factor = 1;
-	factor = 1;
-
-	/* Check if we need to convert to another image format */
-	if (avatar_chooser_need_mime_type_conversion (avatar->format,
-						      req->supported_mime_types,
-						      &new_format_name,
-						      &new_mime_type)) {
-		DEBUG ("Format conversion needed, we'll use mime type '%s' "
-		       "and format name '%s'. Current mime type is '%s'",
-		       new_mime_type, new_format_name, avatar->format);
-		needs_conversion = TRUE;
-	}
-
-	/* If there is no format we can use, report error to the user. */
-	if (new_mime_type == NULL || new_format_name == NULL) {
-		avatar_chooser_error_show (chooser, _("Couldn't convert image"),
-				_("None of the accepted image formats are "
-				  "supported on your system"));
-		return NULL;
-	}
-
-	/* If width or height are too big, it needs converting. */
-	width = gdk_pixbuf_get_width (pixbuf);
-	height = gdk_pixbuf_get_height (pixbuf);
-	if ((req->maximum_width > 0 && width > req->maximum_width) ||
-	    (req->maximum_height > 0 && height > req->maximum_height)) {
-		gdouble h_factor, v_factor;
-
-		h_factor = (gdouble) req->maximum_width / width;
-		v_factor = (gdouble) req->maximum_height / height;
-		factor = max_factor = MIN (h_factor, v_factor);
-
-		DEBUG ("Image dimensions (%dx%d) are too big. Max is %dx%d.",
-		       width, height, req->maximum_width, req->maximum_height);
-
-		needs_conversion = TRUE;
-	}
-
-	/* If the data len is too big and no other conversion is needed,
-	 * try with a lower factor. */
-	if (req->maximum_bytes > 0 && avatar->len > req->maximum_bytes && !needs_conversion) {
-		DEBUG ("Image data (%"G_GSIZE_FORMAT" bytes) is too big "
-		       "(max is %u bytes), conversion needed.",
-		       avatar->len, req->maximum_bytes);
-
-		factor = 0.5;
-		needs_conversion = TRUE;
-	}
-
-	/* If no conversion is needed, return the avatar */
-	if (!needs_conversion) {
-		g_free (new_format_name);
-		g_free (new_mime_type);
-		return empathy_avatar_ref (avatar);
-	}
-
-	do {
-		GdkPixbuf *pixbuf_scaled = NULL;
-		gboolean   saved;
-		gint       new_width, new_height;
-		gchar     *converted_image_data;
-		gsize      converted_image_size;
-		GError    *error = NULL;
-
-		if (factor != 1) {
-			new_width = width * factor;
-			new_height = height * factor;
-			pixbuf_scaled = gdk_pixbuf_scale_simple (pixbuf,
-								 new_width,
-								 new_height,
-								 GDK_INTERP_HYPER);
-		} else {
-			new_width = width;
-			new_height = height;
-			pixbuf_scaled = g_object_ref (pixbuf);
-		}
-
-		DEBUG ("Trying with factor %f (%dx%d) and format %s...", factor,
-			new_width, new_height, new_format_name);
-
-		saved = gdk_pixbuf_save_to_buffer (pixbuf_scaled,
-						   &converted_image_data,
-						   &converted_image_size,
-						   new_format_name,
-						   &error, NULL);
-		g_object_unref (pixbuf_scaled);
-
-		if (!saved) {
-			g_free (new_format_name);
-			g_free (new_mime_type);
-			avatar_chooser_error_show (chooser,
-				_("Couldn't convert image"),
-				error ? error->message : NULL);
-			g_clear_error (&error);
-			return NULL;
-		}
-
-		DEBUG ("Produced an image data of %"G_GSIZE_FORMAT" bytes.",
-			converted_image_size);
-
-		/* If the new image satisfy the req, keep it as current best */
-		if (req->maximum_bytes == 0 ||
-		    converted_image_size <= req->maximum_bytes) {
-			if (best_image_data)
-				g_free (best_image_data);
-
-			best_image_data = converted_image_data;
-			best_image_size = converted_image_size;
-
-			/* If this image is close enough to the optimal size,
-			 * stop searching */
-			if (req->maximum_bytes == 0 ||
-			    req->maximum_bytes - converted_image_size <= 1024)
-				break;
-		} else {
-			g_free (converted_image_data);
-		}
-
-		/* Make a binary search for the bigest factor that produce
-		 * an image data size less than max_size */
-		if (converted_image_size > req->maximum_bytes)
-			max_factor = factor;
-		if (converted_image_size < req->maximum_bytes)
-			min_factor = factor;
-		factor = (min_factor + max_factor)/2;
-
-		if ((int) (width * factor) == new_width ||
-		    (int) (height * factor) == new_height) {
-			/* min_factor and max_factor are too close, so the new
-			 * factor will produce the same image as previous
-			 * iteration. No need to continue, we already found
-			 * the optimal size. */
-			break;
-		}
-
-		/* Do 10 iterations in the worst case */
-	} while (++count < 10);
-
-	g_free (new_format_name);
-
-	/* Takes ownership of new_mime_type and best_image_data */
-	avatar = empathy_avatar_new ((guchar *) best_image_data,
-		best_image_size, new_mime_type, NULL);
-
-	return avatar;
+  gchar *good_mime_types[] = {"image/jpeg", "image/png", NULL};
+  guint i;
+  GSList *formats, *l;
+  gboolean found = FALSE;
+
+  *satisfactory_format_name = NULL;
+  *satisfactory_mime_type = NULL;
+
+  /* If there is no accepted format there is nothing we can do */
+  if (accepted_mime_types == NULL || *accepted_mime_types == NULL)
+    return TRUE;
+
+  /* If the current mime type is good and accepted, don't change it!
+   * jpeg is compress better pictures, but png is better for logos and
+   * could have an alpha layer. */
+  if (str_in_strv (current_mime_type, good_mime_types) &&
+      str_in_strv (current_mime_type, accepted_mime_types))
+    {
+      *satisfactory_mime_type = g_strdup (current_mime_type);
+      *satisfactory_format_name = g_strdup (current_mime_type +
+                    strlen ("image/"));
+      return FALSE;
+    }
+
+  /* The current mime type is either not accepted or not good to use.
+   * Check if one of the good format is supported... */
+  for (i = 0; good_mime_types[i] != NULL;  i++)
+    {
+      if (str_in_strv (good_mime_types[i], accepted_mime_types))
+        {
+          *satisfactory_mime_type = g_strdup (good_mime_types[i]);
+          *satisfactory_format_name = g_strdup (good_mime_types[i] +
+              strlen ("image/"));
+          return TRUE;
+        }
+    }
+
+  /* Pick the first supported format we can write */
+  formats = gdk_pixbuf_get_formats ();
+  for (l = formats; !found && l != NULL; l = l->next)
+    {
+      GdkPixbufFormat *format = l->data;
+      gchar **format_mime_types;
+      gchar **iter;
+
+      if (!gdk_pixbuf_format_is_writable (format))
+        continue;
+
+      format_mime_types = gdk_pixbuf_format_get_mime_types (format);
+      for (iter = format_mime_types; *iter != NULL; iter++)
+        {
+          if (str_in_strv (*iter, accepted_mime_types))
+            {
+              *satisfactory_format_name = gdk_pixbuf_format_get_name (format);
+              *satisfactory_mime_type = g_strdup (*iter);
+              found = TRUE;
+              break;
+            }
+        }
+      g_strfreev (format_mime_types);
+    }
+  g_slist_free (formats);
+
+  return TRUE;
 }
 
 static void
-avatar_chooser_clear_image (EmpathyAvatarChooser *chooser)
+avatar_chooser_error_show (EmpathyAvatarChooser *self,
+    const gchar *primary_text,
+    const gchar *secondary_text)
 {
-	EmpathyAvatarChooserPriv *priv = GET_PRIV (chooser);
-	GtkWidget *image;
-
-	if (priv->avatar != NULL) {
-		empathy_avatar_unref (priv->avatar);
-		priv->avatar = NULL;
-	}
-
-	image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_AVATAR_DEFAULT,
-		GTK_ICON_SIZE_DIALOG);
-	gtk_button_set_image (GTK_BUTTON (chooser), image);
-	g_signal_emit (chooser, signals[CHANGED], 0);
-}
+  GtkWidget *parent;
+  GtkWidget *dialog;
+
+  parent = gtk_widget_get_toplevel (GTK_WIDGET (self));
+  if (!GTK_IS_WINDOW (parent))
+    parent = NULL;
+
+  dialog = gtk_message_dialog_new (parent ? GTK_WINDOW (parent) : NULL,
+      GTK_DIALOG_MODAL,
+      GTK_MESSAGE_WARNING,
+      GTK_BUTTONS_CLOSE,
+      "%s", primary_text);
+
+  if (secondary_text != NULL)
+    {
+      gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+          "%s", secondary_text);
+    }
+
+  g_signal_connect (dialog, "response",
+        G_CALLBACK (gtk_widget_destroy), NULL);
+  gtk_widget_show (dialog);
 
-static void
-avatar_chooser_set_image_from_data (EmpathyAvatarChooser *chooser,
-				    gchar                *data,
-				    gsize                 size,
-				    gboolean              set_locally)
-{
-	GdkPixbuf     *pixbuf;
-	EmpathyAvatar *avatar = NULL;
-	gchar         *mime_type = NULL;
-
-	if (data == NULL) {
-		avatar_chooser_clear_image (chooser);
-		return;
-	}
-
-	pixbuf = empathy_pixbuf_from_data_and_mime (data, size, &mime_type);
-	if (pixbuf == NULL) {
-		g_free (data);
-		data = NULL;
-		return;
-	}
-
-	/* avatar takes ownership of data and mime_type */
-	avatar = empathy_avatar_new ((guchar *) data, size, mime_type, NULL);
-
-	avatar_chooser_set_image (chooser, avatar, pixbuf, set_locally);
 }
 
-static void
-avatar_chooser_set_image_from_avatar (EmpathyAvatarChooser *chooser,
-				      EmpathyAvatar        *avatar,
-				      gboolean              set_locally)
+static EmpathyAvatar *
+avatar_chooser_maybe_convert_and_scale (EmpathyAvatarChooser *self,
+    GdkPixbuf *pixbuf,
+    EmpathyAvatar *avatar)
 {
-	GdkPixbuf *pixbuf;
-	gchar     *mime_type = NULL;
-
-	g_assert (avatar != NULL);
-
-	pixbuf = empathy_pixbuf_from_data_and_mime ((gchar *) avatar->data,
-						    avatar->len,
-						    &mime_type);
-	if (pixbuf == NULL) {
-		DEBUG ("couldn't make a pixbuf from avatar; giving up");
-		return;
-	}
-
-	if (avatar->format == NULL) {
-		avatar->format = mime_type;
-	} else {
-		if (strcmp (mime_type, avatar->format)) {
-			DEBUG ("avatar->format is %s; gdkpixbuf yields %s!",
-				avatar->format, mime_type);
-		}
-		g_free (mime_type);
-	}
-
-	empathy_avatar_ref (avatar);
-
-	avatar_chooser_set_image (chooser, avatar, pixbuf, set_locally);
+  TpAvatarRequirements *req;
+  gboolean needs_conversion = FALSE;
+  guint width, height;
+  gchar *new_format_name = NULL;
+  gchar *new_mime_type = NULL;
+  gdouble min_factor, max_factor;
+  gdouble factor;
+  gchar *best_image_data = NULL;
+  gsize best_image_size = 0;
+  guint count = 0;
+
+  req = tp_connection_get_avatar_requirements (self->priv->connection);
+  if (req == NULL)
+    {
+      DEBUG ("Avatar requirements not ready");
+      return NULL;
+    }
+
+  /* Smaller is the factor, smaller will be the image.
+   * 0 is an empty image, 1 is the full size. */
+  min_factor = 0;
+  max_factor = 1;
+  factor = 1;
+
+  /* Check if we need to convert to another image format */
+  if (avatar_chooser_need_mime_type_conversion (avatar->format,
+        req->supported_mime_types, &new_format_name, &new_mime_type))
+    {
+      DEBUG ("Format conversion needed, we'll use mime type '%s' "
+             "and format name '%s'. Current mime type is '%s'",
+             new_mime_type, new_format_name, avatar->format);
+      needs_conversion = TRUE;
+    }
+
+  /* If there is no format we can use, report error to the user. */
+  if (new_mime_type == NULL || new_format_name == NULL)
+    {
+      avatar_chooser_error_show (self, _("Couldn't convert image"),
+          _("None of the accepted image formats are "
+            "supported on your system"));
+      return NULL;
+    }
+
+  /* If width or height are too big, it needs converting. */
+  width = gdk_pixbuf_get_width (pixbuf);
+  height = gdk_pixbuf_get_height (pixbuf);
+  if ((req->maximum_width > 0 && width > req->maximum_width) ||
+      (req->maximum_height > 0 && height > req->maximum_height))
+    {
+      gdouble h_factor, v_factor;
+
+      h_factor = (gdouble) req->maximum_width / width;
+      v_factor = (gdouble) req->maximum_height / height;
+      factor = max_factor = MIN (h_factor, v_factor);
+
+      DEBUG ("Image dimensions (%dx%d) are too big. Max is %dx%d.",
+          width, height, req->maximum_width, req->maximum_height);
+
+      needs_conversion = TRUE;
+    }
+
+  /* If the data len is too big and no other conversion is needed,
+   * try with a lower factor. */
+  if (req->maximum_bytes > 0 && avatar->len > req->maximum_bytes &&
+      !needs_conversion)
+    {
+      DEBUG ("Image data (%"G_GSIZE_FORMAT" bytes) is too big "
+             "(max is %u bytes), conversion needed.",
+             avatar->len, req->maximum_bytes);
+
+      factor = 0.5;
+      needs_conversion = TRUE;
+    }
+
+  /* If no conversion is needed, return the avatar */
+  if (!needs_conversion)
+    {
+      g_free (new_format_name);
+      g_free (new_mime_type);
+      return empathy_avatar_ref (avatar);
+    }
+
+  do
+    {
+      GdkPixbuf *pixbuf_scaled = NULL;
+      gboolean saved;
+      gint new_width, new_height;
+      gchar *converted_image_data;
+      gsize converted_image_size;
+      GError *error = NULL;
+
+      if (factor != 1)
+        {
+          new_width = width * factor;
+          new_height = height * factor;
+          pixbuf_scaled = gdk_pixbuf_scale_simple (pixbuf,
+                     new_width,
+                     new_height,
+                     GDK_INTERP_HYPER);
+        }
+      else
+        {
+          new_width = width;
+          new_height = height;
+          pixbuf_scaled = g_object_ref (pixbuf);
+        }
+
+      DEBUG ("Trying with factor %f (%dx%d) and format %s...", factor,
+        new_width, new_height, new_format_name);
+
+      saved = gdk_pixbuf_save_to_buffer (pixbuf_scaled,
+          &converted_image_data,
+          &converted_image_size,
+          new_format_name,
+          &error, NULL);
+      g_object_unref (pixbuf_scaled);
+
+      if (!saved)
+        {
+          g_free (new_format_name);
+          g_free (new_mime_type);
+          avatar_chooser_error_show (self,
+            _("Couldn't convert image"),
+            error ? error->message : NULL);
+          g_clear_error (&error);
+          return NULL;
+        }
+
+      DEBUG ("Produced an image data of %"G_GSIZE_FORMAT" bytes.",
+        converted_image_size);
+
+      /* If the new image satisfy the req, keep it as current best */
+      if (req->maximum_bytes == 0 || converted_image_size <= req->maximum_bytes)
+        {
+          g_free (best_image_data);
+
+          best_image_data = converted_image_data;
+          best_image_size = converted_image_size;
+
+          /* If this image is close enough to the optimal size,
+           * stop searching */
+          if (req->maximum_bytes == 0 ||
+              req->maximum_bytes - converted_image_size <= 1024)
+            break;
+        }
+      else
+        {
+          g_free (converted_image_data);
+        }
+
+    /* Make a binary search for the bigest factor that produce
+     * an image data size less than max_size */
+    if (converted_image_size > req->maximum_bytes)
+      max_factor = factor;
+    if (converted_image_size < req->maximum_bytes)
+      min_factor = factor;
+    factor = (min_factor + max_factor)/2;
+
+    if ((int) (width * factor) == new_width ||
+        (int) (height * factor) == new_height)
+      {
+        /* min_factor and max_factor are too close, so the new
+         * factor will produce the same image as previous
+         * iteration. No need to continue, we already found
+         * the optimal size. */
+        break;
+      }
+
+    /* Do 10 iterations in the worst case */
+  } while (++count < 10);
+
+  g_free (new_format_name);
+
+  avatar = empathy_avatar_new ((guchar *) best_image_data,
+    best_image_size, new_mime_type, NULL);
+
+  g_free (best_image_data);
+  g_free (new_mime_type);
+
+  return avatar;
 }
 
 static void
-avatar_chooser_set_image (EmpathyAvatarChooser *chooser,
-			  EmpathyAvatar        *avatar,
-			  GdkPixbuf            *pixbuf,
-			  gboolean              set_locally)
+avatar_chooser_set_image (EmpathyAvatarChooser *self,
+    EmpathyAvatar *avatar,
+    GdkPixbuf *pixbuf,
+    gboolean set_locally)
 {
-	EmpathyAvatarChooserPriv *priv = GET_PRIV (chooser);
-	GdkPixbuf                *pixbuf_view;
-	GtkWidget                *image;
+  GdkPixbuf *pixbuf_view;
+  GtkWidget *image;
 
-	g_assert (avatar != NULL);
-	g_assert (pixbuf != NULL);
+  g_assert (avatar != NULL);
+  g_assert (pixbuf != NULL);
 
-	if (set_locally) {
-		EmpathyAvatar *conv;
+  if (set_locally)
+    {
+      EmpathyAvatar *conv;
 
-		conv = avatar_chooser_maybe_convert_and_scale (chooser,
-			pixbuf, avatar);
-		empathy_avatar_unref (avatar);
+      conv = avatar_chooser_maybe_convert_and_scale (self,
+        pixbuf, avatar);
+      empathy_avatar_unref (avatar);
 
-		if (conv == NULL) {
-			/* An error occured; don't change the avatar. */
-			return;
-		}
+      if (conv == NULL)
+        /* An error occured; don't change the avatar. */
+        return;
 
-		avatar = conv;
-	}
+      avatar = conv;
+    }
 
-	if (priv->avatar != NULL) {
-		empathy_avatar_unref (priv->avatar);
-	}
-	priv->avatar = avatar;
+  tp_clear_pointer (&self->priv->avatar, empathy_avatar_unref);
+  self->priv->avatar = avatar;
 
-	pixbuf_view = empathy_pixbuf_scale_down_if_necessary (pixbuf, AVATAR_SIZE_VIEW);
-	image = gtk_image_new_from_pixbuf (pixbuf_view);
+  pixbuf_view = empathy_pixbuf_scale_down_if_necessary (pixbuf,
+      AVATAR_SIZE_VIEW);
+  image = gtk_image_new_from_pixbuf (pixbuf_view);
 
-	gtk_button_set_image (GTK_BUTTON (chooser), image);
-	g_signal_emit (chooser, signals[CHANGED], 0);
+  gtk_button_set_image (GTK_BUTTON (self), image);
+  g_signal_emit (self, signals[CHANGED], 0);
 
-	g_object_unref (pixbuf_view);
-	g_object_unref (pixbuf);
+  g_object_unref (pixbuf_view);
+  g_object_unref (pixbuf);
 }
 
+/* takes ownership of @data */
 static void
-avatar_chooser_set_image_from_file (EmpathyAvatarChooser *chooser,
-				    const gchar          *filename)
+avatar_chooser_set_image_from_data (EmpathyAvatarChooser *self,
+    gchar *data,
+    gsize size,
+    gboolean set_locally)
 {
-	gchar  *image_data = NULL;
-	gsize   image_size = 0;
-	GError *error = NULL;
-
-	if (!g_file_get_contents (filename, &image_data, &image_size, &error)) {
-		DEBUG ("Failed to load image from '%s': %s", filename,
-			error ? error->message : "No error given");
-
-		g_clear_error (&error);
-		return;
-	}
-
-	avatar_chooser_set_image_from_data (chooser, image_data, image_size, TRUE);
+  GdkPixbuf *pixbuf;
+  EmpathyAvatar *avatar = NULL;
+  gchar *mime_type = NULL;
+
+  if (data == NULL)
+    {
+      avatar_chooser_clear_image (self);
+      return;
+    }
+
+  pixbuf = empathy_pixbuf_from_data_and_mime (data, size, &mime_type);
+  if (pixbuf == NULL)
+    {
+      g_free (data);
+      data = NULL;
+      return;
+    }
+
+  avatar = empathy_avatar_new ((guchar *) data, size, mime_type, NULL);
+
+  avatar_chooser_set_image (self, avatar, pixbuf, set_locally);
+
+  g_free (mime_type);
+  g_free (data);
 }
 
 static void
-avatar_chooser_set_avatar_from_pixbuf (EmpathyAvatarChooser *chooser,
-				       GdkPixbuf            *pb)
-{
-	/* dup the string as empathy_avatar_new steals ownership of the it */
-	gchar         *mime = g_strdup ("image/png");
-	gsize          size;
-	gchar         *buf;
-	EmpathyAvatar *avatar = NULL;
-	GError        *error = NULL;
-	if (!gdk_pixbuf_save_to_buffer (pb, &buf, &size, "png", &error, NULL)) {
-		avatar_chooser_error_show (chooser,
-			_("Couldn't save pixbuf to png"),
-			error ? error->message : NULL);
-		g_clear_error (&error);
-		return;
-	}
-	avatar = empathy_avatar_new ((guchar *) buf, size, mime, NULL);
-	avatar_chooser_set_image (chooser, avatar, pb, TRUE);
-}
-
-
-static gboolean
-avatar_chooser_drag_motion_cb (GtkWidget          *widget,
-			      GdkDragContext     *context,
-			      gint                x,
-			      gint                y,
-			      guint               time_,
-			      EmpathyAvatarChooser *chooser)
+avatar_chooser_drag_data_received_cb (GtkWidget          *widget,
+    GdkDragContext *context,
+    gint x,
+    gint y,
+    GtkSelectionData *selection_data,
+    guint info,
+    guint time_,
+    EmpathyAvatarChooser *self)
 {
-	GList                  *p;
-
-	for (p = gdk_drag_context_list_targets (context); p != NULL;
-	     p = p->next) {
-		gchar *possible_type;
-
-		possible_type = gdk_atom_name (GDK_POINTER_TO_ATOM (p->data));
-
-		if (!strcmp (possible_type, URI_LIST_TYPE)) {
-			g_free (possible_type);
-			gdk_drag_status (context, GDK_ACTION_COPY, time_);
-
-			return TRUE;
-		}
-
-		g_free (possible_type);
-	}
-
-	return FALSE;
+  gchar *target_type;
+  gboolean handled = FALSE;
+
+  target_type = gdk_atom_name (gtk_selection_data_get_target (selection_data));
+  if (!strcmp (target_type, URI_LIST_TYPE))
+    {
+      GFile *file;
+      gchar *nl;
+      gchar *data = NULL;
+      gsize bytes_read;
+
+      nl = strstr ((gchar *) gtk_selection_data_get_data (selection_data),
+              "\r\n");
+      if (nl != NULL)
+        {
+          gchar *uri;
+
+          uri = g_strndup (
+              (gchar *) gtk_selection_data_get_data (selection_data),
+              nl - (gchar *) gtk_selection_data_get_data (selection_data));
+
+          file = g_file_new_for_uri (uri);
+          g_free (uri);
+        }
+      else
+        {
+          file = g_file_new_for_uri ((gchar *) gtk_selection_data_get_data (
+                selection_data));
+        }
+
+      handled = g_file_load_contents (file, NULL, &data, &bytes_read,
+              NULL, NULL);
+
+      if (handled)
+        {
+          /* pass data to the avatar_chooser_set_image_from_data */
+          avatar_chooser_set_image_from_data (self, data, bytes_read, TRUE);
+        }
+
+      g_object_unref (file);
+    }
+
+  gtk_drag_finish (context, handled, FALSE, time_);
 }
 
 static void
-avatar_chooser_drag_leave_cb (GtkWidget          *widget,
-			     GdkDragContext     *context,
-			     guint               time_,
-			     EmpathyAvatarChooser *chooser)
+avatar_chooser_update_preview_cb (GtkFileChooser *file_chooser,
+    EmpathyAvatarChooser *self)
 {
-}
+  gchar *filename;
 
-static gboolean
-avatar_chooser_drag_drop_cb (GtkWidget          *widget,
-			    GdkDragContext     *context,
-			    gint                x,
-			    gint                y,
-			    guint               time_,
-			    EmpathyAvatarChooser *chooser)
-{
-	GList                  *p;
+  filename = gtk_file_chooser_get_preview_filename (file_chooser);
 
-	if (gdk_drag_context_list_targets (context) == NULL) {
-		return FALSE;
-	}
+  if (filename != NULL)
+    {
+      GtkWidget *image;
+      GdkPixbuf *pixbuf = NULL;
+      GdkPixbuf *scaled_pixbuf;
 
-	for (p = gdk_drag_context_list_targets (context);
-	     p != NULL; p = p->next) {
-		char *possible_type;
+      pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
 
-		possible_type = gdk_atom_name (GDK_POINTER_TO_ATOM (p->data));
-		if (!strcmp (possible_type, URI_LIST_TYPE)) {
-			g_free (possible_type);
-			gtk_drag_get_data (widget, context,
-					   GDK_POINTER_TO_ATOM (p->data),
-					   time_);
+      image = gtk_file_chooser_get_preview_widget (file_chooser);
 
-			return TRUE;
-		}
+      if (pixbuf != NULL)
+        {
+          scaled_pixbuf = empathy_pixbuf_scale_down_if_necessary (pixbuf,
+              AVATAR_SIZE_SAVE);
 
-		g_free (possible_type);
-	}
+          gtk_image_set_from_pixbuf (GTK_IMAGE (image), scaled_pixbuf);
+          g_object_unref (scaled_pixbuf);
+          g_object_unref (pixbuf);
+        }
+      else
+        {
+          gtk_image_set_from_stock (GTK_IMAGE (image),
+                  "gtk-dialog-question",
+                  GTK_ICON_SIZE_DIALOG);
+        }
 
-	return FALSE;
-}
+      g_free (filename);
+    }
 
-static void
-avatar_chooser_drag_data_received_cb (GtkWidget          *widget,
-				     GdkDragContext     *context,
-				     gint                x,
-				     gint                y,
-				     GtkSelectionData   *selection_data,
-				     guint               info,
-				     guint               time_,
-				     EmpathyAvatarChooser *chooser)
-{
-	gchar    *target_type;
-	gboolean  handled = FALSE;
-
-	target_type = gdk_atom_name (gtk_selection_data_get_target (selection_data));
-	if (!strcmp (target_type, URI_LIST_TYPE)) {
-		GFile            *file;
-		gchar            *nl;
-		gchar            *data = NULL;
-		gsize             bytes_read;
-
-		nl = strstr ((gchar *) gtk_selection_data_get_data (selection_data),
-						"\r\n");
-		if (nl) {
-			gchar *uri;
-
-			uri = g_strndup ((gchar *) gtk_selection_data_get_data (selection_data),
-					 nl - (gchar *) gtk_selection_data_get_data (selection_data));
-
-			file = g_file_new_for_uri (uri);
-			g_free (uri);
-		} else {
-			file = g_file_new_for_uri ((gchar *) gtk_selection_data_get_data (
-						selection_data));
-		}
-
-		handled = g_file_load_contents (file, NULL, &data, &bytes_read,
-						NULL, NULL);
-
-		if (handled) {
-			/* this in turn calls empathy_avatar_new (), which assumes
-			 * ownership of data.
-			 */
-			avatar_chooser_set_image_from_data (chooser, data,
-							    bytes_read,
-							    TRUE);
-		}
-
-		g_object_unref (file);
-	}
-
-	gtk_drag_finish (context, handled, FALSE, time_);
+  gtk_file_chooser_set_preview_widget_active (file_chooser, TRUE);
 }
 
 static void
-avatar_chooser_update_preview_cb (GtkFileChooser       *file_chooser,
-				  EmpathyAvatarChooser *chooser)
+avatar_chooser_set_image_from_file (EmpathyAvatarChooser *self,
+    const gchar *filename)
 {
-	gchar *filename;
-
-	filename = gtk_file_chooser_get_preview_filename (file_chooser);
-
-	if (filename) {
-		GtkWidget *image;
-		GdkPixbuf *pixbuf = NULL;
-		GdkPixbuf *scaled_pixbuf;
+  gchar *image_data = NULL;
+  gsize  image_size = 0;
+  GError *error = NULL;
 
-		pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
+  if (!g_file_get_contents (filename, &image_data, &image_size, &error))
+    {
+      DEBUG ("Failed to load image from '%s': %s", filename,
+        error ? error->message : "No error given");
 
-		image = gtk_file_chooser_get_preview_widget (file_chooser);
+      g_clear_error (&error);
+      return;
+    }
 
-		if (pixbuf) {
-			scaled_pixbuf = empathy_pixbuf_scale_down_if_necessary (pixbuf, AVATAR_SIZE_SAVE);
-			gtk_image_set_from_pixbuf (GTK_IMAGE (image), scaled_pixbuf);
-			g_object_unref (scaled_pixbuf);
-			g_object_unref (pixbuf);
-		} else {
-			gtk_image_set_from_stock (GTK_IMAGE (image),
-						  "gtk-dialog-question",
-						  GTK_ICON_SIZE_DIALOG);
-		}
-
-		g_free (filename);
-	}
+  /* pass image_data to the avatar_chooser_set_image_from_data */
+  avatar_chooser_set_image_from_data (self, image_data, image_size, TRUE);
+}
 
-	gtk_file_chooser_set_preview_widget_active (file_chooser, TRUE);
+static void
+avatar_chooser_set_avatar_from_pixbuf (EmpathyAvatarChooser *self,
+               GdkPixbuf *pb)
+{
+  gsize size;
+  gchar *buf;
+  EmpathyAvatar *avatar = NULL;
+  GError *error = NULL;
+
+  if (!gdk_pixbuf_save_to_buffer (pb, &buf, &size, "png", &error, NULL))
+    {
+      avatar_chooser_error_show (self,
+        _("Couldn't save pixbuf to png"),
+        error ? error->message : NULL);
+      g_clear_error (&error);
+      return;
+    }
+
+  avatar = empathy_avatar_new ((guchar *) buf, size, "image/png", NULL);
+  avatar_chooser_set_image (self, avatar, pb, TRUE);
+
+  g_free (buf);
 }
 
 #ifdef HAVE_CHEESE
 static gboolean
-destroy_chooser (GtkWidget *chooser)
+destroy_chooser (GtkWidget *self)
 {
-	gtk_widget_destroy (chooser);
-	return FALSE;
+  gtk_widget_destroy (self);
+  return FALSE;
 }
 
 static void
-webcam_response_cb (GtkDialog            *dialog,
-		    int                   response,
-		    EmpathyAvatarChooser *chooser)
+webcam_response_cb (GtkDialog *dialog,
+        int response,
+        EmpathyAvatarChooser *self)
 {
-	if (response == GTK_RESPONSE_ACCEPT) {
-		GdkPixbuf           *pb;
-		CheeseAvatarChooser *cheese_chooser;
-
-		cheese_chooser = CHEESE_AVATAR_CHOOSER (dialog);
-		pb = cheese_avatar_chooser_get_picture (cheese_chooser);
-		avatar_chooser_set_avatar_from_pixbuf (chooser, pb);
-	}
-	if (response != GTK_RESPONSE_DELETE_EVENT &&
-	    response != GTK_RESPONSE_NONE)
-		g_idle_add ((GSourceFunc) destroy_chooser, dialog);
+  if (response == GTK_RESPONSE_ACCEPT)
+    {
+      GdkPixbuf *pb;
+      CheeseAvatarChooser *cheese_chooser;
+
+      cheese_chooser = CHEESE_AVATAR_CHOOSER (dialog);
+      pb = cheese_avatar_chooser_get_picture (cheese_chooser);
+      avatar_chooser_set_avatar_from_pixbuf (self, pb);
+    }
+
+  if (response != GTK_RESPONSE_DELETE_EVENT &&
+      response != GTK_RESPONSE_NONE)
+    g_idle_add ((GSourceFunc) destroy_chooser, dialog);
 }
 
 static void
-choose_avatar_from_webcam (GtkWidget            *widget,
-			   EmpathyAvatarChooser *chooser)
+choose_avatar_from_webcam (GtkWidget *widget,
+    EmpathyAvatarChooser *self)
 {
-	GtkWidget *window;
+  GtkWidget *window;
 
-	window = cheese_avatar_chooser_new ();
+  window = cheese_avatar_chooser_new ();
 
-	gtk_window_set_transient_for (GTK_WINDOW (window),
-				      GTK_WINDOW (empathy_get_toplevel_window (GTK_WIDGET (chooser))));
-	gtk_window_set_modal (GTK_WINDOW (window), TRUE);
-	g_signal_connect (G_OBJECT (window), "response",
-			  G_CALLBACK (webcam_response_cb), chooser);
-	gtk_widget_show (window);
+  gtk_window_set_transient_for (GTK_WINDOW (window),
+      GTK_WINDOW (empathy_get_toplevel_window (GTK_WIDGET (self))));
+  gtk_window_set_modal (GTK_WINDOW (window), TRUE);
+  g_signal_connect (G_OBJECT (window), "response",
+      G_CALLBACK (webcam_response_cb), self);
+  gtk_widget_show (window);
 }
 #endif /* HAVE_CHEESE */
 
 static void
-avatar_chooser_response_cb (GtkWidget            *widget,
-			    gint                  response,
-			    EmpathyAvatarChooser *chooser)
+avatar_chooser_response_cb (GtkWidget *widget,
+    gint response,
+    EmpathyAvatarChooser *self)
+{
+  self->priv->chooser_dialog = NULL;
+
+  if (response == EMPATHY_AVATAR_CHOOSER_RESPONSE_FILE)
+    {
+      gchar *filename;
+      gchar *path;
+
+      filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));
+      avatar_chooser_set_image_from_file (self, filename);
+      g_free (filename);
+
+      path = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (widget));
+      if (path != NULL)
+        {
+          g_settings_set_string (self->priv->gsettings_ui,
+                     EMPATHY_PREFS_UI_AVATAR_DIRECTORY,
+                     path);
+
+          g_free (path);
+        }
+    }
+  else if (response == EMPATHY_AVATAR_CHOOSER_RESPONSE_NO_IMAGE)
+    {
+      /* This corresponds to "No Image", not to "Cancel" */
+      avatar_chooser_clear_image (self);
+    }
+  #ifdef HAVE_CHEESE
+  else if (response == EMPATHY_AVATAR_CHOOSER_RESPONSE_WEBCAM)
+    {
+      /* This corresponds to "Camera Picture" */
+      choose_avatar_from_webcam (widget, self);
+    }
+  #endif
+
+  gtk_widget_destroy (widget);
+}
+
+static void
+avatar_chooser_clicked_cb (GtkWidget *button,
+    EmpathyAvatarChooser *self)
 {
-	EmpathyAvatarChooserPriv *priv = GET_PRIV (chooser);
-
-	priv->chooser_dialog = NULL;
-
-	if (response == EMPATHY_AVATAR_CHOOSER_RESPONSE_FILE) {
-		gchar *filename;
-		gchar *path;
-
-		filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));
-		avatar_chooser_set_image_from_file (chooser, filename);
-		g_free (filename);
-
-		path = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (widget));
-		if (path) {
-			g_settings_set_string (priv->gsettings_ui,
-					       EMPATHY_PREFS_UI_AVATAR_DIRECTORY,
-					       path);
-
-			g_free (path);
-		}
-	}
-	else if (response == EMPATHY_AVATAR_CHOOSER_RESPONSE_NO_IMAGE) {
-		/* This corresponds to "No Image", not to "Cancel" */
-		avatar_chooser_clear_image (chooser);
-	}
-	#ifdef HAVE_CHEESE
-	else if (response == EMPATHY_AVATAR_CHOOSER_RESPONSE_WEBCAM) {
-		/* This corresponds to "Camera Picture" */
-		choose_avatar_from_webcam (widget, chooser);
-	}
-	#endif
-	gtk_widget_destroy (widget);
+  GtkFileChooser *chooser_dialog;
+  GtkWidget *image;
+  gchar *saved_dir = NULL;
+  const gchar *default_dir = DEFAULT_DIR;
+  const gchar *pics_dir;
+  GtkFileFilter *filter;
+
+  if (self->priv->chooser_dialog != NULL)
+    {
+      gtk_window_present (GTK_WINDOW (self->priv->chooser_dialog));
+      return;
+    }
+
+  self->priv->chooser_dialog = GTK_FILE_CHOOSER (
+      gtk_file_chooser_dialog_new (_("Select Your Avatar Image"),
+        empathy_get_toplevel_window (GTK_WIDGET (self)),
+        GTK_FILE_CHOOSER_ACTION_OPEN,
+        #ifdef HAVE_CHEESE
+        _("Take a picture..."),
+        EMPATHY_AVATAR_CHOOSER_RESPONSE_WEBCAM,
+        #endif
+        _("No Image"),
+        EMPATHY_AVATAR_CHOOSER_RESPONSE_NO_IMAGE,
+        GTK_STOCK_CANCEL,
+        EMPATHY_AVATAR_CHOOSER_RESPONSE_CANCEL,
+        GTK_STOCK_OPEN,
+        EMPATHY_AVATAR_CHOOSER_RESPONSE_FILE,
+        NULL));
+
+  chooser_dialog = self->priv->chooser_dialog;
+  gtk_window_set_destroy_with_parent (GTK_WINDOW (chooser_dialog), TRUE);
+
+  /* Get special dirs */
+  saved_dir = g_settings_get_string (self->priv->gsettings_ui,
+             EMPATHY_PREFS_UI_AVATAR_DIRECTORY);
+
+  if (saved_dir != NULL &&
+      !g_file_test (saved_dir, G_FILE_TEST_IS_DIR))
+    {
+      g_free (saved_dir);
+      saved_dir = NULL;
+    }
+
+  if (!g_file_test (default_dir, G_FILE_TEST_IS_DIR))
+    default_dir = NULL;
+
+  pics_dir = g_get_user_special_dir (G_USER_DIRECTORY_PICTURES);
+  if (pics_dir != NULL && !g_file_test (pics_dir, G_FILE_TEST_IS_DIR))
+    pics_dir = NULL;
+
+  /* Set current dir to the last one or to DEFAULT_DIR or to home */
+  if (saved_dir != NULL)
+    gtk_file_chooser_set_current_folder (chooser_dialog, saved_dir);
+  else if (pics_dir != NULL)
+    gtk_file_chooser_set_current_folder (chooser_dialog, pics_dir);
+  else if (default_dir != NULL)
+    gtk_file_chooser_set_current_folder (chooser_dialog, default_dir);
+  else
+    gtk_file_chooser_set_current_folder (chooser_dialog, g_get_home_dir ());
+
+  /* Add shortcuts to special dirs */
+  if (saved_dir)
+    gtk_file_chooser_add_shortcut_folder (chooser_dialog, saved_dir, NULL);
+  else if (pics_dir)
+    gtk_file_chooser_add_shortcut_folder (chooser_dialog, pics_dir, NULL);
+
+  if (default_dir != NULL)
+    gtk_file_chooser_add_shortcut_folder (chooser_dialog, default_dir, NULL);
+
+  /* Setup preview image */
+  image = gtk_image_new ();
+  gtk_file_chooser_set_preview_widget (chooser_dialog, image);
+  gtk_widget_set_size_request (image, AVATAR_SIZE_SAVE, AVATAR_SIZE_SAVE);
+  gtk_widget_show (image);
+  gtk_file_chooser_set_use_preview_label (chooser_dialog, FALSE);
+  g_signal_connect (chooser_dialog, "update-preview",
+      G_CALLBACK (avatar_chooser_update_preview_cb),
+      self);
+
+  /* Setup filers */
+  filter = gtk_file_filter_new ();
+  gtk_file_filter_set_name (filter, _("Images"));
+  gtk_file_filter_add_pixbuf_formats (filter);
+  gtk_file_chooser_add_filter (chooser_dialog, filter);
+  filter = gtk_file_filter_new ();
+  gtk_file_filter_set_name (filter, _("All Files"));
+  gtk_file_filter_add_pattern (filter, "*");
+  gtk_file_chooser_add_filter (chooser_dialog, filter);
+
+  /* Setup response */
+  gtk_dialog_set_default_response (GTK_DIALOG (chooser_dialog),
+      EMPATHY_AVATAR_CHOOSER_RESPONSE_FILE);
+
+  g_signal_connect (chooser_dialog, "response",
+      G_CALLBACK (avatar_chooser_response_cb),
+      self);
+
+  gtk_widget_show (GTK_WIDGET (chooser_dialog));
+
+  g_free (saved_dir);
 }
 
 static void
-avatar_chooser_clicked_cb (GtkWidget            *button,
-			   EmpathyAvatarChooser *chooser)
+empathy_avatar_chooser_init (EmpathyAvatarChooser *self)
 {
-	GtkFileChooser *chooser_dialog;
-	GtkWidget      *image;
-	gchar          *saved_dir = NULL;
-	const gchar    *default_dir = DEFAULT_DIR;
-	const gchar    *pics_dir;
-	GtkFileFilter  *filter;
-	EmpathyAvatarChooserPriv *priv = GET_PRIV (chooser);
-
-	if (priv->chooser_dialog) {
-		gtk_window_present (GTK_WINDOW (priv->chooser_dialog));
-		return;
-	}
-
-	priv->chooser_dialog = GTK_FILE_CHOOSER (
-		gtk_file_chooser_dialog_new (_("Select Your Avatar Image"),
-					     empathy_get_toplevel_window (GTK_WIDGET (chooser)),
-					     GTK_FILE_CHOOSER_ACTION_OPEN,
-					     #ifdef HAVE_CHEESE
-					     _("Take a picture..."),
-					     EMPATHY_AVATAR_CHOOSER_RESPONSE_WEBCAM,
-					     #endif
-					     _("No Image"),
-					     EMPATHY_AVATAR_CHOOSER_RESPONSE_NO_IMAGE,
-					     GTK_STOCK_CANCEL,
-					     EMPATHY_AVATAR_CHOOSER_RESPONSE_CANCEL,
-					     GTK_STOCK_OPEN,
-					     EMPATHY_AVATAR_CHOOSER_RESPONSE_FILE,
-					     NULL));
-	chooser_dialog = priv->chooser_dialog;
-	gtk_window_set_destroy_with_parent (GTK_WINDOW (chooser_dialog), TRUE);
-
-	/* Get special dirs */
-	saved_dir = g_settings_get_string (priv->gsettings_ui,
-					   EMPATHY_PREFS_UI_AVATAR_DIRECTORY);
-
-	if (saved_dir && !g_file_test (saved_dir, G_FILE_TEST_IS_DIR)) {
-		g_free (saved_dir);
-		saved_dir = NULL;
-	}
-	if (!g_file_test (default_dir, G_FILE_TEST_IS_DIR)) {
-		default_dir = NULL;
-	}
-	pics_dir = g_get_user_special_dir (G_USER_DIRECTORY_PICTURES);
-	if (pics_dir && !g_file_test (pics_dir, G_FILE_TEST_IS_DIR)) {
-		pics_dir = NULL;
-	}
-
-	/* Set current dir to the last one or to DEFAULT_DIR or to home */
-	if (saved_dir) {
-		gtk_file_chooser_set_current_folder (chooser_dialog, saved_dir);
-	}
-	else if (pics_dir) {
-		gtk_file_chooser_set_current_folder (chooser_dialog, pics_dir);
-	}
-	else if (default_dir) {
-		gtk_file_chooser_set_current_folder (chooser_dialog, default_dir);
-	} else {
-		gtk_file_chooser_set_current_folder (chooser_dialog, g_get_home_dir ());
-	}
-
-	/* Add shortcuts to special dirs */
-	if (saved_dir) {
-		gtk_file_chooser_add_shortcut_folder (chooser_dialog, saved_dir, NULL);
-	}
-	else if (pics_dir) {
-		gtk_file_chooser_add_shortcut_folder (chooser_dialog, pics_dir, NULL);
-	}
-	if (default_dir) {
-		gtk_file_chooser_add_shortcut_folder (chooser_dialog, default_dir, NULL);
-	}
-
-	/* Setup preview image */
-	image = gtk_image_new ();
-	gtk_file_chooser_set_preview_widget (chooser_dialog, image);
-	gtk_widget_set_size_request (image, AVATAR_SIZE_SAVE, AVATAR_SIZE_SAVE);
-	gtk_widget_show (image);
-	gtk_file_chooser_set_use_preview_label (chooser_dialog,	FALSE);
-	g_signal_connect (chooser_dialog, "update-preview",
-			  G_CALLBACK (avatar_chooser_update_preview_cb),
-			  chooser);
-
-	/* Setup filers */
-	filter = gtk_file_filter_new ();
-	gtk_file_filter_set_name (filter, _("Images"));
-	gtk_file_filter_add_pixbuf_formats (filter);
-	gtk_file_chooser_add_filter (chooser_dialog, filter);
-	filter = gtk_file_filter_new ();
-	gtk_file_filter_set_name (filter, _("All Files"));
-	gtk_file_filter_add_pattern (filter, "*");
-	gtk_file_chooser_add_filter (chooser_dialog, filter);
-
-	/* Setup response */
-	gtk_dialog_set_default_response (GTK_DIALOG (chooser_dialog), EMPATHY_AVATAR_CHOOSER_RESPONSE_FILE);
-	g_signal_connect (chooser_dialog, "response",
-			  G_CALLBACK (avatar_chooser_response_cb),
-			  chooser);
-
-	gtk_widget_show (GTK_WIDGET (chooser_dialog));
-
-	g_free (saved_dir);
+  self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+    EMPATHY_TYPE_AVATAR_CHOOSER, EmpathyAvatarChooserPrivate);
+
+  gtk_drag_dest_set (GTK_WIDGET (self),
+      GTK_DEST_DEFAULT_ALL,
+      drop_types,
+      G_N_ELEMENTS (drop_types),
+      GDK_ACTION_COPY);
+
+  self->priv->gsettings_ui = g_settings_new (EMPATHY_PREFS_UI_SCHEMA);
+
+  g_signal_connect (self, "drag-motion",
+      G_CALLBACK (avatar_chooser_drag_motion_cb),
+      self);
+  g_signal_connect (self, "drag-drop",
+      G_CALLBACK (avatar_chooser_drag_drop_cb),
+      self);
+  g_signal_connect (self, "drag-data-received",
+      G_CALLBACK (avatar_chooser_drag_data_received_cb),
+      self);
+  g_signal_connect (self, "clicked",
+      G_CALLBACK (avatar_chooser_clicked_cb),
+      self);
+
+  empathy_avatar_chooser_set (self, NULL);
+}
+
+static void
+avatar_chooser_set_image_from_avatar (EmpathyAvatarChooser *self,
+    EmpathyAvatar *avatar,
+    gboolean set_locally)
+{
+  GdkPixbuf *pixbuf;
+  gchar *mime_type = NULL;
+
+  g_assert (avatar != NULL);
+
+  pixbuf = empathy_pixbuf_from_data_and_mime ((gchar *) avatar->data,
+      avatar->len, &mime_type);
+
+  if (pixbuf == NULL)
+    {
+      DEBUG ("couldn't make a pixbuf from avatar; giving up");
+      return;
+    }
+
+  if (avatar->format == NULL)
+    {
+      avatar->format = mime_type;
+    }
+  else
+    {
+      if (strcmp (mime_type, avatar->format))
+        DEBUG ("avatar->format is %s; gdkpixbuf yields %s!",
+          avatar->format, mime_type);
+
+      g_free (mime_type);
+    }
+
+  empathy_avatar_ref (avatar);
+
+  avatar_chooser_set_image (self, avatar, pixbuf, set_locally);
 }
 
 /**
@@ -1112,32 +1100,31 @@ avatar_chooser_clicked_cb (GtkWidget            *button,
 GtkWidget *
 empathy_avatar_chooser_new (void)
 {
-	return g_object_new (EMPATHY_TYPE_AVATAR_CHOOSER, NULL);
+  return g_object_new (EMPATHY_TYPE_AVATAR_CHOOSER, NULL);
 }
 
 /**
  * empathy_avatar_chooser_set:
- * @chooser: an #EmpathyAvatarChooser
+ * @self: an #EmpathyAvatarChooser
  * @avatar: a new #EmpathyAvatar
  *
- * Sets the @chooser to display the avatar indicated by @avatar.
+ * Sets the @self to display the avatar indicated by @avatar.
  */
 void
-empathy_avatar_chooser_set (EmpathyAvatarChooser *chooser,
-			    EmpathyAvatar        *avatar)
+empathy_avatar_chooser_set (EmpathyAvatarChooser *self,
+    EmpathyAvatar *avatar)
 {
-	g_return_if_fail (EMPATHY_IS_AVATAR_CHOOSER (chooser));
+  g_return_if_fail (EMPATHY_IS_AVATAR_CHOOSER (self));
 
-	if (avatar != NULL) {
-		avatar_chooser_set_image_from_avatar (chooser, avatar, FALSE);
-	} else {
-		avatar_chooser_clear_image (chooser);
-	}
+  if (avatar != NULL)
+    avatar_chooser_set_image_from_avatar (self, avatar, FALSE);
+  else
+    avatar_chooser_clear_image (self);
 }
 
 /**
  * empathy_avatar_chooser_get_image_data:
- * @chooser: an #EmpathyAvatarChooser
+ * @self: an #EmpathyAvatarChooser
  * @data: avatar bytes
  * @data_size: size of @data
  * @mime_type: avatar mime-type
@@ -1145,46 +1132,43 @@ empathy_avatar_chooser_set (EmpathyAvatarChooser *chooser,
  * Gets image data about the currently selected avatar.
  */
 void
-empathy_avatar_chooser_get_image_data (EmpathyAvatarChooser  *chooser,
-				       const gchar          **data,
-				       gsize                 *data_size,
-				       const gchar          **mime_type)
+empathy_avatar_chooser_get_image_data (EmpathyAvatarChooser  *self,
+    const gchar **data,
+    gsize *data_size,
+    const gchar **mime_type)
 {
-	EmpathyAvatarChooserPriv *priv;
-
-	g_return_if_fail (EMPATHY_IS_AVATAR_CHOOSER (chooser));
-
-	priv = GET_PRIV (chooser);
-
-	if (priv->avatar != NULL) {
-		if (data != NULL) {
-			*data = (gchar *) priv->avatar->data;
-		}
-		if (data_size != NULL) {
-			*data_size = priv->avatar->len;
-		}
-		if (mime_type != NULL) {
-			*mime_type = priv->avatar->format;
-		}
-	} else {
-		if (data != NULL) {
-			*data = NULL;
-		}
-		if (data_size != NULL) {
-			*data_size = 0;
-		}
-		if (mime_type != NULL) {
-			*mime_type = NULL;
-		}
-	}
+  g_return_if_fail (EMPATHY_IS_AVATAR_CHOOSER (self));
+
+  if (self->priv->avatar != NULL)
+    {
+      if (data != NULL)
+        *data = (gchar *) self->priv->avatar->data;
+
+      if (data_size != NULL)
+        *data_size = self->priv->avatar->len;
+
+      if (mime_type != NULL)
+        *mime_type = self->priv->avatar->format;
+  }
+  else
+    {
+      if (data != NULL)
+        *data = NULL;
+
+      if (data_size != NULL)
+        *data_size = 0;
+
+      if (mime_type != NULL)
+        *mime_type = NULL;
+    }
 }
 
 void
 empathy_avatar_chooser_set_account (EmpathyAvatarChooser *self,
-				       TpAccount *account)
+    TpAccount *account)
 {
-	g_return_if_fail (account != NULL);
+  g_return_if_fail (account != NULL);
 
-	avatar_chooser_set_connection (self, tp_account_get_connection (account));
-	g_object_notify (G_OBJECT (self), "connection");
+  avatar_chooser_set_connection (self, tp_account_get_connection (account));
+  g_object_notify (G_OBJECT (self), "connection");
 }
diff --git a/libempathy-gtk/empathy-avatar-chooser.h b/libempathy-gtk/empathy-avatar-chooser.h
index 6ca5831..7df142b 100644
--- a/libempathy-gtk/empathy-avatar-chooser.h
+++ b/libempathy-gtk/empathy-avatar-chooser.h
@@ -30,36 +30,42 @@
 
 G_BEGIN_DECLS
 
-#define EMPATHY_TYPE_AVATAR_CHOOSER	       (empathy_avatar_chooser_get_type ())
-#define EMPATHY_AVATAR_CHOOSER(obj)	       (G_TYPE_CHECK_INSTANCE_CAST ((obj), EMPATHY_TYPE_AVATAR_CHOOSER, EmpathyAvatarChooser))
+#define EMPATHY_TYPE_AVATAR_CHOOSER        (empathy_avatar_chooser_get_type ())
+#define EMPATHY_AVATAR_CHOOSER(obj)        (G_TYPE_CHECK_INSTANCE_CAST ((obj), EMPATHY_TYPE_AVATAR_CHOOSER, EmpathyAvatarChooser))
 #define EMPATHY_AVATAR_CHOOSER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), EMPATHY_TYPE_AVATAR_CHOOSER, EmpathyAvatarChooserClass))
-#define EMPATHY_IS_AVATAR_CHOOSER(obj)	       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EMPATHY_TYPE_AVATAR_CHOOSER))
+#define EMPATHY_IS_AVATAR_CHOOSER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EMPATHY_TYPE_AVATAR_CHOOSER))
 #define EMPATHY_IS_AVATAR_CHOOSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), EMPATHY_TYPE_AVATAR_CHOOSER))
 
 typedef struct _EmpathyAvatarChooser        EmpathyAvatarChooser;
 typedef struct _EmpathyAvatarChooserClass   EmpathyAvatarChooserClass;
+typedef struct _EmpathyAvatarChooserPrivate EmpathyAvatarChooserPrivate;
 
-struct _EmpathyAvatarChooser {
-	GtkButton parent;
+struct _EmpathyAvatarChooser
+{
+  GtkButton parent;
 
-	/*<private>*/
-	gpointer priv;
+  /*<private>*/
+  EmpathyAvatarChooserPrivate *priv;
 };
 
-struct _EmpathyAvatarChooserClass {
-	GtkButtonClass parent_class;
+struct _EmpathyAvatarChooserClass
+{
+  GtkButtonClass parent_class;
 };
 
-GType      empathy_avatar_chooser_get_type       (void);
-GtkWidget *empathy_avatar_chooser_new            (void);
-void       empathy_avatar_chooser_set            (EmpathyAvatarChooser *chooser,
-						  EmpathyAvatar        *avatar);
-void       empathy_avatar_chooser_get_image_data (EmpathyAvatarChooser *chooser,
-						  const gchar         **data,
-						  gsize                *data_size,
-						  const gchar         **mime_type);
+GType empathy_avatar_chooser_get_type (void);
 
-void       empathy_avatar_chooser_set_account (EmpathyAvatarChooser *self,
-						  TpAccount *account);
+GtkWidget *empathy_avatar_chooser_new (void);
+
+void empathy_avatar_chooser_set (EmpathyAvatarChooser *self,
+    EmpathyAvatar *avatar);
+
+void empathy_avatar_chooser_get_image_data (EmpathyAvatarChooser *self,
+    const gchar **data,
+    gsize *data_size,
+    const gchar **mime_type);
+
+void empathy_avatar_chooser_set_account (EmpathyAvatarChooser *self,
+    TpAccount *account);
 
 #endif /* __EMPATHY_AVATAR_CHOOSER_H__ */
diff --git a/libempathy/empathy-contact.c b/libempathy/empathy-contact.c
index f3e200e..7b23df0 100644
--- a/libempathy/empathy-contact.c
+++ b/libempathy/empathy-contact.c
@@ -1282,17 +1282,16 @@ contact_load_avatar_cache (EmpathyContact *contact,
         }
     }
 
-  if (data)
+  if (data != NULL)
     {
       DEBUG ("Avatar loaded from %s", filename);
       avatar = empathy_avatar_new ((guchar *) data, len, NULL, filename);
       contact_set_avatar (contact, avatar);
       empathy_avatar_unref (avatar);
     }
-  else
-    {
-      g_free (filename);
-    }
+
+  g_free (data);
+  g_free (filename);
 
   return data != NULL;
 }
@@ -1319,24 +1318,23 @@ empathy_avatar_get_type (void)
  * @format: the mime type of the avatar image
  * @filename: the filename where the avatar is stored in cache
  *
- * Create a #EmpathyAvatar from the provided data. This function takes the
- * ownership of @data, @format and @filename.
+ * Create a #EmpathyAvatar from the provided data.
  *
  * Returns: a new #EmpathyAvatar
  */
 EmpathyAvatar *
-empathy_avatar_new (guchar *data,
+empathy_avatar_new (const guchar *data,
                     gsize len,
-                    gchar *format,
-                    gchar *filename)
+                    const gchar *format,
+                    const gchar *filename)
 {
   EmpathyAvatar *avatar;
 
   avatar = g_slice_new0 (EmpathyAvatar);
-  avatar->data = data;
+  avatar->data = g_memdup (data, len);
   avatar->len = len;
-  avatar->format = format;
-  avatar->filename = filename;
+  avatar->format = g_strdup (format);
+  avatar->filename = g_strdup (filename);
   avatar->refcount = 1;
 
   return avatar;
@@ -1783,12 +1781,17 @@ contact_set_avatar_from_tp_contact (EmpathyContact *contact)
       EmpathyAvatar *avatar;
       gchar *data;
       gsize len;
+      gchar *path;
 
       g_file_load_contents (file, NULL, &data, &len, NULL, NULL);
-      avatar = empathy_avatar_new ((guchar *) data, len, g_strdup (mime),
-          g_file_get_path (file));
+      path = g_file_get_path (file);
+
+      avatar = empathy_avatar_new ((guchar *) data, len, mime, path);
+
       contact_set_avatar (contact, avatar);
       empathy_avatar_unref (avatar);
+      g_free (path);
+      g_free (data);
     }
   else
     {
diff --git a/libempathy/empathy-contact.h b/libempathy/empathy-contact.h
index 16b50e5..b32971a 100644
--- a/libempathy/empathy-contact.h
+++ b/libempathy/empathy-contact.h
@@ -117,10 +117,10 @@ gboolean empathy_contact_can_do_action (EmpathyContact *self,
 
 #define EMPATHY_TYPE_AVATAR (empathy_avatar_get_type ())
 GType empathy_avatar_get_type (void) G_GNUC_CONST;
-EmpathyAvatar * empathy_avatar_new (guchar *data,
+EmpathyAvatar * empathy_avatar_new (const guchar *data,
     gsize len,
-    gchar *format,
-    gchar *filename);
+    const gchar *format,
+    const gchar *filename);
 EmpathyAvatar * empathy_avatar_ref (EmpathyAvatar *avatar);
 void empathy_avatar_unref (EmpathyAvatar *avatar);
 
