diff --git a/src/Makefile.am b/src/Makefile.am
index a36ac21..1ecc226 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -28,15 +28,6 @@ lib_LTLIBRARIES = libvte-@VTE_API_MAJOR_VERSION@.@VTE_API_MINOR_VERSION@.la
 EXTRA_libvte_@VTE_API_MAJOR_VERSION@_@VTE_API_MINOR_VERSION@_la_SOURCES = \
 	box_drawing_generate.sh \
 	marshal.list \
-	mkunitables.sh \
-	unitable.CNS11643 \
-	unitable.CP437 \
-	unitable.GB12345 \
-	unitable.GB2312 \
-	unitable.JIS0201 \
-	unitable.JIS0208 \
-	unitable.JIS0212 \
-	unitable.KSX1001 \
 	vteseq-n.gperf \
 	vteseq-n.c \
 	vtetypebuiltins.c.template \
@@ -324,7 +315,7 @@ TEST_SH = \
 	$(NULL)
 EXTRA_DIST += $(TEST_SH)
 
-check_PROGRAMS = dumpkeys iso2022 reflect-text-view reflect-vte mev table xticker vteconv
+check_PROGRAMS = dumpkeys reflect-text-view reflect-vte mev table xticker vteconv
 TESTS = table vteconv $(TEST_SH)
 
 reflect_text_view_CPPFLAGS = -DUSE_TEXT_VIEW $(AM_CPPFLAGS)
@@ -367,33 +358,6 @@ interpret_LDADD = \
 	$(GLIB_LIBS) \
 	$(GOBJECT_LIBS)
 
-iso2022_SOURCES = \
-	buffer.h \
-	caps.c \
-	caps.h \
-	debug.c \
-	debug.h \
-	iso2022.c \
-	iso2022.h \
-	matcher.c \
-	matcher.h \
-	table.c \
-	table.h \
-	vteconv.c \
-	vteconv.h \
-	vtetree.c \
-	vtetree.h
-iso2022_CPPFLAGS = \
-	-DISO2022_MAIN \
-	$(AM_CPPFLAGS)
-iso2022_CFLAGS = \
-	$(GLIB_CFLAGS) \
-	$(GTK_CFLAGS) \
-	$(AM_CFLAGS)
-iso2022_LDADD = \
-	$(GLIB_LIBS) \
-	$(GOBJECT_LIBS)
-
 slowcat_SOURCES = \
 	slowcat.c \
 	$(NULL)
diff --git a/src/caps.c b/src/caps.c
index 0e7ab43..5508ede 100644
--- a/src/caps.c
+++ b/src/caps.c
@@ -54,6 +54,8 @@ const char _vte_xterm_capability_strings[] =
         ENTRY(VT,  "vertical-tab")
         ENTRY(FF,  "form-feed")
         ENTRY(CR,  "carriage-return")
+        ENTRY(SO,  "shift-out")
+        ENTRY(SI,  "shift-in")
         ENTRY(DEL, "backspace")
 
         ENTRY(ESC " F", "7-bit-controls")
@@ -73,8 +75,12 @@ const char _vte_xterm_capability_strings[] =
         ENTRY(ESC "%%@", "default-character-set")
         ENTRY(ESC "%%G", "utf-8-character-set")
 
-        ENTRY(ESC "(0", "alternate-character-set-start")
-        ENTRY(ESC "(B", "alternate-character-set-end")
+        ENTRY(ESC "(0", "designate-g0-line-drawing")
+        ENTRY(ESC "(A", "designate-g0-british")
+        ENTRY(ESC "(B", "designate-g0-plain")
+        ENTRY(ESC ")0", "designate-g1-line-drawing")
+        ENTRY(ESC ")A", "designate-g1-british")
+        ENTRY(ESC ")B", "designate-g1-plain")
 
         ENTRY(ESC "7", "save-cursor")
         ENTRY(ESC "8", "restore-cursor")
diff --git a/src/interpret.c b/src/interpret.c
index 807c136..c192aa5 100644
--- a/src/interpret.c
+++ b/src/interpret.c
@@ -72,7 +72,7 @@ main(int argc, char **argv)
 
         matcher = _vte_matcher_new();
 
-	subst = _vte_iso2022_state_new(NULL, VTE_ISO2022_DEFAULT_UTF8_AMBIGUOUS_WIDTH, NULL, NULL);
+        subst = _vte_iso2022_state_new(NULL);
 
 	for (;;) {
 		l = read (infile, buf, sizeof (buf));
@@ -107,9 +107,6 @@ main(int argc, char **argv)
 			if (tmp == NULL) {
 				gunichar c;
 				c = g_array_index(array, gunichar, i);
-				if (VTE_ISO2022_HAS_ENCODED_WIDTH(c)) {
-					c &= ~VTE_ISO2022_ENCODED_WIDTH_MASK;
-				}
 				if (c < 32) {
 					g_print("`^%c'\n", c + 64);
 				} else
diff --git a/src/iso2022.c b/src/iso2022.c
index 0989082..50469c2 100644
--- a/src/iso2022.c
+++ b/src/iso2022.c
@@ -26,9 +26,7 @@
 #include "debug.h"
 #include "buffer.h"
 #include "iso2022.h"
-#include "matcher.h"
 #include "vteconv.h"
-#include "vtetree.h"
 
 #ifdef HAVE_LOCALE_H
 #include <locale.h>
@@ -37,741 +35,21 @@
 
 #include <gdk/gdkkeysyms.h>
 
-/* Maps which jive with XTerm's ESC ()*+ ? sequences, RFC 1468.  Add the
- * PC437 map because despite knowing that XTerm doesn't support it, certain
- * applications try to use it anyway. */
-#define NARROW_MAPS	"012AB4C5RQKYE6ZH7=" "J" "U"
-/* Maps which jive with RFC 1468's ESC $ ? sequences. */
-#define WIDE_MAPS	"@B"
-/* Maps which jive with RFC 1557/1922/2237's ESC $ ()*+ ? sequences. */
-#define WIDE_GMAPS	"C" "AGHIJKLM" "D"
-/* Fudge factor we add to wide map identifiers to keep them distinct. */
-#define WIDE_FUDGE	0x100000
 /* An invalid codepoint. */
 #define INVALID_CODEPOINT 0xFFFD
 
-struct _vte_iso2022_map16 {
-	guint16 from, to;
-};
-
-struct _vte_iso2022_map32 {
-	guint32 from, to;
-};
-
-struct _vte_iso2022_block {
-	enum {
-		_vte_iso2022_cdata,
-		_vte_iso2022_preserve,
-		_vte_iso2022_control
-	} type;
-	gulong start, end;
-};
-
 struct _vte_iso2022_state {
-	gboolean nrc_enabled;
-	int current, override;
-	gunichar g[4];
 	const gchar *codeset, *native_codeset, *utf8_codeset, *target_codeset;
-	gint ambiguous_width;
-        gint utf8_ambiguous_width;
 	VteConv conv;
-	_vte_iso2022_codeset_changed_cb_fn codeset_changed;
-	gpointer codeset_changed_data;
 	VteByteArray *buffer;
 };
 
-/* DEC Special Character and Line Drawing Set.  VT100 and higher (per XTerm
- * docs). */
-static const struct _vte_iso2022_map16 _vte_iso2022_map_0[] = {
-	{ 96, 0x25c6},	/* diamond */
-	{'a', 0x2592},	/* checkerboard */
-	{'b', 0x2409},	/* HT symbol */
-	{'c', 0x240c},	/* FF symbol */
-	{'d', 0x240d},	/* CR symbol */
-	{'e', 0x240a},	/* LF symbol */
-	{'f', 0x00b0},	/* degree */
-	{'g', 0x00b1},	/* plus/minus */
-	{'h', 0x2424},  /* NL symbol */
-	{'i', 0x240b},  /* VT symbol */
-	{'j', 0x2518},	/* downright corner */
-	{'k', 0x2510},	/* upright corner */
-	{'l', 0x250c},	/* upleft corner */
-	{'m', 0x2514},	/* downleft corner */
-	{'n', 0x253c},	/* cross */
-	{'o', 0x23ba},  /* scan line 1/9 */
-	{'p', 0x23bb},  /* scan line 3/9 */
-	{'q', 0x2500},	/* horizontal line (also scan line 5/9) */
-	{'r', 0x23bc},  /* scan line 7/9 */
-	{'s', 0x23bd},  /* scan line 9/9 */
-	{'t', 0x251c},	/* left t */
-	{'u', 0x2524},	/* right t */
-	{'v', 0x2534},	/* bottom t */
-	{'w', 0x252c},	/* top t */
-	{'x', 0x2502},	/* vertical line */
-	{'y', 0x2264},  /* <= */
-	{'z', 0x2265},  /* >= */
-	{'{', 0x03c0},  /* pi */
-	{'|', 0x2260},  /* not equal */
-	{'}', 0x00a3},  /* pound currency sign */
-	{'~', 0x00b7},	/* bullet */
-};
-/* United Kingdom.  VT100 and higher (per XTerm docs). */
-static const struct _vte_iso2022_map16 _vte_iso2022_map_A[] = {
-	{'$', GDK_KEY_sterling},
-};
-/* US-ASCII (no conversions).  VT100 and higher (per XTerm docs). */
-static const struct _vte_iso2022_map16 _vte_iso2022_map_B[] = {
-	{0, 0},
-};
-/* Dutch. VT220 and higher (per XTerm docs). */
-static const struct _vte_iso2022_map16 _vte_iso2022_map_4[] = {
-	{'#',  GDK_KEY_sterling},
-	{'@',  GDK_KEY_threequarters},
-	{'[',  GDK_KEY_ydiaeresis},
-	{'\\', GDK_KEY_onehalf},
-	{']',  GDK_KEY_bar}, /* FIXME? not in XTerm 170 */
-	{'{',  GDK_KEY_diaeresis},
-	{'|',  0x192}, /* f with hook (florin) */ /* FIXME? not in XTerm 170 */
-	{'}',  GDK_KEY_onequarter},
-	{'~',  GDK_KEY_acute},
-};
-/* Finnish. VT220 and higher (per XTerm docs). */
-static const struct _vte_iso2022_map16 _vte_iso2022_map_C[] = {
-	{'[',  GDK_KEY_Adiaeresis},
-	{'\\', GDK_KEY_Odiaeresis},
-	{']',  GDK_KEY_Aring},
-	{'^',  GDK_KEY_Udiaeresis},
-	{'`',  GDK_KEY_eacute},
-	{'{',  GDK_KEY_adiaeresis},
-	{'|',  GDK_KEY_odiaeresis},
-	{'}',  GDK_KEY_aring},
-	{'~',  GDK_KEY_udiaeresis},
-};
-/* French. VT220 and higher (per XTerm docs). */
-static const struct _vte_iso2022_map16 _vte_iso2022_map_R[] = {
-	{'#',  GDK_KEY_sterling},
-	{'@',  GDK_KEY_agrave},
-	{'[',  GDK_KEY_degree},
-	{'\\', GDK_KEY_ccedilla},
-	{']',  GDK_KEY_section},
-	{'{',  GDK_KEY_eacute},
-	{'|',  GDK_KEY_ugrave},
-	{'}',  GDK_KEY_egrave},
-	{'~',  GDK_KEY_diaeresis},
-};
-/* French Canadian. VT220 and higher (per XTerm docs). */
-static const struct _vte_iso2022_map16 _vte_iso2022_map_Q[] = {
-	{'@',  GDK_KEY_agrave},
-	{'[',  GDK_KEY_acircumflex},
-	{'\\', GDK_KEY_ccedilla},
-	{']',  GDK_KEY_ecircumflex},
-	{'^',  GDK_KEY_icircumflex},
-	{'`',  GDK_KEY_ocircumflex},
-	{'{',  GDK_KEY_eacute},
-	{'|',  GDK_KEY_ugrave},
-	{'}',  GDK_KEY_egrave},
-	{'~',  GDK_KEY_ucircumflex},
-};
-/* German. VT220 and higher (per XTerm docs). */
-static const struct _vte_iso2022_map16 _vte_iso2022_map_K[] = {
-	{'@',  GDK_KEY_section},
-	{'[',  GDK_KEY_Adiaeresis},
-	{'\\', GDK_KEY_Odiaeresis},
-	{']',  GDK_KEY_Udiaeresis},
-	{'{',  GDK_KEY_adiaeresis},
-	{'|',  GDK_KEY_odiaeresis},
-	{'}',  GDK_KEY_udiaeresis},
-	{'~',  GDK_KEY_ssharp},
-};
-/* Italian. VT220 and higher (per XTerm docs). */
-static const struct _vte_iso2022_map16 _vte_iso2022_map_Y[] = {
-	{'#',  GDK_KEY_sterling},
-	{'@',  GDK_KEY_section},
-	{'[',  GDK_KEY_degree},
-	{'\\', GDK_KEY_ccedilla},
-	{']',  GDK_KEY_eacute},
-	{'`',  GDK_KEY_ugrave},
-	{'{',  GDK_KEY_agrave},
-	{'|',  GDK_KEY_ograve},
-	{'}',  GDK_KEY_egrave},
-	{'~',  GDK_KEY_igrave},
-};
-/* Norwegian and Danish. VT220 and higher (per XTerm docs). */
-static const struct _vte_iso2022_map16 _vte_iso2022_map_E[] = {
-	{'@',  GDK_KEY_Adiaeresis},
-	{'[',  GDK_KEY_AE},
-	{'\\', GDK_KEY_Ooblique},
-	{']',  GDK_KEY_Aring},
-	{'^',  GDK_KEY_Udiaeresis},
-	{'`',  GDK_KEY_adiaeresis},
-	{'{',  GDK_KEY_ae},
-	{'|',  GDK_KEY_oslash},
-	{'}',  GDK_KEY_aring},
-	{'~',  GDK_KEY_udiaeresis},
-};
-/* Spanish. VT220 and higher (per XTerm docs). */
-static const struct _vte_iso2022_map16 _vte_iso2022_map_Z[] = {
-	{'#',  GDK_KEY_sterling},
-	{'@',  GDK_KEY_section},
-	{'[',  GDK_KEY_exclamdown},
-	{'\\', GDK_KEY_Ntilde},
-	{']',  GDK_KEY_questiondown},
-	{'{',  GDK_KEY_degree},
-	{'|',  GDK_KEY_ntilde},
-	{'}',  GDK_KEY_ccedilla},
-};
-/* Swedish. VT220 and higher (per XTerm docs). */
-static const struct _vte_iso2022_map16 _vte_iso2022_map_H[] = {
-	{'@',  GDK_KEY_Eacute},
-	{'[',  GDK_KEY_Adiaeresis},
-	{'\\', GDK_KEY_Odiaeresis},
-	{']',  GDK_KEY_Aring},
-	{'^',  GDK_KEY_Udiaeresis},
-	{'`',  GDK_KEY_eacute},
-	{'{',  GDK_KEY_adiaeresis},
-	{'|',  GDK_KEY_odiaeresis},
-	{'}',  GDK_KEY_aring},
-	{'~',  GDK_KEY_udiaeresis},
-};
-/* Swiss. VT220 and higher (per XTerm docs). */
-static const struct _vte_iso2022_map16 _vte_iso2022_map_equal[] = {
-	{'#',  GDK_KEY_ugrave},
-	{'@',  GDK_KEY_agrave},
-	{'[',  GDK_KEY_eacute},
-	{'\\', GDK_KEY_ccedilla},
-	{']',  GDK_KEY_ecircumflex},
-	{'^',  GDK_KEY_icircumflex},
-	{'_',  GDK_KEY_egrave},
-	{'`',  GDK_KEY_ocircumflex},
-	{'{',  GDK_KEY_adiaeresis},
-	{'|',  GDK_KEY_odiaeresis},
-	{'}',  GDK_KEY_udiaeresis},
-	{'~',  GDK_KEY_ucircumflex},
-};
-/* Codepage 437. */
-static const struct _vte_iso2022_map16 _vte_iso2022_map_U[] = {
-#include "unitable.CP437"
-};
-
-/* Japanese.  JIS X 0201-1976 ("Roman" set), per RFC 1468/2237. */
-static const struct _vte_iso2022_map16 _vte_iso2022_map_J[] = {
-#include "unitable.JIS0201"
-};
-/* Japanese.  JIS X 0208-1978, per RFC 1468/2237. */
-static const struct _vte_iso2022_map16 _vte_iso2022_map_wide_at[] = {
-#include "unitable.JIS0208"
-};
-/* Chinese.  GB 2312-80, per RFC 1922. */
-static const struct _vte_iso2022_map16 _vte_iso2022_map_wide_A[] = {
-#include "unitable.GB2312"
-};
-/* Japanese.  JIS X 0208-1983, per RFC 1468/2237. */
-static const struct _vte_iso2022_map16 _vte_iso2022_map_wide_B[] = {
-#include "unitable.JIS0208"
-};
-/* Korean.  KS X 1001 (formerly KS C 5601), per Ken Lunde's
- * CJKV_Information_Processing. */
-static const struct _vte_iso2022_map16 _vte_iso2022_map_wide_C[] = {
-#include "unitable.KSX1001"
-};
-/* Japanese.  JIS X 0212-1990, per RFC 2237. */
-static const struct _vte_iso2022_map16 _vte_iso2022_map_wide_D[] = {
-#include "unitable.JIS0212"
-};
-/* Chinese.  CNS 11643-plane-1, per RFC 1922. */
-static const struct _vte_iso2022_map32 _vte_iso2022_map_wide_G[] = {
-#include "unitable.CNS11643"
-};
-
-static gint
-_vte_direct_compare(gconstpointer a, gconstpointer b)
-{
-	return GPOINTER_TO_INT(a) - GPOINTER_TO_INT(b);
-}
-
-/* If we have the encoding, decide how wide an ambiguously-wide character is
- * based on the encoding.  This is basically what GNU libc does, and it agrees
- * with my reading of Unicode UAX 11, so.... */
-static int
-_vte_iso2022_ambiguous_width(struct _vte_iso2022_state *state)
-{
-	const char wide_codelist[][10] = {
-		"big5",
-		"big5hkscs",
-		"euccn",
-		"eucjp",
-		"euckr",
-		"euctw",
-		"gb18030",
-		"gb2312",
-		"gbk",
-		"shiftjis",
-		"tcvn",
-	};
-	gsize i, j;
-	char codeset[16];
-
-	/* Catch weirdo cases. */
-	if ((state->codeset == NULL) || (state->codeset[0] == '\0')) {
-		return 1;
-	}
-
-	/* Sort-of canonify the encoding name. */
-	i = j = 0;
-	for (i = 0; state->codeset[i] != '\0'; i++) {
-		if (g_ascii_isalnum(state->codeset[i]))
-			codeset[j++] = g_ascii_tolower(state->codeset[i]);
-
-		if (j >= sizeof(codeset) - 1)
-			break;
-	}
-	codeset[j] = '\0';
-
-	/* Check for the name in the list. */
-	for (i = 0; i < G_N_ELEMENTS(wide_codelist); i++) {
-		if (strcmp(codeset, wide_codelist[i]) == 0) {
-			return 2;
-		}
-	}
-
-	/*
-	 * Decide the ambiguous width according to user preference if
-	 * current locale is UTF-8.
-	 */
-	if (strcmp (codeset, "utf8") == 0) {
-                return state->utf8_ambiguous_width;
-	}
-
-	/* Not in the list => not wide. */
-	return 1;
-}
-
-static gboolean
-_vte_unichar_iswide_cjk(gunichar c)
-{
-        /* U+254C..U+254F and U+2574..U+257F have East Asian Width property
-         * N (neutral) while all the other line drawing characters are
-         * A (ambigous). This makes those characters not match up with those
-         * other line drawing characters from the Box Drawing (U+2500..U+257F)
-         * block; so we treat them as ambigous too.
-         *
-         * And we also do the same for the Terminal Graphic Characters
-         * (U+2596..U+259F) as well as U+2590 and U+2591 from the Block Elements 
-         * (U+2580..U+259F) block.
-         */
-        return G_UNLIKELY(c >= 0x2500 && c <= 0x259f);
-}
-
-static inline gboolean
-_vte_iso2022_is_ambiguous(gunichar c)
-{
-	if (G_LIKELY (c < 0x80))
-		return FALSE;
-	if (G_UNLIKELY (g_unichar_iszerowidth (c)))
-		return FALSE;
-	return G_UNLIKELY (!g_unichar_iswide (c) && (g_unichar_iswide_cjk (c) || _vte_unichar_iswide_cjk (c)));
-}
-
-int
-_vte_iso2022_unichar_width(struct _vte_iso2022_state *state,
-			   gunichar c)
-{
-	if (G_LIKELY (c < 0x80))
-		return 1;
-	if (G_UNLIKELY (g_unichar_iszerowidth (c)))
-		return 0;
-	if (G_UNLIKELY (g_unichar_iswide (c)))
-		return 2;
-	if (G_LIKELY (state->ambiguous_width == 1))
-		return 1;
-	if (G_UNLIKELY (g_unichar_iswide_cjk (c)))
-		return 2;
-	return 1;
-}
-
-static GHashTable *
-_vte_iso2022_map_init16(const struct _vte_iso2022_map16 *map, gssize length)
-{
-	GHashTable *ret;
-	int i;
-	if (length == 0) {
-		return NULL;
-	}
-	ret = g_hash_table_new(NULL, NULL);
-	for (i = 0; i < length; i++) {
-		g_hash_table_insert(ret,
-			      GINT_TO_POINTER((unsigned int) map[i].from),
-			      GINT_TO_POINTER((unsigned int) map[i].to));
-	}
-	return ret;
-}
-
-static GHashTable *
-_vte_iso2022_map_init32(const struct _vte_iso2022_map32 *map, gssize length)
-{
-	GHashTable *ret;
-	int i;
-	if (length == 0) {
-		return NULL;
-	}
-	ret = g_hash_table_new(NULL, NULL);
-	for (i = 0; i < length; i++) {
-		g_hash_table_insert(ret,
-			      GINT_TO_POINTER((unsigned int) map[i].from),
-			      GINT_TO_POINTER((unsigned int) map[i].to));
-	}
-	return ret;
-}
-
-static void
-_vte_iso2022_map_get(gunichar mapname,
-		     GHashTable **_map, guint *bytes_per_char, guint *force_width,
-		     gulong *or_mask, gulong *and_mask)
-{
-	static VteTree *maps = NULL;
-	gint bytes = 0, width = 0;
-	GHashTable *map = NULL;
-	gboolean new_map = FALSE;
-	gsize i;
-
-	if (or_mask) {
-		*or_mask = 0;
-	}
-	if (and_mask) {
-		*and_mask = (~(0));
-	}
-
-	/* Make sure we have a map, erm, map. */
-	if (maps == NULL) {
-		maps = _vte_tree_new(_vte_direct_compare);
-	}
-
-	/* Check for a cached map for this charset. */
-	map = _vte_tree_lookup(maps, GINT_TO_POINTER(mapname));
-	new_map = map == NULL;
-
-	/* Construct a new one. */
-	switch (mapname) {
-	case '0':
-		if (G_UNLIKELY (map == NULL)) {
-			map = _vte_iso2022_map_init16(_vte_iso2022_map_0,
-					    G_N_ELEMENTS(_vte_iso2022_map_0));
-		}
-		width = 1;
-		bytes = 1;
-		break;
-	case 'A':
-		if (G_UNLIKELY (map == NULL)) {
-			map = _vte_iso2022_map_init16(_vte_iso2022_map_A,
-					    G_N_ELEMENTS(_vte_iso2022_map_A));
-		}
-		width = 1;
-		bytes = 1;
-		break;
-	case '1': /* treated as an alias in xterm */
-	case '2': /* treated as an alias in xterm */
-	case 'B':
-		if (G_UNLIKELY (map == NULL)) {
-			map = _vte_iso2022_map_init16(_vte_iso2022_map_B,
-					    G_N_ELEMENTS(_vte_iso2022_map_B));
-		}
-		width = 1;
-		bytes = 1;
-		break;
-	case '4':
-		if (G_UNLIKELY (map == NULL)) {
-			map = _vte_iso2022_map_init16(_vte_iso2022_map_4,
-					    G_N_ELEMENTS(_vte_iso2022_map_4));
-		}
-		width = 1;
-		bytes = 1;
-		break;
-	case 'C':
-	case '5':
-		if (G_UNLIKELY (map == NULL)) {
-			map = _vte_iso2022_map_init16(_vte_iso2022_map_C,
-					    G_N_ELEMENTS(_vte_iso2022_map_C));
-		}
-		width = 1;
-		bytes = 1;
-		break;
-	case 'R':
-		if (G_UNLIKELY (map == NULL)) {
-			map = _vte_iso2022_map_init16(_vte_iso2022_map_R,
-					    G_N_ELEMENTS(_vte_iso2022_map_R));
-		}
-		width = 1;
-		bytes = 1;
-		break;
-	case 'Q':
-		if (G_UNLIKELY (map == NULL)) {
-			map = _vte_iso2022_map_init16(_vte_iso2022_map_Q,
-					    G_N_ELEMENTS(_vte_iso2022_map_Q));
-		}
-		width = 1;
-		bytes = 1;
-		break;
-	case 'K':
-		if (G_UNLIKELY (map == NULL)) {
-			map = _vte_iso2022_map_init16(_vte_iso2022_map_K,
-					    G_N_ELEMENTS(_vte_iso2022_map_K));
-		}
-		width = 1;
-		bytes = 1;
-		break;
-	case 'Y':
-		if (G_UNLIKELY (map == NULL)) {
-			map = _vte_iso2022_map_init16(_vte_iso2022_map_Y,
-					    G_N_ELEMENTS(_vte_iso2022_map_Y));
-		}
-		width = 1;
-		bytes = 1;
-		break;
-	case 'E':
-	case '6':
-		if (G_UNLIKELY (map == NULL)) {
-			map = _vte_iso2022_map_init16(_vte_iso2022_map_E,
-					    G_N_ELEMENTS(_vte_iso2022_map_E));
-		}
-		width = 1;
-		bytes = 1;
-		break;
-	case 'Z':
-		if (G_UNLIKELY (map == NULL)) {
-			map = _vte_iso2022_map_init16(_vte_iso2022_map_Z,
-					    G_N_ELEMENTS(_vte_iso2022_map_Z));
-		}
-		width = 1;
-		bytes = 1;
-		break;
-	case 'H':
-	case '7':
-		if (G_UNLIKELY (map == NULL)) {
-			map = _vte_iso2022_map_init16(_vte_iso2022_map_H,
-					    G_N_ELEMENTS(_vte_iso2022_map_H));
-		}
-		width = 1;
-		bytes = 1;
-		break;
-	case '=':
-		if (G_UNLIKELY (map == NULL)) {
-			map = _vte_iso2022_map_init16(_vte_iso2022_map_equal,
-					    G_N_ELEMENTS(_vte_iso2022_map_equal));
-		}
-		width = 1;
-		bytes = 1;
-		break;
-	case 'U':
-		if (G_UNLIKELY (map == NULL)) {
-			map = _vte_iso2022_map_init16(_vte_iso2022_map_U,
-					    G_N_ELEMENTS(_vte_iso2022_map_U));
-		}
-		width = 1;
-		bytes = 1;
-		break;
-	case 'J':
-		if (G_UNLIKELY (map == NULL)) {
-			map = _vte_iso2022_map_init16(_vte_iso2022_map_J,
-					    G_N_ELEMENTS(_vte_iso2022_map_J));
-		}
-		width = 1;
-		bytes = 1;
-		break;
-	case '@' + WIDE_FUDGE:
-		if (G_UNLIKELY (map == NULL)) {
-			map = _vte_iso2022_map_init16(_vte_iso2022_map_wide_at,
-					    G_N_ELEMENTS(_vte_iso2022_map_wide_at));
-		}
-		width = 2; /* CJKV expects 2 bytes -> 2 columns */
-		bytes = 2;
-		*and_mask = 0xf7f7f;
-		break;
-	case 'A' + WIDE_FUDGE:
-		if (G_UNLIKELY (map == NULL)) {
-			map = _vte_iso2022_map_init16(_vte_iso2022_map_wide_A,
-					    G_N_ELEMENTS(_vte_iso2022_map_wide_A));
-		}
-		width = 2; /* CJKV expects 2 bytes -> 2 columns */
-		bytes = 2;
-		*and_mask = 0xf7f7f;
-		break;
-	case 'B' + WIDE_FUDGE:
-		if (G_UNLIKELY (map == NULL)) {
-			map = _vte_iso2022_map_init16(_vte_iso2022_map_wide_B,
-					    G_N_ELEMENTS(_vte_iso2022_map_wide_B));
-		}
-		width = 2; /* CJKV expects 2 bytes -> 2 columns */
-		bytes = 2;
-		*and_mask = 0xf7f7f;
-		break;
-	case 'C' + WIDE_FUDGE:
-		if (G_UNLIKELY (map == NULL)) {
-			map = _vte_iso2022_map_init16(_vte_iso2022_map_wide_C,
-					    G_N_ELEMENTS(_vte_iso2022_map_wide_C));
-		}
-		width = 2; /* CJKV expects 2 bytes -> 2 columns */
-		bytes = 2;
-		*and_mask = 0xf7f7f;
-		break;
-	case 'D' + WIDE_FUDGE:
-		if (G_UNLIKELY (map == NULL)) {
-			map = _vte_iso2022_map_init16(_vte_iso2022_map_wide_D,
-					    G_N_ELEMENTS(_vte_iso2022_map_wide_D));
-		}
-		width = 2; /* CJKV expects 2 bytes -> 2 columns */
-		bytes = 2;
-		*and_mask = 0xf7f7f;
-		break;
-	case 'G' + WIDE_FUDGE:
-		if (G_UNLIKELY (map == NULL)) {
-			map = _vte_iso2022_map_init32(_vte_iso2022_map_wide_G,
-					    G_N_ELEMENTS(_vte_iso2022_map_wide_G));
-		}
-		/* Return the plane number as part of the "or" mask. */
-		g_assert(or_mask != NULL);
-		*or_mask = 0x10000;
-		*and_mask = 0xf7f7f;
-		width = 2; /* CJKV expects 2 bytes -> 2 columns */
-		bytes = 2;
-		break;
-	case 'H' + WIDE_FUDGE:
-		if (G_UNLIKELY (map == NULL)) {
-			map = _vte_iso2022_map_init32(_vte_iso2022_map_wide_G,
-					    G_N_ELEMENTS(_vte_iso2022_map_wide_G));
-		}
-		/* Return the plane number as part of the "or" mask. */
-		g_assert(or_mask != NULL);
-		*or_mask = 0x20000;
-		*and_mask = 0xf7f7f;
-		width = 2; /* CJKV expects 2 bytes -> 2 columns */
-		bytes = 2;
-		break;
-	case 'I' + WIDE_FUDGE:
-		if (G_UNLIKELY (map == NULL)) {
-			map = _vte_iso2022_map_init32(_vte_iso2022_map_wide_G,
-					    G_N_ELEMENTS(_vte_iso2022_map_wide_G));
-		}
-		/* Return the plane number as part of the "or" mask. */
-		g_assert(or_mask != NULL);
-		*or_mask = 0x30000;
-		*and_mask = 0xf7f7f;
-		width = 2; /* CJKV expects 2 bytes -> 2 columns */
-		bytes = 2;
-		break;
-	case 'J' + WIDE_FUDGE:
-		if (G_UNLIKELY (map == NULL)) {
-			map = _vte_iso2022_map_init32(_vte_iso2022_map_wide_G,
-					    G_N_ELEMENTS(_vte_iso2022_map_wide_G));
-		}
-		/* Return the plane number as part of the "or" mask. */
-		g_assert(or_mask != NULL);
-		*or_mask = 0x40000;
-		*and_mask = 0xf7f7f;
-		width = 2; /* CJKV expects 2 bytes -> 2 columns */
-		bytes = 2;
-		break;
-	case 'K' + WIDE_FUDGE:
-		if (map == NULL) {
-			map = _vte_iso2022_map_init32(_vte_iso2022_map_wide_G,
-					    G_N_ELEMENTS(_vte_iso2022_map_wide_G));
-		}
-		/* Return the plane number as part of the "or" mask. */
-		g_assert(or_mask != NULL);
-		*or_mask = 0x50000;
-		*and_mask = 0xf7f7f;
-		width = 2; /* CJKV expects 2 bytes -> 2 columns */
-		bytes = 2;
-		break;
-	case 'L' + WIDE_FUDGE:
-		if (G_UNLIKELY (map == NULL)) {
-			map = _vte_iso2022_map_init32(_vte_iso2022_map_wide_G,
-					    G_N_ELEMENTS(_vte_iso2022_map_wide_G));
-		}
-		/* Return the plane number as part of the "or" mask. */
-		g_assert(or_mask != NULL);
-		*or_mask = 0x60000;
-		*and_mask = 0xf7f7f;
-		width = 2; /* CJKV expects 2 bytes -> 2 columns */
-		bytes = 2;
-		break;
-	case 'M' + WIDE_FUDGE:
-		if (G_UNLIKELY(map == NULL)) {
-			map = _vte_iso2022_map_init32(_vte_iso2022_map_wide_G,
-					    G_N_ELEMENTS(_vte_iso2022_map_wide_G));
-		}
-		/* Return the plane number as part of the "or" mask. */
-		g_assert(or_mask != NULL);
-		*or_mask = 0x70000;
-		*and_mask = 0xf7f7f;
-		width = 2; /* CJKV expects 2 bytes -> 2 columns */
-		bytes = 2;
-		break;
-	default:
-		/* No such map.  Set up a ISO-8859-1 to UCS-4 map. */
-		if (G_UNLIKELY (map == NULL)) {
-			struct _vte_iso2022_map16 _vte_iso2022_map_NUL[256];
-			for (i = 0; i < G_N_ELEMENTS(_vte_iso2022_map_NUL); i++) {
-				_vte_iso2022_map_NUL[i].from = (i & 0xff);
-				_vte_iso2022_map_NUL[i].to = (i & 0xff);
-			}
-			map = _vte_iso2022_map_init16(_vte_iso2022_map_NUL,
-					    G_N_ELEMENTS(_vte_iso2022_map_NUL));
-		}
-		width = 1;
-		bytes = 1;
-		break;
-	}
-	/* Save the new map. */
-	if (G_UNLIKELY(new_map && map != NULL)) {
-		_vte_tree_insert(maps, GINT_TO_POINTER(mapname), map);
-	}
-	/* Return. */
-	if (_map) {
-		*_map = map;
-	}
-	if (bytes_per_char) {
-		*bytes_per_char = bytes;
-	}
-	if (force_width) {
-		*force_width = width;
-	}
-}
-
-int
-_vte_iso2022_get_encoded_width(gunichar c)
-{
-	int width;
-	width = (c & VTE_ISO2022_ENCODED_WIDTH_MASK) >> VTE_ISO2022_ENCODED_WIDTH_BIT_OFFSET;
-	return CLAMP(width, 0, 2);
-}
-
-static gunichar
-_vte_iso2022_set_encoded_width(gunichar c, int width)
-{
-	width = CLAMP(width, 0, 2);
-	c &= ~(VTE_ISO2022_ENCODED_WIDTH_MASK);
-	c |= (width << VTE_ISO2022_ENCODED_WIDTH_BIT_OFFSET);
-	return c;
-}
-
 struct _vte_iso2022_state *
-_vte_iso2022_state_new(const char *native_codeset,
-                       int utf8_ambiguous_width,
-		       _vte_iso2022_codeset_changed_cb_fn fn,
-		       gpointer data)
+_vte_iso2022_state_new(const char *native_codeset)
 {
 	struct _vte_iso2022_state *state;
 
-        g_return_val_if_fail(utf8_ambiguous_width == 1 || utf8_ambiguous_width == 2, NULL);
-
 	state = g_slice_new0(struct _vte_iso2022_state);
-	state->nrc_enabled = TRUE;
-	state->current = 0;
-	state->override = -1;
-	state->g[0] = 'B';
-	state->g[1] = 'B';
-	state->g[2] = 'B';
-	state->g[3] = 'B';
 	state->native_codeset = state->codeset = g_intern_string(native_codeset);
 	if (native_codeset == NULL) {
                 const char *codeset;
@@ -784,8 +62,6 @@ _vte_iso2022_state_new(const char *native_codeset,
 			"Native codeset \"%s\", currently %s\n",
 			state->native_codeset, state->codeset);
 	state->conv = _vte_conv_open(state->target_codeset, state->codeset);
-	state->codeset_changed = fn;
-	state->codeset_changed_data = data;
 	state->buffer = _vte_byte_array_new();
 	if (state->conv == VTE_INVALID_CONV) {
 		g_warning(_("Unable to convert characters from %s to %s."),
@@ -800,7 +76,6 @@ _vte_iso2022_state_new(const char *native_codeset,
 				state->codeset, state->target_codeset);
 		}
 	}
-        _vte_iso2022_state_set_utf8_ambiguous_width(state, utf8_ambiguous_width);
 	return state;
 }
 
@@ -836,8 +111,6 @@ _vte_iso2022_state_set_codeset(struct _vte_iso2022_state *state,
 	}
 	state->codeset = g_intern_string (codeset);
 	state->conv = conv;
-	state->ambiguous_width = _vte_iso2022_ambiguous_width (state);
-
 }
 
 const char *
@@ -846,348 +119,20 @@ _vte_iso2022_state_get_codeset(struct _vte_iso2022_state *state)
 	return state->codeset;
 }
 
-void
-_vte_iso2022_state_set_utf8_ambiguous_width(struct _vte_iso2022_state *state,
-                                            int utf8_ambiguous_width)
-{
-        state->utf8_ambiguous_width = utf8_ambiguous_width;
-	state->ambiguous_width = _vte_iso2022_ambiguous_width(state);
-}
-
-static const guchar *
-_vte_iso2022_find_nextctl(const guchar *p, const guchar * const q)
-{
-	do {
-		switch (*p) {
-			case '\033':
-			case '\n':
-			case '\r':
-			case '\016':
-			case '\017':
-#ifdef VTE_ISO2022_8_BIT_CONTROLS
-		    /* This breaks UTF-8 and other encodings which
-		     * use the high bits.
-		     */
-			case '0x8e':
-			case '0x8f':
-#endif
-				return p;
-		}
-	} while (++p < q);
-	return NULL;
-}
-
-static long
-_vte_iso2022_sequence_length(const unsigned char *nextctl, gsize length)
-{
-	long sequence_length = -1;
-	gsize i;
-
-	switch (nextctl[0]) {
-	case '\n':
-	case '\r':
-	case '\016':
-	case '\017':
-		/* LF */
-		/* CR */
-		/* SO */
-		/* SI */
-		sequence_length = 1;
-		break;
-	case 0x8e:
-	case 0x8f:
-		/* SS2 - 8bit */
-		/* SS3 - 8bit */
-		sequence_length = 1;
-		break;
-	case '\033':
-		if (length < 2) {
-			/* Inconclusive. */
-			sequence_length = 0;
-		} else {
-			switch (nextctl[1]) {
-			case '[':
-				/* ESC [, the CSI.  The first letter
-				 * is the end of the sequence, */
-				for (i = 2; i < length; i++) {
-					if (g_unichar_isalpha(nextctl[i])) {
-						break;
-					}
-					if ((nextctl[i] == '@') ||
-					    (nextctl[i] == '`') ||
-					    (nextctl[i] == '{') ||
-					    (nextctl[i] == '|')) {
-						break;
-					}
-				}
-				if (i < length) {
-					/* Return the length of this
-					 * sequence. */
-					sequence_length = i + 1;
-				} else {
-					/* Inconclusive. */
-					sequence_length = 0;
-				}
-				break;
-#if 0
-			case ']':
-				/* ESC ], the OSC.  Search for a string
-				 * terminator or a BEL. */
-				for (i = 2; i < q - nextctl - 1; i++) {
-					if ((nextctl[i] == '\033') &&
-					    (nextctl[i + 1] == '\\')) {
-						break;
-					}
-				}
-				if (i < length - 1) {
-					/* Return the length of this
-					 * sequence. */
-					sequence_length = i + 1;
-				} else {
-					for (i = 2; i < length; i++) {
-						if (nextctl[i] == '\007') {
-							break;
-						}
-					}
-					if (i < length) {
-						/* Return the length of
-						 * this sequence. */
-						sequence_length = i + 1;
-					} else {
-						/* Inconclusive. */
-						sequence_length = 0;
-					}
-				}
-				break;
-#endif
-#if 0
-			case '^':
-				/* ESC ^, the PM.  Search for a string
-				 * terminator. */
-#endif
-			case 'P':
-				/* ESC P, the DCS.  Search for a string
-				 * terminator. */
-				for (i = 2; i < length - 1; i++) {
-					if ((nextctl[i] == '\033') &&
-					    (nextctl[i + 1] == '\\')) {
-						break;
-					}
-				}
-				if (i < length - 1) {
-					/* Return the length of this
-					 * sequence. */
-					sequence_length = i + 1;
-				} else {
-					/* Inconclusive. */
-					sequence_length = 0;
-				}
-				break;
-			case 'N':
-			case 'O':
-			case 'n':
-			case 'o':
-				/* ESC N */
-				/* ESC O */
-				/* ESC n */
-				/* ESC o */
-				sequence_length = 2;
-				break;
-			case '(':
-			case ')':
-			case '*':
-			case '+':
-				if (length < 3) {
-					/* Inconclusive. */
-					sequence_length = 0;
-				} else {
-					/* ESC ) x */
-					/* ESC ( x */
-					/* ESC * x */
-					/* ESC + x */
-					/* Just accept whatever. */
-					sequence_length = 3;
-				}
-				break;
-			case '%':
-				if (length < 3) {
-					/* Inconclusive. */
-					sequence_length = 0;
-				} else {
-					/* ESC % @ */
-					/* ESC % G */
-					switch (nextctl[2]) {
-					case '@':
-					case 'G':
-						sequence_length = 3;
-						break;
-					default:
-						break;
-					}
-				}
-				break;
-			case '$':
-				if (length < 3) {
-					/* Inconclusive. */
-					sequence_length = 0;
-				} else {
-					switch (nextctl[2]) {
-					case '@':
-					case 'B':
-						/* ESC $ @ */
-						/* ESC $ B */
-						sequence_length = 3;
-						break;
-					case '(':
-					case ')':
-					case '*':
-					case '+':
-						/* ESC $ ( x */
-						/* ESC $ ) x */
-						/* ESC $ * x */
-						/* ESC $ + x */
-						if (length < 4) {
-							/* Inconclusive. */
-							sequence_length = 0;
-						} else {
-							/* strchr(WIDE_GMAPS, nextctl[3]) */
-							switch (nextctl[3]) {
-							case 'C':
-							case 'A':
-							case 'G':
-							case 'H':
-							case 'I':
-							case 'J':
-							case 'K':
-							case 'L':
-							case 'M':
-							case 'D':
-								sequence_length = 4;
-								break;
-							default:
-								break;
-							}
-						}
-						break;
-					}
-				}
-				break;
-			default:
-				break;
-			}
-		}
-		break;
-	}
-	return sequence_length;
-}
-
-static int
-process_8_bit_sequence(struct _vte_iso2022_state *state,
-		       const guchar **inbuf, gsize *inbytes,
-		       gunichar **outbuf, gsize *outbytes)
-{
-	guint i, width;
-	gpointer p;
-	gunichar c, *outptr;
-	const guchar *inptr;
-	gulong acc, or_mask, and_mask;
-	GHashTable *map;
-	guint bytes_per_char, force_width, current;
-
-	/* Check if it's an 8-bit escape.  If it is, take a note of which map
-	 * it's for, and if it isn't, fail. */
-	current = 0;
-	switch (**inbuf) {
-	case 0x8e:
-		current = 2;
-		break;
-	case 0x8f:
-		current = 3;
-		break;
-	default:
-		/* We processed 0 bytes, and we have no intention of looking
-		 * at this byte again. */
-		return 0;
-	}
-
-	inptr = *inbuf;
-	outptr = *outbuf;
-
-	/* Find the map, and ensure that in addition to the escape byte, we
-	 * have enough information to construct the character. */
-	_vte_iso2022_map_get(state->g[current],
-			     &map, &bytes_per_char, &force_width,
-			     &or_mask, &and_mask);
-	if (*inbytes < (bytes_per_char + 1)) {
-		/* We need more information to work with. */
-		return -1;
-	}
-
-	for (acc = 0, i = 0; i < bytes_per_char; i++) {
-		acc = (acc << 8) | ((guint8*)inptr)[i + 1];
-	}
-	*inbuf += (bytes_per_char + 1);
-	*inbytes -= (bytes_per_char + 1);
-
-	acc &= and_mask;
-	acc |= or_mask;
-	p = GINT_TO_POINTER(acc);
-	c = GPOINTER_TO_INT(g_hash_table_lookup(map, p));
-	if ((c == 0) && (acc != 0)) {
-		_vte_debug_print(VTE_DEBUG_SUBSTITUTION,
-				"%04lx -(%c)-> %04lx(?)\n",
-				acc, state->g[current] & 0xff, acc);
-	} else {
-		width = 0;
-		if (force_width != 0) {
-			width = force_width;
-		} else {
-			if (G_UNLIKELY (_vte_iso2022_is_ambiguous(c))) {
-				width = state->ambiguous_width;
-			}
-		}
-		_vte_debug_print(VTE_DEBUG_SUBSTITUTION,
-				"%05lx -> " "%04x\n", acc, c);
-		c = _vte_iso2022_set_encoded_width(c, width);
-	}
-	/* Save the unichar. */
-	g_assert(*outbytes >= sizeof(c));
-	*outbytes -= sizeof(c);
-	*outptr++ = c;
-	*outbuf = outptr;
-	/* Return the number of input bytes consumed. */
-	return bytes_per_char + 1;
-}
-
-static glong
-process_cdata(struct _vte_iso2022_state *state, const guchar *cdata, gsize length,
-	      gboolean incomplete_is_invalid, GArray *gunichars)
+gsize
+_vte_iso2022_process(struct _vte_iso2022_state *state,
+                     const guchar *cdata, gsize length,
+                     GArray *gunichars)
 {
-	int ambiguous_width;
 	glong processed = 0;
-	GHashTable *map;
-	guint bytes_per_char, force_width, current;
 	gsize converted;
 	const guchar *inbuf;
 	gunichar *outbuf, *buf;
 	gsize inbytes, outbytes;
-	guint i, j, width;
-	gulong acc, or_mask, and_mask;
+        guint i, j;
 	gunichar c;
-	gboolean single, stop;
-
-	ambiguous_width = state->ambiguous_width;
-
-	single = (state->override != -1);
-	current = single ? state->override : state->current;
-	state->override = -1;
-	g_assert(current < G_N_ELEMENTS(state->g));
-
-	_vte_debug_print(VTE_DEBUG_SUBSTITUTION,
-			"Current map = %d (%c).\n",
-			current, (state->g[current] & 0xff));
+        gboolean stop;
 
-	if (!state->nrc_enabled || (state->g[current] == 'B')) {
 		inbuf = cdata;
 		inbytes = length;
 		_vte_byte_array_set_minimum_size(state->buffer,
@@ -1202,41 +147,13 @@ process_cdata(struct _vte_iso2022_state *state, const guchar *cdata, gsize lengt
 			stop = FALSE;
 			switch (converted) {
 			case ((gsize)-1):
-				if (errno == EINVAL && incomplete_is_invalid) {
-					errno = EILSEQ;
-				}
 				switch (errno) {
 				case EILSEQ:
-					/* Check if it's an 8-bit sequence. */
-					i = process_8_bit_sequence(state,
-								   &inbuf,
-								   &inbytes,
-								   &outbuf,
-								   &outbytes);
-					switch (i) {
-					case 0:
-						/* iconv() may be buggy,
-						 * returning EILSEQ and
-						 * no remaining bytes.
-						 * Bug 567064 */
-						if (inbytes) {
-							/* Nope, munge the input. */
-							inbuf++;
-							inbytes--;
-						}
-						*outbuf++ = INVALID_CODEPOINT;
-						outbytes -= sizeof(gunichar);
-						break;
-					case -1:
-						/* Looks good so far, try again
-						 * later. */
-						stop = TRUE;
-						break;
-					default:
-						/* Processed n bytes, just keep
-						 * going. */
-						break;
-					}
+                                        /* Munge the input. */
+                                        inbuf++;
+                                        inbytes--;
+                                        *outbuf++ = INVALID_CODEPOINT;
+                                        outbytes -= sizeof(gunichar);
 					break;
 				case EINVAL:
 					/* Incomplete. Save for later. */
@@ -1256,7 +173,7 @@ process_cdata(struct _vte_iso2022_state *state, const guchar *cdata, gsize lengt
 			}
 		} while ((inbytes > 0) && !stop);
 
-		/* encode any ambiguous widths and skip blanks */
+                /* skip blanks -- TODOegmont: why here? */
 		j = gunichars->len;
 		g_array_set_size(gunichars, gunichars->len + outbuf-buf);
 		for (i = 0; buf + i < outbuf; i++) {
@@ -1265,595 +182,14 @@ process_cdata(struct _vte_iso2022_state *state, const guchar *cdata, gsize lengt
 				/* Skip the padding character. */
 				continue;
 			}
-			if (G_UNLIKELY (_vte_iso2022_is_ambiguous(c))) {
-				width = ambiguous_width;
-				c = _vte_iso2022_set_encoded_width(c, width);
-			}
 			g_array_index(gunichars, gunichar, j++) = c;
 		}
 		gunichars->len = j;
 
 		/* Done. */
 		processed = length - inbytes;
-	} else {
-		_vte_iso2022_map_get(state->g[current],
-				     &map, &bytes_per_char, &force_width,
-				     &or_mask, &and_mask);
-		i = 0;
-		acc = 0;
-		j = gunichars->len;
-		g_array_set_size(gunichars, gunichars->len + length);
-		do {
-			if (i < length) {
-				acc = (acc << 8) | cdata[i];
-			}
-			i++;
-			if ((i % bytes_per_char) == 0) {
-				acc &= and_mask;
-				acc |= or_mask;
-				c = GPOINTER_TO_INT(g_hash_table_lookup(map,
-							GINT_TO_POINTER(acc)));
-				if ((c == 0) && (acc != 0)) {
-					_vte_debug_print(VTE_DEBUG_SUBSTITUTION,
-							"%04lx -(%c)-> "
-							"%04lx(?)\n",
-							acc,
-							state->g[current] & 0xff,
-							acc);
-					c = acc;
-				} else {
-					width = 0;
-					if (force_width != 0) {
-						width = force_width;
-					} else {
-						if (G_UNLIKELY (_vte_iso2022_is_ambiguous(c))) {
-							width = ambiguous_width;
-						}
-					}
-					_vte_debug_print(VTE_DEBUG_SUBSTITUTION,
-							"%05lx -> "
-							"%04x\n", acc, c);
-					c = _vte_iso2022_set_encoded_width(c, width);
-				}
-				g_array_index(gunichars, gunichar, j++) = c;
-				if (single) {
-					break;
-				}
-				acc = 0;
-			}
-		} while (i < length);
-		processed = i;
-		gunichars->len = j;
-	}
-	return processed;
-}
-
-gunichar
-_vte_iso2022_process_single(struct _vte_iso2022_state *state,
-			    gunichar c, gunichar map)
-{
-	GHashTable *hash;
-	gunichar ret = c;
-	gpointer p;
-	guint bytes_per_char, force_width;
-	gulong or_mask, and_mask;
-
-	_vte_iso2022_map_get(map,
-			     &hash, &bytes_per_char, &force_width,
-			     &or_mask, &and_mask);
 
-	p = GINT_TO_POINTER((c & and_mask) | or_mask);
-	if (hash != NULL) {
-		p = g_hash_table_lookup(hash, p);
-	}
-	if (p != NULL) {
-		ret = GPOINTER_TO_INT(p);
-	}
-	if (force_width) {
-		ret = _vte_iso2022_set_encoded_width(ret, force_width);
-	}
-	return ret;
-}
-
-static void
-process_control(struct _vte_iso2022_state *state, guchar *ctl, gsize length,
-		GArray *gunichars)
-{
-	gunichar c;
-	gsize i;
-	if (length >= 1) {
-		switch (ctl[0]) {
-		case '\r':  /* CR */
-			c = '\r';
-			g_array_append_val(gunichars, c);
-			_vte_debug_print(VTE_DEBUG_SUBSTITUTION, "\tCR\n");
-			break;
-		case '\n':  /* LF */
-			c = '\n';
-			g_array_append_val(gunichars, c);
-			_vte_debug_print(VTE_DEBUG_SUBSTITUTION, "\tLF\n");
-			break;
-		case '\016': /* SO */
-			state->current = 1;
-			state->override = -1;
-			_vte_debug_print(VTE_DEBUG_SUBSTITUTION, "\tSO (^N)\n");
-			break;
-		case '\017': /* SI */
-			state->current = 0;
-			state->override = -1;
-			_vte_debug_print(VTE_DEBUG_SUBSTITUTION, "\tSI (^O)\n");
-			break;
-		case 0x8e:
-			/* SS2 - 8bit */
-			state->override = 2;
-			_vte_debug_print(VTE_DEBUG_SUBSTITUTION,
-					"\tSS2 (8-bit)\n");
-			break;
-		case 0x8f:
-			/* SS3 - 8bit */
-			state->override = 3;
-			_vte_debug_print(VTE_DEBUG_SUBSTITUTION,
-				"\tSS3 (8-bit)\n");
-			break;
-		case '\033':
-			if (length >= 2) {
-				switch (ctl[1]) {
-				case '[': /* CSI */
-				case ']': /* OSC */
-				case '^': /* PM */
-				case 'P': /* DCS */
-					/* Pass it through. */
-					for (i = 0; i < length; i++) {
-						c = (guchar) ctl[i];
-						g_array_append_val(gunichars,
-								   c);
-					}
-					_VTE_DEBUG_IF(VTE_DEBUG_SUBSTITUTION) {
-						g_printerr("\t");
-						for (i = 0; i < length; i++) {
-							c = (guchar) ctl[i];
-							g_printerr(
-								"(%s%c)",
-								c < 0x20 ?
-								"^" : "",
-								c < 0x20 ?
-								c : c + 64);
-						}
-						g_printerr("\n");
-					}
-					break;
-				case 'N': /* SS2 */
-					state->override = 2;
-					_vte_debug_print(VTE_DEBUG_SUBSTITUTION,
-						"\tSS2\n");
-					break;
-				case 'O': /* SS3 */
-					state->override = 3;
-					_vte_debug_print(VTE_DEBUG_SUBSTITUTION,
-						"\tSS3\n");
-					break;
-				case 'n': /* LS2 */
-					state->current = 2;
-					state->override = -1;
-					_vte_debug_print(VTE_DEBUG_SUBSTITUTION,
-							"\tLS2\n");
-					break;
-				case 'o': /* LS3 */
-					state->current = 3;
-					state->override = -1;
-					_vte_debug_print(VTE_DEBUG_SUBSTITUTION,
-							"\tLS3\n");
-					break;
-				case '(':
-				case ')':
-				case '*':
-				case '+':
-					if (length >= 3) {
-						int g = -1;
-						switch (ctl[1]) {
-						case '(':
-							g = 0;
-							break;
-						case ')':
-							g = 1;
-							break;
-						case '*':
-							g = 2;
-							break;
-						case '+':
-							g = 3;
-							break;
-						default:
-							g_assert_not_reached();
-							break;
-						}
-						/* strchr(NARROW_MAPS, c) */
-						switch (ctl[2]) {
-						case '0':
-						case '1':
-						case '2':
-						case 'A':
-						case 'B':
-						case '4':
-						case 'C':
-						case '5':
-						case 'R':
-						case 'Q':
-						case 'K':
-						case 'Y':
-						case 'E':
-						case '6':
-						case 'Z':
-						case 'H':
-						case '7':
-						case '=':
-						case 'J':
-						case 'U':
-							state->g[g] = ctl[2];
-							break;
-
-						default:
-							g_warning(_("Attempt to set invalid NRC map '%c'."), ctl[2]);
-							break;
-						}
-						_vte_debug_print(VTE_DEBUG_SUBSTITUTION,
-								"\tG[%d] = %c.\n",
-								g, c);
-					}
-					break;
-				case '%':
-					if (length >= 3) {
-						gboolean notify = FALSE;
-						switch (ctl[2]) {
-						case '@':
-							if (strcmp(state->codeset, state->native_codeset) != 0) {
-								notify = TRUE;
-							}
-							_vte_iso2022_state_set_codeset(state, state->native_codeset);
-							_vte_debug_print(VTE_DEBUG_SUBSTITUTION,
-									"\tNative encoding.\n");
-							break;
-						case 'G':
-							if (strcmp(state->codeset, state->utf8_codeset) != 0) {
-								notify = TRUE;
-							}
-							_vte_iso2022_state_set_codeset(state, state->utf8_codeset);
-							_vte_debug_print(VTE_DEBUG_SUBSTITUTION,
-									"\tUTF-8 encoding.\n");
-							break;
-						default:
-							/* Application signalled an "identified coding system" we haven't heard of.  See ECMA-35 for gory details. */
-							g_warning(_("Unrecognized identified coding system."));
-							break;
-						}
-						if (notify &&
-						    state->codeset_changed) {
-							state->codeset_changed(state, state->codeset_changed_data);
-						}
-					}
-					break;
-				case '$':
-					if (length >= 4) {
-						int g = -1;
-						c = 0;
-						switch (ctl[2]) {
-						case '@':
-							g = 0;
-							c = '@';
-							break;
-						case 'B':
-							g = 0;
-							c = 'B';
-							break;
-						case '(':
-							g = 0;
-							break;
-						case ')':
-							g = 1;
-							break;
-						case '*':
-							g = 2;
-							break;
-						case '+':
-							g = 3;
-							break;
-						default:
-							g_assert_not_reached();
-							break;
-						}
-						if (c == 0) {
-							c = ctl[3];
-						}
-						/* strchr(WIDE_MAPS WIDE_GMAPS, c) */
-						switch (c) {
-						case '@':
-						case 'B':
-						case 'C':
-						case 'A':
-						case 'G':
-						case 'H':
-						case 'I':
-						case 'J':
-						case 'K':
-						case 'L':
-						case 'M':
-						case 'D':
-							state->g[g] = c + WIDE_FUDGE;
-							break;
-
-						default:
-							g_warning(_("Attempt to set invalid wide NRC map '%c'."), c);
-							break;
-						}
-						_vte_debug_print(VTE_DEBUG_SUBSTITUTION,
-								"\tG[%d] = wide %c.\n",
-								g, c);
-					} else
-					if (length >= 3) {
-						switch (ctl[2]) {
-						case '@':
-							c = '@';
-							break;
-						case 'B':
-							c = 'B';
-							break;
-						default:
-							c = ctl[2];
-							break;
-						}
-						/* strchr(WIDE_MAPS, c) */
-						switch (c){
-						case '@':
-						case 'B':
-							state->g[0] = c + WIDE_FUDGE;
-							break;
-
-						default:
-							g_warning(_("Attempt to set invalid wide NRC map '%c'."), c);
-						}
-						_vte_debug_print(VTE_DEBUG_SUBSTITUTION,
-								"\tG[0] = wide %c.\n",
-								c);
-					}
-					break;
-				default:
-					g_assert_not_reached();
-					break;
-				}
-				break;
-			}
-			break;
-		default:
-			g_assert_not_reached();
-			break;
-		}
-	}
-}
-
-static guint
-process_block (struct _vte_iso2022_state *state,
-	       guchar *input,
-	       struct _vte_iso2022_block *block,
-	       gboolean last,
-	       gboolean incomplete_is_invalid,
-	       GArray *gunichars)
-{
-	guint preserve_last = -1;
-	guint initial;
-
-	switch (block->type) {
-	case _vte_iso2022_cdata:
-		_VTE_DEBUG_IF(VTE_DEBUG_SUBSTITUTION) {
-			guint j;
-			g_printerr("%3ld %3ld CDATA \"%.*s\"",
-				block->start, block->end,
-				(int) (block->end - block->start),
-				input + block->start);
-			g_printerr(" (");
-			for (j = block->start; j < block->end; j++) {
-				if (j > block->start) {
-					g_printerr(", ");
-				}
-				g_printerr("0x%02x",
-					input[j]);
-			}
-			g_printerr(")\n");
-		}
-		initial = 0;
-		while (initial < block->end - block->start) {
-			int j;
-			j = process_cdata(state,
-					  input +
-					  block->start +
-					  initial,
-					  block->end -
-					  block->start -
-					  initial,
-					  incomplete_is_invalid,
-					  gunichars);
-			if (j == 0) {
-				break;
-			}
-			initial += j;
-		}
-		if (initial < block->end - block->start && last) {
-			preserve_last = block->start + initial;
-		}
-		break;
-	case _vte_iso2022_control:
-		_vte_debug_print(VTE_DEBUG_SUBSTITUTION,
-				"%3ld %3ld CONTROL ",
-				block->start, block->end);
-		process_control(state,
-				input + block->start,
-				block->end - block->start,
-				gunichars);
-		break;
-	case _vte_iso2022_preserve:
-		_vte_debug_print(VTE_DEBUG_SUBSTITUTION,
-				"%3ld %3ld PRESERVE\n",
-				block->start, block->end);
-		preserve_last = block->start;
-		break;
-	default:
-		g_assert_not_reached();
-		break;
-	}
-
-	return preserve_last;
-}
-
-gsize
-_vte_iso2022_process(struct _vte_iso2022_state *state,
-		     guchar *input, gsize length,
-		     GArray *gunichars)
-{
-	struct _vte_iso2022_block block;
-	guint preserve_last = -1;
-	const guchar *nextctl, *p, *q;
-	glong sequence_length = 0;
-
-	p = input;
-	q = input + length;
-	do {
-		nextctl = _vte_iso2022_find_nextctl(p, q);
-		if (nextctl == NULL) {
-			/* It's all garden-variety data. */
-			block.type = _vte_iso2022_cdata;
-			block.start = p - input;
-			block.end = q - input;
-			preserve_last = process_block (state,
-					               input, &block,
-						       TRUE,
-						       FALSE,
-					               gunichars);
-			break;
-		}
-		/* We got some garden-variety data. */
-		if (nextctl != p) {
-			block.type = _vte_iso2022_cdata;
-			block.start = p - input;
-			block.end = nextctl - input;
-			process_block (state, input, &block, FALSE, TRUE, gunichars);
-		}
-		/* Move on to the control data. */
-		p = nextctl;
-		sequence_length = _vte_iso2022_sequence_length(nextctl,
-							       q - nextctl);
-		switch (sequence_length) {
-		case -1:
-			/* It's just garden-variety data. */
-			block.type = _vte_iso2022_cdata;
-			block.start = p - input;
-			block.end = nextctl + 1 - input;
-			/* Continue at the next byte. */
-			p = nextctl + 1;
-			break;
-		case 0:
-			/* Inconclusive.  Save this data and try again later. */
-			block.type = _vte_iso2022_preserve;
-			block.start = nextctl - input;
-			block.end = q - input;
-			/* Trigger an end-of-loop. */
-			p = q;
-			break;
-		default:
-			/* It's a control sequence. */
-			block.type = _vte_iso2022_control;
-			block.start = nextctl - input;
-			block.end = nextctl + sequence_length - input;
-			/* Continue after the sequence. */
-			p = nextctl + sequence_length;
-			break;
-		}
-		preserve_last = process_block (state,
-				               input, &block,
-					       FALSE,
-					       FALSE,
-					       gunichars);
-	} while (p < q);
-	if (preserve_last != (guint) -1) {
-		length = preserve_last;
-	}
 	_vte_debug_print(VTE_DEBUG_SUBSTITUTION,
-			"Consuming %ld bytes.\n", (long) length);
-	return length;
-}
-
-#ifdef ISO2022_MAIN
-#include <stdio.h>
-int
-main(int argc, char **argv)
-{
-	VteByteArray *buffer;
-	struct _vte_iso2022_state *state;
-	GString *string;
-	GArray *gunichars;
-	struct {
-		const char *s;
-		gboolean process;
-	} strings[] = {
-		{"abcd\033$(Cefgh\ri\nj\033)0k\017lmn\033Nopqrst\033%G", TRUE},
-		{"ABCD\033$(C\033)", TRUE},
-		{"0", TRUE},
-		{"\014\033[33;41m", TRUE},
-		{"\015", TRUE},
-		{"\014{|}\015\r\n", TRUE},
-		{"\033(B\033)0\033*B\033+B", TRUE},
-		{"\033$B$+$J4A;z\033(J~", TRUE},
-		{"\033(B\033)0\033*B\033+B", TRUE},
-		{"\033$)C\0161hD!\017", TRUE},
-		{"\033$*C\033N1hD!", TRUE},
-		{"\033$(G\043\071", TRUE},
-		{"\033(B\033)0\033*B\033+B", TRUE},
-		{"\r\n", TRUE},
-	};
-	guint i;
-	FILE *fp;
-	guchar b;
-
-	state = _vte_iso2022_state_new(NULL, VTE_ISO2022_DEFAULT_UTF8_AMBIGUOUS_WIDTH, NULL, NULL);
-	buffer = _vte_byte_array_new();
-	gunichars = g_array_new(FALSE, FALSE, sizeof(gunichar));
-	if (argc > 1) {
-		string = g_string_new(NULL);
-		for (i = 1; i < (guint) argc; i++) {
-			if (strcmp(argv[i], "-") == 0) {
-				fp = stdin;
-			} else {
-				fp = fopen(argv[i], "r");
-			}
-			while (fread(&b, sizeof(guchar), 1, fp) == sizeof(b)) {
-				g_string_append_c(string, b);
-			}
-			if (fp != stdin) {
-				fclose(fp);
-			}
-		}
-		_vte_byte_array_append(buffer, string->str, string->len);
-		_vte_iso2022_process(state, buffer->data, _vte_byte_array_length (buffer), gunichars);
-		g_string_free(string, TRUE);
-	} else {
-		for (i = 0; i < G_N_ELEMENTS(strings); i++) {
-			string = g_string_new(strings[i].s);
-			_vte_byte_array_append(buffer, string->str, string->len);
-			g_string_free(string, TRUE);
-			if (strings[i].process) {
-				_vte_iso2022_process(state, buffer->data, _vte_byte_array_length (buffer), gunichars);
-			}
-		}
-	}
-	_vte_byte_array_free(buffer);
-	_vte_iso2022_state_free(state);
-
-	string = g_string_new(NULL);
-	for (i = 0; i < gunichars->len; i++) {
-		g_string_append_unichar(string,
-					g_array_index(gunichars, gunichar, i));
-	}
-	(void) write(STDOUT_FILENO, string->str, string->len);
-	g_string_free(string, TRUE);
-
-	return 0;
+                        "Consuming %ld bytes.\n", (long) processed);
+        return processed;
 }
-#endif
diff --git a/src/iso2022.h b/src/iso2022.h
index 0c186e7..4e417c2 100644
--- a/src/iso2022.h
+++ b/src/iso2022.h
@@ -30,33 +30,15 @@
 G_BEGIN_DECLS
 
 struct _vte_iso2022_state;
-typedef void (*_vte_iso2022_codeset_changed_cb_fn)(struct _vte_iso2022_state *,
-						   gpointer);
-struct _vte_iso2022_state *_vte_iso2022_state_new(const char *native_codeset,
-                                                  int utf8_ambiguous_width,
-						  _vte_iso2022_codeset_changed_cb_fn,
-						  gpointer);
+struct _vte_iso2022_state *_vte_iso2022_state_new(const char *native_codeset);
 void _vte_iso2022_state_set_codeset(struct _vte_iso2022_state *state,
 				    const char *codeset);
-void _vte_iso2022_state_set_utf8_ambiguous_width(struct _vte_iso2022_state *state,
-                                                 int utf8_ambiguous_width);
 const char *_vte_iso2022_state_get_codeset(struct _vte_iso2022_state *state);
 gsize _vte_iso2022_process(struct _vte_iso2022_state *state,
-			  guchar *input, gsize length,
+                          const guchar *input, gsize length,
 			  GArray *gunichars);
-gunichar _vte_iso2022_process_single(struct _vte_iso2022_state *state,
-				     gunichar c, gunichar map);
 void _vte_iso2022_state_free(struct _vte_iso2022_state *);
 
-#define VTE_ISO2022_DEFAULT_UTF8_AMBIGUOUS_WIDTH 1
-
-#define VTE_ISO2022_ENCODED_WIDTH_BIT_OFFSET	28
-#define VTE_ISO2022_ENCODED_WIDTH_MASK		(3 << VTE_ISO2022_ENCODED_WIDTH_BIT_OFFSET)
-#define VTE_ISO2022_HAS_ENCODED_WIDTH(__c)	(((__c) & VTE_ISO2022_ENCODED_WIDTH_MASK) != 0)
-int _vte_iso2022_get_encoded_width(gunichar c);
-int _vte_iso2022_unichar_width(struct _vte_iso2022_state *state,
-			       gunichar c);
-
 G_END_DECLS
 
 #endif
diff --git a/src/table.c b/src/table.c
index e8d1cf6..820b00c 100644
--- a/src/table.c
+++ b/src/table.c
@@ -561,13 +561,10 @@ _vte_table_extract_string(GValueArray **array,
 {
 	GValue value = {0,};
 	gunichar *ptr;
-	guint i;
 
 	ptr = g_new(gunichar, arginfo->length + 1);
-	for (i = 0; i < arginfo->length; i++) {
-		ptr[i] = arginfo->start[i] & ~VTE_ISO2022_ENCODED_WIDTH_MASK;
-	}
-	ptr[i] = '\0';
+        memcpy(ptr, arginfo->start, sizeof(gunichar) * arginfo->length);
+        ptr[arginfo->length] = '\0';
 	g_value_init(&value, G_TYPE_POINTER);
 	g_value_set_pointer(&value, ptr);
 
diff --git a/src/vte-private.h b/src/vte-private.h
index fc6a570..5d3f268 100644
--- a/src/vte-private.h
+++ b/src/vte-private.h
@@ -104,6 +104,7 @@ G_BEGIN_DECLS
 #define VTE_UPDATE_REPEAT_TIMEOUT	30
 #define VTE_MAX_PROCESS_TIME		100
 #define VTE_CELL_BBOX_SLACK		1
+#define VTE_DEFAULT_UTF8_AMBIGUOUS_WIDTH 1
 
 #define VTE_UTF8_BPC                    (6) /* Maximum number of bytes used per UTF-8 character */
 
@@ -145,6 +146,12 @@ struct vte_match_regex {
         } cursor;
 };
 
+typedef enum _VteCharacterReplacement {
+        VTE_CHARACTER_REPLACEMENT_NONE,
+        VTE_CHARACTER_REPLACEMENT_LINE_DRAWING,
+        VTE_CHARACTER_REPLACEMENT_BRITISH
+} VteCharacterReplacement;
+
 /* The terminal's keypad/cursor state.  A terminal can either be using the
  * normal keypad, or the "application" keypad. */
 typedef enum _VteKeymode {
@@ -186,7 +193,7 @@ struct _VteTerminalPrivate {
 
 	/* Input data queues. */
 	const char *encoding;		/* the pty's encoding */
-        int iso2022_utf8_ambiguous_width;
+        int utf8_ambiguous_width;
 	struct _vte_iso2022_state *iso2022;
 	struct _vte_incoming_chunk{
 		struct _vte_incoming_chunk *next;
@@ -238,7 +245,6 @@ struct _VteTerminalPrivate {
 					   plus the current
 					   fore/back with no
 					   character data */
-		gboolean alternate_charset;
 	} normal_screen, alternate_screen, *screen;
 
 	/* Selection information. */
@@ -267,7 +273,6 @@ struct _VteTerminalPrivate {
 	gboolean margin_bell;
 	guint bell_margin;
 	gboolean allow_bold;
-	gboolean nrc_mode;
         gboolean deccolm_mode; /* DECCOLM allowed */
 	GHashTable *tabstops;
 	gboolean text_modified_flag;
@@ -275,6 +280,8 @@ struct _VteTerminalPrivate {
 	gboolean text_deleted_flag;
 	gboolean rewrap_on_resize;
 	gboolean bracketed_paste_mode;
+        VteCharacterReplacement character_replacements[2];  /* charsets in the G0 and G1 slots */
+        VteCharacterReplacement *character_replacement;     /* pointer to the active one */
 
 	/* Scrolling options. */
 	gboolean scroll_background;
diff --git a/src/vte.c b/src/vte.c
index 437139c..01d2e41 100644
--- a/src/vte.c
+++ b/src/vte.c
@@ -78,6 +78,7 @@ typedef gunichar wint_t;
 #define howmany(x, y) (((x) + ((y) - 1)) / (y))
 #endif
 
+static int _vte_unichar_width(gunichar c, int utf8_ambiguous_width);
 static void vte_terminal_set_visibility (VteTerminal *terminal, GdkVisibilityState state);
 static void vte_terminal_paste(VteTerminal *terminal, GdkAtom board);
 static void vte_terminal_real_copy_clipboard(VteTerminal *terminal);
@@ -180,6 +181,22 @@ static GTimer *process_timer;
 
 static const GtkBorder default_padding = { 1, 1, 1, 1 };
 
+static int
+_vte_unichar_width(gunichar c, int utf8_ambiguous_width)
+{
+        if (G_LIKELY (c < 0x80))
+                return 1;
+        if (G_UNLIKELY (g_unichar_iszerowidth (c)))
+                return 0;
+        if (G_UNLIKELY (g_unichar_iswide (c)))
+                return 2;
+        if (G_LIKELY (utf8_ambiguous_width == 1))
+                return 1;
+        if (G_UNLIKELY (g_unichar_iswide_cjk (c)))
+                return 2;
+        return 1;
+}
+
 /* process incoming data without copying */
 static struct _vte_incoming_chunk *free_chunks;
 static struct _vte_incoming_chunk *
@@ -617,7 +634,7 @@ vte_terminal_preedit_width(VteTerminal *terminal, gboolean left_only)
 		     (!left_only || (i < terminal->pvt->im_preedit_cursor));
 		     i++) {
 			c = g_utf8_get_char(preedit);
-			ret += _vte_iso2022_unichar_width(terminal->pvt->iso2022, c);
+                        ret += _vte_unichar_width(c, terminal->pvt->utf8_ambiguous_width);
 			preedit = g_utf8_next_char(preedit);
 		}
 	}
@@ -2069,9 +2086,6 @@ vte_terminal_get_encoding(VteTerminal *terminal)
  * when using the UTF-8 encoding (vte_terminal_set_encoding()). In all other encodings,
  * the width of ambiguous-width characters is fixed.
  *
- * This setting only takes effect the next time the terminal is reset, either
- * via escape sequence or with vte_terminal_reset().
- *
  * Since: 0.38
  */
 void
@@ -2080,9 +2094,7 @@ vte_terminal_set_cjk_ambiguous_width(VteTerminal *terminal, int width)
         g_return_if_fail(VTE_IS_TERMINAL(terminal));
         g_return_if_fail(width == 1 || width == 2);
 
-        terminal->pvt->iso2022_utf8_ambiguous_width = width;
-        if (terminal->pvt->pty == NULL)
-                _vte_iso2022_state_set_utf8_ambiguous_width(terminal->pvt->iso2022, width);
+        terminal->pvt->utf8_ambiguous_width = width;
 }
 
 /**
@@ -2100,7 +2112,7 @@ int
 vte_terminal_get_cjk_ambiguous_width(VteTerminal *terminal)
 {
         g_return_val_if_fail(VTE_IS_TERMINAL(terminal), 1);
-        return terminal->pvt->iso2022_utf8_ambiguous_width;
+        return terminal->pvt->utf8_ambiguous_width;
 }
 
 static inline VteRowData *
@@ -3087,28 +3099,57 @@ _vte_terminal_insert_char(VteTerminal *terminal, gunichar c,
 	VteScreen *screen;
 	gboolean line_wrapped = FALSE; /* cursor moved before char inserted */
 
+        /* DEC Special Character and Line Drawing Set.  VT100 and higher (per XTerm docs). */
+        static gunichar line_drawing_map[31] = {
+                0x25c6,  /* ` => diamond */
+                0x2592,  /* a => checkerboard */
+                0x2409,  /* b => HT symbol */
+                0x240c,  /* c => FF symbol */
+                0x240d,  /* d => CR symbol */
+                0x240a,  /* e => LF symbol */
+                0x00b0,  /* f => degree */
+                0x00b1,  /* g => plus/minus */
+                0x2424,  /* h => NL symbol */
+                0x240b,  /* i => VT symbol */
+                0x2518,  /* j => downright corner */
+                0x2510,  /* k => upright corner */
+                0x250c,  /* l => upleft corner */
+                0x2514,  /* m => downleft corner */
+                0x253c,  /* n => cross */
+                0x23ba,  /* o => scan line 1/9 */
+                0x23bb,  /* p => scan line 3/9 */
+                0x2500,  /* q => horizontal line (also scan line 5/9) */
+                0x23bc,  /* r => scan line 7/9 */
+                0x23bd,  /* s => scan line 9/9 */
+                0x251c,  /* t => left t */
+                0x2524,  /* u => right t */
+                0x2534,  /* v => bottom t */
+                0x252c,  /* w => top t */
+                0x2502,  /* x => vertical line */
+                0x2264,  /* y => <= */
+                0x2265,  /* z => >= */
+                0x03c0,  /* { => pi */
+                0x2260,  /* | => not equal */
+                0x00a3,  /* } => pound currency sign */
+                0x00b7,  /* ~ => bullet */
+        };
+
 	screen = terminal->pvt->screen;
 	insert |= screen->insert_mode;
 	invalidate_now |= insert;
 
 	/* If we've enabled the special drawing set, map the characters to
 	 * Unicode. */
-	if (G_UNLIKELY (screen->alternate_charset)) {
-		_vte_debug_print(VTE_DEBUG_SUBSTITUTION,
-				"Attempting charset substitution"
-				"for U+%04X.\n", c);
-		/* See if there's a mapping for it. */
-		c = _vte_iso2022_process_single(terminal->pvt->iso2022, c, '0');
-	}
+        if (G_UNLIKELY (*terminal->pvt->character_replacement == VTE_CHARACTER_REPLACEMENT_LINE_DRAWING)) {
+                if (c >= 96 && c <= 126)
+                        c = line_drawing_map[c - 96];
+        } else if (G_UNLIKELY (*terminal->pvt->character_replacement == VTE_CHARACTER_REPLACEMENT_BRITISH)) {
+                if (G_UNLIKELY (c == '#'))
+                        c = 0x00a3;  /* pound sign */
+        }
 
 	/* Figure out how many columns this character should occupy. */
-	if (G_UNLIKELY (VTE_ISO2022_HAS_ENCODED_WIDTH(c))) {
-		columns = _vte_iso2022_get_encoded_width(c);
-		c &= ~VTE_ISO2022_ENCODED_WIDTH_MASK;
-	} else {
-		columns = _vte_iso2022_unichar_width(terminal->pvt->iso2022, c);
-	}
-
+        columns = _vte_unichar_width(c, terminal->pvt->utf8_ambiguous_width);
 
 	/* If we're autowrapping here, do it. */
 	col = screen->cursor_current.col;
@@ -3861,20 +3902,19 @@ skip_chunk:
 				}
 			}
 			_VTE_DEBUG_IF(VTE_DEBUG_PARSE) {
-				gunichar cc = c & ~VTE_ISO2022_ENCODED_WIDTH_MASK;
-				if (cc > 255) {
-					g_printerr("U+%04lx\n", (long) cc);
+                                if (c > 255) {
+                                        g_printerr("U+%04lx\n", (long) c);
 				} else {
-					if (cc > 127) {
+                                        if (c > 127) {
 						g_printerr("%ld = ",
-								(long) cc);
+                                                                (long) c);
 					}
-					if (cc < 32) {
+                                        if (c < 32) {
 						g_printerr("^%lc\n",
-								(wint_t)cc + 64);
+                                                                (wint_t)c + 64);
 					} else {
 						g_printerr("`%lc'\n",
-								(wint_t)cc);
+                                                                (wint_t)c);
 					}
 				}
 			}
@@ -7985,12 +8025,6 @@ _vte_terminal_inline_error_message(VteTerminal *terminal, const char *format, ..
 	g_free (str);
 }
 
-static void
-_vte_terminal_codeset_changed_cb(struct _vte_iso2022_state *state, gpointer p)
-{
-	vte_terminal_set_encoding(p, _vte_iso2022_state_get_codeset(state));
-}
-
 /* Initialize the terminal widget after the base widget stuff is initialized.
  * We need to create a new psuedo-terminal pair, and set ourselves up to do
  * the interpretation of sequences. */
@@ -8045,17 +8079,19 @@ vte_terminal_init(VteTerminal *terminal)
 	pvt->screen = &terminal->pvt->normal_screen;
 	_vte_terminal_set_default_attributes(terminal);
 
+        /* Initialize charset modes. */
+        pvt->character_replacements[0] = VTE_CHARACTER_REPLACEMENT_NONE;
+        pvt->character_replacements[1] = VTE_CHARACTER_REPLACEMENT_NONE;
+        pvt->character_replacement = &pvt->character_replacements[0];
+
 	/* Set up the desired palette. */
 	vte_terminal_set_default_colors(terminal);
 	for (i = 0; i < VTE_PALETTE_SIZE; i++)
 		terminal->pvt->palette[i].sources[VTE_COLOR_SOURCE_ESCAPE].is_set = FALSE;
 
 	/* Set up I/O encodings. */
-        pvt->iso2022_utf8_ambiguous_width = VTE_ISO2022_DEFAULT_UTF8_AMBIGUOUS_WIDTH;
-	pvt->iso2022 = _vte_iso2022_state_new(pvt->encoding,
-                                              pvt->iso2022_utf8_ambiguous_width,
-					      &_vte_terminal_codeset_changed_cb,
-					      terminal);
+        pvt->utf8_ambiguous_width = VTE_DEFAULT_UTF8_AMBIGUOUS_WIDTH;
+        pvt->iso2022 = _vte_iso2022_state_new(pvt->encoding);
 	pvt->incoming = NULL;
 	pvt->pending = g_array_new(FALSE, TRUE, sizeof(gunichar));
 	pvt->max_input_bytes = VTE_MAX_INPUT_READ;
@@ -8094,7 +8130,6 @@ vte_terminal_init(VteTerminal *terminal)
 	pvt->audible_bell = TRUE;
 	pvt->bell_margin = 10;
 	pvt->allow_bold = TRUE;
-	pvt->nrc_mode = TRUE;
         pvt->deccolm_mode = FALSE;
         pvt->rewrap_on_resize = TRUE;
 	vte_terminal_set_default_tabstops(terminal);
@@ -10278,8 +10313,8 @@ vte_terminal_paint_im_preedit_string(VteTerminal *terminal)
 		items = g_new(struct _vte_draw_text_request, len);
 		for (i = columns = 0; i < len; i++) {
 			items[i].c = g_utf8_get_char(preedit);
-			items[i].columns = _vte_iso2022_unichar_width(terminal->pvt->iso2022,
-								      items[i].c);
+                        items[i].columns = _vte_unichar_width(items[i].c,
+                                                              terminal->pvt->utf8_ambiguous_width);
 			items[i].x = (col + columns) * width;
 			items[i].y = row * height;
 			columns += items[i].columns;
@@ -11391,7 +11426,7 @@ vte_terminal_class_init(VteTerminalClass *klass)
                 (gobject_class,
                  PROP_CURSOR_BLINK_MODE,
                  g_param_spec_int ("cjk-ambiguous-width", NULL, NULL,
-                                   1, 2, VTE_ISO2022_DEFAULT_UTF8_AMBIGUOUS_WIDTH,
+                                   1, 2, VTE_DEFAULT_UTF8_AMBIGUOUS_WIDTH,
                                     G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
         /**
@@ -12380,10 +12415,7 @@ vte_terminal_reset(VteTerminal *terminal,
 	_vte_byte_array_clear(pvt->outgoing);
 	/* Reset charset substitution state. */
 	_vte_iso2022_state_free(pvt->iso2022);
-	pvt->iso2022 = _vte_iso2022_state_new(NULL,
-                                              pvt->iso2022_utf8_ambiguous_width,
-							&_vte_terminal_codeset_changed_cb,
-							terminal);
+        pvt->iso2022 = _vte_iso2022_state_new(NULL);
 	_vte_iso2022_state_set_codeset(pvt->iso2022,
 				       pvt->encoding);
 	/* Reset keypad/cursor key modes. */
@@ -12395,8 +12427,6 @@ vte_terminal_reset(VteTerminal *terminal,
 	pvt->meta_sends_escape = TRUE;
 	/* Disable margin bell. */
 	pvt->margin_bell = FALSE;
-	/* Enable iso2022/NRC processing. */
-	pvt->nrc_mode = TRUE;
         /* Disable DECCOLM mode. */
         pvt->deccolm_mode = FALSE;
 	/* Reset saved settings. */
@@ -12413,9 +12443,10 @@ vte_terminal_reset(VteTerminal *terminal,
 	_vte_terminal_set_default_attributes(terminal);
 	pvt->screen = &pvt->normal_screen;
 	_vte_terminal_set_default_attributes(terminal);
-	/* Reset alternate charset mode. */
-	pvt->normal_screen.alternate_charset = FALSE;
-	pvt->alternate_screen.alternate_charset = FALSE;
+        /* Reset charset modes. */
+        pvt->character_replacements[0] = VTE_CHARACTER_REPLACEMENT_NONE;
+        pvt->character_replacements[1] = VTE_CHARACTER_REPLACEMENT_NONE;
+        pvt->character_replacement = &pvt->character_replacements[0];
 	/* Clear the scrollback buffers and reset the cursors. */
 	if (clear_history) {
 		_vte_ring_fini(pvt->normal_screen.row_data);
diff --git a/src/vteseq-n.gperf b/src/vteseq-n.gperf
index 208ab19..69d12ac 100644
--- a/src/vteseq-n.gperf
+++ b/src/vteseq-n.gperf
@@ -117,8 +117,14 @@ struct vteseq_n_struct {
 #"ansi-conformance-level-1", VTE_SEQUENCE_HANDLER_NULL
 #"ansi-conformance-level-2", VTE_SEQUENCE_HANDLER_NULL
 #"ansi-conformance-level-3", VTE_SEQUENCE_HANDLER_NULL
-"alternate-character-set-start", VTE_SEQUENCE_HANDLER(vte_sequence_handler_alternate_character_set_start)
-"alternate-character-set-end", VTE_SEQUENCE_HANDLER(vte_sequence_handler_alternate_character_set_end)
+"designate-g0-plain", VTE_SEQUENCE_HANDLER(vte_sequence_handler_designate_g0_plain)
+"designate-g0-line-drawing", VTE_SEQUENCE_HANDLER(vte_sequence_handler_designate_g0_line_drawing)
+"designate-g0-british", VTE_SEQUENCE_HANDLER(vte_sequence_handler_designate_g0_british)
+"designate-g1-plain", VTE_SEQUENCE_HANDLER(vte_sequence_handler_designate_g1_plain)
+"designate-g1-line-drawing", VTE_SEQUENCE_HANDLER(vte_sequence_handler_designate_g1_line_drawing)
+"designate-g1-british", VTE_SEQUENCE_HANDLER(vte_sequence_handler_designate_g1_british)
+"shift-in", VTE_SEQUENCE_HANDLER(vte_sequence_handler_shift_in)
+"shift-out", VTE_SEQUENCE_HANDLER(vte_sequence_handler_shift_out)
 "change-background-color-bel", VTE_SEQUENCE_HANDLER(vte_sequence_handler_change_background_color_bel)
 "change-background-color-st", VTE_SEQUENCE_HANDLER(vte_sequence_handler_change_background_color_st)
 "reset-background-color", VTE_SEQUENCE_HANDLER(vte_sequence_handler_reset_background_color)
diff --git a/src/vteseq.c b/src/vteseq.c
index 2120960..164bc85 100644
--- a/src/vteseq.c
+++ b/src/vteseq.c
@@ -633,10 +633,6 @@ vte_sequence_handler_decset_internal(VteTerminal *terminal,
                  NULL, NULL,},
 		/* 41: more(1) fix. */
 		/* 42: Enable NLS replacements. */
-		{42, PRIV_OFFSET(nrc_mode), 0, 0,
-		 FALSE,
-		 TRUE,
-		 NULL, NULL,},
 		/* 44: Margin bell. */
 		{44, PRIV_OFFSET(margin_bell), 0, 0,
 		 FALSE,
@@ -890,18 +886,60 @@ vte_sequence_handler_decset_internal(VteTerminal *terminal,
 /* THE HANDLERS */
 
 
-/* End alternate character set. */
+/* G0 character set is a pass-thru (no mapping). */
+static void
+vte_sequence_handler_designate_g0_plain (VteTerminal *terminal, GValueArray *params)
+{
+        terminal->pvt->character_replacements[0] = VTE_CHARACTER_REPLACEMENT_NONE;
+}
+
+/* G0 character set is DEC Special Character and Line Drawing Set. */
+static void
+vte_sequence_handler_designate_g0_line_drawing (VteTerminal *terminal, GValueArray *params)
+{
+        terminal->pvt->character_replacements[0] = VTE_CHARACTER_REPLACEMENT_LINE_DRAWING;
+}
+
+/* G0 character set is British (# is converted to £). */
+static void
+vte_sequence_handler_designate_g0_british (VteTerminal *terminal, GValueArray *params)
+{
+        terminal->pvt->character_replacements[0] = VTE_CHARACTER_REPLACEMENT_BRITISH;
+}
+
+/* G1 character set is a pass-thru (no mapping). */
+static void
+vte_sequence_handler_designate_g1_plain (VteTerminal *terminal, GValueArray *params)
+{
+        terminal->pvt->character_replacements[1] = VTE_CHARACTER_REPLACEMENT_NONE;
+}
+
+/* G1 character set is DEC Special Character and Line Drawing Set. */
+static void
+vte_sequence_handler_designate_g1_line_drawing (VteTerminal *terminal, GValueArray *params)
+{
+        terminal->pvt->character_replacements[1] = VTE_CHARACTER_REPLACEMENT_LINE_DRAWING;
+}
+
+/* G1 character set is British (# is converted to £). */
+static void
+vte_sequence_handler_designate_g1_british (VteTerminal *terminal, GValueArray *params)
+{
+        terminal->pvt->character_replacements[1] = VTE_CHARACTER_REPLACEMENT_BRITISH;
+}
+
+/* SI (shift in): switch to G0 character set. */
 static void
-vte_sequence_handler_alternate_character_set_end (VteTerminal *terminal, GValueArray *params)
+vte_sequence_handler_shift_in (VteTerminal *terminal, GValueArray *params)
 {
-	terminal->pvt->screen->alternate_charset = FALSE;
+        terminal->pvt->character_replacement = &terminal->pvt->character_replacements[0];
 }
 
-/* Start using alternate character set. */
+/* SO (shift out): switch to G1 character set. */
 static void
-vte_sequence_handler_alternate_character_set_start (VteTerminal *terminal, GValueArray *params)
+vte_sequence_handler_shift_out (VteTerminal *terminal, GValueArray *params)
 {
-	terminal->pvt->screen->alternate_charset = TRUE;
+        terminal->pvt->character_replacement = &terminal->pvt->character_replacements[1];
 }
 
 /* Beep. */
@@ -2162,7 +2200,7 @@ static void
 vte_sequence_handler_send_primary_device_attributes (VteTerminal *terminal, GValueArray *params)
 {
 	/* Claim to be a VT220 with only national character set support. */
-	vte_terminal_feed_child(terminal, "\e[?62;9;c", -1);
+        vte_terminal_feed_child(terminal, "\e[?62;c", -1);
 }
 
 /* Send terminal ID. */
