diff --git a/src/vte-private.h b/src/vte-private.h
index 6b5e0b3..25da7ca 100644
--- a/src/vte-private.h
+++ b/src/vte-private.h
@@ -339,6 +339,12 @@ struct _VteTerminalPrivate {
 	gboolean adjustment_changed_tag;
 	guint status_line_changed_pending;
 
+	/* Title changes pending. */
+	gchar *change_window_title;
+	gchar *change_icon_title;
+	guint change_window_title_tag;
+	guint change_icon_title_tag;
+
 	/* Background images/"transparency". */
 	guint bg_update_pending;
 	gboolean bg_transparent;
@@ -387,6 +393,9 @@ gboolean _vte_terminal_get_tabstop(VteTe
 void _vte_terminal_set_tabstop(VteTerminal *terminal, int column);
 void _vte_terminal_update_insert_delta(VteTerminal *terminal);
 
+gboolean _vte_terminal_apply_change_icon_title(VteTerminal *terminal);
+gboolean _vte_terminal_apply_change_window_title(VteTerminal *terminal);
+
 G_END_DECLS
 
 #endif
diff --git a/src/vte.c b/src/vte.c
index 0bf7bc0..f8858ca 100644
--- a/src/vte.c
+++ b/src/vte.c
@@ -6800,6 +6800,10 @@ #endif
 	vte_terminal_set_encoding(terminal, NULL);
 	g_assert(terminal->pvt->encoding != NULL);
 
+	/* initialize window queues */
+	pvt->change_window_title_tag = VTE_INVALID_SOURCE;
+	pvt->change_icon_title_tag = VTE_INVALID_SOURCE;
+
 	/* Initialize the screens and histories. */
 	vte_terminal_reset_rowdata(&pvt->alternate_screen.row_data,
 				   pvt->scrollback_lines);
@@ -7093,6 +7097,7 @@ #endif
 	}
 	terminal->pvt->has_fonts = FALSE;
 
+
 	/* Unmap the widget if it hasn't been already. */
 	if (GTK_WIDGET_MAPPED(widget)) {
 		gtk_widget_unmap(widget);
@@ -7129,6 +7134,10 @@ #endif
 
 	/* Mark that we no longer have a GDK window. */
 	GTK_WIDGET_UNSET_FLAGS(widget, GTK_REALIZED);
+
+	/* apply pending window updates */
+	_vte_terminal_apply_change_window_title (terminal);
+	_vte_terminal_apply_change_icon_title (terminal);
 }
 
 /* Perform final cleanups for the widget before it's freed. */
diff --git a/src/vteseq.c b/src/vteseq.c
index aaeae57..5cc03d1 100644
--- a/src/vteseq.c
+++ b/src/vteseq.c
@@ -131,28 +131,136 @@ #endif
 	g_signal_emit_by_name(terminal, "iconify-window");
 }
 
-/* Emit an "icon-title-changed" signal. */
-static void
-vte_terminal_emit_icon_title_changed(VteTerminal *terminal)
+/* Apply change in title and emit an "icon-title-changed" signal. */
+gboolean
+_vte_terminal_apply_change_icon_title(VteTerminal *terminal)
 {
+	if (terminal->pvt->change_icon_title == NULL) {
+		return FALSE;
+	}
+
+	/* swap over to the new title */
+	g_free (terminal->icon_title);
+	terminal->icon_title = terminal->pvt->change_icon_title;
+	terminal->pvt->change_icon_title = NULL;
+
+	if (terminal->widget.window != NULL)
+		gdk_window_set_icon_name (terminal->widget.window,
+			       	terminal->icon_title);
+
 #ifdef VTE_DEBUG
 	if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
 		g_printerr("Emitting `icon-title-changed'.\n");
 	}
 #endif
 	g_signal_emit_by_name(terminal, "icon-title-changed");
-}
 
-/* Emit a "window-title-changed" signal. */
+	if (terminal->pvt->change_icon_title_tag != VTE_INVALID_SOURCE) {
+		g_source_remove (terminal->pvt->change_icon_title_tag);
+		terminal->pvt->change_icon_title_tag = VTE_INVALID_SOURCE;
+	}
+	return FALSE;
+}
 static void
-vte_terminal_emit_window_title_changed(VteTerminal *terminal)
+vte_terminal_queue_change_icon_title(VteTerminal *terminal, const gchar *title)
+{
+	/* check to see if they truly have changed the title */
+	if (terminal->pvt->change_icon_title == NULL) {
+		if (terminal->icon_title != NULL &&
+				strcmp(title, terminal->icon_title) == 0) {
+			return;
+		}
+	} else {
+		if (terminal->icon_title != NULL &&
+				strcmp(title, terminal->pvt->change_icon_title) == 0) {
+			return;
+		}
+
+		/* and check to see if they're changing it back... */
+		if (strcmp(title, terminal->icon_title) == 0) {
+			g_free (terminal->pvt->change_icon_title);
+			terminal->pvt->change_icon_title = NULL;
+			g_source_remove (terminal->pvt->change_icon_title_tag);
+			terminal->pvt->change_icon_title_tag =
+			       	VTE_INVALID_SOURCE;
+			return;
+		}
+	}
+
+	g_free (terminal->pvt->change_icon_title);
+	terminal->pvt->change_icon_title = g_strdup (title);
+
+	if (terminal->pvt->change_icon_title_tag == VTE_INVALID_SOURCE) {
+		terminal->pvt->change_icon_title_tag =
+			g_idle_add((GSourceFunc) _vte_terminal_apply_change_icon_title,
+					terminal);
+	}
+}
+
+/* Apply change in title and emit a "window-title-changed" signal. */
+gboolean
+_vte_terminal_apply_change_window_title(VteTerminal *terminal)
 {
+	if (terminal->pvt->change_window_title == NULL) {
+		return FALSE;
+	}
+
+	/* swap over to the new title */
+	g_free (terminal->window_title);
+	terminal->window_title = terminal->pvt->change_window_title;
+	terminal->pvt->change_window_title = NULL;
+
+	if (terminal->widget.window != NULL)
+		gdk_window_set_title (terminal->widget.window,
+			       	terminal->window_title);
+
 #ifdef VTE_DEBUG
 	if (_vte_debug_on(VTE_DEBUG_SIGNALS)) {
 		g_printerr("Emitting `window-title-changed'.\n");
 	}
 #endif
 	g_signal_emit_by_name(terminal, "window-title-changed");
+
+	if (terminal->pvt->change_window_title_tag != VTE_INVALID_SOURCE) {
+		g_source_remove (terminal->pvt->change_window_title_tag);
+		terminal->pvt->change_window_title_tag = VTE_INVALID_SOURCE;
+	}
+	return FALSE;
+}
+static void
+vte_terminal_queue_change_window_title(VteTerminal *terminal, const gchar *title)
+{
+	/* check to see if they truly have changed the title */
+	if (terminal->pvt->change_window_title == NULL) {
+		if (terminal->window_title != NULL &&
+			       	strcmp(title, terminal->window_title) == 0) {
+			return;
+		}
+	} else {
+		if (strcmp(title, terminal->pvt->change_window_title) == 0) {
+			return;
+		}
+
+		/* and check to see if they're changing it back... */
+		if (terminal->window_title != NULL &&
+				strcmp(title, terminal->window_title) == 0) {
+			g_free (terminal->pvt->change_window_title);
+			terminal->pvt->change_window_title = NULL;
+			g_source_remove (terminal->pvt->change_window_title_tag);
+			terminal->pvt->change_window_title_tag =
+			       	VTE_INVALID_SOURCE;
+			return;
+		}
+	}
+
+	g_free (terminal->pvt->change_window_title);
+	terminal->pvt->change_window_title = g_strdup (title);
+
+	if (terminal->pvt->change_window_title_tag == VTE_INVALID_SOURCE) {
+		terminal->pvt->change_window_title_tag =
+			g_idle_add((GSourceFunc) _vte_terminal_apply_change_window_title,
+					terminal);
+	}
 }
 
 /* Emit a "raise-window" signal. */
@@ -455,18 +563,12 @@ #endif
 
 			/* Emit the signal */
 			if (strcmp(signal, "window") == 0) {
-				g_free(terminal->window_title);
-				terminal->window_title = g_strdup(validated);
-				if (terminal->widget.window)
-					gdk_window_set_title (terminal->widget.window, validated);
-				vte_terminal_emit_window_title_changed(terminal);
+				vte_terminal_queue_change_window_title(terminal,
+					       	validated);
 			} else
 			if (strcmp(signal, "icon") == 0) {
-				g_free (terminal->icon_title);
-				terminal->icon_title = g_strdup(validated);
-				if (terminal->widget.window)
-					gdk_window_set_icon_name (terminal->widget.window, validated);
-				vte_terminal_emit_icon_title_changed(terminal);
+				vte_terminal_queue_change_icon_title(terminal,
+					       	validated);
 			}
 			g_free(validated);
 			g_free(title);
