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., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301 USA
20 * Authors: Based on Novell's e-image-chooser.
21 * Xavier Claessens <xclaesse@gmail.com>
28 #include <glib/gi18n-lib.h>
32 #include <libempathy/empathy-gsettings.h>
33 #include <libempathy/empathy-utils.h>
35 #include "empathy-avatar-chooser.h"
36 #include "empathy-images.h"
37 #include "empathy-ui-utils.h"
39 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
40 #include <libempathy/empathy-debug.h>
43 * SECTION:empathy-avatar-chooser
44 * @title: EmpathyAvatarChooser
45 * @short_description: A widget used to change avatar
46 * @include: libempathy-gtk/empathy-avatar-chooser.h
48 * #EmpathyAvatarChooser is a widget which extends #GtkButton to
49 * provide a way of changing avatar.
53 * EmpathyAvatarChooser:
54 * @parent: parent object
56 * Widget which extends #GtkButton to provide a way of changing avatar.
59 #define AVATAR_SIZE_SAVE 96
60 #define AVATAR_SIZE_VIEW 64
61 #define DEFAULT_DIR DATADIR"/pixmaps/faces"
63 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyAvatarChooser)
65 TpConnection
*connection
;
66 GtkFileChooser
*chooser_dialog
;
68 gulong ready_handler_id
;
70 EmpathyAvatar
*avatar
;
71 } EmpathyAvatarChooserPriv
;
73 static void avatar_chooser_finalize (GObject
*object
);
74 static void avatar_chooser_set_connection (EmpathyAvatarChooser
*self
,
75 TpConnection
*connection
);
76 static void avatar_chooser_set_image (EmpathyAvatarChooser
*chooser
,
77 EmpathyAvatar
*avatar
,
79 gboolean set_locally
);
80 static gboolean
avatar_chooser_drag_motion_cb (GtkWidget
*widget
,
81 GdkDragContext
*context
,
85 EmpathyAvatarChooser
*chooser
);
86 static void avatar_chooser_drag_leave_cb (GtkWidget
*widget
,
87 GdkDragContext
*context
,
89 EmpathyAvatarChooser
*chooser
);
90 static gboolean
avatar_chooser_drag_drop_cb (GtkWidget
*widget
,
91 GdkDragContext
*context
,
95 EmpathyAvatarChooser
*chooser
);
96 static void avatar_chooser_drag_data_received_cb (GtkWidget
*widget
,
97 GdkDragContext
*context
,
100 GtkSelectionData
*selection_data
,
103 EmpathyAvatarChooser
*chooser
);
104 static void avatar_chooser_clicked_cb (GtkWidget
*button
,
105 EmpathyAvatarChooser
*chooser
);
117 static guint signals
[LAST_SIGNAL
];
119 G_DEFINE_TYPE (EmpathyAvatarChooser
, empathy_avatar_chooser
, GTK_TYPE_BUTTON
);
122 * Drag and drop stuff
124 #define URI_LIST_TYPE "text/uri-list"
127 DND_TARGET_TYPE_URI_LIST
130 static const GtkTargetEntry drop_types
[] = {
131 { URI_LIST_TYPE
, 0, DND_TARGET_TYPE_URI_LIST
},
135 avatar_chooser_get_property (GObject
*object
,
140 EmpathyAvatarChooserPriv
*priv
= GET_PRIV (object
);
143 case PROP_CONNECTION
:
144 g_value_set_object (value
, priv
->connection
);
147 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, param_id
, pspec
);
153 avatar_chooser_set_property (GObject
*object
,
158 EmpathyAvatarChooser
*self
= EMPATHY_AVATAR_CHOOSER (object
);
161 case PROP_CONNECTION
:
162 avatar_chooser_set_connection (self
, g_value_get_object (value
));
165 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, param_id
, pspec
);
171 empathy_avatar_chooser_class_init (EmpathyAvatarChooserClass
*klass
)
173 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
174 GParamSpec
*param_spec
;
176 object_class
->finalize
= avatar_chooser_finalize
;
177 object_class
->get_property
= avatar_chooser_get_property
;
178 object_class
->set_property
= avatar_chooser_set_property
;
181 * EmpathyAvatarChooser::changed:
182 * @chooser: an #EmpathyAvatarChooser
184 * Emitted when the chosen avatar has changed.
188 g_signal_new ("changed",
189 G_TYPE_FROM_CLASS (klass
),
193 g_cclosure_marshal_VOID__VOID
,
197 * EmpathyAvatarChooser:connection:
199 * The #TpConnection whose avatar should be shown and modified by
200 * the #EmpathyAvatarChooser instance.
202 param_spec
= g_param_spec_object ("connection",
204 "TpConnection whose avatar should be "
205 "shown and modified by this widget",
208 G_PARAM_STATIC_STRINGS
);
209 g_object_class_install_property (object_class
,
213 g_type_class_add_private (object_class
, sizeof (EmpathyAvatarChooserPriv
));
217 empathy_avatar_chooser_init (EmpathyAvatarChooser
*chooser
)
219 EmpathyAvatarChooserPriv
*priv
= G_TYPE_INSTANCE_GET_PRIVATE (chooser
,
220 EMPATHY_TYPE_AVATAR_CHOOSER
, EmpathyAvatarChooserPriv
);
222 chooser
->priv
= priv
;
223 gtk_drag_dest_set (GTK_WIDGET (chooser
),
224 GTK_DEST_DEFAULT_ALL
,
226 G_N_ELEMENTS (drop_types
),
229 g_signal_connect (chooser
, "drag-motion",
230 G_CALLBACK (avatar_chooser_drag_motion_cb
),
232 g_signal_connect (chooser
, "drag-leave",
233 G_CALLBACK (avatar_chooser_drag_leave_cb
),
235 g_signal_connect (chooser
, "drag-drop",
236 G_CALLBACK (avatar_chooser_drag_drop_cb
),
238 g_signal_connect (chooser
, "drag-data-received",
239 G_CALLBACK (avatar_chooser_drag_data_received_cb
),
241 g_signal_connect (chooser
, "clicked",
242 G_CALLBACK (avatar_chooser_clicked_cb
),
245 empathy_avatar_chooser_set (chooser
, NULL
);
249 avatar_chooser_finalize (GObject
*object
)
251 EmpathyAvatarChooserPriv
*priv
;
253 priv
= GET_PRIV (object
);
255 avatar_chooser_set_connection (EMPATHY_AVATAR_CHOOSER (object
), NULL
);
256 g_assert (priv
->connection
== NULL
);
258 if (priv
->avatar
!= NULL
) {
259 empathy_avatar_unref (priv
->avatar
);
262 G_OBJECT_CLASS (empathy_avatar_chooser_parent_class
)->finalize (object
);
266 avatar_chooser_set_connection (EmpathyAvatarChooser
*self
,
267 TpConnection
*connection
)
269 EmpathyAvatarChooserPriv
*priv
= GET_PRIV (self
);
271 if (priv
->connection
!= NULL
) {
272 g_object_unref (priv
->connection
);
273 priv
->connection
= NULL
;
276 if (connection
!= NULL
) {
277 GQuark features
[] = { TP_CONNECTION_FEATURE_AVATAR_REQUIREMENTS
, 0 };
278 priv
->connection
= g_object_ref (connection
);
279 tp_proxy_prepare_async (priv
->connection
, features
, NULL
, NULL
);
284 avatar_chooser_error_show (EmpathyAvatarChooser
*chooser
,
285 const gchar
*primary_text
,
286 const gchar
*secondary_text
)
291 parent
= gtk_widget_get_toplevel (GTK_WIDGET (chooser
));
292 if (!GTK_IS_WINDOW (parent
)) {
296 dialog
= gtk_message_dialog_new (parent
? GTK_WINDOW (parent
) : NULL
,
302 if (secondary_text
!= NULL
) {
303 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog
),
304 "%s", secondary_text
);
307 g_signal_connect (dialog
, "response",
308 G_CALLBACK (gtk_widget_destroy
), NULL
);
309 gtk_widget_show (dialog
);
314 str_in_strv (const gchar
*str
,
321 while (*strv
!= NULL
) {
322 if (g_str_equal (str
, *strv
)) {
330 /* The caller must free the strings stored in satisfactory_format_name and
331 * satisfactory_mime_type.
334 avatar_chooser_need_mime_type_conversion (const gchar
*current_mime_type
,
335 gchar
**accepted_mime_types
,
336 gchar
**satisfactory_format_name
,
337 gchar
**satisfactory_mime_type
)
339 gchar
*good_mime_types
[] = {"image/jpeg", "image/png", NULL
};
342 gboolean found
= FALSE
;
344 *satisfactory_format_name
= NULL
;
345 *satisfactory_mime_type
= NULL
;
347 /* If there is no accepted format there is nothing we can do */
348 if (accepted_mime_types
== NULL
|| *accepted_mime_types
== NULL
) {
352 /* If the current mime type is good and accepted, don't change it!
353 * jpeg is compress better pictures, but png is better for logos and
354 * could have an alpha layer. */
355 if (str_in_strv (current_mime_type
, good_mime_types
) &&
356 str_in_strv (current_mime_type
, accepted_mime_types
)) {
357 *satisfactory_mime_type
= g_strdup (current_mime_type
);
358 *satisfactory_format_name
= g_strdup (current_mime_type
+
363 /* The current mime type is either not accepted or not good to use.
364 * Check if one of the good format is supported... */
365 for (i
= 0; good_mime_types
[i
] != NULL
; i
++) {
366 if (str_in_strv (good_mime_types
[i
], accepted_mime_types
)) {
367 *satisfactory_mime_type
= g_strdup (good_mime_types
[i
]);
368 *satisfactory_format_name
= g_strdup (good_mime_types
[i
] +
374 /* Pick the first supported format we can write */
375 formats
= gdk_pixbuf_get_formats ();
376 for (l
= formats
; !found
&& l
!= NULL
; l
= l
->next
) {
377 GdkPixbufFormat
*format
= l
->data
;
378 gchar
**format_mime_types
;
381 if (!gdk_pixbuf_format_is_writable (format
)) {
385 format_mime_types
= gdk_pixbuf_format_get_mime_types (format
);
386 for (iter
= format_mime_types
; *iter
!= NULL
; iter
++) {
387 if (str_in_strv (*iter
, accepted_mime_types
)) {
388 *satisfactory_format_name
= gdk_pixbuf_format_get_name (format
);
389 *satisfactory_mime_type
= g_strdup (*iter
);
394 g_strfreev (format_mime_types
);
396 g_slist_free (formats
);
401 static EmpathyAvatar
*
402 avatar_chooser_maybe_convert_and_scale (EmpathyAvatarChooser
*chooser
,
404 EmpathyAvatar
*avatar
)
406 EmpathyAvatarChooserPriv
*priv
= GET_PRIV (chooser
);
407 TpAvatarRequirements
*req
;
408 gboolean needs_conversion
= FALSE
;
410 gchar
*new_format_name
= NULL
;
411 gchar
*new_mime_type
= NULL
;
412 gdouble min_factor
, max_factor
;
414 gchar
*best_image_data
= NULL
;
415 gsize best_image_size
= 0;
418 req
= tp_connection_get_avatar_requirements (priv
->connection
);
420 DEBUG ("Avatar requirements not ready");
424 /* Smaller is the factor, smaller will be the image.
425 * 0 is an empty image, 1 is the full size. */
430 /* Check if we need to convert to another image format */
431 if (avatar_chooser_need_mime_type_conversion (avatar
->format
,
432 req
->supported_mime_types
,
435 DEBUG ("Format conversion needed, we'll use mime type '%s' "
436 "and format name '%s'. Current mime type is '%s'",
437 new_mime_type
, new_format_name
, avatar
->format
);
438 needs_conversion
= TRUE
;
441 /* If there is no format we can use, report error to the user. */
442 if (new_mime_type
== NULL
|| new_format_name
== NULL
) {
443 avatar_chooser_error_show (chooser
, _("Couldn't convert image"),
444 _("None of the accepted image formats are "
445 "supported on your system"));
449 /* If width or height are too big, it needs converting. */
450 width
= gdk_pixbuf_get_width (pixbuf
);
451 height
= gdk_pixbuf_get_height (pixbuf
);
452 if ((req
->maximum_width
> 0 && width
> req
->maximum_width
) ||
453 (req
->maximum_height
> 0 && height
> req
->maximum_height
)) {
454 gdouble h_factor
, v_factor
;
456 h_factor
= (gdouble
) req
->maximum_width
/ width
;
457 v_factor
= (gdouble
) req
->maximum_height
/ height
;
458 factor
= max_factor
= MIN (h_factor
, v_factor
);
460 DEBUG ("Image dimensions (%dx%d) are too big. Max is %dx%d.",
461 width
, height
, req
->maximum_width
, req
->maximum_height
);
463 needs_conversion
= TRUE
;
466 /* If the data len is too big and no other conversion is needed,
467 * try with a lower factor. */
468 if (req
->maximum_bytes
> 0 && avatar
->len
> req
->maximum_bytes
&& !needs_conversion
) {
469 DEBUG ("Image data (%"G_GSIZE_FORMAT
" bytes) is too big "
470 "(max is %u bytes), conversion needed.",
471 avatar
->len
, req
->maximum_bytes
);
474 needs_conversion
= TRUE
;
477 /* If no conversion is needed, return the avatar */
478 if (!needs_conversion
) {
479 g_free (new_format_name
);
480 g_free (new_mime_type
);
481 return empathy_avatar_ref (avatar
);
485 GdkPixbuf
*pixbuf_scaled
= NULL
;
487 gint new_width
, new_height
;
488 gchar
*converted_image_data
;
489 gsize converted_image_size
;
490 GError
*error
= NULL
;
493 new_width
= width
* factor
;
494 new_height
= height
* factor
;
495 pixbuf_scaled
= gdk_pixbuf_scale_simple (pixbuf
,
502 pixbuf_scaled
= g_object_ref (pixbuf
);
505 DEBUG ("Trying with factor %f (%dx%d) and format %s...", factor
,
506 new_width
, new_height
, new_format_name
);
508 saved
= gdk_pixbuf_save_to_buffer (pixbuf_scaled
,
509 &converted_image_data
,
510 &converted_image_size
,
513 g_object_unref (pixbuf_scaled
);
516 g_free (new_format_name
);
517 g_free (new_mime_type
);
518 avatar_chooser_error_show (chooser
,
519 _("Couldn't convert image"),
520 error
? error
->message
: NULL
);
521 g_clear_error (&error
);
525 DEBUG ("Produced an image data of %"G_GSIZE_FORMAT
" bytes.",
526 converted_image_size
);
528 /* If the new image satisfy the req, keep it as current best */
529 if (req
->maximum_bytes
== 0 ||
530 converted_image_size
<= req
->maximum_bytes
) {
532 g_free (best_image_data
);
534 best_image_data
= converted_image_data
;
535 best_image_size
= converted_image_size
;
537 /* If this image is close enough to the optimal size,
539 if (req
->maximum_bytes
== 0 ||
540 req
->maximum_bytes
- converted_image_size
<= 1024)
543 g_free (converted_image_data
);
546 /* Make a binary search for the bigest factor that produce
547 * an image data size less than max_size */
548 if (converted_image_size
> req
->maximum_bytes
)
550 if (converted_image_size
< req
->maximum_bytes
)
552 factor
= (min_factor
+ max_factor
)/2;
554 if ((int) (width
* factor
) == new_width
||
555 (int) (height
* factor
) == new_height
) {
556 /* min_factor and max_factor are too close, so the new
557 * factor will produce the same image as previous
558 * iteration. No need to continue, we already found
559 * the optimal size. */
563 /* Do 10 iterations in the worst case */
564 } while (++count
< 10);
566 g_free (new_format_name
);
568 /* Takes ownership of new_mime_type and best_image_data */
569 avatar
= empathy_avatar_new ((guchar
*) best_image_data
,
570 best_image_size
, new_mime_type
, NULL
, NULL
);
576 avatar_chooser_clear_image (EmpathyAvatarChooser
*chooser
)
578 EmpathyAvatarChooserPriv
*priv
= GET_PRIV (chooser
);
581 if (priv
->avatar
!= NULL
) {
582 empathy_avatar_unref (priv
->avatar
);
586 image
= gtk_image_new_from_icon_name (EMPATHY_IMAGE_AVATAR_DEFAULT
,
587 GTK_ICON_SIZE_DIALOG
);
588 gtk_button_set_image (GTK_BUTTON (chooser
), image
);
589 g_signal_emit (chooser
, signals
[CHANGED
], 0);
593 avatar_chooser_set_image_from_data (EmpathyAvatarChooser
*chooser
,
596 gboolean set_locally
)
599 EmpathyAvatar
*avatar
= NULL
;
600 gchar
*mime_type
= NULL
;
603 avatar_chooser_clear_image (chooser
);
607 pixbuf
= empathy_pixbuf_from_data_and_mime (data
, size
, &mime_type
);
608 if (pixbuf
== NULL
) {
614 /* avatar takes ownership of data and mime_type */
615 avatar
= empathy_avatar_new ((guchar
*) data
, size
, mime_type
, NULL
, NULL
);
617 avatar_chooser_set_image (chooser
, avatar
, pixbuf
, set_locally
);
621 avatar_chooser_set_image_from_avatar (EmpathyAvatarChooser
*chooser
,
622 EmpathyAvatar
*avatar
,
623 gboolean set_locally
)
626 gchar
*mime_type
= NULL
;
628 g_assert (avatar
!= NULL
);
630 pixbuf
= empathy_pixbuf_from_data_and_mime ((gchar
*) avatar
->data
,
633 if (pixbuf
== NULL
) {
634 DEBUG ("couldn't make a pixbuf from avatar; giving up");
638 if (avatar
->format
== NULL
) {
639 avatar
->format
= mime_type
;
641 if (strcmp (mime_type
, avatar
->format
)) {
642 DEBUG ("avatar->format is %s; gdkpixbuf yields %s!",
643 avatar
->format
, mime_type
);
648 empathy_avatar_ref (avatar
);
650 avatar_chooser_set_image (chooser
, avatar
, pixbuf
, set_locally
);
654 avatar_chooser_set_image (EmpathyAvatarChooser
*chooser
,
655 EmpathyAvatar
*avatar
,
657 gboolean set_locally
)
659 EmpathyAvatarChooserPriv
*priv
= GET_PRIV (chooser
);
660 GdkPixbuf
*pixbuf_view
;
663 g_assert (avatar
!= NULL
);
664 g_assert (pixbuf
!= NULL
);
669 conv
= avatar_chooser_maybe_convert_and_scale (chooser
,
671 empathy_avatar_unref (avatar
);
674 /* An error occured; don't change the avatar. */
681 if (priv
->avatar
!= NULL
) {
682 empathy_avatar_unref (priv
->avatar
);
684 priv
->avatar
= avatar
;
686 pixbuf_view
= empathy_pixbuf_scale_down_if_necessary (pixbuf
, AVATAR_SIZE_VIEW
);
687 image
= gtk_image_new_from_pixbuf (pixbuf_view
);
689 gtk_button_set_image (GTK_BUTTON (chooser
), image
);
690 g_signal_emit (chooser
, signals
[CHANGED
], 0);
692 g_object_unref (pixbuf_view
);
693 g_object_unref (pixbuf
);
697 avatar_chooser_set_image_from_file (EmpathyAvatarChooser
*chooser
,
698 const gchar
*filename
)
700 gchar
*image_data
= NULL
;
701 gsize image_size
= 0;
702 GError
*error
= NULL
;
704 if (!g_file_get_contents (filename
, &image_data
, &image_size
, &error
)) {
705 DEBUG ("Failed to load image from '%s': %s", filename
,
706 error
? error
->message
: "No error given");
708 g_clear_error (&error
);
712 avatar_chooser_set_image_from_data (chooser
, image_data
, image_size
, TRUE
);
716 avatar_chooser_drag_motion_cb (GtkWidget
*widget
,
717 GdkDragContext
*context
,
721 EmpathyAvatarChooser
*chooser
)
723 EmpathyAvatarChooserPriv
*priv
;
726 priv
= GET_PRIV (chooser
);
728 for (p
= gdk_drag_context_list_targets (context
); p
!= NULL
;
730 gchar
*possible_type
;
732 possible_type
= gdk_atom_name (GDK_POINTER_TO_ATOM (p
->data
));
734 if (!strcmp (possible_type
, URI_LIST_TYPE
)) {
735 g_free (possible_type
);
736 gdk_drag_status (context
, GDK_ACTION_COPY
, time_
);
741 g_free (possible_type
);
748 avatar_chooser_drag_leave_cb (GtkWidget
*widget
,
749 GdkDragContext
*context
,
751 EmpathyAvatarChooser
*chooser
)
756 avatar_chooser_drag_drop_cb (GtkWidget
*widget
,
757 GdkDragContext
*context
,
761 EmpathyAvatarChooser
*chooser
)
763 EmpathyAvatarChooserPriv
*priv
;
766 priv
= GET_PRIV (chooser
);
768 if (gdk_drag_context_list_targets (context
) == NULL
) {
772 for (p
= gdk_drag_context_list_targets (context
);
773 p
!= NULL
; p
= p
->next
) {
776 possible_type
= gdk_atom_name (GDK_POINTER_TO_ATOM (p
->data
));
777 if (!strcmp (possible_type
, URI_LIST_TYPE
)) {
778 g_free (possible_type
);
779 gtk_drag_get_data (widget
, context
,
780 GDK_POINTER_TO_ATOM (p
->data
),
786 g_free (possible_type
);
793 avatar_chooser_drag_data_received_cb (GtkWidget
*widget
,
794 GdkDragContext
*context
,
797 GtkSelectionData
*selection_data
,
800 EmpathyAvatarChooser
*chooser
)
803 gboolean handled
= FALSE
;
805 target_type
= gdk_atom_name (gtk_selection_data_get_target (selection_data
));
806 if (!strcmp (target_type
, URI_LIST_TYPE
)) {
812 nl
= strstr ((gchar
*) gtk_selection_data_get_data (selection_data
),
817 uri
= g_strndup ((gchar
*) gtk_selection_data_get_data (selection_data
),
818 nl
- (gchar
*) gtk_selection_data_get_data (selection_data
));
820 file
= g_file_new_for_uri (uri
);
823 file
= g_file_new_for_uri ((gchar
*) gtk_selection_data_get_data (
827 handled
= g_file_load_contents (file
, NULL
, &data
, &bytes_read
,
831 /* this in turn calls empathy_avatar_new (), which assumes
834 avatar_chooser_set_image_from_data (chooser
, data
,
839 g_object_unref (file
);
842 gtk_drag_finish (context
, handled
, FALSE
, time_
);
846 avatar_chooser_update_preview_cb (GtkFileChooser
*file_chooser
,
847 EmpathyAvatarChooser
*chooser
)
851 filename
= gtk_file_chooser_get_preview_filename (file_chooser
);
855 GdkPixbuf
*pixbuf
= NULL
;
856 GdkPixbuf
*scaled_pixbuf
;
858 pixbuf
= gdk_pixbuf_new_from_file (filename
, NULL
);
860 image
= gtk_file_chooser_get_preview_widget (file_chooser
);
863 scaled_pixbuf
= empathy_pixbuf_scale_down_if_necessary (pixbuf
, AVATAR_SIZE_SAVE
);
864 gtk_image_set_from_pixbuf (GTK_IMAGE (image
), scaled_pixbuf
);
865 g_object_unref (scaled_pixbuf
);
866 g_object_unref (pixbuf
);
868 gtk_image_set_from_stock (GTK_IMAGE (image
),
869 "gtk-dialog-question",
870 GTK_ICON_SIZE_DIALOG
);
876 gtk_file_chooser_set_preview_widget_active (file_chooser
, TRUE
);
880 avatar_chooser_response_cb (GtkWidget
*widget
,
882 EmpathyAvatarChooser
*chooser
)
884 EmpathyAvatarChooserPriv
*priv
= GET_PRIV (chooser
);
886 priv
->chooser_dialog
= NULL
;
888 if (response
== GTK_RESPONSE_OK
) {
892 filename
= gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget
));
893 avatar_chooser_set_image_from_file (chooser
, filename
);
896 path
= gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (widget
));
898 GSettings
*gsettings_ui
= g_settings_new (EMPATHY_PREFS_UI_SCHEMA
);
900 g_settings_set_string (gsettings_ui
,
901 EMPATHY_PREFS_UI_AVATAR_DIRECTORY
,
905 g_object_unref (gsettings_ui
);
908 else if (response
== GTK_RESPONSE_NO
) {
909 /* This corresponds to "No Image", not to "Cancel" */
910 avatar_chooser_clear_image (chooser
);
913 gtk_widget_destroy (widget
);
917 avatar_chooser_clicked_cb (GtkWidget
*button
,
918 EmpathyAvatarChooser
*chooser
)
920 GtkFileChooser
*chooser_dialog
;
922 gchar
*saved_dir
= NULL
;
923 const gchar
*default_dir
= DEFAULT_DIR
;
924 const gchar
*pics_dir
;
925 GtkFileFilter
*filter
;
926 GSettings
*gsettings_ui
= g_settings_new (EMPATHY_PREFS_UI_SCHEMA
);
927 EmpathyAvatarChooserPriv
*priv
= GET_PRIV (chooser
);
929 if (priv
->chooser_dialog
) {
930 gtk_window_present (GTK_WINDOW (priv
->chooser_dialog
));
934 priv
->chooser_dialog
= GTK_FILE_CHOOSER (
935 gtk_file_chooser_dialog_new (_("Select Your Avatar Image"),
936 empathy_get_toplevel_window (GTK_WIDGET (chooser
)),
937 GTK_FILE_CHOOSER_ACTION_OPEN
,
945 chooser_dialog
= priv
->chooser_dialog
;
946 gtk_window_set_destroy_with_parent (GTK_WINDOW (chooser_dialog
), TRUE
);
948 /* Get special dirs */
949 saved_dir
= g_settings_get_string (gsettings_ui
,
950 EMPATHY_PREFS_UI_AVATAR_DIRECTORY
);
952 if (saved_dir
&& !g_file_test (saved_dir
, G_FILE_TEST_IS_DIR
)) {
956 if (!g_file_test (default_dir
, G_FILE_TEST_IS_DIR
)) {
959 pics_dir
= g_get_user_special_dir (G_USER_DIRECTORY_PICTURES
);
960 if (pics_dir
&& !g_file_test (pics_dir
, G_FILE_TEST_IS_DIR
)) {
964 /* Set current dir to the last one or to DEFAULT_DIR or to home */
966 gtk_file_chooser_set_current_folder (chooser_dialog
, saved_dir
);
969 gtk_file_chooser_set_current_folder (chooser_dialog
, pics_dir
);
971 else if (default_dir
) {
972 gtk_file_chooser_set_current_folder (chooser_dialog
, default_dir
);
974 gtk_file_chooser_set_current_folder (chooser_dialog
, g_get_home_dir ());
977 /* Add shortcuts to special dirs */
979 gtk_file_chooser_add_shortcut_folder (chooser_dialog
, saved_dir
, NULL
);
982 gtk_file_chooser_add_shortcut_folder (chooser_dialog
, pics_dir
, NULL
);
985 gtk_file_chooser_add_shortcut_folder (chooser_dialog
, default_dir
, NULL
);
988 /* Setup preview image */
989 image
= gtk_image_new ();
990 gtk_file_chooser_set_preview_widget (chooser_dialog
, image
);
991 gtk_widget_set_size_request (image
, AVATAR_SIZE_SAVE
, AVATAR_SIZE_SAVE
);
992 gtk_widget_show (image
);
993 gtk_file_chooser_set_use_preview_label (chooser_dialog
, FALSE
);
994 g_signal_connect (chooser_dialog
, "update-preview",
995 G_CALLBACK (avatar_chooser_update_preview_cb
),
999 filter
= gtk_file_filter_new ();
1000 gtk_file_filter_set_name (filter
, _("Images"));
1001 gtk_file_filter_add_pixbuf_formats (filter
);
1002 gtk_file_chooser_add_filter (chooser_dialog
, filter
);
1003 filter
= gtk_file_filter_new ();
1004 gtk_file_filter_set_name (filter
, _("All Files"));
1005 gtk_file_filter_add_pattern (filter
, "*");
1006 gtk_file_chooser_add_filter (chooser_dialog
, filter
);
1008 /* Setup response */
1009 gtk_dialog_set_default_response (GTK_DIALOG (chooser_dialog
), GTK_RESPONSE_OK
);
1010 g_signal_connect (chooser_dialog
, "response",
1011 G_CALLBACK (avatar_chooser_response_cb
),
1014 gtk_widget_show (GTK_WIDGET (chooser_dialog
));
1017 g_object_unref (gsettings_ui
);
1021 * empathy_avatar_chooser_new:
1023 * Creates a new #EmpathyAvatarChooser.
1025 * Return value: a new #EmpathyAvatarChooser
1028 empathy_avatar_chooser_new ()
1030 return g_object_new (EMPATHY_TYPE_AVATAR_CHOOSER
, NULL
);
1034 * empathy_avatar_chooser_set:
1035 * @chooser: an #EmpathyAvatarChooser
1036 * @avatar: a new #EmpathyAvatar
1038 * Sets the @chooser to display the avatar indicated by @avatar.
1041 empathy_avatar_chooser_set (EmpathyAvatarChooser
*chooser
,
1042 EmpathyAvatar
*avatar
)
1044 g_return_if_fail (EMPATHY_IS_AVATAR_CHOOSER (chooser
));
1046 if (avatar
!= NULL
) {
1047 avatar_chooser_set_image_from_avatar (chooser
, avatar
, FALSE
);
1049 avatar_chooser_clear_image (chooser
);
1054 * empathy_avatar_chooser_get_image_data:
1055 * @chooser: an #EmpathyAvatarChooser
1056 * @data: avatar bytes
1057 * @data_size: size of @data
1058 * @mime_type: avatar mime-type
1060 * Gets image data about the currently selected avatar.
1063 empathy_avatar_chooser_get_image_data (EmpathyAvatarChooser
*chooser
,
1066 const gchar
**mime_type
)
1068 EmpathyAvatarChooserPriv
*priv
;
1070 g_return_if_fail (EMPATHY_IS_AVATAR_CHOOSER (chooser
));
1072 priv
= GET_PRIV (chooser
);
1074 if (priv
->avatar
!= NULL
) {
1076 *data
= (gchar
*) priv
->avatar
->data
;
1078 if (data_size
!= NULL
) {
1079 *data_size
= priv
->avatar
->len
;
1081 if (mime_type
!= NULL
) {
1082 *mime_type
= priv
->avatar
->format
;
1088 if (data_size
!= NULL
) {
1091 if (mime_type
!= NULL
) {
1098 empathy_avatar_chooser_set_account (EmpathyAvatarChooser
*self
,
1101 g_return_if_fail (account
!= NULL
);
1103 avatar_chooser_set_connection (self
, tp_account_get_connection (account
));
1104 g_object_notify (G_OBJECT (self
), "connection");