1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2003-2007 Imendio AB
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
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 program; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301 USA
20 * Authors: Mikael Hallendal <micke@imendio.com>
21 * Richard Hult <richard@imendio.com>
22 * Martyn Russell <martyn@imendio.com>
23 * Danielle Madeley <danielle.madeley@collabora.co.uk>
32 #include <glib/gi18n.h>
33 #include <telepathy-glib/dbus.h>
34 #include <telepathy-glib/util.h>
36 #include <libempathy/empathy-gsettings.h>
37 #include <libempathy/empathy-utils.h>
39 #include <libempathy-gtk/empathy-ui-utils.h>
40 #include <libempathy-gtk/empathy-theme-manager.h>
41 #include <libempathy-gtk/empathy-spell.h>
42 #include <libempathy-gtk/empathy-gtk-enum-types.h>
43 #include <libempathy-gtk/empathy-theme-adium.h>
45 #include "empathy-preferences.h"
47 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
48 #include <libempathy/empathy-debug.h>
50 G_DEFINE_TYPE (EmpathyPreferences, empathy_preferences, GTK_TYPE_DIALOG);
52 #define GET_PRIV(self) ((EmpathyPreferencesPriv *)((EmpathyPreferences *) self)->priv)
54 static const gchar * empathy_preferences_tabs[] =
65 struct _EmpathyPreferencesPriv {
68 GtkWidget *checkbutton_events_notif_area;
70 GtkWidget *treeview_sounds;
71 GtkWidget *treeview_spell_checker;
73 GtkWidget *vbox_chat_theme;
74 GtkWidget *combobox_chat_theme;
75 GtkWidget *combobox_chat_theme_variant;
76 GtkWidget *hbox_chat_theme_variant;
77 GtkWidget *sw_chat_theme_preview;
78 EmpathyChatView *chat_theme_preview;
79 EmpathyThemeManager *theme_manager;
82 GSettings *gsettings_chat;
83 GSettings *gsettings_call;
84 GSettings *gsettings_loc;
85 GSettings *gsettings_notify;
86 GSettings *gsettings_sound;
87 GSettings *gsettings_ui;
88 GSettings *gsettings_logger;
89 GSettings *gsettings_contacts;
92 static void preferences_setup_widgets (EmpathyPreferences *preferences,
94 static void preferences_languages_setup (EmpathyPreferences *preferences);
95 static void preferences_languages_add (EmpathyPreferences *preferences);
96 static void preferences_languages_save (EmpathyPreferences *preferences);
97 static gboolean preferences_languages_save_foreach (GtkTreeModel *model,
101 static void preferences_languages_load (EmpathyPreferences *preferences);
102 static gboolean preferences_languages_load_foreach (GtkTreeModel *model,
106 static void preferences_languages_cell_toggled_cb (GtkCellRendererToggle *cell,
108 EmpathyPreferences *preferences);
118 COL_THEME_VISIBLE_NAME,
121 COL_THEME_ADIUM_PATH,
122 COL_THEME_ADIUM_INFO,
144 /* TODO: add phone related sounds also? */
145 static SoundEventEntry sound_entries [] = {
146 { N_("Message received"), EMPATHY_PREFS_SOUNDS_INCOMING_MESSAGE },
147 { N_("Message sent"), EMPATHY_PREFS_SOUNDS_OUTGOING_MESSAGE },
148 { N_("New conversation"), EMPATHY_PREFS_SOUNDS_NEW_CONVERSATION },
149 { N_("Contact comes online"), EMPATHY_PREFS_SOUNDS_CONTACT_LOGIN },
150 { N_("Contact goes offline"), EMPATHY_PREFS_SOUNDS_CONTACT_LOGOUT },
151 { N_("Account connected"), EMPATHY_PREFS_SOUNDS_SERVICE_LOGIN },
152 { N_("Account disconnected"), EMPATHY_PREFS_SOUNDS_SERVICE_LOGOUT }
156 sort_criterium_get_mapping (GValue *value,
160 const char *s = g_variant_get_string (variant, NULL);
162 if (!tp_strdiff (s, "state"))
163 g_value_set_boolean (value, TRUE);
164 else if (!tp_strdiff (s, "name"))
165 g_value_set_boolean (value, FALSE);
173 sort_criterium_set_mapping (const GValue *value,
174 const GVariantType *expected_type,
177 gboolean b = g_value_get_boolean (value);
180 return g_variant_new_string ("state");
182 return g_variant_new_string ("name");
186 preferences_setup_widgets (EmpathyPreferences *preferences,
189 EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
190 #define BIND_ACTIVE(schema, key, widget) \
191 g_settings_bind (priv->gsettings_##schema, EMPATHY_PREFS_##key, \
192 gtk_builder_get_object (gui, widget), "active", \
193 G_SETTINGS_BIND_DEFAULT);
195 BIND_ACTIVE (notify, NOTIFICATIONS_ENABLED,
196 "checkbutton_notifications_enabled");
197 BIND_ACTIVE (notify, NOTIFICATIONS_DISABLED_AWAY,
198 "checkbutton_notifications_disabled_away");
199 BIND_ACTIVE (notify, NOTIFICATIONS_FOCUS,
200 "checkbutton_notifications_focus");
201 BIND_ACTIVE (notify, NOTIFICATIONS_CONTACT_SIGNIN,
202 "checkbutton_notifications_contact_signin");
203 BIND_ACTIVE (notify, NOTIFICATIONS_CONTACT_SIGNOUT,
204 "checkbutton_notifications_contact_signout");
206 BIND_ACTIVE (sound, SOUNDS_ENABLED,
207 "checkbutton_sounds_enabled");
208 BIND_ACTIVE (sound, SOUNDS_DISABLED_AWAY,
209 "checkbutton_sounds_disabled_away");
211 BIND_ACTIVE (ui, UI_SHOW_OFFLINE,
212 "checkbutton_show_offline");
213 BIND_ACTIVE (ui, UI_SHOW_PROTOCOLS,
214 "checkbutton_show_protocols");
215 BIND_ACTIVE (ui, UI_SEPARATE_CHAT_WINDOWS,
216 "radiobutton_chats_new_windows");
217 BIND_ACTIVE (ui, UI_EVENTS_NOTIFY_AREA,
218 "checkbutton_events_notif_area");
219 BIND_ACTIVE (ui, UI_SHOW_AVATARS,
220 "radiobutton_normal_size_avatars");
221 BIND_ACTIVE (ui, UI_COMPACT_CONTACT_LIST,
222 "radiobutton_compact_size");
224 BIND_ACTIVE (chat, CHAT_SHOW_SMILEYS,
225 "checkbutton_show_smileys");
226 BIND_ACTIVE (chat, CHAT_SHOW_CONTACTS_IN_ROOMS,
227 "checkbutton_show_contacts_in_rooms");
229 BIND_ACTIVE (call, CALL_ECHO_CANCELLATION,
230 "call_echo_cancellation");
232 BIND_ACTIVE (loc, LOCATION_PUBLISH,
233 "checkbutton_location_publish");
234 BIND_ACTIVE (loc, LOCATION_RESOURCE_NETWORK,
235 "checkbutton_location_resource_network");
236 BIND_ACTIVE (loc, LOCATION_RESOURCE_CELL,
237 "checkbutton_location_resource_cell");
238 BIND_ACTIVE (loc, LOCATION_RESOURCE_GPS,
239 "checkbutton_location_resource_gps");
240 BIND_ACTIVE (loc, LOCATION_REDUCE_ACCURACY,
241 "checkbutton_location_reduce_accuracy");
243 BIND_ACTIVE (logger, LOGGER_ENABLED,
244 "checkbutton_logging");
248 #define BIND_SENSITIVE(schema, key, widget) \
249 g_settings_bind (priv->gsettings_##schema, EMPATHY_PREFS_##key, \
250 gtk_builder_get_object (gui, widget), "sensitive", \
251 G_SETTINGS_BIND_GET);
252 /* N.B. BIND_SENSITIVE() is in addition to the sensitivity setting of
254 BIND_SENSITIVE (notify, NOTIFICATIONS_ENABLED,
255 "checkbutton_notifications_disabled_away");
256 BIND_SENSITIVE (notify, NOTIFICATIONS_ENABLED,
257 "checkbutton_notifications_focus");
258 BIND_SENSITIVE (notify, NOTIFICATIONS_ENABLED,
259 "checkbutton_notifications_contact_signin");
260 BIND_SENSITIVE (notify, NOTIFICATIONS_ENABLED,
261 "checkbutton_notifications_contact_signout");
263 BIND_SENSITIVE (sound, SOUNDS_ENABLED,
264 "checkbutton_sounds_disabled_away");
265 BIND_SENSITIVE (sound, SOUNDS_ENABLED,
268 BIND_SENSITIVE (loc, LOCATION_PUBLISH,
269 "checkbutton_location_resource_network");
270 BIND_SENSITIVE (loc, LOCATION_PUBLISH,
271 "checkbutton_location_resource_cell");
272 BIND_SENSITIVE (loc, LOCATION_PUBLISH,
273 "checkbutton_location_resource_gps");
274 BIND_SENSITIVE (loc, LOCATION_PUBLISH,
275 "checkbutton_location_reduce_accuracy");
277 #undef BIND_SENSITIVE
279 g_settings_bind (priv->gsettings,
280 EMPATHY_PREFS_AUTOCONNECT,
281 gtk_builder_get_object (gui,
282 "checkbutton_autoconnect"),
284 G_SETTINGS_BIND_DEFAULT);
286 g_settings_bind_with_mapping (priv->gsettings_contacts,
287 EMPATHY_PREFS_CONTACTS_SORT_CRITERIUM,
288 gtk_builder_get_object (gui,
289 "radiobutton_sort_by_status"),
291 G_SETTINGS_BIND_DEFAULT,
292 sort_criterium_get_mapping,
293 sort_criterium_set_mapping,
298 preferences_sound_cell_toggled_cb (GtkCellRendererToggle *toggle,
300 EmpathyPreferences *preferences)
302 EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
310 view = GTK_TREE_VIEW (priv->treeview_sounds);
311 model = gtk_tree_view_get_model (view);
313 path = gtk_tree_path_new_from_string (path_string);
315 gtk_tree_model_get_iter (model, &iter, path);
316 gtk_tree_model_get (model, &iter, COL_SOUND_KEY, &key,
317 COL_SOUND_ENABLED, &instore, -1);
321 gtk_list_store_set (GTK_LIST_STORE (model), &iter,
322 COL_SOUND_ENABLED, instore, -1);
324 g_settings_set_boolean (priv->gsettings_sound, key, instore);
327 gtk_tree_path_free (path);
331 preferences_sound_load (EmpathyPreferences *preferences)
333 EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
340 view = GTK_TREE_VIEW (priv->treeview_sounds);
341 store = GTK_LIST_STORE (gtk_tree_view_get_model (view));
343 for (i = 0; i < G_N_ELEMENTS (sound_entries); i++) {
344 set = g_settings_get_boolean (priv->gsettings_sound,
345 sound_entries[i].key);
347 gtk_list_store_insert_with_values (store, &iter, i,
348 COL_SOUND_NAME, gettext (sound_entries[i].name),
349 COL_SOUND_KEY, sound_entries[i].key,
350 COL_SOUND_ENABLED, set, -1);
355 preferences_sound_setup (EmpathyPreferences *preferences)
357 EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
360 GtkCellRenderer *renderer;
361 GtkTreeViewColumn *column;
363 view = GTK_TREE_VIEW (priv->treeview_sounds);
365 store = gtk_list_store_new (COL_SOUND_COUNT,
366 G_TYPE_BOOLEAN, /* enabled */
367 G_TYPE_STRING, /* name */
368 G_TYPE_STRING); /* key */
370 gtk_tree_view_set_model (view, GTK_TREE_MODEL (store));
372 renderer = gtk_cell_renderer_toggle_new ();
373 g_signal_connect (renderer, "toggled",
374 G_CALLBACK (preferences_sound_cell_toggled_cb),
377 column = gtk_tree_view_column_new ();
378 gtk_tree_view_column_pack_start (column, renderer, FALSE);
379 gtk_tree_view_column_add_attribute (column, renderer,
380 "active", COL_SOUND_ENABLED);
382 renderer = gtk_cell_renderer_text_new ();
383 gtk_tree_view_column_pack_start (column, renderer, FALSE);
384 gtk_tree_view_column_add_attribute (column, renderer,
385 "text", COL_SOUND_NAME);
387 gtk_tree_view_append_column (view, column);
389 gtk_tree_view_column_set_resizable (column, FALSE);
390 gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
392 g_object_unref (store);
396 preferences_languages_setup (EmpathyPreferences *preferences)
398 EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
401 GtkTreeSelection *selection;
402 GtkTreeViewColumn *column;
403 GtkCellRenderer *renderer;
406 view = GTK_TREE_VIEW (priv->treeview_spell_checker);
408 store = gtk_list_store_new (COL_LANG_COUNT,
409 G_TYPE_BOOLEAN, /* enabled */
410 G_TYPE_STRING, /* code */
411 G_TYPE_STRING); /* name */
413 gtk_tree_view_set_model (view, GTK_TREE_MODEL (store));
415 selection = gtk_tree_view_get_selection (view);
416 gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
418 renderer = gtk_cell_renderer_toggle_new ();
419 g_signal_connect (renderer, "toggled",
420 G_CALLBACK (preferences_languages_cell_toggled_cb),
423 column = gtk_tree_view_column_new_with_attributes (NULL, renderer,
424 "active", COL_LANG_ENABLED,
427 gtk_tree_view_append_column (view, column);
429 renderer = gtk_cell_renderer_text_new ();
430 col_offset = gtk_tree_view_insert_column_with_attributes (view,
433 "text", COL_LANG_NAME,
436 g_object_set_data (G_OBJECT (renderer),
437 "column", GINT_TO_POINTER (COL_LANG_NAME));
439 column = gtk_tree_view_get_column (view, col_offset - 1);
440 gtk_tree_view_column_set_sort_column_id (column, COL_LANG_NAME);
441 gtk_tree_view_column_set_resizable (column, FALSE);
442 gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
444 g_object_unref (store);
448 preferences_languages_add (EmpathyPreferences *preferences)
450 EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
455 view = GTK_TREE_VIEW (priv->treeview_spell_checker);
456 store = GTK_LIST_STORE (gtk_tree_view_get_model (view));
458 codes = empathy_spell_get_language_codes ();
461 gtk_widget_set_sensitive (priv->treeview_spell_checker, FALSE);
464 for (l = codes; l; l = l->next) {
469 name = empathy_spell_get_language_name (code);
474 gtk_list_store_insert_with_values (store, NULL, -1,
480 empathy_spell_free_language_codes (codes);
484 preferences_languages_save (EmpathyPreferences *preferences)
486 EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
490 gchar *languages = NULL;
492 view = GTK_TREE_VIEW (priv->treeview_spell_checker);
493 model = gtk_tree_view_get_model (view);
495 gtk_tree_model_foreach (model,
496 (GtkTreeModelForeachFunc) preferences_languages_save_foreach,
499 /* if user selects no languages, we don't want spell check */
500 g_settings_set_boolean (priv->gsettings_chat,
501 EMPATHY_PREFS_CHAT_SPELL_CHECKER_ENABLED,
504 g_settings_set_string (priv->gsettings_chat,
505 EMPATHY_PREFS_CHAT_SPELL_CHECKER_LANGUAGES,
506 languages != NULL ? languages : "");
512 preferences_languages_save_foreach (GtkTreeModel *model,
524 gtk_tree_model_get (model, iter, COL_LANG_ENABLED, &enabled, -1);
529 gtk_tree_model_get (model, iter, COL_LANG_CODE, &code, -1);
535 *languages = g_strdup (code);
537 gchar *str = *languages;
538 *languages = g_strdup_printf ("%s,%s", str, code);
548 preferences_languages_load (EmpathyPreferences *preferences)
550 EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
553 GList *enabled_codes;
555 enabled_codes = empathy_spell_get_enabled_language_codes ();
557 g_settings_set_boolean (priv->gsettings_chat,
558 EMPATHY_PREFS_CHAT_SPELL_CHECKER_ENABLED,
559 enabled_codes != NULL);
561 if (enabled_codes == NULL)
564 view = GTK_TREE_VIEW (priv->treeview_spell_checker);
565 model = gtk_tree_view_get_model (view);
567 gtk_tree_model_foreach (model,
568 (GtkTreeModelForeachFunc) preferences_languages_load_foreach,
571 g_list_free (enabled_codes);
575 preferences_languages_load_foreach (GtkTreeModel *model,
581 gboolean found = FALSE;
587 gtk_tree_model_get (model, iter, COL_LANG_CODE, &code, -1);
592 if (g_list_find_custom (languages, code, (GCompareFunc) strcmp)) {
597 gtk_list_store_set (GTK_LIST_STORE (model), iter, COL_LANG_ENABLED, found, -1);
602 preferences_languages_cell_toggled_cb (GtkCellRendererToggle *cell,
604 EmpathyPreferences *preferences)
606 EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
614 view = GTK_TREE_VIEW (priv->treeview_spell_checker);
615 model = gtk_tree_view_get_model (view);
616 store = GTK_LIST_STORE (model);
618 path = gtk_tree_path_new_from_string (path_string);
620 gtk_tree_model_get_iter (model, &iter, path);
621 gtk_tree_model_get (model, &iter, COL_LANG_ENABLED, &enabled, -1);
625 gtk_list_store_set (store, &iter, COL_LANG_ENABLED, enabled, -1);
626 gtk_tree_path_free (path);
628 preferences_languages_save (preferences);
632 preferences_preview_theme_append_message (EmpathyChatView *view,
633 EmpathyContact *sender,
634 EmpathyContact *receiver,
636 gboolean should_highlight)
638 EmpathyMessage *message;
640 message = g_object_new (EMPATHY_TYPE_MESSAGE,
642 "receiver", receiver,
646 empathy_chat_view_append_message (view, message, should_highlight);
647 g_object_unref (message);
651 preferences_preview_theme_changed_cb (EmpathyThemeManager *manager,
652 EmpathyPreferences *preferences)
654 EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
657 EmpathyContact *juliet;
658 EmpathyContact *romeo;
660 DEBUG ("Theme changed, update preview widget");
662 if (priv->chat_theme_preview != NULL) {
663 gtk_widget_destroy (GTK_WIDGET (priv->chat_theme_preview));
665 priv->chat_theme_preview = empathy_theme_manager_create_view (manager);
666 gtk_container_add (GTK_CONTAINER (priv->sw_chat_theme_preview),
667 GTK_WIDGET (priv->chat_theme_preview));
668 gtk_widget_show (GTK_WIDGET (priv->chat_theme_preview));
670 /* FIXME: It is ugly to add a fake conversation like that.
671 * Would be cool if we could request a TplLogManager for a fake
673 dbus = tp_dbus_daemon_dup (NULL);
674 account = tp_account_new (dbus,
675 TP_ACCOUNT_OBJECT_PATH_BASE "cm/jabber/account", NULL);
676 juliet = g_object_new (EMPATHY_TYPE_CONTACT,
679 /* translators: Contact name for the chat theme preview */
680 "alias", _("Juliet"),
683 romeo = g_object_new (EMPATHY_TYPE_CONTACT,
686 /* translators: Contact name for the chat theme preview */
691 preferences_preview_theme_append_message (priv->chat_theme_preview,
692 /* translators: Quote from Romeo & Julier, for chat theme preview */
693 juliet, romeo, _("O Romeo, Romeo, wherefore art thou Romeo?"),
694 TRUE /* this message mentions Romeo */);
695 preferences_preview_theme_append_message (priv->chat_theme_preview,
696 /* translators: Quote from Romeo & Julier, for chat theme preview */
697 juliet, romeo, _("Deny thy father and refuse thy name;"), FALSE);
698 preferences_preview_theme_append_message (priv->chat_theme_preview,
699 /* translators: Quote from Romeo & Julier, for chat theme preview */
700 juliet, romeo, _("Or if thou wilt not, be but sworn my love"), FALSE);
701 preferences_preview_theme_append_message (priv->chat_theme_preview,
702 /* translators: Quote from Romeo & Julier, for chat theme preview */
703 juliet, romeo, _("And I'll no longer be a Capulet."), FALSE);
704 preferences_preview_theme_append_message (priv->chat_theme_preview,
705 /* translators: Quote from Romeo & Julier, for chat theme preview */
706 romeo, juliet, _("Shall I hear more, or shall I speak at this?"), FALSE);
708 /* translators: Quote from Romeo & Julier, for chat theme preview */
709 empathy_chat_view_append_event (priv->chat_theme_preview, _("Juliet has disconnected"));
711 g_object_unref (juliet);
712 g_object_unref (romeo);
713 g_object_unref (account);
714 g_object_unref (dbus);
718 preferences_theme_variant_changed_cb (GtkComboBox *combo,
719 EmpathyPreferences *preferences)
721 EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
724 if (gtk_combo_box_get_active_iter (combo, &iter)) {
728 model = gtk_combo_box_get_model (combo);
729 gtk_tree_model_get (model, &iter,
730 COL_VARIANT_NAME, &name,
733 g_settings_set_string (priv->gsettings_chat,
734 EMPATHY_PREFS_CHAT_THEME_VARIANT,
742 preferences_theme_variant_notify_cb (GSettings *gsettings,
746 EmpathyPreferences *preferences = user_data;
747 EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
752 GtkTreeIter default_iter;
753 gboolean found_default = FALSE;
754 gboolean found = FALSE;
757 conf_name = g_settings_get_string (gsettings, EMPATHY_PREFS_CHAT_THEME_VARIANT);
758 combo = GTK_COMBO_BOX (priv->combobox_chat_theme_variant);
759 model = gtk_combo_box_get_model (combo);
761 for (ok = gtk_tree_model_get_iter_first (model, &iter);
763 ok = gtk_tree_model_iter_next (model, &iter)) {
767 gtk_tree_model_get (model, &iter,
768 COL_VARIANT_NAME, &name,
769 COL_VARIANT_DEFAULT, &is_default,
772 if (!tp_strdiff (name, conf_name)) {
774 gtk_combo_box_set_active_iter (combo, &iter);
777 found_default = TRUE;
784 /* Fallback to the first one. */
787 gtk_combo_box_set_active_iter (combo, &default_iter);
788 } else if (gtk_tree_model_get_iter_first (model, &iter)) {
789 gtk_combo_box_set_active_iter (combo, &iter);
796 /* return TRUE if we added at least one variant */
798 preferences_theme_variants_fill (EmpathyPreferences *preferences,
801 EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
805 const gchar *default_variant;
807 gboolean result = FALSE;
809 model = gtk_combo_box_get_model (GTK_COMBO_BOX (priv->combobox_chat_theme_variant));
810 store = GTK_LIST_STORE (model);
811 gtk_list_store_clear (store);
813 variants = empathy_adium_info_get_available_variants (info);
814 default_variant = empathy_adium_info_get_default_variant (info);
815 for (i = 0; i < variants->len; i++) {
816 gchar *name = g_ptr_array_index (variants, i);
818 gtk_list_store_insert_with_values (store, NULL, -1,
819 COL_VARIANT_NAME, name,
820 COL_VARIANT_DEFAULT, !tp_strdiff (name, default_variant),
826 /* Select the variant from the GSetting key */
827 preferences_theme_variant_notify_cb (priv->gsettings_chat,
828 EMPATHY_PREFS_CHAT_THEME_VARIANT,
835 preferences_theme_variants_setup (EmpathyPreferences *preferences)
837 EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
839 GtkCellLayout *cell_layout;
840 GtkCellRenderer *renderer;
843 combo = GTK_COMBO_BOX (priv->combobox_chat_theme_variant);
844 cell_layout = GTK_CELL_LAYOUT (combo);
846 /* Create the model */
847 store = gtk_list_store_new (COL_VARIANT_COUNT,
848 G_TYPE_STRING, /* name */
849 G_TYPE_BOOLEAN); /* is default */
850 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
851 COL_VARIANT_NAME, GTK_SORT_ASCENDING);
853 /* Add cell renderer */
854 renderer = gtk_cell_renderer_text_new ();
855 gtk_cell_layout_pack_start (cell_layout, renderer, TRUE);
856 gtk_cell_layout_set_attributes (cell_layout, renderer,
857 "text", COL_VARIANT_NAME, NULL);
859 gtk_combo_box_set_model (combo, GTK_TREE_MODEL (store));
860 g_object_unref (store);
862 g_signal_connect (combo, "changed",
863 G_CALLBACK (preferences_theme_variant_changed_cb),
866 /* Track changes of the GSetting key */
867 g_signal_connect (priv->gsettings_chat,
868 "changed::" EMPATHY_PREFS_CHAT_THEME_VARIANT,
869 G_CALLBACK (preferences_theme_variant_notify_cb),
874 preferences_theme_changed_cb (GtkComboBox *combo,
875 EmpathyPreferences *preferences)
877 EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
880 if (gtk_combo_box_get_active_iter (combo, &iter)) {
887 model = gtk_combo_box_get_model (combo);
888 gtk_tree_model_get (model, &iter,
889 COL_THEME_IS_ADIUM, &is_adium,
890 COL_THEME_NAME, &name,
891 COL_THEME_ADIUM_PATH, &path,
892 COL_THEME_ADIUM_INFO, &info,
895 g_settings_set_string (priv->gsettings_chat,
896 EMPATHY_PREFS_CHAT_THEME,
901 g_settings_set_string (priv->gsettings_chat,
902 EMPATHY_PREFS_CHAT_ADIUM_PATH,
905 variant = preferences_theme_variants_fill (preferences, info);
906 gtk_widget_set_visible (priv->hbox_chat_theme_variant, variant);
908 gtk_widget_hide (priv->hbox_chat_theme_variant);
912 tp_clear_pointer (&info, g_hash_table_unref);
917 preferences_theme_notify_cb (GSettings *gsettings,
921 EmpathyPreferences *preferences = user_data;
922 EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
928 gboolean found = FALSE;
931 conf_name = g_settings_get_string (gsettings, EMPATHY_PREFS_CHAT_THEME);
932 conf_path = g_settings_get_string (gsettings, EMPATHY_PREFS_CHAT_ADIUM_PATH);
934 combo = GTK_COMBO_BOX (priv->combobox_chat_theme);
935 model = gtk_combo_box_get_model (combo);
936 for (ok = gtk_tree_model_get_iter_first (model, &iter);
938 ok = gtk_tree_model_iter_next (model, &iter)) {
943 gtk_tree_model_get (model, &iter,
944 COL_THEME_IS_ADIUM, &is_adium,
945 COL_THEME_NAME, &name,
946 COL_THEME_ADIUM_PATH, &path,
949 if (!tp_strdiff (name, conf_name) &&
950 (!is_adium || !tp_strdiff (path, conf_path))) {
952 gtk_combo_box_set_active_iter (combo, &iter);
959 /* Fallback to the first one. */
961 if (gtk_tree_model_get_iter_first (model, &iter)) {
962 gtk_combo_box_set_active_iter (combo, &iter);
971 preferences_themes_setup (EmpathyPreferences *preferences)
973 EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
975 GtkCellLayout *cell_layout;
976 GtkCellRenderer *renderer;
978 const gchar **themes;
982 preferences_theme_variants_setup (preferences);
984 combo = GTK_COMBO_BOX (priv->combobox_chat_theme);
985 cell_layout = GTK_CELL_LAYOUT (combo);
987 /* Create the model */
988 store = gtk_list_store_new (COL_THEME_COUNT,
989 G_TYPE_STRING, /* Display name */
990 G_TYPE_STRING, /* Theme name */
991 G_TYPE_BOOLEAN, /* Is an Adium theme */
992 G_TYPE_STRING, /* Adium theme path */
993 G_TYPE_HASH_TABLE); /* Adium theme info */
994 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
995 COL_THEME_VISIBLE_NAME, GTK_SORT_ASCENDING);
998 themes = empathy_theme_manager_get_themes ();
999 for (i = 0; themes[i]; i += 2) {
1000 gtk_list_store_insert_with_values (store, NULL, -1,
1001 COL_THEME_VISIBLE_NAME, _(themes[i + 1]),
1002 COL_THEME_NAME, themes[i],
1003 COL_THEME_IS_ADIUM, FALSE,
1007 adium_themes = empathy_theme_manager_get_adium_themes ();
1008 while (adium_themes != NULL) {
1013 info = adium_themes->data;
1014 name = tp_asv_get_string (info, "CFBundleName");
1015 path = tp_asv_get_string (info, "path");
1017 if (name != NULL && path != NULL) {
1018 gtk_list_store_insert_with_values (store, NULL, -1,
1019 COL_THEME_VISIBLE_NAME, name,
1020 COL_THEME_NAME, "adium",
1021 COL_THEME_IS_ADIUM, TRUE,
1022 COL_THEME_ADIUM_PATH, path,
1023 COL_THEME_ADIUM_INFO, info,
1026 g_hash_table_unref (info);
1027 adium_themes = g_list_delete_link (adium_themes, adium_themes);
1030 /* Add cell renderer */
1031 renderer = gtk_cell_renderer_text_new ();
1032 gtk_cell_layout_pack_start (cell_layout, renderer, TRUE);
1033 gtk_cell_layout_set_attributes (cell_layout, renderer,
1034 "text", COL_THEME_VISIBLE_NAME, NULL);
1036 gtk_combo_box_set_model (combo, GTK_TREE_MODEL (store));
1037 g_object_unref (store);
1039 g_signal_connect (combo, "changed",
1040 G_CALLBACK (preferences_theme_changed_cb),
1043 /* Select the theme from the GSetting key and track changes */
1044 preferences_theme_notify_cb (priv->gsettings_chat,
1045 EMPATHY_PREFS_CHAT_THEME,
1047 g_signal_connect (priv->gsettings_chat,
1048 "changed::" EMPATHY_PREFS_CHAT_THEME,
1049 G_CALLBACK (preferences_theme_notify_cb),
1052 g_signal_connect (priv->gsettings_chat,
1053 "changed::" EMPATHY_PREFS_CHAT_ADIUM_PATH,
1054 G_CALLBACK (preferences_theme_notify_cb),
1059 empathy_preferences_response (GtkDialog *widget,
1062 gtk_widget_destroy (GTK_WIDGET (widget));
1066 empathy_preferences_finalize (GObject *self)
1068 EmpathyPreferencesPriv *priv = GET_PRIV (self);
1070 g_object_unref (priv->theme_manager);
1072 g_object_unref (priv->gsettings);
1073 g_object_unref (priv->gsettings_chat);
1074 g_object_unref (priv->gsettings_call);
1075 g_object_unref (priv->gsettings_loc);
1076 g_object_unref (priv->gsettings_notify);
1077 g_object_unref (priv->gsettings_sound);
1078 g_object_unref (priv->gsettings_ui);
1079 g_object_unref (priv->gsettings_logger);
1080 g_object_unref (priv->gsettings_contacts);
1082 G_OBJECT_CLASS (empathy_preferences_parent_class)->finalize (self);
1086 empathy_preferences_class_init (EmpathyPreferencesClass *klass)
1088 GtkDialogClass *dialog_class = GTK_DIALOG_CLASS (klass);
1089 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1091 dialog_class->response = empathy_preferences_response;
1093 object_class->finalize = empathy_preferences_finalize;
1095 g_type_class_add_private (object_class,
1096 sizeof (EmpathyPreferencesPriv));
1100 empathy_preferences_init (EmpathyPreferences *preferences)
1102 EmpathyPreferencesPriv *priv;
1107 priv = preferences->priv = G_TYPE_INSTANCE_GET_PRIVATE (preferences,
1108 EMPATHY_TYPE_PREFERENCES, EmpathyPreferencesPriv);
1110 gtk_dialog_add_button (GTK_DIALOG (preferences),
1111 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
1113 gtk_container_set_border_width (GTK_CONTAINER (preferences), 5);
1114 gtk_window_set_title (GTK_WINDOW (preferences), _("Preferences"));
1115 gtk_window_set_role (GTK_WINDOW (preferences), "preferences");
1116 gtk_window_set_position (GTK_WINDOW (preferences),
1117 GTK_WIN_POS_CENTER_ON_PARENT);
1118 gtk_window_set_icon_name (GTK_WINDOW (preferences), "gtk-preferences");
1120 filename = empathy_file_lookup ("empathy-preferences.ui", "src");
1121 gui = empathy_builder_get_file (filename,
1122 "notebook", &priv->notebook,
1123 "vbox_chat_theme", &priv->vbox_chat_theme,
1124 "combobox_chat_theme", &priv->combobox_chat_theme,
1125 "combobox_chat_theme_variant", &priv->combobox_chat_theme_variant,
1126 "hbox_chat_theme_variant", &priv->hbox_chat_theme_variant,
1127 "sw_chat_theme_preview", &priv->sw_chat_theme_preview,
1128 "checkbutton_events_notif_area", &priv->checkbutton_events_notif_area,
1129 "treeview_sounds", &priv->treeview_sounds,
1130 "treeview_spell_checker", &priv->treeview_spell_checker,
1134 gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (preferences))), priv->notebook);
1135 gtk_widget_show (priv->notebook);
1137 priv->gsettings = g_settings_new (EMPATHY_PREFS_SCHEMA);
1138 priv->gsettings_chat = g_settings_new (EMPATHY_PREFS_CHAT_SCHEMA);
1139 priv->gsettings_call = g_settings_new (EMPATHY_PREFS_CALL_SCHEMA);
1140 priv->gsettings_loc = g_settings_new (EMPATHY_PREFS_LOCATION_SCHEMA);
1141 priv->gsettings_notify = g_settings_new (EMPATHY_PREFS_NOTIFICATIONS_SCHEMA);
1142 priv->gsettings_sound = g_settings_new (EMPATHY_PREFS_SOUNDS_SCHEMA);
1143 priv->gsettings_ui = g_settings_new (EMPATHY_PREFS_UI_SCHEMA);
1144 priv->gsettings_logger = g_settings_new (EMPATHY_PREFS_LOGGER_SCHEMA);
1145 priv->gsettings_contacts = g_settings_new (EMPATHY_PREFS_CONTACTS_SCHEMA);
1147 /* Create chat theme preview, and track changes */
1148 priv->theme_manager = empathy_theme_manager_dup_singleton ();
1149 tp_g_signal_connect_object (priv->theme_manager, "theme-changed",
1150 G_CALLBACK (preferences_preview_theme_changed_cb),
1152 preferences_preview_theme_changed_cb (priv->theme_manager, preferences);
1154 preferences_themes_setup (preferences);
1156 preferences_setup_widgets (preferences, gui);
1158 preferences_languages_setup (preferences);
1159 preferences_languages_add (preferences);
1160 preferences_languages_load (preferences);
1162 preferences_sound_setup (preferences);
1163 preferences_sound_load (preferences);
1165 g_object_unref (gui);
1167 if (empathy_spell_supported ()) {
1168 page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (priv->notebook), EMPATHY_PREFERENCES_TAB_SPELL);
1169 gtk_widget_show (page);
1172 page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (priv->notebook), EMPATHY_PREFERENCES_TAB_LOCATION);
1174 gtk_widget_show (page);
1176 gtk_widget_hide (page);
1180 static EmpathyPreferencesTab
1181 empathy_preferences_tab_from_string (const gchar *str)
1185 for (i = 0; i < G_N_ELEMENTS (empathy_preferences_tabs); i++)
1187 if (!tp_strdiff (str, empathy_preferences_tabs[i]))
1191 g_warn_if_reached ();
1196 empathy_preferences_tab_to_string (EmpathyPreferencesTab tab)
1198 g_return_val_if_fail (tab < G_N_ELEMENTS (empathy_preferences_tabs), NULL);
1200 return empathy_preferences_tabs[tab];
1204 empathy_preferences_new (GtkWindow *parent,
1205 gboolean shell_running)
1208 EmpathyPreferencesPriv *priv;
1209 GtkWidget *notif_page;
1211 g_return_val_if_fail (parent == NULL || GTK_IS_WINDOW (parent), NULL);
1213 self = g_object_new (EMPATHY_TYPE_PREFERENCES, NULL);
1215 if (parent != NULL) {
1216 gtk_window_set_transient_for (GTK_WINDOW (self),
1220 /* when running in Gnome Shell we must hide these options since they
1221 * are meaningless in that context:
1222 * - 'Display incoming events in the notification area' (General->Behavior)
1223 * - 'Notifications' tab
1225 priv = GET_PRIV (self);
1226 if (shell_running) {
1227 gtk_widget_hide (priv->checkbutton_events_notif_area);
1228 notif_page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (priv->notebook),
1229 EMPATHY_PREFERENCES_TAB_NOTIFICATIONS);
1230 gtk_widget_hide (notif_page);
1237 empathy_preferences_show_tab (EmpathyPreferences *self,
1240 EmpathyPreferencesPriv *priv = GET_PRIV (self);
1242 gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook),
1243 empathy_preferences_tab_from_string (page));