Add sixel support
Originated from https://gist.github.com/CommandMaker/27ba97427424c06aff54d0a2a91a4ef1
This commit is contained in:
2
Makefile
2
Makefile
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
include config.mk
|
include config.mk
|
||||||
|
|
||||||
SRC = st.c x.c
|
SRC = st.c x.c $(SIXEL_C)
|
||||||
OBJ = $(SRC:.c=.o)
|
OBJ = $(SRC:.c=.o)
|
||||||
|
|
||||||
all: st
|
all: st
|
||||||
|
@@ -23,7 +23,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;
|
||||||
|
@@ -12,11 +12,14 @@ X11LIB = /usr/X11R6/lib
|
|||||||
|
|
||||||
PKG_CONFIG = pkg-config
|
PKG_CONFIG = pkg-config
|
||||||
|
|
||||||
|
SIXEL_C = sixel.c sixel_hls.c
|
||||||
|
SIXEL_LIBS = `$(PKG_CONFIG) --libs imlib2`
|
||||||
|
|
||||||
# includes and libs
|
# includes and libs
|
||||||
INCS = -I$(X11INC) \
|
INCS = -I$(X11INC) \
|
||||||
`$(PKG_CONFIG) --cflags fontconfig` \
|
`$(PKG_CONFIG) --cflags fontconfig` \
|
||||||
`$(PKG_CONFIG) --cflags freetype2`
|
`$(PKG_CONFIG) --cflags freetype2`
|
||||||
LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft \
|
LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft ${SIXEL_LIBS}\
|
||||||
`$(PKG_CONFIG) --libs fontconfig` \
|
`$(PKG_CONFIG) --libs fontconfig` \
|
||||||
`$(PKG_CONFIG) --libs freetype2`
|
`$(PKG_CONFIG) --libs freetype2`
|
||||||
|
|
||||||
@@ -28,8 +31,8 @@ STLDFLAGS = $(LIBS) $(LDFLAGS)
|
|||||||
# OpenBSD:
|
# OpenBSD:
|
||||||
#CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 -D_BSD_SOURCE
|
#CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 -D_BSD_SOURCE
|
||||||
#LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft \
|
#LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft \
|
||||||
# `$(PKG_CONFIG) --libs fontconfig` \
|
# `pkg-config --libs fontconfig` \
|
||||||
# `$(PKG_CONFIG) --libs freetype2`
|
# `pkg-config --libs freetype2`
|
||||||
#MANPREFIX = ${PREFIX}/man
|
#MANPREFIX = ${PREFIX}/man
|
||||||
|
|
||||||
# compiler and linker
|
# compiler and linker
|
||||||
|
690
sixel.c
Normal file
690
sixel.c
Normal file
@@ -0,0 +1,690 @@
|
|||||||
|
// 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 = 0;
|
||||||
|
|
||||||
|
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, color;
|
||||||
|
int w, h;
|
||||||
|
int i, j, cols, numimages;
|
||||||
|
char trans;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
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 (trans = 0, j = 0; j < im->height && y < h; j++, y++) {
|
||||||
|
src = st->image.data + image->width * y;
|
||||||
|
for (x = 0; x < w; x++) {
|
||||||
|
color = st->image.palette[*src++];
|
||||||
|
trans |= (color == 0);
|
||||||
|
*dst++ = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
im->transparent = (st->transparent && trans);
|
||||||
|
}
|
||||||
|
|
||||||
|
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
sixel.h
Normal file
63
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
sixel_hls.c
Normal file
115
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
sixel_hls.h
Normal file
7
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);
|
193
st.h
193
st.h
@@ -1,7 +1,14 @@
|
|||||||
/* See LICENSE for license details. */
|
/* See LICENSE for license details. */
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <time.h>
|
||||||
#include <sys/types.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>
|
||||||
|
|
||||||
/* macros */
|
/* macros */
|
||||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||||
@@ -21,21 +28,45 @@
|
|||||||
#define IS_TRUECOL(x) (1 << 24 & (x))
|
#define IS_TRUECOL(x) (1 << 24 & (x))
|
||||||
|
|
||||||
enum glyph_attribute {
|
enum glyph_attribute {
|
||||||
ATTR_NULL = 0,
|
ATTR_NULL = 0,
|
||||||
ATTR_BOLD = 1 << 0,
|
ATTR_SET = 1 << 0,
|
||||||
ATTR_FAINT = 1 << 1,
|
ATTR_BOLD = 1 << 1,
|
||||||
ATTR_ITALIC = 1 << 2,
|
ATTR_FAINT = 1 << 2,
|
||||||
ATTR_UNDERLINE = 1 << 3,
|
ATTR_ITALIC = 1 << 3,
|
||||||
ATTR_BLINK = 1 << 4,
|
ATTR_UNDERLINE = 1 << 4,
|
||||||
ATTR_REVERSE = 1 << 5,
|
ATTR_BLINK = 1 << 5,
|
||||||
ATTR_INVISIBLE = 1 << 6,
|
ATTR_REVERSE = 1 << 6,
|
||||||
ATTR_STRUCK = 1 << 7,
|
ATTR_INVISIBLE = 1 << 7,
|
||||||
ATTR_WRAP = 1 << 8,
|
ATTR_STRUCK = 1 << 8,
|
||||||
ATTR_WIDE = 1 << 9,
|
ATTR_WRAP = 1 << 9,
|
||||||
ATTR_WDUMMY = 1 << 10,
|
ATTR_WIDE = 1 << 10,
|
||||||
|
ATTR_WDUMMY = 1 << 11,
|
||||||
|
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 cols;
|
||||||
|
int cw;
|
||||||
|
int ch;
|
||||||
|
int transparent;
|
||||||
|
} ImageList;
|
||||||
|
|
||||||
|
/* Used to control which screen(s) keybindings and mouse shortcuts apply to. */
|
||||||
|
enum screen {
|
||||||
|
S_PRI = -1, /* primary screen */
|
||||||
|
S_ALL = 0, /* both primary and alt screen */
|
||||||
|
S_ALT = 1 /* alternate screen */
|
||||||
|
};
|
||||||
|
|
||||||
enum selection_mode {
|
enum selection_mode {
|
||||||
SEL_IDLE = 0,
|
SEL_IDLE = 0,
|
||||||
SEL_EMPTY = 1,
|
SEL_EMPTY = 1,
|
||||||
@@ -59,16 +90,50 @@ typedef unsigned short ushort;
|
|||||||
|
|
||||||
typedef uint_least32_t Rune;
|
typedef uint_least32_t Rune;
|
||||||
|
|
||||||
|
typedef XftDraw *Draw;
|
||||||
|
typedef XftColor Color;
|
||||||
|
typedef XftGlyphFontSpec GlyphFontSpec;
|
||||||
|
|
||||||
#define Glyph Glyph_
|
#define Glyph Glyph_
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Rune u; /* character code */
|
Rune u; /* character code */
|
||||||
ushort mode; /* attribute flags */
|
uint32_t mode; /* attribute flags */
|
||||||
uint32_t fg; /* foreground */
|
uint32_t fg; /* foreground */
|
||||||
uint32_t bg; /* background */
|
uint32_t bg; /* background */
|
||||||
} Glyph;
|
} Glyph;
|
||||||
|
|
||||||
typedef Glyph *Line;
|
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 */
|
||||||
|
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;
|
||||||
|
ImageList *images; /* sixel images */
|
||||||
|
ImageList *images_alt; /* sixel images for alternate screen */
|
||||||
|
Rune lastc; /* last printed char outside of sequence, 0 if control */
|
||||||
|
} Term;
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
int i;
|
int i;
|
||||||
uint ui;
|
uint ui;
|
||||||
@@ -77,9 +142,101 @@ typedef union {
|
|||||||
const char *s;
|
const char *s;
|
||||||
} Arg;
|
} Arg;
|
||||||
|
|
||||||
|
/* Purely graphic info */
|
||||||
|
typedef struct {
|
||||||
|
int tw, th; /* tty width and height */
|
||||||
|
int w, h; /* window width and height */
|
||||||
|
int ch; /* char height */
|
||||||
|
int cw; /* char width */
|
||||||
|
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, netwmiconname, netwmpid;
|
||||||
|
struct {
|
||||||
|
XIM xim;
|
||||||
|
XIC xic;
|
||||||
|
XPoint spot;
|
||||||
|
XVaNestedList spotlist;
|
||||||
|
} ime;
|
||||||
|
Draw draw;
|
||||||
|
Visual *vis;
|
||||||
|
XSetWindowAttributes attrs;
|
||||||
|
int scr;
|
||||||
|
int isfixed; /* is fixed geometry? */
|
||||||
|
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;
|
||||||
|
int screen;
|
||||||
|
} Shortcut;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint mod;
|
||||||
|
uint button;
|
||||||
|
void (*func)(const Arg *);
|
||||||
|
const Arg arg;
|
||||||
|
uint release;
|
||||||
|
int screen;
|
||||||
|
} 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 die(const char *, ...);
|
||||||
void redraw(void);
|
void redraw(void);
|
||||||
void draw(void);
|
void draw(void);
|
||||||
|
void drawregion(int, int, int, int);
|
||||||
|
void tfulldirt(void);
|
||||||
|
|
||||||
void printscreen(const Arg *);
|
void printscreen(const Arg *);
|
||||||
void printsel(const Arg *);
|
void printsel(const Arg *);
|
||||||
@@ -87,6 +244,7 @@ void sendbreak(const Arg *);
|
|||||||
void toggleprinter(const Arg *);
|
void toggleprinter(const Arg *);
|
||||||
|
|
||||||
int tattrset(int);
|
int tattrset(int);
|
||||||
|
int tisaltscr(void);
|
||||||
void tnew(int, int);
|
void tnew(int, int);
|
||||||
void tresize(int, int);
|
void tresize(int, int);
|
||||||
void tsetdirtattr(int);
|
void tsetdirtattr(int);
|
||||||
@@ -100,6 +258,7 @@ void resettitle(void);
|
|||||||
|
|
||||||
void selclear(void);
|
void selclear(void);
|
||||||
void selinit(void);
|
void selinit(void);
|
||||||
|
void selremove(void);
|
||||||
void selstart(int, int, int);
|
void selstart(int, int, int);
|
||||||
void selextend(int, int, int, int);
|
void selextend(int, int, int, int);
|
||||||
int selected(int, int);
|
int selected(int, int);
|
||||||
@@ -111,6 +270,8 @@ void *xmalloc(size_t);
|
|||||||
void *xrealloc(void *, size_t);
|
void *xrealloc(void *, size_t);
|
||||||
char *xstrdup(const char *);
|
char *xstrdup(const char *);
|
||||||
|
|
||||||
|
int xgetcolor(int x, unsigned char *r, unsigned char *g, unsigned char *b);
|
||||||
|
|
||||||
/* config.h globals */
|
/* config.h globals */
|
||||||
extern char *utmp;
|
extern char *utmp;
|
||||||
extern char *scroll;
|
extern char *scroll;
|
||||||
@@ -124,3 +285,9 @@ extern unsigned int tabspaces;
|
|||||||
extern unsigned int defaultfg;
|
extern unsigned int defaultfg;
|
||||||
extern unsigned int defaultbg;
|
extern unsigned int defaultbg;
|
||||||
extern unsigned int defaultcs;
|
extern unsigned int defaultcs;
|
||||||
|
|
||||||
|
extern DC dc;
|
||||||
|
extern XWindow xw;
|
||||||
|
extern XSelection xsel;
|
||||||
|
extern TermWindow win;
|
||||||
|
extern Term term;
|
||||||
|
569
x.c
569
x.c
@@ -20,30 +20,8 @@ char *argv0;
|
|||||||
#include "st.h"
|
#include "st.h"
|
||||||
#include "win.h"
|
#include "win.h"
|
||||||
|
|
||||||
/* types used in config.h */
|
#include <Imlib2.h>
|
||||||
typedef struct {
|
#include "sixel.h"
|
||||||
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 */
|
/* X modifiers */
|
||||||
#define XK_ANY_MOD UINT_MAX
|
#define XK_ANY_MOD UINT_MAX
|
||||||
@@ -55,10 +33,11 @@ static void clipcopy(const Arg *);
|
|||||||
static void clippaste(const Arg *);
|
static void clippaste(const Arg *);
|
||||||
static void numlock(const Arg *);
|
static void numlock(const Arg *);
|
||||||
static void selpaste(const Arg *);
|
static void selpaste(const Arg *);
|
||||||
|
static void ttysend(const Arg *);
|
||||||
static void zoom(const Arg *);
|
static void zoom(const Arg *);
|
||||||
static void zoomabs(const Arg *);
|
static void zoomabs(const Arg *);
|
||||||
static void zoomreset(const Arg *);
|
static void zoomreset(const Arg *);
|
||||||
static void ttysend(const Arg *);
|
|
||||||
|
|
||||||
/* config.h for applying patches and the configuration. */
|
/* config.h for applying patches and the configuration. */
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
@@ -73,77 +52,10 @@ static void ttysend(const Arg *);
|
|||||||
#define TRUEGREEN(x) (((x) & 0xff00))
|
#define TRUEGREEN(x) (((x) & 0xff00))
|
||||||
#define TRUEBLUE(x) (((x) & 0xff) << 8)
|
#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 */
|
|
||||||
int ch; /* char height */
|
|
||||||
int cw; /* char width */
|
|
||||||
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, netwmiconname, netwmpid;
|
|
||||||
struct {
|
|
||||||
XIM xim;
|
|
||||||
XIC xic;
|
|
||||||
XPoint spot;
|
|
||||||
XVaNestedList spotlist;
|
|
||||||
} ime;
|
|
||||||
Draw draw;
|
|
||||||
Visual *vis;
|
|
||||||
XSetWindowAttributes attrs;
|
|
||||||
int scr;
|
|
||||||
int isfixed; /* is fixed geometry? */
|
|
||||||
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 inline ushort sixd_to_16bit(int);
|
||||||
static int xmakeglyphfontspecs(XftGlyphFontSpec *, const Glyph *, int, int, int);
|
static int xmakeglyphfontspecs(XftGlyphFontSpec *, const Glyph *, int, int, int);
|
||||||
static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int);
|
static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int);
|
||||||
static void xdrawglyph(Glyph, int, int);
|
void xdrawglyph(Glyph, int, int);
|
||||||
static void xclear(int, int, int, int);
|
static void xclear(int, int, int, int);
|
||||||
static int xgeommasktogravity(int);
|
static int xgeommasktogravity(int);
|
||||||
static int ximopen(Display *);
|
static int ximopen(Display *);
|
||||||
@@ -172,7 +84,6 @@ static void cmessage(XEvent *);
|
|||||||
static void resize(XEvent *);
|
static void resize(XEvent *);
|
||||||
static void focus(XEvent *);
|
static void focus(XEvent *);
|
||||||
static uint buttonmask(uint);
|
static uint buttonmask(uint);
|
||||||
static int mouseaction(XEvent *, uint);
|
|
||||||
static void brelease(XEvent *);
|
static void brelease(XEvent *);
|
||||||
static void bpress(XEvent *);
|
static void bpress(XEvent *);
|
||||||
static void bmotion(XEvent *);
|
static void bmotion(XEvent *);
|
||||||
@@ -181,6 +92,7 @@ static void selnotify(XEvent *);
|
|||||||
static void selclear_(XEvent *);
|
static void selclear_(XEvent *);
|
||||||
static void selrequest(XEvent *);
|
static void selrequest(XEvent *);
|
||||||
static void setsel(char *, Time);
|
static void setsel(char *, Time);
|
||||||
|
static int mouseaction(XEvent *, uint);
|
||||||
static void mousesel(XEvent *, int);
|
static void mousesel(XEvent *, int);
|
||||||
static void mousereport(XEvent *);
|
static void mousereport(XEvent *);
|
||||||
static char *kmap(KeySym, uint);
|
static char *kmap(KeySym, uint);
|
||||||
@@ -216,10 +128,11 @@ static void (*handler[LASTEvent])(XEvent *) = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Globals */
|
/* Globals */
|
||||||
static DC dc;
|
Term term;
|
||||||
static XWindow xw;
|
DC dc;
|
||||||
static XSelection xsel;
|
XWindow xw;
|
||||||
static TermWindow win;
|
XSelection xsel;
|
||||||
|
TermWindow win;
|
||||||
|
|
||||||
/* Font Ring Cache */
|
/* Font Ring Cache */
|
||||||
enum {
|
enum {
|
||||||
@@ -254,6 +167,7 @@ static char *opt_title = NULL;
|
|||||||
|
|
||||||
static uint buttons; /* bit field of pressed buttons */
|
static uint buttons; /* bit field of pressed buttons */
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
clipcopy(const Arg *dummy)
|
clipcopy(const Arg *dummy)
|
||||||
{
|
{
|
||||||
@@ -279,17 +193,24 @@ clippaste(const Arg *dummy)
|
|||||||
xw.win, CurrentTime);
|
xw.win, CurrentTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
numlock(const Arg *dummy)
|
||||||
|
{
|
||||||
|
win.mode ^= MODE_NUMLOCK;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
selpaste(const Arg *dummy)
|
selpaste(const Arg *dummy)
|
||||||
{
|
{
|
||||||
|
|
||||||
XConvertSelection(xw.dpy, XA_PRIMARY, xsel.xtarget, XA_PRIMARY,
|
XConvertSelection(xw.dpy, XA_PRIMARY, xsel.xtarget, XA_PRIMARY,
|
||||||
xw.win, CurrentTime);
|
xw.win, CurrentTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
numlock(const Arg *dummy)
|
ttysend(const Arg *arg)
|
||||||
{
|
{
|
||||||
win.mode ^= MODE_NUMLOCK;
|
ttywrite(arg->s, strlen(arg->s), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -298,14 +219,31 @@ zoom(const Arg *arg)
|
|||||||
Arg larg;
|
Arg larg;
|
||||||
|
|
||||||
larg.f = usedfontsize + arg->f;
|
larg.f = usedfontsize + arg->f;
|
||||||
zoomabs(&larg);
|
if (larg.f >= 1.0)
|
||||||
|
zoomabs(&larg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
zoomabs(const Arg *arg)
|
zoomabs(const Arg *arg)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
ImageList *im;
|
||||||
|
|
||||||
xunloadfonts();
|
xunloadfonts();
|
||||||
xloadfonts(usedfont, arg->f);
|
xloadfonts(usedfont, arg->f);
|
||||||
|
|
||||||
|
/* delete old pixmaps so that xfinishdraw() can create new scaled ones */
|
||||||
|
for (im = term.images, i = 0; i < 2; i++, im = term.images_alt) {
|
||||||
|
for (; 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();
|
||||||
@@ -322,12 +260,6 @@ zoomreset(const Arg *arg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
ttysend(const Arg *arg)
|
|
||||||
{
|
|
||||||
ttywrite(arg->s, strlen(arg->s), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
evcol(XEvent *e)
|
evcol(XEvent *e)
|
||||||
{
|
{
|
||||||
@@ -344,6 +276,40 @@ evrow(XEvent *e)
|
|||||||
return y / win.ch;
|
return y / win.ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint
|
||||||
|
buttonmask(uint button)
|
||||||
|
{
|
||||||
|
return button == Button1 ? Button1Mask
|
||||||
|
: button == Button2 ? Button2Mask
|
||||||
|
: button == Button3 ? Button3Mask
|
||||||
|
: button == Button4 ? Button4Mask
|
||||||
|
: button == Button5 ? Button5Mask
|
||||||
|
: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
mouseaction(XEvent *e, uint release)
|
||||||
|
{
|
||||||
|
MouseShortcut *ms;
|
||||||
|
int screen = tisaltscr() ? S_ALT : S_PRI;
|
||||||
|
|
||||||
|
/* ignore Button<N>mask for Button<N> - it's set on release */
|
||||||
|
uint state = e->xbutton.state & ~buttonmask(e->xbutton.button);
|
||||||
|
|
||||||
|
for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) {
|
||||||
|
if (ms->release == release &&
|
||||||
|
ms->button == e->xbutton.button &&
|
||||||
|
(!ms->screen || (ms->screen == screen)) &&
|
||||||
|
(match(ms->mod, state) || /* exact or forced */
|
||||||
|
match(ms->mod, state & ~forcemousemod))) {
|
||||||
|
ms->func(&(ms->arg));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
mousesel(XEvent *e, int done)
|
mousesel(XEvent *e, int done)
|
||||||
{
|
{
|
||||||
@@ -378,6 +344,7 @@ mousereport(XEvent *e)
|
|||||||
/* MODE_MOUSEMOTION: no reporting if no button is pressed */
|
/* MODE_MOUSEMOTION: no reporting if no button is pressed */
|
||||||
if (IS_SET(MODE_MOUSEMOTION) && buttons == 0)
|
if (IS_SET(MODE_MOUSEMOTION) && buttons == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Set btn to lowest-numbered pressed button, or 12 if no
|
/* Set btn to lowest-numbered pressed button, or 12 if no
|
||||||
* buttons are pressed. */
|
* buttons are pressed. */
|
||||||
for (btn = 1; btn <= 11 && !(buttons & (1<<(btn-1))); btn++)
|
for (btn = 1; btn <= 11 && !(buttons & (1<<(btn-1))); btn++)
|
||||||
@@ -433,38 +400,6 @@ mousereport(XEvent *e)
|
|||||||
ttywrite(buf, len, 0);
|
ttywrite(buf, len, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint
|
|
||||||
buttonmask(uint button)
|
|
||||||
{
|
|
||||||
return button == Button1 ? Button1Mask
|
|
||||||
: button == Button2 ? Button2Mask
|
|
||||||
: button == Button3 ? Button3Mask
|
|
||||||
: button == Button4 ? Button4Mask
|
|
||||||
: button == Button5 ? Button5Mask
|
|
||||||
: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
mouseaction(XEvent *e, uint release)
|
|
||||||
{
|
|
||||||
MouseShortcut *ms;
|
|
||||||
|
|
||||||
/* ignore Button<N>mask for Button<N> - it's set on release */
|
|
||||||
uint state = e->xbutton.state & ~buttonmask(e->xbutton.button);
|
|
||||||
|
|
||||||
for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) {
|
|
||||||
if (ms->release == release &&
|
|
||||||
ms->button == e->xbutton.button &&
|
|
||||||
(match(ms->mod, state) || /* exact or forced */
|
|
||||||
match(ms->mod, state & ~forcemousemod))) {
|
|
||||||
ms->func(&(ms->arg));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
bpress(XEvent *e)
|
bpress(XEvent *e)
|
||||||
{
|
{
|
||||||
@@ -500,6 +435,7 @@ bpress(XEvent *e)
|
|||||||
xsel.tclick1 = now;
|
xsel.tclick1 = now;
|
||||||
|
|
||||||
selstart(evcol(e), evrow(e), snap);
|
selstart(evcol(e), evrow(e), snap);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -515,6 +451,7 @@ propnotify(XEvent *e)
|
|||||||
xpev->atom == clipboard)) {
|
xpev->atom == clipboard)) {
|
||||||
selnotify(e);
|
selnotify(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -545,7 +482,8 @@ selnotify(XEvent *e)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e->type == PropertyNotify && nitems == 0 && rem == 0) {
|
if (e->type == PropertyNotify && nitems == 0 && rem == 0)
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* If there is some PropertyNotify with no data, then
|
* If there is some PropertyNotify with no data, then
|
||||||
* this is the signal of the selection owner that all
|
* this is the signal of the selection owner that all
|
||||||
@@ -686,6 +624,7 @@ setsel(char *str, Time t)
|
|||||||
XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t);
|
XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t);
|
||||||
if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win)
|
if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win)
|
||||||
selclear();
|
selclear();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -709,13 +648,17 @@ brelease(XEvent *e)
|
|||||||
|
|
||||||
if (mouseaction(e, 1))
|
if (mouseaction(e, 1))
|
||||||
return;
|
return;
|
||||||
if (btn == Button1)
|
|
||||||
|
if (btn == Button1) {
|
||||||
mousesel(e, 1);
|
mousesel(e, 1);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
bmotion(XEvent *e)
|
bmotion(XEvent *e)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) {
|
if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) {
|
||||||
mousereport(e);
|
mousereport(e);
|
||||||
return;
|
return;
|
||||||
@@ -736,7 +679,7 @@ cresize(int width, int height)
|
|||||||
|
|
||||||
col = (win.w - 2 * borderpx) / win.cw;
|
col = (win.w - 2 * borderpx) / win.cw;
|
||||||
row = (win.h - 2 * borderpx) / win.ch;
|
row = (win.h - 2 * borderpx) / win.ch;
|
||||||
col = MAX(1, col);
|
col = MAX(2, col);
|
||||||
row = MAX(1, row);
|
row = MAX(1, row);
|
||||||
|
|
||||||
tresize(col, row);
|
tresize(col, row);
|
||||||
@@ -752,7 +695,8 @@ xresize(int col, int row)
|
|||||||
|
|
||||||
XFreePixmap(xw.dpy, xw.buf);
|
XFreePixmap(xw.dpy, xw.buf);
|
||||||
xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
|
xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
|
||||||
DefaultDepth(xw.dpy, xw.scr));
|
DefaultDepth(xw.dpy, xw.scr)
|
||||||
|
);
|
||||||
XftDrawChange(xw.draw, xw.buf);
|
XftDrawChange(xw.draw, xw.buf);
|
||||||
xclear(0, 0, win.w, win.h);
|
xclear(0, 0, win.w, win.h);
|
||||||
|
|
||||||
@@ -856,6 +800,12 @@ xclear(int x1, int y1, int x2, int y2)
|
|||||||
x1, y1, x2-x1, y2-y1);
|
x1, y1, x2-x1, y2-y1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xclearwin(void)
|
||||||
|
{
|
||||||
|
xclear(0, 0, win.w, win.h);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
xhints(void)
|
xhints(void)
|
||||||
{
|
{
|
||||||
@@ -907,6 +857,60 @@ xgeommasktogravity(int mask)
|
|||||||
return SouthEastGravity;
|
return SouthEastGravity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ximopen(Display *dpy)
|
||||||
|
{
|
||||||
|
XIMCallback imdestroy = { .client_data = NULL, .callback = ximdestroy };
|
||||||
|
XICCallback icdestroy = { .client_data = NULL, .callback = xicdestroy };
|
||||||
|
|
||||||
|
xw.ime.xim = XOpenIM(xw.dpy, NULL, NULL, NULL);
|
||||||
|
if (xw.ime.xim == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (XSetIMValues(xw.ime.xim, XNDestroyCallback, &imdestroy, NULL))
|
||||||
|
fprintf(stderr, "XSetIMValues: "
|
||||||
|
"Could not set XNDestroyCallback.\n");
|
||||||
|
|
||||||
|
xw.ime.spotlist = XVaCreateNestedList(0, XNSpotLocation, &xw.ime.spot,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (xw.ime.xic == NULL) {
|
||||||
|
xw.ime.xic = XCreateIC(xw.ime.xim, XNInputStyle,
|
||||||
|
XIMPreeditNothing | XIMStatusNothing,
|
||||||
|
XNClientWindow, xw.win,
|
||||||
|
XNDestroyCallback, &icdestroy,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
if (xw.ime.xic == NULL)
|
||||||
|
fprintf(stderr, "XCreateIC: Could not create input context.\n");
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ximinstantiate(Display *dpy, XPointer client, XPointer call)
|
||||||
|
{
|
||||||
|
if (ximopen(dpy))
|
||||||
|
XUnregisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL,
|
||||||
|
ximinstantiate, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ximdestroy(XIM xim, XPointer client, XPointer call)
|
||||||
|
{
|
||||||
|
xw.ime.xim = NULL;
|
||||||
|
XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL,
|
||||||
|
ximinstantiate, NULL);
|
||||||
|
XFree(xw.ime.spotlist);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
xicdestroy(XIC xim, XPointer client, XPointer call)
|
||||||
|
{
|
||||||
|
xw.ime.xic = NULL;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
xloadfont(Font *f, FcPattern *pattern)
|
xloadfont(Font *f, FcPattern *pattern)
|
||||||
{
|
{
|
||||||
@@ -1062,6 +1066,7 @@ xunloadfont(Font *f)
|
|||||||
void
|
void
|
||||||
xunloadfonts(void)
|
xunloadfonts(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
/* Free the loaded fonts in the font cache. */
|
/* Free the loaded fonts in the font cache. */
|
||||||
while (frclen > 0)
|
while (frclen > 0)
|
||||||
XftFontClose(xw.dpy, frc[--frclen].font);
|
XftFontClose(xw.dpy, frc[--frclen].font);
|
||||||
@@ -1072,60 +1077,6 @@ xunloadfonts(void)
|
|||||||
xunloadfont(&dc.ibfont);
|
xunloadfont(&dc.ibfont);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
|
||||||
ximopen(Display *dpy)
|
|
||||||
{
|
|
||||||
XIMCallback imdestroy = { .client_data = NULL, .callback = ximdestroy };
|
|
||||||
XICCallback icdestroy = { .client_data = NULL, .callback = xicdestroy };
|
|
||||||
|
|
||||||
xw.ime.xim = XOpenIM(xw.dpy, NULL, NULL, NULL);
|
|
||||||
if (xw.ime.xim == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (XSetIMValues(xw.ime.xim, XNDestroyCallback, &imdestroy, NULL))
|
|
||||||
fprintf(stderr, "XSetIMValues: "
|
|
||||||
"Could not set XNDestroyCallback.\n");
|
|
||||||
|
|
||||||
xw.ime.spotlist = XVaCreateNestedList(0, XNSpotLocation, &xw.ime.spot,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
if (xw.ime.xic == NULL) {
|
|
||||||
xw.ime.xic = XCreateIC(xw.ime.xim, XNInputStyle,
|
|
||||||
XIMPreeditNothing | XIMStatusNothing,
|
|
||||||
XNClientWindow, xw.win,
|
|
||||||
XNDestroyCallback, &icdestroy,
|
|
||||||
NULL);
|
|
||||||
}
|
|
||||||
if (xw.ime.xic == NULL)
|
|
||||||
fprintf(stderr, "XCreateIC: Could not create input context.\n");
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ximinstantiate(Display *dpy, XPointer client, XPointer call)
|
|
||||||
{
|
|
||||||
if (ximopen(dpy))
|
|
||||||
XUnregisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL,
|
|
||||||
ximinstantiate, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ximdestroy(XIM xim, XPointer client, XPointer call)
|
|
||||||
{
|
|
||||||
xw.ime.xim = NULL;
|
|
||||||
XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL,
|
|
||||||
ximinstantiate, NULL);
|
|
||||||
XFree(xw.ime.spotlist);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
xicdestroy(XIC xim, XPointer client, XPointer call)
|
|
||||||
{
|
|
||||||
xw.ime.xic = NULL;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
xinit(int cols, int rows)
|
xinit(int cols, int rows)
|
||||||
{
|
{
|
||||||
@@ -1138,6 +1089,7 @@ xinit(int cols, int rows)
|
|||||||
if (!(xw.dpy = XOpenDisplay(NULL)))
|
if (!(xw.dpy = XOpenDisplay(NULL)))
|
||||||
die("can't open display\n");
|
die("can't open display\n");
|
||||||
xw.scr = XDefaultScreen(xw.dpy);
|
xw.scr = XDefaultScreen(xw.dpy);
|
||||||
|
|
||||||
xw.vis = XDefaultVisual(xw.dpy, xw.scr);
|
xw.vis = XDefaultVisual(xw.dpy, xw.scr);
|
||||||
|
|
||||||
/* font */
|
/* font */
|
||||||
@@ -1165,7 +1117,8 @@ xinit(int cols, int rows)
|
|||||||
xw.attrs.bit_gravity = NorthWestGravity;
|
xw.attrs.bit_gravity = NorthWestGravity;
|
||||||
xw.attrs.event_mask = FocusChangeMask | KeyPressMask | KeyReleaseMask
|
xw.attrs.event_mask = FocusChangeMask | KeyPressMask | KeyReleaseMask
|
||||||
| ExposureMask | VisibilityChangeMask | StructureNotifyMask
|
| ExposureMask | VisibilityChangeMask | StructureNotifyMask
|
||||||
| ButtonMotionMask | ButtonPressMask | ButtonReleaseMask;
|
| ButtonMotionMask | ButtonPressMask | ButtonReleaseMask
|
||||||
|
;
|
||||||
xw.attrs.colormap = xw.cmap;
|
xw.attrs.colormap = xw.cmap;
|
||||||
|
|
||||||
root = XRootWindow(xw.dpy, xw.scr);
|
root = XRootWindow(xw.dpy, xw.scr);
|
||||||
@@ -1180,6 +1133,7 @@ xinit(int cols, int rows)
|
|||||||
|
|
||||||
memset(&gcvalues, 0, sizeof(gcvalues));
|
memset(&gcvalues, 0, sizeof(gcvalues));
|
||||||
gcvalues.graphics_exposures = False;
|
gcvalues.graphics_exposures = False;
|
||||||
|
|
||||||
dc.gc = XCreateGC(xw.dpy, xw.win, GCGraphicsExposures,
|
dc.gc = XCreateGC(xw.dpy, xw.win, GCGraphicsExposures,
|
||||||
&gcvalues);
|
&gcvalues);
|
||||||
xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
|
xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
|
||||||
@@ -1196,7 +1150,7 @@ xinit(int cols, int rows)
|
|||||||
/* input methods */
|
/* input methods */
|
||||||
if (!ximopen(xw.dpy)) {
|
if (!ximopen(xw.dpy)) {
|
||||||
XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL,
|
XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL,
|
||||||
ximinstantiate, NULL);
|
ximinstantiate, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* white cursor, black outline */
|
/* white cursor, black outline */
|
||||||
@@ -1240,6 +1194,7 @@ xinit(int cols, int rows)
|
|||||||
xsel.xtarget = XInternAtom(xw.dpy, "UTF8_STRING", 0);
|
xsel.xtarget = XInternAtom(xw.dpy, "UTF8_STRING", 0);
|
||||||
if (xsel.xtarget == None)
|
if (xsel.xtarget == None)
|
||||||
xsel.xtarget = XA_STRING;
|
xsel.xtarget = XA_STRING;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -1249,7 +1204,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
|
|||||||
ushort mode, prevmode = USHRT_MAX;
|
ushort mode, prevmode = USHRT_MAX;
|
||||||
Font *font = &dc.font;
|
Font *font = &dc.font;
|
||||||
int frcflags = FRC_NORMAL;
|
int frcflags = FRC_NORMAL;
|
||||||
float runewidth = win.cw;
|
float runewidth = win.cw * ((glyphs[0].mode & ATTR_WIDE) ? 2.0f : 1.0f);
|
||||||
Rune rune;
|
Rune rune;
|
||||||
FT_UInt glyphidx;
|
FT_UInt glyphidx;
|
||||||
FcResult fcres;
|
FcResult fcres;
|
||||||
@@ -1258,7 +1213,8 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
|
|||||||
FcCharSet *fccharset;
|
FcCharSet *fccharset;
|
||||||
int i, f, numspecs = 0;
|
int i, f, numspecs = 0;
|
||||||
|
|
||||||
for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) {
|
for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i)
|
||||||
|
{
|
||||||
/* Fetch rune and mode for current glyph. */
|
/* Fetch rune and mode for current glyph. */
|
||||||
rune = glyphs[i].u;
|
rune = glyphs[i].u;
|
||||||
mode = glyphs[i].mode;
|
mode = glyphs[i].mode;
|
||||||
@@ -1314,8 +1270,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
|
|||||||
/* Nothing was found. Use fontconfig to find matching font. */
|
/* Nothing was found. Use fontconfig to find matching font. */
|
||||||
if (f >= frclen) {
|
if (f >= frclen) {
|
||||||
if (!font->set)
|
if (!font->set)
|
||||||
font->set = FcFontSort(0, font->pattern,
|
font->set = FcFontSort(0, font->pattern, 1, 0, &fcres);
|
||||||
1, 0, &fcres);
|
|
||||||
fcsets[0] = font->set;
|
fcsets[0] = font->set;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1329,16 +1284,13 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
|
|||||||
fccharset = FcCharSetCreate();
|
fccharset = FcCharSetCreate();
|
||||||
|
|
||||||
FcCharSetAddChar(fccharset, rune);
|
FcCharSetAddChar(fccharset, rune);
|
||||||
FcPatternAddCharSet(fcpattern, FC_CHARSET,
|
FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
|
||||||
fccharset);
|
|
||||||
FcPatternAddBool(fcpattern, FC_SCALABLE, 1);
|
FcPatternAddBool(fcpattern, FC_SCALABLE, 1);
|
||||||
|
|
||||||
FcConfigSubstitute(0, fcpattern,
|
FcConfigSubstitute(0, fcpattern, FcMatchPattern);
|
||||||
FcMatchPattern);
|
|
||||||
FcDefaultSubstitute(fcpattern);
|
FcDefaultSubstitute(fcpattern);
|
||||||
|
|
||||||
fontpattern = FcFontSetMatch(0, fcsets, 1,
|
fontpattern = FcFontSetMatch(0, fcsets, 1, fcpattern, &fcres);
|
||||||
fcpattern, &fcres);
|
|
||||||
|
|
||||||
/* Allocate memory for the new cache entry. */
|
/* Allocate memory for the new cache entry. */
|
||||||
if (frclen >= frccap) {
|
if (frclen >= frccap) {
|
||||||
@@ -1346,8 +1298,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
|
|||||||
frc = xrealloc(frc, frccap * sizeof(Fontcache));
|
frc = xrealloc(frc, frccap * sizeof(Fontcache));
|
||||||
}
|
}
|
||||||
|
|
||||||
frc[frclen].font = XftFontOpenPattern(xw.dpy,
|
frc[frclen].font = XftFontOpenPattern(xw.dpy, fontpattern);
|
||||||
fontpattern);
|
|
||||||
if (!frc[frclen].font)
|
if (!frc[frclen].font)
|
||||||
die("XftFontOpenPattern failed seeking fallback font: %s\n",
|
die("XftFontOpenPattern failed seeking fallback font: %s\n",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
@@ -1375,11 +1326,11 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y)
|
xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y
|
||||||
{
|
) {
|
||||||
int charlen = len * ((base.mode & ATTR_WIDE) ? 2 : 1);
|
int charlen = len * ((base.mode & ATTR_WIDE) ? 2 : 1);
|
||||||
int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch,
|
int width = charlen * win.cw;
|
||||||
width = charlen * win.cw;
|
int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch;
|
||||||
Color *fg, *bg, *temp, revfg, revbg, truefg, truebg;
|
Color *fg, *bg, *temp, revfg, revbg, truefg, truebg;
|
||||||
XRenderColor colfg, colbg;
|
XRenderColor colfg, colbg;
|
||||||
XRectangle r;
|
XRectangle r;
|
||||||
@@ -1482,6 +1433,7 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
|
|||||||
xclear(winx, winy + win.ch, winx + width, win.h);
|
xclear(winx, winy + win.ch, winx + width, win.h);
|
||||||
|
|
||||||
/* Clean up the region we want to draw to. */
|
/* Clean up the region we want to draw to. */
|
||||||
|
|
||||||
XftDrawRect(xw.draw, bg, winx, winy, width, win.ch);
|
XftDrawRect(xw.draw, bg, winx, winy, width, win.ch);
|
||||||
|
|
||||||
/* Set the clip region because Xft is sometimes dirty. */
|
/* Set the clip region because Xft is sometimes dirty. */
|
||||||
@@ -1513,10 +1465,11 @@ void
|
|||||||
xdrawglyph(Glyph g, int x, int y)
|
xdrawglyph(Glyph g, int x, int y)
|
||||||
{
|
{
|
||||||
int numspecs;
|
int numspecs;
|
||||||
XftGlyphFontSpec spec;
|
XftGlyphFontSpec *specs = xw.specbuf;
|
||||||
|
|
||||||
numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y);
|
numspecs = xmakeglyphfontspecs(specs, &g, 1, x, y);
|
||||||
xdrawglyphfontspecs(&spec, g, numspecs, x, y);
|
xdrawglyphfontspecs(specs, g, numspecs, x, y
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -1527,6 +1480,7 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
|
|||||||
/* remove the old cursor */
|
/* remove the old cursor */
|
||||||
if (selected(ox, oy))
|
if (selected(ox, oy))
|
||||||
og.mode ^= ATTR_REVERSE;
|
og.mode ^= ATTR_REVERSE;
|
||||||
|
|
||||||
xdrawglyph(og, ox, oy);
|
xdrawglyph(og, ox, oy);
|
||||||
|
|
||||||
if (IS_SET(MODE_HIDE))
|
if (IS_SET(MODE_HIDE))
|
||||||
@@ -1535,7 +1489,8 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
|
|||||||
/*
|
/*
|
||||||
* Select the right color for the right mode.
|
* Select the right color for the right mode.
|
||||||
*/
|
*/
|
||||||
g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE;
|
g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE
|
||||||
|
;
|
||||||
|
|
||||||
if (IS_SET(MODE_REVERSE)) {
|
if (IS_SET(MODE_REVERSE)) {
|
||||||
g.mode |= ATTR_REVERSE;
|
g.mode |= ATTR_REVERSE;
|
||||||
@@ -1555,6 +1510,7 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
|
|||||||
g.fg = defaultbg;
|
g.fg = defaultbg;
|
||||||
g.bg = defaultcs;
|
g.bg = defaultcs;
|
||||||
}
|
}
|
||||||
|
|
||||||
drawcol = dc.col[g.bg];
|
drawcol = dc.col[g.bg];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1564,13 +1520,13 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
|
|||||||
case 7: /* st extension */
|
case 7: /* st extension */
|
||||||
g.u = 0x2603; /* snowman (U+2603) */
|
g.u = 0x2603; /* snowman (U+2603) */
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
case 0: /* Blinking Block */
|
case 0: /* Blinking block */
|
||||||
case 1: /* Blinking Block (Default) */
|
case 1: /* Blinking block (default) */
|
||||||
case 2: /* Steady Block */
|
case 2: /* Steady block */
|
||||||
xdrawglyph(g, cx, cy);
|
xdrawglyph(g, cx, cy);
|
||||||
break;
|
break;
|
||||||
case 3: /* Blinking Underline */
|
case 3: /* Blinking underline */
|
||||||
case 4: /* Steady Underline */
|
case 4: /* Steady underline */
|
||||||
XftDrawRect(xw.draw, &drawcol,
|
XftDrawRect(xw.draw, &drawcol,
|
||||||
borderpx + cx * win.cw,
|
borderpx + cx * win.cw,
|
||||||
borderpx + (cy + 1) * win.ch - \
|
borderpx + (cy + 1) * win.ch - \
|
||||||
@@ -1624,7 +1580,7 @@ xseticontitle(char *p)
|
|||||||
p = opt_title;
|
p = opt_title;
|
||||||
|
|
||||||
if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
|
if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
|
||||||
&prop) != Success)
|
&prop) != Success)
|
||||||
return;
|
return;
|
||||||
XSetWMIconName(xw.dpy, xw.win, &prop);
|
XSetWMIconName(xw.dpy, xw.win, &prop);
|
||||||
XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmiconname);
|
XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmiconname);
|
||||||
@@ -1641,7 +1597,7 @@ xsettitle(char *p)
|
|||||||
p = opt_title;
|
p = opt_title;
|
||||||
|
|
||||||
if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
|
if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
|
||||||
&prop) != Success)
|
&prop) != Success)
|
||||||
return;
|
return;
|
||||||
XSetWMName(xw.dpy, xw.win, &prop);
|
XSetWMName(xw.dpy, xw.win, &prop);
|
||||||
XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmname);
|
XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmname);
|
||||||
@@ -1659,6 +1615,7 @@ xdrawline(Line line, int x1, int y1, int x2)
|
|||||||
{
|
{
|
||||||
int i, x, ox, numspecs;
|
int i, x, ox, numspecs;
|
||||||
Glyph base, new;
|
Glyph base, new;
|
||||||
|
|
||||||
XftGlyphFontSpec *specs = xw.specbuf;
|
XftGlyphFontSpec *specs = xw.specbuf;
|
||||||
|
|
||||||
numspecs = xmakeglyphfontspecs(specs, &line[x1], x2 - x1, x1, y1);
|
numspecs = xmakeglyphfontspecs(specs, &line[x1], x2 - x1, x1, y1);
|
||||||
@@ -1683,16 +1640,132 @@ xdrawline(Line line, int x1, int y1, int x2)
|
|||||||
}
|
}
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
xdrawglyphfontspecs(specs, base, i, ox, y1);
|
xdrawglyphfontspecs(specs, base, i, ox, y1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
xfinishdraw(void)
|
xfinishdraw(void)
|
||||||
{
|
{
|
||||||
XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, win.w,
|
ImageList *im, *next;
|
||||||
win.h, 0, 0);
|
Imlib_Image origin, scaled;
|
||||||
XSetForeground(xw.dpy, dc.gc,
|
XGCValues gcvalues;
|
||||||
dc.col[IS_SET(MODE_REVERSE)?
|
GC gc = NULL;
|
||||||
defaultfg : defaultbg].pixel);
|
int width, height;
|
||||||
|
int del, desty, mode, x1, x2, xend;
|
||||||
|
int bw = borderpx, bh = borderpx;
|
||||||
|
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,
|
||||||
|
DefaultDepth(xw.dpy, xw.scr)
|
||||||
|
);
|
||||||
|
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 = 24
|
||||||
|
};
|
||||||
|
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 = 24
|
||||||
|
};
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create GC */
|
||||||
|
if (!gc) {
|
||||||
|
memset(&gcvalues, 0, sizeof(gcvalues));
|
||||||
|
gcvalues.graphics_exposures = False;
|
||||||
|
gc = XCreateGC(xw.dpy, xw.win, GCGraphicsExposures, &gcvalues);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set the clip mask */
|
||||||
|
desty = bh + im->y * win.ch;
|
||||||
|
if (im->clipmask) {
|
||||||
|
XSetClipMask(xw.dpy, gc, (Drawable)im->clipmask);
|
||||||
|
XSetClipOrigin(xw.dpy, gc, bw + im->x * win.cw, desty);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* draw only the parts of the image that are not erased */
|
||||||
|
line = term.line[im->y] + im->x;
|
||||||
|
xend = MIN(im->x + im->cols, term.col);
|
||||||
|
for (del = 1, x1 = im->x; x1 < xend; x1 = x2) {
|
||||||
|
mode = line->mode & ATTR_SIXEL;
|
||||||
|
for (x2 = x1 + 1; x2 < xend; x2++) {
|
||||||
|
if (((++line)->mode & ATTR_SIXEL) != mode)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (mode) {
|
||||||
|
XCopyArea(xw.dpy, (Drawable)im->pixmap, xw.buf, gc,
|
||||||
|
(x1 - im->x) * win.cw, 0,
|
||||||
|
MIN((x2 - x1) * win.cw, width - (x1 - im->x) * win.cw), height,
|
||||||
|
bw + x1 * win.cw, desty);
|
||||||
|
del = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (im->clipmask)
|
||||||
|
XSetClipMask(xw.dpy, gc, None);
|
||||||
|
|
||||||
|
/* if all the parts are erased, we can delete the entire image */
|
||||||
|
if (del && im->x + im->cols <= term.col)
|
||||||
|
delete_image(im);
|
||||||
|
}
|
||||||
|
if (gc)
|
||||||
|
XFreeGC(xw.dpy, gc);
|
||||||
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -1844,7 +1917,7 @@ kpress(XEvent *ev)
|
|||||||
XKeyEvent *e = &ev->xkey;
|
XKeyEvent *e = &ev->xkey;
|
||||||
KeySym ksym = NoSymbol;
|
KeySym ksym = NoSymbol;
|
||||||
char buf[64], *customkey;
|
char buf[64], *customkey;
|
||||||
int len;
|
int len, screen;
|
||||||
Rune c;
|
Rune c;
|
||||||
Status status;
|
Status status;
|
||||||
Shortcut *bp;
|
Shortcut *bp;
|
||||||
@@ -1859,9 +1932,13 @@ kpress(XEvent *ev)
|
|||||||
} else {
|
} else {
|
||||||
len = XLookupString(e, buf, sizeof buf, &ksym, NULL);
|
len = XLookupString(e, buf, sizeof buf, &ksym, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
screen = tisaltscr() ? S_ALT : S_PRI;
|
||||||
|
|
||||||
/* 1. shortcuts */
|
/* 1. shortcuts */
|
||||||
for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
|
for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
|
||||||
if (ksym == bp->keysym && match(bp->mod, e->state)) {
|
if (ksym == bp->keysym && match(bp->mod, e->state) &&
|
||||||
|
(!bp->screen || bp->screen == screen)) {
|
||||||
bp->func(&(bp->arg));
|
bp->func(&(bp->arg));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1914,6 +1991,7 @@ cmessage(XEvent *e)
|
|||||||
void
|
void
|
||||||
resize(XEvent *e)
|
resize(XEvent *e)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (e->xconfigure.width == win.w && e->xconfigure.height == win.h)
|
if (e->xconfigure.width == win.w && e->xconfigure.height == win.h)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -1992,7 +2070,8 @@ run(void)
|
|||||||
* maximum latency intervals during `cat huge.txt`, and perfect
|
* maximum latency intervals during `cat huge.txt`, and perfect
|
||||||
* sync with periodic updates from animations/key-repeats/etc.
|
* sync with periodic updates from animations/key-repeats/etc.
|
||||||
*/
|
*/
|
||||||
if (FD_ISSET(ttyfd, &rfd) || xev) {
|
if (FD_ISSET(ttyfd, &rfd) || xev)
|
||||||
|
{
|
||||||
if (!drawing) {
|
if (!drawing) {
|
||||||
trigger = now;
|
trigger = now;
|
||||||
drawing = 1;
|
drawing = 1;
|
||||||
@@ -2005,7 +2084,8 @@ run(void)
|
|||||||
|
|
||||||
/* idle detected or maxlatency exhausted -> draw */
|
/* idle detected or maxlatency exhausted -> draw */
|
||||||
timeout = -1;
|
timeout = -1;
|
||||||
if (blinktimeout && tattrset(ATTR_BLINK)) {
|
if (blinktimeout && tattrset(ATTR_BLINK))
|
||||||
|
{
|
||||||
timeout = blinktimeout - TIMEDIFF(now, lastblink);
|
timeout = blinktimeout - TIMEDIFF(now, lastblink);
|
||||||
if (timeout <= 0) {
|
if (timeout <= 0) {
|
||||||
if (-timeout > blinktimeout) /* start visible */
|
if (-timeout > blinktimeout) /* start visible */
|
||||||
@@ -2026,14 +2106,16 @@ run(void)
|
|||||||
void
|
void
|
||||||
usage(void)
|
usage(void)
|
||||||
{
|
{
|
||||||
die("usage: %s [-aiv] [-c class] [-f font] [-g geometry]"
|
die("usage: %s [-aiv] [-c class]"
|
||||||
" [-n name] [-o file]\n"
|
" [-f font] [-g geometry]"
|
||||||
" [-T title] [-t title] [-w windowid]"
|
" [-n name] [-o file]\n"
|
||||||
" [[-e] command [args ...]]\n"
|
" [-T title] [-t title] [-w windowid]"
|
||||||
" %s [-aiv] [-c class] [-f font] [-g geometry]"
|
" [[-e] command [args ...]]\n"
|
||||||
" [-n name] [-o file]\n"
|
" %s [-aiv] [-c class]"
|
||||||
" [-T title] [-t title] [-w windowid] -l line"
|
" [-f font] [-g geometry]"
|
||||||
" [stty_args ...]\n", argv0, argv0);
|
" [-n name] [-o file]\n"
|
||||||
|
" [-T title] [-t title] [-w windowid] -l line"
|
||||||
|
" [stty_args ...]\n", argv0, argv0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -2096,6 +2178,7 @@ run:
|
|||||||
|
|
||||||
setlocale(LC_CTYPE, "");
|
setlocale(LC_CTYPE, "");
|
||||||
XSetLocaleModifiers("");
|
XSetLocaleModifiers("");
|
||||||
|
|
||||||
cols = MAX(cols, 1);
|
cols = MAX(cols, 1);
|
||||||
rows = MAX(rows, 1);
|
rows = MAX(rows, 1);
|
||||||
tnew(cols, rows);
|
tnew(cols, rows);
|
||||||
|
Reference in New Issue
Block a user