| 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); |
| 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 } |
| 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 && |
| 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 { |
| 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, |
| 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 **************************************************************************/ |
| 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); |
| 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 |
| 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 { |
| 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, |
| 7743 |
7376 |
| 7744 gtkconv->attach.timer = 0; |
7377 gtkconv->attach.timer = 0; |
| 7745 while (gtkconv->attach.current && count < 100) { /* XXX: 100 is a random value here */ |
7378 while (gtkconv->attach.current && count < 100) { /* XXX: 100 is a random value here */ |
| 7746 PurpleConvMessage *msg = gtkconv->attach.current->data; |
7379 PurpleConvMessage *msg = gtkconv->attach.current->data; |
| 7747 if (!im && when && when < msg->when) { |
7380 if (!im && when && when < msg->when) { |
| 7748 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), "<BR><HR>", 0); |
7381 gtk_webview_append_html(GTK_WEBVIEW(gtkconv->webview), "<BR><HR>"); |
| 7749 g_object_set_data(G_OBJECT(gtkconv->entry), "attach-start-time", NULL); |
7382 g_object_set_data(G_OBJECT(gtkconv->entry), "attach-start-time", NULL); |
| 7750 } |
7383 } |
| 7751 pidgin_conv_write_conv(msg->conv, msg->who, msg->alias, msg->what, msg->flags, msg->when); |
7384 pidgin_conv_write_conv(msg->conv, msg->who, msg->alias, msg->what, msg->flags, msg->when); |
| 7752 if (im) { |
7385 if (im) { |
| 7753 gtkconv->attach.current = g_list_delete_link(gtkconv->attach.current, gtkconv->attach.current); |
7386 gtkconv->attach.current = g_list_delete_link(gtkconv->attach.current, gtkconv->attach.current); |
| 7778 msgs = g_list_sort(msgs, message_compare); |
7411 msgs = g_list_sort(msgs, message_compare); |
| 7779 for (; msgs; msgs = g_list_delete_link(msgs, msgs)) { |
7412 for (; msgs; msgs = g_list_delete_link(msgs, msgs)) { |
| 7780 PurpleConvMessage *msg = msgs->data; |
7413 PurpleConvMessage *msg = msgs->data; |
| 7781 pidgin_conv_write_conv(msg->conv, msg->who, msg->alias, msg->what, msg->flags, msg->when); |
7414 pidgin_conv_write_conv(msg->conv, msg->who, msg->alias, msg->what, msg->flags, msg->when); |
| 7782 } |
7415 } |
| 7783 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), "<BR><HR>", 0); |
7416 gtk_webview_append_html(GTK_WEBVIEW(gtkconv->webview), "<BR><HR>"); |
| 7784 g_object_set_data(G_OBJECT(gtkconv->entry), "attach-start-time", NULL); |
7417 g_object_set_data(G_OBJECT(gtkconv->entry), "attach-start-time", NULL); |
| 7785 } |
7418 } |
| 7786 |
7419 |
| 7787 g_object_set_data(G_OBJECT(gtkconv->entry), "attach-start-time", NULL); |
7420 g_object_set_data(G_OBJECT(gtkconv->entry), "attach-start-time", NULL); |
| 7788 purple_signal_emit(pidgin_conversations_get_handle(), |
7421 purple_signal_emit(pidgin_conversations_get_handle(), |