diff options
Diffstat (limited to 'libempathy-gtk/empathy-chat.c')
-rw-r--r-- | libempathy-gtk/empathy-chat.c | 1052 |
1 files changed, 492 insertions, 560 deletions
diff --git a/libempathy-gtk/empathy-chat.c b/libempathy-gtk/empathy-chat.c index 0d632faf7..9c6b61d27 100644 --- a/libempathy-gtk/empathy-chat.c +++ b/libempathy-gtk/empathy-chat.c @@ -81,6 +81,10 @@ struct _EmpathyChatPriv { GList *backlog_messages; gboolean is_first_char; guint block_events_timeout_id; + TpHandleType handle_type; + gchar *name; + gchar *tooltip; + const gchar *icon_name; /* Used to automatically shrink a window that has temporarily * grown due to long input. */ @@ -90,80 +94,22 @@ struct _EmpathyChatPriv { gboolean vscroll_visible; }; -typedef struct { - EmpathyChat *chat; - gchar *word; - - GtkTextIter start; - 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, - 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); +static void empathy_chat_class_init (EmpathyChatClass *klass); +static void empathy_chat_init (EmpathyChat *chat); enum { COMPOSING, NEW_MESSAGE, - NAME_CHANGED, - STATUS_CHANGED, LAST_SIGNAL }; enum { PROP_0, - PROP_TP_CHAT + PROP_TP_CHAT, + PROP_NAME, + PROP_TOOLTIP, + PROP_ICON_NAME, + PROP_WIDGET }; static guint signals[LAST_SIGNAL] = { 0 }; @@ -182,6 +128,18 @@ chat_get_property (GObject *object, case PROP_TP_CHAT: g_value_set_object (value, priv->tp_chat); break; + case PROP_NAME: + g_value_set_string (value, priv->name); + break; + case PROP_TOOLTIP: + g_value_set_string (value, priv->tooltip); + break; + case PROP_ICON_NAME: + g_value_set_string (value, priv->icon_name); + break; + case PROP_WIDGET: + g_value_set_object (value, priv->widget); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); break; @@ -221,23 +179,15 @@ chat_status_changed_cb (MissionControl *mc, 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_account_equal (account, priv->account) && + priv->handle_type != 0) { 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, + priv->handle_type, NULL, NULL); } @@ -245,136 +195,63 @@ chat_status_changed_cb (MissionControl *mc, } static void -empathy_chat_class_init (EmpathyChatClass *klass) +chat_composing_remove_timeout (EmpathyChat *chat) { - GObjectClass *object_class; - - 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; + EmpathyChatPriv *priv; - 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)); + priv = GET_PRIV (chat); - signals[COMPOSING] = - g_signal_new ("composing", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__BOOLEAN, - G_TYPE_NONE, - 1, G_TYPE_BOOLEAN); + if (priv->composing_stop_timeout_id) { + g_source_remove (priv->composing_stop_timeout_id); + priv->composing_stop_timeout_id = 0; + } +} - signals[NEW_MESSAGE] = - g_signal_new ("new-message", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - _empathy_gtk_marshal_VOID__OBJECT_BOOLEAN, - G_TYPE_NONE, - 2, EMPATHY_TYPE_MESSAGE, G_TYPE_BOOLEAN); +static gboolean +chat_composing_stop_timeout_cb (EmpathyChat *chat) +{ + EmpathyChatPriv *priv; - signals[NAME_CHANGED] = - g_signal_new ("name-changed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, - 1, G_TYPE_POINTER); + priv = GET_PRIV (chat); - signals[STATUS_CHANGED] = - g_signal_new ("status-changed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); + priv->composing_stop_timeout_id = 0; + empathy_tp_chat_set_state (priv->tp_chat, + TP_CHANNEL_CHAT_STATE_PAUSED); - g_type_class_add_private (object_class, sizeof (EmpathyChatPriv)); + return FALSE; } static void -empathy_chat_init (EmpathyChat *chat) +chat_composing_start (EmpathyChat *chat) { - EmpathyChatPriv *priv = GET_PRIV (chat); - GtkTextBuffer *buffer; - - chat->view = empathy_chat_view_new (); - chat->input_text_view = gtk_text_view_new (); - - priv->is_first_char = TRUE; - - g_object_set (chat->input_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); - - priv->log_manager = empathy_log_manager_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); + EmpathyChatPriv *priv; - g_signal_connect (chat->input_text_view, - "key_press_event", - G_CALLBACK (chat_input_key_press_event_cb), - chat); + priv = GET_PRIV (chat); - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (chat->input_text_view)); - g_signal_connect (buffer, - "changed", - G_CALLBACK (chat_input_text_buffer_changed_cb), - chat); - g_signal_connect (chat->view, - "focus_in_event", - G_CALLBACK (chat_text_view_focus_in_event_cb), - chat); + if (priv->composing_stop_timeout_id) { + /* Just restart the timeout */ + chat_composing_remove_timeout (chat); + } else { + empathy_tp_chat_set_state (priv->tp_chat, + TP_CHANNEL_CHAT_STATE_COMPOSING); + } - g_signal_connect (chat->input_text_view, - "size_allocate", - G_CALLBACK (chat_text_view_size_allocate_cb), - chat); + priv->composing_stop_timeout_id = g_timeout_add_seconds ( + COMPOSING_STOP_TIMEOUT, + (GSourceFunc) chat_composing_stop_timeout_cb, + chat); +} - g_signal_connect (chat->input_text_view, - "realize", - G_CALLBACK (chat_text_view_realize_cb), - chat); +static void +chat_composing_stop (EmpathyChat *chat) +{ + EmpathyChatPriv *priv; - g_signal_connect (GTK_TEXT_VIEW (chat->input_text_view), - "populate_popup", - G_CALLBACK (chat_text_populate_popup_cb), - chat); + priv = GET_PRIV (chat); - /* create misspelt words identification tag */ - gtk_text_buffer_create_tag (buffer, - "misspelled", - "underline", PANGO_UNDERLINE_ERROR, - NULL); + chat_composing_remove_timeout (chat); + empathy_tp_chat_set_state (priv->tp_chat, + TP_CHANNEL_CHAT_STATE_ACTIVE); } static void @@ -420,6 +297,8 @@ chat_finalize (GObject *object) } g_free (priv->id); + g_free (priv->name); + g_free (priv->tooltip); G_OBJECT_CLASS (empathy_chat_parent_class)->finalize (object); } @@ -444,10 +323,97 @@ chat_destroy_cb (EmpathyTpChat *tp_chat, if (priv->block_events_timeout_id != 0) { g_source_remove (priv->block_events_timeout_id); } +} + +static void +chat_sent_message_add (EmpathyChat *chat, + const gchar *str) +{ + EmpathyChatPriv *priv; + GSList *list; + GSList *item; + + priv = GET_PRIV (chat); + + /* Save the sent message in our repeat buffer */ + list = priv->sent_messages; + + /* Remove any other occurances of this msg */ + while ((item = g_slist_find_custom (list, str, (GCompareFunc) strcmp)) != NULL) { + list = g_slist_remove_link (list, item); + g_free (item->data); + g_slist_free1 (item); + } - if (EMPATHY_CHAT_GET_CLASS (chat)->set_tp_chat) { - EMPATHY_CHAT_GET_CLASS (chat)->set_tp_chat (chat, NULL); + /* Trim the list to the last 10 items */ + while (g_slist_length (list) > 10) { + item = g_slist_last (list); + if (item) { + list = g_slist_remove_link (list, item); + g_free (item->data); + g_slist_free1 (item); + } } + + /* Add new message */ + list = g_slist_prepend (list, g_strdup (str)); + + /* Set list and reset the index */ + priv->sent_messages = list; + priv->sent_messages_index = -1; +} + +static const gchar * +chat_sent_message_get_next (EmpathyChat *chat) +{ + EmpathyChatPriv *priv; + gint max; + + priv = GET_PRIV (chat); + + if (!priv->sent_messages) { + empathy_debug (DEBUG_DOMAIN, + "No sent messages, next message is NULL"); + return NULL; + } + + max = g_slist_length (priv->sent_messages) - 1; + + if (priv->sent_messages_index < max) { + priv->sent_messages_index++; + } + + empathy_debug (DEBUG_DOMAIN, + "Returning next message index:%d", + priv->sent_messages_index); + + return g_slist_nth_data (priv->sent_messages, priv->sent_messages_index); +} + +static const gchar * +chat_sent_message_get_last (EmpathyChat *chat) +{ + EmpathyChatPriv *priv; + + g_return_val_if_fail (EMPATHY_IS_CHAT (chat), NULL); + + priv = GET_PRIV (chat); + + if (!priv->sent_messages) { + empathy_debug (DEBUG_DOMAIN, + "No sent messages, last message is NULL"); + return NULL; + } + + if (priv->sent_messages_index >= 0) { + priv->sent_messages_index--; + } + + empathy_debug (DEBUG_DOMAIN, + "Returning last message index:%d", + priv->sent_messages_index); + + return g_slist_nth_data (priv->sent_messages, priv->sent_messages_index); } static void @@ -470,9 +436,6 @@ chat_send (EmpathyChat *chat, return; } - /* FIXME: add here something to let group/privrate chat handle - * some special messages */ - message = empathy_message_new (msg); empathy_tp_chat_send (priv->tp_chat, message); @@ -506,6 +469,67 @@ chat_input_text_view_send (EmpathyChat *chat) } static void +chat_state_changed_cb (EmpathyTpChat *tp_chat, + EmpathyContact *contact, + TpChannelChatState state, + EmpathyChat *chat) +{ + EmpathyChatPriv *priv; + GList *l; + gboolean was_composing; + + priv = GET_PRIV (chat); + + if (empathy_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 (contact == l->data) { + break; + } + } + + switch (state) { + case TP_CHANNEL_CHAT_STATE_GONE: + case TP_CHANNEL_CHAT_STATE_INACTIVE: + case TP_CHANNEL_CHAT_STATE_PAUSED: + 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_COMPOSING: + /* Contact is composing */ + if (!l) { + priv->compositors = g_list_prepend (priv->compositors, + g_object_ref (contact)); + } + break; + default: + g_assert_not_reached (); + } + + empathy_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_message_received_cb (EmpathyTpChat *tp_chat, EmpathyMessage *message, EmpathyChat *chat) @@ -550,7 +574,7 @@ chat_message_received_cb (EmpathyTpChat *tp_chat, empathy_log_manager_add_message (priv->log_manager, empathy_chat_get_id (chat), - empathy_chat_is_group_chat (chat), + FALSE, message); empathy_chat_view_append_message (chat->view, message); @@ -604,95 +628,104 @@ chat_send_error_cb (EmpathyTpChat *tp_chat, g_free (str); } -static void -chat_sent_message_add (EmpathyChat *chat, - const gchar *str) +static void +chat_input_text_buffer_changed_cb (GtkTextBuffer *buffer, + EmpathyChat *chat) { EmpathyChatPriv *priv; - GSList *list; - GSList *item; + GtkTextIter start, end; + gchar *str; + gboolean spell_checker = FALSE; priv = GET_PRIV (chat); - /* Save the sent message in our repeat buffer */ - list = priv->sent_messages; - - /* Remove any other occurances of this msg */ - while ((item = g_slist_find_custom (list, str, (GCompareFunc) strcmp)) != NULL) { - list = g_slist_remove_link (list, item); - g_free (item->data); - g_slist_free1 (item); + if (gtk_text_buffer_get_char_count (buffer) == 0) { + chat_composing_stop (chat); + } else { + chat_composing_start (chat); } - /* Trim the list to the last 10 items */ - while (g_slist_length (list) > 10) { - item = g_slist_last (list); - if (item) { - list = g_slist_remove_link (list, item); - g_free (item->data); - g_slist_free1 (item); - } - } + empathy_conf_get_bool (empathy_conf_get (), + EMPATHY_PREFS_CHAT_SPELL_CHECKER_ENABLED, + &spell_checker); - /* Add new message */ - list = g_slist_prepend (list, g_strdup (str)); + if (priv->is_first_char) { + GtkRequisition req; + gint window_height; + GtkWindow *dialog; + GtkAllocation *allocation; - /* Set list and reset the index */ - priv->sent_messages = list; - priv->sent_messages_index = -1; -} + /* Save the window's size */ + dialog = empathy_get_toplevel_window (priv->widget); + if (dialog) { + gtk_window_get_size (GTK_WINDOW (dialog), NULL, &window_height); + gtk_widget_size_request (chat->input_text_view, &req); + allocation = >K_WIDGET (chat->view)->allocation; -static const gchar * -chat_sent_message_get_next (EmpathyChat *chat) -{ - EmpathyChatPriv *priv; - gint max; - - priv = GET_PRIV (chat); + priv->default_window_height = window_height; + priv->last_input_height = req.height; + priv->padding_height = window_height - req.height - allocation->height; + } - if (!priv->sent_messages) { - empathy_debug (DEBUG_DOMAIN, - "No sent messages, next message is NULL"); - return NULL; + priv->is_first_char = FALSE; } - max = g_slist_length (priv->sent_messages) - 1; + gtk_text_buffer_get_start_iter (buffer, &start); - if (priv->sent_messages_index < max) { - priv->sent_messages_index++; + if (!spell_checker) { + gtk_text_buffer_get_end_iter (buffer, &end); + gtk_text_buffer_remove_tag_by_name (buffer, "misspelled", &start, &end); + return; } - - empathy_debug (DEBUG_DOMAIN, - "Returning next message index:%d", - priv->sent_messages_index); - return g_slist_nth_data (priv->sent_messages, priv->sent_messages_index); -} + if (!empathy_spell_supported ()) { + return; + } -static const gchar * -chat_sent_message_get_last (EmpathyChat *chat) -{ - EmpathyChatPriv *priv; + /* NOTE: this is really inefficient, we shouldn't have to + reiterate the whole buffer each time and check each work + every time. */ + while (TRUE) { + gboolean correct = FALSE; - g_return_val_if_fail (EMPATHY_IS_CHAT (chat), NULL); + /* if at start */ + if (gtk_text_iter_is_start (&start)) { + end = start; - priv = GET_PRIV (chat); - - if (!priv->sent_messages) { - empathy_debug (DEBUG_DOMAIN, - "No sent messages, last message is NULL"); - return NULL; - } + if (!gtk_text_iter_forward_word_end (&end)) { + /* no whole word yet */ + break; + } + } else { + if (!gtk_text_iter_forward_word_end (&end)) { + /* must be the end of the buffer */ + break; + } - if (priv->sent_messages_index >= 0) { - priv->sent_messages_index--; - } + start = end; + gtk_text_iter_backward_word_start (&start); + } - empathy_debug (DEBUG_DOMAIN, - "Returning last message index:%d", - priv->sent_messages_index); + str = gtk_text_buffer_get_text (buffer, &start, &end, FALSE); - return g_slist_nth_data (priv->sent_messages, priv->sent_messages_index); + /* spell check string */ + if (!empathy_chat_get_is_command (str)) { + correct = empathy_spell_check (str); + } else { + correct = TRUE; + } + + if (!correct) { + gtk_text_buffer_apply_tag_by_name (buffer, "misspelled", &start, &end); + } else { + gtk_text_buffer_remove_tag_by_name (buffer, "misspelled", &start, &end); + } + + g_free (str); + + /* set start iter to the end iters position */ + start = end; + } } static gboolean @@ -777,10 +810,6 @@ chat_input_key_press_event_cb (GtkWidget *widget, return TRUE; } - if (EMPATHY_CHAT_GET_CLASS (chat)->key_press_event) { - return EMPATHY_CHAT_GET_CLASS (chat)->key_press_event (chat, event); - } - return FALSE; } @@ -794,106 +823,6 @@ chat_text_view_focus_in_event_cb (GtkWidget *widget, return TRUE; } -static void -chat_input_text_buffer_changed_cb (GtkTextBuffer *buffer, - EmpathyChat *chat) -{ - EmpathyChatPriv *priv; - GtkTextIter start, end; - gchar *str; - gboolean spell_checker = FALSE; - - priv = GET_PRIV (chat); - - if (gtk_text_buffer_get_char_count (buffer) == 0) { - chat_composing_stop (chat); - } else { - chat_composing_start (chat); - } - - empathy_conf_get_bool (empathy_conf_get (), - EMPATHY_PREFS_CHAT_SPELL_CHECKER_ENABLED, - &spell_checker); - - if (priv->is_first_char) { - GtkRequisition req; - gint window_height; - GtkWindow *dialog; - GtkAllocation *allocation; - - /* Save the window's size */ - dialog = empathy_get_toplevel_window (priv->widget); - if (dialog) { - gtk_window_get_size (GTK_WINDOW (dialog), NULL, &window_height); - gtk_widget_size_request (chat->input_text_view, &req); - allocation = >K_WIDGET (chat->view)->allocation; - - priv->default_window_height = window_height; - priv->last_input_height = req.height; - priv->padding_height = window_height - req.height - allocation->height; - } - - priv->is_first_char = FALSE; - } - - gtk_text_buffer_get_start_iter (buffer, &start); - - if (!spell_checker) { - gtk_text_buffer_get_end_iter (buffer, &end); - gtk_text_buffer_remove_tag_by_name (buffer, "misspelled", &start, &end); - return; - } - - if (!empathy_spell_supported ()) { - return; - } - - /* NOTE: this is really inefficient, we shouldn't have to - reiterate the whole buffer each time and check each work - every time. */ - while (TRUE) { - gboolean correct = FALSE; - - /* if at start */ - if (gtk_text_iter_is_start (&start)) { - end = start; - - if (!gtk_text_iter_forward_word_end (&end)) { - /* no whole word yet */ - break; - } - } else { - if (!gtk_text_iter_forward_word_end (&end)) { - /* must be the end of the buffer */ - break; - } - - start = end; - gtk_text_iter_backward_word_start (&start); - } - - str = gtk_text_buffer_get_text (buffer, &start, &end, FALSE); - - /* spell check string */ - if (!empathy_chat_get_is_command (str)) { - correct = empathy_spell_check (str); - } else { - correct = TRUE; - } - - if (!correct) { - gtk_text_buffer_apply_tag_by_name (buffer, "misspelled", &start, &end); - } else { - gtk_text_buffer_remove_tag_by_name (buffer, "misspelled", &start, &end); - } - - g_free (str); - - /* set start iter to the end iters position */ - start = end; - } -} - typedef struct { GtkWindow *window; gint width; @@ -1029,6 +958,50 @@ chat_insert_smiley_activate_cb (GtkWidget *menuitem, gtk_text_buffer_insert (buffer, &iter, " ", -1); } +typedef struct { + EmpathyChat *chat; + gchar *word; + + GtkTextIter start; + GtkTextIter end; +} EmpathyChatSpell; + +static EmpathyChatSpell * +chat_spell_new (EmpathyChat *chat, + const gchar *word, + GtkTextIter start, + GtkTextIter end) +{ + EmpathyChatSpell *chat_spell; + + chat_spell = g_slice_new0 (EmpathyChatSpell); + + chat_spell->chat = g_object_ref (chat); + chat_spell->word = g_strdup (word); + chat_spell->start = start; + chat_spell->end = end; + + return chat_spell; +} + +static void +chat_spell_free (EmpathyChatSpell *chat_spell) +{ + g_object_unref (chat_spell->chat); + g_free (chat_spell->word); + g_slice_free (EmpathyChatSpell, chat_spell); +} + +static void +chat_text_check_word_spelling_cb (GtkMenuItem *menuitem, + EmpathyChatSpell *chat_spell) +{ + empathy_spell_dialog_show (chat_spell->chat, + chat_spell->start, + chat_spell->end, + chat_spell->word); +} + static void chat_text_populate_popup_cb (GtkTextView *view, GtkMenu *menu, @@ -1108,161 +1081,19 @@ chat_text_populate_popup_cb (GtkTextView *view, gtk_widget_show (item); } -static void -chat_text_check_word_spelling_cb (GtkMenuItem *menuitem, - EmpathyChatSpell *chat_spell) -{ - empathy_spell_dialog_show (chat_spell->chat, - chat_spell->start, - chat_spell->end, - chat_spell->word); -} - -static EmpathyChatSpell * -chat_spell_new (EmpathyChat *chat, - const gchar *word, - GtkTextIter start, - GtkTextIter end) -{ - EmpathyChatSpell *chat_spell; - - chat_spell = g_new0 (EmpathyChatSpell, 1); - - chat_spell->chat = g_object_ref (chat); - chat_spell->word = g_strdup (word); - chat_spell->start = start; - chat_spell->end = end; - - return chat_spell; -} - -static void -chat_spell_free (EmpathyChatSpell *chat_spell) -{ - g_object_unref (chat_spell->chat); - g_free (chat_spell->word); - g_free (chat_spell); -} - -static void -chat_composing_start (EmpathyChat *chat) -{ - EmpathyChatPriv *priv; - - priv = GET_PRIV (chat); - - if (priv->composing_stop_timeout_id) { - /* Just restart the timeout */ - chat_composing_remove_timeout (chat); - } else { - empathy_tp_chat_set_state (priv->tp_chat, - TP_CHANNEL_CHAT_STATE_COMPOSING); - } - - priv->composing_stop_timeout_id = g_timeout_add_seconds ( - COMPOSING_STOP_TIMEOUT, - (GSourceFunc) chat_composing_stop_timeout_cb, - chat); -} - -static void -chat_composing_stop (EmpathyChat *chat) -{ - EmpathyChatPriv *priv; - - priv = GET_PRIV (chat); - - chat_composing_remove_timeout (chat); - empathy_tp_chat_set_state (priv->tp_chat, - TP_CHANNEL_CHAT_STATE_ACTIVE); -} - -static void -chat_composing_remove_timeout (EmpathyChat *chat) -{ - EmpathyChatPriv *priv; - - priv = GET_PRIV (chat); - - if (priv->composing_stop_timeout_id) { - g_source_remove (priv->composing_stop_timeout_id); - priv->composing_stop_timeout_id = 0; - } -} - static gboolean -chat_composing_stop_timeout_cb (EmpathyChat *chat) -{ - EmpathyChatPriv *priv; - - priv = GET_PRIV (chat); - - priv->composing_stop_timeout_id = 0; - empathy_tp_chat_set_state (priv->tp_chat, - TP_CHANNEL_CHAT_STATE_PAUSED); - - return FALSE; -} - -static void -chat_state_changed_cb (EmpathyTpChat *tp_chat, - EmpathyContact *contact, - TpChannelChatState state, - EmpathyChat *chat) +chat_scroll_down_idle_func (EmpathyChat *chat) { EmpathyChatPriv *priv; - GList *l; - gboolean was_composing; priv = GET_PRIV (chat); - if (empathy_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 (contact == l->data) { - break; - } - } - - switch (state) { - case TP_CHANNEL_CHAT_STATE_GONE: - case TP_CHANNEL_CHAT_STATE_INACTIVE: - case TP_CHANNEL_CHAT_STATE_PAUSED: - 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_COMPOSING: - /* Contact is composing */ - if (!l) { - priv->compositors = g_list_prepend (priv->compositors, - g_object_ref (contact)); - } - break; - default: - g_assert_not_reached (); - } + empathy_chat_scroll_down (chat); + g_object_unref (chat); - empathy_debug (DEBUG_DOMAIN, "Was composing: %s now composing: %s", - was_composing ? "yes" : "no", - priv->compositors ? "yes" : "no"); + priv->scroll_idle_id = 0; - if ((was_composing && !priv->compositors) || - (!was_composing && priv->compositors)) { - /* Composing state changed */ - g_signal_emit (chat, signals[COMPOSING], 0, - priv->compositors != NULL); - } + return FALSE; } static void @@ -1282,7 +1113,7 @@ chat_add_logs (EmpathyChat *chat) messages = empathy_log_manager_get_last_messages (priv->log_manager, priv->account, empathy_chat_get_id (chat), - empathy_chat_is_group_chat (chat)); + FALSE); num_messages = g_list_length (messages); /* Only keep the 10 last messages */ @@ -1309,20 +1140,145 @@ chat_add_logs (EmpathyChat *chat) g_object_ref (chat)); } -/* Scroll down after the back-log has been received. */ -static gboolean -chat_scroll_down_idle_func (EmpathyChat *chat) +static void +empathy_chat_class_init (EmpathyChatClass *klass) { - EmpathyChatPriv *priv; + GObjectClass *object_class; - priv = GET_PRIV (chat); + object_class = G_OBJECT_CLASS (klass); - empathy_chat_scroll_down (chat); - g_object_unref (chat); + object_class->finalize = chat_finalize; + object_class->get_property = chat_get_property; + object_class->set_property = chat_set_property; - priv->scroll_idle_id = 0; + 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)); + g_object_class_install_property (object_class, + PROP_NAME, + g_param_spec_string ("name", + "Chat's name", + "The name of the chat", + NULL, + G_PARAM_READABLE)); + g_object_class_install_property (object_class, + PROP_TOOLTIP, + g_param_spec_string ("tooltip", + "Chat's tooltip", + "The tooltip of the chat", + NULL, + G_PARAM_READABLE)); + g_object_class_install_property (object_class, + PROP_ICON_NAME, + g_param_spec_string ("icon-name", + "Chat's icon name", + "The icon name of the chat", + NULL, + G_PARAM_READABLE)); + g_object_class_install_property (object_class, + PROP_WIDGET, + g_param_spec_object ("widget", + "Chat's widget", + "The widget of the chat", + GTK_TYPE_WIDGET, + G_PARAM_READABLE)); - return FALSE; + signals[COMPOSING] = + g_signal_new ("composing", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__BOOLEAN, + G_TYPE_NONE, + 1, G_TYPE_BOOLEAN); + + signals[NEW_MESSAGE] = + g_signal_new ("new-message", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + _empathy_gtk_marshal_VOID__OBJECT_BOOLEAN, + G_TYPE_NONE, + 2, EMPATHY_TYPE_MESSAGE, G_TYPE_BOOLEAN); + + g_type_class_add_private (object_class, sizeof (EmpathyChatPriv)); +} + +static void +empathy_chat_init (EmpathyChat *chat) +{ + EmpathyChatPriv *priv = GET_PRIV (chat); + GtkTextBuffer *buffer; + + chat->view = empathy_chat_view_new (); + chat->input_text_view = gtk_text_view_new (); + + priv->is_first_char = TRUE; + + g_object_set (chat->input_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); + + priv->log_manager = empathy_log_manager_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_CALLBACK (chat_input_key_press_event_cb), + chat); + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (chat->input_text_view)); + g_signal_connect (buffer, + "changed", + G_CALLBACK (chat_input_text_buffer_changed_cb), + chat); + g_signal_connect (chat->view, + "focus_in_event", + G_CALLBACK (chat_text_view_focus_in_event_cb), + chat); + + g_signal_connect (chat->input_text_view, + "size_allocate", + G_CALLBACK (chat_text_view_size_allocate_cb), + chat); + + g_signal_connect (chat->input_text_view, + "realize", + G_CALLBACK (chat_text_view_realize_cb), + chat); + + g_signal_connect (GTK_TEXT_VIEW (chat->input_text_view), + "populate_popup", + G_CALLBACK (chat_text_populate_popup_cb), + chat); + + /* create misspelt words identification tag */ + gtk_text_buffer_create_tag (buffer, + "misspelled", + "underline", PANGO_UNDERLINE_ERROR, + NULL); } gboolean @@ -1369,37 +1325,31 @@ empathy_chat_correct_word (EmpathyChat *chat, const gchar * empathy_chat_get_name (EmpathyChat *chat) { - g_return_val_if_fail (EMPATHY_IS_CHAT (chat), NULL); + EmpathyChatPriv *priv = GET_PRIV (chat); - if (EMPATHY_CHAT_GET_CLASS (chat)->get_name) { - return EMPATHY_CHAT_GET_CLASS (chat)->get_name (chat); - } + g_return_val_if_fail (EMPATHY_IS_CHAT (chat), NULL); - return NULL; + return priv->name; } -gchar * +const gchar * empathy_chat_get_tooltip (EmpathyChat *chat) { - g_return_val_if_fail (EMPATHY_IS_CHAT (chat), NULL); + EmpathyChatPriv *priv = GET_PRIV (chat); - if (EMPATHY_CHAT_GET_CLASS (chat)->get_tooltip) { - return EMPATHY_CHAT_GET_CLASS (chat)->get_tooltip (chat); - } + g_return_val_if_fail (EMPATHY_IS_CHAT (chat), NULL); - return NULL; + return priv->tooltip; } const gchar * empathy_chat_get_status_icon_name (EmpathyChat *chat) { - g_return_val_if_fail (EMPATHY_IS_CHAT (chat), NULL); + EmpathyChatPriv *priv = GET_PRIV (chat); - if (EMPATHY_CHAT_GET_CLASS (chat)->get_status_icon_name) { - return EMPATHY_CHAT_GET_CLASS (chat)->get_status_icon_name (chat); - } + g_return_val_if_fail (EMPATHY_IS_CHAT (chat), NULL); - return NULL; + return priv->icon_name; } GtkWidget * @@ -1409,25 +1359,9 @@ empathy_chat_get_widget (EmpathyChat *chat) g_return_val_if_fail (EMPATHY_IS_CHAT (chat), NULL); - if (!priv->widget && EMPATHY_CHAT_GET_CLASS (chat)->get_widget) { - priv->widget = EMPATHY_CHAT_GET_CLASS (chat)->get_widget (chat); - } - return priv->widget; } -gboolean -empathy_chat_is_group_chat (EmpathyChat *chat) -{ - g_return_val_if_fail (EMPATHY_IS_CHAT (chat), FALSE); - - if (EMPATHY_CHAT_GET_CLASS (chat)->is_group_chat) { - return EMPATHY_CHAT_GET_CLASS (chat)->is_group_chat (chat); - } - - return FALSE; -} - gboolean empathy_chat_is_connected (EmpathyChat *chat) { @@ -1493,6 +1427,7 @@ empathy_chat_set_tp_chat (EmpathyChat *chat, EmpathyTpChat *tp_chat) { EmpathyChatPriv *priv; + TpChan *tp_chan; g_return_if_fail (EMPATHY_IS_CHAT (chat)); g_return_if_fail (EMPATHY_IS_TP_CHAT (tp_chat)); @@ -1532,7 +1467,8 @@ empathy_chat_set_tp_chat (EmpathyChat *chat, 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)); - empathy_tp_chat_set_acknowledge (tp_chat, TRUE); + tp_chan = empathy_tp_chat_get_channel (tp_chat); + priv->handle_type = tp_chan->handle_type; if (priv->first_tp_chat) { chat_add_logs (chat); @@ -1558,10 +1494,6 @@ empathy_chat_set_tp_chat (EmpathyChat *chat, priv->sensitive = TRUE; } - if (EMPATHY_CHAT_GET_CLASS (chat)->set_tp_chat) { - EMPATHY_CHAT_GET_CLASS (chat)->set_tp_chat (chat, tp_chat); - } - g_object_notify (G_OBJECT (chat), "tp-chat"); } |