diff --git a/FAQ b/FAQ new file mode 100644 index 0000000..6287a27 --- /dev/null +++ b/FAQ @@ -0,0 +1,253 @@ +## Why does st not handle utmp entries? + +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 + terminfo. What you see is the current state of the “xterm compliance”. +* 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. + * `st -e tmux` using C-b [ + * `st -e screen` using C-a ESC +* 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. + + +## Why doesn't the Del key work in some programs? + +Taken from the terminfo manpage: + + If the terminal has a keypad that transmits codes when the keys + are pressed, this information can be given. Note that it is not + possible to handle terminals where the keypad only works in + local (this applies, for example, to the unshifted HP 2621 keys). + If the keypad can be set to transmit or not transmit, give these + codes as smkx and rmkx. Otherwise the keypad is assumed to + always transmit. + +In the st case smkx=E[?1hE= and rmkx=E[?1lE>, so it is mandatory that +applications which want to test against keypad keys send these +sequences. + +But buggy applications (like bash and irssi, for example) don't do this. A fast +solution for them is to use the following command: + + $ printf '\033[?1h\033=' >/dev/tty + +or + $ tput smkx + +In the case of bash, readline is used. Readline has a different note in its +manpage about this issue: + + enable-keypad (Off) + When set to On, readline will try to enable the + application keypad when it is called. Some systems + need this to enable arrow keys. + +Adding this option to your .inputrc will fix the keypad problem for all +applications using readline. + +If you are using zsh, then read the zsh FAQ +: + + It should be noted that the O / [ confusion can occur with other keys + such as Home and End. Some systems let you query the key sequences + sent by these keys from the system's terminal database, terminfo. + Unfortunately, the key sequences given there typically apply to the + mode that is not the one zsh uses by default (it's the "application" + mode rather than the "raw" mode). Explaining the use of terminfo is + outside of the scope of this FAQ, but if you wish to use the key + sequences given there you can tell the line editor to turn on + "application" mode when it starts and turn it off when it stops: + + function zle-line-init () { echoti smkx } + function zle-line-finish () { echoti rmkx } + zle -N zle-line-init + zle -N zle-line-finish + +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 +. +If you want to compile st for OpenBSD you have to remove -lrt from config.mk, and +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 +backspace. + +This is an issue that was discussed in suckless mailing list +. Here is why some old grumpy +terminal users wants its backspace to be how he feels it: + + Well, I am going to comment why I want to change the behaviour + of this key. When ASCII was defined in 1968, communication + with computers was done using punched cards, or hardcopy + terminals (basically a typewriter machine connected with the + computer using a serial port). ASCII defines DELETE as 7F, + because, in punched-card terms, it means all the holes of the + card punched; it is thus a kind of 'physical delete'. In the + same way, the BACKSPACE key was a non-destructive backspace, + as on a typewriter. So, if you wanted to delete a character, + you had to BACKSPACE and then DELETE. Another use of BACKSPACE + was to type accented characters, for example 'a BACKSPACE `'. + The VT100 had no BACKSPACE key; it was generated using the + CONTROL key as another control character (CONTROL key sets to + 0 b7 b6 b5, so it converts H (code 0x48) into BACKSPACE (code + 0x08)), but it had a DELETE key in a similar position where + the BACKSPACE key is located today on common PC keyboards. + All the terminal emulators emulated the difference between + these keys correctly: the backspace key generated a BACKSPACE + (^H) and delete key generated a DELETE (^?). + + But a problem arose when Linus Torvalds wrote Linux. Unlike + earlier terminals, the Linux virtual terminal (the terminal + emulator integrated in the kernel) returned a DELETE when + backspace was pressed, due to the VT100 having a DELETE key in + the same position. This created a lot of problems (see [1] + and [2]). Since Linux has become the king, a lot of terminal + emulators today generate a DELETE when the backspace key is + pressed in order to avoid problems with Linux. The result is + that the only way of generating a BACKSPACE on these systems + is by using CONTROL + H. (I also think that emacs had an + important point here because the CONTROL + H prefix is used + in emacs in some commands (help commands).) + + From point of view of the kernel, you can change the key + for deleting a previous character with stty erase. When you + connect a real terminal into a machine you describe the type + of terminal, so getty configures the correct value of stty + erase for this terminal. In the case of terminal emulators, + however, you don't have any getty that can set the correct + value of stty erase, so you always get the default value. + For this reason, it is necessary to add 'stty erase ^H' to your + profile if you have changed the value of the backspace key. + Of course, another solution is for st itself to modify the + value of stty erase. I usually have the inverse problem: + when I connect to non-Unix machines, I have to press CONTROL + + h to get a BACKSPACE. The inverse problem occurs when a user + connects to my Unix machines from a different system with a + correct backspace key. + + [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 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); + + +## BadLength X error in Xft when trying to render emoji + +Xft makes st crash when rendering color emojis with the following error: + +"X Error of failed request: BadLength (poly request too large or internal Xlib length error)" + Major opcode of failed request: 139 (RENDER) + Minor opcode of failed request: 20 (RenderAddGlyphs) + Serial number of failed request: 1595 + Current serial number in output stream: 1818" + +This is a known bug in Xft (not st) which happens on some platforms and +combination of particular fonts and fontconfig settings. + +See also: +https://gitlab.freedesktop.org/xorg/lib/libxft/issues/6 +https://bugs.freedesktop.org/show_bug.cgi?id=107534 +https://bugzilla.redhat.com/show_bug.cgi?id=1498269 + +The solution is to remove color emoji fonts or disable this in the fontconfig +XML configuration. As an ugly workaround (which may work only on newer +fontconfig versions (FC_COLOR)), the following code can be used to mask color +fonts: + + FcPatternAddBool(fcpattern, FC_COLOR, FcFalse); + +Please don't bother reporting this bug to st, but notify the upstream Xft +developers about fixing this bug. + +As of 2022-09-05 this now seems to be finally fixed in libXft 2.3.5: +https://gitlab.freedesktop.org/xorg/lib/libxft/-/blob/libXft-2.3.5/NEWS diff --git a/LEGACY b/LEGACY new file mode 100644 index 0000000..bf28b1e --- /dev/null +++ b/LEGACY @@ -0,0 +1,17 @@ +A STATEMENT ON LEGACY SUPPORT + +In the terminal world there is much cruft that comes from old and unsup‐ +ported terminals that inherit incompatible modes and escape sequences +which noone is able to know, except when he/she comes from that time and +developed a graphical vt100 emulator at that time. + +One goal of st is to only support what is really needed. When you en‐ +counter a sequence which you really need, implement it. But while you +are at it, do not add the other cruft you might encounter while sneek‐ +ing at other terminal emulators. History has bloated them and there is +no real evidence that most of the sequences are used today. + + +Christoph Lohmann <20h@r-36.net> +2012-09-13T07:00:36.081271045+02:00 + diff --git a/Makefile b/Makefile index adfa07a..15db421 100644 --- a/Makefile +++ b/Makefile @@ -4,16 +4,10 @@ include config.mk -SRC = st.c x.c boxdraw.c hb.c +SRC = st.c x.c OBJ = $(SRC:.c=.o) -all: options st - -options: - @echo st build options: - @echo "CFLAGS = $(STCFLAGS)" - @echo "LDFLAGS = $(STLDFLAGS)" - @echo "CC = $(CC)" +all: st config.h: cp config.def.h config.h @@ -22,9 +16,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 -boxdraw.o: config.h st.h boxdraw_data.h -hb.o: st.h +x.o: arg.h config.h st.h win.h $(OBJ): config.h config.mk @@ -56,4 +48,4 @@ uninstall: rm -f $(DESTDIR)$(PREFIX)/bin/st rm -f $(DESTDIR)$(MANPREFIX)/man1/st.1 -.PHONY: all options clean dist install uninstall +.PHONY: all clean dist install uninstall diff --git a/README b/README new file mode 100644 index 0000000..6a846ed --- /dev/null +++ b/README @@ -0,0 +1,34 @@ +st - simple terminal +-------------------- +st is a simple terminal emulator for X which sucks less. + + +Requirements +------------ +In order to build st you need the Xlib header files. + + +Installation +------------ +Edit config.mk to match your local setup (st is installed into +the /usr/local namespace by default). + +Afterwards enter the following command to build and install st (if +necessary as root): + + make clean install + + +Running st +---------- +If you did not install st with make clean install, you must compile +the st terminfo entry with the following command: + + tic -sx st.info + +See the man page for additional details. + +Credits +------- +Based on Aurélien APTEL bt source code. + diff --git a/TODO b/TODO new file mode 100644 index 0000000..5f74cd5 --- /dev/null +++ b/TODO @@ -0,0 +1,28 @@ +vt emulation +------------ + +* double-height support + +code & interface +---------------- + +* add a simple way to do multiplexing + +drawing +------- +* add diacritics support to xdraws() + * switch to a suckless font drawing library +* make the font cache simpler +* add better support for brightening of the upper colors + +bugs +---- + +* fix shift up/down (shift selection in emacs) +* remove DEC test sequence when appropriate + +misc +---- + + $ grep -nE 'XXX|TODO' st.c + diff --git a/boxdraw.c b/boxdraw.c deleted file mode 100644 index 28a92d0..0000000 --- a/boxdraw.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright 2018 Avi Halachmi (:avih) avihpit@yahoo.com https://github.com/avih - * MIT/X Consortium License - */ - -#include -#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); - } - } -} diff --git a/boxdraw_data.h b/boxdraw_data.h deleted file mode 100644 index 7890500..0000000 --- a/boxdraw_data.h +++ /dev/null @@ -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) */ -}; diff --git a/config.h b/config.def.h similarity index 88% rename from config.h rename to config.def.h index 70d9775..91ab8ca 100644 --- a/config.h +++ b/config.def.h @@ -1,14 +1,12 @@ /* See LICENSE file for copyright and license details. */ -static char *font = "FiraCode Nerd Font Mono:pixelsize=14"; -static int borderpx = 2; - -/* Underline curl style - * CURLY 0 - * SPIKY 1 - * CAPPED 2 +/* + * appearance + * + * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html */ -#define UNDERCURL_STYLE 2 +static char *font = "Liberation Mono:pixelsize=12:antialias=true:autohint=true"; +static int borderpx = 2; /* * What program is execed by st depends of these precedence rules: @@ -55,32 +53,20 @@ int allowwindowops = 0; * 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 = 3; -static double maxlatency = 25; +static double minlatency = 8; +static double maxlatency = 33; /* * blinking timeout (set to 0 to disable blinking) for the terminal blinking * attribute. */ -static unsigned int blinktimeout = 600; +static unsigned int blinktimeout = 800; /* * thickness of underline and bar cursors */ 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 @@ -110,61 +96,52 @@ unsigned int tabspaces = 8; /* Terminal colors (16 first used in escape sequence) */ static const char *colorname[] = { /* 8 normal colors */ - "#15161E", - "#f7768e", - "#9ece6a", - "#e0af68", - "#7aa2f7", - "#bb9af7", - "#7dcfff", - "#a9b1d6", + "black", + "red3", + "green3", + "yellow3", + "blue2", + "magenta3", + "cyan3", + "gray90", /* 8 bright colors */ - "#414868", - "#f7768e", - "#9ece6a", - "#e0af68", - "#7aa2f7", - "#bb9af7", - "#7dcfff", - "#c0caf5", + "gray50", + "red", + "green", + "yellow", + "#5c5cff", + "magenta", + "cyan", + "white", [255] = 0, - // indexes beyond 255 are used for internal colors - "#c0caf5", /* default cursor colour */ - "#1a1b26", /* default inverted cursor colour */ - "#c0caf5", /* default foreground colour */ - "#1a1b26", /* default background colour */ - "#c0caf5", /* default selection foreground colour */ - "#33467C", /* default selection background colour */ + /* more colors can be added after 255 to use with DefaultXX */ + "#cccccc", + "#555555", + "gray90", /* default foreground colour */ + "black", /* default background colour */ }; -unsigned int defaultcs = 256; -static unsigned int defaultrcs = 257; -unsigned int defaultfg = 258; -unsigned int defaultbg = 259; -unsigned int selectionfg = 260; -unsigned int selectionbg = 261; -/* If 0 use selectionfg as foreground in order to have a uniform foreground-color */ -/* Else if 1 keep original foreground-color of each cell => more colors :) */ -static int ignoreselfg = 1; /* -+ * https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h4-Functions-using-CSI-_-ordered-by-the-final-character-lparen-s-rparen:CSI-Ps-SP-q.1D81 -+ * Default style of cursor -+ * 0: blinking block -+ * 1: blinking block (default) -+ * 2: steady block ("█") -+ * 3: blinking underline -+ * 4: steady underline ("_") -+ * 5: blinking bar -+ * 6: steady bar ("|") -+ * 7: blinking st cursor -+ * 8: steady st cursor + * Default colors (colorname index) + * foreground, background, cursor, reverse cursor */ -static unsigned int cursorstyle = 1; -static Rune stcursor = 0x2603; /* snowman ("☃") */ +unsigned int defaultfg = 258; +unsigned int defaultbg = 259; +unsigned int defaultcs = 256; +static unsigned int defaultrcs = 257; + +/* + * Default shape of cursor + * 2: Block ("█") + * 4: Underline ("_") + * 6: Bar ("|") + * 7: Snowman ("☃") + */ +static unsigned int cursorshape = 2; /* * Default columns and rows numbers @@ -199,9 +176,11 @@ static uint forcemousemod = ShiftMask; */ static MouseShortcut mshortcuts[] = { /* mask button function argument release */ - // { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 }, - { ShiftMask, Button4, kscrollup, {.i = 3} }, /* You can increase .i to increase scroll speed*/ - { ShiftMask, Button5, kscrolldown, {.i = 3} }, + { 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"} }, }; /* Internal keyboard shortcuts. */ @@ -214,16 +193,14 @@ 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 = +5} }, - { TERMMOD, XK_Next, zoom, {.f = -5} }, + { 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_Insert, selpaste, {.i = 0} }, { TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, - { ShiftMask, XK_Page_Up, kscrollup, {.i = -1} }, - { ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} }, }; /* @@ -301,7 +278,7 @@ static Key key[] = { { XK_KP_Delete, ControlMask, "\033[3;5~", +1, 0}, { XK_KP_Delete, ShiftMask, "\033[2K", -1, 0}, { XK_KP_Delete, ShiftMask, "\033[3;2~", +1, 0}, - { XK_KP_Delete, XK_ANY_MOD, "\033[3~", -1, 0}, + { XK_KP_Delete, XK_ANY_MOD, "\033[P", -1, 0}, { XK_KP_Delete, XK_ANY_MOD, "\033[3~", +1, 0}, { XK_KP_Multiply, XK_ANY_MOD, "\033Oj", +2, 0}, { XK_KP_Add, XK_ANY_MOD, "\033Ok", +2, 0}, @@ -369,7 +346,7 @@ static Key key[] = { { XK_Delete, ControlMask, "\033[3;5~", +1, 0}, { XK_Delete, ShiftMask, "\033[2K", -1, 0}, { XK_Delete, ShiftMask, "\033[3;2~", +1, 0}, - { XK_Delete, XK_ANY_MOD, "\033[3~", -1, 0}, + { XK_Delete, XK_ANY_MOD, "\033[P", -1, 0}, { XK_Delete, XK_ANY_MOD, "\033[3~", +1, 0}, { XK_BackSpace, XK_NO_MOD, "\177", 0, 0}, { XK_BackSpace, Mod1Mask, "\033\177", 0, 0}, diff --git a/config.mk b/config.mk index 3e13e53..1e306f8 100644 --- a/config.mk +++ b/config.mk @@ -15,12 +15,10 @@ 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 \ `$(PKG_CONFIG) --libs fontconfig` \ - `$(PKG_CONFIG) --libs freetype2` \ - `$(PKG_CONFIG) --libs harfbuzz` + `$(PKG_CONFIG) --libs freetype2` # flags STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 diff --git a/hb.c b/hb.c deleted file mode 100644 index b42f357..0000000 --- a/hb.c +++ /dev/null @@ -1,124 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include "st.h" -#include "hb.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 } -#define BUFFER_STEP 256 - -hb_font_t *hbfindfont(XftFont *match); - -typedef struct { - XftFont *match; - hb_font_t *font; -} HbFontMatch; - -typedef struct { - size_t capacity; - HbFontMatch *fonts; -} HbFontCache; - -static HbFontCache hbfontcache = { 0, NULL }; - -typedef struct { - size_t capacity; - Rune *runes; -} RuneBuffer; - -static RuneBuffer hbrunebuffer = { 0, NULL }; - -/* - * Poplulate the array 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[] = { }; - -void -hbunloadfonts() -{ - for (int i = 0; i < hbfontcache.capacity; i++) { - hb_font_destroy(hbfontcache.fonts[i].font); - XftUnlockFace(hbfontcache.fonts[i].match); - } - - if (hbfontcache.fonts != NULL) { - free(hbfontcache.fonts); - hbfontcache.fonts = NULL; - } - hbfontcache.capacity = 0; -} - -hb_font_t * -hbfindfont(XftFont *match) -{ - for (int i = 0; i < hbfontcache.capacity; i++) { - if (hbfontcache.fonts[i].match == match) - return hbfontcache.fonts[i].font; - } - - /* Font not found in cache, caching it now. */ - hbfontcache.fonts = realloc(hbfontcache.fonts, sizeof(HbFontMatch) * (hbfontcache.capacity + 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.fonts[hbfontcache.capacity].match = match; - hbfontcache.fonts[hbfontcache.capacity].font = font; - hbfontcache.capacity += 1; - - return font; -} - -void hbtransform(HbTransformData *data, XftFont *xfont, const Glyph *glyphs, int start, int length) { - ushort mode = USHRT_MAX; - unsigned int glyph_count; - int rune_idx, glyph_idx, end = start + length; - - hb_font_t *font = hbfindfont(xfont); - if (font == NULL) - return; - - hb_buffer_t *buffer = hb_buffer_create(); - hb_buffer_set_direction(buffer, HB_DIRECTION_LTR); - - /* Resize the buffer if required length is larger. */ - if (hbrunebuffer.capacity < length) { - hbrunebuffer.capacity = (length / BUFFER_STEP + 1) * BUFFER_STEP; - hbrunebuffer.runes = realloc(hbrunebuffer.runes, hbrunebuffer.capacity * sizeof(Rune)); - } - - /* Fill buffer with codepoints. */ - for (rune_idx = 0, glyph_idx = start; glyph_idx < end; glyph_idx++, rune_idx++) { - hbrunebuffer.runes[rune_idx] = glyphs[glyph_idx].u; - mode = glyphs[glyph_idx].mode; - if (mode & ATTR_WDUMMY) - hbrunebuffer.runes[rune_idx] = 0x0020; - } - hb_buffer_add_codepoints(buffer, hbrunebuffer.runes, length, 0, length); - - /* Shape the segment. */ - hb_shape(font, buffer, features, sizeof(features)/sizeof(hb_feature_t)); - - /* Get new glyph info. */ - hb_glyph_info_t *info = hb_buffer_get_glyph_infos(buffer, &glyph_count); - hb_glyph_position_t *pos = hb_buffer_get_glyph_positions(buffer, &glyph_count); - - /* Fill the output. */ - data->buffer = buffer; - data->glyphs = info; - data->positions = pos; - data->count = glyph_count; -} - -void hbcleanup(HbTransformData *data) { - hb_buffer_destroy(data->buffer); - memset(data, 0, sizeof(HbTransformData)); -} diff --git a/hb.h b/hb.h deleted file mode 100644 index 88de9bd..0000000 --- a/hb.h +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include -#include - -typedef struct { - hb_buffer_t *buffer; - hb_glyph_info_t *glyphs; - hb_glyph_position_t *positions; - unsigned int count; -} HbTransformData; - -void hbunloadfonts(); -void hbtransform(HbTransformData *, XftFont *, const Glyph *, int, int); -void hbcleanup(HbTransformData *); diff --git a/patches/st-scrollback-0.8.5.diff b/patches/st-scrollback-0.8.5.diff deleted file mode 100644 index 750111d..0000000 --- a/patches/st-scrollback-0.8.5.diff +++ /dev/null @@ -1,350 +0,0 @@ -diff --git a/config.def.h b/config.def.h -index 91ab8ca..e3b469b 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -201,6 +201,8 @@ static Shortcut shortcuts[] = { - { TERMMOD, XK_Y, selpaste, {.i = 0} }, - { ShiftMask, XK_Insert, selpaste, {.i = 0} }, - { TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, -+ { ShiftMask, XK_Page_Up, kscrollup, {.i = -1} }, -+ { ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} }, - }; - - /* -diff --git a/st.c b/st.c -index 51049ba..cd750f2 100644 ---- a/st.c -+++ b/st.c -@@ -35,6 +35,7 @@ - #define ESC_ARG_SIZ 16 - #define STR_BUF_SIZ ESC_BUF_SIZ - #define STR_ARG_SIZ ESC_ARG_SIZ -+#define HISTSIZE 2000 - - /* macros */ - #define IS_SET(flag) ((term.mode & (flag)) != 0) -@@ -42,6 +43,9 @@ - #define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f)) - #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c)) - #define ISDELIM(u) (u && wcschr(worddelimiters, u)) -+#define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - \ -+ term.scr + HISTSIZE + 1) % HISTSIZE] : \ -+ term.line[(y) - term.scr]) - - enum term_mode { - MODE_WRAP = 1 << 0, -@@ -115,6 +119,9 @@ typedef struct { - int col; /* nb col */ - Line *line; /* screen */ - Line *alt; /* alternate screen */ -+ Line hist[HISTSIZE]; /* history buffer */ -+ int histi; /* history index */ -+ int scr; /* scroll back */ - int *dirty; /* dirtyness of lines */ - TCursor c; /* cursor */ - int ocx; /* old cursor col */ -@@ -184,8 +191,8 @@ static void tnewline(int); - static void tputtab(int); - static void tputc(Rune); - static void treset(void); --static void tscrollup(int, int); --static void tscrolldown(int, int); -+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 tsetdirt(int, int); -@@ -416,10 +423,10 @@ tlinelen(int y) - { - int i = term.col; - -- if (term.line[y][i - 1].mode & ATTR_WRAP) -+ if (TLINE(y)[i - 1].mode & ATTR_WRAP) - return i; - -- while (i > 0 && term.line[y][i - 1].u == ' ') -+ while (i > 0 && TLINE(y)[i - 1].u == ' ') - --i; - - return i; -@@ -528,7 +535,7 @@ selsnap(int *x, int *y, int direction) - * Snap around if the word wraps around at the end or - * beginning of a line. - */ -- prevgp = &term.line[*y][*x]; -+ prevgp = &TLINE(*y)[*x]; - prevdelim = ISDELIM(prevgp->u); - for (;;) { - newx = *x + direction; -@@ -543,14 +550,14 @@ selsnap(int *x, int *y, int direction) - yt = *y, xt = *x; - else - yt = newy, xt = newx; -- if (!(term.line[yt][xt].mode & ATTR_WRAP)) -+ if (!(TLINE(yt)[xt].mode & ATTR_WRAP)) - break; - } - - if (newx >= tlinelen(newy)) - break; - -- gp = &term.line[newy][newx]; -+ gp = &TLINE(newy)[newx]; - delim = ISDELIM(gp->u); - if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim - || (delim && gp->u != prevgp->u))) -@@ -571,14 +578,14 @@ selsnap(int *x, int *y, int direction) - *x = (direction < 0) ? 0 : term.col - 1; - if (direction < 0) { - for (; *y > 0; *y += direction) { -- if (!(term.line[*y-1][term.col-1].mode -+ if (!(TLINE(*y-1)[term.col-1].mode - & ATTR_WRAP)) { - break; - } - } - } else if (direction > 0) { - for (; *y < term.row-1; *y += direction) { -- if (!(term.line[*y][term.col-1].mode -+ if (!(TLINE(*y)[term.col-1].mode - & ATTR_WRAP)) { - break; - } -@@ -609,13 +616,13 @@ getsel(void) - } - - if (sel.type == SEL_RECTANGULAR) { -- gp = &term.line[y][sel.nb.x]; -+ gp = &TLINE(y)[sel.nb.x]; - lastx = sel.ne.x; - } else { -- gp = &term.line[y][sel.nb.y == y ? sel.nb.x : 0]; -+ gp = &TLINE(y)[sel.nb.y == y ? sel.nb.x : 0]; - lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1; - } -- last = &term.line[y][MIN(lastx, linelen-1)]; -+ last = &TLINE(y)[MIN(lastx, linelen-1)]; - while (last >= gp && last->u == ' ') - --last; - -@@ -851,6 +858,9 @@ void - ttywrite(const char *s, size_t n, int may_echo) - { - const char *next; -+ Arg arg = (Arg) { .i = term.scr }; -+ -+ kscrolldown(&arg); - - if (may_echo && IS_SET(MODE_ECHO)) - twrite(s, n, 1); -@@ -1062,12 +1072,52 @@ tswapscreen(void) - } - - void --tscrolldown(int orig, int n) -+kscrolldown(const Arg* a) -+{ -+ int n = a->i; -+ -+ if (n < 0) -+ n = term.row + n; -+ -+ if (n > term.scr) -+ n = term.scr; -+ -+ if (term.scr > 0) { -+ term.scr -= n; -+ selscroll(0, -n); -+ tfulldirt(); -+ } -+} -+ -+void -+kscrollup(const Arg* a) -+{ -+ int n = a->i; -+ -+ if (n < 0) -+ n = term.row + n; -+ -+ if (term.scr <= HISTSIZE-n) { -+ term.scr += n; -+ selscroll(0, n); -+ tfulldirt(); -+ } -+} -+ -+void -+tscrolldown(int orig, int n, int copyhist) - { - int i; - Line temp; - - LIMIT(n, 0, term.bot-orig+1); -+ if (copyhist) { -+ term.histi = (term.histi - 1 + HISTSIZE) % HISTSIZE; -+ temp = term.hist[term.histi]; -+ term.hist[term.histi] = term.line[term.bot]; -+ term.line[term.bot] = temp; -+ } -+ - - tsetdirt(orig, term.bot-n); - tclearregion(0, term.bot-n+1, term.col-1, term.bot); -@@ -1078,17 +1128,28 @@ tscrolldown(int orig, int n) - term.line[i-n] = temp; - } - -- selscroll(orig, n); -+ if (term.scr == 0) -+ selscroll(orig, n); - } - - void --tscrollup(int orig, int n) -+tscrollup(int orig, int n, int copyhist) - { - int i; - Line temp; - - LIMIT(n, 0, term.bot-orig+1); - -+ if (copyhist) { -+ term.histi = (term.histi + 1) % HISTSIZE; -+ temp = term.hist[term.histi]; -+ term.hist[term.histi] = term.line[orig]; -+ term.line[orig] = temp; -+ } -+ -+ if (term.scr > 0 && term.scr < HISTSIZE) -+ term.scr = MIN(term.scr + n, HISTSIZE-1); -+ - tclearregion(0, orig, term.col-1, orig+n-1); - tsetdirt(orig+n, term.bot); - -@@ -1098,7 +1159,8 @@ tscrollup(int orig, int n) - term.line[i+n] = temp; - } - -- selscroll(orig, -n); -+ if (term.scr == 0) -+ selscroll(orig, -n); - } - - void -@@ -1127,7 +1189,7 @@ tnewline(int first_col) - int y = term.c.y; - - if (y == term.bot) { -- tscrollup(term.top, 1); -+ tscrollup(term.top, 1, 1); - } else { - y++; - } -@@ -1292,14 +1354,14 @@ void - tinsertblankline(int n) - { - if (BETWEEN(term.c.y, term.top, term.bot)) -- tscrolldown(term.c.y, n); -+ tscrolldown(term.c.y, n, 0); - } - - void - tdeleteline(int n) - { - if (BETWEEN(term.c.y, term.top, term.bot)) -- tscrollup(term.c.y, n); -+ tscrollup(term.c.y, n, 0); - } - - int32_t -@@ -1736,11 +1798,11 @@ csihandle(void) - break; - case 'S': /* SU -- Scroll line up */ - DEFAULT(csiescseq.arg[0], 1); -- tscrollup(term.top, csiescseq.arg[0]); -+ tscrollup(term.top, csiescseq.arg[0], 0); - break; - case 'T': /* SD -- Scroll line down */ - DEFAULT(csiescseq.arg[0], 1); -- tscrolldown(term.top, csiescseq.arg[0]); -+ tscrolldown(term.top, csiescseq.arg[0], 0); - break; - case 'L': /* IL -- Insert blank lines */ - DEFAULT(csiescseq.arg[0], 1); -@@ -2330,7 +2392,7 @@ eschandle(uchar ascii) - return 0; - case 'D': /* IND -- Linefeed */ - if (term.c.y == term.bot) { -- tscrollup(term.top, 1); -+ tscrollup(term.top, 1, 1); - } else { - tmoveto(term.c.x, term.c.y+1); - } -@@ -2343,7 +2405,7 @@ eschandle(uchar ascii) - break; - case 'M': /* RI -- Reverse index */ - if (term.c.y == term.top) { -- tscrolldown(term.top, 1); -+ tscrolldown(term.top, 1, 1); - } else { - tmoveto(term.c.x, term.c.y-1); - } -@@ -2557,7 +2619,7 @@ twrite(const char *buf, int buflen, int show_ctrl) - void - tresize(int col, int row) - { -- int i; -+ int i, j; - int minrow = MIN(row, term.row); - int mincol = MIN(col, term.col); - int *bp; -@@ -2594,6 +2656,14 @@ tresize(int col, int row) - term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty)); - term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs)); - -+ for (i = 0; i < HISTSIZE; i++) { -+ term.hist[i] = xrealloc(term.hist[i], col * sizeof(Glyph)); -+ for (j = mincol; j < col; j++) { -+ term.hist[i][j] = term.c.attr; -+ term.hist[i][j].u = ' '; -+ } -+ } -+ - /* resize each row to new width, zero-pad if needed */ - for (i = 0; i < minrow; i++) { - term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph)); -@@ -2652,7 +2722,7 @@ drawregion(int x1, int y1, int x2, int y2) - continue; - - term.dirty[y] = 0; -- xdrawline(term.line[y], x1, y, x2); -+ xdrawline(TLINE(y), x1, y, x2); - } - } - -@@ -2673,8 +2743,9 @@ draw(void) - cx--; - - drawregion(0, 0, term.col, term.row); -- xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], -- term.ocx, term.ocy, term.line[term.ocy][term.ocx]); -+ 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 = cx; - term.ocy = term.c.y; - xfinishdraw(); -diff --git a/st.h b/st.h -index 519b9bd..da36b34 100644 ---- a/st.h -+++ b/st.h -@@ -81,6 +81,8 @@ void die(const char *, ...); - void redraw(void); - void draw(void); - -+void kscrolldown(const Arg *); -+void kscrollup(const Arg *); - void printscreen(const Arg *); - void printsel(const Arg *); - void sendbreak(const Arg *); diff --git a/st.1 b/st.1 index b82beb3..39120b4 100644 --- a/st.1 +++ b/st.1 @@ -6,8 +6,6 @@ st \- simple terminal .RB [ \-aiv ] .RB [ \-c .IR class ] -.RB [ \-d -.IR path ] .RB [ \-f .IR font ] .RB [ \-g @@ -32,8 +30,6 @@ st \- simple terminal .RB [ \-aiv ] .RB [ \-c .IR class ] -.RB [ \-d -.IR path ] .RB [ \-f .IR font ] .RB [ \-g @@ -62,10 +58,6 @@ disable alternate screens in terminal .BI \-c " class" defines the window class (default $TERM). .TP -.BI \-d " path" -changes the working directory to -.IR path . -.TP .BI \-f " font" defines the .I font diff --git a/st.c b/st.c index e98d71f..d6478f5 100644 --- a/st.c +++ b/st.c @@ -33,10 +33,8 @@ #define UTF_SIZ 4 #define ESC_BUF_SIZ (128*UTF_SIZ) #define ESC_ARG_SIZ 16 -#define CAR_PER_ARG 4 #define STR_BUF_SIZ ESC_BUF_SIZ #define STR_ARG_SIZ ESC_ARG_SIZ -#define HISTSIZE 5000 /* macros */ #define IS_SET(flag) ((term.mode & (flag)) != 0) @@ -44,9 +42,6 @@ #define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f)) #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c)) #define ISDELIM(u) (u && wcschr(worddelimiters, u)) -#define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - \ - term.scr + HISTSIZE + 1) % HISTSIZE] : \ - term.line[(y) - term.scr]) enum term_mode { MODE_WRAP = 1 << 0, @@ -120,9 +115,6 @@ typedef struct { int col; /* nb col */ Line *line; /* screen */ Line *alt; /* alternate screen */ - Line hist[HISTSIZE]; /* history buffer */ - int histi; /* history index */ - int scr; /* scroll back */ int *dirty; /* dirtyness of lines */ TCursor c; /* cursor */ int ocx; /* old cursor col */ @@ -147,7 +139,6 @@ typedef struct { int arg[ESC_ARG_SIZ]; int narg; /* nb of args */ char mode[2]; - int carg[ESC_ARG_SIZ][CAR_PER_ARG]; /* colon args */ } CSIEscape; /* STR Escape sequence structs */ @@ -168,7 +159,6 @@ static void ttywriteraw(const char *, size_t); static void csidump(void); static void csihandle(void); -static void readcolonargs(char **, int, int[][CAR_PER_ARG]); static void csiparse(void); static void csireset(void); static void osc_color_response(int, int, int); @@ -195,8 +185,8 @@ static void tnewline(int); static void tputtab(int); static void tputc(Rune); static void treset(void); -static void tscrollup(int, int, int); -static void tscrolldown(int, int, int); +static void tscrollup(int, int); +static void tscrolldown(int, int); static void tsetattr(const int *, int); static void tsetchar(Rune, const Glyph *, int, int); static void tsetdirt(int, int); @@ -419,10 +409,10 @@ tlinelen(int y) { int i = term.col; - if (TLINE(y)[i - 1].mode & ATTR_WRAP) + if (term.line[y][i - 1].mode & ATTR_WRAP) return i; - while (i > 0 && TLINE(y)[i - 1].u == ' ') + while (i > 0 && term.line[y][i - 1].u == ' ') --i; return i; @@ -531,7 +521,7 @@ selsnap(int *x, int *y, int direction) * Snap around if the word wraps around at the end or * beginning of a line. */ - prevgp = &TLINE(*y)[*x]; + prevgp = &term.line[*y][*x]; prevdelim = ISDELIM(prevgp->u); for (;;) { newx = *x + direction; @@ -546,14 +536,14 @@ selsnap(int *x, int *y, int direction) yt = *y, xt = *x; else yt = newy, xt = newx; - if (!(TLINE(yt)[xt].mode & ATTR_WRAP)) + if (!(term.line[yt][xt].mode & ATTR_WRAP)) break; } if (newx >= tlinelen(newy)) break; - gp = &TLINE(newy)[newx]; + gp = &term.line[newy][newx]; delim = ISDELIM(gp->u); if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim || (delim && gp->u != prevgp->u))) @@ -574,14 +564,14 @@ selsnap(int *x, int *y, int direction) *x = (direction < 0) ? 0 : term.col - 1; if (direction < 0) { for (; *y > 0; *y += direction) { - if (!(TLINE(*y-1)[term.col-1].mode + if (!(term.line[*y-1][term.col-1].mode & ATTR_WRAP)) { break; } } } else if (direction > 0) { for (; *y < term.row-1; *y += direction) { - if (!(TLINE(*y)[term.col-1].mode + if (!(term.line[*y][term.col-1].mode & ATTR_WRAP)) { break; } @@ -612,13 +602,13 @@ getsel(void) } if (sel.type == SEL_RECTANGULAR) { - gp = &TLINE(y)[sel.nb.x]; + gp = &term.line[y][sel.nb.x]; lastx = sel.ne.x; } else { - gp = &TLINE(y)[sel.nb.y == y ? sel.nb.x : 0]; + gp = &term.line[y][sel.nb.y == y ? sel.nb.x : 0]; lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1; } - last = &TLINE(y)[MIN(lastx, linelen-1)]; + last = &term.line[y][MIN(lastx, linelen-1)]; while (last >= gp && last->u == ' ') --last; @@ -854,9 +844,6 @@ void ttywrite(const char *s, size_t n, int may_echo) { const char *next; - Arg arg = (Arg) { .i = term.scr }; - - kscrolldown(&arg); if (may_echo && IS_SET(MODE_ECHO)) twrite(s, n, 1); @@ -1056,12 +1043,6 @@ tnew(int col, int row) treset(); } -int -tisaltscr(void) -{ - return IS_SET(MODE_ALTSCREEN); -} - void tswapscreen(void) { @@ -1074,52 +1055,12 @@ tswapscreen(void) } void -kscrolldown(const Arg* a) -{ - int n = a->i; - - if (n < 0) - n = term.row + n; - - if (n > term.scr) - n = term.scr; - - if (term.scr > 0) { - term.scr -= n; - selscroll(0, -n); - tfulldirt(); - } -} - -void -kscrollup(const Arg* a) -{ - int n = a->i; - - if (n < 0) - n = term.row + n; - - if (term.scr <= HISTSIZE-n) { - term.scr += n; - selscroll(0, n); - tfulldirt(); - } -} - -void -tscrolldown(int orig, int n, int copyhist) +tscrolldown(int orig, int n) { int i; Line temp; LIMIT(n, 0, term.bot-orig+1); - if (copyhist) { - term.histi = (term.histi - 1 + HISTSIZE) % HISTSIZE; - temp = term.hist[term.histi]; - term.hist[term.histi] = term.line[term.bot]; - term.line[term.bot] = temp; - } - tsetdirt(orig, term.bot-n); tclearregion(0, term.bot-n+1, term.col-1, term.bot); @@ -1130,28 +1071,17 @@ tscrolldown(int orig, int n, int copyhist) term.line[i-n] = temp; } - if (term.scr == 0) - selscroll(orig, n); + selscroll(orig, n); } void -tscrollup(int orig, int n, int copyhist) +tscrollup(int orig, int n) { int i; Line temp; LIMIT(n, 0, term.bot-orig+1); - if (copyhist) { - term.histi = (term.histi + 1) % HISTSIZE; - temp = term.hist[term.histi]; - term.hist[term.histi] = term.line[orig]; - term.line[orig] = temp; - } - - if (term.scr > 0 && term.scr < HISTSIZE) - term.scr = MIN(term.scr + n, HISTSIZE-1); - tclearregion(0, orig, term.col-1, orig+n-1); tsetdirt(orig+n, term.bot); @@ -1161,14 +1091,13 @@ tscrollup(int orig, int n, int copyhist) term.line[i+n] = temp; } - if (term.scr == 0) - selscroll(orig, -n); + selscroll(orig, -n); } void selscroll(int orig, int n) { - if (sel.ob.x == -1) + if (sel.ob.x == -1 || sel.alt != IS_SET(MODE_ALTSCREEN)) return; if (BETWEEN(sel.nb.y, orig, term.bot) != BETWEEN(sel.ne.y, orig, term.bot)) { @@ -1191,35 +1120,13 @@ tnewline(int first_col) int y = term.c.y; if (y == term.bot) { - tscrollup(term.top, 1, 1); + tscrollup(term.top, 1); } else { y++; } tmoveto(first_col ? 0 : term.c.x, y); } -void -readcolonargs(char **p, int cursor, int params[][CAR_PER_ARG]) -{ - int i = 0; - for (; i < CAR_PER_ARG; i++) - params[cursor][i] = -1; - - if (**p != ':') - return; - - char *np = NULL; - i = 0; - - while (**p == ':' && i < CAR_PER_ARG) { - while (**p == ':') - (*p)++; - params[cursor][i] = strtol(*p, &np, 10); - *p = np; - i++; - } -} - void csiparse(void) { @@ -1242,7 +1149,6 @@ csiparse(void) v = -1; csiescseq.arg[csiescseq.narg++] = v; p = np; - readcolonargs(&p, csiescseq.narg-1, csiescseq.carg); if (*p != ';' || csiescseq.narg == ESC_ARG_SIZ) break; p++; @@ -1309,9 +1215,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 @@ -1382,14 +1285,14 @@ void tinsertblankline(int n) { if (BETWEEN(term.c.y, term.top, term.bot)) - tscrolldown(term.c.y, n, 0); + tscrolldown(term.c.y, n); } void tdeleteline(int n) { if (BETWEEN(term.c.y, term.top, term.bot)) - tscrollup(term.c.y, n, 0); + tscrollup(term.c.y, n); } int32_t @@ -1462,10 +1365,6 @@ tsetattr(const int *attr, int l) ATTR_STRUCK ); term.c.attr.fg = defaultfg; term.c.attr.bg = defaultbg; - term.c.attr.ustyle = -1; - term.c.attr.ucolor[0] = -1; - term.c.attr.ucolor[1] = -1; - term.c.attr.ucolor[2] = -1; break; case 1: term.c.attr.mode |= ATTR_BOLD; @@ -1477,14 +1376,7 @@ tsetattr(const int *attr, int l) term.c.attr.mode |= ATTR_ITALIC; break; case 4: - term.c.attr.ustyle = csiescseq.carg[i][0]; - - if (term.c.attr.ustyle != 0) - term.c.attr.mode |= ATTR_UNDERLINE; - else - term.c.attr.mode &= ~ATTR_UNDERLINE; - - term.c.attr.mode ^= ATTR_DIRTYUNDERLINE; + term.c.attr.mode |= ATTR_UNDERLINE; break; case 5: /* slow blink */ /* FALLTHROUGH */ @@ -1535,18 +1427,6 @@ tsetattr(const int *attr, int l) case 49: term.c.attr.bg = defaultbg; break; - case 58: - term.c.attr.ucolor[0] = csiescseq.carg[i][1]; - term.c.attr.ucolor[1] = csiescseq.carg[i][2]; - term.c.attr.ucolor[2] = csiescseq.carg[i][3]; - term.c.attr.mode ^= ATTR_DIRTYUNDERLINE; - break; - case 59: - term.c.attr.ucolor[0] = -1; - term.c.attr.ucolor[1] = -1; - term.c.attr.ucolor[2] = -1; - term.c.attr.mode ^= ATTR_DIRTYUNDERLINE; - break; default: if (BETWEEN(attr[i], 30, 37)) { term.c.attr.fg = attr[i] - 30; @@ -1849,11 +1729,11 @@ csihandle(void) break; case 'S': /* SU -- Scroll line up */ DEFAULT(csiescseq.arg[0], 1); - tscrollup(term.top, csiescseq.arg[0], 0); + tscrollup(term.top, csiescseq.arg[0]); break; case 'T': /* SD -- Scroll line down */ DEFAULT(csiescseq.arg[0], 1); - tscrolldown(term.top, csiescseq.arg[0], 0); + tscrolldown(term.top, csiescseq.arg[0]); break; case 'L': /* IL -- Insert blank lines */ DEFAULT(csiescseq.arg[0], 1); @@ -1929,33 +1809,6 @@ csihandle(void) goto unknown; } break; - case 't': /* title stack operations */ - switch (csiescseq.arg[0]) { - case 22: /* pust current title on stack */ - switch (csiescseq.arg[1]) { - case 0: - case 1: - case 2: - xpushtitle(); - break; - default: - goto unknown; - } - break; - case 23: /* pop last title from stack */ - switch (csiescseq.arg[1]) { - case 0: - case 1: - case 2: - xsettitle(NULL, 1); - break; - default: - goto unknown; - } - break; - default: - goto unknown; - } } } @@ -2034,7 +1887,7 @@ strhandle(void) switch (par) { case 0: if (narg > 1) { - xsettitle(strescseq.args[1], 0); + xsettitle(strescseq.args[1]); xseticontitle(strescseq.args[1]); } return; @@ -2044,7 +1897,7 @@ strhandle(void) return; case 2: if (narg > 1) - xsettitle(strescseq.args[1], 0); + xsettitle(strescseq.args[1]); return; case 52: if (narg > 2 && allowwindowops) { @@ -2103,7 +1956,7 @@ strhandle(void) } break; case 'k': /* old title set compatibility */ - xsettitle(strescseq.args[0], 0); + xsettitle(strescseq.args[0]); return; case 'P': /* DCS -- Device Control String */ case '_': /* APC -- Application Program Command */ @@ -2452,7 +2305,7 @@ eschandle(uchar ascii) return 0; case 'D': /* IND -- Linefeed */ if (term.c.y == term.bot) { - tscrollup(term.top, 1, 1); + tscrollup(term.top, 1); } else { tmoveto(term.c.x, term.c.y+1); } @@ -2465,7 +2318,7 @@ eschandle(uchar ascii) break; case 'M': /* RI -- Reverse index */ if (term.c.y == term.top) { - tscrolldown(term.top, 1, 1); + tscrolldown(term.top, 1); } else { tmoveto(term.c.x, term.c.y-1); } @@ -2475,9 +2328,9 @@ eschandle(uchar ascii) break; case 'c': /* RIS -- Reset to initial state */ treset(); - xfreetitlestack(); resettitle(); xloadcols(); + xsetmode(0, MODE_HIDE); break; case '=': /* DECPAM -- Application keypad */ xsetmode(1, MODE_APPKEYPAD); @@ -2619,11 +2472,16 @@ check_control_code: gp = &term.line[term.c.y][term.c.x]; } - if (IS_SET(MODE_INSERT) && term.c.x+width < term.col) + if (IS_SET(MODE_INSERT) && term.c.x+width < term.col) { memmove(gp+width, gp, (term.col - term.c.x - width) * sizeof(Glyph)); + gp->mode &= ~ATTR_WIDE; + } if (term.c.x+width > term.col) { - tnewline(1); + if (IS_SET(MODE_WRAP)) + tnewline(1); + else + tmoveto(term.col - width, term.c.y); gp = &term.line[term.c.y][term.c.x]; } @@ -2683,7 +2541,7 @@ twrite(const char *buf, int buflen, int show_ctrl) void tresize(int col, int row) { - int i, j; + int i; int minrow = MIN(row, term.row); int mincol = MIN(col, term.col); int *bp; @@ -2720,14 +2578,6 @@ tresize(int col, int row) term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty)); term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs)); - for (i = 0; i < HISTSIZE; i++) { - term.hist[i] = xrealloc(term.hist[i], col * sizeof(Glyph)); - for (j = mincol; j < col; j++) { - term.hist[i][j] = term.c.attr; - term.hist[i][j].u = ' '; - } - } - /* resize each row to new width, zero-pad if needed */ for (i = 0; i < minrow; i++) { term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph)); @@ -2773,7 +2623,7 @@ tresize(int col, int row) void resettitle(void) { - xsettitle(NULL, 0); + xsettitle(NULL); } void @@ -2786,7 +2636,7 @@ drawregion(int x1, int y1, int x2, int y2) continue; term.dirty[y] = 0; - xdrawline(TLINE(y), x1, y, x2); + xdrawline(term.line[y], x1, y, x2); } } @@ -2807,10 +2657,8 @@ draw(void) cx--; drawregion(0, 0, term.col, term.row); - if (term.scr == 0) - xdrawcursor(cx, term.c.y, TLINE(term.c.y)[cx], - term.ocx, term.ocy, TLINE(term.ocy)[term.ocx], - TLINE(term.ocy), term.col); + xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], + term.ocx, term.ocy, term.line[term.ocy][term.ocx]); term.ocx = cx; term.ocy = term.c.y; xfinishdraw(); diff --git a/st.h b/st.h index f0995fb..fd3b0d8 100644 --- a/st.h +++ b/st.h @@ -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)) != ((b).mode & (~ATTR_WRAP)) || \ - (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,10 +33,7 @@ enum glyph_attribute { ATTR_WRAP = 1 << 8, ATTR_WIDE = 1 << 9, ATTR_WDUMMY = 1 << 10, - ATTR_BOXDRAW = 1 << 11, - ATTR_SELECTED = 1 << 12, ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT, - ATTR_DIRTYUNDERLINE = 1 << 15, }; enum selection_mode { @@ -69,8 +65,6 @@ typedef struct { ushort mode; /* attribute flags */ uint32_t fg; /* foreground */ uint32_t bg; /* background */ - int ustyle; /* underline style */ - int ucolor[3]; /* underline color */ } Glyph; typedef Glyph *Line; @@ -87,15 +81,12 @@ void die(const char *, ...); void redraw(void); void draw(void); -void kscrolldown(const Arg *); -void kscrollup(const Arg *); void printscreen(const Arg *); void printsel(const Arg *); void sendbreak(const Arg *); void toggleprinter(const Arg *); int tattrset(int); -int tisaltscr(void); void tnew(int, int); void tresize(int, int); void tsetdirtattr(int); @@ -120,14 +111,6 @@ 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 - /* config.h globals */ extern char *utmp; extern char *scroll; @@ -141,4 +124,3 @@ extern unsigned int tabspaces; extern unsigned int defaultfg; extern unsigned int defaultbg; extern unsigned int defaultcs; -extern const int boxdraw, boxdraw_bold, boxdraw_braille; diff --git a/st.info b/st.info index c3bfbb1..efab2cf 100644 --- a/st.info +++ b/st.info @@ -1,5 +1,4 @@ st-mono| simpleterm monocolor, - Su, acsc=+C\,D-A.B0E``aaffgghFiGjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~, am, bce, @@ -162,7 +161,7 @@ st-mono| simpleterm monocolor, rin=\E[%p1%dT, ritm=\E[23m, rmacs=\E(B, - rmcup=\E[?1049l\E[23;0;0t, + rmcup=\E[?1049l, rmir=\E[4l, rmkx=\E[?1l\E>, rmso=\E[27m, @@ -173,7 +172,7 @@ st-mono| simpleterm monocolor, sitm=\E[3m, sgr0=\E[0m, smacs=\E(0, - smcup=\E[?1049h\E[22;0;0t, + smcup=\E[?1049h, smir=\E[4h, smkx=\E[?1h\E=, smso=\E[7m, @@ -185,6 +184,10 @@ st-mono| simpleterm monocolor, # XTerm extensions rmxx=\E[29m, smxx=\E[9m, + BE=\E[?2004h, + BD=\E[?2004l, + PS=\E[200~, + PE=\E[201~, # 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) diff --git a/win.h b/win.h index 8712eea..6de960d 100644 --- a/win.h +++ b/win.h @@ -25,16 +25,14 @@ 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 xfreetitlestack(void); -void xsettitle(char *, int); -void xpushtitle(void); +void xsettitle(char *); int xsetcursor(int); void xsetmode(int, unsigned int); void xsetpointermotion(int); diff --git a/x.c b/x.c index 886205f..b36fb8c 100644 --- a/x.c +++ b/x.c @@ -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 { @@ -35,7 +34,6 @@ typedef struct { void (*func)(const Arg *); const Arg arg; uint release; - int altscrn; /* 0: don't care, -1: not alt screen, 1: alt screen */ } MouseShortcut; typedef struct { @@ -47,14 +45,6 @@ typedef struct { signed char appcursor; /* application cursor */ } Key; -/* Undercurl slope types */ -enum undercurl_slope_type { - UNDERCURL_SLOPE_ASCENDING = 0, - UNDERCURL_SLOPE_TOP_CAP = 1, - UNDERCURL_SLOPE_DESCENDING = 2, - UNDERCURL_SLOPE_BOTTOM_CAP = 3 -}; - /* X modifiers */ #define XK_ANY_MOD UINT_MAX #define XK_NO_MOD 0 @@ -73,9 +63,6 @@ static void ttysend(const Arg *); /* config.h for applying patches and the configuration. */ #include "config.h" -/* size of title stack */ -#define TITLESTACKSIZE 8 - /* XEMBED messages */ #define XEMBED_FOCUS_IN 4 #define XEMBED_FOCUS_OUT 5 @@ -94,7 +81,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 */ @@ -155,7 +141,6 @@ typedef struct { } DC; static inline ushort sixd_to_16bit(int); -static void xresetfontsettings(ushort mode, Font **font, int *frcflags); static int xmakeglyphfontspecs(XftGlyphFontSpec *, const Glyph *, int, int, int); static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int); static void xdrawglyph(Glyph, int, int); @@ -235,8 +220,6 @@ static DC dc; static XWindow xw; static XSelection xsel; static TermWindow win; -static int tstki; /* title stack index */ -static char *titlestack[TITLESTACKSIZE]; /* title stack */ /* Font Ring Cache */ enum { @@ -268,10 +251,8 @@ static char *opt_io = NULL; static char *opt_line = NULL; static char *opt_name = NULL; static char *opt_title = NULL; -static char *opt_dir = NULL; static uint buttons; /* bit field of pressed buttons */ -static int cursorblinks = 0; void clipcopy(const Arg *dummy) @@ -350,7 +331,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; } @@ -358,7 +339,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; } @@ -474,7 +455,6 @@ mouseaction(XEvent *e, uint release) for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) { if (ms->release == release && ms->button == e->xbutton.button && - (!ms->altscrn || (ms->altscrn == (tisaltscr() ? 1 : -1))) && (match(ms->mod, state) || /* exact or forced */ match(ms->mod, state & ~forcemousemod))) { ms->func(&(ms->arg)); @@ -759,9 +739,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); @@ -780,7 +757,7 @@ xresize(int col, int row) xclear(0, 0, win.w, win.h); /* resize to new width */ - xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec) * 4); + xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec)); } ushort @@ -841,7 +818,7 @@ xloadcols(void) int xgetcolor(int x, unsigned char *r, unsigned char *g, unsigned char *b) { - if (!BETWEEN(x, 0, dc.collen)) + if (!BETWEEN(x, 0, dc.collen - 1)) return 1; *r = dc.col[x].color.red >> 8; @@ -856,7 +833,7 @@ xsetcolorname(int x, const char *name) { Color ncolor; - if (!BETWEEN(x, 0, dc.collen)) + if (!BETWEEN(x, 0, dc.collen - 1)) return 1; if (!xloadcolor(x, name, &ncolor)) @@ -892,8 +869,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; @@ -1085,9 +1062,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); @@ -1178,8 +1152,8 @@ xinit(int cols, int rows) xloadcols(); /* adjust fixed window geometry */ - win.w = 2 * win.hborderpx + 2 * borderpx + cols * win.cw; - win.h = 2 * win.vborderpx + 2 * borderpx + 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) @@ -1211,7 +1185,7 @@ xinit(int cols, int rows) XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h); /* font spec buffer */ - xw.specbuf = xmalloc(cols * sizeof(GlyphFontSpec) * 4); + xw.specbuf = xmalloc(cols * sizeof(GlyphFontSpec)); /* Xft rendering context */ xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap); @@ -1263,30 +1237,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); -} - -void -xresetfontsettings(ushort mode, Font **font, int *frcflags) -{ - *font = &dc.font; - if ((mode & ATTR_ITALIC) && (mode & ATTR_BOLD)) { - *font = &dc.ibfont; - *frcflags = FRC_ITALICBOLD; - } else if (mode & ATTR_ITALIC) { - *font = &dc.ifont; - *frcflags = FRC_ITALIC; - } else if (mode & ATTR_BOLD) { - *font = &dc.bfont; - *frcflags = FRC_BOLD; - } } 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; @@ -1297,211 +1253,129 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x FcPattern *fcpattern, *fontpattern; FcFontSet *fcsets[] = { NULL }; FcCharSet *fccharset; - int i, f, length = 0, start = 0, numspecs = 0; - float cluster_xp = xp, cluster_yp = yp; - HbTransformData shaped = { 0 }; - - /* Initial values. */ - mode = prevmode = glyphs[0].mode; - xresetfontsettings(mode, &font, &frcflags); + int i, f, numspecs = 0; for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) { + /* Fetch rune and mode for current glyph. */ + rune = glyphs[i].u; mode = glyphs[i].mode; /* Skip dummy wide-character spacing. */ - if (mode & ATTR_WDUMMY && i < (len - 1)) + if (mode == ATTR_WDUMMY) continue; - if ( - prevmode != mode - || ATTRCMP(glyphs[start], glyphs[i]) - || selected(x + i, y) != selected(x + start, y) - || i == (len - 1) - ) { - /* Handle 1-character wide segments and end of line */ - length = i - start; - if (i == start) { - length = 1; - } else if (i == (len - 1)) { - length = (i - start + 1); + /* Determine font for glyph if different from previous glyph. */ + if (prevmode != mode) { + prevmode = mode; + font = &dc.font; + frcflags = FRC_NORMAL; + runewidth = win.cw * ((mode & ATTR_WIDE) ? 2.0f : 1.0f); + if ((mode & ATTR_ITALIC) && (mode & ATTR_BOLD)) { + font = &dc.ibfont; + frcflags = FRC_ITALICBOLD; + } else if (mode & ATTR_ITALIC) { + font = &dc.ifont; + frcflags = FRC_ITALIC; + } else if (mode & ATTR_BOLD) { + font = &dc.bfont; + frcflags = FRC_BOLD; } + yp = winy + font->ascent; + } - /* Shape the segment. */ - hbtransform(&shaped, font->match, glyphs, start, length); - runewidth = win.cw * ((glyphs[start].mode & ATTR_WIDE) ? 2.0f : 1.0f); - cluster_xp = xp; cluster_yp = yp; - for (int code_idx = 0; code_idx < shaped.count; code_idx++) { - int idx = shaped.glyphs[code_idx].cluster; + /* Lookup character index with default font. */ + glyphidx = XftCharIndex(xw.dpy, font->match, rune); + if (glyphidx) { + specs[numspecs].font = font->match; + specs[numspecs].glyph = glyphidx; + specs[numspecs].x = (short)xp; + specs[numspecs].y = (short)yp; + xp += runewidth; + numspecs++; + continue; + } - if (glyphs[start + idx].mode & ATTR_WDUMMY) - continue; - - /* Advance the drawing cursor if we've moved to a new cluster */ - if (code_idx > 0 && idx != shaped.glyphs[code_idx - 1].cluster) { - xp += runewidth; - cluster_xp = xp; - cluster_yp = yp; - runewidth = win.cw * ((glyphs[start + idx].mode & ATTR_WIDE) ? 2.0f : 1.0f); - } - - if (glyphs[start + code_idx].mode & ATTR_BOXDRAW) { - /* minor shoehorning: boxdraw uses only this ushort */ - specs[numspecs].font = font->match; - specs[numspecs].glyph = boxdrawindex(&glyphs[start + code_idx]); - specs[numspecs].x = xp; - specs[numspecs].y = yp; - numspecs++; - } else if (shaped.glyphs[code_idx].codepoint != 0) { - /* If symbol is found, put it into the specs. */ - specs[numspecs].font = font->match; - specs[numspecs].glyph = shaped.glyphs[code_idx].codepoint; - specs[numspecs].x = cluster_xp + (short)(shaped.positions[code_idx].x_offset / 64.); - specs[numspecs].y = cluster_yp - (short)(shaped.positions[code_idx].y_offset / 64.); - cluster_xp += shaped.positions[code_idx].x_advance / 64.; - cluster_yp += shaped.positions[code_idx].y_advance / 64.; - numspecs++; - } else { - /* If it's not found, try to fetch it through the font cache. */ - rune = glyphs[start + idx].u; - for (f = 0; f < frclen; f++) { - glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune); - /* Everything correct. */ - if (glyphidx && frc[f].flags == frcflags) - break; - /* We got a default font for a not found glyph. */ - if (!glyphidx && frc[f].flags == frcflags - && frc[f].unicodep == rune) { - break; - } - } - - /* Nothing was found. Use fontconfig to find matching font. */ - if (f >= frclen) { - if (!font->set) - font->set = FcFontSort(0, font->pattern, - 1, 0, &fcres); - fcsets[0] = font->set; - - /* - * Nothing was found in the cache. Now use - * some dozen of Fontconfig calls to get the - * font for one single character. - * - * Xft and fontconfig are design failures. - */ - fcpattern = FcPatternDuplicate(font->pattern); - fccharset = FcCharSetCreate(); - - FcCharSetAddChar(fccharset, rune); - FcPatternAddCharSet(fcpattern, FC_CHARSET, - fccharset); - FcPatternAddBool(fcpattern, FC_SCALABLE, 1); - - FcConfigSubstitute(0, fcpattern, - FcMatchPattern); - FcDefaultSubstitute(fcpattern); - - fontpattern = FcFontSetMatch(0, fcsets, 1, - fcpattern, &fcres); - - /* Allocate memory for the new cache entry. */ - if (frclen >= frccap) { - frccap += 16; - frc = xrealloc(frc, frccap * sizeof(Fontcache)); - } - - frc[frclen].font = XftFontOpenPattern(xw.dpy, - fontpattern); - if (!frc[frclen].font) - die("XftFontOpenPattern failed seeking fallback font: %s\n", - strerror(errno)); - frc[frclen].flags = frcflags; - frc[frclen].unicodep = rune; - - glyphidx = XftCharIndex(xw.dpy, frc[frclen].font, rune); - - f = frclen; - frclen++; - - FcPatternDestroy(fcpattern); - FcCharSetDestroy(fccharset); - } - - specs[numspecs].font = frc[f].font; - specs[numspecs].glyph = glyphidx; - specs[numspecs].x = (short)xp; - specs[numspecs].y = (short)yp; - numspecs++; - } - } - - /* Cleanup and get ready for next segment. */ - hbcleanup(&shaped); - start = i; - - /* Determine font for glyph if different from previous glyph. */ - if (prevmode != mode) { - prevmode = mode; - xresetfontsettings(mode, &font, &frcflags); - yp = winy + font->ascent; + /* Fallback on font cache, search the font cache for match. */ + for (f = 0; f < frclen; f++) { + glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune); + /* Everything correct. */ + if (glyphidx && frc[f].flags == frcflags) + break; + /* We got a default font for a not found glyph. */ + if (!glyphidx && frc[f].flags == frcflags + && frc[f].unicodep == rune) { + break; } } + + /* Nothing was found. Use fontconfig to find matching font. */ + if (f >= frclen) { + if (!font->set) + font->set = FcFontSort(0, font->pattern, + 1, 0, &fcres); + fcsets[0] = font->set; + + /* + * Nothing was found in the cache. Now use + * some dozen of Fontconfig calls to get the + * font for one single character. + * + * Xft and fontconfig are design failures. + */ + fcpattern = FcPatternDuplicate(font->pattern); + fccharset = FcCharSetCreate(); + + FcCharSetAddChar(fccharset, rune); + FcPatternAddCharSet(fcpattern, FC_CHARSET, + fccharset); + FcPatternAddBool(fcpattern, FC_SCALABLE, 1); + + FcConfigSubstitute(0, fcpattern, + FcMatchPattern); + FcDefaultSubstitute(fcpattern); + + fontpattern = FcFontSetMatch(0, fcsets, 1, + fcpattern, &fcres); + + /* Allocate memory for the new cache entry. */ + if (frclen >= frccap) { + frccap += 16; + frc = xrealloc(frc, frccap * sizeof(Fontcache)); + } + + frc[frclen].font = XftFontOpenPattern(xw.dpy, + fontpattern); + if (!frc[frclen].font) + die("XftFontOpenPattern failed seeking fallback font: %s\n", + strerror(errno)); + frc[frclen].flags = frcflags; + frc[frclen].unicodep = rune; + + glyphidx = XftCharIndex(xw.dpy, frc[frclen].font, rune); + + f = frclen; + frclen++; + + FcPatternDestroy(fcpattern); + FcCharSetDestroy(fccharset); + } + + specs[numspecs].font = frc[f].font; + specs[numspecs].glyph = glyphidx; + specs[numspecs].x = (short)xp; + specs[numspecs].y = (short)yp; + xp += runewidth; + numspecs++; } - hbcleanup(&shaped); return numspecs; } -static int isSlopeRising (int x, int iPoint, int waveWidth) -{ - // . . . . - // / \ / \ / \ / \ - // / \ / \ / \ / \ - // . . . . . - - // Find absolute `x` of point - x += iPoint * (waveWidth/2); - - // Find index of absolute wave - int absSlope = x / ((float)waveWidth/2); - - return (absSlope % 2); -} - -static int getSlope (int x, int iPoint, int waveWidth) -{ - // Sizes: Caps are half width of slopes - // 1_2 1_2 1_2 1_2 - // / \ / \ / \ / \ - // / \ / \ / \ / \ - // 0 3_0 3_0 3_0 3_ - // <2-> <1> <---6----> - - // Find type of first point - int firstType; - x -= (x / waveWidth) * waveWidth; - if (x < (waveWidth * (2.f/6.f))) - firstType = UNDERCURL_SLOPE_ASCENDING; - else if (x < (waveWidth * (3.f/6.f))) - firstType = UNDERCURL_SLOPE_TOP_CAP; - else if (x < (waveWidth * (5.f/6.f))) - firstType = UNDERCURL_SLOPE_DESCENDING; - else - firstType = UNDERCURL_SLOPE_BOTTOM_CAP; - - // Find type of given point - int pointType = (iPoint % 4); - pointType += firstType; - pointType %= 4; - - return pointType; -} - 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; @@ -1538,6 +1412,10 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i bg = &dc.col[base.bg]; } + /* Change basic system colors [0-7] to bright system colors [8-15] */ + if ((base.mode & ATTR_BOLD_FAINT) == ATTR_BOLD && BETWEEN(base.fg, 0, 7)) + fg = &dc.col[base.fg + 8]; + if (IS_SET(MODE_REVERSE)) { if (fg == &dc.col[defaultfg]) { fg = &dc.col[defaultbg]; @@ -1579,12 +1457,6 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i bg = temp; } - if (base.mode & ATTR_SELECTED) { - bg = &dc.col[selectionbg]; - if (!ignoreselfg) - fg = &dc.col[selectionfg]; - } - if (base.mode & ATTR_BLINK && win.mode & MODE_BLINK) fg = bg; @@ -1593,17 +1465,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.hborderpx, + 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.vborderpx); - 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. */ @@ -1616,367 +1488,14 @@ 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) { - // Underline Color - const int widthThreshold = 28; // +1 width every widthThreshold px of font - int wlw = (win.ch / widthThreshold) + 1; // Wave Line Width - int linecolor; - if ((base.ucolor[0] >= 0) && - !(base.mode & ATTR_BLINK && win.mode & MODE_BLINK) && - !(base.mode & ATTR_INVISIBLE) - ) { - // Special color for underline - // Index - if (base.ucolor[1] < 0) { - linecolor = dc.col[base.ucolor[0]].pixel; - } - // RGB - else { - XColor lcolor; - lcolor.red = base.ucolor[0] * 257; - lcolor.green = base.ucolor[1] * 257; - lcolor.blue = base.ucolor[2] * 257; - lcolor.flags = DoRed | DoGreen | DoBlue; - XAllocColor(xw.dpy, xw.cmap, &lcolor); - linecolor = lcolor.pixel; - } - } else { - // Foreground color for underline - linecolor = fg->pixel; - } - - XGCValues ugcv = { - .foreground = linecolor, - .line_width = wlw, - .line_style = LineSolid, - .cap_style = CapNotLast - }; - - GC ugc = XCreateGC(xw.dpy, XftDrawDrawable(xw.draw), - GCForeground | GCLineWidth | GCLineStyle | GCCapStyle, - &ugcv); - - // Underline Style - if (base.ustyle != 3) { - //XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent * chscale + 1, width, 1); - XFillRectangle(xw.dpy, XftDrawDrawable(xw.draw), ugc, winx, - winy + dc.font.ascent * chscale + 1, width, wlw); - } else if (base.ustyle == 3) { - int ww = win.cw;//width; - int wh = dc.font.descent - wlw/2 - 1;//r.height/7; - int wx = winx; - int wy = winy + win.ch - dc.font.descent; - -#if UNDERCURL_STYLE == UNDERCURL_CURLY - // Draw waves - int narcs = charlen * 2 + 1; - XArc *arcs = xmalloc(sizeof(XArc) * narcs); - - int i = 0; - for (i = 0; i < charlen-1; i++) { - arcs[i*2] = (XArc) { - .x = wx + win.cw * i + ww / 4, - .y = wy, - .width = win.cw / 2, - .height = wh, - .angle1 = 0, - .angle2 = 180 * 64 - }; - arcs[i*2+1] = (XArc) { - .x = wx + win.cw * i + ww * 0.75, - .y = wy, - .width = win.cw/2, - .height = wh, - .angle1 = 180 * 64, - .angle2 = 180 * 64 - }; - } - // Last wave - arcs[i*2] = (XArc) {wx + ww * i + ww / 4, wy, ww / 2, wh, - 0, 180 * 64 }; - // Last wave tail - arcs[i*2+1] = (XArc) {wx + ww * i + ww * 0.75, wy, ceil(ww / 2.), - wh, 180 * 64, 90 * 64}; - // First wave tail - i++; - arcs[i*2] = (XArc) {wx - ww/4 - 1, wy, ceil(ww / 2.), wh, 270 * 64, - 90 * 64 }; - - XDrawArcs(xw.dpy, XftDrawDrawable(xw.draw), ugc, arcs, narcs); - - free(arcs); -#elif UNDERCURL_STYLE == UNDERCURL_SPIKY - // Make the underline corridor larger - /* - wy -= wh; - */ - wh *= 2; - - // Set the angle of the slope to 45° - ww = wh; - - // Position of wave is independent of word, it's absolute - wx = (wx / (ww/2)) * (ww/2); - - int marginStart = winx - wx; - - // Calculate number of points with floating precision - float n = width; // Width of word in pixels - n = (n / ww) * 2; // Number of slopes (/ or \) - n += 2; // Add two last points - int npoints = n; // Convert to int - - // Total length of underline - float waveLength = 0; - - if (npoints >= 3) { - // We add an aditional slot in case we use a bonus point - XPoint *points = xmalloc(sizeof(XPoint) * (npoints + 1)); - - // First point (Starts with the word bounds) - points[0] = (XPoint) { - .x = wx + marginStart, - .y = (isSlopeRising(wx, 0, ww)) - ? (wy - marginStart + ww/2.f) - : (wy + marginStart) - }; - - // Second point (Goes back to the absolute point coordinates) - points[1] = (XPoint) { - .x = (ww/2.f) - marginStart, - .y = (isSlopeRising(wx, 1, ww)) - ? (ww/2.f - marginStart) - : (-ww/2.f + marginStart) - }; - waveLength += (ww/2.f) - marginStart; - - // The rest of the points - for (int i = 2; i < npoints-1; i++) { - points[i] = (XPoint) { - .x = ww/2, - .y = (isSlopeRising(wx, i, ww)) - ? wh/2 - : -wh/2 - }; - waveLength += ww/2; - } - - // Last point - points[npoints-1] = (XPoint) { - .x = ww/2, - .y = (isSlopeRising(wx, npoints-1, ww)) - ? wh/2 - : -wh/2 - }; - waveLength += ww/2; - - // End - if (waveLength < width) { // Add a bonus point? - int marginEnd = width - waveLength; - points[npoints] = (XPoint) { - .x = marginEnd, - .y = (isSlopeRising(wx, npoints, ww)) - ? (marginEnd) - : (-marginEnd) - }; - - npoints++; - } else if (waveLength > width) { // Is last point too far? - int marginEnd = waveLength - width; - points[npoints-1].x -= marginEnd; - if (isSlopeRising(wx, npoints-1, ww)) - points[npoints-1].y -= (marginEnd); - else - points[npoints-1].y += (marginEnd); - } - - // Draw the lines - XDrawLines(xw.dpy, XftDrawDrawable(xw.draw), ugc, points, npoints, - CoordModePrevious); - - // Draw a second underline with an offset of 1 pixel - if ( ((win.ch / (widthThreshold/2)) % 2)) { - points[0].x++; - - XDrawLines(xw.dpy, XftDrawDrawable(xw.draw), ugc, points, - npoints, CoordModePrevious); - } - - // Free resources - free(points); - } -#else // UNDERCURL_CAPPED - // Cap is half of wave width - float capRatio = 0.5f; - - // Make the underline corridor larger - wh *= 2; - - // Set the angle of the slope to 45° - ww = wh; - ww *= 1 + capRatio; // Add a bit of width for the cap - - // Position of wave is independent of word, it's absolute - wx = (wx / ww) * ww; - - float marginStart; - switch(getSlope(winx, 0, ww)) { - case UNDERCURL_SLOPE_ASCENDING: - marginStart = winx - wx; - break; - case UNDERCURL_SLOPE_TOP_CAP: - marginStart = winx - (wx + (ww * (2.f/6.f))); - break; - case UNDERCURL_SLOPE_DESCENDING: - marginStart = winx - (wx + (ww * (3.f/6.f))); - break; - case UNDERCURL_SLOPE_BOTTOM_CAP: - marginStart = winx - (wx + (ww * (5.f/6.f))); - break; - } - - // Calculate number of points with floating precision - float n = width; // Width of word in pixels - // ._. - n = (n / ww) * 4; // Number of points (./ \.) - n += 2; // Add two last points - int npoints = n; // Convert to int - - // Position of the pen to draw the lines - float penX = 0; - float penY = 0; - - if (npoints >= 3) { - XPoint *points = xmalloc(sizeof(XPoint) * (npoints + 1)); - - // First point (Starts with the word bounds) - penX = winx; - switch (getSlope(winx, 0, ww)) { - case UNDERCURL_SLOPE_ASCENDING: - penY = wy + wh/2.f - marginStart; - break; - case UNDERCURL_SLOPE_TOP_CAP: - penY = wy; - break; - case UNDERCURL_SLOPE_DESCENDING: - penY = wy + marginStart; - break; - case UNDERCURL_SLOPE_BOTTOM_CAP: - penY = wy + wh/2.f; - break; - } - points[0].x = penX; - points[0].y = penY; - - // Second point (Goes back to the absolute point coordinates) - switch (getSlope(winx, 1, ww)) { - case UNDERCURL_SLOPE_ASCENDING: - penX += ww * (1.f/6.f) - marginStart; - penY += 0; - break; - case UNDERCURL_SLOPE_TOP_CAP: - penX += ww * (2.f/6.f) - marginStart; - penY += -wh/2.f + marginStart; - break; - case UNDERCURL_SLOPE_DESCENDING: - penX += ww * (1.f/6.f) - marginStart; - penY += 0; - break; - case UNDERCURL_SLOPE_BOTTOM_CAP: - penX += ww * (2.f/6.f) - marginStart; - penY += -marginStart + wh/2.f; - break; - } - points[1].x = penX; - points[1].y = penY; - - // The rest of the points - for (int i = 2; i < npoints; i++) { - switch (getSlope(winx, i, ww)) { - case UNDERCURL_SLOPE_ASCENDING: - case UNDERCURL_SLOPE_DESCENDING: - penX += ww * (1.f/6.f); - penY += 0; - break; - case UNDERCURL_SLOPE_TOP_CAP: - penX += ww * (2.f/6.f); - penY += -wh / 2.f; - break; - case UNDERCURL_SLOPE_BOTTOM_CAP: - penX += ww * (2.f/6.f); - penY += wh / 2.f; - break; - } - points[i].x = penX; - points[i].y = penY; - } - - // End - float waveLength = penX - winx; - if (waveLength < width) { // Add a bonus point? - int marginEnd = width - waveLength; - penX += marginEnd; - switch(getSlope(winx, npoints, ww)) { - case UNDERCURL_SLOPE_ASCENDING: - case UNDERCURL_SLOPE_DESCENDING: - //penY += 0; - break; - case UNDERCURL_SLOPE_TOP_CAP: - penY += -marginEnd; - break; - case UNDERCURL_SLOPE_BOTTOM_CAP: - penY += marginEnd; - break; - } - - points[npoints].x = penX; - points[npoints].y = penY; - - npoints++; - } else if (waveLength > width) { // Is last point too far? - int marginEnd = waveLength - width; - points[npoints-1].x -= marginEnd; - switch(getSlope(winx, npoints-1, ww)) { - case UNDERCURL_SLOPE_TOP_CAP: - points[npoints-1].y += marginEnd; - break; - case UNDERCURL_SLOPE_BOTTOM_CAP: - points[npoints-1].y -= marginEnd; - break; - default: - break; - } - } - - // Draw the lines - XDrawLines(xw.dpy, XftDrawDrawable(xw.draw), ugc, points, npoints, - CoordModeOrigin); - - // Draw a second underline with an offset of 1 pixel - if ( ((win.ch / (widthThreshold/2)) % 2)) { - for (int i = 0; i < npoints; i++) - points[i].x++; - - XDrawLines(xw.dpy, XftDrawDrawable(xw.draw), ugc, points, - npoints, CoordModeOrigin); - } - - // Free resources - free(points); - } -#endif - } - - XFreeGC(xw.dpy, ugc); - } + 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 * chscale / 3, @@ -1998,17 +1517,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_SELECTED; - - /* Redraw the line where cursor was previously. - * It will restore the ligatures broken by the cursor. */ - xdrawline(line, 0, oy, len); + og.mode ^= ATTR_REVERSE; + xdrawglyph(og, ox, oy); if (IS_SET(MODE_HIDE)) return; @@ -2016,77 +1532,72 @@ 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; - g.fg = defaultcs; g.bg = defaultfg; - drawcol = dc.col[defaultrcs]; + if (selected(cx, cy)) { + drawcol = dc.col[defaultcs]; + g.fg = defaultrcs; + } else { + drawcol = dc.col[defaultrcs]; + g.fg = defaultcs; + } } else { - g.fg = defaultbg; - g.bg = defaultcs; - drawcol = dc.col[defaultcs]; + if (selected(cx, cy)) { + g.fg = defaultfg; + g.bg = defaultrcs; + } else { + g.fg = defaultbg; + g.bg = defaultcs; + } + drawcol = dc.col[g.bg]; } /* draw the new one */ if (IS_SET(MODE_FOCUSED)) { switch (win.cursor) { - default: - case 0: /* blinking block */ - case 1: /* blinking block (default) */ - if (IS_SET(MODE_BLINK)) - break; + case 7: /* st extension */ + g.u = 0x2603; /* snowman (U+2603) */ /* FALLTHROUGH */ - case 2: /* steady block */ + case 0: /* Blinking Block */ + case 1: /* Blinking Block (Default) */ + case 2: /* Steady Block */ xdrawglyph(g, cx, cy); break; - case 3: /* blinking underline */ - if (IS_SET(MODE_BLINK)) - break; - /* FALLTHROUGH */ - case 4: /* steady underline */ + 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 */ - if (IS_SET(MODE_BLINK)) - break; - /* FALLTHROUGH */ - case 6: /* steady bar */ + 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; - case 7: /* blinking st cursor */ - if (IS_SET(MODE_BLINK)) - break; - /* FALLTHROUGH */ - case 8: /* steady st cursor */ - g.u = stcursor; - xdrawglyph(g, cx, cy); - 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); } } @@ -2115,30 +1626,10 @@ xseticontitle(char *p) } void -xfreetitlestack(void) +xsettitle(char *p) { - for (int i = 0; i < LEN(titlestack); i++) { - free(titlestack[i]); - titlestack[i] = NULL; - } -} - -void -xsettitle(char *p, int pop) -{ - XTextProperty prop; - - free(titlestack[tstki]); - if (pop) { - titlestack[tstki] = NULL; - tstki = (tstki - 1 + TITLESTACKSIZE) % TITLESTACKSIZE; - p = titlestack[tstki] ? titlestack[tstki] : opt_title; - } else if (p) { - titlestack[tstki] = xstrdup(p); - } else { - titlestack[tstki] = NULL; - p = opt_title; - } + XTextProperty prop; + DEFAULT(p, opt_title); if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle, &prop) != Success) @@ -2148,16 +1639,6 @@ xsettitle(char *p, int pop) XFree(prop.value); } -void -xpushtitle(void) -{ - int tstkin = (tstki + 1) % TITLESTACKSIZE; - - free(titlestack[tstkin]); - titlestack[tstkin] = titlestack[tstki] ? xstrdup(titlestack[tstki]) : NULL; - tstki = tstkin; -} - int xstartdraw(void) { @@ -2171,16 +1652,18 @@ xdrawline(Line line, int x1, int y1, int x2) Glyph base, new; XftGlyphFontSpec *specs = xw.specbuf; + numspecs = xmakeglyphfontspecs(specs, &line[x1], x2 - x1, x1, y1); i = ox = 0; - for (x = x1; x < x2; x++) { + for (x = x1; x < x2 && i < numspecs; x++) { new = line[x]; if (new.mode == ATTR_WDUMMY) continue; if (selected(x, y1)) - new.mode |= ATTR_SELECTED; - if ((i > 0) && ATTRCMP(base, new)) { - numspecs = xmakeglyphfontspecs(specs, &line[ox], x - ox, ox, y1); - xdrawglyphfontspecs(specs, base, numspecs, ox, y1); + new.mode ^= ATTR_REVERSE; + if (i > 0 && ATTRCMP(base, new)) { + xdrawglyphfontspecs(specs, base, i, ox, y1); + specs += i; + numspecs -= i; i = 0; } if (i == 0) { @@ -2189,10 +1672,8 @@ xdrawline(Line line, int x1, int y1, int x2) } i++; } - if (i > 0) { - numspecs = xmakeglyphfontspecs(specs, &line[ox], x2 - ox, ox, y1); - xdrawglyphfontspecs(specs, base, numspecs, ox, y1); - } + if (i > 0) + xdrawglyphfontspecs(specs, base, i, ox, y1); } void @@ -2256,12 +1737,9 @@ xsetmode(int set, unsigned int flags) int xsetcursor(int cursor) { - if (!BETWEEN(cursor, 0, 8)) /* 7-8: st extensions */ + if (!BETWEEN(cursor, 0, 7)) /* 7: st extension */ return 1; win.cursor = cursor; - cursorblinks = win.cursor == 0 || win.cursor == 1 || - win.cursor == 3 || win.cursor == 5 || - win.cursor == 7; return 0; } @@ -2508,10 +1986,6 @@ run(void) if (FD_ISSET(ttyfd, &rfd) || xev) { if (!drawing) { trigger = now; - if (IS_SET(MODE_BLINK)) { - win.mode ^= MODE_BLINK; - } - lastblink = now; drawing = 1; } timeout = (maxlatency - TIMEDIFF(now, trigger)) \ @@ -2522,7 +1996,7 @@ run(void) /* idle detected or maxlatency exhausted -> draw */ timeout = -1; - if (blinktimeout && (cursorblinks || tattrset(ATTR_BLINK))) { + if (blinktimeout && tattrset(ATTR_BLINK)) { timeout = blinktimeout - TIMEDIFF(now, lastblink); if (timeout <= 0) { if (-timeout > blinktimeout) /* start visible */ @@ -2543,12 +2017,12 @@ run(void) void usage(void) { - die("usage: %s [-aiv] [-c class] [-d path] [-f font]" - " [-g geometry] [-n name] [-o file]\n" + die("usage: %s [-aiv] [-c class] [-f font] [-g geometry]" + " [-n name] [-o file]\n" " [-T title] [-t title] [-w windowid]" " [[-e] command [args ...]]\n" - " %s [-aiv] [-c class] [-d path] [-f font]" - " [-g geometry] [-n name] [-o file]\n" + " %s [-aiv] [-c class] [-f font] [-g geometry]" + " [-n name] [-o file]\n" " [-T title] [-t title] [-w windowid] -l line" " [stty_args ...]\n", argv0, argv0); } @@ -2558,7 +2032,7 @@ main(int argc, char *argv[]) { xw.l = xw.t = 0; xw.isfixed = False; - xsetcursor(cursorstyle); + xsetcursor(cursorshape); ARGBEGIN { case 'a': @@ -2600,9 +2074,6 @@ main(int argc, char *argv[]) case 'v': die("%s " VERSION "\n", argv0); break; - case 'd': - opt_dir = EARGF(usage()); - break; default: usage(); } ARGEND; @@ -2622,7 +2093,6 @@ run: xinit(cols, rows); xsetenv(); selinit(); - chdir(opt_dir); run(); return 0;