commit 169e41e68736aa884f3b1894ffc5735f70e0edcd
parent a33adc1618a3932a9e2ef800f45dee20f27d129c
Author: Kris Yotam <krisyotam@protonmail.com>
Date: Fri, 13 Feb 2026 04:19:06 -0600
Migrate to st-flexipatch with sixel support
Switch from manually patched st to st-flexipatch (bakkeby/st-flexipatch).
This uses preprocessor directives in patches.h to toggle patches at
compile time, making it much easier to add/remove features.
Enabled patches:
- alpha (transparency)
- anygeometry, anysize (dynamic borders)
- blinking_cursor
- boxdraw (box-drawing chars)
- clipboard
- columns (no text cut on resize)
- copyurl
- externalpipe
- font2 (fallback fonts)
- iso14755 (unicode input)
- ligatures (HarfBuzz)
- newterm (spawn in cwd)
- scrollback + scrollback_mouse
- sixel (NEW - for manga-tui image support)
- swapmouse
- sync
- xresources + xresources_reload
To toggle patches: edit patches.h and rebuild.
See README.md for documentation on the preprocessor system.
Diffstat:
95 files changed, 12575 insertions(+), 2607 deletions(-)
diff --git a/LICENSE b/LICENSE
@@ -1,6 +1,6 @@
MIT/X Consortium License
-© 2014-2018 Hiltjo Posthuma <hiltjo at codemadness dot org>
+© 2014-2022 Hiltjo Posthuma <hiltjo at codemadness dot org>
© 2018 Devin J. Pohly <djpohly at gmail dot com>
© 2014-2017 Quentin Rameau <quinq at fifth dot space>
© 2009-2012 Aurélien APTEL <aurelien dot aptel at gmail dot com>
diff --git a/Makefile b/Makefile
@@ -4,40 +4,35 @@
include config.mk
-SRC = st.c x.c boxdraw.c hb.c
+SRC = st.c x.c $(LIGATURES_C) $(SIXEL_C)
OBJ = $(SRC:.c=.o)
-all: options st
-
-options:
- @echo st build options:
- @echo "CFLAGS = $(STCFLAGS)"
- @echo "LDFLAGS = $(STLDFLAGS)"
- @echo "CC = $(CC)"
+all: st
config.h:
cp config.def.h config.h
+patches.h:
+ cp patches.def.h patches.h
+
.c.o:
$(CC) $(STCFLAGS) -c $<
st.o: config.h st.h win.h
-x.o: arg.h config.h st.h win.h hb.h
-hb.o: st.h
-boxdraw.o: config.h st.h boxdraw_data.h
+x.o: arg.h config.h st.h win.h $(LIGATURES_H)
-$(OBJ): config.h config.mk
+$(OBJ): config.h config.mk patches.h
st: $(OBJ)
$(CC) -o $@ $(OBJ) $(STLDFLAGS)
clean:
- rm -f st $(OBJ) st-$(VERSION).tar.gz *.o *.orig *.rej
+ rm -f st $(OBJ) st-$(VERSION).tar.gz
dist: clean
mkdir -p st-$(VERSION)
cp -R FAQ LEGACY TODO LICENSE Makefile README config.mk\
- config.def.h st.info st.1 arg.h st.h win.h $(SRC)\
+ config.def.h st.info st.1 arg.h st.h win.h $(LIGATURES_H) $(SRC)\
st-$(VERSION)
tar -cf - st-$(VERSION) | gzip > st-$(VERSION).tar.gz
rm -rf st-$(VERSION)
@@ -45,27 +40,18 @@ dist: clean
install: st
mkdir -p $(DESTDIR)$(PREFIX)/bin
cp -f st $(DESTDIR)$(PREFIX)/bin
- cp -f st-copyout $(DESTDIR)$(PREFIX)/bin
- cp -f st-urlhandler $(DESTDIR)$(PREFIX)/bin
chmod 755 $(DESTDIR)$(PREFIX)/bin/st
- chmod 755 $(DESTDIR)$(PREFIX)/bin/st-copyout
- chmod 755 $(DESTDIR)$(PREFIX)/bin/st-urlhandler
mkdir -p $(DESTDIR)$(MANPREFIX)/man1
sed "s/VERSION/$(VERSION)/g" < st.1 > $(DESTDIR)$(MANPREFIX)/man1/st.1
chmod 644 $(DESTDIR)$(MANPREFIX)/man1/st.1
tic -sx st.info
+ mkdir -p $(DESTDIR)$(PREFIX)/share/applications # desktop-entry patch
+ test -f ${DESTDIR}${PREFIX}/share/applications/st.desktop || cp -n st.desktop $(DESTDIR)$(PREFIX)/share/applications # desktop-entry patch
@echo Please see the README file regarding the terminfo entry of st.
- mkdir -p $(DESTDIR)$(ICONPREFIX)
- [ -f $(ICONNAME) ] && cp -f $(ICONNAME) $(DESTDIR)$(ICONPREFIX) || :
- mkdir -p $(DESTDIR)$(PREFIX)/share/applications
- cp -f st.desktop $(DESTDIR)$(PREFIX)/share/applications
uninstall:
rm -f $(DESTDIR)$(PREFIX)/bin/st
- rm -f $(DESTDIR)$(PREFIX)/bin/st-copyout
- rm -f $(DESTDIR)$(PREFIX)/bin/st-urlhandler
rm -f $(DESTDIR)$(MANPREFIX)/man1/st.1
- rm -f $(DESTDIR)$(ICONPREFIX)/$(ICONNAME)
- rm -f $(DESTDIR)$(PREFIX)/share/applications/st.desktop
+ rm -f $(DESTDIR)$(PREFIX)/share/applications/st.desktop # desktop-entry patch
-.PHONY: all options clean dist install uninstall
+.PHONY: all clean dist install uninstall
diff --git a/README.md b/README.md
@@ -1,7 +1,27 @@
-# Kris's build of st
+# Kris's build of st (flexipatch)
The [suckless terminal (st)](https://st.suckless.org/) with additional features that make it the best terminal emulator.
+This build is based on [st-flexipatch](https://github.com/bakkeby/st-flexipatch), which uses preprocessor directives to manage patches. This allows easy toggling of features without manual patching.
+
+---
+
+## How Patches Work (Preprocessor Directives)
+
+Unlike traditional st patching, this build uses C preprocessor directives to include/exclude patches at compile time. To enable or disable a patch, edit `patches.h` and set the value to `1` (enabled) or `0` (disabled):
+
+```c
+#define ALPHA_PATCH 1 /* enabled */
+#define FULLSCREEN_PATCH 0 /* disabled */
+```
+
+Then rebuild:
+```bash
+sudo make clean install
+```
+
+All patch options are documented in `patches.h`. The actual code for each patch lives in the source files, wrapped in `#if PATCH_NAME ... #endif` blocks.
+
---
## Features
@@ -10,16 +30,18 @@ The [suckless terminal (st)](https://st.suckless.org/) with additional features
| Keybinding | Action |
|------------|--------|
-| `Ctrl+Shift+c` | Copy selection |
-| `Ctrl+Shift+v` | Paste |
+| `Ctrl+c` or `Ctrl+Shift+c` | Copy selection |
+| `Ctrl+v` or `Ctrl+Shift+v` | Paste |
| `Right Click` | Paste from clipboard |
### Scrollback
| Keybinding | Action |
|------------|--------|
-| `Alt+k` | Scroll up |
-| `Alt+j` | Scroll down |
+| `Alt+k` / `Alt+Up` | Scroll up (1 line) |
+| `Alt+j` / `Alt+Down` | Scroll down (1 line) |
+| `Alt+u` / `Alt+PageUp` | Scroll up (page) |
+| `Alt+d` / `Alt+PageDown` | Scroll down (page) |
### Font & Zoom
@@ -28,6 +50,8 @@ The [suckless terminal (st)](https://st.suckless.org/) with additional features
| `Alt+,` | Zoom in |
| `Alt+.` | Zoom out |
| `Alt+g` | Reset to default size |
+| `Super+Shift+K/J` | Zoom in/out |
+| `Super+Shift+U/D` | Zoom in/out (2x) |
### Transparency
@@ -35,41 +59,60 @@ The [suckless terminal (st)](https://st.suckless.org/) with additional features
|------------|--------|
| `Alt+s` | Increase transparency |
| `Alt+a` | Decrease transparency |
-| `Alt+m` | Reset transparency |
+| `Alt+m` | Reset transparency (opaque) |
+
+### External Pipe
+
+| Keybinding | Action |
+|------------|--------|
+| `Alt+l` | Open URL handler |
+| `Alt+y` | Copy URL to clipboard |
+| `Alt+o` | Copy terminal output |
### Other
| Keybinding | Action |
|------------|--------|
-| `Mod+Shift+Enter` | Spawn new terminal in current directory |
+| `Super+Shift+Enter` | Spawn new terminal in current directory |
+| `Ctrl+Shift+U` | Unicode input (ISO 14755) |
---
-## Patches
+## Enabled Patches
+
+Configured in `patches.h`:
| Patch | Description |
|-------|-------------|
-| ligatures | HarfBuzz ligature support |
-| sixel | Sixel graphics support (check sixel branch) |
-| scrollback | Scroll history |
-| clipboard | Clipboard integration |
| alpha | Transparency support with configurable opacity |
+| anygeometry | Dynamic geometry/borders |
+| anysize | Resize to any pixel size |
+| blinking_cursor | Cursor blinking support |
| boxdraw | Render box-drawing characters without font glyphs |
-| patch_column | Doesn't cut text while resizing |
+| clipboard | Clipboard integration (CLIPBOARD on selection) |
+| columns | Doesn't cut text while resizing |
+| copyurl | Select and copy URLs |
+| externalpipe | Pipe terminal content to external commands |
| font2 | Secondary font support (emoji fallback) |
-| right click paste | Paste with right click |
+| iso14755 | Unicode input via dmenu |
+| ligatures | HarfBuzz ligature support |
| newterm | Spawn new terminal in current directory |
-| anygeometry | Dynamic geometry/borders |
-| xresources | Live reload colors/settings from Xresources |
-| sync | Better draw timing to reduce flicker/tearing |
-| live reload | Change colors/fonts on the fly |
+| scrollback | Scroll history |
+| scrollback_mouse | Scroll with mouse wheel + Shift |
+| scrollback_mouse_altscreen | Mouse scroll in alternate screen |
+| **sixel** | **Sixel graphics support (for manga-tui, etc.)** |
| swapmouse | Swap mouse buttons |
+| sync | Synchronized updates to reduce flicker |
+| xresources | Load settings from Xresources |
+| xresources_reload | Live reload on SIGUSR1 |
---
## Appearance
- **Default font:** JetBrainsMono Nerd Font
+- **Color scheme:** Gruvbox Dark
+- **Transparency:** 85% (configurable)
- **Xresources:** Supports dynamic colors via `~/.Xdefaults` or `~/.Xresources`
- **Live reload:** `xrdb merge ~/.Xresources && kill -USR1 $(pidof st)`
@@ -81,16 +124,16 @@ The [suckless terminal (st)](https://st.suckless.org/) with additional features
```bash
# Arch
-pacman -S gd
+pacman -S harfbuzz imlib2 libxft fontconfig freetype2
# Debian/Ubuntu
-apt install build-essential libxft-dev libharfbuzz-dev libgd-dev
+apt install build-essential libxft-dev libharfbuzz-dev libimlib2-dev
# Fedora
-dnf install gd-devel libXft-devel
+dnf install harfbuzz-devel imlib2-devel libXft-devel
# Void
-xbps-install libXft-devel libX11-devel harfbuzz-devel libXext-devel libXrender-devel libXinerama-devel gd-devel
+xbps-install libXft-devel libX11-devel harfbuzz-devel imlib2-devel
```
### Build
@@ -98,7 +141,7 @@ xbps-install libXft-devel libX11-devel harfbuzz-devel libXext-devel libXrender-d
```bash
git clone https://github.com/krisyotam/st
cd st
-sudo make install
+sudo make clean install
xrdb merge ~/.Xresources
```
@@ -110,6 +153,29 @@ xrdb merge ~/.Xresources
## Configuration
+### Enabling/Disabling Patches
+
+Edit `patches.h` to toggle patches:
+
+```c
+#define SIXEL_PATCH 1 /* Enable sixel graphics */
+#define FULLSCREEN_PATCH 0 /* Disable fullscreen */
+```
+
+### Customizing Settings
+
+Edit `config.def.h` for:
+- Font settings
+- Colors (Gruvbox by default)
+- Keyboard shortcuts
+- Transparency level
+- External pipe commands
+
+After editing, rebuild:
+```bash
+rm config.h && sudo make clean install
+```
+
### Xresources
This build reads settings from `~/.Xdefaults` or `~/.Xresources`. Changes reload live with:
@@ -118,6 +184,27 @@ This build reads settings from `~/.Xdefaults` or `~/.Xresources`. Changes reload
xrdb merge ~/.Xresources && kill -USR1 $(pidof st)
```
+Example Xresources:
+```
+st.font: JetBrainsMono Nerd Font:pixelsize=15
+st.alpha: 0.85
+st.color0: #282828
+st.background: #282828
+st.foreground: #ffffff
+```
+
+---
+
+## Sixel Graphics
+
+This build includes sixel support for displaying images in the terminal. Applications like `manga-tui` can render images directly in st.
+
+To verify sixel support:
+```bash
+# If you have libsixel installed
+img2sixel /path/to/image.png
+```
+
---
## Other Suckless Repos
@@ -125,6 +212,14 @@ xrdb merge ~/.Xresources && kill -USR1 $(pidof st)
- [dwm](https://github.com/krisyotam/dwm) - dynamic window manager
- [dwmblocks](https://github.com/krisyotam/dwmblocks) - modular status bar
- [surf](https://github.com/krisyotam/surf) - simple web browser
+- [dmenu](https://github.com/krisyotam/dmenu) - application launcher
+
+---
+
+## Credits
+
+- Based on [st-flexipatch](https://github.com/bakkeby/st-flexipatch) by bakkeby
+- [suckless.org](https://st.suckless.org/) for the original st
---
diff --git a/boxdraw.c b/boxdraw.c
@@ -1,194 +0,0 @@
-/*
- * Copyright 2018 Avi Halachmi (:avih) avihpit@yahoo.com https://github.com/avih
- * MIT/X Consortium License
- */
-
-#include <X11/Xft/Xft.h>
-#include "st.h"
-#include "boxdraw_data.h"
-
-/* Rounded non-negative integers division of n / d */
-#define DIV(n, d) (((n) + (d) / 2) / (d))
-
-static Display *xdpy;
-static Colormap xcmap;
-static XftDraw *xd;
-static Visual *xvis;
-
-static void drawbox(int, int, int, int, XftColor *, XftColor *, ushort);
-static void drawboxlines(int, int, int, int, XftColor *, ushort);
-
-/* public API */
-
-void
-boxdraw_xinit(Display *dpy, Colormap cmap, XftDraw *draw, Visual *vis)
-{
- xdpy = dpy; xcmap = cmap; xd = draw, xvis = vis;
-}
-
-int
-isboxdraw(Rune u)
-{
- Rune block = u & ~0xff;
- return (boxdraw && block == 0x2500 && boxdata[(uint8_t)u]) ||
- (boxdraw_braille && block == 0x2800);
-}
-
-/* the "index" is actually the entire shape data encoded as ushort */
-ushort
-boxdrawindex(const Glyph *g)
-{
- if (boxdraw_braille && (g->u & ~0xff) == 0x2800)
- return BRL | (uint8_t)g->u;
- if (boxdraw_bold && (g->mode & ATTR_BOLD))
- return BDB | boxdata[(uint8_t)g->u];
- return boxdata[(uint8_t)g->u];
-}
-
-void
-drawboxes(int x, int y, int cw, int ch, XftColor *fg, XftColor *bg,
- const XftGlyphFontSpec *specs, int len)
-{
- for ( ; len-- > 0; x += cw, specs++)
- drawbox(x, y, cw, ch, fg, bg, (ushort)specs->glyph);
-}
-
-/* implementation */
-
-void
-drawbox(int x, int y, int w, int h, XftColor *fg, XftColor *bg, ushort bd)
-{
- ushort cat = bd & ~(BDB | 0xff); /* mask out bold and data */
- if (bd & (BDL | BDA)) {
- /* lines (light/double/heavy/arcs) */
- drawboxlines(x, y, w, h, fg, bd);
-
- } else if (cat == BBD) {
- /* lower (8-X)/8 block */
- int d = DIV((uint8_t)bd * h, 8);
- XftDrawRect(xd, fg, x, y + d, w, h - d);
-
- } else if (cat == BBU) {
- /* upper X/8 block */
- XftDrawRect(xd, fg, x, y, w, DIV((uint8_t)bd * h, 8));
-
- } else if (cat == BBL) {
- /* left X/8 block */
- XftDrawRect(xd, fg, x, y, DIV((uint8_t)bd * w, 8), h);
-
- } else if (cat == BBR) {
- /* right (8-X)/8 block */
- int d = DIV((uint8_t)bd * w, 8);
- XftDrawRect(xd, fg, x + d, y, w - d, h);
-
- } else if (cat == BBQ) {
- /* Quadrants */
- int w2 = DIV(w, 2), h2 = DIV(h, 2);
- if (bd & TL)
- XftDrawRect(xd, fg, x, y, w2, h2);
- if (bd & TR)
- XftDrawRect(xd, fg, x + w2, y, w - w2, h2);
- if (bd & BL)
- XftDrawRect(xd, fg, x, y + h2, w2, h - h2);
- if (bd & BR)
- XftDrawRect(xd, fg, x + w2, y + h2, w - w2, h - h2);
-
- } else if (bd & BBS) {
- /* Shades - data is 1/2/3 for 25%/50%/75% alpha, respectively */
- int d = (uint8_t)bd;
- XftColor xfc;
- XRenderColor xrc = { .alpha = 0xffff };
-
- xrc.red = DIV(fg->color.red * d + bg->color.red * (4 - d), 4);
- xrc.green = DIV(fg->color.green * d + bg->color.green * (4 - d), 4);
- xrc.blue = DIV(fg->color.blue * d + bg->color.blue * (4 - d), 4);
-
- XftColorAllocValue(xdpy, xvis, xcmap, &xrc, &xfc);
- XftDrawRect(xd, &xfc, x, y, w, h);
- XftColorFree(xdpy, xvis, xcmap, &xfc);
-
- } else if (cat == BRL) {
- /* braille, each data bit corresponds to one dot at 2x4 grid */
- int w1 = DIV(w, 2);
- int h1 = DIV(h, 4), h2 = DIV(h, 2), h3 = DIV(3 * h, 4);
-
- if (bd & 1) XftDrawRect(xd, fg, x, y, w1, h1);
- if (bd & 2) XftDrawRect(xd, fg, x, y + h1, w1, h2 - h1);
- if (bd & 4) XftDrawRect(xd, fg, x, y + h2, w1, h3 - h2);
- if (bd & 8) XftDrawRect(xd, fg, x + w1, y, w - w1, h1);
- if (bd & 16) XftDrawRect(xd, fg, x + w1, y + h1, w - w1, h2 - h1);
- if (bd & 32) XftDrawRect(xd, fg, x + w1, y + h2, w - w1, h3 - h2);
- if (bd & 64) XftDrawRect(xd, fg, x, y + h3, w1, h - h3);
- if (bd & 128) XftDrawRect(xd, fg, x + w1, y + h3, w - w1, h - h3);
-
- }
-}
-
-void
-drawboxlines(int x, int y, int w, int h, XftColor *fg, ushort bd)
-{
- /* s: stem thickness. width/8 roughly matches underscore thickness. */
- /* We draw bold as 1.5 * normal-stem and at least 1px thicker. */
- /* doubles draw at least 3px, even when w or h < 3. bold needs 6px. */
- int mwh = MIN(w, h);
- int base_s = MAX(1, DIV(mwh, 8));
- int bold = (bd & BDB) && mwh >= 6; /* possibly ignore boldness */
- int s = bold ? MAX(base_s + 1, DIV(3 * base_s, 2)) : base_s;
- int w2 = DIV(w - s, 2), h2 = DIV(h - s, 2);
- /* the s-by-s square (x + w2, y + h2, s, s) is the center texel. */
- /* The base length (per direction till edge) includes this square. */
-
- int light = bd & (LL | LU | LR | LD);
- int double_ = bd & (DL | DU | DR | DD);
-
- if (light) {
- /* d: additional (negative) length to not-draw the center */
- /* texel - at arcs and avoid drawing inside (some) doubles */
- int arc = bd & BDA;
- int multi_light = light & (light - 1);
- int multi_double = double_ & (double_ - 1);
- /* light crosses double only at DH+LV, DV+LH (ref. shapes) */
- int d = arc || (multi_double && !multi_light) ? -s : 0;
-
- if (bd & LL)
- XftDrawRect(xd, fg, x, y + h2, w2 + s + d, s);
- if (bd & LU)
- XftDrawRect(xd, fg, x + w2, y, s, h2 + s + d);
- if (bd & LR)
- XftDrawRect(xd, fg, x + w2 - d, y + h2, w - w2 + d, s);
- if (bd & LD)
- XftDrawRect(xd, fg, x + w2, y + h2 - d, s, h - h2 + d);
- }
-
- /* double lines - also align with light to form heavy when combined */
- if (double_) {
- /*
- * going clockwise, for each double-ray: p is additional length
- * to the single-ray nearer to the previous direction, and n to
- * the next. p and n adjust from the base length to lengths
- * which consider other doubles - shorter to avoid intersections
- * (p, n), or longer to draw the far-corner texel (n).
- */
- int dl = bd & DL, du = bd & DU, dr = bd & DR, dd = bd & DD;
- if (dl) {
- int p = dd ? -s : 0, n = du ? -s : dd ? s : 0;
- XftDrawRect(xd, fg, x, y + h2 + s, w2 + s + p, s);
- XftDrawRect(xd, fg, x, y + h2 - s, w2 + s + n, s);
- }
- if (du) {
- int p = dl ? -s : 0, n = dr ? -s : dl ? s : 0;
- XftDrawRect(xd, fg, x + w2 - s, y, s, h2 + s + p);
- XftDrawRect(xd, fg, x + w2 + s, y, s, h2 + s + n);
- }
- if (dr) {
- int p = du ? -s : 0, n = dd ? -s : du ? s : 0;
- XftDrawRect(xd, fg, x + w2 - p, y + h2 - s, w - w2 + p, s);
- XftDrawRect(xd, fg, x + w2 - n, y + h2 + s, w - w2 + n, s);
- }
- if (dd) {
- int p = dr ? -s : 0, n = dl ? -s : dr ? s : 0;
- XftDrawRect(xd, fg, x + w2 + s, y + h2 - p, s, h - h2 + p);
- XftDrawRect(xd, fg, x + w2 - s, y + h2 - n, s, h - h2 + n);
- }
- }
-}
diff --git a/boxdraw_data.h b/boxdraw_data.h
@@ -1,214 +0,0 @@
-/*
- * Copyright 2018 Avi Halachmi (:avih) avihpit@yahoo.com https://github.com/avih
- * MIT/X Consortium License
- */
-
-/*
- * U+25XX codepoints data
- *
- * References:
- * http://www.unicode.org/charts/PDF/U2500.pdf
- * http://www.unicode.org/charts/PDF/U2580.pdf
- *
- * Test page:
- * https://github.com/GNOME/vte/blob/master/doc/boxes.txt
- */
-
-/* Each shape is encoded as 16-bits. Higher bits are category, lower are data */
-/* Categories (mutually exclusive except BDB): */
-/* For convenience, BDL/BDA/BBS/BDB are 1 bit each, the rest are enums */
-#define BDL (1<<8) /* Box Draw Lines (light/double/heavy) */
-#define BDA (1<<9) /* Box Draw Arc (light) */
-
-#define BBD (1<<10) /* Box Block Down (lower) X/8 */
-#define BBL (2<<10) /* Box Block Left X/8 */
-#define BBU (3<<10) /* Box Block Upper X/8 */
-#define BBR (4<<10) /* Box Block Right X/8 */
-#define BBQ (5<<10) /* Box Block Quadrants */
-#define BRL (6<<10) /* Box Braille (data is lower byte of U28XX) */
-
-#define BBS (1<<14) /* Box Block Shades */
-#define BDB (1<<15) /* Box Draw is Bold */
-
-/* (BDL/BDA) Light/Double/Heavy x Left/Up/Right/Down/Horizontal/Vertical */
-/* Heavy is light+double (literally drawing light+double align to form heavy) */
-#define LL (1<<0)
-#define LU (1<<1)
-#define LR (1<<2)
-#define LD (1<<3)
-#define LH (LL+LR)
-#define LV (LU+LD)
-
-#define DL (1<<4)
-#define DU (1<<5)
-#define DR (1<<6)
-#define DD (1<<7)
-#define DH (DL+DR)
-#define DV (DU+DD)
-
-#define HL (LL+DL)
-#define HU (LU+DU)
-#define HR (LR+DR)
-#define HD (LD+DD)
-#define HH (HL+HR)
-#define HV (HU+HD)
-
-/* (BBQ) Quadrants Top/Bottom x Left/Right */
-#define TL (1<<0)
-#define TR (1<<1)
-#define BL (1<<2)
-#define BR (1<<3)
-
-/* Data for U+2500 - U+259F except dashes/diagonals */
-static const unsigned short boxdata[256] = {
- /* light lines */
- [0x00] = BDL + LH, /* light horizontal */
- [0x02] = BDL + LV, /* light vertical */
- [0x0c] = BDL + LD + LR, /* light down and right */
- [0x10] = BDL + LD + LL, /* light down and left */
- [0x14] = BDL + LU + LR, /* light up and right */
- [0x18] = BDL + LU + LL, /* light up and left */
- [0x1c] = BDL + LV + LR, /* light vertical and right */
- [0x24] = BDL + LV + LL, /* light vertical and left */
- [0x2c] = BDL + LH + LD, /* light horizontal and down */
- [0x34] = BDL + LH + LU, /* light horizontal and up */
- [0x3c] = BDL + LV + LH, /* light vertical and horizontal */
- [0x74] = BDL + LL, /* light left */
- [0x75] = BDL + LU, /* light up */
- [0x76] = BDL + LR, /* light right */
- [0x77] = BDL + LD, /* light down */
-
- /* heavy [+light] lines */
- [0x01] = BDL + HH,
- [0x03] = BDL + HV,
- [0x0d] = BDL + HR + LD,
- [0x0e] = BDL + HD + LR,
- [0x0f] = BDL + HD + HR,
- [0x11] = BDL + HL + LD,
- [0x12] = BDL + HD + LL,
- [0x13] = BDL + HD + HL,
- [0x15] = BDL + HR + LU,
- [0x16] = BDL + HU + LR,
- [0x17] = BDL + HU + HR,
- [0x19] = BDL + HL + LU,
- [0x1a] = BDL + HU + LL,
- [0x1b] = BDL + HU + HL,
- [0x1d] = BDL + HR + LV,
- [0x1e] = BDL + HU + LD + LR,
- [0x1f] = BDL + HD + LR + LU,
- [0x20] = BDL + HV + LR,
- [0x21] = BDL + HU + HR + LD,
- [0x22] = BDL + HD + HR + LU,
- [0x23] = BDL + HV + HR,
- [0x25] = BDL + HL + LV,
- [0x26] = BDL + HU + LD + LL,
- [0x27] = BDL + HD + LU + LL,
- [0x28] = BDL + HV + LL,
- [0x29] = BDL + HU + HL + LD,
- [0x2a] = BDL + HD + HL + LU,
- [0x2b] = BDL + HV + HL,
- [0x2d] = BDL + HL + LD + LR,
- [0x2e] = BDL + HR + LL + LD,
- [0x2f] = BDL + HH + LD,
- [0x30] = BDL + HD + LH,
- [0x31] = BDL + HD + HL + LR,
- [0x32] = BDL + HR + HD + LL,
- [0x33] = BDL + HH + HD,
- [0x35] = BDL + HL + LU + LR,
- [0x36] = BDL + HR + LU + LL,
- [0x37] = BDL + HH + LU,
- [0x38] = BDL + HU + LH,
- [0x39] = BDL + HU + HL + LR,
- [0x3a] = BDL + HU + HR + LL,
- [0x3b] = BDL + HH + HU,
- [0x3d] = BDL + HL + LV + LR,
- [0x3e] = BDL + HR + LV + LL,
- [0x3f] = BDL + HH + LV,
- [0x40] = BDL + HU + LH + LD,
- [0x41] = BDL + HD + LH + LU,
- [0x42] = BDL + HV + LH,
- [0x43] = BDL + HU + HL + LD + LR,
- [0x44] = BDL + HU + HR + LD + LL,
- [0x45] = BDL + HD + HL + LU + LR,
- [0x46] = BDL + HD + HR + LU + LL,
- [0x47] = BDL + HH + HU + LD,
- [0x48] = BDL + HH + HD + LU,
- [0x49] = BDL + HV + HL + LR,
- [0x4a] = BDL + HV + HR + LL,
- [0x4b] = BDL + HV + HH,
- [0x78] = BDL + HL,
- [0x79] = BDL + HU,
- [0x7a] = BDL + HR,
- [0x7b] = BDL + HD,
- [0x7c] = BDL + HR + LL,
- [0x7d] = BDL + HD + LU,
- [0x7e] = BDL + HL + LR,
- [0x7f] = BDL + HU + LD,
-
- /* double [+light] lines */
- [0x50] = BDL + DH,
- [0x51] = BDL + DV,
- [0x52] = BDL + DR + LD,
- [0x53] = BDL + DD + LR,
- [0x54] = BDL + DR + DD,
- [0x55] = BDL + DL + LD,
- [0x56] = BDL + DD + LL,
- [0x57] = BDL + DL + DD,
- [0x58] = BDL + DR + LU,
- [0x59] = BDL + DU + LR,
- [0x5a] = BDL + DU + DR,
- [0x5b] = BDL + DL + LU,
- [0x5c] = BDL + DU + LL,
- [0x5d] = BDL + DL + DU,
- [0x5e] = BDL + DR + LV,
- [0x5f] = BDL + DV + LR,
- [0x60] = BDL + DV + DR,
- [0x61] = BDL + DL + LV,
- [0x62] = BDL + DV + LL,
- [0x63] = BDL + DV + DL,
- [0x64] = BDL + DH + LD,
- [0x65] = BDL + DD + LH,
- [0x66] = BDL + DD + DH,
- [0x67] = BDL + DH + LU,
- [0x68] = BDL + DU + LH,
- [0x69] = BDL + DH + DU,
- [0x6a] = BDL + DH + LV,
- [0x6b] = BDL + DV + LH,
- [0x6c] = BDL + DH + DV,
-
- /* (light) arcs */
- [0x6d] = BDA + LD + LR,
- [0x6e] = BDA + LD + LL,
- [0x6f] = BDA + LU + LL,
- [0x70] = BDA + LU + LR,
-
- /* Lower (Down) X/8 block (data is 8 - X) */
- [0x81] = BBD + 7, [0x82] = BBD + 6, [0x83] = BBD + 5, [0x84] = BBD + 4,
- [0x85] = BBD + 3, [0x86] = BBD + 2, [0x87] = BBD + 1, [0x88] = BBD + 0,
-
- /* Left X/8 block (data is X) */
- [0x89] = BBL + 7, [0x8a] = BBL + 6, [0x8b] = BBL + 5, [0x8c] = BBL + 4,
- [0x8d] = BBL + 3, [0x8e] = BBL + 2, [0x8f] = BBL + 1,
-
- /* upper 1/2 (4/8), 1/8 block (X), right 1/2, 1/8 block (8-X) */
- [0x80] = BBU + 4, [0x94] = BBU + 1,
- [0x90] = BBR + 4, [0x95] = BBR + 7,
-
- /* Quadrants */
- [0x96] = BBQ + BL,
- [0x97] = BBQ + BR,
- [0x98] = BBQ + TL,
- [0x99] = BBQ + TL + BL + BR,
- [0x9a] = BBQ + TL + BR,
- [0x9b] = BBQ + TL + TR + BL,
- [0x9c] = BBQ + TL + TR + BR,
- [0x9d] = BBQ + TR,
- [0x9e] = BBQ + BL + TR,
- [0x9f] = BBQ + BL + TR + BR,
-
- /* Shades, data is an alpha value in 25% units (1/4, 1/2, 3/4) */
- [0x91] = BBS + 1, [0x92] = BBS + 2, [0x93] = BBS + 3,
-
- /* U+2504 - U+250B, U+254C - U+254F: unsupported (dashes) */
- /* U+2571 - U+2573: unsupported (diagonals) */
-};
diff --git a/config.def.h b/config.def.h
@@ -6,23 +6,60 @@
* font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
*/
static char *font = "JetBrainsMono Nerd Font :pixelsize=15:antialias=true:autohint=true";
-static char *font2[] = { "JetBrainsMono Nerd Font :pixelsize=15:antialias=true:autohint=true" };
+#if FONT2_PATCH
+/* Spare fonts */
+static char *font2[] = {
+ "JetBrainsMono Nerd Font :pixelsize=15:antialias=true:autohint=true",
+};
+#endif // FONT2_PATCH
+
+#if BACKGROUND_IMAGE_PATCH
+/*
+ * background image
+ * expects farbfeld format
+ * pseudo transparency fixes coordinates to the screen origin
+ */
+static const char *bgfile = "/path/to/image.ff";
+static const int pseudotransparency = 0;
+#endif // BACKGROUND_IMAGE_PATCH
+
+#if RELATIVEBORDER_PATCH
+/* borderperc: percentage of cell width to use as a border
+ * 0 = no border, 100 = border width is same as cell width */
+int borderperc = 20;
+#else
static int borderpx = 0;
+#endif // RELATIVEBORDER_PATCH
+
+#if OPENURLONCLICK_PATCH
+/* modkey options: ControlMask, ShiftMask or XK_ANY_MOD */
+static uint url_opener_modkey = XK_ANY_MOD;
+static char *url_opener = "xdg-open";
+#endif // OPENURLONCLICK_PATCH
/*
* What program is execed by st depends of these precedence rules:
* 1: program passed with -e
- * 2: utmp option
+ * 2: scroll and/or utmp
* 3: SHELL environment variable
* 4: value of shell in /etc/passwd
* 5: value of shell in config.h
*/
static char *shell = "/bin/sh";
char *utmp = NULL;
+/* scroll program: to enable use a string like "scroll" */
+char *scroll = NULL;
char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400";
/* identification sequence returned in DA and DECID */
+#if SIXEL_PATCH
+char *vtiden = "\033[?62;4c"; /* VT200 family (62) with sixel (4) */
+
+/* sixel rgb byte order: LSBFirst or MSBFirst */
+int const sixelbyteorder = LSBFirst;
+#else
char *vtiden = "\033[?6c";
+#endif
/* Kerning / character bounding-box multipliers */
static float cwscale = 1.0;
@@ -35,6 +72,12 @@ static float chscale = 1.0;
*/
wchar_t *worddelimiters = L" ";
+#if KEYBOARDSELECT_PATCH && REFLOW_PATCH
+/* Word delimiters for short and long jumps in the keyboard select patch */
+wchar_t *kbds_sdelim = L"!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~ ";
+wchar_t *kbds_ldelim = L" ";
+#endif // KEYBOARDSELECT_PATCH
+
/* selection timeouts (in milliseconds) */
static unsigned int doubleclicktimeout = 300;
static unsigned int tripleclicktimeout = 600;
@@ -42,6 +85,10 @@ static unsigned int tripleclicktimeout = 600;
/* alt screens */
int allowaltscreen = 1;
+/* allow certain non-interactive (insecure) window operations such as:
+ setting the clipboard text */
+int allowwindowops = 0;
+
/*
* draw latency range in ms - from new content/keypress/etc until drawing.
* within this range, st draws when content stops arriving (idle). mostly it's
@@ -51,11 +98,13 @@ int allowaltscreen = 1;
static double minlatency = 8;
static double maxlatency = 33;
+#if SYNC_PATCH
/*
* Synchronized-Update timeout in ms
* https://gitlab.com/gnachman/iterm2/-/wikis/synchronized-updates-spec
*/
static uint su_timeout = 200;
+#endif // SYNC_PATCH
/*
* blinking timeout (set to 0 to disable blinking) for the terminal blinking
@@ -64,17 +113,16 @@ static uint su_timeout = 200;
static unsigned int blinktimeout = 800;
/*
- * interval (in milliseconds) between each successive call to ximspot. This
- * improves terminal performance while not reducing functionality to those
- * whom need XIM support.
- */
-int ximspot_update_interval = 1000;
-
-/*
* thickness of underline and bar cursors
*/
static unsigned int cursorthickness = 2;
+#if HIDECURSOR_PATCH
+/* Hide the X cursor whenever a key is pressed. 0: off, 1: on */
+int hidecursor = 1;
+#endif // HIDECURSOR_PATCH
+
+#if BOXDRAW_PATCH
/*
* 1: render most of the lines/blocks characters without using the font for
* perfect alignment between cells (U2500 - U259F except dashes/diagonals).
@@ -86,6 +134,7 @@ const int boxdraw_bold = 1;
/* braille (U28XX): 1: render as adjacent "pixels", 0: use font */
const int boxdraw_braille = 1;
+#endif // BOXDRAW_PATCH
/*
* bell volume. It must be a value between -100 and 100. Use 0 for disabling
@@ -113,33 +162,56 @@ char *termname = "st-256color";
*/
unsigned int tabspaces = 8;
+#if ALPHA_PATCH
/* bg opacity */
-float alpha = 0.8;
+float alpha = 0.85;
+#if ALPHA_GRADIENT_PATCH
+float grad_alpha = 0.54; //alpha value that'll change
+float stat_alpha = 0.46; //constant alpha value that'll get added to grad_alpha
+#endif // ALPHA_GRADIENT_PATCH
+#if ALPHA_FOCUS_HIGHLIGHT_PATCH
+float alphaUnfocused = 0.6;
+#endif // ALPHA_FOCUS_HIGHLIGHT_PATCH
+#endif // ALPHA_PATCH
+
+#if DRAG_AND_DROP_PATCH
+/*
+ * drag and drop escape characters
+ *
+ * this will add a '\' before any characters specified in the string.
+ */
+char *xdndescchar = " !\"#$&'()*;<>?[\\]^`{|}~";
+#endif // DRAG_AND_DROP_PATCH
-/* Terminal colors (16 first used in escape sequence) */
+/* Terminal colors - Gruvbox Dark */
static const char *colorname[] = {
- "#282828", /* hard contrast: #1d2021 / soft contrast: #32302f */
- "#cc241d",
- "#98971a",
- "#d79921",
- "#458588",
- "#b16286",
- "#689d6a",
- "#a89984",
- "#928374",
- "#fb4934",
- "#b8bb26",
- "#fabd2f",
- "#83a598",
- "#d3869b",
- "#8ec07c",
- "#ebdbb2",
- [255] = 0,
- /* more colors can be added after 255 to use with DefaultXX */
- "#add8e6", /* 256 -> cursor */
- "#555555", /* 257 -> rev cursor*/
- "#282828", /* 258 -> bg */
- "#ffffff", /* 259 -> fg */
+ /* 8 normal colors */
+ "#282828", /* hard contrast: #1d2021 / soft contrast: #32302f */
+ "#cc241d",
+ "#98971a",
+ "#d79921",
+ "#458588",
+ "#b16286",
+ "#689d6a",
+ "#a89984",
+
+ /* 8 bright colors */
+ "#928374",
+ "#fb4934",
+ "#b8bb26",
+ "#fabd2f",
+ "#83a598",
+ "#d3869b",
+ "#8ec07c",
+ "#ebdbb2",
+
+ [255] = 0,
+
+ /* more colors can be added after 255 to use with DefaultXX */
+ "#add8e6", /* 256 -> cursor */
+ "#555555", /* 257 -> rev cursor*/
+ "#282828", /* 258 -> bg */
+ "#ffffff", /* 259 -> fg */
};
@@ -147,17 +219,35 @@ static const char *colorname[] = {
* Default colors (colorname index)
* foreground, background, cursor, reverse cursor
*/
-unsigned int defaultfg = 259;
+#if ALPHA_PATCH && ALPHA_FOCUS_HIGHLIGHT_PATCH
+unsigned int defaultbg = 0;
+unsigned int bg = 17, bgUnfocused = 16;
+#else
unsigned int defaultbg = 258;
+#endif // ALPHA_FOCUS_HIGHLIGHT_PATCH
+unsigned int defaultfg = 259;
unsigned int defaultcs = 256;
unsigned int defaultrcs = 257;
-
+#if SELECTION_COLORS_PATCH
+unsigned int selectionfg = 258;
+unsigned int selectionbg = 259;
+/* If 0 use selectionfg as foreground in order to have a uniform foreground-color */
+/* Else if 1 keep original foreground-color of each cell => more colors :) */
+static int ignoreselfg = 1;
+#endif // SELECTION_COLORS_PATCH
+#if KEYBOARDSELECT_PATCH && REFLOW_PATCH
+/* Foreground and background color of search results */
+unsigned int highlightfg = 15;
+unsigned int highlightbg = 160;
+#endif // KEYBOARDSELECT_PATCH
+
+#if BLINKING_CURSOR_PATCH
/*
* https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h4-Functions-using-CSI-_-ordered-by-the-final-character-lparen-s-rparen:CSI-Ps-SP-q.1D81
* Default style of cursor
* 0: Blinking block
* 1: Blinking block (default)
- * 2: Steady block ("█")
+ * 2: Steady block ("â–ˆ")
* 3: Blinking underline
* 4: Steady underline ("_")
* 5: Blinking bar
@@ -165,7 +255,18 @@ unsigned int defaultrcs = 257;
* 7: Blinking st cursor
* 8: Steady st cursor
*/
-static unsigned int cursorshape = 1;
+static unsigned int cursorstyle = 1;
+static Rune stcursor = 0x2603; /* snowman (U+2603) */
+#else
+/*
+ * Default shape of cursor
+ * 2: Block ("█")
+ * 4: Underline ("_")
+ * 6: Bar ("|")
+ * 7: Snowman ("☃")
+ */
+static unsigned int cursorshape = 2;
+#endif // BLINKING_CURSOR_PATCH
/*
* Default columns and rows numbers
@@ -174,12 +275,29 @@ static unsigned int cursorshape = 1;
static unsigned int cols = 80;
static unsigned int rows = 24;
+#if ANYGEOMETRY_PATCH
+/*
+ * Whether to use pixel geometry or cell geometry
+ */
+
+static Geometry geometry = CellGeometry; // or PixelGeometry to use the below size
+static unsigned int width = 564;
+static unsigned int height = 364;
+#endif // ANYGEOMETRY_PATCH
+
+#if THEMED_CURSOR_PATCH
+/*
+ * Default shape of the mouse cursor
+ */
+static char* mouseshape = "xterm";
+#else
/*
* Default colour and shape of the mouse cursor
*/
static unsigned int mouseshape = XC_xterm;
static unsigned int mousefg = 7;
static unsigned int mousebg = 0;
+#endif // THEMED_CURSOR_PATCH
/*
* Color used to display font attributes when fontconfig selected a font which
@@ -187,115 +305,212 @@ static unsigned int mousebg = 0;
*/
static unsigned int defaultattr = 11;
+#if XRESOURCES_PATCH
/*
* Xresources preferences to load at startup
*/
ResourcePref resources[] = {
- { "font", STRING, &font },
- { "fontalt0", STRING, &font2[0] },
- { "color0", STRING, &colorname[0] },
- { "color1", STRING, &colorname[1] },
- { "color2", STRING, &colorname[2] },
- { "color3", STRING, &colorname[3] },
- { "color4", STRING, &colorname[4] },
- { "color5", STRING, &colorname[5] },
- { "color6", STRING, &colorname[6] },
- { "color7", STRING, &colorname[7] },
- { "color8", STRING, &colorname[8] },
- { "color9", STRING, &colorname[9] },
- { "color10", STRING, &colorname[10] },
- { "color11", STRING, &colorname[11] },
- { "color12", STRING, &colorname[12] },
- { "color13", STRING, &colorname[13] },
- { "color14", STRING, &colorname[14] },
- { "color15", STRING, &colorname[15] },
- { "background", STRING, &colorname[258] },
- { "foreground", STRING, &colorname[259] },
- { "cursorColor", STRING, &colorname[256] },
- { "termname", STRING, &termname },
- { "shell", STRING, &shell },
- { "blinktimeout", INTEGER, &blinktimeout },
- { "bellvolume", INTEGER, &bellvolume },
- { "tabspaces", INTEGER, &tabspaces },
- { "borderpx", INTEGER, &borderpx },
- { "cwscale", FLOAT, &cwscale },
- { "chscale", FLOAT, &chscale },
- { "alpha", FLOAT, &alpha },
- { "ximspot_update_interval", INTEGER, &ximspot_update_interval },
+ { "font", STRING, &font },
+ { "color0", STRING, &colorname[0] },
+ { "color1", STRING, &colorname[1] },
+ { "color2", STRING, &colorname[2] },
+ { "color3", STRING, &colorname[3] },
+ { "color4", STRING, &colorname[4] },
+ { "color5", STRING, &colorname[5] },
+ { "color6", STRING, &colorname[6] },
+ { "color7", STRING, &colorname[7] },
+ { "color8", STRING, &colorname[8] },
+ { "color9", STRING, &colorname[9] },
+ { "color10", STRING, &colorname[10] },
+ { "color11", STRING, &colorname[11] },
+ { "color12", STRING, &colorname[12] },
+ { "color13", STRING, &colorname[13] },
+ { "color14", STRING, &colorname[14] },
+ { "color15", STRING, &colorname[15] },
+ { "background", STRING, &colorname[258] },
+ { "foreground", STRING, &colorname[259] },
+ { "cursorColor", STRING, &colorname[256] },
+ { "termname", STRING, &termname },
+ { "shell", STRING, &shell },
+ { "minlatency", INTEGER, &minlatency },
+ { "maxlatency", INTEGER, &maxlatency },
+ { "blinktimeout", INTEGER, &blinktimeout },
+ { "bellvolume", INTEGER, &bellvolume },
+ { "tabspaces", INTEGER, &tabspaces },
+ #if RELATIVEBORDER_PATCH
+ { "borderperc", INTEGER, &borderperc },
+ #else
+ { "borderpx", INTEGER, &borderpx },
+ #endif // RELATIVEBORDER_PATCH
+ { "cwscale", FLOAT, &cwscale },
+ { "chscale", FLOAT, &chscale },
+ #if ALPHA_PATCH
+ { "alpha", FLOAT, &alpha },
+ #endif // ALPHA_PATCH
+ #if ALPHA_FOCUS_HIGHLIGHT_PATCH
+ { "alphaUnfocused",FLOAT, &alphaUnfocused },
+ #endif // ALPHA_FOCUS_HIGHLIGHT_PATCH
+ #if KEYBOARDSELECT_PATCH && REFLOW_PATCH
+ { "highlightfg", INTEGER, &highlightfg },
+ { "highlightbg", INTEGER, &highlightbg },
+ #endif // KEYBOARDSELECT_PATCH
};
+#endif // XRESOURCES_PATCH
+
+/*
+ * Force mouse select/shortcuts while mask is active (when MODE_MOUSE is set).
+ * Note that if you want to use ShiftMask with selmasks, set this to an other
+ * modifier, set to 0 to not use it.
+ */
+static uint forcemousemod = ShiftMask;
/*
* Internal mouse shortcuts.
* Beware that overloading Button1 will disable the selection.
*/
-const unsigned int mousescrollincrement = 3;
static MouseShortcut mshortcuts[] = {
- /* button mask string */
- { Button4, XK_NO_MOD, "\031" },
- { Button5, XK_NO_MOD, "\005" },
+ /* mask button function argument release screen */
+ #if OPEN_SELECTED_TEXT_PATCH
+ { ControlMask, Button2, selopen, {.i = 0}, 1 },
+ #endif // OPEN_SELECTED_TEXT_PATCH
+ #if CLIPBOARD_PATCH
+ { XK_ANY_MOD, Button2, clippaste, {.i = 0}, 1 },
+ #else
+ { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 },
+ #endif // CLIPBOARD_PATCH
+ #if SCROLLBACK_MOUSE_PATCH
+ { ShiftMask, Button4, kscrollup, {.i = 1}, 0, S_PRI},
+ { ShiftMask, Button5, kscrolldown, {.i = 1}, 0, S_PRI},
+ #elif UNIVERSCROLL_PATCH
+ { XK_ANY_MOD, Button4, ttysend, {.s = "\033[5;2~"}, 0, S_PRI },
+ { XK_ANY_MOD, Button5, ttysend, {.s = "\033[6;2~"}, 0, S_PRI },
+ #else
+ { ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} },
+ { ShiftMask, Button5, ttysend, {.s = "\033[6;2~"} },
+ #endif // SCROLLBACK_MOUSE_PATCH
+ #if SCROLLBACK_MOUSE_ALTSCREEN_PATCH || REFLOW_PATCH
+ { XK_ANY_MOD, Button4, kscrollup, {.i = 1}, 0, S_PRI },
+ { XK_ANY_MOD, Button5, kscrolldown, {.i = 1}, 0, S_PRI },
+ { XK_ANY_MOD, Button4, ttysend, {.s = "\031"}, 0, S_ALT },
+ { XK_ANY_MOD, Button5, ttysend, {.s = "\005"}, 0, S_ALT },
+ #else
+ { XK_ANY_MOD, Button4, ttysend, {.s = "\031"} },
+ { XK_ANY_MOD, Button5, ttysend, {.s = "\005"} },
+ #endif // SCROLLBACK_MOUSE_ALTSCREEN_PATCH
};
/* Internal keyboard shortcuts. */
#define MODKEY Mod1Mask
#define TERMMOD (Mod4Mask|ShiftMask)
-MouseKey mkeys[] = {
- /* button mask function argument */
- { Button4, XK_NO_MOD, kscrollup, {.i = mousescrollincrement} },
- { Button5, XK_NO_MOD, kscrolldown, {.i = mousescrollincrement} },
- { Button4, Mod4Mask, zoom, {.f = +1} },
- { Button5, Mod4Mask, zoom, {.f = -1} },
-};
-
+#if EXTERNALPIPE_PATCH
static char *openurlcmd[] = { "/bin/sh", "-c", "st-urlhandler", "externalpipe", NULL };
static char *copyurlcmd[] = { "/bin/sh", "-c",
- "tmp=$(sed 's/.*│//g' | tr -d '\n' | grep -aEo '(((http|https|gopher|gemini|ftp|ftps|git)://|www\\.)[a-zA-Z0-9.]*[:]?[a-zA-Z0-9./@$&%?$#=_-~]*)|((magnet:\\?xt=urn:btih:)[a-zA-Z0-9]*)' | uniq | sed 's/^www./http:\\/\\/www\\./g' ); IFS=; [ ! -z $tmp ] && echo $tmp | dmenu -i -p 'Copy which url?' -l 10 | tr -d '\n' | xclip -selection clipboard",
- "externalpipe", NULL };
+ "tmp=$(sed 's/.*│//g' | tr -d '\n' | grep -aEo '(((http|https|gopher|gemini|ftp|ftps|git)://|www\\.)[a-zA-Z0-9.]*[:]?[a-zA-Z0-9./@$&%?$#=_-~]*)|((magnet:\\?xt=urn:btih:)[a-zA-Z0-9]*)' | uniq | sed 's/^www./http:\\/\\/www\\./g' ); IFS=; [ ! -z $tmp ] && echo $tmp | dmenu -i -p 'Copy which url?' -l 10 | tr -d '\n' | xclip -selection clipboard",
+ "externalpipe", NULL };
static char *copyoutput[] = { "/bin/sh", "-c", "st-copyout", "externalpipe", NULL };
-static Shortcut shortcuts[] = {
- /* mask keysym function argument */
- { XK_ANY_MOD, XK_Break, sendbreak, {.i = 0} },
- { ControlMask, XK_Print, toggleprinter, {.i = 0} },
- { ShiftMask, XK_Print, printscreen, {.i = 0} },
- { XK_ANY_MOD, XK_Print, printsel, {.i = 0} },
- { MODKEY, XK_comma, zoom, {.f = +1} },
- { MODKEY, XK_period, zoom, {.f = -1} },
- { MODKEY, XK_g, zoomreset, {.f = 0} },
- { ControlMask | ShiftMask, XK_C, clipcopy, {.i = 0} },
- { ControlMask, XK_c, clipcopy, {.i = 0} },
- { ShiftMask, XK_Insert, clippaste, {.i = 0} },
- { ControlMask | ShiftMask, XK_V, clippaste, {.i = 0} },
- { ControlMask, XK_v, clippaste, {.i = 0} },
- { XK_ANY_MOD, Button2, selpaste, {.i = 0} },
- { MODKEY, XK_Num_Lock, numlock, {.i = 0} },
- { ControlMask | ShiftMask, XK_U, iso14755, {.i = 0} },
- { ShiftMask, XK_Page_Up, kscrollup, {.i = -1} },
- { ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} },
- { MODKEY, XK_Page_Up, kscrollup, {.i = -1} },
- { MODKEY, XK_Page_Down, kscrolldown, {.i = -1} },
- { MODKEY, XK_k, kscrollup, {.i = 1} },
- { MODKEY, XK_j, kscrolldown, {.i = 1} },
- { MODKEY, XK_Up, kscrollup, {.i = 1} },
- { MODKEY, XK_Down, kscrolldown, {.i = 1} },
- { MODKEY, XK_u, kscrollup, {.i = -1} },
- { MODKEY, XK_d, kscrolldown, {.i = -1} },
- { MODKEY, XK_s, changealpha, {.f = -0.05} },
- { MODKEY, XK_a, changealpha, {.f = +0.05} },
- { MODKEY, XK_m, changealpha, {.f = +2.00} },
- { TERMMOD, XK_Up, zoom, {.f = +1} },
- { TERMMOD, XK_Down, zoom, {.f = -1} },
- { TERMMOD, XK_K, zoom, {.f = +1} },
- { TERMMOD, XK_J, zoom, {.f = -1} },
- { TERMMOD, XK_U, zoom, {.f = +2} },
- { TERMMOD, XK_D, zoom, {.f = -2} },
- { MODKEY, XK_l, externalpipe, {.v = openurlcmd } },
- { MODKEY, XK_y, externalpipe, {.v = copyurlcmd } },
- { MODKEY, XK_o, externalpipe, {.v = copyoutput } },
- { TERMMOD, XK_Return, newterm, {.i = 0} },
+#if EXTERNALPIPEIN_PATCH // example command
+static char *setbgcolorcmd[] = { "/bin/sh", "-c",
+ "printf '\033]11;#008000\007'",
+ "externalpipein", NULL };
+#endif // EXTERNALPIPEIN_PATCH
+#endif // EXTERNALPIPE_PATCH
+static Shortcut shortcuts[] = {
+ /* mask keysym function argument screen */
+ { XK_ANY_MOD, XK_Break, sendbreak, {.i = 0} },
+ { ControlMask, XK_Print, toggleprinter, {.i = 0} },
+ { ShiftMask, XK_Print, printscreen, {.i = 0} },
+ { XK_ANY_MOD, XK_Print, printsel, {.i = 0} },
+ /* Zoom with Alt+comma/period, reset with Alt+g */
+ { MODKEY, XK_comma, zoom, {.f = +1} },
+ { MODKEY, XK_period, zoom, {.f = -1} },
+ { MODKEY, XK_g, zoomreset, {.f = 0} },
+ /* Additional zoom with Super+Shift+arrows/jk */
+ { TERMMOD, XK_Up, zoom, {.f = +1} },
+ { TERMMOD, XK_Down, zoom, {.f = -1} },
+ { TERMMOD, XK_K, zoom, {.f = +1} },
+ { TERMMOD, XK_J, zoom, {.f = -1} },
+ { TERMMOD, XK_U, zoom, {.f = +2} },
+ { TERMMOD, XK_D, zoom, {.f = -2} },
+ /* Copy/Paste with Ctrl+c/v and Ctrl+Shift+C/V */
+ { ControlMask|ShiftMask, XK_C, clipcopy, {.i = 0} },
+ { ControlMask, XK_c, clipcopy, {.i = 0} },
+ { ShiftMask, XK_Insert, clippaste, {.i = 0} },
+ { ControlMask|ShiftMask, XK_V, clippaste, {.i = 0} },
+ { ControlMask, XK_v, clippaste, {.i = 0} },
+ #if ALPHA_PATCH
+ /* Alpha control with Alt+a/s/m */
+ { MODKEY, XK_s, changealpha, {.f = -0.05} },
+ { MODKEY, XK_a, changealpha, {.f = +0.05} },
+ { MODKEY, XK_m, changealpha, {.f = +2.00} },
+ #if ALPHA_FOCUS_HIGHLIGHT_PATCH
+ //{ TERMMOD, XK_, changealphaunfocused, {.f = +0.05} },
+ //{ TERMMOD, XK_, changealphaunfocused, {.f = -0.05} },
+ #endif // ALPHA_FOCUS_HIGHLIGHT_PATCH
+ #endif // ALPHA_PATCH
+ #if FULLSCREEN_PATCH
+ { XK_NO_MOD, XK_F11, fullscreen, {.i = 0} },
+ { MODKEY, XK_Return, fullscreen, {.i = 0} },
+ #endif // FULLSCREEN_PATCH
+ #if SCROLLBACK_PATCH || REFLOW_PATCH
+ /* Scrollback with Shift+PageUp/Down and Alt+PageUp/Down/j/k/u/d */
+ { ShiftMask, XK_Page_Up, kscrollup, {.i = -1}, S_PRI },
+ { ShiftMask, XK_Page_Down, kscrolldown, {.i = -1}, S_PRI },
+ { MODKEY, XK_Page_Up, kscrollup, {.i = -1}, S_PRI },
+ { MODKEY, XK_Page_Down, kscrolldown, {.i = -1}, S_PRI },
+ { MODKEY, XK_k, kscrollup, {.i = 1}, S_PRI },
+ { MODKEY, XK_j, kscrolldown, {.i = 1}, S_PRI },
+ { MODKEY, XK_Up, kscrollup, {.i = 1}, S_PRI },
+ { MODKEY, XK_Down, kscrolldown, {.i = 1}, S_PRI },
+ { MODKEY, XK_u, kscrollup, {.i = -1}, S_PRI },
+ { MODKEY, XK_d, kscrolldown, {.i = -1}, S_PRI },
+ #endif // SCROLLBACK_PATCH || REFLOW_PATCH
+ #if CLIPBOARD_PATCH
+ { ShiftMask, XK_Insert, clippaste, {.i = 0} },
+ #else
+ { ShiftMask, XK_Insert, selpaste, {.i = 0} },
+ #endif // CLIPBOARD_PATCH
+ { MODKEY, XK_Num_Lock, numlock, {.i = 0} },
+ #if COPYURL_PATCH || COPYURL_HIGHLIGHT_SELECTED_URLS_PATCH
+ /* copyurl not used - using externalpipe instead */
+ #endif // COPYURL_PATCH
+ #if OPENCOPIED_PATCH
+ { MODKEY, XK_o, opencopied, {.v = "xdg-open"} },
+ #endif // OPENCOPIED_PATCH
+ #if NEWTERM_PATCH
+ { TERMMOD, XK_Return, newterm, {.i = 0} },
+ #endif // NEWTERM_PATCH
+ #if EXTERNALPIPE_PATCH
+ /* External pipe commands: Alt+l (urls), Alt+y (copy url), Alt+o (copy output) */
+ { MODKEY, XK_l, externalpipe, { .v = openurlcmd } },
+ { MODKEY, XK_y, externalpipe, { .v = copyurlcmd } },
+ { MODKEY, XK_o, externalpipe, { .v = copyoutput } },
+ #if EXTERNALPIPEIN_PATCH
+ { TERMMOD, XK_M, externalpipein, { .v = setbgcolorcmd } },
+ #endif // EXTERNALPIPEIN_PATCH
+ #endif // EXTERNALPIPE_PATCH
+ #if KEYBOARDSELECT_PATCH
+ { TERMMOD, XK_Escape, keyboard_select, { 0 } },
+ #endif // KEYBOARDSELECT_PATCH
+ #if KEYBOARDSELECT_PATCH && REFLOW_PATCH
+ { TERMMOD, XK_F, searchforward, { 0 } },
+ { TERMMOD, XK_B, searchbackward, { 0 } },
+ #endif // KEYBOARDSELECT_PATCH
+ #if ISO14755_PATCH
+ /* Unicode input with Ctrl+Shift+U */
+ { ControlMask|ShiftMask, XK_U, iso14755, {.i = 0} },
+ #endif // ISO14755_PATCH
+ #if INVERT_PATCH
+ { TERMMOD, XK_X, invert, { 0 } },
+ #endif // INVERT_PATCH
+ #if OSC133_PATCH
+ { ControlMask, XK_Page_Up, scrolltoprompt, {.i = -1}, S_PRI },
+ { ControlMask, XK_Page_Down, scrolltoprompt, {.i = 1}, S_PRI },
+ #endif // OSC133_PATCH
};
/*
@@ -313,21 +528,19 @@ static Shortcut shortcuts[] = {
* * 0: no value
* * > 0: cursor application mode enabled
* * < 0: cursor application mode disabled
- * crlf value
- * * 0: no value
- * * > 0: crlf mode is enabled
- * * < 0: crlf mode is disabled
*
* Be careful with the order of the definitions because st searches in
* this table sequentially, so any XK_ANY_MOD must be in the last
* position for a key.
*/
+#if !FIXKEYBOARDINPUT_PATCH
/*
* If you want keys other than the X11 function keys (0xFD00 - 0xFFFF)
* to be mapped below, add them to this array.
*/
static KeySym mappedkeys[] = { -1 };
+#endif // FIXKEYBOARDINPUT_PATCH
/*
* State bits to ignore when matching key or button events. By default,
@@ -335,229 +548,232 @@ static KeySym mappedkeys[] = { -1 };
*/
static uint ignoremod = Mod2Mask|XK_SWITCH_MOD;
-/*
- * Override mouse-select while mask is active (when MODE_MOUSE is set).
- * Note that if you want to use ShiftMask with selmasks, set this to an other
- * modifier, set to 0 to not use it.
- */
-static uint forceselmod = ShiftMask;
-
+#if !FIXKEYBOARDINPUT_PATCH
/*
* This is the huge key array which defines all compatibility to the Linux
* world. Please decide about changes wisely.
*/
static Key key[] = {
- /* keysym mask string appkey appcursor */
- { XK_KP_Home, ShiftMask, "\033[2J", 0, -1},
- { XK_KP_Home, ShiftMask, "\033[1;2H", 0, +1},
- { XK_KP_Home, XK_ANY_MOD, "\033[H", 0, -1},
- { XK_KP_Home, XK_ANY_MOD, "\033[1~", 0, +1},
- { XK_KP_Up, XK_ANY_MOD, "\033Ox", +1, 0},
- { XK_KP_Up, XK_ANY_MOD, "\033[A", 0, -1},
- { XK_KP_Up, XK_ANY_MOD, "\033OA", 0, +1},
- { XK_KP_Down, XK_ANY_MOD, "\033Or", +1, 0},
- { XK_KP_Down, XK_ANY_MOD, "\033[B", 0, -1},
- { XK_KP_Down, XK_ANY_MOD, "\033OB", 0, +1},
- { XK_KP_Left, XK_ANY_MOD, "\033Ot", +1, 0},
- { XK_KP_Left, XK_ANY_MOD, "\033[D", 0, -1},
- { XK_KP_Left, XK_ANY_MOD, "\033OD", 0, +1},
- { XK_KP_Right, XK_ANY_MOD, "\033Ov", +1, 0},
- { XK_KP_Right, XK_ANY_MOD, "\033[C", 0, -1},
- { XK_KP_Right, XK_ANY_MOD, "\033OC", 0, +1},
- { XK_KP_Prior, ShiftMask, "\033[5;2~", 0, 0},
- { XK_KP_Prior, XK_ANY_MOD, "\033[5~", 0, 0},
- { XK_KP_Begin, XK_ANY_MOD, "\033[E", 0, 0},
- { XK_KP_End, ControlMask, "\033[J", -1, 0},
- { XK_KP_End, ControlMask, "\033[1;5F", +1, 0},
- { XK_KP_End, ShiftMask, "\033[K", -1, 0},
- { XK_KP_End, ShiftMask, "\033[1;2F", +1, 0},
- { XK_KP_End, XK_ANY_MOD, "\033[4~", 0, 0},
- { XK_KP_Next, ShiftMask, "\033[6;2~", 0, 0},
- { XK_KP_Next, XK_ANY_MOD, "\033[6~", 0, 0},
- { XK_KP_Insert, ShiftMask, "\033[2;2~", +1, 0},
- { XK_KP_Insert, ShiftMask, "\033[4l", -1, 0},
- { XK_KP_Insert, ControlMask, "\033[L", -1, 0},
- { XK_KP_Insert, ControlMask, "\033[2;5~", +1, 0},
- { XK_KP_Insert, XK_ANY_MOD, "\033[4h", -1, 0},
- { XK_KP_Insert, XK_ANY_MOD, "\033[2~", +1, 0},
- { XK_KP_Delete, ControlMask, "\033[M", -1, 0},
- { XK_KP_Delete, ControlMask, "\033[3;5~", +1, 0},
- { XK_KP_Delete, ShiftMask, "\033[2K", -1, 0},
- { XK_KP_Delete, ShiftMask, "\033[3;2~", +1, 0},
- { XK_KP_Delete, XK_ANY_MOD, "\033[3~", -1, 0},
- { XK_KP_Delete, XK_ANY_MOD, "\033[3~", +1, 0},
- { XK_KP_Multiply, XK_ANY_MOD, "\033Oj", +2, 0},
- { XK_KP_Add, XK_ANY_MOD, "\033Ok", +2, 0},
- { XK_KP_Enter, XK_ANY_MOD, "\033OM", +2, 0},
- { XK_KP_Enter, XK_ANY_MOD, "\r", -1, 0},
- { XK_KP_Subtract, XK_ANY_MOD, "\033Om", +2, 0},
- { XK_KP_Decimal, XK_ANY_MOD, "\033On", +2, 0},
- { XK_KP_Divide, XK_ANY_MOD, "\033Oo", +2, 0},
- { XK_KP_0, XK_ANY_MOD, "\033Op", +2, 0},
- { XK_KP_1, XK_ANY_MOD, "\033Oq", +2, 0},
- { XK_KP_2, XK_ANY_MOD, "\033Or", +2, 0},
- { XK_KP_3, XK_ANY_MOD, "\033Os", +2, 0},
- { XK_KP_4, XK_ANY_MOD, "\033Ot", +2, 0},
- { XK_KP_5, XK_ANY_MOD, "\033Ou", +2, 0},
- { XK_KP_6, XK_ANY_MOD, "\033Ov", +2, 0},
- { XK_KP_7, XK_ANY_MOD, "\033Ow", +2, 0},
- { XK_KP_8, XK_ANY_MOD, "\033Ox", +2, 0},
- { XK_KP_9, XK_ANY_MOD, "\033Oy", +2, 0},
- { XK_Up, ShiftMask, "\033[1;2A", 0, 0},
- { XK_Up, Mod1Mask, "\033[1;3A", 0, 0},
- { XK_Up, ShiftMask|Mod1Mask,"\033[1;4A", 0, 0},
- { XK_Up, ControlMask, "\033[1;5A", 0, 0},
- { XK_Up, ShiftMask|ControlMask,"\033[1;6A", 0, 0},
- { XK_Up, ControlMask|Mod1Mask,"\033[1;7A", 0, 0},
- { XK_Up,ShiftMask|ControlMask|Mod1Mask,"\033[1;8A", 0, 0},
- { XK_Up, XK_ANY_MOD, "\033[A", 0, -1},
- { XK_Up, XK_ANY_MOD, "\033OA", 0, +1},
- { XK_Down, ShiftMask, "\033[1;2B", 0, 0},
- { XK_Down, Mod1Mask, "\033[1;3B", 0, 0},
- { XK_Down, ShiftMask|Mod1Mask,"\033[1;4B", 0, 0},
- { XK_Down, ControlMask, "\033[1;5B", 0, 0},
- { XK_Down, ShiftMask|ControlMask,"\033[1;6B", 0, 0},
- { XK_Down, ControlMask|Mod1Mask,"\033[1;7B", 0, 0},
- { XK_Down,ShiftMask|ControlMask|Mod1Mask,"\033[1;8B",0, 0},
- { XK_Down, XK_ANY_MOD, "\033[B", 0, -1},
- { XK_Down, XK_ANY_MOD, "\033OB", 0, +1},
- { XK_Left, ShiftMask, "\033[1;2D", 0, 0},
- { XK_Left, Mod1Mask, "\033[1;3D", 0, 0},
- { XK_Left, ShiftMask|Mod1Mask,"\033[1;4D", 0, 0},
- { XK_Left, ControlMask, "\033[1;5D", 0, 0},
- { XK_Left, ShiftMask|ControlMask,"\033[1;6D", 0, 0},
- { XK_Left, ControlMask|Mod1Mask,"\033[1;7D", 0, 0},
- { XK_Left,ShiftMask|ControlMask|Mod1Mask,"\033[1;8D",0, 0},
- { XK_Left, XK_ANY_MOD, "\033[D", 0, -1},
- { XK_Left, XK_ANY_MOD, "\033OD", 0, +1},
- { XK_Right, ShiftMask, "\033[1;2C", 0, 0},
- { XK_Right, Mod1Mask, "\033[1;3C", 0, 0},
- { XK_Right, ShiftMask|Mod1Mask,"\033[1;4C", 0, 0},
- { XK_Right, ControlMask, "\033[1;5C", 0, 0},
- { XK_Right, ShiftMask|ControlMask,"\033[1;6C", 0, 0},
- { XK_Right, ControlMask|Mod1Mask,"\033[1;7C", 0, 0},
- { XK_Right,ShiftMask|ControlMask|Mod1Mask,"\033[1;8C",0, 0},
- { XK_Right, XK_ANY_MOD, "\033[C", 0, -1},
- { XK_Right, XK_ANY_MOD, "\033OC", 0, +1},
- { XK_ISO_Left_Tab, ShiftMask, "\033[Z", 0, 0},
- { XK_Return, Mod1Mask, "\033\r", 0, 0},
- { XK_Return, XK_ANY_MOD, "\r", 0, 0},
- { XK_Insert, ShiftMask, "\033[4l", -1, 0},
- { XK_Insert, ShiftMask, "\033[2;2~", +1, 0},
- { XK_Insert, ControlMask, "\033[L", -1, 0},
- { XK_Insert, ControlMask, "\033[2;5~", +1, 0},
- { XK_Insert, XK_ANY_MOD, "\033[4h", -1, 0},
- { XK_Insert, XK_ANY_MOD, "\033[2~", +1, 0},
- { XK_Delete, ControlMask, "\033[M", -1, 0},
- { XK_Delete, ControlMask, "\033[3;5~", +1, 0},
- { XK_Delete, ShiftMask, "\033[2K", -1, 0},
- { XK_Delete, ShiftMask, "\033[3;2~", +1, 0},
- { XK_Delete, XK_ANY_MOD, "\033[3~", -1, 0},
- { XK_Delete, XK_ANY_MOD, "\033[3~", +1, 0},
- { XK_BackSpace, XK_NO_MOD, "\177", 0, 0},
- { XK_BackSpace, Mod1Mask, "\033\177", 0, 0},
- { XK_Home, ShiftMask, "\033[2J", 0, -1},
- { XK_Home, ShiftMask, "\033[1;2H", 0, +1},
- { XK_Home, XK_ANY_MOD, "\033[H", 0, -1},
- { XK_Home, XK_ANY_MOD, "\033[1~", 0, +1},
- { XK_End, ControlMask, "\033[J", -1, 0},
- { XK_End, ControlMask, "\033[1;5F", +1, 0},
- { XK_End, ShiftMask, "\033[K", -1, 0},
- { XK_End, ShiftMask, "\033[1;2F", +1, 0},
- { XK_End, XK_ANY_MOD, "\033[4~", 0, 0},
- { XK_Prior, ControlMask, "\033[5;5~", 0, 0},
- { XK_Prior, ShiftMask, "\033[5;2~", 0, 0},
- { XK_Prior, XK_ANY_MOD, "\033[5~", 0, 0},
- { XK_Next, ControlMask, "\033[6;5~", 0, 0},
- { XK_Next, ShiftMask, "\033[6;2~", 0, 0},
- { XK_Next, XK_ANY_MOD, "\033[6~", 0, 0},
- { XK_F1, XK_NO_MOD, "\033OP" , 0, 0},
- { XK_F1, /* F13 */ ShiftMask, "\033[1;2P", 0, 0},
- { XK_F1, /* F25 */ ControlMask, "\033[1;5P", 0, 0},
- { XK_F1, /* F37 */ Mod4Mask, "\033[1;6P", 0, 0},
- { XK_F1, /* F49 */ Mod1Mask, "\033[1;3P", 0, 0},
- { XK_F1, /* F61 */ Mod3Mask, "\033[1;4P", 0, 0},
- { XK_F2, XK_NO_MOD, "\033OQ" , 0, 0},
- { XK_F2, /* F14 */ ShiftMask, "\033[1;2Q", 0, 0},
- { XK_F2, /* F26 */ ControlMask, "\033[1;5Q", 0, 0},
- { XK_F2, /* F38 */ Mod4Mask, "\033[1;6Q", 0, 0},
- { XK_F2, /* F50 */ Mod1Mask, "\033[1;3Q", 0, 0},
- { XK_F2, /* F62 */ Mod3Mask, "\033[1;4Q", 0, 0},
- { XK_F3, XK_NO_MOD, "\033OR" , 0, 0},
- { XK_F3, /* F15 */ ShiftMask, "\033[1;2R", 0, 0},
- { XK_F3, /* F27 */ ControlMask, "\033[1;5R", 0, 0},
- { XK_F3, /* F39 */ Mod4Mask, "\033[1;6R", 0, 0},
- { XK_F3, /* F51 */ Mod1Mask, "\033[1;3R", 0, 0},
- { XK_F3, /* F63 */ Mod3Mask, "\033[1;4R", 0, 0},
- { XK_F4, XK_NO_MOD, "\033OS" , 0, 0},
- { XK_F4, /* F16 */ ShiftMask, "\033[1;2S", 0, 0},
- { XK_F4, /* F28 */ ControlMask, "\033[1;5S", 0, 0},
- { XK_F4, /* F40 */ Mod4Mask, "\033[1;6S", 0, 0},
- { XK_F4, /* F52 */ Mod1Mask, "\033[1;3S", 0, 0},
- { XK_F5, XK_NO_MOD, "\033[15~", 0, 0},
- { XK_F5, /* F17 */ ShiftMask, "\033[15;2~", 0, 0},
- { XK_F5, /* F29 */ ControlMask, "\033[15;5~", 0, 0},
- { XK_F5, /* F41 */ Mod4Mask, "\033[15;6~", 0, 0},
- { XK_F5, /* F53 */ Mod1Mask, "\033[15;3~", 0, 0},
- { XK_F6, XK_NO_MOD, "\033[17~", 0, 0},
- { XK_F6, /* F18 */ ShiftMask, "\033[17;2~", 0, 0},
- { XK_F6, /* F30 */ ControlMask, "\033[17;5~", 0, 0},
- { XK_F6, /* F42 */ Mod4Mask, "\033[17;6~", 0, 0},
- { XK_F6, /* F54 */ Mod1Mask, "\033[17;3~", 0, 0},
- { XK_F7, XK_NO_MOD, "\033[18~", 0, 0},
- { XK_F7, /* F19 */ ShiftMask, "\033[18;2~", 0, 0},
- { XK_F7, /* F31 */ ControlMask, "\033[18;5~", 0, 0},
- { XK_F7, /* F43 */ Mod4Mask, "\033[18;6~", 0, 0},
- { XK_F7, /* F55 */ Mod1Mask, "\033[18;3~", 0, 0},
- { XK_F8, XK_NO_MOD, "\033[19~", 0, 0},
- { XK_F8, /* F20 */ ShiftMask, "\033[19;2~", 0, 0},
- { XK_F8, /* F32 */ ControlMask, "\033[19;5~", 0, 0},
- { XK_F8, /* F44 */ Mod4Mask, "\033[19;6~", 0, 0},
- { XK_F8, /* F56 */ Mod1Mask, "\033[19;3~", 0, 0},
- { XK_F9, XK_NO_MOD, "\033[20~", 0, 0},
- { XK_F9, /* F21 */ ShiftMask, "\033[20;2~", 0, 0},
- { XK_F9, /* F33 */ ControlMask, "\033[20;5~", 0, 0},
- { XK_F9, /* F45 */ Mod4Mask, "\033[20;6~", 0, 0},
- { XK_F9, /* F57 */ Mod1Mask, "\033[20;3~", 0, 0},
- { XK_F10, XK_NO_MOD, "\033[21~", 0, 0},
- { XK_F10, /* F22 */ ShiftMask, "\033[21;2~", 0, 0},
- { XK_F10, /* F34 */ ControlMask, "\033[21;5~", 0, 0},
- { XK_F10, /* F46 */ Mod4Mask, "\033[21;6~", 0, 0},
- { XK_F10, /* F58 */ Mod1Mask, "\033[21;3~", 0, 0},
- { XK_F11, XK_NO_MOD, "\033[23~", 0, 0},
- { XK_F11, /* F23 */ ShiftMask, "\033[23;2~", 0, 0},
- { XK_F11, /* F35 */ ControlMask, "\033[23;5~", 0, 0},
- { XK_F11, /* F47 */ Mod4Mask, "\033[23;6~", 0, 0},
- { XK_F11, /* F59 */ Mod1Mask, "\033[23;3~", 0, 0},
- { XK_F12, XK_NO_MOD, "\033[24~", 0, 0},
- { XK_F12, /* F24 */ ShiftMask, "\033[24;2~", 0, 0},
- { XK_F12, /* F36 */ ControlMask, "\033[24;5~", 0, 0},
- { XK_F12, /* F48 */ Mod4Mask, "\033[24;6~", 0, 0},
- { XK_F12, /* F60 */ Mod1Mask, "\033[24;3~", 0, 0},
- { XK_F13, XK_NO_MOD, "\033[1;2P", 0, 0},
- { XK_F14, XK_NO_MOD, "\033[1;2Q", 0, 0},
- { XK_F15, XK_NO_MOD, "\033[1;2R", 0, 0},
- { XK_F16, XK_NO_MOD, "\033[1;2S", 0, 0},
- { XK_F17, XK_NO_MOD, "\033[15;2~", 0, 0},
- { XK_F18, XK_NO_MOD, "\033[17;2~", 0, 0},
- { XK_F19, XK_NO_MOD, "\033[18;2~", 0, 0},
- { XK_F20, XK_NO_MOD, "\033[19;2~", 0, 0},
- { XK_F21, XK_NO_MOD, "\033[20;2~", 0, 0},
- { XK_F22, XK_NO_MOD, "\033[21;2~", 0, 0},
- { XK_F23, XK_NO_MOD, "\033[23;2~", 0, 0},
- { XK_F24, XK_NO_MOD, "\033[24;2~", 0, 0},
- { XK_F25, XK_NO_MOD, "\033[1;5P", 0, 0},
- { XK_F26, XK_NO_MOD, "\033[1;5Q", 0, 0},
- { XK_F27, XK_NO_MOD, "\033[1;5R", 0, 0},
- { XK_F28, XK_NO_MOD, "\033[1;5S", 0, 0},
- { XK_F29, XK_NO_MOD, "\033[15;5~", 0, 0},
- { XK_F30, XK_NO_MOD, "\033[17;5~", 0, 0},
- { XK_F31, XK_NO_MOD, "\033[18;5~", 0, 0},
- { XK_F32, XK_NO_MOD, "\033[19;5~", 0, 0},
- { XK_F33, XK_NO_MOD, "\033[20;5~", 0, 0},
- { XK_F34, XK_NO_MOD, "\033[21;5~", 0, 0},
- { XK_F35, XK_NO_MOD, "\033[23;5~", 0, 0},
+ /* keysym mask string appkey appcursor */
+ { XK_KP_Home, ShiftMask, "\033[2J", 0, -1},
+ { XK_KP_Home, ShiftMask, "\033[1;2H", 0, +1},
+ { XK_KP_Home, XK_ANY_MOD, "\033[H", 0, -1},
+ { XK_KP_Home, XK_ANY_MOD, "\033[1~", 0, +1},
+ { XK_KP_Up, XK_ANY_MOD, "\033Ox", +1, 0},
+ { XK_KP_Up, XK_ANY_MOD, "\033[A", 0, -1},
+ { XK_KP_Up, XK_ANY_MOD, "\033OA", 0, +1},
+ { XK_KP_Down, XK_ANY_MOD, "\033Or", +1, 0},
+ { XK_KP_Down, XK_ANY_MOD, "\033[B", 0, -1},
+ { XK_KP_Down, XK_ANY_MOD, "\033OB", 0, +1},
+ { XK_KP_Left, XK_ANY_MOD, "\033Ot", +1, 0},
+ { XK_KP_Left, XK_ANY_MOD, "\033[D", 0, -1},
+ { XK_KP_Left, XK_ANY_MOD, "\033OD", 0, +1},
+ { XK_KP_Right, XK_ANY_MOD, "\033Ov", +1, 0},
+ { XK_KP_Right, XK_ANY_MOD, "\033[C", 0, -1},
+ { XK_KP_Right, XK_ANY_MOD, "\033OC", 0, +1},
+ { XK_KP_Prior, ShiftMask, "\033[5;2~", 0, 0},
+ { XK_KP_Prior, XK_ANY_MOD, "\033[5~", 0, 0},
+ { XK_KP_Begin, XK_ANY_MOD, "\033[E", 0, 0},
+ { XK_KP_End, ControlMask, "\033[J", -1, 0},
+ { XK_KP_End, ControlMask, "\033[1;5F", +1, 0},
+ { XK_KP_End, ShiftMask, "\033[K", -1, 0},
+ { XK_KP_End, ShiftMask, "\033[1;2F", +1, 0},
+ { XK_KP_End, XK_ANY_MOD, "\033[4~", 0, 0},
+ { XK_KP_Next, ShiftMask, "\033[6;2~", 0, 0},
+ { XK_KP_Next, XK_ANY_MOD, "\033[6~", 0, 0},
+ { XK_KP_Insert, ShiftMask, "\033[2;2~", +1, 0},
+ { XK_KP_Insert, ShiftMask, "\033[4l", -1, 0},
+ { XK_KP_Insert, ControlMask, "\033[L", -1, 0},
+ { XK_KP_Insert, ControlMask, "\033[2;5~", +1, 0},
+ { XK_KP_Insert, XK_ANY_MOD, "\033[4h", -1, 0},
+ { XK_KP_Insert, XK_ANY_MOD, "\033[2~", +1, 0},
+ { XK_KP_Delete, ControlMask, "\033[M", -1, 0},
+ { XK_KP_Delete, ControlMask, "\033[3;5~", +1, 0},
+ { XK_KP_Delete, ShiftMask, "\033[2K", -1, 0},
+ { XK_KP_Delete, ShiftMask, "\033[3;2~", +1, 0},
+ #if DELKEY_PATCH
+ { XK_KP_Delete, XK_ANY_MOD, "\033[3~", -1, 0},
+ #else
+ { XK_KP_Delete, XK_ANY_MOD, "\033[P", -1, 0},
+ #endif // DELKEY_PATCH
+ { XK_KP_Delete, XK_ANY_MOD, "\033[3~", +1, 0},
+ { XK_KP_Multiply, XK_ANY_MOD, "\033Oj", +2, 0},
+ { XK_KP_Add, XK_ANY_MOD, "\033Ok", +2, 0},
+ { XK_KP_Enter, XK_ANY_MOD, "\033OM", +2, 0},
+ { XK_KP_Enter, XK_ANY_MOD, "\r", -1, 0},
+ { XK_KP_Subtract, XK_ANY_MOD, "\033Om", +2, 0},
+ { XK_KP_Decimal, XK_ANY_MOD, "\033On", +2, 0},
+ { XK_KP_Divide, XK_ANY_MOD, "\033Oo", +2, 0},
+ { XK_KP_0, XK_ANY_MOD, "\033Op", +2, 0},
+ { XK_KP_1, XK_ANY_MOD, "\033Oq", +2, 0},
+ { XK_KP_2, XK_ANY_MOD, "\033Or", +2, 0},
+ { XK_KP_3, XK_ANY_MOD, "\033Os", +2, 0},
+ { XK_KP_4, XK_ANY_MOD, "\033Ot", +2, 0},
+ { XK_KP_5, XK_ANY_MOD, "\033Ou", +2, 0},
+ { XK_KP_6, XK_ANY_MOD, "\033Ov", +2, 0},
+ { XK_KP_7, XK_ANY_MOD, "\033Ow", +2, 0},
+ { XK_KP_8, XK_ANY_MOD, "\033Ox", +2, 0},
+ { XK_KP_9, XK_ANY_MOD, "\033Oy", +2, 0},
+ { XK_Up, ShiftMask, "\033[1;2A", 0, 0},
+ { XK_Up, Mod1Mask, "\033[1;3A", 0, 0},
+ { XK_Up, ShiftMask|Mod1Mask,"\033[1;4A", 0, 0},
+ { XK_Up, ControlMask, "\033[1;5A", 0, 0},
+ { XK_Up, ShiftMask|ControlMask,"\033[1;6A", 0, 0},
+ { XK_Up, ControlMask|Mod1Mask,"\033[1;7A", 0, 0},
+ { XK_Up,ShiftMask|ControlMask|Mod1Mask,"\033[1;8A", 0, 0},
+ { XK_Up, XK_ANY_MOD, "\033[A", 0, -1},
+ { XK_Up, XK_ANY_MOD, "\033OA", 0, +1},
+ { XK_Down, ShiftMask, "\033[1;2B", 0, 0},
+ { XK_Down, Mod1Mask, "\033[1;3B", 0, 0},
+ { XK_Down, ShiftMask|Mod1Mask,"\033[1;4B", 0, 0},
+ { XK_Down, ControlMask, "\033[1;5B", 0, 0},
+ { XK_Down, ShiftMask|ControlMask,"\033[1;6B", 0, 0},
+ { XK_Down, ControlMask|Mod1Mask,"\033[1;7B", 0, 0},
+ { XK_Down,ShiftMask|ControlMask|Mod1Mask,"\033[1;8B",0, 0},
+ { XK_Down, XK_ANY_MOD, "\033[B", 0, -1},
+ { XK_Down, XK_ANY_MOD, "\033OB", 0, +1},
+ { XK_Left, ShiftMask, "\033[1;2D", 0, 0},
+ { XK_Left, Mod1Mask, "\033[1;3D", 0, 0},
+ { XK_Left, ShiftMask|Mod1Mask,"\033[1;4D", 0, 0},
+ { XK_Left, ControlMask, "\033[1;5D", 0, 0},
+ { XK_Left, ShiftMask|ControlMask,"\033[1;6D", 0, 0},
+ { XK_Left, ControlMask|Mod1Mask,"\033[1;7D", 0, 0},
+ { XK_Left,ShiftMask|ControlMask|Mod1Mask,"\033[1;8D",0, 0},
+ { XK_Left, XK_ANY_MOD, "\033[D", 0, -1},
+ { XK_Left, XK_ANY_MOD, "\033OD", 0, +1},
+ { XK_Right, ShiftMask, "\033[1;2C", 0, 0},
+ { XK_Right, Mod1Mask, "\033[1;3C", 0, 0},
+ { XK_Right, ShiftMask|Mod1Mask,"\033[1;4C", 0, 0},
+ { XK_Right, ControlMask, "\033[1;5C", 0, 0},
+ { XK_Right, ShiftMask|ControlMask,"\033[1;6C", 0, 0},
+ { XK_Right, ControlMask|Mod1Mask,"\033[1;7C", 0, 0},
+ { XK_Right,ShiftMask|ControlMask|Mod1Mask,"\033[1;8C",0, 0},
+ { XK_Right, XK_ANY_MOD, "\033[C", 0, -1},
+ { XK_Right, XK_ANY_MOD, "\033OC", 0, +1},
+ { XK_ISO_Left_Tab, ShiftMask, "\033[Z", 0, 0},
+ { XK_Return, Mod1Mask, "\033\r", 0, 0},
+ { XK_Return, XK_ANY_MOD, "\r", 0, 0},
+ { XK_Insert, ShiftMask, "\033[4l", -1, 0},
+ { XK_Insert, ShiftMask, "\033[2;2~", +1, 0},
+ { XK_Insert, ControlMask, "\033[L", -1, 0},
+ { XK_Insert, ControlMask, "\033[2;5~", +1, 0},
+ { XK_Insert, XK_ANY_MOD, "\033[4h", -1, 0},
+ { XK_Insert, XK_ANY_MOD, "\033[2~", +1, 0},
+ { XK_Delete, ControlMask, "\033[M", -1, 0},
+ { XK_Delete, ControlMask, "\033[3;5~", +1, 0},
+ { XK_Delete, ShiftMask, "\033[2K", -1, 0},
+ { XK_Delete, ShiftMask, "\033[3;2~", +1, 0},
+ #if DELKEY_PATCH
+ { XK_Delete, XK_ANY_MOD, "\033[3~", -1, 0},
+ #else
+ { XK_Delete, XK_ANY_MOD, "\033[P", -1, 0},
+ #endif // DELKEY_PATCH
+ { XK_Delete, XK_ANY_MOD, "\033[3~", +1, 0},
+ { XK_BackSpace, XK_NO_MOD, "\177", 0, 0},
+ { XK_BackSpace, Mod1Mask, "\033\177", 0, 0},
+ { XK_Home, ShiftMask, "\033[2J", 0, -1},
+ { XK_Home, ShiftMask, "\033[1;2H", 0, +1},
+ { XK_Home, XK_ANY_MOD, "\033[H", 0, -1},
+ { XK_Home, XK_ANY_MOD, "\033[1~", 0, +1},
+ { XK_End, ControlMask, "\033[J", -1, 0},
+ { XK_End, ControlMask, "\033[1;5F", +1, 0},
+ { XK_End, ShiftMask, "\033[K", -1, 0},
+ { XK_End, ShiftMask, "\033[1;2F", +1, 0},
+ { XK_End, XK_ANY_MOD, "\033[4~", 0, 0},
+ { XK_Prior, ControlMask, "\033[5;5~", 0, 0},
+ { XK_Prior, ShiftMask, "\033[5;2~", 0, 0},
+ { XK_Prior, XK_ANY_MOD, "\033[5~", 0, 0},
+ { XK_Next, ControlMask, "\033[6;5~", 0, 0},
+ { XK_Next, ShiftMask, "\033[6;2~", 0, 0},
+ { XK_Next, XK_ANY_MOD, "\033[6~", 0, 0},
+ { XK_F1, XK_NO_MOD, "\033OP" , 0, 0},
+ { XK_F1, /* F13 */ ShiftMask, "\033[1;2P", 0, 0},
+ { XK_F1, /* F25 */ ControlMask, "\033[1;5P", 0, 0},
+ { XK_F1, /* F37 */ Mod4Mask, "\033[1;6P", 0, 0},
+ { XK_F1, /* F49 */ Mod1Mask, "\033[1;3P", 0, 0},
+ { XK_F1, /* F61 */ Mod3Mask, "\033[1;4P", 0, 0},
+ { XK_F2, XK_NO_MOD, "\033OQ" , 0, 0},
+ { XK_F2, /* F14 */ ShiftMask, "\033[1;2Q", 0, 0},
+ { XK_F2, /* F26 */ ControlMask, "\033[1;5Q", 0, 0},
+ { XK_F2, /* F38 */ Mod4Mask, "\033[1;6Q", 0, 0},
+ { XK_F2, /* F50 */ Mod1Mask, "\033[1;3Q", 0, 0},
+ { XK_F2, /* F62 */ Mod3Mask, "\033[1;4Q", 0, 0},
+ { XK_F3, XK_NO_MOD, "\033OR" , 0, 0},
+ { XK_F3, /* F15 */ ShiftMask, "\033[1;2R", 0, 0},
+ { XK_F3, /* F27 */ ControlMask, "\033[1;5R", 0, 0},
+ { XK_F3, /* F39 */ Mod4Mask, "\033[1;6R", 0, 0},
+ { XK_F3, /* F51 */ Mod1Mask, "\033[1;3R", 0, 0},
+ { XK_F3, /* F63 */ Mod3Mask, "\033[1;4R", 0, 0},
+ { XK_F4, XK_NO_MOD, "\033OS" , 0, 0},
+ { XK_F4, /* F16 */ ShiftMask, "\033[1;2S", 0, 0},
+ { XK_F4, /* F28 */ ControlMask, "\033[1;5S", 0, 0},
+ { XK_F4, /* F40 */ Mod4Mask, "\033[1;6S", 0, 0},
+ { XK_F4, /* F52 */ Mod1Mask, "\033[1;3S", 0, 0},
+ { XK_F5, XK_NO_MOD, "\033[15~", 0, 0},
+ { XK_F5, /* F17 */ ShiftMask, "\033[15;2~", 0, 0},
+ { XK_F5, /* F29 */ ControlMask, "\033[15;5~", 0, 0},
+ { XK_F5, /* F41 */ Mod4Mask, "\033[15;6~", 0, 0},
+ { XK_F5, /* F53 */ Mod1Mask, "\033[15;3~", 0, 0},
+ { XK_F6, XK_NO_MOD, "\033[17~", 0, 0},
+ { XK_F6, /* F18 */ ShiftMask, "\033[17;2~", 0, 0},
+ { XK_F6, /* F30 */ ControlMask, "\033[17;5~", 0, 0},
+ { XK_F6, /* F42 */ Mod4Mask, "\033[17;6~", 0, 0},
+ { XK_F6, /* F54 */ Mod1Mask, "\033[17;3~", 0, 0},
+ { XK_F7, XK_NO_MOD, "\033[18~", 0, 0},
+ { XK_F7, /* F19 */ ShiftMask, "\033[18;2~", 0, 0},
+ { XK_F7, /* F31 */ ControlMask, "\033[18;5~", 0, 0},
+ { XK_F7, /* F43 */ Mod4Mask, "\033[18;6~", 0, 0},
+ { XK_F7, /* F55 */ Mod1Mask, "\033[18;3~", 0, 0},
+ { XK_F8, XK_NO_MOD, "\033[19~", 0, 0},
+ { XK_F8, /* F20 */ ShiftMask, "\033[19;2~", 0, 0},
+ { XK_F8, /* F32 */ ControlMask, "\033[19;5~", 0, 0},
+ { XK_F8, /* F44 */ Mod4Mask, "\033[19;6~", 0, 0},
+ { XK_F8, /* F56 */ Mod1Mask, "\033[19;3~", 0, 0},
+ { XK_F9, XK_NO_MOD, "\033[20~", 0, 0},
+ { XK_F9, /* F21 */ ShiftMask, "\033[20;2~", 0, 0},
+ { XK_F9, /* F33 */ ControlMask, "\033[20;5~", 0, 0},
+ { XK_F9, /* F45 */ Mod4Mask, "\033[20;6~", 0, 0},
+ { XK_F9, /* F57 */ Mod1Mask, "\033[20;3~", 0, 0},
+ { XK_F10, XK_NO_MOD, "\033[21~", 0, 0},
+ { XK_F10, /* F22 */ ShiftMask, "\033[21;2~", 0, 0},
+ { XK_F10, /* F34 */ ControlMask, "\033[21;5~", 0, 0},
+ { XK_F10, /* F46 */ Mod4Mask, "\033[21;6~", 0, 0},
+ { XK_F10, /* F58 */ Mod1Mask, "\033[21;3~", 0, 0},
+ { XK_F11, XK_NO_MOD, "\033[23~", 0, 0},
+ { XK_F11, /* F23 */ ShiftMask, "\033[23;2~", 0, 0},
+ { XK_F11, /* F35 */ ControlMask, "\033[23;5~", 0, 0},
+ { XK_F11, /* F47 */ Mod4Mask, "\033[23;6~", 0, 0},
+ { XK_F11, /* F59 */ Mod1Mask, "\033[23;3~", 0, 0},
+ { XK_F12, XK_NO_MOD, "\033[24~", 0, 0},
+ { XK_F12, /* F24 */ ShiftMask, "\033[24;2~", 0, 0},
+ { XK_F12, /* F36 */ ControlMask, "\033[24;5~", 0, 0},
+ { XK_F12, /* F48 */ Mod4Mask, "\033[24;6~", 0, 0},
+ { XK_F12, /* F60 */ Mod1Mask, "\033[24;3~", 0, 0},
+ { XK_F13, XK_NO_MOD, "\033[1;2P", 0, 0},
+ { XK_F14, XK_NO_MOD, "\033[1;2Q", 0, 0},
+ { XK_F15, XK_NO_MOD, "\033[1;2R", 0, 0},
+ { XK_F16, XK_NO_MOD, "\033[1;2S", 0, 0},
+ { XK_F17, XK_NO_MOD, "\033[15;2~", 0, 0},
+ { XK_F18, XK_NO_MOD, "\033[17;2~", 0, 0},
+ { XK_F19, XK_NO_MOD, "\033[18;2~", 0, 0},
+ { XK_F20, XK_NO_MOD, "\033[19;2~", 0, 0},
+ { XK_F21, XK_NO_MOD, "\033[20;2~", 0, 0},
+ { XK_F22, XK_NO_MOD, "\033[21;2~", 0, 0},
+ { XK_F23, XK_NO_MOD, "\033[23;2~", 0, 0},
+ { XK_F24, XK_NO_MOD, "\033[24;2~", 0, 0},
+ { XK_F25, XK_NO_MOD, "\033[1;5P", 0, 0},
+ { XK_F26, XK_NO_MOD, "\033[1;5Q", 0, 0},
+ { XK_F27, XK_NO_MOD, "\033[1;5R", 0, 0},
+ { XK_F28, XK_NO_MOD, "\033[1;5S", 0, 0},
+ { XK_F29, XK_NO_MOD, "\033[15;5~", 0, 0},
+ { XK_F30, XK_NO_MOD, "\033[17;5~", 0, 0},
+ { XK_F31, XK_NO_MOD, "\033[18;5~", 0, 0},
+ { XK_F32, XK_NO_MOD, "\033[19;5~", 0, 0},
+ { XK_F33, XK_NO_MOD, "\033[20;5~", 0, 0},
+ { XK_F34, XK_NO_MOD, "\033[21;5~", 0, 0},
+ { XK_F35, XK_NO_MOD, "\033[23;5~", 0, 0},
};
+#endif // FIXKEYBOARDINPUT_PATCH
/*
* Selection types' masks.
@@ -567,7 +783,7 @@ static Key key[] = {
* If no match is found, regular selection is used.
*/
static uint selmasks[] = {
- [SEL_RECTANGULAR] = Mod1Mask,
+ [SEL_RECTANGULAR] = Mod1Mask,
};
/*
@@ -575,6 +791,40 @@ static uint selmasks[] = {
* of single wide characters.
*/
static char ascii_printable[] =
-" !\"#$%&'()*+,-./0123456789:;<=>?"
-"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
-"`abcdefghijklmnopqrstuvwxyz{|}~";
+ " !\"#$%&'()*+,-./0123456789:;<=>?"
+ "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
+ "`abcdefghijklmnopqrstuvwxyz{|}~";
+
+#if RIGHTCLICKTOPLUMB_PATCH
+/*
+ * plumb_cmd is run on mouse button 3 click, with argument set to
+ * current selection and with cwd set to the cwd of the active shell
+ */
+static char *plumb_cmd = "plumb";
+#endif // RIGHTCLICKTOPLUMB_PATCH
+
+#if UNDERCURL_PATCH
+/**
+ * Undercurl style. Set UNDERCURL_STYLE to one of the available styles.
+ *
+ * Curly: Dunno how to draw it *shrug*
+ * _ _ _ _
+ * ( ) ( ) ( ) ( )
+ * (_) (_) (_) (_)
+ *
+ * Spiky:
+ * /\ /\ /\ /\
+ * \/ \/ \/
+ *
+ * Capped:
+ * _ _ _
+ * / \ / \ / \
+ * \_/ \_/
+ */
+// Available styles
+#define UNDERCURL_CURLY 0
+#define UNDERCURL_SPIKY 1
+#define UNDERCURL_CAPPED 2
+// Active style
+#define UNDERCURL_STYLE UNDERCURL_SPIKY
+#endif // UNDERCURL_PATCH
diff --git a/config.mk b/config.mk
@@ -1,5 +1,5 @@
# st version
-VERSION = 0.8.5
+VERSION = 0.9.3
# Customize below to fit your system
@@ -14,17 +14,35 @@ X11LIB = /usr/X11R6/lib
PKG_CONFIG = pkg-config
+# Alpha patch / ALPHA_PATCH
+XRENDER = `$(PKG_CONFIG) --libs xrender`
+
+# Uncomment this for the themed cursor patch / THEMED_CURSOR_PATCH
+#XCURSOR = `$(PKG_CONFIG) --libs xcursor`
+
+# Ligatures patch / LIGATURES_PATCH (HarfBuzz)
+LIGATURES_C = hb.c
+LIGATURES_H = hb.h
+LIGATURES_INC = `$(PKG_CONFIG) --cflags harfbuzz`
+LIGATURES_LIBS = `$(PKG_CONFIG) --libs harfbuzz`
+
+# SIXEL patch / SIXEL_PATCH (for manga-tui image support)
+SIXEL_C = sixel.c sixel_hls.c
+SIXEL_LIBS = `$(PKG_CONFIG) --libs imlib2`
+
+# Uncomment for the netwmicon patch / NETWMICON_PATCH
+#NETWMICON_LIBS = `$(PKG_CONFIG) --libs gdlib`
+
# includes and libs
INCS = -I$(X11INC) \
- `$(PKG_CONFIG) --cflags glib-2.0` \
`$(PKG_CONFIG) --cflags fontconfig` \
`$(PKG_CONFIG) --cflags freetype2` \
- `$(PKG_CONFIG) --cflags harfbuzz`
-LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lgd \
- `$(PKG_CONFIG) --libs glib-2.0` \
+ $(LIGATURES_INC)
+LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft ${SIXEL_LIBS} ${XRENDER} ${XCURSOR}\
`$(PKG_CONFIG) --libs fontconfig` \
`$(PKG_CONFIG) --libs freetype2` \
- `$(PKG_CONFIG) --libs harfbuzz`
+ $(LIGATURES_LIBS) \
+ $(NETWMICON_LIBS)
# flags
STCPPFLAGS = -DVERSION=\"$(VERSION)\" -DICON=\"$(ICONPREFIX)/$(ICONNAME)\" -D_XOPEN_SOURCE=600
@@ -32,10 +50,8 @@ STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS)
STLDFLAGS = $(LIBS) $(LDFLAGS)
# OpenBSD:
-#CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 -D_BSD_SOURCE
-#LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft \
-# `$(PKG_CONFIG) --libs fontconfig` \
-# `$(PKG_CONFIG) --libs freetype2`
+#CPPFLAGS = $(STCPPFLAGS) -D_XOPEN_SOURCE=600
+#MANPREFIX = ${PREFIX}/man
# compiler and linker
# CC = c99
diff --git a/default.nix b/default.nix
@@ -1,42 +0,0 @@
-{ lib, stdenv, fetchurl, pkg-config, fontconfig, freetype, libX11, libXft
-, harfbuzz, gd, glib, ncurses, writeText, conf ? null, patches ? [ ]
-, extraLibs ? [ ], nixosTests }:
-
-stdenv.mkDerivation rec {
- pname = "st-snazzy";
- version = "0.8.5";
-
- src = ./.;
- inherit patches;
-
- configFile =
- lib.optionalString (conf != null) (writeText "config.def.h" conf);
-
- postPatch = lib.optionalString (conf != null) "cp ${configFile} config.def.h"
- + lib.optionalString stdenv.isDarwin ''
- substituteInPlace config.mk --replace "-lrt" ""
- '';
-
- strictDeps = true;
-
- makeFlags = [ "PKG_CONFIG=${stdenv.cc.targetPrefix}pkg-config" ];
-
- nativeBuildInputs = [ pkg-config ncurses fontconfig freetype ];
- buildInputs = [ libX11 libXft harfbuzz gd glib ] ++ extraLibs;
-
- preInstall = ''
- export TERMINFO=$out/share/terminfo
- '';
-
- installFlags = [ "PREFIX=$(out)" ];
-
- passthru.tests.test = nixosTests.terminal-emulators.st;
-
- meta = with lib; {
- homepage = "https://github.com/siduck/st";
- description = "snazzy terminal (suckless + lightweight)";
- license = licenses.mit;
- maintainers = with maintainers; [ sioodmy ];
- platforms = platforms.unix;
- };
-}
diff --git a/flake.lock b/flake.lock
@@ -1,43 +0,0 @@
-{
- "nodes": {
- "flake-utils": {
- "locked": {
- "lastModified": 1656928814,
- "narHash": "sha256-RIFfgBuKz6Hp89yRr7+NR5tzIAbn52h8vT6vXkYjZoM=",
- "owner": "numtide",
- "repo": "flake-utils",
- "rev": "7e2a3b3dfd9af950a856d66b0a7d01e3c18aa249",
- "type": "github"
- },
- "original": {
- "owner": "numtide",
- "repo": "flake-utils",
- "type": "github"
- }
- },
- "nixpkgs": {
- "locked": {
- "lastModified": 1658161305,
- "narHash": "sha256-X/nhnMCa1Wx4YapsspyAs6QYz6T/85FofrI6NpdPDHg=",
- "owner": "nixos",
- "repo": "nixpkgs",
- "rev": "e4d49de45a3b5dbcb881656b4e3986e666141ea9",
- "type": "github"
- },
- "original": {
- "owner": "nixos",
- "ref": "nixos-unstable",
- "repo": "nixpkgs",
- "type": "github"
- }
- },
- "root": {
- "inputs": {
- "flake-utils": "flake-utils",
- "nixpkgs": "nixpkgs"
- }
- }
- },
- "root": "root",
- "version": 7
-}
diff --git a/flake.nix b/flake.nix
@@ -1,35 +0,0 @@
-{
- description = "snazzy terminal (suckless + lightweight)";
-
- inputs.nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
- inputs.flake-utils.url = "github:numtide/flake-utils";
-
- outputs = { self, nixpkgs, flake-utils }:
- flake-utils.lib.eachDefaultSystem (system:
- let pkgs = nixpkgs.legacyPackages.${system};
- in rec {
- packages = flake-utils.lib.flattenTree {
- st-snazzy = pkgs.callPackage ./default.nix { };
- };
- defaultPackage = packages.st-snazzy;
- apps.st-snazzy = flake-utils.lib.mkApp {
- drv = packages.st-snazzy;
- exePath = "/bin/st";
- };
- apps.default = apps.st-snazzy;
- defaultApp = apps.st-snazzy;
- devShell = pkgs.mkShell rec {
- name = "st-snazzy";
- packages = with pkgs; [
- pkgconfig
- xorg.libX11
- xorg.libXft
- fontconfig
- harfbuzz
- gd
- glib
- ];
- };
-
- });
-}
diff --git a/hb.c b/hb.c
@@ -1,13 +1,18 @@
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
+#include <time.h>
#include <X11/Xft/Xft.h>
+#include <X11/cursorfont.h>
#include <hb.h>
#include <hb-ft.h>
#include "st.h"
+#include "hb.h"
+
+#define FEATURE(c1,c2,c3,c4) { .tag = HB_TAG(c1,c2,c3,c4), .value = 1, .start = HB_FEATURE_GLOBAL_START, .end = HB_FEATURE_GLOBAL_END }
+#define BUFFER_STEP 256
-void hbtransformsegment(XftFont *xfont, const Glyph *string, hb_codepoint_t *codepoints, int start, int length);
hb_font_t *hbfindfont(XftFont *match);
typedef struct {
@@ -15,126 +20,120 @@ typedef struct {
hb_font_t *font;
} HbFontMatch;
-static int hbfontslen = 0;
-static HbFontMatch *hbfontcache = NULL;
+typedef struct {
+ size_t capacity;
+ HbFontMatch *fonts;
+} HbFontCache;
+
+static HbFontCache hbfontcache = { 0, NULL };
+
+typedef struct {
+ size_t capacity;
+ Rune *runes;
+} RuneBuffer;
+
+static RuneBuffer hbrunebuffer = { 0, NULL };
+static hb_buffer_t *hbbuffer;
+
+/*
+ * Poplulate the array with a list of font features, wrapped in FEATURE macro,
+ * e. g.
+ * FEATURE('c', 'a', 'l', 't'), FEATURE('d', 'l', 'i', 'g')
+ */
+hb_feature_t features[] = { };
+
+void
+hbcreatebuffer(void)
+{
+ hbbuffer = hb_buffer_create();
+}
+
+void
+hbdestroybuffer(void)
+{
+ hb_buffer_destroy(hbbuffer);
+}
void
-hbunloadfonts()
+hbunloadfonts(void)
{
- for (int i = 0; i < hbfontslen; i++) {
- hb_font_destroy(hbfontcache[i].font);
- XftUnlockFace(hbfontcache[i].match);
+ for (int i = 0; i < hbfontcache.capacity; i++) {
+ hb_font_destroy(hbfontcache.fonts[i].font);
+ XftUnlockFace(hbfontcache.fonts[i].match);
}
- if (hbfontcache != NULL) {
- free(hbfontcache);
- hbfontcache = NULL;
+ if (hbfontcache.fonts != NULL) {
+ free(hbfontcache.fonts);
+ hbfontcache.fonts = NULL;
}
- hbfontslen = 0;
+ hbfontcache.capacity = 0;
}
hb_font_t *
hbfindfont(XftFont *match)
{
- for (int i = 0; i < hbfontslen; i++) {
- if (hbfontcache[i].match == match)
- return hbfontcache[i].font;
+ for (int i = 0; i < hbfontcache.capacity; i++) {
+ if (hbfontcache.fonts[i].match == match)
+ return hbfontcache.fonts[i].font;
}
/* Font not found in cache, caching it now. */
- hbfontcache = realloc(hbfontcache, sizeof(HbFontMatch) * (hbfontslen + 1));
+ hbfontcache.fonts = realloc(hbfontcache.fonts, sizeof(HbFontMatch) * (hbfontcache.capacity + 1));
FT_Face face = XftLockFace(match);
hb_font_t *font = hb_ft_font_create(face, NULL);
if (font == NULL)
die("Failed to load Harfbuzz font.");
- hbfontcache[hbfontslen].match = match;
- hbfontcache[hbfontslen].font = font;
- hbfontslen += 1;
+ hbfontcache.fonts[hbfontcache.capacity].match = match;
+ hbfontcache.fonts[hbfontcache.capacity].font = font;
+ hbfontcache.capacity += 1;
return font;
}
void
-hbtransform(XftGlyphFontSpec *specs, const Glyph *glyphs, size_t len, int x, int y)
+hbtransform(HbTransformData *data, XftFont *xfont, const Glyph *glyphs, int start, int length)
{
- int start = 0, length = 1, gstart = 0;
- hb_codepoint_t *codepoints = calloc(len, sizeof(hb_codepoint_t));
-
- for (int idx = 1, specidx = 1; idx < len; idx++) {
- if (glyphs[idx].mode & ATTR_WDUMMY) {
- length += 1;
- continue;
- }
-
- if (specs[specidx].font != specs[start].font || ATTRCMP(glyphs[gstart], glyphs[idx]) || selected(x + idx, y) != selected(x + gstart, y)) {
- hbtransformsegment(specs[start].font, glyphs, codepoints, gstart, length);
-
- /* Reset the sequence. */
- length = 1;
- start = specidx;
- gstart = idx;
- } else {
- length += 1;
- }
-
- specidx++;
- }
+ uint32_t mode;
+ unsigned int glyph_count;
+ int rune_idx, glyph_idx, end = start + length;
+ hb_buffer_t *buffer = hbbuffer;
- /* EOL. */
- hbtransformsegment(specs[start].font, glyphs, codepoints, gstart, length);
-
- /* Apply the transformation to glyph specs. */
- for (int i = 0, specidx = 0; i < len; i++) {
- if (glyphs[i].mode & ATTR_WDUMMY)
- continue;
- if (glyphs[i].mode & ATTR_BOXDRAW) {
- specidx++;
- continue;
- }
-
- if (codepoints[i] != specs[specidx].glyph)
- ((Glyph *)glyphs)[i].mode |= ATTR_LIGA;
-
- specs[specidx++].glyph = codepoints[i];
- }
-
- free(codepoints);
-}
-
-void
-hbtransformsegment(XftFont *xfont, const Glyph *string, hb_codepoint_t *codepoints, int start, int length)
-{
hb_font_t *font = hbfindfont(xfont);
- if (font == NULL)
+ if (font == NULL) {
+ data->count = 0;
return;
+ }
- Rune rune;
- ushort mode = USHRT_MAX;
- hb_buffer_t *buffer = hb_buffer_create();
+ hb_buffer_reset(buffer);
hb_buffer_set_direction(buffer, HB_DIRECTION_LTR);
+ hb_buffer_set_cluster_level(buffer, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
+
+ /* Resize the buffer if required length is larger. */
+ if (hbrunebuffer.capacity < length) {
+ hbrunebuffer.capacity = (length / BUFFER_STEP + 1) * BUFFER_STEP;
+ hbrunebuffer.runes = realloc(hbrunebuffer.runes, hbrunebuffer.capacity * sizeof(Rune));
+ }
/* Fill buffer with codepoints. */
- for (int i = start; i < (start+length); i++) {
- rune = string[i].u;
- mode = string[i].mode;
+ for (rune_idx = 0, glyph_idx = start; glyph_idx < end; glyph_idx++, rune_idx++) {
+ hbrunebuffer.runes[rune_idx] = glyphs[glyph_idx].u;
+ mode = glyphs[glyph_idx].mode;
if (mode & ATTR_WDUMMY)
- rune = 0x0020;
- hb_buffer_add_codepoints(buffer, &rune, 1, 0, 1);
+ hbrunebuffer.runes[rune_idx] = 0x0020;
}
+ hb_buffer_add_codepoints(buffer, hbrunebuffer.runes, length, 0, length);
/* Shape the segment. */
- hb_shape(font, buffer, NULL, 0);
+ hb_shape(font, buffer, features, sizeof(features)/sizeof(hb_feature_t));
/* Get new glyph info. */
- hb_glyph_info_t *info = hb_buffer_get_glyph_infos(buffer, NULL);
-
- /* Write new codepoints. */
- for (int i = 0; i < length; i++) {
- hb_codepoint_t gid = info[i].codepoint;
- codepoints[start+i] = gid;
- }
-
- /* Cleanup. */
- hb_buffer_destroy(buffer);
+ hb_glyph_info_t *info = hb_buffer_get_glyph_infos(buffer, &glyph_count);
+ hb_glyph_position_t *pos = hb_buffer_get_glyph_positions(buffer, &glyph_count);
+
+ /* Fill the output. */
+ data->buffer = buffer;
+ data->glyphs = info;
+ data->positions = pos;
+ data->count = glyph_count;
}
diff --git a/hb.h b/hb.h
@@ -2,6 +2,14 @@
#include <hb.h>
#include <hb-ft.h>
-void hbunloadfonts();
-void hbtransform(XftGlyphFontSpec *, const Glyph *, size_t, int, int);
+typedef struct {
+ hb_buffer_t *buffer;
+ hb_glyph_info_t *glyphs;
+ hb_glyph_position_t *positions;
+ unsigned int count;
+} HbTransformData;
+void hbcreatebuffer(void);
+void hbdestroybuffer(void);
+void hbunloadfonts(void);
+void hbtransform(HbTransformData *, XftFont *, const Glyph *, int, int);
diff --git a/normalMode.c b/normalMode.c
@@ -1,284 +0,0 @@
-#include <X11/keysym.h>
-#include <X11/XKBlib.h>
-
-#include "normalMode.h"
-#include "utils.h"
-
-extern Glyph const styleSearch, style[];
-extern char const wDelS[], wDelL[], *nmKeys[];
-extern unsigned int bg[], fg, currentBg, highlightBg, highlightFg, amountNmKeys;
-
-typedef struct { int p[3]; } Pos;
-
-typedef enum {visual='v', visualLine='V', yank = 'y'} Op;
-typedef enum {infix_none=0, infix_i='i', infix_a='a'} Infix;
-typedef enum {fw='/', bw='?'} Search;
-struct NormalModeState {
- struct OperationState { Op op; Infix infix; } cmd;
- struct MotionState { uint32_t c; int active; Pos searchPos; Search search; } m;
-} defaultNormalMode, state;
-
-DynamicArray searchStr=UTF8_ARRAY, cCmd=UTF8_ARRAY, lCmd=UTF8_ARRAY;
-Glyph styleCmd;
-char posBuffer[10], braces[6][3] = { {"()"}, {"<>"}, {"{}"}, {"[]"}, {"\"\""}, {"''"}};
-int exited=1, overlay=1;
-static inline Rune cChar() { return term.line[term.c.y][term.c.x].u; }
-static inline int pos(int p, int h) {return IS_SET(MODE_ALTSCREEN)?p:rangeY(p+h*histOff-insertOff);}
-static inline int contains(Rune l, char const * values, size_t const memSize) {
- for (uint32_t i = 0; i < memSize; ++i) if (l == values[i]) return 1;
- return 0;
-}
-static inline void decodeTo(char const *cs, size_t len, DynamicArray *arr) {
- char *var = expand(arr);
- if (!var) empty(arr); else utf8decode(cs, (Rune*)(var), len);
-}
-static inline void applyPos(Pos p) {
- term.c.x = p.p[0], term.c.y = p.p[1];
- if (!IS_SET(MODE_ALTSCREEN) && histOp) term.line = &buf[histOff = p.p[2]];
-}
-/// Find string in history buffer, and provide string-match-lookup for highlighting matches
-static int highlighted(int x, int y) {
- int const s=term.row*term.col, i=y*term.col+x, sz=size(&searchStr);
- return sz && i<s && mark[i]!=sz && i+mark[i]<s && !mark[i+mark[i]];
-}
-static void markSearchMatches(int all) {
- int sz = size(&searchStr), ox = 0, oy = 0, oi=0;
- for (int y=0; sz && all && y<term.row; ++y)
- for (int x=0; x<term.col; ++x) term.dirty[y] |= highlighted(x, y);
- for (int y = 0, wi=0, owi=0, i=0; sz && y < term.row; ++y)
- for (int x=0; x<term.col; ++x, wi%=sz, ++i, owi=wi)
- if (all || term.dirty[y]) {
- mark[i]=sz-(wi=(getU32(&searchStr,wi,1)==term.line[y][x].u?wi+1:0));
- if (wi==1) ox=x, oy=y, oi=i; else if (!wi && owi) x=ox, y=oy, i=oi;
- }
- for (int y=0; sz &&all &&y<term.row; ++y)
- for (int x=0; x<term.col; ++x) term.dirty[y] |= highlighted(x, y);
-}
-static int findString(int s, int all) {
- Pos p = (Pos) {.p={term.c.x, term.c.y, IS_SET(MODE_ALTSCREEN) ? 0 : histOff}};
- historyMove(s, 0, 0);
- uint32_t strSz=size(&searchStr), maxIter=rows()*term.col+strSz, wIdx=0;
- for (uint32_t i=0, wi = 0; wIdx<strSz && ++i<=maxIter; historyMove(s, 0, 0), wi=wIdx) {
- wIdx = (getU32(&searchStr, wIdx, s>0)==cChar())?wIdx+1:0;
- if (wi && !wIdx) historyMove(-(int)(s*wi), 0, 0);
- }
- if (wIdx == strSz && wIdx) historyMove(-(int)(s*strSz), 0, 0);
- else applyPos(p);
- markSearchMatches(all);
- return wIdx == strSz;
-}
-/// Execute series of normal-mode commands from char array / decoded from dynamic array
-ExitState pressKeys(char const* s, size_t e) {
- ExitState x=success;
- for (size_t i=0; i<e && (x=(!s[i] ? x : kPressHist(&s[i], 1, 0, NULL))); ++i);
- return x;
-}
-static ExitState executeCommand(uint32_t *cs, size_t z) {
- ExitState x=success;
- char dc [32];
- for (size_t i=0; i<z && (x=kPressHist(dc, utf8encode(cs[i],dc),0,NULL));++i);
- return x;
-}
-/// Get character for overlay, if the overlay (st) has something to show, else normal char.
-static void getChar(DynamicArray *st, Glyph *glyphChange, int y, int xEnd, int width, int x) {
- if (x < xEnd - min(min(width,xEnd), size(st))) *glyphChange = term.line[y][x];
- else if (x<xEnd) glyphChange->u = *((Rune*)(st->content + (size(st)+x-xEnd)*st->elSize));
-}
-/// Expand "infix" expression: for instance (w =>) l b | | v e | | y
-static ExitState expandExpression(char l) { // ({ =>) l ? { \n | l | v / } \n | h | y
- int a=state.cmd.infix==infix_a, yank=state.cmd.op=='y', lc=tolower(l), found=1;
- state.cmd.infix = infix_none;
- if(!yank && state.cmd.op!=visual && state.cmd.op!=visualLine) return failed;
- char mot[11] = {'l', 0, 'b', 0, 0, 'v', 0, 'e', 0, 0, (char)(yank ? 'y' : 0)};
- if (lc == 'w') mot[2] = (char) ('b' - lc + l), mot[7] = (char) ((a ? 'w' : 'e') - lc + l), mot[9]=(char)(a?'h':0);
- else {
- mot[1]='?', mot[3]=mot[8]='\n', mot[6]='/', mot[4]=(char)(a?0:'l'), mot[9]=(char)(a?0:'h');
- for (int i=found=0; !found && i < 6; ++i)
- if ((found=contains(l,braces[i],2))) mot[2]=braces[i][0], mot[7]=braces[i][1];
- }
- if (!found) return failed;
- assign(&lCmd, &cCmd);
- empty(&cCmd);
- state.cmd = defaultNormalMode.cmd;
- return pressKeys(mot, 11);
-}
-
-ExitState executeMotion(char const cs, KeySym const *const ks) {
- state.m.c = state.m.c < 1u ? 1u : state.m.c;
- if (ks && *ks == XK_d) historyMove(0, 0, term.row / 2);
- else if (ks && *ks == XK_u) historyMove(0, 0, -term.row / 2);
- else if (ks && *ks == XK_f) historyMove(0, 0, term.row-1+(term.c.y=0));
- else if (ks && *ks == XK_b) historyMove(0, 0, -(term.c.y=term.row-1));
- else if (ks && *ks == XK_h) overlay = !overlay;
- else if (cs == 'K') historyMove(0, 0, -(int)state.m.c);
- else if (cs == 'J') historyMove(0, 0, (int)state.m.c);
- else if (cs == 'k') historyMove(0, -(int)state.m.c, 0);
- else if (cs == 'j') historyMove(0, (int)state.m.c, 0);
- else if (cs == 'h') historyMove(-(int)state.m.c, 0, 0);
- else if (cs == 'l') historyMove( (int)state.m.c, 0, 0);
- else if (cs == 'H') term.c.y = 0;
- else if (cs == 'M') term.c.y = term.bot / 2;
- else if (cs == 'L') term.c.y = term.bot;
- else if (cs == 's' || cs == 'S') altToggle = cs == 's' ? !altToggle : 1;
- else if (cs == 'G' || cs == 'g') {
- if (cs == 'G') term.c = c[0] = c[IS_SET(MODE_ALTSCREEN)+1];
- if (!IS_SET(MODE_ALTSCREEN)) term.line = &buf[histOff=insertOff];
- } else if (cs == '0') term.c.x = 0;
- else if (cs == '$') term.c.x = term.col-1;
- else if (cs == 't') sel.type = sel.type==SEL_REGULAR ? SEL_RECTANGULAR : SEL_REGULAR;
- else if (cs == 'n' || cs == 'N') {
- int const d = ((cs=='N')!=(state.m.search==bw))?-1:1;
- for (uint32_t i = state.m.c; i && findString(d, 0); --i);
- } else if (contains(cs, "wWeEbB", 6)) {
- int const low=cs<=90, off=tolower(cs)!='w', sgn=(tolower(cs)=='b')?-1:1;
- size_t const l=strlen(wDelL), s=strlen(wDelS), maxIt=rows()*term.col;
- for (int it=0, on=0; state.m.c > 0 && it < maxIt; ++it) {
- // If an offset is to be performed in beginning or not in beginning, move in history.
- if ((off || it) && historyMove(sgn, 0, 0)) break;
- // Determine if the category of the current letter changed since last iteration.
- int n = 1<<(contains(cChar(),wDelS,s) ?(2-low) :!contains(cChar(),wDelL,l)),
- found = (on|=n)^n && ((off ?on^n :n)!=1);
- // If a reverse offset is to be performed and this is the last letter:
- if (found && off) historyMove(-sgn, 0, 0);
- // Terminate iteration: reset #it and old n value #on and decrease operation count:
- if (found) it=-1, on=0, --state.m.c;
- }
- } else return failed;
- state.m.c = 0;
- return state.cmd.op == yank ? exitMotion : success;
-}
-
-ExitState kPressHist(char const *cs, size_t len, int ctrl, KeySym const *kSym) {
- historyOpToggle(1, 1);
- int const prevYOff=IS_SET(MODE_ALTSCREEN)?0:histOff, search=state.m.search&&state.m.active,
- prevAltToggle=altToggle, prevOverlay=overlay;
- int const noOp=!state.cmd.op&&!state.cmd.infix, num=len==1&&BETWEEN(cs[0],48,57),
- esc=kSym&&*kSym==XK_Escape, ret=(kSym&&*kSym==XK_Return)||(len==1&&cs[0]=='\n'),
- quantifier=num&&(cs[0]!='0'||state.m.c), ins=!search &&noOp &&len &&cs[0]=='i';
- exited = 0;
- ExitState result = success;
- if (esc || ret || ins) { result = exitMotion, len = 0;
- } else if (kSym && *kSym == XK_BackSpace) {
- if ((search || state.m.c) && size(&cCmd)) pop(&cCmd);
- if (search) {
- if (size(&searchStr)) pop(&searchStr);
- else result = exitMotion;
- if (!size(&searchStr)) tfulldirt();
- applyPos(state.m.searchPos);
- findString(state.m.search==fw ? 1 : -1, 1);
- } else if (state.m.c) state.m.c /= 10;
- len = 0;
- } else if (search) {
- if (len >= 1) decodeTo(cs, len, &searchStr);
- applyPos(state.m.searchPos);
- findString(state.m.search==fw ? 1 : -1, 1);
- } else if (len == 0) { result = failed;
- } else if (quantifier) { state.m.c = min(SHRT_MAX, (int)state.m.c*10+cs[0]-48);
- } else if (state.cmd.infix && state.cmd.op && (result = expandExpression(cs[0]), len=0)) {
- } else if (cs[0] == 'd') { state = defaultNormalMode; result = exitMotion; state.m.active = 1;
- } else if (cs[0] == '.') {
- if (size(&cCmd)) assign(&lCmd, &cCmd);
- empty(&cCmd);
- executeCommand((uint32_t*) lCmd.content, size(&lCmd));
- empty(&cCmd);
- len = 0;
- } else if (cs[0] == 'r') { tfulldirt();
- } else if (cs[0] == 'c') {
- empty(&lCmd);
- empty(&cCmd);
- empty(&searchStr);
- tfulldirt();
- len = 0;
- } else if (cs[0] == fw || cs[0] == bw) {
- empty(&searchStr);
- state.m.search = (Search) cs[0];
- state.m.searchPos = (Pos){.p={term.c.x, term.c.y, prevYOff}};
- state.m.active = 1;
- } else if (cs[0]==infix_i || cs[0]==infix_a) { state.cmd.infix=(Infix) cs[0];
- } else if (cs[0] == 'y') {
- if (state.cmd.op) {
- result = (state.cmd.op == yank || state.cmd.op == visualLine) ? exitOp : exitMotion;
- if (state.cmd.op == yank) selstart(0, term.c.y, 0);
- } else selstart(term.c.x, term.c.y, 0);
- state.cmd.op = yank;
- } else if (cs[0] == visual || cs[0] == visualLine) {
- if (state.cmd.op != (Op) cs[0]) {
- state.cmd = defaultNormalMode.cmd;
- state.cmd.op = (Op) cs[0];
- selstart(cs[0] == visualLine ?0 :term.c.x, term.c.y, 0);
- } else result = exitOp;
- } else if (!(result =executeMotion((char) (len?cs[0]:0), ctrl?kSym:NULL))) {
- result=failed;
- for (size_t i = 0; !ctrl && i < amountNmKeys; ++i)
- if (cs[0]==nmKeys[i][0] &&
- failed!=(result=pressKeys(&nmKeys[i][1], strlen(nmKeys[i])-1))) goto end;
- } // Operation/Motion finished if valid: update cmd string, extend selection, update search
- if (result != failed) {
- if (len == 1 && !ctrl) decodeTo(cs, len, &cCmd);
- if ((state.cmd.op == visualLine) || ((state.cmd.op == yank) && (result == exitOp))) {
- int const off = term.c.y + (IS_SET(MODE_ALTSCREEN) ? 0 : histOff) < sel.ob.y; //< Selection start below end.
- sel.ob.x = off ? term.col - 1 : 0;
- selextend(off ? 0 : term.col-1, term.c.y, sel.type, 0);
- } else if (sel.oe.x != -1) {
- selextend(term.c.x, term.c.y, sel.type, 0);
- }
- } // Set repaint for motion or status bar
- if (!IS_SET(MODE_ALTSCREEN) && prevYOff != histOff) tfulldirt();
- // Terminate Motion / operation if thus indicated
- if (result == exitMotion) {
- if (!state.m.active) result = (exited=noOp) ? finish : exitOp;
- state.m.active = (int) (state.m.c = 0u);
- }
- if (result == exitOp || result == finish) {
- if (state.cmd.op == yank) {
- xsetsel(getsel());
- xclipcopy();
- }
- state = defaultNormalMode;
- selclear();
- if (!esc) assign(&lCmd, &cCmd);
- empty(&cCmd);
- } // Update the content displayed in the history overlay
- styleCmd = style[state.cmd.op==yank ? 1 : (state.cmd.op==visual ? 2 :
- (state.cmd.op==visualLine ? 3 :0))];
- int const posLin = !IS_SET(MODE_ALTSCREEN) ? rangeY(insertOff-histOff):0, h=rows()-term.row;
- if (!posLin || posLin==h || !h) strcpy(posBuffer, posLin ? " [BOT] " : " [TOP] ");
- else sprintf(posBuffer, " % 3d%c ", min(100, max(0, (int)(.5 + posLin * 100. / h))),'%');
- if ((overlay || overlay!=prevOverlay) && term.col>9 && term.row>4) {
- if (!term.dirty[term.row-1]) xdrawline(term.line[term.row-1], term.col*2/3, term.row-1, term.col-1);
- if (!term.dirty[term.row-2]) xdrawline(term.line[term.row-2], term.col*2/3, term.row-2, term.col-1);
- }
- if (result==finish) altToggle = 0;
- if (altToggle != prevAltToggle) tswapscreen();
-end:
- historyOpToggle(-1, 1);
- return result;
-}
-
-void historyOverlay(int x, int y, Glyph* g) {
- if (!histMode) return;
- TCursor const *cHist = histOp ? &term.c : &c[0];
- if(overlay && term.col > 9 && term.row > 4 && (x > (2*term.col/3)) && (y >= (term.row-2))) {
- *g = (y == term.row - 2) ? styleSearch : styleCmd;
- if (y == term.row-2) getChar(&searchStr, g, term.row-2, term.col-2, term.col/3, x);
- else if (x > term.col - 7) g->u = (Rune)(posBuffer[x - term.col + 7]);
- else getChar(size(&cCmd) ?&cCmd :&lCmd, g, term.row-1, term.col-7, term.col/3-6, x);
- } else if (highlighted(x, y)) g->bg = highlightBg, g->fg = highlightFg;
- else if ((x==cHist->x) ^ (y==cHist->y)) g->bg = currentBg;
- else if (x==cHist->x) g->mode^=ATTR_REVERSE;
-}
-void historyPreDraw() {
- static Pos op = {.p={0, 0, 0}};
- historyOpToggle(1, 0);
- // Draw the cursor cross if changed
- if (term.c.y >= term.row || op.p[1] >= term.row) tfulldirt();
- else if (exited || (op.p[1] != term.c.y)) term.dirty[term.c.y] = term.dirty[op.p[1]] = 1;
- for (int i=0; (exited || term.c.x != op.p[0]) && i<term.row; ++i) if (!term.dirty[i]) {
- xdrawline(term.line[i], term.c.x, i, term.c.x + 1);
- xdrawline(term.line[i], op.p[0], i, op.p[0] + 1);
- }
- // Update search results either only for lines with new content or all results if exiting
- markSearchMatches(exited);
- op = (Pos){.p = {term.c.x, term.c.y, 0}};
- historyOpToggle(-1, 0);
-}
diff --git a/normalMode.h b/normalMode.h
@@ -1,8 +0,0 @@
-void normalMode();
-void historyPreDraw();
-void historyOverlay(int x, int y, Glyph* g);
-void historyModeToggle(int start);
-void historyOpToggle(int, int);
-typedef enum {failed=0, success=1, exitMotion=2, exitOp=3, finish=4} ExitState;
-ExitState kPressHist(char const *txt, size_t len, int ctrl, KeySym const *kSym);
-ExitState pressKeys(char const* s, size_t e);
diff --git a/patch/alpha.c b/patch/alpha.c
@@ -0,0 +1,30 @@
+float
+clamp(float value, float lower, float upper) {
+ if (value < lower)
+ return lower;
+ if (value > upper)
+ return upper;
+ return value;
+}
+
+void
+changealpha(const Arg *arg)
+{
+ if ((alpha > 0 && arg->f < 0) || (alpha < 1 && arg->f > 0))
+ alpha += arg->f;
+ alpha = clamp(alpha, 0.0, 1.0);
+ xloadcols();
+ redraw();
+}
+
+#if ALPHA_FOCUS_HIGHLIGHT_PATCH
+void
+changealphaunfocused(const Arg *arg)
+{
+ if ((alphaUnfocused > 0 && arg->f < 0) || (alphaUnfocused < 1 && arg->f > 0))
+ alphaUnfocused += arg->f;
+ alphaUnfocused = clamp(alphaUnfocused, 0.0, 1.0);
+ xloadcols();
+ redraw();
+}
+#endif // ALPHA_FOCUS_HIGHLIGHT_PATCH
diff --git a/patch/alpha.h b/patch/alpha.h
@@ -0,0 +1,5 @@
+static float clamp(float value, float lower, float upper);
+static void changealpha(const Arg *);
+#if ALPHA_FOCUS_HIGHLIGHT_PATCH
+static void changealphaunfocused(const Arg *arg);
+#endif // ALPHA_FOCUS_HIGHLIGHT_PATCH
diff --git a/patch/background_image_x.c b/patch/background_image_x.c
@@ -0,0 +1,106 @@
+void
+updatexy()
+{
+ Window child;
+ XTranslateCoordinates(xw.dpy, xw.win, DefaultRootWindow(xw.dpy), 0, 0, &win.x, &win.y, &child);
+}
+
+/*
+ * load farbfeld file to XImage
+ */
+XImage*
+loadff(const char *filename)
+{
+ uint32_t i, hdr[4], w, h, size;
+ uint64_t *data;
+ FILE *f = fopen(filename, "rb");
+
+ if (f == NULL) {
+ fprintf(stderr, "could not load background image.\n");
+ return NULL;
+ }
+
+ if (fread(hdr, sizeof(*hdr), LEN(hdr), f) != LEN(hdr)) {
+ fprintf(stderr, "fread: %s\n", ferror(f) ? "" : "Unexpected end of file reading header");
+ fclose(f);
+ return NULL;
+ }
+
+ if (memcmp("farbfeld", hdr, sizeof("farbfeld") - 1)) {
+ fprintf(stderr, "Invalid magic value\n");
+ fclose(f);
+ return NULL;
+ }
+
+ w = ntohl(hdr[2]);
+ h = ntohl(hdr[3]);
+ size = w * h;
+ data = xmalloc(size * sizeof(uint64_t));
+
+ if (fread(data, sizeof(uint64_t), size, f) != size) {
+ fprintf(stderr, "fread: %s\n", ferror(f) ? "" : "Unexpected end of file reading data");
+ fclose(f);
+ return NULL;
+ }
+
+ fclose(f);
+
+ for (i = 0; i < size; i++)
+ data[i] = (data[i] & 0x00000000000000FF) << 16 |
+ (data[i] & 0x0000000000FF0000) >> 8 |
+ (data[i] & 0x000000FF00000000) >> 32 |
+ (data[i] & 0x00FF000000000000) >> 24;
+
+ #if ALPHA_PATCH
+ XImage *xi = XCreateImage(xw.dpy, xw.vis, xw.depth, ZPixmap, 0,
+ (char *)data, w, h, 32, w * 8);
+ #else
+ XImage *xi = XCreateImage(xw.dpy, DefaultVisual(xw.dpy, xw.scr),
+ DefaultDepth(xw.dpy, xw.scr), ZPixmap, 0,
+ (char *)data, w, h, 32, w * 8);
+ #endif // ALPHA_PATCH
+ xi->bits_per_pixel = 64;
+ return xi;
+}
+
+/*
+ * initialize background image
+ */
+void
+bginit()
+{
+ XGCValues gcvalues;
+ Drawable bgimg;
+ XImage *bgxi = loadff(bgfile);
+
+ memset(&gcvalues, 0, sizeof(gcvalues));
+ xw.bggc = XCreateGC(xw.dpy, xw.win, 0, &gcvalues);
+ if (!bgxi)
+ return;
+ #if ALPHA_PATCH
+ bgimg = XCreatePixmap(xw.dpy, xw.win, bgxi->width, bgxi->height,
+ xw.depth);
+ #else
+ bgimg = XCreatePixmap(xw.dpy, xw.win, bgxi->width, bgxi->height,
+ DefaultDepth(xw.dpy, xw.scr));
+ #endif // ALPHA_PATCH
+ XPutImage(xw.dpy, bgimg, dc.gc, bgxi, 0, 0, 0, 0, bgxi->width, bgxi->height);
+ XDestroyImage(bgxi);
+ XSetTile(xw.dpy, xw.bggc, bgimg);
+ XSetFillStyle(xw.dpy, xw.bggc, FillTiled);
+ if (pseudotransparency) {
+ updatexy();
+ MODBIT(xw.attrs.event_mask, 1, PropertyChangeMask);
+ XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs);
+ }
+}
+
+#if BACKGROUND_IMAGE_RELOAD_PATCH
+void
+reload_image()
+{
+ XFreeGC(xw.dpy, xw.bggc);
+ bginit();
+ redraw();
+}
+#endif // XRESOURCES_RELOAD_PATCH
diff --git a/patch/background_image_x.h b/patch/background_image_x.h
@@ -0,0 +1,6 @@
+#include <arpa/inet.h>
+
+static void updatexy(void);
+static XImage *loadff(const char *);
+static void bginit();
+static void reload_image();
diff --git a/patch/boxdraw.c b/patch/boxdraw.c
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2018 Avi Halachmi (:avih) avihpit@yahoo.com https://github.com/avih
+ * MIT/X Consortium License
+ */
+
+#include <X11/Xft/Xft.h>
+
+/* Rounded non-negative integers division of n / d */
+#define DIV(n, d) (((n) + (d) / 2) / (d))
+
+static Display *xdpy;
+static Colormap xcmap;
+static XftDraw *xd;
+static Visual *xvis;
+
+static void drawbox(int, int, int, int, XftColor *, XftColor *, ushort);
+static void drawboxlines(int, int, int, int, XftColor *, ushort);
+
+/* public API */
+
+void
+boxdraw_xinit(Display *dpy, Colormap cmap, XftDraw *draw, Visual *vis)
+{
+ xdpy = dpy; xcmap = cmap; xd = draw, xvis = vis;
+}
+
+int
+isboxdraw(Rune u)
+{
+ Rune block = u & ~0xff;
+ return (boxdraw && block == 0x2500 && boxdata[(uint8_t)u]) ||
+ (boxdraw_braille && block == 0x2800);
+}
+
+/* the "index" is actually the entire shape data encoded as ushort */
+ushort
+boxdrawindex(const Glyph *g)
+{
+ if (boxdraw_braille && (g->u & ~0xff) == 0x2800)
+ return BRL | (uint8_t)g->u;
+ if (boxdraw_bold && (g->mode & ATTR_BOLD))
+ return BDB | boxdata[(uint8_t)g->u];
+ return boxdata[(uint8_t)g->u];
+}
+
+void
+drawboxes(int x, int y, int cw, int ch, XftColor *fg, XftColor *bg,
+ const XftGlyphFontSpec *specs, int len)
+{
+ for ( ; len-- > 0; x += cw, specs++)
+ drawbox(x, y, cw, ch, fg, bg, (ushort)specs->glyph);
+}
+
+/* implementation */
+
+void
+drawbox(int x, int y, int w, int h, XftColor *fg, XftColor *bg, ushort bd)
+{
+ ushort cat = bd & ~(BDB | 0xff); /* mask out bold and data */
+ if (bd & (BDL | BDA)) {
+ /* lines (light/double/heavy/arcs) */
+ drawboxlines(x, y, w, h, fg, bd);
+
+ } else if (cat == BBD) {
+ /* lower (8-X)/8 block */
+ int d = DIV((uint8_t)bd * h, 8);
+ XftDrawRect(xd, fg, x, y + d, w, h - d);
+
+ } else if (cat == BBU) {
+ /* upper X/8 block */
+ XftDrawRect(xd, fg, x, y, w, DIV((uint8_t)bd * h, 8));
+
+ } else if (cat == BBL) {
+ /* left X/8 block */
+ XftDrawRect(xd, fg, x, y, DIV((uint8_t)bd * w, 8), h);
+
+ } else if (cat == BBR) {
+ /* right (8-X)/8 block */
+ int d = DIV((uint8_t)bd * w, 8);
+ XftDrawRect(xd, fg, x + d, y, w - d, h);
+
+ } else if (cat == BBQ) {
+ /* Quadrants */
+ int w2 = DIV(w, 2), h2 = DIV(h, 2);
+ if (bd & TL)
+ XftDrawRect(xd, fg, x, y, w2, h2);
+ if (bd & TR)
+ XftDrawRect(xd, fg, x + w2, y, w - w2, h2);
+ if (bd & BL)
+ XftDrawRect(xd, fg, x, y + h2, w2, h - h2);
+ if (bd & BR)
+ XftDrawRect(xd, fg, x + w2, y + h2, w - w2, h - h2);
+
+ } else if (bd & BBS) {
+ /* Shades - data is 1/2/3 for 25%/50%/75% alpha, respectively */
+ int d = (uint8_t)bd;
+ XftColor xfc;
+ XRenderColor xrc = { .alpha = 0xffff };
+
+ xrc.red = DIV(fg->color.red * d + bg->color.red * (4 - d), 4);
+ xrc.green = DIV(fg->color.green * d + bg->color.green * (4 - d), 4);
+ xrc.blue = DIV(fg->color.blue * d + bg->color.blue * (4 - d), 4);
+
+ XftColorAllocValue(xdpy, xvis, xcmap, &xrc, &xfc);
+ XftDrawRect(xd, &xfc, x, y, w, h);
+ XftColorFree(xdpy, xvis, xcmap, &xfc);
+
+ } else if (cat == BRL) {
+ /* braille, each data bit corresponds to one dot at 2x4 grid */
+ int w1 = DIV(w, 2);
+ int h1 = DIV(h, 4), h2 = DIV(h, 2), h3 = DIV(3 * h, 4);
+
+ if (bd & 1) XftDrawRect(xd, fg, x, y, w1, h1);
+ if (bd & 2) XftDrawRect(xd, fg, x, y + h1, w1, h2 - h1);
+ if (bd & 4) XftDrawRect(xd, fg, x, y + h2, w1, h3 - h2);
+ if (bd & 8) XftDrawRect(xd, fg, x + w1, y, w - w1, h1);
+ if (bd & 16) XftDrawRect(xd, fg, x + w1, y + h1, w - w1, h2 - h1);
+ if (bd & 32) XftDrawRect(xd, fg, x + w1, y + h2, w - w1, h3 - h2);
+ if (bd & 64) XftDrawRect(xd, fg, x, y + h3, w1, h - h3);
+ if (bd & 128) XftDrawRect(xd, fg, x + w1, y + h3, w - w1, h - h3);
+
+ }
+}
+
+void
+drawboxlines(int x, int y, int w, int h, XftColor *fg, ushort bd)
+{
+ /* s: stem thickness. width/8 roughly matches underscore thickness. */
+ /* We draw bold as 1.5 * normal-stem and at least 1px thicker. */
+ /* doubles draw at least 3px, even when w or h < 3. bold needs 6px. */
+ int mwh = MIN(w, h);
+ int base_s = MAX(1, DIV(mwh, 8));
+ int bold = (bd & BDB) && mwh >= 6; /* possibly ignore boldness */
+ int s = bold ? MAX(base_s + 1, DIV(3 * base_s, 2)) : base_s;
+ int w2 = DIV(w - s, 2), h2 = DIV(h - s, 2);
+ /* the s-by-s square (x + w2, y + h2, s, s) is the center texel. */
+ /* The base length (per direction till edge) includes this square. */
+
+ int light = bd & (LL | LU | LR | LD);
+ int double_ = bd & (DL | DU | DR | DD);
+
+ if (light) {
+ /* d: additional (negative) length to not-draw the center */
+ /* texel - at arcs and avoid drawing inside (some) doubles */
+ int arc = bd & BDA;
+ int multi_light = light & (light - 1);
+ int multi_double = double_ & (double_ - 1);
+ /* light crosses double only at DH+LV, DV+LH (ref. shapes) */
+ int d = arc || (multi_double && !multi_light) ? -s : 0;
+
+ if (bd & LL)
+ XftDrawRect(xd, fg, x, y + h2, w2 + s + d, s);
+ if (bd & LU)
+ XftDrawRect(xd, fg, x + w2, y, s, h2 + s + d);
+ if (bd & LR)
+ XftDrawRect(xd, fg, x + w2 - d, y + h2, w - w2 + d, s);
+ if (bd & LD)
+ XftDrawRect(xd, fg, x + w2, y + h2 - d, s, h - h2 + d);
+ }
+
+ /* double lines - also align with light to form heavy when combined */
+ if (double_) {
+ /*
+ * going clockwise, for each double-ray: p is additional length
+ * to the single-ray nearer to the previous direction, and n to
+ * the next. p and n adjust from the base length to lengths
+ * which consider other doubles - shorter to avoid intersections
+ * (p, n), or longer to draw the far-corner texel (n).
+ */
+ int dl = bd & DL, du = bd & DU, dr = bd & DR, dd = bd & DD;
+ if (dl) {
+ int p = dd ? -s : 0, n = du ? -s : dd ? s : 0;
+ XftDrawRect(xd, fg, x, y + h2 + s, w2 + s + p, s);
+ XftDrawRect(xd, fg, x, y + h2 - s, w2 + s + n, s);
+ }
+ if (du) {
+ int p = dl ? -s : 0, n = dr ? -s : dl ? s : 0;
+ XftDrawRect(xd, fg, x + w2 - s, y, s, h2 + s + p);
+ XftDrawRect(xd, fg, x + w2 + s, y, s, h2 + s + n);
+ }
+ if (dr) {
+ int p = du ? -s : 0, n = dd ? -s : du ? s : 0;
+ XftDrawRect(xd, fg, x + w2 - p, y + h2 - s, w - w2 + p, s);
+ XftDrawRect(xd, fg, x + w2 - n, y + h2 + s, w - w2 + n, s);
+ }
+ if (dd) {
+ int p = dr ? -s : 0, n = dl ? -s : dr ? s : 0;
+ XftDrawRect(xd, fg, x + w2 + s, y + h2 - p, s, h - h2 + p);
+ XftDrawRect(xd, fg, x + w2 - s, y + h2 - n, s, h - h2 + n);
+ }
+ }
+}
+\ No newline at end of file
diff --git a/patch/boxdraw.h b/patch/boxdraw.h
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2018 Avi Halachmi (:avih) avihpit@yahoo.com https://github.com/avih
+ * MIT/X Consortium License
+ */
+
+/*
+ * U+25XX codepoints data
+ *
+ * References:
+ * http://www.unicode.org/charts/PDF/U2500.pdf
+ * http://www.unicode.org/charts/PDF/U2580.pdf
+ *
+ * Test page:
+ * https://github.com/GNOME/vte/blob/master/doc/boxes.txt
+ */
+
+/* Each shape is encoded as 16-bits. Higher bits are category, lower are data */
+/* Categories (mutually exclusive except BDB): */
+/* For convenience, BDL/BDA/BBS/BDB are 1 bit each, the rest are enums */
+#define BDL (1<<8) /* Box Draw Lines (light/double/heavy) */
+#define BDA (1<<9) /* Box Draw Arc (light) */
+
+#define BBD (1<<10) /* Box Block Down (lower) X/8 */
+#define BBL (2<<10) /* Box Block Left X/8 */
+#define BBU (3<<10) /* Box Block Upper X/8 */
+#define BBR (4<<10) /* Box Block Right X/8 */
+#define BBQ (5<<10) /* Box Block Quadrants */
+#define BRL (6<<10) /* Box Braille (data is lower byte of U28XX) */
+
+#define BBS (1<<14) /* Box Block Shades */
+#define BDB (1<<15) /* Box Draw is Bold */
+
+/* (BDL/BDA) Light/Double/Heavy x Left/Up/Right/Down/Horizontal/Vertical */
+/* Heavy is light+double (literally drawing light+double align to form heavy) */
+#define LL (1<<0)
+#define LU (1<<1)
+#define LR (1<<2)
+#define LD (1<<3)
+#define LH (LL+LR)
+#define LV (LU+LD)
+
+#define DL (1<<4)
+#define DU (1<<5)
+#define DR (1<<6)
+#define DD (1<<7)
+#define DH (DL+DR)
+#define DV (DU+DD)
+
+#define HL (LL+DL)
+#define HU (LU+DU)
+#define HR (LR+DR)
+#define HD (LD+DD)
+#define HH (HL+HR)
+#define HV (HU+HD)
+
+/* (BBQ) Quadrants Top/Bottom x Left/Right */
+#define TL (1<<0)
+#define TR (1<<1)
+#define BL (1<<2)
+#define BR (1<<3)
+
+/* Data for U+2500 - U+259F except dashes/diagonals */
+static const unsigned short boxdata[256] = {
+ /* light lines */
+ [0x00] = BDL + LH, /* light horizontal */
+ [0x02] = BDL + LV, /* light vertical */
+ [0x0c] = BDL + LD + LR, /* light down and right */
+ [0x10] = BDL + LD + LL, /* light down and left */
+ [0x14] = BDL + LU + LR, /* light up and right */
+ [0x18] = BDL + LU + LL, /* light up and left */
+ [0x1c] = BDL + LV + LR, /* light vertical and right */
+ [0x24] = BDL + LV + LL, /* light vertical and left */
+ [0x2c] = BDL + LH + LD, /* light horizontal and down */
+ [0x34] = BDL + LH + LU, /* light horizontal and up */
+ [0x3c] = BDL + LV + LH, /* light vertical and horizontal */
+ [0x74] = BDL + LL, /* light left */
+ [0x75] = BDL + LU, /* light up */
+ [0x76] = BDL + LR, /* light right */
+ [0x77] = BDL + LD, /* light down */
+
+ /* heavy [+light] lines */
+ [0x01] = BDL + HH,
+ [0x03] = BDL + HV,
+ [0x0d] = BDL + HR + LD,
+ [0x0e] = BDL + HD + LR,
+ [0x0f] = BDL + HD + HR,
+ [0x11] = BDL + HL + LD,
+ [0x12] = BDL + HD + LL,
+ [0x13] = BDL + HD + HL,
+ [0x15] = BDL + HR + LU,
+ [0x16] = BDL + HU + LR,
+ [0x17] = BDL + HU + HR,
+ [0x19] = BDL + HL + LU,
+ [0x1a] = BDL + HU + LL,
+ [0x1b] = BDL + HU + HL,
+ [0x1d] = BDL + HR + LV,
+ [0x1e] = BDL + HU + LD + LR,
+ [0x1f] = BDL + HD + LR + LU,
+ [0x20] = BDL + HV + LR,
+ [0x21] = BDL + HU + HR + LD,
+ [0x22] = BDL + HD + HR + LU,
+ [0x23] = BDL + HV + HR,
+ [0x25] = BDL + HL + LV,
+ [0x26] = BDL + HU + LD + LL,
+ [0x27] = BDL + HD + LU + LL,
+ [0x28] = BDL + HV + LL,
+ [0x29] = BDL + HU + HL + LD,
+ [0x2a] = BDL + HD + HL + LU,
+ [0x2b] = BDL + HV + HL,
+ [0x2d] = BDL + HL + LD + LR,
+ [0x2e] = BDL + HR + LL + LD,
+ [0x2f] = BDL + HH + LD,
+ [0x30] = BDL + HD + LH,
+ [0x31] = BDL + HD + HL + LR,
+ [0x32] = BDL + HR + HD + LL,
+ [0x33] = BDL + HH + HD,
+ [0x35] = BDL + HL + LU + LR,
+ [0x36] = BDL + HR + LU + LL,
+ [0x37] = BDL + HH + LU,
+ [0x38] = BDL + HU + LH,
+ [0x39] = BDL + HU + HL + LR,
+ [0x3a] = BDL + HU + HR + LL,
+ [0x3b] = BDL + HH + HU,
+ [0x3d] = BDL + HL + LV + LR,
+ [0x3e] = BDL + HR + LV + LL,
+ [0x3f] = BDL + HH + LV,
+ [0x40] = BDL + HU + LH + LD,
+ [0x41] = BDL + HD + LH + LU,
+ [0x42] = BDL + HV + LH,
+ [0x43] = BDL + HU + HL + LD + LR,
+ [0x44] = BDL + HU + HR + LD + LL,
+ [0x45] = BDL + HD + HL + LU + LR,
+ [0x46] = BDL + HD + HR + LU + LL,
+ [0x47] = BDL + HH + HU + LD,
+ [0x48] = BDL + HH + HD + LU,
+ [0x49] = BDL + HV + HL + LR,
+ [0x4a] = BDL + HV + HR + LL,
+ [0x4b] = BDL + HV + HH,
+ [0x78] = BDL + HL,
+ [0x79] = BDL + HU,
+ [0x7a] = BDL + HR,
+ [0x7b] = BDL + HD,
+ [0x7c] = BDL + HR + LL,
+ [0x7d] = BDL + HD + LU,
+ [0x7e] = BDL + HL + LR,
+ [0x7f] = BDL + HU + LD,
+
+ /* double [+light] lines */
+ [0x50] = BDL + DH,
+ [0x51] = BDL + DV,
+ [0x52] = BDL + DR + LD,
+ [0x53] = BDL + DD + LR,
+ [0x54] = BDL + DR + DD,
+ [0x55] = BDL + DL + LD,
+ [0x56] = BDL + DD + LL,
+ [0x57] = BDL + DL + DD,
+ [0x58] = BDL + DR + LU,
+ [0x59] = BDL + DU + LR,
+ [0x5a] = BDL + DU + DR,
+ [0x5b] = BDL + DL + LU,
+ [0x5c] = BDL + DU + LL,
+ [0x5d] = BDL + DL + DU,
+ [0x5e] = BDL + DR + LV,
+ [0x5f] = BDL + DV + LR,
+ [0x60] = BDL + DV + DR,
+ [0x61] = BDL + DL + LV,
+ [0x62] = BDL + DV + LL,
+ [0x63] = BDL + DV + DL,
+ [0x64] = BDL + DH + LD,
+ [0x65] = BDL + DD + LH,
+ [0x66] = BDL + DD + DH,
+ [0x67] = BDL + DH + LU,
+ [0x68] = BDL + DU + LH,
+ [0x69] = BDL + DH + DU,
+ [0x6a] = BDL + DH + LV,
+ [0x6b] = BDL + DV + LH,
+ [0x6c] = BDL + DH + DV,
+
+ /* (light) arcs */
+ [0x6d] = BDA + LD + LR,
+ [0x6e] = BDA + LD + LL,
+ [0x6f] = BDA + LU + LL,
+ [0x70] = BDA + LU + LR,
+
+ /* Lower (Down) X/8 block (data is 8 - X) */
+ [0x81] = BBD + 7, [0x82] = BBD + 6, [0x83] = BBD + 5, [0x84] = BBD + 4,
+ [0x85] = BBD + 3, [0x86] = BBD + 2, [0x87] = BBD + 1, [0x88] = BBD + 0,
+
+ /* Left X/8 block (data is X) */
+ [0x89] = BBL + 7, [0x8a] = BBL + 6, [0x8b] = BBL + 5, [0x8c] = BBL + 4,
+ [0x8d] = BBL + 3, [0x8e] = BBL + 2, [0x8f] = BBL + 1,
+
+ /* upper 1/2 (4/8), 1/8 block (X), right 1/2, 1/8 block (8-X) */
+ [0x80] = BBU + 4, [0x94] = BBU + 1,
+ [0x90] = BBR + 4, [0x95] = BBR + 7,
+
+ /* Quadrants */
+ [0x96] = BBQ + BL,
+ [0x97] = BBQ + BR,
+ [0x98] = BBQ + TL,
+ [0x99] = BBQ + TL + BL + BR,
+ [0x9a] = BBQ + TL + BR,
+ [0x9b] = BBQ + TL + TR + BL,
+ [0x9c] = BBQ + TL + TR + BR,
+ [0x9d] = BBQ + TR,
+ [0x9e] = BBQ + BL + TR,
+ [0x9f] = BBQ + BL + TR + BR,
+
+ /* Shades, data is an alpha value in 25% units (1/4, 1/2, 3/4) */
+ [0x91] = BBS + 1, [0x92] = BBS + 2, [0x93] = BBS + 3,
+
+ /* U+2504 - U+250B, U+254C - U+254F: unsupported (dashes) */
+ /* U+2571 - U+2573: unsupported (diagonals) */
+};
+\ No newline at end of file
diff --git a/patch/copyurl.c b/patch/copyurl.c
@@ -0,0 +1,180 @@
+#if COPYURL_HIGHLIGHT_SELECTED_URLS_PATCH
+void
+tsetcolor( int row, int start, int end, uint32_t fg, uint32_t bg )
+{
+ int i = start;
+ for( ; i < end; ++i )
+ {
+ term.line[row][i].fg = fg;
+ term.line[row][i].bg = bg;
+ }
+}
+
+char *
+findlastany(char *str, const char** find, size_t len)
+{
+ char* found = NULL;
+ int i = 0;
+ for(found = str + strlen(str) - 1; found >= str; --found) {
+ for(i = 0; i < len; i++) {
+ if(strncmp(found, find[i], strlen(find[i])) == 0) {
+ return found;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/*
+** Select and copy the previous url on screen (do nothing if there's no url).
+**
+** FIXME: doesn't handle urls that span multiple lines; will need to add support
+** for multiline "getsel()" first
+*/
+void
+copyurl(const Arg *arg) {
+ /* () and [] can appear in urls, but excluding them here will reduce false
+ * positives when figuring out where a given url ends.
+ */
+ static char URLCHARS[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789-._~:/?#@!$&'*+,;=%";
+
+ static const char* URLSTRINGS[] = {"http://", "https://"};
+
+ /* remove highlighting from previous selection if any */
+ if(sel.ob.x >= 0 && sel.oe.x >= 0)
+ tsetcolor(sel.nb.y, sel.ob.x, sel.oe.x + 1, defaultfg, defaultbg);
+
+ int i = 0,
+ row = 0, /* row of current URL */
+ col = 0, /* column of current URL start */
+ startrow = 0, /* row of last occurrence */
+ colend = 0, /* column of last occurrence */
+ passes = 0; /* how many rows have been scanned */
+
+ char *linestr = calloc(term.col+1, sizeof(Rune));
+ char *c = NULL,
+ *match = NULL;
+
+ row = (sel.ob.x >= 0 && sel.nb.y > 0) ? sel.nb.y : term.bot;
+ LIMIT(row, term.top, term.bot);
+ startrow = row;
+
+ colend = (sel.ob.x >= 0 && sel.nb.y > 0) ? sel.nb.x : term.col;
+ LIMIT(colend, 0, term.col);
+
+ /*
+ ** Scan from (term.bot,term.col) to (0,0) and find
+ ** next occurrance of a URL
+ */
+ while (passes !=term.bot + 2) {
+ /* Read in each column of every row until
+ ** we hit previous occurrence of URL
+ */
+ for (col = 0, i = 0; col < colend; ++col,++i) {
+ linestr[i] = term.line[row][col].u;
+ }
+ linestr[term.col] = '\0';
+
+ if ((match = findlastany(linestr, URLSTRINGS,
+ sizeof(URLSTRINGS)/sizeof(URLSTRINGS[0]))))
+ break;
+
+ if (--row < term.top)
+ row = term.bot;
+
+ colend = term.col;
+ passes++;
+ };
+
+ if (match) {
+ /* must happen before trim */
+ selclear();
+ sel.ob.x = strlen(linestr) - strlen(match);
+
+ /* trim the rest of the line from the url match */
+ for (c = match; *c != '\0'; ++c)
+ if (!strchr(URLCHARS, *c)) {
+ *c = '\0';
+ break;
+ }
+
+ /* highlight selection by inverting terminal colors */
+ tsetcolor(row, sel.ob.x, sel.ob.x + strlen( match ), defaultbg, defaultfg);
+
+ /* select and copy */
+ sel.mode = 1;
+ sel.type = SEL_REGULAR;
+ sel.oe.x = sel.ob.x + strlen(match)-1;
+ sel.ob.y = sel.oe.y = row;
+ selnormalize();
+ tsetdirt(sel.nb.y, sel.ne.y);
+ xsetsel(getsel());
+ xclipcopy();
+ }
+
+ free(linestr);
+}
+#else
+/* select and copy the previous url on screen (do nothing if there's no url).
+ * known bug: doesn't handle urls that span multiple lines (wontfix), depends on multiline "getsel()"
+ * known bug: only finds first url on line (mightfix)
+ */
+void
+copyurl(const Arg *arg) {
+ /* () and [] can appear in urls, but excluding them here will reduce false
+ * positives when figuring out where a given url ends.
+ */
+ static char URLCHARS[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789-._~:/?#@!$&'*+,;=%";
+
+ int i, row, startrow;
+ char *linestr = calloc(term.col+1, sizeof(Rune));
+ char *c, *match = NULL;
+
+ row = (sel.ob.x >= 0 && sel.nb.y > 0) ? sel.nb.y-1 : term.bot;
+ LIMIT(row, term.top, term.bot);
+ startrow = row;
+
+ /* find the start of the last url before selection */
+ do {
+ for (i = 0; i < term.col; ++i) {
+ linestr[i] = term.line[row][i].u;
+ }
+ linestr[term.col] = '\0';
+ if ((match = strstr(linestr, "http://"))
+ || (match = strstr(linestr, "https://")))
+ break;
+ if (--row < term.top)
+ row = term.bot;
+ } while (row != startrow);
+
+ if (match) {
+ /* must happen before trim */
+ selclear();
+ sel.ob.x = strlen(linestr) - strlen(match);
+
+ /* trim the rest of the line from the url match */
+ for (c = match; *c != '\0'; ++c)
+ if (!strchr(URLCHARS, *c)) {
+ *c = '\0';
+ break;
+ }
+
+ /* select and copy */
+ sel.mode = 1;
+ sel.type = SEL_REGULAR;
+ sel.oe.x = sel.ob.x + strlen(match)-1;
+ sel.ob.y = sel.oe.y = row;
+ selnormalize();
+ tsetdirt(sel.nb.y, sel.ne.y);
+ xsetsel(getsel());
+ xclipcopy();
+ }
+
+ free(linestr);
+}
+#endif // COPYURL_HIGHLIGHT_SELECTED_URLS_PATCH
+\ No newline at end of file
diff --git a/patch/copyurl.h b/patch/copyurl.h
@@ -0,0 +1,5 @@
+void copyurl(const Arg *);
+#if COPYURL_HIGHLIGHT_SELECTED_URLS_PATCH
+static void tsetcolor(int, int, int, uint32_t, uint32_t);
+static char * findlastany(char *, const char**, size_t);
+#endif // COPYURL_HIGHLIGHT_SELECTED_URLS_PATCH
+\ No newline at end of file
diff --git a/patch/drag-n-drop.c b/patch/drag-n-drop.c
@@ -0,0 +1,204 @@
+const char XdndVersion = 5;
+
+void
+xdndsel(XEvent *e)
+{
+ char* data;
+ unsigned long result;
+
+ Atom actualType;
+ int32_t actualFormat;
+ unsigned long bytesAfter;
+ XEvent reply = { ClientMessage };
+
+ reply.xclient.window = xw.XdndSourceWin;
+ reply.xclient.format = 32;
+ reply.xclient.data.l[0] = (long) xw.win;
+ reply.xclient.data.l[2] = 0;
+ reply.xclient.data.l[3] = 0;
+
+ XGetWindowProperty((Display*) xw.dpy, e->xselection.requestor,
+ e->xselection.property, 0, LONG_MAX, False,
+ e->xselection.target, &actualType, &actualFormat, &result,
+ &bytesAfter, (unsigned char**) &data);
+
+ if (result == 0)
+ return;
+
+ if (data) {
+ xdndpastedata(data);
+ XFree(data);
+ }
+
+ if (xw.XdndSourceVersion >= 2) {
+ reply.xclient.message_type = xw.XdndFinished;
+ reply.xclient.data.l[1] = result;
+ reply.xclient.data.l[2] = xw.XdndActionCopy;
+
+ XSendEvent((Display*) xw.dpy, xw.XdndSourceWin, False, NoEventMask,
+ &reply);
+ XFlush((Display*) xw.dpy);
+ }
+}
+
+int
+xdndurldecode(char *src, char *dest)
+{
+ char c;
+ int i = 0;
+
+ while (*src) {
+ if (*src == '%' && HEX_TO_INT(src[1]) != -1 && HEX_TO_INT(src[2]) != -1) {
+ /* handle %xx escape sequences in url e.g. %20 == ' ' */
+ c = (char)((HEX_TO_INT(src[1]) << 4) | HEX_TO_INT(src[2]));
+ src += 3;
+ } else {
+ c = *src++;
+ }
+ if (strchr(xdndescchar, c) != NULL) {
+ *dest++ = '\\';
+ i++;
+ }
+ *dest++ = c;
+ i++;
+ }
+ *dest++ = ' ';
+ *dest = '\0';
+ return i + 1;
+}
+
+void
+xdndpastedata(char *data)
+{
+ char *pastedata, *t;
+ int i = 0;
+
+ pastedata = (char *)malloc(strlen(data) * 2 + 1);
+ *pastedata = '\0';
+
+ t = strtok(data, "\n\r");
+ while(t != NULL) {
+ /* Remove 'file://' prefix if it exists */
+ if (strncmp(data, "file://", 7) == 0) {
+ t += 7;
+ }
+ i += xdndurldecode(t, pastedata + i);
+ t = strtok(NULL, "\n\r");
+ }
+
+ xsetsel(pastedata);
+ selpaste(0);
+}
+
+void
+xdndenter(XEvent *e)
+{
+ unsigned long count;
+ Atom* formats;
+ Atom real_formats[6];
+ Bool list;
+ Atom actualType;
+ int32_t actualFormat;
+ unsigned long bytesAfter;
+ unsigned long i;
+
+ list = e->xclient.data.l[1] & 1;
+
+ if (list) {
+ XGetWindowProperty((Display*) xw.dpy,
+ xw.XdndSourceWin,
+ xw.XdndTypeList,
+ 0,
+ LONG_MAX,
+ False,
+ 4,
+ &actualType,
+ &actualFormat,
+ &count,
+ &bytesAfter,
+ (unsigned char**) &formats);
+ } else {
+ count = 0;
+
+ if (e->xclient.data.l[2] != None)
+ real_formats[count++] = e->xclient.data.l[2];
+ if (e->xclient.data.l[3] != None)
+ real_formats[count++] = e->xclient.data.l[3];
+ if (e->xclient.data.l[4] != None)
+ real_formats[count++] = e->xclient.data.l[4];
+
+ formats = real_formats;
+ }
+
+ for (i = 0; i < count; i++) {
+ if (formats[i] == xw.XtextUriList || formats[i] == xw.XtextPlain) {
+ xw.XdndSourceFormat = formats[i];
+ break;
+ }
+ }
+
+ if (list)
+ XFree(formats);
+}
+
+void
+xdndpos(XEvent *e)
+{
+ const int32_t xabs = (e->xclient.data.l[2] >> 16) & 0xffff;
+ const int32_t yabs = (e->xclient.data.l[2]) & 0xffff;
+ Window dummy;
+ int32_t xpos, ypos;
+ XEvent reply = { ClientMessage };
+
+ reply.xclient.window = xw.XdndSourceWin;
+ reply.xclient.format = 32;
+ reply.xclient.data.l[0] = (long) xw.win;
+ reply.xclient.data.l[2] = 0;
+ reply.xclient.data.l[3] = 0;
+
+ XTranslateCoordinates((Display*) xw.dpy,
+ XDefaultRootWindow((Display*) xw.dpy),
+ (Window) xw.win,
+ xabs, yabs,
+ &xpos, &ypos,
+ &dummy);
+
+ reply.xclient.message_type = xw.XdndStatus;
+
+ if (xw.XdndSourceFormat) {
+ reply.xclient.data.l[1] = 1;
+ if (xw.XdndSourceVersion >= 2)
+ reply.xclient.data.l[4] = xw.XdndActionCopy;
+ }
+
+ XSendEvent((Display*) xw.dpy, xw.XdndSourceWin, False, NoEventMask,
+ &reply);
+ XFlush((Display*) xw.dpy);
+}
+
+void
+xdnddrop(XEvent *e)
+{
+ Time time = CurrentTime;
+ XEvent reply = { ClientMessage };
+
+ reply.xclient.window = xw.XdndSourceWin;
+ reply.xclient.format = 32;
+ reply.xclient.data.l[0] = (long) xw.win;
+ reply.xclient.data.l[2] = 0;
+ reply.xclient.data.l[3] = 0;
+
+ if (xw.XdndSourceFormat) {
+ if (xw.XdndSourceVersion >= 1)
+ time = e->xclient.data.l[2];
+
+ XConvertSelection((Display*) xw.dpy, xw.XdndSelection,
+ xw.XdndSourceFormat, xw.XdndSelection, (Window) xw.win, time);
+ } else if (xw.XdndSourceVersion >= 2) {
+ reply.xclient.message_type = xw.XdndFinished;
+
+ XSendEvent((Display*) xw.dpy, xw.XdndSourceWin,
+ False, NoEventMask, &reply);
+ XFlush((Display*) xw.dpy);
+ }
+}
diff --git a/patch/drag-n-drop.h b/patch/drag-n-drop.h
@@ -0,0 +1,5 @@
+static void xdndenter(XEvent *);
+static void xdndpos(XEvent *);
+static void xdnddrop(XEvent *);
+static void xdndsel(XEvent *);
+static void xdndpastedata(char *);
diff --git a/patch/externalpipe.c b/patch/externalpipe.c
@@ -0,0 +1,77 @@
+void
+#if EXTERNALPIPEIN_PATCH
+extpipe(const Arg *arg, int in)
+#else
+externalpipe(const Arg *arg)
+#endif // EXTERNALPIPEIN_PATCH
+{
+ int to[2];
+ char buf[UTF_SIZ];
+ void (*oldsigpipe)(int);
+ Glyph *bp, *end;
+ int lastpos, n, newline;
+
+ if (pipe(to) == -1)
+ return;
+
+ switch (fork()) {
+ case -1:
+ close(to[0]);
+ close(to[1]);
+ return;
+ case 0:
+ dup2(to[0], STDIN_FILENO);
+ close(to[0]);
+ close(to[1]);
+ #if EXTERNALPIPEIN_PATCH
+ if (in)
+ dup2(csdfd, STDOUT_FILENO);
+ close(csdfd);
+ #endif // EXTERNALPIPEIN_PATCH
+ execvp(((char **)arg->v)[0], (char **)arg->v);
+ fprintf(stderr, "st: execvp %s\n", ((char **)arg->v)[0]);
+ perror("failed");
+ exit(0);
+ }
+
+ close(to[0]);
+ /* ignore sigpipe for now, in case child exists early */
+ oldsigpipe = signal(SIGPIPE, SIG_IGN);
+ newline = 0;
+ for (n = 0; n < term.row; n++) {
+ bp = term.line[n];
+ #if REFLOW_PATCH
+ lastpos = MIN(tlinelen(TLINE(n)) + 1, term.col) - 1;
+ #else
+ lastpos = MIN(tlinelen(n) + 1, term.col) - 1;
+ #endif // REFLOW_PATCH
+ if (lastpos < 0)
+ break;
+ end = &bp[lastpos + 1];
+ for (; bp < end; ++bp)
+ if (xwrite(to[1], buf, utf8encode(bp->u, buf)) < 0)
+ break;
+ if ((newline = term.line[n][lastpos].mode & ATTR_WRAP))
+ continue;
+ if (xwrite(to[1], "\n", 1) < 0)
+ break;
+ newline = 0;
+ }
+ if (newline)
+ (void)xwrite(to[1], "\n", 1);
+ close(to[1]);
+ /* restore */
+ signal(SIGPIPE, oldsigpipe);
+}
+
+#if EXTERNALPIPEIN_PATCH
+void
+externalpipe(const Arg *arg) {
+ extpipe(arg, 0);
+}
+
+void
+externalpipein(const Arg *arg) {
+ extpipe(arg, 1);
+}
+#endif // EXTERNALPIPEIN_PATCH
+\ No newline at end of file
diff --git a/patch/externalpipe.h b/patch/externalpipe.h
@@ -0,0 +1,4 @@
+void externalpipe(const Arg *);
+#if EXTERNALPIPEIN_PATCH
+void externalpipein(const Arg *);
+#endif // EXTERNALPIPEIN_PATCH
+\ No newline at end of file
diff --git a/patch/fixkeyboardinput.c b/patch/fixkeyboardinput.c
@@ -0,0 +1,811 @@
+/*
+ * If you want keys other than the X11 function keys (0xFD00 - 0xFFFF)
+ * to be mapped below, add them to this array.
+ */
+static KeySym mappedkeys[] = {
+ XK_space,
+ XK_m,
+ XK_i,
+ XK_A,
+ XK_B,
+ XK_C,
+ XK_D,
+ XK_E,
+ XK_F,
+ XK_G,
+ XK_H,
+ XK_I,
+ XK_K,
+ XK_J,
+ XK_L,
+ XK_M,
+ XK_N,
+ XK_O,
+ XK_P,
+ XK_Q,
+ XK_R,
+ XK_S,
+ XK_T,
+ XK_U,
+ XK_V,
+ XK_W,
+ XK_X,
+ XK_Y,
+ XK_Z,
+ XK_0,
+ XK_1,
+ XK_2,
+ XK_3,
+ XK_4,
+ XK_5,
+ XK_6,
+ XK_7,
+ XK_8,
+ XK_9,
+ XK_exclam,
+ XK_quotedbl,
+ XK_numbersign,
+ XK_dollar,
+ XK_percent,
+ XK_ampersand,
+ XK_apostrophe,
+ XK_parenleft,
+ XK_parenright,
+ XK_asterisk,
+ XK_plus,
+ XK_comma,
+ XK_minus,
+ XK_period,
+ XK_slash,
+ XK_colon,
+ XK_semicolon,
+ XK_less,
+ XK_equal,
+ XK_greater,
+ XK_question,
+ XK_at,
+ XK_bracketleft,
+ XK_backslash,
+ XK_bracketright,
+ XK_asciicircum,
+ XK_underscore,
+ XK_grave,
+ XK_braceleft,
+ XK_bar,
+ XK_braceright,
+ XK_asciitilde,
+};
+
+/*
+ * This is the huge key array which defines all compatibility to the Linux
+ * world. Please decide about changes wisely.
+ */
+static Key key[] = {
+ /* keysym mask string appkey appcursor */
+ { XK_KP_Home, ShiftMask, "\033[2J", 0, -1},
+ { XK_KP_Home, ShiftMask, "\033[1;2H", 0, +1},
+ { XK_KP_Prior, ShiftMask, "\033[5;2~", 0, 0},
+ { XK_KP_End, ControlMask, "\033[J", -1, 0},
+ { XK_KP_End, ControlMask, "\033[1;5F", +1, 0},
+ { XK_KP_End, ShiftMask, "\033[K", -1, 0},
+ { XK_KP_End, ShiftMask, "\033[1;2F", +1, 0},
+ { XK_KP_Next, ShiftMask, "\033[6;2~", 0, 0},
+ { XK_KP_Insert, ShiftMask, "\033[2;2~", +1, 0},
+ { XK_KP_Insert, ShiftMask, "\033[4l", -1, 0},
+ { XK_KP_Insert, ControlMask, "\033[L", -1, 0},
+ { XK_KP_Insert, ControlMask, "\033[2;5~", +1, 0},
+ { XK_KP_Delete, ControlMask, "\033[M", -1, 0},
+ { XK_KP_Delete, ControlMask, "\033[3;5~", +1, 0},
+ { XK_KP_Delete, ShiftMask, "\033[2K", -1, 0},
+ { XK_KP_Delete, ShiftMask, "\033[3;2~", +1, 0},
+ { XK_Up, ShiftMask, "\033[1;2A", 0, 0},
+ { XK_Up, Mod1Mask, "\033[1;3A", 0, 0},
+ { XK_Up, ShiftMask|Mod1Mask,"\033[1;4A", 0, 0},
+ { XK_Up, ControlMask, "\033[1;5A", 0, 0},
+ { XK_Up, ShiftMask|ControlMask,"\033[1;6A", 0, 0},
+ { XK_Up, ControlMask|Mod1Mask,"\033[1;7A", 0, 0},
+ { XK_Up,ShiftMask|ControlMask|Mod1Mask,"\033[1;8A", 0, 0},
+ { XK_Up, XK_ANY_MOD, "\033[A", 0, -1},
+ { XK_Up, XK_ANY_MOD, "\033OA", 0, +1},
+ { XK_Down, ShiftMask, "\033[1;2B", 0, 0},
+ { XK_Down, Mod1Mask, "\033[1;3B", 0, 0},
+ { XK_Down, ShiftMask|Mod1Mask,"\033[1;4B", 0, 0},
+ { XK_Down, ControlMask, "\033[1;5B", 0, 0},
+ { XK_Down, ShiftMask|ControlMask,"\033[1;6B", 0, 0},
+ { XK_Down, ControlMask|Mod1Mask,"\033[1;7B", 0, 0},
+ { XK_Down,ShiftMask|ControlMask|Mod1Mask,"\033[1;8B",0, 0},
+ { XK_Down, XK_ANY_MOD, "\033[B", 0, -1},
+ { XK_Down, XK_ANY_MOD, "\033OB", 0, +1},
+ { XK_Left, ShiftMask, "\033[1;2D", 0, 0},
+ { XK_Left, Mod1Mask, "\033[1;3D", 0, 0},
+ { XK_Left, ShiftMask|Mod1Mask,"\033[1;4D", 0, 0},
+ { XK_Left, ControlMask, "\033[1;5D", 0, 0},
+ { XK_Left, ShiftMask|ControlMask,"\033[1;6D", 0, 0},
+ { XK_Left, ControlMask|Mod1Mask,"\033[1;7D", 0, 0},
+ { XK_Left,ShiftMask|ControlMask|Mod1Mask,"\033[1;8D",0, 0},
+ { XK_Left, XK_ANY_MOD, "\033[D", 0, -1},
+ { XK_Left, XK_ANY_MOD, "\033OD", 0, +1},
+ { XK_Right, ShiftMask, "\033[1;2C", 0, 0},
+ { XK_Right, Mod1Mask, "\033[1;3C", 0, 0},
+ { XK_Right, ShiftMask|Mod1Mask,"\033[1;4C", 0, 0},
+ { XK_Right, ControlMask, "\033[1;5C", 0, 0},
+ { XK_Right, ShiftMask|ControlMask,"\033[1;6C", 0, 0},
+ { XK_Right, ControlMask|Mod1Mask,"\033[1;7C", 0, 0},
+ { XK_Right,ShiftMask|ControlMask|Mod1Mask,"\033[1;8C",0, 0},
+ { XK_Right, XK_ANY_MOD, "\033[C", 0, -1},
+ { XK_Right, XK_ANY_MOD, "\033OC", 0, +1},
+ { XK_ISO_Left_Tab, ShiftMask, "\033[Z", 0, 0},
+ { XK_Return, Mod1Mask, "\033\r", 0, 0},
+ { XK_Return, XK_NO_MOD, "\r", 0, 0},
+ { XK_Insert, ShiftMask, "\033[4l", -1, 0},
+ { XK_Insert, ShiftMask, "\033[2;2~", +1, 0},
+ { XK_Insert, ControlMask, "\033[L", -1, 0},
+ { XK_Insert, ControlMask, "\033[2;5~", +1, 0},
+ { XK_Delete, ControlMask, "\033[M", -1, 0},
+ { XK_Delete, ControlMask, "\033[3;5~", +1, 0},
+ { XK_Delete, ShiftMask, "\033[2K", -1, 0},
+ { XK_Delete, ShiftMask, "\033[3;2~", +1, 0},
+ { XK_BackSpace, XK_NO_MOD, "\177", 0, 0},
+ { XK_BackSpace, Mod1Mask, "\033\177", 0, 0},
+ { XK_Home, ShiftMask, "\033[2J", 0, -1},
+ { XK_Home, ShiftMask, "\033[1;2H", 0, +1},
+ { XK_End, ControlMask, "\033[J", -1, 0},
+ { XK_End, ControlMask, "\033[1;5F", +1, 0},
+ { XK_End, ShiftMask, "\033[K", -1, 0},
+ { XK_End, ShiftMask, "\033[1;2F", +1, 0},
+ { XK_Prior, ControlMask, "\033[5;5~", 0, 0},
+ { XK_Prior, ShiftMask, "\033[5;2~", 0, 0},
+ { XK_Next, ControlMask, "\033[6;5~", 0, 0},
+ { XK_Next, ShiftMask, "\033[6;2~", 0, 0},
+ { XK_F1, XK_NO_MOD, "\033OP" , 0, 0},
+ { XK_F1, /* F13 */ ShiftMask, "\033[1;2P", 0, 0},
+ { XK_F1, /* F25 */ ControlMask, "\033[1;5P", 0, 0},
+ { XK_F1, /* F37 */ Mod4Mask, "\033[1;6P", 0, 0},
+ { XK_F1, /* F49 */ Mod1Mask, "\033[1;3P", 0, 0},
+ { XK_F1, /* F61 */ Mod3Mask, "\033[1;4P", 0, 0},
+ { XK_F2, XK_NO_MOD, "\033OQ" , 0, 0},
+ { XK_F2, /* F14 */ ShiftMask, "\033[1;2Q", 0, 0},
+ { XK_F2, /* F26 */ ControlMask, "\033[1;5Q", 0, 0},
+ { XK_F2, /* F38 */ Mod4Mask, "\033[1;6Q", 0, 0},
+ { XK_F2, /* F50 */ Mod1Mask, "\033[1;3Q", 0, 0},
+ { XK_F2, /* F62 */ Mod3Mask, "\033[1;4Q", 0, 0},
+ { XK_F3, XK_NO_MOD, "\033OR" , 0, 0},
+ { XK_F3, /* F15 */ ShiftMask, "\033[1;2R", 0, 0},
+ { XK_F3, /* F27 */ ControlMask, "\033[1;5R", 0, 0},
+ { XK_F3, /* F39 */ Mod4Mask, "\033[1;6R", 0, 0},
+ { XK_F3, /* F51 */ Mod1Mask, "\033[1;3R", 0, 0},
+ { XK_F3, /* F63 */ Mod3Mask, "\033[1;4R", 0, 0},
+ { XK_F4, XK_NO_MOD, "\033OS" , 0, 0},
+ { XK_F4, /* F16 */ ShiftMask, "\033[1;2S", 0, 0},
+ { XK_F4, /* F28 */ ControlMask, "\033[1;5S", 0, 0},
+ { XK_F4, /* F40 */ Mod4Mask, "\033[1;6S", 0, 0},
+ { XK_F4, /* F52 */ Mod1Mask, "\033[1;3S", 0, 0},
+ { XK_F5, XK_NO_MOD, "\033[15~", 0, 0},
+ { XK_F5, /* F17 */ ShiftMask, "\033[15;2~", 0, 0},
+ { XK_F5, /* F29 */ ControlMask, "\033[15;5~", 0, 0},
+ { XK_F5, /* F41 */ Mod4Mask, "\033[15;6~", 0, 0},
+ { XK_F5, /* F53 */ Mod1Mask, "\033[15;3~", 0, 0},
+ { XK_F6, XK_NO_MOD, "\033[17~", 0, 0},
+ { XK_F6, /* F18 */ ShiftMask, "\033[17;2~", 0, 0},
+ { XK_F6, /* F30 */ ControlMask, "\033[17;5~", 0, 0},
+ { XK_F6, /* F42 */ Mod4Mask, "\033[17;6~", 0, 0},
+ { XK_F6, /* F54 */ Mod1Mask, "\033[17;3~", 0, 0},
+ { XK_F7, XK_NO_MOD, "\033[18~", 0, 0},
+ { XK_F7, /* F19 */ ShiftMask, "\033[18;2~", 0, 0},
+ { XK_F7, /* F31 */ ControlMask, "\033[18;5~", 0, 0},
+ { XK_F7, /* F43 */ Mod4Mask, "\033[18;6~", 0, 0},
+ { XK_F7, /* F55 */ Mod1Mask, "\033[18;3~", 0, 0},
+ { XK_F8, XK_NO_MOD, "\033[19~", 0, 0},
+ { XK_F8, /* F20 */ ShiftMask, "\033[19;2~", 0, 0},
+ { XK_F8, /* F32 */ ControlMask, "\033[19;5~", 0, 0},
+ { XK_F8, /* F44 */ Mod4Mask, "\033[19;6~", 0, 0},
+ { XK_F8, /* F56 */ Mod1Mask, "\033[19;3~", 0, 0},
+ { XK_F9, XK_NO_MOD, "\033[20~", 0, 0},
+ { XK_F9, /* F21 */ ShiftMask, "\033[20;2~", 0, 0},
+ { XK_F9, /* F33 */ ControlMask, "\033[20;5~", 0, 0},
+ { XK_F9, /* F45 */ Mod4Mask, "\033[20;6~", 0, 0},
+ { XK_F9, /* F57 */ Mod1Mask, "\033[20;3~", 0, 0},
+ { XK_F10, XK_NO_MOD, "\033[21~", 0, 0},
+ { XK_F10, /* F22 */ ShiftMask, "\033[21;2~", 0, 0},
+ { XK_F10, /* F34 */ ControlMask, "\033[21;5~", 0, 0},
+ { XK_F10, /* F46 */ Mod4Mask, "\033[21;6~", 0, 0},
+ { XK_F10, /* F58 */ Mod1Mask, "\033[21;3~", 0, 0},
+ { XK_F11, XK_NO_MOD, "\033[23~", 0, 0},
+ { XK_F11, /* F23 */ ShiftMask, "\033[23;2~", 0, 0},
+ { XK_F11, /* F35 */ ControlMask, "\033[23;5~", 0, 0},
+ { XK_F11, /* F47 */ Mod4Mask, "\033[23;6~", 0, 0},
+ { XK_F11, /* F59 */ Mod1Mask, "\033[23;3~", 0, 0},
+ { XK_F12, XK_NO_MOD, "\033[24~", 0, 0},
+ { XK_F12, /* F24 */ ShiftMask, "\033[24;2~", 0, 0},
+ { XK_F12, /* F36 */ ControlMask, "\033[24;5~", 0, 0},
+ { XK_F12, /* F48 */ Mod4Mask, "\033[24;6~", 0, 0},
+ { XK_F12, /* F60 */ Mod1Mask, "\033[24;3~", 0, 0},
+ { XK_F13, XK_NO_MOD, "\033[1;2P", 0, 0},
+ { XK_F14, XK_NO_MOD, "\033[1;2Q", 0, 0},
+ { XK_F15, XK_NO_MOD, "\033[1;2R", 0, 0},
+ { XK_F16, XK_NO_MOD, "\033[1;2S", 0, 0},
+ { XK_F17, XK_NO_MOD, "\033[15;2~", 0, 0},
+ { XK_F18, XK_NO_MOD, "\033[17;2~", 0, 0},
+ { XK_F19, XK_NO_MOD, "\033[18;2~", 0, 0},
+ { XK_F20, XK_NO_MOD, "\033[19;2~", 0, 0},
+ { XK_F21, XK_NO_MOD, "\033[20;2~", 0, 0},
+ { XK_F22, XK_NO_MOD, "\033[21;2~", 0, 0},
+ { XK_F23, XK_NO_MOD, "\033[23;2~", 0, 0},
+ { XK_F24, XK_NO_MOD, "\033[24;2~", 0, 0},
+ { XK_F25, XK_NO_MOD, "\033[1;5P", 0, 0},
+ { XK_F26, XK_NO_MOD, "\033[1;5Q", 0, 0},
+ { XK_F27, XK_NO_MOD, "\033[1;5R", 0, 0},
+ { XK_F28, XK_NO_MOD, "\033[1;5S", 0, 0},
+ { XK_F29, XK_NO_MOD, "\033[15;5~", 0, 0},
+ { XK_F30, XK_NO_MOD, "\033[17;5~", 0, 0},
+ { XK_F31, XK_NO_MOD, "\033[18;5~", 0, 0},
+ { XK_F32, XK_NO_MOD, "\033[19;5~", 0, 0},
+ { XK_F33, XK_NO_MOD, "\033[20;5~", 0, 0},
+ { XK_F34, XK_NO_MOD, "\033[21;5~", 0, 0},
+ { XK_F35, XK_NO_MOD, "\033[23;5~", 0, 0},
+
+ // libtermkey compatible keyboard input
+ { XK_KP_Home, XK_NO_MOD, "\033[H", 0, -1},
+ { XK_KP_Home, XK_NO_MOD, "\033[1~", 0, +1},
+ { XK_KP_Home, ControlMask, "\033[149;5u", 0, 0},
+ { XK_KP_Home, ControlMask|ShiftMask, "\033[149;6u", 0, 0},
+ { XK_KP_Home, Mod1Mask, "\033[149;3u", 0, 0},
+ { XK_KP_Home, Mod1Mask|ControlMask, "\033[149;7u", 0, 0},
+ { XK_KP_Home, Mod1Mask|ControlMask|ShiftMask, "\033[149;8u", 0, 0},
+ { XK_KP_Home, Mod1Mask|ShiftMask, "\033[149;4u", 0, 0},
+ { XK_KP_Home, ShiftMask, "\033[149;2u", 0, 0},
+ { XK_KP_Up, XK_NO_MOD, "\033Ox", +1, 0},
+ { XK_KP_Up, XK_NO_MOD, "\033[A", 0, -1},
+ { XK_KP_Up, XK_NO_MOD, "\033OA", 0, +1},
+ { XK_KP_Up, ControlMask, "\033[151;5u", 0, 0},
+ { XK_KP_Up, ControlMask|ShiftMask, "\033[151;6u", 0, 0},
+ { XK_KP_Up, Mod1Mask, "\033[151;3u", 0, 0},
+ { XK_KP_Up, Mod1Mask|ControlMask, "\033[151;7u", 0, 0},
+ { XK_KP_Up, Mod1Mask|ControlMask|ShiftMask, "\033[151;8u", 0, 0},
+ { XK_KP_Up, Mod1Mask|ShiftMask, "\033[151;4u", 0, 0},
+ { XK_KP_Up, ShiftMask, "\033[151;2u", 0, 0},
+ { XK_KP_Down, XK_NO_MOD, "\033Or", +1, 0},
+ { XK_KP_Down, XK_NO_MOD, "\033[B", 0, -1},
+ { XK_KP_Down, XK_NO_MOD, "\033OB", 0, +1},
+ { XK_KP_Down, ControlMask, "\033[153;5u", 0, 0},
+ { XK_KP_Down, ControlMask|ShiftMask, "\033[153;6u", 0, 0},
+ { XK_KP_Down, Mod1Mask, "\033[153;3u", 0, 0},
+ { XK_KP_Down, Mod1Mask|ControlMask, "\033[153;7u", 0, 0},
+ { XK_KP_Down, Mod1Mask|ControlMask|ShiftMask, "\033[153;8u", 0, 0},
+ { XK_KP_Down, Mod1Mask|ShiftMask, "\033[153;4u", 0, 0},
+ { XK_KP_Down, ShiftMask, "\033[153;2u", 0, 0},
+ { XK_KP_Left, XK_NO_MOD, "\033Ot", +1, 0},
+ { XK_KP_Left, XK_NO_MOD, "\033[D", 0, -1},
+ { XK_KP_Left, XK_NO_MOD, "\033OD", 0, +1},
+ { XK_KP_Left, ControlMask, "\033[150;5u", 0, 0},
+ { XK_KP_Left, ControlMask|ShiftMask, "\033[150;6u", 0, 0},
+ { XK_KP_Left, Mod1Mask, "\033[150;3u", 0, 0},
+ { XK_KP_Left, Mod1Mask|ControlMask, "\033[150;7u", 0, 0},
+ { XK_KP_Left, Mod1Mask|ControlMask|ShiftMask, "\033[150;8u", 0, 0},
+ { XK_KP_Left, Mod1Mask|ShiftMask, "\033[150;4u", 0, 0},
+ { XK_KP_Left, ShiftMask, "\033[150;2u", 0, 0},
+ { XK_KP_Right, XK_NO_MOD, "\033Ov", +1, 0},
+ { XK_KP_Right, XK_NO_MOD, "\033[C", 0, -1},
+ { XK_KP_Right, XK_NO_MOD, "\033OC", 0, +1},
+ { XK_KP_Right, ControlMask, "\033[152;5u", 0, 0},
+ { XK_KP_Right, ControlMask|ShiftMask, "\033[152;6u", 0, 0},
+ { XK_KP_Right, Mod1Mask, "\033[152;3u", 0, 0},
+ { XK_KP_Right, Mod1Mask|ControlMask, "\033[152;7u", 0, 0},
+ { XK_KP_Right, Mod1Mask|ControlMask|ShiftMask, "\033[152;8u", 0, 0},
+ { XK_KP_Right, Mod1Mask|ShiftMask, "\033[152;4u", 0, 0},
+ { XK_KP_Right, ShiftMask, "\033[152;2u", 0, 0},
+ { XK_KP_Prior, XK_NO_MOD, "\033[5~", 0, 0},
+ { XK_KP_Prior, ControlMask, "\033[154;5u", 0, 0},
+ { XK_KP_Prior, ControlMask|ShiftMask, "\033[154;6u", 0, 0},
+ { XK_KP_Prior, Mod1Mask, "\033[154;3u", 0, 0},
+ { XK_KP_Prior, Mod1Mask|ControlMask, "\033[154;7u", 0, 0},
+ { XK_KP_Prior, Mod1Mask|ControlMask|ShiftMask, "\033[154;8u", 0, 0},
+ { XK_KP_Prior, Mod1Mask|ShiftMask, "\033[154;4u", 0, 0},
+ { XK_KP_Begin, XK_NO_MOD, "\033[E", 0, 0},
+ { XK_KP_Begin, ControlMask, "\033[157;5u", 0, 0},
+ { XK_KP_Begin, ControlMask|ShiftMask, "\033[157;6u", 0, 0},
+ { XK_KP_Begin, Mod1Mask, "\033[157;3u", 0, 0},
+ { XK_KP_Begin, Mod1Mask|ControlMask, "\033[157;7u", 0, 0},
+ { XK_KP_Begin, Mod1Mask|ControlMask|ShiftMask, "\033[157;8u", 0, 0},
+ { XK_KP_Begin, Mod1Mask|ShiftMask, "\033[157;4u", 0, 0},
+ { XK_KP_Begin, ShiftMask, "\033[157;2u", 0, 0},
+ { XK_KP_End, XK_NO_MOD, "\033[4~", 0, 0},
+ { XK_KP_End, ControlMask|ShiftMask, "\033[156;6u", 0, 0},
+ { XK_KP_End, Mod1Mask, "\033[156;3u", 0, 0},
+ { XK_KP_End, Mod1Mask|ControlMask, "\033[156;7u", 0, 0},
+ { XK_KP_End, Mod1Mask|ControlMask|ShiftMask, "\033[156;8u", 0, 0},
+ { XK_KP_End, Mod1Mask|ShiftMask, "\033[156;4u", 0, 0},
+ { XK_KP_Next, XK_NO_MOD, "\033[6~", 0, 0},
+ { XK_KP_Next, ControlMask, "\033[155;5u", 0, 0},
+ { XK_KP_Next, ControlMask|ShiftMask, "\033[155;6u", 0, 0},
+ { XK_KP_Next, Mod1Mask, "\033[155;3u", 0, 0},
+ { XK_KP_Next, Mod1Mask|ControlMask, "\033[155;7u", 0, 0},
+ { XK_KP_Next, Mod1Mask|ControlMask|ShiftMask, "\033[155;8u", 0, 0},
+ { XK_KP_Next, Mod1Mask|ShiftMask, "\033[155;4u", 0, 0},
+ { XK_KP_Insert, XK_NO_MOD, "\033[4h", -1, 0},
+ { XK_KP_Insert, XK_NO_MOD, "\033[2~", +1, 0},
+ { XK_KP_Insert, ControlMask|ShiftMask, "\033[158;6u", 0, 0},
+ { XK_KP_Insert, Mod1Mask, "\033[158;3u", 0, 0},
+ { XK_KP_Insert, Mod1Mask|ControlMask, "\033[158;7u", 0, 0},
+ { XK_KP_Insert, Mod1Mask|ControlMask|ShiftMask, "\033[158;8u", 0, 0},
+ { XK_KP_Insert, Mod1Mask|ShiftMask, "\033[158;4u", 0, 0},
+ { XK_KP_Delete, XK_NO_MOD, "\033[P", -1, 0},
+ { XK_KP_Delete, XK_NO_MOD, "\033[3~", +1, 0},
+ { XK_KP_Delete, ControlMask|ShiftMask, "\033[159;6u", 0, 0},
+ { XK_KP_Delete, Mod1Mask, "\033[159;3u", 0, 0},
+ { XK_KP_Delete, Mod1Mask|ControlMask, "\033[159;7u", 0, 0},
+ { XK_KP_Delete, Mod1Mask|ControlMask|ShiftMask, "\033[159;8u", 0, 0},
+ { XK_KP_Delete, Mod1Mask|ShiftMask, "\033[159;4u", 0, 0},
+ { XK_KP_Multiply, XK_NO_MOD, "\033Oj", +2, 0},
+ { XK_KP_Multiply, ControlMask, "\033[170;5u", 0, 0},
+ { XK_KP_Multiply, ControlMask|ShiftMask, "\033[170;6u", 0, 0},
+ { XK_KP_Multiply, Mod1Mask, "\033[170;3u", 0, 0},
+ { XK_KP_Multiply, Mod1Mask|ControlMask, "\033[170;7u", 0, 0},
+ { XK_KP_Multiply, Mod1Mask|ControlMask|ShiftMask, "\033[170;8u", 0, 0},
+ { XK_KP_Multiply, Mod1Mask|ShiftMask, "\033[170;4u", 0, 0},
+ { XK_KP_Multiply, ShiftMask, "\033[170;2u", 0, 0},
+ { XK_KP_Add, XK_NO_MOD, "\033Ok", +2, 0},
+ { XK_KP_Add, ControlMask, "\033[171;5u", 0, 0},
+ { XK_KP_Add, ControlMask|ShiftMask, "\033[171;6u", 0, 0},
+ { XK_KP_Add, Mod1Mask, "\033[171;3u", 0, 0},
+ { XK_KP_Add, Mod1Mask|ControlMask, "\033[171;7u", 0, 0},
+ { XK_KP_Add, Mod1Mask|ControlMask|ShiftMask, "\033[171;8u", 0, 0},
+ { XK_KP_Add, Mod1Mask|ShiftMask, "\033[171;4u", 0, 0},
+ { XK_KP_Add, ShiftMask, "\033[171;2u", 0, 0},
+ { XK_KP_Enter, XK_NO_MOD, "\033OM", +2, 0},
+ { XK_KP_Enter, XK_NO_MOD, "\r", -1, 0},
+ { XK_KP_Enter, XK_NO_MOD, "\r\n", -1, 0},
+ { XK_KP_Enter, ControlMask, "\033[141;5u", 0, 0},
+ { XK_KP_Enter, ControlMask|ShiftMask, "\033[141;6u", 0, 0},
+ { XK_KP_Enter, Mod1Mask, "\033[141;3u", 0, 0},
+ { XK_KP_Enter, Mod1Mask|ControlMask, "\033[141;7u", 0, 0},
+ { XK_KP_Enter, Mod1Mask|ControlMask|ShiftMask, "\033[141;8u", 0, 0},
+ { XK_KP_Enter, Mod1Mask|ShiftMask, "\033[141;4u", 0, 0},
+ { XK_KP_Enter, ShiftMask, "\033[141;2u", 0, 0},
+ { XK_KP_Subtract, XK_NO_MOD, "\033Om", +2, 0},
+ { XK_KP_Subtract, ControlMask, "\033[173;5u", 0, 0},
+ { XK_KP_Subtract, ControlMask|ShiftMask, "\033[173;6u", 0, 0},
+ { XK_KP_Subtract, Mod1Mask, "\033[173;3u", 0, 0},
+ { XK_KP_Subtract, Mod1Mask|ControlMask, "\033[173;7u", 0, 0},
+ { XK_KP_Subtract, Mod1Mask|ControlMask|ShiftMask, "\033[173;8u", 0, 0},
+ { XK_KP_Subtract, Mod1Mask|ShiftMask, "\033[173;4u", 0, 0},
+ { XK_KP_Subtract, ShiftMask, "\033[173;2u", 0, 0},
+ { XK_KP_Decimal, XK_NO_MOD, "\033On", +2, 0},
+ { XK_KP_Decimal, ControlMask, "\033[174;5u", 0, 0},
+ { XK_KP_Decimal, ControlMask|ShiftMask, "\033[174;6u", 0, 0},
+ { XK_KP_Decimal, Mod1Mask, "\033[174;3u", 0, 0},
+ { XK_KP_Decimal, Mod1Mask|ControlMask, "\033[174;7u", 0, 0},
+ { XK_KP_Decimal, Mod1Mask|ControlMask|ShiftMask, "\033[174;8u", 0, 0},
+ { XK_KP_Decimal, Mod1Mask|ShiftMask, "\033[174;4u", 0, 0},
+ { XK_KP_Decimal, ShiftMask, "\033[174;2u", 0, 0},
+ { XK_KP_Divide, XK_NO_MOD, "\033Oo", +2, 0},
+ { XK_KP_Divide, ControlMask, "\033[175;5u", 0, 0},
+ { XK_KP_Divide, ControlMask|ShiftMask, "\033[175;6u", 0, 0},
+ { XK_KP_Divide, Mod1Mask, "\033[175;3u", 0, 0},
+ { XK_KP_Divide, Mod1Mask|ControlMask, "\033[175;7u", 0, 0},
+ { XK_KP_Divide, Mod1Mask|ControlMask|ShiftMask, "\033[175;8u", 0, 0},
+ { XK_KP_Divide, Mod1Mask|ShiftMask, "\033[175;4u", 0, 0},
+ { XK_KP_Divide, ShiftMask, "\033[175;2u", 0, 0},
+ { XK_KP_0, XK_NO_MOD, "\033Op", +2, 0},
+ { XK_KP_0, ControlMask, "\033[176;5u", 0, 0},
+ { XK_KP_0, ControlMask|ShiftMask, "\033[176;6u", 0, 0},
+ { XK_KP_0, Mod1Mask, "\033[176;3u", 0, 0},
+ { XK_KP_0, Mod1Mask|ControlMask, "\033[176;7u", 0, 0},
+ { XK_KP_0, Mod1Mask|ControlMask|ShiftMask, "\033[176;8u", 0, 0},
+ { XK_KP_0, Mod1Mask|ShiftMask, "\033[176;4u", 0, 0},
+ { XK_KP_0, ShiftMask, "\033[176;2u", 0, 0},
+ { XK_KP_1, XK_NO_MOD, "\033Oq", +2, 0},
+ { XK_KP_0, ControlMask, "\033[177;5u", 0, 0},
+ { XK_KP_0, ControlMask|ShiftMask, "\033[177;6u", 0, 0},
+ { XK_KP_0, Mod1Mask, "\033[177;3u", 0, 0},
+ { XK_KP_0, Mod1Mask|ControlMask, "\033[177;7u", 0, 0},
+ { XK_KP_0, Mod1Mask|ControlMask|ShiftMask, "\033[177;8u", 0, 0},
+ { XK_KP_0, Mod1Mask|ShiftMask, "\033[177;4u", 0, 0},
+ { XK_KP_0, ShiftMask, "\033[177;2u", 0, 0},
+ { XK_KP_2, XK_NO_MOD, "\033Or", +2, 0},
+ { XK_KP_2, ControlMask, "\033[178;5u", 0, 0},
+ { XK_KP_2, ControlMask|ShiftMask, "\033[178;6u", 0, 0},
+ { XK_KP_2, Mod1Mask, "\033[178;3u", 0, 0},
+ { XK_KP_2, Mod1Mask|ControlMask, "\033[178;7u", 0, 0},
+ { XK_KP_2, Mod1Mask|ControlMask|ShiftMask, "\033[178;8u", 0, 0},
+ { XK_KP_2, Mod1Mask|ShiftMask, "\033[178;4u", 0, 0},
+ { XK_KP_2, ShiftMask, "\033[178;2u", 0, 0},
+ { XK_KP_3, XK_NO_MOD, "\033Os", +2, 0},
+ { XK_KP_3, ControlMask, "\033[179;5u", 0, 0},
+ { XK_KP_3, ControlMask|ShiftMask, "\033[179;6u", 0, 0},
+ { XK_KP_3, Mod1Mask, "\033[179;3u", 0, 0},
+ { XK_KP_3, Mod1Mask|ControlMask, "\033[179;7u", 0, 0},
+ { XK_KP_3, Mod1Mask|ControlMask|ShiftMask, "\033[179;8u", 0, 0},
+ { XK_KP_3, Mod1Mask|ShiftMask, "\033[179;4u", 0, 0},
+ { XK_KP_3, ShiftMask, "\033[179;2u", 0, 0},
+ { XK_KP_4, XK_NO_MOD, "\033Ot", +2, 0},
+ { XK_KP_4, ControlMask, "\033[180;5u", 0, 0},
+ { XK_KP_4, ControlMask|ShiftMask, "\033[180;6u", 0, 0},
+ { XK_KP_4, Mod1Mask, "\033[180;3u", 0, 0},
+ { XK_KP_4, Mod1Mask|ControlMask, "\033[180;7u", 0, 0},
+ { XK_KP_4, Mod1Mask|ControlMask|ShiftMask, "\033[180;8u", 0, 0},
+ { XK_KP_4, Mod1Mask|ShiftMask, "\033[180;4u", 0, 0},
+ { XK_KP_4, ShiftMask, "\033[180;2u", 0, 0},
+ { XK_KP_5, XK_NO_MOD, "\033Ou", +2, 0},
+ { XK_KP_5, ControlMask, "\033[181;5u", 0, 0},
+ { XK_KP_5, ControlMask|ShiftMask, "\033[181;6u", 0, 0},
+ { XK_KP_5, Mod1Mask, "\033[181;3u", 0, 0},
+ { XK_KP_5, Mod1Mask|ControlMask, "\033[181;7u", 0, 0},
+ { XK_KP_5, Mod1Mask|ControlMask|ShiftMask, "\033[181;8u", 0, 0},
+ { XK_KP_5, Mod1Mask|ShiftMask, "\033[181;4u", 0, 0},
+ { XK_KP_5, ShiftMask, "\033[181;2u", 0, 0},
+ { XK_KP_6, XK_NO_MOD, "\033Ov", +2, 0},
+ { XK_KP_6, ControlMask, "\033[182;5u", 0, 0},
+ { XK_KP_6, ControlMask|ShiftMask, "\033[182;6u", 0, 0},
+ { XK_KP_6, Mod1Mask, "\033[182;3u", 0, 0},
+ { XK_KP_6, Mod1Mask|ControlMask, "\033[182;7u", 0, 0},
+ { XK_KP_6, Mod1Mask|ControlMask|ShiftMask, "\033[182;8u", 0, 0},
+ { XK_KP_6, Mod1Mask|ShiftMask, "\033[182;4u", 0, 0},
+ { XK_KP_6, ShiftMask, "\033[182;2u", 0, 0},
+ { XK_KP_7, XK_NO_MOD, "\033Ow", +2, 0},
+ { XK_KP_7, ControlMask, "\033[183;5u", 0, 0},
+ { XK_KP_7, ControlMask|ShiftMask, "\033[183;6u", 0, 0},
+ { XK_KP_7, Mod1Mask, "\033[183;3u", 0, 0},
+ { XK_KP_7, Mod1Mask|ControlMask, "\033[183;7u", 0, 0},
+ { XK_KP_7, Mod1Mask|ControlMask|ShiftMask, "\033[183;8u", 0, 0},
+ { XK_KP_7, Mod1Mask|ShiftMask, "\033[183;4u", 0, 0},
+ { XK_KP_7, ShiftMask, "\033[183;2u", 0, 0},
+ { XK_KP_8, XK_NO_MOD, "\033Ox", +2, 0},
+ { XK_KP_8, ControlMask, "\033[184;5u", 0, 0},
+ { XK_KP_8, ControlMask|ShiftMask, "\033[184;6u", 0, 0},
+ { XK_KP_8, Mod1Mask, "\033[184;3u", 0, 0},
+ { XK_KP_8, Mod1Mask|ControlMask, "\033[184;7u", 0, 0},
+ { XK_KP_8, Mod1Mask|ControlMask|ShiftMask, "\033[184;8u", 0, 0},
+ { XK_KP_8, Mod1Mask|ShiftMask, "\033[184;4u", 0, 0},
+ { XK_KP_8, ShiftMask, "\033[184;2u", 0, 0},
+ { XK_KP_9, XK_NO_MOD, "\033Oy", +2, 0},
+ { XK_KP_9, ControlMask, "\033[185;5u", 0, 0},
+ { XK_KP_9, ControlMask|ShiftMask, "\033[185;6u", 0, 0},
+ { XK_KP_9, Mod1Mask, "\033[185;3u", 0, 0},
+ { XK_KP_9, Mod1Mask|ControlMask, "\033[185;7u", 0, 0},
+ { XK_KP_9, Mod1Mask|ControlMask|ShiftMask, "\033[185;8u", 0, 0},
+ { XK_KP_9, Mod1Mask|ShiftMask, "\033[185;4u", 0, 0},
+ { XK_KP_9, ShiftMask, "\033[185;2u", 0, 0},
+ { XK_BackSpace, ControlMask, "\033[127;5u", 0, 0},
+ { XK_BackSpace, ControlMask|ShiftMask, "\033[127;6u", 0, 0},
+ { XK_BackSpace, Mod1Mask, "\033[127;3u", 0, 0},
+ { XK_BackSpace, Mod1Mask|ControlMask, "\033[127;7u", 0, 0},
+ { XK_BackSpace, Mod1Mask|ControlMask|ShiftMask, "\033[127;8u", 0, 0},
+ { XK_BackSpace, Mod1Mask|ShiftMask, "\033[127;4u", 0, 0},
+ { XK_BackSpace, ShiftMask, "\033[127;2u", 0, 0},
+ { XK_Tab, ControlMask, "\033[9;5u", 0, 0},
+ { XK_Tab, ControlMask|ShiftMask, "\033[1;5Z", 0, 0},
+ { XK_Tab, Mod1Mask, "\033[1;3Z", 0, 0},
+ { XK_Tab, Mod1Mask|ControlMask, "\033[1;7Z", 0, 0},
+ { XK_Tab, Mod1Mask|ControlMask|ShiftMask, "\033[1;8Z", 0, 0},
+ { XK_Tab, Mod1Mask|ShiftMask, "\033[1;4Z", 0, 0},
+ { XK_Return, ControlMask, "\033[13;5u", 0, 0},
+ { XK_Return, ControlMask|ShiftMask, "\033[13;6u", 0, 0},
+ { XK_Return, Mod1Mask, "\033[13;3u", 0, 0},
+ { XK_Return, Mod1Mask|ControlMask, "\033[13;7u", 0, 0},
+ { XK_Return, Mod1Mask|ControlMask|ShiftMask, "\033[13;8u", 0, 0},
+ { XK_Return, Mod1Mask|ShiftMask, "\033[13;4u", 0, 0},
+ { XK_Return, ShiftMask, "\033[13;2u", 0, 0},
+ { XK_Pause, ControlMask, "\033[18;5u", 0, 0},
+ { XK_Pause, ControlMask|ShiftMask, "\033[18;6u", 0, 0},
+ { XK_Pause, Mod1Mask, "\033[18;3u", 0, 0},
+ { XK_Pause, Mod1Mask|ControlMask, "\033[18;7u", 0, 0},
+ { XK_Pause, Mod1Mask|ControlMask|ShiftMask, "\033[18;8u", 0, 0},
+ { XK_Pause, Mod1Mask|ShiftMask, "\033[18;4u", 0, 0},
+ { XK_Pause, ShiftMask, "\033[18;2u", 0, 0},
+ { XK_Scroll_Lock, ControlMask, "\033[20;5u", 0, 0},
+ { XK_Scroll_Lock, ControlMask|ShiftMask, "\033[20;6u", 0, 0},
+ { XK_Scroll_Lock, Mod1Mask, "\033[20;3u", 0, 0},
+ { XK_Scroll_Lock, Mod1Mask|ControlMask, "\033[20;7u", 0, 0},
+ { XK_Scroll_Lock, Mod1Mask|ControlMask|ShiftMask, "\033[20;8u", 0, 0},
+ { XK_Scroll_Lock, Mod1Mask|ShiftMask, "\033[20;4u", 0, 0},
+ { XK_Scroll_Lock, ShiftMask, "\033[20;2u", 0, 0},
+ { XK_Escape, ControlMask, "\033[27;5u", 0, 0},
+ { XK_Escape, ControlMask|ShiftMask, "\033[27;6u", 0, 0},
+ { XK_Escape, Mod1Mask, "\033[27;3u", 0, 0},
+ { XK_Escape, Mod1Mask|ControlMask, "\033[27;7u", 0, 0},
+ { XK_Escape, Mod1Mask|ControlMask|ShiftMask, "\033[27;8u", 0, 0},
+ { XK_Escape, Mod1Mask|ShiftMask, "\033[27;4u", 0, 0},
+ { XK_Escape, ShiftMask, "\033[27;2u", 0, 0},
+ { XK_Home, XK_NO_MOD, "\033[H", 0, -1},
+ { XK_Home, XK_NO_MOD, "\033[1~", 0, +1},
+ { XK_Home, ControlMask|ShiftMask, "\033[80;6u", 0, 0},
+ { XK_Home, Mod1Mask, "\033[80;3u", 0, 0},
+ { XK_Home, Mod1Mask|ControlMask, "\033[80;7u", 0, 0},
+ { XK_Home, Mod1Mask|ControlMask|ShiftMask, "\033[80;8u", 0, 0},
+ { XK_Home, Mod1Mask|ShiftMask, "\033[80;4u", 0, 0},
+ { XK_End, XK_NO_MOD, "\033[4~", 0, 0},
+ { XK_End, ControlMask|ShiftMask, "\033[87;6u", 0, 0},
+ { XK_End, Mod1Mask, "\033[87;3u", 0, 0},
+ { XK_End, Mod1Mask|ControlMask, "\033[87;7u", 0, 0},
+ { XK_End, Mod1Mask|ControlMask|ShiftMask, "\033[87;8u", 0, 0},
+ { XK_End, Mod1Mask|ShiftMask, "\033[87;4u", 0, 0},
+ { XK_Prior, XK_NO_MOD, "\033[5~", 0, 0},
+ { XK_Prior, ControlMask|ShiftMask, "\033[85;6u", 0, 0},
+ { XK_Prior, Mod1Mask, "\033[85;3u", 0, 0},
+ { XK_Prior, Mod1Mask|ControlMask, "\033[85;7u", 0, 0},
+ { XK_Prior, Mod1Mask|ControlMask|ShiftMask, "\033[85;8u", 0, 0},
+ { XK_Prior, Mod1Mask|ShiftMask, "\033[85;4u", 0, 0},
+ { XK_Next, XK_NO_MOD, "\033[6~", 0, 0},
+ { XK_Next, ControlMask|ShiftMask, "\033[86;6u", 0, 0},
+ { XK_Next, Mod1Mask, "\033[86;3u", 0, 0},
+ { XK_Next, Mod1Mask|ControlMask, "\033[86;7u", 0, 0},
+ { XK_Next, Mod1Mask|ControlMask|ShiftMask, "\033[86;8u", 0, 0},
+ { XK_Next, Mod1Mask|ShiftMask, "\033[86;4u", 0, 0},
+ { XK_Print, ControlMask, "\033[97;5u", 0, 0},
+ { XK_Print, ControlMask|ShiftMask, "\033[97;6u", 0, 0},
+ { XK_Print, Mod1Mask, "\033[97;3u", 0, 0},
+ { XK_Print, Mod1Mask|ControlMask, "\033[97;7u", 0, 0},
+ { XK_Print, Mod1Mask|ControlMask|ShiftMask, "\033[97;8u", 0, 0},
+ { XK_Print, Mod1Mask|ShiftMask, "\033[97;4u", 0, 0},
+ { XK_Print, ShiftMask, "\033[97;2u", 0, 0},
+ { XK_Insert, XK_NO_MOD, "\033[4h", -1, 0},
+ { XK_Insert, XK_NO_MOD, "\033[2~", +1, 0},
+ { XK_Insert, ControlMask|ShiftMask, "\033[99;6u", 0, 0},
+ { XK_Insert, Mod1Mask, "\033[99;3u", 0, 0},
+ { XK_Insert, Mod1Mask|ControlMask, "\033[99;7u", 0, 0},
+ { XK_Insert, Mod1Mask|ControlMask|ShiftMask, "\033[99;8u", 0, 0},
+ { XK_Insert, Mod1Mask|ShiftMask, "\033[99;4u", 0, 0},
+ { XK_Menu, ControlMask, "\033[103;5u", 0, 0},
+ { XK_Menu, ControlMask|ShiftMask, "\033[103;6u", 0, 0},
+ { XK_Menu, Mod1Mask, "\033[103;3u", 0, 0},
+ { XK_Menu, Mod1Mask|ControlMask, "\033[103;7u", 0, 0},
+ { XK_Menu, Mod1Mask|ControlMask|ShiftMask, "\033[103;8u", 0, 0},
+ { XK_Menu, Mod1Mask|ShiftMask, "\033[103;4u", 0, 0},
+ { XK_Menu, ShiftMask, "\033[103;2u", 0, 0},
+ { XK_Delete, XK_NO_MOD, "\033[P", -1, 0},
+ { XK_Delete, XK_NO_MOD, "\033[3~", +1, 0},
+ { XK_Delete, ControlMask|ShiftMask, "\033[255;6u", 0, 0},
+ { XK_Delete, Mod1Mask, "\033[255;3u", 0, 0},
+ { XK_Delete, Mod1Mask|ControlMask, "\033[255;7u", 0, 0},
+ { XK_Delete, Mod1Mask|ControlMask|ShiftMask, "\033[255;8u", 0, 0},
+ { XK_Delete, Mod1Mask|ShiftMask, "\033[255;4u", 0, 0},
+ { XK_i, ControlMask, "\033[105;5u", 0, 0},
+ { XK_i, Mod1Mask|ControlMask, "\033[105;7u", 0, 0},
+ { XK_m, ControlMask, "\033[109;5u", 0, 0},
+ { XK_m, Mod1Mask|ControlMask, "\033[109;7u", 0, 0},
+ { XK_space, ControlMask|ShiftMask, "\033[32;6u", 0, 0},
+ { XK_space, Mod1Mask, "\033[32;3u", 0, 0},
+ { XK_space, Mod1Mask|ControlMask, "\033[32;7u", 0, 0},
+ { XK_space, Mod1Mask|ControlMask|ShiftMask, "\033[32;8u", 0, 0},
+ { XK_space, Mod1Mask|ShiftMask, "\033[32;4u", 0, 0},
+ { XK_space, ShiftMask, "\033[32;2u", 0, 0},
+ { XK_0, ControlMask, "\033[48;5u", 0, 0},
+ { XK_A, ControlMask|ShiftMask, "\033[65;6u", 0, 0},
+ { XK_B, ControlMask|ShiftMask, "\033[66;6u", 0, 0},
+ { XK_C, ControlMask|ShiftMask, "\033[67;6u", 0, 0},
+ { XK_D, ControlMask|ShiftMask, "\033[68;6u", 0, 0},
+ { XK_E, ControlMask|ShiftMask, "\033[69;6u", 0, 0},
+ { XK_F, ControlMask|ShiftMask, "\033[70;6u", 0, 0},
+ { XK_G, ControlMask|ShiftMask, "\033[71;6u", 0, 0},
+ { XK_H, ControlMask|ShiftMask, "\033[72;6u", 0, 0},
+ { XK_I, ControlMask|ShiftMask, "\033[73;6u", 0, 0},
+ { XK_I, Mod1Mask|ControlMask|ShiftMask, "\033[73;8u", 0, 0},
+ { XK_J, ControlMask|ShiftMask, "\033[75;6u", 0, 0},
+ { XK_K, ControlMask|ShiftMask, "\033[74;6u", 0, 0},
+ { XK_L, ControlMask|ShiftMask, "\033[76;6u", 0, 0},
+ { XK_M, ControlMask|ShiftMask, "\033[77;6u", 0, 0},
+ { XK_M, Mod1Mask|ControlMask|ShiftMask, "\033[77;8u", 0, 0},
+ { XK_N, ControlMask|ShiftMask, "\033[78;6u", 0, 0},
+ { XK_O, ControlMask|ShiftMask, "\033[79;6u", 0, 0},
+ { XK_P, ControlMask|ShiftMask, "\033[80;6u", 0, 0},
+ { XK_Q, ControlMask|ShiftMask, "\033[81;6u", 0, 0},
+ { XK_R, ControlMask|ShiftMask, "\033[82;6u", 0, 0},
+ { XK_S, ControlMask|ShiftMask, "\033[83;6u", 0, 0},
+ { XK_T, ControlMask|ShiftMask, "\033[84;6u", 0, 0},
+ { XK_U, ControlMask|ShiftMask, "\033[85;6u", 0, 0},
+ { XK_V, ControlMask|ShiftMask, "\033[86;6u", 0, 0},
+ { XK_W, ControlMask|ShiftMask, "\033[87;6u", 0, 0},
+ { XK_X, ControlMask|ShiftMask, "\033[88;6u", 0, 0},
+ { XK_Y, ControlMask|ShiftMask, "\033[89;6u", 0, 0},
+ { XK_Z, ControlMask|ShiftMask, "\033[90;6u", 0, 0},
+ { XK_0, Mod1Mask|ControlMask, "\033[48;7u", 0, 0},
+ { XK_1, ControlMask, "\033[49;5u", 0, 0},
+ { XK_1, Mod1Mask|ControlMask, "\033[49;7u", 0, 0},
+ { XK_2, ControlMask, "\033[50;5u", 0, 0},
+ { XK_2, Mod1Mask|ControlMask, "\033[50;7u", 0, 0},
+ { XK_3, ControlMask, "\033[51;5u", 0, 0},
+ { XK_3, Mod1Mask|ControlMask, "\033[51;7u", 0, 0},
+ { XK_4, ControlMask, "\033[52;5u", 0, 0},
+ { XK_4, Mod1Mask|ControlMask, "\033[52;7u", 0, 0},
+ { XK_5, ControlMask, "\033[53;5u", 0, 0},
+ { XK_5, Mod1Mask|ControlMask, "\033[53;7u", 0, 0},
+ { XK_6, ControlMask, "\033[54;5u", 0, 0},
+ { XK_6, Mod1Mask|ControlMask, "\033[54;7u", 0, 0},
+ { XK_7, ControlMask, "\033[55;5u", 0, 0},
+ { XK_7, Mod1Mask|ControlMask, "\033[55;7u", 0, 0},
+ { XK_8, ControlMask, "\033[56;5u", 0, 0},
+ { XK_8, Mod1Mask|ControlMask, "\033[56;7u", 0, 0},
+ { XK_9, ControlMask, "\033[57;5u", 0, 0},
+ { XK_9, Mod1Mask|ControlMask, "\033[57;7u", 0, 0},
+ { XK_ampersand, ControlMask, "\033[38;5u", 0, 0},
+ { XK_ampersand, ControlMask|ShiftMask, "\033[38;6u", 0, 0},
+ { XK_ampersand, Mod1Mask, "\033[38;3u", 0, 0},
+ { XK_ampersand, Mod1Mask|ControlMask, "\033[38;7u", 0, 0},
+ { XK_ampersand, Mod1Mask|ControlMask|ShiftMask, "\033[38;8u", 0, 0},
+ { XK_ampersand, Mod1Mask|ShiftMask, "\033[38;4u", 0, 0},
+ { XK_apostrophe, ControlMask, "\033[39;5u", 0, 0},
+ { XK_apostrophe, ControlMask|ShiftMask, "\033[39;6u", 0, 0},
+ { XK_apostrophe, Mod1Mask, "\033[39;3u", 0, 0},
+ { XK_apostrophe, Mod1Mask|ControlMask, "\033[39;7u", 0, 0},
+ { XK_apostrophe, Mod1Mask|ControlMask|ShiftMask, "\033[39;8u", 0, 0},
+ { XK_apostrophe, Mod1Mask|ShiftMask, "\033[39;4u", 0, 0},
+ { XK_asciicircum, ControlMask, "\033[94;5u", 0, 0},
+ { XK_asciicircum, ControlMask|ShiftMask, "\033[94;6u", 0, 0},
+ { XK_asciicircum, Mod1Mask, "\033[94;3u", 0, 0},
+ { XK_asciicircum, Mod1Mask|ControlMask, "\033[94;7u", 0, 0},
+ { XK_asciicircum, Mod1Mask|ControlMask|ShiftMask, "\033[94;8u", 0, 0},
+ { XK_asciicircum, Mod1Mask|ShiftMask, "\033[94;4u", 0, 0},
+ { XK_asciitilde, ControlMask, "\033[126;5u", 0, 0},
+ { XK_asciitilde, ControlMask|ShiftMask, "\033[126;6u", 0, 0},
+ { XK_asciitilde, Mod1Mask, "\033[126;3u", 0, 0},
+ { XK_asciitilde, Mod1Mask|ControlMask, "\033[126;7u", 0, 0},
+ { XK_asciitilde, Mod1Mask|ControlMask|ShiftMask, "\033[126;8u", 0, 0},
+ { XK_asciitilde, Mod1Mask|ShiftMask, "\033[126;4u", 0, 0},
+ { XK_asterisk, ControlMask, "\033[42;5u", 0, 0},
+ { XK_asterisk, ControlMask|ShiftMask, "\033[42;6u", 0, 0},
+ { XK_asterisk, Mod1Mask, "\033[42;3u", 0, 0},
+ { XK_asterisk, Mod1Mask|ControlMask, "\033[42;7u", 0, 0},
+ { XK_asterisk, Mod1Mask|ControlMask|ShiftMask, "\033[42;8u", 0, 0},
+ { XK_asterisk, Mod1Mask|ShiftMask, "\033[42;4u", 0, 0},
+ { XK_at, ControlMask, "\033[64;5u", 0, 0},
+ { XK_at, ControlMask|ShiftMask, "\033[64;6u", 0, 0},
+ { XK_at, Mod1Mask, "\033[64;3u", 0, 0},
+ { XK_at, Mod1Mask|ControlMask, "\033[64;7u", 0, 0},
+ { XK_at, Mod1Mask|ControlMask|ShiftMask, "\033[64;8u", 0, 0},
+ { XK_at, Mod1Mask|ShiftMask, "\033[64;4u", 0, 0},
+ { XK_backslash, ControlMask, "\033[92;5u", 0, 0},
+ { XK_backslash, ControlMask|ShiftMask, "\033[92;6u", 0, 0},
+ { XK_backslash, Mod1Mask, "\033[92;3u", 0, 0},
+ { XK_backslash, Mod1Mask|ControlMask, "\033[92;7u", 0, 0},
+ { XK_backslash, Mod1Mask|ControlMask|ShiftMask, "\033[92;8u", 0, 0},
+ { XK_backslash, Mod1Mask|ShiftMask, "\033[92;4u", 0, 0},
+ { XK_bar, ControlMask, "\033[124;5u", 0, 0},
+ { XK_bar, ControlMask|ShiftMask, "\033[124;6u", 0, 0},
+ { XK_bar, Mod1Mask, "\033[124;3u", 0, 0},
+ { XK_bar, Mod1Mask|ControlMask, "\033[124;7u", 0, 0},
+ { XK_bar, Mod1Mask|ControlMask|ShiftMask, "\033[124;8u", 0, 0},
+ { XK_bar, Mod1Mask|ShiftMask, "\033[124;4u", 0, 0},
+ { XK_braceleft, ControlMask, "\033[123;5u", 0, 0},
+ { XK_braceleft, ControlMask|ShiftMask, "\033[123;6u", 0, 0},
+ { XK_braceleft, Mod1Mask, "\033[123;3u", 0, 0},
+ { XK_braceleft, Mod1Mask|ControlMask, "\033[123;7u", 0, 0},
+ { XK_braceleft, Mod1Mask|ControlMask|ShiftMask, "\033[123;8u", 0, 0},
+ { XK_braceleft, Mod1Mask|ShiftMask, "\033[123;4u", 0, 0},
+ { XK_braceright, ControlMask, "\033[125;5u", 0, 0},
+ { XK_braceright, ControlMask|ShiftMask, "\033[125;6u", 0, 0},
+ { XK_braceright, Mod1Mask, "\033[125;3u", 0, 0},
+ { XK_braceright, Mod1Mask|ControlMask, "\033[125;7u", 0, 0},
+ { XK_braceright, Mod1Mask|ControlMask|ShiftMask, "\033[125;8u", 0, 0},
+ { XK_braceright, Mod1Mask|ShiftMask, "\033[125;4u", 0, 0},
+ { XK_bracketleft, ControlMask, "\033[91;5u", 0, 0},
+ { XK_bracketleft, ControlMask|ShiftMask, "\033[91;6u", 0, 0},
+ { XK_bracketleft, Mod1Mask, "\033[91;3u", 0, 0},
+ { XK_bracketleft, Mod1Mask|ControlMask, "\033[91;7u", 0, 0},
+ { XK_bracketleft, Mod1Mask|ControlMask|ShiftMask, "\033[91;8u", 0, 0},
+ { XK_bracketleft, Mod1Mask|ShiftMask, "\033[91;4u", 0, 0},
+ { XK_bracketright, ControlMask, "\033[93;5u", 0, 0},
+ { XK_bracketright, ControlMask|ShiftMask, "\033[93;6u", 0, 0},
+ { XK_bracketright, Mod1Mask, "\033[93;3u", 0, 0},
+ { XK_bracketright, Mod1Mask|ControlMask, "\033[93;7u", 0, 0},
+ { XK_bracketright, Mod1Mask|ControlMask|ShiftMask, "\033[93;8u", 0, 0},
+ { XK_bracketright, Mod1Mask|ShiftMask, "\033[93;4u", 0, 0},
+ { XK_colon, ControlMask, "\033[58;5u", 0, 0},
+ { XK_colon, ControlMask|ShiftMask, "\033[58;6u", 0, 0},
+ { XK_colon, Mod1Mask, "\033[58;3u", 0, 0},
+ { XK_colon, Mod1Mask|ControlMask, "\033[58;7u", 0, 0},
+ { XK_colon, Mod1Mask|ControlMask|ShiftMask, "\033[58;8u", 0, 0},
+ { XK_colon, Mod1Mask|ShiftMask, "\033[58;4u", 0, 0},
+ { XK_comma, ControlMask, "\033[44;5u", 0, 0},
+ { XK_comma, ControlMask|ShiftMask, "\033[44;6u", 0, 0},
+ { XK_comma, Mod1Mask, "\033[44;3u", 0, 0},
+ { XK_comma, Mod1Mask|ControlMask, "\033[44;7u", 0, 0},
+ { XK_comma, Mod1Mask|ControlMask|ShiftMask, "\033[44;8u", 0, 0},
+ { XK_comma, Mod1Mask|ShiftMask, "\033[44;4u", 0, 0},
+ { XK_dollar, ControlMask, "\033[36;5u", 0, 0},
+ { XK_dollar, ControlMask|ShiftMask, "\033[36;6u", 0, 0},
+ { XK_dollar, Mod1Mask, "\033[36;3u", 0, 0},
+ { XK_dollar, Mod1Mask|ControlMask, "\033[36;7u", 0, 0},
+ { XK_dollar, Mod1Mask|ControlMask|ShiftMask, "\033[36;8u", 0, 0},
+ { XK_dollar, Mod1Mask|ShiftMask, "\033[36;4u", 0, 0},
+ { XK_equal, ControlMask, "\033[61;5u", 0, 0},
+ { XK_equal, ControlMask|ShiftMask, "\033[61;6u", 0, 0},
+ { XK_equal, Mod1Mask, "\033[61;3u", 0, 0},
+ { XK_equal, Mod1Mask|ControlMask, "\033[61;7u", 0, 0},
+ { XK_equal, Mod1Mask|ControlMask|ShiftMask, "\033[61;8u", 0, 0},
+ { XK_equal, Mod1Mask|ShiftMask, "\033[61;4u", 0, 0},
+ { XK_exclam, ControlMask, "\033[33;5u", 0, 0},
+ { XK_exclam, ControlMask|ShiftMask, "\033[33;6u", 0, 0},
+ { XK_exclam, Mod1Mask, "\033[33;3u", 0, 0},
+ { XK_exclam, Mod1Mask|ControlMask, "\033[33;7u", 0, 0},
+ { XK_exclam, Mod1Mask|ControlMask|ShiftMask, "\033[33;8u", 0, 0},
+ { XK_exclam, Mod1Mask|ShiftMask, "\033[33;4u", 0, 0},
+ { XK_grave, ControlMask, "\033[96;5u", 0, 0},
+ { XK_grave, ControlMask|ShiftMask, "\033[96;6u", 0, 0},
+ { XK_grave, Mod1Mask, "\033[96;3u", 0, 0},
+ { XK_grave, Mod1Mask|ControlMask, "\033[96;7u", 0, 0},
+ { XK_grave, Mod1Mask|ControlMask|ShiftMask, "\033[96;8u", 0, 0},
+ { XK_grave, Mod1Mask|ShiftMask, "\033[96;4u", 0, 0},
+ { XK_greater, ControlMask, "\033[62;5u", 0, 0},
+ { XK_greater, ControlMask|ShiftMask, "\033[62;6u", 0, 0},
+ { XK_greater, Mod1Mask, "\033[62;3u", 0, 0},
+ { XK_greater, Mod1Mask|ControlMask, "\033[62;7u", 0, 0},
+ { XK_greater, Mod1Mask|ControlMask|ShiftMask, "\033[62;8u", 0, 0},
+ { XK_greater, Mod1Mask|ShiftMask, "\033[62;4u", 0, 0},
+ { XK_less, ControlMask, "\033[60;5u", 0, 0},
+ { XK_less, ControlMask|ShiftMask, "\033[60;6u", 0, 0},
+ { XK_less, Mod1Mask, "\033[60;3u", 0, 0},
+ { XK_less, Mod1Mask|ControlMask, "\033[60;7u", 0, 0},
+ { XK_less, Mod1Mask|ControlMask|ShiftMask, "\033[60;8u", 0, 0},
+ { XK_less, Mod1Mask|ShiftMask, "\033[60;4u", 0, 0},
+ { XK_minus, ControlMask, "\033[45;5u", 0, 0},
+ { XK_minus, ControlMask|ShiftMask, "\033[45;6u", 0, 0},
+ { XK_minus, Mod1Mask, "\033[45;3u", 0, 0},
+ { XK_minus, Mod1Mask|ControlMask, "\033[45;7u", 0, 0},
+ { XK_minus, Mod1Mask|ControlMask|ShiftMask, "\033[45;8u", 0, 0},
+ { XK_minus, Mod1Mask|ShiftMask, "\033[45;4u", 0, 0},
+ { XK_numbersign, ControlMask, "\033[35;5u", 0, 0},
+ { XK_numbersign, ControlMask|ShiftMask, "\033[35;6u", 0, 0},
+ { XK_numbersign, Mod1Mask, "\033[35;3u", 0, 0},
+ { XK_numbersign, Mod1Mask|ControlMask, "\033[35;7u", 0, 0},
+ { XK_numbersign, Mod1Mask|ControlMask|ShiftMask, "\033[35;8u", 0, 0},
+ { XK_numbersign, Mod1Mask|ShiftMask, "\033[35;4u", 0, 0},
+ { XK_parenleft, ControlMask, "\033[40;5u", 0, 0},
+ { XK_parenleft, ControlMask|ShiftMask, "\033[40;6u", 0, 0},
+ { XK_parenleft, Mod1Mask, "\033[40;3u", 0, 0},
+ { XK_parenleft, Mod1Mask|ControlMask, "\033[40;7u", 0, 0},
+ { XK_parenleft, Mod1Mask|ControlMask|ShiftMask, "\033[40;8u", 0, 0},
+ { XK_parenleft, Mod1Mask|ShiftMask, "\033[40;4u", 0, 0},
+ { XK_parenright, ControlMask, "\033[41;5u", 0, 0},
+ { XK_parenright, ControlMask|ShiftMask, "\033[41;6u", 0, 0},
+ { XK_parenright, Mod1Mask, "\033[41;3u", 0, 0},
+ { XK_parenright, Mod1Mask|ControlMask, "\033[41;7u", 0, 0},
+ { XK_parenright, Mod1Mask|ControlMask|ShiftMask, "\033[41;8u", 0, 0},
+ { XK_parenright, Mod1Mask|ShiftMask, "\033[41;4u", 0, 0},
+ { XK_percent, ControlMask, "\033[37;5u", 0, 0},
+ { XK_percent, ControlMask|ShiftMask, "\033[37;6u", 0, 0},
+ { XK_percent, Mod1Mask, "\033[37;3u", 0, 0},
+ { XK_percent, Mod1Mask|ControlMask, "\033[37;7u", 0, 0},
+ { XK_percent, Mod1Mask|ControlMask|ShiftMask, "\033[37;8u", 0, 0},
+ { XK_percent, Mod1Mask|ShiftMask, "\033[37;4u", 0, 0},
+ { XK_period, ControlMask, "\033[46;5u", 0, 0},
+ { XK_period, ControlMask|ShiftMask, "\033[46;6u", 0, 0},
+ { XK_period, Mod1Mask|ControlMask, "\033[46;7u", 0, 0},
+ { XK_period, Mod1Mask|ControlMask|ShiftMask, "\033[46;8u", 0, 0},
+ { XK_period, Mod1Mask|ShiftMask, "\033[46;4u", 0, 0},
+ { XK_plus, ControlMask, "\033[43;5u", 0, 0},
+ { XK_plus, ControlMask|ShiftMask, "\033[43;6u", 0, 0},
+ { XK_plus, Mod1Mask, "\033[43;3u", 0, 0},
+ { XK_plus, Mod1Mask|ControlMask, "\033[43;7u", 0, 0},
+ { XK_plus, Mod1Mask|ControlMask|ShiftMask, "\033[43;8u", 0, 0},
+ { XK_plus, Mod1Mask|ShiftMask, "\033[43;4u", 0, 0},
+ { XK_question, ControlMask, "\033[63;5u", 0, 0},
+ { XK_question, ControlMask|ShiftMask, "\033[63;6u", 0, 0},
+ { XK_question, Mod1Mask, "\033[63;3u", 0, 0},
+ { XK_question, Mod1Mask|ControlMask, "\033[63;7u", 0, 0},
+ { XK_question, Mod1Mask|ControlMask|ShiftMask, "\033[63;8u", 0, 0},
+ { XK_question, Mod1Mask|ShiftMask, "\033[63;4u", 0, 0},
+ { XK_quotedbl, ControlMask, "\033[34;5u", 0, 0},
+ { XK_quotedbl, ControlMask|ShiftMask, "\033[34;6u", 0, 0},
+ { XK_quotedbl, Mod1Mask, "\033[34;3u", 0, 0},
+ { XK_quotedbl, Mod1Mask|ControlMask, "\033[34;7u", 0, 0},
+ { XK_quotedbl, Mod1Mask|ControlMask|ShiftMask, "\033[34;8u", 0, 0},
+ { XK_quotedbl, Mod1Mask|ShiftMask, "\033[34;4u", 0, 0},
+ { XK_semicolon, ControlMask, "\033[59;5u", 0, 0},
+ { XK_semicolon, ControlMask|ShiftMask, "\033[59;6u", 0, 0},
+ { XK_semicolon, Mod1Mask, "\033[59;3u", 0, 0},
+ { XK_semicolon, Mod1Mask|ControlMask, "\033[59;7u", 0, 0},
+ { XK_semicolon, Mod1Mask|ControlMask|ShiftMask, "\033[59;8u", 0, 0},
+ { XK_semicolon, Mod1Mask|ShiftMask, "\033[59;4u", 0, 0},
+ { XK_slash, ControlMask|ShiftMask, "\033[47;6u", 0, 0},
+ { XK_slash, Mod1Mask, "\033[47;3u", 0, 0},
+ { XK_slash, Mod1Mask|ControlMask, "\033[47;7u", 0, 0},
+ { XK_slash, Mod1Mask|ControlMask|ShiftMask, "\033[47;8u", 0, 0},
+ { XK_slash, Mod1Mask|ShiftMask, "\033[47;4u", 0, 0},
+ { XK_underscore, ControlMask, "\033[95;5u", 0, 0},
+ { XK_underscore, ControlMask|ShiftMask, "\033[95;6u", 0, 0},
+ { XK_underscore, Mod1Mask, "\033[95;3u", 0, 0},
+ { XK_underscore, Mod1Mask|ControlMask, "\033[95;7u", 0, 0},
+ { XK_underscore, Mod1Mask|ControlMask|ShiftMask, "\033[95;8u", 0, 0},
+ { XK_underscore, Mod1Mask|ShiftMask, "\033[95;4u", 0, 0},
+};
+\ No newline at end of file
diff --git a/patch/font2.c b/patch/font2.c
@@ -0,0 +1,104 @@
+int
+xloadsparefont(FcPattern *pattern, int flags)
+{
+ FcPattern *match;
+ FcResult result;
+
+ #if USE_XFTFONTMATCH_PATCH
+ match = XftFontMatch(xw.dpy, xw.scr, pattern, &result);
+ #else
+ match = FcFontMatch(NULL, pattern, &result);
+ #endif // USE_XFTFONTMATCH_PATCH
+ if (!match) {
+ return 1;
+ }
+
+ if (!(frc[frclen].font = XftFontOpenPattern(xw.dpy, match))) {
+ FcPatternDestroy(match);
+ return 1;
+ }
+
+ frc[frclen].flags = flags;
+ /* Believe U+0000 glyph will present in each default font */
+ frc[frclen].unicodep = 0;
+ frclen++;
+
+ return 0;
+}
+
+void
+xloadsparefonts(void)
+{
+ FcPattern *pattern;
+ double fontval;
+ int fc;
+ char **fp;
+
+ if (frclen != 0)
+ die("can't embed spare fonts. cache isn't empty");
+
+ /* Calculate count of spare fonts */
+ fc = sizeof(font2) / sizeof(*font2);
+ if (fc == 0)
+ return;
+
+ /* Allocate memory for cache entries. */
+ if (frccap < 4 * fc) {
+ frccap += 4 * fc - frccap;
+ frc = xrealloc(frc, frccap * sizeof(Fontcache));
+ }
+
+ for (fp = font2; fp - font2 < fc; ++fp) {
+
+ if (**fp == '-')
+ pattern = XftXlfdParse(*fp, False, False);
+ else
+ pattern = FcNameParse((FcChar8 *)*fp);
+
+ if (!pattern)
+ die("can't open spare font %s\n", *fp);
+
+ if (defaultfontsize > 0 && defaultfontsize != usedfontsize) {
+ if (FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &fontval) ==
+ FcResultMatch) {
+ fontval *= usedfontsize / defaultfontsize;
+ FcPatternDel(pattern, FC_PIXEL_SIZE);
+ FcPatternDel(pattern, FC_SIZE);
+ FcPatternAddDouble(pattern, FC_PIXEL_SIZE, fontval);
+ } else if (FcPatternGetDouble(pattern, FC_SIZE, 0, &fontval) ==
+ FcResultMatch) {
+ fontval *= usedfontsize / defaultfontsize;
+ FcPatternDel(pattern, FC_PIXEL_SIZE);
+ FcPatternDel(pattern, FC_SIZE);
+ FcPatternAddDouble(pattern, FC_SIZE, fontval);
+ }
+ }
+
+ FcPatternAddBool(pattern, FC_SCALABLE, 1);
+
+ #if !USE_XFTFONTMATCH_PATCH
+ FcConfigSubstitute(NULL, pattern, FcMatchPattern);
+ XftDefaultSubstitute(xw.dpy, xw.scr, pattern);
+ #endif // USE_XFTFONTMATCH_PATCH
+
+ if (xloadsparefont(pattern, FRC_NORMAL))
+ die("can't open spare font %s\n", *fp);
+
+ FcPatternDel(pattern, FC_SLANT);
+ FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
+ if (xloadsparefont(pattern, FRC_ITALIC))
+ die("can't open spare font %s\n", *fp);
+
+ FcPatternDel(pattern, FC_WEIGHT);
+ FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
+ if (xloadsparefont(pattern, FRC_ITALICBOLD))
+ die("can't open spare font %s\n", *fp);
+
+ FcPatternDel(pattern, FC_SLANT);
+ FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN);
+ if (xloadsparefont(pattern, FRC_BOLD))
+ die("can't open spare font %s\n", *fp);
+
+ FcPatternDestroy(pattern);
+ }
+}
+\ No newline at end of file
diff --git a/patch/font2.h b/patch/font2.h
@@ -0,0 +1,2 @@
+static int xloadsparefont(FcPattern *, int);
+static void xloadsparefonts(void);
+\ No newline at end of file
diff --git a/patch/fullscreen_x.c b/patch/fullscreen_x.c
@@ -0,0 +1,17 @@
+void
+fullscreen(const Arg *arg)
+{
+ XEvent ev;
+
+ memset(&ev, 0, sizeof(ev));
+
+ ev.xclient.type = ClientMessage;
+ ev.xclient.message_type = xw.netwmstate;
+ ev.xclient.display = xw.dpy;
+ ev.xclient.window = xw.win;
+ ev.xclient.format = 32;
+ ev.xclient.data.l[0] = 2; /* _NET_WM_STATE_TOGGLE */
+ ev.xclient.data.l[1] = xw.netwmfullscreen;
+
+ XSendEvent(xw.dpy, DefaultRootWindow(xw.dpy), False, SubstructureNotifyMask|SubstructureRedirectMask, &ev);
+}
diff --git a/patch/fullscreen_x.h b/patch/fullscreen_x.h
@@ -0,0 +1 @@
+static void fullscreen(const Arg *arg);
diff --git a/patch/invert.c b/patch/invert.c
@@ -0,0 +1,21 @@
+static int invertcolors = 0;
+
+void
+invert(const Arg *dummy)
+{
+ invertcolors = !invertcolors;
+ redraw();
+}
+
+Color
+invertedcolor(Color *clr)
+{
+ XRenderColor rc;
+ Color inverted;
+ rc.red = ~clr->color.red;
+ rc.green = ~clr->color.green;
+ rc.blue = ~clr->color.blue;
+ rc.alpha = clr->color.alpha;
+ XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &rc, &inverted);
+ return inverted;
+}
+\ No newline at end of file
diff --git a/patch/invert.h b/patch/invert.h
@@ -0,0 +1 @@
+static void invert(const Arg *);
+\ No newline at end of file
diff --git a/patch/iso14755.c b/patch/iso14755.c
@@ -0,0 +1,21 @@
+void
+iso14755(const Arg *arg)
+{
+ FILE *p;
+ char *us, *e, codepoint[9], uc[UTF_SIZ];
+ unsigned long utf32;
+
+ if (!(p = popen(ISO14755CMD, "r")))
+ return;
+
+ us = fgets(codepoint, sizeof(codepoint), p);
+ pclose(p);
+
+ if (!us || *us == '\0' || *us == '-' || strlen(us) > 7)
+ return;
+ if ((utf32 = strtoul(us, &e, 16)) == ULONG_MAX ||
+ (*e != '\n' && *e != '\0'))
+ return;
+
+ ttywrite(uc, utf8encode(utf32, uc), 1);
+}
+\ No newline at end of file
diff --git a/patch/iso14755.h b/patch/iso14755.h
@@ -0,0 +1,6 @@
+#define NUMMAXLEN(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1)
+
+/* constants */
+#define ISO14755CMD "dmenu -w \"$WINDOWID\" -p codepoint: </dev/null"
+
+void iso14755(const Arg *);
+\ No newline at end of file
diff --git a/patch/keyboardselect_reflow.txt b/patch/keyboardselect_reflow.txt
@@ -0,0 +1,29 @@
+Shortcuts in keyboard selection mode:
+
+h, j, k, l: move cursor left/down/up/right (also with arrow keys)
+H, M, L: move cursor to the top/middle/bottom of the screen
+Home, End: move cursor to the top/bottom of the screen
+Backspace or 0, $ or A: move cursor to the beginning/end of the line
+^ or I: move cursor to the beginning of the indented line
+!: move cursor to the middle of the row
+_: move cursor to the right edge of the screen
+*: move cursor to the center of the screen
+w, W jump forward to the start of a word
+e, E jump forward to the end of a word
+b, B jump backward to the start of a word
+g, G: go to the first/last line
+z: center the screen on the cursor
+PgUp or K, PgDown or J: scroll the page up/down
+/, ?: activate input mode and search up/down
+n, N: repeat last search and search forward/backward
+f, F: jump forward/backward to the given character
+t, T: jump forward/backward to before the given character
+; or r repeat previous f, t, F or T movement and move forward
+, or R repeat previous f, t, F or T movement and move backward
+v: toggle selection mode
+V: toggle line selection mode
+s: toggle regular/rectangular selection type
+y: yank (copy) selected text
+0 - 9: set the quantifier
+Return: quit keyboard_select, yank and keep the highlight of the selection
+Escape, q: quit keyboard_select/exit input mode/exit selection mode/reset quantifier
diff --git a/patch/keyboardselect_reflow_st.c b/patch/keyboardselect_reflow_st.c
@@ -0,0 +1,769 @@
+#include <wctype.h>
+
+enum keyboardselect_mode {
+ KBDS_MODE_MOVE = 0,
+ KBDS_MODE_SELECT = 1<<1,
+ KBDS_MODE_LSELECT = 1<<2,
+ KBDS_MODE_FIND = 1<<3,
+ KBDS_MODE_SEARCH = 1<<4,
+};
+
+enum cursor_wrap {
+ KBDS_WRAP_NONE = 0,
+ KBDS_WRAP_LINE = 1<<0,
+ KBDS_WRAP_EDGE = 1<<1,
+};
+
+typedef struct {
+ int x;
+ int y;
+ Line line;
+ int len;
+} KCursor;
+
+static int kbds_in_use, kbds_quant;
+static int kbds_seltype = SEL_REGULAR;
+static int kbds_mode, kbds_directsearch;
+static int kbds_searchlen, kbds_searchdir, kbds_searchcase;
+static int kbds_finddir, kbds_findtill;
+static Glyph *kbds_searchstr;
+static Rune kbds_findchar;
+static KCursor kbds_c, kbds_oc;
+
+void
+kbds_drawstatusbar(int y)
+{
+ static char *modes[] = { " MOVE ", "", " SELECT ", " RSELECT ", " LSELECT ",
+ " SEARCH FW ", " SEARCH BW ", " FIND FW ", " FIND BW " };
+ static char quant[20] = { ' ' };
+ static Glyph g;
+ int i, n, m;
+ int mlen, qlen;
+
+ if (!kbds_in_use)
+ return;
+
+ g.mode = ATTR_REVERSE;
+ g.fg = defaultfg;
+ g.bg = defaultbg;
+
+ if (y == 0) {
+ if (kbds_issearchmode())
+ m = 5 + (kbds_searchdir < 0 ? 1 : 0);
+ else if (kbds_mode & KBDS_MODE_FIND)
+ m = 7 + (kbds_finddir < 0 ? 1 : 0);
+ else if (kbds_mode & KBDS_MODE_SELECT)
+ m = 2 + (kbds_seltype == SEL_RECTANGULAR ? 1 : 0);
+ else
+ m = kbds_mode;
+ mlen = strlen(modes[m]);
+ qlen = kbds_quant ? snprintf(quant+1, sizeof quant-1, "%i", kbds_quant) + 1 : 0;
+ if (kbds_c.y != y || kbds_c.x < term.col - qlen - mlen) {
+ for (n = mlen, i = term.col-1; i >= 0 && n > 0; i--) {
+ g.u = modes[m][--n];
+ xdrawglyph(g, i, y);
+ }
+ for (n = qlen; i >= 0 && n > 0; i--) {
+ g.u = quant[--n];
+ xdrawglyph(g, i, y);
+ }
+ }
+ }
+
+ if (y == term.row-1 && kbds_issearchmode()) {
+ for (g.u = ' ', i = 0; i < term.col; i++)
+ xdrawglyph(g, i, y);
+ g.u = (kbds_searchdir > 0) ? '/' : '?';
+ xdrawglyph(g, 0, y);
+ for (i = 0; i < kbds_searchlen; i++) {
+ g.u = kbds_searchstr[i].u;
+ g.mode = kbds_searchstr[i].mode | ATTR_WIDE | ATTR_REVERSE;
+ if (g.u == ' ' || g.mode & ATTR_WDUMMY)
+ continue;
+ xdrawglyph(g, i + 1, y);
+ }
+ g.u = ' ';
+ g.mode = ATTR_NULL;
+ xdrawglyph(g, i + 1, y);
+ }
+}
+
+void
+kbds_pasteintosearch(const char *data, int len, int append)
+{
+ static char buf[BUFSIZ];
+ static int buflen;
+ Rune u;
+ int l, n, charsize;
+
+ if (!append)
+ buflen = 0;
+
+ for (; len > 0; len -= l, data += l) {
+ l = MIN(sizeof(buf) - buflen, len);
+ memmove(buf + buflen, data, l);
+ buflen += l;
+ for (n = 0; n < buflen; n += charsize) {
+ if (IS_SET(MODE_UTF8)) {
+ /* process a complete utf8 char */
+ charsize = utf8decode(buf + n, &u, buflen - n);
+ if (charsize == 0)
+ break;
+ } else {
+ u = buf[n] & 0xFF;
+ charsize = 1;
+ }
+ if (u > 0x1f && kbds_searchlen < term.col-2) {
+ kbds_searchstr[kbds_searchlen].u = u;
+ kbds_searchstr[kbds_searchlen++].mode = ATTR_NULL;
+ if (wcwidth(u) > 1) {
+ kbds_searchstr[kbds_searchlen-1].mode = ATTR_WIDE;
+ if (kbds_searchlen < term.col-2) {
+ kbds_searchstr[kbds_searchlen].u = 0;
+ kbds_searchstr[kbds_searchlen++].mode = ATTR_WDUMMY;
+ }
+ }
+ }
+ }
+ buflen -= n;
+ /* keep any incomplete UTF-8 byte sequence for the next call */
+ if (buflen > 0)
+ memmove(buf, buf + n, buflen);
+ }
+ term.dirty[term.row-1] = 1;
+}
+
+int
+kbds_top(void)
+{
+ return IS_SET(MODE_ALTSCREEN) ? 0 : -term.histf + term.scr;
+}
+
+int
+kbds_bot(void)
+{
+ return IS_SET(MODE_ALTSCREEN) ? term.row-1 : term.row-1 + term.scr;
+}
+
+int
+kbds_iswrapped(KCursor *c)
+{
+ return c->len > 0 && (c->line[c->len-1].mode & ATTR_WRAP);
+}
+
+int
+kbds_isselectmode(void)
+{
+ return kbds_in_use && (kbds_mode & (KBDS_MODE_SELECT | KBDS_MODE_LSELECT));
+}
+
+int
+kbds_issearchmode(void)
+{
+ return kbds_in_use && (kbds_mode & KBDS_MODE_SEARCH);
+}
+
+void
+kbds_setmode(int mode)
+{
+ kbds_mode = mode;
+ term.dirty[0] = 1;
+}
+
+void
+kbds_selecttext(void)
+{
+ if (kbds_isselectmode()) {
+ if (kbds_mode & KBDS_MODE_LSELECT)
+ selextend(term.col-1, kbds_c.y, SEL_RECTANGULAR, 0);
+ else
+ selextend(kbds_c.x, kbds_c.y, kbds_seltype, 0);
+ if (sel.mode == SEL_IDLE)
+ kbds_setmode(kbds_mode & ~(KBDS_MODE_SELECT | KBDS_MODE_LSELECT));
+ }
+}
+
+void
+kbds_copytoclipboard(void)
+{
+ if (kbds_mode & KBDS_MODE_LSELECT) {
+ selextend(term.col-1, kbds_c.y, SEL_RECTANGULAR, 1);
+ sel.type = SEL_REGULAR;
+ } else {
+ selextend(kbds_c.x, kbds_c.y, kbds_seltype, 1);
+ }
+ xsetsel(getsel());
+
+ #if !CLIPBOARD_PATCH
+ xclipcopy();
+ #endif // CLIPBOARD_PATCH
+}
+
+void
+kbds_clearhighlights(void)
+{
+ int x, y;
+ Line line;
+
+ for (y = (IS_SET(MODE_ALTSCREEN) ? 0 : -term.histf); y < term.row; y++) {
+ line = TLINEABS(y);
+ for (x = 0; x < term.col; x++)
+ line[x].mode &= ~ATTR_HIGHLIGHT;
+ }
+ tfulldirt();
+}
+
+int
+kbds_moveto(int x, int y)
+{
+ if (y < 0)
+ kscrollup(&((Arg){ .i = -y }));
+ else if (y >= term.row)
+ kscrolldown(&((Arg){ .i = y - term.row + 1 }));
+ kbds_c.x = (x < 0) ? 0 : (x > term.col-1) ? term.col-1 : x;
+ kbds_c.y = (y < 0) ? 0 : (y > term.row-1) ? term.row-1 : y;
+ kbds_c.line = TLINE(kbds_c.y);
+ kbds_c.len = tlinelen(kbds_c.line);
+ if (kbds_c.x > 0 && (kbds_c.line[kbds_c.x].mode & ATTR_WDUMMY))
+ kbds_c.x--;
+}
+
+int
+kbds_moveforward(KCursor *c, int dx, int wrap)
+{
+ KCursor n = *c;
+
+ n.x += dx;
+ if (n.x >= 0 && n.x < term.col && (n.line[n.x].mode & ATTR_WDUMMY))
+ n.x += dx;
+
+ if (n.x < 0) {
+ if (!wrap || --n.y < kbds_top())
+ return 0;
+ n.line = TLINE(n.y);
+ n.len = tlinelen(n.line);
+ if ((wrap & KBDS_WRAP_LINE) && kbds_iswrapped(&n))
+ n.x = n.len-1;
+ else if (wrap & KBDS_WRAP_EDGE)
+ n.x = term.col-1;
+ else
+ return 0;
+ n.x -= (n.x > 0 && (n.line[n.x].mode & ATTR_WDUMMY)) ? 1 : 0;
+ } else if (n.x >= term.col) {
+ if (((wrap & KBDS_WRAP_EDGE) ||
+ ((wrap & KBDS_WRAP_LINE) && kbds_iswrapped(&n))) && ++n.y <= kbds_bot()) {
+ n.line = TLINE(n.y);
+ n.len = tlinelen(n.line);
+ n.x = 0;
+ } else {
+ return 0;
+ }
+ } else if (n.x >= n.len && dx > 0 && (wrap & KBDS_WRAP_LINE)) {
+ if (n.x == n.len && kbds_iswrapped(&n) && n.y < kbds_bot()) {
+ ++n.y;
+ n.line = TLINE(n.y);
+ n.len = tlinelen(n.line);
+ n.x = 0;
+ } else if (!(wrap & KBDS_WRAP_EDGE)) {
+ return 0;
+ }
+ }
+ *c = n;
+ return 1;
+}
+
+int
+kbds_ismatch(KCursor c)
+{
+ KCursor m = c;
+ int i, next;
+
+ if (c.x + kbds_searchlen > c.len && (!kbds_iswrapped(&c) || c.y >= kbds_bot()))
+ return 0;
+
+ for (next = 0, i = 0; i < kbds_searchlen; i++) {
+ if (kbds_searchstr[i].mode & ATTR_WDUMMY)
+ continue;
+ if ((next++ && !kbds_moveforward(&c, 1, KBDS_WRAP_LINE)) ||
+ (kbds_searchcase && kbds_searchstr[i].u != c.line[c.x].u) ||
+ (!kbds_searchcase && kbds_searchstr[i].u != towlower(c.line[c.x].u)))
+ return 0;
+ }
+
+ for (i = 0; i < kbds_searchlen; i++) {
+ if (!(kbds_searchstr[i].mode & ATTR_WDUMMY)) {
+ m.line[m.x].mode |= ATTR_HIGHLIGHT;
+ kbds_moveforward(&m, 1, KBDS_WRAP_LINE);
+ }
+ }
+ return 1;
+}
+
+int
+kbds_searchall(void)
+{
+ KCursor c;
+ int count = 0;
+
+ if (!kbds_searchlen)
+ return 0;
+
+ for (c.y = kbds_top(); c.y <= kbds_bot(); c.y++) {
+ c.line = TLINE(c.y);
+ c.len = tlinelen(c.line);
+ for (c.x = 0; c.x < c.len; c.x++)
+ count += kbds_ismatch(c);
+ }
+ tfulldirt();
+
+ return count;
+}
+
+void
+kbds_searchnext(int dir)
+{
+ KCursor c = kbds_c, n = kbds_c;
+ int wrapped = 0;
+
+ if (!kbds_searchlen) {
+ kbds_quant = 0;
+ return;
+ }
+
+ if (dir < 0 && c.x > c.len)
+ c.x = c.len;
+
+ for (kbds_quant = MAX(kbds_quant, 1); kbds_quant > 0;) {
+ if (!kbds_moveforward(&c, dir, KBDS_WRAP_LINE)) {
+ c.y += dir;
+ if (c.y < kbds_top())
+ c.y = kbds_bot(), wrapped++;
+ else if (c.y > kbds_bot())
+ c.y = kbds_top(), wrapped++;
+ if (wrapped > 1)
+ break;;
+ c.line = TLINE(c.y);
+ c.len = tlinelen(c.line);
+ c.x = (dir < 0 && c.len > 0) ? c.len-1 : 0;
+ c.x -= (c.x > 0 && (c.line[c.x].mode & ATTR_WDUMMY)) ? 1 : 0;
+ }
+ if (kbds_ismatch(c)) {
+ n = c;
+ kbds_quant--;
+ }
+ }
+
+ kbds_moveto(n.x, n.y);
+ kbds_quant = 0;
+}
+
+void
+kbds_findnext(int dir, int repeat)
+{
+ KCursor prev, c = kbds_c, n = kbds_c;
+ int skipfirst, yoff = 0;
+
+ if (c.len <= 0 || kbds_findchar == 0) {
+ kbds_quant = 0;
+ return;
+ }
+
+ if (dir < 0 && c.x > c.len)
+ c.x = c.len;
+
+ kbds_quant = MAX(kbds_quant, 1);
+ skipfirst = (kbds_quant == 1 && repeat && kbds_findtill);
+
+ while (kbds_quant > 0) {
+ prev = c;
+ if (!kbds_moveforward(&c, dir, KBDS_WRAP_LINE))
+ break;
+ if (c.line[c.x].u == kbds_findchar) {
+ if (skipfirst && prev.x == kbds_c.x && prev.y == kbds_c.y) {
+ skipfirst = 0;
+ continue;
+ }
+ n.x = kbds_findtill ? prev.x : c.x;
+ n.y = c.y;
+ yoff = kbds_findtill ? prev.y - c.y : 0;
+ kbds_quant--;
+ }
+ }
+
+ kbds_moveto(n.x, n.y);
+ kbds_moveto(kbds_c.x, kbds_c.y + yoff);
+ kbds_quant = 0;
+}
+
+int
+kbds_isdelim(KCursor c, int xoff, wchar_t *delims)
+{
+ if (xoff && !kbds_moveforward(&c, xoff, KBDS_WRAP_LINE))
+ return 1;
+ return wcschr(delims, c.line[c.x].u) != NULL;
+}
+
+void
+kbds_nextword(int start, int dir, wchar_t *delims)
+{
+ KCursor c = kbds_c, n = kbds_c;
+ int xoff = start ? -1 : 1;
+
+ if (dir < 0 && c.x > c.len)
+ c.x = c.len;
+ else if (dir > 0 && c.x >= c.len && c.len > 0)
+ c.x = c.len-1;
+
+ for (kbds_quant = MAX(kbds_quant, 1); kbds_quant > 0;) {
+ if (!kbds_moveforward(&c, dir, KBDS_WRAP_LINE)) {
+ c.y += dir;
+ if (c.y < kbds_top() || c.y > kbds_bot())
+ break;
+ c.line = TLINE(c.y);
+ c.len = tlinelen(c.line);
+ c.x = (dir < 0 && c.len > 0) ? c.len-1 : 0;
+ c.x -= (c.x > 0 && (c.line[c.x].mode & ATTR_WDUMMY)) ? 1 : 0;
+ }
+ if (c.len > 0 &&
+ !kbds_isdelim(c, 0, delims) && kbds_isdelim(c, xoff, delims)) {
+ n = c;
+ kbds_quant--;
+ }
+ }
+
+ kbds_moveto(n.x, n.y);
+ kbds_quant = 0;
+}
+
+int
+kbds_drawcursor(void)
+{
+ if (kbds_in_use && (!kbds_issearchmode() || kbds_c.y != term.row-1)) {
+ #if LIGATURES_PATCH
+ xdrawcursor(kbds_c.x, kbds_c.y, TLINE(kbds_c.y)[kbds_c.x],
+ kbds_oc.x, kbds_oc.y, TLINE(kbds_oc.y)[kbds_oc.x],
+ TLINE(kbds_oc.y), term.col);
+ #else
+ xdrawcursor(kbds_c.x, kbds_c.y, TLINE(kbds_c.y)[kbds_c.x],
+ kbds_oc.x, kbds_oc.y, TLINE(kbds_oc.y)[kbds_oc.x]);
+ #endif // LIGATURES_PATCH
+ kbds_moveto(kbds_c.x, kbds_c.y);
+ kbds_oc = kbds_c;
+ }
+ return term.scr != 0 || kbds_in_use;
+}
+
+int
+kbds_keyboardhandler(KeySym ksym, char *buf, int len, int forcequit)
+{
+ int i, q, dy, eol, islast, prevscr, count, wrap;
+ int alt = IS_SET(MODE_ALTSCREEN);
+ Line line;
+ Rune u;
+
+ if (kbds_issearchmode() && !forcequit) {
+ switch (ksym) {
+ case XK_Escape:
+ kbds_searchlen = 0;
+ /* FALLTHROUGH */
+ case XK_Return:
+ for (kbds_searchcase = 0, i = 0; i < kbds_searchlen; i++) {
+ if (kbds_searchstr[i].u != towlower(kbds_searchstr[i].u)) {
+ kbds_searchcase = 1;
+ break;
+ }
+ }
+ count = kbds_searchall();
+ kbds_searchnext(kbds_searchdir);
+ kbds_selecttext();
+ kbds_setmode(kbds_mode & ~KBDS_MODE_SEARCH);
+ if (count == 0 && kbds_directsearch)
+ ksym = XK_Escape;
+ break;
+ case XK_BackSpace:
+ if (kbds_searchlen) {
+ kbds_searchlen--;
+ if (kbds_searchlen && (kbds_searchstr[kbds_searchlen].mode & ATTR_WDUMMY))
+ kbds_searchlen--;
+ }
+ break;
+ default:
+ if (len < 1 || kbds_searchlen >= term.col-2)
+ return 0;
+ utf8decode(buf, &u, len);
+ kbds_searchstr[kbds_searchlen].u = u;
+ kbds_searchstr[kbds_searchlen++].mode = ATTR_NULL;
+ if (wcwidth(u) > 1) {
+ kbds_searchstr[kbds_searchlen-1].mode = ATTR_WIDE;
+ if (kbds_searchlen < term.col-2) {
+ kbds_searchstr[kbds_searchlen].u = 0;
+ kbds_searchstr[kbds_searchlen++].mode = ATTR_WDUMMY;
+ }
+ }
+ break;
+ }
+ /* If the direct search is aborted, we just go to the next switch
+ * statement and exit the keyboard selection mode immediately */
+ if (!(ksym == XK_Escape && kbds_directsearch)) {
+ term.dirty[term.row-1] = 1;
+ return 0;
+ }
+ } else if ((kbds_mode & KBDS_MODE_FIND) && !forcequit) {
+ kbds_findchar = 0;
+ switch (ksym) {
+ case XK_Escape:
+ case XK_Return:
+ kbds_quant = 0;
+ break;
+ default:
+ if (len < 1)
+ return 0;
+ utf8decode(buf, &kbds_findchar, len);
+ kbds_findnext(kbds_finddir, 0);
+ kbds_selecttext();
+ break;
+ }
+ kbds_setmode(kbds_mode & ~KBDS_MODE_FIND);
+ return 0;
+ }
+
+ switch (ksym) {
+ case -1:
+ kbds_searchstr = xmalloc(term.col * sizeof(Glyph));
+ kbds_in_use = 1;
+ kbds_moveto(term.c.x, term.c.y);
+ kbds_oc = kbds_c;
+ kbds_setmode(KBDS_MODE_MOVE);
+ return MODE_KBDSELECT;
+ case XK_V:
+ if (kbds_mode & KBDS_MODE_LSELECT) {
+ selclear();
+ kbds_setmode(kbds_mode & ~(KBDS_MODE_SELECT | KBDS_MODE_LSELECT));
+ } else if (kbds_mode & KBDS_MODE_SELECT) {
+ selextend(term.col-1, kbds_c.y, SEL_RECTANGULAR, 0);
+ sel.ob.x = 0;
+ tfulldirt();
+ kbds_setmode((kbds_mode ^ KBDS_MODE_SELECT) | KBDS_MODE_LSELECT);
+ } else {
+ selstart(0, kbds_c.y, 0);
+ selextend(term.col-1, kbds_c.y, SEL_RECTANGULAR, 0);
+ kbds_setmode(kbds_mode | KBDS_MODE_LSELECT);
+ }
+ break;
+ case XK_v:
+ if (kbds_mode & KBDS_MODE_SELECT) {
+ selclear();
+ kbds_setmode(kbds_mode & ~(KBDS_MODE_SELECT | KBDS_MODE_LSELECT));
+ } else if (kbds_mode & KBDS_MODE_LSELECT) {
+ selextend(kbds_c.x, kbds_c.y, kbds_seltype, 0);
+ kbds_setmode((kbds_mode ^ KBDS_MODE_LSELECT) | KBDS_MODE_SELECT);
+ } else {
+ selstart(kbds_c.x, kbds_c.y, 0);
+ kbds_setmode(kbds_mode | KBDS_MODE_SELECT);
+ }
+ break;
+ case XK_s:
+ if (!(kbds_mode & KBDS_MODE_LSELECT)) {
+ kbds_seltype ^= (SEL_REGULAR | SEL_RECTANGULAR);
+ selextend(kbds_c.x, kbds_c.y, kbds_seltype, 0);
+ }
+ break;
+ case XK_y:
+ case XK_Y:
+ if (kbds_isselectmode()) {
+ kbds_copytoclipboard();
+ selclear();
+ kbds_setmode(kbds_mode & ~(KBDS_MODE_SELECT | KBDS_MODE_LSELECT));
+ }
+ break;
+ case -2:
+ case -3:
+ case XK_slash:
+ case XK_KP_Divide:
+ case XK_question:
+ kbds_directsearch = (ksym == -2 || ksym == -3);
+ kbds_searchdir = (ksym == XK_question || ksym == -3) ? -1 : 1;
+ kbds_searchlen = 0;
+ kbds_setmode(kbds_mode | KBDS_MODE_SEARCH);
+ kbds_clearhighlights();
+ return 0;
+ case XK_q:
+ case XK_Escape:
+ if (!kbds_in_use)
+ return 0;
+ if (kbds_quant && !forcequit) {
+ kbds_quant = 0;
+ break;
+ }
+ selclear();
+ if (kbds_isselectmode() && !forcequit) {
+ kbds_setmode(KBDS_MODE_MOVE);
+ break;
+ }
+ kbds_setmode(KBDS_MODE_MOVE);
+ /* FALLTHROUGH */
+ case XK_Return:
+ if (kbds_isselectmode())
+ kbds_copytoclipboard();
+ kbds_in_use = kbds_quant = 0;
+ free(kbds_searchstr);
+ kscrolldown(&((Arg){ .i = term.histf }));
+ kbds_clearhighlights();
+ return MODE_KBDSELECT;
+ case XK_n:
+ case XK_N:
+ kbds_searchnext(ksym == XK_n ? kbds_searchdir : -kbds_searchdir);
+ break;
+ case XK_BackSpace:
+ kbds_moveto(0, kbds_c.y);
+ break;
+ case XK_exclam:
+ kbds_moveto(term.col/2, kbds_c.y);
+ break;
+ case XK_underscore:
+ kbds_moveto(term.col-1, kbds_c.y);
+ break;
+ case XK_dollar:
+ case XK_A:
+ eol = kbds_c.len-1;
+ line = kbds_c.line;
+ islast = (kbds_c.x == eol || (kbds_c.x == eol-1 && (line[eol-1].mode & ATTR_WIDE)));
+ if (islast && kbds_iswrapped(&kbds_c) && kbds_c.y < kbds_bot())
+ kbds_moveto(tlinelen(TLINE(kbds_c.y+1))-1, kbds_c.y+1);
+ else
+ kbds_moveto(islast ? term.col-1 : eol, kbds_c.y);
+ break;
+ case XK_asciicircum:
+ case XK_I:
+ for (i = 0; i < kbds_c.len && kbds_c.line[i].u == ' '; i++)
+ ;
+ kbds_moveto((i < kbds_c.len) ? i : 0, kbds_c.y);
+ break;
+ case XK_End:
+ case XK_KP_End:
+ kbds_moveto(kbds_c.x, term.row-1);
+ break;
+ case XK_Home:
+ case XK_KP_Home:
+ case XK_H:
+ kbds_moveto(kbds_c.x, 0);
+ break;
+ case XK_M:
+ kbds_moveto(kbds_c.x, alt ? (term.row-1) / 2
+ : MIN(term.c.y + term.scr, term.row-1) / 2);
+ break;
+ case XK_L:
+ kbds_moveto(kbds_c.x, alt ? term.row-1
+ : MIN(term.c.y + term.scr, term.row-1));
+ break;
+ case XK_Page_Up:
+ case XK_KP_Page_Up:
+ case XK_K:
+ prevscr = term.scr;
+ kscrollup(&((Arg){ .i = term.row }));
+ kbds_moveto(kbds_c.x, alt ? 0
+ : MAX(0, kbds_c.y - term.row + term.scr - prevscr));
+ break;
+ case XK_Page_Down:
+ case XK_KP_Page_Down:
+ case XK_J:
+ prevscr = term.scr;
+ kscrolldown(&((Arg){ .i = term.row }));
+ kbds_moveto(kbds_c.x, alt ? term.row-1
+ : MIN(MIN(term.c.y + term.scr, term.row-1),
+ kbds_c.y + term.row + term.scr - prevscr));
+ break;
+ case XK_asterisk:
+ case XK_KP_Multiply:
+ kbds_moveto(term.col/2, (term.row-1) / 2);
+ break;
+ case XK_g:
+ kscrollup(&((Arg){ .i = term.histf }));
+ kbds_moveto(kbds_c.x, 0);
+ break;
+ case XK_G:
+ kscrolldown(&((Arg){ .i = term.histf }));
+ kbds_moveto(kbds_c.x, alt ? term.row-1 : term.c.y);
+ break;
+ case XK_b:
+ case XK_B:
+ kbds_nextword(1, -1, (ksym == XK_b) ? kbds_sdelim : kbds_ldelim);
+ break;
+ case XK_w:
+ case XK_W:
+ kbds_nextword(1, +1, (ksym == XK_w) ? kbds_sdelim : kbds_ldelim);
+ break;
+ case XK_e:
+ case XK_E:
+ kbds_nextword(0, +1, (ksym == XK_e) ? kbds_sdelim : kbds_ldelim);
+ break;
+ case XK_z:
+ prevscr = term.scr;
+ dy = kbds_c.y - (term.row-1) / 2;
+ if (dy <= 0)
+ kscrollup(&((Arg){ .i = -dy }));
+ else
+ kscrolldown(&((Arg){ .i = dy }));
+ kbds_moveto(kbds_c.x, kbds_c.y + term.scr - prevscr);
+ break;
+ case XK_f:
+ case XK_F:
+ case XK_t:
+ case XK_T:
+ kbds_finddir = (ksym == XK_f || ksym == XK_t) ? 1 : -1;
+ kbds_findtill = (ksym == XK_t || ksym == XK_T) ? 1 : 0;
+ kbds_setmode(kbds_mode | KBDS_MODE_FIND);
+ return 0;
+ case XK_semicolon:
+ case XK_r:
+ kbds_findnext(kbds_finddir, 1);
+ break;
+ case XK_comma:
+ case XK_R:
+ kbds_findnext(-kbds_finddir, 1);
+ break;
+ case XK_0:
+ case XK_KP_0:
+ if (!kbds_quant) {
+ kbds_moveto(0, kbds_c.y);
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ if (ksym >= XK_0 && ksym <= XK_9) { /* 0-9 keyboard */
+ q = (kbds_quant * 10) + (ksym ^ XK_0);
+ kbds_quant = q <= 99999999 ? q : kbds_quant;
+ term.dirty[0] = 1;
+ return 0;
+ } else if (ksym >= XK_KP_0 && ksym <= XK_KP_9) { /* 0-9 numpad */
+ q = (kbds_quant * 10) + (ksym ^ XK_KP_0);
+ kbds_quant = q <= 99999999 ? q : kbds_quant;
+ term.dirty[0] = 1;
+ return 0;
+ } else if (ksym == XK_k || ksym == XK_h)
+ i = ksym & 1;
+ else if (ksym == XK_l || ksym == XK_j)
+ i = ((ksym & 6) | 4) >> 1;
+ else if (ksym >= XK_KP_Left && ksym <= XK_KP_Down)
+ i = ksym - XK_KP_Left;
+ else if ((XK_Home & ksym) != XK_Home || (i = (ksym ^ XK_Home) - 1) > 3)
+ return 0;
+
+ kbds_quant = (kbds_quant ? kbds_quant : 1);
+
+ if (i & 1) {
+ kbds_c.y += kbds_quant * (i & 2 ? 1 : -1);
+ } else {
+ for (;kbds_quant > 0; kbds_quant--) {
+ if (!kbds_moveforward(&kbds_c, (i & 2) ? 1 : -1,
+ KBDS_WRAP_LINE | KBDS_WRAP_EDGE))
+ break;
+ }
+ }
+ kbds_moveto(kbds_c.x, kbds_c.y);
+ }
+ kbds_selecttext();
+ kbds_quant = 0;
+ term.dirty[0] = 1;
+ return 0;
+}
diff --git a/patch/keyboardselect_reflow_st.h b/patch/keyboardselect_reflow_st.h
@@ -0,0 +1,6 @@
+void kbds_drawstatusbar(int y);
+void kbds_pasteintosearch(const char *, int, int);
+int kbds_isselectmode(void);
+int kbds_issearchmode(void);
+int kbds_drawcursor(void);
+int kbds_keyboardhandler(KeySym, char *, int, int);
diff --git a/patch/keyboardselect_reflow_x.c b/patch/keyboardselect_reflow_x.c
@@ -0,0 +1,16 @@
+void keyboard_select(const Arg *dummy)
+{
+ win.mode ^= kbds_keyboardhandler(-1, NULL, 0, 0);
+}
+
+void searchforward(const Arg *)
+{
+ win.mode ^= kbds_keyboardhandler(-1, NULL, 0, 0);
+ kbds_keyboardhandler(-2, NULL, 0, 0);
+}
+
+void searchbackward(const Arg *)
+{
+ win.mode ^= kbds_keyboardhandler(-1, NULL, 0, 0);
+ kbds_keyboardhandler(-3, NULL, 0, 0);
+}
diff --git a/patch/keyboardselect_reflow_x.h b/patch/keyboardselect_reflow_x.h
@@ -0,0 +1,3 @@
+void keyboard_select(const Arg *);
+void searchforward(const Arg *);
+void searchbackward(const Arg *);
diff --git a/patch/keyboardselect_st.c b/patch/keyboardselect_st.c
@@ -0,0 +1,240 @@
+void set_notifmode(int type, KeySym ksym)
+{
+ static char *lib[] = { " MOVE ", " SEL "};
+ static Glyph *g, *deb, *fin;
+ static int col, bot;
+
+ if (ksym == -1) {
+ free(g);
+ col = term.col, bot = term.bot;
+ g = xmalloc(col * sizeof(Glyph));
+ memcpy(g, term.line[bot], col * sizeof(Glyph));
+
+ } else if (ksym == -2)
+ memcpy(term.line[bot], g, col * sizeof(Glyph));
+
+ if ( type < 2 ) {
+ char *z = lib[type];
+ for (deb = &term.line[bot][col - 6], fin = &term.line[bot][col]; deb < fin; z++, deb++)
+ deb->mode = ATTR_REVERSE,
+ deb->u = *z,
+ deb->fg = defaultfg, deb->bg = defaultbg;
+ } else if (type < 5)
+ memcpy(term.line[bot], g, col * sizeof(Glyph));
+ else {
+ for (deb = &term.line[bot][0], fin = &term.line[bot][col]; deb < fin; deb++)
+ deb->mode = ATTR_REVERSE,
+ deb->u = ' ',
+ deb->fg = defaultfg, deb->bg = defaultbg;
+ term.line[bot][0].u = ksym;
+ }
+
+ term.dirty[bot] = 1;
+ drawregion(0, bot, col, bot + 1);
+}
+
+#if SCROLLBACK_PATCH && KEYBOARDSELECT_PATCH
+Glyph getglyph(Term term, int y, int x)
+{
+ Glyph g;
+ int realy = y - term.scr;
+ if(realy >= 0) {
+ g = term.line[realy][x];
+ } else {
+ realy = term.histi - term.scr + y + 1;
+ g = term.hist[realy][x];
+ }
+ return g;
+}
+#endif
+
+void select_or_drawcursor(int selectsearch_mode, int type)
+{
+ int done = 0;
+
+ if (selectsearch_mode & 1) {
+ selextend(term.c.x, term.c.y, type, done);
+ xsetsel(getsel());
+ } else {
+ #if LIGATURES_PATCH
+ xdrawcursor(term.c.x, term.c.y, term.line[term.c.y][term.c.x],
+ term.ocx, term.ocy, term.line[term.ocy][term.ocx],
+ term.line[term.ocy], term.col);
+ #elif SCROLLBACK_PATCH && KEYBOARDSELECT_PATCH
+ xdrawcursor(term.c.x, term.c.y, getglyph(term, term.c.y, term.c.x),
+ term.ocx, term.ocy, getglyph(term, term.ocy, term.ocx));
+ #else
+ xdrawcursor(term.c.x, term.c.y, term.line[term.c.y][term.c.x],
+ term.ocx, term.ocy, term.line[term.ocy][term.ocx]);
+ #endif // LIGATURES_PATCH
+ }
+}
+
+void search(int selectsearch_mode, Rune *target, int ptarget, int incr, int type, TCursor *cu)
+{
+ Rune *r;
+ int i, bound = (term.col * cu->y + cu->x) * (incr > 0) + incr;
+
+ for (i = term.col * term.c.y + term.c.x + incr; i != bound; i += incr) {
+ for (r = target; r - target < ptarget; r++) {
+ if (*r == term.line[(i + r - target) / term.col][(i + r - target) % term.col].u) {
+ if (r - target == ptarget - 1)
+ break;
+ } else {
+ r = NULL;
+ break;
+ }
+ }
+ if (r != NULL)
+ break;
+ }
+
+ if (i != bound) {
+ term.c.y = i / term.col, term.c.x = i % term.col;
+ select_or_drawcursor(selectsearch_mode, type);
+ }
+}
+
+int trt_kbdselect(KeySym ksym, char *buf, int len)
+{
+ static TCursor cu;
+ static Rune target[64];
+ static int type = 1, ptarget, in_use;
+ static int sens, quant;
+ static char selectsearch_mode;
+ int i, bound, *xy;
+
+ if (selectsearch_mode & 2) {
+ if (ksym == XK_Return) {
+ selectsearch_mode ^= 2;
+ set_notifmode(selectsearch_mode, -2);
+ if (ksym == XK_Escape)
+ ptarget = 0;
+ return 0;
+ } else if (ksym == XK_BackSpace) {
+ if (!ptarget)
+ return 0;
+ term.line[term.bot][ptarget--].u = ' ';
+ } else if (len < 1) {
+ return 0;
+ } else if (ptarget == term.col || ksym == XK_Escape) {
+ return 0;
+ } else {
+ utf8decode(buf, &target[ptarget++], len);
+ term.line[term.bot][ptarget].u = target[ptarget - 1];
+ }
+
+ if (ksym != XK_BackSpace)
+ search(selectsearch_mode, &target[0], ptarget, sens, type, &cu);
+
+ term.dirty[term.bot] = 1;
+ drawregion(0, term.bot, term.col, term.bot + 1);
+ return 0;
+ }
+
+ switch (ksym) {
+ case -1:
+ in_use = 1;
+ cu.x = term.c.x, cu.y = term.c.y;
+ set_notifmode(0, ksym);
+ return MODE_KBDSELECT;
+ case XK_s:
+ if (selectsearch_mode & 1)
+ selclear();
+ else
+ selstart(term.c.x, term.c.y, 0);
+ set_notifmode(selectsearch_mode ^= 1, ksym);
+ break;
+ case XK_t:
+ selextend(term.c.x, term.c.y, type ^= 3, i = 0); /* 2 fois */
+ selextend(term.c.x, term.c.y, type, i = 0);
+ break;
+ case XK_slash:
+ case XK_KP_Divide:
+ case XK_question:
+ ksym &= XK_question; /* Divide to slash */
+ sens = (ksym == XK_slash) ? -1 : 1;
+ ptarget = 0;
+ set_notifmode(15, ksym);
+ selectsearch_mode ^= 2;
+ break;
+ case XK_Escape:
+ if (!in_use)
+ break;
+ selclear();
+ case XK_Return:
+ set_notifmode(4, ksym);
+ term.c.x = cu.x, term.c.y = cu.y;
+ select_or_drawcursor(selectsearch_mode = 0, type);
+ in_use = quant = 0;
+ return MODE_KBDSELECT;
+ case XK_n:
+ case XK_N:
+ if (ptarget)
+ search(selectsearch_mode, &target[0], ptarget, (ksym == XK_n) ? -1 : 1, type, &cu);
+ break;
+ case XK_BackSpace:
+ term.c.x = 0;
+ select_or_drawcursor(selectsearch_mode, type);
+ break;
+ case XK_dollar:
+ term.c.x = term.col - 1;
+ select_or_drawcursor(selectsearch_mode, type);
+ break;
+ case XK_Home:
+ term.c.x = 0, term.c.y = 0;
+ select_or_drawcursor(selectsearch_mode, type);
+ break;
+ case XK_End:
+ term.c.x = cu.x, term.c.y = cu.y;
+ select_or_drawcursor(selectsearch_mode, type);
+ break;
+ case XK_Page_Up:
+ case XK_Page_Down:
+ term.c.y = (ksym == XK_Prior ) ? 0 : cu.y;
+ select_or_drawcursor(selectsearch_mode, type);
+ break;
+ case XK_exclam:
+ term.c.x = term.col >> 1;
+ select_or_drawcursor(selectsearch_mode, type);
+ break;
+ case XK_asterisk:
+ case XK_KP_Multiply:
+ term.c.x = term.col >> 1;
+ case XK_underscore:
+ term.c.y = cu.y >> 1;
+ select_or_drawcursor(selectsearch_mode, type);
+ break;
+ default:
+ if (ksym >= XK_0 && ksym <= XK_9) { /* 0-9 keyboard */
+ quant = (quant * 10) + (ksym ^ XK_0);
+ return 0;
+ } else if (ksym >= XK_KP_0 && ksym <= XK_KP_9) { /* 0-9 numpad */
+ quant = (quant * 10) + (ksym ^ XK_KP_0);
+ return 0;
+ } else if (ksym == XK_k || ksym == XK_h)
+ i = ksym & 1;
+ else if (ksym == XK_l || ksym == XK_j)
+ i = ((ksym & 6) | 4) >> 1;
+ else if ((XK_Home & ksym) != XK_Home || (i = (ksym ^ XK_Home) - 1) > 3)
+ break;
+
+ xy = (i & 1) ? &term.c.y : &term.c.x;
+ sens = (i & 2) ? 1 : -1;
+ bound = (i >> 1 ^ 1) ? 0 : (i ^ 3) ? term.col - 1 : term.bot;
+
+ if (quant == 0)
+ quant++;
+
+ if (*xy == bound && ((sens < 0 && bound == 0) || (sens > 0 && bound > 0)))
+ break;
+
+ *xy += quant * sens;
+ if (*xy < 0 || ( bound > 0 && *xy > bound))
+ *xy = bound;
+
+ select_or_drawcursor(selectsearch_mode, type);
+ }
+ quant = 0;
+ return 0;
+}
diff --git a/patch/keyboardselect_st.h b/patch/keyboardselect_st.h
@@ -0,0 +1,2 @@
+void toggle_winmode(int);
+int trt_kbdselect(KeySym, char *, int);
+\ No newline at end of file
diff --git a/patch/keyboardselect_x.c b/patch/keyboardselect_x.c
@@ -0,0 +1,7 @@
+void toggle_winmode(int flag) {
+ win.mode ^= flag;
+}
+
+void keyboard_select(const Arg *dummy) {
+ win.mode ^= trt_kbdselect(-1, NULL, 0);
+}
diff --git a/patch/keyboardselect_x.h b/patch/keyboardselect_x.h
@@ -0,0 +1,2 @@
+void toggle_winmode(int);
+void keyboard_select(const Arg *);
+\ No newline at end of file
diff --git a/patch/netwmicon.c b/patch/netwmicon.c
@@ -0,0 +1,40 @@
+#include <gd.h>
+
+void
+setnetwmicon(void)
+{
+ /* use a png-image to set _NET_WM_ICON */
+ FILE* file = fopen(ICON, "r");
+ if (file) {
+ /* load image in rgba-format */
+ const gdImagePtr icon_rgba = gdImageCreateFromPng(file);
+ fclose(file);
+ /* declare icon-variable which will store the image in bgra-format */
+ const int width = gdImageSX(icon_rgba);
+ const int height = gdImageSY(icon_rgba);
+ const int icon_n = width * height + 2;
+ long icon_bgra[icon_n];
+ /* set width and height of the icon */
+ int i = 0;
+ icon_bgra[i++] = width;
+ icon_bgra[i++] = height;
+ /* rgba -> bgra */
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ const int pixel_rgba = gdImageGetPixel(icon_rgba, x, y);
+ unsigned char *pixel_bgra = (unsigned char *) &icon_bgra[i++];
+ pixel_bgra[0] = gdImageBlue(icon_rgba, pixel_rgba);
+ pixel_bgra[1] = gdImageGreen(icon_rgba, pixel_rgba);
+ pixel_bgra[2] = gdImageRed(icon_rgba, pixel_rgba);
+ /* scale alpha from 0-127 to 0-255 */
+ const unsigned char alpha = 127 - gdImageAlpha(icon_rgba, pixel_rgba);
+ pixel_bgra[3] = alpha == 127 ? 255 : alpha * 2;
+ }
+ }
+ gdImageDestroy(icon_rgba);
+ /* set _NET_WM_ICON */
+ xw.netwmicon = XInternAtom(xw.dpy, "_NET_WM_ICON", False);
+ XChangeProperty(xw.dpy, xw.win, xw.netwmicon, XA_CARDINAL, 32,
+ PropModeReplace, (uchar *) icon_bgra, icon_n);
+ }
+}
diff --git a/patch/netwmicon.h b/patch/netwmicon.h
@@ -0,0 +1 @@
+static void setnetwmicon(void);
diff --git a/patch/netwmicon_ff.c b/patch/netwmicon_ff.c
@@ -0,0 +1,46 @@
+void
+setnetwmicon(void)
+{
+ /* use a farbfeld image to set _NET_WM_ICON */
+ FILE* file = fopen(ICON, "r");
+ if (file) {
+ unsigned char buf[16] = {0};
+
+ int hasdata = fread(buf,1,16,file);
+ if (memcmp(buf,"farbfeld",8)) {
+ fprintf(stderr,"netwmicon: file %s is not a farbfeld image\n", ICON);
+ fclose(file);
+ return;
+ }
+
+ /* declare icon-variable which will store the image in bgra-format */
+ const int width=(buf[8]<<24)|(buf[9]<<16)|(buf[10]<<8)|buf[11];
+ const int height=(buf[12]<<24)|(buf[13]<<16)|(buf[14]<<8)|buf[15];
+ const int icon_n = width * height + 2;
+ long icon_bgra[icon_n];
+
+ /* set width and height of the icon */
+ int i = 0;
+ icon_bgra[i++] = width;
+ icon_bgra[i++] = height;
+
+ /* rgba -> bgra */
+ for (int y = 0; y < height && hasdata; y++) {
+ for (int x = 0; x < width && hasdata; x++) {
+ unsigned char *pixel_bgra = (unsigned char *) &icon_bgra[i++];
+ hasdata = fread(buf,1,8,file);
+ pixel_bgra[0] = buf[4];
+ pixel_bgra[1] = buf[2];
+ pixel_bgra[2] = buf[0];
+ pixel_bgra[3] = buf[6];
+ }
+ }
+
+ /* set _NET_WM_ICON */
+ xw.netwmicon = XInternAtom(xw.dpy, "_NET_WM_ICON", False);
+ XChangeProperty(xw.dpy, xw.win, xw.netwmicon, XA_CARDINAL, 32,
+ PropModeReplace, (uchar *) icon_bgra, icon_n);
+
+ fclose(file);
+ }
+}
diff --git a/patch/netwmicon_icon.h b/patch/netwmicon_icon.h
@@ -0,0 +1,686 @@
+unsigned long icon[] = {
+ 64, 64,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x02000000, 0x03000000,
+ 0x03000000, 0x03000000, 0x03000000, 0x03000000, 0x03000000, 0x03000000,
+ 0x03000000, 0x03000000, 0x03000000, 0x03000000, 0x03000000, 0x03000000,
+ 0x03000000, 0x03000000, 0x03000000, 0x03000000, 0x03000000, 0x03000000,
+ 0x03000000, 0x03000000, 0x03000000, 0x03000000, 0x03000000, 0x03000000,
+ 0x03000000, 0x03000000, 0x03000000, 0x03000000, 0x03000000, 0x03000000,
+ 0x03000000, 0x03000000, 0x03000000, 0x03000000, 0x03000000, 0x03000000,
+ 0x03000000, 0x03000000, 0x03000000, 0x03000000, 0x03000000, 0x03000000,
+ 0x03000000, 0x03000000, 0x03000000, 0x03000000, 0x03000000, 0x03000000,
+ 0x03000000, 0x02000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x03000000,
+ 0x20181818, 0x4e868686, 0x74b2b2b2, 0x77b6b6b6, 0x77b6b6b6, 0x77b6b6b6,
+ 0x77b6b6b6, 0x77b6b6b6, 0x77b6b6b6, 0x77b6b6b6, 0x77b6b6b6, 0x77b6b6b6,
+ 0x77b6b6b6, 0x77b6b6b6, 0x77b6b6b6, 0x77b6b6b6, 0x77b6b6b6, 0x77b6b6b6,
+ 0x77b6b6b6, 0x77b6b6b6, 0x77b6b6b6, 0x77b6b6b6, 0x77b6b6b6, 0x77b6b6b6,
+ 0x77b6b6b6, 0x77b6b6b6, 0x77b6b6b6, 0x77b6b6b6, 0x77b6b6b6, 0x77b6b6b6,
+ 0x77b6b6b6, 0x77b6b6b6, 0x77b6b6b6, 0x77b6b6b6, 0x77b6b6b6, 0x77b6b6b6,
+ 0x77b6b6b6, 0x77b6b6b6, 0x77b6b6b6, 0x77b6b6b6, 0x77b6b6b6, 0x77b6b6b6,
+ 0x77b6b6b6, 0x77b6b6b6, 0x77b6b6b6, 0x77b6b6b6, 0x77b6b6b6, 0x77b6b6b6,
+ 0x77b6b6b6, 0x77b6b6b6, 0x77b6b6b6, 0x77b6b6b6, 0x77b6b6b6, 0x74b2b2b2,
+ 0x4e868686, 0x20181818, 0x03000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x03000000, 0x46717171, 0xcef3f3f3, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xcdf3f3f3,
+ 0x456f6f6f, 0x03000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x211f1f1f, 0xd1f4f4f4, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xd0f3f3f3, 0x20181818,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x59959595, 0xffffffff,
+ 0xffffffff, 0xff8b8b8b, 0xff363636, 0xff363636, 0xff363636, 0xff363636,
+ 0xff363636, 0xff363636, 0xff363636, 0xff363636, 0xff363636, 0xff363636,
+ 0xff363636, 0xff363636, 0xff363636, 0xff363636, 0xff363636, 0xff363636,
+ 0xff363636, 0xff363636, 0xff363636, 0xff363636, 0xff363636, 0xff363636,
+ 0xff363636, 0xff363636, 0xff363636, 0xff363636, 0xff363636, 0xff363636,
+ 0xff363636, 0xff363636, 0xff363636, 0xff363636, 0xff363636, 0xff363636,
+ 0xff363636, 0xff363636, 0xff363636, 0xff363636, 0xff363636, 0xff363636,
+ 0xff363636, 0xff363636, 0xff363636, 0xff363636, 0xff363636, 0xff363636,
+ 0xff363636, 0xff363636, 0xff363636, 0xff363636, 0xff363636, 0xff363636,
+ 0xff8c8c8c, 0xffffffff, 0xffffffff, 0x58919191, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x83b3b3b3, 0xffffffff, 0xffffffff, 0xff262626,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff262626, 0xffffffff,
+ 0xffffffff, 0x83b3b3b3, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x8eacacac, 0xffffffff, 0xffffffff, 0xff222222, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff222222, 0xffffffff, 0xffffffff, 0x8eacacac,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x8eacacac, 0xffffffff,
+ 0xffffffff, 0xff222222, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff222222, 0xffffffff, 0xffffffff, 0x8eacacac, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x8eacacac, 0xffffffff, 0xffffffff, 0xff222222,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff222222, 0xffffffff,
+ 0xffffffff, 0x8eacacac, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x8eacacac, 0xffffffff, 0xffffffff, 0xff222222, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff222222, 0xffffffff, 0xffffffff, 0x8eacacac,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x8eacacac, 0xffffffff,
+ 0xffffffff, 0xff222222, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff2c2c2c, 0xffe0e0e0, 0xff1c1c1c, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff222222, 0xffffffff, 0xffffffff, 0x8eacacac, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x8eacacac, 0xffffffff, 0xffffffff, 0xff222222,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff202020,
+ 0xff6c6c6c, 0xffffffff, 0xff6d6d6d, 0xff3c3c3c, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff222222, 0xffffffff,
+ 0xffffffff, 0x8eacacac, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x8eacacac, 0xffffffff, 0xffffffff, 0xff222222, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff2d2d2d, 0xffe1e1e1, 0xffc3c3c3, 0xffffffff,
+ 0xffa1a1a1, 0xffdddddd, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff222222, 0xffffffff, 0xffffffff, 0x8eacacac,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x8eacacac, 0xffffffff,
+ 0xffffffff, 0xff222222, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff7f7f7f, 0xffbfbfbf, 0xff303030, 0xffffffff, 0xff1c1c1c, 0xff181818,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff222222, 0xffffffff, 0xffffffff, 0x8eacacac, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x8eacacac, 0xffffffff, 0xffffffff, 0xff222222,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff717171, 0xffe1e1e1,
+ 0xff545454, 0xffffffff, 0xff1c1c1c, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff222222, 0xffffffff,
+ 0xffffffff, 0x8eacacac, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x8eacacac, 0xffffffff, 0xffffffff, 0xff222222, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff1c1c1c, 0xffa1a1a1, 0xfff6f6f6, 0xffffffff,
+ 0xffaeaeae, 0xff515151, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff222222, 0xffffffff, 0xffffffff, 0x8eacacac,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x8eacacac, 0xffffffff,
+ 0xffffffff, 0xff222222, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff343434, 0xffffffff, 0xff979797, 0xfff9f9f9,
+ 0xff515151, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff222222, 0xffffffff, 0xffffffff, 0x8eacacac, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x8eacacac, 0xffffffff, 0xffffffff, 0xff222222,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff303030, 0xffffffff, 0xff1c1c1c, 0xffb3b3b3, 0xff8d8d8d, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff222222, 0xffffffff,
+ 0xffffffff, 0x8eacacac, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x8eacacac, 0xffffffff, 0xffffffff, 0xff222222, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff686868, 0xff616161, 0xff3c3c3c, 0xffffffff,
+ 0xff545454, 0xffe8e8e8, 0xff5b5b5b, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff222222, 0xffffffff, 0xffffffff, 0x8eacacac,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x8eacacac, 0xffffffff,
+ 0xffffffff, 0xff222222, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff4b4b4b, 0xffb3b3b3, 0xffe1e1e1, 0xffffffff, 0xffcccccc, 0xff717171,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff222222, 0xffffffff, 0xffffffff, 0x8eacacac, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x8eacacac, 0xffffffff, 0xffffffff, 0xff222222,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff303030, 0xffffffff, 0xff1c1c1c, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff222222, 0xffffffff,
+ 0xffffffff, 0x8eacacac, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x8eacacac, 0xffffffff, 0xffffffff, 0xff222222, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff2b2b2b, 0xffd1d1d1,
+ 0xff1c1c1c, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff222222, 0xffffffff, 0xffffffff, 0x8eacacac,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x8eacacac, 0xffffffff,
+ 0xffffffff, 0xff222222, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff7f7f7f, 0xffe9e9e9, 0xffe9e9e9, 0xffe9e9e9, 0xffe9e9e9,
+ 0xffe9e9e9, 0xffe9e9e9, 0xff444444, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff222222, 0xffffffff, 0xffffffff, 0x8eacacac, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x8eacacac, 0xffffffff, 0xffffffff, 0xff222222,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff222222, 0xffffffff,
+ 0xffffffff, 0x8eacacac, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x8eacacac, 0xffffffff, 0xffffffff, 0xff222222, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff222222, 0xffffffff, 0xffffffff, 0x8eacacac,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x8eacacac, 0xffffffff,
+ 0xffffffff, 0xff222222, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff222222, 0xffffffff, 0xffffffff, 0x8eacacac, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x8eacacac, 0xffffffff, 0xffffffff, 0xff222222,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff222222, 0xffffffff,
+ 0xffffffff, 0x8eacacac, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x8eacacac, 0xffffffff, 0xffffffff, 0xff222222, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff222222, 0xffffffff, 0xffffffff, 0x8eacacac,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x8eacacac, 0xffffffff,
+ 0xffffffff, 0xff222222, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff222222, 0xffffffff, 0xffffffff, 0x8eacacac, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x8eacacac, 0xffffffff, 0xffffffff, 0xff222222,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff222222, 0xffffffff,
+ 0xffffffff, 0x8eacacac, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x8eacacac, 0xffffffff, 0xffffffff, 0xff222222, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff222222, 0xffffffff, 0xffffffff, 0x8eacacac,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x8eacacac, 0xffffffff,
+ 0xffffffff, 0xff222222, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff222222, 0xffffffff, 0xffffffff, 0x8eacacac, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x8eacacac, 0xffffffff, 0xffffffff, 0xff222222,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff222222, 0xffffffff,
+ 0xffffffff, 0x8eacacac, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x8eacacac, 0xffffffff, 0xffffffff, 0xff222222, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff222222, 0xffffffff, 0xffffffff, 0x8eacacac,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x8eacacac, 0xffffffff,
+ 0xffffffff, 0xff222222, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff222222, 0xffffffff, 0xffffffff, 0x8eacacac, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x8eacacac, 0xffffffff, 0xffffffff, 0xff222222,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff222222, 0xffffffff,
+ 0xffffffff, 0x8eacacac, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x8eacacac, 0xffffffff, 0xffffffff, 0xff222222, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff222222, 0xffffffff, 0xffffffff, 0x8eacacac,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x8eacacac, 0xffffffff,
+ 0xffffffff, 0xff222222, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff222222, 0xffffffff, 0xffffffff, 0x8eacacac, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x8eacacac, 0xffffffff, 0xffffffff, 0xff222222,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff222222, 0xffffffff,
+ 0xffffffff, 0x8eacacac, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x8eacacac, 0xffffffff, 0xffffffff, 0xff222222, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff222222, 0xffffffff, 0xffffffff, 0x8eacacac,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x8eacacac, 0xffffffff,
+ 0xffffffff, 0xff222222, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff222222, 0xffffffff, 0xffffffff, 0x8eacacac, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x8eacacac, 0xffffffff, 0xffffffff, 0xff222222,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff222222, 0xffffffff,
+ 0xffffffff, 0x8eacacac, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x8eacacac, 0xffffffff, 0xffffffff, 0xff222222, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff222222, 0xffffffff, 0xffffffff, 0x8eacacac,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x8eacacac, 0xffffffff,
+ 0xffffffff, 0xff222222, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff222222, 0xffffffff, 0xffffffff, 0x8eacacac, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x8aacacac, 0xffffffff, 0xffffffff, 0xff262626,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff171717,
+ 0xff171717, 0xff171717, 0xff171717, 0xff171717, 0xff262626, 0xffffffff,
+ 0xffffffff, 0x8aacacac, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x62858585, 0xffffffff, 0xffffffff, 0xff8c8c8c, 0xff373737, 0xff363636,
+ 0xff363636, 0xff363636, 0xff363636, 0xff363636, 0xff363636, 0xff363636,
+ 0xff363636, 0xff363636, 0xff363636, 0xff363636, 0xff363636, 0xff363636,
+ 0xff363636, 0xff363636, 0xff363636, 0xff363636, 0xff363636, 0xff363636,
+ 0xff363636, 0xff363636, 0xff363636, 0xff363636, 0xff363636, 0xff363636,
+ 0xff363636, 0xff363636, 0xff363636, 0xff363636, 0xff363636, 0xff363636,
+ 0xff363636, 0xff363636, 0xff363636, 0xff363636, 0xff363636, 0xff363636,
+ 0xff363636, 0xff363636, 0xff363636, 0xff363636, 0xff363636, 0xff363636,
+ 0xff363636, 0xff363636, 0xff363636, 0xff363636, 0xff363636, 0xff363636,
+ 0xff363636, 0xff373737, 0xff8d8d8d, 0xffffffff, 0xffffffff, 0x62828282,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x21171717, 0xdee2e2e2,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xdee1e1e1, 0x1f101010, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x03000000, 0x5f4e4e4e, 0xdbe1e1e1, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xdae1e1e1,
+ 0x5f4b4b4b, 0x03000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x12000000, 0x48040404, 0x6d595959, 0x8d929292, 0x90979797,
+ 0x90979797, 0x90979797, 0x90979797, 0x90979797, 0x90979797, 0x90979797,
+ 0x90979797, 0x90979797, 0x90979797, 0x90979797, 0x90979797, 0x90979797,
+ 0x90979797, 0x90979797, 0x90979797, 0x90979797, 0x90979797, 0x90979797,
+ 0x90979797, 0x90979797, 0x90979797, 0x90979797, 0x90979797, 0x90979797,
+ 0x90979797, 0x90979797, 0x90979797, 0x90979797, 0x90979797, 0x90979797,
+ 0x90979797, 0x90979797, 0x90979797, 0x90979797, 0x90979797, 0x90979797,
+ 0x90979797, 0x90979797, 0x90979797, 0x90979797, 0x90979797, 0x90979797,
+ 0x90979797, 0x90979797, 0x90979797, 0x90979797, 0x90979797, 0x90979797,
+ 0x90979797, 0x8d929292, 0x6d595959, 0x48040404, 0x12000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x06000000, 0x22000000, 0x29000000, 0x29000000, 0x29000000, 0x29000000,
+ 0x29000000, 0x29000000, 0x29000000, 0x29000000, 0x29000000, 0x29000000,
+ 0x29000000, 0x29000000, 0x29000000, 0x29000000, 0x29000000, 0x29000000,
+ 0x29000000, 0x29000000, 0x29000000, 0x29000000, 0x29000000, 0x29000000,
+ 0x29000000, 0x29000000, 0x29000000, 0x29000000, 0x29000000, 0x29000000,
+ 0x29000000, 0x29000000, 0x29000000, 0x29000000, 0x29000000, 0x29000000,
+ 0x29000000, 0x29000000, 0x29000000, 0x29000000, 0x29000000, 0x29000000,
+ 0x29000000, 0x29000000, 0x29000000, 0x29000000, 0x29000000, 0x29000000,
+ 0x29000000, 0x29000000, 0x29000000, 0x29000000, 0x29000000, 0x29000000,
+ 0x22000000, 0x06000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
+\ No newline at end of file
diff --git a/patch/netwmicon_legacy.c b/patch/netwmicon_legacy.c
@@ -0,0 +1,7 @@
+void
+setnetwmicon(void)
+{
+ xw.netwmicon = XInternAtom(xw.dpy, "_NET_WM_ICON", False);
+ XChangeProperty(xw.dpy, xw.win, xw.netwmicon, XA_CARDINAL, 32,
+ PropModeReplace, (uchar *)&icon, LEN(icon));
+}
diff --git a/patch/newterm.c b/patch/newterm.c
@@ -0,0 +1,44 @@
+extern char* argv0;
+
+static char*
+getcwd_by_pid(pid_t pid) {
+ static char cwd[32];
+ snprintf(cwd, sizeof cwd, "/proc/%d/cwd", pid);
+ return cwd;
+}
+
+void
+newterm(const Arg* a)
+{
+ switch (fork()) {
+ case -1:
+ die("fork failed: %s\n", strerror(errno));
+ break;
+ case 0:
+ switch (fork()) {
+ case -1:
+ die("fork failed: %s\n", strerror(errno));
+ break;
+ case 0:
+ #if OSC7_PATCH
+ if (term.cwd) {
+ if (chdir(term.cwd) == 0) {
+ /* We need to put the working directory also in PWD, so that
+ * the shell starts in the right directory if `cwd` is a
+ * symlink. */
+ setenv("PWD", term.cwd, 1);
+ }
+ } else {
+ chdir(getcwd_by_pid(pid));
+ }
+ #else
+ chdir(getcwd_by_pid(pid));
+ #endif // OSC7_PATCH
+
+ execl("/proc/self/exe", argv0, NULL);
+ exit(1);
+ default:
+ exit(0);
+ }
+ }
+}
diff --git a/patch/newterm.h b/patch/newterm.h
@@ -0,0 +1 @@
+void newterm(const Arg *);
diff --git a/patch/opencopied.c b/patch/opencopied.c
@@ -0,0 +1,19 @@
+void
+opencopied(const Arg *arg)
+{
+ int res;
+ size_t const max_cmd = 2048;
+ char * const clip = xsel.clipboard;
+ if (!clip) {
+ fprintf(stderr, "Warning: nothing copied to clipboard\n");
+ return;
+ }
+
+ /* account for space/quote (3) and \0 (1) and & (1) */
+ /* e.g.: xdg-open "https://st.suckless.org"& */
+ size_t const cmd_size = max_cmd + strlen(clip) + 5;
+ char cmd[cmd_size];
+
+ snprintf(cmd, cmd_size, "%s \"%s\"&", (char *)arg->v, clip);
+ res = system(cmd);
+}
+\ No newline at end of file
diff --git a/patch/opencopied.h b/patch/opencopied.h
@@ -0,0 +1 @@
+void opencopied(const Arg *);
+\ No newline at end of file
diff --git a/patch/openselectedtext.c b/patch/openselectedtext.c
@@ -0,0 +1,13 @@
+void
+selopen(const Arg *dummy)
+{
+ pid_t chpid;
+
+ if ((chpid = fork()) == 0) {
+ if (fork() == 0)
+ execlp("xdg-open", "xdg-open", getsel(), NULL);
+ exit(1);
+ }
+ if (chpid > 0)
+ waitpid(chpid, NULL, 0);
+}
diff --git a/patch/openselectedtext.h b/patch/openselectedtext.h
@@ -0,0 +1,3 @@
+#include <sys/wait.h>
+
+static void selopen(const Arg *);
diff --git a/patch/openurlonclick.c b/patch/openurlonclick.c
@@ -0,0 +1,230 @@
+#if !REFLOW_PATCH
+#if SCROLLBACK_PATCH
+#define TLINEURL(y) TLINE(y)
+#else
+#define TLINEURL(y) term.line[y]
+#endif // SCROLLBACK_PATCH
+#endif // REFLOW_PATCH
+
+int url_x1, url_y1, url_x2, url_y2 = -1;
+int url_draw, url_click, url_maxcol;
+
+static int
+isvalidurlchar(Rune u)
+{
+ /* () and [] can appear in urls, but excluding them here will reduce false
+ * positives when figuring out where a given url ends. See copyurl patch.
+ */
+ static char urlchars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789-._~:/?#@!$&'*+,;=%";
+ return u < 128 && strchr(urlchars, (int)u) != NULL;
+}
+
+/* find the end of the wrapped line */
+#if REFLOW_PATCH
+static int
+findeowl(Line line)
+{
+ int i = term.col - 1;
+
+ do {
+ if (line[i].mode & ATTR_WRAP)
+ return i;
+ } while (!(line[i].mode & ATTR_SET) && --i >= 0);
+
+ return -1;
+}
+#else
+static int
+findeowl(int row)
+{
+ #if COLUMNS_PATCH
+ int col = term.maxcol - 1;
+ #else
+ int col = term.col - 1;
+ #endif // COLUMNS_PATCH
+
+ do {
+ if (TLINEURL(row)[col].mode & ATTR_WRAP)
+ return col;
+ } while (TLINEURL(row)[col].u == ' ' && --col >= 0);
+ return -1;
+}
+#endif // REFLOW_PATCH
+
+void
+clearurl(void)
+{
+ while (url_y1 <= url_y2 && url_y1 < term.row)
+ term.dirty[url_y1++] = 1;
+ url_y2 = -1;
+}
+
+#if REFLOW_PATCH
+char *
+detecturl(int col, int row, int draw)
+{
+ static char url[2048];
+ Line line;
+ int x1, y1, x2, y2;
+ int i = sizeof(url)/2+1, j = sizeof(url)/2;
+ int row_start = row, col_start = col;
+ int minrow = tisaltscr() ? 0 : term.scr - term.histf;
+ int maxrow = tisaltscr() ? term.row - 1 : term.scr + term.row - 1;
+
+ /* clear previously underlined url */
+ if (draw)
+ clearurl();
+
+ url_maxcol = 0;
+ line = TLINE(row);
+
+ if (!isvalidurlchar(line[col].u))
+ return NULL;
+
+ /* find the first character of url */
+ do {
+ x1 = col_start, y1 = row_start;
+ url_maxcol = MAX(url_maxcol, x1);
+ url[--i] = line[col_start].u;
+ if (--col_start < 0) {
+ if (--row_start < minrow || (col_start = findeowl(TLINE(row_start))) < 0)
+ break;
+ line = TLINE(row_start);
+ }
+ } while (isvalidurlchar(line[col_start].u) && i > 0);
+
+ /* early detection */
+ if (url[i] != 'h')
+ return NULL;
+
+ /* find the last character of url */
+ line = TLINE(row);
+ do {
+ x2 = col, y2 = row;
+ url_maxcol = MAX(url_maxcol, x2);
+ url[j++] = line[col].u;
+ if (line[col++].mode & ATTR_WRAP) {
+ if (++row > maxrow)
+ break;
+ col = 0;
+ line = TLINE(row);
+ }
+ } while (col < term.col && isvalidurlchar(line[col].u) && j < sizeof(url)-1);
+
+ url[j] = 0;
+
+ if (strncmp("https://", &url[i], 8) && strncmp("http://", &url[i], 7))
+ return NULL;
+
+ /* Ignore some trailing characters to improve detection. */
+ /* Alacritty and many other terminals also ignore these. */
+ if (strchr(",.;:?!", (int)(url[j-1])) != NULL) {
+ x2 = MAX(x2-1, 0);
+ url[j-1] = 0;
+ }
+
+ /* underline url (see xdrawglyphfontspecs() in x.c) */
+ if (draw) {
+ url_x1 = (y1 >= 0) ? x1 : 0;
+ url_x2 = (y2 < term.row) ? x2 : url_maxcol;
+ url_y1 = MAX(y1, 0);
+ url_y2 = MIN(y2, term.row-1);
+ url_draw = 1;
+ for (y1 = url_y1; y1 <= url_y2; y1++)
+ term.dirty[y1] = 1;
+ }
+
+ return &url[i];
+}
+#else
+char *
+detecturl(int col, int row, int draw)
+{
+ static char url[2048];
+ int x1, y1, x2, y2, wrapped;
+ int row_start = row;
+ int col_start = col;
+ int i = sizeof(url)/2+1, j = sizeof(url)/2;
+
+ #if SCROLLBACK_PATCH
+ int minrow = term.scr - term.histn, maxrow = term.scr + term.row - 1;
+ /* Fixme: MODE_ALTSCREEN is not defined here, I had to use the magic number 1<<2 */
+ if ((term.mode & (1 << 2)) != 0)
+ minrow = 0, maxrow = term.row - 1;
+ #else
+ int minrow = 0, maxrow = term.row - 1;
+ #endif // SCROLLBACK_PATCH
+ url_maxcol = 0;
+
+ /* clear previously underlined url */
+ if (draw)
+ clearurl();
+
+ if (!isvalidurlchar(TLINEURL(row)[col].u))
+ return NULL;
+
+ /* find the first character of url */
+ do {
+ x1 = col_start, y1 = row_start;
+ url_maxcol = MAX(url_maxcol, x1);
+ url[--i] = TLINEURL(row_start)[col_start].u;
+ if (--col_start < 0) {
+ if (--row_start < minrow || (col_start = findeowl(row_start)) < 0)
+ break;
+ }
+ } while (i > 0 && isvalidurlchar(TLINEURL(row_start)[col_start].u));
+
+ /* early detection */
+ if (url[i] != 'h')
+ return NULL;
+
+ /* find the last character of url */
+ do {
+ x2 = col, y2 = row;
+ url_maxcol = MAX(url_maxcol, x2);
+ url[j++] = TLINEURL(row)[col].u;
+ wrapped = TLINEURL(row)[col].mode & ATTR_WRAP;
+ #if COLUMNS_PATCH
+ if (++col >= term.maxcol || wrapped) {
+ #else
+ if (++col >= term.col || wrapped) {
+ #endif // COLUMNS_PATCH
+ col = 0;
+ if (++row > maxrow || !wrapped)
+ break;
+ }
+ } while (j < sizeof(url)-1 && isvalidurlchar(TLINEURL(row)[col].u));
+
+ url[j] = 0;
+
+ if (strncmp("https://", &url[i], 8) && strncmp("http://", &url[i], 7))
+ return NULL;
+
+ /* underline url (see xdrawglyphfontspecs() in x.c) */
+ if (draw) {
+ url_x1 = (y1 >= 0) ? x1 : 0;
+ url_x2 = (y2 < term.row) ? x2 : url_maxcol;
+ url_y1 = MAX(y1, 0);
+ url_y2 = MIN(y2, term.row-1);
+ url_draw = 1;
+ for (y1 = url_y1; y1 <= url_y2; y1++)
+ term.dirty[y1] = 1;
+ }
+
+ return &url[i];
+}
+#endif // REFLOW_PATCH
+
+void
+openUrlOnClick(int col, int row, char* url_opener)
+{
+ char *url = detecturl(col, row, 1);
+ if (url) {
+ extern char **environ;
+ pid_t junk;
+ char *argv[] = { url_opener, url, NULL };
+ posix_spawnp(&junk, argv[0], NULL, NULL, argv, environ);
+ }
+}
diff --git a/patch/openurlonclick.h b/patch/openurlonclick.h
@@ -0,0 +1,8 @@
+#include <spawn.h>
+
+static inline void restoremousecursor(void) {
+ if (!(win.mode & MODE_MOUSE) && xw.pointerisvisible)
+ XDefineCursor(xw.dpy, xw.win, xw.vpointer);
+}
+static void clearurl(void);
+static void openUrlOnClick(int col, int row, char* url_opener);
diff --git a/patch/osc133.c b/patch/osc133.c
@@ -0,0 +1,29 @@
+void
+scrolltoprompt(const Arg *arg)
+{
+ int x, y;
+ #if REFLOW_PATCH
+ int top = term.scr - term.histf;
+ #else
+ int top = term.scr - term.histn;
+ #endif // REFLOW_PATCH
+ int bot = term.scr + term.row-1;
+ int dy = arg->i;
+ Line line;
+
+ if (!dy || tisaltscr())
+ return;
+
+ for (y = dy; y >= top && y <= bot; y += dy) {
+ for (line = TLINE(y), x = 0; x < term.col; x++) {
+ if (line[x].mode & ATTR_FTCS_PROMPT)
+ goto scroll;
+ }
+ }
+
+scroll:
+ if (dy < 0)
+ kscrollup(&((Arg){ .i = -y }));
+ else
+ kscrolldown(&((Arg){ .i = y }));
+}
diff --git a/patch/osc133.h b/patch/osc133.h
@@ -0,0 +1 @@
+static void scrolltoprompt(const Arg *);
diff --git a/patch/osc7.c b/patch/osc7.c
@@ -0,0 +1,74 @@
+static int
+hex2int(char c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ else if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ else if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ else
+ return -1;
+}
+
+int
+osc7parsecwd(const char *uri)
+{
+ const char *auth, *host, *hostend;
+ char *path, decoded[PATH_MAX], thishost[_POSIX_HOST_NAME_MAX];
+ size_t i, decodedlen, hostlen, urilen;
+ int h1, h2;
+ if (!term.cwd) {
+ term.cwd = xmalloc(sizeof(decoded));
+ term.cwd[0] = '\0';
+ }
+ /* reset cwd if uri is empty */
+ if ((urilen = strlen(uri)) == 0) {
+ term.cwd[0] = '\0';
+ return 1;
+ }
+ /* decode uri */
+ for (decodedlen = 0, i = 0; i < urilen; i++) {
+ if (uri[i] == '%' && i <= urilen-3 &&
+ (h1 = hex2int(uri[i+1])) >= 0 && (h2 = hex2int(uri[i+2])) >= 0) {
+ decoded[decodedlen++] = (h1 << 4) | h2;
+ i += 2;
+ } else {
+ decoded[decodedlen++] = uri[i];
+ }
+ if (decodedlen == sizeof(decoded)) {
+ fprintf(stderr, "erresc (OSC 7): uri is too long\n");
+ return 0;
+ }
+ }
+ decoded[decodedlen] = '\0';
+ /* check scheme */
+ if (decodedlen < 5 || strncmp("file:", decoded, 5) != 0) {
+ fprintf(stderr, "erresc (OSC 7): scheme is not supported: '%s'\n", uri);
+ return 0;
+ }
+ /* find start of authority */
+ if (decodedlen < 7 || decoded[5] != '/' || decoded[6] != '/') {
+ fprintf(stderr, "erresc (OSC 7): invalid uri: '%s'\n", uri);
+ return 0;
+ }
+ auth = decoded + 7;
+ /* find start of path and reset cwd if path is missing */
+ if ((path = strchr(auth, '/')) == NULL) {
+ term.cwd[0] = '\0';
+ return 1;
+ }
+ /* ignore path if host is not localhost */
+ host = ((host = memchr(auth, '@', path - auth)) != NULL) ? host+1 : auth;
+ hostend = ((hostend = memchr(host, ':', path - host)) != NULL) ? hostend : path;
+ hostlen = hostend - host;
+ if (gethostname(thishost, sizeof(thishost)) < 0)
+ thishost[0] = '\0';
+ if (hostlen > 0 &&
+ !(hostlen == 9 && strncmp("localhost", host, hostlen) == 0) &&
+ !(hostlen == strlen(thishost) && strncmp(host, thishost, hostlen) == 0)) {
+ return 0;
+ }
+ memcpy(term.cwd, path, decodedlen - (path - decoded) + 1);
+ return 1;
+}
diff --git a/patch/osc7.h b/patch/osc7.h
@@ -0,0 +1 @@
+static int osc7parsecwd(const char *);
diff --git a/patch/reflow.c b/patch/reflow.c
@@ -0,0 +1,923 @@
+void
+tloaddefscreen(int clear, int loadcursor)
+{
+ int col, row, alt = IS_SET(MODE_ALTSCREEN);
+
+ if (alt) {
+ if (clear) {
+ tclearregion(0, 0, term.col-1, term.row-1, 1);
+ #if SIXEL_PATCH
+ tdeleteimages();
+ #endif // SIXEL_PATCH
+ }
+ col = term.col, row = term.row;
+ tswapscreen();
+ }
+ if (loadcursor)
+ tcursor(CURSOR_LOAD);
+ if (alt)
+ tresizedef(col, row);
+}
+
+void
+tloadaltscreen(int clear, int savecursor)
+{
+ int col, row, def = !IS_SET(MODE_ALTSCREEN);
+
+ if (savecursor)
+ tcursor(CURSOR_SAVE);
+ if (def) {
+ col = term.col, row = term.row;
+ kscrolldown(&((Arg){ .i = term.scr }));
+ tswapscreen();
+ tresizealt(col, row);
+ }
+ if (clear) {
+ tclearregion(0, 0, term.col-1, term.row-1, 1);
+ #if SIXEL_PATCH
+ tdeleteimages();
+ #endif // SIXEL_PATCH
+ }
+}
+
+void
+selmove(int n)
+{
+ sel.ob.y += n, sel.nb.y += n;
+ sel.oe.y += n, sel.ne.y += n;
+}
+
+void
+tclearglyph(Glyph *gp, int usecurattr)
+{
+ if (usecurattr) {
+ gp->fg = term.c.attr.fg;
+ gp->bg = term.c.attr.bg;
+ } else {
+ gp->fg = defaultfg;
+ gp->bg = defaultbg;
+ }
+ gp->mode = ATTR_NULL;
+ gp->u = ' ';
+}
+
+#if SIXEL_PATCH
+void
+treflow_moveimages(int oldy, int newy)
+{
+ ImageList *im;
+
+ for (im = term.images; im; im = im->next) {
+ if (im->y == oldy)
+ im->reflow_y = newy;
+ }
+}
+#endif // SIXEL_PATCH
+
+void
+treflow(int col, int row)
+{
+ int i, j;
+ int oce, nce, bot, scr;
+ int ox = 0, oy = -term.histf, nx = 0, ny = -1, len;
+ int cy = -1; /* proxy for new y coordinate of cursor */
+ int buflen, nlines;
+ Line *buf, bufline, line;
+ #if SIXEL_PATCH
+ ImageList *im, *next;
+
+ for (im = term.images; im; im = im->next)
+ im->reflow_y = INT_MIN; /* unset reflow_y */
+ #endif // SIXEL_PATCH
+
+ /* y coordinate of cursor line end */
+ for (oce = term.c.y; oce < term.row - 1 &&
+ tiswrapped(term.line[oce]); oce++);
+
+ nlines = HISTSIZE + row;
+ buf = xmalloc(nlines * sizeof(Line));
+ do {
+ if (!nx && ++ny < nlines)
+ buf[ny] = xmalloc(col * sizeof(Glyph));
+ if (!ox) {
+ line = TLINEABS(oy);
+ len = tlinelen(line);
+ }
+ if (oy == term.c.y) {
+ if (!ox)
+ len = MAX(len, term.c.x + 1);
+ /* update cursor */
+ if (cy < 0 && term.c.x - ox < col - nx) {
+ term.c.x = nx + term.c.x - ox, cy = ny;
+ UPDATEWRAPNEXT(0, col);
+ }
+ }
+ /* get reflowed lines in buf */
+ bufline = buf[ny % nlines];
+ if (col - nx > len - ox) {
+ memcpy(&bufline[nx], &line[ox], (len-ox) * sizeof(Glyph));
+ nx += len - ox;
+ if (len == 0 || !(line[len - 1].mode & ATTR_WRAP)) {
+ for (j = nx; j < col; j++)
+ tclearglyph(&bufline[j], 0);
+ #if SIXEL_PATCH
+ treflow_moveimages(oy+term.scr, ny);
+ #endif // SIXEL_PATCH
+ nx = 0;
+ } else if (nx > 0) {
+ bufline[nx - 1].mode &= ~ATTR_WRAP;
+ }
+ ox = 0, oy++;
+ } else if (col - nx == len - ox) {
+ memcpy(&bufline[nx], &line[ox], (col-nx) * sizeof(Glyph));
+ #if SIXEL_PATCH
+ treflow_moveimages(oy+term.scr, ny);
+ #endif // SIXEL_PATCH
+ ox = 0, oy++, nx = 0;
+ } else/* if (col - nx < len - ox) */ {
+ memcpy(&bufline[nx], &line[ox], (col-nx) * sizeof(Glyph));
+ if (bufline[col - 1].mode & ATTR_WIDE) {
+ bufline[col - 2].mode |= ATTR_WRAP;
+ tclearglyph(&bufline[col - 1], 0);
+ ox--;
+ } else {
+ bufline[col - 1].mode |= ATTR_WRAP;
+ }
+ #if SIXEL_PATCH
+ treflow_moveimages(oy+term.scr, ny);
+ #endif // SIXEL_PATCH
+ ox += col - nx;
+ nx = 0;
+ }
+ } while (oy <= oce);
+ if (nx)
+ for (j = nx; j < col; j++)
+ tclearglyph(&bufline[j], 0);
+
+ /* free extra lines */
+ for (i = row; i < term.row; i++)
+ free(term.line[i]);
+ /* resize to new height */
+ term.line = xrealloc(term.line, row * sizeof(Line));
+
+ buflen = MIN(ny + 1, nlines);
+ bot = MIN(ny, row - 1);
+ scr = MAX(row - term.row, 0);
+ /* update y coordinate of cursor line end */
+ nce = MIN(oce + scr, bot);
+ /* update cursor y coordinate */
+ term.c.y = nce - (ny - cy);
+ if (term.c.y < 0) {
+ j = nce, nce = MIN(nce + -term.c.y, bot);
+ term.c.y += nce - j;
+ while (term.c.y < 0) {
+ free(buf[ny-- % nlines]);
+ buflen--;
+ term.c.y++;
+ }
+ }
+ /* allocate new rows */
+ for (i = row - 1; i > nce; i--) {
+ if (i >= term.row)
+ term.line[i] = xmalloc(col * sizeof(Glyph));
+ else
+ term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph));
+ for (j = 0; j < col; j++)
+ tclearglyph(&term.line[i][j], 0);
+ }
+ /* fill visible area */
+ for (/*i = nce */; i >= term.row; i--, ny--, buflen--)
+ term.line[i] = buf[ny % nlines];
+ for (/*i = term.row - 1 */; i >= 0; i--, ny--, buflen--) {
+ free(term.line[i]);
+ term.line[i] = buf[ny % nlines];
+ }
+ /* fill lines in history buffer and update term.histf */
+ for (/*i = -1 */; buflen > 0 && i >= -HISTSIZE; i--, ny--, buflen--) {
+ j = (term.histi + i + 1 + HISTSIZE) % HISTSIZE;
+ free(term.hist[j]);
+ term.hist[j] = buf[ny % nlines];
+ }
+ term.histf = -i - 1;
+ term.scr = MIN(term.scr, term.histf);
+ /* resize rest of the history lines */
+ for (/*i = -term.histf - 1 */; i >= -HISTSIZE; i--) {
+ j = (term.histi + i + 1 + HISTSIZE) % HISTSIZE;
+ term.hist[j] = xrealloc(term.hist[j], col * sizeof(Glyph));
+ }
+
+ #if SIXEL_PATCH
+ /* move images to the final position */
+ for (im = term.images; im; im = next) {
+ next = im->next;
+ if (im->reflow_y == INT_MIN) {
+ delete_image(im);
+ } else {
+ im->y = im->reflow_y - term.histf + term.scr - (ny + 1);
+ if (im->y - term.scr < -HISTSIZE || im->y - term.scr >= row)
+ delete_image(im);
+ }
+ }
+
+ /* expand images into new text cells */
+ for (im = term.images; im; im = im->next) {
+ j = MIN(im->x + im->cols, col);
+ line = TLINE(im->y);
+ for (i = im->x; i < j; i++) {
+ if (!(line[i].mode & ATTR_SET))
+ line[i].mode |= ATTR_SIXEL;
+ }
+ }
+ #endif // SIXEL_PATCH
+
+ for (; buflen > 0; ny--, buflen--)
+ free(buf[ny % nlines]);
+ free(buf);
+}
+
+void
+rscrolldown(int n)
+{
+ int i;
+ Line temp;
+
+ /* can never be true as of now
+ if (IS_SET(MODE_ALTSCREEN))
+ return; */
+
+ if ((n = MIN(n, term.histf)) <= 0)
+ return;
+
+ for (i = term.c.y + n; i >= n; i--) {
+ temp = term.line[i];
+ term.line[i] = term.line[i-n];
+ term.line[i-n] = temp;
+ }
+ for (/*i = n - 1 */; i >= 0; i--) {
+ temp = term.line[i];
+ term.line[i] = term.hist[term.histi];
+ term.hist[term.histi] = temp;
+ term.histi = (term.histi - 1 + HISTSIZE) % HISTSIZE;
+ }
+ term.c.y += n;
+ term.histf -= n;
+ if ((i = term.scr - n) >= 0) {
+ term.scr = i;
+ } else {
+ #if SIXEL_PATCH
+ scroll_images(n - term.scr);
+ #endif // SIXEL_PATCH
+ term.scr = 0;
+ if (sel.ob.x != -1 && !sel.alt)
+ selmove(-i);
+ }
+}
+
+void
+tresizedef(int col, int row)
+{
+ int i, j;
+
+ /* return if dimensions haven't changed */
+ if (term.col == col && term.row == row) {
+ tfulldirt();
+ return;
+ }
+ if (col != term.col) {
+ if (!sel.alt)
+ selremove();
+ treflow(col, row);
+ } else {
+ /* slide screen up if otherwise cursor would get out of the screen */
+ if (term.c.y >= row) {
+ tscrollup(0, term.row - 1, term.c.y - row + 1, SCROLL_RESIZE);
+ term.c.y = row - 1;
+ }
+ for (i = row; i < term.row; i++)
+ free(term.line[i]);
+
+ /* resize to new height */
+ term.line = xrealloc(term.line, row * sizeof(Line));
+ /* allocate any new rows */
+ for (i = term.row; i < row; i++) {
+ term.line[i] = xmalloc(col * sizeof(Glyph));
+ for (j = 0; j < col; j++)
+ tclearglyph(&term.line[i][j], 0);
+ }
+ /* scroll down as much as height has increased */
+ rscrolldown(row - term.row);
+ }
+ /* update terminal size */
+ term.col = col, term.row = row;
+ /* reset scrolling region */
+ term.top = 0, term.bot = row - 1;
+ /* dirty all lines */
+ tfulldirt();
+}
+
+void
+tresizealt(int col, int row)
+{
+ int i, j;
+ #if SIXEL_PATCH
+ ImageList *im, *next;
+ #endif // SIXEL_PATCH
+
+ /* return if dimensions haven't changed */
+ if (term.col == col && term.row == row) {
+ tfulldirt();
+ return;
+ }
+ if (sel.alt)
+ selremove();
+ /* slide screen up if otherwise cursor would get out of the screen */
+ for (i = 0; i <= term.c.y - row; i++)
+ free(term.line[i]);
+ if (i > 0) {
+ /* ensure that both src and dst are not NULL */
+ memmove(term.line, term.line + i, row * sizeof(Line));
+ #if SIXEL_PATCH
+ scroll_images(-i);
+ #endif // SIXEL_PATCH
+ term.c.y = row - 1;
+ }
+ for (i += row; i < term.row; i++)
+ free(term.line[i]);
+ /* resize to new height */
+ term.line = xrealloc(term.line, row * sizeof(Line));
+ /* resize to new width */
+ for (i = 0; i < MIN(row, term.row); i++) {
+ term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph));
+ for (j = term.col; j < col; j++)
+ tclearglyph(&term.line[i][j], 0);
+ }
+ /* allocate any new rows */
+ for (/*i = MIN(row, term.row) */; i < row; i++) {
+ term.line[i] = xmalloc(col * sizeof(Glyph));
+ for (j = 0; j < col; j++)
+ tclearglyph(&term.line[i][j], 0);
+ }
+ /* update cursor */
+ if (term.c.x >= col) {
+ term.c.state &= ~CURSOR_WRAPNEXT;
+ term.c.x = col - 1;
+ } else {
+ UPDATEWRAPNEXT(1, col);
+ }
+ /* update terminal size */
+ term.col = col, term.row = row;
+ /* reset scrolling region */
+ term.top = 0, term.bot = row - 1;
+
+ #if SIXEL_PATCH
+ /* delete or clip images if they are not inside the screen */
+ for (im = term.images; im; im = next) {
+ next = im->next;
+ if (im->x >= term.col || im->y >= term.row || im->y < 0) {
+ delete_image(im);
+ } else {
+ if ((im->cols = MIN(im->x + im->cols, term.col) - im->x) <= 0)
+ delete_image(im);
+ }
+ }
+ #endif // SIXEL_PATCH
+
+ /* dirty all lines */
+ tfulldirt();
+}
+
+void
+kscrolldown(const Arg* a)
+{
+ int n = a->i;
+
+ if (!term.scr || IS_SET(MODE_ALTSCREEN))
+ return;
+
+ if (n < 0)
+ n = MAX(term.row / -n, 1);
+
+ if (n <= term.scr) {
+ term.scr -= n;
+ } else {
+ n = term.scr;
+ term.scr = 0;
+ }
+
+ if (sel.ob.x != -1 && !sel.alt)
+ selmove(-n); /* negate change in term.scr */
+ tfulldirt();
+
+ #if SIXEL_PATCH
+ scroll_images(-1*n);
+ #endif // SIXEL_PATCH
+
+ #if OPENURLONCLICK_PATCH
+ if (n > 0)
+ restoremousecursor();
+ #endif // OPENURLONCLICK_PATCH
+}
+
+void
+kscrollup(const Arg* a)
+{
+ int n = a->i;
+
+ if (!term.histf || IS_SET(MODE_ALTSCREEN))
+ return;
+
+ if (n < 0)
+ n = MAX(term.row / -n, 1);
+
+ if (term.scr + n <= term.histf) {
+ term.scr += n;
+ } else {
+ n = term.histf - term.scr;
+ term.scr = term.histf;
+ }
+
+ if (sel.ob.x != -1 && !sel.alt)
+ selmove(n); /* negate change in term.scr */
+ tfulldirt();
+
+ #if SIXEL_PATCH
+ scroll_images(n);
+ #endif // SIXEL_PATCH
+
+ #if OPENURLONCLICK_PATCH
+ if (n > 0)
+ restoremousecursor();
+ #endif // OPENURLONCLICK_PATCH
+}
+
+void
+tscrollup(int top, int bot, int n, int mode)
+{
+ #if OPENURLONCLICK_PATCH
+ restoremousecursor();
+ #endif //OPENURLONCLICK_PATCH
+
+ int i, j, s;
+ Line temp;
+ int alt = IS_SET(MODE_ALTSCREEN);
+ int savehist = !alt && top == 0 && mode != SCROLL_NOSAVEHIST;
+ int scr = alt ? 0 : term.scr;
+ #if SIXEL_PATCH
+ int itop = top + scr, ibot = bot + scr;
+ ImageList *im, *next;
+ #endif // SIXEL_PATCH
+
+ if (n <= 0)
+ return;
+ n = MIN(n, bot-top+1);
+
+ if (savehist) {
+ for (i = 0; i < n; i++) {
+ term.histi = (term.histi + 1) % HISTSIZE;
+ temp = term.hist[term.histi];
+ for (j = 0; j < term.col; j++)
+ tclearglyph(&temp[j], 1);
+ term.hist[term.histi] = term.line[i];
+ term.line[i] = temp;
+ }
+ term.histf = MIN(term.histf + n, HISTSIZE);
+ s = n;
+ if (term.scr) {
+ j = term.scr;
+ term.scr = MIN(j + n, HISTSIZE);
+ s = j + n - term.scr;
+ }
+ if (mode != SCROLL_RESIZE)
+ tfulldirt();
+ } else {
+ tclearregion(0, top, term.col-1, top+n-1, 1);
+ tsetdirt(top + scr, bot + scr);
+ }
+
+ for (i = top; i <= bot-n; i++) {
+ temp = term.line[i];
+ term.line[i] = term.line[i+n];
+ term.line[i+n] = temp;
+ }
+
+ #if SIXEL_PATCH
+ if (alt || !savehist) {
+ /* move images, if they are inside the scrolling region */
+ for (im = term.images; im; im = next) {
+ next = im->next;
+ if (im->y >= itop && im->y <= ibot) {
+ im->y -= n;
+ if (im->y < itop)
+ delete_image(im);
+ }
+ }
+ } else {
+ /* move images, if they are inside the scrolling region or scrollback */
+ for (im = term.images; im; im = next) {
+ next = im->next;
+ im->y -= scr;
+ if (im->y < 0) {
+ im->y -= n;
+ } else if (im->y >= top && im->y <= bot) {
+ im->y -= n;
+ if (im->y < top)
+ im->y -= top; // move to scrollback
+ }
+ if (im->y < -HISTSIZE)
+ delete_image(im);
+ else
+ im->y += term.scr;
+ }
+ }
+ #endif // SIXEL_PATCH
+
+ if (sel.ob.x != -1 && sel.alt == alt) {
+ if (!savehist) {
+ selscroll(top, bot, -n);
+ } else if (s > 0) {
+ selmove(-s);
+ if (-term.scr + sel.nb.y < -term.histf)
+ selremove();
+ }
+ }
+}
+
+void
+tscrolldown(int top, int n)
+{
+ #if OPENURLONCLICK_PATCH
+ restoremousecursor();
+ #endif //OPENURLONCLICK_PATCH
+
+ int i, bot = term.bot;
+ int scr = IS_SET(MODE_ALTSCREEN) ? 0 : term.scr;
+ int itop = top + scr, ibot = bot + scr;
+ Line temp;
+ #if SIXEL_PATCH
+ ImageList *im, *next;
+ #endif // SIXEL_PATCH
+
+ if (n <= 0)
+ return;
+ n = MIN(n, bot-top+1);
+
+ tsetdirt(top + scr, bot + scr);
+ tclearregion(0, bot-n+1, term.col-1, bot, 1);
+
+ for (i = bot; i >= top+n; i--) {
+ temp = term.line[i];
+ term.line[i] = term.line[i-n];
+ term.line[i-n] = temp;
+ }
+
+ #if SIXEL_PATCH
+ /* move images, if they are inside the scrolling region */
+ for (im = term.images; im; im = next) {
+ next = im->next;
+ if (im->y >= itop && im->y <= ibot) {
+ im->y += n;
+ if (im->y > ibot)
+ delete_image(im);
+ }
+ }
+ #endif // SIXEL_PATCH
+
+ if (sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN))
+ selscroll(top, bot, n);
+}
+
+void
+tresize(int col, int row)
+{
+ int *bp;
+
+ #if KEYBOARDSELECT_PATCH
+ if (row != term.row || col != term.col)
+ win.mode ^= kbds_keyboardhandler(XK_Escape, NULL, 0, 1);
+ #endif // KEYBOARDSELECT_PATCH
+
+ term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty));
+ term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs));
+ if (col > term.col) {
+ bp = term.tabs + term.col;
+ memset(bp, 0, sizeof(*term.tabs) * (col - term.col));
+ while (--bp > term.tabs && !*bp)
+ /* nothing */ ;
+ for (bp += tabspaces; bp < term.tabs + col; bp += tabspaces)
+ *bp = 1;
+ }
+
+ if (IS_SET(MODE_ALTSCREEN))
+ tresizealt(col, row);
+ else
+ tresizedef(col, row);
+}
+
+void
+tclearregion(int x1, int y1, int x2, int y2, int usecurattr)
+{
+ int x, y;
+
+ /* regionselected() takes relative coordinates */
+ if (regionselected(x1, y1+term.scr, x2, y2+term.scr))
+ selclear();
+
+ for (y = y1; y <= y2; y++) {
+ term.dirty[y] = 1;
+ for (x = x1; x <= x2; x++)
+ tclearglyph(&term.line[y][x], usecurattr);
+ }
+}
+
+void
+tnew(int col, int row)
+{
+ int i, j;
+ for (i = 0; i < 2; i++) {
+ term.line = xmalloc(row * sizeof(Line));
+ for (j = 0; j < row; j++)
+ term.line[j] = xmalloc(col * sizeof(Glyph));
+ term.col = col, term.row = row;
+ tswapscreen();
+ }
+ term.dirty = xmalloc(row * sizeof(*term.dirty));
+ term.tabs = xmalloc(col * sizeof(*term.tabs));
+ for (i = 0; i < HISTSIZE; i++)
+ term.hist[i] = xmalloc(col * sizeof(Glyph));
+ treset();
+}
+
+void
+tdeletechar(int n)
+{
+ int src, dst, size;
+ Line line;
+
+ if (n <= 0)
+ return;
+ dst = term.c.x;
+ src = MIN(term.c.x + n, term.col);
+ size = term.col - src;
+ if (size > 0) { /* otherwise src would point beyond the array
+ https://stackoverflow.com/questions/29844298 */
+ line = term.line[term.c.y];
+ memmove(&line[dst], &line[src], size * sizeof(Glyph));
+ }
+ tclearregion(dst + size, term.c.y, term.col - 1, term.c.y, 1);
+}
+
+void
+tinsertblank(int n)
+{
+ int src, dst, size;
+ Line line;
+
+ if (n <= 0)
+ return;
+ dst = MIN(term.c.x + n, term.col);
+ src = term.c.x;
+ size = term.col - dst;
+
+ if (size > 0) { /* otherwise dst would point beyond the array */
+ line = term.line[term.c.y];
+ memmove(&line[dst], &line[src], size * sizeof(Glyph));
+ }
+ tclearregion(src, term.c.y, dst - 1, term.c.y, 1);
+}
+
+int
+tlinelen(Line line)
+{
+ int i = term.col - 1;
+
+ /* We are using a different algorithm on the alt screen because an
+ * application might use spaces to clear the screen and in that case it is
+ * impossible to find the end of the line when every cell has the ATTR_SET
+ * attribute. The second algorithm is more accurate on the main screen and
+ * and we can use it there. */
+ if (IS_SET(MODE_ALTSCREEN))
+ for (; i >= 0 && !(line[i].mode & ATTR_WRAP) && line[i].u == ' '; i--);
+ else
+ for (; i >= 0 && !(line[i].mode & (ATTR_SET | ATTR_WRAP)); i--);
+
+ return i + 1;
+}
+
+int
+tiswrapped(Line line)
+{
+ int len = tlinelen(line);
+
+ return len > 0 && (line[len - 1].mode & ATTR_WRAP);
+}
+
+char *
+tgetglyphs(char *buf, const Glyph *gp, const Glyph *lgp)
+{
+ while (gp <= lgp)
+ if (gp->mode & ATTR_WDUMMY) {
+ gp++;
+ } else {
+ buf += utf8encode((gp++)->u, buf);
+ }
+ return buf;
+}
+
+size_t
+tgetline(char *buf, const Glyph *fgp)
+{
+ char *ptr;
+ const Glyph *lgp = &fgp[term.col - 1];
+
+ while (lgp > fgp && !(lgp->mode & (ATTR_SET | ATTR_WRAP)))
+ lgp--;
+ ptr = tgetglyphs(buf, fgp, lgp);
+ if (!(lgp->mode & ATTR_WRAP))
+ *(ptr++) = '\n';
+ return ptr - buf;
+}
+
+int
+regionselected(int x1, int y1, int x2, int y2)
+{
+ if (sel.ob.x == -1 || sel.mode == SEL_EMPTY ||
+ sel.alt != IS_SET(MODE_ALTSCREEN) || sel.nb.y > y2 || sel.ne.y < y1)
+ return 0;
+
+ return (sel.type == SEL_RECTANGULAR) ? sel.nb.x <= x2 && sel.ne.x >= x1
+ : (sel.nb.y != y2 || sel.nb.x <= x2) &&
+ (sel.ne.y != y1 || sel.ne.x >= x1);
+}
+
+int
+selected(int x, int y)
+{
+ return regionselected(x, y, x, y);
+}
+
+void
+selsnap(int *x, int *y, int direction)
+{
+ int newx, newy;
+ int rtop = 0, rbot = term.row - 1;
+ int delim, prevdelim, maxlen;
+ const Glyph *gp, *prevgp;
+
+ if (!IS_SET(MODE_ALTSCREEN))
+ rtop += -term.histf + term.scr, rbot += term.scr;
+
+ switch (sel.snap) {
+ case SNAP_WORD:
+ /*
+ * Snap around if the word wraps around at the end or
+ * beginning of a line.
+ */
+ maxlen = (TLINE(*y)[term.col-2].mode & ATTR_WRAP) ? term.col-1 : term.col;
+ LIMIT(*x, 0, maxlen - 1);
+ prevgp = &TLINE(*y)[*x];
+ prevdelim = ISDELIM(prevgp->u);
+ for (;;) {
+ newx = *x + direction;
+ newy = *y;
+ if (!BETWEEN(newx, 0, maxlen - 1)) {
+ newy += direction;
+ if (!BETWEEN(newy, rtop, rbot))
+ break;
+
+ if (!tiswrapped(TLINE(direction > 0 ? *y : newy)))
+ break;
+
+ maxlen = (TLINE(newy)[term.col-2].mode & ATTR_WRAP) ? term.col-1 : term.col;
+ newx = direction > 0 ? 0 : maxlen - 1;
+ }
+
+ gp = &TLINE(newy)[newx];
+ delim = ISDELIM(gp->u);
+ if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim
+ || (delim && gp->u != prevgp->u)))
+ break;
+
+ *x = newx;
+ *y = newy;
+ if (!(gp->mode & ATTR_WDUMMY)) {
+ prevgp = gp;
+ prevdelim = delim;
+ }
+ }
+ break;
+ case SNAP_LINE:
+ /*
+ * Snap around if the the previous line or the current one
+ * has set ATTR_WRAP at its end. Then the whole next or
+ * previous line will be selected.
+ */
+ *x = (direction < 0) ? 0 : term.col - 1;
+ if (direction < 0) {
+ for (; *y > rtop; *y -= 1) {
+ if (!tiswrapped(TLINE(*y-1)))
+ break;
+ }
+ } else if (direction > 0) {
+ for (; *y < rbot; *y += 1) {
+ if (!tiswrapped(TLINE(*y)))
+ break;
+ }
+ }
+ break;
+ }
+}
+
+void
+selscroll(int top, int bot, int n)
+{
+ /* turn absolute coordinates into relative */
+ top += term.scr, bot += term.scr;
+
+ if (BETWEEN(sel.nb.y, top, bot) != BETWEEN(sel.ne.y, top, bot)) {
+ selclear();
+ } else if (BETWEEN(sel.nb.y, top, bot)) {
+ selmove(n);
+ if (sel.nb.y < top || sel.ne.y > bot)
+ selclear();
+ }
+}
+
+void
+tswapscreen(void)
+{
+ static Line *altline;
+ static int altcol, altrow;
+ Line *tmpline = term.line;
+ int tmpcol = term.col, tmprow = term.row;
+ #if SIXEL_PATCH
+ ImageList *im = term.images;
+ #endif // SIXEL_PATCH
+
+ term.line = altline;
+ term.col = altcol, term.row = altrow;
+ altline = tmpline;
+ altcol = tmpcol, altrow = tmprow;
+ term.mode ^= MODE_ALTSCREEN;
+
+ #if SIXEL_PATCH
+ term.images = term.images_alt;
+ term.images_alt = im;
+ #endif // SIXEL_PATCH
+}
+
+char *
+getsel(void)
+{
+ char *str, *ptr;
+ int y, lastx, linelen;
+ const Glyph *gp, *lgp;
+
+ if (sel.ob.x == -1 || sel.alt != IS_SET(MODE_ALTSCREEN))
+ return NULL;
+
+ str = xmalloc((term.col + 1) * (sel.ne.y - sel.nb.y + 1) * UTF_SIZ);
+ ptr = str;
+
+ /* append every set & selected glyph to the selection */
+ for (y = sel.nb.y; y <= sel.ne.y; y++) {
+ Line line = TLINE(y);
+
+ if ((linelen = tlinelen(line)) == 0) {
+ *ptr++ = '\n';
+ continue;
+ }
+
+ if (sel.type == SEL_RECTANGULAR) {
+ gp = &line[sel.nb.x];
+ lastx = sel.ne.x;
+ } else {
+ gp = &line[sel.nb.y == y ? sel.nb.x : 0];
+ lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1;
+ }
+ lgp = &line[MIN(lastx, linelen-1)];
+
+ ptr = tgetglyphs(ptr, gp, lgp);
+ /*
+ * Copy and pasting of line endings is inconsistent
+ * in the inconsistent terminal and GUI world.
+ * The best solution seems like to produce '\n' when
+ * something is copied from st and convert '\n' to
+ * '\r', when something to be pasted is received by
+ * st.
+ * FIXME: Fix the computer world.
+ */
+ if ((y < sel.ne.y || lastx >= linelen) &&
+ (!(lgp->mode & ATTR_WRAP) || sel.type == SEL_RECTANGULAR))
+ *ptr++ = '\n';
+ }
+ *ptr = '\0';
+ return str;
+}
+
+void
+tdumpline(int n)
+{
+ char str[(term.col + 1) * UTF_SIZ];
+
+ tprinter(str, tgetline(str, &term.line[n][0]));
+}
diff --git a/patch/reflow.h b/patch/reflow.h
@@ -0,0 +1,44 @@
+#define TLINE(y) ( \
+ (y) < term.scr ? term.hist[(term.histi + (y) - term.scr + 1 + HISTSIZE) % HISTSIZE] \
+ : term.line[(y) - term.scr] \
+)
+
+#define TLINEABS(y) ( \
+ (y) < 0 ? term.hist[(term.histi + (y) + 1 + HISTSIZE) % HISTSIZE] : term.line[(y)] \
+)
+
+#define UPDATEWRAPNEXT(alt, col) do { \
+ if ((term.c.state & CURSOR_WRAPNEXT) && term.c.x + term.wrapcwidth[alt] < col) { \
+ term.c.x += term.wrapcwidth[alt]; \
+ term.c.state &= ~CURSOR_WRAPNEXT; \
+ } \
+} while (0);
+
+static int tiswrapped(Line line);
+static size_t tgetline(char *, const Glyph *);
+static inline int regionselected(int, int, int, int);
+static void tloaddefscreen(int, int);
+static void tloadaltscreen(int, int);
+static void selmove(int);
+static inline void tclearglyph(Glyph *, int);
+static void treflow(int, int);
+static void rscrolldown(int);
+static void tresizedef(int, int);
+static void tresizealt(int, int);
+void kscrolldown(const Arg *);
+void kscrollup(const Arg *);
+static void tscrollup(int, int, int, int);
+static void tclearregion(int, int, int, int, int);
+static void tdeletechar(int);
+static int tlinelen(Line len);
+static char * tgetglyphs(char *buf, const Glyph *gp, const Glyph *lgp);
+static void selscroll(int, int, int);
+
+typedef struct {
+ uint b;
+ uint mask;
+ void (*func)(const Arg *);
+ const Arg arg;
+} MouseKey;
+
+extern MouseKey mkeys[];
diff --git a/patch/rightclicktoplumb_st.c b/patch/rightclicktoplumb_st.c
@@ -0,0 +1,19 @@
+#if defined(__OpenBSD__)
+ #include <sys/sysctl.h>
+#endif
+
+int
+subprocwd(char *path)
+{
+#if defined(__linux)
+ if (snprintf(path, PATH_MAX, "/proc/%d/cwd", pid) < 0)
+ return -1;
+ return 0;
+#elif defined(__OpenBSD__)
+ size_t sz = PATH_MAX;
+ int name[3] = {CTL_KERN, KERN_PROC_CWD, pid};
+ if (sysctl(name, 3, path, &sz, 0, 0) == -1)
+ return -1;
+ return 0;
+#endif
+}
+\ No newline at end of file
diff --git a/patch/rightclicktoplumb_st.h b/patch/rightclicktoplumb_st.h
@@ -0,0 +1 @@
+int subprocwd(char *);
+\ No newline at end of file
diff --git a/patch/rightclicktoplumb_x.c b/patch/rightclicktoplumb_x.c
@@ -0,0 +1,25 @@
+#include <sys/wait.h>
+
+void
+plumb(char *sel)
+{
+ if (sel == NULL)
+ return;
+
+ char cwd[PATH_MAX];
+ pid_t child;
+
+ if (subprocwd(cwd) != 0)
+ return;
+
+ switch (child = fork()) {
+ case -1:
+ return;
+ case 0:
+ if (chdir(cwd) != 0)
+ exit(1);
+ if (execvp(plumb_cmd, (char *const []){plumb_cmd, sel, 0}) == -1)
+ exit(1);
+ exit(0);
+ }
+}
diff --git a/patch/rightclicktoplumb_x.h b/patch/rightclicktoplumb_x.h
@@ -0,0 +1 @@
+void plumb(char *);
+\ No newline at end of file
diff --git a/patch/scrollback.c b/patch/scrollback.c
@@ -0,0 +1,55 @@
+void
+kscrolldown(const Arg* a)
+{
+ int n = a->i;
+
+ if (n < 0)
+ n = term.row + n;
+
+ if (n > term.scr)
+ n = term.scr;
+
+ if (term.scr > 0) {
+ term.scr -= n;
+ selscroll(0, -n);
+ tfulldirt();
+ }
+
+ #if SIXEL_PATCH
+ scroll_images(-1*n);
+ #endif // SIXEL_PATCH
+
+ #if OPENURLONCLICK_PATCH
+ if (n > 0)
+ restoremousecursor();
+ #endif // OPENURLONCLICK_PATCH
+}
+
+void
+kscrollup(const Arg* a)
+{
+ int n = a->i;
+ if (n < 0)
+ n = term.row + n;
+
+ if (term.scr + n > term.histn)
+ n = term.histn - term.scr;
+
+ if (!n)
+ return;
+
+ if (term.scr <= HISTSIZE-n) {
+ term.scr += n;
+ selscroll(0, n);
+ tfulldirt();
+ }
+
+ #if SIXEL_PATCH
+ scroll_images(n);
+ #endif // SIXEL_PATCH
+
+ #if OPENURLONCLICK_PATCH
+ if (n > 0)
+ restoremousecursor();
+ #endif // OPENURLONCLICK_PATCH
+}
diff --git a/patch/scrollback.h b/patch/scrollback.h
@@ -0,0 +1,17 @@
+#define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - \
+ term.scr + HISTSIZE + 1) % HISTSIZE] : \
+ term.line[(y) - term.scr])
+
+void kscrolldown(const Arg *);
+void kscrollup(const Arg *);
+
+#if SCROLLBACK_MOUSE_PATCH || SCROLLBACK_MOUSE_ALTSCREEN_PATCH
+typedef struct {
+ uint b;
+ uint mask;
+ void (*func)(const Arg *);
+ const Arg arg;
+} MouseKey;
+
+extern MouseKey mkeys[];
+#endif // SCROLLBACK_MOUSE_PATCH / SCROLLBACK_MOUSE_ALTSCREEN_PATCH
diff --git a/patch/st_embedder_x.c b/patch/st_embedder_x.c
@@ -0,0 +1,50 @@
+static Window embed;
+
+void
+createnotify(XEvent *e)
+{
+ XWindowChanges wc;
+
+ if (embed || e->xcreatewindow.override_redirect)
+ return;
+
+ embed = e->xcreatewindow.window;
+
+ XReparentWindow(xw.dpy, embed, xw.win, 0, 0);
+ XSelectInput(xw.dpy, embed, PropertyChangeMask | StructureNotifyMask | EnterWindowMask);
+
+ XMapWindow(xw.dpy, embed);
+ sendxembed(XEMBED_EMBEDDED_NOTIFY, 0, xw.win, 0);
+
+ wc.width = win.w;
+ wc.height = win.h;
+ XConfigureWindow(xw.dpy, embed, CWWidth | CWHeight, &wc);
+
+ XSetInputFocus(xw.dpy, embed, RevertToParent, CurrentTime);
+}
+
+void
+destroynotify(XEvent *e)
+{
+ visibility(e);
+ if (embed == e->xdestroywindow.window) {
+ focus(e);
+ }
+}
+
+void
+sendxembed(long msg, long detail, long d1, long d2)
+{
+ XEvent e = { 0 };
+
+ e.xclient.window = embed;
+ e.xclient.type = ClientMessage;
+ e.xclient.message_type = xw.xembed;
+ e.xclient.format = 32;
+ e.xclient.data.l[0] = CurrentTime;
+ e.xclient.data.l[1] = msg;
+ e.xclient.data.l[2] = detail;
+ e.xclient.data.l[3] = d1;
+ e.xclient.data.l[4] = d2;
+ XSendEvent(xw.dpy, embed, False, NoEventMask, &e);
+}
diff --git a/patch/st_embedder_x.h b/patch/st_embedder_x.h
@@ -0,0 +1,7 @@
+#define XEMBED_EMBEDDED_NOTIFY 0
+#define XEMBED_WINDOW_ACTIVATE 1
+#define XEMBED_FOCUS_CURRENT 0
+
+static void createnotify(XEvent *e);
+static void destroynotify(XEvent *e);
+static void sendxembed(long msg, long detail, long d1, long d2);
+\ No newline at end of file
diff --git a/patch/st_include.c b/patch/st_include.c
@@ -0,0 +1,32 @@
+/* Patches */
+#if COPYURL_PATCH || COPYURL_HIGHLIGHT_SELECTED_URLS_PATCH
+#include "copyurl.c"
+#endif
+#if EXTERNALPIPE_PATCH
+#include "externalpipe.c"
+#endif
+#if ISO14755_PATCH
+#include "iso14755.c"
+#endif
+#if REFLOW_PATCH && KEYBOARDSELECT_PATCH
+#include "keyboardselect_reflow_st.c"
+#elif KEYBOARDSELECT_PATCH
+#include "keyboardselect_st.c"
+#endif
+#if RIGHTCLICKTOPLUMB_PATCH
+#include "rightclicktoplumb_st.c"
+#endif
+#if NEWTERM_PATCH
+#include "newterm.c"
+#endif
+#if REFLOW_PATCH
+#include "reflow.c"
+#elif SCROLLBACK_PATCH || SCROLLBACK_MOUSE_PATCH || SCROLLBACK_MOUSE_ALTSCREEN_PATCH
+#include "scrollback.c"
+#endif
+#if SYNC_PATCH
+#include "sync.c"
+#endif
+#if OSC7_PATCH
+#include "osc7.c"
+#endif
diff --git a/patch/st_include.h b/patch/st_include.h
@@ -0,0 +1,35 @@
+/* Patches */
+#if COPYURL_PATCH || COPYURL_HIGHLIGHT_SELECTED_URLS_PATCH
+#include "copyurl.h"
+#endif
+#if EXTERNALPIPE_PATCH
+#include "externalpipe.h"
+#endif
+#if ISO14755_PATCH
+#include "iso14755.h"
+#endif
+#if REFLOW_PATCH && KEYBOARDSELECT_PATCH
+#include "keyboardselect_reflow_st.h"
+#elif KEYBOARDSELECT_PATCH
+#include "keyboardselect_st.h"
+#endif
+#if OPENURLONCLICK_PATCH
+#include "openurlonclick.h"
+#endif
+#if RIGHTCLICKTOPLUMB_PATCH
+#include "rightclicktoplumb_st.h"
+#endif
+#if NEWTERM_PATCH
+#include "newterm.h"
+#endif
+#if REFLOW_PATCH
+#include "reflow.h"
+#elif SCROLLBACK_PATCH || SCROLLBACK_MOUSE_PATCH || SCROLLBACK_MOUSE_ALTSCREEN_PATCH
+#include "scrollback.h"
+#endif
+#if SYNC_PATCH
+#include "sync.h"
+#endif
+#if OSC7_PATCH
+#include "osc7.h"
+#endif
diff --git a/patch/sync.c b/patch/sync.c
@@ -0,0 +1,31 @@
+#include <time.h>
+struct timespec sutv;
+
+static void
+tsync_begin()
+{
+ clock_gettime(CLOCK_MONOTONIC, &sutv);
+ su = 1;
+}
+
+static void
+tsync_end()
+{
+ su = 0;
+}
+
+int
+tinsync(uint timeout)
+{
+ struct timespec now;
+ if (su && !clock_gettime(CLOCK_MONOTONIC, &now)
+ && TIMEDIFF(now, sutv) >= timeout)
+ su = 0;
+ return su;
+}
+
+int
+ttyread_pending()
+{
+ return twrite_aborted;
+}
+\ No newline at end of file
diff --git a/patch/sync.h b/patch/sync.h
@@ -0,0 +1,7 @@
+static int su = 0;
+static int twrite_aborted = 0;
+
+static void tsync_begin();
+static void tsync_end();
+int tinsync(uint timeout);
+int ttyread_pending();
+\ No newline at end of file
diff --git a/patch/x_include.c b/patch/x_include.c
@@ -0,0 +1,58 @@
+/* Patches */
+#if ALPHA_PATCH
+#include "alpha.c"
+#endif
+#if BACKGROUND_IMAGE_PATCH
+#include "background_image_x.c"
+#endif
+#if BOXDRAW_PATCH
+#include "boxdraw.c"
+#endif
+#if DRAG_AND_DROP_PATCH
+#include "drag-n-drop.c"
+#endif
+#if OPENCOPIED_PATCH
+#include "opencopied.c"
+#endif
+#if FIXKEYBOARDINPUT_PATCH
+#include "fixkeyboardinput.c"
+#endif
+#if FONT2_PATCH
+#include "font2.c"
+#endif
+#if FULLSCREEN_PATCH
+#include "fullscreen_x.c"
+#endif
+#if INVERT_PATCH
+#include "invert.c"
+#endif
+#if REFLOW_PATCH && KEYBOARDSELECT_PATCH
+#include "keyboardselect_reflow_x.c"
+#elif KEYBOARDSELECT_PATCH
+#include "keyboardselect_x.c"
+#endif
+#if NETWMICON_PATCH
+#include "netwmicon.c"
+#elif NETWMICON_FF_PATCH
+#include "netwmicon_ff.c"
+#elif NETWMICON_LEGACY_PATCH
+#include "netwmicon_legacy.c"
+#endif
+#if OPEN_SELECTED_TEXT_PATCH
+#include "openselectedtext.c"
+#endif
+#if OPENURLONCLICK_PATCH
+#include "openurlonclick.c"
+#endif
+#if RIGHTCLICKTOPLUMB_PATCH
+#include "rightclicktoplumb_x.c"
+#endif
+#if ST_EMBEDDER_PATCH
+#include "st_embedder_x.c"
+#endif
+#if XRESOURCES_PATCH
+#include "xresources.c"
+#endif
+#if OSC133_PATCH
+#include "osc133.c"
+#endif
diff --git a/patch/x_include.h b/patch/x_include.h
@@ -0,0 +1,52 @@
+/* Patches */
+#if ALPHA_PATCH
+#include "alpha.h"
+#endif
+#if BACKGROUND_IMAGE_PATCH
+#include "background_image_x.h"
+#endif
+#if BOXDRAW_PATCH
+#include "boxdraw.h"
+#endif
+#if DRAG_AND_DROP_PATCH
+#include "drag-n-drop.h"
+#endif
+#if OPENCOPIED_PATCH
+#include "opencopied.h"
+#endif
+#if FONT2_PATCH
+#include "font2.h"
+#endif
+#if FULLSCREEN_PATCH
+#include "fullscreen_x.h"
+#endif
+#if INVERT_PATCH
+#include "invert.h"
+#endif
+#if REFLOW_PATCH && KEYBOARDSELECT_PATCH
+#include "keyboardselect_reflow_st.h"
+#include "keyboardselect_reflow_x.h"
+#elif KEYBOARDSELECT_PATCH
+#include "keyboardselect_x.h"
+#endif
+#if NETWMICON_LEGACY_PATCH
+#include "netwmicon_icon.h"
+#endif
+#if NETWMICON_PATCH || NETWMICON_FF_PATCH || NETWMICON_LEGACY_PATCH
+#include "netwmicon.h"
+#endif
+#if OPEN_SELECTED_TEXT_PATCH
+#include "openselectedtext.h"
+#endif
+#if RIGHTCLICKTOPLUMB_PATCH
+#include "rightclicktoplumb_x.h"
+#endif
+#if ST_EMBEDDER_PATCH
+#include "st_embedder_x.h"
+#endif
+#if XRESOURCES_PATCH
+#include "xresources.h"
+#endif
+#if OSC133_PATCH
+#include "osc133.h"
+#endif
diff --git a/patch/xresources.c b/patch/xresources.c
@@ -0,0 +1,182 @@
+int
+resource_load(XrmDatabase db, char *name, enum resource_type rtype, void *dst)
+{
+ char **sdst = dst;
+ int *idst = dst;
+ float *fdst = dst;
+
+ char fullname[256];
+ char fullclass[256];
+ char *type;
+ XrmValue ret;
+
+ snprintf(fullname, sizeof(fullname), "%s.%s",
+ opt_name ? opt_name : "st", name);
+ snprintf(fullclass, sizeof(fullclass), "%s.%s",
+ opt_class ? opt_class : "St", name);
+ fullname[sizeof(fullname) - 1] = fullclass[sizeof(fullclass) - 1] = '\0';
+
+ XrmGetResource(db, fullname, fullclass, &type, &ret);
+ if (ret.addr == NULL || strncmp("String", type, 64))
+ return 1;
+
+ switch (rtype) {
+ case STRING:
+ /* Note: this leaks memory */
+ *sdst = strdup(ret.addr);
+ break;
+ case INTEGER:
+ *idst = strtoul(ret.addr, NULL, 10);
+ break;
+ case FLOAT:
+ *fdst = strtof(ret.addr, NULL);
+ break;
+ }
+ return 0;
+}
+
+#if XRESOURCES_XDEFAULTS_PATCH
+/* Returns an XrmDatabase that needs to be freed by the caller. */
+static XrmDatabase
+get_resources(Display *dpy)
+{
+ /*******************************************************************/
+ /* Adapted from rxvt-unicode-9.31 rxvttoolkit.C get_resources() */
+ /*******************************************************************/
+ char *homedir = getenv("HOME");
+ char fname[1024];
+
+ char *displayResource, *xe;
+ XrmDatabase rdb1;
+ XrmDatabase database = XrmGetStringDatabase("");
+
+ /* For ordering, see for example http://www.faqs.org/faqs/Xt-FAQ/ Subject: 20 */
+
+ /* 6. System wide per application default file. */
+
+ /* Add in $XAPPLRESDIR/St only; not bothering with XUSERFILESEARCHPATH */
+ if ((xe = getenv("XAPPLRESDIR")) || (xe = "/etc/X11/app-defaults"))
+ {
+ snprintf(fname, sizeof(fname), "%s/%s", xe, "St");
+
+ if ((rdb1 = XrmGetFileDatabase(fname)))
+ XrmMergeDatabases(rdb1, &database);
+ }
+
+ /* 5. User's per application default file. None. */
+
+ /* 4. User's defaults file. */
+ if (homedir)
+ {
+ snprintf(fname, sizeof(fname), "%s/.Xdefaults", homedir);
+
+ if ((rdb1 = XrmGetFileDatabase(fname)))
+ XrmMergeDatabases(rdb1, &database);
+ }
+
+ /* Get any Xserver Resources (xrdb). */
+ displayResource = XResourceManagerString(dpy);
+
+ if (displayResource)
+ {
+ if ((rdb1 = XrmGetStringDatabase(displayResource)))
+ XrmMergeDatabases(rdb1, &database);
+ }
+
+ /* Get screen specific resources. */
+ displayResource = XScreenResourceString(ScreenOfDisplay(dpy, DefaultScreen(dpy)));
+
+ if (displayResource)
+ {
+ if ((rdb1 = XrmGetStringDatabase(displayResource)))
+ XrmMergeDatabases(rdb1, &database);
+
+ XFree(displayResource);
+ }
+
+ /* 3. User's per host defaults file. */
+ /* Add in XENVIRONMENT file */
+ if ((xe = getenv("XENVIRONMENT")) && (rdb1 = XrmGetFileDatabase(xe)))
+ XrmMergeDatabases(rdb1, &database);
+ else if (homedir)
+ {
+ struct utsname un;
+
+ if (!uname(&un))
+ {
+ snprintf(fname, sizeof(fname), "%s/.Xdefaults-%s", homedir, un.nodename);
+
+ if ((rdb1 = XrmGetFileDatabase(fname)))
+ XrmMergeDatabases(rdb1, &database);
+ }
+ }
+
+ return database;
+}
+
+void
+config_init(Display *dpy)
+{
+ XrmDatabase db;
+ ResourcePref *p;
+
+ XrmInitialize();
+ db = get_resources(dpy);
+
+ for (p = resources; p < resources + LEN(resources); p++)
+ resource_load(db, p->name, p->type, p->dst);
+
+ XrmDestroyDatabase(db);
+}
+
+#else // !XRESOURCES_XDEFAULTS_PATCH
+
+void
+config_init(Display *dpy)
+{
+ char *resm;
+ XrmDatabase db;
+ ResourcePref *p;
+
+ XrmInitialize();
+
+ resm = XResourceManagerString(dpy);
+ if (!resm)
+ return;
+
+ db = XrmGetStringDatabase(resm);
+ if (!db)
+ return;
+
+ for (p = resources; p < resources + LEN(resources); p++)
+ resource_load(db, p->name, p->type, p->dst);
+
+ XrmDestroyDatabase(db);
+}
+#endif // XRESOURCES_XDEFAULTS_PATCH
+
+#if XRESOURCES_RELOAD_PATCH
+void
+reload_config(int sig)
+{
+ /* Recreate a Display object to have up to date Xresources entries */
+ Display *dpy;
+ if (!(dpy = XOpenDisplay(NULL)))
+ die("Can't open display\n");
+
+ config_init(dpy);
+ xloadcols();
+
+ /* nearly like zoomabs() */
+ xunloadfonts();
+ xloadfonts(font, 0); /* font <- config_init() */
+ #if FONT2_PATCH
+ xloadsparefonts();
+ #endif // FONT2_PATCH
+ cresize(0, 0);
+ redraw();
+ xhints();
+
+ XCloseDisplay(dpy);
+}
+#endif // XRESOURCES_RELOAD_PATCH
diff --git a/patch/xresources.h b/patch/xresources.h
@@ -0,0 +1,20 @@
+#include <X11/Xresource.h>
+#if XRESOURCES_XDEFAULTS_PATCH
+#include <sys/utsname.h>
+#endif // XRESOURCES_XDEFAULTS_PATCH
+
+/* Xresources preferences */
+enum resource_type {
+ STRING = 0,
+ INTEGER = 1,
+ FLOAT = 2
+};
+
+typedef struct {
+ char *name;
+ enum resource_type type;
+ void *dst;
+} ResourcePref;
+
+int resource_load(XrmDatabase, char *, enum resource_type, void *);
+void config_init(Display *dpy);
diff --git a/patches.def.h b/patches.def.h
@@ -0,0 +1,544 @@
+/*
+ * This file contains patch control flags.
+ *
+ * In principle you should be able to mix and match any patches
+ * you may want. In cases where patches are logically incompatible
+ * one patch may take precedence over the other as noted in the
+ * relevant descriptions.
+ */
+
+/* Patches */
+
+/* The alpha patch adds transparency for the terminal.
+ * You need to uncomment the corresponding line in config.mk to use the -lXrender library
+ * when including this patch.
+ * https://st.suckless.org/patches/alpha/
+ */
+#define ALPHA_PATCH 0
+
+/* The alpha focus highlight patch allows the user to specify two distinct opacity values or
+ * background colors in order to easily differentiate between focused and unfocused terminal
+ * windows. This depends on the alpha patch.
+ * https://github.com/juliusHuelsmann/st-focus/
+ * https://st.suckless.org/patches/alpha_focus_highlight/
+ */
+#define ALPHA_FOCUS_HIGHLIGHT_PATCH 0
+
+/* Adds gradient transparency to st, depends on the alpha patch.
+ * https://st.suckless.org/patches/gradient/
+ */
+#define ALPHA_GRADIENT_PATCH 0
+
+/* Allows for the initial size of the terminal to be specified as pixel width and height
+ * using the -G command line option. Can be combined with the anysize patch to also allow
+ * the window to be resized to any pixel size.
+ * https://st.suckless.org/patches/anygeometry/
+ */
+#define ANYGEOMETRY_PATCH 0
+
+/* This patch allows st to resize to any pixel size rather than snapping to character width/height.
+ * https://st.suckless.org/patches/anysize/
+ */
+#define ANYSIZE_PATCH 0
+
+/* A simple variant of the anysize patch that only changes the resize hints to allow the window to
+ * be resized to any size.
+ */
+#define ANYSIZE_SIMPLE_PATCH 0
+
+/* Draws a background image in farbfeld format in place of the defaultbg color allowing for pseudo
+ * transparency.
+ * https://st.suckless.org/patches/background_image/
+ */
+#define BACKGROUND_IMAGE_PATCH 0
+
+/* This patch adds the ability to reload the background image config when a SIGUSR1 signal is
+ * received, e.g.: killall -USR1 st
+ * Depends on the BACKGROUND_IMAGE_PATCH.
+ */
+#define BACKGROUND_IMAGE_RELOAD_PATCH 0
+
+/* This patch allows the use of a blinking cursor.
+ * Only cursor styles 0, 1, 3, 5, and 7 blink. Set cursorstyle accordingly.
+ * Cursor styles are defined here:
+ * https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h4-Functions-using-CSI-_-ordered-by-the-final-character-lparen-s-rparen:CSI-Ps-SP-q.1D81
+ * https://st.suckless.org/patches/blinking_cursor/
+ */
+#define BLINKING_CURSOR_PATCH 0
+
+/* By default bold text is rendered with a bold font in the bright variant of the current color.
+ * This patch makes bold text rendered simply as bold, leaving the color unaffected.
+ * https://st.suckless.org/patches/bold-is-not-bright/
+ */
+#define BOLD_IS_NOT_BRIGHT_PATCH 0
+
+/* This patch adds custom rendering of lines/blocks/braille characters for gapless alignment.
+ * https://st.suckless.org/patches/boxdraw/
+ */
+#define BOXDRAW_PATCH 0
+
+/* By default st only sets PRIMARY on selection.
+ * This patch makes st set CLIPBOARD on selection.
+ * https://st.suckless.org/patches/clipboard/
+ */
+#define CLIPBOARD_PATCH 0
+
+/* This patch allows st to be resized without cutting off text when the terminal window is
+ * made larger again. Text does not wrap when the terminal window is made smaller, you may
+ * also want to have a look at the reflow patch.
+ *
+ * https://github.com/bakkeby/st-flexipatch/issues/34
+ */
+#define COLUMNS_PATCH 0
+
+/* Select and copy the last URL displayed with Mod+l. Multiple invocations cycle through the
+ * available URLs.
+ * https://st.suckless.org/patches/copyurl/
+ */
+#define COPYURL_PATCH 0
+
+/* Select and copy the last URL displayed with Mod+l. Multiple invocations cycle through the
+ * available URLs. This variant also highlights the selected URLs.
+ * https://st.suckless.org/patches/copyurl/
+ */
+#define COPYURL_HIGHLIGHT_SELECTED_URLS_PATCH 0
+
+/* This patch adds support for CSI escape sequences 22 and 23, which save and
+ * restores the window title (for instance nvim does this when opening and closing).
+ * https://st.suckless.org/patches/csi_22_23/
+ */
+#define CSI_22_23_PATCH 0
+
+/* According to the specification (see link in BLINKING_CURSOR_PATCH) the "Set cursor style
+ * (DECSCUSR), VT520." escape sequences define both values of 0 and 1 as a blinking block,
+ * with 1 being the default.
+ *
+ * This patch allows the default cursor to be set when value 0 is used, as opposed to
+ * setting the cursor to a blinking block.
+ *
+ * This allows a command like this to restore the cursor to what st is configured with:
+ * $ echo -ne "\e[ q"
+ *
+ * While many terminal emulators do this it is not adhering to specification. xterm is an
+ * example terminal that sets a blinking block instead of the configured one, same as st.
+ */
+#define DEFAULT_CURSOR_PATCH 0
+
+/* Return BS on pressing backspace and DEL on pressing the delete key.
+ * https://st.suckless.org/patches/delkey/
+ */
+#define DELKEY_PATCH 0
+
+/* This patch adds the option of disabling bold fonts globally.
+ * https://st.suckless.org/patches/disable_bold_italic_fonts/
+ */
+#define DISABLE_BOLD_FONTS_PATCH 0
+
+/* This patch adds the option of disabling italic fonts globally.
+ * https://st.suckless.org/patches/disable_bold_italic_fonts/
+ */
+#define DISABLE_ITALIC_FONTS_PATCH 0
+
+/* This patch adds the option of disabling roman fonts globally.
+ * https://st.suckless.org/patches/disable_bold_italic_fonts/
+ */
+#define DISABLE_ROMAN_FONTS_PATCH 0
+
+/* Allows dragging a file into the terminal and have the path printed.
+ * https://st.suckless.org/patches/drag-n-drop
+ */
+#define DRAG_AND_DROP_PATCH 0
+
+/* This patch makes the cursor color the inverse of the current cell color.
+ * https://st.suckless.org/patches/dynamic-cursor-color/
+ */
+#define DYNAMIC_CURSOR_COLOR_PATCH 0
+
+/* This is a variant of the anysize patch that explicitly do not change the size increment hints,
+ * i.e. only keeping the dynamic padding which is the main thing the anysize patch introduces.
+ * In practice this means that the dynamic padding / anysize functionality only ever comes into
+ * effect when the size hints are intentionally ignored.
+ * An example of this would be dwm respecting the size hints of floating windows, but disrespecting
+ * the size hints when the window is tiled (provided that resizehints config is set to 0).
+ *
+ * Note that this patch depends on ANYSIZE_PATCH being enabled to have an effect.
+ */
+#define DYNAMIC_PADDING_PATCH 0
+
+/* Reading and writing st's screen through a pipe, e.g. pass info to dmenu.
+ * https://st.suckless.org/patches/externalpipe/
+ */
+#define EXTERNALPIPE_PATCH 0
+
+/* This patch improves and extends the externalpipe patch in two ways:
+ * - it prevents the reset of the signal handler set on SIGCHILD, when
+ * the forked process that executes the external process exits and
+ * - it adds the externalpipein function to redirect the standard output
+ * of the external command to the slave size of the pty, that is, as if
+ * the external program had been manually executed on the terminal
+ *
+ * It can be used to send desired escape sequences to the terminal with a
+ * keyboard shortcut. The patch was created to make use of the dynamic-colors
+ * tool that uses the OSC escape sequences to change the colors of the terminal.
+ *
+ * This patch depends on EXTERNALPIPE_PATCH being enabled.
+ *
+ * https://github.com/sos4nt/dynamic-colors
+ * https://lists.suckless.org/hackers/2004/17218.html
+ */
+#define EXTERNALPIPEIN_PATCH 0
+
+/* This patch allows command line applications to use all the fancy key combinations
+ * that are available to GUI applications.
+ * https://st.suckless.org/patches/fix_keyboard_input/
+ */
+#define FIXKEYBOARDINPUT_PATCH 0
+
+/* This patch allows you to add spare font besides the default. Some glyphs can be not present in
+ * the default font. For this glyphs st uses font-config and try to find them in font cache first.
+ * This patch append fonts defined in font2 variable to the beginning of the font cache.
+ * So they will be used first for glyphs that are absent in the default font.
+ * https://st.suckless.org/patches/font2/
+ */
+#define FONT2_PATCH 0
+
+/* This patch adds the ability to toggle st into fullscreen mode.
+ * Two key bindings are defined: F11 which is typical with other applications and Alt+Enter
+ * which matches the default xterm behavior.
+ * https://st.suckless.org/patches/fullscreen/
+ */
+#define FULLSCREEN_PATCH 0
+
+/* Hide the X cursor whenever a key is pressed and show it back when the mouse is moved in
+ * the terminal window.
+ * https://st.suckless.org/patches/hidecursor/
+ */
+#define HIDECURSOR_PATCH 0
+
+/* This patch hides the terminal cursor when the window loses focus (as opposed to showing a hollow
+ * cursor).
+ * https://www.reddit.com/r/suckless/comments/nvee8h/how_to_hide_cursor_in_st_is_there_a_patch_for_it/
+ */
+#define HIDE_TERMINAL_CURSOR_PATCH 0
+
+/* This patch adds a keybinding that lets you invert the current colorscheme of st.
+ * This provides a simple way to temporarily switch to a light colorscheme if you use a dark
+ * colorscheme or visa-versa.
+ * https://st.suckless.org/patches/invert/
+ */
+#define INVERT_PATCH 0
+
+/* Pressing the default binding Ctrl+Shift-i will popup dmenu, asking you to enter a unicode
+ * codepoint that will be converted to a glyph and then pushed to st.
+ * https://st.suckless.org/patches/iso14755/
+ */
+#define ISO14755_PATCH 0
+
+/* This patch allows you to select text on the terminal using keyboard shortcuts.
+ * NB: An improved variant of this patch is enabled if combined with the reflow patch.
+ *
+ * https://st.suckless.org/patches/keyboard_select/
+ */
+#define KEYBOARDSELECT_PATCH 0
+
+/* This patch adds support for drawing ligatures using the Harfbuzz library to transform
+ * original text of a single line to a list of glyphs with ligatures included.
+ * This patch depends on the Harfbuzz library and headers to compile.
+ * You need to uncomment the corresponding lines in config.mk to use the harfbuzz library
+ * when including this patch.
+ * https://github.com/cog1to/st-ligatures
+ * https://st.suckless.org/patches/ligatures/
+ */
+#define LIGATURES_PATCH 0
+
+/* This patch makes st ignore terminal color attributes by forcing display of the default
+ * foreground and background colors only - making for a monochrome look. Idea ref.
+ * https://www.reddit.com/r/suckless/comments/ixbx6z/how_to_use_black_and_white_only_for_st/
+ */
+#define MONOCHROME_PATCH 0
+
+/* This patch sets the _NET_WM_ICON X property with an icon that is read from a .png file.
+ * This patch depends on the GD Graphics Library and headers to compile.
+ * You need to uncomment the corresponding lines in config.mk to use the gd library.
+ *
+ * The default location for the .png file is:
+ * - /usr/local/share/pixmaps/st.png
+ *
+ * https://st.suckless.org/patches/netwmicon/
+ */
+#define NETWMICON_PATCH 0
+
+/* This patch sets the _NET_WM_ICON X property with an icon that is read from a farbfeld image.
+ * The benefit of this patch is that you do not need an additional dependency on an external
+ * library to read and convert the farbfeld image.
+ *
+ * The default location for the farbfeld image is:
+ * - /usr/local/share/pixmaps/st.ff
+ *
+ * Remember to change the ICONNAME in config.mk from st.png to st.ff when using this patch.
+ *
+ * Example command to convert a .png to farbfeld:
+ * $ png2ff < st.png > st.ff
+ *
+ * https://tools.suckless.org/farbfeld/
+ * https://github.com/bakkeby/patches/wiki/netwmicon/
+ */
+#define NETWMICON_FF_PATCH 0
+
+/* This patch sets the _NET_WM_ICON X property with a hardcoded icon for st. This is the
+ * original version that predates the version that reads the image from a .png file.
+ * https://st.suckless.org/patches/netwmicon/
+ */
+#define NETWMICON_LEGACY_PATCH 0
+
+/* This patch allows you to spawn a new st terminal using Ctrl-Shift-Return. It will have the
+ * same CWD (current working directory) as the original st instance.
+ * https://st.suckless.org/patches/newterm/
+ */
+#define NEWTERM_PATCH 0
+
+/* This patch will set the _MOTIF_WM_HINTS property for the st window which, if the window manager
+ * respects it, will show the st window without window decorations.
+ *
+ * In dwm, if the decoration hints patch is applied, then the st window will start out without a
+ * border. In GNOME and KDE the window should start without a window title.
+ */
+#define NO_WINDOW_DECORATIONS_PATCH 0
+
+/* Open contents of the clipboard in a user-defined browser.
+ * https://st.suckless.org/patches/open_copied_url/
+ */
+#define OPENCOPIED_PATCH 0
+
+/* Open the selected text using xdg-open.
+ * https://st.suckless.org/patches/open_selected_text/
+ */
+#define OPEN_SELECTED_TEXT_PATCH 0
+
+/* This patch allows for URLs to be opened directly when you click on them. This may not work with
+ * all terminal applications.
+ *
+ * https://www.reddit.com/r/suckless/comments/cc83om/st_open_url/
+ */
+#define OPENURLONCLICK_PATCH 0
+
+/* This patch allows st to fetch the current working directory through the OSC 7 escape
+ * sequence emitted by shells. Must be used with newterm patch.
+ *
+ * https://codeberg.org/dnkl/foot/wiki#spawning-new-terminal-instances-in-the-current-working-directory
+ * https://github.com/veltza/st-sx/commit/817865c2c6ed905af8849580e58bdcf399216fbd
+ */
+#define OSC7_PATCH 0
+
+/* This patch allows jumping between prompts by utilizing the OSC 133 escape sequence
+ * emitted by shells. Must be used with either reflow or scrollback patch.
+ *
+ * https://codeberg.org/dnkl/foot#jumping-between-prompts
+ */
+#define OSC133_PATCH 0
+
+/* Reflow.
+ * Allows st to be resized without cutting off text when the terminal window is made larger again.
+ * Text wraps when the terminal window is made smaller.
+ * Comes with scrollback.
+ */
+#define REFLOW_PATCH 0
+
+/* This patch allows you to specify a border that is relative in size to the width of a cell
+ * in the terminal.
+ * https://st.suckless.org/patches/relativeborder/
+ */
+#define RELATIVEBORDER_PATCH 0
+
+/* This patch allows you to right-click on some selected text to send it to the plumbing
+ * program of choice, e.g. open a file, view an image, open a URL.
+ * https://st.suckless.org/patches/right_click_to_plumb/
+ */
+#define RIGHTCLICKTOPLUMB_PATCH 0
+
+/* Scroll back through terminal output using Shift+{PageUp, PageDown}.
+ * https://st.suckless.org/patches/scrollback/
+ */
+#define SCROLLBACK_PATCH 0
+
+/* Scroll back through terminal output using Shift+MouseWheel.
+ * This variant depends on SCROLLBACK_PATCH being enabled.
+ * https://st.suckless.org/patches/scrollback/
+ */
+#define SCROLLBACK_MOUSE_PATCH 0
+
+/* Scroll back through terminal output using mouse wheel (when not in MODE_ALTSCREEN).
+ * This variant depends on SCROLLBACK_PATCH being enabled.
+ * https://st.suckless.org/patches/scrollback/
+ */
+#define SCROLLBACK_MOUSE_ALTSCREEN_PATCH 0
+
+/* This patch adds the two color-settings selectionfg and selectionbg to config.def.h.
+ * Those define the fore- and background colors which are used when text on the screen is selected
+ * with the mouse. This removes the default behaviour which would simply reverse the colors.
+ * https://st.suckless.org/patches/selectioncolors/
+ */
+#define SELECTION_COLORS_PATCH 0
+
+/* This patch works with selectioncolors and alpha patches to make selection
+ * background color transparent.
+ * https://st.suckless.org/patches/selectionbg-alpha/
+ */
+#define SELECTIONBG_ALPHA_PATCH 0
+
+/* This is the single drawable buffer patch as outlined in the FAQ to get images
+ * in w3m to display. While this patch does not break the alpha patch it images
+ * are not shown in w3m if the alpha patch is applied.
+ */
+#define SINGLE_DRAWABLE_BUFFER_PATCH 0
+
+/* This patch adds SIXEL graphics support for st.
+ * Note that patch/sixel.c/sixel_hls.c come from mintty, licensed under GPL.
+ * Known issues:
+ * - Rendering sixel graphics may cause unusual cursor placement, this is
+ * not specific to this variant of st - the same issue is present in
+ * the xterm implementation. This is likely an issue of sixel height
+ * not being detected correctly.
+ *
+ * Note that you need to uncomment the corresponding lines in config.mk when including this patch.
+ * This patch is incompatible with the W3M patch.
+ *
+ * https://gist.github.com/saitoha/70e0fdf22e3e8f63ce937c7f7da71809
+ */
+#define SIXEL_PATCH 0
+
+/* This patch allows clients to embed into the st window and is useful if you tend to
+ * start X applications from the terminal. For example:
+ *
+ * $ surf -e $WINDOWID
+ *
+ * The behavior is similar to Plan 9 where applications can take over windows.
+ * URL TBC
+ */
+#define ST_EMBEDDER_PATCH 0
+
+/* Use inverted defaultbg/fg for selection when bg/fg are the same.
+ * https://st.suckless.org/patches/spoiler/
+ */
+#define SPOILER_PATCH 0
+
+/* This patch changes the mouse shape to the global default when the running program subscribes
+ * for mouse events, for instance, in programs like ranger and fzf. It emulates the behaviour
+ * shown by vte terminals like termite.
+ * https://st.suckless.org/patches/swapmouse/
+ */
+#define SWAPMOUSE_PATCH 0
+
+/* This patch adds synchronized-updates/application-sync support in st.
+ * This will have no effect except when an application uses the synchronized-update escape
+ * sequences. With this patch nearly all cursor flicker is eliminated in tmux, and tmux detects
+ * it automatically via terminfo.
+ *
+ * Note: this patch alters st.info to promote support for extra escape sequences, which can
+ * potentially cause application misbehaviour if you do not use this patch. Try removing or
+ * commenting out the corresponding line in st.info if this is causing issues.
+ *
+ * https://st.suckless.org/patches/sync/
+ */
+#define SYNC_PATCH 0
+
+/* Instead of a default X cursor, use the xterm cursor from your cursor theme.
+ * You need to uncomment the corresponding line in config.mk to use the -lXcursor library
+ * when including this patch.
+ * https://st.suckless.org/patches/themed_cursor/
+ */
+#define THEMED_CURSOR_PATCH 0
+
+/* Adds support for special underlines.
+ *
+ * Example test command:
+ * $ echo -e "\e[4:3m\e[58:5:10munderline\e[0m"
+ * ^ ^ ^ ^ ^- sets terminal color 10
+ * | | | \- indicates that terminal colors should be used
+ * | | \- indicates that underline color is being set
+ * | \- sets underline style to curvy
+ * \- set underline
+ *
+ * Note: this patch alters st.info to promote support for extra escape sequences, which can
+ * potentially cause application misbehaviour if you do not use this patch. Try removing or
+ * commenting out the corresponding line in st.info if this is causing issues.
+ *
+ * https://st.suckless.org/patches/undercurl/
+ */
+#define UNDERCURL_PATCH 0
+
+/* Allows mouse scroll without modifier keys for regardless of alt screen using the external
+ * scroll program.
+ * https://st.suckless.org/patches/universcroll/
+ */
+#define UNIVERSCROLL_PATCH 0
+
+/* Use XftFontMatch in place of FcFontMatch.
+ *
+ * XftFontMatch calls XftDefaultSubstitute which configures various match properties according
+ * to the user's configured Xft defaults (xrdb) as well as according to the current display and
+ * screen. Most importantly, the screen DPI is computed [1]. Without this, st uses a "default"
+ * DPI of 75 [2].
+ *
+ * [1]: https://cgit.freedesktop.org/xorg/lib/libXft/tree/src/xftdpy.c?id=libXft-2.3.2#n535
+ * [2]: https://cgit.freedesktop.org/fontconfig/tree/src/fcdefault.c?id=2.11.1#n255
+ *
+ * https://git.suckless.org/st/commit/528241aa3835e2f1f052abeeaf891737712955a0.html
+ */
+#define USE_XFTFONTMATCH_PATCH 0
+
+/* Vertically center lines in the space available if you have set a larger chscale in config.h
+ * https://st.suckless.org/patches/vertcenter/
+ */
+#define VERTCENTER_PATCH 0
+
+/* Briefly inverts window content on terminal bell event.
+ * https://st.suckless.org/patches/visualbell/
+ */
+#define VISUALBELL_1_PATCH 0
+
+/* Adds support for w3m images.
+ * https://st.suckless.org/patches/w3m/
+ */
+#define W3M_PATCH 0
+
+/* Adds proper glyphs rendering in st allowing wide glyphs to be drawn as-is as opposed to
+ * smaller or cut glyphs being rendered.
+ * https://github.com/Dreomite/st/commit/e3b821dcb3511d60341dec35ee05a4a0abfef7f2
+ * https://www.reddit.com/r/suckless/comments/jt90ai/update_support_for_proper_glyph_rendering_in_st/
+ */
+#define WIDE_GLYPHS_PATCH 0
+
+/* There is a known issue that Google's Variable Fonts (VF) can end up with letter spacing
+ * that is too wide in programs that use Xft, for example Inconsolata v3.000.
+ *
+ * This is intended as a temporary patch / hack until (if) this is fixed in the Xft library
+ * itself.
+ *
+ * https://github.com/googlefonts/Inconsolata/issues/42#issuecomment-737508890
+ */
+#define WIDE_GLYPH_SPACING_PATCH 0
+
+/* This patch allows user to specify the initial path st should use as the working directory.
+ * https://st.suckless.org/patches/workingdir/
+ */
+#define WORKINGDIR_PATCH 0
+
+/* This patch adds the ability to configure st via Xresources. At startup, st will read and
+ * apply the resources named in the resources[] array in config.h.
+ * https://st.suckless.org/patches/xresources/
+ */
+#define XRESOURCES_PATCH 0
+
+/* This patch adds the ability to reload the Xresources config when a SIGUSR1 signal is received
+ * e.g.: killall -USR1 st
+ * Depends on the XRESOURCES_PATCH.
+ */
+#define XRESOURCES_RELOAD_PATCH 0
+
+/* This patch adds the ability to configure st via Xdefaults, in addition to Xresources,
+ * like the rxvt-unicode terminal. At startup, st will read and apply the system and user's
+ * local Xdefault files, the XServer's Xresources, and the screen and per-host Xdefaults.
+ * This patch depends on XRESOURCES_PATCH and is compatible with XRESOURCES_RELOAD_PATCH.
+ */
+#define XRESOURCES_XDEFAULTS_PATCH 0
diff --git a/patches.h b/patches.h
@@ -0,0 +1,248 @@
+/*
+ * This file contains patch control flags.
+ *
+ * In principle you should be able to mix and match any patches
+ * you may want. In cases where patches are logically incompatible
+ * one patch may take precedence over the other as noted in the
+ * relevant descriptions.
+ *
+ * Kris Yotam's st build - patches enabled:
+ * - alpha (transparency)
+ * - anygeometry (dynamic borders)
+ * - blinking_cursor
+ * - boxdraw
+ * - clipboard
+ * - columns (prevent text cut on resize)
+ * - copyurl
+ * - externalpipe
+ * - font2 (fallback fonts)
+ * - iso14755 (unicode input)
+ * - ligatures (HarfBuzz)
+ * - newterm
+ * - scrollback + scrollback_mouse
+ * - sixel (NEW - image support for manga-tui)
+ * - swapmouse
+ * - sync
+ * - xresources + xresources_reload (live reload)
+ */
+
+/* Patches */
+
+/* The alpha patch adds transparency for the terminal. */
+#define ALPHA_PATCH 1
+
+/* Alpha focus highlight - different opacity for focused/unfocused */
+#define ALPHA_FOCUS_HIGHLIGHT_PATCH 0
+
+/* Gradient transparency */
+#define ALPHA_GRADIENT_PATCH 0
+
+/* Initial size as pixel width/height using -G option */
+#define ANYGEOMETRY_PATCH 1
+
+/* Resize to any pixel size */
+#define ANYSIZE_PATCH 1
+
+/* Simple anysize variant */
+#define ANYSIZE_SIMPLE_PATCH 0
+
+/* Background image in farbfeld format */
+#define BACKGROUND_IMAGE_PATCH 0
+
+/* Background image reload on SIGUSR1 */
+#define BACKGROUND_IMAGE_RELOAD_PATCH 0
+
+/* Blinking cursor support */
+#define BLINKING_CURSOR_PATCH 1
+
+/* Bold is not bright */
+#define BOLD_IS_NOT_BRIGHT_PATCH 0
+
+/* Box drawing characters without font glyphs */
+#define BOXDRAW_PATCH 1
+
+/* Set CLIPBOARD on selection */
+#define CLIPBOARD_PATCH 1
+
+/* Resize without cutting off text */
+#define COLUMNS_PATCH 1
+
+/* Select and copy last URL with Mod+l */
+#define COPYURL_PATCH 1
+
+/* Copyurl with highlight */
+#define COPYURL_HIGHLIGHT_SELECTED_URLS_PATCH 0
+
+/* CSI 22/23 support */
+#define CSI_22_23_PATCH 0
+
+/* Default cursor on escape sequence 0 */
+#define DEFAULT_CURSOR_PATCH 0
+
+/* Return BS on backspace, DEL on delete */
+#define DELKEY_PATCH 0
+
+/* Disable bold fonts */
+#define DISABLE_BOLD_FONTS_PATCH 0
+
+/* Disable italic fonts */
+#define DISABLE_ITALIC_FONTS_PATCH 0
+
+/* Disable roman fonts */
+#define DISABLE_ROMAN_FONTS_PATCH 0
+
+/* Drag and drop files */
+#define DRAG_AND_DROP_PATCH 0
+
+/* Dynamic cursor color */
+#define DYNAMIC_CURSOR_COLOR_PATCH 0
+
+/* Dynamic padding with anysize */
+#define DYNAMIC_PADDING_PATCH 0
+
+/* External pipe support */
+#define EXTERNALPIPE_PATCH 1
+
+/* External pipe in */
+#define EXTERNALPIPEIN_PATCH 0
+
+/* Fix keyboard input */
+#define FIXKEYBOARDINPUT_PATCH 0
+
+/* Secondary font support (emoji fallback) */
+#define FONT2_PATCH 1
+
+/* Fullscreen toggle */
+#define FULLSCREEN_PATCH 0
+
+/* Hide cursor on keypress */
+#define HIDECURSOR_PATCH 0
+
+/* Hide terminal cursor on unfocus */
+#define HIDE_TERMINAL_CURSOR_PATCH 0
+
+/* Invert colorscheme keybinding */
+#define INVERT_PATCH 0
+
+/* Unicode input via dmenu */
+#define ISO14755_PATCH 1
+
+/* Keyboard select */
+#define KEYBOARDSELECT_PATCH 0
+
+/* HarfBuzz ligature support */
+#define LIGATURES_PATCH 1
+
+/* Monochrome mode */
+#define MONOCHROME_PATCH 0
+
+/* Window icon from PNG */
+#define NETWMICON_PATCH 0
+
+/* Window icon from farbfeld */
+#define NETWMICON_FF_PATCH 0
+
+/* Window icon legacy */
+#define NETWMICON_LEGACY_PATCH 0
+
+/* Spawn new terminal in current directory */
+#define NEWTERM_PATCH 1
+
+/* No window decorations */
+#define NO_WINDOW_DECORATIONS_PATCH 0
+
+/* Open copied URL in browser */
+#define OPENCOPIED_PATCH 0
+
+/* Open selected text */
+#define OPEN_SELECTED_TEXT_PATCH 0
+
+/* Open URL on click */
+#define OPENURLONCLICK_PATCH 0
+
+/* OSC 7 working directory */
+#define OSC7_PATCH 0
+
+/* OSC 133 prompt jumping */
+#define OSC133_PATCH 0
+
+/* Text reflow on resize */
+#define REFLOW_PATCH 0
+
+/* Relative border size */
+#define RELATIVEBORDER_PATCH 0
+
+/* Right click to plumb */
+#define RIGHTCLICKTOPLUMB_PATCH 0
+
+/* Scrollback support */
+#define SCROLLBACK_PATCH 1
+
+/* Scrollback with mouse wheel + Shift */
+#define SCROLLBACK_MOUSE_PATCH 1
+
+/* Scrollback mouse in alt screen */
+#define SCROLLBACK_MOUSE_ALTSCREEN_PATCH 1
+
+/* Custom selection colors */
+#define SELECTION_COLORS_PATCH 0
+
+/* Selection background alpha */
+#define SELECTIONBG_ALPHA_PATCH 0
+
+/* Single drawable buffer for w3m */
+#define SINGLE_DRAWABLE_BUFFER_PATCH 0
+
+/* SIXEL graphics support - for manga-tui! */
+#define SIXEL_PATCH 1
+
+/* Embed applications into st */
+#define ST_EMBEDDER_PATCH 0
+
+/* Spoiler mode */
+#define SPOILER_PATCH 0
+
+/* Swap mouse shape in programs */
+#define SWAPMOUSE_PATCH 1
+
+/* Synchronized updates */
+#define SYNC_PATCH 1
+
+/* Themed cursor from Xcursor */
+#define THEMED_CURSOR_PATCH 0
+
+/* Undercurl/special underlines */
+#define UNDERCURL_PATCH 0
+
+/* Universal scroll */
+#define UNIVERSCROLL_PATCH 0
+
+/* Use XftFontMatch */
+#define USE_XFTFONTMATCH_PATCH 0
+
+/* Vertical center lines */
+#define VERTCENTER_PATCH 0
+
+/* Visual bell */
+#define VISUALBELL_1_PATCH 0
+
+/* W3M images - incompatible with SIXEL */
+#define W3M_PATCH 0
+
+/* Wide glyphs rendering */
+#define WIDE_GLYPHS_PATCH 0
+
+/* Wide glyph spacing fix */
+#define WIDE_GLYPH_SPACING_PATCH 0
+
+/* Working directory option */
+#define WORKINGDIR_PATCH 0
+
+/* Xresources support */
+#define XRESOURCES_PATCH 1
+
+/* Xresources reload on SIGUSR1 */
+#define XRESOURCES_RELOAD_PATCH 1
+
+/* Xdefaults support */
+#define XRESOURCES_XDEFAULTS_PATCH 0
diff --git a/sixel.c b/sixel.c
@@ -0,0 +1,700 @@
+// sixel.c (part of mintty)
+// originally written by kmiya@cluti (https://github.com/saitoha/sixel/blob/master/fromsixel.c)
+// Licensed under the terms of the GNU General Public License v3 or later.
+
+#include <stdlib.h>
+#include <string.h> /* memcpy */
+
+#include "st.h"
+#include "win.h"
+#include "sixel.h"
+#include "sixel_hls.h"
+
+#define SIXEL_RGB(r, g, b) ((255 << 24) + ((r) << 16) + ((g) << 8) + (b))
+#define SIXEL_PALVAL(n,a,m) (((n) * (a) + ((m) / 2)) / (m))
+#define SIXEL_XRGB(r,g,b) SIXEL_RGB(SIXEL_PALVAL(r, 255, 100), SIXEL_PALVAL(g, 255, 100), SIXEL_PALVAL(b, 255, 100))
+
+static sixel_color_t const sixel_default_color_table[] = {
+ SIXEL_XRGB( 0, 0, 0), /* 0 Black */
+ SIXEL_XRGB(20, 20, 80), /* 1 Blue */
+ SIXEL_XRGB(80, 13, 13), /* 2 Red */
+ SIXEL_XRGB(20, 80, 20), /* 3 Green */
+ SIXEL_XRGB(80, 20, 80), /* 4 Magenta */
+ SIXEL_XRGB(20, 80, 80), /* 5 Cyan */
+ SIXEL_XRGB(80, 80, 20), /* 6 Yellow */
+ SIXEL_XRGB(53, 53, 53), /* 7 Gray 50% */
+ SIXEL_XRGB(26, 26, 26), /* 8 Gray 25% */
+ SIXEL_XRGB(33, 33, 60), /* 9 Blue* */
+ SIXEL_XRGB(60, 26, 26), /* 10 Red* */
+ SIXEL_XRGB(33, 60, 33), /* 11 Green* */
+ SIXEL_XRGB(60, 33, 60), /* 12 Magenta* */
+ SIXEL_XRGB(33, 60, 60), /* 13 Cyan* */
+ SIXEL_XRGB(60, 60, 33), /* 14 Yellow* */
+ SIXEL_XRGB(80, 80, 80), /* 15 Gray 75% */
+};
+
+void
+scroll_images(int n) {
+ ImageList *im, *next;
+ #if SCROLLBACK_PATCH || REFLOW_PATCH
+ int top = tisaltscr() ? 0 : term.scr - HISTSIZE;
+ #else
+ int top = 0;
+ #endif // SCROLLBACK_PATCH
+
+ for (im = term.images; im; im = next) {
+ next = im->next;
+ im->y += n;
+
+ /* check if the current sixel has exceeded the maximum
+ * draw distance, and should therefore be deleted */
+ if (im->y < top) {
+ //fprintf(stderr, "im@0x%08x exceeded maximum distance\n");
+ delete_image(im);
+ }
+ }
+}
+
+void
+delete_image(ImageList *im)
+{
+ if (im->prev)
+ im->prev->next = im->next;
+ else
+ term.images = im->next;
+ if (im->next)
+ im->next->prev = im->prev;
+ if (im->pixmap)
+ XFreePixmap(xw.dpy, (Drawable)im->pixmap);
+ if (im->clipmask)
+ XFreePixmap(xw.dpy, (Drawable)im->clipmask);
+ free(im->pixels);
+ free(im);
+}
+
+static int
+set_default_color(sixel_image_t *image)
+{
+ int i;
+ int n;
+ int r;
+ int g;
+ int b;
+
+ /* palette initialization */
+ for (n = 1; n < 17; n++) {
+ image->palette[n] = sixel_default_color_table[n - 1];
+ }
+
+ /* colors 17-232 are a 6x6x6 color cube */
+ for (r = 0; r < 6; r++) {
+ for (g = 0; g < 6; g++) {
+ for (b = 0; b < 6; b++) {
+ image->palette[n++] = SIXEL_RGB(r * 51, g * 51, b * 51);
+ }
+ }
+ }
+
+ /* colors 233-256 are a grayscale ramp, intentionally leaving out */
+ for (i = 0; i < 24; i++) {
+ image->palette[n++] = SIXEL_RGB(i * 11, i * 11, i * 11);
+ }
+
+ /* sixels rarely use more than 256 colors and if they do, they use a custom
+ * palette, so we don't need to initialize these colors */
+ /*
+ for (; n < DECSIXEL_PALETTE_MAX; n++) {
+ image->palette[n] = SIXEL_RGB(255, 255, 255);
+ }
+ */
+
+ return (0);
+}
+
+static int
+sixel_image_init(
+ sixel_image_t *image,
+ int width,
+ int height,
+ int fgcolor,
+ int bgcolor,
+ int use_private_register)
+{
+ int status = (-1);
+ size_t size;
+
+ size = (size_t)(width * height) * sizeof(sixel_color_no_t);
+ image->width = width;
+ image->height = height;
+ image->data = (sixel_color_no_t *)malloc(size);
+ image->ncolors = 2;
+ image->use_private_register = use_private_register;
+
+ if (image->data == NULL) {
+ status = (-1);
+ goto end;
+ }
+ memset(image->data, 0, size);
+
+ image->palette[0] = bgcolor;
+
+ if (image->use_private_register)
+ image->palette[1] = fgcolor;
+
+ image->palette_modified = 0;
+
+ status = (0);
+
+end:
+ return status;
+}
+
+
+static int
+image_buffer_resize(
+ sixel_image_t *image,
+ int width,
+ int height)
+{
+ int status = (-1);
+ size_t size;
+ sixel_color_no_t *alt_buffer;
+ int n;
+ int min_height;
+
+ size = (size_t)(width * height) * sizeof(sixel_color_no_t);
+ alt_buffer = (sixel_color_no_t *)malloc(size);
+ if (alt_buffer == NULL) {
+ /* free source image */
+ free(image->data);
+ image->data = NULL;
+ status = (-1);
+ goto end;
+ }
+
+ min_height = height > image->height ? image->height: height;
+ if (width > image->width) { /* if width is extended */
+ for (n = 0; n < min_height; ++n) {
+ /* copy from source image */
+ memcpy(alt_buffer + width * n,
+ image->data + image->width * n,
+ (size_t)image->width * sizeof(sixel_color_no_t));
+ /* fill extended area with background color */
+ memset(alt_buffer + width * n + image->width,
+ 0,
+ (size_t)(width - image->width) * sizeof(sixel_color_no_t));
+ }
+ } else {
+ for (n = 0; n < min_height; ++n) {
+ /* copy from source image */
+ memcpy(alt_buffer + width * n,
+ image->data + image->width * n,
+ (size_t)width * sizeof(sixel_color_no_t));
+ }
+ }
+
+ if (height > image->height) { /* if height is extended */
+ /* fill extended area with background color */
+ memset(alt_buffer + width * image->height,
+ 0,
+ (size_t)(width * (height - image->height)) * sizeof(sixel_color_no_t));
+ }
+
+ /* free source image */
+ free(image->data);
+
+ image->data = alt_buffer;
+ image->width = width;
+ image->height = height;
+
+ status = (0);
+
+end:
+ return status;
+}
+
+static void
+sixel_image_deinit(sixel_image_t *image)
+{
+ if (image->data)
+ free(image->data);
+ image->data = NULL;
+}
+
+int
+sixel_parser_init(sixel_state_t *st,
+ int transparent,
+ sixel_color_t fgcolor, sixel_color_t bgcolor,
+ unsigned char use_private_register,
+ int cell_width, int cell_height)
+{
+ int status = (-1);
+
+ st->state = PS_DECSIXEL;
+ st->pos_x = 0;
+ st->pos_y = 0;
+ st->max_x = 0;
+ st->max_y = 0;
+ st->attributed_pan = 2;
+ st->attributed_pad = 1;
+ st->attributed_ph = 0;
+ st->attributed_pv = 0;
+ st->transparent = transparent;
+ st->repeat_count = 1;
+ st->color_index = 16;
+ st->grid_width = cell_width;
+ st->grid_height = cell_height;
+ st->nparams = 0;
+ st->param = 0;
+
+ /* buffer initialization */
+ status = sixel_image_init(&st->image, 1, 1, fgcolor, transparent ? 0 : bgcolor, use_private_register);
+
+ return status;
+}
+
+int
+sixel_parser_set_default_color(sixel_state_t *st)
+{
+ return set_default_color(&st->image);
+}
+
+int
+sixel_parser_finalize(sixel_state_t *st, ImageList **newimages, int cx, int cy, int cw, int ch)
+{
+ sixel_image_t *image = &st->image;
+ int x, y;
+ sixel_color_no_t *src;
+ sixel_color_t *dst, color;
+ int w, h;
+ int i, j, cols, numimages;
+ char trans;
+ ImageList *im, *next, *tail;
+
+ if (!image->data)
+ return -1;
+
+ if (++st->max_x < st->attributed_ph)
+ st->max_x = st->attributed_ph;
+
+ if (++st->max_y < st->attributed_pv)
+ st->max_y = st->attributed_pv;
+
+ if (image->use_private_register && image->ncolors > 2 && !image->palette_modified) {
+ if (set_default_color(image) < 0)
+ return -1;
+ }
+
+ w = MIN(st->max_x, image->width);
+ h = MIN(st->max_y, image->height);
+
+ if ((numimages = (h + ch-1) / ch) <= 0)
+ return -1;
+
+ cols = (w + cw-1) / cw;
+
+ *newimages = NULL, tail = NULL;
+ for (y = 0, i = 0; i < numimages; i++) {
+ if ((im = malloc(sizeof(ImageList)))) {
+ if (!tail) {
+ *newimages = tail = im;
+ im->prev = im->next = NULL;
+ } else {
+ tail->next = im;
+ im->prev = tail;
+ im->next = NULL;
+ tail = im;
+ }
+ im->x = cx;
+ im->y = cy + i;
+ im->cols = cols;
+ im->width = w;
+ im->height = MIN(h - ch * i, ch);
+ im->pixels = malloc(im->width * im->height * 4);
+ im->pixmap = NULL;
+ im->clipmask = NULL;
+ im->cw = cw;
+ im->ch = ch;
+ }
+ if (!im || !im->pixels) {
+ for (im = *newimages; im; im = next) {
+ next = im->next;
+ if (im->pixels)
+ free(im->pixels);
+ free(im);
+ }
+ *newimages = NULL;
+ return -1;
+ }
+ dst = (sixel_color_t *)im->pixels;
+ for (trans = 0, j = 0; j < im->height && y < h; j++, y++) {
+ src = st->image.data + image->width * y;
+ for (x = 0; x < w; x++) {
+ color = st->image.palette[*src++];
+ trans |= (color == 0);
+ *dst++ = color;
+ }
+ }
+ im->transparent = (st->transparent && trans);
+ }
+
+ return numimages;
+}
+
+/* convert sixel data into indexed pixel bytes and palette data */
+int
+sixel_parser_parse(sixel_state_t *st, const unsigned char *p, size_t len)
+{
+ int n = 0;
+ int i;
+ int x;
+ int y;
+ int bits;
+ int sx;
+ int sy;
+ int c;
+ int pos;
+ int width;
+ const unsigned char *p0 = p, *p2 = p + len;
+ sixel_image_t *image = &st->image;
+ sixel_color_no_t *data, color_index;
+
+ if (!image->data)
+ st->state = PS_ERROR;
+
+ while (p < p2) {
+ switch (st->state) {
+ case PS_ESC:
+ goto end;
+
+ case PS_DECSIXEL:
+ switch (*p) {
+ case '\x1b':
+ st->state = PS_ESC;
+ break;
+ case '"':
+ st->param = 0;
+ st->nparams = 0;
+ st->state = PS_DECGRA;
+ p++;
+ break;
+ case '!':
+ st->param = 0;
+ st->nparams = 0;
+ st->state = PS_DECGRI;
+ p++;
+ break;
+ case '#':
+ st->param = 0;
+ st->nparams = 0;
+ st->state = PS_DECGCI;
+ p++;
+ break;
+ case '$':
+ /* DECGCR Graphics Carriage Return */
+ st->pos_x = 0;
+ p++;
+ break;
+ case '-':
+ /* DECGNL Graphics Next Line */
+ st->pos_x = 0;
+ if (st->pos_y < DECSIXEL_HEIGHT_MAX - 5 - 6)
+ st->pos_y += 6;
+ else
+ st->pos_y = DECSIXEL_HEIGHT_MAX + 1;
+ p++;
+ break;
+ default:
+ if (*p >= '?' && *p <= '~') { /* sixel characters */
+ if ((image->width < (st->pos_x + st->repeat_count) || image->height < (st->pos_y + 6))
+ && image->width < DECSIXEL_WIDTH_MAX && image->height < DECSIXEL_HEIGHT_MAX) {
+ sx = image->width * 2;
+ sy = image->height * 2;
+ while (sx < (st->pos_x + st->repeat_count) || sy < (st->pos_y + 6)) {
+ sx *= 2;
+ sy *= 2;
+ }
+
+ sx = MIN(sx, DECSIXEL_WIDTH_MAX);
+ sy = MIN(sy, DECSIXEL_HEIGHT_MAX);
+
+ if (image_buffer_resize(image, sx, sy) < 0) {
+ perror("sixel_parser_parse() failed");
+ st->state = PS_ERROR;
+ p++;
+ break;
+ }
+ }
+
+ if (st->color_index > image->ncolors)
+ image->ncolors = st->color_index;
+
+ if (st->pos_x + st->repeat_count > image->width)
+ st->repeat_count = image->width - st->pos_x;
+
+ if (st->repeat_count > 0 && st->pos_y + 5 < image->height) {
+ bits = *p - '?';
+ if (bits != 0) {
+ data = image->data + image->width * st->pos_y + st->pos_x;
+ width = image->width;
+ color_index = st->color_index;
+ if (st->repeat_count <= 1) {
+ if (bits & 0x01)
+ *data = color_index, n = 0;
+ data += width;
+ if (bits & 0x02)
+ *data = color_index, n = 1;
+ data += width;
+ if (bits & 0x04)
+ *data = color_index, n = 2;
+ data += width;
+ if (bits & 0x08)
+ *data = color_index, n = 3;
+ data += width;
+ if (bits & 0x10)
+ *data = color_index, n = 4;
+ if (bits & 0x20)
+ data[width] = color_index, n = 5;
+ if (st->max_x < st->pos_x)
+ st->max_x = st->pos_x;
+ } else {
+ /* st->repeat_count > 1 */
+ for (i = 0; bits; bits >>= 1, i++, data += width) {
+ if (bits & 1) {
+ data[0] = color_index;
+ data[1] = color_index;
+ for (x = 2; x < st->repeat_count; x++)
+ data[x] = color_index;
+ n = i;
+ }
+ }
+ if (st->max_x < (st->pos_x + st->repeat_count - 1))
+ st->max_x = st->pos_x + st->repeat_count - 1;
+ }
+ if (st->max_y < (st->pos_y + n))
+ st->max_y = st->pos_y + n;
+ }
+ }
+ if (st->repeat_count > 0)
+ st->pos_x += st->repeat_count;
+ st->repeat_count = 1;
+ }
+ p++;
+ break;
+ }
+ break;
+
+ case PS_DECGRA:
+ /* DECGRA Set Raster Attributes " Pan; Pad; Ph; Pv */
+ switch (*p) {
+ case '\x1b':
+ st->state = PS_ESC;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ st->param = st->param * 10 + *p - '0';
+ st->param = MIN(st->param, DECSIXEL_PARAMVALUE_MAX);
+ p++;
+ break;
+ case ';':
+ if (st->nparams < DECSIXEL_PARAMS_MAX)
+ st->params[st->nparams++] = st->param;
+ st->param = 0;
+ p++;
+ break;
+ default:
+ if (st->nparams < DECSIXEL_PARAMS_MAX)
+ st->params[st->nparams++] = st->param;
+ if (st->nparams > 0)
+ st->attributed_pad = st->params[0];
+ if (st->nparams > 1)
+ st->attributed_pan = st->params[1];
+ if (st->nparams > 2 && st->params[2] > 0)
+ st->attributed_ph = st->params[2];
+ if (st->nparams > 3 && st->params[3] > 0)
+ st->attributed_pv = st->params[3];
+
+ if (st->attributed_pan <= 0)
+ st->attributed_pan = 1;
+ if (st->attributed_pad <= 0)
+ st->attributed_pad = 1;
+
+ if (image->width < st->attributed_ph ||
+ image->height < st->attributed_pv) {
+ sx = MAX(image->width, st->attributed_ph);
+ sy = MAX(image->height, st->attributed_pv);
+
+ /* the height of the image buffer must be divisible by 6
+ * to avoid unnecessary resizing of the image buffer when
+ * parsing the last sixel line */
+ sy = (sy + 5) / 6 * 6;
+
+ sx = MIN(sx, DECSIXEL_WIDTH_MAX);
+ sy = MIN(sy, DECSIXEL_HEIGHT_MAX);
+
+ if (image_buffer_resize(image, sx, sy) < 0) {
+ perror("sixel_parser_parse() failed");
+ st->state = PS_ERROR;
+ break;
+ }
+ }
+ st->state = PS_DECSIXEL;
+ st->param = 0;
+ st->nparams = 0;
+ }
+ break;
+
+ case PS_DECGRI:
+ /* DECGRI Graphics Repeat Introducer ! Pn Ch */
+ switch (*p) {
+ case '\x1b':
+ st->state = PS_ESC;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ st->param = st->param * 10 + *p - '0';
+ st->param = MIN(st->param, DECSIXEL_PARAMVALUE_MAX);
+ p++;
+ break;
+ default:
+ st->repeat_count = MAX(st->param, 1);
+ st->state = PS_DECSIXEL;
+ st->param = 0;
+ st->nparams = 0;
+ break;
+ }
+ break;
+
+ case PS_DECGCI:
+ /* DECGCI Graphics Color Introducer # Pc; Pu; Px; Py; Pz */
+ switch (*p) {
+ case '\x1b':
+ st->state = PS_ESC;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ st->param = st->param * 10 + *p - '0';
+ st->param = MIN(st->param, DECSIXEL_PARAMVALUE_MAX);
+ p++;
+ break;
+ case ';':
+ if (st->nparams < DECSIXEL_PARAMS_MAX)
+ st->params[st->nparams++] = st->param;
+ st->param = 0;
+ p++;
+ break;
+ default:
+ st->state = PS_DECSIXEL;
+ if (st->nparams < DECSIXEL_PARAMS_MAX)
+ st->params[st->nparams++] = st->param;
+ st->param = 0;
+
+ if (st->nparams > 0) {
+ st->color_index = st->params[0];
+ if (st->color_index < 0)
+ st->color_index = 0;
+ else if (st->color_index >= DECSIXEL_PALETTE_MAX)
+ st->color_index = DECSIXEL_PALETTE_MAX - 1;
+ st->color_index++; /* offset by 1 (background) */
+ }
+
+ if (st->nparams > 4) {
+ st->image.palette_modified = 1;
+ if (st->params[1] == 1) {
+ /* HLS */
+ st->params[2] = MIN(st->params[2], 360);
+ st->params[3] = MIN(st->params[3], 100);
+ st->params[4] = MIN(st->params[4], 100);
+ image->palette[st->color_index]
+ = hls_to_rgb(st->params[2], st->params[3], st->params[4]);
+ } else if (st->params[1] == 2) {
+ /* RGB */
+ st->params[2] = MIN(st->params[2], 100);
+ st->params[3] = MIN(st->params[3], 100);
+ st->params[4] = MIN(st->params[4], 100);
+ image->palette[st->color_index]
+ = SIXEL_XRGB(st->params[2], st->params[3], st->params[4]);
+ }
+ }
+ break;
+ }
+ break;
+
+ case PS_ERROR:
+ if (*p == '\x1b') {
+ st->state = PS_ESC;
+ goto end;
+ }
+ p++;
+ break;
+ default:
+ break;
+ }
+ }
+
+end:
+ return p - p0;
+}
+
+void
+sixel_parser_deinit(sixel_state_t *st)
+{
+ if (st)
+ sixel_image_deinit(&st->image);
+}
+
+Pixmap
+sixel_create_clipmask(char *pixels, int width, int height)
+{
+ char c, *clipdata, *dst;
+ int b, i, n, y, w;
+ int msb = (XBitmapBitOrder(xw.dpy) == MSBFirst);
+ sixel_color_t *src = (sixel_color_t *)pixels;
+ Pixmap clipmask;
+
+ clipdata = dst = malloc((width+7)/8 * height);
+ if (!clipdata)
+ return (Pixmap)None;
+
+ for (y = 0; y < height; y++) {
+ for (w = width; w > 0; w -= n) {
+ n = MIN(w, 8);
+ if (msb) {
+ for (b = 0x80, c = 0, i = 0; i < n; i++, b >>= 1)
+ c |= (*src++) ? b : 0;
+ } else {
+ for (b = 0x01, c = 0, i = 0; i < n; i++, b <<= 1)
+ c |= (*src++) ? b : 0;
+ }
+ *dst++ = c;
+ }
+ }
+
+ clipmask = XCreateBitmapFromData(xw.dpy, xw.win, clipdata, width, height);
+ free(clipdata);
+ return clipmask;
+}
diff --git a/sixel.h b/sixel.h
@@ -0,0 +1,63 @@
+#ifndef SIXEL_H
+#define SIXEL_H
+
+#define DECSIXEL_PARAMS_MAX 16
+#define DECSIXEL_PALETTE_MAX 1024
+#define DECSIXEL_PARAMVALUE_MAX 65535
+#define DECSIXEL_WIDTH_MAX 4096
+#define DECSIXEL_HEIGHT_MAX 4096
+
+typedef unsigned short sixel_color_no_t;
+typedef unsigned int sixel_color_t;
+
+typedef struct sixel_image_buffer {
+ sixel_color_no_t *data;
+ int width;
+ int height;
+ sixel_color_t palette[DECSIXEL_PALETTE_MAX + 1];
+ sixel_color_no_t ncolors;
+ int palette_modified;
+ int use_private_register;
+} sixel_image_t;
+
+typedef enum parse_state {
+ PS_ESC = 1, /* ESC */
+ PS_DECSIXEL = 2, /* DECSIXEL body part ", $, -, ? ... ~ */
+ PS_DECGRA = 3, /* DECGRA Set Raster Attributes " Pan; Pad; Ph; Pv */
+ PS_DECGRI = 4, /* DECGRI Graphics Repeat Introducer ! Pn Ch */
+ PS_DECGCI = 5, /* DECGCI Graphics Color Introducer # Pc; Pu; Px; Py; Pz */
+ PS_ERROR = 6,
+} parse_state_t;
+
+typedef struct parser_context {
+ parse_state_t state;
+ int pos_x;
+ int pos_y;
+ int max_x;
+ int max_y;
+ int attributed_pan;
+ int attributed_pad;
+ int attributed_ph;
+ int attributed_pv;
+ int transparent;
+ int repeat_count;
+ int color_index;
+ int bgindex;
+ int grid_width;
+ int grid_height;
+ int param;
+ int nparams;
+ int params[DECSIXEL_PARAMS_MAX];
+ sixel_image_t image;
+} sixel_state_t;
+
+void scroll_images(int n);
+void delete_image(ImageList *im);
+int sixel_parser_init(sixel_state_t *st, int transparent, sixel_color_t fgcolor, sixel_color_t bgcolor, unsigned char use_private_register, int cell_width, int cell_height);
+int sixel_parser_parse(sixel_state_t *st, const unsigned char *p, size_t len);
+int sixel_parser_set_default_color(sixel_state_t *st);
+int sixel_parser_finalize(sixel_state_t *st, ImageList **newimages, int cx, int cy, int cw, int ch);
+void sixel_parser_deinit(sixel_state_t *st);
+Pixmap sixel_create_clipmask(char *pixels, int width, int height);
+
+#endif
diff --git a/sixel_hls.c b/sixel_hls.c
@@ -0,0 +1,115 @@
+// sixel.c (part of mintty)
+// this function is derived from a part of graphics.c
+// in Xterm pl#310 originally written by Ross Combs.
+//
+// Copyright 2013,2014 by Ross Combs
+//
+// All Rights Reserved
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// Except as contained in this notice, the name(s) of the above copyright
+// holders shall not be used in advertising or otherwise to promote the
+// sale, use or other dealings in this Software without prior written
+// authorization.
+
+#define SIXEL_RGB(r, g, b) ((255 << 24) + ((r) << 16) + ((g) << 8) + (b))
+
+int
+hls_to_rgb(int hue, int lum, int sat)
+{
+ double lv = lum / 100.0;
+ double sv = sat / 100.0;
+ double c, x, m, c2;
+ double r1, g1, b1;
+ int r, g, b, hs;
+
+ hue = (hue + 240) % 360;
+ if (sat == 0) {
+ r = g = b = lum * 255 / 100;
+ return SIXEL_RGB(r, g, b);
+ }
+
+ if ((c2 = ((2.0 * lv) - 1.0)) < 0.0) {
+ c2 = -c2;
+ }
+ if ((hs = (hue % 120) - 60) < 0) {
+ hs = -hs;
+ }
+ c = (1.0 - c2) * sv;
+ x = ((60 - hs) / 60.0) * c;
+ m = lv - 0.5 * c;
+
+ switch (hue / 60) {
+ case 0:
+ r1 = c;
+ g1 = x;
+ b1 = 0.0;
+ break;
+ case 1:
+ r1 = x;
+ g1 = c;
+ b1 = 0.0;
+ break;
+ case 2:
+ r1 = 0.0;
+ g1 = c;
+ b1 = x;
+ break;
+ case 3:
+ r1 = 0.0;
+ g1 = x;
+ b1 = c;
+ break;
+ case 4:
+ r1 = x;
+ g1 = 0.0;
+ b1 = c;
+ break;
+ case 5:
+ r1 = c;
+ g1 = 0.0;
+ b1 = x;
+ break;
+ default:
+ return SIXEL_RGB(255, 255, 255);
+ }
+
+ r = (int) ((r1 + m) * 255.0 + 0.5);
+ g = (int) ((g1 + m) * 255.0 + 0.5);
+ b = (int) ((b1 + m) * 255.0 + 0.5);
+
+ if (r < 0) {
+ r = 0;
+ } else if (r > 255) {
+ r = 255;
+ }
+ if (g < 0) {
+ g = 0;
+ } else if (g > 255) {
+ g = 255;
+ }
+ if (b < 0) {
+ b = 0;
+ } else if (b > 255) {
+ b = 255;
+ }
+ return SIXEL_RGB(r, g, b);
+}
diff --git a/sixel_hls.h b/sixel_hls.h
@@ -0,0 +1,7 @@
+/*
+ * Primary color hues:
+ * blue: 0 degrees
+ * red: 120 degrees
+ * green: 240 degrees
+ */
+int hls_to_rgb(int hue, int lum, int sat);
diff --git a/st.1 b/st.1
@@ -1,6 +1,6 @@
.TH ST 1 st\-VERSION
.SH NAME
-st \- simple terminal (Luke Smith (https://lukesmith.xyz)'s build)
+st \- simple terminal
.SH SYNOPSIS
.B st
.RB [ \-aiv ]
@@ -125,41 +125,6 @@ and all the remaining arguments are used as a command
even without it.
.SH SHORTCUTS
.TP
-.B Alt-j/k or Alt-Up/Down or Alt-Mouse Wheel
-Scroll up/down one line at a time.
-.TP
-.B Alt-u/d or Alt-Page Up/Page Down
-Scroll up/down one screen at a time.
-.TP
-.B Alt-Shift-k/j or Alt-Shift-Page Up/Page Down or Alt-Shift-Mouse Wheel
-Increase or decrease font size.
-.TP
-.B Alt-Home
-Reset to default font size.
-.TP
-.B Shift-Insert or Alt-v
-Paste from clipboard.
-.TP
-.B Alt-c
-Copy to clipboard.
-.TP
-.B Alt-p
-Paste/input primary selection.
-.TP
-.B Alt-l
-Show dmenu menu of all URLs on screen and choose one to open.
-.TP
-.B Alt-y
-Show dmenu menu of all URLs on screen and choose one to copy.
-.TP
-.B Alt-o
-Show dmenu menu of all recently run commands and copy the output of the chosen command to the clipboard.
-.I xclip
-required.
-.TP
-.B Alt-a/s
-Increase or decrease opacity/alpha value (make window more or less transparent).
-.TP
.B Break
Send a break in the serial line.
Break key is obtained in PC keyboards
@@ -177,9 +142,23 @@ Print the full screen to the
Print the selection to the
.I iofile.
.TP
-.B Alt-Ctrl
-Launch dmenu to enter a unicode codepoint and send the corresponding glyph
-to st.
+.B Ctrl-Shift-Page Up
+Increase font size.
+.TP
+.B Ctrl-Shift-Page Down
+Decrease font size.
+.TP
+.B Ctrl-Shift-Home
+Reset to default font size.
+.TP
+.B Ctrl-Shift-y
+Paste from primary selection (middle mouse button).
+.TP
+.B Ctrl-Shift-c
+Copy the selected text to the clipboard selection.
+.TP
+.B Ctrl-Shift-v
+Paste from the clipboard selection.
.SH CUSTOMIZATION
.B st
can be customized by creating a custom config.h and (re)compiling the source
@@ -191,7 +170,8 @@ See the LICENSE file for the terms of redistribution.
.SH SEE ALSO
.BR tabbed (1),
.BR utmp (1),
-.BR stty (1)
+.BR stty (1),
+.BR scroll (1)
.SH BUGS
See the TODO file in the distribution.
diff --git a/st.c b/st.c
@@ -21,6 +21,15 @@
#include "st.h"
#include "win.h"
+#if KEYBOARDSELECT_PATCH
+#include <X11/keysym.h>
+#include <X11/X.h>
+#endif // KEYBOARDSELECT_PATCH
+
+#if SIXEL_PATCH
+#include "sixel.h"
+#endif // SIXEL_PATCH
+
#if defined(__linux)
#include <pty.h>
#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
@@ -34,37 +43,44 @@
#define UTF_SIZ 4
#define ESC_BUF_SIZ (128*UTF_SIZ)
#define ESC_ARG_SIZ 16
+#if UNDERCURL_PATCH
+#define CAR_PER_ARG 4
+#endif // UNDERCURL_PATCH
#define STR_BUF_SIZ ESC_BUF_SIZ
#define STR_ARG_SIZ ESC_ARG_SIZ
-#define HISTSIZE 2000
+#define STR_TERM_ST "\033\\"
+#define STR_TERM_BEL "\007"
/* macros */
-#define IS_SET(flag) ((term.mode & (flag)) != 0)
-#define NUMMAXLEN(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1)
-#define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == '\177')
-#define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f))
-#define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
-#define ISDELIM(u) (u && wcschr(worddelimiters, u))
-#define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - \
- term.scr + HISTSIZE + 1) % HISTSIZE] : \
- term.line[(y) - term.scr])
-
-#define TLINE_HIST(y) ((y) <= HISTSIZE-term.row+2 ? term.hist[(y)] : term.line[(y-HISTSIZE+term.row-3)])
-
-/* constants */
-#define ISO14755CMD "dmenu -w \"$WINDOWID\" -p codepoint: </dev/null"
+#define IS_SET(flag) ((term.mode & (flag)) != 0)
+#define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == 0x7f)
+#define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f))
+#define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
+#define ISDELIM(u) (u && wcschr(worddelimiters, u))
enum term_mode {
- MODE_WRAP = 1 << 0,
- MODE_INSERT = 1 << 1,
- MODE_ALTSCREEN = 1 << 2,
- MODE_CRLF = 1 << 3,
- MODE_ECHO = 1 << 4,
- MODE_PRINT = 1 << 5,
- MODE_UTF8 = 1 << 6,
- MODE_SIXEL = 1 << 7,
+ MODE_WRAP = 1 << 0,
+ MODE_INSERT = 1 << 1,
+ MODE_ALTSCREEN = 1 << 2,
+ MODE_CRLF = 1 << 3,
+ MODE_ECHO = 1 << 4,
+ MODE_PRINT = 1 << 5,
+ MODE_UTF8 = 1 << 6,
+ #if SIXEL_PATCH
+ MODE_SIXEL = 1 << 7,
+ MODE_SIXEL_CUR_RT = 1 << 8,
+ MODE_SIXEL_SDM = 1 << 9
+ #endif // SIXEL_PATCH
};
+#if REFLOW_PATCH
+enum scroll_mode {
+ SCROLL_RESIZE = -1,
+ SCROLL_NOSAVEHIST = 0,
+ SCROLL_SAVEHIST = 1
+};
+#endif // REFLOW_PATCH
+
enum cursor_movement {
CURSOR_SAVE,
CURSOR_LOAD
@@ -89,22 +105,17 @@ enum charset {
enum escape_state {
ESC_START = 1,
ESC_CSI = 2,
- ESC_STR = 4, /* OSC, PM, APC */
+ ESC_STR = 4, /* DCS, OSC, PM, APC */
ESC_ALTCHARSET = 8,
ESC_STR_END = 16, /* a final string was encountered */
ESC_TEST = 32, /* Enter in test mode */
ESC_UTF8 = 64,
+ #if SIXEL_PATCH
ESC_DCS =128,
+ #endif // SIXEL_PATCH
};
typedef struct {
- Glyph attr; /* current char attributes */
- int x;
- int y;
- char state;
-} TCursor;
-
-typedef struct {
int mode;
int type;
int snap;
@@ -122,62 +133,48 @@ typedef struct {
int alt;
} Selection;
-/* Internal representation of the screen */
-typedef struct {
- int row; /* nb row */
- int col; /* nb col */
- int maxcol;
- Line *line; /* screen */
- Line *alt; /* alternate screen */
- Line hist[HISTSIZE]; /* history buffer */
- int histi; /* history index */
- int scr; /* scroll back */
- int *dirty; /* dirtyness of lines */
- TCursor c; /* cursor */
- int ocx; /* old cursor col */
- int ocy; /* old cursor row */
- int top; /* top scroll limit */
- int bot; /* bottom scroll limit */
- int mode; /* terminal mode flags */
- int esc; /* escape state flags */
- char trantbl[4]; /* charset table translation */
- int charset; /* current charset */
- int icharset; /* selected charset for sequence */
- int *tabs;
- struct timespec last_ximspot_update;
-} Term;
-
/* CSI Escape sequence structs */
/* ESC '[' [[ [<priv>] <arg> [;]] <mode> [<mode>]] */
typedef struct {
char buf[ESC_BUF_SIZ]; /* raw string */
- int len; /* raw string length */
+ size_t len; /* raw string length */
char priv;
int arg[ESC_ARG_SIZ];
int narg; /* nb of args */
char mode[2];
+ #if UNDERCURL_PATCH
+ int carg[ESC_ARG_SIZ][CAR_PER_ARG]; /* colon args */
+ #endif // UNDERCURL_PATCH
} CSIEscape;
/* STR Escape sequence structs */
/* ESC type [[ [<priv>] <arg> [;]] <mode>] ESC '\' */
typedef struct {
char type; /* ESC type ... */
- char buf[STR_BUF_SIZ]; /* raw string */
- int len; /* raw string length */
+ char *buf; /* allocated raw string */
+ size_t siz; /* allocation size */
+ size_t len; /* raw string length */
char *args[STR_ARG_SIZ];
int narg; /* nb of args */
+ char *term; /* terminator: ST or BEL */
} STREscape;
static void execsh(char *, char **);
-static char *getcwd_by_pid(pid_t pid);
static void stty(char **);
static void sigchld(int);
static void ttywriteraw(const char *, size_t);
static void csidump(void);
static void csihandle(void);
+#if SIXEL_PATCH
+static void dcshandle(void);
+#endif // SIXEL_PATCH
+#if UNDERCURL_PATCH
+static void readcolonargs(char **, int, int[][CAR_PER_ARG]);
+#endif // UNDERCURL_PATCH
static void csiparse(void);
static void csireset(void);
+static void osc_color_response(int, int, int);
static int eschandle(uchar);
static void strdump(void);
static void strhandle(void);
@@ -188,46 +185,63 @@ static void tprinter(char *, size_t);
static void tdumpsel(void);
static void tdumpline(int);
static void tdump(void);
+#if !REFLOW_PATCH
static void tclearregion(int, int, int, int);
+#endif // REFLOW_PATCH
static void tcursor(int);
+static void tresetcursor(void);
+#if !REFLOW_PATCH
static void tdeletechar(int);
+#endif // REFLOW_PATCH
+#if SIXEL_PATCH
+static void tdeleteimages(void);
+#endif // SIXEL_PATCH
static void tdeleteline(int);
static void tinsertblank(int);
static void tinsertblankline(int);
+#if !REFLOW_PATCH
static int tlinelen(int);
+#endif // REFLOW_PATCH
static void tmoveto(int, int);
static void tmoveato(int, int);
static void tnewline(int);
static void tputtab(int);
static void tputc(Rune);
static void treset(void);
+#if !REFLOW_PATCH
+#if SCROLLBACK_PATCH
static void tscrollup(int, int, int);
-static void tscrolldown(int, int, int);
+#else
+static void tscrollup(int, int);
+#endif // SCROLLBACK_PATCH
+#endif // REFLOW_PATCH
+static void tscrolldown(int, int);
static void tsetattr(const int *, int);
static void tsetchar(Rune, const Glyph *, int, int);
static void tsetdirt(int, int);
static void tsetscroll(int, int);
+#if SIXEL_PATCH
+static inline void tsetsixelattr(Line line, int x1, int x2);
+#endif // SIXEL_PATCH
static void tswapscreen(void);
static void tsetmode(int, int, const int *, int);
static int twrite(const char *, int, int);
-static void tfulldirt(void);
static void tcontrolcode(uchar );
static void tdectest(char );
static void tdefutf8(char);
static int32_t tdefcolor(const int *, int *, int);
static void tdeftran(char);
static void tstrsequence(uchar);
-
-static void drawregion(int, int, int, int);
-
static void selnormalize(void);
+#if !REFLOW_PATCH
static void selscroll(int, int);
+#endif // REFLOW_PATCH
static void selsnap(int *, int *, int);
static size_t utf8decode(const char *, Rune *, size_t);
-static Rune utf8decodebyte(char, size_t *);
-static char utf8encodebyte(Rune, size_t);
-static size_t utf8validate(Rune *, size_t);
+static inline Rune utf8decodebyte(char, size_t *);
+static inline char utf8encodebyte(Rune, size_t);
+static inline size_t utf8validate(Rune *, size_t);
static char *base64dec(const char *);
static char base64dec_getc(const char **);
@@ -235,19 +249,26 @@ static char base64dec_getc(const char **);
static ssize_t xwrite(int, const char *, size_t);
/* Globals */
-static Term term;
static Selection sel;
static CSIEscape csiescseq;
static STREscape strescseq;
static int iofd = 1;
static int cmdfd;
+#if EXTERNALPIPEIN_PATCH && EXTERNALPIPE_PATCH
+static int csdfd;
+#endif // EXTERNALPIPEIN_PATCH
static pid_t pid;
+#if SIXEL_PATCH
+sixel_state_t sixel_st;
+#endif // SIXEL_PATCH
static const uchar utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
static const uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
static const Rune utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000};
static const Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
+#include "patch/st_include.h"
+
ssize_t
xwrite(int fd, const char *s, size_t len)
{
@@ -288,8 +309,7 @@ xrealloc(void *p, size_t len)
char *
xstrdup(const char *s)
{
- char *p;
-
+ char *p;
if ((p = strdup(s)) == NULL)
die("strdup: %s\n", strerror(errno));
@@ -299,24 +319,27 @@ xstrdup(const char *s)
size_t
utf8decode(const char *c, Rune *u, size_t clen)
{
- size_t i, j, len, type;
+ size_t i, len;
Rune udecoded;
*u = UTF_INVALID;
if (!clen)
return 0;
udecoded = utf8decodebyte(c[0], &len);
- if (!BETWEEN(len, 1, UTF_SIZ))
+ if (!BETWEEN(len, 2, UTF_SIZ)) {
+ *u = (len == 1) ? udecoded : UTF_INVALID;
return 1;
- for (i = 1, j = 1; i < clen && j < len; ++i, ++j) {
- udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type);
- if (type != 0)
- return j;
}
- if (j < len)
+ clen = MIN(clen, len);
+ for (i = 1; i < clen; ++i) {
+ if ((c[i] & 0xC0) != 0x80)
+ return i;
+ udecoded = (udecoded << 6) | (c[i] & 0x3F);
+ }
+ if (i < len)
return 0;
- *u = udecoded;
- utf8validate(u, len);
+ *u = (!BETWEEN(udecoded, utfmin[len], utfmax[len]) || BETWEEN(udecoded, 0xD800, 0xDFFF))
+ ? UTF_INVALID : udecoded;
return len;
}
@@ -366,26 +389,12 @@ utf8validate(Rune *u, size_t i)
return i;
}
-static const char base64_digits[] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0,
- 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, -1, 0, 0, 0, 0, 1,
- 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
- 22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34,
- 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
char
base64dec_getc(const char **src)
{
- while (**src && !isprint(**src)) (*src)++;
- return *((*src)++);
+ while (**src && !isprint((unsigned char)**src))
+ (*src)++;
+ return **src ? *((*src)++) : '='; /* emulate padding if string ends */
}
char *
@@ -393,6 +402,13 @@ base64dec(const char *src)
{
size_t in_len = strlen(src);
char *result, *dst;
+ static const char base64_digits[256] = {
+ [43] = 62, 0, 0, 0, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
+ 0, 0, 0, -1, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0,
+ 0, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
+ };
if (in_len % 4)
in_len += 4 - (in_len % 4);
@@ -403,6 +419,10 @@ base64dec(const char *src)
int c = base64_digits[(unsigned char) base64dec_getc(&src)];
int d = base64_digits[(unsigned char) base64dec_getc(&src)];
+ /* invalid input. 'a' can be -1, e.g. if src is "\n" (c-str) */
+ if (a == -1 || b == -1)
+ break;
+
*dst++ = (a << 2) | ((b & 0x30) >> 4);
if (c == -1)
break;
@@ -423,33 +443,29 @@ selinit(void)
sel.ob.x = -1;
}
+#if !REFLOW_PATCH
int
tlinelen(int y)
{
int i = term.col;
+ #if SCROLLBACK_PATCH
if (TLINE(y)[i - 1].mode & ATTR_WRAP)
return i;
while (i > 0 && TLINE(y)[i - 1].u == ' ')
- --i;
-
- return i;
-}
-
-int
-tlinehistlen(int y)
-{
- int i = term.col;
-
- if (TLINE_HIST(y)[i - 1].mode & ATTR_WRAP)
+ --i;
+ #else
+ if (term.line[y][i - 1].mode & ATTR_WRAP)
return i;
- while (i > 0 && TLINE_HIST(y)[i - 1].u == ' ')
+ while (i > 0 && term.line[y][i - 1].u == ' ')
--i;
+ #endif // SCROLLBACK_PATCH
return i;
}
+#endif // REFLOW_PATCH
void
selstart(int col, int row, int snap)
@@ -488,8 +504,8 @@ selextend(int col, int row, int type, int done)
sel.oe.x = col;
sel.oe.y = row;
- selnormalize();
sel.type = type;
+ selnormalize();
if (oldey != sel.oe.y || oldex != sel.oe.x || oldtype != sel.type || sel.mode == SEL_EMPTY)
tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey));
@@ -518,13 +534,23 @@ selnormalize(void)
/* expand selection over line breaks */
if (sel.type == SEL_RECTANGULAR)
return;
+
+ #if REFLOW_PATCH
+ i = tlinelen(TLINE(sel.nb.y));
+ if (sel.nb.x > i)
+ sel.nb.x = i;
+ if (sel.ne.x >= tlinelen(TLINE(sel.ne.y)))
+ sel.ne.x = term.col - 1;
+ #else
i = tlinelen(sel.nb.y);
if (i < sel.nb.x)
sel.nb.x = i;
if (tlinelen(sel.ne.y) <= sel.ne.x)
sel.ne.x = term.col - 1;
+ #endif // REFLOW_PATCH
}
+#if !REFLOW_PATCH
int
selected(int x, int y)
{
@@ -540,7 +566,9 @@ selected(int x, int y)
&& (y != sel.nb.y || x >= sel.nb.x)
&& (y != sel.ne.y || x <= sel.ne.x);
}
+#endif // REFLOW_PATCH
+#if !REFLOW_PATCH
void
selsnap(int *x, int *y, int direction)
{
@@ -554,7 +582,11 @@ selsnap(int *x, int *y, int direction)
* Snap around if the word wraps around at the end or
* beginning of a line.
*/
+ #if SCROLLBACK_PATCH
prevgp = &TLINE(*y)[*x];
+ #else
+ prevgp = &term.line[*y][*x];
+ #endif // SCROLLBACK_PATCH
prevdelim = ISDELIM(prevgp->u);
for (;;) {
newx = *x + direction;
@@ -569,14 +601,22 @@ selsnap(int *x, int *y, int direction)
yt = *y, xt = *x;
else
yt = newy, xt = newx;
+ #if SCROLLBACK_PATCH
if (!(TLINE(yt)[xt].mode & ATTR_WRAP))
+ #else
+ if (!(term.line[yt][xt].mode & ATTR_WRAP))
+ #endif // SCROLLBACK_PATCH
break;
}
if (newx >= tlinelen(newy))
break;
+ #if SCROLLBACK_PATCH
gp = &TLINE(newy)[newx];
+ #else
+ gp = &term.line[newy][newx];
+ #endif // SCROLLBACK_PATCH
delim = ISDELIM(gp->u);
if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim
|| (delim && gp->u != prevgp->u)))
@@ -597,15 +637,23 @@ selsnap(int *x, int *y, int direction)
*x = (direction < 0) ? 0 : term.col - 1;
if (direction < 0) {
for (; *y > 0; *y += direction) {
- if (!(TLINE(*y-1)[term.col-1].mode
- & ATTR_WRAP)) {
+ #if SCROLLBACK_PATCH
+ if (!(TLINE(*y-1)[term.col-1].mode & ATTR_WRAP))
+ #else
+ if (!(term.line[*y-1][term.col-1].mode & ATTR_WRAP))
+ #endif // SCROLLBACK_PATCH
+ {
break;
}
}
} else if (direction > 0) {
for (; *y < term.row-1; *y += direction) {
- if (!(TLINE(*y)[term.col-1].mode
- & ATTR_WRAP)) {
+ #if SCROLLBACK_PATCH
+ if (!(TLINE(*y)[term.col-1].mode & ATTR_WRAP))
+ #else
+ if (!(term.line[*y][term.col-1].mode & ATTR_WRAP))
+ #endif // SCROLLBACK_PATCH
+ {
break;
}
}
@@ -613,7 +661,9 @@ selsnap(int *x, int *y, int direction)
break;
}
}
+#endif // REFLOW_PATCH
+#if !REFLOW_PATCH
char *
getsel(void)
{
@@ -628,20 +678,34 @@ getsel(void)
ptr = str = xmalloc(bufsize);
/* append every set & selected glyph to the selection */
- for (y = sel.nb.y; y <= sel.ne.y; y++) {
+ for (y = sel.nb.y; y <= sel.ne.y; y++)
+ {
if ((linelen = tlinelen(y)) == 0) {
*ptr++ = '\n';
continue;
}
if (sel.type == SEL_RECTANGULAR) {
+ #if SCROLLBACK_PATCH
gp = &TLINE(y)[sel.nb.x];
+ #else
+ gp = &term.line[y][sel.nb.x];
+ #endif // SCROLLBACK_PATCH
lastx = sel.ne.x;
} else {
+ #if SCROLLBACK_PATCH
gp = &TLINE(y)[sel.nb.y == y ? sel.nb.x : 0];
+ #else
+ gp = &term.line[y][sel.nb.y == y ? sel.nb.x : 0];
+ #endif // SCROLLBACK_PATCH
lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1;
}
+
+ #if SCROLLBACK_PATCH
last = &TLINE(y)[MIN(lastx, linelen-1)];
+ #else
+ last = &term.line[y][MIN(lastx, linelen-1)];
+ #endif // SCROLLBACK_PATCH
while (last >= gp && last->u == ' ')
--last;
@@ -661,21 +725,29 @@ getsel(void)
* st.
* FIXME: Fix the computer world.
*/
- if ((y < sel.ne.y || lastx >= linelen) && !(last->mode & ATTR_WRAP))
+ if ((y < sel.ne.y || lastx >= linelen)
+ && (!(last->mode & ATTR_WRAP) || sel.type == SEL_RECTANGULAR))
*ptr++ = '\n';
}
*ptr = 0;
return str;
}
+#endif // REFLOW_PATCH
void
selclear(void)
{
if (sel.ob.x == -1)
return;
+ selremove();
+ tsetdirt(sel.nb.y, sel.ne.y);
+}
+
+void
+selremove(void)
+{
sel.mode = SEL_IDLE;
sel.ob.x = -1;
- tsetdirt(sel.nb.y, sel.ne.y);
}
void
@@ -692,7 +764,7 @@ die(const char *errstr, ...)
void
execsh(char *cmd, char **args)
{
- char *sh, *prog;
+ char *sh, *prog, *arg;
const struct passwd *pw;
errno = 0;
@@ -706,13 +778,20 @@ execsh(char *cmd, char **args)
if ((sh = getenv("SHELL")) == NULL)
sh = (pw->pw_shell[0]) ? pw->pw_shell : cmd;
- if (args)
+ if (args) {
prog = args[0];
- else if (utmp)
+ arg = NULL;
+ } else if (scroll) {
+ prog = scroll;
+ arg = utmp ? utmp : sh;
+ } else if (utmp) {
prog = utmp;
- else
+ arg = NULL;
+ } else {
prog = sh;
- DEFAULT(args, ((char *[]) {prog, NULL}));
+ arg = NULL;
+ }
+ DEFAULT(args, ((char *[]) {prog, arg, NULL}));
unsetenv("COLUMNS");
unsetenv("LINES");
@@ -722,6 +801,7 @@ execsh(char *cmd, char **args)
setenv("SHELL", sh, 1);
setenv("HOME", pw->pw_dir, 1);
setenv("TERM", termname, 1);
+ setenv("COLORTERM", "truecolor", 1);
signal(SIGCHLD, SIG_DFL);
signal(SIGHUP, SIG_DFL);
@@ -740,17 +820,19 @@ sigchld(int a)
int stat;
pid_t p;
- if ((p = waitpid(pid, &stat, WNOHANG)) < 0)
- die("waiting for pid %hd failed: %s\n", pid, strerror(errno));
-
- if (pid != p)
- return;
-
- if (WIFEXITED(stat) && WEXITSTATUS(stat))
- die("child exited with status %d\n", WEXITSTATUS(stat));
- else if (WIFSIGNALED(stat))
- die("child terminated due to signal %d\n", WTERMSIG(stat));
- exit(0);
+ while ((p = waitpid(-1, &stat, WNOHANG)) > 0) {
+ if (p == pid) {
+ #if EXTERNALPIPEIN_PATCH && EXTERNALPIPE_PATCH
+ close(csdfd);
+ #endif // EXTERNALPIPEIN_PATCH
+
+ if (WIFEXITED(stat) && WEXITSTATUS(stat))
+ die("child exited with status %d\n", WEXITSTATUS(stat));
+ else if (WIFSIGNALED(stat))
+ die("child terminated due to signal %d\n", WTERMSIG(stat));
+ _exit(0);
+ }
+ }
}
void
@@ -781,6 +863,7 @@ int
ttynew(const char *line, char *cmd, const char *out, char **args)
{
int m, s;
+ struct sigaction sa;
if (out) {
term.mode |= MODE_PRINT;
@@ -811,15 +894,15 @@ ttynew(const char *line, char *cmd, const char *out, char **args)
break;
case 0:
close(iofd);
- close(m);
+ close(m);
setsid(); /* create a new process group */
dup2(s, 0);
dup2(s, 1);
dup2(s, 2);
if (ioctl(s, TIOCSCTTY, NULL) < 0)
die("ioctl TIOCSCTTY failed: %s\n", strerror(errno));
- if (s > 2)
- close(s);
+ if (s > 2)
+ close(s);
#ifdef __OpenBSD__
if (pledge("stdio getpw proc exec", NULL) == -1)
die("pledge\n");
@@ -828,12 +911,24 @@ ttynew(const char *line, char *cmd, const char *out, char **args)
break;
default:
#ifdef __OpenBSD__
+ #if RIGHTCLICKTOPLUMB_PATCH || OPENCOPIED_PATCH
+ if (pledge("stdio rpath tty proc ps exec", NULL) == -1)
+ #else
if (pledge("stdio rpath tty proc", NULL) == -1)
+ #endif // RIGHTCLICKTOPLUMB_PATCH
die("pledge\n");
#endif
+ #if EXTERNALPIPEIN_PATCH && EXTERNALPIPE_PATCH
+ csdfd = s;
+ cmdfd = m;
+ #else
close(s);
cmdfd = m;
- signal(SIGCHLD, sigchld);
+ #endif // EXTERNALPIPEIN_PATCH
+ memset(&sa, 0, sizeof(sa));
+ sigemptyset(&sa.sa_mask);
+ sa.sa_handler = sigchld;
+ sigaction(SIGCHLD, &sa, NULL);
break;
}
return cmdfd;
@@ -844,30 +939,42 @@ ttyread(void)
{
static char buf[BUFSIZ];
static int buflen = 0;
- int written;
- int ret;
+ int ret, written;
/* append read bytes to unprocessed bytes */
- if ((ret = read(cmdfd, buf+buflen, LEN(buf)-buflen)) < 0)
- die("couldn't read from shell: %s\n", strerror(errno));
- buflen += ret;
-
- written = twrite(buf, buflen, 0);
- buflen -= written;
- /* keep any uncomplete utf8 char for the next call */
- if (buflen > 0)
- memmove(buf, buf + written, buflen);
+ #if SYNC_PATCH
+ ret = twrite_aborted ? 1 : read(cmdfd, buf+buflen, LEN(buf)-buflen);
+ #else
+ ret = read(cmdfd, buf+buflen, LEN(buf)-buflen);
+ #endif // SYNC_PATCH
- return ret;
+ switch (ret) {
+ case 0:
+ exit(0);
+ case -1:
+ die("couldn't read from shell: %s\n", strerror(errno));
+ default:
+ #if SYNC_PATCH
+ buflen += twrite_aborted ? 0 : ret;
+ #else
+ buflen += ret;
+ #endif // SYNC_PATCH
+ written = twrite(buf, buflen, 0);
+ buflen -= written;
+ /* keep any incomplete UTF-8 byte sequence for the next call */
+ if (buflen > 0)
+ memmove(buf, buf + written, buflen);
+ return ret;
+ }
}
void
ttywrite(const char *s, size_t n, int may_echo)
{
const char *next;
- Arg arg = (Arg) { .i = term.scr };
-
- kscrolldown(&arg);
+ #if REFLOW_PATCH || SCROLLBACK_PATCH
+ kscrolldown(&((Arg){ .i = term.scr }));
+ #endif // SCROLLBACK_PATCH
if (may_echo && IS_SET(MODE_ECHO))
twrite(s, n, 1);
@@ -963,16 +1070,10 @@ ttyresize(int tw, int th)
}
void
-ttyhangup()
+ttyhangup(void)
{
- /* disable signal handler (fixes window not closing) */
- signal(SIGCHLD, SIG_IGN);
-
/* Send SIGHUP to shell */
kill(pid, SIGHUP);
-
- /* forcefully die */
- die("tty was hung up\n");
}
int
@@ -990,6 +1091,12 @@ tattrset(int attr)
return 0;
}
+int
+tisaltscr(void)
+{
+ return IS_SET(MODE_ALTSCREEN);
+}
+
void
tsetdirt(int top, int bot)
{
@@ -1010,17 +1117,38 @@ tsetdirtattr(int attr)
for (i = 0; i < term.row-1; i++) {
for (j = 0; j < term.col-1; j++) {
if (term.line[i][j].mode & attr) {
+ #if REFLOW_PATCH
+ term.dirty[i] = 1;
+ #else
tsetdirt(i, i);
+ #endif // REFLOW_PATCH
break;
}
}
}
}
+#if SIXEL_PATCH
+void
+tsetsixelattr(Line line, int x1, int x2)
+{
+ for (; x1 <= x2; x1++)
+ line[x1].mode |= ATTR_SIXEL;
+}
+#endif // SIXEL_PATCH
+
void
tfulldirt(void)
{
+ #if SYNC_PATCH
+ tsync_end();
+ #endif // SYNC_PATCH
+ #if REFLOW_PATCH
+ for (int i = 0; i < term.row; i++)
+ term.dirty[i] = 1;
+ #else
tsetdirt(0, term.row-1);
+ #endif // REFLOW_PATCH
}
void
@@ -1038,15 +1166,21 @@ tcursor(int mode)
}
void
+tresetcursor(void)
+{
+ term.c = (TCursor){ { .mode = ATTR_NULL, .fg = defaultfg, .bg = defaultbg },
+ .x = 0, .y = 0, .state = CURSOR_DEFAULT };
+}
+
+void
treset(void)
{
uint i;
+ #if REFLOW_PATCH
+ int x, y;
+ #endif // REFLOW_PATCH
- term.c = (TCursor){{
- .mode = ATTR_NULL,
- .fg = defaultfg,
- .bg = defaultbg
- }, .x = 0, .y = 0, .state = CURSOR_DEFAULT};
+ tresetcursor();
memset(term.tabs, 0, term.col * sizeof(*term.tabs));
for (i = tabspaces; i < term.col; i += tabspaces)
@@ -1056,110 +1190,97 @@ treset(void)
term.mode = MODE_WRAP|MODE_UTF8;
memset(term.trantbl, CS_USA, sizeof(term.trantbl));
term.charset = 0;
+ #if REFLOW_PATCH
+ term.histf = 0;
+ term.histi = 0;
+ term.scr = 0;
+ selremove();
+ #endif // REFLOW_PATCH
for (i = 0; i < 2; i++) {
+ #if REFLOW_PATCH
+ tcursor(CURSOR_SAVE); /* reset saved cursor */
+ for (y = 0; y < term.row; y++)
+ for (x = 0; x < term.col; x++)
+ tclearglyph(&term.line[y][x], 0);
+ #else
tmoveto(0, 0);
tcursor(CURSOR_SAVE);
+ #if COLUMNS_PATCH
+ tclearregion(0, 0, term.maxcol-1, term.row-1);
+ #else
tclearregion(0, 0, term.col-1, term.row-1);
+ #endif // COLUMNS_PATCH
+ #endif // REFLOW_PATCH
+ #if SIXEL_PATCH
+ tdeleteimages();
+ #endif // SIXEL_PATCH
tswapscreen();
}
+ #if REFLOW_PATCH
+ tfulldirt();
+ #endif // REFLOW_PATCH
}
+#if !REFLOW_PATCH
void
tnew(int col, int row)
{
term = (Term){ .c = { .attr = { .fg = defaultfg, .bg = defaultbg } } };
- clock_gettime(CLOCK_MONOTONIC, &term.last_ximspot_update);
tresize(col, row);
treset();
}
+#endif // REFLOW_PATCH
-int tisaltscr(void)
-{
- return IS_SET(MODE_ALTSCREEN);
-}
-
+#if !REFLOW_PATCH
void
tswapscreen(void)
{
Line *tmp = term.line;
+ #if SIXEL_PATCH
+ ImageList *im = term.images;
+ #endif // SIXEL_PATCH
term.line = term.alt;
term.alt = tmp;
+ #if SIXEL_PATCH
+ term.images = term.images_alt;
+ term.images_alt = im;
+ #endif // SIXEL_PATCH
term.mode ^= MODE_ALTSCREEN;
tfulldirt();
}
+#endif // REFLOW_PATCH
+#if !REFLOW_PATCH
void
-newterm(const Arg* a)
-{
- switch (fork()) {
- case -1:
- die("fork failed: %s\n", strerror(errno));
- break;
- case 0:
- chdir(getcwd_by_pid(pid));
- execlp("st", "./st", NULL);
- break;
- }
-}
-
-static char *getcwd_by_pid(pid_t pid) {
- char buf[32];
- snprintf(buf, sizeof buf, "/proc/%d/cwd", pid);
- return realpath(buf, NULL);
-}
-
-void
-kscrolldown(const Arg* a)
-{
- int n = a->i;
-
- if (n < 0)
- n = term.row + n;
-
- if (n > term.scr)
- n = term.scr;
-
- if (term.scr > 0) {
- term.scr -= n;
- selscroll(0, -n);
- tfulldirt();
- }
-}
-
-void
-kscrollup(const Arg* a)
+tscrolldown(int orig, int n)
{
- int n = a->i;
+ #if OPENURLONCLICK_PATCH
+ restoremousecursor();
+ #endif //OPENURLONCLICK_PATCH
- if (n < 0)
- n = term.row + n;
-
- if (term.scr <= HISTSIZE-n) {
- term.scr += n;
- selscroll(0, n);
- tfulldirt();
- }
-}
-
-void
-tscrolldown(int orig, int n, int copyhist)
-{
int i;
Line temp;
+ #if SIXEL_PATCH
+ int bot = term.bot;
+ #if SCROLLBACK_PATCH
+ int scr = IS_SET(MODE_ALTSCREEN) ? 0 : term.scr;
+ #else
+ int scr = 0;
+ #endif // SCROLLBACK_PATCH
+ int itop = orig + scr, ibot = bot + scr;
+ ImageList *im, *next;
+ #endif // SIXEL_PATCH
LIMIT(n, 0, term.bot-orig+1);
- if (copyhist) {
- term.histi = (term.histi - 1 + HISTSIZE) % HISTSIZE;
- temp = term.hist[term.histi];
- term.hist[term.histi] = term.line[term.bot];
- term.line[term.bot] = temp;
- }
-
tsetdirt(orig, term.bot-n);
+ #if COLUMNS_PATCH
+ tclearregion(0, term.bot-n+1, term.maxcol-1, term.bot);
+ #else
tclearregion(0, term.bot-n+1, term.col-1, term.bot);
+ #endif // COLUMNS_PATCH
for (i = term.bot; i >= orig+n; i--) {
temp = term.line[i];
@@ -1167,28 +1288,74 @@ tscrolldown(int orig, int n, int copyhist)
term.line[i-n] = temp;
}
+ #if SIXEL_PATCH
+ /* move images, if they are inside the scrolling region */
+ for (im = term.images; im; im = next) {
+ next = im->next;
+ if (im->y >= itop && im->y <= ibot) {
+ im->y += n;
+ if (im->y > ibot)
+ delete_image(im);
+ }
+ }
+ #endif // SIXEL_PATCH
+
+ #if SCROLLBACK_PATCH
+ if (term.scr == 0)
+ selscroll(orig, n);
+ #else
selscroll(orig, n);
+ #endif // SCROLLBACK_PATCH
}
+#endif // REFLOW_PATCH
+#if !REFLOW_PATCH
void
+#if SCROLLBACK_PATCH
tscrollup(int orig, int n, int copyhist)
+#else
+tscrollup(int orig, int n)
+#endif // SCROLLBACK_PATCH
{
+ #if OPENURLONCLICK_PATCH
+ restoremousecursor();
+ #endif //OPENURLONCLICK_PATCH
+
int i;
Line temp;
+ #if SIXEL_PATCH
+ int bot = term.bot;
+ #if SCROLLBACK_PATCH
+ int scr = IS_SET(MODE_ALTSCREEN) ? 0 : term.scr;
+ #else
+ int scr = 0;
+ #endif // SCROLLBACK_PATCH
+ int itop = orig + scr, ibot = bot + scr;
+ ImageList *im, *next;
+ #endif // SIXEL_PATCH
LIMIT(n, 0, term.bot-orig+1);
- if (copyhist) {
- term.histi = (term.histi + 1) % HISTSIZE;
- temp = term.hist[term.histi];
- term.hist[term.histi] = term.line[orig];
- term.line[orig] = temp;
- }
+ #if SCROLLBACK_PATCH
+ if (copyhist && !IS_SET(MODE_ALTSCREEN)) {
+ for (i = 0; i < n; i++) {
+ term.histi = (term.histi + 1) % HISTSIZE;
+ temp = term.hist[term.histi];
+ term.hist[term.histi] = term.line[orig+i];
+ term.line[orig+i] = temp;
+ }
+ term.histn = MIN(term.histn + n, HISTSIZE);
- if (term.scr > 0 && term.scr < HISTSIZE)
- term.scr = MIN(term.scr + n, HISTSIZE-1);
+ if (term.scr > 0 && term.scr < HISTSIZE)
+ term.scr = MIN(term.scr + n, HISTSIZE-1);
+ }
+ #endif // SCROLLBACK_PATCH
+ #if COLUMNS_PATCH
+ tclearregion(0, orig, term.maxcol-1, orig+n-1);
+ #else
tclearregion(0, orig, term.col-1, orig+n-1);
+ #endif // COLUMNS_PATCH
tsetdirt(orig+n, term.bot);
for (i = orig; i <= term.bot-n; i++) {
@@ -1197,38 +1364,79 @@ tscrollup(int orig, int n, int copyhist)
term.line[i+n] = temp;
}
+ #if SIXEL_PATCH
+ #if SCROLLBACK_PATCH
+ if (IS_SET(MODE_ALTSCREEN) || !copyhist || orig != 0) {
+ /* move images, if they are inside the scrolling region */
+ for (im = term.images; im; im = next) {
+ next = im->next;
+ if (im->y >= itop && im->y <= ibot) {
+ im->y -= n;
+ if (im->y < itop)
+ delete_image(im);
+ }
+ }
+ } else {
+ /* move images, if they are inside the scrolling region or scrollback */
+ for (im = term.images; im; im = next) {
+ next = im->next;
+ im->y -= scr;
+ if (im->y < 0) {
+ im->y -= n;
+ } else if (im->y >= orig && im->y <= bot) {
+ im->y -= n;
+ if (im->y < orig)
+ im->y -= orig; // move to scrollback
+ }
+ if (im->y < -HISTSIZE)
+ delete_image(im);
+ else
+ im->y += term.scr;
+ }
+ }
+ #else
+ /* move images, if they are inside the scrolling region */
+ for (im = term.images; im; im = next) {
+ next = im->next;
+ if (im->y >= itop && im->y <= ibot) {
+ im->y -= n;
+ if (im->y < itop)
+ delete_image(im);
+ }
+ }
+ #endif // SCROLLBACK_PATCH
+ #endif // SIXEL_PATCH
+
+ #if SCROLLBACK_PATCH
+ if (term.scr == 0)
+ selscroll(orig, -n);
+ #else
selscroll(orig, -n);
+ #endif // SCROLLBACK_PATCH
}
+#endif // REFLOW_PATCH
+#if !REFLOW_PATCH
void
selscroll(int orig, int n)
{
- if (sel.ob.x == -1)
+ if (sel.ob.x == -1 || sel.alt != IS_SET(MODE_ALTSCREEN))
return;
- if (BETWEEN(sel.ob.y, orig, term.bot) || BETWEEN(sel.oe.y, orig, term.bot)) {
- if ((sel.ob.y += n) > term.bot || (sel.oe.y += n) < term.top) {
+ if (BETWEEN(sel.nb.y, orig, term.bot) != BETWEEN(sel.ne.y, orig, term.bot)) {
+ selclear();
+ } else if (BETWEEN(sel.nb.y, orig, term.bot)) {
+ sel.ob.y += n;
+ sel.oe.y += n;
+ if (sel.ob.y < term.top || sel.ob.y > term.bot ||
+ sel.oe.y < term.top || sel.oe.y > term.bot) {
selclear();
- return;
- }
- if (sel.type == SEL_RECTANGULAR) {
- if (sel.ob.y < term.top)
- sel.ob.y = term.top;
- if (sel.oe.y > term.bot)
- sel.oe.y = term.bot;
} else {
- if (sel.ob.y < term.top) {
- sel.ob.y = term.top;
- sel.ob.x = 0;
- }
- if (sel.oe.y > term.bot) {
- sel.oe.y = term.bot;
- sel.oe.x = term.col;
- }
+ selnormalize();
}
- selnormalize();
}
}
+#endif // REFLOW_PATCH
void
tnewline(int first_col)
@@ -1236,18 +1444,49 @@ tnewline(int first_col)
int y = term.c.y;
if (y == term.bot) {
+ #if REFLOW_PATCH
+ tscrollup(term.top, term.bot, 1, SCROLL_SAVEHIST);
+ #elif SCROLLBACK_PATCH
tscrollup(term.top, 1, 1);
+ #else
+ tscrollup(term.top, 1);
+ #endif // SCROLLBACK_PATCH
} else {
y++;
}
tmoveto(first_col ? 0 : term.c.x, y);
}
+#if UNDERCURL_PATCH
+void
+readcolonargs(char **p, int cursor, int params[][CAR_PER_ARG])
+{
+ int i = 0;
+ for (; i < CAR_PER_ARG; i++)
+ params[cursor][i] = -1;
+
+ if (**p != ':')
+ return;
+
+ char *np = NULL;
+ i = 0;
+
+ while (**p == ':' && i < CAR_PER_ARG) {
+ while (**p == ':')
+ (*p)++;
+ params[cursor][i] = strtol(*p, &np, 10);
+ *p = np;
+ i++;
+ }
+}
+#endif // UNDERCURL_PATCH
+
void
csiparse(void)
{
char *p = csiescseq.buf, *np;
long int v;
+ int sep = ';'; /* colon or semi-colon, but not both */
csiescseq.narg = 0;
if (*p == '?') {
@@ -1265,7 +1504,12 @@ csiparse(void)
v = -1;
csiescseq.arg[csiescseq.narg++] = v;
p = np;
- if (*p != ';' || csiescseq.narg == ESC_ARG_SIZ)
+ #if UNDERCURL_PATCH
+ readcolonargs(&p, csiescseq.narg-1, csiescseq.carg);
+ #endif // UNDERCURL_PATCH
+ if (sep == ';' && *p == ':')
+ sep = ':'; /* allow override to colon once */
+ if (*p != sep || csiescseq.narg == ESC_ARG_SIZ)
break;
p++;
}
@@ -1298,7 +1542,7 @@ tmoveto(int x, int y)
}
void
-tsetchar(Rune u,const Glyph *attr, int x, int y)
+tsetchar(Rune u, const Glyph *attr, int x, int y)
{
static const char *vt100_0[62] = { /* 0x41 - 0x7e */
"↑", "↓", "→", "←", "█", "▚", "☃", /* A - G */
@@ -1331,11 +1575,17 @@ tsetchar(Rune u,const Glyph *attr, int x, int y)
term.dirty[y] = 1;
term.line[y][x] = *attr;
term.line[y][x].u = u;
+ #if REFLOW_PATCH
+ term.line[y][x].mode |= ATTR_SET;
+ #endif // REFLOW_PATCH
+ #if BOXDRAW_PATCH
if (isboxdraw(u))
term.line[y][x].mode |= ATTR_BOXDRAW;
+ #endif // BOXDRAW_PATCH
}
+#if !REFLOW_PATCH
void
tclearregion(int x1, int y1, int x2, int y2)
{
@@ -1347,8 +1597,13 @@ tclearregion(int x1, int y1, int x2, int y2)
if (y1 > y2)
temp = y1, y1 = y2, y2 = temp;
- LIMIT(x1, 0, term.maxcol-1);
+ #if COLUMNS_PATCH
+ LIMIT(x1, 0, term.maxcol-1);
LIMIT(x2, 0, term.maxcol-1);
+ #else
+ LIMIT(x1, 0, term.col-1);
+ LIMIT(x2, 0, term.col-1);
+ #endif // COLUMNS_PATCH
LIMIT(y1, 0, term.row-1);
LIMIT(y2, 0, term.row-1);
@@ -1365,7 +1620,9 @@ tclearregion(int x1, int y1, int x2, int y2)
}
}
}
+#endif // REFLOW_PATCH
+#if !REFLOW_PATCH
void
tdeletechar(int n)
{
@@ -1382,7 +1639,9 @@ tdeletechar(int n)
memmove(&line[dst], &line[src], size * sizeof(Glyph));
tclearregion(term.col-n, term.c.y, term.col-1, term.c.y);
}
+#endif // REFLOW_PATCH
+#if !REFLOW_PATCH
void
tinsertblank(int n)
{
@@ -1399,19 +1658,40 @@ tinsertblank(int n)
memmove(&line[dst], &line[src], size * sizeof(Glyph));
tclearregion(src, term.c.y, dst - 1, term.c.y);
}
+#endif // REFLOW_PATCH
void
tinsertblankline(int n)
{
if (BETWEEN(term.c.y, term.top, term.bot))
- tscrolldown(term.c.y, n, 0);
+ tscrolldown(term.c.y, n);
}
+#if SIXEL_PATCH
+void
+tdeleteimages(void)
+{
+ ImageList *im, *next;
+
+ for (im = term.images; im; im = next) {
+ next = im->next;
+ delete_image(im);
+ }
+}
+#endif // SIXEL_PATCH
+
void
tdeleteline(int n)
{
- if (BETWEEN(term.c.y, term.top, term.bot))
+ if (BETWEEN(term.c.y, term.top, term.bot)) {
+ #if REFLOW_PATCH
+ tscrollup(term.c.y, term.bot, n, SCROLL_NOSAVEHIST);
+ #elif SCROLLBACK_PATCH
tscrollup(term.c.y, n, 0);
+ #else
+ tscrollup(term.c.y, n);
+ #endif // SCROLLBACK_PATCH
+ }
}
int32_t
@@ -1484,6 +1764,12 @@ tsetattr(const int *attr, int l)
ATTR_STRUCK );
term.c.attr.fg = defaultfg;
term.c.attr.bg = defaultbg;
+ #if UNDERCURL_PATCH
+ term.c.attr.ustyle = -1;
+ term.c.attr.ucolor[0] = -1;
+ term.c.attr.ucolor[1] = -1;
+ term.c.attr.ucolor[2] = -1;
+ #endif // UNDERCURL_PATCH
break;
case 1:
term.c.attr.mode |= ATTR_BOLD;
@@ -1495,7 +1781,18 @@ tsetattr(const int *attr, int l)
term.c.attr.mode |= ATTR_ITALIC;
break;
case 4:
+ #if UNDERCURL_PATCH
+ term.c.attr.ustyle = csiescseq.carg[i][0];
+
+ if (term.c.attr.ustyle != 0)
+ term.c.attr.mode |= ATTR_UNDERLINE;
+ else
+ term.c.attr.mode &= ~ATTR_UNDERLINE;
+
+ term.c.attr.mode ^= ATTR_DIRTYUNDERLINE;
+ #else
term.c.attr.mode |= ATTR_UNDERLINE;
+ #endif // UNDERCURL_PATCH
break;
case 5: /* slow blink */
/* FALLTHROUGH */
@@ -1534,27 +1831,72 @@ tsetattr(const int *attr, int l)
break;
case 38:
if ((idx = tdefcolor(attr, &i, l)) >= 0)
+ #if MONOCHROME_PATCH
+ term.c.attr.fg = defaultfg;
+ #else
term.c.attr.fg = idx;
+ #endif // MONOCHROME_PATCH
break;
- case 39:
+ case 39: /* set foreground color to default */
term.c.attr.fg = defaultfg;
break;
case 48:
if ((idx = tdefcolor(attr, &i, l)) >= 0)
+ #if MONOCHROME_PATCH
+ term.c.attr.bg = 0;
+ #else
term.c.attr.bg = idx;
+ #endif // MONOCHROME_PATCH
break;
- case 49:
+ case 49: /* set background color to default */
term.c.attr.bg = defaultbg;
break;
+ #if UNDERCURL_PATCH
+ case 58:
+ term.c.attr.ucolor[0] = csiescseq.carg[i][1];
+ term.c.attr.ucolor[1] = csiescseq.carg[i][2];
+ term.c.attr.ucolor[2] = csiescseq.carg[i][3];
+ term.c.attr.mode ^= ATTR_DIRTYUNDERLINE;
+ break;
+ case 59:
+ term.c.attr.ucolor[0] = -1;
+ term.c.attr.ucolor[1] = -1;
+ term.c.attr.ucolor[2] = -1;
+ term.c.attr.mode ^= ATTR_DIRTYUNDERLINE;
+ break;
+ #else
+ case 58:
+ /* This starts a sequence to change the color of
+ * "underline" pixels. We don't support that and
+ * instead eat up a following "5;n" or "2;r;g;b". */
+ tdefcolor(attr, &i, l);
+ break;
+ #endif // UNDERCURL_PATCH
default:
if (BETWEEN(attr[i], 30, 37)) {
+ #if MONOCHROME_PATCH
+ term.c.attr.fg = defaultfg;
+ #else
term.c.attr.fg = attr[i] - 30;
+ #endif // MONOCHROME_PATCH
} else if (BETWEEN(attr[i], 40, 47)) {
+ #if MONOCHROME_PATCH
+ term.c.attr.bg = 0;
+ #else
term.c.attr.bg = attr[i] - 40;
+ #endif // MONOCHROME_PATCH
} else if (BETWEEN(attr[i], 90, 97)) {
+ #if MONOCHROME_PATCH
+ term.c.attr.fg = defaultfg;
+ #else
term.c.attr.fg = attr[i] - 90 + 8;
+ #endif // MONOCHROME_PATCH
} else if (BETWEEN(attr[i], 100, 107)) {
+ #if MONOCHROME_PATCH
+ term.c.attr.bg = 0;
+ #else
term.c.attr.bg = attr[i] - 100 + 8;
+ #endif // MONOCHROME_PATCH
} else {
fprintf(stderr,
"erresc(default): gfx attr %d unknown\n",
@@ -1583,9 +1925,10 @@ tsetscroll(int t, int b)
}
void
-tsetmode(int priv, int set,const int *args, int narg)
+tsetmode(int priv, int set, const int *args, int narg)
{
- int alt; const int *lim;
+ int alt;
+ const int *lim;
for (lim = args + narg; args < lim; ++args) {
if (priv) {
@@ -1642,7 +1985,7 @@ tsetmode(int priv, int set,const int *args, int narg)
case 1006: /* 1006: extended reporting mode */
xsetmode(set, MODE_MOUSESGR);
break;
- case 1034:
+ case 1034: /* 1034: enable 8-bit mode for keyboard input */
xsetmode(set, MODE_8BIT);
break;
case 1049: /* swap screen & set/restore cursor as xterm */
@@ -1650,21 +1993,36 @@ tsetmode(int priv, int set,const int *args, int narg)
break;
tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
/* FALLTHROUGH */
- case 47: /* swap screen */
- case 1047:
+ case 47: /* swap screen buffer */
+ case 1047: /* swap screen buffer */
if (!allowaltscreen)
break;
+ #if REFLOW_PATCH
+ if (set)
+ tloadaltscreen(*args != 47, *args == 1049);
+ else
+ tloaddefscreen(*args != 47, *args == 1049);
+ break;
+ #else
alt = IS_SET(MODE_ALTSCREEN);
if (alt) {
- tclearregion(0, 0, term.col-1,
- term.row-1);
+ #if COLUMNS_PATCH
+ tclearregion(0, 0, term.maxcol-1, term.row-1);
+ #else
+ tclearregion(0, 0, term.col-1, term.row-1);
+ #endif // COLUMNS_PATCH
}
if (set ^ alt) /* set is always 1 or 0 */
tswapscreen();
if (*args != 1049)
break;
/* FALLTHROUGH */
- case 1048:
+ #endif // REFLOW_PATCH
+ case 1048: /* save/restore cursor (like DECSC/DECRC) */
+ #if REFLOW_PATCH
+ if (!allowaltscreen)
+ break;
+ #endif // REFLOW_PATCH
tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
break;
case 2004: /* 2004: bracketed paste mode */
@@ -1680,6 +2038,23 @@ tsetmode(int priv, int set,const int *args, int narg)
and can be mistaken for other control
codes. */
break;
+ #if SIXEL_PATCH
+ case 80: /* DECSDM -- Sixel Display Mode */
+ MODBIT(term.mode, set, MODE_SIXEL_SDM);
+ break;
+ case 8452: /* sixel scrolling leaves cursor to right of graphic */
+ MODBIT(term.mode, set, MODE_SIXEL_CUR_RT);
+ break;
+ #endif // SIXEL_PATCH
+ #if SYNC_PATCH
+ case 2026:
+ if (set) {
+ tsync_begin();
+ } else {
+ tsync_end();
+ }
+ break;
+ #endif // SYNC_PATCH
default:
fprintf(stderr,
"erresc: unknown private set/reset mode %d\n",
@@ -1715,8 +2090,20 @@ tsetmode(int priv, int set,const int *args, int narg)
void
csihandle(void)
{
- char buf[40];
- int len;
+ char buffer[40];
+ int n = 0, len;
+ #if SIXEL_PATCH
+ ImageList *im, *next;
+ int pi, pa;
+ #endif // SIXEL_PATCH
+ #if REFLOW_PATCH
+ int x;
+ #endif // REFLOW_PATCH
+ #if COLUMNS_PATCH
+ int maxcol = term.maxcol;
+ #else
+ int maxcol = term.col;
+ #endif // COLUMNS_PATCH
switch (csiescseq.mode[0]) {
default:
@@ -1761,6 +2148,12 @@ csihandle(void)
if (csiescseq.arg[0] == 0)
ttywrite(vtiden, strlen(vtiden), 0);
break;
+ case 'b': /* REP -- if last char is printable print it <n> more times */
+ LIMIT(csiescseq.arg[0], 1, 65535);
+ if (term.lastc)
+ while (csiescseq.arg[0]-- > 0)
+ tputc(term.lastc);
+ break;
case 'C': /* CUF -- Cursor <n> Forward */
case 'a': /* HPR -- Cursor <n> Forward */
DEFAULT(csiescseq.arg[0], 1);
@@ -1808,45 +2201,199 @@ csihandle(void)
case 'J': /* ED -- Clear screen */
switch (csiescseq.arg[0]) {
case 0: /* below */
- tclearregion(term.c.x, term.c.y, term.col-1, term.c.y);
- if (term.c.y < term.row-1) {
- tclearregion(0, term.c.y+1, term.col-1,
- term.row-1);
- }
+ #if REFLOW_PATCH
+ tclearregion(term.c.x, term.c.y, term.col-1, term.c.y, 1);
+ if (term.c.y < term.row-1)
+ tclearregion(0, term.c.y+1, term.col-1, term.row-1, 1);
+ #else
+ tclearregion(term.c.x, term.c.y, maxcol-1, term.c.y);
+ if (term.c.y < term.row-1)
+ tclearregion(0, term.c.y+1, maxcol-1, term.row-1);
+ #endif // REFLOW_PATCH
break;
case 1: /* above */
- if (term.c.y > 1)
- tclearregion(0, 0, term.col-1, term.c.y-1);
+ #if REFLOW_PATCH
+ if (term.c.y > 0)
+ tclearregion(0, 0, term.col-1, term.c.y-1, 1);
+ tclearregion(0, term.c.y, term.c.x, term.c.y, 1);
+ #else
+ if (term.c.y > 0)
+ tclearregion(0, 0, maxcol-1, term.c.y-1);
tclearregion(0, term.c.y, term.c.x, term.c.y);
+ #endif // REFLOW_PATCH
break;
- case 2: /* all */
- tclearregion(0, 0, term.col-1, term.row-1);
+ case 2: /* screen */
+ #if REFLOW_PATCH
+ if (IS_SET(MODE_ALTSCREEN)) {
+ tclearregion(0, 0, term.col-1, term.row-1, 1);
+ #if SIXEL_PATCH
+ tdeleteimages();
+ #endif // SIXEL_PATCH
+ break;
+ }
+ /* vte does this:
+ tscrollup(0, term.row-1, term.row, SCROLL_SAVEHIST); */
+ /* alacritty does this: */
+ for (n = term.row-1; n >= 0 && tlinelen(term.line[n]) == 0; n--)
+ ;
+ #if SIXEL_PATCH
+ for (im = term.images; im; im = im->next)
+ n = MAX(im->y - term.scr, n);
+ #endif // SIXEL_PATCH
+ if (n >= 0)
+ tscrollup(0, term.row-1, n+1, SCROLL_SAVEHIST);
+ tscrollup(0, term.row-1, term.row-n-1, SCROLL_NOSAVEHIST);
+ break;
+ #else // !REFLOW_PATCH
+ #if SCROLLBACK_PATCH
+ if (!IS_SET(MODE_ALTSCREEN)) {
+ #if SCROLLBACK_PATCH
+ kscrolldown(&((Arg){ .i = term.scr }));
+ #endif
+ int n, m, bot = term.bot;
+ term.bot = term.row-1;
+ for (n = term.row-1; n >= 0; n--) {
+ for (m = 0; m < maxcol && term.line[n][m].u == ' ' && !term.line[n][m].mode; m++);
+ if (m < maxcol) {
+ #if SCROLLBACK_PATCH
+ tscrollup(0, n+1, 1);
+ #else
+ tscrollup(0, n+1);
+ #endif
+ break;
+ }
+ }
+ if (n < term.row-1)
+ tclearregion(0, 0, maxcol-1, term.row-n-2);
+ term.bot = bot;
+ break;
+ }
+ #endif // SCROLLBACK_PATCH
+
+ tclearregion(0, 0, maxcol-1, term.row-1);
+ #if SIXEL_PATCH
+ tdeleteimages();
+ #endif // SIXEL_PATCH
+ #endif // REFLOW_PTCH
break;
+ case 3: /* scrollback */
+ #if REFLOW_PATCH
+ if (IS_SET(MODE_ALTSCREEN))
+ break;
+ kscrolldown(&((Arg){ .i = term.scr }));
+ term.scr = 0;
+ term.histi = 0;
+ term.histf = 0;
+ #if SIXEL_PATCH
+ for (im = term.images; im; im = next) {
+ next = im->next;
+ if (im->y < 0)
+ delete_image(im);
+ }
+ #endif // SIXEL_PATCH
+ break;
+ #else // !REFLOW_PATCH
+ #if SCROLLBACK_PATCH
+ if (!IS_SET(MODE_ALTSCREEN)) {
+ term.scr = 0;
+ term.histi = 0;
+ term.histn = 0;
+ Glyph g=(Glyph){.bg=term.c.attr.bg, .fg=term.c.attr.fg, .u=' ', .mode=0};
+ for (int i = 0; i < HISTSIZE; i++) {
+ for (int j = 0; j < maxcol; j++)
+ term.hist[i][j] = g;
+ }
+ }
+ #endif // SCROLLBACK_PATCH
+ #if SIXEL_PATCH
+ for (im = term.images; im; im = next) {
+ next = im->next;
+ if (im->y < 0)
+ delete_image(im);
+ }
+ #endif // SIXEL_PATCH
+ break;
+ #endif // REFLOW_PATCH
+ #if SIXEL_PATCH
+ case 6: /* sixels */
+ tdeleteimages();
+ tfulldirt();
+ break;
+ #endif // SIXEL_PATCH
default:
goto unknown;
}
break;
case 'K': /* EL -- Clear line */
switch (csiescseq.arg[0]) {
+ #if REFLOW_PATCH
case 0: /* right */
- tclearregion(term.c.x, term.c.y, term.col-1,
- term.c.y);
+ tclearregion(term.c.x, term.c.y, term.col-1, term.c.y, 1);
+ break;
+ case 1: /* left */
+ tclearregion(0, term.c.y, term.c.x, term.c.y, 1);
+ break;
+ case 2: /* all */
+ tclearregion(0, term.c.y, term.col-1, term.c.y, 1);
+ break;
+ }
+ #else
+ case 0: /* right */
+ tclearregion(term.c.x, term.c.y, maxcol-1, term.c.y);
break;
case 1: /* left */
tclearregion(0, term.c.y, term.c.x, term.c.y);
break;
case 2: /* all */
- tclearregion(0, term.c.y, term.col-1, term.c.y);
+ tclearregion(0, term.c.y, maxcol-1, term.c.y);
break;
}
+ #endif // REFLOW_PATCH
break;
- case 'S': /* SU -- Scroll <n> line up */
+ case 'S': /* SU -- Scroll <n> line up ; XTSMGRAPHICS */
+ if (csiescseq.priv) {
+ #if SIXEL_PATCH
+ if (csiescseq.narg > 1) {
+ /* XTSMGRAPHICS */
+ pi = csiescseq.arg[0];
+ pa = csiescseq.arg[1];
+ if (pi == 1 && (pa == 1 || pa == 2 || pa == 4)) {
+ /* number of sixel color registers */
+ /* (read, reset and read the maximum value give the same response) */
+ n = snprintf(buffer, sizeof buffer, "\033[?1;0;%dS", DECSIXEL_PALETTE_MAX);
+ ttywrite(buffer, n, 1);
+ break;
+ } else if (pi == 2 && (pa == 1 || pa == 2 || pa == 4)) {
+ /* sixel graphics geometry (in pixels) */
+ /* (read, reset and read the maximum value give the same response) */
+ n = snprintf(buffer, sizeof buffer, "\033[?2;0;%d;%dS",
+ MIN(term.col * win.cw, DECSIXEL_WIDTH_MAX),
+ MIN(term.row * win.ch, DECSIXEL_HEIGHT_MAX));
+ ttywrite(buffer, n, 1);
+ break;
+ }
+ /* the number of color registers and sixel geometry can't be changed */
+ n = snprintf(buffer, sizeof buffer, "\033[?%d;3;0S", pi); /* failure */
+ ttywrite(buffer, n, 1);
+ }
+ #endif // SIXEL_PATCH
+ goto unknown;
+ }
DEFAULT(csiescseq.arg[0], 1);
+ #if REFLOW_PATCH
+ /* xterm, urxvt, alacritty save this in history */
+ tscrollup(term.top, term.bot, csiescseq.arg[0], SCROLL_SAVEHIST);
+ #elif SIXEL_PATCH && SCROLLBACK_PATCH
+ tscrollup(term.top, csiescseq.arg[0], 1);
+ #elif SCROLLBACK_PATCH
tscrollup(term.top, csiescseq.arg[0], 0);
+ #else
+ tscrollup(term.top, csiescseq.arg[0]);
+ #endif // SCROLLBACK_PATCH
break;
case 'T': /* SD -- Scroll <n> line down */
DEFAULT(csiescseq.arg[0], 1);
- tscrolldown(term.top, csiescseq.arg[0], 0);
+ tscrolldown(term.top, csiescseq.arg[0]);
break;
case 'L': /* IL -- Insert <n> blank lines */
DEFAULT(csiescseq.arg[0], 1);
@@ -1860,9 +2407,17 @@ csihandle(void)
tdeleteline(csiescseq.arg[0]);
break;
case 'X': /* ECH -- Erase <n> char */
+ #if REFLOW_PATCH
+ if (csiescseq.arg[0] < 0)
+ return;
+ DEFAULT(csiescseq.arg[0], 1);
+ x = MIN(term.c.x + csiescseq.arg[0], term.col) - 1;
+ tclearregion(term.c.x, term.c.y, x, term.c.y, 1);
+ #else
DEFAULT(csiescseq.arg[0], 1);
tclearregion(term.c.x, term.c.y,
term.c.x + csiescseq.arg[0] - 1, term.c.y);
+ #endif // REFLOW_PATCH
break;
case 'P': /* DCH -- Delete <n> char */
DEFAULT(csiescseq.arg[0], 1);
@@ -1882,13 +2437,49 @@ csihandle(void)
case 'm': /* SGR -- Terminal attribute (color) */
tsetattr(csiescseq.arg, csiescseq.narg);
break;
- case 'n': /* DSR – Device Status Report (cursor position) */
- if (csiescseq.arg[0] == 6) {
- len = snprintf(buf, sizeof(buf),"\033[%i;%iR",
- term.c.y+1, term.c.x+1);
- ttywrite(buf, len, 0);
+ case 'n': /* DSR -- Device Status Report */
+ switch (csiescseq.arg[0]) {
+ case 5: /* Status Report "OK" `0n` */
+ ttywrite("\033[0n", sizeof("\033[0n") - 1, 0);
+ break;
+ case 6: /* Report Cursor Position (CPR) "<row>;<column>R" */
+ len = snprintf(buffer, sizeof(buffer), "\033[%i;%iR",
+ term.c.y+1, term.c.x+1);
+ ttywrite(buffer, len, 0);
+ break;
+ default:
+ goto unknown;
}
break;
+ #if SYNC_PATCH || SIXEL_PATCH
+ case '$': /* DECRQM -- DEC Request Mode (private) */
+ if (csiescseq.mode[1] == 'p' && csiescseq.priv) {
+ switch (csiescseq.arg[0]) {
+ #if SIXEL_PATCH
+ case 80:
+ /* Sixel Display Mode */
+ ttywrite(IS_SET(MODE_SIXEL_SDM) ? "\033[?80;1$y"
+ : "\033[?80;2$y", 9, 0);
+ break;
+ case 8452:
+ /* Sixel scrolling leaves cursor to right of graphic */
+ ttywrite(IS_SET(MODE_SIXEL_CUR_RT) ? "\033[?8452;1$y"
+ : "\033[?8452;2$y", 11, 0);
+ break;
+ #endif // SIXEL_PATCH
+ #if SYNC_PATCH
+ case 2026:
+ /* https://gist.github.com/christianparpart/d8a62cc1ab659194337d73e399004036 */
+ ttywrite(su ? "\033[?2026;1$y" : "\033[?2026;2$y", 11, 0);
+ break;
+ #endif // SYNC_PATCH
+ default:
+ goto unknown;
+ }
+ break;
+ }
+ goto unknown;
+ #endif // SYNC_PATCH | SIXEL_PATCH
case 'r': /* DECSTBM -- Set Scrolling Region */
if (csiescseq.priv) {
goto unknown;
@@ -1902,8 +2493,61 @@ csihandle(void)
case 's': /* DECSC -- Save cursor position (ANSI.SYS) */
tcursor(CURSOR_SAVE);
break;
+ #if CSI_22_23_PATCH | SIXEL_PATCH
+ case 't': /* title stack operations ; XTWINOPS */
+ switch (csiescseq.arg[0]) {
+ #if SIXEL_PATCH
+ case 14: /* text area size in pixels */
+ if (csiescseq.narg > 1)
+ goto unknown;
+ n = snprintf(buffer, sizeof buffer, "\033[4;%d;%dt",
+ term.row * win.ch, term.col * win.cw);
+ ttywrite(buffer, n, 1);
+ break;
+ case 16: /* character cell size in pixels */
+ n = snprintf(buffer, sizeof buffer, "\033[6;%d;%dt", win.ch, win.cw);
+ ttywrite(buffer, n, 1);
+ break;
+ case 18: /* size of the text area in characters */
+ n = snprintf(buffer, sizeof buffer, "\033[8;%d;%dt", term.row, term.col);
+ ttywrite(buffer, n, 1);
+ break;
+ #endif // SIXEL_PATCH
+ #if CSI_22_23_PATCH
+ case 22: /* pust current title on stack */
+ switch (csiescseq.arg[1]) {
+ case 0:
+ case 1:
+ case 2:
+ xpushtitle();
+ break;
+ default:
+ goto unknown;
+ }
+ break;
+ case 23: /* pop last title from stack */
+ switch (csiescseq.arg[1]) {
+ case 0:
+ case 1:
+ case 2:
+ xsettitle(NULL, 1);
+ break;
+ default:
+ goto unknown;
+ }
+ break;
+ #endif // CSI_22_23_PATCH
+ default:
+ goto unknown;
+ }
+ break;
+ #endif // CSI_22_23_PATCH | SIXEL_PATCH
case 'u': /* DECRC -- Restore cursor position (ANSI.SYS) */
- tcursor(CURSOR_LOAD);
+ if (csiescseq.priv) {
+ goto unknown;
+ } else {
+ tcursor(CURSOR_LOAD);
+ }
break;
case ' ':
switch (csiescseq.mode[1]) {
@@ -1921,7 +2565,7 @@ csihandle(void)
void
csidump(void)
{
- int i;
+ size_t i;
uint c;
fprintf(stderr, "ESC[");
@@ -1949,10 +2593,51 @@ csireset(void)
}
void
+osc_color_response(int num, int index, int is_osc4)
+{
+ int n;
+ char buf[32];
+ unsigned char r, g, b;
+
+ if (xgetcolor(is_osc4 ? num : index, &r, &g, &b)) {
+ fprintf(stderr, "erresc: failed to fetch %s color %d\n",
+ is_osc4 ? "osc4" : "osc",
+ is_osc4 ? num : index);
+ return;
+ }
+
+ n = snprintf(buf, sizeof buf, "\033]%s%d;rgb:%02x%02x/%02x%02x/%02x%02x%s",
+ is_osc4 ? "4;" : "", num, r, r, g, g, b, b, strescseq.term);
+ if (n < 0 || n >= sizeof(buf)) {
+ fprintf(stderr, "error: %s while printing %s response\n",
+ n < 0 ? "snprintf failed" : "truncation occurred",
+ is_osc4 ? "osc4" : "osc");
+ } else {
+ ttywrite(buf, n, 1);
+ }
+}
+
+void
strhandle(void)
{
char *p = NULL, *dec;
int j, narg, par;
+ const struct { int idx; char *str; } osc_table[] = {
+ { defaultfg, "foreground" },
+ { defaultbg, "background" },
+ { defaultcs, "cursor" }
+ };
+ #if SIXEL_PATCH
+ ImageList *im, *newimages, *next, *tail = NULL;
+ int i, x1, y1, x2, y2, y, numimages;
+ int cx, cy;
+ Line line;
+ #if SCROLLBACK_PATCH || REFLOW_PATCH
+ int scr = IS_SET(MODE_ALTSCREEN) ? 0 : term.scr;
+ #else
+ int scr = 0;
+ #endif // SCROLLBACK_PATCH
+ #endif // SIXEL_PATCH
term.esc &= ~(ESC_STR_END|ESC_STR);
strparse();
@@ -1962,21 +2647,29 @@ strhandle(void)
case ']': /* OSC -- Operating System Command */
switch (par) {
case 0:
- if (narg > 1) {
+ if (narg > 1) {
+ #if CSI_22_23_PATCH
+ xsettitle(strescseq.args[1], 0);
+ #else
xsettitle(strescseq.args[1]);
+ #endif // CSI_22_23_PATCH
xseticontitle(strescseq.args[1]);
}
return;
case 1:
- if (narg > 1)
+ if (narg > 1)
xseticontitle(strescseq.args[1]);
return;
case 2:
if (narg > 1)
+ #if CSI_22_23_PATCH
+ xsettitle(strescseq.args[1], 0);
+ #else
xsettitle(strescseq.args[1]);
+ #endif // CSI_22_23_PATCH
return;
- case 52:
- if (narg > 2) {
+ case 52: /* manipulate selection data */
+ if (narg > 2 && allowwindowops) {
dec = base64dec(strescseq.args[2]);
if (dec) {
xsetsel(dec);
@@ -1986,46 +2679,205 @@ strhandle(void)
}
}
return;
+ #if OSC7_PATCH
+ case 7:
+ osc7parsecwd((const char *)strescseq.args[1]);
+ return;
+ #endif // OSC7_PATCH
+ case 8: /* Clear Hyperlinks */
+ return;
+ case 10: /* set dynamic VT100 text foreground color */
+ case 11: /* set dynamic VT100 text background color */
+ case 12: /* set dynamic text cursor color */
+ if (narg < 2)
+ break;
+ p = strescseq.args[1];
+ if ((j = par - 10) < 0 || j >= LEN(osc_table))
+ break; /* shouldn't be possible */
+
+ if (!strcmp(p, "?")) {
+ osc_color_response(par, osc_table[j].idx, 0);
+ } else if (xsetcolorname(osc_table[j].idx, p)) {
+ fprintf(stderr, "erresc: invalid %s color: %s\n",
+ osc_table[j].str, p);
+ } else {
+ tfulldirt();
+ }
+ return;
case 4: /* color set */
- case 10: /* foreground set */
- case 11: /* background set */
- case 12: /* cursor color */
- if ((par == 4 && narg < 3) || narg < 2)
+ if (narg < 3)
break;
- p = strescseq.args[((par == 4) ? 2 : 1)];
+ p = strescseq.args[2];
/* FALLTHROUGH */
- case 104: /* color reset, here p = NULL */
- if (par == 10)
- j = defaultfg;
- else if (par == 11)
- j = defaultbg;
- else if (par == 12)
- j = defaultcs;
- else
- j = (narg > 1) ? atoi(strescseq.args[1]) : -1;
-
- if (xsetcolorname(j, p)) {
- if (par == 104 && narg <= 1)
+ case 104: /* color reset */
+ j = (narg > 1) ? atoi(strescseq.args[1]) : -1;
+
+ if (p && !strcmp(p, "?")) {
+ osc_color_response(j, 0, 1);
+ } else if (xsetcolorname(j, p)) {
+ if (par == 104 && narg <= 1) {
+ xloadcols();
return; /* color reset without parameter */
+ }
fprintf(stderr, "erresc: invalid color j=%d, p=%s\n",
- j, p ? p : "(null)");
+ j, p ? p : "(null)");
} else {
/*
* TODO if defaultbg color is changed, borders
* are dirty
*/
- if (j == defaultbg)
- xclearwin();
- redraw();
+ tfulldirt();
+ }
+ return;
+ case 110: /* reset dynamic VT100 text foreground color */
+ case 111: /* reset dynamic VT100 text background color */
+ case 112: /* reset dynamic text cursor color */
+ if (narg != 1)
+ break;
+ if ((j = par - 110) < 0 || j >= LEN(osc_table))
+ break; /* shouldn't be possible */
+ if (xsetcolorname(osc_table[j].idx, NULL)) {
+ fprintf(stderr, "erresc: %s color not found\n", osc_table[j].str);
+ } else {
+ tfulldirt();
}
return;
+ #if OSC133_PATCH
+ case 133:
+ if (narg < 2)
+ break;
+ switch (*strescseq.args[1]) {
+ case 'A':
+ term.c.attr.mode |= ATTR_FTCS_PROMPT;
+ break;
+ /* We don't handle these arguments yet */
+ case 'B':
+ case 'C':
+ case 'D':
+ break;
+ default:
+ fprintf(stderr, "erresc: unknown OSC 133 argument: %c\n", *strescseq.args[1]);
+ break;
+ }
+ return;
+ #endif // OSC133_PATCH
}
break;
case 'k': /* old title set compatibility */
+ #if CSI_22_23_PATCH
+ xsettitle(strescseq.args[0], 0);
+ #else
xsettitle(strescseq.args[0]);
+ #endif // CSI_22_23_PATCH
return;
case 'P': /* DCS -- Device Control String */
- term.mode |= ESC_DCS;
+ #if SIXEL_PATCH
+ if (IS_SET(MODE_SIXEL)) {
+ term.mode &= ~MODE_SIXEL;
+ if (!sixel_st.image.data) {
+ sixel_parser_deinit(&sixel_st);
+ return;
+ }
+ cx = IS_SET(MODE_SIXEL_SDM) ? 0 : term.c.x;
+ cy = IS_SET(MODE_SIXEL_SDM) ? 0 : term.c.y;
+ if ((numimages = sixel_parser_finalize(&sixel_st, &newimages,
+ cx, cy + scr, win.cw, win.ch)) <= 0) {
+ sixel_parser_deinit(&sixel_st);
+ perror("sixel_parser_finalize() failed");
+ return;
+ }
+ sixel_parser_deinit(&sixel_st);
+ x1 = newimages->x;
+ y1 = newimages->y;
+ x2 = x1 + newimages->cols;
+ y2 = y1 + numimages;
+ /* Delete the old images that are covered by the new image(s). We also need
+ * to check if they have already been deleted before adding the new ones. */
+ if (term.images) {
+ char transparent[numimages];
+ for (i = 0, im = newimages; im; im = im->next, i++) {
+ transparent[i] = im->transparent;
+ }
+ for (im = term.images; im; im = next) {
+ next = im->next;
+ if (im->y >= y1 && im->y < y2) {
+ y = im->y - scr;
+ if (y >= 0 && y < term.row && term.dirty[y]) {
+ line = term.line[y];
+ j = MIN(im->x + im->cols, term.col);
+ for (i = im->x; i < j; i++) {
+ if (line[i].mode & ATTR_SIXEL)
+ break;
+ }
+ if (i == j) {
+ delete_image(im);
+ continue;
+ }
+ }
+ if (im->x >= x1 && im->x + im->cols <= x2 && !transparent[im->y - y1]) {
+ delete_image(im);
+ continue;
+ }
+ }
+ tail = im;
+ }
+ }
+ if (tail) {
+ tail->next = newimages;
+ newimages->prev = tail;
+ } else {
+ term.images = newimages;
+ }
+ #if COLUMNS_PATCH && !REFLOW_PATCH
+ x2 = MIN(x2, term.maxcol) - 1;
+ #else
+ x2 = MIN(x2, term.col) - 1;
+ #endif // COLUMNS_PATCH
+ if (IS_SET(MODE_SIXEL_SDM)) {
+ /* Sixel display mode: put the sixel in the upper left corner of
+ * the screen, disable scrolling (the sixel will be truncated if
+ * it is too long) and do not change the cursor position. */
+ for (i = 0, im = newimages; im; im = next, i++) {
+ next = im->next;
+ if (i >= term.row) {
+ delete_image(im);
+ continue;
+ }
+ im->y = i + scr;
+ tsetsixelattr(term.line[i], x1, x2);
+ term.dirty[MIN(im->y, term.row-1)] = 1;
+ }
+ } else {
+ for (i = 0, im = newimages; im; im = next, i++) {
+ next = im->next;
+ #if SCROLLBACK_PATCH || REFLOW_PATCH
+ scr = IS_SET(MODE_ALTSCREEN) ? 0 : term.scr;
+ #endif // SCROLLBACK_PATCH
+ im->y = term.c.y + scr;
+ tsetsixelattr(term.line[term.c.y], x1, x2);
+ term.dirty[MIN(im->y, term.row-1)] = 1;
+ if (i < numimages-1) {
+ im->next = NULL;
+ tnewline(0);
+ im->next = next;
+ }
+ }
+ /* if mode 8452 is set, sixel scrolling leaves cursor to right of graphic */
+ if (IS_SET(MODE_SIXEL_CUR_RT))
+ term.c.x = MIN(term.c.x + newimages->cols, term.col-1);
+ }
+ }
+ #endif // SIXEL_PATCH
+ #if SYNC_PATCH
+ /* https://gitlab.com/gnachman/iterm2/-/wikis/synchronized-updates-spec */
+ if (strstr(strescseq.buf, "=1s") == strescseq.buf)
+ tsync_begin(); /* BSU */
+ else if (strstr(strescseq.buf, "=2s") == strescseq.buf)
+ tsync_end(); /* ESU */
+ #endif // SYNC_PATCH
+ #if SIXEL_PATCH || SYNC_PATCH
+ return;
+ #endif // SIXEL_PATCH | SYNC_PATCH
case '_': /* APC -- Application Program Command */
case '^': /* PM -- Privacy Message */
return;
@@ -2047,6 +2899,19 @@ strparse(void)
if (*p == '\0')
return;
+ /* preserve semicolons in window titles, icon names and OSC 7 sequences */
+ if (strescseq.type == ']' && (
+ p[0] <= '2'
+ #if OSC7_PATCH
+ || p[0] == '7'
+ #endif // OSC7_PATCH
+ ) && p[1] == ';') {
+ strescseq.args[strescseq.narg++] = p;
+ strescseq.args[strescseq.narg++] = p + 2;
+ p[1] = '\0';
+ return;
+ }
+
while (strescseq.narg < STR_ARG_SIZ) {
strescseq.args[strescseq.narg++] = p;
while ((c = *p) != ';' && c != '\0')
@@ -2060,7 +2925,7 @@ strparse(void)
void
strdump(void)
{
- int i;
+ size_t i;
uint c;
fprintf(stderr, "ESC%c", strescseq.type);
@@ -2081,13 +2946,16 @@ strdump(void)
fprintf(stderr, "(%02x)", c);
}
}
- fprintf(stderr, "ESC\\\n");
+ fprintf(stderr, (strescseq.term[0] == 0x1b) ? "ESC\\\n" : "BEL\n");
}
void
strreset(void)
{
- memset(&strescseq, 0, sizeof(strescseq));
+ strescseq = (STREscape){
+ .buf = xrealloc(strescseq.buf, STR_BUF_SIZ),
+ .siz = STR_BUF_SIZ,
+ };
}
void
@@ -2108,84 +2976,6 @@ tprinter(char *s, size_t len)
}
void
-externalpipe(const Arg *arg)
-{
- int to[2];
- char buf[UTF_SIZ];
- void (*oldsigpipe)(int);
- Glyph *bp, *end;
- int lastpos, n, newline;
-
- if (pipe(to) == -1)
- return;
-
- switch (fork()) {
- case -1:
- close(to[0]);
- close(to[1]);
- return;
- case 0:
- dup2(to[0], STDIN_FILENO);
- close(to[0]);
- close(to[1]);
- execvp(((char **)arg->v)[0], (char **)arg->v);
- fprintf(stderr, "st: execvp %s\n", ((char **)arg->v)[0]);
- perror("failed");
- exit(0);
- }
-
- close(to[0]);
- /* ignore sigpipe for now, in case child exists early */
- oldsigpipe = signal(SIGPIPE, SIG_IGN);
- newline = 0;
- /* modify externalpipe patch to pipe history too */
- for (n = 0; n <= HISTSIZE + 2; n++) {
- bp = TLINE_HIST(n);
- lastpos = MIN(tlinehistlen(n) +1, term.col) - 1;
- if (lastpos < 0)
- break;
- if (lastpos == 0)
- continue;
- end = &bp[lastpos + 1];
- for (; bp < end; ++bp)
- if (xwrite(to[1], buf, utf8encode(bp->u, buf)) < 0)
- break;
- if ((newline = TLINE_HIST(n)[lastpos].mode & ATTR_WRAP))
- continue;
- if (xwrite(to[1], "\n", 1) < 0)
- break;
- newline = 0;
- }
- if (newline)
- (void)xwrite(to[1], "\n", 1);
- close(to[1]);
- /* restore */
- signal(SIGPIPE, oldsigpipe);
-}
-
-void
-iso14755(const Arg *arg)
-{
- FILE *p;
- char *us, *e, codepoint[9], uc[UTF_SIZ];
- unsigned long utf32;
-
- if (!(p = popen(ISO14755CMD, "r")))
- return;
-
- us = fgets(codepoint, sizeof(codepoint), p);
- pclose(p);
-
- if (!us || *us == '\0' || *us == '-' || strlen(us) > 7)
- return;
- if ((utf32 = strtoul(us, &e, 16)) == ULONG_MAX ||
- (*e != '\n' && *e != '\0'))
- return;
-
- ttywrite(uc, utf8encode(utf32, uc), 1);
-}
-
-void
toggleprinter(const Arg *arg)
{
term.mode ^= MODE_PRINT;
@@ -2214,6 +3004,7 @@ tdumpsel(void)
}
}
+#if !REFLOW_PATCH
void
tdumpline(int n)
{
@@ -2223,11 +3014,12 @@ tdumpline(int n)
bp = &term.line[n][0];
end = &bp[MIN(tlinelen(n), term.col) - 1];
if (bp != end || bp->u != ' ') {
- for ( ;bp <= end; ++bp)
+ for ( ; bp <= end; ++bp)
tprinter(buf, utf8encode(bp->u, buf));
}
tprinter("\n", 1);
}
+#endif // REFLOW_PATCH
void
tdump(void)
@@ -2294,12 +3086,16 @@ tdectest(char c)
void
tstrsequence(uchar c)
{
+ #if SIXEL_PATCH
strreset();
+ #endif // SIXEL_PATCH
switch (c) {
case 0x90: /* DCS -- Device Control String */
c = 'P';
+ #if SIXEL_PATCH
term.esc |= ESC_DCS;
+ #endif // SIXEL_PATCH
break;
case 0x9f: /* APC -- Application Program Command */
c = '_';
@@ -2311,6 +3107,9 @@ tstrsequence(uchar c)
c = ']';
break;
}
+ #if !SIXEL_PATCH
+ strreset();
+ #endif // SIXEL_PATCH
strescseq.type = c;
term.esc |= ESC_STR;
}
@@ -2337,6 +3136,7 @@ tcontrolcode(uchar ascii)
case '\a': /* BEL */
if (term.esc & ESC_STR_END) {
/* backwards compatibility to xterm */
+ strescseq.term = STR_TERM_BEL;
strhandle();
} else {
xbell();
@@ -2353,6 +3153,7 @@ tcontrolcode(uchar ascii)
return;
case '\032': /* SUB */
tsetchar('?', &term.c.attr, term.c.x, term.c.y);
+ /* FALLTHROUGH */
case '\030': /* CAN */
csireset();
break;
@@ -2411,6 +3212,51 @@ tcontrolcode(uchar ascii)
term.esc &= ~(ESC_STR_END|ESC_STR);
}
+#if SIXEL_PATCH
+void
+dcshandle(void)
+{
+ int bgcolor, transparent;
+ unsigned char r, g, b, a = 255;
+
+ switch (csiescseq.mode[0]) {
+ default:
+ unknown:
+ fprintf(stderr, "erresc: unknown csi ");
+ csidump();
+ /* die(""); */
+ break;
+ #if SYNC_PATCH
+ case '=':
+ /* https://gitlab.com/gnachman/iterm2/-/wikis/synchronized-updates-spec */
+ if (csiescseq.buf[2] == 's' && csiescseq.buf[1] == '1')
+ tsync_begin(); /* BSU */
+ else if (csiescseq.buf[2] == 's' && csiescseq.buf[1] == '2')
+ tsync_end(); /* ESU */
+ else
+ goto unknown;
+ break;
+ #endif // SYNC_PATCH
+ case 'q': /* DECSIXEL */
+ transparent = (csiescseq.narg >= 2 && csiescseq.arg[1] == 1);
+ if (IS_TRUECOL(term.c.attr.bg)) {
+ r = term.c.attr.bg >> 16 & 255;
+ g = term.c.attr.bg >> 8 & 255;
+ b = term.c.attr.bg >> 0 & 255;
+ } else {
+ xgetcolor(term.c.attr.bg, &r, &g, &b);
+ if (term.c.attr.bg == defaultbg)
+ a = dc.col[defaultbg].pixel >> 24 & 255;
+ }
+ bgcolor = a << 24 | r << 16 | g << 8 | b;
+ if (sixel_parser_init(&sixel_st, transparent, (255 << 24), bgcolor, 1, win.cw, win.ch) != 0)
+ perror("sixel_parser_init() failed");
+ term.mode |= MODE_SIXEL;
+ break;
+ }
+}
+#endif // SIXEL_PATCH
+
/*
* returns 1 when the sequence is finished and it hasn't to read
* more characters for this sequence, otherwise 0
@@ -2429,6 +3275,9 @@ eschandle(uchar ascii)
term.esc |= ESC_UTF8;
return 0;
case 'P': /* DCS -- Device Control String */
+ #if SIXEL_PATCH
+ term.esc |= ESC_DCS;
+ #endif // SIXEL_PATCH
case '_': /* APC -- Application Program Command */
case '^': /* PM -- Privacy Message */
case ']': /* OSC -- Operating System Command */
@@ -2448,7 +3297,13 @@ eschandle(uchar ascii)
return 0;
case 'D': /* IND -- Linefeed */
if (term.c.y == term.bot) {
+ #if REFLOW_PATCH
+ tscrollup(term.top, term.bot, 1, SCROLL_SAVEHIST);
+ #elif SCROLLBACK_PATCH
tscrollup(term.top, 1, 1);
+ #else
+ tscrollup(term.top, 1);
+ #endif // SCROLLBACK_PATCH
} else {
tmoveto(term.c.x, term.c.y+1);
}
@@ -2461,7 +3316,7 @@ eschandle(uchar ascii)
break;
case 'M': /* RI -- Reverse index */
if (term.c.y == term.top) {
- tscrolldown(term.top, 1, 1);
+ tscrolldown(term.top, 1);
} else {
tmoveto(term.c.x, term.c.y-1);
}
@@ -2471,8 +3326,19 @@ eschandle(uchar ascii)
break;
case 'c': /* RIS -- Reset to initial state */
treset();
+ #if CSI_22_23_PATCH
+ xfreetitlestack();
+ #endif // CSI_22_23_PATCH
resettitle();
xloadcols();
+ xsetmode(0, MODE_HIDE);
+ #if SCROLLBACK_PATCH && !REFLOW_PATCH
+ if (!IS_SET(MODE_ALTSCREEN)) {
+ term.scr = 0;
+ term.histi = 0;
+ term.histn = 0;
+ }
+ #endif // SCROLLBACK_PATCH
break;
case '=': /* DECPAM -- Application keypad */
xsetmode(1, MODE_APPKEYPAD);
@@ -2487,8 +3353,10 @@ eschandle(uchar ascii)
tcursor(CURSOR_LOAD);
break;
case '\\': /* ST -- String Terminator */
- if (term.esc & ESC_STR_END)
+ if (term.esc & ESC_STR_END) {
+ strescseq.term = STR_TERM_ST;
strhandle();
+ }
break;
default:
fprintf(stderr, "erresc: unknown sequence ESC 0x%02X '%c'\n",
@@ -2507,15 +3375,14 @@ tputc(Rune u)
Glyph *gp;
control = ISCONTROL(u);
- if (!IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) {
+ if (u < 127 || !IS_SET(MODE_UTF8))
+ {
c[0] = u;
width = len = 1;
} else {
len = utf8encode(u, c);
- if (!control && (width = wcwidth(u)) == -1) {
- memcpy(c, "\357\277\275", 4); /* UTF_INVALID */
+ if (!control && (width = wcwidth(u)) == -1)
width = 1;
- }
}
if (IS_SET(MODE_PRINT))
@@ -2530,24 +3397,21 @@ tputc(Rune u)
if (term.esc & ESC_STR) {
if (u == '\a' || u == 030 || u == 032 || u == 033 ||
ISCONTROLC1(u)) {
+ #if SIXEL_PATCH
term.esc &= ~(ESC_START|ESC_STR|ESC_DCS);
- if (IS_SET(MODE_SIXEL)) {
- /* TODO: render sixel */;
- term.mode &= ~MODE_SIXEL;
- return;
- }
+ #else
+ term.esc &= ~(ESC_START|ESC_STR);
+ #endif // SIXEL_PATCH
term.esc |= ESC_STR_END;
goto check_control_code;
}
- if (IS_SET(MODE_SIXEL)) {
- /* TODO: implement sixel mode */
- return;
- }
- if (term.esc&ESC_DCS && strescseq.len == 0 && u == 'q')
- term.mode |= MODE_SIXEL;
+ #if SIXEL_PATCH
+ if (term.esc & ESC_DCS)
+ goto check_control_code;
+ #endif // SIXEL_PATCH
- if (strescseq.len+len >= sizeof(strescseq.buf)-1) {
+ if (strescseq.len+len >= strescseq.siz) {
/*
* Here is a bug in terminals. If the user never sends
* some code to stop the str or esc command, then st
@@ -2561,7 +3425,10 @@ tputc(Rune u)
* term.esc = 0;
* strhandle();
*/
- return;
+ if (strescseq.siz > (SIZE_MAX - UTF_SIZ) / 2)
+ return;
+ strescseq.siz *= 2;
+ strescseq.buf = xrealloc(strescseq.buf, strescseq.siz);
}
memmove(&strescseq.buf[strescseq.len], c, len);
@@ -2576,10 +3443,15 @@ check_control_code:
* they must not cause conflicts with sequences.
*/
if (control) {
+ /* in UTF-8 mode ignore handling C1 control characters */
+ if (IS_SET(MODE_UTF8) && ISCONTROLC1(u))
+ return;
tcontrolcode(u);
/*
* control codes are not shown ever
*/
+ if (!term.esc)
+ term.lastc = 0;
return;
} else if (term.esc & ESC_START) {
if (term.esc & ESC_CSI) {
@@ -2592,6 +3464,17 @@ check_control_code:
csihandle();
}
return;
+ #if SIXEL_PATCH
+ } else if (term.esc & ESC_DCS) {
+ csiescseq.buf[csiescseq.len++] = u;
+ if (BETWEEN(u, 0x40, 0x7E)
+ || csiescseq.len >= \
+ sizeof(csiescseq.buf)-1) {
+ csiparse();
+ dcshandle();
+ }
+ return;
+ #endif // SIXEL_PATCH
} else if (term.esc & ESC_UTF8) {
tdefutf8(u);
} else if (term.esc & ESC_ALTCHARSET) {
@@ -2610,8 +3493,15 @@ check_control_code:
*/
return;
}
- if (sel.ob.x != -1 && BETWEEN(term.c.y, sel.ob.y, sel.oe.y))
+
+ #if REFLOW_PATCH
+ /* selected() takes relative coordinates */
+ if (selected(term.c.x, term.c.y + term.scr))
+ selclear();
+ #else
+ if (selected(term.c.x, term.c.y))
selclear();
+ #endif // REFLOW_PATCH
gp = &term.line[term.c.y][term.c.x];
if (IS_SET(MODE_WRAP) && (term.c.state & CURSOR_WRAPNEXT)) {
@@ -2620,20 +3510,29 @@ check_control_code:
gp = &term.line[term.c.y][term.c.x];
}
- if (IS_SET(MODE_INSERT) && term.c.x+width < term.col)
+ if (IS_SET(MODE_INSERT) && term.c.x+width < term.col) {
memmove(gp+width, gp, (term.col - term.c.x - width) * sizeof(Glyph));
+ gp->mode &= ~ATTR_WIDE;
+ }
if (term.c.x+width > term.col) {
- tnewline(1);
+ if (IS_SET(MODE_WRAP))
+ tnewline(1);
+ else
+ tmoveto(term.col - width, term.c.y);
gp = &term.line[term.c.y][term.c.x];
}
tsetchar(u, &term.c.attr, term.c.x, term.c.y);
+ #if OSC133_PATCH
+ term.c.attr.mode &= ~ATTR_FTCS_PROMPT;
+ #endif // OSC133_PATCH
+ term.lastc = u;
if (width == 2) {
gp->mode |= ATTR_WIDE;
if (term.c.x+1 < term.col) {
- if (gp[1].mode == ATTR_WIDE && term.c.x+2 < term.col) {
+ if (gp[1].mode == ATTR_WIDE && term.c.x+2 < term.col) {
gp[2].u = ' ';
gp[2].mode &= ~ATTR_WDUMMY;
}
@@ -2644,6 +3543,9 @@ check_control_code:
if (term.c.x+width < term.col) {
tmoveto(term.c.x+width, term.c.y);
} else {
+ #if REFLOW_PATCH
+ term.wrapcwidth[IS_SET(MODE_ALTSCREEN)] = width;
+ #endif // REFLOW_PATCH
term.c.state |= CURSOR_WRAPNEXT;
}
}
@@ -2655,8 +3557,21 @@ twrite(const char *buf, int buflen, int show_ctrl)
Rune u;
int n;
+ #if SYNC_PATCH
+ int su0 = su;
+ twrite_aborted = 0;
+ #endif // SYNC_PATCH
+
for (n = 0; n < buflen; n += charsize) {
- if (IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) {
+ #if SIXEL_PATCH
+ if (IS_SET(MODE_SIXEL) && sixel_st.state != PS_ESC) {
+ charsize = sixel_parser_parse(&sixel_st, (const unsigned char*)buf + n, buflen - n);
+ continue;
+ } else if (IS_SET(MODE_UTF8))
+ #else
+ if (IS_SET(MODE_UTF8))
+ #endif // SIXEL_PATCH
+ {
/* process a complete utf8 char */
charsize = utf8decode(buf + n, &u, buflen - n);
if (charsize == 0)
@@ -2665,6 +3580,12 @@ twrite(const char *buf, int buflen, int show_ctrl)
u = buf[n] & 0xFF;
charsize = 1;
}
+ #if SYNC_PATCH
+ if (su0 && !su) {
+ twrite_aborted = 1;
+ break; // ESU - allow rendering before a new BSU
+ }
+ #endif // SYNC_PATCH
if (show_ctrl && ISCONTROL(u)) {
if (u & 0x80) {
u &= 0x7f;
@@ -2680,21 +3601,35 @@ twrite(const char *buf, int buflen, int show_ctrl)
return n;
}
+#if !REFLOW_PATCH
void
tresize(int col, int row)
{
int i, j;
- int tmp;
- int minrow, mincol;
- int *bp;
- TCursor c;
+ #if COLUMNS_PATCH
+ int tmp = col;
+ int minrow, mincol;
- tmp = col;
if (!term.maxcol)
term.maxcol = term.col;
col = MAX(col, term.maxcol);
minrow = MIN(row, term.row);
mincol = MIN(col, term.maxcol);
+ #else
+ int minrow = MIN(row, term.row);
+ int mincol = MIN(col, term.col);
+ #endif // COLUMNS_PATCH
+ int *bp;
+ #if SIXEL_PATCH
+ int x2;
+ Line line;
+ ImageList *im, *next;
+ #endif // SIXEL_PATCH
+
+ #if KEYBOARDSELECT_PATCH
+ if ( row < term.row || col < term.col )
+ toggle_winmode(trt_kbdselect(XK_Escape, NULL, 0));
+ #endif // KEYBOARDSELECT_PATCH
if (col < 1 || row < 1) {
fprintf(stderr,
@@ -2702,23 +3637,23 @@ tresize(int col, int row)
return;
}
- /*
- * slide screen to keep cursor where we expect it -
- * tscrollup would work here, but we can optimize to
- * memmove because we're freeing the earlier lines
- */
- for (i = 0; i <= term.c.y - row; i++) {
- free(term.line[i]);
- free(term.alt[i]);
- }
- /* ensure that both src and dst are not NULL */
- if (i > 0) {
- memmove(term.line, term.line + i, row * sizeof(Line));
- memmove(term.alt, term.alt + i, row * sizeof(Line));
- }
- for (i += row; i < term.row; i++) {
- free(term.line[i]);
- free(term.alt[i]);
+ /* scroll both screens independently */
+ if (row < term.row) {
+ tcursor(CURSOR_SAVE);
+ tsetscroll(0, term.row - 1);
+ for (i = 0; i < 2; i++) {
+ if (term.c.y >= row) {
+ #if SCROLLBACK_PATCH
+ tscrollup(0, term.c.y - row + 1, !IS_SET(MODE_ALTSCREEN));
+ #else
+ tscrollup(0, term.c.y - row + 1);
+ #endif // SCROLLBACK_PATCH
+ }
+ for (j = row; j < term.row; j++)
+ free(term.line[j]);
+ tswapscreen();
+ tcursor(CURSOR_LOAD);
+ }
}
/* resize to new height */
@@ -2727,13 +3662,14 @@ tresize(int col, int row)
term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty));
term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs));
+ #if SCROLLBACK_PATCH
+ Glyph gc=(Glyph){.bg=term.c.attr.bg, .fg=term.c.attr.fg, .u=' ', .mode=0};
for (i = 0; i < HISTSIZE; i++) {
term.hist[i] = xrealloc(term.hist[i], col * sizeof(Glyph));
- for (j = mincol; j < col; j++) {
- term.hist[i][j] = term.c.attr;
- term.hist[i][j].u = ' ';
- }
+ for (j = mincol; j < col; j++)
+ term.hist[i][j] = gc;
}
+ #endif // SCROLLBACK_PATCH
/* resize each row to new width, zero-pad if needed */
for (i = 0; i < minrow; i++) {
@@ -2746,26 +3682,41 @@ tresize(int col, int row)
term.line[i] = xmalloc(col * sizeof(Glyph));
term.alt[i] = xmalloc(col * sizeof(Glyph));
}
+ #if COLUMNS_PATCH
+ if (col > term.maxcol)
+ #else
+ if (col > term.col)
+ #endif // COLUMNS_PATCH
+ {
+ #if COLUMNS_PATCH
+ bp = term.tabs + term.maxcol;
+ memset(bp, 0, sizeof(*term.tabs) * (col - term.maxcol));
+ #else
+ bp = term.tabs + term.col;
+ memset(bp, 0, sizeof(*term.tabs) * (col - term.col));
+ #endif // COLUMNS_PATCH
- if (col > term.maxcol) {
- bp = term.tabs + term.maxcol;
- memset(bp, 0, sizeof(*term.tabs) * (col - term.maxcol));
while (--bp > term.tabs && !*bp)
/* nothing */ ;
for (bp += tabspaces; bp < term.tabs + col; bp += tabspaces)
*bp = 1;
}
+
/* update terminal size */
+ #if COLUMNS_PATCH
term.col = tmp;
- term.maxcol = col;
+ term.maxcol = col;
+ #else
+ term.col = col;
+ #endif // COLUMNS_PATCH
term.row = row;
+
/* reset scrolling region */
tsetscroll(0, row-1);
- /* make use of the LIMIT in tmoveto */
- tmoveto(term.c.x, term.c.y);
/* Clearing both screens (it makes dirty all lines) */
- c = term.c;
for (i = 0; i < 2; i++) {
+ tmoveto(term.c.x, term.c.y); /* make use of the LIMIT in tmoveto */
+ tcursor(CURSOR_SAVE);
if (mincol < col && 0 < minrow) {
tclearregion(mincol, 0, col - 1, minrow - 1);
}
@@ -2775,32 +3726,77 @@ tresize(int col, int row)
tswapscreen();
tcursor(CURSOR_LOAD);
}
- term.c = c;
+
+ #if SIXEL_PATCH
+ /* expand images into new text cells */
+ for (i = 0; i < 2; i++) {
+ for (im = term.images; im; im = next) {
+ next = im->next;
+ #if SCROLLBACK_PATCH
+ if (IS_SET(MODE_ALTSCREEN)) {
+ if (im->y < 0 || im->y >= term.row) {
+ delete_image(im);
+ continue;
+ }
+ line = term.line[im->y];
+ } else {
+ if (im->y - term.scr < -HISTSIZE || im->y - term.scr >= term.row) {
+ delete_image(im);
+ continue;
+ }
+ line = TLINE(im->y);
+ }
+ #else
+ if (im->y < 0 || im->y >= term.row) {
+ delete_image(im);
+ continue;
+ }
+ line = term.line[im->y];
+ #endif // SCROLLBACK_PATCH
+ x2 = MIN(im->x + im->cols, col) - 1;
+ if (mincol < col && x2 >= mincol && im->x < col)
+ tsetsixelattr(line, MAX(im->x, mincol), x2);
+ }
+ tswapscreen();
+ }
+ #endif // SIXEL_PATCH
}
+#endif // REFLOW_PATCH
void
resettitle(void)
{
+ #if CSI_22_23_PATCH
+ xsettitle(NULL, 0);
+ #else
xsettitle(NULL);
+ #endif // CSI_22_23_PATCH
}
void
drawregion(int x1, int y1, int x2, int y2)
{
int y;
+
for (y = y1; y < y2; y++) {
if (!term.dirty[y])
continue;
term.dirty[y] = 0;
+ #if SCROLLBACK_PATCH || REFLOW_PATCH
xdrawline(TLINE(y), x1, y, x2);
+ #else
+ xdrawline(term.line[y], x1, y, x2);
+ #endif // SCROLLBACK_PATCH
}
}
+#include "patch/st_include.c"
+
void
draw(void)
{
- int cx = term.c.x;
+ int cx = term.c.x, ocx = term.ocx, ocy = term.ocy;
if (!xstartdraw())
return;
@@ -2814,19 +3810,25 @@ draw(void)
cx--;
drawregion(0, 0, term.col, term.row);
+
+ #if KEYBOARDSELECT_PATCH && REFLOW_PATCH
+ if (!kbds_drawcursor())
+ #elif REFLOW_PATCH || SCROLLBACK_PATCH
if (term.scr == 0)
- xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
- term.ocx, term.ocy, term.line[term.ocy][term.ocx],
- term.line[term.ocy], term.col);
- term.ocx = cx, term.ocy = term.c.y;
+ #endif // SCROLLBACK_PATCH | REFLOW_PATCH | KEYBOARDSELECT_PATCH
+ #if LIGATURES_PATCH
+ xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
+ term.ocx, term.ocy, term.line[term.ocy][term.ocx],
+ term.line[term.ocy], term.col);
+ #else
+ xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
+ term.ocx, term.ocy, term.line[term.ocy][term.ocx]);
+ #endif // LIGATURES_PATCH
+ term.ocx = cx;
+ term.ocy = term.c.y;
xfinishdraw();
-
- struct timespec now;
- clock_gettime(CLOCK_MONOTONIC, &now);
- if (ximspot_update_interval && TIMEDIFF(now, term.last_ximspot_update) > ximspot_update_interval) {
+ if (ocx != term.ocx || ocy != term.ocy)
xximspot(term.ocx, term.ocy);
- term.last_ximspot_update = now;
- }
}
void
diff --git a/st.desktop b/st.desktop
@@ -1,8 +1,8 @@
[Desktop Entry]
-Type=Application
Name=st
-Comment=simple-terminal emulator for X
-Icon=st
+Comment=st is a simple terminal implementation for X
Exec=st
-Categories=System;TerminalEmulator
-StartupWMClass=st-256color
+Icon=utilities-terminal
+Terminal=false
+Type=Application
+Categories=System;TerminalEmulator;
+\ No newline at end of file
diff --git a/st.h b/st.h
@@ -1,50 +1,120 @@
/* See LICENSE for license details. */
#include <stdint.h>
+#include <time.h>
#include <sys/types.h>
-
-#include <gd.h>
-#include <glib.h>
+#include <X11/Xatom.h>
+#include <X11/Xlib.h>
+#include <X11/cursorfont.h>
+#include <X11/keysym.h>
+#include <X11/Xft/Xft.h>
+#include <X11/XKBlib.h>
+#include "patches.h"
/* macros */
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define MAX(a, b) ((a) < (b) ? (b) : (a))
#define LEN(a) (sizeof(a) / sizeof(a)[0])
#define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b))
#define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d))
#define DEFAULT(a, b) (a) = (a) ? (a) : (b)
#define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x)
+#if LIGATURES_PATCH
#define ATTRCMP(a, b) (((a).mode & (~ATTR_WRAP) & (~ATTR_LIGA)) != ((b).mode & (~ATTR_WRAP) & (~ATTR_LIGA)) || \
(a).fg != (b).fg || \
(a).bg != (b).bg)
+#else
+#define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || \
+ (a).bg != (b).bg)
+#endif // LIGATURES_PATCH
#define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + \
(t1.tv_nsec-t2.tv_nsec)/1E6)
#define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit)))
#define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b))
#define IS_TRUECOL(x) (1 << 24 & (x))
+#if SCROLLBACK_PATCH || REFLOW_PATCH
+#define HISTSIZE 2000
+#endif // SCROLLBACK_PATCH | REFLOW_PATCH
+
+#if DRAG_AND_DROP_PATCH
+#define HEX_TO_INT(c) ((c) >= '0' && (c) <= '9' ? (c) - '0' : \
+ (c) >= 'a' && (c) <= 'f' ? (c) - 'a' + 10 : \
+ (c) >= 'A' && (c) <= 'F' ? (c) - 'A' + 10 : -1)
+#endif // DRAG_AND_DROP_PATCH
enum glyph_attribute {
- ATTR_NULL = 0,
- ATTR_BOLD = 1 << 0,
- ATTR_FAINT = 1 << 1,
- ATTR_ITALIC = 1 << 2,
- ATTR_UNDERLINE = 1 << 3,
- ATTR_BLINK = 1 << 4,
- ATTR_REVERSE = 1 << 5,
- ATTR_INVISIBLE = 1 << 6,
- ATTR_STRUCK = 1 << 7,
- ATTR_WRAP = 1 << 8,
- ATTR_WIDE = 1 << 9,
- ATTR_WDUMMY = 1 << 10,
- ATTR_BOXDRAW = 1 << 11,
- ATTR_LIGA = 1 << 12,
+ ATTR_NULL = 0,
+ ATTR_SET = 1 << 0,
+ ATTR_BOLD = 1 << 1,
+ ATTR_FAINT = 1 << 2,
+ ATTR_ITALIC = 1 << 3,
+ ATTR_UNDERLINE = 1 << 4,
+ ATTR_BLINK = 1 << 5,
+ ATTR_REVERSE = 1 << 6,
+ ATTR_INVISIBLE = 1 << 7,
+ ATTR_STRUCK = 1 << 8,
+ ATTR_WRAP = 1 << 9,
+ ATTR_WIDE = 1 << 10,
+ ATTR_WDUMMY = 1 << 11,
+ #if SELECTION_COLORS_PATCH
+ ATTR_SELECTED = 1 << 12,
+ #endif // SELECTION_COLORS_PATCH | REFLOW_PATCH
+ #if BOXDRAW_PATCH
+ ATTR_BOXDRAW = 1 << 13,
+ #endif // BOXDRAW_PATCH
+ #if UNDERCURL_PATCH
+ ATTR_DIRTYUNDERLINE = 1 << 14,
+ #endif // UNDERCURL_PATCH
+ #if LIGATURES_PATCH
+ ATTR_LIGA = 1 << 15,
+ #endif // LIGATURES_PATCH
+ #if SIXEL_PATCH
+ ATTR_SIXEL = 1 << 16,
+ #endif // SIXEL_PATCH
+ #if KEYBOARDSELECT_PATCH && REFLOW_PATCH
+ ATTR_HIGHLIGHT = 1 << 17,
+ #endif // KEYBOARDSELECT_PATCH
ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
+ #if OSC133_PATCH
+ ATTR_FTCS_PROMPT = 1 << 18, /* OSC 133 ; A ST */
+ #endif // OSC133_PATCH
};
+#if SIXEL_PATCH
+typedef struct _ImageList {
+ struct _ImageList *next, *prev;
+ unsigned char *pixels;
+ void *pixmap;
+ void *clipmask;
+ int width;
+ int height;
+ int x;
+ int y;
+ #if REFLOW_PATCH
+ int reflow_y;
+ #endif // REFLOW_PATCH
+ int cols;
+ int cw;
+ int ch;
+ int transparent;
+} ImageList;
+#endif // SIXEL_PATCH
+
+#if WIDE_GLYPHS_PATCH
enum drawing_mode {
DRAW_NONE = 0,
DRAW_BG = 1 << 0,
DRAW_FG = 1 << 1,
};
+#endif // WIDE_GLYPHS_PATCH
+
+/* Used to control which screen(s) keybindings and mouse shortcuts apply to. */
+enum screen {
+ S_PRI = -1, /* primary screen */
+ S_ALL = 0, /* both primary and alt screen */
+ S_ALT = 1 /* alternate screen */
+};
enum selection_mode {
SEL_IDLE = 0,
@@ -69,39 +139,229 @@ typedef unsigned short ushort;
typedef uint_least32_t Rune;
+typedef XftDraw *Draw;
+typedef XftColor Color;
+typedef XftGlyphFontSpec GlyphFontSpec;
+
#define Glyph Glyph_
typedef struct {
Rune u; /* character code */
- ushort mode; /* attribute flags */
+ uint32_t mode; /* attribute flags */
uint32_t fg; /* foreground */
uint32_t bg; /* background */
+ #if UNDERCURL_PATCH
+ int ustyle; /* underline style */
+ int ucolor[3]; /* underline color */
+ #endif // UNDERCURL_PATCH
} Glyph;
typedef Glyph *Line;
+#if LIGATURES_PATCH
+typedef struct {
+ int ox;
+ int charlen;
+ int numspecs;
+ Glyph base;
+} GlyphFontSeq;
+#endif // LIGATURES_PATCH
+
+typedef struct {
+ Glyph attr; /* current char attributes */
+ int x;
+ int y;
+ char state;
+} TCursor;
+
+/* Internal representation of the screen */
+typedef struct {
+ int row; /* nb row */
+ int col; /* nb col */
+ #if COLUMNS_PATCH
+ int maxcol;
+ #endif // COLUMNS_PATCH
+ Line *line; /* screen */
+ Line *alt; /* alternate screen */
+ #if REFLOW_PATCH
+ Line hist[HISTSIZE]; /* history buffer */
+ int histi; /* history index */
+ int histf; /* nb history available */
+ int scr; /* scroll back */
+ int wrapcwidth[2]; /* used in updating WRAPNEXT when resizing */
+ #elif SCROLLBACK_PATCH
+ Line hist[HISTSIZE]; /* history buffer */
+ int histi; /* history index */
+ int histn; /* number of history entries */
+ int scr; /* scroll back */
+ #endif // SCROLLBACK_PATCH | REFLOW_PATCH
+ int *dirty; /* dirtyness of lines */
+ TCursor c; /* cursor */
+ int ocx; /* old cursor col */
+ int ocy; /* old cursor row */
+ int top; /* top scroll limit */
+ int bot; /* bottom scroll limit */
+ int mode; /* terminal mode flags */
+ int esc; /* escape state flags */
+ char trantbl[4]; /* charset table translation */
+ int charset; /* current charset */
+ int icharset; /* selected charset for sequence */
+ int *tabs;
+ #if SIXEL_PATCH
+ ImageList *images; /* sixel images */
+ ImageList *images_alt; /* sixel images for alternate screen */
+ #endif // SIXEL_PATCH
+ Rune lastc; /* last printed char outside of sequence, 0 if control */
+ #if OSC7_PATCH
+ char* cwd; /* current working directory */
+ #endif // OSC7_PATCH
+} Term;
+
typedef union {
int i;
uint ui;
float f;
const void *v;
+ const char *s;
} Arg;
+/* Purely graphic info */
typedef struct {
- uint b;
- uint mask;
+ int tw, th; /* tty width and height */
+ int w, h; /* window width and height */
+ #if BACKGROUND_IMAGE_PATCH
+ int x, y; /* window location */
+ #endif // BACKGROUND_IMAGE_PATCH
+ #if ANYSIZE_PATCH
+ int hborderpx, vborderpx;
+ #endif // ANYSIZE_PATCH
+ int ch; /* char height */
+ int cw; /* char width */
+ #if VERTCENTER_PATCH
+ int cyo; /* char y offset */
+ #endif // VERTCENTER_PATCH
+ int mode; /* window state/mode flags */
+ int cursor; /* cursor style */
+} TermWindow;
+
+typedef struct {
+ Display *dpy;
+ Colormap cmap;
+ Window win;
+ Drawable buf;
+ GlyphFontSpec *specbuf; /* font spec buffer used for rendering */
+ #if LIGATURES_PATCH
+ GlyphFontSeq *specseq;
+ #endif // LIGATURES_PATCH
+ Atom xembed, wmdeletewin, netwmname, netwmiconname, netwmpid;
+ #if DRAG_AND_DROP_PATCH
+ Atom XdndTypeList, XdndSelection, XdndEnter, XdndPosition, XdndStatus,
+ XdndLeave, XdndDrop, XdndFinished, XdndActionCopy, XdndActionMove,
+ XdndActionLink, XdndActionAsk, XdndActionPrivate, XtextUriList,
+ XtextPlain, XdndAware;
+ int64_t XdndSourceWin, XdndSourceVersion;
+ int32_t XdndSourceFormat;
+ #endif // DRAG_AND_DROP_PATCH
+ #if FULLSCREEN_PATCH
+ Atom netwmstate, netwmfullscreen;
+ #endif // FULLSCREEN_PATCH
+ #if NETWMICON_PATCH || NETWMICON_LEGACY_PATCH || NETWMICON_FF_PATCH
+ Atom netwmicon;
+ #endif // NETWMICON_PATCH
+ struct {
+ XIM xim;
+ XIC xic;
+ XPoint spot;
+ XVaNestedList spotlist;
+ } ime;
+ Draw draw;
+ #if BACKGROUND_IMAGE_PATCH
+ GC bggc; /* Graphics Context for background */
+ #endif // BACKGROUND_IMAGE_PATCH
+ Visual *vis;
+ XSetWindowAttributes attrs;
+ #if HIDECURSOR_PATCH || OPENURLONCLICK_PATCH
+ /* Here, we use the term *pointer* to differentiate the cursor
+ * one sees when hovering the mouse over the terminal from, e.g.,
+ * a green rectangle where text would be entered. */
+ Cursor vpointer, bpointer; /* visible and hidden pointers */
+ int pointerisvisible;
+ #endif // HIDECURSOR_PATCH
+ #if OPENURLONCLICK_PATCH
+ Cursor upointer;
+ #endif // OPENURLONCLICK_PATCH
+ int scr;
+ int isfixed; /* is fixed geometry? */
+ #if ALPHA_PATCH
+ int depth; /* bit depth */
+ #endif // ALPHA_PATCH
+ int l, t; /* left and top offset */
+ int gm; /* geometry mask */
+} XWindow;
+
+typedef struct {
+ Atom xtarget;
+ char *primary, *clipboard;
+ struct timespec tclick1;
+ struct timespec tclick2;
+} XSelection;
+
+/* types used in config.h */
+typedef struct {
+ uint mod;
+ KeySym keysym;
void (*func)(const Arg *);
const Arg arg;
-} MouseKey;
+ int screen;
+} Shortcut;
+
+typedef struct {
+ uint mod;
+ uint button;
+ void (*func)(const Arg *);
+ const Arg arg;
+ uint release;
+ int screen;
+} MouseShortcut;
+
+typedef struct {
+ KeySym k;
+ uint mask;
+ char *s;
+ /* three-valued logic variables: 0 indifferent, 1 on, -1 off */
+ signed char appkey; /* application keypad */
+ signed char appcursor; /* application cursor */
+} Key;
+
+/* Font structure */
+#define Font Font_
+typedef struct {
+ int height;
+ int width;
+ int ascent;
+ int descent;
+ int badslant;
+ int badweight;
+ short lbearing;
+ short rbearing;
+ XftFont *match;
+ FcFontSet *set;
+ FcPattern *pattern;
+} Font;
+
+/* Drawing Context */
+typedef struct {
+ Color *col;
+ size_t collen;
+ Font font, bfont, ifont, ibfont;
+ GC gc;
+} DC;
void die(const char *, ...);
void redraw(void);
void draw(void);
+void drawregion(int, int, int, int);
+void tfulldirt(void);
-void externalpipe(const Arg *);
-void iso14755(const Arg *);
-void kscrolldown(const Arg *);
-void kscrollup(const Arg *);
-void newterm(const Arg *);
void printscreen(const Arg *);
void printsel(const Arg *);
void sendbreak(const Arg *);
@@ -122,6 +382,7 @@ void resettitle(void);
void selclear(void);
void selinit(void);
+void selremove(void);
void selstart(int, int, int);
void selextend(int, int, int, int);
int selected(int, int);
@@ -133,26 +394,51 @@ void *xmalloc(size_t);
void *xrealloc(void *, size_t);
char *xstrdup(const char *);
+int xgetcolor(int x, unsigned char *r, unsigned char *g, unsigned char *b);
+
+#if BOXDRAW_PATCH
int isboxdraw(Rune);
ushort boxdrawindex(const Glyph *);
#ifdef XFT_VERSION
/* only exposed to x.c, otherwise we'll need Xft.h for the types */
void boxdraw_xinit(Display *, Colormap, XftDraw *, Visual *);
void drawboxes(int, int, int, int, XftColor *, XftColor *, const XftGlyphFontSpec *, int);
-#endif
+#endif // XFT_VERSION
+#endif // BOXDRAW_PATCH
/* config.h globals */
extern char *utmp;
+extern char *scroll;
extern char *stty_args;
extern char *vtiden;
extern wchar_t *worddelimiters;
+#if KEYBOARDSELECT_PATCH && REFLOW_PATCH
+extern wchar_t *kbds_sdelim;
+extern wchar_t *kbds_ldelim;
+#endif // KEYBOARDSELECT_PATCH
extern int allowaltscreen;
+extern int allowwindowops;
extern char *termname;
extern unsigned int tabspaces;
extern unsigned int defaultfg;
extern unsigned int defaultbg;
extern unsigned int defaultcs;
+#if EXTERNALPIPE_PATCH
+extern int extpipeactive;
+#endif // EXTERNALPIPE_PATCH
+
+#if BOXDRAW_PATCH
extern const int boxdraw, boxdraw_bold, boxdraw_braille;
+#endif // BOXDRAW_PATCH
+#if ALPHA_PATCH
extern float alpha;
-extern MouseKey mkeys[];
-extern int ximspot_update_interval;
+#if ALPHA_FOCUS_HIGHLIGHT_PATCH
+extern float alphaUnfocused;
+#endif // ALPHA_FOCUS_HIGHLIGHT_PATCH
+#endif // ALPHA_PATCH
+
+extern DC dc;
+extern XWindow xw;
+extern XSelection xsel;
+extern TermWindow win;
+extern Term term;
diff --git a/st.info b/st.info
@@ -1,4 +1,6 @@
-st| simpleterm,
+st-mono| simpleterm monocolor,
+# undercurl patch / UNDERCURL_PATCH
+ Su,
acsc=+C\,D-A.B0E``aaffgghFiGjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,
am,
bce,
@@ -10,7 +12,7 @@ st| simpleterm,
civis=\E[?25l,
clear=\E[H\E[2J,
cnorm=\E[?12l\E[?25h,
- colors#8,
+ colors#2,
cols#80,
cr=^M,
csr=\E[%i%p1%d;%p2%dr,
@@ -33,6 +35,7 @@ st| simpleterm,
el=\E[K,
el1=\E[1K,
enacs=\E)0,
+ E3=\E[3J,
flash=\E[?5h$<80/>\E[?5l,
fsl=^G,
home=\E[H,
@@ -158,9 +161,12 @@ st| simpleterm,
rc=\E8,
rev=\E[7m,
ri=\EM,
+ rin=\E[%p1%dT,
ritm=\E[23m,
rmacs=\E(B,
- rmcup=\E[?1049l,
+# CSI 22, 23 patch / CSI_22_23_PATCH
+# rmcup=\E[?1049l,
+ rmcup=\E[?1049l\E[23;0;0t,
rmir=\E[4l,
rmkx=\E[?1l\E>,
rmso=\E[27m,
@@ -168,15 +174,12 @@ st| simpleterm,
rs1=\Ec,
rs2=\E[4l\E>\E[?1034l,
sc=\E7,
- setab=\E[4%p1%dm,
- setaf=\E[3%p1%dm,
- setb=\E[4%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m,
- setf=\E[3%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m,
- sgr0=\E[0m,
- 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,
sitm=\E[3m,
+ sgr0=\E[0m,
smacs=\E(0,
- smcup=\E[?1049h,
+# CSI 22, 23 patch / CSI_22_23_PATCH
+# smcup=\E[?1049h,
+ smcup=\E[?1049h\E[22;0;0t,
smir=\E[4h,
smkx=\E[?1h\E=,
smso=\E[7m,
@@ -188,11 +191,28 @@ st| simpleterm,
# XTerm extensions
rmxx=\E[29m,
smxx=\E[9m,
+ BE=\E[?2004h,
+ BD=\E[?2004l,
+ PS=\E[200~,
+ PE=\E[201~,
+# disabled rep for now: causes some issues with older ncurses versions.
+# rep=%p1%c\E[%p2%{1}%-%db,
# tmux extensions, see TERMINFO EXTENSIONS in tmux(1)
Tc,
Ms=\E]52;%p1%s;%p2%s\007,
Se=\E[2 q,
Ss=\E[%p1%d q,
+# sync patch / SYNC_PATCH
+ Sync=\EP=%p1%ds\E\\,
+
+st| simpleterm,
+ use=st-mono,
+ colors#8,
+ setab=\E[4%p1%dm,
+ setaf=\E[3%p1%dm,
+ setb=\E[4%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m,
+ setf=\E[3%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m,
+ 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,
st-256color| simpleterm with 256 colors,
use=st,
@@ -220,3 +240,13 @@ st-meta-256color| simpleterm with meta key and 256 colors,
smm=\E[?1034h,
rs2=\E[4l\E>\E[?1034h,
is2=\E[4l\E>\E[?1034h,
+
+st-bs| simpleterm with backspace as backspace,
+ use=st,
+ kbs=\010,
+ kdch1=\177,
+
+st-bs-256color| simpleterm with backspace as backspace and 256colors,
+ use=st-256color,
+ kbs=\010,
+ kdch1=\177,
diff --git a/st.png b/st.png
Binary files differ.
diff --git a/utils.h b/utils.h
@@ -1,23 +0,0 @@
-/// Dynamic memory-chunk, with (1) datatype size, (2/3) initialized / allocated chunk, (4) content
-typedef struct { uint8_t const elSize; uint32_t init, alloc; char* content; } DynamicArray;
-#define UTF8_ARRAY {4, 0, 0, NULL}
-
-static inline int p_alloc(DynamicArray *s, uint32_t amount) {
- uint32_t const diff=s->init+s->elSize*amount-s->alloc, nas=s->alloc+max(diff,15)*s->elSize;
- if (s->alloc < s->init + s->elSize * amount) {
- char* tmp = realloc(s->content, nas);
- if (!tmp) return 0;
- s->alloc = nas, s->content = tmp;
- }
- return 1;
-}
-static inline char *view(DynamicArray * s, uint32_t i) { return s->content + i*s->elSize; }
-static inline char *end(DynamicArray *s, uint32_t i) { return s->content +s->init-(i+1)*s->elSize; }
-static inline uint32_t getU32(DynamicArray* s, uint32_t i, int b) { return *((uint32_t*) (b ?view(s,i) :end(s,i))); }
-static char *expand(DynamicArray *s) { if (!p_alloc(s, 1)) return NULL; s->init += s->elSize; return end(s, 0); }
-static inline void pop(DynamicArray* s) { s->init -= s->elSize; }
-static inline void empty(DynamicArray* s) { s->init = 0; }
-static inline int size(DynamicArray const * s) { return s->init / s->elSize; }
-static inline void assign(DynamicArray* s, DynamicArray const *o) {
- if (p_alloc(s, size(o))) memcpy(s->content, o->content, (s->init=o->init));
-}
diff --git a/win.h b/win.h
@@ -21,17 +21,31 @@ enum win_mode {
MODE_NUMLOCK = 1 << 17,
MODE_MOUSE = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\
|MODE_MOUSEMANY,
+ MODE_PLACEHOLDER = 1 << 18,
+ #if KEYBOARDSELECT_PATCH
+ MODE_KBDSELECT = 1 << 19,
+ #endif // KEYBOARDSELECT_PATCH
};
void xbell(void);
void xclipcopy(void);
+#if LIGATURES_PATCH
void xdrawcursor(int, int, Glyph, int, int, Glyph, Line, int);
+#else
+void xdrawcursor(int, int, Glyph, int, int, Glyph);
+#endif // LIGATURES_PATCH
void xdrawline(Line, int, int, int);
void xfinishdraw(void);
void xloadcols(void);
int xsetcolorname(int, const char *);
void xseticontitle(char *);
+#if CSI_22_23_PATCH
+void xfreetitlestack(void);
+void xsettitle(char *, int);
+void xpushtitle(void);
+#else
void xsettitle(char *);
+#endif // CSI_22_23_PATCH
int xsetcursor(int);
void xsetmode(int, unsigned int);
void xsetpointermotion(int);
@@ -39,3 +53,6 @@ void xsetsel(char *);
int xstartdraw(void);
void xximspot(int, int);
void xclearwin(void);
+#if REFLOW_PATCH && KEYBOARDSELECT_PATCH
+void xdrawglyph(Glyph, int, int);
+#endif // KEYBOARDSELECT_PATCH
+\ No newline at end of file
diff --git a/x.c b/x.c
@@ -14,49 +14,40 @@
#include <X11/keysym.h>
#include <X11/Xft/Xft.h>
#include <X11/XKBlib.h>
-#include <X11/Xresource.h>
-static char *argv0;
+char *argv0;
#include "arg.h"
#include "st.h"
#include "win.h"
+#if LIGATURES_PATCH
#include "hb.h"
-
-/* types used in config.h */
-typedef struct {
- uint mod;
- KeySym keysym;
- void (*func)(const Arg *);
- const Arg arg;
-} Shortcut;
-
-typedef struct {
- uint b;
- uint mask;
- char *s;
-} MouseShortcut;
-
-typedef struct {
- KeySym k;
- uint mask;
- char *s;
- /* three-valued logic variables: 0 indifferent, 1 on, -1 off */
- signed char appkey; /* application keypad */
- signed char appcursor; /* application cursor */
-} Key;
-
-/* Xresources preferences */
-enum resource_type {
- STRING = 0,
- INTEGER = 1,
- FLOAT = 2
+#endif // LIGATURES_PATCH
+
+#if THEMED_CURSOR_PATCH
+#include <X11/Xcursor/Xcursor.h>
+#endif // THEMED_CURSOR_PATCH
+
+#if SIXEL_PATCH
+#include <Imlib2.h>
+#include "sixel.h"
+#endif // SIXEL_PATCH
+
+#if UNDERCURL_PATCH
+/* Undercurl slope types */
+enum undercurl_slope_type {
+ UNDERCURL_SLOPE_ASCENDING = 0,
+ UNDERCURL_SLOPE_TOP_CAP = 1,
+ UNDERCURL_SLOPE_DESCENDING = 2,
+ UNDERCURL_SLOPE_BOTTOM_CAP = 3
};
+#endif // UNDERCURL_PATCH
-typedef struct {
- char *name;
- enum resource_type type;
- void *dst;
-} ResourcePref;
+#if ANYGEOMETRY_PATCH
+typedef enum {
+ PixelGeometry,
+ CellGeometry
+} Geometry;
+#endif // ANYGEOMETRY_PATCH
/* X modifiers */
#define XK_ANY_MOD UINT_MAX
@@ -68,14 +59,22 @@ static void clipcopy(const Arg *);
static void clippaste(const Arg *);
static void numlock(const Arg *);
static void selpaste(const Arg *);
-static void changealpha(const Arg *);
+static void ttysend(const Arg *);
static void zoom(const Arg *);
static void zoomabs(const Arg *);
static void zoomreset(const Arg *);
+#include "patch/st_include.h"
+#include "patch/x_include.h"
+
/* config.h for applying patches and the configuration. */
#include "config.h"
+#if CSI_22_23_PATCH
+/* size of title stack */
+#define TITLESTACKSIZE 8
+#endif // CSI_22_23_PATCH
+
/* XEMBED messages */
#define XEMBED_FOCUS_IN 4
#define XEMBED_FOCUS_OUT 5
@@ -86,83 +85,25 @@ static void zoomreset(const Arg *);
#define TRUEGREEN(x) (((x) & 0xff00))
#define TRUEBLUE(x) (((x) & 0xff) << 8)
-typedef XftDraw *Draw;
-typedef XftColor Color;
-typedef XftGlyphFontSpec GlyphFontSpec;
-
-typedef unsigned long int CARD32;
-
-/* Purely graphic info */
-typedef struct {
- int tw, th; /* tty width and height */
- int w, h; /* window width and height */
- int hborderpx, vborderpx;
- int ch; /* char height */
- int cw; /* char width */
- int cyo; /* char y offset */
- int mode; /* window state/mode flags */
- int cursor; /* cursor style */
-} TermWindow;
-
-typedef struct {
- Display *dpy;
- Colormap cmap;
- Window win;
- Drawable buf;
- GlyphFontSpec *specbuf; /* font spec buffer used for rendering */
- Atom xembed, wmdeletewin, netwmname, netwmicon, netwmiconname, netwmpid;
- XIM xim;
- XIC xic;
- Draw draw;
- Visual *vis;
- XSetWindowAttributes attrs;
- int scr;
- int isfixed; /* is fixed geometry? */
- int depth; /* bit depth */
- int l, t; /* left and top offset */
- int gm; /* geometry mask */
-} XWindow;
-
-typedef struct {
- Atom xtarget;
- char *primary, *clipboard;
- struct timespec tclick1;
- struct timespec tclick2;
-} XSelection;
-
-/* Font structure */
-#define Font Font_
-typedef struct {
- int height;
- int width;
- int ascent;
- int descent;
- int badslant;
- int badweight;
- short lbearing;
- short rbearing;
- XftFont *match;
- FcFontSet *set;
- FcPattern *pattern;
-} Font;
-
-/* Drawing Context */
-typedef struct {
- Color *col;
- size_t collen;
- Font font, bfont, ifont, ibfont;
- GC gc;
-} DC;
-
static inline ushort sixd_to_16bit(int);
static int xmakeglyphfontspecs(XftGlyphFontSpec *, const Glyph *, int, int, int);
+#if LIGATURES_PATCH && WIDE_GLYPHS_PATCH
+static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int, int, int);
+#elif LIGATURES_PATCH || WIDE_GLYPHS_PATCH
static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int, int);
-static void xdrawglyph(Glyph, int, int);
+#else
+static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int);
+#endif // WIDE_GLYPHS_PATCH | LIGATURES_PATCH
+#if LIGATURES_PATCH
+static inline void xresetfontsettings(uint32_t mode, Font **font, int *frcflags);
+#endif // LIGATURES_PATCH
+void xdrawglyph(Glyph, int, int);
static void xclear(int, int, int, int);
static int xgeommasktogravity(int);
-static void ximopen(Display *);
+static int ximopen(Display *);
static void ximinstantiate(Display *, XPointer, XPointer);
static void ximdestroy(XIM, XPointer, XPointer);
+static int xicdestroy(XIC, XPointer, XPointer);
static void xinit(int, int);
static void cresize(int, int);
static void xresize(int, int);
@@ -170,8 +111,6 @@ static void xhints(void);
static int xloadcolor(int, const char *, Color *);
static int xloadfont(Font *, FcPattern *);
static void xloadfonts(const char *, double);
-static int xloadsparefont(FcPattern *, int);
-static void xloadsparefonts(void);
static void xunloadfont(Font *);
static void xunloadfonts(void);
static void xsetenv(void);
@@ -186,6 +125,7 @@ static void kpress(XEvent *);
static void cmessage(XEvent *);
static void resize(XEvent *);
static void focus(XEvent *);
+static uint buttonmask(uint);
static void brelease(XEvent *);
static void bpress(XEvent *);
static void bmotion(XEvent *);
@@ -194,6 +134,10 @@ static void selnotify(XEvent *);
static void selclear_(XEvent *);
static void selrequest(XEvent *);
static void setsel(char *, Time);
+#if XRESOURCES_PATCH && XRESOURCES_RELOAD_PATCH || BACKGROUND_IMAGE_PATCH && BACKGROUND_IMAGE_RELOAD_PATCH
+static void sigusr1_reload(int sig);
+#endif // XRESOURCES_RELOAD_PATCH | BACKGROUND_IMAGE_RELOAD_PATCH
+static int mouseaction(XEvent *, uint);
static void mousesel(XEvent *, int);
static void mousereport(XEvent *);
static char *kmap(KeySym, uint);
@@ -226,13 +170,23 @@ static void (*handler[LASTEvent])(XEvent *) = {
*/
[PropertyNotify] = propnotify,
[SelectionRequest] = selrequest,
+ #if ST_EMBEDDER_PATCH
+ [CreateNotify] = createnotify,
+ [DestroyNotify] = destroynotify,
+ #endif // ST_EMBEDDER_PATCH
};
/* Globals */
-static DC dc;
-static XWindow xw;
-static XSelection xsel;
-static TermWindow win;
+Term term;
+DC dc;
+XWindow xw;
+XSelection xsel;
+TermWindow win;
+
+#if CSI_22_23_PATCH
+static int tstki; /* title stack index */
+static char *titlestack[TITLESTACKSIZE]; /* title stack */
+#endif // CSI_22_23_PATCH
/* Font Ring Cache */
enum {
@@ -256,7 +210,9 @@ static char *usedfont = NULL;
static double usedfontsize = 0;
static double defaultfontsize = 0;
+#if ALPHA_PATCH
static char *opt_alpha = NULL;
+#endif // ALPHA_PATCH
static char *opt_class = NULL;
static char **opt_cmd = NULL;
static char *opt_embed = NULL;
@@ -265,12 +221,30 @@ static char *opt_io = NULL;
static char *opt_line = NULL;
static char *opt_name = NULL;
static char *opt_title = NULL;
+#if WORKINGDIR_PATCH
+static char *opt_dir = NULL;
+#endif // WORKINGDIR_PATCH
-static int oldbutton = 3; /* button event on startup: 3 = release */
-static int cursorblinks = 0;
+#if ALPHA_PATCH && ALPHA_FOCUS_HIGHLIGHT_PATCH
+static int focused = 0;
+#endif // ALPHA_FOCUS_HIGHLIGHT_PATCH
+static uint buttons; /* bit field of pressed buttons */
+#if BLINKING_CURSOR_PATCH
+static int cursorblinks = 0;
+#endif // BLINKING_CURSOR_PATCH
+#if VISUALBELL_1_PATCH
+static int bellon = 0; /* visual bell status */
+#endif // VISUALBELL_1_PATCH
+#if RELATIVEBORDER_PATCH
+int borderpx;
+#endif // RELATIVEBORDER_PATCH
+#if SWAPMOUSE_PATCH
static Cursor cursor;
static XColor xmousefg, xmousebg;
+#endif // SWAPMOUSE_PATCH
+
+#include "patch/x_include.c"
void
clipcopy(const Arg *dummy)
@@ -292,38 +266,38 @@ clippaste(const Arg *dummy)
{
Atom clipboard;
+ #if KEYBOARDSELECT_PATCH && REFLOW_PATCH
+ if (IS_SET(MODE_KBDSELECT) && !kbds_issearchmode())
+ return;
+ #endif // KEYBOARDSELECT_PATCH
+
clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
XConvertSelection(xw.dpy, clipboard, xsel.xtarget, clipboard,
xw.win, CurrentTime);
}
void
-selpaste(const Arg *dummy)
+numlock(const Arg *dummy)
{
- XConvertSelection(xw.dpy, XA_PRIMARY, xsel.xtarget, XA_PRIMARY,
- xw.win, CurrentTime);
+ win.mode ^= MODE_NUMLOCK;
}
void
-numlock(const Arg *dummy)
+selpaste(const Arg *dummy)
{
- win.mode ^= MODE_NUMLOCK;
+ #if KEYBOARDSELECT_PATCH && REFLOW_PATCH
+ if (IS_SET(MODE_KBDSELECT) && !kbds_issearchmode())
+ return;
+ #endif // KEYBOARDSELECT_PATCH
+
+ XConvertSelection(xw.dpy, XA_PRIMARY, xsel.xtarget, XA_PRIMARY,
+ xw.win, CurrentTime);
}
void
-changealpha(const Arg *arg)
+ttysend(const Arg *arg)
{
- if(alpha > 1 && arg->f == 2 )
- alpha = 1;
- if((alpha > 0 && arg->f < 0) || (alpha < 1 && arg->f > 0))
- alpha += arg->f;
- if(alpha < 0)
- alpha = 0;
- if(alpha > 1)
- alpha = 1;
-
- xloadcols();
- redraw();
+ ttywrite(arg->s, strlen(arg->s), 1);
}
void
@@ -332,15 +306,42 @@ zoom(const Arg *arg)
Arg larg;
larg.f = usedfontsize + arg->f;
+ #if SIXEL_PATCH
+ if (larg.f >= 1.0)
+ zoomabs(&larg);
+ #else
zoomabs(&larg);
+ #endif // SIXEL_PATCH
}
void
zoomabs(const Arg *arg)
{
+ #if SIXEL_PATCH
+ int i;
+ ImageList *im;
+ #endif // SIXEL_PATCH
+
xunloadfonts();
xloadfonts(usedfont, arg->f);
+ #if FONT2_PATCH
xloadsparefonts();
+ #endif // FONT2_PATCH
+
+ #if SIXEL_PATCH
+ /* delete old pixmaps so that xfinishdraw() can create new scaled ones */
+ for (im = term.images, i = 0; i < 2; i++, im = term.images_alt) {
+ for (; im; im = im->next) {
+ if (im->pixmap)
+ XFreePixmap(xw.dpy, (Drawable)im->pixmap);
+ if (im->clipmask)
+ XFreePixmap(xw.dpy, (Drawable)im->clipmask);
+ im->pixmap = NULL;
+ im->clipmask = NULL;
+ }
+ }
+ #endif // SIXEL_PATCH
+
cresize(0, 0);
redraw();
xhints();
@@ -360,7 +361,11 @@ zoomreset(const Arg *arg)
int
evcol(XEvent *e)
{
+ #if ANYSIZE_PATCH
+ int x = e->xbutton.x - win.hborderpx;
+ #else
int x = e->xbutton.x - borderpx;
+ #endif // ANYSIZE_PATCH
LIMIT(x, 0, win.tw - 1);
return x / win.cw;
}
@@ -368,16 +373,59 @@ evcol(XEvent *e)
int
evrow(XEvent *e)
{
+ #if ANYSIZE_PATCH
+ int y = e->xbutton.y - win.vborderpx;
+ #else
int y = e->xbutton.y - borderpx;
+ #endif // ANYSIZE_PATCH
LIMIT(y, 0, win.th - 1);
return y / win.ch;
}
+uint
+buttonmask(uint button)
+{
+ return button == Button1 ? Button1Mask
+ : button == Button2 ? Button2Mask
+ : button == Button3 ? Button3Mask
+ : button == Button4 ? Button4Mask
+ : button == Button5 ? Button5Mask
+ : 0;
+}
+
+int
+mouseaction(XEvent *e, uint release)
+{
+ MouseShortcut *ms;
+ int screen = tisaltscr() ? S_ALT : S_PRI;
+
+ /* ignore Button<N>mask for Button<N> - it's set on release */
+ uint state = e->xbutton.state & ~buttonmask(e->xbutton.button);
+
+ for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) {
+ if (ms->release == release &&
+ ms->button == e->xbutton.button &&
+ (!ms->screen || (ms->screen == screen)) &&
+ (match(ms->mod, state) || /* exact or forced */
+ match(ms->mod, state & ~forcemousemod))) {
+ ms->func(&(ms->arg));
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
void
mousesel(XEvent *e, int done)
{
int type, seltype = SEL_REGULAR;
- uint state = e->xbutton.state & ~(Button1Mask | forceselmod);
+ uint state = e->xbutton.state & ~(Button1Mask | forcemousemod);
+
+ #if KEYBOARDSELECT_PATCH && REFLOW_PATCH
+ if (kbds_isselectmode())
+ return;
+ #endif // KEYBOARDSELECT_PATCH
for (type = 1; type < LEN(selmasks); ++type) {
if (match(selmasks[type], state)) {
@@ -393,62 +441,69 @@ mousesel(XEvent *e, int done)
void
mousereport(XEvent *e)
{
- int len, x = evcol(e), y = evrow(e),
- button = e->xbutton.button, state = e->xbutton.state;
+ int len, btn, code;
+ int x = evcol(e), y = evrow(e);
+ int state = e->xbutton.state;
char buf[40];
static int ox, oy;
- /* from urxvt */
- if (e->xbutton.type == MotionNotify) {
+ if (e->type == MotionNotify) {
if (x == ox && y == oy)
return;
if (!IS_SET(MODE_MOUSEMOTION) && !IS_SET(MODE_MOUSEMANY))
return;
- /* MOUSE_MOTION: no reporting if no button is pressed */
- if (IS_SET(MODE_MOUSEMOTION) && oldbutton == 3)
+ /* MODE_MOUSEMOTION: no reporting if no button is pressed */
+ if (IS_SET(MODE_MOUSEMOTION) && buttons == 0)
return;
- button = oldbutton + 32;
- ox = x;
- oy = y;
+ /* Set btn to lowest-numbered pressed button, or 12 if no
+ * buttons are pressed. */
+ for (btn = 1; btn <= 11 && !(buttons & (1<<(btn-1))); btn++)
+ ;
+ code = 32;
} else {
- if (!IS_SET(MODE_MOUSESGR) && e->xbutton.type == ButtonRelease) {
- button = 3;
- } else {
- button -= Button1;
- if (button >= 3)
- if (button >= 7)
- button += 128 - 7;
- else if (button >= 3)
- button += 64 - 3;
- }
- if (e->xbutton.type == ButtonPress) {
- oldbutton = button;
- ox = x;
- oy = y;
- } else if (e->xbutton.type == ButtonRelease) {
- oldbutton = 3;
+ btn = e->xbutton.button;
+ /* Only buttons 1 through 11 can be encoded */
+ if (btn < 1 || btn > 11)
+ return;
+ if (e->type == ButtonRelease) {
/* MODE_MOUSEX10: no button release reporting */
if (IS_SET(MODE_MOUSEX10))
return;
- if (button == 64 || button == 65)
+ /* Don't send release events for the scroll wheel */
+ if (btn == 4 || btn == 5)
return;
}
+ code = 0;
}
+ ox = x;
+ oy = y;
+
+ /* Encode btn into code. If no button is pressed for a motion event in
+ * MODE_MOUSEMANY, then encode it as a release. */
+ if ((!IS_SET(MODE_MOUSESGR) && e->type == ButtonRelease) || btn == 12)
+ code += 3;
+ else if (btn >= 8)
+ code += 128 + btn - 8;
+ else if (btn >= 4)
+ code += 64 + btn - 4;
+ else
+ code += btn - 1;
+
if (!IS_SET(MODE_MOUSEX10)) {
- button += ((state & ShiftMask ) ? 4 : 0)
- + ((state & Mod4Mask ) ? 8 : 0)
- + ((state & ControlMask) ? 16 : 0);
+ code += ((state & ShiftMask ) ? 4 : 0)
+ + ((state & Mod1Mask ) ? 8 : 0) /* meta key: alt */
+ + ((state & ControlMask) ? 16 : 0);
}
if (IS_SET(MODE_MOUSESGR)) {
len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c",
- button, x+1, y+1,
- e->xbutton.type == ButtonRelease ? 'm' : 'M');
+ code, x+1, y+1,
+ e->type == ButtonRelease ? 'm' : 'M');
} else if (x < 223 && y < 223) {
len = snprintf(buf, sizeof(buf), "\033[M%c%c%c",
- 32+button, 32+x+1, 32+y+1);
+ 32+code, 32+x+1, 32+y+1);
} else {
return;
}
@@ -459,35 +514,22 @@ mousereport(XEvent *e)
void
bpress(XEvent *e)
{
+ int btn = e->xbutton.button;
struct timespec now;
- MouseShortcut *ms;
- MouseKey *mk;
int snap;
- if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
+ if (1 <= btn && btn <= 11)
+ buttons |= 1 << (btn-1);
+
+ if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) {
mousereport(e);
return;
}
- if (tisaltscr()) {
- for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) {
- if (e->xbutton.button == ms->b
- && match(ms->mask, e->xbutton.state)) {
- ttywrite(ms->s, strlen(ms->s), 1);
- return;
- }
- }
- }
-
- for (mk = mkeys; mk < mkeys + LEN(mkeys); mk++) {
- if (e->xbutton.button == mk->b
- && match(mk->mask, e->xbutton.state)) {
- mk->func(&mk->arg);
- return;
- }
- }
+ if (mouseaction(e, 0))
+ return;
- if (e->xbutton.button == Button1) {
+ if (btn == Button1) {
/*
* If the user clicks below predefined timeouts specific
* snapping behaviour is exposed.
@@ -503,7 +545,17 @@ bpress(XEvent *e)
xsel.tclick2 = xsel.tclick1;
xsel.tclick1 = now;
+ #if KEYBOARDSELECT_PATCH && REFLOW_PATCH
+ if (kbds_isselectmode())
+ return;
+ #endif // KEYBOARDSELECT_PATCH
+
selstart(evcol(e), evrow(e), snap);
+
+ #if OPENURLONCLICK_PATCH
+ clearurl();
+ url_click = 1;
+ #endif // OPENURLONCLICK_PATCH
}
}
@@ -519,6 +571,14 @@ propnotify(XEvent *e)
xpev->atom == clipboard)) {
selnotify(e);
}
+
+ #if BACKGROUND_IMAGE_PATCH
+ if (pseudotransparency &&
+ !strncmp(XGetAtomName(xw.dpy, e->xproperty.atom), "_NET_WM_STATE", 13)) {
+ updatexy();
+ redraw();
+ }
+ #endif // BACKGROUND_IMAGE_PATCH
}
void
@@ -528,6 +588,9 @@ selnotify(XEvent *e)
int format;
uchar *data, *last, *repl;
Atom type, incratom, property = None;
+ #if KEYBOARDSELECT_PATCH && REFLOW_PATCH
+ int append = 0;
+ #endif // KEYBOARDSELECT_PATCH
incratom = XInternAtom(xw.dpy, "INCR", 0);
@@ -540,6 +603,13 @@ selnotify(XEvent *e)
if (property == None)
return;
+ #if DRAG_AND_DROP_PATCH
+ if (property == xw.XdndSelection) {
+ xdndsel(e);
+ return;
+ }
+ #endif // DRAG_AND_DROP_PATCH
+
do {
if (XGetWindowProperty(xw.dpy, xw.win, property, ofs,
BUFSIZ/4, False, AnyPropertyType,
@@ -549,7 +619,12 @@ selnotify(XEvent *e)
return;
}
- if (e->type == PropertyNotify && nitems == 0 && rem == 0) {
+ #if BACKGROUND_IMAGE_PATCH
+ if (e->type == PropertyNotify && nitems == 0 && rem == 0 && !pseudotransparency)
+ #else
+ if (e->type == PropertyNotify && nitems == 0 && rem == 0)
+ #endif // BACKGROUND_IMAGE_PATCH
+ {
/*
* If there is some PropertyNotify with no data, then
* this is the signal of the selection owner that all
@@ -567,9 +642,15 @@ selnotify(XEvent *e)
* when the selection owner does send us the next
* chunk of data.
*/
+ #if BACKGROUND_IMAGE_PATCH
+ if (!pseudotransparency) {
+ #endif // BACKGROUND_IMAGE_PATCH
MODBIT(xw.attrs.event_mask, 1, PropertyChangeMask);
XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask,
&xw.attrs);
+ #if BACKGROUND_IMAGE_PATCH
+ }
+ #endif // BACKGROUND_IMAGE_PATCH
/*
* Deleting the property is the transfer start signal.
@@ -578,6 +659,30 @@ selnotify(XEvent *e)
continue;
}
+ #if KEYBOARDSELECT_PATCH && REFLOW_PATCH
+ if (IS_SET(MODE_KBDSELECT) && kbds_issearchmode()) {
+ kbds_pasteintosearch(data, nitems * format / 8, append++);
+ } else {
+ /*
+ * As seen in getsel:
+ * Line endings are inconsistent in the terminal and GUI world
+ * copy and pasting. When receiving some selection data,
+ * replace all '\n' with '\r'.
+ * FIXME: Fix the computer world.
+ */
+ repl = data;
+ last = data + nitems * format / 8;
+ while ((repl = memchr(repl, '\n', last - repl))) {
+ *repl++ = '\r';
+ }
+
+ if (IS_SET(MODE_BRCKTPASTE) && ofs == 0)
+ ttywrite("\033[200~", 6, 0);
+ ttywrite((char *)data, nitems * format / 8, 1);
+ if (IS_SET(MODE_BRCKTPASTE) && rem == 0)
+ ttywrite("\033[201~", 6, 0);
+ }
+ #else
/*
* As seen in getsel:
* Line endings are inconsistent in the terminal and GUI world
@@ -596,6 +701,7 @@ selnotify(XEvent *e)
ttywrite((char *)data, nitems * format / 8, 1);
if (IS_SET(MODE_BRCKTPASTE) && rem == 0)
ttywrite("\033[201~", 6, 0);
+ #endif // KEYBOARDSELECT_PATCH
XFree(data);
/* number of 32-bit chunks returned */
ofs += nitems * format / 32;
@@ -690,8 +796,26 @@ setsel(char *str, Time t)
XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t);
if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win)
selclear();
+
+ #if CLIPBOARD_PATCH
+ clipcopy(NULL);
+ #endif // CLIPBOARD_PATCH
}
+#if XRESOURCES_PATCH && XRESOURCES_RELOAD_PATCH || BACKGROUND_IMAGE_PATCH && BACKGROUND_IMAGE_RELOAD_PATCH
+void
+sigusr1_reload(int sig)
+{
+ #if XRESOURCES_PATCH && XRESOURCES_RELOAD_PATCH
+ reload_config(sig);
+ #endif // XRESOURCES_RELOAD_PATCH
+ #if BACKGROUND_IMAGE_PATCH && BACKGROUND_IMAGE_RELOAD_PATCH
+ reload_image();
+ #endif // BACKGROUND_IMAGE_RELOAD_PATCH
+ signal(SIGUSR1, sigusr1_reload);
+}
+#endif // XRESOURCES_RELOAD_PATCH | BACKGROUND_IMAGE_RELOAD_PATCH
+
void
xsetsel(char *str)
{
@@ -701,20 +825,62 @@ xsetsel(char *str)
void
brelease(XEvent *e)
{
- if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
+ int btn = e->xbutton.button;
+
+ if (1 <= btn && btn <= 11)
+ buttons &= ~(1 << (btn-1));
+
+ if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) {
mousereport(e);
return;
}
- if (e->xbutton.button == Button3)
- selpaste(NULL);
- else if (e->xbutton.button == Button1)
+
+ if (mouseaction(e, 1))
+ return;
+
+ if (btn == Button1) {
mousesel(e, 1);
+ #if OPENURLONCLICK_PATCH
+ if (url_click && e->xkey.state & url_opener_modkey)
+ openUrlOnClick(evcol(e), evrow(e), url_opener);
+ #endif // OPENURLONCLICK_PATCH
+ }
+
+ #if RIGHTCLICKTOPLUMB_PATCH
+ else if (btn == Button3)
+ plumb(xsel.primary);
+ #endif // RIGHTCLICKTOPLUMB_PATCH
}
void
bmotion(XEvent *e)
{
- if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
+ #if HIDECURSOR_PATCH
+ if (!xw.pointerisvisible) {
+ #if SWAPMOUSE_PATCH
+ if (win.mode & MODE_MOUSE)
+ XUndefineCursor(xw.dpy, xw.win);
+ else
+ XDefineCursor(xw.dpy, xw.win, xw.vpointer);
+ #else
+ XDefineCursor(xw.dpy, xw.win, xw.vpointer);
+ #endif // SWAPMOUSE_PATCH
+ xw.pointerisvisible = 1;
+ if (!IS_SET(MODE_MOUSEMANY))
+ xsetpointermotion(0);
+ }
+ #endif // HIDECURSOR_PATCH
+ #if OPENURLONCLICK_PATCH
+ if (!IS_SET(MODE_MOUSE)) {
+ if (!(e->xbutton.state & Button1Mask) && detecturl(evcol(e), evrow(e), 1))
+ XDefineCursor(xw.dpy, xw.win, xw.upointer);
+ else
+ XDefineCursor(xw.dpy, xw.win, xw.vpointer);
+ }
+ url_click = 0;
+ #endif // OPENURLONCLICK_PATCH
+
+ if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) {
mousereport(e);
return;
}
@@ -734,9 +900,14 @@ cresize(int width, int height)
col = (win.w - 2 * borderpx) / win.cw;
row = (win.h - 2 * borderpx) / win.ch;
- col = MAX(1, col);
+ col = MAX(2, col);
row = MAX(1, row);
+ #if ANYSIZE_PATCH
+ win.hborderpx = (win.w - col * win.cw) / 2;
+ win.vborderpx = (win.h - row * win.ch) / 2;
+ #endif // ANYSIZE_PATCH
+
tresize(col, row);
xresize(col, row);
ttyresize(win.tw, win.th);
@@ -748,14 +919,26 @@ xresize(int col, int row)
win.tw = col * win.cw;
win.th = row * win.ch;
+ #if !SINGLE_DRAWABLE_BUFFER_PATCH
XFreePixmap(xw.dpy, xw.buf);
xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
- xw.depth);
+ #if ALPHA_PATCH
+ xw.depth
+ #else
+ DefaultDepth(xw.dpy, xw.scr)
+ #endif // ALPHA_PATCH
+ );
XftDrawChange(xw.draw, xw.buf);
+ #endif // SINGLE_DRAWABLE_BUFFER_PATCH
xclear(0, 0, win.w, win.h);
/* resize to new width */
+ #if LIGATURES_PATCH
+ xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec) * 4);
+ xw.specseq = xrealloc(xw.specseq, col * sizeof(GlyphFontSeq));
+ #else
xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec));
+ #endif // LIGATURES_PATCH
}
ushort
@@ -788,6 +971,49 @@ xloadcolor(int i, const char *name, Color *ncolor)
return XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, ncolor);
}
+#if ALPHA_PATCH && ALPHA_FOCUS_HIGHLIGHT_PATCH
+void
+xloadalpha(void)
+{
+ float const usedAlpha = focused ? alpha : alphaUnfocused;
+ if (opt_alpha) alpha = strtof(opt_alpha, NULL);
+ dc.col[defaultbg].color.alpha = (unsigned short)(0xffff * usedAlpha);
+ dc.col[defaultbg].pixel &= 0x00FFFFFF;
+ dc.col[defaultbg].pixel |= (unsigned char)(0xff * usedAlpha) << 24;
+ #if SELECTION_COLORS_PATCH && SELECTIONBG_ALPHA_PATCH
+ dc.col[selectionbg].color.alpha = (unsigned short)(0xffff * usedAlpha);
+ dc.col[selectionbg].pixel &= 0x00FFFFFF;
+ dc.col[selectionbg].pixel |= (unsigned char)(0xff * usedAlpha) << 24;
+ #endif // SELECTION_COLORS_PATCH && SELECTIONBG_ALPHA_PATCH
+}
+#endif // ALPHA_FOCUS_HIGHLIGHT_PATCH
+
+#if ALPHA_PATCH && ALPHA_FOCUS_HIGHLIGHT_PATCH
+void
+xloadcols(void)
+{
+ static int loaded;
+ Color *cp;
+
+ if (!loaded) {
+ dc.collen = 1 + (defaultbg = MAX(LEN(colorname), 256));
+ dc.col = xmalloc((dc.collen) * sizeof(Color));
+ }
+
+ for (int i = 0; i+1 < dc.collen; ++i)
+ if (!xloadcolor(i, NULL, &dc.col[i])) {
+ if (colorname[i])
+ die("could not allocate color '%s'\n", colorname[i]);
+ else
+ die("could not allocate color %d\n", i);
+ }
+ if (dc.collen) // cannot die, as the color is already loaded.
+ xloadcolor(focused ? bg : bgUnfocused, NULL, &dc.col[defaultbg]);
+
+ xloadalpha();
+ loaded = 1;
+}
+#else
void
xloadcols(void)
{
@@ -810,28 +1036,52 @@ xloadcols(void)
else
die("could not allocate color %d\n", i);
}
-
+ #if ALPHA_PATCH
/* set alpha value of bg color */
if (opt_alpha)
alpha = strtof(opt_alpha, NULL);
dc.col[defaultbg].color.alpha = (unsigned short)(0xffff * alpha);
- dc.col[defaultbg].color.red =
- ((unsigned short)(dc.col[defaultbg].color.red * alpha)) & 0xff00;
- dc.col[defaultbg].color.green =
- ((unsigned short)(dc.col[defaultbg].color.green * alpha)) & 0xff00;
- dc.col[defaultbg].color.blue =
- ((unsigned short)(dc.col[defaultbg].color.blue * alpha)) & 0xff00;
dc.col[defaultbg].pixel &= 0x00FFFFFF;
dc.col[defaultbg].pixel |= (unsigned char)(0xff * alpha) << 24;
+ dc.col[defaultbg].color.red *= alpha;
+ dc.col[defaultbg].color.green *= alpha;
+ dc.col[defaultbg].color.blue *= alpha;
+ #if SELECTION_COLORS_PATCH && SELECTIONBG_ALPHA_PATCH
+ /* set alpha value of selbg color */
+ dc.col[selectionbg].color.alpha = (unsigned short)(0xffff * alpha);
+ dc.col[selectionbg].pixel &= 0x00FFFFFF;
+ dc.col[selectionbg].pixel |= (unsigned char)(0xff * alpha) << 24;
+ dc.col[selectionbg].color.red =
+ ((unsigned short)(dc.col[selectionbg].color.red * alpha)) & 0xff00;
+ dc.col[selectionbg].color.green =
+ ((unsigned short)(dc.col[selectionbg].color.green * alpha)) & 0xff00;
+ dc.col[selectionbg].color.blue =
+ ((unsigned short)(dc.col[selectionbg].color.blue * alpha)) & 0xff00;
+ #endif // SELECTION_COLORS_PATCH && SELECTIONBG_ALPHA_PATCH
+ #endif // ALPHA_PATCH
loaded = 1;
}
+#endif // ALPHA_FOCUS_HIGHLIGHT_PATCH
+
+int
+xgetcolor(int x, unsigned char *r, unsigned char *g, unsigned char *b)
+{
+ if (!BETWEEN(x, 0, dc.collen - 1))
+ return 1;
+
+ *r = dc.col[x].color.red >> 8;
+ *g = dc.col[x].color.green >> 8;
+ *b = dc.col[x].color.blue >> 8;
+
+ return 0;
+}
int
xsetcolorname(int x, const char *name)
{
Color ncolor;
- if (!BETWEEN(x, 0, dc.collen))
+ if (!BETWEEN(x, 0, dc.collen - 1))
return 1;
if (!xloadcolor(x, name, &ncolor))
@@ -839,9 +1089,20 @@ xsetcolorname(int x, const char *name)
XftColorFree(xw.dpy, xw.vis, xw.cmap, &dc.col[x]);
dc.col[x] = ncolor;
- if (x == defaultbg)
- dc.col[defaultbg].color.alpha = (unsigned short)(0xffff * alpha);
+ #if ALPHA_PATCH
+ /* set alpha value of bg color */
+ if (x == defaultbg) {
+ if (opt_alpha)
+ alpha = strtof(opt_alpha, NULL);
+ dc.col[defaultbg].color.alpha = (unsigned short)(0xffff * alpha);
+ dc.col[defaultbg].pixel &= 0x00FFFFFF;
+ dc.col[defaultbg].pixel |= (unsigned char)(0xff * alpha) << 24;
+ dc.col[defaultbg].color.red *= alpha;
+ dc.col[defaultbg].color.green *= alpha;
+ dc.col[defaultbg].color.blue *= alpha;
+ }
+ #endif // ALPHA_PATCH
return 0;
}
@@ -851,9 +1112,22 @@ xsetcolorname(int x, const char *name)
void
xclear(int x1, int y1, int x2, int y2)
{
+ #if BACKGROUND_IMAGE_PATCH
+ if (pseudotransparency)
+ XSetTSOrigin(xw.dpy, xw.bggc, -win.x, -win.y);
+ XFillRectangle(xw.dpy, xw.buf, xw.bggc, x1, y1, x2-x1, y2-y1);
+ #elif INVERT_PATCH
+ Color c;
+ c = dc.col[IS_SET(MODE_REVERSE)? defaultfg : defaultbg];
+ if (invertcolors) {
+ c = invertedcolor(&c);
+ }
+ XftDrawRect(xw.draw, &c, x1, y1, x2-x1, y2-y1);
+ #else
XftDrawRect(xw.draw,
&dc.col[IS_SET(MODE_REVERSE)? defaultfg : defaultbg],
x1, y1, x2-x1, y2-y1);
+ #endif // INVERT_PATCH
}
void
@@ -862,12 +1136,16 @@ xclearwin(void)
xclear(0, 0, win.w, win.h);
}
-
void
xhints(void)
{
+ #if XRESOURCES_PATCH
XClassHint class = {opt_name ? opt_name : "st",
opt_class ? opt_class : "St"};
+ #else
+ XClassHint class = {opt_name ? opt_name : termname,
+ opt_class ? opt_class : termname};
+ #endif // XRESOURCES_PATCH
XWMHints wm = {.flags = InputHint, .input = 1};
XSizeHints *sizeh;
@@ -876,8 +1154,13 @@ xhints(void)
sizeh->flags = PSize | PResizeInc | PBaseSize | PMinSize;
sizeh->height = win.h;
sizeh->width = win.w;
- sizeh->height_inc = 1;
- sizeh->width_inc = 1;
+ #if ANYSIZE_PATCH && !DYNAMIC_PADDING_PATCH || ANYSIZE_SIMPLE_PATCH
+ sizeh->height_inc = 1;
+ sizeh->width_inc = 1;
+ #else
+ sizeh->height_inc = win.ch;
+ sizeh->width_inc = win.cw;
+ #endif // ANYSIZE_PATCH
sizeh->base_height = 2 * borderpx;
sizeh->base_width = 2 * borderpx;
sizeh->min_height = win.ch + 2 * borderpx;
@@ -915,6 +1198,60 @@ xgeommasktogravity(int mask)
}
int
+ximopen(Display *dpy)
+{
+ XIMCallback imdestroy = { .client_data = NULL, .callback = ximdestroy };
+ XICCallback icdestroy = { .client_data = NULL, .callback = xicdestroy };
+
+ xw.ime.xim = XOpenIM(xw.dpy, NULL, NULL, NULL);
+ if (xw.ime.xim == NULL)
+ return 0;
+
+ if (XSetIMValues(xw.ime.xim, XNDestroyCallback, &imdestroy, NULL))
+ fprintf(stderr, "XSetIMValues: "
+ "Could not set XNDestroyCallback.\n");
+
+ xw.ime.spotlist = XVaCreateNestedList(0, XNSpotLocation, &xw.ime.spot,
+ NULL);
+
+ if (xw.ime.xic == NULL) {
+ xw.ime.xic = XCreateIC(xw.ime.xim, XNInputStyle,
+ XIMPreeditNothing | XIMStatusNothing,
+ XNClientWindow, xw.win,
+ XNDestroyCallback, &icdestroy,
+ NULL);
+ }
+ if (xw.ime.xic == NULL)
+ fprintf(stderr, "XCreateIC: Could not create input context.\n");
+
+ return 1;
+}
+
+void
+ximinstantiate(Display *dpy, XPointer client, XPointer call)
+{
+ if (ximopen(dpy))
+ XUnregisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL,
+ ximinstantiate, NULL);
+}
+
+void
+ximdestroy(XIM xim, XPointer client, XPointer call)
+{
+ xw.ime.xim = NULL;
+ XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL,
+ ximinstantiate, NULL);
+ XFree(xw.ime.spotlist);
+}
+
+int
+xicdestroy(XIC xim, XPointer client, XPointer call)
+{
+ xw.ime.xic = NULL;
+ return 1;
+}
+
+int
xloadfont(Font *f, FcPattern *pattern)
{
FcPattern *configured;
@@ -935,7 +1272,11 @@ xloadfont(Font *f, FcPattern *pattern)
FcConfigSubstitute(NULL, configured, FcMatchPattern);
XftDefaultSubstitute(xw.dpy, xw.scr, configured);
+ #if USE_XFTFONTMATCH_PATCH
+ match = XftFontMatch(xw.dpy, xw.scr, pattern, &result);
+ #else
match = FcFontMatch(NULL, configured, &result);
+ #endif // USE_XFTFONTMATCH_PATCH
if (!match) {
FcPatternDestroy(configured);
return 1;
@@ -982,7 +1323,11 @@ xloadfont(Font *f, FcPattern *pattern)
f->rbearing = f->match->max_advance_width;
f->height = f->ascent + f->descent;
+ #if WIDE_GLYPH_SPACING_PATCH
+ f->width = DIVCEIL(extents.xOff > 18 ? extents.xOff / 3 : extents.xOff, strlen(ascii_printable));
+ #else
f->width = DIVCEIL(extents.xOff, strlen(ascii_printable));
+ #endif // WIDE_GLYPH_SPACING_PATCH
return 0;
}
@@ -996,7 +1341,7 @@ xloadfonts(const char *fontstr, double fontsize)
if (fontstr[0] == '-')
pattern = XftXlfdParse(fontstr, False, False);
else
- pattern = FcNameParse((const FcChar8 *)fontstr);
+ pattern = FcNameParse((const FcChar8 *)fontstr);
if (!pattern)
die("can't open font %s\n", fontstr);
@@ -1038,121 +1383,37 @@ xloadfonts(const char *fontstr, double fontsize)
/* Setting character width and height. */
win.cw = ceilf(dc.font.width * cwscale);
win.ch = ceilf(dc.font.height * chscale);
+ #if VERTCENTER_PATCH
win.cyo = ceilf(dc.font.height * (chscale - 1) / 2);
+ #endif // VERTCENTER_PATCH
+ #if RELATIVEBORDER_PATCH
+ borderpx = (int) ceilf(((float)borderperc / 100) * win.cw);
+ #endif // RELATIVEBORDER_PATCH
FcPatternDel(pattern, FC_SLANT);
+ #if !DISABLE_ITALIC_FONTS_PATCH
FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
+ #endif // DISABLE_ITALIC_FONTS_PATCH
if (xloadfont(&dc.ifont, pattern))
die("can't open font %s\n", fontstr);
FcPatternDel(pattern, FC_WEIGHT);
+ #if !DISABLE_BOLD_FONTS_PATCH
FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
+ #endif // DISABLE_BOLD_FONTS_PATCH
if (xloadfont(&dc.ibfont, pattern))
die("can't open font %s\n", fontstr);
FcPatternDel(pattern, FC_SLANT);
+ #if !DISABLE_ROMAN_FONTS_PATCH
FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN);
+ #endif // DISABLE_ROMAN_FONTS_PATCH
if (xloadfont(&dc.bfont, pattern))
die("can't open font %s\n", fontstr);
FcPatternDestroy(pattern);
}
-int
-xloadsparefont(FcPattern *pattern, int flags)
-{
- FcPattern *match;
- FcResult result;
-
- match = FcFontMatch(NULL, pattern, &result);
- if (!match) {
- return 1;
- }
-
- if (!(frc[frclen].font = XftFontOpenPattern(xw.dpy, match))) {
- FcPatternDestroy(match);
- return 1;
- }
-
- frc[frclen].flags = flags;
- /* Believe U+0000 glyph will present in each default font */
- frc[frclen].unicodep = 0;
- frclen++;
-
- return 0;
-}
-
-void
-xloadsparefonts(void)
-{
- FcPattern *pattern;
- double sizeshift, fontval;
- int fc;
- char **fp;
-
- if (frclen != 0)
- die("can't embed spare fonts. cache isn't empty");
-
- /* Calculate count of spare fonts */
- fc = sizeof(font2) / sizeof(*font2);
- if (fc == 0)
- return;
-
- /* Allocate memory for cache entries. */
- if (frccap < 4 * fc) {
- frccap += 4 * fc - frccap;
- frc = xrealloc(frc, frccap * sizeof(Fontcache));
- }
-
- for (fp = font2; fp - font2 < fc; ++fp) {
-
- if (**fp == '-')
- pattern = XftXlfdParse(*fp, False, False);
- else
- pattern = FcNameParse((FcChar8 *)*fp);
-
- if (!pattern)
- die("can't open spare font %s\n", *fp);
-
- if (defaultfontsize > 0) {
- sizeshift = usedfontsize - defaultfontsize;
- if (sizeshift != 0 &&
- FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &fontval) ==
- FcResultMatch) {
- fontval += sizeshift;
- FcPatternDel(pattern, FC_PIXEL_SIZE);
- FcPatternDel(pattern, FC_SIZE);
- FcPatternAddDouble(pattern, FC_PIXEL_SIZE, fontval);
- }
- }
-
- FcPatternAddBool(pattern, FC_SCALABLE, 1);
-
- FcConfigSubstitute(NULL, pattern, FcMatchPattern);
- XftDefaultSubstitute(xw.dpy, xw.scr, pattern);
-
- if (xloadsparefont(pattern, FRC_NORMAL))
- die("can't open spare font %s\n", *fp);
-
- FcPatternDel(pattern, FC_SLANT);
- FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
- if (xloadsparefont(pattern, FRC_ITALIC))
- die("can't open spare font %s\n", *fp);
-
- FcPatternDel(pattern, FC_WEIGHT);
- FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
- if (xloadsparefont(pattern, FRC_ITALICBOLD))
- die("can't open spare font %s\n", *fp);
-
- FcPatternDel(pattern, FC_SLANT);
- FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN);
- if (xloadsparefont(pattern, FRC_BOLD))
- die("can't open spare font %s\n", *fp);
-
- FcPatternDestroy(pattern);
- }
-}
-
void
xunloadfont(Font *f)
{
@@ -1165,8 +1426,10 @@ xunloadfont(Font *f)
void
xunloadfonts(void)
{
+ #if LIGATURES_PATCH
/* Clear Harfbuzz font cache. */
hbunloadfonts();
+ #endif // LIGATURES_PATCH
/* Free the loaded fonts in the font cache. */
while (frclen > 0)
@@ -1179,53 +1442,31 @@ xunloadfonts(void)
}
void
-ximopen(Display *dpy)
-{
- XIMCallback destroy = { .client_data = NULL, .callback = ximdestroy };
-
- if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
- XSetLocaleModifiers("@im=local");
- if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) {
- XSetLocaleModifiers("@im=");
- if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL)
- die("XOpenIM failed. Could not open input device.\n");
- }
- }
- if (XSetIMValues(xw.xim, XNDestroyCallback, &destroy, NULL) != NULL)
- die("XSetIMValues failed. Could not set input method value.\n");
- xw.xic = XCreateIC(xw.xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
- XNClientWindow, xw.win, XNFocusWindow, xw.win, NULL);
- if (xw.xic == NULL)
- die("XCreateIC failed. Could not obtain input method.\n");
-}
-
-void
-ximinstantiate(Display *dpy, XPointer client, XPointer call)
-{
- ximopen(dpy);
- XUnregisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL,
- ximinstantiate, NULL);
-}
-
-void
-ximdestroy(XIM xim, XPointer client, XPointer call)
-{
- xw.xim = NULL;
- XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL,
- ximinstantiate, NULL);
-}
-
-void
xinit(int cols, int rows)
{
XGCValues gcvalues;
- Window parent;
+ #if HIDECURSOR_PATCH
+ Pixmap blankpm;
+ #elif !SWAPMOUSE_PATCH
+ Cursor cursor;
+ #endif // HIDECURSOR_PATCH
+ Window parent, root;
pid_t thispid = getpid();
+ #if !SWAPMOUSE_PATCH
+ XColor xmousefg, xmousebg;
+ #endif // SWAPMOUSE_PATCH
+ #if ALPHA_PATCH
XWindowAttributes attr;
XVisualInfo vis;
+ #endif // ALPHA_PATCH
+ #if !XRESOURCES_PATCH
+ if (!(xw.dpy = XOpenDisplay(NULL)))
+ die("can't open display\n");
+ #endif // XRESOURCES_PATCH
xw.scr = XDefaultScreen(xw.dpy);
+ #if ALPHA_PATCH
if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0)))) {
parent = XRootWindow(xw.dpy, xw.scr);
xw.depth = 32;
@@ -1236,6 +1477,9 @@ xinit(int cols, int rows)
XMatchVisualInfo(xw.dpy, xw.scr, xw.depth, TrueColor, &vis);
xw.vis = vis.visual;
+ #else
+ xw.vis = XDefaultVisual(xw.dpy, xw.scr);
+ #endif // ALPHA_PATCH
/* font */
if (!FcInit())
@@ -1244,16 +1488,45 @@ xinit(int cols, int rows)
usedfont = (opt_font == NULL)? font : opt_font;
xloadfonts(usedfont, 0);
+ #if FONT2_PATCH
/* spare fonts */
xloadsparefonts();
+ #endif // FONT2_PATCH
/* colors */
+ #if ALPHA_PATCH
xw.cmap = XCreateColormap(xw.dpy, parent, xw.vis, None);
+ #else
+ xw.cmap = XDefaultColormap(xw.dpy, xw.scr);
+ #endif // ALPHA_PATCH
xloadcols();
/* adjust fixed window geometry */
+ #if ANYGEOMETRY_PATCH
+ switch (geometry) {
+ case CellGeometry:
+ #if ANYSIZE_PATCH
+ win.w = 2 * win.hborderpx + cols * win.cw;
+ win.h = 2 * win.vborderpx + rows * win.ch;
+ #else
+ win.w = 2 * borderpx + cols * win.cw;
+ win.h = 2 * borderpx + rows * win.ch;
+ #endif // ANYGEOMETRY_PATCH | ANYSIZE_PATCH
+ break;
+ case PixelGeometry:
+ win.w = cols;
+ win.h = rows;
+ cols = (win.w - 2 * borderpx) / win.cw;
+ rows = (win.h - 2 * borderpx) / win.ch;
+ break;
+ }
+ #elif ANYSIZE_PATCH
win.w = 2 * win.hborderpx + cols * win.cw;
win.h = 2 * win.vborderpx + rows * win.ch;
+ #else
+ win.w = 2 * borderpx + cols * win.cw;
+ win.h = 2 * borderpx + rows * win.ch;
+ #endif // ANYGEOMETRY_PATCH | ANYSIZE_PATCH
if (xw.gm & XNegative)
xw.l += DisplayWidth(xw.dpy, xw.scr) - win.w - 2;
if (xw.gm & YNegative)
@@ -1265,34 +1538,90 @@ xinit(int cols, int rows)
xw.attrs.bit_gravity = NorthWestGravity;
xw.attrs.event_mask = FocusChangeMask | KeyPressMask | KeyReleaseMask
| ExposureMask | VisibilityChangeMask | StructureNotifyMask
- | ButtonMotionMask | ButtonPressMask | ButtonReleaseMask;
+ | ButtonMotionMask | ButtonPressMask | ButtonReleaseMask
+ #if ST_EMBEDDER_PATCH
+ | SubstructureNotifyMask | SubstructureRedirectMask
+ #endif // ST_EMBEDDER_PATCH
+ ;
xw.attrs.colormap = xw.cmap;
-
- xw.win = XCreateWindow(xw.dpy, parent, xw.l, xw.t,
+ #if OPENURLONCLICK_PATCH
+ xw.attrs.event_mask |= PointerMotionMask;
+ #endif // OPENURLONCLICK_PATCH
+
+ root = XRootWindow(xw.dpy, xw.scr);
+ #if !ALPHA_PATCH
+ if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0))))
+ parent = root;
+ #endif // ALPHA_PATCH
+ xw.win = XCreateWindow(xw.dpy, root, xw.l, xw.t,
+ #if ALPHA_PATCH
win.w, win.h, 0, xw.depth, InputOutput,
+ #else
+ win.w, win.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput,
+ #endif // ALPHA_PATCH
xw.vis, CWBackPixel | CWBorderPixel | CWBitGravity
| CWEventMask | CWColormap, &xw.attrs);
+ if (parent != root)
+ XReparentWindow(xw.dpy, xw.win, parent, xw.l, xw.t);
memset(&gcvalues, 0, sizeof(gcvalues));
gcvalues.graphics_exposures = False;
+
+ #if ALPHA_PATCH
+ #if SINGLE_DRAWABLE_BUFFER_PATCH
+ xw.buf = xw.win;
+ #else
xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, xw.depth);
+ #endif // SINGLE_DRAWABLE_BUFFER_PATCH
dc.gc = XCreateGC(xw.dpy, xw.buf, GCGraphicsExposures, &gcvalues);
+ #else
+ dc.gc = XCreateGC(xw.dpy, xw.win, GCGraphicsExposures,
+ &gcvalues);
+ #if SINGLE_DRAWABLE_BUFFER_PATCH
+ xw.buf = xw.win;
+ #else
+ xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
+ DefaultDepth(xw.dpy, xw.scr));
+ #endif // SINGLE_DRAWABLE_BUFFER_PATCH
+ #endif // ALPHA_PATCH
XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel);
XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h);
/* font spec buffer */
+ #if LIGATURES_PATCH
+ xw.specbuf = xmalloc(cols * sizeof(GlyphFontSpec) * 4);
+ xw.specseq = xmalloc(cols * sizeof(GlyphFontSeq));
+ #else
xw.specbuf = xmalloc(cols * sizeof(GlyphFontSpec));
+ #endif // LIGATURES_PATCH
/* Xft rendering context */
xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
/* input methods */
- ximopen(xw.dpy);
+ if (!ximopen(xw.dpy)) {
+ XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL,
+ ximinstantiate, NULL);
+ }
/* white cursor, black outline */
+ #if HIDECURSOR_PATCH
+ xw.pointerisvisible = 1;
+ #if THEMED_CURSOR_PATCH
+ xw.vpointer = XcursorLibraryLoadCursor(xw.dpy, mouseshape);
+ #else
+ xw.vpointer = XCreateFontCursor(xw.dpy, mouseshape);
+ #endif // THEMED_CURSOR_PATCH
+ XDefineCursor(xw.dpy, xw.win, xw.vpointer);
+ #elif THEMED_CURSOR_PATCH
+ cursor = XcursorLibraryLoadCursor(xw.dpy, mouseshape);
+ XDefineCursor(xw.dpy, xw.win, cursor);
+ #else
cursor = XCreateFontCursor(xw.dpy, mouseshape);
XDefineCursor(xw.dpy, xw.win, cursor);
+ #endif // HIDECURSOR_PATCH
+ #if !THEMED_CURSOR_PATCH
if (XParseColor(xw.dpy, xw.cmap, colorname[mousefg], &xmousefg) == 0) {
xmousefg.red = 0xffff;
xmousefg.green = 0xffff;
@@ -1304,57 +1633,79 @@ xinit(int cols, int rows)
xmousebg.green = 0x0000;
xmousebg.blue = 0x0000;
}
-
+ #endif // THEMED_CURSOR_PATCH
+
+ #if HIDECURSOR_PATCH
+ #if !THEMED_CURSOR_PATCH
+ XRecolorCursor(xw.dpy, xw.vpointer, &xmousefg, &xmousebg);
+ #endif // THEMED_CURSOR_PATCH
+ blankpm = XCreateBitmapFromData(xw.dpy, xw.win, &(char){0}, 1, 1);
+ xw.bpointer = XCreatePixmapCursor(xw.dpy, blankpm, blankpm,
+ &xmousefg, &xmousebg, 0, 0);
+ #elif !THEMED_CURSOR_PATCH
XRecolorCursor(xw.dpy, cursor, &xmousefg, &xmousebg);
+ #endif // HIDECURSOR_PATCH
+
+ #if OPENURLONCLICK_PATCH
+ xw.upointer = XCreateFontCursor(xw.dpy, XC_hand2);
+ #if !HIDECURSOR_PATCH
+ xw.vpointer = cursor;
+ xw.pointerisvisible = 1;
+ #endif // HIDECURSOR_PATCH
+ #endif // OPENURLONCLICK_PATCH
xw.xembed = XInternAtom(xw.dpy, "_XEMBED", False);
xw.wmdeletewin = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False);
xw.netwmname = XInternAtom(xw.dpy, "_NET_WM_NAME", False);
- xw.netwmiconname = XInternAtom(xw.dpy, "_NET_WM_ICON_NAME", False);
+ xw.netwmiconname = XInternAtom(xw.dpy, "_NET_WM_ICON_NAME", False);
XSetWMProtocols(xw.dpy, xw.win, &xw.wmdeletewin, 1);
- /* use a png-image to set _NET_WM_ICON */
- FILE* file = fopen(ICON, "r");
- if (file) {
- /* inititialize variables */
- const gdImagePtr icon_rgba = gdImageCreateFromPng(file);
- fclose(file);
- const int width = gdImageSX(icon_rgba);
- const int height = gdImageSY(icon_rgba);
- const int icon_n = width * height + 2;
- CARD32 *icon_argb = g_new0(CARD32, icon_n);
- /* set width and height of the icon */
- int i = 0;
- icon_argb[i++] = width;
- icon_argb[i++] = height;
- /* RGBA -> ARGB */
- for (int y = 0; y < height; y++) {
- for (int x = 0; x < width; x++) {
- const int pixel_rgba = gdImageGetPixel(icon_rgba, x, y);
- guint8* pixel_argb = (guint8*) &icon_argb[i++];
- pixel_argb[0] = gdImageBlue(icon_rgba, pixel_rgba);
- pixel_argb[1] = gdImageGreen(icon_rgba, pixel_rgba);
- pixel_argb[2] = gdImageRed(icon_rgba, pixel_rgba);
- /* scale alpha from 0-127 to 0-255 */
- const int alpha = 127 - gdImageAlpha(icon_rgba, pixel_rgba);
- pixel_argb[3] = alpha == 127 ? 255 : alpha * 2;
- }
- }
- gdImageDestroy(icon_rgba);
- /* set _NET_WM_ICON */
- xw.netwmicon = XInternAtom(xw.dpy, "_NET_WM_ICON", False);
- XChangeProperty(xw.dpy, xw.win, xw.netwmicon, XA_CARDINAL, 32,
- PropModeReplace, (uchar *)icon_argb, icon_n);
- }
+ #if NETWMICON_PATCH || NETWMICON_FF_PATCH || NETWMICON_LEGACY_PATCH
+ setnetwmicon();
+ #endif // NETWMICON_PATCH
+
+ #if NO_WINDOW_DECORATIONS_PATCH
+ Atom motifwmhints = XInternAtom(xw.dpy, "_MOTIF_WM_HINTS", False);
+ unsigned int data[] = { 0x2, 0x0, 0x0, 0x0, 0x0 };
+ XChangeProperty(xw.dpy, xw.win, motifwmhints, motifwmhints, 16,
+ PropModeReplace, (unsigned char *)data, 5);
+ #endif // NO_WINDOW_DECORATIONS_PATCH
xw.netwmpid = XInternAtom(xw.dpy, "_NET_WM_PID", False);
XChangeProperty(xw.dpy, xw.win, xw.netwmpid, XA_CARDINAL, 32,
PropModeReplace, (uchar *)&thispid, 1);
+ #if FULLSCREEN_PATCH
+ xw.netwmstate = XInternAtom(xw.dpy, "_NET_WM_STATE", False);
+ xw.netwmfullscreen = XInternAtom(xw.dpy, "_NET_WM_STATE_FULLSCREEN", False);
+ #endif // FULLSCREEN_PATCH
+
+ #if DRAG_AND_DROP_PATCH
+ /* Xdnd setup */
+ xw.XdndTypeList = XInternAtom(xw.dpy, "XdndTypeList", 0);
+ xw.XdndSelection = XInternAtom(xw.dpy, "XdndSelection", 0);
+ xw.XdndEnter = XInternAtom(xw.dpy, "XdndEnter", 0);
+ xw.XdndPosition = XInternAtom(xw.dpy, "XdndPosition", 0);
+ xw.XdndStatus = XInternAtom(xw.dpy, "XdndStatus", 0);
+ xw.XdndLeave = XInternAtom(xw.dpy, "XdndLeave", 0);
+ xw.XdndDrop = XInternAtom(xw.dpy, "XdndDrop", 0);
+ xw.XdndFinished = XInternAtom(xw.dpy, "XdndFinished", 0);
+ xw.XdndActionCopy = XInternAtom(xw.dpy, "XdndActionCopy", 0);
+ xw.XdndActionMove = XInternAtom(xw.dpy, "XdndActionMove", 0);
+ xw.XdndActionLink = XInternAtom(xw.dpy, "XdndActionLink", 0);
+ xw.XdndActionAsk = XInternAtom(xw.dpy, "XdndActionAsk", 0);
+ xw.XdndActionPrivate = XInternAtom(xw.dpy, "XdndActionPrivate", 0);
+ xw.XtextUriList = XInternAtom((Display*) xw.dpy, "text/uri-list", 0);
+ xw.XtextPlain = XInternAtom((Display*) xw.dpy, "text/plain", 0);
+ xw.XdndAware = XInternAtom(xw.dpy, "XdndAware", 0);
+ XChangeProperty(xw.dpy, xw.win, xw.XdndAware, 4, 32, PropModeReplace,
+ &XdndVersion, 1);
+ #endif // DRAG_AND_DROP_PATCH
+
win.mode = MODE_NUMLOCK;
resettitle();
- XMapWindow(xw.dpy, xw.win);
xhints();
+ XMapWindow(xw.dpy, xw.win);
XSync(xw.dpy, False);
clock_gettime(CLOCK_MONOTONIC, &xsel.tclick1);
@@ -1365,17 +1716,41 @@ xinit(int cols, int rows)
if (xsel.xtarget == None)
xsel.xtarget = XA_STRING;
+ #if BOXDRAW_PATCH
boxdraw_xinit(xw.dpy, xw.cmap, xw.draw, xw.vis);
+ #endif // BOXDRAW_PATCH
+}
+
+#if LIGATURES_PATCH
+void
+xresetfontsettings(uint32_t mode, Font **font, int *frcflags)
+{
+ *font = &dc.font;
+ if ((mode & ATTR_ITALIC) && (mode & ATTR_BOLD)) {
+ *font = &dc.ibfont;
+ *frcflags = FRC_ITALICBOLD;
+ } else if (mode & ATTR_ITALIC) {
+ *font = &dc.ifont;
+ *frcflags = FRC_ITALIC;
+ } else if (mode & ATTR_BOLD) {
+ *font = &dc.bfont;
+ *frcflags = FRC_BOLD;
+ }
}
+#endif // LIGATURES_PATCH
int
xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y)
{
+ #if ANYSIZE_PATCH
+ float winx = win.hborderpx + x * win.cw, winy = win.vborderpx + y * win.ch, xp, yp;
+ #else
float winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, xp, yp;
+ #endif // ANYSIZE_PATCH
ushort mode, prevmode = USHRT_MAX;
Font *font = &dc.font;
int frcflags = FRC_NORMAL;
- float runewidth = win.cw;
+ float runewidth = win.cw * ((glyphs[0].mode & ATTR_WIDE) ? 2.0f : 1.0f);
Rune rune;
FT_UInt glyphidx;
FcResult fcres;
@@ -1383,14 +1758,140 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
FcFontSet *fcsets[] = { NULL };
FcCharSet *fccharset;
int i, f, numspecs = 0;
-
- for (i = 0, xp = winx, yp = winy + font->ascent + win.cyo; i < len; ++i) {
+ #if LIGATURES_PATCH
+ float cluster_xp, cluster_yp;
+ HbTransformData shaped;
+
+ /* Initial values. */
+ xresetfontsettings(glyphs[0].mode, &font, &frcflags);
+ #if VERTCENTER_PATCH
+ xp = winx, yp = winy + font->ascent + win.cyo;
+ #else
+ xp = winx, yp = winy + font->ascent;
+ #endif // VERTCENTER_PATCH
+ cluster_xp = xp; cluster_yp = yp;
+ /* Shape the segment. */
+ hbtransform(&shaped, font->match, glyphs, 0, len);
+ #endif // LIGATURES_PATCH
+
+ #if LIGATURES_PATCH
+ for (int code_idx = 0; code_idx < shaped.count; code_idx++)
+ #elif VERTCENTER_PATCH
+ for (i = 0, xp = winx, yp = winy + font->ascent + win.cyo; i < len; ++i)
+ #else
+ for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i)
+ #endif // LIGATURES_PATCH | VERTCENTER_PATCH
+ {
/* Fetch rune and mode for current glyph. */
+ #if LIGATURES_PATCH
+ int idx = shaped.glyphs[code_idx].cluster;
+ #else
rune = glyphs[i].u;
mode = glyphs[i].mode;
+ #endif // LIGATURES_PATCH
/* Skip dummy wide-character spacing. */
- if (mode & ATTR_WDUMMY)
+ #if LIGATURES_PATCH
+ if (glyphs[idx].mode & ATTR_WDUMMY)
+ continue;
+
+ /* Advance the drawing cursor if we've moved to a new cluster */
+ if (code_idx > 0 && idx != shaped.glyphs[code_idx - 1].cluster) {
+ xp += runewidth;
+ cluster_xp = xp;
+ cluster_yp = yp;
+ }
+
+ #if BOXDRAW_PATCH
+ if (glyphs[idx].mode & ATTR_BOXDRAW) {
+ /* minor shoehorning: boxdraw uses only this ushort */
+ specs[numspecs].font = font->match;
+ specs[numspecs].glyph = boxdrawindex(&glyphs[idx]);
+ specs[numspecs].x = xp;
+ specs[numspecs].y = yp;
+ numspecs++;
+ } else if (shaped.glyphs[code_idx].codepoint != 0) {
+ #else
+ if (shaped.glyphs[code_idx].codepoint != 0) {
+ #endif // BOXDRAW_PATCH
+ /* If symbol is found, put it into the specs. */
+ specs[numspecs].font = font->match;
+ specs[numspecs].glyph = shaped.glyphs[code_idx].codepoint;
+ specs[numspecs].x = cluster_xp + (short)(shaped.positions[code_idx].x_offset / 64.);
+ specs[numspecs].y = cluster_yp - (short)(shaped.positions[code_idx].y_offset / 64.);
+ cluster_xp += shaped.positions[code_idx].x_advance / 64.;
+ cluster_yp += shaped.positions[code_idx].y_advance / 64.;
+ numspecs++;
+ } else {
+ /* If it's not found, try to fetch it through the font cache. */
+ rune = glyphs[idx].u;
+ for (f = 0; f < frclen; f++) {
+ glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune);
+ /* Everything correct. */
+ if (glyphidx && frc[f].flags == frcflags)
+ break;
+ /* We got a default font for a not found glyph. */
+ if (!glyphidx && frc[f].flags == frcflags
+ && frc[f].unicodep == rune) {
+ break;
+ }
+ }
+
+ /* Nothing was found. Use fontconfig to find matching font. */
+ if (f >= frclen) {
+ if (!font->set)
+ font->set = FcFontSort(0, font->pattern, 1, 0, &fcres);
+ fcsets[0] = font->set;
+
+ /*
+ * Nothing was found in the cache. Now use
+ * some dozen of Fontconfig calls to get the
+ * font for one single character.
+ *
+ * Xft and fontconfig are design failures.
+ */
+ fcpattern = FcPatternDuplicate(font->pattern);
+ fccharset = FcCharSetCreate();
+
+ FcCharSetAddChar(fccharset, rune);
+ FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
+ FcPatternAddBool(fcpattern, FC_SCALABLE, 1);
+
+ FcConfigSubstitute(0, fcpattern, FcMatchPattern);
+ FcDefaultSubstitute(fcpattern);
+
+ fontpattern = FcFontSetMatch(0, fcsets, 1, fcpattern, &fcres);
+
+ /* Allocate memory for the new cache entry. */
+ if (frclen >= frccap) {
+ frccap += 16;
+ frc = xrealloc(frc, frccap * sizeof(Fontcache));
+ }
+
+ frc[frclen].font = XftFontOpenPattern(xw.dpy, fontpattern);
+ if (!frc[frclen].font)
+ die("XftFontOpenPattern failed seeking fallback font: %s\n",
+ strerror(errno));
+ frc[frclen].flags = frcflags;
+ frc[frclen].unicodep = rune;
+
+ glyphidx = XftCharIndex(xw.dpy, frc[frclen].font, rune);
+
+ f = frclen;
+ frclen++;
+
+ FcPatternDestroy(fcpattern);
+ FcCharSetDestroy(fccharset);
+ }
+
+ specs[numspecs].font = frc[f].font;
+ specs[numspecs].glyph = glyphidx;
+ specs[numspecs].x = (short)xp;
+ specs[numspecs].y = (short)yp;
+ numspecs++;
+ }
+ #else // !LIGATURES_PATCH
+ if (mode == ATTR_WDUMMY)
continue;
/* Determine font for glyph if different from previous glyph. */
@@ -1409,9 +1910,14 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
font = &dc.bfont;
frcflags = FRC_BOLD;
}
+ #if VERTCENTER_PATCH
yp = winy + font->ascent + win.cyo;
+ #else
+ yp = winy + font->ascent;
+ #endif // VERTCENTER_PATCH
}
+ #if BOXDRAW_PATCH
if (mode & ATTR_BOXDRAW) {
/* minor shoehorning: boxdraw uses only this ushort */
glyphidx = boxdrawindex(&glyphs[i]);
@@ -1419,6 +1925,10 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
/* Lookup character index with default font. */
glyphidx = XftCharIndex(xw.dpy, font->match, rune);
}
+ #else
+ /* Lookup character index with default font. */
+ glyphidx = XftCharIndex(xw.dpy, font->match, rune);
+ #endif // BOXDRAW_PATCH
if (glyphidx) {
specs[numspecs].font = font->match;
specs[numspecs].glyph = glyphidx;
@@ -1445,8 +1955,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
/* Nothing was found. Use fontconfig to find matching font. */
if (f >= frclen) {
if (!font->set)
- font->set = FcFontSort(0, font->pattern,
- 1, 0, &fcres);
+ font->set = FcFontSort(0, font->pattern, 1, 0, &fcres);
fcsets[0] = font->set;
/*
@@ -1460,16 +1969,15 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
fccharset = FcCharSetCreate();
FcCharSetAddChar(fccharset, rune);
- FcPatternAddCharSet(fcpattern, FC_CHARSET,
- fccharset);
+ FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
FcPatternAddBool(fcpattern, FC_SCALABLE, 1);
- FcConfigSubstitute(0, fcpattern,
- FcMatchPattern);
+ #if !USE_XFTFONTMATCH_PATCH
+ FcConfigSubstitute(0, fcpattern, FcMatchPattern);
FcDefaultSubstitute(fcpattern);
+ #endif // USE_XFTFONTMATCH_PATCH
- fontpattern = FcFontSetMatch(0, fcsets, 1,
- fcpattern, &fcres);
+ fontpattern = FcFontSetMatch(0, fcsets, 1, fcpattern, &fcres);
/* Allocate memory for the new cache entry. */
if (frclen >= frccap) {
@@ -1477,8 +1985,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
frc = xrealloc(frc, frccap * sizeof(Fontcache));
}
- frc[frclen].font = XftFontOpenPattern(xw.dpy,
- fontpattern);
+ frc[frclen].font = XftFontOpenPattern(xw.dpy, fontpattern);
if (!frc[frclen].font)
die("XftFontOpenPattern failed seeking fallback font: %s\n",
strerror(errno));
@@ -1500,22 +2007,82 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
specs[numspecs].y = (short)yp;
xp += runewidth;
numspecs++;
+ #endif // LIGATURES_PATCH
}
- /* Harfbuzz transformation for ligatures. */
- hbtransform(specs, glyphs, len, x, y);
-
return numspecs;
}
-void
-xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y, int dmode)
+#if UNDERCURL_PATCH
+static int isSlopeRising (int x, int iPoint, int waveWidth)
+{
+ // . . . .
+ // / \ / \ / \ / \
+ // / \ / \ / \ / \
+ // . . . . .
+
+ // Find absolute `x` of point
+ x += iPoint * (waveWidth/2);
+
+ // Find index of absolute wave
+ int absSlope = x / ((float)waveWidth/2);
+
+ return (absSlope % 2);
+}
+
+static int getSlope (int x, int iPoint, int waveWidth)
{
+ // Sizes: Caps are half width of slopes
+ // 1_2 1_2 1_2 1_2
+ // / \ / \ / \ / \
+ // / \ / \ / \ / \
+ // 0 3_0 3_0 3_0 3_
+ // <2-> <1> <---6---->
+
+ // Find type of first point
+ int firstType;
+ x -= (x / waveWidth) * waveWidth;
+ if (x < (waveWidth * (2.f/6.f)))
+ firstType = UNDERCURL_SLOPE_ASCENDING;
+ else if (x < (waveWidth * (3.f/6.f)))
+ firstType = UNDERCURL_SLOPE_TOP_CAP;
+ else if (x < (waveWidth * (5.f/6.f)))
+ firstType = UNDERCURL_SLOPE_DESCENDING;
+ else
+ firstType = UNDERCURL_SLOPE_BOTTOM_CAP;
+
+ // Find type of given point
+ int pointType = (iPoint % 4);
+ pointType += firstType;
+ pointType %= 4;
+
+ return pointType;
+}
+#endif // UNDERCURL_PATCH
+
+void
+xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y
+ #if WIDE_GLYPHS_PATCH
+ ,int dmode
+ #endif // WIDE_GLYPHS_PATCH
+ #if LIGATURES_PATCH
+ , int charlen
+ #endif // LIGATURES_PATCH
+) {
+ #if LIGATURES_PATCH
+ int width = charlen * win.cw;
+ #else
int charlen = len * ((base.mode & ATTR_WIDE) ? 2 : 1);
- int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch,
- width = charlen * win.cw;
+ int width = charlen * win.cw;
+ #endif // WIDE_GLYPHS_PATCH
+ #if ANYSIZE_PATCH
+ int winx = win.hborderpx + x * win.cw, winy = win.vborderpx + y * win.ch;
+ #else
+ int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch;
+ #endif // ANYSIZE_PATCH
Color *fg, *bg, *temp, revfg, revbg, truefg, truebg;
XRenderColor colfg, colbg;
+ XRectangle r;
/* Fallback on color display for attributes not supported by the font */
if (base.mode & ATTR_ITALIC && base.mode & ATTR_BOLD) {
@@ -1548,6 +2115,12 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
bg = &dc.col[base.bg];
}
+ #if !BOLD_IS_NOT_BRIGHT_PATCH
+ /* Change basic system colors [0-7] to bright system colors [8-15] */
+ if ((base.mode & ATTR_BOLD_FAINT) == ATTR_BOLD && BETWEEN(base.fg, 0, 7))
+ fg = &dc.col[base.fg + 8];
+ #endif // BOLD_IS_NOT_BRIGHT_PATCH
+
if (IS_SET(MODE_REVERSE)) {
if (fg == &dc.col[defaultfg]) {
fg = &dc.col[defaultbg];
@@ -1584,91 +2157,616 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
}
if (base.mode & ATTR_REVERSE) {
+ #if SPOILER_PATCH
+ if (bg == fg) {
+ bg = &dc.col[defaultfg];
+ fg = &dc.col[defaultbg];
+ } else {
+ temp = fg;
+ fg = bg;
+ bg = temp;
+ }
+ #else
temp = fg;
fg = bg;
bg = temp;
+ #endif // SPOILER_PATCH
}
+ #if SELECTION_COLORS_PATCH
+ if (base.mode & ATTR_SELECTED) {
+ bg = &dc.col[selectionbg];
+ if (!ignoreselfg)
+ fg = &dc.col[selectionfg];
+ }
+ #endif // SELECTION_COLORS_PATCH
+
if (base.mode & ATTR_BLINK && win.mode & MODE_BLINK)
fg = bg;
if (base.mode & ATTR_INVISIBLE)
fg = bg;
+ #if INVERT_PATCH
+ if (invertcolors) {
+ revfg = invertedcolor(fg);
+ revbg = invertedcolor(bg);
+ fg = &revfg;
+ bg = &revbg;
+ }
+ #endif // INVERT_PATCH
+
+ #if KEYBOARDSELECT_PATCH && REFLOW_PATCH
+ if (base.mode & ATTR_HIGHLIGHT) {
+ fg = &dc.col[(base.mode & ATTR_REVERSE) ? highlightbg : highlightfg];
+ bg = &dc.col[(base.mode & ATTR_REVERSE) ? highlightfg : highlightbg];
+ }
+ #endif // KEYBOARDSELECT_PATCH
+
+ #if ALPHA_PATCH && ALPHA_GRADIENT_PATCH
+ // gradient
+ bg->color.alpha = grad_alpha * 0xffff * (win.h - y*win.ch) / win.h + stat_alpha * 0xffff;
+ // uncomment to invert the gradient
+ // bg->color.alpha = grad_alpha * 0xffff * (y*win.ch) / win.h + stat_alpha * 0xffff;
+ #endif // ALPHA_PATCH | ALPHA_GRADIENT_PATCH
+
+ #if WIDE_GLYPHS_PATCH
if (dmode & DRAW_BG) {
- /* Intelligent cleaning up of the borders. */
- if (x == 0) {
- xclear(0, (y == 0)? 0 : winy, borderpx,
- winy + win.ch +
- ((winy + win.ch >= borderpx + win.th)? win.h : 0));
- }
- if (winx + width >= borderpx + win.tw) {
- xclear(winx + width, (y == 0)? 0 : winy, win.w,
- ((winy + win.ch >= borderpx + win.th)? win.h : (winy + win.ch)));
- }
- if (y == 0)
- xclear(winx, 0, winx + width, borderpx);
- if (winy + win.ch >= borderpx + win.th)
- xclear(winx, winy + win.ch, winx + width, win.h);
+ #endif // WIDE_GLYPHS_PATCH
+ /* Intelligent cleaning up of the borders. */
+ #if ANYSIZE_PATCH
+ if (x == 0) {
+ xclear(0, (y == 0)? 0 : winy, win.hborderpx,
+ winy + win.ch +
+ ((winy + win.ch >= win.vborderpx + win.th)? win.h : 0));
+ }
+ if (winx + width >= win.hborderpx + win.tw) {
+ xclear(winx + width, (y == 0)? 0 : winy, win.w,
+ ((winy + win.ch >= win.vborderpx + win.th)? win.h : (winy + win.ch)));
+ }
+ if (y == 0)
+ xclear(winx, 0, winx + width, win.vborderpx);
+ if (winy + win.ch >= win.vborderpx + win.th)
+ xclear(winx, winy + win.ch, winx + width, win.h);
+ #else
+ if (x == 0) {
+ xclear(0, (y == 0)? 0 : winy, borderpx,
+ winy + win.ch +
+ ((winy + win.ch >= borderpx + win.th)? win.h : 0));
+ }
+ if (winx + width >= borderpx + win.tw) {
+ xclear(winx + width, (y == 0)? 0 : winy, win.w,
+ ((winy + win.ch >= borderpx + win.th)? win.h : (winy + win.ch)));
+ }
+ if (y == 0)
+ xclear(winx, 0, winx + width, borderpx);
+ if (winy + win.ch >= borderpx + win.th)
+ xclear(winx, winy + win.ch, winx + width, win.h);
+ #endif // ANYSIZE_PATCH
+
+ /* Clean up the region we want to draw to. */
+ #if BACKGROUND_IMAGE_PATCH
+ if (bg == &dc.col[defaultbg])
+ xclear(winx, winy, winx + width, winy + win.ch);
+ else
+ #endif // BACKGROUND_IMAGE_PATCH
- /* Fill the background */
- XftDrawRect(xw.draw, bg, winx, winy, width, win.ch);
+ /* Fill the background */
+ XftDrawRect(xw.draw, bg, winx, winy, width, win.ch);
+ #if WIDE_GLYPHS_PATCH
}
+ #endif // WIDE_GLYPHS_PATCH
+ #if WIDE_GLYPHS_PATCH
if (dmode & DRAW_FG) {
- if (base.mode & ATTR_BOXDRAW) {
- drawboxes(winx, winy, width / len, win.ch, fg, bg, specs, len);
+ #endif // WIDE_GLYPHS_PATCH
+ #if BOXDRAW_PATCH
+ if (base.mode & ATTR_BOXDRAW) {
+ drawboxes(winx, winy, width / len, win.ch, fg, bg, specs, len);
+ } else {
+ #endif // BOXDRAW_PATCH
+ /* Set the clip region because Xft is sometimes dirty. */
+ #if WIDE_GLYPHS_PATCH
+ r.x = 0;
+ r.y = 0;
+ r.height = win.ch;
+ r.width = win.w;
+ XftDrawSetClipRectangles(xw.draw, 0, winy, &r, 1);
+ #else
+ r.x = 0;
+ r.y = 0;
+ r.height = win.ch;
+ r.width = width;
+ XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1);
+ #endif // WIDE_GLYPHS_PATCH
+
+ /* Render the glyphs. */
+ XftDrawGlyphFontSpec(xw.draw, fg, specs, len);
+
+ #if BOXDRAW_PATCH
+ }
+ #endif // BOXDRAW_PATCH
+
+ /* Render underline and strikethrough. */
+ if (base.mode & ATTR_UNDERLINE) {
+ #if UNDERCURL_PATCH
+ // Underline Color
+ const int widthThreshold = 28; // +1 width every widthThreshold px of font
+ int wlw = (win.ch / widthThreshold) + 1; // Wave Line Width
+ int linecolor;
+ if ((base.ucolor[0] >= 0) &&
+ !(base.mode & ATTR_BLINK && win.mode & MODE_BLINK) &&
+ !(base.mode & ATTR_INVISIBLE)
+ ) {
+ // Special color for underline
+ // Index
+ if (base.ucolor[1] < 0) {
+ linecolor = dc.col[base.ucolor[0]].pixel;
+ }
+ // RGB
+ else {
+ XColor lcolor;
+ lcolor.red = base.ucolor[0] * 257;
+ lcolor.green = base.ucolor[1] * 257;
+ lcolor.blue = base.ucolor[2] * 257;
+ lcolor.flags = DoRed | DoGreen | DoBlue;
+ XAllocColor(xw.dpy, xw.cmap, &lcolor);
+ linecolor = lcolor.pixel;
+ }
} else {
- /* Render the glyphs. */
- XftDrawGlyphFontSpec(xw.draw, fg, specs, len);
+ // Foreground color for underline
+ linecolor = fg->pixel;
}
- /* Render underline and strikethrough. */
- if (base.mode & ATTR_UNDERLINE) {
- XftDrawRect(xw.draw, fg, winx, winy + win.cyo + dc.font.ascent + 1,
- width, 1);
+ XGCValues ugcv = {
+ .foreground = linecolor,
+ .line_width = wlw,
+ .line_style = LineSolid,
+ .cap_style = CapNotLast
+ };
+
+ GC ugc = XCreateGC(xw.dpy, XftDrawDrawable(xw.draw),
+ GCForeground | GCLineWidth | GCLineStyle | GCCapStyle,
+ &ugcv);
+
+ // Underline Style
+ if (base.ustyle != 3) {
+ XFillRectangle(xw.dpy, XftDrawDrawable(xw.draw), ugc, winx,
+ winy + dc.font.ascent * chscale + 1, width, wlw);
+ } else if (base.ustyle == 3) {
+ int ww = win.cw;//width;
+ int wh = dc.font.descent - wlw/2 - 1;//r.height/7;
+ int wx = winx;
+ int wy = winy + win.ch - dc.font.descent;
+ #if VERTCENTER_PATCH
+ wy -= win.cyo;
+ #endif // VERTCENTER_PATCH
+
+#if UNDERCURL_STYLE == UNDERCURL_CURLY
+ // Draw waves
+ int narcs = charlen * 2 + 1;
+ XArc *arcs = xmalloc(sizeof(XArc) * narcs);
+
+ int i = 0;
+ for (i = 0; i < charlen-1; i++) {
+ arcs[i*2] = (XArc) {
+ .x = wx + win.cw * i + ww / 4,
+ .y = wy,
+ .width = win.cw / 2,
+ .height = wh,
+ .angle1 = 0,
+ .angle2 = 180 * 64
+ };
+ arcs[i*2+1] = (XArc) {
+ .x = wx + win.cw * i + ww * 0.75,
+ .y = wy,
+ .width = win.cw/2,
+ .height = wh,
+ .angle1 = 180 * 64,
+ .angle2 = 180 * 64
+ };
+ }
+ // Last wave
+ arcs[i*2] = (XArc) {wx + ww * i + ww / 4, wy, ww / 2, wh,
+ 0, 180 * 64 };
+ // Last wave tail
+ arcs[i*2+1] = (XArc) {wx + ww * i + ww * 0.75, wy, ceil(ww / 2.),
+ wh, 180 * 64, 90 * 64};
+ // First wave tail
+ i++;
+ arcs[i*2] = (XArc) {wx - ww/4 - 1, wy, ceil(ww / 2.), wh, 270 * 64,
+ 90 * 64 };
+
+ XDrawArcs(xw.dpy, XftDrawDrawable(xw.draw), ugc, arcs, narcs);
+
+ free(arcs);
+#elif UNDERCURL_STYLE == UNDERCURL_SPIKY
+ // Make the underline corridor larger
+ /*
+ wy -= wh;
+ */
+ wh *= 2;
+
+ // Set the angle of the slope to 45°
+ ww = wh;
+
+ // Position of wave is independent of word, it's absolute
+ wx = (wx / (ww/2)) * (ww/2);
+
+ int marginStart = winx - wx;
+
+ // Calculate number of points with floating precision
+ float n = width; // Width of word in pixels
+ n = (n / ww) * 2; // Number of slopes (/ or \)
+ n += 2; // Add two last points
+ int npoints = n; // Convert to int
+
+ // Total length of underline
+ float waveLength = 0;
+
+ if (npoints >= 3) {
+ // We add an aditional slot in case we use a bonus point
+ XPoint *points = xmalloc(sizeof(XPoint) * (npoints + 1));
+
+ // First point (Starts with the word bounds)
+ points[0] = (XPoint) {
+ .x = wx + marginStart,
+ .y = (isSlopeRising(wx, 0, ww))
+ ? (wy - marginStart + ww/2.f)
+ : (wy + marginStart)
+ };
+
+ // Second point (Goes back to the absolute point coordinates)
+ points[1] = (XPoint) {
+ .x = (ww/2.f) - marginStart,
+ .y = (isSlopeRising(wx, 1, ww))
+ ? (ww/2.f - marginStart)
+ : (-ww/2.f + marginStart)
+ };
+ waveLength += (ww/2.f) - marginStart;
+
+ // The rest of the points
+ for (int i = 2; i < npoints-1; i++) {
+ points[i] = (XPoint) {
+ .x = ww/2,
+ .y = (isSlopeRising(wx, i, ww))
+ ? wh/2
+ : -wh/2
+ };
+ waveLength += ww/2;
+ }
+
+ // Last point
+ points[npoints-1] = (XPoint) {
+ .x = ww/2,
+ .y = (isSlopeRising(wx, npoints-1, ww))
+ ? wh/2
+ : -wh/2
+ };
+ waveLength += ww/2;
+
+ // End
+ if (waveLength < width) { // Add a bonus point?
+ int marginEnd = width - waveLength;
+ points[npoints] = (XPoint) {
+ .x = marginEnd,
+ .y = (isSlopeRising(wx, npoints, ww))
+ ? (marginEnd)
+ : (-marginEnd)
+ };
+
+ npoints++;
+ } else if (waveLength > width) { // Is last point too far?
+ int marginEnd = waveLength - width;
+ points[npoints-1].x -= marginEnd;
+ if (isSlopeRising(wx, npoints-1, ww))
+ points[npoints-1].y -= (marginEnd);
+ else
+ points[npoints-1].y += (marginEnd);
+ }
+
+ // Draw the lines
+ XDrawLines(xw.dpy, XftDrawDrawable(xw.draw), ugc, points, npoints,
+ CoordModePrevious);
+
+ // Draw a second underline with an offset of 1 pixel
+ if ( ((win.ch / (widthThreshold/2)) % 2)) {
+ points[0].x++;
+
+ XDrawLines(xw.dpy, XftDrawDrawable(xw.draw), ugc, points,
+ npoints, CoordModePrevious);
+ }
+
+ // Free resources
+ free(points);
+ }
+#else // UNDERCURL_CAPPED
+ // Cap is half of wave width
+ float capRatio = 0.5f;
+
+ // Make the underline corridor larger
+ wh *= 2;
+
+ // Set the angle of the slope to 45°
+ ww = wh;
+ ww *= 1 + capRatio; // Add a bit of width for the cap
+
+ // Position of wave is independent of word, it's absolute
+ wx = (wx / ww) * ww;
+
+ float marginStart;
+ switch(getSlope(winx, 0, ww)) {
+ case UNDERCURL_SLOPE_ASCENDING:
+ marginStart = winx - wx;
+ break;
+ case UNDERCURL_SLOPE_TOP_CAP:
+ marginStart = winx - (wx + (ww * (2.f/6.f)));
+ break;
+ case UNDERCURL_SLOPE_DESCENDING:
+ marginStart = winx - (wx + (ww * (3.f/6.f)));
+ break;
+ case UNDERCURL_SLOPE_BOTTOM_CAP:
+ marginStart = winx - (wx + (ww * (5.f/6.f)));
+ break;
+ }
+
+ // Calculate number of points with floating precision
+ float n = width; // Width of word in pixels
+ // ._.
+ n = (n / ww) * 4; // Number of points (./ \.)
+ n += 2; // Add two last points
+ int npoints = n; // Convert to int
+
+ // Position of the pen to draw the lines
+ float penX = 0;
+ float penY = 0;
+
+ if (npoints >= 3) {
+ XPoint *points = xmalloc(sizeof(XPoint) * (npoints + 1));
+
+ // First point (Starts with the word bounds)
+ penX = winx;
+ switch (getSlope(winx, 0, ww)) {
+ case UNDERCURL_SLOPE_ASCENDING:
+ penY = wy + wh/2.f - marginStart;
+ break;
+ case UNDERCURL_SLOPE_TOP_CAP:
+ penY = wy;
+ break;
+ case UNDERCURL_SLOPE_DESCENDING:
+ penY = wy + marginStart;
+ break;
+ case UNDERCURL_SLOPE_BOTTOM_CAP:
+ penY = wy + wh/2.f;
+ break;
+ }
+ points[0].x = penX;
+ points[0].y = penY;
+
+ // Second point (Goes back to the absolute point coordinates)
+ switch (getSlope(winx, 1, ww)) {
+ case UNDERCURL_SLOPE_ASCENDING:
+ penX += ww * (1.f/6.f) - marginStart;
+ penY += 0;
+ break;
+ case UNDERCURL_SLOPE_TOP_CAP:
+ penX += ww * (2.f/6.f) - marginStart;
+ penY += -wh/2.f + marginStart;
+ break;
+ case UNDERCURL_SLOPE_DESCENDING:
+ penX += ww * (1.f/6.f) - marginStart;
+ penY += 0;
+ break;
+ case UNDERCURL_SLOPE_BOTTOM_CAP:
+ penX += ww * (2.f/6.f) - marginStart;
+ penY += -marginStart + wh/2.f;
+ break;
+ }
+ points[1].x = penX;
+ points[1].y = penY;
+
+ // The rest of the points
+ for (int i = 2; i < npoints; i++) {
+ switch (getSlope(winx, i, ww)) {
+ case UNDERCURL_SLOPE_ASCENDING:
+ case UNDERCURL_SLOPE_DESCENDING:
+ penX += ww * (1.f/6.f);
+ penY += 0;
+ break;
+ case UNDERCURL_SLOPE_TOP_CAP:
+ penX += ww * (2.f/6.f);
+ penY += -wh / 2.f;
+ break;
+ case UNDERCURL_SLOPE_BOTTOM_CAP:
+ penX += ww * (2.f/6.f);
+ penY += wh / 2.f;
+ break;
+ }
+ points[i].x = penX;
+ points[i].y = penY;
+ }
+
+ // End
+ float waveLength = penX - winx;
+ if (waveLength < width) { // Add a bonus point?
+ int marginEnd = width - waveLength;
+ penX += marginEnd;
+ switch(getSlope(winx, npoints, ww)) {
+ case UNDERCURL_SLOPE_ASCENDING:
+ case UNDERCURL_SLOPE_DESCENDING:
+ //penY += 0;
+ break;
+ case UNDERCURL_SLOPE_TOP_CAP:
+ penY += -marginEnd;
+ break;
+ case UNDERCURL_SLOPE_BOTTOM_CAP:
+ penY += marginEnd;
+ break;
+ }
+
+ points[npoints].x = penX;
+ points[npoints].y = penY;
+
+ npoints++;
+ } else if (waveLength > width) { // Is last point too far?
+ int marginEnd = waveLength - width;
+ points[npoints-1].x -= marginEnd;
+ switch(getSlope(winx, npoints-1, ww)) {
+ case UNDERCURL_SLOPE_TOP_CAP:
+ points[npoints-1].y += marginEnd;
+ break;
+ case UNDERCURL_SLOPE_BOTTOM_CAP:
+ points[npoints-1].y -= marginEnd;
+ break;
+ default:
+ break;
+ }
+ }
+
+ // Draw the lines
+ XDrawLines(xw.dpy, XftDrawDrawable(xw.draw), ugc, points, npoints,
+ CoordModeOrigin);
+
+ // Draw a second underline with an offset of 1 pixel
+ if ( ((win.ch / (widthThreshold/2)) % 2)) {
+ for (int i = 0; i < npoints; i++)
+ points[i].x++;
+
+ XDrawLines(xw.dpy, XftDrawDrawable(xw.draw), ugc, points,
+ npoints, CoordModeOrigin);
+ }
+
+ // Free resources
+ free(points);
+ }
+#endif
}
- if (base.mode & ATTR_STRUCK) {
- XftDrawRect(xw.draw, fg, winx, winy + win.cyo + 2 * dc.font.ascent / 3,
- width, 1);
+ XFreeGC(xw.dpy, ugc);
+ #elif VERTCENTER_PATCH
+ XftDrawRect(xw.draw, fg, winx, winy + win.cyo + dc.font.ascent * chscale + 1,
+ width, 1);
+ #else
+ XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent * chscale + 1,
+ width, 1);
+ #endif // UNDERCURL_PATCH | VERTCENTER_PATCH
+ }
+
+ if (base.mode & ATTR_STRUCK) {
+ #if VERTCENTER_PATCH
+ XftDrawRect(xw.draw, fg, winx, winy + win.cyo + 2 * dc.font.ascent * chscale / 3,
+ width, 1);
+ #else
+ XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent * chscale / 3,
+ width, 1);
+ #endif // VERTCENTER_PATCH
+ }
+ #if WIDE_GLYPHS_PATCH
+ }
+ #endif // WIDE_GLYPHS_PATCH
+
+ #if OPENURLONCLICK_PATCH
+ /* underline url (openurlonclick patch) */
+ if (url_draw && y >= url_y1 && y <= url_y2) {
+ int x1 = (y == url_y1) ? url_x1 : 0;
+ int x2 = (y == url_y2) ? MIN(url_x2, term.col-1) : url_maxcol;
+ if (x + charlen > x1 && x <= x2) {
+ int xu = MAX(x, x1);
+ int wu = (x2 - xu + 1) * win.cw;
+ #if ANYSIZE_PATCH
+ xu = win.hborderpx + xu * win.cw;
+ #else
+ xu = borderpx + xu * win.cw;
+ #endif // ANYSIZE_PATCH
+ #if VERTCENTER_PATCH
+ XftDrawRect(xw.draw, fg, xu, winy + win.cyo + dc.font.ascent * chscale + 2, wu, 1);
+ #else
+ XftDrawRect(xw.draw, fg, xu, winy + dc.font.ascent * chscale + 2, wu, 1);
+ #endif // VERTCENTER_PATCH
+ url_draw = (y != url_y2 || x + charlen <= x2);
}
}
+ #endif // OPENURLONCLICK_PATCH
+
+ /* Reset clip to none. */
+ XftDrawSetClip(xw.draw, 0);
}
void
xdrawglyph(Glyph g, int x, int y)
{
int numspecs;
- XftGlyphFontSpec spec;
+ XftGlyphFontSpec *specs = xw.specbuf;
- numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y);
- xdrawglyphfontspecs(&spec, g, numspecs, x, y, DRAW_BG | DRAW_FG);
+ numspecs = xmakeglyphfontspecs(specs, &g, 1, x, y);
+ xdrawglyphfontspecs(specs, g, numspecs, x, y
+ #if WIDE_GLYPHS_PATCH
+ ,DRAW_BG | DRAW_FG
+ #endif // WIDE_GLYPHS_PATCH
+ #if LIGATURES_PATCH
+ ,(g.mode & ATTR_WIDE) ? 2 : 1
+ #endif // LIGATURES_PATCH
+ );
}
void
+#if LIGATURES_PATCH
xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og, Line line, int len)
+#else
+xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
+#endif // LIGATURES_PATCH
{
Color drawcol;
+ #if DYNAMIC_CURSOR_COLOR_PATCH
+ XRenderColor colbg;
+ #endif // DYNAMIC_CURSOR_COLOR_PATCH
- /* remove the old cursor */
- if (selected(ox, oy))
- og.mode ^= ATTR_REVERSE;
-
+ #if LIGATURES_PATCH
/* Redraw the line where cursor was previously.
* It will restore the ligatures broken by the cursor. */
xdrawline(line, 0, oy, len);
+ #else
+ /* Remove the old cursor */
+ if (selected(ox, oy))
+ #if SELECTION_COLORS_PATCH
+ og.mode |= ATTR_SELECTED;
+ #else
+ og.mode ^= ATTR_REVERSE;
+ #endif // SELECTION_COLORS_PATCH
- if (IS_SET(MODE_HIDE) || !IS_SET(MODE_FOCUSED)) return;
+ xdrawglyph(og, ox, oy);
+ #endif // LIGATURES_PATCH
+
+ #if HIDE_TERMINAL_CURSOR_PATCH
+ if (IS_SET(MODE_HIDE) || !IS_SET(MODE_FOCUSED))
+ return;
+ #else
+ if (IS_SET(MODE_HIDE))
+ return;
+ #endif // HIDE_TERMINAL_CURSOR_PATCH
/*
* Select the right color for the right mode.
*/
- g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE|ATTR_BOXDRAW;
+ g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE
+ #if BOXDRAW_PATCH
+ |ATTR_BOXDRAW
+ #endif // BOXDRAW_PATCH
+ #if DYNAMIC_CURSOR_COLOR_PATCH
+ |ATTR_REVERSE
+ #endif // DYNAMIC_CURSOR_COLOR_PATCH
+ #if KEYBOARDSELECT_PATCH && REFLOW_PATCH
+ |ATTR_HIGHLIGHT
+ #endif // KEYBOARDSELECT_PATCH
+ ;
if (IS_SET(MODE_REVERSE)) {
g.mode |= ATTR_REVERSE;
g.bg = defaultfg;
+ #if SELECTION_COLORS_PATCH
+ g.fg = defaultcs;
+ drawcol = dc.col[defaultrcs];
+ #else
if (selected(cx, cy)) {
drawcol = dc.col[defaultcs];
g.fg = defaultrcs;
@@ -1676,69 +2774,155 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og, Line line, int le
drawcol = dc.col[defaultrcs];
g.fg = defaultcs;
}
+ #endif // SELECTION_COLORS_PATCH
} else {
+ #if SELECTION_COLORS_PATCH && !DYNAMIC_CURSOR_COLOR_PATCH
+ g.fg = defaultbg;
+ g.bg = defaultcs;
+ drawcol = dc.col[defaultcs];
+ #else
if (selected(cx, cy)) {
+ #if KEYBOARDSELECT_PATCH && REFLOW_PATCH
+ g.mode &= ~(ATTR_REVERSE | ATTR_HIGHLIGHT);
+ #elif DYNAMIC_CURSOR_COLOR_PATCH
+ g.mode &= ~ATTR_REVERSE;
+ #endif // DYNAMIC_CURSOR_COLOR_PATCH
g.fg = defaultfg;
g.bg = defaultrcs;
} else {
+ #if DYNAMIC_CURSOR_COLOR_PATCH
+ unsigned int tmpcol = g.bg;
+ g.bg = g.fg;
+ g.fg = tmpcol;
+ #else
g.fg = defaultbg;
g.bg = defaultcs;
+ #endif // DYNAMIC_CURSOR_COLOR_PATCH
}
+
+ #if DYNAMIC_CURSOR_COLOR_PATCH
+ if (IS_TRUECOL(g.bg)) {
+ colbg.alpha = 0xffff;
+ colbg.red = TRUERED(g.bg);
+ colbg.green = TRUEGREEN(g.bg);
+ colbg.blue = TRUEBLUE(g.bg);
+ XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colbg, &drawcol);
+ } else
+ drawcol = dc.col[g.bg];
+ #else
drawcol = dc.col[g.bg];
+ #endif // DYNAMIC_CURSOR_COLOR_PATCH
+ #endif // SELECTION_COLORS_PATCH
}
+ #if KEYBOARDSELECT_PATCH && REFLOW_PATCH
+ if (g.mode & ATTR_HIGHLIGHT)
+ g.mode ^= ATTR_REVERSE;
+ #endif // KEYBOARDSELECT_PATCH
+
/* draw the new one */
if (IS_SET(MODE_FOCUSED)) {
switch (win.cursor) {
+ #if !BLINKING_CURSOR_PATCH
+ case 7: /* st extension */
+ g.u = 0x2603; /* snowman (U+2603) */
+ /* FALLTHROUGH */
+ #endif // BLINKING_CURSOR_PATCH
case 0: /* Blinking block */
case 1: /* Blinking block (default) */
+ #if BLINKING_CURSOR_PATCH
if (IS_SET(MODE_BLINK))
break;
/* FALLTHROUGH */
+ #endif // BLINKING_CURSOR_PATCH
case 2: /* Steady block */
xdrawglyph(g, cx, cy);
break;
case 3: /* Blinking underline */
+ #if BLINKING_CURSOR_PATCH
if (IS_SET(MODE_BLINK))
break;
/* FALLTHROUGH */
+ #endif // BLINKING_CURSOR_PATCH
case 4: /* Steady underline */
+ #if ANYSIZE_PATCH
+ XftDrawRect(xw.draw, &drawcol,
+ win.hborderpx + cx * win.cw,
+ win.vborderpx + (cy + 1) * win.ch - \
+ cursorthickness,
+ win.cw, cursorthickness);
+ #else
XftDrawRect(xw.draw, &drawcol,
borderpx + cx * win.cw,
borderpx + (cy + 1) * win.ch - \
cursorthickness,
win.cw, cursorthickness);
+ #endif // ANYSIZE_PATCH
break;
case 5: /* Blinking bar */
+ #if BLINKING_CURSOR_PATCH
if (IS_SET(MODE_BLINK))
break;
/* FALLTHROUGH */
+ #endif // BLINKING_CURSOR_PATCH
case 6: /* Steady bar */
XftDrawRect(xw.draw, &drawcol,
+ #if ANYSIZE_PATCH
+ win.hborderpx + cx * win.cw,
+ win.vborderpx + cy * win.ch,
+ #else
borderpx + cx * win.cw,
borderpx + cy * win.ch,
+ #endif // ANYSIZE_PATCH
cursorthickness, win.ch);
break;
+ #if BLINKING_CURSOR_PATCH
case 7: /* Blinking st cursor */
if (IS_SET(MODE_BLINK))
break;
- }
+ /* FALLTHROUGH */
+ case 8: /* Steady st cursor */
+ g.u = stcursor;
+ xdrawglyph(g, cx, cy);
+ break;
+ #endif // BLINKING_CURSOR_PATCH
+ }
} else {
XftDrawRect(xw.draw, &drawcol,
+ #if ANYSIZE_PATCH
+ win.hborderpx + cx * win.cw,
+ win.vborderpx + cy * win.ch,
+ #else
borderpx + cx * win.cw,
borderpx + cy * win.ch,
+ #endif // ANYSIZE_PATCH
win.cw - 1, 1);
XftDrawRect(xw.draw, &drawcol,
+ #if ANYSIZE_PATCH
+ win.hborderpx + cx * win.cw,
+ win.vborderpx + cy * win.ch,
+ #else
borderpx + cx * win.cw,
borderpx + cy * win.ch,
+ #endif // ANYSIZE_PATCH
1, win.ch - 1);
XftDrawRect(xw.draw, &drawcol,
+ #if ANYSIZE_PATCH
+ win.hborderpx + (cx + 1) * win.cw - 1,
+ win.vborderpx + cy * win.ch,
+ #else
borderpx + (cx + 1) * win.cw - 1,
borderpx + cy * win.ch,
+ #endif // ANYSIZE_PATCH
1, win.ch - 1);
XftDrawRect(xw.draw, &drawcol,
+ #if ANYSIZE_PATCH
+ win.hborderpx + cx * win.cw,
+ win.vborderpx + (cy + 1) * win.ch - 1,
+ #else
borderpx + cx * win.cw,
borderpx + (cy + 1) * win.ch - 1,
+ #endif // ANYSIZE_PATCH
win.cw, 1);
}
}
@@ -1758,34 +2942,188 @@ xseticontitle(char *p)
XTextProperty prop;
DEFAULT(p, opt_title);
- if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
- &prop) != Success)
+ if (p[0] == '\0')
+ p = opt_title;
+
+ if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
+ &prop) != Success)
return;
XSetWMIconName(xw.dpy, xw.win, &prop);
XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmiconname);
XFree(prop.value);
}
+#if CSI_22_23_PATCH
+void
+xsettitle(char *p, int pop)
+{
+ XTextProperty prop;
+
+ free(titlestack[tstki]);
+ if (pop) {
+ titlestack[tstki] = NULL;
+ tstki = (tstki - 1 + TITLESTACKSIZE) % TITLESTACKSIZE;
+ p = titlestack[tstki] ? titlestack[tstki] : opt_title;
+ } else if (p && p[0] != '\0') {
+ titlestack[tstki] = xstrdup(p);
+ } else {
+ titlestack[tstki] = NULL;
+ p = opt_title;
+ }
+
+ if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
+ &prop) != Success)
+ return;
+ XSetWMName(xw.dpy, xw.win, &prop);
+ XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmname);
+ XFree(prop.value);
+}
+
+void
+xpushtitle(void)
+{
+ int tstkin = (tstki + 1) % TITLESTACKSIZE;
+
+ free(titlestack[tstkin]);
+ titlestack[tstkin] = titlestack[tstki] ? xstrdup(titlestack[tstki]) : NULL;
+ tstki = tstkin;
+}
+
+void
+xfreetitlestack(void)
+{
+ for (int i = 0; i < LEN(titlestack); i++) {
+ free(titlestack[i]);
+ titlestack[i] = NULL;
+ }
+}
+#else
void
xsettitle(char *p)
{
XTextProperty prop;
DEFAULT(p, opt_title);
- if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
- &prop) != Success)
+ if (p[0] == '\0')
+ p = opt_title;
+
+ if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
+ &prop) != Success)
return;
XSetWMName(xw.dpy, xw.win, &prop);
XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmname);
XFree(prop.value);
}
+#endif // CSI_22_23_PATCH
int
xstartdraw(void)
{
+ #if W3M_PATCH
+ if (IS_SET(MODE_VISIBLE))
+ XCopyArea(xw.dpy, xw.win, xw.buf, dc.gc, 0, 0, win.w, win.h, 0, 0);
+ #endif // W3M_PATCH
return IS_SET(MODE_VISIBLE);
}
+#if LIGATURES_PATCH && WIDE_GLYPHS_PATCH
+void
+xdrawline(Line line, int x1, int y1, int x2)
+{
+ int i, j, x, ox, numspecs;
+ Glyph new;
+ GlyphFontSeq *seq = xw.specseq;
+ XftGlyphFontSpec *specs = xw.specbuf;
+
+ /* Draw line in 2 passes: background and foreground. This way wide glyphs
+ won't get truncated (#223) */
+
+ /* background */
+ i = j = ox = 0;
+ for (x = x1; x < x2; x++) {
+ new = line[x];
+ if (new.mode == ATTR_WDUMMY)
+ continue;
+ if (selected(x, y1))
+ #if SELECTION_COLORS_PATCH
+ new.mode |= ATTR_SELECTED;
+ #else
+ new.mode ^= ATTR_REVERSE;
+ #endif // SELECTION_COLORS_PATCH
+ if ((i > 0) && ATTRCMP(seq[j].base, new)) {
+ numspecs = xmakeglyphfontspecs(specs, &line[ox], x - ox, ox, y1);
+ xdrawglyphfontspecs(specs, seq[j].base, numspecs, ox, y1, DRAW_BG, x - ox);
+ seq[j].charlen = x - ox;
+ seq[j++].numspecs = numspecs;
+ specs += numspecs;
+ i = 0;
+ }
+ if (i == 0) {
+ ox = x;
+ seq[j].ox= ox;
+ seq[j].base = new;
+ }
+ i++;
+ }
+ if (i > 0) {
+ numspecs = xmakeglyphfontspecs(specs, &line[ox], x2 - ox, ox, y1);
+ xdrawglyphfontspecs(specs, seq[j].base, numspecs, ox, y1, DRAW_BG, x2 - ox);
+ seq[j].charlen = x2 - ox;
+ seq[j++].numspecs = numspecs;
+ }
+
+ /* foreground */
+ specs = xw.specbuf;
+ for (i = 0; i < j; i++) {
+ xdrawglyphfontspecs(specs, seq[i].base, seq[i].numspecs, seq[i].ox, y1, DRAW_FG, seq[i].charlen);
+ specs += seq[i].numspecs;
+ }
+
+ #if KEYBOARDSELECT_PATCH && REFLOW_PATCH
+ kbds_drawstatusbar(y1);
+ #endif // KEYBOARDSELECT_PATCH
+}
+#elif LIGATURES_PATCH
+void
+xdrawline(Line line, int x1, int y1, int x2)
+{
+ int i, x, ox, numspecs;
+ Glyph base, new;
+
+ XftGlyphFontSpec *specs = xw.specbuf;
+
+ i = ox = 0;
+ for (x = x1; x < x2; x++) {
+ new = line[x];
+ if (new.mode == ATTR_WDUMMY)
+ continue;
+ if (selected(x, y1))
+ #if SELECTION_COLORS_PATCH
+ new.mode |= ATTR_SELECTED;
+ #else
+ new.mode ^= ATTR_REVERSE;
+ #endif // SELECTION_COLORS_PATCH
+ if ((i > 0) && ATTRCMP(base, new)) {
+ numspecs = xmakeglyphfontspecs(specs, &line[ox], x - ox, ox, y1);
+ xdrawglyphfontspecs(specs, base, numspecs, ox, y1, x - ox);
+ i = 0;
+ }
+ if (i == 0) {
+ ox = x;
+ base = new;
+ }
+ i++;
+ }
+ if (i > 0) {
+ numspecs = xmakeglyphfontspecs(specs, &line[ox], x2 - ox, ox, y1);
+ xdrawglyphfontspecs(specs, base, numspecs, ox, y1, x2 - ox);
+ }
+
+ #if KEYBOARDSELECT_PATCH && REFLOW_PATCH
+ kbds_drawstatusbar(y1);
+ #endif // KEYBOARDSELECT_PATCH
+}
+#elif WIDE_GLYPHS_PATCH
void
xdrawline(Line line, int x1, int y1, int x2)
{
@@ -1806,7 +3144,11 @@ xdrawline(Line line, int x1, int y1, int x2)
if (new.mode == ATTR_WDUMMY)
continue;
if (selected(x, y1))
+ #if SELECTION_COLORS_PATCH
+ new.mode |= ATTR_SELECTED;
+ #else
new.mode ^= ATTR_REVERSE;
+ #endif // SELECTION_COLORS_PATCH
if (i > 0 && ATTRCMP(base, new)) {
xdrawglyphfontspecs(specs, base, i, ox, y1, dmode);
specs += i;
@@ -1822,26 +3164,220 @@ xdrawline(Line line, int x1, int y1, int x2)
if (i > 0)
xdrawglyphfontspecs(specs, base, i, ox, y1, dmode);
}
+
+ #if KEYBOARDSELECT_PATCH && REFLOW_PATCH
+ kbds_drawstatusbar(y1);
+ #endif // KEYBOARDSELECT_PATCH
+}
+#else // !WIDE_GLYPHS_PATCH and !LIGATURES_PATCH
+void
+xdrawline(Line line, int x1, int y1, int x2)
+{
+ int i, x, ox, numspecs;
+ Glyph base, new;
+
+ XftGlyphFontSpec *specs = xw.specbuf;
+
+ numspecs = xmakeglyphfontspecs(specs, &line[x1], x2 - x1, x1, y1);
+ i = ox = 0;
+ for (x = x1; x < x2 && i < numspecs; x++) {
+ new = line[x];
+ if (new.mode == ATTR_WDUMMY)
+ continue;
+ if (selected(x, y1))
+ #if SELECTION_COLORS_PATCH
+ new.mode |= ATTR_SELECTED;
+ #else
+ new.mode ^= ATTR_REVERSE;
+ #endif // SELECTION_COLORS_PATCH
+ if (i > 0 && ATTRCMP(base, new)) {
+ xdrawglyphfontspecs(specs, base, i, ox, y1);
+ specs += i;
+ numspecs -= i;
+ i = 0;
+ }
+ if (i == 0) {
+ ox = x;
+ base = new;
+ }
+ i++;
+ }
+ if (i > 0)
+ xdrawglyphfontspecs(specs, base, i, ox, y1);
+
+ #if KEYBOARDSELECT_PATCH && REFLOW_PATCH
+ kbds_drawstatusbar(y1);
+ #endif // KEYBOARDSELECT_PATCH
}
+#endif // WIDE_GLYPHS_PATCH | LIGATURES_PATCH
void
xfinishdraw(void)
{
- XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, win.w,
- win.h, 0, 0);
- XSetForeground(xw.dpy, dc.gc,
- dc.col[IS_SET(MODE_REVERSE)?
- defaultfg : defaultbg].pixel);
+ #if SIXEL_PATCH
+ ImageList *im, *next;
+ Imlib_Image origin, scaled;
+ XGCValues gcvalues;
+ GC gc = NULL;
+ int width, height;
+ int del, desty, mode, x1, x2, xend;
+ #if ANYSIZE_PATCH
+ int bw = win.hborderpx, bh = win.vborderpx;
+ #else
+ int bw = borderpx, bh = borderpx;
+ #endif // ANYSIZE_PATCH
+ Line line;
+ #endif // SIXEL_PATCH
+
+ #if SIXEL_PATCH
+ for (im = term.images; im; im = next) {
+ next = im->next;
+
+ /* do not draw or process the image, if it is not visible */
+ if (im->x >= term.col || im->y >= term.row || im->y < 0)
+ continue;
+
+ #if KEYBOARDSELECT_PATCH && REFLOW_PATCH
+ /* do not draw the image on the search bar */
+ if (im->y == term.row-1 && IS_SET(MODE_KBDSELECT) && kbds_issearchmode())
+ continue;
+ #endif // KEYBOARDSELECT_PATCH
+
+ /* scale the image */
+ width = MAX(im->width * win.cw / im->cw, 1);
+ height = MAX(im->height * win.ch / im->ch, 1);
+ if (!im->pixmap) {
+ im->pixmap = (void *)XCreatePixmap(xw.dpy, xw.win, width, height,
+ #if ALPHA_PATCH
+ xw.depth
+ #else
+ DefaultDepth(xw.dpy, xw.scr)
+ #endif // ALPHA_PATCH
+ );
+ if (!im->pixmap)
+ continue;
+ if (win.cw == im->cw && win.ch == im->ch) {
+ XImage ximage = {
+ .format = ZPixmap,
+ .data = (char *)im->pixels,
+ .width = im->width,
+ .height = im->height,
+ .xoffset = 0,
+ .byte_order = sixelbyteorder,
+ .bitmap_bit_order = MSBFirst,
+ .bits_per_pixel = 32,
+ .bytes_per_line = im->width * 4,
+ .bitmap_unit = 32,
+ .bitmap_pad = 32,
+ #if ALPHA_PATCH
+ .depth = xw.depth
+ #else
+ .depth = 24
+ #endif // ALPHA_PATCH
+ };
+ XPutImage(xw.dpy, (Drawable)im->pixmap, dc.gc, &ximage, 0, 0, 0, 0, width, height);
+ if (im->transparent)
+ im->clipmask = (void *)sixel_create_clipmask((char *)im->pixels, width, height);
+ } else {
+ origin = imlib_create_image_using_data(im->width, im->height, (DATA32 *)im->pixels);
+ if (!origin)
+ continue;
+ imlib_context_set_image(origin);
+ imlib_image_set_has_alpha(1);
+ imlib_context_set_anti_alias(im->transparent ? 0 : 1); /* anti-aliasing messes up the clip mask */
+ scaled = imlib_create_cropped_scaled_image(0, 0, im->width, im->height, width, height);
+ imlib_free_image_and_decache();
+ if (!scaled)
+ continue;
+ imlib_context_set_image(scaled);
+ imlib_image_set_has_alpha(1);
+ XImage ximage = {
+ .format = ZPixmap,
+ .data = (char *)imlib_image_get_data_for_reading_only(),
+ .width = width,
+ .height = height,
+ .xoffset = 0,
+ .byte_order = sixelbyteorder,
+ .bitmap_bit_order = MSBFirst,
+ .bits_per_pixel = 32,
+ .bytes_per_line = width * 4,
+ .bitmap_unit = 32,
+ .bitmap_pad = 32,
+ #if ALPHA_PATCH
+ .depth = xw.depth
+ #else
+ .depth = 24
+ #endif // ALPHA_PATCH
+ };
+ XPutImage(xw.dpy, (Drawable)im->pixmap, dc.gc, &ximage, 0, 0, 0, 0, width, height);
+ if (im->transparent)
+ im->clipmask = (void *)sixel_create_clipmask((char *)imlib_image_get_data_for_reading_only(), width, height);
+ imlib_free_image_and_decache();
+ }
+ }
+
+ /* create GC */
+ if (!gc) {
+ memset(&gcvalues, 0, sizeof(gcvalues));
+ gcvalues.graphics_exposures = False;
+ gc = XCreateGC(xw.dpy, xw.win, GCGraphicsExposures, &gcvalues);
+ }
+
+ /* set the clip mask */
+ desty = bh + im->y * win.ch;
+ if (im->clipmask) {
+ XSetClipMask(xw.dpy, gc, (Drawable)im->clipmask);
+ XSetClipOrigin(xw.dpy, gc, bw + im->x * win.cw, desty);
+ }
+
+ /* draw only the parts of the image that are not erased */
+ #if SCROLLBACK_PATCH || REFLOW_PATCH
+ line = TLINE(im->y) + im->x;
+ #else
+ line = term.line[im->y] + im->x;
+ #endif // SCROLLBACK_PATCH || REFLOW_PATCH
+ xend = MIN(im->x + im->cols, term.col);
+ for (del = 1, x1 = im->x; x1 < xend; x1 = x2) {
+ mode = line->mode & ATTR_SIXEL;
+ for (x2 = x1 + 1; x2 < xend; x2++) {
+ if (((++line)->mode & ATTR_SIXEL) != mode)
+ break;
+ }
+ if (mode) {
+ XCopyArea(xw.dpy, (Drawable)im->pixmap, xw.buf, gc,
+ (x1 - im->x) * win.cw, 0,
+ MIN((x2 - x1) * win.cw, width - (x1 - im->x) * win.cw), height,
+ bw + x1 * win.cw, desty);
+ del = 0;
+ }
+ }
+ if (im->clipmask)
+ XSetClipMask(xw.dpy, gc, None);
+
+ /* if all the parts are erased, we can delete the entire image */
+ if (del && im->x + im->cols <= term.col)
+ delete_image(im);
+ }
+ if (gc)
+ XFreeGC(xw.dpy, gc);
+ #endif // SIXEL_PATCH
+
+ #if !SINGLE_DRAWABLE_BUFFER_PATCH
+ XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, win.w, win.h, 0, 0);
+ #endif // SINGLE_DRAWABLE_BUFFER_PATCH
+ XSetForeground(xw.dpy, dc.gc, dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg].pixel);
}
void
xximspot(int x, int y)
{
- XPoint spot = { borderpx + x * win.cw, borderpx + (y + 1) * win.ch };
- XVaNestedList attr = XVaCreateNestedList(0, XNSpotLocation, &spot, NULL);
+ if (xw.ime.xic == NULL)
+ return;
- XSetICValues(xw.xic, XNPreeditAttributes, attr, NULL);
- XFree(attr);
+ xw.ime.spot.x = borderpx + x * win.cw;
+ xw.ime.spot.y = borderpx + (y + 1) * win.ch;
+
+ XSetICValues(xw.ime.xic, XNPreeditAttributes, xw.ime.spotlist, NULL);
}
void
@@ -1861,12 +3397,26 @@ visibility(XEvent *ev)
void
unmap(XEvent *ev)
{
+ #if ST_EMBEDDER_PATCH
+ if (embed == ev->xunmap.window) {
+ embed = 0;
+ XRaiseWindow(xw.dpy, xw.win);
+ XSetInputFocus(xw.dpy, xw.win, RevertToParent, CurrentTime);
+ }
+ #endif // ST_EMBEDDER_PATCH
win.mode &= ~MODE_VISIBLE;
}
void
xsetpointermotion(int set)
{
+ #if HIDECURSOR_PATCH
+ if (!set && !xw.pointerisvisible)
+ return;
+ #endif // HIDECURSOR_PATCH
+ #if OPENURLONCLICK_PATCH
+ set = 1; /* keep MotionNotify event enabled */
+ #endif // OPENURLONCLICK_PATCH
MODBIT(xw.attrs.event_mask, set, PointerMotionMask);
XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs);
}
@@ -1876,12 +3426,25 @@ xsetmode(int set, unsigned int flags)
{
int mode = win.mode;
MODBIT(win.mode, set, flags);
- if (flags & MODE_MOUSE) {
- if (win.mode & MODE_MOUSE)
- XUndefineCursor(xw.dpy, xw.win);
- else
- XDefineCursor(xw.dpy, xw.win, cursor);
- }
+ #if SWAPMOUSE_PATCH
+ if ((flags & MODE_MOUSE)
+ #if HIDECURSOR_PATCH
+ && xw.pointerisvisible
+ #endif // HIDECURSOR_PATCH
+ ) {
+ if (win.mode & MODE_MOUSE)
+ XUndefineCursor(xw.dpy, xw.win);
+ else
+ #if HIDECURSOR_PATCH
+ XDefineCursor(xw.dpy, xw.win, xw.vpointer);
+ #else
+ XDefineCursor(xw.dpy, xw.win, cursor);
+ #endif // HIDECURSOR_PATCH
+ }
+ #elif OPENURLONCLICK_PATCH
+ if (win.mode & MODE_MOUSE && xw.pointerisvisible)
+ XDefineCursor(xw.dpy, xw.win, xw.vpointer);
+ #endif // SWAPMOUSE_PATCH
if ((win.mode & MODE_REVERSE) != (mode & MODE_REVERSE))
redraw();
}
@@ -1889,13 +3452,26 @@ xsetmode(int set, unsigned int flags)
int
xsetcursor(int cursor)
{
- DEFAULT(cursor, 1);
+ #if BLINKING_CURSOR_PATCH
if (!BETWEEN(cursor, 0, 8)) /* 7-8: st extensions */
+ #else
+ if (!BETWEEN(cursor, 0, 7)) /* 7: st extension */
+ #endif // BLINKING_CURSOR_PATCH
return 1;
+ #if DEFAULT_CURSOR_PATCH
+ #if BLINKING_CURSOR_PATCH
+ win.cursor = (cursor ? cursor : cursorstyle);
+ #else
+ win.cursor = (cursor ? cursor : cursorshape);
+ #endif // BLINKING_CURSOR_PATCH
+ #else
win.cursor = cursor;
+ #endif // DEFAULT_CURSOR_PATCH
+ #if BLINKING_CURSOR_PATCH
cursorblinks = win.cursor == 0 || win.cursor == 1 ||
win.cursor == 3 || win.cursor == 5 ||
win.cursor == 7;
+ #endif // BLINKING_CURSOR_PATCH
return 0;
}
@@ -1916,6 +3492,10 @@ xbell(void)
xseturgency(1);
if (bellvolume)
XkbBell(xw.dpy, xw.win, bellvolume, (Atom)NULL);
+ #if VISUALBELL_1_PATCH
+ if (!bellon) /* turn visual bell on */
+ bellon = 1;
+ #endif // VISUALBELL_1_PATCH
}
void
@@ -1923,20 +3503,45 @@ focus(XEvent *ev)
{
XFocusChangeEvent *e = &ev->xfocus;
+ #if ST_EMBEDDER_PATCH
+ if (embed && ev->type == FocusIn) {
+ XRaiseWindow(xw.dpy, embed);
+ XSetInputFocus(xw.dpy, embed, RevertToParent, CurrentTime);
+ sendxembed(XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT, 0, 0);
+ sendxembed(XEMBED_WINDOW_ACTIVATE, 0, 0, 0);
+ }
+ #endif // ST_EMBEDDER_PATCH
+
if (e->mode == NotifyGrab)
return;
if (ev->type == FocusIn) {
- XSetICFocus(xw.xic);
+ if (xw.ime.xic)
+ XSetICFocus(xw.ime.xic);
win.mode |= MODE_FOCUSED;
xseturgency(0);
if (IS_SET(MODE_FOCUS))
ttywrite("\033[I", 3, 0);
+ #if ALPHA_PATCH && ALPHA_FOCUS_HIGHLIGHT_PATCH
+ if (!focused) {
+ focused = 1;
+ xloadcols();
+ tfulldirt();
+ }
+ #endif // ALPHA_FOCUS_HIGHLIGHT_PATCH
} else {
- XUnsetICFocus(xw.xic);
+ if (xw.ime.xic)
+ XUnsetICFocus(xw.ime.xic);
win.mode &= ~MODE_FOCUSED;
if (IS_SET(MODE_FOCUS))
ttywrite("\033[O", 3, 0);
+ #if ALPHA_PATCH && ALPHA_FOCUS_HIGHLIGHT_PATCH
+ if (focused) {
+ focused = 0;
+ xloadcols();
+ tfulldirt();
+ }
+ #endif // ALPHA_FOCUS_HIGHLIGHT_PATCH
}
}
@@ -1987,20 +3592,81 @@ void
kpress(XEvent *ev)
{
XKeyEvent *e = &ev->xkey;
- KeySym ksym;
- char buf[32], *customkey;
- int len;
+ KeySym ksym = NoSymbol;
+ char buf[64], *customkey;
+ int len, screen;
Rune c;
Status status;
Shortcut *bp;
+ #if HIDECURSOR_PATCH
+ if (xw.pointerisvisible && hidecursor) {
+ #if OPENURLONCLICK_PATCH
+ #if ANYSIZE_PATCH
+ int x = e->x - win.hborderpx;
+ int y = e->y - win.vborderpx;
+ #else
+ int x = e->x - borderpx;
+ int y = e->y - borderpx;
+ #endif // ANYSIZE_PATCH
+ LIMIT(x, 0, win.tw - 1);
+ LIMIT(y, 0, win.th - 1);
+ if (!detecturl(x / win.cw, y / win.ch, 0)) {
+ XDefineCursor(xw.dpy, xw.win, xw.bpointer);
+ xsetpointermotion(1);
+ xw.pointerisvisible = 0;
+ }
+ #else
+ XDefineCursor(xw.dpy, xw.win, xw.bpointer);
+ xsetpointermotion(1);
+ xw.pointerisvisible = 0;
+ #endif // OPENURLONCLICK_PATCH
+ }
+ #endif // HIDECURSOR_PATCH
+
if (IS_SET(MODE_KBDLOCK))
return;
- len = XmbLookupString(xw.xic, e, buf, sizeof buf, &ksym, &status);
+ if (xw.ime.xic) {
+ len = XmbLookupString(xw.ime.xic, e, buf, sizeof buf, &ksym, &status);
+ if (status == XBufferOverflow)
+ return;
+ } else {
+ len = XLookupString(e, buf, sizeof buf, &ksym, NULL);
+ }
+
+ #if KEYBOARDSELECT_PATCH && REFLOW_PATCH
+ if (IS_SET(MODE_KBDSELECT) ) {
+ if (kbds_issearchmode()) {
+ for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
+ if (ksym == bp->keysym && match(bp->mod, e->state) &&
+ (!bp->screen || bp->screen == screen) &&
+ (bp->func == clippaste || bp->func == selpaste)) {
+ bp->func(&(bp->arg));
+ return;
+ }
+ }
+ }
+ if (match(XK_NO_MOD, e->state) ||
+ (XK_Shift_L | XK_Shift_R) & e->state )
+ win.mode ^= kbds_keyboardhandler(ksym, buf, len, 0);
+ return;
+ }
+ #elif KEYBOARDSELECT_PATCH
+ if ( IS_SET(MODE_KBDSELECT) ) {
+ if ( match(XK_NO_MOD, e->state) ||
+ (XK_Shift_L | XK_Shift_R) & e->state )
+ win.mode ^= trt_kbdselect(ksym, buf, len);
+ return;
+ }
+ #endif // KEYBOARDSELECT_PATCH
+
+ screen = tisaltscr() ? S_ALT : S_PRI;
+
/* 1. shortcuts */
for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
- if (ksym == bp->keysym && match(bp->mod, e->state)) {
+ if (ksym == bp->keysym && match(bp->mod, e->state) &&
+ (!bp->screen || bp->screen == screen)) {
bp->func(&(bp->arg));
return;
}
@@ -2030,6 +3696,7 @@ kpress(XEvent *ev)
ttywrite(buf, len, 1);
}
+
void
cmessage(XEvent *e)
{
@@ -2047,15 +3714,51 @@ cmessage(XEvent *e)
} else if (e->xclient.data.l[0] == xw.wmdeletewin) {
ttyhangup();
exit(0);
+ #if DRAG_AND_DROP_PATCH
+ } else if (e->xclient.message_type == xw.XdndEnter) {
+ xw.XdndSourceWin = e->xclient.data.l[0];
+ xw.XdndSourceVersion = e->xclient.data.l[1] >> 24;
+ xw.XdndSourceFormat = None;
+ if (xw.XdndSourceVersion > 5)
+ return;
+ xdndenter(e);
+ } else if (e->xclient.message_type == xw.XdndPosition
+ && xw.XdndSourceVersion <= 5) {
+ xdndpos(e);
+ } else if (e->xclient.message_type == xw.XdndDrop
+ && xw.XdndSourceVersion <= 5) {
+ xdnddrop(e);
+ #endif // DRAG_AND_DROP_PATCH
}
}
void
resize(XEvent *e)
{
+ #if ST_EMBEDDER_PATCH
+ XWindowChanges wc;
+ #endif // ST_EMBEDDER_PATCH
+
+ #if BACKGROUND_IMAGE_PATCH
+ if (pseudotransparency) {
+ if (e->xconfigure.width == win.w &&
+ e->xconfigure.height == win.h &&
+ e->xconfigure.x == win.x && e->xconfigure.y == win.y)
+ return;
+ updatexy();
+ } else
+ #endif // BACKGROUND_IMAGE_PATCH
if (e->xconfigure.width == win.w && e->xconfigure.height == win.h)
return;
+ #if ST_EMBEDDER_PATCH
+ if (embed) {
+ wc.width = e->xconfigure.width;
+ wc.height = e->xconfigure.height;
+ XConfigureWindow(xw.dpy, embed, CWWidth | CWHeight, &wc);
+ }
+ #endif // ST_EMBEDDER_PATCH
+
cresize(e->xconfigure.width, e->xconfigure.height);
}
@@ -2093,7 +3796,11 @@ run(void)
FD_SET(ttyfd, &rfd);
FD_SET(xfd, &rfd);
+ #if SYNC_PATCH
+ if (XPending(xw.dpy) || ttyread_pending())
+ #else
if (XPending(xw.dpy))
+ #endif // SYNC_PATCH
timeout = 0; /* existing events might not set xfd */
seltv.tv_sec = timeout / 1E3;
@@ -2107,13 +3814,23 @@ run(void)
}
clock_gettime(CLOCK_MONOTONIC, &now);
+ #if SYNC_PATCH
+ int ttyin = FD_ISSET(ttyfd, &rfd) || ttyread_pending();
+ if (ttyin)
+ ttyread();
+ #else
if (FD_ISSET(ttyfd, &rfd))
ttyread();
+ #endif // SYNC_PATCH
xev = 0;
while (XPending(xw.dpy)) {
- xev = 1;
XNextEvent(xw.dpy, &ev);
+ #if BLINKING_CURSOR_PATCH
+ xev = (!xev || xev == SelectionRequest) ? ev.type : xev;
+ #else
+ xev = 1;
+ #endif // BLINKING_CURSOR_PATCH
if (XFilterEvent(&ev, None))
continue;
if (handler[ev.type])
@@ -2125,19 +3842,26 @@ run(void)
* triggers drawing, we first wait a bit to ensure we got
* everything, and if nothing new arrives - we draw.
* We start with trying to wait minlatency ms. If more content
- * arrives sooner, we retry with shorter and shorter preiods,
+ * arrives sooner, we retry with shorter and shorter periods,
* and eventually draw even without idle after maxlatency ms.
* Typically this results in low latency while interacting,
* maximum latency intervals during `cat huge.txt`, and perfect
* sync with periodic updates from animations/key-repeats/etc.
*/
- if (FD_ISSET(ttyfd, &rfd) || xev) {
+ #if SYNC_PATCH
+ if (ttyin || xev)
+ #else
+ if (FD_ISSET(ttyfd, &rfd) || xev)
+ #endif // SYNC_PATCH
+ {
if (!drawing) {
trigger = now;
- if (IS_SET(MODE_BLINK)) {
- win.mode ^= MODE_BLINK;
+ #if BLINKING_CURSOR_PATCH
+ if (xev != SelectionRequest) {
+ win.mode &= ~MODE_BLINK;
+ lastblink = now;
}
- lastblink = now;
+ #endif // BLINKING_CURSOR_PATCH
drawing = 1;
}
timeout = (maxlatency - TIMEDIFF(now, trigger)) \
@@ -2146,9 +3870,28 @@ run(void)
continue; /* we have time, try to find idle */
}
+ #if SYNC_PATCH
+ if (tinsync(su_timeout)) {
+ /*
+ * on synchronized-update draw-suspension: don't reset
+ * drawing so that we draw ASAP once we can (just after
+ * ESU). it won't be too soon because we already can
+ * draw now but we skip. we set timeout > 0 to draw on
+ * SU-timeout even without new content.
+ */
+ timeout = minlatency;
+ continue;
+ }
+ #endif // SYNC_PATCH
+
/* idle detected or maxlatency exhausted -> draw */
timeout = -1;
- if (blinktimeout && (cursorblinks || tattrset(ATTR_BLINK))) {
+ #if BLINKING_CURSOR_PATCH
+ if (blinktimeout && (cursorblinks || tattrset(ATTR_BLINK)))
+ #else
+ if (blinktimeout && tattrset(ATTR_BLINK))
+ #endif // BLINKING_CURSOR_PATCH
+ {
timeout = blinktimeout - TIMEDIFF(now, lastblink);
if (timeout <= 0) {
if (-timeout > blinktimeout) /* start visible */
@@ -2160,200 +3903,42 @@ run(void)
}
}
+ #if VISUALBELL_1_PATCH
+ if (bellon) {
+ bellon++;
+ bellon %= 3;
+ MODBIT(win.mode, !IS_SET(MODE_REVERSE), MODE_REVERSE);
+ redraw();
+ }
+ else
+ draw();
+ #else
draw();
+ #endif // VISUALBELL_1_PATCH
XFlush(xw.dpy);
drawing = 0;
}
}
-#define XRESOURCE_LOAD_META(NAME) \
- if(!XrmGetResource(xrdb, "st." NAME, "st." NAME, &type, &ret)) \
- XrmGetResource(xrdb, "*." NAME, "*." NAME, &type, &ret); \
- if (ret.addr != NULL && !strncmp("String", type, 64))
-
-#define XRESOURCE_LOAD_STRING(NAME, DST) \
- XRESOURCE_LOAD_META(NAME) \
- DST = ret.addr;
-
-#define XRESOURCE_LOAD_CHAR(NAME, DST) \
- XRESOURCE_LOAD_META(NAME) \
- DST = ret.addr[0];
-
-#define XRESOURCE_LOAD_INTEGER(NAME, DST) \
- XRESOURCE_LOAD_META(NAME) \
- DST = strtoul(ret.addr, NULL, 10);
-
-#define XRESOURCE_LOAD_FLOAT(NAME, DST) \
- XRESOURCE_LOAD_META(NAME) \
- DST = strtof(ret.addr, NULL);
-
-void
-xrdb_load(void)
-{
- /* XXX */
- char *xrm;
- char *type;
- XrmDatabase xrdb;
- XrmValue ret;
- Display *dpy;
-
- if(!(dpy = XOpenDisplay(NULL)))
- die("Can't open display\n");
-
- XrmInitialize();
- xrm = XResourceManagerString(dpy);
-
- if (xrm != NULL) {
- xrdb = XrmGetStringDatabase(xrm);
-
- /* handling colors here without macros to do via loop. */
- int i = 0;
- char loadValue[12] = "";
- for (i = 0; i < 256; i++)
- {
- sprintf(loadValue, "%s%d", "st.color", i);
-
- if(!XrmGetResource(xrdb, loadValue, loadValue, &type, &ret))
- {
- sprintf(loadValue, "%s%d", "*.color", i);
- if (!XrmGetResource(xrdb, loadValue, loadValue, &type, &ret))
- /* reset if not found (unless in range for defaults). */
- if (i > 15)
- colorname[i] = NULL;
- }
-
- if (ret.addr != NULL && !strncmp("String", type, 64))
- colorname[i] = ret.addr;
- }
-
- XRESOURCE_LOAD_STRING("foreground", colorname[defaultfg]);
- XRESOURCE_LOAD_STRING("background", colorname[defaultbg]);
- XRESOURCE_LOAD_STRING("cursorfg", colorname[defaultcs])
- else {
- // this looks confusing because we are chaining off of the if
- // in the macro. probably we should be wrapping everything blocks
- // so this isn't possible...
- defaultcs = defaultfg;
- }
- XRESOURCE_LOAD_STRING("reverse-cursor", colorname[defaultrcs])
- else {
- // see above.
- defaultrcs = defaultbg;
- }
-
- XRESOURCE_LOAD_STRING("font", font);
- XRESOURCE_LOAD_STRING("termname", termname);
-
- /* XRESOURCE_LOAD_INTEGER("xfps", xfps); */
- /* XRESOURCE_LOAD_INTEGER("actionfps", actionfps); */
- XRESOURCE_LOAD_INTEGER("blinktimeout", blinktimeout);
- XRESOURCE_LOAD_INTEGER("bellvolume", bellvolume);
- XRESOURCE_LOAD_INTEGER("borderpx", borderpx);
- /* XRESOURCE_LOAD_INTEGER("borderless", borderless); */
- XRESOURCE_LOAD_INTEGER("cursorshape", cursorshape);
-
- /* cursorblinkstate = 1; // in case if cursor shape was changed from a blinking one to a non-blinking */
- /* XRESOURCE_LOAD_INTEGER("cursorthickness", cursorthickness); */
- /* XRESOURCE_LOAD_INTEGER("cursorblinkstyle", cursorblinkstyle); */
- /* XRESOURCE_LOAD_INTEGER("cursorblinkontype", cursorblinkontype); */
-
- /* todo: https://github.com/gnotclub/xst/commit/1e82647b0e04077e975679a4b4cf1eb02b04e6bc */
- /* XRESOURCE_LOAD_INTEGER("mouseScrollLines", mousescrolllines); */
-
- XRESOURCE_LOAD_FLOAT("cwscale", cwscale);
- XRESOURCE_LOAD_FLOAT("chscale", chscale);
-
- /* XRESOURCE_LOAD_CHAR("prompt_char", prompt_char); */
-
- }
- XFlush(dpy);
-}
-
-void
-reload(int sig)
-{
- xrdb_load();
-
- /* colors, fonts */
- xloadcols();
- xunloadfonts();
- xloadfonts(font, 0);
-
- /* pretend the window just got resized */
- cresize(win.w, win.h);
-
- redraw();
-
- /* triggers re-render if we're visible. */
- ttywrite("\033[O", 3, 1);
-
- signal(SIGUSR1, reload);
-}
-
-int
-resource_load(XrmDatabase db, char *name, enum resource_type rtype, void *dst)
-{
- char **sdst = dst;
- int *idst = dst;
- float *fdst = dst;
-
- char fullname[256];
- char fullclass[256];
- char *type;
- XrmValue ret;
-
- snprintf(fullname, sizeof(fullname), "%s.%s",
- opt_name ? opt_name : "st", name);
- snprintf(fullclass, sizeof(fullclass), "%s.%s",
- opt_class ? opt_class : "St", name);
- fullname[sizeof(fullname) - 1] = fullclass[sizeof(fullclass) - 1] = '\0';
-
- XrmGetResource(db, fullname, fullclass, &type, &ret);
- if (ret.addr == NULL || strncmp("String", type, 64))
- return 1;
-
- switch (rtype) {
- case STRING:
- *sdst = ret.addr;
- break;
- case INTEGER:
- *idst = strtoul(ret.addr, NULL, 10);
- break;
- case FLOAT:
- *fdst = strtof(ret.addr, NULL);
- break;
- }
- return 0;
-}
-
-void
-config_init(void)
-{
- char *resm;
- XrmDatabase db;
- ResourcePref *p;
-
- XrmInitialize();
- resm = XResourceManagerString(xw.dpy);
- if (!resm)
- return;
-
- db = XrmGetStringDatabase(resm);
- for (p = resources; p < resources + LEN(resources); p++)
- resource_load(db, p->name, p->type, p->dst);
-}
-
void
usage(void)
{
- die("usage: %s [-aiv] [-c class] [-f font] [-g geometry]"
- " [-n name] [-o file]\n"
- " [-T title] [-t title] [-w windowid]"
- " [[-e] command [args ...]]\n"
- " %s [-aiv] [-c class] [-f font] [-g geometry]"
- " [-n name] [-o file]\n"
- " [-T title] [-t title] [-w windowid] -l line"
- " [stty_args ...]\n", argv0, argv0);
+ die("usage: %s [-aiv] [-c class]"
+ #if WORKINGDIR_PATCH
+ " [-d path]"
+ #endif // WORKINGDIR_PATCH
+ " [-f font] [-g geometry]"
+ " [-n name] [-o file]\n"
+ " [-T title] [-t title] [-w windowid]"
+ " [[-e] command [args ...]]\n"
+ " %s [-aiv] [-c class]"
+ #if WORKINGDIR_PATCH
+ " [-d path]"
+ #endif // WORKINGDIR_PATCH
+ " [-f font] [-g geometry]"
+ " [-n name] [-o file]\n"
+ " [-T title] [-t title] [-w windowid] -l line"
+ " [stty_args ...]\n", argv0, argv0);
}
int
@@ -2361,18 +3946,29 @@ main(int argc, char *argv[])
{
xw.l = xw.t = 0;
xw.isfixed = False;
+ #if BLINKING_CURSOR_PATCH
+ xsetcursor(cursorstyle);
+ #else
xsetcursor(cursorshape);
+ #endif // BLINKING_CURSOR_PATCH
ARGBEGIN {
case 'a':
allowaltscreen = 0;
break;
+ #if ALPHA_PATCH
case 'A':
opt_alpha = EARGF(usage());
break;
+ #endif // ALPHA_PATCH
case 'c':
opt_class = EARGF(usage());
break;
+ #if WORKINGDIR_PATCH
+ case 'd':
+ opt_dir = EARGF(usage());
+ break;
+ #endif // WORKINGDIR_PATCH
case 'e':
if (argc > 0)
--argc, ++argv;
@@ -2383,7 +3979,17 @@ main(int argc, char *argv[])
case 'g':
xw.gm = XParseGeometry(EARGF(usage()),
&xw.l, &xw.t, &cols, &rows);
+ #if ANYGEOMETRY_PATCH
+ geometry = CellGeometry;
+ #endif // ANYGEOMETRY_PATCH
break;
+ #if ANYGEOMETRY_PATCH
+ case 'G':
+ xw.gm = XParseGeometry(EARGF(usage()),
+ &xw.l, &xw.t, &width, &height);
+ geometry = PixelGeometry;
+ break;
+ #endif // ANYGEOMETRY_PATCH
case 'i':
xw.isfixed = 1;
break;
@@ -2419,21 +4025,54 @@ run:
setlocale(LC_CTYPE, "");
XSetLocaleModifiers("");
- xrdb_load();
- signal(SIGUSR1, reload);
-
- if(!(xw.dpy = XOpenDisplay(NULL)))
+ #if XRESOURCES_PATCH && XRESOURCES_RELOAD_PATCH || BACKGROUND_IMAGE_PATCH && BACKGROUND_IMAGE_RELOAD_PATCH
+ signal(SIGUSR1, sigusr1_reload);
+ #endif // XRESOURCES_RELOAD_PATCH | BACKGROUND_IMAGE_RELOAD_PATCH
+ #if XRESOURCES_PATCH
+ if (!(xw.dpy = XOpenDisplay(NULL)))
die("Can't open display\n");
- config_init();
+ config_init(xw.dpy);
+ #endif // XRESOURCES_PATCH
+ #if LIGATURES_PATCH
+ hbcreatebuffer();
+ #endif // LIGATURES_PATCH
+
+ #if ANYGEOMETRY_PATCH
+ switch (geometry) {
+ case CellGeometry:
+ xinit(cols, rows);
+ break;
+ case PixelGeometry:
+ xinit(width, height);
+ cols = (win.w - 2 * borderpx) / win.cw;
+ rows = (win.h - 2 * borderpx) / win.ch;
+ break;
+ }
+ #endif // ANYGEOMETRY_PATCH
+
cols = MAX(cols, 1);
rows = MAX(rows, 1);
- signal(SIGUSR1, reload);
+ #if ALPHA_PATCH && ALPHA_FOCUS_HIGHLIGHT_PATCH
+ defaultbg = MAX(LEN(colorname), 256);
+ #endif // ALPHA_FOCUS_HIGHLIGHT_PATCH
tnew(cols, rows);
+ #if !ANYGEOMETRY_PATCH
xinit(cols, rows);
+ #endif // ANYGEOMETRY_PATCH
+ #if BACKGROUND_IMAGE_PATCH
+ bginit();
+ #endif // BACKGROUND_IMAGE_PATCH
xsetenv();
selinit();
+ #if WORKINGDIR_PATCH
+ if (opt_dir && chdir(opt_dir))
+ die("Can't change to working directory %s\n", opt_dir);
+ #endif // WORKINGDIR_PATCH
run();
+ #if LIGATURES_PATCH
+ hbdestroybuffer();
+ #endif // LIGATURES_PATCH
return 0;
}
diff --git a/xresources b/xresources
@@ -1,49 +0,0 @@
-Xft.antialias: 1
-Xft.hinting: 1
-Xft.autohint: 0
-Xft.hintstyle: hintslight
-Xft.rgba: rgb
-Xft.lcdfilter: lcddefault
-
-st.font: JetBrainsMono Nerd Font:style:medium:pixelsize=13
-
-! window padding
-st.borderpx: 20
-
-!- 0.1 to 0.9 = transparency
-st.alpha: 1.0
-
-*background: #181f21
-*foreground: #dadada
-
-! Black + DarkGrey
-*color0: #22292b
-*color8: #575e60
-
-! DarkRed + Red
-*color1: #e06e6e
-*color9: #ef7d7d
-
-! DarkGreen + Green
-*color2: #8ccf7e
-*color10: #9bdead
-
-! DarkYellow + Yellow
-*color3: #e5c76b
-*color11: #f4d67a
-
-! DarkBlue + Blue
-*color4: #67b0e8
-*color12: #6cb5ed
-
-! DarkMagenta + Magenta
-*color5: #c47fd5
-*color13: #ce89df
-
-! DarkCyan + Cyan
-*color6: #6da4cd
-*color14: #67cbe7
-
-! LightGrey + White
-*color7: #b3b9b8
-*color15: #bdc3c2