mirror of
https://github.com/mintycube/dotfiles.git
synced 2024-10-22 14:05:41 +02:00
Add sixel to st
This commit is contained in:
parent
2b8cee2e35
commit
8e5f25f43a
@ -23,6 +23,7 @@ The patches used are listed below:
|
|||||||
- rightclicktoplumb [link](https://st.suckless.org/patches/right_click_to_plumb)
|
- rightclicktoplumb [link](https://st.suckless.org/patches/right_click_to_plumb)
|
||||||
- scrollback [link](https://st.suckless.org/patches/scrollback)
|
- scrollback [link](https://st.suckless.org/patches/scrollback)
|
||||||
- scrollback mouse altscreen [link](https://st.suckless.org/patches/scrollback)
|
- scrollback mouse altscreen [link](https://st.suckless.org/patches/scrollback)
|
||||||
|
- sixel [link](https://gist.github.com/saitoha/70e0fdf22e3e8f63ce937c7f7da71809)
|
||||||
- swapmouse [link](https://st.suckless.org/patches/swapmouse)
|
- swapmouse [link](https://st.suckless.org/patches/swapmouse)
|
||||||
- use xftfontmatch [link](https://git.suckless.org/st/commit/528241aa3835e2f1f052abeeaf891737712955a0.html)
|
- use xftfontmatch [link](https://git.suckless.org/st/commit/528241aa3835e2f1f052abeeaf891737712955a0.html)
|
||||||
- wide glyphs [link](https://github.com/Dreomite/st/commit/e3b821dcb3511d60341dec35ee05a4a0abfef7f2) [link](https://www.reddit.com/r/suckless/comments/jt90ai/update_support_for_proper_glyph_rendering_in_st)
|
- wide glyphs [link](https://github.com/Dreomite/st/commit/e3b821dcb3511d60341dec35ee05a4a0abfef7f2) [link](https://www.reddit.com/r/suckless/comments/jt90ai/update_support_for_proper_glyph_rendering_in_st)
|
||||||
|
@ -30,7 +30,10 @@ char *scroll = NULL;
|
|||||||
char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400";
|
char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400";
|
||||||
|
|
||||||
/* identification sequence returned in DA and DECID */
|
/* identification sequence returned in DA and DECID */
|
||||||
char *vtiden = "\033[?6c";
|
char *vtiden = "\033[?62;4c"; /* VT200 family (62) with sixel (4) */
|
||||||
|
|
||||||
|
/* sixel rgb byte order: LSBFirst or MSBFirst */
|
||||||
|
int const sixelbyteorder = LSBFirst;
|
||||||
|
|
||||||
/* Kerning / character bounding-box multipliers */
|
/* Kerning / character bounding-box multipliers */
|
||||||
static float cwscale = 1.0;
|
static float cwscale = 1.0;
|
||||||
@ -158,7 +161,7 @@ unsigned int defaultrcs = 257;
|
|||||||
* 7: Blinking st cursor
|
* 7: Blinking st cursor
|
||||||
* 8: Steady st cursor
|
* 8: Steady st cursor
|
||||||
*/
|
*/
|
||||||
static unsigned int cursorstyle = 1;
|
static unsigned int cursorstyle = 3;
|
||||||
static Rune stcursor = 0x2603; /* snowman (U+2603) */
|
static Rune stcursor = 0x2603; /* snowman (U+2603) */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -266,10 +269,8 @@ static Shortcut shortcuts[] = {
|
|||||||
{ControlMask, XK_Print, toggleprinter, {.i = 0}},
|
{ControlMask, XK_Print, toggleprinter, {.i = 0}},
|
||||||
{ShiftMask, XK_Print, printscreen, {.i = 0}},
|
{ShiftMask, XK_Print, printscreen, {.i = 0}},
|
||||||
{XK_ANY_MOD, XK_Print, printsel, {.i = 0}},
|
{XK_ANY_MOD, XK_Print, printsel, {.i = 0}},
|
||||||
{TERMMOD, XK_Up, zoom, {.f = +2}},
|
{TERMMOD, XK_Up, zoom, {.f = +1}},
|
||||||
{TERMMOD, XK_Down, zoom, {.f = -2}},
|
{TERMMOD, XK_Down, zoom, {.f = -1}},
|
||||||
// {MODKEY, XK_equal, zoom, {.f = +2}},
|
|
||||||
// {MODKEY, XK_minus, zoom, {.f = -2}},
|
|
||||||
{TERMMOD, XK_Home, zoomreset, {.f = 0}},
|
{TERMMOD, XK_Home, zoomreset, {.f = 0}},
|
||||||
{TERMMOD, XK_C, clipcopy, {.i = 0}},
|
{TERMMOD, XK_C, clipcopy, {.i = 0}},
|
||||||
{TERMMOD, XK_V, clippaste, {.i = 0}},
|
{TERMMOD, XK_V, clippaste, {.i = 0}},
|
||||||
|
@ -27,8 +27,8 @@ LIGATURES_INC = `$(PKG_CONFIG) --cflags harfbuzz`
|
|||||||
LIGATURES_LIBS = `$(PKG_CONFIG) --libs harfbuzz`
|
LIGATURES_LIBS = `$(PKG_CONFIG) --libs harfbuzz`
|
||||||
|
|
||||||
# Uncomment this for the SIXEL patch / SIXEL_PATCH
|
# Uncomment this for the SIXEL patch / SIXEL_PATCH
|
||||||
#SIXEL_C = sixel.c sixel_hls.c
|
SIXEL_C = sixel.c sixel_hls.c
|
||||||
#SIXEL_LIBS = `$(PKG_CONFIG) --libs imlib2`
|
SIXEL_LIBS = `$(PKG_CONFIG) --libs imlib2`
|
||||||
|
|
||||||
# Uncomment for the netwmicon patch / NETWMICON_PATCH
|
# Uncomment for the netwmicon patch / NETWMICON_PATCH
|
||||||
#NETWMICON_LIBS = `$(PKG_CONFIG) --libs gdlib`
|
#NETWMICON_LIBS = `$(PKG_CONFIG) --libs gdlib`
|
||||||
|
@ -6,6 +6,7 @@ tloaddefscreen(int clear, int loadcursor)
|
|||||||
if (alt) {
|
if (alt) {
|
||||||
if (clear) {
|
if (clear) {
|
||||||
tclearregion(0, 0, term.col-1, term.row-1, 1);
|
tclearregion(0, 0, term.col-1, term.row-1, 1);
|
||||||
|
tdeleteimages();
|
||||||
}
|
}
|
||||||
col = term.col, row = term.row;
|
col = term.col, row = term.row;
|
||||||
tswapscreen();
|
tswapscreen();
|
||||||
@ -31,6 +32,7 @@ tloadaltscreen(int clear, int savecursor)
|
|||||||
}
|
}
|
||||||
if (clear) {
|
if (clear) {
|
||||||
tclearregion(0, 0, term.col-1, term.row-1, 1);
|
tclearregion(0, 0, term.col-1, term.row-1, 1);
|
||||||
|
tdeleteimages();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,6 +57,17 @@ tclearglyph(Glyph *gp, int usecurattr)
|
|||||||
gp->u = ' ';
|
gp->u = ' ';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
treflow_moveimages(int oldy, int newy)
|
||||||
|
{
|
||||||
|
ImageList *im;
|
||||||
|
|
||||||
|
for (im = term.images; im; im = im->next) {
|
||||||
|
if (im->y == oldy)
|
||||||
|
im->reflow_y = newy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
treflow(int col, int row)
|
treflow(int col, int row)
|
||||||
{
|
{
|
||||||
@ -64,6 +77,10 @@ treflow(int col, int row)
|
|||||||
int cy = -1; /* proxy for new y coordinate of cursor */
|
int cy = -1; /* proxy for new y coordinate of cursor */
|
||||||
int buflen, nlines;
|
int buflen, nlines;
|
||||||
Line *buf, bufline, line;
|
Line *buf, bufline, line;
|
||||||
|
ImageList *im, *next;
|
||||||
|
|
||||||
|
for (im = term.images; im; im = im->next)
|
||||||
|
im->reflow_y = INT_MIN; /* unset reflow_y */
|
||||||
|
|
||||||
/* y coordinate of cursor line end */
|
/* y coordinate of cursor line end */
|
||||||
for (oce = term.c.y; oce < term.row - 1 &&
|
for (oce = term.c.y; oce < term.row - 1 &&
|
||||||
@ -95,6 +112,7 @@ treflow(int col, int row)
|
|||||||
if (len == 0 || !(line[len - 1].mode & ATTR_WRAP)) {
|
if (len == 0 || !(line[len - 1].mode & ATTR_WRAP)) {
|
||||||
for (j = nx; j < col; j++)
|
for (j = nx; j < col; j++)
|
||||||
tclearglyph(&bufline[j], 0);
|
tclearglyph(&bufline[j], 0);
|
||||||
|
treflow_moveimages(oy+term.scr, ny);
|
||||||
nx = 0;
|
nx = 0;
|
||||||
} else if (nx > 0) {
|
} else if (nx > 0) {
|
||||||
bufline[nx - 1].mode &= ~ATTR_WRAP;
|
bufline[nx - 1].mode &= ~ATTR_WRAP;
|
||||||
@ -102,6 +120,7 @@ treflow(int col, int row)
|
|||||||
ox = 0, oy++;
|
ox = 0, oy++;
|
||||||
} else if (col - nx == len - ox) {
|
} else if (col - nx == len - ox) {
|
||||||
memcpy(&bufline[nx], &line[ox], (col-nx) * sizeof(Glyph));
|
memcpy(&bufline[nx], &line[ox], (col-nx) * sizeof(Glyph));
|
||||||
|
treflow_moveimages(oy+term.scr, ny);
|
||||||
ox = 0, oy++, nx = 0;
|
ox = 0, oy++, nx = 0;
|
||||||
} else/* if (col - nx < len - ox) */ {
|
} else/* if (col - nx < len - ox) */ {
|
||||||
memcpy(&bufline[nx], &line[ox], (col-nx) * sizeof(Glyph));
|
memcpy(&bufline[nx], &line[ox], (col-nx) * sizeof(Glyph));
|
||||||
@ -112,6 +131,7 @@ treflow(int col, int row)
|
|||||||
} else {
|
} else {
|
||||||
bufline[col - 1].mode |= ATTR_WRAP;
|
bufline[col - 1].mode |= ATTR_WRAP;
|
||||||
}
|
}
|
||||||
|
treflow_moveimages(oy+term.scr, ny);
|
||||||
ox += col - nx;
|
ox += col - nx;
|
||||||
nx = 0;
|
nx = 0;
|
||||||
}
|
}
|
||||||
@ -172,6 +192,29 @@ treflow(int col, int row)
|
|||||||
term.hist[j] = xrealloc(term.hist[j], col * sizeof(Glyph));
|
term.hist[j] = xrealloc(term.hist[j], col * sizeof(Glyph));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* move images to the final position */
|
||||||
|
for (im = term.images; im; im = next) {
|
||||||
|
next = im->next;
|
||||||
|
if (im->reflow_y == INT_MIN) {
|
||||||
|
delete_image(im);
|
||||||
|
} else {
|
||||||
|
im->y = im->reflow_y - term.histf + term.scr - (ny + 1);
|
||||||
|
if (im->y - term.scr < -HISTSIZE || im->y - term.scr >= row)
|
||||||
|
delete_image(im);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* expand images into new text cells */
|
||||||
|
for (im = term.images; im; im = next) {
|
||||||
|
next = im->next;
|
||||||
|
if (im->x < col) {
|
||||||
|
line = TLINE(im->y);
|
||||||
|
x2 = MIN(im->x + im->cols, col);
|
||||||
|
for (x = im->x; x < x2; x++)
|
||||||
|
line[x].mode |= ATTR_SIXEL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (; buflen > 0; ny--, buflen--)
|
for (; buflen > 0; ny--, buflen--)
|
||||||
free(buf[ny % nlines]);
|
free(buf[ny % nlines]);
|
||||||
free(buf);
|
free(buf);
|
||||||
@ -206,6 +249,7 @@ rscrolldown(int n)
|
|||||||
if ((i = term.scr - n) >= 0) {
|
if ((i = term.scr - n) >= 0) {
|
||||||
term.scr = i;
|
term.scr = i;
|
||||||
} else {
|
} else {
|
||||||
|
scroll_images(n - term.scr);
|
||||||
term.scr = 0;
|
term.scr = 0;
|
||||||
if (sel.ob.x != -1 && !sel.alt)
|
if (sel.ob.x != -1 && !sel.alt)
|
||||||
selmove(-i);
|
selmove(-i);
|
||||||
@ -258,6 +302,7 @@ void
|
|||||||
tresizealt(int col, int row)
|
tresizealt(int col, int row)
|
||||||
{
|
{
|
||||||
int i, j;
|
int i, j;
|
||||||
|
ImageList *im, *next;
|
||||||
|
|
||||||
/* return if dimensions haven't changed */
|
/* return if dimensions haven't changed */
|
||||||
if (term.col == col && term.row == row) {
|
if (term.col == col && term.row == row) {
|
||||||
@ -272,6 +317,7 @@ tresizealt(int col, int row)
|
|||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
/* ensure that both src and dst are not NULL */
|
/* ensure that both src and dst are not NULL */
|
||||||
memmove(term.line, term.line + i, row * sizeof(Line));
|
memmove(term.line, term.line + i, row * sizeof(Line));
|
||||||
|
scroll_images(-i);
|
||||||
term.c.y = row - 1;
|
term.c.y = row - 1;
|
||||||
}
|
}
|
||||||
for (i += row; i < term.row; i++)
|
for (i += row; i < term.row; i++)
|
||||||
@ -302,6 +348,17 @@ tresizealt(int col, int row)
|
|||||||
/* reset scrolling region */
|
/* reset scrolling region */
|
||||||
term.top = 0, term.bot = row - 1;
|
term.top = 0, term.bot = row - 1;
|
||||||
|
|
||||||
|
/* delete or clip images if they are not inside the screen */
|
||||||
|
for (im = term.images; im; im = next) {
|
||||||
|
next = im->next;
|
||||||
|
if (im->x >= term.col || im->y >= term.row || im->y < 0) {
|
||||||
|
delete_image(im);
|
||||||
|
} else {
|
||||||
|
if ((im->cols = MIN(im->x + im->cols, term.col) - im->x) <= 0)
|
||||||
|
delete_image(im);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* dirty all lines */
|
/* dirty all lines */
|
||||||
tfulldirt();
|
tfulldirt();
|
||||||
}
|
}
|
||||||
@ -328,6 +385,8 @@ kscrolldown(const Arg* a)
|
|||||||
selmove(-n); /* negate change in term.scr */
|
selmove(-n); /* negate change in term.scr */
|
||||||
tfulldirt();
|
tfulldirt();
|
||||||
|
|
||||||
|
scroll_images(-1*n);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -352,6 +411,8 @@ kscrollup(const Arg* a)
|
|||||||
selmove(n); /* negate change in term.scr */
|
selmove(n); /* negate change in term.scr */
|
||||||
tfulldirt();
|
tfulldirt();
|
||||||
|
|
||||||
|
scroll_images(n);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -363,6 +424,8 @@ tscrollup(int top, int bot, int n, int mode)
|
|||||||
int alt = IS_SET(MODE_ALTSCREEN);
|
int alt = IS_SET(MODE_ALTSCREEN);
|
||||||
int savehist = !alt && top == 0 && mode != SCROLL_NOSAVEHIST;
|
int savehist = !alt && top == 0 && mode != SCROLL_NOSAVEHIST;
|
||||||
int scr = alt ? 0 : term.scr;
|
int scr = alt ? 0 : term.scr;
|
||||||
|
int itop = top + scr, ibot = bot + scr;
|
||||||
|
ImageList *im, *next;
|
||||||
|
|
||||||
if (n <= 0)
|
if (n <= 0)
|
||||||
return;
|
return;
|
||||||
@ -397,6 +460,35 @@ tscrollup(int top, int bot, int n, int mode)
|
|||||||
term.line[i+n] = temp;
|
term.line[i+n] = temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (alt || !savehist) {
|
||||||
|
/* move images, if they are inside the scrolling region */
|
||||||
|
for (im = term.images; im; im = next) {
|
||||||
|
next = im->next;
|
||||||
|
if (im->y >= itop && im->y <= ibot) {
|
||||||
|
im->y -= n;
|
||||||
|
if (im->y < itop)
|
||||||
|
delete_image(im);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* move images, if they are inside the scrolling region or scrollback */
|
||||||
|
for (im = term.images; im; im = next) {
|
||||||
|
next = im->next;
|
||||||
|
im->y -= scr;
|
||||||
|
if (im->y < 0) {
|
||||||
|
im->y -= n;
|
||||||
|
} else if (im->y >= top && im->y <= bot) {
|
||||||
|
im->y -= n;
|
||||||
|
if (im->y < top)
|
||||||
|
im->y -= top; // move to scrollback
|
||||||
|
}
|
||||||
|
if (im->y < -HISTSIZE)
|
||||||
|
delete_image(im);
|
||||||
|
else
|
||||||
|
im->y += term.scr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (sel.ob.x != -1 && sel.alt == alt) {
|
if (sel.ob.x != -1 && sel.alt == alt) {
|
||||||
if (!savehist) {
|
if (!savehist) {
|
||||||
selscroll(top, bot, -n);
|
selscroll(top, bot, -n);
|
||||||
@ -416,6 +508,7 @@ tscrolldown(int top, int n)
|
|||||||
int scr = IS_SET(MODE_ALTSCREEN) ? 0 : term.scr;
|
int scr = IS_SET(MODE_ALTSCREEN) ? 0 : term.scr;
|
||||||
int itop = top + scr, ibot = bot + scr;
|
int itop = top + scr, ibot = bot + scr;
|
||||||
Line temp;
|
Line temp;
|
||||||
|
ImageList *im, *next;
|
||||||
|
|
||||||
if (n <= 0)
|
if (n <= 0)
|
||||||
return;
|
return;
|
||||||
@ -430,6 +523,16 @@ tscrolldown(int top, int n)
|
|||||||
term.line[i-n] = temp;
|
term.line[i-n] = temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* move images, if they are inside the scrolling region */
|
||||||
|
for (im = term.images; im; im = next) {
|
||||||
|
next = im->next;
|
||||||
|
if (im->y >= itop && im->y <= ibot) {
|
||||||
|
im->y += n;
|
||||||
|
if (im->y > ibot)
|
||||||
|
delete_image(im);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN))
|
if (sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN))
|
||||||
selscroll(top, bot, n);
|
selscroll(top, bot, n);
|
||||||
}
|
}
|
||||||
@ -692,6 +795,7 @@ tswapscreen(void)
|
|||||||
static int altcol, altrow;
|
static int altcol, altrow;
|
||||||
Line *tmpline = term.line;
|
Line *tmpline = term.line;
|
||||||
int tmpcol = term.col, tmprow = term.row;
|
int tmpcol = term.col, tmprow = term.row;
|
||||||
|
ImageList *im = term.images;
|
||||||
|
|
||||||
term.line = altline;
|
term.line = altline;
|
||||||
term.col = altcol, term.row = altrow;
|
term.col = altcol, term.row = altrow;
|
||||||
@ -699,6 +803,8 @@ tswapscreen(void)
|
|||||||
altcol = tmpcol, altrow = tmprow;
|
altcol = tmpcol, altrow = tmprow;
|
||||||
term.mode ^= MODE_ALTSCREEN;
|
term.mode ^= MODE_ALTSCREEN;
|
||||||
|
|
||||||
|
term.images = term.images_alt;
|
||||||
|
term.images_alt = im;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *
|
char *
|
||||||
|
687
.config/suckless/st/sixel.c
Normal file
687
.config/suckless/st/sixel.c
Normal file
@ -0,0 +1,687 @@
|
|||||||
|
// 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 "st.h"
|
||||||
|
#include "win.h"
|
||||||
|
#include "sixel.h"
|
||||||
|
#include "sixel_hls.h"
|
||||||
|
|
||||||
|
#define SIXEL_RGB(r, g, b) ((255 << 24) + ((r) << 16) + ((g) << 8) + (b))
|
||||||
|
#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% */
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
scroll_images(int n) {
|
||||||
|
ImageList *im, *next;
|
||||||
|
int top = tisaltscr() ? 0 : term.scr - HISTSIZE;
|
||||||
|
|
||||||
|
for (im = term.images; im; im = next) {
|
||||||
|
next = im->next;
|
||||||
|
im->y += n;
|
||||||
|
|
||||||
|
/* check if the current sixel has exceeded the maximum
|
||||||
|
* draw distance, and should therefore be deleted */
|
||||||
|
if (im->y < top) {
|
||||||
|
//fprintf(stderr, "im@0x%08x exceeded maximum distance\n");
|
||||||
|
delete_image(im);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
if (im->clipmask)
|
||||||
|
XFreePixmap(xw.dpy, (Drawable)im->clipmask);
|
||||||
|
free(im->pixels);
|
||||||
|
free(im);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
if (image->data)
|
||||||
|
free(image->data);
|
||||||
|
image->data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
sixel_parser_init(sixel_state_t *st,
|
||||||
|
int transparent,
|
||||||
|
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->transparent = transparent;
|
||||||
|
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, transparent ? 0 : 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, ImageList **newimages, int cx, int cy, int cw, int ch)
|
||||||
|
{
|
||||||
|
sixel_image_t *image = &st->image;
|
||||||
|
int x, y;
|
||||||
|
sixel_color_no_t *src;
|
||||||
|
sixel_color_t *dst;
|
||||||
|
int color;
|
||||||
|
int w, h;
|
||||||
|
int i, j, cols, numimages;
|
||||||
|
ImageList *im, *next, *tail;
|
||||||
|
|
||||||
|
if (!image->data)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (image->use_private_register && image->ncolors > 2 && !image->palette_modified) {
|
||||||
|
if (set_default_color(image) < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
w = MIN(st->max_x, image->width);
|
||||||
|
h = MIN(st->max_y, image->height);
|
||||||
|
|
||||||
|
if ((numimages = (h + ch-1) / ch) <= 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
cols = (w + cw-1) / cw;
|
||||||
|
|
||||||
|
*newimages = NULL, tail = NULL;
|
||||||
|
for (y = 0, i = 0; i < numimages; i++) {
|
||||||
|
if ((im = malloc(sizeof(ImageList)))) {
|
||||||
|
if (!tail) {
|
||||||
|
*newimages = tail = im;
|
||||||
|
im->prev = im->next = NULL;
|
||||||
|
} else {
|
||||||
|
tail->next = im;
|
||||||
|
im->prev = tail;
|
||||||
|
im->next = NULL;
|
||||||
|
tail = im;
|
||||||
|
}
|
||||||
|
im->x = cx;
|
||||||
|
im->y = cy + i;
|
||||||
|
im->cols = cols;
|
||||||
|
im->width = w;
|
||||||
|
im->height = MIN(h - ch * i, ch);
|
||||||
|
im->pixels = malloc(im->width * im->height * 4);
|
||||||
|
im->pixmap = NULL;
|
||||||
|
im->clipmask = NULL;
|
||||||
|
im->cw = cw;
|
||||||
|
im->ch = ch;
|
||||||
|
im->transparent = st->transparent;
|
||||||
|
}
|
||||||
|
if (!im || !im->pixels) {
|
||||||
|
for (im = *newimages; im; im = next) {
|
||||||
|
next = im->next;
|
||||||
|
if (im->pixels)
|
||||||
|
free(im->pixels);
|
||||||
|
free(im);
|
||||||
|
}
|
||||||
|
*newimages = NULL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
dst = (sixel_color_t *)im->pixels;
|
||||||
|
for (j = 0; j < im->height && y < h; j++, y++) {
|
||||||
|
src = st->image.data + image->width * y;
|
||||||
|
for (x = 0; x < w; x++)
|
||||||
|
*dst++ = st->image.palette[*src++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return numimages;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* convert sixel data into indexed pixel bytes and palette data */
|
||||||
|
int
|
||||||
|
sixel_parser_parse(sixel_state_t *st, const unsigned char *p, size_t len)
|
||||||
|
{
|
||||||
|
int n = 0;
|
||||||
|
int i;
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
int bits;
|
||||||
|
int sx;
|
||||||
|
int sy;
|
||||||
|
int c;
|
||||||
|
int pos;
|
||||||
|
int width;
|
||||||
|
const unsigned char *p0 = p, *p2 = p + len;
|
||||||
|
sixel_image_t *image = &st->image;
|
||||||
|
sixel_color_no_t *data, color_index;
|
||||||
|
|
||||||
|
if (!image->data)
|
||||||
|
st->state = PS_ERROR;
|
||||||
|
|
||||||
|
while (p < p2) {
|
||||||
|
switch (st->state) {
|
||||||
|
case PS_ESC:
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
case PS_DECSIXEL:
|
||||||
|
switch (*p) {
|
||||||
|
case '\x1b':
|
||||||
|
st->state = PS_ESC;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
sx = MIN(sx, DECSIXEL_WIDTH_MAX);
|
||||||
|
sy = MIN(sy, DECSIXEL_HEIGHT_MAX);
|
||||||
|
|
||||||
|
if (image_buffer_resize(image, sx, sy) < 0) {
|
||||||
|
perror("sixel_parser_parse() failed");
|
||||||
|
st->state = PS_ERROR;
|
||||||
|
p++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
data = image->data + image->width * st->pos_y + st->pos_x;
|
||||||
|
width = image->width;
|
||||||
|
color_index = st->color_index;
|
||||||
|
if (st->repeat_count <= 1) {
|
||||||
|
if (bits & 0x01)
|
||||||
|
*data = color_index, n = 0;
|
||||||
|
data += width;
|
||||||
|
if (bits & 0x02)
|
||||||
|
*data = color_index, n = 1;
|
||||||
|
data += width;
|
||||||
|
if (bits & 0x04)
|
||||||
|
*data = color_index, n = 2;
|
||||||
|
data += width;
|
||||||
|
if (bits & 0x08)
|
||||||
|
*data = color_index, n = 3;
|
||||||
|
data += width;
|
||||||
|
if (bits & 0x10)
|
||||||
|
*data = color_index, n = 4;
|
||||||
|
if (bits & 0x20)
|
||||||
|
data[width] = color_index, n = 5;
|
||||||
|
if (st->max_x < st->pos_x)
|
||||||
|
st->max_x = st->pos_x;
|
||||||
|
} else {
|
||||||
|
/* st->repeat_count > 1 */
|
||||||
|
for (i = 0; bits; bits >>= 1, i++, data += width) {
|
||||||
|
if (bits & 1) {
|
||||||
|
data[0] = color_index;
|
||||||
|
data[1] = color_index;
|
||||||
|
for (x = 2; x < st->repeat_count; x++)
|
||||||
|
data[x] = color_index;
|
||||||
|
n = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 + n))
|
||||||
|
st->max_y = st->pos_y + n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
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';
|
||||||
|
st->param = MIN(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 = MAX(image->width, st->attributed_ph);
|
||||||
|
sy = MAX(image->height, st->attributed_pv);
|
||||||
|
|
||||||
|
/* the height of the image buffer must be divisible by 6
|
||||||
|
* to avoid unnecessary resizing of the image buffer when
|
||||||
|
* parsing the last sixel line */
|
||||||
|
sy = (sy + 5) / 6 * 6;
|
||||||
|
|
||||||
|
sx = MIN(sx, DECSIXEL_WIDTH_MAX);
|
||||||
|
sy = MIN(sy, DECSIXEL_HEIGHT_MAX);
|
||||||
|
|
||||||
|
if (image_buffer_resize(image, sx, sy) < 0) {
|
||||||
|
perror("sixel_parser_parse() failed");
|
||||||
|
st->state = PS_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
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';
|
||||||
|
st->param = MIN(st->param, DECSIXEL_PARAMVALUE_MAX);
|
||||||
|
p++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
st->repeat_count = MAX(st->param, 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;
|
||||||
|
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';
|
||||||
|
st->param = MIN(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 */
|
||||||
|
st->params[2] = MIN(st->params[2], 360);
|
||||||
|
st->params[3] = MIN(st->params[3], 100);
|
||||||
|
st->params[4] = MIN(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 */
|
||||||
|
st->params[2] = MIN(st->params[2], 100);
|
||||||
|
st->params[3] = MIN(st->params[3], 100);
|
||||||
|
st->params[4] = MIN(st->params[4], 100);
|
||||||
|
image->palette[st->color_index]
|
||||||
|
= SIXEL_XRGB(st->params[2], st->params[3], st->params[4]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PS_ERROR:
|
||||||
|
if (*p == '\x1b') {
|
||||||
|
st->state = PS_ESC;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
p++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
return p - p0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
sixel_parser_deinit(sixel_state_t *st)
|
||||||
|
{
|
||||||
|
if (st)
|
||||||
|
sixel_image_deinit(&st->image);
|
||||||
|
}
|
||||||
|
|
||||||
|
Pixmap
|
||||||
|
sixel_create_clipmask(char *pixels, int width, int height)
|
||||||
|
{
|
||||||
|
char c, *clipdata, *dst;
|
||||||
|
int b, i, n, y, w;
|
||||||
|
int msb = (XBitmapBitOrder(xw.dpy) == MSBFirst);
|
||||||
|
sixel_color_t *src = (sixel_color_t *)pixels;
|
||||||
|
Pixmap clipmask;
|
||||||
|
|
||||||
|
clipdata = dst = malloc((width+7)/8 * height);
|
||||||
|
if (!clipdata)
|
||||||
|
return (Pixmap)None;
|
||||||
|
|
||||||
|
for (y = 0; y < height; y++) {
|
||||||
|
for (w = width; w > 0; w -= n) {
|
||||||
|
n = MIN(w, 8);
|
||||||
|
if (msb) {
|
||||||
|
for (b = 0x80, c = 0, i = 0; i < n; i++, b >>= 1)
|
||||||
|
c |= (*src++) ? b : 0;
|
||||||
|
} else {
|
||||||
|
for (b = 0x01, c = 0, i = 0; i < n; i++, b <<= 1)
|
||||||
|
c |= (*src++) ? b : 0;
|
||||||
|
}
|
||||||
|
*dst++ = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clipmask = XCreateBitmapFromData(xw.dpy, xw.win, clipdata, width, height);
|
||||||
|
free(clipdata);
|
||||||
|
return clipmask;
|
||||||
|
}
|
63
.config/suckless/st/sixel.h
Normal file
63
.config/suckless/st/sixel.h
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
#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 */
|
||||||
|
PS_ERROR = 6,
|
||||||
|
} 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 transparent;
|
||||||
|
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;
|
||||||
|
|
||||||
|
void scroll_images(int n);
|
||||||
|
void delete_image(ImageList *im);
|
||||||
|
int sixel_parser_init(sixel_state_t *st, int transparent, 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, const unsigned char *p, size_t len);
|
||||||
|
int sixel_parser_set_default_color(sixel_state_t *st);
|
||||||
|
int sixel_parser_finalize(sixel_state_t *st, ImageList **newimages, int cx, int cy, int cw, int ch);
|
||||||
|
void sixel_parser_deinit(sixel_state_t *st);
|
||||||
|
Pixmap sixel_create_clipmask(char *pixels, int width, int height);
|
||||||
|
|
||||||
|
#endif
|
115
.config/suckless/st/sixel_hls.c
Normal file
115
.config/suckless/st/sixel_hls.c
Normal file
@ -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) + ((g) << 8) + ((b) << 16) + (255 << 24))
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
7
.config/suckless/st/sixel_hls.h
Normal file
7
.config/suckless/st/sixel_hls.h
Normal file
@ -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);
|
@ -21,6 +21,8 @@
|
|||||||
#include "st.h"
|
#include "st.h"
|
||||||
#include "win.h"
|
#include "win.h"
|
||||||
|
|
||||||
|
#include "sixel.h"
|
||||||
|
|
||||||
#if defined(__linux)
|
#if defined(__linux)
|
||||||
#include <pty.h>
|
#include <pty.h>
|
||||||
#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
|
#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
|
||||||
@ -54,6 +56,9 @@ enum term_mode {
|
|||||||
MODE_ECHO = 1 << 4,
|
MODE_ECHO = 1 << 4,
|
||||||
MODE_PRINT = 1 << 5,
|
MODE_PRINT = 1 << 5,
|
||||||
MODE_UTF8 = 1 << 6,
|
MODE_UTF8 = 1 << 6,
|
||||||
|
MODE_SIXEL = 1 << 7,
|
||||||
|
MODE_SIXEL_CUR_RT = 1 << 8,
|
||||||
|
MODE_SIXEL_SDM = 1 << 9
|
||||||
};
|
};
|
||||||
|
|
||||||
enum scroll_mode {
|
enum scroll_mode {
|
||||||
@ -91,6 +96,7 @@ enum escape_state {
|
|||||||
ESC_STR_END = 16, /* a final string was encountered */
|
ESC_STR_END = 16, /* a final string was encountered */
|
||||||
ESC_TEST = 32, /* Enter in test mode */
|
ESC_TEST = 32, /* Enter in test mode */
|
||||||
ESC_UTF8 = 64,
|
ESC_UTF8 = 64,
|
||||||
|
ESC_DCS =128,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -141,6 +147,7 @@ static void ttywriteraw(const char *, size_t);
|
|||||||
|
|
||||||
static void csidump(void);
|
static void csidump(void);
|
||||||
static void csihandle(void);
|
static void csihandle(void);
|
||||||
|
static void dcshandle(void);
|
||||||
static void csiparse(void);
|
static void csiparse(void);
|
||||||
static void csireset(void);
|
static void csireset(void);
|
||||||
static void osc_color_response(int, int, int);
|
static void osc_color_response(int, int, int);
|
||||||
@ -156,6 +163,7 @@ static void tdumpline(int);
|
|||||||
static void tdump(void);
|
static void tdump(void);
|
||||||
static void tcursor(int);
|
static void tcursor(int);
|
||||||
static void tresetcursor(void);
|
static void tresetcursor(void);
|
||||||
|
static void tdeleteimages(void);
|
||||||
static void tdeleteline(int);
|
static void tdeleteline(int);
|
||||||
static void tinsertblank(int);
|
static void tinsertblank(int);
|
||||||
static void tinsertblankline(int);
|
static void tinsertblankline(int);
|
||||||
@ -199,6 +207,7 @@ static STREscape strescseq;
|
|||||||
static int iofd = 1;
|
static int iofd = 1;
|
||||||
static int cmdfd;
|
static int cmdfd;
|
||||||
static pid_t pid;
|
static pid_t pid;
|
||||||
|
sixel_state_t sixel_st;
|
||||||
|
|
||||||
static const uchar utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
|
static const uchar utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
|
||||||
static const uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
|
static const uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
|
||||||
@ -885,6 +894,7 @@ treset(void)
|
|||||||
for (y = 0; y < term.row; y++)
|
for (y = 0; y < term.row; y++)
|
||||||
for (x = 0; x < term.col; x++)
|
for (x = 0; x < term.col; x++)
|
||||||
tclearglyph(&term.line[y][x], 0);
|
tclearglyph(&term.line[y][x], 0);
|
||||||
|
tdeleteimages();
|
||||||
tswapscreen();
|
tswapscreen();
|
||||||
}
|
}
|
||||||
tfulldirt();
|
tfulldirt();
|
||||||
@ -1004,6 +1014,17 @@ tinsertblankline(int n)
|
|||||||
tscrolldown(term.c.y, n);
|
tscrolldown(term.c.y, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
tdeleteimages(void)
|
||||||
|
{
|
||||||
|
ImageList *im, *next;
|
||||||
|
|
||||||
|
for (im = term.images; im; im = next) {
|
||||||
|
next = im->next;
|
||||||
|
delete_image(im);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
tdeleteline(int n)
|
tdeleteline(int n)
|
||||||
{
|
{
|
||||||
@ -1276,6 +1297,12 @@ tsetmode(int priv, int set, const int *args, int narg)
|
|||||||
and can be mistaken for other control
|
and can be mistaken for other control
|
||||||
codes. */
|
codes. */
|
||||||
break;
|
break;
|
||||||
|
case 80: /* DECSDM -- Sixel Display Mode */
|
||||||
|
MODBIT(term.mode, set, MODE_SIXEL_SDM);
|
||||||
|
break;
|
||||||
|
case 8452: /* sixel scrolling leaves cursor to right of graphic */
|
||||||
|
MODBIT(term.mode, set, MODE_SIXEL_CUR_RT);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"erresc: unknown private set/reset mode %d\n",
|
"erresc: unknown private set/reset mode %d\n",
|
||||||
@ -1313,6 +1340,8 @@ csihandle(void)
|
|||||||
{
|
{
|
||||||
char buffer[40];
|
char buffer[40];
|
||||||
int n = 0, len;
|
int n = 0, len;
|
||||||
|
ImageList *im, *next;
|
||||||
|
int pi, pa;
|
||||||
int x;
|
int x;
|
||||||
int maxcol = term.col;
|
int maxcol = term.col;
|
||||||
|
|
||||||
@ -1424,6 +1453,7 @@ csihandle(void)
|
|||||||
case 2: /* screen */
|
case 2: /* screen */
|
||||||
if (IS_SET(MODE_ALTSCREEN)) {
|
if (IS_SET(MODE_ALTSCREEN)) {
|
||||||
tclearregion(0, 0, term.col-1, term.row-1, 1);
|
tclearregion(0, 0, term.col-1, term.row-1, 1);
|
||||||
|
tdeleteimages();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* vte does this:
|
/* vte does this:
|
||||||
@ -1431,6 +1461,8 @@ csihandle(void)
|
|||||||
/* alacritty does this: */
|
/* alacritty does this: */
|
||||||
for (n = term.row-1; n >= 0 && tlinelen(term.line[n]) == 0; n--)
|
for (n = term.row-1; n >= 0 && tlinelen(term.line[n]) == 0; n--)
|
||||||
;
|
;
|
||||||
|
for (im = term.images; im; im = im->next)
|
||||||
|
n = MAX(im->y - term.scr, n);
|
||||||
if (n >= 0)
|
if (n >= 0)
|
||||||
tscrollup(0, term.row-1, n+1, SCROLL_SAVEHIST);
|
tscrollup(0, term.row-1, n+1, SCROLL_SAVEHIST);
|
||||||
tscrollup(0, term.row-1, term.row-n-1, SCROLL_NOSAVEHIST);
|
tscrollup(0, term.row-1, term.row-n-1, SCROLL_NOSAVEHIST);
|
||||||
@ -1443,6 +1475,15 @@ csihandle(void)
|
|||||||
term.scr = 0;
|
term.scr = 0;
|
||||||
term.histi = 0;
|
term.histi = 0;
|
||||||
term.histf = 0;
|
term.histf = 0;
|
||||||
|
for (im = term.images; im; im = next) {
|
||||||
|
next = im->next;
|
||||||
|
if (im->y < 0)
|
||||||
|
delete_image(im);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 6: /* sixels */
|
||||||
|
tdeleteimages();
|
||||||
|
tfulldirt();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
goto unknown;
|
goto unknown;
|
||||||
@ -1463,6 +1504,29 @@ csihandle(void)
|
|||||||
break;
|
break;
|
||||||
case 'S': /* SU -- Scroll <n> line up ; XTSMGRAPHICS */
|
case 'S': /* SU -- Scroll <n> line up ; XTSMGRAPHICS */
|
||||||
if (csiescseq.priv) {
|
if (csiescseq.priv) {
|
||||||
|
if (csiescseq.narg > 1) {
|
||||||
|
/* XTSMGRAPHICS */
|
||||||
|
pi = csiescseq.arg[0];
|
||||||
|
pa = csiescseq.arg[1];
|
||||||
|
if (pi == 1 && (pa == 1 || pa == 2 || pa == 4)) {
|
||||||
|
/* number of sixel color registers */
|
||||||
|
/* (read, reset and read the maximum value give the same response) */
|
||||||
|
n = snprintf(buffer, sizeof buffer, "\033[?1;0;%dS", DECSIXEL_PALETTE_MAX);
|
||||||
|
ttywrite(buffer, n, 1);
|
||||||
|
break;
|
||||||
|
} else if (pi == 2 && (pa == 1 || pa == 2 || pa == 4)) {
|
||||||
|
/* sixel graphics geometry (in pixels) */
|
||||||
|
/* (read, reset and read the maximum value give the same response) */
|
||||||
|
n = snprintf(buffer, sizeof buffer, "\033[?2;0;%d;%dS",
|
||||||
|
MIN(term.col * win.cw, DECSIXEL_WIDTH_MAX),
|
||||||
|
MIN(term.row * win.ch, DECSIXEL_HEIGHT_MAX));
|
||||||
|
ttywrite(buffer, n, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* the number of color registers and sixel geometry can't be changed */
|
||||||
|
n = snprintf(buffer, sizeof buffer, "\033[?%d;3;0S", pi); /* failure */
|
||||||
|
ttywrite(buffer, n, 1);
|
||||||
|
}
|
||||||
goto unknown;
|
goto unknown;
|
||||||
}
|
}
|
||||||
DEFAULT(csiescseq.arg[0], 1);
|
DEFAULT(csiescseq.arg[0], 1);
|
||||||
@ -1536,6 +1600,27 @@ csihandle(void)
|
|||||||
case 's': /* DECSC -- Save cursor position (ANSI.SYS) */
|
case 's': /* DECSC -- Save cursor position (ANSI.SYS) */
|
||||||
tcursor(CURSOR_SAVE);
|
tcursor(CURSOR_SAVE);
|
||||||
break;
|
break;
|
||||||
|
case 't': /* title stack operations ; XTWINOPS */
|
||||||
|
switch (csiescseq.arg[0]) {
|
||||||
|
case 14: /* text area size in pixels */
|
||||||
|
if (csiescseq.narg > 1)
|
||||||
|
goto unknown;
|
||||||
|
n = snprintf(buffer, sizeof buffer, "\033[4;%d;%dt",
|
||||||
|
term.row * win.ch, term.col * win.cw);
|
||||||
|
ttywrite(buffer, n, 1);
|
||||||
|
break;
|
||||||
|
case 16: /* character cell size in pixels */
|
||||||
|
n = snprintf(buffer, sizeof buffer, "\033[6;%d;%dt", win.ch, win.cw);
|
||||||
|
ttywrite(buffer, n, 1);
|
||||||
|
break;
|
||||||
|
case 18: /* size of the text area in characters */
|
||||||
|
n = snprintf(buffer, sizeof buffer, "\033[8;%d;%dt", term.row, term.col);
|
||||||
|
ttywrite(buffer, n, 1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto unknown;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'u': /* DECRC -- Restore cursor position (ANSI.SYS) */
|
case 'u': /* DECRC -- Restore cursor position (ANSI.SYS) */
|
||||||
tcursor(CURSOR_LOAD);
|
tcursor(CURSOR_LOAD);
|
||||||
break;
|
break;
|
||||||
@ -1617,6 +1702,11 @@ strhandle(void)
|
|||||||
{ defaultbg, "background" },
|
{ defaultbg, "background" },
|
||||||
{ defaultcs, "cursor" }
|
{ defaultcs, "cursor" }
|
||||||
};
|
};
|
||||||
|
ImageList *im, *newimages, *next, *tail;
|
||||||
|
int i, x, y, x1, y1, x2, y2, numimages;
|
||||||
|
int cx, cy;
|
||||||
|
Line line;
|
||||||
|
int scr = IS_SET(MODE_ALTSCREEN) ? 0 : term.scr;
|
||||||
|
|
||||||
term.esc &= ~(ESC_STR_END|ESC_STR);
|
term.esc &= ~(ESC_STR_END|ESC_STR);
|
||||||
strparse();
|
strparse();
|
||||||
@ -1701,6 +1791,74 @@ strhandle(void)
|
|||||||
xsettitle(strescseq.args[0]);
|
xsettitle(strescseq.args[0]);
|
||||||
return;
|
return;
|
||||||
case 'P': /* DCS -- Device Control String */
|
case 'P': /* DCS -- Device Control String */
|
||||||
|
if (IS_SET(MODE_SIXEL)) {
|
||||||
|
term.mode &= ~MODE_SIXEL;
|
||||||
|
if (!sixel_st.image.data) {
|
||||||
|
sixel_parser_deinit(&sixel_st);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cx = IS_SET(MODE_SIXEL_SDM) ? 0 : term.c.x;
|
||||||
|
cy = IS_SET(MODE_SIXEL_SDM) ? 0 : term.c.y;
|
||||||
|
if ((numimages = sixel_parser_finalize(&sixel_st, &newimages,
|
||||||
|
cx, cy + scr, win.cw, win.ch)) <= 0) {
|
||||||
|
sixel_parser_deinit(&sixel_st);
|
||||||
|
perror("sixel_parser_finalize() failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sixel_parser_deinit(&sixel_st);
|
||||||
|
x1 = newimages->x;
|
||||||
|
y1 = newimages->y;
|
||||||
|
x2 = x1 + newimages->cols;
|
||||||
|
y2 = y1 + numimages;
|
||||||
|
if (newimages->transparent) {
|
||||||
|
for (tail = term.images; tail && tail->next; tail = tail->next);
|
||||||
|
} else {
|
||||||
|
for (tail = NULL, im = term.images; im; im = next) {
|
||||||
|
next = im->next;
|
||||||
|
if (im->x >= x1 && im->x + im->cols <= x2 &&
|
||||||
|
im->y >= y1 && im->y <= y2) {
|
||||||
|
delete_image(im);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
tail = im;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tail) {
|
||||||
|
tail->next = newimages;
|
||||||
|
newimages->prev = tail;
|
||||||
|
} else {
|
||||||
|
term.images = newimages;
|
||||||
|
}
|
||||||
|
x2 = MIN(x2, term.col);
|
||||||
|
for (i = 0, im = newimages; im; im = next, i++) {
|
||||||
|
next = im->next;
|
||||||
|
scr = IS_SET(MODE_ALTSCREEN) ? 0 : term.scr;
|
||||||
|
if (IS_SET(MODE_SIXEL_SDM)) {
|
||||||
|
if (i >= term.row) {
|
||||||
|
delete_image(im);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
im->y = i + scr;
|
||||||
|
line = term.line[i];
|
||||||
|
} else {
|
||||||
|
im->y = term.c.y + scr;
|
||||||
|
line = term.line[term.c.y];
|
||||||
|
}
|
||||||
|
for (x = im->x; x < x2; x++) {
|
||||||
|
line[x].mode |= ATTR_SIXEL;
|
||||||
|
}
|
||||||
|
term.dirty[MIN(im->y, term.row-1)] = 1;
|
||||||
|
if (!IS_SET(MODE_SIXEL_SDM) && i < numimages-1) {
|
||||||
|
im->next = NULL;
|
||||||
|
tnewline(0);
|
||||||
|
im->next = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* if mode 8452 is set, sixel scrolling leaves cursor to right of graphic */
|
||||||
|
if (!IS_SET(MODE_SIXEL_SDM) && IS_SET(MODE_SIXEL_CUR_RT))
|
||||||
|
term.c.x = MIN(term.c.x + newimages->cols, term.col-1);
|
||||||
|
}
|
||||||
|
return;
|
||||||
case '_': /* APC -- Application Program Command */
|
case '_': /* APC -- Application Program Command */
|
||||||
case '^': /* PM -- Privacy Message */
|
case '^': /* PM -- Privacy Message */
|
||||||
return;
|
return;
|
||||||
@ -1879,10 +2037,12 @@ tdectest(char c)
|
|||||||
void
|
void
|
||||||
tstrsequence(uchar c)
|
tstrsequence(uchar c)
|
||||||
{
|
{
|
||||||
|
strreset();
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 0x90: /* DCS -- Device Control String */
|
case 0x90: /* DCS -- Device Control String */
|
||||||
c = 'P';
|
c = 'P';
|
||||||
|
term.esc |= ESC_DCS;
|
||||||
break;
|
break;
|
||||||
case 0x9f: /* APC -- Application Program Command */
|
case 0x9f: /* APC -- Application Program Command */
|
||||||
c = '_';
|
c = '_';
|
||||||
@ -1894,7 +2054,6 @@ tstrsequence(uchar c)
|
|||||||
c = ']';
|
c = ']';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
strreset();
|
|
||||||
strescseq.type = c;
|
strescseq.type = c;
|
||||||
term.esc |= ESC_STR;
|
term.esc |= ESC_STR;
|
||||||
}
|
}
|
||||||
@ -1997,6 +2156,38 @@ tcontrolcode(uchar ascii)
|
|||||||
term.esc &= ~(ESC_STR_END|ESC_STR);
|
term.esc &= ~(ESC_STR_END|ESC_STR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
dcshandle(void)
|
||||||
|
{
|
||||||
|
int bgcolor, transparent;
|
||||||
|
unsigned char r, g, b, a = 255;
|
||||||
|
|
||||||
|
switch (csiescseq.mode[0]) {
|
||||||
|
default:
|
||||||
|
unknown:
|
||||||
|
fprintf(stderr, "erresc: unknown csi ");
|
||||||
|
csidump();
|
||||||
|
/* die(""); */
|
||||||
|
break;
|
||||||
|
case 'q': /* DECSIXEL */
|
||||||
|
transparent = (csiescseq.narg >= 2 && csiescseq.arg[1] == 1);
|
||||||
|
if (IS_TRUECOL(term.c.attr.bg)) {
|
||||||
|
r = term.c.attr.bg >> 16 & 255;
|
||||||
|
g = term.c.attr.bg >> 8 & 255;
|
||||||
|
b = term.c.attr.bg >> 0 & 255;
|
||||||
|
} else {
|
||||||
|
xgetcolor(term.c.attr.bg, &r, &g, &b);
|
||||||
|
if (term.c.attr.bg == defaultbg)
|
||||||
|
a = dc.col[defaultbg].pixel >> 24 & 255;
|
||||||
|
}
|
||||||
|
bgcolor = a << 24 | r << 16 | g << 8 | b;
|
||||||
|
if (sixel_parser_init(&sixel_st, transparent, (255 << 24), bgcolor, 1, win.cw, win.ch) != 0)
|
||||||
|
perror("sixel_parser_init() failed");
|
||||||
|
term.mode |= MODE_SIXEL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* returns 1 when the sequence is finished and it hasn't to read
|
* returns 1 when the sequence is finished and it hasn't to read
|
||||||
* more characters for this sequence, otherwise 0
|
* more characters for this sequence, otherwise 0
|
||||||
@ -2015,6 +2206,7 @@ eschandle(uchar ascii)
|
|||||||
term.esc |= ESC_UTF8;
|
term.esc |= ESC_UTF8;
|
||||||
return 0;
|
return 0;
|
||||||
case 'P': /* DCS -- Device Control String */
|
case 'P': /* DCS -- Device Control String */
|
||||||
|
term.esc |= ESC_DCS;
|
||||||
case '_': /* APC -- Application Program Command */
|
case '_': /* APC -- Application Program Command */
|
||||||
case '^': /* PM -- Privacy Message */
|
case '^': /* PM -- Privacy Message */
|
||||||
case ']': /* OSC -- Operating System Command */
|
case ']': /* OSC -- Operating System Command */
|
||||||
@ -2118,11 +2310,14 @@ tputc(Rune u)
|
|||||||
if (term.esc & ESC_STR) {
|
if (term.esc & ESC_STR) {
|
||||||
if (u == '\a' || u == 030 || u == 032 || u == 033 ||
|
if (u == '\a' || u == 030 || u == 032 || u == 033 ||
|
||||||
ISCONTROLC1(u)) {
|
ISCONTROLC1(u)) {
|
||||||
term.esc &= ~(ESC_START|ESC_STR);
|
term.esc &= ~(ESC_START|ESC_STR|ESC_DCS);
|
||||||
term.esc |= ESC_STR_END;
|
term.esc |= ESC_STR_END;
|
||||||
goto check_control_code;
|
goto check_control_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (term.esc & ESC_DCS)
|
||||||
|
goto check_control_code;
|
||||||
|
|
||||||
if (strescseq.len+len >= strescseq.siz) {
|
if (strescseq.len+len >= strescseq.siz) {
|
||||||
/*
|
/*
|
||||||
* Here is a bug in terminals. If the user never sends
|
* Here is a bug in terminals. If the user never sends
|
||||||
@ -2176,6 +2371,15 @@ check_control_code:
|
|||||||
csihandle();
|
csihandle();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
} 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;
|
||||||
} else if (term.esc & ESC_UTF8) {
|
} else if (term.esc & ESC_UTF8) {
|
||||||
tdefutf8(u);
|
tdefutf8(u);
|
||||||
} else if (term.esc & ESC_ALTCHARSET) {
|
} else if (term.esc & ESC_ALTCHARSET) {
|
||||||
@ -2249,7 +2453,10 @@ twrite(const char *buf, int buflen, int show_ctrl)
|
|||||||
int n;
|
int n;
|
||||||
|
|
||||||
for (n = 0; n < buflen; n += charsize) {
|
for (n = 0; n < buflen; n += charsize) {
|
||||||
if (IS_SET(MODE_UTF8))
|
if (IS_SET(MODE_SIXEL) && sixel_st.state != PS_ESC) {
|
||||||
|
charsize = sixel_parser_parse(&sixel_st, (const unsigned char*)buf + n, buflen - n);
|
||||||
|
continue;
|
||||||
|
} else if (IS_SET(MODE_UTF8))
|
||||||
{
|
{
|
||||||
/* process a complete utf8 char */
|
/* process a complete utf8 char */
|
||||||
charsize = utf8decode(buf + n, &u, buflen - n);
|
charsize = utf8decode(buf + n, &u, buflen - n);
|
||||||
|
@ -45,9 +45,26 @@ enum glyph_attribute {
|
|||||||
ATTR_WDUMMY = 1 << 11,
|
ATTR_WDUMMY = 1 << 11,
|
||||||
ATTR_BOXDRAW = 1 << 13,
|
ATTR_BOXDRAW = 1 << 13,
|
||||||
ATTR_LIGA = 1 << 15,
|
ATTR_LIGA = 1 << 15,
|
||||||
|
ATTR_SIXEL = 1 << 16,
|
||||||
ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
|
ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct _ImageList {
|
||||||
|
struct _ImageList *next, *prev;
|
||||||
|
unsigned char *pixels;
|
||||||
|
void *pixmap;
|
||||||
|
void *clipmask;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
int reflow_y;
|
||||||
|
int cols;
|
||||||
|
int cw;
|
||||||
|
int ch;
|
||||||
|
int transparent;
|
||||||
|
} ImageList;
|
||||||
|
|
||||||
enum drawing_mode {
|
enum drawing_mode {
|
||||||
DRAW_NONE = 0,
|
DRAW_NONE = 0,
|
||||||
DRAW_BG = 1 << 0,
|
DRAW_BG = 1 << 0,
|
||||||
@ -135,6 +152,8 @@ typedef struct {
|
|||||||
int charset; /* current charset */
|
int charset; /* current charset */
|
||||||
int icharset; /* selected charset for sequence */
|
int icharset; /* selected charset for sequence */
|
||||||
int *tabs;
|
int *tabs;
|
||||||
|
ImageList *images; /* sixel images */
|
||||||
|
ImageList *images_alt; /* sixel images for alternate screen */
|
||||||
Rune lastc; /* last printed char outside of sequence, 0 if control */
|
Rune lastc; /* last printed char outside of sequence, 0 if control */
|
||||||
} Term;
|
} Term;
|
||||||
|
|
||||||
|
@ -21,6 +21,9 @@ char *argv0;
|
|||||||
#include "win.h"
|
#include "win.h"
|
||||||
#include "hb.h"
|
#include "hb.h"
|
||||||
|
|
||||||
|
#include <Imlib2.h>
|
||||||
|
#include "sixel.h"
|
||||||
|
|
||||||
/* X modifiers */
|
/* X modifiers */
|
||||||
#define XK_ANY_MOD UINT_MAX
|
#define XK_ANY_MOD UINT_MAX
|
||||||
#define XK_NO_MOD 0
|
#define XK_NO_MOD 0
|
||||||
@ -226,17 +229,29 @@ zoom(const Arg *arg)
|
|||||||
Arg larg;
|
Arg larg;
|
||||||
|
|
||||||
larg.f = usedfontsize + arg->f;
|
larg.f = usedfontsize + arg->f;
|
||||||
|
if (larg.f >= 1.0)
|
||||||
zoomabs(&larg);
|
zoomabs(&larg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
zoomabs(const Arg *arg)
|
zoomabs(const Arg *arg)
|
||||||
{
|
{
|
||||||
|
ImageList *im;
|
||||||
|
|
||||||
xunloadfonts();
|
xunloadfonts();
|
||||||
xloadfonts(usedfont, arg->f);
|
xloadfonts(usedfont, arg->f);
|
||||||
xloadsparefonts();
|
xloadsparefonts();
|
||||||
|
|
||||||
|
/* deleting old pixmaps forces the new scaled pixmaps to be created */
|
||||||
|
for (im = term.images; im; im = im->next) {
|
||||||
|
if (im->pixmap)
|
||||||
|
XFreePixmap(xw.dpy, (Drawable)im->pixmap);
|
||||||
|
if (im->clipmask)
|
||||||
|
XFreePixmap(xw.dpy, (Drawable)im->clipmask);
|
||||||
|
im->pixmap = NULL;
|
||||||
|
im->clipmask = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
cresize(0, 0);
|
cresize(0, 0);
|
||||||
redraw();
|
redraw();
|
||||||
xhints();
|
xhints();
|
||||||
@ -1761,6 +1776,110 @@ xdrawline(Line line, int x1, int y1, int x2)
|
|||||||
void
|
void
|
||||||
xfinishdraw(void)
|
xfinishdraw(void)
|
||||||
{
|
{
|
||||||
|
ImageList *im, *next;
|
||||||
|
Imlib_Image origin, scaled;
|
||||||
|
XGCValues gcvalues;
|
||||||
|
GC gc;
|
||||||
|
int width, height;
|
||||||
|
int x, x2, del, destx, desty;
|
||||||
|
Line line;
|
||||||
|
|
||||||
|
for (im = term.images; im; im = next) {
|
||||||
|
next = im->next;
|
||||||
|
|
||||||
|
/* do not draw or process the image, if it is not visible */
|
||||||
|
if (im->x >= term.col || im->y >= term.row || im->y < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* scale the image */
|
||||||
|
width = MAX(im->width * win.cw / im->cw, 1);
|
||||||
|
height = MAX(im->height * win.ch / im->ch, 1);
|
||||||
|
if (!im->pixmap) {
|
||||||
|
im->pixmap = (void *)XCreatePixmap(xw.dpy, xw.win, width, height,
|
||||||
|
xw.depth
|
||||||
|
);
|
||||||
|
if (!im->pixmap)
|
||||||
|
continue;
|
||||||
|
if (win.cw == im->cw && win.ch == im->ch) {
|
||||||
|
XImage ximage = {
|
||||||
|
.format = ZPixmap,
|
||||||
|
.data = (char *)im->pixels,
|
||||||
|
.width = im->width,
|
||||||
|
.height = im->height,
|
||||||
|
.xoffset = 0,
|
||||||
|
.byte_order = sixelbyteorder,
|
||||||
|
.bitmap_bit_order = MSBFirst,
|
||||||
|
.bits_per_pixel = 32,
|
||||||
|
.bytes_per_line = im->width * 4,
|
||||||
|
.bitmap_unit = 32,
|
||||||
|
.bitmap_pad = 32,
|
||||||
|
.depth = xw.depth
|
||||||
|
};
|
||||||
|
XPutImage(xw.dpy, (Drawable)im->pixmap, dc.gc, &ximage, 0, 0, 0, 0, width, height);
|
||||||
|
if (im->transparent)
|
||||||
|
im->clipmask = (void *)sixel_create_clipmask((char *)im->pixels, width, height);
|
||||||
|
} else {
|
||||||
|
origin = imlib_create_image_using_data(im->width, im->height, (DATA32 *)im->pixels);
|
||||||
|
if (!origin)
|
||||||
|
continue;
|
||||||
|
imlib_context_set_image(origin);
|
||||||
|
imlib_image_set_has_alpha(1);
|
||||||
|
imlib_context_set_anti_alias(im->transparent ? 0 : 1); /* anti-aliasing messes up the clip mask */
|
||||||
|
scaled = imlib_create_cropped_scaled_image(0, 0, im->width, im->height, width, height);
|
||||||
|
imlib_free_image_and_decache();
|
||||||
|
if (!scaled)
|
||||||
|
continue;
|
||||||
|
imlib_context_set_image(scaled);
|
||||||
|
imlib_image_set_has_alpha(1);
|
||||||
|
XImage ximage = {
|
||||||
|
.format = ZPixmap,
|
||||||
|
.data = (char *)imlib_image_get_data_for_reading_only(),
|
||||||
|
.width = width,
|
||||||
|
.height = height,
|
||||||
|
.xoffset = 0,
|
||||||
|
.byte_order = sixelbyteorder,
|
||||||
|
.bitmap_bit_order = MSBFirst,
|
||||||
|
.bits_per_pixel = 32,
|
||||||
|
.bytes_per_line = width * 4,
|
||||||
|
.bitmap_unit = 32,
|
||||||
|
.bitmap_pad = 32,
|
||||||
|
.depth = xw.depth
|
||||||
|
};
|
||||||
|
XPutImage(xw.dpy, (Drawable)im->pixmap, dc.gc, &ximage, 0, 0, 0, 0, width, height);
|
||||||
|
if (im->transparent)
|
||||||
|
im->clipmask = (void *)sixel_create_clipmask((char *)imlib_image_get_data_for_reading_only(), width, height);
|
||||||
|
imlib_free_image_and_decache();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* clip the image so it does not go over to borders */
|
||||||
|
x2 = MIN(im->x + im->cols, term.col);
|
||||||
|
width = MIN(width, (x2 - im->x) * win.cw);
|
||||||
|
|
||||||
|
/* delete the image if the text cells behind it have been changed */
|
||||||
|
line = TLINE(im->y);
|
||||||
|
for (del = 0, x = im->x; x < x2; x++) {
|
||||||
|
if ((del = !(line[x].mode & ATTR_SIXEL)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (del) {
|
||||||
|
delete_image(im);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* draw the image */
|
||||||
|
memset(&gcvalues, 0, sizeof(gcvalues));
|
||||||
|
gcvalues.graphics_exposures = False;
|
||||||
|
gc = XCreateGC(xw.dpy, xw.win, GCGraphicsExposures, &gcvalues);
|
||||||
|
destx = borderpx + im->x * win.cw;
|
||||||
|
desty = borderpx + im->y * win.ch;
|
||||||
|
if (im->clipmask) {
|
||||||
|
XSetClipMask(xw.dpy, gc, (Drawable)im->clipmask);
|
||||||
|
XSetClipOrigin(xw.dpy, gc, destx, desty);
|
||||||
|
}
|
||||||
|
XCopyArea(xw.dpy, (Drawable)im->pixmap, xw.buf, gc, 0, 0, width, height, destx, desty);
|
||||||
|
XFreeGC(xw.dpy, gc);
|
||||||
|
}
|
||||||
|
|
||||||
XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, win.w, win.h, 0, 0);
|
XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, win.w, win.h, 0, 0);
|
||||||
XSetForeground(xw.dpy, dc.gc, dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg].pixel);
|
XSetForeground(xw.dpy, dc.gc, dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg].pixel);
|
||||||
|
Loading…
Reference in New Issue
Block a user