#include <gdk/gdkkeysyms.h>
#include <glib/gi18n.h>
#include <gtk/gtk.h>
-#include <glade/glade.h>
#include <libempathy/empathy-contact-manager.h>
+#include <libempathy/empathy-log-manager.h>
#include <libempathy/gossip-debug.h>
#include <libempathy/gossip-utils.h>
#include <libempathy/gossip-conf.h>
#include "gossip-geometry.h"
#include "gossip-preferences.h"
#include "gossip-spell.h"
-//#include "gossip-spell-dialog.h"
+#include "gossip-spell-dialog.h"
#include "gossip-ui-utils.h"
#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GOSSIP_TYPE_CHAT, GossipChatPriv))
struct _GossipChatPriv {
EmpathyContactManager *manager;
+ EmpathyLogManager *log_manager;
EmpathyTpChat *tp_chat;
GossipChatWindow *window;
-
GtkTooltips *tooltips;
guint composing_stop_timeout_id;
gboolean sensitive;
gchar *id;
GSList *sent_messages;
gint sent_messages_index;
+ GList *compositors;
+ guint scroll_idle_id;
+ gboolean first_tp_chat;
+ GossipTime time_joined;
/* Used to automatically shrink a window that has temporarily
* grown due to long input.
*/
GossipContact *contact,
TelepathyChannelChatState state,
GossipChat *chat);
+static void chat_add_logs (GossipChat *chat);
+static gboolean chat_scroll_down_idle_func (GossipChat *chat);
enum {
COMPOSING,
LAST_SIGNAL
};
-static guint chat_signals[LAST_SIGNAL] = { 0 };
+static guint signals[LAST_SIGNAL] = { 0 };
G_DEFINE_TYPE (GossipChat, gossip_chat, G_TYPE_OBJECT);
object_class->finalize = chat_finalize;
- chat_signals[COMPOSING] =
+ signals[COMPOSING] =
g_signal_new ("composing",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_TYPE_NONE,
1, G_TYPE_BOOLEAN);
- chat_signals[NEW_MESSAGE] =
+ signals[NEW_MESSAGE] =
g_signal_new ("new-message",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_TYPE_NONE,
2, GOSSIP_TYPE_MESSAGE, G_TYPE_BOOLEAN);
- chat_signals[NAME_CHANGED] =
+ signals[NAME_CHANGED] =
g_signal_new ("name-changed",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_TYPE_NONE,
1, G_TYPE_POINTER);
- chat_signals[STATUS_CHANGED] =
+ signals[STATUS_CHANGED] =
g_signal_new ("status-changed",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
priv = GET_PRIV (chat);
priv->manager = empathy_contact_manager_new ();
- priv->tooltips = gtk_tooltips_new ();
+ priv->log_manager = empathy_log_manager_new ();
+ priv->tooltips = g_object_ref_sink (gtk_tooltips_new ());
priv->default_window_height = -1;
priv->vscroll_visible = FALSE;
priv->sensitive = TRUE;
priv->sent_messages = NULL;
priv->sent_messages_index = -1;
+ priv->first_tp_chat = TRUE;
g_signal_connect (chat->input_text_view,
"key_press_event",
g_slist_foreach (priv->sent_messages, (GFunc) g_free, NULL);
g_slist_free (priv->sent_messages);
+ g_list_foreach (priv->compositors, (GFunc) g_object_unref, NULL);
+ g_list_free (priv->compositors);
+
chat_composing_remove_timeout (chat);
g_object_unref (chat->account);
g_object_unref (priv->manager);
+ g_object_unref (priv->log_manager);
+ g_object_unref (priv->tooltips);
if (priv->tp_chat) {
g_object_unref (priv->tp_chat);
}
+ if (priv->scroll_idle_id) {
+ g_source_remove (priv->scroll_idle_id);
+ }
+
g_free (priv->id);
G_OBJECT_CLASS (gossip_chat_parent_class)->finalize (object);
GossipChat *chat)
{
GossipChatPriv *priv;
- GtkWidget *widget;
priv = GET_PRIV (chat);
g_object_unref (priv->tp_chat);
priv->tp_chat = NULL;
}
+ priv->sensitive = FALSE;
gossip_chat_view_append_event (chat->view, _("Disconnected"));
+ gtk_widget_set_sensitive (chat->input_text_view, FALSE);
- widget = gossip_chat_get_widget (chat);
- gtk_widget_set_sensitive (widget, FALSE);
- priv->sensitive = FALSE;
+ if (GOSSIP_CHAT_GET_CLASS (chat)->set_tp_chat) {
+ GOSSIP_CHAT_GET_CLASS (chat)->set_tp_chat (chat, NULL);
+ }
}
static void
chat_send (GossipChat *chat,
const gchar *msg)
{
- GossipChatPriv *priv;
- //GossipLogManager *log_manager;
- GossipMessage *message;
- GossipContact *own_contact;
+ GossipChatPriv *priv;
+ GossipMessage *message;
priv = GET_PRIV (chat);
return;
}
- /* FIXME: gossip_app_set_not_away ();*/
+ /* FIXME: add here something to let group/privrate chat handle
+ * some special messages */
- own_contact = gossip_chat_get_own_contact (chat);
message = gossip_message_new (msg);
- gossip_message_set_sender (message, own_contact);
-
- //FIXME: log_manager = gossip_session_get_log_manager (gossip_app_get_session ());
- //gossip_log_message_for_contact (log_manager, message, FALSE);
empathy_tp_chat_send (priv->tp_chat, message);
GossipChat *chat)
{
GossipChatPriv *priv;
- //GossipLogManager *log_manager;
- GossipContact *sender;
+ GossipContact *sender;
+ GossipTime timestamp;
priv = GET_PRIV (chat);
gossip_debug (DEBUG_DOMAIN, "Appending message ('%s')",
gossip_contact_get_name (sender));
-/*FIXME:
- log_manager = gossip_session_get_log_manager (gossip_app_get_session ());
- gossip_log_message_for_contact (log_manager, message, TRUE);
-*/
+ /* Log the message only if it's not backlog */
+ timestamp = gossip_message_get_timestamp (message);
+ if (timestamp >= priv->time_joined) {
+ empathy_log_manager_add_message (priv->log_manager,
+ gossip_chat_get_id (chat),
+ gossip_chat_is_group_chat (chat),
+ message);
+ }
+
gossip_chat_view_append_message (chat->view, message);
if (gossip_chat_should_play_sound (chat)) {
// FIXME: gossip_sound_play (GOSSIP_SOUND_CHAT);
}
- g_signal_emit_by_name (chat, "new-message", message, FALSE);
+ g_signal_emit (chat, signals[NEW_MESSAGE], 0, message, FALSE);
}
void
}
/* Catch enter but not ctrl/shift-enter */
- if (IS_ENTER (event->keyval) && !(event->state & GDK_SHIFT_MASK)) {
+ if (IS_ENTER (event->keyval) && !(event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK))) {
GtkTextView *view;
/* This is to make sure that kinput2 gets the enter. And if
chat_text_check_word_spelling_cb (GtkMenuItem *menuitem,
GossipChatSpell *chat_spell)
{
-/*FIXME: gossip_spell_dialog_show (chat_spell->chat,
+ gossip_spell_dialog_show (chat_spell->chat,
chat_spell->start,
chat_spell->end,
- chat_spell->word);*/
+ chat_spell->word);
}
static GossipChatSpell *
TelepathyChannelChatState state,
GossipChat *chat)
{
- /* FIXME: not yet implemented */
+ GossipChatPriv *priv;
+ GList *l;
+ gboolean was_composing;
+
+ priv = GET_PRIV (chat);
+
+ if (gossip_contact_is_user (contact)) {
+ /* We don't care about our own chat state */
+ return;
+ }
+
+ was_composing = (priv->compositors != NULL);
+
+ /* Find the contact in the list. After that l is the list elem or NULL */
+ for (l = priv->compositors; l; l = l->next) {
+ if (gossip_contact_equal (contact, l->data)) {
+ break;
+ }
+ }
+
+ switch (state) {
+ case TP_CHANNEL_CHAT_STATE_GONE:
+ case TP_CHANNEL_CHAT_STATE_INACTIVE:
+ case TP_CHANNEL_CHAT_STATE_ACTIVE:
+ /* Contact is not composing */
+ if (l) {
+ priv->compositors = g_list_remove_link (priv->compositors, l);
+ g_object_unref (l->data);
+ g_list_free1 (l);
+ }
+ break;
+ case TP_CHANNEL_CHAT_STATE_PAUSED:
+ case TP_CHANNEL_CHAT_STATE_COMPOSING:
+ /* Contact is composing */
+ if (!l) {
+ priv->compositors = g_list_prepend (priv->compositors,
+ g_object_ref (contact));
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ gossip_debug (DEBUG_DOMAIN, "Was composing: %s now composing: %s",
+ was_composing ? "yes" : "no",
+ priv->compositors ? "yes" : "no");
+
+ if ((was_composing && !priv->compositors) ||
+ (!was_composing && priv->compositors)) {
+ /* Composing state changed */
+ g_signal_emit (chat, signals[COMPOSING], 0,
+ priv->compositors != NULL);
+ }
+}
+
+static void
+chat_add_logs (GossipChat *chat)
+{
+ GossipChatPriv *priv;
+ GList *messages, *l;
+ guint num_messages;
+ guint i;
+
+ priv = GET_PRIV (chat);
+
+ /* Do not display backlog for chatrooms */
+ if (gossip_chat_is_group_chat (chat)) {
+ return;
+ }
+
+ /* Turn off scrolling temporarily */
+ gossip_chat_view_scroll (chat->view, FALSE);
+
+ /* Add messages from last conversation */
+ messages = empathy_log_manager_get_last_messages (priv->log_manager,
+ chat->account,
+ gossip_chat_get_id (chat),
+ gossip_chat_is_group_chat (chat));
+ num_messages = g_list_length (messages);
+
+ for (l = messages, i = 0; l; l = l->next, i++) {
+ GossipMessage *message;
+
+ message = l->data;
+
+ /* Only add 10 last messages */
+ if (num_messages - i > 10) {
+ g_object_unref (message);
+ continue;
+ }
+
+
+ gossip_chat_view_append_message (chat->view, message);
+ g_object_unref (message);
+ }
+ g_list_free (messages);
+
+ /* Turn back on scrolling */
+ gossip_chat_view_scroll (chat->view, TRUE);
+
+ /* Scroll to the most recent messages, we reference the chat
+ * for the duration of the scroll func.
+ */
+ priv->scroll_idle_id = g_idle_add ((GSourceFunc) chat_scroll_down_idle_func,
+ g_object_ref (chat));
+}
+
+/* Scroll down after the back-log has been received. */
+static gboolean
+chat_scroll_down_idle_func (GossipChat *chat)
+{
+ GossipChatPriv *priv;
+
+ priv = GET_PRIV (chat);
+
+ gossip_chat_scroll_down (chat);
+ g_object_unref (chat);
+
+ priv->scroll_idle_id = 0;
+
+ return FALSE;
}
gboolean
return NULL;
}
-GossipContact *
-gossip_chat_get_contact (GossipChat *chat)
-{
- g_return_val_if_fail (GOSSIP_IS_CHAT (chat), NULL);
-
- if (GOSSIP_CHAT_GET_CLASS (chat)->get_contact) {
- return GOSSIP_CHAT_GET_CLASS (chat)->get_contact (chat);
- }
-
- return NULL;
-}
-GossipContact *
-gossip_chat_get_own_contact (GossipChat *chat)
-{
- GossipChatPriv *priv;
-
- g_return_val_if_fail (GOSSIP_IS_CHAT (chat), NULL);
-
- priv = GET_PRIV (chat);
-
- return empathy_contact_manager_get_own (priv->manager, chat->account);
-}
-
GtkWidget *
gossip_chat_get_widget (GossipChat *chat)
{
return (priv->tp_chat != NULL);
}
-gboolean
-gossip_chat_get_show_contacts (GossipChat *chat)
-{
- g_return_val_if_fail (GOSSIP_IS_CHAT (chat), FALSE);
-
- if (GOSSIP_CHAT_GET_CLASS (chat)->get_show_contacts) {
- return GOSSIP_CHAT_GET_CLASS (chat)->get_show_contacts (chat);
- }
-
- return FALSE;
-}
-
-void
-gossip_chat_set_show_contacts (GossipChat *chat,
- gboolean show)
-{
- g_return_if_fail (GOSSIP_IS_CHAT (chat));
-
- if (GOSSIP_CHAT_GET_CLASS (chat)->set_show_contacts) {
- GOSSIP_CHAT_GET_CLASS (chat)->set_show_contacts (chat, show);
- }
-}
-
void
gossip_chat_save_geometry (GossipChat *chat,
gint x,
EmpathyTpChat *tp_chat)
{
GossipChatPriv *priv;
- GtkWidget *widget;
g_return_if_fail (GOSSIP_IS_CHAT (chat));
g_return_if_fail (EMPATHY_IS_TP_CHAT (tp_chat));
g_free (priv->id);
priv->tp_chat = g_object_ref (tp_chat);
priv->id = g_strdup (empathy_tp_chat_get_id (tp_chat));
+ priv->time_joined = gossip_time_get_current ();
+
+ if (priv->first_tp_chat) {
+ chat_add_logs (chat);
+ priv->first_tp_chat = FALSE;
+ }
g_signal_connect (tp_chat, "message-received",
G_CALLBACK (chat_message_received_cb),
empathy_tp_chat_request_pending (tp_chat);
if (!priv->sensitive) {
- widget = gossip_chat_get_widget (chat);
- gtk_widget_set_sensitive (widget, TRUE);
+ gtk_widget_set_sensitive (chat->input_text_view, TRUE);
gossip_chat_view_append_event (chat->view, _("Connected"));
priv->sensitive = TRUE;
}
+
+ if (GOSSIP_CHAT_GET_CLASS (chat)->set_tp_chat) {
+ GOSSIP_CHAT_GET_CLASS (chat)->set_tp_chat (chat, tp_chat);
+ }
+
}
const gchar *
gboolean
gossip_chat_should_highlight_nick (GossipMessage *message)
{
- GossipContact *my_contact;
+ GossipContact *contact;
const gchar *msg, *to;
gchar *cf_msg, *cf_to;
gchar *ch;
return FALSE;
}
- my_contact = gossip_get_own_contact_from_contact (gossip_message_get_sender (message));
- to = gossip_contact_get_name (my_contact);
+ contact = gossip_message_get_receiver (message);
+ if (!contact || !gossip_contact_is_user (contact)) {
+ return FALSE;
+ }
+
+ to = gossip_contact_get_name (contact);
if (!to) {
return FALSE;
}