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>
35 #include "empathy-avatar-chooser.h"
36 #include "empathy-conf.h"
37 #include "empathy-preferences.h"
38 #include "empathy-ui-utils.h"
40 #define DEBUG_DOMAIN "AvatarChooser"
42 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_AVATAR_CHOOSER, EmpathyAvatarChooserPriv))
44 #define AVATAR_SIZE_SAVE 96
45 #define AVATAR_SIZE_VIEW 64
46 #define DEFAULT_DIR DATADIR"/pixmaps/faces"
50 gsize image_data_size;
51 } EmpathyAvatarChooserPriv;
53 static void avatar_chooser_finalize (GObject *object);
54 static void avatar_chooser_set_image_from_data (EmpathyAvatarChooser *chooser,
57 static gboolean avatar_chooser_drag_motion_cb (GtkWidget *widget,
58 GdkDragContext *context,
62 EmpathyAvatarChooser *chooser);
63 static void avatar_chooser_drag_leave_cb (GtkWidget *widget,
64 GdkDragContext *context,
66 EmpathyAvatarChooser *chooser);
67 static gboolean avatar_chooser_drag_drop_cb (GtkWidget *widget,
68 GdkDragContext *context,
72 EmpathyAvatarChooser *chooser);
73 static void avatar_chooser_drag_data_received_cb (GtkWidget *widget,
74 GdkDragContext *context,
77 GtkSelectionData *selection_data,
80 EmpathyAvatarChooser *chooser);
81 static void avatar_chooser_clicked_cb (GtkWidget *button,
82 EmpathyAvatarChooser *chooser);
89 static guint signals [LAST_SIGNAL];
91 G_DEFINE_TYPE (EmpathyAvatarChooser, empathy_avatar_chooser, GTK_TYPE_BUTTON);
96 #define URI_LIST_TYPE "text/uri-list"
99 DND_TARGET_TYPE_URI_LIST
102 static const GtkTargetEntry drop_types[] = {
103 { URI_LIST_TYPE, 0, DND_TARGET_TYPE_URI_LIST },
107 empathy_avatar_chooser_class_init (EmpathyAvatarChooserClass *klass)
109 GObjectClass *object_class = G_OBJECT_CLASS (klass);
111 object_class->finalize = avatar_chooser_finalize;
114 g_signal_new ("changed",
115 G_TYPE_FROM_CLASS (klass),
119 g_cclosure_marshal_VOID__VOID,
122 g_type_class_add_private (object_class, sizeof (EmpathyAvatarChooserPriv));
126 empathy_avatar_chooser_init (EmpathyAvatarChooser *chooser)
128 EmpathyAvatarChooserPriv *priv;
130 priv = GET_PRIV (chooser);
132 gtk_drag_dest_set (GTK_WIDGET (chooser),
133 GTK_DEST_DEFAULT_ALL,
135 G_N_ELEMENTS (drop_types),
138 g_signal_connect (chooser, "drag-motion",
139 G_CALLBACK (avatar_chooser_drag_motion_cb),
141 g_signal_connect (chooser, "drag-leave",
142 G_CALLBACK (avatar_chooser_drag_leave_cb),
144 g_signal_connect (chooser, "drag-drop",
145 G_CALLBACK (avatar_chooser_drag_drop_cb),
147 g_signal_connect (chooser, "drag-data-received",
148 G_CALLBACK (avatar_chooser_drag_data_received_cb),
150 g_signal_connect (chooser, "clicked",
151 G_CALLBACK (avatar_chooser_clicked_cb),
154 empathy_avatar_chooser_set (chooser, NULL);
158 avatar_chooser_finalize (GObject *object)
160 EmpathyAvatarChooserPriv *priv;
162 priv = GET_PRIV (object);
164 g_free (priv->image_data);
166 G_OBJECT_CLASS (empathy_avatar_chooser_parent_class)->finalize (object);
170 avatar_chooser_set_pixbuf (EmpathyAvatarChooser *chooser,
173 EmpathyAvatarChooserPriv *priv = GET_PRIV (chooser);
175 GdkPixbuf *pixbuf_view = NULL;
176 GdkPixbuf *pixbuf_save = NULL;
177 GError *error = NULL;
179 g_free (priv->image_data);
180 priv->image_data = NULL;
181 priv->image_data_size = 0;
184 pixbuf_view = empathy_pixbuf_scale_down_if_necessary (pixbuf, AVATAR_SIZE_VIEW);
185 pixbuf_save = empathy_pixbuf_scale_down_if_necessary (pixbuf, AVATAR_SIZE_SAVE);
187 if (!gdk_pixbuf_save_to_buffer (pixbuf_save,
189 &priv->image_data_size,
192 empathy_debug (DEBUG_DOMAIN, "Failed to save pixbuf: %s",
193 error ? error->message : "No error given");
194 g_clear_error (&error);
196 image = gtk_image_new_from_pixbuf (pixbuf_view);
198 g_object_unref (pixbuf_save);
199 g_object_unref (pixbuf_view);
201 image = gtk_image_new_from_icon_name ("stock_person",
202 GTK_ICON_SIZE_DIALOG);
205 gtk_button_set_image (GTK_BUTTON (chooser), image);
206 g_signal_emit (chooser, signals[CHANGED], 0);
210 avatar_chooser_set_image_from_file (EmpathyAvatarChooser *chooser,
211 const gchar *filename)
214 GError *error = NULL;
216 if (!(pixbuf = gdk_pixbuf_new_from_file (filename, &error))) {
217 empathy_debug (DEBUG_DOMAIN, "Failed to load pixbuf from file: %s",
218 error ? error->message : "No error given");
219 g_clear_error (&error);
222 avatar_chooser_set_pixbuf (chooser, pixbuf);
224 g_object_unref (pixbuf);
229 avatar_chooser_set_image_from_data (EmpathyAvatarChooser *chooser,
235 pixbuf = empathy_pixbuf_from_data (data, size);
236 avatar_chooser_set_pixbuf (chooser, pixbuf);
238 g_object_unref (pixbuf);
243 avatar_chooser_drag_motion_cb (GtkWidget *widget,
244 GdkDragContext *context,
248 EmpathyAvatarChooser *chooser)
250 EmpathyAvatarChooserPriv *priv;
253 priv = GET_PRIV (chooser);
255 for (p = context->targets; p != NULL; p = p->next) {
256 gchar *possible_type;
258 possible_type = gdk_atom_name (GDK_POINTER_TO_ATOM (p->data));
260 if (!strcmp (possible_type, URI_LIST_TYPE)) {
261 g_free (possible_type);
262 gdk_drag_status (context, GDK_ACTION_COPY, time);
267 g_free (possible_type);
274 avatar_chooser_drag_leave_cb (GtkWidget *widget,
275 GdkDragContext *context,
277 EmpathyAvatarChooser *chooser)
282 avatar_chooser_drag_drop_cb (GtkWidget *widget,
283 GdkDragContext *context,
287 EmpathyAvatarChooser *chooser)
289 EmpathyAvatarChooserPriv *priv;
292 priv = GET_PRIV (chooser);
294 if (context->targets == NULL) {
298 for (p = context->targets; p != NULL; p = p->next) {
301 possible_type = gdk_atom_name (GDK_POINTER_TO_ATOM (p->data));
302 if (!strcmp (possible_type, URI_LIST_TYPE)) {
303 g_free (possible_type);
304 gtk_drag_get_data (widget, context,
305 GDK_POINTER_TO_ATOM (p->data),
311 g_free (possible_type);
318 avatar_chooser_drag_data_received_cb (GtkWidget *widget,
319 GdkDragContext *context,
322 GtkSelectionData *selection_data,
325 EmpathyAvatarChooser *chooser)
328 gboolean handled = FALSE;
330 target_type = gdk_atom_name (selection_data->target);
331 if (!strcmp (target_type, URI_LIST_TYPE)) {
332 GnomeVFSHandle *handle = NULL;
333 GnomeVFSResult result;
334 GnomeVFSFileInfo info;
339 nl = strstr (selection_data->data, "\r\n");
341 uri = g_strndup (selection_data->data,
342 nl - (gchar*) selection_data->data);
344 uri = g_strdup (selection_data->data);
347 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
348 if (result == GNOME_VFS_OK) {
349 result = gnome_vfs_get_file_info_from_handle (handle,
351 GNOME_VFS_FILE_INFO_DEFAULT);
352 if (result == GNOME_VFS_OK) {
353 GnomeVFSFileSize data_size;
355 data = g_malloc (info.size);
357 result = gnome_vfs_read (handle, data, info.size, &data_size);
358 if (result == GNOME_VFS_OK) {
359 avatar_chooser_set_image_from_data (chooser,
368 gnome_vfs_close (handle);
374 gtk_drag_finish (context, handled, FALSE, time);
378 avatar_chooser_update_preview_cb (GtkFileChooser *file_chooser,
379 EmpathyAvatarChooser *chooser)
383 filename = gtk_file_chooser_get_preview_filename (file_chooser);
387 GdkPixbuf *pixbuf = NULL;
388 GdkPixbuf *scaled_pixbuf;
390 pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
392 image = gtk_file_chooser_get_preview_widget (file_chooser);
395 scaled_pixbuf = empathy_pixbuf_scale_down_if_necessary (pixbuf, AVATAR_SIZE_SAVE);
396 gtk_image_set_from_pixbuf (GTK_IMAGE (image), scaled_pixbuf);
397 g_object_unref (scaled_pixbuf);
398 g_object_unref (pixbuf);
400 gtk_image_set_from_stock (GTK_IMAGE (image),
401 "gtk-dialog-question",
402 GTK_ICON_SIZE_DIALOG);
406 gtk_file_chooser_set_preview_widget_active (file_chooser, TRUE);
410 avatar_chooser_response_cb (GtkWidget *widget,
412 EmpathyAvatarChooser *chooser)
414 if (response == GTK_RESPONSE_OK) {
418 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));
419 avatar_chooser_set_image_from_file (chooser, filename);
422 path = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (widget));
424 empathy_conf_set_string (empathy_conf_get (),
425 EMPATHY_PREFS_UI_AVATAR_DIRECTORY,
430 else if (response == GTK_RESPONSE_NO) {
431 avatar_chooser_set_image_from_data (chooser, NULL, 0);
434 gtk_widget_destroy (widget);
438 avatar_chooser_clicked_cb (GtkWidget *button,
439 EmpathyAvatarChooser *chooser)
441 GtkFileChooser *chooser_dialog;
443 gchar *saved_dir = NULL;
444 const gchar *default_dir = DEFAULT_DIR;
445 const gchar *pics_dir;
446 GtkFileFilter *filter;
448 chooser_dialog = GTK_FILE_CHOOSER (
449 gtk_file_chooser_dialog_new (_("Select Your Avatar Image"),
450 empathy_get_toplevel_window (GTK_WIDGET (chooser)),
451 GTK_FILE_CHOOSER_ACTION_OPEN,
460 /* Get special dirs */
461 empathy_conf_get_string (empathy_conf_get (),
462 EMPATHY_PREFS_UI_AVATAR_DIRECTORY,
464 if (saved_dir && !g_file_test (saved_dir, G_FILE_TEST_IS_DIR)) {
468 if (!g_file_test (default_dir, G_FILE_TEST_IS_DIR)) {
471 pics_dir = g_get_user_special_dir (G_USER_DIRECTORY_PICTURES);
472 if (pics_dir && !g_file_test (pics_dir, G_FILE_TEST_IS_DIR)) {
476 /* Set current dir to the last one or to DEFAULT_DIR or to home */
478 gtk_file_chooser_set_current_folder (chooser_dialog, saved_dir);
481 gtk_file_chooser_set_current_folder (chooser_dialog, pics_dir);
483 else if (default_dir) {
484 gtk_file_chooser_set_current_folder (chooser_dialog, default_dir);
486 gtk_file_chooser_set_current_folder (chooser_dialog, g_get_home_dir ());
489 /* Add shortcuts to special dirs */
491 gtk_file_chooser_add_shortcut_folder (chooser_dialog, saved_dir, NULL);
494 gtk_file_chooser_add_shortcut_folder (chooser_dialog, pics_dir, NULL);
497 gtk_file_chooser_add_shortcut_folder (chooser_dialog, default_dir, NULL);
500 /* Setup preview image */
501 image = gtk_image_new ();
502 gtk_file_chooser_set_preview_widget (chooser_dialog, image);
503 gtk_widget_set_size_request (image, AVATAR_SIZE_SAVE, AVATAR_SIZE_SAVE);
504 gtk_widget_show (image);
505 gtk_file_chooser_set_use_preview_label (chooser_dialog, FALSE);
506 g_signal_connect (chooser_dialog, "update-preview",
507 G_CALLBACK (avatar_chooser_update_preview_cb),
511 filter = gtk_file_filter_new ();
512 gtk_file_filter_set_name (filter, _("Images"));
513 gtk_file_filter_add_pixbuf_formats (filter);
514 gtk_file_chooser_add_filter (chooser_dialog, filter);
515 filter = gtk_file_filter_new ();
516 gtk_file_filter_set_name (filter, _("All Files"));
517 gtk_file_filter_add_pattern(filter, "*");
518 gtk_file_chooser_add_filter (chooser_dialog, filter);
521 gtk_dialog_set_default_response (GTK_DIALOG (chooser_dialog), GTK_RESPONSE_OK);
522 g_signal_connect (chooser_dialog, "response",
523 G_CALLBACK (avatar_chooser_response_cb),
526 gtk_widget_show (GTK_WIDGET (chooser_dialog));
531 empathy_avatar_chooser_new (void)
533 return g_object_new (EMPATHY_TYPE_AVATAR_CHOOSER, NULL);
537 empathy_avatar_chooser_set (EmpathyAvatarChooser *chooser,
538 EmpathyAvatar *avatar)
540 g_return_if_fail (EMPATHY_IS_AVATAR_CHOOSER (chooser));
542 avatar_chooser_set_image_from_data (chooser,
543 avatar ? avatar->data : NULL,
544 avatar ? avatar->len : 0);
548 empathy_avatar_chooser_get_image_data (EmpathyAvatarChooser *chooser,
551 const gchar **mime_type)
553 EmpathyAvatarChooserPriv *priv;
555 g_return_if_fail (EMPATHY_IS_AVATAR_CHOOSER (chooser));
557 priv = GET_PRIV (chooser);
560 *data = priv->image_data;
563 *data_size = priv->image_data_size;