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_TYPE_AVATAR_CHOOSER, EmpathyAvatarChooserPriv))
43 #define AVATAR_SIZE_SAVE 96
44 #define AVATAR_SIZE_VIEW 64
45 #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);
163 g_free (priv->image_data);
165 G_OBJECT_CLASS (empathy_avatar_chooser_parent_class)->finalize (object);
169 avatar_chooser_set_pixbuf (EmpathyAvatarChooser *chooser,
172 EmpathyAvatarChooserPriv *priv = GET_PRIV (chooser);
174 GdkPixbuf *pixbuf_view = NULL;
175 GdkPixbuf *pixbuf_save = NULL;
176 GError *error = NULL;
178 g_free (priv->image_data);
179 priv->image_data = NULL;
180 priv->image_data_size = 0;
183 pixbuf_view = empathy_pixbuf_scale_down_if_necessary (pixbuf, AVATAR_SIZE_VIEW);
184 pixbuf_save = empathy_pixbuf_scale_down_if_necessary (pixbuf, AVATAR_SIZE_SAVE);
186 if (!gdk_pixbuf_save_to_buffer (pixbuf_save,
188 &priv->image_data_size,
191 empathy_debug (DEBUG_DOMAIN, "Failed to save pixbuf: %s",
192 error ? error->message : "No error given");
193 g_clear_error (&error);
195 image = gtk_image_new_from_pixbuf (pixbuf_view);
197 g_object_unref (pixbuf_save);
198 g_object_unref (pixbuf_view);
200 image = gtk_image_new_from_icon_name ("stock_person",
201 GTK_ICON_SIZE_DIALOG);
204 gtk_button_set_image (GTK_BUTTON (chooser), image);
205 g_signal_emit (chooser, signals[CHANGED], 0);
209 avatar_chooser_set_image_from_file (EmpathyAvatarChooser *chooser,
210 const gchar *filename)
213 GError *error = NULL;
215 if (!(pixbuf = gdk_pixbuf_new_from_file (filename, &error))) {
216 empathy_debug (DEBUG_DOMAIN, "Failed to load pixbuf from file: %s",
217 error ? error->message : "No error given");
218 g_clear_error (&error);
221 avatar_chooser_set_pixbuf (chooser, pixbuf);
223 g_object_unref (pixbuf);
228 avatar_chooser_set_image_from_data (EmpathyAvatarChooser *chooser,
234 pixbuf = empathy_pixbuf_from_data (data, size);
235 avatar_chooser_set_pixbuf (chooser, pixbuf);
237 g_object_unref (pixbuf);
242 avatar_chooser_drag_motion_cb (GtkWidget *widget,
243 GdkDragContext *context,
247 EmpathyAvatarChooser *chooser)
249 EmpathyAvatarChooserPriv *priv;
252 priv = GET_PRIV (chooser);
254 for (p = context->targets; p != NULL; p = p->next) {
255 gchar *possible_type;
257 possible_type = gdk_atom_name (GDK_POINTER_TO_ATOM (p->data));
259 if (!strcmp (possible_type, URI_LIST_TYPE)) {
260 g_free (possible_type);
261 gdk_drag_status (context, GDK_ACTION_COPY, time);
266 g_free (possible_type);
273 avatar_chooser_drag_leave_cb (GtkWidget *widget,
274 GdkDragContext *context,
276 EmpathyAvatarChooser *chooser)
281 avatar_chooser_drag_drop_cb (GtkWidget *widget,
282 GdkDragContext *context,
286 EmpathyAvatarChooser *chooser)
288 EmpathyAvatarChooserPriv *priv;
291 priv = GET_PRIV (chooser);
293 if (context->targets == NULL) {
297 for (p = context->targets; p != NULL; p = p->next) {
300 possible_type = gdk_atom_name (GDK_POINTER_TO_ATOM (p->data));
301 if (!strcmp (possible_type, URI_LIST_TYPE)) {
302 g_free (possible_type);
303 gtk_drag_get_data (widget, context,
304 GDK_POINTER_TO_ATOM (p->data),
310 g_free (possible_type);
317 avatar_chooser_drag_data_received_cb (GtkWidget *widget,
318 GdkDragContext *context,
321 GtkSelectionData *selection_data,
324 EmpathyAvatarChooser *chooser)
327 gboolean handled = FALSE;
329 target_type = gdk_atom_name (selection_data->target);
330 if (!strcmp (target_type, URI_LIST_TYPE)) {
331 GnomeVFSHandle *handle = NULL;
332 GnomeVFSResult result;
333 GnomeVFSFileInfo info;
338 nl = strstr (selection_data->data, "\r\n");
340 uri = g_strndup (selection_data->data,
341 nl - (gchar*) selection_data->data);
343 uri = g_strdup (selection_data->data);
346 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
347 if (result == GNOME_VFS_OK) {
348 result = gnome_vfs_get_file_info_from_handle (handle,
350 GNOME_VFS_FILE_INFO_DEFAULT);
351 if (result == GNOME_VFS_OK) {
352 GnomeVFSFileSize data_size;
354 data = g_malloc (info.size);
356 result = gnome_vfs_read (handle, data, info.size, &data_size);
357 if (result == GNOME_VFS_OK) {
358 avatar_chooser_set_image_from_data (chooser,
367 gnome_vfs_close (handle);
373 gtk_drag_finish (context, handled, FALSE, time);
377 avatar_chooser_update_preview_cb (GtkFileChooser *file_chooser,
378 EmpathyAvatarChooser *chooser)
382 filename = gtk_file_chooser_get_preview_filename (file_chooser);
386 GdkPixbuf *pixbuf = NULL;
387 GdkPixbuf *scaled_pixbuf;
389 pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
391 image = gtk_file_chooser_get_preview_widget (file_chooser);
394 scaled_pixbuf = empathy_pixbuf_scale_down_if_necessary (pixbuf, AVATAR_SIZE_SAVE);
395 gtk_image_set_from_pixbuf (GTK_IMAGE (image), scaled_pixbuf);
396 g_object_unref (scaled_pixbuf);
397 g_object_unref (pixbuf);
399 gtk_image_set_from_stock (GTK_IMAGE (image),
400 "gtk-dialog-question",
401 GTK_ICON_SIZE_DIALOG);
405 gtk_file_chooser_set_preview_widget_active (file_chooser, TRUE);
409 avatar_chooser_response_cb (GtkWidget *widget,
411 EmpathyAvatarChooser *chooser)
413 if (response == GTK_RESPONSE_OK) {
417 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));
418 avatar_chooser_set_image_from_file (chooser, filename);
421 path = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (widget));
423 empathy_conf_set_string (empathy_conf_get (),
424 EMPATHY_PREFS_UI_AVATAR_DIRECTORY,
429 else if (response == GTK_RESPONSE_NO) {
430 avatar_chooser_set_image_from_data (chooser, NULL, 0);
433 gtk_widget_destroy (widget);
437 avatar_chooser_clicked_cb (GtkWidget *button,
438 EmpathyAvatarChooser *chooser)
440 GtkFileChooser *chooser_dialog;
442 gchar *saved_dir = NULL;
443 const gchar *default_dir = DEFAULT_DIR;
444 const gchar *pics_dir;
445 GtkFileFilter *filter;
447 chooser_dialog = GTK_FILE_CHOOSER (
448 gtk_file_chooser_dialog_new (_("Select Your Avatar Image"),
449 empathy_get_toplevel_window (GTK_WIDGET (chooser)),
450 GTK_FILE_CHOOSER_ACTION_OPEN,
459 /* Get special dirs */
460 empathy_conf_get_string (empathy_conf_get (),
461 EMPATHY_PREFS_UI_AVATAR_DIRECTORY,
463 if (saved_dir && !g_file_test (saved_dir, G_FILE_TEST_IS_DIR)) {
467 if (!g_file_test (default_dir, G_FILE_TEST_IS_DIR)) {
470 pics_dir = g_get_user_special_dir (G_USER_DIRECTORY_PICTURES);
471 if (pics_dir && !g_file_test (pics_dir, G_FILE_TEST_IS_DIR)) {
475 /* Set current dir to the last one or to DEFAULT_DIR or to home */
477 gtk_file_chooser_set_current_folder (chooser_dialog, saved_dir);
480 gtk_file_chooser_set_current_folder (chooser_dialog, pics_dir);
482 else if (default_dir) {
483 gtk_file_chooser_set_current_folder (chooser_dialog, default_dir);
485 gtk_file_chooser_set_current_folder (chooser_dialog, g_get_home_dir ());
488 /* Add shortcuts to special dirs */
490 gtk_file_chooser_add_shortcut_folder (chooser_dialog, saved_dir, NULL);
493 gtk_file_chooser_add_shortcut_folder (chooser_dialog, pics_dir, NULL);
496 gtk_file_chooser_add_shortcut_folder (chooser_dialog, default_dir, NULL);
499 /* Setup preview image */
500 image = gtk_image_new ();
501 gtk_file_chooser_set_preview_widget (chooser_dialog, image);
502 gtk_widget_set_size_request (image, AVATAR_SIZE_SAVE, AVATAR_SIZE_SAVE);
503 gtk_widget_show (image);
504 gtk_file_chooser_set_use_preview_label (chooser_dialog, FALSE);
505 g_signal_connect (chooser_dialog, "update-preview",
506 G_CALLBACK (avatar_chooser_update_preview_cb),
510 filter = gtk_file_filter_new ();
511 gtk_file_filter_set_name (filter, _("Images"));
512 gtk_file_filter_add_pixbuf_formats (filter);
513 gtk_file_chooser_add_filter (chooser_dialog, filter);
514 filter = gtk_file_filter_new ();
515 gtk_file_filter_set_name (filter, _("All Files"));
516 gtk_file_filter_add_pattern(filter, "*");
517 gtk_file_chooser_add_filter (chooser_dialog, filter);
520 gtk_dialog_set_default_response (GTK_DIALOG (chooser_dialog), GTK_RESPONSE_OK);
521 g_signal_connect (chooser_dialog, "response",
522 G_CALLBACK (avatar_chooser_response_cb),
525 gtk_widget_show (GTK_WIDGET (chooser_dialog));
530 empathy_avatar_chooser_new (void)
532 return g_object_new (EMPATHY_TYPE_AVATAR_CHOOSER, NULL);
536 empathy_avatar_chooser_set (EmpathyAvatarChooser *chooser,
537 EmpathyAvatar *avatar)
539 g_return_if_fail (EMPATHY_IS_AVATAR_CHOOSER (chooser));
541 avatar_chooser_set_image_from_data (chooser,
542 avatar ? avatar->data : NULL,
543 avatar ? avatar->len : 0);
547 empathy_avatar_chooser_get_image_data (EmpathyAvatarChooser *chooser,
550 const gchar **mime_type)
552 EmpathyAvatarChooserPriv *priv;
554 g_return_if_fail (EMPATHY_IS_AVATAR_CHOOSER (chooser));
556 priv = GET_PRIV (chooser);
559 *data = priv->image_data;
562 *data_size = priv->image_data_size;