diff --git a/src/vte.cc b/src/vte.cc
index 292725c..8d35b29 100644
--- a/src/vte.cc
+++ b/src/vte.cc
@@ -390,14 +390,14 @@ _vte_invalidate_cells(VteTerminal *terminal,
 	_vte_debug_print (VTE_DEBUG_UPDATES,
 			"Invalidating cells at (%ld,%ld+%ld)x(%d,%d).\n",
 			column_start, row_start,
-			(long)terminal->pvt->screen->scroll_delta,
+			(long)terminal->pvt->screen->scroll_delta_px,
 			column_count, row_count);
 	_vte_debug_print (VTE_DEBUG_WORK, "?");
 
 	/* Subtract the scrolling offset from the row start so that the
 	 * resulting rectangle is relative to the visible portion of the
 	 * buffer. */
-	row_start -= terminal->pvt->screen->scroll_delta;
+	row_start -= terminal->pvt->screen->scroll_delta_px / terminal->pvt->char_height;
 
 	/* Ensure the start of region is on screen */
 	if (column_start > terminal->pvt->column_count ||
@@ -1121,9 +1121,9 @@ vte_terminal_match_contents_refresh(VteTerminal *terminal)
         long start_row, start_col, end_row, end_col;
         int context_lines = 3;
         /* Include 3 more lines in both directions. */
-        start_row = terminal->pvt->screen->scroll_delta - context_lines;
+        start_row = terminal->pvt->screen->scroll_delta_px / terminal->pvt->char_height - context_lines;
         start_col = 0;
-        end_row = terminal->pvt->screen->scroll_delta + terminal->pvt->row_count - 1 + context_lines;
+        end_row = terminal->pvt->screen->scroll_delta_px / terminal->pvt->char_height + terminal->pvt->row_count - 1 + context_lines;
         end_col = terminal->pvt->column_count - 1;
 	vte_terminal_match_contents_clear(terminal);
 	array = g_array_new(FALSE, TRUE, sizeof(struct _VteCharAttributes));
@@ -1682,7 +1682,7 @@ vte_terminal_match_check(VteTerminal *terminal, glong column, glong row,
 	long delta;
 	char *ret;
 	g_return_val_if_fail(VTE_IS_TERMINAL(terminal), NULL);
-	delta = terminal->pvt->screen->scroll_delta;
+	delta = terminal->pvt->screen->scroll_delta_px / terminal->pvt->char_height;
 	_vte_debug_print(VTE_DEBUG_EVENTS,
 			"Checking for match at (%ld,%ld).\n",
 			row, column);
@@ -1756,7 +1756,7 @@ vte_terminal_emit_adjustment_changed(VteTerminal *terminal)
 
 		g_object_freeze_notify (G_OBJECT (terminal->pvt->vadjustment));
 
-		v = _vte_ring_delta (screen->row_data);
+		v = _vte_ring_delta (screen->row_data) * terminal->pvt->char_height;
 		current = gtk_adjustment_get_lower(terminal->pvt->vadjustment);
 		if (current != v) {
 			_vte_debug_print(VTE_DEBUG_ADJ,
@@ -1769,7 +1769,7 @@ vte_terminal_emit_adjustment_changed(VteTerminal *terminal)
 		/* The upper value is the number of rows which might be visible.  (Add
 		 * one to the cursor offset because it's zero-based.) */
 		v = MAX(_vte_ring_next(screen->row_data),
-                        terminal->pvt->cursor.row + 1);
+                        terminal->pvt->cursor.row + 1) * terminal->pvt->char_height;
 		current = gtk_adjustment_get_upper(terminal->pvt->vadjustment);
 		if (current != v) {
 			_vte_debug_print(VTE_DEBUG_ADJ,
@@ -1792,14 +1792,14 @@ vte_terminal_emit_adjustment_changed(VteTerminal *terminal)
 				"Emitting adjustment_value_changed.\n");
 		terminal->pvt->adjustment_value_changed_pending = FALSE;
 		v = round (gtk_adjustment_get_value(terminal->pvt->vadjustment));
-		if (v != terminal->pvt->screen->scroll_delta) {
+		if (v != terminal->pvt->screen->scroll_delta_px) {
 			/* this little dance is so that the scroll_delta is
 			 * updated immediately, but we still handled scrolling
 			 * via the adjustment - e.g. user interaction with the
 			 * scrollbar
 			 */
-			delta = terminal->pvt->screen->scroll_delta;
-			terminal->pvt->screen->scroll_delta = v;
+			delta = terminal->pvt->screen->scroll_delta_px;
+			terminal->pvt->screen->scroll_delta_px = v;
 			gtk_adjustment_set_value(terminal->pvt->vadjustment, delta);
 		}
 	}
@@ -1816,8 +1816,11 @@ vte_terminal_queue_adjustment_changed(VteTerminal *terminal)
 static void
 vte_terminal_queue_adjustment_value_changed(VteTerminal *terminal, glong v)
 {
-	if (v != terminal->pvt->screen->scroll_delta) {
-		terminal->pvt->screen->scroll_delta = v;
+	if (v != terminal->pvt->screen->scroll_delta_px) {
+		_vte_debug_print(VTE_DEBUG_ADJ,
+		                 "Adjustment value changed to %ld\n",
+		                 v);
+		terminal->pvt->screen->scroll_delta_px = v;
 		terminal->pvt->adjustment_value_changed_pending = TRUE;
 		add_update_timeout (terminal);
 	}
@@ -1831,7 +1834,7 @@ vte_terminal_queue_adjustment_value_changed_clamped(VteTerminal *terminal, glong
 	lower = gtk_adjustment_get_lower(terminal->pvt->vadjustment);
 	upper = gtk_adjustment_get_upper(terminal->pvt->vadjustment);
 
-	v = CLAMP(v, lower, MAX (lower, upper - terminal->pvt->row_count));
+	v = CLAMP(v, lower, MAX (lower, upper - terminal->pvt->row_count * terminal->pvt->char_height));
 
 	vte_terminal_queue_adjustment_value_changed (terminal, v);
 }
@@ -1858,9 +1861,9 @@ _vte_terminal_adjust_adjustments(VteTerminal *terminal)
         terminal->pvt->cursor.row = MAX(terminal->pvt->cursor.row,
                                         screen->insert_delta);
 
-	if (screen->scroll_delta > screen->insert_delta) {
+	if (screen->scroll_delta_px > screen->insert_delta * terminal->pvt->char_height) {
 		vte_terminal_queue_adjustment_value_changed(terminal,
-				screen->insert_delta);
+				screen->insert_delta * terminal->pvt->char_height);
 	}
 }
 
@@ -1889,28 +1892,28 @@ _vte_terminal_adjust_adjustments_full (VteTerminal *terminal)
 		changed = TRUE;
 	}
 
-	/* Set the number of rows the user sees to the number of rows the
+	/* Set the number of pixels the user sees to the number of pixels the
 	 * user sees. */
 	v = gtk_adjustment_get_page_size(terminal->pvt->vadjustment);
-	if (v != terminal->pvt->row_count) {
+	if (v != terminal->pvt->row_count * terminal->pvt->char_height) {
 		_vte_debug_print(VTE_DEBUG_ADJ,
 				"Changing page size from %.0f to %ld\n",
-				 v, terminal->pvt->row_count);
+				 v, terminal->pvt->row_count * terminal->pvt->char_height);
 		gtk_adjustment_set_page_size(terminal->pvt->vadjustment,
-					     terminal->pvt->row_count);
+					     terminal->pvt->row_count * terminal->pvt->char_height);
 		changed = TRUE;
 	}
 
 	/* Clicking in the empty area should scroll one screen, so set the
-	 * page size to the number of visible rows. */
+	 * page size to the number of visible pixels. */
 	v = gtk_adjustment_get_page_increment(terminal->pvt->vadjustment);
-	if (v != terminal->pvt->row_count) {
+	if (v != terminal->pvt->row_count * terminal->pvt->char_height) {
 		_vte_debug_print(VTE_DEBUG_ADJ,
 				"Changing page increment from "
 				"%.0f to %ld\n",
-				v, terminal->pvt->row_count);
+				v, terminal->pvt->row_count * terminal->pvt->char_height);
 		gtk_adjustment_set_page_increment(terminal->pvt->vadjustment,
-						  terminal->pvt->row_count);
+						  terminal->pvt->row_count * terminal->pvt->char_height);
 		changed = TRUE;
 	}
 
@@ -1928,8 +1931,8 @@ vte_terminal_scroll_lines(VteTerminal *terminal, gint lines)
 	glong destination;
 	_vte_debug_print(VTE_DEBUG_ADJ, "Scrolling %d lines.\n", lines);
 	/* Calculate the ideal position where we want to be before clamping. */
-	destination = terminal->pvt->screen->scroll_delta;
-	destination += lines;
+	destination = terminal->pvt->screen->scroll_delta_px;
+	destination += lines * terminal->pvt->char_height;
 	/* Tell the scrollbar to adjust itself. */
 	vte_terminal_queue_adjustment_value_changed_clamped (terminal, destination);
 }
@@ -1946,14 +1949,14 @@ static void
 vte_terminal_maybe_scroll_to_top(VteTerminal *terminal)
 {
 	vte_terminal_queue_adjustment_value_changed (terminal,
-			_vte_ring_delta(terminal->pvt->screen->row_data));
+			_vte_ring_delta(terminal->pvt->screen->row_data) * terminal->pvt->char_height);
 }
 
 static void
 vte_terminal_maybe_scroll_to_bottom(VteTerminal *terminal)
 {
 	glong delta;
-	delta = terminal->pvt->screen->insert_delta;
+	delta = terminal->pvt->screen->insert_delta * terminal->pvt->char_height;
 	vte_terminal_queue_adjustment_value_changed (terminal, delta);
 	_vte_debug_print(VTE_DEBUG_ADJ,
 			"Snapping to bottom of screen\n");
@@ -3045,7 +3048,7 @@ _vte_terminal_drop_scrollback (VteTerminal *terminal)
                                    terminal->pvt->normal_screen.insert_delta);
 
         if (terminal->pvt->screen == &terminal->pvt->normal_screen) {
-                vte_terminal_queue_adjustment_value_changed (terminal, terminal->pvt->normal_screen.insert_delta);
+                vte_terminal_queue_adjustment_value_changed (terminal, terminal->pvt->normal_screen.insert_delta * terminal->pvt->char_height);
                 _vte_terminal_adjust_adjustments_full (terminal);
         }
 }
@@ -3732,7 +3735,7 @@ vte_terminal_process_incoming(VteTerminal *terminal)
 
 	screen = terminal->pvt->screen;
 
-	delta = screen->scroll_delta;
+	delta = screen->scroll_delta_px / terminal->pvt->char_height;
 	bottom = screen->insert_delta == delta;
 
 	/* Save the current cursor position. */
@@ -3854,7 +3857,7 @@ skip_chunk:
                             && (terminal->pvt->cursor.row >= (screen->insert_delta + terminal->pvt->scrolling_region.start))
                             && (terminal->pvt->cursor.row <= (screen->insert_delta + terminal->pvt->scrolling_region.end));
 
-			delta = screen->scroll_delta;	/* delta may have changed from sequence. */
+			delta = screen->scroll_delta_px / terminal->pvt->char_height;	/* delta may have changed from sequence. */
 
 			/* if we have moved greatly during the sequence handler, or moved
                          * into a scroll_region from outside it, restart the bbox.
@@ -5815,7 +5818,7 @@ cursor_inside_match (VteTerminal *terminal, long x, long y)
 	gint width = terminal->pvt->char_width;
 	gint height = terminal->pvt->char_height;
 	glong col = x / width;
-	glong row = y / height + terminal->pvt->screen->scroll_delta;
+	glong row = y / height + terminal->pvt->screen->scroll_delta_px / terminal->pvt->char_height;
 	if (terminal->pvt->match_start.row == terminal->pvt->match_end.row) {
 		return row == terminal->pvt->match_start.row &&
 			col >= terminal->pvt->match_start.col &&
@@ -5879,7 +5882,7 @@ vte_terminal_match_hilite_update(VteTerminal *terminal, long x, long y)
 
 	/* Check for matches. */
 	screen = terminal->pvt->screen;
-	delta = screen->scroll_delta;
+	delta = screen->scroll_delta_px / height;
 
 	_vte_debug_print(VTE_DEBUG_EVENTS,
 			"Match hilite update (%ld, %ld) -> %ld, %ld\n",
@@ -6286,7 +6289,7 @@ vte_terminal_get_text_maybe_wrapped(VteTerminal *terminal,
 				    gboolean include_trailing_spaces)
 {
 	long start_row, start_col, end_row, end_col;
-	start_row = terminal->pvt->screen->scroll_delta;
+	start_row = terminal->pvt->screen->scroll_delta_px / terminal->pvt->char_height;
 	start_col = 0;
 	end_row = start_row + terminal->pvt->row_count - 1;
 	end_col = terminal->pvt->column_count - 1;
@@ -6688,7 +6691,7 @@ vte_terminal_start_selection(VteTerminal *terminal, long x, long y,
 	vte_terminal_confine_coordinates(terminal, &x, &y);
 
 	/* Record that we have the selection, and where it started. */
-	delta = terminal->pvt->screen->scroll_delta;
+	delta = terminal->pvt->screen->scroll_delta_px / terminal->pvt->char_height;
 	terminal->pvt->has_selection = TRUE;
 	terminal->pvt->selection_last.x = x;
 	terminal->pvt->selection_last.y = y + (terminal->pvt->char_height * delta);
@@ -6992,7 +6995,7 @@ vte_terminal_extend_selection(VteTerminal *terminal, long x, long y,
 	eo = &old_end;
 
 	/* Convert the event coordinates to cell coordinates. */
-	delta = screen->scroll_delta;
+	delta = screen->scroll_delta_px / height;
 
 	/* If we're restarting on a drag, then mark this as the start of
 	 * the selected block. */
@@ -7255,7 +7258,7 @@ vte_terminal_autoscroll(VteTerminal *terminal)
 	if (terminal->pvt->mouse_last_y < 0) {
 		if (terminal->pvt->vadjustment) {
 			/* Try to scroll up by one line. */
-			adj = terminal->pvt->screen->scroll_delta - 1;
+			adj = terminal->pvt->screen->scroll_delta_px - terminal->pvt->char_height;
 			vte_terminal_queue_adjustment_value_changed_clamped (terminal, adj);
 			extend = TRUE;
 		}
@@ -7265,7 +7268,7 @@ vte_terminal_autoscroll(VteTerminal *terminal)
 	    terminal->pvt->row_count * terminal->pvt->char_height) {
 		if (terminal->pvt->vadjustment) {
 			/* Try to scroll up by one line. */
-			adj = terminal->pvt->screen->scroll_delta + 1;
+			adj = terminal->pvt->screen->scroll_delta_px + terminal->pvt->char_height;
 			vte_terminal_queue_adjustment_value_changed_clamped (terminal, adj);
 			extend = TRUE;
 		}
@@ -7340,7 +7343,7 @@ vte_terminal_motion_notify(GtkWidget *widget, GdkEventMotion *event)
 	_vte_debug_print(VTE_DEBUG_EVENTS,
 			"Motion notify (%ld,%ld) [%ld, %ld].\n",
 			x, y,
-			x / width, y / height + terminal->pvt->screen->scroll_delta);
+			x / width, y / height + terminal->pvt->screen->scroll_delta_px);
 
 	vte_terminal_read_modifiers (terminal, (GdkEvent*) event);
 
@@ -7421,7 +7424,7 @@ vte_terminal_button_press(GtkWidget *widget, GdkEventButton *event)
 
 	height = terminal->pvt->char_height;
 	width = terminal->pvt->char_width;
-	delta = terminal->pvt->screen->scroll_delta;
+	delta = terminal->pvt->screen->scroll_delta_px / height;
 
 	vte_terminal_match_hilite(terminal, x, y);
 
@@ -7818,7 +7821,10 @@ vte_terminal_apply_metrics(VteTerminal *terminal,
 	}
 	if (height != terminal->pvt->char_height) {
 		resize = cresize = TRUE;
+		terminal->pvt->normal_screen.scroll_delta_px = terminal->pvt->normal_screen.scroll_delta_px / terminal->pvt->char_height * height;
+		terminal->pvt->alternate_screen.scroll_delta_px = terminal->pvt->alternate_screen.scroll_delta_px / terminal->pvt->char_height * height;
 		terminal->pvt->char_height = height;
+		_vte_terminal_adjust_adjustments_full (terminal);
 	}
 	if (ascent != terminal->pvt->char_ascent) {
 		resize = TRUE;
@@ -8055,10 +8061,10 @@ vte_terminal_screen_set_size(VteTerminal *terminal, VteScreen *screen, glong old
 	VteVisualPosition below_viewport;
 	VteVisualPosition below_current_paragraph;
 	VteVisualPosition *markers[7];
-	gboolean was_scrolled_to_top = (screen->scroll_delta == _vte_ring_delta(ring));
-	gboolean was_scrolled_to_bottom = (screen->scroll_delta == screen->insert_delta);
+	gboolean was_scrolled_to_top = (screen->scroll_delta_px == _vte_ring_delta(ring) * terminal->pvt->char_height);
+	gboolean was_scrolled_to_bottom = (screen->scroll_delta_px == screen->insert_delta * terminal->pvt->char_height);
 	glong old_top_lines;
-	glong new_scroll_delta;
+	glong new_scroll_delta_px;
 
         if (terminal->pvt->selection_block_mode && do_rewrap && old_columns != terminal->pvt->column_count)
                 vte_terminal_deselect_all(terminal);
@@ -8066,16 +8072,16 @@ vte_terminal_screen_set_size(VteTerminal *terminal, VteScreen *screen, glong old
 	_vte_debug_print(VTE_DEBUG_RESIZE,
 			"Resizing %s screen\n"
 			"Old  insert_delta=%ld  scroll_delta=%ld\n"
-                        "     cursor (absolute)  row=%ld  (visual line %ld)  col=%ld\n"
+                        "     cursor (absolute)  row=%ld  col=%ld\n"
 			"     cursor_saved (relative to insert_delta)  row=%ld  col=%ld\n",
 			screen == &terminal->pvt->normal_screen ? "normal" : "alternate",
-			screen->insert_delta, screen->scroll_delta,
-                        terminal->pvt->cursor.row, terminal->pvt->cursor.row - screen->scroll_delta + 1, terminal->pvt->cursor.col,
+			screen->insert_delta, screen->scroll_delta_px,
+                        terminal->pvt->cursor.row, terminal->pvt->cursor.col,
                         screen->saved.cursor.row, screen->saved.cursor.col);
 
         cursor_saved_absolute.row = screen->saved.cursor.row + screen->insert_delta;
         cursor_saved_absolute.col = screen->saved.cursor.col;
-	below_viewport.row = screen->scroll_delta + old_rows;
+	below_viewport.row = screen->scroll_delta_px / terminal->pvt->char_height + old_rows;
 	below_viewport.col = 0;
         below_current_paragraph.row = terminal->pvt->cursor.row + 1;
 	while (below_current_paragraph.row < _vte_ring_next(ring)
@@ -8131,7 +8137,7 @@ vte_terminal_screen_set_size(VteTerminal *terminal, VteScreen *screen, glong old
 	if (_vte_ring_length(ring) <= terminal->pvt->row_count) {
 		/* Everything fits without scrollbars. Align at top. */
 		screen->insert_delta = _vte_ring_delta(ring);
-		new_scroll_delta = screen->insert_delta;
+		new_scroll_delta_px = screen->insert_delta * terminal->pvt->char_height;
 		_vte_debug_print(VTE_DEBUG_RESIZE,
 				"Everything fits without scrollbars\n");
 	} else {
@@ -8139,12 +8145,12 @@ vte_terminal_screen_set_size(VteTerminal *terminal, VteScreen *screen, glong old
 		screen->insert_delta = _vte_ring_next(ring) - terminal->pvt->row_count;
 		if (was_scrolled_to_bottom) {
 			/* Was scrolled to bottom, keep this way. */
-			new_scroll_delta = screen->insert_delta;
+			new_scroll_delta_px = screen->insert_delta * terminal->pvt->char_height;
 			_vte_debug_print(VTE_DEBUG_RESIZE,
 					"Scroll to bottom\n");
 		} else if (was_scrolled_to_top) {
 			/* Was scrolled to top, keep this way. Not sure if this special case is worth it. */
-			new_scroll_delta = _vte_ring_delta(ring);
+			new_scroll_delta_px = _vte_ring_delta(ring) * terminal->pvt->char_height;
 			_vte_debug_print(VTE_DEBUG_RESIZE,
 					"Scroll to top\n");
 		} else {
@@ -8155,7 +8161,8 @@ vte_terminal_screen_set_size(VteTerminal *terminal, VteScreen *screen, glong old
 			   line break will stay there.
 			   TODO: What would be the best behavior if the bottom of the screen is a
 			   soft line break, i.e. only a partial line is visible at the bottom? */
-			new_scroll_delta = below_viewport.row - terminal->pvt->row_count;
+			new_scroll_delta_px = (below_viewport.row - terminal->pvt->row_count) * terminal->pvt->char_height +
+			                      screen->scroll_delta_px % terminal->pvt->char_height;
 			_vte_debug_print(VTE_DEBUG_RESIZE,
 					"Scroll so bottom row stays\n");
 		}
@@ -8168,18 +8175,18 @@ vte_terminal_screen_set_size(VteTerminal *terminal, VteScreen *screen, glong old
 
 	_vte_debug_print(VTE_DEBUG_RESIZE,
 			"New  insert_delta=%ld  scroll_delta=%ld\n"
-                        "     cursor (absolute)  row=%ld  (visual line %ld)  col=%ld\n"
+                        "     cursor (absolute)  row=%ld  col=%ld\n"
 			"     cursor_saved (relative to insert_delta)  row=%ld  col=%ld\n\n",
-			screen->insert_delta, new_scroll_delta,
-                        terminal->pvt->cursor.row, terminal->pvt->cursor.row - new_scroll_delta + 1, terminal->pvt->cursor.col,
+			screen->insert_delta, new_scroll_delta_px,
+                        terminal->pvt->cursor.row, terminal->pvt->cursor.col,
                         screen->saved.cursor.row, screen->saved.cursor.col);
 
 	if (screen == terminal->pvt->screen)
 		vte_terminal_queue_adjustment_value_changed (
 				terminal,
-				new_scroll_delta);
+				new_scroll_delta_px);
 	else
-		screen->scroll_delta = new_scroll_delta;
+		screen->scroll_delta_px = new_scroll_delta_px;
 }
 
 /**
@@ -8259,8 +8266,8 @@ vte_terminal_handle_scroll(VteTerminal *terminal)
 
 	/* Read the new adjustment value and save the difference. */
 	adj = round (gtk_adjustment_get_value(terminal->pvt->vadjustment));
-	dy = adj - screen->scroll_delta;
-	screen->scroll_delta = adj;
+	dy = adj - screen->scroll_delta_px;
+	screen->scroll_delta_px = adj;
 
 	/* Sanity checks. */
         if (G_UNLIKELY(!gtk_widget_get_realized(&terminal->widget)))
@@ -8272,7 +8279,7 @@ vte_terminal_handle_scroll(VteTerminal *terminal)
 	if (dy != 0) {
 		_vte_debug_print(VTE_DEBUG_ADJ,
 			    "Scrolling by %ld\n", dy);
-		_vte_terminal_scroll_region(terminal, screen->scroll_delta,
+		_vte_terminal_scroll_region(terminal, screen->scroll_delta_px,
 					   terminal->pvt->row_count, -dy);
 		vte_terminal_emit_text_scrolled(terminal, dy);
 		_vte_terminal_queue_contents_changed(terminal);
@@ -9877,7 +9884,7 @@ vte_terminal_expand_region (VteTerminal *terminal, cairo_region_t *region, const
 	 * inclusion of neighbouring cells */
 	row = MAX(0, (area->y - terminal->pvt->padding.top - 1) / height);
 	row_stop = MIN(howmany(area->height + area->y - terminal->pvt->padding.top + 1, height),
-		       terminal->pvt->row_count);
+		       terminal->pvt->row_count) + 1; // FIXME
 	if (row_stop <= row) {
 		return;
 	}
@@ -9921,7 +9928,7 @@ vte_terminal_paint_area (VteTerminal *terminal, const GdkRectangle *area)
 
 	row = MAX(0, (area->y - terminal->pvt->padding.top) / height);
 	row_stop = MIN((area->height + area->y - terminal->pvt->padding.top) / height,
-		       terminal->pvt->row_count);
+		       terminal->pvt->row_count) + 1; // FIXME
 	if (row_stop <= row) {
 		return;
 	}
@@ -9945,13 +9952,13 @@ vte_terminal_paint_area (VteTerminal *terminal, const GdkRectangle *area)
 
 	/* Now we're ready to draw the text.  Iterate over the rows we
 	 * need to draw. */
-	delta = screen->scroll_delta;
+	delta = screen->scroll_delta_px / height;
 	vte_terminal_draw_rows(terminal,
 			      screen,
 			      row + delta, row_stop - row,
 			      col, col_stop - col,
 			      col * width,
-			      row * height,
+			      row * height - screen->scroll_delta_px % height,
 			      width,
 			      height);
 }
@@ -9973,12 +9980,12 @@ vte_terminal_paint_cursor(VteTerminal *terminal)
 		return;
 
 	screen = terminal->pvt->screen;
-	delta = screen->scroll_delta;
+	width = terminal->pvt->char_width;
+	height = terminal->pvt->char_height;
+	delta = screen->scroll_delta_px / height;
         col = terminal->pvt->cursor.col;
         drow = terminal->pvt->cursor.row;
 	row = drow - delta;
-	width = terminal->pvt->char_width;
-	height = terminal->pvt->char_height;
 
 	if ((CLAMP(col, 0, terminal->pvt->column_count - 1) != col) ||
 	    (CLAMP(row, 0, terminal->pvt->row_count    - 1) != row))
@@ -10113,7 +10120,7 @@ vte_terminal_paint_im_preedit_string(VteTerminal *terminal)
 	/* Keep local copies of rendering information. */
 	width = terminal->pvt->char_width;
 	height = terminal->pvt->char_height;
-	delta = screen->scroll_delta;
+	delta = screen->scroll_delta_px / height;
 
         row = terminal->pvt->cursor.row - delta;
 
@@ -10393,7 +10400,7 @@ vte_terminal_scroll(GtkWidget *widget, GdkEventScroll *event)
 		g_free (normal);
 	} else {
 		/* Perform a history scroll. */
-		cnt += terminal->pvt->screen->scroll_delta;
+		cnt += terminal->pvt->screen->scroll_delta_px;
 		vte_terminal_queue_adjustment_value_changed_clamped (terminal, cnt);
 	}
 
@@ -12019,7 +12026,7 @@ vte_terminal_set_scrollback_lines(VteTerminal *terminal, glong lines)
 {
         VteTerminalPrivate *pvt;
         GObject *object;
-        glong scroll_delta, low, high, next;
+        glong scroll_delta_px, low, high, next;
 	VteScreen *screen;
 
 	g_return_if_fail(VTE_IS_TERMINAL(terminal));
@@ -12052,7 +12059,7 @@ vte_terminal_set_scrollback_lines(VteTerminal *terminal, glong lines)
         low = _vte_ring_delta (screen->row_data);
         high = lines + MIN (G_MAXLONG - lines, low - terminal->pvt->row_count + 1);
         screen->insert_delta = CLAMP (screen->insert_delta, low, high);
-        screen->scroll_delta = CLAMP (screen->scroll_delta, low, screen->insert_delta);
+        screen->scroll_delta_px = CLAMP (screen->scroll_delta_px, low * pvt->char_height, screen->insert_delta * pvt->char_height);
         next = MIN (next, screen->insert_delta + terminal->pvt->row_count);
         if (_vte_ring_next (screen->row_data) > next){
                 _vte_ring_shrink (screen->row_data, next - low);
@@ -12061,8 +12068,8 @@ vte_terminal_set_scrollback_lines(VteTerminal *terminal, glong lines)
         /* The alternate screen isn't allowed to scroll at all. */
         screen = &terminal->pvt->alternate_screen;
         _vte_ring_resize (screen->row_data, terminal->pvt->row_count);
-        screen->scroll_delta = _vte_ring_delta (screen->row_data);
         screen->insert_delta = _vte_ring_delta (screen->row_data);
+        screen->scroll_delta_px = _vte_ring_delta (screen->row_data) * pvt->char_height;
         if (_vte_ring_next (screen->row_data) > screen->insert_delta + terminal->pvt->row_count){
                 _vte_ring_shrink (screen->row_data, terminal->pvt->row_count);
         }
@@ -12070,9 +12077,9 @@ vte_terminal_set_scrollback_lines(VteTerminal *terminal, glong lines)
 	/* Adjust the scrollbar to the new location. */
 	/* Hack: force a change in scroll_delta even if the value remains, so that
 	   vte_term_q_adj_val_changed() doesn't shortcut to no-op, see bug 676075. */
-        scroll_delta = terminal->pvt->screen->scroll_delta;
-	terminal->pvt->screen->scroll_delta = -1;
-	vte_terminal_queue_adjustment_value_changed (terminal, scroll_delta);
+        scroll_delta_px = terminal->pvt->screen->scroll_delta_px;
+	terminal->pvt->screen->scroll_delta_px = -1;
+	vte_terminal_queue_adjustment_value_changed (terminal, scroll_delta_px);
 	_vte_terminal_adjust_adjustments_full (terminal);
 
         g_object_notify(object, "scrollback-lines");
@@ -12243,16 +12250,18 @@ vte_terminal_reset(VteTerminal *terminal,
 	/* Clear the scrollback buffers and reset the cursors. Switch to normal screen. */
 	if (clear_history) {
                 pvt->screen = &pvt->normal_screen;
-                pvt->normal_screen.scroll_delta = pvt->normal_screen.insert_delta =
+                pvt->normal_screen.insert_delta =
                         _vte_ring_reset(pvt->normal_screen.row_data);
-                pvt->alternate_screen.scroll_delta = pvt->alternate_screen.insert_delta =
+		pvt->normal_screen.scroll_delta_px = pvt->normal_screen.insert_delta * pvt->char_height;
+                pvt->alternate_screen.insert_delta =
                         _vte_ring_reset(pvt->alternate_screen.row_data);
+		pvt->alternate_screen.scroll_delta_px = pvt->alternate_screen.insert_delta * pvt->char_height;
                 pvt->cursor.row = pvt->screen->insert_delta;
                 pvt->cursor.col = 0;
                 /* Adjust the scrollbar to the new location. */
                 /* Hack: force a change in scroll_delta even if the value remains, so that
                    vte_term_q_adj_val_changed() doesn't shortcut to no-op, see bug 730599. */
-                pvt->screen->scroll_delta = -1;
+                pvt->screen->scroll_delta_px = -1;
                 vte_terminal_queue_adjustment_value_changed (terminal, pvt->screen->insert_delta);
 		_vte_terminal_adjust_adjustments_full (terminal);
 	}
@@ -13442,8 +13451,8 @@ vte_terminal_search_find (VteTerminal *terminal,
 		last_start_row = pvt->selection_start.row;
 		last_end_row = pvt->selection_end.row + 1;
 	} else {
-		last_start_row = pvt->screen->scroll_delta + terminal->pvt->row_count;
-		last_end_row = pvt->screen->scroll_delta;
+		last_start_row = pvt->screen->scroll_delta_px / pvt->char_height + terminal->pvt->row_count;
+		last_end_row = pvt->screen->scroll_delta_px / pvt->char_height;
 	}
 	last_start_row = MAX (buffer_start_row, last_start_row);
 	last_end_row = MIN (buffer_end_row, last_end_row);
diff --git a/src/vteinternal.hh b/src/vteinternal.hh
index 04d8104..97c41ad 100644
--- a/src/vteinternal.hh
+++ b/src/vteinternal.hh
@@ -102,7 +102,7 @@ struct _vte_incoming_chunk{
 typedef struct _VteScreen VteScreen;
 struct _VteScreen {
         VteRing row_data[1];	/* buffer contents */
-        long scroll_delta;	/* scroll offset */
+        long scroll_delta_px;	/* scroll offset */
         long insert_delta;	/* insertion offset */
 
         /* Stuff saved along with the cursor */
diff --git a/src/vteseq.cc b/src/vteseq.cc
index af27ff5..3867667 100644
--- a/src/vteseq.cc
+++ b/src/vteseq.cc
@@ -928,7 +928,7 @@ vte_sequence_handler_decset_internal(VteTerminal *terminal,
 		}
 		/* Reset scrollbars and repaint everything. */
 		gtk_adjustment_set_value(terminal->pvt->vadjustment,
-					 terminal->pvt->screen->scroll_delta);
+					 terminal->pvt->screen->scroll_delta_px);
 		vte_terminal_set_scrollback_lines(terminal,
 				terminal->pvt->scrollback_lines);
 		_vte_terminal_queue_contents_changed(terminal);
