? behdad-shrink.patch
? src/TEST
? src/cleanup.patch
? src/perf.patch
? src/r
Index: src/vte.c
===================================================================
RCS file: /cvs/gnome/vte/src/vte.c,v
retrieving revision 1.432
diff -u -p -d -r1.432 vte.c
--- src/vte.c	3 Feb 2006 14:34:10 -0000	1.432
+++ src/vte.c	9 Feb 2006 21:08:28 -0000
@@ -119,10 +119,11 @@ typedef gunichar wint_t;
  * includes any supported visible attributes. */
 struct vte_charcell {
 	gunichar c;		/* The Unicode character. */
-	guint32 columns: 11;	/* Number of visible columns (as determined
+	guint32 columns: 10;	/* Number of visible columns (as determined
 				   by g_unicode_iswide(c)).  Use as many bits
 				   as possible without making this structure
 				   grow any larger. */
+	guint32 selected: 1;    /* behdad */
 	guint32 fragment: 1;	/* The nth fragment of a wide character. */
 	guint32 fore: 5;	/* Indices in the color palette for the */
 	guint32 back: 5;	/* foreground and background of the cell. */
@@ -253,6 +254,9 @@ struct _VteTerminalPrivate {
 		GString *status_line_contents;
 	} normal_screen, alternate_screen, *screen;
 
+	/* behdad */
+	struct vte_charcell *matrix;			/* what's on the screen */
+
 	/* Selection information. */
 	GArray *word_chars;
 	gboolean has_selection;
@@ -571,6 +575,11 @@ vte_unichar_strlen(gunichar *c)
 	return i;
 }
 
+/* behdad */
+const struct vte_charcell zero_cell;
+const struct vte_charcell one_cell = {-1};
+#define MATRIX(i,j) (&terminal->pvt->matrix[(i)*terminal->column_count+(j)])
+
 /* Reset defaults for character insertion. */
 static void
 vte_terminal_set_default_attributes(VteTerminal *terminal)
@@ -597,6 +606,9 @@ vte_terminal_set_default_attributes(VteT
 	terminal->pvt->screen->fill_defaults = terminal->pvt->screen->defaults;
 }
 
+static struct vte_charcell *
+vte_terminal_find_charcell(VteTerminal *terminal, glong col, glong row);
+
 /* Cause certain cells to be repainted. */
 static void
 vte_invalidate_cells(VteTerminal *terminal,
@@ -630,6 +642,86 @@ vte_invalidate_cells(VteTerminal *termin
 	column_start = (column_start > 0) ? column_start : 0;
 	column_count = (i + column_count) - column_start;
 
+	if (!terminal->pvt->selecting) {
+	  /* behdad */
+
+	  /* shrink the requested area to what's actually invalid */
+
+	  gint j;
+	  gboolean f;
+	  static struct vte_charcell cell, *pcell;
+	  gint delta = terminal->pvt->screen->scroll_delta;
+
+	  for (i = row_start + row_count - 1; i >= row_start; i--, row_count--) {
+	    f = 0;
+	    for (j = column_start + column_count - 1; j >= column_start; j--) {
+	      pcell = vte_terminal_find_charcell(terminal, j, i+delta);
+	      cell = pcell ? *pcell : zero_cell;
+	      if (vte_cell_is_selected(terminal, j, i+delta, FALSE))
+	        cell.selected = 1;
+	      if (strncmp (MATRIX(i,j), &cell, sizeof (cell))) {
+	        f = 1;
+		break;
+	      }
+	    }
+	    if (f)
+	      break;
+	  }
+	  for (i = row_start; i < row_start + row_count; i++, row_start++, row_count--) {
+	    f = 0;
+	    for (j = column_start; j < column_start + column_count; j++) {
+	      pcell = vte_terminal_find_charcell(terminal, j, i+delta);
+	      cell = pcell ? *pcell : zero_cell;
+	      if (vte_cell_is_selected(terminal, j, i+delta, FALSE))
+	        cell.selected = 1;
+	      if (strncmp (MATRIX(i,j), &cell, sizeof (cell))) {
+	        f = 1;
+		break;
+	      }
+	    }
+	    if (f)
+	      break;
+	  }
+	  for (j = column_start + column_count - 1; j >= column_start; j--, column_count--) {
+	    f = 0;
+	    for (i = row_start + row_count - 1; i >= row_start; i--) {
+	      pcell = vte_terminal_find_charcell(terminal, j, i+delta);
+	      cell = pcell ? *pcell : zero_cell;
+	      if (vte_cell_is_selected(terminal, j, i+delta, FALSE))
+	        cell.selected = 1;
+
+	      if (strncmp (MATRIX(i,j), &cell, sizeof (cell))) {
+	        f = 1;
+		break;
+	      }
+	    }
+	    if (f)
+	      break;
+	  }
+	  for (j = column_start; j < column_start + column_count; j++, column_start++, column_count--) {
+	    f = 0;
+	    for (i = row_start; i < row_start + row_count; i++) {
+	      pcell = vte_terminal_find_charcell(terminal, j, i+delta);
+	      cell = pcell ? *pcell : zero_cell;
+	      if (vte_cell_is_selected(terminal, j, i+delta, FALSE))
+	        cell.selected = 1;
+	      if (strncmp (MATRIX(i,j), &cell, sizeof (cell))) {
+	        f = 1;
+		break;
+	      }
+	    }
+	    if (f)
+	      break;
+	  }
+	} else {
+	  gint i, j;
+	  for (i = row_start; i < row_start + row_count; i++) {
+	    for (j = column_start; j < column_start + column_count; j++) {
+	      strncpy (MATRIX(i,j), &one_cell, sizeof (one_cell));
+	    }
+	  }
+	}
+
 	/* Convert the column and row start and end to pixel values
 	 * by multiplying by the size of a character cell. */
 	rect.x = column_start * terminal->char_width + VTE_PAD_WIDTH;
@@ -10911,6 +11003,10 @@ vte_terminal_refresh_size(VteTerminal *t
 			terminal->column_count = columns;
 		}
 	}
+
+	if (terminal->pvt->matrix)
+	  g_free (terminal->pvt->matrix);
+	terminal->pvt->matrix = g_new0 (struct vte_charcell, terminal->row_count * terminal->column_count);
 }
 
 /**
@@ -11902,6 +11998,9 @@ vte_terminal_finalize(GObject *object)
 		terminal->pvt->match_previous = -1;
 	}
 
+	/* Free the matrix */
+	g_free (terminal->pvt->matrix);
+
 	/* Disconnect from toplevel window configure events. */
 	toplevel = gtk_widget_get_toplevel(GTK_WIDGET(object));
 	if ((toplevel != NULL) && (G_OBJECT(toplevel) != G_OBJECT(object))) {
@@ -13243,7 +13342,7 @@ vte_terminal_draw_cells(VteTerminal *ter
 			gint fore, gint back, gboolean draw_default_bg,
 			gboolean bold, gboolean underline,
 			gboolean strikethrough, gboolean hilite, gboolean boxed,
-			gint column_width, gint row_height)
+			gint column_width, gint row_height, gboolean invalidated)
 {
 	int i, x, y, ascent;
 	gint columns = 0;
@@ -13254,6 +13353,20 @@ vte_terminal_draw_cells(VteTerminal *ter
 	x = items[0].x;
 	y = items[0].y;
 
+	if (!invalidated) {
+	  /* behdad */
+
+	  /* clear matrix as these items have overriden attributes */
+
+	  gint j, row, col;
+
+	  row = y / row_height;
+	  for (j = 0; j < n; j++) {
+	    col = items[j].x / column_width; /* TODO: handle multi-column here, and elsewhere */
+	    strncpy (MATRIX(row,col), &one_cell, sizeof (one_cell));
+	  }
+	}
+
 	bold = bold && terminal->pvt->allow_bold;
 	fg = &terminal->pvt->palette[fore];
 	bg = &terminal->pvt->palette[back];
@@ -13560,7 +13673,7 @@ vte_terminal_draw_cells_with_attributes(
 					gssize n,
 					PangoAttrList *attrs,
 					gboolean draw_default_bg,
-					gint column_width, gint height)
+					gint column_width, gint height, gboolean invalidated)
 {
 	int i, j, cell_count;
 	struct vte_charcell *cells;
@@ -13585,7 +13698,7 @@ vte_terminal_draw_cells_with_attributes(
 					cells[j].bold,
 					cells[j].underline,
 					cells[j].strikethrough,
-					FALSE, FALSE, column_width, height);
+					FALSE, FALSE, column_width, height, invalidated);
 		j += g_unichar_to_utf8(items[i].c, scratch_buf);
 	}
 	g_free(cells);
@@ -13796,7 +13909,7 @@ vte_terminal_draw_row(VteTerminal *termi
 					fore, back, FALSE,
 					bold, underline,
 					strikethrough, hilite, FALSE,
-					column_width, row_height);
+					column_width, row_height, TRUE);
 		item_count = 0;
 		/* We'll need to continue at the first cell which didn't
 		 * match the first one in this set. */
@@ -13878,6 +13991,30 @@ vte_terminal_paint(GtkWidget *widget, Gd
 	_vte_draw_clear(terminal->pvt->draw,
 			area->x, area->y, area->width, area->height);
 
+	if (!terminal->pvt->selecting) {
+	  /* behdad */
+
+	  /* remember what we're putting in the matrix */
+
+	  gint i, j;
+	  static struct vte_charcell *cell;
+	  for (i = row; i <= row_stop; i++) {
+	    for (j = col; j <= col_stop; j++) {
+	      cell = vte_terminal_find_charcell(terminal, j, i+delta);
+	      strncpy (MATRIX(i,j), cell ? cell : &zero_cell, sizeof (*cell));
+	      if (vte_cell_is_selected(terminal, j, i+delta, FALSE))
+	        MATRIX(i,j)->selected = 1;
+	    }
+	  }
+	} else {
+	  gint i, j;
+	  for (i = row; i <= row_stop; i++) {
+	    for (j = col; j <= col_stop; j++) {
+	      strncpy (MATRIX(i,j), &one_cell, sizeof (one_cell));
+	    }
+	  }
+	}
+
 	/* Now we're ready to draw the text.  Iterate over the rows we
 	 * need to draw. */
 	while (row <= row_stop) {
@@ -13904,7 +14041,7 @@ vte_terminal_paint(GtkWidget *widget, Gd
 		col = screen->cursor_current.col;
 		drow = screen->cursor_current.row;
 		row = drow - delta;
-
+		
 		/* Find the character "under" the cursor. */
 		cell = vte_terminal_find_charcell(terminal, col, drow);
 		while ((cell != NULL) && (cell->fragment) && (col > 0)) {
@@ -13971,7 +14108,8 @@ vte_terminal_paint(GtkWidget *widget, Gd
 							FALSE,
 							FALSE,
 							width,
-							height);
+							height,
+							FALSE);
 			}
 		} else {
 			GdkColor color;
@@ -13994,7 +14132,8 @@ vte_terminal_paint(GtkWidget *widget, Gd
 						FALSE,
 						FALSE,
 						width,
-						height);
+						height,
+						FALSE);
 			color.red = terminal->pvt->palette[fore].red;
 			color.green = terminal->pvt->palette[fore].green;
 			color.blue = terminal->pvt->palette[fore].blue;
@@ -14061,7 +14200,8 @@ vte_terminal_paint(GtkWidget *widget, Gd
 								items, len + 1,
 								terminal->pvt->im_preedit_attrs,
 								TRUE,
-								width, height);
+								width, height,
+								FALSE);
 			if ((preedit_cursor >= 0) && (preedit_cursor < len)) {
 				/* Cursored letter in reverse. */
 				vte_terminal_draw_cells(terminal,
@@ -14072,7 +14212,8 @@ vte_terminal_paint(GtkWidget *widget, Gd
 							FALSE,
 							FALSE,
 							TRUE,
-							width, height);
+							width, height,
+							FALSE);
 			} else
 			if (preedit_cursor == len) {
 				/* Empty cursor at the end. */
@@ -14084,7 +14225,8 @@ vte_terminal_paint(GtkWidget *widget, Gd
 							FALSE,
 							FALSE,
 							FALSE,
-							width, height);
+							width, height,
+							FALSE);
 			}
 			g_free(items);
 		}

