commit f31c43015d15487d5fb129877dc0d87bcb60f5c9
parent 884c62a0564d538491aeaf3b2bc1cded587ed13d
Author: bakkeby <bakkeby@gmail.com>
Date: Wed, 10 Mar 2021 18:09:47 +0100
Adding sixel support ref. #7
Diffstat:
17 files changed, 1264 insertions(+), 156 deletions(-)
diff --git a/Makefile b/Makefile
@@ -8,7 +8,10 @@ include config.mk
#LIGATURES_C = hb.c
#LIGATURES_H = hb.h
-SRC = st.c x.c $(LIGATURES_C)
+# Uncomment this for the SIXEL patch / SIXEL_PATCH
+#SIXEL_C = sixel.c sixel_hls.c
+
+SRC = st.c x.c $(LIGATURES_C) $(SIXEL_C)
OBJ = $(SRC:.c=.o)
all: options st
diff --git a/README.md b/README.md
@@ -15,6 +15,8 @@ Refer to [https://st.suckless.org/](https://st.suckless.org/) for details on the
### Changelog:
+2021-03-10 - Added sixel support
+
2021-02-26 - Added the dynamic cursor color patch
2021-02-15 - Added the alpha gradient patch
@@ -145,6 +147,9 @@ Refer to [https://st.suckless.org/](https://st.suckless.org/) for details on the
- [scrollback](https://st.suckless.org/patches/scrollback/)
- allows you scroll back through terminal output using keyboard shortcuts or mousewheel
+ - sixel
+ - this patch adds SIXEL graphics support
+
- st-embedder
- this patch allows clients to embed into the st window and can be useful if you tend to start X applications from the terminal
- the behavior is similar to Plan 9 where applications can take over windows
diff --git a/config.mk b/config.mk
@@ -13,7 +13,7 @@ X11LIB = /usr/X11R6/lib
PKG_CONFIG = pkg-config
# Uncomment this for the alpha patch / ALPHA_PATCH
-XRENDER = -lXrender
+#XRENDER = -lXrender
# Uncomment this for the themed cursor patch / THEMED_CURSOR_PATCH
#XCURSOR = -lXcursor
diff --git a/patch/sixel_st.c b/patch/sixel_st.c
@@ -0,0 +1,18 @@
+sixel_state_t sixel_st;
+
+void
+dcshandle(void)
+{
+ switch (csiescseq.mode[0]) {
+ default:
+ fprintf(stderr, "erresc: unknown csi ");
+ csidump();
+ /* die(""); */
+ break;
+ case 'q': /* DECSIXEL */
+ if (sixel_parser_init(&sixel_st, 0, 0 << 16 | 0 << 8 | 0, 1, win.cw, win.ch) != 0)
+ perror("sixel_parser_init() failed");
+ term.mode |= MODE_SIXEL;
+ break;
+ }
+}
+\ No newline at end of file
diff --git a/patch/sixel_st.h b/patch/sixel_st.h
@@ -0,0 +1 @@
+static void dcshandle(void);
+\ No newline at end of file
diff --git a/patch/sixel_x.c b/patch/sixel_x.c
@@ -0,0 +1,14 @@
+void
+delete_image(ImageList *im)
+{
+ if (im->prev)
+ im->prev->next = im->next;
+ else
+ term.images = im->next;
+ if (im->next)
+ im->next->prev = im->prev;
+ if (im->pixmap)
+ XFreePixmap(xw.dpy, (Drawable)im->pixmap);
+ free(im->pixels);
+ free(im);
+}
+\ No newline at end of file
diff --git a/patch/st_include.c b/patch/st_include.c
@@ -19,4 +19,7 @@
#endif
#if SCROLLBACK_PATCH || SCROLLBACK_MOUSE_PATCH || SCROLLBACK_MOUSE_ALTSCREEN_PATCH
#include "scrollback.c"
+#endif
+#if SIXEL_PATCH
+#include "sixel_st.c"
#endif
\ No newline at end of file
diff --git a/patch/st_include.h b/patch/st_include.h
@@ -19,4 +19,7 @@
#endif
#if SCROLLBACK_PATCH || SCROLLBACK_MOUSE_PATCH || SCROLLBACK_MOUSE_ALTSCREEN_PATCH
#include "scrollback.h"
+#endif
+#if SIXEL_PATCH
+#include "sixel_st.h"
#endif
\ No newline at end of file
diff --git a/patch/x_include.c b/patch/x_include.c
@@ -20,6 +20,9 @@
#if RIGHTCLICKTOPLUMB_PATCH
#include "rightclicktoplumb_x.c"
#endif
+#if SIXEL_PATCH
+#include "sixel_x.c"
+#endif
#if ST_EMBEDDER_PATCH
#include "st_embedder_x.c"
#endif
diff --git a/patches.def.h b/patches.def.h
@@ -208,6 +208,26 @@
*/
#define SINGLE_DRAWABLE_BUFFER_PATCH 0
+/* This patch adds SIXEL graphics support for st.
+ * Note that patch/sixel.c/sixel_hls.c come from mintty, licensed under GPL.
+ * Known issues:
+ * - Entering clear causes all sixels to be deleted from scrollback.
+ * - Rendering sixel graphics may cause unusual cursor placement, this is
+ * not specific to this variant of st - the same issue is present in
+ * the xterm implementation. This is likely an issue of sixel height
+ * not being detected correctly.
+ * - If combined with the alpha patch sixel graphics disappear (become white)
+ * when transparent and rendered against a white background. This is believed
+ * to be related to how the sixel graphics use RGB colors instead of RGBA.
+ * A pull request or instructions for how to properly add alpha support for
+ * sixel graphics would be very welcome.
+ *
+ * Note that you need to uncomment the corresponding lines in Makefile when including this patch.
+ *
+ * https://gist.github.com/saitoha/70e0fdf22e3e8f63ce937c7f7da71809
+ */
+#define SIXEL_PATCH 0
+
/* This patch allows clients to embed into the st window and is useful if you tend to
* start X applications from the terminal. For example:
*
diff --git a/sixel.c b/sixel.c
@@ -0,0 +1,616 @@
+// sixel.c (part of mintty)
+// originally written by kmiya@cluti (https://github.com/saitoha/sixel/blob/master/fromsixel.c)
+// Licensed under the terms of the GNU General Public License v3 or later.
+
+#include <stdlib.h>
+#include <string.h> /* memcpy */
+
+#include "sixel.h"
+#include "sixel_hls.h"
+
+#define SIXEL_RGB(r, g, b) ((r) + ((g) << 8) + ((b) << 16))
+#define SIXEL_PALVAL(n,a,m) (((n) * (a) + ((m) / 2)) / (m))
+#define SIXEL_XRGB(r,g,b) SIXEL_RGB(SIXEL_PALVAL(r, 255, 100), SIXEL_PALVAL(g, 255, 100), SIXEL_PALVAL(b, 255, 100))
+
+static sixel_color_t const sixel_default_color_table[] = {
+ SIXEL_XRGB( 0, 0, 0), /* 0 Black */
+ SIXEL_XRGB(20, 20, 80), /* 1 Blue */
+ SIXEL_XRGB(80, 13, 13), /* 2 Red */
+ SIXEL_XRGB(20, 80, 20), /* 3 Green */
+ SIXEL_XRGB(80, 20, 80), /* 4 Magenta */
+ SIXEL_XRGB(20, 80, 80), /* 5 Cyan */
+ SIXEL_XRGB(80, 80, 20), /* 6 Yellow */
+ SIXEL_XRGB(53, 53, 53), /* 7 Gray 50% */
+ SIXEL_XRGB(26, 26, 26), /* 8 Gray 25% */
+ SIXEL_XRGB(33, 33, 60), /* 9 Blue* */
+ SIXEL_XRGB(60, 26, 26), /* 10 Red* */
+ SIXEL_XRGB(33, 60, 33), /* 11 Green* */
+ SIXEL_XRGB(60, 33, 60), /* 12 Magenta* */
+ SIXEL_XRGB(33, 60, 60), /* 13 Cyan* */
+ SIXEL_XRGB(60, 60, 33), /* 14 Yellow* */
+ SIXEL_XRGB(80, 80, 80), /* 15 Gray 75% */
+};
+
+static int
+set_default_color(sixel_image_t *image)
+{
+ int i;
+ int n;
+ int r;
+ int g;
+ int b;
+
+ /* palette initialization */
+ for (n = 1; n < 17; n++) {
+ image->palette[n] = sixel_default_color_table[n - 1];
+ }
+
+ /* colors 17-232 are a 6x6x6 color cube */
+ for (r = 0; r < 6; r++) {
+ for (g = 0; g < 6; g++) {
+ for (b = 0; b < 6; b++) {
+ image->palette[n++] = SIXEL_RGB(r * 51, g * 51, b * 51);
+ }
+ }
+ }
+
+ /* colors 233-256 are a grayscale ramp, intentionally leaving out */
+ for (i = 0; i < 24; i++) {
+ image->palette[n++] = SIXEL_RGB(i * 11, i * 11, i * 11);
+ }
+
+ for (; n < DECSIXEL_PALETTE_MAX; n++) {
+ image->palette[n] = SIXEL_RGB(255, 255, 255);
+ }
+
+ return (0);
+}
+
+static int
+sixel_image_init(
+ sixel_image_t *image,
+ int width,
+ int height,
+ int fgcolor,
+ int bgcolor,
+ int use_private_register)
+{
+ int status = (-1);
+ size_t size;
+
+ size = (size_t)(width * height) * sizeof(sixel_color_no_t);
+ image->width = width;
+ image->height = height;
+ image->data = (sixel_color_no_t *)malloc(size);
+ image->ncolors = 2;
+ image->use_private_register = use_private_register;
+
+ if (image->data == NULL) {
+ status = (-1);
+ goto end;
+ }
+ memset(image->data, 0, size);
+
+ image->palette[0] = bgcolor;
+
+ if (image->use_private_register)
+ image->palette[1] = fgcolor;
+
+ image->palette_modified = 0;
+
+ status = (0);
+
+end:
+ return status;
+}
+
+
+static int
+image_buffer_resize(
+ sixel_image_t *image,
+ int width,
+ int height)
+{
+ int status = (-1);
+ size_t size;
+ sixel_color_no_t *alt_buffer;
+ int n;
+ int min_height;
+
+ size = (size_t)(width * height) * sizeof(sixel_color_no_t);
+ alt_buffer = (sixel_color_no_t *)malloc(size);
+ if (alt_buffer == NULL) {
+ /* free source image */
+ free(image->data);
+ image->data = NULL;
+ status = (-1);
+ goto end;
+ }
+
+ min_height = height > image->height ? image->height: height;
+ if (width > image->width) { /* if width is extended */
+ for (n = 0; n < min_height; ++n) {
+ /* copy from source image */
+ memcpy(alt_buffer + width * n,
+ image->data + image->width * n,
+ (size_t)image->width * sizeof(sixel_color_no_t));
+ /* fill extended area with background color */
+ memset(alt_buffer + width * n + image->width,
+ 0,
+ (size_t)(width - image->width) * sizeof(sixel_color_no_t));
+ }
+ } else {
+ for (n = 0; n < min_height; ++n) {
+ /* copy from source image */
+ memcpy(alt_buffer + width * n,
+ image->data + image->width * n,
+ (size_t)width * sizeof(sixel_color_no_t));
+ }
+ }
+
+ if (height > image->height) { /* if height is extended */
+ /* fill extended area with background color */
+ memset(alt_buffer + width * image->height,
+ 0,
+ (size_t)(width * (height - image->height)) * sizeof(sixel_color_no_t));
+ }
+
+ /* free source image */
+ free(image->data);
+
+ image->data = alt_buffer;
+ image->width = width;
+ image->height = height;
+
+ status = (0);
+
+end:
+ return status;
+}
+
+static void
+sixel_image_deinit(sixel_image_t *image)
+{
+ free(image->data);
+ image->data = NULL;
+}
+
+int
+sixel_parser_init(sixel_state_t *st,
+ sixel_color_t fgcolor, sixel_color_t bgcolor,
+ unsigned char use_private_register,
+ int cell_width, int cell_height)
+{
+ int status = (-1);
+
+ st->state = PS_DECSIXEL;
+ st->pos_x = 0;
+ st->pos_y = 0;
+ st->max_x = 0;
+ st->max_y = 0;
+ st->attributed_pan = 2;
+ st->attributed_pad = 1;
+ st->attributed_ph = 0;
+ st->attributed_pv = 0;
+ st->repeat_count = 1;
+ st->color_index = 16;
+ st->grid_width = cell_width;
+ st->grid_height = cell_height;
+ st->nparams = 0;
+ st->param = 0;
+
+ /* buffer initialization */
+ status = sixel_image_init(&st->image, 1, 1, fgcolor, bgcolor, use_private_register);
+
+ return status;
+}
+
+int
+sixel_parser_set_default_color(sixel_state_t *st)
+{
+ return set_default_color(&st->image);
+}
+
+int
+sixel_parser_finalize(sixel_state_t *st, unsigned char *pixels)
+{
+ int status = (-1);
+ int sx;
+ int sy;
+ sixel_image_t *image = &st->image;
+ int x, y;
+ sixel_color_no_t *src;
+ unsigned char *dst;
+ int color;
+
+ if (++st->max_x < st->attributed_ph)
+ st->max_x = st->attributed_ph;
+
+ if (++st->max_y < st->attributed_pv)
+ st->max_y = st->attributed_pv;
+
+ sx = (st->max_x + st->grid_width - 1) / st->grid_width * st->grid_width;
+ sy = (st->max_y + st->grid_height - 1) / st->grid_height * st->grid_height;
+
+ if (image->width > sx || image->height > sy) {
+ status = image_buffer_resize(image, sx, sy);
+ if (status < 0)
+ goto end;
+ }
+
+ if (image->use_private_register && image->ncolors > 2 && !image->palette_modified) {
+ status = set_default_color(image);
+ if (status < 0)
+ goto end;
+ }
+
+ src = st->image.data;
+ dst = pixels;
+ for (y = 0; y < st->image.height; ++y) {
+ for (x = 0; x < st->image.width; ++x) {
+ color = st->image.palette[*src++];
+ *dst++ = color >> 16 & 0xff; /* b */
+ *dst++ = color >> 8 & 0xff; /* g */
+ *dst++ = color >> 0 & 0xff; /* r */
+ dst++; /* a */
+ }
+ /* fill right padding with bgcolor */
+ for (; x < st->image.width; ++x) {
+ color = st->image.palette[0]; /* bgcolor */
+ *dst++ = color >> 16 & 0xff; /* b */
+ *dst++ = color >> 8 & 0xff; /* g */
+ *dst++ = color >> 0 & 0xff; /* r */
+ dst++; /* a */
+ }
+ }
+ /* fill bottom padding with bgcolor */
+ for (; y < st->image.height; ++y) {
+ for (x = 0; x < st->image.width; ++x) {
+ color = st->image.palette[0]; /* bgcolor */
+ *dst++ = color >> 16 & 0xff; /* b */
+ *dst++ = color >> 8 & 0xff; /* g */
+ *dst++ = color >> 0 & 0xff; /* r */
+ dst++; /* a */
+ }
+ }
+
+ status = (0);
+
+end:
+ return status;
+}
+
+/* convert sixel data into indexed pixel bytes and palette data */
+int
+sixel_parser_parse(sixel_state_t *st, unsigned char *p, size_t len)
+{
+ int status = (-1);
+ int n;
+ int i;
+ int x;
+ int y;
+ int bits;
+ int sixel_vertical_mask;
+ int sx;
+ int sy;
+ int c;
+ int pos;
+ unsigned char *p0 = p;
+ sixel_image_t *image = &st->image;
+
+ if (! image->data)
+ goto end;
+
+ while (p < p0 + len) {
+ switch (st->state) {
+ case PS_ESC:
+ goto end;
+
+ case PS_DECSIXEL:
+ switch (*p) {
+ case '\x1b':
+ st->state = PS_ESC;
+ p++;
+ break;
+ case '"':
+ st->param = 0;
+ st->nparams = 0;
+ st->state = PS_DECGRA;
+ p++;
+ break;
+ case '!':
+ st->param = 0;
+ st->nparams = 0;
+ st->state = PS_DECGRI;
+ p++;
+ break;
+ case '#':
+ st->param = 0;
+ st->nparams = 0;
+ st->state = PS_DECGCI;
+ p++;
+ break;
+ case '$':
+ /* DECGCR Graphics Carriage Return */
+ st->pos_x = 0;
+ p++;
+ break;
+ case '-':
+ /* DECGNL Graphics Next Line */
+ st->pos_x = 0;
+ if (st->pos_y < DECSIXEL_HEIGHT_MAX - 5 - 6)
+ st->pos_y += 6;
+ else
+ st->pos_y = DECSIXEL_HEIGHT_MAX + 1;
+ p++;
+ break;
+ default:
+ if (*p >= '?' && *p <= '~') { /* sixel characters */
+ if ((image->width < (st->pos_x + st->repeat_count) || image->height < (st->pos_y + 6))
+ && image->width < DECSIXEL_WIDTH_MAX && image->height < DECSIXEL_HEIGHT_MAX) {
+ sx = image->width * 2;
+ sy = image->height * 2;
+ while (sx < (st->pos_x + st->repeat_count) || sy < (st->pos_y + 6)) {
+ sx *= 2;
+ sy *= 2;
+ }
+
+ if (sx > DECSIXEL_WIDTH_MAX)
+ sx = DECSIXEL_WIDTH_MAX;
+ if (sy > DECSIXEL_HEIGHT_MAX)
+ sy = DECSIXEL_HEIGHT_MAX;
+
+ status = image_buffer_resize(image, sx, sy);
+ if (status < 0)
+ goto end;
+ }
+
+ if (st->color_index > image->ncolors)
+ image->ncolors = st->color_index;
+
+ if (st->pos_x + st->repeat_count > image->width)
+ st->repeat_count = image->width - st->pos_x;
+
+ if (st->repeat_count > 0 && st->pos_y - 5 < image->height) {
+ bits = *p - '?';
+ if (bits != 0) {
+ sixel_vertical_mask = 0x01;
+ if (st->repeat_count <= 1) {
+ for (i = 0; i < 6; i++) {
+ if ((bits & sixel_vertical_mask) != 0) {
+ pos = image->width * (st->pos_y + i) + st->pos_x;
+ image->data[pos] = st->color_index;
+ if (st->max_x < st->pos_x)
+ st->max_x = st->pos_x;
+ if (st->max_y < (st->pos_y + i))
+ st->max_y = st->pos_y + i;
+ }
+ sixel_vertical_mask <<= 1;
+ }
+ } else {
+ /* st->repeat_count > 1 */
+ for (i = 0; i < 6; i++) {
+ if ((bits & sixel_vertical_mask) != 0) {
+ c = sixel_vertical_mask << 1;
+ for (n = 1; (i + n) < 6; n++) {
+ if ((bits & c) == 0)
+ break;
+ c <<= 1;
+ }
+ for (y = st->pos_y + i; y < st->pos_y + i + n; ++y) {
+ for (x = st->pos_x; x < st->pos_x + st->repeat_count; ++x)
+ image->data[image->width * y + x] = st->color_index;
+ }
+ if (st->max_x < (st->pos_x + st->repeat_count - 1))
+ st->max_x = st->pos_x + st->repeat_count - 1;
+ if (st->max_y < (st->pos_y + i + n - 1))
+ st->max_y = st->pos_y + i + n - 1;
+ i += (n - 1);
+ sixel_vertical_mask <<= (n - 1);
+ }
+ sixel_vertical_mask <<= 1;
+ }
+ }
+ }
+ }
+ if (st->repeat_count > 0)
+ st->pos_x += st->repeat_count;
+ st->repeat_count = 1;
+ }
+ p++;
+ break;
+ }
+ break;
+
+ case PS_DECGRA:
+ /* DECGRA Set Raster Attributes " Pan; Pad; Ph; Pv */
+ switch (*p) {
+ case '\x1b':
+ st->state = PS_ESC;
+ p++;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ st->param = st->param * 10 + *p - '0';
+ if (st->param > DECSIXEL_PARAMVALUE_MAX)
+ st->param = DECSIXEL_PARAMVALUE_MAX;
+ p++;
+ break;
+ case ';':
+ if (st->nparams < DECSIXEL_PARAMS_MAX)
+ st->params[st->nparams++] = st->param;
+ st->param = 0;
+ p++;
+ break;
+ default:
+ if (st->nparams < DECSIXEL_PARAMS_MAX)
+ st->params[st->nparams++] = st->param;
+ if (st->nparams > 0)
+ st->attributed_pad = st->params[0];
+ if (st->nparams > 1)
+ st->attributed_pan = st->params[1];
+ if (st->nparams > 2 && st->params[2] > 0)
+ st->attributed_ph = st->params[2];
+ if (st->nparams > 3 && st->params[3] > 0)
+ st->attributed_pv = st->params[3];
+
+ if (st->attributed_pan <= 0)
+ st->attributed_pan = 1;
+ if (st->attributed_pad <= 0)
+ st->attributed_pad = 1;
+
+ if (image->width < st->attributed_ph ||
+ image->height < st->attributed_pv) {
+ sx = st->attributed_ph;
+ if (image->width > st->attributed_ph)
+ sx = image->width;
+
+ sy = st->attributed_pv;
+ if (image->height > st->attributed_pv)
+ sy = image->height;
+
+ sx = (sx + st->grid_width - 1) / st->grid_width * st->grid_width;
+ sy = (sy + st->grid_height - 1) / st->grid_height * st->grid_height;
+
+ if (sx > DECSIXEL_WIDTH_MAX)
+ sx = DECSIXEL_WIDTH_MAX;
+ if (sy > DECSIXEL_HEIGHT_MAX)
+ sy = DECSIXEL_HEIGHT_MAX;
+
+ status = image_buffer_resize(image, sx, sy);
+ if (status < 0)
+ goto end;
+ }
+ st->state = PS_DECSIXEL;
+ st->param = 0;
+ st->nparams = 0;
+ }
+ break;
+
+ case PS_DECGRI:
+ /* DECGRI Graphics Repeat Introducer ! Pn Ch */
+ switch (*p) {
+ case '\x1b':
+ st->state = PS_ESC;
+ p++;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ st->param = st->param * 10 + *p - '0';
+ if (st->param > DECSIXEL_PARAMVALUE_MAX)
+ st->param = DECSIXEL_PARAMVALUE_MAX;
+ p++;
+ break;
+ default:
+ st->repeat_count = st->param;
+ if (st->repeat_count == 0)
+ st->repeat_count = 1;
+ st->state = PS_DECSIXEL;
+ st->param = 0;
+ st->nparams = 0;
+ break;
+ }
+ break;
+
+ case PS_DECGCI:
+ /* DECGCI Graphics Color Introducer # Pc; Pu; Px; Py; Pz */
+ switch (*p) {
+ case '\x1b':
+ st->state = PS_ESC;
+ p++;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ st->param = st->param * 10 + *p - '0';
+ if (st->param > DECSIXEL_PARAMVALUE_MAX)
+ st->param = DECSIXEL_PARAMVALUE_MAX;
+ p++;
+ break;
+ case ';':
+ if (st->nparams < DECSIXEL_PARAMS_MAX)
+ st->params[st->nparams++] = st->param;
+ st->param = 0;
+ p++;
+ break;
+ default:
+ st->state = PS_DECSIXEL;
+ if (st->nparams < DECSIXEL_PARAMS_MAX)
+ st->params[st->nparams++] = st->param;
+ st->param = 0;
+
+ if (st->nparams > 0) {
+ st->color_index = 1 + st->params[0]; /* offset 1(background color) added */
+ if (st->color_index < 0)
+ st->color_index = 0;
+ else if (st->color_index >= DECSIXEL_PALETTE_MAX)
+ st->color_index = DECSIXEL_PALETTE_MAX - 1;
+ }
+
+ if (st->nparams > 4) {
+ st->image.palette_modified = 1;
+ if (st->params[1] == 1) {
+ /* HLS */
+ if (st->params[2] > 360)
+ st->params[2] = 360;
+ if (st->params[3] > 100)
+ st->params[3] = 100;
+ if (st->params[4] > 100)
+ st->params[4] = 100;
+ image->palette[st->color_index]
+ = hls_to_rgb(st->params[2], st->params[3], st->params[4]);
+ } else if (st->params[1] == 2) {
+ /* RGB */
+ if (st->params[2] > 100)
+ st->params[2] = 100;
+ if (st->params[3] > 100)
+ st->params[3] = 100;
+ if (st->params[4] > 100)
+ st->params[4] = 100;
+ image->palette[st->color_index]
+ = SIXEL_XRGB(st->params[2], st->params[3], st->params[4]);
+ }
+ }
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ status = (0);
+
+end:
+ return status;
+}
+
+void
+sixel_parser_deinit(sixel_state_t *st)
+{
+ if (st)
+ sixel_image_deinit(&st->image);
+}
diff --git a/sixel.h b/sixel.h
@@ -0,0 +1,58 @@
+#ifndef SIXEL_H
+#define SIXEL_H
+
+#define DECSIXEL_PARAMS_MAX 16
+#define DECSIXEL_PALETTE_MAX 1024
+#define DECSIXEL_PARAMVALUE_MAX 65535
+#define DECSIXEL_WIDTH_MAX 4096
+#define DECSIXEL_HEIGHT_MAX 4096
+
+typedef unsigned short sixel_color_no_t;
+typedef unsigned int sixel_color_t;
+
+typedef struct sixel_image_buffer {
+ sixel_color_no_t *data;
+ int width;
+ int height;
+ sixel_color_t palette[DECSIXEL_PALETTE_MAX];
+ sixel_color_no_t ncolors;
+ int palette_modified;
+ int use_private_register;
+} sixel_image_t;
+
+typedef enum parse_state {
+ PS_ESC = 1, /* ESC */
+ PS_DECSIXEL = 2, /* DECSIXEL body part ", $, -, ? ... ~ */
+ PS_DECGRA = 3, /* DECGRA Set Raster Attributes " Pan; Pad; Ph; Pv */
+ PS_DECGRI = 4, /* DECGRI Graphics Repeat Introducer ! Pn Ch */
+ PS_DECGCI = 5, /* DECGCI Graphics Color Introducer # Pc; Pu; Px; Py; Pz */
+} parse_state_t;
+
+typedef struct parser_context {
+ parse_state_t state;
+ int pos_x;
+ int pos_y;
+ int max_x;
+ int max_y;
+ int attributed_pan;
+ int attributed_pad;
+ int attributed_ph;
+ int attributed_pv;
+ int repeat_count;
+ int color_index;
+ int bgindex;
+ int grid_width;
+ int grid_height;
+ int param;
+ int nparams;
+ int params[DECSIXEL_PARAMS_MAX];
+ sixel_image_t image;
+} sixel_state_t;
+
+int sixel_parser_init(sixel_state_t *st, sixel_color_t fgcolor, sixel_color_t bgcolor, unsigned char use_private_register, int cell_width, int cell_height);
+int sixel_parser_parse(sixel_state_t *st, unsigned char *p, size_t len);
+int sixel_parser_set_default_color(sixel_state_t *st);
+int sixel_parser_finalize(sixel_state_t *st, unsigned char *pixels);
+void sixel_parser_deinit(sixel_state_t *st);
+
+#endif
diff --git a/sixel_hls.c b/sixel_hls.c
@@ -0,0 +1,115 @@
+// sixel.c (part of mintty)
+// this function is derived from a part of graphics.c
+// in Xterm pl#310 originally written by Ross Combs.
+//
+// Copyright 2013,2014 by Ross Combs
+//
+// All Rights Reserved
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// Except as contained in this notice, the name(s) of the above copyright
+// holders shall not be used in advertising or otherwise to promote the
+// sale, use or other dealings in this Software without prior written
+// authorization.
+
+#define SIXEL_RGB(r, g, b) (((r) << 16) + ((g) << 8) + (b))
+
+int
+hls_to_rgb(int hue, int lum, int sat)
+{
+ double hs = (hue + 240) % 360;
+ double hv = hs / 360.0;
+ double lv = lum / 100.0;
+ double sv = sat / 100.0;
+ double c, x, m, c2;
+ double r1, g1, b1;
+ int r, g, b;
+ int hpi;
+
+ if (sat == 0) {
+ r = g = b = lum * 255 / 100;
+ return SIXEL_RGB(r, g, b);
+ }
+
+ if ((c2 = ((2.0 * lv) - 1.0)) < 0.0) {
+ c2 = -c2;
+ }
+ c = (1.0 - c2) * sv;
+ hpi = (int) (hv * 6.0);
+ x = (hpi & 1) ? c : 0.0;
+ m = lv - 0.5 * c;
+
+ switch (hpi) {
+ case 0:
+ r1 = c;
+ g1 = x;
+ b1 = 0.0;
+ break;
+ case 1:
+ r1 = x;
+ g1 = c;
+ b1 = 0.0;
+ break;
+ case 2:
+ r1 = 0.0;
+ g1 = c;
+ b1 = x;
+ break;
+ case 3:
+ r1 = 0.0;
+ g1 = x;
+ b1 = c;
+ break;
+ case 4:
+ r1 = x;
+ g1 = 0.0;
+ b1 = c;
+ break;
+ case 5:
+ r1 = c;
+ g1 = 0.0;
+ b1 = x;
+ break;
+ default:
+ return SIXEL_RGB(255, 255, 255);
+ }
+
+ r = (int) ((r1 + m) * 100.0 + 0.5);
+ g = (int) ((g1 + m) * 100.0 + 0.5);
+ b = (int) ((b1 + m) * 100.0 + 0.5);
+
+ if (r < 0) {
+ r = 0;
+ } else if (r > 100) {
+ r = 100;
+ }
+ if (g < 0) {
+ g = 0;
+ } else if (g > 100) {
+ g = 100;
+ }
+ if (b < 0) {
+ b = 0;
+ } else if (b > 100) {
+ b = 100;
+ }
+ return SIXEL_RGB(r * 255 / 100, g * 255 / 100, b * 255 / 100);
+}
diff --git a/sixel_hls.h b/sixel_hls.h
@@ -0,0 +1,7 @@
+/*
+ * Primary color hues:
+ * blue: 0 degrees
+ * red: 120 degrees
+ * green: 240 degrees
+ */
+int hls_to_rgb(int hue, int lum, int sat);
diff --git a/st.c b/st.c
@@ -25,6 +25,10 @@
#include <X11/X.h>
#endif // KEYBOARDSELECT_PATCH
+#if SIXEL_PATCH
+#include "sixel.h"
+#endif // SIXEL_PATCH
+
#if defined(__linux)
#include <pty.h>
#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
@@ -59,6 +63,9 @@ enum term_mode {
MODE_ECHO = 1 << 4,
MODE_PRINT = 1 << 5,
MODE_UTF8 = 1 << 6,
+ #if SIXEL_PATCH
+ MODE_SIXEL = 1 << 7,
+ #endif // SIXEL_PATCH
};
enum cursor_movement {
@@ -90,16 +97,12 @@ enum escape_state {
ESC_STR_END = 16, /* a final string was encountered */
ESC_TEST = 32, /* Enter in test mode */
ESC_UTF8 = 64,
+ #if SIXEL_PATCH
+ ESC_DCS =128,
+ #endif // SIXEL_PATCH
};
typedef struct {
- Glyph attr; /* current char attributes */
- int x;
- int y;
- char state;
-} TCursor;
-
-typedef struct {
int mode;
int type;
int snap;
@@ -117,32 +120,6 @@ typedef struct {
int alt;
} Selection;
-/* Internal representation of the screen */
-typedef struct {
- int row; /* nb row */
- int col; /* nb col */
- Line *line; /* screen */
- Line *alt; /* alternate screen */
- #if SCROLLBACK_PATCH
- Line hist[HISTSIZE]; /* history buffer */
- int histi; /* history index */
- int scr; /* scroll back */
- #endif // SCROLLBACK_PATCH
- int *dirty; /* dirtyness of lines */
- TCursor c; /* cursor */
- int ocx; /* old cursor col */
- int ocy; /* old cursor row */
- int top; /* top scroll limit */
- int bot; /* bottom scroll limit */
- int mode; /* terminal mode flags */
- int esc; /* escape state flags */
- char trantbl[4]; /* charset table translation */
- int charset; /* current charset */
- int icharset; /* selected charset for sequence */
- int *tabs;
- Rune lastc; /* last printed char outside of sequence, 0 if control */
-} Term;
-
/* CSI Escape sequence structs */
/* ESC '[' [[ [<priv>] <arg> [;]] <mode> [<mode>]] */
typedef struct {
@@ -217,9 +194,6 @@ static void tdefutf8(char);
static int32_t tdefcolor(int *, int *, int);
static void tdeftran(char);
static void tstrsequence(uchar);
-
-static void drawregion(int, int, int, int);
-
static void selnormalize(void);
static void selscroll(int, int);
static void selsnap(int *, int *, int);
@@ -235,7 +209,6 @@ static char base64dec_getc(const char **);
static ssize_t xwrite(int, const char *, size_t);
/* Globals */
-static Term term;
static Selection sel;
static CSIEscape csiescseq;
static STREscape strescseq;
@@ -245,6 +218,9 @@ static int cmdfd;
static int csdfd;
#endif // EXTERNALPIPEIN_PATCH
static pid_t pid;
+#if SIXEL_PATCH
+sixel_state_t sixel_st;
+#endif // SIXEL_PATCH
static uchar utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
static uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
@@ -1116,6 +1092,9 @@ void
treset(void)
{
uint i;
+ #if SIXEL_PATCH
+ ImageList *im;
+ #endif // SIXEL_PATCH
term.c = (TCursor){{
.mode = ATTR_NULL,
@@ -1138,6 +1117,10 @@ treset(void)
tclearregion(0, 0, term.col-1, term.row-1);
tswapscreen();
}
+ #if SIXEL_PATCH
+ for (im = term.images; im; im = im->next)
+ im->should_delete = 1;
+ #endif // SIXEL_PATCH
}
void
@@ -1152,9 +1135,16 @@ void
tswapscreen(void)
{
Line *tmp = term.line;
+ #if SIXEL_PATCH
+ ImageList *im = term.images;
+ #endif // SIXEL_PATCH
term.line = term.alt;
term.alt = tmp;
+ #if SIXEL_PATCH
+ term.images = term.images_alt;
+ term.images_alt = im;
+ #endif // SIXEL_PATCH
term.mode ^= MODE_ALTSCREEN;
tfulldirt();
}
@@ -1168,6 +1158,9 @@ tscrolldown(int orig, int n)
{
int i;
Line temp;
+ #if SIXEL_PATCH
+ ImageList *im;
+ #endif // SIXEL_PATCH
LIMIT(n, 0, term.bot-orig+1);
@@ -1189,6 +1182,15 @@ tscrolldown(int orig, int n)
term.line[i-n] = temp;
}
+ #if SIXEL_PATCH
+ for (im = term.images; im; im = im->next) {
+ if (im->y < term.bot)
+ im->y += n;
+ if (im->y > term.bot)
+ im->should_delete = 1;
+ }
+ #endif // SIXEL_PATCH
+
#if SCROLLBACK_PATCH
if (term.scr == 0)
selscroll(orig, n);
@@ -1206,6 +1208,9 @@ tscrollup(int orig, int n)
{
int i;
Line temp;
+ #if SIXEL_PATCH
+ ImageList *im;
+ #endif // SIXEL_PATCH
LIMIT(n, 0, term.bot-orig+1);
@@ -1230,6 +1235,15 @@ tscrollup(int orig, int n)
term.line[i+n] = temp;
}
+ #if SIXEL_PATCH
+ for (im = term.images; im; im = im->next) {
+ if (im->y+im->height/win.ch > term.top)
+ im->y -= n;
+ if (im->y+im->height/win.ch < term.top)
+ im->should_delete = 1;
+ }
+ #endif // SIXEL_PATCH
+
#if SCROLLBACK_PATCH
if (term.scr == 0)
selscroll(orig, -n);
@@ -2033,6 +2047,10 @@ strhandle(void)
{
char *p = NULL, *dec;
int j, narg, par;
+ #if SIXEL_PATCH
+ ImageList *new_image;
+ int i;
+ #endif // SIXEL_PATCH
term.esc &= ~(ESC_STR_END|ESC_STR);
strparse();
@@ -2093,6 +2111,41 @@ strhandle(void)
xsettitle(strescseq.args[0]);
return;
case 'P': /* DCS -- Device Control String */
+ #if SIXEL_PATCH
+ if (IS_SET(MODE_SIXEL)) {
+ term.mode &= ~MODE_SIXEL;
+ new_image = malloc(sizeof(ImageList));
+ memset(new_image, 0, sizeof(ImageList));
+ new_image->x = term.c.x;
+ new_image->y = term.c.y;
+ new_image->width = sixel_st.image.width;
+ new_image->height = sixel_st.image.height;
+ new_image->pixels = malloc(new_image->width * new_image->height * 4);
+ if (sixel_parser_finalize(&sixel_st, new_image->pixels) != 0) {
+ perror("sixel_parser_finalize() failed");
+ sixel_parser_deinit(&sixel_st);
+ return;
+ }
+ sixel_parser_deinit(&sixel_st);
+ if (term.images) {
+ ImageList *im;
+ for (im = term.images; im->next;)
+ im = im->next;
+ im->next = new_image;
+ new_image->prev = im;
+ } else {
+ term.images = new_image;
+ }
+ for (i = 0; i < (sixel_st.image.height + win.ch-1)/win.ch; ++i) {
+ int x;
+ tclearregion(term.c.x, term.c.y, term.c.x+(sixel_st.image.width+win.cw-1)/win.cw, term.c.y);
+ for (x = term.c.x; x < MIN(term.col, term.c.x+(sixel_st.image.width+win.cw-1)/win.cw); x++)
+ term.line[term.c.y][x].mode |= ATTR_SIXEL;
+ tnewline(1);
+ }
+ }
+ return;
+ #endif // SIXEL_PATCH
case '_': /* APC -- Application Program Command */
case '^': /* PM -- Privacy Message */
return;
@@ -2286,9 +2339,16 @@ tdectest(char c)
void
tstrsequence(uchar c)
{
+ #if SIXEL_PATCH
+ strreset();
+ #endif // SIXEL_PATCH
+
switch (c) {
case 0x90: /* DCS -- Device Control String */
c = 'P';
+ #if SIXEL_PATCH
+ term.esc |= ESC_DCS;
+ #endif // SIXEL_PATCH
break;
case 0x9f: /* APC -- Application Program Command */
c = '_';
@@ -2300,7 +2360,9 @@ tstrsequence(uchar c)
c = ']';
break;
}
+ #if !SIXEL_PATCH
strreset();
+ #endif // SIXEL_PATCH
strescseq.type = c;
term.esc |= ESC_STR;
}
@@ -2420,6 +2482,9 @@ eschandle(uchar ascii)
term.esc |= ESC_UTF8;
return 0;
case 'P': /* DCS -- Device Control String */
+ #if SIXEL_PATCH
+ term.esc |= ESC_DCS;
+ #endif // SIXEL_PATCH
case '_': /* APC -- Application Program Command */
case '^': /* PM -- Privacy Message */
case ']': /* OSC -- Operating System Command */
@@ -2506,7 +2571,12 @@ tputc(Rune u)
Glyph *gp;
control = ISCONTROL(u);
- if (u < 127 || !IS_SET(MODE_UTF8)) {
+ #if SIXEL_PATCH
+ if (u < 127 || !IS_SET(MODE_UTF8 | MODE_SIXEL))
+ #else
+ if (u < 127 || !IS_SET(MODE_UTF8))
+ #endif // SIXEL_PATCH
+ {
c[0] = u;
width = len = 1;
} else {
@@ -2527,11 +2597,25 @@ tputc(Rune u)
if (term.esc & ESC_STR) {
if (u == '\a' || u == 030 || u == 032 || u == 033 ||
ISCONTROLC1(u)) {
+ #if SIXEL_PATCH
+ term.esc &= ~(ESC_START|ESC_STR|ESC_DCS);
+ #else
term.esc &= ~(ESC_START|ESC_STR);
+ #endif // SIXEL_PATCH
term.esc |= ESC_STR_END;
goto check_control_code;
}
+ #if SIXEL_PATCH
+ if (IS_SET(MODE_SIXEL)) {
+ if (sixel_parser_parse(&sixel_st, (unsigned char *)&u, 1) != 0)
+ perror("sixel_parser_parse() failed");
+ return;
+ }
+ if (term.esc & ESC_DCS)
+ goto check_control_code;
+ #endif // SIXEL_PATCH
+
if (strescseq.len+len >= strescseq.siz) {
/*
* Here is a bug in terminals. If the user never sends
@@ -2582,6 +2666,17 @@ check_control_code:
csihandle();
}
return;
+ #if SIXEL_PATCH
+ } else if (term.esc & ESC_DCS) {
+ csiescseq.buf[csiescseq.len++] = u;
+ if (BETWEEN(u, 0x40, 0x7E)
+ || csiescseq.len >= \
+ sizeof(csiescseq.buf)-1) {
+ csiparse();
+ dcshandle();
+ }
+ return;
+ #endif // SIXEL_PATCH
} else if (term.esc & ESC_UTF8) {
tdefutf8(u);
} else if (term.esc & ESC_ALTCHARSET) {
@@ -2643,7 +2738,12 @@ twrite(const char *buf, int buflen, int show_ctrl)
int n;
for (n = 0; n < buflen; n += charsize) {
- if (IS_SET(MODE_UTF8)) {
+ #if SIXEL_PATCH
+ if (IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL))
+ #else
+ if (IS_SET(MODE_UTF8))
+ #endif // SIXEL_PATCH
+ {
/* process a complete utf8 char */
charsize = utf8decode(buf + n, &u, buflen - n);
if (charsize == 0)
diff --git a/st.h b/st.h
@@ -2,6 +2,12 @@
#include <stdint.h>
#include <sys/types.h>
+#include <X11/Xatom.h>
+#include <X11/Xlib.h>
+#include <X11/cursorfont.h>
+#include <X11/keysym.h>
+#include <X11/Xft/Xft.h>
+#include <X11/XKBlib.h>
#include "patches.h"
/* macros */
@@ -42,15 +48,29 @@ enum glyph_attribute {
ATTR_WDUMMY = 1 << 10,
#if BOXDRAW_PATCH
ATTR_BOXDRAW = 1 << 11,
+ #endif // BOXDRAW_PATCH
#if LIGATURES_PATCH
ATTR_LIGA = 1 << 12,
#endif // LIGATURES_PATCH
- #elif LIGATURES_PATCH
- ATTR_LIGA = 1 << 11,
- #endif // BOXDRAW_PATCH
+ #if SIXEL_PATCH
+ ATTR_SIXEL = 1 << 13,
+ #endif // SIXEL_PATCH
ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
};
+#if SIXEL_PATCH
+typedef struct _ImageList {
+ struct _ImageList *next, *prev;
+ unsigned char *pixels;
+ void *pixmap;
+ int width;
+ int height;
+ int x;
+ int y;
+ int should_delete;
+} ImageList;
+#endif // SIXEL_PATCH
+
#if WIDE_GLYPHS_PATCH
enum drawing_mode {
DRAW_NONE = 0,
@@ -82,6 +102,10 @@ typedef unsigned short ushort;
typedef uint_least32_t Rune;
+typedef XftDraw *Draw;
+typedef XftColor Color;
+typedef XftGlyphFontSpec GlyphFontSpec;
+
#define Glyph Glyph_
typedef struct {
Rune u; /* character code */
@@ -92,6 +116,43 @@ typedef struct {
typedef Glyph *Line;
+typedef struct {
+ Glyph attr; /* current char attributes */
+ int x;
+ int y;
+ char state;
+} TCursor;
+
+/* Internal representation of the screen */
+typedef struct {
+ int row; /* nb row */
+ int col; /* nb col */
+ Line *line; /* screen */
+ Line *alt; /* alternate screen */
+ #if SCROLLBACK_PATCH
+ Line hist[HISTSIZE]; /* history buffer */
+ int histi; /* history index */
+ int scr; /* scroll back */
+ #endif // SCROLLBACK_PATCH
+ int *dirty; /* dirtyness of lines */
+ TCursor c; /* cursor */
+ int ocx; /* old cursor col */
+ int ocy; /* old cursor row */
+ int top; /* top scroll limit */
+ int bot; /* bottom scroll limit */
+ int mode; /* terminal mode flags */
+ int esc; /* escape state flags */
+ char trantbl[4]; /* charset table translation */
+ int charset; /* current charset */
+ int icharset; /* selected charset for sequence */
+ int *tabs;
+ #if SIXEL_PATCH
+ ImageList *images; /* sixel images */
+ ImageList *images_alt; /* sixel images for alternate screen */
+ #endif // SIXEL_PATCH
+ Rune lastc; /* last printed char outside of sequence, 0 if control */
+} Term;
+
typedef union {
int i;
uint ui;
@@ -100,9 +161,114 @@ typedef union {
const char *s;
} Arg;
+/* Purely graphic info */
+typedef struct {
+ int tw, th; /* tty width and height */
+ int w, h; /* window width and height */
+ #if ANYSIZE_PATCH
+ int hborderpx, vborderpx;
+ #endif // ANYSIZE_PATCH
+ int ch; /* char height */
+ int cw; /* char width */
+ #if VERTCENTER_PATCH
+ int cyo; /* char y offset */
+ #endif // VERTCENTER_PATCH
+ int mode; /* window state/mode flags */
+ int cursor; /* cursor style */
+} TermWindow;
+
+typedef struct {
+ Display *dpy;
+ Colormap cmap;
+ Window win;
+ Drawable buf;
+ GlyphFontSpec *specbuf; /* font spec buffer used for rendering */
+ Atom xembed, wmdeletewin, netwmname, netwmpid;
+ struct {
+ XIM xim;
+ XIC xic;
+ XPoint spot;
+ XVaNestedList spotlist;
+ } ime;
+ Draw draw;
+ Visual *vis;
+ XSetWindowAttributes attrs;
+ #if HIDECURSOR_PATCH
+ /* Here, we use the term *pointer* to differentiate the cursor
+ * one sees when hovering the mouse over the terminal from, e.g.,
+ * a green rectangle where text would be entered. */
+ Cursor vpointer, bpointer; /* visible and hidden pointers */
+ int pointerisvisible;
+ #endif // HIDECURSOR_PATCH
+ int scr;
+ int isfixed; /* is fixed geometry? */
+ #if ALPHA_PATCH
+ int depth; /* bit depth */
+ #endif // ALPHA_PATCH
+ int l, t; /* left and top offset */
+ int gm; /* geometry mask */
+} XWindow;
+
+typedef struct {
+ Atom xtarget;
+ char *primary, *clipboard;
+ struct timespec tclick1;
+ struct timespec tclick2;
+} XSelection;
+
+/* types used in config.h */
+typedef struct {
+ uint mod;
+ KeySym keysym;
+ void (*func)(const Arg *);
+ const Arg arg;
+} Shortcut;
+
+typedef struct {
+ uint mod;
+ uint button;
+ void (*func)(const Arg *);
+ const Arg arg;
+ uint release;
+} MouseShortcut;
+
+typedef struct {
+ KeySym k;
+ uint mask;
+ char *s;
+ /* three-valued logic variables: 0 indifferent, 1 on, -1 off */
+ signed char appkey; /* application keypad */
+ signed char appcursor; /* application cursor */
+} Key;
+
+/* Font structure */
+#define Font Font_
+typedef struct {
+ int height;
+ int width;
+ int ascent;
+ int descent;
+ int badslant;
+ int badweight;
+ short lbearing;
+ short rbearing;
+ XftFont *match;
+ FcFontSet *set;
+ FcPattern *pattern;
+} Font;
+
+/* Drawing Context */
+typedef struct {
+ Color *col;
+ size_t collen;
+ Font font, bfont, ifont, ibfont;
+ GC gc;
+} DC;
+
void die(const char *, ...);
void redraw(void);
void draw(void);
+void drawregion(int, int, int, int);
void printscreen(const Arg *);
void printsel(const Arg *);
@@ -165,3 +331,9 @@ extern const int boxdraw, boxdraw_bold, boxdraw_braille;
#if ALPHA_PATCH
extern float alpha;
#endif // ALPHA_PATCH
+
+extern DC dc;
+extern XWindow xw;
+extern XSelection xsel;
+extern TermWindow win;
+extern Term term;
+\ No newline at end of file
diff --git a/x.c b/x.c
@@ -27,31 +27,6 @@ char *argv0;
#include <X11/Xcursor/Xcursor.h>
#endif // THEMED_CURSOR_PATCH
-/* types used in config.h */
-typedef struct {
- uint mod;
- KeySym keysym;
- void (*func)(const Arg *);
- const Arg arg;
-} Shortcut;
-
-typedef struct {
- uint mod;
- uint button;
- void (*func)(const Arg *);
- const Arg arg;
- uint release;
-} MouseShortcut;
-
-typedef struct {
- KeySym k;
- uint mask;
- char *s;
- /* three-valued logic variables: 0 indifferent, 1 on, -1 off */
- signed char appkey; /* application keypad */
- signed char appcursor; /* application cursor */
-} Key;
-
/* X modifiers */
#define XK_ANY_MOD UINT_MAX
#define XK_NO_MOD 0
@@ -83,89 +58,6 @@ static void zoomreset(const Arg *);
#define TRUEGREEN(x) (((x) & 0xff00))
#define TRUEBLUE(x) (((x) & 0xff) << 8)
-typedef XftDraw *Draw;
-typedef XftColor Color;
-typedef XftGlyphFontSpec GlyphFontSpec;
-
-/* Purely graphic info */
-typedef struct {
- int tw, th; /* tty width and height */
- int w, h; /* window width and height */
- #if ANYSIZE_PATCH
- int hborderpx, vborderpx;
- #endif // ANYSIZE_PATCH
- int ch; /* char height */
- int cw; /* char width */
- #if VERTCENTER_PATCH
- int cyo; /* char y offset */
- #endif // VERTCENTER_PATCH
- int mode; /* window state/mode flags */
- int cursor; /* cursor style */
-} TermWindow;
-
-typedef struct {
- Display *dpy;
- Colormap cmap;
- Window win;
- Drawable buf;
- GlyphFontSpec *specbuf; /* font spec buffer used for rendering */
- Atom xembed, wmdeletewin, netwmname, netwmpid;
- struct {
- XIM xim;
- XIC xic;
- XPoint spot;
- XVaNestedList spotlist;
- } ime;
- Draw draw;
- Visual *vis;
- XSetWindowAttributes attrs;
- #if HIDECURSOR_PATCH
- /* Here, we use the term *pointer* to differentiate the cursor
- * one sees when hovering the mouse over the terminal from, e.g.,
- * a green rectangle where text would be entered. */
- Cursor vpointer, bpointer; /* visible and hidden pointers */
- int pointerisvisible;
- #endif // HIDECURSOR_PATCH
- int scr;
- int isfixed; /* is fixed geometry? */
- #if ALPHA_PATCH
- int depth; /* bit depth */
- #endif // ALPHA_PATCH
- int l, t; /* left and top offset */
- int gm; /* geometry mask */
-} XWindow;
-
-typedef struct {
- Atom xtarget;
- char *primary, *clipboard;
- struct timespec tclick1;
- struct timespec tclick2;
-} XSelection;
-
-/* Font structure */
-#define Font Font_
-typedef struct {
- int height;
- int width;
- int ascent;
- int descent;
- int badslant;
- int badweight;
- short lbearing;
- short rbearing;
- XftFont *match;
- FcFontSet *set;
- FcPattern *pattern;
-} Font;
-
-/* Drawing Context */
-typedef struct {
- Color *col;
- size_t collen;
- Font font, bfont, ifont, ibfont;
- GC gc;
-} DC;
-
static inline ushort sixd_to_16bit(int);
static int xmakeglyphfontspecs(XftGlyphFontSpec *, const Glyph *, int, int, int);
#if WIDE_GLYPHS_PATCH
@@ -250,10 +142,11 @@ static void (*handler[LASTEvent])(XEvent *) = {
};
/* Globals */
-static DC dc;
-static XWindow xw;
-static XSelection xsel;
-static TermWindow win;
+Term term;
+DC dc;
+XWindow xw;
+XSelection xsel;
+TermWindow win;
/* Font Ring Cache */
enum {
@@ -2096,6 +1989,16 @@ xdrawline(Line line, int x1, int y1, int x2)
void
xfinishdraw(void)
{
+ #if SIXEL_PATCH
+ ImageList *im;
+ int x, y;
+ int n = 0;
+ int nlimit = 256;
+ XRectangle *rects = NULL;
+ XGCValues gcvalues;
+ GC gc;
+ #endif // SIXEL_PATCH
+
#if VISUALBELL_3_PATCH
if (vbellmode == 3 && win.vbellset)
xdrawvbell();
@@ -2107,6 +2010,69 @@ xfinishdraw(void)
XSetForeground(xw.dpy, dc.gc,
dc.col[IS_SET(MODE_REVERSE)?
defaultfg : defaultbg].pixel);
+
+ #if SIXEL_PATCH
+ for (im = term.images; im; im = im->next) {
+ if (term.images == NULL) {
+ /* last image was deleted, bail out */
+ break;
+ }
+
+ if (im->should_delete) {
+ delete_image(im);
+
+ /* prevent the next iteration from accessing an invalid image pointer */
+ im = term.images;
+ if (im == NULL) {
+ break;
+ } else {
+ continue;
+ }
+ }
+
+ if (!im->pixmap) {
+ im->pixmap = (void *)XCreatePixmap(xw.dpy, xw.win, im->width, im->height,
+ #if ALPHA_PATCH
+ xw.depth
+ #else
+ DefaultDepth(xw.dpy, xw.scr)
+ #endif // ALPHA_PATCH
+ );
+ XImage ximage = {
+ .format = ZPixmap,
+ .data = (char *)im->pixels,
+ .width = im->width,
+ .height = im->height,
+ .xoffset = 0,
+ .byte_order = LSBFirst,
+ .bitmap_bit_order = MSBFirst,
+ .bits_per_pixel = 32,
+ .bytes_per_line = im->width * 4,
+ .bitmap_unit = 32,
+ .bitmap_pad = 32,
+ #if ALPHA_PATCH
+ .depth = xw.depth
+ #else
+ .depth = 24
+ #endif // ALPHA_PATCH
+ };
+ XPutImage(xw.dpy, (Drawable)im->pixmap, dc.gc, &ximage, 0, 0, 0, 0, im->width, im->height);
+ free(im->pixels);
+ im->pixels = NULL;
+ }
+
+ n = 0;
+ memset(&gcvalues, 0, sizeof(gcvalues));
+ gc = XCreateGC(xw.dpy, xw.win, 0, &gcvalues);
+
+ XCopyArea(xw.dpy, (Drawable)im->pixmap, xw.buf, gc, 0, 0, im->width, im->height, borderpx + im->x * win.cw, borderpx + im->y * win.ch);
+ XFreeGC(xw.dpy, gc);
+
+ }
+
+ free(rects);
+ drawregion(0, 0, term.col, term.row);
+ #endif // SIXEL_PATCH
}
void