Compare commits

..

9 Commits

Author SHA1 Message Date
9e7f107c1f Added undercurl v0.8.4 patch 2023-06-27 22:36:11 +02:00
0749fc4857 Added title-parsing-fix v0.8.5 patch (#10)
Reviewed-on: #10
2023-06-27 22:35:52 +02:00
539dfd0bac Added appsync part2 v2020-06-18 patch (#9)
Reviewed-on: #9
2023-06-27 22:35:14 +02:00
af62c87aa8 Added gruvbox-dark v0.8.5 patch (#8)
Reviewed-on: #8
2023-06-27 22:31:59 +02:00
aa9d16a41b Added dynamic-cursor-color v0.9 patch (#7)
Reviewed-on: #7
2023-06-27 22:31:10 +02:00
71d1f725b3 feat/clipboard (#6)
Reviewed-on: #6
2023-06-27 22:30:31 +02:00
fb7383d52f Added bold-is-not-bright v2019-01-27 patch (#3)
Reviewed-on: #3
2023-06-27 21:59:07 +02:00
3a32e68b82 Added anysize v.2022-07-18 patch (#2)
Reviewed-on: #2
2023-06-27 21:57:51 +02:00
a8d62fe07b Added alpha patch v0.8.5 (#1)
Reviewed-on: #1
2023-06-27 21:56:48 +02:00
6 changed files with 194 additions and 94 deletions

View File

@ -56,6 +56,12 @@ int allowwindowops = 0;
static double minlatency = 8; static double minlatency = 8;
static double maxlatency = 33; static double maxlatency = 33;
/*
* Synchronized-Update timeout in ms
* https://gitlab.com/gnachman/iterm2/-/wikis/synchronized-updates-spec
*/
static uint su_timeout = 200;
/* /*
* blinking timeout (set to 0 to disable blinking) for the terminal blinking * blinking timeout (set to 0 to disable blinking) for the terminal blinking
* attribute. * attribute.
@ -93,35 +99,30 @@ char *termname = "st-256color";
*/ */
unsigned int tabspaces = 8; unsigned int tabspaces = 8;
/* bg opacity */
float alpha = 0.8;
/* Terminal colors (16 first used in escape sequence) */ /* Terminal colors (16 first used in escape sequence) */
static const char *colorname[] = { static const char *colorname[] = {
/* 8 normal colors */ /* 8 normal colors */
"black", [0] = "#282828", /* hard contrast: #1d2021 / soft contrast: #32302f */
"red3", [1] = "#cc241d", /* red */
"green3", [2] = "#98971a", /* green */
"yellow3", [3] = "#d79921", /* yellow */
"blue2", [4] = "#458588", /* blue */
"magenta3", [5] = "#b16286", /* magenta */
"cyan3", [6] = "#689d6a", /* cyan */
"gray90", [7] = "#a89984", /* white */
/* 8 bright colors */ /* 8 bright colors */
"gray50", [8] = "#928374", /* black */
"red", [9] = "#fb4934", /* red */
"green", [10] = "#b8bb26", /* green */
"yellow", [11] = "#fabd2f", /* yellow */
"#5c5cff", [12] = "#83a598", /* blue */
"magenta", [13] = "#d3869b", /* magenta */
"cyan", [14] = "#8ec07c", /* cyan */
"white", [15] = "#ebdbb2", /* white */
[255] = 0,
/* more colors can be added after 255 to use with DefaultXX */
"#cccccc",
"#555555",
"gray90", /* default foreground colour */
"black", /* default background colour */
}; };
@ -129,9 +130,9 @@ static const char *colorname[] = {
* Default colors (colorname index) * Default colors (colorname index)
* foreground, background, cursor, reverse cursor * foreground, background, cursor, reverse cursor
*/ */
unsigned int defaultfg = 258; unsigned int defaultfg = 15;
unsigned int defaultbg = 259; unsigned int defaultbg = 0;
unsigned int defaultcs = 256; unsigned int defaultcs = 15;
static unsigned int defaultrcs = 257; static unsigned int defaultrcs = 257;
/* /*

View File

@ -16,7 +16,7 @@ PKG_CONFIG = pkg-config
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 -lXrender\
`$(PKG_CONFIG) --libs fontconfig` \ `$(PKG_CONFIG) --libs fontconfig` \
`$(PKG_CONFIG) --libs freetype2` `$(PKG_CONFIG) --libs freetype2`

82
st.c
View File

@ -43,6 +43,8 @@
#define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f)) #define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f))
#define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c)) #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
#define ISDELIM(u) (u && wcschr(worddelimiters, u)) #define ISDELIM(u) (u && wcschr(worddelimiters, u))
#define STRESCARGREST(n) ((n) == 0 ? strescseq.buf : strescseq.argp[(n)-1] + 1)
#define STRESCARGJUST(n) (*(strescseq.argp[n]) = '\0', STRESCARGREST(n))
enum term_mode { enum term_mode {
MODE_WRAP = 1 << 0, MODE_WRAP = 1 << 0,
@ -150,7 +152,7 @@ typedef struct {
char *buf; /* allocated raw string */ char *buf; /* allocated raw string */
size_t siz; /* allocation size */ size_t siz; /* allocation size */
size_t len; /* raw string length */ size_t len; /* raw string length */
char *args[STR_ARG_SIZ]; char *argp[STR_ARG_SIZ]; /* pointers to the end of nth argument */
int narg; /* nb of args */ int narg; /* nb of args */
} STREscape; } STREscape;
@ -235,6 +237,33 @@ static const uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
static const Rune utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000}; static const Rune utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000};
static const Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF}; static const Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
#include <time.h>
static int su = 0;
struct timespec sutv;
static void
tsync_begin()
{
clock_gettime(CLOCK_MONOTONIC, &sutv);
su = 1;
}
static void
tsync_end()
{
su = 0;
}
int
tinsync(uint timeout)
{
struct timespec now;
if (su && !clock_gettime(CLOCK_MONOTONIC, &now)
&& TIMEDIFF(now, sutv) >= timeout)
su = 0;
return su;
}
ssize_t ssize_t
xwrite(int fd, const char *s, size_t len) xwrite(int fd, const char *s, size_t len)
{ {
@ -817,6 +846,9 @@ ttynew(const char *line, char *cmd, const char *out, char **args)
return cmdfd; return cmdfd;
} }
static int twrite_aborted = 0;
int ttyread_pending() { return twrite_aborted; }
size_t size_t
ttyread(void) ttyread(void)
{ {
@ -825,7 +857,7 @@ ttyread(void)
int ret, written; int ret, written;
/* append read bytes to unprocessed bytes */ /* append read bytes to unprocessed bytes */
ret = read(cmdfd, buf+buflen, LEN(buf)-buflen); ret = twrite_aborted ? 1 : read(cmdfd, buf+buflen, LEN(buf)-buflen);
switch (ret) { switch (ret) {
case 0: case 0:
@ -833,7 +865,7 @@ ttyread(void)
case -1: case -1:
die("couldn't read from shell: %s\n", strerror(errno)); die("couldn't read from shell: %s\n", strerror(errno));
default: default:
buflen += ret; buflen += twrite_aborted ? 0 : ret;
written = twrite(buf, buflen, 0); written = twrite(buf, buflen, 0);
buflen -= written; buflen -= written;
/* keep any incomplete UTF-8 byte sequence for the next call */ /* keep any incomplete UTF-8 byte sequence for the next call */
@ -993,6 +1025,7 @@ tsetdirtattr(int attr)
void void
tfulldirt(void) tfulldirt(void)
{ {
tsync_end();
tsetdirt(0, term.row-1); tsetdirt(0, term.row-1);
} }
@ -1928,29 +1961,30 @@ strhandle(void)
}; };
term.esc &= ~(ESC_STR_END|ESC_STR); term.esc &= ~(ESC_STR_END|ESC_STR);
strparse(); strescseq.buf[strescseq.len] = '\0';
par = (narg = strescseq.narg) ? atoi(strescseq.args[0]) : 0;
switch (strescseq.type) { switch (strescseq.type) {
case ']': /* OSC -- Operating System Command */ case ']': /* OSC -- Operating System Command */
strparse();
par = (narg = strescseq.narg) ? atoi(STRESCARGJUST(0)) : 0;
switch (par) { switch (par) {
case 0: case 0:
if (narg > 1) { if (narg > 1) {
xsettitle(strescseq.args[1]); xsettitle(STRESCARGREST(1));
xseticontitle(strescseq.args[1]); xseticontitle(STRESCARGREST(1));
} }
return; return;
case 1: case 1:
if (narg > 1) if (narg > 1)
xseticontitle(strescseq.args[1]); xseticontitle(STRESCARGREST(1));
return; return;
case 2: case 2:
if (narg > 1) if (narg > 1)
xsettitle(strescseq.args[1]); xsettitle(STRESCARGREST(1));
return; return;
case 52: case 52:
if (narg > 2 && allowwindowops) { if (narg > 2 && allowwindowops) {
dec = base64dec(strescseq.args[2]); dec = base64dec(STRESCARGJUST(2));
if (dec) { if (dec) {
xsetsel(dec); xsetsel(dec);
xclipcopy(); xclipcopy();
@ -1964,7 +1998,7 @@ strhandle(void)
case 12: case 12:
if (narg < 2) if (narg < 2)
break; break;
p = strescseq.args[1]; p = STRESCARGREST(1);
if ((j = par - 10) < 0 || j >= LEN(osc_table)) if ((j = par - 10) < 0 || j >= LEN(osc_table))
break; /* shouldn't be possible */ break; /* shouldn't be possible */
@ -1980,10 +2014,10 @@ strhandle(void)
case 4: /* color set */ case 4: /* color set */
if (narg < 3) if (narg < 3)
break; break;
p = strescseq.args[2]; p = STRESCARGJUST(2);
/* FALLTHROUGH */ /* FALLTHROUGH */
case 104: /* color reset */ case 104: /* color reset */
j = (narg > 1) ? atoi(strescseq.args[1]) : -1; j = (narg > 1) ? atoi(STRESCARGJUST(1)) : -1;
if (p && !strcmp(p, "?")) { if (p && !strcmp(p, "?")) {
osc_color_response(j, 0, 1); osc_color_response(j, 0, 1);
@ -2005,9 +2039,15 @@ strhandle(void)
} }
break; break;
case 'k': /* old title set compatibility */ case 'k': /* old title set compatibility */
xsettitle(strescseq.args[0]); xsettitle(strescseq.buf);
return; return;
case 'P': /* DCS -- Device Control String */ case 'P': /* DCS -- Device Control String */
/* https://gitlab.com/gnachman/iterm2/-/wikis/synchronized-updates-spec */
if (strstr(strescseq.buf, "=1s") == strescseq.buf)
tsync_begin(); /* BSU */
else if (strstr(strescseq.buf, "=2s") == strescseq.buf)
tsync_end(); /* ESU */
return;
case '_': /* APC -- Application Program Command */ case '_': /* APC -- Application Program Command */
case '^': /* PM -- Privacy Message */ case '^': /* PM -- Privacy Message */
return; return;
@ -2024,18 +2064,17 @@ strparse(void)
char *p = strescseq.buf; char *p = strescseq.buf;
strescseq.narg = 0; strescseq.narg = 0;
strescseq.buf[strescseq.len] = '\0';
if (*p == '\0') if (*p == '\0')
return; return;
while (strescseq.narg < STR_ARG_SIZ) { while (strescseq.narg < STR_ARG_SIZ) {
strescseq.args[strescseq.narg++] = p;
while ((c = *p) != ';' && c != '\0') while ((c = *p) != ';' && c != '\0')
++p; p++;
strescseq.argp[strescseq.narg++] = p;
if (c == '\0') if (c == '\0')
return; return;
*p++ = '\0'; p++;
} }
} }
@ -2556,6 +2595,9 @@ twrite(const char *buf, int buflen, int show_ctrl)
Rune u; Rune u;
int n; int n;
int su0 = su;
twrite_aborted = 0;
for (n = 0; n < buflen; n += charsize) { for (n = 0; n < buflen; n += charsize) {
if (IS_SET(MODE_UTF8)) { if (IS_SET(MODE_UTF8)) {
/* process a complete utf8 char */ /* process a complete utf8 char */
@ -2566,6 +2608,10 @@ twrite(const char *buf, int buflen, int show_ctrl)
u = buf[n] & 0xFF; u = buf[n] & 0xFF;
charsize = 1; charsize = 1;
} }
if (su0 && !su) {
twrite_aborted = 1;
break; // ESU - allow rendering before a new BSU
}
if (show_ctrl && ISCONTROL(u)) { if (show_ctrl && ISCONTROL(u)) {
if (u & 0x80) { if (u & 0x80) {
u &= 0x7f; u &= 0x7f;

1
st.h
View File

@ -127,3 +127,4 @@ 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 float alpha;

View File

@ -192,6 +192,7 @@ st-mono| simpleterm monocolor,
Ms=\E]52;%p1%s;%p2%s\007, Ms=\E]52;%p1%s;%p2%s\007,
Se=\E[2 q, Se=\E[2 q,
Ss=\E[%p1%d q, Ss=\E[%p1%d q,
Sync=\EP=%p1%ds\E\\,
st| simpleterm, st| simpleterm,
use=st-mono, use=st-mono,

145
x.c
View File

@ -89,6 +89,7 @@ typedef XftGlyphFontSpec GlyphFontSpec;
typedef struct { typedef struct {
int tw, th; /* tty width and height */ int tw, th; /* tty width and height */
int w, h; /* window width and height */ int w, h; /* window width and height */
int hborderpx, vborderpx;
int ch; /* char height */ int ch; /* char height */
int cw; /* char width */ int cw; /* char width */
int mode; /* window state/mode flags */ int mode; /* window state/mode flags */
@ -113,6 +114,7 @@ typedef struct {
XSetWindowAttributes attrs; XSetWindowAttributes attrs;
int scr; int scr;
int isfixed; /* is fixed geometry? */ int isfixed; /* is fixed geometry? */
int depth; /* bit depth */
int l, t; /* left and top offset */ int l, t; /* left and top offset */
int gm; /* geometry mask */ int gm; /* geometry mask */
} XWindow; } XWindow;
@ -251,6 +253,7 @@ static char *usedfont = NULL;
static double usedfontsize = 0; static double usedfontsize = 0;
static double defaultfontsize = 0; static double defaultfontsize = 0;
static char *opt_alpha = NULL;
static char *opt_class = NULL; static char *opt_class = NULL;
static char **opt_cmd = NULL; static char **opt_cmd = NULL;
static char *opt_embed = NULL; static char *opt_embed = NULL;
@ -339,7 +342,7 @@ ttysend(const Arg *arg)
int int
evcol(XEvent *e) evcol(XEvent *e)
{ {
int x = e->xbutton.x - borderpx; int x = e->xbutton.x - win.hborderpx;
LIMIT(x, 0, win.tw - 1); LIMIT(x, 0, win.tw - 1);
return x / win.cw; return x / win.cw;
} }
@ -347,7 +350,7 @@ evcol(XEvent *e)
int int
evrow(XEvent *e) evrow(XEvent *e)
{ {
int y = e->xbutton.y - borderpx; int y = e->xbutton.y - win.vborderpx;
LIMIT(y, 0, win.th - 1); LIMIT(y, 0, win.th - 1);
return y / win.ch; return y / win.ch;
} }
@ -694,6 +697,8 @@ 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();
xclipcopy();
} }
void void
@ -717,7 +722,9 @@ brelease(XEvent *e)
if (mouseaction(e, 1)) if (mouseaction(e, 1))
return; return;
if (btn == Button1) if (btn == Button3)
selpaste(NULL);
else if (btn == Button1)
mousesel(e, 1); mousesel(e, 1);
} }
@ -747,6 +754,9 @@ cresize(int width, int height)
col = MAX(1, col); col = MAX(1, col);
row = MAX(1, row); row = MAX(1, row);
win.hborderpx = (win.w - col * win.cw) / 2;
win.vborderpx = (win.h - row * win.ch) / 2;
tresize(col, row); tresize(col, row);
xresize(col, row); xresize(col, row);
ttyresize(win.tw, win.th); ttyresize(win.tw, win.th);
@ -760,7 +770,7 @@ 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)); xw.depth);
XftDrawChange(xw.draw, xw.buf); XftDrawChange(xw.draw, xw.buf);
xclear(0, 0, win.w, win.h); xclear(0, 0, win.w, win.h);
@ -820,6 +830,13 @@ xloadcols(void)
else else
die("could not allocate color %d\n", i); die("could not allocate color %d\n", i);
} }
/* set alpha value of bg color */
if (opt_alpha)
alpha = strtof(opt_alpha, NULL);
dc.col[defaultbg].color.alpha = (unsigned short)(0xffff * alpha);
dc.col[defaultbg].pixel &= 0x00FFFFFF;
dc.col[defaultbg].pixel |= (unsigned char)(0xff * alpha) << 24;
loaded = 1; loaded = 1;
} }
@ -877,8 +894,8 @@ xhints(void)
sizeh->flags = PSize | PResizeInc | PBaseSize | PMinSize; sizeh->flags = PSize | PResizeInc | PBaseSize | PMinSize;
sizeh->height = win.h; sizeh->height = win.h;
sizeh->width = win.w; sizeh->width = win.w;
sizeh->height_inc = win.ch; sizeh->height_inc = 1;
sizeh->width_inc = win.cw; sizeh->width_inc = 1;
sizeh->base_height = 2 * borderpx; sizeh->base_height = 2 * borderpx;
sizeh->base_width = 2 * borderpx; sizeh->base_width = 2 * borderpx;
sizeh->min_height = win.ch + 2 * borderpx; sizeh->min_height = win.ch + 2 * borderpx;
@ -1142,11 +1159,23 @@ xinit(int cols, int rows)
Window parent; Window parent;
pid_t thispid = getpid(); pid_t thispid = getpid();
XColor xmousefg, xmousebg; XColor xmousefg, xmousebg;
XWindowAttributes attr;
XVisualInfo vis;
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);
if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0)))) {
parent = XRootWindow(xw.dpy, xw.scr);
xw.depth = 32;
} else {
XGetWindowAttributes(xw.dpy, parent, &attr);
xw.depth = attr.depth;
}
XMatchVisualInfo(xw.dpy, xw.scr, xw.depth, TrueColor, &vis);
xw.vis = vis.visual;
/* font */ /* font */
if (!FcInit()) if (!FcInit())
@ -1156,12 +1185,12 @@ xinit(int cols, int rows)
xloadfonts(usedfont, 0); xloadfonts(usedfont, 0);
/* colors */ /* colors */
xw.cmap = XDefaultColormap(xw.dpy, xw.scr); xw.cmap = XCreateColormap(xw.dpy, parent, xw.vis, None);
xloadcols(); xloadcols();
/* adjust fixed window geometry */ /* adjust fixed window geometry */
win.w = 2 * borderpx + cols * win.cw; win.w = 2 * win.hborderpx + 2 * borderpx + cols * win.cw;
win.h = 2 * borderpx + rows * win.ch; win.h = 2 * win.vborderpx + 2 * borderpx + rows * win.ch;
if (xw.gm & XNegative) if (xw.gm & XNegative)
xw.l += DisplayWidth(xw.dpy, xw.scr) - win.w - 2; xw.l += DisplayWidth(xw.dpy, xw.scr) - win.w - 2;
if (xw.gm & YNegative) if (xw.gm & YNegative)
@ -1176,19 +1205,15 @@ xinit(int cols, int rows)
| ButtonMotionMask | ButtonPressMask | ButtonReleaseMask; | ButtonMotionMask | ButtonPressMask | ButtonReleaseMask;
xw.attrs.colormap = xw.cmap; xw.attrs.colormap = xw.cmap;
if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0))))
parent = XRootWindow(xw.dpy, xw.scr);
xw.win = XCreateWindow(xw.dpy, parent, xw.l, xw.t, xw.win = XCreateWindow(xw.dpy, parent, xw.l, xw.t,
win.w, win.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput, win.w, win.h, 0, xw.depth, InputOutput,
xw.vis, CWBackPixel | CWBorderPixel | CWBitGravity xw.vis, CWBackPixel | CWBorderPixel | CWBitGravity
| CWEventMask | CWColormap, &xw.attrs); | CWEventMask | CWColormap, &xw.attrs);
memset(&gcvalues, 0, sizeof(gcvalues)); memset(&gcvalues, 0, sizeof(gcvalues));
gcvalues.graphics_exposures = False; gcvalues.graphics_exposures = False;
dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures, xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, xw.depth);
&gcvalues); dc.gc = XCreateGC(xw.dpy, xw.buf, GCGraphicsExposures, &gcvalues);
xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
DefaultDepth(xw.dpy, xw.scr));
XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel); XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel);
XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h); XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h);
@ -1250,7 +1275,7 @@ xinit(int cols, int rows)
int int
xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y) xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y)
{ {
float winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, xp, yp; float winx = win.hborderpx + x * win.cw, winy = win.vborderpx + y * win.ch, xp, yp;
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;
@ -1428,7 +1453,7 @@ 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 winx = win.hborderpx + x * win.cw, winy = win.vborderpx + y * win.ch,
width = charlen * win.cw; width = charlen * win.cw;
Color *fg, *bg, *temp, revfg, revbg, truefg, truebg; Color *fg, *bg, *temp, revfg, revbg, truefg, truebg;
XRenderColor colfg, colbg; XRenderColor colfg, colbg;
@ -1465,10 +1490,6 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
bg = &dc.col[base.bg]; bg = &dc.col[base.bg];
} }
/* Change basic system colors [0-7] to bright system colors [8-15] */
if ((base.mode & ATTR_BOLD_FAINT) == ATTR_BOLD && BETWEEN(base.fg, 0, 7))
fg = &dc.col[base.fg + 8];
if (IS_SET(MODE_REVERSE)) { if (IS_SET(MODE_REVERSE)) {
if (fg == &dc.col[defaultfg]) { if (fg == &dc.col[defaultfg]) {
fg = &dc.col[defaultbg]; fg = &dc.col[defaultbg];
@ -1518,17 +1539,17 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
/* Intelligent cleaning up of the borders. */ /* Intelligent cleaning up of the borders. */
if (x == 0) { if (x == 0) {
xclear(0, (y == 0)? 0 : winy, borderpx, xclear(0, (y == 0)? 0 : winy, win.hborderpx,
winy + win.ch + winy + win.ch +
((winy + win.ch >= borderpx + win.th)? win.h : 0)); ((winy + win.ch >= win.vborderpx + win.th)? win.h : 0));
} }
if (winx + width >= borderpx + win.tw) { if (winx + width >= win.hborderpx + win.tw) {
xclear(winx + width, (y == 0)? 0 : winy, win.w, xclear(winx + width, (y == 0)? 0 : winy, win.w,
((winy + win.ch >= borderpx + win.th)? win.h : (winy + win.ch))); ((winy + win.ch >= win.vborderpx + win.th)? win.h : (winy + win.ch)));
} }
if (y == 0) if (y == 0)
xclear(winx, 0, winx + width, borderpx); xclear(winx, 0, winx + width, win.vborderpx);
if (winy + win.ch >= borderpx + win.th) if (winy + win.ch >= win.vborderpx + win.th)
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. */
@ -1922,6 +1943,7 @@ void
xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
{ {
Color drawcol; Color drawcol;
XRenderColor colbg;
/* remove the old cursor */ /* remove the old cursor */
if (selected(ox, oy)) if (selected(ox, oy))
@ -1950,12 +1972,22 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
if (selected(cx, cy)) { if (selected(cx, cy)) {
g.fg = defaultfg; g.fg = defaultfg;
g.bg = defaultrcs; g.bg = defaultrcs;
} else { } else if (!(og.mode & ATTR_REVERSE)) {
g.fg = defaultbg; unsigned long col = g.bg;
g.bg = defaultcs; g.bg = g.fg;
g.fg = col;
} }
if (IS_TRUECOL(g.bg)) {
colbg.alpha = 0xffff;
colbg.red = TRUERED(g.bg);
colbg.green = TRUEGREEN(g.bg);
colbg.blue = TRUEBLUE(g.bg);
XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colbg, &drawcol);
} else {
drawcol = dc.col[g.bg]; drawcol = dc.col[g.bg];
} }
}
/* draw the new one */ /* draw the new one */
if (IS_SET(MODE_FOCUSED)) { if (IS_SET(MODE_FOCUSED)) {
@ -1971,35 +2003,35 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
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, win.hborderpx + cx * win.cw,
borderpx + (cy + 1) * win.ch - \ win.vborderpx + (cy + 1) * win.ch - \
cursorthickness, cursorthickness,
win.cw, cursorthickness); win.cw, cursorthickness);
break; break;
case 5: /* Blinking bar */ case 5: /* Blinking bar */
case 6: /* Steady bar */ case 6: /* Steady bar */
XftDrawRect(xw.draw, &drawcol, XftDrawRect(xw.draw, &drawcol,
borderpx + cx * win.cw, win.hborderpx + cx * win.cw,
borderpx + cy * win.ch, win.vborderpx + cy * win.ch,
cursorthickness, win.ch); cursorthickness, win.ch);
break; break;
} }
} else { } else {
XftDrawRect(xw.draw, &drawcol, XftDrawRect(xw.draw, &drawcol,
borderpx + cx * win.cw, win.hborderpx + cx * win.cw,
borderpx + cy * win.ch, win.vborderpx + cy * win.ch,
win.cw - 1, 1); win.cw - 1, 1);
XftDrawRect(xw.draw, &drawcol, XftDrawRect(xw.draw, &drawcol,
borderpx + cx * win.cw, win.hborderpx + cx * win.cw,
borderpx + cy * win.ch, win.vborderpx + cy * win.ch,
1, win.ch - 1); 1, win.ch - 1);
XftDrawRect(xw.draw, &drawcol, XftDrawRect(xw.draw, &drawcol,
borderpx + (cx + 1) * win.cw - 1, win.hborderpx + (cx + 1) * win.cw - 1,
borderpx + cy * win.ch, win.vborderpx + cy * win.ch,
1, win.ch - 1); 1, win.ch - 1);
XftDrawRect(xw.draw, &drawcol, XftDrawRect(xw.draw, &drawcol,
borderpx + cx * win.cw, win.hborderpx + cx * win.cw,
borderpx + (cy + 1) * win.ch - 1, win.vborderpx + (cy + 1) * win.ch - 1,
win.cw, 1); win.cw, 1);
} }
} }
@ -2313,6 +2345,9 @@ resize(XEvent *e)
cresize(e->xconfigure.width, e->xconfigure.height); cresize(e->xconfigure.width, e->xconfigure.height);
} }
int tinsync(uint);
int ttyread_pending();
void void
run(void) run(void)
{ {
@ -2347,7 +2382,7 @@ run(void)
FD_SET(ttyfd, &rfd); FD_SET(ttyfd, &rfd);
FD_SET(xfd, &rfd); FD_SET(xfd, &rfd);
if (XPending(xw.dpy)) if (XPending(xw.dpy) || ttyread_pending())
timeout = 0; /* existing events might not set xfd */ timeout = 0; /* existing events might not set xfd */
seltv.tv_sec = timeout / 1E3; seltv.tv_sec = timeout / 1E3;
@ -2361,7 +2396,8 @@ run(void)
} }
clock_gettime(CLOCK_MONOTONIC, &now); clock_gettime(CLOCK_MONOTONIC, &now);
if (FD_ISSET(ttyfd, &rfd)) int ttyin = FD_ISSET(ttyfd, &rfd) || ttyread_pending();
if (ttyin)
ttyread(); ttyread();
xev = 0; xev = 0;
@ -2385,7 +2421,7 @@ 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 (ttyin || xev) {
if (!drawing) { if (!drawing) {
trigger = now; trigger = now;
drawing = 1; drawing = 1;
@ -2396,6 +2432,18 @@ run(void)
continue; /* we have time, try to find idle */ continue; /* we have time, try to find idle */
} }
if (tinsync(su_timeout)) {
/*
* on synchronized-update draw-suspension: don't reset
* drawing so that we draw ASAP once we can (just after
* ESU). it won't be too soon because we already can
* draw now but we skip. we set timeout > 0 to draw on
* SU-timeout even without new content.
*/
timeout = minlatency;
continue;
}
/* 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)) {
@ -2440,6 +2488,9 @@ main(int argc, char *argv[])
case 'a': case 'a':
allowaltscreen = 0; allowaltscreen = 0;
break; break;
case 'A':
opt_alpha = EARGF(usage());
break;
case 'c': case 'c':
opt_class = EARGF(usage()); opt_class = EARGF(usage());
break; break;