1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2006-2007 Imendio AB.
4 * Copyright (C) 2007 Collabora Ltd.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
20 * Authors: Based on Novell's e-image-chooser.
21 * Xavier Claessens <xclaesse@gmail.com>
28 #include <glib/gi18n.h>
30 #include <libgnomevfs/gnome-vfs-ops.h>
32 #include <libempathy/empathy-debug.h>
33 #include <libempathy/empathy-conf.h>
35 #include "empathy-avatar-chooser.h"
36 #include "empathy-preferences.h"
37 #include "empathy-ui-utils.h"
39 #define DEBUG_DOMAIN "AvatarChooser"
41 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_AVATAR_CHOOSER_TYPE, EmpathyAvatarChooserPriv))
44 #define DEFAULT_DIR DATADIR"/pixmaps/faces"
49 gsize image_data_size;
50 } EmpathyAvatarChooserPriv;
52 static void avatar_chooser_finalize (GObject *object);
53 static void avatar_chooser_set_image_from_data (EmpathyAvatarChooser *chooser,
56 static gboolean avatar_chooser_drag_motion_cb (GtkWidget *widget,
57 GdkDragContext *context,
61 EmpathyAvatarChooser *chooser);
62 static void avatar_chooser_drag_leave_cb (GtkWidget *widget,
63 GdkDragContext *context,
65 EmpathyAvatarChooser *chooser);
66 static gboolean avatar_chooser_drag_drop_cb (GtkWidget *widget,
67 GdkDragContext *context,
71 EmpathyAvatarChooser *chooser);
72 static void avatar_chooser_drag_data_received_cb (GtkWidget *widget,
73 GdkDragContext *context,
76 GtkSelectionData *selection_data,
79 EmpathyAvatarChooser *chooser);
80 static void avatar_chooser_clicked_cb (GtkWidget *button,
81 EmpathyAvatarChooser *chooser);
88 static guint signals [LAST_SIGNAL];
90 G_DEFINE_TYPE (EmpathyAvatarChooser, empathy_avatar_chooser, GTK_TYPE_BUTTON);
95 #define URI_LIST_TYPE "text/uri-list"
98 DND_TARGET_TYPE_URI_LIST
101 static const GtkTargetEntry drop_types[] = {
102 { URI_LIST_TYPE, 0, DND_TARGET_TYPE_URI_LIST },
106 empathy_avatar_chooser_class_init (EmpathyAvatarChooserClass *klass)
108 GObjectClass *object_class = G_OBJECT_CLASS (klass);
110 object_class->finalize = avatar_chooser_finalize;
113 g_signal_new ("changed",
114 G_TYPE_FROM_CLASS (klass),
118 g_cclosure_marshal_VOID__VOID,
121 g_type_class_add_private (object_class, sizeof (EmpathyAvatarChooserPriv));
125 empathy_avatar_chooser_init (EmpathyAvatarChooser *chooser)
127 EmpathyAvatarChooserPriv *priv;
129 priv = GET_PRIV (chooser);
131 gtk_drag_dest_set (GTK_WIDGET (chooser),
132 GTK_DEST_DEFAULT_ALL,
134 G_N_ELEMENTS (drop_types),
137 g_signal_connect (chooser, "drag-motion",
138 G_CALLBACK (avatar_chooser_drag_motion_cb),
140 g_signal_connect (chooser, "drag-leave",
141 G_CALLBACK (avatar_chooser_drag_leave_cb),
143 g_signal_connect (chooser, "drag-drop",
144 G_CALLBACK (avatar_chooser_drag_drop_cb),
146 g_signal_connect (chooser, "drag-data-received",
147 G_CALLBACK (avatar_chooser_drag_data_received_cb),
149 g_signal_connect (chooser, "clicked",
150 G_CALLBACK (avatar_chooser_clicked_cb),
153 empathy_avatar_chooser_set (chooser, NULL);
157 avatar_chooser_finalize (GObject *object)
159 EmpathyAvatarChooserPriv *priv;
161 priv = GET_PRIV (object);
164 g_object_unref (priv->pixbuf);
166 g_free (priv->image_data);
168 G_OBJECT_CLASS (empathy_avatar_chooser_parent_class)->finalize (object);
172 avatar_chooser_set_pixbuf (EmpathyAvatarChooser *chooser,
175 EmpathyAvatarChooserPriv *priv = GET_PRIV (chooser);
177 GError *error = NULL;
180 g_object_unref (priv->pixbuf);
183 g_free (priv->image_data);
184 priv->image_data = NULL;
185 priv->image_data_size = 0;
188 priv->pixbuf = empathy_pixbuf_scale_down_if_necessary (pixbuf, AVATAR_MAX);
192 if (!gdk_pixbuf_save_to_buffer (priv->pixbuf,
194 &priv->image_data_size,
197 empathy_debug (DEBUG_DOMAIN, "Failed to save pixbuf: %s",
198 error ? error->message : "No error given");
199 g_clear_error (&error);
200 g_object_unref (priv->pixbuf);
206 image = gtk_image_new_from_icon_name ("stock_person",
207 GTK_ICON_SIZE_DIALOG);
209 image = gtk_image_new_from_pixbuf (priv->pixbuf);
212 gtk_button_set_image (GTK_BUTTON (chooser), image);
213 g_signal_emit (chooser, signals[CHANGED], 0);
217 avatar_chooser_set_image_from_file (EmpathyAvatarChooser *chooser,
218 const gchar *filename)
221 GError *error = NULL;
223 if (!(pixbuf = gdk_pixbuf_new_from_file (filename, &error))) {
224 empathy_debug (DEBUG_DOMAIN, "Failed to load pixbuf from file: %s",
225 error ? error->message : "No error given");
226 g_clear_error (&error);
229 avatar_chooser_set_pixbuf (chooser, pixbuf);
231 g_object_unref (pixbuf);
236 avatar_chooser_set_image_from_data (EmpathyAvatarChooser *chooser,
242 pixbuf = empathy_pixbuf_from_data (data, size);
243 avatar_chooser_set_pixbuf (chooser, pixbuf);
245 g_object_unref (pixbuf);
250 avatar_chooser_drag_motion_cb (GtkWidget *widget,
251 GdkDragContext *context,
255 EmpathyAvatarChooser *chooser)
257 EmpathyAvatarChooserPriv *priv;
260 priv = GET_PRIV (chooser);
262 for (p = context->targets; p != NULL; p = p->next) {
263 gchar *possible_type;
265 possible_type = gdk_atom_name (GDK_POINTER_TO_ATOM (p->data));
267 if (!strcmp (possible_type, URI_LIST_TYPE)) {
268 g_free (possible_type);
269 gdk_drag_status (context, GDK_ACTION_COPY, time);
274 g_free (possible_type);
281 avatar_chooser_drag_leave_cb (GtkWidget *widget,
282 GdkDragContext *context,
284 EmpathyAvatarChooser *chooser)
289 avatar_chooser_drag_drop_cb (GtkWidget *widget,
290 GdkDragContext *context,
294 EmpathyAvatarChooser *chooser)
296 EmpathyAvatarChooserPriv *priv;
299 priv = GET_PRIV (chooser);
301 if (context->targets == NULL) {
305 for (p = context->targets; p != NULL; p = p->next) {
308 possible_type = gdk_atom_name (GDK_POINTER_TO_ATOM (p->data));
309 if (!strcmp (possible_type, URI_LIST_TYPE)) {
310 g_free (possible_type);
311 gtk_drag_get_data (widget, context,
312 GDK_POINTER_TO_ATOM (p->data),
318 g_free (possible_type);
325 avatar_chooser_drag_data_received_cb (GtkWidget *widget,
326 GdkDragContext *context,
329 GtkSelectionData *selection_data,
332 EmpathyAvatarChooser *chooser)
335 gboolean handled = FALSE;
337 target_type = gdk_atom_name (selection_data->target);
338 if (!strcmp (target_type, URI_LIST_TYPE)) {
339 GnomeVFSHandle *handle = NULL;
340 GnomeVFSResult result;
341 GnomeVFSFileInfo info;
346 nl = strstr (selection_data->data, "\r\n");
348 uri = g_strndup (selection_data->data,
349 nl - (gchar*) selection_data->data);
351 uri = g_strdup (selection_data->data);
354 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
355 if (result == GNOME_VFS_OK) {
356 result = gnome_vfs_get_file_info_from_handle (handle,
358 GNOME_VFS_FILE_INFO_DEFAULT);
359 if (result == GNOME_VFS_OK) {
360 GnomeVFSFileSize data_size;
362 data = g_malloc (info.size);
364 result = gnome_vfs_read (handle, data, info.size, &data_size);
365 if (result == GNOME_VFS_OK) {
366 avatar_chooser_set_image_from_data (chooser,
375 gnome_vfs_close (handle);
381 gtk_drag_finish (context, handled, FALSE, time);
385 avatar_chooser_update_preview_cb (GtkFileChooser *file_chooser,
386 EmpathyAvatarChooser *chooser)
390 filename = gtk_file_chooser_get_preview_filename (file_chooser);
394 GdkPixbuf *pixbuf = NULL;
395 GdkPixbuf *scaled_pixbuf;
397 pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
399 image = gtk_file_chooser_get_preview_widget (file_chooser);
402 scaled_pixbuf = empathy_pixbuf_scale_down_if_necessary (pixbuf, AVATAR_MAX);
403 gtk_image_set_from_pixbuf (GTK_IMAGE (image), scaled_pixbuf);
404 g_object_unref (scaled_pixbuf);
405 g_object_unref (pixbuf);
407 gtk_image_set_from_stock (GTK_IMAGE (image),
408 "gtk-dialog-question",
409 GTK_ICON_SIZE_DIALOG);
413 gtk_file_chooser_set_preview_widget_active (file_chooser, TRUE);
417 avatar_chooser_response_cb (GtkWidget *widget,
419 EmpathyAvatarChooser *chooser)
421 if (response == GTK_RESPONSE_OK) {
425 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));
426 avatar_chooser_set_image_from_file (chooser, filename);
429 path = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (widget));
431 empathy_conf_set_string (empathy_conf_get (),
432 EMPATHY_PREFS_UI_AVATAR_DIRECTORY,
437 else if (response == GTK_RESPONSE_NO) {
438 avatar_chooser_set_image_from_data (chooser, NULL, 0);
441 gtk_widget_destroy (widget);
445 avatar_chooser_clicked_cb (GtkWidget *button,
446 EmpathyAvatarChooser *chooser)
448 GtkFileChooser *chooser_dialog;
450 gchar *saved_dir = NULL;
451 const gchar *default_dir = DEFAULT_DIR;
452 const gchar *pics_dir;
453 GtkFileFilter *filter;
455 chooser_dialog = GTK_FILE_CHOOSER (
456 gtk_file_chooser_dialog_new (_("Select Your Avatar Image"),
457 empathy_get_toplevel_window (GTK_WIDGET (chooser)),
458 GTK_FILE_CHOOSER_ACTION_OPEN,
467 /* Get special dirs */
468 empathy_conf_get_string (empathy_conf_get (),
469 EMPATHY_PREFS_UI_AVATAR_DIRECTORY,
471 if (saved_dir && !g_file_test (saved_dir, G_FILE_TEST_IS_DIR)) {
475 if (!g_file_test (default_dir, G_FILE_TEST_IS_DIR)) {
478 pics_dir = g_get_user_special_dir (G_USER_DIRECTORY_PICTURES);
479 if (pics_dir && !g_file_test (pics_dir, G_FILE_TEST_IS_DIR)) {
483 /* Set current dir to the last one or to DEFAULT_DIR or to home */
485 gtk_file_chooser_set_current_folder (chooser_dialog, saved_dir);
488 gtk_file_chooser_set_current_folder (chooser_dialog, pics_dir);
490 else if (default_dir) {
491 gtk_file_chooser_set_current_folder (chooser_dialog, default_dir);
493 gtk_file_chooser_set_current_folder (chooser_dialog, g_get_home_dir ());
496 /* Add shortcuts to special dirs */
498 gtk_file_chooser_add_shortcut_folder (chooser_dialog, saved_dir, NULL);
501 gtk_file_chooser_add_shortcut_folder (chooser_dialog, pics_dir, NULL);
504 gtk_file_chooser_add_shortcut_folder (chooser_dialog, default_dir, NULL);
507 /* Setup preview image */
508 image = gtk_image_new ();
509 gtk_file_chooser_set_preview_widget (chooser_dialog, image);
510 gtk_widget_set_size_request (image, AVATAR_MAX, AVATAR_MAX);
511 gtk_widget_show (image);
512 gtk_file_chooser_set_use_preview_label (chooser_dialog, FALSE);
513 g_signal_connect (chooser_dialog, "update-preview",
514 G_CALLBACK (avatar_chooser_update_preview_cb),
518 filter = gtk_file_filter_new ();
519 gtk_file_filter_set_name (filter, _("Images"));
520 gtk_file_filter_add_pixbuf_formats (filter);
521 gtk_file_chooser_add_filter (chooser_dialog, filter);
522 filter = gtk_file_filter_new ();
523 gtk_file_filter_set_name (filter, _("All Files"));
524 gtk_file_filter_add_pattern(filter, "*");
525 gtk_file_chooser_add_filter (chooser_dialog, filter);
528 gtk_dialog_set_default_response (GTK_DIALOG (chooser_dialog), GTK_RESPONSE_OK);
529 g_signal_connect (chooser_dialog, "response",
530 G_CALLBACK (avatar_chooser_response_cb),
533 gtk_widget_show (GTK_WIDGET (chooser_dialog));
538 empathy_avatar_chooser_new (void)
540 return g_object_new (EMPATHY_AVATAR_CHOOSER_TYPE, NULL);
544 empathy_avatar_chooser_set (EmpathyAvatarChooser *chooser,
545 EmpathyAvatar *avatar)
547 g_return_if_fail (EMPATHY_IS_AVATAR_CHOOSER (chooser));
549 avatar_chooser_set_image_from_data (chooser,
550 avatar ? avatar->data : NULL,
551 avatar ? avatar->len : 0);
555 empathy_avatar_chooser_get_image_data (EmpathyAvatarChooser *chooser,
559 EmpathyAvatarChooserPriv *priv;
561 g_return_if_fail (EMPATHY_IS_AVATAR_CHOOSER (chooser));
563 priv = GET_PRIV (chooser);
566 *data = priv->image_data;
569 *data_size = priv->image_data_size;