]> git.0d.be Git - empathy.git/blob - src/empathy.c
empathy: rely on gtk_application_add_window() to manage the main loop
[empathy.git] / src / empathy.c
1 /*
2  * Copyright (C) 2007-2009 Collabora Ltd.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public
15  * License along with this program; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA  02110-1301  USA
18  *
19  * Authors: Xavier Claessens <xclaesse@gmail.com>
20  */
21
22 #include <config.h>
23
24 #include <stdlib.h>
25 #include <errno.h>
26 #include <string.h>
27
28 #include <glib.h>
29 #include <glib/gstdio.h>
30 #include <glib/gi18n.h>
31 #include <gtk/gtk.h>
32 #include <gdk/gdkx.h>
33
34 #ifdef HAVE_LIBCHAMPLAIN
35 #include <clutter-gtk/clutter-gtk.h>
36 #endif
37
38 #include <libnotify/notify.h>
39
40 #include <telepathy-glib/account-manager.h>
41 #include <telepathy-glib/dbus.h>
42 #include <telepathy-glib/debug-sender.h>
43 #include <telepathy-glib/util.h>
44 #include <telepathy-glib/connection-manager.h>
45 #include <telepathy-glib/interfaces.h>
46
47 #include <telepathy-yell/telepathy-yell.h>
48
49 #include <telepathy-logger/log-manager.h>
50
51 #include <libempathy/empathy-presence-manager.h>
52 #include <libempathy/empathy-utils.h>
53 #include <libempathy/empathy-chatroom-manager.h>
54 #include <libempathy/empathy-account-settings.h>
55 #include <libempathy/empathy-connectivity.h>
56 #include <libempathy/empathy-connection-managers.h>
57 #include <libempathy/empathy-request-util.h>
58 #include <libempathy/empathy-ft-factory.h>
59 #include <libempathy/empathy-gsettings.h>
60 #include <libempathy/empathy-tp-chat.h>
61
62 #include <libempathy-gtk/empathy-ui-utils.h>
63 #include <libempathy-gtk/empathy-location-manager.h>
64 #include <libempathy-gtk/empathy-notify-manager.h>
65
66 #include "empathy-main-window.h"
67 #include "empathy-accounts-common.h"
68 #include "empathy-accounts-dialog.h"
69 #include "empathy-status-icon.h"
70 #include "empathy-ft-manager.h"
71 #include "empathy-notifications-approver.h"
72
73 #include "extensions/extensions.h"
74
75 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
76 #include <libempathy/empathy-debug.h>
77
78 #define EMPATHY_DBUS_NAME "org.gnome.Empathy"
79
80 #define EMPATHY_TYPE_APP (empathy_app_get_type ())
81 #define EMPATHY_APP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EMPATHY_TYPE_APP, EmpathyApp))
82 #define EMPATHY_APP_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST ((obj), EMPATHY_TYPE_APP, EmpathyAppClass))
83 #define EMPATHY_IS_EMPATHY_APP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EMPATHY_TYPE_APP))
84 #define EMPATHY_IS_EMPATHY_APP_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((obj), EMPATHY_TYPE_APP))
85 #define EMPATHY_APP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EMPATHY_TYPE_APP, EmpathyAppClass))
86
87 typedef struct _EmpathyApp EmpathyApp;
88 typedef struct _EmpathyAppClass EmpathyAppClass;
89
90 enum
91 {
92   PROP_NO_CONNECT = 1,
93   PROP_START_HIDDEN
94 };
95
96 GType empathy_app_get_type (void);
97
98 struct _EmpathyAppClass
99 {
100   GtkApplicationClass parent_class;
101 };
102
103 struct _EmpathyApp
104 {
105   GtkApplication parent;
106
107   /* Properties */
108   gboolean no_connect;
109   gboolean start_hidden;
110   gboolean show_preferences;
111   gchar *preferences_tab;
112
113   gboolean activated;
114
115   GtkWidget *window;
116   EmpathyStatusIcon *icon;
117   TpAccountManager *account_manager;
118   TplLogManager *log_manager;
119   EmpathyChatroomManager *chatroom_manager;
120   EmpathyFTFactory  *ft_factory;
121   EmpathyPresenceManager *presence_mgr;
122   EmpathyConnectivity *connectivity;
123   GSettings *gsettings;
124   EmpathyNotificationsApprover *notifications_approver;
125 #ifdef HAVE_GEOCLUE
126   EmpathyLocationManager *location_manager;
127 #endif
128 #ifdef ENABLE_DEBUG
129   TpDebugSender *debug_sender;
130 #endif
131
132   gboolean shell_running;
133 };
134
135
136 G_DEFINE_TYPE(EmpathyApp, empathy_app, GTK_TYPE_APPLICATION)
137
138 static void
139 empathy_app_dispose (GObject *object)
140 {
141   EmpathyApp *self = EMPATHY_APP (object);
142   void (*dispose) (GObject *) =
143     G_OBJECT_CLASS (empathy_app_parent_class)->dispose;
144
145   /* Only set our presence to offline when exiting if GNOME Shell is not
146    * running */
147   if (self->presence_mgr != NULL &&
148       !self->shell_running)
149     {
150       empathy_presence_manager_set_state (self->presence_mgr,
151           TP_CONNECTION_PRESENCE_TYPE_OFFLINE);
152     }
153
154 #ifdef ENABLE_DEBUG
155   tp_clear_object (&self->debug_sender);
156 #endif
157
158   tp_clear_object (&self->presence_mgr);
159   tp_clear_object (&self->connectivity);
160   tp_clear_object (&self->icon);
161   tp_clear_object (&self->account_manager);
162   tp_clear_object (&self->log_manager);
163   tp_clear_object (&self->chatroom_manager);
164 #ifdef HAVE_GEOCLUE
165   tp_clear_object (&self->location_manager);
166 #endif
167   tp_clear_object (&self->ft_factory);
168   tp_clear_object (&self->gsettings);
169   tp_clear_object (&self->notifications_approver);
170
171   if (dispose != NULL)
172     dispose (object);
173 }
174
175 static void
176 empathy_app_finalize (GObject *object)
177 {
178   EmpathyApp *self = EMPATHY_APP (object);
179   void (*finalize) (GObject *) =
180     G_OBJECT_CLASS (empathy_app_parent_class)->finalize;
181
182   g_free (self->preferences_tab);
183
184   if (finalize != NULL)
185     finalize (object);
186 }
187
188 static void account_manager_ready_cb (GObject *source_object,
189     GAsyncResult *result,
190     gpointer user_data);
191
192 static void
193 empathy_app_set_property (GObject *object,
194     guint prop_id,
195     const GValue *value,
196     GParamSpec *pspec)
197 {
198   EmpathyApp *self = EMPATHY_APP (object);
199
200   switch (prop_id)
201     {
202       case PROP_NO_CONNECT:
203         self->no_connect = g_value_get_boolean (value);
204         break;
205       case PROP_START_HIDDEN:
206         self->start_hidden = g_value_get_boolean (value);
207         break;
208       default:
209         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
210         break;
211     }
212 }
213
214 static void
215 new_incoming_transfer_cb (EmpathyFTFactory *factory,
216     EmpathyFTHandler *handler,
217     GError *error,
218     gpointer user_data)
219 {
220   if (error)
221     empathy_ft_manager_display_error (handler, error);
222   else
223     empathy_receive_file_with_file_chooser (handler);
224 }
225
226 static void
227 new_ft_handler_cb (EmpathyFTFactory *factory,
228     EmpathyFTHandler *handler,
229     GError *error,
230     gpointer user_data)
231 {
232   if (error)
233     empathy_ft_manager_display_error (handler, error);
234   else
235     empathy_ft_manager_add_handler (handler);
236
237   g_object_unref (handler);
238 }
239
240 static gboolean
241 empathy_app_local_command_line (GApplication *app,
242     gchar ***arguments,
243     gint *exit_status);
244
245 static void
246 empathy_presence_manager_set_auto_away_cb (GSettings *gsettings,
247     const gchar *key,
248     gpointer user_data)
249 {
250   EmpathyPresenceManager *presence_mgr = user_data;
251
252   empathy_presence_manager_set_auto_away (presence_mgr,
253       g_settings_get_boolean (gsettings, key));
254 }
255
256 #define GNOME_SHELL_BUS_NAME "org.gnome.Shell"
257
258 static void
259 list_names_cb (TpDBusDaemon *bus_daemon,
260         const gchar * const *names,
261         const GError *error,
262         gpointer user_data,
263         GObject *weak_object)
264 {
265   EmpathyApp *self = (EmpathyApp *) weak_object;
266   guint i;
267
268   if (error != NULL)
269       goto out;
270
271   for (i = 0; names[i] != NULL; i++)
272     {
273       if (!tp_strdiff (names[i], GNOME_SHELL_BUS_NAME))
274         {
275           self->shell_running = TRUE;
276           break;
277         }
278     }
279
280 out:
281   if (self->shell_running)
282     {
283       DEBUG ("GNOME Shell is running, don't create status icon");
284
285       /* Rely on GNOME Shell to watch session state */
286       empathy_presence_manager_set_auto_away (self->presence_mgr, FALSE);
287
288       empathy_main_window_set_shell_running (EMPATHY_MAIN_WINDOW (self->window),
289                                              TRUE);
290     }
291   else
292     {
293       gboolean autoaway;
294
295       self->icon = empathy_status_icon_new (GTK_WINDOW (self->window),
296           self->start_hidden);
297
298       /* Allow Empathy to watch session state */
299       autoaway = g_settings_get_boolean (self->gsettings,
300           EMPATHY_PREFS_AUTOAWAY);
301
302       g_signal_connect (self->gsettings,
303           "changed::" EMPATHY_PREFS_AUTOAWAY,
304           G_CALLBACK (empathy_presence_manager_set_auto_away_cb),
305           self->presence_mgr);
306
307       empathy_presence_manager_set_auto_away (self->presence_mgr, autoaway);
308     }
309 }
310
311 static int
312 empathy_app_command_line (GApplication *app,
313     GApplicationCommandLine *cmdline)
314 {
315   EmpathyApp *self = (EmpathyApp *) app;
316   gchar **args, **argv;
317   gint argc, exit_status, i;
318
319   args = g_application_command_line_get_arguments (cmdline, &argc);
320   /* We have to make an extra copy of the array, since g_option_context_parse()
321    * assumes that it can remove strings from the array without freeing them. */
322   argv = g_new (gchar*, argc + 1);
323   for (i = 0; i <= argc; i++)
324     argv[i] = args[i];
325
326   if (empathy_app_local_command_line (app, &argv, &exit_status))
327     DEBUG ("failed to parse command line!");
328
329   g_free (argv);
330   g_strfreev (args);
331
332   if (!self->activated)
333     {
334       GError *error = NULL;
335       TpDBusDaemon *dbus;
336
337       /* Create the FT factory */
338       self->ft_factory = empathy_ft_factory_dup_singleton ();
339       g_signal_connect (self->ft_factory, "new-ft-handler",
340           G_CALLBACK (new_ft_handler_cb), NULL);
341       g_signal_connect (self->ft_factory, "new-incoming-transfer",
342           G_CALLBACK (new_incoming_transfer_cb), NULL);
343
344       if (!empathy_ft_factory_register (self->ft_factory, &error))
345         {
346           g_warning ("Failed to register FileTransfer handler: %s",
347               error->message);
348           g_error_free (error);
349         }
350
351       self->activated = TRUE;
352
353       /* Setting up UI */
354       self->window = empathy_main_window_dup ();
355
356       gtk_application_add_window (GTK_APPLICATION (app),
357           GTK_WINDOW (self->window));
358
359       /* check if Shell is running */
360       dbus = tp_dbus_daemon_dup (&error);
361       g_assert_no_error (error);
362
363       tp_dbus_daemon_list_names (dbus, -1, list_names_cb,
364               self, NULL, G_OBJECT (self));
365
366       g_object_unref (dbus);
367
368       self->notifications_approver =
369         empathy_notifications_approver_dup_singleton ();
370     }
371   else
372     {
373       /* We're requested to show stuff again, disable the start hidden global in
374        * case the accounts wizard wants to pop up.
375        */
376       self->start_hidden = FALSE;
377     }
378
379   if (self->show_preferences)
380     empathy_main_window_show_preferences (EMPATHY_MAIN_WINDOW (self->window),
381         self->preferences_tab);
382
383   if (!self->start_hidden)
384     empathy_window_present (GTK_WINDOW (self->window));
385
386   /* Display the accounts dialog if needed */
387   tp_proxy_prepare_async (self->account_manager, NULL,
388       account_manager_ready_cb, self);
389
390   return 0;
391 }
392
393 static gboolean
394 preferences_cb (const char *option_name,
395     const char *value,
396     gpointer data,
397     GError **error)
398 {
399   EmpathyApp *self = data;
400
401   self->show_preferences = TRUE;
402
403   g_free (self->preferences_tab);
404   self->preferences_tab = g_strdup (value);
405
406   return TRUE;
407 }
408
409 static gboolean
410 show_version_cb (const char *option_name,
411     const char *value,
412     gpointer data,
413     GError **error);
414
415 static gboolean
416 empathy_app_local_command_line (GApplication *app,
417     gchar ***arguments,
418     gint *exit_status)
419 {
420   EmpathyApp *self = (EmpathyApp *) app;
421   gint i;
422   gchar **argv;
423   gint argc = 0;
424   gboolean retval = FALSE;
425   GError *error = NULL;
426   gboolean no_connect = FALSE, start_hidden = FALSE;
427
428   GOptionContext *optcontext;
429   GOptionGroup *group;
430   GOptionEntry options[] = {
431       { "no-connect", 'n',
432         0, G_OPTION_ARG_NONE, &no_connect,
433         N_("Don't connect on startup"),
434         NULL },
435       { "start-hidden", 'h',
436         0, G_OPTION_ARG_NONE, &start_hidden,
437         N_("Don't display the contact list or any other dialogs on startup"),
438         NULL },
439       { "show-preferences", 'p',
440         G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, &preferences_cb,
441         NULL, NULL },
442       { "version", 'v',
443         G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, show_version_cb,
444         NULL, NULL },
445       { NULL }
446   };
447
448   /* We create a group so that GOptionArgFuncs get the user data */
449   group = g_option_group_new ("empathy", NULL, NULL, app, NULL);
450   g_option_group_add_entries (group, options);
451
452   optcontext = g_option_context_new (N_("- Empathy IM Client"));
453   g_option_context_add_group (optcontext, gtk_get_option_group (TRUE));
454   g_option_context_set_main_group (optcontext, group);
455   g_option_context_set_translation_domain (optcontext, GETTEXT_PACKAGE);
456
457   argc = g_strv_length (*arguments);
458
459   /* We dup the args because g_option_context_parse() sets things to NULL,
460    * but we want to parse all the command line to the primary instance
461    * if necessary. */
462   argv = g_new (gchar*, argc + 1);
463   for (i = 0; i <= argc; i++)
464     argv[i] = (*arguments)[i];
465
466   if (!g_option_context_parse (optcontext, &argc, &argv, &error))
467     {
468       g_print ("%s\nRun '%s --help' to see a full list of available command "
469           "line options.\n",
470           error->message, argv[0]);
471       g_warning ("Error in empathy init: %s", error->message);
472
473       *exit_status = EXIT_FAILURE;
474       retval = TRUE;
475     }
476
477   g_free (argv);
478
479   g_option_context_free (optcontext);
480
481   self->no_connect = no_connect;
482   self->start_hidden = start_hidden;
483
484   return retval;
485 }
486
487 static void empathy_app_constructed (GObject *object);
488
489 static void
490 empathy_app_class_init (EmpathyAppClass *klass)
491 {
492   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
493   GApplicationClass *g_app_class = G_APPLICATION_CLASS (klass);
494   GParamSpec *spec;
495
496   gobject_class->set_property = empathy_app_set_property;
497   gobject_class->constructed = empathy_app_constructed;
498   gobject_class->dispose = empathy_app_dispose;
499   gobject_class->finalize = empathy_app_finalize;
500
501   g_app_class->command_line = empathy_app_command_line;
502   g_app_class->local_command_line = empathy_app_local_command_line;
503
504   spec = g_param_spec_boolean ("no-connect", "no connect",
505       "Don't connect on startup",
506       FALSE,
507       G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
508   g_object_class_install_property (gobject_class, PROP_NO_CONNECT, spec);
509
510   spec = g_param_spec_boolean ("start-hidden", "start hidden",
511       "Don't display the contact list or any other dialogs on startup",
512       FALSE,
513       G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
514   g_object_class_install_property (gobject_class, PROP_START_HIDDEN, spec);
515 }
516
517 static void
518 empathy_app_init (EmpathyApp *self)
519 {
520 }
521
522 static void
523 use_conn_notify_cb (GSettings *gsettings,
524     const gchar *key,
525     gpointer     user_data)
526 {
527   EmpathyConnectivity *connectivity = user_data;
528
529   empathy_connectivity_set_use_conn (connectivity,
530       g_settings_get_boolean (gsettings, key));
531 }
532
533 static void
534 migrate_config_to_xdg_dir (void)
535 {
536   gchar *xdg_dir, *old_dir, *xdg_filename, *old_filename;
537   int i;
538   GFile *xdg_file, *old_file;
539   static const gchar* filenames[] = {
540     "geometry.ini",
541     "irc-networks.xml",
542     "chatrooms.xml",
543     "contact-groups.xml",
544     "status-presets.xml",
545     "accels.txt",
546     NULL
547   };
548
549   xdg_dir = g_build_filename (g_get_user_config_dir (), PACKAGE_NAME, NULL);
550   if (g_file_test (xdg_dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
551     {
552       /* xdg config dir already exists */
553       g_free (xdg_dir);
554       return;
555     }
556
557   old_dir = g_build_filename (g_get_home_dir (), ".gnome2",
558       PACKAGE_NAME, NULL);
559   if (!g_file_test (old_dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
560     {
561       /* old config dir didn't exist */
562       g_free (xdg_dir);
563       g_free (old_dir);
564       return;
565     }
566
567   if (g_mkdir_with_parents (xdg_dir, (S_IRUSR | S_IWUSR | S_IXUSR)) == -1)
568     {
569       DEBUG ("Failed to create configuration directory; aborting migration");
570       g_free (xdg_dir);
571       g_free (old_dir);
572       return;
573     }
574
575   for (i = 0; filenames[i]; i++)
576     {
577       old_filename = g_build_filename (old_dir, filenames[i], NULL);
578       if (!g_file_test (old_filename, G_FILE_TEST_EXISTS))
579         {
580           g_free (old_filename);
581           continue;
582         }
583       xdg_filename = g_build_filename (xdg_dir, filenames[i], NULL);
584       old_file = g_file_new_for_path (old_filename);
585       xdg_file = g_file_new_for_path (xdg_filename);
586
587       if (!g_file_move (old_file, xdg_file, G_FILE_COPY_NONE,
588           NULL, NULL, NULL, NULL))
589         DEBUG ("Failed to migrate %s", filenames[i]);
590
591       g_free (old_filename);
592       g_free (xdg_filename);
593       g_object_unref (old_file);
594       g_object_unref (xdg_file);
595     }
596
597   g_free (xdg_dir);
598   g_free (old_dir);
599 }
600
601 static void
602 show_accounts_ui (EmpathyApp *self,
603     GdkScreen *screen,
604     gboolean if_needed)
605 {
606   empathy_accounts_dialog_show_application (screen,
607       NULL, if_needed, self->start_hidden);
608 }
609
610 static gboolean
611 show_version_cb (const char *option_name,
612     const char *value,
613     gpointer data,
614     GError **error)
615 {
616   g_print ("%s\n", PACKAGE_STRING);
617
618   exit (EXIT_SUCCESS);
619 }
620
621 static void
622 account_manager_ready_cb (GObject *source_object,
623     GAsyncResult *result,
624     gpointer user_data)
625 {
626   TpAccountManager *manager = TP_ACCOUNT_MANAGER (source_object);
627   EmpathyApp *self = user_data;
628   GError *error = NULL;
629   TpConnectionPresenceType presence;
630
631   if (!tp_proxy_prepare_finish (manager, result, &error))
632     {
633       GtkWidget *dialog;
634
635       DEBUG ("Failed to prepare account manager: %s", error->message);
636
637       dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL,
638           GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
639           _("Error contacting the Account Manager"));
640       gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
641           _("There was an error while trying to connect to the Telepathy "
642             "Account Manager. The error was:\n\n%s"),
643           error->message);
644
645       gtk_dialog_run (GTK_DIALOG (dialog));
646       gtk_widget_destroy (dialog);
647
648       g_error_free (error);
649       return;
650     }
651
652   /* Autoconnect */
653   presence = tp_account_manager_get_most_available_presence (manager, NULL,
654       NULL);
655
656   if (g_settings_get_boolean (self->gsettings, EMPATHY_PREFS_AUTOCONNECT) &&
657       !self->no_connect &&
658       tp_connection_presence_type_cmp_availability
659           (presence, TP_CONNECTION_PRESENCE_TYPE_OFFLINE)
660             <= 0)
661       /* if current state is Offline, then put it online */
662       empathy_presence_manager_set_state (self->presence_mgr,
663           TP_CONNECTION_PRESENCE_TYPE_AVAILABLE);
664
665   /* Pop up the accounts dialog if we don't have any account */
666   if (!empathy_accounts_has_accounts (manager))
667     show_accounts_ui (self, gdk_screen_get_default (), TRUE);
668 }
669
670 static void
671 account_join_chatrooms (TpAccount *account,
672   EmpathyChatroomManager *chatroom_manager)
673 {
674   TpConnection *conn;
675   GList *chatrooms, *p;
676
677   /* Wait if we are not connected or the TpConnection is not prepared yet */
678   conn = tp_account_get_connection (account);
679   if (conn == NULL)
680     return;
681
682   chatrooms = empathy_chatroom_manager_get_chatrooms (
683           chatroom_manager, account);
684
685   for (p = chatrooms; p != NULL; p = p->next)
686     {
687       EmpathyChatroom *room = EMPATHY_CHATROOM (p->data);
688
689       if (!empathy_chatroom_get_auto_connect (room))
690         continue;
691
692       empathy_join_muc (account, empathy_chatroom_get_room (room),
693         TP_USER_ACTION_TIME_NOT_USER_ACTION);
694     }
695   g_list_free (chatrooms);
696 }
697
698 static void
699 account_connection_changed_cb (TpAccount *account,
700     GParamSpec *spec,
701     EmpathyChatroomManager *manager)
702 {
703   account_join_chatrooms (account, manager);
704 }
705
706 static void
707 account_manager_chatroom_ready_cb (GObject *source_object,
708     GAsyncResult *result,
709     gpointer user_data)
710 {
711   TpAccountManager *account_manager = TP_ACCOUNT_MANAGER (source_object);
712   EmpathyChatroomManager *chatroom_manager = user_data;
713   GList *accounts, *l;
714   GError *error = NULL;
715
716   if (!tp_proxy_prepare_finish (account_manager, result, &error))
717     {
718       DEBUG ("Failed to prepare account manager: %s", error->message);
719       g_error_free (error);
720       return;
721     }
722
723   accounts = tp_account_manager_get_valid_accounts (account_manager);
724
725   for (l = accounts; l != NULL; l = g_list_next (l))
726     {
727       TpAccount *account = TP_ACCOUNT (l->data);
728
729       /* Try to join all rooms if we're connected */
730       account_join_chatrooms (account, chatroom_manager);
731
732       /* And/or join them on (re)connection */
733       tp_g_signal_connect_object (account, "notify::connection",
734         G_CALLBACK (account_connection_changed_cb), chatroom_manager, 0);
735     }
736   g_list_free (accounts);
737 }
738
739 static void
740 chatroom_manager_ready_cb (EmpathyChatroomManager *chatroom_manager,
741     GParamSpec *pspec,
742     gpointer user_data)
743 {
744   TpAccountManager *account_manager = user_data;
745
746   tp_proxy_prepare_async (account_manager, NULL,
747       account_manager_chatroom_ready_cb, chatroom_manager);
748 }
749
750 static void
751 empathy_app_constructed (GObject *object)
752 {
753   EmpathyApp *self = (EmpathyApp *) object;
754   gboolean chatroom_manager_ready;
755
756   g_set_application_name (_(PACKAGE_NAME));
757
758   gtk_window_set_default_icon_name ("empathy");
759   textdomain (GETTEXT_PACKAGE);
760
761 #ifdef ENABLE_DEBUG
762   /* Set up debug sender */
763   self->debug_sender = tp_debug_sender_dup ();
764   g_log_set_default_handler (tp_debug_sender_log_handler, G_LOG_DOMAIN);
765 #endif
766
767   notify_init (_(PACKAGE_NAME));
768
769   /* Setting up Idle */
770   self->presence_mgr = empathy_presence_manager_dup_singleton ();
771
772   self->gsettings = g_settings_new (EMPATHY_PREFS_SCHEMA);
773
774   /* Setting up Connectivity */
775   self->connectivity = empathy_connectivity_dup_singleton ();
776   use_conn_notify_cb (self->gsettings, EMPATHY_PREFS_USE_CONN,
777       self->connectivity);
778   g_signal_connect (self->gsettings,
779       "changed::" EMPATHY_PREFS_USE_CONN,
780       G_CALLBACK (use_conn_notify_cb), self->connectivity);
781
782   /* account management */
783   self->account_manager = tp_account_manager_dup ();
784   tp_proxy_prepare_async (self->account_manager, NULL,
785       account_manager_ready_cb, self);
786
787   migrate_config_to_xdg_dir ();
788
789   /* Logging */
790   self->log_manager = tpl_log_manager_dup_singleton ();
791
792   self->chatroom_manager = empathy_chatroom_manager_dup_singleton (NULL);
793
794   g_object_get (self->chatroom_manager, "ready", &chatroom_manager_ready, NULL);
795   if (!chatroom_manager_ready)
796     {
797       g_signal_connect (G_OBJECT (self->chatroom_manager), "notify::ready",
798           G_CALLBACK (chatroom_manager_ready_cb), self->account_manager);
799     }
800   else
801     {
802       chatroom_manager_ready_cb (self->chatroom_manager, NULL,
803           self->account_manager);
804     }
805
806   /* Location mananger */
807 #ifdef HAVE_GEOCLUE
808   self->location_manager = empathy_location_manager_dup_singleton ();
809 #endif
810
811   self->activated = FALSE;
812   self->ft_factory = NULL;
813   self->window = NULL;
814 }
815
816 int
817 main (int argc, char *argv[])
818 {
819   EmpathyApp *app;
820   gint retval;
821
822   g_thread_init (NULL);
823   g_type_init ();
824
825 #ifdef HAVE_LIBCHAMPLAIN
826   gtk_clutter_init (&argc, &argv);
827 #endif
828
829   g_type_init ();
830   tpy_cli_init ();
831   empathy_init ();
832   gtk_init (&argc, &argv);
833   empathy_gtk_init ();
834
835   app = g_object_new (EMPATHY_TYPE_APP,
836       "application-id", EMPATHY_DBUS_NAME,
837       "flags", G_APPLICATION_HANDLES_COMMAND_LINE,
838       NULL);
839
840   retval = g_application_run (G_APPLICATION (app), argc, argv);
841
842   notify_uninit ();
843   xmlCleanupParser ();
844
845   g_object_unref (app);
846
847   return retval;
848 }