changeset 15171:a00712d0522e

[gaim-migrate @ 17957] Show 'ABC is typing...' in the conversation window for typing notification. seanegan suggested this, and it sounded like an interesting thing to do. The change in gnttextview.c will need some more work if it is to be used for some other task, but its current use should be OK. committer: Tailor Script <tailor@pidgin.im>
author Sadrul Habib Chowdhury <imadil@gmail.com>
date Mon, 11 Dec 2006 06:02:15 +0000
parents b7f83eba6029
children fed5a2527dd3
files console/gntconv.c console/libgnt/gnttextview.c console/libgnt/gnttextview.h
diffstat 3 files changed, 137 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/console/gntconv.c	Mon Dec 11 05:35:19 2006 +0000
+++ b/console/gntconv.c	Mon Dec 11 06:02:15 2006 +0000
@@ -205,7 +205,7 @@
 	GaimConversation *conv;
 	GGConv *ggc;
 	GaimConvIm *im = NULL;
-	char *title, *old_title;
+	char *title, *str;
 
 	conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, who, account);
 
@@ -213,15 +213,26 @@
 		return;
 
 	im = GAIM_CONV_IM(conv);
+	ggc = conv->ui_data;
 
 	if (gaim_conv_im_get_typing_state(im) == GAIM_TYPING) {
-		old_title = get_conversation_title(conv, account);
-		title = g_strdup_printf(_("%s [%s]"), old_title,
+		int scroll;
+		str = get_conversation_title(conv, account);
+		title = g_strdup_printf(_("%s [%s]"), str,
 			gnt_ascii_only() ? "T" : "\342\243\277");
-		g_free(old_title);
- 	} else
+		g_free(str);
+
+		scroll = gnt_text_view_get_lines_below(GNT_TEXT_VIEW(ggc->tv));
+		str = g_strdup_printf(_("\n%s is typing..."), gaim_conversation_get_name(conv));
+		gnt_text_view_append_text_with_tag(GNT_TEXT_VIEW(ggc->tv),
+					str, GNT_TEXT_FLAG_DIM, "typing");
+		g_free(str);
+		if (scroll <= 1)
+			gnt_text_view_scroll(GNT_TEXT_VIEW(ggc->tv), 0);
+ 	} else {
 		title = get_conversation_title(conv, account);
-	ggc = conv->ui_data;
+		gnt_text_view_tag_change(GNT_TEXT_VIEW(ggc->tv), "typing", NULL, TRUE);
+	}
 	gnt_screen_rename_widget(ggc->window, title);
 	g_free(title);
 }
@@ -324,6 +335,7 @@
 	char *strip, *newline;
 	GntTextFormatFlags fl = 0;
 	int pos;
+	gboolean notify;
 
 	g_return_if_fail(ggconv != NULL);
 
@@ -336,6 +348,7 @@
 
 	pos = gnt_text_view_get_lines_below(GNT_TEXT_VIEW(ggconv->tv));
 
+	notify = !!gnt_text_view_tag_change(GNT_TEXT_VIEW(ggconv->tv), "typing", NULL, TRUE);
 	gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(ggconv->tv), "\n", GNT_TEXT_FLAG_NORMAL);
 
 	/* Unnecessary to print the timestamp for delayed message */
@@ -374,12 +387,20 @@
 	strip = gaim_markup_strip_html(newline);
 	gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(ggconv->tv),
 				strip, fl);
-	if (pos <= 1)
-		gnt_text_view_scroll(GNT_TEXT_VIEW(ggconv->tv), 0);
 
 	g_free(newline);
 	g_free(strip);
 
+	if (notify) {
+		strip = g_strdup_printf(_("\n%s is typing..."), gaim_conversation_get_name(conv));
+		gnt_text_view_append_text_with_tag(GNT_TEXT_VIEW(ggconv->tv),
+					strip, GNT_TEXT_FLAG_DIM, "typing");
+		g_free(strip);
+	}
+
+	if (pos <= 1)
+		gnt_text_view_scroll(GNT_TEXT_VIEW(ggconv->tv), 0);
+
 	if (flags & (GAIM_MESSAGE_RECV | GAIM_MESSAGE_NICK | GAIM_MESSAGE_ERROR))
 		gnt_widget_set_urgent(ggconv->tv);
 }
--- a/console/libgnt/gnttextview.c	Mon Dec 11 05:35:19 2006 +0000
+++ b/console/libgnt/gnttextview.c	Mon Dec 11 06:02:15 2006 +0000
@@ -23,6 +23,13 @@
 	gboolean soft;           /* TRUE if it's an overflow from prev. line */
 } GntTextLine;
 
+typedef struct
+{
+	char *name;
+	int start;
+	int end;
+} GntTextTag;
+
 static GntWidgetClass *parent_class = NULL;
 
 static void
@@ -134,12 +141,22 @@
 }
 
 static void
+free_tag(gpointer data, gpointer null)
+{
+	GntTextTag *tag = data;
+	g_free(tag->name);
+	g_free(tag);
+}
+
+static void
 gnt_text_view_destroy(GntWidget *widget)
 {
 	GntTextView *view = GNT_TEXT_VIEW(widget);
 	view->list = g_list_first(view->list);
 	g_list_foreach(view->list, free_text_line, NULL);
 	g_list_free(view->list);
+	g_list_foreach(view->tags, free_tag, NULL);
+	g_list_free(view->tags);
 	g_string_free(view->string, TRUE);
 }
 
@@ -297,6 +314,12 @@
 
 void gnt_text_view_append_text_with_flags(GntTextView *view, const char *text, GntTextFormatFlags flags)
 {
+	gnt_text_view_append_text_with_tag(view, text, flags, NULL);
+}
+
+void gnt_text_view_append_text_with_tag(GntTextView *view, const char *text,
+			GntTextFormatFlags flags, const char *tagname)
+{
 	GntWidget *widget = GNT_WIDGET(view);
 	int fl = 0;
 	const char *start, *end;
@@ -312,6 +335,14 @@
 	len = view->string->len;
 	view->string = g_string_append(view->string, text);
 
+	if (tagname) {
+		GntTextTag *tag = g_new0(GntTextTag, 1);
+		tag->name = g_strdup(tagname);
+		tag->start = len;
+		tag->end = view->string->len;
+		view->tags = g_list_append(view->tags, tag);
+	}
+
 	view->list = g_list_first(view->list);
 
 	start = end = view->string->str + len;
@@ -471,3 +502,73 @@
 	return above;
 }
 
+/**
+ * XXX: There are quite possibly more than a few bugs here.
+ */
+int gnt_text_view_tag_change(GntTextView *view, const char *name, const char *text, gboolean all)
+{
+	GList *list, *next, *iter, *inext;
+	int count = 0;
+	for (list = view->tags; list; list = next) {
+		GntTextTag *tag = list->data;
+		next = list->next;
+		if (strcmp(tag->name, name) == 0) {
+			int change;
+			char *before, *after;
+
+			count++;
+
+			before = g_strndup(view->string->str, tag->start);
+			after = g_strdup(view->string->str + tag->end);
+			change = (tag->end - tag->start) - (text ? strlen(text) : 0);
+
+			g_string_printf(view->string, "%s%s%s", before, text ? text : "", after);
+			g_free(before);
+			g_free(after);
+
+			/* Update the offsets of the next tags */
+			for (iter = next; iter; iter = iter->next) {
+				GntTextTag *t = iter->data;
+				t->start -= change;
+				t->end -= change;
+			}
+
+			/* Update the offsets of the segments */
+			for (iter = view->list; iter; iter = inext) {
+				GList *segs, *snext;
+				GntTextLine *line = iter->data;
+				inext = iter->next;
+				for (segs = line->segments; segs; segs = snext) {
+					GntTextSegment *seg = segs->data;
+					snext = segs->next;
+					if (seg->start >= tag->end) {
+						seg->start -= change;
+						seg->end -= change;
+						continue;
+					}
+					if (seg->end < tag->start)
+						continue;
+					
+					if (seg->start >= tag->start && seg->end <= tag->end) {
+						free_text_segment(seg, NULL);
+						line->segments = g_list_delete_link(line->segments, segs);
+						if (line->segments == NULL) {
+							free_text_line(line, NULL);
+							view->list = g_list_delete_link(view->list, iter);
+						}
+					}
+					/* XXX: handle the rest of the conditions */
+				}
+			}
+			if (text == NULL) {
+				/* Remove the tag */
+				view->tags = g_list_delete_link(view->tags, list);
+				free_tag(tag, NULL);
+			}
+			if (!all)
+				break;
+		}
+	}
+	return count;
+}
+
--- a/console/libgnt/gnttextview.h	Mon Dec 11 05:35:19 2006 +0000
+++ b/console/libgnt/gnttextview.h	Mon Dec 11 06:02:15 2006 +0000
@@ -27,6 +27,8 @@
 
 	GString *string;
 	GList *list;        /* List of GntTextLine */
+
+	GList *tags;       /* A list of tags */
 };
 
 typedef enum
@@ -62,6 +64,8 @@
 
 void gnt_text_view_append_text_with_flags(GntTextView *view, const char *text, GntTextFormatFlags flags);
 
+void gnt_text_view_append_text_with_tag(GntTextView *view, const char *text, GntTextFormatFlags flags, const char *tag);
+
 /* Move the cursor to the beginning of the next line and resets text-attributes.
  * It first completes the current line with the current text-attributes. */
 void gnt_text_view_next_line(GntTextView *view);
@@ -74,6 +78,9 @@
 
 int gnt_text_view_get_lines_above(GntTextView *view);
 
+/* If text is NULL, then the tag is removed. */
+int gnt_text_view_tag_change(GntTextView *view, const char *name, const char *text, gboolean all);
+
 G_END_DECLS
 
 #endif /* GNT_TEXT_VIEW_H */