VTE performance work (done)



Hi,

So vte is everybody's favorite inefficient module, eh?  And
nobody sits down doing real work on it?

I did.  Here goes a report.  A few notes about vte first:


  * It has various backends for drawing.  In the order they are
tested for use:

    - Direct Xft backend.  By far the fastest one and I don't see
any obvious way to optimize it further.

    - FreeType2 backend.  This one draws on a bitmap and load it
to screen, but they are cached I believe.  Unlike what people may
think, it's blazingly fast too.

    - OpenGL backend.  Yes!  Uses OpenGL to copy glyphs around.
Glyphs are produced by FT2 of course.  Not that fast without
accelerated GLX.

    - Pango backend.  This one sucks most, since it uses a
PangoLayout to render a single character, every time that a
character needs to be rendered.  I have a billion ideas about how
to make that fast, but I don't see much point optimizing this, as
a direct Xft backend is by far faster.

    - PangoX backend.  If you don't have Render extension, you
may want to use that one...


  * Unlike all the myth, vte does not keep a matrix of what's
currently rendered on the screen.  Whenever it thinks something
*may* need a redraw, it calls gdk_window_invalidate_rect on it.

  * If playing with what is redrawn, compiling with
--enable-debugging and VTE_DEBUG_FLAGS=updates makes gdk do the
infamous red flicker on each update, so you'll see how frequently
the entire widget is repainted.


==================================================================


Anyway, back to work.   First idea I had was to keep a matrix of
what's on screen and only invalidate those areas that the
character to be rendered is different from character that is
rendered.  It was not easy to cook this patch, since each cell
has a billion different properties and all.  This is attached as
vte-shrink.patch.  It still doesn't work perfect with
selection.  Try selecting some text and then scrolling...  It
does make vte do almost nothing if you run yes(1) in it, or push
enter for long periods of time, but not much more really.  So I
actually gave up working on it.  There are much better ways to
optimize vte.  But if somebody wants to work on the patch, it's
attached.


==================================================================


Next idea was, the same old "not render too many times".  Seems
like it was quite easy to cook that one.  It's attached as
vte-throttle.patch.  What it does is: whenever an invalidate
happens, it checks whether a timer is set.  If no time is set, it
calls gdk_window_invalidate_rect and sets a timer of 25ms.  If
the timer is already set, it doesn't invalide and only merges
rect with update_region.  In the callback, if update_region is
not NULL, call gdk_window_invalidate_region and shut timer down.
So, you don't get more than 40 repaints a second, but when idle,
it doesn't lag behind as you type.  If nobody objects, I'm going
to commit this tomorrow.


==================================================================


The third patch, vte-faster-private.patch, simply changes the
allocation of the private object to use GObject private data
instead of a malloc0, and removes tens of unneeded member
initializations that set pvt->something to 0 or NULL, when we
know it already is so.  Again, will commit this soon.


==================================================================


A couple ideas I've not had time to explore yet (and may not have
anytime soon, so, feel free to take):


There is this struct vte_sequence_handlers that maps strings to
function pointers.  It's used to map incoming control sequences
to their handlers.  It starts in vte.c:6000 and goes does to
6420.  Some 400 entries.  A few facts about this:

  * The struct is not defined const, and making it const doesn't
really help, since it contains strings and function pointers, all
needing relocation anyway.

  * There are 128 different sequence handler functions.

  * From the 400 strings, 300 are two-letter strings.  The rest
are up to 37 bytes long.

  * The struct is used in vte_terminal_set_emulation to populate
a GTree mapping the (quarks of) strings to their handlers.

  * The said GTree is only used to lookup incoming control
sequences for their handlers.  Never modified.

  * The height of this tree is 9, which means on each lookup,
it's calling the (trivial ) compare function nine times.


So, hopefully you see the problem already :). Let's see how much
does it costing us.  At Vte relocation time, costs some 800
relocations, plus 3.2kb, and per Vte instance creation it costs
inserting 400 items in a GTree, and of course the memory required
to keep that tree in memory.  There's the time freeing this tree
at finilization too, but that doesn't matter much.

Now see what we can do instead:

  * Have an array of all the handlers and use indices into this
array instead.  This reduces handler relocations to 128, and a
single byte can be used to refere to them.

  * Get rid of the GTree completely, as the data is static.

  * Split the 400-entry lookup struct into two, one for
the 300 two-letter sequences, another for the remaining 100.

  * For two letter sequences, use a struct { char seq[3], uchar
handler } for a total of 1.2kb and no relocations, sorted on seq.

  * For the remaining sequences, use a struct { char seq[38],
uchar len, uchar handler } at the cost of something like 2kb
extra static memory but no relocations.  Sorted on len and the
seq.

  * When looking up, if the sequence is two-bytes long, bsearch
in the first table, otherwise bsearch in the second table.

  * The bsearches can be written in place, to have the compare
function inlined.  In the compare function for the second table,
compare len first, to avoid most of the strcmp's.


Whoever doing this should also move struct VteTerminalPrivate
into a vte-private.h and move all the handlers and their handling
into a new source file.  That helps splitting the 16000-line
vte.c a bit.  As for the tables, the easiest is to use a
generator to generate them from a file holding the current
not-optimized table.


==================================================================


Finally, to solve the excessive redraws on scrolling text, one
can do this:  Keep a pixmap of size width x 2*height, and render
to this pixmap.  On expose, make sure the bitmap is up to date
and use (one or two) XCopyArea calls.  But on scroll, instead of
invalidating the entire screen, just shift the offset into the
pixmap to point to the next line.

This is a bit harder to get right, and I'm not sure whether it's
worth it with the throttling patch.


Ok, that was all for now.

--behdad
http://behdad.org/

"Commandment Three says Do Not Kill, Amendment Two says Blood Will Spill"
	-- Dan Bern, "New American Language"
? 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);
 		}
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 23:13:02 -0000
@@ -253,6 +253,9 @@ struct _VteTerminalPrivate {
 		GString *status_line_contents;
 	} normal_screen, alternate_screen, *screen;
 
+	GdkRegion *update_region;
+	gint update_timer;
+
 	/* Selection information. */
 	GArray *word_chars;
 	gboolean has_selection;
@@ -597,6 +600,34 @@ vte_terminal_set_default_attributes(VteT
 	terminal->pvt->screen->fill_defaults = terminal->pvt->screen->defaults;
 }
 
+static gboolean
+vte_update_timeout(VteTerminal *terminal)
+{
+	terminal->pvt->update_timer = 0;
+	if (terminal->pvt->update_region) {
+		gdk_window_invalidate_region(GTK_WIDGET(terminal)->window,
+					     terminal->pvt->update_region, FALSE);
+		gdk_region_destroy (terminal->pvt->update_region);
+		terminal->pvt->update_region = NULL;
+	}
+
+	return FALSE;
+}
+
+static void
+vte_free_update_timer (VteTerminal *terminal)
+{
+	if (terminal->pvt->update_timer) {
+		g_source_remove (terminal->pvt->update_timer);
+		terminal->pvt->update_timer = 0;
+	}
+
+	if (terminal->pvt->update_region) {
+		gdk_region_destroy (terminal->pvt->update_region);
+		terminal->pvt->update_region = NULL;
+	}
+}
+
 /* Cause certain cells to be repainted. */
 static void
 vte_invalidate_cells(VteTerminal *terminal,
@@ -656,8 +687,20 @@ vte_invalidate_cells(VteTerminal *termin
 		rect.height += VTE_PAD_WIDTH;
 	}
 
-	/* Invalidate the rectangle. */
-	gdk_window_invalidate_rect(widget->window, &rect, FALSE);
+	if (terminal->pvt->update_timer) {
+		if (!terminal->pvt->update_region)
+			terminal->pvt->update_region = gdk_region_rectangle (&rect);
+		else
+			gdk_region_union_with_rect (terminal->pvt->update_region, &rect);
+	} else {
+		/* Invalidate the rectangle. */
+		gdk_window_invalidate_rect(widget->window, &rect, FALSE);
+
+		/* Set a timer such that we do not invalidate for a while. */
+		/* This limits the number of times we draw to 40 Hz. */
+		terminal->pvt->update_timer = g_timeout_add (25, vte_update_timeout, terminal);
+	}
+
 }
 
 /* Redraw the entire visible portion of the window. */
@@ -680,6 +723,10 @@ vte_invalidate_all(VteTerminal *terminal
 		return;
 	}
 
+	if (terminal->pvt->update_timer) {
+		vte_free_update_timer (terminal);
+	}
+
 	/* Expose the entire widget area. */
 	width = height = 0;
 	gdk_drawable_get_size(widget->window, &width, &height);
@@ -12038,6 +12085,10 @@ vte_terminal_finalize(GObject *object)
 	}
 	_vte_termcap_free(terminal->pvt->termcap);
 	terminal->pvt->termcap = NULL;
+
+	if (terminal->pvt->update_timer) {
+		vte_free_update_timer (terminal);
+	}
 
 	/* Done with our private data. */
 	g_free(terminal->pvt);
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 23:06:14 -0000
@@ -11325,6 +11325,9 @@ vte_terminal_init(VteTerminal *terminal,
 	widget = GTK_WIDGET(terminal);
 	GTK_WIDGET_SET_FLAGS(widget, GTK_CAN_FOCUS);
 
+	/* We do our own redrawing. */
+	gtk_widget_set_redraw_on_allocate (widget, FALSE);
+
 	/* Set an adjustment for the application to use to control scrolling. */
 	adjustment = GTK_ADJUSTMENT(gtk_adjustment_new(0, 0, 0, 0, 0, 0));
 	vte_terminal_set_scroll_adjustment(terminal, adjustment);
@@ -11340,24 +11343,14 @@ vte_terminal_init(VteTerminal *terminal,
 	terminal->char_descent = 0;
 
 	/* Initialize private data. */
-	pvt = terminal->pvt = g_malloc0(sizeof(*terminal->pvt));
+	pvt = terminal->pvt = G_TYPE_INSTANCE_GET_PRIVATE (terminal, VTE_TYPE_TERMINAL, VteTerminalPrivate);
+
+	/* We allocated zeroed memory, just fill in non-zero stuff. */
 
 	/* Load the termcap data and set up the emulation. */
-	pvt->termcap = NULL;
-	pvt->matcher = NULL;
-	pvt->termcap_path = NULL;
 	memset(&pvt->flags, 0, sizeof(pvt->flags));
-	pvt->flags.am = FALSE;
-	pvt->flags.bw = FALSE;
-	pvt->flags.LP = FALSE;
-	pvt->flags.ul = FALSE;
-	pvt->flags.xn = FALSE;
 	pvt->keypad_mode = VTE_KEYMODE_NORMAL;
 	pvt->cursor_mode = VTE_KEYMODE_NORMAL;
-	pvt->sun_fkey_mode = FALSE;
-	pvt->hp_fkey_mode = FALSE;
-	pvt->legacy_fkey_mode = FALSE;
-	pvt->vt220_fkey_mode = FALSE;
 	pvt->dec_saved = g_hash_table_new(g_direct_hash, g_direct_equal);
 	pvt->default_column_count = 80;
 	pvt->default_row_count = 24;
@@ -11369,17 +11362,12 @@ vte_terminal_init(VteTerminal *terminal,
 	vte_terminal_set_size(terminal,
 			      pvt->default_column_count,
 			      pvt->default_row_count);
-	pvt->shell = NULL;
 	pvt->pty_master = -1;
-	pvt->pty_input = NULL;
 	pvt->pty_input_source = VTE_INVALID_SOURCE;
-	pvt->pty_output = NULL;
 	pvt->pty_output_source = VTE_INVALID_SOURCE;
 	pvt->pty_pid = -1;
-	pvt->pty_reaper = NULL;
 
 	/* Set up I/O encodings. */
-	pvt->encoding = NULL;
 	pvt->iso2022 = _vte_iso2022_state_new(pvt->encoding,
 					      &_vte_terminal_codeset_changed_cb,
 					      (gpointer)terminal);
@@ -11394,55 +11382,21 @@ vte_terminal_init(VteTerminal *terminal,
 	g_assert(terminal->pvt->encoding != NULL);
 
 	/* Initialize the screens and histories. */
-	pvt->alternate_screen.row_data = NULL;
 	vte_terminal_reset_rowdata(&pvt->alternate_screen.row_data,
 				   pvt->scrollback_lines);
-	pvt->alternate_screen.cursor_current.row = 0;
-	pvt->alternate_screen.cursor_current.col = 0;
-	pvt->alternate_screen.cursor_saved.row = 0;
-	pvt->alternate_screen.cursor_saved.col = 0;
-	pvt->alternate_screen.insert_delta = 0;
-	pvt->alternate_screen.scroll_delta = 0;
 	pvt->alternate_screen.sendrecv_mode = TRUE;
-	pvt->alternate_screen.insert_mode = FALSE;
-	pvt->alternate_screen.linefeed_mode = FALSE;
-	pvt->alternate_screen.origin_mode = FALSE;
-	pvt->alternate_screen.reverse_mode = FALSE;
-	pvt->alternate_screen.status_line = FALSE;
-	pvt->alternate_screen.status_line_contents = g_string_new("");
+	pvt->alternate_screen.status_line_contents = g_string_new(NULL);
 	pvt->screen = &terminal->pvt->alternate_screen;
 	vte_terminal_set_default_attributes(terminal);
 
-	pvt->normal_screen.row_data = NULL;
 	vte_terminal_reset_rowdata(&pvt->normal_screen.row_data,
 				   pvt->scrollback_lines);
-	pvt->normal_screen.cursor_current.row = 0;
-	pvt->normal_screen.cursor_current.col = 0;
-	pvt->normal_screen.cursor_saved.row = 0;
-	pvt->normal_screen.cursor_saved.col = 0;
-	pvt->normal_screen.insert_delta = 0;
-	pvt->normal_screen.scroll_delta = 0;
 	pvt->normal_screen.sendrecv_mode = TRUE;
-	pvt->normal_screen.insert_mode = FALSE;
-	pvt->normal_screen.linefeed_mode = FALSE;
-	pvt->normal_screen.origin_mode = FALSE;
-	pvt->normal_screen.reverse_mode = FALSE;
-	pvt->normal_screen.status_line = FALSE;
-	pvt->normal_screen.status_line_contents = g_string_new("");
+	pvt->normal_screen.status_line_contents = g_string_new(NULL);
 	pvt->screen = &terminal->pvt->normal_screen;
 	vte_terminal_set_default_attributes(terminal);
 
 	/* Selection info. */
-	pvt->word_chars = NULL;
-	pvt->has_selection = FALSE;
-	pvt->selecting = FALSE;
-	pvt->selecting_restart = FALSE;
-	pvt->selecting_had_delta = FALSE;
-	pvt->selection = NULL;
-	pvt->selection_start.x = 0;
-	pvt->selection_start.y = 0;
-	pvt->selection_end.x = 0;
-	pvt->selection_end.y = 0;
 	vte_terminal_set_word_chars(terminal, NULL);
 
 	/* Miscellaneous options. */
@@ -11450,31 +11404,18 @@ vte_terminal_init(VteTerminal *terminal,
 	vte_terminal_set_delete_binding(terminal, VTE_ERASE_AUTO);
 	pvt->meta_sends_escape = TRUE;
 	pvt->audible_bell = TRUE;
-	pvt->visible_bell = FALSE;
-	pvt->margin_bell = FALSE;
 	pvt->bell_margin = 10;
 	pvt->allow_bold = TRUE;
 	pvt->nrc_mode = TRUE;
-	pvt->smooth_scroll = FALSE;
-	pvt->tabstops = NULL;
-	pvt->text_modified_flag = FALSE;
-	pvt->text_inserted_count = 0;
-	pvt->text_deleted_count = 0;
 	vte_terminal_set_default_tabstops(terminal);
 
 	/* Scrolling options. */
-	pvt->scroll_background = FALSE;
-	pvt->scroll_lock_count = 0;
-	pvt->scroll_on_output = FALSE;
 	pvt->scroll_on_keystroke = TRUE;
 	pvt->scrollback_lines = VTE_SCROLLBACK_MIN;
 	vte_terminal_set_scrollback_lines(terminal,
 					  terminal->pvt->scrollback_lines);
 
 	/* Cursor blinking. */
-	pvt->cursor_force_fg = 0;
-	pvt->cursor_blinks = FALSE;
-	pvt->cursor_blink_tag = 0;
 	pvt->cursor_visible = TRUE;
 	pvt->cursor_blink_timeout = 1000;
 
@@ -11484,63 +11425,29 @@ vte_terminal_init(VteTerminal *terminal,
 	} else {
 		pvt->last_keypress_time = 0;
 	}
-	pvt->mouse_send_xy_on_click = FALSE;
-	pvt->mouse_send_xy_on_button = FALSE;
-	pvt->mouse_hilite_tracking = FALSE;
-	pvt->mouse_cell_motion_tracking = FALSE;
-	pvt->mouse_all_motion_tracking = FALSE;
-	pvt->mouse_last_button = 0;
-	pvt->mouse_last_x = 0;
-	pvt->mouse_last_y = 0;
-	pvt->mouse_autohide = FALSE;
-	pvt->mouse_autoscroll_tag = 0;
 
 	/* Matching data. */
-	pvt->match_contents = NULL;
-	pvt->match_attributes = NULL;
 	pvt->match_regexes = g_array_new(FALSE, TRUE,
 					 sizeof(struct vte_match_regex));
 	pvt->match_previous = -1;
 	vte_terminal_match_hilite_clear(terminal);
 
 	/* Rendering data.  Try everything. */
-	pvt->palette_initialized = FALSE;
-	pvt->highlight_color_set = FALSE;
-	memset(&pvt->palette, 0, sizeof(pvt->palette));
 	pvt->draw = _vte_draw_new(GTK_WIDGET(terminal));
 
 	/* The font description. */
-	pvt->fontdesc = NULL;
 	pvt->fontantialias = VTE_ANTI_ALIAS_USE_DEFAULT;
-	pvt->connected_settings = NULL;
 	gtk_widget_ensure_style(widget);
 	vte_terminal_connect_xft_settings(terminal);
 	vte_terminal_set_font_full(terminal, NULL, VTE_ANTI_ALIAS_USE_DEFAULT);
 
-	/* Input method support. */
-	pvt->im_context = NULL;
-	pvt->im_preedit_active = FALSE;
-	pvt->im_preedit = NULL;
-	pvt->im_preedit_attrs = NULL;
-	pvt->im_preedit_cursor = 0;
-
-	/* Bookkeeping data for adjustment-changed signals. */
-	pvt->adjustment_changed_tag = 0;
-
 	/* Set up background information. */
-	pvt->bg_update_pending = FALSE;
-	pvt->bg_transparent = FALSE;
-	pvt->bg_pixbuf = NULL;
-	pvt->bg_file = NULL;
 	pvt->bg_update_tag = VTE_INVALID_SOURCE;
 	pvt->bg_tint_color.red = 0;
 	pvt->bg_tint_color.green = 0;
 	pvt->bg_tint_color.blue = 0;
 	pvt->bg_saturation = 0.4 * VTE_SATURATION_MAX;
 
-	/* Clear modifiers. */
-	pvt->modifiers = 0;
-
 	/* Assume we're visible unless we're told otherwise. */
 	pvt->visibility_state = GDK_VISIBILITY_UNOBSCURED;
 
@@ -11554,8 +11461,6 @@ vte_terminal_init(VteTerminal *terminal,
 			 G_CALLBACK(vte_terminal_style_changed),
 			 NULL);
 
-	pvt->accessible_emit = FALSE;
-
 #ifdef VTE_DEBUG
 	/* In debuggable mode, we always do this. */
 	/* gtk_widget_get_accessible(GTK_WIDGET(terminal)); */
@@ -12040,7 +11945,6 @@ vte_terminal_finalize(GObject *object)
 	terminal->pvt->termcap = NULL;
 
 	/* Done with our private data. */
-	g_free(terminal->pvt);
 	terminal->pvt = NULL;
 
 	/* Free public-facing data. */
@@ -14259,6 +14163,8 @@ vte_terminal_class_init(VteTerminalClass
 #ifdef HAVE_DECL_BIND_TEXTDOMAIN_CODESET
 	bind_textdomain_codeset(PACKAGE, "UTF-8");
 #endif
+
+	g_type_class_add_private(klass, sizeof (VteTerminalPrivate));
 
 	gobject_class = G_OBJECT_CLASS(klass);
 	widget_class = GTK_WIDGET_CLASS(klass);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]