summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--FAQ2
-rw-r--r--LICENSE9
-rw-r--r--Makefile65
-rw-r--r--README.md27
-rw-r--r--arg.h22
-rw-r--r--config.def.h539
-rw-r--r--config.mk18
-rw-r--r--patches/st-alpha-0.8.1.diff183
-rw-r--r--patches/st-clipboard-20160727-308bfbf.diff13
-rw-r--r--patches/st-clipboard-20180309-c5ba9c0.diff13
-rw-r--r--patches/st-no_bold_colors-0.8.1.diff25
-rw-r--r--patches/st-no_bold_colors-20160727-308bfbf.diff13
-rw-r--r--patches/st-scrollback-0.8.diff (renamed from patches/st-scrollback-20170104-c63a87c.diff)181
-rw-r--r--patches/st-scrollback-mouse-0.8.diff (renamed from patches/st-scrollback-mouse-20161020-6e79e83.diff)41
-rw-r--r--patches/st-solarized-both-20160727-308bfbf.diff189
-rw-r--r--patches/transparency.diff189
-rwxr-xr-xrun-patches.sh8
-rwxr-xr-xst-remove.sh5
-rw-r--r--st.119
-rw-r--r--st.c2694
-rw-r--r--st.h140
-rw-r--r--st.info11
-rw-r--r--win.h42
-rw-r--r--x.c2020
24 files changed, 3243 insertions, 3225 deletions
diff --git a/FAQ b/FAQ
index 4defff9..921c493 100644
--- a/FAQ
+++ b/FAQ
@@ -6,7 +6,7 @@ Use the excellent tool of [utmp](http://git.suckless.org/utmp/) for this task.
It means that st doesn’t have any terminfo entry on your system. Chances are
you did not `make install`. If you just want to test it without installing it,
-you can manualy run `tic -sx st.info`.
+you can manually run `tic -sx st.info`.
## Nothing works, and nothing is said about an unknown terminal!
diff --git a/LICENSE b/LICENSE
index fa0c63e..c356c39 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,13 +1,16 @@
MIT/X Consortium License
+© 2014-2018 Hiltjo Posthuma <hiltjo at codemadness dot org>
+© 2018 Devin J. Pohly <djpohly at gmail dot com>
+© 2014-2017 Quentin Rameau <quinq at fifth dot space>
© 2009-2012 Aurélien APTEL <aurelien dot aptel at gmail dot com>
-© 2009 Anselm R Garbe <garbeam at gmail dot com>
-© 2012-2016 Roberto E. Vargas Caballero <k0ga at shike2 dot com>
+© 2008-2017 Anselm R Garbe <garbeam at gmail dot com>
+© 2012-2017 Roberto E. Vargas Caballero <k0ga at shike2 dot com>
© 2012-2016 Christoph Lohmann <20h at r-36 dot net>
© 2013 Eon S. Jeon <esjeon at hyunmu dot am>
© 2013 Alexander Sedov <alex0player at gmail dot com>
© 2013 Mark Edgar <medgar123 at gmail dot com>
-© 2013 Eric Pruitt <eric.pruitt at gmail dot com>
+© 2013-2014 Eric Pruitt <eric.pruitt at gmail dot com>
© 2013 Michael Forney <mforney at mforney dot org>
© 2013-2014 Markus Teich <markus dot teich at stusta dot mhn dot de>
© 2014-2015 Laslo Hunhold <dev at frign dot de>
diff --git a/Makefile b/Makefile
index aa93c0d..0b3cecd 100644
--- a/Makefile
+++ b/Makefile
@@ -1,60 +1,57 @@
# st - simple terminal
# See LICENSE file for copyright and license details.
+.POSIX:
include config.mk
-SRC = st.c
-OBJ = ${SRC:.c=.o}
+SRC = st.c x.c
+OBJ = $(SRC:.c=.o)
all: options st
options:
@echo st build options:
- @echo "CFLAGS = ${CFLAGS}"
- @echo "LDFLAGS = ${LDFLAGS}"
- @echo "CC = ${CC}"
+ @echo "CFLAGS = $(STCFLAGS)"
+ @echo "LDFLAGS = $(STLDFLAGS)"
+ @echo "CC = $(CC)"
config.h:
cp config.def.h config.h
.c.o:
- @echo CC $<
- @${CC} -c ${CFLAGS} $<
+ $(CC) $(STCFLAGS) -c $<
-${OBJ}: config.h config.mk
+st.o: config.h st.h win.h
+x.o: arg.h st.h win.h
-st: ${OBJ}
- @echo CC -o $@
- @${CC} -o $@ ${OBJ} ${LDFLAGS}
+$(OBJ): config.h config.mk
+
+st: $(OBJ)
+ $(CC) -o $@ $(OBJ) $(STLDFLAGS)
clean:
- @echo cleaning
- @rm -f config.h st ${OBJ} st-${VERSION}.tar.gz
+ rm -f st $(OBJ) st-$(VERSION).tar.gz
dist: clean
- @echo creating dist tarball
- @mkdir -p st-${VERSION}
- @cp -R LICENSE Makefile README config.mk config.def.h st.info st.1 arg.h ${SRC} st-${VERSION}
- @tar -cf st-${VERSION}.tar st-${VERSION}
- @gzip st-${VERSION}.tar
- @rm -rf st-${VERSION}
-
-install: all
- @echo installing executable file to ${DESTDIR}${PREFIX}/bin
- @mkdir -p ${DESTDIR}${PREFIX}/bin
- @cp -f st ${DESTDIR}${PREFIX}/bin
- @chmod 755 ${DESTDIR}${PREFIX}/bin/st
- @echo installing manual page to ${DESTDIR}${MANPREFIX}/man1
- @mkdir -p ${DESTDIR}${MANPREFIX}/man1
- @sed "s/VERSION/${VERSION}/g" < st.1 > ${DESTDIR}${MANPREFIX}/man1/st.1
- @chmod 644 ${DESTDIR}${MANPREFIX}/man1/st.1
+ 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)\
+ st-$(VERSION)
+ tar -cf - st-$(VERSION) | gzip > st-$(VERSION).tar.gz
+ rm -rf st-$(VERSION)
+
+install: st
+ mkdir -p $(DESTDIR)$(PREFIX)/bin
+ cp -f st $(DESTDIR)$(PREFIX)/bin
+ chmod 755 $(DESTDIR)$(PREFIX)/bin/st
+ 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
@echo Please see the README file regarding the terminfo entry of st.
- @tic -sx st.info
uninstall:
- @echo removing executable file from ${DESTDIR}${PREFIX}/bin
- @rm -f ${DESTDIR}${PREFIX}/bin/st
- @echo removing manual page from ${DESTDIR}${MANPREFIX}/man1
- @rm -f ${DESTDIR}${MANPREFIX}/man1/st.1
+ rm -f $(DESTDIR)$(PREFIX)/bin/st
+ rm -f $(DESTDIR)$(MANPREFIX)/man1/st.1
.PHONY: all options clean dist install uninstall
diff --git a/README.md b/README.md
index 3786738..9ad7a8a 100644
--- a/README.md
+++ b/README.md
@@ -4,18 +4,18 @@ Forked from [https://github.com/shiva/st](https://github.com/shiva/st) for simpl
+ transparency
+ copy to clipboard
-+ solarized colors (light and dark toggleable)
++ ~~Solarized colors (light and dark toggleable)~~ (Change to your own colors, see no value of toggle)
+ vertcenter
+ scrollback with keyboard
+ scrollback with mouse
++ updated to latest version 0.8.1
## My own additions
+ Default font is system "mono" at 14pt
-+ Fixed transparency patch (see below for installation)
-+ Toggle light/dark mode now Alt-Tab instead of the frequently conflicting F6
+ Alt-k and Alt-j scroll back/foward in history one line at a time
+ Alt-u and Alt-d scroll back/foward in history a page at a time
++ Applied colors, insipred by Pop! OS colors.
## Terminal-specific mappings
@@ -28,20 +28,23 @@ Forked from [https://github.com/shiva/st](https://github.com/shiva/st) for simpl
## Installation for newbs
-```
-make
-sudo make install
-```
+## Requirements for build
-### Solarized mode
+Install `base-devel` - compiler and stuff (most distros have).
+
+Install code depndencies (voidlinux - most distro should have something similar)
+
++ `fontconfig-devel`
++ `libX11-devel`
++ `libXft-devel`
-The terminal is now transparent by default, if you want non-transparent solarized colors, run the following:
```
-make clean
-patch -R < patches/transparency.diff
make
sudo make install
```
-You can change the transparency value by changing the `alpha` variable in the `config.h` file.
+## Custom changes (`config.def.h` or `config.h`)
+
++ change `alpha`
++ chnage colors in `colorname` added comments with numbers `0`-`15` colors and also `bg`, `fg` and `cursor` color.
diff --git a/arg.h b/arg.h
index ba3fb3f..a22e019 100644
--- a/arg.h
+++ b/arg.h
@@ -21,28 +21,30 @@ extern char *argv0;
argc--;\
break;\
}\
- for (brk_ = 0, argv[0]++, argv_ = argv;\
- argv[0][0] && !brk_;\
- argv[0]++) {\
+ int i_;\
+ for (i_ = 1, brk_ = 0, argv_ = argv;\
+ argv[0][i_] && !brk_;\
+ i_++) {\
if (argv_ != argv)\
break;\
- argc_ = argv[0][0];\
+ argc_ = argv[0][i_];\
switch (argc_)
+
#define ARGEND }\
}
#define ARGC() argc_
-#define EARGF(x) ((argv[0][1] == '\0' && argv[1] == NULL)?\
+#define EARGF(x) ((argv[0][i_+1] == '\0' && argv[1] == NULL)?\
((x), abort(), (char *)0) :\
- (brk_ = 1, (argv[0][1] != '\0')?\
- (&argv[0][1]) :\
+ (brk_ = 1, (argv[0][i_+1] != '\0')?\
+ (&argv[0][i_+1]) :\
(argc--, argv++, argv[0])))
-#define ARGF() ((argv[0][1] == '\0' && argv[1] == NULL)?\
+#define ARGF() ((argv[0][i_+1] == '\0' && argv[1] == NULL)?\
(char *)0 :\
- (brk_ = 1, (argv[0][1] != '\0')?\
- (&argv[0][1]) :\
+ (brk_ = 1, (argv[0][i_+1] != '\0')?\
+ (&argv[0][i_+1]) :\
(argc--, argv++, argv[0])))
#endif
diff --git a/config.def.h b/config.def.h
index 8e10abd..e373018 100644
--- a/config.def.h
+++ b/config.def.h
@@ -5,7 +5,7 @@
*
* font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
*/
-static char font[] = "mono:pixelsize=14:antialias=true:autohint=true";
+static char *font = "Liberation Mono:pixelsize=12:antialias=true:autohint=true";
static int borderpx = 2;
/*
@@ -16,12 +16,12 @@ static int borderpx = 2;
* 4: value of shell in /etc/passwd
* 5: value of shell in config.h
*/
-static char shell[] = "/bin/sh";
-static char *utmp = NULL;
-static char stty_args[] = "stty raw pass8 nl -echo -iexten -cstopb 38400";
+static char *shell = "/bin/sh";
+char *utmp = NULL;
+char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400";
/* identification sequence returned in DA and DECID */
-static char vtiden[] = "\033[?6c";
+char *vtiden = "\033[?6c";
/* Kerning / character bounding-box multipliers */
static float cwscale = 1.0;
@@ -32,14 +32,14 @@ static float chscale = 1.0;
*
* More advanced example: " `'\"()[]{}"
*/
-static char worddelimiters[] = " ";
+char *worddelimiters = " ";
/* selection timeouts (in milliseconds) */
static unsigned int doubleclicktimeout = 300;
static unsigned int tripleclicktimeout = 600;
/* alt screens */
-static int allowaltscreen = 1;
+int allowaltscreen = 1;
/* frames per second st should at maximum draw to the screen */
static unsigned int xfps = 120;
@@ -63,7 +63,7 @@ static unsigned int cursorthickness = 2;
static int bellvolume = 0;
/* default TERM value */
-static char termname[] = "st-256color";
+char *termname = "st-256color";
/*
* spaces per tab
@@ -80,63 +80,49 @@ static char termname[] = "st-256color";
*
* stty tabs
*/
-static unsigned int tabspaces = 8;
+unsigned int tabspaces = 8;
/* bg opacity */
-static const int alpha = 0xdd;
+unsigned int alpha = 0xcd;
/* Terminal colors (16 first used in escape sequence) */
static const char *colorname[] = {
- /* solarized dark */
- "#073642", /* 0: black */
- "#dc322f", /* 1: red */
- "#859900", /* 2: green */
- "#b58900", /* 3: yellow */
- "#268bd2", /* 4: blue */
- "#d33682", /* 5: magenta */
- "#2aa198", /* 6: cyan */
- "#eee8d5", /* 7: white */
- "#002b36", /* 8: brblack */
- "#cb4b16", /* 9: brred */
- "#586e75", /* 10: brgreen */
- "#657b83", /* 11: bryellow */
- "#839496", /* 12: brblue */
- "#6c71c4", /* 13: brmagenta*/
- "#93a1a1", /* 14: brcyan */
- "#fdf6e3", /* 15: brwhite */
+ /* 8 normal colors */
"black",
+ "red3",
+ "green3",
+ "yellow3",
+ "blue2",
+ "magenta3",
+ "cyan3",
+ "gray90",
+
+ /* 8 bright colors */
+ "gray50",
+ "red",
+ "green",
+ "yellow",
+ "#5c5cff",
+ "magenta",
+ "cyan",
+ "white",
+
+ [255] = 0,
+
+ /* more colors can be added after 255 to use with DefaultXX */
+ "#cccccc",
+ "#555555",
};
-/* Terminal colors for alternate (light) palette */
-static const char *altcolorname[] = {
- /* solarized light */
- "#eee8d5", /* 0: black */
- "#dc322f", /* 1: red */
- "#859900", /* 2: green */
- "#b58900", /* 3: yellow */
- "#268bd2", /* 4: blue */
- "#d33682", /* 5: magenta */
- "#2aa198", /* 6: cyan */
- "#073642", /* 7: white */
- "#fdf6e3", /* 8: brblack */
- "#cb4b16", /* 9: brred */
- "#93a1a1", /* 10: brgreen */
- "#839496", /* 11: bryellow */
- "#657b83", /* 12: brblue */
- "#6c71c4", /* 13: brmagenta*/
- "#586e75", /* 14: brcyan */
- "#002b36", /* 15: brwhite */
- "black",
-};
/*
* Default colors (colorname index)
* foreground, background, cursor, reverse cursor
*/
-static unsigned int defaultfg = 12;
-static unsigned int defaultbg = 257;
-static unsigned int defaultcs = 14;
-static unsigned int defaultrcs = 15;
+unsigned int defaultfg = 7;
+unsigned int defaultbg = 0;
+static unsigned int defaultcs = 256;
+static unsigned int defaultrcs = 257;
/*
* Default shape of cursor
@@ -177,7 +163,7 @@ static MouseShortcut mshortcuts[] = {
{ Button5, XK_NO_MOD, "\005" },
};
-static MouseKey mkeys[] = {
+MouseKey mkeys[] = {
/* button mask function argument */
{ Button4, ShiftMask, kscrollup, {.i = 1} },
{ Button5, ShiftMask, kscrolldown, {.i = 1} },
@@ -185,6 +171,7 @@ static MouseKey mkeys[] = {
/* Internal keyboard shortcuts. */
#define MODKEY Mod1Mask
+#define TERMMOD (ControlMask|ShiftMask)
static Shortcut shortcuts[] = {
/* mask keysym function argument */
@@ -192,22 +179,16 @@ static Shortcut shortcuts[] = {
{ ControlMask, XK_Print, toggleprinter, {.i = 0} },
{ ShiftMask, XK_Print, printscreen, {.i = 0} },
{ XK_ANY_MOD, XK_Print, printsel, {.i = 0} },
- { MODKEY|ShiftMask, XK_Prior, xzoom, {.f = +1} },
- { MODKEY|ShiftMask, XK_Next, xzoom, {.f = -1} },
- { MODKEY|ShiftMask, XK_Home, xzoomreset, {.f = 0} },
- { ShiftMask, XK_Insert, selpaste, {.i = 0} },
- { MODKEY|ShiftMask, XK_Insert, clippaste, {.i = 0} },
- { MODKEY|ShiftMask, XK_C, clipcopy, {.i = 0} },
- { MODKEY|ShiftMask, XK_V, clippaste, {.i = 0} },
- { MODKEY, XK_Num_Lock, numlock, {.i = 0} },
- { MODKEY, XK_Control_L, iso14755, {.i = 0} },
- { MODKEY, XK_Tab, swapcolors, {.i = 0} },
+ { TERMMOD, XK_Prior, zoom, {.f = +1} },
+ { TERMMOD, XK_Next, zoom, {.f = -1} },
+ { TERMMOD, XK_Home, zoomreset, {.f = 0} },
+ { TERMMOD, XK_C, clipcopy, {.i = 0} },
+ { TERMMOD, XK_V, clippaste, {.i = 0} },
+ { TERMMOD, XK_Y, selpaste, {.i = 0} },
+ { TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
+ { TERMMOD, XK_I, iso14755, {.i = 0} },
{ ShiftMask, XK_Page_Up, kscrollup, {.i = -1} },
{ ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} },
- { MODKEY, XK_k, kscrollup, {.i = 1} },
- { MODKEY, XK_j, kscrolldown, {.i = 1} },
- { MODKEY, XK_u, kscrollup, {.i = -1} },
- { MODKEY, XK_d, kscrolldown, {.i = -1} },
};
/*
@@ -259,219 +240,216 @@ static uint forceselmod = ShiftMask;
* world. Please decide about changes wisely.
*/
static Key key[] = {
- /* keysym mask string appkey appcursor crlf */
- { XK_KP_Home, ShiftMask, "\033[2J", 0, -1, 0},
- { XK_KP_Home, ShiftMask, "\033[1;2H", 0, +1, 0},
- { XK_KP_Home, XK_ANY_MOD, "\033[H", 0, -1, 0},
- { XK_KP_Home, XK_ANY_MOD, "\033[1~", 0, +1, 0},
- { XK_KP_Up, XK_ANY_MOD, "\033Ox", +1, 0, 0},
- { XK_KP_Up, XK_ANY_MOD, "\033[A", 0, -1, 0},
- { XK_KP_Up, XK_ANY_MOD, "\033OA", 0, +1, 0},
- { XK_KP_Down, XK_ANY_MOD, "\033Or", +1, 0, 0},
- { XK_KP_Down, XK_ANY_MOD, "\033[B", 0, -1, 0},
- { XK_KP_Down, XK_ANY_MOD, "\033OB", 0, +1, 0},
- { XK_KP_Left, XK_ANY_MOD, "\033Ot", +1, 0, 0},
- { XK_KP_Left, XK_ANY_MOD, "\033[D", 0, -1, 0},
- { XK_KP_Left, XK_ANY_MOD, "\033OD", 0, +1, 0},
- { XK_KP_Right, XK_ANY_MOD, "\033Ov", +1, 0, 0},
- { XK_KP_Right, XK_ANY_MOD, "\033[C", 0, -1, 0},
- { XK_KP_Right, XK_ANY_MOD, "\033OC", 0, +1, 0},
- { XK_KP_Prior, ShiftMask, "\033[5;2~", 0, 0, 0},
- { XK_KP_Prior, XK_ANY_MOD, "\033[5~", 0, 0, 0},
- { XK_KP_Begin, XK_ANY_MOD, "\033[E", 0, 0, 0},
- { XK_KP_End, ControlMask, "\033[J", -1, 0, 0},
- { XK_KP_End, ControlMask, "\033[1;5F", +1, 0, 0},
- { XK_KP_End, ShiftMask, "\033[K", -1, 0, 0},
- { XK_KP_End, ShiftMask, "\033[1;2F", +1, 0, 0},
- { XK_KP_End, XK_ANY_MOD, "\033[4~", 0, 0, 0},
- { XK_KP_Next, ShiftMask, "\033[6;2~", 0, 0, 0},
- { XK_KP_Next, XK_ANY_MOD, "\033[6~", 0, 0, 0},
- { XK_KP_Insert, ShiftMask, "\033[2;2~", +1, 0, 0},
- { XK_KP_Insert, ShiftMask, "\033[4l", -1, 0, 0},
- { XK_KP_Insert, ControlMask, "\033[L", -1, 0, 0},
- { XK_KP_Insert, ControlMask, "\033[2;5~", +1, 0, 0},
- { XK_KP_Insert, XK_ANY_MOD, "\033[4h", -1, 0, 0},
- { XK_KP_Insert, XK_ANY_MOD, "\033[2~", +1, 0, 0},
- { XK_KP_Delete, ControlMask, "\033[M", -1, 0, 0},
- { XK_KP_Delete, ControlMask, "\033[3;5~", +1, 0, 0},
- { XK_KP_Delete, ShiftMask, "\033[2K", -1, 0, 0},
- { XK_KP_Delete, ShiftMask, "\033[3;2~", +1, 0, 0},
- { XK_KP_Delete, XK_ANY_MOD, "\033[P", -1, 0, 0},
- { XK_KP_Delete, XK_ANY_MOD, "\033[3~", +1, 0, 0},
- { XK_KP_Multiply, XK_ANY_MOD, "\033Oj", +2, 0, 0},
- { XK_KP_Add, XK_ANY_MOD, "\033Ok", +2, 0, 0},
- { XK_KP_Enter, XK_ANY_MOD, "\033OM", +2, 0, 0},
- { XK_KP_Enter, XK_ANY_MOD, "\r", -1, 0, -1},
- { XK_KP_Enter, XK_ANY_MOD, "\r\n", -1, 0, +1},
- { XK_KP_Subtract, XK_ANY_MOD, "\033Om", +2, 0, 0},
- { XK_KP_Decimal, XK_ANY_MOD, "\033On", +2, 0, 0},
- { XK_KP_Divide, XK_ANY_MOD, "\033Oo", +2, 0, 0},
- { XK_KP_0, XK_ANY_MOD, "\033Op", +2, 0, 0},
- { XK_KP_1, XK_ANY_MOD, "\033Oq", +2, 0, 0},
- { XK_KP_2, XK_ANY_MOD, "\033Or", +2, 0, 0},
- { XK_KP_3, XK_ANY_MOD, "\033Os", +2, 0, 0},
- { XK_KP_4, XK_ANY_MOD, "\033Ot", +2, 0, 0},
- { XK_KP_5, XK_ANY_MOD, "\033Ou", +2, 0, 0},
- { XK_KP_6, XK_ANY_MOD, "\033Ov", +2, 0, 0},
- { XK_KP_7, XK_ANY_MOD, "\033Ow", +2, 0, 0},
- { XK_KP_8, XK_ANY_MOD, "\033Ox", +2, 0, 0},
- { XK_KP_9, XK_ANY_MOD, "\033Oy", +2, 0, 0},
- { XK_Up, ShiftMask, "\033[1;2A", 0, 0, 0},
- { XK_Up, Mod1Mask, "\033[1;3A", 0, 0, 0},
- { XK_Up, ShiftMask|Mod1Mask,"\033[1;4A", 0, 0, 0},
- { XK_Up, ControlMask, "\033[1;5A", 0, 0, 0},
- { XK_Up, ShiftMask|ControlMask,"\033[1;6A", 0, 0, 0},
- { XK_Up, ControlMask|Mod1Mask,"\033[1;7A", 0, 0, 0},
- { XK_Up,ShiftMask|ControlMask|Mod1Mask,"\033[1;8A", 0, 0, 0},
- { XK_Up, XK_ANY_MOD, "\033[A", 0, -1, 0},
- { XK_Up, XK_ANY_MOD, "\033OA", 0, +1, 0},
- { XK_Down, ShiftMask, "\033[1;2B", 0, 0, 0},
- { XK_Down, Mod1Mask, "\033[1;3B", 0, 0, 0},
- { XK_Down, ShiftMask|Mod1Mask,"\033[1;4B", 0, 0, 0},
- { XK_Down, ControlMask, "\033[1;5B", 0, 0, 0},
- { XK_Down, ShiftMask|ControlMask,"\033[1;6B", 0, 0, 0},
- { XK_Down, ControlMask|Mod1Mask,"\033[1;7B", 0, 0, 0},
- { XK_Down,ShiftMask|ControlMask|Mod1Mask,"\033[1;8B",0, 0, 0},
- { XK_Down, XK_ANY_MOD, "\033[B", 0, -1, 0},
- { XK_Down, XK_ANY_MOD, "\033OB", 0, +1, 0},
- { XK_Left, ShiftMask, "\033[1;2D", 0, 0, 0},
- { XK_Left, Mod1Mask, "\033[1;3D", 0, 0, 0},
- { XK_Left, ShiftMask|Mod1Mask,"\033[1;4D", 0, 0, 0},
- { XK_Left, ControlMask, "\033[1;5D", 0, 0, 0},
- { XK_Left, ShiftMask|ControlMask,"\033[1;6D", 0, 0, 0},
- { XK_Left, ControlMask|Mod1Mask,"\033[1;7D", 0, 0, 0},
- { XK_Left,ShiftMask|ControlMask|Mod1Mask,"\033[1;8D",0, 0, 0},
- { XK_Left, XK_ANY_MOD, "\033[D", 0, -1, 0},
- { XK_Left, XK_ANY_MOD, "\033OD", 0, +1, 0},
- { XK_Right, ShiftMask, "\033[1;2C", 0, 0, 0},
- { XK_Right, Mod1Mask, "\033[1;3C", 0, 0, 0},
- { XK_Right, ShiftMask|Mod1Mask,"\033[1;4C", 0, 0, 0},
- { XK_Right, ControlMask, "\033[1;5C", 0, 0, 0},
- { XK_Right, ShiftMask|ControlMask,"\033[1;6C", 0, 0, 0},
- { XK_Right, ControlMask|Mod1Mask,"\033[1;7C", 0, 0, 0},
- { XK_Right,ShiftMask|ControlMask|Mod1Mask,"\033[1;8C",0, 0, 0},
- { XK_Right, XK_ANY_MOD, "\033[C", 0, -1, 0},
- { XK_Right, XK_ANY_MOD, "\033OC", 0, +1, 0},
- { XK_ISO_Left_Tab, ShiftMask, "\033[Z", 0, 0, 0},
- { XK_Return, Mod1Mask, "\033\r", 0, 0, -1},
- { XK_Return, Mod1Mask, "\033\r\n", 0, 0, +1},
- { XK_Return, XK_ANY_MOD, "\r", 0, 0, -1},
- { XK_Return, XK_ANY_MOD, "\r\n", 0, 0, +1},
- { XK_Insert, ShiftMask, "\033[4l", -1, 0, 0},
- { XK_Insert, ShiftMask, "\033[2;2~", +1, 0, 0},
- { XK_Insert, ControlMask, "\033[L", -1, 0, 0},
- { XK_Insert, ControlMask, "\033[2;5~", +1, 0, 0},
- { XK_Insert, XK_ANY_MOD, "\033[4h", -1, 0, 0},
- { XK_Insert, XK_ANY_MOD, "\033[2~", +1, 0, 0},
- { XK_Delete, ControlMask, "\033[M", -1, 0, 0},
- { XK_Delete, ControlMask, "\033[3;5~", +1, 0, 0},
- { XK_Delete, ShiftMask, "\033[2K", -1, 0, 0},
- { XK_Delete, ShiftMask, "\033[3;2~", +1, 0, 0},
- { XK_Delete, XK_ANY_MOD, "\033[P", -1, 0, 0},
- { XK_Delete, XK_ANY_MOD, "\033[3~", +1, 0, 0},
- { XK_BackSpace, XK_NO_MOD, "\177", 0, 0, 0},
- { XK_BackSpace, Mod1Mask, "\033\177", 0, 0, 0},
- { XK_Home, ShiftMask, "\033[2J", 0, -1, 0},
- { XK_Home, ShiftMask, "\033[1;2H", 0, +1, 0},
- { XK_Home, XK_ANY_MOD, "\033[H", 0, -1, 0},
- { XK_Home, XK_ANY_MOD, "\033[1~", 0, +1, 0},
- { XK_End, ControlMask, "\033[J", -1, 0, 0},
- { XK_End, ControlMask, "\033[1;5F", +1, 0, 0},
- { XK_End, ShiftMask, "\033[K", -1, 0, 0},
- { XK_End, ShiftMask, "\033[1;2F", +1, 0, 0},
- { XK_End, XK_ANY_MOD, "\033[4~", 0, 0, 0},
- { XK_Prior, ControlMask, "\033[5;5~", 0, 0, 0},
- { XK_Prior, ShiftMask, "\033[5;2~", 0, 0, 0},
- { XK_Prior, XK_ANY_MOD, "\033[5~", 0, 0, 0},
- { XK_Next, ControlMask, "\033[6;5~", 0, 0, 0},
- { XK_Next, ShiftMask, "\033[6;2~", 0, 0, 0},
- { XK_Next, XK_ANY_MOD, "\033[6~", 0, 0, 0},
- { XK_F1, XK_NO_MOD, "\033OP" , 0, 0, 0},
- { XK_F1, /* F13 */ ShiftMask, "\033[1;2P", 0, 0, 0},
- { XK_F1, /* F25 */ ControlMask, "\033[1;5P", 0, 0, 0},
- { XK_F1, /* F37 */ Mod4Mask, "\033[1;6P", 0, 0, 0},
- { XK_F1, /* F49 */ Mod1Mask, "\033[1;3P", 0, 0, 0},
- { XK_F1, /* F61 */ Mod3Mask, "\033[1;4P", 0, 0, 0},
- { XK_F2, XK_NO_MOD, "\033OQ" , 0, 0, 0},
- { XK_F2, /* F14 */ ShiftMask, "\033[1;2Q", 0, 0, 0},
- { XK_F2, /* F26 */ ControlMask, "\033[1;5Q", 0, 0, 0},
- { XK_F2, /* F38 */ Mod4Mask, "\033[1;6Q", 0, 0, 0},
- { XK_F2, /* F50 */ Mod1Mask, "\033[1;3Q", 0, 0, 0},
- { XK_F2, /* F62 */ Mod3Mask, "\033[1;4Q", 0, 0, 0},
- { XK_F3, XK_NO_MOD, "\033OR" , 0, 0, 0},
- { XK_F3, /* F15 */ ShiftMask, "\033[1;2R", 0, 0, 0},
- { XK_F3, /* F27 */ ControlMask, "\033[1;5R", 0, 0, 0},
- { XK_F3, /* F39 */ Mod4Mask, "\033[1;6R", 0, 0, 0},
- { XK_F3, /* F51 */ Mod1Mask, "\033[1;3R", 0, 0, 0},
- { XK_F3, /* F63 */ Mod3Mask, "\033[1;4R", 0, 0, 0},
- { XK_F4, XK_NO_MOD, "\033OS" , 0, 0, 0},
- { XK_F4, /* F16 */ ShiftMask, "\033[1;2S", 0, 0, 0},
- { XK_F4, /* F28 */ ControlMask, "\033[1;5S", 0, 0, 0},
- { XK_F4, /* F40 */ Mod4Mask, "\033[1;6S", 0, 0, 0},
- { XK_F4, /* F52 */ Mod1Mask, "\033[1;3S", 0, 0, 0},
- { XK_F5, XK_NO_MOD, "\033[15~", 0, 0, 0},
- { XK_F5, /* F17 */ ShiftMask, "\033[15;2~", 0, 0, 0},
- { XK_F5, /* F29 */ ControlMask, "\033[15;5~", 0, 0, 0},
- { XK_F5, /* F41 */ Mod4Mask, "\033[15;6~", 0, 0, 0},
- { XK_F5, /* F53 */ Mod1Mask, "\033[15;3~", 0, 0, 0},
- { XK_F6, XK_NO_MOD, "\033[17~", 0, 0, 0},
- { XK_F6, /* F18 */ ShiftMask, "\033[17;2~", 0, 0, 0},
- { XK_F6, /* F30 */ ControlMask, "\033[17;5~", 0, 0, 0},
- { XK_F6, /* F42 */ Mod4Mask, "\033[17;6~", 0, 0, 0},
- { XK_F6, /* F54 */ Mod1Mask, "\033[17;3~", 0, 0, 0},
- { XK_F7, XK_NO_MOD, "\033[18~", 0, 0, 0},
- { XK_F7, /* F19 */ ShiftMask, "\033[18;2~", 0, 0, 0},
- { XK_F7, /* F31 */ ControlMask, "\033[18;5~", 0, 0, 0},
- { XK_F7, /* F43 */ Mod4Mask, "\033[18;6~", 0, 0, 0},
- { XK_F7, /* F55 */ Mod1Mask, "\033[18;3~", 0, 0, 0},
- { XK_F8, XK_NO_MOD, "\033[19~", 0, 0, 0},
- { XK_F8, /* F20 */ ShiftMask, "\033[19;2~", 0, 0, 0},
- { XK_F8, /* F32 */ ControlMask, "\033[19;5~", 0, 0, 0},
- { XK_F8, /* F44 */ Mod4Mask, "\033[19;6~", 0, 0, 0},
- { XK_F8, /* F56 */ Mod1Mask, "\033[19;3~", 0, 0, 0},
- { XK_F9, XK_NO_MOD, "\033[20~", 0, 0, 0},
- { XK_F9, /* F21 */ ShiftMask, "\033[20;2~", 0, 0, 0},
- { XK_F9, /* F33 */ ControlMask, "\033[20;5~", 0, 0, 0},
- { XK_F9, /* F45 */ Mod4Mask, "\033[20;6~", 0, 0, 0},
- { XK_F9, /* F57 */ Mod1Mask, "\033[20;3~", 0, 0, 0},
- { XK_F10, XK_NO_MOD, "\033[21~", 0, 0, 0},
- { XK_F10, /* F22 */ ShiftMask, "\033[21;2~", 0, 0, 0},
- { XK_F10, /* F34 */ ControlMask, "\033[21;5~", 0, 0, 0},
- { XK_F10, /* F46 */ Mod4Mask, "\033[21;6~", 0, 0, 0},
- { XK_F10, /* F58 */ Mod1Mask, "\033[21;3~", 0, 0, 0},
- { XK_F11, XK_NO_MOD, "\033[23~", 0, 0, 0},
- { XK_F11, /* F23 */ ShiftMask, "\033[23;2~", 0, 0, 0},
- { XK_F11, /* F35 */ ControlMask, "\033[23;5~", 0, 0, 0},
- { XK_F11, /* F47 */ Mod4Mask, "\033[23;6~", 0, 0, 0},
- { XK_F11, /* F59 */ Mod1Mask, "\033[23;3~", 0, 0, 0},
- { XK_F12, XK_NO_MOD, "\033[24~", 0, 0, 0},
- { XK_F12, /* F24 */ ShiftMask, "\033[24;2~", 0, 0, 0},
- { XK_F12, /* F36 */ ControlMask, "\033[24;5~", 0, 0, 0},
- { XK_F12, /* F48 */ Mod4Mask, "\033[24;6~", 0, 0, 0},
- { XK_F12, /* F60 */ Mod1Mask, "\033[24;3~", 0, 0, 0},
- { XK_F13, XK_NO_MOD, "\033[1;2P", 0, 0, 0},
- { XK_F14, XK_NO_MOD, "\033[1;2Q", 0, 0, 0},
- { XK_F15, XK_NO_MOD, "\033[1;2R", 0, 0, 0},
- { XK_F16, XK_NO_MOD, "\033[1;2S", 0, 0, 0},
- { XK_F17, XK_NO_MOD, "\033[15;2~", 0, 0, 0},
- { XK_F18, XK_NO_MOD, "\033[17;2~", 0, 0, 0},
- { XK_F19, XK_NO_MOD, "\033[18;2~", 0, 0, 0},
- { XK_F20, XK_NO_MOD, "\033[19;2~", 0, 0, 0},
- { XK_F21, XK_NO_MOD, "\033[20;2~", 0, 0, 0},
- { XK_F22, XK_NO_MOD, "\033[21;2~", 0, 0, 0},
- { XK_F23, XK_NO_MOD, "\033[23;2~", 0, 0, 0},
- { XK_F24, XK_NO_MOD, "\033[24;2~", 0, 0, 0},
- { XK_F25, XK_NO_MOD, "\033[1;5P", 0, 0, 0},
- { XK_F26, XK_NO_MOD, "\033[1;5Q", 0, 0, 0},
- { XK_F27, XK_NO_MOD, "\033[1;5R", 0, 0, 0},
- { XK_F28, XK_NO_MOD, "\033[1;5S", 0, 0, 0},
- { XK_F29, XK_NO_MOD, "\033[15;5~", 0, 0, 0},
- { XK_F30, XK_NO_MOD, "\033[17;5~", 0, 0, 0},
- { XK_F31, XK_NO_MOD, "\033[18;5~", 0, 0, 0},
- { XK_F32, XK_NO_MOD, "\033[19;5~", 0, 0, 0},
- { XK_F33, XK_NO_MOD, "\033[20;5~", 0, 0, 0},
- { XK_F34, XK_NO_MOD, "\033[21;5~", 0, 0, 0},
- { XK_F35, XK_NO_MOD, "\033[23;5~", 0, 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},
+ { XK_KP_Delete, XK_ANY_MOD, "\033[P", -1, 0},
+ { XK_KP_Delete, XK_ANY_MOD, "\033[3~", +1, 0},
+ { XK_KP_Multiply, XK_ANY_MOD, "\033Oj", +2, 0},
+ { XK_KP_Add, XK_ANY_MOD, "\033Ok", +2, 0},
+ { 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[P", -1, 0},
+ { XK_Delete, XK_ANY_MOD, "\033[3~", +1, 0},
+ { XK_BackSpace, XK_NO_MOD, "\177", 0, 0},
+ { XK_BackSpace, Mod1Mask, "\033\177", 0, 0},
+ { 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},
};
/*
@@ -493,4 +471,3 @@ static char ascii_printable[] =
" !\"#$%&'()*+,-./0123456789:;<=>?"
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
"`abcdefghijklmnopqrstuvwxyz{|}~";
-
diff --git a/config.mk b/config.mk
index 19a03bb..3b00d7e 100644
--- a/config.mk
+++ b/config.mk
@@ -1,28 +1,28 @@
# st version
-VERSION = 0.7
+VERSION = 0.8.1
# Customize below to fit your system
# paths
PREFIX = /usr/local
-MANPREFIX = ${PREFIX}/share/man
+MANPREFIX = $(PREFIX)/share/man
X11INC = /usr/X11R6/include
X11LIB = /usr/X11R6/lib
# includes and libs
-INCS = -I. -I/usr/include -I${X11INC} \
+INCS = -I$(X11INC) \
`pkg-config --cflags fontconfig` \
`pkg-config --cflags freetype2`
-LIBS = -L/usr/lib -lc -L${X11LIB} -lm -lrt -lX11 -lutil -lXext -lXft -lXrender\
- `pkg-config --libs fontconfig` \
+LIBS = -L${X11LIB} -lm -lrt -lX11 -lutil -lXft -lXrender \
+ `pkg-config --libs fontconfig` \
`pkg-config --libs freetype2`
# flags
-CPPFLAGS = -DVERSION=\"${VERSION}\" -D_XOPEN_SOURCE=600
-CFLAGS += -g -std=c99 -pedantic -Wall -Wvariadic-macros -Os ${INCS} ${CPPFLAGS}
-LDFLAGS += -g ${LIBS}
+CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600
+STCFLAGS = $(INCS) $(CPPFLAGS) $(CFLAGS)
+STLDFLAGS = $(LIBS) $(LDFLAGS)
# compiler and linker
-# CC = cc
+# CC = c99
diff --git a/patches/st-alpha-0.8.1.diff b/patches/st-alpha-0.8.1.diff
new file mode 100644
index 0000000..9dd26c3
--- /dev/null
+++ b/patches/st-alpha-0.8.1.diff
@@ -0,0 +1,183 @@
+diff --git a/config.def.h b/config.def.h
+index feec7e2..e373018 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -82,6 +82,9 @@ char *termname = "st-256color";
+ */
+ unsigned int tabspaces = 8;
+
++/* bg opacity */
++unsigned int alpha = 0xcd;
++
+ /* Terminal colors (16 first used in escape sequence) */
+ static const char *colorname[] = {
+ /* 8 normal colors */
+diff --git a/config.mk b/config.mk
+index 039c42c..3b00d7e 100644
+--- a/config.mk
++++ b/config.mk
+@@ -14,7 +14,7 @@ X11LIB = /usr/X11R6/lib
+ INCS = -I$(X11INC) \
+ `pkg-config --cflags fontconfig` \
+ `pkg-config --cflags freetype2`
+-LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft \
++LIBS = -L${X11LIB} -lm -lrt -lX11 -lutil -lXft -lXrender \
+ `pkg-config --libs fontconfig` \
+ `pkg-config --libs freetype2`
+
+diff --git a/st.h b/st.h
+index cdd25ae..850c5f0 100644
+--- a/st.h
++++ b/st.h
+@@ -134,6 +134,7 @@ extern char *worddelimiters;
+ extern int allowaltscreen;
+ extern char *termname;
+ extern unsigned int tabspaces;
++extern unsigned int alpha;
+ extern unsigned int defaultfg;
+ extern unsigned int defaultbg;
+ extern MouseKey mkeys[];
+diff --git a/win.h b/win.h
+index 31f327d..d277477 100644
+--- a/win.h
++++ b/win.h
+@@ -23,6 +23,10 @@ enum win_mode {
+ |MODE_MOUSEMANY,
+ };
+
++/* alpha */
++#define OPAQUE 0Xff
++#define USE_ARGB (alpha != OPAQUE && opt_embed == NULL)
++
+ void xbell(void);
+ void xclipcopy(void);
+ void xdrawcursor(int, int, Glyph, int, int, Glyph);
+diff --git a/x.c b/x.c
+index f4a6be7..840d2fa 100644
+--- a/x.c
++++ b/x.c
+@@ -99,6 +99,7 @@ typedef struct {
+ XSetWindowAttributes attrs;
+ int scr;
+ int isfixed; /* is fixed geometry? */
++ int depth; /* bit depth */
+ int l, t; /* left and top offset */
+ int gm; /* geometry mask */
+ } XWindow;
+@@ -698,7 +699,7 @@ xresize(int col, int row)
+
+ XFreePixmap(xw.dpy, xw.buf);
+ xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
+- DefaultDepth(xw.dpy, xw.scr));
++ xw.depth);
+ XftDrawChange(xw.draw, xw.buf);
+ xclear(0, 0, win.w, win.h);
+
+@@ -758,6 +759,13 @@ xloadcols(void)
+ else
+ die("Could not allocate color %d\n", i);
+ }
++
++ /* set alpha value of bg color */
++ if (USE_ARGB) {
++ dc.col[defaultbg].color.alpha = (0xffff * alpha) / OPAQUE;
++ dc.col[defaultbg].pixel &= 0x00111111;
++ dc.col[defaultbg].pixel |= alpha << 24;
++ }
+ loaded = 1;
+ }
+
+@@ -779,6 +787,17 @@ xsetcolorname(int x, const char *name)
+ return 0;
+ }
+
++void
++xtermclear(int col1, int row1, int col2, int row2)
++{
++ XftDrawRect(xw.draw,
++ &dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg],
++ borderpx + col1 * win.cw,
++ borderpx + row1 * win.ch,
++ (col2-col1+1) * win.cw,
++ (row2-row1+1) * win.ch);
++}
++
+ /*
+ * Absolute coordinates.
+ */
+@@ -1018,7 +1037,40 @@ xinit(int cols, int rows)
+ if (!(xw.dpy = XOpenDisplay(NULL)))
+ die("Can't open display\n");
+ xw.scr = XDefaultScreen(xw.dpy);
+- xw.vis = XDefaultVisual(xw.dpy, xw.scr);
++ xw.depth = (USE_ARGB) ? 32: XDefaultDepth(xw.dpy, xw.scr);
++ if (!USE_ARGB)
++ xw.vis = XDefaultVisual(xw.dpy, xw.scr);
++ else {
++ XVisualInfo *vis;
++ XRenderPictFormat *fmt;
++ int nvi;
++ int i;
++
++ XVisualInfo tpl = {
++ .screen = xw.scr,
++ .depth = 32,
++ .class = TrueColor
++ };
++
++ vis = XGetVisualInfo(xw.dpy,
++ VisualScreenMask | VisualDepthMask | VisualClassMask,
++ &tpl, &nvi);
++ xw.vis = NULL;
++ for (i = 0; i < nvi; i++) {
++ fmt = XRenderFindVisualFormat(xw.dpy, vis[i].visual);
++ if (fmt->type == PictTypeDirect && fmt->direct.alphaMask) {
++ xw.vis = vis[i].visual;
++ break;
++ }
++ }
++
++ XFree(vis);
++
++ if (!xw.vis) {
++ fprintf(stderr, "Couldn't find ARGB visual.\n");
++ exit(1);
++ }
++ }
+
+ /* font */
+ if (!FcInit())
+@@ -1028,7 +1080,11 @@ xinit(int cols, int rows)
+ xloadfonts(usedfont, 0);
+
+ /* colors */
+- xw.cmap = XDefaultColormap(xw.dpy, xw.scr);
++ if (!USE_ARGB)
++ xw.cmap = XDefaultColormap(xw.dpy, xw.scr);
++ else
++ xw.cmap = XCreateColormap(xw.dpy, XRootWindow(xw.dpy, xw.scr),
++ xw.vis, None);
+ xloadcols();
+
+ /* adjust fixed window geometry */
+@@ -1051,16 +1107,15 @@ xinit(int cols, int rows)
+ if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0))))
+ parent = XRootWindow(xw.dpy, xw.scr);
+ xw.win = XCreateWindow(xw.dpy, parent, xw.l, xw.t,
+- win.w, win.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput,
++ win.w, win.h, 0, xw.depth, InputOutput,
+ xw.vis, CWBackPixel | CWBorderPixel | CWBitGravity
+ | CWEventMask | CWColormap, &xw.attrs);
+
+ memset(&gcvalues, 0, sizeof(gcvalues));
+ gcvalues.graphics_exposures = False;
+- dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures,
+- &gcvalues);
+- xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
+- DefaultDepth(xw.dpy, xw.scr));
++ xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, xw.depth);
++ dc.gc = XCreateGC(xw.dpy, (USE_ARGB) ? xw.buf: parent,
++ GCGraphicsExposures, &gcvalues);
+ XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel);
+ XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h);
+
diff --git a/patches/st-clipboard-20160727-308bfbf.diff b/patches/st-clipboard-20160727-308bfbf.diff
deleted file mode 100644
index 4cbec85..0000000
--- a/patches/st-clipboard-20160727-308bfbf.diff
+++ /dev/null
@@ -1,13 +0,0 @@
-diff --git a/st.c b/st.c
-index 2594c65..ebdde9f 100644
---- a/st.c
-+++ b/st.c
-@@ -1263,6 +1263,8 @@ xsetsel(char *str, Time t)
- XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t);
- if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win)
- selclear(0);
-+
-+ clipcopy(NULL);
- }
-
- void
diff --git a/patches/st-clipboard-20180309-c5ba9c0.diff b/patches/st-clipboard-20180309-c5ba9c0.diff
new file mode 100644
index 0000000..4a14e2b
--- /dev/null
+++ b/patches/st-clipboard-20180309-c5ba9c0.diff
@@ -0,0 +1,13 @@
+diff --git a/x.c b/x.c
+index 13fa9f4..88fd341 100644
+--- a/x.c
++++ b/x.c
+@@ -624,6 +624,8 @@ setsel(char *str, Time t)
+ XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t);
+ if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win)
+ selclear();
++
++ xclipcopy();
+ }
+
+ void
diff --git a/patches/st-no_bold_colors-0.8.1.diff b/patches/st-no_bold_colors-0.8.1.diff
new file mode 100644
index 0000000..1bd4657
--- /dev/null
+++ b/patches/st-no_bold_colors-0.8.1.diff
@@ -0,0 +1,25 @@
+From e0a92b498278e42e33f8007fd7b622a05e5310eb Mon Sep 17 00:00:00 2001
+From: Linh Nguyen <linhvng.2212@gmail.com>
+Date: Wed, 28 Mar 2018 12:23:45 -0400
+Subject: [PATCH] port st-no_bold_colors patch to 0.8.1
+
+---
+ x.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/x.c b/x.c
+index c343ba2..42e7e9f 100644
+--- a/x.c
++++ b/x.c
+@@ -1295,7 +1295,7 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
+
+ /* 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];
++ fg = &dc.col[base.fg];
+
+ if (IS_SET(MODE_REVERSE)) {
+ if (fg == &dc.col[defaultfg]) {
+--
+2.16.3
+
diff --git a/patches/st-no_bold_colors-20160727-308bfbf.diff b/patches/st-no_bold_colors-20160727-308bfbf.diff
deleted file mode 100644
index c381703..0000000
--- a/patches/st-no_bold_colors-20160727-308bfbf.diff
+++ /dev/null
@@ -1,13 +0,0 @@
-diff --git a/st.c b/st.c
-index 2594c65..f6fe717 100644
---- a/st.c
-+++ b/st.c
-@@ -3719,7 +3719,7 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
-
- /* 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];
-+ fg = &dc.col[base.fg];
-
- if (IS_SET(MODE_REVERSE)) {
- if (fg == &dc.col[defaultfg]) {
diff --git a/patches/st-scrollback-20170104-c63a87c.diff b/patches/st-scrollback-0.8.diff
index 38d1ad6..a61601a 100644
--- a/patches/st-scrollback-20170104-c63a87c.diff
+++ b/patches/st-scrollback-0.8.diff
@@ -1,68 +1,42 @@
diff --git a/config.def.h b/config.def.h
-index a719e36..9b51988 100644
+index 82b1b09..27d42ca 100644
--- a/config.def.h
+++ b/config.def.h
-@@ -178,6 +178,8 @@ static Shortcut shortcuts[] = {
- { MODKEY|ShiftMask, XK_V, clippaste, {.i = 0} },
- { MODKEY, XK_Num_Lock, numlock, {.i = 0} },
- { MODKEY, XK_Control_L, iso14755, {.i = 0} },
+@@ -181,6 +181,8 @@ static Shortcut shortcuts[] = {
+ { TERMMOD, XK_Y, selpaste, {.i = 0} },
+ { TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
+ { TERMMOD, XK_I, iso14755, {.i = 0} },
+ { ShiftMask, XK_Page_Up, kscrollup, {.i = -1} },
+ { ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} },
};
/*
diff --git a/st.c b/st.c
-index fbcd9e0..64bc208 100644
+index 65a0cb6..1d8c12a 100644
--- a/st.c
+++ b/st.c
-@@ -61,6 +61,7 @@ char *argv0;
- #define XK_ANY_MOD UINT_MAX
- #define XK_NO_MOD 0
- #define XK_SWITCH_MOD (1<<13)
-+#define histsize 2000
-
- /* macros */
- #define MIN(a, b) ((a) < (b) ? (a) : (b))
-@@ -87,6 +88,8 @@ char *argv0;
- #define TRUERED(x) (((x) & 0xff0000) >> 8)
- #define TRUEGREEN(x) (((x) & 0xff00))
- #define TRUEBLUE(x) (((x) & 0xff) << 8)
-+#define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - term.scr \
-+ + histsize + 1) % histsize] : term.line[(y) - term.scr])
-
- /* constants */
- #define ISO14755CMD "dmenu -w %lu -p codepoint: </dev/null"
-@@ -241,6 +244,9 @@ typedef struct {
+@@ -121,6 +121,9 @@ typedef struct {
int col; /* nb col */
Line *line; /* screen */
Line *alt; /* alternate screen */
-+ Line hist[histsize]; /* history buffer */
++ Line hist[HISTSIZE]; /* history buffer */
+ int histi; /* history index */
+ int scr; /* scroll back */
- int *dirty; /* dirtyness of lines */
- XftGlyphFontSpec *specbuf; /* font spec buffer used for rendering */
+ int *dirty; /* dirtyness of lines */
TCursor c; /* cursor */
-@@ -334,6 +340,8 @@ typedef struct {
- /* function definitions used in config.h */
- static void clipcopy(const Arg *);
- static void clippaste(const Arg *);
-+static void kscrolldown(const Arg *);
-+static void kscrollup(const Arg *);
- static void numlock(const Arg *);
- static void selpaste(const Arg *);
- static void xzoom(const Arg *);
-@@ -409,8 +417,8 @@ static void tputtab(int);
+ int ocx; /* old cursor col */
+@@ -188,8 +191,8 @@ static void tnewline(int);
+ static void tputtab(int);
static void tputc(Rune);
static void treset(void);
- static void tresize(int, int);
-static void tscrollup(int, int);
-static void tscrolldown(int, int);
+static void tscrollup(int, int, int);
+static void tscrolldown(int, int, int);
static void tsetattr(int *, int);
static void tsetchar(Rune, Glyph *, int, int);
- static void tsetscroll(int, int);
-@@ -742,10 +750,10 @@ tlinelen(int y)
+ static void tsetdirt(int, int);
+@@ -431,10 +434,10 @@ tlinelen(int y)
{
int i = term.col;
@@ -75,7 +49,7 @@ index fbcd9e0..64bc208 100644
--i;
return i;
-@@ -807,7 +815,7 @@ selsnap(int *x, int *y, int direction)
+@@ -543,7 +546,7 @@ selsnap(int *x, int *y, int direction)
* Snap around if the word wraps around at the end or
* beginning of a line.
*/
@@ -84,7 +58,7 @@ index fbcd9e0..64bc208 100644
prevdelim = ISDELIM(prevgp->u);
for (;;) {
newx = *x + direction;
-@@ -822,14 +830,14 @@ selsnap(int *x, int *y, int direction)
+@@ -558,14 +561,14 @@ selsnap(int *x, int *y, int direction)
yt = *y, xt = *x;
else
yt = newy, xt = newx;
@@ -101,7 +75,7 @@ index fbcd9e0..64bc208 100644
delim = ISDELIM(gp->u);
if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim
|| (delim && gp->u != prevgp->u)))
-@@ -850,14 +858,14 @@ selsnap(int *x, int *y, int direction)
+@@ -586,14 +589,14 @@ selsnap(int *x, int *y, int direction)
*x = (direction < 0) ? 0 : term.col - 1;
if (direction < 0) {
for (; *y > 0; *y += direction) {
@@ -118,7 +92,7 @@ index fbcd9e0..64bc208 100644
& ATTR_WRAP)) {
break;
}
-@@ -1023,13 +1031,13 @@ getsel(void)
+@@ -624,13 +627,13 @@ getsel(void)
}
if (sel.type == SEL_RECTANGULAR) {
@@ -135,27 +109,27 @@ index fbcd9e0..64bc208 100644
while (last >= gp && last->u == ' ')
--last;
-@@ -1513,6 +1521,9 @@ ttyread(void)
+@@ -836,6 +839,9 @@ ttyread(void)
if (buflen > 0)
- memmove(buf, ptr, buflen);
+ memmove(buf, buf + written, buflen);
-+ if (term.scr > 0 && term.scr < histsize-1)
++ if (term.scr > 0 && term.scr < HISTSIZE-1)
+ term.scr++;
+
return ret;
}
-@@ -1522,6 +1533,9 @@ ttywrite(const char *s, size_t n)
- fd_set wfd, rfd;
- ssize_t r;
- size_t lim = 256;
+@@ -843,6 +849,9 @@ void
+ ttywrite(const char *s, size_t n, int may_echo)
+ {
+ const char *next;
+ Arg arg = (Arg) { .i = term.scr };
+
+ kscrolldown(&arg);
- /*
- * Remember that we are using a pty, which might be a modem line.
-@@ -1724,13 +1738,53 @@ tswapscreen(void)
+ if (may_echo && IS_SET(MODE_ECHO))
+ twrite(s, n, 1);
+@@ -1054,13 +1063,54 @@ tswapscreen(void)
}
void
@@ -185,13 +159,14 @@ index fbcd9e0..64bc208 100644
+ if (n < 0)
+ n = term.row + n;
+
-+ if (term.scr <= histsize - n) {
++ if (term.scr <= HISTSIZE-n) {
+ term.scr += n;
+ selscroll(0, n);
+ tfulldirt();
+ }
+}
+
++
+void
+tscrolldown(int orig, int n, int copyhist)
{
@@ -201,7 +176,7 @@ index fbcd9e0..64bc208 100644
LIMIT(n, 0, term.bot-orig+1);
+ if (copyhist) {
-+ term.histi = (term.histi - 1 + histsize) % histsize;
++ 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;
@@ -210,7 +185,7 @@ index fbcd9e0..64bc208 100644
tsetdirt(orig, term.bot-n);
tclearregion(0, term.bot-n+1, term.col-1, term.bot);
-@@ -1744,13 +1798,20 @@ tscrolldown(int orig, int n)
+@@ -1074,13 +1124,20 @@ tscrolldown(int orig, int n)
}
void
@@ -223,7 +198,7 @@ index fbcd9e0..64bc208 100644
LIMIT(n, 0, term.bot-orig+1);
+ if (copyhist) {
-+ term.histi = (term.histi + 1) % histsize;
++ term.histi = (term.histi + 1) % HISTSIZE;
+ temp = term.hist[term.histi];
+ term.hist[term.histi] = term.line[orig];
+ term.line[orig] = temp;
@@ -232,7 +207,7 @@ index fbcd9e0..64bc208 100644
tclearregion(0, orig, term.col-1, orig+n-1);
tsetdirt(orig+n, term.bot);
-@@ -1799,7 +1860,7 @@ tnewline(int first_col)
+@@ -1129,7 +1186,7 @@ tnewline(int first_col)
int y = term.c.y;
if (y == term.bot) {
@@ -241,7 +216,7 @@ index fbcd9e0..64bc208 100644
} else {
y++;
}
-@@ -1964,14 +2025,14 @@ void
+@@ -1294,14 +1351,14 @@ void
tinsertblankline(int n)
{
if (BETWEEN(term.c.y, term.top, term.bot))
@@ -258,7 +233,7 @@ index fbcd9e0..64bc208 100644
}
int32_t
-@@ -2405,11 +2466,11 @@ csihandle(void)
+@@ -1730,11 +1787,11 @@ csihandle(void)
break;
case 'S': /* SU -- Scroll <n> line up */
DEFAULT(csiescseq.arg[0], 1);
@@ -272,7 +247,7 @@ index fbcd9e0..64bc208 100644
break;
case 'L': /* IL -- Insert <n> blank lines */
DEFAULT(csiescseq.arg[0], 1);
-@@ -2945,7 +3006,7 @@ eschandle(uchar ascii)
+@@ -2258,7 +2315,7 @@ eschandle(uchar ascii)
return 0;
case 'D': /* IND -- Linefeed */
if (term.c.y == term.bot) {
@@ -281,7 +256,7 @@ index fbcd9e0..64bc208 100644
} else {
tmoveto(term.c.x, term.c.y+1);
}
-@@ -2958,7 +3019,7 @@ eschandle(uchar ascii)
+@@ -2271,7 +2328,7 @@ eschandle(uchar ascii)
break;
case 'M': /* RI -- Reverse index */
if (term.c.y == term.top) {
@@ -290,7 +265,7 @@ index fbcd9e0..64bc208 100644
} else {
tmoveto(term.c.x, term.c.y-1);
}
-@@ -3145,7 +3206,7 @@ check_control_code:
+@@ -2490,7 +2547,7 @@ twrite(const char *buf, int buflen, int show_ctrl)
void
tresize(int col, int row)
{
@@ -299,11 +274,12 @@ index fbcd9e0..64bc208 100644
int minrow = MIN(row, term.row);
int mincol = MIN(col, term.col);
int *bp;
-@@ -3185,6 +3246,14 @@ tresize(int col, int row)
+@@ -2527,7 +2584,15 @@ tresize(int col, int row)
term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty));
term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs));
-+ for (i = 0; i < histsize; i++) {
+- /* resize each row to new width, zero-pad if needed */
++ 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;
@@ -311,31 +287,62 @@ index fbcd9e0..64bc208 100644
+ }
+ }
+
- /* resize each row to new width, zero-pad if needed */
++ /* resize each r w to new width, zero-pad if needed */
for (i = 0; i < minrow; i++) {
term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph));
-@@ -4112,11 +4181,11 @@ drawregion(int x1, int y1, int x2, int y2)
+ term.alt[i] = xrealloc(term.alt[i], col * sizeof(Glyph));
+@@ -2584,7 +2649,7 @@ drawregion(int x1, int y1, int x2, int y2)
+ continue;
+
term.dirty[y] = 0;
+- xdrawline(term.line[y], x1, y, x2);
++ xdrawline(TLINE(y), x1, y, x2);
+ }
+ }
- specs = term.specbuf;
-- numspecs = xmakeglyphfontspecs(specs, &term.line[y][x1], x2 - x1, x1, y);
-+ numspecs = xmakeglyphfontspecs(specs, &TLINE(y)[x1], x2 - x1, x1, y);
+@@ -2605,8 +2670,10 @@ draw(void)
+ cx--;
- i = ox = 0;
- for (x = x1; x < x2 && i < numspecs; x++) {
-- new = term.line[y][x];
-+ new = TLINE(y)[x];
- if (new.mode == ATTR_WDUMMY)
- continue;
- if (ena_sel && selected(x, y))
-@@ -4136,7 +4205,9 @@ drawregion(int x1, int y1, int x2, int y2)
- if (i > 0)
- xdrawglyphfontspecs(specs, base, i, ox, y);
- }
-- xdrawcursor();
-+
-+ if (term.scr == 0)
-+ xdrawcursor();
+ drawregion(0, 0, term.col, term.row);
+- xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
+- term.ocx, term.ocy, term.line[term.ocy][term.ocx]);
++ if (term.scr == 0) {
++ xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
++ term.ocx, term.ocy, term.line[term.ocy][term.ocx]);
++ }
+ term.ocx = cx, term.ocy = term.c.y;
+ xfinishdraw();
}
+diff --git a/st.h b/st.h
+index dac64d8..628e876 100644
+--- a/st.h
++++ b/st.h
+@@ -3,6 +3,9 @@
+ #include <stdint.h>
+ #include <sys/types.h>
- void
++/* Arbitrary size */
++#define HISTSIZE 2000
++
+ /* macros */
+ #define MIN(a, b) ((a) < (b) ? (a) : (b))
+ #define MAX(a, b) ((a) < (b) ? (b) : (a))
+@@ -19,6 +22,8 @@
+
+ #define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b))
+ #define IS_TRUECOL(x) (1 << 24 & (x))
++#define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - term.scr \
++ + HISTSIZE + 1) % HISTSIZE] : term.line[(y) - term.scr])
+
+ enum glyph_attribute {
+ ATTR_NULL = 0,
+@@ -111,6 +116,9 @@ void *xmalloc(size_t);
+ void *xrealloc(void *, size_t);
+ char *xstrdup(char *);
+
++void kscrolldown(const Arg *);
++void kscrollup(const Arg *);
++
+ /* config.h globals */
+ extern char *utmp;
+ extern char *stty_args;
diff --git a/patches/st-scrollback-mouse-20161020-6e79e83.diff b/patches/st-scrollback-mouse-0.8.diff
index 05b8b45..3b2729e 100644
--- a/patches/st-scrollback-mouse-20161020-6e79e83.diff
+++ b/patches/st-scrollback-mouse-0.8.diff
@@ -1,8 +1,8 @@
diff --git a/config.def.h b/config.def.h
-index eae969e..34ebb44 100644
+index 27d42ca..feec7e2 100644
--- a/config.def.h
+++ b/config.def.h
-@@ -152,8 +152,14 @@ static unsigned int defaultunderline = 7;
+@@ -156,8 +156,14 @@ static unsigned int defaultattr = 11;
*/
static MouseShortcut mshortcuts[] = {
/* button mask string */
@@ -12,18 +12,18 @@ index eae969e..34ebb44 100644
+ { Button5, XK_NO_MOD, "\005" },
+};
+
-+static MouseKey mkeys[] = {
++MouseKey mkeys[] = {
+ /* button mask function argument */
+ { Button4, ShiftMask, kscrollup, {.i = 1} },
+ { Button5, ShiftMask, kscrolldown, {.i = 1} },
};
/* Internal keyboard shortcuts. */
-diff --git a/st.c b/st.c
-index 233d301..c71b6e7 100644
---- a/st.c
-+++ b/st.c
-@@ -299,6 +299,13 @@ typedef union {
+diff --git a/st.h b/st.h
+index 628e876..cdd25ae 100644
+--- a/st.h
++++ b/st.h
+@@ -81,6 +81,13 @@ typedef union {
const void *v;
} Arg;
@@ -34,18 +34,27 @@ index 233d301..c71b6e7 100644
+ const Arg arg;
+} MouseKey;
+
- typedef struct {
- uint mod;
- KeySym keysym;
-@@ -953,6 +960,7 @@ bpress(XEvent *e)
+ void die(const char *, ...);
+ void redraw(void);
+ void draw(void);
+@@ -129,3 +136,4 @@ extern char *termname;
+ extern unsigned int tabspaces;
+ extern unsigned int defaultfg;
+ extern unsigned int defaultbg;
++extern MouseKey mkeys[];
+diff --git a/x.c b/x.c
+index d43a529..754d859 100644
+--- a/x.c
++++ b/x.c
+@@ -409,6 +409,7 @@ bpress(XEvent *e)
{
struct timespec now;
MouseShortcut *ms;
+ MouseKey *mk;
+ int snap;
if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
- mousereport(e);
-@@ -967,6 +975,14 @@ bpress(XEvent *e)
+@@ -424,6 +425,14 @@ bpress(XEvent *e)
}
}
@@ -58,5 +67,5 @@ index 233d301..c71b6e7 100644
+ }
+
if (e->xbutton.button == Button1) {
- clock_gettime(CLOCK_MONOTONIC, &now);
-
+ /*
+ * If the user clicks below predefined timeouts specific
diff --git a/patches/st-solarized-both-20160727-308bfbf.diff b/patches/st-solarized-both-20160727-308bfbf.diff
deleted file mode 100644
index c966579..0000000
--- a/patches/st-solarized-both-20160727-308bfbf.diff
+++ /dev/null
@@ -1,189 +0,0 @@
-diff --git a/config.def.h b/config.def.h
-index b41747f..adaa9b8 100644
---- a/config.def.h
-+++ b/config.def.h
-@@ -84,42 +84,54 @@ static unsigned int tabspaces = 8;
-
- /* Terminal colors (16 first used in escape sequence) */
- static const char *colorname[] = {
-- /* 8 normal colors */
-- "black",
-- "red3",
-- "green3",
-- "yellow3",
-- "blue2",
-- "magenta3",
-- "cyan3",
-- "gray90",
--
-- /* 8 bright colors */
-- "gray50",
-- "red",
-- "green",
-- "yellow",
-- "#5c5cff",
-- "magenta",
-- "cyan",
-- "white",
--
-- [255] = 0,
--
-- /* more colors can be added after 255 to use with DefaultXX */
-- "#cccccc",
-- "#555555",
-+ /* solarized dark */
-+ "#073642", /* 0: black */
-+ "#dc322f", /* 1: red */
-+ "#859900", /* 2: green */
-+ "#b58900", /* 3: yellow */
-+ "#268bd2", /* 4: blue */
-+ "#d33682", /* 5: magenta */
-+ "#2aa198", /* 6: cyan */
-+ "#eee8d5", /* 7: white */
-+ "#002b36", /* 8: brblack */
-+ "#cb4b16", /* 9: brred */
-+ "#586e75", /* 10: brgreen */
-+ "#657b83", /* 11: bryellow */
-+ "#839496", /* 12: brblue */
-+ "#6c71c4", /* 13: brmagenta*/
-+ "#93a1a1", /* 14: brcyan */
-+ "#fdf6e3", /* 15: brwhite */
- };
-
-+/* Terminal colors for alternate (light) palette */
-+static const char *altcolorname[] = {
-+ /* solarized light */
-+ "#eee8d5", /* 0: black */
-+ "#dc322f", /* 1: red */
-+ "#859900", /* 2: green */
-+ "#b58900", /* 3: yellow */
-+ "#268bd2", /* 4: blue */
-+ "#d33682", /* 5: magenta */
-+ "#2aa198", /* 6: cyan */
-+ "#073642", /* 7: white */
-+ "#fdf6e3", /* 8: brblack */
-+ "#cb4b16", /* 9: brred */
-+ "#93a1a1", /* 10: brgreen */
-+ "#839496", /* 11: bryellow */
-+ "#657b83", /* 12: brblue */
-+ "#6c71c4", /* 13: brmagenta*/
-+ "#586e75", /* 14: brcyan */
-+ "#002b36", /* 15: brwhite */
-+};
-
- /*
- * Default colors (colorname index)
- * foreground, background, cursor, reverse cursor
- */
--static unsigned int defaultfg = 7;
--static unsigned int defaultbg = 0;
--static unsigned int defaultcs = 256;
--static unsigned int defaultrcs = 257;
-+static unsigned int defaultfg = 12;
-+static unsigned int defaultbg = 8;
-+static unsigned int defaultcs = 14;
-+static unsigned int defaultrcs = 15;
-
- /*
- * Default shape of cursor
-@@ -172,6 +184,7 @@ static Shortcut shortcuts[] = {
- { MODKEY|ShiftMask, XK_C, clipcopy, {.i = 0} },
- { MODKEY|ShiftMask, XK_V, clippaste, {.i = 0} },
- { MODKEY, XK_Num_Lock, numlock, {.i = 0} },
-+ { XK_ANY_MOD, XK_F6, swapcolors, {.i = 0} },
- };
-
- /*
-diff --git a/st.c b/st.c
-index 2594c65..b4a3089 100644
---- a/st.c
-+++ b/st.c
-@@ -328,6 +328,7 @@ typedef struct {
- static void clipcopy(const Arg *);
- static void clippaste(const Arg *);
- static void numlock(const Arg *);
-+static void swapcolors(const Arg *);
- static void selpaste(const Arg *);
- static void xzoom(const Arg *);
- static void xzoomabs(const Arg *);
-@@ -355,7 +356,7 @@ typedef struct {
-
- /* Drawing Context */
- typedef struct {
-- Color col[MAX(LEN(colorname), 256)];
-+ Color col[MAX(MAX(LEN(colorname), LEN(altcolorname)), 256)];
- Font font, bfont, ifont, ibfont;
- GC gc;
- } DC;
-@@ -533,6 +534,8 @@ static char *opt_name = NULL;
- static char *opt_title = NULL;
- static int oldbutton = 3; /* button event on startup: 3 = release */
-
-+static int usealtcolors = 0; /* 1 to use alternate palette */
-+
- static char *usedfont = NULL;
- static double usedfontsize = 0;
- static double defaultfontsize = 0;
-@@ -3148,6 +3151,11 @@ sixd_to_16bit(int x)
- return x == 0 ? 0 : 0x3737 + 0x2828 * x;
- }
-
-+const char* getcolorname(int i)
-+{
-+ return (usealtcolors) ? altcolorname[i] : colorname[i];
-+}
-+
- int
- xloadcolor(int i, const char *name, Color *ncolor)
- {
-@@ -3166,7 +3174,7 @@ xloadcolor(int i, const char *name, Color *ncolor)
- return XftColorAllocValue(xw.dpy, xw.vis,
- xw.cmap, &color, ncolor);
- } else
-- name = colorname[i];
-+ name = getcolorname(i);
- }
-
- return XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, ncolor);
-@@ -3186,8 +3194,8 @@ xloadcols(void)
-
- for (i = 0; i < LEN(dc.col); i++)
- if (!xloadcolor(i, NULL, &dc.col[i])) {
-- if (colorname[i])
-- die("Could not allocate color '%s'\n", colorname[i]);
-+ if (getcolorname(i))
-+ die("Could not allocate color '%s'\n", getcolorname(i));
- else
- die("Could not allocate color %d\n", i);
- }
-@@ -3514,13 +3522,13 @@ xinit(void)
- cursor = XCreateFontCursor(xw.dpy, mouseshape);
- XDefineCursor(xw.dpy, xw.win, cursor);
-
-- if (XParseColor(xw.dpy, xw.cmap, colorname[mousefg], &xmousefg) == 0) {
-+ if (XParseColor(xw.dpy, xw.cmap, getcolorname(mousefg), &xmousefg) == 0) {
- xmousefg.red = 0xffff;
- xmousefg.green = 0xffff;
- xmousefg.blue = 0xffff;
- }
-
-- if (XParseColor(xw.dpy, xw.cmap, colorname[mousebg], &xmousebg) == 0) {
-+ if (XParseColor(xw.dpy, xw.cmap, getcolorname(mousebg), &xmousebg) == 0) {
- xmousebg.red = 0x0000;
- xmousebg.green = 0x0000;
- xmousebg.blue = 0x0000;
-@@ -4074,6 +4082,14 @@ numlock(const Arg *dummy)
- term.numlock ^= 1;
- }
-
-+void
-+swapcolors(const Arg *dummy)
-+{
-+ usealtcolors = !usealtcolors;
-+ xloadcols();
-+ redraw();
-+}
-+
- char*
- kmap(KeySym k, uint state)
- {
diff --git a/patches/transparency.diff b/patches/transparency.diff
deleted file mode 100644
index b0d923c..0000000
--- a/patches/transparency.diff
+++ /dev/null
@@ -1,189 +0,0 @@
---- st/config.def.h 2018-01-19 12:48:07.280548253 -0700
-+++ st-transparent/config.def.h 2018-01-19 13:15:25.443443692 -0700
-@@ -82,6 +82,9 @@
- */
- static unsigned int tabspaces = 8;
-
-+/* bg opacity */
-+static const int alpha = 0xdd;
-+
- /* Terminal colors (16 first used in escape sequence) */
- static const char *colorname[] = {
- /* solarized dark */
-@@ -101,6 +104,7 @@
- "#6c71c4", /* 13: brmagenta*/
- "#93a1a1", /* 14: brcyan */
- "#fdf6e3", /* 15: brwhite */
-+ "black",
- };
-
- /* Terminal colors for alternate (light) palette */
-@@ -122,6 +126,7 @@
- "#6c71c4", /* 13: brmagenta*/
- "#586e75", /* 14: brcyan */
- "#002b36", /* 15: brwhite */
-+ "black",
- };
-
- /*
-@@ -129,7 +134,7 @@
- * foreground, background, cursor, reverse cursor
- */
- static unsigned int defaultfg = 12;
--static unsigned int defaultbg = 8;
-+static unsigned int defaultbg = 257;
- static unsigned int defaultcs = 14;
- static unsigned int defaultrcs = 15;
-
---- st/config.mk 2018-01-17 23:51:03.804274540 -0700
-+++ st-transparent/config.mk 2018-01-19 12:56:45.323928617 -0700
-@@ -14,7 +14,7 @@
- INCS = -I. -I/usr/include -I${X11INC} \
- `pkg-config --cflags fontconfig` \
- `pkg-config --cflags freetype2`
--LIBS = -L/usr/lib -lc -L${X11LIB} -lm -lrt -lX11 -lutil -lXft \
-+LIBS = -L/usr/lib -lc -L${X11LIB} -lm -lrt -lX11 -lutil -lXext -lXft -lXrender\
- `pkg-config --libs fontconfig` \
- `pkg-config --libs freetype2`
-
---- st/st.c 2018-01-18 19:01:56.693663129 -0700
-+++ st-transparent/st.c 2018-01-19 13:03:28.877184002 -0700
-@@ -61,6 +61,7 @@
- #define XK_ANY_MOD UINT_MAX
- #define XK_NO_MOD 0
- #define XK_SWITCH_MOD (1<<13)
-+#define OPAQUE 0Xff
- #define histsize 2000
-
- /* macros */
-@@ -83,6 +84,8 @@
- (t1.tv_nsec-t2.tv_nsec)/1E6)
- #define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit)))
-
-+#define USE_ARGB (alpha != OPAQUE && opt_embed == NULL)
-+
- #define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b))
- #define IS_TRUECOL(x) (1 << 24 & (x))
- #define TRUERED(x) (((x) & 0xff0000) >> 8)
-@@ -281,6 +284,7 @@
- int w, h; /* window width and height */
- int ch; /* char height */
- int cw; /* char width */
-+ int depth; /* bit depth */
- int cyo; /* char y offset */
- char state; /* focus, redraw, visible */
- int cursor; /* cursor style */
-@@ -3326,7 +3330,7 @@
-
- XFreePixmap(xw.dpy, xw.buf);
- xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.w, xw.h,
-- DefaultDepth(xw.dpy, xw.scr));
-+ xw.depth);
- XftDrawChange(xw.draw, xw.buf);
- xclear(0, 0, xw.w, xw.h);
- }
-@@ -3385,6 +3389,14 @@
- else
- die("Could not allocate color %d\n", i);
- }
-+
-+ /* set alpha value of bg color */
-+ if (USE_ARGB) {
-+ dc.col[defaultbg].color.alpha = (0xffff * alpha) / OPAQUE; //0xcccc;
-+ dc.col[defaultbg].pixel &= 0x00111111;
-+ dc.col[defaultbg].pixel |= alpha << 24; // 0xcc000000;
-+ }
-+
- loaded = 1;
- }
-
-@@ -3405,6 +3417,15 @@
-
- return 0;
- }
-+void
-+xtermclear(int col1, int row1, int col2, int row2) {
-+ XftDrawRect(xw.draw,
-+ &dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg],
-+ borderpx + col1 * xw.cw,
-+ borderpx + row1 * xw.ch,
-+ (col2-col1+1) * xw.cw,
-+ (row2-row1+1) * xw.ch);
-+}
-
- /*
- * Absolute coordinates.
-@@ -3677,7 +3698,38 @@
- if (!(xw.dpy = XOpenDisplay(NULL)))
- die("Can't open display\n");
- xw.scr = XDefaultScreen(xw.dpy);
-- xw.vis = XDefaultVisual(xw.dpy, xw.scr);
-+ xw.depth = (USE_ARGB) ? 32: XDefaultDepth(xw.dpy, xw.scr);
-+ if (! USE_ARGB)
-+ xw.vis = XDefaultVisual(xw.dpy, xw.scr);
-+ else {
-+ XVisualInfo *vis;
-+ XRenderPictFormat *fmt;
-+ int nvi;
-+ int i;
-+
-+ XVisualInfo tpl = {
-+ .screen = xw.scr,
-+ .depth = 32,
-+ .class = TrueColor
-+ };
-+
-+ vis = XGetVisualInfo(xw.dpy, VisualScreenMask | VisualDepthMask | VisualClassMask, &tpl, &nvi);
-+ xw.vis = NULL;
-+ for(i = 0; i < nvi; i ++) {
-+ fmt = XRenderFindVisualFormat(xw.dpy, vis[i].visual);
-+ if (fmt->type == PictTypeDirect && fmt->direct.alphaMask) {
-+ xw.vis = vis[i].visual;
-+ break;
-+ }
-+ }
-+
-+ XFree(vis);
-+
-+ if (! xw.vis) {
-+ fprintf(stderr, "Couldn't find ARGB visual.\n");
-+ exit(1);
-+ }
-+ }
-
- /* font */
- if (!FcInit())
-@@ -3687,7 +3739,10 @@
- xloadfonts(usedfont, 0);
-
- /* colors */
-- xw.cmap = XDefaultColormap(xw.dpy, xw.scr);
-+ if (! USE_ARGB)
-+ xw.cmap = XDefaultColormap(xw.dpy, xw.scr);
-+ else
-+ xw.cmap = XCreateColormap(xw.dpy, XRootWindow(xw.dpy, xw.scr), xw.vis, None);
- xloadcols();
-
- /* adjust fixed window geometry */
-@@ -3710,16 +3765,17 @@
- if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0))))
- parent = XRootWindow(xw.dpy, xw.scr);
- xw.win = XCreateWindow(xw.dpy, parent, xw.l, xw.t,
-- xw.w, xw.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput,
-+ xw.w, xw.h, 0, xw.depth, InputOutput,
- xw.vis, CWBackPixel | CWBorderPixel | CWBitGravity
- | CWEventMask | CWColormap, &xw.attrs);
-
- memset(&gcvalues, 0, sizeof(gcvalues));
- gcvalues.graphics_exposures = False;
-- dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures,
-+ xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.w, xw.h, xw.depth);
-+ dc.gc = XCreateGC(xw.dpy,
-+ (USE_ARGB)? xw.buf: parent,
-+ GCGraphicsExposures,
- &gcvalues);
-- xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.w, xw.h,
-- DefaultDepth(xw.dpy, xw.scr));
- XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel);
- XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, xw.w, xw.h);
-
diff --git a/run-patches.sh b/run-patches.sh
new file mode 100755
index 0000000..48047e1
--- /dev/null
+++ b/run-patches.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+patch < patches/st-clipboard-20180309-c5ba9c0.diff
+patch < patches/st-no_bold_colors-0.8.1.diff
+patch < patches/st-scrollback-0.8.diff
+patch < patches/st-scrollback-mouse-0.8.diff
+patch < patches/st-vertcenter-20180320-6ac8c8a.diff
+patch < patches/st-alpha-0.8.1.diff
diff --git a/st-remove.sh b/st-remove.sh
new file mode 100755
index 0000000..48d3d41
--- /dev/null
+++ b/st-remove.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+rm /usr/local/bin/st
+rm /usr/local/share/man/man1/st.1
+rm /usr/share/terminfo/s/st*
diff --git a/st.1 b/st.1
index c429dcf..81bceff 100644
--- a/st.1
+++ b/st.1
@@ -120,7 +120,7 @@ st executes
instead of the shell. If this is used it
.B must be the last option
on the command line, as in xterm / rxvt.
-This option is only intended for compability,
+This option is only intended for compatibility,
and all the remaining arguments are used as a command
even without it.
.SH SHORTCUTS
@@ -142,28 +142,25 @@ Print the full screen to the
Print the selection to the
.I iofile.
.TP
-.B Alt-Shift-Page Up
+.B Ctrl-Shift-Page Up
Increase font size.
.TP
-.B Alt-Shift-Page Down
+.B Ctrl-Shift-Page Down
Decrease font size.
.TP
-.B Alt-Shift-Home
+.B Ctrl-Shift-Home
Reset to default font size.
.TP
-.B Shift-Insert
+.B Ctrl-Shift-y
Paste from primary selection (middle mouse button).
.TP
-.B Alt-Shift-Insert
-Paste from clipboard selection.
-.TP
-.B Alt-Shift-c
+.B Ctrl-Shift-c
Copy the selected text to the clipboard selection.
.TP
-.B Alt-Shift-v
+.B Ctrl-Shift-v
Paste from the clipboard selection.
.TP
-.B Alt-Ctrl
+.B Ctrl-Shift-i
Launch dmenu to enter a unicode codepoint and send the corresponding glyph
to st.
.SH CUSTOMIZATION
diff --git a/st.c b/st.c
index 5fb8e95..45d2544 100644
--- a/st.c
+++ b/st.c
@@ -3,40 +3,22 @@
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
-#include <locale.h>
#include <pwd.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
-#include <stdint.h>
#include <sys/ioctl.h>
#include <sys/select.h>
-#include <sys/stat.h>
-#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <termios.h>
-#include <time.h>
#include <unistd.h>
-#include <libgen.h>
-#include <X11/Xatom.h>
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-#include <X11/cursorfont.h>
-#include <X11/keysym.h>
-#include <X11/Xft/Xft.h>
-#include <X11/XKBlib.h>
-#include <fontconfig/fontconfig.h>
#include <wchar.h>
-#include "arg.h"
-
-char *argv0;
-
-#define Glyph Glyph_
-#define Font Font_
+#include "st.h"
+#include "win.h"
#if defined(__linux)
#include <pty.h>
@@ -46,11 +28,6 @@ char *argv0;
#include <libutil.h>
#endif
-
-/* XEMBED messages */
-#define XEMBED_FOCUS_IN 4
-#define XEMBED_FOCUS_OUT 5
-
/* Arbitrary sizes */
#define UTF_INVALID 0xFFFD
#define UTF_SIZ 4
@@ -58,59 +35,27 @@ char *argv0;
#define ESC_ARG_SIZ 16
#define STR_BUF_SIZ ESC_BUF_SIZ
#define STR_ARG_SIZ ESC_ARG_SIZ
-#define XK_ANY_MOD UINT_MAX
-#define XK_NO_MOD 0
-#define XK_SWITCH_MOD (1<<13)
-#define OPAQUE 0Xff
-#define histsize 2000
/* 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 IS_SET(flag) ((term.mode & (flag)) != 0)
#define NUMMAXLEN(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1)
-#define DEFAULT(a, b) (a) = (a) ? (a) : (b)
-#define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b))
-#define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d))
#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) (utf8strchr(worddelimiters, u) != NULL)
-#define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x)
-#define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || \
- (a).bg != (b).bg)
-#define IS_SET(flag) ((term.mode & (flag)) != 0)
-#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 USE_ARGB (alpha != OPAQUE && opt_embed == NULL)
-
-#define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b))
-#define IS_TRUECOL(x) (1 << 24 & (x))
-#define TRUERED(x) (((x) & 0xff0000) >> 8)
-#define TRUEGREEN(x) (((x) & 0xff00))
-#define TRUEBLUE(x) (((x) & 0xff) << 8)
-#define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - term.scr \
- + histsize + 1) % histsize] : term.line[(y) - term.scr])
/* constants */
-#define ISO14755CMD "dmenu -w %lu -p codepoint: </dev/null"
-
-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_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
+#define ISO14755CMD "dmenu -w \"$WINDOWID\" -p codepoint: </dev/null"
+
+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,
};
enum cursor_movement {
@@ -124,34 +69,6 @@ enum cursor_state {
CURSOR_ORIGIN = 2
};
-enum term_mode {
- MODE_WRAP = 1 << 0,
- MODE_INSERT = 1 << 1,
- MODE_APPKEYPAD = 1 << 2,
- MODE_ALTSCREEN = 1 << 3,
- MODE_CRLF = 1 << 4,
- MODE_MOUSEBTN = 1 << 5,
- MODE_MOUSEMOTION = 1 << 6,
- MODE_REVERSE = 1 << 7,
- MODE_KBDLOCK = 1 << 8,
- MODE_HIDE = 1 << 9,
- MODE_ECHO = 1 << 10,
- MODE_APPCURSOR = 1 << 11,
- MODE_MOUSESGR = 1 << 12,
- MODE_8BIT = 1 << 13,
- MODE_BLINK = 1 << 14,
- MODE_FBLINK = 1 << 15,
- MODE_FOCUS = 1 << 16,
- MODE_MOUSEX10 = 1 << 17,
- MODE_MOUSEMANY = 1 << 18,
- MODE_BRCKTPASTE = 1 << 19,
- MODE_PRINT = 1 << 20,
- MODE_UTF8 = 1 << 21,
- MODE_SIXEL = 1 << 22,
- MODE_MOUSE = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\
- |MODE_MOUSEMANY,
-};
-
enum charset {
CS_GRAPHIC0,
CS_GRAPHIC1,
@@ -173,46 +90,6 @@ enum escape_state {
ESC_DCS =128,
};
-enum window_state {
- WIN_VISIBLE = 1,
- WIN_FOCUSED = 2
-};
-
-enum selection_mode {
- SEL_IDLE = 0,
- SEL_EMPTY = 1,
- SEL_READY = 2
-};
-
-enum selection_type {
- SEL_REGULAR = 1,
- SEL_RECTANGULAR = 2
-};
-
-enum selection_snap {
- SNAP_WORD = 1,
- SNAP_LINE = 2
-};
-
-typedef unsigned char uchar;
-typedef unsigned int uint;
-typedef unsigned long ulong;
-typedef unsigned short ushort;
-
-typedef uint_least32_t Rune;
-
-typedef XftDraw *Draw;
-typedef XftColor Color;
-
-typedef struct {
- Rune u; /* character code */
- ushort mode; /* attribute flags */
- uint32_t fg; /* foreground */
- uint32_t bg; /* background */
-} Glyph;
-
-typedef Glyph *Line;
-
typedef struct {
Glyph attr; /* current char attributes */
int x;
@@ -220,26 +97,23 @@ typedef struct {
char state;
} TCursor;
-/* CSI Escape sequence structs */
-/* ESC '[' [[ [<priv>] <arg> [;]] <mode> [<mode>]] */
typedef struct {
- char buf[ESC_BUF_SIZ]; /* raw string */
- int len; /* raw string length */
- char priv;
- int arg[ESC_ARG_SIZ];
- int narg; /* nb of args */
- char mode[2];
-} CSIEscape;
+ int mode;
+ int type;
+ int snap;
+ /*
+ * Selection variables:
+ * nb – normalized coordinates of the beginning of the selection
+ * ne – normalized coordinates of the end of the selection
+ * ob – original coordinates of the beginning of the selection
+ * oe – original coordinates of the end of the selection
+ */
+ struct {
+ int x, y;
+ } nb, ne, ob, oe;
-/* 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 *args[STR_ARG_SIZ];
- int narg; /* nb of args */
-} STREscape;
+ int alt;
+} Selection;
/* Internal representation of the screen */
typedef struct {
@@ -247,12 +121,13 @@ typedef struct {
int col; /* nb col */
Line *line; /* screen */
Line *alt; /* alternate screen */
- Line hist[histsize]; /* history buffer */
+ Line hist[HISTSIZE]; /* history buffer */
int histi; /* history index */
int scr; /* scroll back */
- int *dirty; /* dirtyness of lines */
- XftGlyphFontSpec *specbuf; /* font spec buffer used for rendering */
+ 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 */
@@ -260,145 +135,34 @@ typedef struct {
char trantbl[4]; /* charset table translation */
int charset; /* current charset */
int icharset; /* selected charset for sequence */
- int numlock; /* lock numbers in keyboard */
int *tabs;
} Term;
-/* Purely graphic info */
-typedef struct {
- Display *dpy;
- Colormap cmap;
- Window win;
- Drawable buf;
- Atom xembed, wmdeletewin, netwmname, netwmpid;
- XIM xim;
- XIC xic;
- Draw draw;
- Visual *vis;
- XSetWindowAttributes attrs;
- int scr;
- int isfixed; /* is fixed geometry? */
- int l, t; /* left and top offset */
- int gm; /* geometry mask */
- int tw, th; /* tty width and height */
- int w, h; /* window width and height */
- int ch; /* char height */
- int cw; /* char width */
- int depth; /* bit depth */
- int cyo; /* char y offset */
- char state; /* focus, redraw, visible */
- int cursor; /* cursor style */
-} XWindow;
-
-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 */
- signed char crlf; /* crlf mode */
-} Key;
-
+/* CSI Escape sequence structs */
+/* ESC '[' [[ [<priv>] <arg> [;]] <mode> [<mode>]] */
typedef struct {
- int mode;
- int type;
- int snap;
- /*
- * Selection variables:
- * nb – normalized coordinates of the beginning of the selection
- * ne – normalized coordinates of the end of the selection
- * ob – original coordinates of the beginning of the selection
- * oe – original coordinates of the end of the selection
- */
- struct {
- int x, y;
- } nb, ne, ob, oe;
-
- char *primary, *clipboard;
- Atom xtarget;
- int alt;
- struct timespec tclick1;
- struct timespec tclick2;
-} Selection;
-
-typedef union {
- int i;
- uint ui;
- float f;
- const void *v;
-} Arg;
+ char buf[ESC_BUF_SIZ]; /* raw string */
+ int len; /* raw string length */
+ char priv;
+ int arg[ESC_ARG_SIZ];
+ int narg; /* nb of args */
+ char mode[2];
+} CSIEscape;
+/* STR Escape sequence structs */
+/* ESC type [[ [<priv>] <arg> [;]] <mode>] ESC '\' */
typedef struct {
- uint b;
- uint mask;
- void (*func)(const Arg *);
- const Arg arg;
-} MouseKey;
+ char type; /* ESC type ... */
+ char buf[STR_BUF_SIZ]; /* raw string */
+ int len; /* raw string length */
+ char *args[STR_ARG_SIZ];
+ int narg; /* nb of args */
+} STREscape;
-typedef struct {
- uint mod;
- KeySym keysym;
- void (*func)(const Arg *);
- const Arg arg;
-} Shortcut;
-
-/* function definitions used in config.h */
-static void clipcopy(const Arg *);
-static void clippaste(const Arg *);
-static void kscrolldown(const Arg *);
-static void kscrollup(const Arg *);
-static void numlock(const Arg *);
-static void swapcolors(const Arg *);
-static void selpaste(const Arg *);
-static void xzoom(const Arg *);
-static void xzoomabs(const Arg *);
-static void xzoomreset(const Arg *);
-static void printsel(const Arg *);
-static void printscreen(const Arg *) ;
-static void iso14755(const Arg *);
-static void toggleprinter(const Arg *);
-static void sendbreak(const Arg *);
-
-/* Config.h for applying patches and the configuration. */
-#include "config.h"
-
-/* Font structure */
-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[MAX(MAX(LEN(colorname), LEN(altcolorname)), 256)];
- Font font, bfont, ifont, ibfont;
- GC gc;
-} DC;
-
-static void die(const char *, ...);
-static void draw(void);
-static void redraw(void);
-static void drawregion(int, int, int, int);
-static void execsh(void);
-static void stty(void);
+static void execsh(char *, char **);
+static void stty(char **);
static void sigchld(int);
-static void run(void);
+static void ttywriteraw(const char *, size_t);
static void csidump(void);
static void csihandle(void);
@@ -410,7 +174,6 @@ static void strhandle(void);
static void strparse(void);
static void strreset(void);
-static int tattrset(int);
static void tprinter(char *, size_t);
static void tdumpsel(void);
static void tdumpline(int);
@@ -424,176 +187,58 @@ static void tinsertblankline(int);
static int tlinelen(int);
static void tmoveto(int, int);
static void tmoveato(int, int);
-static void tnew(int, int);
static void tnewline(int);
static void tputtab(int);
static void tputc(Rune);
static void treset(void);
-static void tresize(int, int);
static void tscrollup(int, int, int);
static void tscrolldown(int, int, int);
static void tsetattr(int *, int);
static void tsetchar(Rune, Glyph *, int, int);
+static void tsetdirt(int, int);
static void tsetscroll(int, int);
static void tswapscreen(void);
-static void tsetdirt(int, int);
-static void tsetdirtattr(int);
static void tsetmode(int, int, int *, int);
+static int twrite(const char *, int, int);
static void tfulldirt(void);
-static void techo(Rune);
static void tcontrolcode(uchar );
static void tdectest(char );
static void tdefutf8(char);
static int32_t tdefcolor(int *, int *, int);
static void tdeftran(char);
-static inline int match(uint, uint);
-static void ttynew(void);
-static size_t ttyread(void);
-static void ttyresize(void);
-static void ttysend(char *, size_t);
-static void ttywrite(const char *, size_t);
static void tstrsequence(uchar);
-static inline ushort sixd_to_16bit(int);
-static int xmakeglyphfontspecs(XftGlyphFontSpec *, const Glyph *, int, int, int);
-static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int);
-static void xdrawglyph(Glyph, int, int);
-static void xhints(void);
-static void xclear(int, int, int, int);
-static void xdrawcursor(void);
-static void xinit(void);
-static void xloadcols(void);
-static int xsetcolorname(int, const char *);
-static int xgeommasktogravity(int);
-static int xloadfont(Font *, FcPattern *);
-static void xloadfonts(char *, double);
-static void xsettitle(char *);
-static void xresettitle(void);
-static void xsetpointermotion(int);
-static void xseturgency(int);
-static void xsetsel(char *, Time);
-static void xunloadfont(Font *);
-static void xunloadfonts(void);
-static void xresize(int, int);
-
-static void expose(XEvent *);
-static void visibility(XEvent *);
-static void unmap(XEvent *);
-static char *kmap(KeySym, uint);
-static void kpress(XEvent *);
-static void cmessage(XEvent *);
-static void cresize(int, int);
-static void resize(XEvent *);
-static void focus(XEvent *);
-static void brelease(XEvent *);
-static void bpress(XEvent *);
-static void bmotion(XEvent *);
-static void propnotify(XEvent *);
-static void selnotify(XEvent *);
-static void selclear(XEvent *);
-static void selrequest(XEvent *);
-
-static void selinit(void);
+static void drawregion(int, int, int, int);
+
static void selnormalize(void);
-static inline int selected(int, int);
-static char *getsel(void);
-static void selcopy(Time);
static void selscroll(int, int);
static void selsnap(int *, int *, int);
-static int x2col(int);
-static int y2row(int);
-static void getbuttoninfo(XEvent *);
-static void mousereport(XEvent *);
-static size_t utf8decode(char *, Rune *, size_t);
+static size_t utf8decode(const char *, Rune *, size_t);
static Rune utf8decodebyte(char, size_t *);
-static size_t utf8encode(Rune, char *);
static char utf8encodebyte(Rune, size_t);
-static char *utf8strchr(char *s, Rune u);
+static char *utf8strchr(char *, Rune);
static size_t utf8validate(Rune *, size_t);
+static char *base64dec(const char *);
+static char base64dec_getc(const char **);
+
static ssize_t xwrite(int, const char *, size_t);
-static void *xmalloc(size_t);
-static void *xrealloc(void *, size_t);
-static char *xstrdup(char *);
-
-static void usage(void);
-
-static void (*handler[LASTEvent])(XEvent *) = {
- [KeyPress] = kpress,
- [ClientMessage] = cmessage,
- [ConfigureNotify] = resize,
- [VisibilityNotify] = visibility,
- [UnmapNotify] = unmap,
- [Expose] = expose,
- [FocusIn] = focus,
- [FocusOut] = focus,
- [MotionNotify] = bmotion,
- [ButtonPress] = bpress,
- [ButtonRelease] = brelease,
-/*
- * Uncomment if you want the selection to disappear when you select something
- * different in another window.
- */
-/* [SelectionClear] = selclear, */
- [SelectionNotify] = selnotify,
-/*
- * PropertyNotify is only turned on when there is some INCR transfer happening
- * for the selection retrieval.
- */
- [PropertyNotify] = propnotify,
- [SelectionRequest] = selrequest,
-};
/* Globals */
-static DC dc;
-static XWindow xw;
static Term term;
+static Selection sel;
static CSIEscape csiescseq;
static STREscape strescseq;
+static int iofd = 1;
static int cmdfd;
static pid_t pid;
-static Selection sel;
-static int iofd = 1;
-static char **opt_cmd = NULL;
-static char *opt_class = NULL;
-static char *opt_embed = NULL;
-static char *opt_font = NULL;
-static char *opt_io = NULL;
-static char *opt_line = NULL;
-static char *opt_name = NULL;
-static char *opt_title = NULL;
-static int oldbutton = 3; /* button event on startup: 3 = release */
-
-static int usealtcolors = 0; /* 1 to use alternate palette */
-
-static char *usedfont = NULL;
-static double usedfontsize = 0;
-static double defaultfontsize = 0;
static uchar utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
static uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
static Rune utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000};
static Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
-/* Font Ring Cache */
-enum {
- FRC_NORMAL,
- FRC_ITALIC,
- FRC_BOLD,
- FRC_ITALICBOLD
-};
-
-typedef struct {
- XftFont *font;
- int flags;
- Rune unicodep;
-} Fontcache;
-
-/* Fontcache is an array now. A new font will be appended to the array. */
-static Fontcache frc[16];
-static int frclen = 0;
-
ssize_t
xwrite(int fd, const char *s, size_t len)
{
@@ -641,7 +286,7 @@ xstrdup(char *s)
}
size_t
-utf8decode(char *c, Rune *u, size_t clen)
+utf8decode(const char *c, Rune *u, size_t clen)
{
size_t i, j, len, type;
Rune udecoded;
@@ -727,51 +372,121 @@ 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)++);
+}
+
+char *
+base64dec(const char *src)
+{
+ size_t in_len = strlen(src);
+ char *result, *dst;
+
+ if (in_len % 4)
+ in_len += 4 - (in_len % 4);
+ result = dst = xmalloc(in_len / 4 * 3 + 1);
+ while (*src) {
+ int a = base64_digits[(unsigned char) base64dec_getc(&src)];
+ int b = base64_digits[(unsigned char) base64dec_getc(&src)];
+ int c = base64_digits[(unsigned char) base64dec_getc(&src)];
+ int d = base64_digits[(unsigned char) base64dec_getc(&src)];
+
+ *dst++ = (a << 2) | ((b & 0x30) >> 4);
+ if (c == -1)
+ break;
+ *dst++ = ((b & 0x0f) << 4) | ((c & 0x3c) >> 2);
+ if (d == -1)
+ break;
+ *dst++ = ((c & 0x03) << 6) | d;
+ }
+ *dst = '\0';
+ return result;
+}
+
void
selinit(void)
{
- clock_gettime(CLOCK_MONOTONIC, &sel.tclick1);
- clock_gettime(CLOCK_MONOTONIC, &sel.tclick2);
sel.mode = SEL_IDLE;
sel.snap = 0;
sel.ob.x = -1;
- sel.primary = NULL;
- sel.clipboard = NULL;
- sel.xtarget = XInternAtom(xw.dpy, "UTF8_STRING", 0);
- if (sel.xtarget == None)
- sel.xtarget = XA_STRING;
}
int
-x2col(int x)
+tlinelen(int y)
{
- x -= borderpx;
- x /= xw.cw;
+ int i = term.col;
+
+ if (TLINE(y)[i - 1].mode & ATTR_WRAP)
+ return i;
- return LIMIT(x, 0, term.col-1);
+ while (i > 0 && TLINE(y)[i - 1].u == ' ')
+ --i;
+
+ return i;
}
-int
-y2row(int y)
+void
+selstart(int col, int row, int snap)
{
- y -= borderpx;
- y /= xw.ch;
+ selclear();
+ sel.mode = SEL_EMPTY;
+ sel.type = SEL_REGULAR;
+ sel.snap = snap;
+ sel.oe.x = sel.ob.x = col;
+ sel.oe.y = sel.ob.y = row;
+ selnormalize();
- return LIMIT(y, 0, term.row-1);
+ if (sel.snap != 0)
+ sel.mode = SEL_READY;
+ tsetdirt(sel.nb.y, sel.ne.y);
}
-int
-tlinelen(int y)
+void
+selextend(int col, int row, int type, int done)
{
- int i = term.col;
+ int oldey, oldex, oldsby, oldsey, oldtype;
- if (TLINE(y)[i - 1].mode & ATTR_WRAP)
- return i;
+ if (sel.mode == SEL_IDLE)
+ return;
+ if (done && sel.mode == SEL_EMPTY) {
+ selclear();
+ return;
+ }
- while (i > 0 && TLINE(y)[i - 1].u == ' ')
- --i;
+ oldey = sel.oe.y;
+ oldex = sel.oe.x;
+ oldsby = sel.nb.y;
+ oldsey = sel.ne.y;
+ oldtype = sel.type;
- return i;
+ sel.alt = IS_SET(MODE_ALTSCREEN);
+ sel.oe.x = col;
+ sel.oe.y = row;
+ selnormalize();
+ sel.type = type;
+
+ if (oldey != sel.oe.y || oldex != sel.oe.x || oldtype != sel.type)
+ tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey));
+
+ sel.mode = done ? SEL_IDLE : SEL_READY;
}
void
@@ -805,7 +520,8 @@ selnormalize(void)
int
selected(int x, int y)
{
- if (sel.mode == SEL_EMPTY)
+ if (sel.mode == SEL_EMPTY || sel.ob.x == -1 ||
+ sel.alt != IS_SET(MODE_ALTSCREEN))
return 0;
if (sel.type == SEL_RECTANGULAR)
@@ -890,150 +606,6 @@ selsnap(int *x, int *y, int direction)
}
}
-void
-getbuttoninfo(XEvent *e)
-{
- int type;
- uint state = e->xbutton.state & ~(Button1Mask | forceselmod);
-
- sel.alt = IS_SET(MODE_ALTSCREEN);
-
- sel.oe.x = x2col(e->xbutton.x);
- sel.oe.y = y2row(e->xbutton.y);
- selnormalize();
-
- sel.type = SEL_REGULAR;
- for (type = 1; type < LEN(selmasks); ++type) {
- if (match(selmasks[type], state)) {
- sel.type = type;
- break;
- }
- }
-}
-
-void
-mousereport(XEvent *e)
-{
- int x = x2col(e->xbutton.x), y = y2row(e->xbutton.y),
- button = e->xbutton.button, state = e->xbutton.state,
- len;
- char buf[40];
- static int ox, oy;
-
- /* from urxvt */
- if (e->xbutton.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)
- return;
-
- button = oldbutton + 32;
- ox = x;
- oy = y;
- } else {
- if (!IS_SET(MODE_MOUSESGR) && e->xbutton.type == ButtonRelease) {
- button = 3;
- } else {
- button -= Button1;
- if (button >= 3)
- button += 64 - 3;
- }
- if (e->xbutton.type == ButtonPress) {
- oldbutton = button;
- ox = x;
- oy = y;
- } else if (e->xbutton.type == ButtonRelease) {
- oldbutton = 3;
- /* MODE_MOUSEX10: no button release reporting */
- if (IS_SET(MODE_MOUSEX10))
- return;
- if (button == 64 || button == 65)
- return;
- }
- }
-
- if (!IS_SET(MODE_MOUSEX10)) {
- button += ((state & ShiftMask ) ? 4 : 0)
- + ((state & Mod4Mask ) ? 8 : 0)
- + ((state & ControlMask) ? 16 : 0);
- }
-
- if (IS_SET(MODE_MOUSESGR)) {
- len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c",
- button, x+1, y+1,
- e->xbutton.type == ButtonRelease ? 'm' : 'M');
- } else if (x < 223 && y < 223) {
- len = snprintf(buf, sizeof(buf), "\033[M%c%c%c",
- 32+button, 32+x+1, 32+y+1);
- } else {
- return;
- }
-
- ttywrite(buf, len);
-}
-
-void
-bpress(XEvent *e)
-{
- struct timespec now;
- MouseShortcut *ms;
- MouseKey *mk;
-
- if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
- mousereport(e);
- return;
- }
-
- for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) {
- if (e->xbutton.button == ms->b
- && match(ms->mask, e->xbutton.state)) {
- ttysend(ms->s, strlen(ms->s));
- 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 (e->xbutton.button == Button1) {
- clock_gettime(CLOCK_MONOTONIC, &now);
-
- /* Clear previous selection, logically and visually. */
- selclear(NULL);
- sel.mode = SEL_EMPTY;
- sel.type = SEL_REGULAR;
- sel.oe.x = sel.ob.x = x2col(e->xbutton.x);
- sel.oe.y = sel.ob.y = y2row(e->xbutton.y);
-
- /*
- * If the user clicks below predefined timeouts specific
- * snapping behaviour is exposed.
- */
- if (TIMEDIFF(now, sel.tclick2) <= tripleclicktimeout) {
- sel.snap = SNAP_LINE;
- } else if (TIMEDIFF(now, sel.tclick1) <= doubleclicktimeout) {
- sel.snap = SNAP_WORD;
- } else {
- sel.snap = 0;
- }
- selnormalize();
-
- if (sel.snap != 0)
- sel.mode = SEL_READY;
- tsetdirt(sel.nb.y, sel.ne.y);
- sel.tclick2 = sel.tclick1;
- sel.tclick1 = now;
- }
-}
-
char *
getsel(void)
{
@@ -1089,148 +661,7 @@ getsel(void)
}
void
-selcopy(Time t)
-{
- xsetsel(getsel(), t);
-}
-
-void
-propnotify(XEvent *e)
-{
- XPropertyEvent *xpev;
- Atom clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
-
- xpev = &e->xproperty;
- if (xpev->state == PropertyNewValue &&
- (xpev->atom == XA_PRIMARY ||
- xpev->atom == clipboard)) {
- selnotify(e);
- }
-}
-
-void
-selnotify(XEvent *e)
-{
- ulong nitems, ofs, rem;
- int format;
- uchar *data, *last, *repl;
- Atom type, incratom, property;
-
- incratom = XInternAtom(xw.dpy, "INCR", 0);
-
- ofs = 0;
- if (e->type == SelectionNotify) {
- property = e->xselection.property;
- } else if(e->type == PropertyNotify) {
- property = e->xproperty.atom;
- } else {
- return;
- }
- if (property == None)
- return;
-
- do {
- if (XGetWindowProperty(xw.dpy, xw.win, property, ofs,
- BUFSIZ/4, False, AnyPropertyType,
- &type, &format, &nitems, &rem,
- &data)) {
- fprintf(stderr, "Clipboard allocation failed\n");
- return;
- }
-
- if (e->type == PropertyNotify && nitems == 0 && rem == 0) {
- /*
- * If there is some PropertyNotify with no data, then
- * this is the signal of the selection owner that all
- * data has been transferred. We won't need to receive
- * PropertyNotify events anymore.
- */
- MODBIT(xw.attrs.event_mask, 0, PropertyChangeMask);
- XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask,
- &xw.attrs);
- }
-
- if (type == incratom) {
- /*
- * Activate the PropertyNotify events so we receive
- * when the selection owner does send us the next
- * chunk of data.
- */
- MODBIT(xw.attrs.event_mask, 1, PropertyChangeMask);
- XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask,
- &xw.attrs);
-
- /*
- * Deleting the property is the transfer start signal.
- */
- XDeleteProperty(xw.dpy, xw.win, (int)property);
- continue;
- }
-
- /*
- * 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);
- ttysend((char *)data, nitems * format / 8);
- if (IS_SET(MODE_BRCKTPASTE) && rem == 0)
- ttywrite("\033[201~", 6);
- XFree(data);
- /* number of 32-bit chunks returned */
- ofs += nitems * format / 32;
- } while (rem > 0);
-
- /*
- * Deleting the property again tells the selection owner to send the
- * next data chunk in the property.
- */
- XDeleteProperty(xw.dpy, xw.win, (int)property);
-}
-
-void
-selpaste(const Arg *dummy)
-{
- XConvertSelection(xw.dpy, XA_PRIMARY, sel.xtarget, XA_PRIMARY,
- xw.win, CurrentTime);
-}
-
-void
-clipcopy(const Arg *dummy)
-{
- Atom clipboard;
-
- if (sel.clipboard != NULL)
- free(sel.clipboard);
-
- if (sel.primary != NULL) {
- sel.clipboard = xstrdup(sel.primary);
- clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
- XSetSelectionOwner(xw.dpy, clipboard, xw.win, CurrentTime);
- }
-}
-
-void
-clippaste(const Arg *dummy)
-{
- Atom clipboard;
-
- clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
- XConvertSelection(xw.dpy, clipboard, sel.xtarget, clipboard,
- xw.win, CurrentTime);
-}
-
-void
-selclear(XEvent *e)
+selclear(void)
{
if (sel.ob.x == -1)
return;
@@ -1240,122 +671,6 @@ selclear(XEvent *e)
}
void
-selrequest(XEvent *e)
-{
- XSelectionRequestEvent *xsre;
- XSelectionEvent xev;
- Atom xa_targets, string, clipboard;
- char *seltext;
-
- xsre = (XSelectionRequestEvent *) e;
- xev.type = SelectionNotify;
- xev.requestor = xsre->requestor;
- xev.selection = xsre->selection;
- xev.target = xsre->target;
- xev.time = xsre->time;
- if (xsre->property == None)
- xsre->property = xsre->target;
-
- /* reject */
- xev.property = None;
-
- xa_targets = XInternAtom(xw.dpy, "TARGETS", 0);
- if (xsre->target == xa_targets) {
- /* respond with the supported type */
- string = sel.xtarget;
- XChangeProperty(xsre->display, xsre->requestor, xsre->property,
- XA_ATOM, 32, PropModeReplace,
- (uchar *) &string, 1);
- xev.property = xsre->property;
- } else if (xsre->target == sel.xtarget || xsre->target == XA_STRING) {
- /*
- * xith XA_STRING non ascii characters may be incorrect in the
- * requestor. It is not our problem, use utf8.
- */
- clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
- if (xsre->selection == XA_PRIMARY) {
- seltext = sel.primary;
- } else if (xsre->selection == clipboard) {
- seltext = sel.clipboard;
- } else {
- fprintf(stderr,
- "Unhandled clipboard selection 0x%lx\n",
- xsre->selection);
- return;
- }
- if (seltext != NULL) {
- XChangeProperty(xsre->display, xsre->requestor,
- xsre->property, xsre->target,
- 8, PropModeReplace,
- (uchar *)seltext, strlen(seltext));
- xev.property = xsre->property;
- }
- }
-
- /* all done, send a notification to the listener */
- if (!XSendEvent(xsre->display, xsre->requestor, 1, 0, (XEvent *) &xev))
- fprintf(stderr, "Error sending SelectionNotify event\n");
-}
-
-void
-xsetsel(char *str, Time t)
-{
- free(sel.primary);
- sel.primary = str;
-
- XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t);
- if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win)
- selclear(0);
-
- clipcopy(NULL);
-}
-
-void
-brelease(XEvent *e)
-{
- if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
- mousereport(e);
- return;
- }
-
- if (e->xbutton.button == Button2) {
- selpaste(NULL);
- } else if (e->xbutton.button == Button1) {
- if (sel.mode == SEL_READY) {
- getbuttoninfo(e);
- selcopy(e->xbutton.time);
- } else
- selclear(NULL);
- sel.mode = SEL_IDLE;
- tsetdirt(sel.nb.y, sel.ne.y);
- }
-}
-
-void
-bmotion(XEvent *e)
-{
- int oldey, oldex, oldsby, oldsey;
-
- if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
- mousereport(e);
- return;
- }
-
- if (!sel.mode)
- return;
-
- sel.mode = SEL_READY;
- oldey = sel.oe.y;
- oldex = sel.oe.x;
- oldsby = sel.nb.y;
- oldsey = sel.ne.y;
- getbuttoninfo(e);
-
- if (oldey != sel.oe.y || oldex != sel.oe.x)
- tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey));
-}
-
-void
die(const char *errstr, ...)
{
va_list ap;
@@ -1367,11 +682,10 @@ die(const char *errstr, ...)
}
void
-execsh(void)
+execsh(char *cmd, char **args)
{
- char **args, *sh, *prog;
+ char *sh, *prog;
const struct passwd *pw;
- char buf[sizeof(long) * 8 + 1];
errno = 0;
if ((pw = getpwuid(getuid())) == NULL) {
@@ -1382,17 +696,15 @@ execsh(void)
}
if ((sh = getenv("SHELL")) == NULL)
- sh = (pw->pw_shell[0]) ? pw->pw_shell : shell;
+ sh = (pw->pw_shell[0]) ? pw->pw_shell : cmd;
- if (opt_cmd)
- prog = opt_cmd[0];
+ if (args)
+ prog = args[0];
else if (utmp)
prog = utmp;
else
prog = sh;
- args = (opt_cmd) ? opt_cmd : (char *[]) {prog, NULL};
-
- snprintf(buf, sizeof(buf), "%lu", xw.win);
+ DEFAULT(args, ((char *[]) {prog, NULL}));
unsetenv("COLUMNS");
unsetenv("LINES");
@@ -1402,7 +714,6 @@ execsh(void)
setenv("SHELL", sh, 1);
setenv("HOME", pw->pw_dir, 1);
setenv("TERM", termname, 1);
- setenv("WINDOWID", buf, 1);
signal(SIGCHLD, SIG_DFL);
signal(SIGHUP, SIG_DFL);
@@ -1432,9 +743,8 @@ sigchld(int a)
exit(0);
}
-
void
-stty(void)
+stty(char **args)
{
char cmd[_POSIX_ARG_MAX], **p, *q, *s;
size_t n, siz;
@@ -1444,7 +754,7 @@ stty(void)
memcpy(cmd, stty_args, n);
q = cmd + n;
siz = sizeof(cmd) - n;
- for (p = opt_cmd; p && (s = *p); ++p) {
+ for (p = args; p && (s = *p); ++p) {
if ((n = strlen(s)) > siz-1)
die("stty parameter length too long\n");
*q++ = ' ';
@@ -1454,35 +764,34 @@ stty(void)
}
*q = '\0';
if (system(cmd) != 0)
- perror("Couldn't call stty");
+ perror("Couldn't call stty");
}
-void
-ttynew(void)
+int
+ttynew(char *line, char *cmd, char *out, char **args)
{
int m, s;
- struct winsize w = {term.row, term.col, 0, 0};
- if (opt_io) {
+ if (out) {
term.mode |= MODE_PRINT;
- iofd = (!strcmp(opt_io, "-")) ?
- 1 : open(opt_io, O_WRONLY | O_CREAT, 0666);
+ iofd = (!strcmp(out, "-")) ?
+ 1 : open(out, O_WRONLY | O_CREAT, 0666);
if (iofd < 0) {
fprintf(stderr, "Error opening %s:%s\n",
- opt_io, strerror(errno));
+ out, strerror(errno));
}
}
- if (opt_line) {
- if ((cmdfd = open(opt_line, O_RDWR)) < 0)
+ if (line) {
+ if ((cmdfd = open(line, O_RDWR)) < 0)
die("open line failed: %s\n", strerror(errno));
dup2(cmdfd, 0);
- stty();
- return;
+ stty(args);
+ return cmdfd;
}
/* seems to work fine on linux, openbsd and freebsd */
- if (openpty(&m, &s, NULL, NULL, &w) < 0)
+ if (openpty(&m, &s, NULL, NULL, NULL) < 0)
die("openpty failed: %s\n", strerror(errno));
switch (pid = fork()) {
@@ -1499,7 +808,7 @@ ttynew(void)
die("ioctl TIOCSCTTY failed: %s\n", strerror(errno));
close(s);
close(m);
- execsh();
+ execsh(cmd, args);
break;
default:
close(s);
@@ -1507,6 +816,7 @@ ttynew(void)
signal(SIGCHLD, sigchld);
break;
}
+ return cmdfd;
}
size_t
@@ -1514,55 +824,64 @@ ttyread(void)
{
static char buf[BUFSIZ];
static int buflen = 0;
- char *ptr;
- int charsize; /* size of utf8 char in bytes */
- Rune unicodep;
+ int written;
int ret;
/* 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;
- ptr = buf;
-
- for (;;) {
- if (IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) {
- /* process a complete utf8 char */
- charsize = utf8decode(ptr, &unicodep, buflen);
- if (charsize == 0)
- break;
- tputc(unicodep);
- ptr += charsize;
- buflen -= charsize;
- } else {
- if (buflen <= 0)
- break;
- tputc(*ptr++ & 0xFF);
- buflen--;
- }
- }
+ written = twrite(buf, buflen, 0);
+ buflen -= written;
/* keep any uncomplete utf8 char for the next call */
if (buflen > 0)
- memmove(buf, ptr, buflen);
+ memmove(buf, buf + written, buflen);
- if (term.scr > 0 && term.scr < histsize-1)
+ if (term.scr > 0 && term.scr < HISTSIZE-1)
term.scr++;
return ret;
}
void
-ttywrite(const char *s, size_t n)
+ttywrite(const char *s, size_t n, int may_echo)
{
- fd_set wfd, rfd;
- ssize_t r;
- size_t lim = 256;
+ const char *next;
Arg arg = (Arg) { .i = term.scr };
kscrolldown(&arg);
+ if (may_echo && IS_SET(MODE_ECHO))
+ twrite(s, n, 1);
+
+ if (!IS_SET(MODE_CRLF)) {
+ ttywriteraw(s, n);
+ return;
+ }
+
+ /* This is similar to how the kernel handles ONLCR for ttys */
+ while (n > 0) {
+ if (*s == '\r') {
+ next = s + 1;
+ ttywriteraw("\r\n", 2);
+ } else {
+ next = memchr(s, '\r', n);
+ DEFAULT(next, s + n);
+ ttywriteraw(s, next - s);
+ }
+ n -= next - s;
+ s = next;
+ }
+}
+
+void
+ttywriteraw(const char *s, size_t n)
+{
+ fd_set wfd, rfd;
+ ssize_t r;
+ size_t lim = 256;
+
/*
* Remember that we are using a pty, which might be a modem line.
* Writing too much will clog the line. That's why we are doing this
@@ -1614,44 +933,25 @@ write_error:
}
void
-ttysend(char *s, size_t n)
-{
- int len;
- char *t, *lim;
- Rune u;
-
- ttywrite(s, n);
- if (!IS_SET(MODE_ECHO))
- return;
-
- lim = &s[n];
- for (t = s; t < lim; t += len) {
- if (IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) {
- len = utf8decode(t, &u, n);
- } else {
- u = *t & 0xFF;
- len = 1;
- }
- if (len <= 0)
- break;
- techo(u);
- n -= len;
- }
-}
-
-void
-ttyresize(void)
+ttyresize(int tw, int th)
{
struct winsize w;
w.ws_row = term.row;
w.ws_col = term.col;
- w.ws_xpixel = xw.tw;
- w.ws_ypixel = xw.th;
+ w.ws_xpixel = tw;
+ w.ws_ypixel = th;
if (ioctl(cmdfd, TIOCSWINSZ, &w) < 0)
fprintf(stderr, "Couldn't set window size: %s\n", strerror(errno));
}
+void
+ttyhangup()
+{
+ /* Send SIGHUP to shell */
+ kill(pid, SIGHUP);
+}
+
int
tattrset(int attr)
{
@@ -1747,8 +1047,6 @@ tnew(int col, int row)
{
term = (Term){ .c = { .attr = { .fg = defaultfg, .bg = defaultbg } } };
tresize(col, row);
- term.numlock = 1;
-
treset();
}
@@ -1789,13 +1087,14 @@ kscrollup(const Arg* a)
if (n < 0)
n = term.row + n;
- if (term.scr <= histsize - n) {
+ if (term.scr <= HISTSIZE-n) {
term.scr += n;
selscroll(0, n);
tfulldirt();
}
}
+
void
tscrolldown(int orig, int n, int copyhist)
{
@@ -1805,7 +1104,7 @@ tscrolldown(int orig, int n, int copyhist)
LIMIT(n, 0, term.bot-orig+1);
if (copyhist) {
- term.histi = (term.histi - 1 + histsize) % histsize;
+ 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;
@@ -1832,7 +1131,7 @@ tscrollup(int orig, int n, int copyhist)
LIMIT(n, 0, term.bot-orig+1);
if (copyhist) {
- term.histi = (term.histi + 1) % histsize;
+ term.histi = (term.histi + 1) % HISTSIZE;
temp = term.hist[term.histi];
term.hist[term.histi] = term.line[orig];
term.line[orig] = temp;
@@ -1858,7 +1157,7 @@ selscroll(int orig, int n)
if (BETWEEN(sel.ob.y, orig, term.bot) || BETWEEN(sel.oe.y, orig, term.bot)) {
if ((sel.ob.y += n) > term.bot || (sel.oe.y += n) < term.top) {
- selclear(NULL);
+ selclear();
return;
}
if (sel.type == SEL_RECTANGULAR) {
@@ -2004,7 +1303,7 @@ tclearregion(int x1, int y1, int x2, int y2)
for (x = x1; x <= x2; x++) {
gp = &term.line[y][x];
if (selected(x, y))
- selclear(NULL);
+ selclear();
gp->fg = term.c.attr.fg;
gp->bg = term.c.attr.bg;
gp->mode = 0;
@@ -2231,20 +1530,16 @@ tsetscroll(int t, int b)
void
tsetmode(int priv, int set, int *args, int narg)
{
- int *lim, mode;
- int alt;
+ int alt, *lim;
for (lim = args + narg; args < lim; ++args) {
if (priv) {
switch (*args) {
case 1: /* DECCKM -- Cursor key */
- MODBIT(term.mode, set, MODE_APPCURSOR);
+ xsetmode(set, MODE_APPCURSOR);
break;
case 5: /* DECSCNM -- Reverse video */
- mode = term.mode;
- MODBIT(term.mode, set, MODE_REVERSE);
- if (mode != term.mode)
- redraw();
+ xsetmode(set, MODE_REVERSE);
break;
case 6: /* DECOM -- Origin */
MODBIT(term.c.state, set, CURSOR_ORIGIN);
@@ -2264,36 +1559,36 @@ tsetmode(int priv, int set, int *args, int narg)
case 12: /* att610 -- Start blinking cursor (IGNORED) */
break;
case 25: /* DECTCEM -- Text Cursor Enable Mode */
- MODBIT(term.mode, !set, MODE_HIDE);
+ xsetmode(!set, MODE_HIDE);
break;
case 9: /* X10 mouse compatibility mode */
xsetpointermotion(0);
- MODBIT(term.mode, 0, MODE_MOUSE);
- MODBIT(term.mode, set, MODE_MOUSEX10);
+ xsetmode(0, MODE_MOUSE);
+ xsetmode(set, MODE_MOUSEX10);
break;
case 1000: /* 1000: report button press */
xsetpointermotion(0);
- MODBIT(term.mode, 0, MODE_MOUSE);
- MODBIT(term.mode, set, MODE_MOUSEBTN);
+ xsetmode(0, MODE_MOUSE);
+ xsetmode(set, MODE_MOUSEBTN);
break;
case 1002: /* 1002: report motion on button press */
xsetpointermotion(0);
- MODBIT(term.mode, 0, MODE_MOUSE);
- MODBIT(term.mode, set, MODE_MOUSEMOTION);
+ xsetmode(0, MODE_MOUSE);
+ xsetmode(set, MODE_MOUSEMOTION);
break;
case 1003: /* 1003: enable all mouse motions */
xsetpointermotion(set);
- MODBIT(term.mode, 0, MODE_MOUSE);
- MODBIT(term.mode, set, MODE_MOUSEMANY);
+ xsetmode(0, MODE_MOUSE);
+ xsetmode(set, MODE_MOUSEMANY);
break;
case 1004: /* 1004: send focus events to tty */
- MODBIT(term.mode, set, MODE_FOCUS);
+ xsetmode(set, MODE_FOCUS);
break;
case 1006: /* 1006: extended reporting mode */
- MODBIT(term.mode, set, MODE_MOUSESGR);
+ xsetmode(set, MODE_MOUSESGR);
break;
case 1034:
- MODBIT(term.mode, set, MODE_8BIT);
+ xsetmode(set, MODE_8BIT);
break;
case 1049: /* swap screen & set/restore cursor as xterm */
if (!allowaltscreen)
@@ -2318,7 +1613,7 @@ tsetmode(int priv, int set, int *args, int narg)
tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
break;
case 2004: /* 2004: bracketed paste mode */
- MODBIT(term.mode, set, MODE_BRCKTPASTE);
+ xsetmode(set, MODE_BRCKTPASTE);
break;
/* Not implemented mouse modes. See comments there. */
case 1001: /* mouse highlight mode; can hang the
@@ -2339,8 +1634,8 @@ tsetmode(int priv, int set, int *args, int narg)
switch (*args) {
case 0: /* Error (IGNORED) */
break;
- case 2: /* KAM -- keyboard action */
- MODBIT(term.mode, set, MODE_KBDLOCK);
+ case 2:
+ xsetmode(set, MODE_KBDLOCK);
break;
case 4: /* IRM -- Insertion-replacement */
MODBIT(term.mode, set, MODE_INSERT);
@@ -2408,7 +1703,7 @@ csihandle(void)
break;
case 'c': /* DA -- Device Attributes */
if (csiescseq.arg[0] == 0)
- ttywrite(vtiden, sizeof(vtiden) - 1);
+ ttywrite(vtiden, strlen(vtiden), 0);
break;
case 'C': /* CUF -- Cursor <n> Forward */
case 'a': /* HPR -- Cursor <n> Forward */
@@ -2455,7 +1750,6 @@ csihandle(void)
tputtab(csiescseq.arg[0]);
break;
case 'J': /* ED -- Clear screen */
- selclear(NULL);
switch (csiescseq.arg[0]) {
case 0: /* below */
tclearregion(term.c.x, term.c.y, term.col-1, term.c.y);
@@ -2536,7 +1830,7 @@ csihandle(void)
if (csiescseq.arg[0] == 6) {
len = snprintf(buf, sizeof(buf),"\033[%i;%iR",
term.c.y+1, term.c.x+1);
- ttywrite(buf, len);
+ ttywrite(buf, len, 0);
}
break;
case 'r': /* DECSTBM -- Set Scrolling Region */
@@ -2558,11 +1852,8 @@ csihandle(void)
case ' ':
switch (csiescseq.mode[1]) {
case 'q': /* DECSCUSR -- Set Cursor Style */
- DEFAULT(csiescseq.arg[0], 1);
- if (!BETWEEN(csiescseq.arg[0], 0, 6)) {
+ if (xsetcursor(csiescseq.arg[0]))
goto unknown;
- }
- xw.cursor = csiescseq.arg[0];
break;
default:
goto unknown;
@@ -2620,6 +1911,19 @@ strhandle(void)
if (narg > 1)
xsettitle(strescseq.args[1]);
return;
+ case 52:
+ if (narg > 2) {
+ char *dec;
+
+ dec = base64dec(strescseq.args[2]);
+ if (dec) {
+ xsetsel(dec);
+ xclipcopy();
+ } else {
+ fprintf(stderr, "erresc: invalid base64\n");
+ }
+ }
+ return;
case 4: /* color set */
if (narg < 3)
break;
@@ -2719,8 +2023,7 @@ void
tprinter(char *s, size_t len)
{
if (iofd != -1 && xwrite(iofd, s, len) < 0) {
- fprintf(stderr, "Error writing in %s:%s\n",
- opt_io, strerror(errno));
+ perror("Error writing to output file");
close(iofd);
iofd = -1;
}
@@ -2729,13 +2032,11 @@ tprinter(char *s, size_t len)
void
iso14755(const Arg *arg)
{
- char cmd[sizeof(ISO14755CMD) + NUMMAXLEN(xw.win)];
FILE *p;
char *us, *e, codepoint[9], uc[UTF_SIZ];
unsigned long utf32;
- snprintf(cmd, sizeof(cmd), ISO14755CMD, xw.win);
- if (!(p = popen(cmd, "r")))
+ if (!(p = popen(ISO14755CMD, "r")))
return;
us = fgets(codepoint, sizeof(codepoint), p);
@@ -2747,7 +2048,7 @@ iso14755(const Arg *arg)
(*e != '\n' && *e != '\0'))
return;
- ttysend(uc, utf8encode(utf32, uc));
+ ttywrite(uc, utf8encode(utf32, uc), 1);
}
void
@@ -2821,22 +2122,6 @@ tputtab(int n)
}
void
-techo(Rune u)
-{
- if (ISCONTROL(u)) { /* control code */
- if (u & 0x80) {
- u &= 0x7f;
- tputc('^');
- tputc('[');
- } else if (u != '\n' && u != '\r' && u != '\t') {
- u ^= 0x40;
- tputc('^');
- }
- }
- tputc(u);
-}
-
-void
tdefutf8(char ascii)
{
if (ascii == 'G')
@@ -2920,10 +2205,7 @@ tcontrolcode(uchar ascii)
/* backwards compatibility to xterm */
strhandle();
} else {
- if (!(xw.state & WIN_FOCUSED))
- xseturgency(1);
- if (bellvolume)
- XkbBell(xw.dpy, xw.win, bellvolume, (Atom)NULL);
+ xbell();
}
break;
case '\033': /* ESC */
@@ -2979,7 +2261,7 @@ tcontrolcode(uchar ascii)
case 0x99: /* TODO: SGCI */
break;
case 0x9a: /* DECID -- Identify Terminal */
- ttywrite(vtiden, sizeof(vtiden) - 1);
+ ttywrite(vtiden, strlen(vtiden), 0);
break;
case 0x9b: /* TODO: CSI */
case 0x9c: /* TODO: ST */
@@ -3051,18 +2333,18 @@ eschandle(uchar ascii)
}
break;
case 'Z': /* DECID -- Identify Terminal */
- ttywrite(vtiden, sizeof(vtiden) - 1);
+ ttywrite(vtiden, strlen(vtiden), 0);
break;
case 'c': /* RIS -- Reset to inital state */
treset();
- xresettitle();
+ resettitle();
xloadcols();
break;
case '=': /* DECPAM -- Application keypad */
- term.mode |= MODE_APPKEYPAD;
+ xsetmode(1, MODE_APPKEYPAD);
break;
case '>': /* DECPNM -- Normal keypad */
- term.mode &= ~MODE_APPKEYPAD;
+ xsetmode(0, MODE_APPKEYPAD);
break;
case '7': /* DECSC -- Save Cursor */
tcursor(CURSOR_SAVE);
@@ -3196,7 +2478,7 @@ check_control_code:
return;
}
if (sel.ob.x != -1 && BETWEEN(term.c.y, sel.ob.y, sel.oe.y))
- selclear(NULL);
+ selclear();
gp = &term.line[term.c.y][term.c.x];
if (IS_SET(MODE_WRAP) && (term.c.state & CURSOR_WRAPNEXT)) {
@@ -3229,6 +2511,38 @@ check_control_code:
}
}
+int
+twrite(const char *buf, int buflen, int show_ctrl)
+{
+ int charsize;
+ Rune u;
+ int n;
+
+ for (n = 0; n < buflen; n += charsize) {
+ if (IS_SET(MODE_UTF8) && !IS_SET(MODE_SIXEL)) {
+ /* process a complete utf8 char */
+ charsize = utf8decode(buf + n, &u, buflen - n);
+ if (charsize == 0)
+ break;
+ } else {
+ u = buf[n] & 0xFF;
+ charsize = 1;
+ }
+ if (show_ctrl && ISCONTROL(u)) {
+ if (u & 0x80) {
+ u &= 0x7f;
+ tputc('^');
+ tputc('[');
+ } else if (u != '\n' && u != '\r' && u != '\t') {
+ u ^= 0x40;
+ tputc('^');
+ }
+ }
+ tputc(u);
+ }
+ return n;
+}
+
void
tresize(int col, int row)
{
@@ -3263,16 +2577,13 @@ tresize(int col, int row)
free(term.alt[i]);
}
- /* resize to new width */
- term.specbuf = xrealloc(term.specbuf, col * sizeof(XftGlyphFontSpec));
-
/* resize to new height */
term.line = xrealloc(term.line, row * sizeof(Line));
term.alt = xrealloc(term.alt, row * sizeof(Line));
term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty));
term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs));
- for (i = 0; i < histsize; i++) {
+ 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;
@@ -3280,14 +2591,14 @@ tresize(int col, int row)
}
}
- /* resize each row to new width, zero-pad if needed */
+ /* resize each r w to new width, zero-pad if needed */
for (i = 0; i < minrow; i++) {
term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph));
term.alt[i] = xrealloc(term.alt[i], col * sizeof(Glyph));
}
/* allocate any new rows */
- for (/* i == minrow */; i < row; i++) {
+ for (/* i = minrow */; i < row; i++) {
term.line[i] = xmalloc(col * sizeof(Glyph));
term.alt[i] = xmalloc(col * sizeof(Glyph));
}
@@ -3323,1379 +2634,52 @@ tresize(int col, int row)
}
void
-xresize(int col, int row)
-{
- xw.tw = MAX(1, col * xw.cw);
- xw.th = MAX(1, row * xw.ch);
-
- XFreePixmap(xw.dpy, xw.buf);
- xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.w, xw.h,
- xw.depth);
- XftDrawChange(xw.draw, xw.buf);
- xclear(0, 0, xw.w, xw.h);
-}
-
-ushort
-sixd_to_16bit(int x)
+resettitle(void)
{
- return x == 0 ? 0 : 0x3737 + 0x2828 * x;
-}
-
-const char* getcolorname(int i)
-{
- return (usealtcolors) ? altcolorname[i] : colorname[i];
-}
-
-int
-xloadcolor(int i, const char *name, Color *ncolor)
-{
- XRenderColor color = { .alpha = 0xffff };
-
- if (!name) {
- if (BETWEEN(i, 16, 255)) { /* 256 color */
- if (i < 6*6*6+16) { /* same colors as xterm */
- color.red = sixd_to_16bit( ((i-16)/36)%6 );
- color.green = sixd_to_16bit( ((i-16)/6) %6 );
- color.blue = sixd_to_16bit( ((i-16)/1) %6 );
- } else { /* greyscale */
- color.red = 0x0808 + 0x0a0a * (i - (6*6*6+16));
- color.green = color.blue = color.red;
- }
- return XftColorAllocValue(xw.dpy, xw.vis,
- xw.cmap, &color, ncolor);
- } else
- name = getcolorname(i);
- }
-
- return XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, ncolor);
-}
-
-void
-xloadcols(void)
-{
- int i;
- static int loaded;
- Color *cp;
-
- if (loaded) {
- for (cp = dc.col; cp < &dc.col[LEN(dc.col)]; ++cp)
- XftColorFree(xw.dpy, xw.vis, xw.cmap, cp);
- }
-
- for (i = 0; i < LEN(dc.col); i++)
- if (!xloadcolor(i, NULL, &dc.col[i])) {
- if (getcolorname(i))
- die("Could not allocate color '%s'\n", getcolorname(i));
- else
- die("Could not allocate color %d\n", i);
- }
-
- /* set alpha value of bg color */
- if (USE_ARGB) {
- dc.col[defaultbg].color.alpha = (0xffff * alpha) / OPAQUE; //0xcccc;
- dc.col[defaultbg].pixel &= 0x00111111;
- dc.col[defaultbg].pixel |= alpha << 24; // 0xcc000000;
- }
-
- loaded = 1;
-}
-
-int
-xsetcolorname(int x, const char *name)
-{
- Color ncolor;
-
- if (!BETWEEN(x, 0, LEN(dc.col)))
- return 1;
-
-
- if (!xloadcolor(x, name, &ncolor))
- return 1;
-
- XftColorFree(xw.dpy, xw.vis, xw.cmap, &dc.col[x]);
- dc.col[x] = ncolor;
-
- return 0;
-}
-void
-xtermclear(int col1, int row1, int col2, int row2) {
- XftDrawRect(xw.draw,
- &dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg],
- borderpx + col1 * xw.cw,
- borderpx + row1 * xw.ch,
- (col2-col1+1) * xw.cw,
- (row2-row1+1) * xw.ch);
-}
-
-/*
- * Absolute coordinates.
- */
-void
-xclear(int x1, int y1, int x2, int y2)
-{
- XftDrawRect(xw.draw,
- &dc.col[IS_SET(MODE_REVERSE)? defaultfg : defaultbg],
- x1, y1, x2-x1, y2-y1);
-}
-
-void
-xhints(void)
-{
- XClassHint class = {opt_name ? opt_name : termname,
- opt_class ? opt_class : termname};
- XWMHints wm = {.flags = InputHint, .input = 1};
- XSizeHints *sizeh = NULL;
-
- sizeh = XAllocSizeHints();
-
- sizeh->flags = PSize | PResizeInc | PBaseSize;
- sizeh->height = xw.h;
- sizeh->width = xw.w;
- sizeh->height_inc = xw.ch;
- sizeh->width_inc = xw.cw;
- sizeh->base_height = 2 * borderpx;
- sizeh->base_width = 2 * borderpx;
- if (xw.isfixed) {
- sizeh->flags |= PMaxSize | PMinSize;
- sizeh->min_width = sizeh->max_width = xw.w;
- sizeh->min_height = sizeh->max_height = xw.h;
- }
- if (xw.gm & (XValue|YValue)) {
- sizeh->flags |= USPosition | PWinGravity;
- sizeh->x = xw.l;
- sizeh->y = xw.t;
- sizeh->win_gravity = xgeommasktogravity(xw.gm);
- }
-
- XSetWMProperties(xw.dpy, xw.win, NULL, NULL, NULL, 0, sizeh, &wm,
- &class);
- XFree(sizeh);
-}
-
-int
-xgeommasktogravity(int mask)
-{
- switch (mask & (XNegative|YNegative)) {
- case 0:
- return NorthWestGravity;
- case XNegative:
- return NorthEastGravity;
- case YNegative:
- return SouthWestGravity;
- }
-
- return SouthEastGravity;
-}
-
-int
-xloadfont(Font *f, FcPattern *pattern)
-{
- FcPattern *configured;
- FcPattern *match;
- FcResult result;
- XGlyphInfo extents;
- int wantattr, haveattr;
-
- /*
- * Manually configure instead of calling XftMatchFont
- * so that we can use the configured pattern for
- * "missing glyph" lookups.
- */
- configured = FcPatternDuplicate(pattern);
- if (!configured)
- return 1;
-
- FcConfigSubstitute(NULL, configured, FcMatchPattern);
- XftDefaultSubstitute(xw.dpy, xw.scr, configured);
-
- match = FcFontMatch(NULL, configured, &result);
- if (!match) {
- FcPatternDestroy(configured);
- return 1;
- }
-
- if (!(f->match = XftFontOpenPattern(xw.dpy, match))) {
- FcPatternDestroy(configured);
- FcPatternDestroy(match);
- return 1;
- }
-
- if ((XftPatternGetInteger(pattern, "slant", 0, &wantattr) ==
- XftResultMatch)) {
- /*
- * Check if xft was unable to find a font with the appropriate
- * slant but gave us one anyway. Try to mitigate.
- */
- if ((XftPatternGetInteger(f->match->pattern, "slant", 0,
- &haveattr) != XftResultMatch) || haveattr < wantattr) {
- f->badslant = 1;
- fputs("st: font slant does not match\n", stderr);
- }
- }
-
- if ((XftPatternGetInteger(pattern, "weight", 0, &wantattr) ==
- XftResultMatch)) {
- if ((XftPatternGetInteger(f->match->pattern, "weight", 0,
- &haveattr) != XftResultMatch) || haveattr != wantattr) {
- f->badweight = 1;
- fputs("st: font weight does not match\n", stderr);
- }
- }
-
- XftTextExtentsUtf8(xw.dpy, f->match,
- (const FcChar8 *) ascii_printable,
- strlen(ascii_printable), &extents);
-
- f->set = NULL;
- f->pattern = configured;
-
- f->ascent = f->match->ascent;
- f->descent = f->match->descent;
- f->lbearing = 0;
- f->rbearing = f->match->max_advance_width;
-
- f->height = f->ascent + f->descent;
- f->width = DIVCEIL(extents.xOff, strlen(ascii_printable));
-
- return 0;
-}
-
-void
-xloadfonts(char *fontstr, double fontsize)
-{
- FcPattern *pattern;
- double fontval;
- float ceilf(float);
-
- if (fontstr[0] == '-') {
- pattern = XftXlfdParse(fontstr, False, False);
- } else {
- pattern = FcNameParse((FcChar8 *)fontstr);
- }
-
- if (!pattern)
- die("st: can't open font %s\n", fontstr);
-
- if (fontsize > 1) {
- FcPatternDel(pattern, FC_PIXEL_SIZE);
- FcPatternDel(pattern, FC_SIZE);
- FcPatternAddDouble(pattern, FC_PIXEL_SIZE, (double)fontsize);
- usedfontsize = fontsize;
- } else {
- if (FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &fontval) ==
- FcResultMatch) {
- usedfontsize = fontval;
- } else if (FcPatternGetDouble(pattern, FC_SIZE, 0, &fontval) ==
- FcResultMatch) {
- usedfontsize = -1;
- } else {
- /*
- * Default font size is 12, if none given. This is to
- * have a known usedfontsize value.
- */
- FcPatternAddDouble(pattern, FC_PIXEL_SIZE, 12);
- usedfontsize = 12;
- }
- defaultfontsize = usedfontsize;
- }
-
- if (xloadfont(&dc.font, pattern))
- die("st: can't open font %s\n", fontstr);
-
- if (usedfontsize < 0) {
- FcPatternGetDouble(dc.font.match->pattern,
- FC_PIXEL_SIZE, 0, &fontval);
- usedfontsize = fontval;
- if (fontsize == 0)
- defaultfontsize = fontval;
- }
-
- /* Setting character width and height. */
- xw.cw = ceilf(dc.font.width * cwscale);
- xw.ch = ceilf(dc.font.height * chscale);
- xw.cyo = ceilf(dc.font.height * (chscale - 1) / 2);
-
- FcPatternDel(pattern, FC_SLANT);
- FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
- if (xloadfont(&dc.ifont, pattern))
- die("st: can't open font %s\n", fontstr);
-
- FcPatternDel(pattern, FC_WEIGHT);
- FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
- if (xloadfont(&dc.ibfont, pattern))
- die("st: can't open font %s\n", fontstr);
-
- FcPatternDel(pattern, FC_SLANT);
- FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN);
- if (xloadfont(&dc.bfont, pattern))
- die("st: can't open font %s\n", fontstr);
-
- FcPatternDestroy(pattern);
-}
-
-void
-xunloadfont(Font *f)
-{
- XftFontClose(xw.dpy, f->match);
- FcPatternDestroy(f->pattern);
- if (f->set)
- FcFontSetDestroy(f->set);
-}
-
-void
-xunloadfonts(void)
-{
- /* Free the loaded fonts in the font cache. */
- while (frclen > 0)
- XftFontClose(xw.dpy, frc[--frclen].font);
-
- xunloadfont(&dc.font);
- xunloadfont(&dc.bfont);
- xunloadfont(&dc.ifont);
- xunloadfont(&dc.ibfont);
-}
-
-void
-xzoom(const Arg *arg)
-{
- Arg larg;
-
- larg.f = usedfontsize + arg->f;
- xzoomabs(&larg);
-}
-
-void
-xzoomabs(const Arg *arg)
-{
- xunloadfonts();
- xloadfonts(usedfont, arg->f);
- cresize(0, 0);
- ttyresize();
- redraw();
- xhints();
-}
-
-void
-xzoomreset(const Arg *arg)
-{
- Arg larg;
-
- if (defaultfontsize > 0) {
- larg.f = defaultfontsize;
- xzoomabs(&larg);
- }
-}
-
-void
-xinit(void)
-{
- XGCValues gcvalues;
- Cursor cursor;
- Window parent;
- pid_t thispid = getpid();
- XColor xmousefg, xmousebg;
-
- if (!(xw.dpy = XOpenDisplay(NULL)))
- die("Can't open display\n");
- xw.scr = XDefaultScreen(xw.dpy);
- xw.depth = (USE_ARGB) ? 32: XDefaultDepth(xw.dpy, xw.scr);
- if (! USE_ARGB)
- xw.vis = XDefaultVisual(xw.dpy, xw.scr);
- else {
- XVisualInfo *vis;
- XRenderPictFormat *fmt;
- int nvi;
- int i;
-
- XVisualInfo tpl = {
- .screen = xw.scr,
- .depth = 32,
- .class = TrueColor
- };
-
- vis = XGetVisualInfo(xw.dpy, VisualScreenMask | VisualDepthMask | VisualClassMask, &tpl, &nvi);
- xw.vis = NULL;
- for(i = 0; i < nvi; i ++) {
- fmt = XRenderFindVisualFormat(xw.dpy, vis[i].visual);
- if (fmt->type == PictTypeDirect && fmt->direct.alphaMask) {
- xw.vis = vis[i].visual;
- break;
- }
- }
-
- XFree(vis);
-
- if (! xw.vis) {
- fprintf(stderr, "Couldn't find ARGB visual.\n");
- exit(1);
- }
- }
-
- /* font */
- if (!FcInit())
- die("Could not init fontconfig.\n");
-
- usedfont = (opt_font == NULL)? font : opt_font;
- xloadfonts(usedfont, 0);
-
- /* colors */
- if (! USE_ARGB)
- xw.cmap = XDefaultColormap(xw.dpy, xw.scr);
- else
- xw.cmap = XCreateColormap(xw.dpy, XRootWindow(xw.dpy, xw.scr), xw.vis, None);
- xloadcols();
-
- /* adjust fixed window geometry */
- xw.w = 2 * borderpx + term.col * xw.cw;
- xw.h = 2 * borderpx + term.row * xw.ch;
- if (xw.gm & XNegative)
- xw.l += DisplayWidth(xw.dpy, xw.scr) - xw.w - 2;
- if (xw.gm & YNegative)
- xw.t += DisplayHeight(xw.dpy, xw.scr) - xw.h - 2;
-
- /* Events */
- xw.attrs.background_pixel = dc.col[defaultbg].pixel;
- xw.attrs.border_pixel = dc.col[defaultbg].pixel;
- xw.attrs.bit_gravity = NorthWestGravity;
- xw.attrs.event_mask = FocusChangeMask | KeyPressMask
- | ExposureMask | VisibilityChangeMask | StructureNotifyMask
- | ButtonMotionMask | ButtonPressMask | ButtonReleaseMask;
- xw.attrs.colormap = xw.cmap;
-
- if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0))))
- parent = XRootWindow(xw.dpy, xw.scr);
- xw.win = XCreateWindow(xw.dpy, parent, xw.l, xw.t,
- xw.w, xw.h, 0, xw.depth, InputOutput,
- xw.vis, CWBackPixel | CWBorderPixel | CWBitGravity
- | CWEventMask | CWColormap, &xw.attrs);
-
- memset(&gcvalues, 0, sizeof(gcvalues));
- gcvalues.graphics_exposures = False;
- xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.w, xw.h, xw.depth);
- dc.gc = XCreateGC(xw.dpy,
- (USE_ARGB)? xw.buf: parent,
- GCGraphicsExposures,
- &gcvalues);
- XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel);
- XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, xw.w, xw.h);
-
- /* Xft rendering context */
- xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
-
- /* input methods */
- 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");
- }
- }
- }
- 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");
-
- /* white cursor, black outline */
- cursor = XCreateFontCursor(xw.dpy, mouseshape);
- XDefineCursor(xw.dpy, xw.win, cursor);
-
- if (XParseColor(xw.dpy, xw.cmap, getcolorname(mousefg), &xmousefg) == 0) {
- xmousefg.red = 0xffff;
- xmousefg.green = 0xffff;
- xmousefg.blue = 0xffff;
- }
-
- if (XParseColor(xw.dpy, xw.cmap, getcolorname(mousebg), &xmousebg) == 0) {
- xmousebg.red = 0x0000;
- xmousebg.green = 0x0000;
- xmousebg.blue = 0x0000;
- }
-
- XRecolorCursor(xw.dpy, cursor, &xmousefg, &xmousebg);
-
- 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);
- XSetWMProtocols(xw.dpy, xw.win, &xw.wmdeletewin, 1);
-
- xw.netwmpid = XInternAtom(xw.dpy, "_NET_WM_PID", False);
- XChangeProperty(xw.dpy, xw.win, xw.netwmpid, XA_CARDINAL, 32,
- PropModeReplace, (uchar *)&thispid, 1);
-
- xresettitle();
- XMapWindow(xw.dpy, xw.win);
- xhints();
- XSync(xw.dpy, False);
-}
-
-int
-xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y)
-{
- float winx = borderpx + x * xw.cw, winy = borderpx + y * xw.ch, xp, yp;
- ushort mode, prevmode = USHRT_MAX;
- Font *font = &dc.font;
- int frcflags = FRC_NORMAL;
- float runewidth = xw.cw;
- Rune rune;
- FT_UInt glyphidx;
- FcResult fcres;
- FcPattern *fcpattern, *fontpattern;
- FcFontSet *fcsets[] = { NULL };
- FcCharSet *fccharset;
- int i, f, numspecs = 0;
-
- for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) {
- /* Fetch rune and mode for current glyph. */
- rune = glyphs[i].u;
- mode = glyphs[i].mode;
-
- /* Skip dummy wide-character spacing. */
- if (mode == ATTR_WDUMMY)
- continue;
-
- /* Determine font for glyph if different from previous glyph. */
- if (prevmode != mode) {
- prevmode = mode;
- font = &dc.font;
- frcflags = FRC_NORMAL;
- runewidth = xw.cw * ((mode & ATTR_WIDE) ? 2.0f : 1.0f);
- if ((mode & ATTR_ITALIC) && (mode & ATTR_BOLD)) {
- font = &dc.ibfont;
- frcflags = FRC_ITALICBOLD;
- } else if (mode & ATTR_ITALIC) {
- font = &dc.ifont;
- frcflags = FRC_ITALIC;
- } else if (mode & ATTR_BOLD) {
- font = &dc.bfont;
- frcflags = FRC_BOLD;
- }
- yp = winy + font->ascent + xw.cyo;
- }
-
- /* Lookup character index with default font. */
- glyphidx = XftCharIndex(xw.dpy, font->match, rune);
- if (glyphidx) {
- specs[numspecs].font = font->match;
- specs[numspecs].glyph = glyphidx;
- specs[numspecs].x = (short)xp;
- specs[numspecs].y = (short)yp;
- xp += runewidth;
- numspecs++;
- continue;
- }
-
- /* Fallback on font cache, search the font cache for match. */
- for (f = 0; f < frclen; f++) {
- glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune);
- /* Everything correct. */
- if (glyphidx && frc[f].flags == frcflags)
- break;
- /* We got a default font for a not found glyph. */
- if (!glyphidx && frc[f].flags == frcflags
- && frc[f].unicodep == rune) {
- break;
- }
- }
-
- /* Nothing was found. Use fontconfig to find matching font. */
- if (f >= frclen) {
- if (!font->set)
- font->set = FcFontSort(0, font->pattern,
- 1, 0, &fcres);
- fcsets[0] = font->set;
-
- /*
- * Nothing was found in the cache. Now use
- * some dozen of Fontconfig calls to get the
- * font for one single character.
- *
- * Xft and fontconfig are design failures.
- */
- fcpattern = FcPatternDuplicate(font->pattern);
- fccharset = FcCharSetCreate();
-
- FcCharSetAddChar(fccharset, rune);
- FcPatternAddCharSet(fcpattern, FC_CHARSET,
- fccharset);
- FcPatternAddBool(fcpattern, FC_SCALABLE, 1);
-
- FcConfigSubstitute(0, fcpattern,
- FcMatchPattern);
- FcDefaultSubstitute(fcpattern);
-
- fontpattern = FcFontSetMatch(0, fcsets, 1,
- fcpattern, &fcres);
-
- /*
- * Overwrite or create the new cache entry.
- */
- if (frclen >= LEN(frc)) {
- frclen = LEN(frc) - 1;
- XftFontClose(xw.dpy, frc[frclen].font);
- frc[frclen].unicodep = 0;
- }
-
- frc[frclen].font = XftFontOpenPattern(xw.dpy,
- fontpattern);
- frc[frclen].flags = frcflags;
- frc[frclen].unicodep = rune;
-
- glyphidx = XftCharIndex(xw.dpy, frc[frclen].font, rune);
-
- f = frclen;
- frclen++;
-
- FcPatternDestroy(fcpattern);
- FcCharSetDestroy(fccharset);
- }
-
- specs[numspecs].font = frc[f].font;
- specs[numspecs].glyph = glyphidx;
- specs[numspecs].x = (short)xp;
- specs[numspecs].y = (short)yp;
- xp += runewidth;
- numspecs++;
- }
-
- return numspecs;
-}
-
-void
-xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y)
-{
- int charlen = len * ((base.mode & ATTR_WIDE) ? 2 : 1);
- int winx = borderpx + x * xw.cw, winy = borderpx + y * xw.ch,
- width = charlen * xw.cw;
- 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) {
- if (dc.ibfont.badslant || dc.ibfont.badweight)
- base.fg = defaultattr;
- } else if ((base.mode & ATTR_ITALIC && dc.ifont.badslant) ||
- (base.mode & ATTR_BOLD && dc.bfont.badweight)) {
- base.fg = defaultattr;
- }
-
- if (IS_TRUECOL(base.fg)) {
- colfg.alpha = 0xffff;
- colfg.red = TRUERED(base.fg);
- colfg.green = TRUEGREEN(base.fg);
- colfg.blue = TRUEBLUE(base.fg);
- XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg, &truefg);
- fg = &truefg;
- } else {
- fg = &dc.col[base.fg];
- }
-
- if (IS_TRUECOL(base.bg)) {
- colbg.alpha = 0xffff;
- colbg.green = TRUEGREEN(base.bg);
- colbg.red = TRUERED(base.bg);
- colbg.blue = TRUEBLUE(base.bg);
- XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colbg, &truebg);
- bg = &truebg;
- } else {
- bg = &dc.col[base.bg];
- }
-
- /* Change basic system colors [0-7] to bright system colors [8-15] */
- if ((base.mode & ATTR_BOLD_FAINT) == ATTR_BOLD && BETWEEN(base.fg, 0, 7))
- fg = &dc.col[base.fg];
-
- if (IS_SET(MODE_REVERSE)) {
- if (fg == &dc.col[defaultfg]) {
- fg = &dc.col[defaultbg];
- } else {
- colfg.red = ~fg->color.red;
- colfg.green = ~fg->color.green;
- colfg.blue = ~fg->color.blue;
- colfg.alpha = fg->color.alpha;
- XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg,
- &revfg);
- fg = &revfg;
- }
-
- if (bg == &dc.col[defaultbg]) {
- bg = &dc.col[defaultfg];
- } else {
- colbg.red = ~bg->color.red;
- colbg.green = ~bg->color.green;
- colbg.blue = ~bg->color.blue;
- colbg.alpha = bg->color.alpha;
- XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colbg,
- &revbg);
- bg = &revbg;
- }
- }
-
- if (base.mode & ATTR_REVERSE) {
- temp = fg;
- fg = bg;
- bg = temp;
- }
-
- if ((base.mode & ATTR_BOLD_FAINT) == ATTR_FAINT) {
- colfg.red = fg->color.red / 2;
- colfg.green = fg->color.green / 2;
- colfg.blue = fg->color.blue / 2;
- XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg, &revfg);
- fg = &revfg;
- }
-
- if (base.mode & ATTR_BLINK && term.mode & MODE_BLINK)
- fg = bg;
-
- if (base.mode & ATTR_INVISIBLE)
- fg = bg;
-
- /* Intelligent cleaning up of the borders. */
- if (x == 0) {
- xclear(0, (y == 0)? 0 : winy, borderpx,
- winy + xw.ch + ((y >= term.row-1)? xw.h : 0));
- }
- if (x + charlen >= term.col) {
- xclear(winx + width, (y == 0)? 0 : winy, xw.w,
- ((y >= term.row-1)? xw.h : (winy + xw.ch)));
- }
- if (y == 0)
- xclear(winx, 0, winx + width, borderpx);
- if (y == term.row-1)
- xclear(winx, winy + xw.ch, winx + width, xw.h);
-
- /* Clean up the region we want to draw to. */
- XftDrawRect(xw.draw, bg, winx, winy, width, xw.ch);
-
- /* Set the clip region because Xft is sometimes dirty. */
- r.x = 0;
- r.y = 0;
- r.height = xw.ch;
- r.width = width;
- XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1);
-
- /* Render the glyphs. */
- XftDrawGlyphFontSpec(xw.draw, fg, specs, len);
-
- /* Render underline and strikethrough. */
- if (base.mode & ATTR_UNDERLINE) {
- XftDrawRect(xw.draw, fg, winx, winy + xw.cyo + dc.font.ascent + 1,
- width, 1);
- }
-
- if (base.mode & ATTR_STRUCK) {
- XftDrawRect(xw.draw, fg, winx, winy + xw.cyo + 2 * dc.font.ascent / 3,
- width, 1);
- }
-
- /* Reset clip to none. */
- XftDrawSetClip(xw.draw, 0);
-}
-
-void
-xdrawglyph(Glyph g, int x, int y)
-{
- int numspecs;
- XftGlyphFontSpec spec;
-
- numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y);
- xdrawglyphfontspecs(&spec, g, numspecs, x, y);
-}
-
-void
-xdrawcursor(void)
-{
- static int oldx = 0, oldy = 0;
- int curx;
- Glyph g = {' ', ATTR_NULL, defaultbg, defaultcs}, og;
- int ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN);
- Color drawcol;
-
- LIMIT(oldx, 0, term.col-1);
- LIMIT(oldy, 0, term.row-1);
-
- curx = term.c.x;
-
- /* adjust position if in dummy */
- if (term.line[oldy][oldx].mode & ATTR_WDUMMY)
- oldx--;
- if (term.line[term.c.y][curx].mode & ATTR_WDUMMY)
- curx--;
-
- /* remove the old cursor */
- og = term.line[oldy][oldx];
- if (ena_sel && selected(oldx, oldy))
- og.mode ^= ATTR_REVERSE;
- xdrawglyph(og, oldx, oldy);
-
- g.u = term.line[term.c.y][term.c.x].u;
-
- /*
- * Select the right color for the right mode.
- */
- if (IS_SET(MODE_REVERSE)) {
- g.mode |= ATTR_REVERSE;
- g.bg = defaultfg;
- if (ena_sel && selected(term.c.x, term.c.y)) {
- drawcol = dc.col[defaultcs];
- g.fg = defaultrcs;
- } else {
- drawcol = dc.col[defaultrcs];
- g.fg = defaultcs;
- }
- } else {
- if (ena_sel && selected(term.c.x, term.c.y)) {
- drawcol = dc.col[defaultrcs];
- g.fg = defaultfg;
- g.bg = defaultrcs;
- } else {
- drawcol = dc.col[defaultcs];
- }
- }
-
- if (IS_SET(MODE_HIDE))
- return;
-
- /* draw the new one */
- if (xw.state & WIN_FOCUSED) {
- switch (xw.cursor) {
- case 7: /* st extension: snowman */
- utf8decode("☃", &g.u, UTF_SIZ);
- case 0: /* Blinking Block */
- case 1: /* Blinking Block (Default) */
- case 2: /* Steady Block */
- g.mode |= term.line[term.c.y][curx].mode & ATTR_WIDE;
- xdrawglyph(g, term.c.x, term.c.y);
- break;
- case 3: /* Blinking Underline */
- case 4: /* Steady Underline */
- XftDrawRect(xw.draw, &drawcol,
- borderpx + curx * xw.cw,
- borderpx + (term.c.y + 1) * xw.ch - \
- cursorthickness,
- xw.cw, cursorthickness);
- break;
- case 5: /* Blinking bar */
- case 6: /* Steady bar */
- XftDrawRect(xw.draw, &drawcol,
- borderpx + curx * xw.cw,
- borderpx + term.c.y * xw.ch,
- cursorthickness, xw.ch);
- break;
- }
- } else {
- XftDrawRect(xw.draw, &drawcol,
- borderpx + curx * xw.cw,
- borderpx + term.c.y * xw.ch,
- xw.cw - 1, 1);
- XftDrawRect(xw.draw, &drawcol,
- borderpx + curx * xw.cw,
- borderpx + term.c.y * xw.ch,
- 1, xw.ch - 1);
- XftDrawRect(xw.draw, &drawcol,
- borderpx + (curx + 1) * xw.cw - 1,
- borderpx + term.c.y * xw.ch,
- 1, xw.ch - 1);
- XftDrawRect(xw.draw, &drawcol,
- borderpx + curx * xw.cw,
- borderpx + (term.c.y + 1) * xw.ch - 1,
- xw.cw, 1);
- }
- oldx = curx, oldy = term.c.y;
-}
-
-
-void
-xsettitle(char *p)
-{
- XTextProperty prop;
-
- Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
- &prop);
- XSetWMName(xw.dpy, xw.win, &prop);
- XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmname);
- XFree(prop.value);
-}
-
-void
-xresettitle(void)
-{
- xsettitle(opt_title ? opt_title : "st");
-}
-
-void
-redraw(void)
-{
- tfulldirt();
- draw();
-}
-
-void
-draw(void)
-{
- drawregion(0, 0, term.col, term.row);
- XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, xw.w,
- xw.h, 0, 0);
- XSetForeground(xw.dpy, dc.gc,
- dc.col[IS_SET(MODE_REVERSE)?
- defaultfg : defaultbg].pixel);
+ xsettitle(NULL);
}
void
drawregion(int x1, int y1, int x2, int y2)
{
- int i, x, y, ox, numspecs;
- Glyph base, new;
- XftGlyphFontSpec *specs;
- int ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN);
-
- if (!(xw.state & WIN_VISIBLE))
- return;
-
+ int y;
for (y = y1; y < y2; y++) {
if (!term.dirty[y])
continue;
term.dirty[y] = 0;
-
- specs = term.specbuf;
- numspecs = xmakeglyphfontspecs(specs, &TLINE(y)[x1], x2 - x1, x1, y);
-
- i = ox = 0;
- for (x = x1; x < x2 && i < numspecs; x++) {
- new = TLINE(y)[x];
- if (new.mode == ATTR_WDUMMY)
- continue;
- if (ena_sel && selected(x, y))
- new.mode ^= ATTR_REVERSE;
- if (i > 0 && ATTRCMP(base, new)) {
- xdrawglyphfontspecs(specs, base, i, ox, y);
- specs += i;
- numspecs -= i;
- i = 0;
- }
- if (i == 0) {
- ox = x;
- base = new;
- }
- i++;
- }
- if (i > 0)
- xdrawglyphfontspecs(specs, base, i, ox, y);
- }
-
- if (term.scr == 0)
- xdrawcursor();
-}
-
-void
-expose(XEvent *ev)
-{
- redraw();
-}
-
-void
-visibility(XEvent *ev)
-{
- XVisibilityEvent *e = &ev->xvisibility;
-
- MODBIT(xw.state, e->state != VisibilityFullyObscured, WIN_VISIBLE);
-}
-
-void
-unmap(XEvent *ev)
-{
- xw.state &= ~WIN_VISIBLE;
-}
-
-void
-xsetpointermotion(int set)
-{
- MODBIT(xw.attrs.event_mask, set, PointerMotionMask);
- XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs);
-}
-
-void
-xseturgency(int add)
-{
- XWMHints *h = XGetWMHints(xw.dpy, xw.win);
-
- MODBIT(h->flags, add, XUrgencyHint);
- XSetWMHints(xw.dpy, xw.win, h);
- XFree(h);
-}
-
-void
-focus(XEvent *ev)
-{
- XFocusChangeEvent *e = &ev->xfocus;
-
- if (e->mode == NotifyGrab)
- return;
-
- if (ev->type == FocusIn) {
- XSetICFocus(xw.xic);
- xw.state |= WIN_FOCUSED;
- xseturgency(0);
- if (IS_SET(MODE_FOCUS))
- ttywrite("\033[I", 3);
- } else {
- XUnsetICFocus(xw.xic);
- xw.state &= ~WIN_FOCUSED;
- if (IS_SET(MODE_FOCUS))
- ttywrite("\033[O", 3);
- }
-}
-
-int
-match(uint mask, uint state)
-{
- return mask == XK_ANY_MOD || mask == (state & ~ignoremod);
-}
-
-void
-numlock(const Arg *dummy)
-{
- term.numlock ^= 1;
-}
-
-void
-swapcolors(const Arg *dummy)
-{
- usealtcolors = !usealtcolors;
- xloadcols();
- redraw();
-}
-
-char*
-kmap(KeySym k, uint state)
-{
- Key *kp;
- int i;
-
- /* Check for mapped keys out of X11 function keys. */
- for (i = 0; i < LEN(mappedkeys); i++) {
- if (mappedkeys[i] == k)
- break;
+ xdrawline(TLINE(y), x1, y, x2);
}
- if (i == LEN(mappedkeys)) {
- if ((k & 0xFFFF) < 0xFD00)
- return NULL;
- }
-
- for (kp = key; kp < key + LEN(key); kp++) {
- if (kp->k != k)
- continue;
-
- if (!match(kp->mask, state))
- continue;
-
- if (IS_SET(MODE_APPKEYPAD) ? kp->appkey < 0 : kp->appkey > 0)
- continue;
- if (term.numlock && kp->appkey == 2)
- continue;
-
- if (IS_SET(MODE_APPCURSOR) ? kp->appcursor < 0 : kp->appcursor > 0)
- continue;
-
- if (IS_SET(MODE_CRLF) ? kp->crlf < 0 : kp->crlf > 0)
- continue;
-
- return kp->s;
- }
-
- return NULL;
}
void
-kpress(XEvent *ev)
-{
- XKeyEvent *e = &ev->xkey;
- KeySym ksym;
- char buf[32], *customkey;
- int len;
- Rune c;
- Status status;
- Shortcut *bp;
-
- if (IS_SET(MODE_KBDLOCK))
- return;
-
- len = XmbLookupString(xw.xic, e, buf, sizeof buf, &ksym, &status);
- /* 1. shortcuts */
- for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
- if (ksym == bp->keysym && match(bp->mod, e->state)) {
- bp->func(&(bp->arg));
- return;
- }
- }
-
- /* 2. custom keys from config.h */
- if ((customkey = kmap(ksym, e->state))) {
- ttysend(customkey, strlen(customkey));
- return;
- }
-
- /* 3. composed string from input method */
- if (len == 0)
- return;
- if (len == 1 && e->state & Mod1Mask) {
- if (IS_SET(MODE_8BIT)) {
- if (*buf < 0177) {
- c = *buf | 0x80;
- len = utf8encode(c, buf);
- }
- } else {
- buf[1] = buf[0];
- buf[0] = '\033';
- len = 2;
- }
- }
- ttysend(buf, len);
-}
-
-
-void
-cmessage(XEvent *e)
-{
- /*
- * See xembed specs
- * http://standards.freedesktop.org/xembed-spec/xembed-spec-latest.html
- */
- if (e->xclient.message_type == xw.xembed && e->xclient.format == 32) {
- if (e->xclient.data.l[1] == XEMBED_FOCUS_IN) {
- xw.state |= WIN_FOCUSED;
- xseturgency(0);
- } else if (e->xclient.data.l[1] == XEMBED_FOCUS_OUT) {
- xw.state &= ~WIN_FOCUSED;
- }
- } else if (e->xclient.data.l[0] == xw.wmdeletewin) {
- /* Send SIGHUP to shell */
- kill(pid, SIGHUP);
- exit(0);
- }
-}
-
-void
-cresize(int width, int height)
+draw(void)
{
- int col, row;
+ int cx = term.c.x;
- if (width != 0)
- xw.w = width;
- if (height != 0)
- xw.h = height;
-
- col = (xw.w - 2 * borderpx) / xw.cw;
- row = (xw.h - 2 * borderpx) / xw.ch;
-
- tresize(col, row);
- xresize(col, row);
-}
-
-void
-resize(XEvent *e)
-{
- if (e->xconfigure.width == xw.w && e->xconfigure.height == xw.h)
+ if (!xstartdraw())
return;
- cresize(e->xconfigure.width, e->xconfigure.height);
- ttyresize();
-}
+ /* adjust cursor position */
+ LIMIT(term.ocx, 0, term.col-1);
+ LIMIT(term.ocy, 0, term.row-1);
+ if (term.line[term.ocy][term.ocx].mode & ATTR_WDUMMY)
+ term.ocx--;
+ if (term.line[term.c.y][cx].mode & ATTR_WDUMMY)
+ cx--;
-void
-run(void)
-{
- XEvent ev;
- int w = xw.w, h = xw.h;
- fd_set rfd;
- int xfd = XConnectionNumber(xw.dpy), xev, blinkset = 0, dodraw = 0;
- struct timespec drawtimeout, *tv = NULL, now, last, lastblink;
- long deltatime;
-
- /* Waiting for window mapping */
- do {
- XNextEvent(xw.dpy, &ev);
- /*
- * This XFilterEvent call is required because of XOpenIM. It
- * does filter out the key event and some client message for
- * the input method too.
- */
- if (XFilterEvent(&ev, None))
- continue;
- if (ev.type == ConfigureNotify) {
- w = ev.xconfigure.width;
- h = ev.xconfigure.height;
- }
- } while (ev.type != MapNotify);
-
- cresize(w, h);
- ttynew();
- ttyresize();
-
- clock_gettime(CLOCK_MONOTONIC, &last);
- lastblink = last;
-
- for (xev = actionfps;;) {
- FD_ZERO(&rfd);
- FD_SET(cmdfd, &rfd);
- FD_SET(xfd, &rfd);
-
- if (pselect(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, tv, NULL) < 0) {
- if (errno == EINTR)
- continue;
- die("select failed: %s\n", strerror(errno));
- }
- if (FD_ISSET(cmdfd, &rfd)) {
- ttyread();
- if (blinktimeout) {
- blinkset = tattrset(ATTR_BLINK);
- if (!blinkset)
- MODBIT(term.mode, 0, MODE_BLINK);
- }
- }
-
- if (FD_ISSET(xfd, &rfd))
- xev = actionfps;
-
- clock_gettime(CLOCK_MONOTONIC, &now);
- drawtimeout.tv_sec = 0;
- drawtimeout.tv_nsec = (1000 * 1E6)/ xfps;
- tv = &drawtimeout;
-
- dodraw = 0;
- if (blinktimeout && TIMEDIFF(now, lastblink) > blinktimeout) {
- tsetdirtattr(ATTR_BLINK);
- term.mode ^= MODE_BLINK;
- lastblink = now;
- dodraw = 1;
- }
- deltatime = TIMEDIFF(now, last);
- if (deltatime > 1000 / (xev ? xfps : actionfps)) {
- dodraw = 1;
- last = now;
- }
-
- if (dodraw) {
- while (XPending(xw.dpy)) {
- XNextEvent(xw.dpy, &ev);
- if (XFilterEvent(&ev, None))
- continue;
- if (handler[ev.type])
- (handler[ev.type])(&ev);
- }
-
- draw();
- XFlush(xw.dpy);
-
- if (xev && !FD_ISSET(xfd, &rfd))
- xev--;
- if (!FD_ISSET(cmdfd, &rfd) && !FD_ISSET(xfd, &rfd)) {
- if (blinkset) {
- if (TIMEDIFF(now, lastblink) \
- > blinktimeout) {
- drawtimeout.tv_nsec = 1000;
- } else {
- drawtimeout.tv_nsec = (1E6 * \
- (blinktimeout - \
- TIMEDIFF(now,
- lastblink)));
- }
- drawtimeout.tv_sec = \
- drawtimeout.tv_nsec / 1E9;
- drawtimeout.tv_nsec %= (long)1E9;
- } else {
- tv = NULL;
- }
- }
- }
+ drawregion(0, 0, term.col, term.row);
+ if (term.scr == 0) {
+ xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
+ term.ocx, term.ocy, term.line[term.ocy][term.ocx]);
}
+ term.ocx = cx, term.ocy = term.c.y;
+ xfinishdraw();
}
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);
-}
-
-int
-main(int argc, char *argv[])
+redraw(void)
{
- xw.l = xw.t = 0;
- xw.isfixed = False;
- xw.cursor = cursorshape;
-
- ARGBEGIN {
- case 'a':
- allowaltscreen = 0;
- break;
- case 'c':
- opt_class = EARGF(usage());
- break;
- case 'e':
- if (argc > 0)
- --argc, ++argv;
- goto run;
- case 'f':
- opt_font = EARGF(usage());
- break;
- case 'g':
- xw.gm = XParseGeometry(EARGF(usage()),
- &xw.l, &xw.t, &cols, &rows);
- break;
- case 'i':
- xw.isfixed = 1;
- break;
- case 'o':
- opt_io = EARGF(usage());
- break;
- case 'l':
- opt_line = EARGF(usage());
- break;
- case 'n':
- opt_name = EARGF(usage());
- break;
- case 't':
- case 'T':
- opt_title = EARGF(usage());
- break;
- case 'w':
- opt_embed = EARGF(usage());
- break;
- case 'v':
- die("%s " VERSION " (c) 2010-2016 st engineers\n", argv0);
- break;
- default:
- usage();
- } ARGEND;
-
-run:
- if (argc > 0) {
- /* eat all remaining arguments */
- opt_cmd = argv;
- if (!opt_title && !opt_line)
- opt_title = basename(xstrdup(argv[0]));
- }
- setlocale(LC_CTYPE, "");
- XSetLocaleModifiers("");
- tnew(MAX(cols, 1), MAX(rows, 1));
- xinit();
- selinit();
- run();
-
- return 0;
+ tfulldirt();
+ draw();
}
-
diff --git a/st.h b/st.h
new file mode 100644
index 0000000..850c5f0
--- /dev/null
+++ b/st.h
@@ -0,0 +1,140 @@
+/* See LICENSE for license details. */
+
+#include <stdint.h>
+#include <sys/types.h>
+
+/* Arbitrary size */
+#define HISTSIZE 2000
+
+/* 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)
+#define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || \
+ (a).bg != (b).bg)
+#define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + \
+ (t1.tv_nsec-t2.tv_nsec)/1E6)
+#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))
+#define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - term.scr \
+ + HISTSIZE + 1) % HISTSIZE] : term.line[(y) - term.scr])
+
+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_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
+};
+
+enum selection_mode {
+ SEL_IDLE = 0,
+ SEL_EMPTY = 1,
+ SEL_READY = 2
+};
+
+enum selection_type {
+ SEL_REGULAR = 1,
+ SEL_RECTANGULAR = 2
+};
+
+enum selection_snap {
+ SNAP_WORD = 1,
+ SNAP_LINE = 2
+};
+
+typedef unsigned char uchar;
+typedef unsigned int uint;
+typedef unsigned long ulong;
+typedef unsigned short ushort;
+
+typedef uint_least32_t Rune;
+
+#define Glyph Glyph_
+typedef struct {
+ Rune u; /* character code */
+ ushort mode; /* attribute flags */
+ uint32_t fg; /* foreground */
+ uint32_t bg; /* background */
+} Glyph;
+
+typedef Glyph *Line;
+
+typedef union {
+ int i;
+ uint ui;
+ float f;
+ const void *v;
+} Arg;
+
+typedef struct {
+ uint b;
+ uint mask;
+ void (*func)(const Arg *);
+ const Arg arg;
+} MouseKey;
+
+void die(const char *, ...);
+void redraw(void);
+void draw(void);
+
+void iso14755(const Arg *);
+void printscreen(const Arg *);
+void printsel(const Arg *);
+void sendbreak(const Arg *);
+void toggleprinter(const Arg *);
+
+int tattrset(int);
+void tnew(int, int);
+void tresize(int, int);
+void tsetdirtattr(int);
+void ttyhangup(void);
+int ttynew(char *, char *, char *, char **);
+size_t ttyread(void);
+void ttyresize(int, int);
+void ttywrite(const char *, size_t, int);
+
+void resettitle(void);
+
+void selclear(void);
+void selinit(void);
+void selstart(int, int, int);
+void selextend(int, int, int, int);
+int selected(int, int);
+char *getsel(void);
+
+size_t utf8encode(Rune, char *);
+
+void *xmalloc(size_t);
+void *xrealloc(void *, size_t);
+char *xstrdup(char *);
+
+void kscrolldown(const Arg *);
+void kscrollup(const Arg *);
+
+/* config.h globals */
+extern char *utmp;
+extern char *stty_args;
+extern char *vtiden;
+extern char *worddelimiters;
+extern int allowaltscreen;
+extern char *termname;
+extern unsigned int tabspaces;
+extern unsigned int alpha;
+extern unsigned int defaultfg;
+extern unsigned int defaultbg;
+extern MouseKey mkeys[];
diff --git a/st.info b/st.info
index 13cc8eb..52fc617 100644
--- a/st.info
+++ b/st.info
@@ -25,6 +25,7 @@ st| simpleterm,
cuu=\E[%p1%dA,
dch=\E[%p1%dP,
dch1=\E[P,
+ dim=\E[2m,
dl=\E[%p1%dM,
dl1=\E[M,
ech=\E[%p1%dX,
@@ -142,7 +143,6 @@ st| simpleterm,
khome=\E[1~,
kil1=\E[2;5~,
krmir=\E[2;2~,
- kich1=\E[2~,
knp=\E[6~,
kmous=\E[M,
kpp=\E[5~,
@@ -185,16 +185,23 @@ st| simpleterm,
tsl=\E]0;,
xenl,
vpa=\E[%i%p1%dd,
-# Tmux unofficial extensions, see TERMINFO EXTENSIONS in tmux(1)
+# XTerm extensions
+ rmxx=\E[29m,
+ smxx=\E[9m,
+# tmux extensions, see TERMINFO EXTENSIONS in tmux(1)
Se,
Ss,
Tc,
+ Ms=\E]52;%p1%s;%p2%s\007,
st-256color| simpleterm with 256 colors,
use=st,
+ ccc,
colors#256,
+ oc=\E]104\007,
pairs#32767,
# Nicked from xterm-256color
+ initc=\E]4;%p1%d;rgb\:%p2%{255}%*%{1000}%/%2.2X/%p3%{255}%*%{1000}%/%2.2X/%p4%{255}%*%{1000}%/%2.2X\E\\,
setab=\E[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m,
setaf=\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m,
diff --git a/win.h b/win.h
new file mode 100644
index 0000000..d277477
--- /dev/null
+++ b/win.h
@@ -0,0 +1,42 @@
+/* See LICENSE for license details. */
+
+enum win_mode {
+ MODE_VISIBLE = 1 << 0,
+ MODE_FOCUSED = 1 << 1,
+ MODE_APPKEYPAD = 1 << 2,
+ MODE_MOUSEBTN = 1 << 3,
+ MODE_MOUSEMOTION = 1 << 4,
+ MODE_REVERSE = 1 << 5,
+ MODE_KBDLOCK = 1 << 6,
+ MODE_HIDE = 1 << 7,
+ MODE_APPCURSOR = 1 << 8,
+ MODE_MOUSESGR = 1 << 9,
+ MODE_8BIT = 1 << 10,
+ MODE_BLINK = 1 << 11,
+ MODE_FBLINK = 1 << 12,
+ MODE_FOCUS = 1 << 13,
+ MODE_MOUSEX10 = 1 << 14,
+ MODE_MOUSEMANY = 1 << 15,
+ MODE_BRCKTPASTE = 1 << 16,
+ MODE_NUMLOCK = 1 << 17,
+ MODE_MOUSE = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\
+ |MODE_MOUSEMANY,
+};
+
+/* alpha */
+#define OPAQUE 0Xff
+#define USE_ARGB (alpha != OPAQUE && opt_embed == NULL)
+
+void xbell(void);
+void xclipcopy(void);
+void xdrawcursor(int, int, Glyph, int, int, Glyph);
+void xdrawline(Line, int, int, int);
+void xfinishdraw(void);
+void xloadcols(void);
+int xsetcolorname(int, const char *);
+void xsettitle(char *);
+int xsetcursor(int);
+void xsetmode(int, unsigned int);
+void xsetpointermotion(int);
+void xsetsel(char *);
+int xstartdraw(void);
diff --git a/x.c b/x.c
new file mode 100644
index 0000000..840d2fa
--- /dev/null
+++ b/x.c
@@ -0,0 +1,2020 @@
+/* See LICENSE for license details. */
+#include <errno.h>
+#include <math.h>
+#include <limits.h>
+#include <locale.h>
+#include <signal.h>
+#include <sys/select.h>
+#include <time.h>
+#include <unistd.h>
+#include <libgen.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>
+
+static char *argv0;
+#include "arg.h"
+#include "st.h"
+#include "win.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;
+
+/* X modifiers */
+#define XK_ANY_MOD UINT_MAX
+#define XK_NO_MOD 0
+#define XK_SWITCH_MOD (1<<13)
+
+/* function definitions used in config.h */
+static void clipcopy(const Arg *);
+static void clippaste(const Arg *);
+static void numlock(const Arg *);
+static void selpaste(const Arg *);
+static void zoom(const Arg *);
+static void zoomabs(const Arg *);
+static void zoomreset(const Arg *);
+
+/* config.h for applying patches and the configuration. */
+#include "config.h"
+
+/* XEMBED messages */
+#define XEMBED_FOCUS_IN 4
+#define XEMBED_FOCUS_OUT 5
+
+/* macros */
+#define IS_SET(flag) ((win.mode & (flag)) != 0)
+#define TRUERED(x) (((x) & 0xff0000) >> 8)
+#define TRUEGREEN(x) (((x) & 0xff00))
+#define TRUEBLUE(x) (((x) & 0xff) << 8)
+
+typedef XftDraw *Draw;
+typedef XftColor Color;
+typedef XftGlyphFontSpec GlyphFontSpec;
+
+/* Purely graphic info */
+typedef struct {
+ int tw, th; /* tty width and height */
+ int w, h; /* window width and height */
+ 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, 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);
+static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int);
+static void xdrawglyph(Glyph, int, int);
+static void xclear(int, int, int, int);
+static int xgeommasktogravity(int);
+static void xinit(int, int);
+static void cresize(int, int);
+static void xresize(int, int);
+static void xhints(void);
+static int xloadcolor(int, const char *, Color *);
+static int xloadfont(Font *, FcPattern *);
+static void xloadfonts(char *, double);
+static void xunloadfont(Font *);
+static void xunloadfonts(void);
+static void xsetenv(void);
+static void xseturgency(int);
+static int evcol(XEvent *);
+static int evrow(XEvent *);
+
+static void expose(XEvent *);
+static void visibility(XEvent *);
+static void unmap(XEvent *);
+static void kpress(XEvent *);
+static void cmessage(XEvent *);
+static void resize(XEvent *);
+static void focus(XEvent *);
+static void brelease(XEvent *);
+static void bpress(XEvent *);
+static void bmotion(XEvent *);
+static void propnotify(XEvent *);
+static void selnotify(XEvent *);
+static void selclear_(XEvent *);
+static void selrequest(XEvent *);
+static void setsel(char *, Time);
+static void mousesel(XEvent *, int);
+static void mousereport(XEvent *);
+static char *kmap(KeySym, uint);
+static int match(uint, uint);
+
+static void run(void);
+static void usage(void);
+
+static void (*handler[LASTEvent])(XEvent *) = {
+ [KeyPress] = kpress,
+ [ClientMessage] = cmessage,
+ [ConfigureNotify] = resize,
+ [VisibilityNotify] = visibility,
+ [UnmapNotify] = unmap,
+ [Expose] = expose,
+ [FocusIn] = focus,
+ [FocusOut] = focus,
+ [MotionNotify] = bmotion,
+ [ButtonPress] = bpress,
+ [ButtonRelease] = brelease,
+/*
+ * Uncomment if you want the selection to disappear when you select something
+ * different in another window.
+ */
+/* [SelectionClear] = selclear_, */
+ [SelectionNotify] = selnotify,
+/*
+ * PropertyNotify is only turned on when there is some INCR transfer happening
+ * for the selection retrieval.
+ */
+ [PropertyNotify] = propnotify,
+ [SelectionRequest] = selrequest,
+};
+
+/* Globals */
+static DC dc;
+static XWindow xw;
+static XSelection xsel;
+static TermWindow win;
+
+/* Font Ring Cache */
+enum {
+ FRC_NORMAL,
+ FRC_ITALIC,
+ FRC_BOLD,
+ FRC_ITALICBOLD
+};
+
+typedef struct {
+ XftFont *font;
+ int flags;
+ Rune unicodep;
+} Fontcache;
+
+/* Fontcache is an array now. A new font will be appended to the array. */
+static Fontcache frc[16];
+static int frclen = 0;
+static char *usedfont = NULL;
+static double usedfontsize = 0;
+static double defaultfontsize = 0;
+
+static char *opt_class = NULL;
+static char **opt_cmd = NULL;
+static char *opt_embed = NULL;
+static char *opt_font = NULL;
+static char *opt_io = NULL;
+static char *opt_line = NULL;
+static char *opt_name = NULL;
+static char *opt_title = NULL;
+
+static int oldbutton = 3; /* button event on startup: 3 = release */
+
+void
+clipcopy(const Arg *dummy)
+{
+ Atom clipboard;
+
+ free(xsel.clipboard);
+ xsel.clipboard = NULL;
+
+ if (xsel.primary != NULL) {
+ xsel.clipboard = xstrdup(xsel.primary);
+ clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
+ XSetSelectionOwner(xw.dpy, clipboard, xw.win, CurrentTime);
+ }
+}
+
+void
+clippaste(const Arg *dummy)
+{
+ Atom clipboard;
+
+ clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
+ XConvertSelection(xw.dpy, clipboard, xsel.xtarget, clipboard,
+ xw.win, CurrentTime);
+}
+
+void
+selpaste(const Arg *dummy)
+{
+ XConvertSelection(xw.dpy, XA_PRIMARY, xsel.xtarget, XA_PRIMARY,
+ xw.win, CurrentTime);
+}
+
+void
+numlock(const Arg *dummy)
+{
+ win.mode ^= MODE_NUMLOCK;
+}
+
+void
+zoom(const Arg *arg)
+{
+ Arg larg;
+
+ larg.f = usedfontsize + arg->f;
+ zoomabs(&larg);
+}
+
+void
+zoomabs(const Arg *arg)
+{
+ xunloadfonts();
+ xloadfonts(usedfont, arg->f);
+ cresize(0, 0);
+ redraw();
+ xhints();
+}
+
+void
+zoomreset(const Arg *arg)
+{
+ Arg larg;
+
+ if (defaultfontsize > 0) {
+ larg.f = defaultfontsize;
+ zoomabs(&larg);
+ }
+}
+
+int
+evcol(XEvent *e)
+{
+ int x = e->xbutton.x - borderpx;
+ LIMIT(x, 0, win.tw - 1);
+ return x / win.cw;
+}
+
+int
+evrow(XEvent *e)
+{
+ int y = e->xbutton.y - borderpx;
+ LIMIT(y, 0, win.th - 1);
+ return y / win.ch;
+}
+
+void
+mousesel(XEvent *e, int done)
+{
+ int type, seltype = SEL_REGULAR;
+ uint state = e->xbutton.state & ~(Button1Mask | forceselmod);
+
+ for (type = 1; type < LEN(selmasks); ++type) {
+ if (match(selmasks[type], state)) {
+ seltype = type;
+ break;
+ }
+ }
+ selextend(evcol(e), evrow(e), seltype, done);
+ if (done)
+ setsel(getsel(), e->xbutton.time);
+}
+
+void
+mousereport(XEvent *e)
+{
+ int len, x = evcol(e), y = evrow(e),
+ button = e->xbutton.button, state = e->xbutton.state;
+ char buf[40];
+ static int ox, oy;
+
+ /* from urxvt */
+ if (e->xbutton.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)
+ return;
+
+ button = oldbutton + 32;
+ ox = x;
+ oy = y;
+ } else {
+ if (!IS_SET(MODE_MOUSESGR) && e->xbutton.type == ButtonRelease) {
+ button = 3;
+ } else {
+ button -= Button1;
+ if (button >= 3)
+ button += 64 - 3;
+ }
+ if (e->xbutton.type == ButtonPress) {
+ oldbutton = button;
+ ox = x;
+ oy = y;
+ } else if (e->xbutton.type == ButtonRelease) {
+ oldbutton = 3;
+ /* MODE_MOUSEX10: no button release reporting */
+ if (IS_SET(MODE_MOUSEX10))
+ return;
+ if (button == 64 || button == 65)
+ return;
+ }
+ }
+
+ if (!IS_SET(MODE_MOUSEX10)) {
+ button += ((state & ShiftMask ) ? 4 : 0)
+ + ((state & Mod4Mask ) ? 8 : 0)
+ + ((state & ControlMask) ? 16 : 0);
+ }
+
+ if (IS_SET(MODE_MOUSESGR)) {
+ len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c",
+ button, x+1, y+1,
+ e->xbutton.type == ButtonRelease ? 'm' : 'M');
+ } else if (x < 223 && y < 223) {
+ len = snprintf(buf, sizeof(buf), "\033[M%c%c%c",
+ 32+button, 32+x+1, 32+y+1);
+ } else {
+ return;
+ }
+
+ ttywrite(buf, len, 0);
+}
+
+void
+bpress(XEvent *e)
+{
+ struct timespec now;
+ MouseShortcut *ms;
+ MouseKey *mk;
+ int snap;
+
+ if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
+ mousereport(e);
+ return;
+ }
+
+ 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 (e->xbutton.button == Button1) {
+ /*
+ * If the user clicks below predefined timeouts specific
+ * snapping behaviour is exposed.
+ */
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ if (TIMEDIFF(now, xsel.tclick2) <= tripleclicktimeout) {
+ snap = SNAP_LINE;
+ } else if (TIMEDIFF(now, xsel.tclick1) <= doubleclicktimeout) {
+ snap = SNAP_WORD;
+ } else {
+ snap = 0;
+ }
+ xsel.tclick2 = xsel.tclick1;
+ xsel.tclick1 = now;
+
+ selstart(evcol(e), evrow(e), snap);
+ }
+}
+
+void
+propnotify(XEvent *e)
+{
+ XPropertyEvent *xpev;
+ Atom clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
+
+ xpev = &e->xproperty;
+ if (xpev->state == PropertyNewValue &&
+ (xpev->atom == XA_PRIMARY ||
+ xpev->atom == clipboard)) {
+ selnotify(e);
+ }
+}
+
+void
+selnotify(XEvent *e)
+{
+ ulong nitems, ofs, rem;
+ int format;
+ uchar *data, *last, *repl;
+ Atom type, incratom, property = None;
+
+ incratom = XInternAtom(xw.dpy, "INCR", 0);
+
+ ofs = 0;
+ if (e->type == SelectionNotify)
+ property = e->xselection.property;
+ else if (e->type == PropertyNotify)
+ property = e->xproperty.atom;
+
+ if (property == None)
+ return;
+
+ do {
+ if (XGetWindowProperty(xw.dpy, xw.win, property, ofs,
+ BUFSIZ/4, False, AnyPropertyType,
+ &type, &format, &nitems, &rem,
+ &data)) {
+ fprintf(stderr, "Clipboard allocation failed\n");
+ return;
+ }
+
+ if (e->type == PropertyNotify && nitems == 0 && rem == 0) {
+ /*
+ * If there is some PropertyNotify with no data, then
+ * this is the signal of the selection owner that all
+ * data has been transferred. We won't need to receive
+ * PropertyNotify events anymore.
+ */
+ MODBIT(xw.attrs.event_mask, 0, PropertyChangeMask);
+ XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask,
+ &xw.attrs);
+ }
+
+ if (type == incratom) {
+ /*
+ * Activate the PropertyNotify events so we receive
+ * when the selection owner does send us the next
+ * chunk of data.
+ */
+ MODBIT(xw.attrs.event_mask, 1, PropertyChangeMask);
+ XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask,
+ &xw.attrs);
+
+ /*
+ * Deleting the property is the transfer start signal.
+ */
+ XDeleteProperty(xw.dpy, xw.win, (int)property);
+ continue;
+ }
+
+ /*
+ * 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);
+ XFree(data);
+ /* number of 32-bit chunks returned */
+ ofs += nitems * format / 32;
+ } while (rem > 0);
+
+ /*
+ * Deleting the property again tells the selection owner to send the
+ * next data chunk in the property.
+ */
+ XDeleteProperty(xw.dpy, xw.win, (int)property);
+}
+
+void
+xclipcopy(void)
+{
+ clipcopy(NULL);
+}
+
+void
+selclear_(XEvent *e)
+{
+ selclear();
+}
+
+void
+selrequest(XEvent *e)
+{
+ XSelectionRequestEvent *xsre;
+ XSelectionEvent xev;
+ Atom xa_targets, string, clipboard;
+ char *seltext;
+
+ xsre = (XSelectionRequestEvent *) e;
+ xev.type = SelectionNotify;
+ xev.requestor = xsre->requestor;
+ xev.selection = xsre->selection;
+ xev.target = xsre->target;
+ xev.time = xsre->time;
+ if (xsre->property == None)
+ xsre->property = xsre->target;
+
+ /* reject */
+ xev.property = None;
+
+ xa_targets = XInternAtom(xw.dpy, "TARGETS", 0);
+ if (xsre->target == xa_targets) {
+ /* respond with the supported type */
+ string = xsel.xtarget;
+ XChangeProperty(xsre->display, xsre->requestor, xsre->property,
+ XA_ATOM, 32, PropModeReplace,
+ (uchar *) &string, 1);
+ xev.property = xsre->property;
+ } else if (xsre->target == xsel.xtarget || xsre->target == XA_STRING) {
+ /*
+ * xith XA_STRING non ascii characters may be incorrect in the
+ * requestor. It is not our problem, use utf8.
+ */
+ clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
+ if (xsre->selection == XA_PRIMARY) {
+ seltext = xsel.primary;
+ } else if (xsre->selection == clipboard) {
+ seltext = xsel.clipboard;
+ } else {
+ fprintf(stderr,
+ "Unhandled clipboard selection 0x%lx\n",
+ xsre->selection);
+ return;
+ }
+ if (seltext != NULL) {
+ XChangeProperty(xsre->display, xsre->requestor,
+ xsre->property, xsre->target,
+ 8, PropModeReplace,
+ (uchar *)seltext, strlen(seltext));
+ xev.property = xsre->property;
+ }
+ }
+
+ /* all done, send a notification to the listener */
+ if (!XSendEvent(xsre->display, xsre->requestor, 1, 0, (XEvent *) &xev))
+ fprintf(stderr, "Error sending SelectionNotify event\n");
+}
+
+void
+setsel(char *str, Time t)
+{
+ if (!str)
+ return;
+
+ free(xsel.primary);
+ xsel.primary = str;
+
+ XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t);
+ if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win)
+ selclear();
+
+ xclipcopy();
+}
+
+void
+xsetsel(char *str)
+{
+ setsel(str, CurrentTime);
+}
+
+void
+brelease(XEvent *e)
+{
+ if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
+ mousereport(e);
+ return;
+ }
+
+ if (e->xbutton.button == Button2)
+ selpaste(NULL);
+ else if (e->xbutton.button == Button1)
+ mousesel(e, 1);
+}
+
+void
+bmotion(XEvent *e)
+{
+ if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) {
+ mousereport(e);
+ return;
+ }
+
+ mousesel(e, 0);
+}
+
+void
+cresize(int width, int height)
+{
+ int col, row;
+
+ if (width != 0)
+ win.w = width;
+ if (height != 0)
+ win.h = height;
+
+ col = (win.w - 2 * borderpx) / win.cw;
+ row = (win.h - 2 * borderpx) / win.ch;
+
+ tresize(col, row);
+ xresize(col, row);
+ ttyresize(win.tw, win.th);
+}
+
+void
+xresize(int col, int row)
+{
+ win.tw = MAX(1, col * win.cw);
+ win.th = MAX(1, row * win.ch);
+
+ XFreePixmap(xw.dpy, xw.buf);
+ xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
+ xw.depth);
+ XftDrawChange(xw.draw, xw.buf);
+ xclear(0, 0, win.w, win.h);
+
+ /* resize to new width */
+ xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec));
+}
+
+ushort
+sixd_to_16bit(int x)
+{
+ return x == 0 ? 0 : 0x3737 + 0x2828 * x;
+}
+
+int
+xloadcolor(int i, const char *name, Color *ncolor)
+{
+ XRenderColor color = { .alpha = 0xffff };
+
+ if (!name) {
+ if (BETWEEN(i, 16, 255)) { /* 256 color */
+ if (i < 6*6*6+16) { /* same colors as xterm */
+ color.red = sixd_to_16bit( ((i-16)/36)%6 );
+ color.green = sixd_to_16bit( ((i-16)/6) %6 );
+ color.blue = sixd_to_16bit( ((i-16)/1) %6 );
+ } else { /* greyscale */
+ color.red = 0x0808 + 0x0a0a * (i - (6*6*6+16));
+ color.green = color.blue = color.red;
+ }
+ return XftColorAllocValue(xw.dpy, xw.vis,
+ xw.cmap, &color, ncolor);
+ } else
+ name = colorname[i];
+ }
+
+ return XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, ncolor);
+}
+
+void
+xloadcols(void)
+{
+ int i;
+ static int loaded;
+ Color *cp;
+
+ dc.collen = MAX(LEN(colorname), 256);
+ dc.col = xmalloc(dc.collen * sizeof(Color));
+
+ if (loaded) {
+ for (cp = dc.col; cp < &dc.col[dc.collen]; ++cp)
+ XftColorFree(xw.dpy, xw.vis, xw.cmap, cp);
+ }
+
+ for (i = 0; i < 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);
+ }
+
+ /* set alpha value of bg color */
+ if (USE_ARGB) {
+ dc.col[defaultbg].color.alpha = (0xffff * alpha) / OPAQUE;
+ dc.col[defaultbg].pixel &= 0x00111111;
+ dc.col[defaultbg].pixel |= alpha << 24;
+ }
+ loaded = 1;
+}
+
+int
+xsetcolorname(int x, const char *name)
+{
+ Color ncolor;
+
+ if (!BETWEEN(x, 0, dc.collen))
+ return 1;
+
+
+ if (!xloadcolor(x, name, &ncolor))
+ return 1;
+
+ XftColorFree(xw.dpy, xw.vis, xw.cmap, &dc.col[x]);
+ dc.col[x] = ncolor;
+
+ return 0;
+}
+
+void
+xtermclear(int col1, int row1, int col2, int row2)
+{
+ XftDrawRect(xw.draw,
+ &dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg],
+ borderpx + col1 * win.cw,
+ borderpx + row1 * win.ch,
+ (col2-col1+1) * win.cw,
+ (row2-row1+1) * win.ch);
+}
+
+/*
+ * Absolute coordinates.
+ */
+void
+xclear(int x1, int y1, int x2, int y2)
+{
+ XftDrawRect(xw.draw,
+ &dc.col[IS_SET(MODE_REVERSE)? defaultfg : defaultbg],
+ x1, y1, x2-x1, y2-y1);
+}
+
+void
+xhints(void)
+{
+ XClassHint class = {opt_name ? opt_name : termname,
+ opt_class ? opt_class : termname};
+ XWMHints wm = {.flags = InputHint, .input = 1};
+ XSizeHints *sizeh;
+
+ sizeh = XAllocSizeHints();
+
+ sizeh->flags = PSize | PResizeInc | PBaseSize;
+ sizeh->height = win.h;
+ sizeh->width = win.w;
+ sizeh->height_inc = win.ch;
+ sizeh->width_inc = win.cw;
+ sizeh->base_height = 2 * borderpx;
+ sizeh->base_width = 2 * borderpx;
+ if (xw.isfixed) {
+ sizeh->flags |= PMaxSize | PMinSize;
+ sizeh->min_width = sizeh->max_width = win.w;
+ sizeh->min_height = sizeh->max_height = win.h;
+ }
+ if (xw.gm & (XValue|YValue)) {
+ sizeh->flags |= USPosition | PWinGravity;
+ sizeh->x = xw.l;
+ sizeh->y = xw.t;
+ sizeh->win_gravity = xgeommasktogravity(xw.gm);
+ }
+
+ XSetWMProperties(xw.dpy, xw.win, NULL, NULL, NULL, 0, sizeh, &wm,
+ &class);
+ XFree(sizeh);
+}
+
+int
+xgeommasktogravity(int mask)
+{
+ switch (mask & (XNegative|YNegative)) {
+ case 0:
+ return NorthWestGravity;
+ case XNegative:
+ return NorthEastGravity;
+ case YNegative:
+ return SouthWestGravity;
+ }
+
+ return SouthEastGravity;
+}
+
+int
+xloadfont(Font *f, FcPattern *pattern)
+{
+ FcPattern *configured;
+ FcPattern *match;
+ FcResult result;
+ XGlyphInfo extents;
+ int wantattr, haveattr;
+
+ /*
+ * Manually configure instead of calling XftMatchFont
+ * so that we can use the configured pattern for
+ * "missing glyph" lookups.
+ */
+ configured = FcPatternDuplicate(pattern);
+ if (!configured)
+ return 1;
+
+ FcConfigSubstitute(NULL, configured, FcMatchPattern);
+ XftDefaultSubstitute(xw.dpy, xw.scr, configured);
+
+ match = FcFontMatch(NULL, configured, &result);
+ if (!match) {
+ FcPatternDestroy(configured);
+ return 1;
+ }
+
+ if (!(f->match = XftFontOpenPattern(xw.dpy, match))) {
+ FcPatternDestroy(configured);
+ FcPatternDestroy(match);
+ return 1;
+ }
+
+ if ((XftPatternGetInteger(pattern, "slant", 0, &wantattr) ==
+ XftResultMatch)) {
+ /*
+ * Check if xft was unable to find a font with the appropriate
+ * slant but gave us one anyway. Try to mitigate.
+ */
+ if ((XftPatternGetInteger(f->match->pattern, "slant", 0,
+ &haveattr) != XftResultMatch) || haveattr < wantattr) {
+ f->badslant = 1;
+ fputs("st: font slant does not match\n", stderr);
+ }
+ }
+
+ if ((XftPatternGetInteger(pattern, "weight", 0, &wantattr) ==
+ XftResultMatch)) {
+ if ((XftPatternGetInteger(f->match->pattern, "weight", 0,
+ &haveattr) != XftResultMatch) || haveattr != wantattr) {
+ f->badweight = 1;
+ fputs("st: font weight does not match\n", stderr);
+ }
+ }
+
+ XftTextExtentsUtf8(xw.dpy, f->match,
+ (const FcChar8 *) ascii_printable,
+ strlen(ascii_printable), &extents);
+
+ f->set = NULL;
+ f->pattern = configured;
+
+ f->ascent = f->match->ascent;
+ f->descent = f->match->descent;
+ f->lbearing = 0;
+ f->rbearing = f->match->max_advance_width;
+
+ f->height = f->ascent + f->descent;
+ f->width = DIVCEIL(extents.xOff, strlen(ascii_printable));
+
+ return 0;
+}
+
+void
+xloadfonts(char *fontstr, double fontsize)
+{
+ FcPattern *pattern;
+ double fontval;
+
+ if (fontstr[0] == '-') {
+ pattern = XftXlfdParse(fontstr, False, False);
+ } else {
+ pattern = FcNameParse((FcChar8 *)fontstr);
+ }
+
+ if (!pattern)
+ die("st: can't open font %s\n", fontstr);
+
+ if (fontsize > 1) {
+ FcPatternDel(pattern, FC_PIXEL_SIZE);
+ FcPatternDel(pattern, FC_SIZE);
+ FcPatternAddDouble(pattern, FC_PIXEL_SIZE, (double)fontsize);
+ usedfontsize = fontsize;
+ } else {
+ if (FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &fontval) ==
+ FcResultMatch) {
+ usedfontsize = fontval;
+ } else if (FcPatternGetDouble(pattern, FC_SIZE, 0, &fontval) ==
+ FcResultMatch) {
+ usedfontsize = -1;
+ } else {
+ /*
+ * Default font size is 12, if none given. This is to
+ * have a known usedfontsize value.
+ */
+ FcPatternAddDouble(pattern, FC_PIXEL_SIZE, 12);
+ usedfontsize = 12;
+ }
+ defaultfontsize = usedfontsize;
+ }
+
+ if (xloadfont(&dc.font, pattern))
+ die("st: can't open font %s\n", fontstr);
+
+ if (usedfontsize < 0) {
+ FcPatternGetDouble(dc.font.match->pattern,
+ FC_PIXEL_SIZE, 0, &fontval);
+ usedfontsize = fontval;
+ if (fontsize == 0)
+ defaultfontsize = fontval;
+ }
+
+ /* Setting character width and height. */
+ win.cw = ceilf(dc.font.width * cwscale);
+ win.ch = ceilf(dc.font.height * chscale);
+ win.cyo = ceilf(dc.font.height * (chscale - 1) / 2);
+
+ FcPatternDel(pattern, FC_SLANT);
+ FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
+ if (xloadfont(&dc.ifont, pattern))
+ die("st: can't open font %s\n", fontstr);
+
+ FcPatternDel(pattern, FC_WEIGHT);
+ FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
+ if (xloadfont(&dc.ibfont, pattern))
+ die("st: can't open font %s\n", fontstr);
+
+ FcPatternDel(pattern, FC_SLANT);
+ FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN);
+ if (xloadfont(&dc.bfont, pattern))
+ die("st: can't open font %s\n", fontstr);
+
+ FcPatternDestroy(pattern);
+}
+
+void
+xunloadfont(Font *f)
+{
+ XftFontClose(xw.dpy, f->match);
+ FcPatternDestroy(f->pattern);
+ if (f->set)
+ FcFontSetDestroy(f->set);
+}
+
+void
+xunloadfonts(void)
+{
+ /* Free the loaded fonts in the font cache. */
+ while (frclen > 0)
+ XftFontClose(xw.dpy, frc[--frclen].font);
+
+ xunloadfont(&dc.font);
+ xunloadfont(&dc.bfont);
+ xunloadfont(&dc.ifont);
+ xunloadfont(&dc.ibfont);
+}
+
+void
+xinit(int cols, int rows)
+{
+ XGCValues gcvalues;
+ Cursor cursor;
+ Window parent;
+ pid_t thispid = getpid();
+ XColor xmousefg, xmousebg;
+
+ if (!(xw.dpy = XOpenDisplay(NULL)))
+ die("Can't open display\n");
+ xw.scr = XDefaultScreen(xw.dpy);
+ xw.depth = (USE_ARGB) ? 32: XDefaultDepth(xw.dpy, xw.scr);
+ if (!USE_ARGB)
+ xw.vis = XDefaultVisual(xw.dpy, xw.scr);
+ else {
+ XVisualInfo *vis;
+ XRenderPictFormat *fmt;
+ int nvi;
+ int i;
+
+ XVisualInfo tpl = {
+ .screen = xw.scr,
+ .depth = 32,
+ .class = TrueColor
+ };
+
+ vis = XGetVisualInfo(xw.dpy,
+ VisualScreenMask | VisualDepthMask | VisualClassMask,
+ &tpl, &nvi);
+ xw.vis = NULL;
+ for (i = 0; i < nvi; i++) {
+ fmt = XRenderFindVisualFormat(xw.dpy, vis[i].visual);
+ if (fmt->type == PictTypeDirect && fmt->direct.alphaMask) {
+ xw.vis = vis[i].visual;
+ break;
+ }
+ }
+
+ XFree(vis);
+
+ if (!xw.vis) {
+ fprintf(stderr, "Couldn't find ARGB visual.\n");
+ exit(1);
+ }
+ }
+
+ /* font */
+ if (!FcInit())
+ die("Could not init fontconfig.\n");
+
+ usedfont = (opt_font == NULL)? font : opt_font;
+ xloadfonts(usedfont, 0);
+
+ /* colors */
+ if (!USE_ARGB)
+ xw.cmap = XDefaultColormap(xw.dpy, xw.scr);
+ else
+ xw.cmap = XCreateColormap(xw.dpy, XRootWindow(xw.dpy, xw.scr),
+ xw.vis, None);
+ xloadcols();
+
+ /* adjust fixed window geometry */
+ win.w = 2 * borderpx + cols * win.cw;
+ win.h = 2 * borderpx + rows * win.ch;
+ if (xw.gm & XNegative)
+ xw.l += DisplayWidth(xw.dpy, xw.scr) - win.w - 2;
+ if (xw.gm & YNegative)
+ xw.t += DisplayHeight(xw.dpy, xw.scr) - win.h - 2;
+
+ /* Events */
+ xw.attrs.background_pixel = dc.col[defaultbg].pixel;
+ xw.attrs.border_pixel = dc.col[defaultbg].pixel;
+ xw.attrs.bit_gravity = NorthWestGravity;
+ xw.attrs.event_mask = FocusChangeMask | KeyPressMask
+ | ExposureMask | VisibilityChangeMask | StructureNotifyMask
+ | ButtonMotionMask | ButtonPressMask | ButtonReleaseMask;
+ xw.attrs.colormap = xw.cmap;
+
+ if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0))))
+ parent = XRootWindow(xw.dpy, xw.scr);
+ xw.win = XCreateWindow(xw.dpy, parent, xw.l, xw.t,
+ win.w, win.h, 0, xw.depth, InputOutput,
+ xw.vis, CWBackPixel | CWBorderPixel | CWBitGravity
+ | CWEventMask | CWColormap, &xw.attrs);
+
+ memset(&gcvalues, 0, sizeof(gcvalues));
+ gcvalues.graphics_exposures = False;
+ xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, xw.depth);
+ dc.gc = XCreateGC(xw.dpy, (USE_ARGB) ? xw.buf: parent,
+ GCGraphicsExposures, &gcvalues);
+ 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 */
+ xw.specbuf = xmalloc(cols * sizeof(GlyphFontSpec));
+
+ /* Xft rendering context */
+ xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
+
+ /* input methods */
+ 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");
+ }
+ }
+ }
+ 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");
+
+ /* white cursor, black outline */
+ cursor = XCreateFontCursor(xw.dpy, mouseshape);
+ XDefineCursor(xw.dpy, xw.win, cursor);
+
+ if (XParseColor(xw.dpy, xw.cmap, colorname[mousefg], &xmousefg) == 0) {
+ xmousefg.red = 0xffff;
+ xmousefg.green = 0xffff;
+ xmousefg.blue = 0xffff;
+ }
+
+ if (XParseColor(xw.dpy, xw.cmap, colorname[mousebg], &xmousebg) == 0) {
+ xmousebg.red = 0x0000;
+ xmousebg.green = 0x0000;
+ xmousebg.blue = 0x0000;
+ }
+
+ XRecolorCursor(xw.dpy, cursor, &xmousefg, &xmousebg);
+
+ 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);
+ XSetWMProtocols(xw.dpy, xw.win, &xw.wmdeletewin, 1);
+
+ xw.netwmpid = XInternAtom(xw.dpy, "_NET_WM_PID", False);
+ XChangeProperty(xw.dpy, xw.win, xw.netwmpid, XA_CARDINAL, 32,
+ PropModeReplace, (uchar *)&thispid, 1);
+
+ win.mode = MODE_NUMLOCK;
+ resettitle();
+ XMapWindow(xw.dpy, xw.win);
+ xhints();
+ XSync(xw.dpy, False);
+
+ clock_gettime(CLOCK_MONOTONIC, &xsel.tclick1);
+ clock_gettime(CLOCK_MONOTONIC, &xsel.tclick2);
+ xsel.primary = NULL;
+ xsel.clipboard = NULL;
+ xsel.xtarget = XInternAtom(xw.dpy, "UTF8_STRING", 0);
+ if (xsel.xtarget == None)
+ xsel.xtarget = XA_STRING;
+}
+
+int
+xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y)
+{
+ float winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, xp, yp;
+ ushort mode, prevmode = USHRT_MAX;
+ Font *font = &dc.font;
+ int frcflags = FRC_NORMAL;
+ float runewidth = win.cw;
+ Rune rune;
+ FT_UInt glyphidx;
+ FcResult fcres;
+ FcPattern *fcpattern, *fontpattern;
+ FcFontSet *fcsets[] = { NULL };
+ FcCharSet *fccharset;
+ int i, f, numspecs = 0;
+
+ for (i = 0, xp = winx, yp = winy + font->ascent + win.cyo; i < len; ++i) {
+ /* Fetch rune and mode for current glyph. */
+ rune = glyphs[i].u;
+ mode = glyphs[i].mode;
+
+ /* Skip dummy wide-character spacing. */
+ if (mode == ATTR_WDUMMY)
+ continue;
+
+ /* Determine font for glyph if different from previous glyph. */
+ if (prevmode != mode) {
+ prevmode = mode;
+ font = &dc.font;
+ frcflags = FRC_NORMAL;
+ runewidth = win.cw * ((mode & ATTR_WIDE) ? 2.0f : 1.0f);
+ if ((mode & ATTR_ITALIC) && (mode & ATTR_BOLD)) {
+ font = &dc.ibfont;
+ frcflags = FRC_ITALICBOLD;
+ } else if (mode & ATTR_ITALIC) {
+ font = &dc.ifont;
+ frcflags = FRC_ITALIC;
+ } else if (mode & ATTR_BOLD) {
+ font = &dc.bfont;
+ frcflags = FRC_BOLD;
+ }
+ yp = winy + font->ascent + win.cyo;
+ }
+
+ /* Lookup character index with default font. */
+ glyphidx = XftCharIndex(xw.dpy, font->match, rune);
+ if (glyphidx) {
+ specs[numspecs].font = font->match;
+ specs[numspecs].glyph = glyphidx;
+ specs[numspecs].x = (short)xp;
+ specs[numspecs].y = (short)yp;
+ xp += runewidth;
+ numspecs++;
+ continue;
+ }
+
+ /* Fallback on font cache, search the font cache for match. */
+ for (f = 0; f < frclen; f++) {
+ glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune);
+ /* Everything correct. */
+ if (glyphidx && frc[f].flags == frcflags)
+ break;
+ /* We got a default font for a not found glyph. */
+ if (!glyphidx && frc[f].flags == frcflags
+ && frc[f].unicodep == rune) {
+ break;
+ }
+ }
+
+ /* Nothing was found. Use fontconfig to find matching font. */
+ if (f >= frclen) {
+ if (!font->set)
+ font->set = FcFontSort(0, font->pattern,
+ 1, 0, &fcres);
+ fcsets[0] = font->set;
+
+ /*
+ * Nothing was found in the cache. Now use
+ * some dozen of Fontconfig calls to get the
+ * font for one single character.
+ *
+ * Xft and fontconfig are design failures.
+ */
+ fcpattern = FcPatternDuplicate(font->pattern);
+ fccharset = FcCharSetCreate();
+
+ FcCharSetAddChar(fccharset, rune);
+ FcPatternAddCharSet(fcpattern, FC_CHARSET,
+ fccharset);
+ FcPatternAddBool(fcpattern, FC_SCALABLE, 1);
+
+ FcConfigSubstitute(0, fcpattern,
+ FcMatchPattern);
+ FcDefaultSubstitute(fcpattern);
+
+ fontpattern = FcFontSetMatch(0, fcsets, 1,
+ fcpattern, &fcres);
+
+ /*
+ * Overwrite or create the new cache entry.
+ */
+ if (frclen >= LEN(frc)) {
+ frclen = LEN(frc) - 1;
+ XftFontClose(xw.dpy, frc[frclen].font);
+ frc[frclen].unicodep = 0;
+ }
+
+ frc[frclen].font = XftFontOpenPattern(xw.dpy,
+ fontpattern);
+ if (!frc[frclen].font)
+ die("XftFontOpenPattern failed seeking fallback font: %s\n",
+ strerror(errno));
+ frc[frclen].flags = frcflags;
+ frc[frclen].unicodep = rune;
+
+ glyphidx = XftCharIndex(xw.dpy, frc[frclen].font, rune);
+
+ f = frclen;
+ frclen++;
+
+ FcPatternDestroy(fcpattern);
+ FcCharSetDestroy(fccharset);
+ }
+
+ specs[numspecs].font = frc[f].font;
+ specs[numspecs].glyph = glyphidx;
+ specs[numspecs].x = (short)xp;
+ specs[numspecs].y = (short)yp;
+ xp += runewidth;
+ numspecs++;
+ }
+
+ return numspecs;
+}
+
+void
+xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y)
+{
+ int charlen = len * ((base.mode & ATTR_WIDE) ? 2 : 1);
+ int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch,
+ width = charlen * win.cw;
+ 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) {
+ if (dc.ibfont.badslant || dc.ibfont.badweight)
+ base.fg = defaultattr;
+ } else if ((base.mode & ATTR_ITALIC && dc.ifont.badslant) ||
+ (base.mode & ATTR_BOLD && dc.bfont.badweight)) {
+ base.fg = defaultattr;
+ }
+
+ if (IS_TRUECOL(base.fg)) {
+ colfg.alpha = 0xffff;
+ colfg.red = TRUERED(base.fg);
+ colfg.green = TRUEGREEN(base.fg);
+ colfg.blue = TRUEBLUE(base.fg);
+ XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg, &truefg);
+ fg = &truefg;
+ } else {
+ fg = &dc.col[base.fg];
+ }
+
+ if (IS_TRUECOL(base.bg)) {
+ colbg.alpha = 0xffff;
+ colbg.green = TRUEGREEN(base.bg);
+ colbg.red = TRUERED(base.bg);
+ colbg.blue = TRUEBLUE(base.bg);
+ XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colbg, &truebg);
+ bg = &truebg;
+ } else {
+ bg = &dc.col[base.bg];
+ }
+
+ /* Change basic system colors [0-7] to bright system colors [8-15] */
+ if ((base.mode & ATTR_BOLD_FAINT) == ATTR_BOLD && BETWEEN(base.fg, 0, 7))
+ fg = &dc.col[base.fg];
+
+ if (IS_SET(MODE_REVERSE)) {
+ if (fg == &dc.col[defaultfg]) {
+ fg = &dc.col[defaultbg];
+ } else {
+ colfg.red = ~fg->color.red;
+ colfg.green = ~fg->color.green;
+ colfg.blue = ~fg->color.blue;
+ colfg.alpha = fg->color.alpha;
+ XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg,
+ &revfg);
+ fg = &revfg;
+ }
+
+ if (bg == &dc.col[defaultbg]) {
+ bg = &dc.col[defaultfg];
+ } else {
+ colbg.red = ~bg->color.red;
+ colbg.green = ~bg->color.green;
+ colbg.blue = ~bg->color.blue;
+ colbg.alpha = bg->color.alpha;
+ XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colbg,
+ &revbg);
+ bg = &revbg;
+ }
+ }
+
+ if ((base.mode & ATTR_BOLD_FAINT) == ATTR_FAINT) {
+ colfg.red = fg->color.red / 2;
+ colfg.green = fg->color.green / 2;
+ colfg.blue = fg->color.blue / 2;
+ colfg.alpha = fg->color.alpha;
+ XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg, &revfg);
+ fg = &revfg;
+ }
+
+ if (base.mode & ATTR_REVERSE) {
+ temp = fg;
+ fg = bg;
+ bg = temp;
+ }
+
+ if (base.mode & ATTR_BLINK && win.mode & MODE_BLINK)
+ fg = bg;
+
+ if (base.mode & ATTR_INVISIBLE)
+ fg = 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);
+
+ /* Clean up the region we want to draw to. */
+ XftDrawRect(xw.draw, bg, winx, winy, width, win.ch);
+
+ /* Set the clip region because Xft is sometimes dirty. */
+ r.x = 0;
+ r.y = 0;
+ r.height = win.ch;
+ r.width = width;
+ XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1);
+
+ /* Render the glyphs. */
+ XftDrawGlyphFontSpec(xw.draw, fg, specs, len);
+
+ /* Render underline and strikethrough. */
+ if (base.mode & ATTR_UNDERLINE) {
+ XftDrawRect(xw.draw, fg, winx, winy + win.cyo + dc.font.ascent + 1,
+ width, 1);
+ }
+
+ if (base.mode & ATTR_STRUCK) {
+ XftDrawRect(xw.draw, fg, winx, winy + win.cyo + 2 * dc.font.ascent / 3,
+ width, 1);
+ }
+
+ /* Reset clip to none. */
+ XftDrawSetClip(xw.draw, 0);
+}
+
+void
+xdrawglyph(Glyph g, int x, int y)
+{
+ int numspecs;
+ XftGlyphFontSpec spec;
+
+ numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y);
+ xdrawglyphfontspecs(&spec, g, numspecs, x, y);
+}
+
+void
+xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
+{
+ Color drawcol;
+
+ /* remove the old cursor */
+ if (selected(ox, oy))
+ og.mode ^= ATTR_REVERSE;
+ xdrawglyph(og, ox, oy);
+
+ if (IS_SET(MODE_HIDE))
+ return;
+
+ /*
+ * Select the right color for the right mode.
+ */
+ g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE;
+
+ if (IS_SET(MODE_REVERSE)) {
+ g.mode |= ATTR_REVERSE;
+ g.bg = defaultfg;
+ if (selected(cx, cy)) {
+ drawcol = dc.col[defaultcs];
+ g.fg = defaultrcs;
+ } else {
+ drawcol = dc.col[defaultrcs];
+ g.fg = defaultcs;
+ }
+ } else {
+ if (selected(cx, cy)) {
+ g.fg = defaultfg;
+ g.bg = defaultrcs;
+ } else {
+ g.fg = defaultbg;
+ g.bg = defaultcs;
+ }
+ drawcol = dc.col[g.bg];
+ }
+
+ /* draw the new one */
+ if (IS_SET(MODE_FOCUSED)) {
+ switch (win.cursor) {
+ case 7: /* st extension: snowman (U+2603) */
+ g.u = 0x2603;
+ case 0: /* Blinking Block */
+ case 1: /* Blinking Block (Default) */
+ case 2: /* Steady Block */
+ xdrawglyph(g, cx, cy);
+ break;
+ case 3: /* Blinking Underline */
+ case 4: /* Steady Underline */
+ XftDrawRect(xw.draw, &drawcol,
+ borderpx + cx * win.cw,
+ borderpx + (cy + 1) * win.ch - \
+ cursorthickness,
+ win.cw, cursorthickness);
+ break;
+ case 5: /* Blinking bar */
+ case 6: /* Steady bar */
+ XftDrawRect(xw.draw, &drawcol,
+ borderpx + cx * win.cw,
+ borderpx + cy * win.ch,
+ cursorthickness, win.ch);
+ break;
+ }
+ } else {
+ XftDrawRect(xw.draw, &drawcol,
+ borderpx + cx * win.cw,
+ borderpx + cy * win.ch,
+ win.cw - 1, 1);
+ XftDrawRect(xw.draw, &drawcol,
+ borderpx + cx * win.cw,
+ borderpx + cy * win.ch,
+ 1, win.ch - 1);
+ XftDrawRect(xw.draw, &drawcol,
+ borderpx + (cx + 1) * win.cw - 1,
+ borderpx + cy * win.ch,
+ 1, win.ch - 1);
+ XftDrawRect(xw.draw, &drawcol,
+ borderpx + cx * win.cw,
+ borderpx + (cy + 1) * win.ch - 1,
+ win.cw, 1);
+ }
+}
+
+void
+xsetenv(void)
+{
+ char buf[sizeof(long) * 8 + 1];
+
+ snprintf(buf, sizeof(buf), "%lu", xw.win);
+ setenv("WINDOWID", buf, 1);
+}
+
+void
+xsettitle(char *p)
+{
+ XTextProperty prop;
+ DEFAULT(p, opt_title);
+
+ Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
+ &prop);
+ XSetWMName(xw.dpy, xw.win, &prop);
+ XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmname);
+ XFree(prop.value);
+}
+
+int
+xstartdraw(void)
+{
+ return IS_SET(MODE_VISIBLE);
+}
+
+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))
+ new.mode ^= ATTR_REVERSE;
+ if (i > 0 && ATTRCMP(base, new)) {
+ xdrawglyphfontspecs(specs, base, i, ox, y1);
+ specs += i;
+ numspecs -= i;
+ i = 0;
+ }
+ if (i == 0) {
+ ox = x;
+ base = new;
+ }
+ i++;
+ }
+ if (i > 0)
+ xdrawglyphfontspecs(specs, base, i, ox, y1);
+}
+
+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);
+}
+
+void
+expose(XEvent *ev)
+{
+ redraw();
+}
+
+void
+visibility(XEvent *ev)
+{
+ XVisibilityEvent *e = &ev->xvisibility;
+
+ MODBIT(win.mode, e->state != VisibilityFullyObscured, MODE_VISIBLE);
+}
+
+void
+unmap(XEvent *ev)
+{
+ win.mode &= ~MODE_VISIBLE;
+}
+
+void
+xsetpointermotion(int set)
+{
+ MODBIT(xw.attrs.event_mask, set, PointerMotionMask);
+ XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs);
+}
+
+void
+xsetmode(int set, unsigned int flags)
+{
+ int mode = win.mode;
+ MODBIT(win.mode, set, flags);
+ if ((win.mode & MODE_REVERSE) != (mode & MODE_REVERSE))
+ redraw();
+}
+
+int
+xsetcursor(int cursor)
+{
+ DEFAULT(cursor, 1);
+ if (!BETWEEN(cursor, 0, 6))
+ return 1;
+ win.cursor = cursor;
+ return 0;
+}
+
+void
+xseturgency(int add)
+{
+ XWMHints *h = XGetWMHints(xw.dpy, xw.win);
+
+ MODBIT(h->flags, add, XUrgencyHint);
+ XSetWMHints(xw.dpy, xw.win, h);
+ XFree(h);
+}
+
+void
+xbell(void)
+{
+ if (!(IS_SET(MODE_FOCUSED)))
+ xseturgency(1);
+ if (bellvolume)
+ XkbBell(xw.dpy, xw.win, bellvolume, (Atom)NULL);
+}
+
+void
+focus(XEvent *ev)
+{
+ XFocusChangeEvent *e = &ev->xfocus;
+
+ if (e->mode == NotifyGrab)
+ return;
+
+ if (ev->type == FocusIn) {
+ XSetICFocus(xw.xic);
+ win.mode |= MODE_FOCUSED;
+ xseturgency(0);
+ if (IS_SET(MODE_FOCUS))
+ ttywrite("\033[I", 3, 0);
+ } else {
+ XUnsetICFocus(xw.xic);
+ win.mode &= ~MODE_FOCUSED;
+ if (IS_SET(MODE_FOCUS))
+ ttywrite("\033[O", 3, 0);
+ }
+}
+
+int
+match(uint mask, uint state)
+{
+ return mask == XK_ANY_MOD || mask == (state & ~ignoremod);
+}
+
+char*
+kmap(KeySym k, uint state)
+{
+ Key *kp;
+ int i;
+
+ /* Check for mapped keys out of X11 function keys. */
+ for (i = 0; i < LEN(mappedkeys); i++) {
+ if (mappedkeys[i] == k)
+ break;
+ }
+ if (i == LEN(mappedkeys)) {
+ if ((k & 0xFFFF) < 0xFD00)
+ return NULL;
+ }
+
+ for (kp = key; kp < key + LEN(key); kp++) {
+ if (kp->k != k)
+ continue;
+
+ if (!match(kp->mask, state))
+ continue;
+
+ if (IS_SET(MODE_APPKEYPAD) ? kp->appkey < 0 : kp->appkey > 0)
+ continue;
+ if (IS_SET(MODE_NUMLOCK) && kp->appkey == 2)
+ continue;
+
+ if (IS_SET(MODE_APPCURSOR) ? kp->appcursor < 0 : kp->appcursor > 0)
+ continue;
+
+ return kp->s;
+ }
+
+ return NULL;
+}
+
+void
+kpress(XEvent *ev)
+{
+ XKeyEvent *e = &ev->xkey;
+ KeySym ksym;
+ char buf[32], *customkey;
+ int len;
+ Rune c;
+ Status status;
+ Shortcut *bp;
+
+ if (IS_SET(MODE_KBDLOCK))
+ return;
+
+ len = XmbLookupString(xw.xic, e, buf, sizeof buf, &ksym, &status);
+ /* 1. shortcuts */
+ for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
+ if (ksym == bp->keysym && match(bp->mod, e->state)) {
+ bp->func(&(bp->arg));
+ return;
+ }
+ }
+
+ /* 2. custom keys from config.h */
+ if ((customkey = kmap(ksym, e->state))) {
+ ttywrite(customkey, strlen(customkey), 1);
+ return;
+ }
+
+ /* 3. composed string from input method */
+ if (len == 0)
+ return;
+ if (len == 1 && e->state & Mod1Mask) {
+ if (IS_SET(MODE_8BIT)) {
+ if (*buf < 0177) {
+ c = *buf | 0x80;
+ len = utf8encode(c, buf);
+ }
+ } else {
+ buf[1] = buf[0];
+ buf[0] = '\033';
+ len = 2;
+ }
+ }
+ ttywrite(buf, len, 1);
+}
+
+
+void
+cmessage(XEvent *e)
+{
+ /*
+ * See xembed specs
+ * http://standards.freedesktop.org/xembed-spec/xembed-spec-latest.html
+ */
+ if (e->xclient.message_type == xw.xembed && e->xclient.format == 32) {
+ if (e->xclient.data.l[1] == XEMBED_FOCUS_IN) {
+ win.mode |= MODE_FOCUSED;
+ xseturgency(0);
+ } else if (e->xclient.data.l[1] == XEMBED_FOCUS_OUT) {
+ win.mode &= ~MODE_FOCUSED;
+ }
+ } else if (e->xclient.data.l[0] == xw.wmdeletewin) {
+ ttyhangup();
+ exit(0);
+ }
+}
+
+void
+resize(XEvent *e)
+{
+ if (e->xconfigure.width == win.w && e->xconfigure.height == win.h)
+ return;
+
+ cresize(e->xconfigure.width, e->xconfigure.height);
+}
+
+void
+run(void)
+{
+ XEvent ev;
+ int w = win.w, h = win.h;
+ fd_set rfd;
+ int xfd = XConnectionNumber(xw.dpy), xev, blinkset = 0, dodraw = 0;
+ int ttyfd;
+ struct timespec drawtimeout, *tv = NULL, now, last, lastblink;
+ long deltatime;
+
+ /* Waiting for window mapping */
+ do {
+ XNextEvent(xw.dpy, &ev);
+ /*
+ * This XFilterEvent call is required because of XOpenIM. It
+ * does filter out the key event and some client message for
+ * the input method too.
+ */
+ if (XFilterEvent(&ev, None))
+ continue;
+ if (ev.type == ConfigureNotify) {
+ w = ev.xconfigure.width;
+ h = ev.xconfigure.height;
+ }
+ } while (ev.type != MapNotify);
+
+ ttyfd = ttynew(opt_line, shell, opt_io, opt_cmd);
+ cresize(w, h);
+
+ clock_gettime(CLOCK_MONOTONIC, &last);
+ lastblink = last;
+
+ for (xev = actionfps;;) {
+ FD_ZERO(&rfd);
+ FD_SET(ttyfd, &rfd);
+ FD_SET(xfd, &rfd);
+
+ if (pselect(MAX(xfd, ttyfd)+1, &rfd, NULL, NULL, tv, NULL) < 0) {
+ if (errno == EINTR)
+ continue;
+ die("select failed: %s\n", strerror(errno));
+ }
+ if (FD_ISSET(ttyfd, &rfd)) {
+ ttyread();
+ if (blinktimeout) {
+ blinkset = tattrset(ATTR_BLINK);
+ if (!blinkset)
+ MODBIT(win.mode, 0, MODE_BLINK);
+ }
+ }
+
+ if (FD_ISSET(xfd, &rfd))
+ xev = actionfps;
+
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ drawtimeout.tv_sec = 0;
+ drawtimeout.tv_nsec = (1000 * 1E6)/ xfps;
+ tv = &drawtimeout;
+
+ dodraw = 0;
+ if (blinktimeout && TIMEDIFF(now, lastblink) > blinktimeout) {
+ tsetdirtattr(ATTR_BLINK);
+ win.mode ^= MODE_BLINK;
+ lastblink = now;
+ dodraw = 1;
+ }
+ deltatime = TIMEDIFF(now, last);
+ if (deltatime > 1000 / (xev ? xfps : actionfps)) {
+ dodraw = 1;
+ last = now;
+ }
+
+ if (dodraw) {
+ while (XPending(xw.dpy)) {
+ XNextEvent(xw.dpy, &ev);
+ if (XFilterEvent(&ev, None))
+ continue;
+ if (handler[ev.type])
+ (handler[ev.type])(&ev);
+ }
+
+ draw();
+ XFlush(xw.dpy);
+
+ if (xev && !FD_ISSET(xfd, &rfd))
+ xev--;
+ if (!FD_ISSET(ttyfd, &rfd) && !FD_ISSET(xfd, &rfd)) {
+ if (blinkset) {
+ if (TIMEDIFF(now, lastblink) \
+ > blinktimeout) {
+ drawtimeout.tv_nsec = 1000;
+ } else {
+ drawtimeout.tv_nsec = (1E6 * \
+ (blinktimeout - \
+ TIMEDIFF(now,
+ lastblink)));
+ }
+ drawtimeout.tv_sec = \
+ drawtimeout.tv_nsec / 1E9;
+ drawtimeout.tv_nsec %= (long)1E9;
+ } else {
+ tv = NULL;
+ }
+ }
+ }
+ }
+}
+
+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);
+}
+
+int
+main(int argc, char *argv[])
+{
+ xw.l = xw.t = 0;
+ xw.isfixed = False;
+ win.cursor = cursorshape;
+
+ ARGBEGIN {
+ case 'a':
+ allowaltscreen = 0;
+ break;
+ case 'c':
+ opt_class = EARGF(usage());
+ break;
+ case 'e':
+ if (argc > 0)
+ --argc, ++argv;
+ goto run;
+ case 'f':
+ opt_font = EARGF(usage());
+ break;
+ case 'g':
+ xw.gm = XParseGeometry(EARGF(usage()),
+ &xw.l, &xw.t, &cols, &rows);
+ break;
+ case 'i':
+ xw.isfixed = 1;
+ break;
+ case 'o':
+ opt_io = EARGF(usage());
+ break;
+ case 'l':
+ opt_line = EARGF(usage());
+ break;
+ case 'n':
+ opt_name = EARGF(usage());
+ break;
+ case 't':
+ case 'T':
+ opt_title = EARGF(usage());
+ break;
+ case 'w':
+ opt_embed = EARGF(usage());
+ break;
+ case 'v':
+ die("%s " VERSION " (c) 2010-2016 st engineers\n", argv0);
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+run:
+ if (argc > 0) /* eat all remaining arguments */
+ opt_cmd = argv;
+
+ if (!opt_title)
+ opt_title = (opt_line || !opt_cmd) ? "st" : opt_cmd[0];
+
+ setlocale(LC_CTYPE, "");
+ XSetLocaleModifiers("");
+ cols = MAX(cols, 1);
+ rows = MAX(rows, 1);
+ tnew(cols, rows);
+ xinit(cols, rows);
+ xsetenv();
+ selinit();
+ run();
+
+ return 0;
+}