| 159 static void update_typing_message(PidginConversation *gtkconv, const char *message); |
159 static void update_typing_message(PidginConversation *gtkconv, const char *message); |
| 160 static const char *item_factory_translate_func (const char *path, gpointer func_data); |
160 static const char *item_factory_translate_func (const char *path, gpointer func_data); |
| 161 gboolean pidgin_conv_has_focus(PurpleConversation *conv); |
161 gboolean pidgin_conv_has_focus(PurpleConversation *conv); |
| 162 static GdkColor* generate_nick_colors(guint *numcolors, GdkColor background); |
162 static GdkColor* generate_nick_colors(guint *numcolors, GdkColor background); |
| 163 static gboolean color_is_visible(GdkColor foreground, GdkColor background, int color_contrast, int brightness_contrast); |
163 static gboolean color_is_visible(GdkColor foreground, GdkColor background, int color_contrast, int brightness_contrast); |
| 164 static GtkTextTag *get_buddy_tag(PurpleConversation *conv, const char *who, gboolean create); |
164 static GtkTextTag *get_buddy_tag(PurpleConversation *conv, const char *who, PurpleMessageFlags flag, gboolean create); |
| 165 static void pidgin_conv_update_fields(PurpleConversation *conv, PidginConvFields fields); |
165 static void pidgin_conv_update_fields(PurpleConversation *conv, PidginConvFields fields); |
| 166 static void focus_out_from_menubar(GtkWidget *wid, PidginWindow *win); |
166 static void focus_out_from_menubar(GtkWidget *wid, PidginWindow *win); |
| 167 static void pidgin_conv_tab_pack(PidginWindow *win, PidginConversation *gtkconv); |
167 static void pidgin_conv_tab_pack(PidginWindow *win, PidginConversation *gtkconv); |
| 168 static gboolean infopane_press_cb(GtkWidget *widget, GdkEventButton *e, PidginConversation *conv); |
168 static gboolean infopane_press_cb(GtkWidget *widget, GdkEventButton *e, PidginConversation *conv); |
| 169 static void hide_conv(PidginConversation *gtkconv, gboolean closetimer); |
169 static void hide_conv(PidginConversation *gtkconv, gboolean closetimer); |
| 170 |
170 |
| 171 static void pidgin_conv_set_position_size(PidginWindow *win, int x, int y, |
171 static void pidgin_conv_set_position_size(PidginWindow *win, int x, int y, |
| 172 int width, int height); |
172 int width, int height); |
| 173 static gboolean pidgin_conv_xy_to_right_infopane(PidginWindow *win, int x, int y); |
173 static gboolean pidgin_conv_xy_to_right_infopane(PidginWindow *win, int x, int y); |
| 174 |
174 |
| 175 static const GdkColor *get_nick_color(PidginConversation *gtkconv, const char *name) { |
175 static const GdkColor *get_nick_color(PidginConversation *gtkconv, const char *name) |
| |
176 { |
| 176 static GdkColor col; |
177 static GdkColor col; |
| 177 GtkStyle *style = gtk_widget_get_style(gtkconv->imhtml); |
178 GtkStyle *style = gtk_widget_get_style(gtkconv->imhtml); |
| 178 float scale; |
179 float scale; |
| 179 |
180 |
| 180 col = nick_colors[g_str_hash(name) % nbr_nick_colors]; |
181 col = nick_colors[g_str_hash(name) % nbr_nick_colors]; |
| 1908 if (most_active != NULL && most_active != gtkconv) |
1909 if (most_active != NULL && most_active != gtkconv) |
| 1909 pidgin_conv_window_switch_gtkconv(win, most_active); |
1910 pidgin_conv_window_switch_gtkconv(win, most_active); |
| 1910 } |
1911 } |
| 1911 |
1912 |
| 1912 static gboolean |
1913 static gboolean |
| |
1914 gtkconv_cycle_focus(PidginConversation *gtkconv, GtkDirectionType dir) |
| |
1915 { |
| |
1916 PurpleConversation *conv = gtkconv->active_conv; |
| |
1917 gboolean chat = purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT; |
| |
1918 GtkWidget *next = NULL; |
| |
1919 struct { |
| |
1920 GtkWidget *from; |
| |
1921 GtkWidget *to; |
| |
1922 } transitions[] = { |
| |
1923 {gtkconv->entry, gtkconv->imhtml}, |
| |
1924 {gtkconv->imhtml, chat ? gtkconv->u.chat->list : gtkconv->entry}, |
| |
1925 {chat ? gtkconv->u.chat->list : NULL, gtkconv->entry}, |
| |
1926 {NULL, NULL} |
| |
1927 }, *ptr; |
| |
1928 |
| |
1929 for (ptr = transitions; !next && ptr->from; ptr++) { |
| |
1930 GtkWidget *from, *to; |
| |
1931 if (dir == GTK_DIR_TAB_FORWARD) { |
| |
1932 from = ptr->from; |
| |
1933 to = ptr->to; |
| |
1934 } else { |
| |
1935 from = ptr->to; |
| |
1936 to = ptr->from; |
| |
1937 } |
| |
1938 if (gtk_widget_is_focus(from)) |
| |
1939 next = to; |
| |
1940 } |
| |
1941 |
| |
1942 if (next) |
| |
1943 gtk_widget_grab_focus(next); |
| |
1944 return !!next; |
| |
1945 } |
| |
1946 |
| |
1947 static gboolean |
| 1913 conv_keypress_common(PidginConversation *gtkconv, GdkEventKey *event) |
1948 conv_keypress_common(PidginConversation *gtkconv, GdkEventKey *event) |
| 1914 { |
1949 { |
| 1915 PidginWindow *win; |
1950 PidginWindow *win; |
| 1916 PurpleConversation *conv; |
1951 PurpleConversation *conv; |
| 1917 int curconv; |
1952 int curconv; |
| 4421 |
4463 |
| 4422 g_free(normalized_name); |
4464 g_free(normalized_name); |
| 4423 |
4465 |
| 4424 blist_node_aliased_cb((PurpleBlistNode *)buddy, NULL, conv); |
4466 blist_node_aliased_cb((PurpleBlistNode *)buddy, NULL, conv); |
| 4425 |
4467 |
| 4426 texttag = get_buddy_tag(conv, purple_buddy_get_name(buddy), FALSE); /* XXX: do we want the normalized name? */ |
4468 texttag = get_buddy_tag(conv, purple_buddy_get_name(buddy), 0, FALSE); /* XXX: do we want the normalized name? */ |
| 4427 if (texttag) { |
4469 if (texttag) { |
| 4428 g_object_set(texttag, "weight", is_buddy ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL, NULL); |
4470 g_object_set(texttag, "weight", is_buddy ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL, NULL); |
| 4429 } |
4471 } |
| 4430 } |
4472 } |
| 4431 |
4473 |
| 5341 } |
5383 } |
| 5342 |
5384 |
| 5343 purple_conversation_write(conv, who, message, flags, mtime); |
5385 purple_conversation_write(conv, who, message, flags, mtime); |
| 5344 } |
5386 } |
| 5345 |
5387 |
| |
5388 static const char * |
| |
5389 get_text_tag_color(GtkTextTag *tag) |
| |
5390 { |
| |
5391 GdkColor *color = NULL; |
| |
5392 gboolean set = FALSE; |
| |
5393 static char colcode[] = "#XXXXXX"; |
| |
5394 if (tag) |
| |
5395 g_object_get(G_OBJECT(tag), "foreground-set", &set, "foreground-gdk", &color, NULL); |
| |
5396 if (set && color) |
| |
5397 g_snprintf(colcode, sizeof(colcode), "#%02x%02x%02x", |
| |
5398 color->red >> 8, color->green >> 8, color->blue >> 8); |
| |
5399 else |
| |
5400 colcode[0] = '\0'; |
| |
5401 if (color) |
| |
5402 gdk_color_free(color); |
| |
5403 return colcode; |
| |
5404 } |
| |
5405 |
| 5346 /* The callback for an event on a link tag. */ |
5406 /* The callback for an event on a link tag. */ |
| 5347 static gboolean buddytag_event(GtkTextTag *tag, GObject *imhtml, |
5407 static gboolean buddytag_event(GtkTextTag *tag, GObject *imhtml, |
| 5348 GdkEvent *event, GtkTextIter *arg2, gpointer data) { |
5408 GdkEvent *event, GtkTextIter *arg2, gpointer data) |
| |
5409 { |
| 5349 if (event->type == GDK_BUTTON_PRESS |
5410 if (event->type == GDK_BUTTON_PRESS |
| 5350 || event->type == GDK_2BUTTON_PRESS) { |
5411 || event->type == GDK_2BUTTON_PRESS) { |
| 5351 GdkEventButton *btn_event = (GdkEventButton*) event; |
5412 GdkEventButton *btn_event = (GdkEventButton*) event; |
| 5352 PurpleConversation *conv = data; |
5413 PurpleConversation *conv = data; |
| 5353 char *buddyname; |
5414 char *buddyname; |
| 5354 |
5415 |
| 5355 /* strlen("BUDDY ") == 6 */ |
5416 /* strlen("BUDDY " or "HILIT ") == 6 */ |
| 5356 g_return_val_if_fail((tag->name != NULL) |
5417 g_return_val_if_fail((tag->name != NULL) |
| 5357 && (strlen(tag->name) > 6), FALSE); |
5418 && (strlen(tag->name) > 6), FALSE); |
| 5358 |
5419 |
| 5359 buddyname = (tag->name) + 6; |
5420 buddyname = (tag->name) + 6; |
| 5360 |
5421 |
| 5390 } |
5451 } |
| 5391 |
5452 |
| 5392 return FALSE; |
5453 return FALSE; |
| 5393 } |
5454 } |
| 5394 |
5455 |
| 5395 static GtkTextTag *get_buddy_tag(PurpleConversation *conv, const char *who, gboolean create) |
5456 static GtkTextTag *get_buddy_tag(PurpleConversation *conv, const char *who, PurpleMessageFlags flag, |
| |
5457 gboolean create) |
| 5396 { |
5458 { |
| 5397 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv); |
5459 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv); |
| 5398 GtkTextTag *buddytag; |
5460 GtkTextTag *buddytag; |
| 5399 gchar *str; |
5461 gchar *str; |
| 5400 |
5462 gboolean highlight = (flag & PURPLE_MESSAGE_NICK); |
| 5401 str = g_strdup_printf("BUDDY %s", who); |
5463 GtkTextBuffer *buffer = GTK_IMHTML(gtkconv->imhtml)->text_buffer; |
| |
5464 |
| |
5465 str = g_strdup_printf(highlight ? "HILIT %s" : "BUDDY %s", who); |
| 5402 |
5466 |
| 5403 buddytag = gtk_text_tag_table_lookup( |
5467 buddytag = gtk_text_tag_table_lookup( |
| 5404 gtk_text_buffer_get_tag_table( |
5468 gtk_text_buffer_get_tag_table(buffer), str); |
| 5405 GTK_IMHTML(gtkconv->imhtml)->text_buffer), str); |
|
| 5406 |
5469 |
| 5407 if (buddytag == NULL && create) { |
5470 if (buddytag == NULL && create) { |
| 5408 buddytag = gtk_text_buffer_create_tag( |
5471 if (highlight) |
| 5409 GTK_IMHTML(gtkconv->imhtml)->text_buffer, str, |
5472 buddytag = gtk_text_buffer_create_tag(buffer, str, |
| 5410 "foreground-gdk", get_nick_color(gtkconv, who), |
5473 "foreground", get_text_tag_color(gtk_text_tag_table_lookup( |
| 5411 "weight", purple_find_buddy(purple_conversation_get_account(conv), who) ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL, |
5474 gtk_text_buffer_get_tag_table(buffer), "highlight-name")), |
| 5412 NULL); |
5475 "weight", PANGO_WEIGHT_BOLD, |
| |
5476 NULL); |
| |
5477 else |
| |
5478 buddytag = gtk_text_buffer_create_tag( |
| |
5479 buffer, str, |
| |
5480 "foreground-gdk", get_nick_color(gtkconv, who), |
| |
5481 "weight", purple_find_buddy(purple_conversation_get_account(conv), who) ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL, |
| |
5482 NULL); |
| 5413 |
5483 |
| 5414 g_signal_connect(G_OBJECT(buddytag), "event", |
5484 g_signal_connect(G_OBJECT(buddytag), "event", |
| 5415 G_CALLBACK(buddytag_event), conv); |
5485 G_CALLBACK(buddytag_event), conv); |
| 5416 } |
5486 } |
| 5417 |
5487 |
| 5764 g_snprintf(str, 1024, "%s:", alias_escaped); |
5834 g_snprintf(str, 1024, "%s:", alias_escaped); |
| 5765 tag_end_offset = 1; |
5835 tag_end_offset = 1; |
| 5766 } |
5836 } |
| 5767 |
5837 |
| 5768 if (flags & PURPLE_MESSAGE_NICK) { |
5838 if (flags & PURPLE_MESSAGE_NICK) { |
| 5769 tagname = "highlight-name"; |
5839 if (type == PURPLE_CONV_TYPE_IM) { |
| |
5840 tagname = "highlight-name"; |
| |
5841 } |
| 5770 } else if (flags & PURPLE_MESSAGE_RECV) { |
5842 } else if (flags & PURPLE_MESSAGE_RECV) { |
| 5771 /* The tagname for chats is handled by get_buddy_tag */ |
5843 /* The tagname for chats is handled by get_buddy_tag */ |
| 5772 if (type == PURPLE_CONV_TYPE_IM) { |
5844 if (type == PURPLE_CONV_TYPE_IM) { |
| 5773 tagname = "receive-name"; |
5845 tagname = "receive-name"; |
| 5774 } |
5846 } |
| 5783 g_free(alias_escaped); |
5855 g_free(alias_escaped); |
| 5784 |
5856 |
| 5785 if (tagname) |
5857 if (tagname) |
| 5786 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(buffer), tagname); |
5858 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(buffer), tagname); |
| 5787 else |
5859 else |
| 5788 tag = get_buddy_tag(conv, name, TRUE); |
5860 tag = get_buddy_tag(conv, name, flags, TRUE); |
| 5789 |
5861 |
| 5790 if (GTK_IMHTML(gtkconv->imhtml)->show_comments) { |
5862 if (GTK_IMHTML(gtkconv->imhtml)->show_comments) { |
| 5791 /* The color for the timestamp has to be set in the font-tags, unfortunately. |
5863 /* The color for the timestamp has to be set in the font-tags, unfortunately. |
| 5792 * Applying the nick-tag to timestamps would work, but that can make it |
5864 * Applying the nick-tag to timestamps would work, but that can make it |
| 5793 * bold. I thought applying the "comment" tag again, which has "weight" set |
5865 * bold. I thought applying the "comment" tag again, which has "weight" set |
| 5794 * to PANGO_WEIGHT_NORMAL, would remove the boldness. But it doesn't. So |
5866 * to PANGO_WEIGHT_NORMAL, would remove the boldness. But it doesn't. So |
| 5795 * this will have to do. I don't terribly like it. -- sadrul */ |
5867 * this will have to do. I don't terribly like it. -- sadrul */ |
| 5796 GdkColor *color = NULL; |
5868 const char *color = get_text_tag_color(tag); |
| 5797 gboolean set = FALSE; |
5869 g_snprintf(buf2, BUF_LONG, "<FONT %s%s%s SIZE=\"2\"><!--%s --></FONT>", |
| 5798 char colcode[] = "COLOR=\"#XXXXXX\""; |
5870 color ? "COLOR=\"" : "", color ? color : "", color ? "\"" : "", mdate); |
| 5799 g_object_get(G_OBJECT(tag), "foreground-set", &set, "foreground-gdk", &color, NULL); |
|
| 5800 if (set && color) |
|
| 5801 g_snprintf(colcode, sizeof(colcode), "COLOR=\"#%02x%02x%02x\"", |
|
| 5802 color->red >> 8, color->green >> 8, color->blue >> 8); |
|
| 5803 else |
|
| 5804 colcode[0] = '\0'; |
|
| 5805 g_snprintf(buf2, BUF_LONG, "<FONT %s SIZE=\"2\"><!--%s --></FONT>", colcode, mdate); |
|
| 5806 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf2, gtk_font_options_all | GTK_IMHTML_NO_SCROLL); |
5871 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf2, gtk_font_options_all | GTK_IMHTML_NO_SCROLL); |
| 5807 if (color) |
|
| 5808 gdk_color_free(color); |
|
| 5809 } |
5872 } |
| 5810 |
5873 |
| 5811 gtk_text_buffer_get_end_iter(buffer, &end); |
5874 gtk_text_buffer_get_end_iter(buffer, &end); |
| 5812 mark = gtk_text_buffer_create_mark(buffer, NULL, &end, TRUE); |
5875 mark = gtk_text_buffer_create_mark(buffer, NULL, &end, TRUE); |
| 5813 |
5876 |