├── FAQ ├── LEGACY ├── LICENSE ├── Makefile ├── README ├── README.md ├── TODO ├── arg.h ├── boxdraw.c ├── boxdraw.o ├── boxdraw_data.h ├── config.def.h ├── config.def.h.orig ├── config.h ├── config.mk ├── hb.c ├── hb.h ├── hb.o ├── patch ├── st-anysize-20220718-baa9357.diff ├── st-boxdraw_v2-0.8.5.diff ├── st-font2-0.8.5.diff ├── st-glyph-wide-support-boxdraw-20220411-ef05519.diff ├── st-ligatures-boxdraw-20221120-0.9.diff └── st-scrollback-0.8.5.diff ├── preview.png ├── st ├── st.1 ├── st.c ├── st.c.orig ├── st.h ├── st.h.orig ├── st.info ├── st.o ├── stclean ├── win.h ├── x.c ├── x.c.orig └── x.o /FAQ: -------------------------------------------------------------------------------- 1 | ## Why does st not handle utmp entries? 2 | 3 | Use the excellent tool of [utmp](https://git.suckless.org/utmp/) for this task. 4 | 5 | 6 | ## Some _random program_ complains that st is unknown/not recognised/unsupported/whatever! 7 | 8 | It means that st doesn’t have any terminfo entry on your system. Chances are 9 | you did not `make install`. If you just want to test it without installing it, 10 | you can manually run `tic -sx st.info`. 11 | 12 | 13 | ## Nothing works, and nothing is said about an unknown terminal! 14 | 15 | * Some programs just assume they’re running in xterm i.e. they don’t rely on 16 | terminfo. What you see is the current state of the “xterm compliance”. 17 | * Some programs don’t complain about the lacking st description and default to 18 | another terminal. In that case see the question about terminfo. 19 | 20 | 21 | ## How do I scroll back up? 22 | 23 | * Using a terminal multiplexer. 24 | * `st -e tmux` using C-b [ 25 | * `st -e screen` using C-a ESC 26 | * Using the excellent tool of [scroll](https://git.suckless.org/scroll/). 27 | * Using the scrollback [patch](https://st.suckless.org/patches/scrollback/). 28 | 29 | 30 | ## I would like to have utmp and/or scroll functionality by default 31 | 32 | You can add the absolute path of both programs in your config.h file. You only 33 | have to modify the value of utmp and scroll variables. 34 | 35 | 36 | ## Why doesn't the Del key work in some programs? 37 | 38 | Taken from the terminfo manpage: 39 | 40 | If the terminal has a keypad that transmits codes when the keys 41 | are pressed, this information can be given. Note that it is not 42 | possible to handle terminals where the keypad only works in 43 | local (this applies, for example, to the unshifted HP 2621 keys). 44 | If the keypad can be set to transmit or not transmit, give these 45 | codes as smkx and rmkx. Otherwise the keypad is assumed to 46 | always transmit. 47 | 48 | In the st case smkx=E[?1hE= and rmkx=E[?1lE>, so it is mandatory that 49 | applications which want to test against keypad keys send these 50 | sequences. 51 | 52 | But buggy applications (like bash and irssi, for example) don't do this. A fast 53 | solution for them is to use the following command: 54 | 55 | $ printf '\033[?1h\033=' >/dev/tty 56 | 57 | or 58 | $ tput smkx 59 | 60 | In the case of bash, readline is used. Readline has a different note in its 61 | manpage about this issue: 62 | 63 | enable-keypad (Off) 64 | When set to On, readline will try to enable the 65 | application keypad when it is called. Some systems 66 | need this to enable arrow keys. 67 | 68 | Adding this option to your .inputrc will fix the keypad problem for all 69 | applications using readline. 70 | 71 | If you are using zsh, then read the zsh FAQ 72 | : 73 | 74 | It should be noted that the O / [ confusion can occur with other keys 75 | such as Home and End. Some systems let you query the key sequences 76 | sent by these keys from the system's terminal database, terminfo. 77 | Unfortunately, the key sequences given there typically apply to the 78 | mode that is not the one zsh uses by default (it's the "application" 79 | mode rather than the "raw" mode). Explaining the use of terminfo is 80 | outside of the scope of this FAQ, but if you wish to use the key 81 | sequences given there you can tell the line editor to turn on 82 | "application" mode when it starts and turn it off when it stops: 83 | 84 | function zle-line-init () { echoti smkx } 85 | function zle-line-finish () { echoti rmkx } 86 | zle -N zle-line-init 87 | zle -N zle-line-finish 88 | 89 | Putting these lines into your .zshrc will fix the problems. 90 | 91 | 92 | ## How can I use meta in 8bit mode? 93 | 94 | St supports meta in 8bit mode, but the default terminfo entry doesn't 95 | use this capability. If you want it, you have to use the 'st-meta' value 96 | in TERM. 97 | 98 | 99 | ## I cannot compile st in OpenBSD 100 | 101 | OpenBSD lacks librt, despite it being mandatory in POSIX 102 | . 103 | If you want to compile st for OpenBSD you have to remove -lrt from config.mk, and 104 | st will compile without any loss of functionality, because all the functions are 105 | included in libc on this platform. 106 | 107 | 108 | ## The Backspace Case 109 | 110 | St is emulating the Linux way of handling backspace being delete and delete being 111 | backspace. 112 | 113 | This is an issue that was discussed in suckless mailing list 114 | . Here is why some old grumpy 115 | terminal users wants its backspace to be how he feels it: 116 | 117 | Well, I am going to comment why I want to change the behaviour 118 | of this key. When ASCII was defined in 1968, communication 119 | with computers was done using punched cards, or hardcopy 120 | terminals (basically a typewriter machine connected with the 121 | computer using a serial port). ASCII defines DELETE as 7F, 122 | because, in punched-card terms, it means all the holes of the 123 | card punched; it is thus a kind of 'physical delete'. In the 124 | same way, the BACKSPACE key was a non-destructive backspace, 125 | as on a typewriter. So, if you wanted to delete a character, 126 | you had to BACKSPACE and then DELETE. Another use of BACKSPACE 127 | was to type accented characters, for example 'a BACKSPACE `'. 128 | The VT100 had no BACKSPACE key; it was generated using the 129 | CONTROL key as another control character (CONTROL key sets to 130 | 0 b7 b6 b5, so it converts H (code 0x48) into BACKSPACE (code 131 | 0x08)), but it had a DELETE key in a similar position where 132 | the BACKSPACE key is located today on common PC keyboards. 133 | All the terminal emulators emulated the difference between 134 | these keys correctly: the backspace key generated a BACKSPACE 135 | (^H) and delete key generated a DELETE (^?). 136 | 137 | But a problem arose when Linus Torvalds wrote Linux. Unlike 138 | earlier terminals, the Linux virtual terminal (the terminal 139 | emulator integrated in the kernel) returned a DELETE when 140 | backspace was pressed, due to the VT100 having a DELETE key in 141 | the same position. This created a lot of problems (see [1] 142 | and [2]). Since Linux has become the king, a lot of terminal 143 | emulators today generate a DELETE when the backspace key is 144 | pressed in order to avoid problems with Linux. The result is 145 | that the only way of generating a BACKSPACE on these systems 146 | is by using CONTROL + H. (I also think that emacs had an 147 | important point here because the CONTROL + H prefix is used 148 | in emacs in some commands (help commands).) 149 | 150 | From point of view of the kernel, you can change the key 151 | for deleting a previous character with stty erase. When you 152 | connect a real terminal into a machine you describe the type 153 | of terminal, so getty configures the correct value of stty 154 | erase for this terminal. In the case of terminal emulators, 155 | however, you don't have any getty that can set the correct 156 | value of stty erase, so you always get the default value. 157 | For this reason, it is necessary to add 'stty erase ^H' to your 158 | profile if you have changed the value of the backspace key. 159 | Of course, another solution is for st itself to modify the 160 | value of stty erase. I usually have the inverse problem: 161 | when I connect to non-Unix machines, I have to press CONTROL + 162 | h to get a BACKSPACE. The inverse problem occurs when a user 163 | connects to my Unix machines from a different system with a 164 | correct backspace key. 165 | 166 | [1] http://www.ibb.net/~anne/keyboard.html 167 | [2] http://www.tldp.org/HOWTO/Keyboard-and-Console-HOWTO-5.html 168 | 169 | 170 | ## But I really want the old grumpy behaviour of my terminal 171 | 172 | Apply [1]. 173 | 174 | [1] https://st.suckless.org/patches/delkey 175 | 176 | 177 | ## Why do images not work in st using the w3m image hack? 178 | 179 | w3mimg uses a hack that draws an image on top of the terminal emulator Drawable 180 | window. The hack relies on the terminal to use a single buffer to draw its 181 | contents directly. 182 | 183 | st uses double-buffered drawing so the image is quickly replaced and may show a 184 | short flicker effect. 185 | 186 | Below is a patch example to change st double-buffering to a single Drawable 187 | buffer. 188 | 189 | diff --git a/x.c b/x.c 190 | --- a/x.c 191 | +++ b/x.c 192 | @@ -732,10 +732,6 @@ xresize(int col, int row) 193 | win.tw = col * win.cw; 194 | win.th = row * win.ch; 195 | 196 | - XFreePixmap(xw.dpy, xw.buf); 197 | - xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, 198 | - DefaultDepth(xw.dpy, xw.scr)); 199 | - XftDrawChange(xw.draw, xw.buf); 200 | xclear(0, 0, win.w, win.h); 201 | 202 | /* resize to new width */ 203 | @@ -1148,8 +1144,7 @@ xinit(int cols, int rows) 204 | gcvalues.graphics_exposures = False; 205 | dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures, 206 | &gcvalues); 207 | - xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, 208 | - DefaultDepth(xw.dpy, xw.scr)); 209 | + xw.buf = xw.win; 210 | XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel); 211 | XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h); 212 | 213 | @@ -1632,8 +1627,6 @@ xdrawline(Line line, int x1, int y1, int x2) 214 | void 215 | xfinishdraw(void) 216 | { 217 | - XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, win.w, 218 | - win.h, 0, 0); 219 | XSetForeground(xw.dpy, dc.gc, 220 | dc.col[IS_SET(MODE_REVERSE)? 221 | defaultfg : defaultbg].pixel); 222 | 223 | 224 | ## BadLength X error in Xft when trying to render emoji 225 | 226 | Xft makes st crash when rendering color emojis with the following error: 227 | 228 | "X Error of failed request: BadLength (poly request too large or internal Xlib length error)" 229 | Major opcode of failed request: 139 (RENDER) 230 | Minor opcode of failed request: 20 (RenderAddGlyphs) 231 | Serial number of failed request: 1595 232 | Current serial number in output stream: 1818" 233 | 234 | This is a known bug in Xft (not st) which happens on some platforms and 235 | combination of particular fonts and fontconfig settings. 236 | 237 | See also: 238 | https://gitlab.freedesktop.org/xorg/lib/libxft/issues/6 239 | https://bugs.freedesktop.org/show_bug.cgi?id=107534 240 | https://bugzilla.redhat.com/show_bug.cgi?id=1498269 241 | 242 | The solution is to remove color emoji fonts or disable this in the fontconfig 243 | XML configuration. As an ugly workaround (which may work only on newer 244 | fontconfig versions (FC_COLOR)), the following code can be used to mask color 245 | fonts: 246 | 247 | FcPatternAddBool(fcpattern, FC_COLOR, FcFalse); 248 | 249 | Please don't bother reporting this bug to st, but notify the upstream Xft 250 | developers about fixing this bug. 251 | 252 | As of 2022-09-05 this now seems to be finally fixed in libXft 2.3.5: 253 | https://gitlab.freedesktop.org/xorg/lib/libxft/-/blob/libXft-2.3.5/NEWS 254 | -------------------------------------------------------------------------------- /LEGACY: -------------------------------------------------------------------------------- 1 | A STATEMENT ON LEGACY SUPPORT 2 | 3 | In the terminal world there is much cruft that comes from old and unsup‐ 4 | ported terminals that inherit incompatible modes and escape sequences 5 | which noone is able to know, except when he/she comes from that time and 6 | developed a graphical vt100 emulator at that time. 7 | 8 | One goal of st is to only support what is really needed. When you en‐ 9 | counter a sequence which you really need, implement it. But while you 10 | are at it, do not add the other cruft you might encounter while sneek‐ 11 | ing at other terminal emulators. History has bloated them and there is 12 | no real evidence that most of the sequences are used today. 13 | 14 | 15 | Christoph Lohmann <20h@r-36.net> 16 | 2012-09-13T07:00:36.081271045+02:00 17 | 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT/X Consortium License 2 | 3 | © 2014-2022 Hiltjo Posthuma 4 | © 2018 Devin J. Pohly 5 | © 2014-2017 Quentin Rameau 6 | © 2009-2012 Aurélien APTEL 7 | © 2008-2017 Anselm R Garbe 8 | © 2012-2017 Roberto E. Vargas Caballero 9 | © 2012-2016 Christoph Lohmann <20h at r-36 dot net> 10 | © 2013 Eon S. Jeon 11 | © 2013 Alexander Sedov 12 | © 2013 Mark Edgar 13 | © 2013-2014 Eric Pruitt 14 | © 2013 Michael Forney 15 | © 2013-2014 Markus Teich 16 | © 2014-2015 Laslo Hunhold 17 | 18 | Permission is hereby granted, free of charge, to any person obtaining a 19 | copy of this software and associated documentation files (the "Software"), 20 | to deal in the Software without restriction, including without limitation 21 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 22 | and/or sell copies of the Software, and to permit persons to whom the 23 | Software is furnished to do so, subject to the following conditions: 24 | 25 | The above copyright notice and this permission notice shall be included in 26 | all copies or substantial portions of the Software. 27 | 28 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 29 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 30 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 31 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 32 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 33 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 34 | DEALINGS IN THE SOFTWARE. 35 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # st - simple terminal 2 | # See LICENSE file for copyright and license details. 3 | .POSIX: 4 | 5 | include config.mk 6 | 7 | SRC = st.c x.c boxdraw.c hb.c 8 | OBJ = $(SRC:.c=.o) 9 | 10 | all: options st 11 | 12 | options: 13 | @echo st build options: 14 | @echo "CFLAGS = $(STCFLAGS)" 15 | @echo "LDFLAGS = $(STLDFLAGS)" 16 | @echo "CC = $(CC)" 17 | 18 | config.h: 19 | cp config.def.h config.h 20 | 21 | .c.o: 22 | $(CC) $(STCFLAGS) -c $< 23 | 24 | st.o: config.h st.h win.h 25 | x.o: arg.h config.h st.h win.h hb.h 26 | boxdraw.o: config.h st.h boxdraw_data.h 27 | hb.o: st.h 28 | 29 | $(OBJ): config.h config.mk 30 | 31 | st: $(OBJ) 32 | $(CC) -o $@ $(OBJ) $(STLDFLAGS) 33 | 34 | clean: 35 | rm -f st $(OBJ) st-$(VERSION).tar.gz 36 | 37 | dist: clean 38 | mkdir -p st-$(VERSION) 39 | cp -R FAQ LEGACY TODO LICENSE Makefile README config.mk\ 40 | config.def.h st.info st.1 arg.h st.h win.h $(SRC)\ 41 | st-$(VERSION) 42 | tar -cf - st-$(VERSION) | gzip > st-$(VERSION).tar.gz 43 | rm -rf st-$(VERSION) 44 | 45 | install: st 46 | mkdir -p $(DESTDIR)$(PREFIX)/bin 47 | cp -f st $(DESTDIR)$(PREFIX)/bin 48 | chmod 755 $(DESTDIR)$(PREFIX)/bin/st 49 | mkdir -p $(DESTDIR)$(MANPREFIX)/man1 50 | sed "s/VERSION/$(VERSION)/g" < st.1 > $(DESTDIR)$(MANPREFIX)/man1/st.1 51 | chmod 644 $(DESTDIR)$(MANPREFIX)/man1/st.1 52 | tic -sx st.info 53 | @echo Please see the README file regarding the terminfo entry of st. 54 | 55 | uninstall: 56 | rm -f $(DESTDIR)$(PREFIX)/bin/st 57 | rm -f $(DESTDIR)$(MANPREFIX)/man1/st.1 58 | 59 | .PHONY: all options clean dist install uninstall 60 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | st - simple terminal 2 | -------------------- 3 | st is a simple terminal emulator for X which sucks less. 4 | 5 | 6 | Requirements 7 | ------------ 8 | In order to build st you need the Xlib header files. 9 | 10 | 11 | Installation 12 | ------------ 13 | Edit config.mk to match your local setup (st is installed into 14 | the /usr/local namespace by default). 15 | 16 | Afterwards enter the following command to build and install st (if 17 | necessary as root): 18 | 19 | make clean install 20 | 21 | 22 | Running st 23 | ---------- 24 | If you did not install st with make clean install, you must compile 25 | the st terminfo entry with the following command: 26 | 27 | tic -sx st.info 28 | 29 | See the man page for additional details. 30 | 31 | Credits 32 | ------- 33 | Based on Aurélien APTEL bt source code. 34 | 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | st is a simple terminal implementation for X. 2 | 3 | # **Preview** 4 |

5 | 6 |

7 | 8 | 9 | # **Quick Keybind** 10 | ``` 11 | # Copy & Paste 12 | Ctrl + Shift + C | Copy Selected 13 | Ctrl + Shift + V | Paste 14 | 15 | # Zoom 16 | Ctrl + + | Zoom In 17 | Ctrl + - | Zoom Out 18 | Ctrl + 0 | Reset Zoom 19 | 20 | # Scroll 21 | Shift + Page_Up | Scroll Up 22 | Shift + Page_Down | Scroll Down 23 | ``` 24 | 25 | # Requirements 26 | + Void 27 | ``` 28 | xbps-install pkgconf pkgconf-devel libXft-devel libX11-devel libXinerama-devel 29 | ``` 30 | + Optional (fallback is using the default monospace) 31 | [M PLUS FONT](https://github.com/coz-m/MPLUS_FONTS) 32 | 33 | # Install 34 | **Clone repo** 35 | ``` 36 | git clone https://github.com/gillgrite/st.git 37 | ``` 38 | **Build & Install** 39 | 40 | ``` 41 | ./stclean 42 | ``` 43 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | vt emulation 2 | ------------ 3 | 4 | * double-height support 5 | 6 | code & interface 7 | ---------------- 8 | 9 | * add a simple way to do multiplexing 10 | 11 | drawing 12 | ------- 13 | * add diacritics support to xdraws() 14 | * switch to a suckless font drawing library 15 | * make the font cache simpler 16 | * add better support for brightening of the upper colors 17 | 18 | bugs 19 | ---- 20 | 21 | * fix shift up/down (shift selection in emacs) 22 | * remove DEC test sequence when appropriate 23 | 24 | misc 25 | ---- 26 | 27 | $ grep -nE 'XXX|TODO' st.c 28 | 29 | -------------------------------------------------------------------------------- /arg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copy me if you can. 3 | * by 20h 4 | */ 5 | 6 | #ifndef ARG_H__ 7 | #define ARG_H__ 8 | 9 | extern char *argv0; 10 | 11 | /* use main(int argc, char *argv[]) */ 12 | #define ARGBEGIN for (argv0 = *argv, argv++, argc--;\ 13 | argv[0] && argv[0][0] == '-'\ 14 | && argv[0][1];\ 15 | argc--, argv++) {\ 16 | char argc_;\ 17 | char **argv_;\ 18 | int brk_;\ 19 | if (argv[0][1] == '-' && argv[0][2] == '\0') {\ 20 | argv++;\ 21 | argc--;\ 22 | break;\ 23 | }\ 24 | int i_;\ 25 | for (i_ = 1, brk_ = 0, argv_ = argv;\ 26 | argv[0][i_] && !brk_;\ 27 | i_++) {\ 28 | if (argv_ != argv)\ 29 | break;\ 30 | argc_ = argv[0][i_];\ 31 | switch (argc_) 32 | 33 | #define ARGEND }\ 34 | } 35 | 36 | #define ARGC() argc_ 37 | 38 | #define EARGF(x) ((argv[0][i_+1] == '\0' && argv[1] == NULL)?\ 39 | ((x), abort(), (char *)0) :\ 40 | (brk_ = 1, (argv[0][i_+1] != '\0')?\ 41 | (&argv[0][i_+1]) :\ 42 | (argc--, argv++, argv[0]))) 43 | 44 | #define ARGF() ((argv[0][i_+1] == '\0' && argv[1] == NULL)?\ 45 | (char *)0 :\ 46 | (brk_ = 1, (argv[0][i_+1] != '\0')?\ 47 | (&argv[0][i_+1]) :\ 48 | (argc--, argv++, argv[0]))) 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /boxdraw.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Avi Halachmi (:avih) avihpit@yahoo.com https://github.com/avih 3 | * MIT/X Consortium License 4 | */ 5 | 6 | #include 7 | #include "st.h" 8 | #include "boxdraw_data.h" 9 | 10 | /* Rounded non-negative integers division of n / d */ 11 | #define DIV(n, d) (((n) + (d) / 2) / (d)) 12 | 13 | static Display *xdpy; 14 | static Colormap xcmap; 15 | static XftDraw *xd; 16 | static Visual *xvis; 17 | 18 | static void drawbox(int, int, int, int, XftColor *, XftColor *, ushort); 19 | static void drawboxlines(int, int, int, int, XftColor *, ushort); 20 | 21 | /* public API */ 22 | 23 | void 24 | boxdraw_xinit(Display *dpy, Colormap cmap, XftDraw *draw, Visual *vis) 25 | { 26 | xdpy = dpy; xcmap = cmap; xd = draw, xvis = vis; 27 | } 28 | 29 | int 30 | isboxdraw(Rune u) 31 | { 32 | Rune block = u & ~0xff; 33 | return (boxdraw && block == 0x2500 && boxdata[(uint8_t)u]) || 34 | (boxdraw_braille && block == 0x2800); 35 | } 36 | 37 | /* the "index" is actually the entire shape data encoded as ushort */ 38 | ushort 39 | boxdrawindex(const Glyph *g) 40 | { 41 | if (boxdraw_braille && (g->u & ~0xff) == 0x2800) 42 | return BRL | (uint8_t)g->u; 43 | if (boxdraw_bold && (g->mode & ATTR_BOLD)) 44 | return BDB | boxdata[(uint8_t)g->u]; 45 | return boxdata[(uint8_t)g->u]; 46 | } 47 | 48 | void 49 | drawboxes(int x, int y, int cw, int ch, XftColor *fg, XftColor *bg, 50 | const XftGlyphFontSpec *specs, int len) 51 | { 52 | for ( ; len-- > 0; x += cw, specs++) 53 | drawbox(x, y, cw, ch, fg, bg, (ushort)specs->glyph); 54 | } 55 | 56 | /* implementation */ 57 | 58 | void 59 | drawbox(int x, int y, int w, int h, XftColor *fg, XftColor *bg, ushort bd) 60 | { 61 | ushort cat = bd & ~(BDB | 0xff); /* mask out bold and data */ 62 | if (bd & (BDL | BDA)) { 63 | /* lines (light/double/heavy/arcs) */ 64 | drawboxlines(x, y, w, h, fg, bd); 65 | 66 | } else if (cat == BBD) { 67 | /* lower (8-X)/8 block */ 68 | int d = DIV((uint8_t)bd * h, 8); 69 | XftDrawRect(xd, fg, x, y + d, w, h - d); 70 | 71 | } else if (cat == BBU) { 72 | /* upper X/8 block */ 73 | XftDrawRect(xd, fg, x, y, w, DIV((uint8_t)bd * h, 8)); 74 | 75 | } else if (cat == BBL) { 76 | /* left X/8 block */ 77 | XftDrawRect(xd, fg, x, y, DIV((uint8_t)bd * w, 8), h); 78 | 79 | } else if (cat == BBR) { 80 | /* right (8-X)/8 block */ 81 | int d = DIV((uint8_t)bd * w, 8); 82 | XftDrawRect(xd, fg, x + d, y, w - d, h); 83 | 84 | } else if (cat == BBQ) { 85 | /* Quadrants */ 86 | int w2 = DIV(w, 2), h2 = DIV(h, 2); 87 | if (bd & TL) 88 | XftDrawRect(xd, fg, x, y, w2, h2); 89 | if (bd & TR) 90 | XftDrawRect(xd, fg, x + w2, y, w - w2, h2); 91 | if (bd & BL) 92 | XftDrawRect(xd, fg, x, y + h2, w2, h - h2); 93 | if (bd & BR) 94 | XftDrawRect(xd, fg, x + w2, y + h2, w - w2, h - h2); 95 | 96 | } else if (bd & BBS) { 97 | /* Shades - data is 1/2/3 for 25%/50%/75% alpha, respectively */ 98 | int d = (uint8_t)bd; 99 | XftColor xfc; 100 | XRenderColor xrc = { .alpha = 0xffff }; 101 | 102 | xrc.red = DIV(fg->color.red * d + bg->color.red * (4 - d), 4); 103 | xrc.green = DIV(fg->color.green * d + bg->color.green * (4 - d), 4); 104 | xrc.blue = DIV(fg->color.blue * d + bg->color.blue * (4 - d), 4); 105 | 106 | XftColorAllocValue(xdpy, xvis, xcmap, &xrc, &xfc); 107 | XftDrawRect(xd, &xfc, x, y, w, h); 108 | XftColorFree(xdpy, xvis, xcmap, &xfc); 109 | 110 | } else if (cat == BRL) { 111 | /* braille, each data bit corresponds to one dot at 2x4 grid */ 112 | int w1 = DIV(w, 2); 113 | int h1 = DIV(h, 4), h2 = DIV(h, 2), h3 = DIV(3 * h, 4); 114 | 115 | if (bd & 1) XftDrawRect(xd, fg, x, y, w1, h1); 116 | if (bd & 2) XftDrawRect(xd, fg, x, y + h1, w1, h2 - h1); 117 | if (bd & 4) XftDrawRect(xd, fg, x, y + h2, w1, h3 - h2); 118 | if (bd & 8) XftDrawRect(xd, fg, x + w1, y, w - w1, h1); 119 | if (bd & 16) XftDrawRect(xd, fg, x + w1, y + h1, w - w1, h2 - h1); 120 | if (bd & 32) XftDrawRect(xd, fg, x + w1, y + h2, w - w1, h3 - h2); 121 | if (bd & 64) XftDrawRect(xd, fg, x, y + h3, w1, h - h3); 122 | if (bd & 128) XftDrawRect(xd, fg, x + w1, y + h3, w - w1, h - h3); 123 | 124 | } 125 | } 126 | 127 | void 128 | drawboxlines(int x, int y, int w, int h, XftColor *fg, ushort bd) 129 | { 130 | /* s: stem thickness. width/8 roughly matches underscore thickness. */ 131 | /* We draw bold as 1.5 * normal-stem and at least 1px thicker. */ 132 | /* doubles draw at least 3px, even when w or h < 3. bold needs 6px. */ 133 | int mwh = MIN(w, h); 134 | int base_s = MAX(1, DIV(mwh, 8)); 135 | int bold = (bd & BDB) && mwh >= 6; /* possibly ignore boldness */ 136 | int s = bold ? MAX(base_s + 1, DIV(3 * base_s, 2)) : base_s; 137 | int w2 = DIV(w - s, 2), h2 = DIV(h - s, 2); 138 | /* the s-by-s square (x + w2, y + h2, s, s) is the center texel. */ 139 | /* The base length (per direction till edge) includes this square. */ 140 | 141 | int light = bd & (LL | LU | LR | LD); 142 | int double_ = bd & (DL | DU | DR | DD); 143 | 144 | if (light) { 145 | /* d: additional (negative) length to not-draw the center */ 146 | /* texel - at arcs and avoid drawing inside (some) doubles */ 147 | int arc = bd & BDA; 148 | int multi_light = light & (light - 1); 149 | int multi_double = double_ & (double_ - 1); 150 | /* light crosses double only at DH+LV, DV+LH (ref. shapes) */ 151 | int d = arc || (multi_double && !multi_light) ? -s : 0; 152 | 153 | if (bd & LL) 154 | XftDrawRect(xd, fg, x, y + h2, w2 + s + d, s); 155 | if (bd & LU) 156 | XftDrawRect(xd, fg, x + w2, y, s, h2 + s + d); 157 | if (bd & LR) 158 | XftDrawRect(xd, fg, x + w2 - d, y + h2, w - w2 + d, s); 159 | if (bd & LD) 160 | XftDrawRect(xd, fg, x + w2, y + h2 - d, s, h - h2 + d); 161 | } 162 | 163 | /* double lines - also align with light to form heavy when combined */ 164 | if (double_) { 165 | /* 166 | * going clockwise, for each double-ray: p is additional length 167 | * to the single-ray nearer to the previous direction, and n to 168 | * the next. p and n adjust from the base length to lengths 169 | * which consider other doubles - shorter to avoid intersections 170 | * (p, n), or longer to draw the far-corner texel (n). 171 | */ 172 | int dl = bd & DL, du = bd & DU, dr = bd & DR, dd = bd & DD; 173 | if (dl) { 174 | int p = dd ? -s : 0, n = du ? -s : dd ? s : 0; 175 | XftDrawRect(xd, fg, x, y + h2 + s, w2 + s + p, s); 176 | XftDrawRect(xd, fg, x, y + h2 - s, w2 + s + n, s); 177 | } 178 | if (du) { 179 | int p = dl ? -s : 0, n = dr ? -s : dl ? s : 0; 180 | XftDrawRect(xd, fg, x + w2 - s, y, s, h2 + s + p); 181 | XftDrawRect(xd, fg, x + w2 + s, y, s, h2 + s + n); 182 | } 183 | if (dr) { 184 | int p = du ? -s : 0, n = dd ? -s : du ? s : 0; 185 | XftDrawRect(xd, fg, x + w2 - p, y + h2 - s, w - w2 + p, s); 186 | XftDrawRect(xd, fg, x + w2 - n, y + h2 + s, w - w2 + n, s); 187 | } 188 | if (dd) { 189 | int p = dr ? -s : 0, n = dl ? -s : dr ? s : 0; 190 | XftDrawRect(xd, fg, x + w2 + s, y + h2 - p, s, h - h2 + p); 191 | XftDrawRect(xd, fg, x + w2 - s, y + h2 - n, s, h - h2 + n); 192 | } 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /boxdraw.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motolla/st/80a40a50d86193c9524ca91ae73bba192ad9a9d1/boxdraw.o -------------------------------------------------------------------------------- /boxdraw_data.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Avi Halachmi (:avih) avihpit@yahoo.com https://github.com/avih 3 | * MIT/X Consortium License 4 | */ 5 | 6 | /* 7 | * U+25XX codepoints data 8 | * 9 | * References: 10 | * http://www.unicode.org/charts/PDF/U2500.pdf 11 | * http://www.unicode.org/charts/PDF/U2580.pdf 12 | * 13 | * Test page: 14 | * https://github.com/GNOME/vte/blob/master/doc/boxes.txt 15 | */ 16 | 17 | /* Each shape is encoded as 16-bits. Higher bits are category, lower are data */ 18 | /* Categories (mutually exclusive except BDB): */ 19 | /* For convenience, BDL/BDA/BBS/BDB are 1 bit each, the rest are enums */ 20 | #define BDL (1<<8) /* Box Draw Lines (light/double/heavy) */ 21 | #define BDA (1<<9) /* Box Draw Arc (light) */ 22 | 23 | #define BBD (1<<10) /* Box Block Down (lower) X/8 */ 24 | #define BBL (2<<10) /* Box Block Left X/8 */ 25 | #define BBU (3<<10) /* Box Block Upper X/8 */ 26 | #define BBR (4<<10) /* Box Block Right X/8 */ 27 | #define BBQ (5<<10) /* Box Block Quadrants */ 28 | #define BRL (6<<10) /* Box Braille (data is lower byte of U28XX) */ 29 | 30 | #define BBS (1<<14) /* Box Block Shades */ 31 | #define BDB (1<<15) /* Box Draw is Bold */ 32 | 33 | /* (BDL/BDA) Light/Double/Heavy x Left/Up/Right/Down/Horizontal/Vertical */ 34 | /* Heavy is light+double (literally drawing light+double align to form heavy) */ 35 | #define LL (1<<0) 36 | #define LU (1<<1) 37 | #define LR (1<<2) 38 | #define LD (1<<3) 39 | #define LH (LL+LR) 40 | #define LV (LU+LD) 41 | 42 | #define DL (1<<4) 43 | #define DU (1<<5) 44 | #define DR (1<<6) 45 | #define DD (1<<7) 46 | #define DH (DL+DR) 47 | #define DV (DU+DD) 48 | 49 | #define HL (LL+DL) 50 | #define HU (LU+DU) 51 | #define HR (LR+DR) 52 | #define HD (LD+DD) 53 | #define HH (HL+HR) 54 | #define HV (HU+HD) 55 | 56 | /* (BBQ) Quadrants Top/Bottom x Left/Right */ 57 | #define TL (1<<0) 58 | #define TR (1<<1) 59 | #define BL (1<<2) 60 | #define BR (1<<3) 61 | 62 | /* Data for U+2500 - U+259F except dashes/diagonals */ 63 | static const unsigned short boxdata[256] = { 64 | /* light lines */ 65 | [0x00] = BDL + LH, /* light horizontal */ 66 | [0x02] = BDL + LV, /* light vertical */ 67 | [0x0c] = BDL + LD + LR, /* light down and right */ 68 | [0x10] = BDL + LD + LL, /* light down and left */ 69 | [0x14] = BDL + LU + LR, /* light up and right */ 70 | [0x18] = BDL + LU + LL, /* light up and left */ 71 | [0x1c] = BDL + LV + LR, /* light vertical and right */ 72 | [0x24] = BDL + LV + LL, /* light vertical and left */ 73 | [0x2c] = BDL + LH + LD, /* light horizontal and down */ 74 | [0x34] = BDL + LH + LU, /* light horizontal and up */ 75 | [0x3c] = BDL + LV + LH, /* light vertical and horizontal */ 76 | [0x74] = BDL + LL, /* light left */ 77 | [0x75] = BDL + LU, /* light up */ 78 | [0x76] = BDL + LR, /* light right */ 79 | [0x77] = BDL + LD, /* light down */ 80 | 81 | /* heavy [+light] lines */ 82 | [0x01] = BDL + HH, 83 | [0x03] = BDL + HV, 84 | [0x0d] = BDL + HR + LD, 85 | [0x0e] = BDL + HD + LR, 86 | [0x0f] = BDL + HD + HR, 87 | [0x11] = BDL + HL + LD, 88 | [0x12] = BDL + HD + LL, 89 | [0x13] = BDL + HD + HL, 90 | [0x15] = BDL + HR + LU, 91 | [0x16] = BDL + HU + LR, 92 | [0x17] = BDL + HU + HR, 93 | [0x19] = BDL + HL + LU, 94 | [0x1a] = BDL + HU + LL, 95 | [0x1b] = BDL + HU + HL, 96 | [0x1d] = BDL + HR + LV, 97 | [0x1e] = BDL + HU + LD + LR, 98 | [0x1f] = BDL + HD + LR + LU, 99 | [0x20] = BDL + HV + LR, 100 | [0x21] = BDL + HU + HR + LD, 101 | [0x22] = BDL + HD + HR + LU, 102 | [0x23] = BDL + HV + HR, 103 | [0x25] = BDL + HL + LV, 104 | [0x26] = BDL + HU + LD + LL, 105 | [0x27] = BDL + HD + LU + LL, 106 | [0x28] = BDL + HV + LL, 107 | [0x29] = BDL + HU + HL + LD, 108 | [0x2a] = BDL + HD + HL + LU, 109 | [0x2b] = BDL + HV + HL, 110 | [0x2d] = BDL + HL + LD + LR, 111 | [0x2e] = BDL + HR + LL + LD, 112 | [0x2f] = BDL + HH + LD, 113 | [0x30] = BDL + HD + LH, 114 | [0x31] = BDL + HD + HL + LR, 115 | [0x32] = BDL + HR + HD + LL, 116 | [0x33] = BDL + HH + HD, 117 | [0x35] = BDL + HL + LU + LR, 118 | [0x36] = BDL + HR + LU + LL, 119 | [0x37] = BDL + HH + LU, 120 | [0x38] = BDL + HU + LH, 121 | [0x39] = BDL + HU + HL + LR, 122 | [0x3a] = BDL + HU + HR + LL, 123 | [0x3b] = BDL + HH + HU, 124 | [0x3d] = BDL + HL + LV + LR, 125 | [0x3e] = BDL + HR + LV + LL, 126 | [0x3f] = BDL + HH + LV, 127 | [0x40] = BDL + HU + LH + LD, 128 | [0x41] = BDL + HD + LH + LU, 129 | [0x42] = BDL + HV + LH, 130 | [0x43] = BDL + HU + HL + LD + LR, 131 | [0x44] = BDL + HU + HR + LD + LL, 132 | [0x45] = BDL + HD + HL + LU + LR, 133 | [0x46] = BDL + HD + HR + LU + LL, 134 | [0x47] = BDL + HH + HU + LD, 135 | [0x48] = BDL + HH + HD + LU, 136 | [0x49] = BDL + HV + HL + LR, 137 | [0x4a] = BDL + HV + HR + LL, 138 | [0x4b] = BDL + HV + HH, 139 | [0x78] = BDL + HL, 140 | [0x79] = BDL + HU, 141 | [0x7a] = BDL + HR, 142 | [0x7b] = BDL + HD, 143 | [0x7c] = BDL + HR + LL, 144 | [0x7d] = BDL + HD + LU, 145 | [0x7e] = BDL + HL + LR, 146 | [0x7f] = BDL + HU + LD, 147 | 148 | /* double [+light] lines */ 149 | [0x50] = BDL + DH, 150 | [0x51] = BDL + DV, 151 | [0x52] = BDL + DR + LD, 152 | [0x53] = BDL + DD + LR, 153 | [0x54] = BDL + DR + DD, 154 | [0x55] = BDL + DL + LD, 155 | [0x56] = BDL + DD + LL, 156 | [0x57] = BDL + DL + DD, 157 | [0x58] = BDL + DR + LU, 158 | [0x59] = BDL + DU + LR, 159 | [0x5a] = BDL + DU + DR, 160 | [0x5b] = BDL + DL + LU, 161 | [0x5c] = BDL + DU + LL, 162 | [0x5d] = BDL + DL + DU, 163 | [0x5e] = BDL + DR + LV, 164 | [0x5f] = BDL + DV + LR, 165 | [0x60] = BDL + DV + DR, 166 | [0x61] = BDL + DL + LV, 167 | [0x62] = BDL + DV + LL, 168 | [0x63] = BDL + DV + DL, 169 | [0x64] = BDL + DH + LD, 170 | [0x65] = BDL + DD + LH, 171 | [0x66] = BDL + DD + DH, 172 | [0x67] = BDL + DH + LU, 173 | [0x68] = BDL + DU + LH, 174 | [0x69] = BDL + DH + DU, 175 | [0x6a] = BDL + DH + LV, 176 | [0x6b] = BDL + DV + LH, 177 | [0x6c] = BDL + DH + DV, 178 | 179 | /* (light) arcs */ 180 | [0x6d] = BDA + LD + LR, 181 | [0x6e] = BDA + LD + LL, 182 | [0x6f] = BDA + LU + LL, 183 | [0x70] = BDA + LU + LR, 184 | 185 | /* Lower (Down) X/8 block (data is 8 - X) */ 186 | [0x81] = BBD + 7, [0x82] = BBD + 6, [0x83] = BBD + 5, [0x84] = BBD + 4, 187 | [0x85] = BBD + 3, [0x86] = BBD + 2, [0x87] = BBD + 1, [0x88] = BBD + 0, 188 | 189 | /* Left X/8 block (data is X) */ 190 | [0x89] = BBL + 7, [0x8a] = BBL + 6, [0x8b] = BBL + 5, [0x8c] = BBL + 4, 191 | [0x8d] = BBL + 3, [0x8e] = BBL + 2, [0x8f] = BBL + 1, 192 | 193 | /* upper 1/2 (4/8), 1/8 block (X), right 1/2, 1/8 block (8-X) */ 194 | [0x80] = BBU + 4, [0x94] = BBU + 1, 195 | [0x90] = BBR + 4, [0x95] = BBR + 7, 196 | 197 | /* Quadrants */ 198 | [0x96] = BBQ + BL, 199 | [0x97] = BBQ + BR, 200 | [0x98] = BBQ + TL, 201 | [0x99] = BBQ + TL + BL + BR, 202 | [0x9a] = BBQ + TL + BR, 203 | [0x9b] = BBQ + TL + TR + BL, 204 | [0x9c] = BBQ + TL + TR + BR, 205 | [0x9d] = BBQ + TR, 206 | [0x9e] = BBQ + BL + TR, 207 | [0x9f] = BBQ + BL + TR + BR, 208 | 209 | /* Shades, data is an alpha value in 25% units (1/4, 1/2, 3/4) */ 210 | [0x91] = BBS + 1, [0x92] = BBS + 2, [0x93] = BBS + 3, 211 | 212 | /* U+2504 - U+250B, U+254C - U+254F: unsupported (dashes) */ 213 | /* U+2571 - U+2573: unsupported (diagonals) */ 214 | }; 215 | -------------------------------------------------------------------------------- /config.def.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | 3 | /* 4 | * appearance 5 | * 6 | * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html 7 | */ 8 | static char *font = "M PLUS Code Latin 50:Semibold:size=14:antialias=true:autohint=true"; 9 | /* Spare fonts */ 10 | static char *font2[] = { 11 | "monospace:size=14", 12 | "Symbols NF:Semibold:size=14", 13 | }; 14 | static int borderpx = 12; 15 | 16 | /* 17 | * What program is execed by st depends of these precedence rules: 18 | * 1: program passed with -e 19 | * 2: scroll and/or utmp 20 | * 3: SHELL environment variable 21 | * 4: value of shell in /etc/passwd 22 | * 5: value of shell in config.h 23 | */ 24 | static char *shell = "/bin/sh"; 25 | char *utmp = NULL; 26 | /* scroll program: to enable use a string like "scroll" */ 27 | char *scroll = NULL; 28 | char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400"; 29 | 30 | /* identification sequence returned in DA and DECID */ 31 | char *vtiden = "\033[?6c"; 32 | 33 | /* Kerning / character bounding-box multipliers */ 34 | static float cwscale = 1.0; 35 | static float chscale = 1.0; 36 | 37 | /* 38 | * word delimiter string 39 | * 40 | * More advanced example: L" `'\"()[]{}" 41 | */ 42 | wchar_t *worddelimiters = L" "; 43 | 44 | /* selection timeouts (in milliseconds) */ 45 | static unsigned int doubleclicktimeout = 300; 46 | static unsigned int tripleclicktimeout = 600; 47 | 48 | /* alt screens */ 49 | int allowaltscreen = 1; 50 | 51 | /* allow certain non-interactive (insecure) window operations such as: 52 | setting the clipboard text */ 53 | int allowwindowops = 0; 54 | 55 | /* 56 | * draw latency range in ms - from new content/keypress/etc until drawing. 57 | * within this range, st draws when content stops arriving (idle). mostly it's 58 | * near minlatency, but it waits longer for slow updates to avoid partial draw. 59 | * low minlatency will tear/flicker more, as it can "detect" idle too early. 60 | */ 61 | static double minlatency = 8; 62 | static double maxlatency = 33; 63 | 64 | /* 65 | * blinking timeout (set to 0 to disable blinking) for the terminal blinking 66 | * attribute. 67 | */ 68 | static unsigned int blinktimeout = 800; 69 | 70 | /* 71 | * thickness of underline and bar cursors 72 | */ 73 | static unsigned int cursorthickness = 2; 74 | 75 | /* 76 | * 1: render most of the lines/blocks characters without using the font for 77 | * perfect alignment between cells (U2500 - U259F except dashes/diagonals). 78 | * Bold affects lines thickness if boxdraw_bold is not 0. Italic is ignored. 79 | * 0: disable (render all U25XX glyphs normally from the font). 80 | */ 81 | const int boxdraw = 1; 82 | const int boxdraw_bold = 0; 83 | 84 | /* braille (U28XX): 1: render as adjacent "pixels", 0: use font */ 85 | const int boxdraw_braille = 0; 86 | 87 | /* 88 | * bell volume. It must be a value between -100 and 100. Use 0 for disabling 89 | * it 90 | */ 91 | static int bellvolume = 0; 92 | 93 | /* default TERM value */ 94 | char *termname = "st-256color"; 95 | 96 | /* 97 | * spaces per tab 98 | * 99 | * When you are changing this value, don't forget to adapt the »it« value in 100 | * the st.info and appropriately install the st.info in the environment where 101 | * you use this st version. 102 | * 103 | * it#$tabspaces, 104 | * 105 | * Secondly make sure your kernel is not expanding tabs. When running `stty 106 | * -a` »tab0« should appear. You can tell the terminal to not expand tabs by 107 | * running following command: 108 | * 109 | * stty tabs 110 | */ 111 | unsigned int tabspaces = 8; 112 | 113 | /* Terminal colors (16 first used in escape sequence) */ 114 | static const char *colorname[] = { 115 | /* 8 normal colors */ 116 | [0] = "#373737", /* black */ 117 | [1] = "#ec5f67", /* red */ 118 | [2] = "#99c794", /* green */ 119 | [3] = "#fac863", /* yellow */ 120 | [4] = "#6699cc", /* blue */ 121 | [5] = "#c594c5", /* magenta */ 122 | [6] = "#62b2b3", /* cyan */ 123 | [7] = "#d8dee9", /* white */ 124 | 125 | /* 8 bright colors */ 126 | [8] = "#bbbbbb", /* black */ 127 | [9] = "#ec5f67", /* red */ 128 | [10] = "#99c794", /* green */ 129 | [11] = "#fac863", /* yellow */ 130 | [12] = "#6699cc", /* blue */ 131 | [13] = "#c594c5", /* magenta */ 132 | [14] = "#62b2b3", /* cyan */ 133 | [15] = "#d8dee9", /* white */ 134 | 135 | /* special colors */ 136 | [256] = "#1e1e1e", /* background */ 137 | [257] = "#f7f7f7", /* foreground */ 138 | }; 139 | 140 | 141 | /* 142 | * Default colors (colorname index) 143 | * foreground, background, cursor, reverse cursor 144 | */ 145 | unsigned int defaultfg = 257; 146 | unsigned int defaultbg = 256; 147 | unsigned int defaultcs = 257; 148 | static unsigned int defaultrcs = 257; 149 | 150 | /* 151 | * Colors used, when the specific fg == defaultfg. So in reverse mode this 152 | * will reverse too. Another logic would only make the simple feature too 153 | * complex. 154 | */ 155 | unsigned int defaultitalic = 7; 156 | unsigned int defaultunderline = 7; 157 | /* 158 | * Default shape of cursor 159 | * 2: Block ("█") 160 | * 4: Underline ("_") 161 | * 6: Bar ("|") 162 | * 7: Snowman ("☃") 163 | */ 164 | static unsigned int cursorshape = 2; 165 | 166 | /* 167 | * Default columns and rows numbers 168 | */ 169 | 170 | static unsigned int cols = 80; 171 | static unsigned int rows = 24; 172 | 173 | /* 174 | * Default colour and shape of the mouse cursor 175 | */ 176 | static unsigned int mouseshape = XC_xterm; 177 | static unsigned int mousefg = 7; 178 | static unsigned int mousebg = 0; 179 | 180 | /* 181 | * Color used to display font attributes when fontconfig selected a font which 182 | * doesn't match the ones requested. 183 | */ 184 | static unsigned int defaultattr = 11; 185 | 186 | /* 187 | * Force mouse select/shortcuts while mask is active (when MODE_MOUSE is set). 188 | * Note that if you want to use ShiftMask with selmasks, set this to an other 189 | * modifier, set to 0 to not use it. 190 | */ 191 | static uint forcemousemod = ShiftMask; 192 | 193 | /* 194 | * Internal mouse shortcuts. 195 | * Beware that overloading Button1 will disable the selection. 196 | */ 197 | static MouseShortcut mshortcuts[] = { 198 | /* mask button function argument release */ 199 | { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 }, 200 | { ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} }, 201 | { XK_ANY_MOD, Button4, ttysend, {.s = "\031"} }, 202 | { ShiftMask, Button5, ttysend, {.s = "\033[6;2~"} }, 203 | { XK_ANY_MOD, Button5, ttysend, {.s = "\005"} }, 204 | }; 205 | 206 | /* Internal keyboard shortcuts. */ 207 | #define MODKEY Mod1Mask 208 | #define TERMMOD (ControlMask|ShiftMask) 209 | 210 | static Shortcut shortcuts[] = { 211 | /* mask keysym function argument */ 212 | { XK_ANY_MOD, XK_Break, sendbreak, {.i = 0} }, 213 | { ControlMask, XK_Print, toggleprinter, {.i = 0} }, 214 | { ShiftMask, XK_Print, printscreen, {.i = 0} }, 215 | { XK_ANY_MOD, XK_Print, printsel, {.i = 0} }, 216 | { ControlMask, XK_equal, zoom, {.f = +1} }, 217 | { ControlMask, XK_minus, zoom, {.f = -1} }, 218 | { ControlMask, XK_0, zoomreset, {.f = 0} }, 219 | { TERMMOD, XK_C, clipcopy, {.i = 0} }, 220 | { TERMMOD, XK_V, clippaste, {.i = 0} }, 221 | { TERMMOD, XK_Y, selpaste, {.i = 0} }, 222 | { ShiftMask, XK_Insert, selpaste, {.i = 0} }, 223 | { TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, 224 | { ShiftMask, XK_Page_Up, kscrollup, {.i = -1} }, 225 | { ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} }, 226 | }; 227 | 228 | /* 229 | * Special keys (change & recompile st.info accordingly) 230 | * 231 | * Mask value: 232 | * * Use XK_ANY_MOD to match the key no matter modifiers state 233 | * * Use XK_NO_MOD to match the key alone (no modifiers) 234 | * appkey value: 235 | * * 0: no value 236 | * * > 0: keypad application mode enabled 237 | * * = 2: term.numlock = 1 238 | * * < 0: keypad application mode disabled 239 | * appcursor value: 240 | * * 0: no value 241 | * * > 0: cursor application mode enabled 242 | * * < 0: cursor application mode disabled 243 | * 244 | * Be careful with the order of the definitions because st searches in 245 | * this table sequentially, so any XK_ANY_MOD must be in the last 246 | * position for a key. 247 | */ 248 | 249 | /* 250 | * If you want keys other than the X11 function keys (0xFD00 - 0xFFFF) 251 | * to be mapped below, add them to this array. 252 | */ 253 | static KeySym mappedkeys[] = { -1 }; 254 | 255 | /* 256 | * State bits to ignore when matching key or button events. By default, 257 | * numlock (Mod2Mask) and keyboard layout (XK_SWITCH_MOD) are ignored. 258 | */ 259 | static uint ignoremod = Mod2Mask|XK_SWITCH_MOD; 260 | 261 | /* 262 | * This is the huge key array which defines all compatibility to the Linux 263 | * world. Please decide about changes wisely. 264 | */ 265 | static Key key[] = { 266 | /* keysym mask string appkey appcursor */ 267 | { XK_KP_Home, ShiftMask, "\033[2J", 0, -1}, 268 | { XK_KP_Home, ShiftMask, "\033[1;2H", 0, +1}, 269 | { XK_KP_Home, XK_ANY_MOD, "\033[H", 0, -1}, 270 | { XK_KP_Home, XK_ANY_MOD, "\033[1~", 0, +1}, 271 | { XK_KP_Up, XK_ANY_MOD, "\033Ox", +1, 0}, 272 | { XK_KP_Up, XK_ANY_MOD, "\033[A", 0, -1}, 273 | { XK_KP_Up, XK_ANY_MOD, "\033OA", 0, +1}, 274 | { XK_KP_Down, XK_ANY_MOD, "\033Or", +1, 0}, 275 | { XK_KP_Down, XK_ANY_MOD, "\033[B", 0, -1}, 276 | { XK_KP_Down, XK_ANY_MOD, "\033OB", 0, +1}, 277 | { XK_KP_Left, XK_ANY_MOD, "\033Ot", +1, 0}, 278 | { XK_KP_Left, XK_ANY_MOD, "\033[D", 0, -1}, 279 | { XK_KP_Left, XK_ANY_MOD, "\033OD", 0, +1}, 280 | { XK_KP_Right, XK_ANY_MOD, "\033Ov", +1, 0}, 281 | { XK_KP_Right, XK_ANY_MOD, "\033[C", 0, -1}, 282 | { XK_KP_Right, XK_ANY_MOD, "\033OC", 0, +1}, 283 | { XK_KP_Prior, ShiftMask, "\033[5;2~", 0, 0}, 284 | { XK_KP_Prior, XK_ANY_MOD, "\033[5~", 0, 0}, 285 | { XK_KP_Begin, XK_ANY_MOD, "\033[E", 0, 0}, 286 | { XK_KP_End, ControlMask, "\033[J", -1, 0}, 287 | { XK_KP_End, ControlMask, "\033[1;5F", +1, 0}, 288 | { XK_KP_End, ShiftMask, "\033[K", -1, 0}, 289 | { XK_KP_End, ShiftMask, "\033[1;2F", +1, 0}, 290 | { XK_KP_End, XK_ANY_MOD, "\033[4~", 0, 0}, 291 | { XK_KP_Next, ShiftMask, "\033[6;2~", 0, 0}, 292 | { XK_KP_Next, XK_ANY_MOD, "\033[6~", 0, 0}, 293 | { XK_KP_Insert, ShiftMask, "\033[2;2~", +1, 0}, 294 | { XK_KP_Insert, ShiftMask, "\033[4l", -1, 0}, 295 | { XK_KP_Insert, ControlMask, "\033[L", -1, 0}, 296 | { XK_KP_Insert, ControlMask, "\033[2;5~", +1, 0}, 297 | { XK_KP_Insert, XK_ANY_MOD, "\033[4h", -1, 0}, 298 | { XK_KP_Insert, XK_ANY_MOD, "\033[2~", +1, 0}, 299 | { XK_KP_Delete, ControlMask, "\033[M", -1, 0}, 300 | { XK_KP_Delete, ControlMask, "\033[3;5~", +1, 0}, 301 | { XK_KP_Delete, ShiftMask, "\033[2K", -1, 0}, 302 | { XK_KP_Delete, ShiftMask, "\033[3;2~", +1, 0}, 303 | { XK_KP_Delete, XK_ANY_MOD, "\033[P", -1, 0}, 304 | { XK_KP_Delete, XK_ANY_MOD, "\033[3~", +1, 0}, 305 | { XK_KP_Multiply, XK_ANY_MOD, "\033Oj", +2, 0}, 306 | { XK_KP_Add, XK_ANY_MOD, "\033Ok", +2, 0}, 307 | { XK_KP_Enter, XK_ANY_MOD, "\033OM", +2, 0}, 308 | { XK_KP_Enter, XK_ANY_MOD, "\r", -1, 0}, 309 | { XK_KP_Subtract, XK_ANY_MOD, "\033Om", +2, 0}, 310 | { XK_KP_Decimal, XK_ANY_MOD, "\033On", +2, 0}, 311 | { XK_KP_Divide, XK_ANY_MOD, "\033Oo", +2, 0}, 312 | { XK_KP_0, XK_ANY_MOD, "\033Op", +2, 0}, 313 | { XK_KP_1, XK_ANY_MOD, "\033Oq", +2, 0}, 314 | { XK_KP_2, XK_ANY_MOD, "\033Or", +2, 0}, 315 | { XK_KP_3, XK_ANY_MOD, "\033Os", +2, 0}, 316 | { XK_KP_4, XK_ANY_MOD, "\033Ot", +2, 0}, 317 | { XK_KP_5, XK_ANY_MOD, "\033Ou", +2, 0}, 318 | { XK_KP_6, XK_ANY_MOD, "\033Ov", +2, 0}, 319 | { XK_KP_7, XK_ANY_MOD, "\033Ow", +2, 0}, 320 | { XK_KP_8, XK_ANY_MOD, "\033Ox", +2, 0}, 321 | { XK_KP_9, XK_ANY_MOD, "\033Oy", +2, 0}, 322 | { XK_Up, ShiftMask, "\033[1;2A", 0, 0}, 323 | { XK_Up, Mod1Mask, "\033[1;3A", 0, 0}, 324 | { XK_Up, ShiftMask|Mod1Mask,"\033[1;4A", 0, 0}, 325 | { XK_Up, ControlMask, "\033[1;5A", 0, 0}, 326 | { XK_Up, ShiftMask|ControlMask,"\033[1;6A", 0, 0}, 327 | { XK_Up, ControlMask|Mod1Mask,"\033[1;7A", 0, 0}, 328 | { XK_Up,ShiftMask|ControlMask|Mod1Mask,"\033[1;8A", 0, 0}, 329 | { XK_Up, XK_ANY_MOD, "\033[A", 0, -1}, 330 | { XK_Up, XK_ANY_MOD, "\033OA", 0, +1}, 331 | { XK_Down, ShiftMask, "\033[1;2B", 0, 0}, 332 | { XK_Down, Mod1Mask, "\033[1;3B", 0, 0}, 333 | { XK_Down, ShiftMask|Mod1Mask,"\033[1;4B", 0, 0}, 334 | { XK_Down, ControlMask, "\033[1;5B", 0, 0}, 335 | { XK_Down, ShiftMask|ControlMask,"\033[1;6B", 0, 0}, 336 | { XK_Down, ControlMask|Mod1Mask,"\033[1;7B", 0, 0}, 337 | { XK_Down,ShiftMask|ControlMask|Mod1Mask,"\033[1;8B",0, 0}, 338 | { XK_Down, XK_ANY_MOD, "\033[B", 0, -1}, 339 | { XK_Down, XK_ANY_MOD, "\033OB", 0, +1}, 340 | { XK_Left, ShiftMask, "\033[1;2D", 0, 0}, 341 | { XK_Left, Mod1Mask, "\033[1;3D", 0, 0}, 342 | { XK_Left, ShiftMask|Mod1Mask,"\033[1;4D", 0, 0}, 343 | { XK_Left, ControlMask, "\033[1;5D", 0, 0}, 344 | { XK_Left, ShiftMask|ControlMask,"\033[1;6D", 0, 0}, 345 | { XK_Left, ControlMask|Mod1Mask,"\033[1;7D", 0, 0}, 346 | { XK_Left,ShiftMask|ControlMask|Mod1Mask,"\033[1;8D",0, 0}, 347 | { XK_Left, XK_ANY_MOD, "\033[D", 0, -1}, 348 | { XK_Left, XK_ANY_MOD, "\033OD", 0, +1}, 349 | { XK_Right, ShiftMask, "\033[1;2C", 0, 0}, 350 | { XK_Right, Mod1Mask, "\033[1;3C", 0, 0}, 351 | { XK_Right, ShiftMask|Mod1Mask,"\033[1;4C", 0, 0}, 352 | { XK_Right, ControlMask, "\033[1;5C", 0, 0}, 353 | { XK_Right, ShiftMask|ControlMask,"\033[1;6C", 0, 0}, 354 | { XK_Right, ControlMask|Mod1Mask,"\033[1;7C", 0, 0}, 355 | { XK_Right,ShiftMask|ControlMask|Mod1Mask,"\033[1;8C",0, 0}, 356 | { XK_Right, XK_ANY_MOD, "\033[C", 0, -1}, 357 | { XK_Right, XK_ANY_MOD, "\033OC", 0, +1}, 358 | { XK_ISO_Left_Tab, ShiftMask, "\033[Z", 0, 0}, 359 | { XK_Return, Mod1Mask, "\033\r", 0, 0}, 360 | { XK_Return, XK_ANY_MOD, "\r", 0, 0}, 361 | { XK_Insert, ShiftMask, "\033[4l", -1, 0}, 362 | { XK_Insert, ShiftMask, "\033[2;2~", +1, 0}, 363 | { XK_Insert, ControlMask, "\033[L", -1, 0}, 364 | { XK_Insert, ControlMask, "\033[2;5~", +1, 0}, 365 | { XK_Insert, XK_ANY_MOD, "\033[4h", -1, 0}, 366 | { XK_Insert, XK_ANY_MOD, "\033[2~", +1, 0}, 367 | { XK_Delete, ControlMask, "\033[M", -1, 0}, 368 | { XK_Delete, ControlMask, "\033[3;5~", +1, 0}, 369 | { XK_Delete, ShiftMask, "\033[2K", -1, 0}, 370 | { XK_Delete, ShiftMask, "\033[3;2~", +1, 0}, 371 | { XK_Delete, XK_ANY_MOD, "\033[P", -1, 0}, 372 | { XK_Delete, XK_ANY_MOD, "\033[3~", +1, 0}, 373 | { XK_BackSpace, XK_NO_MOD, "\177", 0, 0}, 374 | { XK_BackSpace, Mod1Mask, "\033\177", 0, 0}, 375 | { XK_Home, ShiftMask, "\033[2J", 0, -1}, 376 | { XK_Home, ShiftMask, "\033[1;2H", 0, +1}, 377 | { XK_Home, XK_ANY_MOD, "\033[H", 0, -1}, 378 | { XK_Home, XK_ANY_MOD, "\033[1~", 0, +1}, 379 | { XK_End, ControlMask, "\033[J", -1, 0}, 380 | { XK_End, ControlMask, "\033[1;5F", +1, 0}, 381 | { XK_End, ShiftMask, "\033[K", -1, 0}, 382 | { XK_End, ShiftMask, "\033[1;2F", +1, 0}, 383 | { XK_End, XK_ANY_MOD, "\033[4~", 0, 0}, 384 | { XK_Prior, ControlMask, "\033[5;5~", 0, 0}, 385 | { XK_Prior, ShiftMask, "\033[5;2~", 0, 0}, 386 | { XK_Prior, XK_ANY_MOD, "\033[5~", 0, 0}, 387 | { XK_Next, ControlMask, "\033[6;5~", 0, 0}, 388 | { XK_Next, ShiftMask, "\033[6;2~", 0, 0}, 389 | { XK_Next, XK_ANY_MOD, "\033[6~", 0, 0}, 390 | { XK_F1, XK_NO_MOD, "\033OP" , 0, 0}, 391 | { XK_F1, /* F13 */ ShiftMask, "\033[1;2P", 0, 0}, 392 | { XK_F1, /* F25 */ ControlMask, "\033[1;5P", 0, 0}, 393 | { XK_F1, /* F37 */ Mod4Mask, "\033[1;6P", 0, 0}, 394 | { XK_F1, /* F49 */ Mod1Mask, "\033[1;3P", 0, 0}, 395 | { XK_F1, /* F61 */ Mod3Mask, "\033[1;4P", 0, 0}, 396 | { XK_F2, XK_NO_MOD, "\033OQ" , 0, 0}, 397 | { XK_F2, /* F14 */ ShiftMask, "\033[1;2Q", 0, 0}, 398 | { XK_F2, /* F26 */ ControlMask, "\033[1;5Q", 0, 0}, 399 | { XK_F2, /* F38 */ Mod4Mask, "\033[1;6Q", 0, 0}, 400 | { XK_F2, /* F50 */ Mod1Mask, "\033[1;3Q", 0, 0}, 401 | { XK_F2, /* F62 */ Mod3Mask, "\033[1;4Q", 0, 0}, 402 | { XK_F3, XK_NO_MOD, "\033OR" , 0, 0}, 403 | { XK_F3, /* F15 */ ShiftMask, "\033[1;2R", 0, 0}, 404 | { XK_F3, /* F27 */ ControlMask, "\033[1;5R", 0, 0}, 405 | { XK_F3, /* F39 */ Mod4Mask, "\033[1;6R", 0, 0}, 406 | { XK_F3, /* F51 */ Mod1Mask, "\033[1;3R", 0, 0}, 407 | { XK_F3, /* F63 */ Mod3Mask, "\033[1;4R", 0, 0}, 408 | { XK_F4, XK_NO_MOD, "\033OS" , 0, 0}, 409 | { XK_F4, /* F16 */ ShiftMask, "\033[1;2S", 0, 0}, 410 | { XK_F4, /* F28 */ ControlMask, "\033[1;5S", 0, 0}, 411 | { XK_F4, /* F40 */ Mod4Mask, "\033[1;6S", 0, 0}, 412 | { XK_F4, /* F52 */ Mod1Mask, "\033[1;3S", 0, 0}, 413 | { XK_F5, XK_NO_MOD, "\033[15~", 0, 0}, 414 | { XK_F5, /* F17 */ ShiftMask, "\033[15;2~", 0, 0}, 415 | { XK_F5, /* F29 */ ControlMask, "\033[15;5~", 0, 0}, 416 | { XK_F5, /* F41 */ Mod4Mask, "\033[15;6~", 0, 0}, 417 | { XK_F5, /* F53 */ Mod1Mask, "\033[15;3~", 0, 0}, 418 | { XK_F6, XK_NO_MOD, "\033[17~", 0, 0}, 419 | { XK_F6, /* F18 */ ShiftMask, "\033[17;2~", 0, 0}, 420 | { XK_F6, /* F30 */ ControlMask, "\033[17;5~", 0, 0}, 421 | { XK_F6, /* F42 */ Mod4Mask, "\033[17;6~", 0, 0}, 422 | { XK_F6, /* F54 */ Mod1Mask, "\033[17;3~", 0, 0}, 423 | { XK_F7, XK_NO_MOD, "\033[18~", 0, 0}, 424 | { XK_F7, /* F19 */ ShiftMask, "\033[18;2~", 0, 0}, 425 | { XK_F7, /* F31 */ ControlMask, "\033[18;5~", 0, 0}, 426 | { XK_F7, /* F43 */ Mod4Mask, "\033[18;6~", 0, 0}, 427 | { XK_F7, /* F55 */ Mod1Mask, "\033[18;3~", 0, 0}, 428 | { XK_F8, XK_NO_MOD, "\033[19~", 0, 0}, 429 | { XK_F8, /* F20 */ ShiftMask, "\033[19;2~", 0, 0}, 430 | { XK_F8, /* F32 */ ControlMask, "\033[19;5~", 0, 0}, 431 | { XK_F8, /* F44 */ Mod4Mask, "\033[19;6~", 0, 0}, 432 | { XK_F8, /* F56 */ Mod1Mask, "\033[19;3~", 0, 0}, 433 | { XK_F9, XK_NO_MOD, "\033[20~", 0, 0}, 434 | { XK_F9, /* F21 */ ShiftMask, "\033[20;2~", 0, 0}, 435 | { XK_F9, /* F33 */ ControlMask, "\033[20;5~", 0, 0}, 436 | { XK_F9, /* F45 */ Mod4Mask, "\033[20;6~", 0, 0}, 437 | { XK_F9, /* F57 */ Mod1Mask, "\033[20;3~", 0, 0}, 438 | { XK_F10, XK_NO_MOD, "\033[21~", 0, 0}, 439 | { XK_F10, /* F22 */ ShiftMask, "\033[21;2~", 0, 0}, 440 | { XK_F10, /* F34 */ ControlMask, "\033[21;5~", 0, 0}, 441 | { XK_F10, /* F46 */ Mod4Mask, "\033[21;6~", 0, 0}, 442 | { XK_F10, /* F58 */ Mod1Mask, "\033[21;3~", 0, 0}, 443 | { XK_F11, XK_NO_MOD, "\033[23~", 0, 0}, 444 | { XK_F11, /* F23 */ ShiftMask, "\033[23;2~", 0, 0}, 445 | { XK_F11, /* F35 */ ControlMask, "\033[23;5~", 0, 0}, 446 | { XK_F11, /* F47 */ Mod4Mask, "\033[23;6~", 0, 0}, 447 | { XK_F11, /* F59 */ Mod1Mask, "\033[23;3~", 0, 0}, 448 | { XK_F12, XK_NO_MOD, "\033[24~", 0, 0}, 449 | { XK_F12, /* F24 */ ShiftMask, "\033[24;2~", 0, 0}, 450 | { XK_F12, /* F36 */ ControlMask, "\033[24;5~", 0, 0}, 451 | { XK_F12, /* F48 */ Mod4Mask, "\033[24;6~", 0, 0}, 452 | { XK_F12, /* F60 */ Mod1Mask, "\033[24;3~", 0, 0}, 453 | { XK_F13, XK_NO_MOD, "\033[1;2P", 0, 0}, 454 | { XK_F14, XK_NO_MOD, "\033[1;2Q", 0, 0}, 455 | { XK_F15, XK_NO_MOD, "\033[1;2R", 0, 0}, 456 | { XK_F16, XK_NO_MOD, "\033[1;2S", 0, 0}, 457 | { XK_F17, XK_NO_MOD, "\033[15;2~", 0, 0}, 458 | { XK_F18, XK_NO_MOD, "\033[17;2~", 0, 0}, 459 | { XK_F19, XK_NO_MOD, "\033[18;2~", 0, 0}, 460 | { XK_F20, XK_NO_MOD, "\033[19;2~", 0, 0}, 461 | { XK_F21, XK_NO_MOD, "\033[20;2~", 0, 0}, 462 | { XK_F22, XK_NO_MOD, "\033[21;2~", 0, 0}, 463 | { XK_F23, XK_NO_MOD, "\033[23;2~", 0, 0}, 464 | { XK_F24, XK_NO_MOD, "\033[24;2~", 0, 0}, 465 | { XK_F25, XK_NO_MOD, "\033[1;5P", 0, 0}, 466 | { XK_F26, XK_NO_MOD, "\033[1;5Q", 0, 0}, 467 | { XK_F27, XK_NO_MOD, "\033[1;5R", 0, 0}, 468 | { XK_F28, XK_NO_MOD, "\033[1;5S", 0, 0}, 469 | { XK_F29, XK_NO_MOD, "\033[15;5~", 0, 0}, 470 | { XK_F30, XK_NO_MOD, "\033[17;5~", 0, 0}, 471 | { XK_F31, XK_NO_MOD, "\033[18;5~", 0, 0}, 472 | { XK_F32, XK_NO_MOD, "\033[19;5~", 0, 0}, 473 | { XK_F33, XK_NO_MOD, "\033[20;5~", 0, 0}, 474 | { XK_F34, XK_NO_MOD, "\033[21;5~", 0, 0}, 475 | { XK_F35, XK_NO_MOD, "\033[23;5~", 0, 0}, 476 | }; 477 | 478 | /* 479 | * Selection types' masks. 480 | * Use the same masks as usual. 481 | * Button1Mask is always unset, to make masks match between ButtonPress. 482 | * ButtonRelease and MotionNotify. 483 | * If no match is found, regular selection is used. 484 | */ 485 | static uint selmasks[] = { 486 | [SEL_RECTANGULAR] = Mod1Mask, 487 | }; 488 | 489 | /* 490 | * Printable characters in ASCII, used to estimate the advance width 491 | * of single wide characters. 492 | */ 493 | static char ascii_printable[] = 494 | " !\"#$%&'()*+,-./0123456789:;<=>?" 495 | "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" 496 | "`abcdefghijklmnopqrstuvwxyz{|}~"; 497 | -------------------------------------------------------------------------------- /config.def.h.orig: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | 3 | /* 4 | * appearance 5 | * 6 | * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html 7 | */ 8 | static char *font = "M PLUS Code Latin 50:Semibold:size=14:antialias=true:autohint=true"; 9 | /* Spare fonts */ 10 | static char *font2[] = { 11 | "Symbols NF:Semibold:size=14", 12 | }; 13 | static int borderpx = 12; 14 | 15 | /* 16 | * What program is execed by st depends of these precedence rules: 17 | * 1: program passed with -e 18 | * 2: scroll and/or utmp 19 | * 3: SHELL environment variable 20 | * 4: value of shell in /etc/passwd 21 | * 5: value of shell in config.h 22 | */ 23 | static char *shell = "/bin/sh"; 24 | char *utmp = NULL; 25 | /* scroll program: to enable use a string like "scroll" */ 26 | char *scroll = NULL; 27 | char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400"; 28 | 29 | /* identification sequence returned in DA and DECID */ 30 | char *vtiden = "\033[?6c"; 31 | 32 | /* Kerning / character bounding-box multipliers */ 33 | static float cwscale = 1.0; 34 | static float chscale = 1.0; 35 | 36 | /* 37 | * word delimiter string 38 | * 39 | * More advanced example: L" `'\"()[]{}" 40 | */ 41 | wchar_t *worddelimiters = L" "; 42 | 43 | /* selection timeouts (in milliseconds) */ 44 | static unsigned int doubleclicktimeout = 300; 45 | static unsigned int tripleclicktimeout = 600; 46 | 47 | /* alt screens */ 48 | int allowaltscreen = 1; 49 | 50 | /* allow certain non-interactive (insecure) window operations such as: 51 | setting the clipboard text */ 52 | int allowwindowops = 0; 53 | 54 | /* 55 | * draw latency range in ms - from new content/keypress/etc until drawing. 56 | * within this range, st draws when content stops arriving (idle). mostly it's 57 | * near minlatency, but it waits longer for slow updates to avoid partial draw. 58 | * low minlatency will tear/flicker more, as it can "detect" idle too early. 59 | */ 60 | static double minlatency = 8; 61 | static double maxlatency = 33; 62 | 63 | /* 64 | * blinking timeout (set to 0 to disable blinking) for the terminal blinking 65 | * attribute. 66 | */ 67 | static unsigned int blinktimeout = 800; 68 | 69 | /* 70 | * thickness of underline and bar cursors 71 | */ 72 | static unsigned int cursorthickness = 2; 73 | 74 | /* 75 | * 1: render most of the lines/blocks characters without using the font for 76 | * perfect alignment between cells (U2500 - U259F except dashes/diagonals). 77 | * Bold affects lines thickness if boxdraw_bold is not 0. Italic is ignored. 78 | * 0: disable (render all U25XX glyphs normally from the font). 79 | */ 80 | const int boxdraw = 0; 81 | const int boxdraw_bold = 0; 82 | 83 | /* braille (U28XX): 1: render as adjacent "pixels", 0: use font */ 84 | const int boxdraw_braille = 0; 85 | 86 | /* 87 | * bell volume. It must be a value between -100 and 100. Use 0 for disabling 88 | * it 89 | */ 90 | static int bellvolume = 0; 91 | 92 | /* default TERM value */ 93 | char *termname = "st-256color"; 94 | 95 | /* 96 | * spaces per tab 97 | * 98 | * When you are changing this value, don't forget to adapt the »it« value in 99 | * the st.info and appropriately install the st.info in the environment where 100 | * you use this st version. 101 | * 102 | * it#$tabspaces, 103 | * 104 | * Secondly make sure your kernel is not expanding tabs. When running `stty 105 | * -a` »tab0« should appear. You can tell the terminal to not expand tabs by 106 | * running following command: 107 | * 108 | * stty tabs 109 | */ 110 | unsigned int tabspaces = 8; 111 | 112 | /* Terminal colors (16 first used in escape sequence) */ 113 | static const char *colorname[] = { 114 | /* 8 normal colors */ 115 | "black", 116 | "red3", 117 | "green3", 118 | "yellow3", 119 | "blue2", 120 | "magenta3", 121 | "cyan3", 122 | "gray90", 123 | 124 | /* 8 bright colors */ 125 | "gray50", 126 | "red", 127 | "green", 128 | "yellow", 129 | "#5c5cff", 130 | "magenta", 131 | "cyan", 132 | "white", 133 | 134 | [255] = 0, 135 | 136 | /* more colors can be added after 255 to use with DefaultXX */ 137 | "#cccccc", 138 | "#555555", 139 | "gray90", /* default foreground colour */ 140 | "black", /* default background colour */ 141 | }; 142 | 143 | 144 | /* 145 | * Default colors (colorname index) 146 | * foreground, background, cursor, reverse cursor 147 | */ 148 | unsigned int defaultfg = 258; 149 | unsigned int defaultbg = 259; 150 | unsigned int defaultcs = 256; 151 | static unsigned int defaultrcs = 257; 152 | 153 | /* 154 | * Default shape of cursor 155 | * 2: Block ("█") 156 | * 4: Underline ("_") 157 | * 6: Bar ("|") 158 | * 7: Snowman ("☃") 159 | */ 160 | static unsigned int cursorshape = 2; 161 | 162 | /* 163 | * Default columns and rows numbers 164 | */ 165 | 166 | static unsigned int cols = 80; 167 | static unsigned int rows = 24; 168 | 169 | /* 170 | * Default colour and shape of the mouse cursor 171 | */ 172 | static unsigned int mouseshape = XC_xterm; 173 | static unsigned int mousefg = 7; 174 | static unsigned int mousebg = 0; 175 | 176 | /* 177 | * Color used to display font attributes when fontconfig selected a font which 178 | * doesn't match the ones requested. 179 | */ 180 | static unsigned int defaultattr = 11; 181 | 182 | /* 183 | * Force mouse select/shortcuts while mask is active (when MODE_MOUSE is set). 184 | * Note that if you want to use ShiftMask with selmasks, set this to an other 185 | * modifier, set to 0 to not use it. 186 | */ 187 | static uint forcemousemod = ShiftMask; 188 | 189 | /* 190 | * Internal mouse shortcuts. 191 | * Beware that overloading Button1 will disable the selection. 192 | */ 193 | static MouseShortcut mshortcuts[] = { 194 | /* mask button function argument release */ 195 | { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 }, 196 | { ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} }, 197 | { XK_ANY_MOD, Button4, ttysend, {.s = "\031"} }, 198 | { ShiftMask, Button5, ttysend, {.s = "\033[6;2~"} }, 199 | { XK_ANY_MOD, Button5, ttysend, {.s = "\005"} }, 200 | }; 201 | 202 | /* Internal keyboard shortcuts. */ 203 | #define MODKEY Mod1Mask 204 | #define TERMMOD (ControlMask|ShiftMask) 205 | 206 | static Shortcut shortcuts[] = { 207 | /* mask keysym function argument */ 208 | { XK_ANY_MOD, XK_Break, sendbreak, {.i = 0} }, 209 | { ControlMask, XK_Print, toggleprinter, {.i = 0} }, 210 | { ShiftMask, XK_Print, printscreen, {.i = 0} }, 211 | { XK_ANY_MOD, XK_Print, printsel, {.i = 0} }, 212 | { TERMMOD, XK_Prior, zoom, {.f = +1} }, 213 | { TERMMOD, XK_Next, zoom, {.f = -1} }, 214 | { TERMMOD, XK_Home, zoomreset, {.f = 0} }, 215 | { TERMMOD, XK_C, clipcopy, {.i = 0} }, 216 | { TERMMOD, XK_V, clippaste, {.i = 0} }, 217 | { TERMMOD, XK_Y, selpaste, {.i = 0} }, 218 | { ShiftMask, XK_Insert, selpaste, {.i = 0} }, 219 | { TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, 220 | }; 221 | 222 | /* 223 | * Special keys (change & recompile st.info accordingly) 224 | * 225 | * Mask value: 226 | * * Use XK_ANY_MOD to match the key no matter modifiers state 227 | * * Use XK_NO_MOD to match the key alone (no modifiers) 228 | * appkey value: 229 | * * 0: no value 230 | * * > 0: keypad application mode enabled 231 | * * = 2: term.numlock = 1 232 | * * < 0: keypad application mode disabled 233 | * appcursor value: 234 | * * 0: no value 235 | * * > 0: cursor application mode enabled 236 | * * < 0: cursor application mode disabled 237 | * 238 | * Be careful with the order of the definitions because st searches in 239 | * this table sequentially, so any XK_ANY_MOD must be in the last 240 | * position for a key. 241 | */ 242 | 243 | /* 244 | * If you want keys other than the X11 function keys (0xFD00 - 0xFFFF) 245 | * to be mapped below, add them to this array. 246 | */ 247 | static KeySym mappedkeys[] = { -1 }; 248 | 249 | /* 250 | * State bits to ignore when matching key or button events. By default, 251 | * numlock (Mod2Mask) and keyboard layout (XK_SWITCH_MOD) are ignored. 252 | */ 253 | static uint ignoremod = Mod2Mask|XK_SWITCH_MOD; 254 | 255 | /* 256 | * This is the huge key array which defines all compatibility to the Linux 257 | * world. Please decide about changes wisely. 258 | */ 259 | static Key key[] = { 260 | /* keysym mask string appkey appcursor */ 261 | { XK_KP_Home, ShiftMask, "\033[2J", 0, -1}, 262 | { XK_KP_Home, ShiftMask, "\033[1;2H", 0, +1}, 263 | { XK_KP_Home, XK_ANY_MOD, "\033[H", 0, -1}, 264 | { XK_KP_Home, XK_ANY_MOD, "\033[1~", 0, +1}, 265 | { XK_KP_Up, XK_ANY_MOD, "\033Ox", +1, 0}, 266 | { XK_KP_Up, XK_ANY_MOD, "\033[A", 0, -1}, 267 | { XK_KP_Up, XK_ANY_MOD, "\033OA", 0, +1}, 268 | { XK_KP_Down, XK_ANY_MOD, "\033Or", +1, 0}, 269 | { XK_KP_Down, XK_ANY_MOD, "\033[B", 0, -1}, 270 | { XK_KP_Down, XK_ANY_MOD, "\033OB", 0, +1}, 271 | { XK_KP_Left, XK_ANY_MOD, "\033Ot", +1, 0}, 272 | { XK_KP_Left, XK_ANY_MOD, "\033[D", 0, -1}, 273 | { XK_KP_Left, XK_ANY_MOD, "\033OD", 0, +1}, 274 | { XK_KP_Right, XK_ANY_MOD, "\033Ov", +1, 0}, 275 | { XK_KP_Right, XK_ANY_MOD, "\033[C", 0, -1}, 276 | { XK_KP_Right, XK_ANY_MOD, "\033OC", 0, +1}, 277 | { XK_KP_Prior, ShiftMask, "\033[5;2~", 0, 0}, 278 | { XK_KP_Prior, XK_ANY_MOD, "\033[5~", 0, 0}, 279 | { XK_KP_Begin, XK_ANY_MOD, "\033[E", 0, 0}, 280 | { XK_KP_End, ControlMask, "\033[J", -1, 0}, 281 | { XK_KP_End, ControlMask, "\033[1;5F", +1, 0}, 282 | { XK_KP_End, ShiftMask, "\033[K", -1, 0}, 283 | { XK_KP_End, ShiftMask, "\033[1;2F", +1, 0}, 284 | { XK_KP_End, XK_ANY_MOD, "\033[4~", 0, 0}, 285 | { XK_KP_Next, ShiftMask, "\033[6;2~", 0, 0}, 286 | { XK_KP_Next, XK_ANY_MOD, "\033[6~", 0, 0}, 287 | { XK_KP_Insert, ShiftMask, "\033[2;2~", +1, 0}, 288 | { XK_KP_Insert, ShiftMask, "\033[4l", -1, 0}, 289 | { XK_KP_Insert, ControlMask, "\033[L", -1, 0}, 290 | { XK_KP_Insert, ControlMask, "\033[2;5~", +1, 0}, 291 | { XK_KP_Insert, XK_ANY_MOD, "\033[4h", -1, 0}, 292 | { XK_KP_Insert, XK_ANY_MOD, "\033[2~", +1, 0}, 293 | { XK_KP_Delete, ControlMask, "\033[M", -1, 0}, 294 | { XK_KP_Delete, ControlMask, "\033[3;5~", +1, 0}, 295 | { XK_KP_Delete, ShiftMask, "\033[2K", -1, 0}, 296 | { XK_KP_Delete, ShiftMask, "\033[3;2~", +1, 0}, 297 | { XK_KP_Delete, XK_ANY_MOD, "\033[P", -1, 0}, 298 | { XK_KP_Delete, XK_ANY_MOD, "\033[3~", +1, 0}, 299 | { XK_KP_Multiply, XK_ANY_MOD, "\033Oj", +2, 0}, 300 | { XK_KP_Add, XK_ANY_MOD, "\033Ok", +2, 0}, 301 | { XK_KP_Enter, XK_ANY_MOD, "\033OM", +2, 0}, 302 | { XK_KP_Enter, XK_ANY_MOD, "\r", -1, 0}, 303 | { XK_KP_Subtract, XK_ANY_MOD, "\033Om", +2, 0}, 304 | { XK_KP_Decimal, XK_ANY_MOD, "\033On", +2, 0}, 305 | { XK_KP_Divide, XK_ANY_MOD, "\033Oo", +2, 0}, 306 | { XK_KP_0, XK_ANY_MOD, "\033Op", +2, 0}, 307 | { XK_KP_1, XK_ANY_MOD, "\033Oq", +2, 0}, 308 | { XK_KP_2, XK_ANY_MOD, "\033Or", +2, 0}, 309 | { XK_KP_3, XK_ANY_MOD, "\033Os", +2, 0}, 310 | { XK_KP_4, XK_ANY_MOD, "\033Ot", +2, 0}, 311 | { XK_KP_5, XK_ANY_MOD, "\033Ou", +2, 0}, 312 | { XK_KP_6, XK_ANY_MOD, "\033Ov", +2, 0}, 313 | { XK_KP_7, XK_ANY_MOD, "\033Ow", +2, 0}, 314 | { XK_KP_8, XK_ANY_MOD, "\033Ox", +2, 0}, 315 | { XK_KP_9, XK_ANY_MOD, "\033Oy", +2, 0}, 316 | { XK_Up, ShiftMask, "\033[1;2A", 0, 0}, 317 | { XK_Up, Mod1Mask, "\033[1;3A", 0, 0}, 318 | { XK_Up, ShiftMask|Mod1Mask,"\033[1;4A", 0, 0}, 319 | { XK_Up, ControlMask, "\033[1;5A", 0, 0}, 320 | { XK_Up, ShiftMask|ControlMask,"\033[1;6A", 0, 0}, 321 | { XK_Up, ControlMask|Mod1Mask,"\033[1;7A", 0, 0}, 322 | { XK_Up,ShiftMask|ControlMask|Mod1Mask,"\033[1;8A", 0, 0}, 323 | { XK_Up, XK_ANY_MOD, "\033[A", 0, -1}, 324 | { XK_Up, XK_ANY_MOD, "\033OA", 0, +1}, 325 | { XK_Down, ShiftMask, "\033[1;2B", 0, 0}, 326 | { XK_Down, Mod1Mask, "\033[1;3B", 0, 0}, 327 | { XK_Down, ShiftMask|Mod1Mask,"\033[1;4B", 0, 0}, 328 | { XK_Down, ControlMask, "\033[1;5B", 0, 0}, 329 | { XK_Down, ShiftMask|ControlMask,"\033[1;6B", 0, 0}, 330 | { XK_Down, ControlMask|Mod1Mask,"\033[1;7B", 0, 0}, 331 | { XK_Down,ShiftMask|ControlMask|Mod1Mask,"\033[1;8B",0, 0}, 332 | { XK_Down, XK_ANY_MOD, "\033[B", 0, -1}, 333 | { XK_Down, XK_ANY_MOD, "\033OB", 0, +1}, 334 | { XK_Left, ShiftMask, "\033[1;2D", 0, 0}, 335 | { XK_Left, Mod1Mask, "\033[1;3D", 0, 0}, 336 | { XK_Left, ShiftMask|Mod1Mask,"\033[1;4D", 0, 0}, 337 | { XK_Left, ControlMask, "\033[1;5D", 0, 0}, 338 | { XK_Left, ShiftMask|ControlMask,"\033[1;6D", 0, 0}, 339 | { XK_Left, ControlMask|Mod1Mask,"\033[1;7D", 0, 0}, 340 | { XK_Left,ShiftMask|ControlMask|Mod1Mask,"\033[1;8D",0, 0}, 341 | { XK_Left, XK_ANY_MOD, "\033[D", 0, -1}, 342 | { XK_Left, XK_ANY_MOD, "\033OD", 0, +1}, 343 | { XK_Right, ShiftMask, "\033[1;2C", 0, 0}, 344 | { XK_Right, Mod1Mask, "\033[1;3C", 0, 0}, 345 | { XK_Right, ShiftMask|Mod1Mask,"\033[1;4C", 0, 0}, 346 | { XK_Right, ControlMask, "\033[1;5C", 0, 0}, 347 | { XK_Right, ShiftMask|ControlMask,"\033[1;6C", 0, 0}, 348 | { XK_Right, ControlMask|Mod1Mask,"\033[1;7C", 0, 0}, 349 | { XK_Right,ShiftMask|ControlMask|Mod1Mask,"\033[1;8C",0, 0}, 350 | { XK_Right, XK_ANY_MOD, "\033[C", 0, -1}, 351 | { XK_Right, XK_ANY_MOD, "\033OC", 0, +1}, 352 | { XK_ISO_Left_Tab, ShiftMask, "\033[Z", 0, 0}, 353 | { XK_Return, Mod1Mask, "\033\r", 0, 0}, 354 | { XK_Return, XK_ANY_MOD, "\r", 0, 0}, 355 | { XK_Insert, ShiftMask, "\033[4l", -1, 0}, 356 | { XK_Insert, ShiftMask, "\033[2;2~", +1, 0}, 357 | { XK_Insert, ControlMask, "\033[L", -1, 0}, 358 | { XK_Insert, ControlMask, "\033[2;5~", +1, 0}, 359 | { XK_Insert, XK_ANY_MOD, "\033[4h", -1, 0}, 360 | { XK_Insert, XK_ANY_MOD, "\033[2~", +1, 0}, 361 | { XK_Delete, ControlMask, "\033[M", -1, 0}, 362 | { XK_Delete, ControlMask, "\033[3;5~", +1, 0}, 363 | { XK_Delete, ShiftMask, "\033[2K", -1, 0}, 364 | { XK_Delete, ShiftMask, "\033[3;2~", +1, 0}, 365 | { XK_Delete, XK_ANY_MOD, "\033[P", -1, 0}, 366 | { XK_Delete, XK_ANY_MOD, "\033[3~", +1, 0}, 367 | { XK_BackSpace, XK_NO_MOD, "\177", 0, 0}, 368 | { XK_BackSpace, Mod1Mask, "\033\177", 0, 0}, 369 | { XK_Home, ShiftMask, "\033[2J", 0, -1}, 370 | { XK_Home, ShiftMask, "\033[1;2H", 0, +1}, 371 | { XK_Home, XK_ANY_MOD, "\033[H", 0, -1}, 372 | { XK_Home, XK_ANY_MOD, "\033[1~", 0, +1}, 373 | { XK_End, ControlMask, "\033[J", -1, 0}, 374 | { XK_End, ControlMask, "\033[1;5F", +1, 0}, 375 | { XK_End, ShiftMask, "\033[K", -1, 0}, 376 | { XK_End, ShiftMask, "\033[1;2F", +1, 0}, 377 | { XK_End, XK_ANY_MOD, "\033[4~", 0, 0}, 378 | { XK_Prior, ControlMask, "\033[5;5~", 0, 0}, 379 | { XK_Prior, ShiftMask, "\033[5;2~", 0, 0}, 380 | { XK_Prior, XK_ANY_MOD, "\033[5~", 0, 0}, 381 | { XK_Next, ControlMask, "\033[6;5~", 0, 0}, 382 | { XK_Next, ShiftMask, "\033[6;2~", 0, 0}, 383 | { XK_Next, XK_ANY_MOD, "\033[6~", 0, 0}, 384 | { XK_F1, XK_NO_MOD, "\033OP" , 0, 0}, 385 | { XK_F1, /* F13 */ ShiftMask, "\033[1;2P", 0, 0}, 386 | { XK_F1, /* F25 */ ControlMask, "\033[1;5P", 0, 0}, 387 | { XK_F1, /* F37 */ Mod4Mask, "\033[1;6P", 0, 0}, 388 | { XK_F1, /* F49 */ Mod1Mask, "\033[1;3P", 0, 0}, 389 | { XK_F1, /* F61 */ Mod3Mask, "\033[1;4P", 0, 0}, 390 | { XK_F2, XK_NO_MOD, "\033OQ" , 0, 0}, 391 | { XK_F2, /* F14 */ ShiftMask, "\033[1;2Q", 0, 0}, 392 | { XK_F2, /* F26 */ ControlMask, "\033[1;5Q", 0, 0}, 393 | { XK_F2, /* F38 */ Mod4Mask, "\033[1;6Q", 0, 0}, 394 | { XK_F2, /* F50 */ Mod1Mask, "\033[1;3Q", 0, 0}, 395 | { XK_F2, /* F62 */ Mod3Mask, "\033[1;4Q", 0, 0}, 396 | { XK_F3, XK_NO_MOD, "\033OR" , 0, 0}, 397 | { XK_F3, /* F15 */ ShiftMask, "\033[1;2R", 0, 0}, 398 | { XK_F3, /* F27 */ ControlMask, "\033[1;5R", 0, 0}, 399 | { XK_F3, /* F39 */ Mod4Mask, "\033[1;6R", 0, 0}, 400 | { XK_F3, /* F51 */ Mod1Mask, "\033[1;3R", 0, 0}, 401 | { XK_F3, /* F63 */ Mod3Mask, "\033[1;4R", 0, 0}, 402 | { XK_F4, XK_NO_MOD, "\033OS" , 0, 0}, 403 | { XK_F4, /* F16 */ ShiftMask, "\033[1;2S", 0, 0}, 404 | { XK_F4, /* F28 */ ControlMask, "\033[1;5S", 0, 0}, 405 | { XK_F4, /* F40 */ Mod4Mask, "\033[1;6S", 0, 0}, 406 | { XK_F4, /* F52 */ Mod1Mask, "\033[1;3S", 0, 0}, 407 | { XK_F5, XK_NO_MOD, "\033[15~", 0, 0}, 408 | { XK_F5, /* F17 */ ShiftMask, "\033[15;2~", 0, 0}, 409 | { XK_F5, /* F29 */ ControlMask, "\033[15;5~", 0, 0}, 410 | { XK_F5, /* F41 */ Mod4Mask, "\033[15;6~", 0, 0}, 411 | { XK_F5, /* F53 */ Mod1Mask, "\033[15;3~", 0, 0}, 412 | { XK_F6, XK_NO_MOD, "\033[17~", 0, 0}, 413 | { XK_F6, /* F18 */ ShiftMask, "\033[17;2~", 0, 0}, 414 | { XK_F6, /* F30 */ ControlMask, "\033[17;5~", 0, 0}, 415 | { XK_F6, /* F42 */ Mod4Mask, "\033[17;6~", 0, 0}, 416 | { XK_F6, /* F54 */ Mod1Mask, "\033[17;3~", 0, 0}, 417 | { XK_F7, XK_NO_MOD, "\033[18~", 0, 0}, 418 | { XK_F7, /* F19 */ ShiftMask, "\033[18;2~", 0, 0}, 419 | { XK_F7, /* F31 */ ControlMask, "\033[18;5~", 0, 0}, 420 | { XK_F7, /* F43 */ Mod4Mask, "\033[18;6~", 0, 0}, 421 | { XK_F7, /* F55 */ Mod1Mask, "\033[18;3~", 0, 0}, 422 | { XK_F8, XK_NO_MOD, "\033[19~", 0, 0}, 423 | { XK_F8, /* F20 */ ShiftMask, "\033[19;2~", 0, 0}, 424 | { XK_F8, /* F32 */ ControlMask, "\033[19;5~", 0, 0}, 425 | { XK_F8, /* F44 */ Mod4Mask, "\033[19;6~", 0, 0}, 426 | { XK_F8, /* F56 */ Mod1Mask, "\033[19;3~", 0, 0}, 427 | { XK_F9, XK_NO_MOD, "\033[20~", 0, 0}, 428 | { XK_F9, /* F21 */ ShiftMask, "\033[20;2~", 0, 0}, 429 | { XK_F9, /* F33 */ ControlMask, "\033[20;5~", 0, 0}, 430 | { XK_F9, /* F45 */ Mod4Mask, "\033[20;6~", 0, 0}, 431 | { XK_F9, /* F57 */ Mod1Mask, "\033[20;3~", 0, 0}, 432 | { XK_F10, XK_NO_MOD, "\033[21~", 0, 0}, 433 | { XK_F10, /* F22 */ ShiftMask, "\033[21;2~", 0, 0}, 434 | { XK_F10, /* F34 */ ControlMask, "\033[21;5~", 0, 0}, 435 | { XK_F10, /* F46 */ Mod4Mask, "\033[21;6~", 0, 0}, 436 | { XK_F10, /* F58 */ Mod1Mask, "\033[21;3~", 0, 0}, 437 | { XK_F11, XK_NO_MOD, "\033[23~", 0, 0}, 438 | { XK_F11, /* F23 */ ShiftMask, "\033[23;2~", 0, 0}, 439 | { XK_F11, /* F35 */ ControlMask, "\033[23;5~", 0, 0}, 440 | { XK_F11, /* F47 */ Mod4Mask, "\033[23;6~", 0, 0}, 441 | { XK_F11, /* F59 */ Mod1Mask, "\033[23;3~", 0, 0}, 442 | { XK_F12, XK_NO_MOD, "\033[24~", 0, 0}, 443 | { XK_F12, /* F24 */ ShiftMask, "\033[24;2~", 0, 0}, 444 | { XK_F12, /* F36 */ ControlMask, "\033[24;5~", 0, 0}, 445 | { XK_F12, /* F48 */ Mod4Mask, "\033[24;6~", 0, 0}, 446 | { XK_F12, /* F60 */ Mod1Mask, "\033[24;3~", 0, 0}, 447 | { XK_F13, XK_NO_MOD, "\033[1;2P", 0, 0}, 448 | { XK_F14, XK_NO_MOD, "\033[1;2Q", 0, 0}, 449 | { XK_F15, XK_NO_MOD, "\033[1;2R", 0, 0}, 450 | { XK_F16, XK_NO_MOD, "\033[1;2S", 0, 0}, 451 | { XK_F17, XK_NO_MOD, "\033[15;2~", 0, 0}, 452 | { XK_F18, XK_NO_MOD, "\033[17;2~", 0, 0}, 453 | { XK_F19, XK_NO_MOD, "\033[18;2~", 0, 0}, 454 | { XK_F20, XK_NO_MOD, "\033[19;2~", 0, 0}, 455 | { XK_F21, XK_NO_MOD, "\033[20;2~", 0, 0}, 456 | { XK_F22, XK_NO_MOD, "\033[21;2~", 0, 0}, 457 | { XK_F23, XK_NO_MOD, "\033[23;2~", 0, 0}, 458 | { XK_F24, XK_NO_MOD, "\033[24;2~", 0, 0}, 459 | { XK_F25, XK_NO_MOD, "\033[1;5P", 0, 0}, 460 | { XK_F26, XK_NO_MOD, "\033[1;5Q", 0, 0}, 461 | { XK_F27, XK_NO_MOD, "\033[1;5R", 0, 0}, 462 | { XK_F28, XK_NO_MOD, "\033[1;5S", 0, 0}, 463 | { XK_F29, XK_NO_MOD, "\033[15;5~", 0, 0}, 464 | { XK_F30, XK_NO_MOD, "\033[17;5~", 0, 0}, 465 | { XK_F31, XK_NO_MOD, "\033[18;5~", 0, 0}, 466 | { XK_F32, XK_NO_MOD, "\033[19;5~", 0, 0}, 467 | { XK_F33, XK_NO_MOD, "\033[20;5~", 0, 0}, 468 | { XK_F34, XK_NO_MOD, "\033[21;5~", 0, 0}, 469 | { XK_F35, XK_NO_MOD, "\033[23;5~", 0, 0}, 470 | }; 471 | 472 | /* 473 | * Selection types' masks. 474 | * Use the same masks as usual. 475 | * Button1Mask is always unset, to make masks match between ButtonPress. 476 | * ButtonRelease and MotionNotify. 477 | * If no match is found, regular selection is used. 478 | */ 479 | static uint selmasks[] = { 480 | [SEL_RECTANGULAR] = Mod1Mask, 481 | }; 482 | 483 | /* 484 | * Printable characters in ASCII, used to estimate the advance width 485 | * of single wide characters. 486 | */ 487 | static char ascii_printable[] = 488 | " !\"#$%&'()*+,-./0123456789:;<=>?" 489 | "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" 490 | "`abcdefghijklmnopqrstuvwxyz{|}~"; 491 | -------------------------------------------------------------------------------- /config.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for copyright and license details. */ 2 | 3 | /* 4 | * appearance 5 | * 6 | * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html 7 | */ 8 | static char *font = "M PLUS Code Latin 50:Semibold:size=14:antialias=true:autohint=true"; 9 | /* Spare fonts */ 10 | static char *font2[] = { 11 | "Symbols NF:Semibold:size=14", 12 | }; 13 | static int borderpx = 12; 14 | 15 | /* 16 | * What program is execed by st depends of these precedence rules: 17 | * 1: program passed with -e 18 | * 2: scroll and/or utmp 19 | * 3: SHELL environment variable 20 | * 4: value of shell in /etc/passwd 21 | * 5: value of shell in config.h 22 | */ 23 | static char *shell = "/bin/sh"; 24 | char *utmp = NULL; 25 | /* scroll program: to enable use a string like "scroll" */ 26 | char *scroll = NULL; 27 | char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400"; 28 | 29 | /* identification sequence returned in DA and DECID */ 30 | char *vtiden = "\033[?6c"; 31 | 32 | /* Kerning / character bounding-box multipliers */ 33 | static float cwscale = 1.0; 34 | static float chscale = 1.0; 35 | 36 | /* 37 | * word delimiter string 38 | * 39 | * More advanced example: L" `'\"()[]{}" 40 | */ 41 | wchar_t *worddelimiters = L" "; 42 | 43 | /* selection timeouts (in milliseconds) */ 44 | static unsigned int doubleclicktimeout = 300; 45 | static unsigned int tripleclicktimeout = 600; 46 | 47 | /* alt screens */ 48 | int allowaltscreen = 1; 49 | 50 | /* allow certain non-interactive (insecure) window operations such as: 51 | setting the clipboard text */ 52 | int allowwindowops = 0; 53 | 54 | /* 55 | * draw latency range in ms - from new content/keypress/etc until drawing. 56 | * within this range, st draws when content stops arriving (idle). mostly it's 57 | * near minlatency, but it waits longer for slow updates to avoid partial draw. 58 | * low minlatency will tear/flicker more, as it can "detect" idle too early. 59 | */ 60 | static double minlatency = 8; 61 | static double maxlatency = 33; 62 | 63 | /* 64 | * blinking timeout (set to 0 to disable blinking) for the terminal blinking 65 | * attribute. 66 | */ 67 | static unsigned int blinktimeout = 800; 68 | 69 | /* 70 | * thickness of underline and bar cursors 71 | */ 72 | static unsigned int cursorthickness = 2; 73 | 74 | /* 75 | * 1: render most of the lines/blocks characters without using the font for 76 | * perfect alignment between cells (U2500 - U259F except dashes/diagonals). 77 | * Bold affects lines thickness if boxdraw_bold is not 0. Italic is ignored. 78 | * 0: disable (render all U25XX glyphs normally from the font). 79 | */ 80 | const int boxdraw = 1; 81 | const int boxdraw_bold = 0; 82 | 83 | /* braille (U28XX): 1: render as adjacent "pixels", 0: use font */ 84 | const int boxdraw_braille = 0; 85 | 86 | /* 87 | * bell volume. It must be a value between -100 and 100. Use 0 for disabling 88 | * it 89 | */ 90 | static int bellvolume = 0; 91 | 92 | /* default TERM value */ 93 | char *termname = "st-256color"; 94 | 95 | /* 96 | * spaces per tab 97 | * 98 | * When you are changing this value, don't forget to adapt the »it« value in 99 | * the st.info and appropriately install the st.info in the environment where 100 | * you use this st version. 101 | * 102 | * it#$tabspaces, 103 | * 104 | * Secondly make sure your kernel is not expanding tabs. When running `stty 105 | * -a` »tab0« should appear. You can tell the terminal to not expand tabs by 106 | * running following command: 107 | * 108 | * stty tabs 109 | */ 110 | unsigned int tabspaces = 8; 111 | 112 | /* Terminal colors (16 first used in escape sequence) */ 113 | static const char *colorname[] = { 114 | /* 8 normal colors */ 115 | [0] = "#373737", /* black */ 116 | [1] = "#ec5f67", /* red */ 117 | [2] = "#99c794", /* green */ 118 | [3] = "#fac863", /* yellow */ 119 | [4] = "#6699cc", /* blue */ 120 | [5] = "#c594c5", /* magenta */ 121 | [6] = "#62b2b3", /* cyan */ 122 | [7] = "#d8dee9", /* white */ 123 | 124 | /* 8 bright colors */ 125 | [8] = "#373737", /* black */ 126 | [9] = "#ec5f67", /* red */ 127 | [10] = "#99c794", /* green */ 128 | [11] = "#fac863", /* yellow */ 129 | [12] = "#6699cc", /* blue */ 130 | [13] = "#c594c5", /* magenta */ 131 | [14] = "#62b2b3", /* cyan */ 132 | [15] = "#d8dee9", /* white */ 133 | 134 | /* special colors */ 135 | [256] = "#1e1e1e", /* background */ 136 | [257] = "#f7f7f7", /* foreground */ 137 | }; 138 | 139 | 140 | /* 141 | * Default colors (colorname index) 142 | * foreground, background, cursor, reverse cursor 143 | */ 144 | unsigned int defaultfg = 257; 145 | unsigned int defaultbg = 256; 146 | unsigned int defaultcs = 257; 147 | static unsigned int defaultrcs = 257; 148 | 149 | /* 150 | * Colors used, when the specific fg == defaultfg. So in reverse mode this 151 | * will reverse too. Another logic would only make the simple feature too 152 | * complex. 153 | */ 154 | unsigned int defaultitalic = 7; 155 | unsigned int defaultunderline = 7; 156 | /* 157 | * Default shape of cursor 158 | * 2: Block ("█") 159 | * 4: Underline ("_") 160 | * 6: Bar ("|") 161 | * 7: Snowman ("☃") 162 | */ 163 | static unsigned int cursorshape = 2; 164 | 165 | /* 166 | * Default columns and rows numbers 167 | */ 168 | 169 | static unsigned int cols = 80; 170 | static unsigned int rows = 24; 171 | 172 | /* 173 | * Default colour and shape of the mouse cursor 174 | */ 175 | static unsigned int mouseshape = XC_xterm; 176 | static unsigned int mousefg = 7; 177 | static unsigned int mousebg = 0; 178 | 179 | /* 180 | * Color used to display font attributes when fontconfig selected a font which 181 | * doesn't match the ones requested. 182 | */ 183 | static unsigned int defaultattr = 11; 184 | 185 | /* 186 | * Force mouse select/shortcuts while mask is active (when MODE_MOUSE is set). 187 | * Note that if you want to use ShiftMask with selmasks, set this to an other 188 | * modifier, set to 0 to not use it. 189 | */ 190 | static uint forcemousemod = ShiftMask; 191 | 192 | /* 193 | * Internal mouse shortcuts. 194 | * Beware that overloading Button1 will disable the selection. 195 | */ 196 | static MouseShortcut mshortcuts[] = { 197 | /* mask button function argument release */ 198 | { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 }, 199 | { ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} }, 200 | { XK_ANY_MOD, Button4, ttysend, {.s = "\031"} }, 201 | { ShiftMask, Button5, ttysend, {.s = "\033[6;2~"} }, 202 | { XK_ANY_MOD, Button5, ttysend, {.s = "\005"} }, 203 | }; 204 | 205 | /* Internal keyboard shortcuts. */ 206 | #define MODKEY Mod1Mask 207 | #define TERMMOD (ControlMask|ShiftMask) 208 | 209 | static Shortcut shortcuts[] = { 210 | /* mask keysym function argument */ 211 | { XK_ANY_MOD, XK_Break, sendbreak, {.i = 0} }, 212 | { ControlMask, XK_Print, toggleprinter, {.i = 0} }, 213 | { ShiftMask, XK_Print, printscreen, {.i = 0} }, 214 | { XK_ANY_MOD, XK_Print, printsel, {.i = 0} }, 215 | { ControlMask, XK_equal, zoom, {.f = +1} }, 216 | { ControlMask, XK_minus, zoom, {.f = -1} }, 217 | { ControlMask, XK_0, zoomreset, {.f = 0} }, 218 | { TERMMOD, XK_C, clipcopy, {.i = 0} }, 219 | { TERMMOD, XK_V, clippaste, {.i = 0} }, 220 | { TERMMOD, XK_Y, selpaste, {.i = 0} }, 221 | { ShiftMask, XK_Insert, selpaste, {.i = 0} }, 222 | { TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, 223 | { ShiftMask, XK_Page_Up, kscrollup, {.i = -1} }, 224 | { ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} }, 225 | }; 226 | 227 | /* 228 | * Special keys (change & recompile st.info accordingly) 229 | * 230 | * Mask value: 231 | * * Use XK_ANY_MOD to match the key no matter modifiers state 232 | * * Use XK_NO_MOD to match the key alone (no modifiers) 233 | * appkey value: 234 | * * 0: no value 235 | * * > 0: keypad application mode enabled 236 | * * = 2: term.numlock = 1 237 | * * < 0: keypad application mode disabled 238 | * appcursor value: 239 | * * 0: no value 240 | * * > 0: cursor application mode enabled 241 | * * < 0: cursor application mode disabled 242 | * 243 | * Be careful with the order of the definitions because st searches in 244 | * this table sequentially, so any XK_ANY_MOD must be in the last 245 | * position for a key. 246 | */ 247 | 248 | /* 249 | * If you want keys other than the X11 function keys (0xFD00 - 0xFFFF) 250 | * to be mapped below, add them to this array. 251 | */ 252 | static KeySym mappedkeys[] = { -1 }; 253 | 254 | /* 255 | * State bits to ignore when matching key or button events. By default, 256 | * numlock (Mod2Mask) and keyboard layout (XK_SWITCH_MOD) are ignored. 257 | */ 258 | static uint ignoremod = Mod2Mask|XK_SWITCH_MOD; 259 | 260 | /* 261 | * This is the huge key array which defines all compatibility to the Linux 262 | * world. Please decide about changes wisely. 263 | */ 264 | static Key key[] = { 265 | /* keysym mask string appkey appcursor */ 266 | { XK_KP_Home, ShiftMask, "\033[2J", 0, -1}, 267 | { XK_KP_Home, ShiftMask, "\033[1;2H", 0, +1}, 268 | { XK_KP_Home, XK_ANY_MOD, "\033[H", 0, -1}, 269 | { XK_KP_Home, XK_ANY_MOD, "\033[1~", 0, +1}, 270 | { XK_KP_Up, XK_ANY_MOD, "\033Ox", +1, 0}, 271 | { XK_KP_Up, XK_ANY_MOD, "\033[A", 0, -1}, 272 | { XK_KP_Up, XK_ANY_MOD, "\033OA", 0, +1}, 273 | { XK_KP_Down, XK_ANY_MOD, "\033Or", +1, 0}, 274 | { XK_KP_Down, XK_ANY_MOD, "\033[B", 0, -1}, 275 | { XK_KP_Down, XK_ANY_MOD, "\033OB", 0, +1}, 276 | { XK_KP_Left, XK_ANY_MOD, "\033Ot", +1, 0}, 277 | { XK_KP_Left, XK_ANY_MOD, "\033[D", 0, -1}, 278 | { XK_KP_Left, XK_ANY_MOD, "\033OD", 0, +1}, 279 | { XK_KP_Right, XK_ANY_MOD, "\033Ov", +1, 0}, 280 | { XK_KP_Right, XK_ANY_MOD, "\033[C", 0, -1}, 281 | { XK_KP_Right, XK_ANY_MOD, "\033OC", 0, +1}, 282 | { XK_KP_Prior, ShiftMask, "\033[5;2~", 0, 0}, 283 | { XK_KP_Prior, XK_ANY_MOD, "\033[5~", 0, 0}, 284 | { XK_KP_Begin, XK_ANY_MOD, "\033[E", 0, 0}, 285 | { XK_KP_End, ControlMask, "\033[J", -1, 0}, 286 | { XK_KP_End, ControlMask, "\033[1;5F", +1, 0}, 287 | { XK_KP_End, ShiftMask, "\033[K", -1, 0}, 288 | { XK_KP_End, ShiftMask, "\033[1;2F", +1, 0}, 289 | { XK_KP_End, XK_ANY_MOD, "\033[4~", 0, 0}, 290 | { XK_KP_Next, ShiftMask, "\033[6;2~", 0, 0}, 291 | { XK_KP_Next, XK_ANY_MOD, "\033[6~", 0, 0}, 292 | { XK_KP_Insert, ShiftMask, "\033[2;2~", +1, 0}, 293 | { XK_KP_Insert, ShiftMask, "\033[4l", -1, 0}, 294 | { XK_KP_Insert, ControlMask, "\033[L", -1, 0}, 295 | { XK_KP_Insert, ControlMask, "\033[2;5~", +1, 0}, 296 | { XK_KP_Insert, XK_ANY_MOD, "\033[4h", -1, 0}, 297 | { XK_KP_Insert, XK_ANY_MOD, "\033[2~", +1, 0}, 298 | { XK_KP_Delete, ControlMask, "\033[M", -1, 0}, 299 | { XK_KP_Delete, ControlMask, "\033[3;5~", +1, 0}, 300 | { XK_KP_Delete, ShiftMask, "\033[2K", -1, 0}, 301 | { XK_KP_Delete, ShiftMask, "\033[3;2~", +1, 0}, 302 | { XK_KP_Delete, XK_ANY_MOD, "\033[P", -1, 0}, 303 | { XK_KP_Delete, XK_ANY_MOD, "\033[3~", +1, 0}, 304 | { XK_KP_Multiply, XK_ANY_MOD, "\033Oj", +2, 0}, 305 | { XK_KP_Add, XK_ANY_MOD, "\033Ok", +2, 0}, 306 | { XK_KP_Enter, XK_ANY_MOD, "\033OM", +2, 0}, 307 | { XK_KP_Enter, XK_ANY_MOD, "\r", -1, 0}, 308 | { XK_KP_Subtract, XK_ANY_MOD, "\033Om", +2, 0}, 309 | { XK_KP_Decimal, XK_ANY_MOD, "\033On", +2, 0}, 310 | { XK_KP_Divide, XK_ANY_MOD, "\033Oo", +2, 0}, 311 | { XK_KP_0, XK_ANY_MOD, "\033Op", +2, 0}, 312 | { XK_KP_1, XK_ANY_MOD, "\033Oq", +2, 0}, 313 | { XK_KP_2, XK_ANY_MOD, "\033Or", +2, 0}, 314 | { XK_KP_3, XK_ANY_MOD, "\033Os", +2, 0}, 315 | { XK_KP_4, XK_ANY_MOD, "\033Ot", +2, 0}, 316 | { XK_KP_5, XK_ANY_MOD, "\033Ou", +2, 0}, 317 | { XK_KP_6, XK_ANY_MOD, "\033Ov", +2, 0}, 318 | { XK_KP_7, XK_ANY_MOD, "\033Ow", +2, 0}, 319 | { XK_KP_8, XK_ANY_MOD, "\033Ox", +2, 0}, 320 | { XK_KP_9, XK_ANY_MOD, "\033Oy", +2, 0}, 321 | { XK_Up, ShiftMask, "\033[1;2A", 0, 0}, 322 | { XK_Up, Mod1Mask, "\033[1;3A", 0, 0}, 323 | { XK_Up, ShiftMask|Mod1Mask,"\033[1;4A", 0, 0}, 324 | { XK_Up, ControlMask, "\033[1;5A", 0, 0}, 325 | { XK_Up, ShiftMask|ControlMask,"\033[1;6A", 0, 0}, 326 | { XK_Up, ControlMask|Mod1Mask,"\033[1;7A", 0, 0}, 327 | { XK_Up,ShiftMask|ControlMask|Mod1Mask,"\033[1;8A", 0, 0}, 328 | { XK_Up, XK_ANY_MOD, "\033[A", 0, -1}, 329 | { XK_Up, XK_ANY_MOD, "\033OA", 0, +1}, 330 | { XK_Down, ShiftMask, "\033[1;2B", 0, 0}, 331 | { XK_Down, Mod1Mask, "\033[1;3B", 0, 0}, 332 | { XK_Down, ShiftMask|Mod1Mask,"\033[1;4B", 0, 0}, 333 | { XK_Down, ControlMask, "\033[1;5B", 0, 0}, 334 | { XK_Down, ShiftMask|ControlMask,"\033[1;6B", 0, 0}, 335 | { XK_Down, ControlMask|Mod1Mask,"\033[1;7B", 0, 0}, 336 | { XK_Down,ShiftMask|ControlMask|Mod1Mask,"\033[1;8B",0, 0}, 337 | { XK_Down, XK_ANY_MOD, "\033[B", 0, -1}, 338 | { XK_Down, XK_ANY_MOD, "\033OB", 0, +1}, 339 | { XK_Left, ShiftMask, "\033[1;2D", 0, 0}, 340 | { XK_Left, Mod1Mask, "\033[1;3D", 0, 0}, 341 | { XK_Left, ShiftMask|Mod1Mask,"\033[1;4D", 0, 0}, 342 | { XK_Left, ControlMask, "\033[1;5D", 0, 0}, 343 | { XK_Left, ShiftMask|ControlMask,"\033[1;6D", 0, 0}, 344 | { XK_Left, ControlMask|Mod1Mask,"\033[1;7D", 0, 0}, 345 | { XK_Left,ShiftMask|ControlMask|Mod1Mask,"\033[1;8D",0, 0}, 346 | { XK_Left, XK_ANY_MOD, "\033[D", 0, -1}, 347 | { XK_Left, XK_ANY_MOD, "\033OD", 0, +1}, 348 | { XK_Right, ShiftMask, "\033[1;2C", 0, 0}, 349 | { XK_Right, Mod1Mask, "\033[1;3C", 0, 0}, 350 | { XK_Right, ShiftMask|Mod1Mask,"\033[1;4C", 0, 0}, 351 | { XK_Right, ControlMask, "\033[1;5C", 0, 0}, 352 | { XK_Right, ShiftMask|ControlMask,"\033[1;6C", 0, 0}, 353 | { XK_Right, ControlMask|Mod1Mask,"\033[1;7C", 0, 0}, 354 | { XK_Right,ShiftMask|ControlMask|Mod1Mask,"\033[1;8C",0, 0}, 355 | { XK_Right, XK_ANY_MOD, "\033[C", 0, -1}, 356 | { XK_Right, XK_ANY_MOD, "\033OC", 0, +1}, 357 | { XK_ISO_Left_Tab, ShiftMask, "\033[Z", 0, 0}, 358 | { XK_Return, Mod1Mask, "\033\r", 0, 0}, 359 | { XK_Return, XK_ANY_MOD, "\r", 0, 0}, 360 | { XK_Insert, ShiftMask, "\033[4l", -1, 0}, 361 | { XK_Insert, ShiftMask, "\033[2;2~", +1, 0}, 362 | { XK_Insert, ControlMask, "\033[L", -1, 0}, 363 | { XK_Insert, ControlMask, "\033[2;5~", +1, 0}, 364 | { XK_Insert, XK_ANY_MOD, "\033[4h", -1, 0}, 365 | { XK_Insert, XK_ANY_MOD, "\033[2~", +1, 0}, 366 | { XK_Delete, ControlMask, "\033[M", -1, 0}, 367 | { XK_Delete, ControlMask, "\033[3;5~", +1, 0}, 368 | { XK_Delete, ShiftMask, "\033[2K", -1, 0}, 369 | { XK_Delete, ShiftMask, "\033[3;2~", +1, 0}, 370 | { XK_Delete, XK_ANY_MOD, "\033[P", -1, 0}, 371 | { XK_Delete, XK_ANY_MOD, "\033[3~", +1, 0}, 372 | { XK_BackSpace, XK_NO_MOD, "\177", 0, 0}, 373 | { XK_BackSpace, Mod1Mask, "\033\177", 0, 0}, 374 | { XK_Home, ShiftMask, "\033[2J", 0, -1}, 375 | { XK_Home, ShiftMask, "\033[1;2H", 0, +1}, 376 | { XK_Home, XK_ANY_MOD, "\033[H", 0, -1}, 377 | { XK_Home, XK_ANY_MOD, "\033[1~", 0, +1}, 378 | { XK_End, ControlMask, "\033[J", -1, 0}, 379 | { XK_End, ControlMask, "\033[1;5F", +1, 0}, 380 | { XK_End, ShiftMask, "\033[K", -1, 0}, 381 | { XK_End, ShiftMask, "\033[1;2F", +1, 0}, 382 | { XK_End, XK_ANY_MOD, "\033[4~", 0, 0}, 383 | { XK_Prior, ControlMask, "\033[5;5~", 0, 0}, 384 | { XK_Prior, ShiftMask, "\033[5;2~", 0, 0}, 385 | { XK_Prior, XK_ANY_MOD, "\033[5~", 0, 0}, 386 | { XK_Next, ControlMask, "\033[6;5~", 0, 0}, 387 | { XK_Next, ShiftMask, "\033[6;2~", 0, 0}, 388 | { XK_Next, XK_ANY_MOD, "\033[6~", 0, 0}, 389 | { XK_F1, XK_NO_MOD, "\033OP" , 0, 0}, 390 | { XK_F1, /* F13 */ ShiftMask, "\033[1;2P", 0, 0}, 391 | { XK_F1, /* F25 */ ControlMask, "\033[1;5P", 0, 0}, 392 | { XK_F1, /* F37 */ Mod4Mask, "\033[1;6P", 0, 0}, 393 | { XK_F1, /* F49 */ Mod1Mask, "\033[1;3P", 0, 0}, 394 | { XK_F1, /* F61 */ Mod3Mask, "\033[1;4P", 0, 0}, 395 | { XK_F2, XK_NO_MOD, "\033OQ" , 0, 0}, 396 | { XK_F2, /* F14 */ ShiftMask, "\033[1;2Q", 0, 0}, 397 | { XK_F2, /* F26 */ ControlMask, "\033[1;5Q", 0, 0}, 398 | { XK_F2, /* F38 */ Mod4Mask, "\033[1;6Q", 0, 0}, 399 | { XK_F2, /* F50 */ Mod1Mask, "\033[1;3Q", 0, 0}, 400 | { XK_F2, /* F62 */ Mod3Mask, "\033[1;4Q", 0, 0}, 401 | { XK_F3, XK_NO_MOD, "\033OR" , 0, 0}, 402 | { XK_F3, /* F15 */ ShiftMask, "\033[1;2R", 0, 0}, 403 | { XK_F3, /* F27 */ ControlMask, "\033[1;5R", 0, 0}, 404 | { XK_F3, /* F39 */ Mod4Mask, "\033[1;6R", 0, 0}, 405 | { XK_F3, /* F51 */ Mod1Mask, "\033[1;3R", 0, 0}, 406 | { XK_F3, /* F63 */ Mod3Mask, "\033[1;4R", 0, 0}, 407 | { XK_F4, XK_NO_MOD, "\033OS" , 0, 0}, 408 | { XK_F4, /* F16 */ ShiftMask, "\033[1;2S", 0, 0}, 409 | { XK_F4, /* F28 */ ControlMask, "\033[1;5S", 0, 0}, 410 | { XK_F4, /* F40 */ Mod4Mask, "\033[1;6S", 0, 0}, 411 | { XK_F4, /* F52 */ Mod1Mask, "\033[1;3S", 0, 0}, 412 | { XK_F5, XK_NO_MOD, "\033[15~", 0, 0}, 413 | { XK_F5, /* F17 */ ShiftMask, "\033[15;2~", 0, 0}, 414 | { XK_F5, /* F29 */ ControlMask, "\033[15;5~", 0, 0}, 415 | { XK_F5, /* F41 */ Mod4Mask, "\033[15;6~", 0, 0}, 416 | { XK_F5, /* F53 */ Mod1Mask, "\033[15;3~", 0, 0}, 417 | { XK_F6, XK_NO_MOD, "\033[17~", 0, 0}, 418 | { XK_F6, /* F18 */ ShiftMask, "\033[17;2~", 0, 0}, 419 | { XK_F6, /* F30 */ ControlMask, "\033[17;5~", 0, 0}, 420 | { XK_F6, /* F42 */ Mod4Mask, "\033[17;6~", 0, 0}, 421 | { XK_F6, /* F54 */ Mod1Mask, "\033[17;3~", 0, 0}, 422 | { XK_F7, XK_NO_MOD, "\033[18~", 0, 0}, 423 | { XK_F7, /* F19 */ ShiftMask, "\033[18;2~", 0, 0}, 424 | { XK_F7, /* F31 */ ControlMask, "\033[18;5~", 0, 0}, 425 | { XK_F7, /* F43 */ Mod4Mask, "\033[18;6~", 0, 0}, 426 | { XK_F7, /* F55 */ Mod1Mask, "\033[18;3~", 0, 0}, 427 | { XK_F8, XK_NO_MOD, "\033[19~", 0, 0}, 428 | { XK_F8, /* F20 */ ShiftMask, "\033[19;2~", 0, 0}, 429 | { XK_F8, /* F32 */ ControlMask, "\033[19;5~", 0, 0}, 430 | { XK_F8, /* F44 */ Mod4Mask, "\033[19;6~", 0, 0}, 431 | { XK_F8, /* F56 */ Mod1Mask, "\033[19;3~", 0, 0}, 432 | { XK_F9, XK_NO_MOD, "\033[20~", 0, 0}, 433 | { XK_F9, /* F21 */ ShiftMask, "\033[20;2~", 0, 0}, 434 | { XK_F9, /* F33 */ ControlMask, "\033[20;5~", 0, 0}, 435 | { XK_F9, /* F45 */ Mod4Mask, "\033[20;6~", 0, 0}, 436 | { XK_F9, /* F57 */ Mod1Mask, "\033[20;3~", 0, 0}, 437 | { XK_F10, XK_NO_MOD, "\033[21~", 0, 0}, 438 | { XK_F10, /* F22 */ ShiftMask, "\033[21;2~", 0, 0}, 439 | { XK_F10, /* F34 */ ControlMask, "\033[21;5~", 0, 0}, 440 | { XK_F10, /* F46 */ Mod4Mask, "\033[21;6~", 0, 0}, 441 | { XK_F10, /* F58 */ Mod1Mask, "\033[21;3~", 0, 0}, 442 | { XK_F11, XK_NO_MOD, "\033[23~", 0, 0}, 443 | { XK_F11, /* F23 */ ShiftMask, "\033[23;2~", 0, 0}, 444 | { XK_F11, /* F35 */ ControlMask, "\033[23;5~", 0, 0}, 445 | { XK_F11, /* F47 */ Mod4Mask, "\033[23;6~", 0, 0}, 446 | { XK_F11, /* F59 */ Mod1Mask, "\033[23;3~", 0, 0}, 447 | { XK_F12, XK_NO_MOD, "\033[24~", 0, 0}, 448 | { XK_F12, /* F24 */ ShiftMask, "\033[24;2~", 0, 0}, 449 | { XK_F12, /* F36 */ ControlMask, "\033[24;5~", 0, 0}, 450 | { XK_F12, /* F48 */ Mod4Mask, "\033[24;6~", 0, 0}, 451 | { XK_F12, /* F60 */ Mod1Mask, "\033[24;3~", 0, 0}, 452 | { XK_F13, XK_NO_MOD, "\033[1;2P", 0, 0}, 453 | { XK_F14, XK_NO_MOD, "\033[1;2Q", 0, 0}, 454 | { XK_F15, XK_NO_MOD, "\033[1;2R", 0, 0}, 455 | { XK_F16, XK_NO_MOD, "\033[1;2S", 0, 0}, 456 | { XK_F17, XK_NO_MOD, "\033[15;2~", 0, 0}, 457 | { XK_F18, XK_NO_MOD, "\033[17;2~", 0, 0}, 458 | { XK_F19, XK_NO_MOD, "\033[18;2~", 0, 0}, 459 | { XK_F20, XK_NO_MOD, "\033[19;2~", 0, 0}, 460 | { XK_F21, XK_NO_MOD, "\033[20;2~", 0, 0}, 461 | { XK_F22, XK_NO_MOD, "\033[21;2~", 0, 0}, 462 | { XK_F23, XK_NO_MOD, "\033[23;2~", 0, 0}, 463 | { XK_F24, XK_NO_MOD, "\033[24;2~", 0, 0}, 464 | { XK_F25, XK_NO_MOD, "\033[1;5P", 0, 0}, 465 | { XK_F26, XK_NO_MOD, "\033[1;5Q", 0, 0}, 466 | { XK_F27, XK_NO_MOD, "\033[1;5R", 0, 0}, 467 | { XK_F28, XK_NO_MOD, "\033[1;5S", 0, 0}, 468 | { XK_F29, XK_NO_MOD, "\033[15;5~", 0, 0}, 469 | { XK_F30, XK_NO_MOD, "\033[17;5~", 0, 0}, 470 | { XK_F31, XK_NO_MOD, "\033[18;5~", 0, 0}, 471 | { XK_F32, XK_NO_MOD, "\033[19;5~", 0, 0}, 472 | { XK_F33, XK_NO_MOD, "\033[20;5~", 0, 0}, 473 | { XK_F34, XK_NO_MOD, "\033[21;5~", 0, 0}, 474 | { XK_F35, XK_NO_MOD, "\033[23;5~", 0, 0}, 475 | }; 476 | 477 | /* 478 | * Selection types' masks. 479 | * Use the same masks as usual. 480 | * Button1Mask is always unset, to make masks match between ButtonPress. 481 | * ButtonRelease and MotionNotify. 482 | * If no match is found, regular selection is used. 483 | */ 484 | static uint selmasks[] = { 485 | [SEL_RECTANGULAR] = Mod1Mask, 486 | }; 487 | 488 | /* 489 | * Printable characters in ASCII, used to estimate the advance width 490 | * of single wide characters. 491 | */ 492 | static char ascii_printable[] = 493 | " !\"#$%&'()*+,-./0123456789:;<=>?" 494 | "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" 495 | "`abcdefghijklmnopqrstuvwxyz{|}~"; 496 | -------------------------------------------------------------------------------- /config.mk: -------------------------------------------------------------------------------- 1 | # st version 2 | VERSION = 0.9 3 | 4 | # Customize below to fit your system 5 | 6 | # paths 7 | PREFIX = /usr/local 8 | MANPREFIX = $(PREFIX)/share/man 9 | 10 | X11INC = /usr/include/X11 11 | X11LIB = /usr/lib/X11 12 | 13 | PKG_CONFIG = pkg-config 14 | 15 | # includes and libs 16 | INCS = -I$(X11INC) \ 17 | `$(PKG_CONFIG) --cflags fontconfig` \ 18 | `$(PKG_CONFIG) --cflags freetype2` \ 19 | `$(PKG_CONFIG) --cflags harfbuzz` 20 | LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft \ 21 | `$(PKG_CONFIG) --libs fontconfig` \ 22 | `$(PKG_CONFIG) --libs freetype2` \ 23 | `$(PKG_CONFIG) --libs harfbuzz` 24 | 25 | # flags 26 | STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 27 | STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS) 28 | STLDFLAGS = $(LIBS) $(LDFLAGS) 29 | 30 | # OpenBSD: 31 | #CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 -D_BSD_SOURCE 32 | #LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft \ 33 | # `$(PKG_CONFIG) --libs fontconfig` \ 34 | # `$(PKG_CONFIG) --libs freetype2` 35 | #MANPREFIX = ${PREFIX}/man 36 | 37 | # compiler and linker 38 | CC = gcc 39 | -------------------------------------------------------------------------------- /hb.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "st.h" 10 | #include "hb.h" 11 | 12 | #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 } 13 | 14 | hb_font_t *hbfindfont(XftFont *match); 15 | 16 | typedef struct { 17 | XftFont *match; 18 | hb_font_t *font; 19 | } HbFontMatch; 20 | 21 | static int hbfontslen = 0; 22 | static HbFontMatch *hbfontcache = NULL; 23 | 24 | /* 25 | * Poplulate the array with a list of font features, wrapped in FEATURE macro, 26 | * e. g. 27 | * FEATURE('c', 'a', 'l', 't'), FEATURE('d', 'l', 'i', 'g') 28 | */ 29 | hb_feature_t features[] = { }; 30 | 31 | void 32 | hbunloadfonts() 33 | { 34 | for (int i = 0; i < hbfontslen; i++) { 35 | hb_font_destroy(hbfontcache[i].font); 36 | XftUnlockFace(hbfontcache[i].match); 37 | } 38 | 39 | if (hbfontcache != NULL) { 40 | free(hbfontcache); 41 | hbfontcache = NULL; 42 | } 43 | hbfontslen = 0; 44 | } 45 | 46 | hb_font_t * 47 | hbfindfont(XftFont *match) 48 | { 49 | for (int i = 0; i < hbfontslen; i++) { 50 | if (hbfontcache[i].match == match) 51 | return hbfontcache[i].font; 52 | } 53 | 54 | /* Font not found in cache, caching it now. */ 55 | hbfontcache = realloc(hbfontcache, sizeof(HbFontMatch) * (hbfontslen + 1)); 56 | FT_Face face = XftLockFace(match); 57 | hb_font_t *font = hb_ft_font_create(face, NULL); 58 | if (font == NULL) 59 | die("Failed to load Harfbuzz font."); 60 | 61 | hbfontcache[hbfontslen].match = match; 62 | hbfontcache[hbfontslen].font = font; 63 | hbfontslen += 1; 64 | 65 | return font; 66 | } 67 | 68 | void hbtransform(HbTransformData *data, XftFont *xfont, const Glyph *glyphs, int start, int length) { 69 | Rune rune; 70 | ushort mode = USHRT_MAX; 71 | unsigned int glyph_count; 72 | int i, end = start + length; 73 | 74 | hb_font_t *font = hbfindfont(xfont); 75 | if (font == NULL) 76 | return; 77 | 78 | hb_buffer_t *buffer = hb_buffer_create(); 79 | hb_buffer_set_direction(buffer, HB_DIRECTION_LTR); 80 | 81 | /* Fill buffer with codepoints. */ 82 | for (i = start; i < end; i++) { 83 | rune = glyphs[i].u; 84 | mode = glyphs[i].mode; 85 | if (mode & ATTR_WDUMMY) 86 | rune = 0x0020; 87 | hb_buffer_add_codepoints(buffer, &rune, 1, 0, 1); 88 | } 89 | 90 | /* Shape the segment. */ 91 | hb_shape(font, buffer, features, sizeof(features)/sizeof(hb_feature_t)); 92 | 93 | /* Get new glyph info. */ 94 | hb_glyph_info_t *info = hb_buffer_get_glyph_infos(buffer, &glyph_count); 95 | hb_glyph_position_t *pos = hb_buffer_get_glyph_positions(buffer, &glyph_count); 96 | 97 | /** Fill the output. */ 98 | data->buffer = buffer; 99 | data->glyphs = info; 100 | data->positions = pos; 101 | data->count = glyph_count; 102 | } 103 | 104 | void hbcleanup(HbTransformData *data) { 105 | hb_buffer_destroy(data->buffer); 106 | memset(data, 0, sizeof(HbTransformData)); 107 | } 108 | -------------------------------------------------------------------------------- /hb.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | typedef struct { 6 | hb_buffer_t *buffer; 7 | hb_glyph_info_t *glyphs; 8 | hb_glyph_position_t *positions; 9 | unsigned int count; 10 | } HbTransformData; 11 | 12 | void hbunloadfonts(); 13 | void hbtransform(HbTransformData *, XftFont *, const Glyph *, int, int); 14 | void hbcleanup(HbTransformData *); 15 | -------------------------------------------------------------------------------- /hb.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motolla/st/80a40a50d86193c9524ca91ae73bba192ad9a9d1/hb.o -------------------------------------------------------------------------------- /patch/st-anysize-20220718-baa9357.diff: -------------------------------------------------------------------------------- 1 | From 8dcdc4b21a73268e167d98aa30f24315c7f3b7ff Mon Sep 17 00:00:00 2001 2 | From: Bakkeby 3 | Date: Mon, 18 Jul 2022 16:52:03 +0200 4 | Subject: [PATCH] Adding anysize patch 5 | 6 | --- 7 | x.c | 56 ++++++++++++++++++++++++++++++-------------------------- 8 | 1 file changed, 30 insertions(+), 26 deletions(-) 9 | 10 | diff --git a/x.c b/x.c 11 | index 2a3bd38..f534347 100644 12 | --- a/x.c 13 | +++ b/x.c 14 | @@ -81,6 +81,7 @@ typedef XftGlyphFontSpec GlyphFontSpec; 15 | typedef struct { 16 | int tw, th; /* tty width and height */ 17 | int w, h; /* window width and height */ 18 | + int hborderpx, vborderpx; 19 | int ch; /* char height */ 20 | int cw; /* char width */ 21 | int mode; /* window state/mode flags */ 22 | @@ -331,7 +332,7 @@ ttysend(const Arg *arg) 23 | int 24 | evcol(XEvent *e) 25 | { 26 | - int x = e->xbutton.x - borderpx; 27 | + int x = e->xbutton.x - win.hborderpx; 28 | LIMIT(x, 0, win.tw - 1); 29 | return x / win.cw; 30 | } 31 | @@ -339,7 +340,7 @@ evcol(XEvent *e) 32 | int 33 | evrow(XEvent *e) 34 | { 35 | - int y = e->xbutton.y - borderpx; 36 | + int y = e->xbutton.y - win.vborderpx; 37 | LIMIT(y, 0, win.th - 1); 38 | return y / win.ch; 39 | } 40 | @@ -739,6 +740,9 @@ cresize(int width, int height) 41 | col = MAX(1, col); 42 | row = MAX(1, row); 43 | 44 | + win.hborderpx = (win.w - col * win.cw) / 2; 45 | + win.vborderpx = (win.h - row * win.ch) / 2; 46 | + 47 | tresize(col, row); 48 | xresize(col, row); 49 | ttyresize(win.tw, win.th); 50 | @@ -869,8 +873,8 @@ xhints(void) 51 | sizeh->flags = PSize | PResizeInc | PBaseSize | PMinSize; 52 | sizeh->height = win.h; 53 | sizeh->width = win.w; 54 | - sizeh->height_inc = win.ch; 55 | - sizeh->width_inc = win.cw; 56 | + sizeh->height_inc = 1; 57 | + sizeh->width_inc = 1; 58 | sizeh->base_height = 2 * borderpx; 59 | sizeh->base_width = 2 * borderpx; 60 | sizeh->min_height = win.ch + 2 * borderpx; 61 | @@ -1152,8 +1156,8 @@ xinit(int cols, int rows) 62 | xloadcols(); 63 | 64 | /* adjust fixed window geometry */ 65 | - win.w = 2 * borderpx + cols * win.cw; 66 | - win.h = 2 * borderpx + rows * win.ch; 67 | + win.w = 2 * win.hborderpx + 2 * borderpx + cols * win.cw; 68 | + win.h = 2 * win.vborderpx + 2 * borderpx + rows * win.ch; 69 | if (xw.gm & XNegative) 70 | xw.l += DisplayWidth(xw.dpy, xw.scr) - win.w - 2; 71 | if (xw.gm & YNegative) 72 | @@ -1242,7 +1246,7 @@ xinit(int cols, int rows) 73 | int 74 | xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y) 75 | { 76 | - float winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, xp, yp; 77 | + float winx = win.hborderpx + x * win.cw, winy = win.vborderpx + y * win.ch, xp, yp; 78 | ushort mode, prevmode = USHRT_MAX; 79 | Font *font = &dc.font; 80 | int frcflags = FRC_NORMAL; 81 | @@ -1375,7 +1379,7 @@ void 82 | xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y) 83 | { 84 | int charlen = len * ((base.mode & ATTR_WIDE) ? 2 : 1); 85 | - int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, 86 | + int winx = win.hborderpx + x * win.cw, winy = win.vborderpx + y * win.ch, 87 | width = charlen * win.cw; 88 | Color *fg, *bg, *temp, revfg, revbg, truefg, truebg; 89 | XRenderColor colfg, colbg; 90 | @@ -1465,17 +1469,17 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i 91 | 92 | /* Intelligent cleaning up of the borders. */ 93 | if (x == 0) { 94 | - xclear(0, (y == 0)? 0 : winy, borderpx, 95 | + xclear(0, (y == 0)? 0 : winy, win.hborderpx, 96 | winy + win.ch + 97 | - ((winy + win.ch >= borderpx + win.th)? win.h : 0)); 98 | + ((winy + win.ch >= win.vborderpx + win.th)? win.h : 0)); 99 | } 100 | - if (winx + width >= borderpx + win.tw) { 101 | + if (winx + width >= win.hborderpx + win.tw) { 102 | xclear(winx + width, (y == 0)? 0 : winy, win.w, 103 | - ((winy + win.ch >= borderpx + win.th)? win.h : (winy + win.ch))); 104 | + ((winy + win.ch >= win.vborderpx + win.th)? win.h : (winy + win.ch))); 105 | } 106 | if (y == 0) 107 | - xclear(winx, 0, winx + width, borderpx); 108 | - if (winy + win.ch >= borderpx + win.th) 109 | + xclear(winx, 0, winx + width, win.vborderpx); 110 | + if (winy + win.ch >= win.vborderpx + win.th) 111 | xclear(winx, winy + win.ch, winx + width, win.h); 112 | 113 | /* Clean up the region we want to draw to. */ 114 | @@ -1569,35 +1573,35 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) 115 | case 3: /* Blinking Underline */ 116 | case 4: /* Steady Underline */ 117 | XftDrawRect(xw.draw, &drawcol, 118 | - borderpx + cx * win.cw, 119 | - borderpx + (cy + 1) * win.ch - \ 120 | + win.hborderpx + cx * win.cw, 121 | + win.vborderpx + (cy + 1) * win.ch - \ 122 | cursorthickness, 123 | win.cw, cursorthickness); 124 | break; 125 | case 5: /* Blinking bar */ 126 | case 6: /* Steady bar */ 127 | XftDrawRect(xw.draw, &drawcol, 128 | - borderpx + cx * win.cw, 129 | - borderpx + cy * win.ch, 130 | + win.hborderpx + cx * win.cw, 131 | + win.vborderpx + cy * win.ch, 132 | cursorthickness, win.ch); 133 | break; 134 | } 135 | } else { 136 | XftDrawRect(xw.draw, &drawcol, 137 | - borderpx + cx * win.cw, 138 | - borderpx + cy * win.ch, 139 | + win.hborderpx + cx * win.cw, 140 | + win.vborderpx + cy * win.ch, 141 | win.cw - 1, 1); 142 | XftDrawRect(xw.draw, &drawcol, 143 | - borderpx + cx * win.cw, 144 | - borderpx + cy * win.ch, 145 | + win.hborderpx + cx * win.cw, 146 | + win.vborderpx + cy * win.ch, 147 | 1, win.ch - 1); 148 | XftDrawRect(xw.draw, &drawcol, 149 | - borderpx + (cx + 1) * win.cw - 1, 150 | - borderpx + cy * win.ch, 151 | + win.hborderpx + (cx + 1) * win.cw - 1, 152 | + win.vborderpx + cy * win.ch, 153 | 1, win.ch - 1); 154 | XftDrawRect(xw.draw, &drawcol, 155 | - borderpx + cx * win.cw, 156 | - borderpx + (cy + 1) * win.ch - 1, 157 | + win.hborderpx + cx * win.cw, 158 | + win.vborderpx + (cy + 1) * win.ch - 1, 159 | win.cw, 1); 160 | } 161 | } 162 | -- 163 | 2.37.1 164 | 165 | -------------------------------------------------------------------------------- /patch/st-boxdraw_v2-0.8.5.diff: -------------------------------------------------------------------------------- 1 | From 46a1124957b8de5e7f827656b64bfc3baeaa097f Mon Sep 17 00:00:00 2001 2 | From: wael <40663@protonmail.com> 3 | Date: Mon, 11 Apr 2022 17:04:30 +0300 4 | Subject: [PATCH] [st][patch][boxdraw] update to 0.8.5 5 | 6 | --- 7 | Makefile | 3 +- 8 | boxdraw.c | 194 ++++++++++++++++++++++++++++++++++++++++++++ 9 | boxdraw_data.h | 214 +++++++++++++++++++++++++++++++++++++++++++++++++ 10 | config.def.h | 12 +++ 11 | st.c | 3 + 12 | st.h | 10 +++ 13 | x.c | 21 +++-- 14 | 7 files changed, 451 insertions(+), 6 deletions(-) 15 | create mode 100644 boxdraw.c 16 | create mode 100644 boxdraw_data.h 17 | 18 | diff --git a/Makefile b/Makefile 19 | index 470ac86..6dfa212 100644 20 | --- a/Makefile 21 | +++ b/Makefile 22 | @@ -4,7 +4,7 @@ 23 | 24 | include config.mk 25 | 26 | -SRC = st.c x.c 27 | +SRC = st.c x.c boxdraw.c 28 | OBJ = $(SRC:.c=.o) 29 | 30 | all: options st 31 | @@ -23,6 +23,7 @@ config.h: 32 | 33 | st.o: config.h st.h win.h 34 | x.o: arg.h config.h st.h win.h 35 | +boxdraw.o: config.h st.h boxdraw_data.h 36 | 37 | $(OBJ): config.h config.mk 38 | 39 | diff --git a/boxdraw.c b/boxdraw.c 40 | new file mode 100644 41 | index 0000000..28a92d0 42 | --- /dev/null 43 | +++ b/boxdraw.c 44 | @@ -0,0 +1,194 @@ 45 | +/* 46 | + * Copyright 2018 Avi Halachmi (:avih) avihpit@yahoo.com https://github.com/avih 47 | + * MIT/X Consortium License 48 | + */ 49 | + 50 | +#include 51 | +#include "st.h" 52 | +#include "boxdraw_data.h" 53 | + 54 | +/* Rounded non-negative integers division of n / d */ 55 | +#define DIV(n, d) (((n) + (d) / 2) / (d)) 56 | + 57 | +static Display *xdpy; 58 | +static Colormap xcmap; 59 | +static XftDraw *xd; 60 | +static Visual *xvis; 61 | + 62 | +static void drawbox(int, int, int, int, XftColor *, XftColor *, ushort); 63 | +static void drawboxlines(int, int, int, int, XftColor *, ushort); 64 | + 65 | +/* public API */ 66 | + 67 | +void 68 | +boxdraw_xinit(Display *dpy, Colormap cmap, XftDraw *draw, Visual *vis) 69 | +{ 70 | + xdpy = dpy; xcmap = cmap; xd = draw, xvis = vis; 71 | +} 72 | + 73 | +int 74 | +isboxdraw(Rune u) 75 | +{ 76 | + Rune block = u & ~0xff; 77 | + return (boxdraw && block == 0x2500 && boxdata[(uint8_t)u]) || 78 | + (boxdraw_braille && block == 0x2800); 79 | +} 80 | + 81 | +/* the "index" is actually the entire shape data encoded as ushort */ 82 | +ushort 83 | +boxdrawindex(const Glyph *g) 84 | +{ 85 | + if (boxdraw_braille && (g->u & ~0xff) == 0x2800) 86 | + return BRL | (uint8_t)g->u; 87 | + if (boxdraw_bold && (g->mode & ATTR_BOLD)) 88 | + return BDB | boxdata[(uint8_t)g->u]; 89 | + return boxdata[(uint8_t)g->u]; 90 | +} 91 | + 92 | +void 93 | +drawboxes(int x, int y, int cw, int ch, XftColor *fg, XftColor *bg, 94 | + const XftGlyphFontSpec *specs, int len) 95 | +{ 96 | + for ( ; len-- > 0; x += cw, specs++) 97 | + drawbox(x, y, cw, ch, fg, bg, (ushort)specs->glyph); 98 | +} 99 | + 100 | +/* implementation */ 101 | + 102 | +void 103 | +drawbox(int x, int y, int w, int h, XftColor *fg, XftColor *bg, ushort bd) 104 | +{ 105 | + ushort cat = bd & ~(BDB | 0xff); /* mask out bold and data */ 106 | + if (bd & (BDL | BDA)) { 107 | + /* lines (light/double/heavy/arcs) */ 108 | + drawboxlines(x, y, w, h, fg, bd); 109 | + 110 | + } else if (cat == BBD) { 111 | + /* lower (8-X)/8 block */ 112 | + int d = DIV((uint8_t)bd * h, 8); 113 | + XftDrawRect(xd, fg, x, y + d, w, h - d); 114 | + 115 | + } else if (cat == BBU) { 116 | + /* upper X/8 block */ 117 | + XftDrawRect(xd, fg, x, y, w, DIV((uint8_t)bd * h, 8)); 118 | + 119 | + } else if (cat == BBL) { 120 | + /* left X/8 block */ 121 | + XftDrawRect(xd, fg, x, y, DIV((uint8_t)bd * w, 8), h); 122 | + 123 | + } else if (cat == BBR) { 124 | + /* right (8-X)/8 block */ 125 | + int d = DIV((uint8_t)bd * w, 8); 126 | + XftDrawRect(xd, fg, x + d, y, w - d, h); 127 | + 128 | + } else if (cat == BBQ) { 129 | + /* Quadrants */ 130 | + int w2 = DIV(w, 2), h2 = DIV(h, 2); 131 | + if (bd & TL) 132 | + XftDrawRect(xd, fg, x, y, w2, h2); 133 | + if (bd & TR) 134 | + XftDrawRect(xd, fg, x + w2, y, w - w2, h2); 135 | + if (bd & BL) 136 | + XftDrawRect(xd, fg, x, y + h2, w2, h - h2); 137 | + if (bd & BR) 138 | + XftDrawRect(xd, fg, x + w2, y + h2, w - w2, h - h2); 139 | + 140 | + } else if (bd & BBS) { 141 | + /* Shades - data is 1/2/3 for 25%/50%/75% alpha, respectively */ 142 | + int d = (uint8_t)bd; 143 | + XftColor xfc; 144 | + XRenderColor xrc = { .alpha = 0xffff }; 145 | + 146 | + xrc.red = DIV(fg->color.red * d + bg->color.red * (4 - d), 4); 147 | + xrc.green = DIV(fg->color.green * d + bg->color.green * (4 - d), 4); 148 | + xrc.blue = DIV(fg->color.blue * d + bg->color.blue * (4 - d), 4); 149 | + 150 | + XftColorAllocValue(xdpy, xvis, xcmap, &xrc, &xfc); 151 | + XftDrawRect(xd, &xfc, x, y, w, h); 152 | + XftColorFree(xdpy, xvis, xcmap, &xfc); 153 | + 154 | + } else if (cat == BRL) { 155 | + /* braille, each data bit corresponds to one dot at 2x4 grid */ 156 | + int w1 = DIV(w, 2); 157 | + int h1 = DIV(h, 4), h2 = DIV(h, 2), h3 = DIV(3 * h, 4); 158 | + 159 | + if (bd & 1) XftDrawRect(xd, fg, x, y, w1, h1); 160 | + if (bd & 2) XftDrawRect(xd, fg, x, y + h1, w1, h2 - h1); 161 | + if (bd & 4) XftDrawRect(xd, fg, x, y + h2, w1, h3 - h2); 162 | + if (bd & 8) XftDrawRect(xd, fg, x + w1, y, w - w1, h1); 163 | + if (bd & 16) XftDrawRect(xd, fg, x + w1, y + h1, w - w1, h2 - h1); 164 | + if (bd & 32) XftDrawRect(xd, fg, x + w1, y + h2, w - w1, h3 - h2); 165 | + if (bd & 64) XftDrawRect(xd, fg, x, y + h3, w1, h - h3); 166 | + if (bd & 128) XftDrawRect(xd, fg, x + w1, y + h3, w - w1, h - h3); 167 | + 168 | + } 169 | +} 170 | + 171 | +void 172 | +drawboxlines(int x, int y, int w, int h, XftColor *fg, ushort bd) 173 | +{ 174 | + /* s: stem thickness. width/8 roughly matches underscore thickness. */ 175 | + /* We draw bold as 1.5 * normal-stem and at least 1px thicker. */ 176 | + /* doubles draw at least 3px, even when w or h < 3. bold needs 6px. */ 177 | + int mwh = MIN(w, h); 178 | + int base_s = MAX(1, DIV(mwh, 8)); 179 | + int bold = (bd & BDB) && mwh >= 6; /* possibly ignore boldness */ 180 | + int s = bold ? MAX(base_s + 1, DIV(3 * base_s, 2)) : base_s; 181 | + int w2 = DIV(w - s, 2), h2 = DIV(h - s, 2); 182 | + /* the s-by-s square (x + w2, y + h2, s, s) is the center texel. */ 183 | + /* The base length (per direction till edge) includes this square. */ 184 | + 185 | + int light = bd & (LL | LU | LR | LD); 186 | + int double_ = bd & (DL | DU | DR | DD); 187 | + 188 | + if (light) { 189 | + /* d: additional (negative) length to not-draw the center */ 190 | + /* texel - at arcs and avoid drawing inside (some) doubles */ 191 | + int arc = bd & BDA; 192 | + int multi_light = light & (light - 1); 193 | + int multi_double = double_ & (double_ - 1); 194 | + /* light crosses double only at DH+LV, DV+LH (ref. shapes) */ 195 | + int d = arc || (multi_double && !multi_light) ? -s : 0; 196 | + 197 | + if (bd & LL) 198 | + XftDrawRect(xd, fg, x, y + h2, w2 + s + d, s); 199 | + if (bd & LU) 200 | + XftDrawRect(xd, fg, x + w2, y, s, h2 + s + d); 201 | + if (bd & LR) 202 | + XftDrawRect(xd, fg, x + w2 - d, y + h2, w - w2 + d, s); 203 | + if (bd & LD) 204 | + XftDrawRect(xd, fg, x + w2, y + h2 - d, s, h - h2 + d); 205 | + } 206 | + 207 | + /* double lines - also align with light to form heavy when combined */ 208 | + if (double_) { 209 | + /* 210 | + * going clockwise, for each double-ray: p is additional length 211 | + * to the single-ray nearer to the previous direction, and n to 212 | + * the next. p and n adjust from the base length to lengths 213 | + * which consider other doubles - shorter to avoid intersections 214 | + * (p, n), or longer to draw the far-corner texel (n). 215 | + */ 216 | + int dl = bd & DL, du = bd & DU, dr = bd & DR, dd = bd & DD; 217 | + if (dl) { 218 | + int p = dd ? -s : 0, n = du ? -s : dd ? s : 0; 219 | + XftDrawRect(xd, fg, x, y + h2 + s, w2 + s + p, s); 220 | + XftDrawRect(xd, fg, x, y + h2 - s, w2 + s + n, s); 221 | + } 222 | + if (du) { 223 | + int p = dl ? -s : 0, n = dr ? -s : dl ? s : 0; 224 | + XftDrawRect(xd, fg, x + w2 - s, y, s, h2 + s + p); 225 | + XftDrawRect(xd, fg, x + w2 + s, y, s, h2 + s + n); 226 | + } 227 | + if (dr) { 228 | + int p = du ? -s : 0, n = dd ? -s : du ? s : 0; 229 | + XftDrawRect(xd, fg, x + w2 - p, y + h2 - s, w - w2 + p, s); 230 | + XftDrawRect(xd, fg, x + w2 - n, y + h2 + s, w - w2 + n, s); 231 | + } 232 | + if (dd) { 233 | + int p = dr ? -s : 0, n = dl ? -s : dr ? s : 0; 234 | + XftDrawRect(xd, fg, x + w2 + s, y + h2 - p, s, h - h2 + p); 235 | + XftDrawRect(xd, fg, x + w2 - s, y + h2 - n, s, h - h2 + n); 236 | + } 237 | + } 238 | +} 239 | diff --git a/boxdraw_data.h b/boxdraw_data.h 240 | new file mode 100644 241 | index 0000000..7890500 242 | --- /dev/null 243 | +++ b/boxdraw_data.h 244 | @@ -0,0 +1,214 @@ 245 | +/* 246 | + * Copyright 2018 Avi Halachmi (:avih) avihpit@yahoo.com https://github.com/avih 247 | + * MIT/X Consortium License 248 | + */ 249 | + 250 | +/* 251 | + * U+25XX codepoints data 252 | + * 253 | + * References: 254 | + * http://www.unicode.org/charts/PDF/U2500.pdf 255 | + * http://www.unicode.org/charts/PDF/U2580.pdf 256 | + * 257 | + * Test page: 258 | + * https://github.com/GNOME/vte/blob/master/doc/boxes.txt 259 | + */ 260 | + 261 | +/* Each shape is encoded as 16-bits. Higher bits are category, lower are data */ 262 | +/* Categories (mutually exclusive except BDB): */ 263 | +/* For convenience, BDL/BDA/BBS/BDB are 1 bit each, the rest are enums */ 264 | +#define BDL (1<<8) /* Box Draw Lines (light/double/heavy) */ 265 | +#define BDA (1<<9) /* Box Draw Arc (light) */ 266 | + 267 | +#define BBD (1<<10) /* Box Block Down (lower) X/8 */ 268 | +#define BBL (2<<10) /* Box Block Left X/8 */ 269 | +#define BBU (3<<10) /* Box Block Upper X/8 */ 270 | +#define BBR (4<<10) /* Box Block Right X/8 */ 271 | +#define BBQ (5<<10) /* Box Block Quadrants */ 272 | +#define BRL (6<<10) /* Box Braille (data is lower byte of U28XX) */ 273 | + 274 | +#define BBS (1<<14) /* Box Block Shades */ 275 | +#define BDB (1<<15) /* Box Draw is Bold */ 276 | + 277 | +/* (BDL/BDA) Light/Double/Heavy x Left/Up/Right/Down/Horizontal/Vertical */ 278 | +/* Heavy is light+double (literally drawing light+double align to form heavy) */ 279 | +#define LL (1<<0) 280 | +#define LU (1<<1) 281 | +#define LR (1<<2) 282 | +#define LD (1<<3) 283 | +#define LH (LL+LR) 284 | +#define LV (LU+LD) 285 | + 286 | +#define DL (1<<4) 287 | +#define DU (1<<5) 288 | +#define DR (1<<6) 289 | +#define DD (1<<7) 290 | +#define DH (DL+DR) 291 | +#define DV (DU+DD) 292 | + 293 | +#define HL (LL+DL) 294 | +#define HU (LU+DU) 295 | +#define HR (LR+DR) 296 | +#define HD (LD+DD) 297 | +#define HH (HL+HR) 298 | +#define HV (HU+HD) 299 | + 300 | +/* (BBQ) Quadrants Top/Bottom x Left/Right */ 301 | +#define TL (1<<0) 302 | +#define TR (1<<1) 303 | +#define BL (1<<2) 304 | +#define BR (1<<3) 305 | + 306 | +/* Data for U+2500 - U+259F except dashes/diagonals */ 307 | +static const unsigned short boxdata[256] = { 308 | + /* light lines */ 309 | + [0x00] = BDL + LH, /* light horizontal */ 310 | + [0x02] = BDL + LV, /* light vertical */ 311 | + [0x0c] = BDL + LD + LR, /* light down and right */ 312 | + [0x10] = BDL + LD + LL, /* light down and left */ 313 | + [0x14] = BDL + LU + LR, /* light up and right */ 314 | + [0x18] = BDL + LU + LL, /* light up and left */ 315 | + [0x1c] = BDL + LV + LR, /* light vertical and right */ 316 | + [0x24] = BDL + LV + LL, /* light vertical and left */ 317 | + [0x2c] = BDL + LH + LD, /* light horizontal and down */ 318 | + [0x34] = BDL + LH + LU, /* light horizontal and up */ 319 | + [0x3c] = BDL + LV + LH, /* light vertical and horizontal */ 320 | + [0x74] = BDL + LL, /* light left */ 321 | + [0x75] = BDL + LU, /* light up */ 322 | + [0x76] = BDL + LR, /* light right */ 323 | + [0x77] = BDL + LD, /* light down */ 324 | + 325 | + /* heavy [+light] lines */ 326 | + [0x01] = BDL + HH, 327 | + [0x03] = BDL + HV, 328 | + [0x0d] = BDL + HR + LD, 329 | + [0x0e] = BDL + HD + LR, 330 | + [0x0f] = BDL + HD + HR, 331 | + [0x11] = BDL + HL + LD, 332 | + [0x12] = BDL + HD + LL, 333 | + [0x13] = BDL + HD + HL, 334 | + [0x15] = BDL + HR + LU, 335 | + [0x16] = BDL + HU + LR, 336 | + [0x17] = BDL + HU + HR, 337 | + [0x19] = BDL + HL + LU, 338 | + [0x1a] = BDL + HU + LL, 339 | + [0x1b] = BDL + HU + HL, 340 | + [0x1d] = BDL + HR + LV, 341 | + [0x1e] = BDL + HU + LD + LR, 342 | + [0x1f] = BDL + HD + LR + LU, 343 | + [0x20] = BDL + HV + LR, 344 | + [0x21] = BDL + HU + HR + LD, 345 | + [0x22] = BDL + HD + HR + LU, 346 | + [0x23] = BDL + HV + HR, 347 | + [0x25] = BDL + HL + LV, 348 | + [0x26] = BDL + HU + LD + LL, 349 | + [0x27] = BDL + HD + LU + LL, 350 | + [0x28] = BDL + HV + LL, 351 | + [0x29] = BDL + HU + HL + LD, 352 | + [0x2a] = BDL + HD + HL + LU, 353 | + [0x2b] = BDL + HV + HL, 354 | + [0x2d] = BDL + HL + LD + LR, 355 | + [0x2e] = BDL + HR + LL + LD, 356 | + [0x2f] = BDL + HH + LD, 357 | + [0x30] = BDL + HD + LH, 358 | + [0x31] = BDL + HD + HL + LR, 359 | + [0x32] = BDL + HR + HD + LL, 360 | + [0x33] = BDL + HH + HD, 361 | + [0x35] = BDL + HL + LU + LR, 362 | + [0x36] = BDL + HR + LU + LL, 363 | + [0x37] = BDL + HH + LU, 364 | + [0x38] = BDL + HU + LH, 365 | + [0x39] = BDL + HU + HL + LR, 366 | + [0x3a] = BDL + HU + HR + LL, 367 | + [0x3b] = BDL + HH + HU, 368 | + [0x3d] = BDL + HL + LV + LR, 369 | + [0x3e] = BDL + HR + LV + LL, 370 | + [0x3f] = BDL + HH + LV, 371 | + [0x40] = BDL + HU + LH + LD, 372 | + [0x41] = BDL + HD + LH + LU, 373 | + [0x42] = BDL + HV + LH, 374 | + [0x43] = BDL + HU + HL + LD + LR, 375 | + [0x44] = BDL + HU + HR + LD + LL, 376 | + [0x45] = BDL + HD + HL + LU + LR, 377 | + [0x46] = BDL + HD + HR + LU + LL, 378 | + [0x47] = BDL + HH + HU + LD, 379 | + [0x48] = BDL + HH + HD + LU, 380 | + [0x49] = BDL + HV + HL + LR, 381 | + [0x4a] = BDL + HV + HR + LL, 382 | + [0x4b] = BDL + HV + HH, 383 | + [0x78] = BDL + HL, 384 | + [0x79] = BDL + HU, 385 | + [0x7a] = BDL + HR, 386 | + [0x7b] = BDL + HD, 387 | + [0x7c] = BDL + HR + LL, 388 | + [0x7d] = BDL + HD + LU, 389 | + [0x7e] = BDL + HL + LR, 390 | + [0x7f] = BDL + HU + LD, 391 | + 392 | + /* double [+light] lines */ 393 | + [0x50] = BDL + DH, 394 | + [0x51] = BDL + DV, 395 | + [0x52] = BDL + DR + LD, 396 | + [0x53] = BDL + DD + LR, 397 | + [0x54] = BDL + DR + DD, 398 | + [0x55] = BDL + DL + LD, 399 | + [0x56] = BDL + DD + LL, 400 | + [0x57] = BDL + DL + DD, 401 | + [0x58] = BDL + DR + LU, 402 | + [0x59] = BDL + DU + LR, 403 | + [0x5a] = BDL + DU + DR, 404 | + [0x5b] = BDL + DL + LU, 405 | + [0x5c] = BDL + DU + LL, 406 | + [0x5d] = BDL + DL + DU, 407 | + [0x5e] = BDL + DR + LV, 408 | + [0x5f] = BDL + DV + LR, 409 | + [0x60] = BDL + DV + DR, 410 | + [0x61] = BDL + DL + LV, 411 | + [0x62] = BDL + DV + LL, 412 | + [0x63] = BDL + DV + DL, 413 | + [0x64] = BDL + DH + LD, 414 | + [0x65] = BDL + DD + LH, 415 | + [0x66] = BDL + DD + DH, 416 | + [0x67] = BDL + DH + LU, 417 | + [0x68] = BDL + DU + LH, 418 | + [0x69] = BDL + DH + DU, 419 | + [0x6a] = BDL + DH + LV, 420 | + [0x6b] = BDL + DV + LH, 421 | + [0x6c] = BDL + DH + DV, 422 | + 423 | + /* (light) arcs */ 424 | + [0x6d] = BDA + LD + LR, 425 | + [0x6e] = BDA + LD + LL, 426 | + [0x6f] = BDA + LU + LL, 427 | + [0x70] = BDA + LU + LR, 428 | + 429 | + /* Lower (Down) X/8 block (data is 8 - X) */ 430 | + [0x81] = BBD + 7, [0x82] = BBD + 6, [0x83] = BBD + 5, [0x84] = BBD + 4, 431 | + [0x85] = BBD + 3, [0x86] = BBD + 2, [0x87] = BBD + 1, [0x88] = BBD + 0, 432 | + 433 | + /* Left X/8 block (data is X) */ 434 | + [0x89] = BBL + 7, [0x8a] = BBL + 6, [0x8b] = BBL + 5, [0x8c] = BBL + 4, 435 | + [0x8d] = BBL + 3, [0x8e] = BBL + 2, [0x8f] = BBL + 1, 436 | + 437 | + /* upper 1/2 (4/8), 1/8 block (X), right 1/2, 1/8 block (8-X) */ 438 | + [0x80] = BBU + 4, [0x94] = BBU + 1, 439 | + [0x90] = BBR + 4, [0x95] = BBR + 7, 440 | + 441 | + /* Quadrants */ 442 | + [0x96] = BBQ + BL, 443 | + [0x97] = BBQ + BR, 444 | + [0x98] = BBQ + TL, 445 | + [0x99] = BBQ + TL + BL + BR, 446 | + [0x9a] = BBQ + TL + BR, 447 | + [0x9b] = BBQ + TL + TR + BL, 448 | + [0x9c] = BBQ + TL + TR + BR, 449 | + [0x9d] = BBQ + TR, 450 | + [0x9e] = BBQ + BL + TR, 451 | + [0x9f] = BBQ + BL + TR + BR, 452 | + 453 | + /* Shades, data is an alpha value in 25% units (1/4, 1/2, 3/4) */ 454 | + [0x91] = BBS + 1, [0x92] = BBS + 2, [0x93] = BBS + 3, 455 | + 456 | + /* U+2504 - U+250B, U+254C - U+254F: unsupported (dashes) */ 457 | + /* U+2571 - U+2573: unsupported (diagonals) */ 458 | +}; 459 | diff --git a/config.def.h b/config.def.h 460 | index 91ab8ca..7bb3ff7 100644 461 | --- a/config.def.h 462 | +++ b/config.def.h 463 | @@ -67,6 +67,18 @@ static unsigned int blinktimeout = 800; 464 | */ 465 | static unsigned int cursorthickness = 2; 466 | 467 | +/* 468 | + * 1: render most of the lines/blocks characters without using the font for 469 | + * perfect alignment between cells (U2500 - U259F except dashes/diagonals). 470 | + * Bold affects lines thickness if boxdraw_bold is not 0. Italic is ignored. 471 | + * 0: disable (render all U25XX glyphs normally from the font). 472 | + */ 473 | +const int boxdraw = 0; 474 | +const int boxdraw_bold = 0; 475 | + 476 | +/* braille (U28XX): 1: render as adjacent "pixels", 0: use font */ 477 | +const int boxdraw_braille = 0; 478 | + 479 | /* 480 | * bell volume. It must be a value between -100 and 100. Use 0 for disabling 481 | * it 482 | diff --git a/st.c b/st.c 483 | index f43cfd3..baa2bed 100644 484 | --- a/st.c 485 | +++ b/st.c 486 | @@ -1214,6 +1214,9 @@ tsetchar(Rune u, const Glyph *attr, int x, int y) 487 | term.dirty[y] = 1; 488 | term.line[y][x] = *attr; 489 | term.line[y][x].u = u; 490 | + 491 | + if (isboxdraw(u)) 492 | + term.line[y][x].mode |= ATTR_BOXDRAW; 493 | } 494 | 495 | void 496 | diff --git a/st.h b/st.h 497 | index 519b9bd..07a7c66 100644 498 | --- a/st.h 499 | +++ b/st.h 500 | @@ -33,6 +33,7 @@ enum glyph_attribute { 501 | ATTR_WRAP = 1 << 8, 502 | ATTR_WIDE = 1 << 9, 503 | ATTR_WDUMMY = 1 << 10, 504 | + ATTR_BOXDRAW = 1 << 11, 505 | ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT, 506 | }; 507 | 508 | @@ -113,6 +114,14 @@ char *xstrdup(const char *); 509 | 510 | int xgetcolor(int x, unsigned char *r, unsigned char *g, unsigned char *b); 511 | 512 | +int isboxdraw(Rune); 513 | +ushort boxdrawindex(const Glyph *); 514 | +#ifdef XFT_VERSION 515 | +/* only exposed to x.c, otherwise we'll need Xft.h for the types */ 516 | +void boxdraw_xinit(Display *, Colormap, XftDraw *, Visual *); 517 | +void drawboxes(int, int, int, int, XftColor *, XftColor *, const XftGlyphFontSpec *, int); 518 | +#endif 519 | + 520 | /* config.h globals */ 521 | extern char *utmp; 522 | extern char *scroll; 523 | @@ -126,3 +135,4 @@ extern unsigned int tabspaces; 524 | extern unsigned int defaultfg; 525 | extern unsigned int defaultbg; 526 | extern unsigned int defaultcs; 527 | +extern const int boxdraw, boxdraw_bold, boxdraw_braille; 528 | diff --git a/x.c b/x.c 529 | index 2a3bd38..bf6bbf9 100644 530 | --- a/x.c 531 | +++ b/x.c 532 | @@ -1237,6 +1237,8 @@ xinit(int cols, int rows) 533 | xsel.xtarget = XInternAtom(xw.dpy, "UTF8_STRING", 0); 534 | if (xsel.xtarget == None) 535 | xsel.xtarget = XA_STRING; 536 | + 537 | + boxdraw_xinit(xw.dpy, xw.cmap, xw.draw, xw.vis); 538 | } 539 | 540 | int 541 | @@ -1283,8 +1285,13 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x 542 | yp = winy + font->ascent; 543 | } 544 | 545 | - /* Lookup character index with default font. */ 546 | - glyphidx = XftCharIndex(xw.dpy, font->match, rune); 547 | + if (mode & ATTR_BOXDRAW) { 548 | + /* minor shoehorning: boxdraw uses only this ushort */ 549 | + glyphidx = boxdrawindex(&glyphs[i]); 550 | + } else { 551 | + /* Lookup character index with default font. */ 552 | + glyphidx = XftCharIndex(xw.dpy, font->match, rune); 553 | + } 554 | if (glyphidx) { 555 | specs[numspecs].font = font->match; 556 | specs[numspecs].glyph = glyphidx; 557 | @@ -1488,8 +1495,12 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i 558 | r.width = width; 559 | XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1); 560 | 561 | - /* Render the glyphs. */ 562 | - XftDrawGlyphFontSpec(xw.draw, fg, specs, len); 563 | + if (base.mode & ATTR_BOXDRAW) { 564 | + drawboxes(winx, winy, width / len, win.ch, fg, bg, specs, len); 565 | + } else { 566 | + /* Render the glyphs. */ 567 | + XftDrawGlyphFontSpec(xw.draw, fg, specs, len); 568 | + } 569 | 570 | /* Render underline and strikethrough. */ 571 | if (base.mode & ATTR_UNDERLINE) { 572 | @@ -1532,7 +1543,7 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) 573 | /* 574 | * Select the right color for the right mode. 575 | */ 576 | - g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE; 577 | + g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE|ATTR_BOXDRAW; 578 | 579 | if (IS_SET(MODE_REVERSE)) { 580 | g.mode |= ATTR_REVERSE; 581 | -- 582 | 2.35.1 583 | 584 | -------------------------------------------------------------------------------- /patch/st-font2-0.8.5.diff: -------------------------------------------------------------------------------- 1 | From 1635e04d3643dd4caa0c7c2043b585c6d7e4705f Mon Sep 17 00:00:00 2001 2 | From: Rizqi Nur Assyaufi 3 | Date: Mon, 18 Jul 2022 01:15:45 +0800 4 | Subject: [PATCH] [st][patch][font2] Add patch for st-0.8.5 5 | 6 | --- 7 | config.def.h | 6 +++ 8 | x.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++ 9 | 2 files changed, 107 insertions(+) 10 | 11 | diff --git a/config.def.h b/config.def.h 12 | index 91ab8ca..717b2f0 100644 13 | --- a/config.def.h 14 | +++ b/config.def.h 15 | @@ -6,6 +6,12 @@ 16 | * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html 17 | */ 18 | static char *font = "Liberation Mono:pixelsize=12:antialias=true:autohint=true"; 19 | +/* Spare fonts */ 20 | +static char *font2[] = { 21 | +/* "Inconsolata for Powerline:pixelsize=12:antialias=true:autohint=true", */ 22 | +/* "Hack Nerd Font Mono:pixelsize=11:antialias=true:autohint=true", */ 23 | +}; 24 | + 25 | static int borderpx = 2; 26 | 27 | /* 28 | diff --git a/x.c b/x.c 29 | index 8a16faa..220fc4f 100644 30 | --- a/x.c 31 | +++ b/x.c 32 | @@ -157,6 +157,8 @@ static void xhints(void); 33 | static int xloadcolor(int, const char *, Color *); 34 | static int xloadfont(Font *, FcPattern *); 35 | static void xloadfonts(const char *, double); 36 | +static int xloadsparefont(FcPattern *, int); 37 | +static void xloadsparefonts(void); 38 | static void xunloadfont(Font *); 39 | static void xunloadfonts(void); 40 | static void xsetenv(void); 41 | @@ -306,6 +308,7 @@ zoomabs(const Arg *arg) 42 | { 43 | xunloadfonts(); 44 | xloadfonts(usedfont, arg->f); 45 | + xloadsparefonts(); 46 | cresize(0, 0); 47 | redraw(); 48 | xhints(); 49 | @@ -1034,6 +1037,101 @@ xloadfonts(const char *fontstr, double fontsize) 50 | FcPatternDestroy(pattern); 51 | } 52 | 53 | +int 54 | +xloadsparefont(FcPattern *pattern, int flags) 55 | +{ 56 | + FcPattern *match; 57 | + FcResult result; 58 | + 59 | + match = FcFontMatch(NULL, pattern, &result); 60 | + if (!match) { 61 | + return 1; 62 | + } 63 | + 64 | + if (!(frc[frclen].font = XftFontOpenPattern(xw.dpy, match))) { 65 | + FcPatternDestroy(match); 66 | + return 1; 67 | + } 68 | + 69 | + frc[frclen].flags = flags; 70 | + /* Believe U+0000 glyph will present in each default font */ 71 | + frc[frclen].unicodep = 0; 72 | + frclen++; 73 | + 74 | + return 0; 75 | +} 76 | + 77 | +void 78 | +xloadsparefonts(void) 79 | +{ 80 | + FcPattern *pattern; 81 | + double sizeshift, fontval; 82 | + int fc; 83 | + char **fp; 84 | + 85 | + if (frclen != 0) 86 | + die("can't embed spare fonts. cache isn't empty"); 87 | + 88 | + /* Calculate count of spare fonts */ 89 | + fc = sizeof(font2) / sizeof(*font2); 90 | + if (fc == 0) 91 | + return; 92 | + 93 | + /* Allocate memory for cache entries. */ 94 | + if (frccap < 4 * fc) { 95 | + frccap += 4 * fc - frccap; 96 | + frc = xrealloc(frc, frccap * sizeof(Fontcache)); 97 | + } 98 | + 99 | + for (fp = font2; fp - font2 < fc; ++fp) { 100 | + 101 | + if (**fp == '-') 102 | + pattern = XftXlfdParse(*fp, False, False); 103 | + else 104 | + pattern = FcNameParse((FcChar8 *)*fp); 105 | + 106 | + if (!pattern) 107 | + die("can't open spare font %s\n", *fp); 108 | + 109 | + if (defaultfontsize > 0) { 110 | + sizeshift = usedfontsize - defaultfontsize; 111 | + if (sizeshift != 0 && 112 | + FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &fontval) == 113 | + FcResultMatch) { 114 | + fontval += sizeshift; 115 | + FcPatternDel(pattern, FC_PIXEL_SIZE); 116 | + FcPatternDel(pattern, FC_SIZE); 117 | + FcPatternAddDouble(pattern, FC_PIXEL_SIZE, fontval); 118 | + } 119 | + } 120 | + 121 | + FcPatternAddBool(pattern, FC_SCALABLE, 1); 122 | + 123 | + FcConfigSubstitute(NULL, pattern, FcMatchPattern); 124 | + XftDefaultSubstitute(xw.dpy, xw.scr, pattern); 125 | + 126 | + if (xloadsparefont(pattern, FRC_NORMAL)) 127 | + die("can't open spare font %s\n", *fp); 128 | + 129 | + FcPatternDel(pattern, FC_SLANT); 130 | + FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); 131 | + if (xloadsparefont(pattern, FRC_ITALIC)) 132 | + die("can't open spare font %s\n", *fp); 133 | + 134 | + FcPatternDel(pattern, FC_WEIGHT); 135 | + FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); 136 | + if (xloadsparefont(pattern, FRC_ITALICBOLD)) 137 | + die("can't open spare font %s\n", *fp); 138 | + 139 | + FcPatternDel(pattern, FC_SLANT); 140 | + FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN); 141 | + if (xloadsparefont(pattern, FRC_BOLD)) 142 | + die("can't open spare font %s\n", *fp); 143 | + 144 | + FcPatternDestroy(pattern); 145 | + } 146 | +} 147 | + 148 | void 149 | xunloadfont(Font *f) 150 | { 151 | @@ -1131,6 +1229,9 @@ xinit(int cols, int rows) 152 | usedfont = (opt_font == NULL)? font : opt_font; 153 | xloadfonts(usedfont, 0); 154 | 155 | + /* spare fonts */ 156 | + xloadsparefonts(); 157 | + 158 | /* colors */ 159 | xw.cmap = XDefaultColormap(xw.dpy, xw.scr); 160 | xloadcols(); 161 | -- 162 | 2.37.1 163 | 164 | -------------------------------------------------------------------------------- /patch/st-glyph-wide-support-boxdraw-20220411-ef05519.diff: -------------------------------------------------------------------------------- 1 | From 9583955da47177c9557210f70baaaf9511ba106c Mon Sep 17 00:00:00 2001 2 | From: wael <40663@protonmail.com> 3 | Date: Mon, 11 Apr 2022 17:14:06 +0300 4 | Subject: [PATCH] boxdraw support for glyph wide support 5 | 6 | --- 7 | st.h | 6 +++ 8 | x.c | 139 ++++++++++++++++++++++++++++++----------------------------- 9 | 2 files changed, 76 insertions(+), 69 deletions(-) 10 | 11 | diff --git a/st.h b/st.h 12 | index 07a7c66..3b8c97d 100644 13 | --- a/st.h 14 | +++ b/st.h 15 | @@ -37,6 +37,12 @@ enum glyph_attribute { 16 | ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT, 17 | }; 18 | 19 | +enum drawing_mode { 20 | + DRAW_NONE = 0, 21 | + DRAW_BG = 1 << 0, 22 | + DRAW_FG = 1 << 1, 23 | +}; 24 | + 25 | enum selection_mode { 26 | SEL_IDLE = 0, 27 | SEL_EMPTY = 1, 28 | diff --git a/x.c b/x.c 29 | index bf6bbf9..1311c0d 100644 30 | --- a/x.c 31 | +++ b/x.c 32 | @@ -142,7 +142,7 @@ typedef struct { 33 | 34 | static inline ushort sixd_to_16bit(int); 35 | static int xmakeglyphfontspecs(XftGlyphFontSpec *, const Glyph *, int, int, int); 36 | -static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int); 37 | +static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int, int); 38 | static void xdrawglyph(Glyph, int, int); 39 | static void xclear(int, int, int, int); 40 | static int xgeommasktogravity(int); 41 | @@ -1379,7 +1379,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x 42 | } 43 | 44 | void 45 | -xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y) 46 | +xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y, int dmode) 47 | { 48 | int charlen = len * ((base.mode & ATTR_WIDE) ? 2 : 1); 49 | int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, 50 | @@ -1470,51 +1470,45 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i 51 | if (base.mode & ATTR_INVISIBLE) 52 | fg = bg; 53 | 54 | - /* Intelligent cleaning up of the borders. */ 55 | - if (x == 0) { 56 | - xclear(0, (y == 0)? 0 : winy, borderpx, 57 | - winy + win.ch + 58 | - ((winy + win.ch >= borderpx + win.th)? win.h : 0)); 59 | - } 60 | - if (winx + width >= borderpx + win.tw) { 61 | - xclear(winx + width, (y == 0)? 0 : winy, win.w, 62 | - ((winy + win.ch >= borderpx + win.th)? win.h : (winy + win.ch))); 63 | - } 64 | - if (y == 0) 65 | - xclear(winx, 0, winx + width, borderpx); 66 | - if (winy + win.ch >= borderpx + win.th) 67 | - xclear(winx, winy + win.ch, winx + width, win.h); 68 | - 69 | - /* Clean up the region we want to draw to. */ 70 | - XftDrawRect(xw.draw, bg, winx, winy, width, win.ch); 71 | - 72 | - /* Set the clip region because Xft is sometimes dirty. */ 73 | - r.x = 0; 74 | - r.y = 0; 75 | - r.height = win.ch; 76 | - r.width = width; 77 | - XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1); 78 | - 79 | - if (base.mode & ATTR_BOXDRAW) { 80 | - drawboxes(winx, winy, width / len, win.ch, fg, bg, specs, len); 81 | - } else { 82 | - /* Render the glyphs. */ 83 | - XftDrawGlyphFontSpec(xw.draw, fg, specs, len); 84 | - } 85 | + if (dmode & DRAW_BG) { 86 | + /* Intelligent cleaning up of the borders. */ 87 | + if (x == 0) { 88 | + xclear(0, (y == 0)? 0 : winy, borderpx, 89 | + winy + win.ch + 90 | + ((winy + win.ch >= borderpx + win.th)? win.h : 0)); 91 | + } 92 | + if (winx + width >= borderpx + win.tw) { 93 | + xclear(winx + width, (y == 0)? 0 : winy, win.w, 94 | + ((winy + win.ch >= borderpx + win.th)? win.h : (winy + win.ch))); 95 | + } 96 | + if (y == 0) 97 | + xclear(winx, 0, winx + width, borderpx); 98 | + if (winy + win.ch >= borderpx + win.th) 99 | + xclear(winx, winy + win.ch, winx + width, win.h); 100 | + /* Fill the background */ 101 | + XftDrawRect(xw.draw, bg, winx, winy, width, win.ch); 102 | + } 103 | + 104 | + 105 | + if (dmode & DRAW_FG) { 106 | + if (base.mode & ATTR_BOXDRAW) { 107 | + drawboxes(winx, winy, width / len, win.ch, fg, bg, specs, len); 108 | + } else { 109 | + /* Render the glyphs. */ 110 | + XftDrawGlyphFontSpec(xw.draw, fg, specs, len); 111 | + } 112 | 113 | - /* Render underline and strikethrough. */ 114 | - if (base.mode & ATTR_UNDERLINE) { 115 | - XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent * chscale + 1, 116 | - width, 1); 117 | - } 118 | + /* Render underline and strikethrough. */ 119 | + if (base.mode & ATTR_UNDERLINE) { 120 | + XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1, 121 | + width, 1); 122 | + } 123 | 124 | - if (base.mode & ATTR_STRUCK) { 125 | - XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent * chscale / 3, 126 | - width, 1); 127 | - } 128 | - 129 | - /* Reset clip to none. */ 130 | - XftDrawSetClip(xw.draw, 0); 131 | + if (base.mode & ATTR_STRUCK) { 132 | + XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent / 3, 133 | + width, 1); 134 | + } 135 | + } 136 | } 137 | 138 | void 139 | @@ -1524,7 +1518,7 @@ xdrawglyph(Glyph g, int x, int y) 140 | XftGlyphFontSpec spec; 141 | 142 | numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y); 143 | - xdrawglyphfontspecs(&spec, g, numspecs, x, y); 144 | + xdrawglyphfontspecs(&spec, g, numspecs, x, y, DRAW_BG | DRAW_FG); 145 | } 146 | 147 | void 148 | @@ -1659,32 +1653,39 @@ xstartdraw(void) 149 | void 150 | xdrawline(Line line, int x1, int y1, int x2) 151 | { 152 | - int i, x, ox, numspecs; 153 | + int i, x, ox, numspecs, numspecs_cached; 154 | Glyph base, new; 155 | - XftGlyphFontSpec *specs = xw.specbuf; 156 | - 157 | - numspecs = xmakeglyphfontspecs(specs, &line[x1], x2 - x1, x1, y1); 158 | - i = ox = 0; 159 | - for (x = x1; x < x2 && i < numspecs; x++) { 160 | - new = line[x]; 161 | - if (new.mode == ATTR_WDUMMY) 162 | - continue; 163 | - if (selected(x, y1)) 164 | - new.mode ^= ATTR_REVERSE; 165 | - if (i > 0 && ATTRCMP(base, new)) { 166 | - xdrawglyphfontspecs(specs, base, i, ox, y1); 167 | - specs += i; 168 | - numspecs -= i; 169 | - i = 0; 170 | - } 171 | - if (i == 0) { 172 | - ox = x; 173 | - base = new; 174 | + XftGlyphFontSpec *specs; 175 | + 176 | + numspecs_cached = xmakeglyphfontspecs(xw.specbuf, &line[x1], x2 - x1, x1, y1); 177 | + 178 | + /* Draw line in 2 passes: background and foreground. This way wide glyphs 179 | + won't get truncated (#223) */ 180 | + for (int dmode = DRAW_BG; dmode <= DRAW_FG; dmode <<= 1) { 181 | + specs = xw.specbuf; 182 | + numspecs = numspecs_cached; 183 | + i = ox = 0; 184 | + for (x = x1; x < x2 && i < numspecs; x++) { 185 | + new = line[x]; 186 | + if (new.mode == ATTR_WDUMMY) 187 | + continue; 188 | + if (selected(x, y1)) 189 | + new.mode ^= ATTR_REVERSE; 190 | + if (i > 0 && ATTRCMP(base, new)) { 191 | + xdrawglyphfontspecs(specs, base, i, ox, y1, dmode); 192 | + specs += i; 193 | + numspecs -= i; 194 | + i = 0; 195 | + } 196 | + if (i == 0) { 197 | + ox = x; 198 | + base = new; 199 | + } 200 | + i++; 201 | } 202 | - i++; 203 | + if (i > 0) 204 | + xdrawglyphfontspecs(specs, base, i, ox, y1, dmode); 205 | } 206 | - if (i > 0) 207 | - xdrawglyphfontspecs(specs, base, i, ox, y1); 208 | } 209 | 210 | void 211 | -- 212 | 2.35.1 213 | 214 | -------------------------------------------------------------------------------- /patch/st-ligatures-boxdraw-20221120-0.9.diff: -------------------------------------------------------------------------------- 1 | diff --git a/Makefile b/Makefile 2 | index 6dfa212..adfa07a 100644 3 | --- a/Makefile 4 | +++ b/Makefile 5 | @@ -4,7 +4,7 @@ 6 | 7 | include config.mk 8 | 9 | -SRC = st.c x.c boxdraw.c 10 | +SRC = st.c x.c boxdraw.c hb.c 11 | OBJ = $(SRC:.c=.o) 12 | 13 | all: options st 14 | @@ -22,8 +22,9 @@ config.h: 15 | $(CC) $(STCFLAGS) -c $< 16 | 17 | st.o: config.h st.h win.h 18 | -x.o: arg.h config.h st.h win.h 19 | +x.o: arg.h config.h st.h win.h hb.h 20 | boxdraw.o: config.h st.h boxdraw_data.h 21 | +hb.o: st.h 22 | 23 | $(OBJ): config.h config.mk 24 | 25 | diff --git a/config.mk b/config.mk 26 | index 1e306f8..3e13e53 100644 27 | --- a/config.mk 28 | +++ b/config.mk 29 | @@ -15,10 +15,12 @@ PKG_CONFIG = pkg-config 30 | # includes and libs 31 | INCS = -I$(X11INC) \ 32 | `$(PKG_CONFIG) --cflags fontconfig` \ 33 | - `$(PKG_CONFIG) --cflags freetype2` 34 | + `$(PKG_CONFIG) --cflags freetype2` \ 35 | + `$(PKG_CONFIG) --cflags harfbuzz` 36 | LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft \ 37 | `$(PKG_CONFIG) --libs fontconfig` \ 38 | - `$(PKG_CONFIG) --libs freetype2` 39 | + `$(PKG_CONFIG) --libs freetype2` \ 40 | + `$(PKG_CONFIG) --libs harfbuzz` 41 | 42 | # flags 43 | STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 44 | diff --git a/hb.c b/hb.c 45 | new file mode 100644 46 | index 0000000..59b9200 47 | --- /dev/null 48 | +++ b/hb.c 49 | @@ -0,0 +1,107 @@ 50 | +#include 51 | +#include 52 | +#include 53 | +#include 54 | +#include 55 | +#include 56 | +#include 57 | + 58 | +#include "st.h" 59 | +#include "hb.h" 60 | + 61 | +#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 } 62 | + 63 | +hb_font_t *hbfindfont(XftFont *match); 64 | + 65 | +typedef struct { 66 | + XftFont *match; 67 | + hb_font_t *font; 68 | +} HbFontMatch; 69 | + 70 | +static int hbfontslen = 0; 71 | +static HbFontMatch *hbfontcache = NULL; 72 | + 73 | +/* 74 | + * Poplulate the array with a list of font features, wrapped in FEATURE macro, 75 | + * e. g. 76 | + * FEATURE('c', 'a', 'l', 't'), FEATURE('d', 'l', 'i', 'g') 77 | + */ 78 | +hb_feature_t features[] = { }; 79 | + 80 | +void 81 | +hbunloadfonts() 82 | +{ 83 | + for (int i = 0; i < hbfontslen; i++) { 84 | + hb_font_destroy(hbfontcache[i].font); 85 | + XftUnlockFace(hbfontcache[i].match); 86 | + } 87 | + 88 | + if (hbfontcache != NULL) { 89 | + free(hbfontcache); 90 | + hbfontcache = NULL; 91 | + } 92 | + hbfontslen = 0; 93 | +} 94 | + 95 | +hb_font_t * 96 | +hbfindfont(XftFont *match) 97 | +{ 98 | + for (int i = 0; i < hbfontslen; i++) { 99 | + if (hbfontcache[i].match == match) 100 | + return hbfontcache[i].font; 101 | + } 102 | + 103 | + /* Font not found in cache, caching it now. */ 104 | + hbfontcache = realloc(hbfontcache, sizeof(HbFontMatch) * (hbfontslen + 1)); 105 | + FT_Face face = XftLockFace(match); 106 | + hb_font_t *font = hb_ft_font_create(face, NULL); 107 | + if (font == NULL) 108 | + die("Failed to load Harfbuzz font."); 109 | + 110 | + hbfontcache[hbfontslen].match = match; 111 | + hbfontcache[hbfontslen].font = font; 112 | + hbfontslen += 1; 113 | + 114 | + return font; 115 | +} 116 | + 117 | +void hbtransform(HbTransformData *data, XftFont *xfont, const Glyph *glyphs, int start, int length) { 118 | + Rune rune; 119 | + ushort mode = USHRT_MAX; 120 | + unsigned int glyph_count; 121 | + int i, end = start + length; 122 | + 123 | + hb_font_t *font = hbfindfont(xfont); 124 | + if (font == NULL) 125 | + return; 126 | + 127 | + hb_buffer_t *buffer = hb_buffer_create(); 128 | + hb_buffer_set_direction(buffer, HB_DIRECTION_LTR); 129 | + 130 | + /* Fill buffer with codepoints. */ 131 | + for (i = start; i < end; i++) { 132 | + rune = glyphs[i].u; 133 | + mode = glyphs[i].mode; 134 | + if (mode & ATTR_WDUMMY) 135 | + rune = 0x0020; 136 | + hb_buffer_add_codepoints(buffer, &rune, 1, 0, 1); 137 | + } 138 | + 139 | + /* Shape the segment. */ 140 | + hb_shape(font, buffer, features, sizeof(features)/sizeof(hb_feature_t)); 141 | + 142 | + /* Get new glyph info. */ 143 | + hb_glyph_info_t *info = hb_buffer_get_glyph_infos(buffer, &glyph_count); 144 | + hb_glyph_position_t *pos = hb_buffer_get_glyph_positions(buffer, &glyph_count); 145 | + 146 | + /** Fill the output. */ 147 | + data->buffer = buffer; 148 | + data->glyphs = info; 149 | + data->positions = pos; 150 | + data->count = glyph_count; 151 | +} 152 | + 153 | +void hbcleanup(HbTransformData *data) { 154 | + hb_buffer_destroy(data->buffer); 155 | + memset(data, 0, sizeof(HbTransformData)); 156 | +} 157 | diff --git a/hb.h b/hb.h 158 | new file mode 100644 159 | index 0000000..88de9bd 160 | --- /dev/null 161 | +++ b/hb.h 162 | @@ -0,0 +1,14 @@ 163 | +#include 164 | +#include 165 | +#include 166 | + 167 | +typedef struct { 168 | + hb_buffer_t *buffer; 169 | + hb_glyph_info_t *glyphs; 170 | + hb_glyph_position_t *positions; 171 | + unsigned int count; 172 | +} HbTransformData; 173 | + 174 | +void hbunloadfonts(); 175 | +void hbtransform(HbTransformData *, XftFont *, const Glyph *, int, int); 176 | +void hbcleanup(HbTransformData *); 177 | diff --git a/st.c b/st.c 178 | index 41d5ace..1c2edd6 100644 179 | --- a/st.c 180 | +++ b/st.c 181 | @@ -2643,7 +2643,8 @@ draw(void) 182 | 183 | drawregion(0, 0, term.col, term.row); 184 | xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], 185 | - term.ocx, term.ocy, term.line[term.ocy][term.ocx]); 186 | + term.ocx, term.ocy, term.line[term.ocy][term.ocx], 187 | + term.line[term.ocy], term.col); 188 | term.ocx = cx; 189 | term.ocy = term.c.y; 190 | xfinishdraw(); 191 | diff --git a/st.h b/st.h 192 | index 808f5f7..ae41368 100644 193 | --- a/st.h 194 | +++ b/st.h 195 | @@ -11,7 +11,8 @@ 196 | #define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d)) 197 | #define DEFAULT(a, b) (a) = (a) ? (a) : (b) 198 | #define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x) 199 | -#define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || \ 200 | +#define ATTRCMP(a, b) (((a).mode & (~ATTR_WRAP)) != ((b).mode & (~ATTR_WRAP)) || \ 201 | + (a).fg != (b).fg || \ 202 | (a).bg != (b).bg) 203 | #define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + \ 204 | (t1.tv_nsec-t2.tv_nsec)/1E6) 205 | diff --git a/win.h b/win.h 206 | index 6de960d..94679e4 100644 207 | --- a/win.h 208 | +++ b/win.h 209 | @@ -25,7 +25,7 @@ enum win_mode { 210 | 211 | void xbell(void); 212 | void xclipcopy(void); 213 | -void xdrawcursor(int, int, Glyph, int, int, Glyph); 214 | +void xdrawcursor(int, int, Glyph, int, int, Glyph, Line, int); 215 | void xdrawline(Line, int, int, int); 216 | void xfinishdraw(void); 217 | void xloadcols(void); 218 | diff --git a/x.c b/x.c 219 | index bf6bbf9..440bd2a 100644 220 | --- a/x.c 221 | +++ b/x.c 222 | @@ -19,6 +19,7 @@ char *argv0; 223 | #include "arg.h" 224 | #include "st.h" 225 | #include "win.h" 226 | +#include "hb.h" 227 | 228 | /* types used in config.h */ 229 | typedef struct { 230 | @@ -141,6 +142,7 @@ typedef struct { 231 | } DC; 232 | 233 | static inline ushort sixd_to_16bit(int); 234 | +static void xresetfontsettings(ushort mode, Font **font, int *frcflags); 235 | static int xmakeglyphfontspecs(XftGlyphFontSpec *, const Glyph *, int, int, int); 236 | static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int); 237 | static void xdrawglyph(Glyph, int, int); 238 | @@ -1062,6 +1064,9 @@ xunloadfont(Font *f) 239 | void 240 | xunloadfonts(void) 241 | { 242 | + /* Clear Harfbuzz font cache. */ 243 | + hbunloadfonts(); 244 | + 245 | /* Free the loaded fonts in the font cache. */ 246 | while (frclen > 0) 247 | XftFontClose(xw.dpy, frc[--frclen].font); 248 | @@ -1241,6 +1246,22 @@ xinit(int cols, int rows) 249 | boxdraw_xinit(xw.dpy, xw.cmap, xw.draw, xw.vis); 250 | } 251 | 252 | +void 253 | +xresetfontsettings(ushort mode, Font **font, int *frcflags) 254 | +{ 255 | + *font = &dc.font; 256 | + if ((mode & ATTR_ITALIC) && (mode & ATTR_BOLD)) { 257 | + *font = &dc.ibfont; 258 | + *frcflags = FRC_ITALICBOLD; 259 | + } else if (mode & ATTR_ITALIC) { 260 | + *font = &dc.ifont; 261 | + *frcflags = FRC_ITALIC; 262 | + } else if (mode & ATTR_BOLD) { 263 | + *font = &dc.bfont; 264 | + *frcflags = FRC_BOLD; 265 | + } 266 | +} 267 | + 268 | int 269 | xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y) 270 | { 271 | @@ -1255,124 +1276,145 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x 272 | FcPattern *fcpattern, *fontpattern; 273 | FcFontSet *fcsets[] = { NULL }; 274 | FcCharSet *fccharset; 275 | - int i, f, numspecs = 0; 276 | + int i, f, length = 0, start = 0, numspecs = 0; 277 | + HbTransformData shaped = { 0 }; 278 | + 279 | + /* Initial values. */ 280 | + mode = prevmode = glyphs[0].mode; 281 | + xresetfontsettings(mode, &font, &frcflags); 282 | 283 | for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) { 284 | - /* Fetch rune and mode for current glyph. */ 285 | - rune = glyphs[i].u; 286 | mode = glyphs[i].mode; 287 | 288 | /* Skip dummy wide-character spacing. */ 289 | - if (mode == ATTR_WDUMMY) 290 | + if (mode & ATTR_WDUMMY) 291 | continue; 292 | 293 | - /* Determine font for glyph if different from previous glyph. */ 294 | - if (prevmode != mode) { 295 | - prevmode = mode; 296 | - font = &dc.font; 297 | - frcflags = FRC_NORMAL; 298 | - runewidth = win.cw * ((mode & ATTR_WIDE) ? 2.0f : 1.0f); 299 | - if ((mode & ATTR_ITALIC) && (mode & ATTR_BOLD)) { 300 | - font = &dc.ibfont; 301 | - frcflags = FRC_ITALICBOLD; 302 | - } else if (mode & ATTR_ITALIC) { 303 | - font = &dc.ifont; 304 | - frcflags = FRC_ITALIC; 305 | - } else if (mode & ATTR_BOLD) { 306 | - font = &dc.bfont; 307 | - frcflags = FRC_BOLD; 308 | + if ( 309 | + prevmode != mode 310 | + || ATTRCMP(glyphs[start], glyphs[i]) 311 | + || selected(x + i, y) != selected(x + start, y) 312 | + || i == (len - 1) 313 | + ) { 314 | + /* Handle 1-character wide segments and end of line */ 315 | + length = i - start; 316 | + if (i == start) { 317 | + length = 1; 318 | + } else if (i == (len - 1)) { 319 | + length = (i - start + 1); 320 | } 321 | - yp = winy + font->ascent; 322 | - } 323 | 324 | - if (mode & ATTR_BOXDRAW) { 325 | - /* minor shoehorning: boxdraw uses only this ushort */ 326 | - glyphidx = boxdrawindex(&glyphs[i]); 327 | - } else { 328 | - /* Lookup character index with default font. */ 329 | - glyphidx = XftCharIndex(xw.dpy, font->match, rune); 330 | - } 331 | - if (glyphidx) { 332 | - specs[numspecs].font = font->match; 333 | - specs[numspecs].glyph = glyphidx; 334 | - specs[numspecs].x = (short)xp; 335 | - specs[numspecs].y = (short)yp; 336 | - xp += runewidth; 337 | - numspecs++; 338 | - continue; 339 | - } 340 | - 341 | - /* Fallback on font cache, search the font cache for match. */ 342 | - for (f = 0; f < frclen; f++) { 343 | - glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune); 344 | - /* Everything correct. */ 345 | - if (glyphidx && frc[f].flags == frcflags) 346 | - break; 347 | - /* We got a default font for a not found glyph. */ 348 | - if (!glyphidx && frc[f].flags == frcflags 349 | - && frc[f].unicodep == rune) { 350 | - break; 351 | + /* Shape the segment. */ 352 | + hbtransform(&shaped, font->match, glyphs, start, length); 353 | + for (int code_idx = 0; code_idx < shaped.count; code_idx++) { 354 | + rune = glyphs[start + code_idx].u; 355 | + runewidth = win.cw * ((glyphs[start + code_idx].mode & ATTR_WIDE) ? 2.0f : 1.0f); 356 | + 357 | + if (glyphs[start + code_idx].mode & ATTR_WDUMMY) 358 | + continue; 359 | + 360 | + if (glyphs[start + code_idx].mode & ATTR_BOXDRAW) { 361 | + /* minor shoehorning: boxdraw uses only this ushort */ 362 | + specs[numspecs].font = font->match; 363 | + specs[numspecs].glyph = boxdrawindex(&glyphs[start + code_idx]); 364 | + specs[numspecs].x = xp; 365 | + specs[numspecs].y = yp; 366 | + xp += runewidth; 367 | + numspecs++; 368 | + } else if (shaped.glyphs[code_idx].codepoint != 0) { 369 | + /* If symbol is found, put it into the specs. */ 370 | + specs[numspecs].font = font->match; 371 | + specs[numspecs].glyph = shaped.glyphs[code_idx].codepoint; 372 | + specs[numspecs].x = xp + (short)shaped.positions[code_idx].x_offset; 373 | + specs[numspecs].y = yp + (short)shaped.positions[code_idx].y_offset; 374 | + xp += runewidth; 375 | + numspecs++; 376 | + } else { 377 | + /* If it's not found, try to fetch it through the font cache. */ 378 | + for (f = 0; f < frclen; f++) { 379 | + glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune); 380 | + /* Everything correct. */ 381 | + if (glyphidx && frc[f].flags == frcflags) 382 | + break; 383 | + /* We got a default font for a not found glyph. */ 384 | + if (!glyphidx && frc[f].flags == frcflags 385 | + && frc[f].unicodep == rune) { 386 | + break; 387 | + } 388 | + } 389 | + 390 | + /* Nothing was found. Use fontconfig to find matching font. */ 391 | + if (f >= frclen) { 392 | + if (!font->set) 393 | + font->set = FcFontSort(0, font->pattern, 394 | + 1, 0, &fcres); 395 | + fcsets[0] = font->set; 396 | + 397 | + /* 398 | + * Nothing was found in the cache. Now use 399 | + * some dozen of Fontconfig calls to get the 400 | + * font for one single character. 401 | + * 402 | + * Xft and fontconfig are design failures. 403 | + */ 404 | + fcpattern = FcPatternDuplicate(font->pattern); 405 | + fccharset = FcCharSetCreate(); 406 | + 407 | + FcCharSetAddChar(fccharset, rune); 408 | + FcPatternAddCharSet(fcpattern, FC_CHARSET, 409 | + fccharset); 410 | + FcPatternAddBool(fcpattern, FC_SCALABLE, 1); 411 | + 412 | + FcConfigSubstitute(0, fcpattern, 413 | + FcMatchPattern); 414 | + FcDefaultSubstitute(fcpattern); 415 | + 416 | + fontpattern = FcFontSetMatch(0, fcsets, 1, 417 | + fcpattern, &fcres); 418 | + 419 | + /* Allocate memory for the new cache entry. */ 420 | + if (frclen >= frccap) { 421 | + frccap += 16; 422 | + frc = xrealloc(frc, frccap * sizeof(Fontcache)); 423 | + } 424 | + 425 | + frc[frclen].font = XftFontOpenPattern(xw.dpy, 426 | + fontpattern); 427 | + if (!frc[frclen].font) 428 | + die("XftFontOpenPattern failed seeking fallback font: %s\n", 429 | + strerror(errno)); 430 | + frc[frclen].flags = frcflags; 431 | + frc[frclen].unicodep = rune; 432 | + 433 | + glyphidx = XftCharIndex(xw.dpy, frc[frclen].font, rune); 434 | + 435 | + f = frclen; 436 | + frclen++; 437 | + 438 | + FcPatternDestroy(fcpattern); 439 | + FcCharSetDestroy(fccharset); 440 | + } 441 | + 442 | + specs[numspecs].font = frc[f].font; 443 | + specs[numspecs].glyph = glyphidx; 444 | + specs[numspecs].x = (short)xp; 445 | + specs[numspecs].y = (short)yp; 446 | + xp += runewidth; 447 | + numspecs++; 448 | + } 449 | } 450 | - } 451 | 452 | - /* Nothing was found. Use fontconfig to find matching font. */ 453 | - if (f >= frclen) { 454 | - if (!font->set) 455 | - font->set = FcFontSort(0, font->pattern, 456 | - 1, 0, &fcres); 457 | - fcsets[0] = font->set; 458 | + /* Cleanup and get ready for next segment. */ 459 | + hbcleanup(&shaped); 460 | + start = i; 461 | 462 | - /* 463 | - * Nothing was found in the cache. Now use 464 | - * some dozen of Fontconfig calls to get the 465 | - * font for one single character. 466 | - * 467 | - * Xft and fontconfig are design failures. 468 | - */ 469 | - fcpattern = FcPatternDuplicate(font->pattern); 470 | - fccharset = FcCharSetCreate(); 471 | - 472 | - FcCharSetAddChar(fccharset, rune); 473 | - FcPatternAddCharSet(fcpattern, FC_CHARSET, 474 | - fccharset); 475 | - FcPatternAddBool(fcpattern, FC_SCALABLE, 1); 476 | - 477 | - FcConfigSubstitute(0, fcpattern, 478 | - FcMatchPattern); 479 | - FcDefaultSubstitute(fcpattern); 480 | - 481 | - fontpattern = FcFontSetMatch(0, fcsets, 1, 482 | - fcpattern, &fcres); 483 | - 484 | - /* Allocate memory for the new cache entry. */ 485 | - if (frclen >= frccap) { 486 | - frccap += 16; 487 | - frc = xrealloc(frc, frccap * sizeof(Fontcache)); 488 | + /* Determine font for glyph if different from previous glyph. */ 489 | + if (prevmode != mode) { 490 | + prevmode = mode; 491 | + xresetfontsettings(mode, &font, &frcflags); 492 | + yp = winy + font->ascent; 493 | } 494 | - 495 | - frc[frclen].font = XftFontOpenPattern(xw.dpy, 496 | - fontpattern); 497 | - if (!frc[frclen].font) 498 | - die("XftFontOpenPattern failed seeking fallback font: %s\n", 499 | - strerror(errno)); 500 | - frc[frclen].flags = frcflags; 501 | - frc[frclen].unicodep = rune; 502 | - 503 | - glyphidx = XftCharIndex(xw.dpy, frc[frclen].font, rune); 504 | - 505 | - f = frclen; 506 | - frclen++; 507 | - 508 | - FcPatternDestroy(fcpattern); 509 | - FcCharSetDestroy(fccharset); 510 | } 511 | - 512 | - specs[numspecs].font = frc[f].font; 513 | - specs[numspecs].glyph = glyphidx; 514 | - specs[numspecs].x = (short)xp; 515 | - specs[numspecs].y = (short)yp; 516 | - xp += runewidth; 517 | - numspecs++; 518 | } 519 | 520 | return numspecs; 521 | @@ -1528,14 +1570,17 @@ xdrawglyph(Glyph g, int x, int y) 522 | } 523 | 524 | void 525 | -xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) 526 | +xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og, Line line, int len) 527 | { 528 | Color drawcol; 529 | 530 | /* remove the old cursor */ 531 | if (selected(ox, oy)) 532 | og.mode ^= ATTR_REVERSE; 533 | - xdrawglyph(og, ox, oy); 534 | + 535 | + /* Redraw the line where cursor was previously. 536 | + * It will restore the ligatures broken by the cursor. */ 537 | + xdrawline(line, 0, oy, len); 538 | 539 | if (IS_SET(MODE_HIDE)) 540 | return; 541 | -------------------------------------------------------------------------------- /patch/st-scrollback-0.8.5.diff: -------------------------------------------------------------------------------- 1 | diff --git a/config.def.h b/config.def.h 2 | index 91ab8ca..e3b469b 100644 3 | --- a/config.def.h 4 | +++ b/config.def.h 5 | @@ -201,6 +201,8 @@ static Shortcut shortcuts[] = { 6 | { TERMMOD, XK_Y, selpaste, {.i = 0} }, 7 | { ShiftMask, XK_Insert, selpaste, {.i = 0} }, 8 | { TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, 9 | + { ShiftMask, XK_Page_Up, kscrollup, {.i = -1} }, 10 | + { ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} }, 11 | }; 12 | 13 | /* 14 | diff --git a/st.c b/st.c 15 | index 51049ba..cd750f2 100644 16 | --- a/st.c 17 | +++ b/st.c 18 | @@ -35,6 +35,7 @@ 19 | #define ESC_ARG_SIZ 16 20 | #define STR_BUF_SIZ ESC_BUF_SIZ 21 | #define STR_ARG_SIZ ESC_ARG_SIZ 22 | +#define HISTSIZE 2000 23 | 24 | /* macros */ 25 | #define IS_SET(flag) ((term.mode & (flag)) != 0) 26 | @@ -42,6 +43,9 @@ 27 | #define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f)) 28 | #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c)) 29 | #define ISDELIM(u) (u && wcschr(worddelimiters, u)) 30 | +#define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - \ 31 | + term.scr + HISTSIZE + 1) % HISTSIZE] : \ 32 | + term.line[(y) - term.scr]) 33 | 34 | enum term_mode { 35 | MODE_WRAP = 1 << 0, 36 | @@ -115,6 +119,9 @@ typedef struct { 37 | int col; /* nb col */ 38 | Line *line; /* screen */ 39 | Line *alt; /* alternate screen */ 40 | + Line hist[HISTSIZE]; /* history buffer */ 41 | + int histi; /* history index */ 42 | + int scr; /* scroll back */ 43 | int *dirty; /* dirtyness of lines */ 44 | TCursor c; /* cursor */ 45 | int ocx; /* old cursor col */ 46 | @@ -184,8 +191,8 @@ static void tnewline(int); 47 | static void tputtab(int); 48 | static void tputc(Rune); 49 | static void treset(void); 50 | -static void tscrollup(int, int); 51 | -static void tscrolldown(int, int); 52 | +static void tscrollup(int, int, int); 53 | +static void tscrolldown(int, int, int); 54 | static void tsetattr(const int *, int); 55 | static void tsetchar(Rune, const Glyph *, int, int); 56 | static void tsetdirt(int, int); 57 | @@ -416,10 +423,10 @@ tlinelen(int y) 58 | { 59 | int i = term.col; 60 | 61 | - if (term.line[y][i - 1].mode & ATTR_WRAP) 62 | + if (TLINE(y)[i - 1].mode & ATTR_WRAP) 63 | return i; 64 | 65 | - while (i > 0 && term.line[y][i - 1].u == ' ') 66 | + while (i > 0 && TLINE(y)[i - 1].u == ' ') 67 | --i; 68 | 69 | return i; 70 | @@ -528,7 +535,7 @@ selsnap(int *x, int *y, int direction) 71 | * Snap around if the word wraps around at the end or 72 | * beginning of a line. 73 | */ 74 | - prevgp = &term.line[*y][*x]; 75 | + prevgp = &TLINE(*y)[*x]; 76 | prevdelim = ISDELIM(prevgp->u); 77 | for (;;) { 78 | newx = *x + direction; 79 | @@ -543,14 +550,14 @@ selsnap(int *x, int *y, int direction) 80 | yt = *y, xt = *x; 81 | else 82 | yt = newy, xt = newx; 83 | - if (!(term.line[yt][xt].mode & ATTR_WRAP)) 84 | + if (!(TLINE(yt)[xt].mode & ATTR_WRAP)) 85 | break; 86 | } 87 | 88 | if (newx >= tlinelen(newy)) 89 | break; 90 | 91 | - gp = &term.line[newy][newx]; 92 | + gp = &TLINE(newy)[newx]; 93 | delim = ISDELIM(gp->u); 94 | if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim 95 | || (delim && gp->u != prevgp->u))) 96 | @@ -571,14 +578,14 @@ selsnap(int *x, int *y, int direction) 97 | *x = (direction < 0) ? 0 : term.col - 1; 98 | if (direction < 0) { 99 | for (; *y > 0; *y += direction) { 100 | - if (!(term.line[*y-1][term.col-1].mode 101 | + if (!(TLINE(*y-1)[term.col-1].mode 102 | & ATTR_WRAP)) { 103 | break; 104 | } 105 | } 106 | } else if (direction > 0) { 107 | for (; *y < term.row-1; *y += direction) { 108 | - if (!(term.line[*y][term.col-1].mode 109 | + if (!(TLINE(*y)[term.col-1].mode 110 | & ATTR_WRAP)) { 111 | break; 112 | } 113 | @@ -609,13 +616,13 @@ getsel(void) 114 | } 115 | 116 | if (sel.type == SEL_RECTANGULAR) { 117 | - gp = &term.line[y][sel.nb.x]; 118 | + gp = &TLINE(y)[sel.nb.x]; 119 | lastx = sel.ne.x; 120 | } else { 121 | - gp = &term.line[y][sel.nb.y == y ? sel.nb.x : 0]; 122 | + gp = &TLINE(y)[sel.nb.y == y ? sel.nb.x : 0]; 123 | lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1; 124 | } 125 | - last = &term.line[y][MIN(lastx, linelen-1)]; 126 | + last = &TLINE(y)[MIN(lastx, linelen-1)]; 127 | while (last >= gp && last->u == ' ') 128 | --last; 129 | 130 | @@ -851,6 +858,9 @@ void 131 | ttywrite(const char *s, size_t n, int may_echo) 132 | { 133 | const char *next; 134 | + Arg arg = (Arg) { .i = term.scr }; 135 | + 136 | + kscrolldown(&arg); 137 | 138 | if (may_echo && IS_SET(MODE_ECHO)) 139 | twrite(s, n, 1); 140 | @@ -1062,12 +1072,52 @@ tswapscreen(void) 141 | } 142 | 143 | void 144 | -tscrolldown(int orig, int n) 145 | +kscrolldown(const Arg* a) 146 | +{ 147 | + int n = a->i; 148 | + 149 | + if (n < 0) 150 | + n = term.row + n; 151 | + 152 | + if (n > term.scr) 153 | + n = term.scr; 154 | + 155 | + if (term.scr > 0) { 156 | + term.scr -= n; 157 | + selscroll(0, -n); 158 | + tfulldirt(); 159 | + } 160 | +} 161 | + 162 | +void 163 | +kscrollup(const Arg* a) 164 | +{ 165 | + int n = a->i; 166 | + 167 | + if (n < 0) 168 | + n = term.row + n; 169 | + 170 | + if (term.scr <= HISTSIZE-n) { 171 | + term.scr += n; 172 | + selscroll(0, n); 173 | + tfulldirt(); 174 | + } 175 | +} 176 | + 177 | +void 178 | +tscrolldown(int orig, int n, int copyhist) 179 | { 180 | int i; 181 | Line temp; 182 | 183 | LIMIT(n, 0, term.bot-orig+1); 184 | + if (copyhist) { 185 | + term.histi = (term.histi - 1 + HISTSIZE) % HISTSIZE; 186 | + temp = term.hist[term.histi]; 187 | + term.hist[term.histi] = term.line[term.bot]; 188 | + term.line[term.bot] = temp; 189 | + } 190 | + 191 | 192 | tsetdirt(orig, term.bot-n); 193 | tclearregion(0, term.bot-n+1, term.col-1, term.bot); 194 | @@ -1078,17 +1128,28 @@ tscrolldown(int orig, int n) 195 | term.line[i-n] = temp; 196 | } 197 | 198 | - selscroll(orig, n); 199 | + if (term.scr == 0) 200 | + selscroll(orig, n); 201 | } 202 | 203 | void 204 | -tscrollup(int orig, int n) 205 | +tscrollup(int orig, int n, int copyhist) 206 | { 207 | int i; 208 | Line temp; 209 | 210 | LIMIT(n, 0, term.bot-orig+1); 211 | 212 | + if (copyhist) { 213 | + term.histi = (term.histi + 1) % HISTSIZE; 214 | + temp = term.hist[term.histi]; 215 | + term.hist[term.histi] = term.line[orig]; 216 | + term.line[orig] = temp; 217 | + } 218 | + 219 | + if (term.scr > 0 && term.scr < HISTSIZE) 220 | + term.scr = MIN(term.scr + n, HISTSIZE-1); 221 | + 222 | tclearregion(0, orig, term.col-1, orig+n-1); 223 | tsetdirt(orig+n, term.bot); 224 | 225 | @@ -1098,7 +1159,8 @@ tscrollup(int orig, int n) 226 | term.line[i+n] = temp; 227 | } 228 | 229 | - selscroll(orig, -n); 230 | + if (term.scr == 0) 231 | + selscroll(orig, -n); 232 | } 233 | 234 | void 235 | @@ -1127,7 +1189,7 @@ tnewline(int first_col) 236 | int y = term.c.y; 237 | 238 | if (y == term.bot) { 239 | - tscrollup(term.top, 1); 240 | + tscrollup(term.top, 1, 1); 241 | } else { 242 | y++; 243 | } 244 | @@ -1292,14 +1354,14 @@ void 245 | tinsertblankline(int n) 246 | { 247 | if (BETWEEN(term.c.y, term.top, term.bot)) 248 | - tscrolldown(term.c.y, n); 249 | + tscrolldown(term.c.y, n, 0); 250 | } 251 | 252 | void 253 | tdeleteline(int n) 254 | { 255 | if (BETWEEN(term.c.y, term.top, term.bot)) 256 | - tscrollup(term.c.y, n); 257 | + tscrollup(term.c.y, n, 0); 258 | } 259 | 260 | int32_t 261 | @@ -1736,11 +1798,11 @@ csihandle(void) 262 | break; 263 | case 'S': /* SU -- Scroll line up */ 264 | DEFAULT(csiescseq.arg[0], 1); 265 | - tscrollup(term.top, csiescseq.arg[0]); 266 | + tscrollup(term.top, csiescseq.arg[0], 0); 267 | break; 268 | case 'T': /* SD -- Scroll line down */ 269 | DEFAULT(csiescseq.arg[0], 1); 270 | - tscrolldown(term.top, csiescseq.arg[0]); 271 | + tscrolldown(term.top, csiescseq.arg[0], 0); 272 | break; 273 | case 'L': /* IL -- Insert blank lines */ 274 | DEFAULT(csiescseq.arg[0], 1); 275 | @@ -2330,7 +2392,7 @@ eschandle(uchar ascii) 276 | return 0; 277 | case 'D': /* IND -- Linefeed */ 278 | if (term.c.y == term.bot) { 279 | - tscrollup(term.top, 1); 280 | + tscrollup(term.top, 1, 1); 281 | } else { 282 | tmoveto(term.c.x, term.c.y+1); 283 | } 284 | @@ -2343,7 +2405,7 @@ eschandle(uchar ascii) 285 | break; 286 | case 'M': /* RI -- Reverse index */ 287 | if (term.c.y == term.top) { 288 | - tscrolldown(term.top, 1); 289 | + tscrolldown(term.top, 1, 1); 290 | } else { 291 | tmoveto(term.c.x, term.c.y-1); 292 | } 293 | @@ -2557,7 +2619,7 @@ twrite(const char *buf, int buflen, int show_ctrl) 294 | void 295 | tresize(int col, int row) 296 | { 297 | - int i; 298 | + int i, j; 299 | int minrow = MIN(row, term.row); 300 | int mincol = MIN(col, term.col); 301 | int *bp; 302 | @@ -2594,6 +2656,14 @@ tresize(int col, int row) 303 | term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty)); 304 | term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs)); 305 | 306 | + for (i = 0; i < HISTSIZE; i++) { 307 | + term.hist[i] = xrealloc(term.hist[i], col * sizeof(Glyph)); 308 | + for (j = mincol; j < col; j++) { 309 | + term.hist[i][j] = term.c.attr; 310 | + term.hist[i][j].u = ' '; 311 | + } 312 | + } 313 | + 314 | /* resize each row to new width, zero-pad if needed */ 315 | for (i = 0; i < minrow; i++) { 316 | term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph)); 317 | @@ -2652,7 +2722,7 @@ drawregion(int x1, int y1, int x2, int y2) 318 | continue; 319 | 320 | term.dirty[y] = 0; 321 | - xdrawline(term.line[y], x1, y, x2); 322 | + xdrawline(TLINE(y), x1, y, x2); 323 | } 324 | } 325 | 326 | @@ -2673,8 +2743,9 @@ draw(void) 327 | cx--; 328 | 329 | drawregion(0, 0, term.col, term.row); 330 | - xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], 331 | - term.ocx, term.ocy, term.line[term.ocy][term.ocx]); 332 | + if (term.scr == 0) 333 | + xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], 334 | + term.ocx, term.ocy, term.line[term.ocy][term.ocx]); 335 | term.ocx = cx; 336 | term.ocy = term.c.y; 337 | xfinishdraw(); 338 | diff --git a/st.h b/st.h 339 | index 519b9bd..da36b34 100644 340 | --- a/st.h 341 | +++ b/st.h 342 | @@ -81,6 +81,8 @@ void die(const char *, ...); 343 | void redraw(void); 344 | void draw(void); 345 | 346 | +void kscrolldown(const Arg *); 347 | +void kscrollup(const Arg *); 348 | void printscreen(const Arg *); 349 | void printsel(const Arg *); 350 | void sendbreak(const Arg *); 351 | -------------------------------------------------------------------------------- /preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motolla/st/80a40a50d86193c9524ca91ae73bba192ad9a9d1/preview.png -------------------------------------------------------------------------------- /st: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motolla/st/80a40a50d86193c9524ca91ae73bba192ad9a9d1/st -------------------------------------------------------------------------------- /st.1: -------------------------------------------------------------------------------- 1 | .TH ST 1 st\-VERSION 2 | .SH NAME 3 | st \- simple terminal 4 | .SH SYNOPSIS 5 | .B st 6 | .RB [ \-aiv ] 7 | .RB [ \-c 8 | .IR class ] 9 | .RB [ \-f 10 | .IR font ] 11 | .RB [ \-g 12 | .IR geometry ] 13 | .RB [ \-n 14 | .IR name ] 15 | .RB [ \-o 16 | .IR iofile ] 17 | .RB [ \-T 18 | .IR title ] 19 | .RB [ \-t 20 | .IR title ] 21 | .RB [ \-l 22 | .IR line ] 23 | .RB [ \-w 24 | .IR windowid ] 25 | .RB [[ \-e ] 26 | .IR command 27 | .RI [ arguments ...]] 28 | .PP 29 | .B st 30 | .RB [ \-aiv ] 31 | .RB [ \-c 32 | .IR class ] 33 | .RB [ \-f 34 | .IR font ] 35 | .RB [ \-g 36 | .IR geometry ] 37 | .RB [ \-n 38 | .IR name ] 39 | .RB [ \-o 40 | .IR iofile ] 41 | .RB [ \-T 42 | .IR title ] 43 | .RB [ \-t 44 | .IR title ] 45 | .RB [ \-w 46 | .IR windowid ] 47 | .RB \-l 48 | .IR line 49 | .RI [ stty_args ...] 50 | .SH DESCRIPTION 51 | .B st 52 | is a simple terminal emulator. 53 | .SH OPTIONS 54 | .TP 55 | .B \-a 56 | disable alternate screens in terminal 57 | .TP 58 | .BI \-c " class" 59 | defines the window class (default $TERM). 60 | .TP 61 | .BI \-f " font" 62 | defines the 63 | .I font 64 | to use when st is run. 65 | .TP 66 | .BI \-g " geometry" 67 | defines the X11 geometry string. 68 | The form is [=][{xX}][{+-}{+-}]. See 69 | .BR XParseGeometry (3) 70 | for further details. 71 | .TP 72 | .B \-i 73 | will fixate the position given with the -g option. 74 | .TP 75 | .BI \-n " name" 76 | defines the window instance name (default $TERM). 77 | .TP 78 | .BI \-o " iofile" 79 | writes all the I/O to 80 | .I iofile. 81 | This feature is useful when recording st sessions. A value of "-" means 82 | standard output. 83 | .TP 84 | .BI \-T " title" 85 | defines the window title (default 'st'). 86 | .TP 87 | .BI \-t " title" 88 | defines the window title (default 'st'). 89 | .TP 90 | .BI \-w " windowid" 91 | embeds st within the window identified by 92 | .I windowid 93 | .TP 94 | .BI \-l " line" 95 | use a tty 96 | .I line 97 | instead of a pseudo terminal. 98 | .I line 99 | should be a (pseudo-)serial device (e.g. /dev/ttyS0 on Linux for serial port 100 | 0). 101 | When this flag is given 102 | remaining arguments are used as flags for 103 | .BR stty(1). 104 | By default st initializes the serial line to 8 bits, no parity, 1 stop bit 105 | and a 38400 baud rate. The speed is set by appending it as last argument 106 | (e.g. 'st -l /dev/ttyS0 115200'). Arguments before the last one are 107 | .BR stty(1) 108 | flags. If you want to set odd parity on 115200 baud use for example 'st -l 109 | /dev/ttyS0 parenb parodd 115200'. Set the number of bits by using for 110 | example 'st -l /dev/ttyS0 cs7 115200'. See 111 | .BR stty(1) 112 | for more arguments and cases. 113 | .TP 114 | .B \-v 115 | prints version information to stderr, then exits. 116 | .TP 117 | .BI \-e " command " [ " arguments " "... ]" 118 | st executes 119 | .I command 120 | instead of the shell. If this is used it 121 | .B must be the last option 122 | on the command line, as in xterm / rxvt. 123 | This option is only intended for compatibility, 124 | and all the remaining arguments are used as a command 125 | even without it. 126 | .SH SHORTCUTS 127 | .TP 128 | .B Break 129 | Send a break in the serial line. 130 | Break key is obtained in PC keyboards 131 | pressing at the same time control and pause. 132 | .TP 133 | .B Ctrl-Print Screen 134 | Toggle if st should print to the 135 | .I iofile. 136 | .TP 137 | .B Shift-Print Screen 138 | Print the full screen to the 139 | .I iofile. 140 | .TP 141 | .B Print Screen 142 | Print the selection to the 143 | .I iofile. 144 | .TP 145 | .B Ctrl-Shift-Page Up 146 | Increase font size. 147 | .TP 148 | .B Ctrl-Shift-Page Down 149 | Decrease font size. 150 | .TP 151 | .B Ctrl-Shift-Home 152 | Reset to default font size. 153 | .TP 154 | .B Ctrl-Shift-y 155 | Paste from primary selection (middle mouse button). 156 | .TP 157 | .B Ctrl-Shift-c 158 | Copy the selected text to the clipboard selection. 159 | .TP 160 | .B Ctrl-Shift-v 161 | Paste from the clipboard selection. 162 | .SH CUSTOMIZATION 163 | .B st 164 | can be customized by creating a custom config.h and (re)compiling the source 165 | code. This keeps it fast, secure and simple. 166 | .SH AUTHORS 167 | See the LICENSE file for the authors. 168 | .SH LICENSE 169 | See the LICENSE file for the terms of redistribution. 170 | .SH SEE ALSO 171 | .BR tabbed (1), 172 | .BR utmp (1), 173 | .BR stty (1), 174 | .BR scroll (1) 175 | .SH BUGS 176 | See the TODO file in the distribution. 177 | 178 | -------------------------------------------------------------------------------- /st.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE for license details. */ 2 | 3 | #include 4 | #include 5 | 6 | /* macros */ 7 | #define MIN(a, b) ((a) < (b) ? (a) : (b)) 8 | #define MAX(a, b) ((a) < (b) ? (b) : (a)) 9 | #define LEN(a) (sizeof(a) / sizeof(a)[0]) 10 | #define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b)) 11 | #define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d)) 12 | #define DEFAULT(a, b) (a) = (a) ? (a) : (b) 13 | #define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x) 14 | #define ATTRCMP(a, b) (((a).mode & (~ATTR_WRAP)) != ((b).mode & (~ATTR_WRAP)) || \ 15 | (a).fg != (b).fg || \ 16 | (a).bg != (b).bg) 17 | #define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + \ 18 | (t1.tv_nsec-t2.tv_nsec)/1E6) 19 | #define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit))) 20 | 21 | #define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b)) 22 | #define IS_TRUECOL(x) (1 << 24 & (x)) 23 | 24 | enum glyph_attribute { 25 | ATTR_NULL = 0, 26 | ATTR_BOLD = 1 << 0, 27 | ATTR_FAINT = 1 << 1, 28 | ATTR_ITALIC = 1 << 2, 29 | ATTR_UNDERLINE = 1 << 3, 30 | ATTR_BLINK = 1 << 4, 31 | ATTR_REVERSE = 1 << 5, 32 | ATTR_INVISIBLE = 1 << 6, 33 | ATTR_STRUCK = 1 << 7, 34 | ATTR_WRAP = 1 << 8, 35 | ATTR_WIDE = 1 << 9, 36 | ATTR_WDUMMY = 1 << 10, 37 | ATTR_BOXDRAW = 1 << 11, 38 | ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT, 39 | }; 40 | 41 | enum drawing_mode { 42 | DRAW_NONE = 0, 43 | DRAW_BG = 1 << 0, 44 | DRAW_FG = 1 << 1, 45 | }; 46 | 47 | enum selection_mode { 48 | SEL_IDLE = 0, 49 | SEL_EMPTY = 1, 50 | SEL_READY = 2 51 | }; 52 | 53 | enum selection_type { 54 | SEL_REGULAR = 1, 55 | SEL_RECTANGULAR = 2 56 | }; 57 | 58 | enum selection_snap { 59 | SNAP_WORD = 1, 60 | SNAP_LINE = 2 61 | }; 62 | 63 | typedef unsigned char uchar; 64 | typedef unsigned int uint; 65 | typedef unsigned long ulong; 66 | typedef unsigned short ushort; 67 | 68 | typedef uint_least32_t Rune; 69 | 70 | #define Glyph Glyph_ 71 | typedef struct { 72 | Rune u; /* character code */ 73 | ushort mode; /* attribute flags */ 74 | uint32_t fg; /* foreground */ 75 | uint32_t bg; /* background */ 76 | } Glyph; 77 | 78 | typedef Glyph *Line; 79 | 80 | typedef union { 81 | int i; 82 | uint ui; 83 | float f; 84 | const void *v; 85 | const char *s; 86 | } Arg; 87 | 88 | void die(const char *, ...); 89 | void redraw(void); 90 | void draw(void); 91 | 92 | void kscrolldown(const Arg *); 93 | void kscrollup(const Arg *); 94 | void printscreen(const Arg *); 95 | void printsel(const Arg *); 96 | void sendbreak(const Arg *); 97 | void toggleprinter(const Arg *); 98 | 99 | int tattrset(int); 100 | void tnew(int, int); 101 | void tresize(int, int); 102 | void tsetdirtattr(int); 103 | void ttyhangup(void); 104 | int ttynew(const char *, char *, const char *, char **); 105 | size_t ttyread(void); 106 | void ttyresize(int, int); 107 | void ttywrite(const char *, size_t, int); 108 | 109 | void resettitle(void); 110 | 111 | void selclear(void); 112 | void selinit(void); 113 | void selstart(int, int, int); 114 | void selextend(int, int, int, int); 115 | int selected(int, int); 116 | char *getsel(void); 117 | 118 | size_t utf8encode(Rune, char *); 119 | 120 | void *xmalloc(size_t); 121 | void *xrealloc(void *, size_t); 122 | char *xstrdup(const char *); 123 | 124 | int isboxdraw(Rune); 125 | ushort boxdrawindex(const Glyph *); 126 | #ifdef XFT_VERSION 127 | /* only exposed to x.c, otherwise we'll need Xft.h for the types */ 128 | void boxdraw_xinit(Display *, Colormap, XftDraw *, Visual *); 129 | void drawboxes(int, int, int, int, XftColor *, XftColor *, const XftGlyphFontSpec *, int); 130 | #endif 131 | 132 | /* config.h globals */ 133 | extern char *utmp; 134 | extern char *scroll; 135 | extern char *stty_args; 136 | extern char *vtiden; 137 | extern wchar_t *worddelimiters; 138 | extern int allowaltscreen; 139 | extern int allowwindowops; 140 | extern char *termname; 141 | extern unsigned int tabspaces; 142 | extern unsigned int defaultfg; 143 | extern unsigned int defaultbg; 144 | extern unsigned int defaultcs; 145 | extern const int boxdraw, boxdraw_bold, boxdraw_braille; 146 | -------------------------------------------------------------------------------- /st.h.orig: -------------------------------------------------------------------------------- 1 | /* See LICENSE for license details. */ 2 | 3 | #include 4 | #include 5 | 6 | /* macros */ 7 | #define MIN(a, b) ((a) < (b) ? (a) : (b)) 8 | #define MAX(a, b) ((a) < (b) ? (b) : (a)) 9 | #define LEN(a) (sizeof(a) / sizeof(a)[0]) 10 | #define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b)) 11 | #define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d)) 12 | #define DEFAULT(a, b) (a) = (a) ? (a) : (b) 13 | #define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x) 14 | #define ATTRCMP(a, b) (((a).mode & (~ATTR_WRAP)) != ((b).mode & (~ATTR_WRAP)) || \ 15 | (a).fg != (b).fg || \ 16 | (a).bg != (b).bg) 17 | #define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + \ 18 | (t1.tv_nsec-t2.tv_nsec)/1E6) 19 | #define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit))) 20 | 21 | #define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b)) 22 | #define IS_TRUECOL(x) (1 << 24 & (x)) 23 | 24 | enum glyph_attribute { 25 | ATTR_NULL = 0, 26 | ATTR_BOLD = 1 << 0, 27 | ATTR_FAINT = 1 << 1, 28 | ATTR_ITALIC = 1 << 2, 29 | ATTR_UNDERLINE = 1 << 3, 30 | ATTR_BLINK = 1 << 4, 31 | ATTR_REVERSE = 1 << 5, 32 | ATTR_INVISIBLE = 1 << 6, 33 | ATTR_STRUCK = 1 << 7, 34 | ATTR_WRAP = 1 << 8, 35 | ATTR_WIDE = 1 << 9, 36 | ATTR_WDUMMY = 1 << 10, 37 | ATTR_BOXDRAW = 1 << 11, 38 | ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT, 39 | }; 40 | 41 | enum selection_mode { 42 | SEL_IDLE = 0, 43 | SEL_EMPTY = 1, 44 | SEL_READY = 2 45 | }; 46 | 47 | enum selection_type { 48 | SEL_REGULAR = 1, 49 | SEL_RECTANGULAR = 2 50 | }; 51 | 52 | enum selection_snap { 53 | SNAP_WORD = 1, 54 | SNAP_LINE = 2 55 | }; 56 | 57 | typedef unsigned char uchar; 58 | typedef unsigned int uint; 59 | typedef unsigned long ulong; 60 | typedef unsigned short ushort; 61 | 62 | typedef uint_least32_t Rune; 63 | 64 | #define Glyph Glyph_ 65 | typedef struct { 66 | Rune u; /* character code */ 67 | ushort mode; /* attribute flags */ 68 | uint32_t fg; /* foreground */ 69 | uint32_t bg; /* background */ 70 | } Glyph; 71 | 72 | typedef Glyph *Line; 73 | 74 | typedef union { 75 | int i; 76 | uint ui; 77 | float f; 78 | const void *v; 79 | const char *s; 80 | } Arg; 81 | 82 | void die(const char *, ...); 83 | void redraw(void); 84 | void draw(void); 85 | 86 | void kscrolldown(const Arg *); 87 | void kscrollup(const Arg *); 88 | void printscreen(const Arg *); 89 | void printsel(const Arg *); 90 | void sendbreak(const Arg *); 91 | void toggleprinter(const Arg *); 92 | 93 | int tattrset(int); 94 | void tnew(int, int); 95 | void tresize(int, int); 96 | void tsetdirtattr(int); 97 | void ttyhangup(void); 98 | int ttynew(const char *, char *, const char *, char **); 99 | size_t ttyread(void); 100 | void ttyresize(int, int); 101 | void ttywrite(const char *, size_t, int); 102 | 103 | void resettitle(void); 104 | 105 | void selclear(void); 106 | void selinit(void); 107 | void selstart(int, int, int); 108 | void selextend(int, int, int, int); 109 | int selected(int, int); 110 | char *getsel(void); 111 | 112 | size_t utf8encode(Rune, char *); 113 | 114 | void *xmalloc(size_t); 115 | void *xrealloc(void *, size_t); 116 | char *xstrdup(const char *); 117 | 118 | int isboxdraw(Rune); 119 | ushort boxdrawindex(const Glyph *); 120 | #ifdef XFT_VERSION 121 | /* only exposed to x.c, otherwise we'll need Xft.h for the types */ 122 | void boxdraw_xinit(Display *, Colormap, XftDraw *, Visual *); 123 | void drawboxes(int, int, int, int, XftColor *, XftColor *, const XftGlyphFontSpec *, int); 124 | #endif 125 | 126 | /* config.h globals */ 127 | extern char *utmp; 128 | extern char *scroll; 129 | extern char *stty_args; 130 | extern char *vtiden; 131 | extern wchar_t *worddelimiters; 132 | extern int allowaltscreen; 133 | extern int allowwindowops; 134 | extern char *termname; 135 | extern unsigned int tabspaces; 136 | extern unsigned int defaultfg; 137 | extern unsigned int defaultbg; 138 | extern unsigned int defaultcs; 139 | extern const int boxdraw, boxdraw_bold, boxdraw_braille; 140 | -------------------------------------------------------------------------------- /st.info: -------------------------------------------------------------------------------- 1 | st-mono| simpleterm monocolor, 2 | acsc=+C\,D-A.B0E``aaffgghFiGjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~, 3 | am, 4 | bce, 5 | bel=^G, 6 | blink=\E[5m, 7 | bold=\E[1m, 8 | cbt=\E[Z, 9 | cvvis=\E[?25h, 10 | civis=\E[?25l, 11 | clear=\E[H\E[2J, 12 | cnorm=\E[?12l\E[?25h, 13 | colors#2, 14 | cols#80, 15 | cr=^M, 16 | csr=\E[%i%p1%d;%p2%dr, 17 | cub=\E[%p1%dD, 18 | cub1=^H, 19 | cud1=^J, 20 | cud=\E[%p1%dB, 21 | cuf1=\E[C, 22 | cuf=\E[%p1%dC, 23 | cup=\E[%i%p1%d;%p2%dH, 24 | cuu1=\E[A, 25 | cuu=\E[%p1%dA, 26 | dch=\E[%p1%dP, 27 | dch1=\E[P, 28 | dim=\E[2m, 29 | dl=\E[%p1%dM, 30 | dl1=\E[M, 31 | ech=\E[%p1%dX, 32 | ed=\E[J, 33 | el=\E[K, 34 | el1=\E[1K, 35 | enacs=\E)0, 36 | flash=\E[?5h$<80/>\E[?5l, 37 | fsl=^G, 38 | home=\E[H, 39 | hpa=\E[%i%p1%dG, 40 | hs, 41 | ht=^I, 42 | hts=\EH, 43 | ich=\E[%p1%d@, 44 | il1=\E[L, 45 | il=\E[%p1%dL, 46 | ind=^J, 47 | indn=\E[%p1%dS, 48 | invis=\E[8m, 49 | is2=\E[4l\E>\E[?1034l, 50 | it#8, 51 | kel=\E[1;2F, 52 | ked=\E[1;5F, 53 | ka1=\E[1~, 54 | ka3=\E[5~, 55 | kc1=\E[4~, 56 | kc3=\E[6~, 57 | kbs=\177, 58 | kcbt=\E[Z, 59 | kb2=\EOu, 60 | kcub1=\EOD, 61 | kcud1=\EOB, 62 | kcuf1=\EOC, 63 | kcuu1=\EOA, 64 | kDC=\E[3;2~, 65 | kent=\EOM, 66 | kEND=\E[1;2F, 67 | kIC=\E[2;2~, 68 | kNXT=\E[6;2~, 69 | kPRV=\E[5;2~, 70 | kHOM=\E[1;2H, 71 | kLFT=\E[1;2D, 72 | kRIT=\E[1;2C, 73 | kind=\E[1;2B, 74 | kri=\E[1;2A, 75 | kclr=\E[3;5~, 76 | kdl1=\E[3;2~, 77 | kdch1=\E[3~, 78 | kich1=\E[2~, 79 | kend=\E[4~, 80 | kf1=\EOP, 81 | kf2=\EOQ, 82 | kf3=\EOR, 83 | kf4=\EOS, 84 | kf5=\E[15~, 85 | kf6=\E[17~, 86 | kf7=\E[18~, 87 | kf8=\E[19~, 88 | kf9=\E[20~, 89 | kf10=\E[21~, 90 | kf11=\E[23~, 91 | kf12=\E[24~, 92 | kf13=\E[1;2P, 93 | kf14=\E[1;2Q, 94 | kf15=\E[1;2R, 95 | kf16=\E[1;2S, 96 | kf17=\E[15;2~, 97 | kf18=\E[17;2~, 98 | kf19=\E[18;2~, 99 | kf20=\E[19;2~, 100 | kf21=\E[20;2~, 101 | kf22=\E[21;2~, 102 | kf23=\E[23;2~, 103 | kf24=\E[24;2~, 104 | kf25=\E[1;5P, 105 | kf26=\E[1;5Q, 106 | kf27=\E[1;5R, 107 | kf28=\E[1;5S, 108 | kf29=\E[15;5~, 109 | kf30=\E[17;5~, 110 | kf31=\E[18;5~, 111 | kf32=\E[19;5~, 112 | kf33=\E[20;5~, 113 | kf34=\E[21;5~, 114 | kf35=\E[23;5~, 115 | kf36=\E[24;5~, 116 | kf37=\E[1;6P, 117 | kf38=\E[1;6Q, 118 | kf39=\E[1;6R, 119 | kf40=\E[1;6S, 120 | kf41=\E[15;6~, 121 | kf42=\E[17;6~, 122 | kf43=\E[18;6~, 123 | kf44=\E[19;6~, 124 | kf45=\E[20;6~, 125 | kf46=\E[21;6~, 126 | kf47=\E[23;6~, 127 | kf48=\E[24;6~, 128 | kf49=\E[1;3P, 129 | kf50=\E[1;3Q, 130 | kf51=\E[1;3R, 131 | kf52=\E[1;3S, 132 | kf53=\E[15;3~, 133 | kf54=\E[17;3~, 134 | kf55=\E[18;3~, 135 | kf56=\E[19;3~, 136 | kf57=\E[20;3~, 137 | kf58=\E[21;3~, 138 | kf59=\E[23;3~, 139 | kf60=\E[24;3~, 140 | kf61=\E[1;4P, 141 | kf62=\E[1;4Q, 142 | kf63=\E[1;4R, 143 | khome=\E[1~, 144 | kil1=\E[2;5~, 145 | krmir=\E[2;2~, 146 | knp=\E[6~, 147 | kmous=\E[M, 148 | kpp=\E[5~, 149 | lines#24, 150 | mir, 151 | msgr, 152 | npc, 153 | op=\E[39;49m, 154 | pairs#64, 155 | mc0=\E[i, 156 | mc4=\E[4i, 157 | mc5=\E[5i, 158 | rc=\E8, 159 | rev=\E[7m, 160 | ri=\EM, 161 | rin=\E[%p1%dT, 162 | ritm=\E[23m, 163 | rmacs=\E(B, 164 | rmcup=\E[?1049l, 165 | rmir=\E[4l, 166 | rmkx=\E[?1l\E>, 167 | rmso=\E[27m, 168 | rmul=\E[24m, 169 | rs1=\Ec, 170 | rs2=\E[4l\E>\E[?1034l, 171 | sc=\E7, 172 | sitm=\E[3m, 173 | sgr0=\E[0m, 174 | smacs=\E(0, 175 | smcup=\E[?1049h, 176 | smir=\E[4h, 177 | smkx=\E[?1h\E=, 178 | smso=\E[7m, 179 | smul=\E[4m, 180 | tbc=\E[3g, 181 | tsl=\E]0;, 182 | xenl, 183 | vpa=\E[%i%p1%dd, 184 | # XTerm extensions 185 | rmxx=\E[29m, 186 | smxx=\E[9m, 187 | # disabled rep for now: causes some issues with older ncurses versions. 188 | # rep=%p1%c\E[%p2%{1}%-%db, 189 | # tmux extensions, see TERMINFO EXTENSIONS in tmux(1) 190 | Tc, 191 | Ms=\E]52;%p1%s;%p2%s\007, 192 | Se=\E[2 q, 193 | Ss=\E[%p1%d q, 194 | 195 | st| simpleterm, 196 | use=st-mono, 197 | colors#8, 198 | setab=\E[4%p1%dm, 199 | setaf=\E[3%p1%dm, 200 | setb=\E[4%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m, 201 | setf=\E[3%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m, 202 | sgr=%?%p9%t\E(0%e\E(B%;\E[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m, 203 | 204 | st-256color| simpleterm with 256 colors, 205 | use=st, 206 | ccc, 207 | colors#256, 208 | oc=\E]104\007, 209 | pairs#32767, 210 | # Nicked from xterm-256color 211 | initc=\E]4;%p1%d;rgb\:%p2%{255}%*%{1000}%/%2.2X/%p3%{255}%*%{1000}%/%2.2X/%p4%{255}%*%{1000}%/%2.2X\E\\, 212 | setab=\E[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m, 213 | setaf=\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m, 214 | 215 | st-meta| simpleterm with meta key, 216 | use=st, 217 | km, 218 | rmm=\E[?1034l, 219 | smm=\E[?1034h, 220 | rs2=\E[4l\E>\E[?1034h, 221 | is2=\E[4l\E>\E[?1034h, 222 | 223 | st-meta-256color| simpleterm with meta key and 256 colors, 224 | use=st-256color, 225 | km, 226 | rmm=\E[?1034l, 227 | smm=\E[?1034h, 228 | rs2=\E[4l\E>\E[?1034h, 229 | is2=\E[4l\E>\E[?1034h, 230 | 231 | st-bs| simpleterm with backspace as backspace, 232 | use=st, 233 | kbs=\010, 234 | kdch1=\177, 235 | 236 | st-bs-256color| simpleterm with backspace as backspace and 256colors, 237 | use=st-256color, 238 | kbs=\010, 239 | kdch1=\177, 240 | -------------------------------------------------------------------------------- /st.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motolla/st/80a40a50d86193c9524ca91ae73bba192ad9a9d1/st.o -------------------------------------------------------------------------------- /stclean: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | cp config.def.h config.h; make; sudo make install 3 | -------------------------------------------------------------------------------- /win.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE for license details. */ 2 | 3 | enum win_mode { 4 | MODE_VISIBLE = 1 << 0, 5 | MODE_FOCUSED = 1 << 1, 6 | MODE_APPKEYPAD = 1 << 2, 7 | MODE_MOUSEBTN = 1 << 3, 8 | MODE_MOUSEMOTION = 1 << 4, 9 | MODE_REVERSE = 1 << 5, 10 | MODE_KBDLOCK = 1 << 6, 11 | MODE_HIDE = 1 << 7, 12 | MODE_APPCURSOR = 1 << 8, 13 | MODE_MOUSESGR = 1 << 9, 14 | MODE_8BIT = 1 << 10, 15 | MODE_BLINK = 1 << 11, 16 | MODE_FBLINK = 1 << 12, 17 | MODE_FOCUS = 1 << 13, 18 | MODE_MOUSEX10 = 1 << 14, 19 | MODE_MOUSEMANY = 1 << 15, 20 | MODE_BRCKTPASTE = 1 << 16, 21 | MODE_NUMLOCK = 1 << 17, 22 | MODE_MOUSE = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\ 23 | |MODE_MOUSEMANY, 24 | }; 25 | 26 | void xbell(void); 27 | void xclipcopy(void); 28 | void xdrawcursor(int, int, Glyph, int, int, Glyph, Line, int); 29 | void xdrawline(Line, int, int, int); 30 | void xfinishdraw(void); 31 | void xloadcols(void); 32 | int xsetcolorname(int, const char *); 33 | int xgetcolor(int, unsigned char *, unsigned char *, unsigned char *); 34 | void xseticontitle(char *); 35 | void xsettitle(char *); 36 | int xsetcursor(int); 37 | void xsetmode(int, unsigned int); 38 | void xsetpointermotion(int); 39 | void xsetsel(char *); 40 | int xstartdraw(void); 41 | void xximspot(int, int); 42 | -------------------------------------------------------------------------------- /x.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/motolla/st/80a40a50d86193c9524ca91ae73bba192ad9a9d1/x.o --------------------------------------------------------------------------------