]> git.0d.be Git - empathy.git/blobdiff - src/empathy-chat-window.c
Merge branch 'sasl'
[empathy.git] / src / empathy-chat-window.c
index 8a0502b262e2bb2735016b45d3ff3a6cdd7f4907..16329ee7be4ebde149b65519b669b92f88e85dd3 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
 #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-contact-list.h>
 
 #include <libempathy-gtk/empathy-images.h>
-#include <libempathy-gtk/empathy-conf.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.h>
+#include <libempathy-gtk/empathy-sound-manager.h>
 #include <libempathy-gtk/empathy-ui-utils.h>
 #include <libempathy-gtk/empathy-notify-manager.h>
 
@@ -111,13 +111,19 @@ typedef struct {
 
        /* 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;
 
 static GList *chat_windows = NULL;
 
 static const guint tab_accel_keys[] = {
-       GDK_1, GDK_2, GDK_3, GDK_4, GDK_5,
-       GDK_6, GDK_7, GDK_8, GDK_9, GDK_0
+       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 {
@@ -146,6 +152,20 @@ static const GtkTargetEntry drag_types_dest_file[] = {
 
 static void chat_window_update (EmpathyChatWindow *window);
 
+static void empathy_chat_window_add_chat (EmpathyChatWindow *window,
+                             EmpathyChat       *chat);
+
+static void empathy_chat_window_remove_chat (EmpathyChatWindow *window,
+                                EmpathyChat       *chat);
+
+static void empathy_chat_window_move_chat (EmpathyChatWindow *old_window,
+                              EmpathyChatWindow *new_window,
+                              EmpathyChat       *chat);
+
+static void empathy_chat_window_get_nb_chats (EmpathyChatWindow *self,
+                              guint *nb_rooms,
+                              guint *nb_private);
+
 G_DEFINE_TYPE (EmpathyChatWindow, empathy_chat_window, G_TYPE_OBJECT);
 
 static void
@@ -519,9 +539,8 @@ chat_window_icon_update (EmpathyChatWindowPriv *priv)
                gtk_window_set_icon_name (GTK_WINDOW (priv->dialog),
                                          EMPATHY_IMAGE_MESSAGE);
        } else {
-               empathy_conf_get_bool (empathy_conf_get (),
-                                      EMPATHY_PREFS_CHAT_AVATAR_IN_ICON,
-                                      &avatar_in_icon);
+               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);
@@ -931,7 +950,7 @@ chat_window_invite_participant_activate_cb (GtkAction         *action,
                const char *id;
 
                id = empathy_contact_selector_dialog_get_selected (
-                               EMPATHY_CONTACT_SELECTOR_DIALOG (dialog), NULL);
+                               EMPATHY_CONTACT_SELECTOR_DIALOG (dialog), NULL, NULL);
                if (EMP_STR_EMPTY (id)) goto out;
 
                connection = tp_channel_borrow_connection (channel);
@@ -1151,6 +1170,12 @@ chat_window_tabs_right_activate_cb (GtkAction         *action,
        chat_window_menu_context_update (priv, num_pages);
 }
 
+static EmpathyChatWindow *
+empathy_chat_window_new (void)
+{
+       return EMPATHY_CHAT_WINDOW (g_object_new (EMPATHY_TYPE_CHAT_WINDOW, NULL));
+}
+
 static void
 chat_window_detach_activate_cb (GtkAction         *action,
                                EmpathyChatWindow *window)
@@ -1264,15 +1289,16 @@ chat_window_show_or_update_notification (EmpathyChatWindow *window,
        if (!empathy_notify_manager_notification_is_enabled (priv->notify_mgr)) {
                return;
        } else {
-               empathy_conf_get_bool (empathy_conf_get (),
-                                      EMPATHY_PREFS_NOTIFICATIONS_FOCUS, &res);
+               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_name (sender);
+       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 (
@@ -1291,7 +1317,7 @@ chat_window_show_or_update_notification (EmpathyChatWindow *window,
                   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, NULL);
+               notification = notify_notification_new (header, escaped, NULL);
 
                if (priv->notification == NULL) {
                        priv->notification = notification;
@@ -1339,9 +1365,25 @@ chat_window_set_highlight_room_tab_label (EmpathyChat *chat)
        g_free (markup);
 }
 
+static gboolean
+empathy_chat_window_has_focus (EmpathyChatWindow *window)
+{
+       EmpathyChatWindowPriv *priv;
+       gboolean              has_focus;
+
+       g_return_val_if_fail (EMPATHY_IS_CHAT_WINDOW (window), FALSE);
+
+       priv = GET_PRIV (window);
+
+       g_object_get (priv->dialog, "has-toplevel-focus", &has_focus, NULL);
+
+       return has_focus;
+}
+
 static void
 chat_window_new_message_cb (EmpathyChat       *chat,
                            EmpathyMessage    *message,
+                           gboolean pending,
                            EmpathyChatWindow *window)
 {
        EmpathyChatWindowPriv *priv;
@@ -1363,7 +1405,7 @@ chat_window_new_message_cb (EmpathyChat       *chat,
        sender = empathy_message_get_sender (message);
 
        if (empathy_contact_is_user (sender)) {
-               empathy_sound_play (GTK_WIDGET (priv->dialog),
+               empathy_sound_manager_play (priv->sound_mgr, GTK_WIDGET (priv->dialog),
                                    EMPATHY_SOUND_MESSAGE_OUTGOING);
        }
 
@@ -1414,17 +1456,22 @@ chat_window_new_message_cb (EmpathyChat       *chat,
                        chat_window_set_highlight_room_tab_label (chat);
                }
 
-               empathy_sound_play (GTK_WIDGET (priv->dialog),
+               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 in the approver, so we don't
+               * display a notification for those. */
+               if (!pending)
+                       chat_window_show_or_update_notification (window, message, chat);
        }
 
-       /* update the number of unread messages */
+       /* update the number of unread messages and the window icon */
        chat_window_title_update (priv);
+       chat_window_icon_update (priv);
 }
 
 static GtkNotebook *
-chat_window_detach_hook (GtkNotebook *source,
+notebook_create_window_cb (GtkNotebook *source,
                         GtkWidget   *page,
                         gint         x,
                         gint         y,
@@ -1444,15 +1491,15 @@ chat_window_detach_hook (GtkNotebook *source,
 
        empathy_chat_window_move_chat (window, new_window, chat);
 
-       gtk_window_move (GTK_WINDOW (priv->dialog), x, y);
        gtk_widget_show (priv->dialog);
+       gtk_window_move (GTK_WINDOW (priv->dialog), x, y);
 
        return NULL;
 }
 
 static void
 chat_window_page_switched_cb (GtkNotebook      *notebook,
-                             GtkNotebookPage  *page,
+                             gpointer          ignore, /* see note below */
                              gint              page_num,
                              EmpathyChatWindow *window)
 {
@@ -1464,6 +1511,9 @@ chat_window_page_switched_cb (GtkNotebook      *notebook,
 
        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);
 
@@ -1726,14 +1776,8 @@ chat_window_drag_data_received (GtkWidget        *widget,
                }
 
                if (!chat) {
-                       TpConnection *connection;
-
-                       connection = tp_account_get_connection (account);
-
-                       if (connection) {
-                               empathy_dispatcher_chat_with_contact_id (
-                                       connection, contact_id, gtk_get_current_event_time (), NULL, NULL);
-                       }
+                       empathy_dispatcher_chat_with_contact_id (
+                               account, contact_id, gtk_get_current_event_time ());
 
                        g_strfreev (strv);
                        return;
@@ -1755,7 +1799,7 @@ chat_window_drag_data_received (GtkWidget        *widget,
 
                /* Added to take care of any outstanding chat events */
                empathy_chat_window_present_chat (chat,
-                       EMPATHY_DISPATCHER_NON_USER_ACTION);
+                       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
@@ -1833,6 +1877,10 @@ chat_window_finalize (GObject *object)
        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 (priv->notification != NULL) {
                notify_notification_close (priv->notification, NULL);
@@ -1877,8 +1925,6 @@ empathy_chat_window_class_init (EmpathyChatWindowClass *klass)
                "  ythickness = 0\n"
                "}\n"
                "widget \"*.empathy-close-button\" style \"empathy-close-button-style\"");
-
-       gtk_notebook_set_window_creation_hook (chat_window_detach_hook, NULL, NULL);
 }
 
 static void
@@ -1945,10 +1991,20 @@ empathy_chat_window_init (EmpathyChatWindow *window)
        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 ();
-       gtk_notebook_set_group (GTK_NOTEBOOK (priv->notebook), "EmpathyChatWindow");
+
+       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);
@@ -2046,34 +2102,41 @@ empathy_chat_window_init (EmpathyChatWindow *window)
 
        priv->chat_manager = empathy_chat_manager_dup_singleton ();
        priv->chat_manager_chats_changed_id =
-               g_signal_connect (priv->chat_manager, "chats-changed",
+               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_chats (priv->chat_manager),
+                                                  empathy_chat_manager_get_num_closed_chats (priv->chat_manager),
                                                   window);
 }
 
-EmpathyChatWindow *
-empathy_chat_window_new (void)
+static GtkWidget *
+empathy_chat_window_get_dialog (EmpathyChatWindow *window)
 {
-       return EMPATHY_CHAT_WINDOW (g_object_new (EMPATHY_TYPE_CHAT_WINDOW, NULL));
+       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 only one window
- * visble, otherwise, returns NULL indicating that a new window should
- * be added.
+/* 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.
  */
-EmpathyChatWindow *
+static EmpathyChatWindow *
 empathy_chat_window_get_default (gboolean room)
 {
+       GSettings *gsettings = g_settings_new (EMPATHY_PREFS_UI_SCHEMA);
        GList    *l;
        gboolean  separate_windows = TRUE;
 
-       empathy_conf_get_bool (empathy_conf_get (),
-                             EMPATHY_PREFS_UI_SEPARATE_CHAT_WINDOWS,
-                             &separate_windows);
+       separate_windows = g_settings_get_boolean (gsettings,
+                       EMPATHY_PREFS_UI_SEPARATE_CHAT_WINDOWS);
+
+       g_object_unref (gsettings);
 
        if (separate_windows) {
                /* Always create a new window */
@@ -2084,44 +2147,33 @@ empathy_chat_window_get_default (gboolean room)
                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);
-               if (empathy_window_get_is_visible (GTK_WINDOW (dialog))) {
-                       guint nb_rooms, nb_private;
-                       empathy_chat_window_get_nb_chats (chat_window, &nb_rooms, &nb_private);
 
-                       /* Skip the window if there aren't any rooms in it */
-                       if (room && nb_rooms == 0)
-                               continue;
+               empathy_chat_window_get_nb_chats (chat_window, &nb_rooms, &nb_private);
 
-                       /* Skip the window if there aren't any 1-1 chats in it */
-                       if (!room && nb_private == 0)
-                               continue;
+               /* Skip the window if there aren't any rooms in it */
+               if (room && nb_rooms == 0)
+                       continue;
 
-                       /* Found a visible window on this desktop */
-                       return chat_window;
-               }
+               /* Skip the window if there aren't any 1-1 chats in it */
+               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;
        }
 
        return NULL;
 }
 
-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;
-}
-
-void
+static void
 empathy_chat_window_add_chat (EmpathyChatWindow *window,
                              EmpathyChat       *chat)
 {
@@ -2144,16 +2196,32 @@ empathy_chat_window_add_chat (EmpathyChatWindow *window,
                const gchar *name = "chat-window";
                gboolean     separate_windows;
 
-               empathy_conf_get_bool (empathy_conf_get (),
-                                      EMPATHY_PREFS_UI_SEPARATE_CHAT_WINDOWS,
-                                      &separate_windows);
+               separate_windows = g_settings_get_boolean (priv->gsettings_ui,
+                               EMPATHY_PREFS_UI_SEPARATE_CHAT_WINDOWS);
+
+               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 (priv->dialog), &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 (priv->dialog), 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 (priv->dialog), 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);
                }
-               else if (empathy_chat_is_room (chat)) {
-                       name = "room-window";
-               }
 
                empathy_geometry_bind (GTK_WINDOW (priv->dialog), name);
        }
@@ -2188,7 +2256,7 @@ empathy_chat_window_add_chat (EmpathyChatWindow *window,
        DEBUG ("Chat added (%d references)", G_OBJECT (chat)->ref_count);
 }
 
-void
+static void
 empathy_chat_window_remove_chat (EmpathyChatWindow *window,
                                 EmpathyChat       *chat)
 {
@@ -2226,7 +2294,7 @@ empathy_chat_window_remove_chat (EmpathyChatWindow *window,
        g_object_unref (chat);
 }
 
-void
+static void
 empathy_chat_window_move_chat (EmpathyChatWindow *old_window,
                               EmpathyChatWindow *new_window,
                               EmpathyChat       *chat)
@@ -2255,7 +2323,7 @@ empathy_chat_window_move_chat (EmpathyChatWindow *old_window,
        g_object_unref (chat);
 }
 
-void
+static void
 empathy_chat_window_switch_to_chat (EmpathyChatWindow *window,
                                    EmpathyChat       *chat)
 {
@@ -2273,21 +2341,6 @@ empathy_chat_window_switch_to_chat (EmpathyChatWindow *window,
                                       page_num);
 }
 
-gboolean
-empathy_chat_window_has_focus (EmpathyChatWindow *window)
-{
-       EmpathyChatWindowPriv *priv;
-       gboolean              has_focus;
-
-       g_return_val_if_fail (EMPATHY_IS_CHAT_WINDOW (window), FALSE);
-
-       priv = GET_PRIV (window);
-
-       g_object_get (priv->dialog, "has-toplevel-focus", &has_focus, NULL);
-
-       return has_focus;
-}
-
 EmpathyChat *
 empathy_chat_window_find_chat (TpAccount   *account,
                               const gchar *id)
@@ -2345,15 +2398,12 @@ empathy_chat_window_present_chat (EmpathyChat *chat,
        /* Don't force the window to show itself when it wasn't
         * an action by the user
         */
-       if (timestamp == EMPATHY_DISPATCHER_NON_USER_ACTION)
+       if (!tp_user_action_time_should_present (timestamp, &x_timestamp))
                return;
 
        priv = GET_PRIV (window);
 
-       if (timestamp == EMPATHY_DISPATCHER_CURRENT_TIME) {
-               x_timestamp = GDK_CURRENT_TIME;
-       } else {
-               x_timestamp = CLAMP (timestamp, 0, G_MAXUINT32);
+       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 */
@@ -2372,7 +2422,7 @@ empathy_chat_window_present_chat (EmpathyChat *chat,
        gtk_widget_grab_focus (chat->input_text_view);
 }
 
-void
+static void
 empathy_chat_window_get_nb_chats (EmpathyChatWindow *self,
                               guint *nb_rooms,
                               guint *nb_private)