]> git.0d.be Git - empathy.git/blobdiff - src/empathy-chat-window.c
use a single window, with tabs
[empathy.git] / src / empathy-chat-window.c
index eb2e4b1330d2cc9182663cd360e3e926474b15a0..2f41d3d9b887d5b258dcf4b819727531701fd6cd 100644 (file)
@@ -1,7 +1,6 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
  * Copyright (C) 2003-2007 Imendio AB
- * Copyright (C) 2007-2010 Collabora Ltd.
+ * Copyright (C) 2007-2012 Collabora Ltd.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
  *          Rômulo Fernandes Machado <romulo@castorgroup.net>
  */
 
-#include <config.h>
-
-#include <string.h>
+#include "config.h"
+#include "empathy-chat-window.h"
 
-#include <gtk/gtk.h>
-#include <gdk/gdkkeysyms.h>
-#include <gdk/gdkx.h>
 #include <glib/gi18n.h>
-#include <libnotify/notification.h>
-
-#include <telepathy-glib/telepathy-glib.h>
-
-#include <libempathy/empathy-client-factory.h>
-#include <libempathy/empathy-contact.h>
-#include <libempathy/empathy-message.h>
-#include <libempathy/empathy-chatroom-manager.h>
-#include <libempathy/empathy-gsettings.h>
-#include <libempathy/empathy-utils.h>
-#include <libempathy/empathy-tp-contact-factory.h>
-#include <libempathy/empathy-request-util.h>
-#include <libempathy/empathy-individual-manager.h>
-
-#include <libempathy-gtk/empathy-images.h>
-#include <libempathy-gtk/empathy-contact-dialogs.h>
-#include <libempathy-gtk/empathy-log-window.h>
-#include <libempathy-gtk/empathy-geometry.h>
-#include <libempathy-gtk/empathy-smiley-manager.h>
-#include <libempathy-gtk/empathy-sound-manager.h>
-#include <libempathy-gtk/empathy-ui-utils.h>
-#include <libempathy-gtk/empathy-notify-manager.h>
+#include <tp-account-widgets/tpaw-builder.h>
+#include <tp-account-widgets/tpaw-utils.h>
 
-#include "empathy-chat-manager.h"
-#include "empathy-chat-window.h"
 #include "empathy-about-dialog.h"
+#include "empathy-chat-manager.h"
+#include "empathy-chatroom-manager.h"
+#include "empathy-client-factory.h"
+#include "empathy-geometry.h"
+#include "empathy-gsettings.h"
+#include "empathy-images.h"
 #include "empathy-invite-participant-dialog.h"
-#include "gedit-close-button.h"
+#include "empathy-notify-manager.h"
+#include "empathy-request-util.h"
+#include "empathy-sound-manager.h"
+#include "empathy-ui-utils.h"
+#include "empathy-utils.h"
+#include "empathy-new-message-dialog.h"
 
 #define DEBUG_FLAG EMPATHY_DEBUG_CHAT
-#include <libempathy/empathy-debug.h>
+#include "empathy-debug.h"
 
 /* Macro to compare guint32 X timestamps, while accounting for wrapping around
  */
 #define X_EARLIER_OR_EQL(t1, t2) \
-       ((t1 <= t2 && ((t2 - t1) < G_MAXUINT32/2))  \
-         || (t1 >= t2 && (t1 - t2) > (G_MAXUINT32/2)) \
-       )
-
-#define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyChatWindow)
-typedef struct {
-       EmpathyChat *current_chat;
-       GList       *chats;
-       gboolean     page_added;
-       gboolean     dnd_same_window;
-       EmpathyChatroomManager *chatroom_manager;
-       EmpathyNotifyManager *notify_mgr;
-       GtkWidget   *dialog;
-       GtkWidget   *notebook;
-       NotifyNotification *notification;
-
-       GtkTargetList *contact_targets;
-       GtkTargetList *file_targets;
-
-       EmpathyChatManager *chat_manager;
-       gulong chat_manager_chats_changed_id;
-
-       /* Menu items. */
-       GtkUIManager *ui_manager;
-       GtkAction   *menu_conv_insert_smiley;
-       GtkAction   *menu_conv_favorite;
-       GtkAction   *menu_conv_always_urgent;
-       GtkAction   *menu_conv_toggle_contacts;
-
-       GtkAction   *menu_edit_cut;
-       GtkAction   *menu_edit_copy;
-       GtkAction   *menu_edit_paste;
-       GtkAction   *menu_edit_find;
-
-       GtkAction   *menu_tabs_next;
-       GtkAction   *menu_tabs_prev;
-       GtkAction   *menu_tabs_undo_close_tab;
-       GtkAction   *menu_tabs_left;
-       GtkAction   *menu_tabs_right;
-       GtkAction   *menu_tabs_detach;
-
-       /* Last user action time we acted upon to show a tab */
-       guint32    x_user_action_time;
-
-       GSettings *gsettings_chat;
-       GSettings *gsettings_notif;
-       GSettings *gsettings_ui;
-
-       EmpathySoundManager *sound_mgr;
-} EmpathyChatWindowPriv;
+  ((t1 <= t2 && ((t2 - t1) < G_MAXUINT32/2))  \
+    || (t1 >= t2 && (t1 - t2) > (G_MAXUINT32/2)) \
+  )
+
+enum
+{
+  PROP_INDIVIDUAL_MGR = 1
+};
+
+struct _EmpathyChatWindowPriv
+{
+  EmpathyChat *current_chat;
+  GList *chats;
+  gboolean page_added;
+  gboolean dnd_same_window;
+  EmpathyChatroomManager *chatroom_manager;
+  EmpathyNotifyManager *notify_mgr;
+  EmpathyIndividualManager *individual_mgr;
+  GtkWidget *notebook;
+  NotifyNotification *notification;
+
+  GtkTargetList *contact_targets;
+  GtkTargetList *file_targets;
+
+  EmpathyChatManager *chat_manager;
+  gulong chat_manager_chats_changed_id;
+
+  /* Menu items. */
+  GtkUIManager *ui_manager;
+  GtkAction *menu_conv_insert_smiley;
+  GtkAction *menu_conv_favorite;
+  GtkAction *menu_conv_join_chat;
+  GtkAction *menu_conv_leave_chat;
+  GtkAction *menu_conv_always_urgent;
+  GtkAction *menu_conv_toggle_contacts;
+
+  GtkAction *menu_edit_cut;
+  GtkAction *menu_edit_copy;
+  GtkAction *menu_edit_paste;
+  GtkAction *menu_edit_find;
+
+  GtkAction *menu_tabs_next;
+  GtkAction *menu_tabs_prev;
+  GtkAction *menu_tabs_undo_close_tab;
+  GtkAction *menu_tabs_left;
+  GtkAction *menu_tabs_right;
+  GtkAction *menu_tabs_detach;
+
+  /* Last user action time we acted upon to show a tab */
+  guint32 x_user_action_time;
+
+  GSettings *gsettings_chat;
+  GSettings *gsettings_notif;
+  GSettings *gsettings_ui;
+
+  EmpathySoundManager *sound_mgr;
+
+  gboolean updating_menu;
+};
 
 static GList *chat_windows = NULL;
 
-static const guint tab_accel_keys[] = {
-       GDK_KEY_1, GDK_KEY_2, GDK_KEY_3, GDK_KEY_4, GDK_KEY_5,
-       GDK_KEY_6, GDK_KEY_7, GDK_KEY_8, GDK_KEY_9, GDK_KEY_0
+static const guint tab_accel_keys[] =
+{
+  GDK_KEY_1, GDK_KEY_2, GDK_KEY_3, GDK_KEY_4, GDK_KEY_5,
+  GDK_KEY_6, GDK_KEY_7, GDK_KEY_8, GDK_KEY_9, GDK_KEY_0
 };
 
-typedef enum {
-       DND_DRAG_TYPE_CONTACT_ID,
-       DND_DRAG_TYPE_INDIVIDUAL_ID,
-       DND_DRAG_TYPE_URI_LIST,
-       DND_DRAG_TYPE_TAB
+typedef enum
+{
+  DND_DRAG_TYPE_CONTACT_ID,
+  DND_DRAG_TYPE_INDIVIDUAL_ID,
+  DND_DRAG_TYPE_URI_LIST,
+  DND_DRAG_TYPE_TAB
 } DndDragType;
 
-static const GtkTargetEntry drag_types_dest[] = {
-       { "text/contact-id", 0, DND_DRAG_TYPE_CONTACT_ID },
-       { "text/x-individual-id", 0, DND_DRAG_TYPE_INDIVIDUAL_ID },
-       { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, DND_DRAG_TYPE_TAB },
-       { "text/uri-list", 0, DND_DRAG_TYPE_URI_LIST },
-       { "text/path-list", 0, DND_DRAG_TYPE_URI_LIST },
+static const GtkTargetEntry drag_types_dest[] =
+{
+  { "text/contact-id", 0, DND_DRAG_TYPE_CONTACT_ID },
+  { "text/x-individual-id", 0, DND_DRAG_TYPE_INDIVIDUAL_ID },
+  { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, DND_DRAG_TYPE_TAB },
+  /* FIXME: disabled because of bug #640513
+  { "text/uri-list", 0, DND_DRAG_TYPE_URI_LIST },
+  { "text/path-list", 0, DND_DRAG_TYPE_URI_LIST },
+  */
 };
 
-static const GtkTargetEntry drag_types_dest_contact[] = {
-       { "text/contact-id", 0, DND_DRAG_TYPE_CONTACT_ID },
-       { "text/x-individual-id", 0, DND_DRAG_TYPE_INDIVIDUAL_ID },
+static const GtkTargetEntry drag_types_dest_contact[] =
+{
+  { "text/contact-id", 0, DND_DRAG_TYPE_CONTACT_ID },
+  { "text/x-individual-id", 0, DND_DRAG_TYPE_INDIVIDUAL_ID },
 };
 
-static const GtkTargetEntry drag_types_dest_file[] = {
-       /* must be first to be prioritized, in order to receive the
-        * note's file path from Tomboy instead of an URI */
-       { "text/path-list", 0, DND_DRAG_TYPE_URI_LIST },
-       { "text/uri-list", 0, DND_DRAG_TYPE_URI_LIST },
+static const GtkTargetEntry drag_types_dest_file[] =
+{
+  /* must be first to be prioritized, in order to receive the
+   * note's file path from Tomboy instead of an URI */
+  { "text/path-list", 0, DND_DRAG_TYPE_URI_LIST },
+  { "text/uri-list", 0, DND_DRAG_TYPE_URI_LIST },
 };
 
 static void chat_window_update (EmpathyChatWindow *window,
-               gboolean update_contact_menu);
+    gboolean update_contact_menu);
 
 static void empathy_chat_window_add_chat (EmpathyChatWindow *window,
-                             EmpathyChat       *chat);
+    EmpathyChat *chat);
 
 static void empathy_chat_window_remove_chat (EmpathyChatWindow *window,
-                                EmpathyChat       *chat);
+    EmpathyChat *chat);
 
 static void empathy_chat_window_move_chat (EmpathyChatWindow *old_window,
-                              EmpathyChatWindow *new_window,
-                              EmpathyChat       *chat);
+    EmpathyChatWindow *new_window,
+    EmpathyChat *chat);
 
 static void empathy_chat_window_get_nb_chats (EmpathyChatWindow *self,
-                              guint *nb_rooms,
-                              guint *nb_private);
+    guint *nb_rooms,
+    guint *nb_private);
 
-G_DEFINE_TYPE (EmpathyChatWindow, empathy_chat_window, G_TYPE_OBJECT);
+G_DEFINE_TYPE (EmpathyChatWindow, empathy_chat_window, GTK_TYPE_BIN)
 
 static void
-chat_window_accel_cb (GtkAccelGroup    *accelgroup,
-                     GObject          *object,
-                     guint             key,
-                     GdkModifierType   mod,
-                     EmpathyChatWindow *window)
+chat_window_accel_cb (GtkAccelGroup *accelgroup,
+    GObject *object,
+    guint key,
+    GdkModifierType mod,
+    EmpathyChatWindow *self)
 {
-       EmpathyChatWindowPriv *priv;
-       gint                  num = -1;
-       guint                 i;
+  gint num = -1;
+  guint i;
 
-       priv = GET_PRIV (window);
+  for (i = 0; i < G_N_ELEMENTS (tab_accel_keys); i++)
+    {
+      if (tab_accel_keys[i] == key)
+        {
+          num = i;
+          break;
+        }
+    }
 
-       for (i = 0; i < G_N_ELEMENTS (tab_accel_keys); i++) {
-               if (tab_accel_keys[i] == key) {
-                       num = i;
-                       break;
-               }
-       }
-
-       if (num != -1) {
-               gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), num);
-       }
+  if (num != -1)
+    gtk_notebook_set_current_page (GTK_NOTEBOOK (self->priv->notebook), num);
 }
 
 static EmpathyChatWindow *
 chat_window_find_chat (EmpathyChat *chat)
 {
-       EmpathyChatWindowPriv *priv;
-       GList                 *l, *ll;
+  GList *l, *ll;
+
+  for (l = chat_windows; l; l = l->next)
+    {
+      EmpathyChatWindow *window = l->data;
 
-       for (l = chat_windows; l; l = l->next) {
-               priv = GET_PRIV (l->data);
-               ll = g_list_find (priv->chats, chat);
-               if (ll) {
-                       return l->data;
-               }
-       }
+      ll = g_list_find (window->priv->chats, chat);
+      if (ll)
+        return l->data;
+    }
 
-       return NULL;
+  return NULL;
 }
 
 static void
-remove_all_chats (EmpathyChatWindow *window)
+remove_all_chats (EmpathyChatWindow *self)
 {
-       EmpathyChatWindowPriv *priv;
-
-       priv = GET_PRIV (window);
-       g_object_ref (window);
+  g_object_ref (self);
 
-       while (priv->chats) {
-               empathy_chat_window_remove_chat (window, priv->chats->data);
-       }
+  while (self->priv->chats)
+    empathy_chat_window_remove_chat (self, self->priv->chats->data);
 
-       g_object_unref (window);
+  g_object_unref (self);
 }
 
 static void
 confirm_close_response_cb (GtkWidget *dialog,
-                           int response,
-                           EmpathyChatWindow *window)
-{
-       EmpathyChat *chat;
-
-       chat = g_object_get_data (G_OBJECT (dialog), "chat");
-
-       gtk_widget_destroy (dialog);
-
-       if (response != GTK_RESPONSE_ACCEPT)
-               return;
-
-       if (chat != NULL) {
-               empathy_chat_window_remove_chat (window, chat);
-       } else {
-               remove_all_chats (window);
-       }
-}
-
-static void
-confirm_close (EmpathyChatWindow *window,
-               gboolean close_window,
-               guint n_rooms,
-               EmpathyChat *chat)
-{
-       EmpathyChatWindowPriv *priv;
-       GtkWidget *dialog;
-       gchar *primary, *secondary;
-
-       g_return_if_fail (n_rooms > 0);
-
-       if (n_rooms > 1) {
-               g_return_if_fail (chat == NULL);
-       } else {
-               g_return_if_fail (chat != NULL);
-       }
-
-       priv = GET_PRIV (window);
-
-       /* If there are no chats in this window, how could we possibly have got
-        * here?
-        */
-       g_return_if_fail (priv->chats != NULL);
-
-       /* Treat closing a window which only has one tab exactly like closing
-        * that tab.
-        */
-       if (close_window && priv->chats->next == NULL) {
-               close_window = FALSE;
-               chat = priv->chats->data;
-       }
-
-       if (close_window) {
-               primary = g_strdup (_("Close this window?"));
-
-               if (n_rooms == 1) {
-                       gchar *chat_name = empathy_chat_dup_name (chat);
-                       secondary = g_strdup_printf (
-                               _("Closing this window will leave %s. You will "
-                                 "not receive any further messages until you "
-                                 "rejoin it."),
-                               chat_name);
-                       g_free (chat_name);
-               } else {
-                       secondary = g_strdup_printf (
-                               /* Note to translators: the number of chats will
-                                * always be at least 2.
-                                */
-                               ngettext (
-                                       "Closing this window will leave a chat room. You will "
-                                       "not receive any further messages until you rejoin it.",
-                                       "Closing this window will leave %u chat rooms. You will "
-                                       "not receive any further messages until you rejoin them.",
-                                       n_rooms),
-                               n_rooms);
-               }
-       } else {
-               gchar *chat_name = empathy_chat_dup_name (chat);
-               primary = g_strdup_printf (_("Leave %s?"), chat_name);
-               secondary = g_strdup (_("You will not receive any further messages from this chat "
-                                       "room until you rejoin it."));
-               g_free (chat_name);
-       }
-
-       dialog = gtk_message_dialog_new (
-               GTK_WINDOW (priv->dialog),
-               GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
-               GTK_MESSAGE_WARNING,
-               GTK_BUTTONS_CANCEL,
-               "%s", primary);
-
-       gtk_window_set_title (GTK_WINDOW (dialog), "");
-       g_object_set (dialog, "secondary-text", secondary, NULL);
-
-       g_free (primary);
-       g_free (secondary);
-
-       gtk_dialog_add_button (GTK_DIALOG (dialog),
-               close_window ? _("Close window") : _("Leave room"),
-               GTK_RESPONSE_ACCEPT);
-       gtk_dialog_set_default_response (GTK_DIALOG (dialog),
-               GTK_RESPONSE_ACCEPT);
-
-       if (!close_window) {
-               g_object_set_data (G_OBJECT (dialog), "chat", chat);
-       }
-
-       g_signal_connect (dialog, "response",
-               G_CALLBACK (confirm_close_response_cb), window);
-
-       gtk_window_present (GTK_WINDOW (dialog));
-}
-
-/* Returns TRUE if we should check if the user really wants to leave.  If it's
+    int response,
+    EmpathyChatWindow *window)
+{
+  EmpathyChat *chat;
+
+  chat = g_object_get_data (G_OBJECT (dialog), "chat");
+
+  gtk_widget_destroy (dialog);
+
+  if (response != GTK_RESPONSE_ACCEPT)
+    return;
+
+  if (chat != NULL)
+    empathy_chat_window_remove_chat (window, chat);
+  else
+    remove_all_chats (window);
+}
+
+static void
+confirm_close (EmpathyChatWindow *self,
+    gboolean close_window,
+    guint n_rooms,
+    EmpathyChat *chat)
+{
+  GtkWidget *dialog;
+  gchar *primary, *secondary;
+
+  g_return_if_fail (n_rooms > 0);
+
+  if (n_rooms > 1)
+    g_return_if_fail (chat == NULL);
+  else
+    g_return_if_fail (chat != NULL);
+
+  /* If there are no chats in this window, how could we possibly have got
+   * here?
+   */
+  g_return_if_fail (self->priv->chats != NULL);
+
+  /* Treat closing a window which only has one tab exactly like closing
+   * that tab.
+   */
+  if (close_window && self->priv->chats->next == NULL)
+    {
+      close_window = FALSE;
+      chat = self->priv->chats->data;
+    }
+
+  if (close_window)
+    {
+      primary = g_strdup (_("Close this window?"));
+
+      if (n_rooms == 1)
+        {
+          gchar *chat_name = empathy_chat_dup_name (chat);
+          secondary = g_strdup_printf (
+            _("Closing this window will leave %s. You will "
+              "not receive any further messages until you "
+              "rejoin it."),
+            chat_name);
+          g_free (chat_name);
+        }
+      else
+        {
+          secondary = g_strdup_printf (
+            /* Note to translators: the number of chats will
+             * always be at least 2.
+             */
+            ngettext (
+              "Closing this window will leave a chat room. You will "
+              "not receive any further messages until you rejoin it.",
+              "Closing this window will leave %u chat rooms. You will "
+              "not receive any further messages until you rejoin them.",
+              n_rooms),
+            n_rooms);
+        }
+    }
+  else
+    {
+      gchar *chat_name = empathy_chat_dup_name (chat);
+      primary = g_strdup_printf (_("Leave %s?"), chat_name);
+      secondary = g_strdup (
+          _("You will not receive any further messages from this chat "
+            "room until you rejoin it."));
+      g_free (chat_name);
+    }
+
+  dialog = gtk_message_dialog_new (
+    GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (self))),
+    GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+    GTK_MESSAGE_WARNING,
+    GTK_BUTTONS_CANCEL,
+    "%s", primary);
+
+  gtk_window_set_title (GTK_WINDOW (dialog), "");
+  g_object_set (dialog, "secondary-text", secondary, NULL);
+
+  g_free (primary);
+  g_free (secondary);
+
+  gtk_dialog_add_button (GTK_DIALOG (dialog),
+    close_window ? _("Close window") : _("Leave room"),
+    GTK_RESPONSE_ACCEPT);
+  gtk_dialog_set_default_response (GTK_DIALOG (dialog),
+    GTK_RESPONSE_ACCEPT);
+
+  if (!close_window)
+    g_object_set_data (G_OBJECT (dialog), "chat", chat);
+
+  g_signal_connect (dialog, "response",
+    G_CALLBACK (confirm_close_response_cb), self);
+
+  gtk_window_present (GTK_WINDOW (dialog));
+}
+
+/* Returns TRUE if we should check if the user really wants to leave. If it's
  * a multi-user chat, and it has a TpChat (so there's an underlying channel, so
  * the user is actually in the room as opposed to having been kicked or gone
  * offline or something), then we should check.
@@ -353,2407 +349,2589 @@ confirm_close (EmpathyChatWindow *window,
 static gboolean
 chat_needs_close_confirmation (EmpathyChat *chat)
 {
-       return (empathy_chat_is_room (chat)
-               && empathy_chat_get_tp_chat (chat) != NULL);
+  return (empathy_chat_is_room (chat) &&
+      empathy_chat_get_tp_chat (chat) != NULL);
 }
 
 static void
 maybe_close_chat (EmpathyChatWindow *window,
-                  EmpathyChat *chat)
+    EmpathyChat *chat)
 {
-       g_return_if_fail (chat != NULL);
+  g_return_if_fail (chat != NULL);
 
-       if (chat_needs_close_confirmation (chat)) {
-               confirm_close (window, FALSE, 1, chat);
-       } else {
-               empathy_chat_window_remove_chat (window, chat);
-       }
+  if (chat_needs_close_confirmation (chat))
+    confirm_close (window, FALSE, 1, chat);
+  else
+    empathy_chat_window_remove_chat (window, chat);
 }
 
 static void
-chat_window_close_clicked_cb (GtkAction   *action,
-                             EmpathyChat *chat)
+chat_window_close_clicked_cb (GtkAction *action,
+    EmpathyChat *chat)
 {
-       EmpathyChatWindow *window;
+  EmpathyChatWindow *window;
 
-       window = chat_window_find_chat (chat);
-       maybe_close_chat (window, chat);
+  window = chat_window_find_chat (chat);
+  maybe_close_chat (window, chat);
 }
 
 static void
 chat_tab_style_updated_cb (GtkWidget *hbox,
-                          gpointer   user_data)
+    gpointer user_data)
 {
-       GtkWidget *button;
-       int char_width, h, w;
-       PangoContext *context;
-       const PangoFontDescription *font_desc;
-       PangoFontMetrics *metrics;
+  GtkWidget *button;
+  int char_width, h, w;
+  PangoContext *context;
+  PangoFontDescription *font_desc;
+  PangoFontMetrics *metrics;
 
-       button = g_object_get_data (G_OBJECT (user_data),
-               "chat-window-tab-close-button");
-       context = gtk_widget_get_pango_context (hbox);
+  button = g_object_get_data (G_OBJECT (user_data),
+    "chat-window-tab-close-button");
+  context = gtk_widget_get_pango_context (hbox);
 
-       font_desc = gtk_style_context_get_font (gtk_widget_get_style_context (hbox),
-                                               GTK_STATE_FLAG_NORMAL);
+  gtk_style_context_get (gtk_widget_get_style_context (hbox),
+      GTK_STATE_FLAG_NORMAL,
+      "font", &font_desc,
+      NULL);
 
-       metrics = pango_context_get_metrics (context, font_desc,
-               pango_context_get_language (context));
-       char_width = pango_font_metrics_get_approximate_char_width (metrics);
-       pango_font_metrics_unref (metrics);
+  metrics = pango_context_get_metrics (context, font_desc,
+    pango_context_get_language (context));
+  char_width = pango_font_metrics_get_approximate_char_width (metrics);
+  pango_font_metrics_unref (metrics);
 
-       gtk_icon_size_lookup_for_settings (gtk_widget_get_settings (button),
-                                          GTK_ICON_SIZE_MENU, &w, &h);
+  gtk_icon_size_lookup_for_settings (gtk_widget_get_settings (button),
+      GTK_ICON_SIZE_MENU, &w, &h);
 
-       /* Request at least about 12 chars width plus at least space for the status
-        * image and the close button */
-       gtk_widget_set_size_request (hbox,
-               12 * PANGO_PIXELS (char_width) + 2 * w, -1);
+  /* Request at least about 12 chars width plus at least space for the status
+   * image and the close button */
+  gtk_widget_set_size_request (hbox,
+    12 * PANGO_PIXELS (char_width) + 2 * w, -1);
 
-       gtk_widget_set_size_request (button, w, h);
+  gtk_widget_set_size_request (button, w, h);
+  pango_font_description_free (font_desc);
+}
+
+static GtkWidget *
+create_close_button (void)
+{
+  GtkWidget *button, *image;
+  GtkStyleContext *context;
+
+  button = gtk_button_new ();
+
+  context = gtk_widget_get_style_context (button);
+  gtk_style_context_add_class (context, "empathy-tab-close-button");
+
+  gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
+  gtk_button_set_focus_on_click (GTK_BUTTON (button), FALSE);
+
+  /* We don't want focus/keynav for the button to avoid clutter, and
+   * Ctrl-W works anyway.
+   */
+  gtk_widget_set_can_focus (button, FALSE);
+  gtk_widget_set_can_default (button, FALSE);
+
+  image = gtk_image_new_from_icon_name ("window-close-symbolic",
+      GTK_ICON_SIZE_MENU);
+  gtk_widget_show (image);
+
+  gtk_container_add (GTK_CONTAINER (button), image);
+
+  return button;
 }
 
 static GtkWidget *
 chat_window_create_label (EmpathyChatWindow *window,
-                         EmpathyChat       *chat,
-                         gboolean           is_tab_label)
+    EmpathyChat *chat,
+    gboolean is_tab_label)
 {
-       GtkWidget            *hbox;
-       GtkWidget            *name_label;
-       GtkWidget            *status_image;
-       GtkWidget            *event_box;
-       GtkWidget            *event_box_hbox;
-       PangoAttrList        *attr_list;
-       PangoAttribute       *attr;
+  GtkWidget *hbox;
+  GtkWidget *name_label;
+  GtkWidget *status_image;
+  GtkWidget *event_box;
+  GtkWidget *event_box_hbox;
+  PangoAttrList *attr_list;
+  PangoAttribute *attr;
 
-       /* The spacing between the button and the label. */
-       hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+  /* The spacing between the button and the label. */
+  hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
 
-       event_box = gtk_event_box_new ();
-       gtk_event_box_set_visible_window (GTK_EVENT_BOX (event_box), FALSE);
+  event_box = gtk_event_box_new ();
+  gtk_event_box_set_visible_window (GTK_EVENT_BOX (event_box), FALSE);
 
-       name_label = gtk_label_new (NULL);
-       if (is_tab_label)
-               gtk_label_set_ellipsize (GTK_LABEL (name_label), PANGO_ELLIPSIZE_END);
+  name_label = gtk_label_new (NULL);
+  if (is_tab_label)
+    gtk_label_set_ellipsize (GTK_LABEL (name_label), PANGO_ELLIPSIZE_END);
 
-       attr_list = pango_attr_list_new ();
-       attr = pango_attr_scale_new (1/1.2);
-       attr->start_index = 0;
-       attr->end_index = -1;
-       pango_attr_list_insert (attr_list, attr);
-       gtk_label_set_attributes (GTK_LABEL (name_label), attr_list);
-       pango_attr_list_unref (attr_list);
-
-       gtk_misc_set_padding (GTK_MISC (name_label), 2, 0);
-       gtk_misc_set_alignment (GTK_MISC (name_label), 0.0, 0.5);
-       g_object_set_data (G_OBJECT (chat),
-               is_tab_label ? "chat-window-tab-label" : "chat-window-menu-label",
-               name_label);
+  attr_list = pango_attr_list_new ();
+  attr = pango_attr_scale_new (1/1.2);
+  attr->start_index = 0;
+  attr->end_index = -1;
+  pango_attr_list_insert (attr_list, attr);
+  gtk_label_set_attributes (GTK_LABEL (name_label), attr_list);
+  pango_attr_list_unref (attr_list);
 
-       status_image = gtk_image_new ();
+  gtk_misc_set_padding (GTK_MISC (name_label), 2, 0);
+  gtk_misc_set_alignment (GTK_MISC (name_label), 0.0, 0.5);
+  g_object_set_data (G_OBJECT (chat),
+    is_tab_label ? "chat-window-tab-label" : "chat-window-menu-label",
+    name_label);
 
-       /* Spacing between the icon and label. */
-       event_box_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+  status_image = gtk_image_new ();
 
-       gtk_box_pack_start (GTK_BOX (event_box_hbox), status_image, FALSE, FALSE, 0);
-       gtk_box_pack_start (GTK_BOX (event_box_hbox), name_label, TRUE, TRUE, 0);
+  /* Spacing between the icon and label. */
+  event_box_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
 
-       g_object_set_data (G_OBJECT (chat),
-               is_tab_label ? "chat-window-tab-image" : "chat-window-menu-image",
-               status_image);
-       g_object_set_data (G_OBJECT (chat),
-               is_tab_label ? "chat-window-tab-tooltip-widget" : "chat-window-menu-tooltip-widget",
-               event_box);
+  gtk_box_pack_start (GTK_BOX (event_box_hbox), status_image, FALSE, FALSE, 0);
+  gtk_box_pack_start (GTK_BOX (event_box_hbox), name_label, TRUE, TRUE, 0);
 
-       gtk_container_add (GTK_CONTAINER (event_box), event_box_hbox);
-       gtk_box_pack_start (GTK_BOX (hbox), event_box, TRUE, TRUE, 0);
+  g_object_set_data (G_OBJECT (chat),
+    is_tab_label ? "chat-window-tab-image" : "chat-window-menu-image",
+    status_image);
+  g_object_set_data (G_OBJECT (chat),
+    is_tab_label ? "chat-window-tab-tooltip-widget" :
+      "chat-window-menu-tooltip-widget",
+    event_box);
 
-       if (is_tab_label) {
-               GtkWidget            *close_button;
-               GtkWidget *sending_spinner;
+  gtk_container_add (GTK_CONTAINER (event_box), event_box_hbox);
+  gtk_box_pack_start (GTK_BOX (hbox), event_box, TRUE, TRUE, 0);
 
-               sending_spinner = gtk_spinner_new ();
+  if (is_tab_label)
+    {
+      GtkWidget *close_button;
+      GtkWidget *sending_spinner;
 
-               gtk_box_pack_start (GTK_BOX (hbox), sending_spinner,
-                       FALSE, FALSE, 0);
-               g_object_set_data (G_OBJECT (chat),
-                       "chat-window-tab-sending-spinner",
-                       sending_spinner);
+      sending_spinner = gtk_spinner_new ();
 
-               close_button = gedit_close_button_new ();
-               g_object_set_data (G_OBJECT (chat), "chat-window-tab-close-button", close_button);
+      gtk_box_pack_start (GTK_BOX (hbox), sending_spinner,
+        FALSE, FALSE, 0);
+      g_object_set_data (G_OBJECT (chat),
+        "chat-window-tab-sending-spinner",
+        sending_spinner);
 
-               /* We don't want focus/keynav for the button to avoid clutter, and
-                * Ctrl-W works anyway.
-                */
-               gtk_widget_set_can_focus (close_button, FALSE);
-               gtk_widget_set_can_default (close_button, FALSE);
+      close_button = create_close_button ();
+      g_object_set_data (G_OBJECT (chat), "chat-window-tab-close-button",
+          close_button);
 
-               gtk_box_pack_end (GTK_BOX (hbox), close_button, FALSE, FALSE, 0);
+      gtk_box_pack_end (GTK_BOX (hbox), close_button, FALSE, FALSE, 0);
 
-               g_signal_connect (close_button,
-                                 "clicked",
-                                 G_CALLBACK (chat_window_close_clicked_cb),
-                                 chat);
+      g_signal_connect (close_button,
+          "clicked",
+          G_CALLBACK (chat_window_close_clicked_cb), chat);
 
-               /* React to theme changes and also setup the size correctly.  */
-               g_signal_connect (hbox,
-                                 "style-updated",
-                                 G_CALLBACK (chat_tab_style_updated_cb),
-                                 chat);
-       }
+      /* React to theme changes and also setup the size correctly. */
+      g_signal_connect (hbox, "style-updated",
+          G_CALLBACK (chat_tab_style_updated_cb), chat);
+    }
 
-       gtk_widget_show_all (hbox);
+  gtk_widget_show_all (hbox);
 
-       return hbox;
+  return hbox;
 }
 
 static void
-_submenu_notify_visible_changed_cb (GObject    *object,
-                                   GParamSpec *pspec,
-                                   gpointer    userdata)
+_submenu_notify_visible_changed_cb (GObject *object,
+    GParamSpec *pspec,
+    gpointer userdata)
 {
-       g_signal_handlers_disconnect_by_func (object,
-                                             _submenu_notify_visible_changed_cb,
-                                             userdata);
-       chat_window_update (EMPATHY_CHAT_WINDOW (userdata), TRUE);
+  g_signal_handlers_disconnect_by_func (object,
+      _submenu_notify_visible_changed_cb, userdata);
+
+  chat_window_update (EMPATHY_CHAT_WINDOW (userdata), TRUE);
 }
 
 static void
-chat_window_menu_context_update (EmpathyChatWindowPriv *priv,
-                             gint num_pages)
-{
-       gboolean first_page;
-       gboolean last_page;
-       gboolean wrap_around;
-       gboolean is_connected;
-       gint     page_num;
-
-       page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook));
-       first_page = (page_num == 0);
-       last_page = (page_num == (num_pages - 1));
-       g_object_get (gtk_settings_get_default (), "gtk-keynav-wrap-around",
-                     &wrap_around, NULL);
-       is_connected = empathy_chat_get_tp_chat (priv->current_chat) != NULL;
-
-       gtk_action_set_sensitive (priv->menu_tabs_next, (!last_page ||
-                                                        wrap_around));
-       gtk_action_set_sensitive (priv->menu_tabs_prev, (!first_page ||
-                                                        wrap_around));
-       gtk_action_set_sensitive (priv->menu_tabs_detach, num_pages > 1);
-       gtk_action_set_sensitive (priv->menu_tabs_left, !first_page);
-       gtk_action_set_sensitive (priv->menu_tabs_right, !last_page);
-       gtk_action_set_sensitive (priv->menu_conv_insert_smiley, is_connected);
+chat_window_menu_context_update (EmpathyChatWindow *self,
+    gint num_pages)
+{
+  gboolean first_page;
+  gboolean last_page;
+  gboolean wrap_around;
+  gboolean is_connected;
+  gint page_num;
+
+  page_num = gtk_notebook_get_current_page (
+      GTK_NOTEBOOK (self->priv->notebook));
+  first_page = (page_num == 0);
+  last_page = (page_num == (num_pages - 1));
+  g_object_get (gtk_settings_get_default (), "gtk-keynav-wrap-around",
+      &wrap_around, NULL);
+  is_connected = empathy_chat_get_tp_chat (self->priv->current_chat) != NULL;
+
+  gtk_action_set_sensitive (self->priv->menu_tabs_next, (!last_page ||
+        wrap_around));
+  gtk_action_set_sensitive (self->priv->menu_tabs_prev, (!first_page ||
+        wrap_around));
+  gtk_action_set_sensitive (self->priv->menu_tabs_detach, num_pages > 1);
+  gtk_action_set_sensitive (self->priv->menu_tabs_left, !first_page);
+  gtk_action_set_sensitive (self->priv->menu_tabs_right, !last_page);
+  gtk_action_set_sensitive (self->priv->menu_conv_insert_smiley, is_connected);
 }
 
 static void
-chat_window_conversation_menu_update (EmpathyChatWindowPriv *priv,
-                                      EmpathyChatWindow     *self)
+chat_window_conversation_menu_update (EmpathyChatWindow *self)
 {
-       EmpathyTpChat *tp_chat;
-       TpConnection *connection;
-       GtkAction *action;
-       gboolean sensitive = FALSE;
+  EmpathyTpChat *tp_chat;
+  TpConnection *connection;
+  GtkAction *action;
+  gboolean sensitive = FALSE;
 
-       g_return_if_fail (priv->current_chat != NULL);
+  g_return_if_fail (self->priv->current_chat != NULL);
 
-       action = gtk_ui_manager_get_action (priv->ui_manager,
-               "/chats_menubar/menu_conv/menu_conv_invite_participant");
-       tp_chat = empathy_chat_get_tp_chat (priv->current_chat);
+  action = gtk_ui_manager_get_action (self->priv->ui_manager,
+    "/chats_menubar/menu_conv/menu_conv_invite_participant");
+  tp_chat = empathy_chat_get_tp_chat (self->priv->current_chat);
 
-       if (tp_chat != NULL) {
-               connection = tp_channel_borrow_connection (TP_CHANNEL (tp_chat));
+  if (tp_chat != NULL)
+    {
+      connection = tp_channel_get_connection (TP_CHANNEL (tp_chat));
 
-               sensitive = empathy_tp_chat_can_add_contact (tp_chat) &&
-                       (tp_connection_get_status (connection, NULL) ==
-                        TP_CONNECTION_STATUS_CONNECTED);
-       }
+      sensitive = empathy_tp_chat_can_add_contact (tp_chat) &&
+        (tp_connection_get_status (connection, NULL) ==
+         TP_CONNECTION_STATUS_CONNECTED);
+    }
 
-       gtk_action_set_sensitive (action, sensitive);
+  gtk_action_set_sensitive (action, sensitive);
 }
 
 static void
-chat_window_contact_menu_update (EmpathyChatWindowPriv *priv,
-                                EmpathyChatWindow     *window)
+chat_window_contact_menu_update (EmpathyChatWindow *self)
 {
-       GtkWidget *menu, *submenu, *orig_submenu;
+  GtkWidget *menu, *submenu, *orig_submenu;
 
-       menu = gtk_ui_manager_get_widget (priv->ui_manager,
-               "/chats_menubar/menu_contact");
-       orig_submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (menu));
+  if (self->priv->current_chat == NULL)
+    return;
 
-       if (orig_submenu == NULL || !gtk_widget_get_visible (orig_submenu)) {
-               submenu = empathy_chat_get_contact_menu (priv->current_chat);
+  if (self->priv->updating_menu)
+    return;
+  self->priv->updating_menu = TRUE;
 
-               if (submenu != NULL) {
-                       /* gtk_menu_attach_to_widget () doesn't behave nicely here */
-                       g_object_set_data (G_OBJECT (submenu), "window", priv->dialog);
+  menu = gtk_ui_manager_get_widget (self->priv->ui_manager,
+    "/chats_menubar/menu_contact");
+  orig_submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (menu));
 
-                       gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu), submenu);
-                       gtk_widget_show (menu);
-                       gtk_widget_set_sensitive (menu, TRUE);
-               } else {
-                       gtk_widget_set_sensitive (menu, FALSE);
-               }
-       } else {
-               tp_g_signal_connect_object (orig_submenu,
-                                            "notify::visible",
-                                            (GCallback)_submenu_notify_visible_changed_cb,
-                                            window, 0);
-       }
-}
+  if (orig_submenu == NULL || !gtk_widget_get_visible (orig_submenu))
+    {
+      submenu = empathy_chat_get_contact_menu (self->priv->current_chat);
 
-static guint
-get_all_unread_messages (EmpathyChatWindowPriv *priv)
-{
-       GList *l;
-       guint nb = 0;
+      if (submenu != NULL)
+        {
+          /* gtk_menu_attach_to_widget () doesn't behave nicely here */
+          g_object_set_data (G_OBJECT (submenu), "window", self);
 
-       for (l = priv->chats; l != NULL; l = g_list_next (l))
-               nb += empathy_chat_get_nb_unread_messages (EMPATHY_CHAT (l->data));
+          gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu), submenu);
+          gtk_widget_show (menu);
+          gtk_widget_set_sensitive (menu, TRUE);
+        }
+      else
+        {
+          gtk_widget_set_sensitive (menu, FALSE);
+        }
+    }
+  else
+    {
+      tp_g_signal_connect_object (orig_submenu,
+          "notify::visible",
+          (GCallback)_submenu_notify_visible_changed_cb, self, 0);
+    }
 
-       return nb;
+  self->priv->updating_menu = FALSE;
 }
 
-static gchar *
-get_window_title_name (EmpathyChatWindowPriv *priv)
+static guint
+get_all_unread_messages (EmpathyChatWindow *self)
 {
-       gchar *active_name, *ret;
-       guint nb_chats;
-       guint current_unread_msgs;
-
-       nb_chats = g_list_length (priv->chats);
-       g_assert (nb_chats > 0);
-
-       active_name = empathy_chat_dup_name (priv->current_chat);
-
-       current_unread_msgs = empathy_chat_get_nb_unread_messages (
-                       priv->current_chat);
+  GList *l;
+  guint nb = 0;
 
-       if (nb_chats == 1) {
-               /* only one tab */
-               if (current_unread_msgs == 0)
-                       ret = g_strdup (active_name);
-               else
-                       ret = g_strdup_printf (ngettext (
-                               "%s (%d unread)",
-                               "%s (%d unread)", current_unread_msgs),
-                               active_name, current_unread_msgs);
-       } else {
-               guint nb_others = nb_chats - 1;
-               guint all_unread_msgs;
-
-               all_unread_msgs = get_all_unread_messages (priv);
-
-               if (all_unread_msgs == 0) {
-                       /* no unread message */
-                       ret = g_strdup_printf (ngettext (
-                               "%s (and %u other)",
-                               "%s (and %u others)", nb_others),
-                               active_name, nb_others);
-               }
-
-               else if (all_unread_msgs == current_unread_msgs) {
-                       /* unread messages are in the current tab */
-                       ret = g_strdup_printf (ngettext (
-                               "%s (%d unread)",
-                               "%s (%d unread)", current_unread_msgs),
-                               active_name, current_unread_msgs);
-               }
+  for (l = self->priv->chats; l != NULL; l = g_list_next (l))
+    nb += empathy_chat_get_nb_unread_messages (EMPATHY_CHAT (l->data));
 
-               else if (current_unread_msgs == 0) {
-                       /* unread messages are in other tabs */
-                       ret = g_strdup_printf (ngettext (
-                               "%s (%d unread from others)",
-                               "%s (%d unread from others)",
-                               all_unread_msgs),
-                               active_name, all_unread_msgs);
-               }
-
-               else {
-                       /* unread messages are in all the tabs */
-                       ret = g_strdup_printf (ngettext (
-                               "%s (%d unread from all)",
-                               "%s (%d unread from all)",
-                               all_unread_msgs),
-                               active_name, all_unread_msgs);
-               }
-       }
-
-       g_free (active_name);
+  return nb;
+}
 
-       return ret;
+static gchar *
+get_window_title_name (EmpathyChatWindow *self)
+{
+  gchar *active_name, *ret;
+  guint nb_chats;
+  guint current_unread_msgs;
+
+  nb_chats = g_list_length (self->priv->chats);
+  g_assert (nb_chats > 0);
+
+  active_name = empathy_chat_dup_name (self->priv->current_chat);
+
+  current_unread_msgs = empathy_chat_get_nb_unread_messages (
+      self->priv->current_chat);
+
+  if (nb_chats == 1)
+    {
+      /* only one tab */
+      if (current_unread_msgs == 0)
+        ret = g_strdup (active_name);
+      else
+        ret = g_strdup_printf (ngettext (
+          "%s (%d unread)",
+          "%s (%d unread)", current_unread_msgs),
+          active_name, current_unread_msgs);
+    }
+  else
+    {
+      guint nb_others = nb_chats - 1;
+      guint all_unread_msgs;
+
+      all_unread_msgs = get_all_unread_messages (self);
+
+      if (all_unread_msgs == 0)
+        {
+          /* no unread message */
+          ret = g_strdup_printf (ngettext (
+            "%s (and %u other)",
+            "%s (and %u others)", nb_others),
+            active_name, nb_others);
+        }
+      else if (all_unread_msgs == current_unread_msgs)
+        {
+          /* unread messages are in the current tab */
+          ret = g_strdup_printf (ngettext (
+            "%s (%d unread)",
+            "%s (%d unread)", current_unread_msgs),
+            active_name, current_unread_msgs);
+        }
+      else if (current_unread_msgs == 0)
+        {
+          /* unread messages are in other tabs */
+          ret = g_strdup_printf (ngettext (
+            "%s (%d unread from others)",
+            "%s (%d unread from others)",
+            all_unread_msgs),
+            active_name, all_unread_msgs);
+        }
+      else
+        {
+          /* unread messages are in all the tabs */
+          ret = g_strdup_printf (ngettext (
+            "%s (%d unread from all)",
+            "%s (%d unread from all)",
+            all_unread_msgs),
+            active_name, all_unread_msgs);
+        }
+    }
+
+  g_free (active_name);
+
+  return ret;
 }
 
 static void
-chat_window_title_update (EmpathyChatWindowPriv *priv)
+chat_window_title_update (EmpathyChatWindow *self)
 {
-       gchar *name;
+  gchar *name;
 
-       name = get_window_title_name (priv);
-       gtk_window_set_title (GTK_WINDOW (priv->dialog), name);
-       g_free (name);
+  name = get_window_title_name (self);
+  //gtk_window_set_title (GTK_WINDOW (self), name);
+  g_free (name);
 }
 
 static void
-chat_window_icon_update (EmpathyChatWindowPriv *priv, gboolean new_messages)
-{
-       GdkPixbuf      *icon;
-       EmpathyContact *remote_contact;
-       gboolean        avatar_in_icon;
-       guint           n_chats;
-
-       n_chats = g_list_length (priv->chats);
-
-       /* Update window icon */
-       if (new_messages) {
-               gtk_window_set_icon_name (GTK_WINDOW (priv->dialog),
-                                         EMPATHY_IMAGE_MESSAGE);
-       } else {
-               avatar_in_icon = g_settings_get_boolean (priv->gsettings_chat,
-                               EMPATHY_PREFS_CHAT_AVATAR_IN_ICON);
-
-               if (n_chats == 1 && avatar_in_icon) {
-                       remote_contact = empathy_chat_get_remote_contact (priv->current_chat);
-                       icon = empathy_pixbuf_avatar_from_contact_scaled (remote_contact, 0, 0);
-                       gtk_window_set_icon (GTK_WINDOW (priv->dialog), icon);
-
-                       if (icon != NULL) {
-                               g_object_unref (icon);
-                       }
-               } else {
-                       gtk_window_set_icon_name (GTK_WINDOW (priv->dialog), NULL);
-               }
-       }
+chat_window_icon_update (EmpathyChatWindow *self,
+    gboolean new_messages)
+{
+  GdkPixbuf *icon;
+  EmpathyContact *remote_contact;
+  gboolean avatar_in_icon;
+  guint n_chats;
+
+  n_chats = g_list_length (self->priv->chats);
+
+  /* Update window icon */
+  if (new_messages)
+    {
+      //gtk_window_set_icon_name (GTK_WINDOW (self),
+      //    EMPATHY_IMAGE_MESSAGE);
+    }
+  else
+    {
+      avatar_in_icon = g_settings_get_boolean (self->priv->gsettings_chat,
+          EMPATHY_PREFS_CHAT_AVATAR_IN_ICON);
+
+      if (n_chats == 1 && avatar_in_icon)
+        {
+          remote_contact = empathy_chat_get_remote_contact (self->priv->current_chat);
+          icon = empathy_pixbuf_avatar_from_contact_scaled (remote_contact,
+              0, 0);
+          //gtk_window_set_icon (GTK_WINDOW (self), icon);
+
+          if (icon != NULL)
+            g_object_unref (icon);
+        }
+      else
+        {
+          //gtk_window_set_icon_name (GTK_WINDOW (self), NULL);
+        }
+    }
 }
 
 static void
-chat_window_close_button_update (EmpathyChatWindowPriv *priv,
-                                gint num_pages)
-{
-       GtkWidget *chat;
-       GtkWidget *chat_close_button;
-       gint       i;
-
-       if (num_pages == 1) {
-               chat = gtk_notebook_get_nth_page (GTK_NOTEBOOK (priv->notebook), 0);
-               chat_close_button = g_object_get_data (G_OBJECT (chat),
-                               "chat-window-tab-close-button");
-               gtk_widget_hide (chat_close_button);
-       } else {
-               for (i=0; i<num_pages; i++) {
-                       chat = gtk_notebook_get_nth_page (GTK_NOTEBOOK (priv->notebook), i);
-                       chat_close_button = g_object_get_data (G_OBJECT (chat),
-                                       "chat-window-tab-close-button");
-                       gtk_widget_show (chat_close_button);
-               }
-       }
+chat_window_close_button_update (EmpathyChatWindow *self,
+    gint num_pages)
+{
+  GtkWidget *chat;
+  GtkWidget *chat_close_button;
+  gint i;
+
+  if (num_pages == 1)
+    {
+      chat = gtk_notebook_get_nth_page (GTK_NOTEBOOK (self->priv->notebook), 0);
+      chat_close_button = g_object_get_data (G_OBJECT (chat),
+          "chat-window-tab-close-button");
+      gtk_widget_hide (chat_close_button);
+    }
+  else
+    {
+      for (i=0; i<num_pages; i++)
+        {
+          chat = gtk_notebook_get_nth_page (GTK_NOTEBOOK (self->priv->notebook), i);
+          chat_close_button = g_object_get_data (G_OBJECT (chat),
+              "chat-window-tab-close-button");
+          gtk_widget_show (chat_close_button);
+        }
+    }
 }
 
 static void
-chat_window_update (EmpathyChatWindow *window,
-                   gboolean update_contact_menu)
+chat_window_update (EmpathyChatWindow *self,
+    gboolean update_contact_menu)
 {
-       EmpathyChatWindowPriv *priv = GET_PRIV (window);
-       gint                   num_pages;
+  gint num_pages;
 
-       num_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->notebook));
+  num_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (self->priv->notebook));
 
-       /* Update Tab menu */
-       chat_window_menu_context_update (priv,
-                                        num_pages);
+  /* Update Tab menu */
+  chat_window_menu_context_update (self, num_pages);
 
-       chat_window_conversation_menu_update (priv, window);
+  chat_window_conversation_menu_update (self);
 
-       /* If this update is due to a focus-in event, we know the menu will be
-          the same as when we last left it, so no work to do.  Besides, if we
-          swap out the menu on a focus-in, we may confuse any external global
-          menu watching. */
-       if (update_contact_menu) {
-               chat_window_contact_menu_update (priv,
-                                                window);
-       }
+  /* If this update is due to a focus-in event, we know the menu will be
+     the same as when we last left it, so no work to do. Besides, if we
+     swap out the menu on a focus-in, we may confuse any external global
+     menu watching. */
+  if (update_contact_menu)
+    {
+      chat_window_contact_menu_update (self);
+    }
 
-       chat_window_title_update (priv);
+  chat_window_title_update (self);
 
-       chat_window_icon_update (priv, get_all_unread_messages (priv) > 0);
+  chat_window_icon_update (self, get_all_unread_messages (self) > 0);
 
-       chat_window_close_button_update (priv,
-                                        num_pages);
+  chat_window_close_button_update (self, num_pages);
 }
 
 static void
-append_markup_printf (GString    *string,
-                     const char *format,
-                     ...)
+append_markup_printf (GString *string,
+    const char *format,
+    ...)
 {
-       gchar *tmp;
-       va_list args;
+  gchar *tmp;
+  va_list args;
 
-       va_start (args, format);
+  va_start (args, format);
 
-       tmp = g_markup_vprintf_escaped (format, args);
-       g_string_append (string, tmp);
-       g_free (tmp);
+  tmp = g_markup_vprintf_escaped (format, args);
+  g_string_append (string, tmp);
+  g_free (tmp);
 
-       va_end (args);
+  va_end (args);
 }
 
 static void
 chat_window_update_chat_tab_full (EmpathyChat *chat,
-                                 gboolean update_contact_menu)
-{
-       EmpathyChatWindow     *window;
-       EmpathyChatWindowPriv *priv;
-       EmpathyContact        *remote_contact;
-       gchar                 *name;
-       const gchar           *id;
-       TpAccount             *account;
-       const gchar           *subject;
-       const gchar           *status = NULL;
-       GtkWidget             *widget;
-       GString               *tooltip;
-       gchar                 *markup;
-       const gchar           *icon_name;
-       GtkWidget             *tab_image;
-       GtkWidget             *menu_image;
-       GtkWidget             *sending_spinner;
-       guint                  nb_sending;
-
-       window = chat_window_find_chat (chat);
-       if (!window) {
-               return;
-       }
-       priv = GET_PRIV (window);
-
-       /* Get information */
-       name = empathy_chat_dup_name (chat);
-       account = empathy_chat_get_account (chat);
-       subject = empathy_chat_get_subject (chat);
-       remote_contact = empathy_chat_get_remote_contact (chat);
-
-       DEBUG ("Updating chat tab, name=%s, account=%s, subject=%s, remote_contact=%p",
-               name, tp_proxy_get_object_path (account), subject, remote_contact);
-
-       /* Update tab image */
-       if (empathy_chat_get_tp_chat (chat) == NULL) {
-               /* No TpChat, we are disconnected */
-               icon_name = NULL;
-       }
-       else if (empathy_chat_get_nb_unread_messages (chat) > 0) {
-               icon_name = EMPATHY_IMAGE_MESSAGE;
-       }
-       else if (remote_contact && empathy_chat_is_composing (chat)) {
-               icon_name = EMPATHY_IMAGE_TYPING;
-       }
-       else if (empathy_chat_is_sms_channel (chat)) {
-               icon_name = EMPATHY_IMAGE_SMS;
-       }
-       else if (remote_contact) {
-               icon_name = empathy_icon_name_for_contact (remote_contact);
-       } else {
-               icon_name = EMPATHY_IMAGE_GROUP_MESSAGE;
-       }
-
-       tab_image = g_object_get_data (G_OBJECT (chat), "chat-window-tab-image");
-       menu_image = g_object_get_data (G_OBJECT (chat), "chat-window-menu-image");
-       if (icon_name != NULL) {
-               gtk_image_set_from_icon_name (GTK_IMAGE (tab_image), icon_name, GTK_ICON_SIZE_MENU);
-               gtk_widget_show (tab_image);
-               gtk_image_set_from_icon_name (GTK_IMAGE (menu_image), icon_name, GTK_ICON_SIZE_MENU);
-               gtk_widget_show (menu_image);
-       } else {
-               gtk_widget_hide (tab_image);
-               gtk_widget_hide (menu_image);
-       }
-
-       /* Update the sending spinner */
-       nb_sending = empathy_chat_get_n_messages_sending (chat);
-       sending_spinner = g_object_get_data (G_OBJECT (chat),
-               "chat-window-tab-sending-spinner");
-
-       g_object_set (sending_spinner,
-               "active", nb_sending > 0,
-               "visible", nb_sending > 0,
-               NULL);
-
-       /* Update tab tooltip */
-       tooltip = g_string_new (NULL);
-
-       if (remote_contact) {
-               id = empathy_contact_get_id (remote_contact);
-               status = empathy_contact_get_presence_message (remote_contact);
-       } else {
-               id = name;
-       }
-
-       if (empathy_chat_is_sms_channel (chat)) {
-               append_markup_printf (tooltip, "%s ", _("SMS:"));
-       }
-
-       append_markup_printf (tooltip,
-                             "<b>%s</b><small> (%s)</small>",
-                             id,
-                             tp_account_get_display_name (account));
-
-       if (nb_sending > 0) {
-               char *tmp = g_strdup_printf (
-                       ngettext ("Sending %d message",
-                                 "Sending %d messages",
-                                 nb_sending),
-                       nb_sending);
-
-               g_string_append (tooltip, "\n");
-               g_string_append (tooltip, tmp);
-
-               gtk_widget_set_tooltip_text (sending_spinner, tmp);
-               g_free (tmp);
-       }
-
-       if (!EMP_STR_EMPTY (status)) {
-               append_markup_printf (tooltip, "\n<i>%s</i>", status);
-       }
-
-       if (subject) {
-               append_markup_printf (tooltip, "\n<b>%s</b> %s",
-                                     _("Topic:"), subject);
-       }
-
-       if (remote_contact && empathy_chat_is_composing (chat)) {
-               append_markup_printf (tooltip, "\n%s", _("Typing a message."));
-       }
-
-       if (remote_contact != NULL) {
-               const gchar * const *types;
-
-               types = empathy_contact_get_client_types (remote_contact);
-               if (types != NULL && !tp_strdiff (types[0], "phone")) {
-                       /* I'm on a phone ! */
-                       gchar *tmp = name;
-
-                       name = g_strdup_printf ("☎ %s", name);
-                       g_free (tmp);
-               }
-       }
-
-       markup = g_string_free (tooltip, FALSE);
-       widget = g_object_get_data (G_OBJECT (chat), "chat-window-tab-tooltip-widget");
-       gtk_widget_set_tooltip_markup (widget, markup);
-       widget = g_object_get_data (G_OBJECT (chat), "chat-window-menu-tooltip-widget");
-       gtk_widget_set_tooltip_markup (widget, markup);
-       g_free (markup);
-
-       /* Update tab and menu label */
-       if (empathy_chat_is_highlighted (chat)) {
-               markup = g_markup_printf_escaped (
-                       "<span color=\"red\" weight=\"bold\">%s</span>",
-                       name);
-       } else {
-               markup = g_markup_escape_text (name, -1);
-       }
-
-       widget = g_object_get_data (G_OBJECT (chat), "chat-window-tab-label");
-       gtk_label_set_markup (GTK_LABEL (widget), markup);
-       widget = g_object_get_data (G_OBJECT (chat), "chat-window-menu-label");
-       gtk_label_set_markup (GTK_LABEL (widget), markup);
-       g_free (markup);
-
-       /* Update the window if it's the current chat */
-       if (priv->current_chat == chat) {
-               chat_window_update (window, update_contact_menu);
-       }
-
-       g_free (name);
+    gboolean update_contact_menu)
+{
+  EmpathyChatWindow *self;
+  EmpathyContact *remote_contact;
+  gchar *name;
+  const gchar *id;
+  TpAccount *account;
+  const gchar *subject;
+  const gchar *status = NULL;
+  GtkWidget *widget;
+  GString *tooltip;
+  gchar *markup;
+  const gchar *icon_name;
+  GtkWidget *tab_image;
+  GtkWidget *menu_image;
+  GtkWidget *sending_spinner;
+  guint nb_sending;
+
+  self = chat_window_find_chat (chat);
+  if (!self)
+    return;
+
+  /* Get information */
+  name = empathy_chat_dup_name (chat);
+  account = empathy_chat_get_account (chat);
+  subject = empathy_chat_get_subject (chat);
+  remote_contact = empathy_chat_get_remote_contact (chat);
+
+  DEBUG ("Updating chat tab, name=%s, account=%s, subject=%s, "
+      "remote_contact=%p",
+    name, tp_proxy_get_object_path (account), subject, remote_contact);
+
+  /* Update tab image */
+  if (empathy_chat_get_tp_chat (chat) == NULL)
+    {
+      /* No TpChat, we are disconnected */
+      icon_name = NULL;
+    }
+  else if (empathy_chat_get_nb_unread_messages (chat) > 0)
+    {
+      icon_name = EMPATHY_IMAGE_MESSAGE;
+    }
+  else if (remote_contact && empathy_chat_is_composing (chat))
+    {
+      icon_name = EMPATHY_IMAGE_TYPING;
+    }
+  else if (empathy_chat_is_sms_channel (chat))
+    {
+      icon_name = EMPATHY_IMAGE_SMS;
+    }
+  else if (remote_contact)
+    {
+      icon_name = empathy_icon_name_for_contact (remote_contact);
+    }
+  else
+    {
+      icon_name = EMPATHY_IMAGE_GROUP_MESSAGE;
+    }
+
+  tab_image = g_object_get_data (G_OBJECT (chat), "chat-window-tab-image");
+  menu_image = g_object_get_data (G_OBJECT (chat), "chat-window-menu-image");
+
+  if (icon_name != NULL)
+    {
+      gtk_image_set_from_icon_name (GTK_IMAGE (tab_image), icon_name,
+          GTK_ICON_SIZE_MENU);
+      gtk_widget_show (tab_image);
+      gtk_image_set_from_icon_name (GTK_IMAGE (menu_image), icon_name,
+          GTK_ICON_SIZE_MENU);
+      gtk_widget_show (menu_image);
+    }
+  else
+    {
+      gtk_widget_hide (tab_image);
+      gtk_widget_hide (menu_image);
+    }
+
+  /* Update the sending spinner */
+  nb_sending = empathy_chat_get_n_messages_sending (chat);
+  sending_spinner = g_object_get_data (G_OBJECT (chat),
+    "chat-window-tab-sending-spinner");
+
+  g_object_set (sending_spinner,
+    "active", nb_sending > 0,
+    "visible", nb_sending > 0,
+    NULL);
+
+  /* Update tab tooltip */
+  tooltip = g_string_new (NULL);
+
+  if (remote_contact)
+    {
+      id = empathy_contact_get_id (remote_contact);
+      status = empathy_contact_get_presence_message (remote_contact);
+    }
+  else
+    {
+      id = name;
+    }
+
+  if (empathy_chat_is_sms_channel (chat))
+    append_markup_printf (tooltip, "%s ", _("SMS:"));
+
+  append_markup_printf (tooltip, "<b>%s</b><small> (%s)</small>",
+      id, tp_account_get_display_name (account));
+
+  if (nb_sending > 0)
+    {
+      char *tmp = g_strdup_printf (
+        ngettext ("Sending %d message",
+            "Sending %d messages",
+            nb_sending),
+        nb_sending);
+
+      g_string_append (tooltip, "\n");
+      g_string_append (tooltip, tmp);
+
+      gtk_widget_set_tooltip_text (sending_spinner, tmp);
+      g_free (tmp);
+    }
+
+  if (!TPAW_STR_EMPTY (status))
+    append_markup_printf (tooltip, "\n<i>%s</i>", status);
+
+  if (!TPAW_STR_EMPTY (subject))
+    append_markup_printf (tooltip, "\n<b>%s</b> %s",
+        _("Topic:"), subject);
+
+  if (remote_contact && empathy_chat_is_composing (chat))
+    append_markup_printf (tooltip, "\n%s", _("Typing a message."));
+
+  if (remote_contact != NULL)
+    {
+      const gchar * const *types;
+
+      types = empathy_contact_get_client_types (remote_contact);
+      if (empathy_client_types_contains_mobile_device ((GStrv) types))
+        {
+          /* I'm on a mobile device ! */
+          gchar *tmp = name;
+
+          name = g_strdup_printf ("☎ %s", name);
+          g_free (tmp);
+        }
+    }
+
+  markup = g_string_free (tooltip, FALSE);
+  widget = g_object_get_data (G_OBJECT (chat),
+      "chat-window-tab-tooltip-widget");
+  gtk_widget_set_tooltip_markup (widget, markup);
+
+  widget = g_object_get_data (G_OBJECT (chat),
+      "chat-window-menu-tooltip-widget");
+  gtk_widget_set_tooltip_markup (widget, markup);
+  g_free (markup);
+
+  /* Update tab and menu label */
+  if (empathy_chat_is_highlighted (chat))
+    {
+      markup = g_markup_printf_escaped (
+        "<span color=\"red\" weight=\"bold\">%s</span>",
+        name);
+    }
+  else
+    {
+      markup = g_markup_escape_text (name, -1);
+    }
+
+  widget = g_object_get_data (G_OBJECT (chat), "chat-window-tab-label");
+  gtk_label_set_markup (GTK_LABEL (widget), markup);
+  widget = g_object_get_data (G_OBJECT (chat), "chat-window-menu-label");
+  gtk_label_set_markup (GTK_LABEL (widget), markup);
+  g_free (markup);
+
+  /* Update the window if it's the current chat */
+  if (self->priv->current_chat == chat)
+    chat_window_update (self, update_contact_menu);
+
+  g_free (name);
 }
 
 static void
 chat_window_update_chat_tab (EmpathyChat *chat)
 {
-       chat_window_update_chat_tab_full (chat, TRUE);
+  chat_window_update_chat_tab_full (chat, TRUE);
 }
 
 static void
 chat_window_chat_notify_cb (EmpathyChat *chat)
 {
-       EmpathyChatWindow *window;
-       EmpathyContact *old_remote_contact;
-       EmpathyContact *remote_contact = NULL;
+  EmpathyChatWindow *window;
+  EmpathyContact *old_remote_contact;
+  EmpathyContact *remote_contact = NULL;
+
+  old_remote_contact = g_object_get_data (G_OBJECT (chat),
+      "chat-window-remote-contact");
+  remote_contact = empathy_chat_get_remote_contact (chat);
 
-       old_remote_contact = g_object_get_data (G_OBJECT (chat), "chat-window-remote-contact");
-       remote_contact = empathy_chat_get_remote_contact (chat);
+  if (old_remote_contact != remote_contact)
+    {
+      /* The remote-contact associated with the chat changed, we need
+       * to keep track of any change of that contact and update the
+       * window each time. */
+      if (remote_contact)
+        g_signal_connect_swapped (remote_contact, "notify",
+            G_CALLBACK (chat_window_update_chat_tab), chat);
 
-       if (old_remote_contact != remote_contact) {
-               /* The remote-contact associated with the chat changed, we need
-                * to keep track of any change of that contact and update the
-                * window each time. */
-               if (remote_contact) {
-                       g_signal_connect_swapped (remote_contact, "notify",
-                                                 G_CALLBACK (chat_window_update_chat_tab),
-                                                 chat);
-               }
-               if (old_remote_contact) {
-                       g_signal_handlers_disconnect_by_func (old_remote_contact,
-                                                             chat_window_update_chat_tab,
-                                                             chat);
-               }
+      if (old_remote_contact)
+        g_signal_handlers_disconnect_by_func (old_remote_contact,
+            chat_window_update_chat_tab, chat);
 
-               g_object_set_data_full (G_OBJECT (chat), "chat-window-remote-contact",
-                                  g_object_ref (remote_contact), (GDestroyNotify) g_object_unref);
-       }
+      g_object_set_data_full (G_OBJECT (chat), "chat-window-remote-contact",
+          g_object_ref (remote_contact), (GDestroyNotify) g_object_unref);
+    }
 
-       chat_window_update_chat_tab (chat);
+  chat_window_update_chat_tab (chat);
 
-       window = chat_window_find_chat (chat);
-       if (window != NULL) {
-               chat_window_update (window, FALSE);
-       }
+  window = chat_window_find_chat (chat);
+  if (window != NULL)
+    chat_window_update (window, FALSE);
 }
 
 static void
 chat_window_insert_smiley_activate_cb (EmpathySmileyManager *manager,
-                                      EmpathySmiley        *smiley,
-                                      gpointer              window)
+    EmpathySmiley *smiley,
+    gpointer user_data)
 {
-       EmpathyChatWindowPriv *priv = GET_PRIV (window);
-       EmpathyChat           *chat;
-       GtkTextBuffer         *buffer;
-       GtkTextIter            iter;
+  EmpathyChatWindow *self = user_data;
+  EmpathyChat *chat;
+  GtkTextBuffer *buffer;
 
-       chat = priv->current_chat;
+  chat = self->priv->current_chat;
+  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (chat->input_text_view));
 
-       buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (chat->input_text_view));
-       gtk_text_buffer_get_end_iter (buffer, &iter);
-       gtk_text_buffer_insert (buffer, &iter, smiley->str, -1);
+  empathy_chat_insert_smiley (buffer, smiley);
 }
 
 static void
-chat_window_conv_activate_cb (GtkAction         *action,
-                             EmpathyChatWindow *window)
-{
-       EmpathyChatWindowPriv *priv = GET_PRIV (window);
-       gboolean               is_room;
-       gboolean               active;
-       EmpathyContact        *remote_contact = NULL;
-
-       /* Favorite room menu */
-       is_room = empathy_chat_is_room (priv->current_chat);
-       if (is_room) {
-               const gchar *room;
-               TpAccount   *account;
-               gboolean     found = FALSE;
-               EmpathyChatroom *chatroom;
-
-               room = empathy_chat_get_id (priv->current_chat);
-               account = empathy_chat_get_account (priv->current_chat);
-               chatroom = empathy_chatroom_manager_find (priv->chatroom_manager,
-                                                      account, room);
-               if (chatroom != NULL)
-                       found = empathy_chatroom_is_favorite (chatroom);
-
-               DEBUG ("This room %s favorite", found ? "is" : "is not");
-               gtk_toggle_action_set_active (
-                       GTK_TOGGLE_ACTION (priv->menu_conv_favorite), found);
-
-               if (chatroom != NULL)
-                       found = empathy_chatroom_is_always_urgent (chatroom);
-
-               gtk_toggle_action_set_active (
-                       GTK_TOGGLE_ACTION (priv->menu_conv_always_urgent),
-                       found);
-       }
-       gtk_action_set_visible (priv->menu_conv_favorite, is_room);
-       gtk_action_set_visible (priv->menu_conv_always_urgent, is_room);
-
-       /* Show contacts menu */
-       g_object_get (priv->current_chat,
-                     "remote-contact", &remote_contact,
-                     "show-contacts", &active,
-                     NULL);
-       if (remote_contact == NULL) {
-               gtk_toggle_action_set_active (
-                       GTK_TOGGLE_ACTION (priv->menu_conv_toggle_contacts),
-                                          active);
-       }
-       gtk_action_set_visible (priv->menu_conv_toggle_contacts,
-                               (remote_contact == NULL));
-       if (remote_contact != NULL) {
-               g_object_unref (remote_contact);
-       }
+chat_window_conv_activate_cb (GtkAction *action,
+    EmpathyChatWindow *self)
+{
+  gboolean is_room;
+  gboolean active;
+  EmpathyContact *remote_contact = NULL;
+  gboolean disconnected;
+
+  /* Favorite room menu */
+  is_room = empathy_chat_is_room (self->priv->current_chat);
+  if (is_room)
+    {
+      const gchar *room;
+      TpAccount *account;
+      gboolean found = FALSE;
+      EmpathyChatroom *chatroom;
+
+      room = empathy_chat_get_id (self->priv->current_chat);
+      account = empathy_chat_get_account (self->priv->current_chat);
+      chatroom = empathy_chatroom_manager_find (self->priv->chatroom_manager,
+          account, room);
+
+      if (chatroom != NULL)
+        found = empathy_chatroom_is_favorite (chatroom);
+
+      DEBUG ("This room %s favorite", found ? "is" : "is not");
+      gtk_toggle_action_set_active (
+        GTK_TOGGLE_ACTION (self->priv->menu_conv_favorite), found);
+
+      if (chatroom != NULL)
+        found = empathy_chatroom_is_always_urgent (chatroom);
+
+      gtk_toggle_action_set_active (
+          GTK_TOGGLE_ACTION (self->priv->menu_conv_always_urgent), found);
+    }
+
+  gtk_action_set_visible (self->priv->menu_conv_favorite, is_room);
+  gtk_action_set_visible (self->priv->menu_conv_always_urgent, is_room);
+
+  /* Show contacts menu */
+  g_object_get (self->priv->current_chat,
+      "remote-contact", &remote_contact,
+      "show-contacts", &active,
+      NULL);
+
+  if (remote_contact == NULL)
+    {
+      gtk_toggle_action_set_active (
+        GTK_TOGGLE_ACTION (self->priv->menu_conv_toggle_contacts), active);
+    }
+
+  /* Menu-items to be visible for MUCs only */
+  gtk_action_set_visible (self->priv->menu_conv_toggle_contacts,
+      (remote_contact == NULL));
+
+  disconnected = (empathy_chat_get_tp_chat (self->priv->current_chat) == NULL);
+  if (disconnected)
+    {
+      gtk_action_set_visible (self->priv->menu_conv_join_chat, TRUE);
+      gtk_action_set_visible (self->priv->menu_conv_leave_chat, FALSE);
+    }
+  else
+    {
+      TpChannel *channel = NULL;
+      TpContact *self_contact = NULL;
+      TpHandle  self_handle = 0;
+
+      channel = (TpChannel *) (empathy_chat_get_tp_chat (
+          self->priv->current_chat));
+      self_contact = tp_channel_group_get_self_contact (channel);
+      if (self_contact == NULL)
+      {
+        /* The channel may not be a group */
+        gtk_action_set_visible (self->priv->menu_conv_leave_chat, FALSE);
+      }
+      else
+      {
+        self_handle = tp_contact_get_handle (self_contact);
+        /* There is sometimes a lag between the members-changed signal
+           emitted on tp-chat and invalidated signal being emitted on the channel.
+           Leave Chat menu-item should be sensitive only till our self-handle is
+           a part of channel-members */
+        gtk_action_set_visible (self->priv->menu_conv_leave_chat,
+            self_handle != 0);
+      }
+
+      /* Join Chat is insensitive for a connected chat */
+      gtk_action_set_visible (self->priv->menu_conv_join_chat, FALSE);
+    }
+
+  if (remote_contact != NULL)
+    g_object_unref (remote_contact);
 }
 
 static void
-chat_window_clear_activate_cb (GtkAction         *action,
-                              EmpathyChatWindow *window)
+chat_window_clear_activate_cb (GtkAction *action,
+    EmpathyChatWindow *self)
 {
-       EmpathyChatWindowPriv *priv = GET_PRIV (window);
-
-       empathy_chat_clear (priv->current_chat);
+  empathy_chat_clear (self->priv->current_chat);
 }
 
 static void
-chat_window_favorite_toggled_cb (GtkToggleAction   *toggle_action,
-                                EmpathyChatWindow *window)
+chat_window_favorite_toggled_cb (GtkToggleAction *toggle_action,
+    EmpathyChatWindow *self)
 {
-       EmpathyChatWindowPriv *priv = GET_PRIV (window);
-       gboolean               active;
-       TpAccount             *account;
-       gchar                 *name;
-       const gchar           *room;
-       EmpathyChatroom       *chatroom;
+  gboolean active;
+  TpAccount *account;
+  gchar *name;
+  const gchar *room;
+  EmpathyChatroom *chatroom;
 
-       active = gtk_toggle_action_get_active (toggle_action);
-       account = empathy_chat_get_account (priv->current_chat);
-       room = empathy_chat_get_id (priv->current_chat);
-       name = empathy_chat_dup_name (priv->current_chat);
+  active = gtk_toggle_action_get_active (toggle_action);
+  account = empathy_chat_get_account (self->priv->current_chat);
+  room = empathy_chat_get_id (self->priv->current_chat);
+  name = empathy_chat_dup_name (self->priv->current_chat);
 
-       chatroom = empathy_chatroom_manager_ensure_chatroom (
-                    priv->chatroom_manager,
-                    account,
-                    room,
-                    name);
+  chatroom = empathy_chatroom_manager_ensure_chatroom (self->priv->chatroom_manager,
+      account, room, name);
 
-       empathy_chatroom_set_favorite (chatroom, active);
-       g_object_unref (chatroom);
-       g_free (name);
+  empathy_chatroom_set_favorite (chatroom, active);
+  g_object_unref (chatroom);
+  g_free (name);
 }
 
 static void
-chat_window_always_urgent_toggled_cb (GtkToggleAction   *toggle_action,
-                                EmpathyChatWindow *window)
+chat_window_always_urgent_toggled_cb (GtkToggleAction *toggle_action,
+    EmpathyChatWindow *self)
 {
-       EmpathyChatWindowPriv *priv = GET_PRIV (window);
-       gboolean               active;
-       TpAccount             *account;
-       gchar                 *name;
-       const gchar           *room;
-       EmpathyChatroom       *chatroom;
+  gboolean active;
+  TpAccount *account;
+  gchar *name;
+  const gchar *room;
+  EmpathyChatroom *chatroom;
 
-       active = gtk_toggle_action_get_active (toggle_action);
-       account = empathy_chat_get_account (priv->current_chat);
-       room = empathy_chat_get_id (priv->current_chat);
-       name = empathy_chat_dup_name (priv->current_chat);
+  active = gtk_toggle_action_get_active (toggle_action);
+  account = empathy_chat_get_account (self->priv->current_chat);
+  room = empathy_chat_get_id (self->priv->current_chat);
+  name = empathy_chat_dup_name (self->priv->current_chat);
 
-       chatroom = empathy_chatroom_manager_ensure_chatroom (
-                    priv->chatroom_manager,
-                    account,
-                    room,
-                    name);
+  chatroom = empathy_chatroom_manager_ensure_chatroom (self->priv->chatroom_manager,
+      account, room, name);
 
-       empathy_chatroom_set_always_urgent (chatroom, active);
-       g_object_unref (chatroom);
-       g_free (name);
+  empathy_chatroom_set_always_urgent (chatroom, active);
+  g_object_unref (chatroom);
+  g_free (name);
 }
 
 static void
-chat_window_contacts_toggled_cb (GtkToggleAction   *toggle_action,
-                                EmpathyChatWindow *window)
+chat_window_contacts_toggled_cb (GtkToggleAction *toggle_action,
+    EmpathyChatWindow *self)
 {
-       EmpathyChatWindowPriv *priv = GET_PRIV (window);
-       gboolean               active;
+  gboolean active;
 
-       active = gtk_toggle_action_get_active (toggle_action);
+  active = gtk_toggle_action_get_active (toggle_action);
 
-       empathy_chat_set_show_contacts (priv->current_chat, active);
+  empathy_chat_set_show_contacts (self->priv->current_chat, active);
 }
 
 static void
-chat_window_invite_participant_activate_cb (GtkAction         *action,
-                                           EmpathyChatWindow *window)
+chat_window_invite_participant_activate_cb (GtkAction *action,
+    EmpathyChatWindow *self)
 {
-       EmpathyChatWindowPriv *priv;
-       GtkWidget             *dialog;
-       EmpathyTpChat         *tp_chat;
-       int                    response;
+  GtkWidget *dialog;
+  EmpathyTpChat *tp_chat;
+  int response;
 
-       priv = GET_PRIV (window);
+  g_return_if_fail (self->priv->current_chat != NULL);
 
-       g_return_if_fail (priv->current_chat != NULL);
+  tp_chat = empathy_chat_get_tp_chat (self->priv->current_chat);
 
-       tp_chat = empathy_chat_get_tp_chat (priv->current_chat);
+  dialog = empathy_invite_participant_dialog_new (
+      GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (self))), tp_chat);
 
-       dialog = empathy_invite_participant_dialog_new (
-                       GTK_WINDOW (priv->dialog), tp_chat);
-       gtk_widget_show (dialog);
+  gtk_widget_show (dialog);
 
-       response = gtk_dialog_run (GTK_DIALOG (dialog));
+  response = gtk_dialog_run (GTK_DIALOG (dialog));
 
-       if (response == GTK_RESPONSE_ACCEPT) {
-               TpContact *tp_contact;
-               EmpathyContact *contact;
+  if (response == GTK_RESPONSE_ACCEPT)
+    {
+      TpContact *tp_contact;
+      EmpathyContact *contact;
 
-               tp_contact = empathy_invite_participant_dialog_get_selected (
-                       EMPATHY_INVITE_PARTICIPANT_DIALOG (dialog));
-               if (tp_contact == NULL) goto out;
+      tp_contact = empathy_invite_participant_dialog_get_selected (
+        EMPATHY_INVITE_PARTICIPANT_DIALOG (dialog));
+      if (tp_contact == NULL)
+        goto out;
 
-               contact = empathy_contact_dup_from_tp_contact (tp_contact);
+      contact = empathy_contact_dup_from_tp_contact (tp_contact);
 
-               empathy_tp_chat_add (tp_chat, contact, _("Inviting you to this room"));
+      empathy_tp_chat_add (tp_chat, contact, _("Inviting you to this room"));
 
-               g_object_unref (contact);
-       }
+      g_object_unref (contact);
+    }
 
 out:
-       gtk_widget_destroy (dialog);
+  gtk_widget_destroy (dialog);
 }
 
 static void
-chat_window_close_activate_cb (GtkAction         *action,
-                              EmpathyChatWindow *window)
+chat_window_join_chat_activate_cb (GtkAction *action,
+    EmpathyChatWindow *self)
 {
-       EmpathyChatWindowPriv *priv;
-
-       priv = GET_PRIV (window);
+    g_return_if_fail (self->priv->current_chat != NULL);
 
-       g_return_if_fail (priv->current_chat != NULL);
-
-       maybe_close_chat (window, priv->current_chat);
+    empathy_chat_join_muc (self->priv->current_chat,
+        empathy_chat_get_id (self->priv->current_chat));
 }
 
 static void
-chat_window_edit_activate_cb (GtkAction         *action,
-                             EmpathyChatWindow *window)
+chat_window_leave_chat_activate_cb (GtkAction *action,
+    EmpathyChatWindow *self)
 {
-       EmpathyChatWindowPriv *priv;
-       GtkClipboard         *clipboard;
-       GtkTextBuffer        *buffer;
-       gboolean              text_available;
-
-       priv = GET_PRIV (window);
+    EmpathyTpChat * tp_chat;
 
-       g_return_if_fail (priv->current_chat != NULL);
+    g_return_if_fail (self->priv->current_chat != NULL);
 
-       if (!empathy_chat_get_tp_chat (priv->current_chat)) {
-               gtk_action_set_sensitive (priv->menu_edit_copy, FALSE);
-               gtk_action_set_sensitive (priv->menu_edit_cut, FALSE);
-               gtk_action_set_sensitive (priv->menu_edit_paste, FALSE);
-               return;
-       }
-
-       buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->current_chat->input_text_view));
-       if (gtk_text_buffer_get_has_selection (buffer)) {
-               gtk_action_set_sensitive (priv->menu_edit_copy, TRUE);
-               gtk_action_set_sensitive (priv->menu_edit_cut, TRUE);
-       } else {
-               gboolean selection;
-
-               selection = empathy_chat_view_get_has_selection (priv->current_chat->view);
+    tp_chat = empathy_chat_get_tp_chat (self->priv->current_chat);
+    if (tp_chat != NULL)
+        empathy_tp_chat_leave (tp_chat, "");
+}
 
-               gtk_action_set_sensitive (priv->menu_edit_cut, FALSE);
-               gtk_action_set_sensitive (priv->menu_edit_copy, selection);
-       }
+static void
+chat_window_close_activate_cb (GtkAction *action,
+    EmpathyChatWindow *self)
+{
+  g_return_if_fail (self->priv->current_chat != NULL);
 
-       clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
-       text_available = gtk_clipboard_wait_is_text_available (clipboard);
-       gtk_action_set_sensitive (priv->menu_edit_paste, text_available);
+  maybe_close_chat (self, self->priv->current_chat);
 }
 
 static void
-chat_window_cut_activate_cb (GtkAction         *action,
-                            EmpathyChatWindow *window)
+chat_window_edit_activate_cb (GtkAction *action,
+    EmpathyChatWindow *self)
 {
-       EmpathyChatWindowPriv *priv;
+  GtkClipboard *clipboard;
+  GtkTextBuffer *buffer;
+  gboolean text_available;
 
-       g_return_if_fail (EMPATHY_IS_CHAT_WINDOW (window));
+  g_return_if_fail (self->priv->current_chat != NULL);
 
-       priv = GET_PRIV (window);
+  if (!empathy_chat_get_tp_chat (self->priv->current_chat))
+    {
+      gtk_action_set_sensitive (self->priv->menu_edit_copy, FALSE);
+      gtk_action_set_sensitive (self->priv->menu_edit_cut, FALSE);
+      gtk_action_set_sensitive (self->priv->menu_edit_paste, FALSE);
+      return;
+    }
 
-       empathy_chat_cut (priv->current_chat);
-}
+  buffer = gtk_text_view_get_buffer (
+      GTK_TEXT_VIEW (self->priv->current_chat->input_text_view));
 
-static void
-chat_window_copy_activate_cb (GtkAction         *action,
-                             EmpathyChatWindow *window)
-{
-       EmpathyChatWindowPriv *priv;
+  if (gtk_text_buffer_get_has_selection (buffer))
+    {
+      gtk_action_set_sensitive (self->priv->menu_edit_copy, TRUE);
+      gtk_action_set_sensitive (self->priv->menu_edit_cut, TRUE);
+    }
+  else
+    {
+      gboolean selection;
 
-       g_return_if_fail (EMPATHY_IS_CHAT_WINDOW (window));
+      selection = empathy_theme_adium_get_has_selection (
+          self->priv->current_chat->view);
 
-       priv = GET_PRIV (window);
+      gtk_action_set_sensitive (self->priv->menu_edit_cut, FALSE);
+      gtk_action_set_sensitive (self->priv->menu_edit_copy, selection);
+    }
 
-       empathy_chat_copy (priv->current_chat);
+  clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
+  text_available = gtk_clipboard_wait_is_text_available (clipboard);
+  gtk_action_set_sensitive (self->priv->menu_edit_paste, text_available);
 }
 
 static void
-chat_window_paste_activate_cb (GtkAction         *action,
-                              EmpathyChatWindow *window)
+chat_window_cut_activate_cb (GtkAction *action,
+    EmpathyChatWindow *self)
 {
-       EmpathyChatWindowPriv *priv;
+  g_return_if_fail (EMPATHY_IS_CHAT_WINDOW (self));
 
-       g_return_if_fail (EMPATHY_IS_CHAT_WINDOW (window));
+  empathy_chat_cut (self->priv->current_chat);
+}
 
-       priv = GET_PRIV (window);
+static void
+chat_window_copy_activate_cb (GtkAction *action,
+    EmpathyChatWindow *self)
+{
+  g_return_if_fail (EMPATHY_IS_CHAT_WINDOW (self));
 
-       empathy_chat_paste (priv->current_chat);
+  empathy_chat_copy (self->priv->current_chat);
 }
 
 static void
-chat_window_find_activate_cb (GtkAction         *action,
-                             EmpathyChatWindow *window)
+chat_window_paste_activate_cb (GtkAction *action,
+    EmpathyChatWindow *self)
 {
-       EmpathyChatWindowPriv *priv;
+  g_return_if_fail (EMPATHY_IS_CHAT_WINDOW (self));
 
-       g_return_if_fail (EMPATHY_IS_CHAT_WINDOW (window));
+  empathy_chat_paste (self->priv->current_chat);
+}
 
-       priv = GET_PRIV (window);
+static void
+chat_window_find_activate_cb (GtkAction *action,
+    EmpathyChatWindow *self)
+{
+  g_return_if_fail (EMPATHY_IS_CHAT_WINDOW (self));
 
-       empathy_chat_find (priv->current_chat);
+  empathy_chat_find (self->priv->current_chat);
 }
 
 static void
-chat_window_tabs_next_activate_cb (GtkAction         *action,
-                                  EmpathyChatWindow *window)
+chat_window_tabs_next_activate_cb (GtkAction *action,
+    EmpathyChatWindow *self)
 {
-       EmpathyChatWindowPriv *priv;
-       gint                  index_, numPages;
-       gboolean              wrap_around;
-
-       priv = GET_PRIV (window);
+  gint index_, numPages;
+  gboolean wrap_around;
 
-       g_object_get (gtk_settings_get_default (), "gtk-keynav-wrap-around",
-                      &wrap_around, NULL);
+  g_object_get (gtk_settings_get_default (),
+      "gtk-keynav-wrap-around", &wrap_around,
+      NULL);
 
-       index_ = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook));
-       numPages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->notebook));
+  index_ = gtk_notebook_get_current_page (GTK_NOTEBOOK (self->priv->notebook));
+  numPages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (self->priv->notebook));
 
-       if (index_ == (numPages - 1) && wrap_around) {
-               gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), 0);
-               return;
-       }
+  if (index_ == (numPages - 1) && wrap_around)
+    {
+      gtk_notebook_set_current_page (GTK_NOTEBOOK (self->priv->notebook), 0);
+      return;
+    }
 
-       gtk_notebook_next_page (GTK_NOTEBOOK (priv->notebook));
+  gtk_notebook_next_page (GTK_NOTEBOOK (self->priv->notebook));
 }
 
 static void
-chat_window_tabs_previous_activate_cb (GtkAction         *action,
-                                  EmpathyChatWindow *window)
+chat_window_tabs_previous_activate_cb (GtkAction *action,
+    EmpathyChatWindow *self)
 {
-       EmpathyChatWindowPriv *priv;
-       gint                  index_, numPages;
-       gboolean              wrap_around;
+  gint index_, numPages;
+  gboolean wrap_around;
 
-       priv = GET_PRIV (window);
+  g_object_get (gtk_settings_get_default (),
+      "gtk-keynav-wrap-around", &wrap_around,
+      NULL);
 
-       g_object_get (gtk_settings_get_default (), "gtk-keynav-wrap-around",
-                      &wrap_around, NULL);
+  index_ = gtk_notebook_get_current_page (GTK_NOTEBOOK (self->priv->notebook));
+  numPages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (self->priv->notebook));
 
-       index_ = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook));
-       numPages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->notebook));
+  if (index_ <= 0 && wrap_around)
+    {
+      gtk_notebook_set_current_page (GTK_NOTEBOOK (self->priv->notebook),
+          numPages - 1);
+      return;
+    }
 
-       if (index_ <= 0 && wrap_around) {
-               gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), numPages - 1);
-               return;
-       }
+  gtk_notebook_prev_page (GTK_NOTEBOOK (self->priv->notebook));
+}
 
-       gtk_notebook_prev_page (GTK_NOTEBOOK (priv->notebook));
+void
+empathy_chat_window_next_tab (EmpathyChatWindow *self)
+{
+  chat_window_tabs_next_activate_cb (NULL, self);
 }
 
-static void
-chat_window_tabs_undo_close_tab_activate_cb (GtkAction         *action,
-                                            EmpathyChatWindow *window)
+void
+empathy_chat_window_prev_tab (EmpathyChatWindow *self)
 {
-       EmpathyChatWindowPriv *priv = GET_PRIV (window);
-       empathy_chat_manager_undo_closed_chat (priv->chat_manager,
-                                              empathy_get_current_action_time ());
+  chat_window_tabs_previous_activate_cb (NULL, self);
 }
 
+
 static void
-chat_window_tabs_left_activate_cb (GtkAction         *action,
-                                  EmpathyChatWindow *window)
+chat_window_tabs_undo_close_tab_activate_cb (GtkAction *action,
+    EmpathyChatWindow *self)
 {
-       EmpathyChatWindowPriv *priv;
-       EmpathyChat           *chat;
-       gint                  index_, num_pages;
+  empathy_chat_manager_undo_closed_chat (self->priv->chat_manager,
+      empathy_get_current_action_time ());
+}
 
-       priv = GET_PRIV (window);
+static void
+chat_window_tabs_left_activate_cb (GtkAction *action,
+    EmpathyChatWindow *self)
+{
+  EmpathyChat *chat;
+  gint index_, num_pages;
 
-       chat = priv->current_chat;
-       index_ = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook));
-       if (index_ <= 0) {
-               return;
-       }
+  chat = self->priv->current_chat;
+  index_ = gtk_notebook_get_current_page (GTK_NOTEBOOK (self->priv->notebook));
+  if (index_ <= 0)
+    return;
 
-       gtk_notebook_reorder_child (GTK_NOTEBOOK (priv->notebook),
-                                   GTK_WIDGET (chat),
-                                   index_ - 1);
+  gtk_notebook_reorder_child (GTK_NOTEBOOK (self->priv->notebook), GTK_WIDGET (chat),
+      index_ - 1);
 
-       num_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->notebook));
-       chat_window_menu_context_update (priv, num_pages);
+  num_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (self->priv->notebook));
+  chat_window_menu_context_update (self, num_pages);
 }
 
 static void
-chat_window_tabs_right_activate_cb (GtkAction         *action,
-                                   EmpathyChatWindow *window)
+chat_window_tabs_right_activate_cb (GtkAction *action,
+    EmpathyChatWindow *self)
 {
-       EmpathyChatWindowPriv *priv;
-       EmpathyChat           *chat;
-       gint                  index_, num_pages;
-
-       priv = GET_PRIV (window);
+  EmpathyChat *chat;
+  gint index_, num_pages;
 
-       chat = priv->current_chat;
-       index_ = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook));
+  chat = self->priv->current_chat;
+  index_ = gtk_notebook_get_current_page (GTK_NOTEBOOK (self->priv->notebook));
 
-       gtk_notebook_reorder_child (GTK_NOTEBOOK (priv->notebook),
-                                   GTK_WIDGET (chat),
-                                   index_ + 1);
+  gtk_notebook_reorder_child (GTK_NOTEBOOK (self->priv->notebook), GTK_WIDGET (chat),
+      index_ + 1);
 
-       num_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->notebook));
-       chat_window_menu_context_update (priv, num_pages);
+  num_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (self->priv->notebook));
+  chat_window_menu_context_update (self, num_pages);
 }
 
-static EmpathyChatWindow *
+EmpathyChatWindow *
 empathy_chat_window_new (void)
 {
-       return EMPATHY_CHAT_WINDOW (g_object_new (EMPATHY_TYPE_CHAT_WINDOW, NULL));
+  return g_object_new (EMPATHY_TYPE_CHAT_WINDOW,
+      NULL);
 }
 
 static void
-chat_window_detach_activate_cb (GtkAction         *action,
-                               EmpathyChatWindow *window)
+chat_window_detach_activate_cb (GtkAction *action,
+    EmpathyChatWindow *self)
 {
-       EmpathyChatWindowPriv *priv;
-       EmpathyChatWindow     *new_window;
-       EmpathyChat           *chat;
+  EmpathyChatWindow *new_window;
+  EmpathyChat *chat;
 
-       priv = GET_PRIV (window);
+  chat = self->priv->current_chat;
+  new_window = empathy_chat_window_new ();
 
-       chat = priv->current_chat;
-       new_window = empathy_chat_window_new ();
+  empathy_chat_window_move_chat (self, new_window, chat);
 
-       empathy_chat_window_move_chat (window, new_window, chat);
-
-       priv = GET_PRIV (new_window);
-       gtk_widget_show (priv->dialog);
+  gtk_widget_show (GTK_WIDGET (new_window));
 }
 
 static void
-chat_window_help_contents_activate_cb (GtkAction         *action,
-                                      EmpathyChatWindow *window)
+chat_window_help_contents_activate_cb (GtkAction *action,
+    EmpathyChatWindow *self)
 {
-       EmpathyChatWindowPriv *priv = GET_PRIV (window);
-
-       empathy_url_show (priv->dialog, "help:empathy");
+  empathy_url_show (GTK_WIDGET (self), "help:empathy");
 }
 
 static void
-chat_window_help_about_activate_cb (GtkAction         *action,
-                                   EmpathyChatWindow *window)
+chat_window_help_about_activate_cb (GtkAction *action,
+    EmpathyChatWindow *self)
 {
-       EmpathyChatWindowPriv *priv = GET_PRIV (window);
-
-       empathy_about_dialog_new (GTK_WINDOW (priv->dialog));
+  empathy_about_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (self))));
 }
 
 static gboolean
-chat_window_delete_event_cb (GtkWidget        *dialog,
-                            GdkEvent         *event,
-                            EmpathyChatWindow *window)
+chat_window_delete_event_cb (GtkWidget *dialog,
+    GdkEvent *event,
+    EmpathyChatWindow *self)
 {
-       EmpathyChatWindowPriv *priv = GET_PRIV (window);
-       EmpathyChat *chat = NULL;
-       guint n_rooms = 0;
-       GList *l;
+  EmpathyChat *chat = NULL;
+  guint n_rooms = 0;
+  GList *l;
 
-       DEBUG ("Delete event received");
+  DEBUG ("Delete event received");
 
-       for (l = priv->chats; l != NULL; l = l->next) {
-               if (chat_needs_close_confirmation (l->data)) {
-                       chat = l->data;
-                       n_rooms++;
-               }
-       }
+  for (l = self->priv->chats; l != NULL; l = l->next)
+    {
+      if (chat_needs_close_confirmation (l->data))
+        {
+          chat = l->data;
+          n_rooms++;
+        }
+    }
 
-       if (n_rooms > 0) {
-               confirm_close (window, TRUE, n_rooms,
-                       (n_rooms == 1 ? chat : NULL));
-       } else {
-               remove_all_chats (window);
-       }
+  if (n_rooms > 0)
+    {
+      confirm_close (self, TRUE, n_rooms, (n_rooms == 1 ? chat : NULL));
+    }
+  else
+    {
+      remove_all_chats (self);
+    }
 
-       return TRUE;
+  return TRUE;
 }
 
 static void
-chat_window_composing_cb (EmpathyChat       *chat,
-                         gboolean          is_composing,
-                         EmpathyChatWindow *window)
+chat_window_composing_cb (EmpathyChat *chat,
+    gboolean is_composing,
+    EmpathyChatWindow *self)
 {
-       chat_window_update_chat_tab (chat);
+  chat_window_update_chat_tab (chat);
 }
 
 static void
-chat_window_set_urgency_hint (EmpathyChatWindow *window,
-                             gboolean          urgent)
+chat_window_set_urgency_hint (EmpathyChatWindow *self,
+    gboolean urgent)
 {
-       EmpathyChatWindowPriv *priv;
-
-       priv = GET_PRIV (window);
-
-       gtk_window_set_urgency_hint (GTK_WINDOW (priv->dialog), urgent);
+  //gtk_window_set_urgency_hint (GTK_WINDOW (self), urgent);
 }
 
 static void
 chat_window_notification_closed_cb (NotifyNotification *notify,
-                                   EmpathyChatWindow *self)
-{
-       EmpathyChatWindowPriv *priv = GET_PRIV (self);
-
-       g_object_unref (notify);
-       if (priv->notification == notify) {
-               priv->notification = NULL;
-       }
-}
-
-static void
-chat_window_show_or_update_notification (EmpathyChatWindow *window,
-                                        EmpathyMessage *message,
-                                        EmpathyChat *chat)
-{
-       EmpathyContact *sender;
-       const gchar *header;
-       char *escaped;
-       const char *body;
-       GdkPixbuf *pixbuf;
-       EmpathyChatWindowPriv *priv = GET_PRIV (window);
-       gboolean res, has_x_canonical_append;
-       NotifyNotification *notification = priv->notification;
-
-       if (!empathy_notify_manager_notification_is_enabled (priv->notify_mgr)) {
-               return;
-       } else {
-               res = g_settings_get_boolean (priv->gsettings_notif,
-                               EMPATHY_PREFS_NOTIFICATIONS_FOCUS);
-
-               if (!res) {
-                       return;
-               }
-       }
-
-       sender = empathy_message_get_sender (message);
-       header = empathy_contact_get_alias (sender);
-       body = empathy_message_get_body (message);
-       escaped = g_markup_escape_text (body, -1);
-       has_x_canonical_append = empathy_notify_manager_has_capability (
-               priv->notify_mgr, EMPATHY_NOTIFY_MANAGER_CAP_X_CANONICAL_APPEND);
-
-       if (notification != NULL && !has_x_canonical_append) {
-               /* if the notification server supports x-canonical-append, it is
-                  better to not use notify_notification_update to avoid
-                  overwriting the current notification message */
-               notify_notification_update (notification,
-                                           header, escaped, NULL);
-       } else {
-               /* if the notification server supports x-canonical-append,
-                  the hint will be added, so that the message from the
-                  just created notification will be automatically appended
-                  to an existing notification with the same title.
-                  In this way the previous message will not be lost: the new
-                  message will appear below it, in the same notification */
-               notification = notify_notification_new (header, escaped, NULL);
-
-               if (priv->notification == NULL) {
-                       priv->notification = notification;
-               }
-
-               notify_notification_set_timeout (notification, NOTIFY_EXPIRES_DEFAULT);
-
-               tp_g_signal_connect_object (notification, "closed",
-                                 G_CALLBACK (chat_window_notification_closed_cb), window, 0);
-
-               if (has_x_canonical_append) {
-                       /* We have to set a not empty string to keep libnotify happy */
-                       notify_notification_set_hint_string (notification,
-                               EMPATHY_NOTIFY_MANAGER_CAP_X_CANONICAL_APPEND, "1");
-               }
-
-               {
-                       const gchar *category = empathy_chat_is_room (chat)
-                               ? EMPATHY_NOTIFICATION_CATEGORY_MENTIONED
-                               : EMPATHY_NOTIFICATION_CATEGORY_CHAT;
-                       notify_notification_set_hint (notification,
-                               EMPATHY_NOTIFY_MANAGER_CAP_CATEGORY,
-                               g_variant_new_string (category));
-               }
-       }
-
-       pixbuf = empathy_notify_manager_get_pixbuf_for_notification (priv->notify_mgr,
-               sender, EMPATHY_IMAGE_NEW_MESSAGE);
-
-       if (pixbuf != NULL) {
-               notify_notification_set_icon_from_pixbuf (notification, pixbuf);
-               g_object_unref (pixbuf);
-       }
-
-       notify_notification_show (notification, NULL);
-
-       g_free (escaped);
+    EmpathyChatWindow *self)
+{
+  g_object_unref (notify);
+  if (self->priv->notification == notify)
+    self->priv->notification = NULL;
+}
+
+static void
+chat_window_show_or_update_notification (EmpathyChatWindow *self,
+    EmpathyMessage *message,
+    EmpathyChat *chat)
+{
+  EmpathyContact *sender;
+  const gchar *header;
+  char *escaped;
+  const char *body;
+  GdkPixbuf *pixbuf;
+  gboolean res, has_x_canonical_append;
+  NotifyNotification *notification = self->priv->notification;
+
+  if (!empathy_notify_manager_notification_is_enabled (self->priv->notify_mgr))
+    return;
+
+  res = g_settings_get_boolean (self->priv->gsettings_notif,
+      EMPATHY_PREFS_NOTIFICATIONS_FOCUS);
+
+  if (!res)
+    return;
+
+  sender = empathy_message_get_sender (message);
+  header = empathy_contact_get_alias (sender);
+  body = empathy_message_get_body (message);
+  escaped = g_markup_escape_text (body, -1);
+
+  has_x_canonical_append = empathy_notify_manager_has_capability (
+    self->priv->notify_mgr, EMPATHY_NOTIFY_MANAGER_CAP_X_CANONICAL_APPEND);
+
+  if (notification != NULL && !has_x_canonical_append)
+    {
+      /* if the notification server supports x-canonical-append, it is
+         better to not use notify_notification_update to avoid
+         overwriting the current notification message */
+      notify_notification_update (notification,
+                header, escaped, NULL);
+    }
+  else
+    {
+      /* if the notification server supports x-canonical-append,
+         the hint will be added, so that the message from the
+         just created notification will be automatically appended
+         to an existing notification with the same title.
+         In this way the previous message will not be lost: the new
+         message will appear below it, in the same notification */
+      const gchar *category = empathy_chat_is_room (chat)
+        ? EMPATHY_NOTIFICATION_CATEGORY_MENTIONED
+        : EMPATHY_NOTIFICATION_CATEGORY_CHAT;
+
+      notification = empathy_notify_manager_create_notification (header,
+          escaped, NULL);
+
+      if (self->priv->notification == NULL)
+        self->priv->notification = notification;
+
+      tp_g_signal_connect_object (notification, "closed",
+            G_CALLBACK (chat_window_notification_closed_cb), self, 0);
+
+      if (has_x_canonical_append)
+        {
+          /* We have to set a not empty string to keep libnotify happy */
+          notify_notification_set_hint_string (notification,
+            EMPATHY_NOTIFY_MANAGER_CAP_X_CANONICAL_APPEND, "1");
+        }
+
+      notify_notification_set_hint (notification,
+          EMPATHY_NOTIFY_MANAGER_CAP_CATEGORY, g_variant_new_string (category));
+    }
+
+  pixbuf = empathy_notify_manager_get_pixbuf_for_notification (self->priv->notify_mgr,
+    sender, EMPATHY_IMAGE_NEW_MESSAGE);
+
+  if (pixbuf != NULL)
+    {
+      notify_notification_set_icon_from_pixbuf (notification, pixbuf);
+      g_object_unref (pixbuf);
+    }
+
+  notify_notification_show (notification, NULL);
+
+  g_free (escaped);
 }
 
 static gboolean
-empathy_chat_window_has_focus (EmpathyChatWindow *window)
+empathy_chat_window_has_focus (EmpathyChatWindow *self)
 {
-       EmpathyChatWindowPriv *priv;
-       gboolean              has_focus;
+  gboolean has_focus;
 
-       g_return_val_if_fail (EMPATHY_IS_CHAT_WINDOW (window), FALSE);
+  g_return_val_if_fail (EMPATHY_IS_CHAT_WINDOW (self), FALSE);
 
-       priv = GET_PRIV (window);
+  g_object_get ( gtk_widget_get_toplevel (GTK_WIDGET (self)), "has-toplevel-focus", &has_focus, NULL);
 
-       g_object_get (priv->dialog, "has-toplevel-focus", &has_focus, NULL);
+  return has_focus;
+}
 
-       return has_focus;
+static void
+chat_window_new_message_cb (EmpathyChat *chat,
+    EmpathyMessage *message,
+    gboolean pending,
+    gboolean should_highlight,
+    EmpathyChatWindow *self)
+{
+  gboolean has_focus;
+  gboolean needs_urgency;
+  EmpathyContact *sender;
+
+  has_focus = empathy_chat_window_has_focus (self);
+
+  /* - if we're the sender, we play the sound if it's specified in the
+   *   preferences and we're not away.
+   * - if we receive a message, we play the sound if it's specified in the
+   *   preferences and the window does not have focus on the chat receiving
+   *   the message.
+   */
+
+  sender = empathy_message_get_sender (message);
+
+  if (empathy_contact_is_user (sender))
+    {
+      empathy_sound_manager_play (self->priv->sound_mgr, GTK_WIDGET (self),
+          EMPATHY_SOUND_MESSAGE_OUTGOING);
+      return;
+    }
+
+  if (has_focus && self->priv->current_chat == chat)
+    {
+      /* window and tab are focused so consider the message to be read */
+
+      /* FIXME: see Bug#610994 and coments about it in EmpathyChatPriv */
+      empathy_chat_messages_read (chat);
+      return;
+    }
+
+  /* Update the chat tab if this is the first unread message */
+  if (empathy_chat_get_nb_unread_messages (chat) == 1)
+    {
+      chat_window_update_chat_tab (chat);
+    }
+
+  /* If empathy_chat_is_room () returns TRUE, that means it's a named MUC.
+   * If empathy_chat_get_remote_contact () returns NULL, that means it's
+   * an unamed MUC (msn-like).
+   * In case of a MUC, we set urgency if either:
+   *   a) the chatroom's always_urgent property is TRUE
+   *   b) the message contains our alias
+   */
+  if (empathy_chat_is_room (chat))
+    {
+      TpAccount *account;
+      const gchar *room;
+      EmpathyChatroom *chatroom;
+
+      account = empathy_chat_get_account (chat);
+      room = empathy_chat_get_id (chat);
+
+      chatroom = empathy_chatroom_manager_find (self->priv->chatroom_manager,
+          account, room);
+
+      if (chatroom != NULL && empathy_chatroom_is_always_urgent (chatroom))
+        needs_urgency = TRUE;
+      else
+        needs_urgency = should_highlight;
+    }
+  else
+    {
+      needs_urgency = TRUE;
+    }
+
+  if (needs_urgency)
+    {
+      if (!has_focus)
+        chat_window_set_urgency_hint (self, TRUE);
+
+      /* Pending messages have already been displayed and notified in the
+      * approver, so we don't display a notification and play a sound
+      * for those */
+      if (!pending)
+        {
+          empathy_sound_manager_play (self->priv->sound_mgr,
+              GTK_WIDGET (self), EMPATHY_SOUND_MESSAGE_INCOMING);
+
+          chat_window_show_or_update_notification (self, message, chat);
+        }
+    }
+
+  /* update the number of unread messages and the window icon */
+  chat_window_title_update (self);
+  chat_window_icon_update (self, TRUE);
 }
 
 static void
-chat_window_new_message_cb (EmpathyChat       *chat,
-                           EmpathyMessage    *message,
-                           gboolean pending,
-                           gboolean should_highlight,
-                           EmpathyChatWindow *window)
+chat_window_command_part (EmpathyChat *chat,
+    GStrv strv)
 {
-       EmpathyChatWindowPriv *priv;
-       gboolean              has_focus;
-       gboolean              needs_urgency;
-       EmpathyContact        *sender;
-
-       priv = GET_PRIV (window);
-
-       has_focus = empathy_chat_window_has_focus (window);
-
-       /* - if we're the sender, we play the sound if it's specified in the
-        *   preferences and we're not away.
-        * - if we receive a message, we play the sound if it's specified in the
-        *   preferences and the window does not have focus on the chat receiving
-        *   the message.
-        */
+  EmpathyChat *chat_to_be_parted;
+  EmpathyTpChat *tp_chat = NULL;
 
-       sender = empathy_message_get_sender (message);
+  if (strv[1] == NULL)
+    {
+      /* No chatroom ID specified */
+      tp_chat = empathy_chat_get_tp_chat (chat);
 
-       if (empathy_contact_is_user (sender)) {
-               empathy_sound_manager_play (priv->sound_mgr, GTK_WIDGET (priv->dialog),
-                                   EMPATHY_SOUND_MESSAGE_OUTGOING);
-       }
+      if (tp_chat)
+        empathy_tp_chat_leave (tp_chat, "");
 
-       if (has_focus && priv->current_chat == chat) {
-               /* window and tab are focused so consider the message to be read */
+      return;
+    }
 
-               /* FIXME: see Bug#610994 and coments about it in EmpathyChatPriv */
-               empathy_chat_messages_read (chat);
-               return;
-       }
+  chat_to_be_parted = empathy_chat_window_find_chat (
+    empathy_chat_get_account (chat), strv[1], FALSE);
 
-       /* Update the chat tab if this is the first unread message */
-       if (empathy_chat_get_nb_unread_messages (chat) == 1) {
-               chat_window_update_chat_tab (chat);
-       }
+  if (chat_to_be_parted != NULL)
+    {
+      /* Found a chatroom matching the specified ID */
+      tp_chat = empathy_chat_get_tp_chat (chat_to_be_parted);
 
-       /* If empathy_chat_is_room () returns TRUE, that means it's a named MUC.
-        * If empathy_chat_get_remote_contact () returns NULL, that means it's
-        * an unamed MUC (msn-like).
-        * In case of a MUC, we set urgency if either:
-        *   a) the chatroom's always_urgent property is TRUE
-        *   b) the message contains our alias
-        */
-       if (empathy_chat_is_room (chat)) {
-               TpAccount             *account;
-               const gchar           *room;
-               EmpathyChatroom       *chatroom;
+      if (tp_chat)
+        empathy_tp_chat_leave (tp_chat, strv[2]);
+    }
+  else
+    {
+      gchar *message;
 
-               account = empathy_chat_get_account (chat);
-               room = empathy_chat_get_id (chat);
+      /* Going by the syntax of PART command:
+       *
+       * /PART [<chatroom-ID>] [<reason>]
+       *
+       * Chatroom-ID is not a must to specify a reason.
+       * If strv[1] (chatroom-ID) is not a valid identifier for a connected
+       * MUC then the current chatroom should be parted and srtv[1] should
+       * be treated as part of the optional part-message. */
+      message = g_strconcat (strv[1], " ", strv[2], NULL);
+      tp_chat = empathy_chat_get_tp_chat (chat);
 
-               chatroom = empathy_chatroom_manager_find (priv->chatroom_manager,
-                                                         account, room);
+      if (tp_chat)
+        empathy_tp_chat_leave (tp_chat, message);
 
-               if (chatroom != NULL && empathy_chatroom_is_always_urgent (chatroom)) {
-                       needs_urgency = TRUE;
-               } else {
-                       needs_urgency = should_highlight;
-               }
-       } else {
-               needs_urgency = TRUE;
-       }
-
-       if (needs_urgency) {
-               if (!has_focus) {
-                       chat_window_set_urgency_hint (window, TRUE);
-               }
-
-               /* Pending messages have already been displayed and notified in the
-               * approver, so we don't display a notification and play a sound for those */
-               if (!pending) {
-                       empathy_sound_manager_play (priv->sound_mgr, GTK_WIDGET (priv->dialog),
-                                   EMPATHY_SOUND_MESSAGE_INCOMING);
-
-                       chat_window_show_or_update_notification (window, message, chat);
-               }
-       }
-
-       /* update the number of unread messages and the window icon */
-       chat_window_title_update (priv);
-       chat_window_icon_update (priv, TRUE);
-}
-
-static void
-chat_window_command_part (EmpathyChat *chat,
-                          GStrv        strv)
-{
-       EmpathyChat *chat_to_be_parted;
-       EmpathyTpChat *tp_chat = NULL;
-
-       if (strv[1] == NULL) {
-               /* No chatroom ID specified  */
-               tp_chat = empathy_chat_get_tp_chat (chat);
-               if (tp_chat)
-                       empathy_tp_chat_leave (tp_chat, "");
-               return;
-       }
-       chat_to_be_parted = empathy_chat_window_find_chat (
-               empathy_chat_get_account (chat), strv[1], FALSE);
-
-       if (chat_to_be_parted != NULL) {
-               /* Found a chatroom matching the specified ID */
-               tp_chat = empathy_chat_get_tp_chat (chat_to_be_parted);
-               if (tp_chat)
-                       empathy_tp_chat_leave (tp_chat, strv[2]);
-       } else {
-               gchar *message;
-
-               /* Going by the syntax of PART command:
-                *
-                * /PART [<chatroom-ID>] [<reason>]
-                *
-                * Chatroom-ID is not a must to specify a reason.
-                * If strv[1] (chatroom-ID) is not a valid identifier for a connected
-                * MUC then the current chatroom should be parted and srtv[1] should
-                * be treated as part of the optional part-message. */
-               message = g_strconcat (strv[1], " ", strv[2], NULL);
-               tp_chat = empathy_chat_get_tp_chat (chat);
-               if (tp_chat)
-                       empathy_tp_chat_leave (tp_chat, message);
-
-               g_free (message);
-       }
+      g_free (message);
+    }
 }
 
 static GtkNotebook *
 notebook_create_window_cb (GtkNotebook *source,
-                        GtkWidget   *page,
-                        gint         x,
-                        gint         y,
-                        gpointer     user_data)
+    GtkWidget *page,
+    gint x,
+    gint y,
+    gpointer user_data)
 {
-       EmpathyChatWindowPriv *priv;
-       EmpathyChatWindow     *window, *new_window;
-       EmpathyChat           *chat;
+  EmpathyChatWindow *window, *new_window;
+  EmpathyChat *chat;
 
-       chat = EMPATHY_CHAT (page);
-       window = chat_window_find_chat (chat);
+  chat = EMPATHY_CHAT (page);
+  window = chat_window_find_chat (chat);
 
-       new_window = empathy_chat_window_new ();
-       priv = GET_PRIV (new_window);
+  new_window = empathy_chat_window_new ();
 
-       DEBUG ("Detach hook called");
+  DEBUG ("Detach hook called");
 
-       empathy_chat_window_move_chat (window, new_window, chat);
+  empathy_chat_window_move_chat (window, new_window, chat);
 
-       gtk_widget_show (priv->dialog);
-       gtk_window_move (GTK_WINDOW (priv->dialog), x, y);
+  gtk_widget_show (GTK_WIDGET (new_window));
+  //gtk_window_move (GTK_WINDOW (new_window), x, y);
 
-       return NULL;
+  return NULL;
 }
 
 static void
-chat_window_page_switched_cb (GtkNotebook      *notebook,
-                             GtkWidget         *child,
-                             gint              page_num,
-                             EmpathyChatWindow *window)
+chat_window_page_switched_cb (GtkNotebook *notebook,
+    GtkWidget *child,
+    gint page_num,
+    EmpathyChatWindow *self)
 {
-       EmpathyChatWindowPriv *priv = GET_PRIV (window);
-       EmpathyChat           *chat = EMPATHY_CHAT (child);
+  EmpathyChat *chat = EMPATHY_CHAT (child);
 
-       DEBUG ("Page switched");
+  DEBUG ("Page switched");
 
-       if (priv->page_added) {
-               priv->page_added = FALSE;
-               empathy_chat_scroll_down (chat);
-       }
-       else if (priv->current_chat == chat) {
-               return;
-       }
+  if (self->priv->page_added)
+    {
+      self->priv->page_added = FALSE;
+      empathy_chat_scroll_down (chat);
+    }
+  else if (self->priv->current_chat == chat)
+    {
+      return;
+    }
 
-       priv->current_chat = chat;
-       empathy_chat_messages_read (chat);
+  self->priv->current_chat = chat;
+  empathy_chat_messages_read (chat);
 
-       chat_window_update_chat_tab (chat);
+  chat_window_update_chat_tab (chat);
 }
 
 static void
-chat_window_page_added_cb (GtkNotebook      *notebook,
-                          GtkWidget        *child,
-                          guint             page_num,
-                          EmpathyChatWindow *window)
-{
-       EmpathyChatWindowPriv *priv;
-       EmpathyChat           *chat;
-
-       priv = GET_PRIV (window);
-
-       /* If we just received DND to the same window, we don't want
-        * to do anything here like removing the tab and then readding
-        * it, so we return here and in "page-added".
-        */
-       if (priv->dnd_same_window) {
-               DEBUG ("Page added (back to the same window)");
-               priv->dnd_same_window = FALSE;
-               return;
-       }
-
-       DEBUG ("Page added");
-
-       /* Get chat object */
-       chat = EMPATHY_CHAT (child);
-
-       /* Connect chat signals for this window */
-       g_signal_connect (chat, "composing",
-                         G_CALLBACK (chat_window_composing_cb),
-                         window);
-       g_signal_connect (chat, "new-message",
-                         G_CALLBACK (chat_window_new_message_cb),
-                         window);
-       g_signal_connect (chat, "part-command-entered",
-                         G_CALLBACK (chat_window_command_part),
-                         NULL);
-       g_signal_connect (chat, "notify::tp-chat",
-                         G_CALLBACK (chat_window_update_chat_tab),
-                         window);
-
-       /* Set flag so we know to perform some special operations on
-        * switch page due to the new page being added.
-        */
-       priv->page_added = TRUE;
-
-       /* Get list of chats up to date */
-       priv->chats = g_list_append (priv->chats, chat);
-
-       chat_window_update_chat_tab (chat);
+chat_window_page_added_cb (GtkNotebook *notebook,
+    GtkWidget *child,
+    guint page_num,
+    EmpathyChatWindow *self)
+{
+  EmpathyChat *chat;
+
+  /* If we just received DND to the same window, we don't want
+   * to do anything here like removing the tab and then readding
+   * it, so we return here and in "page-added".
+   */
+  if (self->priv->dnd_same_window)
+    {
+      DEBUG ("Page added (back to the same window)");
+      self->priv->dnd_same_window = FALSE;
+      return;
+    }
+
+  DEBUG ("Page added");
+
+  /* Get chat object */
+  chat = EMPATHY_CHAT (child);
+
+  /* Connect chat signals for this window */
+  g_signal_connect (chat, "composing",
+      G_CALLBACK (chat_window_composing_cb), self);
+  g_signal_connect (chat, "new-message",
+      G_CALLBACK (chat_window_new_message_cb), self);
+  g_signal_connect (chat, "part-command-entered",
+      G_CALLBACK (chat_window_command_part), NULL);
+  g_signal_connect (chat, "notify::tp-chat",
+      G_CALLBACK (chat_window_update_chat_tab), self);
+
+  /* Set flag so we know to perform some special operations on
+   * switch page due to the new page being added.
+   */
+  self->priv->page_added = TRUE;
+
+  /* Get list of chats up to date */
+  self->priv->chats = g_list_append (self->priv->chats, chat);
+
+  chat_window_update_chat_tab (chat);
 }
 
 static void
-chat_window_page_removed_cb (GtkNotebook      *notebook,
-                            GtkWidget        *child,
-                            guint             page_num,
-                            EmpathyChatWindow *window)
-{
-       EmpathyChatWindowPriv *priv;
-       EmpathyChat           *chat;
-
-       priv = GET_PRIV (window);
-
-       /* If we just received DND to the same window, we don't want
-        * to do anything here like removing the tab and then readding
-        * it, so we return here and in "page-added".
-        */
-       if (priv->dnd_same_window) {
-               DEBUG ("Page removed (and will be readded to same window)");
-               return;
-       }
-
-       DEBUG ("Page removed");
-
-       /* Get chat object */
-       chat = EMPATHY_CHAT (child);
-
-       /* Disconnect all signal handlers for this chat and this window */
-       g_signal_handlers_disconnect_by_func (chat,
-                                             G_CALLBACK (chat_window_composing_cb),
-                                             window);
-       g_signal_handlers_disconnect_by_func (chat,
-                                             G_CALLBACK (chat_window_new_message_cb),
-                                             window);
-       g_signal_handlers_disconnect_by_func (chat,
-                                             G_CALLBACK (chat_window_update_chat_tab),
-                                             window);
-
-       /* Keep list of chats up to date */
-       priv->chats = g_list_remove (priv->chats, chat);
-       empathy_chat_messages_read (chat);
-
-       if (priv->chats == NULL) {
-               g_object_unref (window);
-       } else {
-               chat_window_update (window, TRUE);
-       }
+chat_window_page_removed_cb (GtkNotebook *notebook,
+    GtkWidget *child,
+    guint page_num,
+    EmpathyChatWindow *self)
+{
+  EmpathyChat *chat;
+
+  /* If we just received DND to the same window, we don't want
+   * to do anything here like removing the tab and then readding
+   * it, so we return here and in "page-added".
+   */
+  if (self->priv->dnd_same_window)
+    {
+      DEBUG ("Page removed (and will be readded to same window)");
+      return;
+    }
+
+  DEBUG ("Page removed");
+
+  /* Get chat object */
+  chat = EMPATHY_CHAT (child);
+
+  /* Disconnect all signal handlers for this chat and this window */
+  g_signal_handlers_disconnect_by_func (chat,
+      G_CALLBACK (chat_window_composing_cb), self);
+  g_signal_handlers_disconnect_by_func (chat,
+      G_CALLBACK (chat_window_new_message_cb), self);
+  g_signal_handlers_disconnect_by_func (chat,
+      G_CALLBACK (chat_window_update_chat_tab), self);
+
+  /* Keep list of chats up to date */
+  self->priv->chats = g_list_remove (self->priv->chats, chat);
+  empathy_chat_messages_read (chat);
+
+  if (self->priv->chats == NULL)
+    {
+      gtk_widget_destroy (GTK_WIDGET (self));
+    }
+  else
+    {
+      chat_window_update (self, TRUE);
+    }
 }
 
 static gboolean
-chat_window_focus_in_event_cb (GtkWidget        *widget,
-                              GdkEvent         *event,
-                              EmpathyChatWindow *window)
+chat_window_focus_in_event_cb (GtkWidget *widget,
+    GdkEvent *event,
+    EmpathyChatWindow *self)
 {
-       EmpathyChatWindowPriv *priv;
+  if (self->priv->current_chat == NULL) {
+          return FALSE;
+  }
+  empathy_chat_messages_read (self->priv->current_chat);
 
-       priv = GET_PRIV (window);
+  chat_window_set_urgency_hint (self, FALSE);
 
-       empathy_chat_messages_read (priv->current_chat);
+  /* Update the title, since we now mark all unread messages as read. */
+  chat_window_update_chat_tab_full (self->priv->current_chat, FALSE);
 
-       chat_window_set_urgency_hint (window, FALSE);
+  return FALSE;
+}
 
-       /* Update the title, since we now mark all unread messages as read. */
-       chat_window_update_chat_tab_full (priv->current_chat, FALSE);
+static void
+contacts_loaded_cb (EmpathyIndividualManager *mgr,
+    EmpathyChatWindow *self)
+{
+  chat_window_contact_menu_update (self);
+}
 
-       return FALSE;
+static gboolean
+chat_window_focus_out_event_cb (GtkWidget *widget,
+    GdkEvent *event,
+    EmpathyChatWindow *self)
+{
+  if (self->priv->individual_mgr != NULL)
+    return FALSE;
+
+  /* Keep the individual manager alive so we won't fetch everything from Folks
+   * each time we need to use it. Loading FolksAggregator can takes quite a
+   * while (if user has a huge LDAP abook for example) and it blocks
+   * the mainloop during most of this loading. We workaround this by loading
+   * it when the chat window has been unfocused and so, hopefully, not impact
+   * the reactivity of the chat window too much.
+   *
+   * The individual manager (and so Folks) is needed to know to which
+   * FolksIndividual a TpContact belongs, including:
+   * - empathy_chat_get_contact_menu: to list all the personas of the contact
+   * - empathy_display_individual_info: to invoke gnome-contacts with the
+   *   FolksIndividual.id of the contact
+   * - drag_data_received_individual_id: to find the individual associated
+   *   with the ID we received from the DnD in order to invite him.
+   */
+  self->priv->individual_mgr = empathy_individual_manager_dup_singleton ();
+
+  if (!empathy_individual_manager_get_contacts_loaded (
+      self->priv->individual_mgr))
+    {
+      /* We want to update the contact menu when Folks is loaded so we can
+       * list all the personas of the contact. */
+      tp_g_signal_connect_object (self->priv->individual_mgr, "contacts-loaded",
+          G_CALLBACK (contacts_loaded_cb), self, 0);
+    }
+
+  g_object_notify (G_OBJECT (self), "individual-manager");
+
+  return FALSE;
 }
 
 static gboolean
-chat_window_drag_drop (GtkWidget        *widget,
-                        GdkDragContext   *context,
-                        int               x,
-                        int               y,
-                        guint             time_,
-                        EmpathyChatWindow *window)
+chat_window_drag_drop (GtkWidget *widget,
+    GdkDragContext *context,
+    int x,
+    int y,
+    guint time_,
+    EmpathyChatWindow *self)
 {
-       GdkAtom target;
-       EmpathyChatWindowPriv *priv;
+  GdkAtom target;
 
-       priv = GET_PRIV (window);
+  target = gtk_drag_dest_find_target (widget, context, self->priv->file_targets);
+  if (target == GDK_NONE)
+    target = gtk_drag_dest_find_target (widget, context, self->priv->contact_targets);
 
-       target = gtk_drag_dest_find_target (widget, context, priv->file_targets);
-       if (target == GDK_NONE)
-               target = gtk_drag_dest_find_target (widget, context, priv->contact_targets);
+  if (target != GDK_NONE)
+    {
+      gtk_drag_get_data (widget, context, target, time_);
+      return TRUE;
+    }
 
-       if (target != GDK_NONE) {
-               gtk_drag_get_data (widget, context, target, time_);
-               return TRUE;
-       }
-
-       return FALSE;
+  return FALSE;
 }
 
 static gboolean
-chat_window_drag_motion (GtkWidget        *widget,
-                        GdkDragContext   *context,
-                        int               x,
-                        int               y,
-                        guint             time_,
-                        EmpathyChatWindow *window)
-{
-       GdkAtom target;
-       EmpathyChatWindowPriv *priv;
-
-       priv = GET_PRIV (window);
-
-       target = gtk_drag_dest_find_target (widget, context, priv->file_targets);
-       if (target != GDK_NONE) {
-               /* This is a file drag.  Ensure the contact is online and set the
-                  drag type to COPY.  Note that it's possible that the tab will
-                  be switched by GTK+ after a timeout from drag_motion without
-                  getting another drag_motion to disable the drop.  You have
-                  to hold your mouse really still.
-                */
-               EmpathyContact *contact;
-
-               priv = GET_PRIV (window);
-               contact = empathy_chat_get_remote_contact (priv->current_chat);
-               /* contact is NULL for multi-user chats.  We don't do
-                * file transfers to MUCs.  We also don't send files
-                * to offline contacts or contacts that don't support
-                * file transfer.
-                */
-               if ((contact == NULL) || !empathy_contact_is_online (contact)) {
-                       gdk_drag_status (context, 0, time_);
-                       return FALSE;
-               }
-               if (!(empathy_contact_get_capabilities (contact)
-                          & EMPATHY_CAPABILITIES_FT)) {
-                       gdk_drag_status (context, 0, time_);
-                       return FALSE;
-               }
-               gdk_drag_status (context, GDK_ACTION_COPY, time_);
-               return TRUE;
-       }
-
-       target = gtk_drag_dest_find_target (widget, context, priv->contact_targets);
-       if (target != GDK_NONE) {
-               /* This is a drag of a contact from a contact list.  Set to COPY.
-                  FIXME: If this drag is to a MUC window, it invites the user.
-                  Otherwise, it opens a chat.  Should we use a different drag
-                  type for invites?  Should we allow ASK?
-                */
-               gdk_drag_status (context, GDK_ACTION_COPY, time_);
-               return TRUE;
-       }
-
-       return FALSE;
+chat_window_drag_motion (GtkWidget *widget,
+    GdkDragContext *context,
+    int x,
+    int y,
+    guint time_,
+    EmpathyChatWindow *self)
+{
+  GdkAtom target;
+
+  target = gtk_drag_dest_find_target (widget, context, self->priv->file_targets);
+
+  if (target != GDK_NONE)
+    {
+      /* This is a file drag. Ensure the contact is online and set the
+         drag type to COPY. Note that it's possible that the tab will
+         be switched by GTK+ after a timeout from drag_motion without
+         getting another drag_motion to disable the drop. You have
+         to hold your mouse really still.
+       */
+      EmpathyContact *contact;
+
+      contact = empathy_chat_get_remote_contact (self->priv->current_chat);
+
+      /* contact is NULL for multi-user chats. We don't do
+       * file transfers to MUCs. We also don't send files
+       * to offline contacts or contacts that don't support
+       * file transfer.
+       */
+      if ((contact == NULL) || !empathy_contact_is_online (contact))
+        {
+          gdk_drag_status (context, 0, time_);
+          return FALSE;
+        }
+
+      if (!(empathy_contact_get_capabilities (contact)
+           & EMPATHY_CAPABILITIES_FT))
+        {
+          gdk_drag_status (context, 0, time_);
+          return FALSE;
+        }
+
+      gdk_drag_status (context, GDK_ACTION_COPY, time_);
+      return TRUE;
+    }
+
+  target = gtk_drag_dest_find_target (widget, context, self->priv->contact_targets);
+  if (target != GDK_NONE)
+    {
+      /* This is a drag of a contact from a contact list. Set to COPY.
+         FIXME: If this drag is to a MUC window, it invites the user.
+         Otherwise, it opens a chat. Should we use a different drag
+         type for invites? Should we allow ASK?
+       */
+      gdk_drag_status (context, GDK_ACTION_COPY, time_);
+      return TRUE;
+    }
+
+  return FALSE;
 }
 
 static void
 drag_data_received_individual_id (EmpathyChatWindow *self,
-                                 GtkWidget *widget,
-                                 GdkDragContext *context,
-                                 int x,
-                                 int y,
-                                 GtkSelectionData *selection,
-                                 guint info,
-                                 guint time_)
-{
-       const gchar *id;
-       EmpathyIndividualManager *manager = NULL;
-       FolksIndividual *individual;
-       EmpathyChatWindowPriv *priv = GET_PRIV (self);
-       EmpathyTpChat *chat;
-       TpContact *tp_contact;
-       TpConnection *conn;
-       EmpathyContact *contact;
-
-       id = (const gchar *) gtk_selection_data_get_data (selection);
-
-       DEBUG ("DND invididual %s", id);
-
-       if (priv->current_chat == NULL)
-               goto out;
-
-       chat = empathy_chat_get_tp_chat (priv->current_chat);
-       if (chat == NULL)
-               goto out;
-
-       if (!empathy_tp_chat_can_add_contact (chat)) {
-               DEBUG ("Can't invite contact to %s",
-                               tp_proxy_get_object_path (chat));
-               goto out;
-       }
-
-       manager = empathy_individual_manager_dup_singleton ();
-
-       individual = empathy_individual_manager_lookup_member (manager, id);
-       if (individual == NULL) {
-               DEBUG ("Failed to find individual %s", id);
-               goto out;
-       }
-
-       conn = tp_channel_borrow_connection ((TpChannel *) chat);
-       tp_contact = empathy_get_tp_contact_for_individual (individual, conn);
-       if (tp_contact == NULL) {
-               DEBUG ("Can't find a TpContact on connection %s for %s",
-                               tp_proxy_get_object_path (conn), id);
-               goto out;
-       }
-
-       DEBUG ("Inviting %s to join %s", tp_contact_get_identifier (tp_contact),
-                       tp_channel_get_identifier ((TpChannel *) chat));
-
-       contact = empathy_contact_dup_from_tp_contact (tp_contact);
-       empathy_tp_chat_add (chat, contact, NULL);
-       g_object_unref (contact);
+    GtkWidget *widget,
+    GdkDragContext *context,
+    int x,
+    int y,
+    GtkSelectionData *selection,
+    guint info,
+    guint time_)
+{
+  const gchar *id;
+  FolksIndividual *individual;
+  EmpathyTpChat *chat;
+  TpContact *tp_contact;
+  TpConnection *conn;
+  EmpathyContact *contact;
+
+  id = (const gchar *) gtk_selection_data_get_data (selection);
+
+  DEBUG ("DND invididual %s", id);
+
+  if (self->priv->current_chat == NULL)
+    goto out;
+
+  chat = empathy_chat_get_tp_chat (self->priv->current_chat);
+  if (chat == NULL)
+    goto out;
+
+  if (!empathy_tp_chat_can_add_contact (chat))
+    {
+      DEBUG ("Can't invite contact to %s",
+          tp_proxy_get_object_path (chat));
+      goto out;
+    }
+
+  if (self->priv->individual_mgr == NULL)
+    /* Not likely as we have to focus out the chat window in order to start
+     * the DnD but best to be safe. */
+    goto out;
+
+  individual = empathy_individual_manager_lookup_member (
+          self->priv->individual_mgr, id);
+  if (individual == NULL)
+    {
+      DEBUG ("Failed to find individual %s", id);
+      goto out;
+    }
+
+  conn = tp_channel_get_connection ((TpChannel *) chat);
+  tp_contact = empathy_get_tp_contact_for_individual (individual, conn);
+  if (tp_contact == NULL)
+    {
+      DEBUG ("Can't find a TpContact on connection %s for %s",
+          tp_proxy_get_object_path (conn), id);
+      goto out;
+    }
+
+  DEBUG ("Inviting %s to join %s", tp_contact_get_identifier (tp_contact),
+      tp_channel_get_identifier ((TpChannel *) chat));
+
+  contact = empathy_contact_dup_from_tp_contact (tp_contact);
+  empathy_tp_chat_add (chat, contact, NULL);
+  g_object_unref (contact);
 
 out:
-       gtk_drag_finish (context, TRUE, FALSE, time_);
-       tp_clear_object (&manager);
-}
-
-static void
-chat_window_drag_data_received (GtkWidget        *widget,
-                               GdkDragContext   *context,
-                               int               x,
-                               int               y,
-                               GtkSelectionData *selection,
-                               guint             info,
-                               guint             time_,
-                               EmpathyChatWindow *window)
-{
-       if (info == DND_DRAG_TYPE_CONTACT_ID) {
-               EmpathyChat           *chat = NULL;
-               EmpathyChatWindow     *old_window;
-               TpAccount             *account = NULL;
-               EmpathyClientFactory  *factory;
-               const gchar           *id;
-               gchar                **strv;
-               const gchar           *account_id;
-               const gchar           *contact_id;
-
-               id = (const gchar*) gtk_selection_data_get_data (selection);
-
-               factory = empathy_client_factory_dup ();
-
-               DEBUG ("DND contact from roster with id:'%s'", id);
-
-               strv = g_strsplit (id, ":", 2);
-               if (g_strv_length (strv) == 2) {
-                       account_id = strv[0];
-                       contact_id = strv[1];
-                       account =
-                               tp_simple_client_factory_ensure_account (
-                               TP_SIMPLE_CLIENT_FACTORY (factory), account_id,
-                                NULL, NULL);
-
-                       g_object_unref (factory);
-                       if (account != NULL)
-                               chat = empathy_chat_window_find_chat (account, contact_id, FALSE);
-               }
-
-               if (account == NULL) {
-                       g_strfreev (strv);
-                       gtk_drag_finish (context, FALSE, FALSE, time_);
-                       return;
-               }
-
-               if (!chat) {
-                       empathy_chat_with_contact_id (
-                               account, contact_id,
-                               empathy_get_current_action_time (),
-                               NULL, NULL);
-
-                       g_strfreev (strv);
-                       return;
-               }
-               g_strfreev (strv);
-
-               old_window = chat_window_find_chat (chat);
-               if (old_window) {
-                       if (old_window == window) {
-                               gtk_drag_finish (context, TRUE, FALSE, time_);
-                               return;
-                       }
-
-                       empathy_chat_window_move_chat (old_window, window, chat);
-               } else {
-                       empathy_chat_window_add_chat (window, chat);
-               }
-
-               /* Added to take care of any outstanding chat events */
-               empathy_chat_window_present_chat (chat,
-                       TP_USER_ACTION_TIME_NOT_USER_ACTION);
-
-               /* We should return TRUE to remove the data when doing
-                * GDK_ACTION_MOVE, but we don't here otherwise it has
-                * weird consequences, and we handle that internally
-                * anyway with add_chat () and remove_chat ().
-                */
-               gtk_drag_finish (context, TRUE, FALSE, time_);
-       }
-       else if (info == DND_DRAG_TYPE_INDIVIDUAL_ID) {
-               drag_data_received_individual_id (window, widget, context, x, y,
-                               selection, info, time_);
-       }
-       else if (info == DND_DRAG_TYPE_URI_LIST) {
-               EmpathyChatWindowPriv *priv;
-               EmpathyContact *contact;
-               const gchar *data;
-
-               priv = GET_PRIV (window);
-               contact = empathy_chat_get_remote_contact (priv->current_chat);
-
-               /* contact is NULL when current_chat is a multi-user chat.
-                * We don't do file transfers to MUCs, so just cancel the drag.
-                */
-               if (contact == NULL) {
-                       gtk_drag_finish (context, TRUE, FALSE, time_);
-                       return;
-               }
-
-               data = (const gchar *) gtk_selection_data_get_data (selection);
-               empathy_send_file_from_uri_list (contact, data);
-
-               gtk_drag_finish (context, TRUE, FALSE, time_);
-       }
-       else if (info == DND_DRAG_TYPE_TAB) {
-               EmpathyChat        **chat;
-               EmpathyChatWindow   *old_window = NULL;
-
-               DEBUG ("DND tab");
-
-               chat = (void *) gtk_selection_data_get_data (selection);
-               old_window = chat_window_find_chat (*chat);
-
-               if (old_window) {
-                       EmpathyChatWindowPriv *priv;
-
-                       priv = GET_PRIV (window);
-                       priv->dnd_same_window = (old_window == window);
-                       DEBUG ("DND tab (within same window: %s)",
-                               priv->dnd_same_window ? "Yes" : "No");
-               }
-       } else {
-               DEBUG ("DND from unknown source");
-               gtk_drag_finish (context, FALSE, FALSE, time_);
-       }
+  gtk_drag_finish (context, TRUE, FALSE, time_);
+}
+
+static void
+chat_window_drag_data_received (GtkWidget *widget,
+    GdkDragContext *context,
+    int x,
+    int y,
+    GtkSelectionData *selection,
+    guint info,
+    guint time_,
+    EmpathyChatWindow *self)
+{
+  if (info == DND_DRAG_TYPE_CONTACT_ID)
+    {
+      EmpathyChat *chat = NULL;
+      EmpathyChatWindow *old_window;
+      TpAccount *account = NULL;
+      EmpathyClientFactory *factory;
+      const gchar *id;
+      gchar **strv;
+      const gchar *account_id;
+      const gchar *contact_id;
+
+      id = (const gchar*) gtk_selection_data_get_data (selection);
+
+      factory = empathy_client_factory_dup ();
+
+      DEBUG ("DND contact from roster with id:'%s'", id);
+
+      strv = g_strsplit (id, ":", 2);
+      if (g_strv_length (strv) == 2)
+        {
+          account_id = strv[0];
+          contact_id = strv[1];
+
+          account = tp_simple_client_factory_ensure_account (
+              TP_SIMPLE_CLIENT_FACTORY (factory), account_id, NULL, NULL);
+
+          g_object_unref (factory);
+          if (account != NULL)
+            chat = empathy_chat_window_find_chat (account, contact_id, FALSE);
+        }
+
+      if (account == NULL)
+        {
+          g_strfreev (strv);
+          gtk_drag_finish (context, FALSE, FALSE, time_);
+          return;
+        }
+
+      if (!chat)
+        {
+          empathy_chat_with_contact_id (account, contact_id,
+              empathy_get_current_action_time (), NULL, NULL);
+
+          g_strfreev (strv);
+          return;
+        }
+
+      g_strfreev (strv);
+
+      old_window = chat_window_find_chat (chat);
+      if (old_window)
+        {
+          if (old_window == self)
+            {
+              gtk_drag_finish (context, TRUE, FALSE, time_);
+              return;
+            }
+
+          empathy_chat_window_move_chat (old_window, self, chat);
+        }
+      else
+        {
+          empathy_chat_window_add_chat (self, chat);
+        }
+
+      /* Added to take care of any outstanding chat events */
+      empathy_chat_window_present_chat (chat,
+          TP_USER_ACTION_TIME_NOT_USER_ACTION);
+
+      /* We should return TRUE to remove the data when doing
+       * GDK_ACTION_MOVE, but we don't here otherwise it has
+       * weird consequences, and we handle that internally
+       * anyway with add_chat () and remove_chat ().
+       */
+      gtk_drag_finish (context, TRUE, FALSE, time_);
+    }
+  else if (info == DND_DRAG_TYPE_INDIVIDUAL_ID)
+    {
+      drag_data_received_individual_id (self, widget, context, x, y,
+          selection, info, time_);
+    }
+  else if (info == DND_DRAG_TYPE_URI_LIST)
+    {
+      EmpathyContact *contact;
+      const gchar *data;
+
+      contact = empathy_chat_get_remote_contact (self->priv->current_chat);
+
+      /* contact is NULL when current_chat is a multi-user chat.
+       * We don't do file transfers to MUCs, so just cancel the drag.
+       */
+      if (contact == NULL)
+        {
+          gtk_drag_finish (context, TRUE, FALSE, time_);
+          return;
+        }
+
+      data = (const gchar *) gtk_selection_data_get_data (selection);
+      empathy_send_file_from_uri_list (contact, data);
+
+      gtk_drag_finish (context, TRUE, FALSE, time_);
+    }
+  else if (info == DND_DRAG_TYPE_TAB)
+    {
+      EmpathyChat **chat;
+      EmpathyChatWindow *old_window = NULL;
+
+      DEBUG ("DND tab");
+
+      chat = (void *) gtk_selection_data_get_data (selection);
+      old_window = chat_window_find_chat (*chat);
+
+      if (old_window)
+        {
+          self->priv->dnd_same_window = (old_window == self);
+
+          DEBUG ("DND tab (within same window: %s)",
+            self->priv->dnd_same_window ? "Yes" : "No");
+        }
+    }
+  else
+    {
+      DEBUG ("DND from unknown source");
+      gtk_drag_finish (context, FALSE, FALSE, time_);
+    }
 }
 
 static void
 chat_window_chat_manager_chats_changed_cb (EmpathyChatManager *chat_manager,
-                                          guint num_chats_in_manager,
-                                          EmpathyChatWindow *window)
+    guint num_chats_in_manager,
+    EmpathyChatWindow *self)
 {
-       EmpathyChatWindowPriv *priv = GET_PRIV (window);
-
-       gtk_action_set_sensitive (priv->menu_tabs_undo_close_tab,
-                                 num_chats_in_manager > 0);
+  gtk_action_set_sensitive (self->priv->menu_tabs_undo_close_tab,
+      num_chats_in_manager > 0);
 }
 
 static void
 chat_window_finalize (GObject *object)
 {
-       EmpathyChatWindow     *window;
-       EmpathyChatWindowPriv *priv;
+  EmpathyChatWindow *self = EMPATHY_CHAT_WINDOW (object);
 
-       window = EMPATHY_CHAT_WINDOW (object);
-       priv = GET_PRIV (window);
+  DEBUG ("Finalized: %p", object);
 
-       DEBUG ("Finalized: %p", object);
+  g_object_unref (self->priv->ui_manager);
+  g_object_unref (self->priv->chatroom_manager);
+  g_object_unref (self->priv->notify_mgr);
+  g_object_unref (self->priv->gsettings_chat);
+  g_object_unref (self->priv->gsettings_notif);
+  g_object_unref (self->priv->gsettings_ui);
+  g_object_unref (self->priv->sound_mgr);
+  g_clear_object (&self->priv->individual_mgr);
 
-       g_object_unref (priv->ui_manager);
-       g_object_unref (priv->chatroom_manager);
-       g_object_unref (priv->notify_mgr);
-       g_object_unref (priv->gsettings_chat);
-       g_object_unref (priv->gsettings_notif);
-       g_object_unref (priv->gsettings_ui);
-       g_object_unref (priv->sound_mgr);
+  if (self->priv->notification != NULL)
+    {
+      notify_notification_close (self->priv->notification, NULL);
+      self->priv->notification = NULL;
+    }
 
-       if (priv->notification != NULL) {
-               notify_notification_close (priv->notification, NULL);
-               priv->notification = NULL;
-       }
+  if (self->priv->contact_targets)
+    gtk_target_list_unref (self->priv->contact_targets);
 
-       if (priv->contact_targets) {
-               gtk_target_list_unref (priv->contact_targets);
-       }
-       if (priv->file_targets) {
-               gtk_target_list_unref (priv->file_targets);
-       }
+  if (self->priv->file_targets)
+    gtk_target_list_unref (self->priv->file_targets);
 
-       if (priv->chat_manager) {
-               g_signal_handler_disconnect (priv->chat_manager,
-                                            priv->chat_manager_chats_changed_id);
-               g_object_unref (priv->chat_manager);
-               priv->chat_manager = NULL;
-       }
+  if (self->priv->chat_manager)
+    {
+      g_signal_handler_disconnect (self->priv->chat_manager,
+                 self->priv->chat_manager_chats_changed_id);
+      g_object_unref (self->priv->chat_manager);
+      self->priv->chat_manager = NULL;
+    }
 
-       chat_windows = g_list_remove (chat_windows, window);
-       gtk_widget_destroy (priv->dialog);
+  chat_windows = g_list_remove (chat_windows, self);
 
-       G_OBJECT_CLASS (empathy_chat_window_parent_class)->finalize (object);
+  G_OBJECT_CLASS (empathy_chat_window_parent_class)->finalize (object);
 }
 
 static void
-empathy_chat_window_class_init (EmpathyChatWindowClass *klass)
+chat_window_get_property (GObject *object,
+    guint property_id,
+    GValue *value,
+    GParamSpec *pspec)
 {
-       GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
-       object_class->finalize = chat_window_finalize;
-
-       g_type_class_add_private (object_class, sizeof (EmpathyChatWindowPriv));
-}
-
-static void
-empathy_chat_window_init (EmpathyChatWindow *window)
-{
-       GtkBuilder            *gui;
-       GtkAccelGroup         *accel_group;
-       GClosure              *closure;
-       GtkWidget             *menu;
-       GtkWidget             *submenu;
-       guint                  i;
-       GtkWidget             *chat_vbox;
-       gchar                 *filename;
-       EmpathySmileyManager  *smiley_manager;
-       EmpathyChatWindowPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (window,
-               EMPATHY_TYPE_CHAT_WINDOW, EmpathyChatWindowPriv);
-
-       window->priv = priv;
-       filename = empathy_file_lookup ("empathy-chat-window.ui", "src");
-       gui = empathy_builder_get_file (filename,
-                                      "chat_window", &priv->dialog,
-                                      "chat_vbox", &chat_vbox,
-                                      "ui_manager", &priv->ui_manager,
-                                      "menu_conv_insert_smiley", &priv->menu_conv_insert_smiley,
-                                      "menu_conv_favorite", &priv->menu_conv_favorite,
-                                      "menu_conv_always_urgent", &priv->menu_conv_always_urgent,
-                                      "menu_conv_toggle_contacts", &priv->menu_conv_toggle_contacts,
-                                      "menu_edit_cut", &priv->menu_edit_cut,
-                                      "menu_edit_copy", &priv->menu_edit_copy,
-                                      "menu_edit_paste", &priv->menu_edit_paste,
-                                      "menu_edit_find", &priv->menu_edit_find,
-                                      "menu_tabs_next", &priv->menu_tabs_next,
-                                      "menu_tabs_prev", &priv->menu_tabs_prev,
-                                      "menu_tabs_undo_close_tab", &priv->menu_tabs_undo_close_tab,
-                                      "menu_tabs_left", &priv->menu_tabs_left,
-                                      "menu_tabs_right", &priv->menu_tabs_right,
-                                      "menu_tabs_detach", &priv->menu_tabs_detach,
-                                      NULL);
-       g_free (filename);
-
-       empathy_builder_connect (gui, window,
-                             "menu_conv", "activate", chat_window_conv_activate_cb,
-                             "menu_conv_clear", "activate", chat_window_clear_activate_cb,
-                             "menu_conv_favorite", "toggled", chat_window_favorite_toggled_cb,
-                             "menu_conv_always_urgent", "toggled", chat_window_always_urgent_toggled_cb,
-                             "menu_conv_toggle_contacts", "toggled", chat_window_contacts_toggled_cb,
-                             "menu_conv_invite_participant", "activate", chat_window_invite_participant_activate_cb,
-                             "menu_conv_close", "activate", chat_window_close_activate_cb,
-                             "menu_edit", "activate", chat_window_edit_activate_cb,
-                             "menu_edit_cut", "activate", chat_window_cut_activate_cb,
-                             "menu_edit_copy", "activate", chat_window_copy_activate_cb,
-                             "menu_edit_paste", "activate", chat_window_paste_activate_cb,
-                             "menu_edit_find", "activate", chat_window_find_activate_cb,
-                             "menu_tabs_next", "activate", chat_window_tabs_next_activate_cb,
-                             "menu_tabs_prev", "activate", chat_window_tabs_previous_activate_cb,
-                             "menu_tabs_undo_close_tab", "activate", chat_window_tabs_undo_close_tab_activate_cb,
-                             "menu_tabs_left", "activate", chat_window_tabs_left_activate_cb,
-                             "menu_tabs_right", "activate", chat_window_tabs_right_activate_cb,
-                             "menu_tabs_detach", "activate", chat_window_detach_activate_cb,
-                             "menu_help_contents", "activate", chat_window_help_contents_activate_cb,
-                             "menu_help_about", "activate", chat_window_help_about_activate_cb,
-                             NULL);
-
-       g_object_ref (priv->ui_manager);
-       g_object_unref (gui);
-
-       priv->gsettings_chat = g_settings_new (EMPATHY_PREFS_CHAT_SCHEMA);
-       priv->gsettings_notif = g_settings_new (EMPATHY_PREFS_NOTIFICATIONS_SCHEMA);
-       priv->gsettings_ui = g_settings_new (EMPATHY_PREFS_UI_SCHEMA);
-       priv->chatroom_manager = empathy_chatroom_manager_dup_singleton (NULL);
-
-       priv->sound_mgr = empathy_sound_manager_dup_singleton ();
-
-       priv->notebook = gtk_notebook_new ();
-
-       g_signal_connect (priv->notebook, "create-window",
-               G_CALLBACK (notebook_create_window_cb), window);
-
-       gtk_notebook_set_group_name (GTK_NOTEBOOK (priv->notebook),
-               "EmpathyChatWindow");
-       gtk_notebook_set_scrollable (GTK_NOTEBOOK (priv->notebook), TRUE);
-       gtk_notebook_popup_enable (GTK_NOTEBOOK (priv->notebook));
-       gtk_box_pack_start (GTK_BOX (chat_vbox), priv->notebook, TRUE, TRUE, 0);
-       gtk_widget_show (priv->notebook);
-
-       /* Set up accels */
-       accel_group = gtk_accel_group_new ();
-       gtk_window_add_accel_group (GTK_WINDOW (priv->dialog), accel_group);
-
-       for (i = 0; i < G_N_ELEMENTS (tab_accel_keys); i++) {
-               closure =  g_cclosure_new (G_CALLBACK (chat_window_accel_cb),
-                                          window,
-                                          NULL);
-               gtk_accel_group_connect (accel_group,
-                                        tab_accel_keys[i],
-                                        GDK_MOD1_MASK,
-                                        0,
-                                        closure);
-       }
-
-       g_object_unref (accel_group);
-
-       /* Set up drag target lists */
-       priv->contact_targets = gtk_target_list_new (drag_types_dest_contact,
-                                                    G_N_ELEMENTS (drag_types_dest_contact));
-       priv->file_targets = gtk_target_list_new (drag_types_dest_file,
-                                                 G_N_ELEMENTS (drag_types_dest_file));
-
-       /* Set up smiley menu */
-       smiley_manager = empathy_smiley_manager_dup_singleton ();
-       submenu = empathy_smiley_menu_new (smiley_manager,
-                                          chat_window_insert_smiley_activate_cb,
-                                          window);
-       menu = gtk_ui_manager_get_widget (priv->ui_manager,
-               "/chats_menubar/menu_conv/menu_conv_insert_smiley");
-       gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu), submenu);
-       g_object_unref (smiley_manager);
-
-       /* Set up signals we can't do with ui file since we may need to
-        * block/unblock them at some later stage.
-        */
-
-       g_signal_connect (priv->dialog,
-                         "delete_event",
-                         G_CALLBACK (chat_window_delete_event_cb),
-                         window);
-       g_signal_connect (priv->dialog,
-                         "focus_in_event",
-                         G_CALLBACK (chat_window_focus_in_event_cb),
-                         window);
-       g_signal_connect_after (priv->notebook,
-                               "switch_page",
-                               G_CALLBACK (chat_window_page_switched_cb),
-                               window);
-       g_signal_connect (priv->notebook,
-                         "page_added",
-                         G_CALLBACK (chat_window_page_added_cb),
-                         window);
-       g_signal_connect (priv->notebook,
-                         "page_removed",
-                         G_CALLBACK (chat_window_page_removed_cb),
-                         window);
-
-       /* Set up drag and drop */
-       gtk_drag_dest_set (GTK_WIDGET (priv->notebook),
-                          GTK_DEST_DEFAULT_HIGHLIGHT,
-                          drag_types_dest,
-                          G_N_ELEMENTS (drag_types_dest),
-                          GDK_ACTION_MOVE | GDK_ACTION_COPY);
-
-       /* connect_after to allow GtkNotebook's built-in tab switching */
-       g_signal_connect_after (priv->notebook,
-                               "drag-motion",
-                               G_CALLBACK (chat_window_drag_motion),
-                               window);
-       g_signal_connect (priv->notebook,
-                         "drag-data-received",
-                         G_CALLBACK (chat_window_drag_data_received),
-                         window);
-       g_signal_connect (priv->notebook,
-                         "drag-drop",
-                         G_CALLBACK (chat_window_drag_drop),
-                         window);
-
-       chat_windows = g_list_prepend (chat_windows, window);
-
-       /* Set up private details */
-       priv->chats = NULL;
-       priv->current_chat = NULL;
-       priv->notification = NULL;
-
-       priv->notify_mgr = empathy_notify_manager_dup_singleton ();
-
-       priv->chat_manager = empathy_chat_manager_dup_singleton ();
-       priv->chat_manager_chats_changed_id =
-               g_signal_connect (priv->chat_manager, "closed-chats-changed",
-                                 G_CALLBACK (chat_window_chat_manager_chats_changed_cb),
-                                 window);
-
-       chat_window_chat_manager_chats_changed_cb (priv->chat_manager,
-                                                  empathy_chat_manager_get_num_closed_chats (priv->chat_manager),
-                                                  window);
+  EmpathyChatWindow *self = EMPATHY_CHAT_WINDOW (object);
+
+  switch (property_id)
+    {
+      case PROP_INDIVIDUAL_MGR:
+        g_value_set_object (value, self->priv->individual_mgr);
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+        break;
+    }
 }
 
-/* Returns the window to open a new tab in if there is a suitable window,
- * otherwise, returns NULL indicating that a new window should be added.
- */
-static EmpathyChatWindow *
-empathy_chat_window_get_default (gboolean room)
+static void
+empathy_chat_window_class_init (EmpathyChatWindowClass *klass)
 {
-       GSettings *gsettings = g_settings_new (EMPATHY_PREFS_UI_SCHEMA);
-       GList    *l;
-       gboolean  separate_windows = TRUE;
-
-       separate_windows = g_settings_get_boolean (gsettings,
-                       EMPATHY_PREFS_UI_SEPARATE_CHAT_WINDOWS);
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GParamSpec *spec;
 
-       g_object_unref (gsettings);
+  object_class->get_property = chat_window_get_property;
+  object_class->finalize = chat_window_finalize;
 
-       if (separate_windows) {
-               /* Always create a new window */
-               return NULL;
-       }
+  spec = g_param_spec_object ("individual-manager", "individual-manager",
+      "EmpathyIndividualManager",
+      EMPATHY_TYPE_INDIVIDUAL_MANAGER,
+      G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+  g_object_class_install_property (object_class, PROP_INDIVIDUAL_MGR, spec);
 
-       for (l = chat_windows; l; l = l->next) {
-               EmpathyChatWindow *chat_window;
-               guint nb_rooms, nb_private;
-
-               chat_window = l->data;
-
-               empathy_chat_window_get_nb_chats (chat_window, &nb_rooms, &nb_private);
+  g_type_class_add_private (object_class, sizeof (EmpathyChatWindowPriv));
+}
 
-               /* Skip the window if there aren't any rooms in it */
-               if (room && nb_rooms == 0)
-                       continue;
+static void
+chat_window_chat_new_message_cb (GSimpleAction *action,
+    GVariant *parameter,
+    gpointer user_data)
+{
+  EmpathyChatWindow *self = user_data;
 
-               /* Skip the window if there aren't any 1-1 chats in it */
-               if (!room && nb_private == 0)
-                       continue;
+  //empathy_new_message_dialog_show (GTK_WINDOW (self));
+}
 
-               return chat_window;
-       }
 
-       return NULL;
+static void
+empathy_chat_window_init (EmpathyChatWindow *self)
+{
+  GtkBuilder *gui;
+  GtkAccelGroup *accel_group;
+  GClosure *closure;
+  GtkWidget *menu;
+  GtkWidget *submenu;
+  guint i;
+  GtkWidget *chat_vbox;
+  GtkWidget *main_box;
+  gchar *filename;
+  EmpathySmileyManager *smiley_manager;
+
+  self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+    EMPATHY_TYPE_CHAT_WINDOW, EmpathyChatWindowPriv);
+
+  filename = empathy_file_lookup ("empathy-chat-window.ui", "src");
+  gui = tpaw_builder_get_file (filename,
+      "chat_vbox", &chat_vbox,
+      "main_box", &main_box,
+      "ui_manager", &self->priv->ui_manager,
+      "menu_conv_insert_smiley", &self->priv->menu_conv_insert_smiley,
+      "menu_conv_favorite", &self->priv->menu_conv_favorite,
+      "menu_conv_join_chat", &self->priv->menu_conv_join_chat,
+      "menu_conv_leave_chat", &self->priv->menu_conv_leave_chat,
+      "menu_conv_always_urgent", &self->priv->menu_conv_always_urgent,
+      "menu_conv_toggle_contacts", &self->priv->menu_conv_toggle_contacts,
+      "menu_edit_cut", &self->priv->menu_edit_cut,
+      "menu_edit_copy", &self->priv->menu_edit_copy,
+      "menu_edit_paste", &self->priv->menu_edit_paste,
+      "menu_edit_find", &self->priv->menu_edit_find,
+      "menu_tabs_next", &self->priv->menu_tabs_next,
+      "menu_tabs_prev", &self->priv->menu_tabs_prev,
+      "menu_tabs_undo_close_tab", &self->priv->menu_tabs_undo_close_tab,
+      "menu_tabs_left", &self->priv->menu_tabs_left,
+      "menu_tabs_right", &self->priv->menu_tabs_right,
+       "menu_tabs_detach", &self->priv->menu_tabs_detach,
+      NULL);
+  g_free (filename);
+
+  tpaw_builder_connect (gui, self,
+      "menu_conv", "activate", chat_window_conv_activate_cb,
+      "menu_conv_clear", "activate", chat_window_clear_activate_cb,
+      "menu_conv_favorite", "toggled", chat_window_favorite_toggled_cb,
+      "menu_conv_always_urgent", "toggled", chat_window_always_urgent_toggled_cb,
+      "menu_conv_toggle_contacts", "toggled", chat_window_contacts_toggled_cb,
+      "menu_conv_invite_participant", "activate", chat_window_invite_participant_activate_cb,
+      "menu_conv_join_chat", "activate", chat_window_join_chat_activate_cb,
+      "menu_conv_leave_chat", "activate", chat_window_leave_chat_activate_cb,
+      "menu_conv_close", "activate", chat_window_close_activate_cb,
+      "menu_edit", "activate", chat_window_edit_activate_cb,
+      "menu_edit_cut", "activate", chat_window_cut_activate_cb,
+      "menu_edit_copy", "activate", chat_window_copy_activate_cb,
+      "menu_edit_paste", "activate", chat_window_paste_activate_cb,
+      "menu_edit_find", "activate", chat_window_find_activate_cb,
+      "menu_tabs_next", "activate", chat_window_tabs_next_activate_cb,
+      "menu_tabs_prev", "activate", chat_window_tabs_previous_activate_cb,
+      "menu_tabs_undo_close_tab", "activate", chat_window_tabs_undo_close_tab_activate_cb,
+      "menu_tabs_left", "activate", chat_window_tabs_left_activate_cb,
+      "menu_tabs_right", "activate", chat_window_tabs_right_activate_cb,
+      "menu_tabs_detach", "activate", chat_window_detach_activate_cb,
+      "menu_help_contents", "activate", chat_window_help_contents_activate_cb,
+      "menu_help_about", "activate", chat_window_help_about_activate_cb,
+      NULL);
+
+  empathy_set_css_provider (GTK_WIDGET (self));
+
+  self->priv->gsettings_chat = g_settings_new (EMPATHY_PREFS_CHAT_SCHEMA);
+  self->priv->gsettings_notif = g_settings_new (EMPATHY_PREFS_NOTIFICATIONS_SCHEMA);
+  self->priv->gsettings_ui = g_settings_new (EMPATHY_PREFS_UI_SCHEMA);
+  self->priv->chatroom_manager = empathy_chatroom_manager_dup_singleton (NULL);
+
+  self->priv->sound_mgr = empathy_sound_manager_dup_singleton ();
+
+  self->priv->notebook = gtk_notebook_new ();
+  //gtk_notebook_set_show_tabs (GTK_NOTEBOOK (self->priv->notebook), FALSE);
+
+  g_signal_connect (self->priv->notebook, "create-window",
+      G_CALLBACK (notebook_create_window_cb), self);
+
+  gtk_container_add (GTK_CONTAINER (self), main_box);
+
+  gtk_notebook_set_group_name (GTK_NOTEBOOK (self->priv->notebook),
+    "EmpathyChatWindow");
+  gtk_notebook_set_scrollable (GTK_NOTEBOOK (self->priv->notebook), TRUE);
+  gtk_notebook_popup_enable (GTK_NOTEBOOK (self->priv->notebook));
+  gtk_box_pack_start (GTK_BOX (chat_vbox), self->priv->notebook, TRUE, TRUE, 0);
+  gtk_widget_show (self->priv->notebook);
+
+#if 0 /* no top level window yet at this point */
+  /* Set up accels */
+  accel_group = gtk_accel_group_new ();
+  gtk_window_add_accel_group (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (self))), accel_group);
+
+  for (i = 0; i < G_N_ELEMENTS (tab_accel_keys); i++)
+    {
+      closure = g_cclosure_new (G_CALLBACK (chat_window_accel_cb), self,
+          NULL);
+
+      gtk_accel_group_connect (accel_group, tab_accel_keys[i], GDK_MOD1_MASK, 0,
+          closure);
+    }
+
+  g_object_unref (accel_group);
+#endif
+
+  /* Set up drag target lists */
+  self->priv->contact_targets = gtk_target_list_new (drag_types_dest_contact,
+      G_N_ELEMENTS (drag_types_dest_contact));
+
+  self->priv->file_targets = gtk_target_list_new (drag_types_dest_file,
+      G_N_ELEMENTS (drag_types_dest_file));
+
+  /* Set up smiley menu */
+  smiley_manager = empathy_smiley_manager_dup_singleton ();
+  submenu = empathy_smiley_menu_new (smiley_manager,
+      chat_window_insert_smiley_activate_cb, self);
+
+  menu = gtk_ui_manager_get_widget (self->priv->ui_manager,
+    "/chats_menubar/menu_conv/menu_conv_insert_smiley");
+  gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu), submenu);
+  g_object_unref (smiley_manager);
+
+  /* Set up signals we can't do with ui file since we may need to
+   * block/unblock them at some later stage.
+   */
+
+  g_signal_connect (self, "delete_event",
+      G_CALLBACK (chat_window_delete_event_cb), self);
+  g_signal_connect (self, "focus_in_event",
+      G_CALLBACK (chat_window_focus_in_event_cb), self);
+  g_signal_connect (self, "focus_out_event",
+      G_CALLBACK (chat_window_focus_out_event_cb), self);
+  g_signal_connect_after (self->priv->notebook, "switch_page",
+      G_CALLBACK (chat_window_page_switched_cb), self);
+  g_signal_connect (self->priv->notebook, "page_added",
+      G_CALLBACK (chat_window_page_added_cb), self);
+  g_signal_connect (self->priv->notebook, "page_removed",
+      G_CALLBACK (chat_window_page_removed_cb), self);
+
+  /* Set up drag and drop */
+  gtk_drag_dest_set (GTK_WIDGET (self->priv->notebook),
+      GTK_DEST_DEFAULT_HIGHLIGHT,
+      drag_types_dest,
+      G_N_ELEMENTS (drag_types_dest),
+      GDK_ACTION_MOVE | GDK_ACTION_COPY);
+
+  /* connect_after to allow GtkNotebook's built-in tab switching */
+  g_signal_connect_after (self->priv->notebook, "drag-motion",
+      G_CALLBACK (chat_window_drag_motion), self);
+  g_signal_connect (self->priv->notebook, "drag-data-received",
+      G_CALLBACK (chat_window_drag_data_received), self);
+  g_signal_connect (self->priv->notebook, "drag-drop",
+      G_CALLBACK (chat_window_drag_drop), self);
+
+  chat_windows = g_list_prepend (chat_windows, self);
+
+  /* Set up private details */
+  self->priv->chats = NULL;
+  self->priv->current_chat = NULL;
+  self->priv->notification = NULL;
+
+  self->priv->notify_mgr = empathy_notify_manager_dup_singleton ();
+
+  self->priv->chat_manager = empathy_chat_manager_dup_singleton ();
+  self->priv->chat_manager_chats_changed_id = g_signal_connect (
+      self->priv->chat_manager, "closed-chats-changed",
+      G_CALLBACK (chat_window_chat_manager_chats_changed_cb), self);
+
+  chat_window_chat_manager_chats_changed_cb (self->priv->chat_manager,
+      empathy_chat_manager_get_num_closed_chats (self->priv->chat_manager), self);
+
+  g_object_ref (self->priv->ui_manager);
+  g_object_unref (gui);
 }
 
-static void
-empathy_chat_window_add_chat (EmpathyChatWindow *window,
-                             EmpathyChat       *chat)
+/* Returns the window to open a new tab in if there is a suitable window,
+ * otherwise, returns NULL indicating that a new window should be added.
+ */
+static EmpathyChatWindow *
+empathy_chat_window_get_default (gboolean room)
 {
-       EmpathyChatWindowPriv *priv;
-       GtkWidget             *label;
-       GtkWidget             *popup_label;
-       GtkWidget             *child;
-       GValue                value = { 0, };
+  GSettings *gsettings = g_settings_new (EMPATHY_PREFS_UI_SCHEMA);
+  GList *l;
+  gboolean separate_windows = TRUE;
 
-       g_return_if_fail (window != NULL);
-       g_return_if_fail (EMPATHY_IS_CHAT (chat));
+  separate_windows = g_settings_get_boolean (gsettings,
+      EMPATHY_PREFS_UI_SEPARATE_CHAT_WINDOWS);
+  separate_windows = FALSE;
 
-       priv = GET_PRIV (window);
+  g_object_unref (gsettings);
 
-       /* Reference the chat object */
-       g_object_ref (chat);
+  if (separate_windows)
+    /* Always create a new window */
+    return NULL;
 
-       /* If this window has just been created, position it */
-       if (priv->chats == NULL) {
-               const gchar *name = "chat-window";
-               gboolean     separate_windows;
+  for (l = chat_windows; l; l = l->next)
+    {
+      EmpathyChatWindow *chat_window;
+      guint nb_rooms, nb_private;
 
-               separate_windows = g_settings_get_boolean (priv->gsettings_ui,
-                               EMPATHY_PREFS_UI_SEPARATE_CHAT_WINDOWS);
+      chat_window = l->data;
 
-               if (empathy_chat_is_room (chat))
-                       name = "room-window";
+#if 0
+      empathy_chat_window_get_nb_chats (chat_window, &nb_rooms, &nb_private);
 
-               if (separate_windows) {
-                       gint x, y;
+      /* Skip the window if there aren't any rooms in it */
+      if (room && nb_rooms == 0)
+        continue;
 
-                       /* Save current position of the window */
-                       gtk_window_get_position (GTK_WINDOW (priv->dialog), &x, &y);
+      /* Skip the window if there aren't any 1-1 chats in it */
+      if (!room && nb_private == 0)
+        continue;
+#endif
 
-                       /* First bind to the 'generic' name. So new window for which we didn't
-                       * save a geometry yet will have the geometry of the last saved
-                       * window (bgo #601191). */
-                       empathy_geometry_bind (GTK_WINDOW (priv->dialog), name);
+      return chat_window;
+    }
 
-                       /* Restore previous position of the window so the newly created window
-                       * won't be in the same position as the latest saved window and so
-                       * completely hide it. */
-                       gtk_window_move (GTK_WINDOW (priv->dialog), x, y);
+  return NULL;
+}
 
-                       /* Then bind it to the name of the contact/room so we'll save the
-                       * geometry specific to this window */
-                       name = empathy_chat_get_id (chat);
-               }
+static void
+empathy_chat_window_add_chat (EmpathyChatWindow *self,
+    EmpathyChat *chat)
+{
+  GtkWidget *label;
+  GtkWidget *popup_label;
+  GtkWidget *child;
+  GValue value = { 0, };
+
+  g_return_if_fail (self != NULL);
+  g_return_if_fail (EMPATHY_IS_CHAT (chat));
+
+  /* Reference the chat object */
+  g_object_ref (chat);
+
+  /* If this window has just been created, position it */
+  if (self->priv->chats == NULL)
+    {
+      const gchar *name = "chat-window";
+      gboolean separate_windows;
+
+      separate_windows = g_settings_get_boolean (self->priv->gsettings_ui,
+          EMPATHY_PREFS_UI_SEPARATE_CHAT_WINDOWS);
+          separate_windows = FALSE;
+
+      if (empathy_chat_is_room (chat))
+        name = "room-window";
+
+      if (separate_windows)
+        {
+          gint x, y;
+
+          /* Save current position of the window */
+          //gtk_window_get_position (GTK_WINDOW (self), &x, &y);
+
+          /* First bind to the 'generic' name. So new window for which we didn't
+          * save a geometry yet will have the geometry of the last saved
+          * window (bgo #601191). */
+          //empathy_geometry_bind (GTK_WINDOW (self), name);
+
+          /* Restore previous position of the window so the newly created window
+          * won't be in the same position as the latest saved window and so
+          * completely hide it. */
+          //gtk_window_move (GTK_WINDOW (self), x, y);
+
+          /* Then bind it to the name of the contact/room so we'll save the
+          * geometry specific to this window */
+          name = empathy_chat_get_id (chat);
+        }
+
+      //empathy_geometry_bind (GTK_WINDOW (self), name);
+    }
+
+  child = GTK_WIDGET (chat);
+  label = chat_window_create_label (self, chat, TRUE);
+  popup_label = chat_window_create_label (self, chat, FALSE);
+  gtk_widget_show (child);
+
+  g_signal_connect (chat, "notify::name",
+      G_CALLBACK (chat_window_chat_notify_cb), NULL);
+  g_signal_connect (chat, "notify::subject",
+      G_CALLBACK (chat_window_chat_notify_cb), NULL);
+  g_signal_connect (chat, "notify::remote-contact",
+      G_CALLBACK (chat_window_chat_notify_cb), NULL);
+  g_signal_connect (chat, "notify::sms-channel",
+      G_CALLBACK (chat_window_chat_notify_cb), NULL);
+  g_signal_connect (chat, "notify::n-messages-sending",
+      G_CALLBACK (chat_window_chat_notify_cb), NULL);
+  g_signal_connect (chat, "notify::nb-unread-messages",
+      G_CALLBACK (chat_window_chat_notify_cb), NULL);
+  chat_window_chat_notify_cb (chat);
+
+  gtk_notebook_append_page_menu (GTK_NOTEBOOK (self->priv->notebook), child, label,
+      popup_label);
+  gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (self->priv->notebook), child, TRUE);
+  gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (self->priv->notebook), child, TRUE);
+  g_value_init (&value, G_TYPE_BOOLEAN);
+  g_value_set_boolean (&value, TRUE);
+  gtk_container_child_set_property (GTK_CONTAINER (self->priv->notebook),
+      child, "tab-expand" , &value);
+  gtk_container_child_set_property (GTK_CONTAINER (self->priv->notebook),
+      child,  "tab-fill" , &value);
+  g_value_unset (&value);
+
+  DEBUG ("Chat added (%d references)", G_OBJECT (chat)->ref_count);
+}
 
-               empathy_geometry_bind (GTK_WINDOW (priv->dialog), name);
-       }
+static void
+empathy_chat_window_remove_chat (EmpathyChatWindow *self,
+    EmpathyChat *chat)
+{
+  gint position;
+  EmpathyContact *remote_contact;
+  EmpathyChatManager *chat_manager;
 
-       child = GTK_WIDGET (chat);
-       label = chat_window_create_label (window, chat, TRUE);
-       popup_label = chat_window_create_label (window, chat, FALSE);
-       gtk_widget_show (child);
+  g_return_if_fail (self != NULL);
+  g_return_if_fail (EMPATHY_IS_CHAT (chat));
 
-       g_signal_connect (chat, "notify::name",
-                         G_CALLBACK (chat_window_chat_notify_cb),
-                         NULL);
-       g_signal_connect (chat, "notify::subject",
-                         G_CALLBACK (chat_window_chat_notify_cb),
-                         NULL);
-       g_signal_connect (chat, "notify::remote-contact",
-                         G_CALLBACK (chat_window_chat_notify_cb),
-                         NULL);
-       g_signal_connect (chat, "notify::sms-channel",
-                         G_CALLBACK (chat_window_chat_notify_cb),
-                         NULL);
-       g_signal_connect (chat, "notify::n-messages-sending",
-                         G_CALLBACK (chat_window_chat_notify_cb),
-                         NULL);
-       g_signal_connect (chat, "notify::nb-unread-messages",
-                         G_CALLBACK (chat_window_chat_notify_cb),
-                         NULL);
-       chat_window_chat_notify_cb (chat);
+  g_signal_handlers_disconnect_by_func (chat,
+      chat_window_chat_notify_cb, NULL);
 
-       gtk_notebook_append_page_menu (GTK_NOTEBOOK (priv->notebook), child, label, popup_label);
-       gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (priv->notebook), child, TRUE);
-       gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (priv->notebook), child, TRUE);
-       g_value_init (&value, G_TYPE_BOOLEAN);
-       g_value_set_boolean (&value, TRUE);
-       gtk_container_child_set_property (GTK_CONTAINER (priv->notebook),
-                                         child, "tab-expand" , &value);
-       gtk_container_child_set_property (GTK_CONTAINER (priv->notebook),
-                                         child,  "tab-fill" , &value);
-       g_value_unset (&value);
+  remote_contact = g_object_get_data (G_OBJECT (chat),
+      "chat-window-remote-contact");
 
-       DEBUG ("Chat added (%d references)", G_OBJECT (chat)->ref_count);
-}
+  if (remote_contact)
+    {
+      g_signal_handlers_disconnect_by_func (remote_contact,
+          chat_window_update_chat_tab, chat);
+    }
 
-static void
-empathy_chat_window_remove_chat (EmpathyChatWindow *window,
-                                EmpathyChat       *chat)
-{
-       EmpathyChatWindowPriv *priv;
-       gint                   position;
-       EmpathyContact        *remote_contact;
-       EmpathyChatManager    *chat_manager;
+  chat_manager = empathy_chat_manager_dup_singleton ();
+  empathy_chat_manager_closed_chat (chat_manager, chat);
+  g_object_unref (chat_manager);
+
+  position = gtk_notebook_page_num (GTK_NOTEBOOK (self->priv->notebook),
+      GTK_WIDGET (chat));
+  gtk_notebook_remove_page (GTK_NOTEBOOK (self->priv->notebook), position);
+
+  DEBUG ("Chat removed (%d references)", G_OBJECT (chat)->ref_count - 1);
 
-       g_return_if_fail (window != NULL);
-       g_return_if_fail (EMPATHY_IS_CHAT (chat));
-
-       priv = GET_PRIV (window);
-
-       g_signal_handlers_disconnect_by_func (chat,
-                                             chat_window_chat_notify_cb,
-                                             NULL);
-       remote_contact = g_object_get_data (G_OBJECT (chat),
-                                           "chat-window-remote-contact");
-       if (remote_contact) {
-               g_signal_handlers_disconnect_by_func (remote_contact,
-                                                     chat_window_update_chat_tab,
-                                                     chat);
-       }
-
-       chat_manager = empathy_chat_manager_dup_singleton ();
-       empathy_chat_manager_closed_chat (chat_manager, chat);
-       g_object_unref (chat_manager);
-
-       position = gtk_notebook_page_num (GTK_NOTEBOOK (priv->notebook),
-                                         GTK_WIDGET (chat));
-       gtk_notebook_remove_page (GTK_NOTEBOOK (priv->notebook), position);
-
-       DEBUG ("Chat removed (%d references)", G_OBJECT (chat)->ref_count - 1);
-
-       g_object_unref (chat);
+  g_object_unref (chat);
 }
 
 static void
 empathy_chat_window_move_chat (EmpathyChatWindow *old_window,
-                              EmpathyChatWindow *new_window,
-                              EmpathyChat       *chat)
+    EmpathyChatWindow *new_window,
+    EmpathyChat *chat)
 {
-       GtkWidget *widget;
+  GtkWidget *widget;
 
-       g_return_if_fail (EMPATHY_IS_CHAT_WINDOW (old_window));
-       g_return_if_fail (EMPATHY_IS_CHAT_WINDOW (new_window));
-       g_return_if_fail (EMPATHY_IS_CHAT (chat));
+  g_return_if_fail (EMPATHY_IS_CHAT_WINDOW (old_window));
+  g_return_if_fail (EMPATHY_IS_CHAT_WINDOW (new_window));
+  g_return_if_fail (EMPATHY_IS_CHAT (chat));
 
-       widget = GTK_WIDGET (chat);
+  widget = GTK_WIDGET (chat);
 
-       DEBUG ("Chat moving with widget:%p (%d references)", widget,
-               G_OBJECT (widget)->ref_count);
+  DEBUG ("Chat moving with widget:%p (%d references)", widget,
+      G_OBJECT (widget)->ref_count);
 
-       /* We reference here to make sure we don't loose the widget
-        * and the EmpathyChat object during the move.
-        */
-       g_object_ref (chat);
-       g_object_ref (widget);
+  /* We reference here to make sure we don't loose the widget
+   * and the EmpathyChat object during the move.
+   */
+  g_object_ref (chat);
+  g_object_ref (widget);
 
-       empathy_chat_window_remove_chat (old_window, chat);
-       empathy_chat_window_add_chat (new_window, chat);
+  empathy_chat_window_remove_chat (old_window, chat);
+  empathy_chat_window_add_chat (new_window, chat);
 
-       g_object_unref (widget);
-       g_object_unref (chat);
+  g_object_unref (widget);
+  g_object_unref (chat);
 }
 
 static void
-empathy_chat_window_switch_to_chat (EmpathyChatWindow *window,
-                                   EmpathyChat       *chat)
+empathy_chat_window_switch_to_chat (EmpathyChatWindow *self,
+    EmpathyChat *chat)
 {
-       EmpathyChatWindowPriv *priv;
-       gint                  page_num;
+  gint page_num;
 
-       g_return_if_fail (window != NULL);
-       g_return_if_fail (EMPATHY_IS_CHAT (chat));
+  g_return_if_fail (self != NULL);
+  g_return_if_fail (EMPATHY_IS_CHAT (chat));
 
-       priv = GET_PRIV (window);
+  page_num = gtk_notebook_page_num (GTK_NOTEBOOK (self->priv->notebook),
+      GTK_WIDGET (chat));
 
-       page_num = gtk_notebook_page_num (GTK_NOTEBOOK (priv->notebook),
-                                         GTK_WIDGET (chat));
-       gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook),
-                                      page_num);
+  gtk_notebook_set_current_page (GTK_NOTEBOOK (self->priv->notebook),
+      page_num);
 }
 
 EmpathyChat *
-empathy_chat_window_find_chat (TpAccount   *account,
-                              const gchar *id,
-                              gboolean     sms_channel)
+empathy_chat_window_find_chat (TpAccount *account,
+    const gchar *id,
+    gboolean sms_channel)
 {
-       GList *l;
+  GList *l;
 
-       g_return_val_if_fail (!EMP_STR_EMPTY (id), NULL);
+  g_return_val_if_fail (!TPAW_STR_EMPTY (id), NULL);
 
-       for (l = chat_windows; l; l = l->next) {
-               EmpathyChatWindowPriv *priv;
-               EmpathyChatWindow     *window;
-               GList                *ll;
+  for (l = chat_windows; l; l = l->next)
+    {
+      EmpathyChatWindow *window = l->data;
+      GList *ll;
 
-               window = l->data;
-               priv = GET_PRIV (window);
+      for (ll = window->priv->chats; ll; ll = ll->next)
+        {
+          EmpathyChat *chat;
 
-               for (ll = priv->chats; ll; ll = ll->next) {
-                       EmpathyChat *chat;
+          chat = ll->data;
 
-                       chat = ll->data;
+          if (account == empathy_chat_get_account (chat) &&
+              !tp_strdiff (id, empathy_chat_get_id (chat)) &&
+              sms_channel == empathy_chat_is_sms_channel (chat))
+            return chat;
+        }
+    }
 
-                       if (account == empathy_chat_get_account (chat) &&
-                           !tp_strdiff (id, empathy_chat_get_id (chat)) &&
-                           sms_channel == empathy_chat_is_sms_channel (chat)) {
-                               return chat;
-                       }
-               }
-       }
-
-       return NULL;
+  return NULL;
 }
 
-void
+EmpathyChatWindow *
 empathy_chat_window_present_chat (EmpathyChat *chat,
-                                 gint64 timestamp)
+    gint64 timestamp)
 {
-       EmpathyChatWindow     *window;
-       EmpathyChatWindowPriv *priv;
-       guint32 x_timestamp;
+  EmpathyChatWindow *self;
+  guint32 x_timestamp;
 
-       g_return_if_fail (EMPATHY_IS_CHAT (chat));
+  if (chat == NULL) {
+    /* initial window */
+    self = empathy_chat_window_new ();
+    gtk_widget_show (GTK_WIDGET (self));
+    return self;
+  }
 
-       window = chat_window_find_chat (chat);
+  g_return_val_if_fail (EMPATHY_IS_CHAT (chat), NULL);
 
-       /* If the chat has no window, create one */
-       if (window == NULL) {
-               window = empathy_chat_window_get_default (empathy_chat_is_room (chat));
-               if (!window) {
-                       window = empathy_chat_window_new ();
+  self = chat_window_find_chat (chat);
 
-                       /* we want to display the newly created window even if we don't present
-                       * it */
-                       priv = GET_PRIV (window);
-                       gtk_widget_show (priv->dialog);
-               }
+  /* If the chat has no window, create one */
+  if (self == NULL)
+    {
+      self = empathy_chat_window_get_default (empathy_chat_is_room (chat));
+      if (!self)
+        {
+          self = empathy_chat_window_new ();
 
-               empathy_chat_window_add_chat (window, chat);
-       }
+          /* we want to display the newly created window even if we
+           * don't present it */
+          gtk_widget_show (GTK_WIDGET (self));
+        }
 
-       /* Don't force the window to show itself when it wasn't
-        * an action by the user
-        */
-       if (!tp_user_action_time_should_present (timestamp, &x_timestamp))
-               return;
+      empathy_chat_window_add_chat (self, chat);
+    }
 
-       priv = GET_PRIV (window);
+  /* Don't force the window to show itself when it wasn't
+   * an action by the user
+   */
+  if (!tp_user_action_time_should_present (timestamp, &x_timestamp))
+    return self;
 
-       if (x_timestamp != GDK_CURRENT_TIME) {
-               /* Don't present or switch tab if the action was earlier than the
-                * last actions X time, accounting for overflow and the first ever
-               * presentation */
+  if (x_timestamp != GDK_CURRENT_TIME)
+    {
+      /* Don't present or switch tab if the action was earlier than the
+       * last actions X time, accounting for overflow and the first ever
+      * presentation */
 
-               if (priv->x_user_action_time != 0
-                       && X_EARLIER_OR_EQL (x_timestamp, priv->x_user_action_time))
-                       return;
+      if (self->priv->x_user_action_time != 0
+        && X_EARLIER_OR_EQL (x_timestamp, self->priv->x_user_action_time))
+        return self;
 
-               priv->x_user_action_time = x_timestamp;
-       }
+      self->priv->x_user_action_time = x_timestamp;
+    }
 
-       empathy_chat_window_switch_to_chat (window, chat);
+  empathy_chat_window_switch_to_chat (self, chat);
 
-       /* Don't use empathy_window_present_with_time () which would move the window
-        * to our current desktop but move to the window's desktop instead. This is
-        * more coherent with Shell's 'app is ready' notication which moves the view
-        * to the app desktop rather than moving the app itself. */
-       empathy_move_to_window_desktop (GTK_WINDOW (priv->dialog), x_timestamp);
+  /* Don't use tpaw_window_present_with_time () which would move the window
+   * to our current desktop but move to the window's desktop instead. This is
+   * more coherent with Shell's 'app is ready' notication which moves the view
+   * to the app desktop rather than moving the app itself. */
+  empathy_move_to_window_desktop (GTK_WINDOW (gtk_widget_get_toplevel(GTK_WIDGET(self))), x_timestamp);
 
-       gtk_widget_grab_focus (chat->input_text_view);
+  gtk_widget_grab_focus (chat->input_text_view);
+  return self;
 }
 
 static void
 empathy_chat_window_get_nb_chats (EmpathyChatWindow *self,
-                              guint *nb_rooms,
-                              guint *nb_private)
-{
-       EmpathyChatWindowPriv *priv = GET_PRIV (self);
-       GList *l;
-       guint _nb_rooms = 0, _nb_private = 0;
-
-       for (l = priv->chats; l != NULL; l = g_list_next (l)) {
-               if (empathy_chat_is_room (EMPATHY_CHAT (l->data)))
-                       _nb_rooms++;
-               else
-                       _nb_private++;
-       }
-
-       if (nb_rooms != NULL)
-               *nb_rooms = _nb_rooms;
-       if (nb_private != NULL)
-               *nb_private = _nb_private;
+    guint *nb_rooms,
+    guint *nb_private)
+{
+  GList *l;
+  guint _nb_rooms = 0, _nb_private = 0;
+
+  for (l = self->priv->chats; l != NULL; l = g_list_next (l))
+    {
+      if (empathy_chat_is_room (EMPATHY_CHAT (l->data)))
+        _nb_rooms++;
+      else
+        _nb_private++;
+    }
+
+  if (nb_rooms != NULL)
+    *nb_rooms = _nb_rooms;
+  if (nb_private != NULL)
+    *nb_private = _nb_private;
+}
+
+EmpathyIndividualManager *
+empathy_chat_window_get_individual_manager (EmpathyChatWindow *self)
+{
+  return self->priv->individual_mgr;
 }