GtkTextTag * empathy_chat_text_view_tag_set (EmpathyChatTextView *view, const gchar *tag_name, const gchar *first_property_name, ...) { EmpathyChatTextViewPriv *priv = GET_PRIV (view); GtkTextTag *tag; GtkTextTagTable *table; va_list list; g_return_val_if_fail (EMPATHY_IS_CHAT_TEXT_VIEW (view), NULL); g_return_val_if_fail (tag_name != NULL, NULL); table = gtk_text_buffer_get_tag_table (priv->buffer); tag = gtk_text_tag_table_lookup (table, tag_name); if (tag && first_property_name) { va_start (list, first_property_name); g_object_set_valist (G_OBJECT (tag), first_property_name, list); va_end (list); } return tag; }
static void chat_text_view_copy_clipboard (EmpathyChatView *view) { GtkTextBuffer *buffer; GtkTextIter start, iter, end; GtkClipboard *clipboard; GdkPixbuf *pixbuf; gunichar c; GtkTextChildAnchor *anchor = NULL; GString *str; GList *list; gboolean ignore_newlines = FALSE; g_return_if_fail (EMPATHY_IS_CHAT_TEXT_VIEW (view)); buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); if (!gtk_text_buffer_get_selection_bounds (buffer, &start, &end)) return; str = g_string_new (""); for (iter = start; !gtk_text_iter_equal (&iter, &end); gtk_text_iter_forward_char (&iter)) { c = gtk_text_iter_get_char (&iter); /* 0xFFFC is the 'object replacement' unicode character, * it indicates the presence of a pixbuf or a widget. */ if (c == 0xFFFC) { ignore_newlines = FALSE; if ((pixbuf = gtk_text_iter_get_pixbuf (&iter))) { gchar *text; text = g_object_get_data (G_OBJECT(pixbuf), "smiley_str"); if (text) str = g_string_append (str, text); } else if ((anchor = gtk_text_iter_get_child_anchor (&iter))) { gchar *text; list = gtk_text_child_anchor_get_widgets (anchor); if (list) { text = g_object_get_data (G_OBJECT(list->data), "str_obj"); if (text) str = g_string_append (str, text); } g_list_free (list); } } else if (c == '\n') { if (!ignore_newlines) { ignore_newlines = TRUE; str = g_string_append_unichar (str, c); } } else { ignore_newlines = FALSE; str = g_string_append_unichar (str, c); } } gtk_clipboard_set_text (clipboard, str->str, str->len); g_string_free (str, TRUE); }
EmpathyContact * empathy_chat_text_view_get_last_contact (EmpathyChatTextView *view) { EmpathyChatTextViewPriv *priv = GET_PRIV (view); g_return_val_if_fail (EMPATHY_IS_CHAT_TEXT_VIEW (view), NULL); return priv->last_contact; }
gint64 empathy_chat_text_view_get_last_timestamp (EmpathyChatTextView *view) { EmpathyChatTextViewPriv *priv = GET_PRIV (view); g_return_val_if_fail (EMPATHY_IS_CHAT_TEXT_VIEW (view), 0); return priv->last_timestamp; }
static gboolean chat_text_view_get_has_selection (EmpathyChatView *view) { GtkTextBuffer *buffer; g_return_val_if_fail (EMPATHY_IS_CHAT_TEXT_VIEW (view), FALSE); buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); return gtk_text_buffer_get_has_selection (buffer); }
static void chat_text_view_highlight (EmpathyChatView *view, const gchar *text, gboolean match_case) { GtkTextBuffer *buffer; GtkTextIter iter; GtkTextIter iter_start; GtkTextIter iter_end; GtkTextIter iter_match_start; GtkTextIter iter_match_end; gboolean found; g_return_if_fail (EMPATHY_IS_CHAT_TEXT_VIEW (view)); buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); gtk_text_buffer_get_start_iter (buffer, &iter); gtk_text_buffer_get_bounds (buffer, &iter_start, &iter_end); gtk_text_buffer_remove_tag_by_name (buffer, EMPATHY_CHAT_TEXT_VIEW_TAG_HIGHLIGHT, &iter_start, &iter_end); if (EMP_STR_EMPTY (text)) { return; } while (1) { if (match_case) { found = gtk_text_iter_forward_search (&iter, text, 0, &iter_match_start, &iter_match_end, NULL); } else { found = empathy_text_iter_forward_search (&iter, text, &iter_match_start, &iter_match_end, NULL); } if (!found) { break; } gtk_text_buffer_apply_tag_by_name (buffer, EMPATHY_CHAT_TEXT_VIEW_TAG_HIGHLIGHT, &iter_match_start, &iter_match_end); iter = iter_match_end; } }
static void chat_text_view_find_abilities (EmpathyChatView *view, const gchar *search_criteria, gboolean *can_do_previous, gboolean *can_do_next) { EmpathyChatTextViewPriv *priv; GtkTextBuffer *buffer; GtkTextIter iter_at_mark; GtkTextIter iter_match_start; GtkTextIter iter_match_end; g_return_if_fail (EMPATHY_IS_CHAT_TEXT_VIEW (view)); g_return_if_fail (search_criteria != NULL); g_return_if_fail (can_do_previous != NULL && can_do_next != NULL); priv = GET_PRIV (view); buffer = priv->buffer; if (can_do_previous) { if (priv->find_mark_previous) { gtk_text_buffer_get_iter_at_mark (buffer, &iter_at_mark, priv->find_mark_previous); } else { gtk_text_buffer_get_start_iter (buffer, &iter_at_mark); } *can_do_previous = empathy_text_iter_backward_search (&iter_at_mark, search_criteria, &iter_match_start, &iter_match_end, NULL); } if (can_do_next) { if (priv->find_mark_next) { gtk_text_buffer_get_iter_at_mark (buffer, &iter_at_mark, priv->find_mark_next); } else { gtk_text_buffer_get_start_iter (buffer, &iter_at_mark); } *can_do_next = empathy_text_iter_forward_search (&iter_at_mark, search_criteria, &iter_match_start, &iter_match_end, NULL); } }
void empathy_chat_text_view_set_only_if_date (EmpathyChatTextView *view, gboolean only_if_date) { EmpathyChatTextViewPriv *priv = GET_PRIV (view); g_return_if_fail (EMPATHY_IS_CHAT_TEXT_VIEW (view)); if (only_if_date != priv->only_if_date) { priv->only_if_date = only_if_date; g_object_notify (G_OBJECT (view), "only-if-date"); } }
static void chat_text_view_copy_clipboard (EmpathyChatView *view) { GtkTextBuffer *buffer; GtkClipboard *clipboard; g_return_if_fail (EMPATHY_IS_CHAT_TEXT_VIEW (view)); buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); gtk_text_buffer_copy_clipboard (buffer, clipboard); }
static void chat_text_view_scroll (EmpathyChatView *view, gboolean allow_scrolling) { EmpathyChatTextViewPriv *priv = GET_PRIV (view); g_return_if_fail (EMPATHY_IS_CHAT_TEXT_VIEW (view)); DEBUG ("Scrolling %s", allow_scrolling ? "enabled" : "disabled"); priv->allow_scrolling = allow_scrolling; if (allow_scrolling) { empathy_chat_view_scroll_down (view); } }
static void chat_text_view_clear (EmpathyChatView *view) { GtkTextBuffer *buffer; EmpathyChatTextViewPriv *priv; g_return_if_fail (EMPATHY_IS_CHAT_TEXT_VIEW (view)); buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); gtk_text_buffer_set_text (buffer, "", -1); /* We set these back to the initial values so we get * timestamps when clearing the window to know when * conversations start. */ priv = GET_PRIV (view); priv->last_timestamp = 0; }
static void chat_text_view_append_message (EmpathyChatView *view, EmpathyMessage *msg) { EmpathyChatTextView *text_view = EMPATHY_CHAT_TEXT_VIEW (view); EmpathyChatTextViewPriv *priv = GET_PRIV (text_view); gboolean bottom; gint64 timestamp; g_return_if_fail (EMPATHY_IS_CHAT_TEXT_VIEW (view)); g_return_if_fail (EMPATHY_IS_MESSAGE (msg)); if (!empathy_message_get_body (msg)) { return; } bottom = chat_text_view_is_scrolled_down (text_view); chat_text_view_maybe_trim_buffer (EMPATHY_CHAT_TEXT_VIEW (view)); timestamp = empathy_message_get_timestamp (msg); chat_text_maybe_append_date_and_time (text_view, timestamp); if (EMPATHY_CHAT_TEXT_VIEW_GET_CLASS (view)->append_message) { EMPATHY_CHAT_TEXT_VIEW_GET_CLASS (view)->append_message (text_view, msg); } if (bottom) { chat_text_view_scroll_down (view); } if (priv->last_contact) { g_object_unref (priv->last_contact); } priv->last_contact = g_object_ref (empathy_message_get_sender (msg)); g_object_notify (G_OBJECT (view), "last-contact"); priv->last_timestamp = timestamp; }
static void chat_text_view_append_event (EmpathyChatView *view, const gchar *str) { EmpathyChatTextView *text_view = EMPATHY_CHAT_TEXT_VIEW (view); EmpathyChatTextViewPriv *priv = GET_PRIV (text_view); gboolean bottom; GtkTextIter iter; gchar *msg; g_return_if_fail (EMPATHY_IS_CHAT_TEXT_VIEW (view)); g_return_if_fail (!EMP_STR_EMPTY (str)); bottom = chat_text_view_is_scrolled_down (text_view); chat_text_view_maybe_trim_buffer (EMPATHY_CHAT_TEXT_VIEW (view)); chat_text_maybe_append_date_and_time (text_view, empathy_time_get_current ()); gtk_text_buffer_get_end_iter (priv->buffer, &iter); msg = g_strdup_printf (" - %s\n", str); gtk_text_buffer_insert_with_tags_by_name (priv->buffer, &iter, msg, -1, EMPATHY_CHAT_TEXT_VIEW_TAG_EVENT, NULL); g_free (msg); if (bottom) { chat_text_view_scroll_down (view); } if (priv->last_contact) { g_object_unref (priv->last_contact); priv->last_contact = NULL; g_object_notify (G_OBJECT (view), "last-contact"); } }
static void chat_text_view_scroll_down (EmpathyChatView *view) { EmpathyChatTextViewPriv *priv = GET_PRIV (view); g_return_if_fail (EMPATHY_IS_CHAT_TEXT_VIEW (view)); if (!priv->allow_scrolling) { return; } DEBUG ("Scrolling down"); if (priv->scroll_time) { g_timer_reset (priv->scroll_time); } else { priv->scroll_time = g_timer_new (); } if (!priv->scroll_timeout) { priv->scroll_timeout = g_timeout_add (SCROLL_DELAY, (GSourceFunc) chat_text_view_scroll_cb, view); } }
static gboolean chat_text_view_find_next (EmpathyChatView *view, const gchar *search_criteria, gboolean new_search) { EmpathyChatTextViewPriv *priv; GtkTextBuffer *buffer; GtkTextIter iter_at_mark; GtkTextIter iter_match_start; GtkTextIter iter_match_end; gboolean found; gboolean from_start = FALSE; g_return_val_if_fail (EMPATHY_IS_CHAT_TEXT_VIEW (view), FALSE); g_return_val_if_fail (search_criteria != NULL, FALSE); priv = GET_PRIV (view); buffer = priv->buffer; if (EMP_STR_EMPTY (search_criteria)) { if (priv->find_mark_next) { gtk_text_buffer_get_start_iter (buffer, &iter_at_mark); gtk_text_buffer_move_mark (buffer, priv->find_mark_next, &iter_at_mark); gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view), priv->find_mark_next, 0.0, TRUE, 0.0, 0.0); gtk_text_buffer_select_range (buffer, &iter_at_mark, &iter_at_mark); } return FALSE; } if (new_search) { from_start = TRUE; } if (priv->find_mark_next) { gtk_text_buffer_get_iter_at_mark (buffer, &iter_at_mark, priv->find_mark_next); } else { gtk_text_buffer_get_start_iter (buffer, &iter_at_mark); from_start = TRUE; } priv->find_last_direction = TRUE; found = empathy_text_iter_forward_search (&iter_at_mark, search_criteria, &iter_match_start, &iter_match_end, NULL); if (!found) { gboolean result = FALSE; if (from_start) { return result; } /* Here we wrap around. */ if (!new_search && !priv->find_wrapped) { priv->find_wrapped = TRUE; result = chat_text_view_find_next (view, search_criteria, FALSE); priv->find_wrapped = FALSE; } return result; } /* Set new mark and show on screen */ if (!priv->find_mark_next) { priv->find_mark_next = gtk_text_buffer_create_mark (buffer, NULL, &iter_match_end, TRUE); } else { gtk_text_buffer_move_mark (buffer, priv->find_mark_next, &iter_match_end); } if (!priv->find_mark_previous) { priv->find_mark_previous = gtk_text_buffer_create_mark (buffer, NULL, &iter_match_start, TRUE); } else { gtk_text_buffer_move_mark (buffer, priv->find_mark_previous, &iter_match_start); } gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view), priv->find_mark_next, 0.0, TRUE, 0.5, 0.5); gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &iter_match_start); gtk_text_buffer_move_mark_by_name (buffer, "insert", &iter_match_end); return TRUE; }
static gboolean chat_text_view_find_previous (EmpathyChatView *view, const gchar *search_criteria, gboolean new_search, gboolean match_case) { EmpathyChatTextViewPriv *priv; GtkTextBuffer *buffer; GtkTextIter iter_at_mark; GtkTextIter iter_match_start; GtkTextIter iter_match_end; gboolean found; gboolean from_start = FALSE; g_return_val_if_fail (EMPATHY_IS_CHAT_TEXT_VIEW (view), FALSE); g_return_val_if_fail (search_criteria != NULL, FALSE); priv = GET_PRIV (view); buffer = priv->buffer; if (EMP_STR_EMPTY (search_criteria)) { if (priv->find_mark_previous) { gtk_text_buffer_get_start_iter (buffer, &iter_at_mark); gtk_text_buffer_move_mark (buffer, priv->find_mark_previous, &iter_at_mark); gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view), priv->find_mark_previous, 0.0, TRUE, 0.0, 0.0); gtk_text_buffer_select_range (buffer, &iter_at_mark, &iter_at_mark); } return FALSE; } if (new_search) { from_start = TRUE; } if (!new_search && priv->find_mark_previous) { gtk_text_buffer_get_iter_at_mark (buffer, &iter_at_mark, priv->find_mark_previous); } else { gtk_text_buffer_get_end_iter (buffer, &iter_at_mark); from_start = TRUE; } priv->find_last_direction = FALSE; /* Use the standard GTK+ method for case sensitive searches. It can't do * case insensitive searches (see bug #61852), so keep the custom method * around for case insensitive searches. */ if (match_case) { found = gtk_text_iter_backward_search (&iter_at_mark, search_criteria, 0, /* no text search flags, we want exact matches */ &iter_match_start, &iter_match_end, NULL); } else { found = empathy_text_iter_backward_search (&iter_at_mark, search_criteria, &iter_match_start, &iter_match_end, NULL); } if (!found) { gboolean result = FALSE; if (from_start) { return result; } /* Here we wrap around. */ if (!new_search && !priv->find_wrapped) { priv->find_wrapped = TRUE; result = chat_text_view_find_previous (view, search_criteria, FALSE, match_case); priv->find_wrapped = FALSE; } return result; } /* Set new mark and show on screen */ if (!priv->find_mark_previous) { priv->find_mark_previous = gtk_text_buffer_create_mark (buffer, NULL, &iter_match_start, TRUE); } else { gtk_text_buffer_move_mark (buffer, priv->find_mark_previous, &iter_match_start); } if (!priv->find_mark_next) { priv->find_mark_next = gtk_text_buffer_create_mark (buffer, NULL, &iter_match_end, TRUE); } else { gtk_text_buffer_move_mark (buffer, priv->find_mark_next, &iter_match_end); } gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view), priv->find_mark_previous, 0.0, TRUE, 0.5, 0.5); gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &iter_match_start); gtk_text_buffer_move_mark_by_name (buffer, "insert", &iter_match_end); return TRUE; }