287 lines
6.7 KiB
C
287 lines
6.7 KiB
C
/* See LICENSE for licence details. */
|
|
/* function for osc sequence */
|
|
int32_t parse_color1(char *seq)
|
|
{
|
|
/*
|
|
format
|
|
rgb:r/g/b
|
|
rgb:rr/gg/bb
|
|
rgb:rrr/ggg/bbb
|
|
rgb:rrrr/gggg/bbbb
|
|
*/
|
|
int i, length, value;
|
|
int32_t color;
|
|
uint32_t rgb[3];
|
|
struct parm_t parm;
|
|
|
|
reset_parm(&parm);
|
|
parse_arg(seq, &parm, '/', isalnum);
|
|
|
|
for (i = 0; i < parm.argc; i++)
|
|
logging(DEBUG, "parm.argv[%d]: %s\n", i, parm.argv[i]);
|
|
|
|
if (parm.argc != 3)
|
|
return -1;
|
|
|
|
length = strlen(parm.argv[0]);
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
value = hex2num(parm.argv[i]);
|
|
logging(DEBUG, "value:%d\n", value);
|
|
|
|
if (length == 1) /* r/g/b/ */
|
|
rgb[i] = bit_mask[8] & (value * 0xFF / 0x0F);
|
|
else if (length == 2) /* rr/gg/bb */
|
|
rgb[i] = bit_mask[8] & value;
|
|
else if (length == 3) /* rrr/ggg/bbb */
|
|
rgb[i] = bit_mask[8] & (value * 0xFF / 0xFFF);
|
|
else if (length == 4) /* rrrr/gggg/bbbb */
|
|
rgb[i] = bit_mask[8] & (value * 0xFF / 0xFFFF);
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
color = (rgb[0] << 16) + (rgb[1] << 8) + rgb[2];
|
|
logging(DEBUG, "color:0x%.6X\n", color);
|
|
|
|
return color;
|
|
}
|
|
|
|
int32_t parse_color2(char *seq)
|
|
{
|
|
/*
|
|
format
|
|
#rgb
|
|
#rrggbb
|
|
#rrrgggbbb
|
|
#rrrrggggbbbb
|
|
*/
|
|
int i, length;
|
|
uint32_t rgb[3];
|
|
int32_t color;
|
|
char buf[BUFSIZE];
|
|
|
|
length = strlen(seq);
|
|
memset(buf, '\0', BUFSIZE);
|
|
|
|
if (length == 3) { /* rgb */
|
|
for (i = 0; i < 3; i++) {
|
|
strncpy(buf, seq + i, 1);
|
|
rgb[i] = bit_mask[8] & hex2num(buf) * 0xFF / 0x0F;
|
|
}
|
|
} else if (length == 6) { /* rrggbb */
|
|
for (i = 0; i < 3; i++) { /* rrggbb */
|
|
strncpy(buf, seq + i * 2, 2);
|
|
rgb[i] = bit_mask[8] & hex2num(buf);
|
|
}
|
|
} else if (length == 9) { /* rrrgggbbb */
|
|
for (i = 0; i < 3; i++) {
|
|
strncpy(buf, seq + i * 3, 3);
|
|
rgb[i] = bit_mask[8] & hex2num(buf) * 0xFF / 0xFFF;
|
|
}
|
|
} else if (length == 12) { /* rrrrggggbbbb */
|
|
for (i = 0; i < 3; i++) {
|
|
strncpy(buf, seq + i * 4, 4);
|
|
rgb[i] = bit_mask[8] & hex2num(buf) * 0xFF / 0xFFFF;
|
|
}
|
|
} else {
|
|
return -1;
|
|
}
|
|
|
|
color = (rgb[0] << 16) + (rgb[1] << 8) + rgb[2];
|
|
logging(DEBUG, "color:0x%.6X\n", color);
|
|
|
|
return color;
|
|
}
|
|
|
|
void set_palette(struct terminal_t *term, void *arg)
|
|
{
|
|
/*
|
|
OSC Ps ; Pt ST
|
|
ref: http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
|
|
ref: http://ttssh2.sourceforge.jp/manual/ja/about/ctrlseq.html#OSC
|
|
|
|
only recognize change color palette:
|
|
Ps: 4
|
|
Pt: c ; spec
|
|
c: color index (from 0 to 255)
|
|
spec:
|
|
rgb:r/g/b
|
|
rgb:rr/gg/bb
|
|
rgb:rrr/ggg/bbb
|
|
rgb:rrrr/gggg/bbbb
|
|
#rgb
|
|
#rrggbb
|
|
#rrrgggbbb
|
|
#rrrrggggbbbb
|
|
this rgb format is "RGB Device String Specification"
|
|
see http://xjman.dsl.gr.jp/X11R6/X11/CH06.html
|
|
Pt: c ; ?
|
|
response rgb color
|
|
OSC 4 ; c ; rgb:rr/gg/bb ST
|
|
|
|
TODO: this function only works in 32bpp mode
|
|
*/
|
|
struct parm_t *pt = (struct parm_t *) arg;
|
|
int i, argc = pt->argc, index;
|
|
int32_t color;
|
|
uint8_t rgb[3];
|
|
char **argv = pt->argv;
|
|
char buf[BUFSIZE];
|
|
|
|
if (argc != 3)
|
|
return;
|
|
|
|
index = dec2num(argv[1]);
|
|
if (index < 0 || index >= COLORS)
|
|
return;
|
|
|
|
if (strncmp(argv[2], "rgb:", 4) == 0) {
|
|
if ((color = parse_color1(argv[2] + 4)) != -1) { /* skip "rgb:" */
|
|
term->virtual_palette[index] = (uint32_t) color;
|
|
term->palette_modified = true;
|
|
}
|
|
} else if (strncmp(argv[2], "#", 1) == 0) {
|
|
if ((color = parse_color2(argv[2] + 1)) != -1) { /* skip "#" */
|
|
term->virtual_palette[index] = (uint32_t) color;
|
|
term->palette_modified = true;
|
|
}
|
|
} else if (strncmp(argv[2], "?", 1) == 0) {
|
|
for (i = 0; i < 3; i++)
|
|
rgb[i] = bit_mask[8] & (term->virtual_palette[index] >> (8 * (2 - i)));
|
|
|
|
snprintf(buf, BUFSIZE, "\033]4;%d;rgb:%.2X/%.2X/%.2X\033\\",
|
|
index, rgb[0], rgb[1], rgb[2]);
|
|
ewrite(term->fd, buf, strlen(buf));
|
|
}
|
|
}
|
|
|
|
void reset_palette(struct terminal_t *term, void *arg)
|
|
{
|
|
/*
|
|
reset color c
|
|
OSC 104 ; c ST
|
|
c: index of color
|
|
ST: BEL or ESC \
|
|
reset all color
|
|
OSC 104 ST
|
|
ST: BEL or ESC \
|
|
|
|
terminfo: oc=\E]104\E\\
|
|
*/
|
|
struct parm_t *pt = (struct parm_t *) arg;
|
|
int i, argc = pt->argc, c;
|
|
char **argv = pt->argv;
|
|
|
|
if (argc < 2) { /* reset all color palette */
|
|
for (i = 0; i < COLORS; i++)
|
|
term->virtual_palette[i] = color_list[i];
|
|
term->palette_modified = true;
|
|
} else if (argc == 2) { /* reset color_palette[c] */
|
|
c = dec2num(argv[1]);
|
|
if (0 <= c && c < COLORS) {
|
|
term->virtual_palette[c] = color_list[c];
|
|
term->palette_modified = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
int isdigit_or_questionmark(int c)
|
|
{
|
|
if (isdigit(c) || c == '?')
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
void glyph_width_report(struct terminal_t *term, void *arg)
|
|
{
|
|
/*
|
|
glyph width report
|
|
* request *
|
|
OSC 8900 ; Ps ; Pw ; ? : Pf : Pt ST
|
|
Ps: reserved
|
|
Pw: width (0 or 1 or 2)
|
|
Pfrom: beginning of unicode code point
|
|
Pto: end of unicode code point
|
|
ST: BEL(0x07) or ESC(0x1B) BACKSLASH(0x5C)
|
|
* answer *
|
|
OSC 8900 ; Ps ; Pv ; Pw ; Pf : Pt ; Pf : Pt ; ... ST
|
|
Ps: responce code
|
|
0: ok (default)
|
|
1: recognized but not supported
|
|
2: not recognized
|
|
Pv: reserved (maybe East Asian Width Version)
|
|
Pw: width (0 or 1 or 2)
|
|
Pfrom: beginning of unicode code point
|
|
Pto: end of unicode code point
|
|
ST: BEL(0x07) or ESC(0x1B) BACKSLASH(0x5C)
|
|
ref
|
|
http://uobikiemukot.github.io/yaft/glyph_width_report.html
|
|
https://gist.github.com/saitoha/8767268
|
|
*/
|
|
struct parm_t *pt = (struct parm_t *) arg, sub_parm;
|
|
int i, argc = pt->argc, width, from, to, left, right, w, wcw; //reserved
|
|
char **argv = pt->argv, buf[BUFSIZE];
|
|
|
|
if (argc < 4)
|
|
return;
|
|
|
|
reset_parm(&sub_parm);
|
|
parse_arg(argv[3], &sub_parm, ':', isdigit_or_questionmark);
|
|
|
|
if (sub_parm.argc != 3 || *sub_parm.argv[0] != '?')
|
|
return;
|
|
|
|
//reserved = dec2num(argv[1]);
|
|
width = dec2num(argv[2]);
|
|
from = dec2num(sub_parm.argv[1]);
|
|
to = dec2num(sub_parm.argv[2]);
|
|
|
|
if ((width < 0) || (width > 2))
|
|
return;
|
|
|
|
/* unicode private area: plane 16 (DRCSMMv1) is always half */
|
|
if ((from < 0) || (to >= UCS2_CHARS))
|
|
return;
|
|
|
|
snprintf(buf, BUFSIZE, "\033]8900;0;0;%d;", width); /* OSC 8900 ; Ps; Pv ; Pw ; */
|
|
ewrite(term->fd, buf, strlen(buf));
|
|
|
|
left = right = -1;
|
|
for (i = from; i <= to; i++) {
|
|
wcw = wcwidth(i);
|
|
if (wcw <= 0) /* zero width */
|
|
w = 0;
|
|
else if (term->glyph[i] == NULL) /* missing glyph */
|
|
w = wcw;
|
|
else
|
|
w = term->glyph[i]->width;
|
|
|
|
if (w != width) {
|
|
if (right != -1) {
|
|
snprintf(buf, BUFSIZE, "%d:%d;", left, right);
|
|
ewrite(term->fd, buf, strlen(buf));
|
|
} else if (left != -1) {
|
|
snprintf(buf, BUFSIZE, "%d:%d;", left, left);
|
|
ewrite(term->fd, buf, strlen(buf));
|
|
}
|
|
left = right = -1;
|
|
} else {
|
|
if (left == -1)
|
|
left = i;
|
|
else
|
|
right = i;
|
|
}
|
|
}
|
|
|
|
if (right != -1) {
|
|
snprintf(buf, BUFSIZE, "%d:%d;", left, right);
|
|
ewrite(term->fd, buf, strlen(buf));
|
|
} else if (left != -1) {
|
|
snprintf(buf, BUFSIZE, "%d:%d;", left, left);
|
|
ewrite(term->fd, buf, strlen(buf));
|
|
}
|
|
|
|
ewrite(term->fd, "\033\\", 2); /* ST (ESC BACKSLASH) */
|
|
}
|