| 148 |
148 |
| 149 /* From http://www.w3.org/TR/AERT#color-contrast */ |
149 /* From http://www.w3.org/TR/AERT#color-contrast */ |
| 150 #define MIN_BRIGHTNESS_CONTRAST 75 |
150 #define MIN_BRIGHTNESS_CONTRAST 75 |
| 151 #define MIN_COLOR_CONTRAST 200 |
151 #define MIN_COLOR_CONTRAST 200 |
| 152 |
152 |
| 153 #define NUM_NICK_COLORS 220 |
153 #define NICK_COLOR_GENERATE_COUNT 220 |
| 154 static GdkColor *nick_colors = NULL; |
154 static GArray *generated_nick_colors = NULL; |
| 155 static guint nbr_nick_colors; |
|
| 156 |
155 |
| 157 /* These probably won't conflict with any WebKit values. */ |
156 /* These probably won't conflict with any WebKit values. */ |
| 158 #define PIDGIN_DRAG_BLIST_NODE (1337) |
157 #define PIDGIN_DRAG_BLIST_NODE (1337) |
| 159 #define PIDGIN_DRAG_IM_CONTACT (31337) |
158 #define PIDGIN_DRAG_IM_CONTACT (31337) |
| 160 |
159 |
| 206 static void conv_set_unseen(PurpleConversation *gtkconv, PidginUnseenState state); |
205 static void conv_set_unseen(PurpleConversation *gtkconv, PidginUnseenState state); |
| 207 static void gtkconv_set_unseen(PidginConversation *gtkconv, PidginUnseenState state); |
206 static void gtkconv_set_unseen(PidginConversation *gtkconv, PidginUnseenState state); |
| 208 static void update_typing_icon(PidginConversation *gtkconv); |
207 static void update_typing_icon(PidginConversation *gtkconv); |
| 209 static void update_typing_message(PidginConversation *gtkconv, const char *message); |
208 static void update_typing_message(PidginConversation *gtkconv, const char *message); |
| 210 gboolean pidgin_conv_has_focus(PurpleConversation *conv); |
209 gboolean pidgin_conv_has_focus(PurpleConversation *conv); |
| 211 static GdkColor* generate_nick_colors(guint *numcolors, GdkColor background); |
210 static GArray* generate_nick_colors(guint numcolors, GdkColor background); |
| 212 static gboolean color_is_visible(GdkColor foreground, GdkColor background, int color_contrast, int brightness_contrast); |
211 static gboolean color_is_visible(GdkColor foreground, GdkColor background, int color_contrast, int brightness_contrast); |
| 213 static GtkTextTag *get_buddy_tag(PurpleConversation *conv, const char *who, PurpleMessageFlags flag, gboolean create); |
212 static GtkTextTag *get_buddy_tag(PurpleConversation *conv, const char *who, PurpleMessageFlags flag, gboolean create); |
| 214 static void pidgin_conv_update_fields(PurpleConversation *conv, PidginConvFields fields); |
213 static void pidgin_conv_update_fields(PurpleConversation *conv, PidginConvFields fields); |
| 215 static void focus_out_from_menubar(GtkWidget *wid, PidginWindow *win); |
214 static void focus_out_from_menubar(GtkWidget *wid, PidginWindow *win); |
| 216 static void pidgin_conv_tab_pack(PidginWindow *win, PidginConversation *gtkconv); |
215 static void pidgin_conv_tab_pack(PidginWindow *win, PidginConversation *gtkconv); |
| 225 { |
224 { |
| 226 static GdkColor col; |
225 static GdkColor col; |
| 227 GtkStyle *style = gtk_widget_get_style(gtkconv->webview); |
226 GtkStyle *style = gtk_widget_get_style(gtkconv->webview); |
| 228 float scale; |
227 float scale; |
| 229 |
228 |
| 230 col = nick_colors[g_str_hash(name) % nbr_nick_colors]; |
229 col = g_array_index(gtkconv->nick_colors, GdkColor, g_str_hash(name) % gtkconv->nick_colors->len); |
| 231 scale = ((1-(LUMINANCE(style->base[GTK_STATE_NORMAL]) / LUMINANCE(style->white))) * |
230 scale = ((1-(LUMINANCE(style->base[GTK_STATE_NORMAL]) / LUMINANCE(style->white))) * |
| 232 (LUMINANCE(style->white)/MAX(MAX(col.red, col.blue), col.green))); |
231 (LUMINANCE(style->white)/MAX(MAX(col.red, col.blue), col.green))); |
| 233 |
232 |
| 234 /* The colors are chosen to look fine on white; we should never have to darken */ |
233 /* The colors are chosen to look fine on white; we should never have to darken */ |
| 235 if (scale > 1) { |
234 if (scale > 1) { |
| 5788 if (!theme) |
5787 if (!theme) |
| 5789 theme = default_conv_theme; |
5788 theme = default_conv_theme; |
| 5790 gtkconv->theme = PIDGIN_CONV_THEME(g_object_ref(theme)); |
5789 gtkconv->theme = PIDGIN_CONV_THEME(g_object_ref(theme)); |
| 5791 gtkconv->last_flags = 0; |
5790 gtkconv->last_flags = 0; |
| 5792 |
5791 |
| |
5792 |
| 5793 if (conv_type == PURPLE_CONV_TYPE_IM) { |
5793 if (conv_type == PURPLE_CONV_TYPE_IM) { |
| 5794 gtkconv->u.im = g_malloc0(sizeof(PidginImPane)); |
5794 gtkconv->u.im = g_malloc0(sizeof(PidginImPane)); |
| 5795 } else if (conv_type == PURPLE_CONV_TYPE_CHAT) { |
5795 } else if (conv_type == PURPLE_CONV_TYPE_CHAT) { |
| 5796 gtkconv->u.chat = g_malloc0(sizeof(PidginChatPane)); |
5796 gtkconv->u.chat = g_malloc0(sizeof(PidginChatPane)); |
| 5797 } |
5797 } |
| 5885 if (hidden) |
5885 if (hidden) |
| 5886 pidgin_conv_window_add_gtkconv(hidden_convwin, gtkconv); |
5886 pidgin_conv_window_add_gtkconv(hidden_convwin, gtkconv); |
| 5887 else |
5887 else |
| 5888 pidgin_conv_placement_place(gtkconv); |
5888 pidgin_conv_placement_place(gtkconv); |
| 5889 |
5889 |
| 5890 if (nick_colors == NULL) { |
5890 if (generated_nick_colors == NULL) { |
| 5891 nbr_nick_colors = NUM_NICK_COLORS; |
5891 generated_nick_colors = generate_nick_colors(NICK_COLOR_GENERATE_COUNT, gtk_widget_get_style(gtkconv->webview)->base[GTK_STATE_NORMAL]); |
| 5892 nick_colors = generate_nick_colors(&nbr_nick_colors, gtk_widget_get_style(gtkconv->webview)->base[GTK_STATE_NORMAL]); |
5892 } |
| |
5893 |
| |
5894 if(NULL == (gtkconv->nick_colors = pidgin_conversation_theme_get_nick_colors(gtkconv->theme))) |
| |
5895 { |
| |
5896 gtkconv->nick_colors = g_array_ref(generated_nick_colors); |
| 5893 } |
5897 } |
| 5894 |
5898 |
| 5895 if (purple_conversation_get_features(conv) & PURPLE_CONNECTION_ALLOW_CUSTOM_SMILEY) |
5899 if (purple_conversation_get_features(conv) & PURPLE_CONNECTION_ALLOW_CUSTOM_SMILEY) |
| 5896 pidgin_themes_smiley_themeize_custom(gtkconv->entry); |
5900 pidgin_themes_smiley_themeize_custom(gtkconv->entry); |
| 5897 } |
5901 } |
| 6002 g_list_free(gtkconv->send_history); |
6006 g_list_free(gtkconv->send_history); |
| 6003 |
6007 |
| 6004 if (gtkconv->attach.timer) { |
6008 if (gtkconv->attach.timer) { |
| 6005 g_source_remove(gtkconv->attach.timer); |
6009 g_source_remove(gtkconv->attach.timer); |
| 6006 } |
6010 } |
| |
6011 |
| |
6012 g_array_unref(gtkconv->nick_colors); |
| 6007 |
6013 |
| 6008 g_object_disconnect(G_OBJECT(gtkconv->theme), "any_signal::notify", |
6014 g_object_disconnect(G_OBJECT(gtkconv->theme), "any_signal::notify", |
| 6009 conv_variant_changed_cb, gtkconv, NULL); |
6015 conv_variant_changed_cb, gtkconv, NULL); |
| 6010 g_object_unref(gtkconv->theme); |
6016 g_object_unref(gtkconv->theme); |
| 6011 |
6017 |
| 6312 } else if (g_str_has_prefix(cur, "%senderScreenName%")) { |
6318 } else if (g_str_has_prefix(cur, "%senderScreenName%")) { |
| 6313 replace = name; |
6319 replace = name; |
| 6314 |
6320 |
| 6315 } else if (g_str_has_prefix(cur, "%sender%")) { |
6321 } else if (g_str_has_prefix(cur, "%sender%")) { |
| 6316 replace = alias; |
6322 replace = alias; |
| |
6323 |
| |
6324 } else if (g_str_has_prefix(cur, "%senderColor%")) { |
| |
6325 const GdkColor *color = get_nick_color(PIDGIN_CONVERSATION(conv), name); |
| |
6326 replace = freeval = g_strdup_printf("#%02x%02x%02x", (color->red >> 8), (color->green >> 8), (color->blue >> 8)); |
| 6317 |
6327 |
| 6318 } else if (g_str_has_prefix(cur, "%service%")) { |
6328 } else if (g_str_has_prefix(cur, "%service%")) { |
| 6319 replace = purple_account_get_protocol_name(purple_conversation_get_account(conv)); |
6329 replace = purple_account_get_protocol_name(purple_conversation_get_account(conv)); |
| 6320 |
6330 |
| 6321 } else if (g_str_has_prefix(cur, "%messageDirection%")) { |
6331 } else if (g_str_has_prefix(cur, "%messageDirection%")) { |
| 7402 } |
7412 } |
| 7403 } else if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) { |
7413 } else if (purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT) { |
| 7404 const char *topic = gtkconv->u.chat->topic_text |
7414 const char *topic = gtkconv->u.chat->topic_text |
| 7405 ? gtk_entry_get_text(GTK_ENTRY(gtkconv->u.chat->topic_text)) |
7415 ? gtk_entry_get_text(GTK_ENTRY(gtkconv->u.chat->topic_text)) |
| 7406 : NULL; |
7416 : NULL; |
| 7407 char *esc = NULL, *tmp; |
7417 const char *title = purple_conversation_get_title(conv); |
| 7408 esc = topic ? g_markup_escape_text(topic, -1) : NULL; |
7418 const char *name = purple_conversation_get_name(conv); |
| 7409 tmp = g_markup_escape_text(purple_conversation_get_title(conv), -1); |
7419 |
| 7410 markup = g_strdup_printf("%s%s<span color='%s' size='smaller'>%s</span>", |
7420 char *topic_esc, *unaliased, *unaliased_esc, *title_esc; |
| 7411 tmp, esc && *esc ? "\n" : "", |
7421 |
| |
7422 topic_esc = topic ? g_markup_escape_text(topic, -1) : NULL; |
| |
7423 unaliased = g_utf8_collate(title, name) ? g_strdup_printf("(%s)", name) : NULL; |
| |
7424 unaliased_esc = unaliased ? g_markup_escape_text(unaliased, -1) : NULL; |
| |
7425 title_esc = g_markup_escape_text(title, -1); |
| |
7426 |
| |
7427 markup = g_strdup_printf("%s%s<span size='smaller'>%s</span>%s<span color='%s' size='smaller'>%s</span>", |
| |
7428 title_esc, |
| |
7429 unaliased_esc ? " " : "", |
| |
7430 unaliased_esc ? unaliased_esc : "", |
| |
7431 topic_esc && *topic_esc ? "\n" : "", |
| 7412 pidgin_get_dim_grey_string(gtkconv->infopane), |
7432 pidgin_get_dim_grey_string(gtkconv->infopane), |
| 7413 esc ? esc : ""); |
7433 topic_esc ? topic_esc : ""); |
| 7414 g_free(tmp); |
7434 |
| 7415 g_free(esc); |
7435 g_free(title_esc); |
| |
7436 g_free(topic_esc); |
| |
7437 g_free(unaliased); |
| |
7438 g_free(unaliased_esc); |
| 7416 } |
7439 } |
| 7417 gtk_list_store_set(gtkconv->infopane_model, &(gtkconv->infopane_iter), |
7440 gtk_list_store_set(gtkconv->infopane_model, &(gtkconv->infopane_iter), |
| 7418 CONV_TEXT_COLUMN, markup, -1); |
7441 CONV_TEXT_COLUMN, markup, -1); |
| 7419 /* XXX seanegan Why do I have to do this? */ |
7442 /* XXX seanegan Why do I have to do this? */ |
| 7420 gtk_widget_queue_draw(gtkconv->infopane); |
7443 gtk_widget_queue_draw(gtkconv->infopane); |
| 10091 } |
10114 } |
| 10092 |
10115 |
| 10093 void |
10116 void |
| 10094 pidgin_conv_window_destroy(PidginWindow *win) |
10117 pidgin_conv_window_destroy(PidginWindow *win) |
| 10095 { |
10118 { |
| 10096 PidginConversation *gtkconv; |
|
| 10097 GList *iter; |
|
| 10098 |
|
| 10099 if (win->gtkconvs) { |
10119 if (win->gtkconvs) { |
| 10100 for (iter = win->gtkconvs; iter != NULL; iter = iter->next) { |
10120 GList *iter = win->gtkconvs; |
| 10101 gtkconv = iter->data; |
10121 while (iter) |
| |
10122 { |
| |
10123 PidginConversation *gtkconv = iter->data; |
| |
10124 iter = iter->next; |
| 10102 close_conv_cb(NULL, gtkconv); |
10125 close_conv_cb(NULL, gtkconv); |
| 10103 } |
10126 } |
| 10104 return; |
10127 return; |
| 10105 } |
10128 } |
| 10106 |
10129 |
| 10936 |
10959 |
| 10937 return ((col_diff > color_contrast) && (br_diff > brightness_contrast)); |
10960 return ((col_diff > color_contrast) && (br_diff > brightness_contrast)); |
| 10938 } |
10961 } |
| 10939 |
10962 |
| 10940 |
10963 |
| 10941 static GdkColor* |
10964 static GArray* |
| 10942 generate_nick_colors(guint *color_count, GdkColor background) |
10965 generate_nick_colors(guint numcolors, GdkColor background) |
| 10943 { |
10966 { |
| 10944 guint numcolors = *color_count; |
|
| 10945 guint i = 0, j = 0; |
10967 guint i = 0, j = 0; |
| 10946 GdkColor *colors = g_new(GdkColor, numcolors); |
10968 GArray *colors = g_array_new(FALSE, FALSE, sizeof(GdkColor)); |
| 10947 GdkColor nick_highlight; |
10969 GdkColor nick_highlight; |
| 10948 GdkColor send_color; |
10970 GdkColor send_color; |
| 10949 time_t breakout_time; |
10971 time_t breakout_time; |
| 10950 |
10972 |
| 10951 gdk_color_parse(DEFAULT_HIGHLIGHT_COLOR, &nick_highlight); |
10973 gdk_color_parse(DEFAULT_HIGHLIGHT_COLOR, &nick_highlight); |
| 10965 |
10987 |
| 10966 if (color_is_visible(color, background, MIN_COLOR_CONTRAST, MIN_BRIGHTNESS_CONTRAST) && |
10988 if (color_is_visible(color, background, MIN_COLOR_CONTRAST, MIN_BRIGHTNESS_CONTRAST) && |
| 10967 color_is_visible(color, nick_highlight, MIN_COLOR_CONTRAST / 2, 0) && |
10989 color_is_visible(color, nick_highlight, MIN_COLOR_CONTRAST / 2, 0) && |
| 10968 color_is_visible(color, send_color, MIN_COLOR_CONTRAST / 4, 0)) |
10990 color_is_visible(color, send_color, MIN_COLOR_CONTRAST / 4, 0)) |
| 10969 { |
10991 { |
| 10970 colors[i] = color; |
10992 g_array_append_val(colors, color); |
| 10971 i++; |
10993 i++; |
| 10972 } |
10994 } |
| 10973 j++; |
10995 j++; |
| 10974 } |
10996 } |
| 10975 |
10997 |
| 10984 |
11006 |
| 10985 if (color_is_visible(color, background, MIN_COLOR_CONTRAST, MIN_BRIGHTNESS_CONTRAST) && |
11007 if (color_is_visible(color, background, MIN_COLOR_CONTRAST, MIN_BRIGHTNESS_CONTRAST) && |
| 10986 color_is_visible(color, nick_highlight, MIN_COLOR_CONTRAST / 2, 0) && |
11008 color_is_visible(color, nick_highlight, MIN_COLOR_CONTRAST / 2, 0) && |
| 10987 color_is_visible(color, send_color, MIN_COLOR_CONTRAST / 4, 0)) |
11009 color_is_visible(color, send_color, MIN_COLOR_CONTRAST / 4, 0)) |
| 10988 { |
11010 { |
| 10989 colors[i] = color; |
11011 g_array_append_val(colors, color); |
| 10990 i++; |
11012 i++; |
| 10991 } |
11013 } |
| 10992 } |
11014 } |
| 10993 |
11015 |
| 10994 if (i < numcolors) { |
11016 if (i < numcolors) { |
| 10995 GdkColor *c = colors; |
|
| 10996 purple_debug_warning("gtkconv", "Unable to generate enough random colors before timeout. %u colors found.\n", i); |
11017 purple_debug_warning("gtkconv", "Unable to generate enough random colors before timeout. %u colors found.\n", i); |
| 10997 colors = g_memdup(c, i * sizeof(GdkColor)); |
|
| 10998 g_free(c); |
|
| 10999 *color_count = i; |
|
| 11000 } |
11018 } |
| 11001 |
11019 |
| 11002 return colors; |
11020 return colors; |
| 11003 } |
11021 } |