]> git.0d.be Git - empathy.git/blobdiff - src/empathy.c
Merge remote-tracking branch 'glassrose/add-All-service-selection-in-debug-window'
[empathy.git] / src / empathy.c
index e18288c352de241a3d37d007d99c69c6930f4e70..f59a54f17f7c559ec41512f87077c5a5b95e5ee4 100644 (file)
 #include <telepathy-glib/connection-manager.h>
 #include <telepathy-glib/interfaces.h>
 
+#include <telepathy-yell/telepathy-yell.h>
+
 #include <telepathy-logger/log-manager.h>
 
+#include <libempathy/empathy-client-factory.h>
+#include <libempathy/empathy-connection-aggregator.h>
 #include <libempathy/empathy-presence-manager.h>
 #include <libempathy/empathy-utils.h>
 #include <libempathy/empathy-chatroom-manager.h>
@@ -59,8 +63,9 @@
 
 #include <libempathy-gtk/empathy-ui-utils.h>
 #include <libempathy-gtk/empathy-location-manager.h>
+#include <libempathy-gtk/empathy-notify-manager.h>
 
-#include "empathy-main-window.h"
+#include "empathy-roster-window.h"
 #include "empathy-accounts-common.h"
 #include "empathy-accounts-dialog.h"
 #include "empathy-status-icon.h"
@@ -104,6 +109,8 @@ struct _EmpathyApp
   /* Properties */
   gboolean no_connect;
   gboolean start_hidden;
+  gboolean show_preferences;
+  gchar *preferences_tab;
 
   gboolean activated;
 
@@ -117,12 +124,15 @@ struct _EmpathyApp
   EmpathyConnectivity *connectivity;
   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;
 };
 
 
@@ -135,7 +145,10 @@ empathy_app_dispose (GObject *object)
   void (*dispose) (GObject *) =
     G_OBJECT_CLASS (empathy_app_parent_class)->dispose;
 
-  if (self->presence_mgr != NULL)
+  /* Only set our presence to offline when exiting if GNOME Shell is not
+   * running */
+  if (self->presence_mgr != NULL &&
+      !self->shell_running)
     {
       empathy_presence_manager_set_state (self->presence_mgr,
           TP_CONNECTION_PRESENCE_TYPE_OFFLINE);
@@ -157,6 +170,7 @@ empathy_app_dispose (GObject *object)
   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);
@@ -169,8 +183,7 @@ empathy_app_finalize (GObject *object)
   void (*finalize) (GObject *) =
     G_OBJECT_CLASS (empathy_app_parent_class)->finalize;
 
-  if (self->window != NULL)
-    gtk_widget_destroy (self->window);
+  g_free (self->preferences_tab);
 
   if (finalize != NULL)
     finalize (object);
@@ -228,15 +241,102 @@ new_ft_handler_cb (EmpathyFTFactory *factory,
   g_object_unref (handler);
 }
 
+static gboolean
+empathy_app_local_command_line (GApplication *app,
+    gchar ***arguments,
+    gint *exit_status);
+
+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 int
 empathy_app_command_line (GApplication *app,
     GApplicationCommandLine *cmdline)
 {
   EmpathyApp *self = (EmpathyApp *) app;
+  gchar **args, **argv;
+  gint argc, exit_status, i;
+
+  args = g_application_command_line_get_arguments (cmdline, &argc);
+  /* We have to make an extra copy of the array, since g_option_context_parse()
+   * assumes that it can remove strings from the array without freeing them. */
+  argv = g_new (gchar*, argc + 1);
+  for (i = 0; i <= argc; i++)
+    argv[i] = args[i];
+
+  if (empathy_app_local_command_line (app, &argv, &exit_status))
+    DEBUG ("failed to parse command line!");
+
+  g_free (argv);
+  g_strfreev (args);
 
   if (!self->activated)
     {
       GError *error = NULL;
+      TpDBusDaemon *dbus;
 
       /* Create the FT factory */
       self->ft_factory = empathy_ft_factory_dup_singleton ();
@@ -252,14 +352,22 @@ empathy_app_command_line (GApplication *app,
           g_error_free (error);
         }
 
-      g_application_hold (G_APPLICATION (app));
       self->activated = TRUE;
 
       /* 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);
+      self->window = empathy_roster_window_dup ();
+
+      gtk_application_add_window (GTK_APPLICATION (app),
+          GTK_WINDOW (self->window));
+
+      /* 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 ();
@@ -272,16 +380,36 @@ empathy_app_command_line (GApplication *app,
       self->start_hidden = FALSE;
     }
 
+  if (self->show_preferences)
+    empathy_roster_window_show_preferences (
+        EMPATHY_ROSTER_WINDOW (self->window), self->preferences_tab);
+
   if (!self->start_hidden)
     empathy_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);
 
   return 0;
 }
 
+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,
@@ -302,6 +430,7 @@ empathy_app_local_command_line (GApplication *app,
   gboolean no_connect = FALSE, start_hidden = FALSE;
 
   GOptionContext *optcontext;
+  GOptionGroup *group;
   GOptionEntry options[] = {
       { "no-connect", 'n',
         0, G_OPTION_ARG_NONE, &no_connect,
@@ -311,19 +440,32 @@ empathy_app_local_command_line (GApplication *app,
         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 }
   };
 
+  /* We create a group so that GOptionArgFuncs get the user data */
+  group = g_option_group_new ("empathy", NULL, NULL, app, NULL);
+  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 (TRUE));
-  g_option_context_add_main_entries (optcontext, options, GETTEXT_PACKAGE);
+  g_option_context_set_main_group (optcontext, group);
+  g_option_context_set_translation_domain (optcontext, GETTEXT_PACKAGE);
+
+  argc = g_strv_length (*arguments);
 
-  argv = *arguments;
-  for (i = 0; argv[i] != NULL; i++)
-    argc++;
+  /* 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))
     {
@@ -336,6 +478,8 @@ empathy_app_local_command_line (GApplication *app,
       retval = TRUE;
     }
 
+  g_free (argv);
+
   g_option_context_free (optcontext);
 
   self->no_connect = no_connect;
@@ -488,7 +632,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;
 
@@ -528,19 +672,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_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
@@ -553,7 +717,7 @@ 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);
@@ -565,37 +729,14 @@ account_manager_chatroom_ready_cb (GObject *source_object,
   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);
+      /* Try to join all rooms if we're connected */
+      account_join_chatrooms (account, chatroom_manager);
 
-      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_join_muc (account,
-                  empathy_chatroom_get_room (room),
-                  TP_USER_ACTION_TIME_NOT_USER_ACTION);
-            }
-        }
-
-      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);
 }
 
@@ -606,27 +747,15 @@ 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_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));
-}
-
 static void
 empathy_app_constructed (GObject *object)
 {
   EmpathyApp *self = (EmpathyApp *) object;
   gboolean chatroom_manager_ready;
-  gboolean autoaway;
 
   g_set_application_name (_(PACKAGE_NAME));
 
@@ -645,14 +774,6 @@ empathy_app_constructed (GObject *object)
   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_presence_manager_set_auto_away_cb),
-      self->presence_mgr);
-
-  empathy_presence_manager_set_auto_away (self->presence_mgr, autoaway);
 
   /* Setting up Connectivity */
   self->connectivity = empathy_connectivity_dup_singleton ();
@@ -664,7 +785,7 @@ empathy_app_constructed (GObject *object)
 
   /* 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);
 
   migrate_config_to_xdg_dir ();
@@ -691,11 +812,34 @@ empathy_app_constructed (GObject *object)
   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[])
 {
@@ -709,10 +853,14 @@ main (int argc, char *argv[])
   gtk_clutter_init (&argc, &argv);
 #endif
 
+  g_type_init ();
+  tpy_cli_init ();
   empathy_init ();
   gtk_init (&argc, &argv);
   empathy_gtk_init ();
 
+  add_empathy_features ();
+
   app = g_object_new (EMPATHY_TYPE_APP,
       "application-id", EMPATHY_DBUS_NAME,
       "flags", G_APPLICATION_HANDLES_COMMAND_LINE,