1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2002-2007 Imendio AB
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public
16 * License along with this program; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
20 * Authors: Mikael Hallendal <micke@imendio.com>
21 * Richard Hult <richard@imendio.com>
22 * Martyn Russell <martyn@imendio.com>
27 #include <sys/types.h>
31 #include <glib/gi18n.h>
32 #include <gtk/gtkbutton.h>
33 #include <gtk/gtkimage.h>
34 #include <gtk/gtkmenu.h>
35 #include <gtk/gtkmenuitem.h>
36 #include <gtk/gtkimagemenuitem.h>
37 #include <gtk/gtkstock.h>
38 #include <gtk/gtkscrolledwindow.h>
39 #include <gtk/gtksizegroup.h>
40 #include <glade/glade.h>
42 #include <libmissioncontrol/mc-account.h>
44 #include <libempathy/empathy-utils.h>
45 #include <libempathy/empathy-debug.h>
46 #include <libempathy/empathy-conf.h>
48 #include "empathy-chat-view.h"
49 #include "empathy-chat.h"
50 #include "empathy-preferences.h"
51 #include "empathy-theme-manager.h"
52 #include "empathy-ui-utils.h"
53 #include "empathy-smiley-manager.h"
55 #define DEBUG_DOMAIN "ChatView"
57 /* Number of seconds between timestamps when using normal mode, 5 minutes. */
58 #define TIMESTAMP_INTERVAL 300
61 #define MAX_SCROLL_TIME 0.4 /* seconds */
62 #define SCROLL_DELAY 33 /* milliseconds */
64 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_CHAT_VIEW, EmpathyChatViewPriv))
75 struct _EmpathyChatViewPriv {
76 EmpathySmileyManager *smiley_manager;
78 GtkTextBuffer *buffer;
81 time_t last_timestamp;
82 BlockType last_block_type;
84 gboolean allow_scrolling;
87 gboolean is_group_chat;
89 GtkTextMark *find_mark_previous;
90 GtkTextMark *find_mark_next;
91 gboolean find_wrapped;
92 gboolean find_last_direction;
94 /* This is for the group chat so we know if the "other" last contact
95 * changed, so we know whether to insert a header or not.
97 EmpathyContact *last_contact;
99 guint notify_system_fonts_id;
100 guint notify_show_avatars_id;
103 static void empathy_chat_view_class_init (EmpathyChatViewClass *klass);
104 static void empathy_chat_view_init (EmpathyChatView *view);
105 static void chat_view_finalize (GObject *object);
106 static gboolean chat_view_drag_motion (GtkWidget *widget,
107 GdkDragContext *context,
111 static void chat_view_size_allocate (GtkWidget *widget,
112 GtkAllocation *alloc);
113 static void chat_view_setup_tags (EmpathyChatView *view);
114 static void chat_view_system_font_update (EmpathyChatView *view);
115 static void chat_view_notify_system_font_cb (EmpathyConf *conf,
118 static void chat_view_notify_show_avatars_cb (EmpathyConf *conf,
121 static void chat_view_populate_popup (EmpathyChatView *view,
124 static gboolean chat_view_event_cb (EmpathyChatView *view,
125 GdkEventMotion *event,
127 static gboolean chat_view_url_event_cb (GtkTextTag *tag,
131 GtkTextBuffer *buffer);
132 static void chat_view_open_address_cb (GtkMenuItem *menuitem,
134 static void chat_view_copy_address_cb (GtkMenuItem *menuitem,
136 static void chat_view_clear_view_cb (GtkMenuItem *menuitem,
137 EmpathyChatView *view);
138 static void chat_view_insert_text_with_emoticons (EmpathyChatView *view,
141 static gboolean chat_view_is_scrolled_down (EmpathyChatView *view);
142 static void chat_view_theme_changed_cb (EmpathyThemeManager *manager,
143 EmpathyChatView *view);
144 static void chat_view_maybe_append_date_and_time (EmpathyChatView *view,
145 EmpathyMessage *msg);
146 static void chat_view_append_spacing (EmpathyChatView *view);
147 static void chat_view_append_text (EmpathyChatView *view,
150 static void chat_view_maybe_append_fancy_header (EmpathyChatView *view,
151 EmpathyMessage *msg);
152 static void chat_view_append_irc_action (EmpathyChatView *view,
153 EmpathyMessage *msg);
154 static void chat_view_append_fancy_action (EmpathyChatView *view,
155 EmpathyMessage *msg);
156 static void chat_view_append_irc_message (EmpathyChatView *view,
157 EmpathyMessage *msg);
158 static void chat_view_append_fancy_message (EmpathyChatView *view,
159 EmpathyMessage *msg);
160 static GdkPixbuf *chat_view_pad_to_size (GdkPixbuf *pixbuf,
163 gint extra_padding_right);
165 G_DEFINE_TYPE (EmpathyChatView, empathy_chat_view, GTK_TYPE_TEXT_VIEW);
168 empathy_chat_view_class_init (EmpathyChatViewClass *klass)
170 GObjectClass *object_class = G_OBJECT_CLASS (klass);
171 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
173 object_class->finalize = chat_view_finalize;
174 widget_class->size_allocate = chat_view_size_allocate;
175 widget_class->drag_motion = chat_view_drag_motion;
177 g_type_class_add_private (object_class, sizeof (EmpathyChatViewPriv));
181 empathy_chat_view_init (EmpathyChatView *view)
183 EmpathyChatViewPriv *priv;
184 gboolean show_avatars;
186 priv = GET_PRIV (view);
188 priv->smiley_manager = empathy_smiley_manager_new ();
189 priv->buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
191 priv->last_block_type = BLOCK_TYPE_NONE;
192 priv->last_timestamp = 0;
194 priv->allow_scrolling = TRUE;
196 priv->is_group_chat = FALSE;
199 "wrap-mode", GTK_WRAP_WORD_CHAR,
201 "cursor-visible", FALSE,
204 priv->notify_system_fonts_id =
205 empathy_conf_notify_add (empathy_conf_get (),
206 "/desktop/gnome/interface/document_font_name",
207 chat_view_notify_system_font_cb,
209 chat_view_system_font_update (view);
211 priv->notify_show_avatars_id =
212 empathy_conf_notify_add (empathy_conf_get (),
213 EMPATHY_PREFS_UI_SHOW_AVATARS,
214 chat_view_notify_show_avatars_cb,
217 chat_view_setup_tags (view);
219 empathy_theme_manager_apply_saved (empathy_theme_manager_get (), view);
221 show_avatars = FALSE;
222 empathy_conf_get_bool (empathy_conf_get (),
223 EMPATHY_PREFS_UI_SHOW_AVATARS,
226 empathy_theme_manager_update_show_avatars (empathy_theme_manager_get (),
229 g_signal_connect (view,
231 G_CALLBACK (chat_view_populate_popup),
234 g_signal_connect_object (empathy_theme_manager_get (),
236 G_CALLBACK (chat_view_theme_changed_cb),
242 chat_view_finalize (GObject *object)
244 EmpathyChatView *view;
245 EmpathyChatViewPriv *priv;
247 view = EMPATHY_CHAT_VIEW (object);
248 priv = GET_PRIV (view);
250 empathy_debug (DEBUG_DOMAIN, "finalize: %p", object);
252 empathy_conf_notify_remove (empathy_conf_get (), priv->notify_system_fonts_id);
253 empathy_conf_notify_remove (empathy_conf_get (), priv->notify_show_avatars_id);
255 if (priv->smiley_manager) {
256 g_object_unref (priv->smiley_manager);
258 if (priv->last_contact) {
259 g_object_unref (priv->last_contact);
261 if (priv->scroll_time) {
262 g_timer_destroy (priv->scroll_time);
264 if (priv->scroll_timeout) {
265 g_source_remove (priv->scroll_timeout);
268 G_OBJECT_CLASS (empathy_chat_view_parent_class)->finalize (object);
272 chat_view_drag_motion (GtkWidget *widget,
273 GdkDragContext *context,
278 /* Don't handle drag motion, since we don't want the view to scroll as
279 * the result of dragging something across it.
286 chat_view_size_allocate (GtkWidget *widget,
287 GtkAllocation *alloc)
291 down = chat_view_is_scrolled_down (EMPATHY_CHAT_VIEW (widget));
293 GTK_WIDGET_CLASS (empathy_chat_view_parent_class)->size_allocate (widget, alloc);
298 adj = GTK_TEXT_VIEW (widget)->vadjustment;
299 gtk_adjustment_set_value (adj, adj->upper - adj->page_size);
304 chat_view_setup_tags (EmpathyChatView *view)
306 EmpathyChatViewPriv *priv;
309 priv = GET_PRIV (view);
311 gtk_text_buffer_create_tag (priv->buffer,
315 /* FIXME: Move to the theme and come up with something that looks a bit
318 gtk_text_buffer_create_tag (priv->buffer,
320 "background", "yellow",
323 tag = gtk_text_buffer_create_tag (priv->buffer,
327 g_signal_connect (tag,
329 G_CALLBACK (chat_view_url_event_cb),
332 g_signal_connect (view,
333 "motion-notify-event",
334 G_CALLBACK (chat_view_event_cb),
339 chat_view_system_font_update (EmpathyChatView *view)
341 PangoFontDescription *font_description = NULL;
344 if (empathy_conf_get_string (empathy_conf_get (),
345 "/desktop/gnome/interface/document_font_name",
346 &font_name) && font_name) {
347 font_description = pango_font_description_from_string (font_name);
350 font_description = NULL;
353 gtk_widget_modify_font (GTK_WIDGET (view), font_description);
355 if (font_description) {
356 pango_font_description_free (font_description);
361 chat_view_notify_system_font_cb (EmpathyConf *conf,
365 EmpathyChatView *view;
366 gboolean show_avatars = FALSE;
370 chat_view_system_font_update (view);
372 /* Ugly, again, to adjust the vertical position of the nick... Will fix
373 * this when reworking the theme manager so that view register
374 * themselves with it instead of the other way around.
376 empathy_conf_get_bool (conf,
377 EMPATHY_PREFS_UI_SHOW_AVATARS,
380 empathy_theme_manager_update_show_avatars (empathy_theme_manager_get (),
385 chat_view_notify_show_avatars_cb (EmpathyConf *conf,
389 EmpathyChatView *view;
390 EmpathyChatViewPriv *priv;
391 gboolean show_avatars = FALSE;
394 priv = GET_PRIV (view);
396 empathy_conf_get_bool (conf, key, &show_avatars);
398 empathy_theme_manager_update_show_avatars (empathy_theme_manager_get (),
403 chat_view_populate_popup (EmpathyChatView *view,
407 EmpathyChatViewPriv *priv;
408 GtkTextTagTable *table;
411 GtkTextIter iter, start, end;
415 priv = GET_PRIV (view);
417 /* Clear menu item */
418 if (gtk_text_buffer_get_char_count (priv->buffer) > 0) {
419 item = gtk_menu_item_new ();
420 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item);
421 gtk_widget_show (item);
423 item = gtk_image_menu_item_new_from_stock (GTK_STOCK_CLEAR, NULL);
424 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item);
425 gtk_widget_show (item);
427 g_signal_connect (item,
429 G_CALLBACK (chat_view_clear_view_cb),
433 /* Link context menu items */
434 table = gtk_text_buffer_get_tag_table (priv->buffer);
435 tag = gtk_text_tag_table_lookup (table, "link");
437 gtk_widget_get_pointer (GTK_WIDGET (view), &x, &y);
439 gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (view),
440 GTK_TEXT_WINDOW_WIDGET,
444 gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (view), &iter, x, y);
448 if (gtk_text_iter_backward_to_tag_toggle (&start, tag) &&
449 gtk_text_iter_forward_to_tag_toggle (&end, tag)) {
450 str = gtk_text_buffer_get_text (priv->buffer,
451 &start, &end, FALSE);
454 if (G_STR_EMPTY (str)) {
459 /* NOTE: Set data just to get the string freed when not needed. */
460 g_object_set_data_full (G_OBJECT (menu),
462 (GDestroyNotify) g_free);
464 item = gtk_menu_item_new ();
465 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item);
466 gtk_widget_show (item);
468 item = gtk_menu_item_new_with_mnemonic (_("_Copy Link Address"));
469 g_signal_connect (item,
471 G_CALLBACK (chat_view_copy_address_cb),
473 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item);
474 gtk_widget_show (item);
476 item = gtk_menu_item_new_with_mnemonic (_("_Open Link"));
477 g_signal_connect (item,
479 G_CALLBACK (chat_view_open_address_cb),
481 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item);
482 gtk_widget_show (item);
486 chat_view_event_cb (EmpathyChatView *view,
487 GdkEventMotion *event,
490 static GdkCursor *hand = NULL;
491 static GdkCursor *beam = NULL;
492 GtkTextWindowType type;
495 gint x, y, buf_x, buf_y;
497 type = gtk_text_view_get_window_type (GTK_TEXT_VIEW (view),
500 if (type != GTK_TEXT_WINDOW_TEXT) {
504 /* Get where the pointer really is. */
505 win = gtk_text_view_get_window (GTK_TEXT_VIEW (view), type);
510 gdk_window_get_pointer (win, &x, &y, NULL);
512 /* Get the iter where the cursor is at */
513 gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (view), type,
517 gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (view),
521 if (gtk_text_iter_has_tag (&iter, tag)) {
523 hand = gdk_cursor_new (GDK_HAND2);
524 beam = gdk_cursor_new (GDK_XTERM);
526 gdk_window_set_cursor (win, hand);
529 beam = gdk_cursor_new (GDK_XTERM);
531 gdk_window_set_cursor (win, beam);
538 chat_view_url_event_cb (GtkTextTag *tag,
542 GtkTextBuffer *buffer)
544 GtkTextIter start, end;
547 /* If the link is being selected, don't do anything. */
548 gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
549 if (gtk_text_iter_get_offset (&start) != gtk_text_iter_get_offset (&end)) {
553 if (event->type == GDK_BUTTON_RELEASE && event->button.button == 1) {
556 if (gtk_text_iter_backward_to_tag_toggle (&start, tag) &&
557 gtk_text_iter_forward_to_tag_toggle (&end, tag)) {
558 str = gtk_text_buffer_get_text (buffer,
563 empathy_url_show (str);
572 chat_view_open_address_cb (GtkMenuItem *menuitem, const gchar *url)
574 empathy_url_show (url);
578 chat_view_copy_address_cb (GtkMenuItem *menuitem, const gchar *url)
580 GtkClipboard *clipboard;
582 clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
583 gtk_clipboard_set_text (clipboard, url, -1);
585 clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);
586 gtk_clipboard_set_text (clipboard, url, -1);
590 chat_view_clear_view_cb (GtkMenuItem *menuitem, EmpathyChatView *view)
592 empathy_chat_view_clear (view);
596 chat_view_insert_text_with_emoticons (EmpathyChatView *view,
600 EmpathyChatViewPriv *priv = GET_PRIV (view);
601 GtkTextBuffer *buf = priv->buffer;
602 gboolean use_smileys = FALSE;
605 empathy_conf_get_bool (empathy_conf_get (),
606 EMPATHY_PREFS_CHAT_SHOW_SMILEYS,
610 gtk_text_buffer_insert (buf, iter, str, -1);
614 smileys = empathy_smiley_manager_parse (priv->smiley_manager, str);
615 for (l = smileys; l; l = l->next) {
616 EmpathySmiley *smiley;
619 if (smiley->pixbuf) {
620 gtk_text_buffer_insert_pixbuf (buf, iter, smiley->pixbuf);
622 gtk_text_buffer_insert (buf, iter, smiley->str, -1);
624 empathy_smiley_free (smiley);
626 g_slist_free (smileys);
630 chat_view_is_scrolled_down (EmpathyChatView *view)
634 sw = gtk_widget_get_parent (GTK_WIDGET (view));
635 if (GTK_IS_SCROLLED_WINDOW (sw)) {
638 vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (sw));
640 if (vadj->value + vadj->page_size / 2 < vadj->upper - vadj->page_size) {
649 chat_view_maybe_trim_buffer (EmpathyChatView *view)
651 EmpathyChatViewPriv *priv;
652 GtkTextIter top, bottom;
655 GtkTextTagTable *table;
658 priv = GET_PRIV (view);
660 gtk_text_buffer_get_end_iter (priv->buffer, &bottom);
661 line = gtk_text_iter_get_line (&bottom);
662 if (line < MAX_LINES) {
666 remove = line - MAX_LINES;
667 gtk_text_buffer_get_start_iter (priv->buffer, &top);
670 if (!gtk_text_iter_forward_lines (&bottom, remove)) {
674 /* Track backwords to a place where we can safely cut, we don't do it in
675 * the middle of a tag.
677 table = gtk_text_buffer_get_tag_table (priv->buffer);
678 tag = gtk_text_tag_table_lookup (table, "cut");
683 if (!gtk_text_iter_forward_to_tag_toggle (&bottom, tag)) {
687 if (!gtk_text_iter_equal (&top, &bottom)) {
688 gtk_text_buffer_delete (priv->buffer, &top, &bottom);
693 chat_view_maybe_append_date_and_time (EmpathyChatView *view,
696 EmpathyChatViewPriv *priv;
699 GDate *date, *last_date;
701 gboolean append_date, append_time;
704 priv = GET_PRIV (view);
706 if (priv->irc_style) {
712 if (priv->last_block_type == BLOCK_TYPE_TIME) {
716 str = g_string_new (NULL);
720 timestamp = empathy_message_get_timestamp (msg);
723 if (timestamp <= 0) {
724 timestamp = empathy_time_get_current ();
727 date = g_date_new ();
728 g_date_set_time_t (date, timestamp);
730 last_date = g_date_new ();
731 g_date_set_time_t (last_date, priv->last_timestamp);
736 if (g_date_compare (date, last_date) > 0) {
741 if (priv->last_timestamp + TIMESTAMP_INTERVAL < timestamp) {
745 if (append_time || append_date) {
746 chat_view_append_spacing (view);
748 g_string_append (str, "- ");
754 g_date_strftime (buf, 256, _("%A %d %B %Y"), date);
755 g_string_append (str, buf);
758 g_string_append (str, ", ");
763 g_date_free (last_date);
768 tmp = empathy_time_to_string_local (timestamp, EMPATHY_TIME_FORMAT_DISPLAY_SHORT);
769 g_string_append (str, tmp);
773 if (append_time || append_date) {
774 g_string_append (str, " -\n");
776 gtk_text_buffer_get_end_iter (priv->buffer, &iter);
777 gtk_text_buffer_insert_with_tags_by_name (priv->buffer,
783 priv->last_block_type = BLOCK_TYPE_TIME;
784 priv->last_timestamp = timestamp;
787 g_string_free (str, TRUE);
791 chat_view_append_spacing (EmpathyChatView *view)
793 EmpathyChatViewPriv *priv;
797 priv = GET_PRIV (view);
799 if (priv->irc_style) {
802 tag = "fancy-spacing";
805 gtk_text_buffer_get_end_iter (priv->buffer, &iter);
806 gtk_text_buffer_insert_with_tags_by_name (priv->buffer,
816 chat_view_append_text (EmpathyChatView *view,
820 EmpathyChatViewPriv *priv;
821 GtkTextIter start_iter, end_iter;
826 const gchar *link_tag;
828 priv = GET_PRIV (view);
830 if (priv->irc_style) {
831 link_tag = "irc-link";
833 link_tag = "fancy-link";
836 gtk_text_buffer_get_end_iter (priv->buffer, &start_iter);
837 mark = gtk_text_buffer_create_mark (priv->buffer, NULL, &start_iter, TRUE);
839 start = g_array_new (FALSE, FALSE, sizeof (gint));
840 end = g_array_new (FALSE, FALSE, sizeof (gint));
842 num_matches = empathy_regex_match (EMPATHY_REGEX_ALL, body, start, end);
844 if (num_matches == 0) {
845 gtk_text_buffer_get_end_iter (priv->buffer, &iter);
846 chat_view_insert_text_with_emoticons (view, &iter, body);
852 for (i = 0; i < num_matches; i++) {
853 s = g_array_index (start, gint, i);
854 e = g_array_index (end, gint, i);
857 tmp = empathy_substring (body, last, s);
859 gtk_text_buffer_get_end_iter (priv->buffer, &iter);
860 chat_view_insert_text_with_emoticons (view,
866 tmp = empathy_substring (body, s, e);
868 gtk_text_buffer_get_end_iter (priv->buffer, &iter);
869 gtk_text_buffer_insert_with_tags_by_name (priv->buffer,
882 if (e < strlen (body)) {
883 tmp = empathy_substring (body, e, strlen (body));
885 gtk_text_buffer_get_end_iter (priv->buffer, &iter);
886 chat_view_insert_text_with_emoticons (view,
893 g_array_free (start, TRUE);
894 g_array_free (end, TRUE);
896 gtk_text_buffer_get_end_iter (priv->buffer, &iter);
897 gtk_text_buffer_insert (priv->buffer, &iter, "\n", 1);
899 /* Apply the style to the inserted text. */
900 gtk_text_buffer_get_iter_at_mark (priv->buffer, &start_iter, mark);
901 gtk_text_buffer_get_end_iter (priv->buffer, &end_iter);
903 gtk_text_buffer_apply_tag_by_name (priv->buffer,
908 gtk_text_buffer_delete_mark (priv->buffer, mark);
912 chat_view_maybe_append_fancy_header (EmpathyChatView *view,
915 EmpathyChatViewPriv *priv;
916 EmpathyContact *sender;
922 const gchar *avatar_tag;
923 const gchar *line_top_tag;
924 const gchar *line_bottom_tag;
926 GdkPixbuf *pixbuf = NULL;
927 GdkPixbuf *avatar = NULL;
929 priv = GET_PRIV (view);
931 sender = empathy_message_get_sender (msg);
932 name = empathy_contact_get_name (sender);
933 from_self = empathy_contact_is_user (sender);
935 empathy_debug (DEBUG_DOMAIN, "Maybe add fancy header");
938 tag = "fancy-header-self";
939 line_top_tag = "fancy-line-top-self";
940 line_bottom_tag = "fancy-line-bottom-self";
942 tag = "fancy-header-other";
943 line_top_tag = "fancy-line-top-other";
944 line_bottom_tag = "fancy-line-bottom-other";
949 /* Only insert a header if the previously inserted block is not the same
950 * as this one. This catches all the different cases:
952 if (priv->last_block_type != BLOCK_TYPE_SELF &&
953 priv->last_block_type != BLOCK_TYPE_OTHER) {
956 else if (from_self && priv->last_block_type == BLOCK_TYPE_OTHER) {
959 else if (!from_self && priv->last_block_type == BLOCK_TYPE_SELF) {
962 else if (!from_self &&
963 (!priv->last_contact ||
964 !empathy_contact_equal (sender, priv->last_contact))) {
972 chat_view_append_spacing (view);
974 gtk_text_buffer_get_end_iter (priv->buffer, &iter);
975 gtk_text_buffer_insert_with_tags_by_name (priv->buffer,
982 /* FIXME: we should have a cash of avatar pixbufs */
983 pixbuf = empathy_pixbuf_avatar_from_contact_scaled (sender, 32, 32);
985 avatar = chat_view_pad_to_size (pixbuf, 32, 32, 6);
986 g_object_unref (pixbuf);
992 gtk_text_buffer_get_end_iter (priv->buffer, &iter);
993 gtk_text_buffer_insert_pixbuf (priv->buffer, &iter, avatar);
995 gtk_text_buffer_get_end_iter (priv->buffer, &iter);
997 gtk_text_iter_backward_char (&start);
1000 gtk_text_buffer_apply_tag_by_name (priv->buffer,
1001 "fancy-avatar-self",
1003 avatar_tag = "fancy-header-self-avatar";
1005 gtk_text_buffer_apply_tag_by_name (priv->buffer,
1006 "fancy-avatar-other",
1008 avatar_tag = "fancy-header-other-avatar";
1011 g_object_unref (avatar);
1016 tmp = g_strdup_printf ("%s\n", name);
1018 gtk_text_buffer_get_end_iter (priv->buffer, &iter);
1019 gtk_text_buffer_insert_with_tags_by_name (priv->buffer,
1028 gtk_text_buffer_get_end_iter (priv->buffer, &iter);
1029 gtk_text_buffer_insert_with_tags_by_name (priv->buffer,
1038 chat_view_append_irc_action (EmpathyChatView *view,
1039 EmpathyMessage *msg)
1041 EmpathyChatViewPriv *priv;
1042 EmpathyContact *sender;
1049 priv = GET_PRIV (view);
1051 empathy_debug (DEBUG_DOMAIN, "Add IRC action");
1053 sender = empathy_message_get_sender (msg);
1054 name = empathy_contact_get_name (sender);
1056 if (empathy_contact_is_user (sender)) {
1057 tag = "irc-action-self";
1059 tag = "irc-action-other";
1062 if (priv->last_block_type != BLOCK_TYPE_SELF &&
1063 priv->last_block_type != BLOCK_TYPE_OTHER) {
1064 chat_view_append_spacing (view);
1067 gtk_text_buffer_get_end_iter (priv->buffer, &iter);
1069 tmp = g_strdup_printf (" * %s ", name);
1070 gtk_text_buffer_insert_with_tags_by_name (priv->buffer,
1079 body = empathy_message_get_body (msg);
1080 chat_view_append_text (view, body, tag);
1084 chat_view_append_fancy_action (EmpathyChatView *view,
1085 EmpathyMessage *msg)
1087 EmpathyChatViewPriv *priv;
1088 EmpathyContact *sender;
1094 const gchar *line_tag;
1096 priv = GET_PRIV (view);
1098 empathy_debug (DEBUG_DOMAIN, "Add fancy action");
1100 sender = empathy_message_get_sender (msg);
1101 name = empathy_contact_get_name (sender);
1103 if (empathy_contact_is_user (sender)) {
1104 tag = "fancy-action-self";
1105 line_tag = "fancy-line-self";
1107 tag = "fancy-action-other";
1108 line_tag = "fancy-line-other";
1111 tmp = g_strdup_printf (" * %s ", name);
1112 gtk_text_buffer_get_end_iter (priv->buffer, &iter);
1113 gtk_text_buffer_insert_with_tags_by_name (priv->buffer,
1121 body = empathy_message_get_body (msg);
1122 chat_view_append_text (view, body, tag);
1126 chat_view_append_irc_message (EmpathyChatView *view,
1127 EmpathyMessage *msg)
1129 EmpathyChatViewPriv *priv;
1130 EmpathyContact *sender;
1133 const gchar *nick_tag;
1134 const gchar *body_tag;
1138 priv = GET_PRIV (view);
1140 empathy_debug (DEBUG_DOMAIN, "Add IRC message");
1142 body = empathy_message_get_body (msg);
1143 sender = empathy_message_get_sender (msg);
1144 name = empathy_contact_get_name (sender);
1146 if (empathy_contact_is_user (sender)) {
1147 nick_tag = "irc-nick-self";
1148 body_tag = "irc-body-self";
1150 if (empathy_chat_should_highlight_nick (msg)) {
1151 nick_tag = "irc-nick-highlight";
1153 nick_tag = "irc-nick-other";
1156 body_tag = "irc-body-other";
1159 if (priv->last_block_type != BLOCK_TYPE_SELF &&
1160 priv->last_block_type != BLOCK_TYPE_OTHER) {
1161 chat_view_append_spacing (view);
1164 gtk_text_buffer_get_end_iter (priv->buffer, &iter);
1167 tmp = g_strdup_printf ("%s: ", name);
1168 gtk_text_buffer_insert_with_tags_by_name (priv->buffer,
1177 /* The text body. */
1178 chat_view_append_text (view, body, body_tag);
1182 chat_view_append_fancy_message (EmpathyChatView *view,
1183 EmpathyMessage *msg)
1185 EmpathyChatViewPriv *priv;
1186 EmpathyContact *sender;
1190 priv = GET_PRIV (view);
1192 sender = empathy_message_get_sender (msg);
1194 if (empathy_contact_is_user (sender)) {
1195 tag = "fancy-body-self";
1197 tag = "fancy-body-other";
1199 /* FIXME: Might want to support nick highlighting here... */
1202 body = empathy_message_get_body (msg);
1203 chat_view_append_text (view, body, tag);
1207 chat_view_theme_changed_cb (EmpathyThemeManager *manager,
1208 EmpathyChatView *view)
1210 EmpathyChatViewPriv *priv;
1211 gboolean show_avatars = FALSE;
1212 gboolean theme_rooms = FALSE;
1214 priv = GET_PRIV (view);
1216 priv->last_block_type = BLOCK_TYPE_NONE;
1218 empathy_conf_get_bool (empathy_conf_get (),
1219 EMPATHY_PREFS_CHAT_THEME_CHAT_ROOM,
1221 if (!theme_rooms && priv->is_group_chat) {
1222 empathy_theme_manager_apply (manager, view, NULL);
1224 empathy_theme_manager_apply_saved (manager, view);
1227 /* Needed for now to update the "rise" property of the names to get it
1228 * vertically centered.
1230 empathy_conf_get_bool (empathy_conf_get (),
1231 EMPATHY_PREFS_UI_SHOW_AVATARS,
1233 empathy_theme_manager_update_show_avatars (manager, view, show_avatars);
1236 /* Pads a pixbuf to the specified size, by centering it in a larger transparent
1237 * pixbuf. Returns a new ref.
1240 chat_view_pad_to_size (GdkPixbuf *pixbuf,
1243 gint extra_padding_right)
1245 gint src_width, src_height;
1247 gint x_offset, y_offset;
1249 src_width = gdk_pixbuf_get_width (pixbuf);
1250 src_height = gdk_pixbuf_get_height (pixbuf);
1252 x_offset = (width - src_width) / 2;
1253 y_offset = (height - src_height) / 2;
1255 padded = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (pixbuf),
1257 gdk_pixbuf_get_bits_per_sample (pixbuf),
1258 width + extra_padding_right,
1261 gdk_pixbuf_fill (padded, 0);
1263 gdk_pixbuf_copy_area (pixbuf,
1264 0, /* source coords */
1269 x_offset, /* dest coords */
1276 empathy_chat_view_new (void)
1278 return g_object_new (EMPATHY_TYPE_CHAT_VIEW, NULL);
1281 /* The name is optional, if NULL, the sender for msg is used. */
1283 empathy_chat_view_append_message (EmpathyChatView *view,
1284 EmpathyMessage *msg)
1286 EmpathyChatViewPriv *priv;
1287 EmpathyContact *sender;
1289 gboolean scroll_down;
1291 g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view));
1292 g_return_if_fail (EMPATHY_IS_MESSAGE (msg));
1294 priv = GET_PRIV (view);
1296 body = empathy_message_get_body (msg);
1301 scroll_down = chat_view_is_scrolled_down (view);
1303 chat_view_maybe_trim_buffer (view);
1304 chat_view_maybe_append_date_and_time (view, msg);
1306 sender = empathy_message_get_sender (msg);
1308 if (!priv->irc_style) {
1309 chat_view_maybe_append_fancy_header (view, msg);
1312 if (empathy_message_get_type (msg) == EMPATHY_MESSAGE_TYPE_ACTION) {
1313 if (priv->irc_style) {
1314 chat_view_append_irc_action (view, msg);
1316 chat_view_append_fancy_action (view, msg);
1319 if (priv->irc_style) {
1320 chat_view_append_irc_message (view, msg);
1322 chat_view_append_fancy_message (view, msg);
1326 /* Reset the last inserted contact. */
1327 if (priv->last_contact) {
1328 g_object_unref (priv->last_contact);
1331 if (empathy_contact_is_user (sender)) {
1332 priv->last_block_type = BLOCK_TYPE_SELF;
1333 priv->last_contact = NULL;
1335 priv->last_block_type = BLOCK_TYPE_OTHER;
1336 priv->last_contact = g_object_ref (sender);
1340 empathy_chat_view_scroll_down (view);
1345 empathy_chat_view_append_event (EmpathyChatView *view,
1348 EmpathyChatViewPriv *priv;
1354 g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view));
1355 g_return_if_fail (!G_STR_EMPTY (str));
1357 priv = GET_PRIV (view);
1359 bottom = chat_view_is_scrolled_down (view);
1361 chat_view_maybe_trim_buffer (view);
1363 if (priv->irc_style) {
1365 msg = g_strdup_printf (" - %s\n", str);
1367 tag = "fancy-event";
1368 msg = g_strdup_printf (" - %s\n", str);
1371 if (priv->last_block_type != BLOCK_TYPE_EVENT) {
1372 /* Comment out for now. */
1373 /*chat_view_append_spacing (view);*/
1376 chat_view_maybe_append_date_and_time (view, NULL);
1378 gtk_text_buffer_get_end_iter (priv->buffer, &iter);
1380 gtk_text_buffer_insert_with_tags_by_name (priv->buffer, &iter,
1387 empathy_chat_view_scroll_down (view);
1390 priv->last_block_type = BLOCK_TYPE_EVENT;
1394 empathy_chat_view_append_button (EmpathyChatView *view,
1395 const gchar *message,
1399 EmpathyChatViewPriv *priv;
1400 GtkTextChildAnchor *anchor;
1405 g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view));
1406 g_return_if_fail (button1 != NULL);
1408 priv = GET_PRIV (view);
1410 if (priv->irc_style) {
1413 tag = "fancy-invite";
1416 bottom = chat_view_is_scrolled_down (view);
1418 chat_view_maybe_append_date_and_time (view, NULL);
1421 chat_view_append_text (view, message, tag);
1424 gtk_text_buffer_get_end_iter (priv->buffer, &iter);
1426 anchor = gtk_text_buffer_create_child_anchor (priv->buffer, &iter);
1427 gtk_text_view_add_child_at_anchor (GTK_TEXT_VIEW (view), button1, anchor);
1428 gtk_widget_show (button1);
1430 gtk_text_buffer_insert_with_tags_by_name (priv->buffer,
1438 gtk_text_buffer_get_end_iter (priv->buffer, &iter);
1440 anchor = gtk_text_buffer_create_child_anchor (priv->buffer, &iter);
1441 gtk_text_view_add_child_at_anchor (GTK_TEXT_VIEW (view), button2, anchor);
1442 gtk_widget_show (button2);
1444 gtk_text_buffer_insert_with_tags_by_name (priv->buffer,
1452 gtk_text_buffer_get_end_iter (priv->buffer, &iter);
1453 gtk_text_buffer_insert_with_tags_by_name (priv->buffer,
1461 empathy_chat_view_scroll_down (view);
1464 priv->last_block_type = BLOCK_TYPE_INVITE;
1468 empathy_chat_view_scroll (EmpathyChatView *view,
1469 gboolean allow_scrolling)
1471 EmpathyChatViewPriv *priv;
1473 g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view));
1475 priv = GET_PRIV (view);
1477 priv->allow_scrolling = allow_scrolling;
1479 empathy_debug (DEBUG_DOMAIN, "Scrolling %s",
1480 allow_scrolling ? "enabled" : "disabled");
1483 /* Code stolen from pidgin/gtkimhtml.c */
1485 chat_view_scroll_cb (EmpathyChatView *view)
1487 EmpathyChatViewPriv *priv;
1491 priv = GET_PRIV (view);
1492 adj = GTK_TEXT_VIEW (view)->vadjustment;
1493 max_val = adj->upper - adj->page_size;
1495 g_return_val_if_fail (priv->scroll_time != NULL, FALSE);
1497 if (g_timer_elapsed (priv->scroll_time, NULL) > MAX_SCROLL_TIME) {
1498 /* time's up. jump to the end and kill the timer */
1499 gtk_adjustment_set_value (adj, max_val);
1500 g_timer_destroy (priv->scroll_time);
1501 priv->scroll_time = NULL;
1502 priv->scroll_timeout = 0;
1506 /* scroll by 1/3rd the remaining distance */
1507 gtk_adjustment_set_value (adj, gtk_adjustment_get_value (adj) + ((max_val - gtk_adjustment_get_value (adj)) / 3));
1512 empathy_chat_view_scroll_down (EmpathyChatView *view)
1514 EmpathyChatViewPriv *priv;
1516 g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view));
1518 priv = GET_PRIV (view);
1520 if (!priv->allow_scrolling) {
1524 empathy_debug (DEBUG_DOMAIN, "Scrolling down");
1526 if (priv->scroll_time) {
1527 g_timer_reset (priv->scroll_time);
1529 priv->scroll_time = g_timer_new();
1531 if (!priv->scroll_timeout) {
1532 priv->scroll_timeout = g_timeout_add (SCROLL_DELAY,
1533 (GSourceFunc) chat_view_scroll_cb,
1539 empathy_chat_view_get_selection_bounds (EmpathyChatView *view,
1543 GtkTextBuffer *buffer;
1545 g_return_val_if_fail (EMPATHY_IS_CHAT_VIEW (view), FALSE);
1547 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
1549 return gtk_text_buffer_get_selection_bounds (buffer, start, end);
1553 empathy_chat_view_clear (EmpathyChatView *view)
1555 GtkTextBuffer *buffer;
1556 EmpathyChatViewPriv *priv;
1558 g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view));
1560 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
1561 gtk_text_buffer_set_text (buffer, "", -1);
1563 /* We set these back to the initial values so we get
1564 * timestamps when clearing the window to know when
1565 * conversations start.
1567 priv = GET_PRIV (view);
1569 priv->last_block_type = BLOCK_TYPE_NONE;
1570 priv->last_timestamp = 0;
1574 empathy_chat_view_find_previous (EmpathyChatView *view,
1575 const gchar *search_criteria,
1576 gboolean new_search)
1578 EmpathyChatViewPriv *priv;
1579 GtkTextBuffer *buffer;
1580 GtkTextIter iter_at_mark;
1581 GtkTextIter iter_match_start;
1582 GtkTextIter iter_match_end;
1584 gboolean from_start = FALSE;
1586 g_return_val_if_fail (EMPATHY_IS_CHAT_VIEW (view), FALSE);
1587 g_return_val_if_fail (search_criteria != NULL, FALSE);
1589 priv = GET_PRIV (view);
1591 buffer = priv->buffer;
1593 if (G_STR_EMPTY (search_criteria)) {
1594 if (priv->find_mark_previous) {
1595 gtk_text_buffer_get_start_iter (buffer, &iter_at_mark);
1597 gtk_text_buffer_move_mark (buffer,
1598 priv->find_mark_previous,
1600 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view),
1601 priv->find_mark_previous,
1606 gtk_text_buffer_select_range (buffer,
1618 if (priv->find_mark_previous) {
1619 gtk_text_buffer_get_iter_at_mark (buffer,
1621 priv->find_mark_previous);
1623 gtk_text_buffer_get_end_iter (buffer, &iter_at_mark);
1627 priv->find_last_direction = FALSE;
1629 found = empathy_text_iter_backward_search (&iter_at_mark,
1636 gboolean result = FALSE;
1642 /* Here we wrap around. */
1643 if (!new_search && !priv->find_wrapped) {
1644 priv->find_wrapped = TRUE;
1645 result = empathy_chat_view_find_previous (view,
1648 priv->find_wrapped = FALSE;
1654 /* Set new mark and show on screen */
1655 if (!priv->find_mark_previous) {
1656 priv->find_mark_previous = gtk_text_buffer_create_mark (buffer, NULL,
1660 gtk_text_buffer_move_mark (buffer,
1661 priv->find_mark_previous,
1665 if (!priv->find_mark_next) {
1666 priv->find_mark_next = gtk_text_buffer_create_mark (buffer, NULL,
1670 gtk_text_buffer_move_mark (buffer,
1671 priv->find_mark_next,
1675 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view),
1676 priv->find_mark_previous,
1682 gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &iter_match_start);
1683 gtk_text_buffer_move_mark_by_name (buffer, "insert", &iter_match_end);
1689 empathy_chat_view_find_next (EmpathyChatView *view,
1690 const gchar *search_criteria,
1691 gboolean new_search)
1693 EmpathyChatViewPriv *priv;
1694 GtkTextBuffer *buffer;
1695 GtkTextIter iter_at_mark;
1696 GtkTextIter iter_match_start;
1697 GtkTextIter iter_match_end;
1699 gboolean from_start = FALSE;
1701 g_return_val_if_fail (EMPATHY_IS_CHAT_VIEW (view), FALSE);
1702 g_return_val_if_fail (search_criteria != NULL, FALSE);
1704 priv = GET_PRIV (view);
1706 buffer = priv->buffer;
1708 if (G_STR_EMPTY (search_criteria)) {
1709 if (priv->find_mark_next) {
1710 gtk_text_buffer_get_start_iter (buffer, &iter_at_mark);
1712 gtk_text_buffer_move_mark (buffer,
1713 priv->find_mark_next,
1715 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view),
1716 priv->find_mark_next,
1721 gtk_text_buffer_select_range (buffer,
1733 if (priv->find_mark_next) {
1734 gtk_text_buffer_get_iter_at_mark (buffer,
1736 priv->find_mark_next);
1738 gtk_text_buffer_get_start_iter (buffer, &iter_at_mark);
1742 priv->find_last_direction = TRUE;
1744 found = empathy_text_iter_forward_search (&iter_at_mark,
1751 gboolean result = FALSE;
1757 /* Here we wrap around. */
1758 if (!new_search && !priv->find_wrapped) {
1759 priv->find_wrapped = TRUE;
1760 result = empathy_chat_view_find_next (view,
1763 priv->find_wrapped = FALSE;
1769 /* Set new mark and show on screen */
1770 if (!priv->find_mark_next) {
1771 priv->find_mark_next = gtk_text_buffer_create_mark (buffer, NULL,
1775 gtk_text_buffer_move_mark (buffer,
1776 priv->find_mark_next,
1780 if (!priv->find_mark_previous) {
1781 priv->find_mark_previous = gtk_text_buffer_create_mark (buffer, NULL,
1785 gtk_text_buffer_move_mark (buffer,
1786 priv->find_mark_previous,
1790 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view),
1791 priv->find_mark_next,
1797 gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &iter_match_start);
1798 gtk_text_buffer_move_mark_by_name (buffer, "insert", &iter_match_end);
1805 empathy_chat_view_find_abilities (EmpathyChatView *view,
1806 const gchar *search_criteria,
1807 gboolean *can_do_previous,
1808 gboolean *can_do_next)
1810 EmpathyChatViewPriv *priv;
1811 GtkTextBuffer *buffer;
1812 GtkTextIter iter_at_mark;
1813 GtkTextIter iter_match_start;
1814 GtkTextIter iter_match_end;
1816 g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view));
1817 g_return_if_fail (search_criteria != NULL);
1818 g_return_if_fail (can_do_previous != NULL && can_do_next != NULL);
1820 priv = GET_PRIV (view);
1822 buffer = priv->buffer;
1824 if (can_do_previous) {
1825 if (priv->find_mark_previous) {
1826 gtk_text_buffer_get_iter_at_mark (buffer,
1828 priv->find_mark_previous);
1830 gtk_text_buffer_get_start_iter (buffer, &iter_at_mark);
1833 *can_do_previous = empathy_text_iter_backward_search (&iter_at_mark,
1841 if (priv->find_mark_next) {
1842 gtk_text_buffer_get_iter_at_mark (buffer,
1844 priv->find_mark_next);
1846 gtk_text_buffer_get_start_iter (buffer, &iter_at_mark);
1849 *can_do_next = empathy_text_iter_forward_search (&iter_at_mark,
1858 empathy_chat_view_highlight (EmpathyChatView *view,
1861 GtkTextBuffer *buffer;
1863 GtkTextIter iter_start;
1864 GtkTextIter iter_end;
1865 GtkTextIter iter_match_start;
1866 GtkTextIter iter_match_end;
1869 g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view));
1871 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
1873 gtk_text_buffer_get_start_iter (buffer, &iter);
1875 gtk_text_buffer_get_bounds (buffer, &iter_start, &iter_end);
1876 gtk_text_buffer_remove_tag_by_name (buffer, "highlight",
1880 if (G_STR_EMPTY (text)) {
1885 found = empathy_text_iter_forward_search (&iter,
1895 gtk_text_buffer_apply_tag_by_name (buffer, "highlight",
1899 iter = iter_match_end;
1900 gtk_text_iter_forward_char (&iter);
1905 empathy_chat_view_copy_clipboard (EmpathyChatView *view)
1907 GtkTextBuffer *buffer;
1908 GtkClipboard *clipboard;
1910 g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view));
1912 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
1913 clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
1915 gtk_text_buffer_copy_clipboard (buffer, clipboard);
1919 empathy_chat_view_get_irc_style (EmpathyChatView *view)
1921 EmpathyChatViewPriv *priv;
1923 g_return_val_if_fail (EMPATHY_IS_CHAT_VIEW (view), FALSE);
1925 priv = GET_PRIV (view);
1927 return priv->irc_style;
1931 empathy_chat_view_set_irc_style (EmpathyChatView *view,
1934 EmpathyChatViewPriv *priv;
1936 g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view));
1938 priv = GET_PRIV (view);
1940 priv->irc_style = irc_style;
1944 empathy_chat_view_set_margin (EmpathyChatView *view,
1947 EmpathyChatViewPriv *priv;
1949 g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view));
1951 priv = GET_PRIV (view);
1954 "left-margin", margin,
1955 "right-margin", margin,
1960 empathy_chat_view_get_smiley_menu (GCallback callback,
1963 EmpathySmileyManager *smiley_manager;
1964 GSList *smileys, *l;
1969 g_return_val_if_fail (callback != NULL, NULL);
1971 menu = gtk_menu_new ();
1973 smiley_manager = empathy_smiley_manager_new ();
1974 smileys = empathy_smiley_manager_get_all (smiley_manager);
1975 for (l = smileys; l; l = l->next) {
1976 EmpathySmiley *smiley;
1981 image = gtk_image_new_from_pixbuf (smiley->pixbuf);
1983 item = gtk_image_menu_item_new_with_label ("");
1984 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
1986 gtk_menu_attach (GTK_MENU (menu), item,
1987 x, x + 1, y, y + 1);
1989 gtk_widget_set_tooltip_text (item, smiley->str);
1991 g_object_set_data (G_OBJECT (item), "smiley_text", smiley->str);
1992 g_signal_connect (item, "activate", callback, user_data);
2001 g_object_unref (smiley_manager);
2003 gtk_widget_show_all (menu);
2008 /* FIXME: Do we really need this? Better to do it internally only at setup time,
2009 * we will never change it on the fly.
2012 empathy_chat_view_set_is_group_chat (EmpathyChatView *view,
2013 gboolean is_group_chat)
2015 EmpathyChatViewPriv *priv;
2016 gboolean theme_rooms = FALSE;
2018 g_return_if_fail (EMPATHY_IS_CHAT_VIEW (view));
2020 priv = GET_PRIV (view);
2022 priv->is_group_chat = is_group_chat;
2024 empathy_conf_get_bool (empathy_conf_get (),
2025 EMPATHY_PREFS_CHAT_THEME_CHAT_ROOM,
2028 if (!theme_rooms && is_group_chat) {
2029 empathy_theme_manager_apply (empathy_theme_manager_get (),
2033 empathy_theme_manager_apply_saved (empathy_theme_manager_get (),