Index: src/vte-private.h
===================================================================
--- src/vte-private.h	(revision 1487)
+++ src/vte-private.h	(working copy)
@@ -271,6 +271,7 @@
 	gboolean scroll_on_output;
 	gboolean scroll_on_keystroke;
 	long scrollback_lines;
+	gboolean expand_scrollback;
 
 	/* Cursor blinking. */
 	gboolean cursor_blink_state;
Index: src/ring.c
===================================================================
--- src/ring.c	(revision 1487)
+++ src/ring.c	(working copy)
@@ -53,12 +53,13 @@
 VteRing *
 _vte_ring_new(glong max_elements, VteRingFreeFunc free, gpointer data)
 {
-	VteRing *ret = g_slice_new0(VteRing);
+	VteRing *ret = g_slice_new(VteRing);
+	ret->free = free;
 	ret->user_data = data;
 	ret->delta = ret->length = 0;
+	ret->expand = FALSE;
 	ret->max = MAX(max_elements, 2);
-	ret->array = g_malloc0(sizeof(gpointer) * ret->max);
-	ret->free = free;
+	ret->array = g_new0(gpointer, ret->max);
 	return ret;
 }
 
@@ -72,6 +73,47 @@
 	return ret;
 }
 
+VteRing *
+_vte_ring_grow(VteRing *ring, glong size)
+{
+	gpointer *array;
+
+	/* preserves ring->delta */
+
+	array = g_new(gpointer, size);
+	if (ring->length > 0){
+		glong delta = ring->delta % ring->max;
+		glong offset = size - ring->max;
+
+		memcpy (array + delta, ring->array + delta,
+			       	sizeof (gpointer) * (ring->length - delta));
+		if (offset < delta) {
+			glong d = delta - offset;
+			memcpy (array, ring->array + offset,
+				       	sizeof (gpointer) * d);
+			memset (array + d, 0, sizeof (gpointer) * offset);
+			memcpy (array + ring->length, ring->array,
+					sizeof (gpointer) * offset);
+		} else {
+			memset (array, 0, sizeof (gpointer) * delta);
+			memcpy (array + ring->length, ring->array,
+					sizeof (gpointer) * delta);
+			if (offset > delta ) {
+				glong d = offset - delta;
+				memset (array + ring->length + delta, 0,
+					       	sizeof (gpointer) * d);
+			}
+		}
+	} else {
+		memset(array, 0, sizeof (gpointer) * size);
+	}
+	g_free (ring->array);
+	ring->array = array;
+	ring->max = size;
+
+	return ring;
+}
+
 /**
  * _vte_ring_insert:
  * @ring: a #VteRing
@@ -102,6 +144,12 @@
 
 	/* Initial insertion, or append. */
 	if (position == ring->length + ring->delta) {
+		if (ring->length == ring->max && ring->expand) {
+			_vte_ring_grow(ring, (ring->length+16)&~15);
+			ring->array[position % ring->max] = data;
+			ring->length++;
+			return;
+		}
 		/* If there was something there before, free it. */
 		if ((ring->free != NULL) &&
 		    (ring->array[position % ring->max] != NULL)) {
Index: src/ring.h
===================================================================
--- src/ring.h	(revision 1487)
+++ src/ring.h	(working copy)
@@ -34,6 +34,7 @@
 	gpointer user_data;
 	gpointer *array;
 	glong delta, length, max;
+	gboolean expand;
 };
 
 #define _vte_ring_contains(__ring, __position) \
@@ -65,6 +66,7 @@
 		      gpointer data);
 VteRing *_vte_ring_new_with_delta(glong max_elements, glong delta,
 				  VteRingFreeFunc free, gpointer data);
+VteRing * _vte_ring_grow(VteRing *ring, glong size);
 void _vte_ring_insert(VteRing *ring, glong position, gpointer data);
 void _vte_ring_insert_preserve(VteRing *ring, glong position, gpointer data);
 void _vte_ring_remove(VteRing *ring, glong position, gboolean free_element);
Index: src/vte.c
===================================================================
--- src/vte.c	(revision 1487)
+++ src/vte.c	(working copy)
@@ -1793,6 +1793,10 @@
 				row = _vte_new_row_data(terminal);
 			}
 			_vte_ring_append(screen->row_data, row);
+			if (terminal->pvt->expand_scrollback) {
+				screen->row_data->expand =
+					screen->scroll_delta == _vte_ring_delta(screen->row_data);
+			}
 		} while(--delta);
 		_vte_terminal_adjust_adjustments(terminal, FALSE);
 	}
@@ -3045,9 +3049,14 @@
 	gboolean invalidated_text;
 	GArray *unichars;
 
-	bottom = (terminal->pvt->screen->insert_delta ==
-		  terminal->pvt->screen->scroll_delta);
+	screen = terminal->pvt->screen;
 
+	bottom = screen->insert_delta == screen->scroll_delta;
+	if (terminal->pvt->expand_scrollback) {
+		screen->row_data->expand =
+			screen->scroll_delta == _vte_ring_delta(screen->row_data);
+	}
+
 #ifdef VTE_DEBUG
 	if (_vte_debug_on(VTE_DEBUG_IO)) {
 		g_printerr("Handler processing %d bytes.\n",
@@ -3058,7 +3067,6 @@
 	}
 #endif
 	/* Save the current cursor position. */
-	screen = terminal->pvt->screen;
 	cursor = screen->cursor_current;
 	cursor_visible = terminal->pvt->cursor_visible;
 
@@ -3320,7 +3328,7 @@
 		 * we're currently at the bottom of the buffer. */
 		_vte_terminal_update_insert_delta(terminal);
 		if (terminal->pvt->scroll_on_output || bottom) {
-			vte_terminal_maybe_scroll_to_bottom(terminal);
+			vte_terminal_maybe_scroll_to_bottom (terminal);
 		}
 		/* Deselect the current selection if its contents are changed
 		 * by this insertion. */
@@ -6943,6 +6951,8 @@
 	/* In debuggable mode, we always do this. */
 	/* gtk_widget_get_accessible(&terminal->widget); */
 #endif
+
+	pvt->expand_scrollback = TRUE; /* XXX for testing */
 }
 
 /* Tell GTK+ how much space we need. */
@@ -10531,7 +10541,34 @@
 	_vte_invalidate_all(terminal);
 }
 
+
 /**
+ * vte_terminal_set_keep_top_line_in_scrollback:
+ * @terminal: a #VteTerminal
+ * @state: if TRUE
+ *
+ * If set to TRUE then the scrollback buffer will be expanded to maintain the
+ * top line in the history.
+ *
+ * Since: 0.16
+ */
+void
+vte_terminal_set_keep_top_line_in_scrollback(VteTerminal *terminal, gboolean state)
+{
+	g_return_if_fail (VTE_IS_TERMINAL (terminal));
+
+	state = !!state;
+
+	if (state != terminal->pvt->expand_scrollback) {
+		terminal->pvt->expand_scrollback = state;
+		if (!state) {
+			vte_terminal_set_scrollback_lines(terminal,
+					terminal->pvt->scrollback_lines);
+		}
+	}
+}
+
+/**
  * vte_terminal_set_word_chars:
  * @terminal: a #VteTerminal
  * @spec: a specification
