diff --git a/src/vte-private.h b/src/vte-private.h
index 81afda4..89150ea 100644
--- a/src/vte-private.h
+++ b/src/vte-private.h
@@ -81,7 +81,6 @@ #define VTE_REGCOMP_FLAGS		REG_EXTENDED
 #define VTE_REGEXEC_FLAGS		0
 #define VTE_INPUT_CHUNK_SIZE		0x1000
 #define VTE_INVALID_BYTE		'?'
-#define VTE_COALESCE_TIMEOUT		10
 #define VTE_DISPLAY_TIMEOUT		10
 #define VTE_UPDATE_TIMEOUT		10
 #define VTE_UPDATE_REPEAT_TIMEOUT	25
@@ -171,7 +170,6 @@ struct _VteTerminalPrivate {
 	guint pty_input_source;
 	GIOChannel *pty_output;		/* master output watch */
 	guint pty_output_source;
- 	GStaticMutex pty_output_source_mutex;	/* pty_output_source mutex */
 	pid_t pty_pid;			/* pid of child using pty slave */
 	VteReaper *pty_reaper;
 
@@ -180,8 +178,7 @@ struct _VteTerminalPrivate {
 	struct _vte_iso2022_state *iso2022;
 	struct _vte_buffer *incoming;	/* pending bytestream */
 	GArray *pending;		/* pending characters */
-	gint coalesce_timeout;
-	gint display_timeout;
+	gint process_timeout;
 	gint update_timeout;
 	GSList *update_regions;
 
diff --git a/src/vte.c b/src/vte.c
index a789306..c532518 100644
--- a/src/vte.c
+++ b/src/vte.c
@@ -95,8 +95,9 @@ static void _vte_terminal_disconnect_pty
 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);
 
+static void add_update_timeout (VteTerminal *terminal);
+static void remove_update_timeout (VteTerminal *terminal);
 static void reset_update_regions (VteTerminal *terminal);
 
 #ifdef VTE_DEBUG
@@ -233,9 +234,6 @@ update_regions (VteTerminal *terminal)
 	return TRUE;
 }
 
-static void add_update_timeout (VteTerminal *terminal);
-static void remove_update_timeout (VteTerminal *terminal);
-
 /* Cause certain cells to be repainted. */
 void
 _vte_invalidate_cells(VteTerminal *terminal,
@@ -2530,7 +2528,6 @@ _vte_terminal_connect_pty_write(VteTermi
 		terminal->pvt->pty_output =
 			g_io_channel_unix_new(terminal->pvt->pty_master);
 	}
-	g_static_mutex_lock (&(terminal->pvt->pty_output_source_mutex));
 	if (terminal->pvt->pty_output_source == VTE_INVALID_SOURCE) {
 		terminal->pvt->pty_output_source =
 			g_io_add_watch_full(terminal->pvt->pty_output,
@@ -2540,7 +2537,6 @@ _vte_terminal_connect_pty_write(VteTermi
 					    terminal,
 					    NULL);
 	}
-	g_static_mutex_unlock (&(terminal->pvt->pty_output_source_mutex));
 }
 
 static void
@@ -2569,12 +2565,10 @@ _vte_terminal_disconnect_pty_write(VteTe
 		g_io_channel_unref(terminal->pvt->pty_output);
 		terminal->pvt->pty_output = NULL;
 	}
-	g_static_mutex_lock (&(terminal->pvt->pty_output_source_mutex));
 	if (terminal->pvt->pty_output_source != VTE_INVALID_SOURCE) {
 		g_source_remove(terminal->pvt->pty_output_source);
 		terminal->pvt->pty_output_source = VTE_INVALID_SOURCE;
 	}
-	g_static_mutex_unlock (&(terminal->pvt->pty_output_source_mutex));
 }
 
 /* Basic wrapper around _vte_pty_open, which handles the pipefitting. */
@@ -3252,64 +3246,54 @@ vte_terminal_io_read(GIOChannel *channel
 		     GIOCondition condition,
 		     VteTerminal *terminal)
 {
-	char buf[VTE_INPUT_CHUNK_SIZE];
-	int bcount, fd;
+	char buf[VTE_INPUT_CHUNK_SIZE], *bp = buf;
+	int err = 0;
 	gboolean eof, leave_open = TRUE;
 
-	/* Check that the channel is still open. */
-	fd = g_io_channel_unix_get_fd(channel);
-
-	/* Read some data in from this channel. */
-	bcount = 0;
-	if (condition & G_IO_IN) {
-		/* We try not to overfill the incoming buffer below by cutting
-		 * down the read size if we already have pending data. */
-		bcount = sizeof(buf);
-		if (_vte_buffer_length(terminal->pvt->incoming) < sizeof(buf)) {
-			/* Shoot for exactly one "chunk" for processing. */
-			bcount -= _vte_buffer_length(terminal->pvt->incoming);
-		} else {
-			/* Read half of the chunk size. */
-			bcount = sizeof(buf) / 2;
-		}
-		g_assert(bcount >= 0);
-		g_assert(bcount <= sizeof(buf));
-		bcount = read(fd, buf, MAX(bcount, sizeof(buf) / 2));
-	}
-
 	/* Check for end-of-file. */
 	eof = FALSE;
 	if (condition & G_IO_HUP) {
 		eof = TRUE;
 	}
 
-	/* Catch errors. */
-	switch (bcount) {
-	case 0:
-		/* EOF */
-		eof = TRUE;
-		break;
-	case -1:
-		/* Error! */
-		switch (errno) {
-			case EIO: /* Fake an EOF. */
-				eof = TRUE;
-				break;
-			case EAGAIN:
-			case EBUSY: /* do nothing */
-				break;
-			default:
-				/* Translators: %s is replaced with error message returned by strerror(). */
-				g_warning(_("Error reading from child: "
-					    "%s."), strerror(errno));
-				leave_open = TRUE;
+	/* Read some data in from this channel. */
+	if (condition & G_IO_IN) {
+		const int fd = g_io_channel_unix_get_fd(channel);
+		int rem = sizeof(buf);
+		while (rem){
+			int ret = read(fd, bp, rem);
+			if(ret <= 0){
+				if(ret == 0)
+					eof = TRUE;
+				else
+					err = errno;
 				break;
+			}
+			rem -= ret;
+			bp += ret;
 		}
-		break;
-	default:
+	}
+
+	if (bp != buf) {
 		/* Queue up the data for processing. */
-		vte_terminal_feed(terminal, buf, bcount);
-		break;
+		vte_terminal_feed(terminal, buf, bp - buf);
+	}
+
+	/* Error? */
+	switch (err) {
+		case 0: /* no error */
+			break;
+		case EIO: /* Fake an EOF. */
+			eof = TRUE;
+			break;
+		case EAGAIN:
+		case EBUSY: /* do nothing */
+			break;
+		default:
+			/* Translators: %s is replaced with error message returned by strerror(). */
+			g_warning(_("Error reading from child: " "%s."), strerror(err));
+			leave_open = TRUE;
+			break;
 	}
 
 	/* If we detected an eof condition, signal one. */
@@ -3344,9 +3328,8 @@ vte_terminal_feed(VteTerminal *terminal,
 	/* If we got data, modify the pending buffer. */
 	if (length > 0) {
 		_vte_buffer_append(terminal->pvt->incoming, data, length);
+		vte_terminal_start_processing (terminal);
 	}
-
-	vte_terminal_start_processing (terminal);
 }
 
 /* Send locally-encoded characters to the child. */
@@ -3551,16 +3534,16 @@ vte_terminal_feed_child_binary(VteTermin
 	if (length > 0) {
 		vte_terminal_emit_commit(terminal,
 					 data, length);
-	}
 
-	/* If there's a place for it to go, add the data to the
-	 * outgoing buffer. */
-	if ((length > 0) && (terminal->pvt->pty_master != -1)) {
-		_vte_buffer_append(terminal->pvt->outgoing,
-				   data, length);
-		/* If we need to start waiting for the child pty to
-		 * become available for writing, set that up here. */
-		_vte_terminal_connect_pty_write(terminal);
+		/* If there's a place for it to go, add the data to the
+		 * outgoing buffer. */
+		if (terminal->pvt->pty_master != -1) {
+			_vte_buffer_append(terminal->pvt->outgoing,
+					   data, length);
+			/* If we need to start waiting for the child pty to
+			 * become available for writing, set that up here. */
+			_vte_terminal_connect_pty_write(terminal);
+		}
 	}
 }
 
@@ -6706,7 +6689,6 @@ #endif
 	pvt->pty_master = -1;
 	pvt->pty_input_source = VTE_INVALID_SOURCE;
 	pvt->pty_output_source = VTE_INVALID_SOURCE;
-	g_static_mutex_init( &(pvt->pty_output_source_mutex) );
 	pvt->pty_pid = -1;
 
 	/* Set up I/O encodings. */
@@ -6716,8 +6698,7 @@ #endif
 	pvt->incoming = _vte_buffer_new();
 	pvt->pending = g_array_new(FALSE, FALSE, sizeof(gunichar));
 	pvt->cursor_blink_tag = VTE_INVALID_SOURCE;
-	pvt->coalesce_timeout = VTE_INVALID_SOURCE;
-	pvt->display_timeout = VTE_INVALID_SOURCE;
+	pvt->process_timeout = VTE_INVALID_SOURCE;
 	pvt->update_timeout = VTE_INVALID_SOURCE;
 	pvt->outgoing = _vte_buffer_new();
 	pvt->outgoing_conv = (VteConv) -1;
@@ -7050,6 +7031,9 @@ #endif
 		terminal->pvt->bg_update_pending = FALSE;
 	}
 
+	/* Cancel any pending redraws. */
+	remove_update_timeout (terminal);
+
 	/* Clear modifiers. */
 	terminal->pvt->modifiers = 0;
 
@@ -10997,47 +10981,30 @@ _vte_terminal_remove_selection(VteTermin
 	vte_terminal_deselect_all (terminal);
 }
 
-static gboolean display_timeout (gpointer data);
-static gboolean coalesce_timeout (gpointer data);
+static gboolean process_timeout (gpointer data);
 static gboolean update_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)
+add_process_timeout (VteTerminal *terminal)
 {
-	terminal->pvt->coalesce_timeout =
-		g_timeout_add (VTE_COALESCE_TIMEOUT, coalesce_timeout, terminal);
+	terminal->pvt->process_timeout =
+		g_timeout_add (VTE_DISPLAY_TIMEOUT, process_timeout, terminal);
 }
 
 static void
 add_update_timeout (VteTerminal *terminal)
 {
-	if (terminal->pvt->update_timeout == VTE_INVALID_SOURCE) {
-		terminal->pvt->update_timeout =
-			g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE,
-					    VTE_UPDATE_TIMEOUT, update_timeout, terminal,
-					    NULL);
-	}
-}
-
-static void
-remove_display_timeout (VteTerminal *terminal)
-{
-	g_source_remove (terminal->pvt->display_timeout);
-	terminal->pvt->display_timeout = VTE_INVALID_SOURCE;
+	terminal->pvt->update_timeout =
+		g_timeout_add_full (GDK_PRIORITY_REDRAW,
+				VTE_UPDATE_TIMEOUT, update_timeout, terminal,
+				NULL);
 }
 
 static void
-remove_coalesce_timeout (VteTerminal *terminal)
+remove_process_timeout (VteTerminal *terminal)
 {
-	g_source_remove (terminal->pvt->coalesce_timeout);
-	terminal->pvt->coalesce_timeout = VTE_INVALID_SOURCE;
+	g_source_remove (terminal->pvt->process_timeout);
+	terminal->pvt->process_timeout = VTE_INVALID_SOURCE;
 }
 
 static void
@@ -11065,84 +11032,59 @@ remove_update_timeout (VteTerminal *term
 static void
 vte_terminal_stop_processing (VteTerminal *terminal)
 {
-	remove_display_timeout (terminal);
-	remove_coalesce_timeout (terminal);
+	remove_process_timeout (terminal);
 }
 
-static void
-vte_terminal_start_processing (VteTerminal *terminal)
+static gboolean
+vte_terminal_is_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);
-	}
+	return terminal->pvt->process_timeout != VTE_INVALID_SOURCE
+		|| terminal->pvt->update_timeout != VTE_INVALID_SOURCE;
 }
 
-static gboolean
-vte_terminal_is_processing (VteTerminal *terminal)
+static void
+vte_terminal_start_processing (VteTerminal *terminal)
 {
-	return terminal->pvt->coalesce_timeout != VTE_INVALID_SOURCE;
+	if (!vte_terminal_is_processing (terminal)) {
+		add_process_timeout (terminal);
+	}
 }
 
 
-/* This function is called every DISPLAY_TIMEOUT ms.
- * It makes sure output is never delayed by more than DISPLAY_TIMEOUT
- */
-static gboolean
+static inline gboolean
 need_processing (VteTerminal *terminal)
 {
 	return _vte_buffer_length(terminal->pvt->incoming) > 0 ||
 		(terminal->pvt->pending->len > 0);
 }
 	
+/* This function is called after DISPLAY_TIMEOUT ms.
+ * It makes sure initial output is never delayed by more than DISPLAY_TIMEOUT
+ */
 static gboolean
-display_timeout (gpointer data)
+process_timeout (gpointer data)
 {
 	VteTerminal *terminal = data;
 
-	if (need_processing (terminal) && 
-	    vte_terminal_process_incoming(terminal)) {
-		remove_coalesce_timeout (terminal);
-		add_coalesce_timeout (terminal);
-		return TRUE;
+	if (need_processing (terminal)) {
+	    vte_terminal_process_incoming(terminal);
 	}
 
-	remove_coalesce_timeout (terminal);
-	terminal->pvt->display_timeout = VTE_INVALID_SOURCE;
-	
+	terminal->pvt->process_timeout = VTE_INVALID_SOURCE;
 	return FALSE;
 }
 
-/* This function is called whenever data haven't arrived for
- * COALESCE_TIMEOUT ms
- */
 static gboolean
-coalesce_timeout (gpointer data)
+update_repeat_timeout (gpointer data)
 {
 	VteTerminal *terminal = data;
+	gboolean updated;
 
-	if (need_processing (terminal) &&
-	    vte_terminal_process_incoming(terminal)) {
-		remove_display_timeout (terminal);
-		add_display_timeout (terminal);
-		return TRUE;
+	if (need_processing (terminal)) {
+		vte_terminal_process_incoming(terminal);
 	}
 
-	remove_display_timeout (terminal);
-	terminal->pvt->coalesce_timeout = VTE_INVALID_SOURCE;
-
-	return FALSE;
- }
-
-static gboolean
-update_repeat_timeout (gpointer data)
-{
-	VteTerminal *terminal = data;
-	gboolean updated = update_regions (terminal);
+	updated = update_regions (terminal);
 
 	/* We only stop the timer if no update request was received in this
 	 * past cycle.
@@ -11160,6 +11102,12 @@ update_timeout (gpointer data)
 {
 	VteTerminal *terminal = data;
 
+	remove_process_timeout (terminal);
+
+	if (need_processing (terminal)) {
+		vte_terminal_process_incoming(terminal);
+	}
+
 	update_regions (terminal);
 
 	/* Set a timer such that we do not invalidate for a while. */
