]> git.0d.be Git - empathy.git/blobdiff - src/empathy-chat-window.c
Don't warn before leaving disconnected chatrooms
[empathy.git] / src / empathy-chat-window.c
index 1eeba275640482abe61bee6c1ed2230af60c6fd2..634968593d9b6826a003bb17bbde695503e2184e 100644 (file)
@@ -1,7 +1,7 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
  * Copyright (C) 2003-2007 Imendio AB
- * Copyright (C) 2007-2008 Collabora Ltd.
+ * Copyright (C) 2007-2010 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
@@ -38,6 +38,7 @@
 
 #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>
@@ -45,6 +46,7 @@
 #include <libempathy/empathy-utils.h>
 #include <libempathy/empathy-tp-contact-factory.h>
 #include <libempathy/empathy-contact-list.h>
+#include <libempathy/empathy-request-util.h>
 
 #include <libempathy-gtk/empathy-images.h>
 #include <libempathy-gtk/empathy-contact-dialogs.h>
@@ -59,6 +61,7 @@
 #include "empathy-chat-window.h"
 #include "empathy-about-dialog.h"
 #include "empathy-invite-participant-dialog.h"
+#include "gedit-close-button.h"
 
 #define DEBUG_FLAG EMPATHY_DEBUG_CHAT
 #include <libempathy/empathy-debug.h>
@@ -74,8 +77,6 @@
 typedef struct {
        EmpathyChat *current_chat;
        GList       *chats;
-       GList       *chats_new_msg;
-       GList       *chats_composing;
        gboolean     page_added;
        gboolean     dnd_same_window;
        EmpathyChatroomManager *chatroom_manager;
@@ -150,7 +151,8 @@ static const GtkTargetEntry drag_types_dest_file[] = {
        { "text/uri-list", 0, DND_DRAG_TYPE_URI_LIST },
 };
 
-static void chat_window_update (EmpathyChatWindow *window);
+static void chat_window_update (EmpathyChatWindow *window,
+               gboolean update_contact_menu);
 
 static void empathy_chat_window_add_chat (EmpathyChatWindow *window,
                              EmpathyChat       *chat);
@@ -210,6 +212,161 @@ chat_window_find_chat (EmpathyChat *chat)
        return NULL;
 }
 
+static void
+remove_all_chats (EmpathyChatWindow *window)
+{
+       EmpathyChatWindowPriv *priv;
+
+       priv = GET_PRIV (window);
+       g_object_ref (window);
+
+       while (priv->chats) {
+               empathy_chat_window_remove_chat (window, priv->chats->data);
+       }
+
+       g_object_unref (window);
+}
+
+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
+ * 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.
+ */
+static gboolean
+chat_needs_close_confirmation (EmpathyChat *chat)
+{
+       return (empathy_chat_is_room (chat)
+               && empathy_chat_get_tp_chat (chat) != NULL);
+}
+
+static void
+maybe_close_chat (EmpathyChatWindow *window,
+                  EmpathyChat *chat)
+{
+       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);
+       }
+}
+
 static void
 chat_window_close_clicked_cb (GtkAction   *action,
                              EmpathyChat *chat)
@@ -217,24 +374,27 @@ chat_window_close_clicked_cb (GtkAction   *action,
        EmpathyChatWindow *window;
 
        window = chat_window_find_chat (chat);
-       empathy_chat_window_remove_chat (window, chat);
+       maybe_close_chat (window, chat);
 }
 
 static void
-chat_tab_style_set_cb (GtkWidget *hbox,
-                                      GtkStyle  *previous_style,
-                                      gpointer   user_data)
+chat_tab_style_updated_cb (GtkWidget *hbox,
+                          gpointer   user_data)
 {
        GtkWidget *button;
        int char_width, h, w;
        PangoContext *context;
+       const 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);
 
-       metrics = pango_context_get_metrics (context, gtk_widget_get_style (hbox)->font_desc,
+       font_desc = gtk_style_context_get_font (gtk_widget_get_style_context (hbox),
+                                               GTK_STATE_FLAG_NORMAL);
+
+       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);
@@ -255,21 +415,16 @@ chat_window_create_label (EmpathyChatWindow *window,
                          EmpathyChat       *chat,
                          gboolean           is_tab_label)
 {
-       EmpathyChatWindowPriv *priv;
        GtkWidget            *hbox;
        GtkWidget            *name_label;
        GtkWidget            *status_image;
-       GtkWidget            *close_button;
-       GtkWidget            *close_image;
        GtkWidget            *event_box;
        GtkWidget            *event_box_hbox;
        PangoAttrList        *attr_list;
        PangoAttribute       *attr;
 
-       priv = GET_PRIV (window);
-
        /* The spacing between the button and the label. */
-       hbox = gtk_hbox_new (FALSE, 0);
+       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);
@@ -295,7 +450,7 @@ chat_window_create_label (EmpathyChatWindow *window,
        status_image = gtk_image_new ();
 
        /* Spacing between the icon and label. */
-       event_box_hbox = gtk_hbox_new (FALSE, 0);
+       event_box_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
 
        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);
@@ -311,8 +466,18 @@ chat_window_create_label (EmpathyChatWindow *window,
        gtk_box_pack_start (GTK_BOX (hbox), event_box, TRUE, TRUE, 0);
 
        if (is_tab_label) {
-               close_button = gtk_button_new ();
-               gtk_button_set_relief (GTK_BUTTON (close_button), GTK_RELIEF_NONE);
+               GtkWidget            *close_button;
+               GtkWidget *sending_spinner;
+
+               sending_spinner = gtk_spinner_new ();
+
+               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);
+
+               close_button = gedit_close_button_new ();
                g_object_set_data (G_OBJECT (chat), "chat-window-tab-close-button", close_button);
 
                /* We don't want focus/keynav for the button to avoid clutter, and
@@ -321,13 +486,6 @@ chat_window_create_label (EmpathyChatWindow *window,
                gtk_widget_set_can_focus (close_button, FALSE);
                gtk_widget_set_can_default (close_button, FALSE);
 
-               /* Set the name to make the special rc style match. */
-               gtk_widget_set_name (close_button, "empathy-close-button");
-
-               close_image = gtk_image_new_from_stock (GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
-
-               gtk_container_add (GTK_CONTAINER (close_button), close_image);
-
                gtk_box_pack_end (GTK_BOX (hbox), close_button, FALSE, FALSE, 0);
 
                g_signal_connect (close_button,
@@ -337,8 +495,8 @@ chat_window_create_label (EmpathyChatWindow *window,
 
                /* React to theme changes and also setup the size correctly.  */
                g_signal_connect (hbox,
-                                 "style-set",
-                                 G_CALLBACK (chat_tab_style_set_cb),
+                                 "style-updated",
+                                 G_CALLBACK (chat_tab_style_updated_cb),
                                  chat);
        }
 
@@ -355,7 +513,7 @@ _submenu_notify_visible_changed_cb (GObject    *object,
        g_signal_handlers_disconnect_by_func (object,
                                              _submenu_notify_visible_changed_cb,
                                              userdata);
-       chat_window_update (EMPATHY_CHAT_WINDOW (userdata));
+       chat_window_update (EMPATHY_CHAT_WINDOW (userdata), TRUE);
 }
 
 static void
@@ -401,7 +559,7 @@ chat_window_conversation_menu_update (EmpathyChatWindowPriv *priv,
        tp_chat = empathy_chat_get_tp_chat (priv->current_chat);
 
        if (tp_chat != NULL) {
-               connection = empathy_tp_chat_get_connection (tp_chat);
+               connection = tp_channel_borrow_connection (TP_CHANNEL (tp_chat));
 
                sensitive = empathy_tp_chat_can_add_contact (tp_chat) &&
                        (tp_connection_get_status (connection, NULL) ==
@@ -423,8 +581,17 @@ chat_window_contact_menu_update (EmpathyChatWindowPriv *priv,
 
        if (orig_submenu == NULL || !gtk_widget_get_visible (orig_submenu)) {
                submenu = empathy_chat_get_contact_menu (priv->current_chat);
-               gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu), submenu);
-               gtk_widget_show (menu);
+
+               if (submenu != NULL) {
+                       /* gtk_menu_attach_to_widget () doesn't behave nicely here */
+                       g_object_set_data (G_OBJECT (submenu), "window", priv->dialog);
+
+                       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",
@@ -439,11 +606,8 @@ get_all_unread_messages (EmpathyChatWindowPriv *priv)
        GList *l;
        guint nb = 0;
 
-       for (l = priv->chats_new_msg; l != NULL; l = g_list_next (l)) {
-               EmpathyChat *chat = l->data;
-
-               nb += empathy_chat_get_nb_unread_messages (chat);
-       }
+       for (l = priv->chats; l != NULL; l = g_list_next (l))
+               nb += empathy_chat_get_nb_unread_messages (EMPATHY_CHAT (l->data));
 
        return nb;
 }
@@ -451,14 +615,14 @@ get_all_unread_messages (EmpathyChatWindowPriv *priv)
 static gchar *
 get_window_title_name (EmpathyChatWindowPriv *priv)
 {
-       const gchar *active_name;
+       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_get_name (priv->current_chat);
+       active_name = empathy_chat_dup_name (priv->current_chat);
 
        current_unread_msgs = empathy_chat_get_nb_unread_messages (
                        priv->current_chat);
@@ -466,9 +630,9 @@ get_window_title_name (EmpathyChatWindowPriv *priv)
        if (nb_chats == 1) {
                /* only one tab */
                if (current_unread_msgs == 0)
-                       return g_strdup (active_name);
+                       ret = g_strdup (active_name);
                else
-                       return g_strdup_printf (ngettext (
+                       ret = g_strdup_printf (ngettext (
                                "%s (%d unread)",
                                "%s (%d unread)", current_unread_msgs),
                                active_name, current_unread_msgs);
@@ -480,7 +644,7 @@ get_window_title_name (EmpathyChatWindowPriv *priv)
 
                if (all_unread_msgs == 0) {
                        /* no unread message */
-                       return g_strdup_printf (ngettext (
+                       ret = g_strdup_printf (ngettext (
                                "%s (and %u other)",
                                "%s (and %u others)", nb_others),
                                active_name, nb_others);
@@ -488,7 +652,7 @@ get_window_title_name (EmpathyChatWindowPriv *priv)
 
                else if (all_unread_msgs == current_unread_msgs) {
                        /* unread messages are in the current tab */
-                       return g_strdup_printf (ngettext (
+                       ret = g_strdup_printf (ngettext (
                                "%s (%d unread)",
                                "%s (%d unread)", current_unread_msgs),
                                active_name, current_unread_msgs);
@@ -496,7 +660,7 @@ get_window_title_name (EmpathyChatWindowPriv *priv)
 
                else if (current_unread_msgs == 0) {
                        /* unread messages are in other tabs */
-                       return g_strdup_printf (ngettext (
+                       ret = g_strdup_printf (ngettext (
                                "%s (%d unread from others)",
                                "%s (%d unread from others)",
                                all_unread_msgs),
@@ -505,13 +669,17 @@ get_window_title_name (EmpathyChatWindowPriv *priv)
 
                else {
                        /* unread messages are in all the tabs */
-                       return g_strdup_printf (ngettext (
+                       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
@@ -525,7 +693,7 @@ chat_window_title_update (EmpathyChatWindowPriv *priv)
 }
 
 static void
-chat_window_icon_update (EmpathyChatWindowPriv *priv)
+chat_window_icon_update (EmpathyChatWindowPriv *priv, gboolean new_messages)
 {
        GdkPixbuf      *icon;
        EmpathyContact *remote_contact;
@@ -535,7 +703,7 @@ chat_window_icon_update (EmpathyChatWindowPriv *priv)
        n_chats = g_list_length (priv->chats);
 
        /* Update window icon */
-       if (priv->chats_new_msg) {
+       if (new_messages) {
                gtk_window_set_icon_name (GTK_WINDOW (priv->dialog),
                                          EMPATHY_IMAGE_MESSAGE);
        } else {
@@ -580,7 +748,8 @@ chat_window_close_button_update (EmpathyChatWindowPriv *priv,
 }
 
 static void
-chat_window_update (EmpathyChatWindow *window)
+chat_window_update (EmpathyChatWindow *window,
+                   gboolean update_contact_menu)
 {
        EmpathyChatWindowPriv *priv = GET_PRIV (window);
        gint                   num_pages;
@@ -593,12 +762,18 @@ chat_window_update (EmpathyChatWindow *window)
 
        chat_window_conversation_menu_update (priv, window);
 
-       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 (priv,
+                                                window);
+       }
 
        chat_window_title_update (priv);
 
-       chat_window_icon_update (priv);
+       chat_window_icon_update (priv, get_all_unread_messages (priv) > 0);
 
        chat_window_close_button_update (priv,
                                         num_pages);
@@ -622,12 +797,13 @@ append_markup_printf (GString    *string,
 }
 
 static void
-chat_window_update_chat_tab (EmpathyChat *chat)
+chat_window_update_chat_tab_full (EmpathyChat *chat,
+                                 gboolean update_contact_menu)
 {
        EmpathyChatWindow     *window;
        EmpathyChatWindowPriv *priv;
        EmpathyContact        *remote_contact;
-       const gchar           *name;
+       gchar                 *name;
        const gchar           *id;
        TpAccount             *account;
        const gchar           *subject;
@@ -638,6 +814,8 @@ chat_window_update_chat_tab (EmpathyChat *chat)
        const gchar           *icon_name;
        GtkWidget             *tab_image;
        GtkWidget             *menu_image;
+       GtkWidget             *sending_spinner;
+       guint                  nb_sending;
 
        window = chat_window_find_chat (chat);
        if (!window) {
@@ -646,7 +824,7 @@ chat_window_update_chat_tab (EmpathyChat *chat)
        priv = GET_PRIV (window);
 
        /* Get information */
-       name = empathy_chat_get_name (chat);
+       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);
@@ -659,12 +837,15 @@ chat_window_update_chat_tab (EmpathyChat *chat)
                /* No TpChat, we are disconnected */
                icon_name = NULL;
        }
-       else if (g_list_find (priv->chats_new_msg, chat)) {
+       else if (empathy_chat_get_nb_unread_messages (chat) > 0) {
                icon_name = EMPATHY_IMAGE_MESSAGE;
        }
-       else if (g_list_find (priv->chats_composing, chat)) {
+       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 {
@@ -683,6 +864,16 @@ chat_window_update_chat_tab (EmpathyChat *chat)
                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);
 
@@ -693,11 +884,29 @@ chat_window_update_chat_tab (EmpathyChat *chat)
                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);
        }
@@ -707,7 +916,7 @@ chat_window_update_chat_tab (EmpathyChat *chat)
                                      _("Topic:"), subject);
        }
 
-       if (g_list_find (priv->chats_composing, chat)) {
+       if (remote_contact && empathy_chat_is_composing (chat)) {
                append_markup_printf (tooltip, "\n%s", _("Typing a message."));
        }
 
@@ -726,13 +935,22 @@ chat_window_update_chat_tab (EmpathyChat *chat)
 
        /* Update the window if it's the current chat */
        if (priv->current_chat == chat) {
-               chat_window_update (window);
+               chat_window_update (window, update_contact_menu);
        }
+
+       g_free (name);
+}
+
+static void
+chat_window_update_chat_tab (EmpathyChat *chat)
+{
+       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;
 
@@ -759,6 +977,11 @@ chat_window_chat_notify_cb (EmpathyChat *chat)
        }
 
        chat_window_update_chat_tab (chat);
+
+       window = chat_window_find_chat (chat);
+       if (window != NULL) {
+               chat_window_update (window, FALSE);
+       }
 }
 
 static void
@@ -849,21 +1072,24 @@ chat_window_favorite_toggled_cb (GtkToggleAction   *toggle_action,
        EmpathyChatWindowPriv *priv = GET_PRIV (window);
        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);
 
        chatroom = empathy_chatroom_manager_ensure_chatroom (
                     priv->chatroom_manager,
                     account,
                     room,
-                    empathy_chat_get_name (priv->current_chat));
+                    name);
 
        empathy_chatroom_set_favorite (chatroom, active);
        g_object_unref (chatroom);
+       g_free (name);
 }
 
 static void
@@ -873,21 +1099,24 @@ chat_window_always_urgent_toggled_cb (GtkToggleAction   *toggle_action,
        EmpathyChatWindowPriv *priv = GET_PRIV (window);
        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);
 
        chatroom = empathy_chatroom_manager_ensure_chatroom (
                     priv->chatroom_manager,
                     account,
                     room,
-                    empathy_chat_get_name (priv->current_chat));
+                    name);
 
        empathy_chatroom_set_always_urgent (chatroom, active);
        g_object_unref (chatroom);
+       g_free (name);
 }
 
 static void
@@ -902,24 +1131,6 @@ chat_window_contacts_toggled_cb (GtkToggleAction   *toggle_action,
        empathy_chat_set_show_contacts (priv->current_chat, active);
 }
 
-static void
-got_contact_cb (TpConnection            *connection,
-                EmpathyContact          *contact,
-                const GError            *error,
-                gpointer                 user_data,
-                GObject                 *object)
-{
-       EmpathyTpChat *tp_chat = EMPATHY_TP_CHAT (user_data);
-
-       if (error != NULL) {
-               DEBUG ("Failed: %s", error->message);
-               return;
-       } else {
-               empathy_contact_list_add (EMPATHY_CONTACT_LIST (tp_chat),
-                               contact, _("Inviting you to this room"));
-       }
-}
-
 static void
 chat_window_invite_participant_activate_cb (GtkAction         *action,
                                            EmpathyChatWindow *window)
@@ -927,35 +1138,34 @@ chat_window_invite_participant_activate_cb (GtkAction         *action,
        EmpathyChatWindowPriv *priv;
        GtkWidget             *dialog;
        EmpathyTpChat         *tp_chat;
-       TpChannel             *channel;
        int                    response;
-       TpAccount             *account;
 
        priv = GET_PRIV (window);
 
        g_return_if_fail (priv->current_chat != NULL);
 
        tp_chat = empathy_chat_get_tp_chat (priv->current_chat);
-       channel = empathy_tp_chat_get_channel (tp_chat);
-       account = empathy_chat_get_account (priv->current_chat);
 
        dialog = empathy_invite_participant_dialog_new (
-                       GTK_WINDOW (priv->dialog), account);
+                       GTK_WINDOW (priv->dialog), tp_chat);
        gtk_widget_show (dialog);
 
        response = gtk_dialog_run (GTK_DIALOG (dialog));
 
        if (response == GTK_RESPONSE_ACCEPT) {
-               TpConnection *connection;
-               const char *id;
+               TpContact *tp_contact;
+               EmpathyContact *contact;
+
+               tp_contact = empathy_invite_participant_dialog_get_selected (
+                       EMPATHY_INVITE_PARTICIPANT_DIALOG (dialog));
+               if (tp_contact == NULL) goto out;
 
-               id = empathy_contact_selector_dialog_get_selected (
-                               EMPATHY_CONTACT_SELECTOR_DIALOG (dialog), NULL, NULL);
-               if (EMP_STR_EMPTY (id)) goto out;
+               contact = empathy_contact_dup_from_tp_contact (tp_contact);
+
+               empathy_contact_list_add (EMPATHY_CONTACT_LIST (tp_chat),
+                               contact, _("Inviting you to this room"));
 
-               connection = tp_channel_borrow_connection (channel);
-               empathy_tp_contact_factory_get_from_id (connection, id,
-                       got_contact_cb, tp_chat,  NULL, NULL);
+               g_object_unref (contact);
        }
 
 out:
@@ -972,7 +1182,7 @@ chat_window_close_activate_cb (GtkAction         *action,
 
        g_return_if_fail (priv->current_chat != NULL);
 
-       empathy_chat_window_remove_chat (window, priv->current_chat);
+       maybe_close_chat (window, priv->current_chat);
 }
 
 static void
@@ -1070,7 +1280,6 @@ chat_window_tabs_next_activate_cb (GtkAction         *action,
                                   EmpathyChatWindow *window)
 {
        EmpathyChatWindowPriv *priv;
-       EmpathyChat           *chat;
        gint                  index_, numPages;
        gboolean              wrap_around;
 
@@ -1079,7 +1288,6 @@ chat_window_tabs_next_activate_cb (GtkAction         *action,
        g_object_get (gtk_settings_get_default (), "gtk-keynav-wrap-around",
                       &wrap_around, NULL);
 
-       chat = priv->current_chat;
        index_ = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook));
        numPages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->notebook));
 
@@ -1096,7 +1304,6 @@ chat_window_tabs_previous_activate_cb (GtkAction         *action,
                                   EmpathyChatWindow *window)
 {
        EmpathyChatWindowPriv *priv;
-       EmpathyChat           *chat;
        gint                  index_, numPages;
        gboolean              wrap_around;
 
@@ -1105,7 +1312,6 @@ chat_window_tabs_previous_activate_cb (GtkAction         *action,
        g_object_get (gtk_settings_get_default (), "gtk-keynav-wrap-around",
                       &wrap_around, NULL);
 
-       chat = priv->current_chat;
        index_ = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook));
        numPages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->notebook));
 
@@ -1122,7 +1328,8 @@ chat_window_tabs_undo_close_tab_activate_cb (GtkAction         *action,
                                             EmpathyChatWindow *window)
 {
        EmpathyChatWindowPriv *priv = GET_PRIV (window);
-       empathy_chat_manager_undo_closed_chat (priv->chat_manager);
+       empathy_chat_manager_undo_closed_chat (priv->chat_manager,
+                                              empathy_get_current_action_time ());
 }
 
 static void
@@ -1219,14 +1426,25 @@ chat_window_delete_event_cb (GtkWidget        *dialog,
                             EmpathyChatWindow *window)
 {
        EmpathyChatWindowPriv *priv = GET_PRIV (window);
+       EmpathyChat *chat = NULL;
+       guint n_rooms = 0;
+       GList *l;
 
        DEBUG ("Delete event received");
 
-       g_object_ref (window);
-       while (priv->chats) {
-               empathy_chat_window_remove_chat (window, priv->chats->data);
+       for (l = 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);
        }
-       g_object_unref (window);
 
        return TRUE;
 }
@@ -1236,16 +1454,6 @@ chat_window_composing_cb (EmpathyChat       *chat,
                          gboolean          is_composing,
                          EmpathyChatWindow *window)
 {
-       EmpathyChatWindowPriv *priv;
-
-       priv = GET_PRIV (window);
-
-       if (is_composing && !g_list_find (priv->chats_composing, chat)) {
-               priv->chats_composing = g_list_prepend (priv->chats_composing, chat);
-       } else {
-               priv->chats_composing = g_list_remove (priv->chats_composing, chat);
-       }
-
        chat_window_update_chat_tab (chat);
 }
 
@@ -1329,9 +1537,14 @@ chat_window_show_or_update_notification (EmpathyChatWindow *window,
                                  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, "");
+                               EMPATHY_NOTIFY_MANAGER_CAP_X_CANONICAL_APPEND, "1");
                }
+
+               notify_notification_set_hint (notification,
+                       EMPATHY_NOTIFY_MANAGER_CAP_CATEGORY,
+                       g_variant_new_string ("im.received"));
        }
 
        pixbuf = empathy_notify_manager_get_pixbuf_for_notification (priv->notify_mgr,
@@ -1348,20 +1561,26 @@ chat_window_show_or_update_notification (EmpathyChatWindow *window,
 }
 
 static void
-chat_window_set_highlight_room_tab_label (EmpathyChat *chat)
+chat_window_set_highlight_room_labels (EmpathyChat *chat)
 {
-       gchar *markup;
+       gchar *markup, *name;
        GtkWidget *widget;
 
        if (!empathy_chat_is_room (chat))
                return;
 
+       name = empathy_chat_dup_name (chat);
        markup = g_markup_printf_escaped (
                "<span color=\"red\" weight=\"bold\">%s</span>",
-               empathy_chat_get_name (chat));
+               name);
 
        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 (name);
        g_free (markup);
 }
 
@@ -1384,6 +1603,7 @@ static void
 chat_window_new_message_cb (EmpathyChat       *chat,
                            EmpathyMessage    *message,
                            gboolean pending,
+                           gboolean should_highlight,
                            EmpathyChatWindow *window)
 {
        EmpathyChatWindowPriv *priv;
@@ -1417,8 +1637,8 @@ chat_window_new_message_cb (EmpathyChat       *chat,
                return;
        }
 
-       if (!g_list_find (priv->chats_new_msg, chat)) {
-               priv->chats_new_msg = g_list_prepend (priv->chats_new_msg, chat);
+       /* 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);
        }
 
@@ -1429,8 +1649,7 @@ chat_window_new_message_cb (EmpathyChat       *chat,
         *   a) the chatroom's always_urgent property is TRUE
         *   b) the message contains our alias
         */
-       if (empathy_chat_is_room (chat) ||
-           empathy_chat_get_remote_contact (chat) == NULL) {
+       if (empathy_chat_is_room (chat)) {
                TpAccount             *account;
                const gchar           *room;
                EmpathyChatroom       *chatroom;
@@ -1441,29 +1660,77 @@ chat_window_new_message_cb (EmpathyChat       *chat,
                chatroom = empathy_chatroom_manager_find (priv->chatroom_manager,
                                                          account, room);
 
-               if (empathy_chatroom_is_always_urgent (chatroom)) {
+               if (chatroom != NULL && empathy_chatroom_is_always_urgent (chatroom)) {
                        needs_urgency = TRUE;
                } else {
-                       needs_urgency = empathy_message_should_highlight (message);
+                       needs_urgency = should_highlight;
                }
        } else {
                needs_urgency = TRUE;
        }
 
        if (needs_urgency) {
+               chat_window_set_highlight_room_labels (chat);
+
                if (!has_focus) {
                        chat_window_set_urgency_hint (window, TRUE);
-                       chat_window_set_highlight_room_tab_label (chat);
                }
 
-               empathy_sound_manager_play (priv->sound_mgr, GTK_WIDGET (priv->dialog),
-                   EMPATHY_SOUND_MESSAGE_INCOMING);
-               chat_window_show_or_update_notification (window, message, chat);
+               /* 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);
+       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);
+       }
 }
 
 static GtkNotebook *
@@ -1495,24 +1762,15 @@ notebook_create_window_cb (GtkNotebook *source,
 
 static void
 chat_window_page_switched_cb (GtkNotebook      *notebook,
-                             gpointer          ignore, /* see note below */
+                             GtkWidget         *child,
                              gint              page_num,
                              EmpathyChatWindow *window)
 {
-       EmpathyChatWindowPriv *priv;
-       EmpathyChat           *chat;
-       GtkWidget            *child;
+       EmpathyChatWindowPriv *priv = GET_PRIV (window);
+       EmpathyChat           *chat = EMPATHY_CHAT (child);
 
        DEBUG ("Page switched");
 
-       priv = GET_PRIV (window);
-
-       /* N.B. in GTK+ 3 child is passed as the first argument to the signal,
-        * but we can't use that while trying to retain GTK+ 2.x compatibility.
-        */
-       child = gtk_notebook_get_nth_page (notebook, page_num);
-       chat = EMPATHY_CHAT (child);
-
        if (priv->page_added) {
                priv->page_added = FALSE;
                empathy_chat_scroll_down (chat);
@@ -1522,7 +1780,6 @@ chat_window_page_switched_cb (GtkNotebook      *notebook,
        }
 
        priv->current_chat = chat;
-       priv->chats_new_msg = g_list_remove (priv->chats_new_msg, chat);
        empathy_chat_messages_read (chat);
 
        chat_window_update_chat_tab (chat);
@@ -1561,6 +1818,9 @@ chat_window_page_added_cb (GtkNotebook      *notebook,
        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);
@@ -1614,14 +1874,12 @@ chat_window_page_removed_cb (GtkNotebook      *notebook,
 
        /* Keep list of chats up to date */
        priv->chats = g_list_remove (priv->chats, chat);
-       priv->chats_new_msg = g_list_remove (priv->chats_new_msg, chat);
        empathy_chat_messages_read (chat);
-       priv->chats_composing = g_list_remove (priv->chats_composing, chat);
 
        if (priv->chats == NULL) {
                g_object_unref (window);
        } else {
-               chat_window_update (window);
+               chat_window_update (window, TRUE);
        }
 }
 
@@ -1634,13 +1892,12 @@ chat_window_focus_in_event_cb (GtkWidget        *widget,
 
        priv = GET_PRIV (window);
 
-       priv->chats_new_msg = g_list_remove (priv->chats_new_msg, priv->current_chat);
        empathy_chat_messages_read (priv->current_chat);
 
        chat_window_set_urgency_hint (window, FALSE);
 
        /* Update the title, since we now mark all unread messages as read. */
-       chat_window_update_chat_tab (priv->current_chat);
+       chat_window_update_chat_tab_full (priv->current_chat, FALSE);
 
        return FALSE;
 }
@@ -1741,7 +1998,7 @@ chat_window_drag_data_received (GtkWidget        *widget,
                EmpathyChat           *chat = NULL;
                EmpathyChatWindow     *old_window;
                TpAccount             *account = NULL;
-               TpAccountManager      *account_manager;
+               EmpathyClientFactory  *factory;
                const gchar           *id;
                gchar                **strv;
                const gchar           *account_id;
@@ -1749,9 +2006,7 @@ chat_window_drag_data_received (GtkWidget        *widget,
 
                id = (const gchar*) gtk_selection_data_get_data (selection);
 
-               /* FIXME: Perhaps should be sure that the account manager is
-                * prepared before calling _ensure_account on it. */
-               account_manager = tp_account_manager_dup ();
+               factory = empathy_client_factory_dup ();
 
                DEBUG ("DND contact from roster with id:'%s'", id);
 
@@ -1760,9 +2015,13 @@ chat_window_drag_data_received (GtkWidget        *widget,
                        account_id = strv[0];
                        contact_id = strv[1];
                        account =
-                               tp_account_manager_ensure_account (account_manager, account_id);
+                               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);
+                               chat = empathy_chat_window_find_chat (account, contact_id, FALSE);
                }
 
                if (account == NULL) {
@@ -1772,13 +2031,14 @@ chat_window_drag_data_received (GtkWidget        *widget,
                }
 
                if (!chat) {
-                       empathy_dispatcher_chat_with_contact_id (
-                               account, contact_id, gtk_get_current_event_time ());
+                       empathy_chat_with_contact_id (
+                               account, contact_id,
+                               empathy_get_current_action_time (),
+                               NULL, NULL);
 
                        g_strfreev (strv);
                        return;
                }
-               g_object_unref (account_manager);
                g_strfreev (strv);
 
                old_window = chat_window_find_chat (chat);
@@ -1911,16 +2171,6 @@ empathy_chat_window_class_init (EmpathyChatWindowClass *klass)
        object_class->finalize = chat_window_finalize;
 
        g_type_class_add_private (object_class, sizeof (EmpathyChatWindowPriv));
-
-       /* Set up a style for the close button with no focus padding. */
-       gtk_rc_parse_string (
-               "style \"empathy-close-button-style\"\n"
-               "{\n"
-               "  GtkWidget::focus-padding = 0\n"
-               "  xthickness = 0\n"
-               "  ythickness = 0\n"
-               "}\n"
-               "widget \"*.empathy-close-button\" style \"empathy-close-button-style\"");
 }
 
 static void
@@ -2089,8 +2339,6 @@ empathy_chat_window_init (EmpathyChatWindow *window)
 
        /* Set up private details */
        priv->chats = NULL;
-       priv->chats_new_msg = NULL;
-       priv->chats_composing = NULL;
        priv->current_chat = NULL;
        priv->notification = NULL;
 
@@ -2107,18 +2355,6 @@ empathy_chat_window_init (EmpathyChatWindow *window)
                                                   window);
 }
 
-static GtkWidget *
-empathy_chat_window_get_dialog (EmpathyChatWindow *window)
-{
-       EmpathyChatWindowPriv *priv;
-
-       g_return_val_if_fail (window != NULL, NULL);
-
-       priv = GET_PRIV (window);
-
-       return priv->dialog;
-}
-
 /* 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.
  */
@@ -2140,15 +2376,10 @@ empathy_chat_window_get_default (gboolean room)
        }
 
        for (l = chat_windows; l; l = l->next) {
-               EmpathyChatWindowPriv *priv;
                EmpathyChatWindow *chat_window;
-               GtkWidget         *dialog;
                guint nb_rooms, nb_private;
 
                chat_window = l->data;
-               priv = GET_PRIV (chat_window);
-
-               dialog = empathy_chat_window_get_dialog (chat_window);
 
                empathy_chat_window_get_nb_chats (chat_window, &nb_rooms, &nb_private);
 
@@ -2160,9 +2391,6 @@ empathy_chat_window_get_default (gboolean room)
                if (!room && nb_private == 0)
                        continue;
 
-               /* Found a window on this desktop, make it visible if necessary */
-               if (!empathy_window_get_is_visible (GTK_WINDOW (dialog)))
-                       empathy_window_present (GTK_WINDOW (dialog));
                return chat_window;
        }
 
@@ -2236,6 +2464,15 @@ empathy_chat_window_add_chat (EmpathyChatWindow *window,
        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 (priv->notebook), child, label, popup_label);
@@ -2339,7 +2576,8 @@ empathy_chat_window_switch_to_chat (EmpathyChatWindow *window,
 
 EmpathyChat *
 empathy_chat_window_find_chat (TpAccount   *account,
-                              const gchar *id)
+                              const gchar *id,
+                              gboolean     sms_channel)
 {
        GList *l;
 
@@ -2359,7 +2597,8 @@ empathy_chat_window_find_chat (TpAccount   *account,
                        chat = ll->data;
 
                        if (account == empathy_chat_get_account (chat) &&
-                           !tp_strdiff (id, empathy_chat_get_id (chat))) {
+                           !tp_strdiff (id, empathy_chat_get_id (chat)) &&
+                           sms_channel == empathy_chat_is_sms_channel (chat)) {
                                return chat;
                        }
                }
@@ -2385,7 +2624,11 @@ empathy_chat_window_present_chat (EmpathyChat *chat,
                window = empathy_chat_window_get_default (empathy_chat_is_room (chat));
                if (!window) {
                        window = empathy_chat_window_new ();
-                       gtk_widget_show_all (GET_PRIV (window)->dialog);
+
+                       /* we want to display the newly created window even if we don't present
+                       * it */
+                       priv = GET_PRIV (window);
+                       gtk_widget_show (priv->dialog);
                }
 
                empathy_chat_window_add_chat (window, chat);
@@ -2412,8 +2655,12 @@ empathy_chat_window_present_chat (EmpathyChat *chat,
        }
 
        empathy_chat_window_switch_to_chat (window, chat);
-       empathy_window_present_with_time (GTK_WINDOW (priv->dialog),
-         x_timestamp);
+
+       /* 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);
 
        gtk_widget_grab_focus (chat->input_text_view);
 }