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 "empathy-avatar-chooser.h"
33 #include "empathy-conf.h"
34 #include "empathy-ui-utils.h"
36 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
37 #include <libempathy/empathy-debug.h>
39 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_AVATAR_CHOOSER, EmpathyAvatarChooserPriv))
41 #define AVATAR_SIZE_SAVE 96
42 #define AVATAR_SIZE_VIEW 64
43 #define DEFAULT_DIR DATADIR"/pixmaps/faces"
47 gsize image_data_size;
48 } EmpathyAvatarChooserPriv;
50 static void avatar_chooser_finalize (GObject *object);
51 static void avatar_chooser_set_image_from_data (EmpathyAvatarChooser *chooser,
54 static gboolean avatar_chooser_drag_motion_cb (GtkWidget *widget,
55 GdkDragContext *context,
59 EmpathyAvatarChooser *chooser);
60 static void avatar_chooser_drag_leave_cb (GtkWidget *widget,
61 GdkDragContext *context,
63 EmpathyAvatarChooser *chooser);
64 static gboolean avatar_chooser_drag_drop_cb (GtkWidget *widget,
65 GdkDragContext *context,
69 EmpathyAvatarChooser *chooser);
70 static void avatar_chooser_drag_data_received_cb (GtkWidget *widget,
71 GdkDragContext *context,
74 GtkSelectionData *selection_data,
77 EmpathyAvatarChooser *chooser);
78 static void avatar_chooser_clicked_cb (GtkWidget *button,
79 EmpathyAvatarChooser *chooser);
86 static guint signals [LAST_SIGNAL];
88 G_DEFINE_TYPE (EmpathyAvatarChooser, empathy_avatar_chooser, GTK_TYPE_BUTTON);
93 #define URI_LIST_TYPE "text/uri-list"
96 DND_TARGET_TYPE_URI_LIST
99 static const GtkTargetEntry drop_types[] = {
100 { URI_LIST_TYPE, 0, DND_TARGET_TYPE_URI_LIST },
104 empathy_avatar_chooser_class_init (EmpathyAvatarChooserClass *klass)
106 GObjectClass *object_class = G_OBJECT_CLASS (klass);
108 object_class->finalize = avatar_chooser_finalize;
111 g_signal_new ("changed",
112 G_TYPE_FROM_CLASS (klass),
116 g_cclosure_marshal_VOID__VOID,
119 g_type_class_add_private (object_class, sizeof (EmpathyAvatarChooserPriv));
123 empathy_avatar_chooser_init (EmpathyAvatarChooser *chooser)
125 EmpathyAvatarChooserPriv *priv;
127 priv = GET_PRIV (chooser);
129 gtk_drag_dest_set (GTK_WIDGET (chooser),
130 GTK_DEST_DEFAULT_ALL,
132 G_N_ELEMENTS (drop_types),
135 g_signal_connect (chooser, "drag-motion",
136 G_CALLBACK (avatar_chooser_drag_motion_cb),
138 g_signal_connect (chooser, "drag-leave",
139 G_CALLBACK (avatar_chooser_drag_leave_cb),
141 g_signal_connect (chooser, "drag-drop",
142 G_CALLBACK (avatar_chooser_drag_drop_cb),
144 g_signal_connect (chooser, "drag-data-received",
145 G_CALLBACK (avatar_chooser_drag_data_received_cb),
147 g_signal_connect (chooser, "clicked",
148 G_CALLBACK (avatar_chooser_clicked_cb),
151 empathy_avatar_chooser_set (chooser, NULL);
155 avatar_chooser_finalize (GObject *object)
157 EmpathyAvatarChooserPriv *priv;
159 priv = GET_PRIV (object);
161 g_free (priv->image_data);
163 G_OBJECT_CLASS (empathy_avatar_chooser_parent_class)->finalize (object);
167 avatar_chooser_set_pixbuf (EmpathyAvatarChooser *chooser,
170 EmpathyAvatarChooserPriv *priv = GET_PRIV (chooser);
172 GdkPixbuf *pixbuf_view = NULL;
173 GdkPixbuf *pixbuf_save = NULL;
174 GError *error = NULL;
176 g_free (priv->image_data);
177 priv->image_data = NULL;
178 priv->image_data_size = 0;
181 pixbuf_view = empathy_pixbuf_scale_down_if_necessary (pixbuf, AVATAR_SIZE_VIEW);
182 pixbuf_save = empathy_pixbuf_scale_down_if_necessary (pixbuf, AVATAR_SIZE_SAVE);
184 if (!gdk_pixbuf_save_to_buffer (pixbuf_save,
186 &priv->image_data_size,
189 DEBUG ("Failed to save pixbuf: %s",
190 error ? error->message : "No error given");
191 g_clear_error (&error);
193 image = gtk_image_new_from_pixbuf (pixbuf_view);
195 g_object_unref (pixbuf_save);
196 g_object_unref (pixbuf_view);
198 image = gtk_image_new_from_icon_name ("stock_person",
199 GTK_ICON_SIZE_DIALOG);
202 gtk_button_set_image (GTK_BUTTON (chooser), image);
203 g_signal_emit (chooser, signals[CHANGED], 0);
207 avatar_chooser_set_image_from_file (EmpathyAvatarChooser *chooser,
208 const gchar *filename)
211 GError *error = NULL;
213 if (!(pixbuf = gdk_pixbuf_new_from_file (filename, &error))) {
214 DEBUG ("Failed to load pixbuf from file: %s",
215 error ? error->message : "No error given");
216 g_clear_error (&error);
219 avatar_chooser_set_pixbuf (chooser, pixbuf);
221 g_object_unref (pixbuf);
226 avatar_chooser_set_image_from_data (EmpathyAvatarChooser *chooser,
232 pixbuf = empathy_pixbuf_from_data (data, size);
233 avatar_chooser_set_pixbuf (chooser, pixbuf);
235 g_object_unref (pixbuf);
240 avatar_chooser_drag_motion_cb (GtkWidget *widget,
241 GdkDragContext *context,
245 EmpathyAvatarChooser *chooser)
247 EmpathyAvatarChooserPriv *priv;
250 priv = GET_PRIV (chooser);
252 for (p = context->targets; p != NULL; p = p->next) {
253 gchar *possible_type;
255 possible_type = gdk_atom_name (GDK_POINTER_TO_ATOM (p->data));
257 if (!strcmp (possible_type, URI_LIST_TYPE)) {
258 g_free (possible_type);
259 gdk_drag_status (context, GDK_ACTION_COPY, time);
264 g_free (possible_type);
271 avatar_chooser_drag_leave_cb (GtkWidget *widget,
272 GdkDragContext *context,
274 EmpathyAvatarChooser *chooser)
279 avatar_chooser_drag_drop_cb (GtkWidget *widget,
280 GdkDragContext *context,
284 EmpathyAvatarChooser *chooser)
286 EmpathyAvatarChooserPriv *priv;
289 priv = GET_PRIV (chooser);
291 if (context->targets == NULL) {
295 for (p = context->targets; p != NULL; p = p->next) {
298 possible_type = gdk_atom_name (GDK_POINTER_TO_ATOM (p->data));
299 if (!strcmp (possible_type, URI_LIST_TYPE)) {
300 g_free (possible_type);
301 gtk_drag_get_data (widget, context,
302 GDK_POINTER_TO_ATOM (p->data),
308 g_free (possible_type);
315 avatar_chooser_drag_data_received_cb (GtkWidget *widget,
316 GdkDragContext *context,
319 GtkSelectionData *selection_data,
322 EmpathyAvatarChooser *chooser)
325 gboolean handled = FALSE;
327 target_type = gdk_atom_name (selection_data->target);
328 if (!strcmp (target_type, URI_LIST_TYPE)) {
330 GFileInputStream *input_stream;
334 nl = strstr (selection_data->data, "\r\n");
338 uri = g_strndup (selection_data->data,
339 nl - (gchar*) selection_data->data);
341 file = g_file_new_for_uri (uri);
344 file = g_file_new_for_uri (selection_data->data);
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 if (bytes_read != -1) {
366 avatar_chooser_set_image_from_data (chooser,
373 g_object_unref (info);
376 g_object_unref (input_stream);
379 g_object_unref (file);
382 gtk_drag_finish (context, handled, FALSE, time);
386 avatar_chooser_update_preview_cb (GtkFileChooser *file_chooser,
387 EmpathyAvatarChooser *chooser)
391 filename = gtk_file_chooser_get_preview_filename (file_chooser);
395 GdkPixbuf *pixbuf = NULL;
396 GdkPixbuf *scaled_pixbuf;
398 pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
400 image = gtk_file_chooser_get_preview_widget (file_chooser);
403 scaled_pixbuf = empathy_pixbuf_scale_down_if_necessary (pixbuf, AVATAR_SIZE_SAVE);
404 gtk_image_set_from_pixbuf (GTK_IMAGE (image), scaled_pixbuf);
405 g_object_unref (scaled_pixbuf);
406 g_object_unref (pixbuf);
408 gtk_image_set_from_stock (GTK_IMAGE (image),
409 "gtk-dialog-question",
410 GTK_ICON_SIZE_DIALOG);
414 gtk_file_chooser_set_preview_widget_active (file_chooser, TRUE);
418 avatar_chooser_response_cb (GtkWidget *widget,
420 EmpathyAvatarChooser *chooser)
422 if (response == GTK_RESPONSE_OK) {
426 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));
427 avatar_chooser_set_image_from_file (chooser, filename);
430 path = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (widget));
432 empathy_conf_set_string (empathy_conf_get (),
433 EMPATHY_PREFS_UI_AVATAR_DIRECTORY,
438 else if (response == GTK_RESPONSE_NO) {
439 avatar_chooser_set_image_from_data (chooser, NULL, 0);
442 gtk_widget_destroy (widget);
446 avatar_chooser_clicked_cb (GtkWidget *button,
447 EmpathyAvatarChooser *chooser)
449 GtkFileChooser *chooser_dialog;
451 gchar *saved_dir = NULL;
452 const gchar *default_dir = DEFAULT_DIR;
453 const gchar *pics_dir;
454 GtkFileFilter *filter;
456 chooser_dialog = GTK_FILE_CHOOSER (
457 gtk_file_chooser_dialog_new (_("Select Your Avatar Image"),
458 empathy_get_toplevel_window (GTK_WIDGET (chooser)),
459 GTK_FILE_CHOOSER_ACTION_OPEN,
468 /* Get special dirs */
469 empathy_conf_get_string (empathy_conf_get (),
470 EMPATHY_PREFS_UI_AVATAR_DIRECTORY,
472 if (saved_dir && !g_file_test (saved_dir, G_FILE_TEST_IS_DIR)) {
476 if (!g_file_test (default_dir, G_FILE_TEST_IS_DIR)) {
479 pics_dir = g_get_user_special_dir (G_USER_DIRECTORY_PICTURES);
480 if (pics_dir && !g_file_test (pics_dir, G_FILE_TEST_IS_DIR)) {
484 /* Set current dir to the last one or to DEFAULT_DIR or to home */
486 gtk_file_chooser_set_current_folder (chooser_dialog, saved_dir);
489 gtk_file_chooser_set_current_folder (chooser_dialog, pics_dir);
491 else if (default_dir) {
492 gtk_file_chooser_set_current_folder (chooser_dialog, default_dir);
494 gtk_file_chooser_set_current_folder (chooser_dialog, g_get_home_dir ());
497 /* Add shortcuts to special dirs */
499 gtk_file_chooser_add_shortcut_folder (chooser_dialog, saved_dir, NULL);
502 gtk_file_chooser_add_shortcut_folder (chooser_dialog, pics_dir, NULL);
505 gtk_file_chooser_add_shortcut_folder (chooser_dialog, default_dir, NULL);
508 /* Setup preview image */
509 image = gtk_image_new ();
510 gtk_file_chooser_set_preview_widget (chooser_dialog, image);
511 gtk_widget_set_size_request (image, AVATAR_SIZE_SAVE, AVATAR_SIZE_SAVE);
512 gtk_widget_show (image);
513 gtk_file_chooser_set_use_preview_label (chooser_dialog, FALSE);
514 g_signal_connect (chooser_dialog, "update-preview",
515 G_CALLBACK (avatar_chooser_update_preview_cb),
519 filter = gtk_file_filter_new ();
520 gtk_file_filter_set_name (filter, _("Images"));
521 gtk_file_filter_add_pixbuf_formats (filter);
522 gtk_file_chooser_add_filter (chooser_dialog, filter);
523 filter = gtk_file_filter_new ();
524 gtk_file_filter_set_name (filter, _("All Files"));
525 gtk_file_filter_add_pattern(filter, "*");
526 gtk_file_chooser_add_filter (chooser_dialog, filter);
529 gtk_dialog_set_default_response (GTK_DIALOG (chooser_dialog), GTK_RESPONSE_OK);
530 g_signal_connect (chooser_dialog, "response",
531 G_CALLBACK (avatar_chooser_response_cb),
534 gtk_widget_show (GTK_WIDGET (chooser_dialog));
539 empathy_avatar_chooser_new (void)
541 return g_object_new (EMPATHY_TYPE_AVATAR_CHOOSER, NULL);
545 empathy_avatar_chooser_set (EmpathyAvatarChooser *chooser,
546 EmpathyAvatar *avatar)
548 g_return_if_fail (EMPATHY_IS_AVATAR_CHOOSER (chooser));
550 avatar_chooser_set_image_from_data (chooser,
551 avatar ? avatar->data : NULL,
552 avatar ? avatar->len : 0);
556 empathy_avatar_chooser_get_image_data (EmpathyAvatarChooser *chooser,
559 const gchar **mime_type)
561 EmpathyAvatarChooserPriv *priv;
563 g_return_if_fail (EMPATHY_IS_AVATAR_CHOOSER (chooser));
565 priv = GET_PRIV (chooser);
568 *data = priv->image_data;
571 *data_size = priv->image_data_size;