aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog16
-rw-r--r--libempathy-gtk/Makefile.am6
-rw-r--r--libempathy-gtk/empathy-avatar-chooser.c572
-rw-r--r--libempathy-gtk/empathy-avatar-chooser.h59
-rw-r--r--libempathy-gtk/empathy-avatar-image.c306
-rw-r--r--libempathy-gtk/empathy-avatar-image.h58
-rw-r--r--libempathy-gtk/empathy-contact-widget.c64
-rw-r--r--libempathy-gtk/empathy-contact-widget.h9
-rw-r--r--libempathy-gtk/empathy-ui-utils.c119
-rw-r--r--libempathy-gtk/empathy-ui-utils.h111
-rw-r--r--src/empathy.c2
11 files changed, 1216 insertions, 106 deletions
diff --git a/ChangeLog b/ChangeLog
index ab876c0c1..317a5ff5f 100644
--- 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:
diff --git a/libempathy-gtk/Makefile.am b/libempathy-gtk/Makefile.am
index fa13e27cc..71ec03bcd 100644
--- a/libempathy-gtk/Makefile.am
+++ b/libempathy-gtk/Makefile.am
@@ -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
index 000000000..2ef3de429
--- /dev/null
+++ b/libempathy-gtk/empathy-avatar-chooser.c
@@ -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
index 000000000..b0c08df11
--- /dev/null
+++ b/libempathy-gtk/empathy-avatar-chooser.h
@@ -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
index 000000000..cc4ecbf45
--- /dev/null
+++ b/libempathy-gtk/empathy-avatar-image.c
@@ -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
index 000000000..8a28ccb9a
--- /dev/null
+++ b/libempathy-gtk/empathy-avatar-image.h
@@ -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__ */
diff --git a/libempathy-gtk/empathy-contact-widget.c b/libempathy-gtk/empathy-contact-widget.c
index b3081b130..b6fd4937d 100644
--- a/libempathy-gtk/empathy-contact-widget.c
+++ b/libempathy-gtk/empathy-contact-widget.c
@@ -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);
@@ -492,6 +501,20 @@ contact_widget_update_contact (EmpathyContactWidget *information)
}
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);
}
}
diff --git a/libempathy-gtk/empathy-contact-widget.h b/libempathy-gtk/empathy-contact-widget.h
index 119d8a596..71fc06acb 100644
--- a/libempathy-gtk/empathy-contact-widget.h
+++ b/libempathy-gtk/empathy-contact-widget.h
@@ -30,10 +30,11 @@
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,
diff --git a/libempathy-gtk/empathy-ui-utils.c b/libempathy-gtk/empathy-ui-utils.c
index 1c2d79c7b..fe032c9ee 100644
--- a/libempathy-gtk/empathy-ui-utils.c
+++ b/libempathy-gtk/empathy-ui-utils.c
@@ -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.
*/
diff --git a/libempathy-gtk/empathy-ui-utils.h b/libempathy-gtk/empathy-ui-utils.h
index 3a8b896cb..eb189545a 100644
--- a/libempathy-gtk/empathy-ui-utils.h
+++ b/libempathy-gtk/empathy-ui-utils.h
@@ -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
diff --git a/src/empathy.c b/src/empathy.c
index a1c521369..6e1abb118 100644
--- a/src/empathy.c
+++ b/src/empathy.c
@@ -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 ();