]> git.0d.be Git - empathy.git/blobdiff - src/empathy.c
use a single window, with tabs
[empathy.git] / src / empathy.c
index b2005f19c520e11c2acc39f62daaa1bfa9fb0da5..fa71d706640e778bc626cbbbbd7b2991778d7f0f 100644 (file)
  * Authors: Xavier Claessens <xclaesse@gmail.com>
  */
 
-#include <config.h>
+#include "config.h"
 
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-
-#include <glib.h>
 #include <glib/gstdio.h>
 #include <glib/gi18n.h>
-#include <gtk/gtk.h>
-#include <gdk/gdkx.h>
+#include <libnotify/notify.h>
+#include <tp-account-widgets/tpaw-utils.h>
 
 #ifdef HAVE_LIBCHAMPLAIN
 #include <clutter-gtk/clutter-gtk.h>
 #endif
 
-#include <libnotify/notify.h>
-
-#include <telepathy-glib/account-manager.h>
-#include <telepathy-glib/dbus.h>
-#include <telepathy-glib/debug-sender.h>
-#include <telepathy-glib/util.h>
-#include <telepathy-glib/connection-manager.h>
-#include <telepathy-glib/interfaces.h>
-
-#include <telepathy-logger/log-manager.h>
-
-#include <libempathy/empathy-idle.h>
-#include <libempathy/empathy-utils.h>
-#include <libempathy/empathy-chatroom-manager.h>
-#include <libempathy/empathy-account-settings.h>
-#include <libempathy/empathy-connectivity.h>
-#include <libempathy/empathy-connection-managers.h>
-#include <libempathy/empathy-dispatcher.h>
-#include <libempathy/empathy-ft-factory.h>
-#include <libempathy/empathy-gsettings.h>
-#include <libempathy/empathy-tp-chat.h>
-
-#include <libempathy-gtk/empathy-ui-utils.h>
-#include <libempathy-gtk/empathy-location-manager.h>
-
-#include "empathy-main-window.h"
 #include "empathy-accounts-common.h"
 #include "empathy-accounts-dialog.h"
-#include "empathy-status-icon.h"
+#include "empathy-bus-names.h"
+#include "empathy-chatroom-manager.h"
+#include "empathy-client-factory.h"
+#include "empathy-connection-aggregator.h"
+#include "empathy-ft-factory.h"
 #include "empathy-ft-manager.h"
-
-#include "extensions/extensions.h"
+#include "empathy-gsettings.h"
+#include "empathy-location-manager.h"
+#include "empathy-notifications-approver.h"
+#include "empathy-presence-manager.h"
+#include "empathy-request-util.h"
+#include "empathy-roster-window.h"
+#include "empathy-status-icon.h"
+#include "empathy-ui-utils.h"
+#include "empathy-utils.h"
 
 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
-#include <libempathy/empathy-debug.h>
-
-#define EMPATHY_DBUS_NAME "org.gnome.Empathy"
+#include "empathy-debug.h"
 
 #define EMPATHY_TYPE_APP (empathy_app_get_type ())
 #define EMPATHY_APP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EMPATHY_TYPE_APP, EmpathyApp))
@@ -103,23 +81,29 @@ struct _EmpathyApp
   /* Properties */
   gboolean no_connect;
   gboolean start_hidden;
+  gboolean show_preferences;
+  gchar *preferences_tab;
+
+  gboolean activated;
 
   GtkWidget *window;
   EmpathyStatusIcon *icon;
-  EmpathyDispatcher *dispatcher;
   TpAccountManager *account_manager;
   TplLogManager *log_manager;
   EmpathyChatroomManager *chatroom_manager;
   EmpathyFTFactory  *ft_factory;
-  EmpathyIdle *idle;
-  EmpathyConnectivity *connectivity;
+  EmpathyPresenceManager *presence_mgr;
   GSettings *gsettings;
+  EmpathyNotificationsApprover *notifications_approver;
+  EmpathyConnectionAggregator *conn_aggregator;
 #ifdef HAVE_GEOCLUE
   EmpathyLocationManager *location_manager;
 #endif
 #ifdef ENABLE_DEBUG
   TpDebugSender *debug_sender;
 #endif
+
+  gboolean shell_running;
 };
 
 
@@ -132,27 +116,31 @@ empathy_app_dispose (GObject *object)
   void (*dispose) (GObject *) =
     G_OBJECT_CLASS (empathy_app_parent_class)->dispose;
 
-  if (self->idle != NULL)
+  /* Only set our presence to offline when exiting if GNOME Shell is not
+   * running */
+  if (self->presence_mgr != NULL &&
+      !self->shell_running)
     {
-      empathy_idle_set_state (self->idle, TP_CONNECTION_PRESENCE_TYPE_OFFLINE);
+      empathy_presence_manager_set_state (self->presence_mgr,
+          TP_CONNECTION_PRESENCE_TYPE_OFFLINE);
     }
 
 #ifdef ENABLE_DEBUG
   tp_clear_object (&self->debug_sender);
 #endif
 
-  tp_clear_object (&self->idle);
-  tp_clear_object (&self->connectivity);
+  tp_clear_object (&self->presence_mgr);
   tp_clear_object (&self->icon);
   tp_clear_object (&self->account_manager);
   tp_clear_object (&self->log_manager);
-  tp_clear_object (&self->dispatcher);
   tp_clear_object (&self->chatroom_manager);
 #ifdef HAVE_GEOCLUE
   tp_clear_object (&self->location_manager);
 #endif
   tp_clear_object (&self->ft_factory);
   tp_clear_object (&self->gsettings);
+  tp_clear_object (&self->notifications_approver);
+  tp_clear_object (&self->conn_aggregator);
 
   if (dispose != NULL)
     dispose (object);
@@ -165,7 +153,7 @@ empathy_app_finalize (GObject *object)
   void (*finalize) (GObject *) =
     G_OBJECT_CLASS (empathy_app_parent_class)->finalize;
 
-  gtk_widget_destroy (self->window);
+  g_free (self->preferences_tab);
 
   if (finalize != NULL)
     finalize (object);
@@ -197,25 +185,307 @@ empathy_app_set_property (GObject *object,
     }
 }
 
+static void
+new_incoming_transfer_cb (EmpathyFTFactory *factory,
+    EmpathyFTHandler *handler,
+    GError *error,
+    gpointer user_data)
+{
+  if (error)
+    empathy_ft_manager_display_error (handler, error);
+  else
+    empathy_receive_file_with_file_chooser (handler);
+}
+
+static void
+new_ft_handler_cb (EmpathyFTFactory *factory,
+    EmpathyFTHandler *handler,
+    GError *error,
+    gpointer user_data)
+{
+  if (error)
+    empathy_ft_manager_display_error (handler, error);
+  else
+    empathy_ft_manager_add_handler (handler);
+
+  g_object_unref (handler);
+}
+
+static void
+empathy_presence_manager_set_auto_away_cb (GSettings *gsettings,
+    const gchar *key,
+    gpointer user_data)
+{
+  EmpathyPresenceManager *presence_mgr = user_data;
+
+  empathy_presence_manager_set_auto_away (presence_mgr,
+      g_settings_get_boolean (gsettings, key));
+}
+
+#define GNOME_SHELL_BUS_NAME "org.gnome.Shell"
+
+static void
+list_names_cb (TpDBusDaemon *bus_daemon,
+        const gchar * const *names,
+        const GError *error,
+        gpointer user_data,
+        GObject *weak_object)
+{
+  EmpathyApp *self = (EmpathyApp *) weak_object;
+  guint i;
+
+  if (error != NULL)
+      goto out;
+
+  for (i = 0; names[i] != NULL; i++)
+    {
+      if (!tp_strdiff (names[i], GNOME_SHELL_BUS_NAME))
+        {
+          self->shell_running = TRUE;
+          break;
+        }
+    }
+
+out:
+  if (self->shell_running)
+    {
+      DEBUG ("GNOME Shell is running, don't create status icon");
+
+      /* Rely on GNOME Shell to watch session state */
+      empathy_presence_manager_set_auto_away (self->presence_mgr, FALSE);
+
+      empathy_roster_window_set_shell_running (
+          EMPATHY_ROSTER_WINDOW (self->window), TRUE);
+    }
+  else
+    {
+      gboolean autoaway;
+
+      self->icon = empathy_status_icon_new (GTK_WINDOW (self->window),
+          self->start_hidden);
+
+      /* Allow Empathy to watch session state */
+      autoaway = g_settings_get_boolean (self->gsettings,
+          EMPATHY_PREFS_AUTOAWAY);
+
+      g_signal_connect (self->gsettings,
+          "changed::" EMPATHY_PREFS_AUTOAWAY,
+          G_CALLBACK (empathy_presence_manager_set_auto_away_cb),
+          self->presence_mgr);
+
+      empathy_presence_manager_set_auto_away (self->presence_mgr, autoaway);
+    }
+}
+
 static void
 empathy_app_activate (GApplication *app)
 {
   EmpathyApp *self = (EmpathyApp *) app;
 
-  /* We're requested to show stuff again, disable the start hidden global
-   * in case the accounts wizard wants to pop up.
-   */
-  self->start_hidden = FALSE;
+  if (!self->activated)
+    {
+      GError *error = NULL;
+      TpDBusDaemon *dbus;
+
+      empathy_gtk_init ();
+
+      /* Create the FT factory */
+      self->ft_factory = empathy_ft_factory_dup_singleton ();
+      g_signal_connect (self->ft_factory, "new-ft-handler",
+          G_CALLBACK (new_ft_handler_cb), NULL);
+      g_signal_connect (self->ft_factory, "new-incoming-transfer",
+          G_CALLBACK (new_incoming_transfer_cb), NULL);
+
+      if (!empathy_ft_factory_register (self->ft_factory, &error))
+        {
+          g_warning ("Failed to register FileTransfer handler: %s",
+              error->message);
+          g_error_free (error);
+        }
+
+      self->activated = TRUE;
+
+      /* Setting up UI */
+      self->window = empathy_roster_window_new (GTK_APPLICATION (app));
+      gtk_application_set_app_menu (GTK_APPLICATION (self),
+          empathy_roster_window_get_menu_model (
+            EMPATHY_ROSTER_WINDOW (self->window)));
+
+      gtk_application_add_window (GTK_APPLICATION (app),
+          GTK_WINDOW (self->window));
+      gtk_application_add_accelerator (GTK_APPLICATION (app),
+          "<Primary>h",
+          "win." EMPATHY_PREFS_UI_SHOW_OFFLINE,
+          NULL);
+      gtk_application_add_accelerator (GTK_APPLICATION (app),
+          "<Control>Page_Up", "win.tab_prev", NULL);
+      gtk_application_add_accelerator (GTK_APPLICATION (app),
+          "<Control>Page_Down", "win.tab_next", NULL);
+
+      /* check if Shell is running */
+      dbus = tp_dbus_daemon_dup (&error);
+      g_assert_no_error (error);
+
+      tp_dbus_daemon_list_names (dbus, -1, list_names_cb,
+              self, NULL, G_OBJECT (self));
+
+      g_object_unref (dbus);
+
+      self->notifications_approver =
+        empathy_notifications_approver_dup_singleton ();
+    }
 
-  g_application_hold (G_APPLICATION (app));
+  if (self->show_preferences)
+    {
+      empathy_roster_window_show_preferences (
+          EMPATHY_ROSTER_WINDOW (self->window),
+          tp_str_empty (self->preferences_tab) ? NULL : self->preferences_tab);
 
-  empathy_window_present (GTK_WINDOW (self->window));
+      self->show_preferences = FALSE;
+    }
+  else
+    {
+      if (!self->start_hidden)
+        tpaw_window_present (GTK_WINDOW (self->window));
+    }
 
   /* Display the accounts dialog if needed */
-  tp_account_manager_prepare_async (self->account_manager, NULL,
+  tp_proxy_prepare_async (self->account_manager, NULL,
       account_manager_ready_cb, self);
 }
 
+static gboolean
+preferences_cb (const char *option_name,
+    const char *value,
+    gpointer data,
+    GError **error)
+{
+  EmpathyApp *self = data;
+
+  self->show_preferences = TRUE;
+
+  g_free (self->preferences_tab);
+  self->preferences_tab = g_strdup (value);
+
+  return TRUE;
+}
+
+static gboolean
+show_version_cb (const char *option_name,
+    const char *value,
+    gpointer data,
+    GError **error);
+
+static void
+open_preference_action_cb (GAction  *action,
+    GVariant *parameter,
+    gpointer  data)
+{
+  EmpathyApp *self = EMPATHY_APP (data);
+
+  self->show_preferences = TRUE;
+
+  g_free (self->preferences_tab);
+  self->preferences_tab = g_variant_dup_string (parameter, NULL);
+}
+
+static gboolean
+empathy_app_local_command_line (GApplication *app,
+    gchar ***arguments,
+    gint *exit_status)
+{
+  EmpathyApp *self = (EmpathyApp *) app;
+  GSimpleAction *action;
+  gint i;
+  gchar **argv;
+  gint argc = 0;
+  gboolean retval = TRUE;
+  GError *error = NULL;
+  gboolean no_connect = FALSE, start_hidden = FALSE;
+
+  GOptionContext *optcontext;
+  GOptionGroup *group;
+  GOptionEntry options[] = {
+      { "no-connect", 'n',
+        0, G_OPTION_ARG_NONE, &no_connect,
+        N_("Don't connect on startup"),
+        NULL },
+      { "start-hidden", 'h',
+        0, G_OPTION_ARG_NONE, &start_hidden,
+        N_("Don't display the contact list or any other dialogs on startup"),
+        NULL },
+      { "show-preferences", 'p',
+        G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, &preferences_cb,
+        NULL, NULL },
+      { "version", 'v',
+        G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, show_version_cb,
+        NULL, NULL },
+      { NULL }
+  };
+
+  if (!g_application_register (app, NULL, &error))
+    {
+      g_warning ("Impossible to register empathy: %s", error->message);
+      g_clear_error (&error);
+      *exit_status = EXIT_FAILURE;
+      return retval;
+    }
+
+  action = g_simple_action_new ("open-preferences", G_VARIANT_TYPE_STRING);
+  g_signal_connect (action, "activate", G_CALLBACK (open_preference_action_cb), app);
+  g_action_map_add_action (G_ACTION_MAP (app), G_ACTION (action));
+  g_object_unref (action);
+
+  /* We create a group so that GOptionArgFuncs get the user data */
+  group = g_option_group_new ("empathy", NULL, NULL, app, NULL);
+  g_option_group_set_translation_domain (group, GETTEXT_PACKAGE);
+  g_option_group_add_entries (group, options);
+
+  optcontext = g_option_context_new (N_("- Empathy IM Client"));
+  g_option_context_add_group (optcontext, gtk_get_option_group (FALSE));
+  g_option_context_set_main_group (optcontext, group);
+  g_option_context_set_translation_domain (optcontext, GETTEXT_PACKAGE);
+
+  argc = g_strv_length (*arguments);
+
+  /* We dup the args because g_option_context_parse() sets things to NULL,
+   * but we want to parse all the command line to the primary instance
+   * if necessary. */
+  argv = g_new (gchar*, argc + 1);
+  for (i = 0; i <= argc; i++)
+    argv[i] = (*arguments)[i];
+
+  if (!g_option_context_parse (optcontext, &argc, &argv, &error))
+    {
+      g_print ("%s\nRun '%s --help' to see a full list of available command "
+          "line options.\n",
+          error->message, argv[0]);
+      g_warning ("Error in empathy init: %s", error->message);
+      g_clear_error (&error);
+
+      *exit_status = EXIT_FAILURE;
+    }
+  else
+    {
+      self->no_connect = no_connect;
+      self->start_hidden = start_hidden;
+
+      if (self->show_preferences)
+        {
+          GVariant *parameter;
+          parameter = g_variant_new_string (self->preferences_tab ? self->preferences_tab : "");
+          g_action_group_activate_action (G_ACTION_GROUP (app), "open-preferences", parameter);
+        }
+
+      g_application_activate (app);
+    }
+
+  g_free (argv);
+  g_option_context_free (optcontext);
+
+  return retval;
+}
+
 static void empathy_app_constructed (GObject *object);
 
 static void
@@ -230,6 +500,7 @@ empathy_app_class_init (EmpathyAppClass *klass)
   gobject_class->dispose = empathy_app_dispose;
   gobject_class->finalize = empathy_app_finalize;
 
+  g_app_class->local_command_line = empathy_app_local_command_line;
   g_app_class->activate = empathy_app_activate;
 
   spec = g_param_spec_boolean ("no-connect", "no connect",
@@ -250,17 +521,6 @@ empathy_app_init (EmpathyApp *self)
 {
 }
 
-static void
-use_conn_notify_cb (GSettings *gsettings,
-    const gchar *key,
-    gpointer     user_data)
-{
-  EmpathyConnectivity *connectivity = user_data;
-
-  empathy_connectivity_set_use_conn (connectivity,
-      g_settings_get_boolean (gsettings, key));
-}
-
 static void
 migrate_config_to_xdg_dir (void)
 {
@@ -349,32 +609,6 @@ show_version_cb (const char *option_name,
   exit (EXIT_SUCCESS);
 }
 
-static void
-new_incoming_transfer_cb (EmpathyFTFactory *factory,
-    EmpathyFTHandler *handler,
-    GError *error,
-    gpointer user_data)
-{
-  if (error)
-    empathy_ft_manager_display_error (handler, error);
-  else
-    empathy_receive_file_with_file_chooser (handler);
-}
-
-static void
-new_ft_handler_cb (EmpathyFTFactory *factory,
-    EmpathyFTHandler *handler,
-    GError *error,
-    gpointer user_data)
-{
-  if (error)
-    empathy_ft_manager_display_error (handler, error);
-  else
-    empathy_ft_manager_add_handler (handler);
-
-  g_object_unref (handler);
-}
-
 static void
 account_manager_ready_cb (GObject *source_object,
     GAsyncResult *result,
@@ -385,7 +619,7 @@ account_manager_ready_cb (GObject *source_object,
   GError *error = NULL;
   TpConnectionPresenceType presence;
 
-  if (!tp_account_manager_prepare_finish (manager, result, &error))
+  if (!tp_proxy_prepare_finish (manager, result, &error))
     {
       GtkWidget *dialog;
 
@@ -416,7 +650,7 @@ account_manager_ready_cb (GObject *source_object,
           (presence, TP_CONNECTION_PRESENCE_TYPE_OFFLINE)
             <= 0)
       /* if current state is Offline, then put it online */
-      empathy_idle_set_state (self->idle,
+      empathy_presence_manager_set_state (self->presence_mgr,
           TP_CONNECTION_PRESENCE_TYPE_AVAILABLE);
 
   /* Pop up the accounts dialog if we don't have any account */
@@ -425,19 +659,39 @@ account_manager_ready_cb (GObject *source_object,
 }
 
 static void
-account_status_changed_cb (TpAccount *account,
-    guint old_status,
-    guint new_status,
-    guint reason,
-    gchar *dbus_error_name,
-    GHashTable *details,
-    EmpathyChatroom *room)
+account_join_chatrooms (TpAccount *account,
+  EmpathyChatroomManager *chatroom_manager)
 {
-  if (new_status != TP_CONNECTION_STATUS_CONNECTED)
+  TpConnection *conn;
+  GList *chatrooms, *p;
+
+  /* Wait if we are not connected or the TpConnection is not prepared yet */
+  conn = tp_account_get_connection (account);
+  if (conn == NULL)
     return;
 
-  empathy_dispatcher_join_muc (account,
-      empathy_chatroom_get_room (room), TP_USER_ACTION_TIME_NOT_USER_ACTION);
+  chatrooms = empathy_chatroom_manager_get_chatrooms (
+          chatroom_manager, account);
+
+  for (p = chatrooms; p != NULL; p = p->next)
+    {
+      EmpathyChatroom *room = EMPATHY_CHATROOM (p->data);
+
+      if (!empathy_chatroom_get_auto_connect (room))
+        continue;
+
+      empathy_join_muc (account, empathy_chatroom_get_room (room),
+        TP_USER_ACTION_TIME_NOT_USER_ACTION);
+    }
+  g_list_free (chatrooms);
+}
+
+static void
+account_connection_changed_cb (TpAccount *account,
+    GParamSpec *spec,
+    EmpathyChatroomManager *manager)
+{
+  account_join_chatrooms (account, manager);
 }
 
 static void
@@ -450,50 +704,27 @@ account_manager_chatroom_ready_cb (GObject *source_object,
   GList *accounts, *l;
   GError *error = NULL;
 
-  if (!tp_account_manager_prepare_finish (account_manager, result, &error))
+  if (!tp_proxy_prepare_finish (account_manager, result, &error))
     {
       DEBUG ("Failed to prepare account manager: %s", error->message);
       g_error_free (error);
       return;
     }
 
-  accounts = tp_account_manager_get_valid_accounts (account_manager);
+  accounts = tp_account_manager_dup_valid_accounts (account_manager);
 
   for (l = accounts; l != NULL; l = g_list_next (l))
     {
       TpAccount *account = TP_ACCOUNT (l->data);
-      TpConnection *conn;
-      GList *chatrooms, *p;
-
-      conn = tp_account_get_connection (account);
 
-      chatrooms = empathy_chatroom_manager_get_chatrooms (
-          chatroom_manager, account);
-
-      for (p = chatrooms; p != NULL; p = p->next)
-        {
-          EmpathyChatroom *room = EMPATHY_CHATROOM (p->data);
-
-          if (!empathy_chatroom_get_auto_connect (room))
-            continue;
-
-          if (conn == NULL)
-            {
-              g_signal_connect (G_OBJECT (account), "status-changed",
-                  G_CALLBACK (account_status_changed_cb), room);
-            }
-          else
-            {
-              empathy_dispatcher_join_muc (account,
-                  empathy_chatroom_get_room (room),
-                  TP_USER_ACTION_TIME_NOT_USER_ACTION);
-            }
-        }
+      /* Try to join all rooms if we're connected */
+      account_join_chatrooms (account, chatroom_manager);
 
-      g_list_free (chatrooms);
+      /* And/or join them on (re)connection */
+      tp_g_signal_connect_object (account, "notify::connection",
+        G_CALLBACK (account_connection_changed_cb), chatroom_manager, 0);
     }
-
-  g_list_free (accounts);
+  g_list_free_full (accounts, g_object_unref);
 }
 
 static void
@@ -503,33 +734,20 @@ chatroom_manager_ready_cb (EmpathyChatroomManager *chatroom_manager,
 {
   TpAccountManager *account_manager = user_data;
 
-  tp_account_manager_prepare_async (account_manager, NULL,
+  tp_proxy_prepare_async (account_manager, NULL,
       account_manager_chatroom_ready_cb, chatroom_manager);
 }
 
-static void
-empathy_idle_set_auto_away_cb (GSettings *gsettings,
-                               const gchar *key,
-                               gpointer user_data)
-{
-       EmpathyIdle *idle = user_data;
-
-       empathy_idle_set_auto_away (idle,
-      g_settings_get_boolean (gsettings, key));
-}
-
 static void
 empathy_app_constructed (GObject *object)
 {
   EmpathyApp *self = (EmpathyApp *) object;
-  GError *error = NULL;
   gboolean chatroom_manager_ready;
-  gboolean autoaway;
 
+  textdomain (GETTEXT_PACKAGE);
   g_set_application_name (_(PACKAGE_NAME));
 
   gtk_window_set_default_icon_name ("empathy");
-  textdomain (GETTEXT_PACKAGE);
 
 #ifdef ENABLE_DEBUG
   /* Set up debug sender */
@@ -540,42 +758,19 @@ empathy_app_constructed (GObject *object)
   notify_init (_(PACKAGE_NAME));
 
   /* Setting up Idle */
-  self->idle = empathy_idle_dup_singleton ();
+  self->presence_mgr = empathy_presence_manager_dup_singleton ();
 
   self->gsettings = g_settings_new (EMPATHY_PREFS_SCHEMA);
-  autoaway = g_settings_get_boolean (self->gsettings, EMPATHY_PREFS_AUTOAWAY);
-
-  g_signal_connect (self->gsettings,
-      "changed::" EMPATHY_PREFS_AUTOAWAY,
-      G_CALLBACK (empathy_idle_set_auto_away_cb), self->idle);
-
-  empathy_idle_set_auto_away (self->idle, autoaway);
-
-  /* Setting up Connectivity */
-  self->connectivity = empathy_connectivity_dup_singleton ();
-  use_conn_notify_cb (self->gsettings, EMPATHY_PREFS_USE_CONN,
-      self->connectivity);
-  g_signal_connect (self->gsettings,
-      "changed::" EMPATHY_PREFS_USE_CONN,
-      G_CALLBACK (use_conn_notify_cb), self->connectivity);
 
   /* account management */
   self->account_manager = tp_account_manager_dup ();
-  tp_account_manager_prepare_async (self->account_manager, NULL,
+  tp_proxy_prepare_async (self->account_manager, NULL,
       account_manager_ready_cb, self);
 
-  /* The EmpathyDispatcher doesn't dispatch anything any more but we have to
-   * keep it around as we still use it to request channels */
-  self->dispatcher = empathy_dispatcher_dup_singleton ();
+  tp_account_manager_enable_restart (self->account_manager);
 
   migrate_config_to_xdg_dir ();
 
-  /* Setting up UI */
-  self->window = empathy_main_window_dup ();
-  gtk_widget_show (self->window);
-  self->icon = empathy_status_icon_new (GTK_WINDOW (self->window),
-      self->start_hidden);
-
   /* Logging */
   self->log_manager = tpl_log_manager_dup_singleton ();
 
@@ -593,80 +788,67 @@ empathy_app_constructed (GObject *object)
           self->account_manager);
     }
 
-  /* Create the FT factory */
-  self->ft_factory = empathy_ft_factory_dup_singleton ();
-  g_signal_connect (self->ft_factory, "new-ft-handler",
-      G_CALLBACK (new_ft_handler_cb), NULL);
-  g_signal_connect (self->ft_factory, "new-incoming-transfer",
-      G_CALLBACK (new_incoming_transfer_cb), NULL);
-
-  if (!empathy_ft_factory_register (self->ft_factory, &error))
-    {
-      g_warning ("Failed to register FileTransfer handler: %s", error->message);
-      g_error_free (error);
-    }
-
   /* Location mananger */
 #ifdef HAVE_GEOCLUE
   self->location_manager = empathy_location_manager_dup_singleton ();
 #endif
+
+  self->conn_aggregator = empathy_connection_aggregator_dup_singleton ();
+
+  self->activated = FALSE;
+  self->ft_factory = NULL;
+  self->window = NULL;
+}
+
+static void
+add_empathy_features (void)
+{
+  /* Add 'empathy' specific feature before doing any preparation */
+  EmpathyClientFactory *factory;
+
+  factory = empathy_client_factory_dup ();
+
+  tp_simple_client_factory_add_connection_features_varargs (
+      TP_SIMPLE_CLIENT_FACTORY (factory),
+      /* empathy_connection_aggregator_get_all_groups(), used by
+       * EmpathyGroupsWidget relies on it */
+      TP_CONNECTION_FEATURE_CONTACT_GROUPS,
+      /* empathy_connection_aggregator_dup_all_contacts(), used by
+       * EmpathyEventManager relies on it */
+      TP_CONNECTION_FEATURE_CONTACT_LIST,
+      NULL);
+
+  g_object_unref (factory);
 }
 
 int
 main (int argc, char *argv[])
 {
   EmpathyApp *app;
-  GError *error = NULL;
-  GOptionContext *optcontext;
-  gboolean no_connect = FALSE, start_hidden = FALSE;
-  GOptionEntry options[] = {
-      { "no-connect", 'n',
-        0, G_OPTION_ARG_NONE, &no_connect,
-        N_("Don't connect on startup"),
-        NULL },
-      { "start-hidden", 'h',
-        0, G_OPTION_ARG_NONE, &start_hidden,
-        N_("Don't display the contact list or any other dialogs on startup"),
-        NULL },
-      { "version", 'v',
-        G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, show_version_cb,
-        NULL, NULL },
-      { NULL }
-  };
+  gint retval;
 
-  g_thread_init (NULL);
   g_type_init ();
 
 #ifdef HAVE_LIBCHAMPLAIN
-  gtk_clutter_init (&argc, &argv);
+  g_return_val_if_fail (gtk_clutter_init (&argc, &argv) ==
+      CLUTTER_INIT_SUCCESS, 1);
 #endif
 
+  g_type_init ();
   empathy_init ();
 
-  optcontext = g_option_context_new (N_("- Empathy IM Client"));
-  g_option_context_add_group (optcontext, gtk_get_option_group (TRUE));
-  g_option_context_add_main_entries (optcontext, options, GETTEXT_PACKAGE);
-
-  if (!g_option_context_parse (optcontext, &argc, &argv, &error)) {
-    g_print ("%s\nRun '%s --help' to see a full list of available command line options.\n",
-        error->message, argv[0]);
-    g_warning ("Error in empathy init: %s", error->message);
-    return EXIT_FAILURE;
-  }
-
-  g_option_context_free (optcontext);
-
-  empathy_gtk_init ();
+  add_empathy_features ();
 
   app = g_object_new (EMPATHY_TYPE_APP,
-      "application-id", EMPATHY_DBUS_NAME,
+      "application-id", EMPATHY_CHAT_BUS_NAME,
       NULL);
 
-  g_application_run (G_APPLICATION (app), argc, argv);
+  retval = g_application_run (G_APPLICATION (app), argc, argv);
 
   notify_uninit ();
   xmlCleanupParser ();
 
   g_object_unref (app);
-  return EXIT_SUCCESS;
+
+  return retval;
 }