pidgin/gtkconv.c

branch
soc.2009.webkitmessageview
changeset 32439
2c681e5daeeb
parent 27779
ad70fa8a4ae2
child 32483
00b642e26a2d
equal deleted inserted replaced
27944:e71e3e3134b3 32439:2c681e5daeeb
67 #include "gtkpounce.h" 67 #include "gtkpounce.h"
68 #include "gtkprefs.h" 68 #include "gtkprefs.h"
69 #include "gtkprivacy.h" 69 #include "gtkprivacy.h"
70 #include "gtkthemes.h" 70 #include "gtkthemes.h"
71 #include "gtkutils.h" 71 #include "gtkutils.h"
72 #include "gtkwebview.h"
72 #include "pidginstock.h" 73 #include "pidginstock.h"
73 #include "pidgintooltip.h" 74 #include "pidgintooltip.h"
74 75
75 #include "gtknickcolors.h" 76 #include "gtknickcolors.h"
76 77
162 static void update_typing_message(PidginConversation *gtkconv, const char *message); 163 static void update_typing_message(PidginConversation *gtkconv, const char *message);
163 static const char *item_factory_translate_func (const char *path, gpointer func_data); 164 static const char *item_factory_translate_func (const char *path, gpointer func_data);
164 gboolean pidgin_conv_has_focus(PurpleConversation *conv); 165 gboolean pidgin_conv_has_focus(PurpleConversation *conv);
165 static GdkColor* generate_nick_colors(guint *numcolors, GdkColor background); 166 static GdkColor* generate_nick_colors(guint *numcolors, GdkColor background);
166 static gboolean color_is_visible(GdkColor foreground, GdkColor background, int color_contrast, int brightness_contrast); 167 static gboolean color_is_visible(GdkColor foreground, GdkColor background, int color_contrast, int brightness_contrast);
167 static GtkTextTag *get_buddy_tag(PurpleConversation *conv, const char *who, PurpleMessageFlags flag, gboolean create);
168 static void pidgin_conv_update_fields(PurpleConversation *conv, PidginConvFields fields); 168 static void pidgin_conv_update_fields(PurpleConversation *conv, PidginConvFields fields);
169 static void focus_out_from_menubar(GtkWidget *wid, PidginWindow *win); 169 static void focus_out_from_menubar(GtkWidget *wid, PidginWindow *win);
170 static void pidgin_conv_tab_pack(PidginWindow *win, PidginConversation *gtkconv); 170 static void pidgin_conv_tab_pack(PidginWindow *win, PidginConversation *gtkconv);
171 static gboolean infopane_press_cb(GtkWidget *widget, GdkEventButton *e, PidginConversation *conv); 171 static gboolean infopane_press_cb(GtkWidget *widget, GdkEventButton *e, PidginConversation *conv);
172 static void hide_conv(PidginConversation *gtkconv, gboolean closetimer); 172 static void hide_conv(PidginConversation *gtkconv, gboolean closetimer);
176 static gboolean pidgin_conv_xy_to_right_infopane(PidginWindow *win, int x, int y); 176 static gboolean pidgin_conv_xy_to_right_infopane(PidginWindow *win, int x, int y);
177 177
178 static const GdkColor *get_nick_color(PidginConversation *gtkconv, const char *name) 178 static const GdkColor *get_nick_color(PidginConversation *gtkconv, const char *name)
179 { 179 {
180 static GdkColor col; 180 static GdkColor col;
181 GtkStyle *style = gtk_widget_get_style(gtkconv->imhtml); 181 GtkStyle *style = gtk_widget_get_style(gtkconv->webview);
182 float scale; 182 float scale;
183 183
184 col = nick_colors[g_str_hash(name) % nbr_nick_colors]; 184 col = nick_colors[g_str_hash(name) % nbr_nick_colors];
185 scale = ((1-(LUMINANCE(style->base[GTK_STATE_NORMAL]) / LUMINANCE(style->white))) * 185 scale = ((1-(LUMINANCE(style->base[GTK_STATE_NORMAL]) / LUMINANCE(style->white))) *
186 (LUMINANCE(style->white)/MAX(MAX(col.red, col.blue), col.green))); 186 (LUMINANCE(style->white)/MAX(MAX(col.red, col.blue), col.green)));
351 PidginConversation *gtkconv = NULL; 351 PidginConversation *gtkconv = NULL;
352 GList *iter; 352 GList *iter;
353 353
354 gtkconv = PIDGIN_CONVERSATION(conv); 354 gtkconv = PIDGIN_CONVERSATION(conv);
355 355
356 gtk_imhtml_clear(GTK_IMHTML(gtkconv->imhtml)); 356 webkit_web_view_load_html_string (WEBKIT_WEB_VIEW (gtkconv->webview), "", "");
357 for (iter = gtkconv->convs; iter; iter = iter->next) 357 for (iter = gtkconv->convs; iter; iter = iter->next)
358 purple_conversation_clear_message_history(iter->data); 358 purple_conversation_clear_message_history(iter->data);
359 } 359 }
360 360
361 static PurpleCmdRet 361 static PurpleCmdRet
959 } 959 }
960 960
961 static void 961 static void
962 savelog_writefile_cb(void *user_data, const char *filename) 962 savelog_writefile_cb(void *user_data, const char *filename)
963 { 963 {
964 PurpleConversation *conv = (PurpleConversation *)user_data; 964 /* TODO: I don't know how to support this using webkit yet. */
965 FILE *fp;
966 const char *name;
967 char **lines;
968 gchar *text;
969
970 if ((fp = g_fopen(filename, "w+")) == NULL) {
971 purple_notify_error(PIDGIN_CONVERSATION(conv), NULL, _("Unable to open file."), NULL);
972 return;
973 }
974
975 name = purple_conversation_get_name(conv);
976 fprintf(fp, "<html>\n<head>\n");
977 fprintf(fp, "<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n");
978 fprintf(fp, "<title>%s</title>\n</head>\n<body>\n", name);
979 fprintf(fp, _("<h1>Conversation with %s</h1>\n"), name);
980
981 lines = gtk_imhtml_get_markup_lines(
982 GTK_IMHTML(PIDGIN_CONVERSATION(conv)->imhtml));
983 text = g_strjoinv("<br>\n", lines);
984 fprintf(fp, "%s", text);
985 g_free(text);
986 g_strfreev(lines);
987
988 fprintf(fp, "\n</body>\n</html>\n");
989 fclose(fp);
990 } 965 }
991 966
992 /* 967 /*
993 * It would be kinda cool if this gave the option of saving a 968 * It would be kinda cool if this gave the option of saving a
994 * plaintext v. HTML file. 969 * plaintext v. HTML file.
1114 { 1089 {
1115 PidginConversation *gtkconv = iter->data; 1090 PidginConversation *gtkconv = iter->data;
1116 1091
1117 if (gtkconv != gtk_active_conv) 1092 if (gtkconv != gtk_active_conv)
1118 { 1093 {
1119 gtk_imhtml_search_clear(GTK_IMHTML(gtkconv->imhtml)); 1094 webkit_web_view_unmark_text_matches (WEBKIT_WEB_VIEW (gtkconv->webview));
1120 } 1095 }
1121 else 1096 else
1122 { 1097 {
1123 gtk_imhtml_search_find(GTK_IMHTML(gtk_active_conv->imhtml), 1098 webkit_web_view_mark_text_matches (WEBKIT_WEB_VIEW (gtkconv->webview),
1124 gtk_entry_get_text(GTK_ENTRY(s->entry))); 1099 gtk_entry_get_text (GTK_ENTRY(s->entry)), TRUE, 0);
1100 webkit_web_view_set_highlight_text_matches (WEBKIT_WEB_VIEW (gtkconv->webview),
1101 true);
1102 webkit_web_view_search_text (WEBKIT_WEB_VIEW (gtkconv->webview),
1103 gtk_entry_get_text (GTK_ENTRY(s->entry)), FALSE, TRUE, FALSE);
1125 } 1104 }
1126 } 1105 }
1127 break; 1106 break;
1128 1107
1129 case GTK_RESPONSE_DELETE_EVENT: 1108 case GTK_RESPONSE_DELETE_EVENT:
1130 case GTK_RESPONSE_CLOSE: 1109 case GTK_RESPONSE_CLOSE:
1131 /* clear the keyword highlighting in all the conversation windows */ 1110 /* clear the keyword highlighting in all the conversation windows */
1132 for (iter = pidgin_conv_window_get_gtkconvs(s->gtkwin); iter; iter=iter->next) 1111 for (iter = pidgin_conv_window_get_gtkconvs(s->gtkwin); iter; iter=iter->next)
1133 { 1112 {
1134 PidginConversation *gconv = iter->data; 1113 PidginConversation *gconv = iter->data;
1135 gtk_imhtml_search_clear(GTK_IMHTML(gconv->imhtml)); 1114 webkit_web_view_unmark_text_matches (WEBKIT_WEB_VIEW(gconv->webview));
1136 } 1115 }
1137 1116
1138 gtk_widget_destroy(s->gtkwin->dialogs.search); 1117 gtk_widget_destroy(s->gtkwin->dialogs.search);
1139 s->gtkwin->dialogs.search = NULL; 1118 s->gtkwin->dialogs.search = NULL;
1140 g_free(s); 1119 g_free(s);
1633 purple_blist_request_add_buddy(account, name, NULL, NULL); 1612 purple_blist_request_add_buddy(account, name, NULL, NULL);
1634 1613
1635 gtk_widget_grab_focus(PIDGIN_CONVERSATION(conv)->entry); 1614 gtk_widget_grab_focus(PIDGIN_CONVERSATION(conv)->entry);
1636 } 1615 }
1637 1616
1638 static GtkTextMark *
1639 get_mark_for_user(PidginConversation *gtkconv, const char *who)
1640 {
1641 GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtkconv->imhtml));
1642 char *tmp = g_strconcat("user:", who, NULL);
1643 GtkTextMark *mark = gtk_text_buffer_get_mark(buf, tmp);
1644
1645 g_free(tmp);
1646 return mark;
1647 }
1648
1649 static void 1617 static void
1650 menu_last_said_cb(GtkWidget *w, PidginConversation *gtkconv) 1618 menu_last_said_cb(GtkWidget *w, PidginConversation *gtkconv)
1651 { 1619 {
1652 GtkTextMark *mark; 1620 /* I don't know what this is! */
1653 const char *who; 1621 return;
1654
1655 who = g_object_get_data(G_OBJECT(w), "user_data");
1656 mark = get_mark_for_user(gtkconv, who);
1657
1658 if (mark != NULL)
1659 gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(gtkconv->imhtml), mark, 0.1, FALSE, 0, 0);
1660 else
1661 g_return_if_reached();
1662 } 1622 }
1663 1623
1664 static GtkWidget * 1624 static GtkWidget *
1665 create_chat_menu(PurpleConversation *conv, const char *who, PurpleConnection *gc) 1625 create_chat_menu(PurpleConversation *conv, const char *who, PurpleConnection *gc)
1666 { 1626 {
1771 } 1731 }
1772 1732
1773 button = pidgin_new_item_from_stock(menu, _("Last Said"), GTK_STOCK_INDEX, 1733 button = pidgin_new_item_from_stock(menu, _("Last Said"), GTK_STOCK_INDEX,
1774 G_CALLBACK(menu_last_said_cb), PIDGIN_CONVERSATION(conv), 0, 0, NULL); 1734 G_CALLBACK(menu_last_said_cb), PIDGIN_CONVERSATION(conv), 0, 0, NULL);
1775 g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free); 1735 g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free);
1776 if (!get_mark_for_user(PIDGIN_CONVERSATION(conv), who))
1777 gtk_widget_set_sensitive(button, FALSE);
1778 1736
1779 if (buddy != NULL) 1737 if (buddy != NULL)
1780 { 1738 {
1781 if (purple_account_is_connected(conv->account)) 1739 if (purple_account_is_connected(conv->account))
1782 pidgin_append_blist_node_proto_menu(menu, conv->account->gc, 1740 pidgin_append_blist_node_proto_menu(menu, conv->account->gc,
1862 1820
1863 if (event->button == 1 && event->type == GDK_2BUTTON_PRESS) { 1821 if (event->button == 1 && event->type == GDK_2BUTTON_PRESS) {
1864 chat_do_im(gtkconv, who); 1822 chat_do_im(gtkconv, who);
1865 } else if (event->button == 2 && event->type == GDK_BUTTON_PRESS) { 1823 } else if (event->button == 2 && event->type == GDK_BUTTON_PRESS) {
1866 /* Move to user's anchor */ 1824 /* Move to user's anchor */
1867 GtkTextMark *mark = get_mark_for_user(gtkconv, who); 1825 //GtkTextMark *mark = get_mark_for_user(gtkconv, who);
1868 1826
1869 if(mark != NULL) 1827 //if(mark != NULL)
1870 gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(gtkconv->imhtml), mark, 0.1, FALSE, 0, 0); 1828 // gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(gtkconv->imhtml), mark, 0.1, FALSE, 0, 0);
1871 } else if (event->button == 3 && event->type == GDK_BUTTON_PRESS) { 1829 } else if (event->button == 3 && event->type == GDK_BUTTON_PRESS) {
1872 GtkWidget *menu = create_chat_menu (conv, who, gc); 1830 GtkWidget *menu = create_chat_menu (conv, who, gc);
1873 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 1831 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
1874 event->button, event->time); 1832 event->button, event->time);
1875 } 1833 }
1941 GtkWidget *next = NULL; 1899 GtkWidget *next = NULL;
1942 struct { 1900 struct {
1943 GtkWidget *from; 1901 GtkWidget *from;
1944 GtkWidget *to; 1902 GtkWidget *to;
1945 } transitions[] = { 1903 } transitions[] = {
1946 {gtkconv->entry, gtkconv->imhtml}, 1904 {gtkconv->entry, gtkconv->webview},
1947 {gtkconv->imhtml, chat ? gtkconv->u.chat->list : gtkconv->entry}, 1905 {gtkconv->webview, chat ? gtkconv->u.chat->list : gtkconv->entry},
1948 {chat ? gtkconv->u.chat->list : NULL, gtkconv->entry}, 1906 {chat ? gtkconv->u.chat->list : NULL, gtkconv->entry},
1949 {NULL, NULL} 1907 {NULL, NULL}
1950 }, *ptr; 1908 }, *ptr;
1951 1909
1952 for (ptr = transitions; !next && ptr->from; ptr++) { 1910 for (ptr = transitions; !next && ptr->from; ptr++) {
2198 break; 2156 break;
2199 return tab_complete(conv); 2157 return tab_complete(conv);
2200 break; 2158 break;
2201 2159
2202 case GDK_Page_Up: 2160 case GDK_Page_Up:
2203 gtk_imhtml_page_up(GTK_IMHTML(gtkconv->imhtml)); 2161 //gtk_imhtml_page_up(GTK_IMHTML(gtkconv->imhtml));
2204 return TRUE; 2162 return TRUE;
2205 break; 2163 break;
2206 2164
2207 case GDK_Page_Down: 2165 case GDK_Page_Down:
2208 gtk_imhtml_page_down(GTK_IMHTML(gtkconv->imhtml)); 2166 //gtk_imhtml_page_down(GTK_IMHTML(gtkconv->imhtml));
2209 return TRUE; 2167 return TRUE;
2210 break; 2168 break;
2211 2169
2212 } 2170 }
2213 } 2171 }
2306 gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(gtkconv->win->menu.logging))); 2264 gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(gtkconv->win->menu.logging)));
2307 2265
2308 entry = GTK_IMHTML(gtkconv->entry); 2266 entry = GTK_IMHTML(gtkconv->entry);
2309 protocol_name = purple_account_get_protocol_name(conv->account); 2267 protocol_name = purple_account_get_protocol_name(conv->account);
2310 gtk_imhtml_set_protocol_name(entry, protocol_name); 2268 gtk_imhtml_set_protocol_name(entry, protocol_name);
2311 gtk_imhtml_set_protocol_name(GTK_IMHTML(gtkconv->imhtml), protocol_name); 2269 //gtk_imhtml_set_protocol_name(GTK_IMHTML(gtkconv->imhtml), protocol_name);
2312 2270
2313 if (!(conv->features & PURPLE_CONNECTION_HTML)) 2271 if (!(conv->features & PURPLE_CONNECTION_HTML))
2314 gtk_imhtml_clear_formatting(GTK_IMHTML(gtkconv->entry)); 2272 gtk_imhtml_clear_formatting(GTK_IMHTML(gtkconv->entry));
2315 else if (conv->features & PURPLE_CONNECTION_FORMATTING_WBFO && 2273 else if (conv->features & PURPLE_CONNECTION_FORMATTING_WBFO &&
2316 !(old_conv->features & PURPLE_CONNECTION_FORMATTING_WBFO)) 2274 !(old_conv->features & PURPLE_CONNECTION_FORMATTING_WBFO))
3248 conv = gtkconv->active_conv; 3206 conv = gtkconv->active_conv;
3249 3207
3250 if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) { 3208 if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) {
3251 chat = purple_blist_find_chat(conv->account, conv->name); 3209 chat = purple_blist_find_chat(conv->account, conv->name);
3252 3210
3253 if ((chat == NULL) && (gtkconv->imhtml != NULL)) { 3211 if ((chat == NULL) && (gtkconv->webview != NULL)) {
3254 chat = g_object_get_data(G_OBJECT(gtkconv->imhtml), "transient_chat"); 3212 chat = g_object_get_data(G_OBJECT(gtkconv->webview), "transient_chat");
3255 } 3213 }
3256 3214
3257 if ((chat == NULL) && (gtkconv->imhtml != NULL)) { 3215 if ((chat == NULL) && (gtkconv->webview != NULL)) {
3258 GHashTable *components; 3216 GHashTable *components;
3259 PurpleAccount *account = purple_conversation_get_account(conv); 3217 PurpleAccount *account = purple_conversation_get_account(conv);
3260 PurplePlugin *prpl = purple_find_prpl(purple_account_get_protocol_id(account)); 3218 PurplePlugin *prpl = purple_find_prpl(purple_account_get_protocol_id(account));
3261 PurplePluginProtocolInfo *prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl); 3219 PurplePluginProtocolInfo *prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
3262 if (purple_account_get_connection(account) != NULL && 3220 if (purple_account_get_connection(account) != NULL &&
3270 g_strdup(purple_conversation_get_name(conv))); 3228 g_strdup(purple_conversation_get_name(conv)));
3271 } 3229 }
3272 chat = purple_chat_new(conv->account, NULL, components); 3230 chat = purple_chat_new(conv->account, NULL, components);
3273 purple_blist_node_set_flags((PurpleBlistNode *)chat, 3231 purple_blist_node_set_flags((PurpleBlistNode *)chat,
3274 PURPLE_BLIST_NODE_FLAG_NO_SAVE); 3232 PURPLE_BLIST_NODE_FLAG_NO_SAVE);
3275 g_object_set_data_full(G_OBJECT(gtkconv->imhtml), "transient_chat", 3233 g_object_set_data_full(G_OBJECT(gtkconv->webview), "transient_chat",
3276 chat, (GDestroyNotify)purple_blist_remove_chat); 3234 chat, (GDestroyNotify)purple_blist_remove_chat);
3277 } 3235 }
3278 } else { 3236 } else {
3279 if (!purple_account_is_connected(conv->account)) 3237 if (!purple_account_is_connected(conv->account))
3280 return FALSE; 3238 return FALSE;
3282 buddy = purple_find_buddy(conv->account, conv->name); 3240 buddy = purple_find_buddy(conv->account, conv->name);
3283 3241
3284 /* gotta remain bug-compatible :( libpurple < 2.0.2 didn't handle 3242 /* gotta remain bug-compatible :( libpurple < 2.0.2 didn't handle
3285 * removing "isolated" buddy nodes well */ 3243 * removing "isolated" buddy nodes well */
3286 if (purple_version_check(2, 0, 2) == NULL) { 3244 if (purple_version_check(2, 0, 2) == NULL) {
3287 if ((buddy == NULL) && (gtkconv->imhtml != NULL)) { 3245 if ((buddy == NULL) && (gtkconv->webview != NULL)) {
3288 buddy = g_object_get_data(G_OBJECT(gtkconv->imhtml), "transient_buddy"); 3246 buddy = g_object_get_data(G_OBJECT(gtkconv->webview), "transient_buddy");
3289 } 3247 }
3290 3248
3291 if ((buddy == NULL) && (gtkconv->imhtml != NULL)) { 3249 if ((buddy == NULL) && (gtkconv->webview != NULL)) {
3292 buddy = purple_buddy_new(conv->account, conv->name, NULL); 3250 buddy = purple_buddy_new(conv->account, conv->name, NULL);
3293 purple_blist_node_set_flags((PurpleBlistNode *)buddy, 3251 purple_blist_node_set_flags((PurpleBlistNode *)buddy,
3294 PURPLE_BLIST_NODE_FLAG_NO_SAVE); 3252 PURPLE_BLIST_NODE_FLAG_NO_SAVE);
3295 g_object_set_data_full(G_OBJECT(gtkconv->imhtml), "transient_buddy", 3253 g_object_set_data_full(G_OBJECT(gtkconv->webview), "transient_buddy",
3296 buddy, (GDestroyNotify)purple_buddy_destroy); 3254 buddy, (GDestroyNotify)purple_buddy_destroy);
3297 } 3255 }
3298 } 3256 }
3299 } 3257 }
3300 3258
3641 #endif 3599 #endif
3642 3600
3643 static void 3601 static void
3644 update_typing_message(PidginConversation *gtkconv, const char *message) 3602 update_typing_message(PidginConversation *gtkconv, const char *message)
3645 { 3603 {
3646 GtkTextBuffer *buffer; 3604 /* this is not handled at all */
3647 GtkTextMark *stmark, *enmark;
3648
3649 if (g_object_get_data(G_OBJECT(gtkconv->imhtml), "disable-typing-notification"))
3650 return;
3651
3652 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtkconv->imhtml));
3653 stmark = gtk_text_buffer_get_mark(buffer, "typing-notification-start");
3654 enmark = gtk_text_buffer_get_mark(buffer, "typing-notification-end");
3655 if (stmark && enmark) {
3656 GtkTextIter start, end;
3657 gtk_text_buffer_get_iter_at_mark(buffer, &start, stmark);
3658 gtk_text_buffer_get_iter_at_mark(buffer, &end, enmark);
3659 gtk_text_buffer_delete_mark(buffer, stmark);
3660 gtk_text_buffer_delete_mark(buffer, enmark);
3661 gtk_text_buffer_delete(buffer, &start, &end);
3662 } else if (message && *message == '\n' && message[1] == ' ' && message[2] == '\0')
3663 message = NULL;
3664
3665 #ifdef RESERVE_LINE
3666 if (!message)
3667 message = "\n "; /* The blank space is required to avoid a GTK+/Pango bug */
3668 #endif
3669
3670 if (message) {
3671 GtkTextIter iter;
3672 gtk_text_buffer_get_end_iter(buffer, &iter);
3673 gtk_text_buffer_create_mark(buffer, "typing-notification-start", &iter, TRUE);
3674 gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, message, -1, "TYPING-NOTIFICATION", NULL);
3675 gtk_text_buffer_get_end_iter(buffer, &iter);
3676 gtk_text_buffer_create_mark(buffer, "typing-notification-end", &iter, TRUE);
3677 }
3678 } 3605 }
3679 3606
3680 static void 3607 static void
3681 update_typing_icon(PidginConversation *gtkconv) 3608 update_typing_icon(PidginConversation *gtkconv)
3682 { 3609 {
3989 GtkTreeIter iter; 3916 GtkTreeIter iter;
3990 gboolean is_me = FALSE; 3917 gboolean is_me = FALSE;
3991 gboolean is_buddy; 3918 gboolean is_buddy;
3992 gchar *tmp, *alias_key, *name, *alias; 3919 gchar *tmp, *alias_key, *name, *alias;
3993 int flags; 3920 int flags;
3994 GdkColor *color = NULL;
3995 3921
3996 alias = cb->alias; 3922 alias = cb->alias;
3997 name = cb->name; 3923 name = cb->name;
3998 flags = GPOINTER_TO_INT(cb->flags); 3924 flags = GPOINTER_TO_INT(cb->flags);
3999 3925
4015 is_buddy = cb->buddy; 3941 is_buddy = cb->buddy;
4016 3942
4017 tmp = g_utf8_casefold(alias, -1); 3943 tmp = g_utf8_casefold(alias, -1);
4018 alias_key = g_utf8_collate_key(tmp, -1); 3944 alias_key = g_utf8_collate_key(tmp, -1);
4019 g_free(tmp); 3945 g_free(tmp);
4020
4021 if (is_me) {
4022 GtkTextTag *tag = gtk_text_tag_table_lookup(
4023 gtk_text_buffer_get_tag_table(GTK_IMHTML(gtkconv->imhtml)->text_buffer),
4024 "send-name");
4025 g_object_get(tag, "foreground-gdk", &color, NULL);
4026 } else {
4027 GtkTextTag *tag;
4028 if ((tag = get_buddy_tag(conv, name, 0, FALSE)))
4029 g_object_set(G_OBJECT(tag), "style", PANGO_STYLE_NORMAL, NULL);
4030 if ((tag = get_buddy_tag(conv, name, PURPLE_MESSAGE_NICK, FALSE)))
4031 g_object_set(G_OBJECT(tag), "style", PANGO_STYLE_NORMAL, NULL);
4032 color = (GdkColor*)get_nick_color(gtkconv, name);
4033 }
4034 3946
4035 #if GTK_CHECK_VERSION(2,6,0) 3947 #if GTK_CHECK_VERSION(2,6,0)
4036 gtk_list_store_insert_with_values(ls, &iter, 3948 gtk_list_store_insert_with_values(ls, &iter,
4037 /* 3949 /*
4038 * The GTK docs are mute about the effects of the "row" value for performance. 3950 * The GTK docs are mute about the effects of the "row" value for performance.
4045 CHAT_USERS_ICON_STOCK_COLUMN, stock, 3957 CHAT_USERS_ICON_STOCK_COLUMN, stock,
4046 CHAT_USERS_ALIAS_COLUMN, alias, 3958 CHAT_USERS_ALIAS_COLUMN, alias,
4047 CHAT_USERS_ALIAS_KEY_COLUMN, alias_key, 3959 CHAT_USERS_ALIAS_KEY_COLUMN, alias_key,
4048 CHAT_USERS_NAME_COLUMN, name, 3960 CHAT_USERS_NAME_COLUMN, name,
4049 CHAT_USERS_FLAGS_COLUMN, flags, 3961 CHAT_USERS_FLAGS_COLUMN, flags,
4050 CHAT_USERS_COLOR_COLUMN, color,
4051 CHAT_USERS_WEIGHT_COLUMN, is_buddy ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL, 3962 CHAT_USERS_WEIGHT_COLUMN, is_buddy ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL,
4052 -1); 3963 -1);
4053 #else 3964 #else
4054 gtk_list_store_append(ls, &iter); 3965 gtk_list_store_append(ls, &iter);
4055 gtk_list_store_set(ls, &iter, 3966 gtk_list_store_set(ls, &iter,
4056 CHAT_USERS_ICON_STOCK_COLUMN, stock, 3967 CHAT_USERS_ICON_STOCK_COLUMN, stock,
4057 CHAT_USERS_ALIAS_COLUMN, alias, 3968 CHAT_USERS_ALIAS_COLUMN, alias,
4058 CHAT_USERS_ALIAS_KEY_COLUMN, alias_key, 3969 CHAT_USERS_ALIAS_KEY_COLUMN, alias_key,
4059 CHAT_USERS_NAME_COLUMN, name, 3970 CHAT_USERS_NAME_COLUMN, name,
4060 CHAT_USERS_FLAGS_COLUMN, flags, 3971 CHAT_USERS_FLAGS_COLUMN, flags,
4061 CHAT_USERS_COLOR_COLUMN, color,
4062 CHAT_USERS_WEIGHT_COLUMN, is_buddy ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL, 3972 CHAT_USERS_WEIGHT_COLUMN, is_buddy ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL,
4063 -1); 3973 -1);
4064 #endif 3974 #endif
4065 3975
4066 if (is_me && color)
4067 gdk_color_free(color);
4068 g_free(alias_key); 3976 g_free(alias_key);
4069 } 3977 }
4070 3978
4071 static void 3979 static void
4072 tab_complete_process_item(int *most_matched, char *entered, gsize entered_bytes, char **partial, char *nick_partial, 3980 tab_complete_process_item(int *most_matched, char *entered, gsize entered_bytes, char **partial, char *nick_partial,
4456 buddy_cb_common(PurpleBuddy *buddy, PurpleConversation *conv, gboolean is_buddy) 4364 buddy_cb_common(PurpleBuddy *buddy, PurpleConversation *conv, gboolean is_buddy)
4457 { 4365 {
4458 GtkTreeModel *model; 4366 GtkTreeModel *model;
4459 char *normalized_name; 4367 char *normalized_name;
4460 GtkTreeIter iter; 4368 GtkTreeIter iter;
4461 GtkTextTag *texttag;
4462 int f; 4369 int f;
4463 4370
4464 g_return_if_fail(buddy != NULL); 4371 g_return_if_fail(buddy != NULL);
4465 g_return_if_fail(conv != NULL); 4372 g_return_if_fail(conv != NULL);
4466 4373
4495 4402
4496 g_free(normalized_name); 4403 g_free(normalized_name);
4497 4404
4498 blist_node_aliased_cb((PurpleBlistNode *)buddy, NULL, conv); 4405 blist_node_aliased_cb((PurpleBlistNode *)buddy, NULL, conv);
4499 4406
4500 texttag = get_buddy_tag(conv, purple_buddy_get_name(buddy), 0, FALSE); /* XXX: do we want the normalized name? */
4501 if (texttag) {
4502 g_object_set(texttag, "weight", is_buddy ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL, NULL);
4503 }
4504 } 4407 }
4505 4408
4506 static void 4409 static void
4507 buddy_added_cb(PurpleBlistNode *node, PurpleConversation *conv) 4410 buddy_added_cb(PurpleBlistNode *node, PurpleConversation *conv)
4508 { 4411 {
4530 { 4433 {
4531 g_signal_emit_by_name(gtkconv->entry, "message_send"); 4434 g_signal_emit_by_name(gtkconv->entry, "message_send");
4532 } 4435 }
4533 4436
4534 static void 4437 static void
4535 entry_popup_menu_cb(GtkIMHtml *imhtml, GtkMenu *menu, gpointer data) 4438 entry_popup_menu_cb(GtkIMHtml *imhtml /* this is for ->entry, fine! */, GtkMenu *menu, gpointer data)
4536 { 4439 {
4537 GtkWidget *menuitem; 4440 GtkWidget *menuitem;
4538 PidginConversation *gtkconv = data; 4441 PidginConversation *gtkconv = data;
4539 4442
4540 g_return_if_fail(menu != NULL); 4443 g_return_if_fail(menu != NULL);
4558 GtkTextIter iter; 4461 GtkTextIter iter;
4559 int lines; 4462 int lines;
4560 GdkRectangle oneline; 4463 GdkRectangle oneline;
4561 int height, diff; 4464 int height, diff;
4562 int pad_top, pad_inside, pad_bottom; 4465 int pad_top, pad_inside, pad_bottom;
4563 int total_height = (gtkconv->imhtml->allocation.height + gtkconv->entry->allocation.height); 4466 int total_height = (gtkconv->webview->allocation.height + gtkconv->entry->allocation.height);
4564 int max_height = total_height / 2; 4467 int max_height = total_height / 2;
4565 int min_lines = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/conversations/minimum_entry_lines"); 4468 int min_lines = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/conversations/minimum_entry_lines");
4566 int min_height; 4469 int min_height;
4567 4470
4568 pad_top = gtk_text_view_get_pixels_above_lines(GTK_TEXT_VIEW(gtkconv->entry)); 4471 pad_top = gtk_text_view_get_pixels_above_lines(GTK_TEXT_VIEW(gtkconv->entry));
4794 4697
4795 conv = gtkconv->active_conv; 4698 conv = gtkconv->active_conv;
4796 if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) { 4699 if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) {
4797 node = (PurpleBlistNode*)(purple_blist_find_chat(conv->account, conv->name)); 4700 node = (PurpleBlistNode*)(purple_blist_find_chat(conv->account, conv->name));
4798 if (!node) 4701 if (!node)
4799 node = g_object_get_data(G_OBJECT(gtkconv->imhtml), "transient_chat"); 4702 node = g_object_get_data(G_OBJECT(gtkconv->webview), "transient_chat");
4800 } else { 4703 } else {
4801 node = (PurpleBlistNode*)(purple_find_buddy(conv->account, conv->name)); 4704 node = (PurpleBlistNode*)(purple_find_buddy(conv->account, conv->name));
4802 #if 0 4705 #if 0
4803 /* Using the transient blist nodes to show the tooltip doesn't quite work yet. */ 4706 /* Using the transient blist nodes to show the tooltip doesn't quite work yet. */
4804 if (!node) 4707 if (!node)
4805 node = g_object_get_data(G_OBJECT(gtkconv->imhtml), "transient_buddy"); 4708 node = g_object_get_data(G_OBJECT(gtkconv->webview), "transient_buddy");
4806 #endif 4709 #endif
4807 } 4710 }
4808 4711
4809 if (node) 4712 if (node)
4810 pidgin_blist_draw_tooltip(node, gtkconv->infopane); 4713 pidgin_blist_draw_tooltip(node, gtkconv->infopane);
4812 } 4715 }
4813 4716
4814 static GtkWidget * 4717 static GtkWidget *
4815 setup_common_pane(PidginConversation *gtkconv) 4718 setup_common_pane(PidginConversation *gtkconv)
4816 { 4719 {
4817 GtkWidget *vbox, *frame, *imhtml_sw, *event_box; 4720 GtkWidget *vbox, *frame, *webview_sw, *event_box;
4818 GtkCellRenderer *rend; 4721 GtkCellRenderer *rend;
4819 GtkTreePath *path; 4722 GtkTreePath *path;
4820 PurpleConversation *conv = gtkconv->active_conv; 4723 PurpleConversation *conv = gtkconv->active_conv;
4821 PurpleBuddy *buddy; 4724 PurpleBuddy *buddy;
4822 gboolean chat = (conv->type == PURPLE_CONV_TYPE_CHAT); 4725 gboolean chat = (conv->type == PURPLE_CONV_TYPE_CHAT);
4823 GtkPolicyType imhtml_sw_hscroll; 4726 GtkPolicyType webview_sw_hscroll;
4824 int buddyicon_size = 0; 4727 int buddyicon_size = 0;
4825 4728
4826 /* Setup the top part of the pane */ 4729 /* Setup the top part of the pane */
4827 vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE); 4730 vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
4828 gtk_widget_show(vbox); 4731 gtk_widget_show(vbox);
4914 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(gtkconv->infopane), rend, FALSE); 4817 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(gtkconv->infopane), rend, FALSE);
4915 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(gtkconv->infopane), rend, "pixbuf", CONV_EMBLEM_COLUMN, NULL); 4818 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(gtkconv->infopane), rend, "pixbuf", CONV_EMBLEM_COLUMN, NULL);
4916 g_object_set(rend, "xalign", 0.0, "xpad", 6, "ypad", 0, NULL); 4819 g_object_set(rend, "xalign", 0.0, "xpad", 6, "ypad", 0, NULL);
4917 4820
4918 /* Setup the gtkimhtml widget */ 4821 /* Setup the gtkimhtml widget */
4919 frame = pidgin_create_imhtml(FALSE, &gtkconv->imhtml, NULL, &imhtml_sw); 4822 webview_sw = gtk_scrolled_window_new (NULL, NULL);
4920 gtk_widget_set_size_request(gtkconv->imhtml, -1, 0); 4823 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(webview_sw), GTK_SHADOW_IN);
4824 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (webview_sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
4825
4826 gtkconv->webview = gtk_webview_new ();
4827 gtk_container_add (GTK_CONTAINER (webview_sw), gtkconv->webview);
4828
4829 gtk_widget_set_size_request(gtkconv->webview, -1, 0);
4830
4921 if (chat) { 4831 if (chat) {
4922 GtkWidget *hpaned; 4832 GtkWidget *hpaned;
4923 4833
4924 /* Add the topic */ 4834 /* Add the topic */
4925 setup_chat_topic(gtkconv, vbox); 4835 setup_chat_topic(gtkconv, vbox);
4926 4836
4927 /* Add the gtkimhtml frame */ 4837 /* Add the gtkimhtml frame */
4928 hpaned = gtk_hpaned_new(); 4838 hpaned = gtk_hpaned_new();
4929 gtk_box_pack_start(GTK_BOX(vbox), hpaned, TRUE, TRUE, 0); 4839 gtk_box_pack_start(GTK_BOX(vbox), hpaned, TRUE, TRUE, 0);
4930 gtk_widget_show(hpaned); 4840 gtk_widget_show(hpaned);
4931 gtk_paned_pack1(GTK_PANED(hpaned), frame, TRUE, TRUE); 4841 gtk_paned_pack1(GTK_PANED(hpaned), webview_sw, TRUE, TRUE);
4932 4842
4933 /* Now add the userlist */ 4843 /* Now add the userlist */
4934 setup_chat_userlist(gtkconv, hpaned); 4844 setup_chat_userlist(gtkconv, hpaned);
4935 } else { 4845 } else {
4936 gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0); 4846 gtk_box_pack_start(GTK_BOX(vbox), webview_sw, TRUE, TRUE, 0);
4937 } 4847 }
4938 gtk_widget_show(frame); 4848 gtk_widget_show_all(webview_sw);
4939 4849
4940 gtk_widget_set_name(gtkconv->imhtml, "pidgin_conv_imhtml"); 4850 gtk_widget_set_name(gtkconv->webview, "pidgin_conv_webview");
4941 gtk_imhtml_show_comments(GTK_IMHTML(gtkconv->imhtml),TRUE); 4851 g_object_set_data(G_OBJECT(gtkconv->webview), "gtkconv", gtkconv);
4942 g_object_set_data(G_OBJECT(gtkconv->imhtml), "gtkconv", gtkconv); 4852
4943 4853 gtk_scrolled_window_get_policy(GTK_SCROLLED_WINDOW(webview_sw),
4944 gtk_scrolled_window_get_policy(GTK_SCROLLED_WINDOW(imhtml_sw), 4854 &webview_sw_hscroll, NULL);
4945 &imhtml_sw_hscroll, NULL); 4855 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(webview_sw),
4946 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(imhtml_sw), 4856 webview_sw_hscroll, GTK_POLICY_ALWAYS);
4947 imhtml_sw_hscroll, GTK_POLICY_ALWAYS); 4857
4948 4858 g_signal_connect_after(G_OBJECT(gtkconv->webview), "button_press_event",
4949 g_signal_connect_after(G_OBJECT(gtkconv->imhtml), "button_press_event",
4950 G_CALLBACK(entry_stop_rclick_cb), NULL); 4859 G_CALLBACK(entry_stop_rclick_cb), NULL);
4951 g_signal_connect(G_OBJECT(gtkconv->imhtml), "key_press_event", 4860 g_signal_connect(G_OBJECT(gtkconv->webview), "key_press_event",
4952 G_CALLBACK(refocus_entry_cb), gtkconv); 4861 G_CALLBACK(refocus_entry_cb), gtkconv);
4953 g_signal_connect(G_OBJECT(gtkconv->imhtml), "key_release_event", 4862 g_signal_connect(G_OBJECT(gtkconv->webview), "key_release_event",
4954 G_CALLBACK(refocus_entry_cb), gtkconv); 4863 G_CALLBACK(refocus_entry_cb), gtkconv);
4955 4864
4956 gtkconv->lower_hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE); 4865 gtkconv->lower_hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
4957 gtk_box_pack_start(GTK_BOX(vbox), gtkconv->lower_hbox, FALSE, FALSE, 0); 4866 gtk_box_pack_start(GTK_BOX(vbox), gtkconv->lower_hbox, FALSE, FALSE, 0);
4958 gtk_widget_show(gtkconv->lower_hbox); 4867 gtk_widget_show(gtkconv->lower_hbox);
5187 return FALSE; 5096 return FALSE;
5188 } 5097 }
5189 5098
5190 static void set_typing_font(GtkWidget *widget, GtkStyle *style, PidginConversation *gtkconv) 5099 static void set_typing_font(GtkWidget *widget, GtkStyle *style, PidginConversation *gtkconv)
5191 { 5100 {
5192 static PangoFontDescription *font_desc = NULL;
5193 static GdkColor *color = NULL;
5194 static gboolean enable = TRUE;
5195
5196 if (font_desc == NULL) {
5197 char *string = NULL;
5198 gtk_widget_style_get(widget,
5199 "typing-notification-font", &string,
5200 "typing-notification-color", &color,
5201 "typing-notification-enable", &enable,
5202 NULL);
5203 font_desc = pango_font_description_from_string(string);
5204 g_free(string);
5205 if (color == NULL) {
5206 GdkColor def = {0, 0x8888, 0x8888, 0x8888};
5207 color = gdk_color_copy(&def);
5208 }
5209 }
5210
5211 gtk_text_buffer_create_tag(GTK_IMHTML(widget)->text_buffer, "TYPING-NOTIFICATION",
5212 "foreground-gdk", color,
5213 "font-desc", font_desc,
5214 NULL);
5215
5216 if (!enable) {
5217 g_object_set_data(G_OBJECT(widget), "disable-typing-notification", GINT_TO_POINTER(TRUE));
5218 /* or may be 'gtkconv->disable_typing = TRUE;' instead? */
5219 }
5220
5221 g_signal_handlers_disconnect_by_func(G_OBJECT(widget), set_typing_font, gtkconv);
5222 } 5101 }
5223 5102
5224 /************************************************************************** 5103 /**************************************************************************
5225 * Conversation UI operations 5104 * Conversation UI operations
5226 **************************************************************************/ 5105 **************************************************************************/
5257 gtkconv->u.im = g_malloc0(sizeof(PidginImPane)); 5136 gtkconv->u.im = g_malloc0(sizeof(PidginImPane));
5258 } else if (conv_type == PURPLE_CONV_TYPE_CHAT) { 5137 } else if (conv_type == PURPLE_CONV_TYPE_CHAT) {
5259 gtkconv->u.chat = g_malloc0(sizeof(PidginChatPane)); 5138 gtkconv->u.chat = g_malloc0(sizeof(PidginChatPane));
5260 } 5139 }
5261 pane = setup_common_pane(gtkconv); 5140 pane = setup_common_pane(gtkconv);
5262
5263 gtk_imhtml_set_format_functions(GTK_IMHTML(gtkconv->imhtml),
5264 gtk_imhtml_get_format_functions(GTK_IMHTML(gtkconv->imhtml)) | GTK_IMHTML_IMAGE);
5265 5141
5266 if (pane == NULL) { 5142 if (pane == NULL) {
5267 if (conv_type == PURPLE_CONV_TYPE_CHAT) 5143 if (conv_type == PURPLE_CONV_TYPE_CHAT)
5268 g_free(gtkconv->u.chat); 5144 g_free(gtkconv->u.chat);
5269 else if (conv_type == PURPLE_CONV_TYPE_IM) 5145 else if (conv_type == PURPLE_CONV_TYPE_IM)
5283 gtk_drag_dest_set(pane, 5159 gtk_drag_dest_set(pane,
5284 GTK_DEST_DEFAULT_MOTION | 5160 GTK_DEST_DEFAULT_MOTION |
5285 GTK_DEST_DEFAULT_DROP, 5161 GTK_DEST_DEFAULT_DROP,
5286 te, sizeof(te) / sizeof(GtkTargetEntry), 5162 te, sizeof(te) / sizeof(GtkTargetEntry),
5287 GDK_ACTION_COPY); 5163 GDK_ACTION_COPY);
5288 gtk_drag_dest_set(gtkconv->imhtml, 0, 5164 gtk_drag_dest_set(gtkconv->webview, 0,
5289 te, sizeof(te) / sizeof(GtkTargetEntry), 5165 te, sizeof(te) / sizeof(GtkTargetEntry),
5290 GDK_ACTION_COPY); 5166 GDK_ACTION_COPY);
5291 5167
5292 gtk_drag_dest_set(gtkconv->entry, 0, 5168 gtk_drag_dest_set(gtkconv->entry, 0,
5293 te, sizeof(te) / sizeof(GtkTargetEntry), 5169 te, sizeof(te) / sizeof(GtkTargetEntry),
5295 5171
5296 g_signal_connect(G_OBJECT(pane), "button_press_event", 5172 g_signal_connect(G_OBJECT(pane), "button_press_event",
5297 G_CALLBACK(ignore_middle_click), NULL); 5173 G_CALLBACK(ignore_middle_click), NULL);
5298 g_signal_connect(G_OBJECT(pane), "drag_data_received", 5174 g_signal_connect(G_OBJECT(pane), "drag_data_received",
5299 G_CALLBACK(conv_dnd_recv), gtkconv); 5175 G_CALLBACK(conv_dnd_recv), gtkconv);
5300 g_signal_connect(G_OBJECT(gtkconv->imhtml), "drag_data_received", 5176 g_signal_connect(G_OBJECT(gtkconv->webview), "drag_data_received",
5301 G_CALLBACK(conv_dnd_recv), gtkconv); 5177 G_CALLBACK(conv_dnd_recv), gtkconv);
5302 g_signal_connect(G_OBJECT(gtkconv->entry), "drag_data_received", 5178 g_signal_connect(G_OBJECT(gtkconv->entry), "drag_data_received",
5303 G_CALLBACK(conv_dnd_recv), gtkconv); 5179 G_CALLBACK(conv_dnd_recv), gtkconv);
5304 5180
5305 g_signal_connect(gtkconv->imhtml, "style-set", G_CALLBACK(set_typing_font), gtkconv); 5181 g_signal_connect(gtkconv->webview, "style-set", G_CALLBACK(set_typing_font), gtkconv);
5306 5182
5307 /* Setup the container for the tab. */ 5183 /* Setup the container for the tab. */
5308 gtkconv->tab_cont = tab_cont = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE); 5184 gtkconv->tab_cont = tab_cont = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
5309 g_object_set_data(G_OBJECT(tab_cont), "PidginConversation", gtkconv); 5185 g_object_set_data(G_OBJECT(tab_cont), "PidginConversation", gtkconv);
5310 gtk_container_set_border_width(GTK_CONTAINER(tab_cont), PIDGIN_HIG_BOX_SPACE); 5186 gtk_container_set_border_width(GTK_CONTAINER(tab_cont), PIDGIN_HIG_BOX_SPACE);
5330 if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/im/show_buddy_icons")) 5206 if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/im/show_buddy_icons"))
5331 gtk_widget_show(gtkconv->infopane_hbox); 5207 gtk_widget_show(gtkconv->infopane_hbox);
5332 else 5208 else
5333 gtk_widget_hide(gtkconv->infopane_hbox); 5209 gtk_widget_hide(gtkconv->infopane_hbox);
5334 5210
5335 gtk_imhtml_show_comments(GTK_IMHTML(gtkconv->imhtml),
5336 purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/show_timestamps"));
5337 gtk_imhtml_set_protocol_name(GTK_IMHTML(gtkconv->imhtml),
5338 purple_account_get_protocol_name(conv->account));
5339 5211
5340 g_signal_connect_swapped(G_OBJECT(pane), "focus", 5212 g_signal_connect_swapped(G_OBJECT(pane), "focus",
5341 G_CALLBACK(gtk_widget_grab_focus), 5213 G_CALLBACK(gtk_widget_grab_focus),
5342 gtkconv->entry); 5214 gtkconv->entry);
5343 5215
5346 else 5218 else
5347 pidgin_conv_placement_place(gtkconv); 5219 pidgin_conv_placement_place(gtkconv);
5348 5220
5349 if (nick_colors == NULL) { 5221 if (nick_colors == NULL) {
5350 nbr_nick_colors = NUM_NICK_COLORS; 5222 nbr_nick_colors = NUM_NICK_COLORS;
5351 nick_colors = generate_nick_colors(&nbr_nick_colors, gtk_widget_get_style(gtkconv->imhtml)->base[GTK_STATE_NORMAL]); 5223 nick_colors = generate_nick_colors(&nbr_nick_colors, gtk_widget_get_style(gtkconv->webview)->base[GTK_STATE_NORMAL]);
5352 } 5224 }
5353 5225
5354 if (conv->features & PURPLE_CONNECTION_ALLOW_CUSTOM_SMILEY) 5226 if (conv->features & PURPLE_CONNECTION_ALLOW_CUSTOM_SMILEY)
5355 pidgin_themes_smiley_themeize_custom(gtkconv->entry); 5227 pidgin_themes_smiley_themeize_custom(gtkconv->entry);
5356 } 5228 }
5545 } 5417 }
5546 5418
5547 return FALSE; 5419 return FALSE;
5548 } 5420 }
5549 5421
5550 static GtkTextTag *get_buddy_tag(PurpleConversation *conv, const char *who, PurpleMessageFlags flag,
5551 gboolean create)
5552 {
5553 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
5554 GtkTextTag *buddytag;
5555 gchar *str;
5556 gboolean highlight = (flag & PURPLE_MESSAGE_NICK);
5557 GtkTextBuffer *buffer = GTK_IMHTML(gtkconv->imhtml)->text_buffer;
5558
5559 str = g_strdup_printf(highlight ? "HILIT %s" : "BUDDY %s", who);
5560
5561 buddytag = gtk_text_tag_table_lookup(
5562 gtk_text_buffer_get_tag_table(buffer), str);
5563
5564 if (buddytag == NULL && create) {
5565 if (highlight)
5566 buddytag = gtk_text_buffer_create_tag(buffer, str,
5567 "foreground", get_text_tag_color(gtk_text_tag_table_lookup(
5568 gtk_text_buffer_get_tag_table(buffer), "highlight-name")),
5569 "weight", PANGO_WEIGHT_BOLD,
5570 NULL);
5571 else
5572 buddytag = gtk_text_buffer_create_tag(
5573 buffer, str,
5574 "foreground-gdk", get_nick_color(gtkconv, who),
5575 "weight", purple_find_buddy(purple_conversation_get_account(conv), who) ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL,
5576 NULL);
5577
5578 g_signal_connect(G_OBJECT(buddytag), "event",
5579 G_CALLBACK(buddytag_event), conv);
5580 }
5581
5582 g_free(str);
5583
5584 return buddytag;
5585 }
5586
5587 static void pidgin_conv_calculate_newday(PidginConversation *gtkconv, time_t mtime) 5422 static void pidgin_conv_calculate_newday(PidginConversation *gtkconv, time_t mtime)
5588 { 5423 {
5589 struct tm *tm = localtime(&mtime); 5424 struct tm *tm = localtime(&mtime);
5590 5425
5591 tm->tm_hour = tm->tm_min = tm->tm_sec = 0; 5426 tm->tm_hour = tm->tm_min = tm->tm_sec = 0;
5638 PidginConversation *gtkconv; 5473 PidginConversation *gtkconv;
5639 PidginWindow *win; 5474 PidginWindow *win;
5640 PurpleConnection *gc; 5475 PurpleConnection *gc;
5641 PurpleAccount *account; 5476 PurpleAccount *account;
5642 PurplePluginProtocolInfo *prpl_info; 5477 PurplePluginProtocolInfo *prpl_info;
5643 int gtk_font_options = 0;
5644 int gtk_font_options_all = 0;
5645 int max_scrollback_lines;
5646 int line_count;
5647 char buf2[BUF_LONG]; 5478 char buf2[BUF_LONG];
5648 gboolean show_date; 5479 gboolean show_date;
5649 char *mdate; 5480 char *mdate;
5650 char *str; 5481 char *str;
5651 char *with_font_tag; 5482 char *with_font_tag;
5652 char *sml_attrib = NULL; 5483 char *sml_attrib = NULL;
5653 size_t length; 5484 size_t length;
5654 PurpleConversationType type; 5485 PurpleConversationType type;
5655 char *displaying; 5486 char *displaying;
5656 gboolean plugin_return; 5487 gboolean plugin_return;
5657 char *bracket;
5658 int tag_count = 0;
5659 gboolean is_rtl_message = FALSE; 5488 gboolean is_rtl_message = FALSE;
5660 5489
5661 g_return_if_fail(conv != NULL); 5490 g_return_if_fail(conv != NULL);
5662 gtkconv = PIDGIN_CONVERSATION(conv); 5491 gtkconv = PIDGIN_CONVERSATION(conv);
5663 g_return_if_fail(gtkconv != NULL); 5492 g_return_if_fail(gtkconv != NULL);
5711 g_free(displaying); 5540 g_free(displaying);
5712 return; 5541 return;
5713 } 5542 }
5714 length = strlen(displaying) + 1; 5543 length = strlen(displaying) + 1;
5715 5544
5716 /* Awful hack to work around GtkIMHtml's inefficient rendering of messages with lots of formatting changes.
5717 * If a message has over 100 '<' characters, strip formatting before appending it. Hopefully nobody actually
5718 * needs that much formatting, anyway.
5719 */
5720 for (bracket = strchr(displaying, '<'); bracket && *(bracket + 1); bracket = strchr(bracket + 1, '<'))
5721 tag_count++;
5722
5723 if (tag_count > 100) {
5724 char *tmp = displaying;
5725 displaying = purple_markup_strip_html(tmp);
5726 g_free(tmp);
5727 }
5728 5545
5729 win = gtkconv->win; 5546 win = gtkconv->win;
5730 prpl_info = gc ? PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl) : NULL; 5547 prpl_info = gc ? PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl) : NULL;
5731 5548
5732 line_count = gtk_text_buffer_get_line_count( 5549 /* if the buffer is not empty add a <br> */
5733 gtk_text_view_get_buffer(GTK_TEXT_VIEW( 5550 if (!gtk_webview_is_empty (GTK_WEBVIEW(gtkconv->webview)))
5734 gtkconv->imhtml))); 5551 gtk_webview_append_html (GTK_WEBVIEW(gtkconv->webview), "<br />");
5735
5736 max_scrollback_lines = purple_prefs_get_int(
5737 PIDGIN_PREFS_ROOT "/conversations/scrollback_lines");
5738 /* If we're sitting at more than 100 lines more than the
5739 max scrollback, trim down to max scrollback */
5740 if (max_scrollback_lines > 0
5741 && line_count > (max_scrollback_lines + 100)) {
5742 GtkTextBuffer *text_buffer = gtk_text_view_get_buffer(
5743 GTK_TEXT_VIEW(gtkconv->imhtml));
5744 GtkTextIter start, end;
5745
5746 gtk_text_buffer_get_start_iter(text_buffer, &start);
5747 gtk_text_buffer_get_iter_at_line(text_buffer, &end,
5748 (line_count - max_scrollback_lines));
5749 gtk_imhtml_delete(GTK_IMHTML(gtkconv->imhtml), &start, &end);
5750 }
5751
5752 if (type == PURPLE_CONV_TYPE_CHAT)
5753 {
5754 /* Create anchor for user */
5755 GtkTextIter iter;
5756 char *tmp = g_strconcat("user:", name, NULL);
5757
5758 gtk_text_buffer_get_end_iter(gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtkconv->imhtml)), &iter);
5759 gtk_text_buffer_create_mark(gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtkconv->imhtml)),
5760 tmp, &iter, TRUE);
5761 g_free(tmp);
5762 }
5763
5764 if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/use_smooth_scrolling"))
5765 gtk_font_options_all |= GTK_IMHTML_USE_SMOOTHSCROLLING;
5766
5767 if (gtk_text_buffer_get_char_count(gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtkconv->imhtml))))
5768 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), "<BR>", gtk_font_options_all | GTK_IMHTML_NO_SCROLL);
5769 5552
5770 /* First message in a conversation. */ 5553 /* First message in a conversation. */
5771 if (gtkconv->newday == 0) 5554 if (gtkconv->newday == 0)
5772 pidgin_conv_calculate_newday(gtkconv, mtime); 5555 pidgin_conv_calculate_newday(gtkconv, mtime);
5773 5556
5799 if (mtime >= gtkconv->newday) 5582 if (mtime >= gtkconv->newday)
5800 pidgin_conv_calculate_newday(gtkconv, mtime); 5583 pidgin_conv_calculate_newday(gtkconv, mtime);
5801 5584
5802 sml_attrib = g_strdup_printf("sml=\"%s\"", purple_account_get_protocol_name(account)); 5585 sml_attrib = g_strdup_printf("sml=\"%s\"", purple_account_get_protocol_name(account));
5803 5586
5804 gtk_font_options |= GTK_IMHTML_NO_COMMENTS;
5805
5806 if ((flags & PURPLE_MESSAGE_RECV) &&
5807 !purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/show_incoming_formatting"))
5808 gtk_font_options |= GTK_IMHTML_NO_COLOURS | GTK_IMHTML_NO_FONTS | GTK_IMHTML_NO_SIZES | GTK_IMHTML_NO_FORMATTING;
5809
5810 /* this is gonna crash one day, I can feel it. */
5811 if (PURPLE_PLUGIN_PROTOCOL_INFO(purple_find_prpl(purple_account_get_protocol_id(conv->account)))->options &
5812 OPT_PROTO_USE_POINTSIZE) {
5813 gtk_font_options |= GTK_IMHTML_USE_POINTSIZE;
5814 }
5815
5816 if (!(flags & PURPLE_MESSAGE_RECV) && (conv->features & PURPLE_CONNECTION_ALLOW_CUSTOM_SMILEY))
5817 {
5818 /* We want to see our own smileys. Need to revert it after send*/
5819 pidgin_themes_smiley_themeize_custom(gtkconv->imhtml);
5820 }
5821
5822 /* TODO: These colors should not be hardcoded so log.c can use them */ 5587 /* TODO: These colors should not be hardcoded so log.c can use them */
5823 if (flags & PURPLE_MESSAGE_RAW) { 5588 if (flags & PURPLE_MESSAGE_RAW) {
5824 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), message, gtk_font_options_all); 5589 gtk_webview_append_html (GTK_WEBVIEW(gtkconv->webview), message);
5825 } else if (flags & PURPLE_MESSAGE_SYSTEM) { 5590 } else if (flags & PURPLE_MESSAGE_SYSTEM) {
5826 g_snprintf(buf2, sizeof(buf2), 5591 g_snprintf(buf2, sizeof(buf2),
5827 "<FONT %s><FONT SIZE=\"2\"><!--%s --></FONT><B>%s</B></FONT>", 5592 "<font %s><font size=\"2\"><span class='timestamp'>%s</span></font><b>%s</b></font>",
5828 sml_attrib ? sml_attrib : "", mdate, displaying); 5593 sml_attrib ? sml_attrib : "", mdate, displaying);
5829 5594
5830 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf2, gtk_font_options_all); 5595 gtk_webview_append_html(GTK_WEBVIEW(gtkconv->webview), buf2);
5831 5596
5832 } else if (flags & PURPLE_MESSAGE_ERROR) { 5597 } else if (flags & PURPLE_MESSAGE_ERROR) {
5833 g_snprintf(buf2, sizeof(buf2), 5598 g_snprintf(buf2, sizeof(buf2),
5834 "<FONT COLOR=\"#ff0000\"><FONT %s><FONT SIZE=\"2\"><!--%s --></FONT><B>%s</B></FONT></FONT>", 5599 "<font color=\"#ff0000\"><font %s><font size=\"2\"><span class='timestamp'>%s</span> </font><b>%s</b></font></font>",
5835 sml_attrib ? sml_attrib : "", mdate, displaying); 5600 sml_attrib ? sml_attrib : "", mdate, displaying);
5836 5601
5837 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf2, gtk_font_options_all); 5602 gtk_webview_append_html(GTK_WEBVIEW(gtkconv->webview), buf2);
5838 5603
5839 } else if (flags & PURPLE_MESSAGE_NO_LOG) { 5604 } else if (flags & PURPLE_MESSAGE_NO_LOG) {
5840 g_snprintf(buf2, BUF_LONG, 5605 g_snprintf(buf2, BUF_LONG,
5841 "<B><FONT %s COLOR=\"#777777\">%s</FONT></B>", 5606 "<b><font %s color=\"#777777\">%s</font></b>",
5842 sml_attrib ? sml_attrib : "", displaying); 5607 sml_attrib ? sml_attrib : "", displaying);
5843 5608
5844 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf2, gtk_font_options_all); 5609 gtk_webview_append_html(GTK_WEBVIEW(gtkconv->webview), buf2);
5845 } else { 5610 } else {
5846 char *new_message = g_memdup(displaying, length); 5611 char *new_message = g_memdup(displaying, length);
5847 char *alias_escaped = (alias ? g_markup_escape_text(alias, strlen(alias)) : g_strdup("")); 5612 char *alias_escaped = (alias ? g_markup_escape_text(alias, strlen(alias)) : g_strdup(""));
5848 /* The initial offset is to deal with 5613 /* The initial offset is to deal with
5849 * escaped entities making the string longer */ 5614 * escaped entities making the string longer */
5850 int tag_start_offset = 0; 5615 int tag_start_offset = 0;
5851 int tag_end_offset = 0; 5616 int tag_end_offset = 0;
5852 const char *tagname = NULL; 5617 const char *tagname = NULL;
5853
5854 GtkTextIter start, end;
5855 GtkTextMark *mark;
5856 GtkTextTag *tag;
5857 GtkTextBuffer *buffer = GTK_IMHTML(gtkconv->imhtml)->text_buffer;
5858 5618
5859 /* Enforce direction on alias */ 5619 /* Enforce direction on alias */
5860 if (is_rtl_message) 5620 if (is_rtl_message)
5861 str_embed_direction_chars(&alias_escaped); 5621 str_embed_direction_chars(&alias_escaped);
5862 5622
5914 } 5674 }
5915 } 5675 }
5916 5676
5917 g_free(alias_escaped); 5677 g_free(alias_escaped);
5918 5678
5919 if (tagname) 5679 /* timestamp */
5920 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(buffer), tagname); 5680 {
5921 else 5681 g_snprintf (buf2, BUF_LONG, "<font size='2'>%s </font>", mdate);
5922 tag = get_buddy_tag(conv, name, flags, TRUE); 5682
5923 5683 gtk_webview_append_html (GTK_WEBVIEW(gtkconv->webview), buf2);
5924 if (GTK_IMHTML(gtkconv->imhtml)->show_comments) { 5684 }
5925 /* The color for the timestamp has to be set in the font-tags, unfortunately. 5685 g_snprintf(buf2, BUF_LONG, "<font %s>%s</font> ", sml_attrib ? sml_attrib : "", str);
5926 * Applying the nick-tag to timestamps would work, but that can make it 5686 gtk_webview_append_html(GTK_WEBVIEW(gtkconv->webview), buf2);
5927 * bold. I thought applying the "comment" tag again, which has "weight" set
5928 * to PANGO_WEIGHT_NORMAL, would remove the boldness. But it doesn't. So
5929 * this will have to do. I don't terribly like it. -- sadrul */
5930 const char *color = get_text_tag_color(tag);
5931 g_snprintf(buf2, BUF_LONG, "<FONT %s%s%s SIZE=\"2\"><!--%s --></FONT>",
5932 color ? "COLOR=\"" : "", color ? color : "", color ? "\"" : "", mdate);
5933 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf2, gtk_font_options_all | GTK_IMHTML_NO_SCROLL);
5934 }
5935
5936 gtk_text_buffer_get_end_iter(buffer, &end);
5937 mark = gtk_text_buffer_create_mark(buffer, NULL, &end, TRUE);
5938
5939 g_snprintf(buf2, BUF_LONG, "<FONT %s>%s</FONT> ", sml_attrib ? sml_attrib : "", str);
5940 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf2, gtk_font_options_all | GTK_IMHTML_NO_SCROLL);
5941
5942 gtk_text_buffer_get_end_iter(buffer, &end);
5943 gtk_text_buffer_get_iter_at_mark(buffer, &start, mark);
5944 gtk_text_buffer_apply_tag(buffer, tag, &start, &end);
5945 gtk_text_buffer_delete_mark(buffer, mark);
5946 5687
5947 g_free(str); 5688 g_free(str);
5948 5689
5949 if(gc){ 5690 if(gc){
5950 char *pre = g_strdup_printf("<font %s>", sml_attrib ? sml_attrib : ""); 5691 char *pre = g_strdup_printf("<font %s>", sml_attrib ? sml_attrib : "");
5951 char *post = "</font>"; 5692 char *post = "</font>";
5952 int pre_len = strlen(pre); 5693 with_font_tag = g_strdup_printf ("%s%s%s", pre, new_message, post);
5953 int post_len = strlen(post);
5954
5955 with_font_tag = g_malloc(length + pre_len + post_len + 1);
5956
5957 strcpy(with_font_tag, pre);
5958 memcpy(with_font_tag + pre_len, new_message, length);
5959 strcpy(with_font_tag + pre_len + length, post);
5960
5961 length += pre_len + post_len;
5962 g_free(pre); 5694 g_free(pre);
5963 } else 5695 } else
5964 with_font_tag = g_memdup(new_message, length); 5696 with_font_tag = g_memdup(new_message, length);
5965 5697
5966 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), 5698 gtk_webview_append_html(GTK_WEBVIEW(gtkconv->webview),
5967 with_font_tag, gtk_font_options | gtk_font_options_all); 5699 with_font_tag);
5968 5700
5969 g_free(with_font_tag); 5701 g_free(with_font_tag);
5970 g_free(new_message); 5702 g_free(new_message);
5971 } 5703 }
5972 5704
5989 unseen = PIDGIN_UNSEEN_TEXT; 5721 unseen = PIDGIN_UNSEEN_TEXT;
5990 5722
5991 gtkconv_set_unseen(gtkconv, unseen); 5723 gtkconv_set_unseen(gtkconv, unseen);
5992 } 5724 }
5993 5725
5994 if (!(flags & PURPLE_MESSAGE_RECV) && (conv->features & PURPLE_CONNECTION_ALLOW_CUSTOM_SMILEY))
5995 {
5996 /* Restore the smiley-data */
5997 pidgin_themes_smiley_themeize(gtkconv->imhtml);
5998 }
5999
6000 purple_signal_emit(pidgin_conversations_get_handle(), 5726 purple_signal_emit(pidgin_conversations_get_handle(),
6001 (type == PURPLE_CONV_TYPE_IM ? "displayed-im-msg" : "displayed-chat-msg"), 5727 (type == PURPLE_CONV_TYPE_IM ? "displayed-im-msg" : "displayed-chat-msg"),
6002 account, name, displaying, conv, flags); 5728 account, name, displaying, conv, flags);
6003 g_free(displaying); 5729 g_free(displaying);
6004 update_typing_message(gtkconv, NULL); 5730 update_typing_message(gtkconv, NULL);
6086 f = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter); 5812 f = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter);
6087 5813
6088 g_free(val); 5814 g_free(val);
6089 } 5815 }
6090 5816
6091 if ((tag = get_buddy_tag(conv, old_name, 0, FALSE)))
6092 g_object_set(G_OBJECT(tag), "style", PANGO_STYLE_ITALIC, NULL);
6093 if ((tag = get_buddy_tag(conv, old_name, PURPLE_MESSAGE_NICK, FALSE)))
6094 g_object_set(G_OBJECT(tag), "style", PANGO_STYLE_ITALIC, NULL);
6095 5817
6096 if (!purple_conv_chat_find_user(chat, old_name)) 5818 if (!purple_conv_chat_find_user(chat, old_name))
6097 return; 5819 return;
6098 5820
6099 g_return_if_fail(new_alias != NULL); 5821 g_return_if_fail(new_alias != NULL);
6147 f = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter); 5869 f = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter);
6148 5870
6149 g_free(val); 5871 g_free(val);
6150 } while (f); 5872 } while (f);
6151 5873
6152 if ((tag = get_buddy_tag(conv, l->data, 0, FALSE))) 5874
6153 g_object_set(G_OBJECT(tag), "style", PANGO_STYLE_ITALIC, NULL);
6154 if ((tag = get_buddy_tag(conv, l->data, PURPLE_MESSAGE_NICK, FALSE)))
6155 g_object_set(G_OBJECT(tag), "style", PANGO_STYLE_ITALIC, NULL);
6156 } 5875 }
6157 5876
6158 g_snprintf(tmp, sizeof(tmp), 5877 g_snprintf(tmp, sizeof(tmp),
6159 ngettext("%d person in room", "%d people in room", 5878 ngettext("%d person in room", "%d people in room",
6160 num_users), num_users); 5879 num_users), num_users);
6254 g_signal_connect_swapped(imhtml, "destroy", G_CALLBACK(gtk_imhtml_smiley_destroy), smiley); 5973 g_signal_connect_swapped(imhtml, "destroy", G_CALLBACK(gtk_imhtml_smiley_destroy), smiley);
6255 5974
6256 return TRUE; 5975 return TRUE;
6257 } 5976 }
6258 5977
6259 static gboolean
6260 pidgin_conv_custom_smiley_add(PurpleConversation *conv, const char *smile, gboolean remote)
6261 {
6262 PidginConversation *gtkconv;
6263 struct smiley_list *list;
6264 const char *sml = NULL, *conv_sml;
6265
6266 if (!conv || !smile || !*smile) {
6267 return FALSE;
6268 }
6269
6270 /* If smileys are off, return false */
6271 if (pidgin_themes_smileys_disabled())
6272 return FALSE;
6273
6274 /* If possible add this smiley to the current theme.
6275 * The addition is only temporary: custom smilies aren't saved to disk. */
6276 conv_sml = purple_account_get_protocol_name(conv->account);
6277 gtkconv = PIDGIN_CONVERSATION(conv);
6278
6279 for (list = (struct smiley_list *)current_smiley_theme->list; list; list = list->next) {
6280 if (!strcmp(list->sml, conv_sml)) {
6281 sml = list->sml;
6282 break;
6283 }
6284 }
6285
6286 if (!add_custom_smiley_for_imhtml(GTK_IMHTML(gtkconv->imhtml), sml, smile))
6287 return FALSE;
6288
6289 if (!remote) /* If it's a local custom smiley, then add it for the entry */
6290 if (!add_custom_smiley_for_imhtml(GTK_IMHTML(gtkconv->entry), sml, smile))
6291 return FALSE;
6292
6293 return TRUE;
6294 }
6295
6296 static void 5978 static void
6297 pidgin_conv_custom_smiley_write(PurpleConversation *conv, const char *smile, 5979 pidgin_conv_custom_smiley_write(PurpleConversation *conv, const char *smile,
6298 const guchar *data, gsize size) 5980 const guchar *data, gsize size)
6299 { 5981 {
6300 PidginConversation *gtkconv; 5982 return;
6301 GtkIMHtmlSmiley *smiley;
6302 GdkPixbufLoader *loader;
6303 const char *sml;
6304
6305 sml = purple_account_get_protocol_name(conv->account);
6306 gtkconv = PIDGIN_CONVERSATION(conv);
6307 smiley = gtk_imhtml_smiley_get(GTK_IMHTML(gtkconv->imhtml), sml, smile);
6308
6309 if (!smiley)
6310 return;
6311
6312 smiley->data = g_realloc(smiley->data, smiley->datasize + size);
6313 g_memmove((guchar *)smiley->data + smiley->datasize, data, size);
6314 smiley->datasize += size;
6315
6316 loader = smiley->loader;
6317 if (!loader)
6318 return;
6319
6320 gdk_pixbuf_loader_write(loader, data, size, NULL);
6321 } 5983 }
6322 5984
6323 static void 5985 static void
6324 pidgin_conv_custom_smiley_close(PurpleConversation *conv, const char *smile) 5986 pidgin_conv_custom_smiley_close(PurpleConversation *conv, const char *smile)
6325 { 5987 {
6326 PidginConversation *gtkconv; 5988 return;
6327 GtkIMHtmlSmiley *smiley;
6328 GdkPixbufLoader *loader;
6329 const char *sml;
6330
6331 g_return_if_fail(conv != NULL);
6332 g_return_if_fail(smile != NULL);
6333
6334 sml = purple_account_get_protocol_name(conv->account);
6335 gtkconv = PIDGIN_CONVERSATION(conv);
6336 smiley = gtk_imhtml_smiley_get(GTK_IMHTML(gtkconv->imhtml), sml, smile);
6337
6338 if (!smiley)
6339 return;
6340
6341 loader = smiley->loader;
6342
6343 if (!loader)
6344 return;
6345
6346
6347
6348 purple_debug_info("gtkconv", "About to close the smiley pixbuf\n");
6349
6350 gdk_pixbuf_loader_close(loader, NULL);
6351
6352 } 5989 }
6353 5990
6354 static void 5991 static void
6355 pidgin_conv_send_confirm(PurpleConversation *conv, const char *message) 5992 pidgin_conv_send_confirm(PurpleConversation *conv, const char *message)
6356 { 5993 {
6644 gtk_tooltips_set_tip(gtkconv->tooltips, gtkchat->topic_text, 6281 gtk_tooltips_set_tip(gtkconv->tooltips, gtkchat->topic_text,
6645 topic ? topic : "", NULL); 6282 topic ? topic : "", NULL);
6646 } 6283 }
6647 } 6284 }
6648 6285
6649 if (fields & PIDGIN_CONV_SMILEY_THEME)
6650 pidgin_themes_smiley_themeize(PIDGIN_CONVERSATION(conv)->imhtml);
6651 6286
6652 if ((fields & PIDGIN_CONV_COLORIZE_TITLE) || 6287 if ((fields & PIDGIN_CONV_COLORIZE_TITLE) ||
6653 (fields & PIDGIN_CONV_SET_TITLE) || 6288 (fields & PIDGIN_CONV_SET_TITLE) ||
6654 (fields & PIDGIN_CONV_TOPIC)) 6289 (fields & PIDGIN_CONV_TOPIC))
6655 { 6290 {
6870 pidgin_conv_chat_rename_user, /* chat_rename_user */ 6505 pidgin_conv_chat_rename_user, /* chat_rename_user */
6871 pidgin_conv_chat_remove_users, /* chat_remove_users */ 6506 pidgin_conv_chat_remove_users, /* chat_remove_users */
6872 pidgin_conv_chat_update_user, /* chat_update_user */ 6507 pidgin_conv_chat_update_user, /* chat_update_user */
6873 pidgin_conv_present_conversation, /* present */ 6508 pidgin_conv_present_conversation, /* present */
6874 pidgin_conv_has_focus, /* has_focus */ 6509 pidgin_conv_has_focus, /* has_focus */
6875 pidgin_conv_custom_smiley_add, /* custom_smiley_add */ 6510 NULL, /* custom_smiley_add */
6876 pidgin_conv_custom_smiley_write, /* custom_smiley_write */ 6511 pidgin_conv_custom_smiley_write, /* custom_smiley_write */
6877 pidgin_conv_custom_smiley_close, /* custom_smiley_close */ 6512 pidgin_conv_custom_smiley_close, /* custom_smiley_close */
6878 pidgin_conv_send_confirm, /* send_confirm */ 6513 pidgin_conv_send_confirm, /* send_confirm */
6879 NULL, 6514 NULL,
6880 NULL, 6515 NULL,
7276 6911
7277 gtk_check_menu_item_set_active( 6912 gtk_check_menu_item_set_active(
7278 GTK_CHECK_MENU_ITEM(win->menu.show_timestamps), 6913 GTK_CHECK_MENU_ITEM(win->menu.show_timestamps),
7279 (gboolean)GPOINTER_TO_INT(value)); 6914 (gboolean)GPOINTER_TO_INT(value));
7280 6915
7281 gtk_imhtml_show_comments(GTK_IMHTML(gtkconv->imhtml),
7282 (gboolean)GPOINTER_TO_INT(value));
7283 } 6916 }
7284 } 6917 }
7285 6918
7286 static void 6919 static void
7287 show_formatting_toolbar_pref_cb(const char *name, PurplePrefType type, 6920 show_formatting_toolbar_pref_cb(const char *name, PurplePrefType type,
7672 7305
7673 gtkconv->attach.timer = 0; 7306 gtkconv->attach.timer = 0;
7674 while (gtkconv->attach.current && count < 100) { /* XXX: 100 is a random value here */ 7307 while (gtkconv->attach.current && count < 100) { /* XXX: 100 is a random value here */
7675 PurpleConvMessage *msg = gtkconv->attach.current->data; 7308 PurpleConvMessage *msg = gtkconv->attach.current->data;
7676 if (!im && when && when < msg->when) { 7309 if (!im && when && when < msg->when) {
7677 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), "<BR><HR>", 0); 7310 gtk_webview_append_html(GTK_WEBVIEW(gtkconv->webview), "<BR><HR>");
7678 g_object_set_data(G_OBJECT(gtkconv->entry), "attach-start-time", NULL); 7311 g_object_set_data(G_OBJECT(gtkconv->entry), "attach-start-time", NULL);
7679 } 7312 }
7680 pidgin_conv_write_conv(msg->conv, msg->who, msg->alias, msg->what, msg->flags, msg->when); 7313 pidgin_conv_write_conv(msg->conv, msg->who, msg->alias, msg->what, msg->flags, msg->when);
7681 if (im) { 7314 if (im) {
7682 gtkconv->attach.current = g_list_delete_link(gtkconv->attach.current, gtkconv->attach.current); 7315 gtkconv->attach.current = g_list_delete_link(gtkconv->attach.current, gtkconv->attach.current);
7707 msgs = g_list_sort(msgs, message_compare); 7340 msgs = g_list_sort(msgs, message_compare);
7708 for (; msgs; msgs = g_list_delete_link(msgs, msgs)) { 7341 for (; msgs; msgs = g_list_delete_link(msgs, msgs)) {
7709 PurpleConvMessage *msg = msgs->data; 7342 PurpleConvMessage *msg = msgs->data;
7710 pidgin_conv_write_conv(msg->conv, msg->who, msg->alias, msg->what, msg->flags, msg->when); 7343 pidgin_conv_write_conv(msg->conv, msg->who, msg->alias, msg->what, msg->flags, msg->when);
7711 } 7344 }
7712 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), "<BR><HR>", 0); 7345 gtk_webview_append_html(GTK_WEBVIEW(gtkconv->webview), "<BR><HR>");
7713 g_object_set_data(G_OBJECT(gtkconv->entry), "attach-start-time", NULL); 7346 g_object_set_data(G_OBJECT(gtkconv->entry), "attach-start-time", NULL);
7714 } 7347 }
7715 7348
7716 g_object_set_data(G_OBJECT(gtkconv->entry), "attach-start-time", NULL); 7349 g_object_set_data(G_OBJECT(gtkconv->entry), "attach-start-time", NULL);
7717 purple_signal_emit(pidgin_conversations_get_handle(), 7350 purple_signal_emit(pidgin_conversations_get_handle(),

mercurial