Mercurial > pidgin
comparison pidgin/gtkconv.c @ 32117:585d6f844f79
propagate from branch 'im.pidgin.pidgin' (head 37329f033a30f4f4f5048f9fdc86df4400e3ada5)
to branch 'im.pidgin.soc.2009.webkitmessageview' (head 7be18cb8139c12d8080e3e0603264c2a623a15d3)
author | Paul Aurich <paul@darkrain42.org> |
---|---|
date | Mon, 09 Nov 2009 01:42:24 +0000 |
parents | e7bb163434c7 7c346c5a05d4 |
children | 041d5144730f |
comparison
equal
deleted
inserted
replaced
28528:231af7ce1b49 | 32117:585d6f844f79 |
---|---|
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))); |
371 PidginConversation *gtkconv = NULL; | 371 PidginConversation *gtkconv = NULL; |
372 GList *iter; | 372 GList *iter; |
373 | 373 |
374 gtkconv = PIDGIN_CONVERSATION(conv); | 374 gtkconv = PIDGIN_CONVERSATION(conv); |
375 | 375 |
376 gtk_imhtml_clear(GTK_IMHTML(gtkconv->imhtml)); | 376 webkit_web_view_load_html_string (WEBKIT_WEB_VIEW (gtkconv->webview), "", ""); |
377 for (iter = gtkconv->convs; iter; iter = iter->next) | 377 for (iter = gtkconv->convs; iter; iter = iter->next) |
378 purple_conversation_clear_message_history(iter->data); | 378 purple_conversation_clear_message_history(iter->data); |
379 } | 379 } |
380 | 380 |
381 static PurpleCmdRet | 381 static PurpleCmdRet |
985 } | 985 } |
986 | 986 |
987 static void | 987 static void |
988 savelog_writefile_cb(void *user_data, const char *filename) | 988 savelog_writefile_cb(void *user_data, const char *filename) |
989 { | 989 { |
990 PurpleConversation *conv = (PurpleConversation *)user_data; | 990 /* TODO: I don't know how to support this using webkit yet. */ |
991 FILE *fp; | |
992 const char *name; | |
993 char **lines; | |
994 gchar *text; | |
995 | |
996 if ((fp = g_fopen(filename, "w+")) == NULL) { | |
997 purple_notify_error(PIDGIN_CONVERSATION(conv), NULL, _("Unable to open file."), NULL); | |
998 return; | |
999 } | |
1000 | |
1001 name = purple_conversation_get_name(conv); | |
1002 fprintf(fp, "<html>\n<head>\n"); | |
1003 fprintf(fp, "<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n"); | |
1004 fprintf(fp, "<title>%s</title>\n</head>\n<body>\n", name); | |
1005 fprintf(fp, _("<h1>Conversation with %s</h1>\n"), name); | |
1006 | |
1007 lines = gtk_imhtml_get_markup_lines( | |
1008 GTK_IMHTML(PIDGIN_CONVERSATION(conv)->imhtml)); | |
1009 text = g_strjoinv("<br>\n", lines); | |
1010 fprintf(fp, "%s", text); | |
1011 g_free(text); | |
1012 g_strfreev(lines); | |
1013 | |
1014 fprintf(fp, "\n</body>\n</html>\n"); | |
1015 fclose(fp); | |
1016 } | 991 } |
1017 | 992 |
1018 /* | 993 /* |
1019 * It would be kinda cool if this gave the option of saving a | 994 * It would be kinda cool if this gave the option of saving a |
1020 * plaintext v. HTML file. | 995 * plaintext v. HTML file. |
1140 { | 1115 { |
1141 PidginConversation *gtkconv = iter->data; | 1116 PidginConversation *gtkconv = iter->data; |
1142 | 1117 |
1143 if (gtkconv != gtk_active_conv) | 1118 if (gtkconv != gtk_active_conv) |
1144 { | 1119 { |
1145 gtk_imhtml_search_clear(GTK_IMHTML(gtkconv->imhtml)); | 1120 webkit_web_view_unmark_text_matches (WEBKIT_WEB_VIEW (gtkconv->webview)); |
1146 } | 1121 } |
1147 else | 1122 else |
1148 { | 1123 { |
1149 gtk_imhtml_search_find(GTK_IMHTML(gtk_active_conv->imhtml), | 1124 webkit_web_view_mark_text_matches (WEBKIT_WEB_VIEW (gtkconv->webview), |
1150 gtk_entry_get_text(GTK_ENTRY(s->entry))); | 1125 gtk_entry_get_text (GTK_ENTRY(s->entry)), TRUE, 0); |
1126 webkit_web_view_set_highlight_text_matches (WEBKIT_WEB_VIEW (gtkconv->webview), | |
1127 true); | |
1128 webkit_web_view_search_text (WEBKIT_WEB_VIEW (gtkconv->webview), | |
1129 gtk_entry_get_text (GTK_ENTRY(s->entry)), FALSE, TRUE, FALSE); | |
1151 } | 1130 } |
1152 } | 1131 } |
1153 break; | 1132 break; |
1154 | 1133 |
1155 case GTK_RESPONSE_DELETE_EVENT: | 1134 case GTK_RESPONSE_DELETE_EVENT: |
1156 case GTK_RESPONSE_CLOSE: | 1135 case GTK_RESPONSE_CLOSE: |
1157 /* clear the keyword highlighting in all the conversation windows */ | 1136 /* clear the keyword highlighting in all the conversation windows */ |
1158 for (iter = pidgin_conv_window_get_gtkconvs(s->gtkwin); iter; iter=iter->next) | 1137 for (iter = pidgin_conv_window_get_gtkconvs(s->gtkwin); iter; iter=iter->next) |
1159 { | 1138 { |
1160 PidginConversation *gconv = iter->data; | 1139 PidginConversation *gconv = iter->data; |
1161 gtk_imhtml_search_clear(GTK_IMHTML(gconv->imhtml)); | 1140 webkit_web_view_unmark_text_matches (WEBKIT_WEB_VIEW(gconv->webview)); |
1162 } | 1141 } |
1163 | 1142 |
1164 gtk_widget_destroy(s->gtkwin->dialogs.search); | 1143 gtk_widget_destroy(s->gtkwin->dialogs.search); |
1165 s->gtkwin->dialogs.search = NULL; | 1144 s->gtkwin->dialogs.search = NULL; |
1166 g_free(s); | 1145 g_free(s); |
1659 purple_blist_request_add_buddy(account, name, NULL, NULL); | 1638 purple_blist_request_add_buddy(account, name, NULL, NULL); |
1660 | 1639 |
1661 gtk_widget_grab_focus(PIDGIN_CONVERSATION(conv)->entry); | 1640 gtk_widget_grab_focus(PIDGIN_CONVERSATION(conv)->entry); |
1662 } | 1641 } |
1663 | 1642 |
1664 static GtkTextMark * | |
1665 get_mark_for_user(PidginConversation *gtkconv, const char *who) | |
1666 { | |
1667 GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtkconv->imhtml)); | |
1668 char *tmp = g_strconcat("user:", who, NULL); | |
1669 GtkTextMark *mark = gtk_text_buffer_get_mark(buf, tmp); | |
1670 | |
1671 g_free(tmp); | |
1672 return mark; | |
1673 } | |
1674 | |
1675 static void | 1643 static void |
1676 menu_last_said_cb(GtkWidget *w, PidginConversation *gtkconv) | 1644 menu_last_said_cb(GtkWidget *w, PidginConversation *gtkconv) |
1677 { | 1645 { |
1678 GtkTextMark *mark; | 1646 /* I don't know what this is! */ |
1679 const char *who; | 1647 return; |
1680 | |
1681 who = g_object_get_data(G_OBJECT(w), "user_data"); | |
1682 mark = get_mark_for_user(gtkconv, who); | |
1683 | |
1684 if (mark != NULL) | |
1685 gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(gtkconv->imhtml), mark, 0.1, FALSE, 0, 0); | |
1686 else | |
1687 g_return_if_reached(); | |
1688 } | 1648 } |
1689 | 1649 |
1690 static GtkWidget * | 1650 static GtkWidget * |
1691 create_chat_menu(PurpleConversation *conv, const char *who, PurpleConnection *gc) | 1651 create_chat_menu(PurpleConversation *conv, const char *who, PurpleConnection *gc) |
1692 { | 1652 { |
1797 } | 1757 } |
1798 | 1758 |
1799 button = pidgin_new_item_from_stock(menu, _("Last Said"), GTK_STOCK_INDEX, | 1759 button = pidgin_new_item_from_stock(menu, _("Last Said"), GTK_STOCK_INDEX, |
1800 G_CALLBACK(menu_last_said_cb), PIDGIN_CONVERSATION(conv), 0, 0, NULL); | 1760 G_CALLBACK(menu_last_said_cb), PIDGIN_CONVERSATION(conv), 0, 0, NULL); |
1801 g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free); | 1761 g_object_set_data_full(G_OBJECT(button), "user_data", g_strdup(who), g_free); |
1802 if (!get_mark_for_user(PIDGIN_CONVERSATION(conv), who)) | |
1803 gtk_widget_set_sensitive(button, FALSE); | |
1804 | 1762 |
1805 if (buddy != NULL) | 1763 if (buddy != NULL) |
1806 { | 1764 { |
1807 if (purple_account_is_connected(conv->account)) | 1765 if (purple_account_is_connected(conv->account)) |
1808 pidgin_append_blist_node_proto_menu(menu, conv->account->gc, | 1766 pidgin_append_blist_node_proto_menu(menu, conv->account->gc, |
1888 | 1846 |
1889 if (event->button == 1 && event->type == GDK_2BUTTON_PRESS) { | 1847 if (event->button == 1 && event->type == GDK_2BUTTON_PRESS) { |
1890 chat_do_im(gtkconv, who); | 1848 chat_do_im(gtkconv, who); |
1891 } else if (event->button == 2 && event->type == GDK_BUTTON_PRESS) { | 1849 } else if (event->button == 2 && event->type == GDK_BUTTON_PRESS) { |
1892 /* Move to user's anchor */ | 1850 /* Move to user's anchor */ |
1893 GtkTextMark *mark = get_mark_for_user(gtkconv, who); | 1851 //GtkTextMark *mark = get_mark_for_user(gtkconv, who); |
1894 | 1852 |
1895 if(mark != NULL) | 1853 //if(mark != NULL) |
1896 gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(gtkconv->imhtml), mark, 0.1, FALSE, 0, 0); | 1854 // gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(gtkconv->imhtml), mark, 0.1, FALSE, 0, 0); |
1897 } else if (event->button == 3 && event->type == GDK_BUTTON_PRESS) { | 1855 } else if (event->button == 3 && event->type == GDK_BUTTON_PRESS) { |
1898 GtkWidget *menu = create_chat_menu (conv, who, gc); | 1856 GtkWidget *menu = create_chat_menu (conv, who, gc); |
1899 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, | 1857 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, |
1900 event->button, event->time); | 1858 event->button, event->time); |
1901 } | 1859 } |
1967 GtkWidget *next = NULL; | 1925 GtkWidget *next = NULL; |
1968 struct { | 1926 struct { |
1969 GtkWidget *from; | 1927 GtkWidget *from; |
1970 GtkWidget *to; | 1928 GtkWidget *to; |
1971 } transitions[] = { | 1929 } transitions[] = { |
1972 {gtkconv->entry, gtkconv->imhtml}, | 1930 {gtkconv->entry, gtkconv->webview}, |
1973 {gtkconv->imhtml, chat ? gtkconv->u.chat->list : gtkconv->entry}, | 1931 {gtkconv->webview, chat ? gtkconv->u.chat->list : gtkconv->entry}, |
1974 {chat ? gtkconv->u.chat->list : NULL, gtkconv->entry}, | 1932 {chat ? gtkconv->u.chat->list : NULL, gtkconv->entry}, |
1975 {NULL, NULL} | 1933 {NULL, NULL} |
1976 }, *ptr; | 1934 }, *ptr; |
1977 | 1935 |
1978 for (ptr = transitions; !next && ptr->from; ptr++) { | 1936 for (ptr = transitions; !next && ptr->from; ptr++) { |
2224 break; | 2182 break; |
2225 return tab_complete(conv); | 2183 return tab_complete(conv); |
2226 break; | 2184 break; |
2227 | 2185 |
2228 case GDK_Page_Up: | 2186 case GDK_Page_Up: |
2229 gtk_imhtml_page_up(GTK_IMHTML(gtkconv->imhtml)); | 2187 //gtk_imhtml_page_up(GTK_IMHTML(gtkconv->imhtml)); |
2230 return TRUE; | 2188 return TRUE; |
2231 break; | 2189 break; |
2232 | 2190 |
2233 case GDK_Page_Down: | 2191 case GDK_Page_Down: |
2234 gtk_imhtml_page_down(GTK_IMHTML(gtkconv->imhtml)); | 2192 //gtk_imhtml_page_down(GTK_IMHTML(gtkconv->imhtml)); |
2235 return TRUE; | 2193 return TRUE; |
2236 break; | 2194 break; |
2237 | 2195 |
2238 } | 2196 } |
2239 } | 2197 } |
2332 gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(gtkconv->win->menu.logging))); | 2290 gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(gtkconv->win->menu.logging))); |
2333 | 2291 |
2334 entry = GTK_IMHTML(gtkconv->entry); | 2292 entry = GTK_IMHTML(gtkconv->entry); |
2335 protocol_name = purple_account_get_protocol_name(conv->account); | 2293 protocol_name = purple_account_get_protocol_name(conv->account); |
2336 gtk_imhtml_set_protocol_name(entry, protocol_name); | 2294 gtk_imhtml_set_protocol_name(entry, protocol_name); |
2337 gtk_imhtml_set_protocol_name(GTK_IMHTML(gtkconv->imhtml), protocol_name); | 2295 //gtk_imhtml_set_protocol_name(GTK_IMHTML(gtkconv->imhtml), protocol_name); |
2338 | 2296 |
2339 if (!(conv->features & PURPLE_CONNECTION_HTML)) | 2297 if (!(conv->features & PURPLE_CONNECTION_HTML)) |
2340 gtk_imhtml_clear_formatting(GTK_IMHTML(gtkconv->entry)); | 2298 gtk_imhtml_clear_formatting(GTK_IMHTML(gtkconv->entry)); |
2341 else if (conv->features & PURPLE_CONNECTION_FORMATTING_WBFO && | 2299 else if (conv->features & PURPLE_CONNECTION_FORMATTING_WBFO && |
2342 !(old_conv->features & PURPLE_CONNECTION_FORMATTING_WBFO)) | 2300 !(old_conv->features & PURPLE_CONNECTION_FORMATTING_WBFO)) |
3276 conv = gtkconv->active_conv; | 3234 conv = gtkconv->active_conv; |
3277 | 3235 |
3278 if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) { | 3236 if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) { |
3279 chat = purple_blist_find_chat(conv->account, conv->name); | 3237 chat = purple_blist_find_chat(conv->account, conv->name); |
3280 | 3238 |
3281 if ((chat == NULL) && (gtkconv->imhtml != NULL)) { | 3239 if ((chat == NULL) && (gtkconv->webview != NULL)) { |
3282 chat = g_object_get_data(G_OBJECT(gtkconv->imhtml), "transient_chat"); | 3240 chat = g_object_get_data(G_OBJECT(gtkconv->webview), "transient_chat"); |
3283 } | 3241 } |
3284 | 3242 |
3285 if ((chat == NULL) && (gtkconv->imhtml != NULL)) { | 3243 if ((chat == NULL) && (gtkconv->webview != NULL)) { |
3286 GHashTable *components; | 3244 GHashTable *components; |
3287 PurpleAccount *account = purple_conversation_get_account(conv); | 3245 PurpleAccount *account = purple_conversation_get_account(conv); |
3288 PurplePlugin *prpl = purple_find_prpl(purple_account_get_protocol_id(account)); | 3246 PurplePlugin *prpl = purple_find_prpl(purple_account_get_protocol_id(account)); |
3289 PurplePluginProtocolInfo *prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl); | 3247 PurplePluginProtocolInfo *prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl); |
3290 if (purple_account_get_connection(account) != NULL && | 3248 if (purple_account_get_connection(account) != NULL && |
3298 g_strdup(purple_conversation_get_name(conv))); | 3256 g_strdup(purple_conversation_get_name(conv))); |
3299 } | 3257 } |
3300 chat = purple_chat_new(conv->account, NULL, components); | 3258 chat = purple_chat_new(conv->account, NULL, components); |
3301 purple_blist_node_set_flags((PurpleBlistNode *)chat, | 3259 purple_blist_node_set_flags((PurpleBlistNode *)chat, |
3302 PURPLE_BLIST_NODE_FLAG_NO_SAVE); | 3260 PURPLE_BLIST_NODE_FLAG_NO_SAVE); |
3303 g_object_set_data_full(G_OBJECT(gtkconv->imhtml), "transient_chat", | 3261 g_object_set_data_full(G_OBJECT(gtkconv->webview), "transient_chat", |
3304 chat, (GDestroyNotify)purple_blist_remove_chat); | 3262 chat, (GDestroyNotify)purple_blist_remove_chat); |
3305 } | 3263 } |
3306 } else { | 3264 } else { |
3307 if (!purple_account_is_connected(conv->account)) | 3265 if (!purple_account_is_connected(conv->account)) |
3308 return FALSE; | 3266 return FALSE; |
3310 buddy = purple_find_buddy(conv->account, conv->name); | 3268 buddy = purple_find_buddy(conv->account, conv->name); |
3311 | 3269 |
3312 /* gotta remain bug-compatible :( libpurple < 2.0.2 didn't handle | 3270 /* gotta remain bug-compatible :( libpurple < 2.0.2 didn't handle |
3313 * removing "isolated" buddy nodes well */ | 3271 * removing "isolated" buddy nodes well */ |
3314 if (purple_version_check(2, 0, 2) == NULL) { | 3272 if (purple_version_check(2, 0, 2) == NULL) { |
3315 if ((buddy == NULL) && (gtkconv->imhtml != NULL)) { | 3273 if ((buddy == NULL) && (gtkconv->webview != NULL)) { |
3316 buddy = g_object_get_data(G_OBJECT(gtkconv->imhtml), "transient_buddy"); | 3274 buddy = g_object_get_data(G_OBJECT(gtkconv->webview), "transient_buddy"); |
3317 } | 3275 } |
3318 | 3276 |
3319 if ((buddy == NULL) && (gtkconv->imhtml != NULL)) { | 3277 if ((buddy == NULL) && (gtkconv->webview != NULL)) { |
3320 buddy = purple_buddy_new(conv->account, conv->name, NULL); | 3278 buddy = purple_buddy_new(conv->account, conv->name, NULL); |
3321 purple_blist_node_set_flags((PurpleBlistNode *)buddy, | 3279 purple_blist_node_set_flags((PurpleBlistNode *)buddy, |
3322 PURPLE_BLIST_NODE_FLAG_NO_SAVE); | 3280 PURPLE_BLIST_NODE_FLAG_NO_SAVE); |
3323 g_object_set_data_full(G_OBJECT(gtkconv->imhtml), "transient_buddy", | 3281 g_object_set_data_full(G_OBJECT(gtkconv->webview), "transient_buddy", |
3324 buddy, (GDestroyNotify)purple_buddy_destroy); | 3282 buddy, (GDestroyNotify)purple_buddy_destroy); |
3325 } | 3283 } |
3326 } | 3284 } |
3327 } | 3285 } |
3328 | 3286 |
3726 #endif | 3684 #endif |
3727 | 3685 |
3728 static void | 3686 static void |
3729 update_typing_message(PidginConversation *gtkconv, const char *message) | 3687 update_typing_message(PidginConversation *gtkconv, const char *message) |
3730 { | 3688 { |
3731 GtkTextBuffer *buffer; | 3689 /* this is not handled at all */ |
3732 GtkTextMark *stmark, *enmark; | |
3733 | |
3734 if (g_object_get_data(G_OBJECT(gtkconv->imhtml), "disable-typing-notification")) | |
3735 return; | |
3736 | |
3737 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtkconv->imhtml)); | |
3738 stmark = gtk_text_buffer_get_mark(buffer, "typing-notification-start"); | |
3739 enmark = gtk_text_buffer_get_mark(buffer, "typing-notification-end"); | |
3740 if (stmark && enmark) { | |
3741 GtkTextIter start, end; | |
3742 gtk_text_buffer_get_iter_at_mark(buffer, &start, stmark); | |
3743 gtk_text_buffer_get_iter_at_mark(buffer, &end, enmark); | |
3744 gtk_text_buffer_delete_mark(buffer, stmark); | |
3745 gtk_text_buffer_delete_mark(buffer, enmark); | |
3746 gtk_text_buffer_delete(buffer, &start, &end); | |
3747 } else if (message && *message == '\n' && message[1] == ' ' && message[2] == '\0') | |
3748 message = NULL; | |
3749 | |
3750 #ifdef RESERVE_LINE | |
3751 if (!message) | |
3752 message = "\n "; /* The blank space is required to avoid a GTK+/Pango bug */ | |
3753 #endif | |
3754 | |
3755 if (message) { | |
3756 GtkTextIter iter; | |
3757 gtk_text_buffer_get_end_iter(buffer, &iter); | |
3758 gtk_text_buffer_create_mark(buffer, "typing-notification-start", &iter, TRUE); | |
3759 gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, message, -1, "TYPING-NOTIFICATION", NULL); | |
3760 gtk_text_buffer_get_end_iter(buffer, &iter); | |
3761 gtk_text_buffer_create_mark(buffer, "typing-notification-end", &iter, TRUE); | |
3762 } | |
3763 } | 3690 } |
3764 | 3691 |
3765 static void | 3692 static void |
3766 update_typing_icon(PidginConversation *gtkconv) | 3693 update_typing_icon(PidginConversation *gtkconv) |
3767 { | 3694 { |
4074 GtkTreeIter iter; | 4001 GtkTreeIter iter; |
4075 gboolean is_me = FALSE; | 4002 gboolean is_me = FALSE; |
4076 gboolean is_buddy; | 4003 gboolean is_buddy; |
4077 gchar *tmp, *alias_key, *name, *alias; | 4004 gchar *tmp, *alias_key, *name, *alias; |
4078 int flags; | 4005 int flags; |
4079 GdkColor *color = NULL; | |
4080 | 4006 |
4081 alias = cb->alias; | 4007 alias = cb->alias; |
4082 name = cb->name; | 4008 name = cb->name; |
4083 flags = GPOINTER_TO_INT(cb->flags); | 4009 flags = GPOINTER_TO_INT(cb->flags); |
4084 | 4010 |
4100 is_buddy = cb->buddy; | 4026 is_buddy = cb->buddy; |
4101 | 4027 |
4102 tmp = g_utf8_casefold(alias, -1); | 4028 tmp = g_utf8_casefold(alias, -1); |
4103 alias_key = g_utf8_collate_key(tmp, -1); | 4029 alias_key = g_utf8_collate_key(tmp, -1); |
4104 g_free(tmp); | 4030 g_free(tmp); |
4105 | |
4106 if (is_me) { | |
4107 GtkTextTag *tag = gtk_text_tag_table_lookup( | |
4108 gtk_text_buffer_get_tag_table(GTK_IMHTML(gtkconv->imhtml)->text_buffer), | |
4109 "send-name"); | |
4110 g_object_get(tag, "foreground-gdk", &color, NULL); | |
4111 } else { | |
4112 GtkTextTag *tag; | |
4113 if ((tag = get_buddy_tag(conv, name, 0, FALSE))) | |
4114 g_object_set(G_OBJECT(tag), "style", PANGO_STYLE_NORMAL, NULL); | |
4115 if ((tag = get_buddy_tag(conv, name, PURPLE_MESSAGE_NICK, FALSE))) | |
4116 g_object_set(G_OBJECT(tag), "style", PANGO_STYLE_NORMAL, NULL); | |
4117 color = (GdkColor*)get_nick_color(gtkconv, name); | |
4118 } | |
4119 | 4031 |
4120 #if GTK_CHECK_VERSION(2,6,0) | 4032 #if GTK_CHECK_VERSION(2,6,0) |
4121 gtk_list_store_insert_with_values(ls, &iter, | 4033 gtk_list_store_insert_with_values(ls, &iter, |
4122 /* | 4034 /* |
4123 * The GTK docs are mute about the effects of the "row" value for performance. | 4035 * The GTK docs are mute about the effects of the "row" value for performance. |
4130 CHAT_USERS_ICON_STOCK_COLUMN, stock, | 4042 CHAT_USERS_ICON_STOCK_COLUMN, stock, |
4131 CHAT_USERS_ALIAS_COLUMN, alias, | 4043 CHAT_USERS_ALIAS_COLUMN, alias, |
4132 CHAT_USERS_ALIAS_KEY_COLUMN, alias_key, | 4044 CHAT_USERS_ALIAS_KEY_COLUMN, alias_key, |
4133 CHAT_USERS_NAME_COLUMN, name, | 4045 CHAT_USERS_NAME_COLUMN, name, |
4134 CHAT_USERS_FLAGS_COLUMN, flags, | 4046 CHAT_USERS_FLAGS_COLUMN, flags, |
4135 CHAT_USERS_COLOR_COLUMN, color, | |
4136 CHAT_USERS_WEIGHT_COLUMN, is_buddy ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL, | 4047 CHAT_USERS_WEIGHT_COLUMN, is_buddy ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL, |
4137 -1); | 4048 -1); |
4138 #else | 4049 #else |
4139 gtk_list_store_append(ls, &iter); | 4050 gtk_list_store_append(ls, &iter); |
4140 gtk_list_store_set(ls, &iter, | 4051 gtk_list_store_set(ls, &iter, |
4141 CHAT_USERS_ICON_STOCK_COLUMN, stock, | 4052 CHAT_USERS_ICON_STOCK_COLUMN, stock, |
4142 CHAT_USERS_ALIAS_COLUMN, alias, | 4053 CHAT_USERS_ALIAS_COLUMN, alias, |
4143 CHAT_USERS_ALIAS_KEY_COLUMN, alias_key, | 4054 CHAT_USERS_ALIAS_KEY_COLUMN, alias_key, |
4144 CHAT_USERS_NAME_COLUMN, name, | 4055 CHAT_USERS_NAME_COLUMN, name, |
4145 CHAT_USERS_FLAGS_COLUMN, flags, | 4056 CHAT_USERS_FLAGS_COLUMN, flags, |
4146 CHAT_USERS_COLOR_COLUMN, color, | |
4147 CHAT_USERS_WEIGHT_COLUMN, is_buddy ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL, | 4057 CHAT_USERS_WEIGHT_COLUMN, is_buddy ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL, |
4148 -1); | 4058 -1); |
4149 #endif | 4059 #endif |
4150 | 4060 |
4151 if (is_me && color) | |
4152 gdk_color_free(color); | |
4153 g_free(alias_key); | 4061 g_free(alias_key); |
4154 } | 4062 } |
4155 | 4063 |
4156 static void | 4064 static void |
4157 tab_complete_process_item(int *most_matched, char *entered, gsize entered_bytes, char **partial, char *nick_partial, | 4065 tab_complete_process_item(int *most_matched, char *entered, gsize entered_bytes, char **partial, char *nick_partial, |
4545 buddy_cb_common(PurpleBuddy *buddy, PurpleConversation *conv, gboolean is_buddy) | 4453 buddy_cb_common(PurpleBuddy *buddy, PurpleConversation *conv, gboolean is_buddy) |
4546 { | 4454 { |
4547 GtkTreeModel *model; | 4455 GtkTreeModel *model; |
4548 char *normalized_name; | 4456 char *normalized_name; |
4549 GtkTreeIter iter; | 4457 GtkTreeIter iter; |
4550 GtkTextTag *texttag; | |
4551 int f; | 4458 int f; |
4552 | 4459 |
4553 g_return_if_fail(buddy != NULL); | 4460 g_return_if_fail(buddy != NULL); |
4554 g_return_if_fail(conv != NULL); | 4461 g_return_if_fail(conv != NULL); |
4555 | 4462 |
4584 | 4491 |
4585 g_free(normalized_name); | 4492 g_free(normalized_name); |
4586 | 4493 |
4587 blist_node_aliased_cb((PurpleBlistNode *)buddy, NULL, conv); | 4494 blist_node_aliased_cb((PurpleBlistNode *)buddy, NULL, conv); |
4588 | 4495 |
4589 texttag = get_buddy_tag(conv, purple_buddy_get_name(buddy), 0, FALSE); /* XXX: do we want the normalized name? */ | |
4590 if (texttag) { | |
4591 g_object_set(texttag, "weight", is_buddy ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL, NULL); | |
4592 } | |
4593 } | 4496 } |
4594 | 4497 |
4595 static void | 4498 static void |
4596 buddy_added_cb(PurpleBlistNode *node, PurpleConversation *conv) | 4499 buddy_added_cb(PurpleBlistNode *node, PurpleConversation *conv) |
4597 { | 4500 { |
4619 { | 4522 { |
4620 g_signal_emit_by_name(gtkconv->entry, "message_send"); | 4523 g_signal_emit_by_name(gtkconv->entry, "message_send"); |
4621 } | 4524 } |
4622 | 4525 |
4623 static void | 4526 static void |
4624 entry_popup_menu_cb(GtkIMHtml *imhtml, GtkMenu *menu, gpointer data) | 4527 entry_popup_menu_cb(GtkIMHtml *imhtml /* this is for ->entry, fine! */, GtkMenu *menu, gpointer data) |
4625 { | 4528 { |
4626 GtkWidget *menuitem; | 4529 GtkWidget *menuitem; |
4627 PidginConversation *gtkconv = data; | 4530 PidginConversation *gtkconv = data; |
4628 | 4531 |
4629 g_return_if_fail(menu != NULL); | 4532 g_return_if_fail(menu != NULL); |
4647 GtkTextIter iter; | 4550 GtkTextIter iter; |
4648 int lines; | 4551 int lines; |
4649 GdkRectangle oneline; | 4552 GdkRectangle oneline; |
4650 int height, diff; | 4553 int height, diff; |
4651 int pad_top, pad_inside, pad_bottom; | 4554 int pad_top, pad_inside, pad_bottom; |
4652 int total_height = (gtkconv->imhtml->allocation.height + gtkconv->entry->allocation.height); | 4555 int total_height = (gtkconv->webview->allocation.height + gtkconv->entry->allocation.height); |
4653 int max_height = total_height / 2; | 4556 int max_height = total_height / 2; |
4654 int min_lines = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/conversations/minimum_entry_lines"); | 4557 int min_lines = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/conversations/minimum_entry_lines"); |
4655 int min_height; | 4558 int min_height; |
4656 | 4559 |
4657 pad_top = gtk_text_view_get_pixels_above_lines(GTK_TEXT_VIEW(gtkconv->entry)); | 4560 pad_top = gtk_text_view_get_pixels_above_lines(GTK_TEXT_VIEW(gtkconv->entry)); |
4886 | 4789 |
4887 conv = gtkconv->active_conv; | 4790 conv = gtkconv->active_conv; |
4888 if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) { | 4791 if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) { |
4889 node = (PurpleBlistNode*)(purple_blist_find_chat(conv->account, conv->name)); | 4792 node = (PurpleBlistNode*)(purple_blist_find_chat(conv->account, conv->name)); |
4890 if (!node) | 4793 if (!node) |
4891 node = g_object_get_data(G_OBJECT(gtkconv->imhtml), "transient_chat"); | 4794 node = g_object_get_data(G_OBJECT(gtkconv->webview), "transient_chat"); |
4892 } else { | 4795 } else { |
4893 node = (PurpleBlistNode*)(purple_find_buddy(conv->account, conv->name)); | 4796 node = (PurpleBlistNode*)(purple_find_buddy(conv->account, conv->name)); |
4894 #if 0 | 4797 #if 0 |
4895 /* Using the transient blist nodes to show the tooltip doesn't quite work yet. */ | 4798 /* Using the transient blist nodes to show the tooltip doesn't quite work yet. */ |
4896 if (!node) | 4799 if (!node) |
4897 node = g_object_get_data(G_OBJECT(gtkconv->imhtml), "transient_buddy"); | 4800 node = g_object_get_data(G_OBJECT(gtkconv->webview), "transient_buddy"); |
4898 #endif | 4801 #endif |
4899 } | 4802 } |
4900 | 4803 |
4901 if (node) | 4804 if (node) |
4902 pidgin_blist_draw_tooltip(node, gtkconv->infopane); | 4805 pidgin_blist_draw_tooltip(node, gtkconv->infopane); |
4904 } | 4807 } |
4905 | 4808 |
4906 static GtkWidget * | 4809 static GtkWidget * |
4907 setup_common_pane(PidginConversation *gtkconv) | 4810 setup_common_pane(PidginConversation *gtkconv) |
4908 { | 4811 { |
4909 GtkWidget *vbox, *frame, *imhtml_sw, *event_box; | 4812 GtkWidget *vbox, *frame, *webview_sw, *event_box; |
4910 GtkCellRenderer *rend; | 4813 GtkCellRenderer *rend; |
4911 GtkTreePath *path; | 4814 GtkTreePath *path; |
4912 PurpleConversation *conv = gtkconv->active_conv; | 4815 PurpleConversation *conv = gtkconv->active_conv; |
4913 PurpleBuddy *buddy; | 4816 PurpleBuddy *buddy; |
4914 gboolean chat = (conv->type == PURPLE_CONV_TYPE_CHAT); | 4817 gboolean chat = (conv->type == PURPLE_CONV_TYPE_CHAT); |
4915 GtkPolicyType imhtml_sw_hscroll; | 4818 GtkPolicyType webview_sw_hscroll; |
4916 int buddyicon_size = 0; | 4819 int buddyicon_size = 0; |
4917 | 4820 |
4918 /* Setup the top part of the pane */ | 4821 /* Setup the top part of the pane */ |
4919 vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE); | 4822 vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE); |
4920 gtk_widget_show(vbox); | 4823 gtk_widget_show(vbox); |
5006 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(gtkconv->infopane), rend, FALSE); | 4909 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(gtkconv->infopane), rend, FALSE); |
5007 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(gtkconv->infopane), rend, "pixbuf", CONV_EMBLEM_COLUMN, NULL); | 4910 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(gtkconv->infopane), rend, "pixbuf", CONV_EMBLEM_COLUMN, NULL); |
5008 g_object_set(rend, "xalign", 0.0, "xpad", 6, "ypad", 0, NULL); | 4911 g_object_set(rend, "xalign", 0.0, "xpad", 6, "ypad", 0, NULL); |
5009 | 4912 |
5010 /* Setup the gtkimhtml widget */ | 4913 /* Setup the gtkimhtml widget */ |
5011 frame = pidgin_create_imhtml(FALSE, >kconv->imhtml, NULL, &imhtml_sw); | 4914 webview_sw = gtk_scrolled_window_new (NULL, NULL); |
5012 gtk_widget_set_size_request(gtkconv->imhtml, -1, 0); | 4915 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(webview_sw), GTK_SHADOW_IN); |
4916 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (webview_sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); | |
4917 | |
4918 gtkconv->webview = gtk_webview_new (); | |
4919 gtk_container_add (GTK_CONTAINER (webview_sw), gtkconv->webview); | |
4920 | |
4921 gtk_widget_set_size_request(gtkconv->webview, -1, 0); | |
4922 | |
5013 if (chat) { | 4923 if (chat) { |
5014 GtkWidget *hpaned; | 4924 GtkWidget *hpaned; |
5015 | 4925 |
5016 /* Add the topic */ | 4926 /* Add the topic */ |
5017 setup_chat_topic(gtkconv, vbox); | 4927 setup_chat_topic(gtkconv, vbox); |
5018 | 4928 |
5019 /* Add the gtkimhtml frame */ | 4929 /* Add the gtkimhtml frame */ |
5020 hpaned = gtk_hpaned_new(); | 4930 hpaned = gtk_hpaned_new(); |
5021 gtk_box_pack_start(GTK_BOX(vbox), hpaned, TRUE, TRUE, 0); | 4931 gtk_box_pack_start(GTK_BOX(vbox), hpaned, TRUE, TRUE, 0); |
5022 gtk_widget_show(hpaned); | 4932 gtk_widget_show(hpaned); |
5023 gtk_paned_pack1(GTK_PANED(hpaned), frame, TRUE, TRUE); | 4933 gtk_paned_pack1(GTK_PANED(hpaned), webview_sw, TRUE, TRUE); |
5024 | 4934 |
5025 /* Now add the userlist */ | 4935 /* Now add the userlist */ |
5026 setup_chat_userlist(gtkconv, hpaned); | 4936 setup_chat_userlist(gtkconv, hpaned); |
5027 } else { | 4937 } else { |
5028 gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0); | 4938 gtk_box_pack_start(GTK_BOX(vbox), webview_sw, TRUE, TRUE, 0); |
5029 } | 4939 } |
5030 gtk_widget_show(frame); | 4940 gtk_widget_show_all(webview_sw); |
5031 | 4941 |
5032 gtk_widget_set_name(gtkconv->imhtml, "pidgin_conv_imhtml"); | 4942 gtk_widget_set_name(gtkconv->webview, "pidgin_conv_webview"); |
5033 gtk_imhtml_show_comments(GTK_IMHTML(gtkconv->imhtml),TRUE); | 4943 g_object_set_data(G_OBJECT(gtkconv->webview), "gtkconv", gtkconv); |
5034 g_object_set_data(G_OBJECT(gtkconv->imhtml), "gtkconv", gtkconv); | 4944 |
5035 | 4945 gtk_scrolled_window_get_policy(GTK_SCROLLED_WINDOW(webview_sw), |
5036 gtk_scrolled_window_get_policy(GTK_SCROLLED_WINDOW(imhtml_sw), | 4946 &webview_sw_hscroll, NULL); |
5037 &imhtml_sw_hscroll, NULL); | 4947 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(webview_sw), |
5038 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(imhtml_sw), | 4948 webview_sw_hscroll, GTK_POLICY_ALWAYS); |
5039 imhtml_sw_hscroll, GTK_POLICY_ALWAYS); | 4949 |
5040 | 4950 g_signal_connect_after(G_OBJECT(gtkconv->webview), "button_press_event", |
5041 g_signal_connect_after(G_OBJECT(gtkconv->imhtml), "button_press_event", | |
5042 G_CALLBACK(entry_stop_rclick_cb), NULL); | 4951 G_CALLBACK(entry_stop_rclick_cb), NULL); |
5043 g_signal_connect(G_OBJECT(gtkconv->imhtml), "key_press_event", | 4952 g_signal_connect(G_OBJECT(gtkconv->webview), "key_press_event", |
5044 G_CALLBACK(refocus_entry_cb), gtkconv); | 4953 G_CALLBACK(refocus_entry_cb), gtkconv); |
5045 g_signal_connect(G_OBJECT(gtkconv->imhtml), "key_release_event", | 4954 g_signal_connect(G_OBJECT(gtkconv->webview), "key_release_event", |
5046 G_CALLBACK(refocus_entry_cb), gtkconv); | 4955 G_CALLBACK(refocus_entry_cb), gtkconv); |
5047 | 4956 |
5048 gtkconv->lower_hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE); | 4957 gtkconv->lower_hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE); |
5049 gtk_box_pack_start(GTK_BOX(vbox), gtkconv->lower_hbox, FALSE, FALSE, 0); | 4958 gtk_box_pack_start(GTK_BOX(vbox), gtkconv->lower_hbox, FALSE, FALSE, 0); |
5050 gtk_widget_show(gtkconv->lower_hbox); | 4959 gtk_widget_show(gtkconv->lower_hbox); |
5279 return FALSE; | 5188 return FALSE; |
5280 } | 5189 } |
5281 | 5190 |
5282 static void set_typing_font(GtkWidget *widget, GtkStyle *style, PidginConversation *gtkconv) | 5191 static void set_typing_font(GtkWidget *widget, GtkStyle *style, PidginConversation *gtkconv) |
5283 { | 5192 { |
5284 static PangoFontDescription *font_desc = NULL; | |
5285 static GdkColor *color = NULL; | |
5286 static gboolean enable = TRUE; | |
5287 | |
5288 if (font_desc == NULL) { | |
5289 char *string = NULL; | |
5290 gtk_widget_style_get(widget, | |
5291 "typing-notification-font", &string, | |
5292 "typing-notification-color", &color, | |
5293 "typing-notification-enable", &enable, | |
5294 NULL); | |
5295 font_desc = pango_font_description_from_string(string); | |
5296 g_free(string); | |
5297 if (color == NULL) { | |
5298 GdkColor def = {0, 0x8888, 0x8888, 0x8888}; | |
5299 color = gdk_color_copy(&def); | |
5300 } | |
5301 } | |
5302 | |
5303 gtk_text_buffer_create_tag(GTK_IMHTML(widget)->text_buffer, "TYPING-NOTIFICATION", | |
5304 "foreground-gdk", color, | |
5305 "font-desc", font_desc, | |
5306 NULL); | |
5307 | |
5308 if (!enable) { | |
5309 g_object_set_data(G_OBJECT(widget), "disable-typing-notification", GINT_TO_POINTER(TRUE)); | |
5310 /* or may be 'gtkconv->disable_typing = TRUE;' instead? */ | |
5311 } | |
5312 | |
5313 g_signal_handlers_disconnect_by_func(G_OBJECT(widget), set_typing_font, gtkconv); | |
5314 } | 5193 } |
5315 | 5194 |
5316 /************************************************************************** | 5195 /************************************************************************** |
5317 * Conversation UI operations | 5196 * Conversation UI operations |
5318 **************************************************************************/ | 5197 **************************************************************************/ |
5349 gtkconv->u.im = g_malloc0(sizeof(PidginImPane)); | 5228 gtkconv->u.im = g_malloc0(sizeof(PidginImPane)); |
5350 } else if (conv_type == PURPLE_CONV_TYPE_CHAT) { | 5229 } else if (conv_type == PURPLE_CONV_TYPE_CHAT) { |
5351 gtkconv->u.chat = g_malloc0(sizeof(PidginChatPane)); | 5230 gtkconv->u.chat = g_malloc0(sizeof(PidginChatPane)); |
5352 } | 5231 } |
5353 pane = setup_common_pane(gtkconv); | 5232 pane = setup_common_pane(gtkconv); |
5354 | |
5355 gtk_imhtml_set_format_functions(GTK_IMHTML(gtkconv->imhtml), | |
5356 gtk_imhtml_get_format_functions(GTK_IMHTML(gtkconv->imhtml)) | GTK_IMHTML_IMAGE); | |
5357 | 5233 |
5358 if (pane == NULL) { | 5234 if (pane == NULL) { |
5359 if (conv_type == PURPLE_CONV_TYPE_CHAT) | 5235 if (conv_type == PURPLE_CONV_TYPE_CHAT) |
5360 g_free(gtkconv->u.chat); | 5236 g_free(gtkconv->u.chat); |
5361 else if (conv_type == PURPLE_CONV_TYPE_IM) | 5237 else if (conv_type == PURPLE_CONV_TYPE_IM) |
5375 gtk_drag_dest_set(pane, | 5251 gtk_drag_dest_set(pane, |
5376 GTK_DEST_DEFAULT_MOTION | | 5252 GTK_DEST_DEFAULT_MOTION | |
5377 GTK_DEST_DEFAULT_DROP, | 5253 GTK_DEST_DEFAULT_DROP, |
5378 te, sizeof(te) / sizeof(GtkTargetEntry), | 5254 te, sizeof(te) / sizeof(GtkTargetEntry), |
5379 GDK_ACTION_COPY); | 5255 GDK_ACTION_COPY); |
5380 gtk_drag_dest_set(gtkconv->imhtml, 0, | 5256 gtk_drag_dest_set(gtkconv->webview, 0, |
5381 te, sizeof(te) / sizeof(GtkTargetEntry), | 5257 te, sizeof(te) / sizeof(GtkTargetEntry), |
5382 GDK_ACTION_COPY); | 5258 GDK_ACTION_COPY); |
5383 | 5259 |
5384 gtk_drag_dest_set(gtkconv->entry, 0, | 5260 gtk_drag_dest_set(gtkconv->entry, 0, |
5385 te, sizeof(te) / sizeof(GtkTargetEntry), | 5261 te, sizeof(te) / sizeof(GtkTargetEntry), |
5387 | 5263 |
5388 g_signal_connect(G_OBJECT(pane), "button_press_event", | 5264 g_signal_connect(G_OBJECT(pane), "button_press_event", |
5389 G_CALLBACK(ignore_middle_click), NULL); | 5265 G_CALLBACK(ignore_middle_click), NULL); |
5390 g_signal_connect(G_OBJECT(pane), "drag_data_received", | 5266 g_signal_connect(G_OBJECT(pane), "drag_data_received", |
5391 G_CALLBACK(conv_dnd_recv), gtkconv); | 5267 G_CALLBACK(conv_dnd_recv), gtkconv); |
5392 g_signal_connect(G_OBJECT(gtkconv->imhtml), "drag_data_received", | 5268 g_signal_connect(G_OBJECT(gtkconv->webview), "drag_data_received", |
5393 G_CALLBACK(conv_dnd_recv), gtkconv); | 5269 G_CALLBACK(conv_dnd_recv), gtkconv); |
5394 g_signal_connect(G_OBJECT(gtkconv->entry), "drag_data_received", | 5270 g_signal_connect(G_OBJECT(gtkconv->entry), "drag_data_received", |
5395 G_CALLBACK(conv_dnd_recv), gtkconv); | 5271 G_CALLBACK(conv_dnd_recv), gtkconv); |
5396 | 5272 |
5397 g_signal_connect(gtkconv->imhtml, "style-set", G_CALLBACK(set_typing_font), gtkconv); | 5273 g_signal_connect(gtkconv->webview, "style-set", G_CALLBACK(set_typing_font), gtkconv); |
5398 | 5274 |
5399 /* Setup the container for the tab. */ | 5275 /* Setup the container for the tab. */ |
5400 gtkconv->tab_cont = tab_cont = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE); | 5276 gtkconv->tab_cont = tab_cont = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE); |
5401 g_object_set_data(G_OBJECT(tab_cont), "PidginConversation", gtkconv); | 5277 g_object_set_data(G_OBJECT(tab_cont), "PidginConversation", gtkconv); |
5402 gtk_container_set_border_width(GTK_CONTAINER(tab_cont), PIDGIN_HIG_BOX_SPACE); | 5278 gtk_container_set_border_width(GTK_CONTAINER(tab_cont), PIDGIN_HIG_BOX_SPACE); |
5422 if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/im/show_buddy_icons")) | 5298 if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/im/show_buddy_icons")) |
5423 gtk_widget_show(gtkconv->infopane_hbox); | 5299 gtk_widget_show(gtkconv->infopane_hbox); |
5424 else | 5300 else |
5425 gtk_widget_hide(gtkconv->infopane_hbox); | 5301 gtk_widget_hide(gtkconv->infopane_hbox); |
5426 | 5302 |
5427 gtk_imhtml_show_comments(GTK_IMHTML(gtkconv->imhtml), | |
5428 purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/show_timestamps")); | |
5429 gtk_imhtml_set_protocol_name(GTK_IMHTML(gtkconv->imhtml), | |
5430 purple_account_get_protocol_name(conv->account)); | |
5431 | 5303 |
5432 g_signal_connect_swapped(G_OBJECT(pane), "focus", | 5304 g_signal_connect_swapped(G_OBJECT(pane), "focus", |
5433 G_CALLBACK(gtk_widget_grab_focus), | 5305 G_CALLBACK(gtk_widget_grab_focus), |
5434 gtkconv->entry); | 5306 gtkconv->entry); |
5435 | 5307 |
5438 else | 5310 else |
5439 pidgin_conv_placement_place(gtkconv); | 5311 pidgin_conv_placement_place(gtkconv); |
5440 | 5312 |
5441 if (nick_colors == NULL) { | 5313 if (nick_colors == NULL) { |
5442 nbr_nick_colors = NUM_NICK_COLORS; | 5314 nbr_nick_colors = NUM_NICK_COLORS; |
5443 nick_colors = generate_nick_colors(&nbr_nick_colors, gtk_widget_get_style(gtkconv->imhtml)->base[GTK_STATE_NORMAL]); | 5315 nick_colors = generate_nick_colors(&nbr_nick_colors, gtk_widget_get_style(gtkconv->webview)->base[GTK_STATE_NORMAL]); |
5444 } | 5316 } |
5445 | 5317 |
5446 if (conv->features & PURPLE_CONNECTION_ALLOW_CUSTOM_SMILEY) | 5318 if (conv->features & PURPLE_CONNECTION_ALLOW_CUSTOM_SMILEY) |
5447 pidgin_themes_smiley_themeize_custom(gtkconv->entry); | 5319 pidgin_themes_smiley_themeize_custom(gtkconv->entry); |
5448 } | 5320 } |
5645 } | 5517 } |
5646 | 5518 |
5647 return FALSE; | 5519 return FALSE; |
5648 } | 5520 } |
5649 | 5521 |
5650 static GtkTextTag *get_buddy_tag(PurpleConversation *conv, const char *who, PurpleMessageFlags flag, | |
5651 gboolean create) | |
5652 { | |
5653 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv); | |
5654 GtkTextTag *buddytag; | |
5655 gchar *str; | |
5656 gboolean highlight = (flag & PURPLE_MESSAGE_NICK); | |
5657 GtkTextBuffer *buffer = GTK_IMHTML(gtkconv->imhtml)->text_buffer; | |
5658 | |
5659 str = g_strdup_printf(highlight ? "HILIT %s" : "BUDDY %s", who); | |
5660 | |
5661 buddytag = gtk_text_tag_table_lookup( | |
5662 gtk_text_buffer_get_tag_table(buffer), str); | |
5663 | |
5664 if (buddytag == NULL && create) { | |
5665 if (highlight) | |
5666 buddytag = gtk_text_buffer_create_tag(buffer, str, | |
5667 "foreground", get_text_tag_color(gtk_text_tag_table_lookup( | |
5668 gtk_text_buffer_get_tag_table(buffer), "highlight-name")), | |
5669 "weight", PANGO_WEIGHT_BOLD, | |
5670 NULL); | |
5671 else | |
5672 buddytag = gtk_text_buffer_create_tag( | |
5673 buffer, str, | |
5674 "foreground-gdk", get_nick_color(gtkconv, who), | |
5675 "weight", purple_find_buddy(purple_conversation_get_account(conv), who) ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL, | |
5676 NULL); | |
5677 | |
5678 g_signal_connect(G_OBJECT(buddytag), "event", | |
5679 G_CALLBACK(buddytag_event), conv); | |
5680 } | |
5681 | |
5682 g_free(str); | |
5683 | |
5684 return buddytag; | |
5685 } | |
5686 | |
5687 static void pidgin_conv_calculate_newday(PidginConversation *gtkconv, time_t mtime) | 5522 static void pidgin_conv_calculate_newday(PidginConversation *gtkconv, time_t mtime) |
5688 { | 5523 { |
5689 struct tm *tm = localtime(&mtime); | 5524 struct tm *tm = localtime(&mtime); |
5690 | 5525 |
5691 tm->tm_hour = tm->tm_min = tm->tm_sec = 0; | 5526 tm->tm_hour = tm->tm_min = tm->tm_sec = 0; |
5738 PidginConversation *gtkconv; | 5573 PidginConversation *gtkconv; |
5739 PidginWindow *win; | 5574 PidginWindow *win; |
5740 PurpleConnection *gc; | 5575 PurpleConnection *gc; |
5741 PurpleAccount *account; | 5576 PurpleAccount *account; |
5742 PurplePluginProtocolInfo *prpl_info; | 5577 PurplePluginProtocolInfo *prpl_info; |
5743 int gtk_font_options = 0; | |
5744 int gtk_font_options_all = 0; | |
5745 int max_scrollback_lines; | |
5746 int line_count; | |
5747 char buf2[BUF_LONG]; | 5578 char buf2[BUF_LONG]; |
5748 gboolean show_date; | 5579 gboolean show_date; |
5749 char *mdate; | 5580 char *mdate; |
5750 char *str; | 5581 char *str; |
5751 char *with_font_tag; | 5582 char *with_font_tag; |
5752 char *sml_attrib = NULL; | 5583 char *sml_attrib = NULL; |
5753 size_t length; | 5584 size_t length; |
5754 PurpleConversationType type; | 5585 PurpleConversationType type; |
5755 char *displaying; | 5586 char *displaying; |
5756 gboolean plugin_return; | 5587 gboolean plugin_return; |
5757 char *bracket; | |
5758 int tag_count = 0; | |
5759 gboolean is_rtl_message = FALSE; | 5588 gboolean is_rtl_message = FALSE; |
5760 | 5589 |
5761 g_return_if_fail(conv != NULL); | 5590 g_return_if_fail(conv != NULL); |
5762 gtkconv = PIDGIN_CONVERSATION(conv); | 5591 gtkconv = PIDGIN_CONVERSATION(conv); |
5763 g_return_if_fail(gtkconv != NULL); | 5592 g_return_if_fail(gtkconv != NULL); |
5811 g_free(displaying); | 5640 g_free(displaying); |
5812 return; | 5641 return; |
5813 } | 5642 } |
5814 length = strlen(displaying) + 1; | 5643 length = strlen(displaying) + 1; |
5815 | 5644 |
5816 /* Awful hack to work around GtkIMHtml's inefficient rendering of messages with lots of formatting changes. | |
5817 * If a message has over 100 '<' characters, strip formatting before appending it. Hopefully nobody actually | |
5818 * needs that much formatting, anyway. | |
5819 */ | |
5820 for (bracket = strchr(displaying, '<'); bracket && *(bracket + 1); bracket = strchr(bracket + 1, '<')) | |
5821 tag_count++; | |
5822 | |
5823 if (tag_count > 100) { | |
5824 char *tmp = displaying; | |
5825 displaying = purple_markup_strip_html(tmp); | |
5826 g_free(tmp); | |
5827 } | |
5828 | 5645 |
5829 win = gtkconv->win; | 5646 win = gtkconv->win; |
5830 prpl_info = gc ? PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl) : NULL; | 5647 prpl_info = gc ? PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl) : NULL; |
5831 | 5648 |
5832 line_count = gtk_text_buffer_get_line_count( | 5649 /* if the buffer is not empty add a <br> */ |
5833 gtk_text_view_get_buffer(GTK_TEXT_VIEW( | 5650 if (!gtk_webview_is_empty (GTK_WEBVIEW(gtkconv->webview))) |
5834 gtkconv->imhtml))); | 5651 gtk_webview_append_html (GTK_WEBVIEW(gtkconv->webview), "<br />"); |
5835 | |
5836 max_scrollback_lines = purple_prefs_get_int( | |
5837 PIDGIN_PREFS_ROOT "/conversations/scrollback_lines"); | |
5838 /* If we're sitting at more than 100 lines more than the | |
5839 max scrollback, trim down to max scrollback */ | |
5840 if (max_scrollback_lines > 0 | |
5841 && line_count > (max_scrollback_lines + 100)) { | |
5842 GtkTextBuffer *text_buffer = gtk_text_view_get_buffer( | |
5843 GTK_TEXT_VIEW(gtkconv->imhtml)); | |
5844 GtkTextIter start, end; | |
5845 | |
5846 gtk_text_buffer_get_start_iter(text_buffer, &start); | |
5847 gtk_text_buffer_get_iter_at_line(text_buffer, &end, | |
5848 (line_count - max_scrollback_lines)); | |
5849 gtk_imhtml_delete(GTK_IMHTML(gtkconv->imhtml), &start, &end); | |
5850 } | |
5851 | |
5852 if (type == PURPLE_CONV_TYPE_CHAT) | |
5853 { | |
5854 /* Create anchor for user */ | |
5855 GtkTextIter iter; | |
5856 char *tmp = g_strconcat("user:", name, NULL); | |
5857 | |
5858 gtk_text_buffer_get_end_iter(gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtkconv->imhtml)), &iter); | |
5859 gtk_text_buffer_create_mark(gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtkconv->imhtml)), | |
5860 tmp, &iter, TRUE); | |
5861 g_free(tmp); | |
5862 } | |
5863 | |
5864 if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/use_smooth_scrolling")) | |
5865 gtk_font_options_all |= GTK_IMHTML_USE_SMOOTHSCROLLING; | |
5866 | |
5867 if (gtk_text_buffer_get_char_count(gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtkconv->imhtml)))) | |
5868 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), "<BR>", gtk_font_options_all | GTK_IMHTML_NO_SCROLL); | |
5869 | 5652 |
5870 /* First message in a conversation. */ | 5653 /* First message in a conversation. */ |
5871 if (gtkconv->newday == 0) | 5654 if (gtkconv->newday == 0) |
5872 pidgin_conv_calculate_newday(gtkconv, mtime); | 5655 pidgin_conv_calculate_newday(gtkconv, mtime); |
5873 | 5656 |
5899 if (mtime >= gtkconv->newday) | 5682 if (mtime >= gtkconv->newday) |
5900 pidgin_conv_calculate_newday(gtkconv, mtime); | 5683 pidgin_conv_calculate_newday(gtkconv, mtime); |
5901 | 5684 |
5902 sml_attrib = g_strdup_printf("sml=\"%s\"", purple_account_get_protocol_name(account)); | 5685 sml_attrib = g_strdup_printf("sml=\"%s\"", purple_account_get_protocol_name(account)); |
5903 | 5686 |
5904 gtk_font_options |= GTK_IMHTML_NO_COMMENTS; | |
5905 | |
5906 if ((flags & PURPLE_MESSAGE_RECV) && | |
5907 !purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/conversations/show_incoming_formatting")) | |
5908 gtk_font_options |= GTK_IMHTML_NO_COLOURS | GTK_IMHTML_NO_FONTS | GTK_IMHTML_NO_SIZES | GTK_IMHTML_NO_FORMATTING; | |
5909 | |
5910 /* this is gonna crash one day, I can feel it. */ | |
5911 if (PURPLE_PLUGIN_PROTOCOL_INFO(purple_find_prpl(purple_account_get_protocol_id(conv->account)))->options & | |
5912 OPT_PROTO_USE_POINTSIZE) { | |
5913 gtk_font_options |= GTK_IMHTML_USE_POINTSIZE; | |
5914 } | |
5915 | |
5916 if (!(flags & PURPLE_MESSAGE_RECV) && (conv->features & PURPLE_CONNECTION_ALLOW_CUSTOM_SMILEY)) | |
5917 { | |
5918 /* We want to see our own smileys. Need to revert it after send*/ | |
5919 pidgin_themes_smiley_themeize_custom(gtkconv->imhtml); | |
5920 } | |
5921 | |
5922 /* TODO: These colors should not be hardcoded so log.c can use them */ | 5687 /* TODO: These colors should not be hardcoded so log.c can use them */ |
5923 if (flags & PURPLE_MESSAGE_RAW) { | 5688 if (flags & PURPLE_MESSAGE_RAW) { |
5924 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), message, gtk_font_options_all); | 5689 gtk_webview_append_html (GTK_WEBVIEW(gtkconv->webview), message); |
5925 } else if (flags & PURPLE_MESSAGE_SYSTEM) { | 5690 } else if (flags & PURPLE_MESSAGE_SYSTEM) { |
5926 g_snprintf(buf2, sizeof(buf2), | 5691 g_snprintf(buf2, sizeof(buf2), |
5927 "<FONT %s><FONT SIZE=\"2\"><!--%s --></FONT><B>%s</B></FONT>", | 5692 "<font %s><font size=\"2\"><span class='timestamp'>%s</span></font><b>%s</b></font>", |
5928 sml_attrib ? sml_attrib : "", mdate, displaying); | 5693 sml_attrib ? sml_attrib : "", mdate, displaying); |
5929 | 5694 |
5930 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf2, gtk_font_options_all); | 5695 gtk_webview_append_html(GTK_WEBVIEW(gtkconv->webview), buf2); |
5931 | 5696 |
5932 } else if (flags & PURPLE_MESSAGE_ERROR) { | 5697 } else if (flags & PURPLE_MESSAGE_ERROR) { |
5933 g_snprintf(buf2, sizeof(buf2), | 5698 g_snprintf(buf2, sizeof(buf2), |
5934 "<FONT COLOR=\"#ff0000\"><FONT %s><FONT SIZE=\"2\"><!--%s --></FONT><B>%s</B></FONT></FONT>", | 5699 "<font color=\"#ff0000\"><font %s><font size=\"2\"><span class='timestamp'>%s</span> </font><b>%s</b></font></font>", |
5935 sml_attrib ? sml_attrib : "", mdate, displaying); | 5700 sml_attrib ? sml_attrib : "", mdate, displaying); |
5936 | 5701 |
5937 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf2, gtk_font_options_all); | 5702 gtk_webview_append_html(GTK_WEBVIEW(gtkconv->webview), buf2); |
5938 | 5703 |
5939 } else if (flags & PURPLE_MESSAGE_NO_LOG) { | 5704 } else if (flags & PURPLE_MESSAGE_NO_LOG) { |
5940 g_snprintf(buf2, BUF_LONG, | 5705 g_snprintf(buf2, BUF_LONG, |
5941 "<B><FONT %s COLOR=\"#777777\">%s</FONT></B>", | 5706 "<b><font %s color=\"#777777\">%s</font></b>", |
5942 sml_attrib ? sml_attrib : "", displaying); | 5707 sml_attrib ? sml_attrib : "", displaying); |
5943 | 5708 |
5944 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf2, gtk_font_options_all); | 5709 gtk_webview_append_html(GTK_WEBVIEW(gtkconv->webview), buf2); |
5945 } else { | 5710 } else { |
5946 char *new_message = g_memdup(displaying, length); | 5711 char *new_message = g_memdup(displaying, length); |
5947 char *alias_escaped = (alias ? g_markup_escape_text(alias, strlen(alias)) : g_strdup("")); | 5712 char *alias_escaped = (alias ? g_markup_escape_text(alias, strlen(alias)) : g_strdup("")); |
5948 /* The initial offset is to deal with | 5713 /* The initial offset is to deal with |
5949 * escaped entities making the string longer */ | 5714 * escaped entities making the string longer */ |
5950 int tag_start_offset = 0; | 5715 int tag_start_offset = 0; |
5951 int tag_end_offset = 0; | 5716 int tag_end_offset = 0; |
5952 const char *tagname = NULL; | 5717 const char *tagname = NULL; |
5953 | |
5954 GtkTextIter start, end; | |
5955 GtkTextMark *mark; | |
5956 GtkTextTag *tag; | |
5957 GtkTextBuffer *buffer = GTK_IMHTML(gtkconv->imhtml)->text_buffer; | |
5958 | 5718 |
5959 /* Enforce direction on alias */ | 5719 /* Enforce direction on alias */ |
5960 if (is_rtl_message) | 5720 if (is_rtl_message) |
5961 str_embed_direction_chars(&alias_escaped); | 5721 str_embed_direction_chars(&alias_escaped); |
5962 | 5722 |
6014 } | 5774 } |
6015 } | 5775 } |
6016 | 5776 |
6017 g_free(alias_escaped); | 5777 g_free(alias_escaped); |
6018 | 5778 |
6019 if (tagname) | 5779 /* timestamp */ |
6020 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(buffer), tagname); | 5780 { |
6021 else | 5781 g_snprintf (buf2, BUF_LONG, "<font size='2'>%s </font>", mdate); |
6022 tag = get_buddy_tag(conv, name, flags, TRUE); | 5782 |
6023 | 5783 gtk_webview_append_html (GTK_WEBVIEW(gtkconv->webview), buf2); |
6024 if (GTK_IMHTML(gtkconv->imhtml)->show_comments) { | 5784 } |
6025 /* The color for the timestamp has to be set in the font-tags, unfortunately. | 5785 g_snprintf(buf2, BUF_LONG, "<font %s>%s</font> ", sml_attrib ? sml_attrib : "", str); |
6026 * Applying the nick-tag to timestamps would work, but that can make it | 5786 gtk_webview_append_html(GTK_WEBVIEW(gtkconv->webview), buf2); |
6027 * bold. I thought applying the "comment" tag again, which has "weight" set | |
6028 * to PANGO_WEIGHT_NORMAL, would remove the boldness. But it doesn't. So | |
6029 * this will have to do. I don't terribly like it. -- sadrul */ | |
6030 const char *color = get_text_tag_color(tag); | |
6031 g_snprintf(buf2, BUF_LONG, "<FONT %s%s%s SIZE=\"2\"><!--%s --></FONT>", | |
6032 color ? "COLOR=\"" : "", color ? color : "", color ? "\"" : "", mdate); | |
6033 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf2, gtk_font_options_all | GTK_IMHTML_NO_SCROLL); | |
6034 } | |
6035 | |
6036 gtk_text_buffer_get_end_iter(buffer, &end); | |
6037 mark = gtk_text_buffer_create_mark(buffer, NULL, &end, TRUE); | |
6038 | |
6039 g_snprintf(buf2, BUF_LONG, "<FONT %s>%s</FONT> ", sml_attrib ? sml_attrib : "", str); | |
6040 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf2, gtk_font_options_all | GTK_IMHTML_NO_SCROLL); | |
6041 | |
6042 gtk_text_buffer_get_end_iter(buffer, &end); | |
6043 gtk_text_buffer_get_iter_at_mark(buffer, &start, mark); | |
6044 gtk_text_buffer_apply_tag(buffer, tag, &start, &end); | |
6045 gtk_text_buffer_delete_mark(buffer, mark); | |
6046 | 5787 |
6047 g_free(str); | 5788 g_free(str); |
6048 | 5789 |
6049 if(gc){ | 5790 if(gc){ |
6050 char *pre = g_strdup_printf("<font %s>", sml_attrib ? sml_attrib : ""); | 5791 char *pre = g_strdup_printf("<font %s>", sml_attrib ? sml_attrib : ""); |
6051 char *post = "</font>"; | 5792 char *post = "</font>"; |
6052 int pre_len = strlen(pre); | 5793 with_font_tag = g_strdup_printf ("%s%s%s", pre, new_message, post); |
6053 int post_len = strlen(post); | |
6054 | |
6055 with_font_tag = g_malloc(length + pre_len + post_len + 1); | |
6056 | |
6057 strcpy(with_font_tag, pre); | |
6058 memcpy(with_font_tag + pre_len, new_message, length); | |
6059 strcpy(with_font_tag + pre_len + length, post); | |
6060 | |
6061 length += pre_len + post_len; | |
6062 g_free(pre); | 5794 g_free(pre); |
6063 } else | 5795 } else |
6064 with_font_tag = g_memdup(new_message, length); | 5796 with_font_tag = g_memdup(new_message, length); |
6065 | 5797 |
6066 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), | 5798 gtk_webview_append_html(GTK_WEBVIEW(gtkconv->webview), |
6067 with_font_tag, gtk_font_options | gtk_font_options_all); | 5799 with_font_tag); |
6068 | 5800 |
6069 g_free(with_font_tag); | 5801 g_free(with_font_tag); |
6070 g_free(new_message); | 5802 g_free(new_message); |
6071 } | 5803 } |
6072 | 5804 |
6089 unseen = PIDGIN_UNSEEN_TEXT; | 5821 unseen = PIDGIN_UNSEEN_TEXT; |
6090 | 5822 |
6091 gtkconv_set_unseen(gtkconv, unseen); | 5823 gtkconv_set_unseen(gtkconv, unseen); |
6092 } | 5824 } |
6093 | 5825 |
6094 if (!(flags & PURPLE_MESSAGE_RECV) && (conv->features & PURPLE_CONNECTION_ALLOW_CUSTOM_SMILEY)) | |
6095 { | |
6096 /* Restore the smiley-data */ | |
6097 pidgin_themes_smiley_themeize(gtkconv->imhtml); | |
6098 } | |
6099 | |
6100 purple_signal_emit(pidgin_conversations_get_handle(), | 5826 purple_signal_emit(pidgin_conversations_get_handle(), |
6101 (type == PURPLE_CONV_TYPE_IM ? "displayed-im-msg" : "displayed-chat-msg"), | 5827 (type == PURPLE_CONV_TYPE_IM ? "displayed-im-msg" : "displayed-chat-msg"), |
6102 account, name, displaying, conv, flags); | 5828 account, name, displaying, conv, flags); |
6103 g_free(displaying); | 5829 g_free(displaying); |
6104 update_typing_message(gtkconv, NULL); | 5830 update_typing_message(gtkconv, NULL); |
6186 f = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter); | 5912 f = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter); |
6187 | 5913 |
6188 g_free(val); | 5914 g_free(val); |
6189 } | 5915 } |
6190 | 5916 |
6191 if ((tag = get_buddy_tag(conv, old_name, 0, FALSE))) | |
6192 g_object_set(G_OBJECT(tag), "style", PANGO_STYLE_ITALIC, NULL); | |
6193 if ((tag = get_buddy_tag(conv, old_name, PURPLE_MESSAGE_NICK, FALSE))) | |
6194 g_object_set(G_OBJECT(tag), "style", PANGO_STYLE_ITALIC, NULL); | |
6195 | 5917 |
6196 if (!purple_conv_chat_find_user(chat, old_name)) | 5918 if (!purple_conv_chat_find_user(chat, old_name)) |
6197 return; | 5919 return; |
6198 | 5920 |
6199 g_return_if_fail(new_alias != NULL); | 5921 g_return_if_fail(new_alias != NULL); |
6247 f = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter); | 5969 f = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter); |
6248 | 5970 |
6249 g_free(val); | 5971 g_free(val); |
6250 } while (f); | 5972 } while (f); |
6251 | 5973 |
6252 if ((tag = get_buddy_tag(conv, l->data, 0, FALSE))) | 5974 |
6253 g_object_set(G_OBJECT(tag), "style", PANGO_STYLE_ITALIC, NULL); | |
6254 if ((tag = get_buddy_tag(conv, l->data, PURPLE_MESSAGE_NICK, FALSE))) | |
6255 g_object_set(G_OBJECT(tag), "style", PANGO_STYLE_ITALIC, NULL); | |
6256 } | 5975 } |
6257 | 5976 |
6258 g_snprintf(tmp, sizeof(tmp), | 5977 g_snprintf(tmp, sizeof(tmp), |
6259 ngettext("%d person in room", "%d people in room", | 5978 ngettext("%d person in room", "%d people in room", |
6260 num_users), num_users); | 5979 num_users), num_users); |
6354 g_signal_connect_swapped(imhtml, "destroy", G_CALLBACK(gtk_imhtml_smiley_destroy), smiley); | 6073 g_signal_connect_swapped(imhtml, "destroy", G_CALLBACK(gtk_imhtml_smiley_destroy), smiley); |
6355 | 6074 |
6356 return TRUE; | 6075 return TRUE; |
6357 } | 6076 } |
6358 | 6077 |
6359 static gboolean | |
6360 pidgin_conv_custom_smiley_add(PurpleConversation *conv, const char *smile, gboolean remote) | |
6361 { | |
6362 PidginConversation *gtkconv; | |
6363 struct smiley_list *list; | |
6364 const char *sml = NULL, *conv_sml; | |
6365 | |
6366 if (!conv || !smile || !*smile) { | |
6367 return FALSE; | |
6368 } | |
6369 | |
6370 /* If smileys are off, return false */ | |
6371 if (pidgin_themes_smileys_disabled()) | |
6372 return FALSE; | |
6373 | |
6374 /* If possible add this smiley to the current theme. | |
6375 * The addition is only temporary: custom smilies aren't saved to disk. */ | |
6376 conv_sml = purple_account_get_protocol_name(conv->account); | |
6377 gtkconv = PIDGIN_CONVERSATION(conv); | |
6378 | |
6379 for (list = (struct smiley_list *)current_smiley_theme->list; list; list = list->next) { | |
6380 if (!strcmp(list->sml, conv_sml)) { | |
6381 sml = list->sml; | |
6382 break; | |
6383 } | |
6384 } | |
6385 | |
6386 if (!add_custom_smiley_for_imhtml(GTK_IMHTML(gtkconv->imhtml), sml, smile)) | |
6387 return FALSE; | |
6388 | |
6389 if (!remote) /* If it's a local custom smiley, then add it for the entry */ | |
6390 if (!add_custom_smiley_for_imhtml(GTK_IMHTML(gtkconv->entry), sml, smile)) | |
6391 return FALSE; | |
6392 | |
6393 return TRUE; | |
6394 } | |
6395 | |
6396 static void | 6078 static void |
6397 pidgin_conv_custom_smiley_write(PurpleConversation *conv, const char *smile, | 6079 pidgin_conv_custom_smiley_write(PurpleConversation *conv, const char *smile, |
6398 const guchar *data, gsize size) | 6080 const guchar *data, gsize size) |
6399 { | 6081 { |
6400 PidginConversation *gtkconv; | 6082 return; |
6401 GtkIMHtmlSmiley *smiley; | |
6402 GdkPixbufLoader *loader; | |
6403 const char *sml; | |
6404 | |
6405 sml = purple_account_get_protocol_name(conv->account); | |
6406 gtkconv = PIDGIN_CONVERSATION(conv); | |
6407 smiley = gtk_imhtml_smiley_get(GTK_IMHTML(gtkconv->imhtml), sml, smile); | |
6408 | |
6409 if (!smiley) | |
6410 return; | |
6411 | |
6412 smiley->data = g_realloc(smiley->data, smiley->datasize + size); | |
6413 g_memmove((guchar *)smiley->data + smiley->datasize, data, size); | |
6414 smiley->datasize += size; | |
6415 | |
6416 loader = smiley->loader; | |
6417 if (!loader) | |
6418 return; | |
6419 | |
6420 gdk_pixbuf_loader_write(loader, data, size, NULL); | |
6421 } | 6083 } |
6422 | 6084 |
6423 static void | 6085 static void |
6424 pidgin_conv_custom_smiley_close(PurpleConversation *conv, const char *smile) | 6086 pidgin_conv_custom_smiley_close(PurpleConversation *conv, const char *smile) |
6425 { | 6087 { |
6426 PidginConversation *gtkconv; | 6088 return; |
6427 GtkIMHtmlSmiley *smiley; | |
6428 GdkPixbufLoader *loader; | |
6429 const char *sml; | |
6430 | |
6431 g_return_if_fail(conv != NULL); | |
6432 g_return_if_fail(smile != NULL); | |
6433 | |
6434 sml = purple_account_get_protocol_name(conv->account); | |
6435 gtkconv = PIDGIN_CONVERSATION(conv); | |
6436 smiley = gtk_imhtml_smiley_get(GTK_IMHTML(gtkconv->imhtml), sml, smile); | |
6437 | |
6438 if (!smiley) | |
6439 return; | |
6440 | |
6441 loader = smiley->loader; | |
6442 | |
6443 if (!loader) | |
6444 return; | |
6445 | |
6446 | |
6447 | |
6448 purple_debug_info("gtkconv", "About to close the smiley pixbuf\n"); | |
6449 | |
6450 gdk_pixbuf_loader_close(loader, NULL); | |
6451 | |
6452 } | 6089 } |
6453 | 6090 |
6454 static void | 6091 static void |
6455 pidgin_conv_send_confirm(PurpleConversation *conv, const char *message) | 6092 pidgin_conv_send_confirm(PurpleConversation *conv, const char *message) |
6456 { | 6093 { |
6714 gtk_tooltips_set_tip(gtkconv->tooltips, gtkchat->topic_text, | 6351 gtk_tooltips_set_tip(gtkconv->tooltips, gtkchat->topic_text, |
6715 topic ? topic : "", NULL); | 6352 topic ? topic : "", NULL); |
6716 } | 6353 } |
6717 } | 6354 } |
6718 | 6355 |
6719 if (fields & PIDGIN_CONV_SMILEY_THEME) | |
6720 pidgin_themes_smiley_themeize(PIDGIN_CONVERSATION(conv)->imhtml); | |
6721 | 6356 |
6722 if ((fields & PIDGIN_CONV_COLORIZE_TITLE) || | 6357 if ((fields & PIDGIN_CONV_COLORIZE_TITLE) || |
6723 (fields & PIDGIN_CONV_SET_TITLE) || | 6358 (fields & PIDGIN_CONV_SET_TITLE) || |
6724 (fields & PIDGIN_CONV_TOPIC)) | 6359 (fields & PIDGIN_CONV_TOPIC)) |
6725 { | 6360 { |
6940 pidgin_conv_chat_rename_user, /* chat_rename_user */ | 6575 pidgin_conv_chat_rename_user, /* chat_rename_user */ |
6941 pidgin_conv_chat_remove_users, /* chat_remove_users */ | 6576 pidgin_conv_chat_remove_users, /* chat_remove_users */ |
6942 pidgin_conv_chat_update_user, /* chat_update_user */ | 6577 pidgin_conv_chat_update_user, /* chat_update_user */ |
6943 pidgin_conv_present_conversation, /* present */ | 6578 pidgin_conv_present_conversation, /* present */ |
6944 pidgin_conv_has_focus, /* has_focus */ | 6579 pidgin_conv_has_focus, /* has_focus */ |
6945 pidgin_conv_custom_smiley_add, /* custom_smiley_add */ | 6580 NULL, /* custom_smiley_add */ |
6946 pidgin_conv_custom_smiley_write, /* custom_smiley_write */ | 6581 pidgin_conv_custom_smiley_write, /* custom_smiley_write */ |
6947 pidgin_conv_custom_smiley_close, /* custom_smiley_close */ | 6582 pidgin_conv_custom_smiley_close, /* custom_smiley_close */ |
6948 pidgin_conv_send_confirm, /* send_confirm */ | 6583 pidgin_conv_send_confirm, /* send_confirm */ |
6949 NULL, | 6584 NULL, |
6950 NULL, | 6585 NULL, |
7347 | 6982 |
7348 gtk_check_menu_item_set_active( | 6983 gtk_check_menu_item_set_active( |
7349 GTK_CHECK_MENU_ITEM(win->menu.show_timestamps), | 6984 GTK_CHECK_MENU_ITEM(win->menu.show_timestamps), |
7350 (gboolean)GPOINTER_TO_INT(value)); | 6985 (gboolean)GPOINTER_TO_INT(value)); |
7351 | 6986 |
7352 gtk_imhtml_show_comments(GTK_IMHTML(gtkconv->imhtml), | |
7353 (gboolean)GPOINTER_TO_INT(value)); | |
7354 } | 6987 } |
7355 } | 6988 } |
7356 | 6989 |
7357 static void | 6990 static void |
7358 show_formatting_toolbar_pref_cb(const char *name, PurplePrefType type, | 6991 show_formatting_toolbar_pref_cb(const char *name, PurplePrefType type, |
7765 | 7398 |
7766 gtkconv->attach.timer = 0; | 7399 gtkconv->attach.timer = 0; |
7767 while (gtkconv->attach.current && count < 100) { /* XXX: 100 is a random value here */ | 7400 while (gtkconv->attach.current && count < 100) { /* XXX: 100 is a random value here */ |
7768 PurpleConvMessage *msg = gtkconv->attach.current->data; | 7401 PurpleConvMessage *msg = gtkconv->attach.current->data; |
7769 if (!im && when && when < msg->when) { | 7402 if (!im && when && when < msg->when) { |
7770 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), "<BR><HR>", 0); | 7403 gtk_webview_append_html(GTK_WEBVIEW(gtkconv->webview), "<BR><HR>"); |
7771 g_object_set_data(G_OBJECT(gtkconv->entry), "attach-start-time", NULL); | 7404 g_object_set_data(G_OBJECT(gtkconv->entry), "attach-start-time", NULL); |
7772 } | 7405 } |
7773 pidgin_conv_write_conv(msg->conv, msg->who, msg->alias, msg->what, msg->flags, msg->when); | 7406 pidgin_conv_write_conv(msg->conv, msg->who, msg->alias, msg->what, msg->flags, msg->when); |
7774 if (im) { | 7407 if (im) { |
7775 gtkconv->attach.current = g_list_delete_link(gtkconv->attach.current, gtkconv->attach.current); | 7408 gtkconv->attach.current = g_list_delete_link(gtkconv->attach.current, gtkconv->attach.current); |
7800 msgs = g_list_sort(msgs, message_compare); | 7433 msgs = g_list_sort(msgs, message_compare); |
7801 for (; msgs; msgs = g_list_delete_link(msgs, msgs)) { | 7434 for (; msgs; msgs = g_list_delete_link(msgs, msgs)) { |
7802 PurpleConvMessage *msg = msgs->data; | 7435 PurpleConvMessage *msg = msgs->data; |
7803 pidgin_conv_write_conv(msg->conv, msg->who, msg->alias, msg->what, msg->flags, msg->when); | 7436 pidgin_conv_write_conv(msg->conv, msg->who, msg->alias, msg->what, msg->flags, msg->when); |
7804 } | 7437 } |
7805 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), "<BR><HR>", 0); | 7438 gtk_webview_append_html(GTK_WEBVIEW(gtkconv->webview), "<BR><HR>"); |
7806 g_object_set_data(G_OBJECT(gtkconv->entry), "attach-start-time", NULL); | 7439 g_object_set_data(G_OBJECT(gtkconv->entry), "attach-start-time", NULL); |
7807 } | 7440 } |
7808 | 7441 |
7809 g_object_set_data(G_OBJECT(gtkconv->entry), "attach-start-time", NULL); | 7442 g_object_set_data(G_OBJECT(gtkconv->entry), "attach-start-time", NULL); |
7810 purple_signal_emit(pidgin_conversations_get_handle(), | 7443 purple_signal_emit(pidgin_conversations_get_handle(), |