]> git.0d.be Git - empathy.git/commitdiff
Implement EmpathyAvatarChooser and EmpathyAvatarImage and make use of them
authorXavier Claessens <xclaesse@gmail.com>
Mon, 8 Oct 2007 16:44:44 +0000 (16:44 +0000)
committerXavier Claessens <xclaesse@src.gnome.org>
Mon, 8 Oct 2007 16:44:44 +0000 (16:44 +0000)
2007-10-08  Xavier Claessens  <xclaesse@gmail.com>

* libempathy-gtk/empathy-ui-utils.c:
* libempathy-gtk/empathy-ui-utils.h:
* libempathy-gtk/empathy-contact-widget.c:
* libempathy-gtk/empathy-contact-widget.h:
* libempathy-gtk/empathy-avatar-chooser.c:
* libempathy-gtk/empathy-avatar-chooser.h:
* libempathy-gtk/empathy-avatar-image.c:
* libempathy-gtk/empathy-avatar-image.h:
* libempathy-gtk/Makefile.am:
* src/empathy.c: Implement EmpathyAvatarChooser and EmpathyAvatarImage
and make use of them in contact information windows. That means we can
now enlarge avatars when clicking on it and we can set our own avatar if
we edit our own contact.

svn path=/trunk/; revision=363

ChangeLog
libempathy-gtk/Makefile.am
libempathy-gtk/empathy-avatar-chooser.c [new file with mode: 0644]
libempathy-gtk/empathy-avatar-chooser.h [new file with mode: 0644]
libempathy-gtk/empathy-avatar-image.c [new file with mode: 0644]
libempathy-gtk/empathy-avatar-image.h [new file with mode: 0644]
libempathy-gtk/empathy-contact-widget.c
libempathy-gtk/empathy-contact-widget.h
libempathy-gtk/empathy-ui-utils.c
libempathy-gtk/empathy-ui-utils.h
src/empathy.c

index ab876c0c1bfc65a0d5fadc46e42bc45616fca7a5..317a5ff5fadaa776ce4df77b313391c1cf6dff9e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2007-10-08  Xavier Claessens  <xclaesse@gmail.com>
+
+       * libempathy-gtk/empathy-ui-utils.c:
+       * libempathy-gtk/empathy-ui-utils.h:
+       * libempathy-gtk/empathy-contact-widget.c:
+       * libempathy-gtk/empathy-contact-widget.h:
+       * libempathy-gtk/empathy-avatar-chooser.c:
+       * libempathy-gtk/empathy-avatar-chooser.h:
+       * libempathy-gtk/empathy-avatar-image.c:
+       * libempathy-gtk/empathy-avatar-image.h:
+       * libempathy-gtk/Makefile.am:
+       * src/empathy.c: Implement EmpathyAvatarChooser and EmpathyAvatarImage
+       and make use of them in contact information windows. That means we can
+       now enlarge avatars when clicking on it and we can set our own avatar if
+       we edit our own contact.
+
 2007-10-03  Marco Barisione  <marco@barisione.org>
 
        * libempathy/empathy-contact-factory.c:
index fa13e27ccc420a658409bbd3d1a127954daba9a7..71ec03bcd35e07362cc03dabc490c8b51bec18dc 100644 (file)
@@ -12,7 +12,7 @@ BUILT_SOURCES =                                       \
 lib_LTLIBRARIES = libempathy-gtk.la
 
 libempathy_gtk_la_SOURCES =                    \
-       ephy-spinner.c  ephy-spinner.h          \
+       ephy-spinner.c ephy-spinner.h           \
        empathy-main-window.c                   \
        empathy-status-icon.c                   \
        empathy-contact-widget.c                \
@@ -48,6 +48,8 @@ libempathy_gtk_la_SOURCES =                   \
        empathy-chatrooms-window.c              \
        empathy-log-window.c                    \
        empathy-call-window.c                   \
+       empathy-avatar-chooser.c                \
+       empathy-avatar-image.c                  \
        empathy-ui-utils.c
 
 # do not distribute generated files
@@ -98,6 +100,8 @@ libempathy_gtk_headers =                     \
        empathy-chatrooms-window.h              \
        empathy-log-window.h                    \
        empathy-call-window.h                   \
+       empathy-avatar-chooser.h                \
+       empathy-avatar-image.h                  \
        empathy-ui-utils.h
 
 libempathy_gtk_includedir = $(includedir)/libempathy-gtk/
diff --git a/libempathy-gtk/empathy-avatar-chooser.c b/libempathy-gtk/empathy-avatar-chooser.c
new file mode 100644 (file)
index 0000000..2ef3de4
--- /dev/null
@@ -0,0 +1,572 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2006-2007 Imendio AB.
+ * Copyright (C) 2007 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Based on Novell's e-image-chooser.
+ *          Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <libgnomevfs/gnome-vfs-ops.h>
+
+#include <libempathy/empathy-debug.h>
+#include <libempathy/empathy-conf.h>
+
+#include "empathy-avatar-chooser.h"
+#include "empathy-preferences.h"
+#include "empathy-ui-utils.h"
+
+#define DEBUG_DOMAIN "AvatarChooser"
+
+#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_AVATAR_CHOOSER_TYPE, EmpathyAvatarChooserPriv))
+
+#define AVATAR_MAX 96
+#define DEFAULT_DIR DATADIR"/pixmaps/faces"
+
+typedef struct {
+       GdkPixbuf *pixbuf;
+       gchar     *image_data;
+       gsize      image_data_size;
+} EmpathyAvatarChooserPriv;
+
+static void       avatar_chooser_finalize              (GObject              *object);
+static void       avatar_chooser_set_image_from_data   (EmpathyAvatarChooser *chooser,
+                                                       gchar                *data,
+                                                       gsize                 size);
+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
+};
+
+static guint signals [LAST_SIGNAL];
+
+G_DEFINE_TYPE (EmpathyAvatarChooser, empathy_avatar_chooser, GTK_TYPE_BUTTON);
+
+/*
+ * Drag and drop stuff
+ */
+#define URI_LIST_TYPE "text/uri-list"
+
+enum DndTargetType {
+       DND_TARGET_TYPE_URI_LIST
+};
+
+static const GtkTargetEntry drop_types[] = {
+       { URI_LIST_TYPE, 0, DND_TARGET_TYPE_URI_LIST },
+};
+
+static void
+empathy_avatar_chooser_class_init (EmpathyAvatarChooserClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+       object_class->finalize = avatar_chooser_finalize;
+
+       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);
+
+       g_type_class_add_private (object_class, sizeof (EmpathyAvatarChooserPriv));
+}
+
+static void
+empathy_avatar_chooser_init (EmpathyAvatarChooser *chooser)
+{
+       EmpathyAvatarChooserPriv *priv;
+
+       priv = GET_PRIV (chooser);
+
+       gtk_drag_dest_set (GTK_WIDGET (chooser),
+                          GTK_DEST_DEFAULT_ALL,
+                          drop_types,
+                          G_N_ELEMENTS (drop_types),
+                          GDK_ACTION_COPY);
+
+       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);
+}
+
+static void
+avatar_chooser_finalize (GObject *object)
+{
+       EmpathyAvatarChooserPriv *priv;
+
+       priv = GET_PRIV (object);
+
+       if (priv->pixbuf) {
+               g_object_unref (priv->pixbuf);
+       }
+       g_free (priv->image_data);
+
+       G_OBJECT_CLASS (empathy_avatar_chooser_parent_class)->finalize (object);
+}
+
+static void
+avatar_chooser_set_pixbuf (EmpathyAvatarChooser *chooser,
+                          GdkPixbuf            *pixbuf)
+{
+       EmpathyAvatarChooserPriv *priv = GET_PRIV (chooser);
+       GtkWidget                *image;
+       GError                   *error = NULL;
+
+       if (priv->pixbuf) {
+               g_object_unref (priv->pixbuf);
+               priv->pixbuf = NULL;
+       }
+       g_free (priv->image_data);
+       priv->image_data = NULL;
+       priv->image_data_size = 0;
+
+       if (pixbuf) {
+               priv->pixbuf = empathy_pixbuf_scale_down_if_necessary (pixbuf, AVATAR_MAX);
+       }
+
+       if (priv->pixbuf) {
+               if (!gdk_pixbuf_save_to_buffer (priv->pixbuf,
+                                               &priv->image_data,
+                                               &priv->image_data_size,
+                                               "png",
+                                               &error, NULL)) {
+                       empathy_debug (DEBUG_DOMAIN, "Failed to save pixbuf: %s",
+                                      error ? error->message : "No error given");
+                       g_clear_error (&error);
+                       g_object_unref (priv->pixbuf);
+                       priv->pixbuf = NULL;
+               }
+       }
+
+       if (!priv->pixbuf) {
+               image = gtk_image_new_from_icon_name ("stock_person",
+                                                     GTK_ICON_SIZE_DIALOG);
+       } else {
+               image = gtk_image_new_from_pixbuf (priv->pixbuf);
+       }
+
+       gtk_button_set_image (GTK_BUTTON (chooser), image);
+       g_signal_emit (chooser, signals[CHANGED], 0);
+}
+
+static void
+avatar_chooser_set_image_from_file (EmpathyAvatarChooser *chooser,
+                                   const gchar          *filename)
+{
+       GdkPixbuf *pixbuf;
+       GError    *error = NULL;
+
+       if (!(pixbuf = gdk_pixbuf_new_from_file (filename, &error))) {
+               empathy_debug (DEBUG_DOMAIN, "Failed to load pixbuf from file: %s",
+                              error ? error->message : "No error given");
+               g_clear_error (&error);
+       }
+
+       avatar_chooser_set_pixbuf (chooser, pixbuf);
+       if (pixbuf) {
+               g_object_unref (pixbuf);
+       }
+}
+
+static void
+avatar_chooser_set_image_from_data (EmpathyAvatarChooser *chooser,
+                                   gchar                *data,
+                                   gsize                 size)
+{
+       GdkPixbuf *pixbuf;
+
+       pixbuf = empathy_pixbuf_from_data (data, size);
+       avatar_chooser_set_pixbuf (chooser, pixbuf);
+       if (pixbuf) {
+               g_object_unref (pixbuf);
+       }
+}
+
+static gboolean
+avatar_chooser_drag_motion_cb (GtkWidget          *widget,
+                             GdkDragContext     *context,
+                             gint                x,
+                             gint                y,
+                             guint               time,
+                             EmpathyAvatarChooser *chooser)
+{
+       EmpathyAvatarChooserPriv *priv;
+       GList                  *p;
+
+       priv = GET_PRIV (chooser);
+
+       for (p = context->targets; 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;
+}
+
+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)
+{
+       EmpathyAvatarChooserPriv *priv;
+       GList                  *p;
+
+       priv = GET_PRIV (chooser);
+
+       if (context->targets == NULL) {
+               return FALSE;
+       }
+
+       for (p = context->targets; p != NULL; p = p->next) {
+               char *possible_type;
+
+               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);
+
+                       return TRUE;
+               }
+
+               g_free (possible_type);
+       }
+
+       return FALSE;
+}
+
+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 (selection_data->target);
+       if (!strcmp (target_type, URI_LIST_TYPE)) {
+               GnomeVFSHandle   *handle = NULL;
+               GnomeVFSResult    result;
+               GnomeVFSFileInfo  info;
+               gchar            *uri;
+               gchar            *nl;
+               gchar            *data = NULL;
+
+               nl = strstr (selection_data->data, "\r\n");
+               if (nl) {
+                       uri = g_strndup (selection_data->data,
+                                        nl - (gchar*) selection_data->data);
+               } else {
+                       uri = g_strdup (selection_data->data);
+               }
+
+               result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
+               if (result == GNOME_VFS_OK) {
+                       result = gnome_vfs_get_file_info_from_handle (handle,
+                                                                     &info,
+                                                                     GNOME_VFS_FILE_INFO_DEFAULT);
+                       if (result == GNOME_VFS_OK) {
+                               GnomeVFSFileSize data_size;
+
+                               data = g_malloc (info.size);
+
+                               result = gnome_vfs_read (handle, data, info.size, &data_size);
+                               if (result == GNOME_VFS_OK) {
+                                       avatar_chooser_set_image_from_data (chooser,
+                                                                           data,
+                                                                           data_size);
+                                       handled = TRUE;
+                               } else {
+                                       g_free (data);
+                               }
+                       }
+
+                       gnome_vfs_close (handle);
+               }
+
+               g_free (uri);
+       }
+
+       gtk_drag_finish (context, handled, FALSE, time);
+}
+
+static void
+avatar_chooser_update_preview_cb (GtkFileChooser       *file_chooser,
+                                 EmpathyAvatarChooser *chooser)
+{
+       gchar *filename;
+
+       filename = gtk_file_chooser_get_preview_filename (file_chooser);
+
+       if (filename) {
+               GtkWidget *image;
+               GdkPixbuf *pixbuf = NULL;
+               GdkPixbuf *scaled_pixbuf;
+
+               pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
+
+               image = gtk_file_chooser_get_preview_widget (file_chooser);
+
+               if (pixbuf) {
+                       scaled_pixbuf = empathy_pixbuf_scale_down_if_necessary (pixbuf, AVATAR_MAX);
+                       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);
+               }
+       }
+
+       gtk_file_chooser_set_preview_widget_active (file_chooser, TRUE);
+}
+
+static void
+avatar_chooser_response_cb (GtkWidget            *widget,
+                           gint                  response,
+                           EmpathyAvatarChooser *chooser)
+{
+       if (response == GTK_RESPONSE_OK) {
+               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) {
+                       empathy_conf_set_string (empathy_conf_get (),
+                                                EMPATHY_PREFS_UI_AVATAR_DIRECTORY,
+                                                path);
+                       g_free (path);
+               }
+       }
+       else if (response == GTK_RESPONSE_NO) {
+               avatar_chooser_set_image_from_data (chooser, NULL, 0);
+       }
+
+       gtk_widget_destroy (widget);
+}
+
+static void
+avatar_chooser_clicked_cb (GtkWidget            *button,
+                          EmpathyAvatarChooser *chooser)
+{
+       GtkFileChooser *chooser_dialog;
+       GtkWidget      *image;
+       gchar          *saved_dir = NULL;
+       const gchar    *default_dir = DEFAULT_DIR;
+       const gchar    *pics_dir;
+       GtkFileFilter  *filter;
+
+       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,
+                                            _("No Image"),
+                                            GTK_RESPONSE_NO,
+                                            GTK_STOCK_CANCEL,
+                                            GTK_RESPONSE_CANCEL,
+                                            GTK_STOCK_OPEN,
+                                            GTK_RESPONSE_OK,
+                                            NULL));
+
+       /* Get special dirs */
+       empathy_conf_get_string (empathy_conf_get (),
+                                EMPATHY_PREFS_UI_AVATAR_DIRECTORY,
+                                &saved_dir);
+       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_MAX, AVATAR_MAX);
+       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), GTK_RESPONSE_OK);
+       g_signal_connect (chooser_dialog, "response",
+                         G_CALLBACK (avatar_chooser_response_cb),
+                         chooser);
+
+       gtk_widget_show (GTK_WIDGET (chooser_dialog));
+       g_free (saved_dir);
+}
+
+GtkWidget *
+empathy_avatar_chooser_new (void)
+{
+       return g_object_new (EMPATHY_AVATAR_CHOOSER_TYPE, NULL);
+}
+
+void
+empathy_avatar_chooser_set (EmpathyAvatarChooser *chooser,
+                           EmpathyAvatar        *avatar)
+{
+       g_return_if_fail (EMPATHY_IS_AVATAR_CHOOSER (chooser));
+
+       avatar_chooser_set_image_from_data (chooser,
+                                           avatar ? avatar->data : NULL,
+                                           avatar ? avatar->len : 0);
+}
+
+void
+empathy_avatar_chooser_get_image_data (EmpathyAvatarChooser  *chooser,
+                                      gchar                **data,
+                                      gsize                 *data_size)
+{
+       EmpathyAvatarChooserPriv *priv;
+
+       g_return_if_fail (EMPATHY_IS_AVATAR_CHOOSER (chooser));
+
+       priv = GET_PRIV (chooser);
+
+       if (data) {
+               *data = priv->image_data;
+       }
+       if (*data_size) {
+               *data_size = priv->image_data_size;
+       }
+}
+
diff --git a/libempathy-gtk/empathy-avatar-chooser.h b/libempathy-gtk/empathy-avatar-chooser.h
new file mode 100644 (file)
index 0000000..b0c08df
--- /dev/null
@@ -0,0 +1,59 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2006-2007 Imendio AB.
+ * Copyright (C) 2007 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Based on Novell's e-image-chooser.
+ *          Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#ifndef __EMPATHY_AVATAR_CHOOSER_H__
+#define __EMPATHY_AVATAR_CHOOSER_H__
+
+#include <gtk/gtkbutton.h>
+
+#include <libempathy/empathy-avatar.h>
+
+G_BEGIN_DECLS
+
+#define EMPATHY_AVATAR_CHOOSER_TYPE           (empathy_avatar_chooser_get_type ())
+#define EMPATHY_AVATAR_CHOOSER(obj)           (G_TYPE_CHECK_INSTANCE_CAST ((obj), EMPATHY_AVATAR_CHOOSER_TYPE, EmpathyAvatarChooser))
+#define EMPATHY_AVATAR_CHOOSER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), EMPATHY_AVATAR_CHOOSER_TYPE, EmpathyAvatarChooserClass))
+#define EMPATHY_IS_AVATAR_CHOOSER(obj)        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EMPATHY_AVATAR_CHOOSER_TYPE))
+#define EMPATHY_IS_AVATAR_CHOOSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), EMPATHY_AVATAR_CHOOSER_TYPE))
+
+typedef struct _EmpathyAvatarChooser        EmpathyAvatarChooser;
+typedef struct _EmpathyAvatarChooserClass   EmpathyAvatarChooserClass;
+typedef struct _EmpathyAvatarChooserPrivate EmpathyAvatarChooserPrivate;
+
+struct _EmpathyAvatarChooser {
+       GtkButton parent;
+};
+
+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,
+                                                 gchar               **data,
+                                                 gsize                *data_size);
+
+#endif /* __EMPATHY_AVATAR_CHOOSER_H__ */
diff --git a/libempathy-gtk/empathy-avatar-image.c b/libempathy-gtk/empathy-avatar-image.c
new file mode 100644 (file)
index 0000000..cc4ecbf
--- /dev/null
@@ -0,0 +1,306 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2006-2007 Imendio AB
+ * Copyright (C) 2007 Collabora Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+#include <gdk/gdkkeysyms.h>
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+
+#include <libempathy/empathy-debug.h>
+
+#include "empathy-avatar-image.h"
+#include "empathy-ui-utils.h"
+
+#define DEBUG_DOMAIN "AvatarImage"
+
+#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_AVATAR_IMAGE, EmpathyAvatarImagePriv))
+
+#define MAX_SMALL  48
+#define MAX_LARGE 400
+
+typedef struct {
+       GtkWidget   *image;
+       GtkWidget   *popup;
+       GdkPixbuf   *pixbuf;
+} EmpathyAvatarImagePriv;
+
+static void     avatar_image_finalize                (GObject           *object);
+static void     avatar_image_add_filter              (EmpathyAvatarImage *avatar_image);
+static void     avatar_image_remove_filter           (EmpathyAvatarImage *avatar_image);
+static gboolean avatar_image_button_press_event      (GtkWidget         *widget,
+                                                     GdkEventButton    *event);
+static gboolean avatar_image_button_release_event    (GtkWidget         *widget,
+                                                     GdkEventButton    *event);
+
+G_DEFINE_TYPE (EmpathyAvatarImage, empathy_avatar_image, GTK_TYPE_EVENT_BOX);
+
+static void
+empathy_avatar_image_class_init (EmpathyAvatarImageClass *klass)
+{
+       GObjectClass   *object_class;
+       GtkWidgetClass *widget_class;
+
+       object_class = G_OBJECT_CLASS (klass);
+       widget_class = GTK_WIDGET_CLASS (klass);
+
+       object_class->finalize = avatar_image_finalize;
+
+       widget_class->button_press_event   = avatar_image_button_press_event;
+       widget_class->button_release_event = avatar_image_button_release_event;
+
+       g_type_class_add_private (object_class, sizeof (EmpathyAvatarImagePriv));
+}
+
+static void
+empathy_avatar_image_init (EmpathyAvatarImage *avatar_image)
+{
+       EmpathyAvatarImagePriv *priv;
+
+       priv = GET_PRIV (avatar_image);
+
+       priv->image = gtk_image_new ();
+       gtk_container_add (GTK_CONTAINER (avatar_image), priv->image);
+       empathy_avatar_image_set (avatar_image, NULL);
+       gtk_widget_show (priv->image);
+
+       avatar_image_add_filter (avatar_image);
+}
+
+static void
+avatar_image_finalize (GObject *object)
+{
+       EmpathyAvatarImagePriv *priv;
+
+       priv = GET_PRIV (object);
+
+       avatar_image_remove_filter (EMPATHY_AVATAR_IMAGE (object));
+
+       if (priv->popup) {
+               gtk_widget_destroy (priv->popup);
+       }
+
+       if (priv->pixbuf) {
+               g_object_unref (priv->pixbuf);
+       }
+
+       G_OBJECT_CLASS (empathy_avatar_image_parent_class)->finalize (object);
+}
+
+static GdkFilterReturn
+avatar_image_filter_func (GdkXEvent  *gdkxevent,
+                         GdkEvent   *event,
+                         gpointer    data)
+{
+       XEvent                *xevent = gdkxevent;
+       Atom                   atom;
+       EmpathyAvatarImagePriv *priv;
+
+       priv = GET_PRIV (data);
+
+       switch (xevent->type) {
+       case PropertyNotify:
+               atom = gdk_x11_get_xatom_by_name ("_NET_CURRENT_DESKTOP");
+               if (xevent->xproperty.atom == atom) {
+                       if (priv->popup) {
+                               gtk_widget_destroy (priv->popup);
+                               priv->popup = NULL;
+                       }
+               }
+               break;
+       }
+
+       return GDK_FILTER_CONTINUE;
+}
+
+static void
+avatar_image_add_filter (EmpathyAvatarImage *avatar_image)
+{
+       Window     window;
+       GdkWindow *gdkwindow;
+       gint       mask;
+
+       mask = PropertyChangeMask;
+
+       window = GDK_ROOT_WINDOW ();
+       gdkwindow = gdk_xid_table_lookup (window);
+
+       gdk_error_trap_push ();
+       if (gdkwindow) {
+               XWindowAttributes attrs;
+               XGetWindowAttributes (gdk_display, window, &attrs);
+               mask |= attrs.your_event_mask;
+       }
+
+       XSelectInput (gdk_display, window, mask);
+
+       gdk_error_trap_pop ();
+
+       gdk_window_add_filter (NULL, avatar_image_filter_func, avatar_image);
+}
+
+static void
+avatar_image_remove_filter (EmpathyAvatarImage *avatar_image)
+{
+       gdk_window_remove_filter (NULL, avatar_image_filter_func, avatar_image);
+}
+
+static gboolean
+avatar_image_button_press_event (GtkWidget *widget, GdkEventButton *event)
+{
+       EmpathyAvatarImagePriv *priv;
+       GtkWidget             *popup;
+       GtkWidget             *frame;
+       GtkWidget             *image;
+       gint                   x, y;
+       gint                   popup_width, popup_height;
+       gint                   width, height;
+       GdkPixbuf             *pixbuf;
+
+       priv = GET_PRIV (widget);
+
+       if (priv->popup) {
+               gtk_widget_destroy (priv->popup);
+               priv->popup = NULL;
+       }
+
+       if (event->button != 1 || event->type != GDK_BUTTON_PRESS || !priv->pixbuf) {
+               return FALSE;
+       }
+
+       popup_width = gdk_pixbuf_get_width (priv->pixbuf);
+       popup_height = gdk_pixbuf_get_height (priv->pixbuf);
+
+       width = priv->image->allocation.width;
+       height = priv->image->allocation.height;
+
+       /* Don't show a popup if the popup is smaller then the currently avatar
+        * image.
+        */
+       if (popup_height <= height && popup_width <= width) {
+               return TRUE;
+       }
+
+       pixbuf = empathy_pixbuf_scale_down_if_necessary (priv->pixbuf, MAX_LARGE);
+       popup_width = gdk_pixbuf_get_width (pixbuf);
+       popup_height = gdk_pixbuf_get_height (pixbuf);
+
+       popup = gtk_window_new (GTK_WINDOW_POPUP);
+
+       frame = gtk_frame_new (NULL);
+       gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
+
+       gtk_container_add (GTK_CONTAINER (popup), frame);
+
+       image = gtk_image_new ();
+       gtk_container_add (GTK_CONTAINER (frame), image);
+
+       gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf);
+       g_object_unref (pixbuf);
+
+       gdk_window_get_origin (priv->image->window, &x, &y);
+
+       x = x - (popup_width - width) / 2;
+       y = y - (popup_height - height) / 2;
+
+       gtk_window_move (GTK_WINDOW (popup), x, y);
+
+       priv->popup = popup;
+
+       gtk_widget_show_all (popup);
+
+       return TRUE;
+}
+
+static gboolean
+avatar_image_button_release_event (GtkWidget *widget, GdkEventButton *event)
+{
+       EmpathyAvatarImagePriv *priv;
+
+       priv = GET_PRIV (widget);
+
+       if (event->button != 1 || event->type != GDK_BUTTON_RELEASE) {
+               return FALSE;
+       }
+
+       if (!priv->popup) {
+               return TRUE;
+       }
+
+       gtk_widget_destroy (priv->popup);
+       priv->popup = NULL;
+
+       return TRUE;
+}
+
+GtkWidget *
+empathy_avatar_image_new (void)
+{
+       EmpathyAvatarImage *avatar_image;
+
+       avatar_image = g_object_new (EMPATHY_TYPE_AVATAR_IMAGE, NULL);
+
+       return GTK_WIDGET (avatar_image);
+}
+
+void
+empathy_avatar_image_set (EmpathyAvatarImage *avatar_image,
+                         EmpathyAvatar      *avatar)
+{
+       EmpathyAvatarImagePriv *priv = GET_PRIV (avatar_image);
+       GdkPixbuf              *scaled_pixbuf;
+
+       g_return_if_fail (EMPATHY_IS_AVATAR_IMAGE (avatar_image));
+
+       if (priv->pixbuf) {
+               g_object_unref (priv->pixbuf);
+               priv->pixbuf = NULL;
+       }
+
+       if (avatar) {
+               priv->pixbuf = empathy_pixbuf_from_data (avatar->data, avatar->len);
+       }
+
+       if (!priv->pixbuf) {
+               gtk_image_set_from_icon_name (GTK_IMAGE (priv->image),
+                                             "stock_person",
+                                             GTK_ICON_SIZE_DIALOG);
+               return;
+       }
+
+       scaled_pixbuf = empathy_pixbuf_scale_down_if_necessary (priv->pixbuf, MAX_SMALL);
+       gtk_image_set_from_pixbuf (GTK_IMAGE (priv->image), scaled_pixbuf);
+
+       if (scaled_pixbuf != priv->pixbuf) {
+               gtk_widget_set_tooltip_text (GTK_WIDGET (avatar_image),
+                                            _("Click to enlarge"));
+       } else {
+               gtk_widget_set_tooltip_text (GTK_WIDGET (avatar_image),
+                                            NULL);
+       }
+
+       g_object_unref (scaled_pixbuf);
+}
+
diff --git a/libempathy-gtk/empathy-avatar-image.h b/libempathy-gtk/empathy-avatar-image.h
new file mode 100644 (file)
index 0000000..8a28ccb
--- /dev/null
@@ -0,0 +1,58 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2006-2007 Imendio AB
+ * Copyright (C) 2007 Collabora Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#ifndef __EMPATHY_AVATAR_IMAGE_H__
+#define __EMPATHY_AVATAR_IMAGE_H__
+
+#include <gtk/gtkeventbox.h>
+
+#include <libempathy/empathy-avatar.h>
+
+G_BEGIN_DECLS
+
+#define EMPATHY_TYPE_AVATAR_IMAGE         (empathy_avatar_image_get_type ())
+#define EMPATHY_AVATAR_IMAGE(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_AVATAR_IMAGE, EmpathyAvatarImage))
+#define EMPATHY_AVATAR_IMAGE_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), EMPATHY_TYPE_AVATAR_IMAGE, EmpathyAvatarImageClass))
+#define EMPATHY_IS_AVATAR_IMAGE(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_AVATAR_IMAGE))
+#define EMPATHY_IS_AVATAR_IMAGE_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_AVATAR_IMAGE))
+#define EMPATHY_AVATAR_IMAGE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_AVATAR_IMAGE, EmpathyAvatarImageClass))
+
+typedef struct _EmpathyAvatarImage      EmpathyAvatarImage;
+typedef struct _EmpathyAvatarImageClass EmpathyAvatarImageClass;
+
+struct _EmpathyAvatarImage {
+       GtkEventBox parent;
+};
+
+struct _EmpathyAvatarImageClass {
+       GtkEventBoxClass parent_class;
+};
+
+GType       empathy_avatar_image_get_type (void) G_GNUC_CONST;
+GtkWidget * empathy_avatar_image_new      (void);
+void        empathy_avatar_image_set      (EmpathyAvatarImage *avatar_image,
+                                          EmpathyAvatar      *avatar);
+
+G_END_DECLS
+
+#endif /* __EMPATHY_AVATAR_IMAGE_H__ */
index b3081b13098d065668751d9d48ef1e20ee4e1e85..b6fd4937dc1eb72e65549954c17032e5fe593748 100644 (file)
@@ -38,6 +38,8 @@
 
 #include "empathy-contact-widget.h"
 #include "empathy-account-chooser.h"
+#include "empathy-avatar-chooser.h"
+#include "empathy-avatar-image.h"
 #include "empathy-ui-utils.h"
 
 /* Delay before updating the widget when the id entry changed (ms) */
@@ -47,7 +49,6 @@ typedef struct {
        EmpathyContactFactory    *factory;
        EmpathyContactManager    *manager;
        EmpathyContact           *contact;
-       gboolean                  is_user;
        EmpathyContactWidgetType  type;
        GtkCellRenderer          *renderer;
        guint                     widget_id_timeout;
@@ -100,6 +101,8 @@ static void     contact_widget_set_contact                (EmpathyContactWidget
 static void     contact_widget_contact_setup              (EmpathyContactWidget  *information);
 static void     contact_widget_contact_update             (EmpathyContactWidget  *information);
 static gboolean contact_widget_update_contact             (EmpathyContactWidget  *information);
+static void     contact_widget_avatar_changed_cb          (EmpathyAvatarChooser  *chooser,
+                                                          EmpathyContactWidget  *information);
 static void     contact_widget_account_changed_cb         (GtkComboBox           *widget,
                                                           EmpathyContactWidget  *information);
 static gboolean contact_widget_id_focus_out_cb            (GtkWidget             *widget,
@@ -153,13 +156,11 @@ empathy_contact_widget_new (EmpathyContact           *contact,
        GladeXML             *glade;
 
        information = g_slice_new0 (EmpathyContactWidget);
+       if (type == CONTACT_WIDGET_TYPE_EDIT && empathy_contact_is_user (contact)) {
+               type = CONTACT_WIDGET_TYPE_EDIT_USER;
+       }
        information->type = type;
        information->factory = empathy_contact_factory_new ();
-       if (contact) {
-               information->is_user = empathy_contact_is_user (contact);
-       } else {
-               information->is_user = FALSE;
-       }
 
        glade = empathy_glade_get_file ("empathy-contact-widget.glade",
                                       "vbox_contact_widget",
@@ -339,12 +340,19 @@ contact_widget_id_changed_cb (GtkEntry             *entry,
 static void
 contact_widget_contact_setup (EmpathyContactWidget *information)
 {
-       /* FIXME: Use EmpathyAvatarImage if (editable && is_user)  */
-       information->widget_avatar = gtk_image_new ();
+       if (information->type == CONTACT_WIDGET_TYPE_EDIT_USER) {
+               information->widget_avatar = empathy_avatar_chooser_new ();
+               g_signal_connect (information->widget_avatar, "changed",
+                                 G_CALLBACK (contact_widget_avatar_changed_cb),
+                                 information);
+       } else {
+               information->widget_avatar = empathy_avatar_image_new ();
+       }
        gtk_box_pack_end (GTK_BOX (information->hbox_contact),
                          information->widget_avatar,
                          FALSE, FALSE,
                          6);
+       gtk_widget_show (information->widget_avatar);
 
        /* Setup account label/chooser */
        if (information->type == CONTACT_WIDGET_TYPE_ADD) {
@@ -459,6 +467,7 @@ contact_widget_contact_update (EmpathyContactWidget *information)
                gtk_widget_show (information->label_alias);
                gtk_widget_show (information->widget_alias);
                gtk_widget_show (information->hbox_presence);
+               gtk_widget_show (information->widget_avatar);
        } else {
                gtk_widget_hide (information->label_alias);
                gtk_widget_hide (information->widget_alias);
@@ -491,6 +500,20 @@ contact_widget_update_contact (EmpathyContactWidget *information)
        return FALSE;
 }
 
+static void
+contact_widget_avatar_changed_cb (EmpathyAvatarChooser *chooser,
+                                 EmpathyContactWidget *information)
+{
+       McAccount *account;
+       gchar     *data;
+       gsize      size;
+
+       account = empathy_contact_get_account (information->contact);
+       empathy_avatar_chooser_get_image_data (EMPATHY_AVATAR_CHOOSER (information->widget_avatar),
+                                              &data, &size);
+       mc_account_set_avatar_from_data (account, data, size, "png");
+}
+
 static void
 contact_widget_account_changed_cb (GtkComboBox          *widget,
                                   EmpathyContactWidget *information)
@@ -550,18 +573,23 @@ contact_widget_presence_notify_cb (EmpathyContactWidget *information)
 static void
 contact_widget_avatar_notify_cb (EmpathyContactWidget *information)
 {
-       GdkPixbuf *avatar_pixbuf;
-
-       avatar_pixbuf = empathy_pixbuf_avatar_from_contact_scaled (information->contact,
-                                                                 48, 48);
+       EmpathyAvatar *avatar = NULL;
 
-       if (avatar_pixbuf) {
-               gtk_image_set_from_pixbuf (GTK_IMAGE (information->widget_avatar),
-                                          avatar_pixbuf);
-               gtk_widget_show  (information->widget_avatar);
-               g_object_unref (avatar_pixbuf);
+       if (information->contact) {
+               avatar = empathy_contact_get_avatar (information->contact);
+       }
+       if (information->type == CONTACT_WIDGET_TYPE_EDIT_USER) {
+               g_signal_handlers_block_by_func (information->widget_avatar,
+                                                contact_widget_avatar_changed_cb,
+                                                information);
+               empathy_avatar_chooser_set (EMPATHY_AVATAR_CHOOSER (information->widget_avatar),
+                                           avatar);
+               g_signal_handlers_unblock_by_func (information->widget_avatar,
+                                                  contact_widget_avatar_changed_cb,
+                                                  information);
        } else {
-               gtk_widget_hide  (information->widget_avatar);
+               empathy_avatar_image_set (EMPATHY_AVATAR_IMAGE (information->widget_avatar),
+                                         avatar);
        }
 }
 
index 119d8a5963445c7b9f45d36a750cf67d0c288bf7..71fc06acb742c8f876dadec53cc9193a3a219f12 100644 (file)
 G_BEGIN_DECLS
 
 typedef enum {
-       CONTACT_WIDGET_TYPE_SHOW, /* used to show contact information */
-       CONTACT_WIDGET_TYPE_EDIT, /* used to edit contact information */
-       CONTACT_WIDGET_TYPE_ADD,  /* used to add a new contact */
-       CONTACT_WIDGET_TYPE_SUBSCRIPTION /* used to accepte/reject a new contact */
+       CONTACT_WIDGET_TYPE_SHOW,         /* used to show contact information */
+       CONTACT_WIDGET_TYPE_EDIT,         /* used to edit contact information */
+       CONTACT_WIDGET_TYPE_ADD,          /* used to add a new contact */
+       CONTACT_WIDGET_TYPE_SUBSCRIPTION, /* used to accepte/reject a new contact */
+       CONTACT_WIDGET_TYPE_EDIT_USER     /* used to edit our own information */
 } EmpathyContactWidgetType;
 
 GtkWidget *     empathy_contact_widget_new         (EmpathyContact           *contact,
index 1c2d79c7b62560c62fb4467d9d1df60cd861361d..fe032c9ee72f22840f33ac383f65f9fef1c209f1 100644 (file)
@@ -201,35 +201,6 @@ empathy_glade_setup_size_group (GladeXML         *gui,
        va_end (args);
 }
 
-GdkPixbuf *
-empathy_pixbuf_from_icon_name (const gchar *icon_name,
-                             GtkIconSize  icon_size)
-{
-       GtkIconTheme  *theme;
-       GdkPixbuf     *pixbuf = NULL;
-       GError        *error = NULL;
-       gint           w, h;
-       gint           size = 48;
-
-       theme = gtk_icon_theme_get_default ();
-
-       if (gtk_icon_size_lookup (icon_size, &w, &h)) {
-               size = (w + h) / 2;
-       }
-
-       pixbuf = gtk_icon_theme_load_icon (theme,
-                                          icon_name,
-                                          size,
-                                          0,
-                                          &error);
-       if (error) {
-               empathy_debug (DEBUG_DOMAIN, "Error loading icon: %s", error->message);
-               g_clear_error (&error);
-       }
-
-       return pixbuf;
-}
-
 const gchar *
 empathy_icon_name_from_account (McAccount *account)
 {
@@ -293,6 +264,44 @@ empathy_icon_name_for_contact (EmpathyContact *contact)
        return EMPATHY_IMAGE_UNKNOWN;
 }
 
+GdkPixbuf *
+empathy_pixbuf_from_data (gchar *data,
+                         gsize  data_size)
+{
+       GdkPixbufLoader *loader;
+       GdkPixbuf       *pixbuf = NULL;
+       GError          *error = NULL;
+
+       if (!data) {
+               return NULL;
+       }
+
+       loader = gdk_pixbuf_loader_new ();
+       if (!gdk_pixbuf_loader_write (loader, data, data_size, &error)) {
+               empathy_debug (DEBUG_DOMAIN, "Failed to write to pixbuf loader: %s",
+                              error ? error->message : "No error given");
+               g_clear_error (&error);
+               g_object_unref (loader);
+               return NULL;
+       }
+       if (!gdk_pixbuf_loader_close (loader, &error)) {
+               empathy_debug (DEBUG_DOMAIN, "Failed to close pixbuf loader: %s",
+                              error ? error->message : "No error given");
+               g_clear_error (&error);
+               g_object_unref (loader);
+               return NULL;
+       }
+
+       pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
+       if (pixbuf) {
+               g_object_ref (pixbuf);
+       }
+
+       g_object_unref (loader);
+
+       return pixbuf;
+}
+
 static void
 pixbuf_from_avatar_size_prepared_cb (GdkPixbufLoader *loader,
                                     int              width,
@@ -488,6 +497,58 @@ empathy_pixbuf_avatar_from_contact_scaled (EmpathyContact *contact,
        return empathy_pixbuf_from_avatar_scaled (avatar, width, height);
 }
 
+GdkPixbuf *
+empathy_pixbuf_scale_down_if_necessary (GdkPixbuf *pixbuf, gint max_size)
+{
+       gint      width, height;
+       gdouble   factor;
+
+       width = gdk_pixbuf_get_width (pixbuf);
+       height = gdk_pixbuf_get_height (pixbuf);
+
+       if (width > max_size || height > max_size) {
+               factor = (gdouble) max_size / MAX (width, height);
+
+               width = width * factor;
+               height = height * factor;
+
+               return gdk_pixbuf_scale_simple (pixbuf,
+                                               width, height,
+                                               GDK_INTERP_HYPER);
+       }
+
+       return g_object_ref (pixbuf);
+}
+
+GdkPixbuf *
+empathy_pixbuf_from_icon_name (const gchar *icon_name,
+                             GtkIconSize  icon_size)
+{
+       GtkIconTheme  *theme;
+       GdkPixbuf     *pixbuf = NULL;
+       GError        *error = NULL;
+       gint           w, h;
+       gint           size = 48;
+
+       theme = gtk_icon_theme_get_default ();
+
+       if (gtk_icon_size_lookup (icon_size, &w, &h)) {
+               size = (w + h) / 2;
+       }
+
+       pixbuf = gtk_icon_theme_load_icon (theme,
+                                          icon_name,
+                                          size,
+                                          0,
+                                          &error);
+       if (error) {
+               empathy_debug (DEBUG_DOMAIN, "Error loading icon: %s", error->message);
+               g_clear_error (&error);
+       }
+
+       return pixbuf;
+}
+
 /* Stolen from GtkSourceView, hence the weird intendation. Please keep it like
  * that to make it easier to apply changes from the original code.
  */
index 3a8b896cb1cfa49e40e7bf037a0f08bec8f63eb4..eb189545aafc6f425db79c9e861c7ad71dbcd1ba 100644 (file)
@@ -48,63 +48,66 @@ G_BEGIN_DECLS
 #define G_STR_EMPTY(x) ((x) == NULL || (x)[0] == '\0')
 
 /* Glade */
-void            empathy_glade_get_file_simple             (const gchar         *filename,
-                                                         const gchar         *root,
-                                                         const gchar         *domain,
-                                                         const gchar         *first_required_widget,
-                                                         ...);
-GladeXML *      empathy_glade_get_file                    (const gchar         *filename,
-                                                         const gchar         *root,
-                                                         const gchar         *domain,
-                                                         const gchar         *first_required_widget,
-                                                         ...);
-void            empathy_glade_connect                     (GladeXML            *gui,
-                                                         gpointer             user_data,
-                                                         gchar               *first_widget,
-                                                         ...);
-void            empathy_glade_setup_size_group            (GladeXML            *gui,
-                                                         GtkSizeGroupMode     mode,
-                                                         gchar               *first_widget,
-                                                         ...);
+void            empathy_glade_get_file_simple           (const gchar      *filename,
+                                                        const gchar      *root,
+                                                        const gchar      *domain,
+                                                        const gchar      *first_required_widget,
+                                                        ...);
+GladeXML *      empathy_glade_get_file                  (const gchar      *filename,
+                                                        const gchar      *root,
+                                                        const gchar      *domain,
+                                                        const gchar      *first_required_widget,
+                                                        ...);
+void            empathy_glade_connect                   (GladeXML         *gui,
+                                                        gpointer          user_data,
+                                                        gchar            *first_widget,
+                                                        ...);
+void            empathy_glade_setup_size_group          (GladeXML         *gui,
+                                                        GtkSizeGroupMode  mode,
+                                                        gchar            *first_widget,
+                                                        ...);
 /* Pixbufs */
-GdkPixbuf *     empathy_pixbuf_from_icon_name             (const gchar         *icon_name,
-                                                         GtkIconSize          icon_size);
-const gchar *   empathy_icon_name_from_account            (McAccount           *account);
-const gchar *   empathy_icon_name_for_presence_state      (McPresence           state);
-const gchar *   empathy_icon_name_for_presence            (EmpathyPresence      *presence);
-const gchar *   empathy_icon_name_for_contact             (EmpathyContact       *contact);
-GdkPixbuf *     empathy_pixbuf_from_avatar_scaled         (EmpathyAvatar        *avatar,
-                                                         gint                 width,
-                                                         gint                 height);
-GdkPixbuf *     empathy_pixbuf_avatar_from_contact_scaled (EmpathyContact       *contact,
-                                                         gint                 width,
-                                                         gint                 height);
+const gchar * empathy_icon_name_from_account            (McAccount        *account);
+const gchar * empathy_icon_name_for_presence_state      (McPresence        state);
+const gchar * empathy_icon_name_for_presence            (EmpathyPresence  *presence);
+const gchar * empathy_icon_name_for_contact             (EmpathyContact   *contact);
+GdkPixbuf *   empathy_pixbuf_from_data                  (gchar            *data,
+                                                        gsize             data_size);
+GdkPixbuf *   empathy_pixbuf_from_avatar_scaled         (EmpathyAvatar    *avatar,
+                                                        gint              width,
+                                                        gint              height);
+GdkPixbuf *   empathy_pixbuf_avatar_from_contact_scaled (EmpathyContact   *contact,
+                                                        gint              width,
+                                                        gint              height);
+GdkPixbuf * empathy_pixbuf_scale_down_if_necessary      (GdkPixbuf        *pixbuf,
+                                                        gint              max_size);
+GdkPixbuf * empathy_pixbuf_from_icon_name               (const gchar      *icon_name,
+                                                        GtkIconSize       icon_size);
 /* Text view */
-gboolean   empathy_text_iter_forward_search          (const GtkTextIter   *iter,
-                                                    const gchar         *str,
-                                                    GtkTextIter         *match_start,
-                                                    GtkTextIter         *match_end,
-                                                    const GtkTextIter   *limit);
-gboolean   empathy_text_iter_backward_search         (const GtkTextIter   *iter,
-                                                    const gchar         *str,
-                                                    GtkTextIter         *match_start,
-                                                    GtkTextIter         *match_end,
-                                                    const GtkTextIter   *limit);
-
+gboolean    empathy_text_iter_forward_search            (const GtkTextIter*iter,
+                                                        const gchar      *str,
+                                                        GtkTextIter      *match_start,
+                                                        GtkTextIter      *match_end,
+                                                        const GtkTextIter*limit);
+gboolean    empathy_text_iter_backward_search           (const GtkTextIter*iter,
+                                                        const gchar      *str,
+                                                        GtkTextIter      *match_start,
+                                                        GtkTextIter      *match_end,
+                                                        const GtkTextIter*limit);
 /* Windows */
-gboolean   empathy_window_get_is_visible             (GtkWindow           *window);
-void       empathy_window_present                    (GtkWindow           *window,
-                                                    gboolean             steal_focus);
-void       empathy_window_iconify                    (GtkWindow           *window,
-                                                     GtkStatusIcon       *status_icon);
-GtkWindow *empathy_get_toplevel_window               (GtkWidget           *widget);
-void       empathy_url_show                          (const char          *url);
-void       empathy_toggle_button_set_state_quietly   (GtkWidget           *widget,
-                                                    GCallback            callback,
-                                                    gpointer             user_data,
-                                                    gboolean             active);
-GtkWidget *empathy_link_button_new                   (const gchar         *url,
-                                                    const gchar         *title);
+gboolean    empathy_window_get_is_visible               (GtkWindow        *window);
+void        empathy_window_present                      (GtkWindow        *window,
+                                                        gboolean          steal_focus);
+void        empathy_window_iconify                      (GtkWindow        *window,
+                                                        GtkStatusIcon    *status_icon);
+GtkWindow * empathy_get_toplevel_window                 (GtkWidget        *widget);
+void        empathy_url_show                            (const char       *url);
+void        empathy_toggle_button_set_state_quietly     (GtkWidget        *widget,
+                                                        GCallback         callback,
+                                                        gpointer          user_data,
+                                                        gboolean          active);
+GtkWidget *empathy_link_button_new                      (const gchar      *url,
+                                                        const gchar      *title);
 
 
 G_END_DECLS
index a1c521369c6c7e7c4ea95da4ff9a4d5ad30d817d..6e1abb1186cdf00d7e026d2a03a82c6930292694 100644 (file)
@@ -29,6 +29,7 @@
 #include <gtk/gtk.h>
 
 #include <libebook/e-book.h>
+#include <libgnomevfs/gnome-vfs.h>
 
 #include <libtelepathy/tp-conn.h>
 #include <libtelepathy/tp-chan.h>
@@ -288,6 +289,7 @@ main (int argc, char *argv[])
        gtk_window_set_default_icon_name ("empathy");
        gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (),
                                           DATADIR G_DIR_SEPARATOR_S "empathy");
+       gnome_vfs_init ();
 
        /* Setting up MC */
        monitor = mc_account_monitor_new ();