diff --git a/configure.ac b/configure.ac
index 8b498d9..75651af 100644
--- a/configure.ac
+++ b/configure.ac
@@ -42,7 +42,6 @@ LIBNOTIFY_REQUIRED=0.5.1
 TELEPATHY_FARSIGHT_REQUIRED=0.0.14
 TELEPATHY_GLIB_REQUIRED=0.11.16
 TELEPATHY_LOGGER=0.1.5
-UNIQUE_REQUIRED=1.1.2
 
 # Optionnal deps
 CLUTTER_GTK_REQUIRED=0.90.3
@@ -182,7 +181,6 @@ PKG_CHECK_MODULES(GTK, gtk+-3.0 >= $GTK_REQUIRED)
 
 PKG_CHECK_MODULES(CANBERRA, libcanberra-gtk3 >= $LIBCANBERRA_GTK_REQUIRED)
 PKG_CHECK_MODULES(LIBNOTIFY, libnotify >= $LIBNOTIFY_REQUIRED)
-PKG_CHECK_MODULES(UNIQUE, unique-3.0 >= $UNIQUE_REQUIRED)
 PKG_CHECK_MODULES(GCR, gcr-3 >= $KEYRING_REQUIRED)
 
 # -----------------------------------------------------------
diff --git a/src/Makefile.am b/src/Makefile.am
index 378bdee..31a2193 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -16,7 +16,6 @@ AM_LDFLAGS = -lm
 AM_CPPFLAGS =						\
 	$(CPPFLAGS_COMMON)				\
 	$(LIBNOTIFY_CFLAGS)				\
-	$(UNIQUE_CFLAGS) \
 	$(LIBCHAMPLAIN_CFLAGS)				\
 	$(WEBKIT_CFLAGS)				\
 	$(NULL)
@@ -26,7 +25,6 @@ LDADD =								\
 	$(top_builddir)/libempathy/libempathy.la		\
 	$(top_builddir)/extensions/libemp-extensions.la		\
 	$(LIBNOTIFY_LIBS)					\
-	$(UNIQUE_LIBS)						\
 	$(EMPATHY_LIBS)						\
 	$(GTK_LIBS)						\
 	$(LIBCHAMPLAIN_LIBS)					\
@@ -49,7 +47,6 @@ libempathy_accounts_common_la_LIBADD =					\
         $(top_builddir)/libempathy-gtk/libempathy-gtk.la		\
 	$(EDS_LIBS)							\
         $(LIBNOTIFY_LIBS)						\
-        $(UNIQUE_LIBS) \
         $(EMPATHY_LIBS)							\
         $(LIBCHAMPLAIN_LIBS)						\
         $(WEBKIT_LIBS)							\
@@ -144,7 +141,6 @@ empathy_LDADD =								\
         $(top_builddir)/libempathy/libempathy.la			\
         $(top_builddir)/extensions/libemp-extensions.la			\
         $(LIBNOTIFY_LIBS)						\
-        $(UNIQUE_LIBS)						\
         $(EMPATHY_LIBS)							\
         $(LIBCHAMPLAIN_LIBS)						\
         $(WEBKIT_LIBS)							\
diff --git a/src/empathy-accounts-common.c b/src/empathy-accounts-common.c
index a14a95c..8932fdb 100644
--- a/src/empathy-accounts-common.c
+++ b/src/empathy-accounts-common.c
@@ -31,7 +31,6 @@
 
 #include <gtk/gtk.h>
 #include <glib/gi18n-lib.h>
-#include <unique/unique.h>
 
 #include <telepathy-glib/account-manager.h>
 #include <telepathy-glib/util.h>
diff --git a/src/empathy-accounts.c b/src/empathy-accounts.c
index 788bc89..4131100 100644
--- a/src/empathy-accounts.c
+++ b/src/empathy-accounts.c
@@ -31,7 +31,6 @@
 
 #include <gtk/gtk.h>
 #include <glib/gi18n.h>
-#include <unique/unique.h>
 
 #include <telepathy-glib/account-manager.h>
 #include <telepathy-glib/defs.h>
@@ -135,35 +134,17 @@ account_manager_ready_for_accounts_cb (GObject *source_object,
     }
 }
 
-static UniqueResponse
-unique_app_message_cb (UniqueApp *unique_app,
-    gint command,
-    UniqueMessageData *data,
-    guint timestamp,
-    gpointer user_data)
+static void
+app_activated_cb (GtkApplication *app)
 {
-  DEBUG ("Other instance launched, presenting the main window. "
-      "Command=%d, timestamp %u", command, timestamp);
-
-  if (command == UNIQUE_ACTIVATE)
-    {
-      TpAccountManager *account_manager;
+  TpAccountManager *account_manager;
 
-      account_manager = tp_account_manager_dup ();
+  account_manager = tp_account_manager_dup ();
 
-      empathy_accounts_show_accounts_ui (account_manager, NULL,
+  empathy_accounts_show_accounts_ui (account_manager, NULL,
           G_CALLBACK (gtk_main_quit));
 
-      g_object_unref (account_manager);
-    }
-  else
-    {
-      g_warning (G_STRLOC "unhandled unique app command %d", command);
-
-      return UNIQUE_RESPONSE_PASSTHROUGH;
-    }
-
-  return UNIQUE_RESPONSE_OK;
+  g_object_unref (account_manager);
 }
 
 #define COMMAND_ACCOUNTS_DIALOG 1
@@ -173,7 +154,7 @@ main (int argc, char *argv[])
 {
   TpAccountManager *account_manager;
   GError *error = NULL;
-  UniqueApp *unique_app;
+  GtkApplication *app;
 
   GOptionContext *optcontext;
   GOptionEntry options[] = {
@@ -218,30 +199,20 @@ main (int argc, char *argv[])
   gtk_window_set_default_icon_name ("empathy");
   textdomain (GETTEXT_PACKAGE);
 
-  unique_app = unique_app_new (EMPATHY_ACCOUNTS_DBUS_NAME, NULL);
-
-  if (unique_app_is_running (unique_app))
-    {
-      if (unique_app_send_message (unique_app, UNIQUE_ACTIVATE, NULL) ==
-          UNIQUE_RESPONSE_OK)
-        {
-          g_object_unref (unique_app);
-          return EXIT_SUCCESS;
-        }
-    }
+  app = gtk_application_new (EMPATHY_ACCOUNTS_DBUS_NAME, &argc, &argv);
 
   account_manager = tp_account_manager_dup ();
 
   tp_account_manager_prepare_async (account_manager, NULL,
     account_manager_ready_for_accounts_cb, selected_account_name);
 
-  g_signal_connect (unique_app, "message-received",
-      G_CALLBACK (unique_app_message_cb), NULL);
+  g_signal_connect (app, "activated",
+      G_CALLBACK (app_activated_cb), NULL);
 
-  gtk_main ();
+  gtk_application_run (app);
 
   g_object_unref (account_manager);
-  g_object_unref (unique_app);
+  g_object_unref (app);
 
   return EXIT_SUCCESS;
 }
diff --git a/src/empathy-av.c b/src/empathy-av.c
index 9ef0fbf..c937c2a 100644
--- a/src/empathy-av.c
+++ b/src/empathy-av.c
@@ -41,6 +41,8 @@
 /* Exit after $TIMEOUT seconds if not displaying any call window */
 #define TIMEOUT 60
 
+#define EMPATHY_AV_DBUS_NAME "org.gnome.Empathy.AudioVideo"
+
 static guint nb_windows = 0;
 static guint timeout_id = 0;
 static gboolean use_timer = TRUE;
@@ -126,6 +128,7 @@ main (int argc,
 #endif
   EmpathyCallFactory *call_factory;
   GError *error = NULL;
+  GtkApplication *app;
 
   /* Init */
   g_thread_init (NULL);
@@ -152,6 +155,8 @@ main (int argc,
   gtk_window_set_default_icon_name ("empathy");
   textdomain (GETTEXT_PACKAGE);
 
+  app = gtk_application_new (EMPATHY_AV_DBUS_NAME, &argc, &argv);
+
 #ifdef ENABLE_DEBUG
   /* Set up debug sender */
   debug_sender = tp_debug_sender_dup ();
@@ -179,8 +184,9 @@ main (int argc,
 
   start_timer ();
 
-  gtk_main ();
+  gtk_application_run (app);
 
+  g_object_unref (app);
   g_object_unref (call_factory);
 
 #ifdef ENABLE_DEBUG
diff --git a/src/empathy-debugger.c b/src/empathy-debugger.c
index 9ff142b..2203041 100644
--- a/src/empathy-debugger.c
+++ b/src/empathy-debugger.c
@@ -27,16 +27,20 @@
 
 #include "empathy-debug-window.h"
 
+#define EMPATHY_DEBUGGER_DBUS_NAME "org.gnome.Empathy.Debugger"
+
 int
 main (int argc,
     char **argv)
 {
   GtkWidget *window;
+  GtkApplication *app;
 
   g_thread_init (NULL);
-  gtk_init (&argc, &argv);
   empathy_gtk_init ();
 
+  app = gtk_application_new (EMPATHY_DEBUGGER_DBUS_NAME, &argc, &argv);
+
   g_set_application_name (_("Empathy Debugger"));
 
   gtk_window_set_default_icon_name ("empathy");
@@ -45,7 +49,8 @@ main (int argc,
   window = empathy_debug_window_new (NULL);
   g_signal_connect (window, "destroy", gtk_main_quit, NULL);
 
-  gtk_main ();
+  gtk_application_run (app);
 
+  g_object_unref (app);
   return EXIT_SUCCESS;
 }
diff --git a/src/empathy.c b/src/empathy.c
index 2a8761c..314e4fb 100644
--- a/src/empathy.c
+++ b/src/empathy.c
@@ -30,7 +30,6 @@
 #include <glib/gi18n.h>
 #include <gtk/gtk.h>
 #include <gdk/gdkx.h>
-#include <unique/unique.h>
 
 #ifdef HAVE_LIBCHAMPLAIN
 #include <clutter-gtk/clutter-gtk.h>
@@ -73,13 +72,216 @@
 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
 #include <libempathy/empathy-debug.h>
 
-static gboolean start_hidden = FALSE;
-static gboolean no_connect = FALSE;
+#define EMPATHY_DBUS_NAME "org.gnome.Empathy"
+
+#define EMPATHY_TYPE_APP (empathy_app_get_type ())
+#define EMPATHY_APP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EMPATHY_TYPE_APP, EmpathyApp))
+#define EMPATHY_APP_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST ((obj), EMPATHY_TYPE_APP, EmpathyAppClass))
+#define EMPATHY_IS_EMPATHY_APP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EMPATHY_TYPE_APP))
+#define EMPATHY_IS_EMPATHY_APP_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((obj), EMPATHY_TYPE_APP))
+#define EMPATHY_APP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EMPATHY_TYPE_APP, EmpathyAppClass))
+
+typedef struct _EmpathyApp EmpathyApp;
+typedef struct _EmpathyAppClass EmpathyAppClass;
+
+enum
+{
+  PROP_NO_CONNECT = 1,
+  PROP_START_HIDDEN
+};
+
+GType empathy_app_get_type (void);
+
+struct _EmpathyAppClass
+{
+  GtkApplicationClass parent_class;
+};
+
+struct _EmpathyApp
+{
+  GtkApplication parent;
+
+  /* Properties */
+  gboolean no_connect;
+  gboolean start_hidden;
+
+  GtkWidget *window;
+  EmpathyStatusIcon *icon;
+  EmpathyDispatcher *dispatcher;
+  TpAccountManager *account_manager;
+  TplLogManager *log_manager;
+  EmpathyChatroomManager *chatroom_manager;
+  EmpathyFTFactory  *ft_factory;
+  EmpathyIdle *idle;
+  EmpathyConnectivity *connectivity;
+  EmpathyChatManager *chat_manager;
+  GSettings *gsettings;
+#ifdef HAVE_GEOCLUE
+  EmpathyLocationManager *location_manager;
+#endif
+#ifdef ENABLE_DEBUG
+  TpDebugSender *debug_sender;
+#endif
+};
+
+
+G_DEFINE_TYPE(EmpathyApp, empathy_app, GTK_TYPE_APPLICATION)
+
+static void
+empathy_app_dispose (GObject *object)
+{
+  EmpathyApp *self = EMPATHY_APP (object);
+  void (*dispose) (GObject *) =
+    G_OBJECT_CLASS (empathy_app_parent_class)->dispose;
+
+  if (self->idle != NULL)
+    {
+      empathy_idle_set_state (self->idle, TP_CONNECTION_PRESENCE_TYPE_OFFLINE);
+    }
+
+#ifdef ENABLE_DEBUG
+  tp_clear_object (&self->debug_sender);
+#endif
+
+  tp_clear_object (&self->chat_manager);
+  tp_clear_object (&self->idle);
+  tp_clear_object (&self->connectivity);
+  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);
+
+  if (dispose != NULL)
+    dispose (object);
+}
+
+static void
+empathy_app_finalize (GObject *object)
+{
+  EmpathyApp *self = EMPATHY_APP (object);
+  void (*finalize) (GObject *) =
+    G_OBJECT_CLASS (empathy_app_parent_class)->finalize;
+
+  gtk_widget_destroy (self->window);
+
+  if (finalize != NULL)
+    finalize (object);
+}
 
 static void account_manager_ready_cb (GObject *source_object,
     GAsyncResult *result,
     gpointer user_data);
 
+static EmpathyApp *
+empathy_app_new (guint argc,
+    const gchar * const * argv,
+    gboolean no_connect,
+    gboolean start_hidden)
+{
+  EmpathyApp *self;
+  GError *error = NULL;
+  GVariant *argv_variant;
+
+  argv_variant = g_variant_new_bytestring_array (argv, argc);
+
+  self = g_initable_new (EMPATHY_TYPE_APP,
+      NULL, &error,
+      "application-id", EMPATHY_DBUS_NAME,
+      "argv", argv_variant,
+      "register", TRUE,
+      "no-connect", no_connect,
+      "start-hidden", start_hidden,
+      NULL);
+
+  if (self == NULL)
+    {
+      g_critical ("Failed to initiate EmpathyApp: %s", error->message);
+      g_error_free (error);
+    }
+
+  return self;
+}
+
+static void
+empathy_app_set_property (GObject *object,
+    guint prop_id,
+    const GValue *value,
+    GParamSpec *pspec)
+{
+  EmpathyApp *self = EMPATHY_APP (object);
+
+  switch (prop_id)
+    {
+      case PROP_NO_CONNECT:
+        self->no_connect = g_value_get_boolean (value);
+        break;
+      case PROP_START_HIDDEN:
+        self->start_hidden = g_value_get_boolean (value);
+        break;
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
+empathy_app_activated (GtkApplication *app,
+    GVariant *args)
+{
+  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;
+
+  empathy_window_present (GTK_WINDOW (self->window));
+
+  /* Display the accounts dialog if needed */
+  tp_account_manager_prepare_async (self->account_manager, NULL,
+      account_manager_ready_cb, self);
+}
+
+static void empathy_app_constructed (GObject *object);
+
+static void
+empathy_app_class_init (EmpathyAppClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GtkApplicationClass *gtk_app_class = GTK_APPLICATION_CLASS (klass);
+  GParamSpec *spec;
+
+  gobject_class->set_property = empathy_app_set_property;
+  gobject_class->constructed = empathy_app_constructed;
+  gobject_class->dispose = empathy_app_dispose;
+  gobject_class->finalize = empathy_app_finalize;
+
+  gtk_app_class->activated = empathy_app_activated;
+
+  spec = g_param_spec_boolean ("no-connect", "no connect",
+      "Don't connect on startup",
+      FALSE,
+      G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
+  g_object_class_install_property (gobject_class, PROP_NO_CONNECT, spec);
+
+  spec = g_param_spec_boolean ("start-hidden", "start hidden",
+      "Don't display the contact list or any other dialogs on startup",
+      FALSE,
+      G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
+  g_object_class_install_property (gobject_class, PROP_START_HIDDEN, spec);
+}
+
+static void
+empathy_app_init (EmpathyApp *self)
+{
+}
+
 static void
 use_conn_notify_cb (GSettings *gsettings,
     const gchar *key,
@@ -160,54 +362,14 @@ migrate_config_to_xdg_dir (void)
 }
 
 static void
-show_accounts_ui (GdkScreen *screen,
+show_accounts_ui (EmpathyApp *self,
+    GdkScreen *screen,
     gboolean if_needed)
 {
   empathy_accounts_dialog_show_application (screen,
-      NULL, if_needed, start_hidden);
+      NULL, if_needed, self->start_hidden);
 }
 
-static UniqueResponse
-unique_app_message_cb (UniqueApp *unique_app,
-    gint command,
-    UniqueMessageData *data,
-    guint timestamp,
-    gpointer user_data)
-{
-  GtkWindow *window = user_data;
-  TpAccountManager *account_manager;
-
-  DEBUG ("Other instance launched, presenting the main window. "
-      "Command=%d, timestamp %u", command, timestamp);
-
-  /* XXX: the standalone app somewhat breaks this case, since
-   * communicating it would be a pain */
-
-  /* We're requested to show stuff again, disable the start hidden global
-   * in case the accounts wizard wants to pop up.
-   */
-  start_hidden = FALSE;
-
-  gtk_window_set_screen (GTK_WINDOW (window),
-      unique_message_data_get_screen (data));
-  gtk_window_set_startup_id (GTK_WINDOW (window),
-      unique_message_data_get_startup_id (data));
-  gtk_window_present_with_time (GTK_WINDOW (window), timestamp);
-  gtk_window_set_skip_taskbar_hint (window, FALSE);
-
-  account_manager = tp_account_manager_dup ();
-  tp_account_manager_prepare_async (account_manager, NULL,
-      account_manager_ready_cb, NULL);
-  g_object_unref (account_manager);
-
-  return UNIQUE_RESPONSE_OK;
-}
-
-static gboolean show_version_cb (const char *option_name,
-    const char *value,
-    gpointer data,
-    GError **error) G_GNUC_NORETURN;
-
 static gboolean
 show_version_cb (const char *option_name,
     const char *value,
@@ -251,11 +413,9 @@ account_manager_ready_cb (GObject *source_object,
     gpointer user_data)
 {
   TpAccountManager *manager = TP_ACCOUNT_MANAGER (source_object);
+  EmpathyApp *self = user_data;
   GError *error = NULL;
-  EmpathyIdle *idle;
-  EmpathyConnectivity *connectivity;
   TpConnectionPresenceType presence;
-  GSettings *gsettings = g_settings_new (EMPATHY_PREFS_SCHEMA);
 
   if (!tp_account_manager_prepare_finish (manager, result, &error))
     {
@@ -279,27 +439,21 @@ account_manager_ready_cb (GObject *source_object,
     }
 
   /* Autoconnect */
-  idle = empathy_idle_dup_singleton ();
-  connectivity = empathy_connectivity_dup_singleton ();
-
   presence = tp_account_manager_get_most_available_presence (manager, NULL,
       NULL);
 
-  if (g_settings_get_boolean (gsettings, EMPATHY_PREFS_AUTOCONNECT) &&
-      !no_connect &&
+  if (g_settings_get_boolean (self->gsettings, EMPATHY_PREFS_AUTOCONNECT) &&
+      !self->no_connect &&
       tp_connection_presence_type_cmp_availability
           (presence, TP_CONNECTION_PRESENCE_TYPE_OFFLINE)
             <= 0)
       /* if current state is Offline, then put it online */
-      empathy_idle_set_state (idle, TP_CONNECTION_PRESENCE_TYPE_AVAILABLE);
+      empathy_idle_set_state (self->idle,
+          TP_CONNECTION_PRESENCE_TYPE_AVAILABLE);
 
   /* Pop up the accounts dialog if we don't have any account */
   if (!empathy_accounts_has_accounts (manager))
-    show_accounts_ui (gdk_screen_get_default (), TRUE);
-
-  g_object_unref (idle);
-  g_object_unref (connectivity);
-  g_object_unref (gsettings);
+    show_accounts_ui (self, gdk_screen_get_default (), TRUE);
 }
 
 static void
@@ -396,70 +550,14 @@ empathy_idle_set_auto_away_cb (GSettings *gsettings,
       g_settings_get_boolean (gsettings, key));
 }
 
-int
-main (int argc, char *argv[])
+static void
+empathy_app_constructed (GObject *object)
 {
-#ifdef HAVE_GEOCLUE
-  EmpathyLocationManager *location_manager = NULL;
-#endif
-  EmpathyStatusIcon *icon;
-  EmpathyDispatcher *dispatcher;
-  TpAccountManager *account_manager;
-  TplLogManager *log_manager;
-  EmpathyChatroomManager *chatroom_manager;
-  EmpathyFTFactory  *ft_factory;
-  GtkWidget *window;
-  EmpathyIdle *idle;
-  EmpathyConnectivity *connectivity;
-  EmpathyChatManager *chat_manager;
+  EmpathyApp *self = (EmpathyApp *) object;
   GError *error = NULL;
-  UniqueApp *unique_app;
   gboolean chatroom_manager_ready;
-  gboolean autoaway = TRUE;
-#ifdef ENABLE_DEBUG
-  TpDebugSender *debug_sender;
-#endif
-  GSettings *gsettings;
+  gboolean autoaway;
 
-  GOptionContext *optcontext;
-  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 }
-  };
-
-  /* Init */
-  g_thread_init (NULL);
-
-#ifdef HAVE_LIBCHAMPLAIN
-  gtk_clutter_init (&argc, &argv);
-#endif
-
-  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 ();
   g_set_application_name (_(PACKAGE_NAME));
 
   gtk_window_set_default_icon_name ("empathy");
@@ -467,90 +565,77 @@ main (int argc, char *argv[])
 
 #ifdef ENABLE_DEBUG
   /* Set up debug sender */
-  debug_sender = tp_debug_sender_dup ();
+  self->debug_sender = tp_debug_sender_dup ();
   g_log_set_default_handler (tp_debug_sender_log_handler, G_LOG_DOMAIN);
 #endif
 
-  unique_app = unique_app_new ("org.gnome."PACKAGE_NAME, NULL);
-
-  if (unique_app_is_running (unique_app))
-    {
-      if (unique_app_send_message (unique_app, UNIQUE_ACTIVATE, NULL) ==
-          UNIQUE_RESPONSE_OK)
-        {
-          g_object_unref (unique_app);
-          return EXIT_SUCCESS;
-        }
-    }
-
   notify_init (_(PACKAGE_NAME));
 
   /* Setting up Idle */
-  idle = empathy_idle_dup_singleton ();
+  self->idle = empathy_idle_dup_singleton ();
 
-  gsettings = g_settings_new (EMPATHY_PREFS_SCHEMA);
-  autoaway = g_settings_get_boolean (gsettings, EMPATHY_PREFS_AUTOAWAY);
+  self->gsettings = g_settings_new (EMPATHY_PREFS_SCHEMA);
+  autoaway = g_settings_get_boolean (self->gsettings, EMPATHY_PREFS_AUTOAWAY);
 
-  g_signal_connect (gsettings,
+  g_signal_connect (self->gsettings,
       "changed::" EMPATHY_PREFS_AUTOAWAY,
-      G_CALLBACK (empathy_idle_set_auto_away_cb), idle);
+      G_CALLBACK (empathy_idle_set_auto_away_cb), self->idle);
 
-  empathy_idle_set_auto_away (idle, autoaway);
+  empathy_idle_set_auto_away (self->idle, autoaway);
 
   /* Setting up Connectivity */
-  connectivity = empathy_connectivity_dup_singleton ();
-  use_conn_notify_cb (gsettings, EMPATHY_PREFS_USE_CONN,
-      connectivity);
-  g_signal_connect (gsettings,
+  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), connectivity);
+      G_CALLBACK (use_conn_notify_cb), self->connectivity);
 
   /* account management */
-  account_manager = tp_account_manager_dup ();
-  tp_account_manager_prepare_async (account_manager, NULL,
-      account_manager_ready_cb, NULL);
+  self->account_manager = tp_account_manager_dup ();
+  tp_account_manager_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 */
-  dispatcher = empathy_dispatcher_dup_singleton ();
+  self->dispatcher = empathy_dispatcher_dup_singleton ();
 
   migrate_config_to_xdg_dir ();
 
   /* Setting up UI */
-  window = empathy_main_window_dup ();
-  gtk_widget_show (window);
-  icon = empathy_status_icon_new (GTK_WINDOW (window), start_hidden);
+  self->window = empathy_main_window_dup ();
+  gtk_widget_show (self->window);
+  self->icon = empathy_status_icon_new (GTK_WINDOW (self->window),
+      self->start_hidden);
 
   /* Chat manager */
-  chat_manager = empathy_chat_manager_dup_singleton ();
-
-  g_signal_connect (unique_app, "message-received",
-      G_CALLBACK (unique_app_message_cb), window);
+  self->chat_manager = empathy_chat_manager_dup_singleton ();
 
   /* Logging */
-  log_manager = tpl_log_manager_dup_singleton ();
+  self->log_manager = tpl_log_manager_dup_singleton ();
 
-  chatroom_manager = empathy_chatroom_manager_dup_singleton (NULL);
+  self->chatroom_manager = empathy_chatroom_manager_dup_singleton (NULL);
 
-  g_object_get (chatroom_manager, "ready", &chatroom_manager_ready, NULL);
+  g_object_get (self->chatroom_manager, "ready", &chatroom_manager_ready, NULL);
   if (!chatroom_manager_ready)
     {
-      g_signal_connect (G_OBJECT (chatroom_manager), "notify::ready",
-          G_CALLBACK (chatroom_manager_ready_cb), account_manager);
+      g_signal_connect (G_OBJECT (self->chatroom_manager), "notify::ready",
+          G_CALLBACK (chatroom_manager_ready_cb), self->account_manager);
     }
   else
     {
-      chatroom_manager_ready_cb (chatroom_manager, NULL, account_manager);
+      chatroom_manager_ready_cb (self->chatroom_manager, NULL,
+          self->account_manager);
     }
 
   /* Create the FT factory */
-  ft_factory = empathy_ft_factory_dup_singleton ();
-  g_signal_connect (ft_factory, "new-ft-handler",
+  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 (ft_factory, "new-incoming-transfer",
+  g_signal_connect (self->ft_factory, "new-incoming-transfer",
       G_CALLBACK (new_incoming_transfer_cb), NULL);
 
-  if (!empathy_ft_factory_register (ft_factory, &error))
+  if (!empathy_ft_factory_register (self->ft_factory, &error))
     {
       g_warning ("Failed to register FileTransfer handler: %s", error->message);
       g_error_free (error);
@@ -558,35 +643,64 @@ main (int argc, char *argv[])
 
   /* Location mananger */
 #ifdef HAVE_GEOCLUE
-  location_manager = empathy_location_manager_dup_singleton ();
+  self->location_manager = empathy_location_manager_dup_singleton ();
 #endif
+}
 
-  gtk_main ();
+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 }
+  };
 
-  empathy_idle_set_state (idle, TP_CONNECTION_PRESENCE_TYPE_OFFLINE);
+  g_thread_init (NULL);
+  g_type_init ();
 
-#ifdef ENABLE_DEBUG
-  g_object_unref (debug_sender);
+#ifdef HAVE_LIBCHAMPLAIN
+  gtk_clutter_init (&argc, &argv);
 #endif
 
-  g_object_unref (chat_manager);
-  g_object_unref (idle);
-  g_object_unref (connectivity);
-  g_object_unref (icon);
-  g_object_unref (account_manager);
-  g_object_unref (log_manager);
-  g_object_unref (dispatcher);
-  g_object_unref (chatroom_manager);
-#ifdef HAVE_GEOCLUE
-  g_object_unref (location_manager);
-#endif
-  g_object_unref (ft_factory);
-  g_object_unref (unique_app);
-  g_object_unref (gsettings);
-  gtk_widget_destroy (window);
+  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 ();
+
+  app = empathy_app_new (argc, (const gchar * const *) argv,
+      no_connect, start_hidden);
+
+  gtk_application_run (GTK_APPLICATION (app));
 
   notify_uninit ();
   xmlCleanupParser ();
 
+  g_object_unref (app);
   return EXIT_SUCCESS;
 }
