]> git.0d.be Git - empathy.git/blobdiff - libempathy-gtk/empathy-chat.c
Merge branch 'sasl'
[empathy.git] / libempathy-gtk / empathy-chat.c
index e946ae57face679d5ed0fdeea91d4b561b02f4b8..a92298cfae7d13370055dd7eb37a9e101e231c48 100644 (file)
@@ -1,7 +1,7 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
  * Copyright (C) 2002-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-gsettings.h>
 #include <libempathy/empathy-utils.h>
 #include <libempathy/empathy-dispatcher.h>
+#include <libempathy/empathy-marshal.h>
 
 #include "empathy-chat.h"
 #include "empathy-spell.h"
 #include "empathy-contact-list-store.h"
 #include "empathy-contact-list-view.h"
 #include "empathy-contact-menu.h"
+#include "empathy-input-text-view.h"
 #include "empathy-search-bar.h"
 #include "empathy-theme-manager.h"
 #include "empathy-smiley-manager.h"
 #define DEBUG_FLAG EMPATHY_DEBUG_CHAT
 #include <libempathy/empathy-debug.h>
 
-#define CHAT_DIR_CREATE_MODE  (S_IRUSR | S_IWUSR | S_IXUSR)
-#define CHAT_FILE_CREATE_MODE (S_IRUSR | S_IWUSR)
 #define IS_ENTER(v) (v == GDK_KEY_Return || v == GDK_KEY_ISO_Enter || v == GDK_KEY_KP_Enter)
-#define MAX_INPUT_HEIGHT 150
 #define COMPOSING_STOP_TIMEOUT 5
 
 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyChat)
@@ -87,7 +86,6 @@ struct _EmpathyChatPriv {
        TpHandleType       handle_type;
        gint               contacts_width;
        gboolean           has_input_vscroll;
-       gint               topic_width;
 
        /* TRUE if spell checking is enabled, FALSE otherwise.
         * This is to keep track of the last state of spell checking
@@ -101,6 +99,8 @@ struct _EmpathyChatPriv {
 
        /* Source func ID for update_misspelled_words () */
        guint              update_misspelled_words_id;
+       /* Source func ID for save_paned_pos_timeout () */
+       guint              save_paned_pos_id;
 
        GtkWidget         *widget;
        GtkWidget         *hpaned;
@@ -1110,7 +1110,9 @@ chat_state_changed_cb (EmpathyTpChat      *tp_chat,
 }
 
 static void
-chat_message_received (EmpathyChat *chat, EmpathyMessage *message)
+chat_message_received (EmpathyChat *chat,
+       EmpathyMessage *message,
+       gboolean pending)
 {
        EmpathyChatPriv *priv = GET_PRIV (chat);
        EmpathyContact  *sender;
@@ -1129,7 +1131,7 @@ chat_message_received (EmpathyChat *chat, EmpathyMessage *message)
                               chat);
 
        priv->unread_messages++;
-       g_signal_emit (chat, signals[NEW_MESSAGE], 0, message);
+       g_signal_emit (chat, signals[NEW_MESSAGE], 0, message, pending);
 }
 
 static void
@@ -1137,7 +1139,7 @@ chat_message_received_cb (EmpathyTpChat  *tp_chat,
                          EmpathyMessage *message,
                          EmpathyChat    *chat)
 {
-       chat_message_received (chat, message);
+       chat_message_received (chat, message, FALSE);
 }
 
 static void
@@ -1178,48 +1180,6 @@ chat_send_error_cb (EmpathyTpChat          *tp_chat,
        g_free (str);
 }
 
-/* WARNING: EXPLICIT CONTENT, keep away childrens!
- *
- * When a GtkLabel is set to wrap, it assume and hardcoded width. To change
- * that width we have to set a size request on the label... but that's not
- * possible because we want the window to be able to shrink, so we MUST request
- * width of 1. Note that the height of a wrapping label depends on its width.
- *
- * To work around that, here is what happens:
- * 1) size-request is first called, an hardcoded small width is requested by
- *    GtkLabel, which means also a too big height. We do nothing.
- * 2) size-allocate is called with the full width available, that's the width
- *    we really want to make wrap the label. We save that width and restart a
- *    size-request/size-allocate round.
- * 3) size-request is called a 2nd time, now we can tell the pango layout its
- *    width (we can't do that in step 2 because GtkLabel::size-request recreate
- *    the layout each time). When the layout has its width, we can know the
- *    height of the label and set its requisition. The width request is set to
- *    1px to make sure the window can shrink, the layout will fill all the
- *    available width anyway.
- */
-static void
-chat_topic_label_size_request_cb (GtkLabel *label,
-                                  GtkRequisition *requisition,
-                                  EmpathyChat *chat)
-{
-       EmpathyChatPriv *priv = GET_PRIV (chat);
-
-       if (gtk_label_get_line_wrap (label) && priv->topic_width > 0) {
-               PangoLayout *layout;
-               PangoRectangle rect;
-               gint ypad;
-
-               layout = gtk_label_get_layout (label);
-               pango_layout_set_width (layout, priv->topic_width * PANGO_SCALE);
-               pango_layout_get_extents (layout, NULL, &rect);
-               gtk_misc_get_padding (GTK_MISC (label), NULL, &ypad);
-
-               requisition->width = 1;
-               requisition->height = PANGO_PIXELS (rect.height) + ypad * 2;
-       }
-}
-
 static void
 chat_topic_label_size_allocate_cb (GtkLabel *label,
                                   GtkAllocation *allocation,
@@ -1228,8 +1188,6 @@ chat_topic_label_size_allocate_cb (GtkLabel *label,
        EmpathyChatPriv *priv = GET_PRIV (chat);
 
        if (!gtk_label_get_line_wrap (label)) {
-               priv->topic_width = -1;
-
                if (pango_layout_is_ellipsized (gtk_label_get_layout (label)))
                        gtk_widget_show (priv->expander_topic);
                else
@@ -1237,11 +1195,6 @@ chat_topic_label_size_allocate_cb (GtkLabel *label,
 
                return;
        }
-
-       if (priv->topic_width != allocation->width) {
-               priv->topic_width = allocation->width;
-               gtk_widget_queue_resize (GTK_WIDGET (label));
-       }
 }
 
 static void
@@ -1659,40 +1612,6 @@ chat_text_view_focus_in_event_cb (GtkWidget  *widget,
        return TRUE;
 }
 
-static gboolean
-chat_input_set_size_request_idle (gpointer sw)
-{
-       gtk_widget_set_size_request (sw, -1, MAX_INPUT_HEIGHT);
-
-       return FALSE;
-}
-
-static void
-chat_input_size_request_cb (GtkWidget      *widget,
-                           GtkRequisition *requisition,
-                           EmpathyChat    *chat)
-{
-       EmpathyChatPriv *priv = GET_PRIV (chat);
-       GtkWidget       *sw;
-
-       sw = gtk_widget_get_parent (widget);
-       if (requisition->height >= MAX_INPUT_HEIGHT && !priv->has_input_vscroll) {
-               g_idle_add (chat_input_set_size_request_idle, sw);
-               gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
-                                               GTK_POLICY_NEVER,
-                                               GTK_POLICY_ALWAYS);
-               priv->has_input_vscroll = TRUE;
-       }
-
-       if (requisition->height < MAX_INPUT_HEIGHT && priv->has_input_vscroll) {
-               gtk_widget_set_size_request (sw, -1, -1);
-               gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
-                                               GTK_POLICY_NEVER,
-                                               GTK_POLICY_NEVER);
-               priv->has_input_vscroll = FALSE;
-       }
-}
-
 static void
 chat_input_realize_cb (GtkWidget   *widget,
                       EmpathyChat *chat)
@@ -1896,7 +1815,7 @@ chat_spelling_build_add_to_dictionary_item (EmpathyChatSpell *chat_spell)
        g_assert (codes != NULL);
        if (g_list_length (codes) > 1) {
                /* translators: %s is the selected word */
-               label = g_strdup_printf(_("Add '%s' to Dictionary"),
+               label = g_strdup_printf (_("Add '%s' to Dictionary"),
                                        chat_spell->word);
                item = gtk_image_menu_item_new_with_mnemonic (label);
                g_free (label);
@@ -1933,7 +1852,7 @@ chat_spelling_build_add_to_dictionary_item (EmpathyChatSpell *chat_spell)
                g_assert (name != NULL);
                /* translators: first %s is the selected word,
                 * second %s is the language name of the target dictionary */
-               label = g_strdup_printf(_("Add '%s' to %s Dictionary"),
+               label = g_strdup_printf (_("Add '%s' to %s Dictionary"),
                                        chat_spell->word, name);
                item = gtk_image_menu_item_new_with_mnemonic (label);
                g_free (label);
@@ -2087,6 +2006,7 @@ chat_log_filter (TplEntry *log,
 
        for (; pending; pending = g_list_next (pending)) {
                if (empathy_message_equal (message, pending->data)) {
+                       g_object_unref (message);
                        return FALSE;
                }
        }
@@ -2113,7 +2033,7 @@ show_pending_messages (EmpathyChat *chat) {
 
        for (l = messages; l != NULL ; l = g_list_next (l)) {
                EmpathyMessage *message = EMPATHY_MESSAGE (l->data);
-               chat_message_received (chat, message);
+               chat_message_received (chat, message, TRUE);
        }
 }
 
@@ -2574,18 +2494,33 @@ conf_spell_checking_cb (GSettings *gsettings_chat,
        priv->spell_checking_enabled = spell_checker;
 }
 
+static gboolean
+save_paned_pos_timeout (gpointer data)
+{
+       EmpathyChat *self = data;
+       gint hpaned_pos;
+
+       hpaned_pos = gtk_paned_get_position (GTK_PANED (self->priv->hpaned));
+
+       g_settings_set_int (self->priv->gsettings_ui,
+                           EMPATHY_PREFS_UI_CHAT_WINDOW_PANED_POS,
+                           hpaned_pos);
+
+       return FALSE;
+}
+
 static gboolean
 chat_hpaned_pos_changed_cb (GtkWidget* hpaned,
                GParamSpec *spec,
                gpointer user_data)
 {
        EmpathyChat *chat = EMPATHY_CHAT (user_data);
-       gint hpaned_pos;
 
-       hpaned_pos = gtk_paned_get_position (GTK_PANED(hpaned));
-       g_settings_set_int (chat->priv->gsettings_ui,
-                           EMPATHY_PREFS_UI_CHAT_WINDOW_PANED_POS,
-                           hpaned_pos);
+       if (chat->priv->save_paned_pos_id != 0)
+               g_source_remove (chat->priv->save_paned_pos_id);
+
+       chat->priv->save_paned_pos_id = g_timeout_add_seconds (1,
+               save_paned_pos_timeout, chat);
 
        return TRUE;
 }
@@ -2618,7 +2553,6 @@ chat_create_ui (EmpathyChat *chat)
        empathy_builder_connect (gui, chat,
                "expander_topic", "notify::expanded", chat_topic_expander_activate_cb,
                "label_topic", "size-allocate", chat_topic_label_size_allocate_cb,
-               "label_topic", "size-request", chat_topic_label_size_request_cb,
                NULL);
 
        g_free (filename);
@@ -2639,20 +2573,11 @@ chat_create_ui (EmpathyChat *chat)
        gtk_widget_show (GTK_WIDGET (chat->view));
 
        /* Add input GtkTextView */
-       chat->input_text_view = g_object_new (GTK_TYPE_TEXT_VIEW,
-                                             "pixels-above-lines", 2,
-                                             "pixels-below-lines", 2,
-                                             "pixels-inside-wrap", 1,
-                                             "right-margin", 2,
-                                             "left-margin", 2,
-                                             "wrap-mode", GTK_WRAP_WORD_CHAR,
-                                             NULL);
+       chat->input_text_view = empathy_input_text_view_new ();
+
        g_signal_connect (chat->input_text_view, "key-press-event",
                          G_CALLBACK (chat_input_key_press_event_cb),
                          chat);
-       g_signal_connect (chat->input_text_view, "size-request",
-                         G_CALLBACK (chat_input_size_request_cb),
-                         chat);
        g_signal_connect (chat->input_text_view, "realize",
                          G_CALLBACK (chat_input_realize_cb),
                          chat);
@@ -2750,6 +2675,9 @@ chat_finalize (GObject *object)
        if (priv->update_misspelled_words_id != 0)
                g_source_remove (priv->update_misspelled_words_id);
 
+       if (priv->save_paned_pos_id != 0)
+               g_source_remove (priv->save_paned_pos_id);
+
        g_object_unref (priv->gsettings_chat);
        g_object_unref (priv->gsettings_ui);
 
@@ -2905,9 +2833,9 @@ empathy_chat_class_init (EmpathyChatClass *klass)
                              G_SIGNAL_RUN_LAST,
                              0,
                              NULL, NULL,
-                             g_cclosure_marshal_VOID__OBJECT,
+                             _empathy_marshal_VOID__OBJECT_BOOLEAN,
                              G_TYPE_NONE,
-                             1, EMPATHY_TYPE_MESSAGE);
+                             2, EMPATHY_TYPE_MESSAGE, G_TYPE_BOOLEAN);
 
        g_type_class_add_private (object_class, sizeof (EmpathyChatPriv));
 }