commit 7674c7b79530f6ee8b84dc865fe9f399e29b089c
parent 9963ae674f248068768124f0e999da4eec2d80e0
Author: robert <robertrussell.72001@gmail.com>
Date: Sun, 6 Jun 2021 22:57:31 -0700
Reorganize (untested)
Diffstat:
| A | config.def.c | | | 368 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| M | config.def.h | | | 492 | ++++++++++++++----------------------------------------------------------------- |
| M | st.c | | | 281 | ++++++++++--------------------------------------------------------------------- |
| M | st.h | | | 79 | +++++++++++++------------------------------------------------------------------ |
| A | util.c | | | 231 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | util.h | | | 34 | ++++++++++++++++++++++++++++++++++ |
| M | win.h | | | 10 | +++++++++- |
| M | x.c | | | 118 | +++++++++++++++++++++++++++---------------------------------------------------- |
8 files changed, 817 insertions(+), 796 deletions(-)
diff --git a/config.def.c b/config.def.c
@@ -0,0 +1,368 @@
+/* See LICENSE file for license details. */
+#include <stdint.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <X11/Xlib.h>
+#include <X11/cursorfont.h>
+#include <X11/keysym.h>
+
+#include "util.h"
+#include "config.h"
+#include "st.h"
+#include "win.h"
+
+static void clipcopy(uint, Arg);
+static void clippaste(uint, Arg);
+static void selpaste(uint, Arg);
+static void zoomrel(uint, Arg);
+static void zoomrst(uint, Arg);
+static void numlock(uint, Arg);
+static void sendstr(uint, Arg);
+static void sendcsi(uint, Arg);
+static void printscreen(uint, Arg);
+static void selprint(uint, Arg);
+static void sendbreak(uint, Arg);
+static void togprinter(uint, Arg);
+
+/* See: http://freedesktop.org/software/fontconfig/fontconfig-user.html */
+char *font = "Fira Mono:pixelsize=18:antialias=true:autohint=true";
+int borderpx = 2;
+/* Kerning / character bounding-box multipliers */
+float cwscale = 1.0;
+float chscale = 1.0;
+
+/* What program is execed by st depends of these precedence rules:
+ * 1: program passed with -e
+ * 2: scroll and/or utmp
+ * 3: SHELL environment variable
+ * 4: value of shell in /etc/passwd
+ * 5: value of shell in config.h */
+char *shell = "/bin/sh";
+char *utmp = 0;
+/* scroll program: to enable use a string like "scroll" */
+char *scroll = 0;
+char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400";
+
+/* identification sequence returned in DA and DECID */
+char *vtiden = "\033[?6c";
+
+wchar_t *worddelimiters = L" "; /* E.g., L" `'\"()[]{}" */
+
+/* selection timeouts (in milliseconds) */
+uint doubleclicktimeout = 300;
+uint tripleclicktimeout = 600;
+
+int allowaltscreen = 1;
+
+/* allow certain non-interactive (insecure) window operations such as:
+ setting the clipboard text */
+int allowwindowops = 0;
+
+/* draw latency range in ms - from new content/keypress/etc until drawing.
+ * within this range, st draws when content stops arriving (idle). mostly it's
+ * near minlatency, but it waits longer for slow updates to avoid partial draw.
+ * low minlatency will tear/flicker more, as it can "detect" idle too early. */
+double minlatency = 8;
+double maxlatency = 33;
+
+/* blinking timeout (set to 0 to disable blinking) for the terminal blinking
+ * attribute. */
+uint blinktimeout = 800;
+
+/* thickness of underline and bar cursors */
+uint cursorthickness = 2;
+
+/* bell volume. It must be a value between -100 and 100.
+ * Use 0 to disabling it. */
+int bellvolume = 0;
+
+char *termname = "st-256color";
+
+/* spaces per tab
+ * When you are changing this value, don't forget to adapt the »it« value in
+ * the st.info and appropriately install the st.info in the environment where
+ * you use this st version.
+ * Secondly make sure your kernel is not expanding tabs. When running
+ * `stty -a`, »tab0« should appear. You can tell the terminal to not expand
+ * tabs by running `stty tabs`. */
+uint tabspaces = 4;
+
+/* Terminal colors (16 first used in escape sequence) */
+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",
+};
+
+/*
+ * Default colors (colorname index)
+ * foreground, background, cursor, reverse cursor
+ */
+uint defaultfg = 7;
+uint defaultbg = 0;
+uint defaultcs = 256;
+uint defaultrcs = 257;
+
+/* Default shape of cursor
+ * 2: Block ("█")
+ * 4: Underline ("_")
+ * 6: Bar ("|")
+ * 7: Snowman ("☃") */
+uint cursorshape = 2;
+
+uint cols = 80;
+uint rows = 24;
+
+/* Default colour and shape of the mouse cursor */
+uint mouseshape = XC_xterm;
+uint mousefg = 7;
+uint mousebg = 0;
+
+/* Color used to display font attributes when fontconfig selected a font which
+ * doesn't match the ones requested. */
+uint defaultattr = 11;
+
+/* Force mouse select/shortcuts while mask is active (when MODE_MOUSE is set).
+ * Note that if you want to use ShiftMask with selmasks, set this to an other
+ * modifier, set to 0 to not use it. */
+uint forcemousemod = ShiftMask; // TODO
+
+#define R RELS
+#define S SHFT
+#define C CTRL
+#define A ALT
+#define TERMMOD (CTRL|SHFT)
+#define SENDSTR(s_) sendstr, .arg = ARG_STR((s_))
+#define SENDCSI(n,m,c) sendcsi, .arg = ARG_CSI((n),(m),(c))
+#define SENDTILDE(n) SENDCSI((n),0,'~')
+#define SENDUNICODE(cp) SENDCSI((cp),S,'u')
+#define ARG_DUMMY {.i = 0}
+
+/* Beware that overloading Button1 will disable the selection. */
+Btn btns[] = {
+ { Button2, R, 0, selpaste, ARG_DUMMY },
+ { Button4, S, KEXCL(S)|R, SENDSTR("\033[5;2~") },
+ { Button4, 0, R, SENDSTR("\031") },
+ { Button5, S, KEXCL(S)|R, SENDSTR("\033[6;2~") },
+ { Button5, 0, R, SENDSTR("\005") },
+};
+
+/* TODO: add RELS to clr */
+Key keys[] = {
+ /* Shortcuts (must be first to get precedence) */
+ { XK_Home, TERMMOD, KEXCL(TERMMOD), zoomrst, ARG_DUMMY },
+ { XK_Prior, TERMMOD, KEXCL(TERMMOD), zoomrel, {.d = +1} },
+ { XK_Next, TERMMOD, KEXCL(TERMMOD), zoomrel, {.d = -1} },
+ { XK_Print, C, KEXCL(C), togprinter, ARG_DUMMY },
+ { XK_Print, S, KEXCL(S), printscreen, ARG_DUMMY },
+ { XK_Print, 0, 0, selprint, ARG_DUMMY },
+ { XK_Insert, S, KEXCL(S), selpaste, ARG_DUMMY },
+ { XK_Break, 0, 0, sendbreak, ARG_DUMMY },
+ { XK_Num_Lock, TERMMOD, KEXCL(TERMMOD), numlock, ARG_DUMMY },
+ { XK_C, TERMMOD, KEXCL(TERMMOD), clipcopy, ARG_DUMMY },
+ { XK_V, TERMMOD, KEXCL(TERMMOD), clippaste, ARG_DUMMY },
+ { XK_Y, TERMMOD, KEXCL(TERMMOD), selpaste, ARG_DUMMY },
+
+ /* Latin1 special cases (kpress handles most cases already) */
+ { XK_space, C, KEXCL(C), SENDSTR("\0") },
+ { XK_space, C|A, KEXCL(C|A), SENDSTR("\033\0") },
+ { XK_at, C, 0, SENDUNICODE('@') }, /* '@'-64 is NUL */
+ { XK_O, A, 0, SENDUNICODE('O') }, /* ESC O is SS3 */
+ { XK_i, C, 0, SENDUNICODE('i') }, /* 'i'-64 is tab */
+ { XK_m, C, 0, SENDUNICODE('m') }, /* 'm'-64 is CR */
+ { XK_bracketleft, C, 0, SENDUNICODE('[') }, /* '['-64 is ESC */
+ { XK_bracketleft, A, 0, SENDUNICODE('[') }, /* ESC [ is CSI */
+
+ /* Misc */
+ { XK_BackSpace, 0, KMOD, SENDSTR("\177") },
+ { XK_BackSpace, A, KEXCL(A), SENDSTR("\033\177") },
+ { XK_BackSpace, 0, 0, SENDCSI(127,0,'u') },
+ { XK_Tab, 0, KMOD, SENDSTR("\t") },
+ { XK_Tab, A, KEXCL(A), SENDSTR("\033\t") },
+ { XK_Tab, S, 0, SENDCSI(1,S,'Z') },
+ { XK_Tab, 0, 0, SENDCSI('\t',0,'u') },
+ { XK_Return, 0, KMOD, SENDSTR("\r") },
+ { XK_Return, A, KEXCL(A), SENDSTR("\033\r") },
+ { XK_Return, 0, 0, SENDCSI('\r',0,'u') },
+ { XK_Escape, 0, KMOD, SENDSTR("\033") },
+ { XK_Escape, A, KEXCL(A), SENDSTR("\033\033") },
+ { XK_Escape, 0, 0, SENDCSI(27,0,'u') },
+ { XK_Delete, 0, 0, SENDTILDE(3) },
+ { XK_Home, CURS, KMOD, SENDSTR("\033OH") },
+ { XK_Home, 0, 0, SENDCSI(1,0,'H') },
+ { XK_Left, CURS, KMOD, SENDSTR("\033OD") },
+ { XK_Left, 0, 0, SENDCSI(1,0,'D') },
+ { XK_Up, CURS, KMOD, SENDSTR("\033OA") },
+ { XK_Up, 0, 0, SENDCSI(1,0,'A') },
+ { XK_Right, CURS, KMOD, SENDSTR("\033OC") },
+ { XK_Right, 0, 0, SENDCSI(1,0,'C') },
+ { XK_Down, CURS, KMOD, SENDSTR("\033OB") },
+ { XK_Down, 0, 0, SENDCSI(1,0,'B') },
+ { XK_Prior, 0, 0, SENDTILDE(5) },
+ { XK_Next, 0, 0, SENDTILDE(6) },
+ { XK_End, CURS, KMOD, SENDSTR("\033OF") },
+ { XK_End, 0, 0, SENDCSI(1,0,'F') },
+ { XK_Begin, 0, 0, SENDCSI(1,0,'E') },
+ { XK_Select, 0, 0, SENDTILDE(4) },
+ { XK_Insert, 0, 0, SENDTILDE(2) },
+ { XK_Find, 0, 0, SENDTILDE(1) },
+
+ /* Keypad */
+ { XK_KP_Enter, KPAD, NMLK|KMOD, SENDSTR("\033OM") },
+ { XK_KP_Enter, 0, KMOD, SENDSTR("\r") },
+ { XK_KP_Enter, A, KEXCL(A), SENDSTR("\033\r") },
+ { XK_KP_Enter, 0, 0, SENDCSI('\r',0,'u') },
+ { XK_KP_F1, 0, KMOD, SENDSTR("\033OP") },
+ { XK_KP_F1, 0, 0, SENDCSI(1,0,'P') },
+ { XK_KP_F2, 0, KMOD, SENDSTR("\033OQ") },
+ { XK_KP_F2, 0, 0, SENDCSI(1,0,'Q') },
+ { XK_KP_F3, 0, KMOD, SENDSTR("\033OR") },
+ { XK_KP_F3, 0, 0, SENDCSI(1,0,'R') },
+ { XK_KP_F4, 0, KMOD, SENDSTR("\033OS") },
+ { XK_KP_F4, 0, 0, SENDCSI(1,0,'S') },
+ { XK_KP_Home, CURS, KMOD, SENDSTR("\033OH") },
+ { XK_KP_Home, 0, 0, SENDCSI(1,0,'H') },
+ { XK_KP_Left, CURS, KMOD, SENDSTR("\033OD") },
+ { XK_KP_Left, 0, 0, SENDCSI(1,0,'D') },
+ { XK_KP_Up, CURS, KMOD, SENDSTR("\033OA") },
+ { XK_KP_Up, 0, 0, SENDCSI(1,0,'A') },
+ { XK_KP_Right, CURS, KMOD, SENDSTR("\033OC") },
+ { XK_KP_Right, 0, 0, SENDCSI(1,0,'C') },
+ { XK_KP_Down, CURS, KMOD, SENDSTR("\033OB") },
+ { XK_KP_Down, 0, 0, SENDCSI(1,0,'B') },
+ { XK_KP_Prior, 0, 0, SENDTILDE(5) },
+ { XK_KP_Next, 0, 0, SENDTILDE(6) },
+ { XK_KP_End, CURS, KMOD, SENDSTR("\033OF") },
+ { XK_KP_End, 0, 0, SENDCSI(1,0,'F') },
+ { XK_KP_Begin, 0, 0, SENDCSI(1,0,'E') },
+ { XK_KP_Insert, 0, 0, SENDTILDE(2) },
+ { XK_KP_Delete, 0, 0, SENDTILDE(3) },
+ { XK_KP_Equal, KPAD, NMLK|KMOD, SENDSTR("\033OX") },
+ { XK_KP_Multiply, KPAD, NMLK|KMOD, SENDSTR("\033Oj") },
+ { XK_KP_Add, KPAD, NMLK|KMOD, SENDSTR("\033Ok") },
+ { XK_KP_Separator, KPAD, NMLK|KMOD, SENDSTR("\033Ol") },
+ { XK_KP_Subtract, KPAD, NMLK|KMOD, SENDSTR("\033Om") },
+ { XK_KP_Decimal, KPAD, NMLK|KMOD, SENDSTR("\033On") },
+ { XK_KP_Divide, KPAD, NMLK|KMOD, SENDSTR("\033Oo") },
+ { XK_KP_0, KPAD, NMLK|KMOD, SENDSTR("\033Op") },
+ { XK_KP_1, KPAD, NMLK|KMOD, SENDSTR("\033Oq") },
+ { XK_KP_2, KPAD, NMLK|KMOD, SENDSTR("\033Or") },
+ { XK_KP_3, KPAD, NMLK|KMOD, SENDSTR("\033Os") },
+ { XK_KP_4, KPAD, NMLK|KMOD, SENDSTR("\033Ot") },
+ { XK_KP_5, KPAD, NMLK|KMOD, SENDSTR("\033Ou") },
+ { XK_KP_6, KPAD, NMLK|KMOD, SENDSTR("\033Ov") },
+ { XK_KP_7, KPAD, NMLK|KMOD, SENDSTR("\033Ow") },
+ { XK_KP_8, KPAD, NMLK|KMOD, SENDSTR("\033Ox") },
+ { XK_KP_9, KPAD, NMLK|KMOD, SENDSTR("\033Oy") },
+
+ /* Function */
+ { XK_F1, 0, 0, SENDTILDE(11) },
+ { XK_F2, 0, 0, SENDTILDE(12) },
+ { XK_F3, 0, 0, SENDTILDE(13) },
+ { XK_F4, 0, 0, SENDTILDE(14) },
+ { XK_F5, 0, 0, SENDTILDE(15) },
+ { XK_F6, 0, 0, SENDTILDE(17) },
+ { XK_F7, 0, 0, SENDTILDE(18) },
+ { XK_F8, 0, 0, SENDTILDE(19) },
+ { XK_F9, 0, 0, SENDTILDE(20) },
+ { XK_F10, 0, 0, SENDTILDE(21) },
+ { XK_F11, 0, 0, SENDTILDE(23) },
+ { XK_F12, 0, 0, SENDTILDE(24) },
+ { XK_F13, 0, 0, SENDTILDE(25) },
+ { XK_F14, 0, 0, SENDTILDE(26) },
+ { XK_F15, 0, 0, SENDTILDE(28) },
+ { XK_F16, 0, 0, SENDTILDE(29) },
+ { XK_F17, 0, 0, SENDTILDE(31) },
+ { XK_F18, 0, 0, SENDTILDE(32) },
+ { XK_F19, 0, 0, SENDTILDE(33) },
+ { XK_F20, 0, 0, SENDTILDE(34) },
+ /* libtermkey only recognizes up to F20. */
+};
+
+/*
+ * Selection types' masks.
+ * Use the same masks as usual.
+ * Button1Mask is always unset, to make masks match between ButtonPress.
+ * ButtonRelease and MotionNotify.
+ * If no match is found, regular selection is used.
+ */
+// TODO: fix
+uint selmasks[] = {
+ [SEL_RECTANGULAR] = Mod1Mask,
+};
+
+void
+clipcopy(uint state, Arg arg)
+{ xclipcopy(); }
+
+void
+clippaste(uint state, Arg arg)
+{ xclippaste(); }
+
+void
+selpaste(uint state, Arg arg)
+{ xselpaste(); }
+
+void
+zoomrel(uint state, Arg arg)
+{ xzoomrel(arg.d); }
+
+void
+zoomrst(uint state, Arg arg)
+{ xzoomrst(); }
+
+void
+numlock(uint state, Arg arg)
+{ xtogmode(MODE_NUMLOCK); }
+
+void
+sendstr(uint state, Arg arg)
+{ ttywrite(arg.str.s, arg.str.l, 1); }
+
+void
+sendcsi(uint state, Arg arg)
+{
+ char buf[64];
+ size_t len;
+
+ len = csienc(buf, sizeof buf, state, arg.csi.n, arg.csi.m, arg.csi.c);
+ ttywrite(buf, len, 1);
+}
+
+void
+printscreen(uint state, Arg arg)
+{ tdump(); }
+
+void
+selprint(uint state, Arg arg)
+{ tdumpsel(); }
+
+void
+sendbreak(uint state, Arg arg)
+{ tsendbreak(); }
+
+void
+togprinter(uint state, Arg arg)
+{ ttogprinter(); }
diff --git a/config.def.h b/config.def.h
@@ -1,420 +1,100 @@
-/* See LICENSE file for copyright and license details. */
-
-/*
- * appearance
- *
- * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
- */
-static char *font = "Fira Mono:pixelsize=18:antialias=true:autohint=true";
-static int borderpx = 2;
-
-/*
- * What program is execed by st depends of these precedence rules:
- * 1: program passed with -e
- * 2: scroll and/or utmp
- * 3: SHELL environment variable
- * 4: value of shell in /etc/passwd
- * 5: value of shell in config.h
- */
-static char *shell = "/bin/sh";
-char *utmp = NULL;
-/* scroll program: to enable use a string like "scroll" */
-char *scroll = NULL;
-char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400";
-
-/* identification sequence returned in DA and DECID */
-char *vtiden = "\033[?6c";
-
-/* Kerning / character bounding-box multipliers */
-static float cwscale = 1.0;
-static float chscale = 1.0;
-
-/*
- * word delimiter string
- *
- * More advanced example: L" `'\"()[]{}"
- */
-wchar_t *worddelimiters = L" ";
-
-/* selection timeouts (in milliseconds) */
-static unsigned int doubleclicktimeout = 300;
-static unsigned int tripleclicktimeout = 600;
-
-/* alt screens */
-int allowaltscreen = 1;
-
-/* allow certain non-interactive (insecure) window operations such as:
- setting the clipboard text */
-int allowwindowops = 0;
-
-/*
- * draw latency range in ms - from new content/keypress/etc until drawing.
- * within this range, st draws when content stops arriving (idle). mostly it's
- * near minlatency, but it waits longer for slow updates to avoid partial draw.
- * low minlatency will tear/flicker more, as it can "detect" idle too early.
- */
-static double minlatency = 8;
-static double maxlatency = 33;
-
-/*
- * blinking timeout (set to 0 to disable blinking) for the terminal blinking
- * attribute.
- */
-static unsigned int blinktimeout = 800;
-
-/*
- * thickness of underline and bar cursors
- */
-static unsigned int cursorthickness = 2;
-
-/*
- * bell volume. It must be a value between -100 and 100. Use 0 for disabling
- * it
- */
-static int bellvolume = 0;
-
-/* default TERM value */
-char *termname = "st-256color";
-
-/*
- * spaces per tab
- *
- * When you are changing this value, don't forget to adapt the »it« value in
- * the st.info and appropriately install the st.info in the environment where
- * you use this st version.
- *
- * it#$tabspaces,
- *
- * Secondly make sure your kernel is not expanding tabs. When running `stty
- * -a` »tab0« should appear. You can tell the terminal to not expand tabs by
- * running following command:
- *
- * stty tabs
- */
-unsigned int tabspaces = 4;
-
-/* 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",
-};
-
-
-/*
- * Default colors (colorname index)
- * foreground, background, cursor, reverse cursor
- */
-unsigned int defaultfg = 7;
-unsigned int defaultbg = 0;
-static unsigned int defaultcs = 256;
-static unsigned int defaultrcs = 257;
-
-/*
- * Default shape of cursor
- * 2: Block ("█")
- * 4: Underline ("_")
- * 6: Bar ("|")
- * 7: Snowman ("☃")
- */
-static unsigned int cursorshape = 2;
-
-/*
- * Default columns and rows numbers
- */
-
-static unsigned int cols = 80;
-static unsigned int rows = 24;
-
-/*
- * Default colour and shape of the mouse cursor
- */
-static unsigned int mouseshape = XC_xterm;
-static unsigned int mousefg = 7;
-static unsigned int mousebg = 0;
-
-/*
- * Color used to display font attributes when fontconfig selected a font which
- * doesn't match the ones requested.
- */
-static unsigned int defaultattr = 11;
-
-/*
- * Force mouse select/shortcuts while mask is active (when MODE_MOUSE is set).
- * Note that if you want to use ShiftMask with selmasks, set this to an other
- * modifier, set to 0 to not use it.
- */
-static uint forcemousemod = ShiftMask;
-
-/*
- * Internal mouse shortcuts.
- * Beware that overloading Button1 will disable the selection.
- */
-static MouseShortcut mshortcuts[] = {
- /* mask button function argument release */
- { XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 },
- { ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} },
- { XK_ANY_MOD, Button4, ttysend, {.s = "\031"} },
- { ShiftMask, Button5, ttysend, {.s = "\033[6;2~"} },
- { XK_ANY_MOD, Button5, ttysend, {.s = "\005"} },
-};
-
-#define TERMMOD (ControlMask|ShiftMask)
-static Shortcut shortcuts[] = {
- /* mask keysym function argument */
- { XK_ANY_MOD, XK_Break, sendbreak, {.i = 0} },
- { ControlMask, XK_Print, toggleprinter, {.i = 0} },
- { ShiftMask, XK_Print, printscreen, {.i = 0} },
- { XK_ANY_MOD, XK_Print, printsel, {.i = 0} },
- { TERMMOD, XK_Prior, zoom, {.f = +1} },
- { TERMMOD, XK_Next, zoom, {.f = -1} },
- { TERMMOD, XK_Home, zoomreset, {.f = 0} },
- { TERMMOD, XK_C, clipcopy, {.i = 0} },
- { TERMMOD, XK_V, clippaste, {.i = 0} },
- { TERMMOD, XK_Y, selpaste, {.i = 0} },
- { ShiftMask, XK_Insert, selpaste, {.i = 0} },
- { TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
-};
-
-/*
- * State bits to ignore when matching key or button events. By default,
- * numlock (Mod2Mask) and keyboard layout (XK_SWITCH_MOD) are ignored.
- */
-static uint ignoremod = Mod2Mask|XK_SWITCH_MOD;
-
-#define CURS (1<<0)
-#define KPAD (1<<1)
-#define NMLK (1<<2)
-#define MODOFFS 3
-#define S (1<<3)
-#define A (1<<4)
-#define C (1<<5)
-#define ALLM (S|A|C)
-
-#define STR(s_) kencstr, .arg.str.l = sizeof(s_)-1, .arg.str.s = (s_)
-#define CSI(n_,m_,c_) kenccsi, .arg.csi.n = (n_), .arg.csi.m = (m_), .arg.csi.c = (c_)
-#define TILDE(n) CSI((n),0,'~')
-#define UNICODE(cp) CSI((cp),S,'u')
+/* See LICENSE file for license details. */
+/* Requires: wchar.h, X11/X.h, util.h */
+
+#define CURS (1<<0) /* Application cursor mode */
+#define KPAD (1<<1) /* Application keypad mode */
+#define NMLK (1<<2) /* Num lock */
+#define RELS (1<<3) /* Key/buttom release */
+/* To allow checking more boolean properties when matching key/button events,
+ * define them here and modify MODOFFS and TODO. */
+#define MODOFFS 4
+#define SHFT (ShiftMask<<MODOFFS)
+#define CTRL (ControlMask<<MODOFFS)
+#define ALT (Mod1Mask<<MODOFFS)
+#define BTN1 (Button1Mask<<MODOFFS)
+#define BTN2 (Button2Mask<<MODOFFS)
+#define BTN3 (Button3Mask<<MODOFFS)
+#define BTN4 (Button4Mask<<MODOFFS)
+#define BTN5 (Button5Mask<<MODOFFS)
+#define KMOD (SHFT|CTRL|ALT)
+#define KEXCL(m) (KMOD&~(m))
typedef union {
+ int i;
+ uint u;
+ double d;
+ const void *v;
struct {
- uint l;
- char *s;
+ uint l; /* Length of s, excluding null */
+ const char *s;
} str;
struct {
- uint n;
- uchar m;
+ uint n; /* First parameter; ignored if 0 or 1 */
+ uint m; /* State mask */
char c;
} csi;
-} KeyArg;
+} Arg;
+#define ARG_STR(s_) { .str.l = sizeof(s_)-1, .str.s = (s_) }
+#define ARG_CSI(n_,m_,c_) { .csi.n = (n_), .csi.m = (m_), .csi.c = (c_) }
+
+typedef void (*Handler)(uint state, Arg arg);
-typedef int (*KeyEncoder)(char *buf, size_t len,
- KeySym sym, uint mod, KeyArg arg);
+/* Tristate logic: each bit in set/clr is interpreted as follows:
+ * set clr
+ * 0 0 don't care
+ * 0 1 bit must be clear
+ * 1 0 bit must be set
+ * 1 1 unsatisfiable (i.e., useless configuration) */
+
+typedef struct {
+ uint btn;
+ uint set, clr;
+ Handler fn;
+ Arg arg;
+} Btn;
typedef struct {
- /* Tristate logic. Each bit in set/clr is interpreted as follows:
- * set clr
- * 0 0 don't care
- * 0 1 bit must be clear
- * 1 0 bit must be set
- * 1 1 unsatisfiable (i.e., useless configuration) */
KeySym sym;
uint set, clr;
- KeyEncoder fn;
- KeyArg arg;
+ Handler fn;
+ Arg arg;
} Key;
-int
-kencstr(char *buf, size_t len, KeySym sym, uint state, KeyArg arg)
-{
- size_t i;
-
- for (i = 0; i < len-1 && i < arg.str.l; i++)
- buf[i] = arg.str.s[i];
- if (len > 0)
- buf[i] = '\0';
- return i;
-}
-
-int
-kcsi(char *buf, size_t len, uint state, uint n, uchar m, char c)
-{
- uint mod;
-
- mod = (state & ~m) >> MODOFFS;
- if (mod > 0)
- return snprintf(buf, len, "\033[%d;%d%c", n, mod+1, c);
- else if (n > 1)
- return snprintf(buf, len, "\033[%d%c", n, c);
- else
- return snprintf(buf, len, "\033[%c", c);
-}
-
-int
-kenccsi(char *buf, size_t len, KeySym sym, uint state, KeyArg arg)
-{
- kcsi(buf, len, state, arg.csi.n, arg.csi.m, arg.csi.c);
-}
-
-Key keys[] = {
- /* SHORTCUTS (must be first) */
- /* XK_Print */
- /* XK_Break */
- /* XK_Num_Lock */
-
- /* LATIN1 */
- { XK_space, C, A|S, STR("\0") },
- { XK_space, C|A, S, STR("\033\0") },
- { XK_at, C, 0, UNICODE('@') }, /* '@'-64 is NUL */
- { XK_O, A, 0, UNICODE('O') }, /* ESC O is SS3 */
- { XK_i, C, 0, UNICODE('i') }, /* 'i'-64 is tab */
- { XK_m, C, 0, UNICODE('m') }, /* 'm'-64 is CR */
- { XK_bracketleft, C, 0, UNICODE('[') }, /* '['-64 is ESC */
- { XK_bracketleft, A, 0, UNICODE('[') }, /* ESC [ is CSI */
-
- /* MISC */
- { XK_BackSpace, 0, ALLM, STR("\177") },
- { XK_BackSpace, A, C|S, STR("\033\177") },
- { XK_BackSpace, 0, 0, CSI(127,0,'u') },
- { XK_Tab, 0, ALLM, STR("\t") },
- { XK_Tab, A, C|S, STR("\033\t") },
- { XK_Tab, S, 0, CSI(1,S,'Z') },
- { XK_Tab, 0, 0, CSI('\t',0,'u') },
- { XK_Return, 0, ALLM, STR("\r") },
- { XK_Return, A, C|S, STR("\033\r") },
- { XK_Return, 0, 0, CSI('\r',0,'u') },
- { XK_Escape, 0, ALLM, STR("\033") },
- { XK_Escape, A, C|S, STR("\033\033") },
- { XK_Escape, 0, 0, CSI(27,0,'u') },
- { XK_Delete, 0, 0, TILDE(3) },
- { XK_Home, CURS, ALLM, STR("\033OH") },
- { XK_Home, 0, 0, CSI(1,0,'H') },
- { XK_Left, CURS, ALLM, STR("\033OD") },
- { XK_Left, 0, 0, CSI(1,0,'D') },
- { XK_Up, CURS, ALLM, STR("\033OA") },
- { XK_Up, 0, 0, CSI(1,0,'A') },
- { XK_Right, CURS, ALLM, STR("\033OC") },
- { XK_Right, 0, 0, CSI(1,0,'C') },
- { XK_Down, CURS, ALLM, STR("\033OB") },
- { XK_Down, 0, 0, CSI(1,0,'B') },
- { XK_Prior, 0, 0, TILDE(5) },
- { XK_Next, 0, 0, TILDE(6) },
- { XK_End, CURS, ALLM, STR("\033OF") },
- { XK_End, 0, 0, CSI(1,0,'F') },
- { XK_Begin, 0, 0, CSI(1,0,'E') },
- { XK_Select, 0, 0, TILDE(4) },
- { XK_Insert, 0, 0, TILDE(2) },
- { XK_Find, 0, 0, TILDE(1) },
-
- /* KEYPAD */
- { XK_KP_Enter, KPAD, NMLK|ALLM, STR("\033OM") },
- { XK_KP_Enter, 0, ALLM, STR("\r") },
- { XK_KP_Enter, A, C|S, STR("\033\r") },
- { XK_KP_Enter, 0, 0, CSI('\r',0,'u') },
- { XK_KP_F1, 0, ALLM, STR("\033OP") },
- { XK_KP_F1, 0, 0, CSI(1,0,'P') },
- { XK_KP_F2, 0, ALLM, STR("\033OQ") },
- { XK_KP_F2, 0, 0, CSI(1,0,'Q') },
- { XK_KP_F3, 0, ALLM, STR("\033OR") },
- { XK_KP_F3, 0, 0, CSI(1,0,'R') },
- { XK_KP_F4, 0, ALLM, STR("\033OS") },
- { XK_KP_F4, 0, 0, CSI(1,0,'S') },
- { XK_KP_Home, CURS, ALLM, STR("\033OH") },
- { XK_KP_Home, 0, 0, CSI(1,0,'H') },
- { XK_KP_Left, CURS, ALLM, STR("\033OD") },
- { XK_KP_Left, 0, 0, CSI(1,0,'D') },
- { XK_KP_Up, CURS, ALLM, STR("\033OA") },
- { XK_KP_Up, 0, 0, CSI(1,0,'A') },
- { XK_KP_Right, CURS, ALLM, STR("\033OC") },
- { XK_KP_Right, 0, 0, CSI(1,0,'C') },
- { XK_KP_Down, CURS, ALLM, STR("\033OB") },
- { XK_KP_Down, 0, 0, CSI(1,0,'B') },
- { XK_KP_Prior, 0, 0, TILDE(5) },
- { XK_KP_Next, 0, 0, TILDE(6) },
- { XK_KP_End, CURS, ALLM, STR("\033OF") },
- { XK_KP_End, 0, 0, CSI(1,0,'F') },
- { XK_KP_Begin, 0, 0, CSI(1,0,'E') },
- { XK_KP_Insert, 0, 0, TILDE(2) },
- { XK_KP_Delete, 0, 0, TILDE(3) },
- { XK_KP_Equal, KPAD, NMLK|ALLM, STR("\033OX") },
- { XK_KP_Multiply, KPAD, NMLK|ALLM, STR("\033Oj") },
- { XK_KP_Add, KPAD, NMLK|ALLM, STR("\033Ok") },
- { XK_KP_Separator, KPAD, NMLK|ALLM, STR("\033Ol") },
- { XK_KP_Subtract, KPAD, NMLK|ALLM, STR("\033Om") },
- { XK_KP_Decimal, KPAD, NMLK|ALLM, STR("\033On") },
- { XK_KP_Divide, KPAD, NMLK|ALLM, STR("\033Oo") },
- { XK_KP_0, KPAD, NMLK|ALLM, STR("\033Op") },
- { XK_KP_1, KPAD, NMLK|ALLM, STR("\033Oq") },
- { XK_KP_2, KPAD, NMLK|ALLM, STR("\033Or") },
- { XK_KP_3, KPAD, NMLK|ALLM, STR("\033Os") },
- { XK_KP_4, KPAD, NMLK|ALLM, STR("\033Ot") },
- { XK_KP_5, KPAD, NMLK|ALLM, STR("\033Ou") },
- { XK_KP_6, KPAD, NMLK|ALLM, STR("\033Ov") },
- { XK_KP_7, KPAD, NMLK|ALLM, STR("\033Ow") },
- { XK_KP_8, KPAD, NMLK|ALLM, STR("\033Ox") },
- { XK_KP_9, KPAD, NMLK|ALLM, STR("\033Oy") },
-
- /* FUNCTION */
- { XK_F1, 0, 0, TILDE(11) },
- { XK_F2, 0, 0, TILDE(12) },
- { XK_F3, 0, 0, TILDE(13) },
- { XK_F4, 0, 0, TILDE(14) },
- { XK_F5, 0, 0, TILDE(15) },
- { XK_F6, 0, 0, TILDE(17) },
- { XK_F7, 0, 0, TILDE(18) },
- { XK_F8, 0, 0, TILDE(19) },
- { XK_F9, 0, 0, TILDE(20) },
- { XK_F10, 0, 0, TILDE(21) },
- { XK_F11, 0, 0, TILDE(23) },
- { XK_F12, 0, 0, TILDE(24) },
- { XK_F13, 0, 0, TILDE(25) },
- { XK_F14, 0, 0, TILDE(26) },
- { XK_F15, 0, 0, TILDE(28) },
- { XK_F16, 0, 0, TILDE(29) },
- { XK_F17, 0, 0, TILDE(31) },
- { XK_F18, 0, 0, TILDE(32) },
- { XK_F19, 0, 0, TILDE(33) },
- { XK_F20, 0, 0, TILDE(34) },
-};
-
-/*
- * Selection types' masks.
- * Use the same masks as usual.
- * Button1Mask is always unset, to make masks match between ButtonPress.
- * ButtonRelease and MotionNotify.
- * If no match is found, regular selection is used.
- */
-static uint selmasks[] = {
- [SEL_RECTANGULAR] = Mod1Mask,
-};
-
-/*
- * Printable characters in ASCII, used to estimate the advance width
- * of single wide characters.
- */
-static char ascii_printable[] =
- " !\"#$%&'()*+,-./0123456789:;<=>?"
- "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
- "`abcdefghijklmnopqrstuvwxyz{|}~";
+extern char *font;
+extern int borderpx;
+extern float cwscale;
+extern float chscale;
+extern char *shell;
+extern char *utmp;
+extern char *scroll;
+extern char *stty_args;
+extern char *vtiden;
+extern wchar_t *worddelimiters;
+extern uint doubleclicktimeout;
+extern uint tripleclicktimeout;
+extern int allowaltscreen;
+extern int allowwindowops;
+extern double minlatency;
+extern double maxlatency;
+extern uint blinktimeout;
+extern uint cursorthickness;
+extern int bellvolume;
+extern char *termname;
+extern uint tabspaces;
+extern const char *colorname[];
+extern uint defaultfg;
+extern uint defaultbg;
+extern uint defaultcs;
+extern uint defaultrcs;
+extern uint cursorshape;
+extern uint cols;
+extern uint rows;
+extern uint mouseshape;
+extern uint mousefg;
+extern uint mousebg;
+extern uint defaultattr;
+extern uint forcemousemod;
+extern uint ignoremod;
+extern Btn btns[];
+extern Key keys[];
+extern uint selmasks[];
diff --git a/st.c b/st.c
@@ -5,6 +5,7 @@
#include <limits.h>
#include <pwd.h>
#include <stdarg.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -17,6 +18,8 @@
#include <unistd.h>
#include <wchar.h>
+#include "util.h"
+#include "config.h"
#include "st.h"
#include "win.h"
@@ -29,27 +32,26 @@
#endif
/* Arbitrary sizes */
-#define UTF_SIZ 4
-#define ESC_BUF_SIZ (128*UTF_SIZ)
-#define ESC_ARG_SIZ 16
-#define STR_BUF_SIZ ESC_BUF_SIZ
-#define STR_ARG_SIZ ESC_ARG_SIZ
+#define ESC_BUF_SIZ (128*UTF_SIZ)
+#define ESC_ARG_SIZ 16
+#define STR_BUF_SIZ ESC_BUF_SIZ
+#define STR_ARG_SIZ ESC_ARG_SIZ
/* macros */
-#define IS_SET(flag) ((term.mode & (flag)) != 0)
-#define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == 0x7f)
-#define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f))
-#define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
-#define ISDELIM(u) (u && wcschr(worddelimiters, u))
+#define IS_SET(flag) ((term.mode & (flag)) != 0)
+#define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == 0x7f)
+#define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f))
+#define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
+#define ISDELIM(u) (u && wcschr(worddelimiters, u))
enum term_mode {
- MODE_WRAP = 1 << 0,
- MODE_INSERT = 1 << 1,
- MODE_ALTSCREEN = 1 << 2,
- MODE_CRLF = 1 << 3,
- MODE_ECHO = 1 << 4,
- MODE_PRINT = 1 << 5,
- MODE_UTF8 = 1 << 6,
+ MODE_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,
};
enum cursor_movement {
@@ -110,23 +112,23 @@ typedef struct {
/* Internal representation of the screen */
typedef struct {
- int row; /* nb row */
- int col; /* nb col */
- Line *line; /* screen */
- Line *alt; /* alternate screen */
- int *dirty; /* dirtyness of lines */
- TCursor c; /* cursor */
- int ocx; /* old cursor col */
- int ocy; /* old cursor row */
- int top; /* top scroll limit */
- int bot; /* bottom scroll limit */
- int mode; /* terminal mode flags */
- int esc; /* escape state flags */
+ int row; /* nb row */
+ int col; /* nb col */
+ Line *line; /* screen */
+ Line *alt; /* alternate screen */
+ int *dirty; /* dirtyness of lines */
+ TCursor c; /* cursor */
+ int ocx; /* old cursor col */
+ int ocy; /* old cursor row */
+ int top; /* top scroll limit */
+ int bot; /* bottom scroll limit */
+ int mode; /* terminal mode flags */
+ int esc; /* escape state flags */
char trantbl[4]; /* charset table translation */
- int charset; /* current charset */
- int icharset; /* selected charset for sequence */
+ int charset; /* current charset */
+ int icharset; /* selected charset for sequence */
int *tabs;
- Rune lastc; /* last printed char outside of sequence, 0 if control */
+ Rune lastc; /* last printed char outside of sequence, 0 if control */
} Term;
/* CSI Escape sequence structs */
@@ -167,9 +169,7 @@ static void strparse(void);
static void strreset(void);
static void tprinter(char *, size_t);
-static void tdumpsel(void);
static void tdumpline(int);
-static void tdump(void);
static void tclearregion(int, int, int, int);
static void tcursor(int);
static void tdeletechar(int);
@@ -206,15 +206,6 @@ static void selnormalize(void);
static void selscroll(int, int);
static void selsnap(int *, int *, int);
-static Rune utf8decodebyte(char, size_t *);
-static char utf8encodebyte(Rune, size_t);
-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);
-
/* Globals */
static Term term;
static Selection sel;
@@ -224,183 +215,6 @@ static int iofd = 1;
static int cmdfd;
static pid_t pid;
-static const uchar utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
-static const uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
-static const Rune utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000};
-static const Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
-
-ssize_t
-xwrite(int fd, const char *s, size_t len)
-{
- size_t aux = len;
- ssize_t r;
-
- while (len > 0) {
- r = write(fd, s, len);
- if (r < 0)
- return r;
- len -= r;
- s += r;
- }
-
- return aux;
-}
-
-void *
-xmalloc(size_t len)
-{
- void *p;
-
- if (!(p = malloc(len)))
- die("malloc: %s\n", strerror(errno));
-
- return p;
-}
-
-void *
-xrealloc(void *p, size_t len)
-{
- if ((p = realloc(p, len)) == NULL)
- die("realloc: %s\n", strerror(errno));
-
- return p;
-}
-
-char *
-xstrdup(const char *s)
-{
- char *p;
-
- if ((p = strdup(s)) == NULL)
- die("strdup: %s\n", strerror(errno));
-
- return p;
-}
-
-size_t
-utf8decode(const char *c, Rune *u, size_t clen)
-{
- size_t i, j, len, type;
- Rune udecoded;
-
- *u = UTF_INVALID;
- if (!clen)
- return 0;
- udecoded = utf8decodebyte(c[0], &len);
- if (!BETWEEN(len, 1, UTF_SIZ))
- return 1;
- for (i = 1, j = 1; i < clen && j < len; ++i, ++j) {
- udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type);
- if (type != 0)
- return j;
- }
- if (j < len)
- return 0;
- *u = udecoded;
- utf8validate(u, len);
-
- return len;
-}
-
-Rune
-utf8decodebyte(char c, size_t *i)
-{
- for (*i = 0; *i < LEN(utfmask); ++(*i))
- if (((uchar)c & utfmask[*i]) == utfbyte[*i])
- return (uchar)c & ~utfmask[*i];
-
- return 0;
-}
-
-size_t
-utf8encode(Rune u, char *c)
-{
- size_t len, i;
-
- len = utf8validate(&u, 0);
- if (len > UTF_SIZ)
- return 0;
-
- for (i = len - 1; i != 0; --i) {
- c[i] = utf8encodebyte(u, 0);
- u >>= 6;
- }
- c[0] = utf8encodebyte(u, len);
-
- return len;
-}
-
-char
-utf8encodebyte(Rune u, size_t i)
-{
- return utfbyte[i] | (u & ~utfmask[i]);
-}
-
-size_t
-utf8validate(Rune *u, size_t i)
-{
- if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF))
- *u = UTF_INVALID;
- for (i = 1; *u > utfmax[i]; ++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 ? *((*src)++) : '='; /* emulate padding if string ends */
-}
-
-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)];
-
- /* invalid input. 'a' can be -1, e.g. if src is "\n" (c-str) */
- if (a == -1 || b == -1)
- break;
-
- *dst++ = (a << 2) | ((b & 0x30) >> 4);
- if (c == -1)
- break;
- *dst++ = ((b & 0x0f) << 4) | ((c & 0x3c) >> 2);
- if (d == -1)
- break;
- *dst++ = ((c & 0x03) << 6) | d;
- }
- *dst = '\0';
- return result;
-}
-
void
selinit(void)
{
@@ -652,17 +466,6 @@ selclear(void)
}
void
-die(const char *errstr, ...)
-{
- va_list ap;
-
- va_start(ap, errstr);
- vfprintf(stderr, errstr, ap);
- va_end(ap);
- exit(1);
-}
-
-void
execsh(char *cmd, char **args)
{
char *sh, *prog, *arg;
@@ -1971,7 +1774,7 @@ strreset(void)
}
void
-sendbreak(const Arg *arg)
+tsendbreak(void)
{
if (tcsendbreak(cmdfd, 0))
perror("Error sending break");
@@ -1988,24 +1791,12 @@ tprinter(char *s, size_t len)
}
void
-toggleprinter(const Arg *arg)
+ttogprinter(void)
{
term.mode ^= MODE_PRINT;
}
void
-printscreen(const Arg *arg)
-{
- tdump();
-}
-
-void
-printsel(const Arg *arg)
-{
- tdumpsel();
-}
-
-void
tdumpsel(void)
{
char *ptr;
diff --git a/st.h b/st.h
@@ -1,26 +1,10 @@
/* See LICENSE for license details. */
+/* Requires: stdint.h, size_t, util.h */
-#include <stdint.h>
-#include <sys/types.h>
-
-#define UTF_INVALID 0xFFFD
-
-/* 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 ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || \
+ (a).bg != (b).bg)
+#define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b))
+#define IS_TRUECOL(x) (1 << 24 & (x))
enum glyph_attribute {
ATTR_NULL = 0,
@@ -54,40 +38,23 @@ enum selection_snap {
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 */
+ 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;
- const char *s;
-} Arg;
-
-void die(const char *, ...);
void redraw(void);
void draw(void);
-void printscreen(const Arg *);
-void printsel(const Arg *);
-void sendbreak(const Arg *);
-void toggleprinter(const Arg *);
-
+void ttogprinter(void);
+void tdump(void);
+void tdumpsel(void);
+void tsendbreak(void);
int tattrset(int);
void tnew(int, int);
void tresize(int, int);
@@ -106,23 +73,3 @@ void selstart(int, int, int);
void selextend(int, int, int, int);
int selected(int, int);
char *getsel(void);
-
-size_t utf8decode(const char *, Rune *, size_t);
-size_t utf8encode(Rune, char *);
-
-void *xmalloc(size_t);
-void *xrealloc(void *, size_t);
-char *xstrdup(const char *);
-
-/* config.h globals */
-extern char *utmp;
-extern char *scroll;
-extern char *stty_args;
-extern char *vtiden;
-extern wchar_t *worddelimiters;
-extern int allowaltscreen;
-extern int allowwindowops;
-extern char *termname;
-extern unsigned int tabspaces;
-extern unsigned int defaultfg;
-extern unsigned int defaultbg;
diff --git a/util.c b/util.c
@@ -0,0 +1,231 @@
+#include <ctype.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "util.h"
+#include "config.h"
+
+static Rune utf8decodebyte(char, size_t *);
+static char utf8encodebyte(Rune, size_t);
+static size_t utf8validate(Rune *, size_t);
+static char base64dec_getc(const char **);
+static uint termkeymod(uint xmod);
+
+static const uchar utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
+static const uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
+static const Rune utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000};
+static const Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
+
+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, 0,
+};
+
+void
+die(const char *errstr, ...)
+{
+ va_list ap;
+
+ va_start(ap, errstr);
+ vfprintf(stderr, errstr, ap);
+ va_end(ap);
+ exit(1);
+}
+
+void *
+xmalloc(size_t len)
+{
+ void *p;
+
+ if ((p = malloc(len)) == NULL)
+ die("malloc: %s\n", strerror(errno));
+
+ return p;
+}
+
+void *
+xrealloc(void *p, size_t len)
+{
+ if ((p = realloc(p, len)) == NULL)
+ die("realloc: %s\n", strerror(errno));
+
+ return p;
+}
+
+char *
+xstrdup(const char *s)
+{
+ char *p;
+
+ if ((p = strdup(s)) == NULL)
+ die("strdup: %s\n", strerror(errno));
+
+ return p;
+}
+
+ssize_t
+xwrite(int fd, const char *s, size_t len)
+{
+ size_t aux = len;
+ ssize_t r;
+
+ while (len > 0) {
+ r = write(fd, s, len);
+ if (r < 0)
+ return r;
+ len -= r;
+ s += r;
+ }
+
+ return aux;
+}
+
+size_t
+utf8decode(const char *c, Rune *u, size_t clen)
+{
+ size_t i, j, len, type;
+ Rune udecoded;
+
+ *u = UTF_INVALID;
+ if (!clen)
+ return 0;
+ udecoded = utf8decodebyte(c[0], &len);
+ if (!BETWEEN(len, 1, UTF_SIZ))
+ return 1;
+ for (i = 1, j = 1; i < clen && j < len; ++i, ++j) {
+ udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type);
+ if (type != 0)
+ return j;
+ }
+ if (j < len)
+ return 0;
+ *u = udecoded;
+ utf8validate(u, len);
+
+ return len;
+}
+
+Rune
+utf8decodebyte(char c, size_t *i)
+{
+ for (*i = 0; *i < LEN(utfmask); ++(*i))
+ if (((uchar)c & utfmask[*i]) == utfbyte[*i])
+ return (uchar)c & ~utfmask[*i];
+
+ return 0;
+}
+
+size_t
+utf8encode(Rune u, char *c)
+{
+ size_t len, i;
+
+ len = utf8validate(&u, 0);
+ if (len > UTF_SIZ)
+ return 0;
+
+ for (i = len - 1; i != 0; --i) {
+ c[i] = utf8encodebyte(u, 0);
+ u >>= 6;
+ }
+ c[0] = utf8encodebyte(u, len);
+
+ return len;
+}
+
+char
+utf8encodebyte(Rune u, size_t i)
+{
+ return utfbyte[i] | (u & ~utfmask[i]);
+}
+
+size_t
+utf8validate(Rune *u, size_t i)
+{
+ if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF))
+ *u = UTF_INVALID;
+ for (i = 1; *u > utfmax[i]; ++i)
+ ;
+
+ return i;
+}
+
+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[(uchar) base64dec_getc(&src)];
+ int b = base64_digits[(uchar) base64dec_getc(&src)];
+ int c = base64_digits[(uchar) base64dec_getc(&src)];
+ int d = base64_digits[(uchar) base64dec_getc(&src)];
+
+ /* invalid input. 'a' can be -1, e.g. if src is "\n" (c-str) */
+ if (a == -1 || b == -1)
+ break;
+
+ *dst++ = (a << 2) | ((b & 0x30) >> 4);
+ if (c == -1)
+ break;
+ *dst++ = ((b & 0x0f) << 4) | ((c & 0x3c) >> 2);
+ if (d == -1)
+ break;
+ *dst++ = ((c & 0x03) << 6) | d;
+ }
+ *dst = '\0';
+ return result;
+}
+
+char
+base64dec_getc(const char **src)
+{
+ while (**src && !isprint(**src))
+ (*src)++;
+ return **src ? *((*src)++) : '='; /* emulate padding if string ends */
+}
+
+size_t
+csienc(char *buf, size_t len, uint state, uint n, uint m, char c)
+{
+ uint mod;
+
+ mod = termkeymod(state & ~m);
+ if (mod > 1)
+ return snprintf(buf, len, "\033[%d;%d%c", n, mod, c);
+ else if (n > 1)
+ return snprintf(buf, len, "\033[%d%c", n, c);
+ else
+ return snprintf(buf, len, "\033[%c", c);
+}
+
+uint
+termkeymod(uint xmod)
+{
+ return 1 + ((xmod&SHFT ? 1<<0 : 0)
+ | (xmod&ALT ? 1<<1 : 0)
+ | (xmod&CTRL ? 1<<2 : 0));
+}
diff --git a/util.h b/util.h
@@ -0,0 +1,34 @@
+/* See LICENSE for license details. */
+/* Requires: stdint.h, size_t, ssize_t */
+
+#define UTF_INVALID 0xFFFD
+#define UTF_SIZ 4
+
+#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 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)))
+
+typedef unsigned char uchar;
+typedef unsigned short ushort;
+typedef unsigned int uint;
+typedef unsigned long ulong;
+
+typedef uint_least32_t Rune;
+
+void die(const char *, ...);
+void *xmalloc(size_t);
+void *xrealloc(void *, size_t);
+char *xstrdup(const char *);
+ssize_t xwrite(int, const char *, size_t);
+/* TODO: utf8 spells out decode, but base64 doesn't... */
+size_t utf8decode(const char *, Rune *, size_t);
+size_t utf8encode(Rune, char *);
+char *base64dec(const char *);
+size_t csienc(char *, size_t, uint, uint, uint, char);
diff --git a/win.h b/win.h
@@ -1,4 +1,5 @@
/* See LICENSE for license details. */
+/* Requires: util.h, st.h */
enum win_mode {
MODE_VISIBLE = 1 << 0,
@@ -23,6 +24,12 @@ enum win_mode {
|MODE_MOUSEMANY,
};
+void xclipcopy(void);
+void xclippaste(void);
+void xselpaste(void);
+void xzoomabs(double);
+void xzoomrel(double);
+void xzoomrst(void);
void xbell(void);
void xclipcopy(void);
void xdrawcursor(int, int, Glyph, int, int, Glyph);
@@ -33,7 +40,8 @@ int xsetcolorname(int, const char *);
void xseticontitle(char *);
void xsettitle(char *);
int xsetcursor(int);
-void xsetmode(int, unsigned int);
+void xsetmode(int, uint);
+void xtogmode(uint);
void xsetpointermotion(int);
void xsetsel(char *);
int xstartdraw(void);
diff --git a/x.c b/x.c
@@ -4,65 +4,35 @@
#include <limits.h>
#include <locale.h>
#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.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>
char *argv0;
#include "arg.h"
+#include "util.h"
+#include "config.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 mod;
- uint button;
- void (*func)(const Arg *);
- const Arg arg;
- uint release;
-} MouseShortcut;
-
-/* 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 *);
-static void ttysend(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)
+#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;
@@ -174,7 +144,6 @@ static void selrequest(XEvent *);
static void setsel(char *, Time);
static void mousesel(XEvent *, int);
static void mousereport(XEvent *);
-static int match(uint, uint);
static void run(void);
static void usage(void);
@@ -244,8 +213,15 @@ static char *opt_title = NULL;
static int oldbutton = 3; /* button event on startup: 3 = release */
+/* Printable characters in ASCII. Used to estimate the advance width
+ * of single wide characters. */
+static char ascii_printable[] =
+ " !\"#$%&'()*+,-./0123456789:;<=>?"
+ "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
+ "`abcdefghijklmnopqrstuvwxyz{|}~";
+
void
-clipcopy(const Arg *dummy)
+xclipcopy(void)
{
Atom clipboard;
@@ -260,7 +236,7 @@ clipcopy(const Arg *dummy)
}
void
-clippaste(const Arg *dummy)
+xclippaste(void)
{
Atom clipboard;
@@ -270,52 +246,33 @@ clippaste(const Arg *dummy)
}
void
-selpaste(const Arg *dummy)
+xselpaste(void)
{
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)
+xzoomabs(double fontsize)
{
xunloadfonts();
- xloadfonts(usedfont, arg->f);
+ xloadfonts(usedfont, fontsize);
cresize(0, 0);
redraw();
xhints();
}
void
-zoomreset(const Arg *arg)
+xzoomrel(double delta)
{
- Arg larg;
-
- if (defaultfontsize > 0) {
- larg.f = defaultfontsize;
- zoomabs(&larg);
- }
+ xzoomabs(usedfontsize+delta);
}
void
-ttysend(const Arg *arg)
+xzoomrst(void)
{
- ttywrite(arg->s, strlen(arg->s), 1);
+ if (defaultfontsize > 0)
+ xzoomabs(defaultfontsize);
}
int
@@ -584,12 +541,6 @@ selnotify(XEvent *e)
}
void
-xclipcopy(void)
-{
- clipcopy(NULL);
-}
-
-void
selclear_(XEvent *e)
{
selclear();
@@ -1684,8 +1635,9 @@ xsetpointermotion(int set)
XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs);
}
+/* TODO combine xsetmode and xtogmode into one general function? */
void
-xsetmode(int set, unsigned int flags)
+xsetmode(int set, uint flags)
{
int mode = win.mode;
MODBIT(win.mode, set, flags);
@@ -1693,6 +1645,15 @@ xsetmode(int set, unsigned int flags)
redraw();
}
+void
+xtogmode(uint flags)
+{
+ int mode = win.mode;
+ win.mode ^= flags;
+ if ((win.mode & MODE_REVERSE) != (mode & MODE_REVERSE))
+ redraw();
+}
+
int
xsetcursor(int cursor)
{
@@ -1748,6 +1709,7 @@ focus(XEvent *ev)
int
match(uint mask, uint state)
{
+ uint ignoremod = Mod2Mask|XK_SWITCH_MOD;
return mask == XK_ANY_MOD || mask == (state & ~ignoremod);
}
@@ -1795,7 +1757,7 @@ kpress(XEvent *ev)
| (e->state&ControlMask ? C : 0);
for (k = keys; k < keys + LEN(keys); k++) {
if (k->sym == ksym && scmatch(state, k->set, k->clr)) {
- len = k->fn(buf, sizeof buf, ksym, state, k->arg);
+ len = k->enc(buf, sizeof buf, ksym, state, k->arg);
ttywrite(buf, len, 1);
return;
}