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-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)) {
332 GFileInputStream *input_stream;
336 nl = strstr (selection_data->data, "\r\n");
340 uri = g_strndup (selection_data->data,
341 nl - (gchar*) selection_data->data);
343 file = g_file_new_for_uri (uri);
346 file = g_file_new_for_uri (selection_data->data);
349 input_stream = g_file_read (file, NULL, NULL);
351 if (input_stream != NULL) {
354 info = g_file_query_info (file,
355 G_FILE_ATTRIBUTE_STANDARD_SIZE,
361 size = g_file_info_get_size (info);
362 data = g_malloc (size);
364 bytes_read = g_input_stream_read (G_INPUT_STREAM (input_stream),
367 if (bytes_read != -1) {
368 avatar_chooser_set_image_from_data (chooser,
375 g_object_unref (info);
378 g_object_unref (input_stream);
381 g_object_unref (file);
384 gtk_drag_finish (context, handled, FALSE, time);
388 avatar_chooser_update_preview_cb (GtkFileChooser *file_chooser,
389 EmpathyAvatarChooser *chooser)
393 filename = gtk_file_chooser_get_preview_filename (file_chooser);
397 GdkPixbuf *pixbuf = NULL;
398 GdkPixbuf *scaled_pixbuf;
400 pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
402 image = gtk_file_chooser_get_preview_widget (file_chooser);
405 scaled_pixbuf = empathy_pixbuf_scale_down_if_necessary (pixbuf, AVATAR_SIZE_SAVE);
406 gtk_image_set_from_pixbuf (GTK_IMAGE (image), scaled_pixbuf);
407 g_object_unref (scaled_pixbuf);
408 g_object_unref (pixbuf);
410 gtk_image_set_from_stock (GTK_IMAGE (image),
411 "gtk-dialog-question",
412 GTK_ICON_SIZE_DIALOG);
416 gtk_file_chooser_set_preview_widget_active (file_chooser, TRUE);
420 avatar_chooser_response_cb (GtkWidget *widget,
422 EmpathyAvatarChooser *chooser)
424 if (response == GTK_RESPONSE_OK) {
428 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));
429 avatar_chooser_set_image_from_file (chooser, filename);
432 path = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (widget));
434 empathy_conf_set_string (empathy_conf_get (),
435 EMPATHY_PREFS_UI_AVATAR_DIRECTORY,
440 else if (response == GTK_RESPONSE_NO) {
441 avatar_chooser_set_image_from_data (chooser, NULL, 0);
444 gtk_widget_destroy (widget);
448 avatar_chooser_clicked_cb (GtkWidget *button,
449 EmpathyAvatarChooser *chooser)
451 GtkFileChooser *chooser_dialog;
453 gchar *saved_dir = NULL;
454 const gchar *default_dir = DEFAULT_DIR;
455 const gchar *pics_dir;
456 GtkFileFilter *filter;
458 chooser_dialog = GTK_FILE_CHOOSER (
459 gtk_file_chooser_dialog_new (_("Select Your Avatar Image"),
460 empathy_get_toplevel_window (GTK_WIDGET (chooser)),
461 GTK_FILE_CHOOSER_ACTION_OPEN,
470 /* Get special dirs */
471 empathy_conf_get_string (empathy_conf_get (),
472 EMPATHY_PREFS_UI_AVATAR_DIRECTORY,
474 if (saved_dir && !g_file_test (saved_dir, G_FILE_TEST_IS_DIR)) {
478 if (!g_file_test (default_dir, G_FILE_TEST_IS_DIR)) {
481 pics_dir = g_get_user_special_dir (G_USER_DIRECTORY_PICTURES);
482 if (pics_dir && !g_file_test (pics_dir, G_FILE_TEST_IS_DIR)) {
486 /* Set current dir to the last one or to DEFAULT_DIR or to home */
488 gtk_file_chooser_set_current_folder (chooser_dialog, saved_dir);
491 gtk_file_chooser_set_current_folder (chooser_dialog, pics_dir);
493 else if (default_dir) {
494 gtk_file_chooser_set_current_folder (chooser_dialog, default_dir);
496 gtk_file_chooser_set_current_folder (chooser_dialog, g_get_home_dir ());
499 /* Add shortcuts to special dirs */
501 gtk_file_chooser_add_shortcut_folder (chooser_dialog, saved_dir, NULL);
504 gtk_file_chooser_add_shortcut_folder (chooser_dialog, pics_dir, NULL);
507 gtk_file_chooser_add_shortcut_folder (chooser_dialog, default_dir, NULL);
510 /* Setup preview image */
511 image = gtk_image_new ();
512 gtk_file_chooser_set_preview_widget (chooser_dialog, image);
513 gtk_widget_set_size_request (image, AVATAR_SIZE_SAVE, AVATAR_SIZE_SAVE);
514 gtk_widget_show (image);
515 gtk_file_chooser_set_use_preview_label (chooser_dialog, FALSE);
516 g_signal_connect (chooser_dialog, "update-preview",
517 G_CALLBACK (avatar_chooser_update_preview_cb),
521 filter = gtk_file_filter_new ();
522 gtk_file_filter_set_name (filter, _("Images"));
523 gtk_file_filter_add_pixbuf_formats (filter);
524 gtk_file_chooser_add_filter (chooser_dialog, filter);
525 filter = gtk_file_filter_new ();
526 gtk_file_filter_set_name (filter, _("All Files"));
527 gtk_file_filter_add_pattern(filter, "*");
528 gtk_file_chooser_add_filter (chooser_dialog, filter);
531 gtk_dialog_set_default_response (GTK_DIALOG (chooser_dialog), GTK_RESPONSE_OK);
532 g_signal_connect (chooser_dialog, "response",
533 G_CALLBACK (avatar_chooser_response_cb),
536 gtk_widget_show (GTK_WIDGET (chooser_dialog));
541 empathy_avatar_chooser_new (void)
543 return g_object_new (EMPATHY_TYPE_AVATAR_CHOOSER, NULL);
547 empathy_avatar_chooser_set (EmpathyAvatarChooser *chooser,
548 EmpathyAvatar *avatar)
550 g_return_if_fail (EMPATHY_IS_AVATAR_CHOOSER (chooser));
552 avatar_chooser_set_image_from_data (chooser,
553 avatar ? avatar->data : NULL,
554 avatar ? avatar->len : 0);
558 empathy_avatar_chooser_get_image_data (EmpathyAvatarChooser *chooser,
561 const gchar **mime_type)
563 EmpathyAvatarChooserPriv *priv;
565 g_return_if_fail (EMPATHY_IS_AVATAR_CHOOSER (chooser));
567 priv = GET_PRIV (chooser);
570 *data = priv->image_data;
573 *data_size = priv->image_data_size;