aboutsummaryrefslogtreecommitdiffstats
path: root/libempathy-gtk/empathy-avatar-chooser.c
diff options
context:
space:
mode:
Diffstat (limited to 'libempathy-gtk/empathy-avatar-chooser.c')
-rw-r--r--libempathy-gtk/empathy-avatar-chooser.c572
1 files changed, 572 insertions, 0 deletions
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;
+ }
+}
+