#include <glib/gi18n.h>
#include <gtk/gtk.h>
+#include <libmissioncontrol/mission-control.h>
+
#include <libempathy/empathy-contact-manager.h>
#include <libempathy/empathy-log-manager.h>
#include <libempathy/empathy-debug.h>
#include <libempathy/empathy-utils.h>
-#include <libempathy/empathy-conf.h>
#include <libempathy/empathy-marshal.h>
#include "empathy-chat.h"
#include "empathy-chat-window.h"
#include "empathy-geometry.h"
+#include "empathy-conf.h"
#include "empathy-preferences.h"
#include "empathy-spell.h"
#include "empathy-spell-dialog.h"
#define COMPOSING_STOP_TIMEOUT 5
struct _EmpathyChatPriv {
- EmpathyContactManager *manager;
EmpathyLogManager *log_manager;
EmpathyTpChat *tp_chat;
- EmpathyChatWindow *window;
- GtkTooltips *tooltips;
+ EmpathyChatWindow *window;
+ McAccount *account;
+ MissionControl *mc;
guint composing_stop_timeout_id;
gboolean sensitive;
gchar *id;
GList *compositors;
guint scroll_idle_id;
gboolean first_tp_chat;
- EmpathyTime last_log_timestamp;
+ time_t last_log_timestamp;
+ gboolean is_first_char;
/* Used to automatically shrink a window that has temporarily
* grown due to long input.
*/
GtkTextIter end;
} EmpathyChatSpell;
-static void empathy_chat_class_init (EmpathyChatClass *klass);
-static void empathy_chat_init (EmpathyChat *chat);
-static void chat_finalize (GObject *object);
-static void chat_destroy_cb (EmpathyTpChat *tp_chat,
- EmpathyChat *chat);
-static void chat_send (EmpathyChat *chat,
- const gchar *msg);
-static void chat_input_text_view_send (EmpathyChat *chat);
-static void chat_message_received_cb (EmpathyTpChat *tp_chat,
- EmpathyMessage *message,
- EmpathyChat *chat);
-static void chat_send_error_cb (EmpathyTpChat *tp_chat,
- EmpathyMessage *message,
- TelepathyChannelTextSendError error_code,
- EmpathyChat *chat);
-void chat_sent_message_add (EmpathyChat *chat,
- const gchar *str);
-const gchar * chat_sent_message_get_next (EmpathyChat *chat);
-const gchar * chat_sent_message_get_last (EmpathyChat *chat);
-static gboolean chat_input_key_press_event_cb (GtkWidget *widget,
- GdkEventKey *event,
- EmpathyChat *chat);
-static void chat_input_text_buffer_changed_cb (GtkTextBuffer *buffer,
- EmpathyChat *chat);
-static gboolean chat_text_view_focus_in_event_cb (GtkWidget *widget,
- GdkEvent *event,
- EmpathyChat *chat);
-static void chat_text_view_scroll_hide_cb (GtkWidget *widget,
- EmpathyChat *chat);
-static void chat_text_view_size_allocate_cb (GtkWidget *widget,
- GtkAllocation *allocation,
- EmpathyChat *chat);
-static void chat_text_view_realize_cb (GtkWidget *widget,
- EmpathyChat *chat);
-static void chat_text_populate_popup_cb (GtkTextView *view,
- GtkMenu *menu,
- EmpathyChat *chat);
-static void chat_text_check_word_spelling_cb (GtkMenuItem *menuitem,
- EmpathyChatSpell *chat_spell);
-static EmpathyChatSpell *chat_spell_new (EmpathyChat *chat,
- const gchar *word,
- GtkTextIter start,
- GtkTextIter end);
-static void chat_spell_free (EmpathyChatSpell *chat_spell);
-static void chat_composing_start (EmpathyChat *chat);
-static void chat_composing_stop (EmpathyChat *chat);
-static void chat_composing_remove_timeout (EmpathyChat *chat);
-static gboolean chat_composing_stop_timeout_cb (EmpathyChat *chat);
-static void chat_state_changed_cb (EmpathyTpChat *tp_chat,
- EmpathyContact *contact,
- TelepathyChannelChatState state,
- EmpathyChat *chat);
-static void chat_add_logs (EmpathyChat *chat);
-static gboolean chat_scroll_down_idle_func (EmpathyChat *chat);
+static void empathy_chat_class_init (EmpathyChatClass *klass);
+static void empathy_chat_init (EmpathyChat *chat);
+static void chat_finalize (GObject *object);
+static void chat_destroy_cb (EmpathyTpChat *tp_chat,
+ EmpathyChat *chat);
+static void chat_send (EmpathyChat *chat,
+ const gchar *msg);
+static void chat_input_text_view_send (EmpathyChat *chat);
+static void chat_message_received_cb (EmpathyTpChat *tp_chat,
+ EmpathyMessage *message,
+ EmpathyChat *chat);
+static void chat_send_error_cb (EmpathyTpChat *tp_chat,
+ EmpathyMessage *message,
+ TpChannelTextSendError error_code,
+ EmpathyChat *chat);
+static void chat_sent_message_add (EmpathyChat *chat,
+ const gchar *str);
+static const gchar * chat_sent_message_get_next (EmpathyChat *chat);
+static const gchar * chat_sent_message_get_last (EmpathyChat *chat);
+static gboolean chat_input_key_press_event_cb (GtkWidget *widget,
+ GdkEventKey *event,
+ EmpathyChat *chat);
+static void chat_input_text_buffer_changed_cb (GtkTextBuffer *buffer,
+ EmpathyChat *chat);
+static gboolean chat_text_view_focus_in_event_cb (GtkWidget *widget,
+ GdkEvent *event,
+ EmpathyChat *chat);
+static void chat_text_view_scroll_hide_cb (GtkWidget *widget,
+ EmpathyChat *chat);
+static void chat_text_view_size_allocate_cb (GtkWidget *widget,
+ GtkAllocation *allocation,
+ EmpathyChat *chat);
+static void chat_text_view_realize_cb (GtkWidget *widget,
+ EmpathyChat *chat);
+static void chat_text_populate_popup_cb (GtkTextView *view,
+ GtkMenu *menu,
+ EmpathyChat *chat);
+static void chat_text_check_word_spelling_cb (GtkMenuItem *menuitem,
+ EmpathyChatSpell *chat_spell);
+static EmpathyChatSpell *chat_spell_new (EmpathyChat *chat,
+ const gchar *word,
+ GtkTextIter start,
+ GtkTextIter end);
+static void chat_spell_free (EmpathyChatSpell *chat_spell);
+static void chat_composing_start (EmpathyChat *chat);
+static void chat_composing_stop (EmpathyChat *chat);
+static void chat_composing_remove_timeout (EmpathyChat *chat);
+static gboolean chat_composing_stop_timeout_cb (EmpathyChat *chat);
+static void chat_state_changed_cb (EmpathyTpChat *tp_chat,
+ EmpathyContact *contact,
+ TpChannelChatState state,
+ EmpathyChat *chat);
+static void chat_add_logs (EmpathyChat *chat);
+static gboolean chat_scroll_down_idle_func (EmpathyChat *chat);
enum {
COMPOSING,
LAST_SIGNAL
};
+enum {
+ PROP_0,
+ PROP_TP_CHAT
+};
+
static guint signals[LAST_SIGNAL] = { 0 };
G_DEFINE_TYPE (EmpathyChat, empathy_chat, G_TYPE_OBJECT);
+static void
+chat_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EmpathyChatPriv *priv = GET_PRIV (object);
+
+ switch (param_id) {
+ case PROP_TP_CHAT:
+ g_value_set_object (value, priv->tp_chat);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ };
+}
+
+static void
+chat_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EmpathyChat *chat = EMPATHY_CHAT (object);
+
+ switch (param_id) {
+ case PROP_TP_CHAT:
+ empathy_chat_set_tp_chat (chat,
+ EMPATHY_TP_CHAT (g_value_get_object (value)));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ };
+}
+
+static void
+chat_status_changed_cb (MissionControl *mc,
+ TpConnectionStatus status,
+ McPresence presence,
+ TpConnectionStatusReason reason,
+ const gchar *unique_name,
+ EmpathyChat *chat)
+{
+ EmpathyChatPriv *priv = GET_PRIV (chat);
+ McAccount *account;
+
+ account = mc_account_lookup (unique_name);
+
+ if (status == TP_CONNECTION_STATUS_CONNECTED && !priv->tp_chat &&
+ empathy_account_equal (account, priv->account)) {
+ TpHandleType handle_type;
+
+ empathy_debug (DEBUG_DOMAIN,
+ "Account reconnected, request a new Text channel");
+
+ if (empathy_chat_is_group_chat (chat)) {
+ handle_type = TP_HANDLE_TYPE_ROOM;
+ } else {
+ handle_type = TP_HANDLE_TYPE_CONTACT;
+ }
+
+ mission_control_request_channel_with_string_handle (mc,
+ priv->account,
+ TP_IFACE_CHANNEL_TYPE_TEXT,
+ priv->id,
+ handle_type,
+ NULL, NULL);
+ }
+
+ g_object_unref (account);
+}
+
static void
empathy_chat_class_init (EmpathyChatClass *klass)
{
object_class = G_OBJECT_CLASS (klass);
object_class->finalize = chat_finalize;
+ object_class->get_property = chat_get_property;
+ object_class->set_property = chat_set_property;
+
+ g_object_class_install_property (object_class,
+ PROP_TP_CHAT,
+ g_param_spec_object ("tp-chat",
+ "Empathy tp chat",
+ "The tp chat object",
+ EMPATHY_TYPE_TP_CHAT,
+ G_PARAM_CONSTRUCT |
+ G_PARAM_READWRITE));
signals[COMPOSING] =
g_signal_new ("composing",
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
- empathy_marshal_VOID__OBJECT_BOOLEAN,
+ _empathy_marshal_VOID__OBJECT_BOOLEAN,
G_TYPE_NONE,
2, EMPATHY_TYPE_MESSAGE, G_TYPE_BOOLEAN);
static void
empathy_chat_init (EmpathyChat *chat)
{
- EmpathyChatPriv *priv;
+ EmpathyChatPriv *priv = GET_PRIV (chat);
GtkTextBuffer *buffer;
chat->view = empathy_chat_view_new ();
chat->input_text_view = gtk_text_view_new ();
- chat->is_first_char = TRUE;
+ priv->is_first_char = TRUE;
g_object_set (chat->input_text_view,
"pixels-above-lines", 2,
"wrap-mode", GTK_WRAP_WORD_CHAR,
NULL);
- priv = GET_PRIV (chat);
-
- priv->manager = empathy_contact_manager_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;
+ priv->mc = empathy_mission_control_new ();
+
+ dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->mc), "AccountStatusChanged",
+ G_CALLBACK (chat_status_changed_cb),
+ chat, NULL);
g_signal_connect (chat->input_text_view,
"key_press_event",
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);
+
+ dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->mc), "AccountStatusChanged",
+ G_CALLBACK (chat_status_changed_cb),
+ chat);
+ g_object_unref (priv->mc);
+
if (priv->tp_chat) {
g_object_unref (priv->tp_chat);
}
+ if (priv->account) {
+ g_object_unref (priv->account);
+ }
+
if (priv->scroll_idle_id) {
g_source_remove (priv->scroll_idle_id);
}
g_free (msg);
- chat->is_first_char = TRUE;
+ priv->is_first_char = TRUE;
}
static void
{
EmpathyChatPriv *priv;
EmpathyContact *sender;
- EmpathyTime timestamp;
+ time_t timestamp;
priv = GET_PRIV (chat);
// FIXME: empathy_sound_play (EMPATHY_SOUND_CHAT);
}
+ /* We received a message so the contact is no more composing */
+ chat_state_changed_cb (tp_chat, sender,
+ TP_CHANNEL_CHAT_STATE_ACTIVE,
+ chat);
+
g_signal_emit (chat, signals[NEW_MESSAGE], 0, message, FALSE);
}
static void
-chat_send_error_cb (EmpathyTpChat *tp_chat,
- EmpathyMessage *message,
- TelepathyChannelTextSendError error_code,
- EmpathyChat *chat)
+chat_send_error_cb (EmpathyTpChat *tp_chat,
+ EmpathyMessage *message,
+ TpChannelTextSendError error_code,
+ EmpathyChat *chat)
{
const gchar *error;
gchar *str;
g_free (str);
}
-void
+static void
chat_sent_message_add (EmpathyChat *chat,
const gchar *str)
{
priv->sent_messages_index = -1;
}
-const gchar *
+static const gchar *
chat_sent_message_get_next (EmpathyChat *chat)
{
EmpathyChatPriv *priv;
return g_slist_nth_data (priv->sent_messages, priv->sent_messages_index);
}
-const gchar *
+static const gchar *
chat_sent_message_get_last (EmpathyChat *chat)
{
EmpathyChatPriv *priv;
static gboolean
chat_input_key_press_event_cb (GtkWidget *widget,
GdkEventKey *event,
- EmpathyChat *chat)
+ EmpathyChat *chat)
{
EmpathyChatPriv *priv;
GtkAdjustment *adj;
priv = GET_PRIV (chat);
- if (event->keyval == GDK_Tab && !(event->state & GDK_CONTROL_MASK)) {
- return TRUE;
- }
-
/* Catch ctrl+up/down so we can traverse messages we sent */
if ((event->state & GDK_CONTROL_MASK) &&
(event->keyval == GDK_Up ||
}
/* Catch enter but not ctrl/shift-enter */
- if (IS_ENTER (event->keyval) && !(event->state & (GDK_SHIFT_MASK | GDK_CONTROL_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
text_view_sw = gtk_widget_get_parent (GTK_WIDGET (chat->view));
- if (IS_ENTER (event->keyval) && (event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK))) {
- /* Newline for shift-enter. */
+ if (IS_ENTER (event->keyval) &&
+ (event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK))) {
+ /* Newline for shift/control-enter. */
return FALSE;
}
- else if ((event->state & GDK_CONTROL_MASK) != GDK_CONTROL_MASK &&
+ else if (!(event->state & GDK_CONTROL_MASK) &&
event->keyval == GDK_Page_Up) {
adj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (text_view_sw));
gtk_adjustment_set_value (adj, adj->value - adj->page_size);
return TRUE;
}
+ if (EMPATHY_CHAT_GET_CLASS (chat)->key_press_event) {
+ return EMPATHY_CHAT_GET_CLASS (chat)->key_press_event (chat, event);
+ }
+
return FALSE;
}
EMPATHY_PREFS_CHAT_SPELL_CHECKER_ENABLED,
&spell_checker);
- if (chat->is_first_char) {
+ if (priv->is_first_char) {
GtkRequisition req;
gint window_height;
GtkWidget *dialog;
priv->last_input_height = req.height;
priv->padding_height = window_height - req.height - allocation->height;
- chat->is_first_char = FALSE;
+ priv->is_first_char = FALSE;
}
gtk_text_buffer_get_start_iter (buffer, &start);
smiley_menu = empathy_chat_view_get_smiley_menu (
G_CALLBACK (chat_insert_smiley_activate_cb),
- chat,
- priv->tooltips);
+ chat);
gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), smiley_menu);
/* Add the spell check menu item. */
}
static void
-chat_state_changed_cb (EmpathyTpChat *tp_chat,
- EmpathyContact *contact,
- TelepathyChannelChatState state,
- EmpathyChat *chat)
+chat_state_changed_cb (EmpathyTpChat *tp_chat,
+ EmpathyContact *contact,
+ TpChannelChatState state,
+ EmpathyChat *chat)
{
EmpathyChatPriv *priv;
GList *l;
/* Add messages from last conversation */
messages = empathy_log_manager_get_last_messages (priv->log_manager,
- chat->account,
+ priv->account,
empathy_chat_get_id (chat),
empathy_chat_is_group_chat (chat));
num_messages = g_list_length (messages);
chat);
g_object_unref (priv->tp_chat);
}
+ if (priv->account) {
+ g_object_unref (priv->account);
+ }
g_free (priv->id);
priv->tp_chat = g_object_ref (tp_chat);
priv->id = g_strdup (empathy_tp_chat_get_id (tp_chat));
+ priv->account = g_object_ref (empathy_tp_chat_get_account (tp_chat));
if (priv->first_tp_chat) {
chat_add_logs (chat);
EMPATHY_CHAT_GET_CLASS (chat)->set_tp_chat (chat, tp_chat);
}
+ g_object_notify (G_OBJECT (chat), "tp-chat");
}
const gchar *
return priv->id;
}
+McAccount *
+empathy_chat_get_account (EmpathyChat *chat)
+{
+ EmpathyChatPriv *priv = GET_PRIV (chat);
+
+ return priv->account;
+}
+
void
empathy_chat_clear (EmpathyChat *chat)
{