diff --git a/src/vte.cc b/src/vte.cc
index d603922..5ca06bf 100644
--- a/src/vte.cc
+++ b/src/vte.cc
@@ -663,8 +663,8 @@ VteTerminalPrivate::invalidate_cursor_once(bool periodic)
 
 	if (m_cursor_visible) {
 		auto preedit_width = get_preedit_width(false);
-                auto row = m_cursor.row;
-                auto column = m_cursor.col;
+                auto row = m_screen->cursor.row;
+                auto column = m_screen->cursor.col;
 		long columns = 1;
 		column = find_start_column (m_terminal, column, row);
 
@@ -2200,8 +2200,8 @@ VteTerminalPrivate::adjust_adjustments()
 	 * area.  Leave the scrolling delta alone because it will be updated
 	 * when the adjustment changes. */
 	screen->insert_delta = MAX(m_screen->insert_delta, delta);
-        m_cursor.row = MAX(m_cursor.row,
-                           m_screen->insert_delta);
+        m_screen->cursor.row = MAX(m_screen->cursor.row,
+                                   m_screen->insert_delta);
 
 	if (m_screen->scroll_delta > m_screen->insert_delta) {
 		queue_adjustment_value_changed(m_screen->insert_delta);
@@ -2420,13 +2420,13 @@ VteTerminalPrivate::ensure_row()
 
 	/* Figure out how many rows we need to add. */
         //FIXMEchpe use long, not int
-	int delta = m_cursor.row - _vte_ring_next(m_screen->row_data) + 1;
+	int delta = m_screen->cursor.row - _vte_ring_next(m_screen->row_data) + 1;
 	if (delta > 0) {
 		row = insert_rows(delta);
 		adjust_adjustments();
 	} else {
 		/* Find the row the cursor is in. */
-		row = _vte_ring_index_writable(m_screen->row_data, m_cursor.row);
+		row = _vte_ring_index_writable(m_screen->row_data, m_screen->cursor.row);
 	}
 	g_assert(row != NULL);
 
@@ -2437,7 +2437,7 @@ VteRowData *
 VteTerminalPrivate::ensure_cursor()
 {
 	VteRowData *row = ensure_row();
-        _vte_row_data_fill(row, &basic_cell.cell, m_cursor.col);
+        _vte_row_data_fill(row, &basic_cell.cell, m_screen->cursor.col);
 
 	return row;
 }
@@ -2450,7 +2450,7 @@ VteTerminalPrivate::update_insert_delta()
 	/* The total number of lines.  Add one to the cursor offset
 	 * because it's zero-based. */
 	auto rows = _vte_ring_next(m_screen->row_data);
-        auto delta = m_cursor.row - rows + 1;
+        auto delta = m_screen->cursor.row - rows + 1;
 	if (G_UNLIKELY (delta > 0)) {
 		insert_rows(delta);
 		rows = _vte_ring_next(m_screen->row_data);
@@ -2462,7 +2462,7 @@ VteTerminalPrivate::update_insert_delta()
 	delta = m_screen->insert_delta;
 	delta = MIN(delta, rows - m_row_count);
 	delta = MAX(delta,
-                    m_cursor.row - (m_row_count - 1));
+                    m_screen->cursor.row - (m_row_count - 1));
 	delta = MAX(delta, _vte_ring_delta(m_screen->row_data));
 
 	/* Adjust the insert delta and scroll if needed. */
@@ -3010,7 +3010,7 @@ VteTerminalPrivate::cleanup_fragments(long start,
                         cell_end->attr.columns = 1;
                         invalidate_cells(
                                               end, 1,
-                                              m_cursor.row, 1);
+                                              m_screen->cursor.row, 1);
                 }
         }
 
@@ -3036,7 +3036,7 @@ VteTerminalPrivate::cleanup_fragments(long start,
                                         g_assert(start - col == 1);
                                         invalidate_cells(
                                                               col, 1,
-                                                              m_cursor.row, 1);
+                                                              m_screen->cursor.row, 1);
                                 }
                                 keep_going = FALSE;
                         }
@@ -3060,19 +3060,19 @@ VteTerminalPrivate::cursor_down()
 		start = m_screen->insert_delta;
 		end = start + m_row_count - 1;
 	}
-        if (m_cursor.row == end) {
+        if (m_screen->cursor.row == end) {
                 if (m_scrolling_restricted) {
 			if (start == m_screen->insert_delta) {
 				/* Scroll this line into the scrollback
 				 * buffer by inserting a line at the next
 				 * line and scrolling the area up. */
 				m_screen->insert_delta++;
-                                m_cursor.row++;
+                                m_screen->cursor.row++;
 				/* update start and end, as they are relative
 				 * to insert_delta. */
 				start++;
 				end++;
-                                _vte_terminal_ring_insert(m_terminal, m_cursor.row, FALSE);
+                                _vte_terminal_ring_insert(m_terminal, m_screen->cursor.row, FALSE);
 				/* Force the areas below the region to be
 				 * redrawn -- they've moved. */
 				scroll_region(start,
@@ -3094,7 +3094,7 @@ VteTerminalPrivate::cursor_down()
 			}
 		} else {
 			/* Scroll up with history. */
-                        m_cursor.row++;
+                        m_screen->cursor.row++;
 			update_insert_delta();
 		}
 
@@ -3107,7 +3107,7 @@ VteTerminalPrivate::cursor_down()
 #endif
 	} else {
 		/* Otherwise, just move the cursor down. */
-                m_cursor.row++;
+                m_screen->cursor.row++;
 	}
 }
 
@@ -3129,9 +3129,9 @@ VteTerminalPrivate::drop_scrollback()
 void
 VteTerminalPrivate::restore_cursor(VteScreen *screen__)
 {
-        m_cursor.col = screen__->saved.cursor.col;
-        m_cursor.row = screen__->insert_delta + CLAMP(screen__->saved.cursor.row,
-                                                      0, m_row_count - 1);
+        screen__->cursor.col = screen__->saved.cursor.col;
+        screen__->cursor.row = screen__->insert_delta + CLAMP(screen__->saved.cursor.row,
+                                                              0, m_row_count - 1);
 
         m_reverse_mode = screen__->saved.reverse_mode;
         m_origin_mode = screen__->saved.origin_mode;
@@ -3150,8 +3150,8 @@ VteTerminalPrivate::restore_cursor(VteScreen *screen__)
 void
 VteTerminalPrivate::save_cursor(VteScreen *screen__)
 {
-        screen__->saved.cursor.col = m_cursor.col;
-        screen__->saved.cursor.row = m_cursor.row - screen__->insert_delta;
+        screen__->saved.cursor.col = screen__->cursor.col;
+        screen__->saved.cursor.row = screen__->cursor.row - screen__->insert_delta;
 
         screen__->saved.reverse_mode = m_reverse_mode;
         screen__->saved.origin_mode = m_origin_mode;
@@ -3230,21 +3230,21 @@ VteTerminalPrivate::insert_char(gunichar c,
         columns = _vte_unichar_width(c, m_utf8_ambiguous_width);
 
 	/* If we're autowrapping here, do it. */
-        col = m_cursor.col;
+        col = m_screen->cursor.col;
 	if (G_UNLIKELY (columns && col + columns > m_column_count)) {
 		if (m_autowrap) {
 			_vte_debug_print(VTE_DEBUG_ADJ,
 					"Autowrapping before character\n");
 			/* Wrap. */
 			/* XXX clear to the end of line */
-                        col = m_cursor.col = 0;
+                        col = m_screen->cursor.col = 0;
 			/* Mark this line as soft-wrapped. */
 			row = ensure_row();
 			row->attr.soft_wrapped = 1;
 			cursor_down();
 		} else {
 			/* Don't wrap, stay at the rightmost column. */
-                        col = m_cursor.col =
+                        col = m_screen->cursor.col =
 				m_column_count - columns;
 		}
 		line_wrapped = true;
@@ -3255,7 +3255,7 @@ VteTerminalPrivate::insert_char(gunichar c,
 			(long)c, c < 256 ? c : ' ',
                          (int)m_color_defaults.attr.fore,
                          (int)m_color_defaults.attr.back,
-                        col, columns, (long)m_cursor.row,
+                        col, columns, (long)m_screen->cursor.row,
 			(long)m_screen->insert_delta);
 
 	if (G_UNLIKELY (columns == 0)) {
@@ -3267,7 +3267,7 @@ VteTerminalPrivate::insert_char(gunichar c,
 
 		_vte_debug_print(VTE_DEBUG_PARSE, "combining U+%04X", c);
 
-                row_num = m_cursor.row;
+                row_num = m_screen->cursor.row;
 		row = NULL;
 		if (G_UNLIKELY (col == 0)) {
 			/* We are at first column.  See if the previous line softwrapped.
@@ -3367,10 +3367,10 @@ VteTerminalPrivate::insert_char(gunichar c,
 		invalidate_cells(
 				col - columns,
 				insert ? m_column_count : columns,
-                                m_cursor.row, 1);
+                                m_screen->cursor.row, 1);
 	}
 
-        m_cursor.col = col;
+        m_screen->cursor.col = col;
 
 done:
 	/* We added text, so make a note of it. */
@@ -3721,12 +3721,12 @@ VteTerminalPrivate::process_incoming()
         auto bottom_row = last_displayed_row();
 
 	/* Save the current cursor position. */
-        saved_cursor = m_cursor;
+        saved_cursor = m_screen->cursor;
 	saved_cursor_visible = m_cursor_visible;
 
         in_scroll_region = m_scrolling_restricted
-            && (m_cursor.row >= (m_screen->insert_delta + m_scrolling_region.start))
-            && (m_cursor.row <= (m_screen->insert_delta + m_scrolling_region.end));
+            && (m_screen->cursor.row >= (m_screen->insert_delta + m_scrolling_region.start))
+            && (m_screen->cursor.row <= (m_screen->insert_delta + m_scrolling_region.end));
 
 	/* We should only be called when there's data to process. */
 	g_assert(m_incoming ||
@@ -3835,8 +3835,8 @@ skip_chunk:
 			modified = TRUE;
 
                         new_in_scroll_region = m_scrolling_restricted
-                            && (m_cursor.row >= (screen->insert_delta + m_scrolling_region.start))
-                            && (m_cursor.row <= (screen->insert_delta + m_scrolling_region.end));
+                            && (m_screen->cursor.row >= (screen->insert_delta + m_scrolling_region.start))
+                            && (m_screen->cursor.row <= (screen->insert_delta + m_scrolling_region.end));
 
                         /* delta may have changed from sequence. */
                         top_row = first_displayed_row();
@@ -3847,10 +3847,10 @@ skip_chunk:
                          */
 			if (invalidated_text &&
 					((new_in_scroll_region && !in_scroll_region) ||
-                                         (m_cursor.col > bbox_bottomright.x + VTE_CELL_BBOX_SLACK ||
-                                          m_cursor.col < bbox_topleft.x - VTE_CELL_BBOX_SLACK     ||
-                                          m_cursor.row > bbox_bottomright.y + VTE_CELL_BBOX_SLACK ||
-                                          m_cursor.row < bbox_topleft.y - VTE_CELL_BBOX_SLACK))) {
+                                         (m_screen->cursor.col > bbox_bottomright.x + VTE_CELL_BBOX_SLACK ||
+                                          m_screen->cursor.col < bbox_topleft.x - VTE_CELL_BBOX_SLACK     ||
+                                          m_screen->cursor.row > bbox_bottomright.y + VTE_CELL_BBOX_SLACK ||
+                                          m_screen->cursor.row < bbox_topleft.y - VTE_CELL_BBOX_SLACK))) {
 				/* Clip off any part of the box which isn't already on-screen. */
 				bbox_topleft.x = MAX(bbox_topleft.x, 0);
                                 bbox_topleft.y = MAX(bbox_topleft.y, top_row);
@@ -3930,19 +3930,19 @@ skip_chunk:
 			}
 
 			bbox_topleft.x = MIN(bbox_topleft.x,
-                                        m_cursor.col);
+                                             m_screen->cursor.col);
 			bbox_topleft.y = MIN(bbox_topleft.y,
-                                        m_cursor.row);
+                                             m_screen->cursor.row);
 
 			/* Insert the character. */
                         // FIXMEchpe should not use UNLIKELY here
 			if (G_UNLIKELY(insert_char(c, false, false))) {
 				/* line wrapped, correct bbox */
 				if (invalidated_text &&
-                                                (m_cursor.col > bbox_bottomright.x + VTE_CELL_BBOX_SLACK	||
-                                                 m_cursor.col < bbox_topleft.x - VTE_CELL_BBOX_SLACK	||
-                                                 m_cursor.row > bbox_bottomright.y + VTE_CELL_BBOX_SLACK	||
-                                                 m_cursor.row < bbox_topleft.y - VTE_CELL_BBOX_SLACK)) {
+                                                (m_screen->cursor.col > bbox_bottomright.x + VTE_CELL_BBOX_SLACK	||
+                                                 m_screen->cursor.col < bbox_topleft.x - VTE_CELL_BBOX_SLACK	||
+                                                 m_screen->cursor.row > bbox_bottomright.y + VTE_CELL_BBOX_SLACK	||
+                                                 m_screen->cursor.row < bbox_topleft.y - VTE_CELL_BBOX_SLACK)) {
 					/* Clip off any part of the box which isn't already on-screen. */
 					bbox_topleft.x = MAX(bbox_topleft.x, 0);
                                         bbox_topleft.y = MAX(bbox_topleft.y, top_row);
@@ -3963,15 +3963,15 @@ skip_chunk:
 				}
 				bbox_topleft.x = MIN(bbox_topleft.x, 0);
 				bbox_topleft.y = MIN(bbox_topleft.y,
-                                                     m_cursor.row);
+                                                     m_screen->cursor.row);
 			}
 			/* Add the cells over which we have moved to the region
 			 * which we need to refresh for the user. */
 			bbox_bottomright.x = MAX(bbox_bottomright.x,
-                                                 m_cursor.col);
+                                                 m_screen->cursor.col);
                         /* cursor.row + 1 (defer until inv.) */
 			bbox_bottomright.y = MAX(bbox_bottomright.y,
-                                                 m_cursor.row);
+                                                 m_screen->cursor.row);
 			invalidated_text = TRUE;
 
 			/* We *don't* emit flush pending signals here. */
@@ -4005,7 +4005,7 @@ skip_chunk:
 			 _vte_ring_delta(screen->row_data));
 		/* The cursor shouldn't be above or below the addressable
 		 * part of the display buffer. */
-                g_assert(m_cursor.row >= m_screen->insert_delta);
+                g_assert(screen->cursor.row >= screen->insert_delta);
 #endif
 
 next_match:
@@ -4072,8 +4072,8 @@ next_match:
 	}
 
 
-        if ((saved_cursor.col != m_cursor.col) ||
-            (saved_cursor.row != m_cursor.row)) {
+        if ((saved_cursor.col != m_screen->cursor.col) ||
+            (saved_cursor.row != m_screen->cursor.row)) {
 		/* invalidate the old and new cursor positions */
 		if (cursor_visible)
 			invalidate_cell(saved_cursor.col, saved_cursor.row);
@@ -4089,10 +4089,9 @@ next_match:
 	/* Tell the input method where the cursor is. */
 	if (widget_realized()) {
 		GdkRectangle rect;
-                rect.x = m_cursor.col *
-			 m_char_width + m_padding.left;
+                rect.x = m_screen->cursor.col * m_char_width + m_padding.left;
 		rect.width = m_char_width; // FIXMEchpe: if columns > 1 ?
-                rect.y = row_to_pixel(m_cursor.row) + m_padding.top;
+                rect.y = row_to_pixel(m_screen->cursor.row) + m_padding.top;
 		rect.height = m_char_height;
 		gtk_im_context_set_cursor_location(m_im_context,
 						   &rect);
@@ -4856,7 +4855,7 @@ VteTerminalPrivate::widget_key_press(GdkEventKey *event)
 		/* If we're in margin bell mode and on the border of the
 		 * margin, bell. */
 		if (m_margin_bell) {
-                        if ((m_cursor.col +
+                        if ((m_screen->cursor.col +
 			     (glong) m_bell_margin) == m_column_count) {
 				beep();
 			}
@@ -7771,14 +7770,14 @@ VteTerminalPrivate::screen_set_size(VteScreen *screen_,
 			"     cursor_saved (relative to insert_delta)  row=%ld  col=%ld\n",
 			screen_ == &m_normal_screen ? "normal" : "alternate",
 			screen_->insert_delta, screen_->scroll_delta,
-                        m_cursor.row, m_cursor.col,
+                        screen_->cursor.row, screen_->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.col = 0;
-        below_current_paragraph.row = m_cursor.row + 1;
+        below_current_paragraph.row = screen_->cursor.row + 1;
 	while (below_current_paragraph.row < _vte_ring_next(ring)
 	    && _vte_ring_index(ring, below_current_paragraph.row - 1)->attr.soft_wrapped) {
 		below_current_paragraph.row++;
@@ -7788,15 +7787,12 @@ VteTerminalPrivate::screen_set_size(VteScreen *screen_,
         markers[0] = &cursor_saved_absolute;
         markers[1] = &below_viewport;
         markers[2] = &below_current_paragraph;
-        if (screen_ == m_screen) {
-                /* Tracking the current cursor only makes sense on the active screen_. */
-                markers[3] = &m_cursor;
-                if (m_has_selection) {
-                        /* selection_end is inclusive, make it non-inclusive, see bug 722635. */
-                        m_selection_end.col++;
-                        markers[4] = &m_selection_start;
-                        markers[5] = &m_selection_end;
-                }
+        markers[3] = &screen_->cursor;
+        if (m_has_selection) {
+                /* selection_end is inclusive, make it non-inclusive, see bug 722635. */
+                m_selection_end.col++;
+                markers[4] = &m_selection_start;
+                markers[5] = &m_selection_end;
 	}
 
 	old_top_lines = below_current_paragraph.row - screen_->insert_delta;
@@ -7824,7 +7820,7 @@ VteTerminalPrivate::screen_set_size(VteScreen *screen_,
 		}
 	}
 
-	if (screen_ == m_screen && m_has_selection) {
+	if (m_has_selection) {
 		/* Make selection_end inclusive again, see above. */
 		m_selection_end.col--;
 	}
@@ -7875,7 +7871,7 @@ VteTerminalPrivate::screen_set_size(VteScreen *screen_,
                         "     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,
-                        m_cursor.row, m_cursor.col,
+                        screen_->cursor.row, screen_->cursor.col,
                         screen_->saved.cursor.row, screen_->saved.cursor.col);
 
 	if (screen_ == m_screen)
@@ -7928,10 +7924,10 @@ VteTerminalPrivate::set_size(long columns,
                 vte_terminal_set_scrollback_lines(m_terminal,
                                                   m_scrollback_lines);
                 /* Ensure the cursor is valid */
-                m_cursor.row = CLAMP (m_cursor.row,
-                                                    _vte_ring_delta (m_screen->row_data),
-                                                    MAX (_vte_ring_delta (m_screen->row_data),
-                                                         _vte_ring_next (m_screen->row_data) - 1));
+                m_screen->cursor.row = CLAMP (m_screen->cursor.row,
+                                              _vte_ring_delta (m_screen->row_data),
+                                              MAX (_vte_ring_delta (m_screen->row_data),
+                                                   _vte_ring_next (m_screen->row_data) - 1));
 
 		adjust_adjustments_full();
 		gtk_widget_queue_resize_no_redraw(m_widget);
@@ -9557,8 +9553,8 @@ VteTerminalPrivate::paint_cursor()
         if (m_im_preedit_active)
                 return;
 
-        col = m_cursor.col;
-        drow = m_cursor.row;
+        col = m_screen->cursor.col;
+        drow = m_screen->cursor.row;
 	width = m_char_width;
 	height = m_char_height;
 
@@ -9690,7 +9686,7 @@ VteTerminalPrivate::paint_im_preedit_string()
 
 	/* If the pre-edit string won't fit on the screen if we start
 	 * drawing it at the cursor's position, move it left. */
-        col = m_cursor.col;
+        col = m_screen->cursor.col;
 	if (col + columns > m_column_count) {
 		col = MAX(0, m_column_count - columns);
 	}
@@ -9707,13 +9703,13 @@ VteTerminalPrivate::paint_im_preedit_string()
                         items[i].columns = _vte_unichar_width(items[i].c,
                                                               m_utf8_ambiguous_width);
 			items[i].x = (col + columns) * width;
-			items[i].y = row_to_pixel(m_cursor.row);
+			items[i].y = row_to_pixel(m_screen->cursor.row);
 			columns += items[i].columns;
 			preedit = g_utf8_next_char(preedit);
 		}
 		_vte_draw_clear(m_draw,
 				col * width,
-				row_to_pixel(m_cursor.row),
+				row_to_pixel(m_screen->cursor.row),
 				width * columns,
 				height,
                                 get_color(VTE_DEFAULT_BG), m_background_alpha);
@@ -10183,7 +10179,7 @@ VteTerminalPrivate::set_scrollback_lines(long lines)
         /* The main screen gets the full scrollback buffer. */
         scrn = &m_normal_screen;
         lines = MAX (lines, m_row_count);
-        next = MAX (m_cursor.row + 1,
+        next = MAX (m_screen->cursor.row + 1,
                     _vte_ring_next (scrn->row_data));
         _vte_ring_resize (scrn->row_data, lines);
         low = _vte_ring_delta (scrn->row_data);
@@ -10302,10 +10298,12 @@ VteTerminalPrivate::reset(bool clear_tabstops,
                 m_screen = &m_normal_screen;
                 m_normal_screen.scroll_delta = m_normal_screen.insert_delta =
                         _vte_ring_reset(m_normal_screen.row_data);
+                m_normal_screen.cursor.row = m_normal_screen.insert_delta;
+                m_normal_screen.cursor.col = 0;
                 m_alternate_screen.scroll_delta = m_alternate_screen.insert_delta =
                         _vte_ring_reset(m_alternate_screen.row_data);
-                m_cursor.row = m_screen->insert_delta;
-                m_cursor.col = 0;
+                m_alternate_screen.cursor.row = m_alternate_screen.insert_delta;
+                m_alternate_screen.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. */
diff --git a/src/vtegtk.cc b/src/vtegtk.cc
index 465407d..0c1a7b5 100644
--- a/src/vtegtk.cc
+++ b/src/vtegtk.cc
@@ -2152,10 +2152,10 @@ vte_terminal_get_cursor_position(VteTerminal *terminal,
 
         auto impl = IMPL(terminal);
 	if (column) {
-                *column = impl->m_cursor.col;
+                *column = impl->m_screen->cursor.col;
 	}
 	if (row) {
-                *row = impl->m_cursor.row;
+                *row = impl->m_screen->cursor.row;
 	}
 }
 
diff --git a/src/vteinternal.hh b/src/vteinternal.hh
index 812ff0b..c69715a 100644
--- a/src/vteinternal.hh
+++ b/src/vteinternal.hh
@@ -132,12 +132,13 @@ struct _vte_incoming_chunk{
 typedef struct _VteScreen VteScreen;
 struct _VteScreen {
         VteRing row_data[1];	/* buffer contents */
+        VteVisualPosition cursor;  /* absolute value, from the beginning of the terminal history */
         double scroll_delta;	/* scroll offset */
         long insert_delta;	/* insertion offset */
 
         /* Stuff saved along with the cursor */
         struct {
-                VteVisualPosition cursor;
+                VteVisualPosition cursor;  /* onscreen coordinate, that is, relative to insert_delta */
                 gboolean reverse_mode;
                 gboolean origin_mode;
                 gboolean sendrecv_mode;
@@ -331,7 +332,6 @@ public:
 #define m_screen screen
 
         /* Values we save along with the cursor */
-        VteVisualPosition cursor;	/* relative to the insertion delta */
         gboolean reverse_mode;	/* reverse mode */
         gboolean origin_mode;	/* origin mode */
         gboolean sendrecv_mode;	/* sendrecv mode */
@@ -1187,7 +1187,6 @@ public:
 #define m_draw draw
 #define m_cursor_blinks cursor_blinks
 #define m_cursor_visible cursor_visible
-#define m_cursor cursor
 #define m_cursor_blink_state cursor_blink_state
 #define m_cursor_blink_time cursor_blink_time
 #define m_cursor_blink_cycle cursor_blink_cycle
diff --git a/src/vteseq.cc b/src/vteseq.cc
index d00fafb..7fc153e 100644
--- a/src/vteseq.cc
+++ b/src/vteseq.cc
@@ -220,8 +220,8 @@ VteTerminalPrivate::emit_resize_window(guint columns,
 void
 VteTerminalPrivate::ensure_cursor_is_onscreen()
 {
-        if (G_UNLIKELY (m_cursor.col >= m_column_count))
-                m_cursor.col = m_column_count - 1;
+        if (G_UNLIKELY (m_screen->cursor.col >= m_column_count))
+                m_screen->cursor.col = m_column_count - 1;
 }
 
 void
@@ -234,7 +234,7 @@ VteTerminalPrivate::seq_home_cursor()
 void
 VteTerminalPrivate::seq_clear_screen()
 {
-        auto row = m_cursor.row - screen->insert_delta;
+        auto row = m_screen->cursor.row - screen->insert_delta;
         auto initial = _vte_ring_next(m_screen->row_data);
 	/* Add a new screen's worth of rows. */
         for (auto i = 0; i < m_row_count; i++)
@@ -242,7 +242,7 @@ VteTerminalPrivate::seq_clear_screen()
 	/* Move the cursor and insertion delta to the first line in the
 	 * newly-cleared area and scroll if need be. */
         m_screen->insert_delta = initial;
-        m_cursor.row = row + m_screen->insert_delta;
+        m_screen->cursor.row = row + m_screen->insert_delta;
         adjust_adjustments();
 	/* Redraw everything. */
         invalidate_all();
@@ -258,9 +258,9 @@ VteTerminalPrivate::seq_clear_current_line()
 
 	/* If the cursor is actually on the screen, clear data in the row
 	 * which corresponds to the cursor. */
-        if (_vte_ring_next(m_screen->row_data) > m_cursor.row) {
+        if (_vte_ring_next(m_screen->row_data) > m_screen->cursor.row) {
 		/* Get the data for the row which the cursor points to. */
-                rowdata = _vte_ring_index_writable(m_screen->row_data, m_cursor.row);
+                rowdata = _vte_ring_index_writable(m_screen->row_data, m_screen->cursor.row);
 		g_assert(rowdata != NULL);
 		/* Remove it. */
 		_vte_row_data_shrink (rowdata, 0);
@@ -269,7 +269,7 @@ VteTerminalPrivate::seq_clear_current_line()
 		rowdata->attr.soft_wrapped = 0;
 		/* Repaint this row. */
 		invalidate_cells(0, m_column_count,
-                                 m_cursor.row, 1);
+                                 m_screen->cursor.row, 1);
 	}
 
 	/* We've modified the display.  Make a note of it. */
@@ -282,7 +282,7 @@ VteTerminalPrivate::seq_clear_above_current()
 {
 	/* If the cursor is actually on the screen, clear data in the row
 	 * which corresponds to the cursor. */
-        for (auto i = m_screen->insert_delta; i < m_cursor.row; i++) {
+        for (auto i = m_screen->insert_delta; i < m_screen->cursor.row; i++) {
                 if (_vte_ring_next(m_screen->row_data) > i) {
 			/* Get the data for the row we're erasing. */
                         auto rowdata = _vte_ring_index_writable(m_screen->row_data, i);
@@ -385,9 +385,9 @@ VteTerminalPrivate::seq_switch_screen(VteScreen *new_screen)
         /* if (new_screen == m_screen) return; ? */
 
         /* cursor.row includes insert_delta, adjust accordingly */
-        m_cursor.row -= m_screen->insert_delta;
+        long cr = m_screen->cursor.row - m_screen->insert_delta;
         m_screen = new_screen;
-        m_cursor.row += m_screen->insert_delta;
+        m_screen->cursor.row = cr + m_screen->insert_delta;
 
         /* Make sure the ring is large enough */
         ensure_row();
@@ -557,7 +557,7 @@ vte_sequence_handler_multiple_r(VteTerminalPrivate *that,
                                 VteTerminalSequenceHandler handler)
 {
         vte_sequence_handler_multiple_limited(that, params, handler,
-                                              that->column_count - that->cursor.col);
+                                              that->column_count - that->m_screen->cursor.col);
 }
 
 static void
@@ -1027,7 +1027,7 @@ void
 VteTerminalPrivate::seq_cursor_back_tab()
 {
 	/* Calculate which column is the previous tab stop. */
-        auto newcol = m_cursor.col;
+        auto newcol = m_screen->cursor.col;
 
 	if (m_tabstops) {
 		/* Find the next tabstop. */
@@ -1054,12 +1054,12 @@ VteTerminalPrivate::seq_cb()
 	/* Get the data for the row which the cursor points to. */
 	auto rowdata = ensure_row();
         /* Clean up Tab/CJK fragments. */
-        cleanup_fragments(0, m_cursor.col + 1);
+        cleanup_fragments(0, m_screen->cursor.col + 1);
 	/* Clear the data up to the current column with the default
 	 * attributes.  If there is no such character cell, we need
 	 * to add one. */
         vte::grid::column_t i;
-        for (i = 0; i <= m_cursor.col; i++) {
+        for (i = 0; i <= m_screen->cursor.col; i++) {
                 if (i < (glong) _vte_row_data_length (rowdata)) {
 			/* Muck with the cell in this location. */
                         auto pcell = _vte_row_data_get_writable(rowdata, i);
@@ -1070,8 +1070,8 @@ VteTerminalPrivate::seq_cb()
 		}
 	}
 	/* Repaint this row. */
-        invalidate_cells(0, m_cursor.col+1,
-                         m_cursor.row, 1);
+        invalidate_cells(0, m_screen->cursor.col+1,
+                         m_screen->cursor.row, 1);
 
 	/* We've modified the display.  Make a note of it. */
         m_text_deleted_flag = TRUE;
@@ -1086,19 +1086,19 @@ VteTerminalPrivate::seq_cd()
 	/* If the cursor is actually on the screen, clear the rest of the
 	 * row the cursor is on and all of the rows below the cursor. */
         VteRowData *rowdata;
-        auto i = m_cursor.row;
+        auto i = m_screen->cursor.row;
 	if (i < _vte_ring_next(m_screen->row_data)) {
 		/* Get the data for the row we're clipping. */
                 rowdata = _vte_ring_index_writable(m_screen->row_data, i);
                 /* Clean up Tab/CJK fragments. */
-                if ((glong) _vte_row_data_length(rowdata) > m_cursor.col)
-                        cleanup_fragments(m_cursor.col, _vte_row_data_length(rowdata));
+                if ((glong) _vte_row_data_length(rowdata) > m_screen->cursor.col)
+                        cleanup_fragments(m_screen->cursor.col, _vte_row_data_length(rowdata));
 		/* Clear everything to the right of the cursor. */
 		if (rowdata)
-                        _vte_row_data_shrink(rowdata, m_cursor.col);
+                        _vte_row_data_shrink(rowdata, m_screen->cursor.col);
 	}
 	/* Now for the rest of the lines. */
-        for (i = m_cursor.row + 1;
+        for (i = m_screen->cursor.row + 1;
 	     i < _vte_ring_next(m_screen->row_data);
 	     i++) {
 		/* Get the data for the row we're removing. */
@@ -1108,7 +1108,7 @@ VteTerminalPrivate::seq_cd()
 			_vte_row_data_shrink (rowdata, 0);
 	}
 	/* Now fill the cleared areas. */
-        for (i = m_cursor.row;
+        for (i = m_screen->cursor.row;
 	     i < m_screen->insert_delta + m_row_count;
 	     i++) {
 		/* Retrieve the row's data, creating it if necessary. */
@@ -1147,12 +1147,12 @@ VteTerminalPrivate::seq_ce()
 	/* Get the data for the row which the cursor points to. */
         auto rowdata = ensure_row();
 	g_assert(rowdata != NULL);
-        if ((glong) _vte_row_data_length(rowdata) > m_cursor.col) {
+        if ((glong) _vte_row_data_length(rowdata) > m_screen->cursor.col) {
                 /* Clean up Tab/CJK fragments. */
-                cleanup_fragments(m_cursor.col, _vte_row_data_length(rowdata));
+                cleanup_fragments(m_screen->cursor.col, _vte_row_data_length(rowdata));
                 /* Remove the data at the end of the array until the current column
                  * is the end of the array. */
-                _vte_row_data_shrink(rowdata, m_cursor.col);
+                _vte_row_data_shrink(rowdata, m_screen->cursor.col);
 		/* We've modified the display.  Make a note of it. */
 		m_text_deleted_flag = TRUE;
 	}
@@ -1162,8 +1162,8 @@ VteTerminalPrivate::seq_ce()
 	}
 	rowdata->attr.soft_wrapped = 0;
 	/* Repaint this row. */
-	invalidate_cells(m_cursor.col, m_column_count - m_cursor.col,
-                         m_cursor.row, 1);
+	invalidate_cells(m_screen->cursor.col, m_column_count - m_screen->cursor.col,
+                         m_screen->cursor.row, 1);
 }
 
 /* Move the cursor to the given column (horizontal position), 1-based. */
@@ -1193,7 +1193,7 @@ vte_sequence_handler_cursor_character_absolute (VteTerminalPrivate *that, GValue
 void
 VteTerminalPrivate::set_cursor_column(vte::grid::column_t col)
 {
-        m_cursor.col = CLAMP(col, 0, m_column_count - 1);
+        m_screen->cursor.col = CLAMP(col, 0, m_column_count - 1);
 }
 
 /*
@@ -1218,7 +1218,7 @@ VteTerminalPrivate::set_cursor_row(vte::grid::row_t row)
         row += start_row;
         row = CLAMP(row, start_row, end_row);
 
-        m_cursor.row = row + m_screen->insert_delta;
+        m_screen->cursor.row = row + m_screen->insert_delta;
 }
 
 /*
@@ -1230,7 +1230,7 @@ VteTerminalPrivate::set_cursor_row(vte::grid::row_t row)
 vte::grid::row_t
 VteTerminalPrivate::get_cursor_row() const
 {
-        auto row = m_cursor.row - m_screen->insert_delta;
+        auto row = m_screen->cursor.row - m_screen->insert_delta;
         /* Note that we do NOT check m_origin_mode here! */
         if (m_scrolling_restricted) {
                 row -= m_scrolling_region.start;
@@ -1241,7 +1241,7 @@ VteTerminalPrivate::get_cursor_row() const
 vte::grid::column_t
 VteTerminalPrivate::get_cursor_column() const
 {
-        return m_cursor.col;
+        return m_screen->cursor.col;
 }
 
 /*
@@ -1412,12 +1412,12 @@ VteTerminalPrivate::seq_dc()
 
         ensure_cursor_is_onscreen();
 
-        if (_vte_ring_next(m_screen->row_data) > m_cursor.row) {
+        if (_vte_ring_next(m_screen->row_data) > m_screen->cursor.row) {
 		long len;
 		/* Get the data for the row which the cursor points to. */
-                rowdata = _vte_ring_index_writable(m_screen->row_data, m_cursor.row);
+                rowdata = _vte_ring_index_writable(m_screen->row_data, m_screen->cursor.row);
 		g_assert(rowdata != NULL);
-                col = m_cursor.col;
+                col = m_screen->cursor.col;
 		len = _vte_row_data_length (rowdata);
 		/* Remove the column. */
 		if (col < len) {
@@ -1430,7 +1430,7 @@ VteTerminalPrivate::seq_dc()
 			}
 			/* Repaint this row. */
                         invalidate_cells(col, len - col,
-                                         m_cursor.row, 1);
+                                         m_screen->cursor.row, 1);
 		}
 	}
 
@@ -1476,7 +1476,7 @@ VteTerminalPrivate::seq_cursor_down(vte::grid::row_t rows)
                 end = m_screen->insert_delta + m_row_count - 1;
 	}
 
-        m_cursor.row = MIN(m_cursor.row + rows, end);
+        m_screen->cursor.row = MIN(m_screen->cursor.row + rows, end);
 }
 
 /* Erase characters starting at the cursor position (overwriting N with
@@ -1508,14 +1508,14 @@ VteTerminalPrivate::seq_erase_characters(long count)
 
 	/* Clear out the given number of characters. */
 	auto rowdata = ensure_row();
-        if (_vte_ring_next(m_screen->row_data) > m_cursor.row) {
+        if (_vte_ring_next(m_screen->row_data) > m_screen->cursor.row) {
 		g_assert(rowdata != NULL);
                 /* Clean up Tab/CJK fragments. */
-                cleanup_fragments(m_cursor.col, m_cursor.col + count);
+                cleanup_fragments(m_screen->cursor.col, m_screen->cursor.col + count);
 		/* Write over the characters.  (If there aren't enough, we'll
 		 * need to create them.) */
 		for (i = 0; i < count; i++) {
-                        col = m_cursor.col + i;
+                        col = m_screen->cursor.col + i;
 			if (col >= 0) {
 				if (col < (glong) _vte_row_data_length (rowdata)) {
 					/* Replace this cell with the current
@@ -1529,8 +1529,8 @@ VteTerminalPrivate::seq_erase_characters(long count)
 			}
 		}
 		/* Repaint this row. */
-                invalidate_cells(m_cursor.col, count,
-                                 m_cursor.row, 1);
+                invalidate_cells(m_screen->cursor.col, count,
+                                 m_screen->cursor.row, 1);
 	}
 
 	/* We've modified the display.  Make a note of it. */
@@ -1556,9 +1556,9 @@ VteTerminalPrivate::seq_insert_blank_character()
 {
         ensure_cursor_is_onscreen();
 
-        auto save = m_cursor;
+        auto save = m_screen->cursor;
         insert_char(' ', true, true);
-        m_cursor = save;
+        m_screen->cursor = save;
 }
 
 /* Insert N blank characters. */
@@ -1588,9 +1588,9 @@ VteTerminalPrivate::seq_backspace()
 {
         ensure_cursor_is_onscreen();
 
-        if (m_cursor.col > 0) {
+        if (m_screen->cursor.col > 0) {
 		/* There's room to move left, so do so. */
-                m_cursor.col--;
+                m_screen->cursor.col--;
 	}
 }
 
@@ -1838,7 +1838,7 @@ VteTerminalPrivate::seq_reverse_index()
                 end = start + m_row_count - 1;
 	}
 
-        if (m_cursor.row == start) {
+        if (m_screen->cursor.row == start) {
 		/* If we're at the top of the scrolling region, add a
 		 * line at the top to scroll the bottom off. */
 		_vte_terminal_ring_remove(m_terminal, end);
@@ -1849,7 +1849,7 @@ VteTerminalPrivate::seq_reverse_index()
                                  start, 2);
 	} else {
 		/* Otherwise, just move the cursor up. */
-                m_cursor.row--;
+                m_screen->cursor.row--;
 	}
 	/* Adjust the scrollbars if necessary. */
         adjust_adjustments();
@@ -1870,7 +1870,7 @@ VteTerminalPrivate::seq_tab_set()
 	if (m_tabstops == NULL) {
 		m_tabstops = g_hash_table_new(NULL, NULL);
 	}
-	set_tabstop(m_cursor.col);
+	set_tabstop(m_screen->cursor.col);
 }
 
 /* Tab. */
@@ -1887,7 +1887,7 @@ VteTerminalPrivate::seq_tab()
         vte::grid::column_t newcol, col;
 
 	/* Calculate which column is the next tab stop. */
-        newcol = col = m_cursor.col;
+        newcol = col = m_screen->cursor.col;
 
 	g_assert (col >= 0);
 
@@ -1958,9 +1958,9 @@ VteTerminalPrivate::seq_tab()
 			}
 		}
 
-		invalidate_cells(m_cursor.col, newcol - m_cursor.col,
-                                 m_cursor.row, 1);
-                m_cursor.col = newcol;
+		invalidate_cells(m_screen->cursor.col, newcol - m_screen->cursor.col,
+                                 m_screen->cursor.row, 1);
+                m_screen->cursor.col = newcol;
 	}
 }
 
@@ -1991,7 +1991,7 @@ void
 VteTerminalPrivate::seq_tab_clear(long param)
 {
 	if (param == 0) {
-		clear_tabstop(m_cursor.col);
+		clear_tabstop(m_screen->cursor.col);
 	} else if (param == 3) {
 		if (m_tabstops != nullptr) {
 			g_hash_table_destroy(m_tabstops);
@@ -2031,7 +2031,7 @@ VteTerminalPrivate::seq_cursor_up(vte::grid::row_t rows)
 		start = m_screen->insert_delta;
 	}
 
-        m_cursor.row = MAX(m_cursor.row - rows, start);
+        m_screen->cursor.row = MAX(m_screen->cursor.row - rows, start);
 }
 
 /* Vertical tab. */
@@ -2722,7 +2722,7 @@ VteTerminalPrivate::seq_insert_lines(vte::grid::row_t param)
         vte::grid::row_t end, i;
 
 	/* Find the region we're messing with. */
-        auto row = m_cursor.row;
+        auto row = m_screen->cursor.row;
         if (m_scrolling_restricted) {
                 end = m_screen->insert_delta + m_scrolling_region.end;
 	} else {
@@ -2741,7 +2741,7 @@ VteTerminalPrivate::seq_insert_lines(vte::grid::row_t param)
                 _vte_terminal_ring_remove(m_terminal, end);
                 _vte_terminal_ring_insert(m_terminal, row, TRUE);
 	}
-        m_cursor.col = 0;
+        m_screen->cursor.col = 0;
 	/* Update the display. */
         scroll_region(row, end - row + 1, param);
 	/* Adjust the scrollbars if necessary. */
@@ -2773,7 +2773,7 @@ VteTerminalPrivate::seq_delete_lines(vte::grid::row_t param)
         vte::grid::row_t end, i;
 
 	/* Find the region we're messing with. */
-        auto row = m_cursor.row;
+        auto row = m_screen->cursor.row;
         if (m_scrolling_restricted) {
                 end = m_screen->insert_delta + m_scrolling_region.end;
 	} else {
@@ -2793,7 +2793,7 @@ VteTerminalPrivate::seq_delete_lines(vte::grid::row_t param)
                 _vte_terminal_ring_remove(m_terminal, row);
                 _vte_terminal_ring_insert(m_terminal, end, TRUE);
 	}
-        m_cursor.col = 0;
+        m_screen->cursor.col = 0;
 	/* Update the display. */
         scroll_region(row, end - row + 1, -param);
 	/* Adjust the scrollbars if necessary. */
@@ -2836,13 +2836,13 @@ VteTerminalPrivate::seq_device_status_report(long param)
                                         rowmax = m_row_count - 1;
                                 }
                                 // FIXMEchpe this looks wrong. shouldn't this first clamp to origin,rowmax and *then* subtract origin?
-                                rowval = m_cursor.row - m_screen->insert_delta - origin;
+                                rowval = m_screen->cursor.row - m_screen->insert_delta - origin;
                                 rowval = CLAMP(rowval, 0, rowmax);
                                 char buf[128];
                                 g_snprintf(buf, sizeof(buf),
 					   _VTE_CAP_CSI "%ld;%ldR",
                                            rowval + 1,
-                                           CLAMP(m_cursor.col + 1, 1, m_column_count));
+                                           CLAMP(m_screen->cursor.col + 1, 1, m_column_count));
 				feed_child(buf, -1);
 				break;
 			default:
@@ -2879,13 +2879,13 @@ VteTerminalPrivate::seq_dec_device_status_report(long param)
                                         rowmax = m_row_count - 1;
                                 }
                                 // FIXMEchpe this looks wrong. shouldn't this first clamp to origin,rowmax and *then* subtract origin?
-                                rowval = m_cursor.row - m_screen->insert_delta - origin;
+                                rowval = m_screen->cursor.row - m_screen->insert_delta - origin;
                                 rowval = CLAMP(rowval, 0, rowmax);
                                 char buf[128];
 				g_snprintf(buf, sizeof(buf),
 					   _VTE_CAP_CSI "?%ld;%ldR",
                                            rowval + 1,
-                                           CLAMP(m_cursor.col + 1, 1, m_column_count));
+                                           CLAMP(m_screen->cursor.col + 1, 1, m_column_count));
 				feed_child(buf, -1);
 				break;
 			case 15:
