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>
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)) {
333 GFileInputStream *input_stream;
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 file = g_file_new_for_uri (uri);
347 input_stream = g_file_read (file, NULL, NULL);
349 if (input_stream != NULL) {
352 info = g_file_query_info (file,
353 G_FILE_ATTRIBUTE_STANDARD_SIZE,
359 size = g_file_info_get_size (info);
360 data = g_malloc (size);
362 bytes_read = g_input_stream_read (G_INPUT_STREAM (input_stream),
365 g_object_unref (info);
366 if (bytes_read != -1) {
367 avatar_chooser_set_image_from_data (chooser,
376 g_input_stream_close (G_INPUT_STREAM (input_stream), NULL, NULL);
379 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;