aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJavier S. Pedro <javier@javispedro.com>2012-11-14 18:04:03 +0100
committerJavier S. Pedro <javier@javispedro.com>2012-11-14 18:04:03 +0100
commit2f2654c57f3ff0d963f8ba21d2c944a458204394 (patch)
treebf6818f0b4018050b0c60d1d34e609cafc49d88c
downloadvteimg-2f2654c57f3ff0d963f8ba21d2c944a458204394.tar.gz
vteimg-2f2654c57f3ff0d963f8ba21d2c944a458204394.zip
initial import
-rw-r--r--Makefile19
-rw-r--r--view.c112
-rw-r--r--vte-0.28.2-vteimg.patch540
3 files changed, 671 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..df0fad2
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,19 @@
+CFLAGS:=-Wall -O2
+
+view_cflags:=$(shell pkg-config --cflags glib-2.0 gio-unix-2.0 gdk-pixbuf-2.0)
+view_libs:=$(shell pkg-config --libs glib-2.0 gio-unix-2.0 gdk-pixbuf-2.0) -lm
+
+objs:=view.o
+
+all: view
+
+view: $(objs)
+ $(CC) $(LDFLAGS) -o $@ $+ $(view_libs)
+
+$(objs): %.o: %.c
+ $(CC) $(view_cflags) $(CFLAGS) -o $@ -c $<
+
+clean:
+ rm -f view *.o
+
+.PHONY: all clean
diff --git a/view.c b/view.c
new file mode 100644
index 0000000..af237c9
--- /dev/null
+++ b/view.c
@@ -0,0 +1,112 @@
+#include <stdlib.h>
+#include <math.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <gio/gio.h>
+#include <gio/gunixinputstream.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gdk-pixbuf/gdk-pixdata.h>
+
+// TODO Unhardcode these
+const int char_width = 8;
+const int char_height = 15;
+
+const int window_width = 8 * 80;
+const int window_height = 15 * 25;
+
+static gboolean view_pixbuf(GdkPixbuf *pixbuf)
+{
+ gint width = gdk_pixbuf_get_width(pixbuf);
+ gint height = gdk_pixbuf_get_height(pixbuf);
+
+ double scale = 1.0;
+ if (width > window_width) {
+ scale *= (double)window_width / width;
+ width = width * scale;
+ height = height * scale;
+ }
+ if (height > window_height || FALSE) {
+ scale *= (double)window_height / height;
+ width = width * scale;
+ height = height * scale;
+ }
+
+ GdkPixbuf *scaled;
+
+ if (scale != 1.0) {
+ scaled = gdk_pixbuf_scale_simple(pixbuf, width, height, GDK_INTERP_BILINEAR);
+ } else {
+ scaled = GDK_PIXBUF(g_object_ref(pixbuf));
+ }
+
+ GdkPixdata pixdata;
+ gpointer pixdata_p = gdk_pixdata_from_pixbuf(&pixdata, scaled, TRUE);
+
+ if (pixdata_p == NULL) {
+ g_object_unref(scaled);
+ return FALSE;
+ }
+
+ guint size;
+ guint8 *data = gdk_pixdata_serialize(&pixdata, &size);
+ gchar *str = g_base64_encode(data, size);
+
+ g_print("\033]v;%s\007", str);
+
+ int rows = ceil(height / (double)char_height);
+ while (rows > 0) {
+ g_print("\n");
+ rows--;
+ }
+
+ g_free(str);
+ g_free(data);
+ g_free(pixdata.pixel_data);
+ g_object_unref(scaled);
+
+ return TRUE;
+}
+
+
+int main(int argc, char * argv[])
+{
+ g_type_init();
+
+ GError *error = NULL;
+
+ if (!isatty(STDOUT_FILENO)) {
+ g_printerr("Refusing to display image on not-terminal\n");
+ return EXIT_FAILURE;
+ }
+
+ if (argc > 1) {
+ int i;
+ for (i = 1; i < argc; i++) {
+ GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(argv[i], &error);
+ if (pixbuf == NULL) {
+ g_printerr("Failed to open image '%s': %s\n", argv[i], error->message);
+ return EXIT_FAILURE;
+ }
+ if (!view_pixbuf(pixbuf)) {
+ g_printerr("Failed to view image '%s'\n", argv[i]);
+ return EXIT_FAILURE;
+ }
+ g_object_unref(pixbuf);
+ }
+ } else {
+ GInputStream *input = g_unix_input_stream_new(STDIN_FILENO, FALSE);
+ GdkPixbuf *pixbuf = gdk_pixbuf_new_from_stream(input, NULL, &error);
+ if (pixbuf == NULL) {
+ g_printerr("Failed to open stdin image: %s\n", error->message);
+ return EXIT_FAILURE;
+ }
+ if (!view_pixbuf(pixbuf)) {
+ g_printerr("Failed to view stdin image\n");
+ return EXIT_FAILURE;
+ }
+ g_object_unref(pixbuf);
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/vte-0.28.2-vteimg.patch b/vte-0.28.2-vteimg.patch
new file mode 100644
index 0000000..8f77776
--- /dev/null
+++ b/vte-0.28.2-vteimg.patch
@@ -0,0 +1,540 @@
+diff --git a/src/caps.c b/src/caps.c
+index c7217e0..061e447 100644
+--- a/src/caps.c
++++ b/src/caps.c
+@@ -561,6 +561,9 @@ struct _vte_capability_string _vte_xterm_capability_strings[] = {
+ {OSC "21;%s" ST, "set-text-property-21", 0},
+ {OSC "2L;%s" ST, "set-text-property-2L", 0},
+
++ {OSC "v;%s" BEL, "view-inline-image", 0},
++ {OSC "v;%s" ST, "view-inline-image", 0},
++
+ {NULL, NULL, 0},
+ };
+
+diff --git a/src/ring.c b/src/ring.c
+index db4edec..a6da094 100644
+--- a/src/ring.c
++++ b/src/ring.c
+@@ -25,6 +25,8 @@
+
+ #include <string.h>
+
++#include <gdk-pixbuf/gdk-pixdata.h>
++
+ /*
+ * VteRing: A buffer ring
+ */
+@@ -64,6 +66,7 @@ _vte_ring_init (VteRing *ring, gulong max_rows)
+
+ ring->attr_stream = _vte_file_stream_new ();
+ ring->text_stream = _vte_file_stream_new ();
++ ring->pics_stream = _vte_file_stream_new ();
+ ring->row_stream = _vte_file_stream_new ();
+
+ ring->last_attr.text_offset = 0;
+@@ -88,6 +91,7 @@ _vte_ring_fini (VteRing *ring)
+
+ g_object_unref (ring->attr_stream);
+ g_object_unref (ring->text_stream);
++ g_object_unref (ring->pics_stream);
+ g_object_unref (ring->row_stream);
+
+ g_string_free (ring->utf8_buffer, TRUE);
+@@ -98,6 +102,7 @@ _vte_ring_fini (VteRing *ring)
+ typedef struct _VteRowRecord {
+ gsize text_offset;
+ gsize attr_offset;
++ gsize pics_offset;
+ } VteRowRecord;
+
+ static gboolean
+@@ -124,6 +129,7 @@ _vte_ring_freeze_row (VteRing *ring, gulong position, const VteRowData *row)
+
+ record.text_offset = _vte_stream_head (ring->text_stream);
+ record.attr_offset = _vte_stream_head (ring->attr_stream);
++ record.pics_offset = _vte_stream_head (ring->pics_stream);
+
+ g_string_set_size (buffer, 0);
+ for (i = 0, cell = row->cells; i < row->len; i++, cell++) {
+@@ -168,6 +174,17 @@ _vte_ring_freeze_row (VteRing *ring, gulong position, const VteRowData *row)
+ if (!row->attr.soft_wrapped)
+ g_string_append_c (buffer, '\n');
+
++ if (row->pixbuf) {
++ GdkPixdata pixdata;
++ if (gdk_pixdata_from_pixbuf(&pixdata, row->pixbuf, TRUE) != NULL) {
++ guint data_len;
++ guint8 *data = gdk_pixdata_serialize(&pixdata, &data_len);
++ _vte_stream_append (ring->pics_stream, data, data_len);
++ g_free(data);
++ g_free(pixdata.pixel_data);
++ }
++ }
++
+ _vte_stream_append (ring->text_stream, buffer->str, buffer->len);
+ _vte_ring_append_row_record (ring, &record, position);
+ }
+@@ -193,8 +210,10 @@ _vte_ring_thaw_row (VteRing *ring, gulong position, VteRowData *row, gboolean do
+ if ((position + 1) * sizeof (records[0]) < _vte_stream_head (ring->row_stream)) {
+ if (!_vte_ring_read_row_record (ring, &records[1], position + 1))
+ return;
+- } else
++ } else {
+ records[1].text_offset = _vte_stream_head (ring->text_stream);
++ records[1].pics_offset = _vte_stream_head (ring->pics_stream);
++ }
+
+ g_string_set_size (buffer, records[1].text_offset - records[0].text_offset);
+ if (!_vte_stream_read (ring->text_stream, records[0].text_offset, buffer->str, buffer->len))
+@@ -250,6 +269,19 @@ _vte_ring_thaw_row (VteRing *ring, gulong position, VteRowData *row, gboolean do
+ }
+ }
+
++ guint pics_data_len = records[1].pics_offset - records[0].pics_offset;
++ if (pics_data_len > 0) {
++ guint8 *data = g_malloc(pics_data_len + 1);
++ if (_vte_stream_read (ring->pics_stream, records[0].pics_offset, data, pics_data_len)) {
++ GError *error = NULL;
++ GdkPixdata pixdata;
++ if (gdk_pixdata_deserialize(&pixdata, pics_data_len, data, &error)) {
++ row->pixbuf = gdk_pixbuf_from_pixdata(&pixdata, TRUE, &error);
++ }
++ }
++ g_free(data);
++ }
++
+ if (do_truncate) {
+ if (records[0].text_offset < ring->last_attr.text_offset)
+ if (!_vte_stream_read (ring->attr_stream, records[0].attr_offset, (char *) &ring->last_attr, sizeof (ring->last_attr))) {
+@@ -259,6 +291,7 @@ _vte_ring_thaw_row (VteRing *ring, gulong position, VteRowData *row, gboolean do
+ _vte_stream_truncate (ring->row_stream, position * sizeof (record));
+ _vte_stream_truncate (ring->attr_stream, records[0].attr_offset);
+ _vte_stream_truncate (ring->text_stream, records[0].text_offset);
++ _vte_stream_truncate (ring->pics_stream, records[0].pics_offset);
+ }
+ }
+
+@@ -270,6 +303,7 @@ _vte_ring_reset_streams (VteRing *ring, gulong position)
+ _vte_stream_reset (ring->row_stream, position * sizeof (VteRowRecord));
+ _vte_stream_reset (ring->text_stream, 0);
+ _vte_stream_reset (ring->attr_stream, 0);
++ _vte_stream_reset (ring->pics_stream, 0);
+
+ ring->last_attr.text_offset = 0;
+ ring->last_attr.attr.i = basic_cell.i.attr;
+@@ -282,6 +316,7 @@ _vte_ring_new_page (VteRing *ring)
+ {
+ _vte_debug_print (VTE_DEBUG_RING, "Starting new stream page at %lu.\n", ring->writable);
+
++ _vte_stream_new_page (ring->pics_stream);
+ _vte_stream_new_page (ring->attr_stream);
+ _vte_stream_new_page (ring->text_stream);
+ _vte_stream_new_page (ring->row_stream);
+diff --git a/src/ring.h b/src/ring.h
+index 50dd5a2..eb6473d 100644
+--- a/src/ring.h
++++ b/src/ring.h
+@@ -54,7 +54,7 @@ struct _VteRing {
+
+ /* Storage */
+ gulong last_page;
+- VteStream *attr_stream, *text_stream, *row_stream;
++ VteStream *attr_stream, *text_stream, *pics_stream, *row_stream;
+ VteCellAttrChange last_attr;
+ GString *utf8_buffer;
+
+diff --git a/src/vte.c b/src/vte.c
+index 695d327..3cfbea3 100644
+--- a/src/vte.c
++++ b/src/vte.c
+@@ -9366,6 +9366,20 @@ vte_terminal_draw_point(VteTerminal *terminal,
+ vte_terminal_fill_rectangle(terminal, color, x, y, 1, 1);
+ }
+
++static void
++vte_terminal_draw_pixbuf(VteTerminal *terminal,
++ const GdkPixbuf *pixbuf,
++ gint x,
++ gint y)
++{
++ _vte_draw_start(terminal->pvt->draw);
++ _vte_draw_draw_pixbuf(terminal->pvt->draw,
++ x + terminal->pvt->inner_border.left,
++ y + terminal->pvt->inner_border.top,
++ pixbuf);
++ _vte_draw_end(terminal->pvt->draw);
++}
++
+ /* Draw the graphic representation of a line-drawing or special graphics
+ * character. */
+ static gboolean
+@@ -10615,6 +10629,29 @@ vte_terminal_draw_rows(VteTerminal *terminal,
+ y += row_height;
+ } while (--rows);
+
++ /** render inline images */
++ x = start_x + terminal->pvt->inner_border.left;
++ y = start_y + terminal->pvt->inner_border.top - 25 * row_height;
++ row = start_row - 25; /* Find for images a few rows up. */
++ rows = row_count + 25;
++ do {
++ row_data = _vte_terminal_find_row_data(terminal, row);
++ /* Back up in case this is a multicolumn character,
++ * making the drawing area a little wider. */
++ i = start_column;
++ if (row_data != NULL && row_data->pixbuf != NULL) {
++ GError *error = NULL;
++ gint img_height = gdk_pixbuf_get_height(row_data->pixbuf);
++ if (!(y > start_y + row_count * row_height || y + img_height <= start_y)) {
++ _vte_draw_draw_pixbuf (terminal->pvt->draw,
++ x /*+ i *column_width*/,
++ y,
++ row_data->pixbuf);
++ }
++ }
++ row++;
++ y += row_height;
++ } while (--rows);
+
+ /* render the text */
+ y = start_y;
+diff --git a/src/vtedraw.c b/src/vtedraw.c
+index 029ebb3..64bd795 100644
+--- a/src/vtedraw.c
++++ b/src/vtedraw.c
+@@ -1164,3 +1164,19 @@ _vte_draw_fill_rectangle (struct _vte_draw *draw,
+ set_source_color_alpha (draw->cr, color, alpha);
+ cairo_fill (draw->cr);
+ }
++
++void _vte_draw_draw_pixbuf(struct _vte_draw *draw,
++ gint x, gint y, const GdkPixbuf *pixbuf)
++{
++ g_return_if_fail (draw->started);
++
++ _vte_debug_print (VTE_DEBUG_DRAW,"draw_pixbuf (%d, %d)\n",x,y);
++
++ gint width = gdk_pixbuf_get_width(pixbuf);
++ gint height = gdk_pixbuf_get_height(pixbuf);
++
++ cairo_set_operator (draw->cr, CAIRO_OPERATOR_OVER);
++ gdk_cairo_set_source_pixbuf (draw->cr, pixbuf, x, y);
++ cairo_rectangle (draw->cr, x, y, width, height);
++ cairo_fill (draw->cr);
++}
+diff --git a/src/vtedraw.h b/src/vtedraw.h
+index 4f65183..685dcf0 100644
+--- a/src/vtedraw.h
++++ b/src/vtedraw.h
+@@ -111,6 +111,9 @@ void _vte_draw_draw_rectangle(struct _vte_draw *draw,
+ gint x, gint y, gint width, gint height,
+ const PangoColor *color, guchar alpha);
+
++void _vte_draw_draw_pixbuf(struct _vte_draw *draw,
++ gint x, gint y, const GdkPixbuf *pixbuf);
++
+ G_END_DECLS
+
+ #endif
+diff --git a/src/vterowdata.c b/src/vterowdata.c
+index 1a29523..b017658 100644
+--- a/src/vterowdata.c
++++ b/src/vterowdata.c
+@@ -79,6 +79,8 @@ void
+ _vte_row_data_clear (VteRowData *row)
+ {
+ VteCell *cells = row->cells;
++ if (row->pixbuf)
++ gdk_pixbuf_unref (row->pixbuf);
+ _vte_row_data_init (row);
+ row->cells = cells;
+ }
+@@ -89,6 +91,9 @@ _vte_row_data_fini (VteRowData *row)
+ if (row->cells)
+ _vte_cells_free (_vte_cells_for_cell_array (row->cells));
+ row->cells = NULL;
++ if (row->pixbuf)
++ gdk_pixbuf_unref (row->pixbuf);
++ row->pixbuf = NULL;
+ }
+
+ static inline gboolean
+diff --git a/src/vterowdata.h b/src/vterowdata.h
+index a911500..4b2072b 100644
+--- a/src/vterowdata.h
++++ b/src/vterowdata.h
+@@ -21,11 +21,11 @@
+ #ifndef vterowdata_h_included
+ #define vterowdata_h_included
+
++#include <gdk/gdk.h>
+ #include "vteunistr.h"
+
+ G_BEGIN_DECLS
+
+-
+ #define VTE_DEF_FG 256
+ #define VTE_DEF_BG 257
+ #define VTE_BOLD_FG 258
+@@ -136,6 +136,7 @@ typedef struct _VteRowData {
+ VteCell *cells;
+ guint16 len;
+ VteRowAttr attr;
++ GdkPixbuf *pixbuf;
+ } VteRowData;
+
+
+diff --git a/src/vteseq-list.h b/src/vteseq-list.h
+index ab9f5f3..3bda2a4 100644
+--- a/src/vteseq-list.h
++++ b/src/vteseq-list.h
+@@ -117,5 +117,6 @@ VTE_SEQUENCE_HANDLER(vte_sequence_handler_vb)
+ VTE_SEQUENCE_HANDLER(vte_sequence_handler_ve)
+ VTE_SEQUENCE_HANDLER(vte_sequence_handler_vertical_tab)
+ VTE_SEQUENCE_HANDLER(vte_sequence_handler_vi)
++VTE_SEQUENCE_HANDLER(vte_sequence_handler_view_inline_image)
+ VTE_SEQUENCE_HANDLER(vte_sequence_handler_vs)
+ VTE_SEQUENCE_HANDLER(vte_sequence_handler_window_manipulation)
+diff --git a/src/vteseq-n.c b/src/vteseq-n.c
+index 2099cc3..64c14e6 100644
+--- a/src/vteseq-n.c
++++ b/src/vteseq-n.c
+@@ -1,4 +1,4 @@
+-/* ANSI-C code produced by gperf version 3.0.3 */
++/* ANSI-C code produced by gperf version 3.0.4 */
+ /* Command-line: gperf -m 100 vteseq-n.gperf */
+ /* Computed positions: -k'1,4,$' */
+
+@@ -58,10 +58,10 @@ vteseq_n_hash (register const char *str, register unsigned int len)
+ 84, 84, 84, 84, 84, 84, 84, 84, 84, 84,
+ 84, 84, 84, 84, 84, 84, 84, 84, 84, 84,
+ 84, 84, 84, 84, 84, 84, 84, 84, 84, 84,
+- 84, 84, 84, 84, 84, 84, 84, 47, 7, 27,
++ 84, 84, 84, 84, 84, 84, 84, 47, 35, 27,
+ 0, 0, 18, 84, 0, 33, 84, 84, 0, 4,
+- 8, 43, 2, 84, 29, 2, 0, 2, 42, 5,
+- 21, 8, 84, 84, 84, 84, 84, 84, 84, 84,
++ 8, 43, 2, 84, 29, 2, 0, 2, 4, 5,
++ 21, 43, 84, 84, 84, 84, 84, 84, 84, 84,
+ 84, 84, 84, 84, 84, 84, 84, 84, 84, 84,
+ 84, 84, 84, 84, 84, 84, 84, 84, 84, 84,
+ 84, 84, 84, 84, 84, 84, 84, 84, 84, 84,
+@@ -98,7 +98,7 @@ struct vteseq_n_pool_t
+ char vteseq_n_pool_str23[sizeof("screen-alignment-test")];
+ char vteseq_n_pool_str24[sizeof("dec-device-status-report")];
+ char vteseq_n_pool_str25[sizeof("normal-keypad")];
+- char vteseq_n_pool_str26[sizeof("erase-in-display")];
++ char vteseq_n_pool_str26[sizeof("view-inline-image")];
+ char vteseq_n_pool_str27[sizeof("set-icon-and-window-title")];
+ char vteseq_n_pool_str28[sizeof("full-reset")];
+ char vteseq_n_pool_str29[sizeof("set-scrolling-region-to-end")];
+@@ -123,7 +123,7 @@ struct vteseq_n_pool_t
+ char vteseq_n_pool_str48[sizeof("cursor-down")];
+ char vteseq_n_pool_str49[sizeof("return-terminal-id")];
+ char vteseq_n_pool_str50[sizeof("cursor-preceding-line")];
+- char vteseq_n_pool_str51[sizeof("cursor-back-tab")];
++ char vteseq_n_pool_str51[sizeof("vertical-tab")];
+ char vteseq_n_pool_str52[sizeof("cursor-position")];
+ char vteseq_n_pool_str53[sizeof("device-status-report")];
+ char vteseq_n_pool_str54[sizeof("cursor-character-absolute")];
+@@ -133,7 +133,7 @@ struct vteseq_n_pool_t
+ char vteseq_n_pool_str58[sizeof("insert-blank-characters")];
+ char vteseq_n_pool_str59[sizeof("index")];
+ char vteseq_n_pool_str60[sizeof("request-terminal-parameters")];
+- char vteseq_n_pool_str61[sizeof("vertical-tab")];
++ char vteseq_n_pool_str61[sizeof("erase-in-display")];
+ char vteseq_n_pool_str62[sizeof("cursor-forward-tabulation")];
+ char vteseq_n_pool_str63[sizeof("reverse-index")];
+ char vteseq_n_pool_str64[sizeof("scroll-down")];
+@@ -143,6 +143,7 @@ struct vteseq_n_pool_t
+ char vteseq_n_pool_str73[sizeof("horizontal-and-vertical-position")];
+ char vteseq_n_pool_str76[sizeof("change-color")];
+ char vteseq_n_pool_str78[sizeof("character-attributes")];
++ char vteseq_n_pool_str79[sizeof("cursor-back-tab")];
+ char vteseq_n_pool_str83[sizeof("character-position-absolute")];
+ };
+ static const struct vteseq_n_pool_t vteseq_n_pool_contents =
+@@ -164,7 +165,7 @@ static const struct vteseq_n_pool_t vteseq_n_pool_contents =
+ "screen-alignment-test",
+ "dec-device-status-report",
+ "normal-keypad",
+- "erase-in-display",
++ "view-inline-image",
+ "set-icon-and-window-title",
+ "full-reset",
+ "set-scrolling-region-to-end",
+@@ -189,7 +190,7 @@ static const struct vteseq_n_pool_t vteseq_n_pool_contents =
+ "cursor-down",
+ "return-terminal-id",
+ "cursor-preceding-line",
+- "cursor-back-tab",
++ "vertical-tab",
+ "cursor-position",
+ "device-status-report",
+ "cursor-character-absolute",
+@@ -199,7 +200,7 @@ static const struct vteseq_n_pool_t vteseq_n_pool_contents =
+ "insert-blank-characters",
+ "index",
+ "request-terminal-parameters",
+- "vertical-tab",
++ "erase-in-display",
+ "cursor-forward-tabulation",
+ "reverse-index",
+ "scroll-down",
+@@ -209,12 +210,13 @@ static const struct vteseq_n_pool_t vteseq_n_pool_contents =
+ "horizontal-and-vertical-position",
+ "change-color",
+ "character-attributes",
++ "cursor-back-tab",
+ "character-position-absolute"
+ };
+ #define vteseq_n_pool ((const char *) &vteseq_n_pool_contents)
+ #ifdef __GNUC__
+ __inline
+-#ifdef __GNUC_STDC_INLINE__
++#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__
+ __attribute__ ((__gnu_inline__))
+ #endif
+ #endif
+@@ -223,7 +225,7 @@ vteseq_n_lookup (register const char *str, register unsigned int len)
+ {
+ enum
+ {
+- TOTAL_KEYWORDS = 63,
++ TOTAL_KEYWORDS = 64,
+ MIN_WORD_LENGTH = 5,
+ MAX_WORD_LENGTH = 32,
+ MIN_HASH_VALUE = 7,
+@@ -233,11 +235,11 @@ vteseq_n_lookup (register const char *str, register unsigned int len)
+ static const unsigned char lengthtable[] =
+ {
+ 0, 0, 0, 0, 0, 0, 0, 7, 6, 0, 8, 9, 10, 0,
+- 12, 13, 14, 9, 16, 17, 16, 19, 22, 21, 24, 13, 16, 25,
++ 12, 13, 14, 9, 16, 17, 16, 19, 22, 21, 24, 13, 17, 25,
+ 10, 27, 20, 9, 19, 31, 30, 31, 32, 8, 9, 10, 9, 12,
+- 11, 14, 15, 16, 17, 12, 11, 18, 21, 15, 15, 20, 25, 22,
+- 9, 20, 23, 5, 27, 12, 25, 13, 11, 18, 23, 0, 0, 0,
+- 0, 0, 14, 32, 0, 0, 12, 0, 20, 0, 0, 0, 0, 27
++ 11, 14, 15, 16, 17, 12, 11, 18, 21, 12, 15, 20, 25, 22,
++ 9, 20, 23, 5, 27, 16, 25, 13, 11, 18, 23, 0, 0, 0,
++ 0, 0, 14, 32, 0, 0, 12, 0, 20, 15, 0, 0, 0, 27
+ };
+ static const struct vteseq_n_struct wordlist[] =
+ {
+@@ -278,8 +280,8 @@ vteseq_n_lookup (register const char *str, register unsigned int len)
+ {(int)(long)&((struct vteseq_n_pool_t *)0)->vteseq_n_pool_str24, VTE_SEQUENCE_HANDLER(vte_sequence_handler_dec_device_status_report)},
+ #line 53 "vteseq-n.gperf"
+ {(int)(long)&((struct vteseq_n_pool_t *)0)->vteseq_n_pool_str25, VTE_SEQUENCE_HANDLER(vte_sequence_handler_normal_keypad)},
+-#line 70 "vteseq-n.gperf"
+- {(int)(long)&((struct vteseq_n_pool_t *)0)->vteseq_n_pool_str26, VTE_SEQUENCE_HANDLER(vte_sequence_handler_erase_in_display)},
++#line 132 "vteseq-n.gperf"
++ {(int)(long)&((struct vteseq_n_pool_t *)0)->vteseq_n_pool_str26, VTE_SEQUENCE_HANDLER(vte_sequence_handler_view_inline_image)},
+ #line 115 "vteseq-n.gperf"
+ {(int)(long)&((struct vteseq_n_pool_t *)0)->vteseq_n_pool_str27, VTE_SEQUENCE_HANDLER(vte_sequence_handler_set_icon_and_window_title)},
+ #line 36 "vteseq-n.gperf"
+@@ -328,8 +330,8 @@ vteseq_n_lookup (register const char *str, register unsigned int len)
+ {(int)(long)&((struct vteseq_n_pool_t *)0)->vteseq_n_pool_str49, VTE_SEQUENCE_HANDLER(vte_sequence_handler_return_terminal_id)},
+ #line 88 "vteseq-n.gperf"
+ {(int)(long)&((struct vteseq_n_pool_t *)0)->vteseq_n_pool_str50, VTE_SEQUENCE_HANDLER(vte_sequence_handler_cursor_preceding_line)},
+-#line 62 "vteseq-n.gperf"
+- {(int)(long)&((struct vteseq_n_pool_t *)0)->vteseq_n_pool_str51, VTE_SEQUENCE_HANDLER(vte_sequence_handler_bt)},
++#line 50 "vteseq-n.gperf"
++ {(int)(long)&((struct vteseq_n_pool_t *)0)->vteseq_n_pool_str51, VTE_SEQUENCE_HANDLER(vte_sequence_handler_vertical_tab)},
+ #line 64 "vteseq-n.gperf"
+ {(int)(long)&((struct vteseq_n_pool_t *)0)->vteseq_n_pool_str52, VTE_SEQUENCE_HANDLER(vte_sequence_handler_cursor_position)},
+ #line 82 "vteseq-n.gperf"
+@@ -348,8 +350,8 @@ vteseq_n_lookup (register const char *str, register unsigned int len)
+ {(int)(long)&((struct vteseq_n_pool_t *)0)->vteseq_n_pool_str59, VTE_SEQUENCE_HANDLER(vte_sequence_handler_index)},
+ #line 118 "vteseq-n.gperf"
+ {(int)(long)&((struct vteseq_n_pool_t *)0)->vteseq_n_pool_str60, VTE_SEQUENCE_HANDLER(vte_sequence_handler_request_terminal_parameters)},
+-#line 50 "vteseq-n.gperf"
+- {(int)(long)&((struct vteseq_n_pool_t *)0)->vteseq_n_pool_str61, VTE_SEQUENCE_HANDLER(vte_sequence_handler_vertical_tab)},
++#line 70 "vteseq-n.gperf"
++ {(int)(long)&((struct vteseq_n_pool_t *)0)->vteseq_n_pool_str61, VTE_SEQUENCE_HANDLER(vte_sequence_handler_erase_in_display)},
+ #line 113 "vteseq-n.gperf"
+ {(int)(long)&((struct vteseq_n_pool_t *)0)->vteseq_n_pool_str62, VTE_SEQUENCE_HANDLER(vte_sequence_handler_ta)},
+ #line 54 "vteseq-n.gperf"
+@@ -371,7 +373,9 @@ vteseq_n_lookup (register const char *str, register unsigned int len)
+ {-1},
+ #line 81 "vteseq-n.gperf"
+ {(int)(long)&((struct vteseq_n_pool_t *)0)->vteseq_n_pool_str78, VTE_SEQUENCE_HANDLER(vte_sequence_handler_character_attributes)},
+- {-1}, {-1}, {-1}, {-1},
++#line 62 "vteseq-n.gperf"
++ {(int)(long)&((struct vteseq_n_pool_t *)0)->vteseq_n_pool_str79, VTE_SEQUENCE_HANDLER(vte_sequence_handler_bt)},
++ {-1}, {-1}, {-1},
+ #line 117 "vteseq-n.gperf"
+ {(int)(long)&((struct vteseq_n_pool_t *)0)->vteseq_n_pool_str83, VTE_SEQUENCE_HANDLER(vte_sequence_handler_character_position_absolute)}
+ };
+diff --git a/src/vteseq-n.gperf b/src/vteseq-n.gperf
+index 8cbcb21..fb6382b 100644
+--- a/src/vteseq-n.gperf
++++ b/src/vteseq-n.gperf
+@@ -129,3 +129,4 @@ struct vteseq_n_struct {
+ "send-secondary-device-attributes", VTE_SEQUENCE_HANDLER(vte_sequence_handler_send_secondary_device_attributes)
+ #"change-mouse-cursor-background-colors", VTE_SEQUENCE_HANDLER_NULL
+ #"change-mouse-cursor-foreground-colors", VTE_SEQUENCE_HANDLER_NULL
++"view-inline-image", VTE_SEQUENCE_HANDLER(vte_sequence_handler_view_inline_image)
+diff --git a/src/vteseq.c b/src/vteseq.c
+index 7ef4c8c..ea88d09 100644
+--- a/src/vteseq.c
++++ b/src/vteseq.c
+@@ -25,6 +25,7 @@
+ #endif
+
+ #include <glib.h>
++#include <gdk-pixbuf/gdk-pixdata.h>
+
+ #include "vte.h"
+ #include "vte-private.h"
+@@ -3304,6 +3305,50 @@ vte_sequence_handler_change_cursor_color (VteTerminal *terminal, GValueArray *pa
+ }
+ }
+
++/* View inline image */
++static void
++vte_sequence_handler_view_inline_image (VteTerminal *terminal, GValueArray *params)
++{
++ VteRowData *rowdata;
++ VteScreen *screen = terminal->pvt->screen;
++
++ GValue *value = g_value_array_get_nth(params, 0);
++ if (value) {
++ GError *error = NULL;
++ GdkPixdata pixdata;
++ gsize data_len;
++ guchar *data ;
++ if (G_VALUE_HOLDS_STRING(value)) {
++ data = g_base64_decode(g_value_get_string(value), &data_len);
++ } else if (G_VALUE_HOLDS_POINTER(value)) {
++ gchar *str = vte_ucs4_to_utf8 (terminal, g_value_get_pointer (value));
++ data = g_base64_decode(str, &data_len);
++ g_free(str);
++ } else {
++ return;
++ }
++
++ if (gdk_pixdata_deserialize(&pixdata, data_len, data, &error)) {
++ GdkPixbuf *pixbuf = gdk_pixbuf_from_pixdata(&pixdata, TRUE, &error);
++ g_warn_if_fail(pixbuf != NULL);
++
++ rowdata = _vte_terminal_ensure_row(terminal);
++ if (rowdata) {
++ rowdata->pixbuf = pixbuf;
++
++ gint height = gdk_pixbuf_get_height(pixbuf);
++
++ /* Repaint affected rows. */
++ _vte_invalidate_cells(terminal,
++ 0, terminal->column_count,
++ screen->cursor_current.row,
++ 1 + (height / terminal->char_height));
++ }
++ }
++ g_free(data);
++ }
++}
++
+
+ /* Lookup tables */
+