diff options
author | Javier S. Pedro <javier@javispedro.com> | 2012-11-14 18:04:03 +0100 |
---|---|---|
committer | Javier S. Pedro <javier@javispedro.com> | 2012-11-14 18:04:03 +0100 |
commit | 2f2654c57f3ff0d963f8ba21d2c944a458204394 (patch) | |
tree | bf6818f0b4018050b0c60d1d34e609cafc49d88c | |
download | vteimg-2f2654c57f3ff0d963f8ba21d2c944a458204394.tar.gz vteimg-2f2654c57f3ff0d963f8ba21d2c944a458204394.zip |
initial import
-rw-r--r-- | Makefile | 19 | ||||
-rw-r--r-- | view.c | 112 | ||||
-rw-r--r-- | vte-0.28.2-vteimg.patch | 540 |
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 @@ -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 */ + |