Adding sixel support ref. #7
This commit is contained in:
parent
884c62a056
commit
f31c43015d
5
Makefile
5
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
static void dcshandle(void);
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
*
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
178
st.c
178
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,15 +97,11 @@ 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;
|
||||
|
@ -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)
|
||||
|
|
178
st.h
178
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;
|
190
x.c
190
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
|
||||
|
|
Loading…
Reference in New Issue