Compare commits
60 Commits
Author | SHA1 | Date | |
---|---|---|---|
f29671710e | |||
9b955a39da | |||
ca1a520e02 | |||
a32f6523c2 | |||
|
693e5b5ae0 | ||
977d6dc561 | |||
674fe00d8f | |||
1318eabdac | |||
d7c0775cbf | |||
|
baa9357e96 | ||
|
8629d9a1da | ||
|
ef0551932f | ||
|
af3bb68add | ||
|
2aefa348ba | ||
|
e823e2308f | ||
|
2c5edf28ec | ||
|
b1d97fec47 | ||
|
ea7cd7b62f | ||
|
7fb0c0cc68 | ||
|
7e1c68f25d | ||
|
65f1dc4283 | ||
|
a0467c802d | ||
|
273db5ceaf | ||
|
8e31030390 | ||
|
2f6e597ed8 | ||
|
1d3142da96 | ||
|
2ec571a30c | ||
|
819f8ea7c2 | ||
a7305631cb | |||
|
4536f46cff | ||
|
9e68fdbcdb | ||
|
4ef0cbd8b9 | ||
|
28b4c822c5 | ||
|
6f57f9765a | ||
|
fa253f077f | ||
|
b27a383a3a | ||
|
81067c65ea | ||
|
f74a9df6e1 | ||
|
818ec746f4 | ||
|
9ba7ecf7b1 | ||
|
ca60bab842 | ||
|
c3ab6c67e4 | ||
|
a2a704492b | ||
|
0f8b40652b | ||
|
e6e2c6199f | ||
|
94b8ec0021 | ||
|
dec6b530a4 | ||
|
475a0a36cb | ||
|
e8392b282c | ||
|
f8afebdfa0 | ||
|
bda9c9ffa6 | ||
|
045a0fab4f | ||
|
9c30066e73 | ||
|
8304d4f059 | ||
|
914fb825df | ||
|
cde480c693 | ||
|
8211e36d28 | ||
|
87545c612e | ||
|
1d59091065 | ||
|
d6ea0a1a61 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
st
|
||||
*.o
|
||||
*.orig
|
||||
.idea/
|
||||
|
63
FAQ
63
FAQ
@ -2,12 +2,14 @@
|
||||
|
||||
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 doesn’t 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 they’re running in xterm i.e. they don’t rely on
|
||||
@ -15,6 +17,7 @@ you can manually run `tic -sx st.info`.
|
||||
* Some programs don’t 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.
|
||||
@ -23,10 +26,12 @@ 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 patch 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 path 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?
|
||||
|
||||
@ -83,12 +88,14 @@ 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
|
||||
@ -97,6 +104,7 @@ 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
|
||||
@ -158,19 +166,60 @@ 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)?
|
||||
|
||||
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.
|
||||
## 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);
|
||||
|
||||
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
|
||||
|
||||
|
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
||||
MIT/X Consortium License
|
||||
|
||||
© 2014-2018 Hiltjo Posthuma <hiltjo at codemadness dot org>
|
||||
© 2014-2022 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>
|
||||
|
9
Makefile
9
Makefile
@ -4,7 +4,7 @@
|
||||
|
||||
include config.mk
|
||||
|
||||
SRC = st.c x.c
|
||||
SRC = st.c x.c boxdraw.c hb.c
|
||||
OBJ = $(SRC:.c=.o)
|
||||
|
||||
all: options st
|
||||
@ -22,7 +22,9 @@ config.h:
|
||||
$(CC) $(STCFLAGS) -c $<
|
||||
|
||||
st.o: config.h st.h win.h
|
||||
x.o: arg.h 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
|
||||
|
||||
$(OBJ): config.h config.mk
|
||||
|
||||
@ -50,9 +52,12 @@ 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
Normal file
194
boxdraw.c
Normal file
@ -0,0 +1,194 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
214
boxdraw_data.h
Normal file
214
boxdraw_data.h
Normal file
@ -0,0 +1,214 @@
|
||||
/*
|
||||
* 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) */
|
||||
};
|
42
config.def.h
42
config.def.h
@ -43,9 +43,18 @@ static unsigned int tripleclicktimeout = 600;
|
||||
/* alt screens */
|
||||
int allowaltscreen = 1;
|
||||
|
||||
/* frames per second st should at maximum draw to the screen */
|
||||
static unsigned int xfps = 120;
|
||||
static unsigned int actionfps = 30;
|
||||
/* 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;
|
||||
|
||||
/*
|
||||
* blinking timeout (set to 0 to disable blinking) for the terminal blinking
|
||||
@ -58,6 +67,18 @@ 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
|
||||
@ -86,6 +107,7 @@ 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[] = {
|
||||
@ -114,7 +136,8 @@ static const char *colorname[] = {
|
||||
/* more colors can be added after 255 to use with DefaultXX */
|
||||
"#cccccc",
|
||||
"#555555",
|
||||
"black",
|
||||
"gray90", /* default foreground colour */
|
||||
"black", /* default background colour */
|
||||
};
|
||||
|
||||
|
||||
@ -122,9 +145,9 @@ static const char *colorname[] = {
|
||||
* Default colors (colorname index)
|
||||
* foreground, background, cursor, reverse cursor
|
||||
*/
|
||||
unsigned int defaultfg = 7;
|
||||
unsigned int defaultbg = 258;
|
||||
static unsigned int defaultcs = 256;
|
||||
unsigned int defaultfg = 258;
|
||||
unsigned int defaultbg = 259;
|
||||
unsigned int defaultcs = 256;
|
||||
static unsigned int defaultrcs = 257;
|
||||
|
||||
/*
|
||||
@ -170,7 +193,9 @@ 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"} },
|
||||
};
|
||||
|
||||
@ -194,6 +219,9 @@ 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 */
|
||||
};
|
||||
|
||||
/*
|
||||
|
44
config.h
44
config.h
@ -5,7 +5,7 @@
|
||||
*
|
||||
* font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
|
||||
*/
|
||||
static char *font = "Liberation Mono:pixelsize=18:antialias=true:autohint=true";
|
||||
static char *font = "FiraCode:pixelsize=18:antialias=true:autohint=true";
|
||||
static int borderpx = 0;
|
||||
|
||||
/*
|
||||
@ -43,6 +43,20 @@ 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;
|
||||
@ -58,6 +72,18 @@ 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
|
||||
@ -85,7 +111,8 @@ char *termname = "st-256color";
|
||||
unsigned int tabspaces = 8;
|
||||
|
||||
/* bg opacity */
|
||||
float alpha = 0.7;
|
||||
float alpha = 0.85;
|
||||
float alpha_def;
|
||||
|
||||
/* Terminal colors (16 first used in escape sequence) */
|
||||
static const char *colorname[] = {
|
||||
@ -123,7 +150,7 @@ static const char *colorname[] = {
|
||||
*/
|
||||
unsigned int defaultfg = 7;
|
||||
unsigned int defaultbg = 0;
|
||||
static unsigned int defaultcs = 256;
|
||||
unsigned int defaultcs = 256;
|
||||
static unsigned int defaultrcs = 257;
|
||||
|
||||
/*
|
||||
@ -185,16 +212,19 @@ static Shortcut shortcuts[] = {
|
||||
{ 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} },
|
||||
{ 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} },
|
||||
{ TERMMOD, XK_Num_Lock, numlock, {.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 */
|
||||
};
|
||||
|
||||
/*
|
||||
|
15
config.mk
15
config.mk
@ -1,10 +1,10 @@
|
||||
# st version
|
||||
VERSION = 0.8.3
|
||||
VERSION = 0.8.5
|
||||
|
||||
# Customize below to fit your system
|
||||
|
||||
# paths
|
||||
PREFIX = $(HOME)
|
||||
PREFIX = /usr/local
|
||||
MANPREFIX = $(PREFIX)/share/man
|
||||
|
||||
X11INC = /usr/X11R6/include
|
||||
@ -15,10 +15,12 @@ PKG_CONFIG = pkg-config
|
||||
# includes and libs
|
||||
INCS = -I$(X11INC) \
|
||||
`$(PKG_CONFIG) --cflags fontconfig` \
|
||||
`$(PKG_CONFIG) --cflags freetype2`
|
||||
`$(PKG_CONFIG) --cflags freetype2` \
|
||||
`$(PKG_CONFIG) --cflags harfbuzz`
|
||||
LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender\
|
||||
`$(PKG_CONFIG) --libs fontconfig` \
|
||||
`$(PKG_CONFIG) --libs freetype2`
|
||||
`$(PKG_CONFIG) --libs freetype2` \
|
||||
`$(PKG_CONFIG) --libs harfbuzz`
|
||||
|
||||
# flags
|
||||
STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600
|
||||
@ -28,8 +30,9 @@ 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`
|
||||
# `$(PKG_CONFIG) --libs fontconfig` \
|
||||
# `$(PKG_CONFIG) --libs freetype2`
|
||||
#MANPREFIX = ${PREFIX}/man
|
||||
|
||||
# compiler and linker
|
||||
# CC = c99
|
||||
|
148
hb.c
Normal file
148
hb.c
Normal file
@ -0,0 +1,148 @@
|
||||
#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
Normal file
6
hb.h
Normal file
@ -0,0 +1,6 @@
|
||||
#include <X11/Xft/Xft.h>
|
||||
#include <hb.h>
|
||||
#include <hb-ft.h>
|
||||
|
||||
void hbunloadfonts();
|
||||
void hbtransform(XftGlyphFontSpec *, const Glyph *, size_t, int, int);
|
194
patches/st-alpha-changealpha-20230519-b44f2ad.diff
Normal file
194
patches/st-alpha-changealpha-20230519-b44f2ad.diff
Normal file
@ -0,0 +1,194 @@
|
||||
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;
|
233
st.c
233
st.c
@ -39,7 +39,7 @@
|
||||
|
||||
/* macros */
|
||||
#define IS_SET(flag) ((term.mode & (flag)) != 0)
|
||||
#define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == '\177')
|
||||
#define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == 0x7f)
|
||||
#define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f))
|
||||
#define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
|
||||
#define ISDELIM(u) (u && wcschr(worddelimiters, u))
|
||||
@ -55,7 +55,6 @@ enum term_mode {
|
||||
MODE_ECHO = 1 << 4,
|
||||
MODE_PRINT = 1 << 5,
|
||||
MODE_UTF8 = 1 << 6,
|
||||
MODE_SIXEL = 1 << 7,
|
||||
};
|
||||
|
||||
enum cursor_movement {
|
||||
@ -82,12 +81,11 @@ enum charset {
|
||||
enum escape_state {
|
||||
ESC_START = 1,
|
||||
ESC_CSI = 2,
|
||||
ESC_STR = 4, /* OSC, PM, APC */
|
||||
ESC_STR = 4, /* DCS, 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 {
|
||||
@ -136,6 +134,7 @@ 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 */
|
||||
@ -169,6 +168,7 @@ 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(int *, int);
|
||||
static void tsetchar(Rune, Glyph *, int, int);
|
||||
static void tsetattr(const int *, int);
|
||||
static void tsetchar(Rune, const Glyph *, int, int);
|
||||
static void tsetdirt(int, int);
|
||||
static void tsetscroll(int, int);
|
||||
static void tswapscreen(void);
|
||||
static void tsetmode(int, int, int *, int);
|
||||
static void tsetmode(int, int, const 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(int *, int *, int);
|
||||
static int32_t tdefcolor(const 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 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};
|
||||
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};
|
||||
|
||||
ssize_t
|
||||
xwrite(int fd, const char *s, size_t len)
|
||||
@ -277,12 +277,14 @@ xrealloc(void *p, size_t len)
|
||||
}
|
||||
|
||||
char *
|
||||
xstrdup(char *s)
|
||||
xstrdup(const char *s)
|
||||
{
|
||||
if ((s = strdup(s)) == NULL)
|
||||
char *p;
|
||||
|
||||
if ((p = strdup(s)) == NULL)
|
||||
die("strdup: %s\n", strerror(errno));
|
||||
|
||||
return s;
|
||||
return p;
|
||||
}
|
||||
|
||||
size_t
|
||||
@ -355,25 +357,10 @@ 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(**src))
|
||||
while (**src && !isprint((unsigned char)**src))
|
||||
(*src)++;
|
||||
return **src ? *((*src)++) : '='; /* emulate padding if string ends */
|
||||
}
|
||||
@ -383,6 +370,13 @@ 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);
|
||||
@ -526,7 +520,7 @@ selsnap(int *x, int *y, int direction)
|
||||
{
|
||||
int newx, newy, xt, yt;
|
||||
int delim, prevdelim;
|
||||
Glyph *gp, *prevgp;
|
||||
const Glyph *gp, *prevgp;
|
||||
|
||||
switch (sel.snap) {
|
||||
case SNAP_WORD:
|
||||
@ -599,7 +593,7 @@ getsel(void)
|
||||
{
|
||||
char *str, *ptr;
|
||||
int y, bufsize, lastx, linelen;
|
||||
Glyph *gp, *last;
|
||||
const Glyph *gp, *last;
|
||||
|
||||
if (sel.ob.x == -1)
|
||||
return NULL;
|
||||
@ -641,7 +635,8 @@ getsel(void)
|
||||
* st.
|
||||
* FIXME: Fix the computer world.
|
||||
*/
|
||||
if ((y < sel.ne.y || lastx >= linelen) && !(last->mode & ATTR_WRAP))
|
||||
if ((y < sel.ne.y || lastx >= linelen) &&
|
||||
(!(last->mode & ATTR_WRAP) || sel.type == SEL_RECTANGULAR))
|
||||
*ptr++ = '\n';
|
||||
}
|
||||
*ptr = 0;
|
||||
@ -737,7 +732,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
|
||||
@ -765,7 +760,7 @@ stty(char **args)
|
||||
}
|
||||
|
||||
int
|
||||
ttynew(char *line, char *cmd, char *out, char **args)
|
||||
ttynew(const char *line, char *cmd, const char *out, char **args)
|
||||
{
|
||||
int m, s;
|
||||
|
||||
@ -798,14 +793,15 @@ ttynew(char *line, char *cmd, 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));
|
||||
close(s);
|
||||
close(m);
|
||||
if (s > 2)
|
||||
close(s);
|
||||
#ifdef __OpenBSD__
|
||||
if (pledge("stdio getpw proc exec", NULL) == -1)
|
||||
die("pledge\n");
|
||||
@ -848,7 +844,6 @@ ttyread(void)
|
||||
if (buflen > 0)
|
||||
memmove(buf, buf + written, buflen);
|
||||
return ret;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -1163,27 +1158,17 @@ selscroll(int orig, int n)
|
||||
if (sel.ob.x == -1)
|
||||
return;
|
||||
|
||||
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) {
|
||||
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) {
|
||||
selclear();
|
||||
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();
|
||||
}
|
||||
selnormalize();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1255,9 +1240,9 @@ tmoveto(int x, int y)
|
||||
}
|
||||
|
||||
void
|
||||
tsetchar(Rune u, Glyph *attr, int x, int y)
|
||||
tsetchar(Rune u, const Glyph *attr, int x, int y)
|
||||
{
|
||||
static char *vt100_0[62] = { /* 0x41 - 0x7e */
|
||||
static const 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 */
|
||||
@ -1288,6 +1273,9 @@ tsetchar(Rune u, 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
|
||||
@ -1369,7 +1357,7 @@ tdeleteline(int n)
|
||||
}
|
||||
|
||||
int32_t
|
||||
tdefcolor(int *attr, int *npar, int l)
|
||||
tdefcolor(const int *attr, int *npar, int l)
|
||||
{
|
||||
int32_t idx = -1;
|
||||
uint r, g, b;
|
||||
@ -1419,7 +1407,7 @@ tdefcolor(int *attr, int *npar, int l)
|
||||
}
|
||||
|
||||
void
|
||||
tsetattr(int *attr, int l)
|
||||
tsetattr(const int *attr, int l)
|
||||
{
|
||||
int i;
|
||||
int32_t idx;
|
||||
@ -1537,9 +1525,9 @@ tsetscroll(int t, int b)
|
||||
}
|
||||
|
||||
void
|
||||
tsetmode(int priv, int set, int *args, int narg)
|
||||
tsetmode(int priv, int set, const int *args, int narg)
|
||||
{
|
||||
int alt, *lim;
|
||||
int alt; const int *lim;
|
||||
|
||||
for (lim = args + narg; args < lim; ++args) {
|
||||
if (priv) {
|
||||
@ -1715,6 +1703,12 @@ 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);
|
||||
@ -1838,7 +1832,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);
|
||||
}
|
||||
@ -1902,11 +1896,41 @@ 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();
|
||||
@ -1916,13 +1940,21 @@ 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) {
|
||||
if (narg > 2 && allowwindowops) {
|
||||
dec = base64dec(strescseq.args[2]);
|
||||
if (dec) {
|
||||
xsetsel(dec);
|
||||
@ -1932,14 +1964,35 @@ 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, here p = NULL */
|
||||
case 104: /* color reset */
|
||||
j = (narg > 1) ? atoi(strescseq.args[1]) : -1;
|
||||
if (xsetcolorname(j, p)) {
|
||||
|
||||
if (p && !strcmp(p, "?")) {
|
||||
osc_color_response(j, 0, 1);
|
||||
} else if (xsetcolorname(j, p)) {
|
||||
if (par == 104 && narg <= 1)
|
||||
return; /* color reset without parameter */
|
||||
fprintf(stderr, "erresc: invalid color j=%d, p=%s\n",
|
||||
@ -1949,7 +2002,7 @@ strhandle(void)
|
||||
* TODO if defaultbg color is changed, borders
|
||||
* are dirty
|
||||
*/
|
||||
redraw();
|
||||
tfulldirt();
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -1958,7 +2011,6 @@ 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;
|
||||
@ -2076,12 +2128,12 @@ void
|
||||
tdumpline(int n)
|
||||
{
|
||||
char buf[UTF_SIZ];
|
||||
Glyph *bp, *end;
|
||||
const 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);
|
||||
@ -2152,12 +2204,9 @@ 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 = '_';
|
||||
@ -2169,6 +2218,7 @@ tstrsequence(uchar c)
|
||||
c = ']';
|
||||
break;
|
||||
}
|
||||
strreset();
|
||||
strescseq.type = c;
|
||||
term.esc |= ESC_STR;
|
||||
}
|
||||
@ -2211,6 +2261,7 @@ tcontrolcode(uchar ascii)
|
||||
return;
|
||||
case '\032': /* SUB */
|
||||
tsetchar('?', &term.c.attr, term.c.x, term.c.y);
|
||||
/* FALLTHROUGH */
|
||||
case '\030': /* CAN */
|
||||
csireset();
|
||||
break;
|
||||
@ -2365,15 +2416,13 @@ tputc(Rune u)
|
||||
Glyph *gp;
|
||||
|
||||
control = ISCONTROL(u);
|
||||
if (!IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) {
|
||||
if (u < 127 || !IS_SET(MODE_UTF8)) {
|
||||
c[0] = u;
|
||||
width = len = 1;
|
||||
} else {
|
||||
len = utf8encode(u, c);
|
||||
if (!control && (width = wcwidth(u)) == -1) {
|
||||
memcpy(c, "\357\277\275", 4); /* UTF_INVALID */
|
||||
if (!control && (width = wcwidth(u)) == -1)
|
||||
width = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_SET(MODE_PRINT))
|
||||
@ -2388,23 +2437,11 @@ 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|ESC_DCS);
|
||||
if (IS_SET(MODE_SIXEL)) {
|
||||
/* TODO: render sixel */;
|
||||
term.mode &= ~MODE_SIXEL;
|
||||
return;
|
||||
}
|
||||
term.esc &= ~(ESC_START|ESC_STR);
|
||||
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
|
||||
@ -2441,6 +2478,8 @@ 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) {
|
||||
@ -2471,7 +2510,7 @@ check_control_code:
|
||||
*/
|
||||
return;
|
||||
}
|
||||
if (sel.ob.x != -1 && BETWEEN(term.c.y, sel.ob.y, sel.oe.y))
|
||||
if (selected(term.c.x, term.c.y))
|
||||
selclear();
|
||||
|
||||
gp = &term.line[term.c.y][term.c.x];
|
||||
@ -2490,10 +2529,15 @@ 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;
|
||||
}
|
||||
@ -2513,7 +2557,7 @@ twrite(const char *buf, int buflen, int show_ctrl)
|
||||
int n;
|
||||
|
||||
for (n = 0; n < buflen; n += charsize) {
|
||||
if (IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) {
|
||||
if (IS_SET(MODE_UTF8)) {
|
||||
/* process a complete utf8 char */
|
||||
charsize = utf8decode(buf + n, &u, buflen - n);
|
||||
if (charsize == 0)
|
||||
@ -2666,7 +2710,8 @@ 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.ocx, term.ocy, term.line[term.ocy][term.ocx],
|
||||
term.line[term.ocy], term.col);
|
||||
term.ocx = cx;
|
||||
term.ocy = term.c.y;
|
||||
xfinishdraw();
|
||||
|
8
st.desktop
Normal file
8
st.desktop
Normal file
@ -0,0 +1,8 @@
|
||||
[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
21
st.h
@ -11,7 +11,8 @@
|
||||
#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 != (b).mode || (a).fg != (b).fg || \
|
||||
#define ATTRCMP(a, b) (((a).mode & (~ATTR_WRAP) & (~ATTR_LIGA)) != ((b).mode & (~ATTR_WRAP) & (~ATTR_LIGA)) || \
|
||||
(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)
|
||||
@ -33,6 +34,8 @@ 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,
|
||||
};
|
||||
|
||||
@ -93,7 +96,7 @@ void tnew(int, int);
|
||||
void tresize(int, int);
|
||||
void tsetdirtattr(int);
|
||||
void ttyhangup(void);
|
||||
int ttynew(char *, char *, char *, char **);
|
||||
int ttynew(const char *, char *, const char *, char **);
|
||||
size_t ttyread(void);
|
||||
void ttyresize(int, int);
|
||||
void ttywrite(const char *, size_t, int);
|
||||
@ -111,7 +114,15 @@ size_t utf8encode(Rune, char *);
|
||||
|
||||
void *xmalloc(size_t);
|
||||
void *xrealloc(void *, size_t);
|
||||
char *xstrdup(char *);
|
||||
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
|
||||
|
||||
/* config.h globals */
|
||||
extern char *utmp;
|
||||
@ -120,8 +131,12 @@ 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;
|
||||
|
3
st.info
3
st.info
@ -158,6 +158,7 @@ st-mono| simpleterm monocolor,
|
||||
rc=\E8,
|
||||
rev=\E[7m,
|
||||
ri=\EM,
|
||||
rin=\E[%p1%dT,
|
||||
ritm=\E[23m,
|
||||
rmacs=\E(B,
|
||||
rmcup=\E[?1049l,
|
||||
@ -183,6 +184,8 @@ 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
4
win.h
@ -25,11 +25,13 @@ enum win_mode {
|
||||
|
||||
void xbell(void);
|
||||
void xclipcopy(void);
|
||||
void xdrawcursor(int, int, Glyph, int, int, Glyph);
|
||||
void xdrawcursor(int, int, Glyph, int, int, Glyph, Line, int);
|
||||
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);
|
||||
|
381
x.c
381
x.c
@ -19,6 +19,7 @@ char *argv0;
|
||||
#include "arg.h"
|
||||
#include "st.h"
|
||||
#include "win.h"
|
||||
#include "hb.h"
|
||||
|
||||
/* types used in config.h */
|
||||
typedef struct {
|
||||
@ -48,7 +49,7 @@ typedef struct {
|
||||
/* X modifiers */
|
||||
#define XK_ANY_MOD UINT_MAX
|
||||
#define XK_NO_MOD 0
|
||||
#define XK_SWITCH_MOD (1<<13)
|
||||
#define XK_SWITCH_MOD (1<<13|1<<14)
|
||||
|
||||
/* function definitions used in config.h */
|
||||
static void clipcopy(const Arg *);
|
||||
@ -59,6 +60,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"
|
||||
@ -81,6 +83,7 @@ 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 */
|
||||
@ -93,7 +96,7 @@ typedef struct {
|
||||
Window win;
|
||||
Drawable buf;
|
||||
GlyphFontSpec *specbuf; /* font spec buffer used for rendering */
|
||||
Atom xembed, wmdeletewin, netwmname, netwmpid;
|
||||
Atom xembed, wmdeletewin, netwmname, netwmiconname, netwmpid;
|
||||
struct {
|
||||
XIM xim;
|
||||
XIC xic;
|
||||
@ -157,7 +160,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(char *, double);
|
||||
static void xloadfonts(const char *, double);
|
||||
static void xunloadfont(Font *);
|
||||
static void xunloadfonts(void);
|
||||
static void xsetenv(void);
|
||||
@ -254,7 +257,7 @@ static char *opt_line = NULL;
|
||||
static char *opt_name = NULL;
|
||||
static char *opt_title = NULL;
|
||||
|
||||
static int oldbutton = 3; /* button event on startup: 3 = release */
|
||||
static uint buttons; /* bit field of pressed buttons */
|
||||
|
||||
void
|
||||
clipcopy(const Arg *dummy)
|
||||
@ -333,7 +336,7 @@ ttysend(const Arg *arg)
|
||||
int
|
||||
evcol(XEvent *e)
|
||||
{
|
||||
int x = e->xbutton.x - borderpx;
|
||||
int x = e->xbutton.x - win.hborderpx;
|
||||
LIMIT(x, 0, win.tw - 1);
|
||||
return x / win.cw;
|
||||
}
|
||||
@ -341,7 +344,7 @@ evcol(XEvent *e)
|
||||
int
|
||||
evrow(XEvent *e)
|
||||
{
|
||||
int y = e->xbutton.y - borderpx;
|
||||
int y = e->xbutton.y - win.vborderpx;
|
||||
LIMIT(y, 0, win.th - 1);
|
||||
return y / win.ch;
|
||||
}
|
||||
@ -366,59 +369,68 @@ mousesel(XEvent *e, int done)
|
||||
void
|
||||
mousereport(XEvent *e)
|
||||
{
|
||||
int len, x = evcol(e), y = evrow(e),
|
||||
button = e->xbutton.button, state = e->xbutton.state;
|
||||
int len, btn, code;
|
||||
int x = evcol(e), y = evrow(e);
|
||||
int state = e->xbutton.state;
|
||||
char buf[40];
|
||||
static int ox, oy;
|
||||
|
||||
/* from urxvt */
|
||||
if (e->xbutton.type == MotionNotify) {
|
||||
if (e->type == MotionNotify) {
|
||||
if (x == ox && y == oy)
|
||||
return;
|
||||
if (!IS_SET(MODE_MOUSEMOTION) && !IS_SET(MODE_MOUSEMANY))
|
||||
return;
|
||||
/* MOUSE_MOTION: no reporting if no button is pressed */
|
||||
if (IS_SET(MODE_MOUSEMOTION) && oldbutton == 3)
|
||||
/* MODE_MOUSEMOTION: no reporting if no button is pressed */
|
||||
if (IS_SET(MODE_MOUSEMOTION) && buttons == 0)
|
||||
return;
|
||||
|
||||
button = oldbutton + 32;
|
||||
ox = x;
|
||||
oy = y;
|
||||
/* 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;
|
||||
} else {
|
||||
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;
|
||||
btn = e->xbutton.button;
|
||||
/* Only buttons 1 through 11 can be encoded */
|
||||
if (btn < 1 || btn > 11)
|
||||
return;
|
||||
if (e->type == ButtonRelease) {
|
||||
/* MODE_MOUSEX10: no button release reporting */
|
||||
if (IS_SET(MODE_MOUSEX10))
|
||||
return;
|
||||
if (button == 64 || button == 65)
|
||||
/* Don't send release events for the scroll wheel */
|
||||
if (btn == 4 || btn == 5)
|
||||
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)) {
|
||||
button += ((state & ShiftMask ) ? 4 : 0)
|
||||
+ ((state & Mod4Mask ) ? 8 : 0)
|
||||
+ ((state & ControlMask) ? 16 : 0);
|
||||
code += ((state & ShiftMask ) ? 4 : 0)
|
||||
+ ((state & Mod1Mask ) ? 8 : 0) /* meta key: alt */
|
||||
+ ((state & ControlMask) ? 16 : 0);
|
||||
}
|
||||
|
||||
if (IS_SET(MODE_MOUSESGR)) {
|
||||
len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c",
|
||||
button, x+1, y+1,
|
||||
e->xbutton.type == ButtonRelease ? 'm' : 'M');
|
||||
code, x+1, y+1,
|
||||
e->type == ButtonRelease ? 'm' : 'M');
|
||||
} else if (x < 223 && y < 223) {
|
||||
len = snprintf(buf, sizeof(buf), "\033[M%c%c%c",
|
||||
32+button, 32+x+1, 32+y+1);
|
||||
32+code, 32+x+1, 32+y+1);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
@ -461,9 +473,13 @@ 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;
|
||||
@ -472,7 +488,7 @@ bpress(XEvent *e)
|
||||
if (mouseaction(e, 0))
|
||||
return;
|
||||
|
||||
if (e->xbutton.button == Button1) {
|
||||
if (btn == Button1) {
|
||||
/*
|
||||
* If the user clicks below predefined timeouts specific
|
||||
* snapping behaviour is exposed.
|
||||
@ -686,6 +702,11 @@ 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;
|
||||
@ -693,7 +714,7 @@ brelease(XEvent *e)
|
||||
|
||||
if (mouseaction(e, 1))
|
||||
return;
|
||||
if (e->xbutton.button == Button1)
|
||||
if (btn == Button1)
|
||||
mousesel(e, 1);
|
||||
}
|
||||
|
||||
@ -723,6 +744,9 @@ 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);
|
||||
@ -806,6 +830,19 @@ 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)
|
||||
{
|
||||
@ -847,8 +884,8 @@ xhints(void)
|
||||
sizeh->flags = PSize | PResizeInc | PBaseSize | PMinSize;
|
||||
sizeh->height = win.h;
|
||||
sizeh->width = win.w;
|
||||
sizeh->height_inc = win.ch;
|
||||
sizeh->width_inc = win.cw;
|
||||
sizeh->height_inc = 1;
|
||||
sizeh->width_inc = 1;
|
||||
sizeh->base_height = 2 * borderpx;
|
||||
sizeh->base_width = 2 * borderpx;
|
||||
sizeh->min_height = win.ch + 2 * borderpx;
|
||||
@ -959,7 +996,7 @@ xloadfont(Font *f, FcPattern *pattern)
|
||||
}
|
||||
|
||||
void
|
||||
xloadfonts(char *fontstr, double fontsize)
|
||||
xloadfonts(const char *fontstr, double fontsize)
|
||||
{
|
||||
FcPattern *pattern;
|
||||
double fontval;
|
||||
@ -967,7 +1004,7 @@ xloadfonts(char *fontstr, double fontsize)
|
||||
if (fontstr[0] == '-')
|
||||
pattern = XftXlfdParse(fontstr, False, False);
|
||||
else
|
||||
pattern = FcNameParse((FcChar8 *)fontstr);
|
||||
pattern = FcNameParse((const FcChar8 *)fontstr);
|
||||
|
||||
if (!pattern)
|
||||
die("can't open font %s\n", fontstr);
|
||||
@ -1040,6 +1077,9 @@ 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);
|
||||
@ -1137,13 +1177,16 @@ 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 * borderpx + cols * win.cw;
|
||||
win.h = 2 * borderpx + rows * win.ch;
|
||||
win.w = 2 * win.hborderpx + cols * win.cw;
|
||||
win.h = 2 * win.vborderpx + rows * win.ch;
|
||||
if (xw.gm & XNegative)
|
||||
xw.l += DisplayWidth(xw.dpy, xw.scr) - win.w - 2;
|
||||
if (xw.gm & YNegative)
|
||||
@ -1203,6 +1246,7 @@ 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);
|
||||
@ -1222,12 +1266,14 @@ 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 = 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;
|
||||
Font *font = &dc.font;
|
||||
int frcflags = FRC_NORMAL;
|
||||
@ -1246,7 +1292,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. */
|
||||
@ -1268,8 +1314,13 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
|
||||
yp = winy + font->ascent;
|
||||
}
|
||||
|
||||
/* Lookup character index with default font. */
|
||||
glyphidx = XftCharIndex(xw.dpy, font->match, rune);
|
||||
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);
|
||||
}
|
||||
if (glyphidx) {
|
||||
specs[numspecs].font = font->match;
|
||||
specs[numspecs].glyph = glyphidx;
|
||||
@ -1353,14 +1404,40 @@ 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 = 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;
|
||||
Color *fg, *bg, *temp, revfg, revbg, truefg, truebg;
|
||||
XRenderColor colfg, colbg;
|
||||
@ -1450,17 +1527,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, borderpx,
|
||||
xclear(0, (y == 0)? 0 : winy, win.vborderpx,
|
||||
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,
|
||||
((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)
|
||||
xclear(winx, 0, winx + width, borderpx);
|
||||
if (winy + win.ch >= borderpx + win.th)
|
||||
xclear(winx, 0, winx + width, win.hborderpx);
|
||||
if (winy + win.ch >= win.vborderpx + win.th)
|
||||
xclear(winx, winy + win.ch, winx + width, win.h);
|
||||
|
||||
/* Clean up the region we want to draw to. */
|
||||
@ -1473,17 +1550,21 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
|
||||
r.width = width;
|
||||
XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1);
|
||||
|
||||
/* Render the glyphs. */
|
||||
XftDrawGlyphFontSpec(xw.draw, fg, specs, len);
|
||||
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 underline and strikethrough. */
|
||||
if (base.mode & ATTR_UNDERLINE) {
|
||||
XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1,
|
||||
XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent * chscale + 1,
|
||||
width, 1);
|
||||
}
|
||||
|
||||
if (base.mode & ATTR_STRUCK) {
|
||||
XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent / 3,
|
||||
XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent * chscale / 3,
|
||||
width, 1);
|
||||
}
|
||||
|
||||
@ -1502,14 +1583,17 @@ xdrawglyph(Glyph g, int x, int y)
|
||||
}
|
||||
|
||||
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, Line line, int len)
|
||||
{
|
||||
Color drawcol;
|
||||
|
||||
/* remove the old cursor */
|
||||
if (selected(ox, oy))
|
||||
og.mode ^= ATTR_REVERSE;
|
||||
xdrawglyph(og, ox, oy);
|
||||
|
||||
/* Redraw the line where cursor was previously.
|
||||
* It will restore the ligatures broken by the cursor. */
|
||||
xdrawline(line, 0, oy, len);
|
||||
|
||||
if (IS_SET(MODE_HIDE))
|
||||
return;
|
||||
@ -1517,7 +1601,7 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
|
||||
/*
|
||||
* Select the right color for the right mode.
|
||||
*/
|
||||
g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE;
|
||||
g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE|ATTR_BOXDRAW;
|
||||
|
||||
if (IS_SET(MODE_REVERSE)) {
|
||||
g.mode |= ATTR_REVERSE;
|
||||
@ -1543,8 +1627,9 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
|
||||
/* draw the new one */
|
||||
if (IS_SET(MODE_FOCUSED)) {
|
||||
switch (win.cursor) {
|
||||
case 7: /* st extension: snowman (U+2603) */
|
||||
g.u = 0x2603;
|
||||
case 7: /* st extension */
|
||||
g.u = 0x2603; /* snowman (U+2603) */
|
||||
/* FALLTHROUGH */
|
||||
case 0: /* Blinking Block */
|
||||
case 1: /* Blinking Block (Default) */
|
||||
case 2: /* Steady Block */
|
||||
@ -1553,35 +1638,35 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
|
||||
case 3: /* Blinking Underline */
|
||||
case 4: /* Steady Underline */
|
||||
XftDrawRect(xw.draw, &drawcol,
|
||||
borderpx + cx * win.cw,
|
||||
borderpx + (cy + 1) * win.ch - \
|
||||
win.hborderpx + cx * win.cw,
|
||||
win.vborderpx + (cy + 1) * win.ch - \
|
||||
cursorthickness,
|
||||
win.cw, cursorthickness);
|
||||
break;
|
||||
case 5: /* Blinking bar */
|
||||
case 6: /* Steady bar */
|
||||
XftDrawRect(xw.draw, &drawcol,
|
||||
borderpx + cx * win.cw,
|
||||
borderpx + cy * win.ch,
|
||||
win.hborderpx + cx * win.cw,
|
||||
win.vborderpx + cy * win.ch,
|
||||
cursorthickness, win.ch);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
XftDrawRect(xw.draw, &drawcol,
|
||||
borderpx + cx * win.cw,
|
||||
borderpx + cy * win.ch,
|
||||
win.hborderpx + cx * win.cw,
|
||||
win.vborderpx + cy * win.ch,
|
||||
win.cw - 1, 1);
|
||||
XftDrawRect(xw.draw, &drawcol,
|
||||
borderpx + cx * win.cw,
|
||||
borderpx + cy * win.ch,
|
||||
win.hborderpx + cx * win.cw,
|
||||
win.vborderpx + cy * win.ch,
|
||||
1, win.ch - 1);
|
||||
XftDrawRect(xw.draw, &drawcol,
|
||||
borderpx + (cx + 1) * win.cw - 1,
|
||||
borderpx + cy * win.ch,
|
||||
win.hborderpx + (cx + 1) * win.cw - 1,
|
||||
win.vborderpx + cy * win.ch,
|
||||
1, win.ch - 1);
|
||||
XftDrawRect(xw.draw, &drawcol,
|
||||
borderpx + cx * win.cw,
|
||||
borderpx + (cy + 1) * win.ch - 1,
|
||||
win.hborderpx + cx * win.cw,
|
||||
win.vborderpx + (cy + 1) * win.ch - 1,
|
||||
win.cw, 1);
|
||||
}
|
||||
}
|
||||
@ -1595,14 +1680,29 @@ 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);
|
||||
|
||||
Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
|
||||
&prop);
|
||||
if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
|
||||
&prop) != Success)
|
||||
return;
|
||||
XSetWMName(xw.dpy, xw.win, &prop);
|
||||
XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmname);
|
||||
XFree(prop.value);
|
||||
@ -1706,8 +1806,7 @@ xsetmode(int set, unsigned int flags)
|
||||
int
|
||||
xsetcursor(int cursor)
|
||||
{
|
||||
DEFAULT(cursor, 1);
|
||||
if (!BETWEEN(cursor, 0, 6))
|
||||
if (!BETWEEN(cursor, 0, 7)) /* 7: st extension */
|
||||
return 1;
|
||||
win.cursor = cursor;
|
||||
return 0;
|
||||
@ -1884,10 +1983,9 @@ run(void)
|
||||
XEvent ev;
|
||||
int w = win.w, h = win.h;
|
||||
fd_set rfd;
|
||||
int xfd = XConnectionNumber(xw.dpy), xev, blinkset = 0, dodraw = 0;
|
||||
int ttyfd;
|
||||
struct timespec drawtimeout, *tv = NULL, now, last, lastblink;
|
||||
long deltatime;
|
||||
int xfd = XConnectionNumber(xw.dpy), ttyfd, xev, drawing;
|
||||
struct timespec seltv, *tv, now, lastblink, trigger;
|
||||
double timeout;
|
||||
|
||||
/* Waiting for window mapping */
|
||||
do {
|
||||
@ -1908,82 +2006,77 @@ run(void)
|
||||
ttyfd = ttynew(opt_line, shell, opt_io, opt_cmd);
|
||||
cresize(w, h);
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &last);
|
||||
lastblink = last;
|
||||
|
||||
for (xev = actionfps;;) {
|
||||
for (timeout = -1, drawing = 0, lastblink = (struct timespec){0};;) {
|
||||
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));
|
||||
}
|
||||
if (FD_ISSET(ttyfd, &rfd)) {
|
||||
ttyread();
|
||||
if (blinktimeout) {
|
||||
blinkset = tattrset(ATTR_BLINK);
|
||||
if (!blinkset)
|
||||
MODBIT(win.mode, 0, MODE_BLINK);
|
||||
}
|
||||
}
|
||||
|
||||
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 (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);
|
||||
}
|
||||
|
||||
if (dodraw) {
|
||||
while (XPending(xw.dpy)) {
|
||||
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 */
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
draw();
|
||||
XFlush(xw.dpy);
|
||||
drawing = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2005,7 +2098,7 @@ main(int argc, char *argv[])
|
||||
{
|
||||
xw.l = xw.t = 0;
|
||||
xw.isfixed = False;
|
||||
win.cursor = cursorshape;
|
||||
xsetcursor(cursorshape);
|
||||
|
||||
ARGBEGIN {
|
||||
case 'a':
|
||||
|
Loading…
Reference in New Issue
Block a user