comparison pidgin/gtkconv.c @ 26028:bcad7dc4b453

propagate from branch 'im.pidgin.pidgin' (head 633ffe234af48ead3631ae62e23840b4438fcf5f) to branch 'im.pidgin.maiku.vv' (head 5585b8e919d9adb0eb491c714768027e81f1918c)
author Mike Ruprecht <maiku@soc.pidgin.im>
date Thu, 06 Nov 2008 03:20:05 +0000
parents 8bfa1f01f035 8282911d5e17
children adf153852bcf
comparison
equal deleted inserted replaced
26027:94224a5563db 26028:bcad7dc4b453
22 * You should have received a copy of the GNU General Public License 22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software 23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA 24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
25 * 25 *
26 */ 26 */
27 #define _PIDGIN_GTKCONV_C_
28
27 #include "internal.h" 29 #include "internal.h"
28 #include "pidgin.h" 30 #include "pidgin.h"
29 31
30 #ifndef _WIN32 32 #ifndef _WIN32
31 # include <X11/Xlib.h> 33 # include <X11/Xlib.h>
161 static void update_typing_message(PidginConversation *gtkconv, const char *message); 163 static void update_typing_message(PidginConversation *gtkconv, const char *message);
162 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);
163 gboolean pidgin_conv_has_focus(PurpleConversation *conv); 165 gboolean pidgin_conv_has_focus(PurpleConversation *conv);
164 static GdkColor* generate_nick_colors(guint *numcolors, GdkColor background); 166 static GdkColor* generate_nick_colors(guint *numcolors, GdkColor background);
165 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);
166 static GtkTextTag *get_buddy_tag(PurpleConversation *conv, const char *who, gboolean create); 168 static GtkTextTag *get_buddy_tag(PurpleConversation *conv, const char *who, PurpleMessageFlags flag, gboolean create);
167 static void pidgin_conv_update_fields(PurpleConversation *conv, PidginConvFields fields); 169 static void pidgin_conv_update_fields(PurpleConversation *conv, PidginConvFields fields);
168 static void focus_out_from_menubar(GtkWidget *wid, PidginWindow *win); 170 static void focus_out_from_menubar(GtkWidget *wid, PidginWindow *win);
169 static void pidgin_conv_tab_pack(PidginWindow *win, PidginConversation *gtkconv); 171 static void pidgin_conv_tab_pack(PidginWindow *win, PidginConversation *gtkconv);
170 static gboolean infopane_press_cb(GtkWidget *widget, GdkEventButton *e, PidginConversation *conv); 172 static gboolean infopane_press_cb(GtkWidget *widget, GdkEventButton *e, PidginConversation *conv);
171 static void hide_conv(PidginConversation *gtkconv, gboolean closetimer); 173 static void hide_conv(PidginConversation *gtkconv, gboolean closetimer);
172 174
173 static void pidgin_conv_set_position_size(PidginWindow *win, int x, int y, 175 static void pidgin_conv_set_position_size(PidginWindow *win, int x, int y,
174 int width, int height); 176 int width, int height);
175 static gboolean pidgin_conv_xy_to_right_infopane(PidginWindow *win, int x, int y); 177 static gboolean pidgin_conv_xy_to_right_infopane(PidginWindow *win, int x, int y);
176 178
177 static const GdkColor *get_nick_color(PidginConversation *gtkconv, const char *name) { 179 static const GdkColor *get_nick_color(PidginConversation *gtkconv, const char *name)
180 {
178 static GdkColor col; 181 static GdkColor col;
179 GtkStyle *style = gtk_widget_get_style(gtkconv->imhtml); 182 GtkStyle *style = gtk_widget_get_style(gtkconv->imhtml);
180 float scale; 183 float scale;
181 184
182 col = nick_colors[g_str_hash(name) % nbr_nick_colors]; 185 col = nick_colors[g_str_hash(name) % nbr_nick_colors];
1922 if (most_active != NULL && most_active != gtkconv) 1925 if (most_active != NULL && most_active != gtkconv)
1923 pidgin_conv_window_switch_gtkconv(win, most_active); 1926 pidgin_conv_window_switch_gtkconv(win, most_active);
1924 } 1927 }
1925 1928
1926 static gboolean 1929 static gboolean
1930 gtkconv_cycle_focus(PidginConversation *gtkconv, GtkDirectionType dir)
1931 {
1932 PurpleConversation *conv = gtkconv->active_conv;
1933 gboolean chat = purple_conversation_get_type(conv) == PURPLE_CONV_TYPE_CHAT;
1934 GtkWidget *next = NULL;
1935 struct {
1936 GtkWidget *from;
1937 GtkWidget *to;
1938 } transitions[] = {
1939 {gtkconv->entry, gtkconv->imhtml},
1940 {gtkconv->imhtml, chat ? gtkconv->u.chat->list : gtkconv->entry},
1941 {chat ? gtkconv->u.chat->list : NULL, gtkconv->entry},
1942 {NULL, NULL}
1943 }, *ptr;
1944
1945 for (ptr = transitions; !next && ptr->from; ptr++) {
1946 GtkWidget *from, *to;
1947 if (dir == GTK_DIR_TAB_FORWARD) {
1948 from = ptr->from;
1949 to = ptr->to;
1950 } else {
1951 from = ptr->to;
1952 to = ptr->from;
1953 }
1954 if (gtk_widget_is_focus(from))
1955 next = to;
1956 }
1957
1958 if (next)
1959 gtk_widget_grab_focus(next);
1960 return !!next;
1961 }
1962
1963 static gboolean
1927 conv_keypress_common(PidginConversation *gtkconv, GdkEventKey *event) 1964 conv_keypress_common(PidginConversation *gtkconv, GdkEventKey *event)
1928 { 1965 {
1929 PidginWindow *win; 1966 PidginWindow *win;
1930 PurpleConversation *conv; 1967 PurpleConversation *conv;
1931 int curconv; 1968 int curconv;
1982 #else 2019 #else
1983 (curconv + 1) % g_list_length(GTK_NOTEBOOK(win->notebook)->children)); 2020 (curconv + 1) % g_list_length(GTK_NOTEBOOK(win->notebook)->children));
1984 #endif 2021 #endif
1985 return TRUE; 2022 return TRUE;
1986 break; 2023 break;
1987 2024 case GDK_F6:
2025 if (gtkconv_cycle_focus(gtkconv, event->state & GDK_SHIFT_MASK ? GTK_DIR_TAB_BACKWARD : GTK_DIR_TAB_FORWARD))
2026 return TRUE;
2027 break;
1988 } /* End of switch */ 2028 } /* End of switch */
1989 } 2029 }
1990 2030
1991 /* If ALT (or whatever) was held down... */ 2031 /* If ALT (or whatever) was held down... */
1992 else if (event->state & GDK_MOD1_MASK) 2032 else if (event->state & GDK_MOD1_MASK)
2008 case GDK_F2: 2048 case GDK_F2:
2009 if (gtk_widget_is_focus(GTK_WIDGET(win->notebook))) { 2049 if (gtk_widget_is_focus(GTK_WIDGET(win->notebook))) {
2010 infopane_entry_activate(gtkconv); 2050 infopane_entry_activate(gtkconv);
2011 return TRUE; 2051 return TRUE;
2012 } 2052 }
2053 break;
2054 case GDK_F6:
2055 if (gtkconv_cycle_focus(gtkconv, event->state & GDK_SHIFT_MASK ? GTK_DIR_TAB_BACKWARD : GTK_DIR_TAB_FORWARD))
2056 return TRUE;
2013 break; 2057 break;
2014 } 2058 }
2015 } 2059 }
2016 return FALSE; 2060 return FALSE;
2017 } 2061 }
4458 4502
4459 g_free(normalized_name); 4503 g_free(normalized_name);
4460 4504
4461 blist_node_aliased_cb((PurpleBlistNode *)buddy, NULL, conv); 4505 blist_node_aliased_cb((PurpleBlistNode *)buddy, NULL, conv);
4462 4506
4463 texttag = get_buddy_tag(conv, purple_buddy_get_name(buddy), FALSE); /* XXX: do we want the normalized name? */ 4507 texttag = get_buddy_tag(conv, purple_buddy_get_name(buddy), 0, FALSE); /* XXX: do we want the normalized name? */
4464 if (texttag) { 4508 if (texttag) {
4465 g_object_set(texttag, "weight", is_buddy ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL, NULL); 4509 g_object_set(texttag, "weight", is_buddy ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL, NULL);
4466 } 4510 }
4467 } 4511 }
4468 4512
5376 } 5420 }
5377 5421
5378 purple_conversation_write(conv, who, message, flags, mtime); 5422 purple_conversation_write(conv, who, message, flags, mtime);
5379 } 5423 }
5380 5424
5425 static const char *
5426 get_text_tag_color(GtkTextTag *tag)
5427 {
5428 GdkColor *color = NULL;
5429 gboolean set = FALSE;
5430 static char colcode[] = "#XXXXXX";
5431 if (tag)
5432 g_object_get(G_OBJECT(tag), "foreground-set", &set, "foreground-gdk", &color, NULL);
5433 if (set && color)
5434 g_snprintf(colcode, sizeof(colcode), "#%02x%02x%02x",
5435 color->red >> 8, color->green >> 8, color->blue >> 8);
5436 else
5437 colcode[0] = '\0';
5438 if (color)
5439 gdk_color_free(color);
5440 return colcode;
5441 }
5442
5381 /* The callback for an event on a link tag. */ 5443 /* The callback for an event on a link tag. */
5382 static gboolean buddytag_event(GtkTextTag *tag, GObject *imhtml, 5444 static gboolean buddytag_event(GtkTextTag *tag, GObject *imhtml,
5383 GdkEvent *event, GtkTextIter *arg2, gpointer data) { 5445 GdkEvent *event, GtkTextIter *arg2, gpointer data)
5446 {
5384 if (event->type == GDK_BUTTON_PRESS 5447 if (event->type == GDK_BUTTON_PRESS
5385 || event->type == GDK_2BUTTON_PRESS) { 5448 || event->type == GDK_2BUTTON_PRESS) {
5386 GdkEventButton *btn_event = (GdkEventButton*) event; 5449 GdkEventButton *btn_event = (GdkEventButton*) event;
5387 PurpleConversation *conv = data; 5450 PurpleConversation *conv = data;
5388 char *buddyname; 5451 char *buddyname;
5389 5452
5390 /* strlen("BUDDY ") == 6 */ 5453 /* strlen("BUDDY " or "HILIT ") == 6 */
5391 g_return_val_if_fail((tag->name != NULL) 5454 g_return_val_if_fail((tag->name != NULL)
5392 && (strlen(tag->name) > 6), FALSE); 5455 && (strlen(tag->name) > 6), FALSE);
5393 5456
5394 buddyname = (tag->name) + 6; 5457 buddyname = (tag->name) + 6;
5395 5458
5425 } 5488 }
5426 5489
5427 return FALSE; 5490 return FALSE;
5428 } 5491 }
5429 5492
5430 static GtkTextTag *get_buddy_tag(PurpleConversation *conv, const char *who, gboolean create) 5493 static GtkTextTag *get_buddy_tag(PurpleConversation *conv, const char *who, PurpleMessageFlags flag,
5494 gboolean create)
5431 { 5495 {
5432 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv); 5496 PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
5433 GtkTextTag *buddytag; 5497 GtkTextTag *buddytag;
5434 gchar *str; 5498 gchar *str;
5435 5499 gboolean highlight = (flag & PURPLE_MESSAGE_NICK);
5436 str = g_strdup_printf("BUDDY %s", who); 5500 GtkTextBuffer *buffer = GTK_IMHTML(gtkconv->imhtml)->text_buffer;
5501
5502 str = g_strdup_printf(highlight ? "HILIT %s" : "BUDDY %s", who);
5437 5503
5438 buddytag = gtk_text_tag_table_lookup( 5504 buddytag = gtk_text_tag_table_lookup(
5439 gtk_text_buffer_get_tag_table( 5505 gtk_text_buffer_get_tag_table(buffer), str);
5440 GTK_IMHTML(gtkconv->imhtml)->text_buffer), str);
5441 5506
5442 if (buddytag == NULL && create) { 5507 if (buddytag == NULL && create) {
5443 buddytag = gtk_text_buffer_create_tag( 5508 if (highlight)
5444 GTK_IMHTML(gtkconv->imhtml)->text_buffer, str, 5509 buddytag = gtk_text_buffer_create_tag(buffer, str,
5445 "foreground-gdk", get_nick_color(gtkconv, who), 5510 "foreground", get_text_tag_color(gtk_text_tag_table_lookup(
5446 "weight", purple_find_buddy(purple_conversation_get_account(conv), who) ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL, 5511 gtk_text_buffer_get_tag_table(buffer), "highlight-name")),
5447 NULL); 5512 "weight", PANGO_WEIGHT_BOLD,
5513 NULL);
5514 else
5515 buddytag = gtk_text_buffer_create_tag(
5516 buffer, str,
5517 "foreground-gdk", get_nick_color(gtkconv, who),
5518 "weight", purple_find_buddy(purple_conversation_get_account(conv), who) ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL,
5519 NULL);
5448 5520
5449 g_signal_connect(G_OBJECT(buddytag), "event", 5521 g_signal_connect(G_OBJECT(buddytag), "event",
5450 G_CALLBACK(buddytag_event), conv); 5522 G_CALLBACK(buddytag_event), conv);
5451 } 5523 }
5452 5524
5799 g_snprintf(str, 1024, "%s:", alias_escaped); 5871 g_snprintf(str, 1024, "%s:", alias_escaped);
5800 tag_end_offset = 1; 5872 tag_end_offset = 1;
5801 } 5873 }
5802 5874
5803 if (flags & PURPLE_MESSAGE_NICK) { 5875 if (flags & PURPLE_MESSAGE_NICK) {
5804 tagname = "highlight-name"; 5876 if (type == PURPLE_CONV_TYPE_IM) {
5877 tagname = "highlight-name";
5878 }
5805 } else if (flags & PURPLE_MESSAGE_RECV) { 5879 } else if (flags & PURPLE_MESSAGE_RECV) {
5806 /* The tagname for chats is handled by get_buddy_tag */ 5880 /* The tagname for chats is handled by get_buddy_tag */
5807 if (type == PURPLE_CONV_TYPE_IM) { 5881 if (type == PURPLE_CONV_TYPE_IM) {
5808 tagname = "receive-name"; 5882 tagname = "receive-name";
5809 } 5883 }
5818 g_free(alias_escaped); 5892 g_free(alias_escaped);
5819 5893
5820 if (tagname) 5894 if (tagname)
5821 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(buffer), tagname); 5895 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(buffer), tagname);
5822 else 5896 else
5823 tag = get_buddy_tag(conv, name, TRUE); 5897 tag = get_buddy_tag(conv, name, flags, TRUE);
5824 5898
5825 if (GTK_IMHTML(gtkconv->imhtml)->show_comments) { 5899 if (GTK_IMHTML(gtkconv->imhtml)->show_comments) {
5826 /* The color for the timestamp has to be set in the font-tags, unfortunately. 5900 /* The color for the timestamp has to be set in the font-tags, unfortunately.
5827 * Applying the nick-tag to timestamps would work, but that can make it 5901 * Applying the nick-tag to timestamps would work, but that can make it
5828 * bold. I thought applying the "comment" tag again, which has "weight" set 5902 * bold. I thought applying the "comment" tag again, which has "weight" set
5829 * to PANGO_WEIGHT_NORMAL, would remove the boldness. But it doesn't. So 5903 * to PANGO_WEIGHT_NORMAL, would remove the boldness. But it doesn't. So
5830 * this will have to do. I don't terribly like it. -- sadrul */ 5904 * this will have to do. I don't terribly like it. -- sadrul */
5831 GdkColor *color = NULL; 5905 const char *color = get_text_tag_color(tag);
5832 gboolean set = FALSE; 5906 g_snprintf(buf2, BUF_LONG, "<FONT %s%s%s SIZE=\"2\"><!--%s --></FONT>",
5833 char colcode[] = "COLOR=\"#XXXXXX\""; 5907 color ? "COLOR=\"" : "", color ? color : "", color ? "\"" : "", mdate);
5834 g_object_get(G_OBJECT(tag), "foreground-set", &set, "foreground-gdk", &color, NULL);
5835 if (set && color)
5836 g_snprintf(colcode, sizeof(colcode), "COLOR=\"#%02x%02x%02x\"",
5837 color->red >> 8, color->green >> 8, color->blue >> 8);
5838 else
5839 colcode[0] = '\0';
5840 g_snprintf(buf2, BUF_LONG, "<FONT %s SIZE=\"2\"><!--%s --></FONT>", colcode, mdate);
5841 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf2, gtk_font_options_all | GTK_IMHTML_NO_SCROLL); 5908 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf2, gtk_font_options_all | GTK_IMHTML_NO_SCROLL);
5842 if (color)
5843 gdk_color_free(color);
5844 } 5909 }
5845 5910
5846 gtk_text_buffer_get_end_iter(buffer, &end); 5911 gtk_text_buffer_get_end_iter(buffer, &end);
5847 mark = gtk_text_buffer_create_mark(buffer, NULL, &end, TRUE); 5912 mark = gtk_text_buffer_create_mark(buffer, NULL, &end, TRUE);
5848 5913