comparison pidgin/gtkconv.c @ 16083:f2a4b05407d7

Patch from shlomil in ticket #78. This fixes RTL text support in MSN, and lays the framework so it could be supported in other prpls as well. As added pluses, shlomil removed some duplicate code and fixed some small related bugs. committer: Richard Laager <rlaager@wiktel.com>
author Shlomi Loubaton <shlomister@gmail.com>
date Fri, 13 Apr 2007 04:13:24 +0000
parents 07554cc5d090
children a5a831a5f186
comparison
equal deleted inserted replaced
16082:7a7377a86ad1 16083:f2a4b05407d7
4893 tm->tm_mday++; 4893 tm->tm_mday++;
4894 4894
4895 gtkconv->newday = mktime(tm); 4895 gtkconv->newday = mktime(tm);
4896 } 4896 }
4897 4897
4898 /* Detect string direction and encapsulate the string in a RLE/LRE/PDF unicode characters
4899 str - pointer to string (string is realocated and new pointer is returned) */
4900 static void
4901 str_embed_direction_chars(char **str)
4902 {
4903 char pre_str[4];
4904 char post_str[10];
4905 char* ret = g_malloc(strlen(*str)+13);
4906
4907 if (PANGO_DIRECTION_RTL == pango_find_base_dir(*str, strlen(*str)))
4908 {
4909 g_sprintf(pre_str, "%c%c%c",
4910 0xE2, 0x80, 0xAB); /* RLE */
4911 g_sprintf(post_str, "%c%c%c%c%c%c%c%c%c",
4912 0xE2, 0x80, 0xAC, /* PDF */
4913 0xE2, 0x80, 0x8E, /* LRM */
4914 0xE2, 0x80, 0xAC); /* PDF */
4915 }
4916 else
4917 {
4918 g_sprintf(pre_str, "%c%c%c",
4919 0xE2, 0x80, 0xAA); /* LRE */
4920 g_sprintf(post_str, "%c%c%c%c%c%c%c%c%c",
4921 0xE2, 0x80, 0xAC, /* PDF */
4922 0xE2, 0x80, 0x8F, /* RLM */
4923 0xE2, 0x80, 0xAC); /* PDF */
4924 }
4925
4926 g_sprintf(ret, "%s%s%s", pre_str, *str, post_str);
4927
4928 g_free(*str);
4929 *str = ret;
4930 return;
4931 }
4932
4933 /* Returns true if the given HTML contains RTL text */
4934 static gboolean
4935 html_is_rtl(const char *html)
4936 {
4937 GData *attributes;
4938 const gchar *start, *end;
4939 gboolean res = FALSE;
4940
4941 if(purple_markup_find_tag("span", html, &start, &end, &attributes))
4942 {
4943 /* tmp is a member of attributes and is free with g_datalist_clear call */
4944 const char *tmp = g_datalist_get_data(&attributes, "dir");
4945 if(tmp && !g_ascii_strcasecmp(tmp, "RTL"))
4946 res = TRUE;
4947 if(!res)
4948 {
4949 char *tmp2 = NULL;
4950 tmp = g_datalist_get_data(&attributes, "style");
4951 if(tmp)
4952 tmp2 = purple_markup_get_css_property(tmp, "direction");
4953 if(tmp2 && !g_ascii_strcasecmp(tmp2, "RTL"))
4954 res = TRUE;
4955 if(tmp2)
4956 g_free(tmp2);
4957
4958 }
4959 g_datalist_clear(&attributes);
4960 }
4961 return res;
4962 }
4963
4964
4898 static void 4965 static void
4899 pidgin_conv_write_conv(PurpleConversation *conv, const char *name, const char *alias, 4966 pidgin_conv_write_conv(PurpleConversation *conv, const char *name, const char *alias,
4900 const char *message, PurpleMessageFlags flags, 4967 const char *message, PurpleMessageFlags flags,
4901 time_t mtime) 4968 time_t mtime)
4902 { 4969 {
4920 PurpleConversationType type; 4987 PurpleConversationType type;
4921 char *displaying; 4988 char *displaying;
4922 gboolean plugin_return; 4989 gboolean plugin_return;
4923 char *bracket; 4990 char *bracket;
4924 int tag_count = 0; 4991 int tag_count = 0;
4992 gboolean is_rtl_message = FALSE;
4925 4993
4926 g_return_if_fail(conv != NULL); 4994 g_return_if_fail(conv != NULL);
4927 gtkconv = PIDGIN_CONVERSATION(conv); 4995 gtkconv = PIDGIN_CONVERSATION(conv);
4928 g_return_if_fail(gtkconv != NULL); 4996 g_return_if_fail(gtkconv != NULL);
4929 4997
5032 conv, mtime, show_date); 5100 conv, mtime, show_date);
5033 5101
5034 if (mdate == NULL) 5102 if (mdate == NULL)
5035 { 5103 {
5036 struct tm *tm = localtime(&mtime); 5104 struct tm *tm = localtime(&mtime);
5105 const char *tmp;
5037 if (show_date) 5106 if (show_date)
5038 mdate = g_strdup(purple_date_format_long(tm)); 5107 tmp = purple_date_format_long(tm);
5039 else 5108 else
5040 mdate = g_strdup(purple_time_format(tm)); 5109 tmp = purple_time_format(tm);
5041 } 5110 mdate = g_strdup_printf("(%s)", tmp);
5111 }
5112
5113 /* Bi-Directional support - set timestamp direction using unicode characters */
5114 is_rtl_message = html_is_rtl(message);
5115 /* Enforce direction only if message is RTL - donesn't effect LTR users */
5116 if(is_rtl_message)
5117 str_embed_direction_chars(&mdate);
5042 5118
5043 if (mtime >= gtkconv->newday) 5119 if (mtime >= gtkconv->newday)
5044 pidgin_conv_calculate_newday(gtkconv, mtime); 5120 pidgin_conv_calculate_newday(gtkconv, mtime);
5045 5121
5046 sml_attrib = g_strdup_printf("sml=\"%s\"", purple_account_get_protocol_name(account)); 5122 sml_attrib = g_strdup_printf("sml=\"%s\"", purple_account_get_protocol_name(account));
5061 /* TODO: These colors should not be hardcoded so log.c can use them */ 5137 /* TODO: These colors should not be hardcoded so log.c can use them */
5062 if (flags & PURPLE_MESSAGE_RAW) { 5138 if (flags & PURPLE_MESSAGE_RAW) {
5063 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), message, gtk_font_options_all); 5139 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), message, gtk_font_options_all);
5064 } else if (flags & PURPLE_MESSAGE_SYSTEM) { 5140 } else if (flags & PURPLE_MESSAGE_SYSTEM) {
5065 g_snprintf(buf2, sizeof(buf2), 5141 g_snprintf(buf2, sizeof(buf2),
5066 "<FONT %s><FONT SIZE=\"2\"><!--(%s) --></FONT><B>%s</B></FONT>", 5142 "<FONT %s><FONT SIZE=\"2\"><!--%s --></FONT><B>%s</B></FONT>",
5067 sml_attrib ? sml_attrib : "", mdate, displaying); 5143 sml_attrib ? sml_attrib : "", mdate, displaying);
5068 5144
5069 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf2, gtk_font_options_all); 5145 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf2, gtk_font_options_all);
5070 5146
5071 } else if (flags & PURPLE_MESSAGE_ERROR) { 5147 } else if (flags & PURPLE_MESSAGE_ERROR) {
5072 g_snprintf(buf2, sizeof(buf2), 5148 g_snprintf(buf2, sizeof(buf2),
5073 "<FONT COLOR=\"#ff0000\"><FONT %s><FONT SIZE=\"2\"><!--(%s) --></FONT><B>%s</B></FONT></FONT>", 5149 "<FONT COLOR=\"#ff0000\"><FONT %s><FONT SIZE=\"2\"><!--%s --></FONT><B>%s</B></FONT></FONT>",
5074 sml_attrib ? sml_attrib : "", mdate, displaying); 5150 sml_attrib ? sml_attrib : "", mdate, displaying);
5075 5151
5076 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf2, gtk_font_options_all); 5152 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf2, gtk_font_options_all);
5077 5153
5078 } else if (flags & PURPLE_MESSAGE_NO_LOG) { 5154 } else if (flags & PURPLE_MESSAGE_NO_LOG) {
5088 * escaped entities making the string longer */ 5164 * escaped entities making the string longer */
5089 int tag_start_offset = alias ? (strlen(alias_escaped) - strlen(alias)) : 0; 5165 int tag_start_offset = alias ? (strlen(alias_escaped) - strlen(alias)) : 0;
5090 int tag_end_offset = 0; 5166 int tag_end_offset = 0;
5091 GtkSmileyTree *tree = NULL; 5167 GtkSmileyTree *tree = NULL;
5092 GHashTable *smiley_data = NULL; 5168 GHashTable *smiley_data = NULL;
5169
5170 /* Enforce direction on alias */
5171 if(is_rtl_message)
5172 str_embed_direction_chars(&alias_escaped);
5093 5173
5094 if (flags & PURPLE_MESSAGE_SEND) 5174 if (flags & PURPLE_MESSAGE_SEND)
5095 { 5175 {
5096 /* Temporarily revert to the original smiley-data to avoid showing up 5176 /* Temporarily revert to the original smiley-data to avoid showing up
5097 * custom smileys of the buddy when sending message 5177 * custom smileys of the buddy when sending message
5176 /* Bold buddies to make them stand out from non-buddies. */ 5256 /* Bold buddies to make them stand out from non-buddies. */
5177 if (flags & PURPLE_MESSAGE_SEND || 5257 if (flags & PURPLE_MESSAGE_SEND ||
5178 flags & PURPLE_MESSAGE_NICK || 5258 flags & PURPLE_MESSAGE_NICK ||
5179 purple_find_buddy(account, name) != NULL) { 5259 purple_find_buddy(account, name) != NULL) {
5180 g_snprintf(buf2, BUF_LONG, 5260 g_snprintf(buf2, BUF_LONG,
5181 "<FONT COLOR=\"%s\" %s><FONT SIZE=\"2\"><!--(%s) --></FONT>" 5261 "<FONT COLOR=\"%s\" %s><FONT SIZE=\"2\"><!--%s --></FONT>"
5182 "<B>%s</B></FONT> ", 5262 "<B>%s</B></FONT> ",
5183 color, sml_attrib ? sml_attrib : "", mdate, str); 5263 color, sml_attrib ? sml_attrib : "", mdate, str);
5184 } else { 5264 } else {
5185 g_snprintf(buf2, BUF_LONG, 5265 g_snprintf(buf2, BUF_LONG,
5186 "<FONT COLOR=\"%s\" %s><FONT SIZE=\"2\"><!--(%s) --></FONT>" 5266 "<FONT COLOR=\"%s\" %s><FONT SIZE=\"2\"><!--%s --></FONT>"
5187 "%s</FONT> ", 5267 "%s</FONT> ",
5188 color, sml_attrib ? sml_attrib : "", mdate, str); 5268 color, sml_attrib ? sml_attrib : "", mdate, str);
5189 5269
5190 } 5270 }
5191 } else { 5271 } else {
5192 /* Bold everyone's name to make the name stand out from the message. */ 5272 /* Bold everyone's name to make the name stand out from the message. */
5193 g_snprintf(buf2, BUF_LONG, 5273 g_snprintf(buf2, BUF_LONG,
5194 "<FONT COLOR=\"%s\" %s><FONT SIZE=\"2\"><!--(%s) --></FONT>" 5274 "<FONT COLOR=\"%s\" %s><FONT SIZE=\"2\"><!--%s --></FONT>"
5195 "<B>%s</B></FONT> ", 5275 "<B>%s</B></FONT> ",
5196 color, sml_attrib ? sml_attrib : "", mdate, str); 5276 color, sml_attrib ? sml_attrib : "", mdate, str);
5197 } 5277 }
5198 5278
5199 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf2, gtk_font_options_all); 5279 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf2, gtk_font_options_all);