]> git.0d.be Git - empathy.git/blob - src/empathy-preferences.c
Merge branch 'gnome-3-4'
[empathy.git] / src / empathy-preferences.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2003-2007 Imendio AB
4  *
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.
9  *
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.
14  *
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
19  *
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>
24  */
25
26 #include <config.h>
27
28 #include <string.h>
29 #include <stdio.h>
30
31 #include <gtk/gtk.h>
32 #include <glib/gi18n.h>
33 #include <telepathy-glib/dbus.h>
34 #include <telepathy-glib/util.h>
35
36 #include <libempathy/empathy-gsettings.h>
37 #include <libempathy/empathy-utils.h>
38
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>
44
45 #include "empathy-preferences.h"
46
47 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
48 #include <libempathy/empathy-debug.h>
49
50 G_DEFINE_TYPE (EmpathyPreferences, empathy_preferences, GTK_TYPE_DIALOG);
51
52 #define GET_PRIV(self) ((EmpathyPreferencesPriv *)((EmpathyPreferences *) self)->priv)
53
54 static const gchar * empathy_preferences_tabs[] =
55 {
56   "general",
57   "notifications",
58   "sounds",
59   "calls",
60   "location",
61   "spell",
62   "themes",
63 };
64
65 struct _EmpathyPreferencesPriv {
66         GtkWidget *notebook;
67
68         GtkWidget *checkbutton_events_notif_area;
69
70         GtkWidget *treeview_sounds;
71         GtkWidget *treeview_spell_checker;
72
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;
80
81         GSettings *gsettings;
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;
90 };
91
92 static void     preferences_setup_widgets                (EmpathyPreferences      *preferences,
93                                                           GtkBuilder              *gui);
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,
98                                                           GtkTreePath            *path,
99                                                           GtkTreeIter            *iter,
100                                                           gchar                 **languages);
101 static void     preferences_languages_load               (EmpathyPreferences      *preferences);
102 static gboolean preferences_languages_load_foreach       (GtkTreeModel           *model,
103                                                           GtkTreePath            *path,
104                                                           GtkTreeIter            *iter,
105                                                           GList                  *languages);
106 static void     preferences_languages_cell_toggled_cb    (GtkCellRendererToggle  *cell,
107                                                           gchar                  *path_string,
108                                                           EmpathyPreferences      *preferences);
109
110 enum {
111         COL_LANG_ENABLED,
112         COL_LANG_CODE,
113         COL_LANG_NAME,
114         COL_LANG_COUNT
115 };
116
117 enum {
118         COL_THEME_VISIBLE_NAME,
119         COL_THEME_NAME,
120         COL_THEME_IS_ADIUM,
121         COL_THEME_ADIUM_PATH,
122         COL_THEME_ADIUM_INFO,
123         COL_THEME_COUNT
124 };
125
126 enum {
127         COL_VARIANT_NAME,
128         COL_VARIANT_DEFAULT,
129         COL_VARIANT_COUNT
130 };
131
132 enum {
133         COL_SOUND_ENABLED,
134         COL_SOUND_NAME,
135         COL_SOUND_KEY,
136         COL_SOUND_COUNT
137 };
138
139 typedef struct {
140         const char *name;
141         const char *key;
142 } SoundEventEntry;
143
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 }
153 };
154
155 static gboolean
156 sort_criterium_get_mapping (GValue *value,
157                             GVariant *variant,
158                             gpointer user_data)
159 {
160         const char *s = g_variant_get_string (variant, NULL);
161
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);
166         else
167                 return FALSE;
168
169         return TRUE;
170 }
171
172 static GVariant *
173 sort_criterium_set_mapping (const GValue *value,
174                             const GVariantType *expected_type,
175                             gpointer user_data)
176 {
177         gboolean b = g_value_get_boolean (value);
178
179         if (b)
180                 return g_variant_new_string ("state");
181         else
182                 return g_variant_new_string ("name");
183 }
184
185 static void
186 preferences_setup_widgets (EmpathyPreferences *preferences,
187                            GtkBuilder *gui)
188 {
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);
194
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");
205
206         BIND_ACTIVE (sound, SOUNDS_ENABLED,
207                      "checkbutton_sounds_enabled");
208         BIND_ACTIVE (sound, SOUNDS_DISABLED_AWAY,
209                      "checkbutton_sounds_disabled_away");
210
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_BALANCES,
220                      "checkbutton_show_balances");
221
222         BIND_ACTIVE (chat, CHAT_SHOW_SMILEYS,
223                      "checkbutton_show_smileys");
224         BIND_ACTIVE (chat, CHAT_SHOW_CONTACTS_IN_ROOMS,
225                      "checkbutton_show_contacts_in_rooms");
226
227         BIND_ACTIVE (call, CALL_ECHO_CANCELLATION,
228                      "call_echo_cancellation");
229
230         BIND_ACTIVE (loc, LOCATION_PUBLISH,
231                      "checkbutton_location_publish");
232         BIND_ACTIVE (loc, LOCATION_RESOURCE_NETWORK,
233                      "checkbutton_location_resource_network");
234         BIND_ACTIVE (loc, LOCATION_RESOURCE_CELL,
235                      "checkbutton_location_resource_cell");
236         BIND_ACTIVE (loc, LOCATION_RESOURCE_GPS,
237                      "checkbutton_location_resource_gps");
238         BIND_ACTIVE (loc, LOCATION_REDUCE_ACCURACY,
239                      "checkbutton_location_reduce_accuracy");
240
241         BIND_ACTIVE (logger, LOGGER_ENABLED,
242                      "checkbutton_logging");
243
244 #undef BIND_ACTIVE
245
246 #define BIND_SENSITIVE(schema, key, widget) \
247         g_settings_bind (priv->gsettings_##schema, EMPATHY_PREFS_##key, \
248                          gtk_builder_get_object (gui, widget), "sensitive", \
249                         G_SETTINGS_BIND_GET);
250         /* N.B. BIND_SENSITIVE() is in addition to the sensitivity setting of
251          *      BIND_ACTIVE() */
252         BIND_SENSITIVE (notify, NOTIFICATIONS_ENABLED,
253                         "checkbutton_notifications_disabled_away");
254         BIND_SENSITIVE (notify, NOTIFICATIONS_ENABLED,
255                         "checkbutton_notifications_focus");
256         BIND_SENSITIVE (notify, NOTIFICATIONS_ENABLED,
257                         "checkbutton_notifications_contact_signin");
258         BIND_SENSITIVE (notify, NOTIFICATIONS_ENABLED,
259                         "checkbutton_notifications_contact_signout");
260
261         BIND_SENSITIVE (sound, SOUNDS_ENABLED,
262                         "checkbutton_sounds_disabled_away");
263         BIND_SENSITIVE (sound, SOUNDS_ENABLED,
264                         "treeview_sounds");
265
266         BIND_SENSITIVE (loc, LOCATION_PUBLISH,
267                         "checkbutton_location_resource_network");
268         BIND_SENSITIVE (loc, LOCATION_PUBLISH,
269                         "checkbutton_location_resource_cell");
270         BIND_SENSITIVE (loc, LOCATION_PUBLISH,
271                         "checkbutton_location_resource_gps");
272         BIND_SENSITIVE (loc, LOCATION_PUBLISH,
273                         "checkbutton_location_reduce_accuracy");
274
275 #undef BIND_SENSITIVE
276
277         g_settings_bind (priv->gsettings,
278                          EMPATHY_PREFS_AUTOCONNECT,
279                          gtk_builder_get_object (gui,
280                                                  "checkbutton_autoconnect"),
281                          "active",
282                          G_SETTINGS_BIND_DEFAULT);
283
284         g_settings_bind_with_mapping (priv->gsettings_contacts,
285                          EMPATHY_PREFS_CONTACTS_SORT_CRITERIUM,
286                          gtk_builder_get_object (gui,
287                                                  "radiobutton_sort_by_status"),
288                          "active",
289                          G_SETTINGS_BIND_DEFAULT,
290                          sort_criterium_get_mapping,
291                          sort_criterium_set_mapping,
292                          NULL, NULL);
293 }
294
295 static void
296 preferences_sound_cell_toggled_cb (GtkCellRendererToggle *toggle,
297                                    char *path_string,
298                                    EmpathyPreferences *preferences)
299 {
300         EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
301         GtkTreePath *path;
302         gboolean instore;
303         GtkTreeIter iter;
304         GtkTreeView *view;
305         GtkTreeModel *model;
306         char *key;
307
308         view = GTK_TREE_VIEW (priv->treeview_sounds);
309         model = gtk_tree_view_get_model (view);
310
311         path = gtk_tree_path_new_from_string (path_string);
312
313         gtk_tree_model_get_iter (model, &iter, path);
314         gtk_tree_model_get (model, &iter, COL_SOUND_KEY, &key,
315                             COL_SOUND_ENABLED, &instore, -1);
316
317         instore ^= 1;
318
319         gtk_list_store_set (GTK_LIST_STORE (model), &iter,
320                             COL_SOUND_ENABLED, instore, -1);
321
322         g_settings_set_boolean (priv->gsettings_sound, key, instore);
323
324         g_free (key);
325         gtk_tree_path_free (path);
326 }
327
328 static void
329 preferences_sound_load (EmpathyPreferences *preferences)
330 {
331         EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
332         guint i;
333         GtkTreeView *view;
334         GtkListStore *store;
335         GtkTreeIter iter;
336         gboolean set;
337
338         view = GTK_TREE_VIEW (priv->treeview_sounds);
339         store = GTK_LIST_STORE (gtk_tree_view_get_model (view));
340
341         for (i = 0; i < G_N_ELEMENTS (sound_entries); i++) {
342                 set = g_settings_get_boolean (priv->gsettings_sound,
343                                               sound_entries[i].key);
344
345                 gtk_list_store_insert_with_values (store, &iter, i,
346                                                    COL_SOUND_NAME, gettext (sound_entries[i].name),
347                                                    COL_SOUND_KEY, sound_entries[i].key,
348                                                    COL_SOUND_ENABLED, set, -1);
349         }
350 }
351
352 static void
353 preferences_sound_setup (EmpathyPreferences *preferences)
354 {
355         EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
356         GtkTreeView *view;
357         GtkListStore *store;
358         GtkCellRenderer *renderer;
359         GtkTreeViewColumn *column;
360
361         view = GTK_TREE_VIEW (priv->treeview_sounds);
362
363         store = gtk_list_store_new (COL_SOUND_COUNT,
364                                     G_TYPE_BOOLEAN, /* enabled */
365                                     G_TYPE_STRING,  /* name */
366                                     G_TYPE_STRING); /* key */
367
368         gtk_tree_view_set_model (view, GTK_TREE_MODEL (store));
369
370         renderer = gtk_cell_renderer_toggle_new ();
371         g_signal_connect (renderer, "toggled",
372                           G_CALLBACK (preferences_sound_cell_toggled_cb),
373                           preferences);
374
375         column = gtk_tree_view_column_new ();
376         gtk_tree_view_column_pack_start (column, renderer, FALSE);
377         gtk_tree_view_column_add_attribute (column, renderer,
378                                             "active", COL_SOUND_ENABLED);
379
380         renderer = gtk_cell_renderer_text_new ();
381         gtk_tree_view_column_pack_start (column, renderer, FALSE);
382         gtk_tree_view_column_add_attribute (column, renderer,
383                                             "text", COL_SOUND_NAME);
384
385         gtk_tree_view_append_column (view, column);
386
387         gtk_tree_view_column_set_resizable (column, FALSE);
388         gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
389
390         g_object_unref (store);
391 }
392
393 static void
394 preferences_languages_setup (EmpathyPreferences *preferences)
395 {
396         EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
397         GtkTreeView       *view;
398         GtkListStore      *store;
399         GtkTreeSelection  *selection;
400         GtkTreeViewColumn *column;
401         GtkCellRenderer   *renderer;
402         guint              col_offset;
403
404         view = GTK_TREE_VIEW (priv->treeview_spell_checker);
405
406         store = gtk_list_store_new (COL_LANG_COUNT,
407                                     G_TYPE_BOOLEAN,  /* enabled */
408                                     G_TYPE_STRING,   /* code */
409                                     G_TYPE_STRING);  /* name */
410
411         gtk_tree_view_set_model (view, GTK_TREE_MODEL (store));
412
413         selection = gtk_tree_view_get_selection (view);
414         gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
415
416         renderer = gtk_cell_renderer_toggle_new ();
417         g_signal_connect (renderer, "toggled",
418                           G_CALLBACK (preferences_languages_cell_toggled_cb),
419                           preferences);
420
421         column = gtk_tree_view_column_new_with_attributes (NULL, renderer,
422                                                            "active", COL_LANG_ENABLED,
423                                                            NULL);
424
425         gtk_tree_view_append_column (view, column);
426
427         renderer = gtk_cell_renderer_text_new ();
428         col_offset = gtk_tree_view_insert_column_with_attributes (view,
429                                                                   -1, _("Language"),
430                                                                   renderer,
431                                                                   "text", COL_LANG_NAME,
432                                                                   NULL);
433
434         g_object_set_data (G_OBJECT (renderer),
435                            "column", GINT_TO_POINTER (COL_LANG_NAME));
436
437         column = gtk_tree_view_get_column (view, col_offset - 1);
438         gtk_tree_view_column_set_sort_column_id (column, COL_LANG_NAME);
439         gtk_tree_view_column_set_resizable (column, FALSE);
440         gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
441
442         g_object_unref (store);
443 }
444
445 static void
446 preferences_languages_add (EmpathyPreferences *preferences)
447 {
448         EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
449         GtkTreeView  *view;
450         GtkListStore *store;
451         GList        *codes, *l;
452
453         view = GTK_TREE_VIEW (priv->treeview_spell_checker);
454         store = GTK_LIST_STORE (gtk_tree_view_get_model (view));
455
456         codes = empathy_spell_get_language_codes ();
457
458         if (!codes) {
459                 gtk_widget_set_sensitive (priv->treeview_spell_checker, FALSE);
460         }
461
462         for (l = codes; l; l = l->next) {
463                 const gchar *code;
464                 const gchar *name;
465
466                 code = l->data;
467                 name = empathy_spell_get_language_name (code);
468                 if (!name) {
469                         continue;
470                 }
471
472                 gtk_list_store_insert_with_values (store, NULL, -1,
473                                     COL_LANG_CODE, code,
474                                     COL_LANG_NAME, name,
475                                     -1);
476         }
477
478         empathy_spell_free_language_codes (codes);
479 }
480
481 static void
482 preferences_languages_save (EmpathyPreferences *preferences)
483 {
484         EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
485         GtkTreeView       *view;
486         GtkTreeModel      *model;
487
488         gchar             *languages = NULL;
489
490         view = GTK_TREE_VIEW (priv->treeview_spell_checker);
491         model = gtk_tree_view_get_model (view);
492
493         gtk_tree_model_foreach (model,
494                                 (GtkTreeModelForeachFunc) preferences_languages_save_foreach,
495                                 &languages);
496
497         /* if user selects no languages, we don't want spell check */
498         g_settings_set_boolean (priv->gsettings_chat,
499                                 EMPATHY_PREFS_CHAT_SPELL_CHECKER_ENABLED,
500                                 languages != NULL);
501
502         g_settings_set_string (priv->gsettings_chat,
503                                EMPATHY_PREFS_CHAT_SPELL_CHECKER_LANGUAGES,
504                                languages != NULL ? languages : "");
505
506         g_free (languages);
507 }
508
509 static gboolean
510 preferences_languages_save_foreach (GtkTreeModel  *model,
511                                     GtkTreePath   *path,
512                                     GtkTreeIter   *iter,
513                                     gchar        **languages)
514 {
515         gboolean  enabled;
516         gchar    *code;
517
518         if (!languages) {
519                 return TRUE;
520         }
521
522         gtk_tree_model_get (model, iter, COL_LANG_ENABLED, &enabled, -1);
523         if (!enabled) {
524                 return FALSE;
525         }
526
527         gtk_tree_model_get (model, iter, COL_LANG_CODE, &code, -1);
528         if (!code) {
529                 return FALSE;
530         }
531
532         if (!(*languages)) {
533                 *languages = g_strdup (code);
534         } else {
535                 gchar *str = *languages;
536                 *languages = g_strdup_printf ("%s,%s", str, code);
537                 g_free (str);
538         }
539
540         g_free (code);
541
542         return FALSE;
543 }
544
545 static void
546 preferences_languages_load (EmpathyPreferences *preferences)
547 {
548         EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
549         GtkTreeView   *view;
550         GtkTreeModel  *model;
551         GList         *enabled_codes;
552
553         enabled_codes = empathy_spell_get_enabled_language_codes ();
554
555         g_settings_set_boolean (priv->gsettings_chat,
556                                 EMPATHY_PREFS_CHAT_SPELL_CHECKER_ENABLED,
557                                 enabled_codes != NULL);
558
559         if (enabled_codes == NULL)
560                 return;
561
562         view = GTK_TREE_VIEW (priv->treeview_spell_checker);
563         model = gtk_tree_view_get_model (view);
564
565         gtk_tree_model_foreach (model,
566                                 (GtkTreeModelForeachFunc) preferences_languages_load_foreach,
567                                 enabled_codes);
568
569         g_list_free (enabled_codes);
570 }
571
572 static gboolean
573 preferences_languages_load_foreach (GtkTreeModel  *model,
574                                     GtkTreePath   *path,
575                                     GtkTreeIter   *iter,
576                                     GList         *languages)
577 {
578         gchar    *code;
579         gboolean  found = FALSE;
580
581         if (!languages) {
582                 return TRUE;
583         }
584
585         gtk_tree_model_get (model, iter, COL_LANG_CODE, &code, -1);
586         if (!code) {
587                 return FALSE;
588         }
589
590         if (g_list_find_custom (languages, code, (GCompareFunc) strcmp)) {
591                 found = TRUE;
592         }
593
594         g_free (code);
595         gtk_list_store_set (GTK_LIST_STORE (model), iter, COL_LANG_ENABLED, found, -1);
596         return FALSE;
597 }
598
599 static void
600 preferences_languages_cell_toggled_cb (GtkCellRendererToggle *cell,
601                                        gchar                 *path_string,
602                                        EmpathyPreferences     *preferences)
603 {
604         EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
605         GtkTreeView  *view;
606         GtkTreeModel *model;
607         GtkListStore *store;
608         GtkTreePath  *path;
609         GtkTreeIter   iter;
610         gboolean      enabled;
611
612         view = GTK_TREE_VIEW (priv->treeview_spell_checker);
613         model = gtk_tree_view_get_model (view);
614         store = GTK_LIST_STORE (model);
615
616         path = gtk_tree_path_new_from_string (path_string);
617
618         gtk_tree_model_get_iter (model, &iter, path);
619         gtk_tree_model_get (model, &iter, COL_LANG_ENABLED, &enabled, -1);
620
621         enabled ^= 1;
622
623         gtk_list_store_set (store, &iter, COL_LANG_ENABLED, enabled, -1);
624         gtk_tree_path_free (path);
625
626         preferences_languages_save (preferences);
627 }
628
629 static void
630 preferences_preview_theme_append_message (EmpathyChatView *view,
631                                           EmpathyContact *sender,
632                                           EmpathyContact *receiver,
633                                           const gchar *text,
634                                           gboolean should_highlight)
635 {
636         EmpathyMessage *message;
637
638         message = g_object_new (EMPATHY_TYPE_MESSAGE,
639                 "sender", sender,
640                 "receiver", receiver,
641                 "body", text,
642                 NULL);
643
644         empathy_chat_view_append_message (view, message, should_highlight);
645         g_object_unref (message);
646 }
647
648 static void
649 preferences_preview_theme_changed_cb (EmpathyThemeManager *manager,
650                                       EmpathyPreferences  *preferences)
651 {
652         EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
653         TpDBusDaemon *dbus;
654         TpAccount *account;
655         EmpathyContact *juliet;
656         EmpathyContact *romeo;
657
658         DEBUG ("Theme changed, update preview widget");
659
660         if (priv->chat_theme_preview != NULL) {
661                 gtk_widget_destroy (GTK_WIDGET (priv->chat_theme_preview));
662         }
663         priv->chat_theme_preview = empathy_theme_manager_create_view (manager);
664         gtk_container_add (GTK_CONTAINER (priv->sw_chat_theme_preview),
665                            GTK_WIDGET (priv->chat_theme_preview));
666         gtk_widget_show (GTK_WIDGET (priv->chat_theme_preview));
667
668         /* FIXME: It is ugly to add a fake conversation like that.
669          * Would be cool if we could request a TplLogManager for a fake
670          * conversation */
671         dbus = tp_dbus_daemon_dup (NULL);
672         account = tp_account_new (dbus,
673                 TP_ACCOUNT_OBJECT_PATH_BASE "cm/jabber/account", NULL);
674         juliet = g_object_new (EMPATHY_TYPE_CONTACT,
675                 "account", account,
676                 "id", "juliet",
677                 /* translators: Contact name for the chat theme preview */
678                 "alias", _("Juliet"),
679                 "is-user", FALSE,
680                 NULL);
681         romeo = g_object_new (EMPATHY_TYPE_CONTACT,
682                 "account", account,
683                 "id", "romeo",
684                 /* translators: Contact name for the chat theme preview */
685                 "alias", _("Romeo"),
686                 "is-user", TRUE,
687                 NULL);
688
689         preferences_preview_theme_append_message (priv->chat_theme_preview,
690                 /* translators: Quote from Romeo & Julier, for chat theme preview */
691                 juliet, romeo, _("O Romeo, Romeo, wherefore art thou Romeo?"),
692                 TRUE /* this message mentions Romeo */);
693         preferences_preview_theme_append_message (priv->chat_theme_preview,
694                 /* translators: Quote from Romeo & Julier, for chat theme preview */
695                 juliet, romeo, _("Deny thy father and refuse thy name;"), FALSE);
696         preferences_preview_theme_append_message (priv->chat_theme_preview,
697                 /* translators: Quote from Romeo & Julier, for chat theme preview */
698                 juliet, romeo, _("Or if thou wilt not, be but sworn my love"), FALSE);
699         preferences_preview_theme_append_message (priv->chat_theme_preview,
700                 /* translators: Quote from Romeo & Julier, for chat theme preview */
701                 juliet, romeo, _("And I'll no longer be a Capulet."), FALSE);
702         preferences_preview_theme_append_message (priv->chat_theme_preview,
703                 /* translators: Quote from Romeo & Julier, for chat theme preview */
704                 romeo, juliet, _("Shall I hear more, or shall I speak at this?"), FALSE);
705
706         /* translators: Quote from Romeo & Julier, for chat theme preview */
707         empathy_chat_view_append_event (priv->chat_theme_preview, _("Juliet has disconnected"));
708
709         g_object_unref (juliet);
710         g_object_unref (romeo);
711         g_object_unref (account);
712         g_object_unref (dbus);
713 }
714
715 static void
716 preferences_theme_variant_changed_cb (GtkComboBox        *combo,
717                                       EmpathyPreferences *preferences)
718 {
719         EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
720         GtkTreeIter   iter;
721
722         if (gtk_combo_box_get_active_iter (combo, &iter)) {
723                 GtkTreeModel *model;
724                 gchar        *name;
725
726                 model = gtk_combo_box_get_model (combo);
727                 gtk_tree_model_get (model, &iter,
728                                     COL_VARIANT_NAME, &name,
729                                     -1);
730
731                 g_settings_set_string (priv->gsettings_chat,
732                                        EMPATHY_PREFS_CHAT_THEME_VARIANT,
733                                        name);
734
735                 g_free (name);
736         }
737 }
738
739 static void
740 preferences_theme_variant_notify_cb (GSettings   *gsettings,
741                                      const gchar *key,
742                                      gpointer     user_data)
743 {
744         EmpathyPreferences *preferences = user_data;
745         EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
746         GtkComboBox        *combo;
747         gchar              *conf_name;
748         GtkTreeModel       *model;
749         GtkTreeIter         iter;
750         GtkTreeIter         default_iter;
751         gboolean            found_default = FALSE;
752         gboolean            found = FALSE;
753         gboolean            ok;
754
755         conf_name = g_settings_get_string (gsettings, EMPATHY_PREFS_CHAT_THEME_VARIANT);
756         combo = GTK_COMBO_BOX (priv->combobox_chat_theme_variant);
757         model = gtk_combo_box_get_model (combo);
758
759         for (ok = gtk_tree_model_get_iter_first (model, &iter);
760              ok && !found;
761              ok = gtk_tree_model_iter_next (model, &iter)) {
762                 gchar *name;
763                 gboolean is_default;
764
765                 gtk_tree_model_get (model, &iter,
766                                     COL_VARIANT_NAME, &name,
767                                     COL_VARIANT_DEFAULT, &is_default,
768                                     -1);
769
770                 if (!tp_strdiff (name, conf_name)) {
771                         found = TRUE;
772                         gtk_combo_box_set_active_iter (combo, &iter);
773                 }
774                 if (is_default) {
775                         found_default = TRUE;
776                         default_iter = iter;
777                 }
778
779                 g_free (name);
780         }
781
782         /* Fallback to the first one. */
783         if (!found) {
784                 if (found_default) {
785                         gtk_combo_box_set_active_iter (combo, &default_iter);
786                 } else if (gtk_tree_model_get_iter_first (model, &iter)) {
787                         gtk_combo_box_set_active_iter (combo, &iter);
788                 }
789         }
790
791         g_free (conf_name);
792 }
793
794 /* return TRUE if we added at least one variant */
795 static gboolean
796 preferences_theme_variants_fill (EmpathyPreferences *preferences,
797                                  GHashTable         *info)
798 {
799         EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
800         GtkTreeModel *model;
801         GtkListStore *store;
802         GPtrArray    *variants;
803         const gchar  *default_variant;
804         guint         i;
805         gboolean      result = FALSE;
806
807         model = gtk_combo_box_get_model (GTK_COMBO_BOX (priv->combobox_chat_theme_variant));
808         store = GTK_LIST_STORE (model);
809         gtk_list_store_clear (store);
810
811         variants = empathy_adium_info_get_available_variants (info);
812         default_variant = empathy_adium_info_get_default_variant (info);
813         for (i = 0; i < variants->len; i++) {
814                 gchar *name = g_ptr_array_index (variants, i);
815
816                 gtk_list_store_insert_with_values (store, NULL, -1,
817                         COL_VARIANT_NAME, name,
818                         COL_VARIANT_DEFAULT, !tp_strdiff (name, default_variant),
819                         -1);
820
821                 result = TRUE;
822         }
823
824         /* Select the variant from the GSetting key */
825         preferences_theme_variant_notify_cb (priv->gsettings_chat,
826                                              EMPATHY_PREFS_CHAT_THEME_VARIANT,
827                                              preferences);
828
829         return result;
830 }
831
832 static void
833 preferences_theme_variants_setup (EmpathyPreferences *preferences)
834 {
835         EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
836         GtkComboBox   *combo;
837         GtkCellLayout *cell_layout;
838         GtkCellRenderer *renderer;
839         GtkListStore  *store;
840
841         combo = GTK_COMBO_BOX (priv->combobox_chat_theme_variant);
842         cell_layout = GTK_CELL_LAYOUT (combo);
843
844         /* Create the model */
845         store = gtk_list_store_new (COL_VARIANT_COUNT,
846                                     G_TYPE_STRING,      /* name */
847                                     G_TYPE_BOOLEAN);    /* is default */
848         gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
849                 COL_VARIANT_NAME, GTK_SORT_ASCENDING);
850
851         /* Add cell renderer */
852         renderer = gtk_cell_renderer_text_new ();
853         gtk_cell_layout_pack_start (cell_layout, renderer, TRUE);
854         gtk_cell_layout_set_attributes (cell_layout, renderer,
855                 "text", COL_VARIANT_NAME, NULL);
856
857         gtk_combo_box_set_model (combo, GTK_TREE_MODEL (store));
858         g_object_unref (store);
859
860         g_signal_connect (combo, "changed",
861                           G_CALLBACK (preferences_theme_variant_changed_cb),
862                           preferences);
863
864         /* Track changes of the GSetting key */
865         g_signal_connect (priv->gsettings_chat,
866                           "changed::" EMPATHY_PREFS_CHAT_THEME_VARIANT,
867                           G_CALLBACK (preferences_theme_variant_notify_cb),
868                           preferences);
869 }
870
871 static void
872 preferences_theme_changed_cb (GtkComboBox        *combo,
873                               EmpathyPreferences *preferences)
874 {
875         EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
876         GtkTreeIter   iter;
877
878         if (gtk_combo_box_get_active_iter (combo, &iter)) {
879                 GtkTreeModel *model;
880                 gboolean      is_adium;
881                 gchar        *name;
882                 gchar        *path;
883                 GHashTable   *info;
884
885                 model = gtk_combo_box_get_model (combo);
886                 gtk_tree_model_get (model, &iter,
887                                     COL_THEME_IS_ADIUM, &is_adium,
888                                     COL_THEME_NAME, &name,
889                                     COL_THEME_ADIUM_PATH, &path,
890                                     COL_THEME_ADIUM_INFO, &info,
891                                     -1);
892
893                 g_settings_set_string (priv->gsettings_chat,
894                                        EMPATHY_PREFS_CHAT_THEME,
895                                        name);
896                 if (is_adium) {
897                         gboolean variant;
898
899                         g_settings_set_string (priv->gsettings_chat,
900                                                EMPATHY_PREFS_CHAT_ADIUM_PATH,
901                                                path);
902
903                         variant = preferences_theme_variants_fill (preferences, info);
904                         gtk_widget_set_visible (priv->hbox_chat_theme_variant, variant);
905                 } else {
906                         gtk_widget_hide (priv->hbox_chat_theme_variant);
907                 }
908                 g_free (name);
909                 g_free (path);
910                 tp_clear_pointer (&info, g_hash_table_unref);
911         }
912 }
913
914 static void
915 preferences_theme_notify_cb (GSettings   *gsettings,
916                              const gchar *key,
917                              gpointer     user_data)
918 {
919         EmpathyPreferences *preferences = user_data;
920         EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
921         GtkComboBox        *combo;
922         gchar              *conf_name;
923         gchar              *conf_path;
924         GtkTreeModel       *model;
925         GtkTreeIter         iter;
926         gboolean            found = FALSE;
927         gboolean            ok;
928
929         conf_name = g_settings_get_string (gsettings, EMPATHY_PREFS_CHAT_THEME);
930         conf_path = g_settings_get_string (gsettings, EMPATHY_PREFS_CHAT_ADIUM_PATH);
931
932         combo = GTK_COMBO_BOX (priv->combobox_chat_theme);
933         model = gtk_combo_box_get_model (combo);
934         for (ok = gtk_tree_model_get_iter_first (model, &iter);
935              ok && !found;
936              ok = gtk_tree_model_iter_next (model, &iter)) {
937                 gboolean is_adium;
938                 gchar *name;
939                 gchar *path;
940
941                 gtk_tree_model_get (model, &iter,
942                                     COL_THEME_IS_ADIUM, &is_adium,
943                                     COL_THEME_NAME, &name,
944                                     COL_THEME_ADIUM_PATH, &path,
945                                     -1);
946
947                 if (!tp_strdiff (name, conf_name) &&
948                     (!is_adium || !tp_strdiff (path, conf_path))) {
949                         found = TRUE;
950                         gtk_combo_box_set_active_iter (combo, &iter);
951                 }
952
953                 g_free (name);
954                 g_free (path);
955         }
956
957         /* Fallback to the first one. */
958         if (!found) {
959                 if (gtk_tree_model_get_iter_first (model, &iter)) {
960                         gtk_combo_box_set_active_iter (combo, &iter);
961                 }
962         }
963
964         g_free (conf_name);
965         g_free (conf_path);
966 }
967
968 static void
969 preferences_themes_setup (EmpathyPreferences *preferences)
970 {
971         EmpathyPreferencesPriv *priv = GET_PRIV (preferences);
972         GtkComboBox   *combo;
973         GtkCellLayout *cell_layout;
974         GtkCellRenderer *renderer;
975         GtkListStore  *store;
976         const gchar  **themes;
977         GList         *adium_themes;
978         gint           i;
979
980         preferences_theme_variants_setup (preferences);
981
982         combo = GTK_COMBO_BOX (priv->combobox_chat_theme);
983         cell_layout = GTK_CELL_LAYOUT (combo);
984
985         /* Create the model */
986         store = gtk_list_store_new (COL_THEME_COUNT,
987                                     G_TYPE_STRING,      /* Display name */
988                                     G_TYPE_STRING,      /* Theme name */
989                                     G_TYPE_BOOLEAN,     /* Is an Adium theme */
990                                     G_TYPE_STRING,      /* Adium theme path */
991                                     G_TYPE_HASH_TABLE); /* Adium theme info */
992         gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
993                 COL_THEME_VISIBLE_NAME, GTK_SORT_ASCENDING);
994
995         /* Fill the model */
996         themes = empathy_theme_manager_get_themes ();
997         for (i = 0; themes[i]; i += 2) {
998                 gtk_list_store_insert_with_values (store, NULL, -1,
999                         COL_THEME_VISIBLE_NAME, _(themes[i + 1]),
1000                         COL_THEME_NAME, themes[i],
1001                         COL_THEME_IS_ADIUM, FALSE,
1002                         -1);
1003         }
1004
1005         adium_themes = empathy_theme_manager_get_adium_themes ();
1006         while (adium_themes != NULL) {
1007                 GHashTable *info;
1008                 const gchar *name;
1009                 const gchar *path;
1010
1011                 info = adium_themes->data;
1012                 name = tp_asv_get_string (info, "CFBundleName");
1013                 path = tp_asv_get_string (info, "path");
1014
1015                 if (name != NULL && path != NULL) {
1016                         gtk_list_store_insert_with_values (store, NULL, -1,
1017                                 COL_THEME_VISIBLE_NAME, name,
1018                                 COL_THEME_NAME, "adium",
1019                                 COL_THEME_IS_ADIUM, TRUE,
1020                                 COL_THEME_ADIUM_PATH, path,
1021                                 COL_THEME_ADIUM_INFO, info,
1022                                 -1);
1023                 }
1024                 g_hash_table_unref (info);
1025                 adium_themes = g_list_delete_link (adium_themes, adium_themes);
1026         }
1027
1028         /* Add cell renderer */
1029         renderer = gtk_cell_renderer_text_new ();
1030         gtk_cell_layout_pack_start (cell_layout, renderer, TRUE);
1031         gtk_cell_layout_set_attributes (cell_layout, renderer,
1032                 "text", COL_THEME_VISIBLE_NAME, NULL);
1033
1034         gtk_combo_box_set_model (combo, GTK_TREE_MODEL (store));
1035         g_object_unref (store);
1036
1037         g_signal_connect (combo, "changed",
1038                           G_CALLBACK (preferences_theme_changed_cb),
1039                           preferences);
1040
1041         /* Select the theme from the GSetting key and track changes */
1042         preferences_theme_notify_cb (priv->gsettings_chat,
1043                                      EMPATHY_PREFS_CHAT_THEME,
1044                                      preferences);
1045         g_signal_connect (priv->gsettings_chat,
1046                           "changed::" EMPATHY_PREFS_CHAT_THEME,
1047                           G_CALLBACK (preferences_theme_notify_cb),
1048                           preferences);
1049
1050         g_signal_connect (priv->gsettings_chat,
1051                           "changed::" EMPATHY_PREFS_CHAT_ADIUM_PATH,
1052                           G_CALLBACK (preferences_theme_notify_cb),
1053                           preferences);
1054 }
1055
1056 static void
1057 empathy_preferences_response (GtkDialog *widget,
1058                               gint response)
1059 {
1060         gtk_widget_destroy (GTK_WIDGET (widget));
1061 }
1062
1063 static void
1064 empathy_preferences_finalize (GObject *self)
1065 {
1066         EmpathyPreferencesPriv *priv = GET_PRIV (self);
1067
1068         g_object_unref (priv->theme_manager);
1069
1070         g_object_unref (priv->gsettings);
1071         g_object_unref (priv->gsettings_chat);
1072         g_object_unref (priv->gsettings_call);
1073         g_object_unref (priv->gsettings_loc);
1074         g_object_unref (priv->gsettings_notify);
1075         g_object_unref (priv->gsettings_sound);
1076         g_object_unref (priv->gsettings_ui);
1077         g_object_unref (priv->gsettings_logger);
1078         g_object_unref (priv->gsettings_contacts);
1079
1080         G_OBJECT_CLASS (empathy_preferences_parent_class)->finalize (self);
1081 }
1082
1083 static void
1084 empathy_preferences_class_init (EmpathyPreferencesClass *klass)
1085 {
1086         GtkDialogClass *dialog_class = GTK_DIALOG_CLASS (klass);
1087         GObjectClass *object_class = G_OBJECT_CLASS (klass);
1088
1089         dialog_class->response = empathy_preferences_response;
1090
1091         object_class->finalize = empathy_preferences_finalize;
1092
1093         g_type_class_add_private (object_class,
1094                                   sizeof (EmpathyPreferencesPriv));
1095 }
1096
1097 static void
1098 empathy_preferences_init (EmpathyPreferences *preferences)
1099 {
1100         EmpathyPreferencesPriv    *priv;
1101         GtkBuilder                *gui;
1102         gchar                     *filename;
1103         GtkWidget                 *page;
1104
1105         priv = preferences->priv = G_TYPE_INSTANCE_GET_PRIVATE (preferences,
1106                         EMPATHY_TYPE_PREFERENCES, EmpathyPreferencesPriv);
1107
1108         gtk_dialog_add_button (GTK_DIALOG (preferences),
1109                                GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
1110
1111         gtk_container_set_border_width (GTK_CONTAINER (preferences), 5);
1112         gtk_window_set_title (GTK_WINDOW (preferences), _("Preferences"));
1113         gtk_window_set_role (GTK_WINDOW (preferences), "preferences");
1114         gtk_window_set_position (GTK_WINDOW (preferences),
1115                                  GTK_WIN_POS_CENTER_ON_PARENT);
1116         gtk_window_set_icon_name (GTK_WINDOW (preferences), "gtk-preferences");
1117
1118         filename = empathy_file_lookup ("empathy-preferences.ui", "src");
1119         gui = empathy_builder_get_file (filename,
1120                 "notebook", &priv->notebook,
1121                 "vbox_chat_theme", &priv->vbox_chat_theme,
1122                 "combobox_chat_theme", &priv->combobox_chat_theme,
1123                 "combobox_chat_theme_variant", &priv->combobox_chat_theme_variant,
1124                 "hbox_chat_theme_variant", &priv->hbox_chat_theme_variant,
1125                 "sw_chat_theme_preview", &priv->sw_chat_theme_preview,
1126                 "checkbutton_events_notif_area", &priv->checkbutton_events_notif_area,
1127                 "treeview_sounds", &priv->treeview_sounds,
1128                 "treeview_spell_checker", &priv->treeview_spell_checker,
1129                 NULL);
1130         g_free (filename);
1131
1132         gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (preferences))), priv->notebook);
1133         gtk_widget_show (priv->notebook);
1134
1135         priv->gsettings = g_settings_new (EMPATHY_PREFS_SCHEMA);
1136         priv->gsettings_chat = g_settings_new (EMPATHY_PREFS_CHAT_SCHEMA);
1137         priv->gsettings_call = g_settings_new (EMPATHY_PREFS_CALL_SCHEMA);
1138         priv->gsettings_loc = g_settings_new (EMPATHY_PREFS_LOCATION_SCHEMA);
1139         priv->gsettings_notify = g_settings_new (EMPATHY_PREFS_NOTIFICATIONS_SCHEMA);
1140         priv->gsettings_sound = g_settings_new (EMPATHY_PREFS_SOUNDS_SCHEMA);
1141         priv->gsettings_ui = g_settings_new (EMPATHY_PREFS_UI_SCHEMA);
1142         priv->gsettings_logger = g_settings_new (EMPATHY_PREFS_LOGGER_SCHEMA);
1143         priv->gsettings_contacts = g_settings_new (EMPATHY_PREFS_CONTACTS_SCHEMA);
1144
1145         /* Create chat theme preview, and track changes */
1146         priv->theme_manager = empathy_theme_manager_dup_singleton ();
1147         tp_g_signal_connect_object (priv->theme_manager, "theme-changed",
1148                           G_CALLBACK (preferences_preview_theme_changed_cb),
1149                           preferences, 0);
1150         preferences_preview_theme_changed_cb (priv->theme_manager, preferences);
1151
1152         preferences_themes_setup (preferences);
1153
1154         preferences_setup_widgets (preferences, gui);
1155
1156         preferences_languages_setup (preferences);
1157         preferences_languages_add (preferences);
1158         preferences_languages_load (preferences);
1159
1160         preferences_sound_setup (preferences);
1161         preferences_sound_load (preferences);
1162
1163         g_object_unref (gui);
1164
1165         if (empathy_spell_supported ()) {
1166                 page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (priv->notebook), EMPATHY_PREFERENCES_TAB_SPELL);
1167                 gtk_widget_show (page);
1168         }
1169
1170         page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (priv->notebook), EMPATHY_PREFERENCES_TAB_LOCATION);
1171 #ifdef HAVE_GEOCLUE
1172         gtk_widget_show (page);
1173 #else
1174         gtk_widget_hide (page);
1175 #endif
1176 }
1177
1178 static EmpathyPreferencesTab
1179 empathy_preferences_tab_from_string (const gchar *str)
1180 {
1181   guint i;
1182
1183   for (i = 0; i < G_N_ELEMENTS (empathy_preferences_tabs); i++)
1184     {
1185       if (!tp_strdiff (str, empathy_preferences_tabs[i]))
1186         return i;
1187     }
1188
1189   g_warn_if_reached ();
1190   return -1;
1191 }
1192
1193 const gchar *
1194 empathy_preferences_tab_to_string (EmpathyPreferencesTab tab)
1195 {
1196   g_return_val_if_fail (tab < G_N_ELEMENTS (empathy_preferences_tabs), NULL);
1197
1198   return empathy_preferences_tabs[tab];
1199 }
1200
1201 GtkWidget *
1202 empathy_preferences_new (GtkWindow *parent,
1203                          gboolean  shell_running)
1204 {
1205         GtkWidget              *self;
1206         EmpathyPreferencesPriv *priv;
1207         GtkWidget              *notif_page;
1208
1209         g_return_val_if_fail (parent == NULL || GTK_IS_WINDOW (parent), NULL);
1210
1211         self = g_object_new (EMPATHY_TYPE_PREFERENCES, NULL);
1212
1213         if (parent != NULL) {
1214                 gtk_window_set_transient_for (GTK_WINDOW (self),
1215                                               parent);
1216         }
1217
1218         /* when running in Gnome Shell we must hide these options since they
1219          * are meaningless in that context:
1220          * - 'Display incoming events in the notification area' (General->Behavior)
1221          * - 'Notifications' tab
1222          */
1223         priv = GET_PRIV (self);
1224         if (shell_running) {
1225                 gtk_widget_hide (priv->checkbutton_events_notif_area);
1226                 notif_page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (priv->notebook),
1227                                                         EMPATHY_PREFERENCES_TAB_NOTIFICATIONS);
1228                 gtk_widget_hide (notif_page);
1229         }
1230
1231         return self;
1232 }
1233
1234 void
1235 empathy_preferences_show_tab (EmpathyPreferences *self,
1236                               const gchar *page)
1237 {
1238         EmpathyPreferencesPriv *priv = GET_PRIV (self);
1239
1240         gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook),
1241                                        empathy_preferences_tab_from_string (page));
1242 }