Bug#197797: gnome-terminal v2 is horribly slow to display with screen

Matthijs Mohlmann Matthijs Mohlmann <matthijs@cacholong.nl>, 197797@bugs.debian.org
Sat, 18 Dec 2004 17:05:07 +0100


--=-BnP9crEp9lGl9AjtypJR
Content-Type: text/plain
Content-Transfer-Encoding: 7bit

Hi,

I have found a patch on gentoo.org and it makes gnome-terminal
significant faster.

And another patch to make gnome-terminal more usable ;)
Shift line-{up,down}

The first patch can close bug #197797 and maybe #217786

I've also posted this to debian-desktop@lists.debian.org

Matthijs Mohlmann


--=-BnP9crEp9lGl9AjtypJR
Content-Disposition: attachment; filename=05_performanceboost.patch
Content-Type: text/x-patch; name=05_performanceboost.patch; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit

? birnan
? vte-speed
Index: iso2022.c
===================================================================
RCS file: /cvs/gnome/vte/src/iso2022.c,v
retrieving revision 1.50
diff -u -p -u -r1.50 iso2022.c
--- vte-0.11.11.orig/src/iso2022.c	15 Sep 2003 18:57:33 -0000	1.50
+++ vte-0.11.11/src/iso2022.c	7 Jun 2004 22:43:22 -0000
@@ -298,24 +298,29 @@ _vte_iso2022_is_ambiguous(gunichar c)
 {
 	int i;
 	gpointer p;
-	static GTree *ambiguous = NULL;
+	static GHashTable *ambiguous = NULL;
 	for (i = 0; i < G_N_ELEMENTS(_vte_iso2022_ambiguous_ranges); i++) {
 		if ((c >= _vte_iso2022_ambiguous_ranges[i].start) &&
 		    (c <= _vte_iso2022_ambiguous_ranges[i].end)) {
 			return TRUE;
 		}
 	}
-	if (ambiguous == NULL) {
-		ambiguous = g_tree_new(_vte_direct_compare);
-		for (i = 0;
-		     i < G_N_ELEMENTS(_vte_iso2022_ambiguous_chars);
-		     i++) {
+	for (i = 0; i < G_N_ELEMENTS(_vte_iso2022_unambiguous_ranges); i++) {
+		if ((c >= _vte_iso2022_unambiguous_ranges[i].start) &&
+		    (c <= _vte_iso2022_unambiguous_ranges[i].end)) {
+			return FALSE;
+		}
+	}
+	if (!ambiguous) {
+		ambiguous = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+		for (i = 0; i < G_N_ELEMENTS(_vte_iso2022_ambiguous_chars); i++) {
 			p = GINT_TO_POINTER(_vte_iso2022_ambiguous_chars[i]);
-			g_tree_insert(ambiguous, p, p);
+			g_hash_table_insert(ambiguous,p,p);
 		}
 	}
-	p = GINT_TO_POINTER(c);
-	return g_tree_lookup(ambiguous, p) == p;
+
+	return g_hash_table_lookup (ambiguous, GINT_TO_POINTER(c)) != NULL;
 }
 
 /* If we only have a codepoint, guess what the ambiguous width should be based
@@ -862,35 +867,34 @@ _vte_iso2022_state_get_codeset(struct _v
 }
 
 static char *
-_vte_iso2022_better(char *p, char *q)
-{
-	if (p == NULL) {
-		return q;
-	}
-	if (q == NULL) {
-		return p;
-	}
-	return MIN(p, q);
-}
-
-static char *
 _vte_iso2022_find_nextctl(const char *p, size_t length)
 {
-	char *ret;
-	if (length == 0) {
-		return NULL;
-	}
-	ret = memchr(p, '\033', length);
-	ret = _vte_iso2022_better(ret, memchr(p, '\n', length));
-	ret = _vte_iso2022_better(ret, memchr(p, '\r', length));
-	ret = _vte_iso2022_better(ret, memchr(p, '\016', length));
-	ret = _vte_iso2022_better(ret, memchr(p, '\017', length));
+ 	char *ret;
+	int i;
+	
+ 	if (length == 0) {
+ 		return NULL;
+ 	}
+
+	for (i = 0; i < length; ++i) {
+		if (p[i] == '\033' ||
+		    p[i] == '\n' ||
+		    p[i] == '\r' ||
+		    p[i] == '\016' ||
+		    p[i] == '\017'
 #ifdef VTE_ISO2022_8_BIT_CONTROLS
-	/* This breaks UTF-8 and other encodings which use the high bits. */
-	ret = _vte_iso2022_better(ret, memchr(p, 0x8e, length));
-	ret = _vte_iso2022_better(ret, memchr(p, 0x8f, length));
+		    /* This breaks UTF-8 and other encodings which
+		     * use the high bits.
+		     */
+  		                 ||
+		    p[i] == 0x8e ||
+		    p[i] == 0x8f
 #endif
-	return ret;
+			) {
+			return (char *)p + i;
+		}
+	}
+	return NULL;
 }
 
 static long
Index: uniwidths
===================================================================
RCS file: /cvs/gnome/vte/src/uniwidths,v
retrieving revision 1.1
diff -u -p -u -r1.1 uniwidths
--- vte-0.11.11.orig/src/uniwidths	11 Feb 2003 20:21:43 -0000	1.1
+++ vte-0.11.11/src/uniwidths	7 Jun 2004 22:43:22 -0000
@@ -5,6 +5,13 @@ static const struct {
 	{0xf0000, 0xffffd},
 	{0x100000, 0x10fffd},
 };
+static const struct {
+	gunichar start, end;
+} _vte_iso2022_unambiguous_ranges[] = {
+	{0x01, 0xa0},
+	{0x452, 0x200f},
+};
+
 static const gunichar _vte_iso2022_ambiguous_chars[] = {
 	0xa1,
 	0xa4,
Index: vte.c
===================================================================
RCS file: /cvs/gnome/vte/src/vte.c,v
retrieving revision 1.404
diff -u -p -u -r1.404 vte.c
--- vte-0.11.11.orig/src/vte.c	2 May 2004 06:43:01 -0000	1.404
+++ vte-0.11.11/src/vte.c	7 Jun 2004 22:44:37 -0000
@@ -110,9 +110,10 @@ typedef gunichar wint_t;
 #define VTE_FX_PRIORITY			G_PRIORITY_DEFAULT_IDLE
 #define VTE_REGCOMP_FLAGS		REG_EXTENDED
 #define VTE_REGEXEC_FLAGS		0
-#define VTE_INPUT_CHUNK_SIZE		0x1000
+#define VTE_INPUT_CHUNK_SIZE           0x1000
 #define VTE_INVALID_BYTE		'?'
-#define VTE_COALESCE_TIMEOUT		2
+#define VTE_COALESCE_TIMEOUT		10
+#define VTE_DISPLAY_TIMEOUT		15
 
 /* The structure we use to hold characters we're supposed to display -- this
  * includes any supported visible attributes. */
@@ -204,8 +205,8 @@ struct _VteTerminalPrivate {
 	struct _vte_iso2022_state *iso2022;
 	struct _vte_buffer *incoming;	/* pending bytestream */
 	GArray *pending;		/* pending characters */
-	gboolean processing;
-	gint processing_tag;
+	gint coalesce_timeout;
+	gint display_timeout;
 
 	/* Output data queue. */
 	struct _vte_buffer *outgoing;	/* pending input characters */
@@ -462,7 +463,7 @@ static void vte_terminal_match_hilite_cl
 static gboolean vte_terminal_background_update(gpointer data);
 static void vte_terminal_queue_background_update(VteTerminal *terminal);
 static void vte_terminal_queue_adjustment_changed(VteTerminal *terminal);
-static gboolean vte_terminal_process_incoming(gpointer data);
+static gboolean vte_terminal_process_incoming(VteTerminal *terminal);
 static gboolean vte_cell_is_selected(VteTerminal *terminal,
 				     glong col, glong row, gpointer data);
 static char *vte_terminal_get_text_range_maybe_wrapped(VteTerminal *terminal,
@@ -489,6 +490,9 @@ static char *vte_terminal_get_text_maybe
 						 gboolean include_trailing_spaces);
 static void _vte_terminal_disconnect_pty_read(VteTerminal *terminal);
 static void _vte_terminal_disconnect_pty_write(VteTerminal *terminal);
+static void vte_terminal_stop_processing (VteTerminal *terminal);
+static void vte_terminal_start_processing (VteTerminal *terminal);
+static gboolean vte_terminal_is_processing (VteTerminal *terminal);
 
 /* Free a no-longer-used row data array. */
 static void
@@ -6989,11 +6993,8 @@ vte_terminal_catch_child_exited(VteReape
 		/* Take one last shot at processing whatever data is pending,
 		 * then flush the buffers in case we're about to run a new
 		 * command, disconnecting the timeout. */
-		if (terminal->pvt->processing) {
-			g_source_remove(terminal->pvt->processing_tag);
-			terminal->pvt->processing = FALSE;
-			terminal->pvt->processing_tag = VTE_INVALID_SOURCE;
-		}
+		vte_terminal_stop_processing (terminal);
+		
 		if (_vte_buffer_length(terminal->pvt->incoming) > 0) {
 			vte_terminal_process_incoming(terminal);
 		}
@@ -7277,11 +7278,7 @@ vte_terminal_eof(GIOChannel *channel, gp
 	/* Take one last shot at processing whatever data is pending, then
 	 * flush the buffers in case we're about to run a new command,
 	 * disconnecting the timeout. */
-	if (terminal->pvt->processing) {
-		g_source_remove(terminal->pvt->processing_tag);
-		terminal->pvt->processing = FALSE;
-		terminal->pvt->processing_tag = VTE_INVALID_SOURCE;
-	}
+	vte_terminal_stop_processing (terminal);
 	if (_vte_buffer_length(terminal->pvt->incoming) > 0) {
 		vte_terminal_process_incoming(terminal);
 	}
@@ -7379,10 +7376,9 @@ vte_terminal_emit_pending_text_signals(V
 /* Process incoming data, first converting it to unicode characters, and then
  * processing control sequences. */
 static gboolean
-vte_terminal_process_incoming(gpointer data)
+vte_terminal_process_incoming(VteTerminal *terminal)
 {
 	GValueArray *params = NULL;
-	VteTerminal *terminal;
 	VteScreen *screen;
 	struct vte_cursor_position cursor;
 	GtkWidget *widget;
@@ -7396,10 +7392,9 @@ vte_terminal_process_incoming(gpointer d
 	gboolean leftovers, modified, bottom, inserted, again;
 	GArray *unichars;
 
-	g_return_val_if_fail(GTK_IS_WIDGET(data), FALSE);
-	g_return_val_if_fail(VTE_IS_TERMINAL(data), FALSE);
-	widget = GTK_WIDGET(data);
-	terminal = VTE_TERMINAL(data);
+	g_return_val_if_fail(GTK_IS_WIDGET(terminal), FALSE);
+	g_return_val_if_fail(VTE_IS_TERMINAL(terminal), FALSE);
+	widget = GTK_WIDGET(terminal);
 
 	bottom = (terminal->pvt->screen->insert_delta ==
 		  terminal->pvt->screen->scroll_delta);
@@ -7410,7 +7405,6 @@ vte_terminal_process_incoming(gpointer d
 			_vte_buffer_length(terminal->pvt->incoming));
 	}
 #endif
-
 	/* Save the current cursor position. */
 	screen = terminal->pvt->screen;
 	cursor = screen->cursor_current;
@@ -7705,15 +7699,7 @@ vte_terminal_process_incoming(gpointer d
 			(long) _vte_buffer_length(terminal->pvt->incoming));
 	}
 #endif
-	/* Disconnect this function from the main loop. */
-	if (!again) {
-		terminal->pvt->processing = FALSE;
-		if (terminal->pvt->processing_tag != VTE_INVALID_SOURCE) {
-			g_source_remove(terminal->pvt->processing_tag);
-		}
-		terminal->pvt->processing_tag = VTE_INVALID_SOURCE;
-	}
-
+	
 #ifdef VTE_DEBUG
 	if (_vte_debug_on(VTE_DEBUG_IO)) {
 		if (terminal->pvt->processing) {
@@ -7724,7 +7710,7 @@ vte_terminal_process_incoming(gpointer d
 	}
 #endif
 
-	return terminal->pvt->processing;
+	return again;
 }
 
 /* Read and handle data from the child. */
@@ -7832,41 +7818,7 @@ vte_terminal_feed(VteTerminal *terminal,
 		_vte_buffer_append(terminal->pvt->incoming, data, length);
 	}
 
-	/* If we have sufficient data, just process it now. */
-	if (_vte_buffer_length(terminal->pvt->incoming) >
-	    VTE_INPUT_CHUNK_SIZE) {
-		/* Disconnect the timeout if one is pending. */
-		if (terminal->pvt->processing) {
-			g_source_remove(terminal->pvt->processing_tag);
-			terminal->pvt->processing = FALSE;
-			terminal->pvt->processing_tag = VTE_INVALID_SOURCE;
-		}
-		vte_terminal_process_incoming(terminal);
-	}
-
-	/* Wait no more than N milliseconds for more data.  We don't
-	 * touch the timeout if we're already slated to call it again
-	 * because if the output were carefully timed, we could
-	 * conceivably put it off forever. */
-	if (!terminal->pvt->processing &&
-	    (_vte_buffer_length(terminal->pvt->incoming) > 0)) {
-#ifdef VTE_DEBUG
-		if (_vte_debug_on(VTE_DEBUG_IO)) {
-			fprintf(stderr, "Adding timed handler.\n");
-		}
-#endif
-		terminal->pvt->processing = TRUE;
-		terminal->pvt->processing_tag = g_timeout_add(VTE_COALESCE_TIMEOUT,
-							      vte_terminal_process_incoming,
-							      terminal);
-	} else {
-#ifdef VTE_DEBUG
-		if (_vte_debug_on(VTE_DEBUG_IO)) {
-			fprintf(stderr, "Not touching timed handler, "
-				"or no data.\n");
-		}
-#endif
-	}
+	vte_terminal_start_processing (terminal);
 }
 
 /* Send locally-encoded characters to the child. */
@@ -11313,8 +11265,8 @@ vte_terminal_init(VteTerminal *terminal,
 					      (gpointer)terminal);
 	pvt->incoming = _vte_buffer_new();
 	pvt->pending = g_array_new(TRUE, TRUE, sizeof(gunichar));
-	pvt->processing = FALSE;
-	pvt->processing_tag = VTE_INVALID_SOURCE;
+	pvt->coalesce_timeout = VTE_INVALID_SOURCE;
+	pvt->display_timeout = VTE_INVALID_SOURCE;
 	pvt->outgoing = _vte_buffer_new();
 	pvt->outgoing_conv = (VteConv) -1;
 	pvt->conv_buffer = _vte_buffer_new();
@@ -11892,10 +11844,7 @@ vte_terminal_finalize(GObject *object)
 	terminal->pvt->pty_reaper = NULL;
 
 	/* Stop processing input. */
-	if (terminal->pvt->processing_tag != VTE_INVALID_SOURCE) {
-		g_source_remove(terminal->pvt->processing_tag);
-		terminal->pvt->processing_tag = VTE_INVALID_SOURCE;
-	}
+	vte_terminal_stop_processing (terminal);
 
 	/* Discard any pending data. */
 	if (terminal->pvt->incoming != NULL) {
@@ -15421,11 +15370,8 @@ vte_terminal_reset(VteTerminal *terminal
 {
 	g_return_if_fail(VTE_IS_TERMINAL(terminal));
 	/* Stop processing any of the data we've got backed up. */
-	if (terminal->pvt->processing) {
-		g_source_remove(terminal->pvt->processing_tag);
-		terminal->pvt->processing_tag = VTE_INVALID_SOURCE;
-		terminal->pvt->processing = FALSE;
-	}
+	vte_terminal_stop_processing (terminal);
+	
 	/* Clear the input and output buffers. */
 	if (terminal->pvt->incoming != NULL) {
 		_vte_buffer_clear(terminal->pvt->incoming);
@@ -15757,4 +15703,115 @@ _vte_terminal_accessible_ref(VteTerminal
 {
 	g_return_if_fail(VTE_IS_TERMINAL(terminal));
 	terminal->pvt->accessible_emit = TRUE;
+}
+
+static gboolean display_timeout (gpointer data);
+static gboolean coalesce_timeout (gpointer data);
+
+static void
+add_display_timeout (VteTerminal *terminal)
+{
+	terminal->pvt->display_timeout =
+		g_timeout_add (VTE_DISPLAY_TIMEOUT, display_timeout, terminal);
+}
+
+static void
+add_coalesce_timeout (VteTerminal *terminal)
+{
+	terminal->pvt->coalesce_timeout =
+		g_timeout_add (VTE_COALESCE_TIMEOUT, coalesce_timeout, terminal);
+}
+
+static void
+remove_display_timeout (VteTerminal *terminal)
+{
+	g_source_remove (terminal->pvt->display_timeout);
+	terminal->pvt->display_timeout = VTE_DISPLAY_TIMEOUT;
+}
+
+static void
+remove_coalesce_timeout (VteTerminal *terminal)
+{
+	g_source_remove (terminal->pvt->coalesce_timeout);
+	terminal->pvt->coalesce_timeout = VTE_INVALID_SOURCE;
+}
+
+static void
+vte_terminal_stop_processing (VteTerminal *terminal)
+{
+	remove_display_timeout (terminal);
+	remove_coalesce_timeout (terminal);
+}
+
+static void
+vte_terminal_start_processing (VteTerminal *terminal)
+{
+	if (vte_terminal_is_processing (terminal)) {
+		remove_coalesce_timeout (terminal);
+		add_coalesce_timeout (terminal);
+	}
+	else {
+		add_coalesce_timeout (terminal);
+		add_display_timeout (terminal);
+	}
+}
+
+static gboolean
+vte_terminal_is_processing (VteTerminal *terminal)
+{
+	return terminal->pvt->coalesce_timeout != VTE_INVALID_SOURCE;
+}
+
+
+/* This function is called every DISPLAY_TIMEOUT ms.
+ * It makes sure output is never delayed by more than DISPLAY_TIMEOUT
+ */
+static gboolean
+display_timeout (gpointer data)
+{
+	gboolean cont;
+	VteTerminal *terminal = data;
+
+	cont = vte_terminal_process_incoming (terminal);
+
+	if (!cont) {
+		remove_coalesce_timeout (terminal);
+		
+		terminal->pvt->display_timeout = VTE_INVALID_SOURCE;
+
+		return FALSE;
+	}
+	else {
+		remove_coalesce_timeout (terminal);
+		add_coalesce_timeout (terminal);
+	}
+
+	return TRUE;
+}
+
+/* This function is called whenever data haven't arrived for
+ * COALESCE_TIMEOUT ms
+ */
+static gboolean
+coalesce_timeout (gpointer data)
+{
+	gboolean cont;
+	VteTerminal *terminal = data;
+
+	cont = vte_terminal_process_incoming (terminal);
+
+	if (!cont) {
+		remove_display_timeout (terminal);
+
+		terminal->pvt->coalesce_timeout = VTE_INVALID_SOURCE;
+
+		return FALSE;
+	}
+	else {
+		/* reset display timeout since we just displayed */
+		remove_display_timeout (terminal);
+		add_display_timeout (terminal);
+	}
+
+	return TRUE;
 }
Index: vtexft.c
===================================================================
RCS file: /cvs/gnome/vte/src/vtexft.c,v
retrieving revision 1.19
diff -u -p -u -r1.19 vtexft.c
--- vte-0.11.11.orig/src/vtexft.c	20 Apr 2004 05:16:56 -0000	1.19
+++ vte-0.11.11/src/vtexft.c	7 Jun 2004 22:44:40 -0000
@@ -661,6 +661,7 @@ _vte_xft_drawcharfontspec(XftDraw *draw,
 			  XftCharFontSpec *specs, int n)
 {
 	int i, j;
+	
 	i = j = 0;
 	while (i < n) {
 		for (j = i + 1; j < n; j++) {
@@ -695,7 +696,7 @@ _vte_xft_draw_text(struct _vte_draw *dra
 	for (i = j = 0; i < n_requests; i++) {
 		specs[j].font = _vte_xft_font_for_char(data->font,
 						       requests[i].c);
-		if (specs[j].font != NULL) {
+		if (specs[j].font != NULL && requests[i].c != 32) {
 			specs[j].x = requests[i].x - data->x_offs;
 			width = _vte_xft_char_width(data->font,
 						    specs[j].font,
@@ -708,7 +709,7 @@ _vte_xft_draw_text(struct _vte_draw *dra
 			specs[j].y = requests[i].y - data->y_offs + draw->ascent;
 			specs[j].ucs4 = requests[i].c;
 			j++;
-		} else {
+		} else if (requests[i].c != 32) {
 			g_warning(_("Can not draw character U+%04x.\n"),
 				  requests[i].c);
 		}

--=-BnP9crEp9lGl9AjtypJR
Content-Disposition: attachment; filename=06_singlelinescroll.patch
Content-Type: text/x-patch; name=06_singlelinescroll.patch; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit

--- vte-0.11.11.orig/src/vte.c	2004-03-06 10:28:09.000000000 -0800
+++ vte-0.11.11/src/vte.c	2004-03-06 10:44:23.000000000 -0800
@@ -1948,4 +1948,31 @@
 }
 
+/* Scroll up or down in the current screen. */
+static void
+vte_terminal_scroll_lines(VteTerminal *terminal, gint lines)
+{
+        glong destination;
+        g_return_if_fail(VTE_IS_TERMINAL(terminal));
+#ifdef VTE_DEBUG
+        if (_vte_debug_on(VTE_DEBUG_IO)) {
+                fprintf(stderr, "Scrolling %d lines.\n", lines);
+        }
+#endif
+        /* Calculate the ideal position where we want to be before clamping. */
+        destination = floor(gtk_adjustment_get_value(terminal->adjustment));
+        destination += lines;
+        /* Can't scroll past data we have. */
+        destination = CLAMP(destination,
+                            terminal->adjustment->lower,
+                            terminal->adjustment->upper - terminal->row_count);
+        /* Tell the scrollbar to adjust itself. */
+        gtk_adjustment_set_value(terminal->adjustment, destination);
+        /* Clear dingus match set. */
+        vte_terminal_match_contents_clear(terminal);
+        /* Notify viewers that the contents have changed. */
+        vte_terminal_emit_contents_changed(terminal);
+}
+
+
 /* Scroll so that the scroll delta is the minimum value. */
 static void
@@ -8474,4 +8474,22 @@
 			}
 			break;
+		case GDK_KP_Up:
+                case GDK_Up:
+                        if (terminal->pvt->modifiers & GDK_SHIFT_MASK) {
+                                vte_terminal_scroll_lines(terminal, -1);
+                                scrolled = TRUE;
+                                handled = TRUE;
+                                suppress_meta_esc = TRUE;
+                        }
+                        break;
+                case GDK_KP_Down:
+                case GDK_Down:
+                        if (terminal->pvt->modifiers & GDK_SHIFT_MASK) {
+                                vte_terminal_scroll_lines(terminal, 1);
+                                scrolled = TRUE;
+                                handled = TRUE;
+                                suppress_meta_esc = TRUE;
+                        }
+                        break;
 		case GDK_KP_Home:
 		case GDK_Home:

--=-BnP9crEp9lGl9AjtypJR--