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-2008 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>
32 #include <libempathy/empathy-debug.h>
34 #include "empathy-avatar-chooser.h"
35 #include "empathy-conf.h"
36 #include "empathy-ui-utils.h"
38 #define DEBUG_DOMAIN "AvatarChooser"
40 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_AVATAR_CHOOSER, EmpathyAvatarChooserPriv))
42 #define AVATAR_SIZE_SAVE 96
43 #define AVATAR_SIZE_VIEW 64
44 #define DEFAULT_DIR DATADIR"/pixmaps/faces"
48 gsize image_data_size;
49 } EmpathyAvatarChooserPriv;
51 static void avatar_chooser_finalize (GObject *object);
52 static void avatar_chooser_set_image_from_data (EmpathyAvatarChooser *chooser,
55 static gboolean avatar_chooser_drag_motion_cb (GtkWidget *widget,
56 GdkDragContext *context,
60 EmpathyAvatarChooser *chooser);
61 static void avatar_chooser_drag_leave_cb (GtkWidget *widget,
62 GdkDragContext *context,
64 EmpathyAvatarChooser *chooser);
65 static gboolean avatar_chooser_drag_drop_cb (GtkWidget *widget,
66 GdkDragContext *context,
70 EmpathyAvatarChooser *chooser);
71 static void avatar_chooser_drag_data_received_cb (GtkWidget *widget,
72 GdkDragContext *context,
75 GtkSelectionData *selection_data,
78 EmpathyAvatarChooser *chooser);
79 static void avatar_chooser_clicked_cb (GtkWidget *button,
80 EmpathyAvatarChooser *chooser);
87 static guint signals [LAST_SIGNAL];
89 G_DEFINE_TYPE (EmpathyAvatarChooser, empathy_avatar_chooser, GTK_TYPE_BUTTON);
94 #define URI_LIST_TYPE "text/uri-list"
97 DND_TARGET_TYPE_URI_LIST
100 static const GtkTargetEntry drop_types[] = {
101 { URI_LIST_TYPE, 0, DND_TARGET_TYPE_URI_LIST },
105 empathy_avatar_chooser_class_init (EmpathyAvatarChooserClass *klass)
107 GObjectClass *object_class = G_OBJECT_CLASS (klass);
109 object_class->finalize = avatar_chooser_finalize;
112 g_signal_new ("changed",
113 G_TYPE_FROM_CLASS (klass),
117 g_cclosure_marshal_VOID__VOID,
120 g_type_class_add_private (object_class, sizeof (EmpathyAvatarChooserPriv));
124 empathy_avatar_chooser_init (EmpathyAvatarChooser *chooser)
126 EmpathyAvatarChooserPriv *priv;
128 priv = GET_PRIV (chooser);
130 gtk_drag_dest_set (GTK_WIDGET (chooser),
131 GTK_DEST_DEFAULT_ALL,
133 G_N_ELEMENTS (drop_types),
136 g_signal_connect (chooser, "drag-motion",
137 G_CALLBACK (avatar_chooser_drag_motion_cb),
139 g_signal_connect (chooser, "drag-leave",
140 G_CALLBACK (avatar_chooser_drag_leave_cb),
142 g_signal_connect (chooser, "drag-drop",
143 G_CALLBACK (avatar_chooser_drag_drop_cb),
145 g_signal_connect (chooser, "drag-data-received",
146 G_CALLBACK (avatar_chooser_drag_data_received_cb),
148 g_signal_connect (chooser, "clicked",
149 G_CALLBACK (avatar_chooser_clicked_cb),
152 empathy_avatar_chooser_set (chooser, NULL);
156 avatar_chooser_finalize (GObject *object)
158 EmpathyAvatarChooserPriv *priv;
160 priv = GET_PRIV (object);
162 g_free (priv->image_data);
164 G_OBJECT_CLASS (empathy_avatar_chooser_parent_class)->finalize (object);
168 avatar_chooser_set_pixbuf (EmpathyAvatarChooser *chooser,
171 EmpathyAvatarChooserPriv *priv = GET_PRIV (chooser);
173 GdkPixbuf *pixbuf_view = NULL;
174 GdkPixbuf *pixbuf_save = NULL;
175 GError *error = NULL;
177 g_free (priv->image_data);
178 priv->image_data = NULL;
179 priv->image_data_size = 0;
182 pixbuf_view = empathy_pixbuf_scale_down_if_necessary (pixbuf, AVATAR_SIZE_VIEW);
183 pixbuf_save = empathy_pixbuf_scale_down_if_necessary (pixbuf, AVATAR_SIZE_SAVE);
185 if (!gdk_pixbuf_save_to_buffer (pixbuf_save,
187 &priv->image_data_size,
190 empathy_debug (DEBUG_DOMAIN, "Failed to save pixbuf: %s",
191 error ? error->message : "No error given");
192 g_clear_error (&error);
194 image = gtk_image_new_from_pixbuf (pixbuf_view);
196 g_object_unref (pixbuf_save);
197 g_object_unref (pixbuf_view);
199 image = gtk_image_new_from_icon_name ("stock_person",
200 GTK_ICON_SIZE_DIALOG);
203 gtk_button_set_image (GTK_BUTTON (chooser), image);
204 g_signal_emit (chooser, signals[CHANGED], 0);
208 avatar_chooser_set_image_from_file (EmpathyAvatarChooser *chooser,
209 const gchar *filename)
212 GError *error = NULL;
214 if (!(pixbuf = gdk_pixbuf_new_from_file (filename, &error))) {
215 empathy_debug (DEBUG_DOMAIN, "Failed to load pixbuf from file: %s",
216 error ? error->message : "No error given");
217 g_clear_error (&error);
220 avatar_chooser_set_pixbuf (chooser, pixbuf);
222 g_object_unref (pixbuf);
227 avatar_chooser_set_image_from_data (EmpathyAvatarChooser *chooser,
233 pixbuf = empathy_pixbuf_from_data (data, size);
234 avatar_chooser_set_pixbuf (chooser, pixbuf);
236 g_object_unref (pixbuf);
241 avatar_chooser_drag_motion_cb (GtkWidget *widget,
242 GdkDragContext *context,
246 EmpathyAvatarChooser *chooser)
248 EmpathyAvatarChooserPriv *priv;
251 priv = GET_PRIV (chooser);
253 for (p = context->targets; p != NULL; p = p->next) {
254 gchar *possible_type;
256 possible_type = gdk_atom_name (GDK_POINTER_TO_ATOM (p->data));
258 if (!strcmp (possible_type, URI_LIST_TYPE)) {
259 g_free (possible_type);
260 gdk_drag_status (context, GDK_ACTION_COPY, time);
265 g_free (possible_type);
272 avatar_chooser_drag_leave_cb (GtkWidget *widget,
273 GdkDragContext *context,
275 EmpathyAvatarChooser *chooser)
280 avatar_chooser_drag_drop_cb (GtkWidget *widget,
281 GdkDragContext *context,
285 EmpathyAvatarChooser *chooser)
287 EmpathyAvatarChooserPriv *priv;
290 priv = GET_PRIV (chooser);
292 if (context->targets == NULL) {
296 for (p = context->targets; p != NULL; p = p->next) {
299 possible_type = gdk_atom_name (GDK_POINTER_TO_ATOM (p->data));
300 if (!strcmp (possible_type, URI_LIST_TYPE)) {
301 g_free (possible_type);
302 gtk_drag_get_data (widget, context,
303 GDK_POINTER_TO_ATOM (p->data),
309 g_free (possible_type);
316 avatar_chooser_drag_data_received_cb (GtkWidget *widget,
317 GdkDragContext *context,
320 GtkSelectionData *selection_data,
323 EmpathyAvatarChooser *chooser)
326 gboolean handled = FALSE;
328 target_type = gdk_atom_name (selection_data->target);
329 if (!strcmp (target_type, URI_LIST_TYPE)) {
331 GFileInputStream *input_stream;
335 nl = strstr (selection_data->data, "\r\n");
339 uri = g_strndup (selection_data->data,
340 nl - (gchar*) selection_data->data);
342 file = g_file_new_for_uri (uri);
345 file = g_file_new_for_uri (selection_data->data);
348 input_stream = g_file_read (file, NULL, NULL);
350 if (input_stream != NULL) {
353 info = g_file_query_info (file,
354 G_FILE_ATTRIBUTE_STANDARD_SIZE,
360 size = g_file_info_get_size (info);
361 data = g_malloc (size);
363 bytes_read = g_input_stream_read (G_INPUT_STREAM (input_stream),
366 if (bytes_read != -1) {
367 avatar_chooser_set_image_from_data (chooser,
374 g_object_unref (info);
377 g_object_unref (input_stream);
380 g_object_unref (file);
383 gtk_drag_finish (context, handled, FALSE, time);
387 avatar_chooser_update_preview_cb (GtkFileChooser *file_chooser,
388 EmpathyAvatarChooser *chooser)
392 filename = gtk_file_chooser_get_preview_filename (file_chooser);
396 GdkPixbuf *pixbuf = NULL;
397 GdkPixbuf *scaled_pixbuf;
399 pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
401 image = gtk_file_chooser_get_preview_widget (file_chooser);
404 scaled_pixbuf = empathy_pixbuf_scale_down_if_necessary (pixbuf, AVATAR_SIZE_SAVE);
405 gtk_image_set_from_pixbuf (GTK_IMAGE (image), scaled_pixbuf);
406 g_object_unref (scaled_pixbuf);
407 g_object_unref (pixbuf);
409 gtk_image_set_from_stock (GTK_IMAGE (image),
410 "gtk-dialog-question",
411 GTK_ICON_SIZE_DIALOG);
415 gtk_file_chooser_set_preview_widget_active (file_chooser, TRUE);
419 avatar_chooser_response_cb (GtkWidget *widget,
421 EmpathyAvatarChooser *chooser)
423 if (response == GTK_RESPONSE_OK) {
427 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));
428 avatar_chooser_set_image_from_file (chooser, filename);
431 path = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (widget));
433 empathy_conf_set_string (empathy_conf_get (),
434 EMPATHY_PREFS_UI_AVATAR_DIRECTORY,
439 else if (response == GTK_RESPONSE_NO) {
440 avatar_chooser_set_image_from_data (chooser, NULL, 0);
443 gtk_widget_destroy (widget);
447 avatar_chooser_clicked_cb (GtkWidget *button,
448 EmpathyAvatarChooser *chooser)
450 GtkFileChooser *chooser_dialog;
452 gchar *saved_dir = NULL;
453 const gchar *default_dir = DEFAULT_DIR;
454 const gchar *pics_dir;
455 GtkFileFilter *filter;
457 chooser_dialog = GTK_FILE_CHOOSER (
458 gtk_file_chooser_dialog_new (_("Select Your Avatar Image"),
459 empathy_get_toplevel_window (GTK_WIDGET (chooser)),
460 GTK_FILE_CHOOSER_ACTION_OPEN,
469 /* Get special dirs */
470 empathy_conf_get_string (empathy_conf_get (),
471 EMPATHY_PREFS_UI_AVATAR_DIRECTORY,
473 if (saved_dir && !g_file_test (saved_dir, G_FILE_TEST_IS_DIR)) {
477 if (!g_file_test (default_dir, G_FILE_TEST_IS_DIR)) {
480 pics_dir = g_get_user_special_dir (G_USER_DIRECTORY_PICTURES);
481 if (pics_dir && !g_file_test (pics_dir, G_FILE_TEST_IS_DIR)) {
485 /* Set current dir to the last one or to DEFAULT_DIR or to home */
487 gtk_file_chooser_set_current_folder (chooser_dialog, saved_dir);
490 gtk_file_chooser_set_current_folder (chooser_dialog, pics_dir);
492 else if (default_dir) {
493 gtk_file_chooser_set_current_folder (chooser_dialog, default_dir);
495 gtk_file_chooser_set_current_folder (chooser_dialog, g_get_home_dir ());
498 /* Add shortcuts to special dirs */
500 gtk_file_chooser_add_shortcut_folder (chooser_dialog, saved_dir, NULL);
503 gtk_file_chooser_add_shortcut_folder (chooser_dialog, pics_dir, NULL);
506 gtk_file_chooser_add_shortcut_folder (chooser_dialog, default_dir, NULL);
509 /* Setup preview image */
510 image = gtk_image_new ();
511 gtk_file_chooser_set_preview_widget (chooser_dialog, image);
512 gtk_widget_set_size_request (image, AVATAR_SIZE_SAVE, AVATAR_SIZE_SAVE);
513 gtk_widget_show (image);
514 gtk_file_chooser_set_use_preview_label (chooser_dialog, FALSE);
515 g_signal_connect (chooser_dialog, "update-preview",
516 G_CALLBACK (avatar_chooser_update_preview_cb),
520 filter = gtk_file_filter_new ();
521 gtk_file_filter_set_name (filter, _("Images"));
522 gtk_file_filter_add_pixbuf_formats (filter);
523 gtk_file_chooser_add_filter (chooser_dialog, filter);
524 filter = gtk_file_filter_new ();
525 gtk_file_filter_set_name (filter, _("All Files"));
526 gtk_file_filter_add_pattern(filter, "*");
527 gtk_file_chooser_add_filter (chooser_dialog, filter);
530 gtk_dialog_set_default_response (GTK_DIALOG (chooser_dialog), GTK_RESPONSE_OK);
531 g_signal_connect (chooser_dialog, "response",
532 G_CALLBACK (avatar_chooser_response_cb),
535 gtk_widget_show (GTK_WIDGET (chooser_dialog));
540 empathy_avatar_chooser_new (void)
542 return g_object_new (EMPATHY_TYPE_AVATAR_CHOOSER, NULL);
546 empathy_avatar_chooser_set (EmpathyAvatarChooser *chooser,
547 EmpathyAvatar *avatar)
549 g_return_if_fail (EMPATHY_IS_AVATAR_CHOOSER (chooser));
551 avatar_chooser_set_image_from_data (chooser,
552 avatar ? avatar->data : NULL,
553 avatar ? avatar->len : 0);
557 empathy_avatar_chooser_get_image_data (EmpathyAvatarChooser *chooser,
560 const gchar **mime_type)
562 EmpathyAvatarChooserPriv *priv;
564 g_return_if_fail (EMPATHY_IS_AVATAR_CHOOSER (chooser));
566 priv = GET_PRIV (chooser);
569 *data = priv->image_data;
572 *data_size = priv->image_data_size;