Mercurial > pidgin.yaz
diff pidgin/gtkconv.c @ 32692:0f94ec89f0bc
merged from im.pidgin.pidgin
| author | Yoshiki Yazawa <yaz@honeyplanet.jp> |
|---|---|
| date | Mon, 26 Sep 2011 14:57:21 +0900 |
| parents | ac6353ffa129 5a379d8a72c1 |
| children | 4a34689eeb33 |
line wrap: on
line diff
--- a/pidgin/gtkconv.c Mon Aug 29 12:59:57 2011 +0900 +++ b/pidgin/gtkconv.c Mon Sep 26 14:57:21 2011 +0900 @@ -53,6 +53,8 @@ #include "notify.h" #include "prpl.h" #include "request.h" +#include "theme-loader.h" +#include "theme-manager.h" #include "util.h" #include "version.h" @@ -60,6 +62,8 @@ #include "gtkblist.h" #include "gtkconv.h" #include "gtkconvwin.h" +#include "gtkconv-theme.h" +#include "gtkconv-theme-loader.h" #include "gtkdialogs.h" #include "gtkimhtml.h" #include "gtkimhtmltoolbar.h" @@ -70,11 +74,46 @@ #include "gtkprivacy.h" #include "gtkthemes.h" #include "gtkutils.h" +#include "gtkwebview.h" #include "pidginstock.h" #include "pidgintooltip.h" +#include "smileyparser.h" #include "gtknickcolors.h" +/** + * A GTK+ Instant Message pane. + */ +struct _PidginImPane +{ + GtkWidget *block; + GtkWidget *send_file; + GtkWidget *sep1; + GtkWidget *sep2; + GtkWidget *check; + GtkWidget *progress; + guint32 typing_timer; + + /* Buddy icon stuff */ + GtkWidget *icon_container; + GtkWidget *icon; + gboolean show_icon; + gboolean animate; + GdkPixbufAnimation *anim; + GdkPixbufAnimationIter *iter; + guint32 icon_timer; +}; + +/** + * GTK+ Chat panes. + */ +struct _PidginChatPane +{ + GtkWidget *count; + GtkWidget *list; + GtkWidget *topic_text; +}; + #define CLOSE_CONV_TIMEOUT_SECS (10 * 60) #define AUTO_RESPONSE "<AUTO-REPLY> : " @@ -181,7 +220,7 @@ static const GdkColor *get_nick_color(PidginConversation *gtkconv, const char *name) { static GdkColor col; - GtkStyle *style = gtk_widget_get_style(gtkconv->imhtml); + GtkStyle *style = gtk_widget_get_style(gtkconv->webview); float scale; col = nick_colors[g_str_hash(name) % nbr_nick_colors]; @@ -445,8 +484,9 @@ PidginConversation *gtkconv = NULL; gtkconv = PIDGIN_CONVERSATION(conv); - if (gtkconv) - gtk_imhtml_clear(GTK_IMHTML(gtkconv->imhtml)); + + if (PIDGIN_CONVERSATION(conv)) + webkit_web_view_load_html_string(WEBKIT_WEB_VIEW(gtkconv->webview), "", ""); } static PurpleCmdRet @@ -1068,6 +1108,8 @@ static void savelog_writefile_cb(void *user_data, const char *filename) { + /* TODO WEBKIT: I don't know how to support this using webkit yet. */ +#if 0 PurpleConversation *conv = (PurpleConversation *)user_data; FILE *fp; const char *name; @@ -1094,6 +1136,7 @@ fprintf(fp, "\n</body>\n</html>\n"); fclose(fp); +#endif /* if 0 */ } /* @@ -1602,32 +1645,6 @@ } static void -menu_chat_get_away_cb(GtkWidget *w, PidginConversation *gtkconv) -{ - PurpleConversation *conv = gtkconv->active_conv; - PurplePluginProtocolInfo *prpl_info = NULL; - PurpleConnection *gc; - char *who; - - gc = purple_conversation_get_gc(conv); - who = g_object_get_data(G_OBJECT(w), "user_data"); - - if (gc != NULL) { - prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl); - - /* - * May want to expand this to work similarly to menu_info_cb? - */ - - if (prpl_info->get_cb_away != NULL) - { - prpl_info->get_cb_away(gc, - purple_conv_chat_get_id(PURPLE_CONV_CHAT(conv)), who); - } - } -} - -static void menu_chat_add_remove_cb(GtkWidget *w, PidginConversation *gtkconv) { PurpleConversation *conv = gtkconv->active_conv; @@ -1650,7 +1667,7 @@ static GtkTextMark * get_mark_for_user(PidginConversation *gtkconv, const char *who) { - GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtkconv->imhtml)); + GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtkconv->webview)); char *tmp = g_strconcat("user:", who, NULL); GtkTextMark *mark = gtk_text_buffer_get_mark(buf, tmp); @@ -1661,6 +1678,8 @@ static void menu_last_said_cb(GtkWidget *w, PidginConversation *gtkconv) { +/* TODO WEBKIT: This doesn't work yet, of course... */ +#if 0 GtkTextMark *mark; const char *who; @@ -1671,6 +1690,7 @@ gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(gtkconv->imhtml), mark, 0.1, FALSE, 0, 0); else g_return_if_reached(); +#endif /* if 0 */ } static GtkWidget * @@ -1758,16 +1778,6 @@ g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free); } - if (prpl_info && prpl_info->get_cb_away) { - button = pidgin_new_item_from_stock(menu, _("Get Away Message"), PIDGIN_STOCK_AWAY, - G_CALLBACK(menu_chat_get_away_cb), PIDGIN_CONVERSATION(conv), 0, 0, NULL); - - if (gc == NULL) - gtk_widget_set_sensitive(button, FALSE); - else - g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free); - } - if (!is_me && prpl_info && !(prpl_info->options & OPT_PROTO_UNIQUE_CHATNAME)) { if ((buddy = purple_find_buddy(conv->account, who)) != NULL) button = pidgin_new_item_from_stock(menu, _("Remove"), GTK_STOCK_REMOVE, @@ -1885,10 +1895,13 @@ chat_do_im(gtkconv, who); } else if (event->button == 2 && event->type == GDK_BUTTON_PRESS) { /* Move to user's anchor */ +/* TODO WEBKIT: This isn't implemented yet. */ +#if 0 GtkTextMark *mark = get_mark_for_user(gtkconv, who); if(mark != NULL) gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(gtkconv->imhtml), mark, 0.1, FALSE, 0, 0); +#endif /* if 0 */ } else if (event->button == 3 && event->type == GDK_BUTTON_PRESS) { GtkWidget *menu = create_chat_menu (conv, who, gc); gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, @@ -1965,8 +1978,8 @@ GtkWidget *from; GtkWidget *to; } transitions[] = { - {gtkconv->entry, gtkconv->imhtml}, - {gtkconv->imhtml, chat ? gtkconv->u.chat->list : gtkconv->entry}, + {gtkconv->entry, gtkconv->webview}, + {gtkconv->webview, chat ? gtkconv->u.chat->list : gtkconv->entry}, {chat ? gtkconv->u.chat->list : NULL, gtkconv->entry}, {NULL, NULL} }, *ptr; @@ -2222,14 +2235,20 @@ break; case GDK_Page_Up: - case GDK_KP_Page_Up: + case GDK_KP_Page_Up: +/* TODO WEBKIT: Write this. */ +#if 0 gtk_imhtml_page_up(GTK_IMHTML(gtkconv->imhtml)); +#endif /* if 0 */ return TRUE; break; case GDK_Page_Down: - case GDK_KP_Page_Down: + case GDK_KP_Page_Down: +/* TODO WEBKIT: Write this. */ +#if 0 gtk_imhtml_page_down(GTK_IMHTML(gtkconv->imhtml)); +#endif /* if 0 */ return TRUE; break; @@ -2339,7 +2358,7 @@ entry = GTK_IMHTML(gtkconv->entry); protocol_name = purple_account_get_protocol_name(conv->account); gtk_imhtml_set_protocol_name(entry, protocol_name); - gtk_imhtml_set_protocol_name(GTK_IMHTML(gtkconv->imhtml), protocol_name); + /* TODO WEBKIT: gtk_imhtml_set_protocol_name(GTK_IMHTML(gtkconv->imhtml), protocol_name); */ if (!(conv->features & PURPLE_CONNECTION_HTML)) gtk_imhtml_clear_formatting(GTK_IMHTML(gtkconv->entry)); @@ -3288,11 +3307,11 @@ if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) { chat = purple_blist_find_chat(conv->account, conv->name); - if ((chat == NULL) && (gtkconv->imhtml != NULL)) { - chat = g_object_get_data(G_OBJECT(gtkconv->imhtml), "transient_chat"); - } - - if ((chat == NULL) && (gtkconv->imhtml != NULL)) { + if ((chat == NULL) && (gtkconv->webview != NULL)) { + chat = g_object_get_data(G_OBJECT(gtkconv->webview), "transient_chat"); + } + + if ((chat == NULL) && (gtkconv->webview != NULL)) { GHashTable *components; PurpleAccount *account = purple_conversation_get_account(conv); PurplePlugin *prpl = purple_find_prpl(purple_account_get_protocol_id(account)); @@ -3310,7 +3329,7 @@ chat = purple_chat_new(conv->account, NULL, components); purple_blist_node_set_flags((PurpleBlistNode *)chat, PURPLE_BLIST_NODE_FLAG_NO_SAVE); - g_object_set_data_full(G_OBJECT(gtkconv->imhtml), "transient_chat", + g_object_set_data_full(G_OBJECT(gtkconv->webview), "transient_chat", chat, (GDestroyNotify)purple_blist_remove_chat); } } else { @@ -3322,15 +3341,15 @@ /* gotta remain bug-compatible :( libpurple < 2.0.2 didn't handle * removing "isolated" buddy nodes well */ if (purple_version_check(2, 0, 2) == NULL) { - if ((buddy == NULL) && (gtkconv->imhtml != NULL)) { - buddy = g_object_get_data(G_OBJECT(gtkconv->imhtml), "transient_buddy"); + if ((buddy == NULL) && (gtkconv->webview != NULL)) { + buddy = g_object_get_data(G_OBJECT(gtkconv->webview), "transient_buddy"); } - if ((buddy == NULL) && (gtkconv->imhtml != NULL)) { + if ((buddy == NULL) && (gtkconv->webview != NULL)) { buddy = purple_buddy_new(conv->account, conv->name, NULL); purple_blist_node_set_flags((PurpleBlistNode *)buddy, PURPLE_BLIST_NODE_FLAG_NO_SAVE); - g_object_set_data_full(G_OBJECT(gtkconv->imhtml), "transient_buddy", + g_object_set_data_full(G_OBJECT(gtkconv->webview), "transient_buddy", buddy, (GDestroyNotify)purple_buddy_destroy); } } @@ -3741,6 +3760,8 @@ static void update_typing_message(PidginConversation *gtkconv, const char *message) { + /* TODO WEBKIT: this is not handled at all */ +#if 0 GtkTextBuffer *buffer; GtkTextMark *stmark, *enmark; @@ -3773,6 +3794,7 @@ gtk_text_buffer_get_end_iter(buffer, &iter); gtk_text_buffer_create_mark(buffer, "typing-notification-end", &iter, TRUE); } +#endif /* if 0 */ } static void @@ -4018,7 +4040,8 @@ continue; account = purple_buddy_get_account(buddy); - if (purple_account_is_connected(account) || account == gtkconv->active_conv->account) + /* TODO WEBKIT: (I'm not actually sure if this is webkit-related --Mark Doliner) */ + if (purple_account_is_connected(account) /*|| account == gtkconv->active_conv->account*/) { /* Use the PurplePresence to get unique buddies. */ PurplePresence *presence = purple_buddy_get_presence(buddy); @@ -4130,10 +4153,13 @@ g_free(tmp); if (is_me) { +#if 0 + /* TODO WEBKIT: No tags in webkit stuff, yet. */ GtkTextTag *tag = gtk_text_tag_table_lookup( - gtk_text_buffer_get_tag_table(GTK_IMHTML(gtkconv->imhtml)->text_buffer), + gtk_text_buffer_get_tag_table(GTK_IMHTML(gtkconv->webview)->text_buffer), "send-name"); g_object_get(tag, "foreground-gdk", &color, NULL); +#endif /* if 0 */ } else { GtkTextTag *tag; if ((tag = get_buddy_tag(conv, name, 0, FALSE))) @@ -4697,7 +4723,7 @@ GdkRectangle oneline; int height, diff; int pad_top, pad_inside, pad_bottom; - int total_height = (gtkconv->imhtml->allocation.height + gtkconv->entry->allocation.height); + int total_height = (gtkconv->webview->allocation.height + gtkconv->entry->allocation.height); int max_height = total_height / 2; int min_lines = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/conversations/minimum_entry_lines"); int min_height; @@ -4919,7 +4945,7 @@ gtkchat->list = list; - gtk_box_pack_start(GTK_BOX(lbox), + gtk_box_pack_start(GTK_BOX(lbox), pidgin_make_scrollable(list, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_IN, -1, -1), TRUE, TRUE, 0); } @@ -4935,13 +4961,13 @@ if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) { node = (PurpleBlistNode*)(purple_blist_find_chat(conv->account, conv->name)); if (!node) - node = g_object_get_data(G_OBJECT(gtkconv->imhtml), "transient_chat"); + node = g_object_get_data(G_OBJECT(gtkconv->webview), "transient_chat"); } else { node = (PurpleBlistNode*)(purple_find_buddy(conv->account, conv->name)); #if 0 /* Using the transient blist nodes to show the tooltip doesn't quite work yet. */ if (!node) - node = g_object_get_data(G_OBJECT(gtkconv->imhtml), "transient_buddy"); + node = g_object_get_data(G_OBJECT(gtkconv->webview), "transient_buddy"); #endif } @@ -4956,7 +4982,7 @@ { gtk_widget_modify_base(gtkconv->quickfind.entry, GTK_STATE_NORMAL, NULL); - gtk_imhtml_search_clear(GTK_IMHTML(gtkconv->imhtml)); + webkit_web_view_unmark_text_matches(WEBKIT_WEB_VIEW(gtkconv->webview)); gtk_widget_hide_all(gtkconv->quickfind.container); gtk_widget_grab_focus(gtkconv->entry); @@ -4973,7 +4999,7 @@ GTK_ENTRY(entry)->need_im_reset = TRUE; return TRUE; } - if (gtk_imhtml_search_find(GTK_IMHTML(gtkconv->imhtml), gtk_entry_get_text(GTK_ENTRY(entry)))) { + if (webkit_web_view_search_text(WEBKIT_WEB_VIEW(gtkconv->webview), gtk_entry_get_text(GTK_ENTRY(entry)), FALSE, TRUE, TRUE)) { gtk_widget_modify_base(gtkconv->quickfind.entry, GTK_STATE_NORMAL, NULL); } else { GdkColor col; @@ -5023,16 +5049,167 @@ /* }}} */ +static char * +replace_header_tokens(PurpleConversation *conv, const char *text) +{ + GString *str; + const char *cur = text; + const char *prev = cur; + + if (text == NULL || *text == '\0') + return NULL; + + str = g_string_new(NULL); + while ((cur = strchr(cur, '%'))) { + const char *replace = NULL; + const char *fin = NULL; + + if (g_str_has_prefix(cur, "%chatName%")) { + replace = conv->name; + + } else if (g_str_has_prefix(cur, "%sourceName%")) { + replace = purple_account_get_alias(conv->account); + if (replace == NULL) + replace = purple_account_get_username(conv->account); + + } else if (g_str_has_prefix(cur, "%destinationName%")) { + PurpleBuddy *buddy = purple_find_buddy(conv->account, conv->name); + if (buddy) { + replace = purple_buddy_get_alias(buddy); + } else { + replace = conv->name; + } + + } else if (g_str_has_prefix(cur, "%incomingIconPath%")) { + PurpleBuddyIcon *icon = purple_conv_im_get_icon(PURPLE_CONV_IM(conv)); + if (icon) + replace = purple_buddy_icon_get_full_path(icon); + + } else if (g_str_has_prefix(cur, "%outgoingIconPath%")) { + replace = purple_account_get_buddy_icon_path(conv->account); + + } else if (g_str_has_prefix(cur, "%timeOpened")) { + const char *tmp = cur + strlen("%timeOpened"); + char *format = NULL; + if (*tmp == '{') { + const char *end; + tmp++; + end = strstr(tmp, "}%"); + if (!end) /* Invalid string */ + continue; + format = g_strndup(tmp, end - tmp); + fin = end + 1; + } + replace = purple_utf8_strftime(format ? format : "%X", NULL); + g_free(format); + + } else { + continue; + } + + /* Here we have a replacement to make */ + g_string_append_len(str, prev, cur - prev); + if (replace) + g_string_append(str, replace); + + /* And update the pointers */ + if (fin) { + prev = cur = fin + 1; + } else { + prev = cur = strchr(cur + 1, '%') + 1; + } + } + + /* And wrap it up */ + g_string_append(str, prev); + return g_string_free(str, FALSE); +} + +static char * +replace_template_tokens(PidginConvTheme *theme, const char *header, const char *footer) +{ + GString *str; + const char *text; + char **ms; + char *path; + + text = pidgin_conversation_theme_get_template(theme, PIDGIN_CONVERSATION_THEME_TEMPLATE_MAIN); + if (text == NULL) + return NULL; + + ms = g_strsplit(text, "%@", 6); + if (ms[0] == NULL || ms[1] == NULL || ms[2] == NULL || ms[3] == NULL || ms[4] == NULL || ms[5] == NULL) { + g_strfreev(ms); + return NULL; + } + + str = g_string_new(NULL); + + g_string_append(str, ms[0]); + g_string_append(str, "file://"); + path = pidgin_conversation_theme_get_template_path(theme); + g_string_append(str, path); + g_free(path); + + g_string_append(str, ms[1]); + + text = pidgin_conversation_theme_get_template(theme, PIDGIN_CONVERSATION_THEME_TEMPLATE_BASESTYLE_CSS); + g_string_append(str, text); + + g_string_append(str, ms[2]); + + g_string_append(str, "file://"); + path = pidgin_conversation_theme_get_css_path(theme); + g_string_append(str, path); + g_free(path); + + g_string_append(str, ms[3]); + if (header) + g_string_append(str, header); + g_string_append(str, ms[4]); + if (footer) + g_string_append(str, footer); + g_string_append(str, ms[5]); + + g_strfreev(ms); + + return g_string_free(str, FALSE); +} + +static void +set_theme_webkit_settings(WebKitWebView *webview, PidginConvTheme *theme) +{ + WebKitWebSettings *settings; + const GValue *val; + + g_object_get(G_OBJECT(webview), "settings", &settings, NULL); + + val = pidgin_conversation_theme_lookup(theme, "DefaultFontFamily", TRUE); + if (val && G_VALUE_HOLDS_STRING(val)) + g_object_set(G_OBJECT(settings), "default-font-family", g_value_get_string(val), NULL); + + val = pidgin_conversation_theme_lookup(theme, "DefaultFontSize", TRUE); + if (val && G_VALUE_HOLDS_INT(val)) + g_object_set(G_OBJECT(settings), "default-font-size", GINT_TO_POINTER(g_value_get_int(val)), NULL); + + val = pidgin_conversation_theme_lookup(theme, "DefaultBackgroundIsTransparent", TRUE); + if (val && G_VALUE_HOLDS_BOOLEAN(val)) + /* this does not work :( */ + webkit_web_view_set_transparent(webview, g_value_get_boolean(val)); +} + static GtkWidget * setup_common_pane(PidginConversation *gtkconv) { - GtkWidget *paned, *vbox, *frame, *imhtml_sw, *event_box; + GtkWidget *paned, *vbox, *frame, *imhtml_sw, *webview_sw, *event_box; GtkCellRenderer *rend; GtkTreePath *path; PurpleConversation *conv = gtkconv->active_conv; PurpleBuddy *buddy; gboolean chat = (conv->type == PURPLE_CONV_TYPE_CHAT); int buddyicon_size = 0; + char *header, *footer; + char *template; paned = gtk_vpaned_new(); gtk_widget_show(paned); @@ -5126,9 +5303,38 @@ gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(gtkconv->infopane), rend, "pixbuf", CONV_EMBLEM_COLUMN, NULL); g_object_set(rend, "xalign", 0.0, "xpad", 6, "ypad", 0, NULL); - /* Setup the gtkimhtml widget */ - frame = pidgin_create_imhtml(FALSE, >kconv->imhtml, NULL, &imhtml_sw); - gtk_widget_set_size_request(gtkconv->imhtml, -1, 0); + /* Setup the webkit widget */ + frame = pidgin_create_webview(FALSE, >kconv->webview, NULL, &webview_sw); + gtk_widget_set_size_request(gtkconv->webview, -1, 0); + + header = replace_header_tokens(conv, + pidgin_conversation_theme_get_template(gtkconv->theme, PIDGIN_CONVERSATION_THEME_TEMPLATE_HEADER)); + footer = replace_header_tokens(conv, + pidgin_conversation_theme_get_template(gtkconv->theme, PIDGIN_CONVERSATION_THEME_TEMPLATE_FOOTER)); + template = replace_template_tokens(gtkconv->theme, header, footer); + g_free(header); + g_free(footer); + + if (template != NULL) { + char *basedir; + char *baseuri; + + purple_debug_info("webkit", "template: %s\n", template); + + set_theme_webkit_settings(WEBKIT_WEB_VIEW(gtkconv->webview), gtkconv->theme); + + basedir = pidgin_conversation_theme_get_template_path(gtkconv->theme); + baseuri = g_strdup_printf("file://%s", basedir); + webkit_web_view_load_string(WEBKIT_WEB_VIEW(gtkconv->webview), template, "text/html", "UTF-8", baseuri); + + if (chat) + gtk_webview_safe_execute_script(GTK_WEBVIEW(gtkconv->webview), "document.getElementById('Chat').className = 'groupchat'"); + + g_free(basedir); + g_free(baseuri); + g_free(template); + } + if (chat) { GtkWidget *hpaned; @@ -5146,19 +5352,16 @@ } else { gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0); } - gtk_widget_show(frame); - - gtk_widget_set_name(gtkconv->imhtml, "pidgin_conv_imhtml"); - gtk_imhtml_show_comments(GTK_IMHTML(gtkconv->imhtml),TRUE); - g_object_set_data(G_OBJECT(gtkconv->imhtml), "gtkconv", gtkconv); - - g_object_set(G_OBJECT(imhtml_sw), "vscrollbar-policy", GTK_POLICY_ALWAYS, NULL); - - g_signal_connect_after(G_OBJECT(gtkconv->imhtml), "button_press_event", + gtk_widget_show_all(frame); + + gtk_widget_set_name(gtkconv->webview, "pidgin_conv_webview"); + g_object_set_data(G_OBJECT(gtkconv->webview), "gtkconv", gtkconv); + + g_signal_connect_after(G_OBJECT(gtkconv->webview), "button_press_event", G_CALLBACK(entry_stop_rclick_cb), NULL); - g_signal_connect(G_OBJECT(gtkconv->imhtml), "key_press_event", + g_signal_connect(G_OBJECT(gtkconv->webview), "key_press_event", G_CALLBACK(refocus_entry_cb), gtkconv); - g_signal_connect(G_OBJECT(gtkconv->imhtml), "key_release_event", + g_signal_connect(G_OBJECT(gtkconv->webview), "key_release_event", G_CALLBACK(refocus_entry_cb), gtkconv); /* Setup the bottom half of the conversation window */ @@ -5413,6 +5616,8 @@ static void set_typing_font(GtkWidget *widget, GtkStyle *style, PidginConversation *gtkconv) { +/* TODO WEBKIT */ +#if 0 static PangoFontDescription *font_desc = NULL; static GdkColor *color = NULL; static gboolean enable = TRUE; @@ -5443,6 +5648,7 @@ } g_signal_handlers_disconnect_by_func(G_OBJECT(widget), set_typing_font, gtkconv); +#endif /* if 0 */ } /************************************************************************** @@ -5452,6 +5658,7 @@ private_gtkconv_new(PurpleConversation *conv, gboolean hidden) { PidginConversation *gtkconv; + PurpleTheme *theme; PurpleConversationType conv_type = purple_conversation_get_type(conv); GtkWidget *pane = NULL; GtkWidget *tab_cont; @@ -5476,6 +5683,11 @@ gtkconv->tooltips = gtk_tooltips_new(); gtkconv->unseen_state = PIDGIN_UNSEEN_NONE; gtkconv->unseen_count = 0; + theme = purple_theme_manager_find_theme(purple_prefs_get_string(PIDGIN_PREFS_ROOT "/conversations/theme"), "conversation"); + if (!theme) + theme = purple_theme_manager_find_theme("Default", "conversation"); + gtkconv->theme = PIDGIN_CONV_THEME(g_object_ref(theme)); + gtkconv->last_flags = 0; if (conv_type == PURPLE_CONV_TYPE_IM) { gtkconv->u.im = g_malloc0(sizeof(PidginImPane)); @@ -5484,9 +5696,6 @@ } pane = setup_common_pane(gtkconv); - gtk_imhtml_set_format_functions(GTK_IMHTML(gtkconv->imhtml), - gtk_imhtml_get_format_functions(GTK_IMHTML(gtkconv->imhtml)) | GTK_IMHTML_IMAGE); - if (pane == NULL) { if (conv_type == PURPLE_CONV_TYPE_CHAT) g_free(gtkconv->u.chat); @@ -5509,7 +5718,7 @@ GTK_DEST_DEFAULT_DROP, te, sizeof(te) / sizeof(GtkTargetEntry), GDK_ACTION_COPY); - gtk_drag_dest_set(gtkconv->imhtml, 0, + gtk_drag_dest_set(gtkconv->webview, 0, te, sizeof(te) / sizeof(GtkTargetEntry), GDK_ACTION_COPY); @@ -5521,12 +5730,12 @@ G_CALLBACK(ignore_middle_click), NULL); g_signal_connect(G_OBJECT(pane), "drag_data_received", G_CALLBACK(conv_dnd_recv), gtkconv); - g_signal_connect(G_OBJECT(gtkconv->imhtml), "drag_data_received", + g_signal_connect(G_OBJECT(gtkconv->webview), "drag_data_received", G_CALLBACK(conv_dnd_recv), gtkconv); g_signal_connect(G_OBJECT(gtkconv->entry), "drag_data_received", G_CALLBACK(conv_dnd_recv), gtkconv); - g_signal_connect(gtkconv->imhtml, "style-set", G_CALLBACK(set_typing_font), gtkconv); + g_signal_connect(gtkconv->webview, "style-set", G_CALLBACK(set_typing_font), gtkconv); /* Setup the container for the tab. */ gtkconv->tab_cont = tab_cont = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE); @@ -5556,10 +5765,6 @@ else gtk_widget_hide(gtkconv->infopane_hbox); - gtk_imhtml_show_comments(GTK_IMHTML(gtkconv->imhtml), - purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/show_timestamps")); - gtk_imhtml_set_protocol_name(GTK_IMHTML(gtkconv->imhtml), - purple_account_get_protocol_name(conv->account)); g_signal_connect_swapped(G_OBJECT(pane), "focus", G_CALLBACK(gtk_widget_grab_focus), @@ -5572,7 +5777,7 @@ if (nick_colors == NULL) { nbr_nick_colors = NUM_NICK_COLORS; - nick_colors = generate_nick_colors(&nbr_nick_colors, gtk_widget_get_style(gtkconv->imhtml)->base[GTK_STATE_NORMAL]); + nick_colors = generate_nick_colors(&nbr_nick_colors, gtk_widget_get_style(gtkconv->webview)->base[GTK_STATE_NORMAL]); } if (conv->features & PURPLE_CONNECTION_ALLOW_CUSTOM_SMILEY) @@ -5686,6 +5891,8 @@ g_source_remove(gtkconv->attach.timer); } + g_object_unref(gtkconv->theme); + g_free(gtkconv); } @@ -5713,6 +5920,7 @@ purple_conversation_write(conv, who, message, flags, mtime); } +#if 0 static const char * get_text_tag_color(GtkTextTag *tag) { @@ -5793,10 +6001,13 @@ return FALSE; } +#endif static GtkTextTag *get_buddy_tag(PurpleConversation *conv, const char *who, PurpleMessageFlags flag, gboolean create) { +/* TODO WEBKIT */ +#if 0 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv); GtkTextTag *buddytag; gchar *str; @@ -5830,8 +6041,11 @@ g_free(str); return buddytag; -} - +#endif /* if 0 */ + return NULL; +} + +#if 0 static void pidgin_conv_calculate_newday(PidginConversation *gtkconv, time_t mtime) { struct tm *tm = localtime(&mtime); @@ -5877,6 +6091,105 @@ *str = ret; #endif } +#endif + +static char * +replace_message_tokens( + const char *text, + PurpleConversation *conv, + const char *name, + const char *alias, + const char *message, + PurpleMessageFlags flags, + time_t mtime) +{ + GString *str; + const char *cur = text; + const char *prev = cur; + + if (text == NULL) + return g_strdup(""); + + str = g_string_new(NULL); + while ((cur = strchr(cur, '%'))) { + const char *replace = NULL; + const char *fin = NULL; + + if (g_str_has_prefix(cur, "%message%")) { + replace = message; + + } else if (g_str_has_prefix(cur, "%messageClasses%")) { + replace = flags & PURPLE_MESSAGE_SEND ? "outgoing" : + flags & PURPLE_MESSAGE_RECV ? "incoming" : "event"; + + } else if (g_str_has_prefix(cur, "%time")) { + const char *tmp = cur + strlen("%time"); + char *format = NULL; + if (*tmp == '{') { + char *end; + tmp++; + end = strstr(tmp, "}%"); + if (!end) /* Invalid string */ + continue; + format = g_strndup(tmp, end - tmp); + fin = end + 1; + } + replace = purple_utf8_strftime(format ? format : "%X", NULL); + g_free(format); + + } else if (g_str_has_prefix(cur, "%userIconPath%")) { + if (flags & PURPLE_MESSAGE_SEND) { + if (purple_account_get_bool(conv->account, "use-global-buddyicon", TRUE)) { + replace = purple_prefs_get_path(PIDGIN_PREFS_ROOT "/accounts/buddyicon"); + } else { + PurpleStoredImage *img = purple_buddy_icons_find_account_icon(conv->account); + replace = purple_imgstore_get_filename(img); + } + if (replace == NULL || !g_file_test(replace, G_FILE_TEST_EXISTS)) { + replace = g_build_filename("Outgoing", "buddy_icon.png", NULL); + } + } else if (flags & PURPLE_MESSAGE_RECV) { + PurpleBuddyIcon *icon = purple_conv_im_get_icon(PURPLE_CONV_IM(conv)); + if (icon) + replace = purple_buddy_icon_get_full_path(icon); + if (replace == NULL || !g_file_test(replace, G_FILE_TEST_EXISTS)) { + replace = g_build_filename("Incoming", "buddy_icon.png", NULL); + } + } + + } else if (g_str_has_prefix(cur, "%senderScreenName%")) { + replace = name; + + } else if (g_str_has_prefix(cur, "%sender%")) { + replace = alias; + + } else if (g_str_has_prefix(cur, "%service%")) { + replace = purple_account_get_protocol_name(conv->account); + + } else { + cur++; + continue; + } + + /* Here we have a replacement to make */ + g_string_append_len(str, prev, cur - prev); + if (replace) + g_string_append(str, replace); + + /* And update the pointers */ + if (fin) { + prev = cur = fin + 1; + } else { + prev = cur = strchr(cur + 1, '%') + 1; + } + + } + + /* And wrap it up */ + g_string_append(str, prev); + + return g_string_free(str, FALSE); +} static void pidgin_conv_write_conv(PurpleConversation *conv, const char *name, const char *alias, @@ -5886,23 +6199,31 @@ PidginConversation *gtkconv; PurpleConnection *gc; PurpleAccount *account; +#if 0 int gtk_font_options = 0; int gtk_font_options_all = 0; - int max_scrollback_lines; - int line_count; char buf2[BUF_LONG]; gboolean show_date; char *mdate; char *str; char *with_font_tag; char *sml_attrib = NULL; +#endif size_t length; PurpleConversationType type; char *displaying; gboolean plugin_return; - char *bracket; - int tag_count = 0; +#if 0 gboolean is_rtl_message = FALSE; +#endif + + const char *message_html; + char *msg; + char *escape; + char *script; + char *smileyed; + PurpleMessageFlags old_flags; + const char *func = "appendMessage"; g_return_if_fail(conv != NULL); gtkconv = PIDGIN_CONVERSATION(conv); @@ -5959,56 +6280,39 @@ } length = strlen(displaying) + 1; - /* Awful hack to work around GtkIMHtml's inefficient rendering of messages with lots of formatting changes. - * If a message has over 100 '<' characters, strip formatting before appending it. Hopefully nobody actually - * needs that much formatting, anyway. - */ - for (bracket = strchr(displaying, '<'); bracket && *(bracket + 1); bracket = strchr(bracket + 1, '<')) - tag_count++; - - if (tag_count > 100) { - char *tmp = displaying; - displaying = purple_markup_strip_html(tmp); - g_free(tmp); - } - - line_count = gtk_text_buffer_get_line_count( - gtk_text_view_get_buffer(GTK_TEXT_VIEW( - gtkconv->imhtml))); - - max_scrollback_lines = purple_prefs_get_int( - PIDGIN_PREFS_ROOT "/conversations/scrollback_lines"); - /* If we're sitting at more than 100 lines more than the - max scrollback, trim down to max scrollback */ - if (max_scrollback_lines > 0 - && line_count > (max_scrollback_lines + 100)) { - GtkTextBuffer *text_buffer = gtk_text_view_get_buffer( - GTK_TEXT_VIEW(gtkconv->imhtml)); - GtkTextIter start, end; - - gtk_text_buffer_get_start_iter(text_buffer, &start); - gtk_text_buffer_get_iter_at_line(text_buffer, &end, - (line_count - max_scrollback_lines)); - gtk_imhtml_delete(GTK_IMHTML(gtkconv->imhtml), &start, &end); - } - - if (type == PURPLE_CONV_TYPE_CHAT) - { - /* Create anchor for user */ - GtkTextIter iter; - char *tmp = g_strconcat("user:", name, NULL); - - gtk_text_buffer_get_end_iter(gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtkconv->imhtml)), &iter); - gtk_text_buffer_create_mark(gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtkconv->imhtml)), - tmp, &iter, TRUE); - g_free(tmp); - } - - if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/use_smooth_scrolling")) - gtk_font_options_all |= GTK_IMHTML_USE_SMOOTHSCROLLING; - - if (gtk_text_buffer_get_char_count(gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtkconv->imhtml)))) - gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), "<BR>", gtk_font_options_all | GTK_IMHTML_NO_SCROLL); + old_flags = gtkconv->last_flags; + if ((flags & PURPLE_MESSAGE_SEND) && (old_flags & PURPLE_MESSAGE_SEND)) { + message_html = pidgin_conversation_theme_get_template(gtkconv->theme, PIDGIN_CONVERSATION_THEME_TEMPLATE_OUTGOING_NEXT_CONTENT); + func = "appendNextMessage"; + } else if (flags & PURPLE_MESSAGE_SEND) { + message_html = pidgin_conversation_theme_get_template(gtkconv->theme, PIDGIN_CONVERSATION_THEME_TEMPLATE_OUTGOING_CONTENT); + } else if ((flags & PURPLE_MESSAGE_RECV) && (old_flags & PURPLE_MESSAGE_RECV)) { + message_html = pidgin_conversation_theme_get_template(gtkconv->theme, PIDGIN_CONVERSATION_THEME_TEMPLATE_INCOMING_NEXT_CONTENT); + func = "appendNextMessage"; + } else if (flags & PURPLE_MESSAGE_RECV) { + message_html = pidgin_conversation_theme_get_template(gtkconv->theme, PIDGIN_CONVERSATION_THEME_TEMPLATE_INCOMING_CONTENT); + } else { + message_html = pidgin_conversation_theme_get_template(gtkconv->theme, PIDGIN_CONVERSATION_THEME_TEMPLATE_STATUS); + } + gtkconv->last_flags = flags; + + smileyed = smiley_parse_markup(message, purple_account_get_protocol_id(account)); + msg = replace_message_tokens(message_html, conv, name, alias, smileyed, flags, mtime); + escape = gtk_webview_quote_js_string(msg); + script = g_strdup_printf("%s(%s)", func, escape); + + purple_debug_info("webkit", "JS: %s\n", script); + gtk_webview_safe_execute_script(GTK_WEBVIEW(gtkconv->webview), script); + + g_free(script); + g_free(smileyed); + g_free(msg); + g_free(escape); + +#if 0 + /* if the buffer is not empty add a <br> */ + if (!gtk_webview_is_empty(GTK_WEBVIEW(gtkconv->webview))) + gtk_webview_append_html(GTK_WEBVIEW(gtkconv->webview), "<br />"); /* First message in a conversation. */ if (gtkconv->newday == 0) @@ -6059,32 +6363,32 @@ if (!(flags & PURPLE_MESSAGE_RECV) && (conv->features & PURPLE_CONNECTION_ALLOW_CUSTOM_SMILEY)) { /* We want to see our own smileys. Need to revert it after send*/ - pidgin_themes_smiley_themeize_custom(gtkconv->imhtml); + pidgin_themes_smiley_themeize_custom(gtkconv->webview); } /* TODO: These colors should not be hardcoded so log.c can use them */ if (flags & PURPLE_MESSAGE_RAW) { - gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), message, gtk_font_options_all); + gtk_webview_append_html(GTK_WEBVIEW(gtkconv->webview), message); } else if (flags & PURPLE_MESSAGE_SYSTEM) { g_snprintf(buf2, sizeof(buf2), - "<FONT %s><FONT SIZE=\"2\"><!--%s --></FONT><B>%s</B></FONT>", + "<font %s><font size=\"2\"><span class='timestamp'>%s</span></font><b>%s</b></font>", sml_attrib ? sml_attrib : "", mdate, displaying); - gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf2, gtk_font_options_all); + gtk_webview_append_html(GTK_WEBVIEW(gtkconv->webview), buf2); } else if (flags & PURPLE_MESSAGE_ERROR) { g_snprintf(buf2, sizeof(buf2), - "<FONT COLOR=\"#ff0000\"><FONT %s><FONT SIZE=\"2\"><!--%s --></FONT><B>%s</B></FONT></FONT>", + "<font color=\"#ff0000\"><font %s><font size=\"2\"><span class='timestamp'>%s</span> </font><b>%s</b></font></font>", sml_attrib ? sml_attrib : "", mdate, displaying); - gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf2, gtk_font_options_all); + gtk_webview_append_html(GTK_WEBVIEW(gtkconv->webview), buf2); } else if (flags & PURPLE_MESSAGE_NO_LOG) { g_snprintf(buf2, BUF_LONG, - "<B><FONT %s COLOR=\"#777777\">%s</FONT></B>", + "<b><font %s color=\"#777777\">%s</font></b>", sml_attrib ? sml_attrib : "", displaying); - gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf2, gtk_font_options_all); + gtk_webview_append_html(GTK_WEBVIEW(gtkconv->webview), buf2); } else { char *new_message = g_memdup(displaying, length); char *alias_escaped = (alias ? g_markup_escape_text(alias, strlen(alias)) : g_strdup("")); @@ -6094,11 +6398,6 @@ int tag_end_offset = 0; const char *tagname = NULL; - GtkTextIter start, end; - GtkTextMark *mark; - GtkTextTag *tag; - GtkTextBuffer *buffer = GTK_IMHTML(gtkconv->imhtml)->text_buffer; - /* Enforce direction on alias */ if (is_rtl_message) str_embed_direction_chars(&alias_escaped); @@ -6159,55 +6458,41 @@ g_free(alias_escaped); + /* TODO WEBKIT */ +#if 0 if (tagname) tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(buffer), tagname); else tag = get_buddy_tag(conv, name, flags, TRUE); if (GTK_IMHTML(gtkconv->imhtml)->show_comments) { + { /* The color for the timestamp has to be set in the font-tags, unfortunately. * Applying the nick-tag to timestamps would work, but that can make it * bold. I thought applying the "comment" tag again, which has "weight" set * to PANGO_WEIGHT_NORMAL, would remove the boldness. But it doesn't. So * this will have to do. I don't terribly like it. -- sadrul */ - const char *color = get_text_tag_color(tag); + /* const char *color = get_text_tag_color(tag); */ g_snprintf(buf2, BUF_LONG, "<FONT %s%s%s SIZE=\"2\"><!--%s --></FONT>", color ? "COLOR=\"" : "", color ? color : "", color ? "\"" : "", mdate); - gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf2, gtk_font_options_all | GTK_IMHTML_NO_SCROLL); - } - - gtk_text_buffer_get_end_iter(buffer, &end); - mark = gtk_text_buffer_create_mark(buffer, NULL, &end, TRUE); - - g_snprintf(buf2, BUF_LONG, "<FONT %s>%s</FONT> ", sml_attrib ? sml_attrib : "", str); - gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf2, gtk_font_options_all | GTK_IMHTML_NO_SCROLL); - - gtk_text_buffer_get_end_iter(buffer, &end); - gtk_text_buffer_get_iter_at_mark(buffer, &start, mark); - gtk_text_buffer_apply_tag(buffer, tag, &start, &end); - gtk_text_buffer_delete_mark(buffer, mark); + gtk_webview_append_html (GTK_WEBVIEW(gtkconv->webview), buf2); + } +#endif /* if 0 */ + g_snprintf(buf2, BUF_LONG, "<font %s>%s</font> ", sml_attrib ? sml_attrib : "", str); + gtk_webview_append_html(GTK_WEBVIEW(gtkconv->webview), buf2); g_free(str); - if(gc){ + if (gc) { char *pre = g_strdup_printf("<font %s>", sml_attrib ? sml_attrib : ""); char *post = "</font>"; - int pre_len = strlen(pre); - int post_len = strlen(post); - - with_font_tag = g_malloc(length + pre_len + post_len + 1); - - strcpy(with_font_tag, pre); - memcpy(with_font_tag + pre_len, new_message, length); - strcpy(with_font_tag + pre_len + length, post); - - length += pre_len + post_len; + with_font_tag = g_strdup_printf("%s%s%s", pre, new_message, post); g_free(pre); } else with_font_tag = g_memdup(new_message, length); - gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), - with_font_tag, gtk_font_options | gtk_font_options_all); + gtk_webview_append_html(GTK_WEBVIEW(gtkconv->webview), + with_font_tag); g_free(with_font_tag); g_free(new_message); @@ -6216,6 +6501,8 @@ g_free(mdate); g_free(sml_attrib); +#endif + /* Tab highlighting stuff */ if (!(flags & PURPLE_MESSAGE_SEND) && !pidgin_conv_has_focus(conv)) { @@ -6234,11 +6521,13 @@ gtkconv_set_unseen(gtkconv, unseen); } +#if 0 if (!(flags & PURPLE_MESSAGE_RECV) && (conv->features & PURPLE_CONNECTION_ALLOW_CUSTOM_SMILEY)) { /* Restore the smiley-data */ - pidgin_themes_smiley_themeize(gtkconv->imhtml); - } + pidgin_themes_smiley_themeize(gtkconv->webview); + } +#endif purple_signal_emit(pidgin_conversations_get_handle(), (type == PURPLE_CONV_TYPE_IM ? "displayed-im-msg" : "displayed-chat-msg"), @@ -6483,6 +6772,13 @@ } static gboolean +add_custom_smiley_for_webview(GtkWebView *webview, const char *sml, const char *smile) +{ + /* TODO WEBKIT: Smileys need to be added to webkit stuff */ + return TRUE; +} + +static gboolean pidgin_conv_custom_smiley_add(PurpleConversation *conv, const char *smile, gboolean remote) { PidginConversation *gtkconv; @@ -6509,7 +6805,7 @@ } } - if (!add_custom_smiley_for_imhtml(GTK_IMHTML(gtkconv->imhtml), sml, smile)) + if (!add_custom_smiley_for_webview(GTK_WEBVIEW(gtkconv->webview), sml, smile)) return FALSE; if (!remote) /* If it's a local custom smiley, then add it for the entry */ @@ -6523,6 +6819,8 @@ pidgin_conv_custom_smiley_write(PurpleConversation *conv, const char *smile, const guchar *data, gsize size) { +/* TODO WEBKIT */ +#if 0 PidginConversation *gtkconv; GtkIMHtmlSmiley *smiley; const char *sml; @@ -6544,7 +6842,7 @@ if (!gdk_pixbuf_loader_write(smiley->loader, data, size, &error) || error) { purple_debug_warning("gtkconv", "gdk_pixbuf_loader_write() " - "failed with size=%zu: %s\n", size, + "failed with size=%" G_GSIZE_FORMAT ": %s\n", size, error ? error->message : "(no error message)"); if (error) g_error_free(error); @@ -6557,11 +6855,14 @@ g_object_unref(G_OBJECT(smiley->loader)); smiley->loader = gdk_pixbuf_loader_new(); } +#endif /* if 0 */ } static void pidgin_conv_custom_smiley_close(PurpleConversation *conv, const char *smile) { +/* TODO WEBKIT */ +#if 0 PidginConversation *gtkconv; GtkIMHtmlSmiley *smiley; const char *sml; @@ -6598,6 +6899,7 @@ g_object_unref(G_OBJECT(smiley->loader)); smiley->loader = gdk_pixbuf_loader_new(); } +#endif /* if 0 */ } static void @@ -6750,7 +7052,7 @@ if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_IM) { - gtk_widget_set_sensitive(win->menu.add, (prpl_info->add_buddy != NULL) || (prpl_info->add_buddy_with_invite != NULL)); + gtk_widget_set_sensitive(win->menu.add, (prpl_info->add_buddy != NULL)); gtk_widget_set_sensitive(win->menu.remove, (prpl_info->remove_buddy != NULL)); gtk_widget_set_sensitive(win->menu.send_file, (prpl_info->send_file != NULL && (!prpl_info->can_receive_file || @@ -6870,8 +7172,10 @@ } } +#if 0 if (fields & PIDGIN_CONV_SMILEY_THEME) - pidgin_themes_smiley_themeize(PIDGIN_CONVERSATION(conv)->imhtml); + pidgin_themes_smiley_themeize(PIDGIN_CONVERSATION(conv)->webview); +#endif if ((fields & PIDGIN_CONV_COLORIZE_TITLE) || (fields & PIDGIN_CONV_SET_TITLE) || @@ -7489,8 +7793,11 @@ GTK_CHECK_MENU_ITEM(win->menu.show_timestamps), (gboolean)GPOINTER_TO_INT(value)); +/* TODO WEBKIT: Use WebKit version of this. */ +#if 0 gtk_imhtml_show_comments(GTK_IMHTML(gtkconv->imhtml), (gboolean)GPOINTER_TO_INT(value)); +#endif /* if 0 */ } } @@ -7891,7 +8198,7 @@ while (gtkconv->attach.current && count < 100) { /* XXX: 100 is a random value here */ PurpleConvMessage *msg = gtkconv->attach.current->data; if (!im && when && when < msg->when) { - gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), "<BR><HR>", 0); + gtk_webview_append_html(GTK_WEBVIEW(gtkconv->webview), "<BR><HR>"); g_object_set_data(G_OBJECT(gtkconv->entry), "attach-start-time", NULL); } pidgin_conv_write_conv(msg->conv, msg->who, msg->alias, msg->what, msg->flags, msg->when); @@ -7926,7 +8233,7 @@ PurpleConvMessage *msg = msgs->data; pidgin_conv_write_conv(msg->conv, msg->who, msg->alias, msg->what, msg->flags, msg->when); } - gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), "<BR><HR>", 0); + gtk_webview_append_html(GTK_WEBVIEW(gtkconv->webview), "<BR><HR>"); g_object_set_data(G_OBJECT(gtkconv->entry), "attach-start-time", NULL); } @@ -8033,6 +8340,7 @@ /* Conversations */ purple_prefs_add_none(PIDGIN_PREFS_ROOT "/conversations"); + purple_prefs_add_none(PIDGIN_PREFS_ROOT "/conversations/themes"); purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/conversations/use_smooth_scrolling", TRUE); purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/conversations/close_on_tabs", TRUE); purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/conversations/trim_vertical_tabs", FALSE); @@ -8319,6 +8627,8 @@ purple_signal_connect(purple_conversations_get_handle(), "wrote-chat-msg", handle, PURPLE_CALLBACK(wrote_msg_update_unseen_cb), NULL); + purple_theme_manager_register_type(g_object_new(PIDGIN_TYPE_CONV_THEME_LOADER, "type", "conversation", NULL)); + { /* Set default tab colors */ GString *str = g_string_new(NULL);
