changeset 4895:9e50494f63a1

[gaim-migrate @ 5227] IM image support. javabsp did most of the hard work, I just cleaned it up and fixed the bugs ;-) committer: Tailor Script <tailor@pidgin.im>
author Nathan Walp <nwalp@pidgin.im>
date Wed, 26 Mar 2003 06:19:44 +0000
parents eea963dcd1ed
children 3c649fe22e2c
files src/conversation.c src/gtkconv.c src/gtkimhtml.c src/gtkimhtml.h src/protocols/oscar/ft.c
diffstat 5 files changed, 287 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/src/conversation.c	Wed Mar 26 02:57:17 2003 +0000
+++ b/src/conversation.c	Wed Mar 26 06:19:44 2003 +0000
@@ -253,7 +253,7 @@
 			int imflags = 0;
 
 			if (conv->u.im->images != NULL) {
-				int id = 1, offset = 0;
+				int id = 0, offset = 0;
 				char *bigbuf = NULL;
 				GSList *tmplist;
 
@@ -267,6 +267,8 @@
 					struct stat st;
 					char imgtag[1024];
 
+					id++;
+
 					if (stat(img_filename, &st) != 0) {
 						debug_printf("Could not stat %s\n",
 									 (char *)img_filename);
@@ -328,7 +330,6 @@
 							strlen("</DATA>") + 1);
 
 					offset += strlen("</DATA>");
-					id++;
 				}
 
 				if (binary) {
@@ -354,7 +355,7 @@
 						g_free(tempy->data);
 					}
 
-					g_slist_free(tempy);
+					g_slist_free(conv->u.im->images);
 					conv->u.im->images = NULL;
 
 					if (binary)
--- a/src/gtkconv.c	Wed Mar 26 02:57:17 2003 +0000
+++ b/src/gtkconv.c	Wed Mar 26 06:19:44 2003 +0000
@@ -215,9 +215,10 @@
 			"clicked", G_CALLBACK(gtk_widget_destroy), window);
 
 	gtk_widget_show(window);
-
+/*
 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtkconv->toolbar.image),
 								FALSE);
+								*/
 }
 
 static void
@@ -3871,6 +3872,10 @@
 	char *str;
 	char *with_font_tag;
 	
+
+	if(length == -1)
+		length = strlen(message) + 1;
+
 	gtkconv = GAIM_GTK_CONVERSATION(conv);
 	gc = gaim_conversation_get_gc(conv);
 
@@ -3956,8 +3961,8 @@
 		gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf, -1, 0);
 	}
 	else {
-		char *new_message = g_strdup(message);
-
+		char *new_message = g_memdup(message, length);
+		
 		if (flags & WFLAG_WHISPER) {
 			str = g_malloc(1024);
 
@@ -4032,15 +4037,26 @@
 
 		gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf2, -1, 0);
 
-		if(gc)
-			with_font_tag = g_strdup_printf("<font sml=\"%s\">%s</font>",
-										gc->prpl->name, new_message);
+		if(gc){
+			char *pre = g_strdup_printf("<font sml=\"%s\">", gc->prpl->name);
+			char *post = "</font>";
+			int pre_len = strlen(pre);
+			int post_len = strlen(post);
+
+			with_font_tag = g_malloc(length + pre_len + post_len + 1);
+
+			strcpy(with_font_tag, pre);
+			memcpy(with_font_tag + pre_len, new_message, length);
+			strcpy(with_font_tag + pre_len + length, post);
+
+			length += pre_len + post_len;
+			g_free(pre);
+		}
 		else
-			with_font_tag = g_strdup(new_message);
+			with_font_tag = g_memdup(new_message, length);
 
 		log_str = gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml),
-										 with_font_tag, length,
-										 gtk_font_options);
+										 with_font_tag, length, gtk_font_options);
 
 		gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), "<BR>", -1, 0);
 
--- a/src/gtkimhtml.c	Wed Mar 26 02:57:17 2003 +0000
+++ b/src/gtkimhtml.c	Wed Mar 26 06:19:44 2003 +0000
@@ -24,6 +24,7 @@
 #endif
 #include "gtkimhtml.h"
 #include <gtk/gtk.h>
+#include <glib/gerror.h>
 #include <gdk/gdkkeysyms.h>
 #include <string.h>
 #include <ctype.h>
@@ -54,8 +55,9 @@
 
 static gboolean gtk_motion_event_notify(GtkWidget *imhtml, GdkEventMotion *event, gpointer user_data);
 
+static gboolean gtk_size_allocate_cb(GtkWidget *widget, GtkAllocation *alloc, gpointer user_data);
+static gint gtk_imhtml_tip (gpointer data);
 
-static gint gtk_imhtml_tip (gpointer data);
 
 /* POINT_SIZE converts from AIM font sizes to point sizes.  It probably should be redone in such a
  * way that it base the sizes off the default font size rather than using arbitrary font sizes. */
@@ -153,6 +155,8 @@
 gtk_imhtml_finalize (GObject *object)
 {
 	GtkIMHtml *imhtml = GTK_IMHTML(object);
+	GList *scalables;
+
 	g_hash_table_destroy(imhtml->smiley_data);
 	gtk_smiley_tree_destroy(imhtml->default_smilies);
 	gdk_cursor_unref(imhtml->hand_cursor);
@@ -163,6 +167,12 @@
 	if(imhtml->tip_timer)
 		gtk_timeout_remove(imhtml->tip_timer);
 
+	for(scalables = imhtml->scalables; scalables; scalables = scalables->next) {
+		GtkIMHtmlScalable *scale = GTK_IMHTML_SCALABLE(scalables->data);
+		scale->free(scale);
+	}
+
+	g_list_free(imhtml->scalables);
 	G_OBJECT_CLASS(parent_class)->finalize (object);
 }
 
@@ -221,10 +231,13 @@
 	imhtml->default_smilies = gtk_smiley_tree_new();
 
 	g_signal_connect(G_OBJECT(imhtml), "motion-notify-event", G_CALLBACK(gtk_motion_event_notify), NULL);
+	g_signal_connect(G_OBJECT(imhtml), "size-allocate", G_CALLBACK(gtk_size_allocate_cb), NULL);
 
 	imhtml->tip = NULL;
 	imhtml->tip_timer = 0;
 	imhtml->tip_window = NULL;
+
+	imhtml->scalables = NULL;
 }
 
 GtkWidget *gtk_imhtml_new(void *a, void *b)
@@ -719,17 +732,17 @@
 
 
 #define NEW_TEXT_BIT 0
-#define NEW_HR_BIT 1
 #define NEW_COMMENT_BIT 2
+#define NEW_SCALABLE_BIT 1
 #define NEW_BIT(x)	ws [wpos] = '\0'; \
                         mark2 = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); \
                         gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, -1); \
-                      	gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); \
+						gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); \
                         gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &siter, mark2); \
                         gtk_text_buffer_delete_mark(imhtml->text_buffer, mark2); \
                         if (bold) \
                                  gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "BOLD", &siter, &iter); \
-		        if (italics) \
+						if (italics) \
                                  gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "ITALICS", &siter, &iter); \
                         if (underline) \
                                  gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "UNDERLINE", &siter, &iter); \
@@ -775,16 +788,17 @@
                         wpos = 0; \
                         ws[0] = 0; \
                         gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); \
-                        if (x == NEW_HR_BIT) { \
-                                 GtkTextChildAnchor *anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, &iter); \
-                                 GtkWidget *sep = gtk_hseparator_new(); \
-                                 GdkRectangle rect; \
-                                 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); \
-                                 gtk_widget_set_size_request(GTK_WIDGET(sep), rect.width, 2); \
-                                 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), sep, anchor); \
-                                 gtk_widget_show(sep); \
+                        if (x == NEW_SCALABLE_BIT) { \
+								GdkRectangle rect; \
+								gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); \
+								scalable->add_to(scalable, imhtml, &iter); \
+								scalable->scale(scalable, rect.width, rect.height); \
+								imhtml->scalables = g_list_append(imhtml->scalables, scalable); \
+								gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); \
                         } \
 
+
+
 GString* gtk_imhtml_append_text (GtkIMHtml        *imhtml,
 				 const gchar      *text,
 				 gint              len,
@@ -818,6 +832,8 @@
 	GdkRectangle rect;
 	int y, height;
 
+	GtkIMHtmlScalable *scalable = NULL;
+
 	g_return_val_if_fail (imhtml != NULL, NULL);
 	g_return_val_if_fail (GTK_IS_IMHTML (imhtml), NULL);
 	g_return_val_if_fail (text != NULL, NULL);
@@ -941,7 +957,8 @@
 				case 26:        /* HR */
 				case 42:        /* HR (opt) */
 					ws[wpos++] = '\n';
-					NEW_BIT(NEW_HR_BIT);
+					scalable = gaim_hr_new();
+					NEW_BIT(NEW_SCALABLE_BIT);
 					ws[wpos++] = '\n';
 					break;
 				case 27:	/* /FONT */
@@ -980,6 +997,8 @@
 				case 39:	/* /HEAD */
 					break; 
 				case 40:        /* BINARY */
+					NEW_BIT (NEW_TEXT_BIT);
+					break;
 				case 41:        /* /BINARY */
 					break;
 				case 43:	/* FONT (opt) */
@@ -1062,6 +1081,54 @@
 						}
 					}
 					break;
+				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=");
+						gint im_len = datasize?atoi(datasize):0;
+
+						if (src && id && im_len && im_len <= len - pos) {
+							/* This is an embedded IM image, or is it? */
+							char *tmp = NULL;
+							const char *alltext;
+							guchar *imagedata = NULL;
+
+							GdkPixbufLoader *load;
+							GdkPixbuf *imagepb = NULL;
+							GError *error = NULL;
+
+							tmp = g_strdup_printf("<DATA ID=\"%s\" SIZE=\"%s\">", id, datasize);
+							alltext = strstr(c, tmp);
+							imagedata = g_memdup(alltext + strlen(tmp), im_len);
+
+							g_free(tmp);
+
+							load = gdk_pixbuf_loader_new();
+							if (!gdk_pixbuf_loader_write(load, imagedata, im_len, &error)){
+								fprintf(stderr, "IM Image corrupted or unreadable.: %s\n", error->message);
+							} else {
+								imagepb = gdk_pixbuf_loader_get_pixbuf(load);
+								if (imagepb) {
+									scalable = gaim_im_image_new(imagepb);
+									NEW_BIT(NEW_SCALABLE_BIT);
+								}
+							}
+
+							gdk_pixbuf_loader_close(load, NULL);
+
+
+							g_free(imagedata);
+							g_free(id);
+							g_free(datasize);
+							g_free(src);
+
+							break;
+						}
+						g_free(id);
+						g_free(datasize);
+						g_free(src);
+					}
 				case 47:	/* P (opt) */
 				case 48:	/* H3 (opt) */
 					break;
@@ -1303,7 +1370,131 @@
 	gtk_window_move (GTK_WINDOW(imhtml->tip_window), x, y);
 
 	pango_font_metrics_unref(font);
-	g_object_unref (layout);
+	g_object_unref(layout);
 
 	return FALSE;
 }
+
+static gboolean gtk_size_allocate_cb(GtkWidget *widget, GtkAllocation *alloc, gpointer user_data)
+{
+	static GdkRectangle old_rect = {0, 0, 0, 0};
+    GdkRectangle rect;
+
+    gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(widget), &rect);
+
+	if(old_rect.width && (old_rect.width != rect.width || old_rect.height != rect.height)){
+		GList *iter = GTK_IMHTML(widget)->scalables;
+		
+		while(iter){
+			GtkIMHtmlScalable *scale = GTK_IMHTML_SCALABLE(iter->data);
+			scale->scale(scale, rect.width, rect.height);
+
+			iter = iter->next;
+		}
+	}
+
+	old_rect = rect;
+	return FALSE;
+}
+
+/* GtkIMHtmlScalable, gaim_im_image, gaim_hr */
+GtkIMHtmlScalable *gaim_im_image_new(GdkPixbuf *img)
+{
+	gaim_im_image *im_image = g_malloc(sizeof(gaim_im_image));
+
+	GTK_IMHTML_SCALABLE(im_image)->scale = gaim_im_image_scale;
+	GTK_IMHTML_SCALABLE(im_image)->add_to = gaim_im_image_add_to;
+	GTK_IMHTML_SCALABLE(im_image)->free = gaim_im_image_free;
+	im_image->image = img;
+	im_image->width = gdk_pixbuf_get_width(img);
+	im_image->height = gdk_pixbuf_get_height(img);
+	im_image->imhtml = NULL;
+	im_image->mark = NULL;
+
+	return GTK_IMHTML_SCALABLE(im_image);
+}
+
+void gaim_im_image_scale(GtkIMHtmlScalable *scale, int width, int height)
+{
+	gaim_im_image *image = (gaim_im_image *)scale;
+
+	if(image->width > width || image->height > height){
+		GdkPixbuf *new_image = NULL;
+		GtkTextIter start, end;
+		float factor;
+		int new_width = image->width, new_height = image->height;
+
+		gtk_text_buffer_get_iter_at_mark(image->imhtml->text_buffer, &start, image->mark);
+		end = start;
+		gtk_text_iter_forward_char(&end);
+		gtk_text_buffer_delete(image->imhtml->text_buffer, &start, &end);
+
+		if(image->width > width){
+			factor = (float)(width)/image->width;
+			new_width = width;
+			new_height = image->height * factor;
+		}
+		if(new_height > height){
+			factor = (float)(height)/new_height;
+			new_height = height;
+			new_width = new_width * factor;
+		}
+
+		gtk_text_buffer_get_iter_at_mark(image->imhtml->text_buffer, &start, image->mark);
+		new_image = gdk_pixbuf_scale_simple(image->image, new_width, new_height, GDK_INTERP_BILINEAR);
+		gtk_text_buffer_insert_pixbuf(image->imhtml->text_buffer, &start, new_image);
+
+		g_object_unref(G_OBJECT(new_image));
+	}
+}
+
+void gaim_im_image_free(GtkIMHtmlScalable *scale)
+{
+	gaim_im_image *image = (gaim_im_image *)scale;
+
+	g_object_unref(image->image);
+	g_free(scale);
+}
+
+void gaim_im_image_add_to(GtkIMHtmlScalable *scale, GtkIMHtml *imhtml, GtkTextIter *iter)
+{
+	gaim_im_image *image = (gaim_im_image *)scale;
+
+	image->mark = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, iter, TRUE);
+	gtk_text_buffer_insert_pixbuf(imhtml->text_buffer, iter, image->image);
+	image->imhtml = imhtml;
+}
+
+GtkIMHtmlScalable *gaim_hr_new()
+{
+	gaim_hr *hr = g_malloc(sizeof(gaim_hr));
+
+	GTK_IMHTML_SCALABLE(hr)->scale = gaim_hr_scale;
+	GTK_IMHTML_SCALABLE(hr)->add_to = gaim_hr_add_to;
+	GTK_IMHTML_SCALABLE(hr)->free = gaim_hr_free;
+
+	hr->sep = gtk_hseparator_new();
+	gtk_widget_set_size_request(hr->sep, 5000, 2);
+	gtk_widget_show(hr->sep);
+
+	return GTK_IMHTML_SCALABLE(hr);
+}
+
+void gaim_hr_scale(GtkIMHtmlScalable *scale, int width, int height)
+{
+	gtk_widget_set_size_request(((gaim_hr *)scale)->sep, width, 2);
+}
+
+void gaim_hr_add_to(GtkIMHtmlScalable *scale, GtkIMHtml *imhtml, GtkTextIter *iter)
+{
+	gaim_hr *hr = (gaim_hr *)scale;
+	GtkTextChildAnchor *anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter);
+
+	gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), hr->sep, anchor);
+}
+
+void gaim_hr_free(GtkIMHtmlScalable *scale)
+{
+/*	gtk_widget_destroy(((gaim_hr *)scale)->sep); */
+	g_free(scale);
+}
--- a/src/gtkimhtml.h	Wed Mar 26 02:57:17 2003 +0000
+++ b/src/gtkimhtml.h	Wed Mar 26 06:19:44 2003 +0000
@@ -60,6 +60,8 @@
 	GtkWidget *tip_window;
 	char *tip;
 	guint tip_timer;
+
+	GList *scalables;
 };
 
 struct _GtkIMHtmlClass {
@@ -118,6 +120,51 @@
 void       gtk_imhtml_page_down        (GtkIMHtml        *imhtml);
 void       gtk_imhtml_to_bottom        (GtkIMHtml        *imhtml);
 
+/* GtkIMHtmlScalable, gaim_im_image, and gaim_hr */
+
+typedef struct _GtkIMHtmlScalable GtkIMHtmlScalable;
+#define GTK_IMHTML_SCALABLE(x) ((GtkIMHtmlScalable *)x)
+
+struct _GtkIMHtmlScalable{
+	void (*scale)(struct _GtkIMHtmlScalable *, int, int);
+	void (*add_to)(struct _GtkIMHtmlScalable *, GtkIMHtml *, GtkTextIter *);
+	void (*free)(struct _GtkIMHtmlScalable *);
+};
+
+typedef struct {
+	GtkIMHtmlScalable scalable;
+	GdkPixbuf *image;
+	GtkIMHtml *imhtml;
+	GtkTextMark *mark;
+	int width;
+	int height;
+} gaim_im_image;
+
+typedef struct {
+	GtkIMHtmlScalable scalable;
+	GtkWidget *sep;
+} gaim_hr;
+
+GtkIMHtmlScalable *gtk_imhtml_scalable_new();
+
+GtkIMHtmlScalable *gaim_im_image_new(GdkPixbuf *img);
+
+void gaim_im_image_free(GtkIMHtmlScalable *);
+
+void gaim_im_image_scale(GtkIMHtmlScalable *, int, int);
+
+void gaim_im_image_add_to(GtkIMHtmlScalable *, GtkIMHtml *, GtkTextIter *);
+
+GtkIMHtmlScalable *gaim_hr_new();
+
+void gaim_hr_free(GtkIMHtmlScalable *);
+
+void gaim_hr_scale(GtkIMHtmlScalable *, int, int);
+
+void gaim_hr_add_to(GtkIMHtmlScalable *, GtkIMHtml *, GtkTextIter *);
+
+
+
 #ifdef __cplusplus
 }
 #endif
--- a/src/protocols/oscar/ft.c	Wed Mar 26 02:57:17 2003 +0000
+++ b/src/protocols/oscar/ft.c	Wed Mar 26 06:19:44 2003 +0000
@@ -672,8 +672,10 @@
 
 		isawaymsg = flags & 0x0001;
 
-		if (!(msg = calloc(1, payloadlength+1)))
+		if (!(msg = calloc(1, payloadlength+1))) {
+			free(snptr);
 			return -ENOMEM;
+		}
 
 		while (payloadlength - recvd) {
 			if (payloadlength - recvd >= 1024)
@@ -682,6 +684,7 @@
 				i = aim_recv(conn->fd, &msg[recvd], payloadlength - recvd);
 			if (i <= 0) {
 				free(msg);
+				free(snptr);
 				return -1;
 			}
 			recvd = recvd + i;
@@ -695,6 +698,8 @@
 		free(msg);
 	}
 
+	free(snptr);
+
 	return ret;
 }