From: Rob F. <rob...@us...> - 2002-03-02 04:52:25
|
Update of /cvsroot/gaim/gaim/src In directory usw-pr-cvs1:/tmp/cvs-serv16032/src Modified Files: about.c aim.c buddy.c conversation.c core.h dialogs.c gaim.h gtkimhtml.c gtkimhtml.h module.c prefs.c prpl.h server.c ui.h Log Message: 0.53 :) Index: about.c =================================================================== RCS file: /cvsroot/gaim/gaim/src/about.c,v retrieving revision 1.63 retrieving revision 1.64 diff -u -d -r1.63 -r1.64 --- about.c 2 Feb 2002 23:57:15 -0000 1.63 +++ about.c 2 Mar 2002 04:52:20 -0000 1.64 @@ -134,7 +134,7 @@ text = gtk_text_new(NULL, NULL); gtk_text_insert (GTK_TEXT (text), NULL, NULL, NULL, - _("Active Developers\n====================\nRob Flynn (maintainer) [ ro...@ma... ]\nSean Egan (coder) [ bj...@bi... ]\n\nCrazy Patch Writers\n===================\nBenjamin Miller\nDecklin Foster\n\nRetired Developers\n===================\nJim Duchek\nEric Warmenhoven [ war...@ya... ]\nMark Spencer (original author) [ mar...@ma... ]"), 369); + _("Active Developers\n====================\nRob Flynn (maintainer) [ ro...@ma... ]\nSean Egan (coder) [ bj...@bi... ]\n\nCrazy Patch Writers\n===================\nBenjamin Miller\nDecklin Foster\nMark Doliner\n\nRetired Developers\n===================\nJim Duchek\nEric Warmenhoven [ war...@ya... ]\nMark Spencer (original author) [ mar...@ma... ]"), 382); sw = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); Index: aim.c =================================================================== RCS file: /cvsroot/gaim/gaim/src/aim.c,v retrieving revision 1.175 retrieving revision 1.176 diff -u -d -r1.175 -r1.176 --- aim.c 20 Dec 2001 19:51:59 -0000 1.175 +++ aim.c 2 Mar 2002 04:52:20 -0000 1.176 @@ -401,7 +401,7 @@ "and post the backtrace from the core file. If you do not know\n" "how to get the backtrace, please get instructions at\n" WEBSITE "gdb.php. If you need further\n" - "assistance, please IM either EWarmenhoven or RobFlynn and\n" + "assistance, please IM either RobFlynn or SeanEgn and\n" "they can help you.\n"); #endif abort(); Index: buddy.c =================================================================== RCS file: /cvsroot/gaim/gaim/src/buddy.c,v retrieving revision 1.286 retrieving revision 1.287 diff -u -d -r1.286 -r1.287 --- buddy.c 23 Feb 2002 23:41:50 -0000 1.286 +++ buddy.c 2 Mar 2002 04:52:20 -0000 1.287 @@ -714,6 +714,8 @@ show_ee_dialog(3); else if (!g_strcasecmp("markster97", normalize (b->name))) show_ee_dialog(4); + else if (!g_strcasecmp("seanegn", normalize (b->name))) + show_ee_dialog(5); } else { @@ -1486,10 +1488,11 @@ * because I thought it'd be funny :-) */ g_snprintf(tmp, sizeof(tmp), "%s has %s", name, - (b->options & OPT_POUNCE_SIGNON) ? "signed on" : - (b->options & OPT_POUNCE_UNIDLE) ? "returned from being idle" : - "returned from being away"); - + (b->options & OPT_POUNCE_TYPING) ? "started typing to you" : + (b->options & OPT_POUNCE_SIGNON) ? "signed on" : + (b->options & OPT_POUNCE_UNIDLE) ? "returned from being idle" : + "returned from being away"); + do_error_dialog(tmp, _("Buddy Pounce")); } if (b->options & OPT_POUNCE_SEND_IM) { Index: conversation.c =================================================================== RCS file: /cvsroot/gaim/gaim/src/conversation.c,v retrieving revision 1.327 retrieving revision 1.328 diff -u -d -r1.327 -r1.328 --- conversation.c 23 Feb 2002 22:50:43 -0000 1.327 +++ conversation.c 2 Mar 2002 04:52:21 -0000 1.328 @@ -259,6 +259,8 @@ if (c->save_icon) gtk_widget_destroy(c->save_icon); #endif + if (c->typing_timeout) + gtk_timeout_remove(c->typing_timeout); g_string_free(c->history, TRUE); g_free(c); } @@ -629,7 +631,7 @@ cnv = g_list_nth(chats, currpage - convlen); while (cnv) { d = cnv->data; - if (d->unseen) + if (d->unseen > 0) break; cnv = cnv->next; d = NULL; @@ -643,7 +645,7 @@ cnv = g_list_nth(conversations, currpage); while (cnv) { d = cnv->data; - if (d->unseen) + if (d->unseen > 0) break; cnv = cnv->next; d = NULL; @@ -660,7 +662,7 @@ cnv = conversations; while (cnv) { d = cnv->data; - if (d->unseen) + if (d->unseen > 0) break; cnv = cnv->next; d = NULL; @@ -674,7 +676,7 @@ cnv = chats; while (cnv) { d = cnv->data; - if (d->unseen) + if (d->unseen > 0) break; cnv = cnv->next; d = NULL; @@ -691,7 +693,7 @@ cnv = chats; while (cnv) { d = cnv->data; - if (d->unseen) + if (d->unseen > 0) break; cnv = cnv->next; d = NULL; @@ -705,7 +707,7 @@ cnv = conversations; while (cnv) { d = cnv->data; - if (d->unseen) + if (d->unseen > 0) break; cnv = cnv->next; d = NULL; @@ -730,6 +732,7 @@ if (convo_options & OPT_CONVO_ESC_CAN_CLOSE) { gtk_signal_emit_stop_by_name(GTK_OBJECT(entry), "key_press_event"); close_callback(c->close, c); + c = NULL; } } else if (event->keyval == GDK_Page_Up) { gtk_signal_emit_stop_by_name(GTK_OBJECT(entry), "key_press_event"); @@ -896,6 +899,27 @@ gtk_signal_emit_stop_by_name(GTK_OBJECT(entry), "key_press_event"); } + if (c && (!(misc_options & OPT_MISC_STEALTH_TYPING)) && !c->is_chat) { + char *txt = gtk_editable_get_chars(GTK_EDITABLE(c->entry), 0, -1); + if ((strlen(txt) == 0 && event->keyval < 256 && isprint(event->keyval)) || + (c->type_again != 0 && time(NULL) > c->type_again)) { + int timeout = serv_send_typing(c->gc, c->name); + if (timeout) + c->type_again = time(NULL) + timeout; + else + c->type_again = 0; + } + else if (strlen(txt) == 1) { + if ((GTK_OLD_EDITABLE(c->entry)->current_pos == 1 && event->keyval == GDK_BackSpace) || + (GTK_OLD_EDITABLE(c->entry)->current_pos == 0 && event->keyval == GDK_Delete)) + serv_send_typing_stopped(c->gc, c->name); + } else if (GTK_OLD_EDITABLE(c->entry)->selection_start_pos == 0) { + if (GTK_OLD_EDITABLE(c->entry)->selection_end_pos == strlen(txt) && + (event->keyval == GDK_BackSpace || event->keyval == GDK_Delete)) + serv_send_typing_stopped(c->gc, c->name); + } + g_free(txt); + } return FALSE; } @@ -1464,7 +1488,8 @@ GString *logstr; char buf2[BUF_LONG]; char mdate[64]; - + int unhighlight = 0; + if (c->is_chat && (!c->gc || !g_slist_find(c->gc->buddy_chats, c))) return; @@ -1693,12 +1718,16 @@ offs = 0; if (gtk_notebook_get_current_page(GTK_NOTEBOOK(chat_notebook)) == g_list_index(chats, c) + offs) - return; + unhighlight = 1; } else { if (gtk_notebook_get_current_page(GTK_NOTEBOOK(convo_notebook)) == g_list_index(conversations, c)) - return; + unhighlight = 1; } + if ((c->unseen != -1) && unhighlight) /* If there's no typing message + and we're on the same tab, don't bother + changing the color. */ + return; { GtkNotebook *notebook = GTK_NOTEBOOK(c->is_chat ? chat_notebook : convo_notebook); @@ -1715,23 +1744,50 @@ gtk_widget_realize(label); gdk_font_unref(gtk_style_get_font(style)); gtk_style_set_font(style, gdk_font_ref(gtk_style_get_font(label->style))); - if (flags & WFLAG_NICK) { + if (!unhighlight && flags & WFLAG_NICK) { style->fg[0].red = 0x0000; style->fg[0].green = 0x0000; style->fg[0].blue = 0xcccc; c->unseen = 2; - } else { + } else if (!unhighlight) { style->fg[0].red = 0xcccc; style->fg[0].green = 0x0000; style->fg[0].blue = 0x0000; c->unseen = 1; + } else { + c->unseen = 0; } gtk_widget_set_style(label, style); gtk_style_unref(style); } + if (flags & WFLAG_RECV) + reset_typing(g_strdup(c->name)); } +void update_progress(struct conversation *c, float percent) { + while (gtk_events_pending()) + gtk_main_iteration(); + + if (percent >= 1 && !(c->progress)) + return; + if (percent >= 1) { + gtk_widget_destroy(c->progress); + c->progress = NULL; + return; + } + + if (!c->progress) { + GtkBox *box = GTK_BOX(c->text->parent->parent); + c->progress = gtk_progress_bar_new(); + gtk_box_pack_end(box, c->progress, FALSE, FALSE, 0); + gtk_widget_set_usize (c->progress, 1, 8); + gtk_widget_show (c->progress); + } + + if (percent < 1) + gtk_progress_set_percentage(GTK_PROGRESS(c->progress), percent); +} GtkWidget *build_conv_toolbar(struct conversation *c) { @@ -2231,6 +2287,7 @@ gtk_window_set_focus(GTK_WINDOW(c->window), c->entry); if (!GTK_WIDGET_REALIZED(label)) return; + if (c->unseen == -1) return; style = gtk_style_new(); gdk_font_unref(gtk_style_get_font(style)); gtk_style_set_font(style, gdk_font_ref(gtk_style_get_font(label->style))); @@ -2240,6 +2297,95 @@ c->unseen = 0; } +void show_typing(struct conversation *c) { + + GtkStyle *style; + GtkNotebook *notebook = GTK_NOTEBOOK(c->is_chat ? chat_notebook : convo_notebook); + int offs = ((convo_options & OPT_CONVO_COMBINE) && + (im_options & OPT_IM_ONE_WINDOW) && c->is_chat) ? + g_list_length(conversations) : 0; + GList *ws = (c->is_chat ? chats : conversations); + GtkWidget *label = gtk_notebook_get_tab_label(notebook, + gtk_notebook_get_nth_page(notebook, + offs + g_list_index(ws, c))); + if (c->is_chat) /* We shouldn't be getting typing notifications from chats. */ + return; + if (im_options & OPT_IM_ONE_WINDOW) { /* We'll make the tab green */ + + style = gtk_style_new(); + if (!GTK_WIDGET_REALIZED(label)) + gtk_widget_realize(label); + gdk_font_unref(gtk_style_get_font(style)); + gtk_style_set_font(style, gdk_font_ref(gtk_style_get_font(label->style))); + style->fg[0].red = 0x0000; + style->fg[0].green = 0x9999; + style->fg[0].blue = 0x0000; + gtk_widget_set_style(label, style); + debug_printf("setting style\n"); + gtk_style_unref(style); + c->unseen = -1; + } else { + GtkWindow *win = (GtkWindow *)c->window; + char *buf; + if (strstr(win->title, " [TYPING]")) + return; + buf = g_malloc(strlen(win->title) + strlen(" [TYPING]") + 1); + g_snprintf(buf, + strlen(win->title) + strlen(" [TYPING]") + 1, "%s [TYPING]", + win->title); + gtk_window_set_title(win, buf); + g_free(buf); + } + +} + +/* This returns a boolean, so that it can timeout */ +gboolean reset_typing(char *name) { + struct conversation *c = find_conversation(name); + if (!c) { + g_free(name); + return FALSE; + } + /* Reset the title (if necessary) */ + debug_printf("resetting style\n"); + if (c->is_chat) { + g_free(name); + c->typing_timeout = 0; + return FALSE; + } + if (!(im_options & OPT_IM_ONE_WINDOW)) { + GtkWindow *win = (GtkWindow*)c->window; + char *new_title; + if (strstr(win->title, " [TYPING]")) { + new_title = g_malloc(strlen(win->title) - strlen("[TYPING]")); + g_snprintf(new_title, strlen(win->title) - strlen("[TYPING]"), win->title); + gtk_window_set_title(win, new_title); + g_free(new_title); + + } + } else if (c->unseen == -1) { + GtkNotebook *notebook = GTK_NOTEBOOK(convo_notebook); + int offs = ((convo_options & OPT_CONVO_COMBINE) && + (im_options & OPT_IM_ONE_WINDOW) && c->is_chat) ? + g_list_length(conversations) : 0; + GList *ws = (conversations); + GtkWidget *label = gtk_notebook_get_tab_label(notebook, + gtk_notebook_get_nth_page(notebook, + offs + g_list_index(ws, c))); + GtkStyle *style; + style = gtk_style_new(); + if (!GTK_WIDGET_REALIZED(label)) + gtk_widget_realize(label); + gdk_font_unref(gtk_style_get_font(style)); + gtk_style_set_font(style, gdk_font_ref(gtk_style_get_font(label->style))); + c->unseen = 0; + gtk_widget_set_style(label, style); + gtk_style_unref(style); + } + g_free(name); + c->typing_timeout = 0; + return FALSE; +} void show_conv(struct conversation *c) { Index: core.h =================================================================== RCS file: /cvsroot/gaim/gaim/src/core.h,v retrieving revision 1.15 retrieving revision 1.16 diff -u -d -r1.15 -r1.16 --- core.h 1 Jan 2002 09:49:04 -0000 1.15 +++ core.h 2 Mar 2002 04:52:21 -0000 1.16 @@ -84,6 +84,7 @@ event_im_displayed_sent, event_im_displayed_rcvd, event_chat_send_invite, + event_got_typing, /* any others? it's easy to add... */ }; @@ -192,6 +193,8 @@ /* Functions in server.c */ extern void serv_got_update(struct gaim_connection *, char *, int, int, time_t, time_t, int, guint); extern void serv_got_im(struct gaim_connection *, char *, char *, guint32, time_t, gint); +extern void serv_got_typing(struct gaim_connection *, char *, int); +extern void serv_got_typing_stopped(struct gaim_connection *, char *); extern void serv_got_eviled(struct gaim_connection *, char *, int); extern void serv_got_chat_invite(struct gaim_connection *, char *, char *, char *, GList *); extern struct conversation *serv_got_joined_chat(struct gaim_connection *, int, char *); Index: dialogs.c =================================================================== RCS file: /cvsroot/gaim/gaim/src/dialogs.c,v retrieving revision 1.301 retrieving revision 1.302 diff -u -d -r1.301 -r1.302 --- dialogs.c 23 Feb 2002 23:41:50 -0000 1.301 +++ dialogs.c 2 Mar 2002 04:52:21 -0000 1.302 @@ -148,6 +148,7 @@ GtkWidget *p_signon; GtkWidget *p_unaway; GtkWidget *p_unidle; + GtkWidget *p_typing; GtkWidget *save; GtkWidget *menu; GtkWidget *sound; @@ -641,9 +642,10 @@ label = gtk_label_new("You should be me. I'm so cute!"); else if (ee == 3) label = gtk_label_new("Now that's what I like!"); - else + else if (ee == 4) label = gtk_label_new("Ahh, and excellent choice!"); - + else + label = gtk_label_new("Everytime you click my name, an angel gets its wings."); gtk_widget_show(label); gtk_widget_show(ok); @@ -1124,6 +1126,9 @@ if (GTK_TOGGLE_BUTTON(b->p_unidle)->active) bp->options |= OPT_POUNCE_UNIDLE; + + if (GTK_TOGGLE_BUTTON(b->p_typing)->active) + bp->options |= OPT_POUNCE_TYPING; if (GTK_TOGGLE_BUTTON(b->save)->active) bp->options |= OPT_POUNCE_SAVE; @@ -1294,10 +1299,11 @@ (edit_bp->options & OPT_POUNCE_UNIDLE) ? TRUE : FALSE); gtk_table_attach(GTK_TABLE(table), b->p_unidle, 0, 1, 1, 2, GTK_FILL, 0, 0, 0); gtk_widget_show(b->p_unidle); + + b->p_typing = gtk_check_button_new_with_label(_("Pounce when buddy is typing to you")); + gtk_table_attach(GTK_TABLE(table), b->p_typing,1,2,1,2, GTK_FILL | GTK_EXPAND, 0, 0, 0); + gtk_widget_show(b->p_typing); - label = gtk_label_new(NULL); - gtk_table_attach(GTK_TABLE(table), label, 1, 2, 1, 2, GTK_FILL | GTK_EXPAND, 0, 0, 0); - gtk_widget_show(label); /* </pounce type="when"> */ /* <pounce type="action"> */ Index: gaim.h =================================================================== RCS file: /cvsroot/gaim/gaim/src/gaim.h,v retrieving revision 1.307 retrieving revision 1.308 diff -u -d -r1.307 -r1.308 --- gaim.h 23 Feb 2002 23:41:50 -0000 1.307 +++ gaim.h 2 Mar 2002 04:52:21 -0000 1.308 @@ -154,7 +154,7 @@ #define OPT_POUNCE_SIGNON 0x010 #define OPT_POUNCE_UNAWAY 0x020 #define OPT_POUNCE_UNIDLE 0x040 - +#define OPT_POUNCE_TYPING 0x080 #define OPT_POUNCE_SAVE 0x100 #define OPT_POUNCE_NOTIFY 0x200 @@ -184,6 +184,7 @@ #define OPT_MISC_BROWSER_POPUP 0x00000002 #define OPT_MISC_BUDDY_TICKER 0x00000004 #define OPT_MISC_COOL_LOOK 0x00000008 +#define OPT_MISC_STEALTH_TYPING 0x00000010 extern guint logging_options; #define OPT_LOG_ALL 0x00000001 @@ -359,6 +360,8 @@ extern void serv_set_info(struct gaim_connection *, char *); extern void serv_set_away(struct gaim_connection *, char *, char *); extern void serv_set_away_all(char *); +extern int serv_send_typing(struct gaim_connection *, char *); +extern void serv_send_typing_stopped(struct gaim_connection *, char *); extern void serv_change_passwd(struct gaim_connection *, char *, char *); extern void serv_add_buddy(struct gaim_connection *, char *); extern void serv_add_buddies(struct gaim_connection *, GList *); Index: gtkimhtml.c =================================================================== RCS file: /cvsroot/gaim/gaim/src/gtkimhtml.c,v retrieving revision 1.95 retrieving revision 1.96 diff -u -d -r1.95 -r1.96 --- gtkimhtml.c 23 Feb 2002 23:17:43 -0000 1.95 +++ gtkimhtml.c 2 Mar 2002 04:52:21 -0000 1.96 @@ -24,6 +24,7 @@ #endif #include "gtkimhtml.h" #include <X11/Xlib.h> +#include <stdlib.h> #include <gdk/gdkx.h> #include <gtk/gtk.h> #include <string.h> @@ -35,6 +36,11 @@ #include <locale.h> #endif +#if USE_PIXBUF +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gdk-pixbuf/gdk-pixbuf-loader.h> +#endif + #if GTK_CHECK_VERSION(1,3,0) # define GTK_IMHTML_GET_STYLE_FONT(style) gtk_style_get_font (style) #else @@ -248,10 +254,28 @@ imhtml->smiley_data = gtk_smiley_tree_new (); } +#if USE_PIXBUF +struct im_image { + gchar *filename; + + gint len; + gpointer data; + GdkPixbuf *pb; + + gint x,y; + gint width,height; + GtkIMHtml *imhtml; + GtkIMHtmlBit *bit; +}; +#endif + struct _GtkIMHtmlBit { gint type; gchar *text; +#if USE_PIXBUF + struct im_image *img; +#endif GdkPixmap *pm; GdkBitmap *bm; @@ -337,7 +361,11 @@ gdk_color_free (imhtml->default_fg_color); if (imhtml->default_bg_color) gdk_color_free (imhtml->default_bg_color); - + if (imhtml->default_hl_color) + gdk_color_free (imhtml->default_hl_color); + if (imhtml->default_hlfg_color) + gdk_color_free (imhtml->default_hlfg_color); + gdk_cursor_destroy (imhtml->hand_cursor); gdk_cursor_destroy (imhtml->arrow_cursor); @@ -409,6 +437,8 @@ imhtml->default_fg_color = gdk_color_copy (>K_WIDGET (imhtml)->style->fg [GTK_STATE_NORMAL]); imhtml->default_bg_color = gdk_color_copy (>K_WIDGET (imhtml)->style->base [GTK_STATE_NORMAL]); + imhtml->default_hl_color = gdk_color_copy (>K_WIDGET (imhtml)->style->bg [GTK_STATE_SELECTED]); + imhtml->default_hlfg_color=gdk_color_copy (>K_WIDGET (imhtml)->style->fg [GTK_STATE_SELECTED]); gdk_window_show (GTK_LAYOUT (imhtml)->bin_window); } @@ -441,6 +471,7 @@ GdkWindow *window = GTK_LAYOUT (imhtml)->bin_window; gfloat xoff, yoff; GdkColor *bg, *fg; + gchar *start = NULL, *end = NULL; if (GTK_LAYOUT (imhtml)->freeze_count) return; @@ -481,7 +512,6 @@ if (line->selected) { gint width, x; - gchar *start, *end; GdkColor col; if ((line->sel_start > line->sel_end) && (line->sel_end != NULL)) { @@ -498,18 +528,17 @@ x = gdk_text_width (bit->font, line->text, start - line->text); if (end == NULL) - width = gdk_string_width (bit->font, line->text) - x; - else - width = gdk_text_width (bit->font, line->text, end - line->text) - x; - - col.red = col.green = col.blue = 0xc000; - gdk_color_alloc (cmap, &col); - gdk_gc_set_foreground (gc, &col); + end = strchr(line->text, '\0'); + + width = gdk_text_width (bit->font, line->text, end - line->text) - x; + gdk_gc_set_foreground (gc, imhtml->default_hl_color); + gdk_draw_rectangle (window, gc, TRUE, x + line->x - xoff, line->y - yoff, width, line->height); + gdk_gc_set_foreground (gc, imhtml->default_hlfg_color); + fg = gdk_color_copy(imhtml->default_hlfg_color); } - if (bit->url) { GdkColor *tc = gtk_imhtml_get_color ("#0000a0"); gdk_color_alloc (cmap, tc); @@ -530,19 +559,60 @@ gdk_color_alloc (cmap, fg); gdk_gc_set_foreground (gc, fg); } + + if (start) { + int offset = 0; + gdk_draw_text (window, bit->font, gc, line->x - xoff, + line->y - yoff + line->ascent, line->text, start - line->text); + offset = gdk_text_width(bit->font, line->text, start - line->text); + if (bit->underline || bit->url) + gdk_draw_rectangle (window, gc, TRUE, line->x - xoff, + line->y - yoff + line->ascent + 1, + offset, 1); + if (bit->strike) + gdk_draw_rectangle (window, gc, TRUE, line->x - xoff, + line->y - yoff + line->ascent - (bit->font->ascent / 2), + offset, 1); + gdk_gc_set_foreground (gc, imhtml->default_hlfg_color); + gdk_draw_text (window, bit->font, gc, line->x - xoff + offset, + line->y - yoff + line->ascent, start, end - start); + if (bit->underline || bit->url) + gdk_draw_rectangle (window, gc, TRUE, line->x - xoff + offset, + line->y - yoff + line->ascent + 1, + gdk_text_width(bit->font, line->text, end - start), 1); + if (bit->strike) + gdk_draw_rectangle (window, gc, TRUE, line->x - xoff + offset, + line->y - yoff + line->ascent - (bit->font->ascent / 2), + gdk_text_width(bit->font, line->text, end - start), 1); + offset = gdk_text_width(bit->font, line->text, end - line->text); + gdk_gc_set_foreground (gc, fg); + gdk_draw_string (window, bit->font, gc, line->x - xoff + offset, + line->y - yoff + line->ascent, end); + if (bit->underline || bit->url) + gdk_draw_rectangle (window, gc, TRUE, line->x - xoff + offset, + line->y - yoff + line->ascent + 1, + gdk_string_width(bit->font, end), 1); + if (bit->strike) + gdk_draw_rectangle (window, gc, TRUE, line->x - xoff + offset, + line->y - yoff + line->ascent - (bit->font->ascent / 2), + gdk_string_width(bit->font, end), 1); + } else { + gdk_draw_string (window, bit->font, gc, line->x - xoff, + line->y - yoff + line->ascent, line->text); + + if (bit->underline || bit->url) + gdk_draw_rectangle (window, gc, TRUE, line->x - xoff, line->y - yoff + line->ascent + 1, + gdk_string_width (bit->font, line->text), 1); + if (bit->strike) + gdk_draw_rectangle (window, gc, TRUE, line->x - xoff, + line->y - yoff + line->ascent - (bit->font->ascent / 2), + gdk_string_width (bit->font, line->text), 1); + } + gdk_color_free (bg); gdk_color_free (fg); - gdk_draw_string (window, bit->font, gc, line->x - xoff, - line->y - yoff + line->ascent, line->text); - - if (bit->underline || bit->url) - gdk_draw_rectangle (window, gc, TRUE, line->x - xoff, line->y - yoff + line->ascent + 1, - gdk_string_width (bit->font, line->text), 1); - if (bit->strike) - gdk_draw_rectangle (window, gc, TRUE, line->x - xoff, - line->y - yoff + line->ascent - (bit->font->ascent / 2), - gdk_string_width (bit->font, line->text), 1); + gdk_gc_unref (gc); } @@ -586,6 +656,10 @@ width, line->height); } + if (bit->bm) { + gdk_gc_set_clip_mask(gc, bit->bm); + gdk_gc_set_clip_origin(gc, line->x - xoff, line->y - yoff + hoff); + } gdk_draw_pixmap (window, gc, bit->pm, 0, 0, line->x - xoff, line->y - yoff + hoff, -1, -1); gdk_gc_unref (gc); @@ -1323,8 +1397,12 @@ NULL, imhtml->tip_window, "tooltip", 0, 0, -1, -1); y = font->ascent + 4; - gtk_paint_string (style, imhtml->tip_window->window, GTK_STATE_NORMAL, NULL, - imhtml->tip_window, "tooltip", 4, y, imhtml->tip_bit->url); + if (imhtml->tip_bit->url) + gtk_paint_string (style, imhtml->tip_window->window, GTK_STATE_NORMAL, NULL, + imhtml->tip_window, "tooltip", 4, y, imhtml->tip_bit->url); + else if (imhtml->tip_bit->img) + gtk_paint_string (style, imhtml->tip_window->window, GTK_STATE_NORMAL, NULL, + imhtml->tip_window, "tooltip", 4, y, imhtml->tip_bit->img->filename); return FALSE; } @@ -1367,7 +1445,8 @@ gap = 2; baseline_skip = font->ascent + font->descent + gap; - w = 8 + gdk_string_width (font, imhtml->tip_bit->url); + w = 8 + gdk_string_width (font, imhtml->tip_bit->img ? imhtml->tip_bit->img->filename : + imhtml->tip_bit->url); h = 8 - gap + baseline_skip; gdk_window_get_pointer (NULL, &x, &y, NULL); @@ -1452,7 +1531,8 @@ while (click) { uw = (struct clickable *) click->data; if ((x > uw->x) && (x < uw->x + uw->width) && - (y > uw->y) && (y < uw->y + uw->height)) { + (y > uw->y) && (y < uw->y + uw->height) && + (uw->bit->url || uw->bit->img)) { if (imhtml->tip_bit != uw->bit) { imhtml->tip_bit = uw->bit; if (imhtml->tip_timer != 0) @@ -1465,8 +1545,9 @@ gtk_imhtml_tip, imhtml); } - gdk_window_set_cursor (GTK_LAYOUT (imhtml)->bin_window, - imhtml->hand_cursor); + if (uw->bit->url) + gdk_window_set_cursor (GTK_LAYOUT (imhtml)->bin_window, + imhtml->hand_cursor); return TRUE; } click = g_list_next (click); @@ -1503,11 +1584,63 @@ imhtml->tip_window = NULL; } imhtml->tip_bit = NULL; +return TRUE; +} +struct imgsv { + GtkWidget *savedialog; + struct im_image *img; +}; - return TRUE; +#if USE_PIXBUF +static void +save_img (GtkObject *object, + gpointer data) +{ + struct imgsv *is = data; + struct im_image *img = is->img; + gchar *filename; + FILE *f; + filename = gtk_file_selection_get_filename(GTK_FILE_SELECTION(is->savedialog)); + g_print("Saving %s\n", filename); + if (! (f=fopen(filename, "w"))) { + /* There should be some sort of dialog */ + g_print("Could not open file for writing.\n"); + gtk_widget_destroy(is->savedialog); + g_free(is); + return; + } + + fwrite(img->data, 1, img->len, f); + fclose(f); + gtk_widget_destroy(is->savedialog); + g_free(is); } static void +save_img_dialog (GtkObject *object, + gpointer data) +{ + struct imgsv *is = g_malloc(sizeof(struct imgsv)); + struct im_image *img = data; + GtkWidget *savedialog = gtk_file_selection_new ("Gaim - Save Image"); + gtk_file_selection_set_filename (GTK_FILE_SELECTION(savedialog), img->filename); + gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION(savedialog)->cancel_button), + "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy), + (gpointer) savedialog); + + is->img = img; + is->savedialog = savedialog; + + gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION(savedialog)->ok_button), + "clicked", GTK_SIGNAL_FUNC (save_img), is); + gtk_widget_show (savedialog); + + +} +#endif + + +static void menu_open_url (GtkObject *object, gpointer data) { @@ -1587,6 +1720,14 @@ gtk_widget_show (button); } + if (uw->bit->img) { + button = gtk_menu_item_new_with_label ("Save Image"); + gtk_signal_connect (GTK_OBJECT (button), "activate", + GTK_SIGNAL_FUNC (save_img_dialog), uw->bit->img); + gtk_menu_append (GTK_MENU (menu), button); + gtk_widget_show (button); + } + gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 3, event->time); if (imhtml->tip_timer) { @@ -1876,42 +2017,6 @@ #endif } -#define TRY_FONT tmp = g_strjoinv ("-", newvals); \ - if (default_font->type == GDK_FONT_FONT) \ - ret_font = gdk_font_load (tmp); \ - else \ - ret_font = gdk_fontset_load (tmp); \ - g_free (tmp); \ - if (ret_font) { \ - g_free (newvals); \ - g_strfreev (xnames); \ - g_strfreev (xflds); \ - g_strfreev (names); \ - return ret_font; \ - } else if (newvals [RGSTRY][0] != '*') { \ - /* if the registry isn't "*" then try it as "*". this is evil. */ \ - gchar *reg = newvals [RGSTRY]; \ - gchar *enc = newvals [ENCDNG]; \ - newvals [RGSTRY] = "*"; \ - newvals [ENCDNG] = "*"; \ - tmp = g_strjoinv ("-", newvals); \ - if (default_font->type == GDK_FONT_FONT) \ - ret_font = gdk_font_load (tmp); \ - else \ - ret_font = gdk_fontset_load (tmp); \ - g_free (tmp); \ - if (ret_font) { \ - g_free (newvals); \ - g_strfreev (xnames); \ - g_strfreev (xflds); \ - g_strfreev (names); \ - return ret_font; \ - } \ - newvals [RGSTRY] = reg; \ - newvals [ENCDNG] = enc; \ - } - - static GdkFont* gtk_imhtml_font_load (GtkIMHtml *imhtml, gchar *name, @@ -1923,142 +2028,162 @@ gchar *default_name; gchar **xnames; gchar **pos; + gchar *tmp = NULL; + GdkFont *ret_font; + gchar *xname; + gchar **xflds; + gchar **newvals; + gchar **names = NULL; + char *italicstrings[] = {"i","o","*"}; + int italicsind = 0, nameind = 0; + gboolean usebold = TRUE, usesize = TRUE, useregenc = TRUE; + /* if we're not changing anything, use the default. this is the common case */ if (!name && !bold && !italics && !fontsize) return gdk_font_ref (default_font); - + /* base things off of the default font name */ default_name = gtk_imhtml_get_font_name (default_font); - - /* the default font name can actually be several names separated by ','. */ - xnames = g_strsplit (default_name, ",", -1); - for (pos = xnames; pos && *pos; pos++) { - gchar *xname; - gchar **xflds; - - gchar **newvals; - gint i, j; - gchar **names; - gchar fs[10]; - - gchar *tmp; - GdkFont *ret_font; - - xname = *pos; - xname = g_strchomp (xname); - xname = g_strchug (xname); - - xflds = g_strsplit (xname, "-", -1); - - /* figure out if we have a valid name. i wish there were an - * easier way for determining how many values g_strplit gave */ - for (i = 0; xflds [i]; i++); - if (i != 15) { - int tmp; - newvals = g_malloc0 (16 * sizeof (gchar *)); - newvals [0] = ""; - for (tmp = 1; tmp < 15; tmp++) - newvals [tmp] = "*"; - } else - newvals = g_memdup (xflds, 16 * sizeof (xflds)); - - /* we force foundry as "*" because i hate them. i should give a better reason. */ - newvals [FNDRY] = "*"; - - /* if it's "*" then it defaults to (nil) anyway. some fonts don't want (nil) */ - if ((i > ADSTYL) && !xflds [ADSTYL][0]) - newvals [ADSTYL] = "*"; - - /* right. */ - if (bold) - newvals [WGHT] = "bold"; - if (italics) - newvals [SLANT] = "i"; - if (fontsize) { - g_snprintf (fs, sizeof (fs), "%d", POINT_SIZE (fontsize)); - newvals [PXLSZ] = "*"; - newvals [PTSZ] = fs; - } - - if (name) { - /* we got passed a name. it might be a list of names. */ - gchar **tmp_nms = g_strsplit (name, ",", -1); - /* we do a bunch of weird things to also use the gtk font name as an option. */ - for (j = 0; tmp_nms [j]; j++); - names = g_new0 (char *, j + 2); - for (j = 0; tmp_nms [j]; j++) - names [j] = tmp_nms [j]; - g_free (tmp_nms); - if (i > FMLY) - names [j] = g_strdup (xflds [FMLY]); - } else if (i > FMLY) { - /* we didn't get a name. we come here if the gtk font name is valid */ - names = g_new0 (gchar *, 2); - names [0] = g_strdup (xflds [FMLY]); - } else { - /* we got fucked */ - names = g_new0 (gchar *, 2); - names [0] = g_strdup ("*"); - } - - /* for each name, try it */ - for (j = 0; names [j]; j++) { - newvals [FMLY] = names [j]; - TRY_FONT; - } - - /* if italics is set, try various italics options for each name, including no italics */ - for (j = 0; italics && names [j]; j++) { - newvals [FMLY] = names [j]; - - newvals [SLANT] = "o"; - TRY_FONT; - - if (i > SLANT) - newvals [SLANT] = xflds [SLANT]; - else - newvals [SLANT] = "*"; - TRY_FONT; - } - - /* if font size was set, try ignoring font size. for each name. */ - for (j = 0; fontsize && names [j]; j++) { - newvals [FMLY] = names [j]; - - if (i > PTSZ) { - newvals [PXLSZ] = xflds [PXLSZ]; - newvals [PTSZ] = xflds [PTSZ]; - } else { + /* the default font name can actually be several names separated by ','. + * This is a fontset... used in foreign encodings. */ + do { + xnames = g_strsplit (default_name, ",", -1); + for (pos = xnames; pos && *pos; pos++) { + gint i, j; + gchar fs[10]; + gchar *garbage; + xname = *pos; + xname = g_strchomp (xname); + xname = g_strchug (xname); + + xflds = g_strsplit (xname, "-", -1); + + /* figure out if we have a valid name. i wish there were an + * easier way for determining how many values g_strplit gave */ + for (i = 0; xflds [i]; i++); + if (i != 15) { + int tmp; + newvals = g_malloc0 (16 * sizeof (gchar *)); + newvals [0] = ""; + for (tmp = 1; tmp < 15; tmp++) + newvals [tmp] = "*"; + } else + newvals = g_memdup (xflds, 16 * sizeof (xflds)); + + /* we force foundry as "*" because i hate them. i should give a better reason. */ + newvals [FNDRY] = "*"; + + /* if it's "*" then it defaults to (nil) anyway. some fonts don't want (nil) */ + if ((i > ADSTYL) && !xflds [ADSTYL][0]) + newvals [ADSTYL] = "*"; + + /* If the font doesn't work the first time, we try it with + * registry and encoding as "*" */ + if (!useregenc) { + newvals [RGSTRY] = "*"; + newvals [ENCDNG] = "*"; + } + /* right. */ + if (bold) + if (usebold) + newvals [WGHT] = "bold"; + else + newvals [WGHT] = "*"; + if (italics) + /* We'll try "i" "o" to get italics and then just use "*" */ + newvals [SLANT] = italicstrings[italicsind]; + if (fontsize) { + if (usesize) { + g_snprintf (fs, sizeof (fs), "%d", POINT_SIZE (fontsize)); + newvals [PTSZ] = fs; + } else + newvals [PTSZ] = "*"; newvals [PXLSZ] = "*"; - newvals [PTSZ] = "*"; } - TRY_FONT; + + if (name) { + /* we got passed a name. it might be a list of names. */ + gchar **tmp_nms = g_strsplit (name, ",", -1); + for (j = 0; tmp_nms [j]; j++); + names = g_new0 (char *, j + 2); + for (j = 0; tmp_nms [j]; j++) + names [j] = tmp_nms [j]; + g_free (tmp_nms); + /* Put the default font on the array. */ + if (i > FMLY) { + names [j] = g_strdup (xflds [FMLY]); + } + newvals [FMLY] = names[nameind]; + } else if (i > FMLY) { + /* we didn't get a name. we come here if the gtk font name is valid */ + names = g_new0 (gchar *, 2); + names [0] = g_strdup (xflds [FMLY]); + } else { + /* we got fucked */ + names = g_new0 (gchar *, 2); + names [0] = g_strdup ("*"); + } + if (!tmp) + tmp = g_strjoinv("-", newvals); + else { + /* We have to concat the xlfds in the fontset */ + garbage = tmp; + tmp = g_strconcat(garbage, ",", + g_strjoinv ("-", newvals), NULL); + g_free(garbage); + } + g_free (newvals); + g_strfreev (xflds); } - - /* abandon bold */ - for (j = 0; bold && names [j]; j++) { - newvals [FMLY] = names [j]; - - if (i > WGHT) - newvals [WGHT] = xflds [WGHT]; - else - newvals [WGHT] = "*"; - TRY_FONT; + g_strfreev (xnames); + + if (default_font->type == GDK_FONT_FONT) + ret_font = gdk_font_load (tmp); + else { + /* For some reason, fontsets must end with a single * as an xlfd */ + gchar *garbage = tmp; + tmp = g_strconcat(garbage, ",*", NULL); + ret_font = gdk_fontset_load (tmp); + } + + /* If the font didn't load, we change some of the xlfds one by one + * to get the closest we can. */ + if (!ret_font) { + if (!useregenc && + (!italics || italicsind == 2) && + (!bold || !usebold) && + (!fontsize || !usesize)) { + useregenc = TRUE; + usebold = TRUE; + italicsind = 0; + usesize = TRUE; + if (names && !names[nameind++]) { + ret_font = gdk_font_ref(default_font); + break; + } + } + if (useregenc) + useregenc = FALSE; + else if (italics && italicsind != 2) { + useregenc = TRUE; + italicsind++; + } else if (bold && usebold) { + useregenc = TRUE; + usebold = FALSE; + } else if (fontsize && usesize) + useregenc = TRUE; + usesize = FALSE; } - - g_free (newvals); - g_strfreev (xflds); g_strfreev (names); - - } - - g_strfreev (xnames); - - /* we couldn't get anything. so, we quit. you get the default. */ - return gdk_font_ref (default_font); + names = NULL; + g_free(tmp); + tmp=NULL; + } while (!ret_font); /* Loop with the new options */ + + return ret_font; } - + static void gtk_imhtml_init (GtkIMHtml *imhtml) { @@ -2144,6 +2269,10 @@ gtk_imhtml_set_adjustments (imhtml, hadj, vadj); +#if USE_PIXBUF + imhtml->im_images = NULL; +#endif + imhtml->bits = NULL; imhtml->click = NULL; @@ -2276,7 +2405,8 @@ GList *ls = NULL; struct line_info *li; struct clickable *uw; - + struct im_image *img; + if (height > imhtml->llheight) { diff = height - imhtml->llheight; @@ -2299,6 +2429,16 @@ ls = g_list_next (ls); } +#if USE_PIXBUF + ls = imhtml->im_images; + while(ls) { + img = ls->data; + if (img->y + diff > imhtml->y) + img->y += diff; + ls = g_list_next(ls); + } +#endif + imhtml->llheight = height; if (ascent) imhtml->llascent = ascent; @@ -2366,7 +2506,11 @@ li->ascent = 0; li->bit = bit; +#if USE_PIXBUF + if (bit->url || bit->img) { +#else if (bit->url) { +#endif uw = g_new0 (struct clickable, 1); uw->x = imhtml->x; uw->y = imhtml->y; @@ -2466,6 +2610,36 @@ g_free (copy); } else if ((bit->type == TYPE_SMILEY) || (bit->type == TYPE_IMG)) { +#if USE_PIXBUF + if (bit->img) { + GdkPixbuf *imagepb = bit->img->pb; + GdkPixbuf *tmp = NULL; + if (gdk_pixbuf_get_width(imagepb) > imhtml->xsize - imhtml->x) + new_line (imhtml); + + if (gdk_pixbuf_get_width(imagepb) > imhtml->xsize) { + tmp = gdk_pixbuf_scale_simple(imagepb, imhtml->xsize, + gdk_pixbuf_get_height(imagepb) * + imhtml->xsize/ + gdk_pixbuf_get_width(imagepb), + GDK_INTERP_TILES); + if (bit->pm) + gdk_pixmap_unref (bit->pm); + if (bit->bm) + gdk_bitmap_unref (bit->bm); + gdk_pixbuf_render_pixmap_and_mask(tmp, &(bit->pm), &(bit->bm), 100); + gdk_pixbuf_unref(tmp); + } + else { + if (bit->pm) + gdk_pixmap_unref (bit->pm); + if (bit->bm) + gdk_bitmap_unref (bit->bm); + gdk_pixbuf_render_pixmap_and_mask(imagepb, &(bit->pm), &(bit->bm), 100); + } + } +#endif + gdk_window_get_size (bit->pm, &width, &height); if ((imhtml->x != 0) && ((imhtml->x + width) > imhtml->xsize)) @@ -2802,8 +2976,10 @@ VALID_TAG ("/BODY"); VALID_TAG ("FONT"); VALID_TAG ("HEAD"); - VALID_TAG ("HEAD"); - + VALID_TAG ("/HEAD"); + VALID_TAG ("BINARY"); + VALID_TAG ("/BINARY"); + VALID_OPT_TAG ("HR"); VALID_OPT_TAG ("FONT"); VALID_OPT_TAG ("BODY"); @@ -2851,17 +3027,14 @@ if ((*t == '\"') || (*t == '\'')) { e = a = ++t; while (*e && (*e != *(t - 1))) e++; - if (*e != '\0') { - *e = '\0'; - return g_strdup (a); - } else { + if (*e == '\0') { return NULL; - } + } else + return g_strndup (a, e - a); } else { e = a = t; while (*e && !isspace ((gint) *e)) e++; - *e = '\0'; - return g_strdup (a); + return g_strndup (a, e - a); } } @@ -3055,12 +3228,27 @@ case 38: /* HEAD */ case 39: /* /HEAD */ break; - - case 40: /* HR (opt) */ + case 40: /* BINARY */ + + NEW_BIT (NEW_TEXT_BIT); + while (pos < len) { + if (!g_strncasecmp("</BINARY>", c, strlen("</BINARY>"))) + break; + else { + c++; + pos++; + } + } + c = c - tlen; /* Because it will add this later */ + break; + case 41: /* /BINARY */ + break; + + case 42: /* HR (opt) */ NEW_BIT (NEW_TEXT_BIT); NEW_BIT (NEW_SEP_BIT); break; - case 41: /* FONT (opt) */ + case 43: /* FONT (opt) */ { gchar *color, *back, *face, *size; FontDetail *font; @@ -3114,7 +3302,7 @@ fonts = g_slist_prepend (fonts, font); } break; - case 42: /* BODY (opt) */ + case 44: /* BODY (opt) */ if (!(options & GTK_IMHTML_NO_COLOURS)) { gchar *bgcolor = gtk_imhtml_get_html_opt (tag, "BGCOLOR="); if (bgcolor) { @@ -3128,7 +3316,7 @@ } } break; - case 43: /* A (opt) */ + case 45: /* A (opt) */ { gchar *href = gtk_imhtml_get_html_opt (tag, "HREF="); if (href) { @@ -3138,16 +3326,94 @@ } } break; - case 44: /* IMG (opt) */ - { + case 46: /* IMG (opt) */ + { gchar *src = gtk_imhtml_get_html_opt (tag, "SRC="); + gchar *id = gtk_imhtml_get_html_opt (tag, "ID="); + gchar *datasize = gtk_imhtml_get_html_opt (tag, "DATASIZE="); gchar **xpm; GdkColor *clr; GtkIMHtmlBit *bit; if (!src) break; + + if (!imhtml->img && id && datasize) { /* This is an embedded IM image */ +#if USE_PIXBUF + char *tmp, *imagedata, *e; + const gchar *alltext; + struct im_image *img; + GdkPixbufLoader *load; + GdkPixbuf *imagepb = NULL; + +#endif + NEW_BIT (NEW_TEXT_BIT); +#if USE_PIXBUF + if (!id || !datasize) + break; + tmp = g_malloc(strlen("<DATA ID=\"\" SIZE=\"\">") + + strlen(id) + strlen(datasize)); + g_snprintf(tmp, strlen("<DATA ID=\"\" SIZE=\"\">") + + strlen(id) + strlen(datasize) + 1, + "<DATA ID=\"%s\" SIZE=\"%s\">", id, datasize); + alltext = c; + while (g_strncasecmp(alltext, tmp, strlen(tmp)) && alltext < (c + len)) + alltext++; + alltext = alltext + strlen("<DATA ID=\"\" SIZE=\"\">") + strlen(id) + strlen(datasize); + g_free(tmp); + imagedata = g_malloc(atoi(datasize)); + memcpy(imagedata, alltext, atoi(datasize)); + + if (!GTK_WIDGET_REALIZED (imhtml)) + gtk_widget_realize (GTK_WIDGET (imhtml)); + + img = g_new0 (struct im_image, 1); + tmp = e = src; + while (*tmp){ + if (*tmp == '/' || *tmp == '\\') { + tmp++; + src = tmp; + } else + tmp++; + } + + *tmp = '\0'; + + img->filename = g_strdup(src); + img->len = atoi(datasize); + if (img->len) { + img->data = g_malloc(img->len); + memcpy(img->data, imagedata, img->len); + + load = gdk_pixbuf_loader_new(); + if (!gdk_pixbuf_loader_write(load, imagedata, img->len)) + g_print("IM Image corrupt or unreadable.\n"); + else + imagepb = gdk_pixbuf_loader_get_pixbuf(load); + img->pb = imagepb; + } + if (imagepb) { + bit = g_new0 (GtkIMHtmlBit, 1); + bit->type = TYPE_IMG; + bit->img = img; + if (url) + bit->url = g_strdup (url); + + NEW_BIT (bit); + } else { + g_free(img->filename); + g_free(img->data); + gdk_pixbuf_unref(img->pb); + } + g_free(imagedata); + g_free(e); + g_free(id); + g_free(datasize); +#endif + break; + } + if (!imhtml->img || ((xpm = imhtml->img (src)) == NULL)) { g_free (src); break; @@ -3171,10 +3437,10 @@ g_free (src); } break; - case 45: /* P (opt) */ - case 46: /* H3 (opt) */ + case 47: /* P (opt) */ + case 48: /* H3 (opt) */ break; - case 47: /* comment */ + case 49: /* comment */ NEW_BIT (NEW_TEXT_BIT); wpos = g_snprintf (ws, len, "%s", tag); NEW_BIT (NEW_COMMENT_BIT); @@ -3335,6 +3601,15 @@ gdk_pixmap_unref (bit->pm); if (bit->bm) gdk_bitmap_unref (bit->bm); +#if USE_PIXBUF + if (bit->img) { + g_free(bit->img->filename); + g_free(bit->img->data); + gdk_pixbuf_unref(bit->img->pb); + g_free(bit->img); + } +#endif + while (bit->chunks) { struct line_info *li = bit->chunks->data; if (li->text) @@ -3349,7 +3624,13 @@ g_free (imhtml->click->data); imhtml->click = g_list_remove (imhtml->click, imhtml->click->data); } - + +#if USE_PIXBUF + while (imhtml->im_images) { + imhtml->im_images = g_list_remove(imhtml->im_images, imhtml->im_images->data); + } +#endif + if (imhtml->selected_text) { g_string_free (imhtml->selected_text, TRUE); imhtml->selected_text = g_string_new (""); @@ -3375,6 +3656,11 @@ gtk_timeout_remove (imhtml->scroll_timer); imhtml->scroll_timer = 0; } + +#if USE_PIXBUF + g_list_free(imhtml->im_images); + imhtml->im_images = NULL; +#endif imhtml->x = 0; imhtml->y = TOP_BORDER; Index: gtkimhtml.h =================================================================== RCS file: /cvsroot/gaim/gaim/src/gtkimhtml.h,v retrieving revision 1.11 retrieving revision 1.12 diff -u -d -r1.11 -r1.12 --- gtkimhtml.h 23 Feb 2002 23:17:43 -0000 1.11 +++ gtkimhtml.h 2 Mar 2002 04:52:21 -0000 1.12 @@ -48,6 +48,8 @@ GdkFont *default_font; GdkColor *default_fg_color; GdkColor *default_bg_color; + GdkColor *default_hl_color; + GdkColor *default_hlfg_color; GdkCursor *hand_cursor; GdkCursor *arrow_cursor; @@ -55,6 +57,7 @@ GList *bits; GList *click; struct _GtkIMHtmlBit *tip_bit; + GList *im_images; GtkWidget *tip_window; guint tip_timer; Index: module.c =================================================================== RCS file: /cvsroot/gaim/gaim/src/module.c,v retrieving revision 1.14 retrieving revision 1.15 diff -u -d -r1.14 -r1.15 --- module.c 1 Dec 2001 01:48:26 -0000 1.14 +++ module.c 2 Mar 2002 04:52:21 -0000 1.15 @@ -360,6 +360,9 @@ case event_chat_send_invite: sprintf(buf, "event_chat_send_invite"); break; + case event_got_typing: + sprintf(buf, "event_got_typing"); + break; default: sprintf(buf, "event_unknown"); break; @@ -373,7 +376,7 @@ return; switch (event) { - case event_quit: + case event_quit: debug_printf("%s\n", event_name(event)); break; case event_signon: @@ -392,9 +395,10 @@ case event_buddy_away: case event_buddy_back: case event_buddy_idle: - case event_buddy_unidle: - case event_set_info: - debug_printf("%s: %s %s\n", event_name(event), + case event_buddy_unidle: + case event_set_info: + case event_got_typing: + debug_printf("%s: %s %s\n", event_name(event), ((struct gaim_connection *)arg1)->username, (char *)arg2); break; case event_chat_leave: @@ -512,6 +516,7 @@ case event_chat_leave: case event_set_info: case event_draw_menu: + case event_got_typing: two = g->function; two(arg1, arg2, g->data); break; Index: prefs.c =================================================================== RCS file: /cvsroot/gaim/gaim/src/prefs.c,v retrieving revision 1.212 retrieving revision 1.213 diff -u -d -r1.212 -r1.213 --- prefs.c 21 Dec 2001 10:23:04 -0000 1.212 +++ prefs.c 2 Mar 2002 04:52:21 -0000 1.213 @@ -183,6 +183,7 @@ GtkWidget *sep; GtkWidget *idle; GtkWidget *opt; + GtkWidget *typingbutton; parent = prefdialog->parent; gtk_widget_destroy(prefdialog); @@ -226,7 +227,15 @@ misc_options ^= OPT_MISC_DEBUG; debugbutton = gaim_button(_("Show Debug Window"), &misc_options, OPT_MISC_DEBUG, mbox); gtk_signal_connect(GTK_OBJECT(debugbutton), "destroy", GTK_SIGNAL_FUNC(destdeb), 0); + + /* Preferences should be positive */ + typingbutton = gaim_button(_("Notify buddies that you are typing to them"), &misc_options, + OPT_MISC_STEALTH_TYPING, mbox); + /* So we have to toggle it */ + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(typingbutton), !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(typingbutton))); + misc_options ^= OPT_MISC_STEALTH_TYPING; + frame = gtk_frame_new(_("Report Idle Times")); gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 5); gtk_widget_show(frame); Index: prpl.h =================================================================== RCS file: /cvsroot/gaim/gaim/src/prpl.h,v retrieving revision 1.59 retrieving revision 1.60 diff -u -d -r1.59 -r1.60 --- prpl.h 17 Feb 2002 18:08:12 -0000 1.59 +++ prpl.h 2 Mar 2002 04:52:21 -0000 1.60 @@ -104,6 +104,8 @@ void (* close) (struct gaim_connection *); int (* send_im) (struct gaim_connection *, char *who, char *message, int away); void (* set_info) (struct gaim_connection *, char *info); + int (* send_typing) (struct gaim_connection *, char *name); + void (* send_typing_stopped) (struct gaim_connection *, char *name); void (* get_info) (struct gaim_connection *, char *who); void (* set_away) (struct gaim_connection *, char *state, char *message); void (* get_away) (struct gaim_connection *, char *who); Index: server.c =================================================================== RCS file: /cvsroot/gaim/gaim/src/server.c,v retrieving revision 1.218 retrieving revision 1.219 diff -u -d -r1.218 -r1.219 --- server.c 23 Feb 2002 22:50:43 -0000 1.218 +++ server.c 2 Mar 2002 04:52:21 -0000 1.219 @@ -142,7 +142,19 @@ update_keepalive(gc, TRUE); } +/* This should return the elapsed time in seconds in which Gaim will not send + * typing notifications. + * if it returns zero, it will not send any more typing notifications */ +int serv_send_typing(struct gaim_connection *g, char *name) { + if (g && g->prpl && g->prpl->send_typing) + return g->prpl->send_typing(g, name); + else return 0; +} +void serv_send_typing_stopped(struct gaim_connection *g, char *name) { + if (g && g->prpl && g->prpl->send_typing_stopped) + g->prpl->send_typing_stopped(g, name); +} int serv_send_im(struct gaim_connection *gc, char *name, char *message, int flags) { @@ -153,6 +165,7 @@ if (!(flags & IM_FLAG_AWAY)) serv_touch_idle(gc); + serv_send_typing_stopped(gc, name); return val; } @@ -657,7 +670,7 @@ { struct buddy *b = find_buddy(gc, name); - if (gc->prpl->options & OPT_PROTO_CORRECT_TIME) { + if (signon && (gc->prpl->options & OPT_PROTO_CORRECT_TIME)) { char *tmp = g_strdup(normalize(name)); if (!g_strcasecmp(tmp, normalize(gc->username))) { gc->evil = evil; @@ -748,7 +761,29 @@ do_error_dialog(buf2, _("Warned")); } +void serv_got_typing(struct gaim_connection *gc, char *name, int timeout) { + struct conversation *cnv = find_conversation(name); + if (cnv) { + set_convo_gc(cnv, gc); + show_typing(cnv); + } else return; + plugin_event(event_got_typing, gc, name, 0, 0); + do_pounce(gc, name, OPT_POUNCE_TYPING); + if (timeout > 0) { + if (cnv->typing_timeout) + gtk_timeout_remove (cnv->typing_timeout); + cnv->typing_timeout = gtk_timeout_add(timeout * 1000,(GtkFunction)reset_typing, + g_strdup(name)); + } +} +void serv_got_typing_stopped(struct gaim_connection *gc, char *name) { + struct conversation *c = find_conversation(name); + if (c->typing_timeout) { + gtk_timeout_remove (c->typing_timeout); + } + reset_typing(g_strdup(name)); +} static void close_invite(GtkWidget *w, GtkWidget *w2) { Index: ui.h =================================================================== RCS file: /cvsroot/gaim/gaim/src/ui.h,v retrieving revision 1.30 retrieving revision 1.31 diff -u -d -r1.30 -r1.31 --- ui.h 23 Feb 2002 23:41:50 -0000 1.30 +++ ui.h 2 Mar 2002 04:52:21 -0000 1.31 @@ -153,7 +153,10 @@ GtkWidget *sep2; GtkWidget *menu; GtkWidget *check; + GtkWidget *progress; gint unseen; + guint typing_timeout; + time_t type_again; /* stuff used just for chat */ GList *in_room; @@ -399,6 +402,9 @@ extern void update_convo_font(); extern void set_hide_icons(); extern void set_convo_titles(); +extern void update_progress(struct conversation *, float); +extern void show_typing(struct conversation *); +extern gboolean reset_typing(char *); /* Functions in dialogs.c */ extern void alias_dialog_bud(struct buddy *); |