Compare commits

..

1 Commits

Author SHA1 Message Date
pgrondek
46040e8e04 Palettes
Based on patch for version 0.8.1
https://st.suckless.org/patches/palettes/
2020-05-31 23:44:52 +02:00
18 changed files with 345 additions and 1402 deletions

1
.gitignore vendored
View File

@ -1,4 +1,3 @@
st
*.o
*.orig
.idea/

63
FAQ
View File

@ -2,14 +2,12 @@
Use the excellent tool of [utmp](https://git.suckless.org/utmp/) for this task.
## Some _random program_ complains that st is unknown/not recognised/unsupported/whatever!
It means that st doesnt have any terminfo entry on your system. Chances are
you did not `make install`. If you just want to test it without installing it,
you can manually run `tic -sx st.info`.
## Nothing works, and nothing is said about an unknown terminal!
* Some programs just assume theyre running in xterm i.e. they dont rely on
@ -17,7 +15,6 @@ you can manually run `tic -sx st.info`.
* Some programs dont complain about the lacking st description and default to
another terminal. In that case see the question about terminfo.
## How do I scroll back up?
* Using a terminal multiplexer.
@ -26,12 +23,10 @@ you can manually run `tic -sx st.info`.
* Using the excellent tool of [scroll](https://git.suckless.org/scroll/).
* Using the scrollback [patch](https://st.suckless.org/patches/scrollback/).
## I would like to have utmp and/or scroll functionality by default
You can add the absolute path of both programs in your config.h file. You only
have to modify the value of utmp and scroll variables.
You can add the absolute patch of both programs in your config.h
file. You only have to modify the value of utmp and scroll variables.
## Why doesn't the Del key work in some programs?
@ -88,14 +83,12 @@ If you are using zsh, then read the zsh FAQ
Putting these lines into your .zshrc will fix the problems.
## How can I use meta in 8bit mode?
St supports meta in 8bit mode, but the default terminfo entry doesn't
use this capability. If you want it, you have to use the 'st-meta' value
in TERM.
## I cannot compile st in OpenBSD
OpenBSD lacks librt, despite it being mandatory in POSIX
@ -104,7 +97,6 @@ If you want to compile st for OpenBSD you have to remove -lrt from config.mk, an
st will compile without any loss of functionality, because all the functions are
included in libc on this platform.
## The Backspace Case
St is emulating the Linux way of handling backspace being delete and delete being
@ -166,60 +158,19 @@ terminal users wants its backspace to be how he feels it:
[1] http://www.ibb.net/~anne/keyboard.html
[2] http://www.tldp.org/HOWTO/Keyboard-and-Console-HOWTO-5.html
## But I really want the old grumpy behaviour of my terminal
Apply [1].
[1] https://st.suckless.org/patches/delkey
## Why do images not work in st (in programs such as w3m)?
## Why do images not work in st using the w3m image hack?
w3mimg uses a hack that draws an image on top of the terminal emulator Drawable
window. The hack relies on the terminal to use a single buffer to draw its
contents directly.
st uses double-buffered drawing so the image is quickly replaced and may show a
short flicker effect.
Below is a patch example to change st double-buffering to a single Drawable
buffer.
diff --git a/x.c b/x.c
--- a/x.c
+++ b/x.c
@@ -732,10 +732,6 @@ xresize(int col, int row)
win.tw = col * win.cw;
win.th = row * win.ch;
- XFreePixmap(xw.dpy, xw.buf);
- xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
- DefaultDepth(xw.dpy, xw.scr));
- XftDrawChange(xw.draw, xw.buf);
xclear(0, 0, win.w, win.h);
/* resize to new width */
@@ -1148,8 +1144,7 @@ xinit(int cols, int rows)
gcvalues.graphics_exposures = False;
dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures,
&gcvalues);
- xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
- DefaultDepth(xw.dpy, xw.scr));
+ xw.buf = xw.win;
XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel);
XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h);
@@ -1632,8 +1627,6 @@ xdrawline(Line line, int x1, int y1, int x2)
void
xfinishdraw(void)
{
- 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);
This is a terrible hack that overdraws an image on top of the terminal emulator
window. It also relies on a very specific way the terminal draws it's contents.
A more proper (but limited way) would be using sixels. Which st doesn't
support.
## BadLength X error in Xft when trying to render emoji

View File

@ -1,6 +1,6 @@
MIT/X Consortium License
© 2014-2022 Hiltjo Posthuma <hiltjo at codemadness dot org>
© 2014-2018 Hiltjo Posthuma <hiltjo at codemadness dot org>
© 2018 Devin J. Pohly <djpohly at gmail dot com>
© 2014-2017 Quentin Rameau <quinq at fifth dot space>
© 2009-2012 Aurélien APTEL <aurelien dot aptel at gmail dot com>

View File

@ -4,7 +4,7 @@
include config.mk
SRC = st.c x.c boxdraw.c hb.c
SRC = st.c x.c
OBJ = $(SRC:.c=.o)
all: options st
@ -22,9 +22,7 @@ config.h:
$(CC) $(STCFLAGS) -c $<
st.o: config.h st.h win.h
x.o: arg.h config.h st.h win.h hb.h
hb.o: st.h
boxdraw.o: config.h st.h boxdraw_data.h
x.o: arg.h config.h st.h win.h
$(OBJ): config.h config.mk
@ -52,12 +50,9 @@ install: st
chmod 644 $(DESTDIR)$(MANPREFIX)/man1/st.1
tic -sx st.info
@echo Please see the README file regarding the terminfo entry of st.
mkdir -p $(DESTDIR)$(PREFIX)/share/applications
cp -f st.desktop $(DESTDIR)$(PREFIX)/share/applications
uninstall:
rm -f $(DESTDIR)$(PREFIX)/bin/st
rm -f $(DESTDIR)$(MANPREFIX)/man1/st.1
rm -f $(DESTDIR)$(PREFIX)/share/applications/st.desktop
.PHONY: all options clean dist install uninstall

194
boxdraw.c
View File

@ -1,194 +0,0 @@
/*
* Copyright 2018 Avi Halachmi (:avih) avihpit@yahoo.com https://github.com/avih
* MIT/X Consortium License
*/
#include <X11/Xft/Xft.h>
#include "st.h"
#include "boxdraw_data.h"
/* Rounded non-negative integers division of n / d */
#define DIV(n, d) (((n) + (d) / 2) / (d))
static Display *xdpy;
static Colormap xcmap;
static XftDraw *xd;
static Visual *xvis;
static void drawbox(int, int, int, int, XftColor *, XftColor *, ushort);
static void drawboxlines(int, int, int, int, XftColor *, ushort);
/* public API */
void
boxdraw_xinit(Display *dpy, Colormap cmap, XftDraw *draw, Visual *vis)
{
xdpy = dpy; xcmap = cmap; xd = draw, xvis = vis;
}
int
isboxdraw(Rune u)
{
Rune block = u & ~0xff;
return (boxdraw && block == 0x2500 && boxdata[(uint8_t)u]) ||
(boxdraw_braille && block == 0x2800);
}
/* the "index" is actually the entire shape data encoded as ushort */
ushort
boxdrawindex(const Glyph *g)
{
if (boxdraw_braille && (g->u & ~0xff) == 0x2800)
return BRL | (uint8_t)g->u;
if (boxdraw_bold && (g->mode & ATTR_BOLD))
return BDB | boxdata[(uint8_t)g->u];
return boxdata[(uint8_t)g->u];
}
void
drawboxes(int x, int y, int cw, int ch, XftColor *fg, XftColor *bg,
const XftGlyphFontSpec *specs, int len)
{
for ( ; len-- > 0; x += cw, specs++)
drawbox(x, y, cw, ch, fg, bg, (ushort)specs->glyph);
}
/* implementation */
void
drawbox(int x, int y, int w, int h, XftColor *fg, XftColor *bg, ushort bd)
{
ushort cat = bd & ~(BDB | 0xff); /* mask out bold and data */
if (bd & (BDL | BDA)) {
/* lines (light/double/heavy/arcs) */
drawboxlines(x, y, w, h, fg, bd);
} else if (cat == BBD) {
/* lower (8-X)/8 block */
int d = DIV((uint8_t)bd * h, 8);
XftDrawRect(xd, fg, x, y + d, w, h - d);
} else if (cat == BBU) {
/* upper X/8 block */
XftDrawRect(xd, fg, x, y, w, DIV((uint8_t)bd * h, 8));
} else if (cat == BBL) {
/* left X/8 block */
XftDrawRect(xd, fg, x, y, DIV((uint8_t)bd * w, 8), h);
} else if (cat == BBR) {
/* right (8-X)/8 block */
int d = DIV((uint8_t)bd * w, 8);
XftDrawRect(xd, fg, x + d, y, w - d, h);
} else if (cat == BBQ) {
/* Quadrants */
int w2 = DIV(w, 2), h2 = DIV(h, 2);
if (bd & TL)
XftDrawRect(xd, fg, x, y, w2, h2);
if (bd & TR)
XftDrawRect(xd, fg, x + w2, y, w - w2, h2);
if (bd & BL)
XftDrawRect(xd, fg, x, y + h2, w2, h - h2);
if (bd & BR)
XftDrawRect(xd, fg, x + w2, y + h2, w - w2, h - h2);
} else if (bd & BBS) {
/* Shades - data is 1/2/3 for 25%/50%/75% alpha, respectively */
int d = (uint8_t)bd;
XftColor xfc;
XRenderColor xrc = { .alpha = 0xffff };
xrc.red = DIV(fg->color.red * d + bg->color.red * (4 - d), 4);
xrc.green = DIV(fg->color.green * d + bg->color.green * (4 - d), 4);
xrc.blue = DIV(fg->color.blue * d + bg->color.blue * (4 - d), 4);
XftColorAllocValue(xdpy, xvis, xcmap, &xrc, &xfc);
XftDrawRect(xd, &xfc, x, y, w, h);
XftColorFree(xdpy, xvis, xcmap, &xfc);
} else if (cat == BRL) {
/* braille, each data bit corresponds to one dot at 2x4 grid */
int w1 = DIV(w, 2);
int h1 = DIV(h, 4), h2 = DIV(h, 2), h3 = DIV(3 * h, 4);
if (bd & 1) XftDrawRect(xd, fg, x, y, w1, h1);
if (bd & 2) XftDrawRect(xd, fg, x, y + h1, w1, h2 - h1);
if (bd & 4) XftDrawRect(xd, fg, x, y + h2, w1, h3 - h2);
if (bd & 8) XftDrawRect(xd, fg, x + w1, y, w - w1, h1);
if (bd & 16) XftDrawRect(xd, fg, x + w1, y + h1, w - w1, h2 - h1);
if (bd & 32) XftDrawRect(xd, fg, x + w1, y + h2, w - w1, h3 - h2);
if (bd & 64) XftDrawRect(xd, fg, x, y + h3, w1, h - h3);
if (bd & 128) XftDrawRect(xd, fg, x + w1, y + h3, w - w1, h - h3);
}
}
void
drawboxlines(int x, int y, int w, int h, XftColor *fg, ushort bd)
{
/* s: stem thickness. width/8 roughly matches underscore thickness. */
/* We draw bold as 1.5 * normal-stem and at least 1px thicker. */
/* doubles draw at least 3px, even when w or h < 3. bold needs 6px. */
int mwh = MIN(w, h);
int base_s = MAX(1, DIV(mwh, 8));
int bold = (bd & BDB) && mwh >= 6; /* possibly ignore boldness */
int s = bold ? MAX(base_s + 1, DIV(3 * base_s, 2)) : base_s;
int w2 = DIV(w - s, 2), h2 = DIV(h - s, 2);
/* the s-by-s square (x + w2, y + h2, s, s) is the center texel. */
/* The base length (per direction till edge) includes this square. */
int light = bd & (LL | LU | LR | LD);
int double_ = bd & (DL | DU | DR | DD);
if (light) {
/* d: additional (negative) length to not-draw the center */
/* texel - at arcs and avoid drawing inside (some) doubles */
int arc = bd & BDA;
int multi_light = light & (light - 1);
int multi_double = double_ & (double_ - 1);
/* light crosses double only at DH+LV, DV+LH (ref. shapes) */
int d = arc || (multi_double && !multi_light) ? -s : 0;
if (bd & LL)
XftDrawRect(xd, fg, x, y + h2, w2 + s + d, s);
if (bd & LU)
XftDrawRect(xd, fg, x + w2, y, s, h2 + s + d);
if (bd & LR)
XftDrawRect(xd, fg, x + w2 - d, y + h2, w - w2 + d, s);
if (bd & LD)
XftDrawRect(xd, fg, x + w2, y + h2 - d, s, h - h2 + d);
}
/* double lines - also align with light to form heavy when combined */
if (double_) {
/*
* going clockwise, for each double-ray: p is additional length
* to the single-ray nearer to the previous direction, and n to
* the next. p and n adjust from the base length to lengths
* which consider other doubles - shorter to avoid intersections
* (p, n), or longer to draw the far-corner texel (n).
*/
int dl = bd & DL, du = bd & DU, dr = bd & DR, dd = bd & DD;
if (dl) {
int p = dd ? -s : 0, n = du ? -s : dd ? s : 0;
XftDrawRect(xd, fg, x, y + h2 + s, w2 + s + p, s);
XftDrawRect(xd, fg, x, y + h2 - s, w2 + s + n, s);
}
if (du) {
int p = dl ? -s : 0, n = dr ? -s : dl ? s : 0;
XftDrawRect(xd, fg, x + w2 - s, y, s, h2 + s + p);
XftDrawRect(xd, fg, x + w2 + s, y, s, h2 + s + n);
}
if (dr) {
int p = du ? -s : 0, n = dd ? -s : du ? s : 0;
XftDrawRect(xd, fg, x + w2 - p, y + h2 - s, w - w2 + p, s);
XftDrawRect(xd, fg, x + w2 - n, y + h2 + s, w - w2 + n, s);
}
if (dd) {
int p = dr ? -s : 0, n = dl ? -s : dr ? s : 0;
XftDrawRect(xd, fg, x + w2 + s, y + h2 - p, s, h - h2 + p);
XftDrawRect(xd, fg, x + w2 - s, y + h2 - n, s, h - h2 + n);
}
}
}

View File

@ -1,214 +0,0 @@
/*
* Copyright 2018 Avi Halachmi (:avih) avihpit@yahoo.com https://github.com/avih
* MIT/X Consortium License
*/
/*
* U+25XX codepoints data
*
* References:
* http://www.unicode.org/charts/PDF/U2500.pdf
* http://www.unicode.org/charts/PDF/U2580.pdf
*
* Test page:
* https://github.com/GNOME/vte/blob/master/doc/boxes.txt
*/
/* Each shape is encoded as 16-bits. Higher bits are category, lower are data */
/* Categories (mutually exclusive except BDB): */
/* For convenience, BDL/BDA/BBS/BDB are 1 bit each, the rest are enums */
#define BDL (1<<8) /* Box Draw Lines (light/double/heavy) */
#define BDA (1<<9) /* Box Draw Arc (light) */
#define BBD (1<<10) /* Box Block Down (lower) X/8 */
#define BBL (2<<10) /* Box Block Left X/8 */
#define BBU (3<<10) /* Box Block Upper X/8 */
#define BBR (4<<10) /* Box Block Right X/8 */
#define BBQ (5<<10) /* Box Block Quadrants */
#define BRL (6<<10) /* Box Braille (data is lower byte of U28XX) */
#define BBS (1<<14) /* Box Block Shades */
#define BDB (1<<15) /* Box Draw is Bold */
/* (BDL/BDA) Light/Double/Heavy x Left/Up/Right/Down/Horizontal/Vertical */
/* Heavy is light+double (literally drawing light+double align to form heavy) */
#define LL (1<<0)
#define LU (1<<1)
#define LR (1<<2)
#define LD (1<<3)
#define LH (LL+LR)
#define LV (LU+LD)
#define DL (1<<4)
#define DU (1<<5)
#define DR (1<<6)
#define DD (1<<7)
#define DH (DL+DR)
#define DV (DU+DD)
#define HL (LL+DL)
#define HU (LU+DU)
#define HR (LR+DR)
#define HD (LD+DD)
#define HH (HL+HR)
#define HV (HU+HD)
/* (BBQ) Quadrants Top/Bottom x Left/Right */
#define TL (1<<0)
#define TR (1<<1)
#define BL (1<<2)
#define BR (1<<3)
/* Data for U+2500 - U+259F except dashes/diagonals */
static const unsigned short boxdata[256] = {
/* light lines */
[0x00] = BDL + LH, /* light horizontal */
[0x02] = BDL + LV, /* light vertical */
[0x0c] = BDL + LD + LR, /* light down and right */
[0x10] = BDL + LD + LL, /* light down and left */
[0x14] = BDL + LU + LR, /* light up and right */
[0x18] = BDL + LU + LL, /* light up and left */
[0x1c] = BDL + LV + LR, /* light vertical and right */
[0x24] = BDL + LV + LL, /* light vertical and left */
[0x2c] = BDL + LH + LD, /* light horizontal and down */
[0x34] = BDL + LH + LU, /* light horizontal and up */
[0x3c] = BDL + LV + LH, /* light vertical and horizontal */
[0x74] = BDL + LL, /* light left */
[0x75] = BDL + LU, /* light up */
[0x76] = BDL + LR, /* light right */
[0x77] = BDL + LD, /* light down */
/* heavy [+light] lines */
[0x01] = BDL + HH,
[0x03] = BDL + HV,
[0x0d] = BDL + HR + LD,
[0x0e] = BDL + HD + LR,
[0x0f] = BDL + HD + HR,
[0x11] = BDL + HL + LD,
[0x12] = BDL + HD + LL,
[0x13] = BDL + HD + HL,
[0x15] = BDL + HR + LU,
[0x16] = BDL + HU + LR,
[0x17] = BDL + HU + HR,
[0x19] = BDL + HL + LU,
[0x1a] = BDL + HU + LL,
[0x1b] = BDL + HU + HL,
[0x1d] = BDL + HR + LV,
[0x1e] = BDL + HU + LD + LR,
[0x1f] = BDL + HD + LR + LU,
[0x20] = BDL + HV + LR,
[0x21] = BDL + HU + HR + LD,
[0x22] = BDL + HD + HR + LU,
[0x23] = BDL + HV + HR,
[0x25] = BDL + HL + LV,
[0x26] = BDL + HU + LD + LL,
[0x27] = BDL + HD + LU + LL,
[0x28] = BDL + HV + LL,
[0x29] = BDL + HU + HL + LD,
[0x2a] = BDL + HD + HL + LU,
[0x2b] = BDL + HV + HL,
[0x2d] = BDL + HL + LD + LR,
[0x2e] = BDL + HR + LL + LD,
[0x2f] = BDL + HH + LD,
[0x30] = BDL + HD + LH,
[0x31] = BDL + HD + HL + LR,
[0x32] = BDL + HR + HD + LL,
[0x33] = BDL + HH + HD,
[0x35] = BDL + HL + LU + LR,
[0x36] = BDL + HR + LU + LL,
[0x37] = BDL + HH + LU,
[0x38] = BDL + HU + LH,
[0x39] = BDL + HU + HL + LR,
[0x3a] = BDL + HU + HR + LL,
[0x3b] = BDL + HH + HU,
[0x3d] = BDL + HL + LV + LR,
[0x3e] = BDL + HR + LV + LL,
[0x3f] = BDL + HH + LV,
[0x40] = BDL + HU + LH + LD,
[0x41] = BDL + HD + LH + LU,
[0x42] = BDL + HV + LH,
[0x43] = BDL + HU + HL + LD + LR,
[0x44] = BDL + HU + HR + LD + LL,
[0x45] = BDL + HD + HL + LU + LR,
[0x46] = BDL + HD + HR + LU + LL,
[0x47] = BDL + HH + HU + LD,
[0x48] = BDL + HH + HD + LU,
[0x49] = BDL + HV + HL + LR,
[0x4a] = BDL + HV + HR + LL,
[0x4b] = BDL + HV + HH,
[0x78] = BDL + HL,
[0x79] = BDL + HU,
[0x7a] = BDL + HR,
[0x7b] = BDL + HD,
[0x7c] = BDL + HR + LL,
[0x7d] = BDL + HD + LU,
[0x7e] = BDL + HL + LR,
[0x7f] = BDL + HU + LD,
/* double [+light] lines */
[0x50] = BDL + DH,
[0x51] = BDL + DV,
[0x52] = BDL + DR + LD,
[0x53] = BDL + DD + LR,
[0x54] = BDL + DR + DD,
[0x55] = BDL + DL + LD,
[0x56] = BDL + DD + LL,
[0x57] = BDL + DL + DD,
[0x58] = BDL + DR + LU,
[0x59] = BDL + DU + LR,
[0x5a] = BDL + DU + DR,
[0x5b] = BDL + DL + LU,
[0x5c] = BDL + DU + LL,
[0x5d] = BDL + DL + DU,
[0x5e] = BDL + DR + LV,
[0x5f] = BDL + DV + LR,
[0x60] = BDL + DV + DR,
[0x61] = BDL + DL + LV,
[0x62] = BDL + DV + LL,
[0x63] = BDL + DV + DL,
[0x64] = BDL + DH + LD,
[0x65] = BDL + DD + LH,
[0x66] = BDL + DD + DH,
[0x67] = BDL + DH + LU,
[0x68] = BDL + DU + LH,
[0x69] = BDL + DH + DU,
[0x6a] = BDL + DH + LV,
[0x6b] = BDL + DV + LH,
[0x6c] = BDL + DH + DV,
/* (light) arcs */
[0x6d] = BDA + LD + LR,
[0x6e] = BDA + LD + LL,
[0x6f] = BDA + LU + LL,
[0x70] = BDA + LU + LR,
/* Lower (Down) X/8 block (data is 8 - X) */
[0x81] = BBD + 7, [0x82] = BBD + 6, [0x83] = BBD + 5, [0x84] = BBD + 4,
[0x85] = BBD + 3, [0x86] = BBD + 2, [0x87] = BBD + 1, [0x88] = BBD + 0,
/* Left X/8 block (data is X) */
[0x89] = BBL + 7, [0x8a] = BBL + 6, [0x8b] = BBL + 5, [0x8c] = BBL + 4,
[0x8d] = BBL + 3, [0x8e] = BBL + 2, [0x8f] = BBL + 1,
/* upper 1/2 (4/8), 1/8 block (X), right 1/2, 1/8 block (8-X) */
[0x80] = BBU + 4, [0x94] = BBU + 1,
[0x90] = BBR + 4, [0x95] = BBR + 7,
/* Quadrants */
[0x96] = BBQ + BL,
[0x97] = BBQ + BR,
[0x98] = BBQ + TL,
[0x99] = BBQ + TL + BL + BR,
[0x9a] = BBQ + TL + BR,
[0x9b] = BBQ + TL + TR + BL,
[0x9c] = BBQ + TL + TR + BR,
[0x9d] = BBQ + TR,
[0x9e] = BBQ + BL + TR,
[0x9f] = BBQ + BL + TR + BR,
/* Shades, data is an alpha value in 25% units (1/4, 1/2, 3/4) */
[0x91] = BBS + 1, [0x92] = BBS + 2, [0x93] = BBS + 3,
/* U+2504 - U+250B, U+254C - U+254F: unsupported (dashes) */
/* U+2571 - U+2573: unsupported (diagonals) */
};

View File

@ -43,18 +43,9 @@ static unsigned int tripleclicktimeout = 600;
/* alt screens */
int allowaltscreen = 1;
/* allow certain non-interactive (insecure) window operations such as:
setting the clipboard text */
int allowwindowops = 0;
/*
* draw latency range in ms - from new content/keypress/etc until drawing.
* within this range, st draws when content stops arriving (idle). mostly it's
* near minlatency, but it waits longer for slow updates to avoid partial draw.
* low minlatency will tear/flicker more, as it can "detect" idle too early.
*/
static double minlatency = 8;
static double maxlatency = 33;
/* frames per second st should at maximum draw to the screen */
static unsigned int xfps = 120;
static unsigned int actionfps = 30;
/*
* blinking timeout (set to 0 to disable blinking) for the terminal blinking
@ -67,18 +58,6 @@ static unsigned int blinktimeout = 800;
*/
static unsigned int cursorthickness = 2;
/*
* 1: render most of the lines/blocks characters without using the font for
* perfect alignment between cells (U2500 - U259F except dashes/diagonals).
* Bold affects lines thickness if boxdraw_bold is not 0. Italic is ignored.
* 0: disable (render all U25XX glyphs normally from the font).
*/
const int boxdraw = 0;
const int boxdraw_bold = 0;
/* braille (U28XX): 1: render as adjacent "pixels", 0: use font */
const int boxdraw_braille = 0;
/*
* bell volume. It must be a value between -100 and 100. Use 0 for disabling
* it
@ -107,48 +86,31 @@ unsigned int tabspaces = 8;
/* bg opacity */
float alpha = 0.8;
float alpha_def;
/* Terminal colors (16 first used in escape sequence) */
static const char *colorname[] = {
/* 8 normal colors */
/* Terminal colors (16 used in escape sequence) */
static const char *palettes[][16] = {
{"black", "red3", "green3", "yellow3", "blue2", "magenta3", "cyan3", "gray90",
"gray50", "red", "green", "yellow", "#5c5cff", "magenta", "cyan", "white"},
{"#223", "#900", "#080", "#fe7", "#35e", "#fc5", "#18e", "#aaa",
"#666", "#f25", "#0b0", "#ff6", "#46f", "#d6a", "#6bf", "#ddd"},
{"#eaeaea", "#b7141f", "#457b24", "#fc7b08", "#134eb2", "#560088", "#0e717c", "#777777",
"#424242", "#e83b3f", "#7aba3a", "#fd8e09", "#54a4f3", "#aa4dbc", "#26bbd1", "#aaaaaa"},
{"#20242d", "#b04b57", "#87b379", "#e5c179", "#7d8fa4", "#a47996", "#85a7a5", "#b3b8c3",
"#000000", "#b04b57", "#87b379", "#e5c179", "#7d8fa4", "#a47996", "#85a7a5", "#ffffff"},
"black",
"red3",
"green3",
"yellow3",
"blue2",
"magenta3",
"cyan3",
"gray90",
/* 8 bright colors */
"gray50",
"red",
"green",
"yellow",
"#5c5cff",
"magenta",
"cyan",
"white",
[255] = 0,
/* more colors can be added after 255 to use with DefaultXX */
"#cccccc",
"#555555",
"gray90", /* default foreground colour */
"black", /* default background colour */
};
static const char **colorname;
/*
* Default colors (colorname index)
* foreground, background, cursor, reverse cursor
*/
unsigned int defaultfg = 258;
unsigned int defaultbg = 259;
unsigned int defaultcs = 256;
static unsigned int defaultrcs = 257;
unsigned int defaultfg = 5;
unsigned int defaultbg = 258;
static unsigned int defaultcs = 5;
static unsigned int defaultrcs = 5;
/*
* Default shape of cursor
@ -193,9 +155,7 @@ static uint forcemousemod = ShiftMask;
static MouseShortcut mshortcuts[] = {
/* mask button function argument release */
{ XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 },
{ ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} },
{ XK_ANY_MOD, Button4, ttysend, {.s = "\031"} },
{ ShiftMask, Button5, ttysend, {.s = "\033[6;2~"} },
{ XK_ANY_MOD, Button5, ttysend, {.s = "\005"} },
};
@ -219,9 +179,15 @@ static Shortcut shortcuts[] = {
{ ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} },
{ ShiftMask, XK_Insert, selpaste, {.i = 0} },
{ TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
{ MODKEY, XK_bracketleft, chgalpha, {.f = -1} }, /* Decrease opacity */
{ MODKEY|ShiftMask, XK_braceright, chgalpha, {.f = +1} }, /* Increase opacity */
{ MODKEY, XK_bracketright,chgalpha, {.f = 0} }, /* Reset opacity */
{ MODKEY|ShiftMask, XK_F1, setpalette, {.i = 0} },
{ MODKEY|ShiftMask, XK_F2, setpalette, {.i = 1} },
{ MODKEY|ShiftMask, XK_F3, setpalette, {.i = 2} },
{ MODKEY|ShiftMask, XK_F4, setpalette, {.i = 3} },
{ MODKEY|ShiftMask, XK_F5, setpalette, {.i = 4} },
{ MODKEY|ShiftMask, XK_F6, setpalette, {.i = 5} },
{ MODKEY|ShiftMask, XK_F7, setpalette, {.i = 6} },
{ MODKEY|ShiftMask, XK_F8, setpalette, {.i = 7} },
{ MODKEY|ShiftMask, XK_F9, setpalette, {.i = 8} },
};
/*

117
config.h
View File

@ -5,7 +5,7 @@
*
* font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
*/
static char *font = "FiraCode:pixelsize=18:antialias=true:autohint=true";
static char *font = "Liberation Mono:pixelsize=18:antialias=true:autohint=true";
static int borderpx = 0;
/*
@ -43,20 +43,6 @@ static unsigned int tripleclicktimeout = 600;
/* alt screens */
int allowaltscreen = 1;
/* allow certain non-interactive (insecure) window operations such as:
setting the clipboard text */
int allowwindowops = 0;
/*
* draw latency range in ms - from new content/keypress/etc until drawing.
* within this range, st draws when content stops arriving (idle). mostly it's
* near minlatency, but it waits longer for slow updates to avoid partial draw.
* low minlatency will tear/flicker more, as it can "detect" idle too early.
*/
static double minlatency = 8;
static double maxlatency = 33;
/* frames per second st should at maximum draw to the screen */
static unsigned int xfps = 120;
static unsigned int actionfps = 30;
@ -72,18 +58,6 @@ static unsigned int blinktimeout = 800;
*/
static unsigned int cursorthickness = 2;
/*
* 1: render most of the lines/blocks characters without using the font for
* perfect alignment between cells (U2500 - U259F except dashes/diagonals).
* Bold affects lines thickness if boxdraw_bold is not 0. Italic is ignored.
* 0: disable (render all U25XX glyphs normally from the font).
*/
const int boxdraw = 1;
const int boxdraw_bold = 0;
/* braille (U28XX): 1: render as adjacent "pixels", 0: use font */
const int boxdraw_braille = 0;
/*
* bell volume. It must be a value between -100 and 100. Use 0 for disabling
* it
@ -111,47 +85,30 @@ char *termname = "st-256color";
unsigned int tabspaces = 8;
/* bg opacity */
float alpha = 0.85;
float alpha_def;
float alpha = 0.7;
/* Terminal colors (16 first used in escape sequence) */
static const char *colorname[] = {
/* 8 normal colors */
"black",
"red3",
"green3",
"yellow3",
"blue2",
"magenta3",
"cyan3",
"gray90",
/* 8 bright colors */
"gray50",
"red",
"green",
"yellow",
"#5c5cff",
"magenta",
"cyan",
"white",
[255] = 0,
/* more colors can be added after 255 to use with DefaultXX */
"#cccccc",
"#555555",
/* Terminal colors (16 used in escape sequence) */
static const char *palettes[][16] = {
{"black", "red3", "green3", "yellow3", "blue2", "magenta3", "cyan3", "gray90",
"gray50", "red", "green", "yellow", "#5c5cff", "magenta", "cyan", "white"},
{"#223", "#900", "#080", "#fe7", "#35e", "#fc5", "#18e", "#aaa",
"#666", "#f25", "#0b0", "#ff6", "#46f", "#d6a", "#6bf", "#ddd"},
{"#eaeaea", "#b7141f", "#457b24", "#fc7b08", "#134eb2", "#560088", "#0e717c", "#777777",
"#424242", "#e83b3f", "#7aba3a", "#fd8e09", "#54a4f3", "#aa4dbc", "#26bbd1", "#aaaaaa"},
{"#20242d", "#b04b57", "#87b379", "#e5c179", "#7d8fa4", "#a47996", "#85a7a5", "#b3b8c3",
"#000000", "#b04b57", "#87b379", "#e5c179", "#7d8fa4", "#a47996", "#85a7a5", "#ffffff"},
};
static const char **colorname;
/*
* Default colors (colorname index)
* foreground, background, cursor, reverse cursor
*/
unsigned int defaultfg = 7;
unsigned int defaultfg = 1;
unsigned int defaultbg = 0;
unsigned int defaultcs = 256;
static unsigned int defaultrcs = 257;
static unsigned int defaultcs = 1;
static unsigned int defaultrcs = 1;
/*
* Default shape of cursor
@ -207,24 +164,30 @@ static MouseShortcut mshortcuts[] = {
#define TERMMOD (ControlMask|ShiftMask)
static Shortcut shortcuts[] = {
/* mask keysym function argument */
{ XK_ANY_MOD, XK_Break, sendbreak, {.i = 0} },
{ ControlMask, XK_Print, toggleprinter, {.i = 0} },
{ ShiftMask, XK_Print, printscreen, {.i = 0} },
{ XK_ANY_MOD, XK_Print, printsel, {.i = 0} },
{ MODKEY, XK_Prior, zoom, {.f = +1} },
{ MODKEY, XK_Next, zoom, {.f = -1} },
{ MODKEY, XK_Home, zoomreset, {.f = 0} },
{ TERMMOD, XK_C, clipcopy, {.i = 0} },
{ TERMMOD, XK_V, clippaste, {.i = 0} },
{ TERMMOD, XK_Y, selpaste, {.i = 0} },
{ ShiftMask, XK_Page_Up, kscrollup, {.i = -1} },
{ ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} },
{ ShiftMask, XK_Insert, selpaste, {.i = 0} },
{ MODKEY, XK_Num_Lock, numlock, {.i = 0} },
{ MODKEY, XK_bracketleft, chgalpha, {.f = -1} }, /* Decrease opacity */
{ MODKEY|ShiftMask, XK_braceright, chgalpha, {.f = +1} }, /* Increase opacity */
{ MODKEY, XK_bracketright,chgalpha, {.f = 0} }, /* Reset opacity */
/* mask keysym function argument */
{XK_ANY_MOD, XK_Break, sendbreak, {.i = 0}},
{ControlMask, XK_Print, toggleprinter, {.i = 0}},
{ShiftMask, XK_Print, printscreen, {.i = 0}},
{XK_ANY_MOD, XK_Print, printsel, {.i = 0}},
{TERMMOD, XK_Prior, zoom, {.f = +1}},
{TERMMOD, XK_Next, zoom, {.f = -1}},
{TERMMOD, XK_Home, zoomreset, {.f = 0}},
{TERMMOD, XK_C, clipcopy, {.i = 0}},
{TERMMOD, XK_V, clippaste, {.i = 0}},
{TERMMOD, XK_Y, selpaste, {.i = 0}},
{ShiftMask, XK_Page_Up, kscrollup, {.i = -1}},
{ShiftMask, XK_Page_Down, kscrolldown, {.i = -1}},
{ShiftMask, XK_Insert, selpaste, {.i = 0}},
{TERMMOD, XK_Num_Lock, numlock, {.i = 0}},
{MODKEY | ShiftMask, XK_F1, setpalette, {.i = 0}},
{MODKEY | ShiftMask, XK_F2, setpalette, {.i = 1}},
{MODKEY | ShiftMask, XK_F3, setpalette, {.i = 2}},
{MODKEY | ShiftMask, XK_F4, setpalette, {.i = 3}},
{MODKEY | ShiftMask, XK_F5, setpalette, {.i = 4}},
{MODKEY | ShiftMask, XK_F6, setpalette, {.i = 5}},
{MODKEY | ShiftMask, XK_F7, setpalette, {.i = 6}},
{MODKEY | ShiftMask, XK_F8, setpalette, {.i = 7}},
{MODKEY | ShiftMask, XK_F9, setpalette, {.i = 8}},
};
/*

View File

@ -1,10 +1,10 @@
# st version
VERSION = 0.8.5
VERSION = 0.8.3
# Customize below to fit your system
# paths
PREFIX = /usr/local
PREFIX = $(HOME)
MANPREFIX = $(PREFIX)/share/man
X11INC = /usr/X11R6/include
@ -15,24 +15,21 @@ PKG_CONFIG = pkg-config
# includes and libs
INCS = -I$(X11INC) \
`$(PKG_CONFIG) --cflags fontconfig` \
`$(PKG_CONFIG) --cflags freetype2` \
`$(PKG_CONFIG) --cflags harfbuzz`
`$(PKG_CONFIG) --cflags freetype2`
LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender\
`$(PKG_CONFIG) --libs fontconfig` \
`$(PKG_CONFIG) --libs freetype2` \
`$(PKG_CONFIG) --libs harfbuzz`
`$(PKG_CONFIG) --libs freetype2`
# flags
STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600
STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS)
STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS) -ggdb
STLDFLAGS = $(LIBS) $(LDFLAGS)
# OpenBSD:
#CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 -D_BSD_SOURCE
#LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft \
# `$(PKG_CONFIG) --libs fontconfig` \
# `$(PKG_CONFIG) --libs freetype2`
#MANPREFIX = ${PREFIX}/man
# `pkg-config --libs fontconfig` \
# `pkg-config --libs freetype2`
# compiler and linker
# CC = c99

148
hb.c
View File

@ -1,148 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <X11/Xft/Xft.h>
#include <hb.h>
#include <hb-ft.h>
#include "st.h"
#define FEATURE(c1,c2,c3,c4) { .tag = HB_TAG(c1,c2,c3,c4), .value = 1, .start = HB_FEATURE_GLOBAL_START, .end = HB_FEATURE_GLOBAL_END }
void hbtransformsegment(XftFont *xfont, const Glyph *string, hb_codepoint_t *codepoints, int start, int length);
hb_font_t *hbfindfont(XftFont *match);
typedef struct {
XftFont *match;
hb_font_t *font;
} HbFontMatch;
static int hbfontslen = 0;
static HbFontMatch *hbfontcache = NULL;
/*
* Replace 0 with a list of font features, wrapped in FEATURE macro, e.g.
* FEATURE('c', 'a', 'l', 't'), FEATURE('d', 'l', 'i', 'g')
*/
hb_feature_t features[] = { 0 };
void
hbunloadfonts()
{
for (int i = 0; i < hbfontslen; i++) {
hb_font_destroy(hbfontcache[i].font);
XftUnlockFace(hbfontcache[i].match);
}
if (hbfontcache != NULL) {
free(hbfontcache);
hbfontcache = NULL;
}
hbfontslen = 0;
}
hb_font_t *
hbfindfont(XftFont *match)
{
for (int i = 0; i < hbfontslen; i++) {
if (hbfontcache[i].match == match)
return hbfontcache[i].font;
}
/* Font not found in cache, caching it now. */
hbfontcache = realloc(hbfontcache, sizeof(HbFontMatch) * (hbfontslen + 1));
FT_Face face = XftLockFace(match);
hb_font_t *font = hb_ft_font_create(face, NULL);
if (font == NULL)
die("Failed to load Harfbuzz font.");
hbfontcache[hbfontslen].match = match;
hbfontcache[hbfontslen].font = font;
hbfontslen += 1;
return font;
}
void
hbtransform(XftGlyphFontSpec *specs, const Glyph *glyphs, size_t len, int x, int y)
{
int start = 0, length = 1, gstart = 0;
hb_codepoint_t *codepoints = calloc((unsigned int)len, sizeof(hb_codepoint_t));
for (int idx = 1, specidx = 1; idx < len; idx++) {
if (glyphs[idx].mode & ATTR_WDUMMY) {
length += 1;
continue;
}
if (specs[specidx].font != specs[start].font || ATTRCMP(glyphs[gstart], glyphs[idx]) || selected(x + idx, y) != selected(x + gstart, y)) {
hbtransformsegment(specs[start].font, glyphs, codepoints, gstart, length);
/* Reset the sequence. */
length = 1;
start = specidx;
gstart = idx;
} else {
length += 1;
}
specidx++;
}
/* EOL. */
hbtransformsegment(specs[start].font, glyphs, codepoints, gstart, length);
/* Apply the transformation to glyph specs. */
for (int i = 0, specidx = 0; i < len; i++) {
if (glyphs[i].mode & ATTR_WDUMMY)
continue;
if (glyphs[i].mode & ATTR_BOXDRAW) {
specidx++;
continue;
}
if (codepoints[i] != specs[specidx].glyph)
((Glyph *)glyphs)[i].mode |= ATTR_LIGA;
specs[specidx++].glyph = codepoints[i];
}
free(codepoints);
}
void
hbtransformsegment(XftFont *xfont, const Glyph *string, hb_codepoint_t *codepoints, int start, int length)
{
hb_font_t *font = hbfindfont(xfont);
if (font == NULL)
return;
Rune rune;
ushort mode = USHRT_MAX;
hb_buffer_t *buffer = hb_buffer_create();
hb_buffer_set_direction(buffer, HB_DIRECTION_LTR);
/* Fill buffer with codepoints. */
for (int i = start; i < (start+length); i++) {
rune = string[i].u;
mode = string[i].mode;
if (mode & ATTR_WDUMMY)
rune = 0x0020;
hb_buffer_add_codepoints(buffer, &rune, 1, 0, 1);
}
/* Shape the segment. */
hb_shape(font, buffer, features, sizeof(features));
/* Get new glyph info. */
hb_glyph_info_t *info = hb_buffer_get_glyph_infos(buffer, NULL);
/* Write new codepoints. */
for (int i = 0; i < length; i++) {
hb_codepoint_t gid = info[i].codepoint;
codepoints[start+i] = gid;
}
/* Cleanup. */
hb_buffer_destroy(buffer);
}

6
hb.h
View File

@ -1,6 +0,0 @@
#include <X11/Xft/Xft.h>
#include <hb.h>
#include <hb-ft.h>
void hbunloadfonts();
void hbtransform(XftGlyphFontSpec *, const Glyph *, size_t, int, int);

View File

@ -1,194 +0,0 @@
diff --git a/st/config.def.h b/st_patched/config.def.h
index 91ab8ca..59fc2a9 100644
--- a/config.def.h
+++ b/config.def.h
@@ -93,6 +93,10 @@ char *termname = "st-256color";
*/
unsigned int tabspaces = 8;
+/* bg opacity */
+float alpha = 0.8;
+float alpha_def;
+
/* Terminal colors (16 first used in escape sequence) */
static const char *colorname[] = {
/* 8 normal colors */
@@ -201,6 +205,9 @@ static Shortcut shortcuts[] = {
{ TERMMOD, XK_Y, selpaste, {.i = 0} },
{ ShiftMask, XK_Insert, selpaste, {.i = 0} },
{ TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
+ { MODKEY, XK_bracketleft, chgalpha, {.f = -1} }, /* Decrease opacity */
+ { MODKEY|ShiftMask, XK_braceright, chgalpha, {.f = +1} }, /* Increase opacity */
+ { MODKEY, XK_bracketright,chgalpha, {.f = 0} }, /* Reset opacity */
};
/*
diff --git a/st/st.h b/st_patched/st.h
index fd3b0d8..cda8c13 100644
--- a/st.h
+++ b/st.h
@@ -124,3 +124,4 @@ extern unsigned int tabspaces;
extern unsigned int defaultfg;
extern unsigned int defaultbg;
extern unsigned int defaultcs;
+extern float alpha, alpha_def;
diff --git a/st/config.mk b/st_patched/config.mk
index 1e306f8..47c615e 100644
--- a/config.mk
+++ b/config.mk
@@ -16,7 +16,7 @@ PKG_CONFIG = pkg-config
INCS = -I$(X11INC) \
`$(PKG_CONFIG) --cflags fontconfig` \
`$(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 freetype2`
diff --git a/st/x.c b/st_patched/x.c
index aa09997..3b05a55 100644
--- a/x.c
+++ b/x.c
@@ -59,6 +59,7 @@ static void zoom(const Arg *);
static void zoomabs(const Arg *);
static void zoomreset(const Arg *);
static void ttysend(const Arg *);
+static void chgalpha(const Arg *);
/* config.h for applying patches and the configuration. */
#include "config.h"
@@ -105,6 +106,7 @@ typedef struct {
XSetWindowAttributes attrs;
int scr;
int isfixed; /* is fixed geometry? */
+ int depth; /* bit depth */
int l, t; /* left and top offset */
int gm; /* geometry mask */
} XWindow;
@@ -243,6 +245,7 @@ static char *usedfont = NULL;
static double usedfontsize = 0;
static double defaultfontsize = 0;
+static char *opt_alpha = NULL;
static char *opt_class = NULL;
static char **opt_cmd = NULL;
static char *opt_embed = NULL;
@@ -752,7 +755,7 @@ xresize(int col, int row)
XFreePixmap(xw.dpy, xw.buf);
xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
- DefaultDepth(xw.dpy, xw.scr));
+ xw.depth);
XftDrawChange(xw.draw, xw.buf);
xclear(0, 0, win.w, win.h);
@@ -812,6 +815,13 @@ xloadcols(void)
else
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;
}
@@ -1134,11 +1144,23 @@ xinit(int cols, int rows)
Window parent;
pid_t thispid = getpid();
XColor xmousefg, xmousebg;
+ XWindowAttributes attr;
+ XVisualInfo vis;
if (!(xw.dpy = XOpenDisplay(NULL)))
die("can't open display\n");
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 */
if (!FcInit())
@@ -1147,8 +1169,11 @@ xinit(int cols, int rows)
usedfont = (opt_font == NULL)? font : opt_font;
xloadfonts(usedfont, 0);
+ /* Backup default alpha value */
+ alpha_def = alpha;
+
/* colors */
- xw.cmap = XDefaultColormap(xw.dpy, xw.scr);
+ xw.cmap = XCreateColormap(xw.dpy, parent, xw.vis, None);
xloadcols();
/* adjust fixed window geometry */
@@ -1168,19 +1193,15 @@ xinit(int cols, int rows)
| ButtonMotionMask | ButtonPressMask | ButtonReleaseMask;
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,
- win.w, win.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput,
+ win.w, win.h, 0, xw.depth, InputOutput,
xw.vis, CWBackPixel | CWBorderPixel | CWBitGravity
| CWEventMask | CWColormap, &xw.attrs);
memset(&gcvalues, 0, sizeof(gcvalues));
gcvalues.graphics_exposures = False;
- dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures,
- &gcvalues);
- xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
- DefaultDepth(xw.dpy, xw.scr));
+ xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, xw.depth);
+ dc.gc = XCreateGC(xw.dpy, xw.buf, GCGraphicsExposures, &gcvalues);
XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel);
XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h);
@@ -1371,6 +1392,24 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
return numspecs;
}
+void
+chgalpha(const Arg *arg)
+{
+ if (arg->f == -1.0f && alpha >= 0.1f)
+ alpha -= 0.1f;
+ else if (arg->f == 1.0f && alpha < 1.0f)
+ alpha += 0.1f;
+ else if (arg->f == 0.0f)
+ alpha = alpha_def;
+ else
+ return;
+
+ dc.col[defaultbg].color.alpha = (unsigned short)(0xFFFF * alpha);
+ /* Required to remove artifacting from borderpx */
+ cresize(0, 0);
+ redraw();
+}
+
void
xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y)
{
@@ -2038,6 +2077,9 @@ main(int argc, char *argv[])
case 'a':
allowaltscreen = 0;
break;
+ case 'A':
+ opt_alpha = EARGF(usage());
+ break;
case 'c':
opt_class = EARGF(usage());
break;

235
st.c
View File

@ -39,7 +39,7 @@
/* macros */
#define IS_SET(flag) ((term.mode & (flag)) != 0)
#define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == 0x7f)
#define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == '\177')
#define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f))
#define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
#define ISDELIM(u) (u && wcschr(worddelimiters, u))
@ -55,6 +55,7 @@ enum term_mode {
MODE_ECHO = 1 << 4,
MODE_PRINT = 1 << 5,
MODE_UTF8 = 1 << 6,
MODE_SIXEL = 1 << 7,
};
enum cursor_movement {
@ -81,11 +82,12 @@ enum charset {
enum escape_state {
ESC_START = 1,
ESC_CSI = 2,
ESC_STR = 4, /* DCS, OSC, PM, APC */
ESC_STR = 4, /* OSC, PM, APC */
ESC_ALTCHARSET = 8,
ESC_STR_END = 16, /* a final string was encountered */
ESC_TEST = 32, /* Enter in test mode */
ESC_UTF8 = 64,
ESC_DCS =128,
};
typedef struct {
@ -134,7 +136,6 @@ typedef struct {
int charset; /* current charset */
int icharset; /* selected charset for sequence */
int *tabs;
Rune lastc; /* last printed char outside of sequence, 0 if control */
} Term;
/* CSI Escape sequence structs */
@ -168,7 +169,6 @@ static void csidump(void);
static void csihandle(void);
static void csiparse(void);
static void csireset(void);
static void osc_color_response(int, int, int);
static int eschandle(uchar);
static void strdump(void);
static void strhandle(void);
@ -194,18 +194,18 @@ static void tputc(Rune);
static void treset(void);
static void tscrollup(int, int, int);
static void tscrolldown(int, int, int);
static void tsetattr(const int *, int);
static void tsetchar(Rune, const Glyph *, int, int);
static void tsetattr(int *, int);
static void tsetchar(Rune, Glyph *, int, int);
static void tsetdirt(int, int);
static void tsetscroll(int, int);
static void tswapscreen(void);
static void tsetmode(int, int, const int *, int);
static void tsetmode(int, int, int *, int);
static int twrite(const char *, int, int);
static void tfulldirt(void);
static void tcontrolcode(uchar );
static void tdectest(char );
static void tdefutf8(char);
static int32_t tdefcolor(const int *, int *, int);
static int32_t tdefcolor(int *, int *, int);
static void tdeftran(char);
static void tstrsequence(uchar);
@ -234,10 +234,10 @@ static int iofd = 1;
static int cmdfd;
static pid_t pid;
static const uchar utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
static const uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
static const Rune utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000};
static const Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
static uchar utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
static uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
static Rune utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000};
static Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
ssize_t
xwrite(int fd, const char *s, size_t len)
@ -277,14 +277,12 @@ xrealloc(void *p, size_t len)
}
char *
xstrdup(const char *s)
xstrdup(char *s)
{
char *p;
if ((p = strdup(s)) == NULL)
if ((s = strdup(s)) == NULL)
die("strdup: %s\n", strerror(errno));
return p;
return s;
}
size_t
@ -357,10 +355,25 @@ utf8validate(Rune *u, size_t i)
return i;
}
static const char base64_digits[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0,
63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, -1, 0, 0, 0, 0, 1,
2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34,
35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
char
base64dec_getc(const char **src)
{
while (**src && !isprint((unsigned char)**src))
while (**src && !isprint(**src))
(*src)++;
return **src ? *((*src)++) : '='; /* emulate padding if string ends */
}
@ -370,13 +383,6 @@ base64dec(const char *src)
{
size_t in_len = strlen(src);
char *result, *dst;
static const char base64_digits[256] = {
[43] = 62, 0, 0, 0, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
0, 0, 0, -1, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0,
0, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
};
if (in_len % 4)
in_len += 4 - (in_len % 4);
@ -520,7 +526,7 @@ selsnap(int *x, int *y, int direction)
{
int newx, newy, xt, yt;
int delim, prevdelim;
const Glyph *gp, *prevgp;
Glyph *gp, *prevgp;
switch (sel.snap) {
case SNAP_WORD:
@ -593,7 +599,7 @@ getsel(void)
{
char *str, *ptr;
int y, bufsize, lastx, linelen;
const Glyph *gp, *last;
Glyph *gp, *last;
if (sel.ob.x == -1)
return NULL;
@ -635,8 +641,7 @@ getsel(void)
* st.
* FIXME: Fix the computer world.
*/
if ((y < sel.ne.y || lastx >= linelen) &&
(!(last->mode & ATTR_WRAP) || sel.type == SEL_RECTANGULAR))
if ((y < sel.ne.y || lastx >= linelen) && !(last->mode & ATTR_WRAP))
*ptr++ = '\n';
}
*ptr = 0;
@ -732,7 +737,7 @@ sigchld(int a)
die("child exited with status %d\n", WEXITSTATUS(stat));
else if (WIFSIGNALED(stat))
die("child terminated due to signal %d\n", WTERMSIG(stat));
_exit(0);
exit(0);
}
void
@ -760,7 +765,7 @@ stty(char **args)
}
int
ttynew(const char *line, char *cmd, const char *out, char **args)
ttynew(char *line, char *cmd, char *out, char **args)
{
int m, s;
@ -793,15 +798,14 @@ ttynew(const char *line, char *cmd, const char *out, char **args)
break;
case 0:
close(iofd);
close(m);
setsid(); /* create a new process group */
dup2(s, 0);
dup2(s, 1);
dup2(s, 2);
if (ioctl(s, TIOCSCTTY, NULL) < 0)
die("ioctl TIOCSCTTY failed: %s\n", strerror(errno));
if (s > 2)
close(s);
close(s);
close(m);
#ifdef __OpenBSD__
if (pledge("stdio getpw proc exec", NULL) == -1)
die("pledge\n");
@ -844,6 +848,7 @@ ttyread(void)
if (buflen > 0)
memmove(buf, buf + written, buflen);
return ret;
}
}
@ -1158,17 +1163,27 @@ selscroll(int orig, int n)
if (sel.ob.x == -1)
return;
if (BETWEEN(sel.nb.y, orig, term.bot) != BETWEEN(sel.ne.y, orig, term.bot)) {
selclear();
} else if (BETWEEN(sel.nb.y, orig, term.bot)) {
sel.ob.y += n;
sel.oe.y += n;
if (sel.ob.y < term.top || sel.ob.y > term.bot ||
sel.oe.y < term.top || sel.oe.y > term.bot) {
if (BETWEEN(sel.ob.y, orig, term.bot) || BETWEEN(sel.oe.y, orig, term.bot)) {
if ((sel.ob.y += n) > term.bot || (sel.oe.y += n) < term.top) {
selclear();
} else {
selnormalize();
return;
}
if (sel.type == SEL_RECTANGULAR) {
if (sel.ob.y < term.top)
sel.ob.y = term.top;
if (sel.oe.y > term.bot)
sel.oe.y = term.bot;
} else {
if (sel.ob.y < term.top) {
sel.ob.y = term.top;
sel.ob.x = 0;
}
if (sel.oe.y > term.bot) {
sel.oe.y = term.bot;
sel.oe.x = term.col;
}
}
selnormalize();
}
}
@ -1240,9 +1255,9 @@ tmoveto(int x, int y)
}
void
tsetchar(Rune u, const Glyph *attr, int x, int y)
tsetchar(Rune u, Glyph *attr, int x, int y)
{
static const char *vt100_0[62] = { /* 0x41 - 0x7e */
static char *vt100_0[62] = { /* 0x41 - 0x7e */
"", "", "", "", "", "", "", /* A - G */
0, 0, 0, 0, 0, 0, 0, 0, /* H - O */
0, 0, 0, 0, 0, 0, 0, 0, /* P - W */
@ -1273,9 +1288,6 @@ tsetchar(Rune u, const Glyph *attr, int x, int y)
term.dirty[y] = 1;
term.line[y][x] = *attr;
term.line[y][x].u = u;
if (isboxdraw(u))
term.line[y][x].mode |= ATTR_BOXDRAW;
}
void
@ -1357,7 +1369,7 @@ tdeleteline(int n)
}
int32_t
tdefcolor(const int *attr, int *npar, int l)
tdefcolor(int *attr, int *npar, int l)
{
int32_t idx = -1;
uint r, g, b;
@ -1407,7 +1419,7 @@ tdefcolor(const int *attr, int *npar, int l)
}
void
tsetattr(const int *attr, int l)
tsetattr(int *attr, int l)
{
int i;
int32_t idx;
@ -1525,9 +1537,9 @@ tsetscroll(int t, int b)
}
void
tsetmode(int priv, int set, const int *args, int narg)
tsetmode(int priv, int set, int *args, int narg)
{
int alt; const int *lim;
int alt, *lim;
for (lim = args + narg; args < lim; ++args) {
if (priv) {
@ -1703,12 +1715,6 @@ csihandle(void)
if (csiescseq.arg[0] == 0)
ttywrite(vtiden, strlen(vtiden), 0);
break;
case 'b': /* REP -- if last char is printable print it <n> more times */
DEFAULT(csiescseq.arg[0], 1);
if (term.lastc)
while (csiescseq.arg[0]-- > 0)
tputc(term.lastc);
break;
case 'C': /* CUF -- Cursor <n> Forward */
case 'a': /* HPR -- Cursor <n> Forward */
DEFAULT(csiescseq.arg[0], 1);
@ -1832,7 +1838,7 @@ csihandle(void)
break;
case 'n': /* DSR Device Status Report (cursor position) */
if (csiescseq.arg[0] == 6) {
len = snprintf(buf, sizeof(buf), "\033[%i;%iR",
len = snprintf(buf, sizeof(buf),"\033[%i;%iR",
term.c.y+1, term.c.x+1);
ttywrite(buf, len, 0);
}
@ -1896,41 +1902,11 @@ csireset(void)
memset(&csiescseq, 0, sizeof(csiescseq));
}
void
osc_color_response(int num, int index, int is_osc4)
{
int n;
char buf[32];
unsigned char r, g, b;
if (xgetcolor(is_osc4 ? num : index, &r, &g, &b)) {
fprintf(stderr, "erresc: failed to fetch %s color %d\n",
is_osc4 ? "osc4" : "osc",
is_osc4 ? num : index);
return;
}
n = snprintf(buf, sizeof buf, "\033]%s%d;rgb:%02x%02x/%02x%02x/%02x%02x\007",
is_osc4 ? "4;" : "", num, r, r, g, g, b, b);
if (n < 0 || n >= sizeof(buf)) {
fprintf(stderr, "error: %s while printing %s response\n",
n < 0 ? "snprintf failed" : "truncation occurred",
is_osc4 ? "osc4" : "osc");
} else {
ttywrite(buf, n, 1);
}
}
void
strhandle(void)
{
char *p = NULL, *dec;
int j, narg, par;
const struct { int idx; char *str; } osc_table[] = {
{ defaultfg, "foreground" },
{ defaultbg, "background" },
{ defaultcs, "cursor" }
};
term.esc &= ~(ESC_STR_END|ESC_STR);
strparse();
@ -1940,21 +1916,13 @@ strhandle(void)
case ']': /* OSC -- Operating System Command */
switch (par) {
case 0:
if (narg > 1) {
xsettitle(strescseq.args[1]);
xseticontitle(strescseq.args[1]);
}
return;
case 1:
if (narg > 1)
xseticontitle(strescseq.args[1]);
return;
case 2:
if (narg > 1)
xsettitle(strescseq.args[1]);
return;
case 52:
if (narg > 2 && allowwindowops) {
if (narg > 2) {
dec = base64dec(strescseq.args[2]);
if (dec) {
xsetsel(dec);
@ -1964,35 +1932,14 @@ strhandle(void)
}
}
return;
case 10:
case 11:
case 12:
if (narg < 2)
break;
p = strescseq.args[1];
if ((j = par - 10) < 0 || j >= LEN(osc_table))
break; /* shouldn't be possible */
if (!strcmp(p, "?")) {
osc_color_response(par, osc_table[j].idx, 0);
} else if (xsetcolorname(osc_table[j].idx, p)) {
fprintf(stderr, "erresc: invalid %s color: %s\n",
osc_table[j].str, p);
} else {
tfulldirt();
}
return;
case 4: /* color set */
if (narg < 3)
break;
p = strescseq.args[2];
/* FALLTHROUGH */
case 104: /* color reset */
case 104: /* color reset, here p = NULL */
j = (narg > 1) ? atoi(strescseq.args[1]) : -1;
if (p && !strcmp(p, "?")) {
osc_color_response(j, 0, 1);
} else if (xsetcolorname(j, p)) {
if (xsetcolorname(j, p)) {
if (par == 104 && narg <= 1)
return; /* color reset without parameter */
fprintf(stderr, "erresc: invalid color j=%d, p=%s\n",
@ -2002,7 +1949,7 @@ strhandle(void)
* TODO if defaultbg color is changed, borders
* are dirty
*/
tfulldirt();
redraw();
}
return;
}
@ -2011,6 +1958,7 @@ strhandle(void)
xsettitle(strescseq.args[0]);
return;
case 'P': /* DCS -- Device Control String */
term.mode |= ESC_DCS;
case '_': /* APC -- Application Program Command */
case '^': /* PM -- Privacy Message */
return;
@ -2128,12 +2076,12 @@ void
tdumpline(int n)
{
char buf[UTF_SIZ];
const Glyph *bp, *end;
Glyph *bp, *end;
bp = &term.line[n][0];
end = &bp[MIN(tlinelen(n), term.col) - 1];
if (bp != end || bp->u != ' ') {
for ( ; bp <= end; ++bp)
for ( ;bp <= end; ++bp)
tprinter(buf, utf8encode(bp->u, buf));
}
tprinter("\n", 1);
@ -2204,9 +2152,12 @@ tdectest(char c)
void
tstrsequence(uchar c)
{
strreset();
switch (c) {
case 0x90: /* DCS -- Device Control String */
c = 'P';
term.esc |= ESC_DCS;
break;
case 0x9f: /* APC -- Application Program Command */
c = '_';
@ -2218,7 +2169,6 @@ tstrsequence(uchar c)
c = ']';
break;
}
strreset();
strescseq.type = c;
term.esc |= ESC_STR;
}
@ -2261,7 +2211,6 @@ tcontrolcode(uchar ascii)
return;
case '\032': /* SUB */
tsetchar('?', &term.c.attr, term.c.x, term.c.y);
/* FALLTHROUGH */
case '\030': /* CAN */
csireset();
break;
@ -2416,13 +2365,15 @@ tputc(Rune u)
Glyph *gp;
control = ISCONTROL(u);
if (u < 127 || !IS_SET(MODE_UTF8)) {
if (!IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) {
c[0] = u;
width = len = 1;
} else {
len = utf8encode(u, c);
if (!control && (width = wcwidth(u)) == -1)
if (!control && (width = wcwidth(u)) == -1) {
memcpy(c, "\357\277\275", 4); /* UTF_INVALID */
width = 1;
}
}
if (IS_SET(MODE_PRINT))
@ -2437,11 +2388,23 @@ tputc(Rune u)
if (term.esc & ESC_STR) {
if (u == '\a' || u == 030 || u == 032 || u == 033 ||
ISCONTROLC1(u)) {
term.esc &= ~(ESC_START|ESC_STR);
term.esc &= ~(ESC_START|ESC_STR|ESC_DCS);
if (IS_SET(MODE_SIXEL)) {
/* TODO: render sixel */;
term.mode &= ~MODE_SIXEL;
return;
}
term.esc |= ESC_STR_END;
goto check_control_code;
}
if (IS_SET(MODE_SIXEL)) {
/* TODO: implement sixel mode */
return;
}
if (term.esc&ESC_DCS && strescseq.len == 0 && u == 'q')
term.mode |= MODE_SIXEL;
if (strescseq.len+len >= strescseq.siz) {
/*
* Here is a bug in terminals. If the user never sends
@ -2478,8 +2441,6 @@ check_control_code:
/*
* control codes are not shown ever
*/
if (!term.esc)
term.lastc = 0;
return;
} else if (term.esc & ESC_START) {
if (term.esc & ESC_CSI) {
@ -2510,7 +2471,7 @@ check_control_code:
*/
return;
}
if (selected(term.c.x, term.c.y))
if (sel.ob.x != -1 && BETWEEN(term.c.y, sel.ob.y, sel.oe.y))
selclear();
gp = &term.line[term.c.y][term.c.x];
@ -2529,15 +2490,10 @@ check_control_code:
}
tsetchar(u, &term.c.attr, term.c.x, term.c.y);
term.lastc = u;
if (width == 2) {
gp->mode |= ATTR_WIDE;
if (term.c.x+1 < term.col) {
if (gp[1].mode == ATTR_WIDE && term.c.x+2 < term.col) {
gp[2].u = ' ';
gp[2].mode &= ~ATTR_WDUMMY;
}
gp[1].u = '\0';
gp[1].mode = ATTR_WDUMMY;
}
@ -2557,7 +2513,7 @@ twrite(const char *buf, int buflen, int show_ctrl)
int n;
for (n = 0; n < buflen; n += charsize) {
if (IS_SET(MODE_UTF8)) {
if (IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) {
/* process a complete utf8 char */
charsize = utf8decode(buf + n, &u, buflen - n);
if (charsize == 0)
@ -2710,8 +2666,7 @@ draw(void)
drawregion(0, 0, term.col, term.row);
if (term.scr == 0)
xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
term.ocx, term.ocy, term.line[term.ocy][term.ocx],
term.line[term.ocy], term.col);
term.ocx, term.ocy, term.line[term.ocy][term.ocx]);
term.ocx = cx;
term.ocy = term.c.y;
xfinishdraw();

View File

@ -1,8 +0,0 @@
[Desktop Entry]
Name=st
Comment=st is a simple terminal implementation for X
Exec=st
Icon=utilities-terminal
Terminal=false
Type=Application
Categories=System;TerminalEmulator;

21
st.h
View File

@ -11,8 +11,7 @@
#define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d))
#define DEFAULT(a, b) (a) = (a) ? (a) : (b)
#define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x)
#define ATTRCMP(a, b) (((a).mode & (~ATTR_WRAP) & (~ATTR_LIGA)) != ((b).mode & (~ATTR_WRAP) & (~ATTR_LIGA)) || \
(a).fg != (b).fg || \
#define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || \
(a).bg != (b).bg)
#define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + \
(t1.tv_nsec-t2.tv_nsec)/1E6)
@ -34,8 +33,6 @@ enum glyph_attribute {
ATTR_WRAP = 1 << 8,
ATTR_WIDE = 1 << 9,
ATTR_WDUMMY = 1 << 10,
ATTR_BOXDRAW = 1 << 11,
ATTR_LIGA = 1 << 12,
ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
};
@ -96,7 +93,7 @@ void tnew(int, int);
void tresize(int, int);
void tsetdirtattr(int);
void ttyhangup(void);
int ttynew(const char *, char *, const char *, char **);
int ttynew(char *, char *, char *, char **);
size_t ttyread(void);
void ttyresize(int, int);
void ttywrite(const char *, size_t, int);
@ -114,15 +111,7 @@ size_t utf8encode(Rune, char *);
void *xmalloc(size_t);
void *xrealloc(void *, size_t);
char *xstrdup(const char *);
int isboxdraw(Rune);
ushort boxdrawindex(const Glyph *);
#ifdef XFT_VERSION
/* only exposed to x.c, otherwise we'll need Xft.h for the types */
void boxdraw_xinit(Display *, Colormap, XftDraw *, Visual *);
void drawboxes(int, int, int, int, XftColor *, XftColor *, const XftGlyphFontSpec *, int);
#endif
char *xstrdup(char *);
/* config.h globals */
extern char *utmp;
@ -131,12 +120,8 @@ extern char *stty_args;
extern char *vtiden;
extern wchar_t *worddelimiters;
extern int allowaltscreen;
extern int allowwindowops;
extern char *termname;
extern unsigned int tabspaces;
extern unsigned int defaultfg;
extern unsigned int defaultbg;
extern unsigned int defaultcs;
extern float alpha, alpha_def;
extern const int boxdraw, boxdraw_bold, boxdraw_braille;
extern float alpha;

View File

@ -158,7 +158,6 @@ st-mono| simpleterm monocolor,
rc=\E8,
rev=\E[7m,
ri=\EM,
rin=\E[%p1%dT,
ritm=\E[23m,
rmacs=\E(B,
rmcup=\E[?1049l,
@ -184,8 +183,6 @@ st-mono| simpleterm monocolor,
# XTerm extensions
rmxx=\E[29m,
smxx=\E[9m,
# disabled rep for now: causes some issues with older ncurses versions.
# rep=%p1%c\E[%p2%{1}%-%db,
# tmux extensions, see TERMINFO EXTENSIONS in tmux(1)
Tc,
Ms=\E]52;%p1%s;%p2%s\007,

4
win.h
View File

@ -25,13 +25,11 @@ enum win_mode {
void xbell(void);
void xclipcopy(void);
void xdrawcursor(int, int, Glyph, int, int, Glyph, Line, int);
void xdrawcursor(int, int, Glyph, int, int, Glyph);
void xdrawline(Line, int, int, int);
void xfinishdraw(void);
void xloadcols(void);
int xsetcolorname(int, const char *);
int xgetcolor(int, unsigned char *, unsigned char *, unsigned char *);
void xseticontitle(char *);
void xsettitle(char *);
int xsetcursor(int);
void xsetmode(int, unsigned int);

421
x.c
View File

@ -19,7 +19,6 @@ char *argv0;
#include "arg.h"
#include "st.h"
#include "win.h"
#include "hb.h"
/* types used in config.h */
typedef struct {
@ -49,7 +48,7 @@ typedef struct {
/* X modifiers */
#define XK_ANY_MOD UINT_MAX
#define XK_NO_MOD 0
#define XK_SWITCH_MOD (1<<13|1<<14)
#define XK_SWITCH_MOD (1<<13)
/* function definitions used in config.h */
static void clipcopy(const Arg *);
@ -59,8 +58,8 @@ static void selpaste(const Arg *);
static void zoom(const Arg *);
static void zoomabs(const Arg *);
static void zoomreset(const Arg *);
static void setpalette(const Arg *);
static void ttysend(const Arg *);
static void chgalpha(const Arg *);
/* config.h for applying patches and the configuration. */
#include "config.h"
@ -83,7 +82,6 @@ typedef XftGlyphFontSpec GlyphFontSpec;
typedef struct {
int tw, th; /* tty width and height */
int w, h; /* window width and height */
int hborderpx, vborderpx;
int ch; /* char height */
int cw; /* char width */
int mode; /* window state/mode flags */
@ -96,7 +94,7 @@ typedef struct {
Window win;
Drawable buf;
GlyphFontSpec *specbuf; /* font spec buffer used for rendering */
Atom xembed, wmdeletewin, netwmname, netwmiconname, netwmpid;
Atom xembed, wmdeletewin, netwmname, netwmpid;
struct {
XIM xim;
XIC xic;
@ -160,7 +158,7 @@ static void xresize(int, int);
static void xhints(void);
static int xloadcolor(int, const char *, Color *);
static int xloadfont(Font *, FcPattern *);
static void xloadfonts(const char *, double);
static void xloadfonts(char *, double);
static void xunloadfont(Font *);
static void xunloadfonts(void);
static void xsetenv(void);
@ -257,7 +255,7 @@ static char *opt_line = NULL;
static char *opt_name = NULL;
static char *opt_title = NULL;
static uint buttons; /* bit field of pressed buttons */
static int oldbutton = 3; /* button event on startup: 3 = release */
void
clipcopy(const Arg *dummy)
@ -336,7 +334,7 @@ ttysend(const Arg *arg)
int
evcol(XEvent *e)
{
int x = e->xbutton.x - win.hborderpx;
int x = e->xbutton.x - borderpx;
LIMIT(x, 0, win.tw - 1);
return x / win.cw;
}
@ -344,7 +342,7 @@ evcol(XEvent *e)
int
evrow(XEvent *e)
{
int y = e->xbutton.y - win.vborderpx;
int y = e->xbutton.y - borderpx;
LIMIT(y, 0, win.th - 1);
return y / win.ch;
}
@ -369,68 +367,59 @@ mousesel(XEvent *e, int done)
void
mousereport(XEvent *e)
{
int len, btn, code;
int x = evcol(e), y = evrow(e);
int state = e->xbutton.state;
int len, x = evcol(e), y = evrow(e),
button = e->xbutton.button, state = e->xbutton.state;
char buf[40];
static int ox, oy;
if (e->type == MotionNotify) {
/* from urxvt */
if (e->xbutton.type == MotionNotify) {
if (x == ox && y == oy)
return;
if (!IS_SET(MODE_MOUSEMOTION) && !IS_SET(MODE_MOUSEMANY))
return;
/* MODE_MOUSEMOTION: no reporting if no button is pressed */
if (IS_SET(MODE_MOUSEMOTION) && buttons == 0)
/* MOUSE_MOTION: no reporting if no button is pressed */
if (IS_SET(MODE_MOUSEMOTION) && oldbutton == 3)
return;
/* Set btn to lowest-numbered pressed button, or 12 if no
* buttons are pressed. */
for (btn = 1; btn <= 11 && !(buttons & (1<<(btn-1))); btn++)
;
code = 32;
button = oldbutton + 32;
ox = x;
oy = y;
} else {
btn = e->xbutton.button;
/* Only buttons 1 through 11 can be encoded */
if (btn < 1 || btn > 11)
return;
if (e->type == ButtonRelease) {
if (!IS_SET(MODE_MOUSESGR) && e->xbutton.type == ButtonRelease) {
button = 3;
} else {
button -= Button1;
if (button >= 3)
button += 64 - 3;
}
if (e->xbutton.type == ButtonPress) {
oldbutton = button;
ox = x;
oy = y;
} else if (e->xbutton.type == ButtonRelease) {
oldbutton = 3;
/* MODE_MOUSEX10: no button release reporting */
if (IS_SET(MODE_MOUSEX10))
return;
/* Don't send release events for the scroll wheel */
if (btn == 4 || btn == 5)
if (button == 64 || button == 65)
return;
}
code = 0;
}
ox = x;
oy = y;
/* Encode btn into code. If no button is pressed for a motion event in
* MODE_MOUSEMANY, then encode it as a release. */
if ((!IS_SET(MODE_MOUSESGR) && e->type == ButtonRelease) || btn == 12)
code += 3;
else if (btn >= 8)
code += 128 + btn - 8;
else if (btn >= 4)
code += 64 + btn - 4;
else
code += btn - 1;
if (!IS_SET(MODE_MOUSEX10)) {
code += ((state & ShiftMask ) ? 4 : 0)
+ ((state & Mod1Mask ) ? 8 : 0) /* meta key: alt */
+ ((state & ControlMask) ? 16 : 0);
button += ((state & ShiftMask ) ? 4 : 0)
+ ((state & Mod4Mask ) ? 8 : 0)
+ ((state & ControlMask) ? 16 : 0);
}
if (IS_SET(MODE_MOUSESGR)) {
len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c",
code, x+1, y+1,
e->type == ButtonRelease ? 'm' : 'M');
button, x+1, y+1,
e->xbutton.type == ButtonRelease ? 'm' : 'M');
} else if (x < 223 && y < 223) {
len = snprintf(buf, sizeof(buf), "\033[M%c%c%c",
32+code, 32+x+1, 32+y+1);
32+button, 32+x+1, 32+y+1);
} else {
return;
}
@ -473,13 +462,9 @@ mouseaction(XEvent *e, uint release)
void
bpress(XEvent *e)
{
int btn = e->xbutton.button;
struct timespec now;
int snap;
if (1 <= btn && btn <= 11)
buttons |= 1 << (btn-1);
if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) {
mousereport(e);
return;
@ -488,7 +473,7 @@ bpress(XEvent *e)
if (mouseaction(e, 0))
return;
if (btn == Button1) {
if (e->xbutton.button == Button1) {
/*
* If the user clicks below predefined timeouts specific
* snapping behaviour is exposed.
@ -702,11 +687,6 @@ xsetsel(char *str)
void
brelease(XEvent *e)
{
int btn = e->xbutton.button;
if (1 <= btn && btn <= 11)
buttons &= ~(1 << (btn-1));
if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) {
mousereport(e);
return;
@ -714,7 +694,7 @@ brelease(XEvent *e)
if (mouseaction(e, 1))
return;
if (btn == Button1)
if (e->xbutton.button == Button1)
mousesel(e, 1);
}
@ -744,9 +724,6 @@ cresize(int width, int height)
col = MAX(1, col);
row = MAX(1, row);
win.hborderpx = (win.w - col * win.cw) / 2;
win.vborderpx = (win.h - row * win.ch) / 2;
tresize(col, row);
xresize(col, row);
ttyresize(win.tw, win.th);
@ -777,24 +754,7 @@ sixd_to_16bit(int x)
int
xloadcolor(int i, const char *name, Color *ncolor)
{
XRenderColor color = { .alpha = 0xffff };
if (!name) {
if (BETWEEN(i, 16, 255)) { /* 256 color */
if (i < 6*6*6+16) { /* same colors as xterm */
color.red = sixd_to_16bit( ((i-16)/36)%6 );
color.green = sixd_to_16bit( ((i-16)/6) %6 );
color.blue = sixd_to_16bit( ((i-16)/1) %6 );
} else { /* greyscale */
color.red = 0x0808 + 0x0a0a * (i - (6*6*6+16));
color.green = color.blue = color.red;
}
return XftColorAllocValue(xw.dpy, xw.vis,
xw.cmap, &color, ncolor);
} else
name = colorname[i];
}
if (!name) name = colorname[i];
return XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, ncolor);
}
@ -805,11 +765,11 @@ xloadcols(void)
static int loaded;
Color *cp;
dc.collen = 16;
if (loaded) {
for (cp = dc.col; cp < &dc.col[dc.collen]; ++cp)
XftColorFree(xw.dpy, xw.vis, xw.cmap, cp);
} else {
dc.collen = MAX(LEN(colorname), 256);
dc.col = xmalloc(dc.collen * sizeof(Color));
}
@ -830,19 +790,6 @@ xloadcols(void)
loaded = 1;
}
int
xgetcolor(int x, unsigned char *r, unsigned char *g, unsigned char *b)
{
if (!BETWEEN(x, 0, dc.collen))
return 1;
*r = dc.col[x].color.red >> 8;
*g = dc.col[x].color.green >> 8;
*b = dc.col[x].color.blue >> 8;
return 0;
}
int
xsetcolorname(int x, const char *name)
{
@ -884,8 +831,8 @@ xhints(void)
sizeh->flags = PSize | PResizeInc | PBaseSize | PMinSize;
sizeh->height = win.h;
sizeh->width = win.w;
sizeh->height_inc = 1;
sizeh->width_inc = 1;
sizeh->height_inc = win.ch;
sizeh->width_inc = win.cw;
sizeh->base_height = 2 * borderpx;
sizeh->base_width = 2 * borderpx;
sizeh->min_height = win.ch + 2 * borderpx;
@ -996,7 +943,7 @@ xloadfont(Font *f, FcPattern *pattern)
}
void
xloadfonts(const char *fontstr, double fontsize)
xloadfonts(char *fontstr, double fontsize)
{
FcPattern *pattern;
double fontval;
@ -1004,7 +951,7 @@ xloadfonts(const char *fontstr, double fontsize)
if (fontstr[0] == '-')
pattern = XftXlfdParse(fontstr, False, False);
else
pattern = FcNameParse((const FcChar8 *)fontstr);
pattern = FcNameParse((FcChar8 *)fontstr);
if (!pattern)
die("can't open font %s\n", fontstr);
@ -1077,9 +1024,6 @@ xunloadfont(Font *f)
void
xunloadfonts(void)
{
/* Clear Harfbuzz font cache. */
hbunloadfonts();
/* Free the loaded fonts in the font cache. */
while (frclen > 0)
XftFontClose(xw.dpy, frc[--frclen].font);
@ -1177,16 +1121,13 @@ xinit(int cols, int rows)
usedfont = (opt_font == NULL)? font : opt_font;
xloadfonts(usedfont, 0);
/* Backup default alpha value */
alpha_def = alpha;
/* colors */
xw.cmap = XCreateColormap(xw.dpy, parent, xw.vis, None);
xloadcols();
/* adjust fixed window geometry */
win.w = 2 * win.hborderpx + cols * win.cw;
win.h = 2 * win.vborderpx + rows * win.ch;
win.w = 2 * borderpx + cols * win.cw;
win.h = 2 * borderpx + rows * win.ch;
if (xw.gm & XNegative)
xw.l += DisplayWidth(xw.dpy, xw.scr) - win.w - 2;
if (xw.gm & YNegative)
@ -1246,7 +1187,6 @@ xinit(int cols, int rows)
xw.xembed = XInternAtom(xw.dpy, "_XEMBED", False);
xw.wmdeletewin = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False);
xw.netwmname = XInternAtom(xw.dpy, "_NET_WM_NAME", False);
xw.netwmiconname = XInternAtom(xw.dpy, "_NET_WM_ICON_NAME", False);
XSetWMProtocols(xw.dpy, xw.win, &xw.wmdeletewin, 1);
xw.netwmpid = XInternAtom(xw.dpy, "_NET_WM_PID", False);
@ -1266,14 +1206,12 @@ xinit(int cols, int rows)
xsel.xtarget = XInternAtom(xw.dpy, "UTF8_STRING", 0);
if (xsel.xtarget == None)
xsel.xtarget = XA_STRING;
boxdraw_xinit(xw.dpy, xw.cmap, xw.draw, xw.vis);
}
int
xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y)
{
float winx = win.hborderpx + x * win.cw, winy = win.vborderpx + y * win.ch, xp, yp;
float winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, xp, yp;
ushort mode, prevmode = USHRT_MAX;
Font *font = &dc.font;
int frcflags = FRC_NORMAL;
@ -1292,7 +1230,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
mode = glyphs[i].mode;
/* Skip dummy wide-character spacing. */
if (mode & ATTR_WDUMMY)
if (mode == ATTR_WDUMMY)
continue;
/* Determine font for glyph if different from previous glyph. */
@ -1314,13 +1252,8 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
yp = winy + font->ascent;
}
if (mode & ATTR_BOXDRAW) {
/* minor shoehorning: boxdraw uses only this ushort */
glyphidx = boxdrawindex(&glyphs[i]);
} else {
/* Lookup character index with default font. */
glyphidx = XftCharIndex(xw.dpy, font->match, rune);
}
/* Lookup character index with default font. */
glyphidx = XftCharIndex(xw.dpy, font->match, rune);
if (glyphidx) {
specs[numspecs].font = font->match;
specs[numspecs].glyph = glyphidx;
@ -1404,40 +1337,14 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
numspecs++;
}
/* Harfbuzz transformation for ligatures. */
hbtransform(specs, glyphs, len, x, y);
return numspecs;
}
void
chgalpha(const Arg *arg)
{
if (arg->f == -1.0f && alpha >= 0.1f)
alpha -= 0.1f;
else if (arg->f == 1.0f && alpha < 1.0f)
alpha += 0.1f;
else if (arg->f == 0.0f)
alpha = alpha_def;
else
return;
if(alpha < 0)
alpha = 0;
if(alpha > 1)
alpha = 1;
dc.col[defaultbg].color.alpha = (unsigned short)(0xFFFF * alpha);
/* Required to remove artifacting from borderpx */
cresize(0, 0);
redraw();
}
void
xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y)
{
int charlen = len * ((base.mode & ATTR_WIDE) ? 2 : 1);
int winx = win.hborderpx + x * win.cw, winy = win.vborderpx + y * win.ch,
int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch,
width = charlen * win.cw;
Color *fg, *bg, *temp, revfg, revbg, truefg, truebg;
XRenderColor colfg, colbg;
@ -1527,17 +1434,17 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
/* Intelligent cleaning up of the borders. */
if (x == 0) {
xclear(0, (y == 0)? 0 : winy, win.vborderpx,
xclear(0, (y == 0)? 0 : winy, borderpx,
winy + win.ch +
((winy + win.ch >= win.vborderpx + win.th)? win.h : 0));
((winy + win.ch >= borderpx + win.th)? win.h : 0));
}
if (winx + width >= win.hborderpx + win.tw) {
if (winx + width >= borderpx + win.tw) {
xclear(winx + width, (y == 0)? 0 : winy, win.w,
((winy + win.ch >= win.vborderpx + win.th)? win.h : (winy + win.ch)));
((winy + win.ch >= borderpx + win.th)? win.h : (winy + win.ch)));
}
if (y == 0)
xclear(winx, 0, winx + width, win.hborderpx);
if (winy + win.ch >= win.vborderpx + win.th)
xclear(winx, 0, winx + width, borderpx);
if (winy + win.ch >= borderpx + win.th)
xclear(winx, winy + win.ch, winx + width, win.h);
/* Clean up the region we want to draw to. */
@ -1550,21 +1457,17 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
r.width = width;
XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1);
if (base.mode & ATTR_BOXDRAW) {
drawboxes(winx, winy, width / len, win.ch, fg, bg, specs, len);
} else {
/* Render the glyphs. */
XftDrawGlyphFontSpec(xw.draw, fg, specs, len);
}
/* Render the glyphs. */
XftDrawGlyphFontSpec(xw.draw, fg, specs, len);
/* Render underline and strikethrough. */
if (base.mode & ATTR_UNDERLINE) {
XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent * chscale + 1,
XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1,
width, 1);
}
if (base.mode & ATTR_STRUCK) {
XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent * chscale / 3,
XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent / 3,
width, 1);
}
@ -1583,17 +1486,14 @@ xdrawglyph(Glyph g, int x, int y)
}
void
xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og, Line line, int len)
xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
{
Color drawcol;
/* remove the old cursor */
if (selected(ox, oy))
og.mode ^= ATTR_REVERSE;
/* Redraw the line where cursor was previously.
* It will restore the ligatures broken by the cursor. */
xdrawline(line, 0, oy, len);
xdrawglyph(og, ox, oy);
if (IS_SET(MODE_HIDE))
return;
@ -1601,7 +1501,7 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og, Line line, int le
/*
* Select the right color for the right mode.
*/
g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE|ATTR_BOXDRAW;
g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE;
if (IS_SET(MODE_REVERSE)) {
g.mode |= ATTR_REVERSE;
@ -1627,9 +1527,8 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og, Line line, int le
/* draw the new one */
if (IS_SET(MODE_FOCUSED)) {
switch (win.cursor) {
case 7: /* st extension */
g.u = 0x2603; /* snowman (U+2603) */
/* FALLTHROUGH */
case 7: /* st extension: snowman (U+2603) */
g.u = 0x2603;
case 0: /* Blinking Block */
case 1: /* Blinking Block (Default) */
case 2: /* Steady Block */
@ -1638,35 +1537,35 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og, Line line, int le
case 3: /* Blinking Underline */
case 4: /* Steady Underline */
XftDrawRect(xw.draw, &drawcol,
win.hborderpx + cx * win.cw,
win.vborderpx + (cy + 1) * win.ch - \
borderpx + cx * win.cw,
borderpx + (cy + 1) * win.ch - \
cursorthickness,
win.cw, cursorthickness);
break;
case 5: /* Blinking bar */
case 6: /* Steady bar */
XftDrawRect(xw.draw, &drawcol,
win.hborderpx + cx * win.cw,
win.vborderpx + cy * win.ch,
borderpx + cx * win.cw,
borderpx + cy * win.ch,
cursorthickness, win.ch);
break;
}
} else {
XftDrawRect(xw.draw, &drawcol,
win.hborderpx + cx * win.cw,
win.vborderpx + cy * win.ch,
borderpx + cx * win.cw,
borderpx + cy * win.ch,
win.cw - 1, 1);
XftDrawRect(xw.draw, &drawcol,
win.hborderpx + cx * win.cw,
win.vborderpx + cy * win.ch,
borderpx + cx * win.cw,
borderpx + cy * win.ch,
1, win.ch - 1);
XftDrawRect(xw.draw, &drawcol,
win.hborderpx + (cx + 1) * win.cw - 1,
win.vborderpx + cy * win.ch,
borderpx + (cx + 1) * win.cw - 1,
borderpx + cy * win.ch,
1, win.ch - 1);
XftDrawRect(xw.draw, &drawcol,
win.hborderpx + cx * win.cw,
win.vborderpx + (cy + 1) * win.ch - 1,
borderpx + cx * win.cw,
borderpx + (cy + 1) * win.ch - 1,
win.cw, 1);
}
}
@ -1680,29 +1579,14 @@ xsetenv(void)
setenv("WINDOWID", buf, 1);
}
void
xseticontitle(char *p)
{
XTextProperty prop;
DEFAULT(p, opt_title);
if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
&prop) != Success)
return;
XSetWMIconName(xw.dpy, xw.win, &prop);
XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmiconname);
XFree(prop.value);
}
void
xsettitle(char *p)
{
XTextProperty prop;
DEFAULT(p, opt_title);
if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
&prop) != Success)
return;
Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
&prop);
XSetWMName(xw.dpy, xw.win, &prop);
XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmname);
XFree(prop.value);
@ -1806,7 +1690,8 @@ xsetmode(int set, unsigned int flags)
int
xsetcursor(int cursor)
{
if (!BETWEEN(cursor, 0, 7)) /* 7: st extension */
DEFAULT(cursor, 1);
if (!BETWEEN(cursor, 0, 6))
return 1;
win.cursor = cursor;
return 0;
@ -1983,9 +1868,10 @@ run(void)
XEvent ev;
int w = win.w, h = win.h;
fd_set rfd;
int xfd = XConnectionNumber(xw.dpy), ttyfd, xev, drawing;
struct timespec seltv, *tv, now, lastblink, trigger;
double timeout;
int xfd = XConnectionNumber(xw.dpy), xev, blinkset = 0, dodraw = 0;
int ttyfd;
struct timespec drawtimeout, *tv = NULL, now, last, lastblink;
long deltatime;
/* Waiting for window mapping */
do {
@ -2006,77 +1892,82 @@ run(void)
ttyfd = ttynew(opt_line, shell, opt_io, opt_cmd);
cresize(w, h);
for (timeout = -1, drawing = 0, lastblink = (struct timespec){0};;) {
clock_gettime(CLOCK_MONOTONIC, &last);
lastblink = last;
for (xev = actionfps;;) {
FD_ZERO(&rfd);
FD_SET(ttyfd, &rfd);
FD_SET(xfd, &rfd);
if (XPending(xw.dpy))
timeout = 0; /* existing events might not set xfd */
seltv.tv_sec = timeout / 1E3;
seltv.tv_nsec = 1E6 * (timeout - 1E3 * seltv.tv_sec);
tv = timeout >= 0 ? &seltv : NULL;
if (pselect(MAX(xfd, ttyfd)+1, &rfd, NULL, NULL, tv, NULL) < 0) {
if (errno == EINTR)
continue;
die("select failed: %s\n", strerror(errno));
}
clock_gettime(CLOCK_MONOTONIC, &now);
if (FD_ISSET(ttyfd, &rfd))
if (FD_ISSET(ttyfd, &rfd)) {
ttyread();
xev = 0;
while (XPending(xw.dpy)) {
xev = 1;
XNextEvent(xw.dpy, &ev);
if (XFilterEvent(&ev, None))
continue;
if (handler[ev.type])
(handler[ev.type])(&ev);
}
/*
* To reduce flicker and tearing, when new content or event
* triggers drawing, we first wait a bit to ensure we got
* everything, and if nothing new arrives - we draw.
* We start with trying to wait minlatency ms. If more content
* arrives sooner, we retry with shorter and shorter periods,
* and eventually draw even without idle after maxlatency ms.
* Typically this results in low latency while interacting,
* maximum latency intervals during `cat huge.txt`, and perfect
* sync with periodic updates from animations/key-repeats/etc.
*/
if (FD_ISSET(ttyfd, &rfd) || xev) {
if (!drawing) {
trigger = now;
drawing = 1;
}
timeout = (maxlatency - TIMEDIFF(now, trigger)) \
/ maxlatency * minlatency;
if (timeout > 0)
continue; /* we have time, try to find idle */
}
/* idle detected or maxlatency exhausted -> draw */
timeout = -1;
if (blinktimeout && tattrset(ATTR_BLINK)) {
timeout = blinktimeout - TIMEDIFF(now, lastblink);
if (timeout <= 0) {
if (-timeout > blinktimeout) /* start visible */
win.mode |= MODE_BLINK;
win.mode ^= MODE_BLINK;
tsetdirtattr(ATTR_BLINK);
lastblink = now;
timeout = blinktimeout;
if (blinktimeout) {
blinkset = tattrset(ATTR_BLINK);
if (!blinkset)
MODBIT(win.mode, 0, MODE_BLINK);
}
}
draw();
XFlush(xw.dpy);
drawing = 0;
if (FD_ISSET(xfd, &rfd))
xev = actionfps;
clock_gettime(CLOCK_MONOTONIC, &now);
drawtimeout.tv_sec = 0;
drawtimeout.tv_nsec = (1000 * 1E6)/ xfps;
tv = &drawtimeout;
dodraw = 0;
if (blinktimeout && TIMEDIFF(now, lastblink) > blinktimeout) {
tsetdirtattr(ATTR_BLINK);
win.mode ^= MODE_BLINK;
lastblink = now;
dodraw = 1;
}
deltatime = TIMEDIFF(now, last);
if (deltatime > 1000 / (xev ? xfps : actionfps)) {
dodraw = 1;
last = now;
}
if (dodraw) {
while (XPending(xw.dpy)) {
XNextEvent(xw.dpy, &ev);
if (XFilterEvent(&ev, None))
continue;
if (handler[ev.type])
(handler[ev.type])(&ev);
}
draw();
XFlush(xw.dpy);
if (xev && !FD_ISSET(xfd, &rfd))
xev--;
if (!FD_ISSET(ttyfd, &rfd) && !FD_ISSET(xfd, &rfd)) {
if (blinkset) {
if (TIMEDIFF(now, lastblink) \
> blinktimeout) {
drawtimeout.tv_nsec = 1000;
} else {
drawtimeout.tv_nsec = (1E6 * \
(blinktimeout - \
TIMEDIFF(now,
lastblink)));
}
drawtimeout.tv_sec = \
drawtimeout.tv_nsec / 1E9;
drawtimeout.tv_nsec %= (long)1E9;
} else {
tv = NULL;
}
}
}
}
}
@ -2093,12 +1984,20 @@ usage(void)
" [stty_args ...]\n", argv0, argv0);
}
void setpalette(const Arg *arg) {
if ( arg->i < LEN(palettes) ) {
colorname = palettes[arg->i];
xloadcols();
cresize(win.w, win.h);
}
}
int
main(int argc, char *argv[])
{
xw.l = xw.t = 0;
xw.isfixed = False;
xsetcursor(cursorshape);
win.cursor = cursorshape;
ARGBEGIN {
case 'a':
@ -2148,6 +2047,8 @@ main(int argc, char *argv[])
} ARGEND;
run:
colorname = palettes[0];
if (argc > 0) /* eat all remaining arguments */
opt_cmd = argv;